Commit c859074e authored by Maarten Lankhorst's avatar Maarten Lankhorst Committed by Ben Skeggs

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: default avatarMaarten Lankhorst <maarten.lankhorst@canonical.com>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent c072470f
...@@ -579,18 +579,31 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, ...@@ -579,18 +579,31 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
return 0; return 0;
} }
static inline void
u_free(void *addr)
{
if (!is_vmalloc_addr(addr))
kfree(addr);
else
vfree(addr);
}
static inline void * static inline void *
u_memcpya(uint64_t user, unsigned nmemb, unsigned size) u_memcpya(uint64_t user, unsigned nmemb, unsigned size)
{ {
void *mem; void *mem;
void __user *userptr = (void __force __user *)(uintptr_t)user; void __user *userptr = (void __force __user *)(uintptr_t)user;
mem = kmalloc(nmemb * size, GFP_KERNEL); size *= nmemb;
mem = kmalloc(size, GFP_KERNEL | __GFP_NOWARN);
if (!mem)
mem = vmalloc(size);
if (!mem) if (!mem)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
if (DRM_COPY_FROM_USER(mem, userptr, nmemb * size)) { if (DRM_COPY_FROM_USER(mem, userptr, size)) {
kfree(mem); u_free(mem);
return ERR_PTR(-EFAULT); return ERR_PTR(-EFAULT);
} }
...@@ -676,7 +689,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, ...@@ -676,7 +689,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli,
nouveau_bo_wr32(nvbo, r->reloc_bo_offset >> 2, data); nouveau_bo_wr32(nvbo, r->reloc_bo_offset >> 2, data);
} }
kfree(reloc); u_free(reloc);
return ret; return ret;
} }
...@@ -738,7 +751,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, ...@@ -738,7 +751,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo)); bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo));
if (IS_ERR(bo)) { if (IS_ERR(bo)) {
kfree(push); u_free(push);
return nouveau_abi16_put(abi16, PTR_ERR(bo)); return nouveau_abi16_put(abi16, PTR_ERR(bo));
} }
...@@ -849,8 +862,8 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, ...@@ -849,8 +862,8 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
nouveau_fence_unref(&fence); nouveau_fence_unref(&fence);
out_prevalid: out_prevalid:
kfree(bo); u_free(bo);
kfree(push); u_free(push);
out_next: out_next:
if (chan->dma.ib_max) { if (chan->dma.ib_max) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment