Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add zero-copy driver #37

Merged
merged 8 commits into from
Apr 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Documentation/gpu/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Linux GPU Driver Developer's Guide
vga-switcheroo
vgaarbiter
bridge/dw-hdmi
xen-front
xen-zcopy
todo

.. only:: subproject and html
Expand Down
31 changes: 31 additions & 0 deletions Documentation/gpu/xen-front.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
====================================================
drm/xen-front Xen para-virtualized frontend driver
====================================================

This frontend driver implements Xen para-virtualized display
according to the display protocol described at
include/xen/interface/io/displif.h

Driver modes of operation in terms of display buffers used
==========================================================

.. kernel-doc:: drivers/gpu/drm/xen/xen_drm_front.h
:doc: Driver modes of operation in terms of display buffers used

Buffers allocated by the frontend driver
----------------------------------------

.. kernel-doc:: drivers/gpu/drm/xen/xen_drm_front.h
:doc: Buffers allocated by the frontend driver

Buffers allocated by the backend
--------------------------------

.. kernel-doc:: drivers/gpu/drm/xen/xen_drm_front.h
:doc: Buffers allocated by the backend

Driver limitations
==================

.. kernel-doc:: drivers/gpu/drm/xen/xen_drm_front.h
:doc: Driver limitations
32 changes: 32 additions & 0 deletions Documentation/gpu/xen-zcopy.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
==============================================
drm/xen-zcopy Xen zero-copy helper DRM driver
==============================================

This helper driver allows implementing zero-copying use-cases
when using Xen para-virtualized frontend display driver:

- a dumb buffer created on backend's side can be shared
with the Xen PV frontend driver, so it directly writes
into backend's domain memory (into the buffer exported from
DRM/KMS driver of a physical display device)
- a dumb buffer allocated by the frontend can be imported
into physical device DRM/KMS driver, thus allowing to
achieve no copying as well

DRM_XEN_ZCOPY_DUMB_FROM_REFS IOCTL
==================================

.. kernel-doc:: include/uapi/drm/xen_zcopy_drm.h
:doc: DRM_XEN_ZCOPY_DUMB_FROM_REFS

DRM_XEN_ZCOPY_DUMB_TO_REFS IOCTL
================================

.. kernel-doc:: include/uapi/drm/xen_zcopy_drm.h
:doc: DRM_XEN_ZCOPY_DUMB_TO_REFS

DRM_XEN_ZCOPY_DUMB_WAIT_FREE IOCTL
==================================

.. kernel-doc:: include/uapi/drm/xen_zcopy_drm.h
:doc: DRM_XEN_ZCOPY_DUMB_WAIT_FREE
1 change: 1 addition & 0 deletions drivers/amba/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ struct bus_type amba_bustype = {
.match = amba_match,
.uevent = amba_uevent,
.pm = &amba_pm,
.force_dma = true,
};

static int __init amba_init(void)
Expand Down
1 change: 1 addition & 0 deletions drivers/base/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -1143,6 +1143,7 @@ struct bus_type platform_bus_type = {
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
.force_dma = true,
};
EXPORT_SYMBOL_GPL(platform_bus_type);

Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,8 @@ source "drivers/gpu/drm/tinydrm/Kconfig"

source "drivers/gpu/drm/pl111/Kconfig"

source "drivers/gpu/drm/xen/Kconfig"

# Keep legacy drivers last

menuconfig DRM_LEGACY
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,4 @@ obj-$(CONFIG_DRM_ZTE) += zte/
obj-$(CONFIG_DRM_MXSFB) += mxsfb/
obj-$(CONFIG_DRM_TINYDRM) += tinydrm/
obj-$(CONFIG_DRM_PL111) += pl111/
obj-$(CONFIG_DRM_XEN) += xen/
54 changes: 49 additions & 5 deletions drivers/gpu/drm/drm_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <linux/moduleparam.h>
#include <linux/mount.h>
#include <linux/slab.h>
#include <linux/srcu.h>

#include <drm/drm_drv.h>
#include <drm/drmP.h>
Expand Down Expand Up @@ -74,6 +75,8 @@ static bool drm_core_init_complete = false;

static struct dentry *drm_debugfs_root;

DEFINE_STATIC_SRCU(drm_unplug_srcu);

