Skip to content

Commit 450fa54

Browse files
grygoriySlinusw
authored andcommitted
gpio: omap: convert to use generic irq handler
This patch converts TI OMAP GPIO driver to use generic irq handler instead of chained IRQ handler. This way OMAP GPIO driver will be compatible with RT kernel where it will be forced thread IRQ handler while in non-RT kernel it still will be executed in HW IRQ context. As part of this change the IRQ wakeup configuration is applied to GPIO Bank IRQ as it now will be under control of IRQ PM Core during suspend. There are also additional benefits: - on-RT kernel there will be no complains any more about PM runtime usage in atomic context "BUG: sleeping function called from invalid context"; - GPIO bank IRQs will appear in /proc/interrupts and its usage statistic will be visible; - GPIO bank IRQs could be configured through IRQ proc_fs interface and, as result, could be a part of IRQ balancing process if needed; - GPIO bank IRQs will be under control of IRQ PM Core during suspend to RAM. Disadvantage: - additional runtime overhed as call chain till omap_gpio_irq_handler() will be longer now - necessity to use wa_lock in omap_gpio_irq_handler() to W/A warning in handle_irq_event_percpu() WARNING: CPU: 1 PID: 35 at kernel/irq/handle.c:149 handle_irq_event_percpu+0x51c/0x638() This patch doesn't fully follows recommendations provided by Sebastian Andrzej Siewior [1], because It's required to go through and check all GPIO IRQ pin states as fast as possible and pass control to handle_level_irq or handle_edge_irq. handle_level_irq or handle_edge_irq will perform actions specific for IRQ triggering type and wakeup corresponding registered threaded IRQ handler (at least it's expected to be threaded). IRQs can be lost if handle_nested_irq() will be used, because excecution time of some pin specific GPIO IRQ handler can be very significant and require accessing ext. devices (I2C). Idea of such kind reworking was also discussed in [2]. [1] http://www.spinics.net/lists/linux-omap/msg120665.html [2] http://www.spinics.net/lists/linux-omap/msg119516.html Tested-by: Tony Lindgren <tony@atomide.com> Tested-by: Austin Schuh <austin@peloton-tech.com> Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> Acked-by: Santosh Shilimkar <ssantosh@kernel.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
1 parent aca82d1 commit 450fa54

File tree

1 file changed

+27
-28
lines changed

1 file changed

+27
-28
lines changed

drivers/gpio/gpio-omap.c

+27-28
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ struct gpio_bank {
5959
u32 level_mask;
6060
u32 toggle_mask;
6161
raw_spinlock_t lock;
62+
raw_spinlock_t wa_lock;
6263
struct gpio_chip chip;
6364
struct clk *dbck;
6465
u32 mod_usage;
@@ -649,8 +650,13 @@ static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable)
649650
{
650651
struct gpio_bank *bank = omap_irq_data_get_bank(d);
651652
unsigned offset = d->hwirq;
653+
int ret;
654+
655+
ret = omap_set_gpio_wakeup(bank, offset, enable);
656+
if (!ret)
657+
ret = irq_set_irq_wake(bank->irq, enable);
652658

653-
return omap_set_gpio_wakeup(bank, offset, enable);
659+
return ret;
654660
}
655661

656662
static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -704,26 +710,21 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
704710
* line's interrupt handler has been run, we may miss some nested
705711
* interrupts.
706712
*/
707-
static void omap_gpio_irq_handler(struct irq_desc *desc)
713+
static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
708714
{
709715
void __iomem *isr_reg = NULL;
710716
u32 isr;
711717
unsigned int bit;
712-
struct gpio_bank *bank;
713-
int unmasked = 0;
714-
struct irq_chip *irqchip = irq_desc_get_chip(desc);
715-
struct gpio_chip *chip = irq_desc_get_handler_data(desc);
718+
struct gpio_bank *bank = gpiobank;
719+
unsigned long wa_lock_flags;
716720
unsigned long lock_flags;
717721

718-
chained_irq_enter(irqchip, desc);
719-
720-
bank = container_of(chip, struct gpio_bank, chip);
721722
isr_reg = bank->base + bank->regs->irqstatus;
722-
pm_runtime_get_sync(bank->dev);
723-
724723
if (WARN_ON(!isr_reg))
725724
goto exit;
726725

726+
pm_runtime_get_sync(bank->dev);
727+
727728
while (1) {
728729
u32 isr_saved, level_mask = 0;
729730
u32 enabled;
@@ -745,13 +746,6 @@ static void omap_gpio_irq_handler(struct irq_desc *desc)
745746

746747
raw_spin_unlock_irqrestore(&bank->lock, lock_flags);
747748

748-
/* if there is only edge sensitive GPIO pin interrupts
749-
configured, we could unmask GPIO bank interrupt immediately */
750-
if (!level_mask && !unmasked) {
751-
unmasked = 1;
752-
chained_irq_exit(irqchip, desc);
753-
}
754-
755749
if (!isr)
756750
break;
757751

@@ -772,18 +766,18 @@ static void omap_gpio_irq_handler(struct irq_desc *desc)
772766

773767
raw_spin_unlock_irqrestore(&bank->lock, lock_flags);
774768

769+
raw_spin_lock_irqsave(&bank->wa_lock, wa_lock_flags);
770+
775771
generic_handle_irq(irq_find_mapping(bank->chip.irqdomain,
776772
bit));
773+
774+
raw_spin_unlock_irqrestore(&bank->wa_lock,
775+
wa_lock_flags);
777776
}
778777
}
779-
/* if bank has any level sensitive GPIO pin interrupt
780-
configured, we must unmask the bank interrupt only after
781-
handler(s) are executed in order to avoid spurious bank
782-
interrupt */
783778
exit:
784-
if (!unmasked)
785-
chained_irq_exit(irqchip, desc);
786779
pm_runtime_put(bank->dev);
780+
return IRQ_HANDLED;
787781
}
788782

789783
static unsigned int omap_gpio_irq_startup(struct irq_data *d)
@@ -1135,7 +1129,7 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
11351129
}
11361130

11371131
ret = gpiochip_irqchip_add(&bank->chip, irqc,
1138-
irq_base, omap_gpio_irq_handler,
1132+
irq_base, handle_bad_irq,
11391133
IRQ_TYPE_NONE);
11401134

11411135
if (ret) {
@@ -1144,10 +1138,14 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
11441138
return -ENODEV;
11451139
}
11461140

1147-
gpiochip_set_chained_irqchip(&bank->chip, irqc,
1148-
bank->irq, omap_gpio_irq_handler);
1141+
gpiochip_set_chained_irqchip(&bank->chip, irqc, bank->irq, NULL);
11491142

1150-
return 0;
1143+
ret = devm_request_irq(bank->dev, bank->irq, omap_gpio_irq_handler,
1144+
0, dev_name(bank->dev), bank);
1145+
if (ret)
1146+
gpiochip_remove(&bank->chip);
1147+
1148+
return ret;
11511149
}
11521150

11531151
static const struct of_device_id omap_gpio_match[];
@@ -1229,6 +1227,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
12291227
bank->set_dataout = omap_set_gpio_dataout_mask;
12301228

12311229
raw_spin_lock_init(&bank->lock);
1230+
raw_spin_lock_init(&bank->wa_lock);
12321231

12331232
/* Static mapping, never released */
12341233
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

0 commit comments

Comments
 (0)