lkml.org 
[lkml]   [2019]   [Jan]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL 4.14 004/170] pinctrl: bcm2835: Use raw spinlock for RT compatibility
    Date
    From: Lukas Wunner <lukas@wunner.de>

    [ Upstream commit 3c7b30f704b6f5e53eed6bf89cf2c8d1b38b02c0 ]

    The BCM2835 pinctrl driver acquires a spinlock in its ->irq_enable,
    ->irq_disable and ->irq_set_type callbacks. Spinlocks become sleeping
    locks with CONFIG_PREEMPT_RT_FULL=y, therefore invocation of one of the
    callbacks in atomic context may cause a hard lockup if at least two GPIO
    pins in the same bank are used as interrupts. The issue doesn't occur
    with just a single interrupt pin per bank because the lock is never
    contended. I'm experiencing such lockups with GPIO 8 and 28 used as
    level-triggered interrupts, i.e. with ->irq_disable being invoked on
    reception of every IRQ.

    The critical section protected by the spinlock is very small (one bitop
    and one RMW of an MMIO register), hence converting to a raw spinlock
    seems a better trade-off than converting the driver to threaded IRQ
    handling (which would increase latency to handle an interrupt).

    Cc: Mathias Duckeck <m.duckeck@kunbus.de>
    Signed-off-by: Lukas Wunner <lukas@wunner.de>
    Acked-by: Julia Cartwright <julia@ni.com>
    Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/pinctrl/bcm/pinctrl-bcm2835.c | 16 ++++++++--------
    1 file changed, 8 insertions(+), 8 deletions(-)

    diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
    index ff782445dfb7..e72bf2502eca 100644
    --- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
    +++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
    @@ -92,7 +92,7 @@ struct bcm2835_pinctrl {
    struct gpio_chip gpio_chip;
    struct pinctrl_gpio_range gpio_range;

    - spinlock_t irq_lock[BCM2835_NUM_BANKS];
    + raw_spinlock_t irq_lock[BCM2835_NUM_BANKS];
    };

    /* pins are just named GPIO0..GPIO53 */
    @@ -471,10 +471,10 @@ static void bcm2835_gpio_irq_enable(struct irq_data *data)
    unsigned bank = GPIO_REG_OFFSET(gpio);
    unsigned long flags;

    - spin_lock_irqsave(&pc->irq_lock[bank], flags);
    + raw_spin_lock_irqsave(&pc->irq_lock[bank], flags);
    set_bit(offset, &pc->enabled_irq_map[bank]);
    bcm2835_gpio_irq_config(pc, gpio, true);
    - spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
    + raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
    }

    static void bcm2835_gpio_irq_disable(struct irq_data *data)
    @@ -486,12 +486,12 @@ static void bcm2835_gpio_irq_disable(struct irq_data *data)
    unsigned bank = GPIO_REG_OFFSET(gpio);
    unsigned long flags;

    - spin_lock_irqsave(&pc->irq_lock[bank], flags);
    + raw_spin_lock_irqsave(&pc->irq_lock[bank], flags);
    bcm2835_gpio_irq_config(pc, gpio, false);
    /* Clear events that were latched prior to clearing event sources */
    bcm2835_gpio_set_bit(pc, GPEDS0, gpio);
    clear_bit(offset, &pc->enabled_irq_map[bank]);
    - spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
    + raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
    }

    static int __bcm2835_gpio_irq_set_type_disabled(struct bcm2835_pinctrl *pc,
    @@ -594,7 +594,7 @@ static int bcm2835_gpio_irq_set_type(struct irq_data *data, unsigned int type)
    unsigned long flags;
    int ret;

    - spin_lock_irqsave(&pc->irq_lock[bank], flags);
    + raw_spin_lock_irqsave(&pc->irq_lock[bank], flags);

    if (test_bit(offset, &pc->enabled_irq_map[bank]))
    ret = __bcm2835_gpio_irq_set_type_enabled(pc, gpio, type);
    @@ -606,7 +606,7 @@ static int bcm2835_gpio_irq_set_type(struct irq_data *data, unsigned int type)
    else
    irq_set_handler_locked(data, handle_level_irq);

    - spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
    + raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags);

    return ret;
    }
    @@ -1021,7 +1021,7 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
    for_each_set_bit(offset, &events, 32)
    bcm2835_gpio_wr(pc, GPEDS0 + i * 4, BIT(offset));

    - spin_lock_init(&pc->irq_lock[i]);
    + raw_spin_lock_init(&pc->irq_lock[i]);
    }

    err = gpiochip_add_data(&pc->gpio_chip, pc);
    --
    2.19.1
    \
     
     \ /
      Last update: 2019-01-28 18:09    [W:4.062 / U:0.556 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site