Message ID | 20180209143937.28866-17-andre.przywara@linaro.org |
---|---|
State | New |
Headers | show |
Series | New VGIC(-v2) implementation | expand |
Hi Andre, On 09/02/18 14:39, 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 not CPU field in the > prototype. > > Signed-off-by: Andre Przywara <andre.przywara@linaro.org> > --- > xen/arch/arm/gic-v2.c | 6 ++++++ > xen/arch/arm/gic-v3.c | 13 +++++++++++++ > xen/arch/arm/gic.c | 5 +++++ > xen/include/asm-arm/gic.h | 5 +++++ > 4 files changed, 29 insertions(+) > > diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c > index 5339f69fbc..30081640ac 100644 > --- a/xen/arch/arm/gic-v2.c > +++ b/xen/arch/arm/gic-v2.c > @@ -514,6 +514,11 @@ static unsigned int gicv2_read_apr(int apr_reg) > return readl_gich(GICH_APR); > } > > +bool gicv2_read_pending_state(int irq) static Also, I would like to see the irq turned into irq_desc to match the other interface. > +{ > + return readl_gicd(GICD_ISPENDR + (irq / 32) * 4) & (1U << (irq % 32)); See my remark in the previous patch. You might want to introduce an helper peek. > +} > + > static void gicv2_irq_enable(struct irq_desc *desc) > { > unsigned long flags; > @@ -1261,6 +1266,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 595eaef43a..2cbfeb8e03 100644 > --- a/xen/arch/arm/gic-v3.c > +++ b/xen/arch/arm/gic-v3.c > @@ -1081,6 +1081,18 @@ static unsigned int gicv3_read_apr(int apr_reg) > } > } > > +static bool gicv3_read_pending_state(int irq) > +{ > + void __iomem *base; > + > + if ( irq >= NR_GIC_LOCAL_IRQS) > + base = GICD + (irq / 32) * 4; > + else > + base = GICD_RDIST_SGI_BASE; > + > + return readl(base + GICD_ISPENDR) & (1U << (irq % 32)); Looking at the GICv3 code we don't have a peek helper. It is probably worth to add one. > +} > + > static void gicv3_irq_enable(struct irq_desc *desc) > { > unsigned long flags; > @@ -1749,6 +1761,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 dfc2108c4d..ce9ab2367e 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(int irq) > +{ > + return gic_hw_ops->read_pending_state(irq); > +} > + > /* 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 d330860580..d7fd18fd47 100644 > --- a/xen/include/asm-arm/gic.h > +++ b/xen/include/asm-arm/gic.h > @@ -244,6 +244,9 @@ void gic_set_active_state(int irq, 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(int irq); > + > /* 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, > @@ -376,6 +379,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)(int irq); > /* Secondary CPU init */ > int (*secondary_init)(void); > /* Create GIC node for the hardware domain */ > Cheers,
diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c index 5339f69fbc..30081640ac 100644 --- a/xen/arch/arm/gic-v2.c +++ b/xen/arch/arm/gic-v2.c @@ -514,6 +514,11 @@ static unsigned int gicv2_read_apr(int apr_reg) return readl_gich(GICH_APR); } +bool gicv2_read_pending_state(int irq) +{ + return readl_gicd(GICD_ISPENDR + (irq / 32) * 4) & (1U << (irq % 32)); +} + static void gicv2_irq_enable(struct irq_desc *desc) { unsigned long flags; @@ -1261,6 +1266,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 595eaef43a..2cbfeb8e03 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -1081,6 +1081,18 @@ static unsigned int gicv3_read_apr(int apr_reg) } } +static bool gicv3_read_pending_state(int irq) +{ + void __iomem *base; + + if ( irq >= NR_GIC_LOCAL_IRQS) + base = GICD + (irq / 32) * 4; + else + base = GICD_RDIST_SGI_BASE; + + return readl(base + GICD_ISPENDR) & (1U << (irq % 32)); +} + static void gicv3_irq_enable(struct irq_desc *desc) { unsigned long flags; @@ -1749,6 +1761,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 dfc2108c4d..ce9ab2367e 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(int irq) +{ + return gic_hw_ops->read_pending_state(irq); +} + /* 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 d330860580..d7fd18fd47 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -244,6 +244,9 @@ void gic_set_active_state(int irq, 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(int irq); + /* 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, @@ -376,6 +379,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)(int irq); /* Secondary CPU init */ int (*secondary_init)(void); /* Create GIC node for the hardware domain */
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 not CPU field in the prototype. Signed-off-by: Andre Przywara <andre.przywara@linaro.org> --- xen/arch/arm/gic-v2.c | 6 ++++++ xen/arch/arm/gic-v3.c | 13 +++++++++++++ xen/arch/arm/gic.c | 5 +++++ xen/include/asm-arm/gic.h | 5 +++++ 4 files changed, 29 insertions(+)