linux/drivers
Lars-Peter Clausen 6dd8595083 gpio: zynq: Fix IRQ handlers
The Zynq GPIO interrupt handling code as two main issues:
1) It does not support IRQF_ONESHOT interrupt since it uses handle_simple_irq()
for the interrupt handler. handle_simple_irq() does not do masking and unmasking
of the IRQ that is required for this chip to be able to support IRQF_ONESHOT
IRQs, causing the CPU to lock up in a interrupt storm if such a interrupt is
requested.
2) Interrupts are acked after the primary interrupt handlers for all asserted
interrupts in a bank have been called. For edge triggered interrupt this is to
late and may cause a interrupt to be missed. For level triggered oneshot
interrupts this is to early and causes the interrupt handler to run twice per
interrupt.

This patch addresses the issue by updating the driver to use the correct IRQ
chip handler functions that are appropriate for this kind of IRQ controller.

The following diagram gives an overview of how the interrupt detection circuit
works, it is not necessarily a accurate depiction of the real hardware though.

     INT_POL/INT_ON_ANY
           |
           | +---+                       INT_STATUS
           `-|   |                            |
             | E |-.                          |
         ,---|   |  \     |\          +----+  |  +---+
         |   +---+   `----| | ,-------|S   | ,*--|   |
GPIO_IN -*                | |-        |   Q|-    | & |-- IRQ_OUT
         |   +---+  ,-----| |       ,-|R   |   ,o|   |
         `---|   | /      |/       |  +----+  |  +---+
             | = |-        |       |          |
           ,-|   |    INT_TYPE    ACK     INT_MASK
           | +---+
           |
        INT_POL

GPIO_IN is the raw signal level connected to the hardware pin. This signal is
routed to a edge detector and to a level detector. The edge detector can be
configured to either detect a rising or falling edge or both edges. The level
detector can detect either a level high or level low event. Depending on the
setting of the INT_TYPE register either the edge or level event will be
propagated to the INT_STATUS register. As long as a interrupt condition is
detected the INT_STATUS register will be set to 1. It can be cleared to 0 if
(and only if) the interrupt condition is no longer detected and software
acknowledges the interrupt by writing a 1 to the address of the INT_STATUS
register. There is also the INT_MASK register which can be used to disable the
propagation of the INT_STATUS signal to the upstream IRQ controller. What is
important to note is that the interrupt detection logic itself can not be
disabled, only the propagation of the INT_STATUS register can be delayed. This
means that for level type interrupts the interrupt must only be acknowledged
after the interrupt source has been cleared otherwise it will stay asserted and
the interrupt handler will be run a second time. For IRQF_ONESHOT interrupts
this means that the IRQ must only be acknowledged after the threaded interrupt
has finished running. If a second interrupt comes in between handling the first
interrupt and acknowledging it the external interrupt will be asserted, which
means trying to acknowledge the first interrupt will not clear the INT_STATUS
register and the interrupt handler will be run a second time when the IRQ is
unmasked, so no interrupts will be lost. The handle_fasteoi_irq() handler in
combination with the IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED flags will
have the desired behavior. For edge triggered interrupts a slightly different
strategy is necessary. For edge triggered interrupts the interrupt condition is
only true when the edge itself is detected, this means this is the only time the
INT_STATUS register is set, acknowledging the interrupt any time after that will
clear the INT_STATUS register until the next interrupt happens. This means in
order to not loose any interrupts the interrupt needs to be acknowledged before
running the interrupt handler. If a second interrupt occurs after the first
interrupt handler has finished but before the interrupt is unmasked the
INT_STATUS register will be re-asserted and the interrupt handler runs a second
time once the interrupt is unmasked. This means with this flow handling strategy
no interrupts are lost for edge triggered interrupts. The handle_level_irq()
handler will have the desired behavior. (Note: The handle_edge_irq() only needs
to be used for edge triggered interrupts where the controller stops detecting
the interrupt event when the interrupt is masked, for this controller the
detection logic still works, while only the propagation is delayed when the
interrupt is masked.)

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Acked-by: Soren Brinkmann <soren.brinkmann@xilinx.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2014-08-17 09:12:35 -05:00
..
accessibility
acpi More ACPI and power management updates for 3.17-rc1 2014-08-14 18:13:46 -06:00
amba
ata Merge branch 'akpm' (patchbomb from Andrew Morton) 2014-08-06 21:14:42 -07:00
atm Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2014-08-13 18:27:40 -06:00
auxdisplay
base Merge branch 'akpm' (patchbomb from Andrew Morton) 2014-08-06 21:14:42 -07:00
bcma bcma: use NS prefix for names of Northstar specific cores 2014-07-31 13:45:32 -04:00
block PCI changes for the v3.17 merge window (part 2): 2014-08-14 18:10:33 -06:00
bluetooth Bluetooth: Fix crash in the Marvell driver initialization codepath 2014-07-31 01:07:28 +02:00
bus ARM: SoC driver changes for 3.17 2014-08-08 11:34:32 -07:00
cdrom
char virtio: rng: add derating factor for use by hwrng core 2014-08-15 10:26:01 +05:30
clk ARM: SoC platform changes for 3.17 2014-08-08 11:14:29 -07:00
clocksource ARM: SoC platform changes for 3.17 2014-08-08 11:14:29 -07:00
connector
cpufreq More ACPI and power management updates for 3.17-rc1 2014-08-14 18:13:46 -06:00
cpuidle More ACPI and power management updates for 3.17-rc1 2014-08-14 18:13:46 -06:00
crypto PCI changes for the v3.17 merge window (part 2): 2014-08-14 18:10:33 -06:00
dca
devfreq
dio
dma Merge branch 'for-linus' of git://git.infradead.org/users/vkoul/slave-dma 2014-08-11 07:14:01 -07:00
dma-buf
edac Merge branch 'linux_next' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac 2014-08-15 17:56:45 -06:00
eisa
extcon
firewire Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next 2014-08-06 09:38:14 -07:00
firmware kexec: support kexec/kdump on EFI systems 2014-08-08 15:57:33 -07:00
fmc
gpio gpio: zynq: Fix IRQ handlers 2014-08-17 09:12:35 -05:00
gpu Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux 2014-08-15 17:57:49 -06:00
hid Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input 2014-08-15 18:16:28 -06:00
hsi HSI changes for the v3.17 series 2014-08-06 20:06:14 -07:00
hv Char / Misc driver patches for 3.17-rc1 2014-08-04 17:32:24 -07:00
hwmon Several bug fixes in various drivers, plus a minor cleanup 2014-08-14 09:55:13 -06:00
hwspinlock
i2c Merge branch 'i2c/for-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux 2014-08-09 09:15:07 -07:00
ide ide: use module_platform_driver() 2014-08-05 21:16:46 -07:00
idle intel_idle: Broadwell support 2014-08-15 17:06:40 -04:00
iio Staging driver patches for 3.17-rc1 2014-08-04 18:36:12 -07:00
infiniband PCI changes for the v3.17 merge window (part 2): 2014-08-14 18:10:33 -06:00
input Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input 2014-08-15 18:16:28 -06:00
iommu ARM: SoC cleanups for 3.17 2014-08-08 11:00:26 -07:00
ipack
irqchip ARM: SoC platform changes for 3.17 2014-08-08 11:14:29 -07:00
isdn net: filter: split 'struct sk_filter' into socket and bpf parts 2014-08-02 15:03:58 -07:00
leds ARM: SoC driver changes for 3.17 2014-08-08 11:34:32 -07:00
lguest mm/vmalloc.c: clean up map_vm_area third argument 2014-08-06 18:01:19 -07:00
macintosh == Changes to existing drivers == 2014-08-07 17:23:16 -07:00
mailbox
mcb
md . Allow the thin target to paired with any size external origin; also 2014-08-14 09:17:56 -06:00
media media: use pci_zalloc_consistent 2014-08-08 15:57:28 -07:00
memory
memstick
message
mfd drivers/mfd/rtsx_usb.c: export device table 2014-08-14 10:56:15 -06:00
misc ARM: SoC driver changes for 3.17 2014-08-08 11:34:32 -07:00
mmc PCI changes for the v3.17 merge window (part 2): 2014-08-14 18:10:33 -06:00
mtd No significant changes, mostly small fixes here and there. The more important 2014-08-13 17:42:11 -06:00
net PCI changes for the v3.17 merge window (part 2): 2014-08-14 18:10:33 -06:00
nfc
ntb
nubus
of The branch contains the following device tree changes the v3.17 merge 2014-08-14 09:53:39 -06:00
oprofile
parisc
parport drivers/parport/parport_ip32.c: use PTR_ERR_OR_ZERO 2014-08-08 15:57:25 -07:00
pci PCI changes for the v3.17 merge window (part 2): 2014-08-14 18:10:33 -06:00
pcmcia Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc 2014-08-07 08:50:34 -07:00
phy ARM: SoC driver changes for 3.17 2014-08-08 11:34:32 -07:00
pinctrl ARM: SoC driver changes for 3.17 2014-08-08 11:34:32 -07:00
platform platform/x86: Enable build support for toshiba_haps 2014-08-16 01:23:56 -07:00
pnp
power ARM: SoC platform changes for 3.17 2014-08-08 11:14:29 -07:00
powercap
pps
ps3
ptp PCI: Remove DEFINE_PCI_DEVICE_TABLE macro use 2014-08-12 12:15:14 -06:00
pwm pwm: Changes for v3.17-rc1 2014-08-08 18:06:29 -07:00
rapidio PCI: Remove DEFINE_PCI_DEVICE_TABLE macro use 2014-08-12 12:15:14 -06:00
ras
regulator == Changes to existing drivers == 2014-08-07 17:17:39 -07:00
remoteproc
reset
rpmsg
rtc Merge branch 'akpm' (second patchbomb from Andrew Morton) 2014-08-08 15:57:47 -07:00
s390 Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux 2014-08-07 08:41:00 -07:00
sbus Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc 2014-08-05 18:57:18 -07:00
scsi SCSI misc on 20140815 2014-08-15 18:28:58 -06:00
sfi
sh
sn
soc
spi ARM: SoC cleanups for 3.17 2014-08-08 11:00:26 -07:00
spmi
ssb
staging Merge branch 'akpm' (second patchbomb from Andrew Morton) 2014-08-08 15:57:47 -07:00
target SCSI misc on 20140806 2014-08-06 20:10:32 -07:00
tc
thermal
thunderbolt
tty The branch contains the following device tree changes the v3.17 merge 2014-08-14 09:53:39 -06:00
uio
usb Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial 2014-08-06 21:03:53 -07:00
uwb uwb/whci: use correct structure type name in sizeof 2014-08-01 15:48:08 -07:00
vfio drivers/vfio: Enable VFIO if EEH is not supported 2014-08-08 10:39:16 -06:00
vhost
video PCI: Remove DEFINE_PCI_DEVICE_TABLE macro use 2014-08-12 12:15:14 -06:00
virt
virtio
vlynq
vme vme: bridges: use pci_zalloc_consistent 2014-08-08 15:57:30 -07:00
w1
watchdog Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus 2014-08-07 08:47:00 -07:00
xen PCI: Remove DEFINE_PCI_DEVICE_TABLE macro use 2014-08-12 12:15:14 -06:00
zorro
Kconfig Char / Misc driver patches for 3.17-rc1 2014-08-04 17:32:24 -07:00
Makefile Driver core patches for 3.17-rc1 2014-08-04 18:34:04 -07:00