diff --git a/drivers/virt/haven/hh_rm_drv_private.h b/drivers/virt/haven/hh_rm_drv_private.h index 84edf4c9ccb6..a59b551eebbd 100644 --- a/drivers/virt/haven/hh_rm_drv_private.h +++ b/drivers/virt/haven/hh_rm_drv_private.h @@ -181,6 +181,16 @@ struct hh_vm_irq_lend_resp_payload { #define HH_VM_IRQ_NOTIFY_FLAGS_LENT BIT(0) #define HH_VM_IRQ_NOTIFY_FLAGS_RELEASED BIT(1) +/* Call: VM_IRQ_RELEASE */ +struct hh_vm_irq_release_req_payload { + hh_virq_handle_t virq_handle; +} __packed; + +/* Call: VM_IRQ_RECLAIM */ +struct hh_vm_irq_reclaim_req_payload { + hh_virq_handle_t virq_handle; +} __packed; + struct hh_vm_irq_notify_req_payload { hh_virq_handle_t virq; u8 flags; diff --git a/drivers/virt/haven/hh_rm_iface.c b/drivers/virt/haven/hh_rm_iface.c index 55476458778d..1737e049fc3a 100644 --- a/drivers/virt/haven/hh_rm_iface.c +++ b/drivers/virt/haven/hh_rm_iface.c @@ -337,6 +337,100 @@ int hh_rm_vm_irq_lend_notify(hh_vmid_t vmid, int virq, int label, *virq_handle); } +/** + * hh_rm_vm_irq_release: Return a lent IRQ + * @virq_handle: IRQ handle to be released + */ +static int hh_rm_vm_irq_release(hh_virq_handle_t virq_handle) +{ + struct hh_vm_irq_release_req_payload req_payload = {0}; + void *resp; + int ret = 0, reply_err_code; + size_t resp_payload_size; + + req_payload.virq_handle = virq_handle; + + resp = hh_rm_call(HH_RM_RPC_MSG_ID_CALL_VM_IRQ_RELEASE, + &req_payload, sizeof(req_payload), + &resp_payload_size, &reply_err_code); + + if (IS_ERR(resp)) { + pr_err("%s: Unable to send IRQ_RELEASE to RM: %d\n", __func__, + PTR_ERR(resp)); + return PTR_ERR(resp); + } + + if (reply_err_code) { + pr_err("%s: IRQ_RELEASE returned error: %d\n", __func__, + reply_err_code); + return reply_err_code; + } + + if (resp_payload_size) { + pr_err("%s: Invalid size received for IRQ_RELEASE: %u\n", + __func__, resp_payload_size); + ret = -EINVAL; + } + + return ret; +} + +/** + * hh_rm_vm_irq_release_notify: Release IRQ back to a VM and notify that it has + * been released. + * @vmid: VM to release interrupt to + * @virq_handle: Virtual IRQ handle to release + */ +int hh_rm_vm_irq_release_notify(hh_vmid_t vmid, hh_virq_handle_t virq_handle) +{ + int ret; + + ret = hh_rm_vm_irq_release(virq_handle); + if (ret) + return ret; + + return hh_rm_vm_irq_notify(NULL, 0, HH_VM_IRQ_NOTIFY_FLAGS_RELEASED, + virq_handle); +} + +/** + * hh_rm_vm_irq_reclaim: Return a lent IRQ + * @virq_handle: IRQ handle to be reclaimed + */ +int hh_rm_vm_irq_reclaim(hh_virq_handle_t virq_handle) +{ + struct hh_vm_irq_reclaim_req_payload req_payload = {0}; + void *resp; + int ret = 0, reply_err_code; + size_t resp_payload_size; + + req_payload.virq_handle = virq_handle; + + resp = hh_rm_call(HH_RM_RPC_MSG_ID_CALL_VM_IRQ_RECLAIM, + &req_payload, sizeof(req_payload), + &resp_payload_size, &reply_err_code); + + if (IS_ERR(resp)) { + pr_err("%s: Unable to send IRQ_RELEASE to RM: %d\n", __func__, + PTR_ERR(resp)); + return PTR_ERR(resp); + } + + if (reply_err_code) { + pr_err("%s: IRQ_RELEASE returned error: %d\n", __func__, + reply_err_code); + return reply_err_code; + } + + if (resp_payload_size) { + pr_err("%s: Invalid size received for IRQ_RELEASE: %u\n", + __func__, resp_payload_size); + ret = -EINVAL; + } + + return ret; +} + /** * hh_rm_vm_alloc_vmid: Return a vmid associated with the vm loaded into * memory. This call should be called only during diff --git a/include/linux/haven/hh_rm_drv.h b/include/linux/haven/hh_rm_drv.h index 793e2e1b93b9..5a8ed91212e7 100644 --- a/include/linux/haven/hh_rm_drv.h +++ b/include/linux/haven/hh_rm_drv.h @@ -181,6 +181,8 @@ int hh_rm_unregister_notifier(struct notifier_block *nb); 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, hh_virq_handle_t *virq_handle); +int hh_rm_vm_irq_release_notify(hh_vmid_t vmid, hh_virq_handle_t virq_handle); +int hh_rm_vm_irq_reclaim(hh_virq_handle_t virq_handle); /* Client APIs for VM management */ int hh_rm_vm_alloc_vmid(enum hh_vm_names vm_name);