From b6c5189a5227ae1c01d9d65f85047af5b8518e9c Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Fri, 17 Apr 2020 17:37:20 -0700 Subject: [PATCH] haven: irq_lend: Use Linux IRQ numbers Users of irq_lend must always translate their Linux IRQ number to HW IRQ number. Instead, move this common logic into hh_irq_lend and hh_irq_accept to do the required translation. Change-Id: Ib43e7f32eb20d3236ff594effda3894eaa115fae Signed-off-by: Elliot Berman --- drivers/virt/haven/hh_irq_lend.c | 49 ++++++++++++++++++++------ drivers/virt/haven/hh_rm_core.c | 3 +- drivers/virt/haven/hh_rm_drv_private.h | 2 ++ 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/drivers/virt/haven/hh_irq_lend.c b/drivers/virt/haven/hh_irq_lend.c index 312c6b3a2488..1dd094d6b836 100644 --- a/drivers/virt/haven/hh_irq_lend.c +++ b/drivers/virt/haven/hh_irq_lend.c @@ -4,11 +4,15 @@ * */ +#include #include #include +#include +#include #include #include -#include + +#include "hh_rm_drv_private.h" struct hh_irq_entry { hh_vmid_t vmid; @@ -116,23 +120,29 @@ static struct notifier_block hh_irq_lent_nb = { * hh_irq_lend: Lend a hardware interrupt to another VM * @label: vIRQ high-level label * @name: VM name to send interrupt to - * @hw_irq: Hardware IRQ number to lend + * @irq: Linux IRQ number to lend * @on_release: callback to invoke when other VM returns the * interrupt * @data: Argument to pass to on_release */ int hh_irq_lend(enum hh_irq_label label, enum hh_vm_names name, - int hw_irq, hh_irq_handle_fn on_release, void *data) + int irq, hh_irq_handle_fn on_release, void *data) { - int ret; + int ret, virq; unsigned long flags; struct hh_irq_entry *entry; + struct irq_data *irq_data; if (label >= HH_IRQ_LABEL_MAX || !on_release) return -EINVAL; entry = &hh_irq_entries[label]; + irq_data = irq_get_irq_data(irq); + if (!irq_data) + return -EINVAL; + virq = irq_data->hwirq; + spin_lock_irqsave(&hh_irq_lend_lock, flags); if (entry->state != HH_IRQ_STATE_NONE) { spin_unlock_irqrestore(&hh_irq_lend_lock, flags); @@ -151,7 +161,7 @@ int hh_irq_lend(enum hh_irq_label label, enum hh_vm_names name, entry->state = HH_IRQ_STATE_WAIT_RELEASE; spin_unlock_irqrestore(&hh_irq_lend_lock, flags); - return hh_rm_vm_irq_lend_notify(entry->vmid, hw_irq, label, + return hh_rm_vm_irq_lend_notify(entry->vmid, virq, label, &entry->virq_handle); } EXPORT_SYMBOL(hh_irq_lend); @@ -231,17 +241,18 @@ EXPORT_SYMBOL(hh_irq_wait_for_lend); /** * hh_irq_accept: Register to receive interrupts with a lent vIRQ * @label: vIRQ high-level label - * @hw_irq: HWIRQ# to associate vIRQ with. If don't care, use -1 + * @irq: Linux IRQ# to associate vIRQ with. If don't care, use -1 * - * If hw_irq is not -1, then returns 0 on success, <0 otherwise - * If hw_irq is -1, then returns the HWIRQ# that vIRQ was registered - * to or <0 for error. + * 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 * with hh_irq_release or another hh_irq_accept with same label. */ -int hh_irq_accept(enum hh_irq_label label, int hw_irq) +int hh_irq_accept(enum hh_irq_label label, int irq) { struct hh_irq_entry *entry; + const struct irq_data *irq_data; + int virq; if (label >= HH_IRQ_LABEL_MAX) return -EINVAL; @@ -251,7 +262,23 @@ int hh_irq_accept(enum hh_irq_label label, int hw_irq) if (entry->state != HH_IRQ_STATE_LENT) return -EINVAL; - return hh_rm_vm_irq_accept(entry->virq_handle, hw_irq); + if (irq != -1) { + irq_data = irq_get_irq_data(irq); + if (!irq_data) + return -EINVAL; + virq = irq_data->hwirq; + } else + virq = -1; + + virq = hh_rm_vm_irq_accept(entry->virq_handle, virq); + if (virq < 0) + return virq; + + if (irq == -1) + irq = hh_rm_virq_to_linux_irq(virq - 32, GIC_SPI, + IRQ_TYPE_LEVEL_HIGH); + + return irq; } EXPORT_SYMBOL(hh_irq_accept); diff --git a/drivers/virt/haven/hh_rm_core.c b/drivers/virt/haven/hh_rm_core.c index 511ba2403f80..d2a18c2d46e7 100644 --- a/drivers/virt/haven/hh_rm_core.c +++ b/drivers/virt/haven/hh_rm_core.c @@ -641,7 +641,7 @@ out: return ret; } -static int hh_rm_virq_to_linux_irq(u32 virq, u32 type, u32 trigger) +int hh_rm_virq_to_linux_irq(u32 virq, u32 type, u32 trigger) { struct irq_fwspec fwspec = {}; @@ -653,6 +653,7 @@ static int hh_rm_virq_to_linux_irq(u32 virq, u32 type, u32 trigger) return irq_create_fwspec_mapping(&fwspec); } +EXPORT_SYMBOL(hh_rm_virq_to_linux_irq); static int hh_rm_get_irq(struct hh_vm_get_hyp_res_resp_entry *res_entry) { diff --git a/drivers/virt/haven/hh_rm_drv_private.h b/drivers/virt/haven/hh_rm_drv_private.h index a59b551eebbd..36fa47c2f97e 100644 --- a/drivers/virt/haven/hh_rm_drv_private.h +++ b/drivers/virt/haven/hh_rm_drv_private.h @@ -8,6 +8,7 @@ #include +#include #include #include @@ -279,6 +280,7 @@ struct hh_mem_notify_req_payload { /* End Message ID headers */ /* Common function declerations */ +int hh_rm_virq_to_linux_irq(u32 virq, u32 type, u32 trigger); int hh_update_vm_prop_table(enum hh_vm_names vm_name, struct hh_vm_property *vm_prop); void *hh_rm_call(hh_rm_msgid_t message_id,