haven: irq_lend: add support for IRQ notifications

Currently IRQ APIs are combined with notifications to VMs for sharing the
handles. This limit the clients for managing the error handling from the
drivers. Hence separate the notifications from the actual APIs so that
clients manage the error handling better. Add support for notifications
like IRQ_LEND/ACCEPT/RELEASE from SVM to PVM when SVM accept the irq
handle shared by PVM.

Change-Id: I49999c2d9494c68b1542680e521c012a25e3f6a8
Signed-off-by: Murali Nalajala <[email protected]>
This commit is contained in:
Murali Nalajala 2020-06-15 14:56:18 -07:00 • committed by Gerrit - the friendly Code Review server
commit e98e9702f5
8 changed files with 376 additions and 176 deletions

View file

@ -17,22 +17,20 @@
struct hh_irq_entry {
hh_vmid_t vmid;
enum hh_vm_names vm_name;
hh_irq_handle_fn_v2 v2_handle;
hh_irq_handle_fn handle;
void *data;
enum {
/* start state */
HH_IRQ_STATE_NONE,
/* NONE -> WAIT_RELEASE by hh_irq_lend */
HH_IRQ_STATE_WAIT_RELEASE,
/* NONE -> WAIT_LEND by hh_irq_wait_lend */
HH_IRQ_STATE_WAIT_RELEASE_OR_ACCEPT,
HH_IRQ_STATE_WAIT_LEND,
/* WAIT_RELEASE -> RELEASED by notifier */
/* RELEASED -> NONE by hh_irq_reclaim */
HH_IRQ_STATE_RELEASED,
/* WAIT_LEND -> LENT by notifier */
/* LENT -> NONE by hh_irq_release */
HH_IRQ_STATE_LENT,
/* notification states */
HH_IRQ_STATE_RELEASED, /* svm -> pvm */
HH_IRQ_STATE_ACCEPTED, /* svm -> pvm */
HH_IRQ_STATE_LENT, /* pvm -> svm */
} state;
hh_virq_handle_t virq_handle;
};
@ -40,31 +38,50 @@ struct hh_irq_entry {
static struct hh_irq_entry hh_irq_entries[HH_IRQ_LABEL_MAX];
static DEFINE_SPINLOCK(hh_irq_lend_lock);
static int hh_irq_released_nb_handler(struct notifier_block *this,
static int hh_irq_released_accepted_nb_handler(struct notifier_block *this,
unsigned long cmd, void *data)
{
unsigned long flags;
enum hh_irq_label label;
struct hh_irq_entry *entry;
struct hh_rm_notif_vm_irq_released_payload *released = data;
struct hh_rm_notif_vm_irq_released_payload *released;
struct hh_rm_notif_vm_irq_accepted_payload *accepted;
if (cmd != HH_RM_NOTIF_VM_IRQ_RELEASED)
if (cmd != HH_RM_NOTIF_VM_IRQ_RELEASED &&
cmd != HH_RM_NOTIF_VM_IRQ_ACCEPTED)
return NOTIFY_DONE;
spin_lock_irqsave(&hh_irq_lend_lock, flags);
for (label = 0; label < HH_IRQ_LABEL_MAX; label++) {
entry = &hh_irq_entries[label];
if (entry->state != HH_IRQ_STATE_WAIT_RELEASE)
if (entry->state != HH_IRQ_STATE_WAIT_RELEASE_OR_ACCEPT &&
entry->state != HH_IRQ_STATE_ACCEPTED)
continue;
if (released->virq_handle == entry->virq_handle) {
entry->state = HH_IRQ_STATE_RELEASED;
spin_unlock_irqrestore(&hh_irq_lend_lock,
flags);
switch (cmd) {
case HH_RM_NOTIF_VM_IRQ_RELEASED:
released = data;
if (released->virq_handle == entry->virq_handle) {
entry->state = HH_IRQ_STATE_RELEASED;
spin_unlock_irqrestore(&hh_irq_lend_lock,
flags);
entry->v2_handle(entry->data, cmd, label);
return NOTIFY_OK;
}
entry->handle(entry->data, label);
break;
case HH_RM_NOTIF_VM_IRQ_ACCEPTED:
accepted = data;
if (accepted->virq_handle == entry->virq_handle) {
entry->state = HH_IRQ_STATE_ACCEPTED;
spin_unlock_irqrestore(&hh_irq_lend_lock,
flags);
entry->v2_handle(entry->data, cmd, label);
return NOTIFY_OK;
}
return NOTIFY_OK;
break;
}
}
spin_unlock_irqrestore(&hh_irq_lend_lock, flags);
@ -72,8 +89,8 @@ static int hh_irq_released_nb_handler(struct notifier_block *this,
return NOTIFY_DONE;
}
static struct notifier_block hh_irq_released_nb = {
.notifier_call = hh_irq_released_nb_handler,
static struct notifier_block hh_irq_released_accepted_nb = {
.notifier_call = hh_irq_released_accepted_nb_handler,
};
static int hh_irq_lent_nb_handler(struct notifier_block *this,
@ -112,7 +129,7 @@ static int hh_irq_lent_nb_handler(struct notifier_block *this,
spin_unlock_irqrestore(&hh_irq_lend_lock,
flags);
entry->handle(entry->data, label);
entry->v2_handle(entry->data, cmd, label);
return NOTIFY_OK;
}
@ -127,22 +144,24 @@ static struct notifier_block hh_irq_lent_nb = {
};
/**
* hh_irq_lend: Lend a hardware interrupt to another VM
* hh_irq_lend_v2: Lend a hardware interrupt to another VM
* @label: vIRQ high-level label
* @name: VM name to send interrupt to
* @irq: Linux IRQ number to lend
* @on_release: callback to invoke when other VM returns the
* interrupt
* @data: Argument to pass to on_release
* @cb_handle: callback to invoke when other VM release or accept the interrupt
* @data: Argument to pass to cb_handle
*
* Returns 0 on success also the handle corresponding to Linux IRQ#.
* Returns < 0 on error
*/
int hh_irq_lend(enum hh_irq_label label, enum hh_vm_names name,
int irq, hh_irq_handle_fn on_release, void *data)
int hh_irq_lend_v2(enum hh_irq_label label, enum hh_vm_names name,
int irq, hh_irq_handle_fn_v2 cb_handle, void *data)
{
int ret, virq;
unsigned long flags;
struct hh_irq_entry *entry;
if (label >= HH_IRQ_LABEL_MAX || !on_release)
if (label >= HH_IRQ_LABEL_MAX || !cb_handle)
return -EINVAL;
entry = &hh_irq_entries[label];
@ -163,16 +182,62 @@ int hh_irq_lend(enum hh_irq_label label, enum hh_vm_names name,
return ret;
}
entry->handle = on_release;
entry->v2_handle = cb_handle;
entry->data = data;
entry->state = HH_IRQ_STATE_WAIT_RELEASE;
entry->state = HH_IRQ_STATE_WAIT_RELEASE_OR_ACCEPT;
spin_unlock_irqrestore(&hh_irq_lend_lock, flags);
return hh_rm_vm_irq_lend_notify(entry->vmid, virq, label,
&entry->virq_handle);
return hh_rm_vm_irq_lend(entry->vmid, virq, label, &entry->virq_handle);
}
EXPORT_SYMBOL(hh_irq_lend_v2);
/**
* hh_irq_lend: Lend a hardware interrupt to another VM
* @label: vIRQ high-level label
* @name: VM name to send interrupt to
* @irq: Linux IRQ number to lend
* @cb_handle: callback to invoke when other VM release or accept the interrupt
* @data: Argument to pass to cb_handle
*
* Returns 0 on success also the handle corresponding to Linux IRQ#.
* Returns < 0 on error
*/
int hh_irq_lend(enum hh_irq_label label, enum hh_vm_names name,
int irq, hh_irq_handle_fn cb_handle, void *data)
{
struct hh_irq_entry *entry;
if (label >= HH_IRQ_LABEL_MAX || !cb_handle)
return -EINVAL;
entry = &hh_irq_entries[label];
entry->handle = cb_handle;
return 0;
}
EXPORT_SYMBOL(hh_irq_lend);
/**
* hh_irq_lend_notify: Pass the irq handle to other VM for accept
* @label: vIRQ high-level label
*
* Returns 0 on success, < 0 on error
*/
int hh_irq_lend_notify(enum hh_irq_label label)
{
struct hh_irq_entry *entry;
if (label >= HH_IRQ_LABEL_MAX)
return -EINVAL;
entry = &hh_irq_entries[label];
if (entry->state == HH_IRQ_STATE_NONE)
return -EINVAL;
return hh_rm_vm_irq_lend_notify(entry->vmid, entry->virq_handle);
}
EXPORT_SYMBOL(hh_irq_lend_notify);
/**
* hh_irq_reclaim: Reclaim a hardware interrupt after other VM
* has released.
@ -193,7 +258,8 @@ int hh_irq_reclaim(enum hh_irq_label label)
entry = &hh_irq_entries[label];
if (entry->state != HH_IRQ_STATE_RELEASED)
if (entry->state != HH_IRQ_STATE_WAIT_RELEASE_OR_ACCEPT &&
(entry->state != HH_IRQ_STATE_RELEASED))
return -EINVAL;
ret = hh_rm_vm_irq_reclaim(entry->virq_handle);
@ -204,15 +270,14 @@ int hh_irq_reclaim(enum hh_irq_label label)
EXPORT_SYMBOL(hh_irq_reclaim);
/**
* hh_irq_wait_lend: Register to claim a lent interrupt from another
* VM
* hh_irq_wait_for_lend_v2: Register to claim a lent interrupt from another VM
* @label: vIRQ high-level label
* @name: Lender's VM name. If don't care, then use HH_VM_MAX
* @on_lend: callback to invoke when other VM lends the interrupt
* @data: Argument to pass to on_lend
*/
int hh_irq_wait_for_lend(enum hh_irq_label label, enum hh_vm_names name,
hh_irq_handle_fn on_lend, void *data)
int hh_irq_wait_for_lend_v2(enum hh_irq_label label, enum hh_vm_names name,
hh_irq_handle_fn_v2 on_lend, void *data)
{
unsigned long flags;
struct hh_irq_entry *entry;
@ -229,13 +294,27 @@ int hh_irq_wait_for_lend(enum hh_irq_label label, enum hh_vm_names name,
}
entry->vm_name = name;
entry->handle = on_lend;
entry->v2_handle = on_lend;
entry->data = data;
entry->state = HH_IRQ_STATE_WAIT_LEND;
spin_unlock_irqrestore(&hh_irq_lend_lock, flags);
return 0;
}
EXPORT_SYMBOL(hh_irq_wait_for_lend_v2);
/**
* hh_irq_wait_lend: Register to claim a lent interrupt from another VM
* @label: vIRQ high-level label
* @name: Lender's VM name. If don't care, then use HH_VM_MAX
* @on_lend: callback to invoke when other VM lends the interrupt
* @data: Argument to pass to on_lend
*/
int hh_irq_wait_for_lend(enum hh_irq_label label, enum hh_vm_names name,
hh_irq_handle_fn on_lend, void *data)
{
return 0;
}
EXPORT_SYMBOL(hh_irq_wait_for_lend);
/**
@ -276,10 +355,38 @@ int hh_irq_accept(enum hh_irq_label label, int irq, int type)
if (irq == -1)
irq = hh_rm_virq_to_irq(virq, type);
entry->state = HH_IRQ_STATE_ACCEPTED;
return irq;
}
EXPORT_SYMBOL(hh_irq_accept);
/**
* hh_irq_accept_notify: Notify the lend vm (pvm) that IRQ is accepted
* @label: vIRQ high-level label
* @irq: Linux IRQ# to associate vIRQ with. If don't care, use -1
*
* Returns the Linux IRQ# that vIRQ was registered to on success.
* Returns <0 on error
* This function is not thread-safe w.r.t. IRQ lend state. Do not race with
* hh_irq_release or another hh_irq_accept with same label.
*/
int hh_irq_accept_notify(enum hh_irq_label label)
{
struct hh_irq_entry *entry;
if (label >= HH_IRQ_LABEL_MAX)
return -EINVAL;
entry = &hh_irq_entries[label];
if (entry->state != HH_IRQ_STATE_ACCEPTED)
return -EINVAL;
return hh_rm_vm_irq_accept_notify(entry->vmid,
entry->virq_handle);
}
EXPORT_SYMBOL(hh_irq_accept_notify);
/**
* hh_irq_release: Release a lent interrupt
* @label: vIRQ high-level label
@ -296,17 +403,34 @@ int hh_irq_release(enum hh_irq_label label)
entry = &hh_irq_entries[label];
if (entry->state != HH_IRQ_STATE_LENT)
if (entry->state != HH_IRQ_STATE_ACCEPTED)
return -EINVAL;
ret = hh_rm_vm_irq_release_notify(entry->vmid,
entry->virq_handle);
ret = hh_rm_vm_irq_release(entry->virq_handle);
if (!ret)
entry->state = HH_IRQ_STATE_WAIT_LEND;
return ret;
}
EXPORT_SYMBOL(hh_irq_release);
int hh_irq_release_notify(enum hh_irq_label label)
{
struct hh_irq_entry *entry;
if (label >= HH_IRQ_LABEL_MAX)
return -EINVAL;
entry = &hh_irq_entries[label];
if (entry->state != HH_IRQ_STATE_ACCEPTED &&
entry->state != HH_IRQ_STATE_WAIT_LEND)
return -EINVAL;
return hh_rm_vm_irq_release_notify(entry->vmid,
entry->virq_handle);
}
EXPORT_SYMBOL(hh_irq_release_notify);
static int __init hh_irq_lend_init(void)
{
int ret;
@ -314,14 +438,15 @@ static int __init hh_irq_lend_init(void)
ret = hh_rm_register_notifier(&hh_irq_lent_nb);
if (ret)
return ret;
return hh_rm_register_notifier(&hh_irq_released_nb);
return hh_rm_register_notifier(&hh_irq_released_accepted_nb);
}
module_init(hh_irq_lend_init);
static void hh_irq_lend_exit(void)
{
hh_rm_unregister_notifier(&hh_irq_lent_nb);
hh_rm_unregister_notifier(&hh_irq_released_nb);
hh_rm_unregister_notifier(&hh_irq_released_accepted_nb);
}
module_exit(hh_irq_lend_exit);

View file

@ -218,6 +218,15 @@ static int hh_rm_process_notif(void *recv_buff, size_t recv_buff_size)
goto err;
}
break;
case HH_RM_NOTIF_VM_IRQ_ACCEPTED:
if (recv_buff_size != sizeof(*hdr) +
sizeof(struct hh_rm_notif_vm_irq_accepted_payload)) {
pr_err("%s: Invalid size for VM_IRQ_ACCEPTED notif: %u\n",
__func__, recv_buff_size - sizeof(*hdr));
ret = -EINVAL;
goto err;
}
break;
case HH_RM_NOTIF_MEM_SHARED:
if (recv_buff_size < sizeof(*hdr) +
sizeof(struct hh_rm_notif_mem_shared_payload)) {

View file

@ -181,6 +181,7 @@ struct hh_vm_irq_lend_resp_payload {
/* Call: VM_IRQ_NOTIFY */
#define HH_VM_IRQ_NOTIFY_FLAGS_LENT BIT(0)
#define HH_VM_IRQ_NOTIFY_FLAGS_RELEASED BIT(1)
#define HH_VM_IRQ_NOTIFY_FLAGS_ACCEPTED BIT(2)
/* Call: VM_IRQ_RELEASE */
struct hh_vm_irq_release_req_payload {

View file

@ -145,102 +145,6 @@ out:
return resp_entries;
}
/**
* hh_rm_vm_irq_accept: Bind the virq number to the supplied virq_handle
* @virq_handle: The virtual IRQ handle (for example, obtained via
* call to hh_rm_get_hyp_resources())
* @virq: The virtual IRQ number to bind to. Note that this is the virtual
* GIC IRQ number and not the linux IRQ number. Pass -1 here if the
* caller wants the Resource Manager VM to allocate a number
*
* If provided -1 for virq, the function returns the new IRQ number, else
* the one that was already provided.
*
* The function encodes the error codes via ERR_PTR. Hence, the caller is
* responsible to check it with IS_ERR_OR_NULL().
*/
int hh_rm_vm_irq_accept(hh_virq_handle_t virq_handle, int virq)
{
struct hh_vm_irq_accept_resp_payload *resp_payload;
struct hh_vm_irq_accept_req_payload req_payload = {0};
size_t resp_payload_size;
int ret, reply_err_code;
/* -1 is valid for virq if requesting for a new number */
if (virq < -1)
return -EINVAL;
req_payload.virq_handle = virq_handle;
req_payload.virq = virq;
resp_payload = hh_rm_call(HH_RM_RPC_MSG_ID_CALL_VM_IRQ_ACCEPT,
&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_ACCEPT failed with err: %d\n",
__func__, ret);
return ret;
}
if (virq == -1 && resp_payload_size != sizeof(*resp_payload)) {
pr_err("%s: Invalid size received for VM_IRQ_ACCEPT: %u\n",
__func__, resp_payload_size);
ret = -EINVAL;
goto out;
}
ret = virq == -1 ? resp_payload->virq : virq;
out:
kfree(resp_payload);
return ret;
}
EXPORT_SYMBOL(hh_rm_vm_irq_accept);
/**
* 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 = {0};
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
@ -250,7 +154,7 @@ out:
* 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)
u16 flags, hh_virq_handle_t virq_handle)
{
void *resp;
struct hh_vm_irq_notify_req_payload *req_payload;
@ -308,6 +212,51 @@ static int hh_rm_vm_irq_notify(const hh_vmid_t *vmids, unsigned int num_vmids,
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
*/
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 = {0};
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;
}
EXPORT_SYMBOL(hh_rm_vm_irq_lend);
/**
* hh_rm_vm_irq_lend_notify: Lend an IRQ to a VM and notify the VM about it
* @vmid: VM to lend interrupt to
@ -320,20 +269,10 @@ static int hh_rm_vm_irq_notify(const hh_vmid_t *vmids, unsigned int num_vmids,
* 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 hh_rm_vm_irq_lend_notify(hh_vmid_t vmid, hh_virq_handle_t virq_handle)
{
int ret;
if (!virq_handle)
return -EINVAL;
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);
virq_handle);
}
EXPORT_SYMBOL(hh_rm_vm_irq_lend_notify);
@ -341,7 +280,7 @@ EXPORT_SYMBOL(hh_rm_vm_irq_lend_notify);
* 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)
int hh_rm_vm_irq_release(hh_virq_handle_t virq_handle)
{
struct hh_vm_irq_release_req_payload req_payload = {0};
void *resp;
@ -374,6 +313,7 @@ static int hh_rm_vm_irq_release(hh_virq_handle_t virq_handle)
return ret;
}
EXPORT_SYMBOL(hh_rm_vm_irq_release);
/**
* hh_rm_vm_irq_release_notify: Release IRQ back to a VM and notify that it has
@ -383,17 +323,76 @@ static int hh_rm_vm_irq_release(hh_virq_handle_t virq_handle)
*/
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);
}
EXPORT_SYMBOL(hh_rm_vm_irq_release_notify);
/**
* hh_rm_vm_irq_accept: Bind the virq number to the supplied virq_handle
* @virq_handle: The virtual IRQ handle (for example, obtained via
* call to hh_rm_get_hyp_resources())
* @virq: The virtual IRQ number to bind to. Note that this is the virtual
* GIC IRQ number and not the linux IRQ number. Pass -1 here if the
* caller wants the Resource Manager VM to allocate a number
*
* If provided -1 for virq, the function returns the new IRQ number, else
* the one that was already provided.
*
* The function encodes the error codes via ERR_PTR. Hence, the caller is
* responsible to check it with IS_ERR_OR_NULL().
*/
int hh_rm_vm_irq_accept(hh_virq_handle_t virq_handle, int virq)
{
struct hh_vm_irq_accept_resp_payload *resp_payload;
struct hh_vm_irq_accept_req_payload req_payload = {0};
size_t resp_payload_size;
int ret, reply_err_code;
/* -1 is valid for virq if requesting for a new number */
if (virq < -1)
return -EINVAL;
req_payload.virq_handle = virq_handle;
req_payload.virq = virq;
resp_payload = hh_rm_call(HH_RM_RPC_MSG_ID_CALL_VM_IRQ_ACCEPT,
&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_ACCEPT failed with err: %d\n",
__func__, ret);
return ret;
}
if (virq == -1 && resp_payload_size != sizeof(*resp_payload)) {
pr_err("%s: Invalid size received for VM_IRQ_ACCEPT: %u\n",
__func__, resp_payload_size);
ret = -EINVAL;
goto out;
}
ret = virq == -1 ? resp_payload->virq : virq;
out:
kfree(resp_payload);
return ret;
}
EXPORT_SYMBOL(hh_rm_vm_irq_accept);
/**
* 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_accept_notify(hh_vmid_t vmid, hh_virq_handle_t virq_handle)
{
return hh_rm_vm_irq_notify(NULL, 0, HH_VM_IRQ_NOTIFY_FLAGS_ACCEPTED,
virq_handle);
}
EXPORT_SYMBOL(hh_rm_vm_irq_accept_notify);
/**
* hh_rm_vm_irq_reclaim: Return a lent IRQ
* @virq_handle: IRQ handle to be reclaimed