Loading arch/arm/boot/dts/qcom/msm8996.dtsi +25 −0 Original line number Diff line number Diff line Loading @@ -2776,6 +2776,31 @@ }; }; qcom,memshare { compatible = "qcom,memshare"; qcom,client_1 { compatible = "qcom,memshare-peripheral"; qcom,peripheral-size = <0x200000>; qcom,client-id = <0>; label = "modem"; }; qcom,client_2 { compatible = "qcom,memshare-peripheral"; qcom,peripheral-size = <0x300000>; qcom,client-id = <2>; label = "modem"; }; qcom,client_3 { compatible = "qcom,memshare-peripheral"; qcom,peripheral-size = <0x0>; qcom,client-id = <1>; label = "modem"; }; }; qcom,msm-core@70000 { compatible = "qcom,apss-core-ea"; reg = <0x70000 0x1000>; Loading drivers/soc/qcom/memshare/msm_memshare.c +64 −10 Original line number Diff line number Diff line /* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -25,6 +25,8 @@ #include "msm_memshare.h" #include "heap_mem_ext_v01.h" #include <soc/qcom/secure_buffer.h> /* Macros */ #define MEMSHARE_DEV_NAME "memshare" #define MEMSHARE_CHILD_DEV_NAME "memshare_child" Loading Loading @@ -144,14 +146,10 @@ static int check_client(int client_id, int proc, int request) void free_client(int id) { memblock[id].size = 0; memblock[id].phy_addr = 0; memblock[id].virtual_addr = 0; memblock[id].alloted = 0; memblock[id].client_id = DHMS_MEM_CLIENT_INVALID; memblock[id].guarantee = 0; memblock[id].peripheral = -1; memblock[id].sequence_id = -1; memblock[id].memory_type = MEMORY_CMA; Loading Loading @@ -191,6 +189,7 @@ void initialize_client(void) memblock[i].sequence_id = -1; memblock[i].memory_type = MEMORY_CMA; memblock[i].free_memory = 0; memblock[i].hyp_mapping = 0; } dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs); } Loading @@ -199,6 +198,10 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code, void *_cmd) { int i; int ret; u32 source_vmlist[2] = {VMID_HLOS, VMID_MSS_MSA}; int dest_vmids[1] = {VMID_HLOS}; int dest_perms[1] = {PERM_READ|PERM_WRITE}; switch (code) { Loading @@ -222,8 +225,28 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code, DHMS_MEM_PROC_MPSS_V01 && !memblock[i].guarantee && memblock[i].alloted) { pr_err("memshare: Freeing memory for client id: %d\n", pr_debug("memshare: Freeing memory for client id: %d\n", memblock[i].client_id); ret = hyp_assign_phys( memblock[i].phy_addr, memblock[i].size, source_vmlist, 2, dest_vmids, dest_perms, 1); if (ret && memblock[i].hyp_mapping == 1) { /* * This is an error case as hyp * mapping was successful * earlier but during unmap * it lead to failure. */ pr_err("memshare: %s, failed to unmap the region\n", __func__); memblock[i].hyp_mapping = 1; } else { memblock[i].hyp_mapping = 0; } dma_free_attrs(memsh_drv->dev, memblock[i].size, memblock[i].virtual_addr, Loading @@ -248,6 +271,32 @@ static struct notifier_block nb = { .notifier_call = modem_notifier_cb, }; static void shared_hyp_mapping(int client_id) { int ret; u32 source_vmlist[1] = {VMID_HLOS}; int dest_vmids[2] = {VMID_HLOS, VMID_MSS_MSA}; int dest_perms[2] = {PERM_READ|PERM_WRITE, PERM_READ|PERM_WRITE}; if (client_id == DHMS_MEM_CLIENT_INVALID) { pr_err("memshare: %s, Invalid Client\n", __func__); return; } ret = hyp_assign_phys(memblock[client_id].phy_addr, memblock[client_id].size, source_vmlist, 1, dest_vmids, dest_perms, 2); if (ret != 0) { pr_err("memshare: hyp_assign_phys failed size=%u err=%d\n", memblock[client_id].size, ret); return; } memblock[client_id].hyp_mapping = 1; } static int handle_alloc_req(void *req_h, void *req, void *conn_h) { struct mem_alloc_req_msg_v01 *alloc_req; Loading Loading @@ -341,9 +390,15 @@ static int handle_alloc_generic_req(void *req_h, void *req, void *conn_h) memblock[client_id].sequence_id = alloc_req->sequence_id; fill_alloc_response(alloc_resp, client_id, &resp); /* * Perform the Hypervisor mapping in order to avoid XPU viloation * to the allocated region for Modem Clients */ if (!memblock[client_id].hyp_mapping && memblock[client_id].alloted) shared_hyp_mapping(client_id); mutex_unlock(&memsh_drv->mem_share); pr_debug("alloc_resp.num_bytes :%d, alloc_resp.handle :%lx, alloc_resp.mem_req_result :%lx\n", pr_debug("memshare: alloc_resp.num_bytes :%d, alloc_resp.handle :%lx, alloc_resp.mem_req_result :%lx\n", alloc_resp->dhms_mem_alloc_addr_info[0].num_bytes, (unsigned long int) alloc_resp->dhms_mem_alloc_addr_info[0].phy_addr, Loading @@ -355,7 +410,6 @@ static int handle_alloc_generic_req(void *req_h, void *req, void *conn_h) if (rc < 0) pr_err("In %s, Error sending the alloc request: %d\n", __func__, rc); return rc; } Loading Loading @@ -405,7 +459,7 @@ static int handle_free_generic_req(void *req_h, void *req, void *conn_h) memset(&free_resp, 0, sizeof(struct mem_free_generic_resp_msg_v01)); free_resp.resp.error = QMI_ERR_INTERNAL_V01; free_resp.resp.result = QMI_RESULT_FAILURE_V01; pr_debug("Client id: %d proc id: %d\n", free_req->client_id, pr_debug("memshare: 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); if (client_id == DHMS_MEM_CLIENT_INVALID) { Loading drivers/soc/qcom/memshare/msm_memshare.h +3 −1 Original line number Diff line number Diff line /* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -49,6 +49,8 @@ struct mem_blocks { void *virtual_addr; /* Release memory only when XPU is released*/ uint8_t free_memory; /* Need Hypervisor mapping*/ uint8_t hyp_mapping; }; int memshare_alloc(struct device *dev, Loading Loading
arch/arm/boot/dts/qcom/msm8996.dtsi +25 −0 Original line number Diff line number Diff line Loading @@ -2776,6 +2776,31 @@ }; }; qcom,memshare { compatible = "qcom,memshare"; qcom,client_1 { compatible = "qcom,memshare-peripheral"; qcom,peripheral-size = <0x200000>; qcom,client-id = <0>; label = "modem"; }; qcom,client_2 { compatible = "qcom,memshare-peripheral"; qcom,peripheral-size = <0x300000>; qcom,client-id = <2>; label = "modem"; }; qcom,client_3 { compatible = "qcom,memshare-peripheral"; qcom,peripheral-size = <0x0>; qcom,client-id = <1>; label = "modem"; }; }; qcom,msm-core@70000 { compatible = "qcom,apss-core-ea"; reg = <0x70000 0x1000>; Loading
drivers/soc/qcom/memshare/msm_memshare.c +64 −10 Original line number Diff line number Diff line /* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -25,6 +25,8 @@ #include "msm_memshare.h" #include "heap_mem_ext_v01.h" #include <soc/qcom/secure_buffer.h> /* Macros */ #define MEMSHARE_DEV_NAME "memshare" #define MEMSHARE_CHILD_DEV_NAME "memshare_child" Loading Loading @@ -144,14 +146,10 @@ static int check_client(int client_id, int proc, int request) void free_client(int id) { memblock[id].size = 0; memblock[id].phy_addr = 0; memblock[id].virtual_addr = 0; memblock[id].alloted = 0; memblock[id].client_id = DHMS_MEM_CLIENT_INVALID; memblock[id].guarantee = 0; memblock[id].peripheral = -1; memblock[id].sequence_id = -1; memblock[id].memory_type = MEMORY_CMA; Loading Loading @@ -191,6 +189,7 @@ void initialize_client(void) memblock[i].sequence_id = -1; memblock[i].memory_type = MEMORY_CMA; memblock[i].free_memory = 0; memblock[i].hyp_mapping = 0; } dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs); } Loading @@ -199,6 +198,10 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code, void *_cmd) { int i; int ret; u32 source_vmlist[2] = {VMID_HLOS, VMID_MSS_MSA}; int dest_vmids[1] = {VMID_HLOS}; int dest_perms[1] = {PERM_READ|PERM_WRITE}; switch (code) { Loading @@ -222,8 +225,28 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code, DHMS_MEM_PROC_MPSS_V01 && !memblock[i].guarantee && memblock[i].alloted) { pr_err("memshare: Freeing memory for client id: %d\n", pr_debug("memshare: Freeing memory for client id: %d\n", memblock[i].client_id); ret = hyp_assign_phys( memblock[i].phy_addr, memblock[i].size, source_vmlist, 2, dest_vmids, dest_perms, 1); if (ret && memblock[i].hyp_mapping == 1) { /* * This is an error case as hyp * mapping was successful * earlier but during unmap * it lead to failure. */ pr_err("memshare: %s, failed to unmap the region\n", __func__); memblock[i].hyp_mapping = 1; } else { memblock[i].hyp_mapping = 0; } dma_free_attrs(memsh_drv->dev, memblock[i].size, memblock[i].virtual_addr, Loading @@ -248,6 +271,32 @@ static struct notifier_block nb = { .notifier_call = modem_notifier_cb, }; static void shared_hyp_mapping(int client_id) { int ret; u32 source_vmlist[1] = {VMID_HLOS}; int dest_vmids[2] = {VMID_HLOS, VMID_MSS_MSA}; int dest_perms[2] = {PERM_READ|PERM_WRITE, PERM_READ|PERM_WRITE}; if (client_id == DHMS_MEM_CLIENT_INVALID) { pr_err("memshare: %s, Invalid Client\n", __func__); return; } ret = hyp_assign_phys(memblock[client_id].phy_addr, memblock[client_id].size, source_vmlist, 1, dest_vmids, dest_perms, 2); if (ret != 0) { pr_err("memshare: hyp_assign_phys failed size=%u err=%d\n", memblock[client_id].size, ret); return; } memblock[client_id].hyp_mapping = 1; } static int handle_alloc_req(void *req_h, void *req, void *conn_h) { struct mem_alloc_req_msg_v01 *alloc_req; Loading Loading @@ -341,9 +390,15 @@ static int handle_alloc_generic_req(void *req_h, void *req, void *conn_h) memblock[client_id].sequence_id = alloc_req->sequence_id; fill_alloc_response(alloc_resp, client_id, &resp); /* * Perform the Hypervisor mapping in order to avoid XPU viloation * to the allocated region for Modem Clients */ if (!memblock[client_id].hyp_mapping && memblock[client_id].alloted) shared_hyp_mapping(client_id); mutex_unlock(&memsh_drv->mem_share); pr_debug("alloc_resp.num_bytes :%d, alloc_resp.handle :%lx, alloc_resp.mem_req_result :%lx\n", pr_debug("memshare: alloc_resp.num_bytes :%d, alloc_resp.handle :%lx, alloc_resp.mem_req_result :%lx\n", alloc_resp->dhms_mem_alloc_addr_info[0].num_bytes, (unsigned long int) alloc_resp->dhms_mem_alloc_addr_info[0].phy_addr, Loading @@ -355,7 +410,6 @@ static int handle_alloc_generic_req(void *req_h, void *req, void *conn_h) if (rc < 0) pr_err("In %s, Error sending the alloc request: %d\n", __func__, rc); return rc; } Loading Loading @@ -405,7 +459,7 @@ static int handle_free_generic_req(void *req_h, void *req, void *conn_h) memset(&free_resp, 0, sizeof(struct mem_free_generic_resp_msg_v01)); free_resp.resp.error = QMI_ERR_INTERNAL_V01; free_resp.resp.result = QMI_RESULT_FAILURE_V01; pr_debug("Client id: %d proc id: %d\n", free_req->client_id, pr_debug("memshare: 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); if (client_id == DHMS_MEM_CLIENT_INVALID) { Loading
drivers/soc/qcom/memshare/msm_memshare.h +3 −1 Original line number Diff line number Diff line /* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -49,6 +49,8 @@ struct mem_blocks { void *virtual_addr; /* Release memory only when XPU is released*/ uint8_t free_memory; /* Need Hypervisor mapping*/ uint8_t hyp_mapping; }; int memshare_alloc(struct device *dev, Loading