mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-12 08:48:48 +00:00
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>
This commit is contained in:
parent
c072470f4e
commit
c859074e7d
@ -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,
|
|||||||
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,
|
|||||||
|
|
||||||
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 @@ out:
|
|||||||
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) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user