diff options
author | Dave Airlie <airlied@redhat.com> | 2014-01-12 22:55:48 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2014-01-12 22:55:48 -0500 |
commit | ca2a2bb13efd1cb42c227d3e2ddac35708146cc1 (patch) | |
tree | 7cd017a0a4bdf262797ed5c75e947065076ab115 /drivers/gpu | |
parent | e95d9f9550358c39d82d32aa53a3867867216103 (diff) | |
parent | 8dd9ad5d3bf4759399e0c716dd065e7d90eee102 (diff) |
Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
This pull request adds an anon file for exynos specific mmaper
to resolve potential a dead lock issue pointed out by Al Viro,
and fixes build break of drm-next.
* 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos:
drm/exynos: fix build error caused by removed drm core macros
drm/exynos: use a new anon file for exynos gem mmaper
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_drv.c | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fimd.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_gem.c | 74 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_gem.h | 3 |
5 files changed, 40 insertions, 63 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 7e074a4d2848..9d096a0c5f8d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c | |||
@@ -14,6 +14,8 @@ | |||
14 | #include <drm/drmP.h> | 14 | #include <drm/drmP.h> |
15 | #include <drm/drm_crtc_helper.h> | 15 | #include <drm/drm_crtc_helper.h> |
16 | 16 | ||
17 | #include <linux/anon_inodes.h> | ||
18 | |||
17 | #include <drm/exynos_drm.h> | 19 | #include <drm/exynos_drm.h> |
18 | 20 | ||
19 | #include "exynos_drm_drv.h" | 21 | #include "exynos_drm_drv.h" |
@@ -152,9 +154,14 @@ static int exynos_drm_unload(struct drm_device *dev) | |||
152 | return 0; | 154 | return 0; |
153 | } | 155 | } |
154 | 156 | ||
157 | static const struct file_operations exynos_drm_gem_fops = { | ||
158 | .mmap = exynos_drm_gem_mmap_buffer, | ||
159 | }; | ||
160 | |||
155 | static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) | 161 | static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) |
156 | { | 162 | { |
157 | struct drm_exynos_file_private *file_priv; | 163 | struct drm_exynos_file_private *file_priv; |
164 | struct file *anon_filp; | ||
158 | int ret; | 165 | int ret; |
159 | 166 | ||
160 | file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL); | 167 | file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL); |
@@ -169,6 +176,16 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) | |||
169 | file->driver_priv = NULL; | 176 | file->driver_priv = NULL; |
170 | } | 177 | } |
171 | 178 | ||
179 | anon_filp = anon_inode_getfile("exynos_gem", &exynos_drm_gem_fops, | ||
180 | NULL, 0); | ||
181 | if (IS_ERR(anon_filp)) { | ||
182 | kfree(file_priv); | ||
183 | return PTR_ERR(anon_filp); | ||
184 | } | ||
185 | |||
186 | anon_filp->f_mode = FMODE_READ | FMODE_WRITE; | ||
187 | file_priv->anon_filp = anon_filp; | ||
188 | |||
172 | return ret; | 189 | return ret; |
173 | } | 190 | } |
174 | 191 | ||
@@ -181,6 +198,7 @@ static void exynos_drm_preclose(struct drm_device *dev, | |||
181 | static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) | 198 | static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) |
182 | { | 199 | { |
183 | struct exynos_drm_private *private = dev->dev_private; | 200 | struct exynos_drm_private *private = dev->dev_private; |
201 | struct drm_exynos_file_private *file_priv; | ||
184 | struct drm_pending_vblank_event *v, *vt; | 202 | struct drm_pending_vblank_event *v, *vt; |
185 | struct drm_pending_event *e, *et; | 203 | struct drm_pending_event *e, *et; |
186 | unsigned long flags; | 204 | unsigned long flags; |
@@ -206,6 +224,9 @@ static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) | |||
206 | } | 224 | } |
207 | spin_unlock_irqrestore(&dev->event_lock, flags); | 225 | spin_unlock_irqrestore(&dev->event_lock, flags); |
208 | 226 | ||
227 | file_priv = file->driver_priv; | ||
228 | if (file_priv->anon_filp) | ||
229 | fput(file_priv->anon_filp); | ||
209 | 230 | ||
210 | kfree(file->driver_priv); | 231 | kfree(file->driver_priv); |
211 | file->driver_priv = NULL; | 232 | file->driver_priv = NULL; |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index eaa19668bf00..0eaf5a27e120 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h | |||
@@ -226,6 +226,7 @@ struct exynos_drm_ipp_private { | |||
226 | struct drm_exynos_file_private { | 226 | struct drm_exynos_file_private { |
227 | struct exynos_drm_g2d_private *g2d_priv; | 227 | struct exynos_drm_g2d_private *g2d_priv; |
228 | struct exynos_drm_ipp_private *ipp_priv; | 228 | struct exynos_drm_ipp_private *ipp_priv; |
229 | struct file *anon_filp; | ||
229 | }; | 230 | }; |
230 | 231 | ||
231 | /* | 232 | /* |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 267aca91b70d..a20440ce32e6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c | |||
@@ -347,7 +347,7 @@ static void fimd_wait_for_vblank(struct device *dev) | |||
347 | */ | 347 | */ |
348 | if (!wait_event_timeout(ctx->wait_vsync_queue, | 348 | if (!wait_event_timeout(ctx->wait_vsync_queue, |
349 | !atomic_read(&ctx->wait_vsync_event), | 349 | !atomic_read(&ctx->wait_vsync_event), |
350 | DRM_HZ/20)) | 350 | HZ/20)) |
351 | DRM_DEBUG_KMS("vblank wait timed out.\n"); | 351 | DRM_DEBUG_KMS("vblank wait timed out.\n"); |
352 | } | 352 | } |
353 | 353 | ||
@@ -706,7 +706,7 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) | |||
706 | /* set wait vsync event to zero and wake up queue. */ | 706 | /* set wait vsync event to zero and wake up queue. */ |
707 | if (atomic_read(&ctx->wait_vsync_event)) { | 707 | if (atomic_read(&ctx->wait_vsync_event)) { |
708 | atomic_set(&ctx->wait_vsync_event, 0); | 708 | atomic_set(&ctx->wait_vsync_event, 0); |
709 | DRM_WAKEUP(&ctx->wait_vsync_queue); | 709 | wake_up(&ctx->wait_vsync_queue); |
710 | } | 710 | } |
711 | out: | 711 | out: |
712 | return IRQ_HANDLED; | 712 | return IRQ_HANDLED; |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 1ade191d84f4..49b8c9b22902 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c | |||
@@ -338,46 +338,22 @@ int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data, | |||
338 | &args->offset); | 338 | &args->offset); |
339 | } | 339 | } |
340 | 340 | ||
341 | static struct drm_file *exynos_drm_find_drm_file(struct drm_device *drm_dev, | 341 | int exynos_drm_gem_mmap_buffer(struct file *filp, |
342 | struct file *filp) | ||
343 | { | ||
344 | struct drm_file *file_priv; | ||
345 | |||
346 | /* find current process's drm_file from filelist. */ | ||
347 | list_for_each_entry(file_priv, &drm_dev->filelist, lhead) | ||
348 | if (file_priv->filp == filp) | ||
349 | return file_priv; | ||
350 | |||
351 | WARN_ON(1); | ||
352 | |||
353 | return ERR_PTR(-EFAULT); | ||
354 | } | ||
355 | |||
356 | static int exynos_drm_gem_mmap_buffer(struct file *filp, | ||
357 | struct vm_area_struct *vma) | 342 | struct vm_area_struct *vma) |
358 | { | 343 | { |
359 | struct drm_gem_object *obj = filp->private_data; | 344 | struct drm_gem_object *obj = filp->private_data; |
360 | struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); | 345 | struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); |
361 | struct drm_device *drm_dev = obj->dev; | 346 | struct drm_device *drm_dev = obj->dev; |
362 | struct exynos_drm_gem_buf *buffer; | 347 | struct exynos_drm_gem_buf *buffer; |
363 | struct drm_file *file_priv; | ||
364 | unsigned long vm_size; | 348 | unsigned long vm_size; |
365 | int ret; | 349 | int ret; |
366 | 350 | ||
351 | WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); | ||
352 | |||
367 | vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; | 353 | vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; |
368 | vma->vm_private_data = obj; | 354 | vma->vm_private_data = obj; |
369 | vma->vm_ops = drm_dev->driver->gem_vm_ops; | 355 | vma->vm_ops = drm_dev->driver->gem_vm_ops; |
370 | 356 | ||
371 | /* restore it to driver's fops. */ | ||
372 | filp->f_op = fops_get(drm_dev->driver->fops); | ||
373 | |||
374 | file_priv = exynos_drm_find_drm_file(drm_dev, filp); | ||
375 | if (IS_ERR(file_priv)) | ||
376 | return PTR_ERR(file_priv); | ||
377 | |||
378 | /* restore it to drm_file. */ | ||
379 | filp->private_data = file_priv; | ||
380 | |||
381 | update_vm_cache_attr(exynos_gem_obj, vma); | 357 | update_vm_cache_attr(exynos_gem_obj, vma); |
382 | 358 | ||
383 | vm_size = vma->vm_end - vma->vm_start; | 359 | vm_size = vma->vm_end - vma->vm_start; |
@@ -411,15 +387,13 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp, | |||
411 | return 0; | 387 | return 0; |
412 | } | 388 | } |
413 | 389 | ||
414 | static const struct file_operations exynos_drm_gem_fops = { | ||
415 | .mmap = exynos_drm_gem_mmap_buffer, | ||
416 | }; | ||
417 | |||
418 | int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data, | 390 | int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data, |
419 | struct drm_file *file_priv) | 391 | struct drm_file *file_priv) |
420 | { | 392 | { |
393 | struct drm_exynos_file_private *exynos_file_priv; | ||
421 | struct drm_exynos_gem_mmap *args = data; | 394 | struct drm_exynos_gem_mmap *args = data; |
422 | struct drm_gem_object *obj; | 395 | struct drm_gem_object *obj; |
396 | struct file *anon_filp; | ||
423 | unsigned long addr; | 397 | unsigned long addr; |
424 | 398 | ||
425 | if (!(dev->driver->driver_features & DRIVER_GEM)) { | 399 | if (!(dev->driver->driver_features & DRIVER_GEM)) { |
@@ -427,47 +401,25 @@ int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data, | |||
427 | return -ENODEV; | 401 | return -ENODEV; |
428 | } | 402 | } |
429 | 403 | ||
404 | mutex_lock(&dev->struct_mutex); | ||
405 | |||
430 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | 406 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); |
431 | if (!obj) { | 407 | if (!obj) { |
432 | DRM_ERROR("failed to lookup gem object.\n"); | 408 | DRM_ERROR("failed to lookup gem object.\n"); |
409 | mutex_unlock(&dev->struct_mutex); | ||
433 | return -EINVAL; | 410 | return -EINVAL; |
434 | } | 411 | } |
435 | 412 | ||
436 | /* | 413 | exynos_file_priv = file_priv->driver_priv; |
437 | * We have to use gem object and its fops for specific mmaper, | 414 | anon_filp = exynos_file_priv->anon_filp; |
438 | * but vm_mmap() can deliver only filp. So we have to change | 415 | anon_filp->private_data = obj; |
439 | * filp->f_op and filp->private_data temporarily, then restore | ||
440 | * again. So it is important to keep lock until restoration the | ||
441 | * settings to prevent others from misuse of filp->f_op or | ||
442 | * filp->private_data. | ||
443 | */ | ||
444 | mutex_lock(&dev->struct_mutex); | ||
445 | |||
446 | /* | ||
447 | * Set specific mmper's fops. And it will be restored by | ||
448 | * exynos_drm_gem_mmap_buffer to dev->driver->fops. | ||
449 | * This is used to call specific mapper temporarily. | ||
450 | */ | ||
451 | file_priv->filp->f_op = &exynos_drm_gem_fops; | ||
452 | |||
453 | /* | ||
454 | * Set gem object to private_data so that specific mmaper | ||
455 | * can get the gem object. And it will be restored by | ||
456 | * exynos_drm_gem_mmap_buffer to drm_file. | ||
457 | */ | ||
458 | file_priv->filp->private_data = obj; | ||
459 | 416 | ||
460 | addr = vm_mmap(file_priv->filp, 0, args->size, | 417 | addr = vm_mmap(anon_filp, 0, args->size, PROT_READ | PROT_WRITE, |
461 | PROT_READ | PROT_WRITE, MAP_SHARED, 0); | 418 | MAP_SHARED, 0); |
462 | 419 | ||
463 | drm_gem_object_unreference(obj); | 420 | drm_gem_object_unreference(obj); |
464 | 421 | ||
465 | if (IS_ERR_VALUE(addr)) { | 422 | if (IS_ERR_VALUE(addr)) { |
466 | /* check filp->f_op, filp->private_data are restored */ | ||
467 | if (file_priv->filp->f_op == &exynos_drm_gem_fops) { | ||
468 | file_priv->filp->f_op = fops_get(dev->driver->fops); | ||
469 | file_priv->filp->private_data = file_priv; | ||
470 | } | ||
471 | mutex_unlock(&dev->struct_mutex); | 423 | mutex_unlock(&dev->struct_mutex); |
472 | return (int)addr; | 424 | return (int)addr; |
473 | } | 425 | } |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index 702ec3abe85c..fde860c7eba3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h | |||
@@ -122,6 +122,9 @@ int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data, | |||
122 | int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data, | 122 | int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data, |
123 | struct drm_file *file_priv); | 123 | struct drm_file *file_priv); |
124 | 124 | ||
125 | int exynos_drm_gem_mmap_buffer(struct file *filp, | ||
126 | struct vm_area_struct *vma); | ||
127 | |||
125 | /* map user space allocated by malloc to pages. */ | 128 | /* map user space allocated by malloc to pages. */ |
126 | int exynos_drm_gem_userptr_ioctl(struct drm_device *dev, void *data, | 129 | int exynos_drm_gem_userptr_ioctl(struct drm_device *dev, void *data, |
127 | struct drm_file *file_priv); | 130 | struct drm_file *file_priv); |