drm/atomic: Add current-mode blob to CRTC state
authorDaniel Stone <daniels@collabora.com>
Mon, 25 May 2015 18:11:51 +0000 (19:11 +0100)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Tue, 26 May 2015 13:50:38 +0000 (15:50 +0200)
Add a blob property tracking the current mode to the CRTC state, and
ensure it is properly updated and referenced.

v2: Continue using crtc_state->mode inside getcrtc, instead of reading
    out the mode blob. Use IS_ERR and PTR_ERR from create_blob. Move
    set_mode_prop_for_crtc to later patch where it actually gets used.
    Enforce !!state->enable == !!state->mode_blob inside
    drm_atomic_crtc_check.

Signed-off-by: Daniel Stone <daniels@collabora.com>
Tested-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
include/drm/drm_crtc.h

index e749287390a3ad957681e9165d5d0884e86bd887..327ccc71012f4d9ea01cf74918cc53baf5610e13 100644 (file)
@@ -304,11 +304,25 @@ EXPORT_SYMBOL(drm_atomic_get_crtc_state);
 int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
                                 struct drm_display_mode *mode)
 {
+       struct drm_mode_modeinfo umode;
+
        /* Early return for no change. */
        if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0)
                return 0;
 
+       if (state->mode_blob)
+               drm_property_unreference_blob(state->mode_blob);
+       state->mode_blob = NULL;
+
        if (mode) {
+               drm_mode_convert_to_umode(&umode, mode);
+               state->mode_blob =
+                       drm_property_create_blob(state->crtc->dev,
+                                                sizeof(umode),
+                                                &umode);
+               if (IS_ERR(state->mode_blob))
+                       return PTR_ERR(state->mode_blob);
+
                drm_mode_copy(&state->mode, mode);
                state->enable = true;
                DRM_DEBUG_ATOMIC("Set [MODE:%s] for CRTC state %p\n",
@@ -324,7 +338,6 @@ int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
 }
 EXPORT_SYMBOL(drm_atomic_set_mode_for_crtc);
 
-
 /**
  * drm_atomic_crtc_set_property - set property on CRTC
  * @crtc: the drm CRTC to set a property on
@@ -410,6 +423,23 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
                return -EINVAL;
        }
 
+       /* The state->enable vs. state->mode_blob checks can be WARN_ON,
+        * as this is a kernel-internal detail that userspace should never
+        * be able to trigger. */
+       if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) &&
+           WARN_ON(state->enable && !state->mode_blob)) {
+               DRM_DEBUG_ATOMIC("[CRTC:%d] enabled without mode blob\n",
+                                crtc->base.id);
+               return -EINVAL;
+       }
+
+       if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) &&
+           WARN_ON(!state->enable && state->mode_blob)) {
+               DRM_DEBUG_ATOMIC("[CRTC:%d] disabled with mode blob\n",
+                                crtc->base.id);
+               return -EINVAL;
+       }
+
        return 0;
 }
 
index e69d4847e237309ccdf5b64bd8cc1ea7408e4b06..a900858fa2657c8dabbd81fb1ec19ab59e2af4ac 100644 (file)
@@ -2044,6 +2044,8 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_dpms);
  */
 void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
 {
+       if (crtc->state && crtc->state->mode_blob)
+               drm_property_unreference_blob(crtc->state->mode_blob);
        kfree(crtc->state);
        crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
 
@@ -2065,6 +2067,8 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
 {
        memcpy(state, crtc->state, sizeof(*state));
 
+       if (state->mode_blob)
+               drm_property_reference_blob(state->mode_blob);
        state->mode_changed = false;
        state->active_changed = false;
        state->planes_changed = false;
@@ -2107,11 +2111,8 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
 void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
                                            struct drm_crtc_state *state)
 {
-       /*
-        * This is currently a placeholder so that drivers that subclass the
-        * state will automatically do the right thing if code is ever added
-        * to this function.
-        */
+       if (state->mode_blob)
+               drm_property_unreference_blob(state->mode_blob);
 }
 EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
 
index 72b60dbe08914137cd18e86000d70a80d1415602..c54fa4add79254f70929f3a57f4671f57b9ca73f 100644 (file)
@@ -299,6 +299,9 @@ struct drm_crtc_state {
 
        struct drm_display_mode mode;
 
+       /* blob property to expose current mode to atomic userspace */
+       struct drm_property_blob *mode_blob;
+
        struct drm_pending_vblank_event *event;
 
        struct drm_atomic_state *state;