summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2016-09-23 20:19:13 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2016-09-23 20:19:13 -0700
commitfa7978ca56d762e604e54dcad511cf57c8a5350d (patch)
tree85d284e9fdd34d319f88fbbd33bbe3010ebfd771
parent7da41e3f7a0349a53dc17583afb5a90c8549dc1d (diff)
parent69fb05e7e51a572a7f2e634061f5274903346a6c (diff)
Merge "memshare: Add support to listen to SUBSYS_RAMDUMP_NOTIFICATION"
-rw-r--r--drivers/soc/qcom/memshare/msm_memshare.c159
-rw-r--r--drivers/soc/qcom/memshare/msm_memshare.h3
2 files changed, 160 insertions, 2 deletions
diff --git a/drivers/soc/qcom/memshare/msm_memshare.c b/drivers/soc/qcom/memshare/msm_memshare.c
index e1e91f56526d..00cc5e12709b 100644
--- a/drivers/soc/qcom/memshare/msm_memshare.c
+++ b/drivers/soc/qcom/memshare/msm_memshare.c
@@ -26,6 +26,7 @@
#include "heap_mem_ext_v01.h"
#include <soc/qcom/secure_buffer.h>
+#include <soc/qcom/ramdump.h>
/* Macros */
#define MEMSHARE_DEV_NAME "memshare"
@@ -37,6 +38,7 @@ static void mem_share_svc_recv_msg(struct work_struct *work);
static DECLARE_DELAYED_WORK(work_recv_msg, mem_share_svc_recv_msg);
static struct workqueue_struct *mem_share_svc_workqueue;
static uint64_t bootup_request;
+static void *memshare_ramdump_dev[MAX_CLIENTS];
/* Memshare Driver Structure */
struct memshare_driver {
@@ -114,9 +116,51 @@ static struct msg_desc mem_share_svc_size_query_resp_desc = {
.ei_array = mem_query_size_resp_msg_data_v01_ei,
};
+/*
+ * This API creates ramdump dev handlers
+ * for each of the memshare clients.
+ * These dev handlers will be used for
+ * extracting the ramdump for loaned memory
+ * segments.
+ */
+
+static int mem_share_configure_ramdump(void)
+{
+ char client_name[18] = "memshare_";
+ char *clnt = NULL;
+
+ switch (num_clients) {
+ case 0:
+ clnt = "GPS";
+ break;
+ case 1:
+ clnt = "FTM";
+ break;
+ case 2:
+ clnt = "DIAG";
+ break;
+ default:
+ pr_info("memshare: no memshare clients registered\n");
+ return -EINVAL;
+ }
+
+ snprintf(client_name, 18, "memshare_%s", clnt);
+
+ memshare_ramdump_dev[num_clients] = create_ramdump_device(client_name,
+ NULL);
+ if (IS_ERR_OR_NULL(memshare_ramdump_dev[num_clients])) {
+ pr_err("memshare: %s: Unable to create memshare ramdump device.\n",
+ __func__);
+ memshare_ramdump_dev[num_clients] = NULL;
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
static int check_client(int client_id, int proc, int request)
{
- int i = 0;
+ int i = 0, rc;
int found = DHMS_MEM_CLIENT_INVALID;
for (i = 0; i < MAX_CLIENTS; i++) {
@@ -127,7 +171,7 @@ static int check_client(int client_id, int proc, int request)
}
}
if ((found == DHMS_MEM_CLIENT_INVALID) && !request) {
- pr_debug("No registered client, adding a new client\n");
+ pr_debug("memshare: No registered client, adding a new client\n");
/* Add a new client */
for (i = 0; i < MAX_CLIENTS; i++) {
if (memblock[i].client_id == DHMS_MEM_CLIENT_INVALID) {
@@ -136,6 +180,16 @@ static int check_client(int client_id, int proc, int request)
memblock[i].guarantee = 0;
memblock[i].peripheral = proc;
found = i;
+
+ if (!memblock[i].file_created) {
+ rc = mem_share_configure_ramdump();
+ if (rc)
+ pr_err("In %s, Cannot create ramdump for client: %d\n",
+ __func__, client_id);
+ else
+ memblock[i].file_created = 1;
+ }
+
break;
}
}
@@ -190,10 +244,75 @@ void initialize_client(void)
memblock[i].memory_type = MEMORY_CMA;
memblock[i].free_memory = 0;
memblock[i].hyp_mapping = 0;
+ memblock[i].file_created = 0;
}
dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs);
}
+/*
+ * This API initializes the ramdump segments
+ * with the physical address and size of
+ * the memshared clients. Extraction of ramdump
+ * is skipped if memshare client is not alloted
+ * This calls the ramdump api in extracting the
+ * ramdump in elf format.
+ */
+
+static int mem_share_do_ramdump(void)
+{
+ int i = 0, ret;
+ char *client_name = NULL;
+
+ for (i = 0; i < num_clients; i++) {
+
+ struct ramdump_segment *ramdump_segments_tmp = NULL;
+
+ switch (i) {
+ case 0:
+ client_name = "GPS";
+ break;
+ case 1:
+ client_name = "FTM";
+ break;
+ case 2:
+ client_name = "DIAG";
+ break;
+ default:
+ pr_info("memshare: no memshare clients registered\n");
+ break;
+ }
+
+ if (!memblock[i].alloted) {
+ pr_err("memshare:%s memblock is not alloted\n",
+ client_name);
+ continue;
+ }
+
+ ramdump_segments_tmp = kcalloc(1,
+ sizeof(struct ramdump_segment),
+ GFP_KERNEL);
+ if (!ramdump_segments_tmp)
+ return -ENOMEM;
+
+ ramdump_segments_tmp[0].size = memblock[i].size;
+ ramdump_segments_tmp[0].address = memblock[i].phy_addr;
+
+ pr_debug("memshare: %s:%s client:phy_address = %llx, size = %d\n",
+ __func__, client_name,
+ (unsigned long long) memblock[i].phy_addr, memblock[i].size);
+
+ ret = do_elf_ramdump(memshare_ramdump_dev[i],
+ ramdump_segments_tmp, 1);
+ if (ret < 0) {
+ pr_err("memshare: Unable to dump: %d\n", ret);
+ kfree(ramdump_segments_tmp);
+ return ret;
+ }
+ kfree(ramdump_segments_tmp);
+ }
+ return 0;
+}
+
static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
void *_cmd)
{
@@ -202,8 +321,10 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
u32 source_vmlist[2] = {VMID_HLOS, VMID_MSS_MSA};
int dest_vmids[1] = {VMID_HLOS};
int dest_perms[1] = {PERM_READ|PERM_WRITE};
+ struct notif_data *notifdata = NULL;
mutex_lock(&memsh_drv->mem_share);
+
switch (code) {
case SUBSYS_BEFORE_SHUTDOWN:
@@ -260,6 +381,22 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
bootup_request++;
break;
+ case SUBSYS_RAMDUMP_NOTIFICATION:
+ if (_cmd)
+ notifdata = (struct notif_data *) _cmd;
+ else
+ break;
+
+ if (!(notifdata->enable_ramdump)) {
+ pr_info("In %s, Ramdump collection is disabled\n",
+ __func__);
+ } else {
+ ret = mem_share_do_ramdump();
+ if (ret)
+ pr_err("Ramdump collection failed\n");
+ }
+ break;
+
default:
pr_debug("Memshare: code: %lu\n", code);
break;
@@ -800,6 +937,9 @@ static int memshare_child_probe(struct platform_device *pdev)
memblock[num_clients].size = size;
memblock[num_clients].client_id = client_id;
+ /*
+ * Memshare allocation for guaranteed clients
+ */
if (memblock[num_clients].guarantee) {
rc = memshare_alloc(memsh_child->dev,
memblock[num_clients].size,
@@ -812,6 +952,21 @@ static int memshare_child_probe(struct platform_device *pdev)
memblock[num_clients].alloted = 1;
}
+ /*
+ * call for creating ramdump dev handlers for
+ * memshare clients
+ */
+
+ if (!memblock[num_clients].file_created) {
+ rc = mem_share_configure_ramdump();
+ if (rc)
+ pr_err("In %s, cannot collect dumps for client id: %d\n",
+ __func__,
+ memblock[num_clients].client_id);
+ else
+ memblock[num_clients].file_created = 1;
+ }
+
num_clients++;
return 0;
diff --git a/drivers/soc/qcom/memshare/msm_memshare.h b/drivers/soc/qcom/memshare/msm_memshare.h
index 68a143907976..398907532977 100644
--- a/drivers/soc/qcom/memshare/msm_memshare.h
+++ b/drivers/soc/qcom/memshare/msm_memshare.h
@@ -51,6 +51,9 @@ struct mem_blocks {
uint8_t free_memory;
/* Need Hypervisor mapping*/
uint8_t hyp_mapping;
+ /* Status flag which checks if ramdump file is created*/
+ int file_created;
+
};
int memshare_alloc(struct device *dev,