From 5c3224adf43bcbd3184bdd42d9ea12b155ae2bda Mon Sep 17 00:00:00 2001 From: Chris Goldsworthy Date: Wed, 31 Aug 2022 19:07:19 -0700 Subject: [PATCH 1/9] mem-buf: Allow selective usage of *memory_subsection functions add_memory_subsection() and remove_memory_subsection() are only needed on the TVM and OEM VMs. These are downstream functions as well. Thus, selectively allow them to be enabled so that we only compile them on downstream kernels. Change-Id: I8416cd8eb8db74cf8a3cfbc8e3d7ea2fff112353 Signed-off-by: Chris Goldsworthy --- drivers/soc/qcom/mem_buf/Kconfig | 14 ++++++++++++++ drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c | 2 ++ drivers/soc/qcom/mem_buf/mem-buf-dev.h | 14 ++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/drivers/soc/qcom/mem_buf/Kconfig b/drivers/soc/qcom/mem_buf/Kconfig index 273d1a77dd1a..13f63ec7b3bd 100644 --- a/drivers/soc/qcom/mem_buf/Kconfig +++ b/drivers/soc/qcom/mem_buf/Kconfig @@ -27,6 +27,20 @@ config QCOM_MEM_BUF_DEV config QCOM_MEM_BUF_DEV_GH bool +config QCOM_MEM_BUF_UPDATE_S1 + tristate "Map imported memory into the S1 logical kernel mapping for cache maintenance" + depends on QCOM_MEM_BUF_DEV_GH + help + When mapping memory into a VM, we must add it to the logical mapping in Linux in + order to perform cache maintenance on the memory. The default functions used for + adding memory, add_memory(), only maps memory at 128 MB chunks and has a 256 KB + overhead in the page table space it consumes (assuming the logical mapping is not + using block mappings). We accordingly use a downstream functions instead - + add_memory_subsection() - that adds memory on a section-size granularity + (currently 4 MB). Select this config option to enable the usage of these functions + on VMs, where these functions will be available using our downstream kernels. + If unsure, say N. + config QCOM_MEM_BUF_MSGQ tristate "Qualcomm Technologies, Inc. Memory Buffer Message Queue Support" depends on GH_MSGQ && QCOM_MEM_BUF_DEV_GH diff --git a/drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c b/drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c index 18194d375677..c227d7bf966e 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c +++ b/drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c @@ -252,6 +252,7 @@ int mem_buf_unmap_mem_s2(gh_memparcel_handle_t memparcel_hdl) } EXPORT_SYMBOL(mem_buf_unmap_mem_s2); +#ifdef CONFIG_QCOM_MEM_BUF_UPDATE_S1 int mem_buf_map_mem_s1(struct gh_sgl_desc *sgl_desc) { u64 base, size; @@ -300,6 +301,7 @@ int mem_buf_unmap_mem_s1(struct gh_sgl_desc *sgl_desc) return ret; } EXPORT_SYMBOL(mem_buf_unmap_mem_s1); +#endif /* CONFIG_QCOM_MEM_BUF_UPDATE_S1 */ static int mem_buf_hyp_assign_table_gh(struct gh_sgl_desc *sgl_desc, int src_vmid, struct gh_acl_desc *acl_desc) diff --git a/drivers/soc/qcom/mem_buf/mem-buf-dev.h b/drivers/soc/qcom/mem_buf/mem-buf-dev.h index 04a44dc6beca..ccafbccbe543 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-dev.h +++ b/drivers/soc/qcom/mem_buf/mem-buf-dev.h @@ -31,8 +31,22 @@ int mem_buf_hyp_assign_table(struct sg_table *sgt, u32 *src_vmid, int source_nel int *dest_vmids, int *dest_perms, int dest_nelems); #ifdef CONFIG_QCOM_MEM_BUF_DEV_GH + +#ifdef CONFIG_QCOM_MEM_BUF_UPDATE_S1 int mem_buf_map_mem_s1(struct gh_sgl_desc *sgl_desc); int mem_buf_unmap_mem_s1(struct gh_sgl_desc *sgl_desc); +#else +static inline int mem_buf_map_mem_s1(struct gh_sgl_desc *sgl_desc) +{ + return -EINVAL; +} + +static inline int mem_buf_unmap_mem_s1(struct gh_sgl_desc *sgl_desc) +{ + return -EINVAL; +} +#endif /* CONFIG_QCOM_MEM_BUF_UPDATE_S1 */ + struct gh_acl_desc *mem_buf_vmid_perm_list_to_gh_acl(int *vmids, int *perms, unsigned int nr_acl_entries); struct gh_sgl_desc *mem_buf_sgt_to_gh_sgl_desc(struct sg_table *sgt); From c4036c4aa71b4b5bab530a6c5ab89165b975fd87 Mon Sep 17 00:00:00 2001 From: Chris Goldsworthy Date: Wed, 31 Aug 2022 19:04:49 -0700 Subject: [PATCH 2/9] defconfig: pineapple: Enable configs for mem-buf CPU use cases Enable CONFIG_QCOM_MEM_BUF_MSGQ, CONFIG_QCOM_MEM_BUF_GH and CONFIG_QCOM_MEM_BUF_DEV_GH to allow mem-buf CPU use cases to be exercised. Change-Id: I15bbb098c1ba28924f73b203718203f4dbd6c2bd Signed-off-by: Chris Goldsworthy --- arch/arm64/configs/vendor/pineapple_GKI.config | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm64/configs/vendor/pineapple_GKI.config b/arch/arm64/configs/vendor/pineapple_GKI.config index dd903e36c353..5e86cfb5d5e7 100644 --- a/arch/arm64/configs/vendor/pineapple_GKI.config +++ b/arch/arm64/configs/vendor/pineapple_GKI.config @@ -83,7 +83,9 @@ CONFIG_QCOM_MDT_LOADER=m CONFIG_QCOM_MEMORY_DUMP_V2=m CONFIG_QCOM_MEM_BUF=m CONFIG_QCOM_MEM_BUF_DEV=m -# CONFIG_QCOM_MEM_BUF_GH is not set +CONFIG_QCOM_MEM_BUF_DEV_GH=y +CONFIG_QCOM_MEM_BUF_GH=y +CONFIG_QCOM_MEM_BUF_MSGQ=m # CONFIG_QCOM_MINIDUMP is not set # CONFIG_QCOM_MSM_IPCC is not set CONFIG_QCOM_PANIC_ON_NOTIF_TIMEOUT=y From a0663e611c1f5473c5541490bc5c1636879fc890 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Thu, 19 May 2022 17:14:17 -0700 Subject: [PATCH 3/9] mem-buf: Rename gh_rm_trans_type to trans_type Rename variables to increase readability. Change-Id: Iec504384e31b76e06c0f30686bb1b332ac85cce5 Signed-off-by: Patrick Daly --- drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c | 4 ++-- drivers/soc/qcom/mem_buf/mem-buf-dev.c | 2 +- drivers/soc/qcom/mem_buf/mem-buf-dev.h | 10 +++++----- drivers/soc/qcom/mem_buf/mem-buf-gh.c | 23 +++++++++++----------- drivers/soc/qcom/mem_buf/mem-buf-msgq.c | 6 +++--- drivers/soc/qcom/mem_buf/mem-buf-msgq.h | 12 +++++------ drivers/soc/qcom/mem_buf/mem_buf_dma_buf.c | 4 ++-- 7 files changed, 31 insertions(+), 30 deletions(-) diff --git a/drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c b/drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c index c227d7bf966e..810f62273533 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c +++ b/drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c @@ -181,7 +181,7 @@ static int mem_buf_hyp_assign_table_gh(struct gh_sgl_desc *sgl_desc, int src_vmi GH_RM_TRANS_TYPE_LEND - unmodified. GH_RM_TRANS_TYPE_SHARE - unmodified. */ -struct gh_sgl_desc *mem_buf_map_mem_s2(int op, gh_memparcel_handle_t *__memparcel_hdl, +struct gh_sgl_desc *mem_buf_map_mem_s2(u32 op, gh_memparcel_handle_t *__memparcel_hdl, struct gh_acl_desc *acl_desc, int src_vmid) { int ret, ret2; @@ -328,7 +328,7 @@ static int mem_buf_hyp_assign_table_gh(struct gh_sgl_desc *sgl_desc, int src_vmi return ret; } -int mem_buf_assign_mem_gunyah(int op, struct sg_table *sgt, +int mem_buf_assign_mem_gunyah(u32 op, struct sg_table *sgt, struct mem_buf_lend_kernel_arg *arg) { int ret, i; diff --git a/drivers/soc/qcom/mem_buf/mem-buf-dev.c b/drivers/soc/qcom/mem_buf/mem-buf-dev.c index 4115ac8daa38..30cb429adca3 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-dev.c +++ b/drivers/soc/qcom/mem_buf/mem-buf-dev.c @@ -43,7 +43,7 @@ int mem_buf_hyp_assign_table(struct sg_table *sgt, u32 *src_vmid, int source_nel return ret; } -int mem_buf_assign_mem(int op, struct sg_table *sgt, +int mem_buf_assign_mem(u32 op, struct sg_table *sgt, struct mem_buf_lend_kernel_arg *arg) { int src_vmid[] = {current_vmid}; diff --git a/drivers/soc/qcom/mem_buf/mem-buf-dev.h b/drivers/soc/qcom/mem_buf/mem-buf-dev.h index ccafbccbe543..ea578b792cf6 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-dev.h +++ b/drivers/soc/qcom/mem_buf/mem-buf-dev.h @@ -22,7 +22,7 @@ extern unsigned char mem_buf_capability; extern struct device *mem_buf_dev; /* Hypervisor Interface */ -int mem_buf_assign_mem(int op, struct sg_table *sgt, +int mem_buf_assign_mem(u32 op, struct sg_table *sgt, struct mem_buf_lend_kernel_arg *arg); int mem_buf_unassign_mem(struct sg_table *sgt, int *src_vmids, unsigned int nr_acl_entries, @@ -50,14 +50,14 @@ static inline int mem_buf_unmap_mem_s1(struct gh_sgl_desc *sgl_desc) struct gh_acl_desc *mem_buf_vmid_perm_list_to_gh_acl(int *vmids, int *perms, unsigned int nr_acl_entries); struct gh_sgl_desc *mem_buf_sgt_to_gh_sgl_desc(struct sg_table *sgt); -struct gh_sgl_desc *mem_buf_map_mem_s2(int op, gh_memparcel_handle_t *__memparcel_hdl, +struct gh_sgl_desc *mem_buf_map_mem_s2(u32 op, gh_memparcel_handle_t *__memparcel_hdl, struct gh_acl_desc *acl_desc, int src_vmid); int mem_buf_unmap_mem_s2(gh_memparcel_handle_t memparcel_hdl); int mem_buf_gh_acl_desc_to_vmid_perm_list(struct gh_acl_desc *acl_desc, int **vmids, int **perms); size_t mem_buf_get_sgl_buf_size(struct gh_sgl_desc *sgl_desc); struct sg_table *dup_gh_sgl_desc_to_sgt(struct gh_sgl_desc *sgl_desc); -int mem_buf_assign_mem_gunyah(int op, struct sg_table *sgt, +int mem_buf_assign_mem_gunyah(u32 op, struct sg_table *sgt, struct mem_buf_lend_kernel_arg *arg); int mem_buf_unassign_mem_gunyah(gh_memparcel_handle_t memparcel_hdl); #else @@ -82,7 +82,7 @@ static inline struct gh_sgl_desc *mem_buf_sgt_to_gh_sgl_desc(struct sg_table *sg return ERR_PTR(-EINVAL); } -static inline struct gh_sgl_desc *mem_buf_map_mem_s2(int op, gh_memparcel_handle_t *__memparcel_hdl, +static inline struct gh_sgl_desc *mem_buf_map_mem_s2(u32 op, gh_memparcel_handle_t *__memparcel_hdl, struct gh_acl_desc *acl_desc, int src_vmid) { return ERR_PTR(-EINVAL); @@ -109,7 +109,7 @@ static inline struct sg_table *dup_gh_sgl_desc_to_sgt(struct gh_sgl_desc *sgl_de return ERR_PTR(-EINVAL); } -static inline int mem_buf_assign_mem_gunyah(int op, struct sg_table *sgt, +static inline int mem_buf_assign_mem_gunyah(u32 op, struct sg_table *sgt, struct mem_buf_lend_kernel_arg *arg) { return -EINVAL; diff --git a/drivers/soc/qcom/mem_buf/mem-buf-gh.c b/drivers/soc/qcom/mem_buf/mem-buf-gh.c index 46385955214f..9a8131039281 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-gh.c +++ b/drivers/soc/qcom/mem_buf/mem-buf-gh.c @@ -56,7 +56,7 @@ struct mem_buf_rmt_msg { * @secure_alloc: Denotes if the memory was assigned to the targeted VMs as part * of the allocation step * @hdl: The memparcel handle associated with the memory - * @gh_rm_trans_type: The type of memory transfer associated with the memory (donation, + * @trans_type: The type of memory transfer associated with the memory (donation, * share, lend). * @entry: List entry for maintaining a list of memory buffers that are lent * out. @@ -72,7 +72,7 @@ struct mem_buf_xfer_mem { void *mem_type_data; struct sg_table *mem_sgt; bool secure_alloc; - int gh_rm_trans_type; + u32 trans_type; gh_memparcel_handle_t hdl; struct list_head entry; u32 nr_acl_entries; @@ -91,7 +91,7 @@ struct mem_buf_xfer_mem { * associated with the memory buffer that was allocated from another VM. * @memparcel_hdl: The handle associated with the memparcel that represents the * memory buffer. - * @gh_rm_trans_type: The type of memory transfer associated with the memory (donation, + * @trans_type: The type of memory transfer associated with the memory (donation, * share, lend). * @src_mem_type: The type of memory that was allocated on the remote VM * @src_data: Memory type specific data used by the remote VM when performing @@ -109,7 +109,7 @@ struct mem_buf_desc { struct gh_acl_desc *acl_desc; struct gh_sgl_desc *sgl_desc; gh_memparcel_handle_t memparcel_hdl; - int gh_rm_trans_type; + u32 trans_type; enum mem_buf_mem_type src_mem_type; void *src_data; enum mem_buf_mem_type dst_mem_type; @@ -343,7 +343,7 @@ static int mem_buf_get_mem_xfer_type_gh(struct gh_acl_desc *acl_desc, int owner_ * Check whether donate operation is supported. If not, use * lend instead. Share is not supported for remotealloc. */ -static int get_alloc_req_xfer_type(struct mem_buf_xfer_mem *xfer_mem) +static u32 get_alloc_req_xfer_type(struct mem_buf_xfer_mem *xfer_mem) { static bool initialized; static int alloc_req_xfer_type; @@ -378,7 +378,8 @@ static int get_alloc_req_xfer_type(struct mem_buf_xfer_mem *xfer_mem) static struct mem_buf_xfer_mem *mem_buf_process_alloc_req(void *req) { - int ret, xfer_type; + int ret; + u32 xfer_type; struct mem_buf_xfer_mem *xfer_mem; struct mem_buf_lend_kernel_arg arg = {0}; @@ -401,7 +402,7 @@ static struct mem_buf_xfer_mem *mem_buf_process_alloc_req(void *req) goto err_assign_mem; xfer_mem->hdl = arg.memparcel_hdl; - xfer_mem->gh_rm_trans_type = xfer_type; + xfer_mem->trans_type = xfer_type; } mutex_lock(&mem_buf_xfer_mem_list_lock); @@ -479,7 +480,7 @@ static void mem_buf_alloc_req_work(struct work_struct *work) } else { ret = 0; hdl = xfer_mem->hdl; - trans_type = xfer_mem->gh_rm_trans_type; + trans_type = xfer_mem->trans_type; } resp_msg = mem_buf_construct_alloc_resp(req_msg, ret, hdl, trans_type); @@ -557,7 +558,7 @@ static int mem_buf_alloc_resp_hdlr(void *hdlr_data, void *msg_buf, size_t size, pr_err("%s remote allocation failed rc: %d\n", __func__, ret); } else { membuf->memparcel_hdl = get_alloc_resp_hdl(alloc_resp); - membuf->gh_rm_trans_type = get_alloc_resp_trans_type(alloc_resp); + membuf->trans_type = get_alloc_resp_trans_type(alloc_resp); } kfree(msg_buf); @@ -676,7 +677,7 @@ static void mem_buf_relinquish_mem(struct mem_buf_desc *membuf) u32 txn_id = mem_buf_retrieve_txn_id(membuf->txn); if (membuf->memparcel_hdl != MEM_BUF_MEMPARCEL_INVALID) { - if (membuf->gh_rm_trans_type != GH_RM_TRANS_TYPE_DONATE) { + if (membuf->trans_type != GH_RM_TRANS_TYPE_DONATE) { ret = mem_buf_unmap_mem_s2(membuf->memparcel_hdl); if (ret) return; @@ -974,7 +975,7 @@ static void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) if (ret) goto err_mem_req; - op = membuf->gh_rm_trans_type; + op = membuf->trans_type; sgl_desc = mem_buf_map_mem_s2(op, &membuf->memparcel_hdl, membuf->acl_desc, VMID_HLOS); if (IS_ERR(sgl_desc)) goto err_map_mem_s2; diff --git a/drivers/soc/qcom/mem_buf/mem-buf-msgq.c b/drivers/soc/qcom/mem_buf/mem-buf-msgq.c index 1f257b9234ff..f67c758f6266 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-msgq.c +++ b/drivers/soc/qcom/mem_buf/mem-buf-msgq.c @@ -134,11 +134,11 @@ EXPORT_SYMBOL(mem_buf_construct_alloc_req); * @req_msg: The request message that is being replied to. * @alloc_ret: The return code of the allocation. * @memparcel_hdl: The memparcel handle that corresponds to the memory that was allocated. - * @gh_rm_trans_type: The type of memory transfer associated with the response (i.e. donation, + * @trans_type: The type of memory transfer associated with the response (i.e. donation, * sharing, or lending). */ void *mem_buf_construct_alloc_resp(void *req_msg, s32 alloc_ret, - gh_memparcel_handle_t memparcel_hdl, int gh_rm_trans_type) + gh_memparcel_handle_t memparcel_hdl, u32 trans_type) { struct mem_buf_alloc_req *req = req_msg; struct mem_buf_alloc_resp *resp_msg = kzalloc(sizeof(*resp_msg), GFP_KERNEL); @@ -151,7 +151,7 @@ void *mem_buf_construct_alloc_resp(void *req_msg, s32 alloc_ret, resp_msg->hdr.msg_size = sizeof(*resp_msg); resp_msg->ret = alloc_ret; resp_msg->hdl = memparcel_hdl; - resp_msg->gh_rm_trans_type = gh_rm_trans_type; + resp_msg->trans_type = trans_type; return resp_msg; } diff --git a/drivers/soc/qcom/mem_buf/mem-buf-msgq.h b/drivers/soc/qcom/mem_buf/mem-buf-msgq.h index 374fb3882403..e846ef83e0f1 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-msgq.h +++ b/drivers/soc/qcom/mem_buf/mem-buf-msgq.h @@ -70,14 +70,14 @@ struct mem_buf_alloc_req { * @hdl: The memparcel handle associated with the memory allocated to the * receiving VM. This field is only meaningful if the allocation on the remote * VM was carried out successfully, as denoted by @ret. - * @gh_rm_trans_type: Denotes the type of memory transfer associated with the response + * @trans_type: Denotes the type of memory transfer associated with the response * (i.e. memory donation, sharing, or lending). */ struct mem_buf_alloc_resp { struct mem_buf_msg_hdr hdr; s32 ret; u32 hdl; - int gh_rm_trans_type; + u32 trans_type; } __packed; /** @@ -171,9 +171,9 @@ static inline u32 get_alloc_resp_hdl(struct mem_buf_alloc_resp *resp) return resp->hdl; } -static inline int get_alloc_resp_trans_type(struct mem_buf_alloc_resp *resp) +static inline u32 get_alloc_resp_trans_type(struct mem_buf_alloc_resp *resp) { - return resp->gh_rm_trans_type; + return resp->trans_type; } static inline u32 get_relinquish_req_txn_id(struct mem_buf_alloc_relinquish *relinquish_msg) @@ -197,7 +197,7 @@ void *mem_buf_construct_alloc_req(void *mem_buf_txn, size_t alloc_size, struct gh_acl_desc *acl_desc, enum mem_buf_mem_type src_mem_type, void *src_data); void *mem_buf_construct_alloc_resp(void *req_msg, s32 alloc_ret, - gh_memparcel_handle_t memparcel_hdl, int gh_rm_trans_type); + gh_memparcel_handle_t memparcel_hdl, u32 trans_type); void *mem_buf_construct_relinquish_msg(u32 txn_id, gh_memparcel_handle_t memparcel_hdl); #else static inline void *mem_buf_msgq_register(const char *msgq_name, @@ -238,7 +238,7 @@ static inline void *mem_buf_construct_alloc_req(void *mem_buf_txn, size_t alloc_ } static inline void *mem_buf_construct_alloc_resp(void *req_msg, s32 alloc_ret, - gh_memparcel_handle_t memparcel_hdl, int gh_rm_trans_type) + gh_memparcel_handle_t memparcel_hdl, u32 trans_type) { return ERR_PTR(-ENODEV); } diff --git a/drivers/soc/qcom/mem_buf/mem_buf_dma_buf.c b/drivers/soc/qcom/mem_buf/mem_buf_dma_buf.c index 56deb4d8ffc9..c1f080885c44 100644 --- a/drivers/soc/qcom/mem_buf/mem_buf_dma_buf.c +++ b/drivers/soc/qcom/mem_buf/mem_buf_dma_buf.c @@ -390,7 +390,7 @@ bool mem_buf_vmperm_can_vmap(struct mem_buf_vmperm *vmperm) EXPORT_SYMBOL(mem_buf_vmperm_can_vmap); static int validate_lend_vmids(struct mem_buf_lend_kernel_arg *arg, - int op) + u32 op) { int i; bool found = false; @@ -443,7 +443,7 @@ static bool validate_lend_mapcount(struct mem_buf_vmperm *vmperm, static int mem_buf_lend_internal(struct dma_buf *dmabuf, struct mem_buf_lend_kernel_arg *arg, - int op) + u32 op) { struct mem_buf_vmperm *vmperm; struct sg_table *sgt; From 010e2b03f35f3bdc282764ce445d229f44f600df Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Wed, 15 Jun 2022 22:17:24 -0700 Subject: [PATCH 4/9] mem-buf: Remove logic for detecting donate support Support to donate memory is always present on compatible hypervisor builds. Change-Id: Ic7a4c03716277e379014bb31e58358cffb85409c Signed-off-by: Patrick Daly --- drivers/soc/qcom/mem_buf/mem-buf-gh.c | 39 +-------------------------- 1 file changed, 1 insertion(+), 38 deletions(-) diff --git a/drivers/soc/qcom/mem_buf/mem-buf-gh.c b/drivers/soc/qcom/mem_buf/mem-buf-gh.c index 9a8131039281..c7a993a3e1dd 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-gh.c +++ b/drivers/soc/qcom/mem_buf/mem-buf-gh.c @@ -339,43 +339,6 @@ static int mem_buf_get_mem_xfer_type_gh(struct gh_acl_desc *acl_desc, int owner_ return GH_RM_TRANS_TYPE_LEND; } -/* - * Check whether donate operation is supported. If not, use - * lend instead. Share is not supported for remotealloc. - */ -static u32 get_alloc_req_xfer_type(struct mem_buf_xfer_mem *xfer_mem) -{ - static bool initialized; - static int alloc_req_xfer_type; - struct mem_buf_lend_kernel_arg arg; - int vmids[] = {VMID_TUIVM}; - int perms[] = {PERM_READ | PERM_WRITE | PERM_EXEC}; - int ret; - - if (initialized) - return alloc_req_xfer_type; - - arg.nr_acl_entries = ARRAY_SIZE(vmids); - arg.vmids = vmids; - arg.perms = perms; - arg.flags = 0; - arg.label = 0; - - ret = mem_buf_assign_mem(GH_RM_TRANS_TYPE_DONATE, xfer_mem->mem_sgt, &arg); - if (ret) { - initialized = true; - alloc_req_xfer_type = GH_RM_TRANS_TYPE_LEND; - } else { - initialized = true; - alloc_req_xfer_type = GH_RM_TRANS_TYPE_DONATE; - - mem_buf_unassign_mem(xfer_mem->mem_sgt, vmids, ARRAY_SIZE(vmids), - arg.memparcel_hdl); - } - pr_info("%s: xfer_type set to %d\n", __func__, alloc_req_xfer_type); - return alloc_req_xfer_type; -} - static struct mem_buf_xfer_mem *mem_buf_process_alloc_req(void *req) { int ret; @@ -392,7 +355,7 @@ static struct mem_buf_xfer_mem *mem_buf_process_alloc_req(void *req) goto err_rmt_alloc; if (!xfer_mem->secure_alloc) { - xfer_type = get_alloc_req_xfer_type(xfer_mem); + xfer_type = GH_RM_TRANS_TYPE_DONATE; arg.nr_acl_entries = xfer_mem->nr_acl_entries; arg.vmids = xfer_mem->dst_vmids; From 5a01357c0f8de9d90576498a8afb14e8587c1b26 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Wed, 15 Jun 2022 22:15:27 -0700 Subject: [PATCH 5/9] mem-buf: Update message format to include trans_type Allow a guest VM to choose whether the memory it requests is obtained via the lend, share or donate hypervisor call. Change-Id: I7e1f25ea0f9b0ec99d4a7afd79f206f9a2b67d85 Signed-off-by: Patrick Daly --- drivers/soc/qcom/mem_buf/mem-buf-gh.c | 19 ++++++++++--------- drivers/soc/qcom/mem_buf/mem-buf-msgq.c | 9 +++++---- drivers/soc/qcom/mem_buf/mem-buf-msgq.h | 24 +++++++++++++----------- include/linux/mem-buf.h | 3 +++ 4 files changed, 31 insertions(+), 24 deletions(-) diff --git a/drivers/soc/qcom/mem_buf/mem-buf-gh.c b/drivers/soc/qcom/mem_buf/mem-buf-gh.c index c7a993a3e1dd..b81c523a479e 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-gh.c +++ b/drivers/soc/qcom/mem_buf/mem-buf-gh.c @@ -355,7 +355,7 @@ static struct mem_buf_xfer_mem *mem_buf_process_alloc_req(void *req) goto err_rmt_alloc; if (!xfer_mem->secure_alloc) { - xfer_type = GH_RM_TRANS_TYPE_DONATE; + xfer_type = get_alloc_req_xfer_type(req); arg.nr_acl_entries = xfer_mem->nr_acl_entries; arg.vmids = xfer_mem->dst_vmids; @@ -430,7 +430,6 @@ static void mem_buf_alloc_req_work(struct work_struct *work) void *resp_msg; struct mem_buf_xfer_mem *xfer_mem; gh_memparcel_handle_t hdl = 0; - int trans_type = 0; int ret; trace_receive_alloc_req(req_msg); @@ -443,10 +442,9 @@ static void mem_buf_alloc_req_work(struct work_struct *work) } else { ret = 0; hdl = xfer_mem->hdl; - trans_type = xfer_mem->trans_type; } - resp_msg = mem_buf_construct_alloc_resp(req_msg, ret, hdl, trans_type); + resp_msg = mem_buf_construct_alloc_resp(req_msg, ret, hdl); kfree(rmt_msg->msg); kfree(rmt_msg); if (IS_ERR(resp_msg)) @@ -521,7 +519,6 @@ static int mem_buf_alloc_resp_hdlr(void *hdlr_data, void *msg_buf, size_t size, pr_err("%s remote allocation failed rc: %d\n", __func__, ret); } else { membuf->memparcel_hdl = get_alloc_resp_hdl(alloc_resp); - membuf->trans_type = get_alloc_resp_trans_type(alloc_resp); } kfree(msg_buf); @@ -577,7 +574,8 @@ static int mem_buf_request_mem(struct mem_buf_desc *membuf) int ret; alloc_req_msg = mem_buf_construct_alloc_req(membuf->txn, membuf->size, membuf->acl_desc, - membuf->src_mem_type, membuf->src_data); + membuf->src_mem_type, membuf->src_data, + membuf->trans_type); if (IS_ERR(alloc_req_msg)) { ret = PTR_ERR(alloc_req_msg); goto out; @@ -882,7 +880,6 @@ static void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) struct file *filp; struct mem_buf_desc *membuf; struct gh_sgl_desc *sgl_desc; - int op; int perms = PERM_READ | PERM_WRITE | PERM_EXEC; if (!(mem_buf_capability & MEM_BUF_CAP_CONSUMER)) @@ -907,6 +904,7 @@ static void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) ret = PTR_ERR(membuf->acl_desc); goto err_alloc_acl_list; } + membuf->trans_type = alloc_data->trans_type; membuf->src_mem_type = alloc_data->src_mem_type; membuf->dst_mem_type = alloc_data->dst_mem_type; @@ -938,8 +936,8 @@ static void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) if (ret) goto err_mem_req; - op = membuf->trans_type; - sgl_desc = mem_buf_map_mem_s2(op, &membuf->memparcel_hdl, membuf->acl_desc, VMID_HLOS); + sgl_desc = mem_buf_map_mem_s2(membuf->trans_type, &membuf->memparcel_hdl, + membuf->acl_desc, VMID_HLOS); if (IS_ERR(sgl_desc)) goto err_map_mem_s2; membuf->sgl_desc = sgl_desc; @@ -1174,6 +1172,7 @@ static int mem_buf_prep_alloc_data(struct mem_buf_allocation_data *alloc_data, if (ret) goto err_acl; + /* alloc_data->trans_type set later according to src&dest_mem_type */ alloc_data->src_mem_type = allocation_args->src_mem_type; alloc_data->dst_mem_type = allocation_args->dst_mem_type; @@ -1236,6 +1235,8 @@ int mem_buf_alloc_fd(struct mem_buf_alloc_ioctl_arg *allocation_args) if (ret < 0) return ret; + /* Only donate is supported currently */ + alloc_data.trans_type = GH_RM_TRANS_TYPE_DONATE; membuf = mem_buf_alloc(&alloc_data); if (IS_ERR(membuf)) { ret = PTR_ERR(membuf); diff --git a/drivers/soc/qcom/mem_buf/mem-buf-msgq.c b/drivers/soc/qcom/mem_buf/mem-buf-msgq.c index f67c758f6266..95465d60f313 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-msgq.c +++ b/drivers/soc/qcom/mem_buf/mem-buf-msgq.c @@ -88,10 +88,12 @@ static void mem_buf_populate_alloc_req_arb_payload(void *dst, void *src, * with what permissions. * @src_mem_type: The type of memory that will be used to satisfy the allocation. * @src_data: A pointer to auxiliary data required to satisfy the allocation. + * @trans_type: One of GH_RM_TRANS_TYPE_DONATE/LEND/SHARE */ void *mem_buf_construct_alloc_req(void *mem_buf_txn, size_t alloc_size, struct gh_acl_desc *acl_desc, - enum mem_buf_mem_type src_mem_type, void *src_data) + enum mem_buf_mem_type src_mem_type, void *src_data, + u32 trans_type) { size_t tot_size, alloc_req_size, acl_desc_size; void *req_buf, *arb_payload; @@ -116,6 +118,7 @@ void *mem_buf_construct_alloc_req(void *mem_buf_txn, size_t alloc_size, req->hdr.msg_size = tot_size; req->size = alloc_size; req->src_mem_type = src_mem_type; + req->trans_type = trans_type; acl_desc_size = offsetof(struct gh_acl_desc, acl_entries[nr_acl_entries]); memcpy(&req->acl_desc, acl_desc, acl_desc_size); @@ -134,11 +137,10 @@ EXPORT_SYMBOL(mem_buf_construct_alloc_req); * @req_msg: The request message that is being replied to. * @alloc_ret: The return code of the allocation. * @memparcel_hdl: The memparcel handle that corresponds to the memory that was allocated. - * @trans_type: The type of memory transfer associated with the response (i.e. donation, * sharing, or lending). */ void *mem_buf_construct_alloc_resp(void *req_msg, s32 alloc_ret, - gh_memparcel_handle_t memparcel_hdl, u32 trans_type) + gh_memparcel_handle_t memparcel_hdl) { struct mem_buf_alloc_req *req = req_msg; struct mem_buf_alloc_resp *resp_msg = kzalloc(sizeof(*resp_msg), GFP_KERNEL); @@ -151,7 +153,6 @@ void *mem_buf_construct_alloc_resp(void *req_msg, s32 alloc_ret, resp_msg->hdr.msg_size = sizeof(*resp_msg); resp_msg->ret = alloc_ret; resp_msg->hdl = memparcel_hdl; - resp_msg->trans_type = trans_type; return resp_msg; } diff --git a/drivers/soc/qcom/mem_buf/mem-buf-msgq.h b/drivers/soc/qcom/mem_buf/mem-buf-msgq.h index e846ef83e0f1..f533c645c413 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-msgq.h +++ b/drivers/soc/qcom/mem_buf/mem-buf-msgq.h @@ -46,6 +46,7 @@ struct mem_buf_msg_hdr { * @hdr: Message header * @size: The size of the memory allocation to be performed on the remote VM. * @src_mem_type: The type of memory that the remote VM should allocate. + * @trans_type: One of GH_RM_TRANS_TYPE_DONATE/SHARE/LEND * @acl_desc: A GH ACL descriptor that describes the VMIDs that will be * accessing the memory, as well as what permissions each VMID will have. * @@ -59,6 +60,7 @@ struct mem_buf_alloc_req { struct mem_buf_msg_hdr hdr; u64 size; u32 src_mem_type; + u32 trans_type; struct gh_acl_desc acl_desc; } __packed; @@ -70,14 +72,12 @@ struct mem_buf_alloc_req { * @hdl: The memparcel handle associated with the memory allocated to the * receiving VM. This field is only meaningful if the allocation on the remote * VM was carried out successfully, as denoted by @ret. - * @trans_type: Denotes the type of memory transfer associated with the response * (i.e. memory donation, sharing, or lending). */ struct mem_buf_alloc_resp { struct mem_buf_msg_hdr hdr; s32 ret; u32 hdl; - u32 trans_type; } __packed; /** @@ -140,6 +140,11 @@ static inline u64 get_alloc_req_size(struct mem_buf_alloc_req *req) return req->size; } +static inline u64 get_alloc_req_xfer_type(struct mem_buf_alloc_req *req) +{ + return req->trans_type; +} + static inline void *get_alloc_req_arb_payload(struct mem_buf_alloc_req *req) { void *buf = req; @@ -171,11 +176,6 @@ static inline u32 get_alloc_resp_hdl(struct mem_buf_alloc_resp *resp) return resp->hdl; } -static inline u32 get_alloc_resp_trans_type(struct mem_buf_alloc_resp *resp) -{ - return resp->trans_type; -} - static inline u32 get_relinquish_req_txn_id(struct mem_buf_alloc_relinquish *relinquish_msg) { return relinquish_msg->hdr.txn_id; @@ -195,9 +195,10 @@ int mem_buf_retrieve_txn_id(void *mem_buf_txn); */ void *mem_buf_construct_alloc_req(void *mem_buf_txn, size_t alloc_size, struct gh_acl_desc *acl_desc, - enum mem_buf_mem_type src_mem_type, void *src_data); + enum mem_buf_mem_type src_mem_type, void *src_data, + u32 trans_type); void *mem_buf_construct_alloc_resp(void *req_msg, s32 alloc_ret, - gh_memparcel_handle_t memparcel_hdl, u32 trans_type); + gh_memparcel_handle_t memparcel_hdl); void *mem_buf_construct_relinquish_msg(u32 txn_id, gh_memparcel_handle_t memparcel_hdl); #else static inline void *mem_buf_msgq_register(const char *msgq_name, @@ -231,14 +232,15 @@ static inline void mem_buf_destroy_txn(void *mem_buf_msgq_hdl, void *mem_buf_txn static inline void *mem_buf_construct_alloc_req(void *mem_buf_txn, size_t alloc_size, struct gh_acl_desc *acl_desc, - enum mem_buf_mem_type src_mem_type, void *src_data) + enum mem_buf_mem_type src_mem_type, void *src_data, + u32 trans_type) { return ERR_PTR(-ENODEV); } static inline void *mem_buf_construct_alloc_resp(void *req_msg, s32 alloc_ret, - gh_memparcel_handle_t memparcel_hdl, u32 trans_type) + gh_memparcel_handle_t memparcel_hdl) { return ERR_PTR(-ENODEV); } diff --git a/include/linux/mem-buf.h b/include/linux/mem-buf.h index a018fe1c89eb..ad76a15ab279 100644 --- a/include/linux/mem-buf.h +++ b/include/linux/mem-buf.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _MEM_BUF_H @@ -38,6 +39,7 @@ int mem_buf_dma_buf_set_destructor(struct dma_buf *dmabuf, * @nr_acl_entries: The number of ACL entries in @acl_list * @acl_list: A list of VMID and permission pairs that describe what VMIDs will * have access to the memory, and with what permissions + * @trans_type: One of GH_RM_TRANS_TYPE_DONATE/LEND/SHARE * @src_mem_type: The type of memory that the remote VM should allocate * (e.g. ION memory) * @src_data: A pointer to memory type specific data that the remote VM may need @@ -52,6 +54,7 @@ struct mem_buf_allocation_data { unsigned int nr_acl_entries; int *vmids; int *perms; + u32 trans_type; enum mem_buf_mem_type src_mem_type; void *src_data; enum mem_buf_mem_type dst_mem_type; From 0f6efbf911756e03b9a834ba2aba64f4f9acab15 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Thu, 19 May 2022 18:35:02 -0700 Subject: [PATCH 6/9] mem-buf: Add infrastructure for requesting specific IPA address gh_rm_mem_accept allows a VM to request memory to be mapped to a specific IPA address. Modify function parameters to allow for future use of this feature. Change-Id: I6ad586886563e769549e4966369da48c27ca0a5c Signed-off-by: Patrick Daly --- drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c | 59 +++++++++++++++++------ drivers/soc/qcom/mem_buf/mem-buf-dev.h | 18 +++++-- drivers/soc/qcom/mem_buf/mem-buf-gh.c | 42 ++++++++++------ include/linux/mem-buf.h | 2 + 4 files changed, 86 insertions(+), 35 deletions(-) diff --git a/drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c b/drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c index 810f62273533..a990ed5a47ab 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c +++ b/drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c @@ -131,6 +131,24 @@ struct sg_table *dup_gh_sgl_desc_to_sgt(struct gh_sgl_desc *sgl_desc) } EXPORT_SYMBOL(dup_gh_sgl_desc_to_sgt); +struct gh_sgl_desc *dup_gh_sgl_desc(struct gh_sgl_desc *sgl_desc) +{ + size_t size; + struct gh_sgl_desc *copy; + + if (!sgl_desc) + return NULL; + + size = offsetof(struct gh_sgl_desc, sgl_entries[sgl_desc->n_sgl_entries]); + copy = kvmalloc(size, GFP_KERNEL); + if (!copy) + return ERR_PTR(-ENOMEM); + + memcpy(copy, sgl_desc, size); + return copy; +} +EXPORT_SYMBOL(dup_gh_sgl_desc); + size_t mem_buf_get_sgl_buf_size(struct gh_sgl_desc *sgl_desc) { size_t size = 0; @@ -176,13 +194,17 @@ static int mem_buf_hyp_assign_table_gh(struct gh_sgl_desc *sgl_desc, int src_vmi /* * @memparcel_hdl: * GH_RM_TRANS_TYPE_DONATE - memparcel_hdl will be set to MEM_BUF_MEMPARCEL_INVALID - on success, and (possibly) set to a different valid memparcel on error. This is - because accepting a donated memparcel handle destroys that handle. - GH_RM_TRANS_TYPE_LEND - unmodified. - GH_RM_TRANS_TYPE_SHARE - unmodified. + * on success, and (possibly) set to a different valid memparcel on error. This is + * because accepting a donated memparcel handle destroys that handle. + * GH_RM_TRANS_TYPE_LEND - unmodified. + * GH_RM_TRANS_TYPE_SHARE - unmodified. + * @sgl_desc: + * If *sgl_desc is not NULL, request specific IPA address(es). Otherwise, hypervisor + * will choose the IPA address, and return it here. */ -struct gh_sgl_desc *mem_buf_map_mem_s2(u32 op, gh_memparcel_handle_t *__memparcel_hdl, - struct gh_acl_desc *acl_desc, int src_vmid) +int mem_buf_map_mem_s2(u32 op, gh_memparcel_handle_t *__memparcel_hdl, + struct gh_acl_desc *acl_desc, struct gh_sgl_desc **__sgl_desc, + int src_vmid) { int ret, ret2; struct gh_sgl_desc *sgl_desc; @@ -190,24 +212,24 @@ struct gh_sgl_desc *mem_buf_map_mem_s2(u32 op, gh_memparcel_handle_t *__memparce GH_RM_MEM_ACCEPT_DONE; gh_memparcel_handle_t memparcel_hdl = *__memparcel_hdl; - if (!acl_desc) - return ERR_PTR(-EINVAL); + if (!acl_desc || !__sgl_desc) + return -EINVAL; /* * memory returns to its original IPA address when accepted by HLOS. For example, * scattered memory returns to being scattered memory. */ - if (current_vmid != VMID_HLOS) + if (current_vmid != VMID_HLOS || (*__sgl_desc && (*__sgl_desc)->n_sgl_entries == 1)) flags |= GH_RM_MEM_ACCEPT_MAP_IPA_CONTIGUOUS; pr_debug("%s: adding CPU MMU stage 2 mappings\n", __func__); sgl_desc = gh_rm_mem_accept(memparcel_hdl, GH_RM_MEM_TYPE_NORMAL, op, - flags, 0, acl_desc, NULL, + flags, 0, acl_desc, *__sgl_desc, NULL, 0); if (IS_ERR(sgl_desc)) { pr_err("%s failed to map memory in stage 2 rc: %d\n", __func__, PTR_ERR(sgl_desc)); - return sgl_desc; + return PTR_ERR(sgl_desc); } if (op == GH_RM_TRANS_TYPE_DONATE) @@ -218,7 +240,8 @@ struct gh_sgl_desc *mem_buf_map_mem_s2(u32 op, gh_memparcel_handle_t *__memparce goto err_relinquish; trace_map_mem_s2(memparcel_hdl, sgl_desc); - return sgl_desc; + *__sgl_desc = sgl_desc; + return 0; err_relinquish: if (op == GH_RM_TRANS_TYPE_DONATE) @@ -226,12 +249,18 @@ struct gh_sgl_desc *mem_buf_map_mem_s2(u32 op, gh_memparcel_handle_t *__memparce __memparcel_hdl); else ret2 = mem_buf_unmap_mem_s2(memparcel_hdl); - kvfree(sgl_desc); + + /* + * Only free sgl_desc if caller passed NULL in *__sgl_desc to request + * gh_rm_mem_accept to allocate new IPA/sgl_desc. + */ + if (sgl_desc != *__sgl_desc) + kvfree(sgl_desc); if (ret2) { pr_err("%s failed to recover\n", __func__); - return ERR_PTR(-EADDRNOTAVAIL); + return -EADDRNOTAVAIL; } - return ERR_PTR(ret); + return ret; } EXPORT_SYMBOL(mem_buf_map_mem_s2); diff --git a/drivers/soc/qcom/mem_buf/mem-buf-dev.h b/drivers/soc/qcom/mem_buf/mem-buf-dev.h index ea578b792cf6..9316e4709458 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-dev.h +++ b/drivers/soc/qcom/mem_buf/mem-buf-dev.h @@ -50,13 +50,15 @@ static inline int mem_buf_unmap_mem_s1(struct gh_sgl_desc *sgl_desc) struct gh_acl_desc *mem_buf_vmid_perm_list_to_gh_acl(int *vmids, int *perms, unsigned int nr_acl_entries); struct gh_sgl_desc *mem_buf_sgt_to_gh_sgl_desc(struct sg_table *sgt); -struct gh_sgl_desc *mem_buf_map_mem_s2(u32 op, gh_memparcel_handle_t *__memparcel_hdl, - struct gh_acl_desc *acl_desc, int src_vmid); +int mem_buf_map_mem_s2(u32 op, gh_memparcel_handle_t *__memparcel_hdl, + struct gh_acl_desc *acl_desc, struct gh_sgl_desc **sgl_desc, + int src_vmid); int mem_buf_unmap_mem_s2(gh_memparcel_handle_t memparcel_hdl); int mem_buf_gh_acl_desc_to_vmid_perm_list(struct gh_acl_desc *acl_desc, int **vmids, int **perms); size_t mem_buf_get_sgl_buf_size(struct gh_sgl_desc *sgl_desc); struct sg_table *dup_gh_sgl_desc_to_sgt(struct gh_sgl_desc *sgl_desc); +struct gh_sgl_desc *dup_gh_sgl_desc(struct gh_sgl_desc *sgl_desc); int mem_buf_assign_mem_gunyah(u32 op, struct sg_table *sgt, struct mem_buf_lend_kernel_arg *arg); int mem_buf_unassign_mem_gunyah(gh_memparcel_handle_t memparcel_hdl); @@ -82,10 +84,11 @@ static inline struct gh_sgl_desc *mem_buf_sgt_to_gh_sgl_desc(struct sg_table *sg return ERR_PTR(-EINVAL); } -static inline struct gh_sgl_desc *mem_buf_map_mem_s2(u32 op, gh_memparcel_handle_t *__memparcel_hdl, - struct gh_acl_desc *acl_desc, int src_vmid) +static inline int mem_buf_map_mem_s2(u32 op, gh_memparcel_handle_t *__memparcel_hdl, + struct gh_acl_desc *acl_desc, struct gh_sgl_desc **__sgl_desc, + int src_vmid) { - return ERR_PTR(-EINVAL); + return -EINVAL; } static inline int mem_buf_unmap_mem_s2(gh_memparcel_handle_t memparcel_hdl) @@ -109,6 +112,11 @@ static inline struct sg_table *dup_gh_sgl_desc_to_sgt(struct gh_sgl_desc *sgl_de return ERR_PTR(-EINVAL); } +static inline struct gh_sgl_desc *dup_gh_sgl_desc(struct gh_sgl_desc *sgl_desc) +{ + return ERR_PTR(-EINVAL); +} + static inline int mem_buf_assign_mem_gunyah(u32 op, struct sg_table *sgt, struct mem_buf_lend_kernel_arg *arg) { diff --git a/drivers/soc/qcom/mem_buf/mem-buf-gh.c b/drivers/soc/qcom/mem_buf/mem-buf-gh.c index b81c523a479e..09ed104768d6 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-gh.c +++ b/drivers/soc/qcom/mem_buf/mem-buf-gh.c @@ -396,7 +396,7 @@ static void mem_buf_cleanup_alloc_req(struct mem_buf_xfer_mem *xfer_mem, if (ret < 0) return; } else { - struct gh_sgl_desc *sgl_desc; + struct gh_sgl_desc *sgl_desc = NULL; struct gh_acl_desc *acl_desc; size_t size; @@ -409,9 +409,9 @@ static void mem_buf_cleanup_alloc_req(struct mem_buf_xfer_mem *xfer_mem, acl_desc->acl_entries[0].vmid = VMID_HLOS; acl_desc->acl_entries[0].perms = GH_RM_ACL_X | GH_RM_ACL_W | GH_RM_ACL_R; - sgl_desc = mem_buf_map_mem_s2(GH_RM_TRANS_TYPE_DONATE, &memparcel_hdl, - acl_desc, VMID_TUIVM); - if (IS_ERR(sgl_desc)) { + ret = mem_buf_map_mem_s2(GH_RM_TRANS_TYPE_DONATE, &memparcel_hdl, + acl_desc, &sgl_desc, VMID_TUIVM); + if (ret) { kfree(acl_desc); return; } @@ -879,7 +879,6 @@ static void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) int ret; struct file *filp; struct mem_buf_desc *membuf; - struct gh_sgl_desc *sgl_desc; int perms = PERM_READ | PERM_WRITE | PERM_EXEC; if (!(mem_buf_capability & MEM_BUF_CAP_CONSUMER)) @@ -897,6 +896,8 @@ static void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) pr_debug("%s: mem buf alloc begin\n", __func__); membuf->size = ALIGN(alloc_data->size, MEM_BUF_MHP_ALIGNMENT); + + /* Create copies of data structures from alloc_data as they may be on-stack */ membuf->acl_desc = mem_buf_vmid_perm_list_to_gh_acl( alloc_data->vmids, &perms, alloc_data->nr_acl_entries); @@ -904,6 +905,15 @@ static void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) ret = PTR_ERR(membuf->acl_desc); goto err_alloc_acl_list; } + + if (alloc_data->sgl_desc) { + membuf->sgl_desc = dup_gh_sgl_desc(alloc_data->sgl_desc); + if (IS_ERR(membuf->sgl_desc)) { + ret = PTR_ERR(membuf->sgl_desc); + goto err_alloc_sgl_desc; + } + } + membuf->trans_type = alloc_data->trans_type; membuf->src_mem_type = alloc_data->src_mem_type; membuf->dst_mem_type = alloc_data->dst_mem_type; @@ -936,11 +946,10 @@ static void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) if (ret) goto err_mem_req; - sgl_desc = mem_buf_map_mem_s2(membuf->trans_type, &membuf->memparcel_hdl, - membuf->acl_desc, VMID_HLOS); - if (IS_ERR(sgl_desc)) + ret = mem_buf_map_mem_s2(membuf->trans_type, &membuf->memparcel_hdl, + membuf->acl_desc, &membuf->sgl_desc, VMID_HLOS); + if (ret) goto err_map_mem_s2; - membuf->sgl_desc = sgl_desc; ret = mem_buf_map_mem_s1(membuf->sgl_desc); if (ret) @@ -975,7 +984,6 @@ static void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) err_map_mem_s1: err_map_mem_s2: mem_buf_relinquish_mem(membuf); - kvfree(membuf->sgl_desc); err_mem_req: mem_buf_destroy_txn(mem_buf_msgq_hdl, membuf->txn); err_init_txn: @@ -983,6 +991,9 @@ static void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) err_alloc_dst_data: mem_buf_free_mem_type_data(membuf->src_mem_type, membuf->src_data); err_alloc_src_data: + if (membuf->sgl_desc) + kvfree(membuf->sgl_desc); +err_alloc_sgl_desc: kfree(membuf->acl_desc); err_alloc_acl_list: kfree(membuf); @@ -1077,7 +1088,8 @@ struct dma_buf *mem_buf_retrieve(struct mem_buf_retrieve_kernel_arg *arg) int ret, op; struct qcom_sg_buffer *buffer; struct gh_acl_desc *acl_desc; - struct gh_sgl_desc *sgl_desc; + /* Hypervisor picks the IPA address */ + struct gh_sgl_desc *sgl_desc = NULL; DEFINE_DMA_BUF_EXPORT_INFO(exp_info); struct dma_buf *dmabuf; struct sg_table *sgt; @@ -1100,11 +1112,10 @@ struct dma_buf *mem_buf_retrieve(struct mem_buf_retrieve_kernel_arg *arg) } op = mem_buf_get_mem_xfer_type_gh(acl_desc, arg->sender_vmid); - sgl_desc = mem_buf_map_mem_s2(op, &arg->memparcel_hdl, acl_desc, arg->sender_vmid); - if (IS_ERR(sgl_desc)) { - ret = PTR_ERR(sgl_desc); + ret = mem_buf_map_mem_s2(op, &arg->memparcel_hdl, acl_desc, &sgl_desc, + arg->sender_vmid); + if (ret) goto err_map_s2; - } ret = mem_buf_map_mem_s1(sgl_desc); if (ret < 0) @@ -1173,6 +1184,7 @@ static int mem_buf_prep_alloc_data(struct mem_buf_allocation_data *alloc_data, goto err_acl; /* alloc_data->trans_type set later according to src&dest_mem_type */ + alloc_data->sgl_desc = NULL; alloc_data->src_mem_type = allocation_args->src_mem_type; alloc_data->dst_mem_type = allocation_args->dst_mem_type; diff --git a/include/linux/mem-buf.h b/include/linux/mem-buf.h index ad76a15ab279..f9e1ecb07b3f 100644 --- a/include/linux/mem-buf.h +++ b/include/linux/mem-buf.h @@ -40,6 +40,7 @@ int mem_buf_dma_buf_set_destructor(struct dma_buf *dmabuf, * @acl_list: A list of VMID and permission pairs that describe what VMIDs will * have access to the memory, and with what permissions * @trans_type: One of GH_RM_TRANS_TYPE_DONATE/LEND/SHARE + * @sgl_desc: Optional. Requests a specific set of IPA addresses. * @src_mem_type: The type of memory that the remote VM should allocate * (e.g. ION memory) * @src_data: A pointer to memory type specific data that the remote VM may need @@ -55,6 +56,7 @@ struct mem_buf_allocation_data { int *vmids; int *perms; u32 trans_type; + struct gh_sgl_desc *sgl_desc; enum mem_buf_mem_type src_mem_type; void *src_data; enum mem_buf_mem_type dst_mem_type; From 63bddcd463fafd4c9567da1ac17ab363f6a8ea16 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Fri, 27 May 2022 12:33:38 -0700 Subject: [PATCH 7/9] mem-buf-msgq: Reduce buffer free complexity Reuse the same buffer for each message in mem_buf_msgq_recv_fn() instead of allocating a new one for each message, and freeing it in a dozen different locations depending on what type of message it is. If a consumer of the message needs to defer its work to a workqueue, it must allocate a new copy of the message. Change-Id: Ia5583bc7dc9937211f25624f7a679d34fe8fb521 Signed-off-by: Patrick Daly --- drivers/soc/qcom/mem_buf/mem-buf-gh.c | 27 ++++++++++++++++--------- drivers/soc/qcom/mem_buf/mem-buf-msgq.c | 13 +++++------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/drivers/soc/qcom/mem_buf/mem-buf-gh.c b/drivers/soc/qcom/mem_buf/mem-buf-gh.c index 09ed104768d6..85296e0be184 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-gh.c +++ b/drivers/soc/qcom/mem_buf/mem-buf-gh.c @@ -445,6 +445,7 @@ static void mem_buf_alloc_req_work(struct work_struct *work) } resp_msg = mem_buf_construct_alloc_resp(req_msg, ret, hdl); + kfree(rmt_msg->msg); kfree(rmt_msg); if (IS_ERR(resp_msg)) @@ -510,7 +511,6 @@ static int mem_buf_alloc_resp_hdlr(void *hdlr_data, void *msg_buf, size_t size, trace_receive_alloc_resp_msg(alloc_resp); if (!(mem_buf_capability & MEM_BUF_CAP_CONSUMER)) { - kfree(msg_buf); return -EPERM; } @@ -521,23 +521,26 @@ static int mem_buf_alloc_resp_hdlr(void *hdlr_data, void *msg_buf, size_t size, membuf->memparcel_hdl = get_alloc_resp_hdl(alloc_resp); } - kfree(msg_buf); return ret; } /* Functions invoked when treating allocation requests to other VMs. */ -static void mem_buf_alloc_req_hdlr(void *hdlr_data, void *buf, size_t size) +static void mem_buf_alloc_req_hdlr(void *hdlr_data, void *_buf, size_t size) { struct mem_buf_rmt_msg *rmt_msg; + void *buf; if (!(mem_buf_capability & MEM_BUF_CAP_SUPPLIER)) { - kfree(buf); return; } rmt_msg = kmalloc(sizeof(*rmt_msg), GFP_KERNEL); - if (!rmt_msg) { - kfree(buf); + if (!rmt_msg) + return; + + buf = kmemdup(_buf, size, GFP_KERNEL); + if (!buf) { + kfree(rmt_msg); return; } @@ -547,18 +550,22 @@ static void mem_buf_alloc_req_hdlr(void *hdlr_data, void *buf, size_t size) queue_work(mem_buf_wq, &rmt_msg->work); } -static void mem_buf_relinquish_hdlr(void *hdlr_data, void *buf, size_t size) +static void mem_buf_relinquish_hdlr(void *hdlr_data, void *_buf, size_t size) { struct mem_buf_rmt_msg *rmt_msg; + void *buf; if (!(mem_buf_capability & MEM_BUF_CAP_SUPPLIER)) { - kfree(buf); return; } rmt_msg = kmalloc(sizeof(*rmt_msg), GFP_KERNEL); - if (!rmt_msg) { - kfree(buf); + if (!rmt_msg) + return; + + buf = kmemdup(_buf, size, GFP_KERNEL); + if (!buf) { + kfree(rmt_msg); return; } diff --git a/drivers/soc/qcom/mem_buf/mem-buf-msgq.c b/drivers/soc/qcom/mem_buf/mem-buf-msgq.c index 95465d60f313..8130ca1592b1 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-msgq.c +++ b/drivers/soc/qcom/mem_buf/mem-buf-msgq.c @@ -310,7 +310,6 @@ static void mem_buf_process_alloc_resp(struct mem_buf_msgq_desc *desc, void *buf if (!alloc_resp->ret) { desc->msgq_ops->relinquish_memparcel_hdl(desc->hdlr_data, hdr->txn_id, alloc_resp->hdl); - kfree(buf); } } else { txn->txn_ret = desc->msgq_ops->alloc_resp_hdlr(desc->hdlr_data, buf, size, @@ -328,7 +327,6 @@ static void mem_buf_process_msg(struct mem_buf_msgq_desc *desc, void *buf, size_ if (size < sizeof(*hdr) || hdr->msg_size != size) { pr_err("%s: message received is not of a proper size: 0x%lx\n", __func__, size); - kfree(buf); return; } @@ -345,7 +343,6 @@ static void mem_buf_process_msg(struct mem_buf_msgq_desc *desc, void *buf, size_ default: pr_err("%s: received message of unknown type: %d\n", __func__, hdr->msg_type); - kfree(buf); } } @@ -367,20 +364,20 @@ static int mem_buf_msgq_recv_fn(void *data) size_t size; int ret; - while (!kthread_should_stop()) { - buf = kzalloc(GH_MSGQ_MAX_MSG_SIZE_BYTES, GFP_KERNEL); - if (!buf) - continue; + buf = kzalloc(GH_MSGQ_MAX_MSG_SIZE_BYTES, GFP_KERNEL); + if (!buf) + return -ENOMEM; + while (!kthread_should_stop()) { ret = gh_msgq_recv(desc->msgq_hdl, buf, GH_MSGQ_MAX_MSG_SIZE_BYTES, &size, 0); if (ret < 0) { - kfree(buf); pr_err_ratelimited("%s failed to receive message rc: %d\n", __func__, ret); } else { mem_buf_process_msg(desc, buf, size); } } + kfree(buf); return 0; } From 8c70fc6160de520abab8385e5e6b1056c8385d16 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Thu, 26 May 2022 21:00:43 -0700 Subject: [PATCH 8/9] mem-buf: Define MEM_BUF_ALLOC_RELINQUISH_RESP message type When below sequence is run back-to-back, -ENOMEM is occasionally returned by MEM_BUF_IOC_REMOTE_ALLOC. ioctl(MEM_BUF_IOC_REMOTE_ALLOC, args) fd = args.fd close(fd) This occurs because the message sent from TUIVM to PVM as part of the file release callback is asynchonous. Resolve this by adding a new message type which indicates when PVM has completed the free operation. Additionally, define a separate obj_id instead of reusing the transaction id for this purpose. Change-Id: Iea458ec80cd14bd08848192371d0bb71cdc5de60 Signed-off-by: Patrick Daly --- drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c | 2 + drivers/soc/qcom/mem_buf/mem-buf-gh.c | 126 +++++++++++++++------- drivers/soc/qcom/mem_buf/mem-buf-msgq.c | 64 ++++++++++- drivers/soc/qcom/mem_buf/mem-buf-msgq.h | 36 +++++-- drivers/soc/qcom/mem_buf/trace-mem-buf.h | 37 +++++++ 5 files changed, 216 insertions(+), 49 deletions(-) diff --git a/drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c b/drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c index a990ed5a47ab..fe369baf210b 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c +++ b/drivers/soc/qcom/mem_buf/mem-buf-dev-gh.c @@ -22,6 +22,8 @@ EXPORT_TRACEPOINT_SYMBOL(receive_relinquish_msg); EXPORT_TRACEPOINT_SYMBOL(send_alloc_resp_msg); EXPORT_TRACEPOINT_SYMBOL(receive_alloc_resp_msg); EXPORT_TRACEPOINT_SYMBOL(mem_buf_alloc_info); +EXPORT_TRACEPOINT_SYMBOL(send_relinquish_resp_msg); +EXPORT_TRACEPOINT_SYMBOL(receive_relinquish_resp_msg); struct gh_acl_desc *mem_buf_vmid_perm_list_to_gh_acl(int *vmids, int *perms, unsigned int nr_acl_entries) diff --git a/drivers/soc/qcom/mem_buf/mem-buf-gh.c b/drivers/soc/qcom/mem_buf/mem-buf-gh.c index 85296e0be184..8e145e37cd89 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-gh.c +++ b/drivers/soc/qcom/mem_buf/mem-buf-gh.c @@ -64,7 +64,7 @@ struct mem_buf_rmt_msg { * memory * @dst_vmids: The VMIDs that have access to the memory * @dst_perms: The access permissions for the VMIDs that can access the memory - * @txn_id: The transaction ID that corresponds to this memory buffer + * @obj_id: Uniquely identifies this object. */ struct mem_buf_xfer_mem { size_t size; @@ -78,7 +78,7 @@ struct mem_buf_xfer_mem { u32 nr_acl_entries; int *dst_vmids; int *dst_perms; - u32 txn_id; + u32 obj_id; }; /** @@ -102,7 +102,7 @@ struct mem_buf_xfer_mem { * @filp: Pointer to the file structure for the membuf * @entry: List head for maintaing a list of memory buffers that have been * provided by remote VMs. - * @txn: The transaction associated with a memory buffer + * @obj_id: Uniquely identifies this object. */ struct mem_buf_desc { size_t size; @@ -116,8 +116,10 @@ struct mem_buf_desc { void *dst_data; struct file *filp; struct list_head entry; - void *txn; + u32 obj_id; }; +static DEFINE_IDR(mem_buf_obj_idr); +static DEFINE_MUTEX(mem_buf_idr_mutex); struct mem_buf_xfer_dmaheap_mem { char name[MEM_BUF_MAX_DMAHEAP_NAME_LEN]; @@ -125,6 +127,28 @@ struct mem_buf_xfer_dmaheap_mem { struct dma_buf_attachment *attachment; }; +static int mem_buf_alloc_obj_id(void) +{ + int ret; + + mutex_lock(&mem_buf_idr_mutex); + ret = idr_alloc_cyclic(&mem_buf_obj_idr, NULL, 0, INT_MAX, GFP_KERNEL); + mutex_unlock(&mem_buf_idr_mutex); + if (ret < 0) { + pr_err("%s: failed to allocate obj id rc: %d\n", + __func__, ret); + return ret; + } + return ret; +} + +static void mem_buf_destroy_obj_id(u32 obj_id) +{ + mutex_lock(&mem_buf_idr_mutex); + idr_remove(&mem_buf_obj_idr, obj_id); + mutex_unlock(&mem_buf_idr_mutex); +} + /* Functions invoked when treating allocation requests from other VMs. */ static int mem_buf_rmt_alloc_dmaheap_mem(struct mem_buf_xfer_mem *xfer_mem) { @@ -272,7 +296,13 @@ struct mem_buf_xfer_mem *mem_buf_prep_xfer_mem(void *req_msg) if (!xfer_mem) return ERR_PTR(-ENOMEM); - xfer_mem->txn_id = get_alloc_req_txn_id(req_msg); + ret = mem_buf_alloc_obj_id(); + if (ret < 0) { + pr_err("%s failed to allocate obj_id: %d\n", __func__, ret); + goto err_idr_alloc; + } + xfer_mem->obj_id = ret; + xfer_mem->size = get_alloc_req_size(req_msg); xfer_mem->mem_type = mem_type; xfer_mem->nr_acl_entries = nr_acl_entries; @@ -282,21 +312,27 @@ struct mem_buf_xfer_mem *mem_buf_prep_xfer_mem(void *req_msg) if (ret) { pr_err("%s failed to create VMID and permissions list: %d\n", __func__, ret); - kfree(xfer_mem); - return ERR_PTR(ret); + goto err_alloc_vmid_perm_list; } mem_type_data = mem_buf_alloc_xfer_mem_type_data(mem_type, arb_payload); if (IS_ERR(mem_type_data)) { pr_err("%s: failed to allocate mem type specific data: %d\n", __func__, PTR_ERR(mem_type_data)); - kfree(xfer_mem->dst_vmids); - kfree(xfer_mem->dst_perms); - kfree(xfer_mem); - return ERR_CAST(mem_type_data); + ret = PTR_ERR(mem_type_data); + goto err_alloc_xfer_mem_type_data; } xfer_mem->mem_type_data = mem_type_data; INIT_LIST_HEAD(&xfer_mem->entry); return xfer_mem; + +err_alloc_xfer_mem_type_data: + kfree(xfer_mem->dst_vmids); + kfree(xfer_mem->dst_perms); +err_alloc_vmid_perm_list: + mem_buf_destroy_obj_id(xfer_mem->obj_id); +err_idr_alloc: + kfree(xfer_mem); + return ERR_PTR(ret); } static void mem_buf_free_xfer_mem(struct mem_buf_xfer_mem *xfer_mem) @@ -305,6 +341,7 @@ static void mem_buf_free_xfer_mem(struct mem_buf_xfer_mem *xfer_mem) xfer_mem->mem_type_data); kfree(xfer_mem->dst_vmids); kfree(xfer_mem->dst_perms); + mem_buf_destroy_obj_id(xfer_mem->obj_id); kfree(xfer_mem); } @@ -430,6 +467,7 @@ static void mem_buf_alloc_req_work(struct work_struct *work) void *resp_msg; struct mem_buf_xfer_mem *xfer_mem; gh_memparcel_handle_t hdl = 0; + u32 obj_id = 0; int ret; trace_receive_alloc_req(req_msg); @@ -442,9 +480,10 @@ static void mem_buf_alloc_req_work(struct work_struct *work) } else { ret = 0; hdl = xfer_mem->hdl; + obj_id = xfer_mem->obj_id; } - resp_msg = mem_buf_construct_alloc_resp(req_msg, ret, hdl); + resp_msg = mem_buf_construct_alloc_resp(req_msg, ret, hdl, obj_id); kfree(rmt_msg->msg); kfree(rmt_msg); @@ -480,13 +519,14 @@ static void mem_buf_relinquish_work(struct work_struct *work) struct mem_buf_xfer_mem *xfer_mem_iter, *tmp, *xfer_mem = NULL; struct mem_buf_rmt_msg *rmt_msg = to_rmt_msg(work); struct mem_buf_alloc_relinquish *relinquish_msg = rmt_msg->msg; - u32 relinquish_txn_id = get_relinquish_req_txn_id(relinquish_msg); + u32 obj_id = get_relinquish_req_obj_id(relinquish_msg); + void *resp_msg; trace_receive_relinquish_msg(relinquish_msg); mutex_lock(&mem_buf_xfer_mem_list_lock); list_for_each_entry_safe(xfer_mem_iter, tmp, &mem_buf_xfer_mem_list, entry) - if (xfer_mem_iter->txn_id == relinquish_txn_id) { + if (xfer_mem_iter->obj_id == obj_id) { xfer_mem = xfer_mem_iter; list_del(&xfer_mem->entry); break; @@ -496,8 +536,15 @@ static void mem_buf_relinquish_work(struct work_struct *work) if (xfer_mem) mem_buf_cleanup_alloc_req(xfer_mem, relinquish_msg->hdl); else - pr_err("%s: transferred memory with txn_id 0x%x not found\n", - __func__, relinquish_txn_id); + pr_err("%s: transferred memory with obj_id 0x%x not found\n", + __func__, obj_id); + + resp_msg = mem_buf_construct_relinquish_resp(relinquish_msg); + if (!IS_ERR(resp_msg)) { + trace_send_relinquish_resp_msg(resp_msg); + mem_buf_msgq_send(mem_buf_msgq_hdl, resp_msg); + kfree(resp_msg); + } kfree(rmt_msg->msg); kfree(rmt_msg); @@ -519,6 +566,7 @@ static int mem_buf_alloc_resp_hdlr(void *hdlr_data, void *msg_buf, size_t size, pr_err("%s remote allocation failed rc: %d\n", __func__, ret); } else { membuf->memparcel_hdl = get_alloc_resp_hdl(alloc_resp); + membuf->obj_id = get_alloc_resp_obj_id(alloc_resp); } return ret; @@ -577,10 +625,15 @@ static void mem_buf_relinquish_hdlr(void *hdlr_data, void *_buf, size_t size) static int mem_buf_request_mem(struct mem_buf_desc *membuf) { + struct mem_buf_txn *txn; void *alloc_req_msg; int ret; - alloc_req_msg = mem_buf_construct_alloc_req(membuf->txn, membuf->size, membuf->acl_desc, + txn = mem_buf_init_txn(mem_buf_msgq_hdl, membuf); + if (IS_ERR(txn)) + return PTR_ERR(txn); + + alloc_req_msg = mem_buf_construct_alloc_req(txn, membuf->size, membuf->acl_desc, membuf->src_mem_type, membuf->src_data, membuf->trans_type); if (IS_ERR(alloc_req_msg)) { @@ -599,23 +652,28 @@ static int mem_buf_request_mem(struct mem_buf_desc *membuf) if (ret < 0) goto out; - ret = mem_buf_txn_wait(membuf->txn); + ret = mem_buf_txn_wait(txn); if (ret < 0) goto out; out: + mem_buf_destroy_txn(mem_buf_msgq_hdl, txn); return ret; } -static void __mem_buf_relinquish_mem(u32 txn_id, u32 memparcel_hdl) +static void __mem_buf_relinquish_mem(u32 obj_id, u32 memparcel_hdl) { - void *relinquish_msg; + void *relinquish_msg, *txn; int ret; - relinquish_msg = mem_buf_construct_relinquish_msg(txn_id, memparcel_hdl); - if (IS_ERR(relinquish_msg)) + txn = mem_buf_init_txn(mem_buf_msgq_hdl, NULL); + if (IS_ERR(txn)) return; + relinquish_msg = mem_buf_construct_relinquish_msg(txn, obj_id, memparcel_hdl); + if (IS_ERR(relinquish_msg)) + goto err_construct_relinquish_msg; + trace_send_relinquish_msg(relinquish_msg); ret = mem_buf_msgq_send(mem_buf_msgq_hdl, relinquish_msg); @@ -630,6 +688,12 @@ static void __mem_buf_relinquish_mem(u32 txn_id, u32 memparcel_hdl) __func__, ret); else pr_debug("%s: allocation relinquish message sent\n", __func__); + + /* Wait for response */ + mem_buf_txn_wait(txn); + +err_construct_relinquish_msg: + mem_buf_destroy_txn(mem_buf_msgq_hdl, txn); } /* @@ -642,7 +706,6 @@ static void mem_buf_relinquish_mem(struct mem_buf_desc *membuf) int perms[] = {PERM_READ | PERM_WRITE | PERM_EXEC}; struct sg_table *sgt; struct mem_buf_lend_kernel_arg arg; - u32 txn_id = mem_buf_retrieve_txn_id(membuf->txn); if (membuf->memparcel_hdl != MEM_BUF_MEMPARCEL_INVALID) { if (membuf->trans_type != GH_RM_TRANS_TYPE_DONATE) { @@ -651,7 +714,7 @@ static void mem_buf_relinquish_mem(struct mem_buf_desc *membuf) return; } - return __mem_buf_relinquish_mem(txn_id, membuf->memparcel_hdl); + return __mem_buf_relinquish_mem(membuf->obj_id, membuf->memparcel_hdl); } sgt = dup_gh_sgl_desc_to_sgt(membuf->sgl_desc); @@ -669,15 +732,15 @@ static void mem_buf_relinquish_mem(struct mem_buf_desc *membuf) goto err_free_sgt; membuf->memparcel_hdl = arg.memparcel_hdl; - __mem_buf_relinquish_mem(txn_id, membuf->memparcel_hdl); + __mem_buf_relinquish_mem(membuf->obj_id, membuf->memparcel_hdl); err_free_sgt: sg_free_table(sgt); kfree(sgt); } -static void mem_buf_relinquish_memparcel_hdl(void *hdlr_data, u32 txn_id, gh_memparcel_handle_t hdl) +static void mem_buf_relinquish_memparcel_hdl(void *hdlr_data, u32 obj_id, gh_memparcel_handle_t hdl) { - __mem_buf_relinquish_mem(txn_id, hdl); + __mem_buf_relinquish_mem(obj_id, hdl); } static int get_mem_buf(void *membuf_desc); @@ -863,7 +926,6 @@ static int mem_buf_buffer_release(struct inode *inode, struct file *filp) mem_buf_relinquish_mem(membuf); out_free_mem: - mem_buf_destroy_txn(mem_buf_msgq_hdl, membuf->txn); mem_buf_free_mem_type_data(membuf->dst_mem_type, membuf->dst_data); mem_buf_free_mem_type_data(membuf->src_mem_type, membuf->src_data); kvfree(membuf->sgl_desc); @@ -941,12 +1003,6 @@ static void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) goto err_alloc_dst_data; } - membuf->txn = mem_buf_init_txn(mem_buf_msgq_hdl, membuf); - if (IS_ERR(membuf->txn)) { - ret = PTR_ERR(membuf->txn); - goto err_init_txn; - } - trace_mem_buf_alloc_info(membuf->size, membuf->src_mem_type, membuf->dst_mem_type, membuf->acl_desc); ret = mem_buf_request_mem(membuf); @@ -992,8 +1048,6 @@ static void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) err_map_mem_s2: mem_buf_relinquish_mem(membuf); err_mem_req: - mem_buf_destroy_txn(mem_buf_msgq_hdl, membuf->txn); -err_init_txn: mem_buf_free_mem_type_data(membuf->dst_mem_type, membuf->dst_data); err_alloc_dst_data: mem_buf_free_mem_type_data(membuf->src_mem_type, membuf->src_data); diff --git a/drivers/soc/qcom/mem_buf/mem-buf-msgq.c b/drivers/soc/qcom/mem_buf/mem-buf-msgq.c index 8130ca1592b1..90bbbb3c9474 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-msgq.c +++ b/drivers/soc/qcom/mem_buf/mem-buf-msgq.c @@ -140,7 +140,8 @@ EXPORT_SYMBOL(mem_buf_construct_alloc_req); * sharing, or lending). */ void *mem_buf_construct_alloc_resp(void *req_msg, s32 alloc_ret, - gh_memparcel_handle_t memparcel_hdl) + gh_memparcel_handle_t memparcel_hdl, + u32 obj_id) { struct mem_buf_alloc_req *req = req_msg; struct mem_buf_alloc_resp *resp_msg = kzalloc(sizeof(*resp_msg), GFP_KERNEL); @@ -153,6 +154,7 @@ void *mem_buf_construct_alloc_resp(void *req_msg, s32 alloc_ret, resp_msg->hdr.msg_size = sizeof(*resp_msg); resp_msg->ret = alloc_ret; resp_msg->hdl = memparcel_hdl; + resp_msg->obj_id = obj_id; return resp_msg; } @@ -160,12 +162,15 @@ EXPORT_SYMBOL(mem_buf_construct_alloc_resp); /* * mem_buf_construct_relinquish_msg: Construct a relinquish message. - * @txn_id: The transaction ID that corresponds to the memory that is being relinquished. + * @mem_buf_txn: The transaction object. + * @obj_id: Uniquely identifies an object. * @memparcel_hdl: The memparcel that corresponds to the memory that is being relinquished. */ -void *mem_buf_construct_relinquish_msg(u32 txn_id, gh_memparcel_handle_t memparcel_hdl) +void *mem_buf_construct_relinquish_msg(void *mem_buf_txn, u32 obj_id, + gh_memparcel_handle_t memparcel_hdl) { struct mem_buf_alloc_relinquish *relinquish_msg; + struct mem_buf_txn *txn = mem_buf_txn; relinquish_msg = kzalloc(sizeof(*relinquish_msg), GFP_KERNEL); if (!relinquish_msg) @@ -173,13 +178,35 @@ void *mem_buf_construct_relinquish_msg(u32 txn_id, gh_memparcel_handle_t memparc relinquish_msg->hdr.msg_type = MEM_BUF_ALLOC_RELINQUISH; relinquish_msg->hdr.msg_size = sizeof(*relinquish_msg); - relinquish_msg->hdr.txn_id = txn_id; + relinquish_msg->hdr.txn_id = txn->txn_id; + relinquish_msg->obj_id = obj_id; relinquish_msg->hdl = memparcel_hdl; return relinquish_msg; } EXPORT_SYMBOL(mem_buf_construct_relinquish_msg); +/* + * mem_buf_construct_relinquish_resp: Construct a relinquish resp message. + * @msg: The msg to reply to. + */ +void *mem_buf_construct_relinquish_resp(void *_msg) +{ + struct mem_buf_alloc_relinquish *msg = _msg; + struct mem_buf_alloc_relinquish *resp; + + resp = kzalloc(sizeof(*resp), GFP_KERNEL); + if (!resp) + return ERR_PTR(-ENOMEM); + + resp->hdr.msg_type = MEM_BUF_ALLOC_RELINQUISH_RESP; + resp->hdr.msg_size = sizeof(*resp); + resp->hdr.txn_id = msg->hdr.txn_id; + + return resp; +} +EXPORT_SYMBOL(mem_buf_construct_relinquish_resp); + int mem_buf_retrieve_txn_id(void *mem_buf_txn) { struct mem_buf_txn *txn = mem_buf_txn; @@ -308,7 +335,8 @@ static void mem_buf_process_alloc_resp(struct mem_buf_msgq_desc *desc, void *buf * it can be reclaimed. */ if (!alloc_resp->ret) { - desc->msgq_ops->relinquish_memparcel_hdl(desc->hdlr_data, hdr->txn_id, + desc->msgq_ops->relinquish_memparcel_hdl(desc->hdlr_data, + alloc_resp->obj_id, alloc_resp->hdl); } } else { @@ -319,6 +347,29 @@ static void mem_buf_process_alloc_resp(struct mem_buf_msgq_desc *desc, void *buf mutex_unlock(&desc->idr_mutex); } +static void mem_buf_process_relinquish_resp(struct mem_buf_msgq_desc *desc, + void *buf, size_t size) +{ + struct mem_buf_txn *txn; + struct mem_buf_alloc_relinquish *relinquish_resp_msg = buf; + + if (size != sizeof(*relinquish_resp_msg)) { + pr_err("%s response received is not of correct size\n", + __func__); + return; + } + trace_receive_relinquish_resp_msg(relinquish_resp_msg); + + mutex_lock(&desc->idr_mutex); + txn = idr_find(&desc->txn_idr, relinquish_resp_msg->hdr.txn_id); + if (!txn) + pr_err("%s no txn associated with id: %d\n", __func__, + relinquish_resp_msg->hdr.txn_id); + else + complete(&txn->txn_done); + mutex_unlock(&desc->idr_mutex); +} + static void mem_buf_process_msg(struct mem_buf_msgq_desc *desc, void *buf, size_t size) { struct mem_buf_msg_hdr *hdr = buf; @@ -340,6 +391,9 @@ static void mem_buf_process_msg(struct mem_buf_msgq_desc *desc, void *buf, size_ case MEM_BUF_ALLOC_RELINQUISH: desc->msgq_ops->relinquish_hdlr(desc->hdlr_data, buf, size); break; + case MEM_BUF_ALLOC_RELINQUISH_RESP: + mem_buf_process_relinquish_resp(desc, buf, size); + break; default: pr_err("%s: received message of unknown type: %d\n", __func__, hdr->msg_type); diff --git a/drivers/soc/qcom/mem_buf/mem-buf-msgq.h b/drivers/soc/qcom/mem_buf/mem-buf-msgq.h index f533c645c413..7615066217c3 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-msgq.h +++ b/drivers/soc/qcom/mem_buf/mem-buf-msgq.h @@ -19,11 +19,13 @@ * allocation request issued by the receiving VM * @MEM_BUF_ALLOC_RELINQUISH: The message is a notification from another VM * that the receiving VM can reclaim the memory. + * @MEM_BUF_ALLOC_RELINQUISH_RESP: Indicates completion of MEM_BUF_ALLOC_RELINQUISH. */ enum mem_buf_msg_type { MEM_BUF_ALLOC_REQ, MEM_BUF_ALLOC_RESP, MEM_BUF_ALLOC_RELINQUISH, + MEM_BUF_ALLOC_RELINQUISH_RESP, MEM_BUF_ALLOC_REQ_MAX, }; @@ -73,11 +75,13 @@ struct mem_buf_alloc_req { * receiving VM. This field is only meaningful if the allocation on the remote * VM was carried out successfully, as denoted by @ret. * (i.e. memory donation, sharing, or lending). + * @obj_id: Unique identifier for the memory object associated with handle. */ struct mem_buf_alloc_resp { struct mem_buf_msg_hdr hdr; s32 ret; u32 hdl; + u32 obj_id; } __packed; /** @@ -86,10 +90,12 @@ struct mem_buf_alloc_resp { * another VM. * @hdr: Message header * @hdl: The memparcel handle associated with the memory. + * @obj_id: Unique identifier for the memory object associated with handle. */ struct mem_buf_alloc_relinquish { struct mem_buf_msg_hdr hdr; u32 hdl; + u32 obj_id; } __packed; /* @@ -111,7 +117,7 @@ struct mem_buf_msgq_ops { void (*alloc_req_hdlr)(void *hdlr_data, void *msg, size_t size); int (*alloc_resp_hdlr)(void *hdlr_data, void *msg, size_t size, void *resp_buf); void (*relinquish_hdlr)(void *hdlr_data, void *msg, size_t size); - void (*relinquish_memparcel_hdl)(void *hdlr_data, u32 txn_id, + void (*relinquish_memparcel_hdl)(void *hdlr_data, u32 obj_id, gh_memparcel_handle_t memparcel_hdl); }; @@ -176,9 +182,14 @@ static inline u32 get_alloc_resp_hdl(struct mem_buf_alloc_resp *resp) return resp->hdl; } -static inline u32 get_relinquish_req_txn_id(struct mem_buf_alloc_relinquish *relinquish_msg) +static inline u32 get_alloc_resp_obj_id(struct mem_buf_alloc_resp *resp) { - return relinquish_msg->hdr.txn_id; + return resp->obj_id; +} + +static inline u32 get_relinquish_req_obj_id(struct mem_buf_alloc_relinquish *relinquish_msg) +{ + return relinquish_msg->obj_id; } #if IS_ENABLED(CONFIG_QCOM_MEM_BUF_MSGQ) @@ -198,8 +209,11 @@ void *mem_buf_construct_alloc_req(void *mem_buf_txn, size_t alloc_size, enum mem_buf_mem_type src_mem_type, void *src_data, u32 trans_type); void *mem_buf_construct_alloc_resp(void *req_msg, s32 alloc_ret, - gh_memparcel_handle_t memparcel_hdl); -void *mem_buf_construct_relinquish_msg(u32 txn_id, gh_memparcel_handle_t memparcel_hdl); + gh_memparcel_handle_t memparcel_hdl, + u32 obj_id); +void *mem_buf_construct_relinquish_msg(void *mem_buf_txn, u32 obj_id, + gh_memparcel_handle_t memparcel_hdl); +void *mem_buf_construct_relinquish_resp(void *_msg); #else static inline void *mem_buf_msgq_register(const char *msgq_name, struct mem_buf_msgq_hdlr_info *info) @@ -240,13 +254,19 @@ static inline void *mem_buf_construct_alloc_req(void *mem_buf_txn, size_t alloc_ } static inline void *mem_buf_construct_alloc_resp(void *req_msg, s32 alloc_ret, - gh_memparcel_handle_t memparcel_hdl) + gh_memparcel_handle_t memparcel_hdl, + u32 obj_id) { return ERR_PTR(-ENODEV); } -static inline void *mem_buf_construct_relinquish_msg(u32 txn_id, - gh_memparcel_handle_t memparcel_hdl) +static inline void *mem_buf_construct_relinquish_msg(void *mem_buf_txn, u32 obj_id, + gh_memparcel_handle_t memparcel_hdl) +{ + return ERR_PTR(-ENODEV); +} + +static inline void *mem_buf_construct_relinquish_resp(void *_msg) { return ERR_PTR(-ENODEV); } diff --git a/drivers/soc/qcom/mem_buf/trace-mem-buf.h b/drivers/soc/qcom/mem_buf/trace-mem-buf.h index 8f7d0c2f6c10..8b909a9c4895 100644 --- a/drivers/soc/qcom/mem_buf/trace-mem-buf.h +++ b/drivers/soc/qcom/mem_buf/trace-mem-buf.h @@ -55,6 +55,8 @@ static char __maybe_unused *msg_type_to_str(enum mem_buf_msg_type type) return "MEM_BUF_ALLOC_RESP"; else if (type == MEM_BUF_ALLOC_RELINQUISH) return "MEM_BUF_ALLOC_RELINQUISH"; + else if (type == MEM_BUF_ALLOC_RELINQUISH_RESP) + return "MEM_BUF_ALLOC_RELINQUISH_RESP"; return NULL; } @@ -223,6 +225,41 @@ DEFINE_EVENT(alloc_resp_class, receive_alloc_resp_msg, TP_ARGS(resp) ); +DECLARE_EVENT_CLASS(relinquish_resp_class, + + TP_PROTO(struct mem_buf_alloc_relinquish *resp), + + TP_ARGS(resp), + + TP_STRUCT__entry( + __field(u32, txn_id) + __string(msg_type, msg_type_to_str(resp->hdr.msg_type)) + ), + + TP_fast_assign( + __entry->txn_id = resp->hdr.txn_id; + __assign_str(msg_type, msg_type_to_str(resp->hdr.msg_type)); + ), + + TP_printk("txn_id: %d msg_type: %s", + __entry->txn_id, __get_str(msg_type) + ) +); + +DEFINE_EVENT(relinquish_resp_class, send_relinquish_resp_msg, + + TP_PROTO(struct mem_buf_alloc_relinquish *resp), + + TP_ARGS(resp) +); + +DEFINE_EVENT(relinquish_resp_class, receive_relinquish_resp_msg, + + TP_PROTO(struct mem_buf_alloc_relinquish *resp), + + TP_ARGS(resp) +); + TRACE_EVENT(lookup_sgl, TP_PROTO(struct gh_sgl_desc *sgl_desc, int ret, From 2f83e4db8c6aee8c8271eb21574a56b0de26a127 Mon Sep 17 00:00:00 2001 From: Chris Goldsworthy Date: Wed, 31 Aug 2022 19:01:49 -0700 Subject: [PATCH 9/9] android: abi_gki_aarch64_qcom: Add flush_delayed_fput Add flushed_delayed_fput for usage by mem-buf. Change-Id: I16b06de8b4b87f8e4d391229c6b13181c7be9bd9 Signed-off-by: Chris Goldsworthy --- android/abi_gki_aarch64_qcom | 1 + 1 file changed, 1 insertion(+) diff --git a/android/abi_gki_aarch64_qcom b/android/abi_gki_aarch64_qcom index cf61d6bef721..165f70286f21 100644 --- a/android/abi_gki_aarch64_qcom +++ b/android/abi_gki_aarch64_qcom @@ -539,6 +539,7 @@ flow_rule_match_ports flow_rule_match_vlan flush_dcache_page + flush_delayed_fput flush_delayed_work flush_work __flush_workqueue