#define DRM_PRINTK_FMT "[" DRM_NAME ":%s]%s %pV"

void drm_dev_printk(const struct device *dev, const char *level,
Expand Down Expand Up @@ -364,18 +367,51 @@ void drm_put_dev(struct drm_device *dev)
}
EXPORT_SYMBOL(drm_put_dev);

static void drm_device_set_unplugged(struct drm_device *dev)
/**
* drm_dev_enter - Enter device critical section
* @dev: DRM device
* @idx: Pointer to index that will be passed to the matching drm_dev_exit()
*
* This function marks and protects the beginning of a section that should not
* be entered after the device has been unplugged. The section end is marked
* with drm_dev_exit(). Calls to this function can be nested.
*
* Returns:
* True if it is OK to enter the section, false otherwise.
*/
bool drm_dev_enter(struct drm_device *dev, int *idx)
{
*idx = srcu_read_lock(&drm_unplug_srcu);

if (dev->unplugged) {
srcu_read_unlock(&drm_unplug_srcu, *idx);
return false;
}

return true;
}
EXPORT_SYMBOL(drm_dev_enter);

/**
* drm_dev_exit - Exit device critical section
* @idx: index returned from drm_dev_enter()
*
* This function marks the end of a section that should not be entered after
* the device has been unplugged.
*/
void drm_dev_exit(int idx)
{
smp_wmb();
atomic_set(&dev->unplugged, 1);
srcu_read_unlock(&drm_unplug_srcu, idx);
}
EXPORT_SYMBOL(drm_dev_exit);

/**
* drm_dev_unplug - unplug a DRM device
* @dev: DRM device
*
* This unplugs a hotpluggable DRM device, which makes it inaccessible to
* userspace operations. Entry-points can use drm_dev_is_unplugged(). This
* userspace operations. Entry-points can use drm_dev_enter() and
* drm_dev_exit() to protect device resources in a race free manner. This
* essentially unregisters the device like drm_dev_unregister(), but can be
* called while there are still open users of @dev.
*/
Expand All @@ -384,10 +420,18 @@ void drm_dev_unplug(struct drm_device *dev)
drm_dev_unregister(dev);

mutex_lock(&drm_global_mutex);
drm_device_set_unplugged(dev);
if (dev->open_count == 0)
drm_dev_unref(dev);
mutex_unlock(&drm_global_mutex);

/*
* After synchronizing any critical read section is guaranteed to see
* the new value of ->unplugged, and any critical section which might
* still have seen the old value of ->unplugged is guaranteed to have
* finished.
*/
dev->unplugged = true;
synchronize_srcu(&drm_unplug_srcu);
}
EXPORT_SYMBOL(drm_dev_unplug);

Expand Down
31 changes: 25 additions & 6 deletions drivers/gpu/drm/drm_simple_kms_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,20 @@ static const struct drm_encoder_funcs drm_simple_kms_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};

static enum drm_mode_status
drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc,
const struct drm_display_mode *mode)
{
struct drm_simple_display_pipe *pipe;

pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
if (!pipe->funcs || !pipe->funcs->mode_valid)
/* Anything goes */
return MODE_OK;

return pipe->funcs->mode_valid(crtc, mode);
}

static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
Expand All @@ -50,13 +64,15 @@ static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
struct drm_plane *plane;
struct drm_simple_display_pipe *pipe;

pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
if (!pipe->funcs || !pipe->funcs->enable)
return;

pipe->funcs->enable(pipe, crtc->state);
plane = &pipe->plane;
pipe->funcs->enable(pipe, crtc->state, plane->state);
}

static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc,
Expand All @@ -72,6 +88,7 @@ static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc,
}

static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
.mode_valid = drm_simple_kms_crtc_mode_valid,
.atomic_check = drm_simple_kms_crtc_check,
.atomic_enable = drm_simple_kms_crtc_enable,
.atomic_disable = drm_simple_kms_crtc_disable,
Expand All @@ -97,11 +114,11 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
pipe = container_of(plane, struct drm_simple_display_pipe, plane);
crtc_state = drm_atomic_get_new_crtc_state(plane_state->state,
&pipe->crtc);
if (!crtc_state->enable)
return 0; /* nothing to check when disabling or disabled */

