aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_gem.c
diff options
context:
space:
mode:
authorMaarten Lankhorst <maarten.lankhorst@canonical.com>2013-09-02 10:31:31 -0400
committerBen Skeggs <bskeggs@redhat.com>2013-09-03 23:48:56 -0400
commitc859074e7d804a254f318bb55ba1b39893247fc7 (patch)
tree1bebcf449ab043da0fd5a90ee466131bc0f6ee47 /drivers/gpu/drm/nouveau/nouveau_gem.c
parentc072470f4e9abdde7cdf1c850b8826f32f9e79e3 (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/gpu/drm/nouveau/nouveau_gem.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c27
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
582static inline void
583u_free(void *addr)
584{
585 if (!is_vmalloc_addr(addr))
586 kfree(addr);
587 else
588 vfree(addr);
589}
590
582static inline void * 591static inline void *
583u_memcpya(uint64_t user, unsigned nmemb, unsigned size) 592u_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
851out_prevalid: 864out_prevalid:
852 kfree(bo); 865 u_free(bo);
853 kfree(push); 866 u_free(push);
854 867
855out_next: 868out_next:
856 if (chan->dma.ib_max) { 869 if (chan->dma.ib_max) {