| From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| Date: Thu, 12 Feb 2015 16:01:13 +0100 |
| Subject: gpio: omap: use raw locks for locking |
| |
| This patch converts gpio_bank.lock from a spin_lock into a |
| raw_spin_lock. The call path is to access this lock is always under a |
| raw_spin_lock, for instance |
| - __setup_irq() holds &desc->lock with irq off |
| + __irq_set_trigger() |
| + omap_gpio_irq_type() |
| |
| - handle_level_irq() (runs with irqs off therefore raw locks) |
| + mask_ack_irq() |
| + omap_gpio_mask_irq() |
| |
| This fixes the obvious backtrace on -RT. However the locking vs context |
| is not and this is not limited to -RT: |
| - omap_gpio_irq_type() is called with IRQ off and has an conditional |
| call to pm_runtime_get_sync() which may sleep. Either it may happen or |
| it may not happen but pm_runtime_get_sync() should not be called with |
| irqs off. |
| |
| - omap_gpio_debounce() is holding the lock with IRQs off. |
| + omap2_set_gpio_debounce() |
| + clk_prepare_enable() |
| + clk_prepare() this one might sleep. |
| The number of users of gpiod_set_debounce() / gpio_set_debounce() |
| looks low but still this is not good. |
| |
| Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| --- |
| drivers/gpio/gpio-omap.c | 78 +++++++++++++++++++++++------------------------ |
| 1 file changed, 39 insertions(+), 39 deletions(-) |
| |
| --- a/drivers/gpio/gpio-omap.c |
| +++ b/drivers/gpio/gpio-omap.c |
| @@ -57,7 +57,7 @@ struct gpio_bank { |
| u32 saved_datain; |
| u32 level_mask; |
| u32 toggle_mask; |
| - spinlock_t lock; |
| + raw_spinlock_t lock; |
| struct gpio_chip chip; |
| struct clk *dbck; |
| u32 mod_usage; |
| @@ -498,14 +498,14 @@ static int omap_gpio_irq_type(struct irq |
| (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH))) |
| return -EINVAL; |
| |
| - spin_lock_irqsave(&bank->lock, flags); |
| + raw_spin_lock_irqsave(&bank->lock, flags); |
| retval = omap_set_gpio_triggering(bank, offset, type); |
| omap_gpio_init_irq(bank, offset); |
| if (!omap_gpio_is_input(bank, offset)) { |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| return -EINVAL; |
| } |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| |
| if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) |
| __irq_set_handler_locked(d->irq, handle_level_irq); |
| @@ -626,14 +626,14 @@ static int omap_set_gpio_wakeup(struct g |
| return -EINVAL; |
| } |
| |
| - spin_lock_irqsave(&bank->lock, flags); |
| + raw_spin_lock_irqsave(&bank->lock, flags); |
| if (enable) |
| bank->context.wake_en |= gpio_bit; |
| else |
| bank->context.wake_en &= ~gpio_bit; |
| |
| writel_relaxed(bank->context.wake_en, bank->base + bank->regs->wkup_en); |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| |
| return 0; |
| } |
| @@ -668,7 +668,7 @@ static int omap_gpio_request(struct gpio |
| if (!BANK_USED(bank)) |
| pm_runtime_get_sync(bank->dev); |
| |
| - spin_lock_irqsave(&bank->lock, flags); |
| + raw_spin_lock_irqsave(&bank->lock, flags); |
| /* Set trigger to none. You need to enable the desired trigger with |
| * request_irq() or set_irq_type(). Only do this if the IRQ line has |
| * not already been requested. |
| @@ -678,7 +678,7 @@ static int omap_gpio_request(struct gpio |
| omap_enable_gpio_module(bank, offset); |
| } |
| bank->mod_usage |= BIT(offset); |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| |
| return 0; |
| } |
| @@ -688,11 +688,11 @@ static void omap_gpio_free(struct gpio_c |
| struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip); |
| unsigned long flags; |
| |
| - spin_lock_irqsave(&bank->lock, flags); |
| + raw_spin_lock_irqsave(&bank->lock, flags); |
| bank->mod_usage &= ~(BIT(offset)); |
| omap_disable_gpio_module(bank, offset); |
| omap_reset_gpio(bank, offset); |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| |
| /* |
| * If this is the last gpio to be freed in the bank, |
| @@ -794,9 +794,9 @@ static unsigned int omap_gpio_irq_startu |
| if (!BANK_USED(bank)) |
| pm_runtime_get_sync(bank->dev); |
| |
| - spin_lock_irqsave(&bank->lock, flags); |
| + raw_spin_lock_irqsave(&bank->lock, flags); |
| omap_gpio_init_irq(bank, offset); |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| omap_gpio_unmask_irq(d); |
| |
| return 0; |
| @@ -808,11 +808,11 @@ static void omap_gpio_irq_shutdown(struc |
| unsigned long flags; |
| unsigned offset = d->hwirq; |
| |
| - spin_lock_irqsave(&bank->lock, flags); |
| + raw_spin_lock_irqsave(&bank->lock, flags); |
| bank->irq_usage &= ~(BIT(offset)); |
| omap_disable_gpio_module(bank, offset); |
| omap_reset_gpio(bank, offset); |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| |
| /* |
| * If this is the last IRQ to be freed in the bank, |
| @@ -836,10 +836,10 @@ static void omap_gpio_mask_irq(struct ir |
| unsigned offset = d->hwirq; |
| unsigned long flags; |
| |
| - spin_lock_irqsave(&bank->lock, flags); |
| + raw_spin_lock_irqsave(&bank->lock, flags); |
| omap_set_gpio_irqenable(bank, offset, 0); |
| omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| } |
| |
| static void omap_gpio_unmask_irq(struct irq_data *d) |
| @@ -849,7 +849,7 @@ static void omap_gpio_unmask_irq(struct |
| u32 trigger = irqd_get_trigger_type(d); |
| unsigned long flags; |
| |
| - spin_lock_irqsave(&bank->lock, flags); |
| + raw_spin_lock_irqsave(&bank->lock, flags); |
| if (trigger) |
| omap_set_gpio_triggering(bank, offset, trigger); |
| |
| @@ -861,7 +861,7 @@ static void omap_gpio_unmask_irq(struct |
| } |
| |
| omap_set_gpio_irqenable(bank, offset, 1); |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| } |
| |
| /*---------------------------------------------------------------------*/ |
| @@ -874,9 +874,9 @@ static int omap_mpuio_suspend_noirq(stru |
| OMAP_MPUIO_GPIO_MASKIT / bank->stride; |
| unsigned long flags; |
| |
| - spin_lock_irqsave(&bank->lock, flags); |
| + raw_spin_lock_irqsave(&bank->lock, flags); |
| writel_relaxed(0xffff & ~bank->context.wake_en, mask_reg); |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| |
| return 0; |
| } |
| @@ -889,9 +889,9 @@ static int omap_mpuio_resume_noirq(struc |
| OMAP_MPUIO_GPIO_MASKIT / bank->stride; |
| unsigned long flags; |
| |
| - spin_lock_irqsave(&bank->lock, flags); |
| + raw_spin_lock_irqsave(&bank->lock, flags); |
| writel_relaxed(bank->context.wake_en, mask_reg); |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| |
| return 0; |
| } |
| @@ -937,9 +937,9 @@ static int omap_gpio_get_direction(struc |
| |
| bank = container_of(chip, struct gpio_bank, chip); |
| reg = bank->base + bank->regs->direction; |
| - spin_lock_irqsave(&bank->lock, flags); |
| + raw_spin_lock_irqsave(&bank->lock, flags); |
| dir = !!(readl_relaxed(reg) & BIT(offset)); |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| return dir; |
| } |
| |
| @@ -949,9 +949,9 @@ static int omap_gpio_input(struct gpio_c |
| unsigned long flags; |
| |
| bank = container_of(chip, struct gpio_bank, chip); |
| - spin_lock_irqsave(&bank->lock, flags); |
| + raw_spin_lock_irqsave(&bank->lock, flags); |
| omap_set_gpio_direction(bank, offset, 1); |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| return 0; |
| } |
| |
| @@ -973,10 +973,10 @@ static int omap_gpio_output(struct gpio_ |
| unsigned long flags; |
| |
| bank = container_of(chip, struct gpio_bank, chip); |
| - spin_lock_irqsave(&bank->lock, flags); |
| + raw_spin_lock_irqsave(&bank->lock, flags); |
| bank->set_dataout(bank, offset, value); |
| omap_set_gpio_direction(bank, offset, 0); |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| return 0; |
| } |
| |
| @@ -988,9 +988,9 @@ static int omap_gpio_debounce(struct gpi |
| |
| bank = container_of(chip, struct gpio_bank, chip); |
| |
| - spin_lock_irqsave(&bank->lock, flags); |
| + raw_spin_lock_irqsave(&bank->lock, flags); |
| omap2_set_gpio_debounce(bank, offset, debounce); |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| |
| return 0; |
| } |
| @@ -1001,9 +1001,9 @@ static void omap_gpio_set(struct gpio_ch |
| unsigned long flags; |
| |
| bank = container_of(chip, struct gpio_bank, chip); |
| - spin_lock_irqsave(&bank->lock, flags); |
| + raw_spin_lock_irqsave(&bank->lock, flags); |
| bank->set_dataout(bank, offset, value); |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| } |
| |
| /*---------------------------------------------------------------------*/ |
| @@ -1199,7 +1199,7 @@ static int omap_gpio_probe(struct platfo |
| else |
| bank->set_dataout = omap_set_gpio_dataout_mask; |
| |
| - spin_lock_init(&bank->lock); |
| + raw_spin_lock_init(&bank->lock); |
| |
| /* Static mapping, never released */ |
| res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| @@ -1246,7 +1246,7 @@ static int omap_gpio_runtime_suspend(str |
| unsigned long flags; |
| u32 wake_low, wake_hi; |
| |
| - spin_lock_irqsave(&bank->lock, flags); |
| + raw_spin_lock_irqsave(&bank->lock, flags); |
| |
| /* |
| * Only edges can generate a wakeup event to the PRCM. |
| @@ -1299,7 +1299,7 @@ static int omap_gpio_runtime_suspend(str |
| bank->get_context_loss_count(bank->dev); |
| |
| omap_gpio_dbck_disable(bank); |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| |
| return 0; |
| } |
| @@ -1314,7 +1314,7 @@ static int omap_gpio_runtime_resume(stru |
| unsigned long flags; |
| int c; |
| |
| - spin_lock_irqsave(&bank->lock, flags); |
| + raw_spin_lock_irqsave(&bank->lock, flags); |
| |
| /* |
| * On the first resume during the probe, the context has not |
| @@ -1350,14 +1350,14 @@ static int omap_gpio_runtime_resume(stru |
| if (c != bank->context_loss_count) { |
| omap_gpio_restore_context(bank); |
| } else { |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| return 0; |
| } |
| } |
| } |
| |
| if (!bank->workaround_enabled) { |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| return 0; |
| } |
| |
| @@ -1412,7 +1412,7 @@ static int omap_gpio_runtime_resume(stru |
| } |
| |
| bank->workaround_enabled = false; |
| - spin_unlock_irqrestore(&bank->lock, flags); |
| + raw_spin_unlock_irqrestore(&bank->lock, flags); |
| |
| return 0; |
| } |