Re: [PATCH] gpio-dwapb: reset mask register on probe

From: Alexey Brodkin
Date: Mon Mar 09 2015 - 16:56:17 EST


Hi Linus,

On Mon, 2015-03-09 at 14:59 +-0100, Linus Walleij wrote:
+AD4- On Tue, Mar 3, 2015 at 9:47 AM, Alexey Brodkin
+AD4- +ADw-Alexey.Brodkin+AEA-synopsys.com+AD4- wrote:

+AD4- +AD4- +-+-+- b/drivers/gpio/gpio-dwapb.c
+AD4- +AD4- +AEAAQA- -370,6 +-370,9 +AEAAQA- static void dwapb+AF8-configure+AF8-irqs(struct dwapb+AF8-gpio +ACo-gpio,
+AD4- +AD4- irq+AF8-create+AF8-mapping(gpio-+AD4-domain, hwirq)+ADs-
+AD4- +AD4-
+AD4- +AD4- port-+AD4-bgc.gc.to+AF8-irq +AD0- dwapb+AF8-gpio+AF8-to+AF8-irq+ADs-
+AD4- +AD4- +-
+AD4- +AD4- +- /+ACo- Reset mask register +ACo-/
+AD4- +AD4- +- dwapb+AF8-write(gpio, GPIO+AF8-INTMASK, 0)+ADs-
+AD4-
+AD4- I don't get this. This looks like you just enable all interrupts. The
+AD4- driver also contains this in .suspend():

DW APB GPIO has 2 separate registers related to interrupts:

+AFs-1+AF0- Mask interrupt register
+AFs-2+AF0- Enable interrupt register

So what I do in my patch I unmask all interrupts. But before at least
one interrupt is enabled output interrupt line will never get in active
state. And by default all interrupts are disabled (reset value +AD0- 0).

+AD4- /+ACo- Mask out interrupts +ACo-/
+AD4- dwapb+AF8-write(gpio, GPIO+AF8-INTMASK, 0xffffffff)+ADs-
+AD4-
+AD4- If +ACo-anything+ACo- the probe should +ACo-mask+ACo- all interrupts so that the
+AD4- .unmask() callback can enable them selectively.

I'm going to agree with this statement, but this requires a bit more
significant change in driver. I just wanted to fix an issue I discovered
on my setup.

Interestingly what I observed in my testing that if both
enable()/disable() and mask()/unmask() are implemented in driver then
only enable()/disable() pair will be actually used.

Look at how generic irq+AF8-enable() function is implemented -
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/kernel/irq/chip.c+ACM-n208

---+AD4-8---
void irq+AF8-enable(struct irq+AF8-desc +ACo-desc)
+AHs-
irq+AF8-state+AF8-clr+AF8-disabled(desc)+ADs-
if (desc-+AD4-irq+AF8-data.chip-+AD4-irq+AF8-enable)
desc-+AD4-irq+AF8-data.chip-+AD4-irq+AF8-enable(+ACY-desc-+AD4-irq+AF8-data)+ADs-
else
desc-+AD4-irq+AF8-data.chip-+AD4-irq+AF8-unmask(+ACY-desc-+AD4-irq+AF8-data)+ADs-
irq+AF8-state+AF8-clr+AF8-masked(desc)+ADs-
+AH0-
---+AD4-8---

+AD4- The real problem I think is that struct irq+AF8-chip contains
+AD4- mask()/unmask() callbacks that are not implemented
+AD4- by this driver.

I'd say that mask()/unmask() callbacks are implemented in this driver
already.

See
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/gpio/gpio-dwapb.c+ACM-n334
---+AD4-8---
ct-+AD4-chip.irq+AF8-mask +AD0- irq+AF8-gc+AF8-mask+AF8-set+AF8-bit+ADs-
ct-+AD4-chip.irq+AF8-unmask +AD0- irq+AF8-gc+AF8-mask+AF8-clr+AF8-bit+ADs-
ct-+AD4-chip.irq+AF8-set+AF8-type +AD0- dwapb+AF8-irq+AF8-set+AF8-type+ADs-
ct-+AD4-chip.irq+AF8-enable +AD0- dwapb+AF8-irq+AF8-enable+ADs-
ct-+AD4-chip.irq+AF8-disable +AD0- dwapb+AF8-irq+AF8-disable+ADs-
---+AD4-8---

It actually uses generic implementation of mask set bit and clear bit:
irq+AF8-gc+AF8-mask+AF8-set+AF8-bit()/irq+AF8-gc+AF8-mask+AF8-clr+AF8-bit() that operate under
GPIO+AF8-INTMASK register. And I may confirm that these functions correctly
set/reset bits in mask register of GPIO controller.


+AD4- Can you please test the below (untested) patch instead:
+AD4-
+AD4- From: Linus Walleij +ADw-linus.walleij+AEA-linaro.org+AD4-
+AD4- Date: Mon, 9 Mar 2015 14:56:18 +-0100
+AD4- Subject: +AFs-PATCH+AF0- RFC: gpio: dwapb: handle mask/unmask properly
+AD4-
+AD4- This implements the callbacks for masking/unmasking IRQs in the
+AD4- special IRQ mask/unmask register of the DWAPB GPIO block.
+AD4- Previously these mask bits were unhandled and relied on
+AD4- boot-up defaults.
+AD4-
+AD4- Reported-by: Alexey Brodkin +ADw-Alexey.Brodkin+AEA-synopsys.com+AD4-
+AD4- Signed-off-by: Linus Walleij +ADw-linus.walleij+AEA-linaro.org+AD4-
+AD4- ---
+AD4- drivers/gpio/gpio-dwapb.c +AHw- 30 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+AD4- 1 file changed, 30 insertions(+-)
+AD4-
+AD4- diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
+AD4- index 58faf04fce5d..1396f26bac5d 100644
+AD4- --- a/drivers/gpio/gpio-dwapb.c
+AD4- +-+-+- b/drivers/gpio/gpio-dwapb.c
+AD4- +AEAAQA- -158,6 +-158,30 +AEAAQA- static void dwapb+AF8-irq+AF8-handler(u32 irq, struct
+AD4- irq+AF8-desc +ACo-desc)
+AD4- chip-+AD4-irq+AF8-eoi(irq+AF8-desc+AF8-get+AF8-irq+AF8-data(desc))+ADs-
+AD4- +AH0-
+AD4-
+AD4- +-static void dwapb+AF8-irq+AF8-mask(struct irq+AF8-data +ACo-d)
+AD4- +-+AHs-
+AD4- +- struct irq+AF8-chip+AF8-generic +ACo-igc +AD0- irq+AF8-data+AF8-get+AF8-irq+AF8-chip+AF8-data(d)+ADs-
+AD4- +- struct dwapb+AF8-gpio +ACo-gpio +AD0- igc-+AD4-private+ADs-
+AD4- +-
+AD4- +- spin+AF8-lock+AF8-irqsave(+ACY-bgc-+AD4-lock, flags)+ADs-
+AD4- +- val +AD0- dwapb+AF8-read(gpio, GPIO+AF8-INTMASK)+ADs-
+AD4- +- val +AHwAPQ- BIT(d-+AD4-hwirq)+ADs-
+AD4- +- dwapb+AF8-write(gpio, GPIO+AF8-INTMASK, val)+ADs-
+AD4- +- spin+AF8-unlock+AF8-irqrestore(+ACY-bgc-+AD4-lock, flags)+ADs-
+AD4- +-+AH0-
+AD4- +-
+AD4- +-static void dwapb+AF8-irq+AF8-unmask(struct irq+AF8-data +ACo-d)
+AD4- +-+AHs-
+AD4- +- struct irq+AF8-chip+AF8-generic +ACo-igc +AD0- irq+AF8-data+AF8-get+AF8-irq+AF8-chip+AF8-data(d)+ADs-
+AD4- +- struct dwapb+AF8-gpio +ACo-gpio +AD0- igc-+AD4-private+ADs-
+AD4- +-
+AD4- +- spin+AF8-lock+AF8-irqsave(+ACY-bgc-+AD4-lock, flags)+ADs-
+AD4- +- val +AD0- dwapb+AF8-read(gpio, GPIO+AF8-INTMASK)+ADs-
+AD4- +- val +ACYAPQ- +AH4-BIT(d-+AD4-hwirq)+ADs-
+AD4- +- dwapb+AF8-write(gpio, GPIO+AF8-INTMASK, val)+ADs-
+AD4- +- spin+AF8-unlock+AF8-irqrestore(+ACY-bgc-+AD4-lock, flags)+ADs-
+AD4- +-+AH0-

Why would we need these custom functions if there're already
irq+AF8-gc+AF8-mask+AF8-set+AF8-bit()/irq+AF8-gc+AF8-mask+AF8-clr+AF8-bit() implemented in
kernel/irq/generic-chip.c

+AD4- static void dwapb+AF8-irq+AF8-enable(struct irq+AF8-data +ACo-d)
+AD4- +AHs-
+AD4- struct irq+AF8-chip+AF8-generic +ACo-igc +AD0- irq+AF8-data+AF8-get+AF8-irq+AF8-chip+AF8-data(d)+ADs-
+AD4- +AEAAQA- -302,6 +-326,10 +AEAAQA- static void dwapb+AF8-configure+AF8-irqs(struct dwapb+AF8-gpio +ACo-gpio,
+AD4- struct irq+AF8-chip+AF8-type +ACo-ct+ADs-
+AD4- int err, i+ADs-
+AD4-
+AD4- +- /+ACo- Mask out and disable all interrupts +ACo-/
+AD4- +- dwapb+AF8-write(gpio, GPIO+AF8-INTMASK, 0xffffffff)+ADs-
+AD4- +- dwapb+AF8-write(gpio, GPIO+AF8-INTEN, 0)+ADs-

This looks good to me - it's always a good idea to make sure defaults
are set as we expect.

+AD4- gpio-+AD4-domain +AD0- irq+AF8-domain+AF8-add+AF8-linear(node, ngpio,
+AD4- +ACY-irq+AF8-generic+AF8-chip+AF8-ops, gpio)+ADs-
+AD4- if (+ACE-gpio-+AD4-domain)
+AD4- +AEAAQA- -334,6 +-362,8 +AEAAQA- static void dwapb+AF8-configure+AF8-irqs(struct dwapb+AF8-gpio +ACo-gpio,
+AD4- ct-+AD4-chip.irq+AF8-mask +AD0- irq+AF8-gc+AF8-mask+AF8-set+AF8-bit+ADs-
+AD4- ct-+AD4-chip.irq+AF8-unmask +AD0- irq+AF8-gc+AF8-mask+AF8-clr+AF8-bit+ADs-
+AD4- ct-+AD4-chip.irq+AF8-set+AF8-type +AD0- dwapb+AF8-irq+AF8-set+AF8-type+ADs-
+AD4- +- ct-+AD4-chip.irq+AF8-mask +AD0- dwapb+AF8-irq+AF8-mask+ADs-
+AD4- +- ct-+AD4-chip.irq+AF8-unmask +AD0- dwapb+AF8-irq+AF8-unmask+ADs-

Looks like we set +ACI-ct-+AD4-chip.irq+AF8-mask+ACI- and +ACI-ct-+AD4-chip.irq+AF8-unmask+ACI- twice,
don't we?

-Alexey
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/