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:
Maarten Lankhorst 2013-09-02 16:31:31 +02:00 committed by Ben Skeggs
parent c072470f4e
commit c859074e7d

View file

@ -579,18 +579,31 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
return 0;
}
static inline void
u_free(void *addr)
{
if (!is_vmalloc_addr(addr))
kfree(addr);
else
vfree(addr);
}
static inline void *
u_memcpya(uint64_t user, unsigned nmemb, unsigned size)
{
void *mem;
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)
return ERR_PTR(-ENOMEM);
if (DRM_COPY_FROM_USER(mem, userptr, nmemb * size)) {
kfree(mem);
if (DRM_COPY_FROM_USER(mem, userptr, size)) {
u_free(mem);
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);
}
kfree(reloc);
u_free(reloc);
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));
if (IS_ERR(bo)) {
kfree(push);
u_free(push);
return nouveau_abi16_put(abi16, PTR_ERR(bo));
}
@ -849,8 +862,8 @@ out:
nouveau_fence_unref(&fence);
out_prevalid:
kfree(bo);
kfree(push);
u_free(bo);
u_free(push);
out_next:
if (chan->dma.ib_max) {