All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFCv1 00/12] Atomic/nuclear modeset/pageflip
@ 2013-10-06  0:45 Rob Clark
  2013-10-06  0:45 ` [RFCv1 01/12] drm: add atomic fxns Rob Clark
                   ` (11 more replies)
  0 siblings, 12 replies; 38+ messages in thread
From: Rob Clark @ 2013-10-06  0:45 UTC (permalink / raw)
  To: dri-devel

Global thermonuclear modeflip?

This patchset is the merging of Ville's atomic modeset ioctl, and
the drm_{crtc,plane}_state stuff from my original nuclear pageflip
RFC.

It is currently in a fairly "rough draft" state, with a few areas
that I need to revisit.  But I think it is far enough along to give
folks a peak at what I have in mind.

Compared to my earlier nuclear pageflip RFC, there is now a set of
drm_atomic helpers which do most of the non-hw-specific work for
the different drivers.

Unlike the crtc helpers, it is intended that the atomic helpers can
be used piecemeal by the drivers, either using all or overriding
parts as needed.

A naive driver, with no special constraints or hw support for atomic
updates may simply add the following to their driver struct:

    .atomic_begin     = drm_atomic_helper_begin,
    .atomic_set_event = drm_atomic_helper_set_event,
    .atomic_check     = drm_atomic_helper_check,
    .atomic_commit    = drm_atomic_helper_commit,
    .atomic_end       = drm_atomic_helper_end,
    .atomic_helpers   = &drm_atomic_helper_funcs,

In addition, if you're plane/crtc doesn't already have it's own
custom properties, then add to your plane/crtc_funcs:

    .set_property     = drm_atomic_helper_{plane,crtc}_set_property,

A driver which can have (for example) conflicting modes across
multiple crtcs (for example, bandwidth limitations or clock/pll
configuration restrictions), can wrap drm_atomic_helper_check()
with their own driver specific .atomic_check() function.

A driver which can support true atomic updates can wrap
drm_atomic_helper_commit().

A driver with custom properties should override the appropriate
get_state(), check_state(), and commit_state() functions in
.atomic_helpers if it uses the drm-atomic-helpers.  Otherwise it
is free to use &drm_atomic_helper_funcs as-is.

TODO:
 * revisit fb refcnting
 * fix drivers with custom plane or crtc properties

Rob Clark (9):
  drm: add atomic fxns
  drm: add object property type
  drm: add DRM_MODE_PROP_DYNAMIC property flag
  drm: add DRM_MODE_PROP_SIGNED property flag
  drm: helpers to find mode objects (BEFORE drm: split property values
    out)
  drm: split propvals out and blob property support
  drm: convert plane to properties/state
  drm: convert crtc to properties/state
  ARM: add get_user() support for 8 byte types

Ville Syrjälä (3):
  drm: Allow drm_mode_object_find() to look up an object of any type
  drm: Refactor object property check code
  drm: Atomic modeset ioctl

 arch/arm/include/asm/uaccess.h              |   18 +-
 arch/arm/lib/getuser.S                      |   17 +-
 drivers/gpu/drm/Makefile                    |    3 +-
 drivers/gpu/drm/ast/ast_drv.c               |    6 +
 drivers/gpu/drm/ast/ast_drv.h               |    1 +
 drivers/gpu/drm/ast/ast_mode.c              |    1 +
 drivers/gpu/drm/cirrus/cirrus_drv.c         |    6 +
 drivers/gpu/drm/cirrus/cirrus_drv.h         |    1 +
 drivers/gpu/drm/cirrus/cirrus_mode.c        |    1 +
 drivers/gpu/drm/drm_atomic_helper.c         |  456 ++++++++++
 drivers/gpu/drm/drm_crtc.c                  | 1219 ++++++++++++++++++---------
 drivers/gpu/drm/drm_drv.c                   |    1 +
 drivers/gpu/drm/drm_fb_helper.c             |   20 +-
 drivers/gpu/drm/exynos/exynos_drm_crtc.c    |   13 +-
 drivers/gpu/drm/exynos/exynos_drm_drv.c     |    7 +
 drivers/gpu/drm/exynos/exynos_drm_encoder.c |    6 +-
 drivers/gpu/drm/exynos/exynos_drm_plane.c   |   17 +-
 drivers/gpu/drm/gma500/cdv_intel_crt.c      |    4 +-
 drivers/gpu/drm/gma500/cdv_intel_display.c  |    1 +
 drivers/gpu/drm/gma500/cdv_intel_dp.c       |    7 +-
 drivers/gpu/drm/gma500/cdv_intel_hdmi.c     |    7 +-
 drivers/gpu/drm/gma500/cdv_intel_lvds.c     |   10 +-
 drivers/gpu/drm/gma500/mdfld_dsi_output.c   |   11 +-
 drivers/gpu/drm/gma500/psb_drv.c            |    7 +
 drivers/gpu/drm/gma500/psb_drv.h            |    1 +
 drivers/gpu/drm/gma500/psb_intel_display.c  |    1 +
 drivers/gpu/drm/gma500/psb_intel_drv.h      |    4 +-
 drivers/gpu/drm/gma500/psb_intel_lvds.c     |   10 +-
 drivers/gpu/drm/gma500/psb_intel_sdvo.c     |   23 +-
 drivers/gpu/drm/i2c/ch7006_drv.c            |    4 +-
 drivers/gpu/drm/i915/i915_drv.c             |    8 +
 drivers/gpu/drm/i915/intel_crt.c            |    4 +-
 drivers/gpu/drm/i915/intel_display.c        |    4 +-
 drivers/gpu/drm/i915/intel_dp.c             |    7 +-
 drivers/gpu/drm/i915/intel_drv.h            |    1 +
 drivers/gpu/drm/i915/intel_hdmi.c           |    7 +-
 drivers/gpu/drm/i915/intel_lvds.c           |    4 +-
 drivers/gpu/drm/i915/intel_sdvo.c           |   23 +-
 drivers/gpu/drm/i915/intel_sprite.c         |   19 +-
 drivers/gpu/drm/i915/intel_tv.c             |   11 +-
 drivers/gpu/drm/mgag200/mgag200_drv.c       |    7 +
 drivers/gpu/drm/mgag200/mgag200_drv.h       |    1 +
 drivers/gpu/drm/mgag200/mgag200_mode.c      |    1 +
 drivers/gpu/drm/msm/mdp4/mdp4_crtc.c        |   11 +-
 drivers/gpu/drm/msm/mdp4/mdp4_plane.c       |   20 +-
 drivers/gpu/drm/msm/msm_drv.c               |    6 +
 drivers/gpu/drm/msm/msm_drv.h               |    1 +
 drivers/gpu/drm/nouveau/dispnv04/crtc.c     |    1 +
 drivers/gpu/drm/nouveau/dispnv04/tvnv17.c   |    3 +-
 drivers/gpu/drm/nouveau/nouveau_connector.c |    7 +-
 drivers/gpu/drm/nouveau/nouveau_drm.c       |    7 +
 drivers/gpu/drm/nouveau/nouveau_drm.h       |    1 +
 drivers/gpu/drm/nouveau/nv50_display.c      |    1 +
 drivers/gpu/drm/omapdrm/omap_crtc.c         |   18 +-
 drivers/gpu/drm/omapdrm/omap_drv.c          |   12 +-
 drivers/gpu/drm/omapdrm/omap_drv.h          |    5 +-
 drivers/gpu/drm/omapdrm/omap_plane.c        |   34 +-
 drivers/gpu/drm/qxl/qxl_display.c           |    6 +-
 drivers/gpu/drm/qxl/qxl_drv.c               |    9 +
 drivers/gpu/drm/radeon/radeon_connectors.c  |    9 +-
 drivers/gpu/drm/radeon/radeon_display.c     |    2 +
 drivers/gpu/drm/radeon/radeon_drv.c         |    9 +
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c      |    2 +
 drivers/gpu/drm/rcar-du/rcar_du_drv.c       |    7 +
 drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c   |    3 +-
 drivers/gpu/drm/rcar-du/rcar_du_plane.c     |    9 +-
 drivers/gpu/drm/rcar-du/rcar_du_vgacon.c    |    3 +-
 drivers/gpu/drm/shmobile/shmob_drm_crtc.c   |    8 +-
 drivers/gpu/drm/shmobile/shmob_drm_drv.c    |    7 +
 drivers/gpu/drm/shmobile/shmob_drm_plane.c  |    6 +-
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c        |    1 +
 drivers/gpu/drm/tilcdc/tilcdc_drv.c         |    6 +
 drivers/gpu/drm/tilcdc/tilcdc_drv.h         |    1 +
 drivers/gpu/drm/tilcdc/tilcdc_slave.c       |    3 +-
 drivers/gpu/drm/udl/udl_connector.c         |    6 +-
 drivers/gpu/drm/udl/udl_drv.c               |    8 +
 drivers/gpu/drm/udl/udl_modeset.c           |    2 +
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.c         |    7 +
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.h         |    1 +
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c         |    4 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.h         |    4 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c         |    1 +
 drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c        |    1 +
 drivers/gpu/host1x/drm/dc.c                 |   17 +-
 drivers/gpu/host1x/drm/drm.c                |    7 +
 drivers/gpu/host1x/drm/drm.h                |    1 +
 drivers/staging/imx-drm/imx-drm-core.c      |    8 +
 drivers/staging/imx-drm/ipuv3-crtc.c        |    1 +
 include/drm/drmP.h                          |   83 ++
 include/drm/drm_atomic_helper.h             |  152 ++++
 include/drm/drm_crtc.h                      |  243 +++++-
 include/uapi/drm/drm.h                      |   12 +
 include/uapi/drm/drm_mode.h                 |   28 +
 93 files changed, 2242 insertions(+), 542 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_atomic_helper.c
 create mode 100644 include/drm/drm_atomic_helper.h

-- 
1.8.3.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [RFCv1 01/12] drm: add atomic fxns
  2013-10-06  0:45 [RFCv1 00/12] Atomic/nuclear modeset/pageflip Rob Clark
@ 2013-10-06  0:45 ` Rob Clark
  2013-10-06  0:45 ` [RFCv1 02/12] drm: add object property type Rob Clark
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 38+ messages in thread
From: Rob Clark @ 2013-10-06  0:45 UTC (permalink / raw)
  To: dri-devel

The 'atomic' mechanism allows for multiple properties to be updated,
checked, and commited atomically.  This will be the basis of atomic-
modeset and nuclear-pageflip.

The basic flow is:

   state = dev->atomic_begin();
   for (... one or more ...)
      obj->set_property(obj, state, prop, value);
   if (dev->atomic_check(state))
      dev->atomic_commit(state);
   dev->atomic_end(state);

The split of check and commit steps is to allow for ioctls with a
test-only flag (which would skip the commit step).
---
 drivers/gpu/drm/Makefile                    |   3 +-
 drivers/gpu/drm/ast/ast_drv.c               |   6 ++
 drivers/gpu/drm/ast/ast_drv.h               |   1 +
 drivers/gpu/drm/cirrus/cirrus_drv.c         |   6 ++
 drivers/gpu/drm/cirrus/cirrus_drv.h         |   1 +
 drivers/gpu/drm/drm_atomic_helper.c         | 129 ++++++++++++++++++++++++++
 drivers/gpu/drm/drm_crtc.c                  | 139 ++++++++++++++++++----------
 drivers/gpu/drm/exynos/exynos_drm_crtc.c    |   4 +-
 drivers/gpu/drm/exynos/exynos_drm_drv.c     |   7 ++
 drivers/gpu/drm/exynos/exynos_drm_plane.c   |   4 +-
 drivers/gpu/drm/gma500/cdv_intel_crt.c      |   4 +-
 drivers/gpu/drm/gma500/cdv_intel_dp.c       |   4 +-
 drivers/gpu/drm/gma500/cdv_intel_hdmi.c     |   4 +-
 drivers/gpu/drm/gma500/cdv_intel_lvds.c     |   4 +-
 drivers/gpu/drm/gma500/mdfld_dsi_output.c   |   3 +-
 drivers/gpu/drm/gma500/psb_drv.c            |   7 ++
 drivers/gpu/drm/gma500/psb_drv.h            |   1 +
 drivers/gpu/drm/gma500/psb_intel_drv.h      |   4 +-
 drivers/gpu/drm/gma500/psb_intel_lvds.c     |   4 +-
 drivers/gpu/drm/gma500/psb_intel_sdvo.c     |   4 +-
 drivers/gpu/drm/i915/i915_drv.c             |   8 ++
 drivers/gpu/drm/i915/intel_crt.c            |   4 +-
 drivers/gpu/drm/i915/intel_dp.c             |   4 +-
 drivers/gpu/drm/i915/intel_drv.h            |   1 +
 drivers/gpu/drm/i915/intel_hdmi.c           |   4 +-
 drivers/gpu/drm/i915/intel_lvds.c           |   4 +-
 drivers/gpu/drm/i915/intel_sdvo.c           |   4 +-
 drivers/gpu/drm/i915/intel_tv.c             |   5 +-
 drivers/gpu/drm/mgag200/mgag200_drv.c       |   7 ++
 drivers/gpu/drm/mgag200/mgag200_drv.h       |   1 +
 drivers/gpu/drm/msm/mdp4/mdp4_crtc.c        |   4 +-
 drivers/gpu/drm/msm/mdp4/mdp4_plane.c       |   4 +-
 drivers/gpu/drm/msm/msm_drv.c               |   6 ++
 drivers/gpu/drm/msm/msm_drv.h               |   1 +
 drivers/gpu/drm/nouveau/nouveau_connector.c |   3 +-
 drivers/gpu/drm/nouveau/nouveau_drm.c       |   7 ++
 drivers/gpu/drm/nouveau/nouveau_drm.h       |   1 +
 drivers/gpu/drm/omapdrm/omap_crtc.c         |   7 +-
 drivers/gpu/drm/omapdrm/omap_drv.c          |   6 ++
 drivers/gpu/drm/omapdrm/omap_drv.h          |   5 +-
 drivers/gpu/drm/omapdrm/omap_plane.c        |   4 +-
 drivers/gpu/drm/qxl/qxl_display.c           |   4 +-
 drivers/gpu/drm/qxl/qxl_drv.c               |   9 ++
 drivers/gpu/drm/radeon/radeon_connectors.c  |   9 +-
 drivers/gpu/drm/radeon/radeon_drv.c         |   9 ++
 drivers/gpu/drm/rcar-du/rcar_du_drv.c       |   7 ++
 drivers/gpu/drm/rcar-du/rcar_du_plane.c     |   4 +-
 drivers/gpu/drm/shmobile/shmob_drm_drv.c    |   7 ++
 drivers/gpu/drm/tilcdc/tilcdc_drv.c         |   6 ++
 drivers/gpu/drm/tilcdc/tilcdc_drv.h         |   1 +
 drivers/gpu/drm/tilcdc/tilcdc_slave.c       |   3 +-
 drivers/gpu/drm/udl/udl_connector.c         |   6 +-
 drivers/gpu/drm/udl/udl_drv.c               |   8 ++
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.c         |   7 ++
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.h         |   1 +
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c         |   4 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.h         |   4 +-
 drivers/gpu/host1x/drm/drm.c                |   7 ++
 drivers/gpu/host1x/drm/drm.h                |   1 +
 drivers/staging/imx-drm/imx-drm-core.c      |   8 ++
 include/drm/drmP.h                          |  77 +++++++++++++++
 include/drm/drm_atomic_helper.h             |  84 +++++++++++++++++
 include/drm/drm_crtc.h                      |  14 +--
 63 files changed, 611 insertions(+), 98 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_atomic_helper.c
 create mode 100644 include/drm/drm_atomic_helper.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index f089adf..4e68e0d 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -13,7 +13,8 @@ drm-y       :=	drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
 		drm_crtc.o drm_modes.o drm_edid.o \
 		drm_info.o drm_debugfs.o drm_encoder_slave.o \
 		drm_trace_points.o drm_global.o drm_prime.o \
-		drm_rect.o drm_vma_manager.o drm_flip_work.o
+		drm_rect.o drm_vma_manager.o drm_flip_work.o \
+		drm_atomic_helper.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c
index 32e270d..d78edaf 100644
--- a/drivers/gpu/drm/ast/ast_drv.c
+++ b/drivers/gpu/drm/ast/ast_drv.c
@@ -217,6 +217,12 @@ static struct drm_driver driver = {
 	.dumb_map_offset = ast_dumb_mmap_offset,
 	.dumb_destroy = drm_gem_dumb_destroy,
 
+	.atomic_begin     = drm_atomic_helper_begin,
+	.atomic_set_event = drm_atomic_helper_set_event,
+	.atomic_check     = drm_atomic_helper_check,
+	.atomic_commit    = drm_atomic_helper_commit,
+	.atomic_end       = drm_atomic_helper_end,
+	.atomic_helpers   = &drm_atomic_helper_funcs,
 };
 
 static int __init ast_init(void)
diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h
index 8492b68..5dddca5 100644
--- a/drivers/gpu/drm/ast/ast_drv.h
+++ b/drivers/gpu/drm/ast/ast_drv.h
@@ -29,6 +29,7 @@
 #define __AST_DRV_H__
 
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic_helper.h>
 
 #include <drm/ttm/ttm_bo_api.h>
 #include <drm/ttm/ttm_bo_driver.h>
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c
index 138364d..e558d1a 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.c
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.c
@@ -102,6 +102,12 @@ static struct drm_driver driver = {
 	.dumb_create = cirrus_dumb_create,
 	.dumb_map_offset = cirrus_dumb_mmap_offset,
 	.dumb_destroy = drm_gem_dumb_destroy,
+	.atomic_begin     = drm_atomic_helper_begin,
+	.atomic_set_event = drm_atomic_helper_set_event,
+	.atomic_check     = drm_atomic_helper_check,
+	.atomic_commit    = drm_atomic_helper_commit,
+	.atomic_end       = drm_atomic_helper_end,
+	.atomic_helpers   = &drm_atomic_helper_funcs,
 };
 
 static struct pci_driver cirrus_pci_driver = {
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h
index 9b0bb91..7d363dc 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.h
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.h
@@ -14,6 +14,7 @@
 #include <video/vga.h>
 
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic_helper.h>
 
 #include <drm/ttm/ttm_bo_api.h>
 #include <drm/ttm/ttm_bo_driver.h>
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
new file mode 100644
index 0000000..563f37d
--- /dev/null
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+
+struct drm_atomic_helper_state {
+	uint32_t flags;
+};
+
+/**
+ * drm_atomic_helper_begin - start a sequence of atomic updates
+ * @dev: DRM device
+ * @flags: the modifier flags that userspace has requested
+ *
+ * Begin a sequence of atomic property sets.  Returns a driver
+ * private state object that is passed back into the various
+ * object's set_property() fxns, and into the remainder of the
+ * atomic funcs.  The state object should accumulate the changes
+ * from one o more set_property()'s.  At the end, the state can
+ * be checked, and optionally committed.
+ *
+ * RETURNS
+ *   a driver private state object, which is passed back in to
+ *   the various other atomic fxns, or error (such as -EBUSY if
+ *   there is still a pending async update)
+ */
+void *drm_atomic_helper_begin(struct drm_device *dev, uint32_t flags)
+{
+	struct drm_atomic_helper_state *state;
+	int sz;
+	void *ptr;
+
+	sz = sizeof(*state);
+
+	ptr = kzalloc(sz, GFP_KERNEL);
+
+	state = ptr;
+	ptr = &state[1];
+
+	state->flags = flags;
+	return state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_begin);
+
+/**
+ * drm_atomic_helper_set_event - set a pending event on mode object
+ * @dev: DRM device
+ * @state: the driver private state object
+ * @obj: the object to set the event on
+ * @event: the event to send back
+ *
+ * Set pending event for an update on the specified object.  The
+ * event is to be sent back to userspace after the update completes.
+ */
+int drm_atomic_helper_set_event(struct drm_device *dev,
+		void *state, struct drm_mode_object *obj,
+		struct drm_pending_vblank_event *event)
+{
+	return -EINVAL;  /* for now */
+}
+EXPORT_SYMBOL(drm_atomic_helper_set_event);
+
+/**
+ * drm_atomic_helper_check - validate state object
+ * @dev: DRM device
+ * @state: the driver private state object
+ *
+ * Check the state object to see if the requested state is
+ * physically possible.
+ *
+ * RETURNS
+ * Zero for success or -errno
+ */
+int drm_atomic_helper_check(struct drm_device *dev, void *state)
+{
+	return 0;  /* for now */
+}
+EXPORT_SYMBOL(drm_atomic_helper_check);
+
+/**
+ * drm_atomic_helper_commit - commit state
+ * @dev: DRM device
+ * @state: the driver private state object
+ *
+ * Commit the state.  This will only be called if atomic_check()
+ * succeeds.
+ *
+ * RETURNS
+ * Zero for success or -errno
+ */
+int drm_atomic_helper_commit(struct drm_device *dev, void *state)
+{
+	return 0;  /* for now */
+}
+EXPORT_SYMBOL(drm_atomic_helper_commit);
+
+/**
+ * drm_atomic_helper_end - conclude the atomic update
+ * @dev: DRM device
+ * @state: the driver private state object
+ *
+ * Release resources associated with the state object.
+ */
+void drm_atomic_helper_end(struct drm_device *dev, void *state)
+{
+	kfree(state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_end);
+
+
+const struct drm_atomic_helper_funcs drm_atomic_helper_funcs = {
+};
+EXPORT_SYMBOL(drm_atomic_helper_funcs);
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index bff2fa9..f2a6d72 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -3231,20 +3231,21 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
 	return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv);
 }
 
-static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
-					   struct drm_property *property,
-					   uint64_t value)
+static int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
+					   void *state, struct drm_property *property,
+					   uint64_t value, void *blob_data)
 {
 	int ret = -EINVAL;
-	struct drm_connector *connector = obj_to_connector(obj);
 
 	/* Do DPMS ourselves */
 	if (property == connector->dev->mode_config.dpms_property) {
 		if (connector->funcs->dpms)
 			(*connector->funcs->dpms)(connector, (int)value);
 		ret = 0;
-	} else if (connector->funcs->set_property)
-		ret = connector->funcs->set_property(connector, property, value);
+	} else if (connector->funcs->set_property) {
+		ret = connector->funcs->set_property(connector, state,
+				property, value, blob_data);
+	}
 
 	/* store the property value if successful */
 	if (!ret)
@@ -3252,36 +3253,90 @@ static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
 	return ret;
 }
 
-static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
-				      struct drm_property *property,
-				      uint64_t value)
+static int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
+				      void *state, struct drm_property *property,
+				      uint64_t value, void *blob_data)
 {
 	int ret = -EINVAL;
-	struct drm_crtc *crtc = obj_to_crtc(obj);
 
 	if (crtc->funcs->set_property)
-		ret = crtc->funcs->set_property(crtc, property, value);
+		ret = crtc->funcs->set_property(crtc, state, property,
+				value, blob_data);
 	if (!ret)
-		drm_object_property_set_value(obj, property, value);
+		drm_object_property_set_value(&crtc->base, property, value);
 
 	return ret;
 }
 
-static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj,
-				      struct drm_property *property,
-				      uint64_t value)
+static int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+				      void *state, struct drm_property *property,
+				      uint64_t value, void *blob_data)
 {
 	int ret = -EINVAL;
-	struct drm_plane *plane = obj_to_plane(obj);
 
 	if (plane->funcs->set_property)
-		ret = plane->funcs->set_property(plane, property, value);
+		ret = plane->funcs->set_property(plane, state, property,
+				value, blob_data);
 	if (!ret)
-		drm_object_property_set_value(obj, property, value);
+		drm_object_property_set_value(&plane->base, property, value);
 
 	return ret;
 }
 
+static int drm_mode_set_obj_prop(struct drm_device *dev,
+		struct drm_mode_object *obj, void *state,
+		struct drm_property *property, uint64_t value, void *blob_data)
+{
+	if (drm_property_change_is_valid(property, value)) {
+		switch (obj->type) {
+		case DRM_MODE_OBJECT_CONNECTOR:
+			return drm_mode_connector_set_obj_prop(obj_to_connector(obj),
+					state, property, value, blob_data);
+		case DRM_MODE_OBJECT_CRTC:
+			return drm_mode_crtc_set_obj_prop(obj_to_crtc(obj),
+					state, property, value, blob_data);
+		case DRM_MODE_OBJECT_PLANE:
+			return drm_mode_plane_set_obj_prop(obj_to_plane(obj),
+					state, property, value, blob_data);
+		}
+	}
+
+	return -EINVAL;
+}
+
+/* call with mode_config mutex held */
+static int drm_mode_set_obj_prop_id(struct drm_device *dev, void *state,
+		uint32_t obj_id, uint32_t obj_type,
+		uint32_t prop_id, uint64_t value, void *blob_data)
+{
+	struct drm_mode_object *arg_obj;
+	struct drm_mode_object *prop_obj;
+	struct drm_property *property;
+	int i;
+
+	arg_obj = drm_mode_object_find(dev, obj_id, obj_type);
+	if (!arg_obj)
+		return -EINVAL;
+	if (!arg_obj->properties)
+		return -EINVAL;
+
+	for (i = 0; i < arg_obj->properties->count; i++)
+		if (arg_obj->properties->ids[i] == prop_id)
+			break;
+
+	if (i == arg_obj->properties->count)
+		return -EINVAL;
+
+	prop_obj = drm_mode_object_find(dev, prop_id,
+					DRM_MODE_OBJECT_PROPERTY);
+	if (!prop_obj)
+		return -EINVAL;
+	property = obj_to_property(prop_obj);
+
+	return drm_mode_set_obj_prop(dev, arg_obj, state, property,
+			value, blob_data);
+}
+
 int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
 				      struct drm_file *file_priv)
 {
@@ -3342,53 +3397,35 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
 				    struct drm_file *file_priv)
 {
 	struct drm_mode_obj_set_property *arg = data;
-	struct drm_mode_object *arg_obj;
-	struct drm_mode_object *prop_obj;
-	struct drm_property *property;
+	void *state;
 	int ret = -EINVAL;
-	int i;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
 
-	arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
-	if (!arg_obj)
-		goto out;
-	if (!arg_obj->properties)
-		goto out;
-
-	for (i = 0; i < arg_obj->properties->count; i++)
-		if (arg_obj->properties->ids[i] == arg->prop_id)
-			break;
+	state = dev->driver->atomic_begin(dev, 0);
+	if (IS_ERR(state)) {
+		ret = PTR_ERR(state);
+		goto out_unlock;
+	}
 
-	if (i == arg_obj->properties->count)
+	ret = drm_mode_set_obj_prop_id(dev, state,
+			arg->obj_id, arg->obj_type,
+			arg->prop_id, arg->value, NULL);
+	if (ret)
 		goto out;
 
-	prop_obj = drm_mode_object_find(dev, arg->prop_id,
-					DRM_MODE_OBJECT_PROPERTY);
-	if (!prop_obj)
-		goto out;
-	property = obj_to_property(prop_obj);
-
-	if (!drm_property_change_is_valid(property, arg->value))
+	ret = dev->driver->atomic_check(dev, state);
+	if (ret)
 		goto out;
 
-	switch (arg_obj->type) {
-	case DRM_MODE_OBJECT_CONNECTOR:
-		ret = drm_mode_connector_set_obj_prop(arg_obj, property,
-						      arg->value);
-		break;
-	case DRM_MODE_OBJECT_CRTC:
-		ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value);
-		break;
-	case DRM_MODE_OBJECT_PLANE:
-		ret = drm_mode_plane_set_obj_prop(arg_obj, property, arg->value);
-		break;
-	}
+	ret = dev->driver->atomic_commit(dev, state);
 
 out:
+	dev->driver->atomic_end(dev, state);
+out_unlock:
 	drm_modeset_unlock_all(dev);
 	return ret;
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index ebc0150..82a9fca 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -254,8 +254,10 @@ static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
 }
 
 static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
+					void *state,
 					struct drm_property *property,
-					uint64_t val)
+					uint64_t val,
+					void *blob_data)
 {
 	struct drm_device *dev = crtc->dev;
 	struct exynos_drm_private *dev_priv = dev->dev_private;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index bb82ef7..08285cb 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -13,6 +13,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 
 #include <drm/exynos_drm.h>
 
@@ -270,6 +271,12 @@ static struct drm_driver exynos_drm_driver = {
 	.dumb_create		= exynos_drm_gem_dumb_create,
 	.dumb_map_offset	= exynos_drm_gem_dumb_map_offset,
 	.dumb_destroy		= drm_gem_dumb_destroy,
+	.atomic_begin     = drm_atomic_helper_begin,
+	.atomic_set_event = drm_atomic_helper_set_event,
+	.atomic_check     = drm_atomic_helper_check,
+	.atomic_commit    = drm_atomic_helper_commit,
+	.atomic_end       = drm_atomic_helper_end,
+	.atomic_helpers   = &drm_atomic_helper_funcs,
 	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
 	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
 	.gem_prime_export	= exynos_dmabuf_prime_export,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index fcb0652..2e31fb8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -217,8 +217,10 @@ static void exynos_plane_destroy(struct drm_plane *plane)
 }
 
 static int exynos_plane_set_property(struct drm_plane *plane,
+				     void *state,
 				     struct drm_property *property,
-				     uint64_t val)
+				     uint64_t val,
+				     void *blob_data)
 {
 	struct drm_device *dev = plane->dev;
 	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c
index 661af49..d9c612f9 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_crt.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c
@@ -212,8 +212,10 @@ static int cdv_intel_crt_get_modes(struct drm_connector *connector)
 }
 
 static int cdv_intel_crt_set_property(struct drm_connector *connector,
+				  void *state,
 				  struct drm_property *property,
-				  uint64_t value)
+				  uint64_t value,
+				  void *blob_data)
 {
 	return 0;
 }
diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c
index f4eb435..5f1a734 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_dp.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c
@@ -1644,8 +1644,10 @@ cdv_intel_dp_detect_audio(struct drm_connector *connector)
 
 static int
 cdv_intel_dp_set_property(struct drm_connector *connector,
+		      void *state,
 		      struct drm_property *property,
-		      uint64_t val)
+		      uint64_t val,
+		      void *blob_data)
 {
 	struct drm_psb_private *dev_priv = connector->dev->dev_private;
 	struct gma_encoder *encoder = gma_attached_encoder(connector);
diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
index 1c0d723..74e5de1 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
@@ -157,8 +157,10 @@ static enum drm_connector_status cdv_hdmi_detect(
 }
 
 static int cdv_hdmi_set_property(struct drm_connector *connector,
+				       void *state,
 				       struct drm_property *property,
-				       uint64_t value)
+				       uint64_t value,
+				       void *blob_data)
 {
 	struct drm_encoder *encoder = connector->encoder;
 
diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
index 20e08e6..97d76c1 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
@@ -452,8 +452,10 @@ static void cdv_intel_lvds_destroy(struct drm_connector *connector)
 }
 
 static int cdv_intel_lvds_set_property(struct drm_connector *connector,
+				       void *state,
 				       struct drm_property *property,
-				       uint64_t value)
+				       uint64_t value,
+				       void *blob_data)
 {
 	struct drm_encoder *encoder = connector->encoder;
 
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
index 860a4ee..4505286 100644
--- a/drivers/gpu/drm/gma500/mdfld_dsi_output.c
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
@@ -244,7 +244,8 @@ mdfld_dsi_connector_detect(struct drm_connector *connector, bool force)
 
 static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
 				struct drm_property *property,
-				uint64_t value)
+				uint64_t value,
+				void *blob_data)
 {
 	struct drm_encoder *encoder = connector->encoder;
 
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index fcb4e9f..391057b 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -646,6 +646,13 @@ static struct drm_driver driver = {
 	.preclose = psb_driver_preclose,
 	.postclose = psb_driver_close,
 
+	.atomic_begin     = drm_atomic_helper_begin,
+	.atomic_set_event = drm_atomic_helper_set_event,
+	.atomic_check     = drm_atomic_helper_check,
+	.atomic_commit    = drm_atomic_helper_commit,
+	.atomic_end       = drm_atomic_helper_end,
+	.atomic_helpers   = &drm_atomic_helper_funcs,
+
 	.gem_init_object = psb_gem_init_object,
 	.gem_free_object = psb_gem_free_object,
 	.gem_vm_ops = &psb_gem_vm_ops,
diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h
index 4535ac7..ef6a0609 100644
--- a/drivers/gpu/drm/gma500/psb_drv.h
+++ b/drivers/gpu/drm/gma500/psb_drv.h
@@ -25,6 +25,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_global.h>
 #include <drm/gma_drm.h>
+#include <drm/drm_atomic_helper.h>
 #include "psb_reg.h"
 #include "psb_intel_drv.h"
 #include "gma_display.h"
diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h
index bde27fd..d8e1911 100644
--- a/drivers/gpu/drm/gma500/psb_intel_drv.h
+++ b/drivers/gpu/drm/gma500/psb_intel_drv.h
@@ -261,8 +261,10 @@ extern bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder,
 extern int psb_intel_lvds_mode_valid(struct drm_connector *connector,
 				     struct drm_display_mode *mode);
 extern int psb_intel_lvds_set_property(struct drm_connector *connector,
+					void *state,
 					struct drm_property *property,
-					uint64_t value);
+					uint64_t value,
+					void *blob_data);
 extern void psb_intel_lvds_destroy(struct drm_connector *connector);
 extern const struct drm_encoder_funcs psb_intel_lvds_enc_funcs;
 
diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c
index 32342f6..e3a3923 100644
--- a/drivers/gpu/drm/gma500/psb_intel_lvds.c
+++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c
@@ -569,8 +569,10 @@ void psb_intel_lvds_destroy(struct drm_connector *connector)
 }
 
 int psb_intel_lvds_set_property(struct drm_connector *connector,
+				       void *state,
 				       struct drm_property *property,
-				       uint64_t value)
+				       uint64_t value,
+				       void *blob_data)
 {
 	struct drm_encoder *encoder = connector->encoder;
 
diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
index 6f01cdf..47e0a2a 100644
--- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c
+++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
@@ -1688,8 +1688,10 @@ static bool psb_intel_sdvo_detect_hdmi_audio(struct drm_connector *connector)
 
 static int
 psb_intel_sdvo_set_property(struct drm_connector *connector,
+			void *state,
 			struct drm_property *property,
-			uint64_t val)
+			uint64_t val,
+			void *blob_data)
 {
 	struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector);
 	struct psb_intel_sdvo_connector *psb_intel_sdvo_connector = to_psb_intel_sdvo_connector(connector);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 69d8ed5..a44be85 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -958,6 +958,14 @@ static struct drm_driver driver = {
 	.dumb_create = i915_gem_dumb_create,
 	.dumb_map_offset = i915_gem_mmap_gtt,
 	.dumb_destroy = drm_gem_dumb_destroy,
+
+	.atomic_begin     = drm_atomic_helper_begin,
+	.atomic_set_event = drm_atomic_helper_set_event,
+	.atomic_check     = drm_atomic_helper_check,
+	.atomic_commit    = drm_atomic_helper_commit,
+	.atomic_end       = drm_atomic_helper_end,
+	.atomic_helpers   = &drm_atomic_helper_funcs,
+
 	.ioctls = i915_ioctls,
 	.fops = &i915_driver_fops,
 	.name = DRIVER_NAME,
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index ea9022e..9a00797 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -676,8 +676,10 @@ static int intel_crt_get_modes(struct drm_connector *connector)
 }
 
 static int intel_crt_set_property(struct drm_connector *connector,
+				  void *state,
 				  struct drm_property *property,
-				  uint64_t value)
+				  uint64_t value,
+				  void *blob_data)
 {
 	return 0;
 }
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 79c14e2..08d29fe 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -2931,8 +2931,10 @@ intel_dp_detect_audio(struct drm_connector *connector)
 
 static int
 intel_dp_set_property(struct drm_connector *connector,
+		      void *state,
 		      struct drm_property *property,
-		      uint64_t val)
+		      uint64_t val,
+		      void *blob_data)
 {
 	struct drm_i915_private *dev_priv = connector->dev->dev_private;
 	struct intel_connector *intel_connector = to_intel_connector(connector);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 28cae80..8556957 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -31,6 +31,7 @@
 #include "i915_drv.h"
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_dp_helper.h>
 
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 4148cc8..dbc02ab 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -993,8 +993,10 @@ intel_hdmi_detect_audio(struct drm_connector *connector)
 
 static int
 intel_hdmi_set_property(struct drm_connector *connector,
+			void *state,
 			struct drm_property *property,
-			uint64_t val)
+			uint64_t val,
+			void *blob_data)
 {
 	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
 	struct intel_digital_port *intel_dig_port =
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 831a5c0..1eb7a97 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -472,8 +472,10 @@ static void intel_lvds_destroy(struct drm_connector *connector)
 }
 
 static int intel_lvds_set_property(struct drm_connector *connector,
+				   void *state,
 				   struct drm_property *property,
-				   uint64_t value)
+				   uint64_t value,
+				   void *blob_data)
 {
 	struct intel_connector *intel_connector = to_intel_connector(connector);
 	struct drm_device *dev = connector->dev;
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 49482fd..e863830 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -2022,8 +2022,10 @@ static bool intel_sdvo_detect_hdmi_audio(struct drm_connector *connector)
 
 static int
 intel_sdvo_set_property(struct drm_connector *connector,
+			void *state,
 			struct drm_property *property,
-			uint64_t val)
+			uint64_t val,
+			void *blob_data)
 {
 	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
 	struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index dd6f84b..4ef1949 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1440,8 +1440,9 @@ intel_tv_destroy(struct drm_connector *connector)
 
 
 static int
-intel_tv_set_property(struct drm_connector *connector, struct drm_property *property,
-		      uint64_t val)
+intel_tv_set_property(struct drm_connector *connector, void *state,
+		      struct drm_property *property,
+		      uint64_t val, void *blob_data)
 {
 	struct drm_device *dev = connector->dev;
 	struct intel_tv *intel_tv = intel_attached_tv(connector);
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c
index fcce7b2..2047479 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -104,6 +104,13 @@ static struct drm_driver driver = {
 	.dumb_create = mgag200_dumb_create,
 	.dumb_map_offset = mgag200_dumb_mmap_offset,
 	.dumb_destroy = drm_gem_dumb_destroy,
+
+	.atomic_begin     = drm_atomic_helper_begin,
+	.atomic_set_event = drm_atomic_helper_set_event,
+	.atomic_check     = drm_atomic_helper_check,
+	.atomic_commit    = drm_atomic_helper_commit,
+	.atomic_end       = drm_atomic_helper_end,
+	.atomic_helpers   = &drm_atomic_helper_funcs,
 };
 
 static struct pci_driver mgag200_pci_driver = {
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h
index baaae19..0b50f77 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -16,6 +16,7 @@
 #include <video/vga.h>
 
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/ttm/ttm_bo_api.h>
 #include <drm/ttm/ttm_bo_driver.h>
 #include <drm/ttm/ttm_placement.h>
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
index de6bea2..e81883d 100644
--- a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
+++ b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
@@ -392,8 +392,8 @@ static int mdp4_crtc_page_flip(struct drm_crtc *crtc,
 			&mdp4_crtc->pageflip_work);
 }
 
-static int mdp4_crtc_set_property(struct drm_crtc *crtc,
-		struct drm_property *property, uint64_t val)
+static int mdp4_crtc_set_property(struct drm_crtc *crtc, void *state,
+		struct drm_property *property, uint64_t val, void *blob_data)
 {
 	// XXX
 	return -EINVAL;
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp4/mdp4_plane.c
index 3468229..f0b6b12 100644
--- a/drivers/gpu/drm/msm/mdp4/mdp4_plane.c
+++ b/drivers/gpu/drm/msm/mdp4/mdp4_plane.c
@@ -82,8 +82,8 @@ void mdp4_plane_install_properties(struct drm_plane *plane,
 	// XXX
 }
 
-int mdp4_plane_set_property(struct drm_plane *plane,
-		struct drm_property *property, uint64_t val)
+int mdp4_plane_set_property(struct drm_plane *plane, void *state,
+		struct drm_property *property, uint64_t val, void *blob_data)
 {
 	// XXX
 	return -EINVAL;
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index b3a2f16..a8acca5 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -698,6 +698,12 @@ static struct drm_driver msm_driver = {
 	.dumb_create        = msm_gem_dumb_create,
 	.dumb_map_offset    = msm_gem_dumb_map_offset,
 	.dumb_destroy       = drm_gem_dumb_destroy,
+	.atomic_begin       = drm_atomic_helper_begin,
+	.atomic_set_event   = drm_atomic_helper_set_event,
+	.atomic_check       = drm_atomic_helper_check,
+	.atomic_commit      = drm_atomic_helper_commit,
+	.atomic_end         = drm_atomic_helper_end,
+	.atomic_helpers     = &drm_atomic_helper_funcs,
 #ifdef CONFIG_DEBUG_FS
 	.debugfs_init       = msm_debugfs_init,
 	.debugfs_cleanup    = msm_debugfs_cleanup,
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index df8f1d0..e04fd84 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -40,6 +40,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/msm_drm.h>
 
 struct msm_kms;
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index c5b36f9..89ed23d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -445,7 +445,8 @@ nouveau_connector_force(struct drm_connector *connector)
 
 static int
 nouveau_connector_set_property(struct drm_connector *connector,
-			       struct drm_property *property, uint64_t value)
+		void *state, struct drm_property *property,
+		uint64_t value, void *blob_data)
 {
 	struct nouveau_display *disp = nouveau_display(connector->dev);
 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index e893c53..55b56e3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -843,6 +843,13 @@ driver = {
 	.dumb_map_offset = nouveau_display_dumb_map_offset,
 	.dumb_destroy = drm_gem_dumb_destroy,
 
+	.atomic_begin     = drm_atomic_helper_begin,
+	.atomic_set_event = drm_atomic_helper_set_event,
+	.atomic_check     = drm_atomic_helper_check,
+	.atomic_commit    = drm_atomic_helper_commit,
+	.atomic_end       = drm_atomic_helper_end,
+	.atomic_helpers   = &drm_atomic_helper_funcs,
+
 	.name = DRIVER_NAME,
 	.desc = DRIVER_DESC,
 #ifdef GIT_REVISION
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h
index 994fd6e..44f2fc9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.h
@@ -29,6 +29,7 @@
 #include <subdev/vm.h>
 
 #include <drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/nouveau_drm.h>
 
 #include <drm/ttm/ttm_bo_api.h>
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index 0fd2eb1..5dd22ab 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -362,8 +362,8 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
 	return 0;
 }
 
-static int omap_crtc_set_property(struct drm_crtc *crtc,
-		struct drm_property *property, uint64_t val)
+static int omap_crtc_set_property(struct drm_crtc *crtc, void *state,
+		struct drm_property *property, uint64_t val, void *blob_data)
 {
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 	struct omap_drm_private *priv = crtc->dev->dev_private;
@@ -373,7 +373,8 @@ static int omap_crtc_set_property(struct drm_crtc *crtc,
 				!!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
 	}
 
-	return omap_plane_set_property(omap_crtc->plane, property, val);
+	return omap_plane_set_property(omap_crtc->plane, state,
+			property, val, blob_data);
 }
 
 static const struct drm_crtc_funcs omap_crtc_funcs = {
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 2603d90..2aaeda8 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -626,6 +626,12 @@ static struct drm_driver omap_drm_driver = {
 		.dumb_create = omap_gem_dumb_create,
 		.dumb_map_offset = omap_gem_dumb_map_offset,
 		.dumb_destroy = drm_gem_dumb_destroy,
+		.atomic_begin     = drm_atomic_helper_begin,
+		.atomic_set_event = drm_atomic_helper_set_event,
+		.atomic_check     = drm_atomic_helper_check,
+		.atomic_commit    = drm_atomic_helper_commit,
+		.atomic_end       = drm_atomic_helper_end,
+		.atomic_helpers   = &drm_atomic_helper_funcs,
 		.ioctls = ioctls,
 		.num_ioctls = DRM_OMAP_NUM_IOCTLS,
 		.fops = &omapdriver_fops,
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
index 30b95b7..16983cc 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.h
+++ b/drivers/gpu/drm/omapdrm/omap_drv.h
@@ -25,6 +25,7 @@
 #include <linux/types.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/omap_drm.h>
 #include <linux/platform_data/omap_drm.h>
 
@@ -173,8 +174,8 @@ int omap_plane_mode_set(struct drm_plane *plane,
 		void (*fxn)(void *), void *arg);
 void omap_plane_install_properties(struct drm_plane *plane,
 		struct drm_mode_object *obj);
-int omap_plane_set_property(struct drm_plane *plane,
-		struct drm_property *property, uint64_t val);
+int omap_plane_set_property(struct drm_plane *plane, void *state,
+		struct drm_property *property, uint64_t val, void *blob_data);
 
 struct drm_encoder *omap_encoder_init(struct drm_device *dev,
 		struct omap_dss_device *dssdev);
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index 046d5e6..fe32f1b 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -327,8 +327,8 @@ void omap_plane_install_properties(struct drm_plane *plane,
 	drm_object_attach_property(obj, prop, 0);
 }
 
-int omap_plane_set_property(struct drm_plane *plane,
-		struct drm_property *property, uint64_t val)
+int omap_plane_set_property(struct drm_plane *plane, void *state,
+		struct drm_property *property, uint64_t val, void *blob_data)
 {
 	struct omap_plane *omap_plane = to_omap_plane(plane);
 	struct omap_drm_private *priv = plane->dev->dev_private;
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 835caba..9f12205 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -799,8 +799,10 @@ static enum drm_connector_status qxl_conn_detect(
 }
 
 static int qxl_conn_set_property(struct drm_connector *connector,
+				   void *state,
 				   struct drm_property *property,
-				   uint64_t value)
+				   uint64_t value,
+				   void *blob_data)
 {
 	DRM_DEBUG("\n");
 	return 0;
diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c
index 514118a..65a93ed 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.c
+++ b/drivers/gpu/drm/qxl/qxl_drv.c
@@ -34,6 +34,7 @@
 #include "drmP.h"
 #include "drm/drm.h"
 #include "drm_crtc_helper.h"
+#include "drm_atomic_helper.h"
 #include "qxl_drv.h"
 #include "qxl_object.h"
 
@@ -221,6 +222,14 @@ static struct drm_driver qxl_driver = {
 	.dumb_create = qxl_mode_dumb_create,
 	.dumb_map_offset = qxl_mode_dumb_mmap,
 	.dumb_destroy = drm_gem_dumb_destroy,
+
+	.atomic_begin     = drm_atomic_helper_begin,
+	.atomic_set_event = drm_atomic_helper_set_event,
+	.atomic_check     = drm_atomic_helper_check,
+	.atomic_commit    = drm_atomic_helper_commit,
+	.atomic_end       = drm_atomic_helper_end,
+	.atomic_helpers   = &drm_atomic_helper_funcs,
+
 #if defined(CONFIG_DEBUG_FS)
 	.debugfs_init = qxl_debugfs_init,
 	.debugfs_cleanup = qxl_debugfs_takedown,
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 79159b5..1c64ce3 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -366,8 +366,9 @@ static void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_conn
 	}
 }
 
-static int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property,
-				  uint64_t val)
+static int radeon_connector_set_property(struct drm_connector *connector,
+		void *state, struct drm_property *property,
+		uint64_t val, void *blob_data)
 {
 	struct drm_device *dev = connector->dev;
 	struct radeon_device *rdev = dev->dev_private;
@@ -667,8 +668,10 @@ static void radeon_connector_destroy(struct drm_connector *connector)
 }
 
 static int radeon_lvds_set_property(struct drm_connector *connector,
+				    void *state,
 				    struct drm_property *property,
-				    uint64_t value)
+				    uint64_t value,
+				    void *blob_data)
 {
 	struct drm_device *dev = connector->dev;
 	struct radeon_encoder *radeon_encoder;
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index cdd12dc..e8a3dda 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -34,6 +34,7 @@
 #include "radeon_drv.h"
 
 #include <drm/drm_pciids.h>
+#include <drm/drm_atomic_helper.h>
 #include <linux/console.h>
 #include <linux/module.h>
 
@@ -415,6 +416,14 @@ static struct drm_driver kms_driver = {
 	.dumb_create = radeon_mode_dumb_create,
 	.dumb_map_offset = radeon_mode_dumb_mmap,
 	.dumb_destroy = drm_gem_dumb_destroy,
+
+	.atomic_begin     = drm_atomic_helper_begin,
+	.atomic_set_event = drm_atomic_helper_set_event,
+	.atomic_check     = drm_atomic_helper_check,
+	.atomic_commit    = drm_atomic_helper_commit,
+	.atomic_end       = drm_atomic_helper_end,
+	.atomic_helpers   = &drm_atomic_helper_funcs,
+
 	.fops = &radeon_driver_kms_fops,
 
 	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 0023f97..100ab8b 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -21,6 +21,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -175,6 +176,12 @@ static struct drm_driver rcar_du_driver = {
 	.dumb_create		= rcar_du_dumb_create,
 	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
 	.dumb_destroy		= drm_gem_dumb_destroy,
+	.atomic_begin     = drm_atomic_helper_begin,
+	.atomic_set_event = drm_atomic_helper_set_event,
+	.atomic_check     = drm_atomic_helper_check,
+	.atomic_commit    = drm_atomic_helper_commit,
+	.atomic_end       = drm_atomic_helper_end,
+	.atomic_helpers   = &drm_atomic_helper_funcs,
 	.fops			= &rcar_du_fops,
 	.name			= "rcar-du",
 	.desc			= "Renesas R-Car Display Unit",
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
index 5300064..5691743 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -396,8 +396,10 @@ done:
 }
 
 static int rcar_du_plane_set_property(struct drm_plane *plane,
+				      void *state,
 				      struct drm_property *property,
-				      uint64_t value)
+				      uint64_t value,
+				      void *blob_data)
 {
 	struct rcar_du_plane *rplane = to_rcar_plane(plane);
 	struct rcar_du_group *rgrp = rplane->group;
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c
index 0155518..ab761ff 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c
@@ -21,6 +21,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
 #include "shmob_drm_crtc.h"
@@ -285,6 +286,12 @@ static struct drm_driver shmob_drm_driver = {
 	.dumb_create		= drm_gem_cma_dumb_create,
 	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
 	.dumb_destroy		= drm_gem_dumb_destroy,
+	.atomic_begin     = drm_atomic_helper_begin,
+	.atomic_set_event = drm_atomic_helper_set_event,
+	.atomic_check     = drm_atomic_helper_check,
+	.atomic_commit    = drm_atomic_helper_commit,
+	.atomic_end       = drm_atomic_helper_end,
+	.atomic_helpers   = &drm_atomic_helper_funcs,
 	.fops			= &shmob_drm_fops,
 	.name			= "shmob-drm",
 	.desc			= "Renesas SH Mobile DRM",
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 116da19..305b961 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -519,6 +519,12 @@ static struct drm_driver tilcdc_driver = {
 	.dumb_create        = drm_gem_cma_dumb_create,
 	.dumb_map_offset    = drm_gem_cma_dumb_map_offset,
 	.dumb_destroy       = drm_gem_dumb_destroy,
+	.atomic_begin       = drm_atomic_helper_begin,
+	.atomic_set_event   = drm_atomic_helper_set_event,
+	.atomic_check       = drm_atomic_helper_check,
+	.atomic_commit      = drm_atomic_helper_commit,
+	.atomic_end         = drm_atomic_helper_end,
+	.atomic_helpers     = &drm_atomic_helper_funcs,
 #ifdef CONFIG_DEBUG_FS
 	.debugfs_init       = tilcdc_debugfs_init,
 	.debugfs_cleanup    = tilcdc_debugfs_cleanup,
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index 0938036..2f0c093 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -31,6 +31,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_slave.c b/drivers/gpu/drm/tilcdc/tilcdc_slave.c
index 595068b..48bcc26 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_slave.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_slave.c
@@ -206,7 +206,8 @@ static struct drm_encoder *slave_connector_best_encoder(
 }
 
 static int slave_connector_set_property(struct drm_connector *connector,
-		struct drm_property *property, uint64_t value)
+		void *state, struct drm_property *property,
+		uint64_t value, void *blob_data)
 {
 	struct drm_encoder *encoder = to_slave_connector(connector)->encoder;
 	return get_slave_funcs(encoder)->set_property(encoder,
diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c
index b44d548..cd0c01a 100644
--- a/drivers/gpu/drm/udl/udl_connector.c
+++ b/drivers/gpu/drm/udl/udl_connector.c
@@ -115,9 +115,9 @@ udl_best_single_encoder(struct drm_connector *connector)
 	return encoder;
 }
 
-static int udl_connector_set_property(struct drm_connector *connector,
-				      struct drm_property *property,
-				      uint64_t val)
+static int udl_connector_set_property(struct drm_connector *connector, 
+			       void *state, struct drm_property *property,
+			       uint64_t val, void *blob_data)
 {
 	return 0;
 }
diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c
index 7650dc0..60e4672 100644
--- a/drivers/gpu/drm/udl/udl_drv.c
+++ b/drivers/gpu/drm/udl/udl_drv.c
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <drm/drm_usb.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include "udl_drv.h"
 
 static struct drm_driver driver;
@@ -89,6 +90,13 @@ static struct drm_driver driver = {
 	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
 	.gem_prime_import = udl_gem_prime_import,
 
+	.atomic_begin     = drm_atomic_helper_begin,
+	.atomic_set_event = drm_atomic_helper_set_event,
+	.atomic_check     = drm_atomic_helper_check,
+	.atomic_commit    = drm_atomic_helper_commit,
+	.atomic_end       = drm_atomic_helper_end,
+	.atomic_helpers   = &drm_atomic_helper_funcs,
+
 	.name = DRIVER_NAME,
 	.desc = DRIVER_DESC,
 	.date = DRIVER_DATE,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 1a90f0a..54e060c 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -1138,6 +1138,13 @@ static struct drm_driver driver = {
 	.dumb_map_offset = vmw_dumb_map_offset,
 	.dumb_destroy = vmw_dumb_destroy,
 
+	.atomic_begin     = drm_atomic_helper_begin,
+	.atomic_set_event = drm_atomic_helper_set_event,
+	.atomic_check     = drm_atomic_helper_check,
+	.atomic_commit    = drm_atomic_helper_commit,
+	.atomic_end       = drm_atomic_helper_end,
+	.atomic_helpers   = &drm_atomic_helper_funcs,
+
 	.fops = &vmwgfx_driver_fops,
 	.name = VMWGFX_DRIVER_NAME,
 	.desc = VMWGFX_DRIVER_DESC,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 150ec64..d930465 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -30,6 +30,7 @@
 
 #include "vmwgfx_reg.h"
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/vmwgfx_drm.h>
 #include <drm/drm_hashtab.h>
 #include <linux/suspend.h>
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index fc43c06..a0f5dfb 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -1994,8 +1994,10 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector,
 }
 
 int vmw_du_connector_set_property(struct drm_connector *connector,
+				  void *state,
 				  struct drm_property *property,
-				  uint64_t val)
+				  uint64_t val,
+				  void *blob_data)
 {
 	return 0;
 }
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index 8d038c3..e259d6c 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -141,8 +141,10 @@ vmw_du_connector_detect(struct drm_connector *connector, bool force);
 int vmw_du_connector_fill_modes(struct drm_connector *connector,
 				uint32_t max_width, uint32_t max_height);
 int vmw_du_connector_set_property(struct drm_connector *connector,
+				  void *state,
 				  struct drm_property *property,
-				  uint64_t val);
+				  uint64_t val,
+				  void *blob_data);
 
 
 /*
diff --git a/drivers/gpu/host1x/drm/drm.c b/drivers/gpu/host1x/drm/drm.c
index 8c61cee..f1c764c 100644
--- a/drivers/gpu/host1x/drm/drm.c
+++ b/drivers/gpu/host1x/drm/drm.c
@@ -634,6 +634,13 @@ struct drm_driver tegra_drm_driver = {
 	.dumb_map_offset = tegra_bo_dumb_map_offset,
 	.dumb_destroy = drm_gem_dumb_destroy,
 
+	.atomic_begin     = drm_atomic_helper_begin,
+	.atomic_set_event = drm_atomic_helper_set_event,
+	.atomic_check     = drm_atomic_helper_check,
+	.atomic_commit    = drm_atomic_helper_commit,
+	.atomic_end       = drm_atomic_helper_end,
+	.atomic_helpers   = &drm_atomic_helper_funcs,
+
 	.ioctls = tegra_drm_ioctls,
 	.num_ioctls = ARRAY_SIZE(tegra_drm_ioctls),
 	.fops = &tegra_drm_fops,
diff --git a/drivers/gpu/host1x/drm/drm.h b/drivers/gpu/host1x/drm/drm.h
index 02ce020..ee5765c 100644
--- a/drivers/gpu/host1x/drm/drm.h
+++ b/drivers/gpu/host1x/drm/drm.h
@@ -12,6 +12,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_fixed.h>
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index a2e52a0..e3eeb34 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -19,6 +19,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <linux/fb.h>
 #include <linux/module.h>
 #include <drm/drm_gem_cma_helper.h>
@@ -784,6 +785,13 @@ static struct drm_driver imx_drm_driver = {
 	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
 	.dumb_destroy		= drm_gem_dumb_destroy,
 
+	.atomic_begin     = drm_atomic_helper_begin,
+	.atomic_set_event = drm_atomic_helper_set_event,
+	.atomic_check     = drm_atomic_helper_check,
+	.atomic_commit    = drm_atomic_helper_commit,
+	.atomic_end       = drm_atomic_helper_end,
+	.atomic_helpers   = &drm_atomic_helper_funcs,
+
 	.get_vblank_counter	= drm_vblank_count,
 	.enable_vblank		= imx_drm_enable_vblank,
 	.disable_vblank		= imx_drm_disable_vblank,
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index b46fb45..4c3de22 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -966,6 +966,83 @@ struct drm_driver {
 			    struct drm_device *dev,
 			    uint32_t handle);
 
+	/*
+	 * Atomic functions:
+	 */
+
+	/**
+	 * atomic_begin - start a sequence of atomic updates
+	 * @dev: DRM device
+	 * @flags: the modifier flags that userspace has requested
+	 *
+	 * Begin a sequence of atomic property sets.  Returns a driver
+	 * private state object that is passed back into the various
+	 * object's set_property() fxns, and into the remainder of the
+	 * atomic funcs.  The state object should accumulate the changes
+	 * from one o more set_property()'s.  At the end, the state can
+	 * be checked, and optionally committed.
+	 *
+	 * RETURNS
+	 *   a driver private state object, which is passed back in to
+	 *   the various other atomic fxns, or error (such as -EBUSY if
+	 *   there is still a pending async update)
+	 */
+	void *(*atomic_begin)(struct drm_device *dev, uint32_t flags);
+
+	/**
+	 * atomic_set_event - set a pending event on mode object
+	 * @dev: DRM device
+	 * @state: the driver private state object
+	 * @obj: the object to set the event on
+	 * @event: the event to send back
+	 *
+	 * Set pending event for an update on the specified object.  The
+	 * event is to be sent back to userspace after the update completes.
+	 */
+	int (*atomic_set_event)(struct drm_device *dev,
+			void *state, struct drm_mode_object *obj,
+			struct drm_pending_vblank_event *event);
+
+	/**
+	 * atomic_check - validate state object
+	 * @dev: DRM device
+	 * @state: the driver private state object
+	 *
+	 * Check the state object to see if the requested state is
+	 * physically possible.
+	 *
+	 * RETURNS
+	 * Zero for success or -errno
+	 */
+	int (*atomic_check)(struct drm_device *dev, void *state);
+
+	/**
+	 * atomic_commit - commit state
+	 * @dev: DRM device
+	 * @state: the driver private state object
+	 *
+	 * Commit the state.  This will only be called if atomic_check()
+	 * succeeds.
+	 *
+	 * RETURNS
+	 * Zero for success or -errno
+	 */
+	int (*atomic_commit)(struct drm_device *dev, void *state);
+
+	/**
+	 * atomic_end - conclude the atomic update
+	 * @dev: DRM device
+	 * @state: the driver private state object
+
+	 * Release resources associated with the state object.
+	 */
+	void (*atomic_end)(struct drm_device *dev, void *state);
+
+	/**
+	 * Helpers used by drm-atomic-helpers
+	 */
+	const void *atomic_helpers;
+
 	/* Driver private ops for this object */
 	const struct vm_operations_struct *gem_vm_ops;
 
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
new file mode 100644
index 0000000..d6cba05
--- /dev/null
+++ b/include/drm/drm_atomic_helper.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRM_ATOMIC_HELPER_H_
+#define DRM_ATOMIC_HELPER_H_
+
+/**
+ * DOC: atomic state helpers
+ *
+ * Base helper atomic state and functions.  Drivers are free to either
+ * use these as-is, extend them, or completely replace them, in order
+ * to implement the atomic KMS API.
+ *
+ * A naive driver, with no special constraints or hw support for atomic
+ * updates may simply add the following to their driver struct:
+ *
+ *     .atomic_begin     = drm_atomic_helper_begin,
+ *     .atomic_set_event = drm_atomic_helper_set_event,
+ *     .atomic_check     = drm_atomic_helper_check,
+ *     .atomic_commit    = drm_atomic_helper_commit,
+ *     .atomic_end       = drm_atomic_helper_end,
+ *     .atomic_helpers   = &drm_atomic_helper_funcs,
+ *
+ * In addition, if you're plane/crtc doesn't already have it's own custom
+ * properties, then add to your plane/crtc_funcs:
+ *
+ *     .set_property     = drm_atomic_helper_{plane,crtc}_set_property,
+ *
+ * Unlike the crtc helpers, it is intended that the atomic helpers can be
+ * used piecemeal by the drivers, either using all or overriding parts as
+ * needed.
+ *
+ * A driver which can have (for example) conflicting modes across multiple
+ * crtcs (for example, bandwidth limitations or clock/pll configuration
+ * restrictions), can simply wrap drm_atomic_helper_check() with their own
+ * driver specific .atomic_check() function.
+ *
+ * A driver which can support true atomic updates can wrap
+ * drm_atomic_helper_commit().
+ *
+ * A driver with custom properties should override the appropriate get_state(),
+ * check_state(), and commit_state() functions in .atomic_helpers if it uses
+ * the drm-atomic-helpers.  Otherwise it is free to use &drm_atomic_helper_funcs
+ * as-is.
+ *
+ * NOTE: currently all drivers using the atomic helpers must use
+ * drm_atomic_helper_begin.  But if there is a good use-case for a driver
+ * overriding .atomic_begin we can loosen this restriction by making
+ * 'struct drm_atomic_helper_state' public and only requiring that the
+ * driver wrap/subclass drm_atomic_helper_state.
+ */
+
+/**
+ * struct drm_atomic_helper_funcs - helper funcs used by the atomic helpers
+ */
+struct drm_atomic_helper_funcs {
+	int dummy; /* for now */
+};
+
+const extern struct drm_atomic_helper_funcs drm_atomic_helper_funcs;
+
+void *drm_atomic_helper_begin(struct drm_device *dev, uint32_t flags);
+int drm_atomic_helper_set_event(struct drm_device *dev,
+		void *state, struct drm_mode_object *obj,
+		struct drm_pending_vblank_event *event);
+int drm_atomic_helper_check(struct drm_device *dev, void *state);
+int drm_atomic_helper_commit(struct drm_device *dev, void *state);
+void drm_atomic_helper_end(struct drm_device *dev, void *state);
+
+#endif /* DRM_ATOMIC_HELPER_H_ */
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 24f4995..ad4e1ce 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -368,8 +368,9 @@ struct drm_crtc_funcs {
 			 struct drm_pending_vblank_event *event,
 			 uint32_t flags);
 
-	int (*set_property)(struct drm_crtc *crtc,
-			    struct drm_property *property, uint64_t val);
+	int (*set_property)(struct drm_crtc *crtc, void *state,
+			    struct drm_property *property, uint64_t val,
+			    void *blob_data);
 };
 
 /**
@@ -479,8 +480,8 @@ struct drm_connector_funcs {
 	enum drm_connector_status (*detect)(struct drm_connector *connector,
 					    bool force);
 	int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
-	int (*set_property)(struct drm_connector *connector, struct drm_property *property,
-			     uint64_t val);
+	int (*set_property)(struct drm_connector *connector, void *state,
+			struct drm_property *property, uint64_t val, void *blob_data);
 	void (*destroy)(struct drm_connector *connector);
 	void (*force)(struct drm_connector *connector);
 };
@@ -650,8 +651,9 @@ struct drm_plane_funcs {
 	int (*disable_plane)(struct drm_plane *plane);
 	void (*destroy)(struct drm_plane *plane);
 
-	int (*set_property)(struct drm_plane *plane,
-			    struct drm_property *property, uint64_t val);
+	int (*set_property)(struct drm_plane *plane, void *state,
+			    struct drm_property *property, uint64_t val,
+			    void *blob_data);
 };
 
 /**
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFCv1 02/12] drm: add object property type
  2013-10-06  0:45 [RFCv1 00/12] Atomic/nuclear modeset/pageflip Rob Clark
  2013-10-06  0:45 ` [RFCv1 01/12] drm: add atomic fxns Rob Clark
@ 2013-10-06  0:45 ` Rob Clark
  2013-10-07 13:43   ` Ville Syrjälä
  2013-10-06  0:45 ` [RFCv1 03/12] drm: add DRM_MODE_PROP_DYNAMIC property flag Rob Clark
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 38+ messages in thread
From: Rob Clark @ 2013-10-06  0:45 UTC (permalink / raw)
  To: dri-devel

An object property is an id (idr) for a drm mode object.  This
will allow a property to be used set/get a framebuffer, CRTC, etc.
---
 drivers/gpu/drm/drm_crtc.c  | 34 ++++++++++++++++++++++++++++++----
 include/drm/drm_crtc.h      | 10 ++++++++++
 include/uapi/drm/drm_mode.h |  1 +
 3 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index f2a6d72..471cf16 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2776,6 +2776,8 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags,
 	if (!property)
 		return NULL;
 
+	property->dev = dev;
+
 	if (num_values) {
 		property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL);
 		if (!property->values)
@@ -2879,6 +2881,23 @@ struct drm_property *drm_property_create_range(struct drm_device *dev, int flags
 }
 EXPORT_SYMBOL(drm_property_create_range);
 
+struct drm_property *drm_property_create_object(struct drm_device *dev,
+					 int flags, const char *name, uint32_t type)
+{
+	struct drm_property *property;
+
+	flags |= DRM_MODE_PROP_OBJECT;
+
+	property = drm_property_create(dev, flags, name, 1);
+	if (!property)
+		return NULL;
+
+	property->values[0] = type;
+
+	return property;
+}
+EXPORT_SYMBOL(drm_property_create_object);
+
 int drm_property_add_enum(struct drm_property *property, int index,
 			  uint64_t value, const char *name)
 {
@@ -3207,6 +3226,11 @@ static bool drm_property_change_is_valid(struct drm_property *property,
 	} else if (property->flags & DRM_MODE_PROP_BLOB) {
 		/* Only the driver knows */
 		return true;
+	} else if (property->flags & DRM_MODE_PROP_OBJECT) {
+		/* a zero value for an object property translates to null: */
+		if (value == 0)
+			return true;
+		return drm_property_get_obj(property, value) != NULL;
 	} else {
 		int i;
 		for (i = 0; i < property->num_values; i++)
@@ -3283,9 +3307,9 @@ static int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
 	return ret;
 }
 
-static int drm_mode_set_obj_prop(struct drm_device *dev,
-		struct drm_mode_object *obj, void *state,
-		struct drm_property *property, uint64_t value, void *blob_data)
+static int drm_mode_set_obj_prop(struct drm_mode_object *obj,
+		void *state, struct drm_property *property, 
+		uint64_t value, void *blob_data)
 {
 	if (drm_property_change_is_valid(property, value)) {
 		switch (obj->type) {
@@ -3299,6 +3323,8 @@ static int drm_mode_set_obj_prop(struct drm_device *dev,
 			return drm_mode_plane_set_obj_prop(obj_to_plane(obj),
 					state, property, value, blob_data);
 		}
+	} else {
+		DRM_DEBUG("invalid value: %s = %llx\n", property->name, value);
 	}
 
 	return -EINVAL;
@@ -3333,7 +3359,7 @@ static int drm_mode_set_obj_prop_id(struct drm_device *dev, void *state,
 		return -EINVAL;
 	property = obj_to_property(prop_obj);
 
-	return drm_mode_set_obj_prop(dev, arg_obj, state, property,
+	return drm_mode_set_obj_prop(arg_obj, state, property, 
 			value, blob_data);
 }
 
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index ad4e1ce..77c8f11 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -297,6 +297,7 @@ struct drm_property {
 	char name[DRM_PROP_NAME_LEN];
 	uint32_t num_values;
 	uint64_t *values;
+	struct drm_device *dev;
 
 	struct list_head enum_blob_list;
 };
@@ -1030,6 +1031,8 @@ struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
 struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
 					 const char *name,
 					 uint64_t min, uint64_t max);
+struct drm_property *drm_property_create_object(struct drm_device *dev,
+					 int flags, const char *name, uint32_t type);
 extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property);
 extern int drm_property_add_enum(struct drm_property *property, int index,
 				 uint64_t value, const char *name);
@@ -1048,6 +1051,13 @@ extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
 					 int gamma_size);
 extern struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
 		uint32_t id, uint32_t type);
+
+static inline struct drm_mode_object *
+drm_property_get_obj(struct drm_property *property, uint64_t value)
+{
+	return drm_mode_object_find(property->dev, value, property->values[0]);
+}
+
 /* IOCTLs */
 extern int drm_mode_getresources(struct drm_device *dev,
 				 void *data, struct drm_file *file_priv);
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index 5508117..35921ba 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -231,6 +231,7 @@ struct drm_mode_get_connector {
 #define DRM_MODE_PROP_ENUM	(1<<3) /* enumerated type with text strings */
 #define DRM_MODE_PROP_BLOB	(1<<4)
 #define DRM_MODE_PROP_BITMASK	(1<<5) /* bitmask of enumerated types */
+#define DRM_MODE_PROP_OBJECT	(1<<6) /* drm mode object */
 
 struct drm_mode_property_enum {
 	__u64 value;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFCv1 03/12] drm: add DRM_MODE_PROP_DYNAMIC property flag
  2013-10-06  0:45 [RFCv1 00/12] Atomic/nuclear modeset/pageflip Rob Clark
  2013-10-06  0:45 ` [RFCv1 01/12] drm: add atomic fxns Rob Clark
  2013-10-06  0:45 ` [RFCv1 02/12] drm: add object property type Rob Clark
@ 2013-10-06  0:45 ` Rob Clark
  2013-10-07 13:46   ` Ville Syrjälä
  2013-10-06  0:45 ` [RFCv1 04/12] drm: add DRM_MODE_PROP_SIGNED " Rob Clark
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 38+ messages in thread
From: Rob Clark @ 2013-10-06  0:45 UTC (permalink / raw)
  To: dri-devel

This indicates to userspace that the property is something that can
be set dynamically without requiring a "test" step to check if the
hw is capable.  This allows a userspace compositor, such as weston,
to avoid an extra ioctl to check whether it needs to fall-back to
GPU to composite some surface prior to submission of GPU render
commands.
---
 include/uapi/drm/drm_mode.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index 35921ba..15db837 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -232,6 +232,15 @@ struct drm_mode_get_connector {
 #define DRM_MODE_PROP_BLOB	(1<<4)
 #define DRM_MODE_PROP_BITMASK	(1<<5) /* bitmask of enumerated types */
 #define DRM_MODE_PROP_OBJECT	(1<<6) /* drm mode object */
+/* Properties that are not dynamic cannot safely be changed without a
+ * atomic-modeset / atomic-pageflip test step.  But if userspace is
+ * only changing dynamic properties, it is guaranteed that the change
+ * will not exceed hw limits, so no test step is required.
+ *
+ * Note that fb_id properties are a bit ambiguous.. they of course can
+ * be changed dynamically, assuming the pixel format does not change.
+ */
+#define DRM_MODE_PROP_DYNAMIC	(1<<24)
 
 struct drm_mode_property_enum {
 	__u64 value;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFCv1 04/12] drm: add DRM_MODE_PROP_SIGNED property flag
  2013-10-06  0:45 [RFCv1 00/12] Atomic/nuclear modeset/pageflip Rob Clark
                   ` (2 preceding siblings ...)
  2013-10-06  0:45 ` [RFCv1 03/12] drm: add DRM_MODE_PROP_DYNAMIC property flag Rob Clark
@ 2013-10-06  0:45 ` Rob Clark
  2013-10-07 14:46   ` Matt Plumtree
  2013-10-06  0:45 ` [RFCv1 05/12] drm: helpers to find mode objects (BEFORE drm: split property values out) Rob Clark
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 38+ messages in thread
From: Rob Clark @ 2013-10-06  0:45 UTC (permalink / raw)
  To: dri-devel

Flag for range property types indicating that the value is a signed
integer rather than unsigned.  For range properties, the signed flag
will trigger use of signed integer comparisions, to handle negative
values properly.
---
 drivers/gpu/drm/drm_crtc.c  | 10 ++++++++--
 include/drm/drm_crtc.h      |  9 +++++++++
 include/uapi/drm/drm_mode.h |  2 ++
 3 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 471cf16..46bae42 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -3211,9 +3211,15 @@ EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
 static bool drm_property_change_is_valid(struct drm_property *property,
 					 uint64_t value)
 {
-	if (property->flags & DRM_MODE_PROP_IMMUTABLE)
+	if (property->flags & DRM_MODE_PROP_IMMUTABLE) {
 		return false;
-	if (property->flags & DRM_MODE_PROP_RANGE) {
+	} else if (property->flags & (DRM_MODE_PROP_RANGE|DRM_MODE_PROP_SIGNED)) {
+		int64_t svalue = U642I64(value);
+		if (svalue < U642I64(property->values[0]) ||
+				svalue > U642I64(property->values[1]))
+			return false;
+		return true;
+	} else if (property->flags & DRM_MODE_PROP_RANGE) {
 		if (value < property->values[0] || value > property->values[1])
 			return false;
 		return true;
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 77c8f11..e042d12 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -64,6 +64,15 @@ struct drm_object_properties {
 	uint64_t values[DRM_OBJECT_MAX_PROPERTY];
 };
 
+static inline int64_t U642I64(uint64_t val)
+{
+	return (int64_t)*((int64_t *)&val);
+}
+static inline uint64_t I642U64(int64_t val)
+{
+	return (uint64_t)*((uint64_t *)&val);
+}
+
 /*
  * Note on terminology:  here, for brevity and convenience, we refer to connector
  * control chips as 'CRTCs'.  They can control any type of connector, VGA, LVDS,
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index 15db837..6d4f089 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -241,6 +241,8 @@ struct drm_mode_get_connector {
  * be changed dynamically, assuming the pixel format does not change.
  */
 #define DRM_MODE_PROP_DYNAMIC	(1<<24)
+/* Indicates that numeric property values are signed rather than unsigned: */
+#define DRM_MODE_PROP_SIGNED   (1<<25)
 
 struct drm_mode_property_enum {
 	__u64 value;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFCv1 05/12] drm: helpers to find mode objects (BEFORE drm: split property values out)
  2013-10-06  0:45 [RFCv1 00/12] Atomic/nuclear modeset/pageflip Rob Clark
                   ` (3 preceding siblings ...)
  2013-10-06  0:45 ` [RFCv1 04/12] drm: add DRM_MODE_PROP_SIGNED " Rob Clark
@ 2013-10-06  0:45 ` Rob Clark
  2013-10-06  0:48   ` Rob Clark
  2013-10-06  0:45 ` [RFCv1 06/12] drm: split propvals out and blob property support Rob Clark
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 38+ messages in thread
From: Rob Clark @ 2013-10-06  0:45 UTC (permalink / raw)
  To: dri-devel

---
 include/drm/drm_crtc.h | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index e042d12..0ea61b3 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -1067,6 +1067,46 @@ drm_property_get_obj(struct drm_property *property, uint64_t value)
 	return drm_mode_object_find(property->dev, value, property->values[0]);
 }
 
+static inline struct drm_plane *drm_plane_find(struct drm_device *dev,
+		uint32_t id)
+{
+	struct drm_mode_object *mo;
+	mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PLANE);
+	return mo ? obj_to_plane(mo) : NULL;
+}
+
+static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev,
+		uint32_t id)
+{
+	struct drm_mode_object *mo;
+	mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_CRTC);
+	return mo ? obj_to_crtc(mo) : NULL;
+}
+
+static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev,
+		uint32_t id)
+{
+	struct drm_mode_object *mo;
+	mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER);
+	return mo ? obj_to_encoder(mo) : NULL;
+}
+
+static inline struct drm_connector *drm_connector_find(struct drm_device *dev,
+		uint32_t id)
+{
+	struct drm_mode_object *mo;
+	mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_CONNECTOR);
+	return mo ? obj_to_connector(mo) : NULL;
+}
+
+static inline struct drm_property_blob *
+drm_property_blob_find(struct drm_device *dev, uint32_t id)
+{
+	struct drm_mode_object *mo;
+	mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_BLOB);
+	return mo ? obj_to_blob(mo) : NULL;
+}
+
 /* IOCTLs */
 extern int drm_mode_getresources(struct drm_device *dev,
 				 void *data, struct drm_file *file_priv);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFCv1 06/12] drm: split propvals out and blob property support
  2013-10-06  0:45 [RFCv1 00/12] Atomic/nuclear modeset/pageflip Rob Clark
                   ` (4 preceding siblings ...)
  2013-10-06  0:45 ` [RFCv1 05/12] drm: helpers to find mode objects (BEFORE drm: split property values out) Rob Clark
@ 2013-10-06  0:45 ` Rob Clark
  2013-10-06  0:45 ` [RFCv1 07/12] drm: Allow drm_mode_object_find() to look up an object of any type Rob Clark
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 38+ messages in thread
From: Rob Clark @ 2013-10-06  0:45 UTC (permalink / raw)
  To: dri-devel

Split property values out into a different struct, so we can later
move property values into state structs.  This will allow the
property values to stay in sync w/ the state updates which are
either discarded or atomically committed.

And since we are touching all the same code, add support for mutable
blob properties, which will also be needed for atomic modeset.
---
 drivers/gpu/drm/drm_crtc.c                  | 79 +++++++++++++++++++++--------
 drivers/gpu/drm/drm_fb_helper.c             |  3 +-
 drivers/gpu/drm/gma500/cdv_intel_dp.c       |  3 +-
 drivers/gpu/drm/gma500/cdv_intel_hdmi.c     |  3 +-
 drivers/gpu/drm/gma500/cdv_intel_lvds.c     |  6 ++-
 drivers/gpu/drm/gma500/mdfld_dsi_output.c   |  8 +--
 drivers/gpu/drm/gma500/psb_intel_lvds.c     |  6 ++-
 drivers/gpu/drm/gma500/psb_intel_sdvo.c     | 19 +++++--
 drivers/gpu/drm/i2c/ch7006_drv.c            |  4 +-
 drivers/gpu/drm/i915/intel_display.c        |  3 +-
 drivers/gpu/drm/i915/intel_dp.c             |  3 +-
 drivers/gpu/drm/i915/intel_hdmi.c           |  3 +-
 drivers/gpu/drm/i915/intel_sdvo.c           | 19 +++++--
 drivers/gpu/drm/i915/intel_tv.c             |  6 ++-
 drivers/gpu/drm/nouveau/dispnv04/tvnv17.c   |  3 +-
 drivers/gpu/drm/nouveau/nouveau_connector.c |  4 +-
 drivers/gpu/drm/omapdrm/omap_drv.c          |  6 ++-
 drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c   |  3 +-
 drivers/gpu/drm/rcar-du/rcar_du_vgacon.c    |  3 +-
 drivers/gpu/drm/shmobile/shmob_drm_crtc.c   |  4 +-
 include/drm/drm_crtc.h                      | 11 +++-
 21 files changed, 142 insertions(+), 57 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 46bae42..0b6e196 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -90,6 +90,14 @@ void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
 
+static int drm_mode_set_obj_prop(struct drm_mode_object *obj,
+		void *state, struct drm_property *property,
+		uint64_t value, void *blob_data);
+static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev,
+		int length, void *data);
+static void drm_property_destroy_blob(struct drm_device *dev,
+		struct drm_property_blob *blob);
+
 /* Avoid boilerplate.  I'm tired of typing. */
 #define DRM_ENUM_NAME_FN(fnname, list)				\
 	const char *fnname(int val)				\
@@ -640,6 +648,7 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 		goto out;
 
 	crtc->base.properties = &crtc->properties;
+	crtc->base.propvals = &crtc->propvals;
 
 	list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
 	dev->mode_config.num_crtc++;
@@ -729,6 +738,7 @@ int drm_connector_init(struct drm_device *dev,
 		goto out;
 
 	connector->base.properties = &connector->properties;
+	connector->base.propvals = &connector->propvals;
 	connector->dev = dev;
 	connector->funcs = funcs;
 	connector->connector_type = connector_type;
@@ -902,6 +912,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 		goto out;
 
 	plane->base.properties = &plane->properties;
+	plane->base.propvals = &plane->propvals;
 	plane->dev = dev;
 	plane->funcs = funcs;
 	plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
@@ -1688,7 +1699,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 				goto out;
 			}
 
-			if (put_user(connector->properties.values[i],
+			if (put_user(connector->propvals.values[i],
 				     prop_values + copied)) {
 				ret = -EFAULT;
 				goto out;
@@ -2969,19 +2980,33 @@ void drm_object_attach_property(struct drm_mode_object *obj,
 	}
 
 	obj->properties->ids[count] = property->base.id;
-	obj->properties->values[count] = init_val;
+	obj->propvals->values[count] = init_val;
 	obj->properties->count++;
 }
 EXPORT_SYMBOL(drm_object_attach_property);
 
 int drm_object_property_set_value(struct drm_mode_object *obj,
-				  struct drm_property *property, uint64_t val)
+				  struct drm_object_property_values *propvals,
+				  struct drm_property *property, uint64_t val,
+				  void *blob_data)
 {
 	int i;
 
 	for (i = 0; i < obj->properties->count; i++) {
 		if (obj->properties->ids[i] == property->base.id) {
-			obj->properties->values[i] = val;
+			struct drm_device *dev = property->dev;
+			if (property->flags & DRM_MODE_PROP_BLOB) {
+				struct drm_property_blob *blob, *old_blob = NULL;
+				old_blob = drm_property_blob_find(dev, propvals->values[i]);
+				blob = drm_property_create_blob(dev, val, blob_data);
+				if (!blob)
+					return -ENOMEM;
+				propvals->values[i] = blob->base.id;
+				if (old_blob)
+					drm_property_destroy_blob(dev, old_blob);
+			} else {
+				propvals->values[i] = val;
+			}
 			return 0;
 		}
 	}
@@ -2997,7 +3022,7 @@ int drm_object_property_get_value(struct drm_mode_object *obj,
 
 	for (i = 0; i < obj->properties->count; i++) {
 		if (obj->properties->ids[i] == property->base.id) {
-			*val = obj->properties->values[i];
+			*val = obj->propvals->values[i];
 			return 0;
 		}
 	}
@@ -3182,27 +3207,35 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
 					    struct edid *edid)
 {
 	struct drm_device *dev = connector->dev;
-	int ret, size;
+	struct drm_mode_object *obj = &connector->base;
+	struct drm_property *edid_prop = dev->mode_config.edid_property;
+	int i, ret, size;
 
-	if (connector->edid_blob_ptr)
-		drm_property_destroy_blob(dev, connector->edid_blob_ptr);
+	/* property_blob will be recreated by drm_object_property_set_value(): */
+	connector->edid_blob_ptr = NULL;
 
 	/* Delete edid, when there is none. */
 	if (!edid) {
-		connector->edid_blob_ptr = NULL;
-		ret = drm_object_property_set_value(&connector->base, dev->mode_config.edid_property, 0);
+		ret = drm_object_property_set_value(obj,
+				&connector->propvals, edid_prop, 0, NULL);
 		return ret;
 	}
 
 	size = EDID_LENGTH * (1 + edid->extensions);
-	connector->edid_blob_ptr = drm_property_create_blob(connector->dev,
-							    size, edid);
-	if (!connector->edid_blob_ptr)
-		return -EINVAL;
 
-	ret = drm_object_property_set_value(&connector->base,
-					       dev->mode_config.edid_property,
-					       connector->edid_blob_ptr->base.id);
+	ret = drm_object_property_set_value(obj,
+			&connector->propvals, edid_prop, size, edid);
+	if (ret)
+		return ret;
+
+	/* find the blob object created for us by drm_object_property_set_value(): */
+	for (i = 0; i < obj->properties->count; i++) {
+		if (obj->properties->ids[i] == edid_prop->base.id) {
+			connector->edid_blob_ptr = drm_property_blob_find(dev,
+					connector->propvals.values[i]);
+			break;
+		}
+	}
 
 	return ret;
 }
@@ -3279,7 +3312,9 @@ static int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
 
 	/* store the property value if successful */
 	if (!ret)
-		drm_object_property_set_value(&connector->base, property, value);
+		drm_object_property_set_value(&connector->base,
+				&connector->propvals, property, value, blob_data);
+
 	return ret;
 }
 
@@ -3293,7 +3328,8 @@ static int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
 		ret = crtc->funcs->set_property(crtc, state, property,
 				value, blob_data);
 	if (!ret)
-		drm_object_property_set_value(&crtc->base, property, value);
+		drm_object_property_set_value(&crtc->base, &crtc->propvals,
+				property, value, NULL);
 
 	return ret;
 }
@@ -3308,7 +3344,8 @@ static int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
 		ret = plane->funcs->set_property(plane, state, property,
 				value, blob_data);
 	if (!ret)
-		drm_object_property_set_value(&plane->base, property, value);
+		drm_object_property_set_value(&plane->base, &plane->propvals,
+				property, value, NULL);
 
 	return ret;
 }
@@ -3411,7 +3448,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
 				ret = -EFAULT;
 				goto out;
 			}
-			if (put_user(obj->properties->values[i],
+			if (put_user(obj->propvals->values[i],
 				     prop_values_ptr + copied)) {
 				ret = -EFAULT;
 				goto out;
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index f6f6cc7..24898dc 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -443,7 +443,8 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
 			connector = fb_helper->connector_info[j]->connector;
 			connector->funcs->dpms(connector, dpms_mode);
 			drm_object_property_set_value(&connector->base,
-				dev->mode_config.dpms_property, dpms_mode);
+				&connector->propvals,
+				dev->mode_config.dpms_property, dpms_mode, NULL);
 		}
 	}
 	drm_modeset_unlock_all(dev);
diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c
index 5f1a734..acd4bfc 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_dp.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c
@@ -1654,7 +1654,8 @@ cdv_intel_dp_set_property(struct drm_connector *connector,
 	struct cdv_intel_dp *intel_dp = encoder->dev_priv;
 	int ret;
 
-	ret = drm_object_property_set_value(&connector->base, property, val);
+	ret = drm_object_property_set_value(&connector->base,
+			&connector->propvals, property, val, blob_data);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
index 74e5de1..188444a 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
@@ -191,7 +191,8 @@ static int cdv_hdmi_set_property(struct drm_connector *connector,
 			return 0;
 
 		if (drm_object_property_set_value(&connector->base,
-							property, value))
+							&connector->propvals,
+							property, value, blob_data))
 			return -1;
 
 		centre = (curValue == DRM_MODE_SCALE_NO_SCALE) ||
diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
index 97d76c1..2dcdd01 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
@@ -486,8 +486,9 @@ static int cdv_intel_lvds_set_property(struct drm_connector *connector,
 			return 0;
 
 		if (drm_object_property_set_value(&connector->base,
+							&connector->propvals,
 							property,
-							value))
+							value, blob_data))
 			return -1;
 
 		if (crtc->saved_mode.hdisplay != 0 &&
@@ -501,8 +502,9 @@ static int cdv_intel_lvds_set_property(struct drm_connector *connector,
 		}
 	} else if (!strcmp(property->name, "backlight") && encoder) {
 		if (drm_object_property_set_value(&connector->base,
+							&connector->propvals,
 							property,
-							value))
+							value, blob_data))
 			return -1;
 		else
                         gma_backlight_set(encoder->dev, value);
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
index 4505286..61f9860 100644
--- a/drivers/gpu/drm/gma500/mdfld_dsi_output.c
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
@@ -275,7 +275,8 @@ static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
 			goto set_prop_done;
 
 		if (drm_object_property_set_value(&connector->base,
-							property, value))
+							&connector->propvals,
+							property, value, blob_data))
 			goto set_prop_error;
 
 		centerechange = (val == DRM_MODE_SCALE_NO_SCALE) ||
@@ -299,8 +300,9 @@ static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
 			}
 		}
 	} else if (!strcmp(property->name, "backlight") && encoder) {
-		if (drm_object_property_set_value(&connector->base, property,
-									value))
+		if (drm_object_property_set_value(&connector->base,
+							&connector->propvals,
+							property, value))
 			goto set_prop_error;
 		else
 			gma_backlight_set(encoder->dev, value);
diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c
index e3a3923..090a6b3 100644
--- a/drivers/gpu/drm/gma500/psb_intel_lvds.c
+++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c
@@ -606,8 +606,9 @@ int psb_intel_lvds_set_property(struct drm_connector *connector,
 			goto set_prop_done;
 
 		if (drm_object_property_set_value(&connector->base,
+							&connector->propvals,
 							property,
-							value))
+							value, blob_data))
 			goto set_prop_error;
 
 		if (crtc->saved_mode.hdisplay != 0 &&
@@ -621,8 +622,9 @@ int psb_intel_lvds_set_property(struct drm_connector *connector,
 		}
 	} else if (!strcmp(property->name, "backlight")) {
 		if (drm_object_property_set_value(&connector->base,
+							&connector->propvals,
 							property,
-							value))
+							value, blob_data))
 			goto set_prop_error;
 		else
                         gma_backlight_set(encoder->dev, value);
diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
index 47e0a2a..22f5c4a 100644
--- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c
+++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
@@ -1700,7 +1700,8 @@ psb_intel_sdvo_set_property(struct drm_connector *connector,
 	uint8_t cmd;
 	int ret;
 
-	ret = drm_object_property_set_value(&connector->base, property, val);
+	ret = drm_object_property_set_value(&connector->base,
+			&connector->propvals, property, val, blob_data);
 	if (ret)
 		return ret;
 
@@ -1756,7 +1757,9 @@ psb_intel_sdvo_set_property(struct drm_connector *connector,
 		temp_value = val;
 		if (psb_intel_sdvo_connector->left == property) {
 			drm_object_property_set_value(&connector->base,
-							 psb_intel_sdvo_connector->right, val);
+							 &connector->propvals,
+							 psb_intel_sdvo_connector->right,
+							 val, blob_data);
 			if (psb_intel_sdvo_connector->left_margin == temp_value)
 				return 0;
 
@@ -1768,7 +1771,9 @@ psb_intel_sdvo_set_property(struct drm_connector *connector,
 			goto set_value;
 		} else if (psb_intel_sdvo_connector->right == property) {
 			drm_object_property_set_value(&connector->base,
-							 psb_intel_sdvo_connector->left, val);
+							 &connector->propvals,
+							 psb_intel_sdvo_connector->left,
+							 val, blob_data);
 			if (psb_intel_sdvo_connector->right_margin == temp_value)
 				return 0;
 
@@ -1780,7 +1785,9 @@ psb_intel_sdvo_set_property(struct drm_connector *connector,
 			goto set_value;
 		} else if (psb_intel_sdvo_connector->top == property) {
 			drm_object_property_set_value(&connector->base,
-							 psb_intel_sdvo_connector->bottom, val);
+							 &connector->propvals,
+							 psb_intel_sdvo_connector->bottom,
+							 val, blob_data);
 			if (psb_intel_sdvo_connector->top_margin == temp_value)
 				return 0;
 
@@ -1792,7 +1799,9 @@ psb_intel_sdvo_set_property(struct drm_connector *connector,
 			goto set_value;
 		} else if (psb_intel_sdvo_connector->bottom == property) {
 			drm_object_property_set_value(&connector->base,
-							 psb_intel_sdvo_connector->top, val);
+							 &connector->propvals,
+							 psb_intel_sdvo_connector->top,
+							 val, blob_data);
 			if (psb_intel_sdvo_connector->bottom_margin == temp_value)
 				return 0;
 
diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c
index 51fa323..a89c205 100644
--- a/drivers/gpu/drm/i2c/ch7006_drv.c
+++ b/drivers/gpu/drm/i2c/ch7006_drv.c
@@ -214,9 +214,9 @@ static enum drm_connector_status ch7006_encoder_detect(struct drm_encoder *encod
 	else
 		priv->subconnector = DRM_MODE_SUBCONNECTOR_Unknown;
 
-	drm_object_property_set_value(&connector->base,
+	drm_object_property_set_value(&connector->base, &connector->propvals,
 			encoder->dev->mode_config.tv_subconnector_property,
-							priv->subconnector);
+			priv->subconnector, NULL);
 
 	return priv->subconnector ? connector_status_connected :
 					connector_status_disconnected;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index e5822e7..d0eff24 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -8481,8 +8481,9 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes)
 
 			connector->dpms = DRM_MODE_DPMS_ON;
 			drm_object_property_set_value(&connector->base,
+							 &connector->propvals,
 							 dpms_property,
-							 DRM_MODE_DPMS_ON);
+							 DRM_MODE_DPMS_ON, NULL);
 
 			intel_encoder = to_intel_encoder(connector->encoder);
 			intel_encoder->connectors_active = true;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 08d29fe..5d9cf68 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -2942,7 +2942,8 @@ intel_dp_set_property(struct drm_connector *connector,
 	struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base);
 	int ret;
 
-	ret = drm_object_property_set_value(&connector->base, property, val);
+	ret = drm_object_property_set_value(&connector->base,
+			&connector->propvals, property, val, blob_data);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index dbc02ab..c477f9c 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -1004,7 +1004,8 @@ intel_hdmi_set_property(struct drm_connector *connector,
 	struct drm_i915_private *dev_priv = connector->dev->dev_private;
 	int ret;
 
-	ret = drm_object_property_set_value(&connector->base, property, val);
+	ret = drm_object_property_set_value(&connector->base,
+			&connector->propvals, property, val, blob_data);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index e863830..32a4382 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -2034,7 +2034,8 @@ intel_sdvo_set_property(struct drm_connector *connector,
 	uint8_t cmd;
 	int ret;
 
-	ret = drm_object_property_set_value(&connector->base, property, val);
+	ret = drm_object_property_set_value(&connector->base,
+			&connector->propvals, property, val, blob_data);
 	if (ret)
 		return ret;
 
@@ -2111,7 +2112,9 @@ intel_sdvo_set_property(struct drm_connector *connector,
 		temp_value = val;
 		if (intel_sdvo_connector->left == property) {
 			drm_object_property_set_value(&connector->base,
-							 intel_sdvo_connector->right, val);
+							 &connector->propvals,
+							 intel_sdvo_connector->right,
+							 val, blob_data);
 			if (intel_sdvo_connector->left_margin == temp_value)
 				return 0;
 
@@ -2123,7 +2126,9 @@ intel_sdvo_set_property(struct drm_connector *connector,
 			goto set_value;
 		} else if (intel_sdvo_connector->right == property) {
 			drm_object_property_set_value(&connector->base,
-							 intel_sdvo_connector->left, val);
+							 &connector->propvals,
+							 intel_sdvo_connector->left,
+							 val, blob_data);
 			if (intel_sdvo_connector->right_margin == temp_value)
 				return 0;
 
@@ -2135,7 +2140,9 @@ intel_sdvo_set_property(struct drm_connector *connector,
 			goto set_value;
 		} else if (intel_sdvo_connector->top == property) {
 			drm_object_property_set_value(&connector->base,
-							 intel_sdvo_connector->bottom, val);
+							 &connector->propvals,
+							 intel_sdvo_connector->bottom,
+							 val, blob_data);
 			if (intel_sdvo_connector->top_margin == temp_value)
 				return 0;
 
@@ -2147,7 +2154,9 @@ intel_sdvo_set_property(struct drm_connector *connector,
 			goto set_value;
 		} else if (intel_sdvo_connector->bottom == property) {
 			drm_object_property_set_value(&connector->base,
-							 intel_sdvo_connector->top, val);
+							 &connector->propvals,
+							 intel_sdvo_connector->top,
+							 val, blob_data);
 			if (intel_sdvo_connector->bottom_margin == temp_value)
 				return 0;
 
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 4ef1949..8bb9d49 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1292,7 +1292,8 @@ static void intel_tv_find_better_format(struct drm_connector *connector)
 
 	intel_tv->tv_format = tv_mode->name;
 	drm_object_property_set_value(&connector->base,
-		connector->dev->mode_config.tv_mode_property, i);
+		&connector->propvals,
+		connector->dev->mode_config.tv_mode_property, i, NULL);
 }
 
 /**
@@ -1450,7 +1451,8 @@ intel_tv_set_property(struct drm_connector *connector, void *state,
 	int ret = 0;
 	bool changed = false;
 
-	ret = drm_object_property_set_value(&connector->base, property, val);
+	ret = drm_object_property_set_value(&connector->base,
+			 &connector->propvals, property, val, blob_data);
 	if (ret < 0)
 		goto out;
 
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
index acef48f..64c60fcb 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
@@ -196,8 +196,9 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector)
 	}
 
 	drm_object_property_set_value(&connector->base,
+					 &connector->propvals,
 					 conf->tv_subconnector_property,
-					 tv_enc->subconnector);
+					 tv_enc->subconnector, NULL);
 
 	if (!reliable) {
 		return connector_status_unknown;
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 89ed23d..f4592be 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -225,10 +225,12 @@ nouveau_connector_set_encoder(struct drm_connector *connector,
 
 	if (nv_connector->type == DCB_CONNECTOR_DVI_I) {
 		drm_object_property_set_value(&connector->base,
+			&connector->propvals,
 			dev->mode_config.dvi_i_subconnector_property,
 			nv_encoder->dcb->type == DCB_OUTPUT_TMDS ?
 			DRM_MODE_SUBCONNECTOR_DVID :
-			DRM_MODE_SUBCONNECTOR_DVIA);
+			DRM_MODE_SUBCONNECTOR_DVIA,
+			NULL);
 	}
 }
 
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 2aaeda8..225d0e9 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -553,12 +553,14 @@ static void dev_lastclose(struct drm_device *dev)
 		 */
 		for (i = 0; i < priv->num_crtcs; i++) {
 			drm_object_property_set_value(&priv->crtcs[i]->base,
-					priv->rotation_prop, 0);
+					&priv->crtcs[i]->propvals,
+					priv->rotation_prop, 0, NULL);
 		}
 
 		for (i = 0; i < priv->num_planes; i++) {
 			drm_object_property_set_value(&priv->planes[i]->base,
-					priv->rotation_prop, 0);
+					&priv->planes[i]->propvals,
+					priv->rotation_prop, 0, NULL);
 		}
 	}
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c
index 4f3ba93..708e044 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c
@@ -118,7 +118,8 @@ int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
 
 	drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
 	drm_object_property_set_value(&connector->base,
-		rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);
+		&connector->propvals,
+		rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF, NULL);
 
 	ret = drm_mode_connector_attach_encoder(connector, &renc->encoder);
 	if (ret < 0)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
index 41d563a..da16774 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
@@ -83,7 +83,8 @@ int rcar_du_vga_connector_init(struct rcar_du_device *rcdu,
 
 	drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
 	drm_object_property_set_value(&connector->base,
-		rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);
+		&connector->propvals,
+		rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF, NULL);
 
 	ret = drm_mode_connector_attach_encoder(connector, &renc->encoder);
 	if (ret < 0)
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
index 54bad98..035bd67 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
@@ -738,8 +738,8 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev,
 	connector->encoder = encoder;
 
 	drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
-	drm_object_property_set_value(&connector->base,
-		sdev->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);
+	drm_object_property_set_value(&connector->base, &connector->propvals,
+		sdev->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF, NULL);
 
 	return 0;
 
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 0ea61b3..372b159 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -40,6 +40,7 @@ struct drm_framebuffer;
 struct drm_object_properties;
 struct drm_file;
 struct drm_clip_rect;
+struct drm_object_property_values;
 
 #define DRM_MODE_OBJECT_CRTC 0xcccccccc
 #define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0
@@ -55,12 +56,16 @@ struct drm_mode_object {
 	uint32_t id;
 	uint32_t type;
 	struct drm_object_properties *properties;
+	struct drm_object_property_values *propvals;
 };
 
 #define DRM_OBJECT_MAX_PROPERTY 24
 struct drm_object_properties {
 	int count;
 	uint32_t ids[DRM_OBJECT_MAX_PROPERTY];
+};
+
+struct drm_object_property_values {
 	uint64_t values[DRM_OBJECT_MAX_PROPERTY];
 };
 
@@ -456,6 +461,7 @@ struct drm_crtc {
 	void *helper_private;
 
 	struct drm_object_properties properties;
+	struct drm_object_property_values propvals;
 };
 
 
@@ -620,6 +626,7 @@ struct drm_connector {
 
 	struct drm_property_blob *edid_blob_ptr;
 	struct drm_object_properties properties;
+	struct drm_object_property_values propvals;
 
 	uint8_t polled; /* DRM_CONNECTOR_POLL_* */
 
@@ -695,6 +702,7 @@ struct drm_plane {
 	const struct drm_plane_funcs *funcs;
 
 	struct drm_object_properties properties;
+	struct drm_object_property_values propvals;
 };
 
 /**
@@ -1008,8 +1016,9 @@ extern void drm_mode_connector_list_update(struct drm_connector *connector);
 extern int drm_mode_connector_update_edid_property(struct drm_connector *connector,
 						struct edid *edid);
 extern int drm_object_property_set_value(struct drm_mode_object *obj,
+					 struct drm_object_property_values *propvals,
 					 struct drm_property *property,
-					 uint64_t val);
+					 uint64_t val, void *blob_data);
 extern int drm_object_property_get_value(struct drm_mode_object *obj,
 					 struct drm_property *property,
 					 uint64_t *value);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFCv1 07/12] drm: Allow drm_mode_object_find() to look up an object of any type
  2013-10-06  0:45 [RFCv1 00/12] Atomic/nuclear modeset/pageflip Rob Clark
                   ` (5 preceding siblings ...)
  2013-10-06  0:45 ` [RFCv1 06/12] drm: split propvals out and blob property support Rob Clark
@ 2013-10-06  0:45 ` Rob Clark
  2013-10-06  0:45 ` [RFCv1 08/12] drm: Refactor object property check code Rob Clark
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 38+ messages in thread
From: Rob Clark @ 2013-10-06  0:45 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

To avoid having to pass object types from userspace for atomic mode
setting ioctl, allow drm_mode_object_find() to look up an object of any
type. This will only work as long as the all object types share the ID
space.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_crtc.c | 3 ++-
 include/drm/drm_crtc.h     | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 0b6e196..c0546e8 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -360,7 +360,8 @@ struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
 
 	mutex_lock(&dev->mode_config.idr_mutex);
 	obj = idr_find(&dev->mode_config.crtc_idr, id);
-	if (!obj || (obj->type != type) || (obj->id != id))
+	if (!obj || (type != DRM_MODE_OBJECT_ANY && obj->type != type) ||
+	    (obj->id != id))
 		obj = NULL;
 	mutex_unlock(&dev->mode_config.idr_mutex);
 
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 372b159..8831562 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -51,6 +51,7 @@ struct drm_object_property_values;
 #define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb
 #define DRM_MODE_OBJECT_PLANE 0xeeeeeeee
 #define DRM_MODE_OBJECT_BRIDGE 0xbdbdbdbd
+#define DRM_MODE_OBJECT_ANY 0
 
 struct drm_mode_object {
 	uint32_t id;
-- 
1.8.3.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFCv1 08/12] drm: Refactor object property check code
  2013-10-06  0:45 [RFCv1 00/12] Atomic/nuclear modeset/pageflip Rob Clark
                   ` (6 preceding siblings ...)
  2013-10-06  0:45 ` [RFCv1 07/12] drm: Allow drm_mode_object_find() to look up an object of any type Rob Clark
@ 2013-10-06  0:45 ` Rob Clark
  2013-10-07 13:47   ` Ville Syrjälä
  2013-10-06  0:45 ` [RFCv1 09/12] drm: convert plane to properties/state Rob Clark
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 38+ messages in thread
From: Rob Clark @ 2013-10-06  0:45 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Refactor the code to check whether an object has a specific property
to a new function.

v1: original
v2: rebase on atomic -- Rob Clark

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_crtc.c | 25 ++++++++++++++-----------
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index c0546e8..776edf3 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -3374,6 +3374,19 @@ static int drm_mode_set_obj_prop(struct drm_mode_object *obj,
 	return -EINVAL;
 }
 
+static bool object_has_prop(const struct drm_mode_object *obj, u32 prop_id)
+{
+	int i;
+
+	if (!obj->properties)
+		return false;
+
+	for (i = 0; i < obj->properties->count; i++)
+		if (obj->properties->ids[i] == prop_id)
+			return true;
+	return false;
+}
+
 /* call with mode_config mutex held */
 static int drm_mode_set_obj_prop_id(struct drm_device *dev, void *state,
 		uint32_t obj_id, uint32_t obj_type,
@@ -3382,19 +3395,9 @@ static int drm_mode_set_obj_prop_id(struct drm_device *dev, void *state,
 	struct drm_mode_object *arg_obj;
 	struct drm_mode_object *prop_obj;
 	struct drm_property *property;
-	int i;
 
 	arg_obj = drm_mode_object_find(dev, obj_id, obj_type);
-	if (!arg_obj)
-		return -EINVAL;
-	if (!arg_obj->properties)
-		return -EINVAL;
-
-	for (i = 0; i < arg_obj->properties->count; i++)
-		if (arg_obj->properties->ids[i] == prop_id)
-			break;
-
-	if (i == arg_obj->properties->count)
+	if (!(arg_obj && object_has_prop(arg_obj, prop_id)))
 		return -EINVAL;
 
 	prop_obj = drm_mode_object_find(dev, prop_id,
-- 
1.8.3.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFCv1 09/12] drm: convert plane to properties/state
  2013-10-06  0:45 [RFCv1 00/12] Atomic/nuclear modeset/pageflip Rob Clark
                   ` (7 preceding siblings ...)
  2013-10-06  0:45 ` [RFCv1 08/12] drm: Refactor object property check code Rob Clark
@ 2013-10-06  0:45 ` Rob Clark
  2013-10-06  0:45 ` [RFCv1 10/12] drm: convert crtc " Rob Clark
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 38+ messages in thread
From: Rob Clark @ 2013-10-06  0:45 UTC (permalink / raw)
  To: dri-devel

Break the mutable state of a plane out into a separate structure
and use atomic properties mechanism to set plane attributes.  This
makes it easier to have some helpers for plane->set_property()
and for checking for invalid params.  The idea is that individual
drivers can wrap the state struct in their own struct which adds
driver specific parameters, for easy build-up of state across
multiple set_property() calls and for easy atomic commit or roll-
back.

The same should be done for CRTC, encoder, and connector, but this
patch only includes the first part (plane).
---
 drivers/gpu/drm/drm_atomic_helper.c         | 139 +++++++++-
 drivers/gpu/drm/drm_crtc.c                  | 400 +++++++++++++++++++---------
 drivers/gpu/drm/drm_fb_helper.c             |  17 +-
 drivers/gpu/drm/exynos/exynos_drm_crtc.c    |   4 +-
 drivers/gpu/drm/exynos/exynos_drm_encoder.c |   6 +-
 drivers/gpu/drm/exynos/exynos_drm_plane.c   |  13 +-
 drivers/gpu/drm/i915/intel_sprite.c         |  19 +-
 drivers/gpu/drm/msm/mdp4/mdp4_crtc.c        |   2 +-
 drivers/gpu/drm/msm/mdp4/mdp4_plane.c       |  16 +-
 drivers/gpu/drm/omapdrm/omap_crtc.c         |   4 +-
 drivers/gpu/drm/omapdrm/omap_drv.c          |   2 +-
 drivers/gpu/drm/omapdrm/omap_plane.c        |  30 ++-
 drivers/gpu/drm/rcar-du/rcar_du_plane.c     |   5 +-
 drivers/gpu/drm/shmobile/shmob_drm_crtc.c   |   2 +-
 drivers/gpu/drm/shmobile/shmob_drm_plane.c  |   6 +-
 drivers/gpu/host1x/drm/dc.c                 |  16 +-
 include/drm/drm_atomic_helper.h             |  35 ++-
 include/drm/drm_crtc.h                      |  86 +++++-
 18 files changed, 614 insertions(+), 188 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 563f37d..ca66b07 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -21,6 +21,8 @@
 
 struct drm_atomic_helper_state {
 	uint32_t flags;
+	struct drm_plane **planes;
+	struct drm_plane_state **pstates;
 };
 
 /**
@@ -43,10 +45,12 @@ struct drm_atomic_helper_state {
 void *drm_atomic_helper_begin(struct drm_device *dev, uint32_t flags)
 {
 	struct drm_atomic_helper_state *state;
+	int nplanes = dev->mode_config.num_plane;
 	int sz;
 	void *ptr;
 
 	sz = sizeof(*state);
+	sz += (sizeof(state->planes) + sizeof(state->pstates)) * nplanes;
 
 	ptr = kzalloc(sz, GFP_KERNEL);
 
@@ -54,6 +58,13 @@ void *drm_atomic_helper_begin(struct drm_device *dev, uint32_t flags)
 	ptr = &state[1];
 
 	state->flags = flags;
+
+	state->planes = ptr;
+	ptr = &state->planes[nplanes];
+
+	state->pstates = ptr;
+	ptr = &state->pstates[nplanes];
+
 	return state;
 }
 EXPORT_SYMBOL(drm_atomic_helper_begin);
@@ -89,7 +100,19 @@ EXPORT_SYMBOL(drm_atomic_helper_set_event);
  */
 int drm_atomic_helper_check(struct drm_device *dev, void *state)
 {
-	return 0;  /* for now */
+	struct drm_atomic_helper_state *a = state;
+	int nplanes = dev->mode_config.num_plane;
+	int i, ret = 0;
+
+	for (i = 0; i < nplanes; i++) {
+		if (a->planes[i]) {
+			ret = drm_atomic_check_plane_state(a->planes[i], a->pstates[i]);
+			if (ret)
+				break;
+		}
+	}
+
+	return ret;
 }
 EXPORT_SYMBOL(drm_atomic_helper_check);
 
@@ -106,7 +129,19 @@ EXPORT_SYMBOL(drm_atomic_helper_check);
  */
 int drm_atomic_helper_commit(struct drm_device *dev, void *state)
 {
-	return 0;  /* for now */
+	struct drm_atomic_helper_state *a = state;
+	int nplanes = dev->mode_config.num_plane;
+	int i, ret = 0;
+
+	for (i = 0; i < nplanes; i++) {
+		if (a->planes[i]) {
+			ret = drm_atomic_commit_plane_state(a->planes[i], a->pstates[i]);
+			if (ret)
+				break;
+		}
+	}
+
+	return ret;
 }
 EXPORT_SYMBOL(drm_atomic_helper_commit);
 
@@ -119,11 +154,111 @@ EXPORT_SYMBOL(drm_atomic_helper_commit);
  */
 void drm_atomic_helper_end(struct drm_device *dev, void *state)
 {
+	struct drm_atomic_helper_state *a = state;
+	int nplanes = dev->mode_config.num_plane;
+	int i;
+
+	for (i = 0; i < nplanes; i++) {
+		if (a->pstates[i]) {
+			a->planes[i]->state->state = NULL;
+			kfree(a->pstates[i]);
+		}
+	}
+
 	kfree(state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_end);
 
+int drm_atomic_helper_plane_set_property(struct drm_plane *plane, void *state,
+		struct drm_property *property, uint64_t val, void *blob_data)
+{
+	return drm_plane_set_property(plane,
+			drm_atomic_get_plane_state(plane, state),
+			property, val, blob_data);
+}
+EXPORT_SYMBOL(drm_atomic_helper_plane_set_property);
+
+void drm_atomic_helper_init_plane_state(struct drm_plane *plane,
+		struct drm_plane_state *pstate, void *state)
+{
+	/* snapshot current state: */
+	*pstate = *plane->state;
+	pstate->state = state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_init_plane_state);
+
+static struct drm_plane_state *
+drm_atomic_helper_get_plane_state(struct drm_plane *plane, void *state)
+{
+	struct drm_atomic_helper_state *a = state;
+	struct drm_plane_state *pstate = a->pstates[plane->id];
+	if (!pstate) {
+		pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
+		drm_atomic_helper_init_plane_state(plane, pstate, state);
+		a->planes[plane->id] = plane;
+		a->pstates[plane->id] = pstate;
+	}
+	return pstate;
+}
+
+static void
+swap_plane_state(struct drm_plane *plane, struct drm_atomic_helper_state *a)
+{
+	swap(plane->state, a->pstates[plane->id]);
+	plane->base.propvals = &plane->state->propvals;
+}
+
+static int
+drm_atomic_helper_commit_plane_state(struct drm_plane *plane,
+		struct drm_plane_state *pstate)
+{
+	struct drm_device *dev = plane->dev;
+	struct drm_framebuffer *old_fb = NULL, *fb = NULL;
+	int ret = 0;
+
+	/* probably more fine grain locking would be ok of old crtc
+	 * and new crtc were same..
+	 */
+	drm_modeset_lock_all(dev);
+
+	fb = pstate->fb;
+
+	if (pstate->crtc && pstate->fb) {
+		ret = plane->funcs->update_plane(plane, pstate->crtc, pstate->fb,
+			pstate->crtc_x, pstate->crtc_y, pstate->crtc_w, pstate->crtc_h,
+			pstate->src_x,  pstate->src_y,  pstate->src_w,  pstate->src_h);
+		if (!ret) {
+			/* on success, update state and fb refcnting: */
+			/* NOTE: if we ensure no driver sets plane->state->fb = NULL
+			 * on disable, we can move this up a level and not duplicate
+			 * nearly the same thing for both update_plane and disable_plane
+			 * cases..  I leave it like this for now to be paranoid due to
+			 * the slightly different ordering in the two cases in the
+			 * original code.
+			 */
+			old_fb = plane->state->fb;
+			swap_plane_state(plane, pstate->state);
+			fb = NULL;
+		}
+	} else {
+		old_fb = plane->state->fb;
+		plane->funcs->disable_plane(plane);
+		swap_plane_state(plane, pstate->state);
+	}
+
+	drm_modeset_unlock_all(dev);
+
+	if (fb)
+		drm_framebuffer_unreference(fb);
+	if (old_fb)
+		drm_framebuffer_unreference(old_fb);
+
+	return ret;
+}
 
 const struct drm_atomic_helper_funcs drm_atomic_helper_funcs = {
+		.get_plane_state    = drm_atomic_helper_get_plane_state,
+		.check_plane_state  = drm_plane_check_state,
+		.commit_plane_state = drm_atomic_helper_commit_plane_state,
 };
 EXPORT_SYMBOL(drm_atomic_helper_funcs);
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 776edf3..db0eb53 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -595,7 +595,20 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 	 * in this manner.
 	 */
 	if (atomic_read(&fb->refcount.refcount) > 1) {
+		void *state;
+
+		state = dev->driver->atomic_begin(dev, 0);
+		if (IS_ERR(state)) {
+			DRM_ERROR("failed to disable crtc and/or plane when fb was deleted\n");
+			return;
+		}
+
+		/* TODO once CRTC is converted to state/properties, we can push the
+		 * locking down into drm_atomic_helper_commit(), since that is where
+		 * the actual changes take place..
+		 */
 		drm_modeset_lock_all(dev);
+
 		/* remove from any CRTC */
 		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 			if (crtc->fb == fb) {
@@ -610,9 +623,18 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 		}
 
 		list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-			if (plane->fb == fb)
-				drm_plane_force_disable(plane);
+			if (plane->state->fb == fb)
+				drm_plane_force_disable(plane, state);
 		}
+
+		/* just disabling stuff shouldn't fail, hopefully: */
+		if(dev->driver->atomic_check(dev, state))
+			DRM_ERROR("failed to disable crtc and/or plane when fb was deleted\n");
+		else
+			dev->driver->atomic_commit(dev, state);
+
+		dev->driver->atomic_end(dev, state);
+
 		drm_modeset_unlock_all(dev);
 	}
 
@@ -904,8 +926,12 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 		   const uint32_t *formats, uint32_t format_count,
 		   bool priv)
 {
+	struct drm_mode_config *config = &dev->mode_config;
 	int ret;
 
+	if (!plane->state)
+		plane->state = kzalloc(sizeof(plane->state), GFP_KERNEL);
+
 	drm_modeset_lock_all(dev);
 
 	ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
@@ -913,7 +939,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 		goto out;
 
 	plane->base.properties = &plane->properties;
-	plane->base.propvals = &plane->propvals;
+	plane->base.propvals = &plane->state->propvals;
 	plane->dev = dev;
 	plane->funcs = funcs;
 	plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
@@ -935,11 +961,23 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 	 */
 	if (!priv) {
 		list_add_tail(&plane->head, &dev->mode_config.plane_list);
+		plane->id = dev->mode_config.num_plane;
 		dev->mode_config.num_plane++;
 	} else {
 		INIT_LIST_HEAD(&plane->head);
 	}
 
+	drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
+	drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
+	drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
+	drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
+	drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);
+	drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);
+	drm_object_attach_property(&plane->base, config->prop_src_x, 0);
+	drm_object_attach_property(&plane->base, config->prop_src_y, 0);
+	drm_object_attach_property(&plane->base, config->prop_src_w, 0);
+	drm_object_attach_property(&plane->base, config->prop_src_h, 0);
+
  out:
 	drm_modeset_unlock_all(dev);
 
@@ -971,6 +1009,111 @@ void drm_plane_cleanup(struct drm_plane *plane)
 }
 EXPORT_SYMBOL(drm_plane_cleanup);
 
+int drm_plane_check_state(struct drm_plane *plane,
+		struct drm_plane_state *state)
+{
+	unsigned int fb_width, fb_height;
+	struct drm_framebuffer *fb = state->fb;
+	int i;
+
+	/* disabling the plane is allowed: */
+	if (!fb)
+		return 0;
+
+	fb_width = fb->width << 16;
+	fb_height = fb->height << 16;
+
+	/* Check whether this plane supports the fb pixel format. */
+	for (i = 0; i < plane->format_count; i++)
+		if (fb->pixel_format == plane->format_types[i])
+			break;
+	if (i == plane->format_count) {
+		DRM_DEBUG_KMS("Invalid pixel format 0x%08x\n", fb->pixel_format);
+		return -EINVAL;
+	}
+
+	/* Make sure source coordinates are inside the fb. */
+	if (state->src_w > fb_width ||
+			state->src_x > fb_width - state->src_w ||
+			state->src_h > fb_height ||
+			state->src_y > fb_height - state->src_h) {
+		DRM_DEBUG_KMS("Invalid source coordinates "
+			      "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
+			      state->src_w >> 16,
+			      ((state->src_w & 0xffff) * 15625) >> 10,
+			      state->src_h >> 16,
+			      ((state->src_h & 0xffff) * 15625) >> 10,
+			      state->src_x >> 16,
+			      ((state->src_x & 0xffff) * 15625) >> 10,
+			      state->src_y >> 16,
+			      ((state->src_y & 0xffff) * 15625) >> 10);
+		return -ENOSPC;
+	}
+
+	/* Give drivers some help against integer overflows */
+	if (state->crtc_w > INT_MAX ||
+			state->crtc_x > INT_MAX - (int32_t) state->crtc_w ||
+			state->crtc_h > INT_MAX ||
+			state->crtc_y > INT_MAX - (int32_t) state->crtc_h) {
+		DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
+			      state->crtc_w, state->crtc_h,
+			      state->crtc_x, state->crtc_y);
+		return -ERANGE;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_plane_check_state);
+
+void drm_plane_commit_state(struct drm_plane *plane,
+		struct drm_plane_state *state)
+{
+	plane->state = state;
+	plane->base.propvals = &state->propvals;
+}
+EXPORT_SYMBOL(drm_plane_commit_state);
+
+int drm_plane_set_property(struct drm_plane *plane,
+		struct drm_plane_state *state,
+		struct drm_property *property,
+		uint64_t value, void *blob_data)
+{
+	struct drm_device *dev = plane->dev;
+	struct drm_mode_config *config = &dev->mode_config;
+
+	drm_object_property_set_value(&plane->base,
+			&state->propvals, property, value, blob_data);
+
+	if (property == config->prop_fb_id) {
+		struct drm_mode_object *obj = drm_property_get_obj(property, value);
+		state->fb = obj ? obj_to_fb(obj) : NULL;
+	} else if (property == config->prop_crtc_id) {
+		struct drm_mode_object *obj = drm_property_get_obj(property, value);
+		state->crtc = obj ? obj_to_crtc(obj) : NULL;
+	} else if (property == config->prop_crtc_x) {
+		state->crtc_x = U642I64(value);
+	} else if (property == config->prop_crtc_y) {
+		state->crtc_y = U642I64(value);
+	} else if (property == config->prop_crtc_w) {
+		state->crtc_w = value;
+	} else if (property == config->prop_crtc_h) {
+		state->crtc_h = value;
+	} else if (property == config->prop_src_x) {
+		state->src_x = value;
+	} else if (property == config->prop_src_y) {
+		state->src_y = value;
+	} else if (property == config->prop_src_w) {
+		state->src_w = value;
+	} else if (property == config->prop_src_h) {
+		state->src_h = value;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_plane_set_property);
+
 /**
  * drm_plane_force_disable - Forcibly disable a plane
  * @plane: plane to disable
@@ -980,20 +1123,15 @@ EXPORT_SYMBOL(drm_plane_cleanup);
  * Used when the plane's current framebuffer is destroyed,
  * and when restoring fbdev mode.
  */
-void drm_plane_force_disable(struct drm_plane *plane)
+void drm_plane_force_disable(struct drm_plane *plane, void *state)
 {
-	int ret;
+	struct drm_mode_config *config = &plane->dev->mode_config;
 
-	if (!plane->fb)
-		return;
-
-	ret = plane->funcs->disable_plane(plane);
-	if (ret)
-		DRM_ERROR("failed to disable plane with busy fb\n");
-	/* disconnect the plane from the fb and crtc: */
-	__drm_framebuffer_unreference(plane->fb);
-	plane->fb = NULL;
-	plane->crtc = NULL;
+	/* should turn off the crtc */
+	drm_mode_plane_set_obj_prop(plane, state,
+		config->prop_crtc_id, 0, NULL);
+	drm_mode_plane_set_obj_prop(plane, state,
+		config->prop_fb_id, 0, NULL);
 }
 EXPORT_SYMBOL(drm_plane_force_disable);
 
@@ -1043,21 +1181,89 @@ EXPORT_SYMBOL(drm_mode_destroy);
 
 static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
 {
-	struct drm_property *edid;
-	struct drm_property *dpms;
+	struct drm_property *prop;
 
 	/*
 	 * Standard properties (apply to all connectors)
 	 */
-	edid = drm_property_create(dev, DRM_MODE_PROP_BLOB |
+	prop = drm_property_create(dev, DRM_MODE_PROP_BLOB |
 				   DRM_MODE_PROP_IMMUTABLE,
 				   "EDID", 0);
-	dev->mode_config.edid_property = edid;
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.edid_property = prop;
 
-	dpms = drm_property_create_enum(dev, 0,
+	prop = drm_property_create_enum(dev, 0,
 				   "DPMS", drm_dpms_enum_list,
 				   ARRAY_SIZE(drm_dpms_enum_list));
-	dev->mode_config.dpms_property = dpms;
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.dpms_property = prop;
+
+
+	/* TODO we need the driver to control which of these are dynamic
+	 * and which are not..  or maybe we should just set all to zero
+	 * and let the individual drivers frob the prop->flags for the
+	 * properties they can support dynamic changes on..
+	 */
+
+	prop = drm_property_create_range(dev, DRM_MODE_PROP_DYNAMIC,
+			"SRC_X", 0, UINT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_src_x = prop;
+
+	prop = drm_property_create_range(dev, DRM_MODE_PROP_DYNAMIC,
+			"SRC_Y", 0, UINT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_src_y = prop;
+
+	prop = drm_property_create_range(dev, 0, "SRC_W", 0, UINT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_src_w = prop;
+
+	prop = drm_property_create_range(dev, 0, "SRC_H", 0, UINT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_src_h = prop;
+
+	prop = drm_property_create_range(dev,
+			DRM_MODE_PROP_DYNAMIC | DRM_MODE_PROP_SIGNED,
+			"CRTC_X", I642U64(INT_MIN), I642U64(INT_MAX));
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_x = prop;
+
+	prop = drm_property_create_range(dev,
+			DRM_MODE_PROP_DYNAMIC | DRM_MODE_PROP_SIGNED,
+			"CRTC_Y", I642U64(INT_MIN), I642U64(INT_MAX));
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_y = prop;
+
+	prop = drm_property_create_range(dev, 0, "CRTC_W", 0, INT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_w = prop;
+
+	prop = drm_property_create_range(dev, 0, "CRTC_H", 0, INT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_h = prop;
+
+	prop = drm_property_create_object(dev, DRM_MODE_PROP_DYNAMIC,
+			"FB_ID", DRM_MODE_OBJECT_FB);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_fb_id = prop;
+
+	prop = drm_property_create_object(dev, 0,
+			"CRTC_ID", DRM_MODE_OBJECT_CRTC);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_id = prop;
 
 	return 0;
 }
@@ -1842,13 +2048,13 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
 	}
 	plane = obj_to_plane(obj);
 
-	if (plane->crtc)
-		plane_resp->crtc_id = plane->crtc->base.id;
+	if (plane->state->crtc)
+		plane_resp->crtc_id = plane->state->crtc->base.id;
 	else
 		plane_resp->crtc_id = 0;
 
-	if (plane->fb)
-		plane_resp->fb_id = plane->fb->base.id;
+	if (plane->state->fb)
+		plane_resp->fb_id = plane->state->fb->base.id;
 	else
 		plane_resp->fb_id = 0;
 
@@ -1890,21 +2096,18 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 			struct drm_file *file_priv)
 {
 	struct drm_mode_set_plane *plane_req = data;
+	struct drm_mode_config *config = &dev->mode_config;
 	struct drm_mode_object *obj;
-	struct drm_plane *plane;
-	struct drm_crtc *crtc;
-	struct drm_framebuffer *fb = NULL, *old_fb = NULL;
+	void *state;
 	int ret = 0;
-	unsigned int fb_width, fb_height;
-	int i;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	/*
-	 * First, find the plane, crtc, and fb objects.  If not available,
-	 * we don't bother to call the driver.
-	 */
+	state = dev->driver->atomic_begin(dev, 0);
+	if (IS_ERR(state))
+		return PTR_ERR(state);
+
 	obj = drm_mode_object_find(dev, plane_req->plane_id,
 				   DRM_MODE_OBJECT_PLANE);
 	if (!obj) {
@@ -1912,102 +2115,39 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 			      plane_req->plane_id);
 		return -ENOENT;
 	}
-	plane = obj_to_plane(obj);
-
-	/* No fb means shut it down */
-	if (!plane_req->fb_id) {
-		drm_modeset_lock_all(dev);
-		old_fb = plane->fb;
-		plane->funcs->disable_plane(plane);
-		plane->crtc = NULL;
-		plane->fb = NULL;
-		drm_modeset_unlock_all(dev);
-		goto out;
-	}
-
-	obj = drm_mode_object_find(dev, plane_req->crtc_id,
-				   DRM_MODE_OBJECT_CRTC);
-	if (!obj) {
-		DRM_DEBUG_KMS("Unknown crtc ID %d\n",
-			      plane_req->crtc_id);
-		ret = -ENOENT;
-		goto out;
-	}
-	crtc = obj_to_crtc(obj);
-
-	fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
-	if (!fb) {
-		DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
-			      plane_req->fb_id);
-		ret = -ENOENT;
-		goto out;
-	}
-
-	/* Check whether this plane supports the fb pixel format. */
-	for (i = 0; i < plane->format_count; i++)
-		if (fb->pixel_format == plane->format_types[i])
-			break;
-	if (i == plane->format_count) {
-		DRM_DEBUG_KMS("Invalid pixel format %s\n",
-			      drm_get_format_name(fb->pixel_format));
-		ret = -EINVAL;
-		goto out;
-	}
 
-	fb_width = fb->width << 16;
-	fb_height = fb->height << 16;
-
-	/* Make sure source coordinates are inside the fb. */
-	if (plane_req->src_w > fb_width ||
-	    plane_req->src_x > fb_width - plane_req->src_w ||
-	    plane_req->src_h > fb_height ||
-	    plane_req->src_y > fb_height - plane_req->src_h) {
-		DRM_DEBUG_KMS("Invalid source coordinates "
-			      "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
-			      plane_req->src_w >> 16,
-			      ((plane_req->src_w & 0xffff) * 15625) >> 10,
-			      plane_req->src_h >> 16,
-			      ((plane_req->src_h & 0xffff) * 15625) >> 10,
-			      plane_req->src_x >> 16,
-			      ((plane_req->src_x & 0xffff) * 15625) >> 10,
-			      plane_req->src_y >> 16,
-			      ((plane_req->src_y & 0xffff) * 15625) >> 10);
-		ret = -ENOSPC;
-		goto out;
-	}
+	drm_modeset_lock_all(dev);
 
-	/* Give drivers some help against integer overflows */
-	if (plane_req->crtc_w > INT_MAX ||
-	    plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w ||
-	    plane_req->crtc_h > INT_MAX ||
-	    plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) {
-		DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
-			      plane_req->crtc_w, plane_req->crtc_h,
-			      plane_req->crtc_x, plane_req->crtc_y);
-		ret = -ERANGE;
+	ret =
+		drm_mode_set_obj_prop(obj, state,
+			config->prop_crtc_id, plane_req->crtc_id, NULL) ||
+		drm_mode_set_obj_prop(obj, state,
+			config->prop_fb_id, plane_req->fb_id, NULL) ||
+		drm_mode_set_obj_prop(obj, state,
+			config->prop_crtc_x, I642U64(plane_req->crtc_x), NULL) ||
+		drm_mode_set_obj_prop(obj, state,
+			config->prop_crtc_y, I642U64(plane_req->crtc_y), NULL) ||
+		drm_mode_set_obj_prop(obj, state,
+			config->prop_crtc_w, plane_req->crtc_w, NULL) ||
+		drm_mode_set_obj_prop(obj, state,
+			config->prop_crtc_h, plane_req->crtc_h, NULL) ||
+		drm_mode_set_obj_prop(obj, state,
+			config->prop_src_w, plane_req->src_w, NULL) ||
+		drm_mode_set_obj_prop(obj, state,
+			config->prop_src_h, plane_req->src_h, NULL) ||
+		drm_mode_set_obj_prop(obj, state,
+			config->prop_src_x, plane_req->src_x, NULL) ||
+		drm_mode_set_obj_prop(obj, state,
+			config->prop_src_y, plane_req->src_y, NULL) ||
+		dev->driver->atomic_check(dev, state);
+	if (ret)
 		goto out;
-	}
 
-	drm_modeset_lock_all(dev);
-	ret = plane->funcs->update_plane(plane, crtc, fb,
-					 plane_req->crtc_x, plane_req->crtc_y,
-					 plane_req->crtc_w, plane_req->crtc_h,
-					 plane_req->src_x, plane_req->src_y,
-					 plane_req->src_w, plane_req->src_h);
-	if (!ret) {
-		old_fb = plane->fb;
-		plane->crtc = crtc;
-		plane->fb = fb;
-		fb = NULL;
-	}
-	drm_modeset_unlock_all(dev);
+	ret = dev->driver->atomic_commit(dev, state);
 
 out:
-	if (fb)
-		drm_framebuffer_unreference(fb);
-	if (old_fb)
-		drm_framebuffer_unreference(old_fb);
-
+	dev->driver->atomic_end(dev, state);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -3295,7 +3435,7 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
 	return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv);
 }
 
-static int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
+int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
 					   void *state, struct drm_property *property,
 					   uint64_t value, void *blob_data)
 {
@@ -3318,8 +3458,9 @@ static int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
 
 	return ret;
 }
+EXPORT_SYMBOL(drm_mode_connector_set_obj_prop);
 
-static int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
+int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
 				      void *state, struct drm_property *property,
 				      uint64_t value, void *blob_data)
 {
@@ -3334,8 +3475,9 @@ static int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
 
 	return ret;
 }
+EXPORT_SYMBOL(drm_mode_crtc_set_obj_prop);
 
-static int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
 				      void *state, struct drm_property *property,
 				      uint64_t value, void *blob_data)
 {
@@ -3344,12 +3486,10 @@ static int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
 	if (plane->funcs->set_property)
 		ret = plane->funcs->set_property(plane, state, property,
 				value, blob_data);
-	if (!ret)
-		drm_object_property_set_value(&plane->base, &plane->propvals,
-				property, value, NULL);
 
 	return ret;
 }
+EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
 
 static int drm_mode_set_obj_prop(struct drm_mode_object *obj,
 		void *state, struct drm_property *property, 
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 24898dc..f1fc605 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -290,12 +290,27 @@ bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
 	struct drm_device *dev = fb_helper->dev;
 	struct drm_plane *plane;
 	bool error = false;
+	void *state;
 	int i;
 
 	drm_warn_on_modeset_not_all_locked(dev);
 
+	state = dev->driver->atomic_begin(dev, 0);
+	if (IS_ERR(state)) {
+		DRM_ERROR("failed to restore fbdev mode\n");
+		return true;
+	}
+
 	list_for_each_entry(plane, &dev->mode_config.plane_list, head)
-		drm_plane_force_disable(plane);
+		drm_plane_force_disable(plane, state);
+
+	/* just disabling stuff shouldn't fail, hopefully: */
+	if(dev->driver->atomic_check(dev, state))
+		DRM_ERROR("failed to restore fbdev mode\n");
+	else
+		dev->driver->atomic_commit(dev, state);
+
+	dev->driver->atomic_end(dev, state);
 
 	for (i = 0; i < fb_helper->crtc_count; i++) {
 		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 82a9fca..4ae55b8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -124,8 +124,8 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
 	if (ret)
 		return ret;
 
-	plane->crtc = crtc;
-	plane->fb = crtc->fb;
+	plane->state->crtc = crtc;
+	plane->state->fb = crtc->fb;
 
 	exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe);
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 06f1b2a..dbe2e19 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -127,7 +127,7 @@ static void disable_plane_to_crtc(struct drm_device *dev,
 	 * (encoder->crtc)
 	 */
 	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-		if (plane->crtc == old_crtc) {
+		if (plane->state->crtc == old_crtc) {
 			/*
 			 * do not change below call order.
 			 *
@@ -138,7 +138,7 @@ static void disable_plane_to_crtc(struct drm_device *dev,
 			 * have new_crtc because new_crtc was set to
 			 * encoder->crtc in advance.
 			 */
-			plane->crtc = new_crtc;
+			plane->state->crtc = new_crtc;
 			plane->funcs->disable_plane(plane);
 		}
 	}
@@ -247,7 +247,7 @@ static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
 
 	/* all planes connected to this encoder should be also disabled. */
 	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-		if (plane->crtc == encoder->crtc)
+		if (plane->state->crtc == encoder->crtc)
 			plane->funcs->disable_plane(plane);
 	}
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index 2e31fb8..45d0fa3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -10,6 +10,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 
 #include <drm/exynos_drm.h>
 #include "exynos_drm_drv.h"
@@ -149,7 +150,7 @@ void exynos_plane_commit(struct drm_plane *plane)
 	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
 	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
 
-	exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
+	exynos_drm_fn_encoder(plane->state->crtc, &overlay->zpos,
 			exynos_drm_encoder_plane_commit);
 }
 
@@ -162,7 +163,7 @@ void exynos_plane_dpms(struct drm_plane *plane, int mode)
 		if (exynos_plane->enabled)
 			return;
 
-		exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
+		exynos_drm_fn_encoder(plane->state->crtc, &overlay->zpos,
 				exynos_drm_encoder_plane_enable);
 
 		exynos_plane->enabled = true;
@@ -170,7 +171,7 @@ void exynos_plane_dpms(struct drm_plane *plane, int mode)
 		if (!exynos_plane->enabled)
 			return;
 
-		exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
+		exynos_drm_fn_encoder(plane->state->crtc, &overlay->zpos,
 				exynos_drm_encoder_plane_disable);
 
 		exynos_plane->enabled = false;
@@ -192,7 +193,7 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 	if (ret < 0)
 		return ret;
 
-	plane->crtc = crtc;
+	plane->state->crtc = crtc;
 
 	exynos_plane_commit(plane);
 	exynos_plane_dpms(plane, DRM_MODE_DPMS_ON);
@@ -229,6 +230,10 @@ static int exynos_plane_set_property(struct drm_plane *plane,
 	if (property == dev_priv->plane_zpos_property) {
 		exynos_plane->overlay.zpos = val;
 		return 0;
+	} else {
+		return drm_plane_set_property(plane,
+				drm_atomic_get_plane_state(plane, state),
+				property, val, blob_data);
 	}
 
 	return -EINVAL;
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index ad6ec4b..d8c2869 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -868,16 +868,17 @@ intel_disable_plane(struct drm_plane *plane)
 {
 	struct drm_device *dev = plane->dev;
 	struct intel_plane *intel_plane = to_intel_plane(plane);
+	struct drm_plane_state *state = plane->state;
 	int ret = 0;
 
-	if (!plane->fb)
+	if (!state->fb)
 		return 0;
 
-	if (WARN_ON(!plane->crtc))
+	if (WARN_ON(!state->crtc))
 		return -EINVAL;
 
-	intel_enable_primary(plane->crtc);
-	intel_plane->disable_plane(plane, plane->crtc);
+	intel_enable_primary(state->crtc);
+	intel_plane->disable_plane(plane, state->crtc);
 
 	if (!intel_plane->obj)
 		goto out;
@@ -966,11 +967,12 @@ out_unlock:
 void intel_plane_restore(struct drm_plane *plane)
 {
 	struct intel_plane *intel_plane = to_intel_plane(plane);
+	struct drm_plane_state *state = plane->state;
 
-	if (!plane->crtc || !plane->fb)
+	if (!state->crtc || !state->fb)
 		return;
 
-	intel_update_plane(plane, plane->crtc, plane->fb,
+	intel_update_plane(plane, state->crtc, state->fb,
 			   intel_plane->crtc_x, intel_plane->crtc_y,
 			   intel_plane->crtc_w, intel_plane->crtc_h,
 			   intel_plane->src_x, intel_plane->src_y,
@@ -979,7 +981,9 @@ void intel_plane_restore(struct drm_plane *plane)
 
 void intel_plane_disable(struct drm_plane *plane)
 {
-	if (!plane->crtc || !plane->fb)
+	struct drm_plane_state *state = plane->state;
+
+	if (!state->crtc || !state->fb)
 		return;
 
 	intel_disable_plane(plane);
@@ -989,6 +993,7 @@ static const struct drm_plane_funcs intel_plane_funcs = {
 	.update_plane = intel_update_plane,
 	.disable_plane = intel_disable_plane,
 	.destroy = intel_destroy_plane,
+	.set_property = drm_atomic_helper_plane_set_property,
 };
 
 static uint32_t ilk_plane_formats[] = {
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
index e81883d..dbedad2 100644
--- a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
+++ b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
@@ -644,7 +644,7 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
 	crtc = &mdp4_crtc->base;
 
 	mdp4_crtc->plane = plane;
-	mdp4_crtc->plane->crtc = crtc;
+	mdp4_crtc->plane->state->crtc = crtc;
 
 	mdp4_crtc->ovlp = ovlp_id;
 	mdp4_crtc->dma = dma_id;
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp4/mdp4_plane.c
index f0b6b12..642a9c8 100644
--- a/drivers/gpu/drm/msm/mdp4/mdp4_plane.c
+++ b/drivers/gpu/drm/msm/mdp4/mdp4_plane.c
@@ -45,11 +45,14 @@ static int mdp4_plane_update(struct drm_plane *plane,
 		uint32_t src_w, uint32_t src_h)
 {
 	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
+	struct drm_plane_state *state = plane->state;
 
 	mdp4_plane->enabled = true;
 
-	if (plane->fb)
-		drm_framebuffer_unreference(plane->fb);
+	if (state->fb) {
+		drm_framebuffer_unreference(state->fb);
+		state->fb = NULL;
+	}
 
 	drm_framebuffer_reference(fb);
 
@@ -85,8 +88,9 @@ void mdp4_plane_install_properties(struct drm_plane *plane,
 int mdp4_plane_set_property(struct drm_plane *plane, void *state,
 		struct drm_property *property, uint64_t val, void *blob_data)
 {
-	// XXX
-	return -EINVAL;
+	return drm_plane_set_property(plane,
+			drm_atomic_get_plane_state(plane, state),
+			property, val, blob_data);
 }
 
 static const struct drm_plane_funcs mdp4_plane_funcs = {
@@ -115,7 +119,7 @@ void mdp4_plane_set_scanout(struct drm_plane *plane,
 	msm_gem_get_iova(msm_framebuffer_bo(fb, 0), mdp4_kms->id, &iova);
 	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP0_BASE(pipe), iova);
 
-	plane->fb = fb;
+	plane->state->fb = fb;
 }
 
 #define MDP4_VG_PHASE_STEP_DEFAULT	0x20000000
@@ -191,7 +195,7 @@ int mdp4_plane_mode_set(struct drm_plane *plane,
 	mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEX_STEP(pipe), phasex_step);
 	mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEY_STEP(pipe), phasey_step);
 
-	plane->crtc = crtc;
+	plane->state->crtc = crtc;
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index 5dd22ab..d53a689 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -210,7 +210,7 @@ static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
 		/* and any attached overlay planes: */
 		for (i = 0; i < priv->num_planes; i++) {
 			struct drm_plane *plane = priv->planes[i];
-			if (plane->crtc == crtc)
+			if (plane->state->crtc == crtc)
 				WARN_ON(omap_plane_dpms(plane, mode));
 		}
 	}
@@ -651,7 +651,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 
 	omap_crtc->channel = channel;
 	omap_crtc->plane = plane;
-	omap_crtc->plane->crtc = crtc;
+	omap_crtc->plane->state->crtc = crtc;
 	omap_crtc->name = channel_names[channel];
 	omap_crtc->pipe = id;
 
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 225d0e9..0e15e2c 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -559,7 +559,7 @@ static void dev_lastclose(struct drm_device *dev)
 
 		for (i = 0; i < priv->num_planes; i++) {
 			drm_object_property_set_value(&priv->planes[i]->base,
-					&priv->planes[i]->propvals,
+					&priv->planes[i]->state->propvals,
 					priv->rotation_prop, 0, NULL);
 		}
 	}
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index fe32f1b..d11a879 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -116,9 +116,10 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
 			container_of(apply, struct omap_plane, apply);
 	struct omap_drm_window *win = &omap_plane->win;
 	struct drm_plane *plane = &omap_plane->base;
+	struct drm_plane_state *state = plane->state;
 	struct drm_device *dev = plane->dev;
 	struct omap_overlay_info *info = &omap_plane->info;
-	struct drm_crtc *crtc = plane->crtc;
+	struct drm_crtc *crtc = state->crtc;
 	enum omap_channel channel;
 	bool enabled = omap_plane->enabled && crtc;
 	bool ilace, replication;
@@ -127,7 +128,7 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
 	DBG("%s, enabled=%d", omap_plane->name, enabled);
 
 	/* if fb has changed, pin new fb: */
-	update_pin(plane, enabled ? plane->fb : NULL);
+	update_pin(plane, enabled ? state->fb : NULL);
 
 	if (!enabled) {
 		dispc_ovl_enable(omap_plane->id, false);
@@ -137,7 +138,7 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
 	channel = omap_crtc_channel(crtc);
 
 	/* update scanout: */
-	omap_framebuffer_update_scanout(plane->fb, win, info);
+	omap_framebuffer_update_scanout(state->fb, win, info);
 
 	DBG("%dx%d -> %dx%d (%d)", info->width, info->height,
 			info->out_width, info->out_height,
@@ -179,16 +180,18 @@ static void omap_plane_post_apply(struct omap_drm_apply *apply)
 		cb.fxn(cb.arg);
 
 	if (omap_plane->enabled) {
-		omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y,
+		omap_framebuffer_flush(plane->state->fb,
+				info->pos_x, info->pos_y,
 				info->out_width, info->out_height);
 	}
 }
 
 static int apply(struct drm_plane *plane)
 {
-	if (plane->crtc) {
+	struct drm_plane_state *state = plane->state;
+	if (state->crtc) {
 		struct omap_plane *omap_plane = to_omap_plane(plane);
-		return omap_crtc_apply(plane->crtc, &omap_plane->apply);
+		return omap_crtc_apply(state->crtc, &omap_plane->apply);
 	}
 	return 0;
 }
@@ -203,6 +206,7 @@ int omap_plane_mode_set(struct drm_plane *plane,
 {
 	struct omap_plane *omap_plane = to_omap_plane(plane);
 	struct omap_drm_window *win = &omap_plane->win;
+	struct drm_plane_state *state = plane->state;
 
 	win->crtc_x = crtc_x;
 	win->crtc_y = crtc_y;
@@ -225,8 +229,8 @@ int omap_plane_mode_set(struct drm_plane *plane,
 		omap_plane->apply_done_cb.arg = arg;
 	}
 
-	plane->fb = fb;
-	plane->crtc = crtc;
+	state->fb = fb;
+	state->crtc = crtc;
 
 	return apply(plane);
 }
@@ -239,10 +243,12 @@ static int omap_plane_update(struct drm_plane *plane,
 		uint32_t src_w, uint32_t src_h)
 {
 	struct omap_plane *omap_plane = to_omap_plane(plane);
+	struct drm_plane_state *state = plane->state;
+
 	omap_plane->enabled = true;
 
-	if (plane->fb)
-		drm_framebuffer_unreference(plane->fb);
+	if (state->fb)
+		drm_framebuffer_unreference(state->fb);
 
 	drm_framebuffer_reference(fb);
 
@@ -342,6 +348,10 @@ int omap_plane_set_property(struct drm_plane *plane, void *state,
 		DBG("%s: zorder: %02x", omap_plane->name, (uint32_t)val);
 		omap_plane->info.zorder = val;
 		ret = apply(plane);
+	} else {
+		ret = drm_plane_set_property(plane,
+				drm_atomic_get_plane_state(plane, state),
+				property, val, blob_data);
 	}
 
 	return ret;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
index 5691743..909e241 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -14,6 +14,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -411,7 +412,9 @@ static int rcar_du_plane_set_property(struct drm_plane *plane,
 	else if (property == rgrp->planes.zpos)
 		rcar_du_plane_set_zpos(rplane, value);
 	else
-		return -EINVAL;
+		return drm_plane_set_property(plane,
+				drm_atomic_get_plane_state(plane, state),
+				property, value, blob_data);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
index 035bd67..e62b0f2 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
@@ -238,7 +238,7 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc)
 
 	/* Setup planes. */
 	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-		if (plane->crtc == crtc)
+		if (plane->state->crtc == crtc)
 			shmob_drm_plane_setup(plane);
 	}
 
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/shmobile/shmob_drm_plane.c
index 060ae03..22da5c1 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_plane.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_plane.c
@@ -14,6 +14,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -166,10 +167,10 @@ void shmob_drm_plane_setup(struct drm_plane *plane)
 {
 	struct shmob_drm_plane *splane = to_shmob_plane(plane);
 
-	if (plane->fb == NULL)
+	if (plane->state->fb == NULL)
 		return;
 
-	__shmob_drm_plane_setup(splane, plane->fb);
+	__shmob_drm_plane_setup(splane, plane->state->fb);
 }
 
 static int
@@ -228,6 +229,7 @@ static void shmob_drm_plane_destroy(struct drm_plane *plane)
 static const struct drm_plane_funcs shmob_drm_plane_funcs = {
 	.update_plane = shmob_drm_plane_update,
 	.disable_plane = shmob_drm_plane_disable,
+	.set_property = drm_atomic_helper_plane_set_property,
 	.destroy = shmob_drm_plane_destroy,
 };
 
diff --git a/drivers/gpu/host1x/drm/dc.c b/drivers/gpu/host1x/drm/dc.c
index b1a05ad..5766010 100644
--- a/drivers/gpu/host1x/drm/dc.c
+++ b/drivers/gpu/host1x/drm/dc.c
@@ -75,11 +75,11 @@ static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
 
 static int tegra_plane_disable(struct drm_plane *plane)
 {
-	struct tegra_dc *dc = to_tegra_dc(plane->crtc);
+	struct tegra_dc *dc = to_tegra_dc(plane->state->crtc);
 	struct tegra_plane *p = to_tegra_plane(plane);
 	unsigned long value;
 
-	if (!plane->crtc)
+	if (!plane->state->crtc)
 		return 0;
 
 	value = WINDOW_A_SELECT << p->index;
@@ -104,6 +104,7 @@ static void tegra_plane_destroy(struct drm_plane *plane)
 static const struct drm_plane_funcs tegra_plane_funcs = {
 	.update_plane = tegra_plane_update,
 	.disable_plane = tegra_plane_disable,
+	.set_property = drm_atomic_helper_plane_set_property,
 	.destroy = tegra_plane_destroy,
 };
 
@@ -267,13 +268,14 @@ static void tegra_crtc_disable(struct drm_crtc *crtc)
 	struct drm_plane *plane;
 
 	list_for_each_entry(plane, &drm->mode_config.plane_list, head) {
-		if (plane->crtc == crtc) {
+		struct drm_plane_state *state = plane->state;
+		if (state->crtc == crtc) {
 			tegra_plane_disable(plane);
-			plane->crtc = NULL;
+			state->crtc = NULL;
 
-			if (plane->fb) {
-				drm_framebuffer_unreference(plane->fb);
-				plane->fb = NULL;
+			if (state->fb) {
+				drm_framebuffer_unreference(state->fb);
+				state->fb = NULL;
 			}
 		}
 	}
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index d6cba05..a51901e 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -68,7 +68,9 @@
  * struct drm_atomic_helper_funcs - helper funcs used by the atomic helpers
  */
 struct drm_atomic_helper_funcs {
-	int dummy; /* for now */
+	struct drm_plane_state *(*get_plane_state)(struct drm_plane *plane, void *state);
+	int (*check_plane_state)(struct drm_plane *plane, struct drm_plane_state *pstate);
+	int (*commit_plane_state)(struct drm_plane *plane, struct drm_plane_state *pstate);
 };
 
 const extern struct drm_atomic_helper_funcs drm_atomic_helper_funcs;
@@ -81,4 +83,35 @@ int drm_atomic_helper_check(struct drm_device *dev, void *state);
 int drm_atomic_helper_commit(struct drm_device *dev, void *state);
 void drm_atomic_helper_end(struct drm_device *dev, void *state);
 
+int drm_atomic_helper_plane_set_property(struct drm_plane *plane, void *state,
+		struct drm_property *property, uint64_t val, void *blob_data);
+void drm_atomic_helper_init_plane_state(struct drm_plane *plane,
+		struct drm_plane_state *pstate, void *state);
+
+static inline struct drm_plane_state *
+drm_atomic_get_plane_state(struct drm_plane *plane, void *state)
+{
+	const struct drm_atomic_helper_funcs *funcs =
+			plane->dev->driver->atomic_helpers;
+	return funcs->get_plane_state(plane, state);
+}
+
+static inline int
+drm_atomic_check_plane_state(struct drm_plane *plane,
+		struct drm_plane_state *pstate)
+{
+	const struct drm_atomic_helper_funcs *funcs =
+			plane->dev->driver->atomic_helpers;
+	return funcs->check_plane_state(plane, pstate);
+}
+
+static inline int
+drm_atomic_commit_plane_state(struct drm_plane *plane,
+		struct drm_plane_state *pstate)
+{
+	const struct drm_atomic_helper_funcs *funcs =
+			plane->dev->driver->atomic_helpers;
+	return funcs->commit_plane_state(plane, pstate);
+}
+
 #endif /* DRM_ATOMIC_HELPER_H_ */
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 8831562..db6c0a9 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -675,6 +675,43 @@ struct drm_plane_funcs {
 };
 
 /**
+ * drm_plane_state - mutable plane state
+ * @crtc: currently bound CRTC
+ * @fb: currently bound fb
+ * @crtc_x: left position of visible portion of plane on crtc
+ * @crtc_y: upper position of visible portion of plane on crtc
+ * @crtc_w: width of visible portion of plane on crtc
+ * @crtc_h: height of visible portion of plane on crtc
+ * @src_x: left position of visible portion of plane within
+ *   plane (in 16.16)
+ * @src_y: upper position of visible portion of plane within
+ *   plane (in 16.16)
+ * @src_w: width of visible portion of plane (in 16.16)
+ * @src_h: height of visible portion of plane (in 16.16)
+ * @propvals: property values
+ * @state: current global/toplevel state object (for atomic) while an
+ *    update is in progress, NULL otherwise.
+ */
+struct drm_plane_state {
+	struct drm_crtc *crtc;
+	struct drm_framebuffer *fb;
+
+	/* Signed dest location allows it to be partially off screen */
+	int32_t crtc_x, crtc_y;
+	uint32_t crtc_w, crtc_h;
+
+	/* Source values are 16.16 fixed point */
+	uint32_t src_x, src_y;
+	uint32_t src_h, src_w;
+
+	bool enabled;
+
+	struct drm_object_property_values propvals;
+
+	void *state;
+};
+
+/**
  * drm_plane - central DRM plane control structure
  * @dev: DRM device this plane belongs to
  * @head: for list management
@@ -682,8 +719,8 @@ struct drm_plane_funcs {
  * @possible_crtcs: pipes this plane can be bound to
  * @format_types: array of formats supported by this plane
  * @format_count: number of formats supported
- * @crtc: currently bound CRTC
- * @fb: currently bound fb
+ * @id: plane number, 0..n
+ * @state: the mutable state
  * @funcs: helper functions
  * @properties: property tracking for this plane
  */
@@ -697,13 +734,17 @@ struct drm_plane {
 	uint32_t *format_types;
 	uint32_t format_count;
 
-	struct drm_crtc *crtc;
-	struct drm_framebuffer *fb;
+	int id;
+
+	/*
+	 * State that can be updated from userspace, and atomically
+	 * commited or rolled back:
+	 */
+	struct drm_plane_state *state;
 
 	const struct drm_plane_funcs *funcs;
 
 	struct drm_object_properties properties;
-	struct drm_object_property_values propvals;
 };
 
 /**
@@ -884,8 +925,20 @@ struct drm_mode_config {
 	bool poll_running;
 	struct delayed_work output_poll_work;
 
-	/* pointers to standard properties */
+	/* just so blob properties can always be in a list: */
 	struct list_head property_blob_list;
+
+	/* pointers to standard properties */
+	struct drm_property *prop_src_x;
+	struct drm_property *prop_src_y;
+	struct drm_property *prop_src_w;
+	struct drm_property *prop_src_h;
+	struct drm_property *prop_crtc_x;
+	struct drm_property *prop_crtc_y;
+	struct drm_property *prop_crtc_w;
+	struct drm_property *prop_crtc_h;
+	struct drm_property *prop_fb_id;
+	struct drm_property *prop_crtc_id;
 	struct drm_property *edid_property;
 	struct drm_property *dpms_property;
 
@@ -969,7 +1022,15 @@ extern int drm_plane_init(struct drm_device *dev,
 			  const uint32_t *formats, uint32_t format_count,
 			  bool priv);
 extern void drm_plane_cleanup(struct drm_plane *plane);
-extern void drm_plane_force_disable(struct drm_plane *plane);
+extern void drm_plane_force_disable(struct drm_plane *plane, void *state);
+extern int drm_plane_check_state(struct drm_plane *plane,
+		struct drm_plane_state *state);
+extern void drm_plane_commit_state(struct drm_plane *plane,
+		struct drm_plane_state *state);
+extern int drm_plane_set_property(struct drm_plane *plane,
+		struct drm_plane_state *state,
+		struct drm_property *property,
+		uint64_t value, void *blob_data);
 
 extern void drm_encoder_cleanup(struct drm_encoder *encoder);
 
@@ -1023,6 +1084,17 @@ extern int drm_object_property_set_value(struct drm_mode_object *obj,
 extern int drm_object_property_get_value(struct drm_mode_object *obj,
 					 struct drm_property *property,
 					 uint64_t *value);
+
+int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
+					   void *state, struct drm_property *property,
+					   uint64_t value, void *blob_data);
+int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
+				      void *state, struct drm_property *property,
+				      uint64_t value, void *blob_data);
+int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+				      void *state, struct drm_property *property,
+				      uint64_t value, void *blob_data);
+
 extern int drm_framebuffer_init(struct drm_device *dev,
 				struct drm_framebuffer *fb,
 				const struct drm_framebuffer_funcs *funcs);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFCv1 10/12] drm: convert crtc to properties/state
  2013-10-06  0:45 [RFCv1 00/12] Atomic/nuclear modeset/pageflip Rob Clark
                   ` (8 preceding siblings ...)
  2013-10-06  0:45 ` [RFCv1 09/12] drm: convert plane to properties/state Rob Clark
@ 2013-10-06  0:45 ` Rob Clark
  2013-10-07 13:39   ` Ville Syrjälä
  2013-10-06  0:45 ` [RFCv1 11/12] drm: Atomic modeset ioctl Rob Clark
  2013-10-06  0:45 ` [RFCv1 12/12] ARM: add get_user() support for 8 byte types Rob Clark
  11 siblings, 1 reply; 38+ messages in thread
From: Rob Clark @ 2013-10-06  0:45 UTC (permalink / raw)
  To: dri-devel

Break the mutable state of a crtc out into a separate structure
and use atomic properties mechanism to set crtc attributes.  This
makes it easier to have some helpers for crtc->set_property()
and for checking for invalid params.  The idea is that individual
drivers can wrap the state struct in their own struct which adds
driver specific parameters, for easy build-up of state across
multiple set_property() calls and for easy atomic commit or roll-
back.
---
 drivers/gpu/drm/ast/ast_mode.c             |   1 +
 drivers/gpu/drm/cirrus/cirrus_mode.c       |   1 +
 drivers/gpu/drm/drm_atomic_helper.c        | 194 ++++++++++++-
 drivers/gpu/drm/drm_crtc.c                 | 422 ++++++++++++++++-------------
 drivers/gpu/drm/exynos/exynos_drm_crtc.c   |   5 +-
 drivers/gpu/drm/gma500/cdv_intel_display.c |   1 +
 drivers/gpu/drm/gma500/psb_intel_display.c |   1 +
 drivers/gpu/drm/i915/intel_display.c       |   1 +
 drivers/gpu/drm/mgag200/mgag200_mode.c     |   1 +
 drivers/gpu/drm/msm/mdp4/mdp4_crtc.c       |   5 +-
 drivers/gpu/drm/nouveau/dispnv04/crtc.c    |   1 +
 drivers/gpu/drm/nouveau/nv50_display.c     |   1 +
 drivers/gpu/drm/omapdrm/omap_crtc.c        |   9 +-
 drivers/gpu/drm/omapdrm/omap_drv.c         |   2 +-
 drivers/gpu/drm/qxl/qxl_display.c          |   2 +
 drivers/gpu/drm/radeon/radeon_display.c    |   2 +
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c     |   2 +
 drivers/gpu/drm/shmobile/shmob_drm_crtc.c  |   2 +
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c       |   1 +
 drivers/gpu/drm/udl/udl_modeset.c          |   2 +
 drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c        |   1 +
 drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c       |   1 +
 drivers/gpu/host1x/drm/dc.c                |   1 +
 drivers/staging/imx-drm/ipuv3-crtc.c       |   1 +
 include/drm/drm_atomic_helper.h            |  35 +++
 include/drm/drm_crtc.h                     |  74 ++++-
 26 files changed, 555 insertions(+), 214 deletions(-)

diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index 7fc9f72..13f6943 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -619,6 +619,7 @@ static const struct drm_crtc_funcs ast_crtc_funcs = {
 	.cursor_move = ast_cursor_move,
 	.reset = ast_crtc_reset,
 	.set_config = drm_crtc_helper_set_config,
+	.set_property = drm_atomic_helper_crtc_set_property,
 	.gamma_set = ast_crtc_gamma_set,
 	.destroy = ast_crtc_destroy,
 };
diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
index 60685b2..2d8b4ce 100644
--- a/drivers/gpu/drm/cirrus/cirrus_mode.c
+++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
@@ -363,6 +363,7 @@ static void cirrus_crtc_destroy(struct drm_crtc *crtc)
 static const struct drm_crtc_funcs cirrus_crtc_funcs = {
 	.gamma_set = cirrus_crtc_gamma_set,
 	.set_config = drm_crtc_helper_set_config,
+	.set_property = drm_atomic_helper_crtc_set_property,
 	.destroy = cirrus_crtc_destroy,
 };
 
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index ca66b07..f96773d 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -23,6 +23,8 @@ struct drm_atomic_helper_state {
 	uint32_t flags;
 	struct drm_plane **planes;
 	struct drm_plane_state **pstates;
+	struct drm_crtc **crtcs;
+	struct drm_crtc_state **cstates;
 };
 
 /**
@@ -46,11 +48,13 @@ void *drm_atomic_helper_begin(struct drm_device *dev, uint32_t flags)
 {
 	struct drm_atomic_helper_state *state;
 	int nplanes = dev->mode_config.num_plane;
+	int ncrtcs  = dev->mode_config.num_crtc;
 	int sz;
 	void *ptr;
 
 	sz = sizeof(*state);
 	sz += (sizeof(state->planes) + sizeof(state->pstates)) * nplanes;
+	sz += (sizeof(state->crtcs) + sizeof(state->cstates)) * ncrtcs;
 
 	ptr = kzalloc(sz, GFP_KERNEL);
 
@@ -65,6 +69,12 @@ void *drm_atomic_helper_begin(struct drm_device *dev, uint32_t flags)
 	state->pstates = ptr;
 	ptr = &state->pstates[nplanes];
 
+	state->crtcs = ptr;
+	ptr = &state->crtcs[ncrtcs];
+
+	state->cstates = ptr;
+	ptr = &state->cstates[ncrtcs];
+
 	return state;
 }
 EXPORT_SYMBOL(drm_atomic_helper_begin);
@@ -83,7 +93,16 @@ int drm_atomic_helper_set_event(struct drm_device *dev,
 		void *state, struct drm_mode_object *obj,
 		struct drm_pending_vblank_event *event)
 {
-	return -EINVAL;  /* for now */
+	switch (obj->type) {
+	case DRM_MODE_OBJECT_CRTC: {
+		struct drm_crtc_state *cstate =
+			drm_atomic_get_crtc_state(obj_to_crtc(obj), state);
+		cstate->event = event;
+		return 0;
+	}
+	default:
+		return -EINVAL;
+	}
 }
 EXPORT_SYMBOL(drm_atomic_helper_set_event);
 
@@ -131,6 +150,7 @@ int drm_atomic_helper_commit(struct drm_device *dev, void *state)
 {
 	struct drm_atomic_helper_state *a = state;
 	int nplanes = dev->mode_config.num_plane;
+	int ncrtcs = dev->mode_config.num_crtc;
 	int i, ret = 0;
 
 	for (i = 0; i < nplanes; i++) {
@@ -141,6 +161,14 @@ int drm_atomic_helper_commit(struct drm_device *dev, void *state)
 		}
 	}
 
+	for (i = 0; i < ncrtcs; i++) {
+		if (a->crtcs[i]) {
+			ret = drm_atomic_commit_crtc_state(a->crtcs[i], a->cstates[i]);
+			if (ret)
+				break;
+		}
+	}
+
 	return ret;
 }
 EXPORT_SYMBOL(drm_atomic_helper_commit);
@@ -156,6 +184,7 @@ void drm_atomic_helper_end(struct drm_device *dev, void *state)
 {
 	struct drm_atomic_helper_state *a = state;
 	int nplanes = dev->mode_config.num_plane;
+	int ncrtcs = dev->mode_config.num_crtc;
 	int i;
 
 	for (i = 0; i < nplanes; i++) {
@@ -165,6 +194,13 @@ void drm_atomic_helper_end(struct drm_device *dev, void *state)
 		}
 	}
 
+	for (i = 0; i < ncrtcs; i++) {
+		if (a->cstates[i]) {
+			a->crtcs[i]->state->state = NULL;
+			kfree(a->cstates[i]);
+		}
+	}
+
 	kfree(state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_end);
@@ -256,9 +292,165 @@ drm_atomic_helper_commit_plane_state(struct drm_plane *plane,
 	return ret;
 }
 
+int drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc, void *state,
+		struct drm_property *property, uint64_t val, void *blob_data)
+{
+	return drm_crtc_set_property(crtc,
+			drm_atomic_get_crtc_state(crtc, state),
+			property, val, blob_data);
+}
+EXPORT_SYMBOL(drm_atomic_helper_crtc_set_property);
+
+void drm_atomic_helper_init_crtc_state(struct drm_crtc *crtc,
+		struct drm_crtc_state *cstate, void *state)
+{
+	/* snapshot current state: */
+	*cstate = *crtc->state;
+	cstate->state = state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_init_crtc_state);
+
+static struct drm_crtc_state *
+drm_atomic_helper_get_crtc_state(struct drm_crtc *crtc, void *state)
+{
+	struct drm_atomic_helper_state *a = state;
+	struct drm_crtc_state *cstate = a->cstates[crtc->id];
+	if (!cstate) {
+		cstate = kzalloc(sizeof(*cstate), GFP_KERNEL);
+		drm_atomic_helper_init_crtc_state(crtc, cstate, state);
+		a->crtcs[crtc->id] = crtc;
+		a->cstates[crtc->id] = cstate;
+	}
+	return cstate;
+}
+
+static void
+swap_crtc_state(struct drm_crtc *crtc, struct drm_atomic_helper_state *a)
+{
+	swap(crtc->state, a->cstates[crtc->id]);
+	crtc->base.propvals = &crtc->state->propvals;
+}
+
+static struct drm_connector **get_connector_set(struct drm_device *dev,
+		uint32_t *connector_ids, uint32_t num_connector_ids)
+{
+	struct drm_connector **connector_set = NULL;
+	int i;
+
+	connector_set = kmalloc(num_connector_ids *
+			sizeof(struct drm_connector *),
+			GFP_KERNEL);
+	if (!connector_set)
+		return NULL;
+
+	for (i = 0; i < num_connector_ids; i++)
+		connector_set[i] = drm_connector_find(dev, connector_ids[i]);
+
+	return connector_set;
+}
+
+static int set_config(struct drm_crtc *crtc, struct drm_crtc_state *cstate)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_framebuffer *fb = cstate->fb;
+	struct drm_connector **connector_set = get_connector_set(crtc->dev,
+			cstate->connector_ids, cstate->num_connector_ids);
+	struct drm_mode_set set = {
+			.crtc = crtc,
+			.x = cstate->x,
+			.y = cstate->y,
+			.mode = cstate->mode_valid ? &cstate->mode : NULL,
+			.num_connectors = cstate->num_connector_ids,
+			.connectors = connector_set,
+			.fb = fb,
+	};
+	int ret;
+
+	drm_modeset_lock_all(dev);
+
+	ret = drm_mode_set_config_internal(&set);
+	if (!ret)
+		swap_crtc_state(crtc, cstate->state);
+
+	if (fb)
+		drm_framebuffer_unreference(fb);
+
+	kfree(connector_set);
+	drm_modeset_unlock_all(dev);
+	return ret;
+}
+
+static int
+drm_atomic_helper_commit_crtc_state(struct drm_crtc *crtc,
+		struct drm_crtc_state *cstate)
+{
+	struct drm_framebuffer *old_fb = NULL, *fb = NULL;
+	struct drm_atomic_helper_state *a = cstate->state;
+	int ret = -EINVAL;
+
+	if (cstate->set_config)
+		return set_config(crtc, cstate);
+
+	mutex_lock(&crtc->mutex);
+	if (cstate->fb && (crtc->state->fb != cstate->fb)) {
+		/* pageflip */
+
+		if (crtc->fb == NULL) {
+			/* The framebuffer is currently unbound, presumably
+			 * due to a hotplug event, that userspace has not
+			 * yet discovered.
+			 */
+			ret = -EBUSY;
+			goto out;
+		}
+
+		if (crtc->funcs->page_flip == NULL)
+			goto out;
+
+		old_fb = crtc->fb;
+		fb = cstate->fb;
+
+		ret = crtc->funcs->page_flip(crtc, fb, cstate->event, a->flags);
+		if (ret) {
+			/* Keep the old fb, don't unref it. */
+			old_fb = NULL;
+		} else {
+			swap_crtc_state(crtc, cstate->state);
+			/* Unref only the old framebuffer. */
+			fb = NULL;
+		}
+	} else if (crtc->state->fb != cstate->fb) {
+		/* disable */
+		struct drm_mode_set set = {
+				.crtc = crtc,
+				.fb = NULL,
+		};
+
+		old_fb = crtc->state->fb;
+		ret = drm_mode_set_config_internal(&set);
+		if (!ret) {
+			swap_crtc_state(crtc, cstate->state);
+		}
+	}
+
+out:
+	mutex_unlock(&crtc->mutex);
+
+	if (fb)
+		drm_framebuffer_unreference(fb);
+	if (old_fb)
+		drm_framebuffer_unreference(old_fb);
+
+	return ret;
+}
+
 const struct drm_atomic_helper_funcs drm_atomic_helper_funcs = {
 		.get_plane_state    = drm_atomic_helper_get_plane_state,
 		.check_plane_state  = drm_plane_check_state,
 		.commit_plane_state = drm_atomic_helper_commit_plane_state,
+
+		.get_crtc_state     = drm_atomic_helper_get_crtc_state,
+		.check_crtc_state   = drm_crtc_check_state,
+		.commit_crtc_state  = drm_atomic_helper_commit_crtc_state,
 };
 EXPORT_SYMBOL(drm_atomic_helper_funcs);
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index db0eb53..09396a9 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -574,8 +574,6 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 	struct drm_device *dev = fb->dev;
 	struct drm_crtc *crtc;
 	struct drm_plane *plane;
-	struct drm_mode_set set;
-	int ret;
 
 	WARN_ON(!list_empty(&fb->filp_head));
 
@@ -595,6 +593,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 	 * in this manner.
 	 */
 	if (atomic_read(&fb->refcount.refcount) > 1) {
+		struct drm_mode_config *config = &fb->dev->mode_config;
 		void *state;
 
 		state = dev->driver->atomic_begin(dev, 0);
@@ -613,12 +612,8 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 			if (crtc->fb == fb) {
 				/* should turn off the crtc */
-				memset(&set, 0, sizeof(struct drm_mode_set));
-				set.crtc = crtc;
-				set.fb = NULL;
-				ret = drm_mode_set_config_internal(&set);
-				if (ret)
-					DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
+				drm_mode_crtc_set_obj_prop(crtc, state,
+					config->prop_fb_id, 0, NULL);
 			}
 		}
 
@@ -656,11 +651,15 @@ EXPORT_SYMBOL(drm_framebuffer_remove);
 int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 		   const struct drm_crtc_funcs *funcs)
 {
+	struct drm_mode_config *config = &dev->mode_config;
 	int ret;
 
+	if (!crtc->state)
+		crtc->state = kzalloc(sizeof(crtc->state), GFP_KERNEL);
+
 	crtc->dev = dev;
 	crtc->funcs = funcs;
-	crtc->invert_dimensions = false;
+	crtc->state->invert_dimensions = false;
 
 	drm_modeset_lock_all(dev);
 	mutex_init(&crtc->mutex);
@@ -671,11 +670,17 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 		goto out;
 
 	crtc->base.properties = &crtc->properties;
-	crtc->base.propvals = &crtc->propvals;
+	crtc->base.propvals = &crtc->state->propvals;
 
 	list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
 	dev->mode_config.num_crtc++;
 
+	drm_object_attach_property(&crtc->base, config->prop_mode, 0);
+	drm_object_attach_property(&crtc->base, config->prop_connector_ids, 0);
+	drm_object_attach_property(&crtc->base, config->prop_fb_id, 0);
+	drm_object_attach_property(&crtc->base, config->prop_src_x, 0);
+	drm_object_attach_property(&crtc->base, config->prop_src_y, 0);
+
  out:
 	drm_modeset_unlock_all(dev);
 
@@ -704,6 +709,106 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
 }
 EXPORT_SYMBOL(drm_crtc_cleanup);
 
+int drm_crtc_check_state(struct drm_crtc *crtc,
+		struct drm_crtc_state *state)
+{
+	struct drm_framebuffer *fb = state->fb;
+	int hdisplay, vdisplay;
+
+	/* disabling the crtc is allowed: */
+	if (!(fb && state->mode_valid))
+		return 0;
+
+	hdisplay = state->mode.hdisplay;
+	vdisplay = state->mode.vdisplay;
+
+	if (state->invert_dimensions)
+		swap(hdisplay, vdisplay);
+
+	/* For some reason crtc x/y offsets are signed internally. */
+	if (state->x > INT_MAX || state->y > INT_MAX)
+		return -ERANGE;
+
+	if (hdisplay > fb->width ||
+	    vdisplay > fb->height ||
+	    state->x > fb->width - hdisplay ||
+	    state->y > fb->height - vdisplay) {
+		DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
+			      fb->width, fb->height, hdisplay, vdisplay,
+			      state->x, state->y,
+			      state->invert_dimensions ? " (inverted)" : "");
+		return -ENOSPC;
+	}
+
+	if (state->num_connector_ids == 0) {
+		DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_crtc_check_state);
+
+void drm_crtc_commit_state(struct drm_crtc *crtc,
+		struct drm_crtc_state *state)
+{
+	crtc->state = state;
+	crtc->base.propvals = &state->propvals;
+}
+EXPORT_SYMBOL(drm_crtc_commit_state);
+
+int drm_crtc_set_property(struct drm_crtc *crtc,
+		struct drm_crtc_state *state,
+		struct drm_property *property,
+		uint64_t value, void *blob_data)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_mode_config *config = &dev->mode_config;
+
+	drm_object_property_set_value(&crtc->base,
+			&state->propvals, property, value, blob_data);
+
+	if (property == config->prop_mode) {
+		if (!blob_data) {
+			memset(&state->mode, 0, sizeof(state->mode));
+			state->mode_valid = false;
+		} else {
+			/* check size: */
+			if (value < sizeof(struct drm_display_mode))
+				return -EINVAL;
+			state->mode = *(struct drm_display_mode *)blob_data;
+			state->mode_valid = true;
+		}
+		state->set_config = true;
+	} else if (property == config->prop_connector_ids) {
+		state->num_connector_ids = value;
+		state->connector_ids = blob_data;
+		state->set_config = true;
+	} else if (property == config->prop_fb_id) {
+		struct drm_mode_object *obj = drm_property_get_obj(property, value);
+		struct drm_framebuffer *fb = obj ? obj_to_fb(obj) : NULL;
+		if (fb && crtc->enabled) {
+			if (crtc->state->fb->pixel_format != fb->pixel_format) {
+				DRM_DEBUG_KMS("Page flip is not allowed to "
+						"change frame buffer format.\n");
+				return -EINVAL;
+			}
+		}
+		state->fb = fb;
+	} else if (property == config->prop_src_x) {
+		state->x = *(int *)&value;
+		state->set_config = true;
+	} else if (property == config->prop_src_y) {
+		state->y = *(int32_t *)&value;
+		state->set_config = true;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_crtc_set_property);
+
 /**
  * drm_mode_probed_add - add a mode to a connector's probed mode list
  * @connector: connector the new mode
@@ -1265,6 +1370,16 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
 		return -ENOMEM;
 	dev->mode_config.prop_crtc_id = prop;
 
+	prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, "CONNECTOR_IDS", 0);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_connector_ids = prop;
+
+	prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, "MODE", 0);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_mode = prop;
+
 	return 0;
 }
 
@@ -1775,17 +1890,17 @@ int drm_mode_getcrtc(struct drm_device *dev,
 	}
 	crtc = obj_to_crtc(obj);
 
-	crtc_resp->x = crtc->x;
-	crtc_resp->y = crtc->y;
+	crtc_resp->x = crtc->state->x;
+	crtc_resp->y = crtc->state->y;
 	crtc_resp->gamma_size = crtc->gamma_size;
-	if (crtc->fb)
-		crtc_resp->fb_id = crtc->fb->base.id;
+	if (crtc->state->fb)
+		crtc_resp->fb_id = crtc->state->fb->base.id;
 	else
 		crtc_resp->fb_id = 0;
 
 	if (crtc->enabled) {
 
-		drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode);
+		drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->state->mode);
 		crtc_resp->mode_valid = 1;
 
 	} else {
@@ -2212,22 +2327,16 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 	struct drm_mode_crtc *crtc_req = data;
 	struct drm_mode_object *obj;
 	struct drm_crtc *crtc;
-	struct drm_connector **connector_set = NULL, *connector;
-	struct drm_framebuffer *fb = NULL;
+	uint32_t fb_id = -1;
 	struct drm_display_mode *mode = NULL;
-	struct drm_mode_set set;
-	uint32_t __user *set_connectors_ptr;
+	uint32_t *connector_ids = NULL;
+	void *state;
 	int ret;
 	int i;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	/* For some reason crtc x/y offsets are signed internally. */
-	if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX)
-		return -ERANGE;
-
-	drm_modeset_lock_all(dev);
 	obj = drm_mode_object_find(dev, crtc_req->crtc_id,
 				   DRM_MODE_OBJECT_CRTC);
 	if (!obj) {
@@ -2239,7 +2348,6 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 	DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
 
 	if (crtc_req->mode_valid) {
-		int hdisplay, vdisplay;
 		/* If we have a mode we need a framebuffer. */
 		/* If we pass -1, set the mode with the currently bound fb */
 		if (crtc_req->fb_id == -1) {
@@ -2248,17 +2356,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 				ret = -EINVAL;
 				goto out;
 			}
-			fb = crtc->fb;
-			/* Make refcounting symmetric with the lookup path. */
-			drm_framebuffer_reference(fb);
+			fb_id = crtc->base.id;
 		} else {
-			fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);
-			if (!fb) {
-				DRM_DEBUG_KMS("Unknown FB ID%d\n",
-						crtc_req->fb_id);
-				ret = -EINVAL;
-				goto out;
-			}
+			fb_id = crtc_req->fb_id;
 		}
 
 		mode = drm_mode_create(dev);
@@ -2274,41 +2374,11 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 		}
 
 		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
-
-		hdisplay = mode->hdisplay;
-		vdisplay = mode->vdisplay;
-
-		if (crtc->invert_dimensions)
-			swap(hdisplay, vdisplay);
-
-		if (hdisplay > fb->width ||
-		    vdisplay > fb->height ||
-		    crtc_req->x > fb->width - hdisplay ||
-		    crtc_req->y > fb->height - vdisplay) {
-			DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
-				      fb->width, fb->height,
-				      hdisplay, vdisplay, crtc_req->x, crtc_req->y,
-				      crtc->invert_dimensions ? " (inverted)" : "");
-			ret = -ENOSPC;
-			goto out;
-		}
-	}
-
-	if (crtc_req->count_connectors == 0 && mode) {
-		DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
-		ret = -EINVAL;
-		goto out;
-	}
-
-	if (crtc_req->count_connectors > 0 && (!mode || !fb)) {
-		DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",
-			  crtc_req->count_connectors);
-		ret = -EINVAL;
-		goto out;
 	}
 
 	if (crtc_req->count_connectors > 0) {
-		u32 out_id;
+		uint32_t __user *set_connectors_ptr =
+				(uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
 
 		/* Avoid unbounded kernel memory allocation */
 		if (crtc_req->count_connectors > config->num_connector) {
@@ -2316,54 +2386,47 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 			goto out;
 		}
 
-		connector_set = kmalloc(crtc_req->count_connectors *
-					sizeof(struct drm_connector *),
+		connector_ids = kmalloc(crtc_req->count_connectors *
+					sizeof(connector_ids[0]),
 					GFP_KERNEL);
-		if (!connector_set) {
+		if (!connector_ids) {
 			ret = -ENOMEM;
 			goto out;
 		}
 
 		for (i = 0; i < crtc_req->count_connectors; i++) {
-			set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
+			u32 out_id;
+
 			if (get_user(out_id, &set_connectors_ptr[i])) {
 				ret = -EFAULT;
 				goto out;
 			}
-
-			obj = drm_mode_object_find(dev, out_id,
-						   DRM_MODE_OBJECT_CONNECTOR);
-			if (!obj) {
-				DRM_DEBUG_KMS("Connector id %d unknown\n",
-						out_id);
-				ret = -EINVAL;
-				goto out;
-			}
-			connector = obj_to_connector(obj);
-			DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
-					connector->base.id,
-					drm_get_connector_name(connector));
-
-			connector_set[i] = connector;
+			connector_ids[i] = out_id;
 		}
 	}
 
-	set.crtc = crtc;
-	set.x = crtc_req->x;
-	set.y = crtc_req->y;
-	set.mode = mode;
-	set.connectors = connector_set;
-	set.num_connectors = crtc_req->count_connectors;
-	set.fb = fb;
-	ret = drm_mode_set_config_internal(&set);
+	state = dev->driver->atomic_begin(dev, 0);
+	if (IS_ERR(state))
+		return PTR_ERR(state);
+
+	ret =
+		drm_mode_set_obj_prop(obj, state,
+			config->prop_mode, sizeof(*mode), mode) ||
+		drm_mode_set_obj_prop(obj, state,
+			config->prop_connector_ids,
+			crtc_req->count_connectors * sizeof(connector_ids[0]),
+			connector_ids) ||
+		drm_mode_set_obj_prop(obj, state,
+			config->prop_fb_id, fb_id, NULL) ||
+		drm_mode_set_obj_prop(obj, state,
+			config->prop_crtc_x, crtc_req->x, NULL) ||
+		drm_mode_set_obj_prop(obj, state,
+			config->prop_crtc_y, crtc_req->y, NULL) ||
+		dev->driver->atomic_check(dev, state);
 
 out:
-	if (fb)
-		drm_framebuffer_unreference(fb);
-
-	kfree(connector_set);
 	drm_mode_destroy(dev, mode);
-	drm_modeset_unlock_all(dev);
+	kfree(connector_ids);
 	return ret;
 }
 
@@ -3469,9 +3532,6 @@ int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
 	if (crtc->funcs->set_property)
 		ret = crtc->funcs->set_property(crtc, state, property,
 				value, blob_data);
-	if (!ret)
-		drm_object_property_set_value(&crtc->base, &crtc->propvals,
-				property, value, NULL);
 
 	return ret;
 }
@@ -3797,16 +3857,60 @@ out:
 	return ret;
 }
 
+static struct drm_pending_vblank_event *create_vblank_event(
+		struct drm_device *dev, struct drm_file *file_priv, uint64_t user_data)
+{
+	struct drm_pending_vblank_event *e = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	if (file_priv->event_space < sizeof e->event) {
+		spin_unlock_irqrestore(&dev->event_lock, flags);
+		goto out;
+	}
+	file_priv->event_space -= sizeof e->event;
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	e = kzalloc(sizeof *e, GFP_KERNEL);
+	if (e == NULL) {
+		spin_lock_irqsave(&dev->event_lock, flags);
+		file_priv->event_space += sizeof e->event;
+		spin_unlock_irqrestore(&dev->event_lock, flags);
+		goto out;
+	}
+
+	e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
+	e->event.base.length = sizeof e->event;
+	e->event.user_data = user_data;
+	e->base.event = &e->event.base;
+	e->base.file_priv = file_priv;
+	e->base.destroy =
+		(void (*) (struct drm_pending_event *)) kfree;
+
+out:
+	return e;
+}
+
+static void destroy_vblank_event(struct drm_device *dev,
+		struct drm_file *file_priv, struct drm_pending_vblank_event *e)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	file_priv->event_space += sizeof e->event;
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+	kfree(e);
+}
+
 int drm_mode_page_flip_ioctl(struct drm_device *dev,
 			     void *data, struct drm_file *file_priv)
 {
 	struct drm_mode_crtc_page_flip *page_flip = data;
+	struct drm_mode_config *config = &dev->mode_config;
 	struct drm_mode_object *obj;
 	struct drm_crtc *crtc;
-	struct drm_framebuffer *fb = NULL, *old_fb = NULL;
 	struct drm_pending_vblank_event *e = NULL;
-	unsigned long flags;
-	int hdisplay, vdisplay;
+	void *state;
 	int ret = -EINVAL;
 
 	if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
@@ -3821,103 +3925,37 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 		return -EINVAL;
 	crtc = obj_to_crtc(obj);
 
-	mutex_lock(&crtc->mutex);
-	if (crtc->fb == NULL) {
-		/* The framebuffer is currently unbound, presumably
-		 * due to a hotplug event, that userspace has not
-		 * yet discovered.
-		 */
-		ret = -EBUSY;
-		goto out;
-	}
-
-	if (crtc->funcs->page_flip == NULL)
-		goto out;
-
-	fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
-	if (!fb)
-		goto out;
-
-	hdisplay = crtc->mode.hdisplay;
-	vdisplay = crtc->mode.vdisplay;
-
-	if (crtc->invert_dimensions)
-		swap(hdisplay, vdisplay);
-
-	if (hdisplay > fb->width ||
-	    vdisplay > fb->height ||
-	    crtc->x > fb->width - hdisplay ||
-	    crtc->y > fb->height - vdisplay) {
-		DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
-			      fb->width, fb->height, hdisplay, vdisplay, crtc->x, crtc->y,
-			      crtc->invert_dimensions ? " (inverted)" : "");
-		ret = -ENOSPC;
-		goto out;
-	}
-
-	if (crtc->fb->pixel_format != fb->pixel_format) {
-		DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
-		ret = -EINVAL;
-		goto out;
-	}
+	state = dev->driver->atomic_begin(dev, page_flip->flags);
+	if (IS_ERR(state))
+		return PTR_ERR(state);
 
 	if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
-		ret = -ENOMEM;
-		spin_lock_irqsave(&dev->event_lock, flags);
-		if (file_priv->event_space < sizeof e->event) {
-			spin_unlock_irqrestore(&dev->event_lock, flags);
+		e = create_vblank_event(dev, file_priv, page_flip->user_data);
+		if (!e) {
+			ret = -ENOMEM;
 			goto out;
 		}
-		file_priv->event_space -= sizeof e->event;
-		spin_unlock_irqrestore(&dev->event_lock, flags);
-
-		e = kzalloc(sizeof *e, GFP_KERNEL);
-		if (e == NULL) {
-			spin_lock_irqsave(&dev->event_lock, flags);
-			file_priv->event_space += sizeof e->event;
-			spin_unlock_irqrestore(&dev->event_lock, flags);
+		ret = dev->driver->atomic_set_event(dev, state, obj, e);
+		if (ret) {
 			goto out;
 		}
-
-		e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
-		e->event.base.length = sizeof e->event;
-		e->event.user_data = page_flip->user_data;
-		e->base.event = &e->event.base;
-		e->base.file_priv = file_priv;
-		e->base.destroy =
-			(void (*) (struct drm_pending_event *)) kfree;
 	}
 
-	old_fb = crtc->fb;
-	ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
-	if (ret) {
-		if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
-			spin_lock_irqsave(&dev->event_lock, flags);
-			file_priv->event_space += sizeof e->event;
-			spin_unlock_irqrestore(&dev->event_lock, flags);
-			kfree(e);
-		}
-		/* Keep the old fb, don't unref it. */
-		old_fb = NULL;
-	} else {
-		/*
-		 * Warn if the driver hasn't properly updated the crtc->fb
-		 * field to reflect that the new framebuffer is now used.
-		 * Failing to do so will screw with the reference counting
-		 * on framebuffers.
-		 */
-		WARN_ON(crtc->fb != fb);
-		/* Unref only the old framebuffer. */
-		fb = NULL;
-	}
+	ret = drm_mode_set_obj_prop(obj, state,
+			config->prop_fb_id, page_flip->fb_id, NULL);
+	if (ret)
+		goto out;
 
-out:
-	if (fb)
-		drm_framebuffer_unreference(fb);
-	if (old_fb)
-		drm_framebuffer_unreference(old_fb);
-	mutex_unlock(&crtc->mutex);
+	ret = dev->driver->atomic_check(dev, state);
+	if (ret)
+		goto out;
+
+	ret = dev->driver->atomic_commit(dev, state);
 
+out:
+	if (ret && e)
+		destroy_vblank_event(dev, file_priv, e);
+	dev->driver->atomic_end(dev, state);
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 4ae55b8..c1ef671 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -14,6 +14,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 
 #include "exynos_drm_crtc.h"
 #include "exynos_drm_drv.h"
@@ -286,7 +287,9 @@ static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
 		return 0;
 	}
 
-	return -EINVAL;
+	return drm_crtc_set_property(crtc,
+			drm_atomic_get_crtc_state(crtc, state),
+			property, val, blob_data);
 }
 
 static struct drm_crtc_funcs exynos_crtc_funcs = {
diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c
index 8fbfa06..2b4bbf5 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_display.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_display.c
@@ -1022,6 +1022,7 @@ const struct drm_crtc_funcs cdv_intel_crtc_funcs = {
 	.cursor_move = gma_crtc_cursor_move,
 	.gamma_set = gma_crtc_gamma_set,
 	.set_config = gma_crtc_set_config,
+	.set_property = drm_atomic_helper_crtc_set_property,
 	.destroy = gma_crtc_destroy,
 };
 
diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
index 97f8a03..34d83ff 100644
--- a/drivers/gpu/drm/gma500/psb_intel_display.c
+++ b/drivers/gpu/drm/gma500/psb_intel_display.c
@@ -444,6 +444,7 @@ const struct drm_crtc_funcs psb_intel_crtc_funcs = {
 	.cursor_move = gma_crtc_cursor_move,
 	.gamma_set = gma_crtc_gamma_set,
 	.set_config = gma_crtc_set_config,
+	.set_property = drm_atomic_helper_crtc_set_property,
 	.destroy = gma_crtc_destroy,
 };
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index d0eff24..517bf6c 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -9277,6 +9277,7 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
 	.cursor_move = intel_crtc_cursor_move,
 	.gamma_set = intel_crtc_gamma_set,
 	.set_config = intel_crtc_set_config,
+	.set_property = drm_atomic_helper_crtc_set_property,
 	.destroy = intel_crtc_destroy,
 	.page_flip = intel_crtc_page_flip,
 };
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 503a414..3bda15b 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1298,6 +1298,7 @@ static const struct drm_crtc_funcs mga_crtc_funcs = {
 	.cursor_move = mga_crtc_cursor_move,
 	.gamma_set = mga_crtc_gamma_set,
 	.set_config = drm_crtc_helper_set_config,
+	.set_property = drm_atomic_helper_crtc_set_property,
 	.destroy = mga_crtc_destroy,
 };
 
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
index dbedad2..8e36a16 100644
--- a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
+++ b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
@@ -395,8 +395,9 @@ static int mdp4_crtc_page_flip(struct drm_crtc *crtc,
 static int mdp4_crtc_set_property(struct drm_crtc *crtc, void *state,
 		struct drm_property *property, uint64_t val, void *blob_data)
 {
-	// XXX
-	return -EINVAL;
+	return drm_crtc_set_property(crtc,
+			drm_atomic_get_crtc_state(crtc, state),
+			property, val, blob_data);
 }
 
 #define CURSOR_WIDTH 64
diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index d4fbf11..8fee163 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -1088,6 +1088,7 @@ static const struct drm_crtc_funcs nv04_crtc_funcs = {
 	.cursor_move = nv04_crtc_cursor_move,
 	.gamma_set = nv_crtc_gamma_set,
 	.set_config = nouveau_crtc_set_config,
+	.set_property = drm_atomic_helper_crtc_set_property,
 	.page_flip = nouveau_crtc_page_flip,
 	.destroy = nv_crtc_destroy,
 };
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index f8e66c0..bfcdf8e 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -1327,6 +1327,7 @@ static const struct drm_crtc_funcs nv50_crtc_func = {
 	.cursor_move = nv50_crtc_cursor_move,
 	.gamma_set = nv50_crtc_gamma_set,
 	.set_config = nouveau_crtc_set_config,
+	.set_property = drm_atomic_helper_crtc_set_property,
 	.destroy = nv50_crtc_destroy,
 	.page_flip = nouveau_crtc_page_flip,
 };
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index d53a689..054d75e 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -367,14 +367,19 @@ static int omap_crtc_set_property(struct drm_crtc *crtc, void *state,
 {
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 	struct omap_drm_private *priv = crtc->dev->dev_private;
+	struct drm_crtc_state *cstate = drm_atomic_get_crtc_state(crtc, state);
+	int ret;
 
 	if (property == priv->rotation_prop) {
-		crtc->invert_dimensions =
+		cstate->invert_dimensions =
 				!!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
 	}
 
-	return omap_plane_set_property(omap_crtc->plane, state,
+	ret = omap_plane_set_property(omap_crtc->plane, state,
 			property, val, blob_data);
+	if (ret)
+		ret = drm_crtc_set_property(crtc, cstate, property, val, blob_data);
+	return ret;
 }
 
 static const struct drm_crtc_funcs omap_crtc_funcs = {
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 0e15e2c..8651a02 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -553,7 +553,7 @@ static void dev_lastclose(struct drm_device *dev)
 		 */
 		for (i = 0; i < priv->num_crtcs; i++) {
 			drm_object_property_set_value(&priv->crtcs[i]->base,
-					&priv->crtcs[i]->propvals,
+					&priv->crtcs[i]->state->propvals,
 					priv->rotation_prop, 0, NULL);
 		}
 
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 9f12205..b138bb1 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -29,6 +29,7 @@
 #include "qxl_drv.h"
 #include "qxl_object.h"
 #include "drm_crtc_helper.h"
+#include "drm_atomic_helper.h"
 
 static bool qxl_head_enabled(struct qxl_head *head)
 {
@@ -365,6 +366,7 @@ static const struct drm_crtc_funcs qxl_crtc_funcs = {
 	.cursor_set2 = qxl_crtc_cursor_set2,
 	.cursor_move = qxl_crtc_cursor_move,
 	.set_config = drm_crtc_helper_set_config,
+	.set_property = drm_atomic_helper_crtc_set_property,
 	.destroy = qxl_crtc_destroy,
 };
 
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 0d1aa05..70d1346 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -31,6 +31,7 @@
 #include <asm/div64.h>
 
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_edid.h>
 
 static void avivo_crtc_load_lut(struct drm_crtc *crtc)
@@ -499,6 +500,7 @@ static const struct drm_crtc_funcs radeon_crtc_funcs = {
 	.cursor_move = radeon_crtc_cursor_move,
 	.gamma_set = radeon_crtc_gamma_set,
 	.set_config = drm_crtc_helper_set_config,
+	.set_property = drm_atomic_helper_crtc_set_property,
 	.destroy = radeon_crtc_destroy,
 	.page_flip = radeon_crtc_page_flip,
 };
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index a9d24e4..c840ba8 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -17,6 +17,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -528,6 +529,7 @@ static int rcar_du_crtc_page_flip(struct drm_crtc *crtc,
 static const struct drm_crtc_funcs crtc_funcs = {
 	.destroy = drm_crtc_cleanup,
 	.set_config = drm_crtc_helper_set_config,
+	.set_property = drm_atomic_helper_crtc_set_property,
 	.page_flip = rcar_du_crtc_page_flip,
 };
 
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
index e62b0f2..794ff95 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
@@ -17,6 +17,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -496,6 +497,7 @@ static int shmob_drm_crtc_page_flip(struct drm_crtc *crtc,
 static const struct drm_crtc_funcs crtc_funcs = {
 	.destroy = drm_crtc_cleanup,
 	.set_config = drm_crtc_helper_set_config,
+	.set_property = drm_atomic_helper_crtc_set_property,
 	.page_flip = shmob_drm_crtc_page_flip,
 };
 
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index d36efc1..34d9804 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -411,6 +411,7 @@ static int tilcdc_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 static const struct drm_crtc_funcs tilcdc_crtc_funcs = {
 		.destroy        = tilcdc_crtc_destroy,
 		.set_config     = drm_crtc_helper_set_config,
+		.set_property   = drm_atomic_helper_crtc_set_property,
 		.page_flip      = tilcdc_crtc_page_flip,
 };
 
diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index 2ae1eb7..e05b2ea 100644
--- a/drivers/gpu/drm/udl/udl_modeset.c
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -14,6 +14,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include "udl_drv.h"
 
 /*
@@ -383,6 +384,7 @@ static struct drm_crtc_helper_funcs udl_helper_funcs = {
 
 static const struct drm_crtc_funcs udl_crtc_funcs = {
 	.set_config = drm_crtc_helper_set_config,
+	.set_property = drm_atomic_helper_crtc_set_property,
 	.destroy = udl_crtc_destroy,
 };
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index 79f7e8e..5d25f21 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -298,6 +298,7 @@ static struct drm_crtc_funcs vmw_legacy_crtc_funcs = {
 	.cursor_move = vmw_du_crtc_cursor_move,
 	.gamma_set = vmw_du_crtc_gamma_set,
 	.destroy = vmw_ldu_crtc_destroy,
+	.set_property = drm_atomic_helper_crtc_set_property,
 	.set_config = vmw_ldu_crtc_set_config,
 };
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index 26387c3..f65fec7 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -394,6 +394,7 @@ static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
 	.gamma_set = vmw_du_crtc_gamma_set,
 	.destroy = vmw_sou_crtc_destroy,
 	.set_config = vmw_sou_crtc_set_config,
+	.set_property = drm_atomic_helper_crtc_set_property,
 	.page_flip = vmw_du_page_flip,
 };
 
diff --git a/drivers/gpu/host1x/drm/dc.c b/drivers/gpu/host1x/drm/dc.c
index 5766010..3a7533e 100644
--- a/drivers/gpu/host1x/drm/dc.c
+++ b/drivers/gpu/host1x/drm/dc.c
@@ -259,6 +259,7 @@ static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 static const struct drm_crtc_funcs tegra_crtc_funcs = {
 	.page_flip = tegra_dc_page_flip,
 	.set_config = drm_crtc_helper_set_config,
+	.set_property = drm_atomic_helper_crtc_set_property,
 	.destroy = drm_crtc_cleanup,
 };
 
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index 6fd37a7..f97862e 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -155,6 +155,7 @@ static int ipu_page_flip(struct drm_crtc *crtc,
 
 static const struct drm_crtc_funcs ipu_crtc_funcs = {
 	.set_config = drm_crtc_helper_set_config,
+	.set_property = drm_atomic_helper_crtc_set_property,
 	.destroy = drm_crtc_cleanup,
 	.page_flip = ipu_page_flip,
 };
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index a51901e..21b6166 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -71,6 +71,10 @@ struct drm_atomic_helper_funcs {
 	struct drm_plane_state *(*get_plane_state)(struct drm_plane *plane, void *state);
 	int (*check_plane_state)(struct drm_plane *plane, struct drm_plane_state *pstate);
 	int (*commit_plane_state)(struct drm_plane *plane, struct drm_plane_state *pstate);
+
+	struct drm_crtc_state *(*get_crtc_state)(struct drm_crtc *crtc, void *state);
+	int (*check_crtc_state)(struct drm_crtc *crtc, struct drm_crtc_state *cstate);
+	int (*commit_crtc_state)(struct drm_crtc *crtc, struct drm_crtc_state *cstate);
 };
 
 const extern struct drm_atomic_helper_funcs drm_atomic_helper_funcs;
@@ -114,4 +118,35 @@ drm_atomic_commit_plane_state(struct drm_plane *plane,
 	return funcs->commit_plane_state(plane, pstate);
 }
 
+int drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc, void *state,
+		struct drm_property *property, uint64_t val, void *blob_data);
+void drm_atomic_helper_init_crtc_state(struct drm_crtc *crtc,
+		struct drm_crtc_state *cstate, void *state);
+
+static inline struct drm_crtc_state *
+drm_atomic_get_crtc_state(struct drm_crtc *crtc, void *state)
+{
+	const struct drm_atomic_helper_funcs *funcs =
+			crtc->dev->driver->atomic_helpers;
+	return funcs->get_crtc_state(crtc, state);
+}
+
+static inline int
+drm_atomic_check_crtc_state(struct drm_crtc *crtc,
+		struct drm_crtc_state *cstate)
+{
+	const struct drm_atomic_helper_funcs *funcs =
+			crtc->dev->driver->atomic_helpers;
+	return funcs->check_crtc_state(crtc, cstate);
+}
+
+static inline int
+drm_atomic_commit_crtc_state(struct drm_crtc *crtc,
+		struct drm_crtc_state *cstate)
+{
+	const struct drm_atomic_helper_funcs *funcs =
+			crtc->dev->driver->atomic_helpers;
+	return funcs->commit_crtc_state(crtc, cstate);
+}
+
 #endif /* DRM_ATOMIC_HELPER_H_ */
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index db6c0a9..86a5a00 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -390,18 +390,49 @@ struct drm_crtc_funcs {
 };
 
 /**
+ * drm_crtc_state - mutable crtc state
+ * @invert_dimensions: for purposes of error checking crtc vs fb sizes,
+ *    invert the width/height of the crtc.  This is used if the driver
+ *    is performing 90 or 270 degree rotated scanout
+ * @set_config: needs modeset (crtc->set_config())
+ * @mode_valid: a valid mode has been set
+ * @num_connector_ids: the number of connector-ids
+ * @connector_ids: array of connector ids
+ * @mode: current mode timings
+ * @fb: the framebuffer that the CRTC is currently bound to
+ * @x: x position on screen
+ * @y: y position on screen
+ * @event: pending pageflip event
+ * @propvals: property values
+ * @state: current global/toplevel state object (for atomic) while an
+ *    update is in progress, NULL otherwise.
+ */
+struct drm_crtc_state {
+	bool invert_dimensions : 1;
+	bool set_config        : 1;
+	bool mode_valid        : 1;  /* drop this if when mode a refcnt'd ptr */
+	uint8_t num_connector_ids;
+	uint32_t *connector_ids;
+	struct drm_display_mode mode;
+	struct drm_framebuffer *fb;
+	int x, y;
+
+	struct drm_pending_vblank_event *event;
+
+	struct drm_object_property_values propvals;
+
+	void *state;
+};
+
+/**
  * drm_crtc - central CRTC control structure
  * @dev: parent DRM device
  * @head: list management
+ * @id: CRTC number, 0..n
  * @base: base KMS object for ID tracking etc.
+ * @state: the mutable state
  * @enabled: is this CRTC enabled?
- * @mode: current mode timings
  * @hwmode: mode timings as programmed to hw regs
- * @invert_dimensions: for purposes of error checking crtc vs fb sizes,
- *    invert the width/height of the crtc.  This is used if the driver
- *    is performing 90 or 270 degree rotated scanout
- * @x: x position on screen
- * @y: y position on screen
  * @funcs: CRTC control functions
  * @gamma_size: size of gamma ramp
  * @gamma_store: gamma ramp values
@@ -418,6 +449,8 @@ struct drm_crtc {
 	struct drm_device *dev;
 	struct list_head head;
 
+	int id;
+
 	/**
 	 * crtc mutex
 	 *
@@ -429,8 +462,7 @@ struct drm_crtc {
 
 	struct drm_mode_object base;
 
-	/* framebuffer the connector is currently bound to */
-	struct drm_framebuffer *fb;
+	struct drm_crtc_state *state;
 
 	/* Temporary tracking of the old fb while a modeset is ongoing. Used
 	 * by drm_mode_set_config_internal to implement correct refcounting. */
@@ -438,17 +470,11 @@ struct drm_crtc {
 
 	bool enabled;
 
-	/* Requested mode from modesetting. */
-	struct drm_display_mode mode;
-
 	/* Programmed mode in hw, after adjustments for encoders,
 	 * crtc, panel scaling etc. Needed for timestamping etc.
 	 */
 	struct drm_display_mode hwmode;
 
-	bool invert_dimensions;
-
-	int x, y;
 	const struct drm_crtc_funcs *funcs;
 
 	/* CRTC gamma size for reporting to userspace */
@@ -462,7 +488,15 @@ struct drm_crtc {
 	void *helper_private;
 
 	struct drm_object_properties properties;
-	struct drm_object_property_values propvals;
+
+	/* These are (temporary) duplicate information from what is in the
+	 * drm_crtc_state struct..  keeping duplicate copy here makes the
+	 * switch to atomic far less intrusive.  Once all the drivers and
+	 * the crtc/fb helpers are updated, then we can remove these:
+	 */
+	struct drm_framebuffer *fb;
+	int x, y;
+	struct drm_display_mode mode;
 };
 
 
@@ -939,6 +973,8 @@ struct drm_mode_config {
 	struct drm_property *prop_crtc_h;
 	struct drm_property *prop_fb_id;
 	struct drm_property *prop_crtc_id;
+	struct drm_property *prop_connector_ids;
+	struct drm_property *prop_mode;
 	struct drm_property *edid_property;
 	struct drm_property *dpms_property;
 
@@ -994,6 +1030,14 @@ extern int drm_crtc_init(struct drm_device *dev,
 			 struct drm_crtc *crtc,
 			 const struct drm_crtc_funcs *funcs);
 extern void drm_crtc_cleanup(struct drm_crtc *crtc);
+extern int drm_crtc_check_state(struct drm_crtc *crtc,
+		struct drm_crtc_state *state);
+extern void drm_crtc_commit_state(struct drm_crtc *crtc,
+		struct drm_crtc_state *state);
+extern int drm_crtc_set_property(struct drm_crtc *crtc,
+		struct drm_crtc_state *state,
+		struct drm_property *property,
+		uint64_t value, void *blob_data);
 
 extern void drm_connector_ida_init(void);
 extern void drm_connector_ida_destroy(void);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFCv1 11/12] drm: Atomic modeset ioctl
  2013-10-06  0:45 [RFCv1 00/12] Atomic/nuclear modeset/pageflip Rob Clark
                   ` (9 preceding siblings ...)
  2013-10-06  0:45 ` [RFCv1 10/12] drm: convert crtc " Rob Clark
@ 2013-10-06  0:45 ` Rob Clark
  2013-10-07 13:28   ` Ville Syrjälä
  2013-10-06  0:45 ` [RFCv1 12/12] ARM: add get_user() support for 8 byte types Rob Clark
  11 siblings, 1 reply; 38+ messages in thread
From: Rob Clark @ 2013-10-06  0:45 UTC (permalink / raw)
  To: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

The atomic modeset ioctl cna be used to push any number of new values
for object properties. The driver can then check the full device
configuration as single unit, and try to apply the changes atomically.

The ioctl simply takes a list of object IDs and property IDs and their
values. For setting values to blob properties, the property value
indicates the length of the data, and the actual data is passed via
another blob pointer.

The caller can demand non-blocking operation from the ioctl, and if the
driver can't satisfy that requirement an error will be returned.

The caller can also request to receive asynchronous completion events
after the operation has reached the hardware. An event is sent for each
object specified by the caller, whether or not the actual state of
that object changed. Each event also carries a framebuffer ID, which
indicates to user space that the specified object is no longer
accessing that framebuffer.

TODO: detailed error reporting?

v1: original
v2: rebase on uapi changes, and drm state structs.. -- Rob Clark
v3: rebase, missing padding in drm_event_atomic.. -- Rob Clark

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_crtc.c  | 159 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_drv.c   |   1 +
 include/drm/drmP.h          |   6 ++
 include/drm/drm_crtc.h      |   2 +
 include/uapi/drm/drm.h      |  12 ++++
 include/uapi/drm/drm_mode.h |  16 +++++
 6 files changed, 196 insertions(+)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 09396a9..910e5c6 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -4338,3 +4338,162 @@ void drm_mode_config_cleanup(struct drm_device *dev)
 	idr_destroy(&dev->mode_config.crtc_idr);
 }
 EXPORT_SYMBOL(drm_mode_config_cleanup);
+
+int drm_mode_atomic_ioctl(struct drm_device *dev,
+			  void *data, struct drm_file *file_priv)
+{
+	struct drm_mode_atomic *arg = data;
+	uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
+	uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
+	uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
+	uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
+	uint64_t __user *blob_values_ptr = (uint64_t __user *)(unsigned long)(arg->blob_values_ptr);
+	unsigned int copied_objs = 0;
+	unsigned int copied_props = 0;
+	unsigned int copied_blobs = 0;
+	void *state;
+	int ret = 0;
+	unsigned int i, j;
+
+	if (arg->flags & ~(DRM_MODE_ATOMIC_TEST_ONLY |
+			DRM_MODE_ATOMIC_EVENT | DRM_MODE_ATOMIC_NONBLOCK))
+		return -EINVAL;
+
+	/* can't test and expect an event at the same time. */
+	if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
+			(arg->flags & DRM_MODE_ATOMIC_EVENT))
+		return -EINVAL;
+
+	mutex_lock(&dev->mode_config.mutex);
+
+	state = dev->driver->atomic_begin(dev, arg->flags);
+	if (IS_ERR(state)) {
+		ret = PTR_ERR(state);
+		goto unlock;
+	}
+
+	for (i = 0; i < arg->count_objs; i++) {
+		uint32_t obj_id, count_props;
+		struct drm_mode_object *obj;
+
+		if (get_user(obj_id, objs_ptr + copied_objs)) {
+			ret = -EFAULT;
+			goto out;
+		}
+
+		obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY);
+		if (!obj || !obj->properties) {
+			ret = -ENOENT;
+			goto out;
+		}
+
+		if (arg->flags & DRM_MODE_ATOMIC_EVENT) {
+			// XXX create atomic event instead..
+			struct drm_pending_vblank_event *e =
+				create_vblank_event(dev, file_priv, arg->user_data);
+			if (!e) {
+				ret = -ENOMEM;
+				goto out;
+			}
+			ret = dev->driver->atomic_set_event(dev, state, obj, e);
+			if (ret) {
+				destroy_vblank_event(dev, file_priv, e);
+				goto out;
+			}
+		}
+
+		if (get_user(count_props, count_props_ptr + copied_objs)) {
+			ret = -EFAULT;
+			goto out;
+		}
+
+		copied_objs++;
+
+		for (j = 0; j < count_props; j++) {
+			uint32_t prop_id;
+			uint64_t prop_value;
+			struct drm_mode_object *prop_obj;
+			struct drm_property *prop;
+			void *blob_data = NULL;
+
+			if (get_user(prop_id, props_ptr + copied_props)) {
+				ret = -EFAULT;
+				goto out;
+			}
+
+			if (!object_has_prop(obj, prop_id)) {
+				ret = -EINVAL;
+				goto out;
+			}
+
+			prop_obj = drm_mode_object_find(dev, prop_id,
+					DRM_MODE_OBJECT_PROPERTY);
+			if (!prop_obj) {
+				ret = -ENOENT;
+				goto out;
+			}
+			prop = obj_to_property(prop_obj);
+
+			if (get_user(prop_value, prop_values_ptr + copied_props)) {
+				ret = -EFAULT;
+				goto out;
+			}
+
+			if (!drm_property_change_is_valid(prop, prop_value)) {
+				ret = -EINVAL;
+				goto out;
+			}
+
+			if ((prop->flags & DRM_MODE_PROP_BLOB) && prop_value) {
+				uint64_t blob_ptr;
+
+				if (get_user(blob_ptr, blob_values_ptr + copied_blobs)) {
+					ret = -EFAULT;
+					goto out;
+				}
+
+				blob_data = kmalloc(prop_value, GFP_KERNEL);
+				if (!blob_data) {
+					ret = -ENOMEM;
+					goto out;
+				}
+
+				if (copy_from_user(blob_data, (void __user *)(unsigned long)blob_ptr, prop_value)) {
+					kfree(blob_data);
+					ret = -EFAULT;
+					goto out;
+				}
+			}
+
+			/* User space sends the blob pointer even if we
+			 * don't use it (length==0).
+			 */
+			if (prop->flags & DRM_MODE_PROP_BLOB)
+				copied_blobs++;
+
+			/* The driver will be in charge of blob_data from now on. */
+			ret = drm_mode_set_obj_prop(obj, state, prop,
+					prop_value, blob_data);
+			if (ret)
+				goto out;
+
+			copied_props++;
+		}
+	}
+
+	ret = dev->driver->atomic_check(dev, state);
+	if (ret)
+		goto out;
+
+	if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
+		goto out;
+
+	ret = dev->driver->atomic_commit(dev, state);
+
+ out:
+	dev->driver->atomic_end(dev, state);
+ unlock:
+	mutex_unlock(&dev->mode_config.mutex);
+
+	return ret;
+}
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index e572dd2..43e04ae 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -166,6 +166,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 };
 
 #define DRM_CORE_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls )
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 4c3de22..f282733 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -1158,6 +1158,12 @@ struct drm_pending_vblank_event {
 	struct drm_event_vblank event;
 };
 
+struct drm_pending_atomic_event {
+	struct drm_pending_event base;
+	int pipe;
+	struct drm_event_atomic event;
+};
+
 /**
  * DRM device structure. This structure represent a complete card that
  * may contain multiple heads.
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 86a5a00..fa3956e 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -1313,6 +1313,8 @@ extern int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
 					     struct drm_file *file_priv);
 extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
 					   struct drm_file *file_priv);
+extern int drm_mode_atomic_ioctl(struct drm_device *dev,
+				 void *data, struct drm_file *file_priv);
 
 extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
 				 int *bpp);
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index ece8678..efb1461 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -733,6 +733,7 @@ struct drm_prime_handle {
 #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES	DRM_IOWR(0xB9, struct drm_mode_obj_get_properties)
 #define DRM_IOCTL_MODE_OBJ_SETPROPERTY	DRM_IOWR(0xBA, struct drm_mode_obj_set_property)
 #define DRM_IOCTL_MODE_CURSOR2		DRM_IOWR(0xBB, struct drm_mode_cursor2)
+#define DRM_IOCTL_MODE_ATOMIC		DRM_IOWR(0xBC, struct drm_mode_atomic)
 
 /**
  * Device specific ioctls should only be in their respective headers
@@ -774,6 +775,17 @@ struct drm_event_vblank {
 	__u32 reserved;
 };
 
+struct drm_event_atomic {
+	struct drm_event base;
+	__u64 user_data;
+	__u32 tv_sec;
+	__u32 tv_usec;
+	__u32 sequence;
+	__u32 obj_id;
+	__u32 old_fb_id;
+	__u32 reserved;
+};
+
 #define DRM_CAP_DUMB_BUFFER 0x1
 #define DRM_CAP_VBLANK_HIGH_CRTC 0x2
 #define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index 6d4f089..03a473c 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -489,4 +489,20 @@ struct drm_mode_destroy_dumb {
 	uint32_t handle;
 };
 
+#define DRM_MODE_ATOMIC_TEST_ONLY (1<<0)
+#define DRM_MODE_ATOMIC_EVENT (1<<1)
+#define DRM_MODE_ATOMIC_NONBLOCK (1<<2)
+
+/* FIXME come up with some sane error reporting mechanism? */
+struct drm_mode_atomic {
+	__u32 flags;
+	__u32 count_objs;
+	__u64 objs_ptr;
+	__u64 count_props_ptr;
+	__u64 props_ptr;
+	__u64 prop_values_ptr;
+	__u64 blob_values_ptr;
+	__u64 user_data;
+};
+
 #endif
-- 
1.8.3.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFCv1 12/12] ARM: add get_user() support for 8 byte types
  2013-10-06  0:45 [RFCv1 00/12] Atomic/nuclear modeset/pageflip Rob Clark
                   ` (10 preceding siblings ...)
  2013-10-06  0:45 ` [RFCv1 11/12] drm: Atomic modeset ioctl Rob Clark
@ 2013-10-06  0:45 ` Rob Clark
  2013-10-06  8:53   ` Russell King - ARM Linux
  11 siblings, 1 reply; 38+ messages in thread
From: Rob Clark @ 2013-10-06  0:45 UTC (permalink / raw)
  To: dri-devel; +Cc: Russell King - ARM Linux

A new atomic modeset/pageflip ioctl being developed in DRM requires
get_user() to work for 64bit types (in addition to just put_user()).

v1: original
v2: pass correct size to check_uaccess, and better handling of narrowing
    double word read with __get_user_xb() (Russell King's suggestion)

Signed-off-by: Rob Clark <robdclark@gmail.com>
Cc: Russell King - ARM Linux <linux@arm.linux.org.uk>
---
 arch/arm/include/asm/uaccess.h | 18 +++++++++++++++++-
 arch/arm/lib/getuser.S         | 17 ++++++++++++++++-
 2 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h
index 72abdc5..c54fdce 100644
--- a/arch/arm/include/asm/uaccess.h
+++ b/arch/arm/include/asm/uaccess.h
@@ -107,6 +107,7 @@ static inline void set_fs(mm_segment_t fs)
 extern int __get_user_1(void *);
 extern int __get_user_2(void *);
 extern int __get_user_4(void *);
+extern int __get_user_8(void *);
 
 #define __GUP_CLOBBER_1	"lr", "cc"
 #ifdef CONFIG_CPU_USE_DOMAINS
@@ -115,6 +116,7 @@ extern int __get_user_4(void *);
 #define __GUP_CLOBBER_2 "lr", "cc"
 #endif
 #define __GUP_CLOBBER_4	"lr", "cc"
+#define __GUP_CLOBBER_8	"lr", "cc"
 
 #define __get_user_x(__r2,__p,__e,__l,__s)				\
 	   __asm__ __volatile__ (					\
@@ -125,11 +127,19 @@ extern int __get_user_4(void *);
 		: "0" (__p), "r" (__l)					\
 		: __GUP_CLOBBER_##__s)
 
+/* narrowing a double-word get into a single 32bit word register: */
+#ifdef BIG_ENDIAN
+#define __get_user_xb(__r2,__p,__e,__l,__s)				\
+	__get_user_x(__r2,(uintptr_t)__p + 4,__e,__l,__s)
+#else
+#define __get_user_xb __get_user_x
+#endif
+
 #define __get_user_check(x,p)							\
 	({								\
 		unsigned long __limit = current_thread_info()->addr_limit - 1; \
 		register const typeof(*(p)) __user *__p asm("r0") = (p);\
-		register unsigned long __r2 asm("r2");			\
+		register typeof(x) __r2 asm("r2");			\
 		register unsigned long __l asm("r1") = __limit;		\
 		register int __e asm("r0");				\
 		switch (sizeof(*(__p))) {				\
@@ -142,6 +152,12 @@ extern int __get_user_4(void *);
 		case 4:							\
 			__get_user_x(__r2, __p, __e, __l, 4);		\
 			break;						\
+		case 8:							\
+			if (sizeof((x)) < 8)				\
+				__get_user_xb(__r2, __p, __e, __l, 4);	\
+			else						\
+				__get_user_x(__r2, __p, __e, __l, 8);	\
+			break;						\
 		default: __e = __get_user_bad(); break;			\
 		}							\
 		x = (typeof(*(p))) __r2;				\
diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S
index 9b06bb4..ed98707 100644
--- a/arch/arm/lib/getuser.S
+++ b/arch/arm/lib/getuser.S
@@ -18,7 +18,7 @@
  * Inputs:	r0 contains the address
  *		r1 contains the address limit, which must be preserved
  * Outputs:	r0 is the error code
- *		r2 contains the zero-extended value
+ *		r2, r3 contains the zero-extended value
  *		lr corrupted
  *
  * No other registers must be altered.  (see <asm/uaccess.h>
@@ -66,6 +66,19 @@ ENTRY(__get_user_4)
 	mov	pc, lr
 ENDPROC(__get_user_4)
 
+ENTRY(__get_user_8)
+	check_uaccess r0, 8, r1, r2, __get_user_bad
+#ifdef CONFIG_THUMB2_KERNEL
+5: TUSER(ldr)	r2, [r0]
+6: TUSER(ldr)	r3, [r0, #4]
+#else
+5: TUSER(ldr)	r2, [r0], #4
+6: TUSER(ldr)	r3, [r0]
+#endif
+	mov	r0, #0
+	mov	pc, lr
+ENDPROC(__get_user_8)
+
 __get_user_bad:
 	mov	r2, #0
 	mov	r0, #-EFAULT
@@ -77,4 +90,6 @@ ENDPROC(__get_user_bad)
 	.long	2b, __get_user_bad
 	.long	3b, __get_user_bad
 	.long	4b, __get_user_bad
+	.long	5b, __get_user_bad
+	.long	6b, __get_user_bad
 .popsection
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [RFCv1 05/12] drm: helpers to find mode objects (BEFORE drm: split property values out)
  2013-10-06  0:45 ` [RFCv1 05/12] drm: helpers to find mode objects (BEFORE drm: split property values out) Rob Clark
@ 2013-10-06  0:48   ` Rob Clark
  0 siblings, 0 replies; 38+ messages in thread
From: Rob Clark @ 2013-10-06  0:48 UTC (permalink / raw)
  To: dri-devel

Oh, and this one was half stolen from rmk's Armada driver with a
couple extra helper's that I needed added

BR,
-R

On Sat, Oct 5, 2013 at 8:45 PM, Rob Clark <robdclark@gmail.com> wrote:
> ---
>  include/drm/drm_crtc.h | 40 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 40 insertions(+)
>
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index e042d12..0ea61b3 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -1067,6 +1067,46 @@ drm_property_get_obj(struct drm_property *property, uint64_t value)
>         return drm_mode_object_find(property->dev, value, property->values[0]);
>  }
>
> +static inline struct drm_plane *drm_plane_find(struct drm_device *dev,
> +               uint32_t id)
> +{
> +       struct drm_mode_object *mo;
> +       mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PLANE);
> +       return mo ? obj_to_plane(mo) : NULL;
> +}
> +
> +static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev,
> +               uint32_t id)
> +{
> +       struct drm_mode_object *mo;
> +       mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_CRTC);
> +       return mo ? obj_to_crtc(mo) : NULL;
> +}
> +
> +static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev,
> +               uint32_t id)
> +{
> +       struct drm_mode_object *mo;
> +       mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER);
> +       return mo ? obj_to_encoder(mo) : NULL;
> +}
> +
> +static inline struct drm_connector *drm_connector_find(struct drm_device *dev,
> +               uint32_t id)
> +{
> +       struct drm_mode_object *mo;
> +       mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_CONNECTOR);
> +       return mo ? obj_to_connector(mo) : NULL;
> +}
> +
> +static inline struct drm_property_blob *
> +drm_property_blob_find(struct drm_device *dev, uint32_t id)
> +{
> +       struct drm_mode_object *mo;
> +       mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_BLOB);
> +       return mo ? obj_to_blob(mo) : NULL;
> +}
> +
>  /* IOCTLs */
>  extern int drm_mode_getresources(struct drm_device *dev,
>                                  void *data, struct drm_file *file_priv);
> --
> 1.8.3.1
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 12/12] ARM: add get_user() support for 8 byte types
  2013-10-06  0:45 ` [RFCv1 12/12] ARM: add get_user() support for 8 byte types Rob Clark
@ 2013-10-06  8:53   ` Russell King - ARM Linux
  2013-10-06 14:09     ` Rob Clark
  0 siblings, 1 reply; 38+ messages in thread
From: Russell King - ARM Linux @ 2013-10-06  8:53 UTC (permalink / raw)
  To: Rob Clark; +Cc: dri-devel

On Sat, Oct 05, 2013 at 08:45:50PM -0400, Rob Clark wrote:
> A new atomic modeset/pageflip ioctl being developed in DRM requires
> get_user() to work for 64bit types (in addition to just put_user()).
> 
> v1: original
> v2: pass correct size to check_uaccess, and better handling of narrowing
>     double word read with __get_user_xb() (Russell King's suggestion)

I thought we had decided not to support this for 32-bit because x86_32
had problems here as well:

#ifdef CONFIG_X86_32
#define __get_user_asm_u64(x, ptr, retval, errret)      (x) = __get_user_bad()
#define __get_user_asm_ex_u64(x, ptr)                   (x) = __get_user_bad()
#else
#define __get_user_asm_u64(x, ptr, retval, errret) \
         __get_user_asm(x, ptr, retval, "q", "", "=r", errret)
#define __get_user_asm_ex_u64(x, ptr) \
         __get_user_asm_ex(x, ptr, "q", "", "=r")
#endif

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 12/12] ARM: add get_user() support for 8 byte types
  2013-10-06  8:53   ` Russell King - ARM Linux
@ 2013-10-06 14:09     ` Rob Clark
  2013-10-06 15:56       ` Russell King - ARM Linux
  0 siblings, 1 reply; 38+ messages in thread
From: Rob Clark @ 2013-10-06 14:09 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: dri-devel

On Sun, Oct 6, 2013 at 4:53 AM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Sat, Oct 05, 2013 at 08:45:50PM -0400, Rob Clark wrote:
>> A new atomic modeset/pageflip ioctl being developed in DRM requires
>> get_user() to work for 64bit types (in addition to just put_user()).
>>
>> v1: original
>> v2: pass correct size to check_uaccess, and better handling of narrowing
>>     double word read with __get_user_xb() (Russell King's suggestion)
>
> I thought we had decided not to support this for 32-bit because x86_32
> had problems here as well:

I don't remember.. actually I didn't even realize it wasn't merged
until I tried to build with the atomic modeset ioctl.

Ville did have a patch to add it for x86_32, and that patch appears to
be merged (96477b4c), so I just assume it wasn't removed since then.

BR,
-R

> #ifdef CONFIG_X86_32
> #define __get_user_asm_u64(x, ptr, retval, errret)      (x) = __get_user_bad()
> #define __get_user_asm_ex_u64(x, ptr)                   (x) = __get_user_bad()
> #else
> #define __get_user_asm_u64(x, ptr, retval, errret) \
>          __get_user_asm(x, ptr, retval, "q", "", "=r", errret)
> #define __get_user_asm_ex_u64(x, ptr) \
>          __get_user_asm_ex(x, ptr, "q", "", "=r")
> #endif
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 12/12] ARM: add get_user() support for 8 byte types
  2013-10-06 14:09     ` Rob Clark
@ 2013-10-06 15:56       ` Russell King - ARM Linux
  0 siblings, 0 replies; 38+ messages in thread
From: Russell King - ARM Linux @ 2013-10-06 15:56 UTC (permalink / raw)
  To: Rob Clark; +Cc: dri-devel

On Sun, Oct 06, 2013 at 10:09:34AM -0400, Rob Clark wrote:
> On Sun, Oct 6, 2013 at 4:53 AM, Russell King - ARM Linux
> <linux@arm.linux.org.uk> wrote:
> > On Sat, Oct 05, 2013 at 08:45:50PM -0400, Rob Clark wrote:
> >> A new atomic modeset/pageflip ioctl being developed in DRM requires
> >> get_user() to work for 64bit types (in addition to just put_user()).
> >>
> >> v1: original
> >> v2: pass correct size to check_uaccess, and better handling of narrowing
> >>     double word read with __get_user_xb() (Russell King's suggestion)
> >
> > I thought we had decided not to support this for 32-bit because x86_32
> > had problems here as well:
> 
> I don't remember.. actually I didn't even realize it wasn't merged
> until I tried to build with the atomic modeset ioctl.
> 
> Ville did have a patch to add it for x86_32, and that patch appears to
> be merged (96477b4c), so I just assume it wasn't removed since then.

Okay, the code I quoted is for __get_user() not get_user().

This is roughly what we (hpa/myself) came up with for ARM which did get
things working, but itw as x86 which made us decide not to persue this.
I've added the __get_user_8 implementation to this.  The __inttype()
thing was hpa's idea.

 arch/arm/include/asm/uaccess.h |   17 +++++++++++++----
 arch/arm/lib/getuser.S         |   33 ++++++++++++++++++++++++++++++++-
 2 files changed, 45 insertions(+), 5 deletions(-)

diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h
index 72abdc5..747f2cb 100644
--- a/arch/arm/include/asm/uaccess.h
+++ b/arch/arm/include/asm/uaccess.h
@@ -93,6 +93,9 @@ static inline void set_fs(mm_segment_t fs)
 		: "cc"); \
 	flag; })
 
+#define __inttype(x) \
+	__typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
+
 /*
  * Single-value transfer routines.  They automatically use the right
  * size if we just have the right pointer type.  Note that the functions
@@ -107,14 +110,16 @@ static inline void set_fs(mm_segment_t fs)
 extern int __get_user_1(void *);
 extern int __get_user_2(void *);
 extern int __get_user_4(void *);
+extern int __get_user_8(void *);
 
-#define __GUP_CLOBBER_1	"lr", "cc"
+#define __GUP_CLOBBER_1 "lr", "cc"
 #ifdef CONFIG_CPU_USE_DOMAINS
-#define __GUP_CLOBBER_2	"ip", "lr", "cc"
+#define __GUP_CLOBBER_2 "ip", "lr", "cc"
 #else
 #define __GUP_CLOBBER_2 "lr", "cc"
 #endif
-#define __GUP_CLOBBER_4	"lr", "cc"
+#define __GUP_CLOBBER_4 "lr", "cc"
+#define __GUP_CLOBBER_8 "lr", "cc"
 
 #define __get_user_x(__r2,__p,__e,__l,__s)				\
 	   __asm__ __volatile__ (					\
@@ -129,7 +134,7 @@ extern int __get_user_4(void *);
 	({								\
 		unsigned long __limit = current_thread_info()->addr_limit - 1; \
 		register const typeof(*(p)) __user *__p asm("r0") = (p);\
-		register unsigned long __r2 asm("r2");			\
+		register __inttype(*p) __r2 asm("r2");			\
 		register unsigned long __l asm("r1") = __limit;		\
 		register int __e asm("r0");				\
 		switch (sizeof(*(__p))) {				\
@@ -142,6 +147,9 @@ extern int __get_user_4(void *);
 		case 4:							\
 			__get_user_x(__r2, __p, __e, __l, 4);		\
 			break;						\
+		case 8:							\
+			__get_user_x(__r2, __p, __e, __l, 8);		\
+			break;						\
 		default: __e = __get_user_bad(); break;			\
 		}							\
 		x = (typeof(*(p))) __r2;				\
@@ -150,6 +158,7 @@ extern int __get_user_4(void *);
 
 #define get_user(x,p)							\
 	({								\
+		__chk_user_ptr(ptr);					\
 		might_fault();						\
 		__get_user_check(x,p);					\
 	 })
diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S
index 9b06bb4..3583c83 100644
--- a/arch/arm/lib/getuser.S
+++ b/arch/arm/lib/getuser.S
@@ -18,7 +18,7 @@
  * Inputs:	r0 contains the address
  *		r1 contains the address limit, which must be preserved
  * Outputs:	r0 is the error code
- *		r2 contains the zero-extended value
+ *		r2/r3 contains the zero-extended value
  *		lr corrupted
  *
  * No other registers must be altered.  (see <asm/uaccess.h>
@@ -32,6 +32,14 @@
 #include <asm/errno.h>
 #include <asm/domain.h>
 
+#ifdef __ARMEB__
+#define rlo8	r3
+#define rhi8	r2
+#else
+#define	rlo8	r2
+#define rhi8	r3
+#endif
+
 ENTRY(__get_user_1)
 	check_uaccess r0, 1, r1, r2, __get_user_bad
 1: TUSER(ldrb)	r2, [r0]
@@ -66,15 +74,38 @@ ENTRY(__get_user_4)
 	mov	pc, lr
 ENDPROC(__get_user_4)
 
+ENTRY(__get_user_8)
+	check_uaccess r0, 4, r1, r2, __get_user_bad8
+#ifdef CONFIG_CPU_USE_DOMAINS
+#define	GU8_FIXUPS	5b, 6b
+5:	ldrt	rlo8, [r0], #4
+6:	ldrt	rhi8, [r0], #0
+#elif __LINUX_ARM_ARCH__ >= 6
+#define	GU8_FIXUPS	5b
+5:	ldrd	r2, [r0]
+#else
+#define	GU8_FIXUPS	5b, 6b
+5:	ldr	rlo8, [r0, #0]
+6:	ldr	rhi8, [r0, #4]
+#endif
+	mov	r0, #0
+	mov	pc, lr
+
+__get_user_bad8:
+	mov	r3, #0
 __get_user_bad:
 	mov	r2, #0
 	mov	r0, #-EFAULT
 	mov	pc, lr
 ENDPROC(__get_user_bad)
+ENDPROC(__get_user_bad8)
 
 .pushsection __ex_table, "a"
 	.long	1b, __get_user_bad
 	.long	2b, __get_user_bad
 	.long	3b, __get_user_bad
 	.long	4b, __get_user_bad
+	.irp	param, GU8_FIXUPS
+	.long	\param, __get_user_bad8
+	.endr
 .popsection

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [RFCv1 11/12] drm: Atomic modeset ioctl
  2013-10-06  0:45 ` [RFCv1 11/12] drm: Atomic modeset ioctl Rob Clark
@ 2013-10-07 13:28   ` Ville Syrjälä
  2013-10-07 13:55     ` Rob Clark
  0 siblings, 1 reply; 38+ messages in thread
From: Ville Syrjälä @ 2013-10-07 13:28 UTC (permalink / raw)
  To: Rob Clark; +Cc: dri-devel

On Sat, Oct 05, 2013 at 08:45:49PM -0400, Rob Clark wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> The atomic modeset ioctl cna be used to push any number of new values
> for object properties. The driver can then check the full device
> configuration as single unit, and try to apply the changes atomically.
> 
> The ioctl simply takes a list of object IDs and property IDs and their
> values. For setting values to blob properties, the property value
> indicates the length of the data, and the actual data is passed via
> another blob pointer.
> 
> The caller can demand non-blocking operation from the ioctl, and if the
> driver can't satisfy that requirement an error will be returned.
> 
> The caller can also request to receive asynchronous completion events
> after the operation has reached the hardware. An event is sent for each
> object specified by the caller, whether or not the actual state of
> that object changed. Each event also carries a framebuffer ID, which
> indicates to user space that the specified object is no longer
> accessing that framebuffer.
> 
> TODO: detailed error reporting?
> 
> v1: original
> v2: rebase on uapi changes, and drm state structs.. -- Rob Clark
> v3: rebase, missing padding in drm_event_atomic.. -- Rob Clark
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/drm_crtc.c  | 159 ++++++++++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_drv.c   |   1 +
>  include/drm/drmP.h          |   6 ++
>  include/drm/drm_crtc.h      |   2 +
>  include/uapi/drm/drm.h      |  12 ++++
>  include/uapi/drm/drm_mode.h |  16 +++++
>  6 files changed, 196 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index 09396a9..910e5c6 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -4338,3 +4338,162 @@ void drm_mode_config_cleanup(struct drm_device *dev)
>  	idr_destroy(&dev->mode_config.crtc_idr);
>  }
>  EXPORT_SYMBOL(drm_mode_config_cleanup);
> +
> +int drm_mode_atomic_ioctl(struct drm_device *dev,
> +			  void *data, struct drm_file *file_priv)
> +{
> +	struct drm_mode_atomic *arg = data;
> +	uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
> +	uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
> +	uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
> +	uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
> +	uint64_t __user *blob_values_ptr = (uint64_t __user *)(unsigned long)(arg->blob_values_ptr);
> +	unsigned int copied_objs = 0;
> +	unsigned int copied_props = 0;
> +	unsigned int copied_blobs = 0;
> +	void *state;
> +	int ret = 0;
> +	unsigned int i, j;
> +
> +	if (arg->flags & ~(DRM_MODE_ATOMIC_TEST_ONLY |
> +			DRM_MODE_ATOMIC_EVENT | DRM_MODE_ATOMIC_NONBLOCK))
> +		return -EINVAL;
> +
> +	/* can't test and expect an event at the same time. */
> +	if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
> +			(arg->flags & DRM_MODE_ATOMIC_EVENT))
> +		return -EINVAL;
> +
> +	mutex_lock(&dev->mode_config.mutex);

I'm pretty sure I had a version w/ fixed locking...

git://gitorious.org/vsyrjala/linux.git rebased_drm_atomic_24

> +
> +	state = dev->driver->atomic_begin(dev, arg->flags);
> +	if (IS_ERR(state)) {
> +		ret = PTR_ERR(state);
> +		goto unlock;
> +	}
> +
> +	for (i = 0; i < arg->count_objs; i++) {
> +		uint32_t obj_id, count_props;
> +		struct drm_mode_object *obj;
> +
> +		if (get_user(obj_id, objs_ptr + copied_objs)) {
> +			ret = -EFAULT;
> +			goto out;
> +		}
> +
> +		obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY);
> +		if (!obj || !obj->properties) {
> +			ret = -ENOENT;
> +			goto out;
> +		}
> +
> +		if (arg->flags & DRM_MODE_ATOMIC_EVENT) {
> +			// XXX create atomic event instead..

Some people are apparently more comfortable with a per-crtc event
rather than the per-obj events I added. So I think we might want
both in the end.

> +			struct drm_pending_vblank_event *e =
> +				create_vblank_event(dev, file_priv, arg->user_data);
> +			if (!e) {
> +				ret = -ENOMEM;
> +				goto out;
> +			}
> +			ret = dev->driver->atomic_set_event(dev, state, obj, e);
> +			if (ret) {
> +				destroy_vblank_event(dev, file_priv, e);
> +				goto out;
> +			}
> +		}
> +
> +		if (get_user(count_props, count_props_ptr + copied_objs)) {
> +			ret = -EFAULT;
> +			goto out;
> +		}
> +
> +		copied_objs++;
> +
> +		for (j = 0; j < count_props; j++) {
> +			uint32_t prop_id;
> +			uint64_t prop_value;
> +			struct drm_mode_object *prop_obj;
> +			struct drm_property *prop;
> +			void *blob_data = NULL;
> +
> +			if (get_user(prop_id, props_ptr + copied_props)) {
> +				ret = -EFAULT;
> +				goto out;
> +			}
> +
> +			if (!object_has_prop(obj, prop_id)) {
> +				ret = -EINVAL;
> +				goto out;
> +			}
> +
> +			prop_obj = drm_mode_object_find(dev, prop_id,
> +					DRM_MODE_OBJECT_PROPERTY);
> +			if (!prop_obj) {
> +				ret = -ENOENT;
> +				goto out;
> +			}
> +			prop = obj_to_property(prop_obj);
> +
> +			if (get_user(prop_value, prop_values_ptr + copied_props)) {
> +				ret = -EFAULT;
> +				goto out;
> +			}
> +
> +			if (!drm_property_change_is_valid(prop, prop_value)) {
> +				ret = -EINVAL;
> +				goto out;
> +			}
> +
> +			if ((prop->flags & DRM_MODE_PROP_BLOB) && prop_value) {
> +				uint64_t blob_ptr;
> +
> +				if (get_user(blob_ptr, blob_values_ptr + copied_blobs)) {
> +					ret = -EFAULT;
> +					goto out;
> +				}
> +
> +				blob_data = kmalloc(prop_value, GFP_KERNEL);
> +				if (!blob_data) {
> +					ret = -ENOMEM;
> +					goto out;
> +				}
> +
> +				if (copy_from_user(blob_data, (void __user *)(unsigned long)blob_ptr, prop_value)) {
> +					kfree(blob_data);
> +					ret = -EFAULT;
> +					goto out;
> +				}
> +			}
> +
> +			/* User space sends the blob pointer even if we
> +			 * don't use it (length==0).
> +			 */
> +			if (prop->flags & DRM_MODE_PROP_BLOB)
> +				copied_blobs++;
> +
> +			/* The driver will be in charge of blob_data from now on. */
> +			ret = drm_mode_set_obj_prop(obj, state, prop,
> +					prop_value, blob_data);
> +			if (ret)
> +				goto out;
> +
> +			copied_props++;
> +		}
> +	}
> +
> +	ret = dev->driver->atomic_check(dev, state);
> +	if (ret)
> +		goto out;
> +
> +	if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
> +		goto out;
> +
> +	ret = dev->driver->atomic_commit(dev, state);
> +
> + out:
> +	dev->driver->atomic_end(dev, state);
> + unlock:
> +	mutex_unlock(&dev->mode_config.mutex);
> +
> +	return ret;
> +}
> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
> index e572dd2..43e04ae 100644
> --- a/drivers/gpu/drm/drm_drv.c
> +++ b/drivers/gpu/drm/drm_drv.c
> @@ -166,6 +166,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
>  	DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>  	DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>  	DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> +	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>  };
>  
>  #define DRM_CORE_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls )
> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
> index 4c3de22..f282733 100644
> --- a/include/drm/drmP.h
> +++ b/include/drm/drmP.h
> @@ -1158,6 +1158,12 @@ struct drm_pending_vblank_event {
>  	struct drm_event_vblank event;
>  };
>  
> +struct drm_pending_atomic_event {
> +	struct drm_pending_event base;
> +	int pipe;
> +	struct drm_event_atomic event;
> +};
> +
>  /**
>   * DRM device structure. This structure represent a complete card that
>   * may contain multiple heads.
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 86a5a00..fa3956e 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -1313,6 +1313,8 @@ extern int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
>  					     struct drm_file *file_priv);
>  extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
>  					   struct drm_file *file_priv);
> +extern int drm_mode_atomic_ioctl(struct drm_device *dev,
> +				 void *data, struct drm_file *file_priv);
>  
>  extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
>  				 int *bpp);
> diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
> index ece8678..efb1461 100644
> --- a/include/uapi/drm/drm.h
> +++ b/include/uapi/drm/drm.h
> @@ -733,6 +733,7 @@ struct drm_prime_handle {
>  #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES	DRM_IOWR(0xB9, struct drm_mode_obj_get_properties)
>  #define DRM_IOCTL_MODE_OBJ_SETPROPERTY	DRM_IOWR(0xBA, struct drm_mode_obj_set_property)
>  #define DRM_IOCTL_MODE_CURSOR2		DRM_IOWR(0xBB, struct drm_mode_cursor2)
> +#define DRM_IOCTL_MODE_ATOMIC		DRM_IOWR(0xBC, struct drm_mode_atomic)
>  
>  /**
>   * Device specific ioctls should only be in their respective headers
> @@ -774,6 +775,17 @@ struct drm_event_vblank {
>  	__u32 reserved;
>  };
>  
> +struct drm_event_atomic {
> +	struct drm_event base;
> +	__u64 user_data;
> +	__u32 tv_sec;
> +	__u32 tv_usec;
> +	__u32 sequence;
> +	__u32 obj_id;
> +	__u32 old_fb_id;
> +	__u32 reserved;
> +};
> +
>  #define DRM_CAP_DUMB_BUFFER 0x1
>  #define DRM_CAP_VBLANK_HIGH_CRTC 0x2
>  #define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3
> diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
> index 6d4f089..03a473c 100644
> --- a/include/uapi/drm/drm_mode.h
> +++ b/include/uapi/drm/drm_mode.h
> @@ -489,4 +489,20 @@ struct drm_mode_destroy_dumb {
>  	uint32_t handle;
>  };
>  
> +#define DRM_MODE_ATOMIC_TEST_ONLY (1<<0)
> +#define DRM_MODE_ATOMIC_EVENT (1<<1)
> +#define DRM_MODE_ATOMIC_NONBLOCK (1<<2)
> +
> +/* FIXME come up with some sane error reporting mechanism? */
> +struct drm_mode_atomic {
> +	__u32 flags;
> +	__u32 count_objs;
> +	__u64 objs_ptr;
> +	__u64 count_props_ptr;
> +	__u64 props_ptr;
> +	__u64 prop_values_ptr;
> +	__u64 blob_values_ptr;
> +	__u64 user_data;
> +};
> +
>  #endif
> -- 
> 1.8.3.1

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 10/12] drm: convert crtc to properties/state
  2013-10-06  0:45 ` [RFCv1 10/12] drm: convert crtc " Rob Clark
@ 2013-10-07 13:39   ` Ville Syrjälä
  2013-10-07 14:03     ` Rob Clark
  0 siblings, 1 reply; 38+ messages in thread
From: Ville Syrjälä @ 2013-10-07 13:39 UTC (permalink / raw)
  To: Rob Clark; +Cc: dri-devel

On Sat, Oct 05, 2013 at 08:45:48PM -0400, Rob Clark wrote:
> Break the mutable state of a crtc out into a separate structure
> and use atomic properties mechanism to set crtc attributes.  This
> makes it easier to have some helpers for crtc->set_property()
> and for checking for invalid params.  The idea is that individual
> drivers can wrap the state struct in their own struct which adds
> driver specific parameters, for easy build-up of state across
> multiple set_property() calls and for easy atomic commit or roll-
> back.

I'm not sure how we're going to handle the mismatch in the behaviour of
the atomic modeset vs. the current setcrtc.

The problem is that setcrtc ignore all kinds of conflicting
crtc->connector assignments, and just overwrites whatever was there
with the latest configuration. For the atomic case we want to return an
error if there's a conflict. And another thing is the DPMS handling. The
current API forces DPMS on when you do a modeset, but for the atomic
case I want to keep things nice and clean and avoid doing such silly
things.

So I don't think we can simply convert the current modeset codepaths to
call into the atomic code. We basically need another version of the
check function, or another step that happens before .check only in the
setcrtc case which eliminates the conflicts in a way that matches the
current setcrtc behaviour.

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 02/12] drm: add object property type
  2013-10-06  0:45 ` [RFCv1 02/12] drm: add object property type Rob Clark
@ 2013-10-07 13:43   ` Ville Syrjälä
  2013-10-07 14:44     ` Rob Clark
  0 siblings, 1 reply; 38+ messages in thread
From: Ville Syrjälä @ 2013-10-07 13:43 UTC (permalink / raw)
  To: Rob Clark; +Cc: dri-devel

On Sat, Oct 05, 2013 at 08:45:40PM -0400, Rob Clark wrote:
> diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
> index 5508117..35921ba 100644
> --- a/include/uapi/drm/drm_mode.h
> +++ b/include/uapi/drm/drm_mode.h
> @@ -231,6 +231,7 @@ struct drm_mode_get_connector {
>  #define DRM_MODE_PROP_ENUM	(1<<3) /* enumerated type with text strings */
>  #define DRM_MODE_PROP_BLOB	(1<<4)
>  #define DRM_MODE_PROP_BITMASK	(1<<5) /* bitmask of enumerated types */
> +#define DRM_MODE_PROP_OBJECT	(1<<6) /* drm mode object */

This way to using up one bit for each type sucks big time. IIRC we
discussed this at Fosdem and one idea was to leave the current bits as
sort of base types, and reserve a bunch of the other bits to indicate a
sub-type. For instance the new signed range and object ID prop types
could be sub-types of the current range type.

Maybe we should reserve a few more bits for new base types in case we
need them in the future, or just add sometime king DRM_MODE_PROP_MISC,
which is where we'd stick every sub-type that doesn't fit the current
base types.

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 03/12] drm: add DRM_MODE_PROP_DYNAMIC property flag
  2013-10-06  0:45 ` [RFCv1 03/12] drm: add DRM_MODE_PROP_DYNAMIC property flag Rob Clark
@ 2013-10-07 13:46   ` Ville Syrjälä
  2013-10-07 14:46     ` Rob Clark
  0 siblings, 1 reply; 38+ messages in thread
From: Ville Syrjälä @ 2013-10-07 13:46 UTC (permalink / raw)
  To: Rob Clark; +Cc: dri-devel

On Sat, Oct 05, 2013 at 08:45:41PM -0400, Rob Clark wrote:
> This indicates to userspace that the property is something that can
> be set dynamically without requiring a "test" step to check if the
> hw is capable.  This allows a userspace compositor, such as weston,
> to avoid an extra ioctl to check whether it needs to fall-back to
> GPU to composite some surface prior to submission of GPU render
> commands.
> ---
>  include/uapi/drm/drm_mode.h | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
> index 35921ba..15db837 100644
> --- a/include/uapi/drm/drm_mode.h
> +++ b/include/uapi/drm/drm_mode.h
> @@ -232,6 +232,15 @@ struct drm_mode_get_connector {
>  #define DRM_MODE_PROP_BLOB	(1<<4)
>  #define DRM_MODE_PROP_BITMASK	(1<<5) /* bitmask of enumerated types */
>  #define DRM_MODE_PROP_OBJECT	(1<<6) /* drm mode object */
> +/* Properties that are not dynamic cannot safely be changed without a
> + * atomic-modeset / atomic-pageflip test step.  But if userspace is
> + * only changing dynamic properties, it is guaranteed that the change
> + * will not exceed hw limits, so no test step is required.
> + *
> + * Note that fb_id properties are a bit ambiguous.. they of course can
> + * be changed dynamically, assuming the pixel format does not change.
> + */
> +#define DRM_MODE_PROP_DYNAMIC	(1<<24)

I'm still not convinced that this is useful. We can't even flag the FB
ID with this flag since the FB encompasses stride/bpp/etc. parameters
that for sure can't just be changed w/o first checking the new
configuration.

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 08/12] drm: Refactor object property check code
  2013-10-06  0:45 ` [RFCv1 08/12] drm: Refactor object property check code Rob Clark
@ 2013-10-07 13:47   ` Ville Syrjälä
  0 siblings, 0 replies; 38+ messages in thread
From: Ville Syrjälä @ 2013-10-07 13:47 UTC (permalink / raw)
  To: Rob Clark; +Cc: dri-devel

On Sat, Oct 05, 2013 at 08:45:46PM -0400, Rob Clark wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Refactor the code to check whether an object has a specific property
> to a new function.
> 
> v1: original
> v2: rebase on atomic -- Rob Clark
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/drm_crtc.c | 25 ++++++++++++++-----------
>  1 file changed, 14 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index c0546e8..776edf3 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -3374,6 +3374,19 @@ static int drm_mode_set_obj_prop(struct drm_mode_object *obj,
>  	return -EINVAL;
>  }
>  
> +static bool object_has_prop(const struct drm_mode_object *obj, u32 prop_id)
> +{
> +	int i;
> +
> +	if (!obj->properties)
> +		return false;
> +
> +	for (i = 0; i < obj->properties->count; i++)
> +		if (obj->properties->ids[i] == prop_id)
> +			return true;
> +	return false;
> +}
> +
>  /* call with mode_config mutex held */
>  static int drm_mode_set_obj_prop_id(struct drm_device *dev, void *state,
>  		uint32_t obj_id, uint32_t obj_type,
> @@ -3382,19 +3395,9 @@ static int drm_mode_set_obj_prop_id(struct drm_device *dev, void *state,
>  	struct drm_mode_object *arg_obj;
>  	struct drm_mode_object *prop_obj;
>  	struct drm_property *property;
> -	int i;
>  
>  	arg_obj = drm_mode_object_find(dev, obj_id, obj_type);
> -	if (!arg_obj)
> -		return -EINVAL;
> -	if (!arg_obj->properties)
> -		return -EINVAL;
> -
> -	for (i = 0; i < arg_obj->properties->count; i++)
> -		if (arg_obj->properties->ids[i] == prop_id)
> -			break;
> -
> -	if (i == arg_obj->properties->count)
> +	if (!(arg_obj && object_has_prop(arg_obj, prop_id)))
>  		return -EINVAL;

-ENOENT would actually seem more appropriate here.

>  
>  	prop_obj = drm_mode_object_find(dev, prop_id,
> -- 
> 1.8.3.1

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 11/12] drm: Atomic modeset ioctl
  2013-10-07 13:28   ` Ville Syrjälä
@ 2013-10-07 13:55     ` Rob Clark
  2013-10-07 14:18       ` Ville Syrjälä
  0 siblings, 1 reply; 38+ messages in thread
From: Rob Clark @ 2013-10-07 13:55 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: dri-devel

On Mon, Oct 7, 2013 at 9:28 AM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> On Sat, Oct 05, 2013 at 08:45:49PM -0400, Rob Clark wrote:
>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>
>> The atomic modeset ioctl cna be used to push any number of new values
>> for object properties. The driver can then check the full device
>> configuration as single unit, and try to apply the changes atomically.
>>
>> The ioctl simply takes a list of object IDs and property IDs and their
>> values. For setting values to blob properties, the property value
>> indicates the length of the data, and the actual data is passed via
>> another blob pointer.
>>
>> The caller can demand non-blocking operation from the ioctl, and if the
>> driver can't satisfy that requirement an error will be returned.
>>
>> The caller can also request to receive asynchronous completion events
>> after the operation has reached the hardware. An event is sent for each
>> object specified by the caller, whether or not the actual state of
>> that object changed. Each event also carries a framebuffer ID, which
>> indicates to user space that the specified object is no longer
>> accessing that framebuffer.
>>
>> TODO: detailed error reporting?
>>
>> v1: original
>> v2: rebase on uapi changes, and drm state structs.. -- Rob Clark
>> v3: rebase, missing padding in drm_event_atomic.. -- Rob Clark
>>
>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> ---
>>  drivers/gpu/drm/drm_crtc.c  | 159 ++++++++++++++++++++++++++++++++++++++++++++
>>  drivers/gpu/drm/drm_drv.c   |   1 +
>>  include/drm/drmP.h          |   6 ++
>>  include/drm/drm_crtc.h      |   2 +
>>  include/uapi/drm/drm.h      |  12 ++++
>>  include/uapi/drm/drm_mode.h |  16 +++++
>>  6 files changed, 196 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
>> index 09396a9..910e5c6 100644
>> --- a/drivers/gpu/drm/drm_crtc.c
>> +++ b/drivers/gpu/drm/drm_crtc.c
>> @@ -4338,3 +4338,162 @@ void drm_mode_config_cleanup(struct drm_device *dev)
>>       idr_destroy(&dev->mode_config.crtc_idr);
>>  }
>>  EXPORT_SYMBOL(drm_mode_config_cleanup);
>> +
>> +int drm_mode_atomic_ioctl(struct drm_device *dev,
>> +                       void *data, struct drm_file *file_priv)
>> +{
>> +     struct drm_mode_atomic *arg = data;
>> +     uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
>> +     uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
>> +     uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
>> +     uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
>> +     uint64_t __user *blob_values_ptr = (uint64_t __user *)(unsigned long)(arg->blob_values_ptr);
>> +     unsigned int copied_objs = 0;
>> +     unsigned int copied_props = 0;
>> +     unsigned int copied_blobs = 0;
>> +     void *state;
>> +     int ret = 0;
>> +     unsigned int i, j;
>> +
>> +     if (arg->flags & ~(DRM_MODE_ATOMIC_TEST_ONLY |
>> +                     DRM_MODE_ATOMIC_EVENT | DRM_MODE_ATOMIC_NONBLOCK))
>> +             return -EINVAL;
>> +
>> +     /* can't test and expect an event at the same time. */
>> +     if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
>> +                     (arg->flags & DRM_MODE_ATOMIC_EVENT))
>> +             return -EINVAL;
>> +
>> +     mutex_lock(&dev->mode_config.mutex);
>
> I'm pretty sure I had a version w/ fixed locking...
>
> git://gitorious.org/vsyrjala/linux.git rebased_drm_atomic_24

oh, hmm.. actually the locking should no longer be in the ioctl fxn,
but should be pushed down to the commit.  looks like I missed this.  I
need to dig up some actual test code for atomic ioctl ;-)

>> +
>> +     state = dev->driver->atomic_begin(dev, arg->flags);
>> +     if (IS_ERR(state)) {
>> +             ret = PTR_ERR(state);
>> +             goto unlock;
>> +     }
>> +
>> +     for (i = 0; i < arg->count_objs; i++) {
>> +             uint32_t obj_id, count_props;
>> +             struct drm_mode_object *obj;
>> +
>> +             if (get_user(obj_id, objs_ptr + copied_objs)) {
>> +                     ret = -EFAULT;
>> +                     goto out;
>> +             }
>> +
>> +             obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY);
>> +             if (!obj || !obj->properties) {
>> +                     ret = -ENOENT;
>> +                     goto out;
>> +             }
>> +
>> +             if (arg->flags & DRM_MODE_ATOMIC_EVENT) {
>> +                     // XXX create atomic event instead..
>
> Some people are apparently more comfortable with a per-crtc event
> rather than the per-obj events I added. So I think we might want
> both in the end.

yeah, sorting out events is a bit 'TODO' at the moment.  I do kind of
like per-crtc event.. it seems easier to implement and I'm not really
sure what finer event granularity buys us.

BR,
-R

>> +                     struct drm_pending_vblank_event *e =
>> +                             create_vblank_event(dev, file_priv, arg->user_data);
>> +                     if (!e) {
>> +                             ret = -ENOMEM;
>> +                             goto out;
>> +                     }
>> +                     ret = dev->driver->atomic_set_event(dev, state, obj, e);
>> +                     if (ret) {
>> +                             destroy_vblank_event(dev, file_priv, e);
>> +                             goto out;
>> +                     }
>> +             }
>> +
>> +             if (get_user(count_props, count_props_ptr + copied_objs)) {
>> +                     ret = -EFAULT;
>> +                     goto out;
>> +             }
>> +
>> +             copied_objs++;
>> +
>> +             for (j = 0; j < count_props; j++) {
>> +                     uint32_t prop_id;
>> +                     uint64_t prop_value;
>> +                     struct drm_mode_object *prop_obj;
>> +                     struct drm_property *prop;
>> +                     void *blob_data = NULL;
>> +
>> +                     if (get_user(prop_id, props_ptr + copied_props)) {
>> +                             ret = -EFAULT;
>> +                             goto out;
>> +                     }
>> +
>> +                     if (!object_has_prop(obj, prop_id)) {
>> +                             ret = -EINVAL;
>> +                             goto out;
>> +                     }
>> +
>> +                     prop_obj = drm_mode_object_find(dev, prop_id,
>> +                                     DRM_MODE_OBJECT_PROPERTY);
>> +                     if (!prop_obj) {
>> +                             ret = -ENOENT;
>> +                             goto out;
>> +                     }
>> +                     prop = obj_to_property(prop_obj);
>> +
>> +                     if (get_user(prop_value, prop_values_ptr + copied_props)) {
>> +                             ret = -EFAULT;
>> +                             goto out;
>> +                     }
>> +
>> +                     if (!drm_property_change_is_valid(prop, prop_value)) {
>> +                             ret = -EINVAL;
>> +                             goto out;
>> +                     }
>> +
>> +                     if ((prop->flags & DRM_MODE_PROP_BLOB) && prop_value) {
>> +                             uint64_t blob_ptr;
>> +
>> +                             if (get_user(blob_ptr, blob_values_ptr + copied_blobs)) {
>> +                                     ret = -EFAULT;
>> +                                     goto out;
>> +                             }
>> +
>> +                             blob_data = kmalloc(prop_value, GFP_KERNEL);
>> +                             if (!blob_data) {
>> +                                     ret = -ENOMEM;
>> +                                     goto out;
>> +                             }
>> +
>> +                             if (copy_from_user(blob_data, (void __user *)(unsigned long)blob_ptr, prop_value)) {
>> +                                     kfree(blob_data);
>> +                                     ret = -EFAULT;
>> +                                     goto out;
>> +                             }
>> +                     }
>> +
>> +                     /* User space sends the blob pointer even if we
>> +                      * don't use it (length==0).
>> +                      */
>> +                     if (prop->flags & DRM_MODE_PROP_BLOB)
>> +                             copied_blobs++;
>> +
>> +                     /* The driver will be in charge of blob_data from now on. */
>> +                     ret = drm_mode_set_obj_prop(obj, state, prop,
>> +                                     prop_value, blob_data);
>> +                     if (ret)
>> +                             goto out;
>> +
>> +                     copied_props++;
>> +             }
>> +     }
>> +
>> +     ret = dev->driver->atomic_check(dev, state);
>> +     if (ret)
>> +             goto out;
>> +
>> +     if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
>> +             goto out;
>> +
>> +     ret = dev->driver->atomic_commit(dev, state);
>> +
>> + out:
>> +     dev->driver->atomic_end(dev, state);
>> + unlock:
>> +     mutex_unlock(&dev->mode_config.mutex);
>> +
>> +     return ret;
>> +}
>> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
>> index e572dd2..43e04ae 100644
>> --- a/drivers/gpu/drm/drm_drv.c
>> +++ b/drivers/gpu/drm/drm_drv.c
>> @@ -166,6 +166,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
>>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>> +     DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>>  };
>>
>>  #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
>> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
>> index 4c3de22..f282733 100644
>> --- a/include/drm/drmP.h
>> +++ b/include/drm/drmP.h
>> @@ -1158,6 +1158,12 @@ struct drm_pending_vblank_event {
>>       struct drm_event_vblank event;
>>  };
>>
>> +struct drm_pending_atomic_event {
>> +     struct drm_pending_event base;
>> +     int pipe;
>> +     struct drm_event_atomic event;
>> +};
>> +
>>  /**
>>   * DRM device structure. This structure represent a complete card that
>>   * may contain multiple heads.
>> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
>> index 86a5a00..fa3956e 100644
>> --- a/include/drm/drm_crtc.h
>> +++ b/include/drm/drm_crtc.h
>> @@ -1313,6 +1313,8 @@ extern int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
>>                                            struct drm_file *file_priv);
>>  extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
>>                                          struct drm_file *file_priv);
>> +extern int drm_mode_atomic_ioctl(struct drm_device *dev,
>> +                              void *data, struct drm_file *file_priv);
>>
>>  extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
>>                                int *bpp);
>> diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
>> index ece8678..efb1461 100644
>> --- a/include/uapi/drm/drm.h
>> +++ b/include/uapi/drm/drm.h
>> @@ -733,6 +733,7 @@ struct drm_prime_handle {
>>  #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES     DRM_IOWR(0xB9, struct drm_mode_obj_get_properties)
>>  #define DRM_IOCTL_MODE_OBJ_SETPROPERTY       DRM_IOWR(0xBA, struct drm_mode_obj_set_property)
>>  #define DRM_IOCTL_MODE_CURSOR2               DRM_IOWR(0xBB, struct drm_mode_cursor2)
>> +#define DRM_IOCTL_MODE_ATOMIC                DRM_IOWR(0xBC, struct drm_mode_atomic)
>>
>>  /**
>>   * Device specific ioctls should only be in their respective headers
>> @@ -774,6 +775,17 @@ struct drm_event_vblank {
>>       __u32 reserved;
>>  };
>>
>> +struct drm_event_atomic {
>> +     struct drm_event base;
>> +     __u64 user_data;
>> +     __u32 tv_sec;
>> +     __u32 tv_usec;
>> +     __u32 sequence;
>> +     __u32 obj_id;
>> +     __u32 old_fb_id;
>> +     __u32 reserved;
>> +};
>> +
>>  #define DRM_CAP_DUMB_BUFFER 0x1
>>  #define DRM_CAP_VBLANK_HIGH_CRTC 0x2
>>  #define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3
>> diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
>> index 6d4f089..03a473c 100644
>> --- a/include/uapi/drm/drm_mode.h
>> +++ b/include/uapi/drm/drm_mode.h
>> @@ -489,4 +489,20 @@ struct drm_mode_destroy_dumb {
>>       uint32_t handle;
>>  };
>>
>> +#define DRM_MODE_ATOMIC_TEST_ONLY (1<<0)
>> +#define DRM_MODE_ATOMIC_EVENT (1<<1)
>> +#define DRM_MODE_ATOMIC_NONBLOCK (1<<2)
>> +
>> +/* FIXME come up with some sane error reporting mechanism? */
>> +struct drm_mode_atomic {
>> +     __u32 flags;
>> +     __u32 count_objs;
>> +     __u64 objs_ptr;
>> +     __u64 count_props_ptr;
>> +     __u64 props_ptr;
>> +     __u64 prop_values_ptr;
>> +     __u64 blob_values_ptr;
>> +     __u64 user_data;
>> +};
>> +
>>  #endif
>> --
>> 1.8.3.1
>
> --
> Ville Syrjälä
> Intel OTC

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 10/12] drm: convert crtc to properties/state
  2013-10-07 13:39   ` Ville Syrjälä
@ 2013-10-07 14:03     ` Rob Clark
  2013-10-07 14:19       ` Ville Syrjälä
  0 siblings, 1 reply; 38+ messages in thread
From: Rob Clark @ 2013-10-07 14:03 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: dri-devel

On Mon, Oct 7, 2013 at 9:39 AM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> On Sat, Oct 05, 2013 at 08:45:48PM -0400, Rob Clark wrote:
>> Break the mutable state of a crtc out into a separate structure
>> and use atomic properties mechanism to set crtc attributes.  This
>> makes it easier to have some helpers for crtc->set_property()
>> and for checking for invalid params.  The idea is that individual
>> drivers can wrap the state struct in their own struct which adds
>> driver specific parameters, for easy build-up of state across
>> multiple set_property() calls and for easy atomic commit or roll-
>> back.
>
> I'm not sure how we're going to handle the mismatch in the behaviour of
> the atomic modeset vs. the current setcrtc.
>
> The problem is that setcrtc ignore all kinds of conflicting
> crtc->connector assignments, and just overwrites whatever was there
> with the latest configuration. For the atomic case we want to return an
> error if there's a conflict.

Hmm, well currently we preserve the setcrtc behavior because it ends
up going through crtc helpers (or whatever the driver uses).  So
should be fine for setcrtc, but probably not what we want for atomic
ioctl.

I suppose we could solve some of this via internal flags, ie
.atomic_begin(dev, LEGACY_SETCRTC_CHECK_MODE)

it is a bit ugly, but it keeps the ugly in core and drivers don't have
to care as much about it (which is my main concern)

> And another thing is the DPMS handling. The
> current API forces DPMS on when you do a modeset, but for the atomic
> case I want to keep things nice and clean and avoid doing such silly
> things.

I guess the easy thing is to set DPMS property in setcrtc too ;-)

BR,
-R

> So I don't think we can simply convert the current modeset codepaths to
> call into the atomic code. We basically need another version of the
> check function, or another step that happens before .check only in the
> setcrtc case which eliminates the conflicts in a way that matches the
> current setcrtc behaviour.
>
> --
> Ville Syrjälä
> Intel OTC

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 11/12] drm: Atomic modeset ioctl
  2013-10-07 13:55     ` Rob Clark
@ 2013-10-07 14:18       ` Ville Syrjälä
  2013-10-07 14:39         ` Rob Clark
  2013-10-08 18:35         ` Matt Roper
  0 siblings, 2 replies; 38+ messages in thread
From: Ville Syrjälä @ 2013-10-07 14:18 UTC (permalink / raw)
  To: Rob Clark; +Cc: dri-devel

On Mon, Oct 07, 2013 at 09:55:47AM -0400, Rob Clark wrote:
> On Mon, Oct 7, 2013 at 9:28 AM, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> > On Sat, Oct 05, 2013 at 08:45:49PM -0400, Rob Clark wrote:
> >> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >>
> >> The atomic modeset ioctl cna be used to push any number of new values
> >> for object properties. The driver can then check the full device
> >> configuration as single unit, and try to apply the changes atomically.
> >>
> >> The ioctl simply takes a list of object IDs and property IDs and their
> >> values. For setting values to blob properties, the property value
> >> indicates the length of the data, and the actual data is passed via
> >> another blob pointer.
> >>
> >> The caller can demand non-blocking operation from the ioctl, and if the
> >> driver can't satisfy that requirement an error will be returned.
> >>
> >> The caller can also request to receive asynchronous completion events
> >> after the operation has reached the hardware. An event is sent for each
> >> object specified by the caller, whether or not the actual state of
> >> that object changed. Each event also carries a framebuffer ID, which
> >> indicates to user space that the specified object is no longer
> >> accessing that framebuffer.
> >>
> >> TODO: detailed error reporting?
> >>
> >> v1: original
> >> v2: rebase on uapi changes, and drm state structs.. -- Rob Clark
> >> v3: rebase, missing padding in drm_event_atomic.. -- Rob Clark
> >>
> >> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >> ---
> >>  drivers/gpu/drm/drm_crtc.c  | 159 ++++++++++++++++++++++++++++++++++++++++++++
> >>  drivers/gpu/drm/drm_drv.c   |   1 +
> >>  include/drm/drmP.h          |   6 ++
> >>  include/drm/drm_crtc.h      |   2 +
> >>  include/uapi/drm/drm.h      |  12 ++++
> >>  include/uapi/drm/drm_mode.h |  16 +++++
> >>  6 files changed, 196 insertions(+)
> >>
> >> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> >> index 09396a9..910e5c6 100644
> >> --- a/drivers/gpu/drm/drm_crtc.c
> >> +++ b/drivers/gpu/drm/drm_crtc.c
> >> @@ -4338,3 +4338,162 @@ void drm_mode_config_cleanup(struct drm_device *dev)
> >>       idr_destroy(&dev->mode_config.crtc_idr);
> >>  }
> >>  EXPORT_SYMBOL(drm_mode_config_cleanup);
> >> +
> >> +int drm_mode_atomic_ioctl(struct drm_device *dev,
> >> +                       void *data, struct drm_file *file_priv)
> >> +{
> >> +     struct drm_mode_atomic *arg = data;
> >> +     uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
> >> +     uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
> >> +     uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
> >> +     uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
> >> +     uint64_t __user *blob_values_ptr = (uint64_t __user *)(unsigned long)(arg->blob_values_ptr);
> >> +     unsigned int copied_objs = 0;
> >> +     unsigned int copied_props = 0;
> >> +     unsigned int copied_blobs = 0;
> >> +     void *state;
> >> +     int ret = 0;
> >> +     unsigned int i, j;
> >> +
> >> +     if (arg->flags & ~(DRM_MODE_ATOMIC_TEST_ONLY |
> >> +                     DRM_MODE_ATOMIC_EVENT | DRM_MODE_ATOMIC_NONBLOCK))
> >> +             return -EINVAL;
> >> +
> >> +     /* can't test and expect an event at the same time. */
> >> +     if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
> >> +                     (arg->flags & DRM_MODE_ATOMIC_EVENT))
> >> +             return -EINVAL;
> >> +
> >> +     mutex_lock(&dev->mode_config.mutex);
> >
> > I'm pretty sure I had a version w/ fixed locking...
> >
> > git://gitorious.org/vsyrjala/linux.git rebased_drm_atomic_24
> 
> oh, hmm.. actually the locking should no longer be in the ioctl fxn,
> but should be pushed down to the commit.  looks like I missed this.  I
> need to dig up some actual test code for atomic ioctl ;-)

It can't be in commit. At the very least it has to be around
check+commit, and also you need to hold some locks when you're copying
the current config over to your temp storage. That's assuming you store
_everything_ in the temp storage and so it doesn't matter if the current
state can change between the copy and check+commit.

> 
> >> +
> >> +     state = dev->driver->atomic_begin(dev, arg->flags);
> >> +     if (IS_ERR(state)) {
> >> +             ret = PTR_ERR(state);
> >> +             goto unlock;
> >> +     }
> >> +
> >> +     for (i = 0; i < arg->count_objs; i++) {
> >> +             uint32_t obj_id, count_props;
> >> +             struct drm_mode_object *obj;
> >> +
> >> +             if (get_user(obj_id, objs_ptr + copied_objs)) {
> >> +                     ret = -EFAULT;
> >> +                     goto out;
> >> +             }
> >> +
> >> +             obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY);
> >> +             if (!obj || !obj->properties) {
> >> +                     ret = -ENOENT;
> >> +                     goto out;
> >> +             }
> >> +
> >> +             if (arg->flags & DRM_MODE_ATOMIC_EVENT) {
> >> +                     // XXX create atomic event instead..
> >
> > Some people are apparently more comfortable with a per-crtc event
> > rather than the per-obj events I added. So I think we might want
> > both in the end.
> 
> yeah, sorting out events is a bit 'TODO' at the moment.  I do kind of
> like per-crtc event.. it seems easier to implement and I'm not really
> sure what finer event granularity buys us.

Mainly it gets you the old fb. If you limit youself to < vrefresh it's
not a big deal, but going faster than that and you start to want that
information.

> 
> BR,
> -R
> 
 >> +                     struct drm_pending_vblank_event *e =
> >> +                             create_vblank_event(dev, file_priv, arg->user_data);
> >> +                     if (!e) {
> >> +                             ret = -ENOMEM;
> >> +                             goto out;
> >> +                     }
> >> +                     ret = dev->driver->atomic_set_event(dev, state, obj, e);
> >> +                     if (ret) {
> >> +                             destroy_vblank_event(dev, file_priv, e);
> >> +                             goto out;
> >> +                     }
> >> +             }
> >> +
> >> +             if (get_user(count_props, count_props_ptr + copied_objs)) {
> >> +                     ret = -EFAULT;
> >> +                     goto out;
> >> +             }
> >> +
> >> +             copied_objs++;
> >> +
> >> +             for (j = 0; j < count_props; j++) {
> >> +                     uint32_t prop_id;
> >> +                     uint64_t prop_value;
> >> +                     struct drm_mode_object *prop_obj;
> >> +                     struct drm_property *prop;
> >> +                     void *blob_data = NULL;
> >> +
> >> +                     if (get_user(prop_id, props_ptr + copied_props)) {
> >> +                             ret = -EFAULT;
> >> +                             goto out;
> >> +                     }
> >> +
> >> +                     if (!object_has_prop(obj, prop_id)) {
> >> +                             ret = -EINVAL;
> >> +                             goto out;
> >> +                     }
> >> +
> >> +                     prop_obj = drm_mode_object_find(dev, prop_id,
> >> +                                     DRM_MODE_OBJECT_PROPERTY);
> >> +                     if (!prop_obj) {
> >> +                             ret = -ENOENT;
> >> +                             goto out;
> >> +                     }
> >> +                     prop = obj_to_property(prop_obj);
> >> +
> >> +                     if (get_user(prop_value, prop_values_ptr + copied_props)) {
> >> +                             ret = -EFAULT;
> >> +                             goto out;
> >> +                     }
> >> +
> >> +                     if (!drm_property_change_is_valid(prop, prop_value)) {
> >> +                             ret = -EINVAL;
> >> +                             goto out;
> >> +                     }
> >> +
> >> +                     if ((prop->flags & DRM_MODE_PROP_BLOB) && prop_value) {
> >> +                             uint64_t blob_ptr;
> >> +
> >> +                             if (get_user(blob_ptr, blob_values_ptr + copied_blobs)) {
> >> +                                     ret = -EFAULT;
> >> +                                     goto out;
> >> +                             }
> >> +
> >> +                             blob_data = kmalloc(prop_value, GFP_KERNEL);
> >> +                             if (!blob_data) {
> >> +                                     ret = -ENOMEM;
> >> +                                     goto out;
> >> +                             }
> >> +
> >> +                             if (copy_from_user(blob_data, (void __user *)(unsigned long)blob_ptr, prop_value)) {
> >> +                                     kfree(blob_data);
> >> +                                     ret = -EFAULT;
> >> +                                     goto out;
> >> +                             }
> >> +                     }
> >> +
> >> +                     /* User space sends the blob pointer even if we
> >> +                      * don't use it (length==0).
> >> +                      */
> >> +                     if (prop->flags & DRM_MODE_PROP_BLOB)
> >> +                             copied_blobs++;
> >> +
> >> +                     /* The driver will be in charge of blob_data from now on. */
> >> +                     ret = drm_mode_set_obj_prop(obj, state, prop,
> >> +                                     prop_value, blob_data);
> >> +                     if (ret)
> >> +                             goto out;
> >> +
> >> +                     copied_props++;
> >> +             }
> >> +     }
> >> +
> >> +     ret = dev->driver->atomic_check(dev, state);
> >> +     if (ret)
> >> +             goto out;
> >> +
> >> +     if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
> >> +             goto out;
> >> +
> >> +     ret = dev->driver->atomic_commit(dev, state);
> >> +
> >> + out:
> >> +     dev->driver->atomic_end(dev, state);
> >> + unlock:
> >> +     mutex_unlock(&dev->mode_config.mutex);
> >> +
> >> +     return ret;
> >> +}
> >> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
> >> index e572dd2..43e04ae 100644
> >> --- a/drivers/gpu/drm/drm_drv.c
> >> +++ b/drivers/gpu/drm/drm_drv.c
> >> @@ -166,6 +166,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
> >>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> >>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> >>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> >> +     DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> >>  };
> >>
> >>  #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
> >> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
> >> index 4c3de22..f282733 100644
> >> --- a/include/drm/drmP.h
> >> +++ b/include/drm/drmP.h
> >> @@ -1158,6 +1158,12 @@ struct drm_pending_vblank_event {
> >>       struct drm_event_vblank event;
> >>  };
> >>
> >> +struct drm_pending_atomic_event {
> >> +     struct drm_pending_event base;
> >> +     int pipe;
> >> +     struct drm_event_atomic event;
> >> +};
> >> +
> >>  /**
> >>   * DRM device structure. This structure represent a complete card that
> >>   * may contain multiple heads.
> >> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> >> index 86a5a00..fa3956e 100644
> >> --- a/include/drm/drm_crtc.h
> >> +++ b/include/drm/drm_crtc.h
> >> @@ -1313,6 +1313,8 @@ extern int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
> >>                                            struct drm_file *file_priv);
> >>  extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
> >>                                          struct drm_file *file_priv);
> >> +extern int drm_mode_atomic_ioctl(struct drm_device *dev,
> >> +                              void *data, struct drm_file *file_priv);
> >>
> >>  extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
> >>                                int *bpp);
> >> diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
> >> index ece8678..efb1461 100644
> >> --- a/include/uapi/drm/drm.h
> >> +++ b/include/uapi/drm/drm.h
> >> @@ -733,6 +733,7 @@ struct drm_prime_handle {
> >>  #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES     DRM_IOWR(0xB9, struct drm_mode_obj_get_properties)
> >>  #define DRM_IOCTL_MODE_OBJ_SETPROPERTY       DRM_IOWR(0xBA, struct drm_mode_obj_set_property)
> >>  #define DRM_IOCTL_MODE_CURSOR2               DRM_IOWR(0xBB, struct drm_mode_cursor2)
> >> +#define DRM_IOCTL_MODE_ATOMIC                DRM_IOWR(0xBC, struct drm_mode_atomic)
> >>
> >>  /**
> >>   * Device specific ioctls should only be in their respective headers
> >> @@ -774,6 +775,17 @@ struct drm_event_vblank {
> >>       __u32 reserved;
> >>  };
> >>
> >> +struct drm_event_atomic {
> >> +     struct drm_event base;
> >> +     __u64 user_data;
> >> +     __u32 tv_sec;
> >> +     __u32 tv_usec;
> >> +     __u32 sequence;
> >> +     __u32 obj_id;
> >> +     __u32 old_fb_id;
> >> +     __u32 reserved;
> >> +};
> >> +
> >>  #define DRM_CAP_DUMB_BUFFER 0x1
> >>  #define DRM_CAP_VBLANK_HIGH_CRTC 0x2
> >>  #define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3
> >> diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
> >> index 6d4f089..03a473c 100644
> >> --- a/include/uapi/drm/drm_mode.h
> >> +++ b/include/uapi/drm/drm_mode.h
> >> @@ -489,4 +489,20 @@ struct drm_mode_destroy_dumb {
> >>       uint32_t handle;
> >>  };
> >>
> >> +#define DRM_MODE_ATOMIC_TEST_ONLY (1<<0)
> >> +#define DRM_MODE_ATOMIC_EVENT (1<<1)
> >> +#define DRM_MODE_ATOMIC_NONBLOCK (1<<2)
> >> +
> >> +/* FIXME come up with some sane error reporting mechanism? */
> >> +struct drm_mode_atomic {
> >> +     __u32 flags;
> >> +     __u32 count_objs;
> >> +     __u64 objs_ptr;
> >> +     __u64 count_props_ptr;
> >> +     __u64 props_ptr;
> >> +     __u64 prop_values_ptr;
> >> +     __u64 blob_values_ptr;
> >> +     __u64 user_data;
> >> +};
> >> +
> >>  #endif
> >> --
> >> 1.8.3.1
> >
> > --
> > Ville Syrjälä
> > Intel OTC

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 10/12] drm: convert crtc to properties/state
  2013-10-07 14:03     ` Rob Clark
@ 2013-10-07 14:19       ` Ville Syrjälä
  2013-10-07 14:29         ` Rob Clark
  0 siblings, 1 reply; 38+ messages in thread
From: Ville Syrjälä @ 2013-10-07 14:19 UTC (permalink / raw)
  To: Rob Clark; +Cc: dri-devel

On Mon, Oct 07, 2013 at 10:03:01AM -0400, Rob Clark wrote:
> On Mon, Oct 7, 2013 at 9:39 AM, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> > On Sat, Oct 05, 2013 at 08:45:48PM -0400, Rob Clark wrote:
> >> Break the mutable state of a crtc out into a separate structure
> >> and use atomic properties mechanism to set crtc attributes.  This
> >> makes it easier to have some helpers for crtc->set_property()
> >> and for checking for invalid params.  The idea is that individual
> >> drivers can wrap the state struct in their own struct which adds
> >> driver specific parameters, for easy build-up of state across
> >> multiple set_property() calls and for easy atomic commit or roll-
> >> back.
> >
> > I'm not sure how we're going to handle the mismatch in the behaviour of
> > the atomic modeset vs. the current setcrtc.
> >
> > The problem is that setcrtc ignore all kinds of conflicting
> > crtc->connector assignments, and just overwrites whatever was there
> > with the latest configuration. For the atomic case we want to return an
> > error if there's a conflict.
> 
> Hmm, well currently we preserve the setcrtc behavior because it ends
> up going through crtc helpers (or whatever the driver uses).  So
> should be fine for setcrtc, but probably not what we want for atomic
> ioctl.
> 
> I suppose we could solve some of this via internal flags, ie
> .atomic_begin(dev, LEGACY_SETCRTC_CHECK_MODE)
> 
> it is a bit ugly, but it keeps the ugly in core and drivers don't have
> to care as much about it (which is my main concern)

Well, it could be an entirely separate .legacy_crap() hook or something
that happens just before .check().

> 
> > And another thing is the DPMS handling. The
> > current API forces DPMS on when you do a modeset, but for the atomic
> > case I want to keep things nice and clean and avoid doing such silly
> > things.
> 
> I guess the easy thing is to set DPMS property in setcrtc too ;-)

That's what we do, but I don't want it for atomic.

> 
> BR,
> -R
> 
> > So I don't think we can simply convert the current modeset codepaths to
> > call into the atomic code. We basically need another version of the
> > check function, or another step that happens before .check only in the
> > setcrtc case which eliminates the conflicts in a way that matches the
> > current setcrtc behaviour.
> >
> > --
> > Ville Syrjälä
> > Intel OTC

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 10/12] drm: convert crtc to properties/state
  2013-10-07 14:19       ` Ville Syrjälä
@ 2013-10-07 14:29         ` Rob Clark
  2013-10-07 17:51           ` Daniel Vetter
  0 siblings, 1 reply; 38+ messages in thread
From: Rob Clark @ 2013-10-07 14:29 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: dri-devel

On Mon, Oct 7, 2013 at 10:19 AM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> On Mon, Oct 07, 2013 at 10:03:01AM -0400, Rob Clark wrote:
>> On Mon, Oct 7, 2013 at 9:39 AM, Ville Syrjälä
>> <ville.syrjala@linux.intel.com> wrote:
>> > On Sat, Oct 05, 2013 at 08:45:48PM -0400, Rob Clark wrote:
>> >> Break the mutable state of a crtc out into a separate structure
>> >> and use atomic properties mechanism to set crtc attributes.  This
>> >> makes it easier to have some helpers for crtc->set_property()
>> >> and for checking for invalid params.  The idea is that individual
>> >> drivers can wrap the state struct in their own struct which adds
>> >> driver specific parameters, for easy build-up of state across
>> >> multiple set_property() calls and for easy atomic commit or roll-
>> >> back.
>> >
>> > I'm not sure how we're going to handle the mismatch in the behaviour of
>> > the atomic modeset vs. the current setcrtc.
>> >
>> > The problem is that setcrtc ignore all kinds of conflicting
>> > crtc->connector assignments, and just overwrites whatever was there
>> > with the latest configuration. For the atomic case we want to return an
>> > error if there's a conflict.
>>
>> Hmm, well currently we preserve the setcrtc behavior because it ends
>> up going through crtc helpers (or whatever the driver uses).  So
>> should be fine for setcrtc, but probably not what we want for atomic
>> ioctl.
>>
>> I suppose we could solve some of this via internal flags, ie
>> .atomic_begin(dev, LEGACY_SETCRTC_CHECK_MODE)
>>
>> it is a bit ugly, but it keeps the ugly in core and drivers don't have
>> to care as much about it (which is my main concern)
>
> Well, it could be an entirely separate .legacy_crap() hook or something
> that happens just before .check().

yeah, that could work too.. I'll think about it a bit and see what I
can come up with

>>
>> > And another thing is the DPMS handling. The
>> > current API forces DPMS on when you do a modeset, but for the atomic
>> > case I want to keep things nice and clean and avoid doing such silly
>> > things.
>>
>> I guess the easy thing is to set DPMS property in setcrtc too ;-)
>
> That's what we do, but I don't want it for atomic.

yeah, I need think about how that could work if we are still using
.set_config() from the commit, but I guess I should be able to sort
out something..

BR,
-R

>>
>> BR,
>> -R
>>
>> > So I don't think we can simply convert the current modeset codepaths to
>> > call into the atomic code. We basically need another version of the
>> > check function, or another step that happens before .check only in the
>> > setcrtc case which eliminates the conflicts in a way that matches the
>> > current setcrtc behaviour.
>> >
>> > --
>> > Ville Syrjälä
>> > Intel OTC
>
> --
> Ville Syrjälä
> Intel OTC

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 11/12] drm: Atomic modeset ioctl
  2013-10-07 14:18       ` Ville Syrjälä
@ 2013-10-07 14:39         ` Rob Clark
  2013-10-07 15:05           ` Ville Syrjälä
  2013-10-08 18:35         ` Matt Roper
  1 sibling, 1 reply; 38+ messages in thread
From: Rob Clark @ 2013-10-07 14:39 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: dri-devel

On Mon, Oct 7, 2013 at 10:18 AM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> On Mon, Oct 07, 2013 at 09:55:47AM -0400, Rob Clark wrote:
>> On Mon, Oct 7, 2013 at 9:28 AM, Ville Syrjälä
>> <ville.syrjala@linux.intel.com> wrote:
>> > On Sat, Oct 05, 2013 at 08:45:49PM -0400, Rob Clark wrote:
>> >> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> >>
>> >> The atomic modeset ioctl cna be used to push any number of new values
>> >> for object properties. The driver can then check the full device
>> >> configuration as single unit, and try to apply the changes atomically.
>> >>
>> >> The ioctl simply takes a list of object IDs and property IDs and their
>> >> values. For setting values to blob properties, the property value
>> >> indicates the length of the data, and the actual data is passed via
>> >> another blob pointer.
>> >>
>> >> The caller can demand non-blocking operation from the ioctl, and if the
>> >> driver can't satisfy that requirement an error will be returned.
>> >>
>> >> The caller can also request to receive asynchronous completion events
>> >> after the operation has reached the hardware. An event is sent for each
>> >> object specified by the caller, whether or not the actual state of
>> >> that object changed. Each event also carries a framebuffer ID, which
>> >> indicates to user space that the specified object is no longer
>> >> accessing that framebuffer.
>> >>
>> >> TODO: detailed error reporting?
>> >>
>> >> v1: original
>> >> v2: rebase on uapi changes, and drm state structs.. -- Rob Clark
>> >> v3: rebase, missing padding in drm_event_atomic.. -- Rob Clark
>> >>
>> >> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> >> ---
>> >>  drivers/gpu/drm/drm_crtc.c  | 159 ++++++++++++++++++++++++++++++++++++++++++++
>> >>  drivers/gpu/drm/drm_drv.c   |   1 +
>> >>  include/drm/drmP.h          |   6 ++
>> >>  include/drm/drm_crtc.h      |   2 +
>> >>  include/uapi/drm/drm.h      |  12 ++++
>> >>  include/uapi/drm/drm_mode.h |  16 +++++
>> >>  6 files changed, 196 insertions(+)
>> >>
>> >> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
>> >> index 09396a9..910e5c6 100644
>> >> --- a/drivers/gpu/drm/drm_crtc.c
>> >> +++ b/drivers/gpu/drm/drm_crtc.c
>> >> @@ -4338,3 +4338,162 @@ void drm_mode_config_cleanup(struct drm_device *dev)
>> >>       idr_destroy(&dev->mode_config.crtc_idr);
>> >>  }
>> >>  EXPORT_SYMBOL(drm_mode_config_cleanup);
>> >> +
>> >> +int drm_mode_atomic_ioctl(struct drm_device *dev,
>> >> +                       void *data, struct drm_file *file_priv)
>> >> +{
>> >> +     struct drm_mode_atomic *arg = data;
>> >> +     uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
>> >> +     uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
>> >> +     uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
>> >> +     uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
>> >> +     uint64_t __user *blob_values_ptr = (uint64_t __user *)(unsigned long)(arg->blob_values_ptr);
>> >> +     unsigned int copied_objs = 0;
>> >> +     unsigned int copied_props = 0;
>> >> +     unsigned int copied_blobs = 0;
>> >> +     void *state;
>> >> +     int ret = 0;
>> >> +     unsigned int i, j;
>> >> +
>> >> +     if (arg->flags & ~(DRM_MODE_ATOMIC_TEST_ONLY |
>> >> +                     DRM_MODE_ATOMIC_EVENT | DRM_MODE_ATOMIC_NONBLOCK))
>> >> +             return -EINVAL;
>> >> +
>> >> +     /* can't test and expect an event at the same time. */
>> >> +     if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
>> >> +                     (arg->flags & DRM_MODE_ATOMIC_EVENT))
>> >> +             return -EINVAL;
>> >> +
>> >> +     mutex_lock(&dev->mode_config.mutex);
>> >
>> > I'm pretty sure I had a version w/ fixed locking...
>> >
>> > git://gitorious.org/vsyrjala/linux.git rebased_drm_atomic_24
>>
>> oh, hmm.. actually the locking should no longer be in the ioctl fxn,
>> but should be pushed down to the commit.  looks like I missed this.  I
>> need to dig up some actual test code for atomic ioctl ;-)
>
> It can't be in commit. At the very least it has to be around
> check+commit, and also you need to hold some locks when you're copying
> the current config over to your temp storage. That's assuming you store
> _everything_ in the temp storage and so it doesn't matter if the current
> state can change between the copy and check+commit.
>

hmm.. I start to wish we did atomic first, before the fine grained
locking re-work ;-)

>>
>> >> +
>> >> +     state = dev->driver->atomic_begin(dev, arg->flags);
>> >> +     if (IS_ERR(state)) {
>> >> +             ret = PTR_ERR(state);
>> >> +             goto unlock;
>> >> +     }
>> >> +
>> >> +     for (i = 0; i < arg->count_objs; i++) {
>> >> +             uint32_t obj_id, count_props;
>> >> +             struct drm_mode_object *obj;
>> >> +
>> >> +             if (get_user(obj_id, objs_ptr + copied_objs)) {
>> >> +                     ret = -EFAULT;
>> >> +                     goto out;
>> >> +             }
>> >> +
>> >> +             obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY);
>> >> +             if (!obj || !obj->properties) {
>> >> +                     ret = -ENOENT;
>> >> +                     goto out;
>> >> +             }
>> >> +
>> >> +             if (arg->flags & DRM_MODE_ATOMIC_EVENT) {
>> >> +                     // XXX create atomic event instead..
>> >
>> > Some people are apparently more comfortable with a per-crtc event
>> > rather than the per-obj events I added. So I think we might want
>> > both in the end.
>>
>> yeah, sorting out events is a bit 'TODO' at the moment.  I do kind of
>> like per-crtc event.. it seems easier to implement and I'm not really
>> sure what finer event granularity buys us.
>
> Mainly it gets you the old fb. If you limit youself to < vrefresh it's
> not a big deal, but going faster than that and you start to want that
> information.
>

oh, right.. well I guess it wouldn't be too hard to add the current
primary plane fb_id to the existing event, which might be sufficient.
At any rate, I don't mind adding new event flags to atomic ioctl once
we get atomic in place.

BR,
-R

>>
>> BR,
>> -R
>>
>  >> +                     struct drm_pending_vblank_event *e =
>> >> +                             create_vblank_event(dev, file_priv, arg->user_data);
>> >> +                     if (!e) {
>> >> +                             ret = -ENOMEM;
>> >> +                             goto out;
>> >> +                     }
>> >> +                     ret = dev->driver->atomic_set_event(dev, state, obj, e);
>> >> +                     if (ret) {
>> >> +                             destroy_vblank_event(dev, file_priv, e);
>> >> +                             goto out;
>> >> +                     }
>> >> +             }
>> >> +
>> >> +             if (get_user(count_props, count_props_ptr + copied_objs)) {
>> >> +                     ret = -EFAULT;
>> >> +                     goto out;
>> >> +             }
>> >> +
>> >> +             copied_objs++;
>> >> +
>> >> +             for (j = 0; j < count_props; j++) {
>> >> +                     uint32_t prop_id;
>> >> +                     uint64_t prop_value;
>> >> +                     struct drm_mode_object *prop_obj;
>> >> +                     struct drm_property *prop;
>> >> +                     void *blob_data = NULL;
>> >> +
>> >> +                     if (get_user(prop_id, props_ptr + copied_props)) {
>> >> +                             ret = -EFAULT;
>> >> +                             goto out;
>> >> +                     }
>> >> +
>> >> +                     if (!object_has_prop(obj, prop_id)) {
>> >> +                             ret = -EINVAL;
>> >> +                             goto out;
>> >> +                     }
>> >> +
>> >> +                     prop_obj = drm_mode_object_find(dev, prop_id,
>> >> +                                     DRM_MODE_OBJECT_PROPERTY);
>> >> +                     if (!prop_obj) {
>> >> +                             ret = -ENOENT;
>> >> +                             goto out;
>> >> +                     }
>> >> +                     prop = obj_to_property(prop_obj);
>> >> +
>> >> +                     if (get_user(prop_value, prop_values_ptr + copied_props)) {
>> >> +                             ret = -EFAULT;
>> >> +                             goto out;
>> >> +                     }
>> >> +
>> >> +                     if (!drm_property_change_is_valid(prop, prop_value)) {
>> >> +                             ret = -EINVAL;
>> >> +                             goto out;
>> >> +                     }
>> >> +
>> >> +                     if ((prop->flags & DRM_MODE_PROP_BLOB) && prop_value) {
>> >> +                             uint64_t blob_ptr;
>> >> +
>> >> +                             if (get_user(blob_ptr, blob_values_ptr + copied_blobs)) {
>> >> +                                     ret = -EFAULT;
>> >> +                                     goto out;
>> >> +                             }
>> >> +
>> >> +                             blob_data = kmalloc(prop_value, GFP_KERNEL);
>> >> +                             if (!blob_data) {
>> >> +                                     ret = -ENOMEM;
>> >> +                                     goto out;
>> >> +                             }
>> >> +
>> >> +                             if (copy_from_user(blob_data, (void __user *)(unsigned long)blob_ptr, prop_value)) {
>> >> +                                     kfree(blob_data);
>> >> +                                     ret = -EFAULT;
>> >> +                                     goto out;
>> >> +                             }
>> >> +                     }
>> >> +
>> >> +                     /* User space sends the blob pointer even if we
>> >> +                      * don't use it (length==0).
>> >> +                      */
>> >> +                     if (prop->flags & DRM_MODE_PROP_BLOB)
>> >> +                             copied_blobs++;
>> >> +
>> >> +                     /* The driver will be in charge of blob_data from now on. */
>> >> +                     ret = drm_mode_set_obj_prop(obj, state, prop,
>> >> +                                     prop_value, blob_data);
>> >> +                     if (ret)
>> >> +                             goto out;
>> >> +
>> >> +                     copied_props++;
>> >> +             }
>> >> +     }
>> >> +
>> >> +     ret = dev->driver->atomic_check(dev, state);
>> >> +     if (ret)
>> >> +             goto out;
>> >> +
>> >> +     if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
>> >> +             goto out;
>> >> +
>> >> +     ret = dev->driver->atomic_commit(dev, state);
>> >> +
>> >> + out:
>> >> +     dev->driver->atomic_end(dev, state);
>> >> + unlock:
>> >> +     mutex_unlock(&dev->mode_config.mutex);
>> >> +
>> >> +     return ret;
>> >> +}
>> >> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
>> >> index e572dd2..43e04ae 100644
>> >> --- a/drivers/gpu/drm/drm_drv.c
>> >> +++ b/drivers/gpu/drm/drm_drv.c
>> >> @@ -166,6 +166,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
>> >>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>> >>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>> >>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>> >> +     DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>> >>  };
>> >>
>> >>  #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
>> >> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
>> >> index 4c3de22..f282733 100644
>> >> --- a/include/drm/drmP.h
>> >> +++ b/include/drm/drmP.h
>> >> @@ -1158,6 +1158,12 @@ struct drm_pending_vblank_event {
>> >>       struct drm_event_vblank event;
>> >>  };
>> >>
>> >> +struct drm_pending_atomic_event {
>> >> +     struct drm_pending_event base;
>> >> +     int pipe;
>> >> +     struct drm_event_atomic event;
>> >> +};
>> >> +
>> >>  /**
>> >>   * DRM device structure. This structure represent a complete card that
>> >>   * may contain multiple heads.
>> >> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
>> >> index 86a5a00..fa3956e 100644
>> >> --- a/include/drm/drm_crtc.h
>> >> +++ b/include/drm/drm_crtc.h
>> >> @@ -1313,6 +1313,8 @@ extern int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
>> >>                                            struct drm_file *file_priv);
>> >>  extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
>> >>                                          struct drm_file *file_priv);
>> >> +extern int drm_mode_atomic_ioctl(struct drm_device *dev,
>> >> +                              void *data, struct drm_file *file_priv);
>> >>
>> >>  extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
>> >>                                int *bpp);
>> >> diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
>> >> index ece8678..efb1461 100644
>> >> --- a/include/uapi/drm/drm.h
>> >> +++ b/include/uapi/drm/drm.h
>> >> @@ -733,6 +733,7 @@ struct drm_prime_handle {
>> >>  #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES     DRM_IOWR(0xB9, struct drm_mode_obj_get_properties)
>> >>  #define DRM_IOCTL_MODE_OBJ_SETPROPERTY       DRM_IOWR(0xBA, struct drm_mode_obj_set_property)
>> >>  #define DRM_IOCTL_MODE_CURSOR2               DRM_IOWR(0xBB, struct drm_mode_cursor2)
>> >> +#define DRM_IOCTL_MODE_ATOMIC                DRM_IOWR(0xBC, struct drm_mode_atomic)
>> >>
>> >>  /**
>> >>   * Device specific ioctls should only be in their respective headers
>> >> @@ -774,6 +775,17 @@ struct drm_event_vblank {
>> >>       __u32 reserved;
>> >>  };
>> >>
>> >> +struct drm_event_atomic {
>> >> +     struct drm_event base;
>> >> +     __u64 user_data;
>> >> +     __u32 tv_sec;
>> >> +     __u32 tv_usec;
>> >> +     __u32 sequence;
>> >> +     __u32 obj_id;
>> >> +     __u32 old_fb_id;
>> >> +     __u32 reserved;
>> >> +};
>> >> +
>> >>  #define DRM_CAP_DUMB_BUFFER 0x1
>> >>  #define DRM_CAP_VBLANK_HIGH_CRTC 0x2
>> >>  #define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3
>> >> diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
>> >> index 6d4f089..03a473c 100644
>> >> --- a/include/uapi/drm/drm_mode.h
>> >> +++ b/include/uapi/drm/drm_mode.h
>> >> @@ -489,4 +489,20 @@ struct drm_mode_destroy_dumb {
>> >>       uint32_t handle;
>> >>  };
>> >>
>> >> +#define DRM_MODE_ATOMIC_TEST_ONLY (1<<0)
>> >> +#define DRM_MODE_ATOMIC_EVENT (1<<1)
>> >> +#define DRM_MODE_ATOMIC_NONBLOCK (1<<2)
>> >> +
>> >> +/* FIXME come up with some sane error reporting mechanism? */
>> >> +struct drm_mode_atomic {
>> >> +     __u32 flags;
>> >> +     __u32 count_objs;
>> >> +     __u64 objs_ptr;
>> >> +     __u64 count_props_ptr;
>> >> +     __u64 props_ptr;
>> >> +     __u64 prop_values_ptr;
>> >> +     __u64 blob_values_ptr;
>> >> +     __u64 user_data;
>> >> +};
>> >> +
>> >>  #endif
>> >> --
>> >> 1.8.3.1
>> >
>> > --
>> > Ville Syrjälä
>> > Intel OTC
>
> --
> Ville Syrjälä
> Intel OTC

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 02/12] drm: add object property type
  2013-10-07 13:43   ` Ville Syrjälä
@ 2013-10-07 14:44     ` Rob Clark
  0 siblings, 0 replies; 38+ messages in thread
From: Rob Clark @ 2013-10-07 14:44 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: dri-devel

On Mon, Oct 7, 2013 at 9:43 AM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> On Sat, Oct 05, 2013 at 08:45:40PM -0400, Rob Clark wrote:
>> diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
>> index 5508117..35921ba 100644
>> --- a/include/uapi/drm/drm_mode.h
>> +++ b/include/uapi/drm/drm_mode.h
>> @@ -231,6 +231,7 @@ struct drm_mode_get_connector {
>>  #define DRM_MODE_PROP_ENUM   (1<<3) /* enumerated type with text strings */
>>  #define DRM_MODE_PROP_BLOB   (1<<4)
>>  #define DRM_MODE_PROP_BITMASK        (1<<5) /* bitmask of enumerated types */
>> +#define DRM_MODE_PROP_OBJECT (1<<6) /* drm mode object */
>
> This way to using up one bit for each type sucks big time. IIRC we
> discussed this at Fosdem and one idea was to leave the current bits as
> sort of base types, and reserve a bunch of the other bits to indicate a
> sub-type. For instance the new signed range and object ID prop types
> could be sub-types of the current range type.

oh, right..  current object-prop is just a straight rebase of the
original patch, so I didn't change this yet.

We probably don't want to use sub-type in cases where old userspace
could misinterpret things, so not sure about signed-range to be a
sub-type of range (if that is what you meant)... but maybe a good idea
for PROP_MISC + PROP_SUBTYPE_OBJECT.  Otoh, at the moment, the only
other prop type I have in mind is ARRAY (although not sure if we can
do single PROP_ARRAY or if we end up needing PROP_ARRAY_foo, for
everything we might want an array of..)

BR,
-R

> Maybe we should reserve a few more bits for new base types in case we
> need them in the future, or just add sometime king DRM_MODE_PROP_MISC,
> which is where we'd stick every sub-type that doesn't fit the current
> base types.
>
> --
> Ville Syrjälä
> Intel OTC

^ permalink raw reply	[flat|nested] 38+ messages in thread

* RE: [RFCv1 04/12] drm: add DRM_MODE_PROP_SIGNED property flag
  2013-10-06  0:45 ` [RFCv1 04/12] drm: add DRM_MODE_PROP_SIGNED " Rob Clark
@ 2013-10-07 14:46   ` Matt Plumtree
  0 siblings, 0 replies; 38+ messages in thread
From: Matt Plumtree @ 2013-10-07 14:46 UTC (permalink / raw)
  To: Rob Clark, dri-devel

> static bool drm_property_change_is_valid(struct drm_property *property,
>  					 uint64_t value)
>  {
> -	if (property->flags & DRM_MODE_PROP_IMMUTABLE)
> +	if (property->flags & DRM_MODE_PROP_IMMUTABLE) {
>  		return false;
> -	if (property->flags & DRM_MODE_PROP_RANGE) {
> +	} else if (property->flags & (DRM_MODE_PROP_RANGE|DRM_MODE_PROP_SIGNED)) {
> +		int64_t svalue = U642I64(value);
> +		if (svalue < U642I64(property->values[0]) ||
> +				svalue > U642I64(property->values[1]))
> +			return false;
> +		return true;
> +	} else if (property->flags & DRM_MODE_PROP_RANGE) {
>		if (value < property->values[0] || value > property->values[1])
>  			return false;
>  		return true;

I don't think this is doing what you think it should. If the flags include
DRM_MODE_PROP_RANGE, the first "else if" will be executed regardless of
whether DRM_MODE_PROP_SIGNED is set or not. This means that the second
"else if" will never be executed.

You'd need to add "== (DRM_MODE_PROP_RANGE|DRM_MODE_PROP_SIGNED)" or
similar.

Matt

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 03/12] drm: add DRM_MODE_PROP_DYNAMIC property flag
  2013-10-07 13:46   ` Ville Syrjälä
@ 2013-10-07 14:46     ` Rob Clark
  0 siblings, 0 replies; 38+ messages in thread
From: Rob Clark @ 2013-10-07 14:46 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: dri-devel

On Mon, Oct 7, 2013 at 9:46 AM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> On Sat, Oct 05, 2013 at 08:45:41PM -0400, Rob Clark wrote:
>> This indicates to userspace that the property is something that can
>> be set dynamically without requiring a "test" step to check if the
>> hw is capable.  This allows a userspace compositor, such as weston,
>> to avoid an extra ioctl to check whether it needs to fall-back to
>> GPU to composite some surface prior to submission of GPU render
>> commands.
>> ---
>>  include/uapi/drm/drm_mode.h | 9 +++++++++
>>  1 file changed, 9 insertions(+)
>>
>> diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
>> index 35921ba..15db837 100644
>> --- a/include/uapi/drm/drm_mode.h
>> +++ b/include/uapi/drm/drm_mode.h
>> @@ -232,6 +232,15 @@ struct drm_mode_get_connector {
>>  #define DRM_MODE_PROP_BLOB   (1<<4)
>>  #define DRM_MODE_PROP_BITMASK        (1<<5) /* bitmask of enumerated types */
>>  #define DRM_MODE_PROP_OBJECT (1<<6) /* drm mode object */
>> +/* Properties that are not dynamic cannot safely be changed without a
>> + * atomic-modeset / atomic-pageflip test step.  But if userspace is
>> + * only changing dynamic properties, it is guaranteed that the change
>> + * will not exceed hw limits, so no test step is required.
>> + *
>> + * Note that fb_id properties are a bit ambiguous.. they of course can
>> + * be changed dynamically, assuming the pixel format does not change.
>> + */
>> +#define DRM_MODE_PROP_DYNAMIC        (1<<24)
>
> I'm still not convinced that this is useful. We can't even flag the FB
> ID with this flag since the FB encompasses stride/bpp/etc. parameters
> that for sure can't just be changed w/o first checking the new
> configuration.

well, I know of at least some hw that can change plane src/crtc coords
without requiring a check step.  So I think it is useful as an
optimization.  But it is also something that could be easily/safely
added later so maybe I should drop it from the initial atomic
patchset.

BR,
-R

> --
> Ville Syrjälä
> Intel OTC

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 11/12] drm: Atomic modeset ioctl
  2013-10-07 14:39         ` Rob Clark
@ 2013-10-07 15:05           ` Ville Syrjälä
  2013-10-07 15:20             ` Rob Clark
  0 siblings, 1 reply; 38+ messages in thread
From: Ville Syrjälä @ 2013-10-07 15:05 UTC (permalink / raw)
  To: Rob Clark; +Cc: dri-devel

On Mon, Oct 07, 2013 at 10:39:01AM -0400, Rob Clark wrote:
> On Mon, Oct 7, 2013 at 10:18 AM, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> > On Mon, Oct 07, 2013 at 09:55:47AM -0400, Rob Clark wrote:
> >> On Mon, Oct 7, 2013 at 9:28 AM, Ville Syrjälä
> >> <ville.syrjala@linux.intel.com> wrote:
> >> > On Sat, Oct 05, 2013 at 08:45:49PM -0400, Rob Clark wrote:
> >> >> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >> >>
> >> >> The atomic modeset ioctl cna be used to push any number of new values
> >> >> for object properties. The driver can then check the full device
> >> >> configuration as single unit, and try to apply the changes atomically.
> >> >>
> >> >> The ioctl simply takes a list of object IDs and property IDs and their
> >> >> values. For setting values to blob properties, the property value
> >> >> indicates the length of the data, and the actual data is passed via
> >> >> another blob pointer.
> >> >>
> >> >> The caller can demand non-blocking operation from the ioctl, and if the
> >> >> driver can't satisfy that requirement an error will be returned.
> >> >>
> >> >> The caller can also request to receive asynchronous completion events
> >> >> after the operation has reached the hardware. An event is sent for each
> >> >> object specified by the caller, whether or not the actual state of
> >> >> that object changed. Each event also carries a framebuffer ID, which
> >> >> indicates to user space that the specified object is no longer
> >> >> accessing that framebuffer.
> >> >>
> >> >> TODO: detailed error reporting?
> >> >>
> >> >> v1: original
> >> >> v2: rebase on uapi changes, and drm state structs.. -- Rob Clark
> >> >> v3: rebase, missing padding in drm_event_atomic.. -- Rob Clark
> >> >>
> >> >> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >> >> ---
> >> >>  drivers/gpu/drm/drm_crtc.c  | 159 ++++++++++++++++++++++++++++++++++++++++++++
> >> >>  drivers/gpu/drm/drm_drv.c   |   1 +
> >> >>  include/drm/drmP.h          |   6 ++
> >> >>  include/drm/drm_crtc.h      |   2 +
> >> >>  include/uapi/drm/drm.h      |  12 ++++
> >> >>  include/uapi/drm/drm_mode.h |  16 +++++
> >> >>  6 files changed, 196 insertions(+)
> >> >>
> >> >> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> >> >> index 09396a9..910e5c6 100644
> >> >> --- a/drivers/gpu/drm/drm_crtc.c
> >> >> +++ b/drivers/gpu/drm/drm_crtc.c
> >> >> @@ -4338,3 +4338,162 @@ void drm_mode_config_cleanup(struct drm_device *dev)
> >> >>       idr_destroy(&dev->mode_config.crtc_idr);
> >> >>  }
> >> >>  EXPORT_SYMBOL(drm_mode_config_cleanup);
> >> >> +
> >> >> +int drm_mode_atomic_ioctl(struct drm_device *dev,
> >> >> +                       void *data, struct drm_file *file_priv)
> >> >> +{
> >> >> +     struct drm_mode_atomic *arg = data;
> >> >> +     uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
> >> >> +     uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
> >> >> +     uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
> >> >> +     uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
> >> >> +     uint64_t __user *blob_values_ptr = (uint64_t __user *)(unsigned long)(arg->blob_values_ptr);
> >> >> +     unsigned int copied_objs = 0;
> >> >> +     unsigned int copied_props = 0;
> >> >> +     unsigned int copied_blobs = 0;
> >> >> +     void *state;
> >> >> +     int ret = 0;
> >> >> +     unsigned int i, j;
> >> >> +
> >> >> +     if (arg->flags & ~(DRM_MODE_ATOMIC_TEST_ONLY |
> >> >> +                     DRM_MODE_ATOMIC_EVENT | DRM_MODE_ATOMIC_NONBLOCK))
> >> >> +             return -EINVAL;
> >> >> +
> >> >> +     /* can't test and expect an event at the same time. */
> >> >> +     if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
> >> >> +                     (arg->flags & DRM_MODE_ATOMIC_EVENT))
> >> >> +             return -EINVAL;
> >> >> +
> >> >> +     mutex_lock(&dev->mode_config.mutex);
> >> >
> >> > I'm pretty sure I had a version w/ fixed locking...
> >> >
> >> > git://gitorious.org/vsyrjala/linux.git rebased_drm_atomic_24
> >>
> >> oh, hmm.. actually the locking should no longer be in the ioctl fxn,
> >> but should be pushed down to the commit.  looks like I missed this.  I
> >> need to dig up some actual test code for atomic ioctl ;-)
> >
> > It can't be in commit. At the very least it has to be around
> > check+commit, and also you need to hold some locks when you're copying
> > the current config over to your temp storage. That's assuming you store
> > _everything_ in the temp storage and so it doesn't matter if the current
> > state can change between the copy and check+commit.
> >
> 
> hmm.. I start to wish we did atomic first, before the fine grained
> locking re-work ;-)

I don't see it mattering for this particular problem if we just grab
the big lock anyway.

But as I already stated, I would prefer to solve the plane locking 
before doing atomic. Whether we have per-plane locks or not can
actually matter for this code, especially when dealing with planes
that can move between crtcs.

And we still have locking issues to solve in the .check+commit steps
when we have to deal with shared resources across the entire device.
We can't simply use some small local lock in the .check step since 
something relevant might have changed by the time we reach .commit.
I guess we could re-check such things at the very start of commit,
before we've clobbered any state, and then update the global state
to match if everything looks good, before we again drop the local
lock.

> 
> >>
> >> >> +
> >> >> +     state = dev->driver->atomic_begin(dev, arg->flags);
> >> >> +     if (IS_ERR(state)) {
> >> >> +             ret = PTR_ERR(state);
> >> >> +             goto unlock;
> >> >> +     }
> >> >> +
> >> >> +     for (i = 0; i < arg->count_objs; i++) {
> >> >> +             uint32_t obj_id, count_props;
> >> >> +             struct drm_mode_object *obj;
> >> >> +
> >> >> +             if (get_user(obj_id, objs_ptr + copied_objs)) {
> >> >> +                     ret = -EFAULT;
> >> >> +                     goto out;
> >> >> +             }
> >> >> +
> >> >> +             obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY);
> >> >> +             if (!obj || !obj->properties) {
> >> >> +                     ret = -ENOENT;
> >> >> +                     goto out;
> >> >> +             }
> >> >> +
> >> >> +             if (arg->flags & DRM_MODE_ATOMIC_EVENT) {
> >> >> +                     // XXX create atomic event instead..
> >> >
> >> > Some people are apparently more comfortable with a per-crtc event
> >> > rather than the per-obj events I added. So I think we might want
> >> > both in the end.
> >>
> >> yeah, sorting out events is a bit 'TODO' at the moment.  I do kind of
> >> like per-crtc event.. it seems easier to implement and I'm not really
> >> sure what finer event granularity buys us.
> >
> > Mainly it gets you the old fb. If you limit youself to < vrefresh it's
> > not a big deal, but going faster than that and you start to want that
> > information.
> >
> 
> oh, right.. well I guess it wouldn't be too hard to add the current
> primary plane fb_id to the existing event, which might be sufficient.
>
> At any rate, I don't mind adding new event flags to atomic ioctl once
> we get atomic in place.

Yeah adding new events isn't that hard. We just need to make sure
things make sense. The code you posted doesn't :P

You add the event to every object, even though you only wanted one
event per crtc. The same object could also be listed multiple times in
the object list, so the code would even add multiple events for the
same object.

> 
> BR,
> -R
> 
> >>
> >> BR,
> >> -R
> >>
> >  >> +                     struct drm_pending_vblank_event *e =
> >> >> +                             create_vblank_event(dev, file_priv, arg->user_data);
> >> >> +                     if (!e) {
> >> >> +                             ret = -ENOMEM;
> >> >> +                             goto out;
> >> >> +                     }
> >> >> +                     ret = dev->driver->atomic_set_event(dev, state, obj, e);
> >> >> +                     if (ret) {
> >> >> +                             destroy_vblank_event(dev, file_priv, e);
> >> >> +                             goto out;
> >> >> +                     }
> >> >> +             }
> >> >> +
> >> >> +             if (get_user(count_props, count_props_ptr + copied_objs)) {
> >> >> +                     ret = -EFAULT;
> >> >> +                     goto out;
> >> >> +             }
> >> >> +
> >> >> +             copied_objs++;
> >> >> +
> >> >> +             for (j = 0; j < count_props; j++) {
> >> >> +                     uint32_t prop_id;
> >> >> +                     uint64_t prop_value;
> >> >> +                     struct drm_mode_object *prop_obj;
> >> >> +                     struct drm_property *prop;
> >> >> +                     void *blob_data = NULL;
> >> >> +
> >> >> +                     if (get_user(prop_id, props_ptr + copied_props)) {
> >> >> +                             ret = -EFAULT;
> >> >> +                             goto out;
> >> >> +                     }
> >> >> +
> >> >> +                     if (!object_has_prop(obj, prop_id)) {
> >> >> +                             ret = -EINVAL;
> >> >> +                             goto out;
> >> >> +                     }
> >> >> +
> >> >> +                     prop_obj = drm_mode_object_find(dev, prop_id,
> >> >> +                                     DRM_MODE_OBJECT_PROPERTY);
> >> >> +                     if (!prop_obj) {
> >> >> +                             ret = -ENOENT;
> >> >> +                             goto out;
> >> >> +                     }
> >> >> +                     prop = obj_to_property(prop_obj);
> >> >> +
> >> >> +                     if (get_user(prop_value, prop_values_ptr + copied_props)) {
> >> >> +                             ret = -EFAULT;
> >> >> +                             goto out;
> >> >> +                     }
> >> >> +
> >> >> +                     if (!drm_property_change_is_valid(prop, prop_value)) {
> >> >> +                             ret = -EINVAL;
> >> >> +                             goto out;
> >> >> +                     }
> >> >> +
> >> >> +                     if ((prop->flags & DRM_MODE_PROP_BLOB) && prop_value) {
> >> >> +                             uint64_t blob_ptr;
> >> >> +
> >> >> +                             if (get_user(blob_ptr, blob_values_ptr + copied_blobs)) {
> >> >> +                                     ret = -EFAULT;
> >> >> +                                     goto out;
> >> >> +                             }
> >> >> +
> >> >> +                             blob_data = kmalloc(prop_value, GFP_KERNEL);
> >> >> +                             if (!blob_data) {
> >> >> +                                     ret = -ENOMEM;
> >> >> +                                     goto out;
> >> >> +                             }
> >> >> +
> >> >> +                             if (copy_from_user(blob_data, (void __user *)(unsigned long)blob_ptr, prop_value)) {
> >> >> +                                     kfree(blob_data);
> >> >> +                                     ret = -EFAULT;
> >> >> +                                     goto out;
> >> >> +                             }
> >> >> +                     }
> >> >> +
> >> >> +                     /* User space sends the blob pointer even if we
> >> >> +                      * don't use it (length==0).
> >> >> +                      */
> >> >> +                     if (prop->flags & DRM_MODE_PROP_BLOB)
> >> >> +                             copied_blobs++;
> >> >> +
> >> >> +                     /* The driver will be in charge of blob_data from now on. */
> >> >> +                     ret = drm_mode_set_obj_prop(obj, state, prop,
> >> >> +                                     prop_value, blob_data);
> >> >> +                     if (ret)
> >> >> +                             goto out;
> >> >> +
> >> >> +                     copied_props++;
> >> >> +             }
> >> >> +     }
> >> >> +
> >> >> +     ret = dev->driver->atomic_check(dev, state);
> >> >> +     if (ret)
> >> >> +             goto out;
> >> >> +
> >> >> +     if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
> >> >> +             goto out;
> >> >> +
> >> >> +     ret = dev->driver->atomic_commit(dev, state);
> >> >> +
> >> >> + out:
> >> >> +     dev->driver->atomic_end(dev, state);
> >> >> + unlock:
> >> >> +     mutex_unlock(&dev->mode_config.mutex);
> >> >> +
> >> >> +     return ret;
> >> >> +}
> >> >> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
> >> >> index e572dd2..43e04ae 100644
> >> >> --- a/drivers/gpu/drm/drm_drv.c
> >> >> +++ b/drivers/gpu/drm/drm_drv.c
> >> >> @@ -166,6 +166,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
> >> >>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> >> >>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> >> >>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> >> >> +     DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> >> >>  };
> >> >>
> >> >>  #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
> >> >> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
> >> >> index 4c3de22..f282733 100644
> >> >> --- a/include/drm/drmP.h
> >> >> +++ b/include/drm/drmP.h
> >> >> @@ -1158,6 +1158,12 @@ struct drm_pending_vblank_event {
> >> >>       struct drm_event_vblank event;
> >> >>  };
> >> >>
> >> >> +struct drm_pending_atomic_event {
> >> >> +     struct drm_pending_event base;
> >> >> +     int pipe;
> >> >> +     struct drm_event_atomic event;
> >> >> +};
> >> >> +
> >> >>  /**
> >> >>   * DRM device structure. This structure represent a complete card that
> >> >>   * may contain multiple heads.
> >> >> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> >> >> index 86a5a00..fa3956e 100644
> >> >> --- a/include/drm/drm_crtc.h
> >> >> +++ b/include/drm/drm_crtc.h
> >> >> @@ -1313,6 +1313,8 @@ extern int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
> >> >>                                            struct drm_file *file_priv);
> >> >>  extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
> >> >>                                          struct drm_file *file_priv);
> >> >> +extern int drm_mode_atomic_ioctl(struct drm_device *dev,
> >> >> +                              void *data, struct drm_file *file_priv);
> >> >>
> >> >>  extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
> >> >>                                int *bpp);
> >> >> diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
> >> >> index ece8678..efb1461 100644
> >> >> --- a/include/uapi/drm/drm.h
> >> >> +++ b/include/uapi/drm/drm.h
> >> >> @@ -733,6 +733,7 @@ struct drm_prime_handle {
> >> >>  #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES     DRM_IOWR(0xB9, struct drm_mode_obj_get_properties)
> >> >>  #define DRM_IOCTL_MODE_OBJ_SETPROPERTY       DRM_IOWR(0xBA, struct drm_mode_obj_set_property)
> >> >>  #define DRM_IOCTL_MODE_CURSOR2               DRM_IOWR(0xBB, struct drm_mode_cursor2)
> >> >> +#define DRM_IOCTL_MODE_ATOMIC                DRM_IOWR(0xBC, struct drm_mode_atomic)
> >> >>
> >> >>  /**
> >> >>   * Device specific ioctls should only be in their respective headers
> >> >> @@ -774,6 +775,17 @@ struct drm_event_vblank {
> >> >>       __u32 reserved;
> >> >>  };
> >> >>
> >> >> +struct drm_event_atomic {
> >> >> +     struct drm_event base;
> >> >> +     __u64 user_data;
> >> >> +     __u32 tv_sec;
> >> >> +     __u32 tv_usec;
> >> >> +     __u32 sequence;
> >> >> +     __u32 obj_id;
> >> >> +     __u32 old_fb_id;
> >> >> +     __u32 reserved;
> >> >> +};
> >> >> +
> >> >>  #define DRM_CAP_DUMB_BUFFER 0x1
> >> >>  #define DRM_CAP_VBLANK_HIGH_CRTC 0x2
> >> >>  #define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3
> >> >> diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
> >> >> index 6d4f089..03a473c 100644
> >> >> --- a/include/uapi/drm/drm_mode.h
> >> >> +++ b/include/uapi/drm/drm_mode.h
> >> >> @@ -489,4 +489,20 @@ struct drm_mode_destroy_dumb {
> >> >>       uint32_t handle;
> >> >>  };
> >> >>
> >> >> +#define DRM_MODE_ATOMIC_TEST_ONLY (1<<0)
> >> >> +#define DRM_MODE_ATOMIC_EVENT (1<<1)
> >> >> +#define DRM_MODE_ATOMIC_NONBLOCK (1<<2)
> >> >> +
> >> >> +/* FIXME come up with some sane error reporting mechanism? */
> >> >> +struct drm_mode_atomic {
> >> >> +     __u32 flags;
> >> >> +     __u32 count_objs;
> >> >> +     __u64 objs_ptr;
> >> >> +     __u64 count_props_ptr;
> >> >> +     __u64 props_ptr;
> >> >> +     __u64 prop_values_ptr;
> >> >> +     __u64 blob_values_ptr;
> >> >> +     __u64 user_data;
> >> >> +};
> >> >> +
> >> >>  #endif
> >> >> --
> >> >> 1.8.3.1
> >> >
> >> > --
> >> > Ville Syrjälä
> >> > Intel OTC
> >
> > --
> > Ville Syrjälä
> > Intel OTC

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 11/12] drm: Atomic modeset ioctl
  2013-10-07 15:05           ` Ville Syrjälä
@ 2013-10-07 15:20             ` Rob Clark
  2013-10-07 17:56               ` Daniel Vetter
  0 siblings, 1 reply; 38+ messages in thread
From: Rob Clark @ 2013-10-07 15:20 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: dri-devel

On Mon, Oct 7, 2013 at 11:05 AM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> On Mon, Oct 07, 2013 at 10:39:01AM -0400, Rob Clark wrote:
>> On Mon, Oct 7, 2013 at 10:18 AM, Ville Syrjälä
>> <ville.syrjala@linux.intel.com> wrote:
>> > On Mon, Oct 07, 2013 at 09:55:47AM -0400, Rob Clark wrote:
>> >> On Mon, Oct 7, 2013 at 9:28 AM, Ville Syrjälä
>> >> <ville.syrjala@linux.intel.com> wrote:
>> >> > On Sat, Oct 05, 2013 at 08:45:49PM -0400, Rob Clark wrote:
>> >> >> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> >> >>
>> >> >> The atomic modeset ioctl cna be used to push any number of new values
>> >> >> for object properties. The driver can then check the full device
>> >> >> configuration as single unit, and try to apply the changes atomically.
>> >> >>
>> >> >> The ioctl simply takes a list of object IDs and property IDs and their
>> >> >> values. For setting values to blob properties, the property value
>> >> >> indicates the length of the data, and the actual data is passed via
>> >> >> another blob pointer.
>> >> >>
>> >> >> The caller can demand non-blocking operation from the ioctl, and if the
>> >> >> driver can't satisfy that requirement an error will be returned.
>> >> >>
>> >> >> The caller can also request to receive asynchronous completion events
>> >> >> after the operation has reached the hardware. An event is sent for each
>> >> >> object specified by the caller, whether or not the actual state of
>> >> >> that object changed. Each event also carries a framebuffer ID, which
>> >> >> indicates to user space that the specified object is no longer
>> >> >> accessing that framebuffer.
>> >> >>
>> >> >> TODO: detailed error reporting?
>> >> >>
>> >> >> v1: original
>> >> >> v2: rebase on uapi changes, and drm state structs.. -- Rob Clark
>> >> >> v3: rebase, missing padding in drm_event_atomic.. -- Rob Clark
>> >> >>
>> >> >> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> >> >> ---
>> >> >>  drivers/gpu/drm/drm_crtc.c  | 159 ++++++++++++++++++++++++++++++++++++++++++++
>> >> >>  drivers/gpu/drm/drm_drv.c   |   1 +
>> >> >>  include/drm/drmP.h          |   6 ++
>> >> >>  include/drm/drm_crtc.h      |   2 +
>> >> >>  include/uapi/drm/drm.h      |  12 ++++
>> >> >>  include/uapi/drm/drm_mode.h |  16 +++++
>> >> >>  6 files changed, 196 insertions(+)
>> >> >>
>> >> >> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
>> >> >> index 09396a9..910e5c6 100644
>> >> >> --- a/drivers/gpu/drm/drm_crtc.c
>> >> >> +++ b/drivers/gpu/drm/drm_crtc.c
>> >> >> @@ -4338,3 +4338,162 @@ void drm_mode_config_cleanup(struct drm_device *dev)
>> >> >>       idr_destroy(&dev->mode_config.crtc_idr);
>> >> >>  }
>> >> >>  EXPORT_SYMBOL(drm_mode_config_cleanup);
>> >> >> +
>> >> >> +int drm_mode_atomic_ioctl(struct drm_device *dev,
>> >> >> +                       void *data, struct drm_file *file_priv)
>> >> >> +{
>> >> >> +     struct drm_mode_atomic *arg = data;
>> >> >> +     uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
>> >> >> +     uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
>> >> >> +     uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
>> >> >> +     uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
>> >> >> +     uint64_t __user *blob_values_ptr = (uint64_t __user *)(unsigned long)(arg->blob_values_ptr);
>> >> >> +     unsigned int copied_objs = 0;
>> >> >> +     unsigned int copied_props = 0;
>> >> >> +     unsigned int copied_blobs = 0;
>> >> >> +     void *state;
>> >> >> +     int ret = 0;
>> >> >> +     unsigned int i, j;
>> >> >> +
>> >> >> +     if (arg->flags & ~(DRM_MODE_ATOMIC_TEST_ONLY |
>> >> >> +                     DRM_MODE_ATOMIC_EVENT | DRM_MODE_ATOMIC_NONBLOCK))
>> >> >> +             return -EINVAL;
>> >> >> +
>> >> >> +     /* can't test and expect an event at the same time. */
>> >> >> +     if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
>> >> >> +                     (arg->flags & DRM_MODE_ATOMIC_EVENT))
>> >> >> +             return -EINVAL;
>> >> >> +
>> >> >> +     mutex_lock(&dev->mode_config.mutex);
>> >> >
>> >> > I'm pretty sure I had a version w/ fixed locking...
>> >> >
>> >> > git://gitorious.org/vsyrjala/linux.git rebased_drm_atomic_24
>> >>
>> >> oh, hmm.. actually the locking should no longer be in the ioctl fxn,
>> >> but should be pushed down to the commit.  looks like I missed this.  I
>> >> need to dig up some actual test code for atomic ioctl ;-)
>> >
>> > It can't be in commit. At the very least it has to be around
>> > check+commit, and also you need to hold some locks when you're copying
>> > the current config over to your temp storage. That's assuming you store
>> > _everything_ in the temp storage and so it doesn't matter if the current
>> > state can change between the copy and check+commit.
>> >
>>
>> hmm.. I start to wish we did atomic first, before the fine grained
>> locking re-work ;-)
>
> I don't see it mattering for this particular problem if we just grab
> the big lock anyway.
>
> But as I already stated, I would prefer to solve the plane locking
> before doing atomic. Whether we have per-plane locks or not can
> actually matter for this code, especially when dealing with planes
> that can move between crtcs.

right, and I think the only sane way to deal w/ per-plane locking is
ww_mutex..  but then at least for crtc move case we can just grab both
old and new crtc lock

> And we still have locking issues to solve in the .check+commit steps
> when we have to deal with shared resources across the entire device.
> We can't simply use some small local lock in the .check step since
> something relevant might have changed by the time we reach .commit.
> I guess we could re-check such things at the very start of commit,
> before we've clobbered any state, and then update the global state
> to match if everything looks good, before we again drop the local
> lock.

I suppose an easy thing would be per-dev atomic to generate sequence
#'s for state updates.. then it would be pretty easy to check if there
has been a state update since atomic_begin()..

>>
>> >>
>> >> >> +
>> >> >> +     state = dev->driver->atomic_begin(dev, arg->flags);
>> >> >> +     if (IS_ERR(state)) {
>> >> >> +             ret = PTR_ERR(state);
>> >> >> +             goto unlock;
>> >> >> +     }
>> >> >> +
>> >> >> +     for (i = 0; i < arg->count_objs; i++) {
>> >> >> +             uint32_t obj_id, count_props;
>> >> >> +             struct drm_mode_object *obj;
>> >> >> +
>> >> >> +             if (get_user(obj_id, objs_ptr + copied_objs)) {
>> >> >> +                     ret = -EFAULT;
>> >> >> +                     goto out;
>> >> >> +             }
>> >> >> +
>> >> >> +             obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY);
>> >> >> +             if (!obj || !obj->properties) {
>> >> >> +                     ret = -ENOENT;
>> >> >> +                     goto out;
>> >> >> +             }
>> >> >> +
>> >> >> +             if (arg->flags & DRM_MODE_ATOMIC_EVENT) {
>> >> >> +                     // XXX create atomic event instead..
>> >> >
>> >> > Some people are apparently more comfortable with a per-crtc event
>> >> > rather than the per-obj events I added. So I think we might want
>> >> > both in the end.
>> >>
>> >> yeah, sorting out events is a bit 'TODO' at the moment.  I do kind of
>> >> like per-crtc event.. it seems easier to implement and I'm not really
>> >> sure what finer event granularity buys us.
>> >
>> > Mainly it gets you the old fb. If you limit youself to < vrefresh it's
>> > not a big deal, but going faster than that and you start to want that
>> > information.
>> >
>>
>> oh, right.. well I guess it wouldn't be too hard to add the current
>> primary plane fb_id to the existing event, which might be sufficient.
>>
>> At any rate, I don't mind adding new event flags to atomic ioctl once
>> we get atomic in place.
>
> Yeah adding new events isn't that hard. We just need to make sure
> things make sense. The code you posted doesn't :P
>
> You add the event to every object, even though you only wanted one
> event per crtc. The same object could also be listed multiple times in
> the object list, so the code would even add multiple events for the
> same object.

yeah, current atomic patch is almost an afterthought in this series.
I still need to get planes working on msm and find some test code (I
guess you have some somewhere?)..  so other than just rebasing it
enough to compile, I didn't really spend any time on it yet.  Right
now I was more interested in getting folks to have a look at the
atomic funcs and helpers.

BR,
-R

>>
>> BR,
>> -R
>>
>> >>
>> >> BR,
>> >> -R
>> >>
>> >  >> +                     struct drm_pending_vblank_event *e =
>> >> >> +                             create_vblank_event(dev, file_priv, arg->user_data);
>> >> >> +                     if (!e) {
>> >> >> +                             ret = -ENOMEM;
>> >> >> +                             goto out;
>> >> >> +                     }
>> >> >> +                     ret = dev->driver->atomic_set_event(dev, state, obj, e);
>> >> >> +                     if (ret) {
>> >> >> +                             destroy_vblank_event(dev, file_priv, e);
>> >> >> +                             goto out;
>> >> >> +                     }
>> >> >> +             }
>> >> >> +
>> >> >> +             if (get_user(count_props, count_props_ptr + copied_objs)) {
>> >> >> +                     ret = -EFAULT;
>> >> >> +                     goto out;
>> >> >> +             }
>> >> >> +
>> >> >> +             copied_objs++;
>> >> >> +
>> >> >> +             for (j = 0; j < count_props; j++) {
>> >> >> +                     uint32_t prop_id;
>> >> >> +                     uint64_t prop_value;
>> >> >> +                     struct drm_mode_object *prop_obj;
>> >> >> +                     struct drm_property *prop;
>> >> >> +                     void *blob_data = NULL;
>> >> >> +
>> >> >> +                     if (get_user(prop_id, props_ptr + copied_props)) {
>> >> >> +                             ret = -EFAULT;
>> >> >> +                             goto out;
>> >> >> +                     }
>> >> >> +
>> >> >> +                     if (!object_has_prop(obj, prop_id)) {
>> >> >> +                             ret = -EINVAL;
>> >> >> +                             goto out;
>> >> >> +                     }
>> >> >> +
>> >> >> +                     prop_obj = drm_mode_object_find(dev, prop_id,
>> >> >> +                                     DRM_MODE_OBJECT_PROPERTY);
>> >> >> +                     if (!prop_obj) {
>> >> >> +                             ret = -ENOENT;
>> >> >> +                             goto out;
>> >> >> +                     }
>> >> >> +                     prop = obj_to_property(prop_obj);
>> >> >> +
>> >> >> +                     if (get_user(prop_value, prop_values_ptr + copied_props)) {
>> >> >> +                             ret = -EFAULT;
>> >> >> +                             goto out;
>> >> >> +                     }
>> >> >> +
>> >> >> +                     if (!drm_property_change_is_valid(prop, prop_value)) {
>> >> >> +                             ret = -EINVAL;
>> >> >> +                             goto out;
>> >> >> +                     }
>> >> >> +
>> >> >> +                     if ((prop->flags & DRM_MODE_PROP_BLOB) && prop_value) {
>> >> >> +                             uint64_t blob_ptr;
>> >> >> +
>> >> >> +                             if (get_user(blob_ptr, blob_values_ptr + copied_blobs)) {
>> >> >> +                                     ret = -EFAULT;
>> >> >> +                                     goto out;
>> >> >> +                             }
>> >> >> +
>> >> >> +                             blob_data = kmalloc(prop_value, GFP_KERNEL);
>> >> >> +                             if (!blob_data) {
>> >> >> +                                     ret = -ENOMEM;
>> >> >> +                                     goto out;
>> >> >> +                             }
>> >> >> +
>> >> >> +                             if (copy_from_user(blob_data, (void __user *)(unsigned long)blob_ptr, prop_value)) {
>> >> >> +                                     kfree(blob_data);
>> >> >> +                                     ret = -EFAULT;
>> >> >> +                                     goto out;
>> >> >> +                             }
>> >> >> +                     }
>> >> >> +
>> >> >> +                     /* User space sends the blob pointer even if we
>> >> >> +                      * don't use it (length==0).
>> >> >> +                      */
>> >> >> +                     if (prop->flags & DRM_MODE_PROP_BLOB)
>> >> >> +                             copied_blobs++;
>> >> >> +
>> >> >> +                     /* The driver will be in charge of blob_data from now on. */
>> >> >> +                     ret = drm_mode_set_obj_prop(obj, state, prop,
>> >> >> +                                     prop_value, blob_data);
>> >> >> +                     if (ret)
>> >> >> +                             goto out;
>> >> >> +
>> >> >> +                     copied_props++;
>> >> >> +             }
>> >> >> +     }
>> >> >> +
>> >> >> +     ret = dev->driver->atomic_check(dev, state);
>> >> >> +     if (ret)
>> >> >> +             goto out;
>> >> >> +
>> >> >> +     if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
>> >> >> +             goto out;
>> >> >> +
>> >> >> +     ret = dev->driver->atomic_commit(dev, state);
>> >> >> +
>> >> >> + out:
>> >> >> +     dev->driver->atomic_end(dev, state);
>> >> >> + unlock:
>> >> >> +     mutex_unlock(&dev->mode_config.mutex);
>> >> >> +
>> >> >> +     return ret;
>> >> >> +}
>> >> >> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
>> >> >> index e572dd2..43e04ae 100644
>> >> >> --- a/drivers/gpu/drm/drm_drv.c
>> >> >> +++ b/drivers/gpu/drm/drm_drv.c
>> >> >> @@ -166,6 +166,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
>> >> >>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>> >> >>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>> >> >>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>> >> >> +     DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>> >> >>  };
>> >> >>
>> >> >>  #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
>> >> >> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
>> >> >> index 4c3de22..f282733 100644
>> >> >> --- a/include/drm/drmP.h
>> >> >> +++ b/include/drm/drmP.h
>> >> >> @@ -1158,6 +1158,12 @@ struct drm_pending_vblank_event {
>> >> >>       struct drm_event_vblank event;
>> >> >>  };
>> >> >>
>> >> >> +struct drm_pending_atomic_event {
>> >> >> +     struct drm_pending_event base;
>> >> >> +     int pipe;
>> >> >> +     struct drm_event_atomic event;
>> >> >> +};
>> >> >> +
>> >> >>  /**
>> >> >>   * DRM device structure. This structure represent a complete card that
>> >> >>   * may contain multiple heads.
>> >> >> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
>> >> >> index 86a5a00..fa3956e 100644
>> >> >> --- a/include/drm/drm_crtc.h
>> >> >> +++ b/include/drm/drm_crtc.h
>> >> >> @@ -1313,6 +1313,8 @@ extern int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
>> >> >>                                            struct drm_file *file_priv);
>> >> >>  extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
>> >> >>                                          struct drm_file *file_priv);
>> >> >> +extern int drm_mode_atomic_ioctl(struct drm_device *dev,
>> >> >> +                              void *data, struct drm_file *file_priv);
>> >> >>
>> >> >>  extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
>> >> >>                                int *bpp);
>> >> >> diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
>> >> >> index ece8678..efb1461 100644
>> >> >> --- a/include/uapi/drm/drm.h
>> >> >> +++ b/include/uapi/drm/drm.h
>> >> >> @@ -733,6 +733,7 @@ struct drm_prime_handle {
>> >> >>  #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES     DRM_IOWR(0xB9, struct drm_mode_obj_get_properties)
>> >> >>  #define DRM_IOCTL_MODE_OBJ_SETPROPERTY       DRM_IOWR(0xBA, struct drm_mode_obj_set_property)
>> >> >>  #define DRM_IOCTL_MODE_CURSOR2               DRM_IOWR(0xBB, struct drm_mode_cursor2)
>> >> >> +#define DRM_IOCTL_MODE_ATOMIC                DRM_IOWR(0xBC, struct drm_mode_atomic)
>> >> >>
>> >> >>  /**
>> >> >>   * Device specific ioctls should only be in their respective headers
>> >> >> @@ -774,6 +775,17 @@ struct drm_event_vblank {
>> >> >>       __u32 reserved;
>> >> >>  };
>> >> >>
>> >> >> +struct drm_event_atomic {
>> >> >> +     struct drm_event base;
>> >> >> +     __u64 user_data;
>> >> >> +     __u32 tv_sec;
>> >> >> +     __u32 tv_usec;
>> >> >> +     __u32 sequence;
>> >> >> +     __u32 obj_id;
>> >> >> +     __u32 old_fb_id;
>> >> >> +     __u32 reserved;
>> >> >> +};
>> >> >> +
>> >> >>  #define DRM_CAP_DUMB_BUFFER 0x1
>> >> >>  #define DRM_CAP_VBLANK_HIGH_CRTC 0x2
>> >> >>  #define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3
>> >> >> diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
>> >> >> index 6d4f089..03a473c 100644
>> >> >> --- a/include/uapi/drm/drm_mode.h
>> >> >> +++ b/include/uapi/drm/drm_mode.h
>> >> >> @@ -489,4 +489,20 @@ struct drm_mode_destroy_dumb {
>> >> >>       uint32_t handle;
>> >> >>  };
>> >> >>
>> >> >> +#define DRM_MODE_ATOMIC_TEST_ONLY (1<<0)
>> >> >> +#define DRM_MODE_ATOMIC_EVENT (1<<1)
>> >> >> +#define DRM_MODE_ATOMIC_NONBLOCK (1<<2)
>> >> >> +
>> >> >> +/* FIXME come up with some sane error reporting mechanism? */
>> >> >> +struct drm_mode_atomic {
>> >> >> +     __u32 flags;
>> >> >> +     __u32 count_objs;
>> >> >> +     __u64 objs_ptr;
>> >> >> +     __u64 count_props_ptr;
>> >> >> +     __u64 props_ptr;
>> >> >> +     __u64 prop_values_ptr;
>> >> >> +     __u64 blob_values_ptr;
>> >> >> +     __u64 user_data;
>> >> >> +};
>> >> >> +
>> >> >>  #endif
>> >> >> --
>> >> >> 1.8.3.1
>> >> >
>> >> > --
>> >> > Ville Syrjälä
>> >> > Intel OTC
>> >
>> > --
>> > Ville Syrjälä
>> > Intel OTC
>
> --
> Ville Syrjälä
> Intel OTC

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 10/12] drm: convert crtc to properties/state
  2013-10-07 14:29         ` Rob Clark
@ 2013-10-07 17:51           ` Daniel Vetter
  0 siblings, 0 replies; 38+ messages in thread
From: Daniel Vetter @ 2013-10-07 17:51 UTC (permalink / raw)
  To: Rob Clark; +Cc: dri-devel

On Mon, Oct 07, 2013 at 10:29:06AM -0400, Rob Clark wrote:
> On Mon, Oct 7, 2013 at 10:19 AM, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> > On Mon, Oct 07, 2013 at 10:03:01AM -0400, Rob Clark wrote:
> >> On Mon, Oct 7, 2013 at 9:39 AM, Ville Syrjälä
> >> <ville.syrjala@linux.intel.com> wrote:
> >> > On Sat, Oct 05, 2013 at 08:45:48PM -0400, Rob Clark wrote:
> >> >> Break the mutable state of a crtc out into a separate structure
> >> >> and use atomic properties mechanism to set crtc attributes.  This
> >> >> makes it easier to have some helpers for crtc->set_property()
> >> >> and for checking for invalid params.  The idea is that individual
> >> >> drivers can wrap the state struct in their own struct which adds
> >> >> driver specific parameters, for easy build-up of state across
> >> >> multiple set_property() calls and for easy atomic commit or roll-
> >> >> back.
> >> >
> >> > I'm not sure how we're going to handle the mismatch in the behaviour of
> >> > the atomic modeset vs. the current setcrtc.
> >> >
> >> > The problem is that setcrtc ignore all kinds of conflicting
> >> > crtc->connector assignments, and just overwrites whatever was there
> >> > with the latest configuration. For the atomic case we want to return an
> >> > error if there's a conflict.
> >>
> >> Hmm, well currently we preserve the setcrtc behavior because it ends
> >> up going through crtc helpers (or whatever the driver uses).  So
> >> should be fine for setcrtc, but probably not what we want for atomic
> >> ioctl.
> >>
> >> I suppose we could solve some of this via internal flags, ie
> >> .atomic_begin(dev, LEGACY_SETCRTC_CHECK_MODE)
> >>
> >> it is a bit ugly, but it keeps the ugly in core and drivers don't have
> >> to care as much about it (which is my main concern)
> >
> > Well, it could be an entirely separate .legacy_crap() hook or something
> > that happens just before .check().
> 
> yeah, that could work too.. I'll think about it a bit and see what I
> can come up with

Why can't the legacy setcrtc ioctl implemenation just fiddle the current
state out of the connector/encoder pointers and then make a relevant
atomic call? So if it notices that some connectors would be disabled it
just adds an explicit clearing of the connector->crtc link  to the atomic
request.

> >> > And another thing is the DPMS handling. The
> >> > current API forces DPMS on when you do a modeset, but for the atomic
> >> > case I want to keep things nice and clean and avoid doing such silly
> >> > things.
> >>
> >> I guess the easy thing is to set DPMS property in setcrtc too ;-)
> >
> > That's what we do, but I don't want it for atomic.
> 
> yeah, I need think about how that could work if we are still using
> .set_config() from the commit, but I guess I should be able to sort
> out something..

Similarly here the legacy setcrtc simply needs to supply a dpms=ON request
for all connectors that are in the setcrtc request.

With those changes drivers can get rid of these hacks and legacy ioctl
quirks internally and we consolidate them into one single place ...

The real crux here is getting legacy pageflip semantics out of the new
interface. In any case I think if we're left with some non-helper
set_cursor, set_plane, setfoo/bar from yonder the new atomic interface is
probably not good enough. After all anything that current userspace does
with these ioctls it probably wants to keep on doing in the new world. So
imo making sure that all the old ioctls work in terms of the new driver
interface is a nice real-world test of their suitability.

Cheers, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 11/12] drm: Atomic modeset ioctl
  2013-10-07 15:20             ` Rob Clark
@ 2013-10-07 17:56               ` Daniel Vetter
  2013-10-07 18:49                 ` Rob Clark
  0 siblings, 1 reply; 38+ messages in thread
From: Daniel Vetter @ 2013-10-07 17:56 UTC (permalink / raw)
  To: Rob Clark; +Cc: dri-devel

On Mon, Oct 07, 2013 at 11:20:54AM -0400, Rob Clark wrote:
> yeah, current atomic patch is almost an afterthought in this series.
> I still need to get planes working on msm and find some test code (I
> guess you have some somewhere?)..  so other than just rebasing it
> enough to compile, I didn't really spend any time on it yet.  Right
> now I was more interested in getting folks to have a look at the
> atomic funcs and helpers.

One in-kernel test user we have is the fbdev restore code - it needs to
get rid of all planes, cursors and set up its new config on all crtcs. I
think this would be a fairly nice (albeit really basic testcase): You can
set up a bunch of planes/cursors, then vt-switch to the fbcon - this way
we can exercise the atomic stuff in drivers a bit better even without
needing to add any ioctl.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 11/12] drm: Atomic modeset ioctl
  2013-10-07 17:56               ` Daniel Vetter
@ 2013-10-07 18:49                 ` Rob Clark
  0 siblings, 0 replies; 38+ messages in thread
From: Rob Clark @ 2013-10-07 18:49 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

On Mon, Oct 7, 2013 at 1:56 PM, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Mon, Oct 07, 2013 at 11:20:54AM -0400, Rob Clark wrote:
>> yeah, current atomic patch is almost an afterthought in this series.
>> I still need to get planes working on msm and find some test code (I
>> guess you have some somewhere?)..  so other than just rebasing it
>> enough to compile, I didn't really spend any time on it yet.  Right
>> now I was more interested in getting folks to have a look at the
>> atomic funcs and helpers.
>
> One in-kernel test user we have is the fbdev restore code - it needs to
> get rid of all planes, cursors and set up its new config on all crtcs. I
> think this would be a fairly nice (albeit really basic testcase): You can
> set up a bunch of planes/cursors, then vt-switch to the fbcon - this way
> we can exercise the atomic stuff in drivers a bit better even without
> needing to add any ioctl.

right..  well, we do have code that disables the planes on fbdev
restore, and fbdev restore (and initial modeset) still hit
crtc->set_config directly.  But once those are converted it would be
cleaner / more elegant to do fbdev restore w/ atomic.

BR,
-R

> -Daniel
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 11/12] drm: Atomic modeset ioctl
  2013-10-07 14:18       ` Ville Syrjälä
  2013-10-07 14:39         ` Rob Clark
@ 2013-10-08 18:35         ` Matt Roper
  2013-10-08 18:46           ` Rob Clark
  1 sibling, 1 reply; 38+ messages in thread
From: Matt Roper @ 2013-10-08 18:35 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: dri-devel

On Mon, Oct 07, 2013 at 05:18:02PM +0300, Ville Syrjälä wrote:
> On Mon, Oct 07, 2013 at 09:55:47AM -0400, Rob Clark wrote:
> > On Mon, Oct 7, 2013 at 9:28 AM, Ville Syrjälä
> > <ville.syrjala@linux.intel.com> wrote:
> > > On Sat, Oct 05, 2013 at 08:45:49PM -0400, Rob Clark wrote:
...
> > >> +
> > >> +     state = dev->driver->atomic_begin(dev, arg->flags);
> > >> +     if (IS_ERR(state)) {
> > >> +             ret = PTR_ERR(state);
> > >> +             goto unlock;
> > >> +     }
> > >> +
> > >> +     for (i = 0; i < arg->count_objs; i++) {
> > >> +             uint32_t obj_id, count_props;
> > >> +             struct drm_mode_object *obj;
> > >> +
> > >> +             if (get_user(obj_id, objs_ptr + copied_objs)) {
> > >> +                     ret = -EFAULT;
> > >> +                     goto out;
> > >> +             }
> > >> +
> > >> +             obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY);
> > >> +             if (!obj || !obj->properties) {
> > >> +                     ret = -ENOENT;
> > >> +                     goto out;
> > >> +             }
> > >> +
> > >> +             if (arg->flags & DRM_MODE_ATOMIC_EVENT) {
> > >> +                     // XXX create atomic event instead..
> > >
> > > Some people are apparently more comfortable with a per-crtc event
> > > rather than the per-obj events I added. So I think we might want
> > > both in the end.
> > 
> > yeah, sorting out events is a bit 'TODO' at the moment.  I do kind of
> > like per-crtc event.. it seems easier to implement and I'm not really
> > sure what finer event granularity buys us.
> 
> Mainly it gets you the old fb. If you limit youself to < vrefresh it's
> not a big deal, but going faster than that and you start to want that
> information.

Are there cases where userspace would really need this fb information
returned?  I'm having trouble envisioning a case where userspace
wouldn't have its own bookkeeping to know which fb's are currently
displayed on each plane and which fb's are pending.

If you're running a compositor like Weston, the redraw of a display is
generally tied to completion events, so there's no real desire/potential
for > vrefresh submission in most cases.  In this model, having a single
per-crtc "I'm done updating everything" event is easier to work with
than an event per object where you have to do some additional counting
to make sure you consume the right number of events before kicking off
the repaint.


> 
> > 
> > BR,
> > -R
> > 
>  >> +                     struct drm_pending_vblank_event *e =
> > >> +                             create_vblank_event(dev, file_priv, arg->user_data);
> > >> +                     if (!e) {
> > >> +                             ret = -ENOMEM;
> > >> +                             goto out;
> > >> +                     }
> > >> +                     ret = dev->driver->atomic_set_event(dev, state, obj, e);
> > >> +                     if (ret) {
> > >> +                             destroy_vblank_event(dev, file_priv, e);
> > >> +                             goto out;
> > >> +                     }
> > >> +             }

Did you mean to use the drm_pending_atomic_event/drm_event_atomic you
declare farther down?  It doesn't look like anything is actually using
them yet in this patch series.

> > >> +
> > >> +             if (get_user(count_props, count_props_ptr + copied_objs)) {
> > >> +                     ret = -EFAULT;
> > >> +                     goto out;
> > >> +             }
> > >> +
> > >> +             copied_objs++;
> > >> +
> > >> +             for (j = 0; j < count_props; j++) {
> > >> +                     uint32_t prop_id;
> > >> +                     uint64_t prop_value;
> > >> +                     struct drm_mode_object *prop_obj;
> > >> +                     struct drm_property *prop;
> > >> +                     void *blob_data = NULL;
> > >> +
> > >> +                     if (get_user(prop_id, props_ptr + copied_props)) {
> > >> +                             ret = -EFAULT;
> > >> +                             goto out;
> > >> +                     }
> > >> +
> > >> +                     if (!object_has_prop(obj, prop_id)) {
> > >> +                             ret = -EINVAL;
> > >> +                             goto out;
> > >> +                     }
> > >> +
> > >> +                     prop_obj = drm_mode_object_find(dev, prop_id,
> > >> +                                     DRM_MODE_OBJECT_PROPERTY);
> > >> +                     if (!prop_obj) {
> > >> +                             ret = -ENOENT;
> > >> +                             goto out;
> > >> +                     }
> > >> +                     prop = obj_to_property(prop_obj);
> > >> +
> > >> +                     if (get_user(prop_value, prop_values_ptr + copied_props)) {
> > >> +                             ret = -EFAULT;
> > >> +                             goto out;
> > >> +                     }
> > >> +
> > >> +                     if (!drm_property_change_is_valid(prop, prop_value)) {
> > >> +                             ret = -EINVAL;
> > >> +                             goto out;
> > >> +                     }
> > >> +
> > >> +                     if ((prop->flags & DRM_MODE_PROP_BLOB) && prop_value) {
> > >> +                             uint64_t blob_ptr;
> > >> +
> > >> +                             if (get_user(blob_ptr, blob_values_ptr + copied_blobs)) {
> > >> +                                     ret = -EFAULT;
> > >> +                                     goto out;
> > >> +                             }
> > >> +
> > >> +                             blob_data = kmalloc(prop_value, GFP_KERNEL);
> > >> +                             if (!blob_data) {
> > >> +                                     ret = -ENOMEM;
> > >> +                                     goto out;
> > >> +                             }
> > >> +
> > >> +                             if (copy_from_user(blob_data, (void __user *)(unsigned long)blob_ptr, prop_value)) {
> > >> +                                     kfree(blob_data);
> > >> +                                     ret = -EFAULT;
> > >> +                                     goto out;
> > >> +                             }
> > >> +                     }
> > >> +
> > >> +                     /* User space sends the blob pointer even if we
> > >> +                      * don't use it (length==0).
> > >> +                      */
> > >> +                     if (prop->flags & DRM_MODE_PROP_BLOB)
> > >> +                             copied_blobs++;
> > >> +
> > >> +                     /* The driver will be in charge of blob_data from now on. */
> > >> +                     ret = drm_mode_set_obj_prop(obj, state, prop,
> > >> +                                     prop_value, blob_data);
> > >> +                     if (ret)
> > >> +                             goto out;
> > >> +
> > >> +                     copied_props++;
> > >> +             }
> > >> +     }
> > >> +
> > >> +     ret = dev->driver->atomic_check(dev, state);
> > >> +     if (ret)
> > >> +             goto out;
> > >> +
> > >> +     if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
> > >> +             goto out;
> > >> +
> > >> +     ret = dev->driver->atomic_commit(dev, state);
> > >> +
> > >> + out:
> > >> +     dev->driver->atomic_end(dev, state);
> > >> + unlock:
> > >> +     mutex_unlock(&dev->mode_config.mutex);
> > >> +
> > >> +     return ret;
> > >> +}
> > >> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
> > >> index e572dd2..43e04ae 100644
> > >> --- a/drivers/gpu/drm/drm_drv.c
> > >> +++ b/drivers/gpu/drm/drm_drv.c
> > >> @@ -166,6 +166,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
> > >>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> > >>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> > >>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> > >> +     DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> > >>  };
> > >>
> > >>  #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
> > >> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
> > >> index 4c3de22..f282733 100644
> > >> --- a/include/drm/drmP.h
> > >> +++ b/include/drm/drmP.h
> > >> @@ -1158,6 +1158,12 @@ struct drm_pending_vblank_event {
> > >>       struct drm_event_vblank event;
> > >>  };
> > >>
> > >> +struct drm_pending_atomic_event {
> > >> +     struct drm_pending_event base;
> > >> +     int pipe;
> > >> +     struct drm_event_atomic event;
> > >> +};
> > >> +
> > >>  /**
> > >>   * DRM device structure. This structure represent a complete card that
> > >>   * may contain multiple heads.
> > >> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> > >> index 86a5a00..fa3956e 100644
> > >> --- a/include/drm/drm_crtc.h
> > >> +++ b/include/drm/drm_crtc.h
> > >> @@ -1313,6 +1313,8 @@ extern int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
> > >>                                            struct drm_file *file_priv);
> > >>  extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
> > >>                                          struct drm_file *file_priv);
> > >> +extern int drm_mode_atomic_ioctl(struct drm_device *dev,
> > >> +                              void *data, struct drm_file *file_priv);
> > >>
> > >>  extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
> > >>                                int *bpp);
> > >> diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
> > >> index ece8678..efb1461 100644
> > >> --- a/include/uapi/drm/drm.h
> > >> +++ b/include/uapi/drm/drm.h
> > >> @@ -733,6 +733,7 @@ struct drm_prime_handle {
> > >>  #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES     DRM_IOWR(0xB9, struct drm_mode_obj_get_properties)
> > >>  #define DRM_IOCTL_MODE_OBJ_SETPROPERTY       DRM_IOWR(0xBA, struct drm_mode_obj_set_property)
> > >>  #define DRM_IOCTL_MODE_CURSOR2               DRM_IOWR(0xBB, struct drm_mode_cursor2)
> > >> +#define DRM_IOCTL_MODE_ATOMIC                DRM_IOWR(0xBC, struct drm_mode_atomic)
> > >>
> > >>  /**
> > >>   * Device specific ioctls should only be in their respective headers
> > >> @@ -774,6 +775,17 @@ struct drm_event_vblank {
> > >>       __u32 reserved;
> > >>  };
> > >>
> > >> +struct drm_event_atomic {
> > >> +     struct drm_event base;
> > >> +     __u64 user_data;
> > >> +     __u32 tv_sec;
> > >> +     __u32 tv_usec;
> > >> +     __u32 sequence;
> > >> +     __u32 obj_id;
> > >> +     __u32 old_fb_id;
> > >> +     __u32 reserved;
> > >> +};
> > >> +
> > >>  #define DRM_CAP_DUMB_BUFFER 0x1
> > >>  #define DRM_CAP_VBLANK_HIGH_CRTC 0x2
> > >>  #define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3
> > >> diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
> > >> index 6d4f089..03a473c 100644
> > >> --- a/include/uapi/drm/drm_mode.h
> > >> +++ b/include/uapi/drm/drm_mode.h
> > >> @@ -489,4 +489,20 @@ struct drm_mode_destroy_dumb {
> > >>       uint32_t handle;
> > >>  };
> > >>
> > >> +#define DRM_MODE_ATOMIC_TEST_ONLY (1<<0)
> > >> +#define DRM_MODE_ATOMIC_EVENT (1<<1)
> > >> +#define DRM_MODE_ATOMIC_NONBLOCK (1<<2)
> > >> +
> > >> +/* FIXME come up with some sane error reporting mechanism? */
> > >> +struct drm_mode_atomic {
> > >> +     __u32 flags;
> > >> +     __u32 count_objs;
> > >> +     __u64 objs_ptr;
> > >> +     __u64 count_props_ptr;
> > >> +     __u64 props_ptr;
> > >> +     __u64 prop_values_ptr;
> > >> +     __u64 blob_values_ptr;
> > >> +     __u64 user_data;
> > >> +};
> > >> +
> > >>  #endif
> > >> --
> > >> 1.8.3.1
> > >
> > > --
> > > Ville Syrjälä
> > > Intel OTC
> 
> -- 
> Ville Syrjälä
> Intel OTC
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Matt Roper
Intel Corporation
Embedded Media & Graphics Driver Group
(916) 356-2795

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFCv1 11/12] drm: Atomic modeset ioctl
  2013-10-08 18:35         ` Matt Roper
@ 2013-10-08 18:46           ` Rob Clark
  0 siblings, 0 replies; 38+ messages in thread
From: Rob Clark @ 2013-10-08 18:46 UTC (permalink / raw)
  To: Matt Roper; +Cc: dri-devel

On Tue, Oct 8, 2013 at 2:35 PM, Matt Roper <matthew.d.roper@intel.com> wrote:
> On Mon, Oct 07, 2013 at 05:18:02PM +0300, Ville Syrjälä wrote:
>> On Mon, Oct 07, 2013 at 09:55:47AM -0400, Rob Clark wrote:
>> > On Mon, Oct 7, 2013 at 9:28 AM, Ville Syrjälä
>> > <ville.syrjala@linux.intel.com> wrote:
>> > > On Sat, Oct 05, 2013 at 08:45:49PM -0400, Rob Clark wrote:
> ...
>> > >> +
>> > >> +     state = dev->driver->atomic_begin(dev, arg->flags);
>> > >> +     if (IS_ERR(state)) {
>> > >> +             ret = PTR_ERR(state);
>> > >> +             goto unlock;
>> > >> +     }
>> > >> +
>> > >> +     for (i = 0; i < arg->count_objs; i++) {
>> > >> +             uint32_t obj_id, count_props;
>> > >> +             struct drm_mode_object *obj;
>> > >> +
>> > >> +             if (get_user(obj_id, objs_ptr + copied_objs)) {
>> > >> +                     ret = -EFAULT;
>> > >> +                     goto out;
>> > >> +             }
>> > >> +
>> > >> +             obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY);
>> > >> +             if (!obj || !obj->properties) {
>> > >> +                     ret = -ENOENT;
>> > >> +                     goto out;
>> > >> +             }
>> > >> +
>> > >> +             if (arg->flags & DRM_MODE_ATOMIC_EVENT) {
>> > >> +                     // XXX create atomic event instead..
>> > >
>> > > Some people are apparently more comfortable with a per-crtc event
>> > > rather than the per-obj events I added. So I think we might want
>> > > both in the end.
>> >
>> > yeah, sorting out events is a bit 'TODO' at the moment.  I do kind of
>> > like per-crtc event.. it seems easier to implement and I'm not really
>> > sure what finer event granularity buys us.
>>
>> Mainly it gets you the old fb. If you limit youself to < vrefresh it's
>> not a big deal, but going faster than that and you start to want that
>> information.
>
> Are there cases where userspace would really need this fb information
> returned?  I'm having trouble envisioning a case where userspace
> wouldn't have its own bookkeeping to know which fb's are currently
> displayed on each plane and which fb's are pending.

if you let userspace flip faster than vsync, then there is some
ambiguity about which buffer is being scanned out after the vblank..

but I think this shouldn't hold up atomic-modeset.. it should be safe
to spiff up the events as a later step.

> If you're running a compositor like Weston, the redraw of a display is
> generally tied to completion events, so there's no real desire/potential
> for > vrefresh submission in most cases.  In this model, having a single
> per-crtc "I'm done updating everything" event is easier to work with
> than an event per object where you have to do some additional counting
> to make sure you consume the right number of events before kicking off
> the repaint.
>
>
>>
>> >
>> > BR,
>> > -R
>> >
>>  >> +                     struct drm_pending_vblank_event *e =
>> > >> +                             create_vblank_event(dev, file_priv, arg->user_data);
>> > >> +                     if (!e) {
>> > >> +                             ret = -ENOMEM;
>> > >> +                             goto out;
>> > >> +                     }
>> > >> +                     ret = dev->driver->atomic_set_event(dev, state, obj, e);
>> > >> +                     if (ret) {
>> > >> +                             destroy_vblank_event(dev, file_priv, e);
>> > >> +                             goto out;
>> > >> +                     }
>> > >> +             }
>
> Did you mean to use the drm_pending_atomic_event/drm_event_atomic you
> declare farther down?  It doesn't look like anything is actually using
> them yet in this patch series.

right.. the event stuff is a bit messy at the moment as result of
merging of two different RFC patchsets about how to do atomic.

I think what I will end up doing is drop the atomic event, and fix up
the logic to only create/set vblank events for the crtc(s).

BR,
-R

>> > >> +
>> > >> +             if (get_user(count_props, count_props_ptr + copied_objs)) {
>> > >> +                     ret = -EFAULT;
>> > >> +                     goto out;
>> > >> +             }
>> > >> +
>> > >> +             copied_objs++;
>> > >> +
>> > >> +             for (j = 0; j < count_props; j++) {
>> > >> +                     uint32_t prop_id;
>> > >> +                     uint64_t prop_value;
>> > >> +                     struct drm_mode_object *prop_obj;
>> > >> +                     struct drm_property *prop;
>> > >> +                     void *blob_data = NULL;
>> > >> +
>> > >> +                     if (get_user(prop_id, props_ptr + copied_props)) {
>> > >> +                             ret = -EFAULT;
>> > >> +                             goto out;
>> > >> +                     }
>> > >> +
>> > >> +                     if (!object_has_prop(obj, prop_id)) {
>> > >> +                             ret = -EINVAL;
>> > >> +                             goto out;
>> > >> +                     }
>> > >> +
>> > >> +                     prop_obj = drm_mode_object_find(dev, prop_id,
>> > >> +                                     DRM_MODE_OBJECT_PROPERTY);
>> > >> +                     if (!prop_obj) {
>> > >> +                             ret = -ENOENT;
>> > >> +                             goto out;
>> > >> +                     }
>> > >> +                     prop = obj_to_property(prop_obj);
>> > >> +
>> > >> +                     if (get_user(prop_value, prop_values_ptr + copied_props)) {
>> > >> +                             ret = -EFAULT;
>> > >> +                             goto out;
>> > >> +                     }
>> > >> +
>> > >> +                     if (!drm_property_change_is_valid(prop, prop_value)) {
>> > >> +                             ret = -EINVAL;
>> > >> +                             goto out;
>> > >> +                     }
>> > >> +
>> > >> +                     if ((prop->flags & DRM_MODE_PROP_BLOB) && prop_value) {
>> > >> +                             uint64_t blob_ptr;
>> > >> +
>> > >> +                             if (get_user(blob_ptr, blob_values_ptr + copied_blobs)) {
>> > >> +                                     ret = -EFAULT;
>> > >> +                                     goto out;
>> > >> +                             }
>> > >> +
>> > >> +                             blob_data = kmalloc(prop_value, GFP_KERNEL);
>> > >> +                             if (!blob_data) {
>> > >> +                                     ret = -ENOMEM;
>> > >> +                                     goto out;
>> > >> +                             }
>> > >> +
>> > >> +                             if (copy_from_user(blob_data, (void __user *)(unsigned long)blob_ptr, prop_value)) {
>> > >> +                                     kfree(blob_data);
>> > >> +                                     ret = -EFAULT;
>> > >> +                                     goto out;
>> > >> +                             }
>> > >> +                     }
>> > >> +
>> > >> +                     /* User space sends the blob pointer even if we
>> > >> +                      * don't use it (length==0).
>> > >> +                      */
>> > >> +                     if (prop->flags & DRM_MODE_PROP_BLOB)
>> > >> +                             copied_blobs++;
>> > >> +
>> > >> +                     /* The driver will be in charge of blob_data from now on. */
>> > >> +                     ret = drm_mode_set_obj_prop(obj, state, prop,
>> > >> +                                     prop_value, blob_data);
>> > >> +                     if (ret)
>> > >> +                             goto out;
>> > >> +
>> > >> +                     copied_props++;
>> > >> +             }
>> > >> +     }
>> > >> +
>> > >> +     ret = dev->driver->atomic_check(dev, state);
>> > >> +     if (ret)
>> > >> +             goto out;
>> > >> +
>> > >> +     if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
>> > >> +             goto out;
>> > >> +
>> > >> +     ret = dev->driver->atomic_commit(dev, state);
>> > >> +
>> > >> + out:
>> > >> +     dev->driver->atomic_end(dev, state);
>> > >> + unlock:
>> > >> +     mutex_unlock(&dev->mode_config.mutex);
>> > >> +
>> > >> +     return ret;
>> > >> +}
>> > >> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
>> > >> index e572dd2..43e04ae 100644
>> > >> --- a/drivers/gpu/drm/drm_drv.c
>> > >> +++ b/drivers/gpu/drm/drm_drv.c
>> > >> @@ -166,6 +166,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
>> > >>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>> > >>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>> > >>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>> > >> +     DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>> > >>  };
>> > >>
>> > >>  #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
>> > >> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
>> > >> index 4c3de22..f282733 100644
>> > >> --- a/include/drm/drmP.h
>> > >> +++ b/include/drm/drmP.h
>> > >> @@ -1158,6 +1158,12 @@ struct drm_pending_vblank_event {
>> > >>       struct drm_event_vblank event;
>> > >>  };
>> > >>
>> > >> +struct drm_pending_atomic_event {
>> > >> +     struct drm_pending_event base;
>> > >> +     int pipe;
>> > >> +     struct drm_event_atomic event;
>> > >> +};
>> > >> +
>> > >>  /**
>> > >>   * DRM device structure. This structure represent a complete card that
>> > >>   * may contain multiple heads.
>> > >> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
>> > >> index 86a5a00..fa3956e 100644
>> > >> --- a/include/drm/drm_crtc.h
>> > >> +++ b/include/drm/drm_crtc.h
>> > >> @@ -1313,6 +1313,8 @@ extern int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
>> > >>                                            struct drm_file *file_priv);
>> > >>  extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
>> > >>                                          struct drm_file *file_priv);
>> > >> +extern int drm_mode_atomic_ioctl(struct drm_device *dev,
>> > >> +                              void *data, struct drm_file *file_priv);
>> > >>
>> > >>  extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
>> > >>                                int *bpp);
>> > >> diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
>> > >> index ece8678..efb1461 100644
>> > >> --- a/include/uapi/drm/drm.h
>> > >> +++ b/include/uapi/drm/drm.h
>> > >> @@ -733,6 +733,7 @@ struct drm_prime_handle {
>> > >>  #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES     DRM_IOWR(0xB9, struct drm_mode_obj_get_properties)
>> > >>  #define DRM_IOCTL_MODE_OBJ_SETPROPERTY       DRM_IOWR(0xBA, struct drm_mode_obj_set_property)
>> > >>  #define DRM_IOCTL_MODE_CURSOR2               DRM_IOWR(0xBB, struct drm_mode_cursor2)
>> > >> +#define DRM_IOCTL_MODE_ATOMIC                DRM_IOWR(0xBC, struct drm_mode_atomic)
>> > >>
>> > >>  /**
>> > >>   * Device specific ioctls should only be in their respective headers
>> > >> @@ -774,6 +775,17 @@ struct drm_event_vblank {
>> > >>       __u32 reserved;
>> > >>  };
>> > >>
>> > >> +struct drm_event_atomic {
>> > >> +     struct drm_event base;
>> > >> +     __u64 user_data;
>> > >> +     __u32 tv_sec;
>> > >> +     __u32 tv_usec;
>> > >> +     __u32 sequence;
>> > >> +     __u32 obj_id;
>> > >> +     __u32 old_fb_id;
>> > >> +     __u32 reserved;
>> > >> +};
>> > >> +
>> > >>  #define DRM_CAP_DUMB_BUFFER 0x1
>> > >>  #define DRM_CAP_VBLANK_HIGH_CRTC 0x2
>> > >>  #define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3
>> > >> diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
>> > >> index 6d4f089..03a473c 100644
>> > >> --- a/include/uapi/drm/drm_mode.h
>> > >> +++ b/include/uapi/drm/drm_mode.h
>> > >> @@ -489,4 +489,20 @@ struct drm_mode_destroy_dumb {
>> > >>       uint32_t handle;
>> > >>  };
>> > >>
>> > >> +#define DRM_MODE_ATOMIC_TEST_ONLY (1<<0)
>> > >> +#define DRM_MODE_ATOMIC_EVENT (1<<1)
>> > >> +#define DRM_MODE_ATOMIC_NONBLOCK (1<<2)
>> > >> +
>> > >> +/* FIXME come up with some sane error reporting mechanism? */
>> > >> +struct drm_mode_atomic {
>> > >> +     __u32 flags;
>> > >> +     __u32 count_objs;
>> > >> +     __u64 objs_ptr;
>> > >> +     __u64 count_props_ptr;
>> > >> +     __u64 props_ptr;
>> > >> +     __u64 prop_values_ptr;
>> > >> +     __u64 blob_values_ptr;
>> > >> +     __u64 user_data;
>> > >> +};
>> > >> +
>> > >>  #endif
>> > >> --
>> > >> 1.8.3.1
>> > >
>> > > --
>> > > Ville Syrjälä
>> > > Intel OTC
>>
>> --
>> Ville Syrjälä
>> Intel OTC
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>
> --
> Matt Roper
> Intel Corporation
> Embedded Media & Graphics Driver Group
> (916) 356-2795

^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2013-10-08 18:46 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-10-06  0:45 [RFCv1 00/12] Atomic/nuclear modeset/pageflip Rob Clark
2013-10-06  0:45 ` [RFCv1 01/12] drm: add atomic fxns Rob Clark
2013-10-06  0:45 ` [RFCv1 02/12] drm: add object property type Rob Clark
2013-10-07 13:43   ` Ville Syrjälä
2013-10-07 14:44     ` Rob Clark
2013-10-06  0:45 ` [RFCv1 03/12] drm: add DRM_MODE_PROP_DYNAMIC property flag Rob Clark
2013-10-07 13:46   ` Ville Syrjälä
2013-10-07 14:46     ` Rob Clark
2013-10-06  0:45 ` [RFCv1 04/12] drm: add DRM_MODE_PROP_SIGNED " Rob Clark
2013-10-07 14:46   ` Matt Plumtree
2013-10-06  0:45 ` [RFCv1 05/12] drm: helpers to find mode objects (BEFORE drm: split property values out) Rob Clark
2013-10-06  0:48   ` Rob Clark
2013-10-06  0:45 ` [RFCv1 06/12] drm: split propvals out and blob property support Rob Clark
2013-10-06  0:45 ` [RFCv1 07/12] drm: Allow drm_mode_object_find() to look up an object of any type Rob Clark
2013-10-06  0:45 ` [RFCv1 08/12] drm: Refactor object property check code Rob Clark
2013-10-07 13:47   ` Ville Syrjälä
2013-10-06  0:45 ` [RFCv1 09/12] drm: convert plane to properties/state Rob Clark
2013-10-06  0:45 ` [RFCv1 10/12] drm: convert crtc " Rob Clark
2013-10-07 13:39   ` Ville Syrjälä
2013-10-07 14:03     ` Rob Clark
2013-10-07 14:19       ` Ville Syrjälä
2013-10-07 14:29         ` Rob Clark
2013-10-07 17:51           ` Daniel Vetter
2013-10-06  0:45 ` [RFCv1 11/12] drm: Atomic modeset ioctl Rob Clark
2013-10-07 13:28   ` Ville Syrjälä
2013-10-07 13:55     ` Rob Clark
2013-10-07 14:18       ` Ville Syrjälä
2013-10-07 14:39         ` Rob Clark
2013-10-07 15:05           ` Ville Syrjälä
2013-10-07 15:20             ` Rob Clark
2013-10-07 17:56               ` Daniel Vetter
2013-10-07 18:49                 ` Rob Clark
2013-10-08 18:35         ` Matt Roper
2013-10-08 18:46           ` Rob Clark
2013-10-06  0:45 ` [RFCv1 12/12] ARM: add get_user() support for 8 byte types Rob Clark
2013-10-06  8:53   ` Russell King - ARM Linux
2013-10-06 14:09     ` Rob Clark
2013-10-06 15:56       ` Russell King - ARM Linux

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.