| @@ -294,6 +294,8 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, · 293 unmodified lines |
| 294 | 294 | { |
| 295 | 295 | int ret; |
| 296 | 296 | |
| 297 | + kref_init(&fb->refcount); |
| 298 | + |
| 297 | 299 | ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); |
| 298 | 300 | if (ret) |
| 299 | 301 | return ret; |
| @@ -307,6 +309,38 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, · 7 unmodified lines |
| 307 | 309 | } |
| 308 | 310 | EXPORT_SYMBOL(drm_framebuffer_init); |
| 309 | 311 | |
| 312 | +static void drm_framebuffer_free(struct kref *kref) |
| 313 | +{ |
| 314 | + struct drm_framebuffer *fb = |
| 315 | + container_of(kref, struct drm_framebuffer, refcount); |
| 316 | + fb->funcs->destroy(fb); |
| 317 | +} |
| 318 | + |
| 319 | +/** |
| 320 | + * drm_framebuffer_unreference - unref a framebuffer |
| 321 | + * |
| 322 | + * LOCKING: |
| 323 | + * Caller must hold mode config lock. |
| 324 | + */ |
| 325 | +void drm_framebuffer_unreference(struct drm_framebuffer *fb) |
| 326 | +{ |
| 327 | + struct drm_device *dev = fb->dev; |
| 328 | + DRM_DEBUG("FB ID: %d\n", fb->base.id); |
| 329 | + WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); |
| 330 | + kref_put(&fb->refcount, drm_framebuffer_free); |
| 331 | +} |
| 332 | +EXPORT_SYMBOL(drm_framebuffer_unreference); |
| 333 | + |
| 334 | +/** |
| 335 | + * drm_framebuffer_reference - incr the fb refcnt |
| 336 | + */ |
| 337 | +void drm_framebuffer_reference(struct drm_framebuffer *fb) |
| 338 | +{ |
| 339 | + DRM_DEBUG("FB ID: %d\n", fb->base.id); |
| 340 | + kref_get(&fb->refcount); |
| 341 | +} |
| 342 | +EXPORT_SYMBOL(drm_framebuffer_reference); |
| 343 | + |
| 310 | 344 | /** |
| 311 | 345 | * drm_framebuffer_cleanup - remove a framebuffer object |
| 312 | 346 | * @fb: framebuffer to remove |
| @@ -318,6 +352,32 @@ EXPORT_SYMBOL(drm_framebuffer_init); · 5 unmodified lines |
| 318 | 352 | * it, setting it to NULL. |
| 319 | 353 | */ |
| 320 | 354 | void drm_framebuffer_cleanup(struct drm_framebuffer *fb) |
| 355 | +{ |
| 356 | + struct drm_device *dev = fb->dev; |
| 357 | + /* |
| 358 | + * This could be moved to drm_framebuffer_remove(), but for |
| 359 | + * debugging is nice to keep around the list of fb's that are |
| 360 | + * no longer associated w/ a drm_file but are not unreferenced |
| 361 | + * yet. (i915 and omapdrm have debugfs files which will show |
| 362 | + * this.) |
| 363 | + */ |
| 364 | + drm_mode_object_put(dev, &fb->base); |
| 365 | + list_del(&fb->head); |
| 366 | + dev->mode_config.num_fb--; |
| 367 | +} |
| 368 | +EXPORT_SYMBOL(drm_framebuffer_cleanup); |
| 369 | + |
| 370 | +/** |
| 371 | + * drm_framebuffer_remove - remove and unreference a framebuffer object |
| 372 | + * @fb: framebuffer to remove |
| 373 | + * |
| 374 | + * LOCKING: |
| 375 | + * Caller must hold mode config lock. |
| 376 | + * |
| 377 | + * Scans all the CRTCs and planes in @dev's mode_config. If they're |
| 378 | + * using @fb, removes it, setting it to NULL. |
| 379 | + */ |
| 380 | +void drm_framebuffer_remove(struct drm_framebuffer *fb) |
| 321 | 381 | { |
| 322 | 382 | struct drm_device *dev = fb->dev; |
| 323 | 383 | struct drm_crtc *crtc; |
| @@ -350,11 +410,11 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb) · 26 unmodified lines |
| 350 | 410 | } |
| 351 | 411 | } |
| 352 | 412 | |
| 353 | | − drm_mode_object_put(dev, &fb->base); |
| 354 | | − list_del(&fb->head); |
| 355 | | − dev->mode_config.num_fb--; |
| 413 | + list_del(&fb->filp_head); |
| 414 | + |
| 415 | + drm_framebuffer_unreference(fb); |
| 356 | 416 | } |
| 357 | | −EXPORT_SYMBOL(drm_framebuffer_cleanup); |
| 417 | +EXPORT_SYMBOL(drm_framebuffer_remove); |
| 358 | 418 | |
| 359 | 419 | /** |
| 360 | 420 | * drm_crtc_init - Initialise a new CRTC object |
| @@ -1031,7 +1091,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) · 670 unmodified lines |
| 1031 | 1091 | } |
| 1032 | 1092 | |
| 1033 | 1093 | list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { |
| 1034 | | − fb->funcs->destroy(fb); |
| 1094 | + drm_framebuffer_remove(fb); |
| 1035 | 1095 | } |
| 1036 | 1096 | |
| 1037 | 1097 | list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, |
| @@ -2337,11 +2397,7 @@ int drm_mode_rmfb(struct drm_device *dev, · 1299 unmodified lines |
| 2337 | 2397 | goto out; |
| 2338 | 2398 | } |
| 2339 | 2399 | |
| 2340 | | − /* TODO release all crtc connected to the framebuffer */ |
| 2341 | | − /* TODO unhock the destructor from the buffer object */ |
| 2342 | | − |
| 2343 | | − list_del(&fb->filp_head); |
| 2344 | | − fb->funcs->destroy(fb); |
| 2400 | + drm_framebuffer_remove(fb); |
| 2345 | 2401 | |
| 2346 | 2402 | out: |
| 2347 | 2403 | mutex_unlock(&dev->mode_config.mutex); |
| @@ -2491,8 +2547,7 @@ void drm_fb_release(struct drm_file *priv) · 143 unmodified lines |
| 2491 | 2547 | |
| 2492 | 2548 | mutex_lock(&dev->mode_config.mutex); |
| 2493 | 2549 | list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { |
| 2494 | | − list_del(&fb->filp_head); |
| 2495 | | − fb->funcs->destroy(fb); |
| 2550 | + drm_framebuffer_remove(fb); |
| 2496 | 2551 | } |
| 2497 | 2552 | mutex_unlock(&dev->mode_config.mutex); |
| 2498 | 2553 | } |