Re: [PATCH 08/14] irqchip: Add driver for WPCM450 interrupt controller

Jonathan Neuschäfer
2021-03-26T18:54:28Z

[-- Attachment #1.1: Type: text/plain, Size: 3546 bytes --]

On Wed, Mar 24, 2021 at 05:16:35PM +0000, Marc Zyngier wrote:
> On Sat, 20 Mar 2021 18:16:04 +0000,
> Jonathan Neuschäfer <j.neuschaefer@gmx.net> wrote:
> >
> > The WPCM450 AIC ("Advanced Interrupt Controller") is the interrupt
> > controller found in the Nuvoton WPCM450 SoC and other Winbond/Nuvoton
> > SoCs.
> >
> > The list of registers if based on the AMI vendor kernel and the
> > Nuvoton W90N745 datasheet.
> >
> > Although the hardware supports other interrupt modes, the driver only
> > supports high-level interrupts at the moment, because other modes could
> > not be tested so far.
> >
> > Signed-off-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net>
> > ---
[...]
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +// Copyright 2021 Jonathan Neuschäfer
> > +
> > +#include <linux/console.h>
>
> That's unexpected. Why do you need this?

I forgot about linux/printk.h.

> > +#define AIC_SCR_SRCTYPE_LOW_LEVEL (0 << 6)
> > +#define AIC_SCR_SRCTYPE_HIGH_LEVEL (1 << 6)
> > +#define AIC_SCR_SRCTYPE_NEG_EDGE (2 << 6)
> > +#define AIC_SCR_SRCTYPE_POS_EDGE (3 << 6)
> > +#define AIC_SCR_PRIORITY(x) (x)
>
> A mask would be welcomed for this field.

Ok, I'll add

+#define AIC_SCR_PRIORITY_MASK 0x7

Should I apply it in AIC_SCR_PRIORITY(x), too?

> > +
> > +#define IRQS 32
>
> Please use something a bit less generic.

Ok, I'll rename it to AIC_NUM_IRQS.

> > +static void wpcm450_aic_init_hw(void)
> > +{
> > + int i;
> > +
> > + /* Disable (mask) all interrupts */
> > + writel(0xffffffff, aic->regs + AIC_MDCR);
>
> Consider using relaxed accessors throughout this driver.

I'll read up on how to use them correctly.

> > +static void __exception_irq_entry wpcm450_aic_handle_irq(struct pt_regs *regs)
> > +{
> > + int hwirq;
> > +
> > + /* Determine the interrupt source */
> > + /* Read IPER to signal that nIRQ can be de-asserted */
> > + hwirq = readl(aic->regs + AIC_IPER) / 4;
> > +
> > + handle_domain_irq(aic->domain, hwirq, regs);
> > +}
> > +
> > +static void wpcm450_aic_ack(struct irq_data *d)
> > +{
> > + /* Signal end-of-service */
> > + writel(0, aic->regs + AIC_EOSCR);
>
> Is that an Ack or an EOI? My gut feeling is that the above read is the
> Ack, and that this write should actually be an EOI callback.

I agree that EOSCR (End of Service Command Register) matches the
description of EOI.

The reading IPER serves a dual purpose, as indicated above. I could
move the IPER read to a separate irq_ack function and use ISNR
(Interrupt source number register) in the IRQ handler instead. This
should work (haven't tested it yet), but I'm not sure it's strictly
better.

> > +static void wpcm450_aic_mask(struct irq_data *d)
> > +{
> > + unsigned int mask = 1U << d->hwirq;
>
> Consider using BIT().

Will do.

> > +static int wpcm450_aic_set_type(struct irq_data *d, unsigned int flow_type)
> > +{
> > + /*
> > + * The hardware supports high/low level, as well as rising/falling edge
> > + * modes, and the DT binding accommodates for that, but as long as
> > + * other modes than high level mode are not used and can't be tested,
> > + * they are rejected in this driver.
> > + */
> > + if ((flow_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_HIGH) {
> > + pr_err("IRQ mode %#x is not supported\n", flow_type);
>
> The core kernel shouts loudly enough, no need for extra messages.

Ok.

> Otherwise, looks good.
>
> M.

Thanks for your review!
Jonathan Neuschäfer

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]