mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 11:41:38 -04:00
gpio: simplify adding threaded interrupts
This tries to simplify the use of CONFIG_GPIOLIB_IRQCHIP when using threaded interrupts: add a new call gpiochip_irqchip_add_nested() to indicate that we're dealing with a nested rather than a chained irqchip, then create a separate gpiochip_set_nested_irqchip() to mirror the gpiochip_set_chained_irqchip() call to connect the parent and child interrupts. In the nested case gpiochip_set_nested_irqchip() does nothing more than call irq_set_parent() on each valid child interrupt, which has little semantic effect in the kernel, but this is probably still formally correct. Update all drivers using nested interrupts to use gpiochip_irqchip_add_nested() so we can now see clearly which these users are. The DLN2 driver can drop its specific hack with .irq_not_threaded as we now recognize whether a chip is threaded or not from its use of gpiochip_irqchip_add_nested() signature rather than from inspecting .can_sleep. We rename the .irq_parent to .irq_chained_parent since this parent IRQ is only really kept around for the chained interrupt handlers. Cc: Lars Poeschel <[email protected]> Cc: Octavian Purdila <[email protected]> Cc: Daniel Baluta <[email protected]> Cc: Bin Gao <[email protected]> Cc: Mika Westerberg <[email protected]> Cc: Ajay Thomas <[email protected]> Cc: Semen Protsenko <[email protected]> Cc: Alexander Stein <[email protected]> Cc: Phil Reid <[email protected]> Cc: Bartosz Golaszewski <[email protected]> Cc: Patrice Chotard <[email protected]> Signed-off-by: Linus Walleij <[email protected]>
This commit is contained in:
parent
07d9a38068
commit
d245b3f9bd
13 changed files with 171 additions and 106 deletions
|
|
@ -175,8 +175,8 @@ The IRQ portions of the GPIO block are implemented using an irqchip, using
|
|||
the header <linux/irq.h>. So basically such a driver is utilizing two sub-
|
||||
systems simultaneously: gpio and irq.
|
||||
|
||||
RT_FULL: GPIO driver should not use spinlock_t or any sleepable APIs
|
||||
(like PM runtime) as part of its irq_chip implementation on -RT.
|
||||
RT_FULL: a realtime compliant GPIO driver should not use spinlock_t or any
|
||||
sleepable APIs (like PM runtime) as part of its irq_chip implementation.
|
||||
- spinlock_t should be replaced with raw_spinlock_t [1].
|
||||
- If sleepable APIs have to be used, these can be done from the .irq_bus_lock()
|
||||
and .irq_bus_unlock() callbacks, as these are the only slowpath callbacks
|
||||
|
|
@ -185,33 +185,32 @@ RT_FULL: GPIO driver should not use spinlock_t or any sleepable APIs
|
|||
GPIO irqchips usually fall in one of two categories:
|
||||
|
||||
* CHAINED GPIO irqchips: these are usually the type that is embedded on
|
||||
an SoC. This means that there is a fast IRQ handler for the GPIOs that
|
||||
an SoC. This means that there is a fast IRQ flow handler for the GPIOs that
|
||||
gets called in a chain from the parent IRQ handler, most typically the
|
||||
system interrupt controller. This means the GPIO irqchip is registered
|
||||
using irq_set_chained_handler() or the corresponding
|
||||
gpiochip_set_chained_irqchip() helper function, and the GPIO irqchip
|
||||
handler will be called immediately from the parent irqchip, while
|
||||
holding the IRQs disabled. The GPIO irqchip will then end up calling
|
||||
something like this sequence in its interrupt handler:
|
||||
system interrupt controller. This means that the GPIO irqchip handler will
|
||||
be called immediately from the parent irqchip, while holding the IRQs
|
||||
disabled. The GPIO irqchip will then end up calling something like this
|
||||
sequence in its interrupt handler:
|
||||
|
||||
static irqreturn_t tc3589x_gpio_irq(int irq, void *data)
|
||||
static irqreturn_t foo_gpio_irq(int irq, void *data)
|
||||
chained_irq_enter(...);
|
||||
generic_handle_irq(...);
|
||||
chained_irq_exit(...);
|
||||
|
||||
Chained GPIO irqchips typically can NOT set the .can_sleep flag on
|
||||
struct gpio_chip, as everything happens directly in the callbacks.
|
||||
struct gpio_chip, as everything happens directly in the callbacks: no
|
||||
slow bus traffic like I2C can be used.
|
||||
|
||||
RT_FULL: Note, chained IRQ handlers will not be forced threaded on -RT.
|
||||
As result, spinlock_t or any sleepable APIs (like PM runtime) can't be used
|
||||
in chained IRQ handler.
|
||||
if required (and if it can't be converted to the nested threaded GPIO irqchip)
|
||||
- chained IRQ handler can be converted to generic irq handler and this way
|
||||
it will be threaded IRQ handler on -RT and hard IRQ handler on non-RT
|
||||
If required (and if it can't be converted to the nested threaded GPIO irqchip)
|
||||
a chained IRQ handler can be converted to generic irq handler and this way
|
||||
it will be a threaded IRQ handler on -RT and a hard IRQ handler on non-RT
|
||||
(for example, see [3]).
|
||||
Know W/A: The generic_handle_irq() is expected to be called with IRQ disabled,
|
||||
so IRQ core will complain if it will be called from IRQ handler which is
|
||||
forced thread. The "fake?" raw lock can be used to W/A this problem:
|
||||
so the IRQ core will complain if it is called from an IRQ handler which is
|
||||
forced to a thread. The "fake?" raw lock can be used to W/A this problem:
|
||||
|
||||
raw_spinlock_t wa_lock;
|
||||
static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
|
||||
|
|
@ -243,7 +242,7 @@ GPIO irqchips usually fall in one of two categories:
|
|||
by the driver. The hallmark of this driver is to call something like
|
||||
this in its interrupt handler:
|
||||
|
||||
static irqreturn_t tc3589x_gpio_irq(int irq, void *data)
|
||||
static irqreturn_t foo_gpio_irq(int irq, void *data)
|
||||
...
|
||||
handle_nested_irq(irq);
|
||||
|
||||
|
|
@ -256,23 +255,31 @@ associated irqdomain and resource allocation callbacks, the gpiolib has
|
|||
some helpers that can be enabled by selecting the GPIOLIB_IRQCHIP Kconfig
|
||||
symbol:
|
||||
|
||||
* gpiochip_irqchip_add(): adds an irqchip to a gpiochip. It will pass
|
||||
* gpiochip_irqchip_add(): adds a chained irqchip to a gpiochip. It will pass
|
||||
the struct gpio_chip* for the chip to all IRQ callbacks, so the callbacks
|
||||
need to embed the gpio_chip in its state container and obtain a pointer
|
||||
to the container using container_of().
|
||||
(See Documentation/driver-model/design-patterns.txt)
|
||||
|
||||
If there is a need to exclude certain GPIOs from the IRQ domain, one can
|
||||
set .irq_need_valid_mask of the gpiochip before gpiochip_add_data() is
|
||||
called. This allocates .irq_valid_mask with as many bits set as there are
|
||||
GPIOs in the chip. Drivers can exclude GPIOs by clearing bits from this
|
||||
mask. The mask must be filled in before gpiochip_irqchip_add() is called.
|
||||
* gpiochip_irqchip_add_nested(): adds a nested irqchip to a gpiochip.
|
||||
Apart from that it works exactly like the chained irqchip.
|
||||
|
||||
* gpiochip_set_chained_irqchip(): sets up a chained irq handler for a
|
||||
gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler
|
||||
data. (Notice handler data, since the irqchip data is likely used by the
|
||||
parent irqchip!) This is for the chained type of chip. This is also used
|
||||
to set up a nested irqchip if NULL is passed as handler.
|
||||
parent irqchip!).
|
||||
|
||||
* gpiochip_set_nested_irqchip(): sets up a nested irq handler for a
|
||||
gpio_chip from a parent IRQ. As the parent IRQ has usually been
|
||||
explicitly requested by the driver, this does very little more than
|
||||
mark all the child IRQs as having the other IRQ as parent.
|
||||
|
||||
If there is a need to exclude certain GPIOs from the IRQ domain, you can
|
||||
set .irq_need_valid_mask of the gpiochip before gpiochip_add_data() is
|
||||
called. This allocates an .irq_valid_mask with as many bits set as there
|
||||
are GPIOs in the chip. Drivers can exclude GPIOs by clearing bits from this
|
||||
mask. The mask must be filled in before gpiochip_irqchip_add() or
|
||||
gpiochip_irqchip_add_nested() is called.
|
||||
|
||||
To use the helpers please keep the following in mind:
|
||||
|
||||
|
|
@ -323,6 +330,9 @@ When implementing an irqchip inside a GPIO driver, these two functions should
|
|||
typically be called in the .startup() and .shutdown() callbacks from the
|
||||
irqchip.
|
||||
|
||||
When using the gpiolib irqchip helpers, these callback are automatically
|
||||
assigned.
|
||||
|
||||
Real-Time compliance for GPIO IRQ chips
|
||||
---------------------------------------
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue