History

drm: refcnt drm_framebuffer (v4.1)

This simplifies drm fb lifetime, and if the crtc/plane needs to hold a ref to the fb when disabling a pipe until the next vblank, this avoids the need to make disabling an overlay synchronous. This is a problem that shows up when userspace is using a drm plane to implement a hw cursor.. making overlay disable synchronous causes a performance problem when x11 is rapidly enabling/disabling the hw cursor. But not making it synchronous opens up a race condition for crashing if userspace turns around and immediately deletes the fb. Refcnt'ing the fb makes it possible to solve this problem. v1: original v2: add drm_framebuffer_remove() which is called in all paths where fb->funcs->destroy() was directly called before. This cleans up the CRTCs/planes that the fb was attached to. You should only directly use drm_framebuffer_unreference() if you are also using drm_framebuffer_reference() to keep a ref to the fb. v3: add comment explaining the fb refcount v4: remove duplicate 'list_del(&fb->filp_head)' [airlied: v4.1: fix local rejection]

Rob Clark committed 14 years ago

Commit f7eff601 parent 33cce6e4 files · +85 −16Browse files

Unified · Split

4 files
  1. drivers/gpu/drm/drm_crtc.c +67 −12
  2. drivers/gpu/drm/exynos/exynos_drm_fbdev.c +2 −2
  3. drivers/staging/omapdrm/omap_fbdev.c +2 −2
  4. include/drm/drm_crtc.h +14 −0
