GPIO level IRQ fires twice each time.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I have a problem with a custom bord based on SoC am335x and a driver utilizing a GPIO line for interrupts. 

I have two mcp2518fd chip connected on one SPI line and everything works, but it's hogs a lot of CPU.
In the current setup only one chip is connected and it only receives packets.

The mcp2518fd is connected with 2 interrupt lines one "main" and one for rx frames. 

The problem is that for every frame received the interrupt handler is run twice, which is kind of expensive since it's a SPI call to the chip to check interrupt registers. 

To me it looks like the interrupt is fired again as soon as it's unmasked. Either because it's queued? or maybe not cleared internally?
I have scoped the interrupt signal and its real good without any glitches. 

I'm currently running a yocto build:
Linux botekcc 5.10.79-yocto-tiny #1 SMP Tue Nov 16 03:57:43 UTC 2021 armv7l armv7l armv7l GNU/Linux 

But the mcp251xfd driver is from net-next/master

mcp251xfd_irq is the irqhandler for the mcp2518fd and is added like this:
err = request_threaded_irq(spi->irq, NULL, mcp251xfd_irq,
                                   IRQF_SHARED | IRQF_ONESHOT,
                                   dev_name(&spi->dev), priv);

I have instrumented some of the handling in /kernel/irq/chip.c and /kernel/irq/handle.c 
And this maybe doesn't say anything but it looks like this:

[  290.229920] IRQ:19 mask_irq
[  290.233098] IRQ:19 Enter. Caller is handle_level_irq+0xe4/0x1dc
[  290.241851] IRQ:64 mask_irq
[  290.245014] IRQ:64 Enter. Caller is handle_level_irq+0xe4/0x1dc
[  290.253777] IRQ:64 Leave
[  290.253784] IRQ:19 Leave
[  290.258868] IRQ:19 unmask_irq
[  290.262785] Enter mcp251xfd_irq

-First enter. Here the interrupt is handled and the interruptline goes inactive. 
-We do not return until rx-int is inactive. AND rx-int and int goes inactive simultaneous. (when only receiving.)
-I've also tried a msleep(1000) here to make sure there is enough time for the int to go inactive. 

[  290.265966] Leave mcp251xfd_irq (RX)
[  290.269167] IRQ:64 unmask_irq
[  290.275740] IRQ:19 mask_irq
[  290.278900] IRQ:19 Enter. Caller is handle_level_irq+0xe4/0x1dc
[  290.287648] IRQ:64 mask_irq
[  290.290806] IRQ:64 Enter. Caller is handle_level_irq+0xe4/0x1dc
[  290.299547] IRQ:64 Leave
[  290.299552] IRQ:19 Leave
[  290.304633] IRQ:19 unmask_irq
[  290.308503] Enter mcp251xfd_irq

-This time rx-int is low and the SPI read of the interrupt registers show no int is pending.

[  290.311515] Leave mcp251xfd_irq (Normal)
[  290.314669] IRQ:64 unmask_irq




cat /proc/interrupts shows this after receiving one frame:

16:      10389      INTC  68 Level     clockevent
 17:          0      INTC   3 Level     arm-pmu
 19:          2      INTC  96 Level     44e07000.gpio
 20:        510      INTC  72 Level     44e09000.serial
 21:       3239      INTC  70 Level     44e0b000.i2c
 24:          0      INTC  75 Level     rtc0
 25:          0      INTC  76 Level     rtc0
 28:          0      INTC  71 Level     4802a000.i2c
 34:          0      INTC  98 Level     4804c000.gpio
 35:       2692      INTC  64 Level     mmc0
 37:          0      INTC 125 Level     481a0000.spi
 40:          0      INTC  32 Level     481ac000.gpio
 41:          0      INTC  62 Level     481ae000.gpio
 42:        315      INTC  28 Level     mmc1
 43:          0      INTC 111 Level     48310000.rng
 45:          0      INTC  41 Level     4a100000.ethernet
 46:          0      INTC  42 Level     4a100000.ethernet
 48:        967      INTC  12 Level     49000000.dma_ccint
 50:          1      INTC  14 Level     49000000.dma_ccerrint
 59:          0      INTC   7 Level     tps65217-irq
 62:          0  tps65217   2 Edge      tps65217_pwrbutton
 63:          0  481ac000.gpio   5 Level     spi1.0
 64:          2  44e07000.gpio  22 Level     spi1.1
 65:          0  44e07000.gpio   6 Edge      48060000.mmc cd


