msm: kgsl: Add ION as an external memory source
Allow ION buffers to be attached via IOCTL_KGSL_MAP_USER_MEM
Change-Id: Ic0dedbada34d12fb70b528f3a93dd21805a4c8a4
Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 181a464..c6fceaa 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -23,6 +23,7 @@
#include <linux/ashmem.h>
#include <linux/major.h>
+#include <linux/ion.h>
#include "kgsl.h"
#include "kgsl_debugfs.h"
@@ -43,6 +44,8 @@
MODULE_PARM_DESC(ksgl_mmu_type,
"Type of MMU to be used for graphics. Valid values are 'iommu' or 'gpummu' or 'nommu'");
+static struct ion_client *kgsl_ion_client;
+
static inline struct kgsl_mem_entry *
kgsl_mem_entry_create(void)
{
@@ -68,6 +71,17 @@
if (entry->memtype != KGSL_MEM_ENTRY_KERNEL)
kgsl_driver.stats.mapped -= entry->memdesc.size;
+ /*
+ * Ion takes care of freeing the sglist for us (how nice </sarcasm>) so
+ * unmap the dma before freeing the sharedmem so kgsl_sharedmem_free
+ * doesn't try to free it again
+ */
+
+ if (entry->memtype == KGSL_MEM_ENTRY_ION) {
+ ion_unmap_dma(kgsl_ion_client, entry->priv_data);
+ entry->memdesc.sg = NULL;
+ }
+
kgsl_sharedmem_free(&entry->memdesc);
switch (entry->memtype) {
@@ -76,6 +90,9 @@
if (entry->priv_data)
fput(entry->priv_data);
break;
+ case KGSL_MEM_ENTRY_ION:
+ ion_free(kgsl_ion_client, entry->priv_data);
+ break;
}
kfree(entry);
@@ -1412,6 +1429,51 @@
}
#endif
+static int kgsl_setup_ion(struct kgsl_mem_entry *entry,
+ struct kgsl_pagetable *pagetable, int fd)
+{
+ struct ion_handle *handle;
+ struct scatterlist *s;
+ unsigned long flags;
+
+ if (kgsl_ion_client == NULL) {
+ kgsl_ion_client = msm_ion_client_create(UINT_MAX, KGSL_NAME);
+ if (kgsl_ion_client == NULL)
+ return -ENODEV;
+ }
+
+ handle = ion_import_fd(kgsl_ion_client, fd);
+ if (IS_ERR_OR_NULL(handle))
+ return PTR_ERR(handle);
+
+ entry->memtype = KGSL_MEM_ENTRY_ION;
+ entry->priv_data = handle;
+ entry->memdesc.pagetable = pagetable;
+ entry->memdesc.size = 0;
+
+ if (ion_handle_get_flags(kgsl_ion_client, handle, &flags))
+ goto err;
+
+ entry->memdesc.sg = ion_map_dma(kgsl_ion_client, handle, flags);
+
+ if (IS_ERR_OR_NULL(entry->memdesc.sg))
+ goto err;
+
+ /* Calculate the size of the memdesc from the sglist */
+
+ entry->memdesc.sglen = 0;
+
+ for (s = entry->memdesc.sg; s != NULL; s = sg_next(s)) {
+ entry->memdesc.size += s->length;
+ entry->memdesc.sglen++;
+ }
+
+ return 0;
+err:
+ ion_free(kgsl_ion_client, handle);
+ return -ENOMEM;
+}
+
static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
@@ -1476,6 +1538,10 @@
entry->memtype = KGSL_MEM_ENTRY_ASHMEM;
break;
+ case KGSL_USER_MEM_TYPE_ION:
+ result = kgsl_setup_ion(entry, private->pagetable,
+ param->fd);
+ break;
default:
KGSL_CORE_ERR("Invalid memory type: %x\n", memtype);
break;
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index b83f9b5..b5c24f0 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -123,7 +123,8 @@
#define KGSL_MEM_ENTRY_PMEM 1
#define KGSL_MEM_ENTRY_ASHMEM 2
#define KGSL_MEM_ENTRY_USER 3
-#define KGSL_MEM_ENTRY_MAX 4
+#define KGSL_MEM_ENTRY_ION 4
+#define KGSL_MEM_ENTRY_MAX 5
struct kgsl_mem_entry {
struct kref refcount;
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index f3ed531..b59761d 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -149,6 +149,9 @@
MEM_ENTRY_STAT(KGSL_MEM_ENTRY_ASHMEM, ashmem),
#endif
MEM_ENTRY_STAT(KGSL_MEM_ENTRY_USER, user),
+#ifdef CONFIG_ION
+ MEM_ENTRY_STAT(KGSL_MEM_ENTRY_USER, ion),
+#endif
};
void