Skip to contentSkip to conversation

Use chained handler entry/exit functions in platform code

PATCH New Will Deacon 8 participants 24 messages Apr 12, 2011 – May 1, 2011

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

v2 cover Use chained handler entry/exit functions in platform code

Hello,

This is version 2 of the patches originally posted here:

http://lists.infradead.org/pipermail/linux-arm-kernel/2011-April/046905.html

Changes since v1:

* Updated to irq_desc_get_chip
* Fixed missing includes
* Updated Tegra IRQ handling
* Based on -rc3

Colin - Please can you look at the changes I've made to mach-tegra/irq.c? I'd also value some feedback on how you'd like to see this merged. See my previous post here:

http://lists.infradead.org/pipermail/linux-arm-kernel/2011-April/047253.html

Please test/ack/complain wherever possible,

Will

Will Deacon (6):
ARM: omap: update GPIO chained IRQ handler to use entry/exit
functions
ARM: tegra: update GPIO chained IRQ handler to use entry/exit
functions
ARM: s5pv310: update IRQ combiner to use chained entry/exit functions
ARM: msm: update GPIO chained IRQ handler to use entry/exit functions
ARM: nmk: update GPIO chained IRQ handler to entry/exit functions
ARM: gic: use handle_fasteoi_irq for SPIs

 arch/arm/common/gic.c                |   32 ++++++++++++++++----------------
 arch/arm/mach-exynos4/irq-combiner.c |    6 ++----
 arch/arm/mach-msm/gpio-v2.c          |   10 ++++++++--
 arch/arm/mach-tegra/gpio.c           |    9 ++++++---
 arch/arm/mach-tegra/irq.c            |   12 ++++++------
 arch/arm/plat-nomadik/gpio.c         |   12 ++++--------
 arch/arm/plat-omap/gpio.c            |    7 ++++---
 7 files changed, 46 insertions(+), 42 deletions(-)
#1 lore raw

PATCH v2 1/6 ARM: omap: update GPIO chained IRQ handler to use entry/exit functions

This patch updates the OMAP gpio chained IRQ handler to use the chained IRQ enter/exit functions in order to function correctly on primary controllers with different methods of flow control.

Cc Colin Cross <[email protected]>
Cc Tony Lindgren <[email protected]>
Cc Santosh Shilimkar <[email protected]>
---
 arch/arm/plat-omap/gpio.c |    7 ++++---
 1 files changed, 4 insertions(+), 3 deletions(-)
arch/arm/plat-omap/gpio.c +4 -3
index d2adcdd..a2478eb 100644
@@ -1137,8 +1137,9 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 	struct gpio_bank *bank;
 	u32 retrigger = 0;
 	int unmasked = 0;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
 
-	desc->irq_data.chip->irq_ack(&desc->irq_data);
+	chained_irq_enter(chip, desc);
 
 	bank = irq_get_handler_data(irq);
 #ifdef CONFIG_ARCH_OMAP1
@@ -1195,7 +1196,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 		configured, we could unmask GPIO bank interrupt immediately */
 		if (!level_mask && !unmasked) {
 			unmasked = 1;
-			desc->irq_data.chip->irq_unmask(&desc->irq_data);
+			chained_irq_exit(chip, desc);
 		}
 
 		isr |= retrigger;
@@ -1231,7 +1232,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 	interrupt */
 exit:
 	if (!unmasked)
-		desc->irq_data.chip->irq_unmask(&desc->irq_data);
+		chained_irq_exit(chip, desc);
 }
 
 static void gpio_irq_shutdown(struct irq_data *d)
Signature · 1 line
1.7.0.4
#2 lore raw

PATCH v2 2/6 ARM: tegra: update GPIO chained IRQ handler to use entry/exit functions

In reply to Will Deacon

This patch updates the Tegra gpio chained IRQ handler to use the chained IRQ enter/exit functions in order to function correctly on primary controllers with different methods of flow control.

This is required for the GIC to move to fasteoi interrupt handling.

---
 arch/arm/mach-tegra/gpio.c |    9 ++++++---
 arch/arm/mach-tegra/irq.c  |   12 ++++++------
 2 files changed, 12 insertions(+), 9 deletions(-)
arch/arm/mach-tegra/gpio.c +6 -3
index 76a3f65..494e28f 100644
@@ -24,6 +24,8 @@
 #include <linux/io.h>
 #include <linux/gpio.h>
 
+#include <asm/mach/irq.h>
+
 #include <mach/iomap.h>
 #include <mach/suspend.h>
 
@@ -221,8 +223,9 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 	int port;
 	int pin;
 	int unmasked = 0;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
 
-	desc->irq_data.chip->irq_ack(&desc->irq_data);
+	chained_irq_enter(chip, desc);
 
 	bank = irq_get_handler_data(irq);
 
@@ -241,7 +244,7 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 			 */
 			if (lvl & (0x100 << pin)) {
 				unmasked = 1;
-				desc->irq_data.chip->irq_unmask(&desc->irq_data);
+				chained_irq_exit(chip, desc);
 			}
 
 			generic_handle_irq(gpio_to_irq(gpio + pin));
@@ -249,7 +252,7 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 	}
 
 	if (!unmasked)
-		desc->irq_data.chip->irq_unmask(&desc->irq_data);
+		chained_irq_exit(chip, desc);
 
 }
 
arch/arm/mach-tegra/irq.c +6 -6
index 4330d89..2424a3b 100644
@@ -48,7 +48,7 @@ static u32 tegra_lp0_wake_level_any;
 
 static void (*tegra_gic_mask_irq)(struct irq_data *d);
 static void (*tegra_gic_unmask_irq)(struct irq_data *d);
-static void (*tegra_gic_ack_irq)(struct irq_data *d);
+static void (*tegra_gic_eoi_irq)(struct irq_data *d);
 
 /* ensures that sufficient time is passed for a register write to
  * serialize into the 32KHz domain */
@@ -113,10 +113,10 @@ static void tegra_unmask(struct irq_data *d)
 	tegra_legacy_unmask_irq(d->irq);
 }
 
-static void tegra_ack(struct irq_data *d)
+static void tegra_eoi(struct irq_data *d)
 {
 	tegra_legacy_force_irq_clr(d->irq);
-	tegra_gic_ack_irq(d);
+	tegra_gic_eoi_irq(d);
 }
 
 static int tegra_retrigger(struct irq_data *d)