clip.x2 = crtc_state->adjusted_mode.hdisplay;
clip.y2 = crtc_state->adjusted_mode.vdisplay;
if (crtc_state) {
clip.x2 = crtc_state->adjusted_mode.hdisplay;
clip.y2 = crtc_state->adjusted_mode.vdisplay;
}

ret = drm_plane_helper_check_state(plane_state, &clip,
DRM_PLANE_HELPER_NO_SCALING,
Expand All @@ -111,7 +128,9 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
return ret;

if (!plane_state->visible)
return -EINVAL;
return 0;

drm_mode_get_hv_timing(&crtc_state->mode, &clip.x2, &clip.y2);

if (!pipe->funcs || !pipe->funcs->check)
return 0;
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/mxsfb/mxsfb_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ static const struct drm_mode_config_funcs mxsfb_mode_config_funcs = {
};

static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe,
struct drm_crtc_state *crtc_state)
struct drm_crtc_state *crtc_state,
struct drm_plane_state *plane_state)
{
struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);

Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/pl111/pl111_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ static int pl111_display_check(struct drm_simple_display_pipe *pipe,
}

static void pl111_display_enable(struct drm_simple_display_pipe *pipe,
struct drm_crtc_state *cstate)
struct drm_crtc_state *cstate,
struct drm_plane_state *plane_state)
{
struct drm_crtc *crtc = &pipe->crtc;
struct drm_plane *plane = &pipe->plane;
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/tinydrm/repaper.c
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,8 @@ static void power_off(struct repaper_epd *epd)
}

static void repaper_pipe_enable(struct drm_simple_display_pipe *pipe,
struct drm_crtc_state *crtc_state)
struct drm_crtc_state *crtc_state,
struct drm_plane_state *plane_state)
{
struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
struct repaper_epd *epd = epd_from_tinydrm(tdev);
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/tinydrm/st7586.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ static const struct drm_framebuffer_funcs st7586_fb_funcs = {
};

static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe,
struct drm_crtc_state *crtc_state)
struct drm_crtc_state *crtc_state,
struct drm_plane_state *plane_state)
{
struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
Expand Down
42 changes: 42 additions & 0 deletions drivers/gpu/drm/xen/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
config DRM_XEN
bool "DRM Support for Xen guest OS"
depends on XEN
help
Choose this option if you want to enable DRM support
for Xen.

choice
prompt "Xen DRM drivers selection"
depends on DRM_XEN

config DRM_XEN_FRONTEND
tristate "Para-virtualized frontend driver for Xen guest OS"
depends on DRM_XEN
depends on DRM
select DRM_KMS_HELPER
select VIDEOMODE_HELPERS
select XEN_XENBUS_FRONTEND
help
Choose this option if you want to enable a para-virtualized
frontend DRM/KMS driver for Xen guest OSes.

config DRM_XEN_ZCOPY
tristate "Zero copy helper DRM driver for Xen"
depends on DRM_XEN
depends on DRM
select DRM_KMS_HELPER
help
Choose this option if you want to enable a zero copy
helper DRM driver for Xen. This is implemented via mapping
of foreign display buffer pages into current domain and
exporting a dumb via PRIME interface. This allows
driver domains to use buffers of unpriveledged guests without
additional memory copying.

config DRM_XEN_ZCOPY_CMA
bool "Use CMA to allocate buffers"
depends on DRM_XEN_ZCOPY
help
Use CMA to allocate display buffers.

endchoice
16 changes: 16 additions & 0 deletions drivers/gpu/drm/xen/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# SPDX-License-Identifier: GPL-2.0 OR MIT

drm_xen_front-objs := xen_drm_front.o \
xen_drm_front_kms.o \
xen_drm_front_conn.o \
xen_drm_front_evtchnl.o \
xen_drm_front_shbuf.o \
xen_drm_front_cfg.o \
xen_drm_front_gem.o

obj-$(CONFIG_DRM_XEN_FRONTEND) += drm_xen_front.o

drm_xen_zcopy-objs := xen_drm_zcopy.o \
xen_drm_zcopy_balloon.o

obj-$(CONFIG_DRM_XEN_ZCOPY) += drm_xen_zcopy.o
Loading