drm/i915: Replace a calloc followed by copying data over it with malloc.
Execbufs involve quite a bit of payload, to the extent that cache misses
show up in the profiles here, and a suspicion that some of those cachelines
may get evicted and then reloaded in the subsequent copy.
This is still abstracted like drm_calloc_large since we want to check for
size overflow, and because we want to choose between kmalloc and vmalloc
on the fly. cairo's interface for malloc-with-calloc's-args was used as
the model.
Signed-off-by: Eric Anholt <eric@anholt.net>
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 2065b8f..481c0ab 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -3563,8 +3563,8 @@
return -EINVAL;
}
/* Copy in the exec list from userland */
- exec_list = drm_calloc_large(sizeof(*exec_list), args->buffer_count);
- object_list = drm_calloc_large(sizeof(*object_list), args->buffer_count);
+ exec_list = drm_malloc_ab(sizeof(*exec_list), args->buffer_count);
+ object_list = drm_malloc_ab(sizeof(*object_list), args->buffer_count);
if (exec_list == NULL || object_list == NULL) {
DRM_ERROR("Failed to allocate exec or object list "
"for %d buffers\n",
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index b0b3683..1b807d0 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -1545,16 +1545,29 @@
static __inline__ void *drm_calloc_large(size_t nmemb, size_t size)
{
- if (size * nmemb <= PAGE_SIZE)
- return kcalloc(nmemb, size, GFP_KERNEL);
-
if (size != 0 && nmemb > ULONG_MAX / size)
return NULL;
+ if (size * nmemb <= PAGE_SIZE)
+ return kcalloc(nmemb, size, GFP_KERNEL);
+
return __vmalloc(size * nmemb,
GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL);
}
+/* Modeled after cairo's malloc_ab, it's like calloc but without the zeroing. */
+static __inline__ void *drm_malloc_ab(size_t nmemb, size_t size)
+{
+ if (size != 0 && nmemb > ULONG_MAX / size)
+ return NULL;
+
+ if (size * nmemb <= PAGE_SIZE)
+ return kmalloc(nmemb * size, GFP_KERNEL);
+
+ return __vmalloc(size * nmemb,
+ GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);
+}
+
static __inline void drm_free_large(void *ptr)
{
if (!is_vmalloc_addr(ptr))