@@ -127,7 +127,7 @@ static int tegra_retrigger(struct irq_data *d)
 
 static struct irq_chip tegra_irq = {
 	.name			= "PPI",
-	.irq_ack		= tegra_ack,
+	.irq_eoi		= tegra_eoi,
 	.irq_mask		= tegra_mask,
 	.irq_unmask		= tegra_unmask,
 	.irq_retrigger		= tegra_retrigger,
@@ -147,14 +147,14 @@ void __init tegra_init_irq(void)
 	gic = irq_get_chip(29);
 	tegra_gic_unmask_irq = gic->irq_unmask;
 	tegra_gic_mask_irq = gic->irq_mask;
-	tegra_gic_ack_irq = gic->irq_ack;
+	tegra_gic_eoi_irq = gic->irq_eoi;
 #ifdef CONFIG_SMP
 	tegra_irq.irq_set_affinity = gic->irq_set_affinity;
 #endif
 
 	for (i = 0; i < INT_MAIN_NR; i++) {
 		irq = INT_PRI_BASE + i;
-		irq_set_chip_and_handler(irq, &tegra_irq, handle_level_irq);
+		irq_set_chip_and_handler(irq, &tegra_irq, handle_fasteoi_irq);
 		set_irq_flags(irq, IRQF_VALID);
 	}
 }
Signature · 1 line
1.7.0.4
#3 lore raw

PATCH 2/6 ARM: tegra: update GPIO chained IRQ handler to use entry/exit functions

Quoted 100 lines · Will Deacon

This patch updates the Tegra gpio chained IRQ handler to use the chained IRQ enter/exit functions in order to function correctly on primary controllers with different methods of flow control.

This is required for the GIC to move to fasteoi interrupt handling.

---
?arch/arm/mach-tegra/gpio.c | ? ?9 ++++++--- ?arch/arm/mach-tegra/irq.c ?| ? 12 ++++++------ ?2 files changed, 12 insertions(+), 9 deletions(-)

arch/arm/mach-tegra/gpio.c +0 -0
index 76a3f65..494e28f 100644
@@ -24,6 +24,8 @@

?#include <linux/io.h>
?#include <linux/gpio.h>

arch/arm/mach-tegra/gpio.c +2 -0
+#include <asm/mach/irq.h>
+

?#include <mach/iomap.h>
?#include <mach/suspend.h>

arch/arm/mach-tegra/gpio.c +2 -1
@@ -221,8 +223,9 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 ? ? ? ?int port;
 ? ? ? ?int pin;
 ? ? ? ?int unmasked = 0;
+ ? ? ? struct irq_chip *chip = irq_desc_get_chip(desc);
 
- ? ? ? desc->irq_data.chip->irq_ack(&desc->irq_data);
+ ? ? ? chained_irq_enter(chip, desc);
 
 ? ? ? ?bank = irq_get_handler_data(irq);
 
@@ -241,7 +244,7 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)

? ? ? ? ? ? ? ? ? ? ? ? */
? ? ? ? ? ? ? ? ? ? ? ?if (lvl & (0x100 << pin)) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unmasked = 1;
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? desc->irq_data.chip->irq_unmask(&desc->irq_data);
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? chained_irq_exit(chip, desc);
? ? ? ? ? ? ? ? ? ? ? ?}

? ? ? ? ? ? ? ? ? ? ? ?generic_handle_irq(gpio_to_irq(gpio + pin));

arch/arm/mach-tegra/gpio.c +1 -1
@@ -249,7 +252,7 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 ? ? ? ?}
 
 ? ? ? ?if (!unmasked)
- ? ? ? ? ? ? ? desc->irq_data.chip->irq_unmask(&desc->irq_data);
+ ? ? ? ? ? ? ? chained_irq_exit(chip, desc);
 
 ?}
 
arch/arm/mach-tegra/irq.c +1 -1
index 4330d89..2424a3b 100644
@@ -48,7 +48,7 @@ static u32 tegra_lp0_wake_level_any;
 
 ?static void (*tegra_gic_mask_irq)(struct irq_data *d);
 ?static void (*tegra_gic_unmask_irq)(struct irq_data *d);
-static void (*tegra_gic_ack_irq)(struct irq_data *d);
+static void (*tegra_gic_eoi_irq)(struct irq_data *d);
 

?/* ensures that sufficient time is passed for a register write to ?* serialize into the 32KHz domain */

arch/arm/mach-tegra/irq.c +4 -4
@@ -113,10 +113,10 @@ static void tegra_unmask(struct irq_data *d)
 ? ? ? ?tegra_legacy_unmask_irq(d->irq);
 ?}
 
-static void tegra_ack(struct irq_data *d)
+static void tegra_eoi(struct irq_data *d)
 ?{
 ? ? ? ?tegra_legacy_force_irq_clr(d->irq);
- ? ? ? tegra_gic_ack_irq(d);
+ ? ? ? tegra_gic_eoi_irq(d);
 ?}
 
 ?static int tegra_retrigger(struct irq_data *d)
@@ -127,7 +127,7 @@ static int tegra_retrigger(struct irq_data *d)
 
 ?static struct irq_chip tegra_irq = {
 ? ? ? ?.name ? ? ? ? ? ? ? ? ? = "PPI",
- ? ? ? .irq_ack ? ? ? ? ? ? ? ?= tegra_ack,
+ ? ? ? .irq_eoi ? ? ? ? ? ? ? ?= tegra_eoi,
 ? ? ? ?.irq_mask ? ? ? ? ? ? ? = tegra_mask,
 ? ? ? ?.irq_unmask ? ? ? ? ? ? = tegra_unmask,
 ? ? ? ?.irq_retrigger ? ? ? ? ?= tegra_retrigger,
@@ -147,14 +147,14 @@ void __init tegra_init_irq(void)
 ? ? ? ?gic = irq_get_chip(29);
 ? ? ? ?tegra_gic_unmask_irq = gic->irq_unmask;
 ? ? ? ?tegra_gic_mask_irq = gic->irq_mask;
- ? ? ? tegra_gic_ack_irq = gic->irq_ack;
+ ? ? ? tegra_gic_eoi_irq = gic->irq_eoi;

?#ifdef CONFIG_SMP
? ? ? ?tegra_irq.irq_set_affinity = gic->irq_set_affinity; ?#endif

Quoted 11 lines

? ? ? ?for (i = 0; i < INT_MAIN_NR; i++) {
? ? ? ? ? ? ? ?irq = INT_PRI_BASE + i;
- ? ? ? ? ? ? ? irq_set_chip_and_handler(irq, &tegra_irq, handle_level_irq);
+ ? ? ? ? ? ? ? irq_set_chip_and_handler(irq, &tegra_irq, handle_fasteoi_irq); ? ? ? ? ? ? ? ?set_irq_flags(irq, IRQF_VALID);
? ? ? ?}
?}
--
1.7.0.4

