From 962f6fcf2b97605f2dcc509f00859a2fef031adc Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Tue, 1 Sep 2020 01:47:02 -0700 Subject: [PATCH] memshare: Use carveouts for memory sharing usecases The memory sharing usecases that memshare caters to require the memory associated with the usecase to be XPU protected. Since the memory is currently drawn from the common CMA pool, there is still a normal cached mapping in the kernel for the memory. This can lead to speculative cache-line fills before the memory is unmapped from the stage-2 page tables of Linux, and XPU protected. Later, when the lines are evicted from the cache (as clean-evicts), this results in a write to the system cache, which triggers an XPU violation. Use carveouts for the memshare usecases, to avoid creating normal cached mappings in the kernel for the memory that the memshare usecases need to use. Modify allocation based on the checks for the client id of the memshare child node. Change-Id: I1cfdc600a1aeea06072253cbbf1564fa5bebd62b Signed-off-by: Isaac J. Manjarres Signed-off-by: Manoj Prabhu B --- drivers/soc/qcom/memshare/msm_memshare.c | 63 ++++++++++++++++++++---- 1 file changed, 53 insertions(+), 10 deletions(-) diff --git a/drivers/soc/qcom/memshare/msm_memshare.c b/drivers/soc/qcom/memshare/msm_memshare.c index 06cef6d7ece9..0190a13ceef7 100644 --- a/drivers/soc/qcom/memshare/msm_memshare.c +++ b/drivers/soc/qcom/memshare/msm_memshare.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -40,10 +41,11 @@ struct memshare_driver { struct memshare_child { struct device *dev; + int client_id; }; static struct memshare_driver *memsh_drv; -static struct memshare_child *memsh_child; +static struct memshare_child *memsh_child[MAX_CLIENTS]; static struct mem_blocks memblock[MAX_CLIENTS]; static uint32_t num_clients; @@ -299,6 +301,7 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code, int dest_vmids[1] = {VMID_HLOS}; int dest_perms[1] = {PERM_READ|PERM_WRITE|PERM_EXEC}; struct notif_data *notifdata = NULL; + struct memshare_child *client_node = NULL; mutex_lock(&memsh_drv->mem_share); @@ -345,6 +348,7 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code, case SUBSYS_AFTER_POWERUP: dev_info(memsh_drv->dev, "memshare: SUBSYS_AFTER_POWERUP: Modem has booted up\n"); for (i = 0; i < MAX_CLIENTS; i++) { + client_node = memsh_child[i]; size = memblock[i].size; if (memblock[i].free_memory > 0 && bootup_request >= 2) { @@ -394,7 +398,7 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code, */ size += MEMSHARE_GUARD_BYTES; } - dma_free_attrs(memsh_drv->dev, + dma_free_attrs(client_node->dev, size, memblock[i].virtual_addr, memblock[i].phy_addr, attrs); @@ -448,7 +452,8 @@ static void handle_alloc_generic_req(struct qmi_handle *handle, { struct mem_alloc_generic_req_msg_v01 *alloc_req; struct mem_alloc_generic_resp_msg_v01 *alloc_resp; - int rc, resp = 0; + struct memshare_child *client_node = NULL; + int rc, resp = 0, i; int client_id; uint32_t size = 0; @@ -468,6 +473,13 @@ static void handle_alloc_generic_req(struct qmi_handle *handle, client_id = check_client(alloc_req->client_id, alloc_req->proc_id, CHECK); + for (i = 0; i < MAX_CLIENTS; i++) { + if (memsh_child[i]->client_id == client_id) { + client_node = memsh_child[i]; + break; + } + } + if (client_id >= MAX_CLIENTS) { dev_err(memsh_drv->dev, "memshare_alloc: client not found, requested client: %d, proc_id: %d\n", @@ -483,7 +495,7 @@ static void handle_alloc_generic_req(struct qmi_handle *handle, size = alloc_req->num_bytes + MEMSHARE_GUARD_BYTES; else size = alloc_req->num_bytes; - rc = memshare_alloc(memsh_drv->dev, size, + rc = memshare_alloc(client_node->dev, size, &memblock[client_id]); if (rc) { dev_err(memsh_drv->dev, @@ -538,7 +550,8 @@ static void handle_free_generic_req(struct qmi_handle *handle, { struct mem_free_generic_req_msg_v01 *free_req; struct mem_free_generic_resp_msg_v01 free_resp; - int rc, flag = 0, ret = 0, size = 0; + struct memshare_child *client_node = NULL; + int rc, flag = 0, ret = 0, size = 0, i; uint32_t client_id; u32 source_vmlist[1] = {VMID_MSS_MSA}; int dest_vmids[1] = {VMID_HLOS}; @@ -552,7 +565,16 @@ static void handle_free_generic_req(struct qmi_handle *handle, dev_info(memsh_drv->dev, "memshare_free: handling memory free request with client id: %d, proc_id: %d\n", free_req->client_id, free_req->proc_id); + client_id = check_client(free_req->client_id, free_req->proc_id, FREE); + + for (i = 0; i < MAX_CLIENTS; i++) { + if (memsh_child[i]->client_id == client_id) { + client_node = memsh_child[i]; + break; + } + } + if (client_id == DHMS_MEM_CLIENT_INVALID) { dev_err(memsh_drv->dev, "memshare_free: invalid client request to free memory\n"); flag = 1; @@ -583,7 +605,7 @@ static void handle_free_generic_req(struct qmi_handle *handle, */ size += MEMSHARE_GUARD_BYTES; } - dma_free_attrs(memsh_drv->dev, size, + dma_free_attrs(client_node->dev, size, memblock[client_id].virtual_addr, memblock[client_id].phy_addr, attrs); @@ -771,6 +793,7 @@ static int memshare_child_probe(struct platform_device *pdev) uint32_t size, client_id; const char *name; struct memshare_child *drv; + struct device_node *mem_node; drv = devm_kzalloc(&pdev->dev, sizeof(struct memshare_child), GFP_KERNEL); @@ -779,13 +802,12 @@ static int memshare_child_probe(struct platform_device *pdev) return -ENOMEM; drv->dev = &pdev->dev; - memsh_child = drv; - platform_set_drvdata(pdev, memsh_child); + platform_set_drvdata(pdev, drv); rc = of_property_read_u32(pdev->dev.of_node, "qcom,peripheral-size", &size); if (rc) { - dev_err(memsh_child->dev, "memshare: Error reading size of clients, rc: %d\n", + dev_err(drv->dev, "memshare: Error reading size of clients, rc: %d\n", rc); return rc; } @@ -827,6 +849,21 @@ static int memshare_child_probe(struct platform_device *pdev) memblock[num_clients].init_size = size; memblock[num_clients].client_id = client_id; + drv->client_id = client_id; + + mem_node = of_parse_phandle(pdev->dev.of_node, "memory-region", 0); + of_node_put(mem_node); + if (mem_node) { + rc = of_reserved_mem_device_init(&pdev->dev); + if (rc) { + dev_err(&pdev->dev, "memshare: Failed to initialize memory region rc: %d\n", + rc); + return rc; + } + dev_info(&pdev->dev, "memshare: Memory allocation from shared DMA pool\n"); + } else { + dev_info(&pdev->dev, "memshare: Continuing with allocation from CMA\n"); + } /* * Memshare allocation for guaranteed clients @@ -834,13 +871,18 @@ static int memshare_child_probe(struct platform_device *pdev) if (memblock[num_clients].guarantee && size > 0) { if (memblock[num_clients].guard_band) size += MEMSHARE_GUARD_BYTES; - rc = memshare_alloc(memsh_child->dev, + rc = memshare_alloc(drv->dev, size, &memblock[num_clients]); if (rc) { dev_err(memsh_drv->dev, "memshare_child: Unable to allocate memory for guaranteed clients, rc: %d\n", rc); + mem_node = of_parse_phandle(pdev->dev.of_node, + "memory-region", 0); + of_node_put(mem_node); + if (mem_node) + of_reserved_mem_device_release(&pdev->dev); return rc; } memblock[num_clients].size = size; @@ -865,6 +907,7 @@ static int memshare_child_probe(struct platform_device *pdev) memblock[num_clients].file_created = 1; } + memsh_child[num_clients] = drv; num_clients++; return 0;