msm: kgsl: Use kzalloc to allocate scatterlists of 1 page or less
The majority of the scatterlist allocations used in KGSL are under 1
page (1 page of struct scatterlist is approximately 1024 entries
equalling 4MB of allocated buffer). In these cases using vmalloc
for the sglist is undesirable and slow. Add functions to check the
size of the allocation and favor kzalloc for 1 page allocations and
vmalloc for larger lists.
Change-Id: Ic0dedbad99b60111677dd56b74edd8cedcac17f0
Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 8ac575c..45bcf69 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1376,7 +1376,8 @@
int sglen = PAGE_ALIGN(size) / PAGE_SIZE;
unsigned long paddr = (unsigned long) addr;
- memdesc->sg = vmalloc(sglen * sizeof(struct scatterlist));
+ memdesc->sg = kgsl_sg_alloc(sglen);
+
if (memdesc->sg == NULL)
return -ENOMEM;
@@ -1416,7 +1417,7 @@
err:
spin_unlock(¤t->mm->page_table_lock);
- vfree(memdesc->sg);
+ kgsl_sg_free(memdesc->sg, sglen);
memdesc->sg = NULL;
return -EINVAL;
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index d7d0809..1f142f8 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -463,7 +463,8 @@
memdesc->priv = KGSL_MEMFLAGS_CACHED;
memdesc->ops = &kgsl_vmalloc_ops;
- memdesc->sg = vmalloc(sglen * sizeof(struct scatterlist));
+ memdesc->sg = kgsl_sg_alloc(sglen);
+
if (memdesc->sg == NULL) {
ret = -ENOMEM;
goto done;
@@ -589,7 +590,7 @@
if (memdesc->ops && memdesc->ops->free)
memdesc->ops->free(memdesc);
- vfree(memdesc->sg);
+ kgsl_sg_free(memdesc->sg, memdesc->sglen);
memset(memdesc, 0, sizeof(*memdesc));
}
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index effe2438..def29b3 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -89,13 +89,34 @@
kgsl_sharedmem_map_vma(struct vm_area_struct *vma,
const struct kgsl_memdesc *memdesc);
+/*
+ * For relatively small sglists, it is preferable to use kzalloc
+ * rather than going down the vmalloc rat hole. If the size of
+ * the sglist is < PAGE_SIZE use kzalloc otherwise fallback to
+ * vmalloc
+ */
+
+static inline void *kgsl_sg_alloc(unsigned int sglen)
+{
+ if ((sglen * sizeof(struct scatterlist)) < PAGE_SIZE)
+ return kzalloc(sglen * sizeof(struct scatterlist), GFP_KERNEL);
+ else
+ return vmalloc(sglen * sizeof(struct scatterlist));
+}
+
+static inline void kgsl_sg_free(void *ptr, unsigned int sglen)
+{
+ if ((sglen * sizeof(struct scatterlist)) < PAGE_SIZE)
+ kfree(ptr);
+ else
+ vfree(ptr);
+}
+
static inline int
memdesc_sg_phys(struct kgsl_memdesc *memdesc,
unsigned int physaddr, unsigned int size)
{
- memdesc->sg = vmalloc(sizeof(struct scatterlist) * 1);
- if (memdesc->sg == NULL)
- return -ENOMEM;
+ memdesc->sg = kgsl_sg_alloc(1);
kmemleak_not_leak(memdesc->sg);