drm: create drm_framebuffer_lookup
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Sun, 2 Dec 2012 20:53:40 +0000 (21:53 +0100)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Sun, 20 Jan 2013 21:16:59 +0000 (22:16 +0100)
And replace all fb lookups with it. Also add a WARN to
drm_mode_object_find since that is now no longer the blessed interface
to look up an fb. And add kerneldoc to both functions.

This only updates all callsites, but immediately drops the acquired
refence again. Hence all callers still rely on the fact that a mode fb
can't disappear while they're holding the struct mutex. Subsequent
patches will instate proper use of refcounts, and then rework the rmfb
and unref code to no longer serialize fb destruction with the
mode_config lock. We don't want that since otherwise a compositor
might end up stalling for a few frames in rmfb.

v2: Don't use kref_get_unless_zero - Greg KH doesn't like that kind of
interface.

Reviewed-by: Rob Clark <rob@ti.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
include/drm/drm_crtc.h

index 13a3d34269619d163075efd236c403fe0f8bbb94..f2ccda85309f648e839d0b9c4284b112e047e91f 100644 (file)
@@ -294,11 +294,24 @@ static void drm_mode_object_put(struct drm_device *dev,
        mutex_unlock(&dev->mode_config.idr_mutex);
 }
 
+/**
+ * drm_mode_object_find - look up a drm object with static lifetime
+ * @dev: drm device
+ * @id: id of the mode object
+ * @type: type of the mode object
+ *
+ * Note that framebuffers cannot be looked up with this functions - since those
+ * are reference counted, they need special treatment.
+ */
 struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
                uint32_t id, uint32_t type)
 {
        struct drm_mode_object *obj = NULL;
 
+       /* Framebuffers are reference counted and need their own lookup
+        * function.*/
+       WARN_ON(type == DRM_MODE_OBJECT_FB);
+
        mutex_lock(&dev->mode_config.idr_mutex);
        obj = idr_find(&dev->mode_config.crtc_idr, id);
        if (!obj || (obj->type != type) || (obj->id != id))
@@ -358,6 +371,40 @@ static void drm_framebuffer_free(struct kref *kref)
        fb->funcs->destroy(fb);
 }
 
+/**
+ * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference
+ * @dev: drm device
+ * @id: id of the fb object
+ *
+ * If successful, this grabs an additional reference to the framebuffer -
+ * callers need to make sure to eventually unreference the returned framebuffer
+ * again.
+ */
+struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
+                                              uint32_t id)
+{
+       struct drm_mode_object *obj = NULL;
+       struct drm_framebuffer *fb;
+
+       mutex_lock(&dev->mode_config.fb_lock);
+
+       mutex_lock(&dev->mode_config.idr_mutex);
+       obj = idr_find(&dev->mode_config.crtc_idr, id);
+       if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id))
+               fb = NULL;
+       else
+               fb = obj_to_fb(obj);
+       mutex_unlock(&dev->mode_config.idr_mutex);
+
+       if (fb)
+               kref_get(&fb->refcount);
+
+       mutex_unlock(&dev->mode_config.fb_lock);
+
+       return fb;
+}
+EXPORT_SYMBOL(drm_framebuffer_lookup);
+
 /**
  * drm_framebuffer_unreference - unref a framebuffer
  * @fb: framebuffer to unref
@@ -1788,17 +1835,15 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
        }
        crtc = obj_to_crtc(obj);
 
-       mutex_lock(&dev->mode_config.fb_lock);
-       obj = drm_mode_object_find(dev, plane_req->fb_id,
-                                  DRM_MODE_OBJECT_FB);
-       mutex_unlock(&dev->mode_config.fb_lock);
-       if (!obj) {
+       fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
+       if (!fb) {
                DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
                              plane_req->fb_id);
                ret = -ENOENT;
                goto out;
        }
-       fb = obj_to_fb(obj);
+       /* fb is protect by the mode_config lock, so drop the ref immediately */
+       drm_framebuffer_unreference(fb);
 
        /* Check whether this plane supports the fb pixel format. */
        for (i = 0; i < plane->format_count; i++)