This version of the patch contains changes to gpio.c and irq.c. If you drop the irq.c changes (which I will fix in my upcoming patch),

#4 lore raw

PATCH v2 2/6 ARM: tegra: update GPIO chained IRQ handler to use entry/exit functions

Hi Colin,

Quoted 13 lines · Colin Cross
Quoted 12 lines · Will Deacon

This patch updates the Tegra gpio chained IRQ handler to use the chained IRQ enter/exit functions in order to function correctly on primary controllers with different methods of flow control.

This is required for the GIC to move to fasteoi interrupt handling.

---
 arch/arm/mach-tegra/gpio.c |    9 ++++++---
 arch/arm/mach-tegra/irq.c  |   12 ++++++------
 2 files changed, 12 insertions(+), 9 deletions(-)

[...]

Quoted 2 lines

This version of the patch contains changes to gpio.c and irq.c. If you drop the irq.c changes (which I will fix in my upcoming patch),

Yes please! I'm more than happy to drop the changes to irq.c. Please CC me on your patch so that I know when it's safe to continue pushing the fasteoi change.

Quoted 1 line

Cheers,

Will

#5 lore raw

PATCH v2 3/6 ARM: s5pv310: update IRQ combiner to use chained entry/exit functions

In reply to Will Deacon

This patch updates the IRQ combiner chained IRQ handler code to use the chained IRQ enter/exit functions in order to function correctly on primary controllers with different methods of flow control.

This is required for the GIC to move to fasteoi interrupt handling.

---
 arch/arm/mach-exynos4/irq-combiner.c |    6 ++----
 1 files changed, 2 insertions(+), 4 deletions(-)
arch/arm/mach-exynos4/irq-combiner.c +2 -4
index f488b66..5a2758a 100644
@@ -59,8 +59,7 @@ static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
 	unsigned int cascade_irq, combiner_irq;
 	unsigned long status;
 
-	/* primary controller ack'ing */
-	chip->irq_ack(&desc->irq_data);
+	chained_irq_enter(chip, desc);
 
 	spin_lock(&irq_controller_lock);
 	status = __raw_readl(chip_data->base + COMBINER_INT_STATUS);
@@ -79,8 +78,7 @@ static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
 		generic_handle_irq(cascade_irq);
 
  out:
-	/* primary controller unmasking */
-	chip->irq_unmask(&desc->irq_data);
+	chained_irq_exit(chip, desc);
 }
 
 static struct irq_chip combiner_chip = {
Signature · 1 line
1.7.0.4
#6 lore raw

PATCH v2 4/6 ARM: msm: update GPIO chained IRQ handler to use entry/exit functions

In reply to Will Deacon

This patch updates the MSM gpio chained IRQ handler to use the chained IRQ enter/exit functions in order to function correctly on primary controllers with different methods of flow control.

Cc Abhijeet Dharmapurikar <[email protected]>
---
 arch/arm/mach-msm/gpio-v2.c |   10 ++++++++--
 1 files changed, 8 insertions(+), 2 deletions(-)
arch/arm/mach-msm/gpio-v2.c +8 -2
index 56a964e..cc9c4fd 100644
@@ -27,6 +27,9 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/spinlock.h>
+
+#include <asm/mach/irq.h>
+
 #include <mach/msm_iomap.h>
 #include "gpiomux.h"
 
@@ -309,8 +312,10 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
  */
 static void msm_summary_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
-	struct irq_data *data = irq_desc_get_irq_data(desc);
 	unsigned long i;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+
+	chained_irq_enter(chip, desc);
 
 	for (i = find_first_bit(msm_gpio.enabled_irqs, NR_GPIO_IRQS);
 	     i < NR_GPIO_IRQS;
@@ -319,7 +324,8 @@ static void msm_summary_irq_handler(unsigned int irq, struct irq_desc *desc)
 			generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip,
 							   i));
 	}
-	data->chip->irq_ack(data);
+
+	chained_irq_exit(chip, desc);
 }
 
 static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
Signature · 1 line
1.7.0.4
#7 lore raw

PATCH 4/6 ARM: msm: update GPIO chained IRQ handler to use entry/exit functions

Quoted 6 lines · Will Deacon

This patch updates the MSM gpio chained IRQ handler to use the chained IRQ enter/exit functions in order to function correctly on primary controllers with different methods of flow control.

Cc Abhijeet Dharmapurikar <[email protected]>

I'm okay acking this as long as Abhijeet is ok with it.

Thanks,
David

Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
#8 lore raw

PATCH v2 4/6 ARM: msm: update GPIO chained IRQ handler to use entry/exit functions

David,

Quoted 10 lines · David Brown
Quoted 6 lines · Will Deacon

This patch updates the MSM gpio chained IRQ handler to use the chained IRQ enter/exit functions in order to function correctly on primary controllers with different methods of flow control.

Cc Abhijeet Dharmapurikar <[email protected]>

I'm okay acking this as long as Abhijeet is ok with it.

Ok, I'll add your Ack to this guy now that Abhijeet has tested/reviewed it.

Thanks,

Will

#9 lore raw

PATCH 4/6 ARM: msm: update GPIO chained IRQ handler to use entry/exit functions

In reply to Will Deacon
Quoted 37 lines · Will Deacon

This patch updates the MSM gpio chained IRQ handler to use the chained IRQ enter/exit functions in order to function correctly on primary controllers with different methods of flow control.

Cc Abhijeet Dharmapurikar <[email protected]>
---
 arch/arm/mach-msm/gpio-v2.c |   10 ++++++++--
 1 files changed, 8 insertions(+), 2 deletions(-)
