diff options
| author | Maarten Lankhorst <maarten.lankhorst@canonical.com> | 2013-09-02 10:31:31 -0400 |
|---|---|---|
| committer | Ben Skeggs <bskeggs@redhat.com> | 2013-09-03 23:48:56 -0400 |
| commit | c859074e7d804a254f318bb55ba1b39893247fc7 (patch) | |
| tree | 1bebcf449ab043da0fd5a90ee466131bc0f6ee47 /drivers | |
| parent | c072470f4e9abdde7cdf1c850b8826f32f9e79e3 (diff) | |
drm/nouveau: fix command submission to use vmalloc for big allocations
I was getting a order 4 allocation failure from kmalloc when testing some
game after a few days uptime with some suspend/resumes.
For big allocations vmalloc should be used instead.
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@canonical.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_gem.c | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 487242fb3fdc..f32b71238c03 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c | |||
| @@ -579,18 +579,31 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, | |||
| 579 | return 0; | 579 | return 0; |
| 580 | } | 580 | } |
| 581 | 581 | ||
| 582 | static inline void | ||
| 583 | u_free(void *addr) | ||
| 584 | { | ||
| 585 | if (!is_vmalloc_addr(addr)) | ||
| 586 | kfree(addr); | ||
| 587 | else | ||
| 588 | vfree(addr); | ||
| 589 | } | ||
| 590 | |||
| 582 | static inline void * | 591 | static inline void * |
| 583 | u_memcpya(uint64_t user, unsigned nmemb, unsigned size) | 592 | u_memcpya(uint64_t user, unsigned nmemb, unsigned size) |
| 584 | { | 593 | { |
| 585 | void *mem; | 594 | void *mem; |
| 586 | void __user *userptr = (void __force __user *)(uintptr_t)user; | 595 | void __user *userptr = (void __force __user *)(uintptr_t)user; |
| 587 | 596 | ||
| 588 | mem = kmalloc(nmemb * size, GFP_KERNEL); | 597 | size *= nmemb; |
| 598 | |||
| 599 | mem = kmalloc(size, GFP_KERNEL | __GFP_NOWARN); | ||
| 600 | if (!mem) | ||
| 601 | mem = vmalloc(size); | ||
| 589 | if (!mem) | 602 | if (!mem) |
| 590 | return ERR_PTR(-ENOMEM); | 603 | return ERR_PTR(-ENOMEM); |
| 591 | 604 | ||
| 592 | if (DRM_COPY_FROM_USER(mem, userptr, nmemb * size)) { | 605 | if (DRM_COPY_FROM_USER(mem, userptr, size)) { |
| 593 | kfree(mem); | 606 | u_free(mem); |
| 594 | return ERR_PTR(-EFAULT); | 607 | return ERR_PTR(-EFAULT); |
| 595 | } | 608 | } |
| 596 | 609 | ||
| @@ -676,7 +689,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, | |||
| 676 | nouveau_bo_wr32(nvbo, r->reloc_bo_offset >> 2, data); | 689 | nouveau_bo_wr32(nvbo, r->reloc_bo_offset >> 2, data); |
| 677 | } | 690 | } |
| 678 | 691 | ||
| 679 | kfree(reloc); | 692 | u_free(reloc); |
| 680 | return ret; | 693 | return ret; |
| 681 | } | 694 | } |
| 682 | 695 | ||
| @@ -738,7 +751,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, | |||
| 738 | 751 | ||
| 739 | bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo)); | 752 | bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo)); |
| 740 | if (IS_ERR(bo)) { | 753 | if (IS_ERR(bo)) { |
| 741 | kfree(push); | 754 | u_free(push); |
| 742 | return nouveau_abi16_put(abi16, PTR_ERR(bo)); | 755 | return nouveau_abi16_put(abi16, PTR_ERR(bo)); |
| 743 | } | 756 | } |
| 744 | 757 | ||
| @@ -849,8 +862,8 @@ out: | |||
| 849 | nouveau_fence_unref(&fence); | 862 | nouveau_fence_unref(&fence); |
| 850 | 863 | ||
| 851 | out_prevalid: | 864 | out_prevalid: |
| 852 | kfree(bo); | 865 | u_free(bo); |
| 853 | kfree(push); | 866 | u_free(push); |
| 854 | 867 | ||
| 855 | out_next: | 868 | out_next: |
| 856 | if (chan->dma.ib_max) { | 869 | if (chan->dma.ib_max) { |
