msm: kgsl: Add support for bulk cache operations

Add a new ioctl, IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK, which can be used
to sync a number of memory ids at once. This gives the driver an
opportunity to optimize the cache operations based on the total
working set of memory that needs to be managed.

Change-Id: I9693c54cb6f12468b7d9abb0afaef348e631a114
Signed-off-by: Jeremy Gebben <jgebben@codeaurora.org>
This commit is contained in:
Jeremy Gebben
2013-05-13 09:10:31 -06:00
parent b44a4b304e
commit e4f2f9767a
2 changed files with 101 additions and 0 deletions
+80
View File
@@ -29,6 +29,8 @@
#include <linux/io.h>
#include <mach/socinfo.h>
#include <linux/mman.h>
#include <linux/sort.h>
#include <asm/cacheflush.h>
#include "kgsl.h"
#include "kgsl_debugfs.h"
@@ -2104,6 +2106,82 @@ kgsl_ioctl_gpumem_sync_cache(struct kgsl_device_private *dev_priv,
return ret;
}
static int mem_id_cmp(const void *_a, const void *_b)
{
const unsigned int *a = _a, *b = _b;
int cmp = a - b;
return (cmp < 0) ? -1 : (cmp > 0);
}
static long
kgsl_ioctl_gpumem_sync_cache_bulk(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
int i;
struct kgsl_gpumem_sync_cache_bulk *param = data;
struct kgsl_process_private *private = dev_priv->process_priv;
unsigned int id, last_id = 0, *id_list = NULL, actual_count = 0;
struct kgsl_mem_entry **entries = NULL;
long ret = 0;
if (param->id_list == NULL || param->count == 0
|| param->count > (UINT_MAX/sizeof(unsigned int)))
return -EINVAL;
id_list = kzalloc(param->count * sizeof(unsigned int), GFP_KERNEL);
if (id_list == NULL)
return -ENOMEM;
entries = kzalloc(param->count * sizeof(*entries), GFP_KERNEL);
if (entries == NULL) {
ret = -ENOMEM;
goto end;
}
if (copy_from_user(id_list, param->id_list,
param->count * sizeof(unsigned int))) {
ret = -EFAULT;
goto end;
}
/* sort the ids so we can weed out duplicates */
sort(id_list, param->count, sizeof(int), mem_id_cmp, NULL);
for (i = 0; i < param->count; i++) {
unsigned int cachemode;
struct kgsl_mem_entry *entry = NULL;
id = id_list[i];
/* skip 0 ids or duplicates */
if (id == last_id)
continue;
entry = kgsl_sharedmem_find_id(private, id);
if (entry == NULL)
continue;
/* skip uncached memory */
cachemode = kgsl_memdesc_get_cachemode(&entry->memdesc);
if (cachemode != KGSL_CACHEMODE_WRITETHROUGH &&
cachemode != KGSL_CACHEMODE_WRITEBACK) {
kgsl_mem_entry_put(entry);
continue;
}
entries[actual_count++] = entry;
last_id = id;
}
for (i = 0; i < actual_count; i++) {
_kgsl_gpumem_sync_cache(entries[i], param->op);
kgsl_mem_entry_put(entries[i]);
}
end:
kfree(entries);
kfree(id_list);
return ret;
}
/* Legacy cache function, does a flush (clean + invalidate) */
static long
@@ -2510,6 +2588,8 @@ static const struct {
kgsl_ioctl_gpumem_get_info, 0),
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE,
kgsl_ioctl_gpumem_sync_cache, 0),
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK,
kgsl_ioctl_gpumem_sync_cache_bulk, 0),
};
static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+21
View File
@@ -781,6 +781,27 @@ struct kgsl_perfcounter_read {
#define IOCTL_KGSL_PERFCOUNTER_READ \
_IOWR(KGSL_IOC_TYPE, 0x3B, struct kgsl_perfcounter_read)
/*
* struct kgsl_gpumem_sync_cache_bulk - argument to
* IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK
* @id_list: list of GPU buffer ids of the buffers to sync
* @count: number of GPU buffer ids in id_list
* @op: a mask of KGSL_GPUMEM_CACHE_* values
*
* Sync the cache for memory headed to and from the GPU. Certain
* optimizations can be made on the cache operation based on the total
* size of the working set of memory to be managed.
*/
struct kgsl_gpumem_sync_cache_bulk {
unsigned int *id_list;
unsigned int count;
unsigned int op;
/* private: reserved for future use */
unsigned int __pad[2]; /* For future binary compatibility */
};
#define IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK \
_IOWR(KGSL_IOC_TYPE, 0x3C, struct kgsl_gpumem_sync_cache_bulk)
#ifdef __KERNEL__
#ifdef CONFIG_MSM_KGSL_DRM