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 <quic_pdaly@quicinc.com>
This commit is contained in:
Patrick Daly 2022-05-19 18:35:02 -07:00 committed by Chris Goldsworthy
parent 5a01357c0f
commit 0f6efbf911
4 changed files with 86 additions and 35 deletions

View File

@ -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);

View File

@ -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)
{

View File

@ -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;

View File

@ -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;