@@ -1933,17 +1978,16 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
                        }
                        fb = crtc->fb;
                } else {
-                       mutex_lock(&dev->mode_config.fb_lock);
-                       obj = drm_mode_object_find(dev, crtc_req->fb_id,
-                                                  DRM_MODE_OBJECT_FB);
-                       mutex_unlock(&dev->mode_config.fb_lock);
-                       if (!obj) {
+                       fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);
+                       if (!fb) {
                                DRM_DEBUG_KMS("Unknown FB ID%d\n",
                                                crtc_req->fb_id);
                                ret = -EINVAL;
                                goto out;
                        }
-                       fb = obj_to_fb(obj);
+                       /* fb is protect by the mode_config lock, so drop the
+                        * ref immediately */
+                       drm_framebuffer_unreference(fb);
                }
 
                mode = drm_mode_create(dev);
@@ -2392,7 +2436,6 @@ int drm_mode_addfb2(struct drm_device *dev,
 int drm_mode_rmfb(struct drm_device *dev,
                   void *data, struct drm_file *file_priv)
 {
-       struct drm_mode_object *obj;
        struct drm_framebuffer *fb = NULL;
        struct drm_framebuffer *fbl = NULL;
        uint32_t *id = data;
@@ -2403,16 +2446,13 @@ int drm_mode_rmfb(struct drm_device *dev,
                return -EINVAL;
 
        drm_modeset_lock_all(dev);
-       mutex_lock(&dev->mode_config.fb_lock);
-       obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB);
-       /* TODO check that we really get a framebuffer back. */
-       if (!obj) {
-               mutex_unlock(&dev->mode_config.fb_lock);
+       fb = drm_framebuffer_lookup(dev, *id);
+       if (!fb) {
                ret = -EINVAL;
                goto out;
        }
-       fb = obj_to_fb(obj);
-       mutex_unlock(&dev->mode_config.fb_lock);
+       /* fb is protect by the mode_config lock, so drop the ref immediately */
+       drm_framebuffer_unreference(fb);
 
        mutex_lock(&file_priv->fbs_lock);
        list_for_each_entry(fbl, &file_priv->fbs, filp_head)
@@ -2451,7 +2491,6 @@ int drm_mode_getfb(struct drm_device *dev,
                   void *data, struct drm_file *file_priv)
 {
        struct drm_mode_fb_cmd *r = data;
-       struct drm_mode_object *obj;
        struct drm_framebuffer *fb;
        int ret = 0;
 
@@ -2459,14 +2498,13 @@ int drm_mode_getfb(struct drm_device *dev,
                return -EINVAL;
 
        drm_modeset_lock_all(dev);
-       mutex_lock(&dev->mode_config.fb_lock);
-       obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
-       mutex_unlock(&dev->mode_config.fb_lock);
-       if (!obj) {
+       fb = drm_framebuffer_lookup(dev, r->fb_id);
+       if (!fb) {
                ret = -EINVAL;
                goto out;
        }
-       fb = obj_to_fb(obj);
+       /* fb is protect by the mode_config lock, so drop the ref immediately */
+       drm_framebuffer_unreference(fb);
 
        r->height = fb->height;
        r->width = fb->width;
@@ -2489,7 +2527,6 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
        struct drm_clip_rect __user *clips_ptr;
        struct drm_clip_rect *clips = NULL;
        struct drm_mode_fb_dirty_cmd *r = data;
-       struct drm_mode_object *obj;
        struct drm_framebuffer *fb;
        unsigned flags;
        int num_clips;
@@ -2499,14 +2536,13 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
                return -EINVAL;
 
        drm_modeset_lock_all(dev);
-       mutex_lock(&dev->mode_config.fb_lock);
-       obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
-       mutex_unlock(&dev->mode_config.fb_lock);
-       if (!obj) {
+       fb = drm_framebuffer_lookup(dev, r->fb_id);
+       if (!fb) {
                ret = -EINVAL;
                goto out_err1;
        }
-       fb = obj_to_fb(obj);
+       /* fb is protect by the mode_config lock, so drop the ref immediately */
+       drm_framebuffer_unreference(fb);
 
        num_clips = r->num_clips;
        clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr;
@@ -3586,12 +3622,11 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
        if (crtc->funcs->page_flip == NULL)
                goto out;
 
-       mutex_lock(&dev->mode_config.fb_lock);
-       obj = drm_mode_object_find(dev, page_flip->fb_id, DRM_MODE_OBJECT_FB);
-       mutex_unlock(&dev->mode_config.fb_lock);
-       if (!obj)
+       fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
+       if (!fb)
                goto out;
-       fb = obj_to_fb(obj);
+       /* fb is protect by the mode_config lock, so drop the ref immediately */
+       drm_framebuffer_unreference(fb);
 
        hdisplay = crtc->mode.hdisplay;
        vdisplay = crtc->mode.vdisplay;
index 0d6a161b204bbdd48ee05c6e2899bdbd8358c5f6..1b8f428accaea045792d05cd2c58e77daf5de635 100644 (file)
@@ -131,7 +131,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,
        struct vmw_master *vmaster = vmw_master(file_priv->master);
        struct drm_vmw_rect __user *clips_ptr;
        struct drm_vmw_rect *clips = NULL;
-       struct drm_mode_object *obj;
+       struct drm_framebuffer *fb;
        struct vmw_framebuffer *vfb;
        struct vmw_resource *res;
        uint32_t num_clips;
@@ -165,15 +165,15 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,
 
        drm_modeset_lock_all(dev);
 
-       mutex_lock(&dev->mode_config.fb_lock);
-       obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
-       mutex_unlock(&dev->mode_config.fb_lock);
-       if (!obj) {
+       fb = drm_framebuffer_lookup(dev, arg->fb_id);
+       if (!fb) {
                DRM_ERROR("Invalid framebuffer id.\n");
                ret = -EINVAL;
                goto out_no_fb;
        }
-       vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj));
+       /* fb is protect by the mode_config lock, so drop the ref immediately */
+       drm_framebuffer_unreference(fb);
+       vfb = vmw_framebuffer_to_vfb(fb);
 
        ret = ttm_read_lock(&vmaster->lock, true);
        if (unlikely(ret != 0))
@@ -217,7 +217,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
        struct vmw_master *vmaster = vmw_master(file_priv->master);
        struct drm_vmw_rect __user *clips_ptr;
        struct drm_vmw_rect *clips = NULL;
-       struct drm_mode_object *obj;
+       struct drm_framebuffer *fb;
        struct vmw_framebuffer *vfb;
        uint32_t num_clips;
        int ret;
@@ -250,16 +250,16 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
 
        drm_modeset_lock_all(dev);
 
-       mutex_lock(&dev->mode_config.fb_lock);
-       obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
-       mutex_unlock(&dev->mode_config.fb_lock);
-       if (!obj) {
+       fb = drm_framebuffer_lookup(dev, arg->fb_id);
+       if (!fb) {
                DRM_ERROR("Invalid framebuffer id.\n");
                ret = -EINVAL;
                goto out_no_fb;
        }
+       /* fb is protect by the mode_config lock, so drop the ref immediately */
+       drm_framebuffer_unreference(fb);
 
-       vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj));
+       vfb = vmw_framebuffer_to_vfb(fb);
        if (!vfb->dmabuf) {
                DRM_ERROR("Framebuffer not dmabuf backed.\n");
                ret = -EINVAL;
index c35a807d7e5cc40029dca2204d59421956e53aef..7dc1b31059d46a9aedfb0a1a028ac0689e59dc82 100644 (file)
@@ -958,6 +958,8 @@ extern void drm_framebuffer_set_object(struct drm_device *dev,
 extern int drm_framebuffer_init(struct drm_device *dev,
                                struct drm_framebuffer *fb,
                                const struct drm_framebuffer_funcs *funcs);
+extern struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
+                                                     uint32_t id);
 extern void drm_framebuffer_unreference(struct drm_framebuffer *fb);
 extern void drm_framebuffer_reference(struct drm_framebuffer *fb);
 extern void drm_framebuffer_remove(struct drm_framebuffer *fb);