@@ -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;
}
}
@@ -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",
@@ -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;
@@ -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;
@@ -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;
@@ -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;
};
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@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(-)