haven: rm: Add IRQ Management APIs for IRQ lending

RM allows VMs to lend interrupts to one another. This patch implements
the lender API.

Change-Id: I7671a2b346d2425f963631da4b8529fc9b10dc40
Signed-off-by: Elliot Berman <eberman@codeaurora.org>
This commit is contained in:
Elliot Berman 2020-01-28 15:12:22 -08:00
commit 3415eaf8cb
3 changed files with 162 additions and 0 deletions

View file

@ -151,6 +151,36 @@ struct hh_vm_irq_accept_resp_payload {
s32 virq;
} __packed;
/* Call: VM_IRQ_LEND */
struct hh_vm_irq_lend_req_payload {
hh_vmid_t vmid;
s32 virq;
s32 label;
} __packed;
struct hh_vm_irq_lend_resp_payload {
hh_virq_handle_t virq;
} __packed;
/* Call: VM_IRQ_NOTIFY */
#define HH_VM_IRQ_NOTIFY_FLAGS_LENT BIT(0)
#define HH_VM_IRQ_NOTIFY_FLAGS_RELEASED BIT(1)
struct hh_vm_irq_notify_req_payload {
hh_virq_handle_t virq;
u16 flags;
u16 reserved0;
u32 reserved1;
struct {
u32 num_vmids;
u64 vmids[0];
} optional[0];
} __packed;
struct hh_vm_irq_notify_resp_payload {
hh_virq_handle_t virq;
} __packed;
/* End Message ID headers */
/* Common function declerations */

View file

@ -185,6 +185,135 @@ out:
return ret;
}
/**
* hh_rm_vm_irq_lend: Lend an IRQ to another VM
* @vmid: VM to lend the interrupt to
* @virq: Virtual IRQ number to lend
* @label: Label to give to VM so it may know how to associate the interrupt
* @virq_handle: Response handle which RM will accept from the other VM to take
* the lent interrupt
*/
static int hh_rm_vm_irq_lend(hh_vmid_t vmid, int virq, int label,
hh_virq_handle_t *virq_handle)
{
struct hh_vm_irq_lend_resp_payload *resp_payload;
struct hh_vm_irq_lend_req_payload req_payload;
size_t resp_payload_size;
int ret = 0, reply_err_code;
req_payload.vmid = vmid;
req_payload.virq = virq;
req_payload.label = label;
resp_payload = hh_rm_call(HH_RM_RPC_MSG_ID_CALL_VM_IRQ_LEND,
&req_payload, sizeof(req_payload),
&resp_payload_size, &reply_err_code);
if (reply_err_code || IS_ERR_OR_NULL(resp_payload)) {
ret = PTR_ERR(resp_payload);
pr_err("%s: VM_IRQ_LEND failed with err: %d\n",
__func__, ret);
return ret;
}
if (resp_payload_size != sizeof(*resp_payload)) {
pr_err("%s: Invalid size received for VM_IRQ_LEND: %u\n",
__func__, resp_payload_size);
ret = -EINVAL;
goto out;
}
if (virq_handle)
*virq_handle = resp_payload->virq;
out:
kfree(resp_payload);
return ret;
}
/**
* hh_rm_vm_irq_notify: Notify an IRQ to another VM
* @vmids: VMs to notify the handle about
* @num_vmids: number of VMs to notify the handle about
* @flags: notification reason
* @virq_handle: Response handle which RM will accept from the other VM to take
* the lent interrupt
*/
static int hh_rm_vm_irq_notify(const hh_vmid_t *vmids, unsigned int num_vmids,
u16 flags, hh_virq_handle_t virq_handle)
{
struct hh_vm_irq_notify_resp_payload *resp_payload;
struct hh_vm_irq_notify_req_payload *req_payload;
size_t resp_payload_size, req_payload_size;
int ret = 0, reply_err_code;
unsigned int i;
if (!(flags & HH_VM_IRQ_NOTIFY_FLAGS_LENT) && num_vmids)
return -EINVAL;
if (num_vmids > U32_MAX)
return -EINVAL;
req_payload_size = sizeof(*req_payload);
if (flags & HH_VM_IRQ_NOTIFY_FLAGS_LENT)
req_payload_size += sizeof(req_payload->optional) +
(sizeof(req_payload->optional->vmids[0]) * num_vmids);
req_payload = kzalloc(req_payload_size, GFP_KERNEL);
if (!req_payload)
return -ENOMEM;
req_payload->virq = virq_handle;
req_payload->flags = flags;
if (flags & HH_VM_IRQ_NOTIFY_FLAGS_LENT) {
req_payload->optional[0].num_vmids = num_vmids;
for (i = 0; i < num_vmids; i++)
req_payload->optional[0].vmids[i] = vmids[i];
}
resp_payload = hh_rm_call(HH_RM_RPC_MSG_ID_CALL_VM_IRQ_NOTIFY,
&req_payload, sizeof(req_payload),
&resp_payload_size, &reply_err_code);
kfree(req_payload);
if (reply_err_code || IS_ERR_OR_NULL(resp_payload)) {
ret = PTR_ERR(resp_payload);
pr_err("%s: VM_IRQ_NOTIFY failed with err: %d\n",
__func__, ret);
return ret;
}
if (resp_payload_size != sizeof(*resp_payload)) {
pr_err("%s: Invalid size received for VM_IRQ_NOTIFY: %u\n",
__func__, resp_payload_size);
ret = -EINVAL;
}
kfree(resp_payload);
return ret;
}
/**
* hh_rm_vm_irq_lend_notify: Lend an IRQ to a VM and notify the VM about it
* @vmid: VM to lend interrupt to
* @virq: Virtual IRQ number to lend
* @label: Label to give to VM so it may know how to associate the interrupt
*
* This function performs interrupt sharing flow for "HLOS" described in
* Resource Manager High Level Design Sec. 3.3.3.
*/
int hh_rm_vm_irq_lend_notify(hh_vmid_t vmid, int virq, int label)
{
hh_virq_handle_t virq_handle;
int ret;
ret = hh_rm_vm_irq_lend(vmid, virq, label, &virq_handle);
if (ret)
return ret;
return hh_rm_vm_irq_notify(&vmid, 1, HH_VM_IRQ_NOTIFY_FLAGS_LENT,
virq_handle);
}
/**
* hh_rm_vm_alloc_vmid: Return a vmid associated with the vm loaded into
* memory. This call should be called only during

View file

@ -114,7 +114,10 @@ struct hh_rm_notif_vm_console_chars {
int hh_rm_register_notifier(struct notifier_block *nb);
int hh_rm_unregister_notifier(struct notifier_block *nb);
/* Client APIs for IRQ management */
int hh_rm_vm_irq_accept(hh_virq_handle_t virq_handle, int virq);
int hh_rm_vm_irq_lend_notify(hh_vmid_t vmid, int virq, int label);
/* Client APIs for VM management */
int hh_rm_vm_alloc_vmid(enum hh_vm_names vm_name);