Where
19:          2      INTC  96 Level     44e07000.gpio
64:          2  44e07000.gpio  22 Level     spi1.1
Is the problem. 



This is the dts part of the mcp2518fd's:
/*
 * Device tree overlay for mcp2518fd on spi1.0 and spi1.1
 */

#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>

&am33xx_pinmux{
        pinctrl_spi1_pins: pinctrl_spi1_pins {
                pinctrl-single,pins = <
                        AM33XX_IOPAD(0x990, PIN_INPUT | MUX_MODE3) /* (A13) mcasp0_aclkx.spi1_sclk */
                        AM33XX_IOPAD(0x994, PIN_INPUT | MUX_MODE3) /* (B13) mcasp0_fsx.spi1_d0 */
                        AM33XX_IOPAD(0x998, PIN_INPUT | MUX_MODE3) /* (D12) mcasp0_axr0.spi1_d1 */
                        AM33XX_IOPAD(0x96c, PIN_OUTPUT_PULLUP | MUX_MODE5) /* (E17) uart0_rtsn.spi1_cs0         CleANopen       LEFT*/
                        AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLUP | MUX_MODE4) /* (A15) xdma_event_intr0.spi1_cs1   SAWM CAN        RIGHT*/
                >;
        };

        can0_int_pins: can0_int_pins {
                pinctrl-single,pins = <
                /*CleANopen*/
                AM33XX_IOPAD(0x89c, PIN_INPUT_PULLUP | MUX_MODE7) /* (T6) gpmc_be0n_cle.gpio2[5]        nINT            */
                AM33XX_IOPAD(0x968, PIN_INPUT_PULLUP | MUX_MODE7) /* (E18) uart0_ctsn.gpio1[8]          nINT1           */
                >;
        };

        can1_int_pins: can1_int_pins {
                pinctrl-single,pins = <
                /*SAWM CAN*/
                AM33XX_IOPAD(0x820, PIN_INPUT_PULLUP | MUX_MODE7) /* (U10) gpmc_ad8.gpio0[22]   nINT            */
                AM33XX_IOPAD(0x8c8, PIN_INPUT_PULLUP | MUX_MODE7) /* (U3) lcd_data10.gpio2[16]  nINT1           */
                >;
        };
};



/{
        /* external 40M oscillator of mcp2518fd on SPI1.0 */
        mcp2518fd_can0_osc: mcp2518fd_can0_osc {
                compatible = "fixed-clock";
                #clock-cells = <0>;
                clock-frequency = <40000000>;
        };
};


/{
        /* external 40M oscillator of mcp2518fd on SPI1.1 */
        mcp2518fd_can1_osc: mcp2518fd_can1_osc {
                compatible = "fixed-clock";
                #clock-cells = <0>;
                clock-frequency = <40000000>;
        };
};

/* the spi config of the can-controller itself binding everything together */
&spi1{
    #address-cells = <1>;
    #size-cells = <0>;

    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_spi1_pins>;

    /*CleANopen*/
    can@0 {
        compatible = "microchip,mcp2518fd";
        reg = <0>;
        clocks = <&mcp2518fd_can0_osc>;
        pinctrl-names = "default";
        pinctrl-0 = <&can0_int_pins>;
        spi-max-frequency = <20000000>;

        interrupt-parent = <&gpio2>;
        interrupts = <5 IRQ_TYPE_LEVEL_LOW>;

        interrupts-extended = <&gpio2 5 IRQ_TYPE_LEVEL_LOW>;
        microchip,rx-int-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
    };

    can@1 {
        compatible = "microchip,mcp2518fd";
        reg = <1>;
        clocks = <&mcp2518fd_can1_osc>;
        pinctrl-names = "default";
        pinctrl-0 = <&can1_int_pins>;
        spi-max-frequency = <20000000>;

        interrupt-parent = <&gpio0>;
        interrupts = <22 IRQ_TYPE_LEVEL_LOW>;

        interrupts-extended = <&gpio0 22 IRQ_TYPE_LEVEL_LOW>;
        microchip,rx-int-gpios = <&gpio2 16 GPIO_ACTIVE_LOW>;
    };
};


Any thought on why I see this behavior?

Regards
Markus 




[Index of Archives]     [Linux SPI]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux