On Wed, Feb 12, 2020 at 10:57:09AM +0800, Zenghui Yu wrote:
> Hi Drew,
>
> On 2020/2/11 23:41, Andrew Jones wrote:
> > On Tue, Feb 11, 2020 at 10:50:58PM +0800, Zenghui Yu wrote:
> > > Hi Drew,
> > >
> > > On 2020/2/11 21:37, Andrew Jones wrote:
> > > > Let's bail out of the wait loop if we see the expected state
> > > > to save over six seconds of run time. Make sure we wait a bit
> > > > before reading the registers and double check again after,
> > > > though, to somewhat mitigate the chance of seeing the expected
> > > > state by accident.
> > > >
> > > > We also take this opportunity to push more IRQ state code to
> > > > the library.
> > > >
> > > > Signed-off-by: Andrew Jones <[email protected]>
> > >
> > > [...]
> > >
> > > > +
> > > > +enum gic_irq_state gic_irq_state(int irq)
> > >
> > > This is a *generic* name while this function only deals with PPI.
> > > Maybe we can use something like gic_ppi_state() instead? Or you
> > > will have to take all interrupt types into account in a single
> > > function, which is not a easy job I think.
> >
> > Very good point.
> >
> > >
> > > > +{
> > > > + enum gic_irq_state state;
> > > > + bool pending = false, active = false;
> > > > + void *base;
> > > > +
> > > > + assert(gic_common_ops);
> > > > +
> > > > + switch (gic_version()) {
> > > > + case 2:
> > > > + base = gicv2_dist_base();
> > > > + pending = readl(base + GICD_ISPENDR) & (1 << PPI(irq));
> > > > + active = readl(base + GICD_ISACTIVER) & (1 << PPI(irq));
> > > > + break;
> > > > + case 3:
> > > > + base = gicv3_sgi_base();
> > > > + pending = readl(base + GICR_ISPENDR0) & (1 << PPI(irq));
> > > > + active = readl(base + GICR_ISACTIVER0) & (1 <<
> > > > PPI(irq));
> > >
> > > And you may also want to ensure that the 'irq' is valid for PPI().
> > > Or personally, I'd just use a real PPI number (PPI(info->irq)) as
> > > the input parameter of this function.
> >
> > Indeed, if we want to make this a general function we should require
> > the caller to pass PPI(irq).
> >
> > >
> > > > + break;
> > > > + }
> > > > +
> > > > + if (!active && !pending)
> > > > + state = GIC_IRQ_STATE_INACTIVE;
> > > > + if (pending)
> > > > + state = GIC_IRQ_STATE_PENDING;
> > > > + if (active)
> > > > + state = GIC_IRQ_STATE_ACTIVE;
> > > > + if (active && pending)
> > > > + state = GIC_IRQ_STATE_ACTIVE_PENDING;
> > > > +
> > > > + return state;
> > > > +}
> > > >
> > >
> > > Otherwise,
> > >
> > > Reviewed-by: Zenghui Yu <[email protected]>
> > > Tested-by: Zenghui Yu <[email protected]>
> >
> > Thanks, but I guess I should squash in changes to make this function more
> > general. My GIC/SPI skills are weak, so I'm not sure this is right,
> > especially because the SPI stuff doesn't yet have a user to validate it.
>
> (I guess the PL031 can be another new user.)
>
> > However, if all reviewers think it's correct, then I'll squash it into
> > the arm/queue branch. I've added Andre and Eric to help review too.
> >
> > Thanks,
> > drew
> >
> >
> > diff --git a/arm/timer.c b/arm/timer.c
> > index ae5fdbf54b35..44621b4f2967 100644
> > --- a/arm/timer.c
> > +++ b/arm/timer.c
> > @@ -189,9 +189,9 @@ static bool gic_timer_check_state(struct timer_info
> > *info,
> > /* Wait for up to 1s for the GIC to sample the interrupt. */
> > for (i = 0; i < 10; i++) {
> > mdelay(100);
> > - if (gic_irq_state(info->irq) == expected_state) {
> > + if (gic_irq_state(PPI(info->irq)) == expected_state) {
> > mdelay(100);
> > - if (gic_irq_state(info->irq) == expected_state)
> > + if (gic_irq_state(PPI(info->irq)) == expected_state)
> > return true;
> > }
> > }
> > diff --git a/lib/arm/gic.c b/lib/arm/gic.c
> > index 0563b31132c8..3924dd1d1ee6 100644
> > --- a/lib/arm/gic.c
> > +++ b/lib/arm/gic.c
> > @@ -150,22 +150,37 @@ void gic_ipi_send_mask(int irq, const cpumask_t *dest)
> > enum gic_irq_state gic_irq_state(int irq)
> > {
> > enum gic_irq_state state;
> > - bool pending = false, active = false;
> > - void *base;
> > + void *ispendr, *isactiver;
> > + bool pending, active;
> > assert(gic_common_ops);
>
> We can also assert that only interrupts with ID smaller than 1020
> will be handled.
Good idea
>
> > switch (gic_version()) {
> > case 2:
> > - base = gicv2_dist_base();
> > - pending = readl(base + GICD_ISPENDR) & (1 << PPI(irq));
> > - active = readl(base + GICD_ISACTIVER) & (1 << PPI(irq));
> > + ispendr = gicv2_dist_base() + GICD_ISPENDR;
> > + isactiver = gicv2_dist_base() + GICD_ISACTIVER;
> > break;
> > case 3:
> > - base = gicv3_sgi_base();
> > - pending = readl(base + GICR_ISPENDR0) & (1 << PPI(irq));
> > - active = readl(base + GICR_ISACTIVER0) & (1 << PPI(irq));
> > + if (irq < GIC_NR_PRIVATE_IRQS) {
> > + ispendr = gicv3_sgi_base() + GICR_ISPENDR0;
> > + isactiver = gicv3_sgi_base() + GICR_ISACTIVER0;
> > + } else {
> > + ispendr = gicv3_dist_base() + GICD_ISPENDR;
> > + isactiver = gicv3_dist_base() + GICD_ISACTIVER;
> > + }
> > break;
> > + default:
> > + assert(0);
> > + }
> > +
> > + if (irq < GIC_NR_PRIVATE_IRQS) {
> > + pending = readl(ispendr) & (1 << irq);
> > + active = readl(isactiver) & (1 << irq);
> > + } else {
> > + int offset = (irq - GIC_FIRST_SPI) / 32;
> > + int mask = 1 << ((irq - GIC_FIRST_SPI) % 32);
>
> No need to minus GIC_FIRST_SPI. And therefore these two cases
> can actually be merged.
Yup, will do
>
> > + pending = readl(ispendr + offset) & mask;
> > + active = readl(isactiver + offset) & mask;
> > }
> > if (!active && !pending)
>
> Otherwise this looks good enough (to me) for now, and let's wait
> other reviewers to comment. I've used the following diff to give
> the pl031 test a go (roughly written, not dig into PL031 so much),
> it just works fine :)
>
>
> Thanks,
> Zenghui
>
> diff --git a/arm/pl031.c b/arm/pl031.c
> index 86035fa..2d4160f 100644
> --- a/arm/pl031.c
> +++ b/arm/pl031.c
> @@ -118,11 +118,12 @@ static int check_rtc_freq(void)
> return 0;
> }
>
> -static bool gic_irq_pending(void)
> +static bool gic_pl031_pending(void)
> {
> - uint32_t offset = (pl031_irq / 32) * 4;
> + enum gic_irq_state state = gic_irq_state(pl031_irq);
>
> - return readl(gic_ispendr + offset) & (1 << (pl031_irq & 31));
> + return state == GIC_IRQ_STATE_PENDING ||
> + state == GIC_IRQ_STATE_ACTIVE_PENDING;
Nice way to test, but I'll leave this change out.
> }
>
> static void gic_irq_unmask(void)
>
> [...]
> /* replace all gic_irq_pending() with gic_pl031_pending() */
> [...]
>
> diff --git a/lib/arm/gic.c b/lib/arm/gic.c
> index 3924dd1..34d77e3 100644
> --- a/lib/arm/gic.c
> +++ b/lib/arm/gic.c
> @@ -152,6 +152,7 @@ enum gic_irq_state gic_irq_state(int irq)
> enum gic_irq_state state;
> void *ispendr, *isactiver;
> bool pending, active;
> + int offset, mask;
>
> assert(gic_common_ops);
>
> @@ -173,15 +174,10 @@ enum gic_irq_state gic_irq_state(int irq)
> assert(0);
> }
>
> - if (irq < GIC_NR_PRIVATE_IRQS) {
> - pending = readl(ispendr) & (1 << irq);
> - active = readl(isactiver) & (1 << irq);
> - } else {
> - int offset = (irq - GIC_FIRST_SPI) / 32;
> - int mask = 1 << ((irq - GIC_FIRST_SPI) % 32);
> - pending = readl(ispendr + offset) & mask;
> - active = readl(isactiver + offset) & mask;
> - }
> + offset = (irq / 32) * 4;
> + mask = 1 << (irq % 32);
> + pending = readl(ispendr + offset) & mask;
> + active = readl(isactiver + offset) & mask;
>
> if (!active && !pending)
> state = GIC_IRQ_STATE_INACTIVE;
>
I'll send a final patch now for review, but I'm pretty happy with this so
I've gone ahead and squashed it into arm/queue already. I kept Alex's
r-b as there shouldn't be any functional change with respect to what
he reviewed.
Thanks,
drew
_______________________________________________
kvmarm mailing list
[email protected]
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm