Enforce the existing rules on when modes can be modified (never modify
the passed-in mode; only modify adjusted_mode in mode_fixup), by
adding const.

This requires duplicating the existing crtc_info->modeset->mode member
in the fb_helper, to keep a non-const version to free later.

Signed-off-by: Daniel Stone <daniels at collabora.com>
---
 drivers/gpu/drm/drm_fb_helper.c      | 27 +++++++++++++++++++--------
 drivers/gpu/drm/i915/intel_fbdev.c   |  4 ++++
 drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c  |  2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c |  4 ++--
 include/drm/drm_crtc.h               |  2 +-
 include/drm/drm_fb_helper.h          |  3 +++
 6 files changed, 30 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 27f5617..71e2420 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -579,8 +579,9 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper 
*helper)
        kfree(helper->connector_info);
        for (i = 0; i < helper->crtc_count; i++) {
                kfree(helper->crtc_info[i].mode_set.connectors);
-               if (helper->crtc_info[i].mode_set.mode)
-                       drm_mode_destroy(helper->dev, 
helper->crtc_info[i].mode_set.mode);
+               if (helper->crtc_info[i].mode)
+                       drm_mode_destroy(helper->dev,
+                                        helper->crtc_info[i].mode);
        }
        kfree(helper->crtc_info);
 }
@@ -1525,11 +1526,17 @@ retry:
                        DRM_DEBUG_KMS("looking for preferred mode on connector 
%d %d\n",
                                      fb_helper_conn->connector->base.id, 
fb_helper_conn->connector->tile_group ? 
fb_helper_conn->connector->tile_group->id : 0);
                        modes[i] = drm_has_preferred_mode(fb_helper_conn, 
width, height);
+                       if (modes[i])
+                               modes[i] = drm_mode_duplicate(fb_helper->dev,
+                                                             modes[i]);
                }
                /* No preferred modes, pick one off the list */
                if (!modes[i] && 
!list_empty(&fb_helper_conn->connector->modes)) {
                        list_for_each_entry(modes[i], 
&fb_helper_conn->connector->modes, head)
                                break;
+                       if (modes[i])
+                               modes[i] = drm_mode_duplicate(fb_helper->dev,
+                                                             modes[i]);
                }
                DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
                          "none");
@@ -1695,10 +1702,11 @@ static void drm_setup_crtcs(struct drm_fb_helper 
*fb_helper)
                        fb_crtc->desired_mode = mode;
                        fb_crtc->x = offset->x;
                        fb_crtc->y = offset->y;
-                       if (modeset->mode)
-                               drm_mode_destroy(dev, modeset->mode);
-                       modeset->mode = drm_mode_duplicate(dev,
+                       if (fb_crtc->mode)
+                               drm_mode_destroy(dev, fb_crtc->mode);
+                       fb_crtc->mode = drm_mode_duplicate(dev,
                                                           
fb_crtc->desired_mode);
+                       modeset->mode = fb_crtc->mode;
                        modeset->connectors[modeset->num_connectors++] = 
fb_helper->connector_info[i]->connector;
                        modeset->fb = fb_helper->fb;
                        modeset->x = offset->x;
@@ -1708,11 +1716,14 @@ static void drm_setup_crtcs(struct drm_fb_helper 
*fb_helper)

        /* Clear out any old modes if there are no more connected outputs. */
        for (i = 0; i < fb_helper->crtc_count; i++) {
-               modeset = &fb_helper->crtc_info[i].mode_set;
+               struct drm_fb_helper_crtc *fb_crtc = &fb_helper->crtc_info[i];
+
+               modeset = &fb_crtc->mode_set;
                if (modeset->num_connectors == 0) {
                        BUG_ON(modeset->fb);
-                       if (modeset->mode)
-                               drm_mode_destroy(dev, modeset->mode);
+                       if (fb_crtc->mode)
+                               drm_mode_destroy(dev, fb_crtc->mode);
+                       fb_crtc->mode = NULL;
                        modeset->mode = NULL;
                }
        }
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c 
b/drivers/gpu/drm/i915/intel_fbdev.c
index 757c0d2..83566e0 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -471,6 +471,10 @@ retry:
                                                    
to_intel_crtc(encoder->crtc)->config);
                        modes[i] = &encoder->crtc->hwmode;
                }
+
+               if (modes[i])
+                       modes[i] =
+                               drm_mode_duplicate(encoder->crtc->dev, 
modes[i]);
                crtcs[i] = new_crtc;

                DRM_DEBUG_KMS("connector %s on pipe %c [CRTC:%d]: %dx%d%s\n",
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index 5c289f7..3c231b2 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -212,7 +212,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
        struct vmw_private *dev_priv;
        struct vmw_legacy_display_unit *ldu;
        struct drm_connector *connector;
-       struct drm_display_mode *mode;
+       const struct drm_display_mode *mode;
        struct drm_encoder *encoder;
        struct vmw_framebuffer *vfb;
        struct drm_framebuffer *fb;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index 7dc591d..213afa5 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -104,7 +104,7 @@ static void vmw_sou_add_active(struct vmw_private *vmw_priv,
 static int vmw_sou_fifo_create(struct vmw_private *dev_priv,
                               struct vmw_screen_object_unit *sou,
                               uint32_t x, uint32_t y,
-                              struct drm_display_mode *mode)
+                              const struct drm_display_mode *mode)
 {
        size_t fifo_size;

@@ -254,7 +254,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
        struct vmw_private *dev_priv;
        struct vmw_screen_object_unit *sou;
        struct drm_connector *connector;
-       struct drm_display_mode *mode;
+       const struct drm_display_mode *mode;
        struct drm_encoder *encoder;
        struct vmw_framebuffer *vfb;
        struct drm_framebuffer *fb;
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index dbc1510..7b141d837 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -961,7 +961,7 @@ struct drm_atomic_state {
 struct drm_mode_set {
        struct drm_framebuffer *fb;
        struct drm_crtc *crtc;
-       struct drm_display_mode *mode;
+       const struct drm_display_mode *mode;

        uint32_t x;
        uint32_t y;
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 0dfd94def..e6a4b8c 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -40,6 +40,9 @@ struct drm_fb_offset {

 struct drm_fb_helper_crtc {
        struct drm_mode_set mode_set;
+       /* mode here is a duplicate of mode_set.mode, but non-const so we
+        * can later free it */
+       struct drm_display_mode *mode;
        struct drm_display_mode *desired_mode;
        int x, y;
 };
-- 
2.3.2

Reply via email to