drivers/gpu/drm/drm_crtc.c+67−12
@@ -294,6 +294,8 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, · 293 unmodified lines
294{294{
295 int ret;295 int ret;
296 296
297 kref_init(&fb->refcount);
298
297 ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB);299 ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB);
298 if (ret)300 if (ret)
299 return ret;301 return ret;
@@ -307,6 +309,38 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, · 7 unmodified lines
307}309}
308EXPORT_SYMBOL(drm_framebuffer_init);310EXPORT_SYMBOL(drm_framebuffer_init);
309 311
312static 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 */
325void 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}
332EXPORT_SYMBOL(drm_framebuffer_unreference);
333
334/**
335 * drm_framebuffer_reference - incr the fb refcnt
336 */
337void drm_framebuffer_reference(struct drm_framebuffer *fb)
338{
339 DRM_DEBUG("FB ID: %d\n", fb->base.id);
340 kref_get(&fb->refcount);
341}
342EXPORT_SYMBOL(drm_framebuffer_reference);
343
310/**344/**
311 * drm_framebuffer_cleanup - remove a framebuffer object345 * drm_framebuffer_cleanup - remove a framebuffer object
312 * @fb: framebuffer to remove346 * @fb: framebuffer to remove
@@ -318,6 +352,32 @@ EXPORT_SYMBOL(drm_framebuffer_init); · 5 unmodified lines
318 * it, setting it to NULL.352 * it, setting it to NULL.
319 */353 */
320void drm_framebuffer_cleanup(struct drm_framebuffer *fb)354void 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}
368EXPORT_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 */
380void drm_framebuffer_remove(struct drm_framebuffer *fb)
321{381{
322 struct drm_device *dev = fb->dev;382 struct drm_device *dev = fb->dev;
323 struct drm_crtc *crtc;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);413 list_del(&fb->filp_head);
354 list_del(&fb->head);414
355 dev->mode_config.num_fb--;415 drm_framebuffer_unreference(fb);
356}416}
357EXPORT_SYMBOL(drm_framebuffer_cleanup);417EXPORT_SYMBOL(drm_framebuffer_remove);
358 418
359/**419/**
360 * drm_crtc_init - Initialise a new CRTC object420 * 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 list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {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 list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,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 goto out;2397 goto out;
2338 }2398 }
2339 2399
2340 /* TODO release all crtc connected to the framebuffer */2400 drm_framebuffer_remove(fb);
2341 /* TODO unhock the destructor from the buffer object */
2342
2343 list_del(&fb->filp_head);
2344 fb->funcs->destroy(fb);
2345 2401
2346out:2402out:
2347 mutex_unlock(&dev->mode_config.mutex);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 mutex_lock(&dev->mode_config.mutex);2548 mutex_lock(&dev->mode_config.mutex);
2493 list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {2549 list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
2494 list_del(&fb->filp_head);2550 drm_framebuffer_remove(fb);
2495 fb->funcs->destroy(fb);
2496 }2551 }
2497 mutex_unlock(&dev->mode_config.mutex);2552 mutex_unlock(&dev->mode_config.mutex);
2498}2553}
drivers/gpu/drm/exynos/exynos_drm_fbdev.c+2−2
@@ -266,8 +266,8 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev, · 265 unmodified lines
266 /* release drm framebuffer and real buffer */266 /* release drm framebuffer and real buffer */
267 if (fb_helper->fb && fb_helper->fb->funcs) {267 if (fb_helper->fb && fb_helper->fb->funcs) {
268 fb = fb_helper->fb;268 fb = fb_helper->fb;
269 if (fb && fb->funcs->destroy)269 if (fb)
270 fb->funcs->destroy(fb);270 drm_framebuffer_remove(fb);
271 }271 }
272 272
273 /* release linux framebuffer */273 /* release linux framebuffer */
drivers/staging/omapdrm/omap_fbdev.c+2−2
@@ -276,7 +276,7 @@ fail: · 275 unmodified lines
276 if (fbi)276 if (fbi)
277 framebuffer_release(fbi);277 framebuffer_release(fbi);
278 if (fb)278 if (fb)
279 fb->funcs->destroy(fb);279 drm_framebuffer_remove(fb);
280 }280 }
281 281
282 return ret;282 return ret;
@@ -401,7 +401,7 @@ void omap_fbdev_free(struct drm_device *dev) · 118 unmodified lines
401 401
402 /* this will free the backing object */402 /* this will free the backing object */
403 if (fbdev->fb)403 if (fbdev->fb)
404 fbdev->fb->funcs->destroy(fbdev->fb);404 drm_framebuffer_remove(fbdev->fb);
405 405
406 kfree(fbdev);406 kfree(fbdev);
407 407
include/drm/drm_crtc.h+14−0
@@ -218,6 +218,7 @@ struct drm_display_info { · 217 unmodified lines
218};218};
219 219
220struct drm_framebuffer_funcs {220struct drm_framebuffer_funcs {
221 /* note: use drm_framebuffer_remove() */
221 void (*destroy)(struct drm_framebuffer *framebuffer);222 void (*destroy)(struct drm_framebuffer *framebuffer);
222 int (*create_handle)(struct drm_framebuffer *fb,223 int (*create_handle)(struct drm_framebuffer *fb,
223 struct drm_file *file_priv,224 struct drm_file *file_priv,
@@ -242,6 +243,16 @@ struct drm_framebuffer_funcs { · 18 unmodified lines
242 243
243struct drm_framebuffer {244struct drm_framebuffer {
244 struct drm_device *dev;245 struct drm_device *dev;
246 /*
247 * Note that the fb is refcounted for the benefit of driver internals,
248 * for example some hw, disabling a CRTC/plane is asynchronous, and
249 * scanout does not actually complete until the next vblank. So some
250 * cleanup (like releasing the reference(s) on the backing GEM bo(s))
251 * should be deferred. In cases like this, the driver would like to
252 * hold a ref to the fb even though it has already been removed from
253 * userspace perspective.
254 */
255 struct kref refcount;
245 struct list_head head;256 struct list_head head;
246 struct drm_mode_object base;257 struct drm_mode_object base;
247 const struct drm_framebuffer_funcs *funcs;258 const struct drm_framebuffer_funcs *funcs;
@@ -919,6 +930,9 @@ extern void drm_framebuffer_set_object(struct drm_device *dev, · 671 unmodified lines
919extern int drm_framebuffer_init(struct drm_device *dev,930extern int drm_framebuffer_init(struct drm_device *dev,
920 struct drm_framebuffer *fb,931 struct drm_framebuffer *fb,
921 const struct drm_framebuffer_funcs *funcs);932 const struct drm_framebuffer_funcs *funcs);
933extern void drm_framebuffer_unreference(struct drm_framebuffer *fb);
934extern void drm_framebuffer_reference(struct drm_framebuffer *fb);
935extern void drm_framebuffer_remove(struct drm_framebuffer *fb);
922extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb);936extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb);
923extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc);937extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc);
924extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);938extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);