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 +#include /* 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,