arch/arm/mach-msm/gpio-v2.c +6 -1
index 56a964e..cc9c4fd 100644
@@ -27,6 +27,9 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/spinlock.h>
+
+#include <asm/mach/irq.h>
+
 #include <mach/msm_iomap.h>
 #include "gpiomux.h"
 
@@ -309,8 +312,10 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
  */
 static void msm_summary_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
-	struct irq_data *data = irq_desc_get_irq_data(desc);
 	unsigned long i;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+
+	chained_irq_enter(chip, desc);
 
 	for (i = find_first_bit(msm_gpio.enabled_irqs, NR_GPIO_IRQS);
 	     i < NR_GPIO_IRQS;

arch/arm/mach-msm/gpio-v2.c static void msm_summary_irq_handler(unsigned int irq, struct irq_desc *desc) · line 331

Quoted 9 lines
arch/arm/mach-msm/gpio-v2.c +2 -1
@@ -319,7 +324,8 @@ static void msm_summary_irq_handler(unsigned int irq, struct irq_desc *desc)
 			generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip,
 							   i));
 	}
-	data->chip->irq_ack(data);
+
+	chained_irq_exit(chip, desc);
 }
 
 static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
Signature · 3 lines
--
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm 
Innovation Center, Inc. is a member of the Code Aurora Forum.
#10 lore raw

PATCH v2 4/6 ARM: msm: update GPIO chained IRQ handler to use entry/exit functions

Abhijeet,

Quoted 10 lines · Abhijeet Dharmapurikar
Quoted 9 lines · Will Deacon

This patch updates the MSM gpio chained IRQ handler to use the chained IRQ enter/exit functions in order to function correctly on primary controllers with different methods of flow control.

Cc Abhijeet Dharmapurikar <[email protected]>
---
 arch/arm/mach-msm/gpio-v2.c |   10 ++++++++--
 1 files changed, 8 insertions(+), 2 deletions(-)

[...]

Quoted 2 lines

Thanks for getting round to looking at this. I don't have any Qualcomm hardware myself (feel free to send me some :) so I'm uneasy without the Tested-by tags.

I'll add your tags for this patch and the final one in the series.

Cheers,

Will

#11 lore raw

PATCH v2 5/6 ARM: nmk: update GPIO chained IRQ handler to entry/exit functions

In reply to Will Deacon

This patch updates the Nomadik gpio chained IRQ handler to use the chained IRQ enter/exit functions in order to function correctly on primary controllers with different methods of flow control.

---
 arch/arm/plat-nomadik/gpio.c |   12 ++++--------
 1 files changed, 4 insertions(+), 8 deletions(-)
arch/arm/plat-nomadik/gpio.c +4 -8
index f49748e..307b813 100644
@@ -23,6 +23,8 @@
 #include <linux/irq.h>
 #include <linux/slab.h>
 
+#include <asm/mach/irq.h>
+
 #include <plat/pincfg.h>
 #include <mach/hardware.h>
 #include <mach/gpio.h>
@@ -681,13 +683,7 @@ static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
 	struct irq_chip *host_chip = irq_get_chip(irq);
 	unsigned int first_irq;
 
-	if (host_chip->irq_mask_ack)
-		host_chip->irq_mask_ack(&desc->irq_data);
-	else {
-		host_chip->irq_mask(&desc->irq_data);
-		if (host_chip->irq_ack)
-			host_chip->irq_ack(&desc->irq_data);
-	}
+	chained_irq_enter(host_chip, desc);
 
 	nmk_chip = irq_get_handler_data(irq);
 	first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base);
@@ -698,7 +694,7 @@ static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
 		status &= ~BIT(bit);
 	}
 
-	host_chip->irq_unmask(&desc->irq_data);
+	chained_irq_exit(host_chip, desc);
 }
 
 static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
Signature · 1 line
1.7.0.4
#12 lore raw

PATCH 5/6 ARM: nmk: update GPIO chained IRQ handler to entry/exit functions

2011/4/12 Will Deacon <[email protected]>:

Quoted 6 lines

This patch updates the Nomadik gpio chained IRQ handler to use the chained IRQ enter/exit functions in order to function correctly on primary controllers with different methods of flow control.

BUT I want it to go through Grants gpio tree. The reason is that I plan to consolidate this driver into drivers/gpio/* and I don't want collisions in merges.

And wait:

Quoted 10 lines

+#include <asm/mach/irq.h>

- ? ? ? if (host_chip->irq_mask_ack)
- ? ? ? ? ? ? ? host_chip->irq_mask_ack(&desc->irq_data);
- ? ? ? else {
- ? ? ? ? ? ? ? host_chip->irq_mask(&desc->irq_data);
- ? ? ? ? ? ? ? if (host_chip->irq_ack)
- ? ? ? ? ? ? ? ? ? ? ? host_chip->irq_ack(&desc->irq_data);
- ? ? ? }
+ ? ? ? chained_irq_enter(host_chip, desc);

(...)

Quoted 2 lines

- ? ? ? host_chip->irq_unmask(&desc->irq_data);
+ ? ? ? chained_irq_exit(host_chip, desc);

This looks an awful lot like this from drivers/gpio/pl061.c:

desc->irq_data.chip->irq_ack(&desc->irq_data);
(...)
desc->irq_data.chip->irq_unmask(&desc->irq_data);

It gets me wondering what the proper way is to do this. Isn't the proper place for chained_irq_[enter|exit]* in include/linux/irq.h rather? It does not really look machine or arch specific, is it, really?

I.e. this:

#ifndef __ASSEMBLY__
/*
* Entry/exit functions for chained handlers where the primary IRQ chip
* may implement either fasteoi or level-trigger flow control. */
static inline void chained_irq_enter(struct irq_chip *chip,
struct irq_desc *desc)

{
        /* FastEOI controllers require no action on entry. */
        if (chip->irq_eoi)
                return;

        if (chip->irq_mask_ack) {
                chip->irq_mask_ack(&desc->irq_data);
        } else {
                chip->irq_mask(&desc->irq_data);
                if (chip->irq_ack)
                        chip->irq_ack(&desc->irq_data);
        }
}

static inline void chained_irq_exit(struct irq_chip *chip,
struct irq_desc *desc)

{
        if (chip->irq_eoi)
                chip->irq_eoi(&desc->irq_data);
        else
                chip->irq_unmask(&desc->irq_data);
}

#endif

Excuse me if this was discussed before...

Yours,
Linus Walleij

