aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorInki Dae <inki.dae@samsung.com>2012-11-08 07:52:54 -0500
committerInki Dae <inki.dae@samsung.com>2012-12-04 00:46:02 -0500
commit5b07c66059313fc998d28cf6775fd1a8bbb034aa (patch)
tree8a2cc3935ae3cb603b9ee5fbd65c680f2c832a03
parent2a3098ff6c2109557868f9f230f4725312dcb882 (diff)
drm/exynos: add vm_ops to specific gem mmaper
Changelog v3: use drm_file's file object instead of gem object's - gem object's file represents the shmem storage so process-unique file object should be used instead. Changelog v2: call mutex_lock before drm_vm_open_locked is called. Changelog v1: This patch makes it takes a reference to gem object when specific gem mmap is requested. For this, it sets dev->driver->gem_vm_ops to vma->vm_ops. And this patch is based on exynos-drm-next-iommu branch of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos Signed-off-by: Inki Dae <inki.dae@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.c75
1 files changed, 70 insertions, 5 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 2cc6b3ae4e07..52187aec8692 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -349,17 +349,53 @@ int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
349 &args->offset); 349 &args->offset);
350} 350}
351 351
352static struct drm_file *exynos_drm_find_drm_file(struct drm_device *drm_dev,
353 struct file *filp)
354{
355 struct drm_file *file_priv;
356
357 mutex_lock(&drm_dev->struct_mutex);
358
359 /* find current process's drm_file from filelist. */
360 list_for_each_entry(file_priv, &drm_dev->filelist, lhead) {
361 if (file_priv->filp == filp) {
362 mutex_unlock(&drm_dev->struct_mutex);
363 return file_priv;
364 }
365 }
366
367 mutex_unlock(&drm_dev->struct_mutex);
368 WARN_ON(1);
369
370 return ERR_PTR(-EFAULT);
371}
372
352static int exynos_drm_gem_mmap_buffer(struct file *filp, 373static int exynos_drm_gem_mmap_buffer(struct file *filp,
353 struct vm_area_struct *vma) 374 struct vm_area_struct *vma)
354{ 375{
355 struct drm_gem_object *obj = filp->private_data; 376 struct drm_gem_object *obj = filp->private_data;
356 struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); 377 struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
378 struct drm_device *drm_dev = obj->dev;
357 struct exynos_drm_gem_buf *buffer; 379 struct exynos_drm_gem_buf *buffer;
380 struct drm_file *file_priv;
358 unsigned long vm_size; 381 unsigned long vm_size;
382 int ret;
359 383
360 DRM_DEBUG_KMS("%s\n", __FILE__); 384 DRM_DEBUG_KMS("%s\n", __FILE__);
361 385
362 vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; 386 vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
387 vma->vm_private_data = obj;
388 vma->vm_ops = drm_dev->driver->gem_vm_ops;
389
390 /* restore it to driver's fops. */
391 filp->f_op = fops_get(drm_dev->driver->fops);
392
393 file_priv = exynos_drm_find_drm_file(drm_dev, filp);
394 if (IS_ERR(file_priv))
395 return PTR_ERR(file_priv);
396
397 /* restore it to drm_file. */
398 filp->private_data = file_priv;
363 399
364 update_vm_cache_attr(exynos_gem_obj, vma); 400 update_vm_cache_attr(exynos_gem_obj, vma);
365 401
@@ -375,9 +411,25 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
375 if (vm_size > buffer->size) 411 if (vm_size > buffer->size)
376 return -EINVAL; 412 return -EINVAL;
377 413
378 return dma_mmap_attrs(obj->dev->dev, vma, buffer->kvaddr, 414 ret = dma_mmap_attrs(drm_dev->dev, vma, buffer->kvaddr,
379 buffer->dma_addr, buffer->size, 415 buffer->dma_addr, buffer->size,
380 &buffer->dma_attrs); 416 &buffer->dma_attrs);
417 if (ret < 0) {
418 DRM_ERROR("failed to mmap.\n");
419 return ret;
420 }
421
422 /*
423 * take a reference to this mapping of the object. And this reference
424 * is unreferenced by the corresponding vm_close call.
425 */
426 drm_gem_object_reference(obj);
427
428 mutex_lock(&drm_dev->struct_mutex);
429 drm_vm_open_locked(drm_dev, vma);
430 mutex_unlock(&drm_dev->struct_mutex);
431
432 return 0;
381} 433}
382 434
383static const struct file_operations exynos_drm_gem_fops = { 435static const struct file_operations exynos_drm_gem_fops = {
@@ -404,16 +456,29 @@ int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
404 return -EINVAL; 456 return -EINVAL;
405 } 457 }
406 458
407 obj->filp->f_op = &exynos_drm_gem_fops; 459 /*
408 obj->filp->private_data = obj; 460 * Set specific mmper's fops. And it will be restored by
461 * exynos_drm_gem_mmap_buffer to dev->driver->fops.
462 * This is used to call specific mapper temporarily.
463 */
464 file_priv->filp->f_op = &exynos_drm_gem_fops;
465
466 /*
467 * Set gem object to private_data so that specific mmaper
468 * can get the gem object. And it will be restored by
469 * exynos_drm_gem_mmap_buffer to drm_file.
470 */
471 file_priv->filp->private_data = obj;
409 472
410 addr = vm_mmap(obj->filp, 0, args->size, 473 addr = vm_mmap(file_priv->filp, 0, args->size,
411 PROT_READ | PROT_WRITE, MAP_SHARED, 0); 474 PROT_READ | PROT_WRITE, MAP_SHARED, 0);
412 475
413 drm_gem_object_unreference_unlocked(obj); 476 drm_gem_object_unreference_unlocked(obj);
414 477
415 if (IS_ERR((void *)addr)) 478 if (IS_ERR((void *)addr)) {
479 file_priv->filp->private_data = file_priv;
416 return PTR_ERR((void *)addr); 480 return PTR_ERR((void *)addr);
481 }
417 482
418 args->mapped = addr; 483 args->mapped = addr;
419 484