fmem: Add support for reusable virtual mappings
Instead of just keeping the entire heap mapped all the
time, reserve the virtual area and map as needed.
Change-Id: Id9a253541f1462379f3f81611aec92cd760e71c8
Signed-off-by: Laura Abbott <lauraa@codeaurora.org>
diff --git a/drivers/staging/qcache/fmem.c b/drivers/staging/qcache/fmem.c
index 9ab21da..489d27a 100644
--- a/drivers/staging/qcache/fmem.c
+++ b/drivers/staging/qcache/fmem.c
@@ -17,11 +17,36 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include "tmem.h"
+#include <asm/mach/map.h>
struct fmem_data fmem_data;
enum fmem_state fmem_state;
static spinlock_t fmem_state_lock;
+void *fmem_map_virtual_area(int cacheability)
+{
+ unsigned long addr;
+ const struct mem_type *type;
+ int ret;
+
+ addr = (unsigned long) fmem_data.area->addr;
+ type = get_mem_type(cacheability);
+ ret = ioremap_page_range(addr, addr + fmem_data.size,
+ fmem_data.phys, __pgprot(type->prot_pte));
+ if (ret)
+ return ERR_PTR(ret);
+
+ fmem_data.virt = fmem_data.area->addr;
+
+ return fmem_data.virt;
+}
+
+void fmem_unmap_virtual_area(void)
+{
+ unmap_kernel_range((unsigned long)fmem_data.virt, fmem_data.size);
+ fmem_data.virt = NULL;
+}
+
static int fmem_probe(struct platform_device *pdev)
{
struct fmem_platform_data *pdata = pdev->dev.platform_data;
@@ -29,13 +54,16 @@
if (!pdata->size)
return -ENODEV;
- fmem_data.virt = ioremap_cached(pdata->phys, pdata->size);
- if (!fmem_data.virt)
- return -ENOMEM;
-
fmem_data.phys = pdata->phys;
fmem_data.size = pdata->size;
+ fmem_data.area = get_vm_area(pdata->size, VM_IOREMAP);
+ if (!fmem_data.area)
+ return -ENOMEM;
+ if (!fmem_map_virtual_area(MT_DEVICE_CACHED)) {
+ remove_vm_area(fmem_data.area->addr);
+ return -ENOMEM;
+ }
pr_info("fmem phys %lx virt %p size %lx\n",
fmem_data.phys, fmem_data.virt, fmem_data.size);
@@ -159,10 +187,18 @@
}
}
- if (new_state == FMEM_T_STATE)
+ if (new_state == FMEM_T_STATE) {
+ void *v;
+ v = fmem_map_virtual_area(MT_DEVICE_CACHED);
+ if (IS_ERR_OR_NULL(v)) {
+ ret = PTR_ERR(v);
+ goto out;
+ }
tmem_enable(true);
- else
+ } else {
tmem_disable();
+ fmem_unmap_virtual_area();
+ }
out_set:
fmem_state = new_state;
diff --git a/include/linux/fmem.h b/include/linux/fmem.h
index a88c674..d91f4c1 100644
--- a/include/linux/fmem.h
+++ b/include/linux/fmem.h
@@ -15,6 +15,8 @@
#ifndef _FMEM_H_
#define _FMEM_H_
+#include <linux/vmalloc.h>
+
struct fmem_platform_data {
unsigned long phys;
unsigned long size;
@@ -23,6 +25,7 @@
struct fmem_data {
unsigned long phys;
void *virt;
+ struct vm_struct *area;
unsigned long size;
};
@@ -38,11 +41,15 @@
int fmem_set_state(enum fmem_state);
void lock_fmem_state(void);
void unlock_fmem_state(void);
+void *fmem_map_virtual_area(int cacheability);
+void fmem_unmap_virtual_area(void);
#else
static inline struct fmem_data *fmem_get_info(void) { return NULL; }
static inline int fmem_set_state(enum fmem_state f) { return -ENODEV; }
static inline void lock_fmem_state(void) { return; }
static inline void unlock_fmem_state(void) { return; }
+static inline void *fmem_map_virtual_area(int cacheability) { return NULL; }
+static inline void fmem_unmap_virtual_area(void) { return; }
#endif