[PATCH v2 31/39] xen/riscv: implement APLIC-hart sync barrier for vCPU migration
Oleksii Kurochko <[email protected]>
| Newsgroups | gmane.comp.emulators.xen.devel |
|---|---|
| Message-ID | <3d953b6e7f221f4cf4143454076466fab38b6236.1787838835.git.oleksii.kurochko@gmail.com> |
During migration of a virtual hart to a different guest interrupt file, straggler MSIs from the APLIC could arrive at the old interrupt file after the switch. genmsi is used despite not supporting guest interrupt files because the AIA spec guarantees that all MSIs previously sent from the APLIC to the same hart are visible at the hart's IMSIC before the extempore MSI from genmsi becomes visible. Signed-off-by: Oleksii Kurochko <[email protected]> --- Changes in v2: - New patch. --- --- xen/arch/riscv/aplic.c | 26 ++++++++++++++++++++++++++ xen/arch/riscv/imsic.c | 12 ++++++++++++ xen/arch/riscv/include/asm/aplic.h | 3 +++ xen/arch/riscv/include/asm/imsic.h | 8 ++++++++ 4 files changed, 49 insertions(+) diff --git a/xen/arch/riscv/aplic.c b/xen/arch/riscv/aplic.c index 0af13f28e467..cb11d6aeaaa9 100644 --- a/xen/arch/riscv/aplic.c +++ b/xen/arch/riscv/aplic.c @@ -27,7 +27,9 @@ #include <asm/imsic.h> #include <asm/intc.h> #include <asm/io.h> +#include <asm/processor.h> #include <asm/riscv_encoding.h> +#include <asm/smp.h> static struct aplic_priv aplic = { .lock = SPIN_LOCK_UNLOCKED, @@ -205,6 +207,30 @@ void aplic_hw_write_reg(unsigned int offset, uint32_t value) spin_unlock_irqrestore(&aplic.lock, flags); } +/* + * As needed, synchronize with all IOMMUs and APLICs to ensure that no + * straggler MSIs will arrive at the old interrupt file after this step. + */ +void aplic_genmsi_barrier(void) +{ + const struct imsic_config *imsic = imsic_get_config(); + unsigned int cpu = smp_processor_id(); + unsigned long flags; + uint32_t val; + + val = MASK_INSR(aplic_hart_field(cpu), APLIC_TARGET_HART_IDX) | + (imsic->sync_id & APLIC_TARGET_EIID); + + spin_lock_irqsave(&aplic.lock, flags); + + writel(val, &aplic.regs->genmsi); + + while ( readl(&aplic.regs->genmsi) & APLIC_GENMSI_BUSY ) + cpu_relax(); + + spin_unlock_irqrestore(&aplic.lock, flags); +} + static void __init aplic_init_hw_interrupts(void) { unsigned int i; diff --git a/xen/arch/riscv/imsic.c b/xen/arch/riscv/imsic.c index 516f0105352a..5de45949610d 100644 --- a/xen/arch/riscv/imsic.c +++ b/xen/arch/riscv/imsic.c @@ -195,6 +195,15 @@ void imsic_irq_enable(unsigned int irq) */ ASSERT(!local_irq_is_enabled()); + if ( irq == imsic_cfg.sync_id ) + { + printk(XENLOG_WARNING + "irq%u is reserved for APLIC sync so shouldn't be set by %s\n", + irq, __func__); + + return; + } + spin_lock(&imsic_cfg.lock); /* * There is no irq - 1 here (look at aplic_set_irq_type()) because: @@ -377,6 +386,9 @@ static int __init imsic_parse_node(const struct dt_device_node *node, return -ENOENT; } + /* Reserve last identity for APLIC-to-hart synchronization */ + imsic_cfg.sync_id = imsic_cfg.nr_ids; + /* Compute base address */ *nr_mmios = 0; rc = dt_device_get_address(node, *nr_mmios, &base_addr, NULL); diff --git a/xen/arch/riscv/include/asm/aplic.h b/xen/arch/riscv/include/asm/aplic.h index 8564f5954b6b..e4f4dfd241cc 100644 --- a/xen/arch/riscv/include/asm/aplic.h +++ b/xen/arch/riscv/include/asm/aplic.h @@ -88,6 +88,7 @@ #define APLIC_SETIPNUM_LE 0x2000 #define APLIC_GENMSI 0x3000 +#define APLIC_GENMSI_BUSY BIT(12, U) #define APLIC_TARGET_BASE 0x3004 #define APLIC_TARGET_LAST 0x3ffc @@ -178,4 +179,6 @@ void aplic_reconfigure_target(const struct vcpu *v, unsigned int old_guest_file_id, unsigned int old_cpu); +void aplic_genmsi_barrier(void); + #endif /* ASM_RISCV_APLIC_H */ diff --git a/xen/arch/riscv/include/asm/imsic.h b/xen/arch/riscv/include/asm/imsic.h index 57d8c729ac0d..6ea2e4b8ca12 100644 --- a/xen/arch/riscv/include/asm/imsic.h +++ b/xen/arch/riscv/include/asm/imsic.h @@ -68,6 +68,14 @@ struct imsic_config { /* Number off interrupt identities */ unsigned int nr_ids; + /* + * Interrupt identity reserved exclusively for APLIC-to-hart + * synchronization. + * + * Must not be allocated to any interrupt source. + */ + unsigned int sync_id; + /* MSI */ const struct imsic_msi *msi; -- 2.55.0