[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH 23/57] ARM: GIC: allow reading pending state of a hardware IRQ
Hi Andre, On 05/03/18 16:03, Andre Przywara wrote: To synchronize level triggered interrupts which are mapped into a guest, we need to update the virtual line level at certain points in time. For a hardware mapped interrupt the GIC is the only place where we can easily access this information. Implement a gic_hw_operations member to return the pending state of a particular interrupt. Due to hardware limitations this only works for private interrupts of the current CPU, so there is no CPU field in the prototype. Would it be worth adding a comment on top of the callback? This adds gicv2/3_peek_irq() helper functions, to read a bit in a bitmap spread over several MMIO registers. Signed-off-by: Andre Przywara <andre.przywara@xxxxxxxxxx> --- Changelog RFC ... v1: - add gicv2/3_peek_irq() helpers - use struct irq_desc* in the interface (instead of just the IRQ number) xen/arch/arm/gic-v2.c | 15 +++++++++++++++ xen/arch/arm/gic-v3.c | 19 +++++++++++++++++++ xen/arch/arm/gic.c | 5 +++++ xen/include/asm-arm/gic.h | 5 +++++ 4 files changed, 44 insertions(+) diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c index 74169b5633..48352f6499 100644 --- a/xen/arch/arm/gic-v2.c +++ b/xen/arch/arm/gic-v2.c @@ -241,6 +241,15 @@ static void gicv2_poke_irq(struct irq_desc *irqd, uint32_t offset) writel_gicd(1U << (irqd->irq % 32), offset + (irqd->irq / 32) * 4); }+static bool gicv2_peek_irq(struct irq_desc *irqd, uint32_t offset)+{ + uint32_t reg; + + reg = readl_gicd(offset + (irqd->irq / 32) * 4) & (1U << (irqd->irq % 32)); + + return reg; +} + static void gicv2_set_active_state(struct irq_desc *irqd, bool active) { ASSERT(spin_is_locked(&irqd->lock)); @@ -549,6 +558,11 @@ static unsigned int gicv2_read_apr(int apr_reg) return readl_gich(GICH_APR); }+static bool gicv2_read_pending_state(struct irq_desc *irqd)+{ + return gicv2_peek_irq(irqd, GICD_ISPENDR); +} + static void gicv2_irq_enable(struct irq_desc *desc) { unsigned long flags; @@ -1294,6 +1308,7 @@ const static struct gic_hw_operations gicv2_ops = { .write_lr = gicv2_write_lr, .read_vmcr_priority = gicv2_read_vmcr_priority, .read_apr = gicv2_read_apr, + .read_pending_state = gicv2_read_pending_state, .make_hwdom_dt_node = gicv2_make_hwdom_dt_node, .make_hwdom_madt = gicv2_make_hwdom_madt, .get_hwdom_extra_madt_size = gicv2_get_hwdom_extra_madt_size, diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index c96469f09d..3e75d06c3b 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -444,6 +444,19 @@ static void gicv3_poke_irq(struct irq_desc *irqd, u32 offset, bool wait_for_rwp) gicv3_wait_for_rwp(irqd->irq); }+static bool gicv3_peek_irq(struct irq_desc *irqd, u32 offset)+{ + void __iomem *base; + unsigned int irq = irqd->irq; + + if ( irq >= NR_GIC_LOCAL_IRQS) + base = GICD + (irq / 32) * 4; + else + base = GICD_RDIST_SGI_BASE; + + return !!(readl(base + offset) & (1U << (irq % 32))); +} + static void gicv3_unmask_irq(struct irq_desc *irqd) { gicv3_poke_irq(irqd, GICD_ISENABLER, false); @@ -1094,6 +1107,11 @@ static unsigned int gicv3_read_apr(int apr_reg) } }+static bool gicv3_read_pending_state(struct irq_desc *irqd)+{ + return gicv3_peek_irq(irqd, GICD_ISPENDR); +} + static void gicv3_irq_enable(struct irq_desc *desc) { unsigned long flags; @@ -1762,6 +1780,7 @@ static const struct gic_hw_operations gicv3_ops = { .write_lr = gicv3_write_lr, .read_vmcr_priority = gicv3_read_vmcr_priority, .read_apr = gicv3_read_apr, + .read_pending_state = gicv3_read_pending_state, .secondary_init = gicv3_secondary_cpu_init, .make_hwdom_dt_node = gicv3_make_hwdom_dt_node, .make_hwdom_madt = gicv3_make_hwdom_madt, diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index f1329a630a..67c3b4d86d 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -116,6 +116,11 @@ static void gic_set_irq_priority(struct irq_desc *desc, unsigned int priority) gic_hw_ops->set_irq_priority(desc, priority); }+bool gic_read_pending_state(struct irq_desc *irqd)+{ + return gic_hw_ops->read_pending_state(irqd); +} How about providing a static inline helper in gic.h? + /* Program the GIC to route an interrupt to the host (i.e. Xen) * - needs to be called with desc.lock held */ diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index 46dcb0fe7c..03667f00cf 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -248,6 +248,9 @@ void gic_set_pending_state(struct irq_desc *irqd, bool state); /* Program the IRQ type into the GIC */ void gic_set_irq_type(struct irq_desc *desc, unsigned int type);+/* Read the pending state of an interrupt from the distributor. */+bool gic_read_pending_state(struct irq_desc *irqd); + /* Program the GIC to route an interrupt */ extern void gic_route_irq_to_xen(struct irq_desc *desc, unsigned int priority); extern int gic_route_irq_to_guest(struct domain *, unsigned int virq, @@ -382,6 +385,8 @@ struct gic_hw_operations { unsigned int (*read_vmcr_priority)(void); /* Read APRn register */ unsigned int (*read_apr)(int apr_reg); + /* Query the pending state of an interrupt at the distributor level. */ + bool (*read_pending_state)(struct irq_desc *irqd); /* Secondary CPU init */ int (*secondary_init)(void); /* Create GIC node for the hardware domain */ Cheers, -- Julien Grall _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |