drm/kms: teardown crtc correctly when fb is destroyed.

If userspace destroys a framebuffer that is in use on a crtc,
don't just null it out, tear down the crtc properly so the
hw gets turned off.

Signed-off-by: Dave Airlie <airlied@redhat.com>

+12 -28
+12 -28
drivers/gpu/drm/drm_crtc.c
··· 258 EXPORT_SYMBOL(drm_mode_object_find); 259 260 /** 261 - * drm_crtc_from_fb - find the CRTC structure associated with an fb 262 - * @dev: DRM device 263 - * @fb: framebuffer in question 264 - * 265 - * LOCKING: 266 - * Caller must hold mode_config lock. 267 - * 268 - * Find CRTC in the mode_config structure that matches @fb. 269 - * 270 - * RETURNS: 271 - * Pointer to the CRTC or NULL if it wasn't found. 272 - */ 273 - struct drm_crtc *drm_crtc_from_fb(struct drm_device *dev, 274 - struct drm_framebuffer *fb) 275 - { 276 - struct drm_crtc *crtc; 277 - 278 - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 279 - if (crtc->fb == fb) 280 - return crtc; 281 - } 282 - return NULL; 283 - } 284 - 285 - /** 286 * drm_framebuffer_init - initialize a framebuffer 287 * @dev: DRM device 288 * ··· 303 { 304 struct drm_device *dev = fb->dev; 305 struct drm_crtc *crtc; 306 307 /* remove from any CRTC */ 308 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 309 - if (crtc->fb == fb) 310 - crtc->fb = NULL; 311 } 312 313 drm_mode_object_put(dev, &fb->base); ··· 1495 set.mode = mode; 1496 set.connectors = connector_set; 1497 set.num_connectors = crtc_req->count_connectors; 1498 - set.fb =fb; 1499 ret = crtc->funcs->set_config(&set); 1500 1501 out:
··· 258 EXPORT_SYMBOL(drm_mode_object_find); 259 260 /** 261 * drm_framebuffer_init - initialize a framebuffer 262 * @dev: DRM device 263 * ··· 328 { 329 struct drm_device *dev = fb->dev; 330 struct drm_crtc *crtc; 331 + struct drm_mode_set set; 332 + int ret; 333 334 /* remove from any CRTC */ 335 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 336 + if (crtc->fb == fb) { 337 + /* should turn off the crtc */ 338 + memset(&set, 0, sizeof(struct drm_mode_set)); 339 + set.crtc = crtc; 340 + set.fb = NULL; 341 + ret = crtc->funcs->set_config(&set); 342 + if (ret) 343 + DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); 344 + } 345 } 346 347 drm_mode_object_put(dev, &fb->base); ··· 1511 set.mode = mode; 1512 set.connectors = connector_set; 1513 set.num_connectors = crtc_req->count_connectors; 1514 + set.fb = fb; 1515 ret = crtc->funcs->set_config(&set); 1516 1517 out: