diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_gem.c')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_gem.c | 79 |
1 files changed, 42 insertions, 37 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index fa1aa94a3d8e..1dffa8359f88 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c | |||
@@ -56,9 +56,28 @@ static unsigned int convert_to_vm_err_msg(int msg) | |||
56 | return out_msg; | 56 | return out_msg; |
57 | } | 57 | } |
58 | 58 | ||
59 | static unsigned int mask_gem_flags(unsigned int flags) | 59 | static int check_gem_flags(unsigned int flags) |
60 | { | 60 | { |
61 | return flags &= EXYNOS_BO_NONCONTIG; | 61 | if (flags & ~(EXYNOS_BO_MASK)) { |
62 | DRM_ERROR("invalid flags.\n"); | ||
63 | return -EINVAL; | ||
64 | } | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static unsigned long roundup_gem_size(unsigned long size, unsigned int flags) | ||
70 | { | ||
71 | if (!IS_NONCONTIG_BUFFER(flags)) { | ||
72 | if (size >= SZ_1M) | ||
73 | return roundup(size, SECTION_SIZE); | ||
74 | else if (size >= SZ_64K) | ||
75 | return roundup(size, SZ_64K); | ||
76 | else | ||
77 | goto out; | ||
78 | } | ||
79 | out: | ||
80 | return roundup(size, PAGE_SIZE); | ||
62 | } | 81 | } |
63 | 82 | ||
64 | static struct page **exynos_gem_get_pages(struct drm_gem_object *obj, | 83 | static struct page **exynos_gem_get_pages(struct drm_gem_object *obj, |
@@ -130,22 +149,12 @@ static int exynos_drm_gem_map_pages(struct drm_gem_object *obj, | |||
130 | unsigned long pfn; | 149 | unsigned long pfn; |
131 | 150 | ||
132 | if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) { | 151 | if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) { |
133 | unsigned long usize = buf->size; | ||
134 | |||
135 | if (!buf->pages) | 152 | if (!buf->pages) |
136 | return -EINTR; | 153 | return -EINTR; |
137 | 154 | ||
138 | while (usize > 0) { | 155 | pfn = page_to_pfn(buf->pages[page_offset++]); |
139 | pfn = page_to_pfn(buf->pages[page_offset++]); | 156 | } else |
140 | vm_insert_mixed(vma, f_vaddr, pfn); | 157 | pfn = (buf->dma_addr >> PAGE_SHIFT) + page_offset; |
141 | f_vaddr += PAGE_SIZE; | ||
142 | usize -= PAGE_SIZE; | ||
143 | } | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | pfn = (buf->dma_addr >> PAGE_SHIFT) + page_offset; | ||
149 | 158 | ||
150 | return vm_insert_mixed(vma, f_vaddr, pfn); | 159 | return vm_insert_mixed(vma, f_vaddr, pfn); |
151 | } | 160 | } |
@@ -319,10 +328,17 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, | |||
319 | struct exynos_drm_gem_buf *buf; | 328 | struct exynos_drm_gem_buf *buf; |
320 | int ret; | 329 | int ret; |
321 | 330 | ||
322 | size = roundup(size, PAGE_SIZE); | 331 | if (!size) { |
323 | DRM_DEBUG_KMS("%s: size = 0x%lx\n", __FILE__, size); | 332 | DRM_ERROR("invalid size.\n"); |
333 | return ERR_PTR(-EINVAL); | ||
334 | } | ||
335 | |||
336 | size = roundup_gem_size(size, flags); | ||
337 | DRM_DEBUG_KMS("%s\n", __FILE__); | ||
324 | 338 | ||
325 | flags = mask_gem_flags(flags); | 339 | ret = check_gem_flags(flags); |
340 | if (ret) | ||
341 | return ERR_PTR(ret); | ||
326 | 342 | ||
327 | buf = exynos_drm_init_buf(dev, size); | 343 | buf = exynos_drm_init_buf(dev, size); |
328 | if (!buf) | 344 | if (!buf) |
@@ -331,7 +347,7 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, | |||
331 | exynos_gem_obj = exynos_drm_gem_init(dev, size); | 347 | exynos_gem_obj = exynos_drm_gem_init(dev, size); |
332 | if (!exynos_gem_obj) { | 348 | if (!exynos_gem_obj) { |
333 | ret = -ENOMEM; | 349 | ret = -ENOMEM; |
334 | goto err; | 350 | goto err_fini_buf; |
335 | } | 351 | } |
336 | 352 | ||
337 | exynos_gem_obj->buffer = buf; | 353 | exynos_gem_obj->buffer = buf; |
@@ -347,18 +363,19 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, | |||
347 | ret = exynos_drm_gem_get_pages(&exynos_gem_obj->base); | 363 | ret = exynos_drm_gem_get_pages(&exynos_gem_obj->base); |
348 | if (ret < 0) { | 364 | if (ret < 0) { |
349 | drm_gem_object_release(&exynos_gem_obj->base); | 365 | drm_gem_object_release(&exynos_gem_obj->base); |
350 | goto err; | 366 | goto err_fini_buf; |
351 | } | 367 | } |
352 | } else { | 368 | } else { |
353 | ret = exynos_drm_alloc_buf(dev, buf, flags); | 369 | ret = exynos_drm_alloc_buf(dev, buf, flags); |
354 | if (ret < 0) { | 370 | if (ret < 0) { |
355 | drm_gem_object_release(&exynos_gem_obj->base); | 371 | drm_gem_object_release(&exynos_gem_obj->base); |
356 | goto err; | 372 | goto err_fini_buf; |
357 | } | 373 | } |
358 | } | 374 | } |
359 | 375 | ||
360 | return exynos_gem_obj; | 376 | return exynos_gem_obj; |
361 | err: | 377 | |
378 | err_fini_buf: | ||
362 | exynos_drm_fini_buf(dev, buf); | 379 | exynos_drm_fini_buf(dev, buf); |
363 | return ERR_PTR(ret); | 380 | return ERR_PTR(ret); |
364 | } | 381 | } |
@@ -497,6 +514,8 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp, | |||
497 | if (!buffer->pages) | 514 | if (!buffer->pages) |
498 | return -EINVAL; | 515 | return -EINVAL; |
499 | 516 | ||
517 | vma->vm_flags |= VM_MIXEDMAP; | ||
518 | |||
500 | do { | 519 | do { |
501 | ret = vm_insert_page(vma, uaddr, buffer->pages[i++]); | 520 | ret = vm_insert_page(vma, uaddr, buffer->pages[i++]); |
502 | if (ret) { | 521 | if (ret) { |
@@ -554,10 +573,8 @@ int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data, | |||
554 | obj->filp->f_op = &exynos_drm_gem_fops; | 573 | obj->filp->f_op = &exynos_drm_gem_fops; |
555 | obj->filp->private_data = obj; | 574 | obj->filp->private_data = obj; |
556 | 575 | ||
557 | down_write(¤t->mm->mmap_sem); | 576 | addr = vm_mmap(obj->filp, 0, args->size, |
558 | addr = do_mmap(obj->filp, 0, args->size, | ||
559 | PROT_READ | PROT_WRITE, MAP_SHARED, 0); | 577 | PROT_READ | PROT_WRITE, MAP_SHARED, 0); |
560 | up_write(¤t->mm->mmap_sem); | ||
561 | 578 | ||
562 | drm_gem_object_unreference_unlocked(obj); | 579 | drm_gem_object_unreference_unlocked(obj); |
563 | 580 | ||
@@ -685,7 +702,6 @@ int exynos_drm_gem_dumb_destroy(struct drm_file *file_priv, | |||
685 | int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | 702 | int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) |
686 | { | 703 | { |
687 | struct drm_gem_object *obj = vma->vm_private_data; | 704 | struct drm_gem_object *obj = vma->vm_private_data; |
688 | struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); | ||
689 | struct drm_device *dev = obj->dev; | 705 | struct drm_device *dev = obj->dev; |
690 | unsigned long f_vaddr; | 706 | unsigned long f_vaddr; |
691 | pgoff_t page_offset; | 707 | pgoff_t page_offset; |
@@ -697,21 +713,10 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
697 | 713 | ||
698 | mutex_lock(&dev->struct_mutex); | 714 | mutex_lock(&dev->struct_mutex); |
699 | 715 | ||
700 | /* | ||
701 | * allocate all pages as desired size if user wants to allocate | ||
702 | * physically non-continuous memory. | ||
703 | */ | ||
704 | if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) { | ||
705 | ret = exynos_drm_gem_get_pages(obj); | ||
706 | if (ret < 0) | ||
707 | goto err; | ||
708 | } | ||
709 | |||
710 | ret = exynos_drm_gem_map_pages(obj, vma, f_vaddr, page_offset); | 716 | ret = exynos_drm_gem_map_pages(obj, vma, f_vaddr, page_offset); |
711 | if (ret < 0) | 717 | if (ret < 0) |
712 | DRM_ERROR("failed to map pages.\n"); | 718 | DRM_ERROR("failed to map pages.\n"); |
713 | 719 | ||
714 | err: | ||
715 | mutex_unlock(&dev->struct_mutex); | 720 | mutex_unlock(&dev->struct_mutex); |
716 | 721 | ||
717 | return convert_to_vm_err_msg(ret); | 722 | return convert_to_vm_err_msg(ret); |