diff options
author | Inki Dae <inki.dae@samsung.com> | 2012-11-08 07:52:54 -0500 |
---|---|---|
committer | Inki Dae <inki.dae@samsung.com> | 2012-12-04 00:46:02 -0500 |
commit | 5b07c66059313fc998d28cf6775fd1a8bbb034aa (patch) | |
tree | 8a2cc3935ae3cb603b9ee5fbd65c680f2c832a03 | |
parent | 2a3098ff6c2109557868f9f230f4725312dcb882 (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.c | 75 |
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 | ||
352 | static 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 | |||
352 | static int exynos_drm_gem_mmap_buffer(struct file *filp, | 373 | static 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 | ||
383 | static const struct file_operations exynos_drm_gem_fops = { | 435 | static 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 | ||