Skip to contentSkip to conversation

prepare for atomic/nuclear modeset/pageflip

PATCH In review Rob Clark 3 participants 69 messages May 24, 2014 – May 28, 2014 Page 1 of 2

Subsystems (20)
lore
Share & tools
lore

Rob Clark

author
#0 lore raw

cover prepare for atomic/nuclear modeset/pageflip

One more time, with feeling..

Previous revision of series:
http://lists.freedesktop.org/archives/dri-devel/2014-March/055806.html

And if you prefer, in git form:
http://cgit.freedesktop.org/~robclark/linux/log/?h=cold-fusion
git://people.freedesktop.org/~robclark/linux cold-fusion

This series does not include the actual atomic ioctl, but it does include all the needed infrastructure changes.

Compared to previous revision, I've split out drm_modeset_acquire_ctx from drm_atomic_state, so that we can ww acquire mode_config and crtc locks outside of atomic transactions. (Which keeps lockdep happy wrt. drm_modeset_lock_all().) I also got to the point in juggling things around where I wanted to let the compiler type checking do it's job, so 's/void *state/struct drm_atomic_state *state/g'.

At this point, I've tested this on i915 (few different generation laptops), radeon, and msm. And of course w/ ww debug (deadlock in- jection) enabled. So I think all the locking related paths should be covered.

I believe Thierry has tested a slighly older revision on tegra. I would of course appreciate more testing on other drivers for which I don't have the hw. But I think it is pretty much ready to go. I do still owe some docs updates, I will send some patches for that in the near future, but didn't want to hold up giving others a chance to start banging on this.

Rob Clark (14):
drm: fix typo
drm: add atomic fxns
drm: convert crtc and mode_config to ww_mutex
drm: add object property type
drm: add signed-range property type
drm: helpers to find mode objects
drm: split propvals out and blob property support
drm: allow FB's in drm_mode_object_find
drm: convert plane to properties/state
drm: convert crtc to properties/state
drm: push locking down into restore_fbdev_mode drm/msm: add atomic support
drm: spiff out FB refcnting traces
drm: more conservative locking

Sean Paul (1):
drm: Fix up the atomic legacy paths so they work

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

 drivers/gpu/drm/Makefile                    |    2 +-
 drivers/gpu/drm/armada/armada_crtc.c        |   14 +-
 drivers/gpu/drm/armada/armada_fbdev.c       |    4 +-
 drivers/gpu/drm/armada/armada_output.c      |    3 +-
 drivers/gpu/drm/armada/armada_overlay.c     |   14 +-
 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.c                |  720 +++++++++++++
 drivers/gpu/drm/drm_crtc.c                  | 1534 ++++++++++++++++++---------
 drivers/gpu/drm/drm_crtc_helper.c           |    6 +-
 drivers/gpu/drm/drm_fb_cma_helper.c         |   15 +-
 drivers/gpu/drm/drm_fb_helper.c             |   69 +-
 drivers/gpu/drm/drm_modes.c                 |    4 +-
 drivers/gpu/drm/drm_modeset_lock.c          |  159 +++
 drivers/gpu/drm/drm_plane_helper.c          |    2 +
 drivers/gpu/drm/drm_probe_helper.c          |   10 +-
 drivers/gpu/drm/drm_sysfs.c                 |    4 +-
 drivers/gpu/drm/exynos/exynos_drm_crtc.c    |   11 +-
 drivers/gpu/drm/exynos/exynos_drm_drv.c     |    7 +
 drivers/gpu/drm/exynos/exynos_drm_fbdev.c   |    8 +-
 drivers/gpu/drm/exynos/exynos_drm_plane.c   |   11 +-
 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     |   16 +-
 drivers/gpu/drm/gma500/mdfld_dsi_output.c   |   12 +-
 drivers/gpu/drm/gma500/oaktrail_lvds.c      |    6 +-
 drivers/gpu/drm/gma500/psb_drv.c            |   11 +-
 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     |   16 +-
 drivers/gpu/drm/gma500/psb_intel_sdvo.c     |   23 +-
 drivers/gpu/drm/i2c/ch7006_drv.c            |    4 +-
 drivers/gpu/drm/i915/i915_debugfs.c         |   12 +-
 drivers/gpu/drm/i915/i915_drv.c             |   16 +-
 drivers/gpu/drm/i915/i915_irq.c             |    6 +-
 drivers/gpu/drm/i915/intel_crt.c            |    4 +-
 drivers/gpu/drm/i915/intel_display.c        |   24 +-
 drivers/gpu/drm/i915/intel_dp.c             |   25 +-
 drivers/gpu/drm/i915/intel_drv.h            |    1 +
 drivers/gpu/drm/i915/intel_fbdev.c          |    6 +-
 drivers/gpu/drm/i915/intel_hdmi.c           |    7 +-
 drivers/gpu/drm/i915/intel_lvds.c           |   10 +-
 drivers/gpu/drm/i915/intel_opregion.c       |    4 +-
 drivers/gpu/drm/i915/intel_overlay.c        |    4 +-
 drivers/gpu/drm/i915/intel_panel.c          |    8 +-
 drivers/gpu/drm/i915/intel_sdvo.c           |   23 +-
 drivers/gpu/drm/i915/intel_sprite.c         |    3 +-
 drivers/gpu/drm/i915/intel_tv.c             |   12 +-
 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/Makefile                |    1 +
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c    |   70 +-
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c     |    6 +
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h     |    1 +
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c   |   14 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c    |   69 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c     |    6 +
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h     |    2 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c   |   14 +-
 drivers/gpu/drm/msm/msm_atomic.c            |  141 +++
 drivers/gpu/drm/msm/msm_drv.c               |   33 +-
 drivers/gpu/drm/msm/msm_drv.h               |    8 +
 drivers/gpu/drm/msm/msm_gem.c               |   24 +-
 drivers/gpu/drm/msm/msm_gem.h               |   13 +
 drivers/gpu/drm/msm/msm_kms.h               |    1 +
 drivers/gpu/drm/nouveau/dispnv04/crtc.c     |    1 +
 drivers/gpu/drm/nouveau/dispnv04/overlay.c  |   13 +-
 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         |   26 +-
 drivers/gpu/drm/omapdrm/omap_drv.c          |   16 +-
 drivers/gpu/drm/omapdrm/omap_drv.h          |    4 +-
 drivers/gpu/drm/omapdrm/omap_plane.c        |   14 +-
 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     |   12 +-
 drivers/gpu/drm/rcar-du/rcar_du_vgacon.c    |    3 +-
 drivers/gpu/drm/shmobile/shmob_drm_crtc.c   |    6 +-
 drivers/gpu/drm/shmobile/shmob_drm_drv.c    |    7 +
 drivers/gpu/drm/shmobile/shmob_drm_plane.c  |    2 +
 drivers/gpu/drm/tegra/fb.c                  |    7 +-
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c        |    5 +-
 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         |   26 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.h         |    4 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c         |    1 +
 drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c        |    1 +
 include/drm/drmP.h                          |   85 +-
 include/drm/drm_atomic.h                    |  170 +++
 include/drm/drm_crtc.h                      |  326 +++++-
 include/drm/drm_fb_helper.h                 |    3 +-
 include/drm/drm_modeset_lock.h              |  130 +++
 include/uapi/drm/drm_mode.h                 |   18 +
 117 files changed, 3401 insertions(+), 882 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_atomic.c
 create mode 100644 drivers/gpu/drm/drm_modeset_lock.c
 create mode 100644 drivers/gpu/drm/msm/msm_atomic.c
 create mode 100644 include/drm/drm_atomic.h
 create mode 100644 include/drm/drm_modeset_lock.h
Signature · 6 lines
1.9.0

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
author
#1 lore raw

PATCH 1/17 drm: fix typo

---
 drivers/gpu/drm/drm_crtc_helper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/drm_crtc_helper.c +1 -1
index a8b78e7..54e8fdb 100644
@@ -147,7 +147,7 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev)
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
 		if (!drm_helper_encoder_in_use(encoder)) {
 			drm_encoder_disable(encoder);
-			/* disconnector encoder from any connector */
+			/* disconnect encoder from any connector */
 			encoder->crtc = NULL;
 		}
 	}
Signature · 1 line
1.9.0
author
#2 lore raw

PATCH 2/17 drm: add atomic fxns

In reply to Rob Clark

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                    |   2 +-
 drivers/gpu/drm/armada/armada_crtc.c        |   3 +-
 drivers/gpu/drm/armada/armada_output.c      |   3 +-
 drivers/gpu/drm/armada/armada_overlay.c     |   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.c                | 142 +++++++++++++++++++++++++++
 drivers/gpu/drm/drm_crtc.c                  | 144 +++++++++++++++++-----------
 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   |   4 +-
 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             |   6 +-
 drivers/gpu/drm/mgag200/mgag200_drv.c       |   7 ++
 drivers/gpu/drm/mgag200/mgag200_drv.h       |   1 +
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c    |   3 +-
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c   |   3 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c    |   3 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c   |   3 +-
 drivers/gpu/drm/msm/msm_drv.c               |   6 ++
 drivers/gpu/drm/msm/msm_drv.h               |   1 +
 drivers/gpu/drm/nouveau/dispnv04/overlay.c  |   5 +-
 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         |   6 +-
 drivers/gpu/drm/omapdrm/omap_drv.c          |   6 ++
 drivers/gpu/drm/omapdrm/omap_drv.h          |   4 +-
 drivers/gpu/drm/omapdrm/omap_plane.c        |   3 +-
 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 +-
 include/drm/drmP.h                          |  80 ++++++++++++++++
 include/drm/drm_atomic.h                    | 107 +++++++++++++++++++++
 include/drm/drm_crtc.h                      |  15 ++-
 66 files changed, 652 insertions(+), 102 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_atomic.c
 create mode 100644 include/drm/drm_atomic.h
drivers/gpu/drm/Makefile +1 -1
index 48e38ba..ba2ed83 100644
@@ -14,7 +14,7 @@ drm-y       :=	drm_auth.o drm_buffer.o drm_bufs.o drm_cache.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_plane_helper.o
+		drm_plane_helper.o drm_atomic.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
drivers/gpu/drm/armada/armada_crtc.c +2 -1
index 81c34f9..7d3c649 100644
@@ -961,7 +961,8 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
 
 static int
 armada_drm_crtc_set_property(struct drm_crtc *crtc,
-	struct drm_property *property, uint64_t val)
+	struct drm_atomic_state *state, struct drm_property *property,
+	uint64_t val, void *blob_data)
 {
 	struct armada_private *priv = crtc->dev->dev_private;
 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
drivers/gpu/drm/armada/armada_output.c +2 -1
index d685a54..9915306 100644
@@ -54,7 +54,8 @@ static void armada_drm_connector_destroy(struct drm_connector *conn)
 }
 
 static int armada_drm_connector_set_property(struct drm_connector *conn,
-	struct drm_property *property, uint64_t value)
+	struct drm_atomic_state *state, struct drm_property *property,
+	uint64_t value, void *blob_data)
 {
 	struct armada_connector *dconn = drm_to_armada_conn(conn);
 
drivers/gpu/drm/armada/armada_overlay.c +2 -1
index c5b06fd..601ba9a 100644
@@ -283,7 +283,8 @@ static void armada_plane_destroy(struct drm_plane *plane)
 }
 
 static int armada_plane_set_property(struct drm_plane *plane,
-	struct drm_property *property, uint64_t val)
+	struct drm_atomic_state *state, struct drm_property *property,
+	uint64_t val, void *blob_data)
 {
 	struct armada_private *priv = plane->dev->dev_private;
 	struct armada_plane *dplane = drm_to_armada_plane(plane);
drivers/gpu/drm/ast/ast_drv.c +6 -0
index 2ba39ac..cd81d68 100644
@@ -215,6 +215,12 @@ static struct drm_driver driver = {
 	.dumb_map_offset = ast_dumb_mmap_offset,
 	.dumb_destroy = drm_gem_dumb_destroy,
 
+	.atomic_begin     = drm_atomic_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
 };
 
 static int __init ast_init(void)
drivers/gpu/drm/ast/ast_drv.h +1 -0
index 5d6a875..0d21ff8 100644
@@ -29,6 +29,7 @@
 #define __AST_DRV_H__
 
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic.h>
 
 #include <drm/ttm/ttm_bo_api.h>
 #include <drm/ttm/ttm_bo_driver.h>
drivers/gpu/drm/cirrus/cirrus_drv.c +6 -0
index 08ce520..023db21 100644
@@ -137,6 +137,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_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
 };
 
 static const struct dev_pm_ops cirrus_pm_ops = {
drivers/gpu/drm/cirrus/cirrus_drv.h +1 -0
index 117d3ec..f929bc8 100644
@@ -14,6 +14,7 @@
 #include <video/vga.h>
 
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic.h>
 
 #include <drm/ttm/ttm_bo_api.h>
 #include <drm/ttm/ttm_bo_driver.h>
drivers/gpu/drm/drm_atomic.c new file +142 -0

142 lines not on this page · raw message

drivers/gpu/drm/drm_crtc.c +89 -55

204 lines not on this page · raw message

drivers/gpu/drm/exynos/exynos_drm_crtc.c +3 -1
index 1ef5ab9..2a56973 100644
@@ -281,8 +281,10 @@ static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
 }
 
 static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
+					struct drm_atomic_state *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;
drivers/gpu/drm/exynos/exynos_drm_drv.c +7 -0
index 2d27ba2..318969d 100644
@@ -14,6 +14,7 @@
 #include <linux/pm_runtime.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 
 #include <linux/anon_inodes.h>
 
@@ -341,6 +342,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_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_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,
drivers/gpu/drm/exynos/exynos_drm_plane.c +3 -1
index 8371cbd..9da0935 100644
@@ -212,8 +212,10 @@ static void exynos_plane_destroy(struct drm_plane *plane)
 }
 
 static int exynos_plane_set_property(struct drm_plane *plane,
+				     struct drm_atomic_state *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);
drivers/gpu/drm/gma500/cdv_intel_crt.c +3 -1
index c18268c..6d637d3 100644
@@ -205,8 +205,10 @@ static int cdv_intel_crt_get_modes(struct drm_connector *connector)
 }
 
 static int cdv_intel_crt_set_property(struct drm_connector *connector,
+				  struct drm_atomic_state *state,
 				  struct drm_property *property,
-				  uint64_t value)
+				  uint64_t value,
+				  void *blob_data)
 {
 	return 0;
 }
drivers/gpu/drm/gma500/cdv_intel_dp.c +3 -1
index 9ff30c2..31d872d 100644
@@ -1645,8 +1645,10 @@ cdv_intel_dp_detect_audio(struct drm_connector *connector)
 
 static int
 cdv_intel_dp_set_property(struct drm_connector *connector,
+		      struct drm_atomic_state *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);
drivers/gpu/drm/gma500/cdv_intel_hdmi.c +3 -1
index b99084b..f0e4d78 100644
@@ -150,8 +150,10 @@ static enum drm_connector_status cdv_hdmi_detect(
 }
 
 static int cdv_hdmi_set_property(struct drm_connector *connector,
+				       struct drm_atomic_state *state,
 				       struct drm_property *property,
-				       uint64_t value)
+				       uint64_t value,
+				       void *blob_data)
 {
 	struct drm_encoder *encoder = connector->encoder;
 
drivers/gpu/drm/gma500/cdv_intel_lvds.c +3 -1
index 8ecc920..7ffaed4 100644
@@ -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,
+				       struct drm_atomic_state *state,
 				       struct drm_property *property,
-				       uint64_t value)
+				       uint64_t value,
+				       void *blob_data)
 {
 	struct drm_encoder *encoder = connector->encoder;
 
drivers/gpu/drm/gma500/mdfld_dsi_output.c +3 -1
index 6e91b20..2318a46 100644
@@ -243,8 +243,10 @@ mdfld_dsi_connector_detect(struct drm_connector *connector, bool force)
 }
 
 static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
+				struct drm_atomic_state *state,
 				struct drm_property *property,
-				uint64_t value)
+				uint64_t value,
+				void *blob_data)
 {
 	struct drm_encoder *encoder = connector->encoder;
 
drivers/gpu/drm/gma500/psb_drv.c +7 -0
index 0a3101a..0180292 100644
@@ -489,6 +489,13 @@ static struct drm_driver driver = {
 	.disable_vblank = psb_disable_vblank,
 	.get_vblank_counter = psb_get_vblank_counter,
 
+	.atomic_begin     = drm_atomic_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
+
 	.gem_free_object = psb_gem_free_object,
 	.gem_vm_ops = &psb_gem_vm_ops,
 
drivers/gpu/drm/gma500/psb_drv.h +1 -0
index 55ebe2b..413ea37 100644
@@ -25,6 +25,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_global.h>
 #include <drm/gma_drm.h>
+#include <drm/drm_atomic.h>
 #include "psb_reg.h"
 #include "psb_intel_drv.h"
 #include "gma_display.h"
drivers/gpu/drm/gma500/psb_intel_drv.h +3 -1
index 336bd3a..96e9759 100644
@@ -254,8 +254,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,
+					struct drm_atomic_state *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;
 
drivers/gpu/drm/gma500/psb_intel_lvds.c +3 -1
index d7778d0..6b64d9d 100644
@@ -569,8 +569,10 @@ void psb_intel_lvds_destroy(struct drm_connector *connector)
 }
 
 int psb_intel_lvds_set_property(struct drm_connector *connector,
+				       struct drm_atomic_state *state,
 				       struct drm_property *property,
-				       uint64_t value)
+				       uint64_t value,
+				       void *blob_data)
 {
 	struct drm_encoder *encoder = connector->encoder;
 
drivers/gpu/drm/gma500/psb_intel_sdvo.c +3 -1
index deeb082..724b525 100644
@@ -1705,8 +1705,10 @@ static bool psb_intel_sdvo_detect_hdmi_audio(struct drm_connector *connector)
 
 static int
 psb_intel_sdvo_set_property(struct drm_connector *connector,
+			struct drm_atomic_state *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);
drivers/gpu/drm/i915/i915_drv.c +8 -0
index 208e185..e3a2482 100644
@@ -1119,6 +1119,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_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
+
 	.ioctls = i915_ioctls,
 	.fops = &i915_driver_fops,
 	.name = DRIVER_NAME,
drivers/gpu/drm/i915/intel_crt.c +3 -1
index 22d8347..d4198ff 100644
@@ -724,8 +724,10 @@ out:
 }
 
 static int intel_crt_set_property(struct drm_connector *connector,
+				  struct drm_atomic_state *state,
 				  struct drm_property *property,
-				  uint64_t value)
+				  uint64_t value,
+				  void *blob_data)
 {
 	return 0;
 }
drivers/gpu/drm/i915/intel_dp.c +3 -1
index 34ed143..c63d210 100644
@@ -3270,8 +3270,10 @@ intel_dp_detect_audio(struct drm_connector *connector)
 
 static int
 intel_dp_set_property(struct drm_connector *connector,
+		      struct drm_atomic_state *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);
drivers/gpu/drm/i915/intel_drv.h +1 -0
index d8b540b..64aeae0 100644
@@ -31,6 +31,7 @@
 #include "i915_drv.h"
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_dp_helper.h>
 
drivers/gpu/drm/i915/intel_hdmi.c +3 -1
index b606162..8e160b0 100644
@@ -1044,8 +1044,10 @@ intel_hdmi_detect_audio(struct drm_connector *connector)
 
 static int
 intel_hdmi_set_property(struct drm_connector *connector,
+			struct drm_atomic_state *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 =
drivers/gpu/drm/i915/intel_lvds.c +3 -1
index 1b1541d..4028237 100644
@@ -486,8 +486,10 @@ static void intel_lvds_destroy(struct drm_connector *connector)
 }
 
 static int intel_lvds_set_property(struct drm_connector *connector,
+				   struct drm_atomic_state *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;
drivers/gpu/drm/i915/intel_sdvo.c +3 -1
index 2bf09e8..4e36ee99 100644
@@ -2052,8 +2052,10 @@ static bool intel_sdvo_detect_hdmi_audio(struct drm_connector *connector)
 
 static int
 intel_sdvo_set_property(struct drm_connector *connector,
+			struct drm_atomic_state *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);
drivers/gpu/drm/i915/intel_tv.c +4 -2
index e0193e8..05ee0d5 100644
@@ -1444,8 +1444,10 @@ 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,
+		      struct drm_atomic_state *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);
drivers/gpu/drm/mgag200/mgag200_drv.c +7 -0
index f15ea3c..0425bdd 100644
@@ -103,6 +103,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_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
 };
 
 static struct pci_driver mgag200_pci_driver = {
drivers/gpu/drm/mgag200/mgag200_drv.h +1 -0
index cf11ee6..c4d1600 100644
@@ -16,6 +16,7 @@
 #include <video/vga.h>
 
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/ttm/ttm_bo_api.h>
 #include <drm/ttm/ttm_bo_driver.h>
 #include <drm/ttm/ttm_placement.h>
drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +2 -1
index ef9957d..efa19c8 100644
@@ -468,7 +468,8 @@ static int mdp4_crtc_page_flip(struct drm_crtc *crtc,
 }
 
 static int mdp4_crtc_set_property(struct drm_crtc *crtc,
-		struct drm_property *property, uint64_t val)
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t val, void *blob_data)
 {
 	// XXX
 	return -EINVAL;
drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c +2 -1
index 66f33db..8c064dc 100644
@@ -85,7 +85,8 @@ void mdp4_plane_install_properties(struct drm_plane *plane,
 }
 
 int mdp4_plane_set_property(struct drm_plane *plane,
-		struct drm_property *property, uint64_t val)
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t val, void *blob_data)
 {
 	// XXX
 	return -EINVAL;
drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +2 -1
index 6ea10bd..ff48944 100644
@@ -386,7 +386,8 @@ static int mdp5_crtc_page_flip(struct drm_crtc *crtc,
 }
 
 static int mdp5_crtc_set_property(struct drm_crtc *crtc,
-		struct drm_property *property, uint64_t val)
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t val, void *blob_data)
 {
 	// XXX
 	return -EINVAL;
drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +2 -1
index 47f7bbb..5cbf226 100644
@@ -100,7 +100,8 @@ void mdp5_plane_install_properties(struct drm_plane *plane,
 }
 
 int mdp5_plane_set_property(struct drm_plane *plane,
-		struct drm_property *property, uint64_t val)
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t val, void *blob_data)
 {
 	// XXX
 	return -EINVAL;
drivers/gpu/drm/msm/msm_drv.c +6 -0
index 50ec1be..46e0f29 100644
@@ -815,6 +815,12 @@ static struct drm_driver msm_driver = {
 	.gem_prime_import_sg_table = msm_gem_prime_import_sg_table,
 	.gem_prime_vmap     = msm_gem_prime_vmap,
 	.gem_prime_vunmap   = msm_gem_prime_vunmap,
+	.atomic_begin       = drm_atomic_begin,
+	.atomic_set_event   = drm_atomic_set_event,
+	.atomic_check       = drm_atomic_check,
+	.atomic_commit      = drm_atomic_commit,
+	.atomic_end         = drm_atomic_end,
+	.atomic_funcs       = &drm_atomic_funcs,
 #ifdef CONFIG_DEBUG_FS
 	.debugfs_init       = msm_debugfs_init,
 	.debugfs_cleanup    = msm_debugfs_cleanup,
drivers/gpu/drm/msm/msm_drv.h +1 -0
index 9d10ee0..afc990e 100644
@@ -50,6 +50,7 @@ static inline struct device *msm_iommu_get_ctx(const char *ctx_name)
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/msm_drm.h>
 
 struct msm_kms;
drivers/gpu/drm/nouveau/dispnv04/overlay.c +3 -2
index ab03f77..577e6aa 100644
@@ -221,8 +221,9 @@ nv10_set_params(struct nouveau_plane *plane)
 
 static int
 nv_set_property(struct drm_plane *plane,
-		struct drm_property *property,
-		uint64_t value)
+		  struct drm_atomic_state *state,
+		  struct drm_property *property,
+		  uint64_t value, void *blob_data)
 {
 	struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
 
drivers/gpu/drm/nouveau/nouveau_connector.c +2 -1
index d07ce02..3351e72 100644
@@ -447,7 +447,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)
+		struct drm_atomic_state *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);
drivers/gpu/drm/nouveau/nouveau_drm.c +7 -0
index ddd8375..9a96d6d 100644
@@ -858,6 +858,13 @@ driver = {
 	.dumb_map_offset = nouveau_display_dumb_map_offset,
 	.dumb_destroy = drm_gem_dumb_destroy,
 
+	.atomic_begin     = drm_atomic_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
+
 	.name = DRIVER_NAME,
 	.desc = DRIVER_DESC,
 #ifdef GIT_REVISION
drivers/gpu/drm/nouveau/nouveau_drm.h +1 -0
index 7efbafa..8941696 100644
@@ -29,6 +29,7 @@
 #include <subdev/vm.h>
 
 #include <drmP.h>
+#include <drm/drm_atomic.h>
 #include <drm/nouveau_drm.h>
 
 #include <drm/ttm/ttm_bo_api.h>
drivers/gpu/drm/omapdrm/omap_crtc.c +4 -2
index e3c47a8..a7c0010 100644
@@ -382,7 +382,8 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
 }
 
 static int omap_crtc_set_property(struct drm_crtc *crtc,
-		struct drm_property *property, uint64_t val)
+		struct drm_atomic_state *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;
@@ -392,7 +393,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 = {
drivers/gpu/drm/omapdrm/omap_drv.c +6 -0
index c8270e4..d3c9161 100644
@@ -651,6 +651,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_begin,
+		.atomic_set_event = drm_atomic_set_event,
+		.atomic_check     = drm_atomic_check,
+		.atomic_commit    = drm_atomic_commit,
+		.atomic_end       = drm_atomic_end,
+		.atomic_funcs     = &drm_atomic_funcs,
 		.ioctls = ioctls,
 		.num_ioctls = DRM_OMAP_NUM_IOCTLS,
 		.fops = &omapdriver_fops,
drivers/gpu/drm/omapdrm/omap_drv.h +3 -1
index 284b80f..346fc8a 100644
@@ -25,6 +25,7 @@
 #include <linux/types.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/omap_drm.h>
 #include <linux/platform_data/omap_drm.h>
 
@@ -178,7 +179,8 @@ int omap_plane_mode_set(struct drm_plane *plane,
 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);
+		struct drm_atomic_state *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);
drivers/gpu/drm/omapdrm/omap_plane.c +2 -1
index 3cf31ee..8ae5c49 100644
@@ -336,7 +336,8 @@ void omap_plane_install_properties(struct drm_plane *plane,
 }
 
 int omap_plane_set_property(struct drm_plane *plane,
-		struct drm_property *property, uint64_t val)
+		struct drm_atomic_state *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;
drivers/gpu/drm/qxl/qxl_display.c +3 -1
index 3ab9072..b54c970 100644
@@ -819,8 +819,10 @@ static enum drm_connector_status qxl_conn_detect(
 }
 
 static int qxl_conn_set_property(struct drm_connector *connector,
+				   struct drm_atomic_state *state,
 				   struct drm_property *property,
-				   uint64_t value)
+				   uint64_t value,
+				   void *blob_data)
 {
 	DRM_DEBUG("\n");
 	return 0;
drivers/gpu/drm/qxl/qxl_drv.c +9 -0
index 6e93663..1984c2c 100644
@@ -34,6 +34,7 @@
 #include "drmP.h"
 #include "drm/drm.h"
 #include "drm_crtc_helper.h"
+#include "drm_atomic.h"
 #include "qxl_drv.h"
 #include "qxl_object.h"
 
@@ -220,6 +221,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_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
+
 #if defined(CONFIG_DEBUG_FS)
 	.debugfs_init = qxl_debugfs_init,
 	.debugfs_cleanup = qxl_debugfs_takedown,
drivers/gpu/drm/radeon/radeon_connectors.c +6 -3
index ea50e0a..f7ecdfc 100644
@@ -359,8 +359,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,
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t val, void *blob_data)
 {
 	struct drm_device *dev = connector->dev;
 	struct radeon_device *rdev = dev->dev_private;
@@ -682,8 +683,10 @@ static void radeon_connector_destroy(struct drm_connector *connector)
 }
 
 static int radeon_lvds_set_property(struct drm_connector *connector,
+				    struct drm_atomic_state *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;
drivers/gpu/drm/radeon/radeon_drv.c +9 -0
index 15447a41..745791d 100644
@@ -34,6 +34,7 @@
 #include "radeon_drv.h"
 
 #include <drm/drm_pciids.h>
+#include <drm/drm_atomic.h>
 #include <linux/console.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
@@ -545,6 +546,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_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
+
 	.fops = &radeon_driver_kms_fops,
 
 	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
drivers/gpu/drm/rcar-du/rcar_du_drv.c +7 -0
index 792fd1d..3f642a8 100644
@@ -21,6 +21,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.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_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
 	.fops			= &rcar_du_fops,
 	.name			= "rcar-du",
 	.desc			= "Renesas R-Car Display Unit",
drivers/gpu/drm/rcar-du/rcar_du_plane.c +3 -1
index 3fb69d9..3a5d843 100644
@@ -397,8 +397,10 @@ done:
 }
 
 static int rcar_du_plane_set_property(struct drm_plane *plane,
+				      struct drm_atomic_state *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;
drivers/gpu/drm/shmobile/shmob_drm_drv.c +7 -0
index 82c84c7..7474ffb 100644
@@ -21,6 +21,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.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_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
 	.fops			= &shmob_drm_fops,
 	.name			= "shmob-drm",
 	.desc			= "Renesas SH Mobile DRM",
drivers/gpu/drm/tilcdc/tilcdc_drv.c +6 -0
index b20b694..3579b07 100644
@@ -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_begin,
+	.atomic_set_event   = drm_atomic_set_event,
+	.atomic_check       = drm_atomic_check,
+	.atomic_commit      = drm_atomic_commit,
+	.atomic_end         = drm_atomic_end,
+	.atomic_funcs       = &drm_atomic_funcs,
 #ifdef CONFIG_DEBUG_FS
 	.debugfs_init       = tilcdc_debugfs_init,
 	.debugfs_cleanup    = tilcdc_debugfs_cleanup,
drivers/gpu/drm/tilcdc/tilcdc_drv.h +1 -0
index 0938036..1280a65 100644
@@ -31,6 +31,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 
drivers/gpu/drm/tilcdc/tilcdc_slave.c +2 -1
index 595068b..693f3ec 100644
@@ -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)
+		struct drm_atomic_state *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,
drivers/gpu/drm/udl/udl_connector.c +3 -3
index b44d548..936244d 100644
@@ -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, 
+			       struct drm_atomic_state *state, struct drm_property *property,
+			       uint64_t val, void *blob_data)
 {
 	return 0;
 }
drivers/gpu/drm/udl/udl_drv.c +8 -0
index 3ddd6cd..52ade41 100644
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <drm/drm_usb.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include "udl_drv.h"
 
 static struct drm_driver driver;
@@ -88,6 +89,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_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
+
 	.name = DRIVER_NAME,
 	.desc = DRIVER_DESC,
 	.date = DRIVER_DATE,
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +7 -0
index 6bdd15e..3ec6792 100644
@@ -1433,6 +1433,13 @@ static struct drm_driver driver = {
 	.prime_fd_to_handle = vmw_prime_fd_to_handle,
 	.prime_handle_to_fd = vmw_prime_handle_to_fd,
 
+	.atomic_begin     = drm_atomic_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
+
 	.fops = &vmwgfx_driver_fops,
 	.name = VMWGFX_DRIVER_NAME,
 	.desc = VMWGFX_DRIVER_DESC,
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +1 -0
index 6b252a8..b0d6f3a 100644
@@ -30,6 +30,7 @@
 
 #include "vmwgfx_reg.h"
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include <drm/vmwgfx_drm.h>
 #include <drm/drm_hashtab.h>
 #include <linux/suspend.h>
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +3 -1
index e7199b4..6b9db5e 100644
@@ -2007,8 +2007,10 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector,
 }
 
 int vmw_du_connector_set_property(struct drm_connector *connector,
+				  struct drm_atomic_state *state,
 				  struct drm_property *property,
-				  uint64_t val)
+				  uint64_t val,
+				  void *blob_data)
 {
 	return 0;
 }
drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +3 -1
index 8d038c3..6b02fdb 100644
@@ -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,
+				  struct drm_atomic_state *state,
 				  struct drm_property *property,
-				  uint64_t val);
+				  uint64_t val,
+				  void *blob_data);
 
 
 /*
include/drm/drmP.h +80 -0

86 lines not on this page · raw message

include/drm/drm_atomic.h new file +107 -0

107 lines not on this page · raw message

include/drm/drm_crtc.h +11 -4
index 698d54e..4790cad 100644
@@ -200,6 +200,8 @@ struct drm_encoder;
 struct drm_pending_vblank_event;
 struct drm_plane;
 struct drm_bridge;
+struct drm_atomic_state;
+struct drm_atomic_funcs;
 
 /**
  * drm_crtc_funcs - control CRTCs for a given device
@@ -262,7 +264,9 @@ struct drm_crtc_funcs {
 			 uint32_t flags);
 
 	int (*set_property)(struct drm_crtc *crtc,
-			    struct drm_property *property, uint64_t val);
+			    struct drm_atomic_state *state,
+			    struct drm_property *property, uint64_t val,
+			    void *blob_data);
 };
 
 /**
@@ -375,8 +379,9 @@ 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,
+			struct drm_atomic_state *state,
+			struct drm_property *property, uint64_t val, void *blob_data);
 	void (*destroy)(struct drm_connector *connector);
 	void (*force)(struct drm_connector *connector);
 };
@@ -541,7 +546,9 @@ struct drm_plane_funcs {
 	void (*destroy)(struct drm_plane *plane);
 
 	int (*set_property)(struct drm_plane *plane,
-			    struct drm_property *property, uint64_t val);
+			    struct drm_atomic_state *state,
+			    struct drm_property *property, uint64_t val,
+			    void *blob_data);
 };
 
 enum drm_plane_type {
Signature · 1 line
1.9.0
author
#3 lore raw

PATCH 3/17 drm: convert crtc and mode_config to ww_mutex

In reply to Rob Clark

For atomic, it will be quite convenient to not have to care so much about locking order. And 'state' gives us a convenient place to stash a ww_ctx for any sort of update that needs to grab multiple crtc locks.

Because we will want to eventually make locking even more fine grained (giving locks to planes, connectors, etc), split out drm_modeset_lock so that the atomic state won't eventually have to keep separate lists of locked planes/crtcs/etc.

The state keeps track of which locks it has aquired, and for the benefit of NONBLOCK operations, supports transfering "locked" resources to driver worker/thread to complete the asynchronous state change.

---
 drivers/gpu/drm/Makefile                  |   2 +-
 drivers/gpu/drm/drm_atomic.c              | 140 ++++++++++++++++++++++++--
 drivers/gpu/drm/drm_crtc.c                |  88 ++++++++++++-----
 drivers/gpu/drm/drm_crtc_helper.c         |   4 +-
 drivers/gpu/drm/drm_fb_cma_helper.c       |   6 +-
 drivers/gpu/drm/drm_fb_helper.c           |  18 ++--
 drivers/gpu/drm/drm_modes.c               |   4 +-
 drivers/gpu/drm/drm_modeset_lock.c        | 159 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_probe_helper.c        |  10 +-
 drivers/gpu/drm/drm_sysfs.c               |   4 +-
 drivers/gpu/drm/exynos/exynos_drm_fbdev.c |   4 +-
 drivers/gpu/drm/gma500/cdv_intel_lvds.c   |   6 +-
 drivers/gpu/drm/gma500/oaktrail_lvds.c    |   6 +-
 drivers/gpu/drm/gma500/psb_intel_lvds.c   |   6 +-
 drivers/gpu/drm/i915/i915_debugfs.c       |  12 +--
 drivers/gpu/drm/i915/i915_drv.c           |   8 +-
 drivers/gpu/drm/i915/i915_irq.c           |   6 +-
 drivers/gpu/drm/i915/intel_display.c      |  20 ++--
 drivers/gpu/drm/i915/intel_dp.c           |  18 ++--
 drivers/gpu/drm/i915/intel_lvds.c         |   6 +-
 drivers/gpu/drm/i915/intel_opregion.c     |   4 +-
 drivers/gpu/drm/i915/intel_overlay.c      |   4 +-
 drivers/gpu/drm/i915/intel_panel.c        |   8 +-
 drivers/gpu/drm/i915/intel_sprite.c       |   2 +-
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c  |   4 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c  |   4 +-
 drivers/gpu/drm/omapdrm/omap_crtc.c       |  10 +-
 drivers/gpu/drm/omapdrm/omap_plane.c      |   4 +-
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c      |   4 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c       |  22 ++---
 include/drm/drmP.h                        |   5 -
 include/drm/drm_atomic.h                  |   7 ++
 include/drm/drm_crtc.h                    |  19 ++--
 include/drm/drm_modeset_lock.h            | 130 ++++++++++++++++++++++++
 include/uapi/drm/drm_mode.h               |   3 +
 35 files changed, 614 insertions(+), 143 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_modeset_lock.c
 create mode 100644 include/drm/drm_modeset_lock.h
drivers/gpu/drm/Makefile +1 -1
index ba2ed83..7a6a9f5 100644
@@ -14,7 +14,7 @@ drm-y       :=	drm_auth.o drm_buffer.o drm_bufs.o drm_cache.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_plane_helper.o drm_atomic.o
+		drm_plane_helper.o drm_atomic.o drm_modeset_lock.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
drivers/gpu/drm/drm_atomic.c +134 -6

182 lines not on this page · raw message

drivers/gpu/drm/drm_crtc.c +63 -25

212 lines not on this page · raw message

drivers/gpu/drm/drm_crtc_helper.c +2 -2
index 54e8fdb..8c30259 100644
@@ -88,7 +88,7 @@ bool drm_helper_encoder_in_use(struct drm_encoder *encoder)
 	struct drm_connector *connector;
 	struct drm_device *dev = encoder->dev;
 
-	WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
+	WARN_ON(!drm_modeset_is_locked(&dev->mode_config.mutex));
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
 		if (connector->encoder == encoder)
 			return true;
@@ -112,7 +112,7 @@ bool drm_helper_crtc_in_use(struct drm_crtc *crtc)
 	struct drm_encoder *encoder;
 	struct drm_device *dev = crtc->dev;
 
-	WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
+	WARN_ON(!drm_modeset_is_locked(&dev->mode_config.mutex));
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
 		if (encoder->crtc == crtc && drm_helper_encoder_in_use(encoder))
 			return true;
drivers/gpu/drm/drm_fb_cma_helper.c +3 -3
index 61b5a47..65540b7 100644
@@ -211,13 +211,13 @@ int drm_fb_cma_debugfs_show(struct seq_file *m, void *arg)
 	struct drm_framebuffer *fb;
 	int ret;
 
-	ret = mutex_lock_interruptible(&dev->mode_config.mutex);
+	ret = drm_modeset_lock_interruptible(&dev->mode_config.mutex, NULL);
 	if (ret)
 		return ret;
 
 	ret = mutex_lock_interruptible(&dev->struct_mutex);
 	if (ret) {
-		mutex_unlock(&dev->mode_config.mutex);
+		drm_modeset_unlock(&dev->mode_config.mutex);
 		return ret;
 	}
 
@@ -225,7 +225,7 @@ int drm_fb_cma_debugfs_show(struct seq_file *m, void *arg)
 		drm_fb_cma_describe(fb, m);
 
 	mutex_unlock(&dev->struct_mutex);
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 
 	return 0;
 }
drivers/gpu/drm/drm_fb_helper.c +11 -7
index e95ed58..142f6bd 100644
@@ -331,7 +331,11 @@ static bool drm_fb_helper_force_kernel_mode(void)
 		if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
 			continue;
 
-		if (!mutex_trylock(&dev->mode_config.mutex)) {
+		/* NOTE: we use lockless flag below to avoid grabbing other
+		 * modeset locks.  So just trylock the underlying mutex
+		 * directly:
+		 */
+		if (!mutex_trylock(&dev->mode_config.mutex.mutex.base)) {
 			error = true;
 			continue;
 		}
@@ -340,7 +344,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
 		if (ret)
 			error = true;
 
-		mutex_unlock(&dev->mode_config.mutex);
+		mutex_unlock(&dev->mode_config.mutex.mutex.base);
 	}
 	return error;
 }
@@ -1557,11 +1561,11 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
 
 	drm_fb_helper_parse_command_line(fb_helper);
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 	count = drm_fb_helper_probe_connector_modes(fb_helper,
 						    dev->mode_config.max_width,
 						    dev->mode_config.max_height);
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 	/*
 	 * we shouldn't end up with no modes here.
 	 */
@@ -1601,10 +1605,10 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 	if (!fb_helper->fb)
 		return 0;
 
-	mutex_lock(&fb_helper->dev->mode_config.mutex);
+	drm_modeset_lock(&fb_helper->dev->mode_config.mutex, NULL);
 	if (!drm_fb_helper_is_bound(fb_helper)) {
 		fb_helper->delayed_hotplug = true;
-		mutex_unlock(&fb_helper->dev->mode_config.mutex);
+		drm_modeset_unlock(&fb_helper->dev->mode_config.mutex);
 		return 0;
 	}
 	DRM_DEBUG_KMS("\n");
@@ -1613,7 +1617,7 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 	max_height = fb_helper->fb->height;
 
 	drm_fb_helper_probe_connector_modes(fb_helper, max_width, max_height);
-	mutex_unlock(&fb_helper->dev->mode_config.mutex);
+	drm_modeset_unlock(&fb_helper->dev->mode_config.mutex);
 
 	drm_modeset_lock_all(dev);
 	drm_setup_crtcs(fb_helper);
drivers/gpu/drm/drm_modes.c +2 -2
index bedf189..d8a6b16 100644
@@ -116,7 +116,7 @@ EXPORT_SYMBOL(drm_mode_destroy);
 void drm_mode_probed_add(struct drm_connector *connector,
 			 struct drm_display_mode *mode)
 {
-	WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));
+	WARN_ON(!drm_modeset_is_locked(&connector->dev->mode_config.mutex));
 
 	list_add_tail(&mode->head, &connector->probed_modes);
 }
@@ -1029,7 +1029,7 @@ void drm_mode_connector_list_update(struct drm_connector *connector,
 	struct drm_display_mode *pmode, *pt;
 	int found_it;
 
-	WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));
+	WARN_ON(!drm_modeset_is_locked(&connector->dev->mode_config.mutex));
 
 	list_for_each_entry_safe(pmode, pt, &connector->probed_modes,
 				 head) {
drivers/gpu/drm/drm_modeset_lock.c new file +159 -0

159 lines not on this page · raw message

drivers/gpu/drm/drm_probe_helper.c +5 -5
index 79f07f2..4552fe5 100644
@@ -93,7 +93,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
 	int mode_flags = 0;
 	bool verbose_prune = true;
 
-	WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
+	WARN_ON(!drm_modeset_is_locked(&dev->mode_config.mutex));
 
 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
 			drm_get_connector_name(connector));
@@ -255,7 +255,7 @@ static void output_poll_execute(struct work_struct *work)
 	if (!drm_kms_helper_poll)
 		return;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 
 		/* Ignore forced connectors. */
@@ -293,7 +293,7 @@ static void output_poll_execute(struct work_struct *work)
 		}
 	}
 
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 
 	if (changed)
 		drm_kms_helper_hotplug_event(dev);
@@ -419,7 +419,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev)
 	if (!dev->mode_config.poll_enabled)
 		return false;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 
 		/* Only handle HPD capable connectors. */
@@ -438,7 +438,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev)
 			changed = true;
 	}
 
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 
 	if (changed)
 		drm_kms_helper_hotplug_event(dev);
drivers/gpu/drm/drm_sysfs.c +2 -2
index c22c309..981e570 100644
@@ -173,12 +173,12 @@ static ssize_t status_show(struct device *device,
 	enum drm_connector_status status;
 	int ret;
 
-	ret = mutex_lock_interruptible(&connector->dev->mode_config.mutex);
+	ret = drm_modeset_lock_interruptible(&connector->dev->mode_config.mutex, NULL);
 	if (ret)
 		return ret;
 
 	status = connector->funcs->detect(connector, true);
-	mutex_unlock(&connector->dev->mode_config.mutex);
+	drm_modeset_unlock(&connector->dev->mode_config.mutex);
 
 	return snprintf(buf, PAGE_SIZE, "%s\n",
 			drm_get_connector_status_name(status));
drivers/gpu/drm/exynos/exynos_drm_fbdev.c +2 -2
index addbf75..2371716 100644
@@ -242,7 +242,7 @@ bool exynos_drm_fbdev_is_anything_connected(struct drm_device *dev)
 	struct drm_connector *connector;
 	bool ret = false;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		if (connector->status != connector_status_connected)
 			continue;
@@ -250,7 +250,7 @@ bool exynos_drm_fbdev_is_anything_connected(struct drm_device *dev)
 		ret = true;
 		break;
 	}
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 
 	return ret;
 }
drivers/gpu/drm/gma500/cdv_intel_lvds.c +3 -3
index 7ffaed4..f9ee300 100644
@@ -714,7 +714,7 @@ void cdv_intel_lvds_init(struct drm_device *dev,
 	 * Attempt to get the fixed panel mode from DDC.  Assume that the
 	 * preferred mode is the right one.
 	 */
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 	psb_intel_ddc_get_modes(connector,
 				&gma_encoder->ddc_bus->adapter);
 	list_for_each_entry(scan, &connector->probed_modes, head) {
@@ -775,12 +775,12 @@ void cdv_intel_lvds_init(struct drm_device *dev,
 	}
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 	drm_sysfs_connector_add(connector);
 	return;
 
 failed_find:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 	printk(KERN_ERR "Failed find\n");
 	if (gma_encoder->ddc_bus)
 		psb_intel_i2c_destroy(gma_encoder->ddc_bus);
drivers/gpu/drm/gma500/oaktrail_lvds.c +3 -3
index 9b09946..b8c1c39 100644
@@ -359,7 +359,7 @@ void oaktrail_lvds_init(struct drm_device *dev,
 	 *    if closed, act like it's not there for now
 	 */
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 	i2c_adap = i2c_get_adapter(dev_priv->ops->i2c_bus);
 	if (i2c_adap == NULL)
 		dev_err(dev->dev, "No ddc adapter available!\n");
@@ -402,13 +402,13 @@ void oaktrail_lvds_init(struct drm_device *dev,
 	}
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 
 	drm_sysfs_connector_add(connector);
 	return;
 
 failed_find:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 
 	dev_dbg(dev->dev, "No LVDS modes found, disabling.\n");
 	if (gma_encoder->ddc_bus)
drivers/gpu/drm/gma500/psb_intel_lvds.c +3 -3
index 6b64d9d..3442e44 100644
@@ -779,7 +779,7 @@ void psb_intel_lvds_init(struct drm_device *dev,
 	 * Attempt to get the fixed panel mode from DDC.  Assume that the
 	 * preferred mode is the right one.
 	 */
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 	psb_intel_ddc_get_modes(connector, &lvds_priv->ddc_bus->adapter);
 	list_for_each_entry(scan, &connector->probed_modes, head) {
 		if (scan->type & DRM_MODE_TYPE_PREFERRED) {
@@ -830,12 +830,12 @@ void psb_intel_lvds_init(struct drm_device *dev,
 	 * actually having one.
 	 */
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 	drm_sysfs_connector_add(connector);
 	return;
 
 failed_find:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 	if (lvds_priv->ddc_bus)
 		psb_intel_i2c_destroy(lvds_priv->ddc_bus);
 failed_ddc:
drivers/gpu/drm/i915/i915_debugfs.c +6 -6
index 18b3565..693c13b 100644
@@ -1635,7 +1635,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
 
 #ifdef CONFIG_DRM_I915_FBDEV
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	int ret = mutex_lock_interruptible(&dev->mode_config.mutex);
+	int ret = drm_modeset_lock_interruptible(&dev->mode_config.mutex, NULL);
 	if (ret)
 		return ret;
 
@@ -1650,7 +1650,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
 		   atomic_read(&fb->base.refcount.refcount));
 	describe_obj(m, fb->obj);
 	seq_putc(m, '\n');
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 #endif
 
 	mutex_lock(&dev->mode_config.fb_lock);
@@ -1681,7 +1681,7 @@ static int i915_context_status(struct seq_file *m, void *unused)
 	struct i915_hw_context *ctx;
 	int ret, i;
 
-	ret = mutex_lock_interruptible(&dev->mode_config.mutex);
+	ret = drm_modeset_lock_interruptible(&dev->mode_config.mutex, NULL);
 	if (ret)
 		return ret;
 
@@ -1711,7 +1711,7 @@ static int i915_context_status(struct seq_file *m, void *unused)
 		seq_putc(m, '\n');
 	}
 
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 
 	return 0;
 }
@@ -2573,7 +2573,7 @@ static int i9xx_pipe_crc_auto_source(struct drm_device *dev, enum pipe pipe,
 
 	*source = INTEL_PIPE_CRC_SOURCE_PIPE;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list,
 			    base.head) {
 		if (!encoder->base.crtc)
@@ -2609,7 +2609,7 @@ static int i9xx_pipe_crc_auto_source(struct drm_device *dev, enum pipe pipe,
 			break;
 		}
 	}
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 
 	return ret;
 }
drivers/gpu/drm/i915/i915_drv.c +4 -4
index e3a2482..8f2741a 100644
@@ -475,10 +475,10 @@ static int i915_drm_freeze(struct drm_device *dev)
 		 * Disable CRTCs directly since we want to preserve sw state
 		 * for _thaw.
 		 */
-		mutex_lock(&dev->mode_config.mutex);
+		drm_modeset_lock(&dev->mode_config.mutex, NULL);
 		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
 			dev_priv->display.crtc_disable(crtc);
-		mutex_unlock(&dev->mode_config.mutex);
+		drm_modeset_unlock(&dev->mode_config.mutex);
 
 		intel_modeset_suspend_hw(dev);
 	}
@@ -546,14 +546,14 @@ static void intel_resume_hotplug(struct drm_device *dev)
 	struct drm_mode_config *mode_config = &dev->mode_config;
 	struct intel_encoder *encoder;
 
-	mutex_lock(&mode_config->mutex);
+	drm_modeset_lock(&mode_config->mutex, NULL);
 	DRM_DEBUG_KMS("running encoder hotplug functions\n");
 
 	list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
 		if (encoder->hot_plug)
 			encoder->hot_plug(encoder);
 
-	mutex_unlock(&mode_config->mutex);
+	drm_modeset_unlock(&mode_config->mutex);
 
 	/* Just fire off a uevent and let userspace tell us what to do */
 	drm_helper_hpd_irq_event(dev);
drivers/gpu/drm/i915/i915_irq.c +3 -3
index 2d76183..e8e931f 100644
@@ -940,7 +940,7 @@ static bool intel_hpd_irq_event(struct drm_device *dev,
 {
 	enum drm_connector_status old_status;
 
-	WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
+	WARN_ON(!drm_modeset_is_locked(&dev->mode_config.mutex));
 	old_status = connector->status;
 
 	connector->status = connector->funcs->detect(connector, false);
@@ -979,7 +979,7 @@ static void i915_hotplug_work_func(struct work_struct *work)
 	if (!dev_priv->enable_hotplug_processing)
 		return;
 
-	mutex_lock(&mode_config->mutex);
+	drm_modeset_lock(&mode_config->mutex, NULL);
 	DRM_DEBUG_KMS("running encoder hotplug functions\n");
 
 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
@@ -1026,7 +1026,7 @@ static void i915_hotplug_work_func(struct work_struct *work)
 				changed = true;
 		}
 	}
-	mutex_unlock(&mode_config->mutex);
+	drm_modeset_unlock(&mode_config->mutex);
 
 	if (changed)
 		drm_kms_helper_hotplug_event(dev);
drivers/gpu/drm/i915/intel_display.c +10 -10
index 72b5c34..562e575 100644
@@ -2363,7 +2363,7 @@ void intel_display_handle_reset(struct drm_device *dev)
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-		mutex_lock(&crtc->mutex);
+		drm_modeset_lock(&crtc->mutex, NULL);
 		/*
 		 * FIXME: Once we have proper support for primary planes (and
 		 * disabling them without disabling the entire crtc) allow again
@@ -2374,7 +2374,7 @@ void intel_display_handle_reset(struct drm_device *dev)
 							       crtc->primary->fb,
 							       crtc->x,
 							       crtc->y);
-		mutex_unlock(&crtc->mutex);
+		drm_modeset_unlock(&crtc->mutex);
 	}
 }
 
@@ -8002,7 +8002,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
 	if (encoder->crtc) {
 		crtc = encoder->crtc;
 
-		mutex_lock(&crtc->mutex);
+		drm_modeset_lock(&crtc->mutex, NULL);
 
 		old->dpms_mode = connector->dpms;
 		old->load_detect_temp = false;
@@ -8033,7 +8033,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
 		return false;
 	}
 
-	mutex_lock(&crtc->mutex);
+	drm_modeset_lock(&crtc->mutex, NULL);
 	intel_encoder->new_crtc = to_intel_crtc(crtc);
 	to_intel_connector(connector)->new_encoder = intel_encoder;
 
@@ -8083,7 +8083,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
 		intel_crtc->new_config = &intel_crtc->config;
 	else
 		intel_crtc->new_config = NULL;
-	mutex_unlock(&crtc->mutex);
+	drm_modeset_unlock(&crtc->mutex);
 	return false;
 }
 
@@ -8112,7 +8112,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
 			drm_framebuffer_unreference(old->release_fb);
 		}
 
-		mutex_unlock(&crtc->mutex);
+		drm_modeset_unlock(&crtc->mutex);
 		return;
 	}
 
@@ -8120,7 +8120,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
 	if (old->dpms_mode != DRM_MODE_DPMS_ON)
 		connector->funcs->dpms(connector, old->dpms_mode);
 
-	mutex_unlock(&crtc->mutex);
+	drm_modeset_unlock(&crtc->mutex);
 }
 
 static int i9xx_pll_refclk(struct drm_device *dev,
@@ -10578,7 +10578,7 @@ enum pipe intel_get_pipe_from_connector(struct intel_connector *connector)
 {
 	struct drm_encoder *encoder = connector->base.encoder;
 
-	WARN_ON(!mutex_is_locked(&connector->base.dev->mode_config.mutex));
+	WARN_ON(!drm_modeset_is_locked(&connector->base.dev->mode_config.mutex));
 
 	if (!encoder)
 		return INVALID_PIPE;
@@ -11336,9 +11336,9 @@ void intel_modeset_init(struct drm_device *dev)
 	/* Just in case the BIOS is doing something questionable. */
 	intel_disable_fbc(dev);
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 	intel_modeset_setup_hw_state(dev, false);
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list,
 			    base.head) {
drivers/gpu/drm/i915/intel_dp.c +9 -9
index c63d210..e4c0b10 100644
@@ -1131,7 +1131,7 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
 	u32 pp;
 	u32 pp_stat_reg, pp_ctrl_reg;
 
-	WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
+	WARN_ON(!drm_modeset_is_locked(&dev->mode_config.mutex));
 
 	if (!intel_dp->want_panel_vdd && edp_have_panel_vdd(intel_dp)) {
 		struct intel_digital_port *intel_dig_port =
@@ -1168,9 +1168,9 @@ static void edp_panel_vdd_work(struct work_struct *__work)
 						 struct intel_dp, panel_vdd_work);
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 	edp_panel_vdd_off_sync(intel_dp);
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 }
 
 static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
@@ -3385,9 +3385,9 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
 	drm_encoder_cleanup(encoder);
 	if (is_edp(intel_dp)) {
 		cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
-		mutex_lock(&dev->mode_config.mutex);
+		drm_modeset_lock(&dev->mode_config.mutex, NULL);
 		edp_panel_vdd_off_sync(intel_dp);
-		mutex_unlock(&dev->mode_config.mutex);
+		drm_modeset_unlock(&dev->mode_config.mutex);
 	}
 	kfree(intel_dig_port);
 }
@@ -3829,7 +3829,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
 	/* We now know it's not a ghost, init power sequence regs. */
 	intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, power_seq);
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 	edid = drm_get_edid(connector, &intel_dp->aux.ddc);
 	if (edid) {
 		if (drm_add_edid_modes(connector, edid)) {
@@ -3863,7 +3863,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
 		if (fixed_mode)
 			fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
 	}
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 
 	intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
 	intel_panel_setup_backlight(connector);
@@ -3966,9 +3966,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 		drm_dp_aux_unregister_i2c_bus(&intel_dp->aux);
 		if (is_edp(intel_dp)) {
 			cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
-			mutex_lock(&dev->mode_config.mutex);
+			drm_modeset_lock(&dev->mode_config.mutex, NULL);
 			edp_panel_vdd_off_sync(intel_dp);
-			mutex_unlock(&dev->mode_config.mutex);
+			drm_modeset_unlock(&dev->mode_config.mutex);
 		}
 		drm_sysfs_connector_remove(connector);
 		drm_connector_cleanup(connector);
drivers/gpu/drm/i915/intel_lvds.c +3 -3
index 4028237..bdee5d8 100644
@@ -997,7 +997,7 @@ void intel_lvds_init(struct drm_device *dev)
 	 * Attempt to get the fixed panel mode from DDC.  Assume that the
 	 * preferred mode is the right one.
 	 */
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 	edid = drm_get_edid(connector, intel_gmbus_get_adapter(dev_priv, pin));
 	if (edid) {
 		if (drm_add_edid_modes(connector, edid)) {
@@ -1091,7 +1091,7 @@ void intel_lvds_init(struct drm_device *dev)
 		goto failed;
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 
 	lvds_encoder->is_dual_link = compute_is_dual_link_lvds(lvds_encoder);
 	DRM_DEBUG_KMS("detected %s-link lvds configuration\n",
@@ -1121,7 +1121,7 @@ out:
 	return;
 
 failed:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 
 	DRM_DEBUG_KMS("No LVDS modes found, disabling.\n");
 	drm_connector_cleanup(connector);
drivers/gpu/drm/i915/intel_opregion.c +2 -2
index acde294..81d2998 100644
@@ -410,7 +410,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
 	if (bclp > 255)
 		return ASLC_BACKLIGHT_FAILED;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 
 	/*
 	 * Update backlight on all connectors that support backlight (usually
@@ -421,7 +421,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
 		intel_panel_set_backlight(intel_connector, bclp, 255);
 	iowrite32(DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID, &asle->cblv);
 
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 
 
 	return 0;
drivers/gpu/drm/i915/intel_overlay.c +2 -2
index d8adc91..38f8234 100644
@@ -688,7 +688,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
 	u32 swidth, swidthsw, sheight, ostride;
 
 	BUG_ON(!mutex_is_locked(&dev->struct_mutex));
-	BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
+	BUG_ON(!drm_modeset_is_locked(&dev->mode_config.mutex));
 	BUG_ON(!overlay);
 
 	ret = intel_overlay_release_old_vid(overlay);
@@ -793,7 +793,7 @@ int intel_overlay_switch_off(struct intel_overlay *overlay)
 	int ret;
 
 	BUG_ON(!mutex_is_locked(&dev->struct_mutex));
-	BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
+	BUG_ON(!drm_modeset_is_locked(&dev->mode_config.mutex));
 
 	ret = intel_overlay_recover_from_interrupt(overlay);
 	if (ret != 0)
drivers/gpu/drm/i915/intel_panel.c +4 -4
index 44ad415..4121b48 100644
@@ -823,12 +823,12 @@ static int intel_backlight_device_update_status(struct backlight_device *bd)
 	struct intel_connector *connector = bl_get_data(bd);
 	struct drm_device *dev = connector->base.dev;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 	DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n",
 		      bd->props.brightness, bd->props.max_brightness);
 	intel_panel_set_backlight(connector, bd->props.brightness,
 				  bd->props.max_brightness);
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 	return 0;
 }
 
@@ -840,9 +840,9 @@ static int intel_backlight_device_get_brightness(struct backlight_device *bd)
 	int ret;
 
 	intel_runtime_pm_get(dev_priv);
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 	ret = intel_panel_get_backlight(connector);
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 	intel_runtime_pm_put(dev_priv);
 
 	return ret;
drivers/gpu/drm/i915/intel_sprite.c +1 -1
index 213cd58..c235546 100644
@@ -55,7 +55,7 @@ static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl
 	int scanline, min, max, vblank_start;
 	DEFINE_WAIT(wait);
 
-	WARN_ON(!mutex_is_locked(&crtc->base.mutex));
+	WARN_ON(!drm_modeset_is_locked(&crtc->base.mutex));
 
 	vblank_start = mode->crtc_vblank_start;
 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +2 -2
index efa19c8..7cf0f78 100644
@@ -198,9 +198,9 @@ static void unref_fb_worker(struct drm_flip_work *work, void *val)
 		container_of(work, struct mdp4_crtc, unref_fb_work);
 	struct drm_device *dev = mdp4_crtc->base.dev;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 	drm_framebuffer_unreference(val);
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 }
 
 static void unref_cursor_worker(struct drm_flip_work *work, void *val)
drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +2 -2
index ff48944..771390b 100644
@@ -186,9 +186,9 @@ static void unref_fb_worker(struct drm_flip_work *work, void *val)
 		container_of(work, struct mdp5_crtc, unref_fb_work);
 	struct drm_device *dev = mdp5_crtc->base.dev;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 	drm_framebuffer_unreference(val);
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 }
 
 static void mdp5_crtc_destroy(struct drm_crtc *crtc)
drivers/gpu/drm/omapdrm/omap_crtc.c +5 -5
index a7c0010..a75934d 100644
@@ -319,13 +319,13 @@ static void page_flip_worker(struct work_struct *work)
 	struct drm_display_mode *mode = &crtc->mode;
 	struct drm_gem_object *bo;
 
-	mutex_lock(&crtc->mutex);
+	drm_modeset_lock(&crtc->mutex, NULL);
 	omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb,
 			0, 0, mode->hdisplay, mode->vdisplay,
 			crtc->x << 16, crtc->y << 16,
 			mode->hdisplay << 16, mode->vdisplay << 16,
 			vblank_cb, crtc);
-	mutex_unlock(&crtc->mutex);
+	drm_modeset_unlock(&crtc->mutex);
 
 	bo = omap_framebuffer_bo(crtc->primary->fb, 0);
 	drm_gem_object_unreference_unlocked(bo);
@@ -467,7 +467,7 @@ static void apply_worker(struct work_struct *work)
 	 * the callbacks and list modification all serialized
 	 * with respect to modesetting ioctls from userspace.
 	 */
-	mutex_lock(&crtc->mutex);
+	drm_modeset_lock(&crtc->mutex, NULL);
 	dispc_runtime_get();
 
 	/*
@@ -512,7 +512,7 @@ static void apply_worker(struct work_struct *work)
 
 out:
 	dispc_runtime_put();
-	mutex_unlock(&crtc->mutex);
+	drm_modeset_unlock(&crtc->mutex);
 }
 
 int omap_crtc_apply(struct drm_crtc *crtc,
@@ -520,7 +520,7 @@ int omap_crtc_apply(struct drm_crtc *crtc,
 {
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 
-	WARN_ON(!mutex_is_locked(&crtc->mutex));
+	WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
 
 	/* no need to queue it again if it is already queued: */
 	if (apply->queued)
drivers/gpu/drm/omapdrm/omap_plane.c +2 -2
index 8ae5c49..2d3c975 100644
@@ -72,9 +72,9 @@ static void unpin_worker(struct drm_flip_work *work, void *val)
 	struct drm_device *dev = omap_plane->base.dev;
 
 	omap_framebuffer_unpin(val);
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 	drm_framebuffer_unreference(val);
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 }
 
 /* update which fb (if any) is pinned for scanout */
drivers/gpu/drm/tilcdc/tilcdc_crtc.c +2 -2
index d642d4a0..92839ba 100644
@@ -45,9 +45,9 @@ static void unref_worker(struct drm_flip_work *work, void *val)
 		container_of(work, struct tilcdc_crtc, unref_work);
 	struct drm_device *dev = tilcdc_crtc->base.dev;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 	drm_framebuffer_unreference(val);
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 }
 
 static void set_scanout(struct drm_crtc *crtc, int n)
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +11 -11
index 6b9db5e..f338e3e 100644
@@ -187,7 +187,7 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
 	 * can do this since the caller in the drm core doesn't check anything
 	 * which is protected by any looks.
 	 */
-	mutex_unlock(&crtc->mutex);
+	drm_modeset_unlock(&crtc->mutex);
 	drm_modeset_lock_all(dev_priv->dev);
 
 	/* A lot of the code assumes this */
@@ -252,7 +252,7 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
 	ret = 0;
 out:
 	drm_modeset_unlock_all(dev_priv->dev);
-	mutex_lock(&crtc->mutex);
+	drm_modeset_lock(&crtc->mutex, NULL);
 
 	return ret;
 }
@@ -273,7 +273,7 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
 	 * can do this since the caller in the drm core doesn't check anything
 	 * which is protected by any looks.
 	 */
-	mutex_unlock(&crtc->mutex);
+	drm_modeset_unlock(&crtc->mutex);
 	drm_modeset_lock_all(dev_priv->dev);
 
 	vmw_cursor_update_position(dev_priv, shown,
@@ -281,7 +281,7 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
 				   du->cursor_y + du->hotspot_y);
 
 	drm_modeset_unlock_all(dev_priv->dev);
-	mutex_lock(&crtc->mutex);
+	drm_modeset_lock(&crtc->mutex, NULL);
 
 	return 0;
 }
@@ -387,7 +387,7 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
 	struct vmw_display_unit *du;
 	struct drm_crtc *crtc;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		du = vmw_crtc_to_du(crtc);
@@ -401,7 +401,7 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
 					64, 64, du->hotspot_x, du->hotspot_y);
 	}
 
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 }
 
 /*
@@ -1506,7 +1506,7 @@ int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data,
 	int ret = 0;
 
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 	if (arg->flags & DRM_VMW_CURSOR_BYPASS_ALL) {
 
 		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
@@ -1515,7 +1515,7 @@ int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data,
 			du->hotspot_y = arg->yhot;
 		}
 
-		mutex_unlock(&dev->mode_config.mutex);
+		drm_modeset_unlock(&dev->mode_config.mutex);
 		return 0;
 	}
 
@@ -1532,7 +1532,7 @@ int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data,
 	du->hotspot_y = arg->yhot;
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 
 	return ret;
 }
@@ -1682,7 +1682,7 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num,
 	struct vmw_display_unit *du;
 	struct drm_connector *con;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 
 #if 0
 	{
@@ -1712,7 +1712,7 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num,
 		con->status = vmw_du_connector_detect(con, true);
 	}
 
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock(&dev->mode_config.mutex);
 
 	return 0;
 }
include/drm/drmP.h +0 -5
index e8d0d17..5ac3587 100644
@@ -1264,11 +1264,6 @@ static inline int drm_device_is_unplugged(struct drm_device *dev)
 	return ret;
 }
 
-static inline bool drm_modeset_is_locked(struct drm_device *dev)
-{
-	return mutex_is_locked(&dev->mode_config.mutex);
-}
-
 static inline bool drm_is_render_client(const struct drm_file *file_priv)
 {
 	return file_priv->minor->type == DRM_MINOR_RENDER;
include/drm/drm_atomic.h +7 -0
index 5274212..ff72b81 100644
@@ -80,6 +80,8 @@ int drm_atomic_set_event(struct drm_device *dev,
 		struct drm_pending_vblank_event *event);
 int drm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state);
 int drm_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state);
+int drm_atomic_commit_unlocked(struct drm_device *dev,
+		struct drm_atomic_state *state);
 void drm_atomic_end(struct drm_device *dev, struct drm_atomic_state *state);
 
 /**
@@ -89,6 +91,11 @@ struct drm_atomic_state {
 	struct kref refcount;
 	struct drm_device *dev;
 	uint32_t flags;
+
+	bool committed;
+	bool checked;       /* just for debugging */
+
+	struct drm_modeset_acquire_ctx acquire_ctx;
 };
 
 static inline void
include/drm/drm_crtc.h +13 -6
index 4790cad..83e0f88 100644
@@ -33,6 +33,7 @@
 #include <linux/hdmi.h>
 #include <drm/drm_mode.h>
 #include <drm/drm_fourcc.h>
+#include <drm/drm_modeset_lock.h>
 
 struct drm_device;
 struct drm_mode_set;
@@ -194,6 +195,10 @@ struct drm_property {
 	struct list_head enum_blob_list;
 };
 
+void drm_modeset_lock_all(struct drm_device *dev);
+void drm_modeset_unlock_all(struct drm_device *dev);
+void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
+
 struct drm_crtc;
 struct drm_connector;
 struct drm_encoder;
@@ -273,6 +278,7 @@ struct drm_crtc_funcs {
  * drm_crtc - central CRTC control structure
  * @dev: parent DRM device
  * @head: list management
+ * @mutex: per-CRTC locking
  * @base: base KMS object for ID tracking etc.
  * @primary: primary plane for this CRTC
  * @cursor: cursor plane for this CRTC
@@ -307,7 +313,7 @@ struct drm_crtc {
 	 * state, ...) and a write lock for everything which can be update
 	 * without a full modeset (fb, cursor data, ...)
 	 */
-	struct mutex mutex;
+	struct drm_modeset_lock mutex;
 
 	struct drm_mode_object base;
 
@@ -729,7 +735,12 @@ struct drm_mode_group {
  * global restrictions are also here, e.g. dimension restrictions.
  */
 struct drm_mode_config {
-	struct mutex mutex; /* protects configuration (mode lists etc.) */
+
+	/* protects configuration (mode lists etc.): */
+	struct drm_modeset_lock mutex;
+	/* the current acquire ctx (for drm_modeset_lock_all()) */
+	struct drm_modeset_acquire_ctx *acquire_ctx;
+
 	struct mutex idr_mutex; /* for IDR management */
 	struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */
 	/* this is limited to one for now */
@@ -830,10 +841,6 @@ struct drm_prop_enum_list {
 	char *name;
 };
 
-extern void drm_modeset_lock_all(struct drm_device *dev);
-extern void drm_modeset_unlock_all(struct drm_device *dev);
-extern void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
-
 extern int drm_crtc_init_with_planes(struct drm_device *dev,
 				     struct drm_crtc *crtc,
 				     struct drm_plane *primary,
include/drm/drm_modeset_lock.h new file +130 -0

130 lines not on this page · raw message

include/uapi/drm/drm_mode.h +3 -0
index f104c26..12e2139 100644
@@ -496,4 +496,7 @@ struct drm_mode_destroy_dumb {
 	uint32_t handle;
 };
 
+#define DRM_MODE_ATOMIC_NONBLOCK  0x0200
+#define DRM_MODE_ATOMIC_NOLOCK    0x8000  /* only used internally */
+
 #endif
Signature · 1 line
1.9.0
#4 lore raw

Re: [PATCH 03/17] drm: convert crtc and mode_config to ww_mutex

drivers/gpu/drm/i915/intel_display.c bool intel_get_load_detect_pipe(struct drm_connector *connector, · line 8005

Quoted 6 lines · Rob Clark
drivers/gpu/drm/i915/intel_display.c +1 -1
@@ -8002,7 +8002,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
        if (encoder->crtc) {
                crtc = encoder->crtc;
 
-               mutex_lock(&crtc->mutex);
+               drm_modeset_lock(&crtc->mutex, NULL);

This is pretty much the reason why I think switching the mode_config.mutex to a ww_mutex is a bad idea: This call here nests within the mode_config.mutex and so must be acquired. Wiring the acquire context through everything is going to be fairly horrible, especially since you must be able to bail out when trying to lock with an axquire context.

My original design behind the crtc->mutex and mode_config.mutex split was that as long as the connector->crtc links didn't change you can get away with the crtc lock. setplane made a bit a mess out of this, but strictly speaking as long as you acquire all crtc locks involved in a potential plane switch (which ww_mtuxes can do) it'll be fine. Since noticing whether any connector properties change should be doable upfront I think we should try _really_ hard to keep the mode_config.mutex a plain mutex which wraps all the more fine-grained locks and is a catch-all for everything else but crtcs/planes. -Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
author
#5 lore raw

Re: [PATCH 03/17] drm: convert crtc and mode_config to ww_mutex

Quoted 5 lines · Daniel Vetter
Quoted 4 lines · Rob Clark
drivers/gpu/drm/i915/intel_display.c +0 -0
@@ -8002,7 +8002,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
        if (encoder->crtc) {
                crtc = encoder->crtc;
 
Quoted 10 lines

Review bool intel_get_load_detect_pipe(struct drm_connector *connector, · line 8005

Quoted 2 lines
(quoted diff) +1 -1
-               mutex_lock(&crtc->mutex);
+               drm_modeset_lock(&crtc->mutex, NULL);

This is pretty much the reason why I think switching the mode_config.mutex to a ww_mutex is a bad idea: This call here nests within the mode_config.mutex and so must be acquired. Wiring the acquire context through everything is going to be fairly horrible, especially since you must be able to bail out when trying to lock with an axquire context.

which is the call-path to here from mode_config.mutex? Is it possible to just move the locking to a higher level for a drm_modeset_lock_all()?

Quoted 9 lines

My original design behind the crtc->mutex and mode_config.mutex split was that as long as the connector->crtc links didn't change you can get away with the crtc lock. setplane made a bit a mess out of this, but strictly speaking as long as you acquire all crtc locks involved in a potential plane switch (which ww_mtuxes can do) it'll be fine. Since noticing whether any connector properties change should be doable upfront I think we should try _really_ hard to keep the mode_config.mutex a plain mutex which wraps all the more fine-grained locks and is a catch-all for everything else but crtcs/planes.

That is basically how it was in one of the earlier iterations of atomic.. but didn't hold mode_config.mutex in a lot of places where it was previously held.. and while I do want to make locking more fine grained I didn't want to try and do it at the same time as landing all these other changes.

BR,
-R

Quoted 5 lines

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

#6 lore raw

Re: [PATCH 03/17] drm: convert crtc and mode_config to ww_mutex

Quoted 17 lines · Rob Clark
Quoted 5 lines · Daniel Vetter
Quoted 4 lines · Rob Clark
drivers/gpu/drm/i915/intel_display.c +0 -0
@@ -8002,7 +8002,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
        if (encoder->crtc) {
                crtc = encoder->crtc;
 
Quoted 10 lines

Review bool intel_get_load_detect_pipe(struct drm_connector *connector, · line 8005

Quoted 2 lines
(quoted diff) +1 -1
-               mutex_lock(&crtc->mutex);
+               drm_modeset_lock(&crtc->mutex, NULL);

This is pretty much the reason why I think switching the mode_config.mutex to a ww_mutex is a bad idea: This call here nests within the mode_config.mutex and so must be acquired. Wiring the acquire context through everything is going to be fairly horrible, especially since you must be able to bail out when trying to lock with an axquire context.

Quoted 3 lines

which is the call-path to here from mode_config.mutex? Is it possible to just move the locking to a higher level for a drm_modeset_lock_all()?

Connector probing. And the entire point of crtc locks was to _not_ block all screen updates while we poke for a new edid or do load balancing. If you want to test this you need a gen3/4 with tv-out (native, not through sdvo) or a gen2 or i915g/gm with vga.

Quoted 10 lines
Quoted 9 lines

My original design behind the crtc->mutex and mode_config.mutex split was that as long as the connector->crtc links didn't change you can get away with the crtc lock. setplane made a bit a mess out of this, but strictly speaking as long as you acquire all crtc locks involved in a potential plane switch (which ww_mtuxes can do) it'll be fine. Since noticing whether any connector properties change should be doable upfront I think we should try _really_ hard to keep the mode_config.mutex a plain mutex which wraps all the more fine-grained locks and is a catch-all for everything else but crtcs/planes.

Quoted 5 lines

That is basically how it was in one of the earlier iterations of atomic.. but didn't hold mode_config.mutex in a lot of places where it was previously held.. and while I do want to make locking more fine grained I didn't want to try and do it at the same time as landing all these other changes.

Hm, maybe we should land the locking stuff first? I.e. just convert crtc->mutex into a ww_mutex, and then add more fine-grained locking to e.g. setplane by only grabbing the locks of the involved crtcs with the w/w logic. We might need an additional plane mutex to make it work. Iirc Ville had some patches for just this.

I'm arguing this since locking at the current interface I have a really hard time seeing how we're going to implement this in i915. Still reading around though.
-Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
author
#7 lore raw

Re: [PATCH 03/17] drm: convert crtc and mode_config to ww_mutex

Quoted 18 lines · Daniel Vetter
Quoted 17 lines · Rob Clark
Quoted 15 lines · Daniel Vetter

drivers/gpu/drm/i915/intel_display.c bool intel_get_load_detect_pipe(struct drm_connector *connector, · line 8005

Quoted 6 lines · Rob Clark
drivers/gpu/drm/i915/intel_display.c +1 -1
@@ -8002,7 +8002,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
        if (encoder->crtc) {
                crtc = encoder->crtc;
 
-               mutex_lock(&crtc->mutex);
+               drm_modeset_lock(&crtc->mutex, NULL);

This is pretty much the reason why I think switching the mode_config.mutex to a ww_mutex is a bad idea: This call here nests within the mode_config.mutex and so must be acquired. Wiring the acquire context through everything is going to be fairly horrible, especially since you must be able to bail out when trying to lock with an axquire context.

Quoted 8 lines
Quoted 3 lines

which is the call-path to here from mode_config.mutex? Is it possible to just move the locking to a higher level for a drm_modeset_lock_all()?

Connector probing. And the entire point of crtc locks was to _not_ block all screen updates while we poke for a new edid or do load balancing. If you want to test this you need a gen3/4 with tv-out (native, not through sdvo) or a gen2 or i915g/gm with vga.

hmm, I guess I'm still not quite seeing the issue. For non-atomic paths, we are grabbing mode_config and/or crtc mutex as bare mutexes in same spots as we did before. So if it worked before without nested_lock stuff it should still work now.

BR,
-R

#8 lore raw

Re: [PATCH 03/17] drm: convert crtc and mode_config to ww_mutex

Quoted 29 lines · Rob Clark
Quoted 18 lines · Daniel Vetter
Quoted 17 lines · Rob Clark
Quoted 15 lines · Daniel Vetter

drivers/gpu/drm/i915/intel_display.c bool intel_get_load_detect_pipe(struct drm_connector *connector, · line 8005

Quoted 6 lines · Rob Clark
drivers/gpu/drm/i915/intel_display.c +1 -1
@@ -8002,7 +8002,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
        if (encoder->crtc) {
                crtc = encoder->crtc;
 
-               mutex_lock(&crtc->mutex);
+               drm_modeset_lock(&crtc->mutex, NULL);

This is pretty much the reason why I think switching the mode_config.mutex to a ww_mutex is a bad idea: This call here nests within the mode_config.mutex and so must be acquired. Wiring the acquire context through everything is going to be fairly horrible, especially since you must be able to bail out when trying to lock with an axquire context.

Quoted 8 lines
Quoted 3 lines

which is the call-path to here from mode_config.mutex? Is it possible to just move the locking to a higher level for a drm_modeset_lock_all()?

Connector probing. And the entire point of crtc locks was to _not_ block all screen updates while we poke for a new edid or do load balancing. If you want to test this you need a gen3/4 with tv-out (native, not through sdvo) or a gen2 or i915g/gm with vga.

Quoted 4 lines

hmm, I guess I'm still not quite seeing the issue. For non-atomic paths, we are grabbing mode_config and/or crtc mutex as bare mutexes in same spots as we did before. So if it worked before without nested_lock stuff it should still work now.

Thread A is doing output probing.

Thread B is doing atomic modeset

Grabs mode_config.mutex

				Grabs crtc_A->ww_mutex

Tries to grab crtc_A->ww_mutex,
blocks since normal ww_mutex_lock

Tries to grab mode_config.mutex with ww acuiquire context, blocks since current holder hasn't acquired the mutex with a ww ticket

-> Deadlock.

You really can't mix lock nesting with w/w and lock nesting with a static hierarchy. It's all or nothing.
-Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#9 lore raw

Re: [PATCH 03/17] drm: convert crtc and mode_config to ww_mutex

Quoted 37 lines · Daniel Vetter
Quoted 29 lines · Rob Clark
Quoted 18 lines · Daniel Vetter
Quoted 17 lines · Rob Clark
Quoted 15 lines · Daniel Vetter

drivers/gpu/drm/i915/intel_display.c bool intel_get_load_detect_pipe(struct drm_connector *connector, · line 8005

Quoted 6 lines · Rob Clark
drivers/gpu/drm/i915/intel_display.c +1 -1
@@ -8002,7 +8002,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
        if (encoder->crtc) {
                crtc = encoder->crtc;
 
-               mutex_lock(&crtc->mutex);
+               drm_modeset_lock(&crtc->mutex, NULL);

This is pretty much the reason why I think switching the mode_config.mutex to a ww_mutex is a bad idea: This call here nests within the mode_config.mutex and so must be acquired. Wiring the acquire context through everything is going to be fairly horrible, especially since you must be able to bail out when trying to lock with an axquire context.

Quoted 8 lines
Quoted 3 lines

which is the call-path to here from mode_config.mutex? Is it possible to just move the locking to a higher level for a drm_modeset_lock_all()?

Connector probing. And the entire point of crtc locks was to _not_ block all screen updates while we poke for a new edid or do load balancing. If you want to test this you need a gen3/4 with tv-out (native, not through sdvo) or a gen2 or i915g/gm with vga.

Quoted 4 lines

hmm, I guess I'm still not quite seeing the issue. For non-atomic paths, we are grabbing mode_config and/or crtc mutex as bare mutexes in same spots as we did before. So if it worked before without nested_lock stuff it should still work now.

Thread A is doing output probing.

Quoted 8 lines

Thread B is doing atomic modeset

Grabs mode_config.mutex

				Grabs crtc_A->ww_mutex

Tries to grab crtc_A->ww_mutex,
blocks since normal ww_mutex_lock

.. blocks since normal ww_mutex_lock without acquire ticket.

Otherwise it's a bit unclear.
-Daniel

Quoted 15 lines

Tries to grab mode_config.mutex with ww acuiquire context, blocks since current holder hasn't acquired the mutex with a ww ticket

-> Deadlock.

You really can't mix lock nesting with w/w and lock nesting with a static hierarchy. It's all or nothing.
-Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
author
#10 lore raw

Re: [PATCH 03/17] drm: convert crtc and mode_config to ww_mutex

In reply to Daniel Vetter
Quoted 43 lines · Daniel Vetter
Quoted 29 lines · Rob Clark
Quoted 18 lines · Daniel Vetter
Quoted 17 lines · Rob Clark
Quoted 15 lines · Daniel Vetter

drivers/gpu/drm/i915/intel_display.c bool intel_get_load_detect_pipe(struct drm_connector *connector, · line 8005

Quoted 6 lines · Rob Clark
drivers/gpu/drm/i915/intel_display.c +1 -1
@@ -8002,7 +8002,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
        if (encoder->crtc) {
                crtc = encoder->crtc;
 
-               mutex_lock(&crtc->mutex);
+               drm_modeset_lock(&crtc->mutex, NULL);

This is pretty much the reason why I think switching the mode_config.mutex to a ww_mutex is a bad idea: This call here nests within the mode_config.mutex and so must be acquired. Wiring the acquire context through everything is going to be fairly horrible, especially since you must be able to bail out when trying to lock with an axquire context.

Quoted 8 lines
Quoted 3 lines

which is the call-path to here from mode_config.mutex? Is it possible to just move the locking to a higher level for a drm_modeset_lock_all()?

Connector probing. And the entire point of crtc locks was to _not_ block all screen updates while we poke for a new edid or do load balancing. If you want to test this you need a gen3/4 with tv-out (native, not through sdvo) or a gen2 or i915g/gm with vga.

Quoted 4 lines

hmm, I guess I'm still not quite seeing the issue. For non-atomic paths, we are grabbing mode_config and/or crtc mutex as bare mutexes in same spots as we did before. So if it worked before without nested_lock stuff it should still work now.

Thread A is doing output probing.

Thread B is doing atomic modeset

Grabs mode_config.mutex

                                Grabs crtc_A->ww_mutex
Quoted 7 lines

Tries to grab crtc_A->ww_mutex,
blocks since normal ww_mutex_lock

Tries to grab mode_config.mutex with ww acuiquire context, blocks since current holder hasn't acquired the mutex with a ww ticket

hmm, ok, I had thought this case, thread B would get -EDEADLK because lock was held, and not his acquire ctx. If that is not the case, then I would propose this:

All places doing things the old way, must grab mode_config.mutex first currently. And we use mode_config.mutex to protect mode_config.acquire_ctx. So all the lower spots grabbing individual crtc mutexes can safely use mode_config.acquire_ctx.

Then the only headache is propagating -EDEADLK up the call stack. If we are lucky, the all already propagate -EINTR, etc.

BR,
-R

Quoted 10 lines

-> Deadlock.

You really can't mix lock nesting with w/w and lock nesting with a static hierarchy. It's all or nothing.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

#11 lore raw

Re: [PATCH 03/17] drm: convert crtc and mode_config to ww_mutex

Quoted 11 lines · Rob Clark

hmm, ok, I had thought this case, thread B would get -EDEADLK because lock was held, and not his acquire ctx. If that is not the case, then I would propose this:

All places doing things the old way, must grab mode_config.mutex first currently. And we use mode_config.mutex to protect mode_config.acquire_ctx. So all the lower spots grabbing individual crtc mutexes can safely use mode_config.acquire_ctx.

Then the only headache is propagating -EDEADLK up the call stack. If we are lucky, the all already propagate -EINTR, etc.

The output poll work most definitely doesn't propagate -EINTR. Like I've said, this will be painful. And imo doing this also makes the kms locking into quite a mess overall.
-Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
author
#12 lore raw

Re: [PATCH 03/17] drm: convert crtc and mode_config to ww_mutex

Quoted 10 lines · Daniel Vetter
Quoted 9 lines · Rob Clark

hmm, ok, I had thought this case, thread B would get -EDEADLK because lock was held, and not his acquire ctx. If that is not the case, then I would propose this:

All places doing things the old way, must grab mode_config.mutex first currently. And we use mode_config.mutex to protect mode_config.acquire_ctx. So all the lower spots grabbing individual crtc mutexes can safely use mode_config.acquire_ctx.

Quoted 6 lines
Quoted 2 lines

Then the only headache is propagating -EDEADLK up the call stack. If we are lucky, the all already propagate -EINTR, etc.

The output poll work most definitely doesn't propagate -EINTR. Like I've said, this will be painful. And imo doing this also makes the kms locking into quite a mess overall.

Well, we could hold mode_config.mutex as a traditional mutex around atomic operations. What you loose out would be now _NONBLOCK operations could conceivable call into driver paths without mode_config.mutex held. This was the advantage of converting mode_config.mutex as well. Granted, it is slightly theoretical because until we expose atomic ioctl it would only apply to page_flip (which was not holding mode_config.mutex). And we also want to get rid of mode_config.mutex in these paths too.

Otoh, if we want to make locking more fine grained, more use of ww_mutex seems like the best way. And if that means adding a return value to a fxn here/there and propagating errors properly, maybe we should just go ahead and do that. It sounds like the right long term solution anyways.

BR,
-R

Quoted 5 lines

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

#13 lore raw

Re: [PATCH 03/17] drm: convert crtc and mode_config to ww_mutex

Quoted 27 lines · Rob Clark
Quoted 10 lines · Daniel Vetter
Quoted 9 lines · Rob Clark

hmm, ok, I had thought this case, thread B would get -EDEADLK because lock was held, and not his acquire ctx. If that is not the case, then I would propose this:

All places doing things the old way, must grab mode_config.mutex first currently. And we use mode_config.mutex to protect mode_config.acquire_ctx. So all the lower spots grabbing individual crtc mutexes can safely use mode_config.acquire_ctx.

Quoted 6 lines
Quoted 2 lines

Then the only headache is propagating -EDEADLK up the call stack. If we are lucky, the all already propagate -EINTR, etc.

The output poll work most definitely doesn't propagate -EINTR. Like I've said, this will be painful. And imo doing this also makes the kms locking into quite a mess overall.

Well, we could hold mode_config.mutex as a traditional mutex around atomic operations. What you loose out would be now _NONBLOCK operations could conceivable call into driver paths without mode_config.mutex held. This was the advantage of converting mode_config.mutex as well. Granted, it is slightly theoretical because until we expose atomic ioctl it would only apply to page_flip (which was not holding mode_config.mutex). And we also want to get rid of mode_config.mutex in these paths too.

Quoted 5 lines

Otoh, if we want to make locking more fine grained, more use of ww_mutex seems like the best way. And if that means adding a return value to a fxn here/there and propagating errors properly, maybe we should just go ahead and do that. It sounds like the right long term solution anyways.

Yeah, I'm starting to lean towards trying to elide mode_config.mutex completely from the atomic paths (and modesets in general). I think the only bits we really need is adding ww mutexes to planes _and_ to connectors. The atomic would _only_ ever acquire ww mutexes, and we would be able to guarante that most of them are only held short times so that we don't need to bother with trylocking them for NONBLOCK. That should simply the atomic logic a bit I hope.

So that, and a full subsystem audit unfortunately :( -Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
author
#14 lore raw

Re: [PATCH 03/17] drm: convert crtc and mode_config to ww_mutex

Quoted 42 lines · Daniel Vetter
Quoted 27 lines · Rob Clark
Quoted 10 lines · Daniel Vetter
Quoted 9 lines · Rob Clark

hmm, ok, I had thought this case, thread B would get -EDEADLK because lock was held, and not his acquire ctx. If that is not the case, then I would propose this:

All places doing things the old way, must grab mode_config.mutex first currently. And we use mode_config.mutex to protect mode_config.acquire_ctx. So all the lower spots grabbing individual crtc mutexes can safely use mode_config.acquire_ctx.

Quoted 6 lines
Quoted 2 lines

Then the only headache is propagating -EDEADLK up the call stack. If we are lucky, the all already propagate -EINTR, etc.

The output poll work most definitely doesn't propagate -EINTR. Like I've said, this will be painful. And imo doing this also makes the kms locking into quite a mess overall.

Well, we could hold mode_config.mutex as a traditional mutex around atomic operations. What you loose out would be now _NONBLOCK operations could conceivable call into driver paths without mode_config.mutex held. This was the advantage of converting mode_config.mutex as well. Granted, it is slightly theoretical because until we expose atomic ioctl it would only apply to page_flip (which was not holding mode_config.mutex). And we also want to get rid of mode_config.mutex in these paths too.

Quoted 5 lines

Otoh, if we want to make locking more fine grained, more use of ww_mutex seems like the best way. And if that means adding a return value to a fxn here/there and propagating errors properly, maybe we should just go ahead and do that. It sounds like the right long term solution anyways.

Yeah, I'm starting to lean towards trying to elide mode_config.mutex completely from the atomic paths (and modesets in general). I think the only bits we really need is adding ww mutexes to planes _and_ to connectors. The atomic would _only_ ever acquire ww mutexes, and we would be able to guarante that most of them are only held short times so that we don't need to bother with trylocking them for NONBLOCK. That should simply the atomic logic a bit I hope.

Quoted 1 line

So that, and a full subsystem audit unfortunately :(

well, getting rid of any global lock from atomic path is, I hope, the eventual goal. But we are *really* late already with atomic, and too many other things backing up on top of this. I suppose I should have a closer look at the detect paths, to just see how hairy the alternative of adding error propagation would be. Although maybe not today (it is supposed to be a holiday here.. and I've already spent enough of the weekend on atomic ;-))

Just to get *something* merged to unblock driver work and maybe get people starting to think about plumbing this through userspace (xrandr atomic modeset, for example), maybe the way to go is just revert mode_config.mutex to a traditional mutex for now. The weird cases only start to come up with real atomic ioctls, and we could use a driver flag to opt-in to that on a per driver basis.

BR,
-R

Quoted 5 lines

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

#15 lore raw

Re: [PATCH 03/17] drm: convert crtc and mode_config to ww_mutex

Quoted 53 lines · Rob Clark
Quoted 42 lines · Daniel Vetter
Quoted 27 lines · Rob Clark
Quoted 10 lines · Daniel Vetter
Quoted 9 lines · Rob Clark

hmm, ok, I had thought this case, thread B would get -EDEADLK because lock was held, and not his acquire ctx. If that is not the case, then I would propose this:

All places doing things the old way, must grab mode_config.mutex first currently. And we use mode_config.mutex to protect mode_config.acquire_ctx. So all the lower spots grabbing individual crtc mutexes can safely use mode_config.acquire_ctx.

Quoted 6 lines
Quoted 2 lines

Then the only headache is propagating -EDEADLK up the call stack. If we are lucky, the all already propagate -EINTR, etc.

The output poll work most definitely doesn't propagate -EINTR. Like I've said, this will be painful. And imo doing this also makes the kms locking into quite a mess overall.

Well, we could hold mode_config.mutex as a traditional mutex around atomic operations. What you loose out would be now _NONBLOCK operations could conceivable call into driver paths without mode_config.mutex held. This was the advantage of converting mode_config.mutex as well. Granted, it is slightly theoretical because until we expose atomic ioctl it would only apply to page_flip (which was not holding mode_config.mutex). And we also want to get rid of mode_config.mutex in these paths too.

Quoted 5 lines

Otoh, if we want to make locking more fine grained, more use of ww_mutex seems like the best way. And if that means adding a return value to a fxn here/there and propagating errors properly, maybe we should just go ahead and do that. It sounds like the right long term solution anyways.

Yeah, I'm starting to lean towards trying to elide mode_config.mutex completely from the atomic paths (and modesets in general). I think the only bits we really need is adding ww mutexes to planes _and_ to connectors. The atomic would _only_ ever acquire ww mutexes, and we would be able to guarante that most of them are only held short times so that we don't need to bother with trylocking them for NONBLOCK. That should simply the atomic logic a bit I hope.

Quoted 1 line

So that, and a full subsystem audit unfortunately :(

well, getting rid of any global lock from atomic path is, I hope, the eventual goal. But we are *really* late already with atomic, and too many other things backing up on top of this. I suppose I should have a closer look at the detect paths, to just see how hairy the alternative of adding error propagation would be. Although maybe not today (it is supposed to be a holiday here.. and I've already spent enough of the weekend on atomic ;-))

Quoted 6 lines

Just to get *something* merged to unblock driver work and maybe get people starting to think about plumbing this through userspace (xrandr atomic modeset, for example), maybe the way to go is just revert mode_config.mutex to a traditional mutex for now. The weird cases only start to come up with real atomic ioctls, and we could use a driver flag to opt-in to that on a per driver basis.

This will result in people raving about regressions, which from a maintainer pov I'll reject. If we want to chicken out of this question I'd vote for an drm_modeset_lock_all for the atomic paths, which also isn't really helpful. I don't really think there's an easy answer.

Wrt unblocking driver work: In i915 we keep on plunging ahead without the interface stuff thus far. And wrt unblocking everything else: I hear a lot of people screaming about the lack of atomic updates, but at least within Intel not many people throwing resources at it. So my impression is that it can't be that bad really.
-Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
author
#16 lore raw

PATCH 4/17 drm: add object property type

In reply to Rob Clark

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  | 60 +++++++++++++++++++++++++++++++++++----------
 include/drm/drm_crtc.h      | 27 ++++++++++++++++++++
 include/uapi/drm/drm_mode.h | 14 +++++++++++
 3 files changed, 88 insertions(+), 13 deletions(-)
drivers/gpu/drm/drm_crtc.c +47 -13
index dd10e4c..c049ba7 100644
@@ -3142,6 +3142,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)
@@ -3162,6 +3164,9 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags,
 	}
 
 	list_add_tail(&property->head, &dev->mode_config.property_list);
+
+	BUG_ON(!drm_property_type_valid(property));
+
 	return property;
 fail:
 	kfree(property->values);
@@ -3299,6 +3304,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);
+
 /**
  * drm_property_add_enum - add a possible value to an enumeration property
  * @property: enumeration property to change
@@ -3319,14 +3341,16 @@ int drm_property_add_enum(struct drm_property *property, int index,
 {
 	struct drm_property_enum *prop_enum;
 
-	if (!(property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)))
+	if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
+			drm_property_type_is(property, DRM_MODE_PROP_BITMASK)))
 		return -EINVAL;
 
 	/*
 	 * Bitmask enum properties have the additional constraint of values
 	 * from 0 to 63
 	 */
-	if ((property->flags & DRM_MODE_PROP_BITMASK) && (value > 63))
+	if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) &&
+			(value > 63))
 		return -EINVAL;
 
 	if (!list_empty(&property->enum_blob_list)) {
@@ -3509,10 +3533,11 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
 	}
 	property = obj_to_property(obj);
 
-	if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
+	if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
+			drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
 		list_for_each_entry(prop_enum, &property->enum_blob_list, head)
 			enum_count++;
-	} else if (property->flags & DRM_MODE_PROP_BLOB) {
+	} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
 		list_for_each_entry(prop_blob, &property->enum_blob_list, head)
 			blob_count++;
 	}
@@ -3534,7 +3559,8 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
 	}
 	out_resp->count_values = value_count;
 
-	if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
+	if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
+			drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
 		if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
 			copied = 0;
 			enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr;
@@ -3556,7 +3582,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
 		out_resp->count_enum_blobs = enum_count;
 	}
 
-	if (property->flags & DRM_MODE_PROP_BLOB) {
+	if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
 		if ((out_resp->count_enum_blobs >= blob_count) && blob_count) {
 			copied = 0;
 			blob_id_ptr = (uint32_t __user *)(unsigned long)out_resp->enum_blob_ptr;
@@ -3712,19 +3738,25 @@ static bool drm_property_change_is_valid(struct drm_property *property,
 {
 	if (property->flags & DRM_MODE_PROP_IMMUTABLE)
 		return false;
-	if (property->flags & DRM_MODE_PROP_RANGE) {
+
+	if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) {
 		if (value < property->values[0] || value > property->values[1])
 			return false;
 		return true;
-	} else if (property->flags & DRM_MODE_PROP_BITMASK) {
+	} else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
 		int i;
 		uint64_t valid_mask = 0;
 		for (i = 0; i < property->num_values; i++)
 			valid_mask |= (1ULL << property->values[i]);
 		return !(value & ~valid_mask);
-	} else if (property->flags & DRM_MODE_PROP_BLOB) {
+	} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
 		/* Only the driver knows */
 		return true;
+	} else if (drm_property_type_is(property, 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++)
@@ -3815,9 +3847,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, struct drm_atomic_state *state,
-		struct drm_property *property, uint64_t value, void *blob_data)
+static int drm_mode_set_obj_prop(struct drm_mode_object *obj,
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t value, void *blob_data)
 {
 	if (drm_property_change_is_valid(property, value)) {
 		switch (obj->type) {
@@ -3831,6 +3863,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;
@@ -3866,7 +3900,7 @@ static int drm_mode_set_obj_prop_id(struct drm_device *dev,
 		return -ENOENT;
 	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);
 }
 
include/drm/drm_crtc.h +27 -0
index 83e0f88..65bfb8b 100644
@@ -191,6 +191,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;
 };
@@ -941,6 +942,23 @@ extern void drm_mode_config_cleanup(struct drm_device *dev);
 
 extern int drm_mode_connector_update_edid_property(struct drm_connector *connector,
 						struct edid *edid);
+
+static inline bool drm_property_type_is(struct drm_property *property,
+		uint32_t type)
+{
+	/* instanceof for props.. handles extended type vs original types: */
+	if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE)
+		return (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) == type;
+	return property->flags & type;
+}
+
+static inline bool drm_property_type_valid(struct drm_property *property)
+{
+	if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE)
+		return !(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
+	return !!(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
+}
+
 extern int drm_object_property_set_value(struct drm_mode_object *obj,
 					 struct drm_property *property,
 					 uint64_t val);
@@ -974,6 +992,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);
@@ -990,6 +1010,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);
include/uapi/drm/drm_mode.h +14 -0
index 12e2139..516425d 100644
@@ -251,6 +251,20 @@ struct drm_mode_get_connector {
 #define DRM_MODE_PROP_BLOB	(1<<4)
 #define DRM_MODE_PROP_BITMASK	(1<<5) /* bitmask of enumerated types */
 
+/* non-extended types: legacy bitmask, one bit per type: */
+#define DRM_MODE_PROP_LEGACY_TYPE  ( \
+		DRM_MODE_PROP_RANGE | \
+		DRM_MODE_PROP_ENUM | \
+		DRM_MODE_PROP_BLOB | \
+		DRM_MODE_PROP_BITMASK)
+
+/* extended-types: rather than continue to consume a bit per type,
+ * grab a chunk of the bits to use as integer type id.
+ */
+#define DRM_MODE_PROP_EXTENDED_TYPE	0x0000ffc0
+#define DRM_MODE_PROP_TYPE(n)		((n) << 6)
+#define DRM_MODE_PROP_OBJECT		DRM_MODE_PROP_TYPE(1)
+
 struct drm_mode_property_enum {
 	__u64 value;
 	char name[DRM_PROP_NAME_LEN];
Signature · 1 line
1.9.0
#17 lore raw

Re: [PATCH 04/17] drm: add object property type

Quoted 125 lines · Rob Clark

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  | 60 +++++++++++++++++++++++++++++++++++----------
 include/drm/drm_crtc.h      | 27 ++++++++++++++++++++
 include/uapi/drm/drm_mode.h | 14 +++++++++++
 3 files changed, 88 insertions(+), 13 deletions(-)
drivers/gpu/drm/drm_crtc.c +35 -8
index dd10e4c..c049ba7 100644
@@ -3142,6 +3142,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)
@@ -3162,6 +3164,9 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags,
 	}
 
 	list_add_tail(&property->head, &dev->mode_config.property_list);
+
+	BUG_ON(!drm_property_type_valid(property));
+
 	return property;
 fail:
 	kfree(property->values);
@@ -3299,6 +3304,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);
+
 /**
  * drm_property_add_enum - add a possible value to an enumeration property
  * @property: enumeration property to change
@@ -3319,14 +3341,16 @@ int drm_property_add_enum(struct drm_property *property, int index,
 {
 	struct drm_property_enum *prop_enum;
 
-	if (!(property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)))
+	if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
+			drm_property_type_is(property, DRM_MODE_PROP_BITMASK)))
 		return -EINVAL;
 
 	/*
 	 * Bitmask enum properties have the additional constraint of values
 	 * from 0 to 63
 	 */
-	if ((property->flags & DRM_MODE_PROP_BITMASK) && (value > 63))
+	if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) &&
+			(value > 63))
 		return -EINVAL;
 
 	if (!list_empty(&property->enum_blob_list)) {
@@ -3509,10 +3533,11 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
 	}
 	property = obj_to_property(obj);
 
-	if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
+	if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
+			drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
 		list_for_each_entry(prop_enum, &property->enum_blob_list, head)
 			enum_count++;
-	} else if (property->flags & DRM_MODE_PROP_BLOB) {
+	} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
 		list_for_each_entry(prop_blob, &property->enum_blob_list, head)
 			blob_count++;
 	}
@@ -3534,7 +3559,8 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
 	}
 	out_resp->count_values = value_count;
 
-	if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
+	if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
+			drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
 		if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
 			copied = 0;
 			enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr;
@@ -3556,7 +3582,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
 		out_resp->count_enum_blobs = enum_count;
 	}
 
-	if (property->flags & DRM_MODE_PROP_BLOB) {
+	if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
 		if ((out_resp->count_enum_blobs >= blob_count) && blob_count) {
 			copied = 0;
 			blob_id_ptr = (uint32_t __user *)(unsigned long)out_resp->enum_blob_ptr;
@@ -3712,19 +3738,25 @@ static bool drm_property_change_is_valid(struct drm_property *property,
 {
 	if (property->flags & DRM_MODE_PROP_IMMUTABLE)
 		return false;
-	if (property->flags & DRM_MODE_PROP_RANGE) {
+
+	if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) {
 		if (value < property->values[0] || value > property->values[1])
 			return false;
 		return true;
-	} else if (property->flags & DRM_MODE_PROP_BITMASK) {
+	} else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
 		int i;
 		uint64_t valid_mask = 0;
 		for (i = 0; i < property->num_values; i++)
 			valid_mask |= (1ULL << property->values[i]);

drivers/gpu/drm/drm_crtc.c static bool drm_property_change_is_valid(struct drm_property *property, · line 3759

Quoted 10 lines
drivers/gpu/drm/drm_crtc.c +6 -1
 		return !(value & ~valid_mask);
-	} else if (property->flags & DRM_MODE_PROP_BLOB) {
+	} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
 		/* Only the driver knows */
 		return true;
+	} else if (drm_property_type_is(property, 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;

Ok, so this usage is indeed safe for framebuffers since you only compare the pointer against NULL. But you can't ever access this pointer since it might disappear any time after you've dropped the idr lock. I think what you actually want here is a new interface drm_mode_object_exists which just returns a bool.

That won't expose any risky things to callers and we can still keep the restriction that calling drm_mode_object_get for framebuffers is a BUG. -Daniel

Quoted 121 lines
drivers/gpu/drm/drm_crtc.c +6 -4
 	} else {
 		int i;
 		for (i = 0; i < property->num_values; i++)
@@ -3815,9 +3847,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, struct drm_atomic_state *state,
-		struct drm_property *property, uint64_t value, void *blob_data)
+static int drm_mode_set_obj_prop(struct drm_mode_object *obj,
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t value, void *blob_data)
 {
 	if (drm_property_change_is_valid(property, value)) {
 		switch (obj->type) {
@@ -3831,6 +3863,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;
@@ -3866,7 +3900,7 @@ static int drm_mode_set_obj_prop_id(struct drm_device *dev,
 		return -ENOENT;
 	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);
 }
 
include/drm/drm_crtc.h +27 -0
index 83e0f88..65bfb8b 100644
@@ -191,6 +191,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;
 };
@@ -941,6 +942,23 @@ extern void drm_mode_config_cleanup(struct drm_device *dev);
 
 extern int drm_mode_connector_update_edid_property(struct drm_connector *connector,
 						struct edid *edid);
+
+static inline bool drm_property_type_is(struct drm_property *property,
+		uint32_t type)
+{
+	/* instanceof for props.. handles extended type vs original types: */
+	if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE)
+		return (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) == type;
+	return property->flags & type;
+}
+
+static inline bool drm_property_type_valid(struct drm_property *property)
+{
+	if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE)
+		return !(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
+	return !!(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
+}
+
 extern int drm_object_property_set_value(struct drm_mode_object *obj,
 					 struct drm_property *property,
 					 uint64_t val);
@@ -974,6 +992,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);
@@ -990,6 +1010,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);
include/uapi/drm/drm_mode.h +14 -0
index 12e2139..516425d 100644
@@ -251,6 +251,20 @@ struct drm_mode_get_connector {
 #define DRM_MODE_PROP_BLOB	(1<<4)
 #define DRM_MODE_PROP_BITMASK	(1<<5) /* bitmask of enumerated types */
 
+/* non-extended types: legacy bitmask, one bit per type: */
+#define DRM_MODE_PROP_LEGACY_TYPE  ( \
+		DRM_MODE_PROP_RANGE | \
+		DRM_MODE_PROP_ENUM | \
+		DRM_MODE_PROP_BLOB | \
+		DRM_MODE_PROP_BITMASK)
+
+/* extended-types: rather than continue to consume a bit per type,
+ * grab a chunk of the bits to use as integer type id.
+ */
+#define DRM_MODE_PROP_EXTENDED_TYPE	0x0000ffc0
+#define DRM_MODE_PROP_TYPE(n)		((n) << 6)
+#define DRM_MODE_PROP_OBJECT		DRM_MODE_PROP_TYPE(1)
+
 struct drm_mode_property_enum {
 	__u64 value;
 	char name[DRM_PROP_NAME_LEN];
Signature · 1 line
1.9.0
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#18 lore raw

Re: [PATCH 04/17] drm: add object property type

Quoted 13 lines · Daniel Vetter

drivers/gpu/drm/drm_crtc.c static bool drm_property_change_is_valid(struct drm_property *property, · line 3759

Quoted 5 lines · Rob Clark
drivers/gpu/drm/drm_crtc.c +5 -0
+	} else if (drm_property_type_is(property, 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;

Ok, so this usage is indeed safe for framebuffers since you only compare the pointer against NULL. But you can't ever access this pointer since it might disappear any time after you've dropped the idr lock. I think what you actually want here is a new interface drm_mode_object_exists which just returns a bool.

Quoted 2 lines

That won't expose any risky things to callers and we can still keep the restriction that calling drm_mode_object_get for framebuffers is a BUG.

s/object_get/object_find/ I've meant ofc.
-Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
author
#19 lore raw

Re: [PATCH 04/17] drm: add object property type

In reply to Daniel Vetter
Quoted 134 lines · Daniel Vetter
Quoted 133 lines · Rob Clark

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  | 60 +++++++++++++++++++++++++++++++++++----------
 include/drm/drm_crtc.h      | 27 ++++++++++++++++++++
 include/uapi/drm/drm_mode.h | 14 +++++++++++
 3 files changed, 88 insertions(+), 13 deletions(-)
drivers/gpu/drm/drm_crtc.c +39 -9
index dd10e4c..c049ba7 100644
@@ -3142,6 +3142,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)
@@ -3162,6 +3164,9 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags,
      }
 
      list_add_tail(&property->head, &dev->mode_config.property_list);
+
+     BUG_ON(!drm_property_type_valid(property));
+
      return property;
 fail:
      kfree(property->values);
@@ -3299,6 +3304,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);
+
 /**
  * drm_property_add_enum - add a possible value to an enumeration property
  * @property: enumeration property to change
@@ -3319,14 +3341,16 @@ int drm_property_add_enum(struct drm_property *property, int index,
 {
      struct drm_property_enum *prop_enum;
 
-     if (!(property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)))
+     if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
+                     drm_property_type_is(property, DRM_MODE_PROP_BITMASK)))
              return -EINVAL;
 
      /*
       * Bitmask enum properties have the additional constraint of values
       * from 0 to 63
       */
-     if ((property->flags & DRM_MODE_PROP_BITMASK) && (value > 63))
+     if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) &&
+                     (value > 63))
              return -EINVAL;
 
      if (!list_empty(&property->enum_blob_list)) {
@@ -3509,10 +3533,11 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
      }
      property = obj_to_property(obj);
 
-     if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
+     if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
+                     drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
              list_for_each_entry(prop_enum, &property->enum_blob_list, head)
                      enum_count++;
-     } else if (property->flags & DRM_MODE_PROP_BLOB) {
+     } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
              list_for_each_entry(prop_blob, &property->enum_blob_list, head)
                      blob_count++;
      }
@@ -3534,7 +3559,8 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
      }
      out_resp->count_values = value_count;
 
-     if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
+     if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
+                     drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
              if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
                      copied = 0;
                      enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr;
@@ -3556,7 +3582,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
              out_resp->count_enum_blobs = enum_count;
      }
 
-     if (property->flags & DRM_MODE_PROP_BLOB) {
+     if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
              if ((out_resp->count_enum_blobs >= blob_count) && blob_count) {
                      copied = 0;
                      blob_id_ptr = (uint32_t __user *)(unsigned long)out_resp->enum_blob_ptr;
@@ -3712,19 +3738,25 @@ static bool drm_property_change_is_valid(struct drm_property *property,
 {
      if (property->flags & DRM_MODE_PROP_IMMUTABLE)
              return false;
-     if (property->flags & DRM_MODE_PROP_RANGE) {
+
+     if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) {
              if (value < property->values[0] || value > property->values[1])
                      return false;
              return true;
-     } else if (property->flags & DRM_MODE_PROP_BITMASK) {
+     } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
              int i;
              uint64_t valid_mask = 0;
              for (i = 0; i < property->num_values; i++)
                      valid_mask |= (1ULL << property->values[i]);
              return !(value & ~valid_mask);
-     } else if (property->flags & DRM_MODE_PROP_BLOB) {
+     } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
              /* Only the driver knows */
              return true;
+     } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
+             /* a zero value for an object property translates to null: */
+             if (value == 0)
Quoted 8 lines

drivers/gpu/drm/drm_crtc.c static bool drm_property_change_is_valid(struct drm_property *property, · line 3759

Quoted 2 lines
drivers/gpu/drm/drm_crtc.c +2 -0
+                     return true;
+             return drm_property_get_obj(property, value) != NULL;

Ok, so this usage is indeed safe for framebuffers since you only compare the pointer against NULL. But you can't ever access this pointer since it might disappear any time after you've dropped the idr lock. I think what you actually want here is a new interface drm_mode_object_exists which just returns a bool.

Hmm, I think I'll just drop drm_property_get_obj() and call directly _object_find() here, I think. Unless we come up with other spots that need a drm_mode_object_exists(). That would avoid potential future misunderstandings.

BR,
-R

Quoted 130 lines

That won't expose any risky things to callers and we can still keep the restriction that calling drm_mode_object_get for framebuffers is a BUG. -Daniel

Quoted 119 lines
drivers/gpu/drm/drm_crtc.c +6 -4
      } else {
              int i;
              for (i = 0; i < property->num_values; i++)
@@ -3815,9 +3847,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, struct drm_atomic_state *state,
-             struct drm_property *property, uint64_t value, void *blob_data)
+static int drm_mode_set_obj_prop(struct drm_mode_object *obj,
+             struct drm_atomic_state *state, struct drm_property *property,
+             uint64_t value, void *blob_data)
 {
      if (drm_property_change_is_valid(property, value)) {
              switch (obj->type) {
@@ -3831,6 +3863,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;
@@ -3866,7 +3900,7 @@ static int drm_mode_set_obj_prop_id(struct drm_device *dev,
              return -ENOENT;
      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);
 }
 
include/drm/drm_crtc.h +27 -0
index 83e0f88..65bfb8b 100644
@@ -191,6 +191,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;
 };
@@ -941,6 +942,23 @@ extern void drm_mode_config_cleanup(struct drm_device *dev);
 
 extern int drm_mode_connector_update_edid_property(struct drm_connector *connector,
                                              struct edid *edid);
+
+static inline bool drm_property_type_is(struct drm_property *property,
+             uint32_t type)
+{
+     /* instanceof for props.. handles extended type vs original types: */
+     if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE)
+             return (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) == type;
+     return property->flags & type;
+}
+
+static inline bool drm_property_type_valid(struct drm_property *property)
+{
+     if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE)
+             return !(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
+     return !!(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
+}
+
 extern int drm_object_property_set_value(struct drm_mode_object *obj,
                                       struct drm_property *property,
                                       uint64_t val);
@@ -974,6 +992,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);
@@ -990,6 +1010,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);
include/uapi/drm/drm_mode.h +14 -1
index 12e2139..516425d 100644
@@ -251,6 +251,20 @@ struct drm_mode_get_connector {
 #define DRM_MODE_PROP_BLOB   (1<<4)
 #define DRM_MODE_PROP_BITMASK        (1<<5) /* bitmask of enumerated types */
 
+/* non-extended types: legacy bitmask, one bit per type: */
+#define DRM_MODE_PROP_LEGACY_TYPE  ( \
+             DRM_MODE_PROP_RANGE | \
+             DRM_MODE_PROP_ENUM | \
+             DRM_MODE_PROP_BLOB | \
+             DRM_MODE_PROP_BITMASK)
+
+/* extended-types: rather than continue to consume a bit per type,
+ * grab a chunk of the bits to use as integer type id.
+ */
+#define DRM_MODE_PROP_EXTENDED_TYPE  0x0000ffc0
+#define DRM_MODE_PROP_TYPE(n)                ((n) << 6)
+#define DRM_MODE_PROP_OBJECT         DRM_MODE_PROP_TYPE(1)
+
 struct drm_mode_property_enum {
      __u64 value;
      char name[DRM_PROP_NAME_LEN];
--
Quoted 2 lines

1.9.0

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

author
#20 lore raw

PATCH 5/17 drm: add signed-range property type

In reply to Rob Clark

Like range, but values are signed.

---
 drivers/gpu/drm/drm_crtc.c  | 45 +++++++++++++++++++++++++++++++++------------
 include/drm/drm_crtc.h      | 12 ++++++++++++
 include/uapi/drm/drm_mode.h |  1 +
 3 files changed, 46 insertions(+), 12 deletions(-)
drivers/gpu/drm/drm_crtc.c +33 -12
index c049ba7..fa86fba 100644
@@ -3267,6 +3267,22 @@ struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_property_create_bitmask);
 
+static struct drm_property *property_create_range(struct drm_device *dev,
+					 int flags, const char *name,
+					 uint64_t min, uint64_t max)
+{
+	struct drm_property *property;
+
+	property = drm_property_create(dev, flags, name, 2);
+	if (!property)
+		return NULL;
+
+	property->values[0] = min;
+	property->values[1] = max;
+
+	return property;
+}
+
 /**
  * drm_property_create - create a new ranged property type
  * @dev: drm device
@@ -3289,21 +3305,20 @@ 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 *property;
-
-	flags |= DRM_MODE_PROP_RANGE;
-
-	property = drm_property_create(dev, flags, name, 2);
-	if (!property)
-		return NULL;
-
-	property->values[0] = min;
-	property->values[1] = max;
-
-	return property;
+	return property_create_range(dev, DRM_MODE_PROP_RANGE | flags,
+			name, min, max);
 }
 EXPORT_SYMBOL(drm_property_create_range);
 
+struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
+					 int flags, const char *name,
+					 int64_t min, int64_t max)
+{
+	return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags,
+			name, I642U64(min), I642U64(max));
+}
+EXPORT_SYMBOL(drm_property_create_signed_range);
+
 struct drm_property *drm_property_create_object(struct drm_device *dev,
 					 int flags, const char *name, uint32_t type)
 {
@@ -3743,6 +3758,12 @@ static bool drm_property_change_is_valid(struct drm_property *property,
 		if (value < property->values[0] || value > property->values[1])
 			return false;
 		return true;
+	} else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) {
+		int64_t svalue = U642I64(value);
+		if (svalue < U642I64(property->values[0]) ||
+				svalue > U642I64(property->values[1]))
+			return false;
+		return true;
 	} else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
 		int i;
 		uint64_t valid_mask = 0;
include/drm/drm_crtc.h +12 -0
index 65bfb8b..cd4a61a 100644
@@ -65,6 +65,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);
+}
+
 enum drm_connector_force {
 	DRM_FORCE_UNSPECIFIED,
 	DRM_FORCE_OFF,
@@ -992,6 +1001,9 @@ 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_signed_range(struct drm_device *dev,
+					 int flags, const char *name,
+					 int64_t min, int64_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);
include/uapi/drm/drm_mode.h +1 -0
index 516425d..6421edc 100644
@@ -264,6 +264,7 @@ struct drm_mode_get_connector {
 #define DRM_MODE_PROP_EXTENDED_TYPE	0x0000ffc0
 #define DRM_MODE_PROP_TYPE(n)		((n) << 6)
 #define DRM_MODE_PROP_OBJECT		DRM_MODE_PROP_TYPE(1)
+#define DRM_MODE_PROP_SIGNED_RANGE	DRM_MODE_PROP_TYPE(2)
 
 struct drm_mode_property_enum {
 	__u64 value;
Signature · 1 line
1.9.0
author
#21 lore raw

PATCH 6/17 drm: helpers to find mode objects

In reply to Rob Clark

Add a few more useful helpers to find mode objects.

---
 drivers/gpu/drm/drm_crtc.c | 97 ++++++++++++++--------------------------------
 include/drm/drm_crtc.h     | 33 ++++++++++++++++
 2 files changed, 63 insertions(+), 67 deletions(-)
drivers/gpu/drm/drm_crtc.c +30 -67
index fa86fba..bd12185 100644
@@ -1736,7 +1736,6 @@ int drm_mode_getcrtc(struct drm_device *dev,
 {
 	struct drm_mode_crtc *crtc_resp = data;
 	struct drm_crtc *crtc;
-	struct drm_mode_object *obj;
 	int ret = 0;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
@@ -1744,13 +1743,11 @@ int drm_mode_getcrtc(struct drm_device *dev,
 
 	drm_modeset_lock_all(dev);
 
-	obj = drm_mode_object_find(dev, crtc_resp->crtc_id,
-				   DRM_MODE_OBJECT_CRTC);
-	if (!obj) {
+	crtc = drm_crtc_find(dev, crtc_resp->crtc_id);
+	if (!crtc) {
 		ret = -ENOENT;
 		goto out;
 	}
-	crtc = obj_to_crtc(obj);
 
 	crtc_resp->x = crtc->x;
 	crtc_resp->y = crtc->y;
@@ -1804,7 +1801,6 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 			  struct drm_file *file_priv)
 {
 	struct drm_mode_get_connector *out_resp = data;
-	struct drm_mode_object *obj;
 	struct drm_connector *connector;
 	struct drm_display_mode *mode;
 	int mode_count = 0;
@@ -1828,13 +1824,11 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 
 	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 
-	obj = drm_mode_object_find(dev, out_resp->connector_id,
-				   DRM_MODE_OBJECT_CONNECTOR);
-	if (!obj) {
+	connector = drm_connector_find(dev, out_resp->connector_id);
+	if (!connector) {
 		ret = -ENOENT;
 		goto out;
 	}
-	connector = obj_to_connector(obj);
 
 	props_count = connector->properties.count;
 
@@ -1949,7 +1943,6 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
 			struct drm_file *file_priv)
 {
 	struct drm_mode_get_encoder *enc_resp = data;
-	struct drm_mode_object *obj;
 	struct drm_encoder *encoder;
 	int ret = 0;
 
@@ -1957,13 +1950,11 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
-	obj = drm_mode_object_find(dev, enc_resp->encoder_id,
-				   DRM_MODE_OBJECT_ENCODER);
-	if (!obj) {
+	encoder = drm_encoder_find(dev, enc_resp->encoder_id);
+	if (!encoder) {
 		ret = -ENOENT;
 		goto out;
 	}
-	encoder = obj_to_encoder(obj);
 
 	if (encoder->crtc)
 		enc_resp->crtc_id = encoder->crtc->base.id;
@@ -2061,7 +2052,6 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
 		      struct drm_file *file_priv)
 {
 	struct drm_mode_get_plane *plane_resp = data;
-	struct drm_mode_object *obj;
 	struct drm_plane *plane;
 	uint32_t __user *format_ptr;
 	int ret = 0;
@@ -2070,13 +2060,11 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
-	obj = drm_mode_object_find(dev, plane_resp->plane_id,
-				   DRM_MODE_OBJECT_PLANE);
-	if (!obj) {
+	plane = drm_plane_find(dev, plane_resp->plane_id);
+	if (!plane) {
 		ret = -ENOENT;
 		goto out;
 	}
-	plane = obj_to_plane(obj);
 
 	if (plane->crtc)
 		plane_resp->crtc_id = plane->crtc->base.id;
@@ -2129,7 +2117,6 @@ 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_object *obj;
 	struct drm_plane *plane;
 	struct drm_crtc *crtc;
 	struct drm_framebuffer *fb = NULL, *old_fb = NULL;
@@ -2144,14 +2131,12 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 	 * First, find the plane, crtc, and fb objects.  If not available,
 	 * we don't bother to call the driver.
 	 */
-	obj = drm_mode_object_find(dev, plane_req->plane_id,
-				   DRM_MODE_OBJECT_PLANE);
-	if (!obj) {
+	plane = drm_plane_find(dev, plane_req->plane_id);
+	if (!plane) {
 		DRM_DEBUG_KMS("Unknown plane ID %d\n",
 			      plane_req->plane_id);
 		return -ENOENT;
 	}
-	plane = obj_to_plane(obj);
 
 	/* No fb means shut it down */
 	if (!plane_req->fb_id) {
@@ -2168,15 +2153,13 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 		goto out;
 	}
 
-	obj = drm_mode_object_find(dev, plane_req->crtc_id,
-				   DRM_MODE_OBJECT_CRTC);
-	if (!obj) {
+	crtc = drm_crtc_find(dev, plane_req->crtc_id);
+	if (!crtc) {
 		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) {
@@ -2363,7 +2346,6 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 {
 	struct drm_mode_config *config = &dev->mode_config;
 	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;
@@ -2381,14 +2363,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 		return -ERANGE;
 
 	drm_modeset_lock_all(dev);
-	obj = drm_mode_object_find(dev, crtc_req->crtc_id,
-				   DRM_MODE_OBJECT_CRTC);
-	if (!obj) {
+	crtc = drm_crtc_find(dev, crtc_req->crtc_id);
+	if (!crtc) {
 		DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
 		ret = -ENOENT;
 		goto out;
 	}
-	crtc = obj_to_crtc(obj);
 	DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
 
 	if (crtc_req->mode_valid) {
@@ -2471,15 +2451,13 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 				goto out;
 			}
 
-			obj = drm_mode_object_find(dev, out_id,
-						   DRM_MODE_OBJECT_CONNECTOR);
-			if (!obj) {
+			connector = drm_connector_find(dev, out_id);
+			if (!connector) {
 				DRM_DEBUG_KMS("Connector id %d unknown\n",
 						out_id);
 				ret = -ENOENT;
 				goto out;
 			}
-			connector = obj_to_connector(obj);
 			DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
 					connector->base.id,
 					drm_get_connector_name(connector));
@@ -2511,7 +2489,6 @@ static int drm_mode_cursor_common(struct drm_device *dev,
 				  struct drm_mode_cursor2 *req,
 				  struct drm_file *file_priv)
 {
-	struct drm_mode_object *obj;
 	struct drm_crtc *crtc;
 	int ret = 0;
 
@@ -2521,12 +2498,11 @@ static int drm_mode_cursor_common(struct drm_device *dev,
 	if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
 		return -EINVAL;
 
-	obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC);
-	if (!obj) {
+	crtc = drm_crtc_find(dev, req->crtc_id);
+	if (!crtc) {
 		DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
 		return -ENOENT;
 	}
-	crtc = obj_to_crtc(obj);
 
 	drm_modeset_lock(&crtc->mutex, NULL);
 	if (req->flags & DRM_MODE_CURSOR_BO) {
@@ -3522,7 +3498,6 @@ EXPORT_SYMBOL(drm_object_property_get_value);
 int drm_mode_getproperty_ioctl(struct drm_device *dev,
 			       void *data, struct drm_file *file_priv)
 {
-	struct drm_mode_object *obj;
 	struct drm_mode_get_property *out_resp = data;
 	struct drm_property *property;
 	int enum_count = 0;
@@ -3541,12 +3516,11 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
-	obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
-	if (!obj) {
+	property = drm_property_find(dev, out_resp->prop_id);
+	if (!property) {
 		ret = -ENOENT;
 		goto done;
 	}
-	property = obj_to_property(obj);
 
 	if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
 			drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
@@ -3676,7 +3650,6 @@ static void drm_property_destroy_blob(struct drm_device *dev,
 int drm_mode_getblob_ioctl(struct drm_device *dev,
 			   void *data, struct drm_file *file_priv)
 {
-	struct drm_mode_object *obj;
 	struct drm_mode_get_blob *out_resp = data;
 	struct drm_property_blob *blob;
 	int ret = 0;
@@ -3686,12 +3659,11 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
-	obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB);
-	if (!obj) {
+	blob = drm_property_blob_find(dev, out_resp->blob_id);
+	if (!blob) {
 		ret = -ENOENT;
 		goto done;
 	}
-	blob = obj_to_blob(obj);
 
 	if (out_resp->length == blob->length) {
 		blob_ptr = (void __user *)(unsigned long)out_resp->data;
@@ -3898,7 +3870,6 @@ static int drm_mode_set_obj_prop_id(struct drm_device *dev,
 		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;
 
@@ -3915,11 +3886,9 @@ static int drm_mode_set_obj_prop_id(struct drm_device *dev,
 	if (i == arg_obj->properties->count)
 		return -EINVAL;
 
-	prop_obj = drm_mode_object_find(dev, prop_id,
-					DRM_MODE_OBJECT_PROPERTY);
-	if (!prop_obj)
+	property = drm_property_find(dev, prop_id);
+	if (!property)
 		return -ENOENT;
-	property = obj_to_property(prop_obj);
 
 	return drm_mode_set_obj_prop(arg_obj, state, property, 
 			value, blob_data);
@@ -4126,7 +4095,6 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
 			     void *data, struct drm_file *file_priv)
 {
 	struct drm_mode_crtc_lut *crtc_lut = data;
-	struct drm_mode_object *obj;
 	struct drm_crtc *crtc;
 	void *r_base, *g_base, *b_base;
 	int size;
@@ -4136,12 +4104,11 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
-	obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
-	if (!obj) {
+	crtc = drm_crtc_find(dev, crtc_lut->crtc_id);
+	if (!crtc) {
 		ret = -ENOENT;
 		goto out;
 	}
-	crtc = obj_to_crtc(obj);
 
 	if (crtc->funcs->gamma_set == NULL) {
 		ret = -ENOSYS;
@@ -4200,7 +4167,6 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev,
 			     void *data, struct drm_file *file_priv)
 {
 	struct drm_mode_crtc_lut *crtc_lut = data;
-	struct drm_mode_object *obj;
 	struct drm_crtc *crtc;
 	void *r_base, *g_base, *b_base;
 	int size;
@@ -4210,12 +4176,11 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev,
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
-	obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
-	if (!obj) {
+	crtc = drm_crtc_find(dev, crtc_lut->crtc_id);
+	if (!crtc) {
 		ret = -ENOENT;
 		goto out;
 	}
-	crtc = obj_to_crtc(obj);
 
 	/* memcpy into gamma store */
 	if (crtc_lut->gamma_size != crtc->gamma_size) {
@@ -4268,7 +4233,6 @@ 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_object *obj;
 	struct drm_crtc *crtc;
 	struct drm_framebuffer *fb = NULL, *old_fb = NULL;
 	struct drm_pending_vblank_event *e = NULL;
@@ -4282,10 +4246,9 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 	if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
 		return -EINVAL;
 
-	obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC);
-	if (!obj)
+	crtc = drm_crtc_find(dev, page_flip->crtc_id);
+	if (!crtc)
 		return -ENOENT;
-	crtc = obj_to_crtc(obj);
 
 	drm_modeset_lock(&crtc->mutex, NULL);
 	if (crtc->primary->fb == NULL) {
include/drm/drm_crtc.h +33 -0
index cd4a61a..b940a29 100644
@@ -1112,6 +1112,15 @@ extern int drm_format_vert_chroma_subsampling(uint32_t format);
 extern const char *drm_get_format_name(uint32_t format);
 
 /* Helpers */
+
+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)
 {
@@ -1128,6 +1137,30 @@ static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev,
 	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 *drm_property_find(struct drm_device *dev,
+		uint32_t id)
+{
+	struct drm_mode_object *mo;
+	mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PROPERTY);
+	return mo ? obj_to_property(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;
+}
+
 /* Plane list iterator for legacy (overlay only) planes. */
 #define drm_for_each_legacy_plane(plane, planelist) \
 	list_for_each_entry(plane, planelist, head) \
Signature · 1 line
1.9.0
#22 lore raw

Re: [PATCH 06/17] drm: helpers to find mode objects

Quoted 3 lines · Rob Clark

Add a few more useful helpers to find mode objects.

There's a pile more in drivers for these. I like this, but imo we should also convert drivers while at it. Also, docbook is missing. And since it's a cleanup I think it's better to do this first, directly on top of drm-next. The patch itself looks good.
-Daniel

Quoted 403 lines
---
 drivers/gpu/drm/drm_crtc.c | 97 ++++++++++++++--------------------------------
 include/drm/drm_crtc.h     | 33 ++++++++++++++++
 2 files changed, 63 insertions(+), 67 deletions(-)
drivers/gpu/drm/drm_crtc.c +30 -67
index fa86fba..bd12185 100644
@@ -1736,7 +1736,6 @@ int drm_mode_getcrtc(struct drm_device *dev,
 {
 	struct drm_mode_crtc *crtc_resp = data;
 	struct drm_crtc *crtc;
-	struct drm_mode_object *obj;
 	int ret = 0;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
@@ -1744,13 +1743,11 @@ int drm_mode_getcrtc(struct drm_device *dev,
 
 	drm_modeset_lock_all(dev);
 
-	obj = drm_mode_object_find(dev, crtc_resp->crtc_id,
-				   DRM_MODE_OBJECT_CRTC);
-	if (!obj) {
+	crtc = drm_crtc_find(dev, crtc_resp->crtc_id);
+	if (!crtc) {
 		ret = -ENOENT;
 		goto out;
 	}
-	crtc = obj_to_crtc(obj);
 
 	crtc_resp->x = crtc->x;
 	crtc_resp->y = crtc->y;
@@ -1804,7 +1801,6 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 			  struct drm_file *file_priv)
 {
 	struct drm_mode_get_connector *out_resp = data;
-	struct drm_mode_object *obj;
 	struct drm_connector *connector;
 	struct drm_display_mode *mode;
 	int mode_count = 0;
@@ -1828,13 +1824,11 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 
 	drm_modeset_lock(&dev->mode_config.mutex, NULL);
 
-	obj = drm_mode_object_find(dev, out_resp->connector_id,
-				   DRM_MODE_OBJECT_CONNECTOR);
-	if (!obj) {
+	connector = drm_connector_find(dev, out_resp->connector_id);
+	if (!connector) {
 		ret = -ENOENT;
 		goto out;
 	}
-	connector = obj_to_connector(obj);
 
 	props_count = connector->properties.count;
 
@@ -1949,7 +1943,6 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
 			struct drm_file *file_priv)
 {
 	struct drm_mode_get_encoder *enc_resp = data;
-	struct drm_mode_object *obj;
 	struct drm_encoder *encoder;
 	int ret = 0;
 
@@ -1957,13 +1950,11 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
-	obj = drm_mode_object_find(dev, enc_resp->encoder_id,
-				   DRM_MODE_OBJECT_ENCODER);
-	if (!obj) {
+	encoder = drm_encoder_find(dev, enc_resp->encoder_id);
+	if (!encoder) {
 		ret = -ENOENT;
 		goto out;
 	}
-	encoder = obj_to_encoder(obj);
 
 	if (encoder->crtc)
 		enc_resp->crtc_id = encoder->crtc->base.id;
@@ -2061,7 +2052,6 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
 		      struct drm_file *file_priv)
 {
 	struct drm_mode_get_plane *plane_resp = data;
-	struct drm_mode_object *obj;
 	struct drm_plane *plane;
 	uint32_t __user *format_ptr;
 	int ret = 0;
@@ -2070,13 +2060,11 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
-	obj = drm_mode_object_find(dev, plane_resp->plane_id,
-				   DRM_MODE_OBJECT_PLANE);
-	if (!obj) {
+	plane = drm_plane_find(dev, plane_resp->plane_id);
+	if (!plane) {
 		ret = -ENOENT;
 		goto out;
 	}
-	plane = obj_to_plane(obj);
 
 	if (plane->crtc)
 		plane_resp->crtc_id = plane->crtc->base.id;
@@ -2129,7 +2117,6 @@ 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_object *obj;
 	struct drm_plane *plane;
 	struct drm_crtc *crtc;
 	struct drm_framebuffer *fb = NULL, *old_fb = NULL;
@@ -2144,14 +2131,12 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 	 * First, find the plane, crtc, and fb objects.  If not available,
 	 * we don't bother to call the driver.
 	 */
-	obj = drm_mode_object_find(dev, plane_req->plane_id,
-				   DRM_MODE_OBJECT_PLANE);
-	if (!obj) {
+	plane = drm_plane_find(dev, plane_req->plane_id);
+	if (!plane) {
 		DRM_DEBUG_KMS("Unknown plane ID %d\n",
 			      plane_req->plane_id);
 		return -ENOENT;
 	}
-	plane = obj_to_plane(obj);
 
 	/* No fb means shut it down */
 	if (!plane_req->fb_id) {
@@ -2168,15 +2153,13 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 		goto out;
 	}
 
-	obj = drm_mode_object_find(dev, plane_req->crtc_id,
-				   DRM_MODE_OBJECT_CRTC);
-	if (!obj) {
+	crtc = drm_crtc_find(dev, plane_req->crtc_id);
+	if (!crtc) {
 		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) {
@@ -2363,7 +2346,6 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 {
 	struct drm_mode_config *config = &dev->mode_config;
 	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;
@@ -2381,14 +2363,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 		return -ERANGE;
 
 	drm_modeset_lock_all(dev);
-	obj = drm_mode_object_find(dev, crtc_req->crtc_id,
-				   DRM_MODE_OBJECT_CRTC);
-	if (!obj) {
+	crtc = drm_crtc_find(dev, crtc_req->crtc_id);
+	if (!crtc) {
 		DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
 		ret = -ENOENT;
 		goto out;
 	}
-	crtc = obj_to_crtc(obj);
 	DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
 
 	if (crtc_req->mode_valid) {
@@ -2471,15 +2451,13 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 				goto out;
 			}
 
-			obj = drm_mode_object_find(dev, out_id,
-						   DRM_MODE_OBJECT_CONNECTOR);
-			if (!obj) {
+			connector = drm_connector_find(dev, out_id);
+			if (!connector) {
 				DRM_DEBUG_KMS("Connector id %d unknown\n",
 						out_id);
 				ret = -ENOENT;
 				goto out;
 			}
-			connector = obj_to_connector(obj);
 			DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
 					connector->base.id,
 					drm_get_connector_name(connector));
@@ -2511,7 +2489,6 @@ static int drm_mode_cursor_common(struct drm_device *dev,
 				  struct drm_mode_cursor2 *req,
 				  struct drm_file *file_priv)
 {
-	struct drm_mode_object *obj;
 	struct drm_crtc *crtc;
 	int ret = 0;
 
@@ -2521,12 +2498,11 @@ static int drm_mode_cursor_common(struct drm_device *dev,
 	if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
 		return -EINVAL;
 
-	obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC);
-	if (!obj) {
+	crtc = drm_crtc_find(dev, req->crtc_id);
+	if (!crtc) {
 		DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
 		return -ENOENT;
 	}
-	crtc = obj_to_crtc(obj);
 
 	drm_modeset_lock(&crtc->mutex, NULL);
 	if (req->flags & DRM_MODE_CURSOR_BO) {
@@ -3522,7 +3498,6 @@ EXPORT_SYMBOL(drm_object_property_get_value);
 int drm_mode_getproperty_ioctl(struct drm_device *dev,
 			       void *data, struct drm_file *file_priv)
 {
-	struct drm_mode_object *obj;
 	struct drm_mode_get_property *out_resp = data;
 	struct drm_property *property;
 	int enum_count = 0;
@@ -3541,12 +3516,11 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
-	obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
-	if (!obj) {
+	property = drm_property_find(dev, out_resp->prop_id);
+	if (!property) {
 		ret = -ENOENT;
 		goto done;
 	}
-	property = obj_to_property(obj);
 
 	if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
 			drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
@@ -3676,7 +3650,6 @@ static void drm_property_destroy_blob(struct drm_device *dev,
 int drm_mode_getblob_ioctl(struct drm_device *dev,
 			   void *data, struct drm_file *file_priv)
 {
-	struct drm_mode_object *obj;
 	struct drm_mode_get_blob *out_resp = data;
 	struct drm_property_blob *blob;
 	int ret = 0;
@@ -3686,12 +3659,11 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
-	obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB);
-	if (!obj) {
+	blob = drm_property_blob_find(dev, out_resp->blob_id);
+	if (!blob) {
 		ret = -ENOENT;
 		goto done;
 	}
-	blob = obj_to_blob(obj);
 
 	if (out_resp->length == blob->length) {
 		blob_ptr = (void __user *)(unsigned long)out_resp->data;
@@ -3898,7 +3870,6 @@ static int drm_mode_set_obj_prop_id(struct drm_device *dev,
 		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;
 
@@ -3915,11 +3886,9 @@ static int drm_mode_set_obj_prop_id(struct drm_device *dev,
 	if (i == arg_obj->properties->count)
 		return -EINVAL;
 
-	prop_obj = drm_mode_object_find(dev, prop_id,
-					DRM_MODE_OBJECT_PROPERTY);
-	if (!prop_obj)
+	property = drm_property_find(dev, prop_id);
+	if (!property)
 		return -ENOENT;
-	property = obj_to_property(prop_obj);
 
 	return drm_mode_set_obj_prop(arg_obj, state, property, 
 			value, blob_data);
@@ -4126,7 +4095,6 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
 			     void *data, struct drm_file *file_priv)
 {
 	struct drm_mode_crtc_lut *crtc_lut = data;
-	struct drm_mode_object *obj;
 	struct drm_crtc *crtc;
 	void *r_base, *g_base, *b_base;
 	int size;
@@ -4136,12 +4104,11 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
-	obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
-	if (!obj) {
+	crtc = drm_crtc_find(dev, crtc_lut->crtc_id);
+	if (!crtc) {
 		ret = -ENOENT;
 		goto out;
 	}
-	crtc = obj_to_crtc(obj);
 
 	if (crtc->funcs->gamma_set == NULL) {
 		ret = -ENOSYS;
@@ -4200,7 +4167,6 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev,
 			     void *data, struct drm_file *file_priv)
 {
 	struct drm_mode_crtc_lut *crtc_lut = data;
-	struct drm_mode_object *obj;
 	struct drm_crtc *crtc;
 	void *r_base, *g_base, *b_base;
 	int size;
@@ -4210,12 +4176,11 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev,
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
-	obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
-	if (!obj) {
+	crtc = drm_crtc_find(dev, crtc_lut->crtc_id);
+	if (!crtc) {
 		ret = -ENOENT;
 		goto out;
 	}
-	crtc = obj_to_crtc(obj);
 
 	/* memcpy into gamma store */
 	if (crtc_lut->gamma_size != crtc->gamma_size) {
@@ -4268,7 +4233,6 @@ 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_object *obj;
 	struct drm_crtc *crtc;
 	struct drm_framebuffer *fb = NULL, *old_fb = NULL;
 	struct drm_pending_vblank_event *e = NULL;
@@ -4282,10 +4246,9 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 	if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
 		return -EINVAL;
 
-	obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC);
-	if (!obj)
+	crtc = drm_crtc_find(dev, page_flip->crtc_id);
+	if (!crtc)
 		return -ENOENT;
-	crtc = obj_to_crtc(obj);
 
 	drm_modeset_lock(&crtc->mutex, NULL);
 	if (crtc->primary->fb == NULL) {
include/drm/drm_crtc.h +33 -0
index cd4a61a..b940a29 100644
@@ -1112,6 +1112,15 @@ extern int drm_format_vert_chroma_subsampling(uint32_t format);
 extern const char *drm_get_format_name(uint32_t format);
 
 /* Helpers */
+
+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)
 {
@@ -1128,6 +1137,30 @@ static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev,
 	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 *drm_property_find(struct drm_device *dev,
+		uint32_t id)
+{
+	struct drm_mode_object *mo;
+	mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PROPERTY);
+	return mo ? obj_to_property(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;
+}
+
 /* Plane list iterator for legacy (overlay only) planes. */
 #define drm_for_each_legacy_plane(plane, planelist) \
 	list_for_each_entry(plane, planelist, head) \
Signature · 1 line
1.9.0
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#23 lore raw

Re: [PATCH 06/17] drm: helpers to find mode objects

Quoted 9 lines · Daniel Vetter
Quoted 3 lines · Rob Clark

Add a few more useful helpers to find mode objects.

There's a pile more in drivers for these. I like this, but imo we should also convert drivers while at it. Also, docbook is missing. And since it's a cleanup I think it's better to do this first, directly on top of drm-next. The patch itself looks good.

Aside: This is a pretty perfect case for coccinelle since it'll match object_find users no matter how crazily they're split up. And you can remove the unused local variable with it too (but that part is a bit more fuzz).
-Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
author
#24 lore raw

Re: [PATCH 06/17] drm: helpers to find mode objects

In reply to Daniel Vetter
Quoted 9 lines · Daniel Vetter
Quoted 3 lines · Rob Clark

Add a few more useful helpers to find mode objects.

There's a pile more in drivers for these. I like this, but imo we should also convert drivers while at it. Also, docbook is missing. And since it's a cleanup I think it's better to do this first, directly on top of drm-next. The patch itself looks good.

Yeah, the intent was to go back and add missing docbook as follow-up patches, to try to get this into a shape where it could be merged earlier.

I can have a go at coccinelle too for follow-up patches.

BR,
-R

Quoted 410 lines

-Daniel

Quoted 401 lines
---
 drivers/gpu/drm/drm_crtc.c | 97 ++++++++++++++--------------------------------
 include/drm/drm_crtc.h     | 33 ++++++++++++++++
 2 files changed, 63 insertions(+), 67 deletions(-)
drivers/gpu/drm/drm_crtc.c +30 -67
index fa86fba..bd12185 100644
@@ -1736,7 +1736,6 @@ int drm_mode_getcrtc(struct drm_device *dev,
 {
      struct drm_mode_crtc *crtc_resp = data;
      struct drm_crtc *crtc;
-     struct drm_mode_object *obj;
      int ret = 0;
 
      if (!drm_core_check_feature(dev, DRIVER_MODESET))
@@ -1744,13 +1743,11 @@ int drm_mode_getcrtc(struct drm_device *dev,
 
      drm_modeset_lock_all(dev);
 
-     obj = drm_mode_object_find(dev, crtc_resp->crtc_id,
-                                DRM_MODE_OBJECT_CRTC);
-     if (!obj) {
+     crtc = drm_crtc_find(dev, crtc_resp->crtc_id);
+     if (!crtc) {
              ret = -ENOENT;
              goto out;
      }
-     crtc = obj_to_crtc(obj);
 
      crtc_resp->x = crtc->x;
      crtc_resp->y = crtc->y;
@@ -1804,7 +1801,6 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
                        struct drm_file *file_priv)
 {
      struct drm_mode_get_connector *out_resp = data;
-     struct drm_mode_object *obj;
      struct drm_connector *connector;
      struct drm_display_mode *mode;
      int mode_count = 0;
@@ -1828,13 +1824,11 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 
      drm_modeset_lock(&dev->mode_config.mutex, NULL);
 
-     obj = drm_mode_object_find(dev, out_resp->connector_id,
-                                DRM_MODE_OBJECT_CONNECTOR);
-     if (!obj) {
+     connector = drm_connector_find(dev, out_resp->connector_id);
+     if (!connector) {
              ret = -ENOENT;
              goto out;
      }
-     connector = obj_to_connector(obj);
 
      props_count = connector->properties.count;
 
@@ -1949,7 +1943,6 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
                      struct drm_file *file_priv)
 {
      struct drm_mode_get_encoder *enc_resp = data;
-     struct drm_mode_object *obj;
      struct drm_encoder *encoder;
      int ret = 0;
 
@@ -1957,13 +1950,11 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
              return -EINVAL;
 
      drm_modeset_lock_all(dev);
-     obj = drm_mode_object_find(dev, enc_resp->encoder_id,
-                                DRM_MODE_OBJECT_ENCODER);
-     if (!obj) {
+     encoder = drm_encoder_find(dev, enc_resp->encoder_id);
+     if (!encoder) {
              ret = -ENOENT;
              goto out;
      }
-     encoder = obj_to_encoder(obj);
 
      if (encoder->crtc)
              enc_resp->crtc_id = encoder->crtc->base.id;
@@ -2061,7 +2052,6 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
                    struct drm_file *file_priv)
 {
      struct drm_mode_get_plane *plane_resp = data;
-     struct drm_mode_object *obj;
      struct drm_plane *plane;
      uint32_t __user *format_ptr;
      int ret = 0;
@@ -2070,13 +2060,11 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
              return -EINVAL;
 
      drm_modeset_lock_all(dev);
-     obj = drm_mode_object_find(dev, plane_resp->plane_id,
-                                DRM_MODE_OBJECT_PLANE);
-     if (!obj) {
+     plane = drm_plane_find(dev, plane_resp->plane_id);
+     if (!plane) {
              ret = -ENOENT;
              goto out;
      }
-     plane = obj_to_plane(obj);
 
      if (plane->crtc)
              plane_resp->crtc_id = plane->crtc->base.id;
@@ -2129,7 +2117,6 @@ 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_object *obj;
      struct drm_plane *plane;
      struct drm_crtc *crtc;
      struct drm_framebuffer *fb = NULL, *old_fb = NULL;
@@ -2144,14 +2131,12 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
       * First, find the plane, crtc, and fb objects.  If not available,
       * we don't bother to call the driver.
       */
-     obj = drm_mode_object_find(dev, plane_req->plane_id,
-                                DRM_MODE_OBJECT_PLANE);
-     if (!obj) {
+     plane = drm_plane_find(dev, plane_req->plane_id);
+     if (!plane) {
              DRM_DEBUG_KMS("Unknown plane ID %d\n",
                            plane_req->plane_id);
              return -ENOENT;
      }
-     plane = obj_to_plane(obj);
 
      /* No fb means shut it down */
      if (!plane_req->fb_id) {
@@ -2168,15 +2153,13 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
              goto out;
      }
 
-     obj = drm_mode_object_find(dev, plane_req->crtc_id,
-                                DRM_MODE_OBJECT_CRTC);
-     if (!obj) {
+     crtc = drm_crtc_find(dev, plane_req->crtc_id);
+     if (!crtc) {
              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) {
@@ -2363,7 +2346,6 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 {
      struct drm_mode_config *config = &dev->mode_config;
      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;
@@ -2381,14 +2363,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
              return -ERANGE;
 
      drm_modeset_lock_all(dev);
-     obj = drm_mode_object_find(dev, crtc_req->crtc_id,
-                                DRM_MODE_OBJECT_CRTC);
-     if (!obj) {
+     crtc = drm_crtc_find(dev, crtc_req->crtc_id);
+     if (!crtc) {
              DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
              ret = -ENOENT;
              goto out;
      }
-     crtc = obj_to_crtc(obj);
      DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
 
      if (crtc_req->mode_valid) {
@@ -2471,15 +2451,13 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
                              goto out;
                      }
 
-                     obj = drm_mode_object_find(dev, out_id,
-                                                DRM_MODE_OBJECT_CONNECTOR);
-                     if (!obj) {
+                     connector = drm_connector_find(dev, out_id);
+                     if (!connector) {
                              DRM_DEBUG_KMS("Connector id %d unknown\n",
                                              out_id);
                              ret = -ENOENT;
                              goto out;
                      }
-                     connector = obj_to_connector(obj);
                      DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
                                      connector->base.id,
                                      drm_get_connector_name(connector));
@@ -2511,7 +2489,6 @@ static int drm_mode_cursor_common(struct drm_device *dev,
                                struct drm_mode_cursor2 *req,
                                struct drm_file *file_priv)
 {
-     struct drm_mode_object *obj;
      struct drm_crtc *crtc;
      int ret = 0;
 
@@ -2521,12 +2498,11 @@ static int drm_mode_cursor_common(struct drm_device *dev,
      if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
              return -EINVAL;
 
-     obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC);
-     if (!obj) {
+     crtc = drm_crtc_find(dev, req->crtc_id);
+     if (!crtc) {
              DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
              return -ENOENT;
      }
-     crtc = obj_to_crtc(obj);
 
      drm_modeset_lock(&crtc->mutex, NULL);
      if (req->flags & DRM_MODE_CURSOR_BO) {
@@ -3522,7 +3498,6 @@ EXPORT_SYMBOL(drm_object_property_get_value);
 int drm_mode_getproperty_ioctl(struct drm_device *dev,
                             void *data, struct drm_file *file_priv)
 {
-     struct drm_mode_object *obj;
      struct drm_mode_get_property *out_resp = data;
      struct drm_property *property;
      int enum_count = 0;
@@ -3541,12 +3516,11 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
              return -EINVAL;
 
      drm_modeset_lock_all(dev);
-     obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
-     if (!obj) {
+     property = drm_property_find(dev, out_resp->prop_id);
+     if (!property) {
              ret = -ENOENT;
              goto done;
      }
-     property = obj_to_property(obj);
 
      if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
                      drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
@@ -3676,7 +3650,6 @@ static void drm_property_destroy_blob(struct drm_device *dev,
 int drm_mode_getblob_ioctl(struct drm_device *dev,
                         void *data, struct drm_file *file_priv)
 {
-     struct drm_mode_object *obj;
      struct drm_mode_get_blob *out_resp = data;
      struct drm_property_blob *blob;
      int ret = 0;
@@ -3686,12 +3659,11 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
              return -EINVAL;
 
      drm_modeset_lock_all(dev);
-     obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB);
-     if (!obj) {
+     blob = drm_property_blob_find(dev, out_resp->blob_id);
+     if (!blob) {
              ret = -ENOENT;
              goto done;
      }
-     blob = obj_to_blob(obj);
 
      if (out_resp->length == blob->length) {
              blob_ptr = (void __user *)(unsigned long)out_resp->data;
@@ -3898,7 +3870,6 @@ static int drm_mode_set_obj_prop_id(struct drm_device *dev,
              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;
 
@@ -3915,11 +3886,9 @@ static int drm_mode_set_obj_prop_id(struct drm_device *dev,
      if (i == arg_obj->properties->count)
              return -EINVAL;
 
-     prop_obj = drm_mode_object_find(dev, prop_id,
-                                     DRM_MODE_OBJECT_PROPERTY);
-     if (!prop_obj)
+     property = drm_property_find(dev, prop_id);
+     if (!property)
              return -ENOENT;
-     property = obj_to_property(prop_obj);
 
      return drm_mode_set_obj_prop(arg_obj, state, property,
                      value, blob_data);
@@ -4126,7 +4095,6 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
                           void *data, struct drm_file *file_priv)
 {
      struct drm_mode_crtc_lut *crtc_lut = data;
-     struct drm_mode_object *obj;
      struct drm_crtc *crtc;
      void *r_base, *g_base, *b_base;
      int size;
@@ -4136,12 +4104,11 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
              return -EINVAL;
 
      drm_modeset_lock_all(dev);
-     obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
-     if (!obj) {
+     crtc = drm_crtc_find(dev, crtc_lut->crtc_id);
+     if (!crtc) {
              ret = -ENOENT;
              goto out;
      }
-     crtc = obj_to_crtc(obj);
 
      if (crtc->funcs->gamma_set == NULL) {
              ret = -ENOSYS;
@@ -4200,7 +4167,6 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev,
                           void *data, struct drm_file *file_priv)
 {
      struct drm_mode_crtc_lut *crtc_lut = data;
-     struct drm_mode_object *obj;
      struct drm_crtc *crtc;
      void *r_base, *g_base, *b_base;
      int size;
@@ -4210,12 +4176,11 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev,
              return -EINVAL;
 
      drm_modeset_lock_all(dev);
-     obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
-     if (!obj) {
+     crtc = drm_crtc_find(dev, crtc_lut->crtc_id);
+     if (!crtc) {
              ret = -ENOENT;
              goto out;
      }
-     crtc = obj_to_crtc(obj);
 
      /* memcpy into gamma store */
      if (crtc_lut->gamma_size != crtc->gamma_size) {
@@ -4268,7 +4233,6 @@ 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_object *obj;
      struct drm_crtc *crtc;
      struct drm_framebuffer *fb = NULL, *old_fb = NULL;
      struct drm_pending_vblank_event *e = NULL;
@@ -4282,10 +4246,9 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
      if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
              return -EINVAL;
 
-     obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC);
-     if (!obj)
+     crtc = drm_crtc_find(dev, page_flip->crtc_id);
+     if (!crtc)
              return -ENOENT;
-     crtc = obj_to_crtc(obj);
 
      drm_modeset_lock(&crtc->mutex, NULL);
      if (crtc->primary->fb == NULL) {
include/drm/drm_crtc.h +33 -1
index cd4a61a..b940a29 100644
@@ -1112,6 +1112,15 @@ extern int drm_format_vert_chroma_subsampling(uint32_t format);
 extern const char *drm_get_format_name(uint32_t format);
 
 /* Helpers */
+
+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)
 {
@@ -1128,6 +1137,30 @@ static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev,
      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 *drm_property_find(struct drm_device *dev,
+             uint32_t id)
+{
+     struct drm_mode_object *mo;
+     mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PROPERTY);
+     return mo ? obj_to_property(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;
+}
+
 /* Plane list iterator for legacy (overlay only) planes. */
 #define drm_for_each_legacy_plane(plane, planelist) \
      list_for_each_entry(plane, planelist, head) \
--
Quoted 2 lines

1.9.0

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

author
#25 lore raw

PATCH 7/17 drm: split propvals out and blob property support

In reply to Rob Clark

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(-)
drivers/gpu/drm/drm_crtc.c +58 -21
index bd12185..e01c286 100644
@@ -123,6 +123,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,
+		struct drm_atomic_state *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)				\
@@ -755,6 +763,7 @@ int drm_crtc_init_with_planes(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++;
@@ -859,6 +868,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;
@@ -1077,6 +1087,7 @@ int drm_universal_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,
@@ -1894,7 +1905,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;
@@ -3418,7 +3429,7 @@ 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);
@@ -3437,13 +3448,27 @@ EXPORT_SYMBOL(drm_object_attach_property);
  * Zero on success, error code on failure.
  */
 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;
 		}
 	}
@@ -3473,7 +3498,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;
 		}
 	}
@@ -3694,27 +3719,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;
 }
@@ -3806,7 +3839,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;
 }
 
@@ -3820,7 +3855,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;
 }
@@ -3835,7 +3871,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;
 }
@@ -3951,7 +3988,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;
drivers/gpu/drm/drm_fb_helper.c +2 -1
index 142f6bd..97b0d84 100644
@@ -451,7 +451,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);
drivers/gpu/drm/gma500/cdv_intel_dp.c +2 -1
index 31d872d..69160d9 100644
@@ -1655,7 +1655,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;
 
drivers/gpu/drm/gma500/cdv_intel_hdmi.c +2 -1
index f0e4d78..f71e513 100644
@@ -184,7 +184,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) ||
drivers/gpu/drm/gma500/cdv_intel_lvds.c +4 -2
index f9ee300..76f7508 100644
@@ -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);
drivers/gpu/drm/gma500/mdfld_dsi_output.c +5 -3
index 2318a46..17f2c19 100644
@@ -276,7 +276,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) ||
@@ -300,8 +301,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, blob_data))
 			goto set_prop_error;
 		else
 			gma_backlight_set(encoder->dev, value);
drivers/gpu/drm/gma500/psb_intel_lvds.c +4 -2
index 3442e44..d1a3a0c 100644
@@ -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);
drivers/gpu/drm/gma500/psb_intel_sdvo.c +14 -5
index 724b525..8191309 100644
@@ -1717,7 +1717,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;
 
@@ -1773,7 +1774,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;
 
@@ -1785,7 +1788,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;
 
@@ -1797,7 +1802,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;
 
@@ -1809,7 +1816,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;
 
drivers/gpu/drm/i2c/ch7006_drv.c +2 -2
index 51fa323..a89c205 100644
@@ -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;
drivers/gpu/drm/i915/intel_display.c +2 -1
index 562e575..e9f6eb7 100644
@@ -9494,8 +9494,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;
drivers/gpu/drm/i915/intel_dp.c +2 -1
index e4c0b10..50f2260 100644
@@ -3281,7 +3281,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;
 
drivers/gpu/drm/i915/intel_hdmi.c +2 -1
index 8e160b0..8c8b7d3 100644
@@ -1055,7 +1055,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;
 
drivers/gpu/drm/i915/intel_sdvo.c +14 -5
index 4e36ee99..83bec46 100644
@@ -2064,7 +2064,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;
 
@@ -2141,7 +2142,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;
 
@@ -2153,7 +2156,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;
 
@@ -2165,7 +2170,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;
 
@@ -2177,7 +2184,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;
 
drivers/gpu/drm/i915/intel_tv.c +4 -2
index 05ee0d5..f7a7bf4 100644
@@ -1297,7 +1297,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);
 }
 
 /**
@@ -1455,7 +1456,8 @@ intel_tv_set_property(struct drm_connector *connector,
 	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;
 
drivers/gpu/drm/nouveau/dispnv04/tvnv17.c +2 -1
index acef48f..64c60fcb 100644
@@ -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;
drivers/gpu/drm/nouveau/nouveau_connector.c +3 -1
index 3351e72..8948c66 100644
@@ -227,10 +227,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);
 	}
 }
 
drivers/gpu/drm/omapdrm/omap_drv.c +4 -2
index d3c9161..3dca538 100644
@@ -579,12 +579,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);
 		}
 	}
 
drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c +2 -1
index 289048d..503bac9 100644
@@ -111,7 +111,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)
drivers/gpu/drm/rcar-du/rcar_du_vgacon.c +2 -1
index ccfe64c..c2d0054 100644
@@ -76,7 +76,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)
drivers/gpu/drm/shmobile/shmob_drm_crtc.c +2 -2
index faf176b..90e023a 100644
@@ -741,8 +741,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;
 
include/drm/drm_crtc.h +10 -1
index b940a29..9caf434 100644
@@ -41,6 +41,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
@@ -56,12 +57,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];
 };
 
@@ -361,6 +366,7 @@ struct drm_crtc {
 	void *helper_private;
 
 	struct drm_object_properties properties;
+	struct drm_object_property_values propvals;
 };
 
 
@@ -520,6 +526,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_* */
 
@@ -603,6 +610,7 @@ struct drm_plane {
 	const struct drm_plane_funcs *funcs;
 
 	struct drm_object_properties properties;
+	struct drm_object_property_values propvals;
 
 	enum drm_plane_type type;
 };
@@ -969,8 +977,9 @@ static inline bool drm_property_type_valid(struct drm_property *property)
 }
 
 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);
Signature · 1 line
1.9.0
author
#26 lore raw

PATCH 8/17 drm: Allow drm_mode_object_find() to look up an object of any type

In reply to Rob Clark

From: Ville Syrjälä <[email protected]>

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.

---
 drivers/gpu/drm/drm_crtc.c | 3 ++-
 include/drm/drm_crtc.h     | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/drm_crtc.c +2 -1
index e01c286..511d33e 100644
@@ -463,7 +463,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);
 
include/drm/drm_crtc.h +1 -0
index 9caf434..31ed7c6 100644
@@ -52,6 +52,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;
Signature · 6 lines
1.9.0

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
author
#27 lore raw

PATCH 9/17 drm: Refactor object property check code

In reply to Rob Clark

From: Ville Syrjälä <[email protected]>

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

v1: original
v2: rebase on atomic -- Rob Clark
v3: EINVAL->ENOENT

---
 drivers/gpu/drm/drm_crtc.c | 25 ++++++++++++++-----------
 1 file changed, 14 insertions(+), 11 deletions(-)
drivers/gpu/drm/drm_crtc.c +14 -11
index 511d33e..9b95601 100644
@@ -3901,6 +3901,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,
 		struct drm_atomic_state *state,
@@ -3909,20 +3922,10 @@ static int drm_mode_set_obj_prop_id(struct drm_device *dev,
 {
 	struct drm_mode_object *arg_obj;
 	struct drm_property *property;
-	int i;
 
 	arg_obj = drm_mode_object_find(dev, obj_id, obj_type);
-	if (!arg_obj)
+	if (!(arg_obj && object_has_prop(arg_obj, prop_id)))
 		return -ENOENT;
-	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;
 
 	property = drm_property_find(dev, prop_id);
 	if (!property)
Signature · 6 lines
1.9.0

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
author
#28 lore raw

PATCH 10/17 drm: allow FB's in drm_mode_object_find

In reply to Rob Clark

We do actually want to permit FB's in atomic case, since FB will be looked up like any other object property value in a few code paths (like property value validation).

So split out into an internal function without the WARN_ON() which we can use in those special cases.

---
 drivers/gpu/drm/drm_crtc.c | 33 ++++++++++++++++++++++-----------
 include/drm/drm_crtc.h     |  6 ------
 2 files changed, 22 insertions(+), 17 deletions(-)
drivers/gpu/drm/drm_crtc.c +22 -11
index 9b95601..48555724 100644
@@ -443,6 +443,21 @@ void drm_mode_object_put(struct drm_device *dev,
 	mutex_unlock(&dev->mode_config.idr_mutex);
 }
 
+static struct drm_mode_object *_object_find(struct drm_device *dev,
+		uint32_t id, uint32_t type)
+{
+	struct drm_mode_object *obj = NULL;
+
+	mutex_lock(&dev->mode_config.idr_mutex);
+	obj = idr_find(&dev->mode_config.crtc_idr, id);
+	if (!obj || (type != DRM_MODE_OBJECT_ANY && obj->type != type) ||
+	    (obj->id != id))
+		obj = NULL;
+	mutex_unlock(&dev->mode_config.idr_mutex);
+
+	return obj;
+}
+
 /**
  * drm_mode_object_find - look up a drm object with static lifetime
  * @dev: drm device
@@ -455,23 +470,19 @@ void drm_mode_object_put(struct drm_device *dev,
 struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
 		uint32_t id, uint32_t type)
 {
-	struct drm_mode_object *obj = NULL;
-
 	/* Framebuffers are reference counted and need their own lookup
 	 * function.*/
 	WARN_ON(type == DRM_MODE_OBJECT_FB);
-
-	mutex_lock(&dev->mode_config.idr_mutex);
-	obj = idr_find(&dev->mode_config.crtc_idr, id);
-	if (!obj || (type != DRM_MODE_OBJECT_ANY && obj->type != type) ||
-	    (obj->id != id))
-		obj = NULL;
-	mutex_unlock(&dev->mode_config.idr_mutex);
-
-	return obj;
+	return _object_find(dev, id, type);
 }
 EXPORT_SYMBOL(drm_mode_object_find);
 
+static struct drm_mode_object *
+drm_property_get_obj(struct drm_property *property, uint64_t value)
+{
+	return _object_find(property->dev, value, property->values[0]);
+}
+
 /**
  * drm_framebuffer_init - initialize a framebuffer
  * @dev: DRM device
include/drm/drm_crtc.h +0 -6
index 31ed7c6..547b75a 100644
@@ -1033,12 +1033,6 @@ extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
 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);
Signature · 1 line
1.9.0
#29 lore raw

Re: [PATCH 10/17] drm: allow FB's in drm_mode_object_find

Quoted 8 lines · Rob Clark

We do actually want to permit FB's in atomic case, since FB will be looked up like any other object property value in a few code paths (like property value validation).

So split out into an internal function without the WARN_ON() which we can use in those special cases.

See my other mail, but Nack. Imo you want a drm_mode_object_exists instead, which just returns a bool. Gives you want you want and is safe. -Daniel

Quoted 82 lines
---
 drivers/gpu/drm/drm_crtc.c | 33 ++++++++++++++++++++++-----------
 include/drm/drm_crtc.h     |  6 ------
 2 files changed, 22 insertions(+), 17 deletions(-)
drivers/gpu/drm/drm_crtc.c +22 -11
index 9b95601..48555724 100644
@@ -443,6 +443,21 @@ void drm_mode_object_put(struct drm_device *dev,
 	mutex_unlock(&dev->mode_config.idr_mutex);
 }
 
+static struct drm_mode_object *_object_find(struct drm_device *dev,
+		uint32_t id, uint32_t type)
+{
+	struct drm_mode_object *obj = NULL;
+
+	mutex_lock(&dev->mode_config.idr_mutex);
+	obj = idr_find(&dev->mode_config.crtc_idr, id);
+	if (!obj || (type != DRM_MODE_OBJECT_ANY && obj->type != type) ||
+	    (obj->id != id))
+		obj = NULL;
+	mutex_unlock(&dev->mode_config.idr_mutex);
+
+	return obj;
+}
+
 /**
  * drm_mode_object_find - look up a drm object with static lifetime
  * @dev: drm device
@@ -455,23 +470,19 @@ void drm_mode_object_put(struct drm_device *dev,
 struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
 		uint32_t id, uint32_t type)
 {
-	struct drm_mode_object *obj = NULL;
-
 	/* Framebuffers are reference counted and need their own lookup
 	 * function.*/
 	WARN_ON(type == DRM_MODE_OBJECT_FB);
-
-	mutex_lock(&dev->mode_config.idr_mutex);
-	obj = idr_find(&dev->mode_config.crtc_idr, id);
-	if (!obj || (type != DRM_MODE_OBJECT_ANY && obj->type != type) ||
-	    (obj->id != id))
-		obj = NULL;
-	mutex_unlock(&dev->mode_config.idr_mutex);
-
-	return obj;
+	return _object_find(dev, id, type);
 }
 EXPORT_SYMBOL(drm_mode_object_find);
 
+static struct drm_mode_object *
+drm_property_get_obj(struct drm_property *property, uint64_t value)
+{
+	return _object_find(property->dev, value, property->values[0]);
+}
+
 /**
  * drm_framebuffer_init - initialize a framebuffer
  * @dev: DRM device
include/drm/drm_crtc.h +0 -6
index 31ed7c6..547b75a 100644
@@ -1033,12 +1033,6 @@ extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
 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);
Signature · 1 line
1.9.0
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
author
#30 lore raw

PATCH 11/17 drm: convert plane to properties/state

In reply to Rob Clark

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/armada/armada_overlay.c    |  11 +-
 drivers/gpu/drm/drm_atomic.c               | 225 ++++++++++++++-
 drivers/gpu/drm/drm_crtc.c                 | 433 ++++++++++++++++++++---------
 drivers/gpu/drm/drm_fb_helper.c            |  17 +-
 drivers/gpu/drm/drm_plane_helper.c         |   2 +
 drivers/gpu/drm/exynos/exynos_drm_plane.c  |   7 +-
 drivers/gpu/drm/i915/intel_sprite.c        |   1 +
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c  |   6 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c  |   6 +-
 drivers/gpu/drm/nouveau/dispnv04/overlay.c |   8 +-
 drivers/gpu/drm/omapdrm/omap_drv.c         |   2 +-
 drivers/gpu/drm/omapdrm/omap_plane.c       |   7 +
 drivers/gpu/drm/rcar-du/rcar_du_plane.c    |   8 +-
 drivers/gpu/drm/shmobile/shmob_drm_plane.c |   2 +
 include/drm/drm_atomic.h                   |  29 +-
 include/drm/drm_crtc.h                     | 114 +++++++-
 16 files changed, 725 insertions(+), 153 deletions(-)
drivers/gpu/drm/armada/armada_overlay.c +10 -1
index 601ba9a..041ea89 100644
@@ -7,6 +7,7 @@
  * published by the Free Software Foundation.
  */
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include "armada_crtc.h"
 #include "armada_drm.h"
 #include "armada_fb.h"
@@ -288,7 +289,12 @@ static int armada_plane_set_property(struct drm_plane *plane,
 {
 	struct armada_private *priv = plane->dev->dev_private;
 	struct armada_plane *dplane = drm_to_armada_plane(plane);
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
 	bool update_attr = false;
+	int ret = 0;
+
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
 
 	if (property == priv->colorkey_prop) {
 #define CCC(v) ((v) << 24 | (v) << 16 | (v) << 8)
@@ -342,13 +348,16 @@ static int armada_plane_set_property(struct drm_plane *plane,
 	} else if (property == priv->saturation_prop) {
 		dplane->prop.saturation = val;
 		update_attr = true;
+	} else {
+		ret = drm_plane_set_property(plane, pstate, property,
+				val, blob_data);
 	}
 
 	if (update_attr && dplane->base.crtc)
 		armada_ovl_update_attr(&dplane->prop,
 				       drm_to_armada_crtc(dplane->base.crtc));
 
-	return 0;
+	return ret;
 }
 
 static const struct drm_plane_funcs armada_plane_funcs = {
drivers/gpu/drm/drm_atomic.c +223 -2

273 lines not on this page · raw message

drivers/gpu/drm/drm_crtc.c +297 -136

556 lines not on this page · raw message

drivers/gpu/drm/drm_fb_helper.c +16 -1
index 97b0d84..b73d3b0 100644
@@ -286,13 +286,28 @@ 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)
 		if (plane->type != DRM_PLANE_TYPE_PRIMARY)
-			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;
drivers/gpu/drm/drm_plane_helper.c +2 -0
index d966afa..7a32383 100644
@@ -26,6 +26,7 @@
 #include <linux/list.h>
 #include <drm/drmP.h>
 #include <drm/drm_rect.h>
+#include <drm/drm_atomic.h>
 
 #define SUBPIXEL_MASK 0xffff
 
@@ -234,6 +235,7 @@ EXPORT_SYMBOL(drm_primary_helper_destroy);
 const struct drm_plane_funcs drm_primary_helper_funcs = {
 	.update_plane = drm_primary_helper_update,
 	.disable_plane = drm_primary_helper_disable,
+	.set_property = drm_atomic_plane_set_property,
 	.destroy = drm_primary_helper_destroy,
 };
 EXPORT_SYMBOL(drm_primary_helper_funcs);
drivers/gpu/drm/exynos/exynos_drm_plane.c +6 -1
index 9da0935..8cf7442 100644
@@ -10,6 +10,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 
 #include <drm/exynos_drm.h>
 #include "exynos_drm_drv.h"
@@ -220,13 +221,17 @@ static int exynos_plane_set_property(struct drm_plane *plane,
 	struct drm_device *dev = plane->dev;
 	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
 	struct exynos_drm_private *dev_priv = dev->dev_private;
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
 
 	if (property == dev_priv->plane_zpos_property) {
 		exynos_plane->overlay.zpos = val;
 		return 0;
 	}
 
-	return -EINVAL;
+	return drm_plane_set_property(plane, pstate, property, val, blob_data);
 }
 
 static struct drm_plane_funcs exynos_plane_funcs = {
drivers/gpu/drm/i915/intel_sprite.c +1 -0
index c235546..3f742f5 100644
@@ -1190,6 +1190,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_plane_set_property,
 };
 
 static uint32_t ilk_plane_formats[] = {
drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c +4 -2
index 8c064dc..4c92985 100644
@@ -88,8 +88,10 @@ int mdp4_plane_set_property(struct drm_plane *plane,
 		struct drm_atomic_state *state, struct drm_property *property,
 		uint64_t val, void *blob_data)
 {
-	// XXX
-	return -EINVAL;
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
+	return drm_plane_set_property(plane, pstate, property, val, blob_data);
 }
 
 static const struct drm_plane_funcs mdp4_plane_funcs = {
drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +4 -2
index 5cbf226..53cc8c6 100644
@@ -103,8 +103,10 @@ int mdp5_plane_set_property(struct drm_plane *plane,
 		struct drm_atomic_state *state, struct drm_property *property,
 		uint64_t val, void *blob_data)
 {
-	// XXX
-	return -EINVAL;
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
+	return drm_plane_set_property(plane, pstate, property, val, blob_data);
 }
 
 static const struct drm_plane_funcs mdp5_plane_funcs = {
drivers/gpu/drm/nouveau/dispnv04/overlay.c +7 -1
index 577e6aa..97b48b5 100644
@@ -24,6 +24,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_fourcc.h>
 
@@ -226,6 +227,10 @@ nv_set_property(struct drm_plane *plane,
 		  uint64_t value, void *blob_data)
 {
 	struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
 
 	if (property == nv_plane->props.colorkey)
 		nv_plane->colorkey = value;
@@ -240,7 +245,8 @@ nv_set_property(struct drm_plane *plane,
 	else if (property == nv_plane->props.iturbt_709)
 		nv_plane->iturbt_709 = value;
 	else
-		return -EINVAL;
+		return drm_plane_set_property(plane, pstate,
+				property, value, blob_data);
 
 	if (nv_plane->set_params)
 		nv_plane->set_params(nv_plane);
drivers/gpu/drm/omapdrm/omap_drv.c +1 -1
index 3dca538..da80bdc 100644
@@ -585,7 +585,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);
 		}
 	}
drivers/gpu/drm/omapdrm/omap_plane.c +7 -0
index 2d3c975..a9acc58 100644
@@ -341,8 +341,12 @@ int omap_plane_set_property(struct drm_plane *plane,
 {
 	struct omap_plane *omap_plane = to_omap_plane(plane);
 	struct omap_drm_private *priv = plane->dev->dev_private;
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
 	int ret = -EINVAL;
 
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
+
 	if (property == priv->rotation_prop) {
 		DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val);
 		omap_plane->win.rotation = val;
@@ -351,6 +355,9 @@ int omap_plane_set_property(struct drm_plane *plane,
 		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, pstate, property,
+				val, blob_data);
 	}
 
 	return ret;
drivers/gpu/drm/rcar-du/rcar_du_plane.c +7 -1
index 3a5d843..015c76a 100644
@@ -14,6 +14,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -404,6 +405,10 @@ static int rcar_du_plane_set_property(struct drm_plane *plane,
 {
 	struct rcar_du_plane *rplane = to_rcar_plane(plane);
 	struct rcar_du_group *rgrp = rplane->group;
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
 
 	if (property == rgrp->planes.alpha)
 		rcar_du_plane_set_alpha(rplane, value);
@@ -412,7 +417,8 @@ 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, pstate,
+				property, value, blob_data);
 
 	return 0;
 }
drivers/gpu/drm/shmobile/shmob_drm_plane.c +2 -0
index 060ae03..ccf03ea 100644
@@ -14,6 +14,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -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_plane_set_property,
 	.destroy = shmob_drm_plane_destroy,
 };
 
include/drm/drm_atomic.h +28 -1
index ff72b81..78e93ec 100644
@@ -68,7 +68,8 @@
  * struct drm_atomic_funcs - helper funcs used by the atomic helpers
  */
 struct drm_atomic_funcs {
-	int dummy; /* for now */
+	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_funcs drm_atomic_funcs;
@@ -84,6 +85,30 @@ int drm_atomic_commit_unlocked(struct drm_device *dev,
 		struct drm_atomic_state *state);
 void drm_atomic_end(struct drm_device *dev, struct drm_atomic_state *state);
 
+int drm_atomic_plane_set_property(struct drm_plane *plane,
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t val, void *blob_data);
+struct drm_plane_state *drm_atomic_get_plane_state(struct drm_plane *plane,
+		struct drm_atomic_state *state);
+
+static inline int
+drm_atomic_check_plane_state(struct drm_plane *plane,
+		struct drm_plane_state *pstate)
+{
+	const struct drm_atomic_funcs *funcs =
+			plane->dev->driver->atomic_funcs;
+	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_funcs *funcs =
+			plane->dev->driver->atomic_funcs;
+	return funcs->commit_plane_state(plane, pstate);
+}
+
 /**
  * struct drm_atomic_state - the state object used by atomic helpers
  */
@@ -91,6 +116,8 @@ struct drm_atomic_state {
 	struct kref refcount;
 	struct drm_device *dev;
 	uint32_t flags;
+	struct drm_plane **planes;
+	struct drm_plane_state **pstates;
 
 	bool committed;
 	bool checked;       /* just for debugging */
include/drm/drm_crtc.h +110 -4

170 lines not on this page · raw message

Signature · 1 line
1.9.0
#31 lore raw

Re: [PATCH 11/17] drm: convert plane to properties/state

Quoted 9 lines · Rob Clark

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.

Quoted 4 lines

The same should be done for CRTC, encoder, and connector, but this patch only includes the first part (plane).

Imo s/plane->id/plane->index/ since plane_id can be too easily confused with the mode object id used for the idr lookup. We already have drm_crtc_index, so this is established convention already.

A few comments below.

Quoted 190 lines
---
 drivers/gpu/drm/armada/armada_overlay.c    |  11 +-
 drivers/gpu/drm/drm_atomic.c               | 225 ++++++++++++++-
 drivers/gpu/drm/drm_crtc.c                 | 433 ++++++++++++++++++++---------
 drivers/gpu/drm/drm_fb_helper.c            |  17 +-
 drivers/gpu/drm/drm_plane_helper.c         |   2 +
 drivers/gpu/drm/exynos/exynos_drm_plane.c  |   7 +-
 drivers/gpu/drm/i915/intel_sprite.c        |   1 +
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c  |   6 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c  |   6 +-
 drivers/gpu/drm/nouveau/dispnv04/overlay.c |   8 +-
 drivers/gpu/drm/omapdrm/omap_drv.c         |   2 +-
 drivers/gpu/drm/omapdrm/omap_plane.c       |   7 +
 drivers/gpu/drm/rcar-du/rcar_du_plane.c    |   8 +-
 drivers/gpu/drm/shmobile/shmob_drm_plane.c |   2 +
 include/drm/drm_atomic.h                   |  29 +-
 include/drm/drm_crtc.h                     | 114 +++++++-
 16 files changed, 725 insertions(+), 153 deletions(-)
drivers/gpu/drm/armada/armada_overlay.c +10 -1
index 601ba9a..041ea89 100644
@@ -7,6 +7,7 @@
  * published by the Free Software Foundation.
  */
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include "armada_crtc.h"
 #include "armada_drm.h"
 #include "armada_fb.h"
@@ -288,7 +289,12 @@ static int armada_plane_set_property(struct drm_plane *plane,
 {
 	struct armada_private *priv = plane->dev->dev_private;
 	struct armada_plane *dplane = drm_to_armada_plane(plane);
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
 	bool update_attr = false;
+	int ret = 0;
+
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
 
 	if (property == priv->colorkey_prop) {
 #define CCC(v) ((v) << 24 | (v) << 16 | (v) << 8)
@@ -342,13 +348,16 @@ static int armada_plane_set_property(struct drm_plane *plane,
 	} else if (property == priv->saturation_prop) {
 		dplane->prop.saturation = val;
 		update_attr = true;
+	} else {
+		ret = drm_plane_set_property(plane, pstate, property,
+				val, blob_data);
 	}
 
 	if (update_attr && dplane->base.crtc)
 		armada_ovl_update_attr(&dplane->prop,
 				       drm_to_armada_crtc(dplane->base.crtc));
 
-	return 0;
+	return ret;
 }
 
 static const struct drm_plane_funcs armada_plane_funcs = {
drivers/gpu/drm/drm_atomic.c +71 -2
index 45df5e5..403ffc5 100644
@@ -24,6 +24,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
+#include <drm/drm_plane_helper.h>
 
 /**
  * drm_atomic_begin - start a sequence of atomic updates
@@ -46,10 +47,12 @@ struct drm_atomic_state *drm_atomic_begin(struct drm_device *dev,
 		uint32_t flags)
 {
 	struct drm_atomic_state *state;
+	int nplanes = dev->mode_config.num_total_plane;
 	int sz;
 	void *ptr;
 
 	sz = sizeof(*state);
+	sz += (sizeof(state->planes) + sizeof(state->pstates)) * nplanes;
 
 	ptr = kzalloc(sz, GFP_KERNEL);
 
@@ -65,6 +68,12 @@ struct drm_atomic_state *drm_atomic_begin(struct drm_device *dev,
 	state->dev = dev;
 	state->flags = flags;
 
+	state->planes = ptr;
+	ptr = &state->planes[nplanes];
+
+	state->pstates = ptr;
+	ptr = &state->pstates[nplanes];
+
 	return state;
 }
 EXPORT_SYMBOL(drm_atomic_begin);
@@ -101,8 +110,20 @@ EXPORT_SYMBOL(drm_atomic_set_event);
 int drm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
 {
 	struct drm_atomic_state *a = state;
+	int nplanes = dev->mode_config.num_total_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;
+		}
+	}
+
 	a->acquire_ctx.frozen = true;
-	return 0;  /* for now */
+
+	return ret;
 }
 EXPORT_SYMBOL(drm_atomic_check);
 
@@ -180,6 +201,18 @@ fail:
 static void commit_locks(struct drm_atomic_state *a,
 		struct ww_acquire_ctx *ww_ctx)
 {
+	struct drm_device *dev = a->dev;
+	int nplanes = dev->mode_config.num_total_plane;
+	int i;
+
+	for (i = 0; i < nplanes; i++) {
+		struct drm_plane *plane = a->planes[i];
+		if (plane) {
+			plane->state->state = NULL;
+			drm_plane_destroy_state(plane, a->pstates[i]);
+		}
+	}
+
 	/* and properly release them (clear in_atomic, remove from list): */
 	drm_modeset_drop_locks(&a->acquire_ctx);
 	ww_acquire_fini(ww_ctx);
@@ -189,7 +222,17 @@ static void commit_locks(struct drm_atomic_state *a,
 static int atomic_commit(struct drm_atomic_state *a,
 		struct ww_acquire_ctx *ww_ctx)
 {
-	int ret = 0;
+	int nplanes = a->dev->mode_config.num_total_plane;
+	int i, ret = 0;
+
+	for (i = 0; i < nplanes; i++) {
+		struct drm_plane *plane = a->planes[i];
+		if (plane) {
+			ret = drm_atomic_commit_plane_state(plane, a->pstates[i]);
+			if (ret)
+				break;
+		}
+	}
 
 	commit_locks(a, ww_ctx);
 
@@ -264,7 +307,185 @@ void _drm_atomic_state_free(struct kref *kref)
 }
 EXPORT_SYMBOL(_drm_atomic_state_free);
 
+int drm_atomic_plane_set_property(struct drm_plane *plane,
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t val, void *blob_data)
+{
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
+	return drm_plane_set_property(plane, pstate, property, val, blob_data);
+}
+EXPORT_SYMBOL(drm_atomic_plane_set_property);
+
+static void init_plane_state(struct drm_plane *plane,
+		struct drm_plane_state *pstate, struct drm_atomic_state *state)
+{
+	/* snapshot current state: */
+	*pstate = *plane->state;
+	pstate->state = state;
+	if (pstate->fb)
+		drm_framebuffer_reference(pstate->fb);
+}
+
+struct drm_plane_state *
+drm_atomic_get_plane_state(struct drm_plane *plane,
+		struct drm_atomic_state *state)
+{
+	struct drm_atomic_state *a = state;

drivers/gpu/drm/drm_atomic.c void _drm_atomic_state_free(struct kref *kref) · line 345

Quoted 10 lines
drivers/gpu/drm/drm_atomic.c +10 -0
+	struct drm_plane_state *pstate;
+	int ret;
+
+	pstate = a->pstates[plane->id];
+
+	if (!pstate) {
+		struct drm_modeset_acquire_ctx *ctx = &a->acquire_ctx;
+
+		/* grab lock of current crtc.. if crtc is NULL then grab all: */
+		if (plane->state->crtc)

Looking here looks fishy - who's preventing someone else from touching plane->state while we don't yet hold any locks? Or do I miss something big here?

Quoted 65 lines
drivers/gpu/drm/drm_atomic.c +65 -0
+			ret = drm_modeset_lock(&plane->state->crtc->mutex, ctx);
+		else
+			ret = drm_modeset_lock_all_crtcs(plane->dev, ctx);
+		if (ret)
+			return ERR_PTR(ret);
+
+		pstate = drm_plane_create_state(plane);
+		if (!pstate)
+			return ERR_PTR(-ENOMEM);
+		init_plane_state(plane, pstate, state);
+		a->planes[plane->id] = plane;
+		a->pstates[plane->id] = pstate;
+	}
+
+	return pstate;
+}
+EXPORT_SYMBOL(drm_atomic_get_plane_state);
+
+static void
+swap_plane_state(struct drm_plane *plane, struct drm_atomic_state *a)
+{
+	struct drm_plane_state *pstate = a->pstates[plane->id];
+
+	/* clear transient state (only valid during atomic update): */
+	pstate->update_plane = false;
+	pstate->new_fb = false;
+
+	swap(plane->state, a->pstates[plane->id]);
+	plane->base.propvals = &plane->state->propvals;
+}
+
+/* For primary plane, if the driver implements ->page_flip(), then
+ * we can use that.  But drivers can now choose not to bother with
+ * implementing page_flip().
+ */
+static bool can_flip(struct drm_plane *plane, struct drm_plane_state *pstate)
+{
+	struct drm_crtc *crtc = pstate->crtc;
+	return (plane == crtc->primary) && crtc->funcs->page_flip &&
+			!pstate->update_plane;
+}
+
+/* clear crtc/fb, ie. after disable_plane().  But takes care to keep
+ * the property state in sync.  Once we get rid of plane->crtc/fb ptrs
+ * and just use state, we can get rid of this fxn:
+ */
+static void
+reset_plane(struct drm_plane *plane, struct drm_plane_state *pstate)
+{
+	struct drm_mode_config *config = &plane->dev->mode_config;
+	drm_plane_set_property(plane, pstate, config->prop_fb_id, 0, NULL);
+	drm_plane_set_property(plane, pstate, config->prop_crtc_id, 0, NULL);
+	plane->crtc = NULL;
+	plane->fb = NULL;
+}
+
+static int
+commit_plane_state(struct drm_plane *plane, struct drm_plane_state *pstate)
+{
+	struct drm_atomic_state *a = pstate->state;
+	struct drm_framebuffer *old_fb = plane->fb;
+	struct drm_framebuffer *fb = pstate->fb;
+	bool enabled = pstate->crtc && fb;
+	int ret = 0;
+

drivers/gpu/drm/drm_atomic.c void _drm_atomic_state_free(struct kref *kref) · line 420

Quoted 10 lines
drivers/gpu/drm/drm_atomic.c +10 -0
+	if (fb)
+		drm_framebuffer_reference(fb);
+
+	if (!enabled) {
+		if ((plane->type == DRM_PLANE_TYPE_PRIMARY) &&
+				(plane->funcs == &drm_primary_helper_funcs)) {
+			/* primary plane helpers don't like ->disable_plane()..
+			 * so this hack for now until someone comes up with
+			 * something better:
+			 */

Imo that's something we could check for in ->check and reject early.

Quoted 9 lines
drivers/gpu/drm/drm_atomic.c +9 -0
+			ret = 0;
+		} else {
+			ret = plane->funcs->disable_plane(plane);
+			reset_plane(plane, pstate);
+		}
+	} else {
+		struct drm_crtc *crtc = pstate->crtc;
+		if (pstate->update_plane ||
+				(pstate->new_fb && !can_flip(plane, pstate))) {

drivers/gpu/drm/drm_atomic.c void _drm_atomic_state_free(struct kref *kref) · line 439

Quoted 10 lines
drivers/gpu/drm/drm_atomic.c +10 -0
+			ret = plane->funcs->update_plane(plane, 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 == 0) {
+				/*
+				 * For page_flip(), the driver does this, but for
+				 * update_plane() it doesn't.. hurray \o/
+				 */

Imo a patch to unify this first wouldn't hurt ...

Quoted 12 lines
drivers/gpu/drm/drm_atomic.c +12 -0
+				plane->crtc = crtc;
+				plane->fb = fb;
+				fb = NULL;  /* don't unref */
+			}
+
+		} else if (pstate->new_fb) {
+			ret = crtc->funcs->page_flip(crtc, fb, NULL, a->flags);
+			if (ret == 0) {
+				/*
+				 * Warn if the driver hasn't properly updated the plane->fb
+				 * field to reflect that the new framebuffer is now used.
+				 * Failing to do so will screw with the reference counting

drivers/gpu/drm/drm_atomic.c void _drm_atomic_state_free(struct kref *kref) · line 461

Quoted 10 lines
drivers/gpu/drm/drm_atomic.c +10 -0
+				 * on framebuffers.
+				 */
+				WARN_ON(plane->fb != fb);
+				fb = NULL;  /* don't unref */
+			}
+		} else {
+			old_fb = NULL;
+			ret = 0;
+		}
+	}

This entire logic here kinda raises the question about transitioning drivers to the atomic interfaces. For modeset operations it might work fairly well since everything but i915 uses the crtc helpers and so can be converted fairly easily.

But doing nuclear pageflips, even more so if we want completion events is an entire new deal. No idea how that should work really.

Quoted 675 lines
drivers/gpu/drm/drm_atomic.c +26 -0
+
+	if (ret) {
+		/* Keep the old fb, don't unref it. */
+		old_fb = NULL;
+	} else {
+		/* 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.
+		 */
+		swap_plane_state(plane, pstate->state);
+	}
+
+
+	if (fb)
+		drm_framebuffer_unreference(fb);
+	if (old_fb)
+		drm_framebuffer_unreference(old_fb);
+
+	return ret;
+}
 
 const struct drm_atomic_funcs drm_atomic_funcs = {
+		.check_plane_state  = drm_plane_check_state,
+		.commit_plane_state = commit_plane_state,
 };
 EXPORT_SYMBOL(drm_atomic_funcs);
drivers/gpu/drm/drm_crtc.c +297 -136
index 48555724..b556a31 100644
@@ -712,6 +712,18 @@ 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_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) {
@@ -728,8 +740,17 @@ 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);
+				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);
 	}
 
@@ -1090,18 +1111,23 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
 			     const uint32_t *formats, uint32_t format_count,
 			     enum drm_plane_type type)
 {
+	struct drm_mode_config *config = &dev->mode_config;
 	int ret;
 
+	/* this is now required: */
+	WARN_ON(!funcs->set_property);
+
 	drm_modeset_lock_all(dev);
 
 	ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
 	if (ret)
 		goto out;
 
+	plane->funcs = funcs;
+	plane->state = drm_plane_create_state(plane);
 	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,
 				      GFP_KERNEL);
 	if (!plane->format_types) {
@@ -1116,15 +1142,27 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
 	plane->possible_crtcs = possible_crtcs;
 	plane->type = type;
 
-	list_add_tail(&plane->head, &dev->mode_config.plane_list);
-	dev->mode_config.num_total_plane++;
+	list_add_tail(&plane->head, &config->plane_list);
+	plane->id = config->num_total_plane;
+	config->num_total_plane++;
 	if (plane->type == DRM_PLANE_TYPE_OVERLAY)
-		dev->mode_config.num_overlay_plane++;
+		config->num_overlay_plane++;
 
 	drm_object_attach_property(&plane->base,
-				   dev->mode_config.plane_type_property,
+				   config->plane_type_property,
 				   plane->type);
 
+	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);
 
@@ -1185,10 +1223,151 @@ void drm_plane_cleanup(struct drm_plane *plane)
 	dev->mode_config.num_total_plane--;
 	if (plane->type == DRM_PLANE_TYPE_OVERLAY)
 		dev->mode_config.num_overlay_plane--;
+	drm_plane_destroy_state(plane, plane->state);
 	drm_modeset_unlock_all(dev);
 }
 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_framebuffer *old_fb = state->fb;
+		/*
+		 * NOTE: the ref to the fb could have been lost between
+		 * drm_property_change_is_valid() and now.  The upshot
+		 * is that drm_framebuffer_lookup() could return NULL
+		 * and we'd disable the plane.
+		 *
+		 * We *could* return an error in that case.  But if (for
+		 * example) _setcrtc() raced with _rmfb() and _rmfb()
+		 * came after, it would disable what was enabled in the
+		 * _setcrtc().  Which is the same end result that we get
+		 * here, just skipping briefly setting the mode.
+		 */
+		state->fb = drm_framebuffer_lookup(dev, value);
+		if (old_fb)
+			drm_framebuffer_unreference(old_fb);
+		state->new_fb = true;
+	} else if (property == config->prop_crtc_id) {
+		struct drm_mode_object *obj = drm_property_get_obj(property, value);
+		struct drm_crtc *crtc = obj ? obj_to_crtc(obj) : NULL;
+		/* take the lock of the incoming crtc as well, moving
+		 * plane between crtcs is synchronized on both incoming
+		 * and outgoing crtc.
+		 */
+		if (crtc) {
+			struct drm_atomic_state *a = state->state;
+			int ret = drm_modeset_lock(&crtc->mutex, &a->acquire_ctx);
+			if (ret)
+				return ret;
+		}
+		state->crtc = crtc;
+		state->update_plane = true;
+	} else if (property == config->prop_crtc_x) {
+		state->crtc_x = U642I64(value);
+		state->update_plane = true;
+	} else if (property == config->prop_crtc_y) {
+		state->crtc_y = U642I64(value);
+		state->update_plane = true;
+	} else if (property == config->prop_crtc_w) {
+		state->crtc_w = value;
+		state->update_plane = true;
+	} else if (property == config->prop_crtc_h) {
+		state->crtc_h = value;
+		state->update_plane = true;
+	} else if (property == config->prop_src_x) {
+		state->src_x = value;
+		state->update_plane = true;
+	} else if (property == config->prop_src_y) {
+		state->src_y = value;
+		state->update_plane = true;
+	} else if (property == config->prop_src_w) {
+		state->src_w = value;
+		state->update_plane = true;
+	} else if (property == config->prop_src_h) {
+		state->src_h = value;
+		state->update_plane = true;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_plane_set_property);
+
 /**
  * drm_plane_force_disable - Forcibly disable a plane
  * @plane: plane to disable
@@ -1198,43 +1377,93 @@ 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,
+		struct drm_atomic_state *state)
 {
-	struct drm_framebuffer *old_fb = plane->fb;
-	int ret;
+	struct drm_mode_config *config = &plane->dev->mode_config;
 
-	if (!old_fb)
-		return;
-
-	ret = plane->funcs->disable_plane(plane);
-	if (ret) {
-		DRM_ERROR("failed to disable plane with busy fb\n");
-		return;
-	}
-	/* disconnect the plane from the fb and crtc: */
-	__drm_framebuffer_unreference(old_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);
 
 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;
+
+
+	prop = drm_property_create_range(dev, 0, "SRC_X", 0, UINT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_src_x = prop;
+
+	prop = drm_property_create_range(dev, 0, "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_signed_range(dev, 0, "CRTC_X",
+			INT_MIN, INT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_x = prop;
+
+	prop = drm_property_create_signed_range(dev, 0, "CRTC_Y",
+			INT_MIN, 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, 0, "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;
 }
@@ -2140,20 +2369,19 @@ 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_plane *plane;
-	struct drm_crtc *crtc;
-	struct drm_framebuffer *fb = NULL, *old_fb = NULL;
+	struct drm_atomic_state *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.
-	 */
+retry:
+	state = dev->driver->atomic_begin(dev, 0);
+	if (IS_ERR(state))
+		return PTR_ERR(state);
+
 	plane = drm_plane_find(dev, plane_req->plane_id);
 	if (!plane) {
 		DRM_DEBUG_KMS("Unknown plane ID %d\n",
@@ -2161,104 +2389,37 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 		return -ENOENT;
 	}
 
-	/* No fb means shut it down */
-	if (!plane_req->fb_id) {
-		drm_modeset_lock_all(dev);
-		old_fb = plane->fb;
-		ret = plane->funcs->disable_plane(plane);
-		if (!ret) {
-			plane->crtc = NULL;
-			plane->fb = NULL;
-		} else {
-			old_fb = NULL;
-		}
-		drm_modeset_unlock_all(dev);
-		goto out;
-	}
-
-	crtc = drm_crtc_find(dev, plane_req->crtc_id);
-	if (!crtc) {
-		DRM_DEBUG_KMS("Unknown crtc ID %d\n",
-			      plane_req->crtc_id);
-		ret = -ENOENT;
-		goto out;
-	}
-
-	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;
-	}
-
-	/* 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_plane_set_obj_prop(plane, state,
+			config->prop_crtc_id, plane_req->crtc_id, NULL) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+			config->prop_fb_id, plane_req->fb_id, NULL) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+			config->prop_crtc_x, I642U64(plane_req->crtc_x), NULL) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+			config->prop_crtc_y, I642U64(plane_req->crtc_y), NULL) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+			config->prop_crtc_w, plane_req->crtc_w, NULL) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+			config->prop_crtc_h, plane_req->crtc_h, NULL) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+			config->prop_src_w, plane_req->src_w, NULL) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+			config->prop_src_h, plane_req->src_h, NULL) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+			config->prop_src_x, plane_req->src_x, NULL) ||
+		drm_mode_plane_set_obj_prop(plane, 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);
-	old_fb = plane->fb;
-	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) {
-		plane->crtc = crtc;
-		plane->fb = fb;
-		fb = NULL;
-	} else {
-		old_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);
+	if (ret == -EDEADLK)
+		goto retry;
 	return ret;
 }
 
@@ -3833,7 +3994,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,
 					   struct drm_atomic_state *state, struct drm_property *property,
 					   uint64_t value, void *blob_data)
 {
@@ -3856,8 +4017,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,
 				      struct drm_atomic_state *state, struct drm_property *property,
 				      uint64_t value, void *blob_data)
 {
@@ -3872,8 +4034,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,
 				      struct drm_atomic_state *state, struct drm_property *property,
 				      uint64_t value, void *blob_data)
 {
@@ -3882,12 +4045,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,
 		struct drm_atomic_state *state, struct drm_property *property,
drivers/gpu/drm/drm_fb_helper.c +16 -1
index 97b0d84..b73d3b0 100644
@@ -286,13 +286,28 @@ 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)
 		if (plane->type != DRM_PLANE_TYPE_PRIMARY)
-			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;
drivers/gpu/drm/drm_plane_helper.c +2 -0
index d966afa..7a32383 100644
@@ -26,6 +26,7 @@
 #include <linux/list.h>
 #include <drm/drmP.h>
 #include <drm/drm_rect.h>
+#include <drm/drm_atomic.h>
 
 #define SUBPIXEL_MASK 0xffff
 
@@ -234,6 +235,7 @@ EXPORT_SYMBOL(drm_primary_helper_destroy);
 const struct drm_plane_funcs drm_primary_helper_funcs = {
 	.update_plane = drm_primary_helper_update,
 	.disable_plane = drm_primary_helper_disable,
+	.set_property = drm_atomic_plane_set_property,
 	.destroy = drm_primary_helper_destroy,
 };
 EXPORT_SYMBOL(drm_primary_helper_funcs);
drivers/gpu/drm/exynos/exynos_drm_plane.c +4 -0
index 9da0935..8cf7442 100644
@@ -10,6 +10,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 
 #include <drm/exynos_drm.h>
 #include "exynos_drm_drv.h"
@@ -220,13 +221,17 @@ static int exynos_plane_set_property(struct drm_plane *plane,
 	struct drm_device *dev = plane->dev;
 	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
 	struct exynos_drm_private *dev_priv = dev->dev_private;
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+
+	if (IS_ERR(pstate))

drivers/gpu/drm/exynos/exynos_drm_plane.c static int exynos_plane_set_property(struct drm_plane *plane, · line 235

Quoted 10 lines
drivers/gpu/drm/exynos/exynos_drm_plane.c +2 -1
+		return PTR_ERR(pstate);
 
 	if (property == dev_priv->plane_zpos_property) {
 		exynos_plane->overlay.zpos = val;
 		return 0;
 	}
 
-	return -EINVAL;
+	return drm_plane_set_property(plane, pstate, property, val, blob_data);
 }

Imo the interfaces here are a bit wonky - most drivers have the exact same structure of allocating a plane state object if it's not there and setting the property. Imo we should push this down a bit and have type-specific set_prop interfaces which take the state-specific state object. Core properties would be fully handled in the core. Which means that driver don't need to implement set_prop callbacks if they don't have any special properties on top of the core stuff. Much less boilerplate that way.

This would also give us a strong incentive to have common properties for e.g. blending since we could simply pimp the core with them, and leave drivers to just register the properties if they support them. If they have additional restrictions they only need to implement the ->check hook, which has the awesome advantage that they can deal with a real structure instead of abstract prop arrays.

E.g. we could add a plane->supports_blending bool which would enabled/disable the default blending/Z-order properties for updating.

Quoted 413 lines
drivers/gpu/drm/exynos/exynos_drm_plane.c +0 -0
 static struct drm_plane_funcs exynos_plane_funcs = {
drivers/gpu/drm/i915/intel_sprite.c +1 -0
index c235546..3f742f5 100644
@@ -1190,6 +1190,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_plane_set_property,
 };
 
 static uint32_t ilk_plane_formats[] = {
drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c +4 -2
index 8c064dc..4c92985 100644
@@ -88,8 +88,10 @@ int mdp4_plane_set_property(struct drm_plane *plane,
 		struct drm_atomic_state *state, struct drm_property *property,
 		uint64_t val, void *blob_data)
 {
-	// XXX
-	return -EINVAL;
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
+	return drm_plane_set_property(plane, pstate, property, val, blob_data);
 }
 
 static const struct drm_plane_funcs mdp4_plane_funcs = {
drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +4 -2
index 5cbf226..53cc8c6 100644
@@ -103,8 +103,10 @@ int mdp5_plane_set_property(struct drm_plane *plane,
 		struct drm_atomic_state *state, struct drm_property *property,
 		uint64_t val, void *blob_data)
 {
-	// XXX
-	return -EINVAL;
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
+	return drm_plane_set_property(plane, pstate, property, val, blob_data);
 }
 
 static const struct drm_plane_funcs mdp5_plane_funcs = {
drivers/gpu/drm/nouveau/dispnv04/overlay.c +7 -1
index 577e6aa..97b48b5 100644
@@ -24,6 +24,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_fourcc.h>
 
@@ -226,6 +227,10 @@ nv_set_property(struct drm_plane *plane,
 		  uint64_t value, void *blob_data)
 {
 	struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
 
 	if (property == nv_plane->props.colorkey)
 		nv_plane->colorkey = value;
@@ -240,7 +245,8 @@ nv_set_property(struct drm_plane *plane,
 	else if (property == nv_plane->props.iturbt_709)
 		nv_plane->iturbt_709 = value;
 	else
-		return -EINVAL;
+		return drm_plane_set_property(plane, pstate,
+				property, value, blob_data);
 
 	if (nv_plane->set_params)
 		nv_plane->set_params(nv_plane);
drivers/gpu/drm/omapdrm/omap_drv.c +1 -1
index 3dca538..da80bdc 100644
@@ -585,7 +585,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);
 		}
 	}
drivers/gpu/drm/omapdrm/omap_plane.c +7 -0
index 2d3c975..a9acc58 100644
@@ -341,8 +341,12 @@ int omap_plane_set_property(struct drm_plane *plane,
 {
 	struct omap_plane *omap_plane = to_omap_plane(plane);
 	struct omap_drm_private *priv = plane->dev->dev_private;
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
 	int ret = -EINVAL;
 
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
+
 	if (property == priv->rotation_prop) {
 		DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val);
 		omap_plane->win.rotation = val;
@@ -351,6 +355,9 @@ int omap_plane_set_property(struct drm_plane *plane,
 		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, pstate, property,
+				val, blob_data);
 	}
 
 	return ret;
drivers/gpu/drm/rcar-du/rcar_du_plane.c +7 -1
index 3a5d843..015c76a 100644
@@ -14,6 +14,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -404,6 +405,10 @@ static int rcar_du_plane_set_property(struct drm_plane *plane,
 {
 	struct rcar_du_plane *rplane = to_rcar_plane(plane);
 	struct rcar_du_group *rgrp = rplane->group;
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
 
 	if (property == rgrp->planes.alpha)
 		rcar_du_plane_set_alpha(rplane, value);
@@ -412,7 +417,8 @@ 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, pstate,
+				property, value, blob_data);
 
 	return 0;
 }
drivers/gpu/drm/shmobile/shmob_drm_plane.c +2 -0
index 060ae03..ccf03ea 100644
@@ -14,6 +14,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -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_plane_set_property,
 	.destroy = shmob_drm_plane_destroy,
 };
 
include/drm/drm_atomic.h +28 -1
index ff72b81..78e93ec 100644
@@ -68,7 +68,8 @@
  * struct drm_atomic_funcs - helper funcs used by the atomic helpers
  */
 struct drm_atomic_funcs {
-	int dummy; /* for now */
+	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_funcs drm_atomic_funcs;
@@ -84,6 +85,30 @@ int drm_atomic_commit_unlocked(struct drm_device *dev,
 		struct drm_atomic_state *state);
 void drm_atomic_end(struct drm_device *dev, struct drm_atomic_state *state);
 
+int drm_atomic_plane_set_property(struct drm_plane *plane,
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t val, void *blob_data);
+struct drm_plane_state *drm_atomic_get_plane_state(struct drm_plane *plane,
+		struct drm_atomic_state *state);
+
+static inline int
+drm_atomic_check_plane_state(struct drm_plane *plane,
+		struct drm_plane_state *pstate)
+{
+	const struct drm_atomic_funcs *funcs =
+			plane->dev->driver->atomic_funcs;
+	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_funcs *funcs =
+			plane->dev->driver->atomic_funcs;
+	return funcs->commit_plane_state(plane, pstate);
+}
+
 /**
  * struct drm_atomic_state - the state object used by atomic helpers
  */
@@ -91,6 +116,8 @@ struct drm_atomic_state {
 	struct kref refcount;
 	struct drm_device *dev;
 	uint32_t flags;
+	struct drm_plane **planes;
+	struct drm_plane_state **pstates;
 
 	bool committed;
 	bool checked;       /* just for debugging */
include/drm/drm_crtc.h +110 -4
index 547b75a..58309cc 100644
@@ -569,7 +569,10 @@ 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_plane_state *(*create_state)(struct drm_plane *plane);
+	void (*destroy_state)(struct drm_plane *plane,
+			    struct drm_plane_state *pstate);
+	int (*set_property)(struct drm_plane *plane, 
 			    struct drm_atomic_state *state,
 			    struct drm_property *property, uint64_t val,
 			    void *blob_data);
@@ -582,6 +585,48 @@ enum drm_plane_type {
 };
 
 /**
+ * drm_plane_state - mutable plane state
+ * @update_plane: if full update_plane() is needed (vs pageflip)
+ * @new_fb: has the fb been changed
+ * @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 {
+	bool update_plane      : 1;
+	bool new_fb            : 1;
+
+	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;
+
+	struct drm_atomic_state *state;
+};
+
+/**
  * drm_plane - central DRM plane control structure
  * @dev: DRM device this plane belongs to
  * @head: for list management
@@ -591,6 +636,8 @@ enum drm_plane_type {
  * @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
  * @type: type of plane (overlay, primary, cursor)
@@ -608,10 +655,17 @@ struct drm_plane {
 	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;
 
 	enum drm_plane_type type;
 };
@@ -807,8 +861,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;
 	struct drm_property *plane_type_property;
@@ -930,11 +996,20 @@ extern int drm_plane_init(struct drm_device *dev,
 			  const uint32_t *formats, uint32_t format_count,
 			  bool is_primary);
 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,
+		struct drm_atomic_state *state);
 extern int drm_crtc_check_viewport(const struct drm_crtc *crtc,
 				   int x, int y,
 				   const struct drm_display_mode *mode,
 				   const struct drm_framebuffer *fb);
+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);
 
@@ -984,6 +1059,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,
+					   struct drm_atomic_state *state, struct drm_property *property,
+					   uint64_t value, void *blob_data);
+int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
+				      struct drm_atomic_state *state, struct drm_property *property,
+				      uint64_t value, void *blob_data);
+int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+				      struct drm_atomic_state *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);
@@ -1165,6 +1251,26 @@ drm_property_blob_find(struct drm_device *dev, uint32_t id)
 	return mo ? obj_to_blob(mo) : NULL;
 }
 
+static inline struct drm_plane_state *
+drm_plane_create_state(struct drm_plane *plane)
+{
+	if (plane->funcs->create_state)
+		return plane->funcs->create_state(plane);
+	return kzalloc(sizeof(struct drm_plane_state), GFP_KERNEL);
+}
+
+static inline void
+drm_plane_destroy_state(struct drm_plane *plane,
+		struct drm_plane_state *pstate)
+{
+	if (pstate->fb)
+		drm_framebuffer_unreference(pstate->fb);
+	if (plane->funcs->destroy_state)
+		plane->funcs->destroy_state(plane, pstate);
+	else
+		kfree(pstate);
+}
+
 /* Plane list iterator for legacy (overlay only) planes. */
 #define drm_for_each_legacy_plane(plane, planelist) \
 	list_for_each_entry(plane, planelist, head) \
Signature · 1 line
1.9.0
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
author
#32 lore raw

Re: [PATCH 11/17] drm: convert plane to properties/state

Quoted 10 lines · Daniel Vetter
Quoted 9 lines · Rob Clark

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.

Quoted 8 lines
Quoted 4 lines

The same should be done for CRTC, encoder, and connector, but this patch only includes the first part (plane).

Imo s/plane->id/plane->index/ since plane_id can be too easily confused with the mode object id used for the idr lookup. We already have drm_crtc_index, so this is established convention already.

fair enough.. I suppose I could do the same in crtc.

Quoted 198 lines

A few comments below.

Quoted 196 lines
---
 drivers/gpu/drm/armada/armada_overlay.c    |  11 +-
 drivers/gpu/drm/drm_atomic.c               | 225 ++++++++++++++-
 drivers/gpu/drm/drm_crtc.c                 | 433 ++++++++++++++++++++---------
 drivers/gpu/drm/drm_fb_helper.c            |  17 +-
 drivers/gpu/drm/drm_plane_helper.c         |   2 +
 drivers/gpu/drm/exynos/exynos_drm_plane.c  |   7 +-
 drivers/gpu/drm/i915/intel_sprite.c        |   1 +
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c  |   6 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c  |   6 +-
 drivers/gpu/drm/nouveau/dispnv04/overlay.c |   8 +-
 drivers/gpu/drm/omapdrm/omap_drv.c         |   2 +-
 drivers/gpu/drm/omapdrm/omap_plane.c       |   7 +
 drivers/gpu/drm/rcar-du/rcar_du_plane.c    |   8 +-
 drivers/gpu/drm/shmobile/shmob_drm_plane.c |   2 +
 include/drm/drm_atomic.h                   |  29 +-
 include/drm/drm_crtc.h                     | 114 +++++++-
 16 files changed, 725 insertions(+), 153 deletions(-)
drivers/gpu/drm/armada/armada_overlay.c +10 -1
index 601ba9a..041ea89 100644
@@ -7,6 +7,7 @@
  * published by the Free Software Foundation.
  */
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include "armada_crtc.h"
 #include "armada_drm.h"
 #include "armada_fb.h"
@@ -288,7 +289,12 @@ static int armada_plane_set_property(struct drm_plane *plane,
 {
      struct armada_private *priv = plane->dev->dev_private;
      struct armada_plane *dplane = drm_to_armada_plane(plane);
+     struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
      bool update_attr = false;
+     int ret = 0;
+
+     if (IS_ERR(pstate))
+             return PTR_ERR(pstate);
 
      if (property == priv->colorkey_prop) {
 #define CCC(v) ((v) << 24 | (v) << 16 | (v) << 8)
@@ -342,13 +348,16 @@ static int armada_plane_set_property(struct drm_plane *plane,
      } else if (property == priv->saturation_prop) {
              dplane->prop.saturation = val;
              update_attr = true;
+     } else {
+             ret = drm_plane_set_property(plane, pstate, property,
+                             val, blob_data);
      }
 
      if (update_attr && dplane->base.crtc)
              armada_ovl_update_attr(&dplane->prop,
                                     drm_to_armada_crtc(dplane->base.crtc));
 
-     return 0;
+     return ret;
 }
 
 static const struct drm_plane_funcs armada_plane_funcs = {
drivers/gpu/drm/drm_atomic.c +77 -2
index 45df5e5..403ffc5 100644
@@ -24,6 +24,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
+#include <drm/drm_plane_helper.h>
 
 /**
  * drm_atomic_begin - start a sequence of atomic updates
@@ -46,10 +47,12 @@ struct drm_atomic_state *drm_atomic_begin(struct drm_device *dev,
              uint32_t flags)
 {
      struct drm_atomic_state *state;
+     int nplanes = dev->mode_config.num_total_plane;
      int sz;
      void *ptr;
 
      sz = sizeof(*state);
+     sz += (sizeof(state->planes) + sizeof(state->pstates)) * nplanes;
 
      ptr = kzalloc(sz, GFP_KERNEL);
 
@@ -65,6 +68,12 @@ struct drm_atomic_state *drm_atomic_begin(struct drm_device *dev,
      state->dev = dev;
      state->flags = flags;
 
+     state->planes = ptr;
+     ptr = &state->planes[nplanes];
+
+     state->pstates = ptr;
+     ptr = &state->pstates[nplanes];
+
      return state;
 }
 EXPORT_SYMBOL(drm_atomic_begin);
@@ -101,8 +110,20 @@ EXPORT_SYMBOL(drm_atomic_set_event);
 int drm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
 {
      struct drm_atomic_state *a = state;
+     int nplanes = dev->mode_config.num_total_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;
+             }
+     }
+
      a->acquire_ctx.frozen = true;
-     return 0;  /* for now */
+
+     return ret;
 }
 EXPORT_SYMBOL(drm_atomic_check);
 
@@ -180,6 +201,18 @@ fail:
 static void commit_locks(struct drm_atomic_state *a,
              struct ww_acquire_ctx *ww_ctx)
 {
+     struct drm_device *dev = a->dev;
+     int nplanes = dev->mode_config.num_total_plane;
+     int i;
+
+     for (i = 0; i < nplanes; i++) {
+             struct drm_plane *plane = a->planes[i];
+             if (plane) {
+                     plane->state->state = NULL;
+                     drm_plane_destroy_state(plane, a->pstates[i]);
+             }
+     }
+
      /* and properly release them (clear in_atomic, remove from list): */
      drm_modeset_drop_locks(&a->acquire_ctx);
      ww_acquire_fini(ww_ctx);
@@ -189,7 +222,17 @@ static void commit_locks(struct drm_atomic_state *a,
 static int atomic_commit(struct drm_atomic_state *a,
              struct ww_acquire_ctx *ww_ctx)
 {
-     int ret = 0;
+     int nplanes = a->dev->mode_config.num_total_plane;
+     int i, ret = 0;
+
+     for (i = 0; i < nplanes; i++) {
+             struct drm_plane *plane = a->planes[i];
+             if (plane) {
+                     ret = drm_atomic_commit_plane_state(plane, a->pstates[i]);
+                     if (ret)
+                             break;
+             }
+     }
 
      commit_locks(a, ww_ctx);
 
@@ -264,7 +307,185 @@ void _drm_atomic_state_free(struct kref *kref)
 }
 EXPORT_SYMBOL(_drm_atomic_state_free);
 
+int drm_atomic_plane_set_property(struct drm_plane *plane,
+             struct drm_atomic_state *state, struct drm_property *property,
+             uint64_t val, void *blob_data)
+{
+     struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+     if (IS_ERR(pstate))
+             return PTR_ERR(pstate);
+     return drm_plane_set_property(plane, pstate, property, val, blob_data);
+}
+EXPORT_SYMBOL(drm_atomic_plane_set_property);
+
+static void init_plane_state(struct drm_plane *plane,
+             struct drm_plane_state *pstate, struct drm_atomic_state *state)
+{
+     /* snapshot current state: */
+     *pstate = *plane->state;
+     pstate->state = state;
+     if (pstate->fb)
+             drm_framebuffer_reference(pstate->fb);
+}
+
+struct drm_plane_state *
+drm_atomic_get_plane_state(struct drm_plane *plane,
+             struct drm_atomic_state *state)
+{
+     struct drm_atomic_state *a = state;
+     struct drm_plane_state *pstate;
+     int ret;
+
+     pstate = a->pstates[plane->id];
+
+     if (!pstate) {
Quoted 8 lines

drivers/gpu/drm/drm_atomic.c void _drm_atomic_state_free(struct kref *kref) · line 345

Quoted 4 lines
drivers/gpu/drm/drm_atomic.c +4 -0
+             struct drm_modeset_acquire_ctx *ctx = &a->acquire_ctx;
+
+             /* grab lock of current crtc.. if crtc is NULL then grab all: */
+             if (plane->state->crtc)

Looking here looks fishy - who's preventing someone else from touching plane->state while we don't yet hold any locks? Or do I miss something big here?

Yeah, probably should hoist that out into a local variable to avoid problems on transition to null crtc. I don't think it can happen at the moment, but when we start to relax locking it could

Quoted 69 lines
Quoted 69 lines
drivers/gpu/drm/drm_atomic.c +69 -0
+                     ret = drm_modeset_lock(&plane->state->crtc->mutex, ctx);
+             else
+                     ret = drm_modeset_lock_all_crtcs(plane->dev, ctx);
+             if (ret)
+                     return ERR_PTR(ret);
+
+             pstate = drm_plane_create_state(plane);
+             if (!pstate)
+                     return ERR_PTR(-ENOMEM);
+             init_plane_state(plane, pstate, state);
+             a->planes[plane->id] = plane;
+             a->pstates[plane->id] = pstate;
+     }
+
+     return pstate;
+}
+EXPORT_SYMBOL(drm_atomic_get_plane_state);
+
+static void
+swap_plane_state(struct drm_plane *plane, struct drm_atomic_state *a)
+{
+     struct drm_plane_state *pstate = a->pstates[plane->id];
+
+     /* clear transient state (only valid during atomic update): */
+     pstate->update_plane = false;
+     pstate->new_fb = false;
+
+     swap(plane->state, a->pstates[plane->id]);
+     plane->base.propvals = &plane->state->propvals;
+}
+
+/* For primary plane, if the driver implements ->page_flip(), then
+ * we can use that.  But drivers can now choose not to bother with
+ * implementing page_flip().
+ */
+static bool can_flip(struct drm_plane *plane, struct drm_plane_state *pstate)
+{
+     struct drm_crtc *crtc = pstate->crtc;
+     return (plane == crtc->primary) && crtc->funcs->page_flip &&
+                     !pstate->update_plane;
+}
+
+/* clear crtc/fb, ie. after disable_plane().  But takes care to keep
+ * the property state in sync.  Once we get rid of plane->crtc/fb ptrs
+ * and just use state, we can get rid of this fxn:
+ */
+static void
+reset_plane(struct drm_plane *plane, struct drm_plane_state *pstate)
+{
+     struct drm_mode_config *config = &plane->dev->mode_config;
+     drm_plane_set_property(plane, pstate, config->prop_fb_id, 0, NULL);
+     drm_plane_set_property(plane, pstate, config->prop_crtc_id, 0, NULL);
+     plane->crtc = NULL;
+     plane->fb = NULL;
+}
+
+static int
+commit_plane_state(struct drm_plane *plane, struct drm_plane_state *pstate)
+{
+     struct drm_atomic_state *a = pstate->state;
+     struct drm_framebuffer *old_fb = plane->fb;
+     struct drm_framebuffer *fb = pstate->fb;
+     bool enabled = pstate->crtc && fb;
+     int ret = 0;
+
+     if (fb)
+             drm_framebuffer_reference(fb);
+
+     if (!enabled) {
Quoted 8 lines

drivers/gpu/drm/drm_atomic.c void _drm_atomic_state_free(struct kref *kref) · line 420

Quoted 6 lines
drivers/gpu/drm/drm_atomic.c +6 -0
+             if ((plane->type == DRM_PLANE_TYPE_PRIMARY) &&
+                             (plane->funcs == &drm_primary_helper_funcs)) {
+                     /* primary plane helpers don't like ->disable_plane()..
+                      * so this hack for now until someone comes up with
+                      * something better:
+                      */

Imo that's something we could check for in ->check and reject early.

well, we aren't actually treating it as a failure. If we did want to treat it as an error, then yes, we should fail it in ->check(). I'm going to let someone who actually uses primary planes helpers decide how they want it and change it if necessary.

Quoted 20 lines
Quoted 9 lines
drivers/gpu/drm/drm_atomic.c +9 -0
+                     ret = 0;
+             } else {
+                     ret = plane->funcs->disable_plane(plane);
+                     reset_plane(plane, pstate);
+             }
+     } else {
+             struct drm_crtc *crtc = pstate->crtc;
+             if (pstate->update_plane ||
+                             (pstate->new_fb && !can_flip(plane, pstate))) {

drivers/gpu/drm/drm_atomic.c void _drm_atomic_state_free(struct kref *kref) · line 439

Quoted 10 lines
drivers/gpu/drm/drm_atomic.c +10 -0
+                     ret = plane->funcs->update_plane(plane, 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 == 0) {
+                             /*
+                              * For page_flip(), the driver does this, but for
+                              * update_plane() it doesn't.. hurray \o/
+                              */
Quoted 1 line

Imo a patch to unify this first wouldn't hurt ...

I was kinda leaning more towards introducing a new API with unified behaviour, and deprecating the old eventually. Doing it all at once and not having someone who is more expert in each different drivers, seems like too big a chance to introduce problems.

I kinda want to more to an api that is more like atomic_commit() on a per object basis (ie. {crtc,plane,etc}->atomic_commit()). Then driver can hook in to the commit process at device level (dev->atomic_commit()) and/or per-object level as needed.

So yes, I want to unify.. but by building on top of atomic and deprecating the old.

Quoted 24 lines
Quoted 13 lines
drivers/gpu/drm/drm_atomic.c +12 -0
+                             plane->crtc = crtc;
+                             plane->fb = fb;
+                             fb = NULL;  /* don't unref */
+                     }
+
+             } else if (pstate->new_fb) {
+                     ret = crtc->funcs->page_flip(crtc, fb, NULL, a->flags);
+                     if (ret == 0) {
+                             /*
+                              * Warn if the driver hasn't properly updated the plane->fb
+                              * field to reflect that the new framebuffer is now used.
+                              * Failing to do so will screw with the reference counting

drivers/gpu/drm/drm_atomic.c void _drm_atomic_state_free(struct kref *kref) · line 461

Quoted 10 lines
drivers/gpu/drm/drm_atomic.c +10 -0
+                              * on framebuffers.
+                              */
+                             WARN_ON(plane->fb != fb);
+                             fb = NULL;  /* don't unref */
+                     }
+             } else {
+                     old_fb = NULL;
+                     ret = 0;
+             }
+     }
Quoted 7 lines

This entire logic here kinda raises the question about transitioning drivers to the atomic interfaces. For modeset operations it might work fairly well since everything but i915 uses the crtc helpers and so can be converted fairly easily.

But doing nuclear pageflips, even more so if we want completion events is an entire new deal. No idea how that should work really.

Currently we only have completion events on CRTCs, but we are going to need no APIs internally for completion events on planes. Which might end up being the motivation for plane->atomic_commit() API.

At an rate, that should not hold up this patchset, or even adding atomic ioctl itself (as long as we don't expose new events yet, which is something we could leave out of the first version).

Quoted 682 lines
Quoted 682 lines
drivers/gpu/drm/drm_atomic.c +26 -0
+
+     if (ret) {
+             /* Keep the old fb, don't unref it. */
+             old_fb = NULL;
+     } else {
+             /* 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.
+              */
+             swap_plane_state(plane, pstate->state);
+     }
+
+
+     if (fb)
+             drm_framebuffer_unreference(fb);
+     if (old_fb)
+             drm_framebuffer_unreference(old_fb);
+
+     return ret;
+}
 
 const struct drm_atomic_funcs drm_atomic_funcs = {
+             .check_plane_state  = drm_plane_check_state,
+             .commit_plane_state = commit_plane_state,
 };
 EXPORT_SYMBOL(drm_atomic_funcs);
drivers/gpu/drm/drm_crtc.c +297 -136
index 48555724..b556a31 100644
@@ -712,6 +712,18 @@ 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_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) {
@@ -728,8 +740,17 @@ 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);
+                             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);
      }
 
@@ -1090,18 +1111,23 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
                           const uint32_t *formats, uint32_t format_count,
                           enum drm_plane_type type)
 {
+     struct drm_mode_config *config = &dev->mode_config;
      int ret;
 
+     /* this is now required: */
+     WARN_ON(!funcs->set_property);
+
      drm_modeset_lock_all(dev);
 
      ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
      if (ret)
              goto out;
 
+     plane->funcs = funcs;
+     plane->state = drm_plane_create_state(plane);
      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,
                                    GFP_KERNEL);
      if (!plane->format_types) {
@@ -1116,15 +1142,27 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
      plane->possible_crtcs = possible_crtcs;
      plane->type = type;
 
-     list_add_tail(&plane->head, &dev->mode_config.plane_list);
-     dev->mode_config.num_total_plane++;
+     list_add_tail(&plane->head, &config->plane_list);
+     plane->id = config->num_total_plane;
+     config->num_total_plane++;
      if (plane->type == DRM_PLANE_TYPE_OVERLAY)
-             dev->mode_config.num_overlay_plane++;
+             config->num_overlay_plane++;
 
      drm_object_attach_property(&plane->base,
-                                dev->mode_config.plane_type_property,
+                                config->plane_type_property,
                                 plane->type);
 
+     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);
 
@@ -1185,10 +1223,151 @@ void drm_plane_cleanup(struct drm_plane *plane)
      dev->mode_config.num_total_plane--;
      if (plane->type == DRM_PLANE_TYPE_OVERLAY)
              dev->mode_config.num_overlay_plane--;
+     drm_plane_destroy_state(plane, plane->state);
      drm_modeset_unlock_all(dev);
 }
 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_framebuffer *old_fb = state->fb;
+             /*
+              * NOTE: the ref to the fb could have been lost between
+              * drm_property_change_is_valid() and now.  The upshot
+              * is that drm_framebuffer_lookup() could return NULL
+              * and we'd disable the plane.
+              *
+              * We *could* return an error in that case.  But if (for
+              * example) _setcrtc() raced with _rmfb() and _rmfb()
+              * came after, it would disable what was enabled in the
+              * _setcrtc().  Which is the same end result that we get
+              * here, just skipping briefly setting the mode.
+              */
+             state->fb = drm_framebuffer_lookup(dev, value);
+             if (old_fb)
+                     drm_framebuffer_unreference(old_fb);
+             state->new_fb = true;
+     } else if (property == config->prop_crtc_id) {
+             struct drm_mode_object *obj = drm_property_get_obj(property, value);
+             struct drm_crtc *crtc = obj ? obj_to_crtc(obj) : NULL;
+             /* take the lock of the incoming crtc as well, moving
+              * plane between crtcs is synchronized on both incoming
+              * and outgoing crtc.
+              */
+             if (crtc) {
+                     struct drm_atomic_state *a = state->state;
+                     int ret = drm_modeset_lock(&crtc->mutex, &a->acquire_ctx);
+                     if (ret)
+                             return ret;
+             }
+             state->crtc = crtc;
+             state->update_plane = true;
+     } else if (property == config->prop_crtc_x) {
+             state->crtc_x = U642I64(value);
+             state->update_plane = true;
+     } else if (property == config->prop_crtc_y) {
+             state->crtc_y = U642I64(value);
+             state->update_plane = true;
+     } else if (property == config->prop_crtc_w) {
+             state->crtc_w = value;
+             state->update_plane = true;
+     } else if (property == config->prop_crtc_h) {
+             state->crtc_h = value;
+             state->update_plane = true;
+     } else if (property == config->prop_src_x) {
+             state->src_x = value;
+             state->update_plane = true;
+     } else if (property == config->prop_src_y) {
+             state->src_y = value;
+             state->update_plane = true;
+     } else if (property == config->prop_src_w) {
+             state->src_w = value;
+             state->update_plane = true;
+     } else if (property == config->prop_src_h) {
+             state->src_h = value;
+             state->update_plane = true;
+     } else {
+             return -EINVAL;
+     }
+
+     return 0;
+}
+EXPORT_SYMBOL(drm_plane_set_property);
+
 /**
  * drm_plane_force_disable - Forcibly disable a plane
  * @plane: plane to disable
@@ -1198,43 +1377,93 @@ 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,
+             struct drm_atomic_state *state)
 {
-     struct drm_framebuffer *old_fb = plane->fb;
-     int ret;
+     struct drm_mode_config *config = &plane->dev->mode_config;
 
-     if (!old_fb)
-             return;
-
-     ret = plane->funcs->disable_plane(plane);
-     if (ret) {
-             DRM_ERROR("failed to disable plane with busy fb\n");
-             return;
-     }
-     /* disconnect the plane from the fb and crtc: */
-     __drm_framebuffer_unreference(old_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);
 
 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;
+
+
+     prop = drm_property_create_range(dev, 0, "SRC_X", 0, UINT_MAX);
+     if (!prop)
+             return -ENOMEM;
+     dev->mode_config.prop_src_x = prop;
+
+     prop = drm_property_create_range(dev, 0, "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_signed_range(dev, 0, "CRTC_X",
+                     INT_MIN, INT_MAX);
+     if (!prop)
+             return -ENOMEM;
+     dev->mode_config.prop_crtc_x = prop;
+
+     prop = drm_property_create_signed_range(dev, 0, "CRTC_Y",
+                     INT_MIN, 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, 0, "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;
 }
@@ -2140,20 +2369,19 @@ 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_plane *plane;
-     struct drm_crtc *crtc;
-     struct drm_framebuffer *fb = NULL, *old_fb = NULL;
+     struct drm_atomic_state *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.
-      */
+retry:
+     state = dev->driver->atomic_begin(dev, 0);
+     if (IS_ERR(state))
+             return PTR_ERR(state);
+
      plane = drm_plane_find(dev, plane_req->plane_id);
      if (!plane) {
              DRM_DEBUG_KMS("Unknown plane ID %d\n",
@@ -2161,104 +2389,37 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
              return -ENOENT;
      }
 
-     /* No fb means shut it down */
-     if (!plane_req->fb_id) {
-             drm_modeset_lock_all(dev);
-             old_fb = plane->fb;
-             ret = plane->funcs->disable_plane(plane);
-             if (!ret) {
-                     plane->crtc = NULL;
-                     plane->fb = NULL;
-             } else {
-                     old_fb = NULL;
-             }
-             drm_modeset_unlock_all(dev);
-             goto out;
-     }
-
-     crtc = drm_crtc_find(dev, plane_req->crtc_id);
-     if (!crtc) {
-             DRM_DEBUG_KMS("Unknown crtc ID %d\n",
-                           plane_req->crtc_id);
-             ret = -ENOENT;
-             goto out;
-     }
-
-     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;
-     }
-
-     /* 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_plane_set_obj_prop(plane, state,
+                     config->prop_crtc_id, plane_req->crtc_id, NULL) ||
+             drm_mode_plane_set_obj_prop(plane, state,
+                     config->prop_fb_id, plane_req->fb_id, NULL) ||
+             drm_mode_plane_set_obj_prop(plane, state,
+                     config->prop_crtc_x, I642U64(plane_req->crtc_x), NULL) ||
+             drm_mode_plane_set_obj_prop(plane, state,
+                     config->prop_crtc_y, I642U64(plane_req->crtc_y), NULL) ||
+             drm_mode_plane_set_obj_prop(plane, state,
+                     config->prop_crtc_w, plane_req->crtc_w, NULL) ||
+             drm_mode_plane_set_obj_prop(plane, state,
+                     config->prop_crtc_h, plane_req->crtc_h, NULL) ||
+             drm_mode_plane_set_obj_prop(plane, state,
+                     config->prop_src_w, plane_req->src_w, NULL) ||
+             drm_mode_plane_set_obj_prop(plane, state,
+                     config->prop_src_h, plane_req->src_h, NULL) ||
+             drm_mode_plane_set_obj_prop(plane, state,
+                     config->prop_src_x, plane_req->src_x, NULL) ||
+             drm_mode_plane_set_obj_prop(plane, 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);
-     old_fb = plane->fb;
-     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) {
-             plane->crtc = crtc;
-             plane->fb = fb;
-             fb = NULL;
-     } else {
-             old_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);
+     if (ret == -EDEADLK)
+             goto retry;
      return ret;
 }
 
@@ -3833,7 +3994,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,
                                         struct drm_atomic_state *state, struct drm_property *property,
                                         uint64_t value, void *blob_data)
 {
@@ -3856,8 +4017,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,
                                    struct drm_atomic_state *state, struct drm_property *property,
                                    uint64_t value, void *blob_data)
 {
@@ -3872,8 +4034,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,
                                    struct drm_atomic_state *state, struct drm_property *property,
                                    uint64_t value, void *blob_data)
 {
@@ -3882,12 +4045,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,
              struct drm_atomic_state *state, struct drm_property *property,
drivers/gpu/drm/drm_fb_helper.c +16 -1
index 97b0d84..b73d3b0 100644
@@ -286,13 +286,28 @@ 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)
              if (plane->type != DRM_PLANE_TYPE_PRIMARY)
-                     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;
drivers/gpu/drm/drm_plane_helper.c +2 -0
index d966afa..7a32383 100644
@@ -26,6 +26,7 @@
 #include <linux/list.h>
 #include <drm/drmP.h>
 #include <drm/drm_rect.h>
+#include <drm/drm_atomic.h>
 
 #define SUBPIXEL_MASK 0xffff
 
@@ -234,6 +235,7 @@ EXPORT_SYMBOL(drm_primary_helper_destroy);
 const struct drm_plane_funcs drm_primary_helper_funcs = {
      .update_plane = drm_primary_helper_update,
      .disable_plane = drm_primary_helper_disable,
+     .set_property = drm_atomic_plane_set_property,
      .destroy = drm_primary_helper_destroy,
 };
 EXPORT_SYMBOL(drm_primary_helper_funcs);
drivers/gpu/drm/exynos/exynos_drm_plane.c +5 -0
index 9da0935..8cf7442 100644
@@ -10,6 +10,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 
 #include <drm/exynos_drm.h>
 #include "exynos_drm_drv.h"
@@ -220,13 +221,17 @@ static int exynos_plane_set_property(struct drm_plane *plane,
      struct drm_device *dev = plane->dev;
      struct exynos_plane *exynos_plane = to_exynos_plane(plane);
      struct exynos_drm_private *dev_priv = dev->dev_private;
+     struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+
+     if (IS_ERR(pstate))
+             return PTR_ERR(pstate);
 
      if (property == dev_priv->plane_zpos_property) {
              exynos_plane->overlay.zpos = val;
              return 0;
      }
 
Quoted 11 lines

drivers/gpu/drm/exynos/exynos_drm_plane.c static int exynos_plane_set_property(struct drm_plane *plane, · line 235

Quoted 3 lines
drivers/gpu/drm/exynos/exynos_drm_plane.c +1 -1
-     return -EINVAL;
+     return drm_plane_set_property(plane, pstate, property, val, blob_data);
 }

Imo the interfaces here are a bit wonky - most drivers have the exact same structure of allocating a plane state object if it's not there and setting the property. Imo we should push this down a bit and have type-specific set_prop interfaces which take the state-specific state object. Core properties would be fully handled in the core. Which means that driver don't need to implement set_prop callbacks if they don't have any special properties on top of the core stuff. Much less boilerplate that way.

Drivers which do not have any custom properties already just directly use drm_{plane,crtc}_set_property().

Basically, a vanilla driver with no planes, no custom properties, and no inter-crtc dependencies could plug in helpers everywhere a be "fully atomic"(TM).

BR,
-R

Quoted 428 lines

This would also give us a strong incentive to have common properties for e.g. blending since we could simply pimp the core with them, and leave drivers to just register the properties if they support them. If they have additional restrictions they only need to implement the ->check hook, which has the awesome advantage that they can deal with a real structure instead of abstract prop arrays.

E.g. we could add a plane->supports_blending bool which would enabled/disable the default blending/Z-order properties for updating.

Quoted 411 lines
drivers/gpu/drm/exynos/exynos_drm_plane.c +0 -0
 static struct drm_plane_funcs exynos_plane_funcs = {
drivers/gpu/drm/i915/intel_sprite.c +1 -0
index c235546..3f742f5 100644
@@ -1190,6 +1190,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_plane_set_property,
 };
 
 static uint32_t ilk_plane_formats[] = {
drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c +4 -2
index 8c064dc..4c92985 100644
@@ -88,8 +88,10 @@ int mdp4_plane_set_property(struct drm_plane *plane,
              struct drm_atomic_state *state, struct drm_property *property,
              uint64_t val, void *blob_data)
 {
-     // XXX
-     return -EINVAL;
+     struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+     if (IS_ERR(pstate))
+             return PTR_ERR(pstate);
+     return drm_plane_set_property(plane, pstate, property, val, blob_data);
 }
 
 static const struct drm_plane_funcs mdp4_plane_funcs = {
drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +4 -2
index 5cbf226..53cc8c6 100644
@@ -103,8 +103,10 @@ int mdp5_plane_set_property(struct drm_plane *plane,
              struct drm_atomic_state *state, struct drm_property *property,
              uint64_t val, void *blob_data)
 {
-     // XXX
-     return -EINVAL;
+     struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+     if (IS_ERR(pstate))
+             return PTR_ERR(pstate);
+     return drm_plane_set_property(plane, pstate, property, val, blob_data);
 }
 
 static const struct drm_plane_funcs mdp5_plane_funcs = {
drivers/gpu/drm/nouveau/dispnv04/overlay.c +7 -1
index 577e6aa..97b48b5 100644
@@ -24,6 +24,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_fourcc.h>
 
@@ -226,6 +227,10 @@ nv_set_property(struct drm_plane *plane,
                uint64_t value, void *blob_data)
 {
      struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
+     struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+
+     if (IS_ERR(pstate))
+             return PTR_ERR(pstate);
 
      if (property == nv_plane->props.colorkey)
              nv_plane->colorkey = value;
@@ -240,7 +245,8 @@ nv_set_property(struct drm_plane *plane,
      else if (property == nv_plane->props.iturbt_709)
              nv_plane->iturbt_709 = value;
      else
-             return -EINVAL;
+             return drm_plane_set_property(plane, pstate,
+                             property, value, blob_data);
 
      if (nv_plane->set_params)
              nv_plane->set_params(nv_plane);
drivers/gpu/drm/omapdrm/omap_drv.c +1 -1
index 3dca538..da80bdc 100644
@@ -585,7 +585,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);
              }
      }
drivers/gpu/drm/omapdrm/omap_plane.c +7 -0
index 2d3c975..a9acc58 100644
@@ -341,8 +341,12 @@ int omap_plane_set_property(struct drm_plane *plane,
 {
      struct omap_plane *omap_plane = to_omap_plane(plane);
      struct omap_drm_private *priv = plane->dev->dev_private;
+     struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
      int ret = -EINVAL;
 
+     if (IS_ERR(pstate))
+             return PTR_ERR(pstate);
+
      if (property == priv->rotation_prop) {
              DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val);
              omap_plane->win.rotation = val;
@@ -351,6 +355,9 @@ int omap_plane_set_property(struct drm_plane *plane,
              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, pstate, property,
+                             val, blob_data);
      }
 
      return ret;
drivers/gpu/drm/rcar-du/rcar_du_plane.c +7 -1
index 3a5d843..015c76a 100644
@@ -14,6 +14,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -404,6 +405,10 @@ static int rcar_du_plane_set_property(struct drm_plane *plane,
 {
      struct rcar_du_plane *rplane = to_rcar_plane(plane);
      struct rcar_du_group *rgrp = rplane->group;
+     struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+
+     if (IS_ERR(pstate))
+             return PTR_ERR(pstate);
 
      if (property == rgrp->planes.alpha)
              rcar_du_plane_set_alpha(rplane, value);
@@ -412,7 +417,8 @@ 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, pstate,
+                             property, value, blob_data);
 
      return 0;
 }
drivers/gpu/drm/shmobile/shmob_drm_plane.c +2 -0
index 060ae03..ccf03ea 100644
@@ -14,6 +14,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -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_plane_set_property,
      .destroy = shmob_drm_plane_destroy,
 };
 
include/drm/drm_atomic.h +28 -1
index ff72b81..78e93ec 100644
@@ -68,7 +68,8 @@
  * struct drm_atomic_funcs - helper funcs used by the atomic helpers
  */
 struct drm_atomic_funcs {
-     int dummy; /* for now */
+     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_funcs drm_atomic_funcs;
@@ -84,6 +85,30 @@ int drm_atomic_commit_unlocked(struct drm_device *dev,
              struct drm_atomic_state *state);
 void drm_atomic_end(struct drm_device *dev, struct drm_atomic_state *state);
 
+int drm_atomic_plane_set_property(struct drm_plane *plane,
+             struct drm_atomic_state *state, struct drm_property *property,
+             uint64_t val, void *blob_data);
+struct drm_plane_state *drm_atomic_get_plane_state(struct drm_plane *plane,
+             struct drm_atomic_state *state);
+
+static inline int
+drm_atomic_check_plane_state(struct drm_plane *plane,
+             struct drm_plane_state *pstate)
+{
+     const struct drm_atomic_funcs *funcs =
+                     plane->dev->driver->atomic_funcs;
+     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_funcs *funcs =
+                     plane->dev->driver->atomic_funcs;
+     return funcs->commit_plane_state(plane, pstate);
+}
+
 /**
  * struct drm_atomic_state - the state object used by atomic helpers
  */
@@ -91,6 +116,8 @@ struct drm_atomic_state {
      struct kref refcount;
      struct drm_device *dev;
      uint32_t flags;
+     struct drm_plane **planes;
+     struct drm_plane_state **pstates;
 
      bool committed;
      bool checked;       /* just for debugging */
include/drm/drm_crtc.h +110 -5
index 547b75a..58309cc 100644
@@ -569,7 +569,10 @@ 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_plane_state *(*create_state)(struct drm_plane *plane);
+     void (*destroy_state)(struct drm_plane *plane,
+                         struct drm_plane_state *pstate);
+     int (*set_property)(struct drm_plane *plane,
                          struct drm_atomic_state *state,
                          struct drm_property *property, uint64_t val,
                          void *blob_data);
@@ -582,6 +585,48 @@ enum drm_plane_type {
 };
 
 /**
+ * drm_plane_state - mutable plane state
+ * @update_plane: if full update_plane() is needed (vs pageflip)
+ * @new_fb: has the fb been changed
+ * @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 {
+     bool update_plane      : 1;
+     bool new_fb            : 1;
+
+     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;
+
+     struct drm_atomic_state *state;
+};
+
+/**
  * drm_plane - central DRM plane control structure
  * @dev: DRM device this plane belongs to
  * @head: for list management
@@ -591,6 +636,8 @@ enum drm_plane_type {
  * @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
  * @type: type of plane (overlay, primary, cursor)
@@ -608,10 +655,17 @@ struct drm_plane {
      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;
 
      enum drm_plane_type type;
 };
@@ -807,8 +861,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;
      struct drm_property *plane_type_property;
@@ -930,11 +996,20 @@ extern int drm_plane_init(struct drm_device *dev,
                        const uint32_t *formats, uint32_t format_count,
                        bool is_primary);
 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,
+             struct drm_atomic_state *state);
 extern int drm_crtc_check_viewport(const struct drm_crtc *crtc,
                                 int x, int y,
                                 const struct drm_display_mode *mode,
                                 const struct drm_framebuffer *fb);
+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);
 
@@ -984,6 +1059,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,
+                                        struct drm_atomic_state *state, struct drm_property *property,
+                                        uint64_t value, void *blob_data);
+int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
+                                   struct drm_atomic_state *state, struct drm_property *property,
+                                   uint64_t value, void *blob_data);
+int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+                                   struct drm_atomic_state *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);
@@ -1165,6 +1251,26 @@ drm_property_blob_find(struct drm_device *dev, uint32_t id)
      return mo ? obj_to_blob(mo) : NULL;
 }
 
+static inline struct drm_plane_state *
+drm_plane_create_state(struct drm_plane *plane)
+{
+     if (plane->funcs->create_state)
+             return plane->funcs->create_state(plane);
+     return kzalloc(sizeof(struct drm_plane_state), GFP_KERNEL);
+}
+
+static inline void
+drm_plane_destroy_state(struct drm_plane *plane,
+             struct drm_plane_state *pstate)
+{
+     if (pstate->fb)
+             drm_framebuffer_unreference(pstate->fb);
+     if (plane->funcs->destroy_state)
+             plane->funcs->destroy_state(plane, pstate);
+     else
+             kfree(pstate);
+}
+
 /* Plane list iterator for legacy (overlay only) planes. */
 #define drm_for_each_legacy_plane(plane, planelist) \
      list_for_each_entry(plane, planelist, head) \
--
Quoted 2 lines

1.9.0

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

#33 lore raw

Re: [PATCH 11/17] drm: convert plane to properties/state

Quoted 14 lines · Rob Clark
Quoted 13 lines · Daniel Vetter
Quoted 12 lines · Rob Clark

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).

Quoted 7 lines
Quoted 5 lines
Quoted 1 line

Imo s/plane->id/plane->index/ since plane_id can be too easily confused with the mode object id used for the idr lookup. We already have drm_crtc_index, so this is established convention already.

fair enough.. I suppose I could do the same in crtc.

I've forgotten to mention: We then should replace drm_crtc_index with crtc->index since that helper is redundant.

Quoted 207 lines
Quoted 198 lines

A few comments below.

Quoted 196 lines
---
 drivers/gpu/drm/armada/armada_overlay.c    |  11 +-
 drivers/gpu/drm/drm_atomic.c               | 225 ++++++++++++++-
 drivers/gpu/drm/drm_crtc.c                 | 433 ++++++++++++++++++++---------
 drivers/gpu/drm/drm_fb_helper.c            |  17 +-
 drivers/gpu/drm/drm_plane_helper.c         |   2 +
 drivers/gpu/drm/exynos/exynos_drm_plane.c  |   7 +-
 drivers/gpu/drm/i915/intel_sprite.c        |   1 +
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c  |   6 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c  |   6 +-
 drivers/gpu/drm/nouveau/dispnv04/overlay.c |   8 +-
 drivers/gpu/drm/omapdrm/omap_drv.c         |   2 +-
 drivers/gpu/drm/omapdrm/omap_plane.c       |   7 +
 drivers/gpu/drm/rcar-du/rcar_du_plane.c    |   8 +-
 drivers/gpu/drm/shmobile/shmob_drm_plane.c |   2 +
 include/drm/drm_atomic.h                   |  29 +-
 include/drm/drm_crtc.h                     | 114 +++++++-
 16 files changed, 725 insertions(+), 153 deletions(-)
drivers/gpu/drm/armada/armada_overlay.c +10 -1
index 601ba9a..041ea89 100644
@@ -7,6 +7,7 @@
  * published by the Free Software Foundation.
  */
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include "armada_crtc.h"
 #include "armada_drm.h"
 #include "armada_fb.h"
@@ -288,7 +289,12 @@ static int armada_plane_set_property(struct drm_plane *plane,
 {
      struct armada_private *priv = plane->dev->dev_private;
      struct armada_plane *dplane = drm_to_armada_plane(plane);
+     struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
      bool update_attr = false;
+     int ret = 0;
+
+     if (IS_ERR(pstate))
+             return PTR_ERR(pstate);
 
      if (property == priv->colorkey_prop) {
 #define CCC(v) ((v) << 24 | (v) << 16 | (v) << 8)
@@ -342,13 +348,16 @@ static int armada_plane_set_property(struct drm_plane *plane,
      } else if (property == priv->saturation_prop) {
              dplane->prop.saturation = val;
              update_attr = true;
+     } else {
+             ret = drm_plane_set_property(plane, pstate, property,
+                             val, blob_data);
      }
 
      if (update_attr && dplane->base.crtc)
              armada_ovl_update_attr(&dplane->prop,
                                     drm_to_armada_crtc(dplane->base.crtc));
 
-     return 0;
+     return ret;
 }
 
 static const struct drm_plane_funcs armada_plane_funcs = {
drivers/gpu/drm/drm_atomic.c +77 -2
index 45df5e5..403ffc5 100644
@@ -24,6 +24,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
+#include <drm/drm_plane_helper.h>
 
 /**
  * drm_atomic_begin - start a sequence of atomic updates
@@ -46,10 +47,12 @@ struct drm_atomic_state *drm_atomic_begin(struct drm_device *dev,
              uint32_t flags)
 {
      struct drm_atomic_state *state;
+     int nplanes = dev->mode_config.num_total_plane;
      int sz;
      void *ptr;
 
      sz = sizeof(*state);
+     sz += (sizeof(state->planes) + sizeof(state->pstates)) * nplanes;
 
      ptr = kzalloc(sz, GFP_KERNEL);
 
@@ -65,6 +68,12 @@ struct drm_atomic_state *drm_atomic_begin(struct drm_device *dev,
      state->dev = dev;
      state->flags = flags;
 
+     state->planes = ptr;
+     ptr = &state->planes[nplanes];
+
+     state->pstates = ptr;
+     ptr = &state->pstates[nplanes];
+
      return state;
 }
 EXPORT_SYMBOL(drm_atomic_begin);
@@ -101,8 +110,20 @@ EXPORT_SYMBOL(drm_atomic_set_event);
 int drm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
 {
      struct drm_atomic_state *a = state;
+     int nplanes = dev->mode_config.num_total_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;
+             }
+     }
+
      a->acquire_ctx.frozen = true;
-     return 0;  /* for now */
+
+     return ret;
 }
 EXPORT_SYMBOL(drm_atomic_check);
 
@@ -180,6 +201,18 @@ fail:
 static void commit_locks(struct drm_atomic_state *a,
              struct ww_acquire_ctx *ww_ctx)
 {
+     struct drm_device *dev = a->dev;
+     int nplanes = dev->mode_config.num_total_plane;
+     int i;
+
+     for (i = 0; i < nplanes; i++) {
+             struct drm_plane *plane = a->planes[i];
+             if (plane) {
+                     plane->state->state = NULL;
+                     drm_plane_destroy_state(plane, a->pstates[i]);
+             }
+     }
+
      /* and properly release them (clear in_atomic, remove from list): */
      drm_modeset_drop_locks(&a->acquire_ctx);
      ww_acquire_fini(ww_ctx);
@@ -189,7 +222,17 @@ static void commit_locks(struct drm_atomic_state *a,
 static int atomic_commit(struct drm_atomic_state *a,
              struct ww_acquire_ctx *ww_ctx)
 {
-     int ret = 0;
+     int nplanes = a->dev->mode_config.num_total_plane;
+     int i, ret = 0;
+
+     for (i = 0; i < nplanes; i++) {
+             struct drm_plane *plane = a->planes[i];
+             if (plane) {
+                     ret = drm_atomic_commit_plane_state(plane, a->pstates[i]);
+                     if (ret)
+                             break;
+             }
+     }
 
      commit_locks(a, ww_ctx);
 
@@ -264,7 +307,185 @@ void _drm_atomic_state_free(struct kref *kref)
 }
 EXPORT_SYMBOL(_drm_atomic_state_free);
 
+int drm_atomic_plane_set_property(struct drm_plane *plane,
+             struct drm_atomic_state *state, struct drm_property *property,
+             uint64_t val, void *blob_data)
+{
+     struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+     if (IS_ERR(pstate))
+             return PTR_ERR(pstate);
+     return drm_plane_set_property(plane, pstate, property, val, blob_data);
+}
+EXPORT_SYMBOL(drm_atomic_plane_set_property);
+
+static void init_plane_state(struct drm_plane *plane,
+             struct drm_plane_state *pstate, struct drm_atomic_state *state)
+{
+     /* snapshot current state: */
+     *pstate = *plane->state;
+     pstate->state = state;
+     if (pstate->fb)
+             drm_framebuffer_reference(pstate->fb);
+}
+
+struct drm_plane_state *
+drm_atomic_get_plane_state(struct drm_plane *plane,
+             struct drm_atomic_state *state)
+{
+     struct drm_atomic_state *a = state;
+     struct drm_plane_state *pstate;
+     int ret;
+
+     pstate = a->pstates[plane->id];
+
+     if (!pstate) {
Quoted 8 lines

drivers/gpu/drm/drm_atomic.c void _drm_atomic_state_free(struct kref *kref) · line 345

Quoted 4 lines
drivers/gpu/drm/drm_atomic.c +4 -0
+             struct drm_modeset_acquire_ctx *ctx = &a->acquire_ctx;
+
+             /* grab lock of current crtc.. if crtc is NULL then grab all: */
+             if (plane->state->crtc)

Looking here looks fishy - who's preventing someone else from touching plane->state while we don't yet hold any locks? Or do I miss something big here?

Quoted 3 lines

Yeah, probably should hoist that out into a local variable to avoid problems on transition to null crtc. I don't think it can happen at the moment, but when we start to relax locking it could

So what if some manages to race a 2nd atomic modeset and flips out the plane->state from underneath you're now chasing a freed structure?

Trying to be clever and attempting to do this without locks is imo just not worth the (review) pain to keep it race-free.

Quoted 79 lines
Quoted 70 lines
Quoted 70 lines
drivers/gpu/drm/drm_atomic.c +69 -0
+                     ret = drm_modeset_lock(&plane->state->crtc->mutex, ctx);
+             else
+                     ret = drm_modeset_lock_all_crtcs(plane->dev, ctx);
+             if (ret)
+                     return ERR_PTR(ret);
+
+             pstate = drm_plane_create_state(plane);
+             if (!pstate)
+                     return ERR_PTR(-ENOMEM);
+             init_plane_state(plane, pstate, state);
+             a->planes[plane->id] = plane;
+             a->pstates[plane->id] = pstate;
+     }
+
+     return pstate;
+}
+EXPORT_SYMBOL(drm_atomic_get_plane_state);
+
+static void
+swap_plane_state(struct drm_plane *plane, struct drm_atomic_state *a)
+{
+     struct drm_plane_state *pstate = a->pstates[plane->id];
+
+     /* clear transient state (only valid during atomic update): */
+     pstate->update_plane = false;
+     pstate->new_fb = false;
+
+     swap(plane->state, a->pstates[plane->id]);
+     plane->base.propvals = &plane->state->propvals;
+}
+
+/* For primary plane, if the driver implements ->page_flip(), then
+ * we can use that.  But drivers can now choose not to bother with
+ * implementing page_flip().
+ */
+static bool can_flip(struct drm_plane *plane, struct drm_plane_state *pstate)
+{
+     struct drm_crtc *crtc = pstate->crtc;
+     return (plane == crtc->primary) && crtc->funcs->page_flip &&
+                     !pstate->update_plane;
+}
+
+/* clear crtc/fb, ie. after disable_plane().  But takes care to keep
+ * the property state in sync.  Once we get rid of plane->crtc/fb ptrs
+ * and just use state, we can get rid of this fxn:
+ */
+static void
+reset_plane(struct drm_plane *plane, struct drm_plane_state *pstate)
+{
+     struct drm_mode_config *config = &plane->dev->mode_config;
+     drm_plane_set_property(plane, pstate, config->prop_fb_id, 0, NULL);
+     drm_plane_set_property(plane, pstate, config->prop_crtc_id, 0, NULL);
+     plane->crtc = NULL;
+     plane->fb = NULL;
+}
+
+static int
+commit_plane_state(struct drm_plane *plane, struct drm_plane_state *pstate)
+{
+     struct drm_atomic_state *a = pstate->state;
+     struct drm_framebuffer *old_fb = plane->fb;
+     struct drm_framebuffer *fb = pstate->fb;
+     bool enabled = pstate->crtc && fb;
+     int ret = 0;
+
+     if (fb)
+             drm_framebuffer_reference(fb);
+
+     if (!enabled) {
Quoted 8 lines

drivers/gpu/drm/drm_atomic.c void _drm_atomic_state_free(struct kref *kref) · line 420

Quoted 6 lines
drivers/gpu/drm/drm_atomic.c +6 -0
+             if ((plane->type == DRM_PLANE_TYPE_PRIMARY) &&
+                             (plane->funcs == &drm_primary_helper_funcs)) {
+                     /* primary plane helpers don't like ->disable_plane()..
+                      * so this hack for now until someone comes up with
+                      * something better:
+                      */

Imo that's something we could check for in ->check and reject early.

Quoted 4 lines

well, we aren't actually treating it as a failure. If we did want to treat it as an error, then yes, we should fail it in ->check(). I'm going to let someone who actually uses primary planes helpers decide how they want it and change it if necessary.

Atm all drivers use the primary plane helpers. And I guess for a long time most will stick to them, so I think we should have an answer here. Rejecting the modeset sounds like the right one, since after all arbitrary driver restrictions is what we have the ->check hook for.

Quoted 27 lines
Quoted 20 lines
Quoted 9 lines
drivers/gpu/drm/drm_atomic.c +9 -0
+                     ret = 0;
+             } else {
+                     ret = plane->funcs->disable_plane(plane);
+                     reset_plane(plane, pstate);
+             }
+     } else {
+             struct drm_crtc *crtc = pstate->crtc;
+             if (pstate->update_plane ||
+                             (pstate->new_fb && !can_flip(plane, pstate))) {

drivers/gpu/drm/drm_atomic.c void _drm_atomic_state_free(struct kref *kref) · line 439

Quoted 10 lines
drivers/gpu/drm/drm_atomic.c +10 -0
+                     ret = plane->funcs->update_plane(plane, 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 == 0) {
+                             /*
+                              * For page_flip(), the driver does this, but for
+                              * update_plane() it doesn't.. hurray \o/
+                              */
Quoted 1 line

Imo a patch to unify this first wouldn't hurt ...

I was kinda leaning more towards introducing a new API with unified behaviour, and deprecating the old eventually. Doing it all at once and not having someone who is more expert in each different drivers, seems like too big a chance to introduce problems.

Quoted 7 lines

I kinda want to more to an api that is more like atomic_commit() on a per object basis (ie. {crtc,plane,etc}->atomic_commit()). Then driver can hook in to the commit process at device level (dev->atomic_commit()) and/or per-object level as needed.

So yes, I want to unify.. but by building on top of atomic and deprecating the old.

I only meant to unify the refcounting and updating rules for obj->fb and similar. Like I've done for update_plane and set_crtc as part of Matt's primary plane work. Unifying all the flip interfaces is seriously out of scope ;-)

Also I really don't think you can make atomic pageflips work in a generic fashion with per-obj callbacks. After all the entire point is to have an atomic, global update, and the means (or lack thereof) the hw provides to make this happen will be different everywhere.

Atomic modesets (i.e. "do we have sufficient plls for this output config") are a bit different and for those it might work. But that should clearly be part of some helper library.

Yet another reason why imo it's really important to make a clear disdinction between atomic modesets (which we can mostly do for everyone using crtc helpers) and atomic/nuclear pageflips (for which we completely lack the unified driver interface and for which a per-obj ->commit hook is imo useless).

Quoted 31 lines
Quoted 23 lines
Quoted 12 lines
drivers/gpu/drm/drm_atomic.c +12 -0
+                             plane->crtc = crtc;
+                             plane->fb = fb;
+                             fb = NULL;  /* don't unref */
+                     }
+
+             } else if (pstate->new_fb) {
+                     ret = crtc->funcs->page_flip(crtc, fb, NULL, a->flags);
+                     if (ret == 0) {
+                             /*
+                              * Warn if the driver hasn't properly updated the plane->fb
+                              * field to reflect that the new framebuffer is now used.
+                              * Failing to do so will screw with the reference counting

drivers/gpu/drm/drm_atomic.c void _drm_atomic_state_free(struct kref *kref) · line 461

Quoted 10 lines
drivers/gpu/drm/drm_atomic.c +10 -0
+                              * on framebuffers.
+                              */
+                             WARN_ON(plane->fb != fb);
+                             fb = NULL;  /* don't unref */
+                     }
+             } else {
+                     old_fb = NULL;
+                     ret = 0;
+             }
+     }
Quoted 7 lines

This entire logic here kinda raises the question about transitioning drivers to the atomic interfaces. For modeset operations it might work fairly well since everything but i915 uses the crtc helpers and so can be converted fairly easily.

But doing nuclear pageflips, even more so if we want completion events is an entire new deal. No idea how that should work really.

Quoted 7 lines

Currently we only have completion events on CRTCs, but we are going to need no APIs internally for completion events on planes. Which might end up being the motivation for plane->atomic_commit() API.

At an rate, that should not hold up this patchset, or even adding atomic ioctl itself (as long as we don't expose new events yet, which is something we could leave out of the first version).

Hm, what's the use-case for per-plane completion events? Userspace can always multiplex it when they want, and one single nuclear pageflip certainly shouldn't result in different vblank events for different planes on the same crtc. Otherwise it's just not atomic enough ;-)

Imo the pain we gain in making this generic (I've commented about this in other places) doesn't justify the possible gain. Especially since I don't see a real use case.

I think we should have a NUCLEAR_FLIP option in the atomic ioctl which requests that:
- all updates happen on one vblank
- all updates happen asynchronously

and promises that the update only concerns one crtc. All drivers without support for it (i.e. atm everything, hopefully soonish i915 will have support for this) would then reject this.

Which means that for the start atomic updates would only work for modesets, but I also think that's about as good as it gets without driver-specific work anyway.

Quoted 694 lines
Quoted 682 lines
Quoted 682 lines
drivers/gpu/drm/drm_atomic.c +26 -0
+
+     if (ret) {
+             /* Keep the old fb, don't unref it. */
+             old_fb = NULL;
+     } else {
+             /* 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.
+              */
+             swap_plane_state(plane, pstate->state);
+     }
+
+
+     if (fb)
+             drm_framebuffer_unreference(fb);
+     if (old_fb)
+             drm_framebuffer_unreference(old_fb);
+
+     return ret;
+}
 
 const struct drm_atomic_funcs drm_atomic_funcs = {
+             .check_plane_state  = drm_plane_check_state,
+             .commit_plane_state = commit_plane_state,
 };
 EXPORT_SYMBOL(drm_atomic_funcs);
drivers/gpu/drm/drm_crtc.c +297 -136
index 48555724..b556a31 100644
@@ -712,6 +712,18 @@ 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_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) {
@@ -728,8 +740,17 @@ 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);
+                             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);
      }
 
@@ -1090,18 +1111,23 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
                           const uint32_t *formats, uint32_t format_count,
                           enum drm_plane_type type)
 {
+     struct drm_mode_config *config = &dev->mode_config;
      int ret;
 
+     /* this is now required: */
+     WARN_ON(!funcs->set_property);
+
      drm_modeset_lock_all(dev);
 
      ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
      if (ret)
              goto out;
 
+     plane->funcs = funcs;
+     plane->state = drm_plane_create_state(plane);
      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,
                                    GFP_KERNEL);
      if (!plane->format_types) {
@@ -1116,15 +1142,27 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
      plane->possible_crtcs = possible_crtcs;
      plane->type = type;
 
-     list_add_tail(&plane->head, &dev->mode_config.plane_list);
-     dev->mode_config.num_total_plane++;
+     list_add_tail(&plane->head, &config->plane_list);
+     plane->id = config->num_total_plane;
+     config->num_total_plane++;
      if (plane->type == DRM_PLANE_TYPE_OVERLAY)
-             dev->mode_config.num_overlay_plane++;
+             config->num_overlay_plane++;
 
      drm_object_attach_property(&plane->base,
-                                dev->mode_config.plane_type_property,
+                                config->plane_type_property,
                                 plane->type);
 
+     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);
 
@@ -1185,10 +1223,151 @@ void drm_plane_cleanup(struct drm_plane *plane)
      dev->mode_config.num_total_plane--;
      if (plane->type == DRM_PLANE_TYPE_OVERLAY)
              dev->mode_config.num_overlay_plane--;
+     drm_plane_destroy_state(plane, plane->state);
      drm_modeset_unlock_all(dev);
 }
 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_framebuffer *old_fb = state->fb;
+             /*
+              * NOTE: the ref to the fb could have been lost between
+              * drm_property_change_is_valid() and now.  The upshot
+              * is that drm_framebuffer_lookup() could return NULL
+              * and we'd disable the plane.
+              *
+              * We *could* return an error in that case.  But if (for
+              * example) _setcrtc() raced with _rmfb() and _rmfb()
+              * came after, it would disable what was enabled in the
+              * _setcrtc().  Which is the same end result that we get
+              * here, just skipping briefly setting the mode.
+              */
+             state->fb = drm_framebuffer_lookup(dev, value);
+             if (old_fb)
+                     drm_framebuffer_unreference(old_fb);
+             state->new_fb = true;
+     } else if (property == config->prop_crtc_id) {
+             struct drm_mode_object *obj = drm_property_get_obj(property, value);
+             struct drm_crtc *crtc = obj ? obj_to_crtc(obj) : NULL;
+             /* take the lock of the incoming crtc as well, moving
+              * plane between crtcs is synchronized on both incoming
+              * and outgoing crtc.
+              */
+             if (crtc) {
+                     struct drm_atomic_state *a = state->state;
+                     int ret = drm_modeset_lock(&crtc->mutex, &a->acquire_ctx);
+                     if (ret)
+                             return ret;
+             }
+             state->crtc = crtc;
+             state->update_plane = true;
+     } else if (property == config->prop_crtc_x) {
+             state->crtc_x = U642I64(value);
+             state->update_plane = true;
+     } else if (property == config->prop_crtc_y) {
+             state->crtc_y = U642I64(value);
+             state->update_plane = true;
+     } else if (property == config->prop_crtc_w) {
+             state->crtc_w = value;
+             state->update_plane = true;
+     } else if (property == config->prop_crtc_h) {
+             state->crtc_h = value;
+             state->update_plane = true;
+     } else if (property == config->prop_src_x) {
+             state->src_x = value;
+             state->update_plane = true;
+     } else if (property == config->prop_src_y) {
+             state->src_y = value;
+             state->update_plane = true;
+     } else if (property == config->prop_src_w) {
+             state->src_w = value;
+             state->update_plane = true;
+     } else if (property == config->prop_src_h) {
+             state->src_h = value;
+             state->update_plane = true;
+     } else {
+             return -EINVAL;
+     }
+
+     return 0;
+}
+EXPORT_SYMBOL(drm_plane_set_property);
+
 /**
  * drm_plane_force_disable - Forcibly disable a plane
  * @plane: plane to disable
@@ -1198,43 +1377,93 @@ 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,
+             struct drm_atomic_state *state)
 {
-     struct drm_framebuffer *old_fb = plane->fb;
-     int ret;
+     struct drm_mode_config *config = &plane->dev->mode_config;
 
-     if (!old_fb)
-             return;
-
-     ret = plane->funcs->disable_plane(plane);
-     if (ret) {
-             DRM_ERROR("failed to disable plane with busy fb\n");
-             return;
-     }
-     /* disconnect the plane from the fb and crtc: */
-     __drm_framebuffer_unreference(old_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);
 
 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;
+
+
+     prop = drm_property_create_range(dev, 0, "SRC_X", 0, UINT_MAX);
+     if (!prop)
+             return -ENOMEM;
+     dev->mode_config.prop_src_x = prop;
+
+     prop = drm_property_create_range(dev, 0, "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_signed_range(dev, 0, "CRTC_X",
+                     INT_MIN, INT_MAX);
+     if (!prop)
+             return -ENOMEM;
+     dev->mode_config.prop_crtc_x = prop;
+
+     prop = drm_property_create_signed_range(dev, 0, "CRTC_Y",
+                     INT_MIN, 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, 0, "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;
 }
@@ -2140,20 +2369,19 @@ 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_plane *plane;
-     struct drm_crtc *crtc;
-     struct drm_framebuffer *fb = NULL, *old_fb = NULL;
+     struct drm_atomic_state *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.
-      */
+retry:
+     state = dev->driver->atomic_begin(dev, 0);
+     if (IS_ERR(state))
+             return PTR_ERR(state);
+
      plane = drm_plane_find(dev, plane_req->plane_id);
      if (!plane) {
              DRM_DEBUG_KMS("Unknown plane ID %d\n",
@@ -2161,104 +2389,37 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
              return -ENOENT;
      }
 
-     /* No fb means shut it down */
-     if (!plane_req->fb_id) {
-             drm_modeset_lock_all(dev);
-             old_fb = plane->fb;
-             ret = plane->funcs->disable_plane(plane);
-             if (!ret) {
-                     plane->crtc = NULL;
-                     plane->fb = NULL;
-             } else {
-                     old_fb = NULL;
-             }
-             drm_modeset_unlock_all(dev);
-             goto out;
-     }
-
-     crtc = drm_crtc_find(dev, plane_req->crtc_id);
-     if (!crtc) {
-             DRM_DEBUG_KMS("Unknown crtc ID %d\n",
-                           plane_req->crtc_id);
-             ret = -ENOENT;
-             goto out;
-     }
-
-     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;
-     }
-
-     /* 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_plane_set_obj_prop(plane, state,
+                     config->prop_crtc_id, plane_req->crtc_id, NULL) ||
+             drm_mode_plane_set_obj_prop(plane, state,
+                     config->prop_fb_id, plane_req->fb_id, NULL) ||
+             drm_mode_plane_set_obj_prop(plane, state,
+                     config->prop_crtc_x, I642U64(plane_req->crtc_x), NULL) ||
+             drm_mode_plane_set_obj_prop(plane, state,
+                     config->prop_crtc_y, I642U64(plane_req->crtc_y), NULL) ||
+             drm_mode_plane_set_obj_prop(plane, state,
+                     config->prop_crtc_w, plane_req->crtc_w, NULL) ||
+             drm_mode_plane_set_obj_prop(plane, state,
+                     config->prop_crtc_h, plane_req->crtc_h, NULL) ||
+             drm_mode_plane_set_obj_prop(plane, state,
+                     config->prop_src_w, plane_req->src_w, NULL) ||
+             drm_mode_plane_set_obj_prop(plane, state,
+                     config->prop_src_h, plane_req->src_h, NULL) ||
+             drm_mode_plane_set_obj_prop(plane, state,
+                     config->prop_src_x, plane_req->src_x, NULL) ||
+             drm_mode_plane_set_obj_prop(plane, 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);
-     old_fb = plane->fb;
-     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) {
-             plane->crtc = crtc;
-             plane->fb = fb;
-             fb = NULL;
-     } else {
-             old_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);
+     if (ret == -EDEADLK)
+             goto retry;
      return ret;
 }
 
@@ -3833,7 +3994,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,
                                         struct drm_atomic_state *state, struct drm_property *property,
                                         uint64_t value, void *blob_data)
 {
@@ -3856,8 +4017,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,
                                    struct drm_atomic_state *state, struct drm_property *property,
                                    uint64_t value, void *blob_data)
 {
@@ -3872,8 +4034,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,
                                    struct drm_atomic_state *state, struct drm_property *property,
                                    uint64_t value, void *blob_data)
 {
@@ -3882,12 +4045,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,
              struct drm_atomic_state *state, struct drm_property *property,
drivers/gpu/drm/drm_fb_helper.c +16 -1
index 97b0d84..b73d3b0 100644
@@ -286,13 +286,28 @@ 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)
              if (plane->type != DRM_PLANE_TYPE_PRIMARY)
-                     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;
drivers/gpu/drm/drm_plane_helper.c +2 -0
index d966afa..7a32383 100644
@@ -26,6 +26,7 @@
 #include <linux/list.h>
 #include <drm/drmP.h>
 #include <drm/drm_rect.h>
+#include <drm/drm_atomic.h>
 
 #define SUBPIXEL_MASK 0xffff
 
@@ -234,6 +235,7 @@ EXPORT_SYMBOL(drm_primary_helper_destroy);
 const struct drm_plane_funcs drm_primary_helper_funcs = {
      .update_plane = drm_primary_helper_update,
      .disable_plane = drm_primary_helper_disable,
+     .set_property = drm_atomic_plane_set_property,
      .destroy = drm_primary_helper_destroy,
 };
 EXPORT_SYMBOL(drm_primary_helper_funcs);
drivers/gpu/drm/exynos/exynos_drm_plane.c +5 -0
index 9da0935..8cf7442 100644
@@ -10,6 +10,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 
 #include <drm/exynos_drm.h>
 #include "exynos_drm_drv.h"
@@ -220,13 +221,17 @@ static int exynos_plane_set_property(struct drm_plane *plane,
      struct drm_device *dev = plane->dev;
      struct exynos_plane *exynos_plane = to_exynos_plane(plane);
      struct exynos_drm_private *dev_priv = dev->dev_private;
+     struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+
+     if (IS_ERR(pstate))
+             return PTR_ERR(pstate);
 
      if (property == dev_priv->plane_zpos_property) {
              exynos_plane->overlay.zpos = val;
              return 0;
      }
 
Quoted 11 lines

drivers/gpu/drm/exynos/exynos_drm_plane.c static int exynos_plane_set_property(struct drm_plane *plane, · line 235

Quoted 3 lines
drivers/gpu/drm/exynos/exynos_drm_plane.c +1 -1
-     return -EINVAL;
+     return drm_plane_set_property(plane, pstate, property, val, blob_data);
 }

Imo the interfaces here are a bit wonky - most drivers have the exact same structure of allocating a plane state object if it's not there and setting the property. Imo we should push this down a bit and have type-specific set_prop interfaces which take the state-specific state object. Core properties would be fully handled in the core. Which means that driver don't need to implement set_prop callbacks if they don't have any special properties on top of the core stuff. Much less boilerplate that way.

Quoted 6 lines

Drivers which do not have any custom properties already just directly use drm_{plane,crtc}_set_property().

Basically, a vanilla driver with no planes, no custom properties, and no inter-crtc dependencies could plug in helpers everywhere a be "fully atomic"(TM).

My critique is two-fold:
- It looks like the core property parsing is helper code which can be overriden. We very much don't want that, since we want to expose a common set of kms operations that work everywhere.

- Since the callbacks are not object specific there's a bit too much casting going on for my taste.

- For drivers that do have driver props we could move the allocation error handling into the core. Which is imo a Very Good Thing(tm).

Cheers, Daniel

Quoted 432 lines

BR,
-R

Quoted 428 lines

This would also give us a strong incentive to have common properties for e.g. blending since we could simply pimp the core with them, and leave drivers to just register the properties if they support them. If they have additional restrictions they only need to implement the ->check hook, which has the awesome advantage that they can deal with a real structure instead of abstract prop arrays.

E.g. we could add a plane->supports_blending bool which would enabled/disable the default blending/Z-order properties for updating.

Quoted 411 lines
drivers/gpu/drm/exynos/exynos_drm_plane.c +0 -0
 static struct drm_plane_funcs exynos_plane_funcs = {
drivers/gpu/drm/i915/intel_sprite.c +1 -0
index c235546..3f742f5 100644
@@ -1190,6 +1190,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_plane_set_property,
 };
 
 static uint32_t ilk_plane_formats[] = {
drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c +4 -2
index 8c064dc..4c92985 100644
@@ -88,8 +88,10 @@ int mdp4_plane_set_property(struct drm_plane *plane,
              struct drm_atomic_state *state, struct drm_property *property,
              uint64_t val, void *blob_data)
 {
-     // XXX
-     return -EINVAL;
+     struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+     if (IS_ERR(pstate))
+             return PTR_ERR(pstate);
+     return drm_plane_set_property(plane, pstate, property, val, blob_data);
 }
 
 static const struct drm_plane_funcs mdp4_plane_funcs = {
drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +4 -2
index 5cbf226..53cc8c6 100644
@@ -103,8 +103,10 @@ int mdp5_plane_set_property(struct drm_plane *plane,
              struct drm_atomic_state *state, struct drm_property *property,
              uint64_t val, void *blob_data)
 {
-     // XXX
-     return -EINVAL;
+     struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+     if (IS_ERR(pstate))
+             return PTR_ERR(pstate);
+     return drm_plane_set_property(plane, pstate, property, val, blob_data);
 }
 
 static const struct drm_plane_funcs mdp5_plane_funcs = {
drivers/gpu/drm/nouveau/dispnv04/overlay.c +7 -1
index 577e6aa..97b48b5 100644
@@ -24,6 +24,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_fourcc.h>
 
@@ -226,6 +227,10 @@ nv_set_property(struct drm_plane *plane,
                uint64_t value, void *blob_data)
 {
      struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
+     struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+
+     if (IS_ERR(pstate))
+             return PTR_ERR(pstate);
 
      if (property == nv_plane->props.colorkey)
              nv_plane->colorkey = value;
@@ -240,7 +245,8 @@ nv_set_property(struct drm_plane *plane,
      else if (property == nv_plane->props.iturbt_709)
              nv_plane->iturbt_709 = value;
      else
-             return -EINVAL;
+             return drm_plane_set_property(plane, pstate,
+                             property, value, blob_data);
 
      if (nv_plane->set_params)
              nv_plane->set_params(nv_plane);
drivers/gpu/drm/omapdrm/omap_drv.c +1 -1
index 3dca538..da80bdc 100644
@@ -585,7 +585,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);
              }
      }
drivers/gpu/drm/omapdrm/omap_plane.c +7 -0
index 2d3c975..a9acc58 100644
@@ -341,8 +341,12 @@ int omap_plane_set_property(struct drm_plane *plane,
 {
      struct omap_plane *omap_plane = to_omap_plane(plane);
      struct omap_drm_private *priv = plane->dev->dev_private;
+     struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
      int ret = -EINVAL;
 
+     if (IS_ERR(pstate))
+             return PTR_ERR(pstate);
+
      if (property == priv->rotation_prop) {
              DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val);
              omap_plane->win.rotation = val;
@@ -351,6 +355,9 @@ int omap_plane_set_property(struct drm_plane *plane,
              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, pstate, property,
+                             val, blob_data);
      }
 
      return ret;
drivers/gpu/drm/rcar-du/rcar_du_plane.c +7 -1
index 3a5d843..015c76a 100644
@@ -14,6 +14,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -404,6 +405,10 @@ static int rcar_du_plane_set_property(struct drm_plane *plane,
 {
      struct rcar_du_plane *rplane = to_rcar_plane(plane);
      struct rcar_du_group *rgrp = rplane->group;
+     struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+
+     if (IS_ERR(pstate))
+             return PTR_ERR(pstate);
 
      if (property == rgrp->planes.alpha)
              rcar_du_plane_set_alpha(rplane, value);
@@ -412,7 +417,8 @@ 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, pstate,
+                             property, value, blob_data);
 
      return 0;
 }
drivers/gpu/drm/shmobile/shmob_drm_plane.c +2 -0
index 060ae03..ccf03ea 100644
@@ -14,6 +14,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -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_plane_set_property,
      .destroy = shmob_drm_plane_destroy,
 };
 
include/drm/drm_atomic.h +28 -1
index ff72b81..78e93ec 100644
@@ -68,7 +68,8 @@
  * struct drm_atomic_funcs - helper funcs used by the atomic helpers
  */
 struct drm_atomic_funcs {
-     int dummy; /* for now */
+     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_funcs drm_atomic_funcs;
@@ -84,6 +85,30 @@ int drm_atomic_commit_unlocked(struct drm_device *dev,
              struct drm_atomic_state *state);
 void drm_atomic_end(struct drm_device *dev, struct drm_atomic_state *state);
 
+int drm_atomic_plane_set_property(struct drm_plane *plane,
+             struct drm_atomic_state *state, struct drm_property *property,
+             uint64_t val, void *blob_data);
+struct drm_plane_state *drm_atomic_get_plane_state(struct drm_plane *plane,
+             struct drm_atomic_state *state);
+
+static inline int
+drm_atomic_check_plane_state(struct drm_plane *plane,
+             struct drm_plane_state *pstate)
+{
+     const struct drm_atomic_funcs *funcs =
+                     plane->dev->driver->atomic_funcs;
+     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_funcs *funcs =
+                     plane->dev->driver->atomic_funcs;
+     return funcs->commit_plane_state(plane, pstate);
+}
+
 /**
  * struct drm_atomic_state - the state object used by atomic helpers
  */
@@ -91,6 +116,8 @@ struct drm_atomic_state {
      struct kref refcount;
      struct drm_device *dev;
      uint32_t flags;
+     struct drm_plane **planes;
+     struct drm_plane_state **pstates;
 
      bool committed;
      bool checked;       /* just for debugging */
include/drm/drm_crtc.h +110 -5
index 547b75a..58309cc 100644
@@ -569,7 +569,10 @@ 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_plane_state *(*create_state)(struct drm_plane *plane);
+     void (*destroy_state)(struct drm_plane *plane,
+                         struct drm_plane_state *pstate);
+     int (*set_property)(struct drm_plane *plane,
                          struct drm_atomic_state *state,
                          struct drm_property *property, uint64_t val,
                          void *blob_data);
@@ -582,6 +585,48 @@ enum drm_plane_type {
 };
 
 /**
+ * drm_plane_state - mutable plane state
+ * @update_plane: if full update_plane() is needed (vs pageflip)
+ * @new_fb: has the fb been changed
+ * @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 {
+     bool update_plane      : 1;
+     bool new_fb            : 1;
+
+     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;
+
+     struct drm_atomic_state *state;
+};
+
+/**
  * drm_plane - central DRM plane control structure
  * @dev: DRM device this plane belongs to
  * @head: for list management
@@ -591,6 +636,8 @@ enum drm_plane_type {
  * @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
  * @type: type of plane (overlay, primary, cursor)
@@ -608,10 +655,17 @@ struct drm_plane {
      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;
 
      enum drm_plane_type type;
 };
@@ -807,8 +861,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;
      struct drm_property *plane_type_property;
@@ -930,11 +996,20 @@ extern int drm_plane_init(struct drm_device *dev,
                        const uint32_t *formats, uint32_t format_count,
                        bool is_primary);
 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,
+             struct drm_atomic_state *state);
 extern int drm_crtc_check_viewport(const struct drm_crtc *crtc,
                                 int x, int y,
                                 const struct drm_display_mode *mode,
                                 const struct drm_framebuffer *fb);
+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);
 
@@ -984,6 +1059,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,
+                                        struct drm_atomic_state *state, struct drm_property *property,
+                                        uint64_t value, void *blob_data);
+int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
+                                   struct drm_atomic_state *state, struct drm_property *property,
+                                   uint64_t value, void *blob_data);
+int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+                                   struct drm_atomic_state *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);
@@ -1165,6 +1251,26 @@ drm_property_blob_find(struct drm_device *dev, uint32_t id)
      return mo ? obj_to_blob(mo) : NULL;
 }
 
+static inline struct drm_plane_state *
+drm_plane_create_state(struct drm_plane *plane)
+{
+     if (plane->funcs->create_state)
+             return plane->funcs->create_state(plane);
+     return kzalloc(sizeof(struct drm_plane_state), GFP_KERNEL);
+}
+
+static inline void
+drm_plane_destroy_state(struct drm_plane *plane,
+             struct drm_plane_state *pstate)
+{
+     if (pstate->fb)
+             drm_framebuffer_unreference(pstate->fb);
+     if (plane->funcs->destroy_state)
+             plane->funcs->destroy_state(plane, pstate);
+     else
+             kfree(pstate);
+}
+
 /* Plane list iterator for legacy (overlay only) planes. */
 #define drm_for_each_legacy_plane(plane, planelist) \
      list_for_each_entry(plane, planelist, head) \
--
Quoted 2 lines

1.9.0

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

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
author
#34 lore raw

PATCH 12/17 drm: convert crtc to properties/state

In reply to Rob Clark

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/armada/armada_crtc.c       |  11 +-
 drivers/gpu/drm/ast/ast_mode.c             |   1 +
 drivers/gpu/drm/cirrus/cirrus_mode.c       |   1 +
 drivers/gpu/drm/drm_atomic.c               | 231 ++++++++++-
 drivers/gpu/drm/drm_crtc.c                 | 598 ++++++++++++++++++-----------
 drivers/gpu/drm/drm_fb_helper.c            |   2 +-
 drivers/gpu/drm/exynos/exynos_drm_crtc.c   |   7 +-
 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/mdp/mdp4/mdp4_crtc.c   |   6 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c   |   6 +-
 drivers/gpu/drm/nouveau/dispnv04/crtc.c    |   1 +
 drivers/gpu/drm/nouveau/nv50_display.c     |   1 +
 drivers/gpu/drm/omapdrm/omap_crtc.c        |  12 +-
 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 +
 include/drm/drm_atomic.h                   |  29 ++
 include/drm/drm_crtc.h                     | 103 ++++-
 27 files changed, 785 insertions(+), 243 deletions(-)
drivers/gpu/drm/armada/armada_crtc.c +10 -1
index 7d3c649..6237af4 100644
@@ -9,6 +9,7 @@
 #include <linux/clk.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include "armada_crtc.h"
 #include "armada_drm.h"
 #include "armada_fb.h"
@@ -966,7 +967,12 @@ armada_drm_crtc_set_property(struct drm_crtc *crtc,
 {
 	struct armada_private *priv = crtc->dev->dev_private;
 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
+	struct drm_crtc_state *cstate = drm_atomic_get_crtc_state(crtc, state);
 	bool update_csc = false;
+	int ret = 0;
+
+	if (IS_ERR(cstate))
+		return PTR_ERR(cstate);
 
 	if (property == priv->csc_yuv_prop) {
 		dcrtc->csc_yuv_mode = val;
@@ -974,6 +980,9 @@ armada_drm_crtc_set_property(struct drm_crtc *crtc,
 	} else if (property == priv->csc_rgb_prop) {
 		dcrtc->csc_rgb_mode = val;
 		update_csc = true;
+	} else {
+		ret = drm_crtc_set_property(crtc, cstate, property,
+				val, blob_data);
 	}
 
 	if (update_csc) {
@@ -984,7 +993,7 @@ armada_drm_crtc_set_property(struct drm_crtc *crtc,
 		writel_relaxed(val, dcrtc->base + LCD_SPU_IOPAD_CONTROL);
 	}
 
-	return 0;
+	return ret;
 }
 
 static struct drm_crtc_funcs armada_crtc_funcs = {
drivers/gpu/drm/ast/ast_mode.c +1 -0
index 114aee9..c08e0e1 100644
@@ -632,6 +632,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_crtc_set_property,
 	.gamma_set = ast_crtc_gamma_set,
 	.destroy = ast_crtc_destroy,
 };
drivers/gpu/drm/cirrus/cirrus_mode.c +1 -0
index 49332c5..3c4428c 100644
@@ -366,6 +366,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_crtc_set_property,
 	.destroy = cirrus_crtc_destroy,
 };
 
drivers/gpu/drm/drm_atomic.c +228 -3

322 lines not on this page · raw message

drivers/gpu/drm/drm_crtc.c +384 -214

774 lines not on this page · raw message

drivers/gpu/drm/drm_fb_helper.c +1 -1
index b73d3b0..4669e69 100644
@@ -286,7 +286,7 @@ 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;
+	struct drm_atomic_state *state;
 	int i;
 
 	drm_warn_on_modeset_not_all_locked(dev);
drivers/gpu/drm/exynos/exynos_drm_crtc.c +6 -1
index 2a56973..f3c7e77 100644
@@ -14,6 +14,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 
 #include "exynos_drm_crtc.h"
 #include "exynos_drm_drv.h"
@@ -289,6 +290,10 @@ static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
 	struct drm_device *dev = crtc->dev;
 	struct exynos_drm_private *dev_priv = dev->dev_private;
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+	struct drm_crtc_state *cstate = drm_atomic_get_crtc_state(crtc, state);
+
+	if (IS_ERR(cstate))
+		return PTR_ERR(cstate);
 
 	if (property == dev_priv->crtc_mode_property) {
 		enum exynos_crtc_mode mode = val;
@@ -313,7 +318,7 @@ static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
 		return 0;
 	}
 
-	return -EINVAL;
+	return drm_crtc_set_property(crtc, cstate, property, val, blob_data);
 }
 
 static struct drm_crtc_funcs exynos_crtc_funcs = {
drivers/gpu/drm/gma500/cdv_intel_display.c +1 -0
index 6672732..5b6eee9 100644
@@ -989,6 +989,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_crtc_set_property,
 	.destroy = gma_crtc_destroy,
 };
 
drivers/gpu/drm/gma500/psb_intel_display.c +1 -0
index 87b50ba..79b5692 100644
@@ -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_crtc_set_property,
 	.destroy = gma_crtc_destroy,
 };
 
drivers/gpu/drm/i915/intel_display.c +1 -0
index e9f6eb7..53b996f 100644
@@ -10430,6 +10430,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_crtc_set_property,
 	.destroy = intel_crtc_destroy,
 	.page_flip = intel_crtc_page_flip,
 };
drivers/gpu/drm/mgag200/mgag200_mode.c +1 -0
index a034ed4..ba9bd91 100644
@@ -1296,6 +1296,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_crtc_set_property,
 	.destroy = mga_crtc_destroy,
 };
 
drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +4 -2
index 7cf0f78..d0d8befd 100644
@@ -471,8 +471,10 @@ static int mdp4_crtc_set_property(struct drm_crtc *crtc,
 		struct drm_atomic_state *state, struct drm_property *property,
 		uint64_t val, void *blob_data)
 {
-	// XXX
-	return -EINVAL;
+	struct drm_crtc_state *cstate = drm_atomic_get_crtc_state(crtc, state);
+	if (IS_ERR(cstate))
+		return PTR_ERR(cstate);
+	return drm_crtc_set_property(crtc, cstate, property, val, blob_data);
 }
 
 #define CURSOR_WIDTH 64
drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +4 -2
index 771390b..7f4ee99 100644
@@ -389,8 +389,10 @@ static int mdp5_crtc_set_property(struct drm_crtc *crtc,
 		struct drm_atomic_state *state, struct drm_property *property,
 		uint64_t val, void *blob_data)
 {
-	// XXX
-	return -EINVAL;
+	struct drm_crtc_state *cstate = drm_atomic_get_crtc_state(crtc, state);
+	if (IS_ERR(cstate))
+		return PTR_ERR(cstate);
+	return drm_crtc_set_property(crtc, cstate, property, val, blob_data);
 }
 
 static const struct drm_crtc_funcs mdp5_crtc_funcs = {
drivers/gpu/drm/nouveau/dispnv04/crtc.c +1 -0
index 41be342..9e24632 100644
@@ -1086,6 +1086,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_crtc_set_property,
 	.page_flip = nouveau_crtc_page_flip,
 	.destroy = nv_crtc_destroy,
 };
drivers/gpu/drm/nouveau/nv50_display.c +1 -0
index 58af547..ecbffeb 100644
@@ -1329,6 +1329,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_crtc_set_property,
 	.destroy = nv50_crtc_destroy,
 	.page_flip = nouveau_crtc_page_flip,
 };
drivers/gpu/drm/omapdrm/omap_crtc.c +10 -2
index a75934d..772687b 100644
@@ -387,14 +387,22 @@ static int omap_crtc_set_property(struct drm_crtc *crtc,
 {
 	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 (IS_ERR(cstate))
+		return PTR_ERR(cstate);
 
 	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 = {
drivers/gpu/drm/omapdrm/omap_drv.c +1 -1
index da80bdc..3f64c47 100644
@@ -579,7 +579,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);
 		}
 
drivers/gpu/drm/qxl/qxl_display.c +2 -0
index b54c970..25896a9 100644
@@ -29,6 +29,7 @@
 #include "qxl_drv.h"
 #include "qxl_object.h"
 #include "drm_crtc_helper.h"
+#include "drm_atomic.h"
 
 static bool qxl_head_enabled(struct qxl_head *head)
 {
@@ -373,6 +374,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_crtc_set_property,
 	.destroy = qxl_crtc_destroy,
 };
 
drivers/gpu/drm/radeon/radeon_display.c +2 -0
index 8d99d5e..cc86aac 100644
@@ -32,6 +32,7 @@
 
 #include <linux/pm_runtime.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_edid.h>
 
 #include <linux/gcd.h>
@@ -546,6 +547,7 @@ static const struct drm_crtc_funcs radeon_crtc_funcs = {
 	.cursor_move = radeon_crtc_cursor_move,
 	.gamma_set = radeon_crtc_gamma_set,
 	.set_config = radeon_crtc_set_config,
+	.set_property = drm_atomic_crtc_set_property,
 	.destroy = radeon_crtc_destroy,
 	.page_flip = radeon_crtc_page_flip,
 };
drivers/gpu/drm/rcar-du/rcar_du_crtc.c +2 -0
index 299267d..f5a3d55 100644
@@ -17,6 +17,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -527,6 +528,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_crtc_set_property,
 	.page_flip = rcar_du_crtc_page_flip,
 };
 
drivers/gpu/drm/shmobile/shmob_drm_crtc.c +2 -0
index 90e023a..0a5280c 100644
@@ -17,6 +17,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -506,6 +507,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_crtc_set_property,
 	.page_flip = shmob_drm_crtc_page_flip,
 };
 
drivers/gpu/drm/tilcdc/tilcdc_crtc.c +1 -0
index 92839ba..b07f116 100644
@@ -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_crtc_set_property,
 		.page_flip      = tilcdc_crtc_page_flip,
 };
 
drivers/gpu/drm/udl/udl_modeset.c +2 -0
index cddc4fc..36d0116 100644
@@ -14,6 +14,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.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_crtc_set_property,
 	.destroy = udl_crtc_destroy,
 };
 
drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +1 -0
index b2b9bd2..0313b00 100644
@@ -300,6 +300,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_crtc_set_property,
 	.set_config = vmw_ldu_crtc_set_config,
 };
 
drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +1 -0
index a95d3a0..b723e09 100644
@@ -397,6 +397,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_crtc_set_property,
 	.page_flip = vmw_du_page_flip,
 };
 
include/drm/drm_atomic.h +29 -0
index 78e93ec..7946b7f 100644
@@ -70,6 +70,9 @@
 struct drm_atomic_funcs {
 	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);
+
+	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_funcs drm_atomic_funcs;
@@ -109,6 +112,30 @@ drm_atomic_commit_plane_state(struct drm_plane *plane,
 	return funcs->commit_plane_state(plane, pstate);
 }
 
+int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t val, void *blob_data);
+struct drm_crtc_state *drm_atomic_get_crtc_state(struct drm_crtc *crtc,
+		struct drm_atomic_state *state);
+
+static inline int
+drm_atomic_check_crtc_state(struct drm_crtc *crtc,
+		struct drm_crtc_state *cstate)
+{
+	const struct drm_atomic_funcs *funcs =
+			crtc->dev->driver->atomic_funcs;
+	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_funcs *funcs =
+			crtc->dev->driver->atomic_funcs;
+	return funcs->commit_crtc_state(crtc, cstate);
+}
+
 /**
  * struct drm_atomic_state - the state object used by atomic helpers
  */
@@ -118,6 +145,8 @@ struct drm_atomic_state {
 	uint32_t flags;
 	struct drm_plane **planes;
 	struct drm_plane_state **pstates;
+	struct drm_crtc **crtcs;
+	struct drm_crtc_state **cstates;
 
 	bool committed;
 	bool checked;       /* just for debugging */
include/drm/drm_crtc.h +87 -16

186 lines not on this page · raw message

Signature · 1 line
1.9.0
#35 lore raw

Re: [PATCH 12/17] drm: convert crtc to properties/state

Quoted 10 lines · Rob Clark

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.

Same comments about interface design as for the plane patch apply here. One additional comment below.

Quoted 136 lines
---
 drivers/gpu/drm/armada/armada_crtc.c       |  11 +-
 drivers/gpu/drm/ast/ast_mode.c             |   1 +
 drivers/gpu/drm/cirrus/cirrus_mode.c       |   1 +
 drivers/gpu/drm/drm_atomic.c               | 231 ++++++++++-
 drivers/gpu/drm/drm_crtc.c                 | 598 ++++++++++++++++++-----------
 drivers/gpu/drm/drm_fb_helper.c            |   2 +-
 drivers/gpu/drm/exynos/exynos_drm_crtc.c   |   7 +-
 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/mdp/mdp4/mdp4_crtc.c   |   6 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c   |   6 +-
 drivers/gpu/drm/nouveau/dispnv04/crtc.c    |   1 +
 drivers/gpu/drm/nouveau/nv50_display.c     |   1 +
 drivers/gpu/drm/omapdrm/omap_crtc.c        |  12 +-
 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 +
 include/drm/drm_atomic.h                   |  29 ++
 include/drm/drm_crtc.h                     | 103 ++++-
 27 files changed, 785 insertions(+), 243 deletions(-)
drivers/gpu/drm/armada/armada_crtc.c +10 -1
index 7d3c649..6237af4 100644
@@ -9,6 +9,7 @@
 #include <linux/clk.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include "armada_crtc.h"
 #include "armada_drm.h"
 #include "armada_fb.h"
@@ -966,7 +967,12 @@ armada_drm_crtc_set_property(struct drm_crtc *crtc,
 {
 	struct armada_private *priv = crtc->dev->dev_private;
 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
+	struct drm_crtc_state *cstate = drm_atomic_get_crtc_state(crtc, state);
 	bool update_csc = false;
+	int ret = 0;
+
+	if (IS_ERR(cstate))
+		return PTR_ERR(cstate);
 
 	if (property == priv->csc_yuv_prop) {
 		dcrtc->csc_yuv_mode = val;
@@ -974,6 +980,9 @@ armada_drm_crtc_set_property(struct drm_crtc *crtc,
 	} else if (property == priv->csc_rgb_prop) {
 		dcrtc->csc_rgb_mode = val;
 		update_csc = true;
+	} else {
+		ret = drm_crtc_set_property(crtc, cstate, property,
+				val, blob_data);
 	}
 
 	if (update_csc) {
@@ -984,7 +993,7 @@ armada_drm_crtc_set_property(struct drm_crtc *crtc,
 		writel_relaxed(val, dcrtc->base + LCD_SPU_IOPAD_CONTROL);
 	}
 
-	return 0;
+	return ret;
 }
 
 static struct drm_crtc_funcs armada_crtc_funcs = {
drivers/gpu/drm/ast/ast_mode.c +1 -0
index 114aee9..c08e0e1 100644
@@ -632,6 +632,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_crtc_set_property,
 	.gamma_set = ast_crtc_gamma_set,
 	.destroy = ast_crtc_destroy,
 };
drivers/gpu/drm/cirrus/cirrus_mode.c +1 -0
index 49332c5..3c4428c 100644
@@ -366,6 +366,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_crtc_set_property,
 	.destroy = cirrus_crtc_destroy,
 };
 
drivers/gpu/drm/drm_atomic.c +10 -1
index 403ffc5..863a0fe 100644
@@ -48,11 +48,13 @@ struct drm_atomic_state *drm_atomic_begin(struct drm_device *dev,
 {
 	struct drm_atomic_state *state;
 	int nplanes = dev->mode_config.num_total_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);
 
@@ -74,6 +76,12 @@ struct drm_atomic_state *drm_atomic_begin(struct drm_device *dev,
 	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_begin);
@@ -92,7 +100,18 @@ int drm_atomic_set_event(struct drm_device *dev,
 		struct drm_atomic_state *state, struct drm_mode_object *obj,
 		struct drm_pending_vblank_event *event)
 {
-	return -EINVAL;  /* for now */
+	switch (obj->type) {
+	case DRM_MODE_OBJECT_CRTC: {

drivers/gpu/drm/drm_atomic.c int drm_atomic_set_event(struct drm_device *dev, · line 114

Quoted 10 lines
drivers/gpu/drm/drm_atomic.c +10 -0
+		struct drm_crtc_state *cstate =
+			drm_atomic_get_crtc_state(obj_to_crtc(obj), state);
+		if (IS_ERR(cstate))
+			return PTR_ERR(cstate);
+		cstate->event = event;
+		return 0;
+	}
+	default:
+		return -EINVAL;
+	}

Hm, I think if we only want completion events on crtcs (which I agree on) then we should make the set_event interface more specific by passing struct drm_crtc * and only call it for crtcs.

Quoted 154 lines
drivers/gpu/drm/drm_atomic.c +76 -2
 }
 EXPORT_SYMBOL(drm_atomic_set_event);
 
@@ -111,6 +130,7 @@ int drm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
 {
 	struct drm_atomic_state *a = state;
 	int nplanes = dev->mode_config.num_total_plane;
+	int ncrtcs = dev->mode_config.num_crtc;
 	int i, ret = 0;
 
 	for (i = 0; i < nplanes; i++) {
@@ -120,6 +140,13 @@ int drm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
 				break;
 		}
 	}
+	for (i = 0; i < ncrtcs; i++) {
+		if (a->crtcs[i]) {
+			ret = drm_atomic_check_crtc_state(a->crtcs[i], a->cstates[i]);
+			if (ret)
+				break;
+		}
+	}
 
 	a->acquire_ctx.frozen = true;
 
@@ -203,6 +230,7 @@ static void commit_locks(struct drm_atomic_state *a,
 {
 	struct drm_device *dev = a->dev;
 	int nplanes = dev->mode_config.num_total_plane;
+	int ncrtcs = dev->mode_config.num_crtc;
 	int i;
 
 	for (i = 0; i < nplanes; i++) {
@@ -213,6 +241,14 @@ static void commit_locks(struct drm_atomic_state *a,
 		}
 	}
 
+	for (i = 0; i < ncrtcs; i++) {
+		struct drm_crtc *crtc = a->crtcs[i];
+		if (crtc) {
+			crtc->state->state = NULL;
+			drm_crtc_destroy_state(crtc, a->cstates[i]);
+		}
+	}
+
 	/* and properly release them (clear in_atomic, remove from list): */
 	drm_modeset_drop_locks(&a->acquire_ctx);
 	ww_acquire_fini(ww_ctx);
@@ -223,8 +259,18 @@ static int atomic_commit(struct drm_atomic_state *a,
 		struct ww_acquire_ctx *ww_ctx)
 {
 	int nplanes = a->dev->mode_config.num_total_plane;
+	int ncrtcs = a->dev->mode_config.num_crtc;
 	int i, ret = 0;
 
+	for (i = 0; i < ncrtcs; i++) {
+		struct drm_crtc *crtc = a->crtcs[i];
+		if (crtc) {
+			ret = drm_atomic_commit_crtc_state(crtc, a->cstates[i]);
+			if (ret)
+				break;
+		}
+	}
+
 	for (i = 0; i < nplanes; i++) {
 		struct drm_plane *plane = a->planes[i];
 		if (plane) {
@@ -403,6 +449,7 @@ static int
 commit_plane_state(struct drm_plane *plane, struct drm_plane_state *pstate)
 {
 	struct drm_atomic_state *a = pstate->state;
+	struct drm_crtc_state *cstate = NULL;
 	struct drm_framebuffer *old_fb = plane->fb;
 	struct drm_framebuffer *fb = pstate->fb;
 	bool enabled = pstate->crtc && fb;
@@ -425,8 +472,11 @@ commit_plane_state(struct drm_plane *plane, struct drm_plane_state *pstate)
 		}
 	} else {
 		struct drm_crtc *crtc = pstate->crtc;
+		cstate = drm_atomic_get_crtc_state(crtc, pstate->state);
 		if (pstate->update_plane ||
 				(pstate->new_fb && !can_flip(plane, pstate))) {
+/* TODO pass event to update_plane().. */
+WARN_ON(cstate->event);
 			ret = plane->funcs->update_plane(plane, crtc, pstate->fb,
 					pstate->crtc_x, pstate->crtc_y,
 					pstate->crtc_w, pstate->crtc_h,
@@ -443,7 +493,7 @@ commit_plane_state(struct drm_plane *plane, struct drm_plane_state *pstate)
 			}
 
 		} else if (pstate->new_fb) {
-			ret = crtc->funcs->page_flip(crtc, fb, NULL, a->flags);
+			ret = crtc->funcs->page_flip(crtc, fb, cstate->event, a->flags);
 			if (ret == 0) {
 				/*
 				 * Warn if the driver hasn't properly updated the plane->fb
@@ -473,9 +523,10 @@ commit_plane_state(struct drm_plane *plane, struct drm_plane_state *pstate)
 		 * original code.
 		 */
 		swap_plane_state(plane, pstate->state);
+		if (cstate)
+			cstate->event = NULL;
 	}
 
-
 	if (fb)
 		drm_framebuffer_unreference(fb);
 	if (old_fb)
@@ -484,8 +535,182 @@ commit_plane_state(struct drm_plane *plane, struct drm_plane_state *pstate)
 	return ret;
 }
 
+int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t val, void *blob_data)
+{
+	struct drm_crtc_state *cstate = drm_atomic_get_crtc_state(crtc, state);
+	if (IS_ERR(cstate))
+		return PTR_ERR(cstate);
+	return drm_crtc_set_property(crtc, cstate, property, val, blob_data);
+}
+EXPORT_SYMBOL(drm_atomic_crtc_set_property);
+
+static void init_crtc_state(struct drm_crtc *crtc,
+		struct drm_crtc_state *cstate, struct drm_atomic_state *state)
+{
+	/* snapshot current state: */
+	*cstate = *crtc->state;
+	cstate->state = state;
+
+	if (cstate->connector_ids) {
+		int sz = cstate->num_connector_ids * sizeof(cstate->connector_ids[0]);
+		cstate->connector_ids = kmemdup(cstate->connector_ids, sz, GFP_KERNEL);
+	}
+
+	/* this should never happen.. but make sure! */
+	WARN_ON(cstate->event);
+	cstate->event = NULL;
+}
+
+struct drm_crtc_state *
+drm_atomic_get_crtc_state(struct drm_crtc *crtc, struct drm_atomic_state *a)
+{
+	struct drm_crtc_state *cstate;
+	int ret;
+
+	cstate = a->cstates[crtc->id];
+
+	if (!cstate) {
+		ret = drm_modeset_lock(&crtc->mutex, &a->acquire_ctx);
+		if (ret)
+			return ERR_PTR(ret);
+
+		cstate = drm_crtc_create_state(crtc);

drivers/gpu/drm/drm_atomic.c commit_plane_state(struct drm_plane *plane, struct drm_plane_state *pstate) · line 589

Quoted 10 lines
drivers/gpu/drm/drm_atomic.c +10 -0
+		if (!cstate)
+			return ERR_PTR(-ENOMEM);
+		init_crtc_state(crtc, cstate, a);
+		a->crtcs[crtc->id] = crtc;
+		a->cstates[crtc->id] = cstate;
+
+		/* we'll need it later, so make sure we have state
+		 * for primary plane too:
+		 */
+		drm_atomic_get_plane_state(crtc->primary, a);

I haven't figured out why. With primary planes I don't really see a need for this. If we need it to implement the legacy setcrtc interface, then that should be done there, not here.

Quoted 1,511 lines
drivers/gpu/drm/drm_atomic.c +122 -0
+	}
+	return cstate;
+}
+EXPORT_SYMBOL(drm_atomic_get_crtc_state);
+
+static void
+swap_crtc_state(struct drm_crtc *crtc, struct drm_atomic_state *a)
+{
+	struct drm_crtc_state *cstate = a->cstates[crtc->id];
+	struct drm_device *dev = crtc->dev;
+	struct drm_pending_vblank_event *event = cstate->event;
+
+	if (event) {
+		/* hrm, need to sort out a better way to send events for
+		 * other-than-pageflip.. but modeset is not async, so:
+		 */
+		unsigned long flags;
+		spin_lock_irqsave(&dev->event_lock, flags);
+		drm_send_vblank_event(dev, crtc->id, event);
+		cstate->event = NULL;
+		spin_unlock_irqrestore(&dev->event_lock, flags);
+	}
+
+	/* clear transient state (only valid during atomic update): */
+	cstate->set_config = false;
+	cstate->connectors_change = false;
+
+	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_plane_state *pstate =
+			drm_atomic_get_plane_state(crtc->primary, cstate->state);
+	struct drm_framebuffer *fb = pstate->fb;
+	struct drm_connector **connector_set = get_connector_set(crtc->dev,
+			cstate->connector_ids, cstate->num_connector_ids);
+	struct drm_display_mode *mode = drm_crtc_get_mode(crtc, cstate);
+	struct drm_mode_set set = {
+			.crtc = crtc,
+			.x = pstate->src_x >> 16,
+			.y = pstate->src_y >> 16,
+			.mode = mode,
+			.num_connectors = cstate->num_connector_ids,
+			.connectors = connector_set,
+			.fb = fb,
+	};
+	int ret;
+
+	if (IS_ERR(mode)) {
+		ret = PTR_ERR(mode);
+		return ret;
+	}
+
+	if (fb)
+		drm_framebuffer_reference(fb);
+
+	ret = drm_mode_set_config_internal(&set);
+	if (!ret) {
+		swap_crtc_state(crtc, cstate->state);
+		pstate->new_fb = pstate->update_plane = false;
+	}
+
+	if (fb)
+		drm_framebuffer_unreference(fb);
+
+	kfree(connector_set);
+	if (mode)
+		drm_mode_destroy(dev, mode);
+	return ret;
+}
+
+static int
+commit_crtc_state(struct drm_crtc *crtc,
+		struct drm_crtc_state *cstate)
+{
+	struct drm_plane_state *pstate =
+			drm_atomic_get_plane_state(crtc->primary, cstate->state);
+	int ret = -EINVAL;
+
+	if (cstate->set_config)
+		return set_config(crtc, cstate);
+
+	if (!pstate->fb) {
+		/* disable */
+		struct drm_mode_set set = {
+				.crtc = crtc,
+				.fb = NULL,
+		};
+
+		ret = drm_mode_set_config_internal(&set);
+		if (!ret) {
+			swap_crtc_state(crtc, cstate->state);
+		}
+	}
+
+	return ret;
+}
+
 const struct drm_atomic_funcs drm_atomic_funcs = {
 		.check_plane_state  = drm_plane_check_state,
 		.commit_plane_state = commit_plane_state,
+
+		.check_crtc_state   = drm_crtc_check_state,
+		.commit_crtc_state  = commit_crtc_state,
 };
 EXPORT_SYMBOL(drm_atomic_funcs);
drivers/gpu/drm/drm_crtc.c +384 -214
index b556a31..e14d517 100644
@@ -689,10 +689,7 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
 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));
 
@@ -712,7 +709,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 	 * in this manner.
 	 */
 	if (atomic_read(&fb->refcount.refcount) > 1) {
-		void *state;
+		struct drm_atomic_state *state;
 
 		state = dev->driver->atomic_begin(dev, 0);
 		if (IS_ERR(state)) {
@@ -720,24 +717,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 			return;
 		}
 
-		/* TODO once CRTC is converted to state/properties, we can push the
-		 * locking down into drm_atomic_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->primary->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);
-			}
-		}
-
+		/* remove from any plane */
 		list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
 			if (plane->fb == fb)
 				drm_plane_force_disable(plane, state);
@@ -750,8 +730,6 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 			dev->driver->atomic_commit(dev, state);
 
 		dev->driver->atomic_end(dev, state);
-
-		drm_modeset_unlock_all(dev);
 	}
 
 	drm_framebuffer_unreference(fb);
@@ -782,9 +760,13 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
 	struct drm_mode_config *config = &dev->mode_config;
 	int ret;
 
+	/* this is now required: */
+	WARN_ON(!funcs->set_property);
+
 	crtc->dev = dev;
 	crtc->funcs = funcs;
-	crtc->invert_dimensions = false;
+	crtc->state = drm_crtc_create_state(crtc);
+	crtc->state->invert_dimensions = false;
 
 	drm_modeset_lock_all(dev);
 	drm_modeset_lock_init(&crtc->mutex);
@@ -796,14 +778,17 @@ int drm_crtc_init_with_planes(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++;
 
 	crtc->primary = primary;
 	if (primary)
-		primary->possible_crtcs = 1 << drm_crtc_index(crtc);
+		primary->possible_crtcs = 1 << crtc->id;
+
+	drm_object_attach_property(&crtc->base, config->prop_mode, 0);
+	drm_object_attach_property(&crtc->base, config->prop_connector_ids, 0);
 
  out:
 	drm_modeset_unlock_all(dev);
@@ -832,31 +817,245 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
 	drm_mode_object_put(dev, &crtc->base);
 	list_del(&crtc->head);
 	dev->mode_config.num_crtc--;
+
+	drm_crtc_destroy_state(crtc, crtc->state);
 }
 EXPORT_SYMBOL(drm_crtc_cleanup);
 
-/**
- * drm_crtc_index - find the index of a registered CRTC
- * @crtc: CRTC to find index for
- *
- * Given a registered CRTC, return the index of that CRTC within a DRM
- * device's list of CRTCs.
- */
-unsigned int drm_crtc_index(struct drm_crtc *crtc)
+/* get display-mode from user-mode */
+struct drm_display_mode *drm_crtc_get_mode(struct drm_crtc *crtc,
+		struct drm_crtc_state *cstate)
 {
-	unsigned int index = 0;
-	struct drm_crtc *tmp;
+	struct drm_display_mode *mode = NULL;
+	if (cstate->mode_valid) {
+		struct drm_device *dev = crtc->dev;
+		int ret;
 
-	list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) {
-		if (tmp == crtc)
-			return index;
+		mode = drm_mode_create(dev);
+		if (!mode)
+			return ERR_PTR(-ENOMEM);
+
+		ret = drm_crtc_convert_umode(mode, &cstate->mode);
+		if (ret) {
+			DRM_DEBUG_KMS("Invalid mode\n");
+			drm_mode_destroy(dev, mode);
+			return ERR_PTR(ret);
+		}
 
-		index++;
+		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
 	}
+	return mode;
+}
 
-	BUG();
+static int connector_idx(struct drm_crtc_state *state,
+		uint32_t connector_id)
+{
+	int i;
+	for (i = 0; i < state->num_connector_ids; i++)
+		if (state->connector_ids[i] == connector_id)
+			return i;
+	return -1;
+}
+
+static int remove_connector(struct drm_crtc *ocrtc,
+		struct drm_crtc_state *ostate, struct drm_atomic_state *state,
+		int idx)
+{
+	struct drm_mode_config *config = &ocrtc->dev->mode_config;
+	uint32_t *new_connector_ids;
+	int a, b;
+
+	/* before deletion point: */
+	a = idx * sizeof(ostate->connector_ids[0]);
+
+	/* after deletion point: */
+	b = (ostate->num_connector_ids - 1 - idx) *
+			sizeof(ostate->connector_ids[0]);
+
+	new_connector_ids = kmalloc(a+b, GFP_KERNEL);
+	if (!new_connector_ids)
+		return -ENOMEM;
+
+	memcpy(new_connector_ids, ostate->connector_ids, a);
+	memcpy(&new_connector_ids[idx],
+			&ostate->connector_ids[idx + 1], b);
+
+	return drm_mode_crtc_set_obj_prop(ocrtc, state,
+		config->prop_connector_ids, a + b,
+		new_connector_ids);
 }
-EXPORT_SYMBOL(drm_crtc_index);
+
+static int check_connectors(struct drm_crtc *crtc,
+		struct drm_atomic_state *state, bool fix,
+		uint32_t *connector_ids, uint32_t num_connector_ids)
+{
+	struct drm_mode_config *config = &crtc->dev->mode_config;
+	struct drm_crtc *ocrtc; /* other connector */
+
+	list_for_each_entry(ocrtc, &config->crtc_list, head) {
+		struct drm_crtc_state *ostate; /* other state */
+		unsigned i;
+
+		if (ocrtc == crtc)
+			continue;
+
+		ostate = drm_atomic_get_crtc_state(crtc, state);
+		if (IS_ERR(ostate))
+			return PTR_ERR(ostate);
+
+		for (i = 0; i < num_connector_ids; i++) {
+			struct drm_connector *connector;
+			uint32_t cid = connector_ids[i];
+			int idx;
+
+retry:
+			idx = connector_idx(ostate, cid);
+			if (idx < 0)
+				continue;
+
+			if (fix) {
+				int ret = remove_connector(ocrtc,
+						ostate, state, idx);
+				if (ret)
+					return ret;
+				goto retry;
+			}
+
+			connector = drm_connector_find(crtc->dev, cid);
+			DRM_DEBUG_KMS("[CONNECTOR:%d:%s] already in use\n",
+					connector->base.id,
+					drm_get_connector_name(connector));
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+int drm_crtc_check_state(struct drm_crtc *crtc,
+		struct drm_crtc_state *state)
+{
+	struct drm_plane *primary = crtc->primary;
+	struct drm_plane_state *pstate =
+			drm_atomic_get_plane_state(primary, state->state);
+	struct drm_framebuffer *fb = pstate->fb;
+	int hdisplay, vdisplay;
+	struct drm_display_mode *mode = drm_crtc_get_mode(crtc, state);
+	unsigned x, y;
+
+	if (IS_ERR(mode))
+		return PTR_ERR(mode);
+
+	/* disabling the crtc is allowed: */
+	if (!(fb && state->mode_valid))
+		return 0;
+
+	hdisplay = state->mode.hdisplay;
+	vdisplay = state->mode.vdisplay;
+
+	if (mode && drm_mode_is_stereo(mode)) {
+		struct drm_display_mode adjusted = *mode;
+
+		drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE);
+		hdisplay = adjusted.crtc_hdisplay;
+		vdisplay = adjusted.crtc_vdisplay;
+	}
+
+	if (state->invert_dimensions)
+		swap(hdisplay, vdisplay);
+
+	x = pstate->src_x >> 16;
+	y = pstate->src_y >> 16;
+
+	if (hdisplay > fb->width ||
+	    vdisplay > fb->height ||
+	    x > fb->width - hdisplay ||
+	    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,
+			      x, y, state->invert_dimensions ? " (inverted)" : "");
+		return -ENOSPC;
+	}
+
+	if (crtc->enabled && !state->set_config) {
+		if (primary->state->fb->pixel_format != fb->pixel_format) {
+			DRM_DEBUG_KMS("Page flip is not allowed to "
+					"change frame buffer format.\n");
+			return -EINVAL;
+		}
+	}
+
+	if (state->num_connector_ids == 0) {
+		DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
+		return -EINVAL;
+	}
+
+	if (state->connectors_change) {
+		int ret = check_connectors(crtc, state->state, false,
+				state->connector_ids, state->num_connector_ids);
+		if (ret)
+			return ret;
+	}
+
+	if (mode)
+		drm_mode_destroy(crtc->dev, mode);
+
+	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;
+
+	/* grab primary plane state now, to ensure locks are held, etc. */
+	drm_atomic_get_plane_state(crtc->primary, state->state);
+
+	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_mode_modeinfo))
+				return -EINVAL;
+			state->mode = *(struct drm_mode_modeinfo *)blob_data;
+			state->mode_valid = true;
+		}
+		state->set_config = true;
+	} else if (property == config->prop_connector_ids) {
+		/* if connector-id's changing, we need to have all the locks: */
+		struct drm_atomic_state *a = state->state;
+		int ret = drm_modeset_lock_all_crtcs(crtc->dev, &a->acquire_ctx);
+		if (ret)
+			return ret;
+		state->connectors_change = true;
+		state->num_connector_ids = value / sizeof(state->connector_ids[0]);
+		kfree(state->connector_ids);
+		state->connector_ids = blob_data;
+		state->set_config = true;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_crtc_set_property);
 
 /*
  * drm_mode_remove - remove and free a mode
@@ -1239,6 +1438,10 @@ int drm_plane_check_state(struct drm_plane *plane,
 	if (!fb)
 		return 0;
 
+	/* we'll need this later during commit: */
+	if (state->crtc)
+		drm_atomic_get_crtc_state(state->crtc, state->state);
+
 	fb_width = fb->width << 16;
 	fb_height = fb->height << 16;
 
@@ -1465,6 +1668,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;
 }
 
@@ -1754,7 +1967,7 @@ static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
  * Returns:
  * Zero on success, errno on failure.
  */
-static int drm_crtc_convert_umode(struct drm_display_mode *out,
+int drm_crtc_convert_umode(struct drm_display_mode *out,
 				  const struct drm_mode_modeinfo *in)
 {
 	if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
@@ -2001,8 +2214,8 @@ int drm_mode_getcrtc(struct drm_device *dev,
 		goto out;
 	}
 
-	crtc_resp->x = crtc->x;
-	crtc_resp->y = crtc->y;
+	crtc_resp->x = crtc->primary->state->src_x >> 16;
+	crtc_resp->y = crtc->primary->state->src_y >> 16;
 	crtc_resp->gamma_size = crtc->gamma_size;
 	if (crtc->primary->fb)
 		crtc_resp->fb_id = crtc->primary->fb->base.id;
@@ -2495,7 +2708,7 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc,
 		vdisplay = adjusted.crtc_vdisplay;
 	}
 
-	if (crtc->invert_dimensions)
+	if (crtc->state->invert_dimensions)
 		swap(hdisplay, vdisplay);
 
 	if (hdisplay > fb->width ||
@@ -2504,7 +2717,7 @@ int drm_crtc_check_viewport(const struct drm_crtc *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, x, y,
-			      crtc->invert_dimensions ? " (inverted)" : "");
+			      crtc->state->invert_dimensions ? " (inverted)" : "");
 		return -ENOSPC;
 	}
 
@@ -2531,22 +2744,15 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 	struct drm_mode_config *config = &dev->mode_config;
 	struct drm_mode_crtc *crtc_req = data;
 	struct drm_crtc *crtc;
-	struct drm_connector **connector_set = NULL, *connector;
-	struct drm_framebuffer *fb = NULL;
-	struct drm_display_mode *mode = NULL;
-	struct drm_mode_set set;
-	uint32_t __user *set_connectors_ptr;
+	uint32_t fb_id = -1;
+	uint32_t *connector_ids = NULL;
+	struct drm_atomic_state *state = NULL;
 	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);
 	crtc = drm_crtc_find(dev, crtc_req->crtc_id);
 	if (!crtc) {
 		DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
@@ -2564,55 +2770,15 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 				ret = -EINVAL;
 				goto out;
 			}
-			fb = crtc->primary->fb;
-			/* Make refcounting symmetric with the lookup path. */
-			drm_framebuffer_reference(fb);
+			fb_id = crtc->primary->fb->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 = -ENOENT;
-				goto out;
-			}
-		}
-
-		mode = drm_mode_create(dev);
-		if (!mode) {
-			ret = -ENOMEM;
-			goto out;
+			fb_id = crtc_req->fb_id;
 		}
-
-		ret = drm_crtc_convert_umode(mode, &crtc_req->mode);
-		if (ret) {
-			DRM_DEBUG_KMS("Invalid mode\n");
-			goto out;
-		}
-
-		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
-
-		ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
-					      mode, fb);
-		if (ret)
-			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) {
@@ -2620,52 +2786,65 @@ 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;
 			}
-
-			connector = drm_connector_find(dev, out_id);
-			if (!connector) {
-				DRM_DEBUG_KMS("Connector id %d unknown\n",
-						out_id);
-				ret = -ENOENT;
-				goto out;
-			}
-			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);
+retry:
+	state = dev->driver->atomic_begin(dev, 0);
+	if (IS_ERR(state))
+		return PTR_ERR(state);
 
-out:
-	if (fb)
-		drm_framebuffer_unreference(fb);
+	/* If connectors change, we need to check if we need to steal one
+	 * from another CRTC..  setcrtc makes this implicit, but atomic
+	 * treats it as an error so we need to handle here:
+	 */
+	ret = check_connectors(crtc, state, true,
+		connector_ids, crtc_req->count_connectors);
+	if (ret)
+		goto out;
 
-	kfree(connector_set);
-	drm_mode_destroy(dev, mode);
-	drm_modeset_unlock_all(dev);
+	ret =
+		drm_mode_crtc_set_obj_prop(crtc, state,
+			config->prop_mode, sizeof(crtc_req->mode), &crtc_req->mode) ||
+		drm_mode_crtc_set_obj_prop(crtc, state,
+			config->prop_connector_ids,
+			crtc_req->count_connectors * sizeof(connector_ids[0]),
+			connector_ids) ||
+		drm_mode_plane_set_obj_prop(crtc->primary, state,
+			config->prop_crtc_id, crtc->base.id, NULL) ||
+		drm_mode_plane_set_obj_prop(crtc->primary, state,
+			config->prop_fb_id, fb_id, NULL) ||
+		drm_mode_plane_set_obj_prop(crtc->primary, state,
+			config->prop_src_x, crtc_req->x << 16, NULL) ||
+		drm_mode_plane_set_obj_prop(crtc->primary, state,
+			config->prop_src_y, crtc_req->y << 16, NULL) ||
+		dev->driver->atomic_check(dev, state);
+	if (ret)
+		goto out;
+
+	ret = dev->driver->atomic_commit(dev, state);
+
+out:
+	if (state)
+		dev->driver->atomic_end(dev, state);
+	if (ret == -EDEADLK)
+		goto retry;
 	return ret;
 }
 
@@ -4028,9 +4207,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;
 }
@@ -4424,6 +4600,51 @@ 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);
+}
+
 /**
  * drm_mode_page_flip_ioctl - schedule an asynchronous fb update
  * @dev: DRM device
@@ -4446,10 +4667,10 @@ 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_crtc *crtc;
-	struct drm_framebuffer *fb = NULL, *old_fb = NULL;
 	struct drm_pending_vblank_event *e = NULL;
-	unsigned long flags;
+	struct drm_atomic_state *state;
 	int ret = -EINVAL;
 
 	if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
@@ -4463,92 +4684,41 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 	if (!crtc)
 		return -ENOENT;
 
-	drm_modeset_lock(&crtc->mutex, NULL);
-	if (crtc->primary->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) {
-		ret = -ENOENT;
-		goto out;
-	}
-
-	ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb);
-	if (ret)
-		goto out;
-
-	if (crtc->primary->fb->pixel_format != fb->pixel_format) {
-		DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
-		ret = -EINVAL;
-		goto out;
-	}
+retry:
+	state = dev->driver->atomic_begin(dev,
+			page_flip->flags | DRM_MODE_ATOMIC_NONBLOCK);
+	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, &crtc->base, 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->primary->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->primary->fb != fb);
-		/* Unref only the old framebuffer. */
-		fb = NULL;
-	}
+	ret = drm_mode_plane_set_obj_prop(crtc->primary, 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);
-	drm_modeset_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);
+	if (ret == -EDEADLK)
+		goto retry;
 	return ret;
 }
 
drivers/gpu/drm/drm_fb_helper.c +1 -1
index b73d3b0..4669e69 100644
@@ -286,7 +286,7 @@ 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;
+	struct drm_atomic_state *state;
 	int i;
 
 	drm_warn_on_modeset_not_all_locked(dev);
drivers/gpu/drm/exynos/exynos_drm_crtc.c +6 -1
index 2a56973..f3c7e77 100644
@@ -14,6 +14,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 
 #include "exynos_drm_crtc.h"
 #include "exynos_drm_drv.h"
@@ -289,6 +290,10 @@ static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
 	struct drm_device *dev = crtc->dev;
 	struct exynos_drm_private *dev_priv = dev->dev_private;
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+	struct drm_crtc_state *cstate = drm_atomic_get_crtc_state(crtc, state);
+
+	if (IS_ERR(cstate))
+		return PTR_ERR(cstate);
 
 	if (property == dev_priv->crtc_mode_property) {
 		enum exynos_crtc_mode mode = val;
@@ -313,7 +318,7 @@ static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
 		return 0;
 	}
 
-	return -EINVAL;
+	return drm_crtc_set_property(crtc, cstate, property, val, blob_data);
 }
 
 static struct drm_crtc_funcs exynos_crtc_funcs = {
drivers/gpu/drm/gma500/cdv_intel_display.c +1 -0
index 6672732..5b6eee9 100644
@@ -989,6 +989,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_crtc_set_property,
 	.destroy = gma_crtc_destroy,
 };
 
drivers/gpu/drm/gma500/psb_intel_display.c +1 -0
index 87b50ba..79b5692 100644
@@ -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_crtc_set_property,
 	.destroy = gma_crtc_destroy,
 };
 
drivers/gpu/drm/i915/intel_display.c +1 -0
index e9f6eb7..53b996f 100644
@@ -10430,6 +10430,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_crtc_set_property,
 	.destroy = intel_crtc_destroy,
 	.page_flip = intel_crtc_page_flip,
 };
drivers/gpu/drm/mgag200/mgag200_mode.c +1 -0
index a034ed4..ba9bd91 100644
@@ -1296,6 +1296,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_crtc_set_property,
 	.destroy = mga_crtc_destroy,
 };
 
drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +4 -2
index 7cf0f78..d0d8befd 100644
@@ -471,8 +471,10 @@ static int mdp4_crtc_set_property(struct drm_crtc *crtc,
 		struct drm_atomic_state *state, struct drm_property *property,
 		uint64_t val, void *blob_data)
 {
-	// XXX
-	return -EINVAL;
+	struct drm_crtc_state *cstate = drm_atomic_get_crtc_state(crtc, state);
+	if (IS_ERR(cstate))
+		return PTR_ERR(cstate);
+	return drm_crtc_set_property(crtc, cstate, property, val, blob_data);
 }
 
 #define CURSOR_WIDTH 64
drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +4 -2
index 771390b..7f4ee99 100644
@@ -389,8 +389,10 @@ static int mdp5_crtc_set_property(struct drm_crtc *crtc,
 		struct drm_atomic_state *state, struct drm_property *property,
 		uint64_t val, void *blob_data)
 {
-	// XXX
-	return -EINVAL;
+	struct drm_crtc_state *cstate = drm_atomic_get_crtc_state(crtc, state);
+	if (IS_ERR(cstate))
+		return PTR_ERR(cstate);
+	return drm_crtc_set_property(crtc, cstate, property, val, blob_data);
 }
 
 static const struct drm_crtc_funcs mdp5_crtc_funcs = {
drivers/gpu/drm/nouveau/dispnv04/crtc.c +1 -0
index 41be342..9e24632 100644
@@ -1086,6 +1086,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_crtc_set_property,
 	.page_flip = nouveau_crtc_page_flip,
 	.destroy = nv_crtc_destroy,
 };
drivers/gpu/drm/nouveau/nv50_display.c +1 -0
index 58af547..ecbffeb 100644
@@ -1329,6 +1329,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_crtc_set_property,
 	.destroy = nv50_crtc_destroy,
 	.page_flip = nouveau_crtc_page_flip,
 };
drivers/gpu/drm/omapdrm/omap_crtc.c +10 -2
index a75934d..772687b 100644
@@ -387,14 +387,22 @@ static int omap_crtc_set_property(struct drm_crtc *crtc,
 {
 	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 (IS_ERR(cstate))
+		return PTR_ERR(cstate);
 
 	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 = {
drivers/gpu/drm/omapdrm/omap_drv.c +1 -1
index da80bdc..3f64c47 100644
@@ -579,7 +579,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);
 		}
 
drivers/gpu/drm/qxl/qxl_display.c +2 -0
index b54c970..25896a9 100644
@@ -29,6 +29,7 @@
 #include "qxl_drv.h"
 #include "qxl_object.h"
 #include "drm_crtc_helper.h"
+#include "drm_atomic.h"
 
 static bool qxl_head_enabled(struct qxl_head *head)
 {
@@ -373,6 +374,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_crtc_set_property,
 	.destroy = qxl_crtc_destroy,
 };
 
drivers/gpu/drm/radeon/radeon_display.c +2 -0
index 8d99d5e..cc86aac 100644
@@ -32,6 +32,7 @@
 
 #include <linux/pm_runtime.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_edid.h>
 
 #include <linux/gcd.h>
@@ -546,6 +547,7 @@ static const struct drm_crtc_funcs radeon_crtc_funcs = {
 	.cursor_move = radeon_crtc_cursor_move,
 	.gamma_set = radeon_crtc_gamma_set,
 	.set_config = radeon_crtc_set_config,
+	.set_property = drm_atomic_crtc_set_property,
 	.destroy = radeon_crtc_destroy,
 	.page_flip = radeon_crtc_page_flip,
 };
drivers/gpu/drm/rcar-du/rcar_du_crtc.c +2 -0
index 299267d..f5a3d55 100644
@@ -17,6 +17,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -527,6 +528,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_crtc_set_property,
 	.page_flip = rcar_du_crtc_page_flip,
 };
 
drivers/gpu/drm/shmobile/shmob_drm_crtc.c +2 -0
index 90e023a..0a5280c 100644
@@ -17,6 +17,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -506,6 +507,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_crtc_set_property,
 	.page_flip = shmob_drm_crtc_page_flip,
 };
 
drivers/gpu/drm/tilcdc/tilcdc_crtc.c +1 -0
index 92839ba..b07f116 100644
@@ -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_crtc_set_property,
 		.page_flip      = tilcdc_crtc_page_flip,
 };
 
drivers/gpu/drm/udl/udl_modeset.c +2 -0
index cddc4fc..36d0116 100644
@@ -14,6 +14,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.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_crtc_set_property,
 	.destroy = udl_crtc_destroy,
 };
 
drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +1 -0
index b2b9bd2..0313b00 100644
@@ -300,6 +300,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_crtc_set_property,
 	.set_config = vmw_ldu_crtc_set_config,
 };
 
drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +1 -0
index a95d3a0..b723e09 100644
@@ -397,6 +397,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_crtc_set_property,
 	.page_flip = vmw_du_page_flip,
 };
 
include/drm/drm_atomic.h +29 -0
index 78e93ec..7946b7f 100644
@@ -70,6 +70,9 @@
 struct drm_atomic_funcs {
 	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);
+
+	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_funcs drm_atomic_funcs;
@@ -109,6 +112,30 @@ drm_atomic_commit_plane_state(struct drm_plane *plane,
 	return funcs->commit_plane_state(plane, pstate);
 }
 
+int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t val, void *blob_data);
+struct drm_crtc_state *drm_atomic_get_crtc_state(struct drm_crtc *crtc,
+		struct drm_atomic_state *state);
+
+static inline int
+drm_atomic_check_crtc_state(struct drm_crtc *crtc,
+		struct drm_crtc_state *cstate)
+{
+	const struct drm_atomic_funcs *funcs =
+			crtc->dev->driver->atomic_funcs;
+	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_funcs *funcs =
+			crtc->dev->driver->atomic_funcs;
+	return funcs->commit_crtc_state(crtc, cstate);
+}
+
 /**
  * struct drm_atomic_state - the state object used by atomic helpers
  */
@@ -118,6 +145,8 @@ struct drm_atomic_state {
 	uint32_t flags;
 	struct drm_plane **planes;
 	struct drm_plane_state **pstates;
+	struct drm_crtc **crtcs;
+	struct drm_crtc_state **cstates;
 
 	bool committed;
 	bool checked;       /* just for debugging */
include/drm/drm_crtc.h +87 -16
index 58309cc..2fbf13a 100644
@@ -284,6 +284,10 @@ struct drm_crtc_funcs {
 			 struct drm_pending_vblank_event *event,
 			 uint32_t flags);
 
+	struct drm_crtc_state *(*create_state)(struct drm_crtc *crtc);
+	void (*destroy_state)(struct drm_crtc *crtc,
+			    struct drm_crtc_state *cstate);
+
 	int (*set_property)(struct drm_crtc *crtc,
 			    struct drm_atomic_state *state,
 			    struct drm_property *property, uint64_t val,
@@ -291,21 +295,52 @@ 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
+ * @mode_valid: a valid mode has been set
+ * @set_config: needs modeset (crtc->set_config())
+ * @connectors_change: the connector-ids array has changed
+ * @num_connector_ids: the number of connector-ids
+ * @connector_ids: array of connector ids
+ * @mode: current mode timings
+ * @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 mode_valid        : 1;
+
+	/* transient state, only valid during atomic operation: */
+	bool set_config        : 1;
+	bool connectors_change : 1;
+
+	uint8_t num_connector_ids;
+	uint32_t *connector_ids;
+	struct drm_mode_modeinfo mode;
+
+	struct drm_pending_vblank_event *event;
+
+	struct drm_object_property_values propvals;
+
+	struct drm_atomic_state *state;
+};
+
+/**
  * drm_crtc - central CRTC control structure
  * @dev: parent DRM device
  * @head: list management
+ * @id: CRTC number, 0..n
  * @mutex: per-CRTC locking
  * @base: base KMS object for ID tracking etc.
  * @primary: primary plane for this CRTC
  * @cursor: cursor plane for this CRTC
+ * @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
@@ -322,6 +357,8 @@ struct drm_crtc {
 	struct drm_device *dev;
 	struct list_head head;
 
+	int id;
+
 	/**
 	 * crtc mutex
 	 *
@@ -337,23 +374,19 @@ struct drm_crtc {
 	struct drm_plane *primary;
 	struct drm_plane *cursor;
 
+	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. */
 	struct drm_framebuffer *old_fb;
 
 	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 */
@@ -367,9 +400,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:
+	 */
+	int x, y;
+	struct drm_display_mode mode;
+};
 
 /**
  * drm_connector_funcs - control connectors on a given device
@@ -875,6 +914,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;
 	struct drm_property *plane_type_property;
@@ -935,7 +976,8 @@ 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 unsigned int drm_crtc_index(struct drm_crtc *crtc);
+struct drm_display_mode *drm_crtc_get_mode(struct drm_crtc *crtc,
+		struct drm_crtc_state *cstate);
 
 /**
  * drm_crtc_mask - find the mask of a registered CRTC
@@ -946,9 +988,18 @@ extern unsigned int drm_crtc_index(struct drm_crtc *crtc);
  */
 static inline uint32_t drm_crtc_mask(struct drm_crtc *crtc)
 {
-	return 1 << drm_crtc_index(crtc);
+	return 1 << crtc->id;
 }
 
+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);
 extern int drm_connector_init(struct drm_device *dev,
@@ -1024,6 +1075,7 @@ extern const char *drm_get_tv_select_name(int val);
 extern void drm_fb_release(struct drm_file *file_priv);
 extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group);
 extern void drm_mode_group_destroy(struct drm_mode_group *group);
+extern int drm_crtc_convert_umode(struct drm_display_mode *out, const struct drm_mode_modeinfo *in);
 extern bool drm_probe_ddc(struct i2c_adapter *adapter);
 extern struct edid *drm_get_edid(struct drm_connector *connector,
 				 struct i2c_adapter *adapter);
@@ -1251,6 +1303,25 @@ drm_property_blob_find(struct drm_device *dev, uint32_t id)
 	return mo ? obj_to_blob(mo) : NULL;
 }
 
+static inline struct drm_crtc_state *
+drm_crtc_create_state(struct drm_crtc *crtc)
+{
+	if (crtc->funcs->create_state)
+		return crtc->funcs->create_state(crtc);
+	return kzalloc(sizeof(struct drm_crtc_state), GFP_KERNEL);
+}
+
+static inline void
+drm_crtc_destroy_state(struct drm_crtc *crtc,
+		struct drm_crtc_state *cstate)
+{
+	kfree(cstate->connector_ids);
+	if (crtc->funcs->destroy_state)
+		crtc->funcs->destroy_state(crtc, cstate);
+	else
+		kfree(cstate);
+}
+
 static inline struct drm_plane_state *
 drm_plane_create_state(struct drm_plane *plane)
 {
Signature · 1 line
1.9.0
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
author
#36 lore raw

Re: [PATCH 12/17] drm: convert crtc to properties/state

Quoted 20 lines · Daniel Vetter
Quoted 20 lines
drivers/gpu/drm/drm_atomic.c +20 -0
+struct drm_crtc_state *
+drm_atomic_get_crtc_state(struct drm_crtc *crtc, struct drm_atomic_state *a)
+{
+     struct drm_crtc_state *cstate;
+     int ret;
+
+     cstate = a->cstates[crtc->id];
+
+     if (!cstate) {
+             ret = drm_modeset_lock(&crtc->mutex, &a->acquire_ctx);
+             if (ret)
+                     return ERR_PTR(ret);
+
+             cstate = drm_crtc_create_state(crtc);
+             if (!cstate)
+                     return ERR_PTR(-ENOMEM);
+             init_crtc_state(crtc, cstate, a);
+             a->crtcs[crtc->id] = crtc;
+             a->cstates[crtc->id] = cstate;
+
Quoted 8 lines

drivers/gpu/drm/drm_atomic.c commit_plane_state(struct drm_plane *plane, struct drm_plane_state *pstate) · line 589

Quoted 4 lines
drivers/gpu/drm/drm_atomic.c +4 -0
+             /* we'll need it later, so make sure we have state
+              * for primary plane too:
+              */
+             drm_atomic_get_plane_state(crtc->primary, a);

I haven't figured out why. With primary planes I don't really see a need for this. If we need it to implement the legacy setcrtc interface, then that should be done there, not here.

well, if you sort out how to disable primary helper plane, then yes, you are right :-)

see commit_crtc_state()

BR,
-R

#37 lore raw

Re: [PATCH 12/17] drm: convert crtc to properties/state

Quoted 31 lines · Rob Clark
Quoted 20 lines · Daniel Vetter
Quoted 20 lines
drivers/gpu/drm/drm_atomic.c +20 -0
+struct drm_crtc_state *
+drm_atomic_get_crtc_state(struct drm_crtc *crtc, struct drm_atomic_state *a)
+{
+     struct drm_crtc_state *cstate;
+     int ret;
+
+     cstate = a->cstates[crtc->id];
+
+     if (!cstate) {
+             ret = drm_modeset_lock(&crtc->mutex, &a->acquire_ctx);
+             if (ret)
+                     return ERR_PTR(ret);
+
+             cstate = drm_crtc_create_state(crtc);
+             if (!cstate)
+                     return ERR_PTR(-ENOMEM);
+             init_crtc_state(crtc, cstate, a);
+             a->crtcs[crtc->id] = crtc;
+             a->cstates[crtc->id] = cstate;
+
Quoted 8 lines

drivers/gpu/drm/drm_atomic.c commit_plane_state(struct drm_plane *plane, struct drm_plane_state *pstate) · line 589

Quoted 4 lines
drivers/gpu/drm/drm_atomic.c +4 -0
+             /* we'll need it later, so make sure we have state
+              * for primary plane too:
+              */
+             drm_atomic_get_plane_state(crtc->primary, a);

I haven't figured out why. With primary planes I don't really see a need for this. If we need it to implement the legacy setcrtc interface, then that should be done there, not here.

Quoted 4 lines

well, if you sort out how to disable primary helper plane, then yes, you are right :-)

see commit_crtc_state()

Imo bail when we have a crtc with NULL primary plane in crtc_commit (and wont disable the entire crtc ofc).

Also I think your current commit_crtc should be pushed down into the crtc helpers - it's not going to do any good for i915. But I guess until we have a real user of the atomic interface (i.e. updates more than 1 crtc) like the fb helper code we don't need this yet.

But as soon as we update more than one crtc we _must_ push it down into the crtc helpers or the i915 machinery - if you try to enable crtcs which need resources from crtcs which aren't yet off this is simply going to fail.
-Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
author
#38 lore raw

Re: [PATCH 12/17] drm: convert crtc to properties/state

Quoted 37 lines · Daniel Vetter
Quoted 31 lines · Rob Clark
Quoted 20 lines · Daniel Vetter
Quoted 20 lines
drivers/gpu/drm/drm_atomic.c +20 -0
+struct drm_crtc_state *
+drm_atomic_get_crtc_state(struct drm_crtc *crtc, struct drm_atomic_state *a)
+{
+     struct drm_crtc_state *cstate;
+     int ret;
+
+     cstate = a->cstates[crtc->id];
+
+     if (!cstate) {
+             ret = drm_modeset_lock(&crtc->mutex, &a->acquire_ctx);
+             if (ret)
+                     return ERR_PTR(ret);
+
+             cstate = drm_crtc_create_state(crtc);
+             if (!cstate)
+                     return ERR_PTR(-ENOMEM);
+             init_crtc_state(crtc, cstate, a);
+             a->crtcs[crtc->id] = crtc;
+             a->cstates[crtc->id] = cstate;
+
Quoted 8 lines

drivers/gpu/drm/drm_atomic.c commit_plane_state(struct drm_plane *plane, struct drm_plane_state *pstate) · line 589

Quoted 4 lines
drivers/gpu/drm/drm_atomic.c +4 -0
+             /* we'll need it later, so make sure we have state
+              * for primary plane too:
+              */
+             drm_atomic_get_plane_state(crtc->primary, a);

I haven't figured out why. With primary planes I don't really see a need for this. If we need it to implement the legacy setcrtc interface, then that should be done there, not here.

Quoted 4 lines

well, if you sort out how to disable primary helper plane, then yes, you are right :-)

see commit_crtc_state()

Quoted 7 lines

Imo bail when we have a crtc with NULL primary plane in crtc_commit (and wont disable the entire crtc ofc).

Also I think your current commit_crtc should be pushed down into the crtc helpers - it's not going to do any good for i915. But I guess until we have a real user of the atomic interface (i.e. updates more than 1 crtc) like the fb helper code we don't need this yet.

it is in helpers (if we rename drm_atomic_funcs -> drm_atomic_helper_funcs, which is basically what it is).

I suspect what you actually want is to split up atomic_commit() so you can do the loop over all the planes and crtcs internally.

BR,
-R

Quoted 9 lines

But as soon as we update more than one crtc we _must_ push it down into the crtc helpers or the i915 machinery - if you try to enable crtcs which need resources from crtcs which aren't yet off this is simply going to fail.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

#39 lore raw

Re: [PATCH 12/17] drm: convert crtc to properties/state

In reply to Daniel Vetter
Quoted 155 lines · Daniel Vetter
Quoted 10 lines · Rob Clark

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.

Same comments about interface design as for the plane patch apply here. One additional comment below.

Quoted 140 lines
---
 drivers/gpu/drm/armada/armada_crtc.c       |  11 +-
 drivers/gpu/drm/ast/ast_mode.c             |   1 +
 drivers/gpu/drm/cirrus/cirrus_mode.c       |   1 +
 drivers/gpu/drm/drm_atomic.c               | 231 ++++++++++-
 drivers/gpu/drm/drm_crtc.c                 | 598 ++++++++++++++++++-----------
 drivers/gpu/drm/drm_fb_helper.c            |   2 +-
 drivers/gpu/drm/exynos/exynos_drm_crtc.c   |   7 +-
 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/mdp/mdp4/mdp4_crtc.c   |   6 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c   |   6 +-
 drivers/gpu/drm/nouveau/dispnv04/crtc.c    |   1 +
 drivers/gpu/drm/nouveau/nv50_display.c     |   1 +
 drivers/gpu/drm/omapdrm/omap_crtc.c        |  12 +-
 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 +
 include/drm/drm_atomic.h                   |  29 ++
 include/drm/drm_crtc.h                     | 103 ++++-
 27 files changed, 785 insertions(+), 243 deletions(-)
drivers/gpu/drm/armada/armada_crtc.c +10 -1
index 7d3c649..6237af4 100644
@@ -9,6 +9,7 @@
 #include <linux/clk.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include "armada_crtc.h"
 #include "armada_drm.h"
 #include "armada_fb.h"
@@ -966,7 +967,12 @@ armada_drm_crtc_set_property(struct drm_crtc *crtc,
 {
 	struct armada_private *priv = crtc->dev->dev_private;
 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
+	struct drm_crtc_state *cstate = drm_atomic_get_crtc_state(crtc, state);
 	bool update_csc = false;
+	int ret = 0;
+
+	if (IS_ERR(cstate))
+		return PTR_ERR(cstate);
 
 	if (property == priv->csc_yuv_prop) {
 		dcrtc->csc_yuv_mode = val;
@@ -974,6 +980,9 @@ armada_drm_crtc_set_property(struct drm_crtc *crtc,
 	} else if (property == priv->csc_rgb_prop) {
 		dcrtc->csc_rgb_mode = val;
 		update_csc = true;
+	} else {
+		ret = drm_crtc_set_property(crtc, cstate, property,
+				val, blob_data);
 	}
 
 	if (update_csc) {
@@ -984,7 +993,7 @@ armada_drm_crtc_set_property(struct drm_crtc *crtc,
 		writel_relaxed(val, dcrtc->base + LCD_SPU_IOPAD_CONTROL);
 	}
 
-	return 0;
+	return ret;
 }
 
 static struct drm_crtc_funcs armada_crtc_funcs = {
drivers/gpu/drm/ast/ast_mode.c +1 -0
index 114aee9..c08e0e1 100644
@@ -632,6 +632,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_crtc_set_property,
 	.gamma_set = ast_crtc_gamma_set,
 	.destroy = ast_crtc_destroy,
 };
drivers/gpu/drm/cirrus/cirrus_mode.c +1 -0
index 49332c5..3c4428c 100644
@@ -366,6 +366,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_crtc_set_property,
 	.destroy = cirrus_crtc_destroy,
 };
 
drivers/gpu/drm/drm_atomic.c +14 -1
index 403ffc5..863a0fe 100644
@@ -48,11 +48,13 @@ struct drm_atomic_state *drm_atomic_begin(struct drm_device *dev,
 {
 	struct drm_atomic_state *state;
 	int nplanes = dev->mode_config.num_total_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);
 
@@ -74,6 +76,12 @@ struct drm_atomic_state *drm_atomic_begin(struct drm_device *dev,
 	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_begin);
@@ -92,7 +100,18 @@ int drm_atomic_set_event(struct drm_device *dev,
 		struct drm_atomic_state *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);
+		if (IS_ERR(cstate))
+			return PTR_ERR(cstate);
Quoted 8 lines

drivers/gpu/drm/drm_atomic.c int drm_atomic_set_event(struct drm_device *dev, · line 114

Quoted 6 lines
drivers/gpu/drm/drm_atomic.c +6 -0
+		cstate->event = event;
+		return 0;
+	}
+	default:
+		return -EINVAL;
+	}

Hm, I think if we only want completion events on crtcs (which I agree on)

I don't. Unless you have a nice way of passing some kind of "fbs now available for rendering" list back to userland in the single crtc event. Last time I looked making the drm event stuff deal with variable length events looked more painful than just adding per plane events. But I must admit that I didn't really try to do it.

Signature · 2 lines
Ville Syrjälä
Intel OTC
#40 lore raw

Re: [PATCH 12/17] drm: convert crtc to properties/state

Quoted 22 lines · Ville Syrjälä
Quoted 12 lines · Daniel Vetter
Quoted 11 lines · Rob Clark
drivers/gpu/drm/drm_atomic.c +6 -1
@@ -92,7 +100,18 @@ int drm_atomic_set_event(struct drm_device *dev,
 		struct drm_atomic_state *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);
+		if (IS_ERR(cstate))
+			return PTR_ERR(cstate);
Quoted 8 lines

drivers/gpu/drm/drm_atomic.c int drm_atomic_set_event(struct drm_device *dev, · line 114

Quoted 6 lines
drivers/gpu/drm/drm_atomic.c +6 -0
+		cstate->event = event;
+		return 0;
+	}
+	default:
+		return -EINVAL;
+	}

Hm, I think if we only want completion events on crtcs (which I agree on)

Quoted 5 lines

I don't. Unless you have a nice way of passing some kind of "fbs now available for rendering" list back to userland in the single crtc event. Last time I looked making the drm event stuff deal with variable length events looked more painful than just adding per plane events. But I must admit that I didn't really try to do it.

Hm, why can't userspace keep a list of fb ids involved in a given crtc pageflip around and index those with the cookie we pass around?

I really don't see why the kernel has to implement a half-baked event multiplexer (which just copies the same thing n times), while userspace is perfectly capable of doing that itself?

Now if the timestamps would be genuinely different then I'd agree, but then that's not an atomic update.
-Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
author
#41 lore raw

Re: [PATCH 12/17] drm: convert crtc to properties/state

Quoted 32 lines · Daniel Vetter
Quoted 22 lines · Ville Syrjälä
Quoted 12 lines · Daniel Vetter
Quoted 11 lines · Rob Clark
drivers/gpu/drm/drm_atomic.c +6 -1
@@ -92,7 +100,18 @@ int drm_atomic_set_event(struct drm_device *dev,
          struct drm_atomic_state *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);
+         if (IS_ERR(cstate))
+                 return PTR_ERR(cstate);
Quoted 8 lines

drivers/gpu/drm/drm_atomic.c int drm_atomic_set_event(struct drm_device *dev, · line 114

Quoted 6 lines
drivers/gpu/drm/drm_atomic.c +6 -0
+         cstate->event = event;
+         return 0;
+ }
+ default:
+         return -EINVAL;
+ }

Hm, I think if we only want completion events on crtcs (which I agree on)

Quoted 5 lines

I don't. Unless you have a nice way of passing some kind of "fbs now available for rendering" list back to userland in the single crtc event. Last time I looked making the drm event stuff deal with variable length events looked more painful than just adding per plane events. But I must admit that I didn't really try to do it.

Hm, why can't userspace keep a list of fb ids involved in a given crtc pageflip around and index those with the cookie we pass around?

Quoted 6 lines

I really don't see why the kernel has to implement a half-baked event multiplexer (which just copies the same thing n times), while userspace is perfectly capable of doing that itself?

Now if the timestamps would be genuinely different then I'd agree, but then that's not an atomic update.

I do kinda think userspace would want to know somehow if an fb is going to be really late and explicitly submit an older fb. If you were resizing, for example, I don't think the driver could make the call to leave one plane displaying an older fb.

But I do think we can bikeshed about that in parallel with getting the inital atomic infrastructure merged.

BR,
-R

Quoted 5 lines

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

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel

#42 lore raw

Re: [PATCH 12/17] drm: convert crtc to properties/state

In reply to Daniel Vetter
Quoted 32 lines · Daniel Vetter
Quoted 22 lines · Ville Syrjälä
Quoted 12 lines · Daniel Vetter
Quoted 11 lines · Rob Clark
drivers/gpu/drm/drm_atomic.c +6 -1
@@ -92,7 +100,18 @@ int drm_atomic_set_event(struct drm_device *dev,
 		struct drm_atomic_state *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);
+		if (IS_ERR(cstate))
+			return PTR_ERR(cstate);
Quoted 8 lines

drivers/gpu/drm/drm_atomic.c int drm_atomic_set_event(struct drm_device *dev, · line 114

Quoted 6 lines
drivers/gpu/drm/drm_atomic.c +6 -0
+		cstate->event = event;
+		return 0;
+	}
+	default:
+		return -EINVAL;
+	}

Hm, I think if we only want completion events on crtcs (which I agree on)

Quoted 5 lines

I don't. Unless you have a nice way of passing some kind of "fbs now available for rendering" list back to userland in the single crtc event. Last time I looked making the drm event stuff deal with variable length events looked more painful than just adding per plane events. But I must admit that I didn't really try to do it.

Hm, why can't userspace keep a list of fb ids involved in a given crtc pageflip around and index those with the cookie we pass around?

Quoted 6 lines

I really don't see why the kernel has to implement a half-baked event multiplexer (which just copies the same thing n times), while userspace is perfectly capable of doing that itself?

Now if the timestamps would be genuinely different then I'd agree, but then that's not an atomic update.

User space can't do it if flips get issued faster than the vrefresh rate. I still want my "moar fps" triple buffering mode.

Signature · 2 lines
Ville Syrjälä
Intel OTC
#43 lore raw

Re: [PATCH 12/17] drm: convert crtc to properties/state

Quoted 37 lines · Ville Syrjälä
Quoted 36 lines · Daniel Vetter
Quoted 22 lines · Ville Syrjälä
Quoted 12 lines · Daniel Vetter
Quoted 11 lines · Rob Clark
drivers/gpu/drm/drm_atomic.c +6 -1
@@ -92,7 +100,18 @@ int drm_atomic_set_event(struct drm_device *dev,
 		struct drm_atomic_state *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);
+		if (IS_ERR(cstate))
+			return PTR_ERR(cstate);
Quoted 8 lines

drivers/gpu/drm/drm_atomic.c int drm_atomic_set_event(struct drm_device *dev, · line 114

Quoted 6 lines
drivers/gpu/drm/drm_atomic.c +6 -0
+		cstate->event = event;
+		return 0;
+	}
+	default:
+		return -EINVAL;
+	}

Hm, I think if we only want completion events on crtcs (which I agree on)

Quoted 5 lines

I don't. Unless you have a nice way of passing some kind of "fbs now available for rendering" list back to userland in the single crtc event. Last time I looked making the drm event stuff deal with variable length events looked more painful than just adding per plane events. But I must admit that I didn't really try to do it.

Hm, why can't userspace keep a list of fb ids involved in a given crtc pageflip around and index those with the cookie we pass around?

I really don't see why the kernel has to implement a half-baked event multiplexer (which just copies the same thing n times), while userspace is perfectly capable of doing that itself?

Quoted 5 lines
Quoted 2 lines

Now if the timestamps would be genuinely different then I'd agree, but then that's not an atomic update.

User space can't do it if flips get issued faster than the vrefresh rate. I still want my "moar fps" triple buffering mode.

Hm right, I forget about this every time it comes up. Imo we should postpone this to when it actually gets implemented - usualy preemptive generalism just ends up hurting everyone for now real good. For the current logic we could ditch all the indirection and callbacks really and simply require that the ->commit hook sends out the crtc even if it's there.

And even if we add per-plane events we don't need new hooks imo. Just adding an event pointer to the plane state structure and firing off those events together with the crtc one in drivers should be good enough.

The proposed set_event callback plus implementation otoh are serious overkill.
-Daniel

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