diff --git a/android/abi_gki_aarch64_qcom b/android/abi_gki_aarch64_qcom index f65c969f8e38..1259f08ade43 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 diff --git a/arch/arm64/configs/vendor/pineapple_GKI.config b/arch/arm64/configs/vendor/pineapple_GKI.config index fcda6bb7ef71..f10526b24641 100644 --- a/arch/arm64/configs/vendor/pineapple_GKI.config +++ b/arch/arm64/configs/vendor/pineapple_GKI.config @@ -97,7 +97,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 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..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) @@ -131,6 +133,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 +196,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(int 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 +214,24 @@ struct gh_sgl_desc *mem_buf_map_mem_s2(int 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 +242,8 @@ struct gh_sgl_desc *mem_buf_map_mem_s2(int 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 +251,18 @@ struct gh_sgl_desc *mem_buf_map_mem_s2(int 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); @@ -252,6 +283,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 +332,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) @@ -326,7 +359,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 04a44dc6beca..9316e4709458 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, @@ -31,19 +31,35 @@ 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); -struct gh_sgl_desc *mem_buf_map_mem_s2(int 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); -int mem_buf_assign_mem_gunyah(int op, struct sg_table *sgt, +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); #else @@ -68,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(int 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) @@ -95,7 +112,12 @@ 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 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) { 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..8e145e37cd89 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. @@ -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; @@ -72,13 +72,13 @@ 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; int *dst_vmids; int *dst_perms; - u32 txn_id; + u32 obj_id; }; /** @@ -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 @@ -102,22 +102,24 @@ 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; 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; 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); } @@ -339,46 +376,10 @@ 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 int 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, xfer_type; + int ret; + u32 xfer_type; struct mem_buf_xfer_mem *xfer_mem; struct mem_buf_lend_kernel_arg arg = {0}; @@ -391,7 +392,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 = get_alloc_req_xfer_type(req); arg.nr_acl_entries = xfer_mem->nr_acl_entries; arg.vmids = xfer_mem->dst_vmids; @@ -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); @@ -432,7 +433,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; @@ -445,9 +446,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; } @@ -466,7 +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; - int trans_type = 0; + u32 obj_id = 0; int ret; trace_receive_alloc_req(req_msg); @@ -479,10 +480,11 @@ 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; + obj_id = xfer_mem->obj_id; } - resp_msg = mem_buf_construct_alloc_resp(req_msg, ret, hdl, trans_type); + resp_msg = mem_buf_construct_alloc_resp(req_msg, ret, hdl, obj_id); + kfree(rmt_msg->msg); kfree(rmt_msg); if (IS_ERR(resp_msg)) @@ -517,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; @@ -533,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); @@ -548,7 +558,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; } @@ -557,26 +566,29 @@ 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->obj_id = get_alloc_resp_obj_id(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; } @@ -586,18 +598,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; } @@ -609,11 +625,17 @@ 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, - membuf->src_mem_type, membuf->src_data); + 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)) { ret = PTR_ERR(alloc_req_msg); goto out; @@ -630,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); @@ -661,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); } /* @@ -673,16 +706,15 @@ 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->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; } - 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); @@ -700,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); @@ -894,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); @@ -917,8 +948,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 op; int perms = PERM_READ | PERM_WRITE | PERM_EXEC; if (!(mem_buf_capability & MEM_BUF_CAP_CONSUMER)) @@ -936,6 +965,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); @@ -943,6 +974,16 @@ 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; @@ -962,23 +1003,16 @@ 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); if (ret) goto err_mem_req; - op = membuf->gh_rm_trans_type; - sgl_desc = mem_buf_map_mem_s2(op, &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) @@ -1013,14 +1047,14 @@ 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: 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); 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); @@ -1115,7 +1149,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; @@ -1138,11 +1173,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) @@ -1210,6 +1244,8 @@ 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->sgl_desc = NULL; alloc_data->src_mem_type = allocation_args->src_mem_type; alloc_data->dst_mem_type = allocation_args->dst_mem_type; @@ -1272,6 +1308,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 1f257b9234ff..90bbbb3c9474 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,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, * 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 obj_id) { struct mem_buf_alloc_req *req = req_msg; struct mem_buf_alloc_resp *resp_msg = kzalloc(sizeof(*resp_msg), GFP_KERNEL); @@ -151,7 +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->gh_rm_trans_type = gh_rm_trans_type; + resp_msg->obj_id = obj_id; return resp_msg; } @@ -159,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) @@ -172,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; @@ -307,9 +335,9 @@ 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); - kfree(buf); } } else { txn->txn_ret = desc->msgq_ops->alloc_resp_hdlr(desc->hdlr_data, buf, size, @@ -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; @@ -327,7 +378,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; } @@ -341,10 +391,12 @@ 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); - kfree(buf); } } @@ -366,20 +418,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; } diff --git a/drivers/soc/qcom/mem_buf/mem-buf-msgq.h b/drivers/soc/qcom/mem_buf/mem-buf-msgq.h index 374fb3882403..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, }; @@ -46,6 +48,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 +62,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 +74,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 * (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; - int gh_rm_trans_type; + 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); }; @@ -140,6 +146,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,14 +182,14 @@ 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_obj_id(struct mem_buf_alloc_resp *resp) { - return resp->gh_rm_trans_type; + return resp->obj_id; } -static inline u32 get_relinquish_req_txn_id(struct mem_buf_alloc_relinquish *relinquish_msg) +static inline u32 get_relinquish_req_obj_id(struct mem_buf_alloc_relinquish *relinquish_msg) { - return relinquish_msg->hdr.txn_id; + return relinquish_msg->obj_id; } #if IS_ENABLED(CONFIG_QCOM_MEM_BUF_MSGQ) @@ -195,10 +206,14 @@ 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, int gh_rm_trans_type); -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) @@ -231,20 +246,27 @@ 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, int gh_rm_trans_type) + 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/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; 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, diff --git a/include/linux/mem-buf.h b/include/linux/mem-buf.h index a018fe1c89eb..f9e1ecb07b3f 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,8 @@ 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 + * @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 @@ -52,6 +55,8 @@ struct mem_buf_allocation_data { unsigned int nr_acl_entries; 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;