linux-riscv.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* PLIC and interrupts received while no hart enabled
@ 2021-07-04  6:41 Vincent Pelletier
  2021-07-10  2:00 ` [RFC PATCH] gpio: sifive: Take care of interrupt masking Vincent Pelletier
  2021-07-23  3:21 ` PLIC and interrupts received while no hart enabled Vincent Pelletier
  0 siblings, 2 replies; 3+ messages in thread
From: Vincent Pelletier @ 2021-07-04  6:41 UTC (permalink / raw)
  To: linux-riscv

[-- Attachment #1: Type: text/plain, Size: 6959 bytes --]

Hello,

I've recently purchased a sifive unmatched board, and have tried to
complete its devicetree using the schematics.

Doing so, I enabled some sub-functions of its PMIC chip (DA9063). Those
which matter for this email are:
- power button, notified by interrupt
- hwmon, based on an ADC which signals conversion completion with an
  interrupt

The PMIC has an interrupt line, active low, connected to line 1 of the
GPIO controller embedded in the board's SoC (fu740).
Internally to the SoC, the GPIO has one interrupt line per GPIO line,
connected to the PLIC.

The issue I originally had was, which I noticed with the ADC but could
equally reproduce with the power button, I could only ever get a single
IRQ to be processed.

Reading the corresponding registers (with the script attached),
enabling IRQ and regmap tracing, I saw the output at the end of this email.

Here is how I read the register states:
- initial state:
  The PMIC interrupt line is in its idle state (high).
  The GPIO controller noticed the high state, and armed the
  corresponding interrupt-pending bit - this an important first piece of
  information.
  As the corresponding interrupt-enable is cleared, no interrupt is
  signalled and the PLIC does not see an interrupt pending. This is all
  good.
- after one button press:
  The PMIC interrupt line is again in its idle state, so the interrupt
  source was cleared. I know it triggered as the power button input
  event does fire as intended.
  This time, the GPIO controller noticed 3 interrupt conditions on this
  line: low, rising edge, and high. This means it was cleared *before*
  the PMIC line went high:
  - if it was cleared after, only "high" should be visible
  - if is was never cleared, all low/rise/high/fall interrupt
    conditions would be present
  As the "low" interrupt is enabled, I believe (but cannot check) that
  it notified the PLIC of the interrupt.
  But like before, the PLIC does not see this interrupt being signalled.

As a result, the hart assigned to this interrupt (here, hart4) does not
get interrupted even after it gets re-assigned to the corresponding
PLIC line, so the GPIO interrupt pending bits are never cleared, and it
cannot signal any further interrupt to the PLIC.
Pressing the key a second time, the only difference is that the GPIO
controller noticed the falling edge interrupt condition, which is
masked so nothing happens.

The kernel/debug/tracing/trace buffer tells a similar story:
- the GPIO regmap clear writes happen first
- later, the PMIC interrupt source register is cleared (the write to
  register 6)

Checking gpio-sifive.c and irq-sifive-plic.c, I see:
- the GPIO propagates irq_mask and irq_unmask to the PLIC
- the PLIC implements irq masking by making the interrupt line handled
  by no hart

Reading the PLIC documentation, I cannot tell if this behaviour of the
PLIC ("losing" an interrupt if there is no hart servicing it) is
intended or not.

If it is intended, then what is the proper way of masking an
interrupt ?
Is it to lower that interrupt priority ? (which I did not try)
Is it to mask it outside the PLIC (so on the GPIO controller here) ?

I did try the latter as a quick hack, and it allows repeated
interrupts, fixing both the power button and the hwmon subsystems.
But I am not sure it is possible to do this while being certain to never
lose an interrupt - but I am very new to interrupt handling in Linux.

Traces:

  # ./unmatched_gpio_irq_debug.py 1
  gpio_pin=1 gpio_mask=0b10 plic_irq=24 plic_mask=0b1000000000000000000000000
  GPIO 1: dir=in  in=1 out=0 irq_en=low irq_pending=high
  PLIC 24: priority=1 irq_en=hart4 irq_pending=False
  hart min prio: 1=0, 2=0, 3=0, 4=0
  # echo 1 > /sys/kernel/debug/tracing/events/regmap/enable; echo 1 > /sys/kernel/debug/tracing/events/irq/enable

  button pressed once here

  # echo 0 > /sys/kernel/debug/tracing/events/regmap/enable; echo 0 > /sys/kernel/debug/tracing/events/irq/enable
  # ./unmatched_gpio_irq_debug.py 1
  gpio_pin=1 gpio_mask=0b10 plic_irq=24 plic_mask=0b1000000000000000000000000
  GPIO 1: dir=in  in=1 out=0 irq_en=low irq_pending=rise,high,low
  PLIC 24: priority=1 irq_en=hart4 irq_pending=False
  hart min prio: 1=0, 2=0, 3=0, 4=0

Trace output with i2c interrupts trimmed for brevity:
          <idle>-0       [000] d.h2   102.707972: irq_handler_entry: irq=53 name=da9063-irq
          <idle>-0       [000] d.h2   102.707976: irq_handler_exit: irq=53 ret=handled
          <idle>-0       [000] d.h4   102.708019: regmap_reg_write: 10060000.gpio reg=1c val=2
          <idle>-0       [000] d.h4   102.708022: regmap_reg_write: 10060000.gpio reg=24 val=2
          <idle>-0       [000] d.h4   102.708024: regmap_reg_write: 10060000.gpio reg=2c val=2
          <idle>-0       [000] d.h4   102.708026: regmap_reg_write: 10060000.gpio reg=34 val=2
 irq/53-da9063-i-140     [002] ...1   102.708072: regmap_hw_read_start: 0-0058 reg=0 count=1
 irq/53-da9063-i-140     [002] d.h2   102.708121: irq_handler_entry: irq=5 name=riscv-timer
 irq/53-da9063-i-140     [002] dnh2   102.708159: irq_handler_exit: irq=5 ret=handled
(snip)
 irq/53-da9063-i-140     [002] ...1   102.709089: regmap_hw_read_done: 0-0058 reg=0 count=1
 irq/53-da9063-i-140     [002] ...1   102.709095: regmap_reg_read: 0-0058 reg=0 val=0
 irq/53-da9063-i-140     [002] ...1   102.709099: regmap_hw_read_start: 0-0058 reg=6 count=4
(snip)
 irq/53-da9063-i-140     [002] ...1   102.709879: regmap_hw_read_done: 0-0058 reg=6 count=4
 irq/53-da9063-i-140     [002] ...1   102.709893: regmap_hw_read_start: 0-0058 reg=0 count=1
(snip)
 irq/53-da9063-i-140     [002] ...1   102.710371: regmap_hw_read_done: 0-0058 reg=0 count=1
 irq/53-da9063-i-140     [002] ...1   102.710374: regmap_reg_read: 0-0058 reg=0 val=0
 irq/53-da9063-i-140     [002] ...1   102.710378: regmap_hw_write_start: 0-0058 reg=6 count=1
(snip)
 irq/53-da9063-i-140     [002] ...1   102.710763: regmap_hw_write_done: 0-0058 reg=6 count=1
 irq/53-da9063-i-140     [002] ...1   102.710767: regmap_reg_write: 0-0058 reg=6 val=1
 irq/53-da9063-i-140     [002] ...1   102.710783: regmap_hw_read_start: 0-0058 reg=0 count=1
(snip)
 irq/53-da9063-i-140     [002] ...1   102.711268: regmap_hw_read_done: 0-0058 reg=0 count=1
 irq/53-da9063-i-140     [002] ...1   102.711271: regmap_reg_read: 0-0058 reg=0 val=0
 irq/53-da9063-i-140     [002] ...1   102.711274: regmap_hw_read_start: 0-0058 reg=1 count=1
(snip)
 irq/53-da9063-i-140     [002] ...1   102.711770: regmap_hw_read_done: 0-0058 reg=1 count=1
 irq/53-da9063-i-140     [002] ...1   102.711773: regmap_reg_read: 0-0058 reg=1 val=0
 irq/53-da9063-i-140     [002] d..3   102.712183: softirq_raise: vec=6 [action=TASKLET]
     ksoftirqd/2-23      [002] ..s1   102.714162: softirq_entry: vec=6 [action=TASKLET]
     ksoftirqd/2-23      [002] ..s1   102.714173: softirq_exit: vec=6 [action=TASKLET]

Regards,
-- 
Vincent Pelletier
GPG fingerprint 983A E8B7 3B91 1598 7A92 3845 CAC9 3691 4257 B0C1

[-- Attachment #2: unmatched_gpio_irq_debug.py --]
[-- Type: text/x-python, Size: 4619 bytes --]

#!/bin/env python3
import io
import mmap

GPIO_INPUT_VAL      = 0x00 // 4
GPIO_INPUT_EN       = 0x04 // 4
GPIO_OUTPUT_EN      = 0x08 // 4
GPIO_OUTPUT_VAL     = 0x0c // 4
GPIO_PULL_UP_ENABLE = 0x10 // 4
GPIO_DRIVE_STRENGTH = 0x14 // 4
GPIO_RISE_IE        = 0x18 // 4
GPIO_RISE_IP        = 0x1c // 4
GPIO_FALL_IE        = 0x20 // 4
GPIO_FALL_IP        = 0x24 // 4
GPIO_HIGH_IE        = 0x28 // 4
GPIO_HIGH_IP        = 0x2c // 4
GPIO_LOW_IE         = 0x30 // 4
GPIO_LOW_IP         = 0x34 // 4
GPIO_IOF_EN         = 0x38 // 4
GPIO_IOF_SEL        = 0x3c // 4
GPIO_OUT_XOR        = 0x40 // 4

PLIC_SOURCE_PRIORITY_BASE = 0x00_0000 // 4 # + source index, 0-based
PLIC_PENDING_BASE         = 0x00_1000 // 4 # 3-words (12 bytes) bit-field
PLIC_HART1_S_IE_BASE      = 0x00_2100 // 4 # 3-words (12 bytes) bit-field
PLIC_HART2_S_IE_BASE      = 0x00_2200 // 4 # 3-words (12 bytes) bit-field
PLIC_HART3_S_IE_BASE      = 0x00_2300 // 4 # 3-words (12 bytes) bit-field
PLIC_HART4_S_IE_BASE      = 0x00_2400 // 4 # 3-words (12 bytes) bit-field
PLIC_HART1_S_PRIORITY     = 0x20_2000 // 4
PLIC_HART1_S_COMPLETE     = 0x20_2008 // 4
PLIC_HART2_S_PRIORITY     = 0x20_4000 // 4
PLIC_HART2_S_COMPLETE     = 0x20_4008 // 4
PLIC_HART3_S_PRIORITY     = 0x20_6000 // 4
PLIC_HART3_S_COMPLETE     = 0x20_6008 // 4
PLIC_HART4_S_PRIORITY     = 0x20_8000 // 4
PLIC_HART4_S_COMPLETE     = 0x20_8008 // 4

PLIC_IRQ_GPIO_BASE = 23

def get3wBitField(plic, base):
  return (
    (plic[base + 0] <<  0) |
    (plic[base + 1] << 32) |
    (plic[base + 2] << 64)
  )

def uint32le_memoryview(value):
  return memoryview(value).cast('I')

def main(argv):
  gpio_pin = int(argv[1])
  assert 0 <= gpio_pin <= 15
  gpio_mask = 1 << gpio_pin
  plic_irq = PLIC_IRQ_GPIO_BASE + gpio_pin
  plic_mask = 1 << plic_irq
  print('gpio_pin=%i gpio_mask=%s plic_irq=%i plic_mask=%s' % (
    gpio_pin,
    bin(gpio_mask),
    plic_irq,
    bin(plic_mask),
  ))
  # Sanity check: must be on the correct board
  with open('/sys/firmware/devicetree/base/compatible', 'rb') as board_compatible:
    compatible = board_compatible.read().strip()
    assert compatible == b'sifive,hifive-unmatched-a00\x00sifive,fu740-c000\x00sifive,fu740\x00', repr(compatible)
  with io.open('/dev/mem', mode='rb', buffering=0) as dev_mem:
    dev_mem_fileno = dev_mem.fileno()
    with (
      mmap.mmap(dev_mem_fileno, length=0x30_0000, offset=0x0c00_0000, prot=mmap.PROT_READ) as plic,
      mmap.mmap(dev_mem_fileno, length=0x00_0044, offset=0x1006_0000, prot=mmap.PROT_READ) as gpio
    ):
      plic = uint32le_memoryview(plic)
      gpio = uint32le_memoryview(gpio)
      try:
        print('GPIO %i: dir=%s in=%i out=%i irq_en=%s irq_pending=%s' % (
          gpio_pin,
          {
            (False, False): 'off',
            (False,  True): 'out',
            (True,  False): 'in ',
          }[(
            bool(gpio[GPIO_INPUT_EN] & gpio_mask),
            bool(gpio[GPIO_OUTPUT_EN] & gpio_mask),
          )],
          bool(gpio[GPIO_INPUT_VAL] & gpio_mask),
          bool(gpio[GPIO_OUTPUT_VAL] & gpio_mask),
          ','.join(
            x
            for x, y in (
              ('rise', GPIO_RISE_IE),
              ('fall', GPIO_FALL_IE),
              ('high', GPIO_HIGH_IE),
              ('low',  GPIO_LOW_IE),
            )
            if gpio[y] & gpio_mask
          ),
          ','.join(
            x
            for x, y in (
              ('rise', GPIO_RISE_IP),
              ('fall', GPIO_FALL_IP),
              ('high', GPIO_HIGH_IP),
              ('low',  GPIO_LOW_IP),
            )
            if gpio[y] & gpio_mask
          ),
        ))
        print('PLIC %i: priority=%i irq_en=%s irq_pending=%s' % (
          plic_irq,
          plic[PLIC_SOURCE_PRIORITY_BASE + plic_irq],
          ', '.join(
            x
            for x, y in (
              ('hart1', PLIC_HART1_S_IE_BASE),
              ('hart2', PLIC_HART2_S_IE_BASE),
              ('hart3', PLIC_HART3_S_IE_BASE),
              ('hart4', PLIC_HART4_S_IE_BASE),
            )
            if get3wBitField(plic, y) & plic_mask
          ),
          bool(get3wBitField(plic, PLIC_PENDING_BASE) & plic_mask),
        ))
        print('hart min prio: %s' % (
          ', '.join(
            '%i=%s' % (x, plic[y])
            for x, y in enumerate(
              (
                PLIC_HART1_S_PRIORITY,
                PLIC_HART2_S_PRIORITY,
                PLIC_HART3_S_PRIORITY,
                PLIC_HART4_S_PRIORITY,
              ),
              1,
            )
          )
        ))
      finally:
        del gpio, plic

if __name__ == '__main__':
  import sys
  main(sys.argv)

[-- Attachment #3: Type: text/plain, Size: 161 bytes --]

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [RFC PATCH] gpio: sifive: Take care of interrupt masking.
  2021-07-04  6:41 PLIC and interrupts received while no hart enabled Vincent Pelletier
@ 2021-07-10  2:00 ` Vincent Pelletier
  2021-07-23  3:21 ` PLIC and interrupts received while no hart enabled Vincent Pelletier
  1 sibling, 0 replies; 3+ messages in thread
From: Vincent Pelletier @ 2021-07-10  2:00 UTC (permalink / raw)
  To: linux-riscv

Rather than relying on the PLIC.
Fixes the inability to trigger PMIC IRQs more than once.
---
Note: intended as an illustration for parent email, for comments, hence
the absence of S-o-b and gpio maintainers not being cc'ed, all as extra
safety nets against accidental inclusion until I get confirmation that this
IRQ issue should in fact be fixed at the gpio level and not somewhere else.

One thing I would like to get feedback on which is maybe secondary to the
"where does the fix go" question is whether it is correct to clear edge
interrupts during unmask: I'm worried it could miss a trigger edge between
the attached chip's handler clearing a source and gpio level unmasking.
For level sources it should not matter, they will immediately re-trigger
anyway.
---
 drivers/gpio/gpio-sifive.c | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/drivers/gpio/gpio-sifive.c b/drivers/gpio/gpio-sifive.c
index 9c2d0bf04e58..cd4bb1f9ece5 100644
--- a/drivers/gpio/gpio-sifive.c
+++ b/drivers/gpio/gpio-sifive.c
@@ -108,7 +108,22 @@ static void sifive_gpio_irq_disable(struct irq_data *d)
 	irq_chip_disable_parent(d);
 }
 
-static void sifive_gpio_irq_eoi(struct irq_data *d)
+static void sifive_gpio_irq_mask(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct sifive_gpio *chip = gpiochip_get_data(gc);
+	int offset = irqd_to_hwirq(d) % SIFIVE_GPIO_MAX;
+	unsigned long flags;
+
+	spin_lock_irqsave(&gc->bgpio_lock, flags);
+	regmap_update_bits(chip->regs, SIFIVE_GPIO_RISE_IE, BIT(offset), 0);
+	regmap_update_bits(chip->regs, SIFIVE_GPIO_FALL_IE, BIT(offset), 0);
+	regmap_update_bits(chip->regs, SIFIVE_GPIO_HIGH_IE, BIT(offset), 0);
+	regmap_update_bits(chip->regs, SIFIVE_GPIO_LOW_IE, BIT(offset), 0);
+	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+}
+
+static void sifive_gpio_irq_unmask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 	struct sifive_gpio *chip = gpiochip_get_data(gc);
@@ -124,7 +139,7 @@ static void sifive_gpio_irq_eoi(struct irq_data *d)
 	regmap_write(chip->regs, SIFIVE_GPIO_LOW_IP, bit);
 	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 
-	irq_chip_eoi_parent(d);
+	sifive_gpio_set_ie(chip, offset);
 }
 
 static int sifive_gpio_irq_set_affinity(struct irq_data *data,
@@ -140,11 +155,11 @@ static int sifive_gpio_irq_set_affinity(struct irq_data *data,
 static struct irq_chip sifive_gpio_irqchip = {
 	.name		= "sifive-gpio",
 	.irq_set_type	= sifive_gpio_irq_set_type,
-	.irq_mask	= irq_chip_mask_parent,
-	.irq_unmask	= irq_chip_unmask_parent,
+	.irq_mask	= sifive_gpio_irq_mask,
+	.irq_unmask	= sifive_gpio_irq_unmask,
 	.irq_enable	= sifive_gpio_irq_enable,
 	.irq_disable	= sifive_gpio_irq_disable,
-	.irq_eoi	= sifive_gpio_irq_eoi,
+	.irq_eoi	= irq_chip_eoi_parent,
 	.irq_set_affinity = sifive_gpio_irq_set_affinity,
 };
 
-- 
2.32.0


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: PLIC and interrupts received while no hart enabled
  2021-07-04  6:41 PLIC and interrupts received while no hart enabled Vincent Pelletier
  2021-07-10  2:00 ` [RFC PATCH] gpio: sifive: Take care of interrupt masking Vincent Pelletier
@ 2021-07-23  3:21 ` Vincent Pelletier
  1 sibling, 0 replies; 3+ messages in thread
From: Vincent Pelletier @ 2021-07-23  3:21 UTC (permalink / raw)
  To: linux-riscv, Palmer Dabbelt, Anup Patel, Atish Patra; +Cc: David Abdurachmanov

On Sun, 4 Jul 2021 06:41:14 +0000, Vincent Pelletier <plr.vincent@gmail.com> wrote:
> Hello,
> 
> I've recently purchased a sifive unmatched board, and have tried to
> complete its devicetree using the schematics.
> 
> Doing so, I enabled some sub-functions of its PMIC chip (DA9063). Those
> which matter for this email are:
> - power button, notified by interrupt
> - hwmon, based on an ADC which signals conversion completion with an
>   interrupt
> 
> The PMIC has an interrupt line, active low, connected to line 1 of the
> GPIO controller embedded in the board's SoC (fu740).
> Internally to the SoC, the GPIO has one interrupt line per GPIO line,
> connected to the PLIC.
> 
> The issue I originally had was, which I noticed with the ADC but could
> equally reproduce with the power button, I could only ever get a single
> IRQ to be processed.
> 
> Reading the corresponding registers (with the script attached),
> enabling IRQ and regmap tracing, I saw the output at the end of this email.
> 
> Here is how I read the register states:
> - initial state:
>   The PMIC interrupt line is in its idle state (high).
>   The GPIO controller noticed the high state, and armed the
>   corresponding interrupt-pending bit - this an important first piece of
>   information.
>   As the corresponding interrupt-enable is cleared, no interrupt is
>   signalled and the PLIC does not see an interrupt pending. This is all
>   good.
> - after one button press:
>   The PMIC interrupt line is again in its idle state, so the interrupt
>   source was cleared. I know it triggered as the power button input
>   event does fire as intended.
>   This time, the GPIO controller noticed 3 interrupt conditions on this
>   line: low, rising edge, and high. This means it was cleared *before*
>   the PMIC line went high:
>   - if it was cleared after, only "high" should be visible
>   - if is was never cleared, all low/rise/high/fall interrupt
>     conditions would be present
>   As the "low" interrupt is enabled, I believe (but cannot check) that
>   it notified the PLIC of the interrupt.
>   But like before, the PLIC does not see this interrupt being signalled.
> 
> As a result, the hart assigned to this interrupt (here, hart4) does not
> get interrupted even after it gets re-assigned to the corresponding
> PLIC line, so the GPIO interrupt pending bits are never cleared, and it
> cannot signal any further interrupt to the PLIC.
> Pressing the key a second time, the only difference is that the GPIO
> controller noticed the falling edge interrupt condition, which is
> masked so nothing happens.
> 
> The kernel/debug/tracing/trace buffer tells a similar story:
> - the GPIO regmap clear writes happen first
> - later, the PMIC interrupt source register is cleared (the write to
>   register 6)
> 
> Checking gpio-sifive.c and irq-sifive-plic.c, I see:
> - the GPIO propagates irq_mask and irq_unmask to the PLIC
> - the PLIC implements irq masking by making the interrupt line handled
>   by no hart
> 
> Reading the PLIC documentation, I cannot tell if this behaviour of the
> PLIC ("losing" an interrupt if there is no hart servicing it) is
> intended or not.
> 
> If it is intended, then what is the proper way of masking an
> interrupt ?
> Is it to lower that interrupt priority ? (which I did not try)
> Is it to mask it outside the PLIC (so on the GPIO controller here) ?
> 
> I did try the latter as a quick hack, and it allows repeated
> interrupts, fixing both the power button and the hwmon subsystems.
> But I am not sure it is possible to do this while being certain to never
> lose an interrupt - but I am very new to interrupt handling in Linux.
> 
> Traces:
> 
>   # ./unmatched_gpio_irq_debug.py 1
>   gpio_pin=1 gpio_mask=0b10 plic_irq=24 plic_mask=0b1000000000000000000000000
>   GPIO 1: dir=in  in=1 out=0 irq_en=low irq_pending=high
>   PLIC 24: priority=1 irq_en=hart4 irq_pending=False
>   hart min prio: 1=0, 2=0, 3=0, 4=0
>   # echo 1 > /sys/kernel/debug/tracing/events/regmap/enable; echo 1 > /sys/kernel/debug/tracing/events/irq/enable
> 
>   button pressed once here
> 
>   # echo 0 > /sys/kernel/debug/tracing/events/regmap/enable; echo 0 > /sys/kernel/debug/tracing/events/irq/enable
>   # ./unmatched_gpio_irq_debug.py 1
>   gpio_pin=1 gpio_mask=0b10 plic_irq=24 plic_mask=0b1000000000000000000000000
>   GPIO 1: dir=in  in=1 out=0 irq_en=low irq_pending=rise,high,low
>   PLIC 24: priority=1 irq_en=hart4 irq_pending=False
>   hart min prio: 1=0, 2=0, 3=0, 4=0
> 
> Trace output with i2c interrupts trimmed for brevity:
>           <idle>-0       [000] d.h2   102.707972: irq_handler_entry: irq=53 name=da9063-irq
>           <idle>-0       [000] d.h2   102.707976: irq_handler_exit: irq=53 ret=handled
>           <idle>-0       [000] d.h4   102.708019: regmap_reg_write: 10060000.gpio reg=1c val=2
>           <idle>-0       [000] d.h4   102.708022: regmap_reg_write: 10060000.gpio reg=24 val=2
>           <idle>-0       [000] d.h4   102.708024: regmap_reg_write: 10060000.gpio reg=2c val=2
>           <idle>-0       [000] d.h4   102.708026: regmap_reg_write: 10060000.gpio reg=34 val=2
>  irq/53-da9063-i-140     [002] ...1   102.708072: regmap_hw_read_start: 0-0058 reg=0 count=1
>  irq/53-da9063-i-140     [002] d.h2   102.708121: irq_handler_entry: irq=5 name=riscv-timer
>  irq/53-da9063-i-140     [002] dnh2   102.708159: irq_handler_exit: irq=5 ret=handled
> (snip)
>  irq/53-da9063-i-140     [002] ...1   102.709089: regmap_hw_read_done: 0-0058 reg=0 count=1
>  irq/53-da9063-i-140     [002] ...1   102.709095: regmap_reg_read: 0-0058 reg=0 val=0
>  irq/53-da9063-i-140     [002] ...1   102.709099: regmap_hw_read_start: 0-0058 reg=6 count=4
> (snip)
>  irq/53-da9063-i-140     [002] ...1   102.709879: regmap_hw_read_done: 0-0058 reg=6 count=4
>  irq/53-da9063-i-140     [002] ...1   102.709893: regmap_hw_read_start: 0-0058 reg=0 count=1
> (snip)
>  irq/53-da9063-i-140     [002] ...1   102.710371: regmap_hw_read_done: 0-0058 reg=0 count=1
>  irq/53-da9063-i-140     [002] ...1   102.710374: regmap_reg_read: 0-0058 reg=0 val=0
>  irq/53-da9063-i-140     [002] ...1   102.710378: regmap_hw_write_start: 0-0058 reg=6 count=1
> (snip)
>  irq/53-da9063-i-140     [002] ...1   102.710763: regmap_hw_write_done: 0-0058 reg=6 count=1
>  irq/53-da9063-i-140     [002] ...1   102.710767: regmap_reg_write: 0-0058 reg=6 val=1
>  irq/53-da9063-i-140     [002] ...1   102.710783: regmap_hw_read_start: 0-0058 reg=0 count=1
> (snip)
>  irq/53-da9063-i-140     [002] ...1   102.711268: regmap_hw_read_done: 0-0058 reg=0 count=1
>  irq/53-da9063-i-140     [002] ...1   102.711271: regmap_reg_read: 0-0058 reg=0 val=0
>  irq/53-da9063-i-140     [002] ...1   102.711274: regmap_hw_read_start: 0-0058 reg=1 count=1
> (snip)
>  irq/53-da9063-i-140     [002] ...1   102.711770: regmap_hw_read_done: 0-0058 reg=1 count=1
>  irq/53-da9063-i-140     [002] ...1   102.711773: regmap_reg_read: 0-0058 reg=1 val=0
>  irq/53-da9063-i-140     [002] d..3   102.712183: softirq_raise: vec=6 [action=TASKLET]
>      ksoftirqd/2-23      [002] ..s1   102.714162: softirq_entry: vec=6 [action=TASKLET]
>      ksoftirqd/2-23      [002] ..s1   102.714173: softirq_exit: vec=6 [action=TASKLET]
> 
> Regards,

I have just been told that someone has the same issue on the previous
sifive board (hifive unleashed) which uses the same GPIO and PLIC
modules, although they were using the 5.10.42 kernel.

So I would like to go forward with my RFC gpio patch,
  https://patchwork.kernel.org/project/linux-riscv/patch/8c36c1a28ce63b5120765fd3c636944bfec8bee9.1625882423.git.plr.vincent@gmail.com/
but before this if possible I would prefer to get feedback about the
PLIC:
Is the behaviour I describe above expected ?

I do not find anything in the PLIC documentations (neither riscv.org
nor sifive) which mention whether the PLIC gateways should be edge- or
level-sensitive.

I suspect in the sifive SoC it would be edge-sensitive whereas the
embedded GPIO chip would produce a level IRQ output, something like
  (pending && enabled)
so both GPIO-level sensitivity types would produce an edge output when
"pending" gets set, but level interrupts would not re-trigger. If this
is the case, then I believe my patch works around the issue: by
changing "enabled" at GPIO level it forces the generation of a new edge
even on level inputs.

But maybe I am missing something more fundamental about how the PLIC
should work.

Regards,
-- 
Vincent Pelletier
GPG fingerprint 983A E8B7 3B91 1598 7A92 3845 CAC9 3691 4257 B0C1

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-07-23  3:22 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-04  6:41 PLIC and interrupts received while no hart enabled Vincent Pelletier
2021-07-10  2:00 ` [RFC PATCH] gpio: sifive: Take care of interrupt masking Vincent Pelletier
2021-07-23  3:21 ` PLIC and interrupts received while no hart enabled Vincent Pelletier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).