aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2014-01-12 22:55:48 -0500
committerDave Airlie <airlied@redhat.com>2014-01-12 22:55:48 -0500
commitca2a2bb13efd1cb42c227d3e2ddac35708146cc1 (patch)
tree7cd017a0a4bdf262797ed5c75e947065076ab115 /drivers/gpu
parente95d9f9550358c39d82d32aa53a3867867216103 (diff)
parent8dd9ad5d3bf4759399e0c716dd065e7d90eee102 (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.c21
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.c74
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.h3
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
157static const struct file_operations exynos_drm_gem_fops = {
158 .mmap = exynos_drm_gem_mmap_buffer,
159};
160
155static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) 161static 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,
181static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) 198static 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 {
226struct drm_exynos_file_private { 226struct 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 }
711out: 711out:
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
341static struct drm_file *exynos_drm_find_drm_file(struct drm_device *drm_dev, 341int 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
356static 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
414static const struct file_operations exynos_drm_gem_fops = {
415 .mmap = exynos_drm_gem_mmap_buffer,
416};
417
418int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data, 390int 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,
122int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data, 122int 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
125int 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. */
126int exynos_drm_gem_userptr_ioctl(struct drm_device *dev, void *data, 129int exynos_drm_gem_userptr_ioctl(struct drm_device *dev, void *data,
127 struct drm_file *file_priv); 130 struct drm_file *file_priv);