Commit bc6b54931d1750b75592c5fb5d8f89fd73ae3139

Authored by Grygorii Strashko
Committed by Tero Kristo
1 parent d8b79f86dd

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

Cc: <linux-rt-users@vger.kernel.org>
Tested-by: Tony Lindgren <tony@atomide.com>
Tested-by: Austin Schuh <austin@peloton-tech.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>

Showing 1 changed file with 27 additions and 28 deletions Side-by-side Diff

drivers/gpio/gpio-omap.c
... ... @@ -59,6 +59,7 @@
59 59 u32 level_mask;
60 60 u32 toggle_mask;
61 61 raw_spinlock_t lock;
  62 + raw_spinlock_t wa_lock;
62 63 struct gpio_chip chip;
63 64 struct clk *dbck;
64 65 u32 mod_usage;
65 66  
... ... @@ -649,8 +650,13 @@
649 650 {
650 651 struct gpio_bank *bank = omap_irq_data_get_bank(d);
651 652 unsigned offset = d->hwirq;
  653 + int ret;
652 654  
653   - return omap_set_gpio_wakeup(bank, offset, enable);
  655 + ret = omap_set_gpio_wakeup(bank, offset, enable);
  656 + if (!ret)
  657 + ret = irq_set_irq_wake(bank->irq, enable);
  658 +
  659 + return ret;
654 660 }
655 661  
656 662 static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
657 663  
658 664  
659 665  
660 666  
... ... @@ -704,26 +710,21 @@
704 710 * line's interrupt handler has been run, we may miss some nested
705 711 * interrupts.
706 712 */
707   -static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
  713 +static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
708 714 {
709 715 void __iomem *isr_reg = NULL;
710 716 u32 isr;
711 717 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_get_handler_data(irq);
  718 + struct gpio_bank *bank = gpiobank;
  719 + unsigned long wa_lock_flags;
716 720 unsigned long lock_flags;
717 721  
718   - chained_irq_enter(irqchip, desc);
719   -
720   - bank = container_of(chip, struct gpio_bank, chip);
721 722 isr_reg = bank->base + bank->regs->irqstatus;
722   - pm_runtime_get_sync(bank->dev);
723   -
724 723 if (WARN_ON(!isr_reg))
725 724 goto exit;
726 725  
  726 + pm_runtime_get_sync(bank->dev);
  727 +
727 728 while (1) {
728 729 u32 isr_saved, level_mask = 0;
729 730 u32 enabled;
... ... @@ -745,13 +746,6 @@
745 746  
746 747 raw_spin_unlock_irqrestore(&bank->lock, lock_flags);
747 748  
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   -
755 749 if (!isr)
756 750 break;
757 751  
758 752  
759 753  
760 754  
761 755  
... ... @@ -772,18 +766,18 @@
772 766  
773 767 raw_spin_unlock_irqrestore(&bank->lock, lock_flags);
774 768  
  769 + raw_spin_lock_irqsave(&bank->wa_lock, wa_lock_flags);
  770 +
775 771 generic_handle_irq(irq_find_mapping(bank->chip.irqdomain,
776 772 bit));
  773 +
  774 + raw_spin_unlock_irqrestore(&bank->wa_lock,
  775 + wa_lock_flags);
777 776 }
778 777 }
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 */
783 778 exit:
784   - if (!unmasked)
785   - chained_irq_exit(irqchip, desc);
786 779 pm_runtime_put(bank->dev);
  780 + return IRQ_HANDLED;
787 781 }
788 782  
789 783 static unsigned int omap_gpio_irq_startup(struct irq_data *d)
... ... @@ -1135,7 +1129,7 @@
1135 1129 }
1136 1130  
1137 1131 ret = gpiochip_irqchip_add(&bank->chip, irqc,
1138   - irq_base, omap_gpio_irq_handler,
  1132 + irq_base, handle_bad_irq,
1139 1133 IRQ_TYPE_NONE);
1140 1134  
1141 1135 if (ret) {
1142 1136  
... ... @@ -1144,10 +1138,14 @@
1144 1138 return -ENODEV;
1145 1139 }
1146 1140  
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);
1149 1142  
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;
1151 1149 }
1152 1150  
1153 1151 static const struct of_device_id omap_gpio_match[];
... ... @@ -1223,6 +1221,7 @@
1223 1221 bank->set_dataout = omap_set_gpio_dataout_mask;
1224 1222  
1225 1223 raw_spin_lock_init(&bank->lock);
  1224 + raw_spin_lock_init(&bank->wa_lock);
1226 1225  
1227 1226 /* Static mapping, never released */
1228 1227 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);