aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/drm_crtc.c118
1 files changed, 80 insertions, 38 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 3eddfabeba96..a50f7553b31d 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -356,6 +356,9 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
356 if (ret) 356 if (ret)
357 goto out; 357 goto out;
358 358
359 /* Grab the idr reference. */
360 drm_framebuffer_reference(fb);
361
359 dev->mode_config.num_fb++; 362 dev->mode_config.num_fb++;
360 list_add(&fb->head, &dev->mode_config.fb_list); 363 list_add(&fb->head, &dev->mode_config.fb_list);
361out: 364out:
@@ -372,6 +375,23 @@ static void drm_framebuffer_free(struct kref *kref)
372 fb->funcs->destroy(fb); 375 fb->funcs->destroy(fb);
373} 376}
374 377
378static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev,
379 uint32_t id)
380{
381 struct drm_mode_object *obj = NULL;
382 struct drm_framebuffer *fb;
383
384 mutex_lock(&dev->mode_config.idr_mutex);
385 obj = idr_find(&dev->mode_config.crtc_idr, id);
386 if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id))
387 fb = NULL;
388 else
389 fb = obj_to_fb(obj);
390 mutex_unlock(&dev->mode_config.idr_mutex);
391
392 return fb;
393}
394
375/** 395/**
376 * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference 396 * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference
377 * @dev: drm device 397 * @dev: drm device
@@ -384,22 +404,12 @@ static void drm_framebuffer_free(struct kref *kref)
384struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, 404struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
385 uint32_t id) 405 uint32_t id)
386{ 406{
387 struct drm_mode_object *obj = NULL;
388 struct drm_framebuffer *fb; 407 struct drm_framebuffer *fb;
389 408
390 mutex_lock(&dev->mode_config.fb_lock); 409 mutex_lock(&dev->mode_config.fb_lock);
391 410 fb = __drm_framebuffer_lookup(dev, id);
392 mutex_lock(&dev->mode_config.idr_mutex);
393 obj = idr_find(&dev->mode_config.crtc_idr, id);
394 if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id))
395 fb = NULL;
396 else
397 fb = obj_to_fb(obj);
398 mutex_unlock(&dev->mode_config.idr_mutex);
399
400 if (fb) 411 if (fb)
401 kref_get(&fb->refcount); 412 kref_get(&fb->refcount);
402
403 mutex_unlock(&dev->mode_config.fb_lock); 413 mutex_unlock(&dev->mode_config.fb_lock);
404 414
405 return fb; 415 return fb;
@@ -430,6 +440,24 @@ void drm_framebuffer_reference(struct drm_framebuffer *fb)
430} 440}
431EXPORT_SYMBOL(drm_framebuffer_reference); 441EXPORT_SYMBOL(drm_framebuffer_reference);
432 442
443static void drm_framebuffer_free_bug(struct kref *kref)
444{
445 BUG();
446}
447
448/* dev->mode_config.fb_lock must be held! */
449static void __drm_framebuffer_unregister(struct drm_device *dev,
450 struct drm_framebuffer *fb)
451{
452 mutex_lock(&dev->mode_config.idr_mutex);
453 idr_remove(&dev->mode_config.crtc_idr, fb->base.id);
454 mutex_unlock(&dev->mode_config.idr_mutex);
455
456 fb->base.id = 0;
457
458 kref_put(&fb->refcount, drm_framebuffer_free_bug);
459}
460
433/** 461/**
434 * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr 462 * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
435 * @fb: fb to unregister 463 * @fb: fb to unregister
@@ -441,6 +469,12 @@ EXPORT_SYMBOL(drm_framebuffer_reference);
441 */ 469 */
442void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) 470void drm_framebuffer_unregister_private(struct drm_framebuffer *fb)
443{ 471{
472 struct drm_device *dev = fb->dev;
473
474 mutex_lock(&dev->mode_config.fb_lock);
475 /* Mark fb as reaped and drop idr ref. */
476 __drm_framebuffer_unregister(dev, fb);
477 mutex_unlock(&dev->mode_config.fb_lock);
444} 478}
445EXPORT_SYMBOL(drm_framebuffer_unregister_private); 479EXPORT_SYMBOL(drm_framebuffer_unregister_private);
446 480
@@ -464,14 +498,6 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
464{ 498{
465 struct drm_device *dev = fb->dev; 499 struct drm_device *dev = fb->dev;
466 500
467 /*
468 * This could be moved to drm_framebuffer_remove(), but for
469 * debugging is nice to keep around the list of fb's that are
470 * no longer associated w/ a drm_file but are not unreferenced
471 * yet. (i915 and omapdrm have debugfs files which will show
472 * this.)
473 */
474 drm_mode_object_put(dev, &fb->base);
475 mutex_lock(&dev->mode_config.fb_lock); 501 mutex_lock(&dev->mode_config.fb_lock);
476 list_del(&fb->head); 502 list_del(&fb->head);
477 dev->mode_config.num_fb--; 503 dev->mode_config.num_fb--;
@@ -1181,9 +1207,15 @@ void drm_mode_config_cleanup(struct drm_device *dev)
1181 drm_property_destroy(dev, property); 1207 drm_property_destroy(dev, property);
1182 } 1208 }
1183 1209
1184 /* Single-threaded teardown context, so it's not requied to grab the 1210 /*
1211 * Single-threaded teardown context, so it's not required to grab the
1185 * fb_lock to protect against concurrent fb_list access. Contrary, it 1212 * fb_lock to protect against concurrent fb_list access. Contrary, it
1186 * would actually deadlock with the drm_framebuffer_cleanup function. */ 1213 * would actually deadlock with the drm_framebuffer_cleanup function.
1214 *
1215 * Also, if there are any framebuffers left, that's a driver leak now,
1216 * so politely WARN about this.
1217 */
1218 WARN_ON(!list_empty(&dev->mode_config.fb_list));
1187 list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { 1219 list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
1188 drm_framebuffer_remove(fb); 1220 drm_framebuffer_remove(fb);
1189 } 1221 }
@@ -2464,39 +2496,41 @@ int drm_mode_rmfb(struct drm_device *dev,
2464 struct drm_framebuffer *fb = NULL; 2496 struct drm_framebuffer *fb = NULL;
2465 struct drm_framebuffer *fbl = NULL; 2497 struct drm_framebuffer *fbl = NULL;
2466 uint32_t *id = data; 2498 uint32_t *id = data;
2467 int ret = 0;
2468 int found = 0; 2499 int found = 0;
2469 2500
2470 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2501 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2471 return -EINVAL; 2502 return -EINVAL;
2472 2503
2473 drm_modeset_lock_all(dev);
2474 fb = drm_framebuffer_lookup(dev, *id);
2475 if (!fb) {
2476 ret = -EINVAL;
2477 goto out;
2478 }
2479 /* fb is protect by the mode_config lock, so drop the ref immediately */
2480 drm_framebuffer_unreference(fb);
2481
2482 mutex_lock(&file_priv->fbs_lock); 2504 mutex_lock(&file_priv->fbs_lock);
2505 mutex_lock(&dev->mode_config.fb_lock);
2506 fb = __drm_framebuffer_lookup(dev, *id);
2507 if (!fb)
2508 goto fail_lookup;
2509
2483 list_for_each_entry(fbl, &file_priv->fbs, filp_head) 2510 list_for_each_entry(fbl, &file_priv->fbs, filp_head)
2484 if (fb == fbl) 2511 if (fb == fbl)
2485 found = 1; 2512 found = 1;
2486 if (!found) { 2513 if (!found)
2487 ret = -EINVAL; 2514 goto fail_lookup;
2488 mutex_unlock(&file_priv->fbs_lock); 2515
2489 goto out; 2516 /* Mark fb as reaped, we still have a ref from fpriv->fbs. */
2490 } 2517 __drm_framebuffer_unregister(dev, fb);
2491 2518
2492 list_del_init(&fb->filp_head); 2519 list_del_init(&fb->filp_head);
2520 mutex_unlock(&dev->mode_config.fb_lock);
2493 mutex_unlock(&file_priv->fbs_lock); 2521 mutex_unlock(&file_priv->fbs_lock);
2494 2522
2523 drm_modeset_lock_all(dev);
2495 drm_framebuffer_remove(fb); 2524 drm_framebuffer_remove(fb);
2496out:
2497 drm_modeset_unlock_all(dev); 2525 drm_modeset_unlock_all(dev);
2498 2526
2499 return ret; 2527 return 0;
2528
2529fail_lookup:
2530 mutex_unlock(&dev->mode_config.fb_lock);
2531 mutex_unlock(&file_priv->fbs_lock);
2532
2533 return -EINVAL;
2500} 2534}
2501 2535
2502/** 2536/**
@@ -2639,7 +2673,15 @@ void drm_fb_release(struct drm_file *priv)
2639 drm_modeset_lock_all(dev); 2673 drm_modeset_lock_all(dev);
2640 mutex_lock(&priv->fbs_lock); 2674 mutex_lock(&priv->fbs_lock);
2641 list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { 2675 list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
2676
2677 mutex_lock(&dev->mode_config.fb_lock);
2678 /* Mark fb as reaped, we still have a ref from fpriv->fbs. */
2679 __drm_framebuffer_unregister(dev, fb);
2680 mutex_unlock(&dev->mode_config.fb_lock);
2681
2642 list_del_init(&fb->filp_head); 2682 list_del_init(&fb->filp_head);
2683
2684 /* This will also drop the fpriv->fbs reference. */
2643 drm_framebuffer_remove(fb); 2685 drm_framebuffer_remove(fb);
2644 } 2686 }
2645 mutex_unlock(&priv->fbs_lock); 2687 mutex_unlock(&priv->fbs_lock);