aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2016-10-26 10:41:18 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2016-10-26 12:52:42 -0400
commita2889606636d135148de101fe3311dfea67baf1c (patch)
treecbe6f38f1f4384b9c3bdc9b6786c3ea78d866f38
parent38d868e41c4b9250d5a115c049dc2d48f4909581 (diff)
drm/fb-helper: Keep references for the current set of used connectors
The fbdev helper code keeps around two lists of connectors. One is the list of all connectors it could use, and that list already holds references for all the connectors. However the other list, or rather lists, is the one actively being used. That list is tracked per-crtc and currently doesn't hold any extra references. Let's grab those extra references to avoid oopsing when the connector vanishes. The list of all possible connectors should get updated when the hpd happens, but the list of actively used connectors would not get updated until the next time the fb-helper picks through the set of possible connectors. And so we need to hang on to the connectors until that time. Since we need to clean up in drm_fb_helper_crtc_free() as well, let's pull the code to a common place. And while at it let's pull in up the modeset->mode cleanup in there as well. The case of modeset->fb is a bit less clear. I'm thinking we should probably hold a reference to it, but for now I just slapped on a FIXME. v2: Cleanup things drm_fb_helper_crtc_free() too (Chris) v3: Don't leak modeset->connectors (Chris) Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: stable@vger.kernel.org Cc: Carlos Santa <carlos.santa@intel.com> Cc: Kirill A. Shutemov <kirill@shutemov.name> Tested-by: Carlos Santa <carlos.santa@intel.com> (v1) Tested-by: Kirill A. Shutemov <kirill@shutemov.name> (v1) Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=97666 Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: http://patchwork.freedesktop.org/patch/msgid/1477492878-4990-1-git-send-email-ville.syrjala@linux.intel.com
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c57
1 files changed, 33 insertions, 24 deletions
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index efaccc2e1b4c..6c75e62c0b22 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -608,6 +608,24 @@ int drm_fb_helper_blank(int blank, struct fb_info *info)
608} 608}
609EXPORT_SYMBOL(drm_fb_helper_blank); 609EXPORT_SYMBOL(drm_fb_helper_blank);
610 610
611static void drm_fb_helper_modeset_release(struct drm_fb_helper *helper,
612 struct drm_mode_set *modeset)
613{
614 int i;
615
616 for (i = 0; i < modeset->num_connectors; i++) {
617 drm_connector_unreference(modeset->connectors[i]);
618 modeset->connectors[i] = NULL;
619 }
620 modeset->num_connectors = 0;
621
622 drm_mode_destroy(helper->dev, modeset->mode);
623 modeset->mode = NULL;
624
625 /* FIXME should hold a ref? */
626 modeset->fb = NULL;
627}
628
611static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper) 629static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
612{ 630{
613 int i; 631 int i;
@@ -617,10 +635,12 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
617 kfree(helper->connector_info[i]); 635 kfree(helper->connector_info[i]);
618 } 636 }
619 kfree(helper->connector_info); 637 kfree(helper->connector_info);
638
620 for (i = 0; i < helper->crtc_count; i++) { 639 for (i = 0; i < helper->crtc_count; i++) {
621 kfree(helper->crtc_info[i].mode_set.connectors); 640 struct drm_mode_set *modeset = &helper->crtc_info[i].mode_set;
622 if (helper->crtc_info[i].mode_set.mode) 641
623 drm_mode_destroy(helper->dev, helper->crtc_info[i].mode_set.mode); 642 drm_fb_helper_modeset_release(helper, modeset);
643 kfree(modeset->connectors);
624 } 644 }
625 kfree(helper->crtc_info); 645 kfree(helper->crtc_info);
626} 646}
@@ -2095,7 +2115,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
2095 struct drm_fb_helper_crtc **crtcs; 2115 struct drm_fb_helper_crtc **crtcs;
2096 struct drm_display_mode **modes; 2116 struct drm_display_mode **modes;
2097 struct drm_fb_offset *offsets; 2117 struct drm_fb_offset *offsets;
2098 struct drm_mode_set *modeset;
2099 bool *enabled; 2118 bool *enabled;
2100 int width, height; 2119 int width, height;
2101 int i; 2120 int i;
@@ -2143,45 +2162,35 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
2143 2162
2144 /* need to set the modesets up here for use later */ 2163 /* need to set the modesets up here for use later */
2145 /* fill out the connector<->crtc mappings into the modesets */ 2164 /* fill out the connector<->crtc mappings into the modesets */
2146 for (i = 0; i < fb_helper->crtc_count; i++) { 2165 for (i = 0; i < fb_helper->crtc_count; i++)
2147 modeset = &fb_helper->crtc_info[i].mode_set; 2166 drm_fb_helper_modeset_release(fb_helper,
2148 modeset->num_connectors = 0; 2167 &fb_helper->crtc_info[i].mode_set);
2149 modeset->fb = NULL;
2150 }
2151 2168
2152 for (i = 0; i < fb_helper->connector_count; i++) { 2169 for (i = 0; i < fb_helper->connector_count; i++) {
2153 struct drm_display_mode *mode = modes[i]; 2170 struct drm_display_mode *mode = modes[i];
2154 struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; 2171 struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
2155 struct drm_fb_offset *offset = &offsets[i]; 2172 struct drm_fb_offset *offset = &offsets[i];
2156 modeset = &fb_crtc->mode_set; 2173 struct drm_mode_set *modeset = &fb_crtc->mode_set;
2157 2174
2158 if (mode && fb_crtc) { 2175 if (mode && fb_crtc) {
2176 struct drm_connector *connector =
2177 fb_helper->connector_info[i]->connector;
2178
2159 DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n", 2179 DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
2160 mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y); 2180 mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y);
2181
2161 fb_crtc->desired_mode = mode; 2182 fb_crtc->desired_mode = mode;
2162 fb_crtc->x = offset->x; 2183 fb_crtc->x = offset->x;
2163 fb_crtc->y = offset->y; 2184 fb_crtc->y = offset->y;
2164 if (modeset->mode)
2165 drm_mode_destroy(dev, modeset->mode);
2166 modeset->mode = drm_mode_duplicate(dev, 2185 modeset->mode = drm_mode_duplicate(dev,
2167 fb_crtc->desired_mode); 2186 fb_crtc->desired_mode);
2168 modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector; 2187 drm_connector_reference(connector);
2188 modeset->connectors[modeset->num_connectors++] = connector;
2169 modeset->fb = fb_helper->fb; 2189 modeset->fb = fb_helper->fb;
2170 modeset->x = offset->x; 2190 modeset->x = offset->x;
2171 modeset->y = offset->y; 2191 modeset->y = offset->y;
2172 } 2192 }
2173 } 2193 }
2174
2175 /* Clear out any old modes if there are no more connected outputs. */
2176 for (i = 0; i < fb_helper->crtc_count; i++) {
2177 modeset = &fb_helper->crtc_info[i].mode_set;
2178 if (modeset->num_connectors == 0) {
2179 BUG_ON(modeset->fb);
2180 if (modeset->mode)
2181 drm_mode_destroy(dev, modeset->mode);
2182 modeset->mode = NULL;
2183 }
2184 }
2185out: 2194out:
2186 kfree(crtcs); 2195 kfree(crtcs);
2187 kfree(modes); 2196 kfree(modes);