diff --git a/drivers/virt/gunyah/rsc_mgr.c b/drivers/virt/gunyah/rsc_mgr.c index c5bed971a699..10cc8db37d30 100644 --- a/drivers/virt/gunyah/rsc_mgr.c +++ b/drivers/virt/gunyah/rsc_mgr.c @@ -380,7 +380,7 @@ static void gh_rm_notif_work(struct work_struct *work) blocking_notifier_call_chain(&rm->nh, connection->msg_id, connection->payload); - gh_rm_put(rm); + put_device(rm->dev); kfree(connection->payload); kfree(connection); } @@ -401,14 +401,14 @@ static void gh_rm_process_notif(struct gh_rm *rm, void *msg, size_t msg_size) connection->type = RM_RPC_TYPE_NOTIF; connection->msg_id = hdr->msg_id; - gh_rm_get(rm); + get_device(rm->dev); connection->notification.rm = rm; INIT_WORK(&connection->notification.work, gh_rm_notif_work); ret = gh_rm_init_connection_payload(connection, msg, sizeof(*hdr), msg_size); if (ret) { dev_err(rm->dev, "Failed to initialize connection for notification: %d\n", ret); - gh_rm_put(rm); + put_device(rm->dev); kfree(connection); return; } @@ -482,7 +482,7 @@ static void gh_rm_try_complete_connection(struct gh_rm *rm) schedule_work(&connection->notification.work); break; default: - dev_err_ratelimited(rm->dev, "Invalid message type (%d) received\n", + dev_err_ratelimited(rm->dev, "Invalid message type (%u) received\n", connection->type); gh_rm_abort_connection(rm); break; @@ -536,11 +536,11 @@ static void gh_rm_msgq_tx_done(struct mbox_client *cl, void *mssg, int r) } static int gh_rm_send_request(struct gh_rm *rm, u32 message_id, - const void *req_buff, size_t req_buf_size, + const void *req_buf, size_t req_buf_size, struct gh_rm_connection *connection) { size_t buf_size_remaining = req_buf_size; - const void *req_buf_curr = req_buff; + const void *req_buf_curr = req_buf; struct gh_msgq_tx_data *msg; struct gh_rm_rpc_hdr *hdr, hdr_template; u32 cont_fragments = 0; @@ -549,8 +549,8 @@ static int gh_rm_send_request(struct gh_rm *rm, u32 message_id, int ret; if (req_buf_size > GH_RM_MAX_NUM_FRAGMENTS * GH_RM_MAX_MSG_SIZE) { - dev_warn(rm->dev, "Limit exceeded for the number of fragments: %u\n", - cont_fragments); + dev_warn(rm->dev, "Limit (%lu bytes) exceeded for the maximum message size: %lu\n", + GH_RM_MAX_NUM_FRAGMENTS * GH_RM_MAX_MSG_SIZE, req_buf_size); dump_stack(); return -E2BIG; } @@ -560,7 +560,7 @@ static int gh_rm_send_request(struct gh_rm *rm, u32 message_id, hdr_template.api = RM_RPC_API; hdr_template.type = FIELD_PREP(RM_RPC_TYPE_MASK, RM_RPC_TYPE_REQUEST) | - FIELD_PREP(RM_RPC_FRAGMENTS_MASK, cont_fragments); + FIELD_PREP(RM_RPC_FRAGMENTS_MASK, cont_fragments); hdr_template.seq = cpu_to_le16(connection->reply.seq); hdr_template.msg_id = cpu_to_le32(message_id); @@ -568,7 +568,6 @@ static int gh_rm_send_request(struct gh_rm *rm, u32 message_id, if (ret) return ret; - /* Consider also the 'request' packet for the loop count */ do { msg = kmem_cache_zalloc(rm->cache, GFP_KERNEL); if (!msg) { @@ -577,11 +576,11 @@ static int gh_rm_send_request(struct gh_rm *rm, u32 message_id, } /* Fill header */ - hdr = (struct gh_rm_rpc_hdr *)msg->data; + hdr = (struct gh_rm_rpc_hdr *)&msg->data[0]; *hdr = hdr_template; /* Copy payload */ - payload = hdr + 1; + payload = &msg->data[0] + sizeof(*hdr); payload_size = min(buf_size_remaining, GH_RM_MAX_MSG_SIZE); memcpy(payload, req_buf_curr, payload_size); req_buf_curr += payload_size; @@ -615,23 +614,23 @@ out: * gh_rm_call: Achieve request-response type communication with RPC * @rm: Pointer to Gunyah resource manager internal data * @message_id: The RM RPC message-id - * @req_buff: Request buffer that contains the payload + * @req_buf: Request buffer that contains the payload * @req_buf_size: Total size of the payload * @resp_buf: Pointer to a response buffer * @resp_buf_size: Size of the response buffer * - * Make a request to the RM-VM and wait for reply back. For a successful + * Make a request to the Resource Manager and wait for reply back. For a successful * response, the function returns the payload. The size of the payload is set in - * resp_buf_size. The resp_buf should be freed by the caller when 0 is returned + * resp_buf_size. The resp_buf must be freed by the caller when 0 is returned * and resp_buf_size != 0. * - * req_buff should be not NULL for req_buf_size >0. If req_buf_size == 0, - * req_buff *can* be NULL and no additional payload is sent. + * req_buf should be not NULL for req_buf_size >0. If req_buf_size == 0, + * req_buf *can* be NULL and no additional payload is sent. * * Context: Process context. Will sleep waiting for reply. * Return: 0 on success. <0 if error. */ -int gh_rm_call(struct gh_rm *rm, u32 message_id, void *req_buff, size_t req_buf_size, +int gh_rm_call(struct gh_rm *rm, u32 message_id, void *req_buf, size_t req_buf_size, void **resp_buf, size_t *resp_buf_size) { struct gh_rm_connection *connection; @@ -639,7 +638,7 @@ int gh_rm_call(struct gh_rm *rm, u32 message_id, void *req_buff, size_t req_buf_ int ret; /* message_id 0 is reserved. req_buf_size implies req_buf is not NULL */ - if (!message_id || (!req_buff && req_buf_size) || !rm) + if (!rm || !message_id || (!req_buf && req_buf_size)) return -EINVAL; @@ -660,7 +659,7 @@ int gh_rm_call(struct gh_rm *rm, u32 message_id, void *req_buff, size_t req_buf_ connection->reply.seq = lower_16_bits(seq_id); /* Send the request to the Resource Manager */ - ret = gh_rm_send_request(rm, message_id, req_buff, req_buf_size, connection); + ret = gh_rm_send_request(rm, message_id, req_buf, req_buf_size, connection); if (ret < 0) goto out; diff --git a/drivers/virt/gunyah/rsc_mgr.h b/drivers/virt/gunyah/rsc_mgr.h index 6838e736f361..1e0a1cc7e844 100644 --- a/drivers/virt/gunyah/rsc_mgr.h +++ b/drivers/virt/gunyah/rsc_mgr.h @@ -10,7 +10,7 @@ #include struct gh_rm; -int gh_rm_call(struct gh_rm *rsc_mgr, u32 message_id, void *req_buff, size_t req_buf_size, +int gh_rm_call(struct gh_rm *rsc_mgr, u32 message_id, void *req_buf, size_t req_buf_size, void **resp_buf, size_t *resp_buf_size); int gh_rm_platform_pre_mem_share(struct gh_rm *rm, struct gh_rm_mem_parcel *mem_parcel); diff --git a/drivers/virt/gunyah/rsc_mgr_rpc.c b/drivers/virt/gunyah/rsc_mgr_rpc.c index d6b3ccceee68..4a8f94a34cf2 100644 --- a/drivers/virt/gunyah/rsc_mgr_rpc.c +++ b/drivers/virt/gunyah/rsc_mgr_rpc.c @@ -60,7 +60,7 @@ struct gh_rm_mem_release_req { } __packed; /* Call: MEM_APPEND */ -#define GH_MEM_APPEND_REQ_FLAGS_END BIT(0) +#define GH_MEM_APPEND_REQ_FLAGS_END BIT(0) struct gh_rm_mem_append_req_header { __le32 mem_handle; @@ -76,7 +76,7 @@ struct gh_rm_vm_alloc_vmid_resp { } __packed; /* Call: VM_STOP */ -#define GH_RM_VM_STOP_FLAG_FORCE_STOP BIT(0) +#define GH_RM_VM_STOP_FLAG_FORCE_STOP BIT(0) #define GH_RM_VM_STOP_REASON_FORCE_STOP 3 @@ -184,6 +184,7 @@ static int gh_rm_mem_append(struct gh_rm *rm, u32 mem_handle, static int gh_rm_mem_lend_common(struct gh_rm *rm, u32 message_id, struct gh_rm_mem_parcel *p) { size_t msg_size = 0, initial_mem_entries = p->n_mem_entries, resp_size; + size_t acl_section_size, mem_section_size; struct gh_rm_mem_share_req_acl_section *acl_section; struct gh_rm_mem_share_req_mem_section *mem_section; struct gh_rm_mem_share_req_header *req_header; @@ -199,6 +200,8 @@ static int gh_rm_mem_lend_common(struct gh_rm *rm, u32 message_id, struct gh_rm_ if (initial_mem_entries > GH_RM_MAX_MEM_ENTRIES) initial_mem_entries = GH_RM_MAX_MEM_ENTRIES; + acl_section_size = struct_size(acl_section, entries, p->n_acl_entries); + mem_section_size = struct_size(mem_section, entries, initial_mem_entries); /* The format of the message goes: * request header * ACL entries (which VMs get what kind of access to this memory parcel) @@ -206,8 +209,8 @@ static int gh_rm_mem_lend_common(struct gh_rm *rm, u32 message_id, struct gh_rm_ * Memory attributes (currently unused, we'll hard-code the size to 0) */ msg_size += sizeof(struct gh_rm_mem_share_req_header); - msg_size += struct_size(acl_section, entries, p->n_acl_entries); - msg_size += struct_size(mem_section, entries, initial_mem_entries); + msg_size += acl_section_size; + msg_size += mem_section_size; msg_size += sizeof(u32); /* for memory attributes, currently unused */ msg = kzalloc(msg_size, GFP_KERNEL); @@ -222,8 +225,8 @@ static int gh_rm_mem_lend_common(struct gh_rm *rm, u32 message_id, struct gh_rm_ req_header = msg; acl_section = (void *)req_header + sizeof(*req_header); - mem_section = (void *)acl_section + struct_size(acl_section, entries, p->n_acl_entries); - attr_section = (void *)mem_section + struct_size(mem_section, entries, initial_mem_entries); + mem_section = (void *)acl_section + acl_section_size; + attr_section = (void *)mem_section + mem_section_size; req_header->mem_type = p->mem_type; if (initial_mem_entries != p->n_mem_entries) @@ -231,11 +234,12 @@ static int gh_rm_mem_lend_common(struct gh_rm *rm, u32 message_id, struct gh_rm_ req_header->label = cpu_to_le32(p->label); acl_section->n_entries = cpu_to_le32(p->n_acl_entries); - memcpy(acl_section->entries, p->acl_entries, sizeof(*(p->acl_entries)) * p->n_acl_entries); + memcpy(acl_section->entries, p->acl_entries, + flex_array_size(acl_section, entries, p->n_acl_entries)); mem_section->n_entries = cpu_to_le16(initial_mem_entries); memcpy(mem_section->entries, p->mem_entries, - sizeof(*(p->mem_entries)) * initial_mem_entries); + flex_array_size(mem_section, entries, initial_mem_entries)); /* Set n_entries for memory attribute section to 0 */ *attr_section = 0; @@ -249,6 +253,7 @@ static int gh_rm_mem_lend_common(struct gh_rm *rm, u32 message_id, struct gh_rm_ } p->mem_handle = le32_to_cpu(*resp); + kfree(resp); if (initial_mem_entries != p->n_mem_entries) { ret = gh_rm_mem_append(rm, p->mem_handle, @@ -260,14 +265,13 @@ static int gh_rm_mem_lend_common(struct gh_rm *rm, u32 message_id, struct gh_rm_ } } - kfree(resp); return ret; } /** * gh_rm_mem_lend() - Lend memory to other virtual machines. * @rm: Handle to a Gunyah resource manager - * @parcel: Package the memory information of the memory to be lent. + * @parcel: Information about the memory to be lent. * * Lending removes Linux's access to the memory while the memory parcel is lent. */ @@ -280,7 +284,7 @@ int gh_rm_mem_lend(struct gh_rm *rm, struct gh_rm_mem_parcel *parcel) /** * gh_rm_mem_share() - Share memory with other virtual machines. * @rm: Handle to a Gunyah resource manager - * @parcel: Package the memory information of the memory to be shared. + * @parcel: Information about the memory to be shared. * * Sharing keeps Linux's access to the memory while the memory parcel is shared. */ @@ -292,7 +296,7 @@ int gh_rm_mem_share(struct gh_rm *rm, struct gh_rm_mem_parcel *parcel) /** * gh_rm_mem_reclaim() - Reclaim a memory parcel * @rm: Handle to a Gunyah resource manager - * @parcel: Package the memory information of the memory to be reclaimed. + * @parcel: Information about the memory to be reclaimed. * * RM maps the associated memory back into the stage-2 page tables of the owner VM. */ @@ -366,7 +370,7 @@ int gh_rm_alloc_vmid(struct gh_rm *rm, u16 vmid) } /** - * gh_rm_dealloc_vmid() - Dispose the VMID + * gh_rm_dealloc_vmid() - Dispose of a VMID * @rm: Handle to a Gunyah resource manager * @vmid: VM identifier allocated with gh_rm_alloc_vmid */ @@ -376,11 +380,11 @@ int gh_rm_dealloc_vmid(struct gh_rm *rm, u16 vmid) } /** - * gh_rm_vm_reset() - Reset the VM's resources + * gh_rm_vm_reset() - Reset a VM's resources * @rm: Handle to a Gunyah resource manager * @vmid: VM identifier allocated with gh_rm_alloc_vmid * - * While tearing down the VM, request RM to clean up all the VM resources + * As part of tearing down the VM, request RM to clean up all the VM resources * associated with the VM. Only after this, Linux can clean up all the * references it maintains to resources. */ @@ -390,7 +394,7 @@ int gh_rm_vm_reset(struct gh_rm *rm, u16 vmid) } /** - * gh_rm_vm_start() - Move the VM into "ready to run" state + * gh_rm_vm_start() - Move a VM into "ready to run" state * @rm: Handle to a Gunyah resource manager * @vmid: VM identifier allocated with gh_rm_alloc_vmid * @@ -432,9 +436,7 @@ int gh_rm_vm_stop(struct gh_rm *rm, u16 vmid) * @image_size: Size of the VM image * @dtb_offset: Start address of the devicetree binary with VM configuration, * relative to start of memparcel. - * @dtb_size: Maximum size of devicetree binary. Resource manager applies - * an overlay to the DTB and dtb_size should include room for - * the overlay. + * @dtb_size: Maximum size of devicetree binary. */ int gh_rm_vm_configure(struct gh_rm *rm, u16 vmid, enum gh_rm_vm_auth_mechanism auth_mechanism, u32 mem_handle, u64 image_offset, u64 image_size, u64 dtb_offset, u64 dtb_size) @@ -470,6 +472,7 @@ int gh_rm_vm_init(struct gh_rm *rm, u16 vmid) * @rm: Handle to a Gunyah resource manager * @vmid: VMID of the other VM to get the resources of * @resources: Set by gh_rm_get_hyp_resources and contains the returned hypervisor resources. + * Caller must free the resources pointer if successful. */ int gh_rm_get_hyp_resources(struct gh_rm *rm, u16 vmid, struct gh_rm_hyp_resources **resources) diff --git a/include/linux/gunyah_rsc_mgr.h b/include/linux/gunyah_rsc_mgr.h index 11a9d14b4e98..7e2c9b7d5e20 100644 --- a/include/linux/gunyah_rsc_mgr.h +++ b/include/linux/gunyah_rsc_mgr.h @@ -14,8 +14,8 @@ #define GH_MEM_HANDLE_INVAL U32_MAX struct gh_rm; -int gh_rm_call(struct gh_rm *rm, u32 message_id, void *req_buff, size_t req_buff_size, - void **resp_buf, size_t *resp_buff_size); +int gh_rm_call(struct gh_rm *rm, u32 message_id, void *req_buf, size_t req_buf_size, + void **resp_buf, size_t *resp_buf_size); int gh_rm_notifier_register(struct gh_rm *rm, struct notifier_block *nb); int gh_rm_notifier_unregister(struct gh_rm *rm, struct notifier_block *nb); struct device *gh_rm_get(struct gh_rm *rm);