|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v4 42/42] xen/riscv: drive the line of a virtual vAPLIC source
The line of a virtual vAPLIC source is driven by the emulator of a device in Xen, but nothing lets such an emulator do it yet: vaplic_source.level is never set. Introduce vintc_set_irq_level(), which an emulator calls whenever the level of its interrupt line changes, and implement it for vAPLIC as a new vintc_ops.set_irq_level callback. vAPLIC supports MSI delivery mode only, where, according to the AIA spec, a low-to-high transition of the rectified input value of a source makes it pending, whether it is edge- or level-sensitive, and the pending bit of a level-sensitive source is cleared whenever the value is low. A source made pending and enabled gets its MSI right away, through vaplic_forward_msis(). Signed-off-by: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx> --- All the patches connected to virtual interrupts support for vAPLIC/vIMSIC were tested on [1]. This branch is based on Denis M's framework which should be soon sent to ML. Note that in [1] RISC-V is only draft version and it has been ported in a quick way just to verify virtual interrupts are working. [1] https://gitlab.com/xen-project/people/olkur/xen/-/tree/riscv-vuart-support-wip?ref_type=heads --- Changes in v4: - New patch. --- --- xen/arch/riscv/include/asm/intc.h | 9 +++++ xen/arch/riscv/include/asm/vaplic.h | 8 ++--- xen/arch/riscv/intc.c | 14 ++++++++ xen/arch/riscv/vaplic.c | 51 +++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 5 deletions(-) diff --git a/xen/arch/riscv/include/asm/intc.h b/xen/arch/riscv/include/asm/intc.h index d188a45b3fe1..a332838bea17 100644 --- a/xen/arch/riscv/include/asm/intc.h +++ b/xen/arch/riscv/include/asm/intc.h @@ -8,6 +8,8 @@ #ifndef RISCV_INTC_H #define RISCV_INTC_H +#include <xen/types.h> + struct dt_device_node; enum intc_variant { @@ -79,6 +81,10 @@ struct vintc_ops { * guest. */ void (*enter_guest)(struct vcpu *v); + + /* Set the level of the line of a virtual source */ + void (*set_irq_level)(const struct domain *d, unsigned int virq, + bool level); }; struct vintc { @@ -114,4 +120,7 @@ void vintc_ctxt_switch_to(struct vcpu *n); void vintc_enter_guest(struct vcpu *v); +void vintc_set_irq_level(const struct domain *d, unsigned int virq, + bool level); + #endif /* RISCV_INTC_H */ diff --git a/xen/arch/riscv/include/asm/vaplic.h b/xen/arch/riscv/include/asm/vaplic.h index f2c768e84b11..1d5b9840be6c 100644 --- a/xen/arch/riscv/include/asm/vaplic.h +++ b/xen/arch/riscv/include/asm/vaplic.h @@ -41,11 +41,9 @@ struct vaplic_source { uint32_t sourcecfg; /* - * Level of the line of a virtual source, protected by vaplic->lock. - * - * TODO: nothing drives it yet. The emulator of a device with an interrupt - * line will have to, and to call vaplic_forward_msis() for a source a - * change of the level makes pending. + * Level of the line of a virtual source, as the emulator of the device + * in Xen drives it through vintc_set_irq_level(). Protected by + * vaplic->lock. */ bool level; }; diff --git a/xen/arch/riscv/intc.c b/xen/arch/riscv/intc.c index 449f6b252414..630c6d2ae730 100644 --- a/xen/arch/riscv/intc.c +++ b/xen/arch/riscv/intc.c @@ -224,3 +224,17 @@ void vintc_enter_guest(struct vcpu *v) if ( ops->enter_guest ) ops->enter_guest(v); } + +/* + * Set the level of the line of virtual source @virq of @d. To be used by the + * emulator of a device in Xen, the line of which is connected to @virq: such + * a source has to be reserved with vintc_reserve_virq(), and no h/w IRQ may be + * routed to it. + */ +void vintc_set_irq_level(const struct domain *d, unsigned int virq, + bool level) +{ + const struct vintc_ops *ops = d->arch.vintc->ops; + + ops->set_irq_level(d, virq, level); +} diff --git a/xen/arch/riscv/vaplic.c b/xen/arch/riscv/vaplic.c index ba0a867f6988..023f5116ec93 100644 --- a/xen/arch/riscv/vaplic.c +++ b/xen/arch/riscv/vaplic.c @@ -779,6 +779,56 @@ static void vaplic_ip_write(const struct domain *d, unsigned int word_idx, spin_unlock_irqrestore(&vaplic->lock, flags); } +/* + * Set the level of the line of virtual source @virq of @d, as the emulator of + * the device in Xen driving it does. + */ +static void cf_check vaplic_set_irq_level(const struct domain *d, + unsigned int virq, bool level) +{ + struct vaplic *vaplic = to_vaplic(d); + struct vaplic_source *src; + unsigned int word_idx; + unsigned long flags; + uint32_t bit; + bool was_high; + + /* Only a virtual source of @d has its line driven by an emulator. */ + if ( !vaplic_is_assigned(d, virq) || vaplic_is_hw_source(d, virq) ) + { + ASSERT_UNREACHABLE(); + return; + } + + virq = array_index_nospec(virq, d->arch.vintc->nr_virqs); + src = &vaplic->regs.sources[virq]; + word_idx = virq / IRQS_PER_WORD; + bit = BIT(virq % IRQS_PER_WORD, U); + + spin_lock_irqsave(&vaplic->lock, flags); + + was_high = vaplic_rectified_input(src); + src->level = level; + + /* + * According to the AIA spec, in MSI delivery mode a low-to-high + * transition of the rectified input value sets the pending bit of an + * edge- as well as of a level-sensitive source, and the pending bit of a + * level-sensitive one is cleared whenever the value is low. Neither + * happens to an inactive or a Detached source, whose rectified input + * value is always low. + */ + if ( !was_high && vaplic_rectified_input(src) ) + vaplic->regs.ip[word_idx] |= bit; + else if ( vaplic_is_level(src) && !vaplic_rectified_input(src) ) + vaplic->regs.ip[word_idx] &= ~bit; + + /* An enabled source the new level has made pending gets its MSI now. */ + vaplic_forward_msis(d, word_idx, bit); + + spin_unlock_irqrestore(&vaplic->lock, flags); +} + static uint32_t vaplic_genmsi_read(const struct domain *d) { /* @@ -1189,6 +1239,7 @@ static const struct vintc_ops vintc_ops = { * by the vCPU itself. It moves it on its way to the guest instead. */ .enter_guest = imsic_migrate_vcpu, + .set_irq_level = vaplic_set_irq_level, }; int domain_vaplic_init(struct domain *d) -- 2.56.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |