[PATCH 1/2] irqchip/sifive-plic: Fix duplicate mask/unmask for claim/complete

Guo Ren guoren at kernel.org
Tue Oct 19 05:08:25 PDT 2021


On Tue, Oct 12, 2021 at 11:37 AM Anup Patel <anup at brainfault.org> wrote:
>
> On Tue, Oct 12, 2021 at 6:52 AM Guo Ren <guoren at kernel.org> wrote:
> >
> > On Mon, Oct 11, 2021 at 11:02 PM Anup Patel <anup at brainfault.org> wrote:
> > >
> > > On Mon, Oct 11, 2021 at 6:54 PM <guoren at kernel.org> wrote:
> > > >
> > > > From: Guo Ren <guoren at linux.alibaba.com>
> > > >
> > > > PLIC only has enable-registers not mask/unmask registers. Mixing
> > > > mask/unmask with irq_eoi is wrong, because readl(claim) could mask
> > >
> > > This is an incorrect assumption about readl(claim). When SW does
> > > read(claim) the HW updates internal state that IRQ has been claimed.
> > > The HW can still get same (already claimed) IRQ again before
> > > writel(claim) which will be delivered after writel(claim).
> > Our hw would mask IRQ with readl(claim), so it's unnecessary for our
> > board. I agree some hardware won't mask IRQ after readl(claim), so I
> > put DT-bool to control it.
>
> Clearly, the PLIC on C9xx does not comply with RISC-V PLIC because
> it is violating the "Interrupt Claim Process" and "Interrupt Completion
> Process" defined by the RISC-V PLIC specification.
> (Refer, https://github.com/riscv/riscv-plic-spec/blob/master/riscv-plic.adoc)
10. Interrupt Completion
The PLIC signals it has completed executing an interrupt handler by
writing the interrupt ID it received from the claim to the
claim/complete register. The PLIC does not check whether the
completion ID is the same as the last claim ID for that target. If the
completion ID does not match an interrupt source that is *currently
enabled* for the target, the completion is silently *ignored*.

How do you think about *currently enabled* & *silently ignored*?


>
> I would suggest you to have a separate compatible string
> "thead,c9xx-plic" for C9xx PLIC implementation.
>
> >
> > >
> > > > irq by hardware. We only need mask/unmask to fixup the hardware
> > > > which couldn't claim + mask correctly.
> > >
> > > The handle_fasteoi_irq() only calls unmask_irq() mostly when the
> > > underlying IRQ is threaded. Is there any other case ?
> > When in handle_fasteoi_irq ONESHOT path, it will call:
> >         if (desc->istate & IRQS_ONESHOT)
> >                 mask_irq(desc);
> >
> > mask_irq->plic_irq_mask->"write 0 to PRIORITY & ENABLE_BASE-bit"
> >
> > In this IRQ context, it wouldn't call unmask_irq with
> > cond_unmask_eoi_irq when in IRQCHIP_EOI_THREADED. Then the path would
> > writel(hwirq, claim) with irq disabled.
> > static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip)
> > {
> > ...
> >         } else if (!(chip->flags & IRQCHIP_EOI_THREADED)) {
> >                 chip->irq_eoi(&desc->irq_data);
> >         }
> >
> > When IRQ is disabled in c9xx, writel(hwirq, claim) would be invalid
> > and cause a blocking irq bug.
>
> Like mentioned above, this is not inline with RISC-V PLIC. You
> should call it C9xx PLIC.
>
> >
> > >
> > > Another fact is that all irqchip drivers using handle_fasteoi_irq()
> > > implement irq_mask/unmask().
> > C9xx needn't call mask&unmask after readl(claim), because:
> > 1. If hw supports readl(claim) with acquiring irq then the mask/unmask
> > is unnecessary and causes performance problems.
> > 2. When in IRQS_ONESHOT & IRQCHIP_EOI_THREADED path, unnecessary mask
> > operation would cause a blocking irq bug.
>
> I would suggest the following:
>
> 1) Add a separate compatible string "thead,c9xx-plic" for your PLIC
> implementation.
>
> 2) In plic_init() when DT node is compatible to "thead,c9xx-plic",
> you should set irq_mask/unmask of "plic_chip" to NULL and point
> irq_enable/disable of "plic_chip" to plic_irq_mask/unmask.
>
> 3) Add a detailed comment block in plic_init() about the differences
> in Claim/Completion process of RISC-V PLIC and C9xx PLIC.
>
> Regards,
> Anup
>
> >
> > >
> > > Regards,
> > > Anup
> > >
> > > >
> > > > If hardware supports claim + mask, it would cause unnecessary
> > > > mask/umak operations.
> > > >
> > > > Signed-off-by: Guo Ren <guoren at linux.alibaba.com>
> > > > Cc: Thomas Gleixner <tglx at linutronix.de>
> > > > Cc: Marc Zyngier <maz at kernel.org>
> > > > Cc: Palmer Dabbelt <palmer at dabbelt.com>
> > > > Cc: Anup Patel <anup at brainfault.org>
> > > > Cc: Atish Patra <atish.patra at wdc.com>
> > > > ---
> > > >  drivers/irqchip/irq-sifive-plic.c | 16 ++++++++++++----
> > > >  1 file changed, 12 insertions(+), 4 deletions(-)
> > > >
> > > > diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
> > > > index cf74cfa82045..0fa46912f452 100644
> > > > --- a/drivers/irqchip/irq-sifive-plic.c
> > > > +++ b/drivers/irqchip/irq-sifive-plic.c
> > > > @@ -64,6 +64,7 @@ struct plic_priv {
> > > >         struct cpumask lmask;
> > > >         struct irq_domain *irqdomain;
> > > >         void __iomem *regs;
> > > > +       bool claim_mask_support;
> > > >  };
> > > >
> > > >  struct plic_handler {
> > > > @@ -111,7 +112,7 @@ static inline void plic_irq_toggle(const struct cpumask *mask,
> > > >         }
> > > >  }
> > > >
> > > > -static void plic_irq_unmask(struct irq_data *d)
> > > > +static void plic_irq_enable(struct irq_data *d)
> > > >  {
> > > >         struct cpumask amask;
> > > >         unsigned int cpu;
> > > > @@ -125,7 +126,7 @@ static void plic_irq_unmask(struct irq_data *d)
> > > >         plic_irq_toggle(cpumask_of(cpu), d, 1);
> > > >  }
> > > >
> > > > -static void plic_irq_mask(struct irq_data *d)
> > > > +static void plic_irq_disable(struct irq_data *d)
> > > >  {
> > > >         struct plic_priv *priv = irq_data_get_irq_chip_data(d);
> > > >
> > > > @@ -168,8 +169,8 @@ static void plic_irq_eoi(struct irq_data *d)
> > > >
> > > >  static struct irq_chip plic_chip = {
> > > >         .name           = "SiFive PLIC",
> > > > -       .irq_mask       = plic_irq_mask,
> > > > -       .irq_unmask     = plic_irq_unmask,
> > > > +       .irq_enable     = plic_irq_enable,
> > > > +       .irq_disable    = plic_irq_disable,
> > > >         .irq_eoi        = plic_irq_eoi,
> > > >  #ifdef CONFIG_SMP
> > > >         .irq_set_affinity = plic_set_affinity,
> > > > @@ -181,6 +182,11 @@ static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq,
> > > >  {
> > > >         struct plic_priv *priv = d->host_data;
> > > >
> > > > +       if (!priv->claim_mask_support) {
> > > > +               plic_chip.irq_mask      = plic_irq_disable;
> > > > +               plic_chip.irq_unmask    = plic_irq_enable;
> > > > +       }
> > > > +
> > > >         irq_domain_set_info(d, irq, hwirq, &plic_chip, d->host_data,
> > > >                             handle_fasteoi_irq, NULL, NULL);
> > > >         irq_set_noprobe(irq);
> > > > @@ -298,6 +304,8 @@ static int __init plic_init(struct device_node *node,
> > > >         if (WARN_ON(!nr_contexts))
> > > >                 goto out_iounmap;
> > > >
> > > > +       priv->claim_mask_support = of_property_read_bool(node, "claim-mask-support");
> > > > +
> > > >         error = -ENOMEM;
> > > >         priv->irqdomain = irq_domain_add_linear(node, nr_irqs + 1,
> > > >                         &plic_irqdomain_ops, priv);
> > > > --
> > > > 2.25.1
> > > >
> >
> >
> >
> > --
> > Best Regards
> >  Guo Ren
> >
> > ML: https://lore.kernel.org/linux-csky/



-- 
Best Regards
 Guo Ren

ML: https://lore.kernel.org/linux-csky/



More information about the linux-riscv mailing list