Merge "msm: ocmem: Add support for dumping OCMEM"
diff --git a/arch/arm/mach-msm/include/mach/ocmem.h b/arch/arm/mach-msm/include/mach/ocmem.h
index 904de5e..cb8aae0 100644
--- a/arch/arm/mach-msm/include/mach/ocmem.h
+++ b/arch/arm/mach-msm/include/mach/ocmem.h
@@ -134,6 +134,9 @@
int ocmem_unmap(int client_id, struct ocmem_buf *buffer,
struct ocmem_map_list *list);
+int ocmem_dump(int client_id, struct ocmem_buf *buffer,
+ unsigned long dst_phys_addr);
+
/* Priority Enforcement APIs */
int ocmem_evict(int client_id);
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 09dfac0..0b30c26 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -56,6 +56,8 @@
NR_TRANSFER_FAILS,
NR_EVICTIONS,
NR_RESTORES,
+ NR_DUMP_REQUESTS,
+ NR_DUMP_COMPLETE,
NR_OCMEM_ZSTAT_ITEMS,
};
@@ -198,6 +200,7 @@
int process_evict(int);
int process_restore(int);
int process_shrink(int, struct ocmem_handle *, unsigned long);
+int process_dump(int, struct ocmem_handle *, unsigned long);
int ocmem_rdm_transfer(int, struct ocmem_map_list *,
unsigned long, int);
int ocmem_clear(unsigned long, unsigned long);
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index 793fcc5..7829d8d 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -82,6 +82,8 @@
"Transfer failures",
"Evictions",
"Restorations",
+ "Dump requests",
+ "Dump completed",
};
struct ocmem_quota_table {
diff --git a/arch/arm/mach-msm/ocmem_api.c b/arch/arm/mach-msm/ocmem_api.c
index 6e094fd..689e015 100644
--- a/arch/arm/mach-msm/ocmem_api.c
+++ b/arch/arm/mach-msm/ocmem_api.c
@@ -399,6 +399,36 @@
}
EXPORT_SYMBOL(ocmem_unmap);
+int ocmem_dump(int client_id, struct ocmem_buf *buffer,
+ unsigned long dst_phys_addr)
+{
+ int ret = 0;
+ struct ocmem_handle *handle = NULL;
+
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid client id: %d\n", client_id);
+ return -EINVAL;
+ }
+
+ if (!zone_active(client_id)) {
+ pr_err("ocmem: Client id: %s (id: %d) not allowed to use OCMEM\n",
+ get_name(client_id), client_id);
+ return -EINVAL;
+ }
+
+ if (!buffer) {
+ pr_err("ocmem: Invalid buffer\n");
+ return -EINVAL;
+ }
+
+ handle = buffer_to_handle(buffer);
+ mutex_lock(&handle->handle_mutex);
+ ret = process_dump(client_id, handle, dst_phys_addr);
+ mutex_unlock(&handle->handle_mutex);
+ return ret;
+}
+EXPORT_SYMBOL(ocmem_dump);
+
unsigned long get_max_quota(int client_id)
{
if (!check_id(client_id)) {
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index e8854d5..c380c54 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -65,6 +65,7 @@
MAX_OCMEM_PRIO = PRIO_OCMEM + 1,
};
+static void __iomem *ocmem_vaddr;
static struct list_head sched_queue[MAX_OCMEM_PRIO];
static struct mutex sched_queue_mutex;
@@ -1670,6 +1671,34 @@
return -EINVAL;
}
+static int do_dump(struct ocmem_req *req, unsigned long addr)
+{
+
+ void __iomem *req_vaddr;
+ unsigned long offset = 0x0;
+
+ down_write(&req->rw_sem);
+
+ offset = phys_to_offset(req->req_start);
+
+ req_vaddr = ocmem_vaddr + offset;
+
+ if (!req_vaddr)
+ goto err_do_dump;
+
+ pr_debug("Dumping client %s buffer ocmem p: %lx (v: %p) to ddr %lx\n",
+ get_name(req->owner), req->req_start,
+ req_vaddr, addr);
+
+ memcpy((void *)addr, req_vaddr, req->req_sz);
+
+ up_write(&req->rw_sem);
+ return 0;
+err_do_dump:
+ up_write(&req->rw_sem);
+ return -EINVAL;
+}
+
int process_restore(int id)
{
struct ocmem_req *req = NULL;
@@ -1828,6 +1857,38 @@
return -EINVAL;
}
+int process_dump(int id, struct ocmem_handle *handle, unsigned long addr)
+{
+ struct ocmem_req *req = NULL;
+ int rc = 0;
+
+ req = handle_to_req(handle);
+
+ if (!req)
+ return -EINVAL;
+
+ if (!is_mapped(req)) {
+ pr_err("Buffer is not mapped\n");
+ goto dump_error;
+ }
+
+ inc_ocmem_stat(zone_of(req), NR_DUMP_REQUESTS);
+
+ mutex_lock(&sched_mutex);
+ rc = do_dump(req, addr);
+ mutex_unlock(&sched_mutex);
+
+ if (rc < 0)
+ goto dump_error;
+
+ inc_ocmem_stat(zone_of(req), NR_DUMP_COMPLETE);
+ return 0;
+
+dump_error:
+ pr_err("Dumping OCMEM memory failed for client %d\n", id);
+ return -EINVAL;
+}
+
static void ocmem_sched_wk_func(struct work_struct *work)
{
@@ -1906,6 +1967,7 @@
pdata = platform_get_drvdata(pdev);
mutex_init(&sched_mutex);
mutex_init(&sched_queue_mutex);
+ ocmem_vaddr = pdata->vbase;
for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++)
INIT_LIST_HEAD(&sched_queue[i]);