#13 lore raw

PATCH v2 5/6 ARM: nmk: update GPIO chained IRQ handler to entry/exit functions

Hi Linus,

Quoted 10 lines · Linus Walleij

2011/4/12 Will Deacon <[email protected]>:

Quoted 6 lines

This patch updates the Nomadik gpio chained IRQ handler to use the chained IRQ enter/exit functions in order to function correctly on primary controllers with different methods of flow control.

Thanks for the Ack.

Quoted 3 lines

BUT I want it to go through Grants gpio tree. The reason is that I plan to consolidate this driver into drivers/gpio/* and I don't want collisions in merges.

Ok. Will Grant just pick it up when he's happy with it?

Quoted 15 lines

And wait:

Quoted 10 lines
arch/arm/plat-nomadik/gpio.c +2 -7
+#include <asm/mach/irq.h>
 
-       if (host_chip->irq_mask_ack)
-               host_chip->irq_mask_ack(&desc->irq_data);
-       else {
-               host_chip->irq_mask(&desc->irq_data);
-               if (host_chip->irq_ack)
-                       host_chip->irq_ack(&desc->irq_data);
-       }
+       chained_irq_enter(host_chip, desc);

(...)

Quoted 8 lines

arch/arm/plat-nomadik/gpio.c static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc, · line 697

Quoted 2 lines
arch/arm/plat-nomadik/gpio.c +1 -1
-       host_chip->irq_unmask(&desc->irq_data);
+       chained_irq_exit(host_chip, desc);

This looks an awful lot like this from drivers/gpio/pl061.c:

desc->irq_data.chip->irq_ack(&desc->irq_data);
(...)
desc->irq_data.chip->irq_unmask(&desc->irq_data);

The chained_{enter,exit} functions are there so that chained handlers written for multiple parent IRQ chips can cope when the chips differ in their method of flow control. I'd argue that we shouldn't be promoting chained handlers like this (there should probably be a separate handler for each primary chip implementation with which it's designed to work).

The *only* reason I abstracting this pattern is so that platforms can survive the GIC migration from ACK => FastEOI without being broken in mainline while the GIC code is in a state of flux.

Quoted 4 lines

It gets me wondering what the proper way is to do this. Isn't the proper place for chained_irq_[enter|exit]* in include/linux/irq.h rather? It does not really look machine or arch specific, is it, really?

There are only a handful of machines under arch/arm/ that suffer from this problem and need to be able to handle two flow types simultaneously. If there's a demand for making this stuff more visible, then fine, but I don't think there is.

Cheers,

Will

#14 lore raw

PATCH 5/6 ARM: nmk: update GPIO chained IRQ handler to entry/exit functions

2011/4/18 Will Deacon <[email protected]>:

Quoted 5 lines
Quoted 3 lines

BUT I want it to go through Grants gpio tree. The reason is that I plan to consolidate this driver into drivers/gpio/* and I don't want collisions in merges.

Ok. Will Grant just pick it up when he's happy with it?

If not picked up, I'll queue it on the top of my patch series when moving it to drivers/gpio...

Thanks,
Linus Walleij

#15 lore raw

PATCH 5/6 ARM: nmk: update GPIO chained IRQ handler to entry/exit functions

Quoted 10 lines · Linus Walleij

2011/4/18 Will Deacon <[email protected]>:

Quoted 5 lines
Quoted 3 lines

BUT I want it to go through Grants gpio tree. The reason is that I plan to consolidate this driver into drivers/gpio/* and I don't want collisions in merges.

Ok. Will Grant just pick it up when he's happy with it?

If not picked up, I'll queue it on the top of my patch series when moving it to drivers/gpio...

Go ahead and put it in your series. Since you're going to be doing consolidation work on it, I'd rather deal with it all at once.

g.

#16 lore raw

PATCH v2 6/6 ARM: gic: use handle_fasteoi_irq for SPIs

In reply to Will Deacon

Currently, the gic uses handle_level_irq for handling SPIs (Shared Peripheral Interrupts), requiring active interrupts to be masked at the distributor level during IRQ handling.

On a virtualised system, only the CPU interfaces are virtualised in hardware. Accesses to the distributor must be trapped by the hypervisor, adding latency to the critical interrupt path in Linux.

This patch modifies the GIC code to use handle_fasteoi_irq for handling interrupts, which only requires us to signal EOI to the CPU interface when handling is complete. Cascaded IRQ handling is also updated to use the chained IRQ enter/exit functions to honour the flow control of the parent chip.

Note that commit 846afbd1 ("GIC: Dont disable INT in ack callback") broke cascading interrupts by forgetting to add IRQ masking. This is no longer an issue because the unmask call is now unnecessary.

Tested on Versatile Express and Realview EB (1176 w/ cascaded GICs).

Cc Abhijeet Dharmapurikar <[email protected]>
Cc Russell King - ARM Linux <[email protected]>
---
 arch/arm/common/gic.c |   32 ++++++++++++++++----------------
 1 files changed, 16 insertions(+), 16 deletions(-)
arch/arm/common/gic.c +16 -16
index f70ec7d..e9c2ff8 100644
@@ -49,7 +49,7 @@ struct gic_chip_data {
  * Default make them NULL.
  */
 struct irq_chip gic_arch_extn = {
-	.irq_ack	= NULL,
+	.irq_eoi	= NULL,
 	.irq_mask	= NULL,
 	.irq_unmask	= NULL,
 	.irq_retrigger	= NULL,
@@ -84,15 +84,6 @@ static inline unsigned int gic_irq(struct irq_data *d)
 /*
  * Routines to acknowledge, disable and enable interrupts
  */
-static void gic_ack_irq(struct irq_data *d)
-{
-	spin_lock(&irq_controller_lock);
-	if (gic_arch_extn.irq_ack)
-		gic_arch_extn.irq_ack(d);
-	writel(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
-	spin_unlock(&irq_controller_lock);
-}
-
 static void gic_mask_irq(struct irq_data *d)
 {
 	u32 mask = 1 << (d->irq % 32);
@@ -115,6 +106,17 @@ static void gic_unmask_irq(struct irq_data *d)
 	spin_unlock(&irq_controller_lock);
 }
 
+static void gic_eoi_irq(struct irq_data *d)
+{
+	if (gic_arch_extn.irq_eoi) {
+		spin_lock(&irq_controller_lock);
+		gic_arch_extn.irq_eoi(d);
+		spin_unlock(&irq_controller_lock);
+	}
+
+	writel(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
+}
+
 static int gic_set_type(struct irq_data *d, unsigned int type)
 {
 	void __iomem *base = gic_dist_base(d);
@@ -218,8 +220,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
 	unsigned int cascade_irq, gic_irq;
 	unsigned long status;
 
-	/* primary controller ack'ing */
-	chip->irq_ack(&desc->irq_data);
+	chained_irq_enter(chip, desc);
 
 	spin_lock(&irq_controller_lock);
 	status = readl(chip_data->cpu_base + GIC_CPU_INTACK);
@@ -236,15 +237,14 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
 		generic_handle_irq(cascade_irq);
 
  out:
-	/* primary controller unmasking */
-	chip->irq_unmask(&desc->irq_data);
+	chained_irq_exit(chip, desc);
 }
 
 static struct irq_chip gic_chip = {
 	.name			= "GIC",
-	.irq_ack		= gic_ack_irq,
 	.irq_mask		= gic_mask_irq,
 	.irq_unmask		= gic_unmask_irq,
+	.irq_eoi		= gic_eoi_irq,
 	.irq_set_type		= gic_set_type,
 	.irq_retrigger		= gic_retrigger,
 #ifdef CONFIG_SMP
@@ -319,7 +319,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
 	 * Setup the Linux IRQ subsystem.
 	 */
 	for (i = irq_start; i < irq_limit; i++) {
-		irq_set_chip_and_handler(i, &gic_chip, handle_level_irq);
+		irq_set_chip_and_handler(i, &gic_chip, handle_fasteoi_irq);
 		irq_set_chip_data(i, gic);
 		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
 	}
Signature · 1 line
1.7.0.4
#17 lore raw

PATCH 6/6 ARM: gic: use handle_fasteoi_irq for SPIs

Quoted 104 lines · Will Deacon

Currently, the gic uses handle_level_irq for handling SPIs (Shared Peripheral Interrupts), requiring active interrupts to be masked at the distributor level during IRQ handling.

On a virtualised system, only the CPU interfaces are virtualised in hardware. Accesses to the distributor must be trapped by the hypervisor, adding latency to the critical interrupt path in Linux.

This patch modifies the GIC code to use handle_fasteoi_irq for handling interrupts, which only requires us to signal EOI to the CPU interface when handling is complete. Cascaded IRQ handling is also updated to use the chained IRQ enter/exit functions to honour the flow control of the parent chip.

Note that commit 846afbd1 ("GIC: Dont disable INT in ack callback") broke cascading interrupts by forgetting to add IRQ masking. This is no longer an issue because the unmask call is now unnecessary.

Tested on Versatile Express and Realview EB (1176 w/ cascaded GICs).

Cc Abhijeet Dharmapurikar <[email protected]>
Cc Russell King - ARM Linux <[email protected]>
---
 arch/arm/common/gic.c |   32 ++++++++++++++++----------------
 1 files changed, 16 insertions(+), 16 deletions(-)
arch/arm/common/gic.c +15 -15
index f70ec7d..e9c2ff8 100644
@@ -49,7 +49,7 @@ struct gic_chip_data {
  * Default make them NULL.
  */
 struct irq_chip gic_arch_extn = {
-	.irq_ack	= NULL,
+	.irq_eoi	= NULL,
 	.irq_mask	= NULL,
 	.irq_unmask	= NULL,
 	.irq_retrigger	= NULL,
@@ -84,15 +84,6 @@ static inline unsigned int gic_irq(struct irq_data *d)
 /*
  * Routines to acknowledge, disable and enable interrupts
  */
-static void gic_ack_irq(struct irq_data *d)
-{
-	spin_lock(&irq_controller_lock);
-	if (gic_arch_extn.irq_ack)
-		gic_arch_extn.irq_ack(d);
-	writel(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
-	spin_unlock(&irq_controller_lock);
-}
-
 static void gic_mask_irq(struct irq_data *d)
 {
 	u32 mask = 1 << (d->irq % 32);
@@ -115,6 +106,17 @@ static void gic_unmask_irq(struct irq_data *d)
 	spin_unlock(&irq_controller_lock);
 }
 
+static void gic_eoi_irq(struct irq_data *d)
+{
+	if (gic_arch_extn.irq_eoi) {
+		spin_lock(&irq_controller_lock);
+		gic_arch_extn.irq_eoi(d);
+		spin_unlock(&irq_controller_lock);
+	}
+
+	writel(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
+}
+
 static int gic_set_type(struct irq_data *d, unsigned int type)
 {
 	void __iomem *base = gic_dist_base(d);
@@ -218,8 +220,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
 	unsigned int cascade_irq, gic_irq;
 	unsigned long status;
 
-	/* primary controller ack'ing */
-	chip->irq_ack(&desc->irq_data);
+	chained_irq_enter(chip, desc);
 
 	spin_lock(&irq_controller_lock);
 	status = readl(chip_data->cpu_base + GIC_CPU_INTACK);
@@ -236,15 +237,14 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
 		generic_handle_irq(cascade_irq);
 
  out:
-	/* primary controller unmasking */
-	chip->irq_unmask(&desc->irq_data);
+	chained_irq_exit(chip, desc);
 }
 
 static struct irq_chip gic_chip = {
 	.name			= "GIC",
-	.irq_ack		= gic_ack_irq,
 	.irq_mask		= gic_mask_irq,
 	.irq_unmask		= gic_unmask_irq,
+	.irq_eoi		= gic_eoi_irq,
 	.irq_set_type		= gic_set_type,
 	.irq_retrigger		= gic_retrigger,
 #ifdef CONFIG_SMP

arch/arm/common/gic.c static void __init gic_dist_init(struct gic_chip_data *gic, · line 325

Quoted 8 lines
arch/arm/common/gic.c +1 -1
@@ -319,7 +319,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
 	 * Setup the Linux IRQ subsystem.
 	 */
 	for (i = irq_start; i < irq_limit; i++) {
-		irq_set_chip_and_handler(i, &gic_chip, handle_level_irq);
+		irq_set_chip_and_handler(i, &gic_chip, handle_fasteoi_irq);
 		irq_set_chip_data(i, gic);
 		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
 	}

--
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

#18 lore raw

PATCH 6/6 ARM: gic: use handle_fasteoi_irq for SPIs

In reply to Will Deacon
Quoted 18 lines · Will Deacon

Currently, the gic uses handle_level_irq for handling SPIs (Shared Peripheral Interrupts), requiring active interrupts to be masked at the distributor level during IRQ handling.

On a virtualised system, only the CPU interfaces are virtualised in hardware. Accesses to the distributor must be trapped by the hypervisor, adding latency to the critical interrupt path in Linux.

This patch modifies the GIC code to use handle_fasteoi_irq for handling interrupts, which only requires us to signal EOI to the CPU interface when handling is complete. Cascaded IRQ handling is also updated to use the chained IRQ enter/exit functions to honour the flow control of the parent chip.

Note that commit 846afbd1 ("GIC: Dont disable INT in ack callback") broke cascading interrupts by forgetting to add IRQ masking. This is no longer an issue because the unmask call is now unnecessary.

Quoted 7 lines

Tested on Versatile Express and Realview EB (1176 w/ cascaded GICs).

Cc Abhijeet Dharmapurikar<[email protected]>
Cc Russell King - ARM Linux<[email protected]>

---

Tested with OMAP4.

#19 lore raw

PATCH v2 6/6 ARM: gic: use handle_fasteoi_irq for SPIs

Hi Santosh,

Quoted 21 lines · Santosh Shilimkar
Quoted 20 lines · Will Deacon

Currently, the gic uses handle_level_irq for handling SPIs (Shared Peripheral Interrupts), requiring active interrupts to be masked at the distributor level during IRQ handling.

On a virtualised system, only the CPU interfaces are virtualised in hardware. Accesses to the distributor must be trapped by the hypervisor, adding latency to the critical interrupt path in Linux.

This patch modifies the GIC code to use handle_fasteoi_irq for handling interrupts, which only requires us to signal EOI to the CPU interface when handling is complete. Cascaded IRQ handling is also updated to use the chained IRQ enter/exit functions to honour the flow control of the parent chip.

Note that commit 846afbd1 ("GIC: Dont disable INT in ack callback") broke cascading interrupts by forgetting to add IRQ masking. This is no longer an issue because the unmask call is now unnecessary.

Tested on Versatile Express and Realview EB (1176 w/ cascaded GICs).

Quoted 8 lines
Quoted 5 lines
Cc Abhijeet Dharmapurikar<[email protected]>
Cc Russell King - ARM Linux<[email protected]>

---

Tested with OMAP4.

Cheers for this. I'll add this and the tags for the OMAP-specific patch (for some reason you dropped the list when you replied with your Ack).

Thanks!

Will

#20 lore raw

PATCH 6/6 ARM: gic: use handle_fasteoi_irq for SPIs

Quoted 29 lines · Will Deacon

Hi Santosh,

Quoted 26 lines · Santosh Shilimkar
Quoted 25 lines · Will Deacon

Currently, the gic uses handle_level_irq for handling SPIs (Shared Peripheral Interrupts), requiring active interrupts to be masked at the distributor level during IRQ handling.

On a virtualised system, only the CPU interfaces are virtualised in hardware. Accesses to the distributor must be trapped by the hypervisor, adding latency to the critical interrupt path in Linux.

This patch modifies the GIC code to use handle_fasteoi_irq for handling interrupts, which only requires us to signal EOI to the CPU interface when handling is complete. Cascaded IRQ handling is also updated to use the chained IRQ enter/exit functions to honour the flow control of the parent chip.

Note that commit 846afbd1 ("GIC: Dont disable INT in ack callback") broke cascading interrupts by forgetting to add IRQ masking. This is no longer an issue because the unmask call is now unnecessary.

Tested on Versatile Express and Realview EB (1176 w/ cascaded GICs).

Cc Abhijeet Dharmapurikar<[email protected]>
Cc Russell King - ARM Linux<[email protected]>

---

Quoted 7 lines
Quoted 3 lines

Tested with OMAP4.

Cheers for this. I'll add this and the tags for the OMAP-specific patch (for some reason you dropped the list when you replied with your Ack).

Sure. By mistake I did reply instead of reply all :(

Regards
Santosh

#21 lore raw

PATCH 6/6 ARM: gic: use handle_fasteoi_irq for SPIs

In reply to Will Deacon
Quoted 18 lines · Will Deacon

Currently, the gic uses handle_level_irq for handling SPIs (Shared Peripheral Interrupts), requiring active interrupts to be masked at the distributor level during IRQ handling.

On a virtualised system, only the CPU interfaces are virtualised in hardware. Accesses to the distributor must be trapped by the hypervisor, adding latency to the critical interrupt path in Linux.

This patch modifies the GIC code to use handle_fasteoi_irq for handling interrupts, which only requires us to signal EOI to the CPU interface when handling is complete. Cascaded IRQ handling is also updated to use the chained IRQ enter/exit functions to honour the flow control of the parent chip.

Note that commit 846afbd1 ("GIC: Dont disable INT in ack callback") broke cascading interrupts by forgetting to add IRQ masking. This is no longer an issue because the unmask call is now unnecessary.

Quoted 6 lines

Tested on Versatile Express and Realview EB (1176 w/ cascaded GICs).

Cc Abhijeet Dharmapurikar <[email protected]>
Cc Russell King - ARM Linux <[email protected]>

After further testing, I'm having a problem with this patch, although I think its more of a core issue than the fault of this patch. One of my interrupts is getting stuck with the PENDING flag set, and preventing suspend. The flow that triggers this is:

level triggered irq
handle_fasteoi_irq
handle_irq_event
isr
disable_irq_nosync
schedule_work (because it takes a sleeping i2c transaction to
deassert the irq pin)
irq_eoi
same irq
handle_fasteoi_irq
mark irq pending
mask_irq
work function
causes level triggered irq to go low
enable_irq
unmask_irq
check_irq_resend (returns immediately)

At this point, the irq is unmasked, but not being asserted, and marked as pending. check_irq_resend doesn't clear the pending flag for level triggered interrupts, so the pending flag will stay set until the next time the interrupt occurs.

Should handle_fasteoi_irq mask the interrupt before eoi if it was disabled by the interrupt handler? Otherwise, every level triggered interrupt that is not deasserted by the interrupt handler will interrupt the cpu twice. There is still the case where a driver disables the irq, the interrupt goes high, then goes low again before enable_irq is called.

This patch fixes the double interrupt problem, but not the vanishing interrupt problem:

kernel/irq/chip.c +3 -0
index 4af1e2b..424bdfc 100644
@@ -398,6 +398,9 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
        preflow_handler(desc);
        handle_irq_event(desc);
 
+       if (irqd_irq_disabled(&desc->irq_data) &&
+           !irqd_irq_masked(&desc->irq_data))
+               mask_irq(desc);
 out_eoi:
        desc->irq_data.chip->irq_eoi(&desc->irq_data);
 out_unlock:
#22 lore raw

PATCH 6/6 ARM: gic: use handle_fasteoi_irq for SPIs

Quoted 10 lines · Colin Cross
Quoted 4 lines
Cc Abhijeet Dharmapurikar <[email protected]>
Cc Russell King - ARM Linux <[email protected]>

After further testing, I'm having a problem with this patch, although I think its more of a core issue than the fault of this patch. One of my interrupts is getting stuck with the PENDING flag set, and preventing suspend. The flow that triggers this is:

Quoted 7 lines

level triggered irq
handle_fasteoi_irq
handle_irq_event
isr
disable_irq_nosync
schedule_work (because it takes a sleeping i2c transaction to
deassert the irq pin)

If you'd use a threaded irq handler the IRQ_ONESHOT mechanism would handle that problem for you. It masks the irq line before calling the handler and unmask happens after the threaded handler has run.

disable_irq_nosync from an interrupt handler plus scheduling work is the historic "threaded" interrupt handler mechanism. It's kinda murky nowadays due to the lazy irq disable mechanism.

Quoted 11 lines

irq_eoi
same irq
handle_fasteoi_irq
mark irq pending
mask_irq
work function
causes level triggered irq to go low
enable_irq
unmask_irq
check_irq_resend (returns immediately)

Quoted 4 lines

At this point, the irq is unmasked, but not being asserted, and marked as pending. check_irq_resend doesn't clear the pending flag for level triggered interrupts, so the pending flag will stay set until the next time the interrupt occurs.

Yes, that should be cleared unconditionally in check_irq_resend.

Quoted 4 lines

Should handle_fasteoi_irq mask the interrupt before eoi if it was disabled by the interrupt handler? Otherwise, every level triggered interrupt that is not deasserted by the interrupt handler will interrupt the cpu twice. There is still the case where a driver

No, we should stop doing the disable_irq_nosync from handlers and use threaded interrupts instead.

Quoted 2 lines

disables the irq, the interrupt goes high, then goes low again before enable_irq is called.

So what you're saying is:

irq ____ _______

        |________________|       |_____________________

	    |                              |
	 ISR/mask/eoi                enable_irq/unmask

So after the unmask the asserted new interrupt is not delivered? That's not a software problem :)

Thanks,

tglx

#23 lore raw

PATCH 6/6 ARM: gic: use handle_fasteoi_irq for SPIs

Quoted 19 lines · Thomas Gleixner
Quoted 10 lines · Colin Cross
Quoted 4 lines
Cc Abhijeet Dharmapurikar <[email protected]>
Cc Russell King - ARM Linux <[email protected]>

After further testing, I'm having a problem with this patch, although I think its more of a core issue than the fault of this patch. ?One of my interrupts is getting stuck with the PENDING flag set, and preventing suspend. ?The flow that triggers this is:

Quoted 7 lines

level triggered irq
?handle_fasteoi_irq
? handle_irq_event
? ?isr
? ? disable_irq_nosync
? ? schedule_work (because it takes a sleeping i2c transaction to deassert the irq pin)

Quoted 7 lines

If you'd use a threaded irq handler the IRQ_ONESHOT mechanism would handle that problem for you. It masks the irq line before calling the handler and unmask happens after the threaded handler has run.

disable_irq_nosync from an interrupt handler plus scheduling work is the historic "threaded" interrupt handler mechanism. It's kinda murky nowadays due to the lazy irq disable mechanism.

Yes, and in the specific case that reproduces this problem for me a threaded handler would be appropriate. However, there are cases where disable irq can legitimately be called from an interrupt handler. One example I was given is a debounce timer - the interrupt handler disables the irq and then sets a timer.

Quoted 18 lines
Quoted 11 lines

? ?irq_eoi
same irq
?handle_fasteoi_irq
? mark irq pending
? mask_irq
work function
?causes level triggered irq to go low
?enable_irq
? unmask_irq
? check_irq_resend (returns immediately)

Quoted 4 lines

At this point, the irq is unmasked, but not being asserted, and marked as pending. ?check_irq_resend doesn't clear the pending flag for level triggered interrupts, so the pending flag will stay set until the next time the interrupt occurs.

Yes, that should be cleared unconditionally in check_irq_resend.

Quoted 7 lines
Quoted 4 lines

Should handle_fasteoi_irq mask the interrupt before eoi if it was disabled by the interrupt handler? ?Otherwise, every level triggered interrupt that is not deasserted by the interrupt handler will interrupt the cpu twice. ?There is still the case where a driver

No, we should stop doing the disable_irq_nosync from handlers and use threaded interrupts instead.

As in the example above, I don't think threaded interrupts cover all the cases where disable_irq_nosync is used in an interrupt handler, although 99% of the time they do. handle_level_irq already has this optimization - it doesn't unmask the irq line if the handler returns with the irq disabled. I think the patch I posted would need to check for a level triggered interrupt, masking the line on an edge triggered interrupt could lose the next interrupt.

Quoted 5 lines
Quoted 2 lines

disables the irq, the interrupt goes high, then goes low again before enable_irq is called.

So what you're saying is:

Quoted 8 lines

irq ____ ? ? ? ? ? ? ? ? ?_______
? ? ? ?|________________| ? ? ? |_____________________

? ? ? ? ? ?| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|
? ? ? ? ISR/mask/eoi ? ? ? ? ? ? ? ?enable_irq/unmask

So after the unmask the asserted new interrupt is not delivered? That's not a software problem :)

Of course its not delivered, the problem is that it is marked pending, check_wakeup_irqs returns true and prevents suspend. Always clearing the pending flag in check_if_resend fixes suspend after calling enable_irq, but suspend will still fail if attempted between when the irq line goes low and enable_irq is called (which could be never if the driver has been disabled for some reason).