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 | |
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>
-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) { |