summaryrefslogtreecommitdiffstats
path: root/kernel/irq/chip.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2015-10-09 23:28:58 +0200
committerThomas Gleixner <tglx@linutronix.de>2015-10-11 11:33:42 +0200
commite9849777d0e27cdd2902805be51da73e7c79578c (patch)
tree398bab5d6a91973d2e8a281bae6dff8ebd57ac8b /kernel/irq/chip.c
parentfcf8ab690e3decf8335c51fdabea773a3f5ea026 (diff)
downloadlinux-e9849777d0e27cdd2902805be51da73e7c79578c.tar.gz
linux-e9849777d0e27cdd2902805be51da73e7c79578c.tar.bz2
linux-e9849777d0e27cdd2902805be51da73e7c79578c.zip
genirq: Add flag to force mask in disable_irq[_nosync]()
If an irq chip does not implement the irq_disable callback, then we use a lazy approach for disabling the interrupt. That means that the interrupt is marked disabled, but the interrupt line is not immediately masked in the interrupt chip. It only becomes masked if the interrupt is raised while it's marked disabled. We use this to avoid possibly expensive mask/unmask operations for common case operations. Unfortunately there are devices which do not allow the interrupt to be disabled easily at the device level. They are forced to use disable_irq_nosync(). This can result in taking each interrupt twice. Instead of enforcing the non lazy mode on all interrupts of a irq chip, provide a settings flag, which can be set by the driver for that particular interrupt line. Reported-and-tested-by: Duc Dang <dhdang@apm.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Marc Zyngier <marc.zyngier@arm.com> Cc: Jason Cooper <jason@lakedaemon.net> Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1510092348370.6097@nanos
Diffstat (limited to 'kernel/irq/chip.c')
-rw-r--r--kernel/irq/chip.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 4aa00d325b8c..15206453b12a 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -241,6 +241,13 @@ void irq_enable(struct irq_desc *desc)
* disabled. If an interrupt happens, then the interrupt flow
* handler masks the line at the hardware level and marks it
* pending.
+ *
+ * If the interrupt chip does not implement the irq_disable callback,
+ * a driver can disable the lazy approach for a particular irq line by
+ * calling 'irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY)'. This can
+ * be used for devices which cannot disable the interrupt at the
+ * device level under certain circumstances and have to use
+ * disable_irq[_nosync] instead.
*/
void irq_disable(struct irq_desc *desc)
{
@@ -248,6 +255,8 @@ void irq_disable(struct irq_desc *desc)
if (desc->irq_data.chip->irq_disable) {
desc->irq_data.chip->irq_disable(&desc->irq_data);
irq_state_set_masked(desc);
+ } else if (irq_settings_disable_unlazy(desc)) {
+ mask_irq(desc);
}
}