[PATCH v1] irqchip/meson-gpio: replace 'spinlock_t' with 'raw_spinlock_t'

From: Arseniy Krasnov
Date: Mon Jul 29 2024 - 09:31:42 EST


This lock is acquired under 'lock' of 'struct irq_desc' which has
type 'raw_spinlock_t'. When PREEMPT_RT is enabled, 'spinlock_t'
become preemptible, so we will lock preemptible lock under raw
spinlock. Found by lockdep:

[] =============================
[] [ BUG: Invalid wait context ]
[] 6.9.9-sdkernel #1 Not tainted
[] -----------------------------
[] swapper/0/1 is trying to lock:
[] ffff0000008fed30 (&ctl->lock){....}-{3:3}, at: meson_gpio_irq_update_bits0
[] other info that might help us debug this:
[] context-{5:5}
[] 3 locks held by swapper/0/1:
[] #0: ffff0000003cd0f8 (&dev->mutex){....}-{4:4}, at: __driver_attach+0x90c
[] #1: ffff000004714650 (&desc->request_mutex){+.+.}-{4:4}, at: __setup_irq0
[] #2: ffff0000047144c8 (&irq_desc_lock_class){-.-.}-{2:2}, at: __setup_irq0
[] stack backtrace:
[] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 6.9.9-sdkernel #1
[] Call trace:
[] dump_backtrace+0x98/0xf0
[] show_stack+0x18/0x24
[] dump_stack_lvl+0x90/0xd0
[] dump_stack+0x18/0x24
[] __lock_acquire+0x9dc/0x1f10
[] lock_acquire.part.0+0xe8/0x228
[] lock_acquire+0x68/0x84
[] _raw_spin_lock_irqsave+0x60/0x88
[] meson_gpio_irq_update_bits+0x34/0x70
[] meson8_gpio_irq_set_type+0x78/0xc4
[] meson_gpio_irq_set_type+0x30/0x60
[] __irq_set_trigger+0x60/0x180
[] __setup_irq+0x30c/0x6e0
[] request_threaded_irq+0xec/0x1a4
[] request_any_context_irq+0x64/0xc4
[] devm_request_any_context_irq+0x78/0x110
[] gpio_keys_probe+0x374/0xa6c
[] platform_probe+0x68/0xc0
[] really_probe+0xbc/0x2a4
[] __driver_probe_device+0x78/0x12c
[] driver_probe_device+0xd8/0x160
[] __driver_attach+0x9c/0x1ac
[] bus_for_each_dev+0x78/0xd8
[] driver_attach+0x24/0x30
[] bus_add_driver+0xe4/0x208
[] driver_register+0x60/0x128
[] __platform_driver_register+0x28/0x34
[] gpio_keys_init+0x1c/0x28
[] do_one_initcall+0x88/0x34c
[] kernel_init_freeable+0x240/0x334
[] kernel_init+0x20/0x1d8
[] ret_from_fork+0x10/0x20

Signed-off-by: Arseniy Krasnov <avkrasnov@xxxxxxxxxxxxxxxxx>
---
drivers/irqchip/irq-meson-gpio.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c
index 9a1791908598d..a4c3b57098ba0 100644
--- a/drivers/irqchip/irq-meson-gpio.c
+++ b/drivers/irqchip/irq-meson-gpio.c
@@ -178,7 +178,7 @@ struct meson_gpio_irq_controller {
void __iomem *base;
u32 channel_irqs[MAX_NUM_CHANNEL];
DECLARE_BITMAP(channel_map, MAX_NUM_CHANNEL);
- spinlock_t lock;
+ raw_spinlock_t lock;
};

static void meson_gpio_irq_update_bits(struct meson_gpio_irq_controller *ctl,
@@ -187,14 +187,14 @@ static void meson_gpio_irq_update_bits(struct meson_gpio_irq_controller *ctl,
unsigned long flags;
u32 tmp;

- spin_lock_irqsave(&ctl->lock, flags);
+ raw_spin_lock_irqsave(&ctl->lock, flags);

tmp = readl_relaxed(ctl->base + reg);
tmp &= ~mask;
tmp |= val;
writel_relaxed(tmp, ctl->base + reg);

- spin_unlock_irqrestore(&ctl->lock, flags);
+ raw_spin_unlock_irqrestore(&ctl->lock, flags);
}

static void meson_gpio_irq_init_dummy(struct meson_gpio_irq_controller *ctl)
@@ -244,12 +244,12 @@ meson_gpio_irq_request_channel(struct meson_gpio_irq_controller *ctl,
unsigned long flags;
unsigned int idx;

- spin_lock_irqsave(&ctl->lock, flags);
+ raw_spin_lock_irqsave(&ctl->lock, flags);

/* Find a free channel */
idx = find_first_zero_bit(ctl->channel_map, ctl->params->nr_channels);
if (idx >= ctl->params->nr_channels) {
- spin_unlock_irqrestore(&ctl->lock, flags);
+ raw_spin_unlock_irqrestore(&ctl->lock, flags);
pr_err("No channel available\n");
return -ENOSPC;
}
@@ -257,7 +257,7 @@ meson_gpio_irq_request_channel(struct meson_gpio_irq_controller *ctl,
/* Mark the channel as used */
set_bit(idx, ctl->channel_map);

- spin_unlock_irqrestore(&ctl->lock, flags);
+ raw_spin_unlock_irqrestore(&ctl->lock, flags);

/*
* Setup the mux of the channel to route the signal of the pad
@@ -567,7 +567,7 @@ static int meson_gpio_irq_of_init(struct device_node *node, struct device_node *
if (!ctl)
return -ENOMEM;

- spin_lock_init(&ctl->lock);
+ raw_spin_lock_init(&ctl->lock);

ctl->base = of_iomap(node, 0);
if (!ctl->base) {
--
2.30.1