diff options
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 109 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 24 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 2 |
3 files changed, 86 insertions, 49 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 13a3d3426961..f2ccda85309f 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -294,11 +294,24 @@ static void drm_mode_object_put(struct drm_device *dev, | |||
294 | mutex_unlock(&dev->mode_config.idr_mutex); | 294 | mutex_unlock(&dev->mode_config.idr_mutex); |
295 | } | 295 | } |
296 | 296 | ||
297 | /** | ||
298 | * drm_mode_object_find - look up a drm object with static lifetime | ||
299 | * @dev: drm device | ||
300 | * @id: id of the mode object | ||
301 | * @type: type of the mode object | ||
302 | * | ||
303 | * Note that framebuffers cannot be looked up with this functions - since those | ||
304 | * are reference counted, they need special treatment. | ||
305 | */ | ||
297 | struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, | 306 | struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, |
298 | uint32_t id, uint32_t type) | 307 | uint32_t id, uint32_t type) |
299 | { | 308 | { |
300 | struct drm_mode_object *obj = NULL; | 309 | struct drm_mode_object *obj = NULL; |
301 | 310 | ||
311 | /* Framebuffers are reference counted and need their own lookup | ||
312 | * function.*/ | ||
313 | WARN_ON(type == DRM_MODE_OBJECT_FB); | ||
314 | |||
302 | mutex_lock(&dev->mode_config.idr_mutex); | 315 | mutex_lock(&dev->mode_config.idr_mutex); |
303 | obj = idr_find(&dev->mode_config.crtc_idr, id); | 316 | obj = idr_find(&dev->mode_config.crtc_idr, id); |
304 | if (!obj || (obj->type != type) || (obj->id != id)) | 317 | if (!obj || (obj->type != type) || (obj->id != id)) |
@@ -359,6 +372,40 @@ static void drm_framebuffer_free(struct kref *kref) | |||
359 | } | 372 | } |
360 | 373 | ||
361 | /** | 374 | /** |
375 | * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference | ||
376 | * @dev: drm device | ||
377 | * @id: id of the fb object | ||
378 | * | ||
379 | * If successful, this grabs an additional reference to the framebuffer - | ||
380 | * callers need to make sure to eventually unreference the returned framebuffer | ||
381 | * again. | ||
382 | */ | ||
383 | struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, | ||
384 | uint32_t id) | ||
385 | { | ||
386 | struct drm_mode_object *obj = NULL; | ||
387 | struct drm_framebuffer *fb; | ||
388 | |||
389 | mutex_lock(&dev->mode_config.fb_lock); | ||
390 | |||
391 | mutex_lock(&dev->mode_config.idr_mutex); | ||
392 | obj = idr_find(&dev->mode_config.crtc_idr, id); | ||
393 | if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id)) | ||
394 | fb = NULL; | ||
395 | else | ||
396 | fb = obj_to_fb(obj); | ||
397 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
398 | |||
399 | if (fb) | ||
400 | kref_get(&fb->refcount); | ||
401 | |||
402 | mutex_unlock(&dev->mode_config.fb_lock); | ||
403 | |||
404 | return fb; | ||
405 | } | ||
406 | EXPORT_SYMBOL(drm_framebuffer_lookup); | ||
407 | |||
408 | /** | ||
362 | * drm_framebuffer_unreference - unref a framebuffer | 409 | * drm_framebuffer_unreference - unref a framebuffer |
363 | * @fb: framebuffer to unref | 410 | * @fb: framebuffer to unref |
364 | * | 411 | * |
@@ -1788,17 +1835,15 @@ int drm_mode_setplane(struct drm_device *dev, void *data, | |||
1788 | } | 1835 | } |
1789 | crtc = obj_to_crtc(obj); | 1836 | crtc = obj_to_crtc(obj); |
1790 | 1837 | ||
1791 | mutex_lock(&dev->mode_config.fb_lock); | 1838 | fb = drm_framebuffer_lookup(dev, plane_req->fb_id); |
1792 | obj = drm_mode_object_find(dev, plane_req->fb_id, | 1839 | if (!fb) { |
1793 | DRM_MODE_OBJECT_FB); | ||
1794 | mutex_unlock(&dev->mode_config.fb_lock); | ||
1795 | if (!obj) { | ||
1796 | DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", | 1840 | DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", |
1797 | plane_req->fb_id); | 1841 | plane_req->fb_id); |
1798 | ret = -ENOENT; | 1842 | ret = -ENOENT; |
1799 | goto out; | 1843 | goto out; |
1800 | } | 1844 | } |
1801 | fb = obj_to_fb(obj); | 1845 | /* fb is protect by the mode_config lock, so drop the ref immediately */ |
1846 | drm_framebuffer_unreference(fb); | ||
1802 | 1847 | ||
1803 | /* Check whether this plane supports the fb pixel format. */ | 1848 | /* Check whether this plane supports the fb pixel format. */ |
1804 | for (i = 0; i < plane->format_count; i++) | 1849 | for (i = 0; i < plane->format_count; i++) |
@@ -1933,17 +1978,16 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, | |||
1933 | } | 1978 | } |
1934 | fb = crtc->fb; | 1979 | fb = crtc->fb; |
1935 | } else { | 1980 | } else { |
1936 | mutex_lock(&dev->mode_config.fb_lock); | 1981 | fb = drm_framebuffer_lookup(dev, crtc_req->fb_id); |
1937 | obj = drm_mode_object_find(dev, crtc_req->fb_id, | 1982 | if (!fb) { |
1938 | DRM_MODE_OBJECT_FB); | ||
1939 | mutex_unlock(&dev->mode_config.fb_lock); | ||
1940 | if (!obj) { | ||
1941 | DRM_DEBUG_KMS("Unknown FB ID%d\n", | 1983 | DRM_DEBUG_KMS("Unknown FB ID%d\n", |
1942 | crtc_req->fb_id); | 1984 | crtc_req->fb_id); |
1943 | ret = -EINVAL; | 1985 | ret = -EINVAL; |
1944 | goto out; | 1986 | goto out; |
1945 | } | 1987 | } |
1946 | fb = obj_to_fb(obj); | 1988 | /* fb is protect by the mode_config lock, so drop the |
1989 | * ref immediately */ | ||
1990 | drm_framebuffer_unreference(fb); | ||
1947 | } | 1991 | } |
1948 | 1992 | ||
1949 | mode = drm_mode_create(dev); | 1993 | mode = drm_mode_create(dev); |
@@ -2392,7 +2436,6 @@ int drm_mode_addfb2(struct drm_device *dev, | |||
2392 | int drm_mode_rmfb(struct drm_device *dev, | 2436 | int drm_mode_rmfb(struct drm_device *dev, |
2393 | void *data, struct drm_file *file_priv) | 2437 | void *data, struct drm_file *file_priv) |
2394 | { | 2438 | { |
2395 | struct drm_mode_object *obj; | ||
2396 | struct drm_framebuffer *fb = NULL; | 2439 | struct drm_framebuffer *fb = NULL; |
2397 | struct drm_framebuffer *fbl = NULL; | 2440 | struct drm_framebuffer *fbl = NULL; |
2398 | uint32_t *id = data; | 2441 | uint32_t *id = data; |
@@ -2403,16 +2446,13 @@ int drm_mode_rmfb(struct drm_device *dev, | |||
2403 | return -EINVAL; | 2446 | return -EINVAL; |
2404 | 2447 | ||
2405 | drm_modeset_lock_all(dev); | 2448 | drm_modeset_lock_all(dev); |
2406 | mutex_lock(&dev->mode_config.fb_lock); | 2449 | fb = drm_framebuffer_lookup(dev, *id); |
2407 | obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB); | 2450 | if (!fb) { |
2408 | /* TODO check that we really get a framebuffer back. */ | ||
2409 | if (!obj) { | ||
2410 | mutex_unlock(&dev->mode_config.fb_lock); | ||
2411 | ret = -EINVAL; | 2451 | ret = -EINVAL; |
2412 | goto out; | 2452 | goto out; |
2413 | } | 2453 | } |
2414 | fb = obj_to_fb(obj); | 2454 | /* fb is protect by the mode_config lock, so drop the ref immediately */ |
2415 | mutex_unlock(&dev->mode_config.fb_lock); | 2455 | drm_framebuffer_unreference(fb); |
2416 | 2456 | ||
2417 | mutex_lock(&file_priv->fbs_lock); | 2457 | mutex_lock(&file_priv->fbs_lock); |
2418 | list_for_each_entry(fbl, &file_priv->fbs, filp_head) | 2458 | list_for_each_entry(fbl, &file_priv->fbs, filp_head) |
@@ -2451,7 +2491,6 @@ int drm_mode_getfb(struct drm_device *dev, | |||
2451 | void *data, struct drm_file *file_priv) | 2491 | void *data, struct drm_file *file_priv) |
2452 | { | 2492 | { |
2453 | struct drm_mode_fb_cmd *r = data; | 2493 | struct drm_mode_fb_cmd *r = data; |
2454 | struct drm_mode_object *obj; | ||
2455 | struct drm_framebuffer *fb; | 2494 | struct drm_framebuffer *fb; |
2456 | int ret = 0; | 2495 | int ret = 0; |
2457 | 2496 | ||
@@ -2459,14 +2498,13 @@ int drm_mode_getfb(struct drm_device *dev, | |||
2459 | return -EINVAL; | 2498 | return -EINVAL; |
2460 | 2499 | ||
2461 | drm_modeset_lock_all(dev); | 2500 | drm_modeset_lock_all(dev); |
2462 | mutex_lock(&dev->mode_config.fb_lock); | 2501 | fb = drm_framebuffer_lookup(dev, r->fb_id); |
2463 | obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); | 2502 | if (!fb) { |
2464 | mutex_unlock(&dev->mode_config.fb_lock); | ||
2465 | if (!obj) { | ||
2466 | ret = -EINVAL; | 2503 | ret = -EINVAL; |
2467 | goto out; | 2504 | goto out; |
2468 | } | 2505 | } |
2469 | fb = obj_to_fb(obj); | 2506 | /* fb is protect by the mode_config lock, so drop the ref immediately */ |
2507 | drm_framebuffer_unreference(fb); | ||
2470 | 2508 | ||
2471 | r->height = fb->height; | 2509 | r->height = fb->height; |
2472 | r->width = fb->width; | 2510 | r->width = fb->width; |
@@ -2489,7 +2527,6 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, | |||
2489 | struct drm_clip_rect __user *clips_ptr; | 2527 | struct drm_clip_rect __user *clips_ptr; |
2490 | struct drm_clip_rect *clips = NULL; | 2528 | struct drm_clip_rect *clips = NULL; |
2491 | struct drm_mode_fb_dirty_cmd *r = data; | 2529 | struct drm_mode_fb_dirty_cmd *r = data; |
2492 | struct drm_mode_object *obj; | ||
2493 | struct drm_framebuffer *fb; | 2530 | struct drm_framebuffer *fb; |
2494 | unsigned flags; | 2531 | unsigned flags; |
2495 | int num_clips; | 2532 | int num_clips; |
@@ -2499,14 +2536,13 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, | |||
2499 | return -EINVAL; | 2536 | return -EINVAL; |
2500 | 2537 | ||
2501 | drm_modeset_lock_all(dev); | 2538 | drm_modeset_lock_all(dev); |
2502 | mutex_lock(&dev->mode_config.fb_lock); | 2539 | fb = drm_framebuffer_lookup(dev, r->fb_id); |
2503 | obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); | 2540 | if (!fb) { |
2504 | mutex_unlock(&dev->mode_config.fb_lock); | ||
2505 | if (!obj) { | ||
2506 | ret = -EINVAL; | 2541 | ret = -EINVAL; |
2507 | goto out_err1; | 2542 | goto out_err1; |
2508 | } | 2543 | } |
2509 | fb = obj_to_fb(obj); | 2544 | /* fb is protect by the mode_config lock, so drop the ref immediately */ |
2545 | drm_framebuffer_unreference(fb); | ||
2510 | 2546 | ||
2511 | num_clips = r->num_clips; | 2547 | num_clips = r->num_clips; |
2512 | clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; | 2548 | 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, | |||
3586 | if (crtc->funcs->page_flip == NULL) | 3622 | if (crtc->funcs->page_flip == NULL) |
3587 | goto out; | 3623 | goto out; |
3588 | 3624 | ||
3589 | mutex_lock(&dev->mode_config.fb_lock); | 3625 | fb = drm_framebuffer_lookup(dev, page_flip->fb_id); |
3590 | obj = drm_mode_object_find(dev, page_flip->fb_id, DRM_MODE_OBJECT_FB); | 3626 | if (!fb) |
3591 | mutex_unlock(&dev->mode_config.fb_lock); | ||
3592 | if (!obj) | ||
3593 | goto out; | 3627 | goto out; |
3594 | fb = obj_to_fb(obj); | 3628 | /* fb is protect by the mode_config lock, so drop the ref immediately */ |
3629 | drm_framebuffer_unreference(fb); | ||
3595 | 3630 | ||
3596 | hdisplay = crtc->mode.hdisplay; | 3631 | hdisplay = crtc->mode.hdisplay; |
3597 | vdisplay = crtc->mode.vdisplay; | 3632 | vdisplay = crtc->mode.vdisplay; |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 0d6a161b204b..1b8f428accae 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | |||
@@ -131,7 +131,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, | |||
131 | struct vmw_master *vmaster = vmw_master(file_priv->master); | 131 | struct vmw_master *vmaster = vmw_master(file_priv->master); |
132 | struct drm_vmw_rect __user *clips_ptr; | 132 | struct drm_vmw_rect __user *clips_ptr; |
133 | struct drm_vmw_rect *clips = NULL; | 133 | struct drm_vmw_rect *clips = NULL; |
134 | struct drm_mode_object *obj; | 134 | struct drm_framebuffer *fb; |
135 | struct vmw_framebuffer *vfb; | 135 | struct vmw_framebuffer *vfb; |
136 | struct vmw_resource *res; | 136 | struct vmw_resource *res; |
137 | uint32_t num_clips; | 137 | uint32_t num_clips; |
@@ -165,15 +165,15 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, | |||
165 | 165 | ||
166 | drm_modeset_lock_all(dev); | 166 | drm_modeset_lock_all(dev); |
167 | 167 | ||
168 | mutex_lock(&dev->mode_config.fb_lock); | 168 | fb = drm_framebuffer_lookup(dev, arg->fb_id); |
169 | obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB); | 169 | if (!fb) { |
170 | mutex_unlock(&dev->mode_config.fb_lock); | ||
171 | if (!obj) { | ||
172 | DRM_ERROR("Invalid framebuffer id.\n"); | 170 | DRM_ERROR("Invalid framebuffer id.\n"); |
173 | ret = -EINVAL; | 171 | ret = -EINVAL; |
174 | goto out_no_fb; | 172 | goto out_no_fb; |
175 | } | 173 | } |
176 | vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj)); | 174 | /* fb is protect by the mode_config lock, so drop the ref immediately */ |
175 | drm_framebuffer_unreference(fb); | ||
176 | vfb = vmw_framebuffer_to_vfb(fb); | ||
177 | 177 | ||
178 | ret = ttm_read_lock(&vmaster->lock, true); | 178 | ret = ttm_read_lock(&vmaster->lock, true); |
179 | if (unlikely(ret != 0)) | 179 | if (unlikely(ret != 0)) |
@@ -217,7 +217,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, | |||
217 | struct vmw_master *vmaster = vmw_master(file_priv->master); | 217 | struct vmw_master *vmaster = vmw_master(file_priv->master); |
218 | struct drm_vmw_rect __user *clips_ptr; | 218 | struct drm_vmw_rect __user *clips_ptr; |
219 | struct drm_vmw_rect *clips = NULL; | 219 | struct drm_vmw_rect *clips = NULL; |
220 | struct drm_mode_object *obj; | 220 | struct drm_framebuffer *fb; |
221 | struct vmw_framebuffer *vfb; | 221 | struct vmw_framebuffer *vfb; |
222 | uint32_t num_clips; | 222 | uint32_t num_clips; |
223 | int ret; | 223 | int ret; |
@@ -250,16 +250,16 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, | |||
250 | 250 | ||
251 | drm_modeset_lock_all(dev); | 251 | drm_modeset_lock_all(dev); |
252 | 252 | ||
253 | mutex_lock(&dev->mode_config.fb_lock); | 253 | fb = drm_framebuffer_lookup(dev, arg->fb_id); |
254 | obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB); | 254 | if (!fb) { |
255 | mutex_unlock(&dev->mode_config.fb_lock); | ||
256 | if (!obj) { | ||
257 | DRM_ERROR("Invalid framebuffer id.\n"); | 255 | DRM_ERROR("Invalid framebuffer id.\n"); |
258 | ret = -EINVAL; | 256 | ret = -EINVAL; |
259 | goto out_no_fb; | 257 | goto out_no_fb; |
260 | } | 258 | } |
259 | /* fb is protect by the mode_config lock, so drop the ref immediately */ | ||
260 | drm_framebuffer_unreference(fb); | ||
261 | 261 | ||
262 | vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj)); | 262 | vfb = vmw_framebuffer_to_vfb(fb); |
263 | if (!vfb->dmabuf) { | 263 | if (!vfb->dmabuf) { |
264 | DRM_ERROR("Framebuffer not dmabuf backed.\n"); | 264 | DRM_ERROR("Framebuffer not dmabuf backed.\n"); |
265 | ret = -EINVAL; | 265 | ret = -EINVAL; |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index c35a807d7e5c..7dc1b31059d4 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -958,6 +958,8 @@ extern void drm_framebuffer_set_object(struct drm_device *dev, | |||
958 | extern int drm_framebuffer_init(struct drm_device *dev, | 958 | extern int drm_framebuffer_init(struct drm_device *dev, |
959 | struct drm_framebuffer *fb, | 959 | struct drm_framebuffer *fb, |
960 | const struct drm_framebuffer_funcs *funcs); | 960 | const struct drm_framebuffer_funcs *funcs); |
961 | extern struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, | ||
962 | uint32_t id); | ||
961 | extern void drm_framebuffer_unreference(struct drm_framebuffer *fb); | 963 | extern void drm_framebuffer_unreference(struct drm_framebuffer *fb); |
962 | extern void drm_framebuffer_reference(struct drm_framebuffer *fb); | 964 | extern void drm_framebuffer_reference(struct drm_framebuffer *fb); |
963 | extern void drm_framebuffer_remove(struct drm_framebuffer *fb); | 965 | extern void drm_framebuffer_remove(struct drm_framebuffer *fb); |