All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 0/8] kgdb: NMI/FIQ support for ARM
@ 2014-05-14 15:58 ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-14 15:58 UTC (permalink / raw)
  To: Jason Wessel, kgdb-bugreport
  Cc: Mark Rutland, kernel, Frederic Weisbecker, Linus Walleij,
	Jiri Slaby, Daniel Thompson, Dirk Behme, Russell King,
	Nicolas Pitre, Ian Campbell, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, patches, Kumar Gala, Rob Herring,
	John Stultz, Thomas Gleixner, linux-arm-kernel,
	Greg Kroah-Hartman

This patchset makes it possible to use the kgdb NMI infrastructure
on ARM platforms.

The kgdb NMI infrastructure works by re-routing an UARTs interrupt
signal from IRQ to FIQ. The UART will no longer function normally
and will instead be managed by kgdb using the polled I/O functions.
Any character delivered to the UART causes the kgdb handler function
to be called. Each serial driver explicitly consents (or not) to this
abuse by calling the appropriate registration functions.

[PATCH 1/8] arm: fiq: Allow EOI to be communicated to the intc
[PATCH 2/8] irqchip: gic: Provide support for interrupt grouping
    Both these patches lay the ground work to allow modern ARM
    interrupt controllers to support FIQ correctly.

[PATCH 3/8] ARM: Move some macros from entry-armv to entry-header
[PATCH 4/8] ARM: Add KGDB/KDB FIQ debugger generic code
    This is the heart of the patch series, allowing FIQs to be
    registered with KGDB and handled by KGDB.

[PATCH 5/8] serial: amba-pl011: Pass on FIQ information to KGDB.
[PATCH 6/8] serial: asc: Add support for KGDB's FIQ/NMI mode
    Extend to UART drivers to allow the register the appropriate FIQ
    (implicitly promising to behave properly when their own IRQ handler 
    is cut off).


[PATCH 7/8] ARM: VIC: Add vic_set_fiq function to select if an...
[PATCH 8/8] arm: fiq: Hack FIQ routing backdoors into GIC and VIC
    Here we hit the serious request-for-comment section. It is not 
    clear what the best way to get the interrupt controller to re-route 
    an interrupt source from the IRQ signal to the FIQ signal.
    
    Clearly the approach here is wrong but it has been enough for me
    to test my work so far.

Anton Vorontsov (2):
  ARM: Move some macros from entry-armv to entry-header
  ARM: Add KGDB/KDB FIQ debugger generic code

Arve Hjønnevåg (1):
  ARM: VIC: Add vic_set_fiq function to select if an interrupt should
    generate an IRQ or FIQ

Daniel Thompson (5):
  arm: fiq: Allow EOI to be communicated to the intc
  irqchip: gic: Provide support for interrupt grouping
  serial: amba-pl011: Pass on FIQ information to KGDB.
  serial: asc: Add support for KGDB's FIQ/NMI mode
  arm: fiq: Hack FIQ routing backdoors into GIC and VIC

 arch/arm/Kconfig                        |   2 +
 arch/arm/Kconfig.debug                  |  18 ++++
 arch/arm/boot/dts/stih416.dtsi          |   2 +-
 arch/arm/boot/dts/vexpress-v2m-rs1.dtsi |   2 +-
 arch/arm/include/asm/fiq.h              |   1 +
 arch/arm/include/asm/kgdb.h             |   7 ++
 arch/arm/kernel/Makefile                |   1 +
 arch/arm/kernel/entry-armv.S            | 151 +----------------------------
 arch/arm/kernel/entry-header.S          | 164 ++++++++++++++++++++++++++++++++
 arch/arm/kernel/fiq.c                   |  50 ++++++++++
 arch/arm/kernel/kgdb_fiq.c              | 117 +++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S        |  87 +++++++++++++++++
 drivers/irqchip/irq-gic.c               |  62 +++++++++++-
 drivers/irqchip/irq-vic.c               |  23 +++++
 drivers/tty/serial/amba-pl011.c         |  18 +++-
 drivers/tty/serial/st-asc.c             |  25 +++++
 include/linux/irqchip/arm-gic.h         |   3 +
 include/linux/irqchip/arm-vic.h         |   1 +
 18 files changed, 576 insertions(+), 158 deletions(-)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

-- 
1.9.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC 0/8] kgdb: NMI/FIQ support for ARM
@ 2014-05-14 15:58 ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-14 15:58 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset makes it possible to use the kgdb NMI infrastructure
on ARM platforms.

The kgdb NMI infrastructure works by re-routing an UARTs interrupt
signal from IRQ to FIQ. The UART will no longer function normally
and will instead be managed by kgdb using the polled I/O functions.
Any character delivered to the UART causes the kgdb handler function
to be called. Each serial driver explicitly consents (or not) to this
abuse by calling the appropriate registration functions.

[PATCH 1/8] arm: fiq: Allow EOI to be communicated to the intc
[PATCH 2/8] irqchip: gic: Provide support for interrupt grouping
    Both these patches lay the ground work to allow modern ARM
    interrupt controllers to support FIQ correctly.

[PATCH 3/8] ARM: Move some macros from entry-armv to entry-header
[PATCH 4/8] ARM: Add KGDB/KDB FIQ debugger generic code
    This is the heart of the patch series, allowing FIQs to be
    registered with KGDB and handled by KGDB.

[PATCH 5/8] serial: amba-pl011: Pass on FIQ information to KGDB.
[PATCH 6/8] serial: asc: Add support for KGDB's FIQ/NMI mode
    Extend to UART drivers to allow the register the appropriate FIQ
    (implicitly promising to behave properly when their own IRQ handler 
    is cut off).


[PATCH 7/8] ARM: VIC: Add vic_set_fiq function to select if an...
[PATCH 8/8] arm: fiq: Hack FIQ routing backdoors into GIC and VIC
    Here we hit the serious request-for-comment section. It is not 
    clear what the best way to get the interrupt controller to re-route 
    an interrupt source from the IRQ signal to the FIQ signal.
    
    Clearly the approach here is wrong but it has been enough for me
    to test my work so far.

Anton Vorontsov (2):
  ARM: Move some macros from entry-armv to entry-header
  ARM: Add KGDB/KDB FIQ debugger generic code

Arve Hj?nnev?g (1):
  ARM: VIC: Add vic_set_fiq function to select if an interrupt should
    generate an IRQ or FIQ

Daniel Thompson (5):
  arm: fiq: Allow EOI to be communicated to the intc
  irqchip: gic: Provide support for interrupt grouping
  serial: amba-pl011: Pass on FIQ information to KGDB.
  serial: asc: Add support for KGDB's FIQ/NMI mode
  arm: fiq: Hack FIQ routing backdoors into GIC and VIC

 arch/arm/Kconfig                        |   2 +
 arch/arm/Kconfig.debug                  |  18 ++++
 arch/arm/boot/dts/stih416.dtsi          |   2 +-
 arch/arm/boot/dts/vexpress-v2m-rs1.dtsi |   2 +-
 arch/arm/include/asm/fiq.h              |   1 +
 arch/arm/include/asm/kgdb.h             |   7 ++
 arch/arm/kernel/Makefile                |   1 +
 arch/arm/kernel/entry-armv.S            | 151 +----------------------------
 arch/arm/kernel/entry-header.S          | 164 ++++++++++++++++++++++++++++++++
 arch/arm/kernel/fiq.c                   |  50 ++++++++++
 arch/arm/kernel/kgdb_fiq.c              | 117 +++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S        |  87 +++++++++++++++++
 drivers/irqchip/irq-gic.c               |  62 +++++++++++-
 drivers/irqchip/irq-vic.c               |  23 +++++
 drivers/tty/serial/amba-pl011.c         |  18 +++-
 drivers/tty/serial/st-asc.c             |  25 +++++
 include/linux/irqchip/arm-gic.h         |   3 +
 include/linux/irqchip/arm-vic.h         |   1 +
 18 files changed, 576 insertions(+), 158 deletions(-)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

-- 
1.9.0

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC 1/8] arm: fiq: Allow EOI to be communicated to the intc
  2014-05-14 15:58 ` Daniel Thompson
@ 2014-05-14 15:58   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-14 15:58 UTC (permalink / raw)
  To: Jason Wessel, kgdb-bugreport
  Cc: Mark Rutland, kernel, Frederic Weisbecker, Linus Walleij,
	Jiri Slaby, Daniel Thompson, Dirk Behme, Russell King,
	Nicolas Pitre, Ian Campbell, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, patches, Kumar Gala, Rob Herring,
	John Stultz, Thomas Gleixner, linux-arm-kernel,
	Greg Kroah-Hartman

Modern ARM systems require an EOI to be sent to the interrupt controller
on completion of both IRQ and FIQ. The FIQ code currently does not permit
this requiring nasty register poke hacks from the FIQ handler. This patch
provides a simple interface for C based handlers to complete a FIQ.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/fiq.h |  1 +
 arch/arm/kernel/fiq.c      | 11 +++++++++++
 2 files changed, 12 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..5a2a9b9 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -38,6 +38,7 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern void eoi_fiq(int fiq);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..defbe85 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -139,6 +140,15 @@ void disable_fiq(int fiq)
 	disable_irq(fiq + fiq_start);
 }
 
+void eoi_fiq(int fiq)
+{
+	struct irq_data *irq_data = irq_get_irq_data(fiq + fiq_start);
+	struct irq_chip *chip = irq_data_get_irq_chip(irq_data);
+
+	if (chip->irq_eoi)
+			chip->irq_eoi(irq_data);
+}
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -146,6 +156,7 @@ EXPORT_SYMBOL(claim_fiq);
 EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
+EXPORT_SYMBOL(eoi_fiq);
 
 void __init init_FIQ(int start)
 {
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC 1/8] arm: fiq: Allow EOI to be communicated to the intc
@ 2014-05-14 15:58   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-14 15:58 UTC (permalink / raw)
  To: linux-arm-kernel

Modern ARM systems require an EOI to be sent to the interrupt controller
on completion of both IRQ and FIQ. The FIQ code currently does not permit
this requiring nasty register poke hacks from the FIQ handler. This patch
provides a simple interface for C based handlers to complete a FIQ.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/fiq.h |  1 +
 arch/arm/kernel/fiq.c      | 11 +++++++++++
 2 files changed, 12 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..5a2a9b9 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -38,6 +38,7 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern void eoi_fiq(int fiq);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..defbe85 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -139,6 +140,15 @@ void disable_fiq(int fiq)
 	disable_irq(fiq + fiq_start);
 }
 
+void eoi_fiq(int fiq)
+{
+	struct irq_data *irq_data = irq_get_irq_data(fiq + fiq_start);
+	struct irq_chip *chip = irq_data_get_irq_chip(irq_data);
+
+	if (chip->irq_eoi)
+			chip->irq_eoi(irq_data);
+}
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -146,6 +156,7 @@ EXPORT_SYMBOL(claim_fiq);
 EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
+EXPORT_SYMBOL(eoi_fiq);
 
 void __init init_FIQ(int start)
 {
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC 2/8] irqchip: gic: Provide support for interrupt grouping
  2014-05-14 15:58 ` Daniel Thompson
@ 2014-05-14 15:58   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-14 15:58 UTC (permalink / raw)
  To: Jason Wessel, kgdb-bugreport
  Cc: Mark Rutland, kernel, Frederic Weisbecker, Linus Walleij,
	Jiri Slaby, Daniel Thompson, Dirk Behme, Russell King,
	Nicolas Pitre, Ian Campbell, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, patches, Kumar Gala, Rob Herring,
	John Stultz, Thomas Gleixner, linux-arm-kernel,
	Greg Kroah-Hartman

GICv2+ implementions that do not implement security extensions (and
devices that boot in secure mode by default) allow the interrupt group
registers (used for FIQ/IRQ selection) to be accessed from kernel code.
However the current gic support does not initialize the controller to
make interrupt grouping effective.

The registers involved are RAZ/WI when unimplemented or protected by
security policy then it should be safe to set up the grouping
unconditionally.

Tested on a (self-written) qemu GICv2 model (written from ARM spec) and
an STiH416 (ARM Cortex A9).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Dirk Behme <dirk.behme@de.bosch.com>
---
 drivers/irqchip/irq-gic.c       | 35 ++++++++++++++++++++++++++++++-----
 include/linux/irqchip/arm-gic.h |  3 +++
 2 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 57d165e..aa8efe4 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -408,13 +408,27 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 		writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
 
 	/*
+	 * Set all global interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers a read-as-zero/write-ignored.
+	 */
+	for (i = 32; i < gic_irqs; i += 32)
+		writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
 	 * Disable all interrupts.  Leave the PPI and SGIs alone
 	 * as these enables are banked registers.
 	 */
 	for (i = 32; i < gic_irqs; i += 32)
 		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	writel_relaxed(GIC_DIST_CTRL_ENABLE_GRP0_BIT |
+		       GIC_DIST_CTRL_ENABLE_GRP1_BIT, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -452,8 +466,16 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	for (i = 0; i < 32; i += 4)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
 
+	/*
+	 * Set all PPI and SGI interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers are read-as-zero/write-ignored.
+	 */
+	writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -537,7 +559,9 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	writel_relaxed(GIC_DIST_CTRL_ENABLE_GRP0_BIT |
+			   GIC_DIST_CTRL_ENABLE_GRP1_BIT,
+		       dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -594,7 +618,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -670,7 +694,8 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+	writel_relaxed(map << 16 | irq | 0x8000,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 7ed92d0..919502f 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -37,6 +37,9 @@
 #define GIC_DIST_SGI_PENDING_CLEAR	0xf10
 #define GIC_DIST_SGI_PENDING_SET	0xf20
 
+#define GIC_DIST_CTRL_ENABLE_GRP0_BIT	(1 << 0)
+#define GIC_DIST_CTRL_ENABLE_GRP1_BIT	(1 << 1)
+
 #define GICH_HCR			0x0
 #define GICH_VTR			0x4
 #define GICH_VMCR			0x8
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC 2/8] irqchip: gic: Provide support for interrupt grouping
@ 2014-05-14 15:58   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-14 15:58 UTC (permalink / raw)
  To: linux-arm-kernel

GICv2+ implementions that do not implement security extensions (and
devices that boot in secure mode by default) allow the interrupt group
registers (used for FIQ/IRQ selection) to be accessed from kernel code.
However the current gic support does not initialize the controller to
make interrupt grouping effective.

The registers involved are RAZ/WI when unimplemented or protected by
security policy then it should be safe to set up the grouping
unconditionally.

Tested on a (self-written) qemu GICv2 model (written from ARM spec) and
an STiH416 (ARM Cortex A9).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Dirk Behme <dirk.behme@de.bosch.com>
---
 drivers/irqchip/irq-gic.c       | 35 ++++++++++++++++++++++++++++++-----
 include/linux/irqchip/arm-gic.h |  3 +++
 2 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 57d165e..aa8efe4 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -408,13 +408,27 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 		writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
 
 	/*
+	 * Set all global interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers a read-as-zero/write-ignored.
+	 */
+	for (i = 32; i < gic_irqs; i += 32)
+		writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
 	 * Disable all interrupts.  Leave the PPI and SGIs alone
 	 * as these enables are banked registers.
 	 */
 	for (i = 32; i < gic_irqs; i += 32)
 		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	writel_relaxed(GIC_DIST_CTRL_ENABLE_GRP0_BIT |
+		       GIC_DIST_CTRL_ENABLE_GRP1_BIT, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -452,8 +466,16 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	for (i = 0; i < 32; i += 4)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
 
+	/*
+	 * Set all PPI and SGI interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers are read-as-zero/write-ignored.
+	 */
+	writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -537,7 +559,9 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	writel_relaxed(GIC_DIST_CTRL_ENABLE_GRP0_BIT |
+			   GIC_DIST_CTRL_ENABLE_GRP1_BIT,
+		       dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -594,7 +618,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -670,7 +694,8 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+	writel_relaxed(map << 16 | irq | 0x8000,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 7ed92d0..919502f 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -37,6 +37,9 @@
 #define GIC_DIST_SGI_PENDING_CLEAR	0xf10
 #define GIC_DIST_SGI_PENDING_SET	0xf20
 
+#define GIC_DIST_CTRL_ENABLE_GRP0_BIT	(1 << 0)
+#define GIC_DIST_CTRL_ENABLE_GRP1_BIT	(1 << 1)
+
 #define GICH_HCR			0x0
 #define GICH_VTR			0x4
 #define GICH_VMCR			0x8
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC 3/8] ARM: Move some macros from entry-armv to entry-header
  2014-05-14 15:58 ` Daniel Thompson
@ 2014-05-14 15:58   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-14 15:58 UTC (permalink / raw)
  To: Jason Wessel, kgdb-bugreport
  Cc: Mark Rutland, kernel, Frederic Weisbecker, Linus Walleij,
	Jiri Slaby, Daniel Thompson, Dirk Behme, Russell King,
	Nicolas Pitre, Ian Campbell, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, patches, Kumar Gala, Rob Herring,
	John Stultz, Thomas Gleixner, linux-arm-kernel,
	Greg Kroah-Hartman

From: Anton Vorontsov <anton.vorontsov@linaro.org>

Just move the macros into header file as we would want to use them for
KGDB FIQ entry code.

The following macros were moved:

 - svc_entry
 - usr_entry
 - kuser_cmpxchg_check
 - vector_stub

To make kuser_cmpxchg_check actually work across different files, we
also have to make kuser_cmpxchg64_fixup global.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
 arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 150 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 1879e8d..ed95b95 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -140,53 +140,6 @@ ENDPROC(__und_invalid)
  * SVC mode handlers
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
-#define SPFIX(code...) code
-#else
-#define SPFIX(code...)
-#endif
-
-	.macro	svc_entry, stack_hole=0
- UNWIND(.fnstart		)
- UNWIND(.save {r0 - pc}		)
-	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
-#ifdef CONFIG_THUMB2_KERNEL
- SPFIX(	str	r0, [sp]	)	@ temporarily saved
- SPFIX(	mov	r0, sp		)
- SPFIX(	tst	r0, #4		)	@ test original stack alignment
- SPFIX(	ldr	r0, [sp]	)	@ restored
-#else
- SPFIX(	tst	sp, #4		)
-#endif
- SPFIX(	subeq	sp, sp, #4	)
-	stmia	sp, {r1 - r12}
-
-	ldmia	r0, {r3 - r5}
-	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""      ""       ""
-	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
- SPFIX(	addeq	r2, r2, #4	)
-	str	r3, [sp, #-4]!		@ save the "real" r0 copied
-					@ from the exception stack
-
-	mov	r3, lr
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r2 - sp_svc
-	@  r3 - lr_svc
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	stmia	r7, {r2 - r6}
-
-#ifdef CONFIG_TRACE_IRQFLAGS
-	bl	trace_hardirqs_off
-#endif
-	.endm
-
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -306,73 +259,8 @@ ENDPROC(__pabt_svc)
 
 /*
  * User mode handlers
- *
- * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
 	.align	5
 __dabt_usr:
 	usr_entry
@@ -819,6 +707,7 @@ __kuser_cmpxchg64:				@ 0xffff0f60
 	ldmfd	sp!, {r4, r5, r6, pc}
 
 	.text
+	.global kuser_cmpxchg64_fixup
 kuser_cmpxchg64_fixup:
 	@ Called from kuser_cmpxchg_fixup.
 	@ r4 = address of interrupted insn (must be preserved).
@@ -960,44 +849,6 @@ __kuser_helper_end:
  * SP points to a minimal amount of processor-private memory, the address
  * of which is copied into r0 for the mode specific abort handler.
  */
-	.macro	vector_stub, name, mode, correction=0
-	.align	5
-
-vector_\name:
-	.if \correction
-	sub	lr, lr, #\correction
-	.endif
-
-	@
-	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
-	@ (parent CPSR)
-	@
-	stmia	sp, {r0, lr}		@ save r0, lr
-	mrs	lr, spsr
-	str	lr, [sp, #8]		@ save spsr
-
-	@
-	@ Prepare for SVC32 mode.  IRQs remain disabled.
-	@
-	mrs	r0, cpsr
-	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
-	msr	spsr_cxsf, r0
-
-	@
-	@ the branch table must immediately follow this code
-	@
-	and	lr, lr, #0x0f
- THUMB(	adr	r0, 1f			)
- THUMB(	ldr	lr, [r0, lr, lsl #2]	)
-	mov	r0, sp
- ARM(	ldr	lr, [pc, lr, lsl #2]	)
-	movs	pc, lr			@ branch to handler in SVC mode
-ENDPROC(vector_\name)
-
-	.align	2
-	@ handler addresses follow this label
-1:
-	.endm
 
 	.section .stubs, "ax", %progbits
 __stubs_start:
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 1420725..ab04a67 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -352,3 +352,167 @@ scno	.req	r7		@ syscall number
 tbl	.req	r8		@ syscall table pointer
 why	.req	r8		@ Linux syscall (!= 0)
 tsk	.req	r9		@ current thread_info
+
+/*
+ * SVC mode handler macros
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define SPFIX(code...) code
+#else
+#define SPFIX(code...)
+#endif
+
+	.macro	svc_entry, stack_hole=0
+ UNWIND(.fnstart		)
+ UNWIND(.save {r0 - pc}		)
+	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+#ifdef CONFIG_THUMB2_KERNEL
+ SPFIX(	str	r0, [sp]	)	@ temporarily saved
+ SPFIX(	mov	r0, sp		)
+ SPFIX(	tst	r0, #4		)	@ test original stack alignment
+ SPFIX(	ldr	r0, [sp]	)	@ restored
+#else
+ SPFIX(	tst	sp, #4		)
+#endif
+ SPFIX(	subeq	sp, sp, #4	)
+	stmia	sp, {r1 - r12}
+
+	ldmia	r0, {r3 - r5}
+	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""      ""       ""
+	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+ SPFIX(	addeq	r2, r2, #4	)
+	str	r3, [sp, #-4]!		@ save the "real" r0 copied
+					@ from the exception stack
+
+	mov	r3, lr
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r2 - sp_svc
+	@  r3 - lr_svc
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	stmia	r7, {r2 - r6}
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_off
+#endif
+	.endm
+
+/*
+ * User mode handler macros
+ *
+ * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+/*
+ * Vector stubs macro.
+ */
+	.macro	vector_stub, name, mode, correction=0
+	.align	5
+
+vector_\name:
+	.if \correction
+	sub	lr, lr, #\correction
+	.endif
+
+	@
+	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
+	@ (parent CPSR)
+	@
+	stmia	sp, {r0, lr}		@ save r0, lr
+	mrs	lr, spsr
+	str	lr, [sp, #8]		@ save spsr
+
+	@
+	@ Prepare for SVC32 mode.  IRQs remain disabled.
+	@
+	mrs	r0, cpsr
+	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
+	msr	spsr_cxsf, r0
+
+	@
+	@ the branch table must immediately follow this code
+	@
+	and	lr, lr, #0x0f
+ THUMB(	adr	r0, 1f			)
+ THUMB(	ldr	lr, [r0, lr, lsl #2]	)
+	mov	r0, sp
+ ARM(	ldr	lr, [pc, lr, lsl #2]	)
+	movs	pc, lr			@ branch to handler in SVC mode
+ENDPROC(vector_\name)
+
+	.align	2
+	@ handler addresses follow this label
+1:
+	.endm
+
+
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC 3/8] ARM: Move some macros from entry-armv to entry-header
@ 2014-05-14 15:58   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-14 15:58 UTC (permalink / raw)
  To: linux-arm-kernel

From: Anton Vorontsov <anton.vorontsov@linaro.org>

Just move the macros into header file as we would want to use them for
KGDB FIQ entry code.

The following macros were moved:

 - svc_entry
 - usr_entry
 - kuser_cmpxchg_check
 - vector_stub

To make kuser_cmpxchg_check actually work across different files, we
also have to make kuser_cmpxchg64_fixup global.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
 arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 150 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 1879e8d..ed95b95 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -140,53 +140,6 @@ ENDPROC(__und_invalid)
  * SVC mode handlers
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
-#define SPFIX(code...) code
-#else
-#define SPFIX(code...)
-#endif
-
-	.macro	svc_entry, stack_hole=0
- UNWIND(.fnstart		)
- UNWIND(.save {r0 - pc}		)
-	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
-#ifdef CONFIG_THUMB2_KERNEL
- SPFIX(	str	r0, [sp]	)	@ temporarily saved
- SPFIX(	mov	r0, sp		)
- SPFIX(	tst	r0, #4		)	@ test original stack alignment
- SPFIX(	ldr	r0, [sp]	)	@ restored
-#else
- SPFIX(	tst	sp, #4		)
-#endif
- SPFIX(	subeq	sp, sp, #4	)
-	stmia	sp, {r1 - r12}
-
-	ldmia	r0, {r3 - r5}
-	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""      ""       ""
-	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
- SPFIX(	addeq	r2, r2, #4	)
-	str	r3, [sp, #-4]!		@ save the "real" r0 copied
-					@ from the exception stack
-
-	mov	r3, lr
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r2 - sp_svc
-	@  r3 - lr_svc
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	stmia	r7, {r2 - r6}
-
-#ifdef CONFIG_TRACE_IRQFLAGS
-	bl	trace_hardirqs_off
-#endif
-	.endm
-
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -306,73 +259,8 @@ ENDPROC(__pabt_svc)
 
 /*
  * User mode handlers
- *
- * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
 	.align	5
 __dabt_usr:
 	usr_entry
@@ -819,6 +707,7 @@ __kuser_cmpxchg64:				@ 0xffff0f60
 	ldmfd	sp!, {r4, r5, r6, pc}
 
 	.text
+	.global kuser_cmpxchg64_fixup
 kuser_cmpxchg64_fixup:
 	@ Called from kuser_cmpxchg_fixup.
 	@ r4 = address of interrupted insn (must be preserved).
@@ -960,44 +849,6 @@ __kuser_helper_end:
  * SP points to a minimal amount of processor-private memory, the address
  * of which is copied into r0 for the mode specific abort handler.
  */
-	.macro	vector_stub, name, mode, correction=0
-	.align	5
-
-vector_\name:
-	.if \correction
-	sub	lr, lr, #\correction
-	.endif
-
-	@
-	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
-	@ (parent CPSR)
-	@
-	stmia	sp, {r0, lr}		@ save r0, lr
-	mrs	lr, spsr
-	str	lr, [sp, #8]		@ save spsr
-
-	@
-	@ Prepare for SVC32 mode.  IRQs remain disabled.
-	@
-	mrs	r0, cpsr
-	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
-	msr	spsr_cxsf, r0
-
-	@
-	@ the branch table must immediately follow this code
-	@
-	and	lr, lr, #0x0f
- THUMB(	adr	r0, 1f			)
- THUMB(	ldr	lr, [r0, lr, lsl #2]	)
-	mov	r0, sp
- ARM(	ldr	lr, [pc, lr, lsl #2]	)
-	movs	pc, lr			@ branch to handler in SVC mode
-ENDPROC(vector_\name)
-
-	.align	2
-	@ handler addresses follow this label
-1:
-	.endm
 
 	.section .stubs, "ax", %progbits
 __stubs_start:
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 1420725..ab04a67 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -352,3 +352,167 @@ scno	.req	r7		@ syscall number
 tbl	.req	r8		@ syscall table pointer
 why	.req	r8		@ Linux syscall (!= 0)
 tsk	.req	r9		@ current thread_info
+
+/*
+ * SVC mode handler macros
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define SPFIX(code...) code
+#else
+#define SPFIX(code...)
+#endif
+
+	.macro	svc_entry, stack_hole=0
+ UNWIND(.fnstart		)
+ UNWIND(.save {r0 - pc}		)
+	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+#ifdef CONFIG_THUMB2_KERNEL
+ SPFIX(	str	r0, [sp]	)	@ temporarily saved
+ SPFIX(	mov	r0, sp		)
+ SPFIX(	tst	r0, #4		)	@ test original stack alignment
+ SPFIX(	ldr	r0, [sp]	)	@ restored
+#else
+ SPFIX(	tst	sp, #4		)
+#endif
+ SPFIX(	subeq	sp, sp, #4	)
+	stmia	sp, {r1 - r12}
+
+	ldmia	r0, {r3 - r5}
+	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""      ""       ""
+	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+ SPFIX(	addeq	r2, r2, #4	)
+	str	r3, [sp, #-4]!		@ save the "real" r0 copied
+					@ from the exception stack
+
+	mov	r3, lr
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r2 - sp_svc
+	@  r3 - lr_svc
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	stmia	r7, {r2 - r6}
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_off
+#endif
+	.endm
+
+/*
+ * User mode handler macros
+ *
+ * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+/*
+ * Vector stubs macro.
+ */
+	.macro	vector_stub, name, mode, correction=0
+	.align	5
+
+vector_\name:
+	.if \correction
+	sub	lr, lr, #\correction
+	.endif
+
+	@
+	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
+	@ (parent CPSR)
+	@
+	stmia	sp, {r0, lr}		@ save r0, lr
+	mrs	lr, spsr
+	str	lr, [sp, #8]		@ save spsr
+
+	@
+	@ Prepare for SVC32 mode.  IRQs remain disabled.
+	@
+	mrs	r0, cpsr
+	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
+	msr	spsr_cxsf, r0
+
+	@
+	@ the branch table must immediately follow this code
+	@
+	and	lr, lr, #0x0f
+ THUMB(	adr	r0, 1f			)
+ THUMB(	ldr	lr, [r0, lr, lsl #2]	)
+	mov	r0, sp
+ ARM(	ldr	lr, [pc, lr, lsl #2]	)
+	movs	pc, lr			@ branch to handler in SVC mode
+ENDPROC(vector_\name)
+
+	.align	2
+	@ handler addresses follow this label
+1:
+	.endm
+
+
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC 4/8] ARM: Add KGDB/KDB FIQ debugger generic code
  2014-05-14 15:58 ` Daniel Thompson
@ 2014-05-14 15:58   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-14 15:58 UTC (permalink / raw)
  To: Jason Wessel, kgdb-bugreport
  Cc: Mark Rutland, kernel, Frederic Weisbecker, Linus Walleij,
	Jiri Slaby, Daniel Thompson, Dirk Behme, Russell King,
	Nicolas Pitre, Ian Campbell, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, patches, Kumar Gala, Rob Herring,
	John Stultz, Thomas Gleixner, linux-arm-kernel,
	Greg Kroah-Hartman

From: Anton Vorontsov <anton.vorontsov@linaro.org>

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

By default KGDB FIQ is disabled in runtime, but can be enabled with
kgdb_fiq.enable=1 kernel command line option.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 ++++++
 arch/arm/include/asm/kgdb.h      |   7 +++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/kgdb_fiq.c       | 117 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S |  87 +++++++++++++++++++++++++++++
 6 files changed, 232 insertions(+)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index db3c541..419fd0a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -307,6 +307,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -356,6 +357,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 6a2bcfd..1f1bec1 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,24 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be
+	  enabled with kgdb_fiq.enable=1 kernel command line option.
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..5de21f01 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,11 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern char kgdb_fiq_handler;
+extern char kgdb_fiq_handler_end;
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs);
+extern int kgdb_register_fiq(unsigned int fiq);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 040619c..251f651 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -67,6 +67,7 @@ endif
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
 obj-$(CONFIG_ARM_THUMBEE)	+= thumbee.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
+obj-$(CONFIG_KGDB_FIQ)		+= kgdb_fiq_entry.o kgdb_fiq.o
 obj-$(CONFIG_ARM_UNWIND)	+= unwind.o
 obj-$(CONFIG_HAVE_TCM)		+= tcm.o
 obj-$(CONFIG_OF)		+= devtree.o
diff --git a/arch/arm/kernel/kgdb_fiq.c b/arch/arm/kernel/kgdb_fiq.c
new file mode 100644
index 0000000..b236409
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq.c
@@ -0,0 +1,117 @@
+/*
+ * KGDB FIQ
+ *
+ * Copyright 2010 Google, Inc.
+ *		  Arve Hjønnevåg <arve@android.com>
+ *		  Colin Cross <ccross@android.com>
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/hardirq.h>
+#include <linux/atomic.h>
+#include <linux/kdb.h>
+#include <linux/kgdb.h>
+#include <asm/fiq.h>
+#include <asm/exception.h>
+
+static int kgdb_fiq_enabled;
+module_param_named(enable, kgdb_fiq_enabled, int, 0600);
+MODULE_PARM_DESC(enable, "set to 1 to enable FIQ KGDB");
+
+static unsigned int kgdb_fiq;
+
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs)
+{
+	if (kgdb_nmi_poll_knock()) {
+		nmi_enter();
+		kgdb_handle_exception(1, 0, 0, regs);
+		nmi_exit();
+	}
+
+	eoi_fiq(kgdb_fiq);
+}
+
+static struct fiq_handler kgdb_fiq_desc = {
+	.name = "kgdb",
+};
+
+static long kgdb_fiq_setup_stack(void *info)
+{
+	struct pt_regs regs;
+
+	regs.ARM_sp = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER) +
+			THREAD_START_SP;
+	WARN_ON(!regs.ARM_sp);
+
+	set_fiq_regs(&regs);
+	return 0;
+}
+
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * This function manages NMIs that usually cause KGDB to enter. That is, not
+ * all NMIs should be enabled or disabled, but only those that issue
+ * kgdb_handle_exception().
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	static atomic_t cnt;
+	int ret;
+
+	ret = atomic_add_return(on ? 1 : -1, &cnt);
+	if (ret > 1 && on) {
+		/*
+		 * There should be only one instance that calls this function
+		 * in "enable, disable" order. All other users must call
+		 * disable first, then enable. If not, something is wrong.
+		 */
+		WARN_ON(1);
+		return;
+	}
+
+	if (ret > 0)
+		enable_fiq(kgdb_fiq);
+	else
+		disable_fiq(kgdb_fiq);
+}
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	int err;
+	int cpu;
+
+	if (!kgdb_fiq_enabled)
+		return -ENODEV;
+
+	kgdb_fiq = fiq;
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	for_each_possible_cpu(cpu)
+		work_on_cpu(cpu, kgdb_fiq_setup_stack, NULL);
+
+	set_fiq_handler(&kgdb_fiq_handler,
+			&kgdb_fiq_handler_end - &kgdb_fiq_handler);
+
+	arch_kgdb_ops.enable_nmi = kgdb_fiq_enable_nmi;
+	return 0;
+}
diff --git a/arch/arm/kernel/kgdb_fiq_entry.S b/arch/arm/kernel/kgdb_fiq_entry.S
new file mode 100644
index 0000000..d6becca
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq_entry.S
@@ -0,0 +1,87 @@
+/*
+ * KGDB FIQ entry
+ *
+ * Copyright 1996,1997,1998 Russell King.
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+#include <asm/unwind.h>
+#include "entry-header.S"
+
+	.text
+
+@ This is needed for usr_entry/alignment_trap
+.LCcralign:
+	.long	cr_alignment
+.LCdohandle:
+	.long	kgdb_fiq_do_handle
+
+	.macro	fiq_handler
+	ldr	r1, =.LCdohandle
+	mov	r0, sp
+	adr	lr, BSYM(9997f)
+	ldr	pc, [r1]
+9997:
+	.endm
+
+	.align	5
+__fiq_svc:
+	svc_entry
+	fiq_handler
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+	.ltorg
+
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+	.ltorg
+
+	.global kgdb_fiq_handler
+kgdb_fiq_handler:
+
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_svc			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
+
+	.global kgdb_fiq_handler_end
+kgdb_fiq_handler_end:
-- 
1.9.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC 4/8] ARM: Add KGDB/KDB FIQ debugger generic code
@ 2014-05-14 15:58   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-14 15:58 UTC (permalink / raw)
  To: linux-arm-kernel

From: Anton Vorontsov <anton.vorontsov@linaro.org>

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

By default KGDB FIQ is disabled in runtime, but can be enabled with
kgdb_fiq.enable=1 kernel command line option.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 ++++++
 arch/arm/include/asm/kgdb.h      |   7 +++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/kgdb_fiq.c       | 117 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S |  87 +++++++++++++++++++++++++++++
 6 files changed, 232 insertions(+)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index db3c541..419fd0a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -307,6 +307,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -356,6 +357,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 6a2bcfd..1f1bec1 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,24 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be
+	  enabled with kgdb_fiq.enable=1 kernel command line option.
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..5de21f01 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,11 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern char kgdb_fiq_handler;
+extern char kgdb_fiq_handler_end;
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs);
+extern int kgdb_register_fiq(unsigned int fiq);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 040619c..251f651 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -67,6 +67,7 @@ endif
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
 obj-$(CONFIG_ARM_THUMBEE)	+= thumbee.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
+obj-$(CONFIG_KGDB_FIQ)		+= kgdb_fiq_entry.o kgdb_fiq.o
 obj-$(CONFIG_ARM_UNWIND)	+= unwind.o
 obj-$(CONFIG_HAVE_TCM)		+= tcm.o
 obj-$(CONFIG_OF)		+= devtree.o
diff --git a/arch/arm/kernel/kgdb_fiq.c b/arch/arm/kernel/kgdb_fiq.c
new file mode 100644
index 0000000..b236409
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq.c
@@ -0,0 +1,117 @@
+/*
+ * KGDB FIQ
+ *
+ * Copyright 2010 Google, Inc.
+ *		  Arve Hj?nnev?g <arve@android.com>
+ *		  Colin Cross <ccross@android.com>
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/hardirq.h>
+#include <linux/atomic.h>
+#include <linux/kdb.h>
+#include <linux/kgdb.h>
+#include <asm/fiq.h>
+#include <asm/exception.h>
+
+static int kgdb_fiq_enabled;
+module_param_named(enable, kgdb_fiq_enabled, int, 0600);
+MODULE_PARM_DESC(enable, "set to 1 to enable FIQ KGDB");
+
+static unsigned int kgdb_fiq;
+
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs)
+{
+	if (kgdb_nmi_poll_knock()) {
+		nmi_enter();
+		kgdb_handle_exception(1, 0, 0, regs);
+		nmi_exit();
+	}
+
+	eoi_fiq(kgdb_fiq);
+}
+
+static struct fiq_handler kgdb_fiq_desc = {
+	.name = "kgdb",
+};
+
+static long kgdb_fiq_setup_stack(void *info)
+{
+	struct pt_regs regs;
+
+	regs.ARM_sp = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER) +
+			THREAD_START_SP;
+	WARN_ON(!regs.ARM_sp);
+
+	set_fiq_regs(&regs);
+	return 0;
+}
+
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * This function manages NMIs that usually cause KGDB to enter. That is, not
+ * all NMIs should be enabled or disabled, but only those that issue
+ * kgdb_handle_exception().
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	static atomic_t cnt;
+	int ret;
+
+	ret = atomic_add_return(on ? 1 : -1, &cnt);
+	if (ret > 1 && on) {
+		/*
+		 * There should be only one instance that calls this function
+		 * in "enable, disable" order. All other users must call
+		 * disable first, then enable. If not, something is wrong.
+		 */
+		WARN_ON(1);
+		return;
+	}
+
+	if (ret > 0)
+		enable_fiq(kgdb_fiq);
+	else
+		disable_fiq(kgdb_fiq);
+}
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	int err;
+	int cpu;
+
+	if (!kgdb_fiq_enabled)
+		return -ENODEV;
+
+	kgdb_fiq = fiq;
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	for_each_possible_cpu(cpu)
+		work_on_cpu(cpu, kgdb_fiq_setup_stack, NULL);
+
+	set_fiq_handler(&kgdb_fiq_handler,
+			&kgdb_fiq_handler_end - &kgdb_fiq_handler);
+
+	arch_kgdb_ops.enable_nmi = kgdb_fiq_enable_nmi;
+	return 0;
+}
diff --git a/arch/arm/kernel/kgdb_fiq_entry.S b/arch/arm/kernel/kgdb_fiq_entry.S
new file mode 100644
index 0000000..d6becca
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq_entry.S
@@ -0,0 +1,87 @@
+/*
+ * KGDB FIQ entry
+ *
+ * Copyright 1996,1997,1998 Russell King.
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+#include <asm/unwind.h>
+#include "entry-header.S"
+
+	.text
+
+@ This is needed for usr_entry/alignment_trap
+.LCcralign:
+	.long	cr_alignment
+.LCdohandle:
+	.long	kgdb_fiq_do_handle
+
+	.macro	fiq_handler
+	ldr	r1, =.LCdohandle
+	mov	r0, sp
+	adr	lr, BSYM(9997f)
+	ldr	pc, [r1]
+9997:
+	.endm
+
+	.align	5
+__fiq_svc:
+	svc_entry
+	fiq_handler
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+	.ltorg
+
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+	.ltorg
+
+	.global kgdb_fiq_handler
+kgdb_fiq_handler:
+
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_svc			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
+
+	.global kgdb_fiq_handler_end
+kgdb_fiq_handler_end:
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC 5/8] serial: amba-pl011: Pass on FIQ information to KGDB.
  2014-05-14 15:58 ` Daniel Thompson
@ 2014-05-14 15:58   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-14 15:58 UTC (permalink / raw)
  To: Jason Wessel, kgdb-bugreport
  Cc: Mark Rutland, kernel, Frederic Weisbecker, Linus Walleij,
	Jiri Slaby, Daniel Thompson, Dirk Behme, Russell King,
	Nicolas Pitre, Ian Campbell, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, patches, Kumar Gala, Rob Herring,
	John Stultz, Thomas Gleixner, linux-arm-kernel,
	Greg Kroah-Hartman

It is important this information comes from the serial driver because, by
doing so, the driver offers "permission" for KGDB to route its interrupt
signal from the drivers own handler to KGDBs FIQ handler (which will
handle the interrupt signal by making polled I/O callbacks).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/tty/serial/amba-pl011.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index dacf0a0..aac817a 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -58,6 +58,7 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/sizes.h>
 #include <linux/io.h>
+#include <linux/kgdb.h>
 
 #define UART_NR			14
 
@@ -2091,6 +2092,18 @@ static int pl011_probe_dt_alias(int index, struct device *dev)
 	return ret;
 }
 
+#ifdef CONFIG_KGDB_FIQ
+/* Register with KGDB if there is a FIQ linked to this device */
+static void pl011_register_fiq(struct amba_device *dev)
+{
+	int fiq = dev->irq[1];
+	if (fiq > 0)
+		kgdb_register_fiq(fiq);
+}
+#else
+static void pl011_register_fiq(struct platform_device *pdev) {}
+#endif
+
 static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
 {
 	struct uart_amba_port *uap;
@@ -2164,11 +2177,14 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
 	}
 
 	ret = uart_add_one_port(&amba_reg, &uap->port);
-	if (ret) {
+	if (0 == ret) {
+		pl011_register_fiq(dev);
+	} else {
 		amba_ports[i] = NULL;
 		uart_unregister_driver(&amba_reg);
 		pl011_dma_remove(uap);
 	}
+
  out:
 	return ret;
 }
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC 5/8] serial: amba-pl011: Pass on FIQ information to KGDB.
@ 2014-05-14 15:58   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-14 15:58 UTC (permalink / raw)
  To: linux-arm-kernel

It is important this information comes from the serial driver because, by
doing so, the driver offers "permission" for KGDB to route its interrupt
signal from the drivers own handler to KGDBs FIQ handler (which will
handle the interrupt signal by making polled I/O callbacks).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/tty/serial/amba-pl011.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index dacf0a0..aac817a 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -58,6 +58,7 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/sizes.h>
 #include <linux/io.h>
+#include <linux/kgdb.h>
 
 #define UART_NR			14
 
@@ -2091,6 +2092,18 @@ static int pl011_probe_dt_alias(int index, struct device *dev)
 	return ret;
 }
 
+#ifdef CONFIG_KGDB_FIQ
+/* Register with KGDB if there is a FIQ linked to this device */
+static void pl011_register_fiq(struct amba_device *dev)
+{
+	int fiq = dev->irq[1];
+	if (fiq > 0)
+		kgdb_register_fiq(fiq);
+}
+#else
+static void pl011_register_fiq(struct platform_device *pdev) {}
+#endif
+
 static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
 {
 	struct uart_amba_port *uap;
@@ -2164,11 +2177,14 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
 	}
 
 	ret = uart_add_one_port(&amba_reg, &uap->port);
-	if (ret) {
+	if (0 == ret) {
+		pl011_register_fiq(dev);
+	} else {
 		amba_ports[i] = NULL;
 		uart_unregister_driver(&amba_reg);
 		pl011_dma_remove(uap);
 	}
+
  out:
 	return ret;
 }
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC 6/8] serial: asc: Add support for KGDB's FIQ/NMI mode
  2014-05-14 15:58 ` Daniel Thompson
@ 2014-05-14 15:58   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-14 15:58 UTC (permalink / raw)
  To: Jason Wessel, kgdb-bugreport
  Cc: Mark Rutland, kernel, Frederic Weisbecker, Linus Walleij,
	Jiri Slaby, Daniel Thompson, Dirk Behme, Russell King,
	Nicolas Pitre, Ian Campbell, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, patches, Kumar Gala, Rob Herring,
	John Stultz, Thomas Gleixner, linux-arm-kernel,
	Greg Kroah-Hartman

For a serial driver to support FIQ/NMI debugging it must enable the RX
interrupt when a polling client attaches itself (otherwise the FIQ signal
will never be asserted). This concept is copied from similar code in
amba-pl011.c .

It must also register the appropriate FIQ number with kgdb. kgdb will use
this to make calls to enable_fiq/disable_fiq/eoi_fiq. The FIQ number must
be supplied via the devices bus (in this case platform bus).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/tty/serial/st-asc.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index c7f61ac..e93803f 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -30,6 +30,7 @@
 #include <linux/of_platform.h>
 #include <linux/serial_core.h>
 #include <linux/clk.h>
+#include <linux/kgdb.h>
 
 #define DRIVER_NAME "st-asc"
 #define ASC_SERIAL_NAME "ttyAS"
@@ -613,6 +614,14 @@ asc_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+static int asc_poll_init(struct uart_port *port)
+{
+	/* enable RX interrupts in case the interrupt is used for NMI entry. */
+	asc_enable_rx_interrupts(port);
+
+	return 0;
+}
+
 /*
  * Console polling routines for writing and reading from the uart while
  * in an interrupt or debug context (i.e. kgdb).
@@ -656,11 +665,25 @@ static struct uart_ops asc_uart_ops = {
 	.verify_port	= asc_verify_port,
 	.pm		= asc_pm,
 #ifdef CONFIG_CONSOLE_POLL
+	.poll_init     = asc_poll_init,
 	.poll_get_char = asc_get_poll_char,
 	.poll_put_char = asc_put_poll_char,
 #endif /* CONFIG_CONSOLE_POLL */
 };
 
+#ifdef CONFIG_KGDB_FIQ
+/* Register with KGDB if there is a FIQ linked to this device */
+static void asc_register_fiq(struct platform_device *pdev)
+{
+	int fiq = platform_get_irq(pdev, 1);
+	if (fiq >= 0)
+		kgdb_register_fiq(fiq);
+}
+#else
+static void asc_register_fiq(struct platform_device *pdev) {}
+#endif
+
+
 static int asc_init_port(struct asc_port *ascport,
 			  struct platform_device *pdev)
 {
@@ -692,6 +715,8 @@ static int asc_init_port(struct asc_port *ascport,
 	WARN_ON(ascport->port.uartclk == 0);
 	clk_disable_unprepare(ascport->clk);
 
+	asc_register_fiq(pdev);
+
 	return 0;
 }
 
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC 6/8] serial: asc: Add support for KGDB's FIQ/NMI mode
@ 2014-05-14 15:58   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-14 15:58 UTC (permalink / raw)
  To: linux-arm-kernel

For a serial driver to support FIQ/NMI debugging it must enable the RX
interrupt when a polling client attaches itself (otherwise the FIQ signal
will never be asserted). This concept is copied from similar code in
amba-pl011.c .

It must also register the appropriate FIQ number with kgdb. kgdb will use
this to make calls to enable_fiq/disable_fiq/eoi_fiq. The FIQ number must
be supplied via the devices bus (in this case platform bus).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/tty/serial/st-asc.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index c7f61ac..e93803f 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -30,6 +30,7 @@
 #include <linux/of_platform.h>
 #include <linux/serial_core.h>
 #include <linux/clk.h>
+#include <linux/kgdb.h>
 
 #define DRIVER_NAME "st-asc"
 #define ASC_SERIAL_NAME "ttyAS"
@@ -613,6 +614,14 @@ asc_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+static int asc_poll_init(struct uart_port *port)
+{
+	/* enable RX interrupts in case the interrupt is used for NMI entry. */
+	asc_enable_rx_interrupts(port);
+
+	return 0;
+}
+
 /*
  * Console polling routines for writing and reading from the uart while
  * in an interrupt or debug context (i.e. kgdb).
@@ -656,11 +665,25 @@ static struct uart_ops asc_uart_ops = {
 	.verify_port	= asc_verify_port,
 	.pm		= asc_pm,
 #ifdef CONFIG_CONSOLE_POLL
+	.poll_init     = asc_poll_init,
 	.poll_get_char = asc_get_poll_char,
 	.poll_put_char = asc_put_poll_char,
 #endif /* CONFIG_CONSOLE_POLL */
 };
 
+#ifdef CONFIG_KGDB_FIQ
+/* Register with KGDB if there is a FIQ linked to this device */
+static void asc_register_fiq(struct platform_device *pdev)
+{
+	int fiq = platform_get_irq(pdev, 1);
+	if (fiq >= 0)
+		kgdb_register_fiq(fiq);
+}
+#else
+static void asc_register_fiq(struct platform_device *pdev) {}
+#endif
+
+
 static int asc_init_port(struct asc_port *ascport,
 			  struct platform_device *pdev)
 {
@@ -692,6 +715,8 @@ static int asc_init_port(struct asc_port *ascport,
 	WARN_ON(ascport->port.uartclk == 0);
 	clk_disable_unprepare(ascport->clk);
 
+	asc_register_fiq(pdev);
+
 	return 0;
 }
 
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC 7/8] ARM: VIC: Add vic_set_fiq function to select if an interrupt should generate an IRQ or FIQ
  2014-05-14 15:58 ` Daniel Thompson
@ 2014-05-14 15:58   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-14 15:58 UTC (permalink / raw)
  To: Jason Wessel, kgdb-bugreport
  Cc: Mark Rutland, kernel, Frederic Weisbecker, Linus Walleij,
	Jiri Slaby, Daniel Thompson, Dirk Behme, Russell King,
	Nicolas Pitre, Ian Campbell, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, patches, Kumar Gala, Rob Herring,
	John Stultz, Thomas Gleixner, linux-arm-kernel,
	Greg Kroah-Hartman

From: Arve Hjønnevåg <arve@android.com>

Signed-off-by: Arve Hjønnevåg <arve@android.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/irqchip/irq-vic.c       | 23 +++++++++++++++++++++++
 include/linux/irqchip/arm-vic.h |  1 +
 2 files changed, 24 insertions(+)

diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287..3eaa2e4 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -337,6 +337,29 @@ static void vic_unmask_irq(struct irq_data *d)
 	writel(1 << irq, base + VIC_INT_ENABLE);
 }
 
+static DEFINE_SPINLOCK(vic_intselect_lock);
+int vic_set_fiq(unsigned int irq, bool enable)
+{
+	u32 int_select;
+	u32 mask;
+	unsigned long irq_flags;
+	void __iomem *base = irq_get_chip_data(irq);
+	irq &= 31;
+	mask = 1 << irq;
+
+	spin_lock_irqsave(&vic_intselect_lock, irq_flags);
+	int_select = readl(base + VIC_INT_SELECT);
+	if (enable)
+		int_select |= mask;
+	else
+		int_select &= ~mask;
+	writel(int_select, base + VIC_INT_SELECT);
+	spin_unlock_irqrestore(&vic_intselect_lock, irq_flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(vic_set_fiq);
+
 #if defined(CONFIG_PM)
 static struct vic_device *vic_from_irq(unsigned int irq)
 {
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index ba46c79..61ee4c9 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -34,5 +34,6 @@ void __vic_init(void __iomem *base, int parent_irq, int irq_start,
 void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
 int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 		      u32 vic_sources, u32 resume_sources);
+int vic_set_fiq(unsigned int irq, bool enable);
 
 #endif
-- 
1.9.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC 7/8] ARM: VIC: Add vic_set_fiq function to select if an interrupt should generate an IRQ or FIQ
@ 2014-05-14 15:58   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-14 15:58 UTC (permalink / raw)
  To: linux-arm-kernel

From: Arve Hj?nnev?g <arve@android.com>

Signed-off-by: Arve Hj?nnev?g <arve@android.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/irqchip/irq-vic.c       | 23 +++++++++++++++++++++++
 include/linux/irqchip/arm-vic.h |  1 +
 2 files changed, 24 insertions(+)

diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287..3eaa2e4 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -337,6 +337,29 @@ static void vic_unmask_irq(struct irq_data *d)
 	writel(1 << irq, base + VIC_INT_ENABLE);
 }
 
+static DEFINE_SPINLOCK(vic_intselect_lock);
+int vic_set_fiq(unsigned int irq, bool enable)
+{
+	u32 int_select;
+	u32 mask;
+	unsigned long irq_flags;
+	void __iomem *base = irq_get_chip_data(irq);
+	irq &= 31;
+	mask = 1 << irq;
+
+	spin_lock_irqsave(&vic_intselect_lock, irq_flags);
+	int_select = readl(base + VIC_INT_SELECT);
+	if (enable)
+		int_select |= mask;
+	else
+		int_select &= ~mask;
+	writel(int_select, base + VIC_INT_SELECT);
+	spin_unlock_irqrestore(&vic_intselect_lock, irq_flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(vic_set_fiq);
+
 #if defined(CONFIG_PM)
 static struct vic_device *vic_from_irq(unsigned int irq)
 {
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index ba46c79..61ee4c9 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -34,5 +34,6 @@ void __vic_init(void __iomem *base, int parent_irq, int irq_start,
 void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
 int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 		      u32 vic_sources, u32 resume_sources);
+int vic_set_fiq(unsigned int irq, bool enable);
 
 #endif
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC 8/8] arm: fiq: Hack FIQ routing backdoors into GIC and VIC
  2014-05-14 15:58 ` Daniel Thompson
@ 2014-05-14 15:58   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-14 15:58 UTC (permalink / raw)
  To: Jason Wessel, kgdb-bugreport
  Cc: Mark Rutland, kernel, Frederic Weisbecker, Linus Walleij,
	Jiri Slaby, Daniel Thompson, Dirk Behme, Russell King,
	Nicolas Pitre, Ian Campbell, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, patches, Kumar Gala, Rob Herring,
	John Stultz, Thomas Gleixner, linux-arm-kernel,
	Greg Kroah-Hartman

This is a hack to make it easy to check that the other interfaces in the
patchset make sense. It needs to be replaced by code to get the
interrupt controllers to expose FIQs.

Unless a better option presents itself I plan to double up each
interrupt source (so we get two virqs, one for regular interrupt and
one for FIQ). This is what most of the prior art around FIQ in Linux
has done in the past.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/boot/dts/stih416.dtsi          |  2 +-
 arch/arm/boot/dts/vexpress-v2m-rs1.dtsi |  2 +-
 arch/arm/kernel/fiq.c                   | 39 +++++++++++++++++++++++++++++++++
 drivers/irqchip/irq-gic.c               | 27 +++++++++++++++++++++++
 4 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/stih416.dtsi b/arch/arm/boot/dts/stih416.dtsi
index 78746d2..a288898 100644
--- a/arch/arm/boot/dts/stih416.dtsi
+++ b/arch/arm/boot/dts/stih416.dtsi
@@ -99,7 +99,7 @@
 			compatible	= "st,asc";
 			status 		= "disabled";
 			reg		= <0xfe531000 0x2c>;
-			interrupts	= <0 210 0>;
+			interrupts	= <0 210 0>, <0 210 0>;
 			pinctrl-names 	= "default";
 			pinctrl-0 	= <&pinctrl_sbc_serial1>;
 			clocks          = <&CLK_SYSIN>;
diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
index ac870fb..fab2a40 100644
--- a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
@@ -140,7 +140,7 @@
 			v2m_serial0: uart@090000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x090000 0x1000>;
-				interrupts = <5>;
+				interrupts = <5>, <5>;
 				clocks = <&v2m_oscclk2>, <&smbclk>;
 				clock-names = "uartclk", "apb_pclk";
 			};
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index defbe85..efce321 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -41,6 +41,7 @@
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
 #include <linux/irq.h>
+#include <linux/irqchip/arm-vic.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -130,14 +131,52 @@ void release_fiq(struct fiq_handler *f)
 
 static int fiq_start;
 
+/* These hacks use backdoors into the interrupt controller to perform FIQ/IRQ
+ * routing. These hacks are nasty and completely incompatible with (working)
+ * multiarch kernels. Additionally these hacks don't count enable/disable
+ * properly...
+ *
+ * This should probably all be replaced with virtual interrupt numbers
+ * that the intc already knows to bind to FIQ.
+ */
+#ifdef CONFIG_ARCH_VERSATILE
+#define USE_VIC_HACK
+#else
+#define USE_GIC_HACK
+#endif
+
 void enable_fiq(int fiq)
 {
+#ifdef USE_VIC_HACK
+	vic_set_fiq(fiq, true);
+#endif
+#ifdef USE_GIC_HACK
+{
+	struct irq_data *irq_data = irq_get_irq_data(fiq);
+
+	extern void gic_set_group_irq(struct irq_data *d, int group);
+	gic_set_group_irq(irq_data, 0);
+}
+#endif
+
 	enable_irq(fiq + fiq_start);
 }
 
 void disable_fiq(int fiq)
 {
 	disable_irq(fiq + fiq_start);
+
+#ifdef USE_VIC_HACK
+	vic_set_fiq(fiq, false);
+#endif
+#ifdef USE_GIC_HACK
+{
+	struct irq_data *irq_data = irq_get_irq_data(fiq);
+
+	extern void gic_set_group_irq(struct irq_data *d, int group);
+	gic_set_group_irq(irq_data, 1);
+}
+#endif
 }
 
 void eoi_fiq(int fiq)
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index aa8efe4..c25632b 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -173,6 +173,33 @@ static void gic_unmask_irq(struct irq_data *d)
 	raw_spin_unlock(&irq_controller_lock);
 }
 
+/*static*/ void gic_set_group_irq(struct irq_data *d, int group)
+{
+	unsigned long flags;
+	unsigned int reg = gic_irq(d) / 32 * 4;
+	u32 mask = 1 << (gic_irq(d) % 32);
+	u32 val;
+
+	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+	val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + reg);
+	if (group)
+		val |= mask;
+	else
+		val &= ~mask;
+	writel_relaxed(val, gic_dist_base(d) + GIC_DIST_IGROUP + reg);
+	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
+
+/*static*/ int gic_get_group_irq(struct irq_data *d)
+{
+	unsigned int reg = gic_irq(d) / 32 * 4;
+	u32 mask = 1 << (gic_irq(d) % 32);
+	u32 val;
+
+	val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + reg);
+	return !!(val & mask);
+}
+
 static void gic_eoi_irq(struct irq_data *d)
 {
 	if (gic_arch_extn.irq_eoi) {
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC 8/8] arm: fiq: Hack FIQ routing backdoors into GIC and VIC
@ 2014-05-14 15:58   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-14 15:58 UTC (permalink / raw)
  To: linux-arm-kernel

This is a hack to make it easy to check that the other interfaces in the
patchset make sense. It needs to be replaced by code to get the
interrupt controllers to expose FIQs.

Unless a better option presents itself I plan to double up each
interrupt source (so we get two virqs, one for regular interrupt and
one for FIQ). This is what most of the prior art around FIQ in Linux
has done in the past.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/boot/dts/stih416.dtsi          |  2 +-
 arch/arm/boot/dts/vexpress-v2m-rs1.dtsi |  2 +-
 arch/arm/kernel/fiq.c                   | 39 +++++++++++++++++++++++++++++++++
 drivers/irqchip/irq-gic.c               | 27 +++++++++++++++++++++++
 4 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/stih416.dtsi b/arch/arm/boot/dts/stih416.dtsi
index 78746d2..a288898 100644
--- a/arch/arm/boot/dts/stih416.dtsi
+++ b/arch/arm/boot/dts/stih416.dtsi
@@ -99,7 +99,7 @@
 			compatible	= "st,asc";
 			status 		= "disabled";
 			reg		= <0xfe531000 0x2c>;
-			interrupts	= <0 210 0>;
+			interrupts	= <0 210 0>, <0 210 0>;
 			pinctrl-names 	= "default";
 			pinctrl-0 	= <&pinctrl_sbc_serial1>;
 			clocks          = <&CLK_SYSIN>;
diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
index ac870fb..fab2a40 100644
--- a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
@@ -140,7 +140,7 @@
 			v2m_serial0: uart at 090000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x090000 0x1000>;
-				interrupts = <5>;
+				interrupts = <5>, <5>;
 				clocks = <&v2m_oscclk2>, <&smbclk>;
 				clock-names = "uartclk", "apb_pclk";
 			};
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index defbe85..efce321 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -41,6 +41,7 @@
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
 #include <linux/irq.h>
+#include <linux/irqchip/arm-vic.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -130,14 +131,52 @@ void release_fiq(struct fiq_handler *f)
 
 static int fiq_start;
 
+/* These hacks use backdoors into the interrupt controller to perform FIQ/IRQ
+ * routing. These hacks are nasty and completely incompatible with (working)
+ * multiarch kernels. Additionally these hacks don't count enable/disable
+ * properly...
+ *
+ * This should probably all be replaced with virtual interrupt numbers
+ * that the intc already knows to bind to FIQ.
+ */
+#ifdef CONFIG_ARCH_VERSATILE
+#define USE_VIC_HACK
+#else
+#define USE_GIC_HACK
+#endif
+
 void enable_fiq(int fiq)
 {
+#ifdef USE_VIC_HACK
+	vic_set_fiq(fiq, true);
+#endif
+#ifdef USE_GIC_HACK
+{
+	struct irq_data *irq_data = irq_get_irq_data(fiq);
+
+	extern void gic_set_group_irq(struct irq_data *d, int group);
+	gic_set_group_irq(irq_data, 0);
+}
+#endif
+
 	enable_irq(fiq + fiq_start);
 }
 
 void disable_fiq(int fiq)
 {
 	disable_irq(fiq + fiq_start);
+
+#ifdef USE_VIC_HACK
+	vic_set_fiq(fiq, false);
+#endif
+#ifdef USE_GIC_HACK
+{
+	struct irq_data *irq_data = irq_get_irq_data(fiq);
+
+	extern void gic_set_group_irq(struct irq_data *d, int group);
+	gic_set_group_irq(irq_data, 1);
+}
+#endif
 }
 
 void eoi_fiq(int fiq)
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index aa8efe4..c25632b 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -173,6 +173,33 @@ static void gic_unmask_irq(struct irq_data *d)
 	raw_spin_unlock(&irq_controller_lock);
 }
 
+/*static*/ void gic_set_group_irq(struct irq_data *d, int group)
+{
+	unsigned long flags;
+	unsigned int reg = gic_irq(d) / 32 * 4;
+	u32 mask = 1 << (gic_irq(d) % 32);
+	u32 val;
+
+	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+	val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + reg);
+	if (group)
+		val |= mask;
+	else
+		val &= ~mask;
+	writel_relaxed(val, gic_dist_base(d) + GIC_DIST_IGROUP + reg);
+	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
+
+/*static*/ int gic_get_group_irq(struct irq_data *d)
+{
+	unsigned int reg = gic_irq(d) / 32 * 4;
+	u32 mask = 1 << (gic_irq(d) % 32);
+	u32 val;
+
+	val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + reg);
+	return !!(val & mask);
+}
+
 static void gic_eoi_irq(struct irq_data *d)
 {
 	if (gic_arch_extn.irq_eoi) {
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 00/10] kgdb: NMI/FIQ support for ARM
  2014-05-14 15:58 ` Daniel Thompson
@ 2014-05-23 13:57   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Ian Campbell, Anton Vorontsov, David A. Long, linux-serial,
	Catalin Marinas, kernel-team, devicetree, linaro-kernel,
	Pawel Moll, patches, Kumar Gala, Rob Herring, John Stultz,
	Thomas Gleixner, linux-arm-kernel, Greg Kroah-Hartman

This patchset makes it possible to use the kgdb NMI infrastructure
on ARM platforms by providing a mutli-arch compatible means for drivers
to manage FIQ routings.

First a quick summary of how the mainline kgdb NMI infrastructure
(mostly found in drivers/tty/serial/kgdb_nmi.c) works. The kgdb
infrastructure will re-route the kgdb console UART's interrupt signal
from IRQ to FIQ. Naturally the UART will no longer function normally and
will instead be managed by kgdb using the polled I/O functions. Any
character delivered to the UART causes the kgdb handler function to be
called.

Note that, within this patchset a serial driver explicitly consents (or 
not) to the abuse outlined by calling the appropriate registration
during the .poll_init() callback.

The patch set is structured as follows:

  The first six patches modify the interrupt system to make it easier
  to describe FIQ. The key concept is that a call to enable_fiq() must
  modify the IRQ/FIQ routing to that the FIQ really is enabled (rather
  than spuriously delivering the signal on the IRQ). To achieve this
  each interrupt controller registers two virqs for each hwirq (allowing
  IRQ and FIQ to be readily distinguished).

  The next two patches (7 and 8) provide kgdb with a FIQ handler and
  a means for serial drivers to register their FIQ with kgdb.

  Finally two example serial drivers are modified in order to register
  their FIQs with kgdb.

Major remaining TODO item is to modify the code to halt the other CPUs;
at present this code sends IPIs (which use a normal IRQ) and busy waits
for the other CPUs to halt. This means the benefits of invoking the
debugger via NMI are not support realized on SMP systems. However I plan
to tackle that later (i.e.  when there's some consensus on whether this
approach is the right way to handle FIQ).
 
Changes since v1:

* Fully fledged multi-arch support.

* Tested for correct FIQ operation on STiH416/B2020 (Cortex A9),
  qemu/versatile and qemu/vexpress-a15 (with self-written mods to the
  GIC model to support FIQ).

* Regression tested (and resulting bugs fixed) on qemu/versatile+DT and
  qemu/integreatorcp.


Anton Vorontsov (2):
  ARM: Move some macros from entry-armv to entry-header
  ARM: Add KGDB/KDB FIQ debugger generic code

Daniel Thompson (8):
  arm: fiq: Allow EOI to be communicated to the intc
  irqchip: gic: Provide support for interrupt grouping
  irqchip: gic: Introduce shadow irqs for FIQ
  ARM: vexpress: Extend UART with FIQ support
  ARM: STi: STiH41x: Extend UART with FIQ support.
  irqchip: vic: Introduce shadow irqs for FIQ
  serial: amba-pl011: Pass on FIQ information to KGDB.
  serial: asc: Add support for KGDB's FIQ/NMI mode

 arch/arm/Kconfig                            |   2 +
 arch/arm/Kconfig.debug                      |  18 +++
 arch/arm/boot/dts/stih415.dtsi              |   4 +-
 arch/arm/boot/dts/stih416.dtsi              |   4 +-
 arch/arm/boot/dts/vexpress-v2m-rs1.dtsi     |   8 +-
 arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts |  10 +-
 arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts  |   8 +-
 arch/arm/boot/dts/vexpress-v2p-ca5s.dts     |  10 +-
 arch/arm/include/asm/fiq.h                  |   1 +
 arch/arm/include/asm/kgdb.h                 |   7 ++
 arch/arm/kernel/Makefile                    |   1 +
 arch/arm/kernel/entry-armv.S                | 151 +------------------------
 arch/arm/kernel/entry-header.S              | 164 ++++++++++++++++++++++++++++
 arch/arm/kernel/fiq.c                       |  11 ++
 arch/arm/kernel/kgdb_fiq.c                  | 117 ++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S            |  87 +++++++++++++++
 arch/arm/mach-ep93xx/core.c                 |   6 +-
 arch/arm/mach-netx/generic.c                |   3 +-
 arch/arm/mach-s3c64xx/common.c              |   6 +-
 arch/arm/mach-versatile/core.c              |   9 +-
 arch/arm/mach-versatile/include/mach/irqs.h |  76 ++++++-------
 arch/arm/plat-samsung/s5p-irq.c             |   3 +-
 drivers/irqchip/irq-gic.c                   |  81 ++++++++++++--
 drivers/irqchip/irq-vic.c                   |  87 ++++++++++++---
 drivers/tty/serial/amba-pl011.c             | 101 ++++++++++-------
 drivers/tty/serial/st-asc.c                 |  27 +++++
 include/linux/irqchip/arm-gic.h             |   3 +
 include/linux/irqchip/arm-vic.h             |   8 +-
 28 files changed, 733 insertions(+), 280 deletions(-)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

-- 
1.9.0

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v2 00/10] kgdb: NMI/FIQ support for ARM
@ 2014-05-23 13:57   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset makes it possible to use the kgdb NMI infrastructure
on ARM platforms by providing a mutli-arch compatible means for drivers
to manage FIQ routings.

First a quick summary of how the mainline kgdb NMI infrastructure
(mostly found in drivers/tty/serial/kgdb_nmi.c) works. The kgdb
infrastructure will re-route the kgdb console UART's interrupt signal
from IRQ to FIQ. Naturally the UART will no longer function normally and
will instead be managed by kgdb using the polled I/O functions. Any
character delivered to the UART causes the kgdb handler function to be
called.

Note that, within this patchset a serial driver explicitly consents (or 
not) to the abuse outlined by calling the appropriate registration
during the .poll_init() callback.

The patch set is structured as follows:

  The first six patches modify the interrupt system to make it easier
  to describe FIQ. The key concept is that a call to enable_fiq() must
  modify the IRQ/FIQ routing to that the FIQ really is enabled (rather
  than spuriously delivering the signal on the IRQ). To achieve this
  each interrupt controller registers two virqs for each hwirq (allowing
  IRQ and FIQ to be readily distinguished).

  The next two patches (7 and 8) provide kgdb with a FIQ handler and
  a means for serial drivers to register their FIQ with kgdb.

  Finally two example serial drivers are modified in order to register
  their FIQs with kgdb.

Major remaining TODO item is to modify the code to halt the other CPUs;
at present this code sends IPIs (which use a normal IRQ) and busy waits
for the other CPUs to halt. This means the benefits of invoking the
debugger via NMI are not support realized on SMP systems. However I plan
to tackle that later (i.e.  when there's some consensus on whether this
approach is the right way to handle FIQ).
 
Changes since v1:

* Fully fledged multi-arch support.

* Tested for correct FIQ operation on STiH416/B2020 (Cortex A9),
  qemu/versatile and qemu/vexpress-a15 (with self-written mods to the
  GIC model to support FIQ).

* Regression tested (and resulting bugs fixed) on qemu/versatile+DT and
  qemu/integreatorcp.


Anton Vorontsov (2):
  ARM: Move some macros from entry-armv to entry-header
  ARM: Add KGDB/KDB FIQ debugger generic code

Daniel Thompson (8):
  arm: fiq: Allow EOI to be communicated to the intc
  irqchip: gic: Provide support for interrupt grouping
  irqchip: gic: Introduce shadow irqs for FIQ
  ARM: vexpress: Extend UART with FIQ support
  ARM: STi: STiH41x: Extend UART with FIQ support.
  irqchip: vic: Introduce shadow irqs for FIQ
  serial: amba-pl011: Pass on FIQ information to KGDB.
  serial: asc: Add support for KGDB's FIQ/NMI mode

 arch/arm/Kconfig                            |   2 +
 arch/arm/Kconfig.debug                      |  18 +++
 arch/arm/boot/dts/stih415.dtsi              |   4 +-
 arch/arm/boot/dts/stih416.dtsi              |   4 +-
 arch/arm/boot/dts/vexpress-v2m-rs1.dtsi     |   8 +-
 arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts |  10 +-
 arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts  |   8 +-
 arch/arm/boot/dts/vexpress-v2p-ca5s.dts     |  10 +-
 arch/arm/include/asm/fiq.h                  |   1 +
 arch/arm/include/asm/kgdb.h                 |   7 ++
 arch/arm/kernel/Makefile                    |   1 +
 arch/arm/kernel/entry-armv.S                | 151 +------------------------
 arch/arm/kernel/entry-header.S              | 164 ++++++++++++++++++++++++++++
 arch/arm/kernel/fiq.c                       |  11 ++
 arch/arm/kernel/kgdb_fiq.c                  | 117 ++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S            |  87 +++++++++++++++
 arch/arm/mach-ep93xx/core.c                 |   6 +-
 arch/arm/mach-netx/generic.c                |   3 +-
 arch/arm/mach-s3c64xx/common.c              |   6 +-
 arch/arm/mach-versatile/core.c              |   9 +-
 arch/arm/mach-versatile/include/mach/irqs.h |  76 ++++++-------
 arch/arm/plat-samsung/s5p-irq.c             |   3 +-
 drivers/irqchip/irq-gic.c                   |  81 ++++++++++++--
 drivers/irqchip/irq-vic.c                   |  87 ++++++++++++---
 drivers/tty/serial/amba-pl011.c             | 101 ++++++++++-------
 drivers/tty/serial/st-asc.c                 |  27 +++++
 include/linux/irqchip/arm-gic.h             |   3 +
 include/linux/irqchip/arm-vic.h             |   8 +-
 28 files changed, 733 insertions(+), 280 deletions(-)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

-- 
1.9.0

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v2 01/10] arm: fiq: Allow EOI to be communicated to the intc
  2014-05-23 13:57   ` Daniel Thompson
@ 2014-05-23 13:57     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Fabio Estevam, Ian Campbell, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, patches, Kumar Gala, Rob Herring,
	John Stultz, Thomas Gleixner, linux-arm-kernel

Modern ARM systems require an EOI to be sent to the interrupt controller
on completion of both IRQ and FIQ. The FIQ code currently does not provide
any API to perform this. This patch provides this API, implemented by
hooking into main irq driver in a similar way to the existing
enable_fiq()/disable_fiq().

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/include/asm/fiq.h |  1 +
 arch/arm/kernel/fiq.c      | 11 +++++++++++
 2 files changed, 12 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..5a2a9b9 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -38,6 +38,7 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern void eoi_fiq(int fiq);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..defbe85 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -139,6 +140,15 @@ void disable_fiq(int fiq)
 	disable_irq(fiq + fiq_start);
 }
 
+void eoi_fiq(int fiq)
+{
+	struct irq_data *irq_data = irq_get_irq_data(fiq + fiq_start);
+	struct irq_chip *chip = irq_data_get_irq_chip(irq_data);
+
+	if (chip->irq_eoi)
+			chip->irq_eoi(irq_data);
+}
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -146,6 +156,7 @@ EXPORT_SYMBOL(claim_fiq);
 EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
+EXPORT_SYMBOL(eoi_fiq);
 
 void __init init_FIQ(int start)
 {
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 01/10] arm: fiq: Allow EOI to be communicated to the intc
@ 2014-05-23 13:57     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: linux-arm-kernel

Modern ARM systems require an EOI to be sent to the interrupt controller
on completion of both IRQ and FIQ. The FIQ code currently does not provide
any API to perform this. This patch provides this API, implemented by
hooking into main irq driver in a similar way to the existing
enable_fiq()/disable_fiq().

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/include/asm/fiq.h |  1 +
 arch/arm/kernel/fiq.c      | 11 +++++++++++
 2 files changed, 12 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..5a2a9b9 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -38,6 +38,7 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern void eoi_fiq(int fiq);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..defbe85 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -139,6 +140,15 @@ void disable_fiq(int fiq)
 	disable_irq(fiq + fiq_start);
 }
 
+void eoi_fiq(int fiq)
+{
+	struct irq_data *irq_data = irq_get_irq_data(fiq + fiq_start);
+	struct irq_chip *chip = irq_data_get_irq_chip(irq_data);
+
+	if (chip->irq_eoi)
+			chip->irq_eoi(irq_data);
+}
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -146,6 +156,7 @@ EXPORT_SYMBOL(claim_fiq);
 EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
+EXPORT_SYMBOL(eoi_fiq);
 
 void __init init_FIQ(int start)
 {
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 02/10] irqchip: gic: Provide support for interrupt grouping
  2014-05-23 13:57   ` Daniel Thompson
@ 2014-05-23 13:57     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, Nicolas Pitre, kernel, kgdb-bugreport,
	Linus Walleij, Sricharan R, Jiri Slaby, Daniel Thompson,
	Dirk Behme, Russell King, Nicolas Pitre, Ian Campbell,
	Anton Vorontsov, David A. Long, linux-serial, Catalin Marinas,
	kernel-team, devicetree, linaro-kernel, Jason Cooper, Pawel Moll,
	patches, Kumar Gala, Rob Herring, John Stultz

All GIC hardware except GICv1 without TrustZone support provides a means
to group exceptions into group 0 (which can optionally be signally using
use FIQ) and group 1. The kernel currently provides no means to exploit
this. This patch alters the initialization of the GIC to place all
interrupts into group 1, this is a foundational requirement to meaningfully
use FIQ.

Note that the hardware functionality is unavailable to the kernel when a
secure monitor is present because access to the grouping registers are
prohibited outside "secure world". This allows grouping to be used to
allow hardware peripherals to send interrupts into the secure world.

On systems without TrustZone support the kernel has the power to
route interrupt sources to FIQ, potentially allowing a driver to exploit the
NMI-like properties of FIQ.

The registers involved are RAZ/WI when unimplemented or protected by
security policy. This patch therefore applies grouping unconditionally.

Tested on a qemu GICv2 model (self-written from GICv2 spec) and
an STiH416 (ARM Cortex A9, GICv1, TZ).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
Acked-by: Dirk Behme <dirk.behme@de.bosch.com>
---
 drivers/irqchip/irq-gic.c       | 35 ++++++++++++++++++++++++++++++-----
 include/linux/irqchip/arm-gic.h |  3 +++
 2 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 57d165e..aa8efe4 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -408,13 +408,27 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 		writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
 
 	/*
+	 * Set all global interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers a read-as-zero/write-ignored.
+	 */
+	for (i = 32; i < gic_irqs; i += 32)
+		writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
 	 * Disable all interrupts.  Leave the PPI and SGIs alone
 	 * as these enables are banked registers.
 	 */
 	for (i = 32; i < gic_irqs; i += 32)
 		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	writel_relaxed(GIC_DIST_CTRL_ENABLE_GRP0_BIT |
+		       GIC_DIST_CTRL_ENABLE_GRP1_BIT, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -452,8 +466,16 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	for (i = 0; i < 32; i += 4)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
 
+	/*
+	 * Set all PPI and SGI interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers are read-as-zero/write-ignored.
+	 */
+	writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -537,7 +559,9 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	writel_relaxed(GIC_DIST_CTRL_ENABLE_GRP0_BIT |
+			   GIC_DIST_CTRL_ENABLE_GRP1_BIT,
+		       dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -594,7 +618,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -670,7 +694,8 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+	writel_relaxed(map << 16 | irq | 0x8000,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 7ed92d0..919502f 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -37,6 +37,9 @@
 #define GIC_DIST_SGI_PENDING_CLEAR	0xf10
 #define GIC_DIST_SGI_PENDING_SET	0xf20
 
+#define GIC_DIST_CTRL_ENABLE_GRP0_BIT	(1 << 0)
+#define GIC_DIST_CTRL_ENABLE_GRP1_BIT	(1 << 1)
+
 #define GICH_HCR			0x0
 #define GICH_VTR			0x4
 #define GICH_VMCR			0x8
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 02/10] irqchip: gic: Provide support for interrupt grouping
@ 2014-05-23 13:57     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: linux-arm-kernel

All GIC hardware except GICv1 without TrustZone support provides a means
to group exceptions into group 0 (which can optionally be signally using
use FIQ) and group 1. The kernel currently provides no means to exploit
this. This patch alters the initialization of the GIC to place all
interrupts into group 1, this is a foundational requirement to meaningfully
use FIQ.

Note that the hardware functionality is unavailable to the kernel when a
secure monitor is present because access to the grouping registers are
prohibited outside "secure world". This allows grouping to be used to
allow hardware peripherals to send interrupts into the secure world.

On systems without TrustZone support the kernel has the power to
route interrupt sources to FIQ, potentially allowing a driver to exploit the
NMI-like properties of FIQ.

The registers involved are RAZ/WI when unimplemented or protected by
security policy. This patch therefore applies grouping unconditionally.

Tested on a qemu GICv2 model (self-written from GICv2 spec) and
an STiH416 (ARM Cortex A9, GICv1, TZ).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
Acked-by: Dirk Behme <dirk.behme@de.bosch.com>
---
 drivers/irqchip/irq-gic.c       | 35 ++++++++++++++++++++++++++++++-----
 include/linux/irqchip/arm-gic.h |  3 +++
 2 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 57d165e..aa8efe4 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -408,13 +408,27 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 		writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
 
 	/*
+	 * Set all global interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers a read-as-zero/write-ignored.
+	 */
+	for (i = 32; i < gic_irqs; i += 32)
+		writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
 	 * Disable all interrupts.  Leave the PPI and SGIs alone
 	 * as these enables are banked registers.
 	 */
 	for (i = 32; i < gic_irqs; i += 32)
 		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	writel_relaxed(GIC_DIST_CTRL_ENABLE_GRP0_BIT |
+		       GIC_DIST_CTRL_ENABLE_GRP1_BIT, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -452,8 +466,16 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	for (i = 0; i < 32; i += 4)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
 
+	/*
+	 * Set all PPI and SGI interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers are read-as-zero/write-ignored.
+	 */
+	writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -537,7 +559,9 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	writel_relaxed(GIC_DIST_CTRL_ENABLE_GRP0_BIT |
+			   GIC_DIST_CTRL_ENABLE_GRP1_BIT,
+		       dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -594,7 +618,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -670,7 +694,8 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+	writel_relaxed(map << 16 | irq | 0x8000,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 7ed92d0..919502f 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -37,6 +37,9 @@
 #define GIC_DIST_SGI_PENDING_CLEAR	0xf10
 #define GIC_DIST_SGI_PENDING_SET	0xf20
 
+#define GIC_DIST_CTRL_ENABLE_GRP0_BIT	(1 << 0)
+#define GIC_DIST_CTRL_ENABLE_GRP1_BIT	(1 << 1)
+
 #define GICH_HCR			0x0
 #define GICH_VTR			0x4
 #define GICH_VMCR			0x8
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 03/10] irqchip: gic: Introduce shadow irqs for FIQ
  2014-05-23 13:57   ` Daniel Thompson
@ 2014-05-23 13:57     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, Nicolas Pitre, kernel, kgdb-bugreport,
	Linus Walleij, Sricharan R, Jiri Slaby, Daniel Thompson,
	Dirk Behme, Russell King, Nicolas Pitre, Ian Campbell,
	Anton Vorontsov, David A. Long, linux-serial, Catalin Marinas,
	kernel-team, devicetree, linaro-kernel, Jason Cooper, Pawel Moll,
	patches, Kumar Gala, Rob Herring, John Stultz

This patch registers two virqs for each interrupt source it supports.
Using multiple virqs allows the GIC driver to automatically modify the group
register, allowing the new virqs to be used as argument to enable_fiq().
This also allows FIQ resources to be described in the device tree's
interrupt list using a special flag (currently 0x80).

Both these aspects combine and allow a driver to deploy a FIQ handler
without any machine specific knowledge; it can be used effectively on
multi-arch kernels.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc:: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
---
 drivers/irqchip/irq-gic.c | 46 +++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 41 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index aa8efe4..0c259ac 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -48,6 +48,8 @@
 
 #include "irqchip.h"
 
+#define GIC_INTSPEC_IRQ_IS_FIQ (1 << 7)
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -65,6 +67,7 @@ struct gic_chip_data {
 #endif
 	struct irq_domain *domain;
 	unsigned int gic_irqs;
+	unsigned int fiq_shadow_offset;
 #ifdef CONFIG_GIC_NON_BANKED
 	void __iomem *(*get_base)(union gic_base *);
 #endif
@@ -143,11 +146,34 @@ static inline void __iomem *gic_cpu_base(struct irq_data *d)
 	return gic_data_cpu_base(gic_data);
 }
 
+static inline bool gic_is_fiq(struct irq_data *d)
+{
+	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
+	return d->hwirq > gic_data->gic_irqs;
+}
+
 static inline unsigned int gic_irq(struct irq_data *d)
 {
+	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
+	if (gic_is_fiq(d))
+		return d->hwirq - gic_data->fiq_shadow_offset;
 	return d->hwirq;
 }
 
+static void gic_set_group_irq(struct irq_data *d, int group)
+{
+	unsigned int reg = gic_irq(d) / 32 * 4;
+	u32 mask = 1 << (gic_irq(d) % 32);
+	u32 val;
+
+	val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + reg);
+	if (group)
+		val |= mask;
+	else
+		val &= ~mask;
+	writel_relaxed(val, gic_dist_base(d) + GIC_DIST_IGROUP + reg);
+}
+
 /*
  * Routines to acknowledge, disable and enable interrupts
  */
@@ -159,6 +185,8 @@ static void gic_mask_irq(struct irq_data *d)
 	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
 	if (gic_arch_extn.irq_mask)
 		gic_arch_extn.irq_mask(d);
+	if (gic_is_fiq(d))
+		gic_set_group_irq(d, 1);
 	raw_spin_unlock(&irq_controller_lock);
 }
 
@@ -167,6 +195,8 @@ static void gic_unmask_irq(struct irq_data *d)
 	u32 mask = 1 << (gic_irq(d) % 32);
 
 	raw_spin_lock(&irq_controller_lock);
+	if (gic_is_fiq(d))
+		gic_set_group_irq(d, 0);
 	if (gic_arch_extn.irq_unmask)
 		gic_arch_extn.irq_unmask(d);
 	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
@@ -940,7 +970,12 @@ static int gic_routable_irq_domain_xlate(struct irq_domain *d,
 				unsigned long *out_hwirq,
 				unsigned int *out_type)
 {
+	struct gic_chip_data *gic_data = d->host_data;
 	*out_hwirq += 16;
+
+	if (intspec[2] & GIC_INTSPEC_IRQ_IS_FIQ)
+		*out_hwirq += gic_data->fiq_shadow_offset;
+
 	return 0;
 }
 
@@ -1026,10 +1061,11 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 	gic->gic_irqs = gic_irqs;
 
 	gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
+	gic->fiq_shadow_offset = gic_irqs;
 
 	if (of_property_read_u32(node, "arm,routable-irqs",
 				 &nr_routable_irqs)) {
-		irq_base = irq_alloc_descs(irq_start, 16, gic_irqs,
+		irq_base = irq_alloc_descs(irq_start, 16, 2 * gic_irqs,
 					   numa_node_id());
 		if (IS_ERR_VALUE(irq_base)) {
 			WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
@@ -1037,12 +1073,12 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 			irq_base = irq_start;
 		}
 
-		gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
-					hwirq_base, &gic_irq_domain_ops, gic);
+		gic->domain =
+		    irq_domain_add_legacy(node, 2 * gic_irqs, irq_base,
+					  hwirq_base, &gic_irq_domain_ops, gic);
 	} else {
 		gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
-						    &gic_irq_domain_ops,
-						    gic);
+						    &gic_irq_domain_ops, gic);
 	}
 
 	if (WARN_ON(!gic->domain))
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 03/10] irqchip: gic: Introduce shadow irqs for FIQ
@ 2014-05-23 13:57     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: linux-arm-kernel

This patch registers two virqs for each interrupt source it supports.
Using multiple virqs allows the GIC driver to automatically modify the group
register, allowing the new virqs to be used as argument to enable_fiq().
This also allows FIQ resources to be described in the device tree's
interrupt list using a special flag (currently 0x80).

Both these aspects combine and allow a driver to deploy a FIQ handler
without any machine specific knowledge; it can be used effectively on
multi-arch kernels.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc:: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
---
 drivers/irqchip/irq-gic.c | 46 +++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 41 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index aa8efe4..0c259ac 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -48,6 +48,8 @@
 
 #include "irqchip.h"
 
+#define GIC_INTSPEC_IRQ_IS_FIQ (1 << 7)
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -65,6 +67,7 @@ struct gic_chip_data {
 #endif
 	struct irq_domain *domain;
 	unsigned int gic_irqs;
+	unsigned int fiq_shadow_offset;
 #ifdef CONFIG_GIC_NON_BANKED
 	void __iomem *(*get_base)(union gic_base *);
 #endif
@@ -143,11 +146,34 @@ static inline void __iomem *gic_cpu_base(struct irq_data *d)
 	return gic_data_cpu_base(gic_data);
 }
 
+static inline bool gic_is_fiq(struct irq_data *d)
+{
+	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
+	return d->hwirq > gic_data->gic_irqs;
+}
+
 static inline unsigned int gic_irq(struct irq_data *d)
 {
+	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
+	if (gic_is_fiq(d))
+		return d->hwirq - gic_data->fiq_shadow_offset;
 	return d->hwirq;
 }
 
+static void gic_set_group_irq(struct irq_data *d, int group)
+{
+	unsigned int reg = gic_irq(d) / 32 * 4;
+	u32 mask = 1 << (gic_irq(d) % 32);
+	u32 val;
+
+	val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + reg);
+	if (group)
+		val |= mask;
+	else
+		val &= ~mask;
+	writel_relaxed(val, gic_dist_base(d) + GIC_DIST_IGROUP + reg);
+}
+
 /*
  * Routines to acknowledge, disable and enable interrupts
  */
@@ -159,6 +185,8 @@ static void gic_mask_irq(struct irq_data *d)
 	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
 	if (gic_arch_extn.irq_mask)
 		gic_arch_extn.irq_mask(d);
+	if (gic_is_fiq(d))
+		gic_set_group_irq(d, 1);
 	raw_spin_unlock(&irq_controller_lock);
 }
 
@@ -167,6 +195,8 @@ static void gic_unmask_irq(struct irq_data *d)
 	u32 mask = 1 << (gic_irq(d) % 32);
 
 	raw_spin_lock(&irq_controller_lock);
+	if (gic_is_fiq(d))
+		gic_set_group_irq(d, 0);
 	if (gic_arch_extn.irq_unmask)
 		gic_arch_extn.irq_unmask(d);
 	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
@@ -940,7 +970,12 @@ static int gic_routable_irq_domain_xlate(struct irq_domain *d,
 				unsigned long *out_hwirq,
 				unsigned int *out_type)
 {
+	struct gic_chip_data *gic_data = d->host_data;
 	*out_hwirq += 16;
+
+	if (intspec[2] & GIC_INTSPEC_IRQ_IS_FIQ)
+		*out_hwirq += gic_data->fiq_shadow_offset;
+
 	return 0;
 }
 
@@ -1026,10 +1061,11 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 	gic->gic_irqs = gic_irqs;
 
 	gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
+	gic->fiq_shadow_offset = gic_irqs;
 
 	if (of_property_read_u32(node, "arm,routable-irqs",
 				 &nr_routable_irqs)) {
-		irq_base = irq_alloc_descs(irq_start, 16, gic_irqs,
+		irq_base = irq_alloc_descs(irq_start, 16, 2 * gic_irqs,
 					   numa_node_id());
 		if (IS_ERR_VALUE(irq_base)) {
 			WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
@@ -1037,12 +1073,12 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 			irq_base = irq_start;
 		}
 
-		gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
-					hwirq_base, &gic_irq_domain_ops, gic);
+		gic->domain =
+		    irq_domain_add_legacy(node, 2 * gic_irqs, irq_base,
+					  hwirq_base, &gic_irq_domain_ops, gic);
 	} else {
 		gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
-						    &gic_irq_domain_ops,
-						    gic);
+						    &gic_irq_domain_ops, gic);
 	}
 
 	if (WARN_ON(!gic->domain))
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 04/10] ARM: vexpress: Extend UART with FIQ support
  2014-05-23 13:57   ` Daniel Thompson
@ 2014-05-23 13:57     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Ian Campbell, Anton Vorontsov, David A. Long, linux-serial,
	Catalin Marinas, kernel-team, devicetree, linaro-kernel,
	Pawel Moll, patches, Kumar Gala, Rob Herring, John Stultz,
	Thomas Gleixner, linux-arm-kernel, Greg Kroah-Hartman

This patch provides the UART with a second interrupt resource that can
be used to route the UARTs interrupt to FIQ. The size of the interrupt
map is doubled and new mappings for the FIQ shadows added (demarked by
setting bit 7 in the final item in the tuple).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: devicetree@vger.kernel.org
---
 arch/arm/boot/dts/vexpress-v2m-rs1.dtsi     |  8 ++++----
 arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts | 10 ++++++++--
 arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts  |  8 +++++++-
 arch/arm/boot/dts/vexpress-v2p-ca5s.dts     | 10 ++++++++--
 4 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
index ac870fb..e86936c 100644
--- a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
@@ -140,7 +140,7 @@
 			v2m_serial0: uart@090000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x090000 0x1000>;
-				interrupts = <5>;
+				interrupts = <5>, <69>;
 				clocks = <&v2m_oscclk2>, <&smbclk>;
 				clock-names = "uartclk", "apb_pclk";
 			};
@@ -148,7 +148,7 @@
 			v2m_serial1: uart@0a0000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x0a0000 0x1000>;
-				interrupts = <6>;
+				interrupts = <6>, <70>;
 				clocks = <&v2m_oscclk2>, <&smbclk>;
 				clock-names = "uartclk", "apb_pclk";
 			};
@@ -156,7 +156,7 @@
 			v2m_serial2: uart@0b0000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x0b0000 0x1000>;
-				interrupts = <7>;
+				interrupts = <7>, <71>;
 				clocks = <&v2m_oscclk2>, <&smbclk>;
 				clock-names = "uartclk", "apb_pclk";
 			};
@@ -164,7 +164,7 @@
 			v2m_serial3: uart@0c0000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x0c0000 0x1000>;
-				interrupts = <8>;
+				interrupts = <8>, <72>;
 				clocks = <&v2m_oscclk2>, <&smbclk>;
 				clock-names = "uartclk", "apb_pclk";
 			};
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
index 9420053..9c489fa 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
@@ -233,7 +233,7 @@
 			 <5 0 0 0x10000000 0x04000000>;
 
 		#interrupt-cells = <1>;
-		interrupt-map-mask = <0 0 63>;
+		interrupt-map-mask = <0 0 127>;
 		interrupt-map = <0 0  0 &gic 0  0 4>,
 				<0 0  1 &gic 0  1 4>,
 				<0 0  2 &gic 0  2 4>,
@@ -276,7 +276,13 @@
 				<0 0 39 &gic 0 39 4>,
 				<0 0 40 &gic 0 40 4>,
 				<0 0 41 &gic 0 41 4>,
-				<0 0 42 &gic 0 42 4>;
+				<0 0 42 &gic 0 42 4>,
+
+				/* FIQ shadow routings */
+				<0 0 69 &gic 0 5 0x84>,
+				<0 0 70 &gic 0 6 0x84>,
+				<0 0 71 &gic 0 7 0x84>,
+				<0 0 72 &gic 0 8 0x84>;
 
 		/include/ "vexpress-v2m-rs1.dtsi"
 	};
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
index 15f98cb..75821d2 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
@@ -390,7 +390,13 @@
 				<0 0 39 &gic 0 39 4>,
 				<0 0 40 &gic 0 40 4>,
 				<0 0 41 &gic 0 41 4>,
-				<0 0 42 &gic 0 42 4>;
+				<0 0 42 &gic 0 42 4>,
+
+				/* FIQ shadow routings */
+				<0 0 69 &gic 0 5 0x84>,
+				<0 0 70 &gic 0 6 0x84>,
+				<0 0 71 &gic 0 7 0x84>,
+				<0 0 72 &gic 0 8 0x84>;
 
 		/include/ "vexpress-v2m-rs1.dtsi"
 	};
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
index c544a55..930e2ef 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
@@ -195,7 +195,7 @@
 			 <5 0 0x10000000 0x04000000>;
 
 		#interrupt-cells = <1>;
-		interrupt-map-mask = <0 0 63>;
+		interrupt-map-mask = <0 0 127>;
 		interrupt-map = <0 0  0 &gic 0  0 4>,
 				<0 0  1 &gic 0  1 4>,
 				<0 0  2 &gic 0  2 4>,
@@ -238,7 +238,13 @@
 				<0 0 39 &gic 0 39 4>,
 				<0 0 40 &gic 0 40 4>,
 				<0 0 41 &gic 0 41 4>,
-				<0 0 42 &gic 0 42 4>;
+				<0 0 42 &gic 0 42 4>,
+
+				/* FIQ shadow routings */
+				<0 0 69 &gic 0 5 0x84>,
+				<0 0 70 &gic 0 6 0x84>,
+				<0 0 71 &gic 0 7 0x84>,
+				<0 0 72 &gic 0 8 0x84>;
 
 		/include/ "vexpress-v2m-rs1.dtsi"
 	};
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 04/10] ARM: vexpress: Extend UART with FIQ support
@ 2014-05-23 13:57     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: linux-arm-kernel

This patch provides the UART with a second interrupt resource that can
be used to route the UARTs interrupt to FIQ. The size of the interrupt
map is doubled and new mappings for the FIQ shadows added (demarked by
setting bit 7 in the final item in the tuple).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: devicetree at vger.kernel.org
---
 arch/arm/boot/dts/vexpress-v2m-rs1.dtsi     |  8 ++++----
 arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts | 10 ++++++++--
 arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts  |  8 +++++++-
 arch/arm/boot/dts/vexpress-v2p-ca5s.dts     | 10 ++++++++--
 4 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
index ac870fb..e86936c 100644
--- a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
@@ -140,7 +140,7 @@
 			v2m_serial0: uart at 090000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x090000 0x1000>;
-				interrupts = <5>;
+				interrupts = <5>, <69>;
 				clocks = <&v2m_oscclk2>, <&smbclk>;
 				clock-names = "uartclk", "apb_pclk";
 			};
@@ -148,7 +148,7 @@
 			v2m_serial1: uart at 0a0000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x0a0000 0x1000>;
-				interrupts = <6>;
+				interrupts = <6>, <70>;
 				clocks = <&v2m_oscclk2>, <&smbclk>;
 				clock-names = "uartclk", "apb_pclk";
 			};
@@ -156,7 +156,7 @@
 			v2m_serial2: uart at 0b0000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x0b0000 0x1000>;
-				interrupts = <7>;
+				interrupts = <7>, <71>;
 				clocks = <&v2m_oscclk2>, <&smbclk>;
 				clock-names = "uartclk", "apb_pclk";
 			};
@@ -164,7 +164,7 @@
 			v2m_serial3: uart at 0c0000 {
 				compatible = "arm,pl011", "arm,primecell";
 				reg = <0x0c0000 0x1000>;
-				interrupts = <8>;
+				interrupts = <8>, <72>;
 				clocks = <&v2m_oscclk2>, <&smbclk>;
 				clock-names = "uartclk", "apb_pclk";
 			};
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
index 9420053..9c489fa 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
@@ -233,7 +233,7 @@
 			 <5 0 0 0x10000000 0x04000000>;
 
 		#interrupt-cells = <1>;
-		interrupt-map-mask = <0 0 63>;
+		interrupt-map-mask = <0 0 127>;
 		interrupt-map = <0 0  0 &gic 0  0 4>,
 				<0 0  1 &gic 0  1 4>,
 				<0 0  2 &gic 0  2 4>,
@@ -276,7 +276,13 @@
 				<0 0 39 &gic 0 39 4>,
 				<0 0 40 &gic 0 40 4>,
 				<0 0 41 &gic 0 41 4>,
-				<0 0 42 &gic 0 42 4>;
+				<0 0 42 &gic 0 42 4>,
+
+				/* FIQ shadow routings */
+				<0 0 69 &gic 0 5 0x84>,
+				<0 0 70 &gic 0 6 0x84>,
+				<0 0 71 &gic 0 7 0x84>,
+				<0 0 72 &gic 0 8 0x84>;
 
 		/include/ "vexpress-v2m-rs1.dtsi"
 	};
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
index 15f98cb..75821d2 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
@@ -390,7 +390,13 @@
 				<0 0 39 &gic 0 39 4>,
 				<0 0 40 &gic 0 40 4>,
 				<0 0 41 &gic 0 41 4>,
-				<0 0 42 &gic 0 42 4>;
+				<0 0 42 &gic 0 42 4>,
+
+				/* FIQ shadow routings */
+				<0 0 69 &gic 0 5 0x84>,
+				<0 0 70 &gic 0 6 0x84>,
+				<0 0 71 &gic 0 7 0x84>,
+				<0 0 72 &gic 0 8 0x84>;
 
 		/include/ "vexpress-v2m-rs1.dtsi"
 	};
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
index c544a55..930e2ef 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
@@ -195,7 +195,7 @@
 			 <5 0 0x10000000 0x04000000>;
 
 		#interrupt-cells = <1>;
-		interrupt-map-mask = <0 0 63>;
+		interrupt-map-mask = <0 0 127>;
 		interrupt-map = <0 0  0 &gic 0  0 4>,
 				<0 0  1 &gic 0  1 4>,
 				<0 0  2 &gic 0  2 4>,
@@ -238,7 +238,13 @@
 				<0 0 39 &gic 0 39 4>,
 				<0 0 40 &gic 0 40 4>,
 				<0 0 41 &gic 0 41 4>,
-				<0 0 42 &gic 0 42 4>;
+				<0 0 42 &gic 0 42 4>,
+
+				/* FIQ shadow routings */
+				<0 0 69 &gic 0 5 0x84>,
+				<0 0 70 &gic 0 6 0x84>,
+				<0 0 71 &gic 0 7 0x84>,
+				<0 0 72 &gic 0 8 0x84>;
 
 		/include/ "vexpress-v2m-rs1.dtsi"
 	};
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 05/10] ARM: STi: STiH41x: Extend UART with FIQ support.
  2014-05-23 13:57   ` Daniel Thompson
@ 2014-05-23 13:57     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij,
	Patrice Chotard, Jiri Slaby, Daniel Thompson, Dirk Behme,
	Russell King, Nicolas Pitre, Ian Campbell, Anton Vorontsov,
	David A. Long, linux-serial, Catalin Marinas, kernel-team,
	devicetree, linaro-kernel, Pawel Moll, patches, Kumar Gala,
	Rob Herring, John Stultz, Thomas Gleixner, linux-arm-kernel

This patch provides the UART with a second interrupt resource that
can be used to route the UARTs interrupt to FIQ (demarked by setting
bit 7 in the third item in the tuple).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: kernel@stlinux.com
Cc: devicetree@vger.kernel.org
---
 arch/arm/boot/dts/stih415.dtsi | 4 ++--
 arch/arm/boot/dts/stih416.dtsi | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/stih415.dtsi b/arch/arm/boot/dts/stih415.dtsi
index d89064c..b2c9df4 100644
--- a/arch/arm/boot/dts/stih415.dtsi
+++ b/arch/arm/boot/dts/stih415.dtsi
@@ -79,7 +79,7 @@
 			compatible	= "st,asc";
 			status 		= "disabled";
 			reg		= <0xfed32000 0x2c>;
-			interrupts	= <0 197 0>;
+			interrupts	= <0 197 0>, <0 197 0x80>;
 			pinctrl-names 	= "default";
 			pinctrl-0 	= <&pinctrl_serial2>;
 			clocks		= <&CLKS_ICN_REG_0>;
@@ -90,7 +90,7 @@
 			compatible	= "st,asc";
 			status 		= "disabled";
 			reg		= <0xfe531000 0x2c>;
-			interrupts	= <0 210 0>;
+			interrupts	= <0 210 0>, <0 197 0x80>;
 			clocks		= <&CLK_SYSIN>;
 			pinctrl-names 	= "default";
 			pinctrl-0	= <&pinctrl_sbc_serial1>;
diff --git a/arch/arm/boot/dts/stih416.dtsi b/arch/arm/boot/dts/stih416.dtsi
index 78746d2..fdf7b43 100644
--- a/arch/arm/boot/dts/stih416.dtsi
+++ b/arch/arm/boot/dts/stih416.dtsi
@@ -88,7 +88,7 @@
 			compatible	= "st,asc";
 			status 		= "disabled";
 			reg		= <0xfed32000 0x2c>;
-			interrupts	= <0 197 0>;
+			interrupts	= <0 197 0>, <0 210 0x80>;
 			clocks          = <&CLK_S_ICN_REG_0>;
 			pinctrl-names 	= "default";
 			pinctrl-0 	= <&pinctrl_serial2 &pinctrl_serial2_oe>;
@@ -99,7 +99,7 @@
 			compatible	= "st,asc";
 			status 		= "disabled";
 			reg		= <0xfe531000 0x2c>;
-			interrupts	= <0 210 0>;
+			interrupts	= <0 210 0>, <0 210 0x80>;
 			pinctrl-names 	= "default";
 			pinctrl-0 	= <&pinctrl_sbc_serial1>;
 			clocks          = <&CLK_SYSIN>;
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 05/10] ARM: STi: STiH41x: Extend UART with FIQ support.
@ 2014-05-23 13:57     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: linux-arm-kernel

This patch provides the UART with a second interrupt resource that
can be used to route the UARTs interrupt to FIQ (demarked by setting
bit 7 in the third item in the tuple).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: kernel at stlinux.com
Cc: devicetree at vger.kernel.org
---
 arch/arm/boot/dts/stih415.dtsi | 4 ++--
 arch/arm/boot/dts/stih416.dtsi | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/stih415.dtsi b/arch/arm/boot/dts/stih415.dtsi
index d89064c..b2c9df4 100644
--- a/arch/arm/boot/dts/stih415.dtsi
+++ b/arch/arm/boot/dts/stih415.dtsi
@@ -79,7 +79,7 @@
 			compatible	= "st,asc";
 			status 		= "disabled";
 			reg		= <0xfed32000 0x2c>;
-			interrupts	= <0 197 0>;
+			interrupts	= <0 197 0>, <0 197 0x80>;
 			pinctrl-names 	= "default";
 			pinctrl-0 	= <&pinctrl_serial2>;
 			clocks		= <&CLKS_ICN_REG_0>;
@@ -90,7 +90,7 @@
 			compatible	= "st,asc";
 			status 		= "disabled";
 			reg		= <0xfe531000 0x2c>;
-			interrupts	= <0 210 0>;
+			interrupts	= <0 210 0>, <0 197 0x80>;
 			clocks		= <&CLK_SYSIN>;
 			pinctrl-names 	= "default";
 			pinctrl-0	= <&pinctrl_sbc_serial1>;
diff --git a/arch/arm/boot/dts/stih416.dtsi b/arch/arm/boot/dts/stih416.dtsi
index 78746d2..fdf7b43 100644
--- a/arch/arm/boot/dts/stih416.dtsi
+++ b/arch/arm/boot/dts/stih416.dtsi
@@ -88,7 +88,7 @@
 			compatible	= "st,asc";
 			status 		= "disabled";
 			reg		= <0xfed32000 0x2c>;
-			interrupts	= <0 197 0>;
+			interrupts	= <0 197 0>, <0 210 0x80>;
 			clocks          = <&CLK_S_ICN_REG_0>;
 			pinctrl-names 	= "default";
 			pinctrl-0 	= <&pinctrl_serial2 &pinctrl_serial2_oe>;
@@ -99,7 +99,7 @@
 			compatible	= "st,asc";
 			status 		= "disabled";
 			reg		= <0xfe531000 0x2c>;
-			interrupts	= <0 210 0>;
+			interrupts	= <0 210 0>, <0 210 0x80>;
 			pinctrl-names 	= "default";
 			pinctrl-0 	= <&pinctrl_sbc_serial1>;
 			clocks          = <&CLK_SYSIN>;
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 06/10] irqchip: vic: Introduce shadow irqs for FIQ
  2014-05-23 13:57   ` Daniel Thompson
@ 2014-05-23 13:57     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Kukjin Kim,
	Jiri Slaby, Daniel Thompson, Dirk Behme, Russell King,
	Nicolas Pitre, Ian Campbell, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Jason Cooper, Pawel Moll, patches, Kumar Gala,
	Rob Herring, John Stultz, linux-samsung-soc, Ben

Currently on the ARM Versatile machine both FIQ and IRQ signals share
the same irq number. The effect of this is that enable_fiq() will
enable an interrupt but will leave it routed to IRQ. This requires a
driver utilizing FIQ to employ machine specific knowledge (i.e. that
the machine has a VIC).

By introducing shadow irqs to describe FIQs the VIC driver is able
to update the routing automatically during enable_fiq()/disable_fiq().

Changes to the vic_init() API allow individual machines to choose where
to fit the shadow irqs in the interrupt map and also to
choose not to have shadows at all.

This patch introduces shadows for mach-versatile whilst mach-ep93xx, mach-netx, mach-s3c64xx and plat-samsung retain unmodified interrupt maps.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: linux-samsung-soc@vger.kernel.org
---
 arch/arm/mach-ep93xx/core.c                 |  6 +-
 arch/arm/mach-netx/generic.c                |  3 +-
 arch/arm/mach-s3c64xx/common.c              |  6 +-
 arch/arm/mach-versatile/core.c              |  9 +--
 arch/arm/mach-versatile/include/mach/irqs.h | 76 ++++++++++++-------------
 arch/arm/plat-samsung/s5p-irq.c             |  3 +-
 drivers/irqchip/irq-vic.c                   | 87 +++++++++++++++++++++++------
 include/linux/irqchip/arm-vic.h             |  8 ++-
 8 files changed, 132 insertions(+), 66 deletions(-)

diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 0e571f1..aa26411 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -185,8 +185,10 @@ void __init ep93xx_timer_init(void)
  *************************************************************************/
 void __init ep93xx_init_irq(void)
 {
-	vic_init(EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK, 0);
-	vic_init(EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK, 0);
+	vic_init(EP93XX_VIC1_BASE, 0, VIC_FIQ_START_NONE,
+		 EP93XX_VIC1_VALID_IRQ_MASK, 0);
+	vic_init(EP93XX_VIC2_BASE, 32, VIC_FIQ_START_NONE,
+		 EP93XX_VIC2_VALID_IRQ_MASK, 0);
 }
 
 
diff --git a/arch/arm/mach-netx/generic.c b/arch/arm/mach-netx/generic.c
index db25b0c..5398dcd 100644
--- a/arch/arm/mach-netx/generic.c
+++ b/arch/arm/mach-netx/generic.c
@@ -169,7 +169,8 @@ void __init netx_init_irq(void)
 {
 	int irq;
 
-	vic_init(io_p2v(NETX_PA_VIC), NETX_IRQ_VIC_START, ~0, 0);
+	vic_init(io_p2v(NETX_PA_VIC), NETX_IRQ_VIC_START, VIC_FIQ_START_NONE,
+		 ~0, 0);
 
 	for (irq = NETX_IRQ_HIF_CHAINED(0); irq <= NETX_IRQ_HIF_LAST; irq++) {
 		irq_set_chip_and_handler(irq, &netx_hif_chip,
diff --git a/arch/arm/mach-s3c64xx/common.c b/arch/arm/mach-s3c64xx/common.c
index 5c45aae..b98dd48 100644
--- a/arch/arm/mach-s3c64xx/common.c
+++ b/arch/arm/mach-s3c64xx/common.c
@@ -242,8 +242,10 @@ void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid)
 	printk(KERN_DEBUG "%s: initialising interrupts\n", __func__);
 
 	/* initialise the pair of VICs */
-	vic_init(VA_VIC0, IRQ_VIC0_BASE, vic0_valid, IRQ_VIC0_RESUME);
-	vic_init(VA_VIC1, IRQ_VIC1_BASE, vic1_valid, IRQ_VIC1_RESUME);
+	vic_init(VA_VIC0, IRQ_VIC0_BASE, VIC_FIQ_START_NONE, vic0_valid,
+		 IRQ_VIC0_RESUME);
+	vic_init(VA_VIC1, IRQ_VIC1_BASE, VIC_FIQ_START_NONE, vic1_valid,
+		 IRQ_VIC1_RESUME);
 }
 
 #define eint_offset(irq)	((irq) - IRQ_EINT(0))
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index f2c89fb..3444ca8 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -108,7 +108,8 @@ void __init versatile_init_irq(void)
 
 	np = of_find_matching_node_by_address(NULL, vic_of_match,
 					      VERSATILE_VIC_BASE);
-	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np);
+	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START,
+		   np ? -1 : FIQ_VIC_START, ~0, 0, np);
 
 	writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
 
@@ -614,9 +615,9 @@ static struct pl022_ssp_controller ssp0_plat_data = {
  * These devices are connected via the DMA APB bridge
  */
 #define SCI_IRQ		{ IRQ_SCIINT }
-#define UART0_IRQ	{ IRQ_UARTINT0 }
-#define UART1_IRQ	{ IRQ_UARTINT1 }
-#define UART2_IRQ	{ IRQ_UARTINT2 }
+#define UART0_IRQ	{ IRQ_UARTINT0, FIQ_UARTINT0 }
+#define UART1_IRQ	{ IRQ_UARTINT1, FIQ_UARTINT1 }
+#define UART2_IRQ	{ IRQ_UARTINT2, FIQ_UARTINT2 }
 #define SSP_IRQ		{ IRQ_SSPINT }
 
 /* FPGA Primecells */
diff --git a/arch/arm/mach-versatile/include/mach/irqs.h b/arch/arm/mach-versatile/include/mach/irqs.h
index 0fd771c..da3f919 100644
--- a/arch/arm/mach-versatile/include/mach/irqs.h
+++ b/arch/arm/mach-versatile/include/mach/irqs.h
@@ -60,43 +60,6 @@
 #define IRQ_VICSOURCE31		(IRQ_VIC_START + INT_VICSOURCE31)
 #define IRQ_VIC_END		(IRQ_VIC_START + 31)
 
-/* 
- *  FIQ interrupts definitions are the same as the INT definitions.
- */
-#define FIQ_WDOGINT		INT_WDOGINT
-#define FIQ_SOFTINT		INT_SOFTINT
-#define FIQ_COMMRx		INT_COMMRx
-#define FIQ_COMMTx		INT_COMMTx
-#define FIQ_TIMERINT0_1		INT_TIMERINT0_1
-#define FIQ_TIMERINT2_3		INT_TIMERINT2_3
-#define FIQ_GPIOINT0		INT_GPIOINT0
-#define FIQ_GPIOINT1		INT_GPIOINT1
-#define FIQ_GPIOINT2		INT_GPIOINT2
-#define FIQ_GPIOINT3		INT_GPIOINT3
-#define FIQ_RTCINT		INT_RTCINT
-#define FIQ_SSPINT		INT_SSPINT
-#define FIQ_UARTINT0		INT_UARTINT0
-#define FIQ_UARTINT1		INT_UARTINT1
-#define FIQ_UARTINT2		INT_UARTINT2
-#define FIQ_SCIINT		INT_SCIINT
-#define FIQ_CLCDINT		INT_CLCDINT
-#define FIQ_DMAINT		INT_DMAINT
-#define FIQ_PWRFAILINT 		INT_PWRFAILINT
-#define FIQ_MBXINT		INT_MBXINT
-#define FIQ_GNDINT		INT_GNDINT
-#define FIQ_VICSOURCE21		INT_VICSOURCE21
-#define FIQ_VICSOURCE22		INT_VICSOURCE22
-#define FIQ_VICSOURCE23		INT_VICSOURCE23
-#define FIQ_VICSOURCE24		INT_VICSOURCE24
-#define FIQ_VICSOURCE25		INT_VICSOURCE25
-#define FIQ_VICSOURCE26		INT_VICSOURCE26
-#define FIQ_VICSOURCE27		INT_VICSOURCE27
-#define FIQ_VICSOURCE28		INT_VICSOURCE28
-#define FIQ_VICSOURCE29		INT_VICSOURCE29
-#define FIQ_VICSOURCE30		INT_VICSOURCE30
-#define FIQ_VICSOURCE31		INT_VICSOURCE31
-
-
 /*
  * Secondary interrupt controller
  */
@@ -131,4 +94,41 @@
 #define IRQ_GPIO3_START		(IRQ_GPIO2_END + 1)
 #define IRQ_GPIO3_END		(IRQ_GPIO3_START + 31)
 
-#define NR_IRQS			(IRQ_GPIO3_END + 1)
+/*
+ *  FIQ interrupts definitions shadow the VIC INT definitions.
+ */
+#define FIQ_VIC_START		(IRQ_GPIO3_END + 1)
+#define FIQ_WDOGINT		(INT_WDOGINT + FIQ_VIC_START)
+#define FIQ_SOFTINT		(INT_SOFTINT + FIQ_VIC_START)
+#define FIQ_COMMRx		(INT_COMMRx + FIQ_VIC_START)
+#define FIQ_COMMTx		(INT_COMMTx + FIQ_VIC_START)
+#define FIQ_TIMERINT0_1		(INT_TIMERINT0_1 + FIQ_VIC_START)
+#define FIQ_TIMERINT2_3		(INT_TIMERINT2_3 + FIQ_VIC_START)
+#define FIQ_GPIOINT0		(INT_GPIOINT0 + FIQ_VIC_START)
+#define FIQ_GPIOINT1		(INT_GPIOINT1 + FIQ_VIC_START)
+#define FIQ_GPIOINT2		(INT_GPIOINT2 + FIQ_VIC_START)
+#define FIQ_GPIOINT3		(INT_GPIOINT3 + FIQ_VIC_START)
+#define FIQ_RTCINT		(INT_RTCINT + FIQ_VIC_START)
+#define FIQ_SSPINT		(INT_SSPINT + FIQ_VIC_START)
+#define FIQ_UARTINT0		(INT_UARTINT0 + FIQ_VIC_START)
+#define FIQ_UARTINT1		(INT_UARTINT1 + FIQ_VIC_START)
+#define FIQ_UARTINT2		(INT_UARTINT2 + FIQ_VIC_START)
+#define FIQ_SCIINT		(INT_SCIINT + FIQ_VIC_START)
+#define FIQ_CLCDINT		(INT_CLCDINT + FIQ_VIC_START)
+#define FIQ_DMAINT		(INT_DMAINT + FIQ_VIC_START)
+#define FIQ_PWRFAILINT		(INT_PWRFAILINT + FIQ_VIC_START)
+#define FIQ_MBXINT		(INT_MBXINT + FIQ_VIC_START)
+#define FIQ_GNDINT		(INT_GNDINT + FIQ_VIC_START)
+#define FIQ_VICSOURCE21		(INT_VICSOURCE21 + FIQ_VIC_START)
+#define FIQ_VICSOURCE22		(INT_VICSOURCE22 + FIQ_VIC_START)
+#define FIQ_VICSOURCE23		(INT_VICSOURCE23 + FIQ_VIC_START)
+#define FIQ_VICSOURCE24		(INT_VICSOURCE24 + FIQ_VIC_START)
+#define FIQ_VICSOURCE25		(INT_VICSOURCE25 + FIQ_VIC_START)
+#define FIQ_VICSOURCE26		(INT_VICSOURCE26 + FIQ_VIC_START)
+#define FIQ_VICSOURCE27		(INT_VICSOURCE27 + FIQ_VIC_START)
+#define FIQ_VICSOURCE28		(INT_VICSOURCE28 + FIQ_VIC_START)
+#define FIQ_VICSOURCE29		(INT_VICSOURCE29 + FIQ_VIC_START)
+#define FIQ_VICSOURCE30		(INT_VICSOURCE30 + FIQ_VIC_START)
+#define FIQ_VICSOURCE31		(INT_VICSOURCE31 + FIQ_VIC_START)
+
+#define NR_IRQS			(FIQ_VICSOURCE31 + 1)
diff --git a/arch/arm/plat-samsung/s5p-irq.c b/arch/arm/plat-samsung/s5p-irq.c
index ddfaca9..ddb1138 100644
--- a/arch/arm/plat-samsung/s5p-irq.c
+++ b/arch/arm/plat-samsung/s5p-irq.c
@@ -26,6 +26,7 @@ void __init s5p_init_irq(u32 *vic, u32 num_vic)
 
 	/* initialize the VICs */
 	for (irq = 0; irq < num_vic; irq++)
-		vic_init(VA_VIC(irq), VIC_BASE(irq), vic[irq], 0);
+		vic_init(VA_VIC(irq), VIC_BASE(irq), VIC_FIQ_START_NONE,
+			 vic[irq], 0);
 #endif
 }
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287..82bce53 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -56,6 +56,8 @@
 
 #define VIC_PL192_VECT_ADDR		0xF00
 
+#define VIC_FIQ_SHADOW_OFFSET		32
+
 /**
  * struct vic_device - VIC PM device
  * @parent_irq: The parent IRQ number of the VIC if cascaded, or 0.
@@ -81,8 +83,11 @@ struct vic_device {
 	u32		soft_int;
 	u32		protect;
 	struct irq_domain *domain;
+	struct irq_domain *fiq_domain;
 };
 
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
 /* we cannot allocate memory when VICs are initially registered */
 static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
 
@@ -197,6 +202,9 @@ static int vic_irqdomain_map(struct irq_domain *d, unsigned int irq,
 {
 	struct vic_device *v = d->host_data;
 
+	if (hwirq > VIC_FIQ_SHADOW_OFFSET)
+		hwirq -= VIC_FIQ_SHADOW_OFFSET;
+
 	/* Skip invalid IRQs, only register handlers for the real ones */
 	if (!(v->valid_sources & (1 << hwirq)))
 		return -EPERM;
@@ -277,7 +285,7 @@ static struct irq_domain_ops vic_irqdomain_ops = {
  * This also configures the IRQ domain for the VIC.
  */
 static void __init vic_register(void __iomem *base, unsigned int parent_irq,
-				unsigned int irq,
+				unsigned int irq, int fiq,
 				u32 valid_sources, u32 resume_sources,
 				struct device_node *node)
 {
@@ -307,6 +315,19 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 	for (i = 0; i < fls(valid_sources); i++)
 		if (valid_sources & (1 << i))
 			irq_create_mapping(v->domain, i);
+
+	/* create FIQ shadow mapping for each IRQ */
+	if (fiq >= 0) {
+		v->fiq_domain = irq_domain_add_legacy(
+				node, fls(valid_sources), fiq,
+				VIC_FIQ_SHADOW_OFFSET, &vic_irqdomain_ops, v);
+		/* create an IRQ mapping for each valid IRQ */
+		for (i = 0; i < fls(valid_sources); i++)
+			if (valid_sources & (1 << i))
+				irq_create_mapping(v->fiq_domain,
+						   i + VIC_FIQ_SHADOW_OFFSET);
+	}
+
 	/* If no base IRQ was passed, figure out our allocated base */
 	if (irq)
 		v->irq = irq;
@@ -314,10 +335,36 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 		v->irq = irq_find_mapping(v->domain, 0);
 }
 
+static inline bool vic_is_fiq(struct irq_data *d)
+{
+	return d->hwirq >= VIC_FIQ_SHADOW_OFFSET;
+}
+
+static inline unsigned int vic_irq(struct irq_data *d)
+{
+	return d->hwirq & (VIC_FIQ_SHADOW_OFFSET-1);
+}
+
+static void vic_set_fiq(struct irq_data *d, bool enable)
+{
+	void __iomem *base = irq_data_get_irq_chip_data(d);
+	unsigned int irq = vic_irq(d);
+	u32 val;
+
+	raw_spin_lock(&irq_controller_lock);
+	val = readl(base + VIC_INT_SELECT);
+	if (enable)
+		val |= 1 << irq;
+	else
+		val &= ~(1 << irq);
+	writel(val, base + VIC_INT_SELECT);
+	raw_spin_unlock(&irq_controller_lock);
+}
+
 static void vic_ack_irq(struct irq_data *d)
 {
 	void __iomem *base = irq_data_get_irq_chip_data(d);
-	unsigned int irq = d->hwirq;
+	unsigned int irq = vic_irq(d);
 	writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
 	/* moreover, clear the soft-triggered, in case it was the reason */
 	writel(1 << irq, base + VIC_INT_SOFT_CLEAR);
@@ -326,17 +373,22 @@ static void vic_ack_irq(struct irq_data *d)
 static void vic_mask_irq(struct irq_data *d)
 {
 	void __iomem *base = irq_data_get_irq_chip_data(d);
-	unsigned int irq = d->hwirq;
+	unsigned int irq = vic_irq(d);
+	if (vic_is_fiq(d))
+		vic_set_fiq(d, false);
 	writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
 }
 
 static void vic_unmask_irq(struct irq_data *d)
 {
 	void __iomem *base = irq_data_get_irq_chip_data(d);
-	unsigned int irq = d->hwirq;
+	unsigned int irq = vic_irq(d);
+	if (vic_is_fiq(d))
+		vic_set_fiq(d, true);
 	writel(1 << irq, base + VIC_INT_ENABLE);
 }
 
+
 #if defined(CONFIG_PM)
 static struct vic_device *vic_from_irq(unsigned int irq)
 {
@@ -355,7 +407,7 @@ static struct vic_device *vic_from_irq(unsigned int irq)
 static int vic_set_wake(struct irq_data *d, unsigned int on)
 {
 	struct vic_device *v = vic_from_irq(d->irq);
-	unsigned int off = d->hwirq;
+	unsigned int off = vic_irq(d);
 	u32 bit = 1 << off;
 
 	if (!v)
@@ -413,7 +465,8 @@ static void __init vic_clear_interrupts(void __iomem *base)
  *  and 020 within the page. We call this "second block".
  */
 static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
-			       u32 vic_sources, struct device_node *node)
+			       int fiq_start, u32 vic_sources,
+			       struct device_node *node)
 {
 	unsigned int i;
 	int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
@@ -439,12 +492,12 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
 		writel(32, base + VIC_PL190_DEF_VECT_ADDR);
 	}
 
-	vic_register(base, 0, irq_start, vic_sources, 0, node);
+	vic_register(base, 0, irq_start, fiq_start, vic_sources, 0, node);
 }
 
 void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
-			      u32 vic_sources, u32 resume_sources,
-			      struct device_node *node)
+		       int fiq_start, u32 vic_sources, u32 resume_sources,
+		       struct device_node *node)
 {
 	unsigned int i;
 	u32 cellid = 0;
@@ -462,7 +515,7 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	switch(vendor) {
 	case AMBA_VENDOR_ST:
-		vic_init_st(base, irq_start, vic_sources, node);
+		vic_init_st(base, irq_start, fiq_start, vic_sources, node);
 		return;
 	default:
 		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
@@ -479,7 +532,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	vic_init2(base);
 
-	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);
+	vic_register(base, parent_irq, irq_start, fiq_start, vic_sources,
+		     resume_sources, node);
 }
 
 /**
@@ -490,9 +544,9 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
  * @resume_sources: bitmask of interrupt sources to allow for resume
  */
 void __init vic_init(void __iomem *base, unsigned int irq_start,
-		     u32 vic_sources, u32 resume_sources)
+		     int fiq_start, u32 vic_sources, u32 resume_sources)
 {
-	__vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL);
+	__vic_init(base, 0, irq_start, -1, vic_sources, resume_sources, NULL);
 }
 
 /**
@@ -511,7 +565,7 @@ int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 	struct vic_device *v;
 
 	v = &vic_devices[vic_id];
-	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL);
+	__vic_init(base, parent_irq, 0, -1, vic_sources, resume_sources, NULL);
 	/* Return out acquired base */
 	return v->irq;
 }
@@ -535,9 +589,10 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
 	of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask);
 
 	/*
-	 * Passing 0 as first IRQ makes the simple domain allocate descriptors
+	 * Passing 0 as first IRQ (and first FIQ) makes the domain allocate
+	 * descriptors.
 	 */
-	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
+	__vic_init(regs, 0, 0, -1, interrupt_mask, wakeup_mask, node);
 
 	return 0;
 }
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index ba46c79..fae480d 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -26,12 +26,16 @@
 #define VIC_INT_ENABLE			0x10	/* 1 = enable, 0 = disable */
 #define VIC_INT_ENABLE_CLEAR		0x14
 
+#define VIC_FIQ_START_NONE -1
+
 struct device_node;
 struct pt_regs;
 
 void __vic_init(void __iomem *base, int parent_irq, int irq_start,
-		u32 vic_sources, u32 resume_sources, struct device_node *node);
-void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
+		int fiq_start, u32 vic_sources, u32 resume_sources,
+		struct device_node *node);
+void vic_init(void __iomem *base, unsigned int irq_start, int fiq_start,
+	      u32 vic_sources, u32 resume_sources);
 int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 		      u32 vic_sources, u32 resume_sources);
 
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 06/10] irqchip: vic: Introduce shadow irqs for FIQ
@ 2014-05-23 13:57     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: linux-arm-kernel

Currently on the ARM Versatile machine both FIQ and IRQ signals share
the same irq number. The effect of this is that enable_fiq() will
enable an interrupt but will leave it routed to IRQ. This requires a
driver utilizing FIQ to employ machine specific knowledge (i.e. that
the machine has a VIC).

By introducing shadow irqs to describe FIQs the VIC driver is able
to update the routing automatically during enable_fiq()/disable_fiq().

Changes to the vic_init() API allow individual machines to choose where
to fit the shadow irqs in the interrupt map and also to
choose not to have shadows at all.

This patch introduces shadows for mach-versatile whilst mach-ep93xx, mach-netx, mach-s3c64xx and plat-samsung retain unmodified interrupt maps.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: linux-samsung-soc at vger.kernel.org
---
 arch/arm/mach-ep93xx/core.c                 |  6 +-
 arch/arm/mach-netx/generic.c                |  3 +-
 arch/arm/mach-s3c64xx/common.c              |  6 +-
 arch/arm/mach-versatile/core.c              |  9 +--
 arch/arm/mach-versatile/include/mach/irqs.h | 76 ++++++++++++-------------
 arch/arm/plat-samsung/s5p-irq.c             |  3 +-
 drivers/irqchip/irq-vic.c                   | 87 +++++++++++++++++++++++------
 include/linux/irqchip/arm-vic.h             |  8 ++-
 8 files changed, 132 insertions(+), 66 deletions(-)

diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 0e571f1..aa26411 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -185,8 +185,10 @@ void __init ep93xx_timer_init(void)
  *************************************************************************/
 void __init ep93xx_init_irq(void)
 {
-	vic_init(EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK, 0);
-	vic_init(EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK, 0);
+	vic_init(EP93XX_VIC1_BASE, 0, VIC_FIQ_START_NONE,
+		 EP93XX_VIC1_VALID_IRQ_MASK, 0);
+	vic_init(EP93XX_VIC2_BASE, 32, VIC_FIQ_START_NONE,
+		 EP93XX_VIC2_VALID_IRQ_MASK, 0);
 }
 
 
diff --git a/arch/arm/mach-netx/generic.c b/arch/arm/mach-netx/generic.c
index db25b0c..5398dcd 100644
--- a/arch/arm/mach-netx/generic.c
+++ b/arch/arm/mach-netx/generic.c
@@ -169,7 +169,8 @@ void __init netx_init_irq(void)
 {
 	int irq;
 
-	vic_init(io_p2v(NETX_PA_VIC), NETX_IRQ_VIC_START, ~0, 0);
+	vic_init(io_p2v(NETX_PA_VIC), NETX_IRQ_VIC_START, VIC_FIQ_START_NONE,
+		 ~0, 0);
 
 	for (irq = NETX_IRQ_HIF_CHAINED(0); irq <= NETX_IRQ_HIF_LAST; irq++) {
 		irq_set_chip_and_handler(irq, &netx_hif_chip,
diff --git a/arch/arm/mach-s3c64xx/common.c b/arch/arm/mach-s3c64xx/common.c
index 5c45aae..b98dd48 100644
--- a/arch/arm/mach-s3c64xx/common.c
+++ b/arch/arm/mach-s3c64xx/common.c
@@ -242,8 +242,10 @@ void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid)
 	printk(KERN_DEBUG "%s: initialising interrupts\n", __func__);
 
 	/* initialise the pair of VICs */
-	vic_init(VA_VIC0, IRQ_VIC0_BASE, vic0_valid, IRQ_VIC0_RESUME);
-	vic_init(VA_VIC1, IRQ_VIC1_BASE, vic1_valid, IRQ_VIC1_RESUME);
+	vic_init(VA_VIC0, IRQ_VIC0_BASE, VIC_FIQ_START_NONE, vic0_valid,
+		 IRQ_VIC0_RESUME);
+	vic_init(VA_VIC1, IRQ_VIC1_BASE, VIC_FIQ_START_NONE, vic1_valid,
+		 IRQ_VIC1_RESUME);
 }
 
 #define eint_offset(irq)	((irq) - IRQ_EINT(0))
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index f2c89fb..3444ca8 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -108,7 +108,8 @@ void __init versatile_init_irq(void)
 
 	np = of_find_matching_node_by_address(NULL, vic_of_match,
 					      VERSATILE_VIC_BASE);
-	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np);
+	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START,
+		   np ? -1 : FIQ_VIC_START, ~0, 0, np);
 
 	writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
 
@@ -614,9 +615,9 @@ static struct pl022_ssp_controller ssp0_plat_data = {
  * These devices are connected via the DMA APB bridge
  */
 #define SCI_IRQ		{ IRQ_SCIINT }
-#define UART0_IRQ	{ IRQ_UARTINT0 }
-#define UART1_IRQ	{ IRQ_UARTINT1 }
-#define UART2_IRQ	{ IRQ_UARTINT2 }
+#define UART0_IRQ	{ IRQ_UARTINT0, FIQ_UARTINT0 }
+#define UART1_IRQ	{ IRQ_UARTINT1, FIQ_UARTINT1 }
+#define UART2_IRQ	{ IRQ_UARTINT2, FIQ_UARTINT2 }
 #define SSP_IRQ		{ IRQ_SSPINT }
 
 /* FPGA Primecells */
diff --git a/arch/arm/mach-versatile/include/mach/irqs.h b/arch/arm/mach-versatile/include/mach/irqs.h
index 0fd771c..da3f919 100644
--- a/arch/arm/mach-versatile/include/mach/irqs.h
+++ b/arch/arm/mach-versatile/include/mach/irqs.h
@@ -60,43 +60,6 @@
 #define IRQ_VICSOURCE31		(IRQ_VIC_START + INT_VICSOURCE31)
 #define IRQ_VIC_END		(IRQ_VIC_START + 31)
 
-/* 
- *  FIQ interrupts definitions are the same as the INT definitions.
- */
-#define FIQ_WDOGINT		INT_WDOGINT
-#define FIQ_SOFTINT		INT_SOFTINT
-#define FIQ_COMMRx		INT_COMMRx
-#define FIQ_COMMTx		INT_COMMTx
-#define FIQ_TIMERINT0_1		INT_TIMERINT0_1
-#define FIQ_TIMERINT2_3		INT_TIMERINT2_3
-#define FIQ_GPIOINT0		INT_GPIOINT0
-#define FIQ_GPIOINT1		INT_GPIOINT1
-#define FIQ_GPIOINT2		INT_GPIOINT2
-#define FIQ_GPIOINT3		INT_GPIOINT3
-#define FIQ_RTCINT		INT_RTCINT
-#define FIQ_SSPINT		INT_SSPINT
-#define FIQ_UARTINT0		INT_UARTINT0
-#define FIQ_UARTINT1		INT_UARTINT1
-#define FIQ_UARTINT2		INT_UARTINT2
-#define FIQ_SCIINT		INT_SCIINT
-#define FIQ_CLCDINT		INT_CLCDINT
-#define FIQ_DMAINT		INT_DMAINT
-#define FIQ_PWRFAILINT 		INT_PWRFAILINT
-#define FIQ_MBXINT		INT_MBXINT
-#define FIQ_GNDINT		INT_GNDINT
-#define FIQ_VICSOURCE21		INT_VICSOURCE21
-#define FIQ_VICSOURCE22		INT_VICSOURCE22
-#define FIQ_VICSOURCE23		INT_VICSOURCE23
-#define FIQ_VICSOURCE24		INT_VICSOURCE24
-#define FIQ_VICSOURCE25		INT_VICSOURCE25
-#define FIQ_VICSOURCE26		INT_VICSOURCE26
-#define FIQ_VICSOURCE27		INT_VICSOURCE27
-#define FIQ_VICSOURCE28		INT_VICSOURCE28
-#define FIQ_VICSOURCE29		INT_VICSOURCE29
-#define FIQ_VICSOURCE30		INT_VICSOURCE30
-#define FIQ_VICSOURCE31		INT_VICSOURCE31
-
-
 /*
  * Secondary interrupt controller
  */
@@ -131,4 +94,41 @@
 #define IRQ_GPIO3_START		(IRQ_GPIO2_END + 1)
 #define IRQ_GPIO3_END		(IRQ_GPIO3_START + 31)
 
-#define NR_IRQS			(IRQ_GPIO3_END + 1)
+/*
+ *  FIQ interrupts definitions shadow the VIC INT definitions.
+ */
+#define FIQ_VIC_START		(IRQ_GPIO3_END + 1)
+#define FIQ_WDOGINT		(INT_WDOGINT + FIQ_VIC_START)
+#define FIQ_SOFTINT		(INT_SOFTINT + FIQ_VIC_START)
+#define FIQ_COMMRx		(INT_COMMRx + FIQ_VIC_START)
+#define FIQ_COMMTx		(INT_COMMTx + FIQ_VIC_START)
+#define FIQ_TIMERINT0_1		(INT_TIMERINT0_1 + FIQ_VIC_START)
+#define FIQ_TIMERINT2_3		(INT_TIMERINT2_3 + FIQ_VIC_START)
+#define FIQ_GPIOINT0		(INT_GPIOINT0 + FIQ_VIC_START)
+#define FIQ_GPIOINT1		(INT_GPIOINT1 + FIQ_VIC_START)
+#define FIQ_GPIOINT2		(INT_GPIOINT2 + FIQ_VIC_START)
+#define FIQ_GPIOINT3		(INT_GPIOINT3 + FIQ_VIC_START)
+#define FIQ_RTCINT		(INT_RTCINT + FIQ_VIC_START)
+#define FIQ_SSPINT		(INT_SSPINT + FIQ_VIC_START)
+#define FIQ_UARTINT0		(INT_UARTINT0 + FIQ_VIC_START)
+#define FIQ_UARTINT1		(INT_UARTINT1 + FIQ_VIC_START)
+#define FIQ_UARTINT2		(INT_UARTINT2 + FIQ_VIC_START)
+#define FIQ_SCIINT		(INT_SCIINT + FIQ_VIC_START)
+#define FIQ_CLCDINT		(INT_CLCDINT + FIQ_VIC_START)
+#define FIQ_DMAINT		(INT_DMAINT + FIQ_VIC_START)
+#define FIQ_PWRFAILINT		(INT_PWRFAILINT + FIQ_VIC_START)
+#define FIQ_MBXINT		(INT_MBXINT + FIQ_VIC_START)
+#define FIQ_GNDINT		(INT_GNDINT + FIQ_VIC_START)
+#define FIQ_VICSOURCE21		(INT_VICSOURCE21 + FIQ_VIC_START)
+#define FIQ_VICSOURCE22		(INT_VICSOURCE22 + FIQ_VIC_START)
+#define FIQ_VICSOURCE23		(INT_VICSOURCE23 + FIQ_VIC_START)
+#define FIQ_VICSOURCE24		(INT_VICSOURCE24 + FIQ_VIC_START)
+#define FIQ_VICSOURCE25		(INT_VICSOURCE25 + FIQ_VIC_START)
+#define FIQ_VICSOURCE26		(INT_VICSOURCE26 + FIQ_VIC_START)
+#define FIQ_VICSOURCE27		(INT_VICSOURCE27 + FIQ_VIC_START)
+#define FIQ_VICSOURCE28		(INT_VICSOURCE28 + FIQ_VIC_START)
+#define FIQ_VICSOURCE29		(INT_VICSOURCE29 + FIQ_VIC_START)
+#define FIQ_VICSOURCE30		(INT_VICSOURCE30 + FIQ_VIC_START)
+#define FIQ_VICSOURCE31		(INT_VICSOURCE31 + FIQ_VIC_START)
+
+#define NR_IRQS			(FIQ_VICSOURCE31 + 1)
diff --git a/arch/arm/plat-samsung/s5p-irq.c b/arch/arm/plat-samsung/s5p-irq.c
index ddfaca9..ddb1138 100644
--- a/arch/arm/plat-samsung/s5p-irq.c
+++ b/arch/arm/plat-samsung/s5p-irq.c
@@ -26,6 +26,7 @@ void __init s5p_init_irq(u32 *vic, u32 num_vic)
 
 	/* initialize the VICs */
 	for (irq = 0; irq < num_vic; irq++)
-		vic_init(VA_VIC(irq), VIC_BASE(irq), vic[irq], 0);
+		vic_init(VA_VIC(irq), VIC_BASE(irq), VIC_FIQ_START_NONE,
+			 vic[irq], 0);
 #endif
 }
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287..82bce53 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -56,6 +56,8 @@
 
 #define VIC_PL192_VECT_ADDR		0xF00
 
+#define VIC_FIQ_SHADOW_OFFSET		32
+
 /**
  * struct vic_device - VIC PM device
  * @parent_irq: The parent IRQ number of the VIC if cascaded, or 0.
@@ -81,8 +83,11 @@ struct vic_device {
 	u32		soft_int;
 	u32		protect;
 	struct irq_domain *domain;
+	struct irq_domain *fiq_domain;
 };
 
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
 /* we cannot allocate memory when VICs are initially registered */
 static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
 
@@ -197,6 +202,9 @@ static int vic_irqdomain_map(struct irq_domain *d, unsigned int irq,
 {
 	struct vic_device *v = d->host_data;
 
+	if (hwirq > VIC_FIQ_SHADOW_OFFSET)
+		hwirq -= VIC_FIQ_SHADOW_OFFSET;
+
 	/* Skip invalid IRQs, only register handlers for the real ones */
 	if (!(v->valid_sources & (1 << hwirq)))
 		return -EPERM;
@@ -277,7 +285,7 @@ static struct irq_domain_ops vic_irqdomain_ops = {
  * This also configures the IRQ domain for the VIC.
  */
 static void __init vic_register(void __iomem *base, unsigned int parent_irq,
-				unsigned int irq,
+				unsigned int irq, int fiq,
 				u32 valid_sources, u32 resume_sources,
 				struct device_node *node)
 {
@@ -307,6 +315,19 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 	for (i = 0; i < fls(valid_sources); i++)
 		if (valid_sources & (1 << i))
 			irq_create_mapping(v->domain, i);
+
+	/* create FIQ shadow mapping for each IRQ */
+	if (fiq >= 0) {
+		v->fiq_domain = irq_domain_add_legacy(
+				node, fls(valid_sources), fiq,
+				VIC_FIQ_SHADOW_OFFSET, &vic_irqdomain_ops, v);
+		/* create an IRQ mapping for each valid IRQ */
+		for (i = 0; i < fls(valid_sources); i++)
+			if (valid_sources & (1 << i))
+				irq_create_mapping(v->fiq_domain,
+						   i + VIC_FIQ_SHADOW_OFFSET);
+	}
+
 	/* If no base IRQ was passed, figure out our allocated base */
 	if (irq)
 		v->irq = irq;
@@ -314,10 +335,36 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 		v->irq = irq_find_mapping(v->domain, 0);
 }
 
+static inline bool vic_is_fiq(struct irq_data *d)
+{
+	return d->hwirq >= VIC_FIQ_SHADOW_OFFSET;
+}
+
+static inline unsigned int vic_irq(struct irq_data *d)
+{
+	return d->hwirq & (VIC_FIQ_SHADOW_OFFSET-1);
+}
+
+static void vic_set_fiq(struct irq_data *d, bool enable)
+{
+	void __iomem *base = irq_data_get_irq_chip_data(d);
+	unsigned int irq = vic_irq(d);
+	u32 val;
+
+	raw_spin_lock(&irq_controller_lock);
+	val = readl(base + VIC_INT_SELECT);
+	if (enable)
+		val |= 1 << irq;
+	else
+		val &= ~(1 << irq);
+	writel(val, base + VIC_INT_SELECT);
+	raw_spin_unlock(&irq_controller_lock);
+}
+
 static void vic_ack_irq(struct irq_data *d)
 {
 	void __iomem *base = irq_data_get_irq_chip_data(d);
-	unsigned int irq = d->hwirq;
+	unsigned int irq = vic_irq(d);
 	writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
 	/* moreover, clear the soft-triggered, in case it was the reason */
 	writel(1 << irq, base + VIC_INT_SOFT_CLEAR);
@@ -326,17 +373,22 @@ static void vic_ack_irq(struct irq_data *d)
 static void vic_mask_irq(struct irq_data *d)
 {
 	void __iomem *base = irq_data_get_irq_chip_data(d);
-	unsigned int irq = d->hwirq;
+	unsigned int irq = vic_irq(d);
+	if (vic_is_fiq(d))
+		vic_set_fiq(d, false);
 	writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
 }
 
 static void vic_unmask_irq(struct irq_data *d)
 {
 	void __iomem *base = irq_data_get_irq_chip_data(d);
-	unsigned int irq = d->hwirq;
+	unsigned int irq = vic_irq(d);
+	if (vic_is_fiq(d))
+		vic_set_fiq(d, true);
 	writel(1 << irq, base + VIC_INT_ENABLE);
 }
 
+
 #if defined(CONFIG_PM)
 static struct vic_device *vic_from_irq(unsigned int irq)
 {
@@ -355,7 +407,7 @@ static struct vic_device *vic_from_irq(unsigned int irq)
 static int vic_set_wake(struct irq_data *d, unsigned int on)
 {
 	struct vic_device *v = vic_from_irq(d->irq);
-	unsigned int off = d->hwirq;
+	unsigned int off = vic_irq(d);
 	u32 bit = 1 << off;
 
 	if (!v)
@@ -413,7 +465,8 @@ static void __init vic_clear_interrupts(void __iomem *base)
  *  and 020 within the page. We call this "second block".
  */
 static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
-			       u32 vic_sources, struct device_node *node)
+			       int fiq_start, u32 vic_sources,
+			       struct device_node *node)
 {
 	unsigned int i;
 	int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
@@ -439,12 +492,12 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
 		writel(32, base + VIC_PL190_DEF_VECT_ADDR);
 	}
 
-	vic_register(base, 0, irq_start, vic_sources, 0, node);
+	vic_register(base, 0, irq_start, fiq_start, vic_sources, 0, node);
 }
 
 void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
-			      u32 vic_sources, u32 resume_sources,
-			      struct device_node *node)
+		       int fiq_start, u32 vic_sources, u32 resume_sources,
+		       struct device_node *node)
 {
 	unsigned int i;
 	u32 cellid = 0;
@@ -462,7 +515,7 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	switch(vendor) {
 	case AMBA_VENDOR_ST:
-		vic_init_st(base, irq_start, vic_sources, node);
+		vic_init_st(base, irq_start, fiq_start, vic_sources, node);
 		return;
 	default:
 		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
@@ -479,7 +532,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	vic_init2(base);
 
-	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);
+	vic_register(base, parent_irq, irq_start, fiq_start, vic_sources,
+		     resume_sources, node);
 }
 
 /**
@@ -490,9 +544,9 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
  * @resume_sources: bitmask of interrupt sources to allow for resume
  */
 void __init vic_init(void __iomem *base, unsigned int irq_start,
-		     u32 vic_sources, u32 resume_sources)
+		     int fiq_start, u32 vic_sources, u32 resume_sources)
 {
-	__vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL);
+	__vic_init(base, 0, irq_start, -1, vic_sources, resume_sources, NULL);
 }
 
 /**
@@ -511,7 +565,7 @@ int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 	struct vic_device *v;
 
 	v = &vic_devices[vic_id];
-	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL);
+	__vic_init(base, parent_irq, 0, -1, vic_sources, resume_sources, NULL);
 	/* Return out acquired base */
 	return v->irq;
 }
@@ -535,9 +589,10 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
 	of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask);
 
 	/*
-	 * Passing 0 as first IRQ makes the simple domain allocate descriptors
+	 * Passing 0 as first IRQ (and first FIQ) makes the domain allocate
+	 * descriptors.
 	 */
-	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
+	__vic_init(regs, 0, 0, -1, interrupt_mask, wakeup_mask, node);
 
 	return 0;
 }
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index ba46c79..fae480d 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -26,12 +26,16 @@
 #define VIC_INT_ENABLE			0x10	/* 1 = enable, 0 = disable */
 #define VIC_INT_ENABLE_CLEAR		0x14
 
+#define VIC_FIQ_START_NONE -1
+
 struct device_node;
 struct pt_regs;
 
 void __vic_init(void __iomem *base, int parent_irq, int irq_start,
-		u32 vic_sources, u32 resume_sources, struct device_node *node);
-void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
+		int fiq_start, u32 vic_sources, u32 resume_sources,
+		struct device_node *node);
+void vic_init(void __iomem *base, unsigned int irq_start, int fiq_start,
+	      u32 vic_sources, u32 resume_sources);
 int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 		      u32 vic_sources, u32 resume_sources);
 
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 07/10] ARM: Move some macros from entry-armv to entry-header
  2014-05-23 13:57   ` Daniel Thompson
@ 2014-05-23 13:57     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Ian Campbell, Anton Vorontsov, David A. Long, linux-serial,
	Catalin Marinas, kernel-team, devicetree, linaro-kernel,
	Pawel Moll, patches, Kumar Gala, Rob Herring, John Stultz,
	Thomas Gleixner, linux-arm-kernel, Greg Kroah-Hartman

From: Anton Vorontsov <anton.vorontsov@linaro.org>

Just move the macros into header file as we would want to use them for
KGDB FIQ entry code.

The following macros were moved:

 - svc_entry
 - usr_entry
 - kuser_cmpxchg_check
 - vector_stub

To make kuser_cmpxchg_check actually work across different files, we
also have to make kuser_cmpxchg64_fixup global.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
---
 arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
 arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 150 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 1879e8d..ed95b95 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -140,53 +140,6 @@ ENDPROC(__und_invalid)
  * SVC mode handlers
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
-#define SPFIX(code...) code
-#else
-#define SPFIX(code...)
-#endif
-
-	.macro	svc_entry, stack_hole=0
- UNWIND(.fnstart		)
- UNWIND(.save {r0 - pc}		)
-	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
-#ifdef CONFIG_THUMB2_KERNEL
- SPFIX(	str	r0, [sp]	)	@ temporarily saved
- SPFIX(	mov	r0, sp		)
- SPFIX(	tst	r0, #4		)	@ test original stack alignment
- SPFIX(	ldr	r0, [sp]	)	@ restored
-#else
- SPFIX(	tst	sp, #4		)
-#endif
- SPFIX(	subeq	sp, sp, #4	)
-	stmia	sp, {r1 - r12}
-
-	ldmia	r0, {r3 - r5}
-	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""      ""       ""
-	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
- SPFIX(	addeq	r2, r2, #4	)
-	str	r3, [sp, #-4]!		@ save the "real" r0 copied
-					@ from the exception stack
-
-	mov	r3, lr
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r2 - sp_svc
-	@  r3 - lr_svc
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	stmia	r7, {r2 - r6}
-
-#ifdef CONFIG_TRACE_IRQFLAGS
-	bl	trace_hardirqs_off
-#endif
-	.endm
-
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -306,73 +259,8 @@ ENDPROC(__pabt_svc)
 
 /*
  * User mode handlers
- *
- * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
 	.align	5
 __dabt_usr:
 	usr_entry
@@ -819,6 +707,7 @@ __kuser_cmpxchg64:				@ 0xffff0f60
 	ldmfd	sp!, {r4, r5, r6, pc}
 
 	.text
+	.global kuser_cmpxchg64_fixup
 kuser_cmpxchg64_fixup:
 	@ Called from kuser_cmpxchg_fixup.
 	@ r4 = address of interrupted insn (must be preserved).
@@ -960,44 +849,6 @@ __kuser_helper_end:
  * SP points to a minimal amount of processor-private memory, the address
  * of which is copied into r0 for the mode specific abort handler.
  */
-	.macro	vector_stub, name, mode, correction=0
-	.align	5
-
-vector_\name:
-	.if \correction
-	sub	lr, lr, #\correction
-	.endif
-
-	@
-	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
-	@ (parent CPSR)
-	@
-	stmia	sp, {r0, lr}		@ save r0, lr
-	mrs	lr, spsr
-	str	lr, [sp, #8]		@ save spsr
-
-	@
-	@ Prepare for SVC32 mode.  IRQs remain disabled.
-	@
-	mrs	r0, cpsr
-	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
-	msr	spsr_cxsf, r0
-
-	@
-	@ the branch table must immediately follow this code
-	@
-	and	lr, lr, #0x0f
- THUMB(	adr	r0, 1f			)
- THUMB(	ldr	lr, [r0, lr, lsl #2]	)
-	mov	r0, sp
- ARM(	ldr	lr, [pc, lr, lsl #2]	)
-	movs	pc, lr			@ branch to handler in SVC mode
-ENDPROC(vector_\name)
-
-	.align	2
-	@ handler addresses follow this label
-1:
-	.endm
 
 	.section .stubs, "ax", %progbits
 __stubs_start:
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 1420725..ab04a67 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -352,3 +352,167 @@ scno	.req	r7		@ syscall number
 tbl	.req	r8		@ syscall table pointer
 why	.req	r8		@ Linux syscall (!= 0)
 tsk	.req	r9		@ current thread_info
+
+/*
+ * SVC mode handler macros
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define SPFIX(code...) code
+#else
+#define SPFIX(code...)
+#endif
+
+	.macro	svc_entry, stack_hole=0
+ UNWIND(.fnstart		)
+ UNWIND(.save {r0 - pc}		)
+	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+#ifdef CONFIG_THUMB2_KERNEL
+ SPFIX(	str	r0, [sp]	)	@ temporarily saved
+ SPFIX(	mov	r0, sp		)
+ SPFIX(	tst	r0, #4		)	@ test original stack alignment
+ SPFIX(	ldr	r0, [sp]	)	@ restored
+#else
+ SPFIX(	tst	sp, #4		)
+#endif
+ SPFIX(	subeq	sp, sp, #4	)
+	stmia	sp, {r1 - r12}
+
+	ldmia	r0, {r3 - r5}
+	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""      ""       ""
+	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+ SPFIX(	addeq	r2, r2, #4	)
+	str	r3, [sp, #-4]!		@ save the "real" r0 copied
+					@ from the exception stack
+
+	mov	r3, lr
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r2 - sp_svc
+	@  r3 - lr_svc
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	stmia	r7, {r2 - r6}
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_off
+#endif
+	.endm
+
+/*
+ * User mode handler macros
+ *
+ * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+/*
+ * Vector stubs macro.
+ */
+	.macro	vector_stub, name, mode, correction=0
+	.align	5
+
+vector_\name:
+	.if \correction
+	sub	lr, lr, #\correction
+	.endif
+
+	@
+	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
+	@ (parent CPSR)
+	@
+	stmia	sp, {r0, lr}		@ save r0, lr
+	mrs	lr, spsr
+	str	lr, [sp, #8]		@ save spsr
+
+	@
+	@ Prepare for SVC32 mode.  IRQs remain disabled.
+	@
+	mrs	r0, cpsr
+	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
+	msr	spsr_cxsf, r0
+
+	@
+	@ the branch table must immediately follow this code
+	@
+	and	lr, lr, #0x0f
+ THUMB(	adr	r0, 1f			)
+ THUMB(	ldr	lr, [r0, lr, lsl #2]	)
+	mov	r0, sp
+ ARM(	ldr	lr, [pc, lr, lsl #2]	)
+	movs	pc, lr			@ branch to handler in SVC mode
+ENDPROC(vector_\name)
+
+	.align	2
+	@ handler addresses follow this label
+1:
+	.endm
+
+
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 07/10] ARM: Move some macros from entry-armv to entry-header
@ 2014-05-23 13:57     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: linux-arm-kernel

From: Anton Vorontsov <anton.vorontsov@linaro.org>

Just move the macros into header file as we would want to use them for
KGDB FIQ entry code.

The following macros were moved:

 - svc_entry
 - usr_entry
 - kuser_cmpxchg_check
 - vector_stub

To make kuser_cmpxchg_check actually work across different files, we
also have to make kuser_cmpxchg64_fixup global.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
---
 arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
 arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 150 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 1879e8d..ed95b95 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -140,53 +140,6 @@ ENDPROC(__und_invalid)
  * SVC mode handlers
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
-#define SPFIX(code...) code
-#else
-#define SPFIX(code...)
-#endif
-
-	.macro	svc_entry, stack_hole=0
- UNWIND(.fnstart		)
- UNWIND(.save {r0 - pc}		)
-	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
-#ifdef CONFIG_THUMB2_KERNEL
- SPFIX(	str	r0, [sp]	)	@ temporarily saved
- SPFIX(	mov	r0, sp		)
- SPFIX(	tst	r0, #4		)	@ test original stack alignment
- SPFIX(	ldr	r0, [sp]	)	@ restored
-#else
- SPFIX(	tst	sp, #4		)
-#endif
- SPFIX(	subeq	sp, sp, #4	)
-	stmia	sp, {r1 - r12}
-
-	ldmia	r0, {r3 - r5}
-	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""      ""       ""
-	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
- SPFIX(	addeq	r2, r2, #4	)
-	str	r3, [sp, #-4]!		@ save the "real" r0 copied
-					@ from the exception stack
-
-	mov	r3, lr
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r2 - sp_svc
-	@  r3 - lr_svc
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	stmia	r7, {r2 - r6}
-
-#ifdef CONFIG_TRACE_IRQFLAGS
-	bl	trace_hardirqs_off
-#endif
-	.endm
-
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -306,73 +259,8 @@ ENDPROC(__pabt_svc)
 
 /*
  * User mode handlers
- *
- * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
 	.align	5
 __dabt_usr:
 	usr_entry
@@ -819,6 +707,7 @@ __kuser_cmpxchg64:				@ 0xffff0f60
 	ldmfd	sp!, {r4, r5, r6, pc}
 
 	.text
+	.global kuser_cmpxchg64_fixup
 kuser_cmpxchg64_fixup:
 	@ Called from kuser_cmpxchg_fixup.
 	@ r4 = address of interrupted insn (must be preserved).
@@ -960,44 +849,6 @@ __kuser_helper_end:
  * SP points to a minimal amount of processor-private memory, the address
  * of which is copied into r0 for the mode specific abort handler.
  */
-	.macro	vector_stub, name, mode, correction=0
-	.align	5
-
-vector_\name:
-	.if \correction
-	sub	lr, lr, #\correction
-	.endif
-
-	@
-	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
-	@ (parent CPSR)
-	@
-	stmia	sp, {r0, lr}		@ save r0, lr
-	mrs	lr, spsr
-	str	lr, [sp, #8]		@ save spsr
-
-	@
-	@ Prepare for SVC32 mode.  IRQs remain disabled.
-	@
-	mrs	r0, cpsr
-	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
-	msr	spsr_cxsf, r0
-
-	@
-	@ the branch table must immediately follow this code
-	@
-	and	lr, lr, #0x0f
- THUMB(	adr	r0, 1f			)
- THUMB(	ldr	lr, [r0, lr, lsl #2]	)
-	mov	r0, sp
- ARM(	ldr	lr, [pc, lr, lsl #2]	)
-	movs	pc, lr			@ branch to handler in SVC mode
-ENDPROC(vector_\name)
-
-	.align	2
-	@ handler addresses follow this label
-1:
-	.endm
 
 	.section .stubs, "ax", %progbits
 __stubs_start:
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 1420725..ab04a67 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -352,3 +352,167 @@ scno	.req	r7		@ syscall number
 tbl	.req	r8		@ syscall table pointer
 why	.req	r8		@ Linux syscall (!= 0)
 tsk	.req	r9		@ current thread_info
+
+/*
+ * SVC mode handler macros
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define SPFIX(code...) code
+#else
+#define SPFIX(code...)
+#endif
+
+	.macro	svc_entry, stack_hole=0
+ UNWIND(.fnstart		)
+ UNWIND(.save {r0 - pc}		)
+	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+#ifdef CONFIG_THUMB2_KERNEL
+ SPFIX(	str	r0, [sp]	)	@ temporarily saved
+ SPFIX(	mov	r0, sp		)
+ SPFIX(	tst	r0, #4		)	@ test original stack alignment
+ SPFIX(	ldr	r0, [sp]	)	@ restored
+#else
+ SPFIX(	tst	sp, #4		)
+#endif
+ SPFIX(	subeq	sp, sp, #4	)
+	stmia	sp, {r1 - r12}
+
+	ldmia	r0, {r3 - r5}
+	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""      ""       ""
+	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+ SPFIX(	addeq	r2, r2, #4	)
+	str	r3, [sp, #-4]!		@ save the "real" r0 copied
+					@ from the exception stack
+
+	mov	r3, lr
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r2 - sp_svc
+	@  r3 - lr_svc
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	stmia	r7, {r2 - r6}
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_off
+#endif
+	.endm
+
+/*
+ * User mode handler macros
+ *
+ * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+/*
+ * Vector stubs macro.
+ */
+	.macro	vector_stub, name, mode, correction=0
+	.align	5
+
+vector_\name:
+	.if \correction
+	sub	lr, lr, #\correction
+	.endif
+
+	@
+	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
+	@ (parent CPSR)
+	@
+	stmia	sp, {r0, lr}		@ save r0, lr
+	mrs	lr, spsr
+	str	lr, [sp, #8]		@ save spsr
+
+	@
+	@ Prepare for SVC32 mode.  IRQs remain disabled.
+	@
+	mrs	r0, cpsr
+	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
+	msr	spsr_cxsf, r0
+
+	@
+	@ the branch table must immediately follow this code
+	@
+	and	lr, lr, #0x0f
+ THUMB(	adr	r0, 1f			)
+ THUMB(	ldr	lr, [r0, lr, lsl #2]	)
+	mov	r0, sp
+ ARM(	ldr	lr, [pc, lr, lsl #2]	)
+	movs	pc, lr			@ branch to handler in SVC mode
+ENDPROC(vector_\name)
+
+	.align	2
+	@ handler addresses follow this label
+1:
+	.endm
+
+
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 08/10] ARM: Add KGDB/KDB FIQ debugger generic code
  2014-05-23 13:57   ` Daniel Thompson
@ 2014-05-23 13:57     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Ian Campbell, Anton Vorontsov, Ben Dooks, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, Dave Martin,
	devicetree, linaro-kernel, Pawel Moll, patches, Kumar Gala,
	Rob Herring, John Stultz, Thomas Gleixner

From: Anton Vorontsov <anton.vorontsov@linaro.org>

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

By default KGDB FIQ is disabled in runtime, but can be enabled with
kgdb_fiq.enable=1 kernel command line option.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben.dooks@codethink.co.uk>
Cc: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 ++++++
 arch/arm/include/asm/kgdb.h      |   7 +++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/kgdb_fiq.c       | 117 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S |  87 +++++++++++++++++++++++++++++
 6 files changed, 232 insertions(+)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index db3c541..419fd0a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -307,6 +307,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -356,6 +357,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 6a2bcfd..1f1bec1 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,24 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be
+	  enabled with kgdb_fiq.enable=1 kernel command line option.
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..5de21f01 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,11 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern char kgdb_fiq_handler;
+extern char kgdb_fiq_handler_end;
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs);
+extern int kgdb_register_fiq(unsigned int fiq);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 040619c..251f651 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -67,6 +67,7 @@ endif
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
 obj-$(CONFIG_ARM_THUMBEE)	+= thumbee.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
+obj-$(CONFIG_KGDB_FIQ)		+= kgdb_fiq_entry.o kgdb_fiq.o
 obj-$(CONFIG_ARM_UNWIND)	+= unwind.o
 obj-$(CONFIG_HAVE_TCM)		+= tcm.o
 obj-$(CONFIG_OF)		+= devtree.o
diff --git a/arch/arm/kernel/kgdb_fiq.c b/arch/arm/kernel/kgdb_fiq.c
new file mode 100644
index 0000000..b236409
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq.c
@@ -0,0 +1,117 @@
+/*
+ * KGDB FIQ
+ *
+ * Copyright 2010 Google, Inc.
+ *		  Arve Hjønnevåg <arve@android.com>
+ *		  Colin Cross <ccross@android.com>
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/hardirq.h>
+#include <linux/atomic.h>
+#include <linux/kdb.h>
+#include <linux/kgdb.h>
+#include <asm/fiq.h>
+#include <asm/exception.h>
+
+static int kgdb_fiq_enabled;
+module_param_named(enable, kgdb_fiq_enabled, int, 0600);
+MODULE_PARM_DESC(enable, "set to 1 to enable FIQ KGDB");
+
+static unsigned int kgdb_fiq;
+
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs)
+{
+	if (kgdb_nmi_poll_knock()) {
+		nmi_enter();
+		kgdb_handle_exception(1, 0, 0, regs);
+		nmi_exit();
+	}
+
+	eoi_fiq(kgdb_fiq);
+}
+
+static struct fiq_handler kgdb_fiq_desc = {
+	.name = "kgdb",
+};
+
+static long kgdb_fiq_setup_stack(void *info)
+{
+	struct pt_regs regs;
+
+	regs.ARM_sp = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER) +
+			THREAD_START_SP;
+	WARN_ON(!regs.ARM_sp);
+
+	set_fiq_regs(&regs);
+	return 0;
+}
+
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * This function manages NMIs that usually cause KGDB to enter. That is, not
+ * all NMIs should be enabled or disabled, but only those that issue
+ * kgdb_handle_exception().
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	static atomic_t cnt;
+	int ret;
+
+	ret = atomic_add_return(on ? 1 : -1, &cnt);
+	if (ret > 1 && on) {
+		/*
+		 * There should be only one instance that calls this function
+		 * in "enable, disable" order. All other users must call
+		 * disable first, then enable. If not, something is wrong.
+		 */
+		WARN_ON(1);
+		return;
+	}
+
+	if (ret > 0)
+		enable_fiq(kgdb_fiq);
+	else
+		disable_fiq(kgdb_fiq);
+}
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	int err;
+	int cpu;
+
+	if (!kgdb_fiq_enabled)
+		return -ENODEV;
+
+	kgdb_fiq = fiq;
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	for_each_possible_cpu(cpu)
+		work_on_cpu(cpu, kgdb_fiq_setup_stack, NULL);
+
+	set_fiq_handler(&kgdb_fiq_handler,
+			&kgdb_fiq_handler_end - &kgdb_fiq_handler);
+
+	arch_kgdb_ops.enable_nmi = kgdb_fiq_enable_nmi;
+	return 0;
+}
diff --git a/arch/arm/kernel/kgdb_fiq_entry.S b/arch/arm/kernel/kgdb_fiq_entry.S
new file mode 100644
index 0000000..d6becca
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq_entry.S
@@ -0,0 +1,87 @@
+/*
+ * KGDB FIQ entry
+ *
+ * Copyright 1996,1997,1998 Russell King.
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+#include <asm/unwind.h>
+#include "entry-header.S"
+
+	.text
+
+@ This is needed for usr_entry/alignment_trap
+.LCcralign:
+	.long	cr_alignment
+.LCdohandle:
+	.long	kgdb_fiq_do_handle
+
+	.macro	fiq_handler
+	ldr	r1, =.LCdohandle
+	mov	r0, sp
+	adr	lr, BSYM(9997f)
+	ldr	pc, [r1]
+9997:
+	.endm
+
+	.align	5
+__fiq_svc:
+	svc_entry
+	fiq_handler
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+	.ltorg
+
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+	.ltorg
+
+	.global kgdb_fiq_handler
+kgdb_fiq_handler:
+
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_svc			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
+
+	.global kgdb_fiq_handler_end
+kgdb_fiq_handler_end:
-- 
1.9.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 08/10] ARM: Add KGDB/KDB FIQ debugger generic code
@ 2014-05-23 13:57     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: linux-arm-kernel

From: Anton Vorontsov <anton.vorontsov@linaro.org>

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

By default KGDB FIQ is disabled in runtime, but can be enabled with
kgdb_fiq.enable=1 kernel command line option.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben.dooks@codethink.co.uk>
Cc: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 ++++++
 arch/arm/include/asm/kgdb.h      |   7 +++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/kgdb_fiq.c       | 117 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S |  87 +++++++++++++++++++++++++++++
 6 files changed, 232 insertions(+)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index db3c541..419fd0a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -307,6 +307,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -356,6 +357,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 6a2bcfd..1f1bec1 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,24 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be
+	  enabled with kgdb_fiq.enable=1 kernel command line option.
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..5de21f01 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,11 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern char kgdb_fiq_handler;
+extern char kgdb_fiq_handler_end;
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs);
+extern int kgdb_register_fiq(unsigned int fiq);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 040619c..251f651 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -67,6 +67,7 @@ endif
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
 obj-$(CONFIG_ARM_THUMBEE)	+= thumbee.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
+obj-$(CONFIG_KGDB_FIQ)		+= kgdb_fiq_entry.o kgdb_fiq.o
 obj-$(CONFIG_ARM_UNWIND)	+= unwind.o
 obj-$(CONFIG_HAVE_TCM)		+= tcm.o
 obj-$(CONFIG_OF)		+= devtree.o
diff --git a/arch/arm/kernel/kgdb_fiq.c b/arch/arm/kernel/kgdb_fiq.c
new file mode 100644
index 0000000..b236409
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq.c
@@ -0,0 +1,117 @@
+/*
+ * KGDB FIQ
+ *
+ * Copyright 2010 Google, Inc.
+ *		  Arve Hj?nnev?g <arve@android.com>
+ *		  Colin Cross <ccross@android.com>
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/hardirq.h>
+#include <linux/atomic.h>
+#include <linux/kdb.h>
+#include <linux/kgdb.h>
+#include <asm/fiq.h>
+#include <asm/exception.h>
+
+static int kgdb_fiq_enabled;
+module_param_named(enable, kgdb_fiq_enabled, int, 0600);
+MODULE_PARM_DESC(enable, "set to 1 to enable FIQ KGDB");
+
+static unsigned int kgdb_fiq;
+
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs)
+{
+	if (kgdb_nmi_poll_knock()) {
+		nmi_enter();
+		kgdb_handle_exception(1, 0, 0, regs);
+		nmi_exit();
+	}
+
+	eoi_fiq(kgdb_fiq);
+}
+
+static struct fiq_handler kgdb_fiq_desc = {
+	.name = "kgdb",
+};
+
+static long kgdb_fiq_setup_stack(void *info)
+{
+	struct pt_regs regs;
+
+	regs.ARM_sp = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER) +
+			THREAD_START_SP;
+	WARN_ON(!regs.ARM_sp);
+
+	set_fiq_regs(&regs);
+	return 0;
+}
+
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * This function manages NMIs that usually cause KGDB to enter. That is, not
+ * all NMIs should be enabled or disabled, but only those that issue
+ * kgdb_handle_exception().
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	static atomic_t cnt;
+	int ret;
+
+	ret = atomic_add_return(on ? 1 : -1, &cnt);
+	if (ret > 1 && on) {
+		/*
+		 * There should be only one instance that calls this function
+		 * in "enable, disable" order. All other users must call
+		 * disable first, then enable. If not, something is wrong.
+		 */
+		WARN_ON(1);
+		return;
+	}
+
+	if (ret > 0)
+		enable_fiq(kgdb_fiq);
+	else
+		disable_fiq(kgdb_fiq);
+}
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	int err;
+	int cpu;
+
+	if (!kgdb_fiq_enabled)
+		return -ENODEV;
+
+	kgdb_fiq = fiq;
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	for_each_possible_cpu(cpu)
+		work_on_cpu(cpu, kgdb_fiq_setup_stack, NULL);
+
+	set_fiq_handler(&kgdb_fiq_handler,
+			&kgdb_fiq_handler_end - &kgdb_fiq_handler);
+
+	arch_kgdb_ops.enable_nmi = kgdb_fiq_enable_nmi;
+	return 0;
+}
diff --git a/arch/arm/kernel/kgdb_fiq_entry.S b/arch/arm/kernel/kgdb_fiq_entry.S
new file mode 100644
index 0000000..d6becca
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq_entry.S
@@ -0,0 +1,87 @@
+/*
+ * KGDB FIQ entry
+ *
+ * Copyright 1996,1997,1998 Russell King.
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+#include <asm/unwind.h>
+#include "entry-header.S"
+
+	.text
+
+@ This is needed for usr_entry/alignment_trap
+.LCcralign:
+	.long	cr_alignment
+.LCdohandle:
+	.long	kgdb_fiq_do_handle
+
+	.macro	fiq_handler
+	ldr	r1, =.LCdohandle
+	mov	r0, sp
+	adr	lr, BSYM(9997f)
+	ldr	pc, [r1]
+9997:
+	.endm
+
+	.align	5
+__fiq_svc:
+	svc_entry
+	fiq_handler
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+	.ltorg
+
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+	.ltorg
+
+	.global kgdb_fiq_handler
+kgdb_fiq_handler:
+
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_svc			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
+
+	.global kgdb_fiq_handler_end
+kgdb_fiq_handler_end:
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 09/10] serial: amba-pl011: Pass on FIQ information to KGDB.
  2014-05-23 13:57   ` Daniel Thompson
@ 2014-05-23 13:57     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Ian Campbell, Anton Vorontsov, David A. Long, linux-serial,
	Catalin Marinas, kernel-team, devicetree, linaro-kernel,
	Pawel Moll, patches, Kumar Gala, Rob Herring, John Stultz,
	Thomas Gleixner, linux-arm-kernel, Greg Kroah-Hartman

If the AMBA bus has provided the pl011 with a FIQ resource (i.e. a
second IRQ) then speculatively register it with KGDB when the polling
driver is initialized.

By providing this information to KGDB the serial driver offers
"permission" for KGDB to route the UART interrupt signal from the
drivers own handler to KGDBs FIQ handler (which will eventually use the
UART's polled I/O callbacks to interact with the user). This permission
also implies the amba-pl011 driver has already unmasked RX interrupts
(otherwise the FIQ handler will never trigger).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 101 ++++++++++++++++++++++++----------------
 1 file changed, 60 insertions(+), 41 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index dacf0a0..d34c72c 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -58,6 +58,7 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/sizes.h>
 #include <linux/io.h>
+#include <linux/kgdb.h>
 
 #define UART_NR			14
 
@@ -158,6 +159,7 @@ struct uart_amba_port {
 	unsigned int		old_cr;		/* state during shutdown */
 	bool			autorts;
 	char			type[12];
+	int			fiq;
 #ifdef CONFIG_DMA_ENGINE
 	/* DMA stuff */
 	bool			using_tx_dma;
@@ -1416,8 +1418,63 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
 	spin_unlock_irqrestore(&uap->port.lock, flags);
 }
 
+static int pl011_hwinit(struct uart_port *port)
+{
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	int retval;
+
+	/* Optionaly enable pins to be muxed in and configured */
+	pinctrl_pm_select_default_state(port->dev);
+
+	/*
+	 * Try to enable the clock producer.
+	 */
+	retval = clk_prepare_enable(uap->clk);
+	if (retval)
+		goto out;
+
+	uap->port.uartclk = clk_get_rate(uap->clk);
+
+	/* Clear pending error and receive interrupts */
+	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
+	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
+
+	/*
+	 * Save interrupts enable mask, and enable RX interrupts in case if
+	 * the interrupt is used for NMI entry.
+	 */
+	uap->im = readw(uap->port.membase + UART011_IMSC);
+	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
+
+	if (dev_get_platdata(uap->port.dev)) {
+		struct amba_pl011_data *plat;
+
+		plat = dev_get_platdata(uap->port.dev);
+		if (plat->init)
+			plat->init();
+	}
+	return 0;
+ out:
+	return retval;
+}
+
 #ifdef CONFIG_CONSOLE_POLL
 
+static int pl011_poll_init(struct uart_port *port)
+{
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	int retval;
+
+	retval = pl011_hwinit(port);
+
+#ifdef CONFIG_KGDB_FIQ
+	if (retval == 0 && uap->fiq > 0)
+		kgdb_register_fiq(uap->fiq);
+#endif
+
+	return retval;
+}
+
 static void pl011_quiesce_irqs(struct uart_port *port)
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1471,46 +1528,6 @@ static void pl011_put_poll_char(struct uart_port *port,
 
 #endif /* CONFIG_CONSOLE_POLL */
 
-static int pl011_hwinit(struct uart_port *port)
-{
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
-	int retval;
-
-	/* Optionaly enable pins to be muxed in and configured */
-	pinctrl_pm_select_default_state(port->dev);
-
-	/*
-	 * Try to enable the clock producer.
-	 */
-	retval = clk_prepare_enable(uap->clk);
-	if (retval)
-		goto out;
-
-	uap->port.uartclk = clk_get_rate(uap->clk);
-
-	/* Clear pending error and receive interrupts */
-	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
-	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
-
-	/*
-	 * Save interrupts enable mask, and enable RX interrupts in case if
-	 * the interrupt is used for NMI entry.
-	 */
-	uap->im = readw(uap->port.membase + UART011_IMSC);
-	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
-
-	if (dev_get_platdata(uap->port.dev)) {
-		struct amba_pl011_data *plat;
-
-		plat = dev_get_platdata(uap->port.dev);
-		if (plat->init)
-			plat->init();
-	}
-	return 0;
- out:
-	return retval;
-}
-
 static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
 {
 	writew(lcr_h, uap->port.membase + uap->lcrh_rx);
@@ -1890,7 +1907,7 @@ static struct uart_ops amba_pl011_pops = {
 	.config_port	= pl011_config_port,
 	.verify_port	= pl011_verify_port,
 #ifdef CONFIG_CONSOLE_POLL
-	.poll_init     = pl011_hwinit,
+	.poll_init     = pl011_poll_init,
 	.poll_get_char = pl011_get_poll_char,
 	.poll_put_char = pl011_put_poll_char,
 #endif
@@ -2139,6 +2156,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
 	uap->port.membase = base;
 	uap->port.iotype = UPIO_MEM;
 	uap->port.irq = dev->irq[0];
+	uap->fiq = dev->irq[1];
 	uap->port.fifosize = uap->fifosize;
 	uap->port.ops = &amba_pl011_pops;
 	uap->port.flags = UPF_BOOT_AUTOCONF;
@@ -2169,6 +2187,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
 		uart_unregister_driver(&amba_reg);
 		pl011_dma_remove(uap);
 	}
+
  out:
 	return ret;
 }
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 09/10] serial: amba-pl011: Pass on FIQ information to KGDB.
@ 2014-05-23 13:57     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: linux-arm-kernel

If the AMBA bus has provided the pl011 with a FIQ resource (i.e. a
second IRQ) then speculatively register it with KGDB when the polling
driver is initialized.

By providing this information to KGDB the serial driver offers
"permission" for KGDB to route the UART interrupt signal from the
drivers own handler to KGDBs FIQ handler (which will eventually use the
UART's polled I/O callbacks to interact with the user). This permission
also implies the amba-pl011 driver has already unmasked RX interrupts
(otherwise the FIQ handler will never trigger).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 101 ++++++++++++++++++++++++----------------
 1 file changed, 60 insertions(+), 41 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index dacf0a0..d34c72c 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -58,6 +58,7 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/sizes.h>
 #include <linux/io.h>
+#include <linux/kgdb.h>
 
 #define UART_NR			14
 
@@ -158,6 +159,7 @@ struct uart_amba_port {
 	unsigned int		old_cr;		/* state during shutdown */
 	bool			autorts;
 	char			type[12];
+	int			fiq;
 #ifdef CONFIG_DMA_ENGINE
 	/* DMA stuff */
 	bool			using_tx_dma;
@@ -1416,8 +1418,63 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
 	spin_unlock_irqrestore(&uap->port.lock, flags);
 }
 
+static int pl011_hwinit(struct uart_port *port)
+{
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	int retval;
+
+	/* Optionaly enable pins to be muxed in and configured */
+	pinctrl_pm_select_default_state(port->dev);
+
+	/*
+	 * Try to enable the clock producer.
+	 */
+	retval = clk_prepare_enable(uap->clk);
+	if (retval)
+		goto out;
+
+	uap->port.uartclk = clk_get_rate(uap->clk);
+
+	/* Clear pending error and receive interrupts */
+	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
+	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
+
+	/*
+	 * Save interrupts enable mask, and enable RX interrupts in case if
+	 * the interrupt is used for NMI entry.
+	 */
+	uap->im = readw(uap->port.membase + UART011_IMSC);
+	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
+
+	if (dev_get_platdata(uap->port.dev)) {
+		struct amba_pl011_data *plat;
+
+		plat = dev_get_platdata(uap->port.dev);
+		if (plat->init)
+			plat->init();
+	}
+	return 0;
+ out:
+	return retval;
+}
+
 #ifdef CONFIG_CONSOLE_POLL
 
+static int pl011_poll_init(struct uart_port *port)
+{
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	int retval;
+
+	retval = pl011_hwinit(port);
+
+#ifdef CONFIG_KGDB_FIQ
+	if (retval == 0 && uap->fiq > 0)
+		kgdb_register_fiq(uap->fiq);
+#endif
+
+	return retval;
+}
+
 static void pl011_quiesce_irqs(struct uart_port *port)
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1471,46 +1528,6 @@ static void pl011_put_poll_char(struct uart_port *port,
 
 #endif /* CONFIG_CONSOLE_POLL */
 
-static int pl011_hwinit(struct uart_port *port)
-{
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
-	int retval;
-
-	/* Optionaly enable pins to be muxed in and configured */
-	pinctrl_pm_select_default_state(port->dev);
-
-	/*
-	 * Try to enable the clock producer.
-	 */
-	retval = clk_prepare_enable(uap->clk);
-	if (retval)
-		goto out;
-
-	uap->port.uartclk = clk_get_rate(uap->clk);
-
-	/* Clear pending error and receive interrupts */
-	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
-	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
-
-	/*
-	 * Save interrupts enable mask, and enable RX interrupts in case if
-	 * the interrupt is used for NMI entry.
-	 */
-	uap->im = readw(uap->port.membase + UART011_IMSC);
-	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
-
-	if (dev_get_platdata(uap->port.dev)) {
-		struct amba_pl011_data *plat;
-
-		plat = dev_get_platdata(uap->port.dev);
-		if (plat->init)
-			plat->init();
-	}
-	return 0;
- out:
-	return retval;
-}
-
 static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
 {
 	writew(lcr_h, uap->port.membase + uap->lcrh_rx);
@@ -1890,7 +1907,7 @@ static struct uart_ops amba_pl011_pops = {
 	.config_port	= pl011_config_port,
 	.verify_port	= pl011_verify_port,
 #ifdef CONFIG_CONSOLE_POLL
-	.poll_init     = pl011_hwinit,
+	.poll_init     = pl011_poll_init,
 	.poll_get_char = pl011_get_poll_char,
 	.poll_put_char = pl011_put_poll_char,
 #endif
@@ -2139,6 +2156,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
 	uap->port.membase = base;
 	uap->port.iotype = UPIO_MEM;
 	uap->port.irq = dev->irq[0];
+	uap->fiq = dev->irq[1];
 	uap->port.fifosize = uap->fifosize;
 	uap->port.ops = &amba_pl011_pops;
 	uap->port.flags = UPF_BOOT_AUTOCONF;
@@ -2169,6 +2187,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
 		uart_unregister_driver(&amba_reg);
 		pl011_dma_remove(uap);
 	}
+
  out:
 	return ret;
 }
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 10/10] serial: asc: Add support for KGDB's FIQ/NMI mode
  2014-05-23 13:57   ` Daniel Thompson
@ 2014-05-23 13:57     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij,
	Patrice Chotard, Jiri Slaby, Daniel Thompson, Dirk Behme,
	Russell King, Nicolas Pitre, Ian Campbell, Anton Vorontsov,
	David A. Long, linux-serial, Catalin Marinas, kernel-team,
	devicetree, linaro-kernel, Pawel Moll, patches, Kumar Gala,
	Rob Herring, John Stultz, Thomas Gleixner, linux-arm-kernel

If the platform bus has provided the st-asc with a FIQ resource (i.e. a
second IRQ) then speculatively register it with KGDB when the polling
driver is initialized.

By providing this information to KGDB the serial driver offers
"permission" for KGDB to route the UART interrupt signal from the
drivers own handler to KGDBs FIQ handler (which will eventually use the
UART's polled I/O callbacks to interact with the user). This permission
also implies the st-asc driver has already unmasked RX interrupts
(otherwise the FIQ handler will never trigger). This unmask is copied
from similar code in amba-pl011.c .

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel@stlinux.com
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index c7f61ac..328720f 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -30,6 +30,7 @@
 #include <linux/of_platform.h>
 #include <linux/serial_core.h>
 #include <linux/clk.h>
+#include <linux/kgdb.h>
 
 #define DRIVER_NAME "st-asc"
 #define ASC_SERIAL_NAME "ttyAS"
@@ -39,6 +40,7 @@
 struct asc_port {
 	struct uart_port port;
 	struct clk *clk;
+	int fiq;
 	unsigned int hw_flow_control:1;
 	unsigned int force_m1:1;
 };
@@ -613,6 +615,26 @@ asc_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+
+#ifdef CONFIG_KGDB_FIQ
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int asc_poll_init(struct uart_port *port)
+{
+	struct asc_port *ascport = container_of(port, struct asc_port, port);
+
+	/* register the FIQ with kgdb */
+	if (ascport->fiq >= 0)
+		kgdb_register_fiq(ascport->fiq);
+
+	/* enable RX interrupts in case the interrupt is used for NMI entry. */
+	asc_enable_rx_interrupts(port);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 /*
  * Console polling routines for writing and reading from the uart while
  * in an interrupt or debug context (i.e. kgdb).
@@ -656,11 +678,15 @@ static struct uart_ops asc_uart_ops = {
 	.verify_port	= asc_verify_port,
 	.pm		= asc_pm,
 #ifdef CONFIG_CONSOLE_POLL
+#ifdef CONFIG_KGDB_FIQ
+	.poll_init     = asc_poll_init,
+#endif /* CONFIG_KGDB_FIQ */
 	.poll_get_char = asc_get_poll_char,
 	.poll_put_char = asc_put_poll_char,
 #endif /* CONFIG_CONSOLE_POLL */
 };
 
+
 static int asc_init_port(struct asc_port *ascport,
 			  struct platform_device *pdev)
 {
@@ -673,6 +699,7 @@ static int asc_init_port(struct asc_port *ascport,
 	port->fifosize	= ASC_FIFO_SIZE;
 	port->dev	= &pdev->dev;
 	port->irq	= platform_get_irq(pdev, 0);
+	ascport->fiq    = platform_get_irq(pdev, 1);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	port->membase = devm_ioremap_resource(&pdev->dev, res);
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v2 10/10] serial: asc: Add support for KGDB's FIQ/NMI mode
@ 2014-05-23 13:57     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-23 13:57 UTC (permalink / raw)
  To: linux-arm-kernel

If the platform bus has provided the st-asc with a FIQ resource (i.e. a
second IRQ) then speculatively register it with KGDB when the polling
driver is initialized.

By providing this information to KGDB the serial driver offers
"permission" for KGDB to route the UART interrupt signal from the
drivers own handler to KGDBs FIQ handler (which will eventually use the
UART's polled I/O callbacks to interact with the user). This permission
also implies the st-asc driver has already unmasked RX interrupts
(otherwise the FIQ handler will never trigger). This unmask is copied
from similar code in amba-pl011.c .

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel at stlinux.com
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index c7f61ac..328720f 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -30,6 +30,7 @@
 #include <linux/of_platform.h>
 #include <linux/serial_core.h>
 #include <linux/clk.h>
+#include <linux/kgdb.h>
 
 #define DRIVER_NAME "st-asc"
 #define ASC_SERIAL_NAME "ttyAS"
@@ -39,6 +40,7 @@
 struct asc_port {
 	struct uart_port port;
 	struct clk *clk;
+	int fiq;
 	unsigned int hw_flow_control:1;
 	unsigned int force_m1:1;
 };
@@ -613,6 +615,26 @@ asc_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+
+#ifdef CONFIG_KGDB_FIQ
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int asc_poll_init(struct uart_port *port)
+{
+	struct asc_port *ascport = container_of(port, struct asc_port, port);
+
+	/* register the FIQ with kgdb */
+	if (ascport->fiq >= 0)
+		kgdb_register_fiq(ascport->fiq);
+
+	/* enable RX interrupts in case the interrupt is used for NMI entry. */
+	asc_enable_rx_interrupts(port);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 /*
  * Console polling routines for writing and reading from the uart while
  * in an interrupt or debug context (i.e. kgdb).
@@ -656,11 +678,15 @@ static struct uart_ops asc_uart_ops = {
 	.verify_port	= asc_verify_port,
 	.pm		= asc_pm,
 #ifdef CONFIG_CONSOLE_POLL
+#ifdef CONFIG_KGDB_FIQ
+	.poll_init     = asc_poll_init,
+#endif /* CONFIG_KGDB_FIQ */
 	.poll_get_char = asc_get_poll_char,
 	.poll_put_char = asc_put_poll_char,
 #endif /* CONFIG_CONSOLE_POLL */
 };
 
+
 static int asc_init_port(struct asc_port *ascport,
 			  struct platform_device *pdev)
 {
@@ -673,6 +699,7 @@ static int asc_init_port(struct asc_port *ascport,
 	port->fifosize	= ASC_FIFO_SIZE;
 	port->dev	= &pdev->dev;
 	port->irq	= platform_get_irq(pdev, 0);
+	ascport->fiq    = platform_get_irq(pdev, 1);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	port->membase = devm_ioremap_resource(&pdev->dev, res);
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* Re: [RFC v2 10/10] serial: asc: Add support for KGDB's FIQ/NMI mode
  2014-05-23 13:57     ` Daniel Thompson
@ 2014-05-23 14:50       ` Srinivas Kandagatla
  -1 siblings, 0 replies; 535+ messages in thread
From: Srinivas Kandagatla @ 2014-05-23 14:50 UTC (permalink / raw)
  To: Daniel Thompson, Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij,
	linux-kernel, Jiri Slaby, Dirk Behme, Russell King,
	Nicolas Pitre, patches, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, Ian Campbell, Colin Cross,
	Rob Herring, John Stultz, Thomas Gleixner, linux-arm-kernel,
	Maxime Coquelin, Greg

Hi Dan,

On 23/05/14 14:57, Daniel Thompson wrote:
> If the platform bus has provided the st-asc with a FIQ resource (i.e. a
> second IRQ) then speculatively register it with KGDB when the polling
> driver is initialized.
>
> By providing this information to KGDB the serial driver offers
> "permission" for KGDB to route the UART interrupt signal from the
> drivers own handler to KGDBs FIQ handler (which will eventually use the
> UART's polled I/O callbacks to interact with the user). This permission
> also implies the st-asc driver has already unmasked RX interrupts
> (otherwise the FIQ handler will never trigger). This unmask is copied
> from similar code in amba-pl011.c .
>
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
> Cc: Maxime Coquelin <maxime.coquelin@st.com>
> Cc: Patrice Chotard <patrice.chotard@st.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Jiri Slaby <jslaby@suse.cz>
> Cc: kernel@stlinux.com
> Cc: linux-serial@vger.kernel.org
> ---
>   drivers/tty/serial/st-asc.c | 27 +++++++++++++++++++++++++++
>   1 file changed, 27 insertions(+)
>


Also this new entry should be documented in the st-asc dt bindings.


> diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
> index c7f61ac..328720f 100644
> --- a/drivers/tty/serial/st-asc.c
> +++ b/drivers/tty/serial/st-asc.c
> @@ -30,6 +30,7 @@
>   #include <linux/of_platform.h>
>   #include <linux/serial_core.h>
>   #include <linux/clk.h>
> +#include <linux/kgdb.h>
>
>   #define DRIVER_NAME "st-asc"
>   #define ASC_SERIAL_NAME "ttyAS"
> @@ -39,6 +40,7 @@
>   struct asc_port {
>   	struct uart_port port;
>   	struct clk *clk;
> +	int fiq;
>   	unsigned int hw_flow_control:1;
>   	unsigned int force_m1:1;
>   };
...


>   #ifdef CONFIG_CONSOLE_POLL
> +#ifdef CONFIG_KGDB_FIQ
> +	.poll_init     = asc_poll_init,
> +#endif /* CONFIG_KGDB_FIQ */
>   	.poll_get_char = asc_get_poll_char,
>   	.poll_put_char = asc_put_poll_char,
>   #endif /* CONFIG_CONSOLE_POLL */
>   };
>
> +

no need of extra new line here.

>   static int asc_init_port(struct asc_port *ascport,
>   			  struct platform_device *pdev)
>   {
> @@ -673,6 +699,7 @@ static int asc_init_port(struct asc_port *ascport,
>   	port->fifosize	= ASC_FIFO_SIZE;
>   	port->dev	= &pdev->dev;
>   	port->irq	= platform_get_irq(pdev, 0);
> +	ascport->fiq    = platform_get_irq(pdev, 1);
>

Probably its better to give names to the irq resources and get them. As 
forcing the order in DT is always tricky highly possible for an error.



Thanks,
srini

>   	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>   	port->membase = devm_ioremap_resource(&pdev->dev, res);
>

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v2 10/10] serial: asc: Add support for KGDB's FIQ/NMI mode
@ 2014-05-23 14:50       ` Srinivas Kandagatla
  0 siblings, 0 replies; 535+ messages in thread
From: Srinivas Kandagatla @ 2014-05-23 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Dan,

On 23/05/14 14:57, Daniel Thompson wrote:
> If the platform bus has provided the st-asc with a FIQ resource (i.e. a
> second IRQ) then speculatively register it with KGDB when the polling
> driver is initialized.
>
> By providing this information to KGDB the serial driver offers
> "permission" for KGDB to route the UART interrupt signal from the
> drivers own handler to KGDBs FIQ handler (which will eventually use the
> UART's polled I/O callbacks to interact with the user). This permission
> also implies the st-asc driver has already unmasked RX interrupts
> (otherwise the FIQ handler will never trigger). This unmask is copied
> from similar code in amba-pl011.c .
>
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
> Cc: Maxime Coquelin <maxime.coquelin@st.com>
> Cc: Patrice Chotard <patrice.chotard@st.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Jiri Slaby <jslaby@suse.cz>
> Cc: kernel at stlinux.com
> Cc: linux-serial at vger.kernel.org
> ---
>   drivers/tty/serial/st-asc.c | 27 +++++++++++++++++++++++++++
>   1 file changed, 27 insertions(+)
>


Also this new entry should be documented in the st-asc dt bindings.


> diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
> index c7f61ac..328720f 100644
> --- a/drivers/tty/serial/st-asc.c
> +++ b/drivers/tty/serial/st-asc.c
> @@ -30,6 +30,7 @@
>   #include <linux/of_platform.h>
>   #include <linux/serial_core.h>
>   #include <linux/clk.h>
> +#include <linux/kgdb.h>
>
>   #define DRIVER_NAME "st-asc"
>   #define ASC_SERIAL_NAME "ttyAS"
> @@ -39,6 +40,7 @@
>   struct asc_port {
>   	struct uart_port port;
>   	struct clk *clk;
> +	int fiq;
>   	unsigned int hw_flow_control:1;
>   	unsigned int force_m1:1;
>   };
...


>   #ifdef CONFIG_CONSOLE_POLL
> +#ifdef CONFIG_KGDB_FIQ
> +	.poll_init     = asc_poll_init,
> +#endif /* CONFIG_KGDB_FIQ */
>   	.poll_get_char = asc_get_poll_char,
>   	.poll_put_char = asc_put_poll_char,
>   #endif /* CONFIG_CONSOLE_POLL */
>   };
>
> +

no need of extra new line here.

>   static int asc_init_port(struct asc_port *ascport,
>   			  struct platform_device *pdev)
>   {
> @@ -673,6 +699,7 @@ static int asc_init_port(struct asc_port *ascport,
>   	port->fifosize	= ASC_FIFO_SIZE;
>   	port->dev	= &pdev->dev;
>   	port->irq	= platform_get_irq(pdev, 0);
> +	ascport->fiq    = platform_get_irq(pdev, 1);
>

Probably its better to give names to the irq resources and get them. As 
forcing the order in DT is always tricky highly possible for an error.



Thanks,
srini

>   	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>   	port->membase = devm_ioremap_resource(&pdev->dev, res);
>

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [RFC v2 01/10] arm: fiq: Allow EOI to be communicated to the intc
  2014-05-23 13:57     ` Daniel Thompson
@ 2014-05-23 14:59       ` Srinivas Kandagatla
  -1 siblings, 0 replies; 535+ messages in thread
From: Srinivas Kandagatla @ 2014-05-23 14:59 UTC (permalink / raw)
  To: Daniel Thompson, Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij,
	Fabio Estevam, Dirk Behme, Russell King, Nicolas Pitre,
	Jiri Slaby, patches, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, Ian Campbell, Colin Cross,
	Rob Herring, John Stultz, Thomas Gleixner, linux-arm-kernel,
	Greg Kroah-Hartman



On 23/05/14 14:57, Daniel Thompson wrote:
> +
> +	if (chip->irq_eoi)
> +			chip->irq_eoi(irq_data);
> +}
> +
Looks like an extra tab here..

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v2 01/10] arm: fiq: Allow EOI to be communicated to the intc
@ 2014-05-23 14:59       ` Srinivas Kandagatla
  0 siblings, 0 replies; 535+ messages in thread
From: Srinivas Kandagatla @ 2014-05-23 14:59 UTC (permalink / raw)
  To: linux-arm-kernel



On 23/05/14 14:57, Daniel Thompson wrote:
> +
> +	if (chip->irq_eoi)
> +			chip->irq_eoi(irq_data);
> +}
> +
Looks like an extra tab here..

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [RFC v2 01/10] arm: fiq: Allow EOI to be communicated to the intc
  2014-05-23 13:57     ` Daniel Thompson
@ 2014-05-23 15:00       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-05-23 15:00 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Mark Rutland, kernel, Catalin Marinas, Linus Walleij, Jiri Slaby,
	Dirk Behme, Nicolas Pitre, Fabio Estevam, patches,
	Anton Vorontsov, Kumar Gala, David A. Long, linux-serial,
	kgdb-bugreport, kernel-team, devicetree, linaro-kernel,
	Pawel Moll, Ian Campbell, Jason Wessel, Rob Herring, John Stultz,
	Thomas Gleixner, linux-arm-kernel, Greg Kroah-Hartman

On Fri, May 23, 2014 at 02:57:49PM +0100, Daniel Thompson wrote:
> +void eoi_fiq(int fiq)
> +{
> +	struct irq_data *irq_data = irq_get_irq_data(fiq + fiq_start);
> +	struct irq_chip *chip = irq_data_get_irq_chip(irq_data);
> +
> +	if (chip->irq_eoi)
> +			chip->irq_eoi(irq_data);
> +}

So what if the IRQ chip takes a spinlock?  You can't take spinlocks in
FIQ context...  Who checks for that kind of stuff - just hoping that
the IRQ driver doesn't take a spinlock sounds real fragile.

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v2 01/10] arm: fiq: Allow EOI to be communicated to the intc
@ 2014-05-23 15:00       ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-05-23 15:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 23, 2014 at 02:57:49PM +0100, Daniel Thompson wrote:
> +void eoi_fiq(int fiq)
> +{
> +	struct irq_data *irq_data = irq_get_irq_data(fiq + fiq_start);
> +	struct irq_chip *chip = irq_data_get_irq_chip(irq_data);
> +
> +	if (chip->irq_eoi)
> +			chip->irq_eoi(irq_data);
> +}

So what if the IRQ chip takes a spinlock?  You can't take spinlocks in
FIQ context...  Who checks for that kind of stuff - just hoping that
the IRQ driver doesn't take a spinlock sounds real fragile.

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [RFC v2 04/10] ARM: vexpress: Extend UART with FIQ support
  2014-05-23 13:57     ` Daniel Thompson
@ 2014-05-23 15:04       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-05-23 15:04 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Mark Rutland, kernel, Catalin Marinas, Linus Walleij, Jiri Slaby,
	Dirk Behme, Nicolas Pitre, patches, Anton Vorontsov, Kumar Gala,
	David A. Long, linux-serial, kgdb-bugreport, kernel-team,
	devicetree, linaro-kernel, Pawel Moll, Ian Campbell,
	Jason Wessel, Rob Herring, John Stultz, Thomas Gleixner,
	linux-arm-kernel, Greg Kroah-Hartman, linux-kernel

On Fri, May 23, 2014 at 02:57:52PM +0100, Daniel Thompson wrote:
> @@ -140,7 +140,7 @@
>  			v2m_serial0: uart@090000 {
>  				compatible = "arm,pl011", "arm,primecell";
>  				reg = <0x090000 0x1000>;
> -				interrupts = <5>;
> +				interrupts = <5>, <69>;

NAK.  This is obviously a Linux implementation detail - the second
number is your "FIQ" number which you've decided will be offset by
64.

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v2 04/10] ARM: vexpress: Extend UART with FIQ support
@ 2014-05-23 15:04       ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-05-23 15:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 23, 2014 at 02:57:52PM +0100, Daniel Thompson wrote:
> @@ -140,7 +140,7 @@
>  			v2m_serial0: uart at 090000 {
>  				compatible = "arm,pl011", "arm,primecell";
>  				reg = <0x090000 0x1000>;
> -				interrupts = <5>;
> +				interrupts = <5>, <69>;

NAK.  This is obviously a Linux implementation detail - the second
number is your "FIQ" number which you've decided will be offset by
64.

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [RFC v2 01/10] arm: fiq: Allow EOI to be communicated to the intc
  2014-05-23 15:00       ` Russell King - ARM Linux
@ 2014-05-28 15:47         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-28 15:47 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Mark Rutland, kernel, Catalin Marinas, Linus Walleij, Jiri Slaby,
	Dirk Behme, Nicolas Pitre, Fabio Estevam, patches,
	Anton Vorontsov, Kumar Gala, David A. Long, linux-serial,
	kgdb-bugreport, kernel-team, devicetree, linaro-kernel,
	Pawel Moll, Ian Campbell, Jason Wessel, Rob Herring, John Stultz,
	Thomas Gleixner, linux-arm-kernel, Greg Kroah-Hartman

On 23/05/14 16:00, Russell King - ARM Linux wrote:
> On Fri, May 23, 2014 at 02:57:49PM +0100, Daniel Thompson wrote:
>> +void eoi_fiq(int fiq)
>> +{
>> +	struct irq_data *irq_data = irq_get_irq_data(fiq + fiq_start);
>> +	struct irq_chip *chip = irq_data_get_irq_chip(irq_data);
>> +
>> +	if (chip->irq_eoi)
>> +			chip->irq_eoi(irq_data);
>> +}
> 
> So what if the IRQ chip takes a spinlock?  You can't take spinlocks in
> FIQ context...  Who checks for that kind of stuff - just hoping that
> the IRQ driver doesn't take a spinlock sounds real fragile.

I'll certainly do a better code review before pushing on. I certainly
did overlook a spinlock in the GIC code which (I think) is actually
reachable on a Tegra platform. I'll have to do something about that.

I've spent a bit of time this week seeing whether lock dep can be
provoked into triggering if it sees a spin lock in this code but that
isn't turning out very well (it needs CONFIG_LOCKDEP_DEBUG, relies on
lockdep believing the FIQ handling state isn't a hardirq and still
doesn't work properly).

Fortunately architectures using EOI appear to be pretty rare (I count
five in drivers/irqchip/ and three in arch/arm/) so traditional code
review and yelling might be sufficient.


Daniel.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v2 01/10] arm: fiq: Allow EOI to be communicated to the intc
@ 2014-05-28 15:47         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-28 15:47 UTC (permalink / raw)
  To: linux-arm-kernel

On 23/05/14 16:00, Russell King - ARM Linux wrote:
> On Fri, May 23, 2014 at 02:57:49PM +0100, Daniel Thompson wrote:
>> +void eoi_fiq(int fiq)
>> +{
>> +	struct irq_data *irq_data = irq_get_irq_data(fiq + fiq_start);
>> +	struct irq_chip *chip = irq_data_get_irq_chip(irq_data);
>> +
>> +	if (chip->irq_eoi)
>> +			chip->irq_eoi(irq_data);
>> +}
> 
> So what if the IRQ chip takes a spinlock?  You can't take spinlocks in
> FIQ context...  Who checks for that kind of stuff - just hoping that
> the IRQ driver doesn't take a spinlock sounds real fragile.

I'll certainly do a better code review before pushing on. I certainly
did overlook a spinlock in the GIC code which (I think) is actually
reachable on a Tegra platform. I'll have to do something about that.

I've spent a bit of time this week seeing whether lock dep can be
provoked into triggering if it sees a spin lock in this code but that
isn't turning out very well (it needs CONFIG_LOCKDEP_DEBUG, relies on
lockdep believing the FIQ handling state isn't a hardirq and still
doesn't work properly).

Fortunately architectures using EOI appear to be pretty rare (I count
five in drivers/irqchip/ and three in arch/arm/) so traditional code
review and yelling might be sufficient.


Daniel.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [RFC v2 04/10] ARM: vexpress: Extend UART with FIQ support
  2014-05-23 15:04       ` Russell King - ARM Linux
@ 2014-05-29 10:31         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-29 10:31 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Mark Rutland, kernel, Catalin Marinas, Linus Walleij, Jiri Slaby,
	Dirk Behme, Nicolas Pitre, patches, Anton Vorontsov, Kumar Gala,
	David A. Long, linux-serial, kgdb-bugreport, kernel-team,
	devicetree, linaro-kernel, Pawel Moll, Ian Campbell,
	Jason Wessel, Rob Herring, John Stultz, Thomas Gleixner,
	linux-arm-kernel, Greg Kroah-Hartman, linux-kernel

On 23/05/14 16:04, Russell King - ARM Linux wrote:
> On Fri, May 23, 2014 at 02:57:52PM +0100, Daniel Thompson wrote:
>> @@ -140,7 +140,7 @@
>>  			v2m_serial0: uart@090000 {
>>  				compatible = "arm,pl011", "arm,primecell";
>>  				reg = <0x090000 0x1000>;
>> -				interrupts = <5>;
>> +				interrupts = <5>, <69>;
> 
> NAK.  This is obviously a Linux implementation detail - the second
> number is your "FIQ" number which you've decided will be offset by
> 64.

Certainly the offset of 64 is a more or less meaningless magic number
that I decided on, however I don't think it originates within Linux. It
is both introduced and consumed within the device tree itself.

I've proposed adding a flag to the gic bindings to mark a FIQ; the GIC
calls interrupt 69 (above) <0 5 0x84> (where 0x80 is the flag to request
FIQ routing alongside 0x04 which is the trigger type).

However vexpress-a15 has an interrupt-map between the UART and the GIC.
Thus far I've not found a way, other by offset, to allow a UART sitting
on a child bus to be provided with both IRQ and FIQ versions of an
interrupt.

> --- a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
> +++ b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
> @@ -233,7 +233,7 @@
>  			 <5 0 0 0x10000000 0x04000000>;
>  
>  		#interrupt-cells = <1>;
> -		interrupt-map-mask = <0 0 63>;
> +		interrupt-map-mask = <0 0 127>;
                                         ^^^^^

The 64 offset is introduced here. Nothing in Linux imposes anything on
the value (I originally had the shadow routings from 59 to 63 and this
also worked).

My code may still be inappropriate but, right now, I'm unsure whether
the proposed changes to the gic bindings are included in the NAK, not in
the NAK or whether they sit in the middle ground where I have to provide
better argumentation.


Daniel.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v2 04/10] ARM: vexpress: Extend UART with FIQ support
@ 2014-05-29 10:31         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-05-29 10:31 UTC (permalink / raw)
  To: linux-arm-kernel

On 23/05/14 16:04, Russell King - ARM Linux wrote:
> On Fri, May 23, 2014 at 02:57:52PM +0100, Daniel Thompson wrote:
>> @@ -140,7 +140,7 @@
>>  			v2m_serial0: uart at 090000 {
>>  				compatible = "arm,pl011", "arm,primecell";
>>  				reg = <0x090000 0x1000>;
>> -				interrupts = <5>;
>> +				interrupts = <5>, <69>;
> 
> NAK.  This is obviously a Linux implementation detail - the second
> number is your "FIQ" number which you've decided will be offset by
> 64.

Certainly the offset of 64 is a more or less meaningless magic number
that I decided on, however I don't think it originates within Linux. It
is both introduced and consumed within the device tree itself.

I've proposed adding a flag to the gic bindings to mark a FIQ; the GIC
calls interrupt 69 (above) <0 5 0x84> (where 0x80 is the flag to request
FIQ routing alongside 0x04 which is the trigger type).

However vexpress-a15 has an interrupt-map between the UART and the GIC.
Thus far I've not found a way, other by offset, to allow a UART sitting
on a child bus to be provided with both IRQ and FIQ versions of an
interrupt.

> --- a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
> +++ b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
> @@ -233,7 +233,7 @@
>  			 <5 0 0 0x10000000 0x04000000>;
>  
>  		#interrupt-cells = <1>;
> -		interrupt-map-mask = <0 0 63>;
> +		interrupt-map-mask = <0 0 127>;
                                         ^^^^^

The 64 offset is introduced here. Nothing in Linux imposes anything on
the value (I originally had the shadow routings from 59 to 63 and this
also worked).

My code may still be inappropriate but, right now, I'm unsure whether
the proposed changes to the gic bindings are included in the NAK, not in
the NAK or whether they sit in the middle ground where I have to provide
better argumentation.


Daniel.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [RFC v2 04/10] ARM: vexpress: Extend UART with FIQ support
  2014-05-29 10:31         ` Daniel Thompson
@ 2014-05-29 13:44           ` Rob Herring
  -1 siblings, 0 replies; 535+ messages in thread
From: Rob Herring @ 2014-05-29 13:44 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Dirk Behme, Russell King - ARM Linux, Nicolas Pitre,
	Linaro Patches, Anton Vorontsov, Kumar Gala, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, Ian Campbell, Jason Wessel,
	Rob Herring, John Stultz

On Thu, May 29, 2014 at 5:31 AM, Daniel Thompson
<daniel.thompson@linaro.org> wrote:
> On 23/05/14 16:04, Russell King - ARM Linux wrote:
>> On Fri, May 23, 2014 at 02:57:52PM +0100, Daniel Thompson wrote:
>>> @@ -140,7 +140,7 @@
>>>                      v2m_serial0: uart@090000 {
>>>                              compatible = "arm,pl011", "arm,primecell";
>>>                              reg = <0x090000 0x1000>;
>>> -                            interrupts = <5>;
>>> +                            interrupts = <5>, <69>;
>>
>> NAK.  This is obviously a Linux implementation detail - the second
>> number is your "FIQ" number which you've decided will be offset by
>> 64.

+1

> Certainly the offset of 64 is a more or less meaningless magic number
> that I decided on, however I don't think it originates within Linux. It
> is both introduced and consumed within the device tree itself.
>
> I've proposed adding a flag to the gic bindings to mark a FIQ; the GIC
> calls interrupt 69 (above) <0 5 0x84> (where 0x80 is the flag to request
> FIQ routing alongside 0x04 which is the trigger type).

That would be better than the magic number, but I'm not convinced that
belongs in the DT either.

Whether the uart uses FIQ is not dependent on this DT setting, but
based on whether the user wants to use the uart for kdb or not. You
have enough information already to figure out which interrupt. What's
missing is whether you have the capability to use FIQ or not. I don't
recall if you can tell that from the GIC or not.

Rob

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v2 04/10] ARM: vexpress: Extend UART with FIQ support
@ 2014-05-29 13:44           ` Rob Herring
  0 siblings, 0 replies; 535+ messages in thread
From: Rob Herring @ 2014-05-29 13:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 29, 2014 at 5:31 AM, Daniel Thompson
<daniel.thompson@linaro.org> wrote:
> On 23/05/14 16:04, Russell King - ARM Linux wrote:
>> On Fri, May 23, 2014 at 02:57:52PM +0100, Daniel Thompson wrote:
>>> @@ -140,7 +140,7 @@
>>>                      v2m_serial0: uart at 090000 {
>>>                              compatible = "arm,pl011", "arm,primecell";
>>>                              reg = <0x090000 0x1000>;
>>> -                            interrupts = <5>;
>>> +                            interrupts = <5>, <69>;
>>
>> NAK.  This is obviously a Linux implementation detail - the second
>> number is your "FIQ" number which you've decided will be offset by
>> 64.

+1

> Certainly the offset of 64 is a more or less meaningless magic number
> that I decided on, however I don't think it originates within Linux. It
> is both introduced and consumed within the device tree itself.
>
> I've proposed adding a flag to the gic bindings to mark a FIQ; the GIC
> calls interrupt 69 (above) <0 5 0x84> (where 0x80 is the flag to request
> FIQ routing alongside 0x04 which is the trigger type).

That would be better than the magic number, but I'm not convinced that
belongs in the DT either.

Whether the uart uses FIQ is not dependent on this DT setting, but
based on whether the user wants to use the uart for kdb or not. You
have enough information already to figure out which interrupt. What's
missing is whether you have the capability to use FIQ or not. I don't
recall if you can tell that from the GIC or not.

Rob

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [RFC v2 04/10] ARM: vexpress: Extend UART with FIQ support
  2014-05-29 13:44           ` Rob Herring
@ 2014-06-03 12:41             ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-03 12:41 UTC (permalink / raw)
  To: Rob Herring
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Dirk Behme, Russell King - ARM Linux, Nicolas Pitre,
	Linaro Patches, Anton Vorontsov, Kumar Gala, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, Ian Campbell, Jason Wessel,
	Rob Herring, John Stultz

On 29/05/14 14:44, Rob Herring wrote:
> On Thu, May 29, 2014 at 5:31 AM, Daniel Thompson
> <daniel.thompson@linaro.org> wrote:
>> On 23/05/14 16:04, Russell King - ARM Linux wrote:
>>> On Fri, May 23, 2014 at 02:57:52PM +0100, Daniel Thompson wrote:
>>>> @@ -140,7 +140,7 @@
>>>>                      v2m_serial0: uart@090000 {
>>>>                              compatible = "arm,pl011", "arm,primecell";
>>>>                              reg = <0x090000 0x1000>;
>>>> -                            interrupts = <5>;
>>>> +                            interrupts = <5>, <69>;
>>>
>>> NAK.  This is obviously a Linux implementation detail - the second
>>> number is your "FIQ" number which you've decided will be offset by
>>> 64.
> 
> +1
> 
>> Certainly the offset of 64 is a more or less meaningless magic number
>> that I decided on, however I don't think it originates within Linux. It
>> is both introduced and consumed within the device tree itself.
>>
>> I've proposed adding a flag to the gic bindings to mark a FIQ; the GIC
>> calls interrupt 69 (above) <0 5 0x84> (where 0x80 is the flag to request
>> FIQ routing alongside 0x04 which is the trigger type).
> 
> That would be better than the magic number, but I'm not convinced that
> belongs in the DT either.
> 
> Whether the uart uses FIQ is not dependent on this DT setting, but
> based on whether the user wants to use the uart for kdb or not. You
> have enough information already to figure out which interrupt. What's
> missing is whether you have the capability to use FIQ or not. I don't
> recall if you can tell that from the GIC or not.

Ok.

I've just started playing with an idea that keeps the shadow virqw for
FIQ idea but doesn't require any device tree changes...

Another RFC will follow in due course.


Daniel.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v2 04/10] ARM: vexpress: Extend UART with FIQ support
@ 2014-06-03 12:41             ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-03 12:41 UTC (permalink / raw)
  To: linux-arm-kernel

On 29/05/14 14:44, Rob Herring wrote:
> On Thu, May 29, 2014 at 5:31 AM, Daniel Thompson
> <daniel.thompson@linaro.org> wrote:
>> On 23/05/14 16:04, Russell King - ARM Linux wrote:
>>> On Fri, May 23, 2014 at 02:57:52PM +0100, Daniel Thompson wrote:
>>>> @@ -140,7 +140,7 @@
>>>>                      v2m_serial0: uart at 090000 {
>>>>                              compatible = "arm,pl011", "arm,primecell";
>>>>                              reg = <0x090000 0x1000>;
>>>> -                            interrupts = <5>;
>>>> +                            interrupts = <5>, <69>;
>>>
>>> NAK.  This is obviously a Linux implementation detail - the second
>>> number is your "FIQ" number which you've decided will be offset by
>>> 64.
> 
> +1
> 
>> Certainly the offset of 64 is a more or less meaningless magic number
>> that I decided on, however I don't think it originates within Linux. It
>> is both introduced and consumed within the device tree itself.
>>
>> I've proposed adding a flag to the gic bindings to mark a FIQ; the GIC
>> calls interrupt 69 (above) <0 5 0x84> (where 0x80 is the flag to request
>> FIQ routing alongside 0x04 which is the trigger type).
> 
> That would be better than the magic number, but I'm not convinced that
> belongs in the DT either.
> 
> Whether the uart uses FIQ is not dependent on this DT setting, but
> based on whether the user wants to use the uart for kdb or not. You
> have enough information already to figure out which interrupt. What's
> missing is whether you have the capability to use FIQ or not. I don't
> recall if you can tell that from the GIC or not.

Ok.

I've just started playing with an idea that keeps the shadow virqw for
FIQ idea but doesn't require any device tree changes...

Another RFC will follow in due course.


Daniel.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v3 0/9] kgdb: NMI/FIQ support for ARM
  2014-05-23 13:57   ` Daniel Thompson
@ 2014-06-05  9:53     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Ian Campbell, Anton Vorontsov, David A. Long, linux-serial,
	Catalin Marinas, kernel-team, devicetree, linaro-kernel,
	Pawel Moll, patches, Kumar Gala, Rob Herring, John Stultz,
	Thomas Gleixner, linux-arm-kernel, Greg Kroah-Hartman

This patchset makes it possible to use the kgdb NMI infrastructure on
ARM platforms by providing a mutli-platform compatible means for drivers
to manage FIQ routings.

First a quick summary of how the mainline kgdb NMI infrastructure
(mostly found in drivers/tty/serial/kgdb_nmi.c) works. The kgdb
infrastructure will re-route the kgdb console UART's interrupt signal
from IRQ to FIQ. Naturally the UART will no longer function normally and
will instead be managed by kgdb using the polled I/O functions. Any
character delivered to the UART causes the kgdb handler function to be
called.

Note that, within this patchset a serial driver explicitly consents (or
not) to the abuse outlined above by calling the appropriate registration
during the .poll_init() callback.

The patch set is structured as follows:

  The first five patches modify the interrupt system to make it easier
  to describe FIQ. The key concept is that a call to enable_fiq() must
  modify the IRQ/FIQ routing to that the FIQ really is enabled (rather
  than spuriously delivering the signal on the IRQ). To achieve this
  each interrupt controller registers two virqs for each hwirq (allowing
  IRQ and FIQ to be readily distinguished) and registers the mappings
  using a new call, fiq_add_mapping().
  
  The next two patches (6 and 7) provide kgdb with a FIQ handler and
  a means for serial drivers to register their FIQ with kgdb.

  Finally two example serial drivers are modified in order to register
  their FIQs with kgdb.

Major remaining TODO item is to modify the code to halt the other CPUs;
at present this code sends IPIs (which use a normal IRQ) and busy waits
for the other CPUs to halt. This means the benefits of invoking the
debugger via NMI are not yet realized on SMP systems. However I plan
to tackle that later (i.e.  when there's some consensus on whether this
approach is the right way to handle FIQ).

Changes since v2:

* Use flexible mappings to link a normal virq to a FIQ virq. This
  replaces the device tree proposals from the previous RFC
  (thanks Russell King and Rob Herring).

* Reviewed all use of spin locks within .irq_eoi callbacks (and fixed
  the issue identified). Added comments to the FIQ registration
  functions making clear the requirements imposed on interrupt
  controller that call the FIQ API (thanks Russell King).

* Fixed a few whitespace issues (thanks Srinivas Kandagatla)

* ARM64/defconfig build tests (no problems found)

Changes since v1:

* Fully fledged multi-platform

* Tested for correct FIQ operation on STiH416/B2020 (Cortex A9),
  qemu/versatile and qemu/vexpress-a15 (with self-written mods to the
  GIC model to support FIQ).

* Regression tested (and resulting bugs fixed) on qemu/versatile+DT and
  qemu/integreatorcp.

Anton Vorontsov (2):
  ARM: Move some macros from entry-armv to entry-header
  ARM: Add KGDB/KDB FIQ debugger generic code

Daniel Thompson (7):
  arm: fiq: arbitrary mappings from IRQ to FIQ virqs
  arm: fiq: Allow EOI to be communicated to the intc
  irqchip: gic: Provide support for interrupt grouping
  irqchip: gic: Introduce shadow irqs for FIQ
  irqchip: vic: Introduce shadow irqs for FIQ
  serial: amba-pl011: Pass on FIQ information to KGDB.
  serial: asc: Add support for KGDB's FIQ/NMI mode

 arch/arm/Kconfig                            |   2 +
 arch/arm/Kconfig.debug                      |  18 +++
 arch/arm/include/asm/fiq.h                  |   4 +
 arch/arm/include/asm/kgdb.h                 |   7 ++
 arch/arm/kernel/Makefile                    |   1 +
 arch/arm/kernel/entry-armv.S                | 151 +------------------------
 arch/arm/kernel/entry-header.S              | 164 ++++++++++++++++++++++++++++
 arch/arm/kernel/fiq.c                       |  85 +++++++++++++-
 arch/arm/kernel/kgdb_fiq.c                  | 124 +++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S            |  87 +++++++++++++++
 arch/arm/mach-ep93xx/core.c                 |   6 +-
 arch/arm/mach-netx/generic.c                |   3 +-
 arch/arm/mach-s3c64xx/common.c              |   6 +-
 arch/arm/mach-versatile/core.c              |   9 +-
 arch/arm/mach-versatile/include/mach/irqs.h |   5 +-
 arch/arm/plat-samsung/s5p-irq.c             |   3 +-
 drivers/irqchip/irq-gic.c                   |  97 ++++++++++++++--
 drivers/irqchip/irq-vic.c                   | 102 ++++++++++++++---
 drivers/tty/serial/amba-pl011.c             |  99 ++++++++++-------
 drivers/tty/serial/st-asc.c                 |  23 ++++
 include/linux/irqchip/arm-gic.h             |   3 +
 include/linux/irqchip/arm-vic.h             |   8 +-
 22 files changed, 770 insertions(+), 237 deletions(-)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

-- 
1.9.0

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v3 0/9] kgdb: NMI/FIQ support for ARM
@ 2014-06-05  9:53     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset makes it possible to use the kgdb NMI infrastructure on
ARM platforms by providing a mutli-platform compatible means for drivers
to manage FIQ routings.

First a quick summary of how the mainline kgdb NMI infrastructure
(mostly found in drivers/tty/serial/kgdb_nmi.c) works. The kgdb
infrastructure will re-route the kgdb console UART's interrupt signal
from IRQ to FIQ. Naturally the UART will no longer function normally and
will instead be managed by kgdb using the polled I/O functions. Any
character delivered to the UART causes the kgdb handler function to be
called.

Note that, within this patchset a serial driver explicitly consents (or
not) to the abuse outlined above by calling the appropriate registration
during the .poll_init() callback.

The patch set is structured as follows:

  The first five patches modify the interrupt system to make it easier
  to describe FIQ. The key concept is that a call to enable_fiq() must
  modify the IRQ/FIQ routing to that the FIQ really is enabled (rather
  than spuriously delivering the signal on the IRQ). To achieve this
  each interrupt controller registers two virqs for each hwirq (allowing
  IRQ and FIQ to be readily distinguished) and registers the mappings
  using a new call, fiq_add_mapping().
  
  The next two patches (6 and 7) provide kgdb with a FIQ handler and
  a means for serial drivers to register their FIQ with kgdb.

  Finally two example serial drivers are modified in order to register
  their FIQs with kgdb.

Major remaining TODO item is to modify the code to halt the other CPUs;
at present this code sends IPIs (which use a normal IRQ) and busy waits
for the other CPUs to halt. This means the benefits of invoking the
debugger via NMI are not yet realized on SMP systems. However I plan
to tackle that later (i.e.  when there's some consensus on whether this
approach is the right way to handle FIQ).

Changes since v2:

* Use flexible mappings to link a normal virq to a FIQ virq. This
  replaces the device tree proposals from the previous RFC
  (thanks Russell King and Rob Herring).

* Reviewed all use of spin locks within .irq_eoi callbacks (and fixed
  the issue identified). Added comments to the FIQ registration
  functions making clear the requirements imposed on interrupt
  controller that call the FIQ API (thanks Russell King).

* Fixed a few whitespace issues (thanks Srinivas Kandagatla)

* ARM64/defconfig build tests (no problems found)

Changes since v1:

* Fully fledged multi-platform

* Tested for correct FIQ operation on STiH416/B2020 (Cortex A9),
  qemu/versatile and qemu/vexpress-a15 (with self-written mods to the
  GIC model to support FIQ).

* Regression tested (and resulting bugs fixed) on qemu/versatile+DT and
  qemu/integreatorcp.

Anton Vorontsov (2):
  ARM: Move some macros from entry-armv to entry-header
  ARM: Add KGDB/KDB FIQ debugger generic code

Daniel Thompson (7):
  arm: fiq: arbitrary mappings from IRQ to FIQ virqs
  arm: fiq: Allow EOI to be communicated to the intc
  irqchip: gic: Provide support for interrupt grouping
  irqchip: gic: Introduce shadow irqs for FIQ
  irqchip: vic: Introduce shadow irqs for FIQ
  serial: amba-pl011: Pass on FIQ information to KGDB.
  serial: asc: Add support for KGDB's FIQ/NMI mode

 arch/arm/Kconfig                            |   2 +
 arch/arm/Kconfig.debug                      |  18 +++
 arch/arm/include/asm/fiq.h                  |   4 +
 arch/arm/include/asm/kgdb.h                 |   7 ++
 arch/arm/kernel/Makefile                    |   1 +
 arch/arm/kernel/entry-armv.S                | 151 +------------------------
 arch/arm/kernel/entry-header.S              | 164 ++++++++++++++++++++++++++++
 arch/arm/kernel/fiq.c                       |  85 +++++++++++++-
 arch/arm/kernel/kgdb_fiq.c                  | 124 +++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S            |  87 +++++++++++++++
 arch/arm/mach-ep93xx/core.c                 |   6 +-
 arch/arm/mach-netx/generic.c                |   3 +-
 arch/arm/mach-s3c64xx/common.c              |   6 +-
 arch/arm/mach-versatile/core.c              |   9 +-
 arch/arm/mach-versatile/include/mach/irqs.h |   5 +-
 arch/arm/plat-samsung/s5p-irq.c             |   3 +-
 drivers/irqchip/irq-gic.c                   |  97 ++++++++++++++--
 drivers/irqchip/irq-vic.c                   | 102 ++++++++++++++---
 drivers/tty/serial/amba-pl011.c             |  99 ++++++++++-------
 drivers/tty/serial/st-asc.c                 |  23 ++++
 include/linux/irqchip/arm-gic.h             |   3 +
 include/linux/irqchip/arm-vic.h             |   8 +-
 22 files changed, 770 insertions(+), 237 deletions(-)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

-- 
1.9.0

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v3 1/9] arm: fiq: arbitrary mappings from IRQ to FIQ virqs
  2014-06-05  9:53     ` Daniel Thompson
@ 2014-06-05  9:53       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Fabio Estevam, Ian Campbell, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, patches, Kumar Gala, Rob Herring,
	John Stultz, Thomas Gleixner, linux-arm-kernel

Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
virq into a FIQ virq. This is too inflexible for multi-platform kernels
and makes runtime error checking impossible.

We solve this by introducing a flexible mapping that allows interrupt
controllers that support FIQ to register those mappings. This, in turn,
makes it much possible for drivers in DT kernels to gain access to
FIQ virqs.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/include/asm/fiq.h |  2 ++
 arch/arm/kernel/fiq.c      | 57 +++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..75d98c6 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -36,8 +36,10 @@ struct fiq_handler {
 extern int claim_fiq(struct fiq_handler *f);
 extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
+extern struct irq_data *lookup_fiq_irq_data(int fiq);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern void fiq_add_mapping(int irq, int fiq_virq, unsigned int length);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..177939c 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,8 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
+#include <linux/radix-tree.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -53,6 +55,9 @@
 	})
 
 static unsigned long no_fiq_insn;
+static int fiq_start = -1;
+static RADIX_TREE(fiq_virq_tree, GFP_KERNEL);
+static DEFINE_MUTEX(fiq_virq_mutex);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -60,8 +65,11 @@ static unsigned long no_fiq_insn;
  */
 static int fiq_def_op(void *ref, int relinquish)
 {
-	if (!relinquish)
+	if (!relinquish) {
+		unsigned offset = FIQ_OFFSET;
+		no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
 		set_fiq_handler(&no_fiq_insn, sizeof(no_fiq_insn));
+	}
 
 	return 0;
 }
@@ -127,16 +135,33 @@ void release_fiq(struct fiq_handler *f)
 	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
 }
 
-static int fiq_start;
+struct irq_data *lookup_fiq_irq_data(int fiq)
+{
+	struct irq_data *d;
+
+	if (fiq_start != -1)
+		return irq_get_irq_data(fiq + fiq_start);
+
+	rcu_read_lock();
+	d = radix_tree_lookup(&fiq_virq_tree, fiq);
+	rcu_read_unlock();
+	return d;
+}
 
 void enable_fiq(int fiq)
 {
-	enable_irq(fiq + fiq_start);
+	struct irq_data *d = lookup_fiq_irq_data(fiq);
+	if (WARN_ON(!d))
+		return;
+	enable_irq(d->irq);
 }
 
 void disable_fiq(int fiq)
 {
-	disable_irq(fiq + fiq_start);
+	struct irq_data *d = lookup_fiq_irq_data(fiq);
+	if (WARN_ON(!d))
+		return;
+	disable_irq(d->irq);
 }
 
 EXPORT_SYMBOL(set_fiq_handler);
@@ -144,12 +169,32 @@ EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(claim_fiq);
 EXPORT_SYMBOL(release_fiq);
+EXPORT_SYMBOL(lookup_fiq_irq_data);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
 
+/*
+ * Add a mapping between a normal IRQ and a FIQ shadow.
+ */
+void fiq_add_mapping(int irq, int fiq_virq, unsigned int length)
+{
+	int i;
+
+	/* fiq_add_mapping can't be mixed with init_FIQ */
+	BUG_ON(fiq_start != -1);
+
+	mutex_lock(&fiq_virq_mutex);
+	for (i = 0; i < length; i++) {
+		int err = radix_tree_insert(&fiq_virq_tree, irq + i,
+					    irq_get_irq_data(fiq_virq + i));
+		if (err)
+			pr_err("fiq: Cannot map %d to %d\n", irq + i,
+			       fiq_virq + i);
+	}
+	mutex_unlock(&fiq_virq_mutex);
+}
+
 void __init init_FIQ(int start)
 {
-	unsigned offset = FIQ_OFFSET;
-	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
 	fiq_start = start;
 }
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v3 1/9] arm: fiq: arbitrary mappings from IRQ to FIQ virqs
@ 2014-06-05  9:53       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: linux-arm-kernel

Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
virq into a FIQ virq. This is too inflexible for multi-platform kernels
and makes runtime error checking impossible.

We solve this by introducing a flexible mapping that allows interrupt
controllers that support FIQ to register those mappings. This, in turn,
makes it much possible for drivers in DT kernels to gain access to
FIQ virqs.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/include/asm/fiq.h |  2 ++
 arch/arm/kernel/fiq.c      | 57 +++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..75d98c6 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -36,8 +36,10 @@ struct fiq_handler {
 extern int claim_fiq(struct fiq_handler *f);
 extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
+extern struct irq_data *lookup_fiq_irq_data(int fiq);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern void fiq_add_mapping(int irq, int fiq_virq, unsigned int length);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..177939c 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,8 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
+#include <linux/radix-tree.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -53,6 +55,9 @@
 	})
 
 static unsigned long no_fiq_insn;
+static int fiq_start = -1;
+static RADIX_TREE(fiq_virq_tree, GFP_KERNEL);
+static DEFINE_MUTEX(fiq_virq_mutex);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -60,8 +65,11 @@ static unsigned long no_fiq_insn;
  */
 static int fiq_def_op(void *ref, int relinquish)
 {
-	if (!relinquish)
+	if (!relinquish) {
+		unsigned offset = FIQ_OFFSET;
+		no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
 		set_fiq_handler(&no_fiq_insn, sizeof(no_fiq_insn));
+	}
 
 	return 0;
 }
@@ -127,16 +135,33 @@ void release_fiq(struct fiq_handler *f)
 	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
 }
 
-static int fiq_start;
+struct irq_data *lookup_fiq_irq_data(int fiq)
+{
+	struct irq_data *d;
+
+	if (fiq_start != -1)
+		return irq_get_irq_data(fiq + fiq_start);
+
+	rcu_read_lock();
+	d = radix_tree_lookup(&fiq_virq_tree, fiq);
+	rcu_read_unlock();
+	return d;
+}
 
 void enable_fiq(int fiq)
 {
-	enable_irq(fiq + fiq_start);
+	struct irq_data *d = lookup_fiq_irq_data(fiq);
+	if (WARN_ON(!d))
+		return;
+	enable_irq(d->irq);
 }
 
 void disable_fiq(int fiq)
 {
-	disable_irq(fiq + fiq_start);
+	struct irq_data *d = lookup_fiq_irq_data(fiq);
+	if (WARN_ON(!d))
+		return;
+	disable_irq(d->irq);
 }
 
 EXPORT_SYMBOL(set_fiq_handler);
@@ -144,12 +169,32 @@ EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(claim_fiq);
 EXPORT_SYMBOL(release_fiq);
+EXPORT_SYMBOL(lookup_fiq_irq_data);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
 
+/*
+ * Add a mapping between a normal IRQ and a FIQ shadow.
+ */
+void fiq_add_mapping(int irq, int fiq_virq, unsigned int length)
+{
+	int i;
+
+	/* fiq_add_mapping can't be mixed with init_FIQ */
+	BUG_ON(fiq_start != -1);
+
+	mutex_lock(&fiq_virq_mutex);
+	for (i = 0; i < length; i++) {
+		int err = radix_tree_insert(&fiq_virq_tree, irq + i,
+					    irq_get_irq_data(fiq_virq + i));
+		if (err)
+			pr_err("fiq: Cannot map %d to %d\n", irq + i,
+			       fiq_virq + i);
+	}
+	mutex_unlock(&fiq_virq_mutex);
+}
+
 void __init init_FIQ(int start)
 {
-	unsigned offset = FIQ_OFFSET;
-	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
 	fiq_start = start;
 }
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v3 2/9] arm: fiq: Allow EOI to be communicated to the intc
  2014-06-05  9:53     ` Daniel Thompson
@ 2014-06-05  9:53       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Fabio Estevam, Ian Campbell, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, patches, Kumar Gala, Rob Herring,
	John Stultz, Thomas Gleixner, linux-arm-kernel

Modern ARM systems require an EOI to be sent to the interrupt controller
on completion of both IRQ and FIQ. The FIQ code currently does not provide
any API to perform this. This patch provides this API, implemented by
hooking into main irq driver in a similar way to the existing
enable_fiq()/disable_fiq().

All existing in-kernel callers of init_FIQ() and fiq_add_mapping() have
been reviewed to check they meet the documented restriction.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/include/asm/fiq.h |  2 ++
 arch/arm/kernel/fiq.c      | 28 ++++++++++++++++++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index 75d98c6..10d22eb 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -39,6 +39,8 @@ extern void set_fiq_handler(void *start, unsigned int length);
 extern struct irq_data *lookup_fiq_irq_data(int fiq);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern void eoi_fiq_with_irq_data(struct irq_data *d);
+extern void eoi_fiq(int fiq);
 extern void fiq_add_mapping(int irq, int fiq_virq, unsigned int length);
 
 /* helpers defined in fiqasm.S: */
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 177939c..ed01162 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -164,6 +164,25 @@ void disable_fiq(int fiq)
 	disable_irq(d->irq);
 }
 
+/* This call ends a FIQ and does not perform radix tree lookups. Use this
+ * if the FIQ interrupt rate is expected to be extremely high.
+ */
+void eoi_fiq_with_irq_data(struct irq_data *irq_data)
+{
+	struct irq_chip *chip = irq_data_get_irq_chip(irq_data);
+	if (chip->irq_eoi)
+		chip->irq_eoi(irq_data);
+}
+EXPORT_SYMBOL(eoi_fiq_with_irq_data);
+
+void eoi_fiq(int fiq)
+{
+	struct irq_data *d = lookup_fiq_irq_data(fiq);
+	BUG_ON(!d);
+	eoi_fiq_with_irq_data(d);
+}
+EXPORT_SYMBOL(eoi_fiq);
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -175,6 +194,9 @@ EXPORT_SYMBOL(disable_fiq);
 
 /*
  * Add a mapping between a normal IRQ and a FIQ shadow.
+ *
+ * By providing a mapping the interrupt controller is guaranteeing not
+ * to use spin locks from .irq_eoi
  */
 void fiq_add_mapping(int irq, int fiq_virq, unsigned int length)
 {
@@ -194,6 +216,12 @@ void fiq_add_mapping(int irq, int fiq_virq, unsigned int length)
 	mutex_unlock(&fiq_virq_mutex);
 }
 
+/*
+ * Set the offset between normal IRQs and their FIQ shadows.
+ *
+ * By providing an offset the interrupt controller is guaranteeing not
+ * to use spin locks from .irq_eoi
+ */
 void __init init_FIQ(int start)
 {
 	fiq_start = start;
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v3 2/9] arm: fiq: Allow EOI to be communicated to the intc
@ 2014-06-05  9:53       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: linux-arm-kernel

Modern ARM systems require an EOI to be sent to the interrupt controller
on completion of both IRQ and FIQ. The FIQ code currently does not provide
any API to perform this. This patch provides this API, implemented by
hooking into main irq driver in a similar way to the existing
enable_fiq()/disable_fiq().

All existing in-kernel callers of init_FIQ() and fiq_add_mapping() have
been reviewed to check they meet the documented restriction.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/include/asm/fiq.h |  2 ++
 arch/arm/kernel/fiq.c      | 28 ++++++++++++++++++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index 75d98c6..10d22eb 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -39,6 +39,8 @@ extern void set_fiq_handler(void *start, unsigned int length);
 extern struct irq_data *lookup_fiq_irq_data(int fiq);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern void eoi_fiq_with_irq_data(struct irq_data *d);
+extern void eoi_fiq(int fiq);
 extern void fiq_add_mapping(int irq, int fiq_virq, unsigned int length);
 
 /* helpers defined in fiqasm.S: */
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 177939c..ed01162 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -164,6 +164,25 @@ void disable_fiq(int fiq)
 	disable_irq(d->irq);
 }
 
+/* This call ends a FIQ and does not perform radix tree lookups. Use this
+ * if the FIQ interrupt rate is expected to be extremely high.
+ */
+void eoi_fiq_with_irq_data(struct irq_data *irq_data)
+{
+	struct irq_chip *chip = irq_data_get_irq_chip(irq_data);
+	if (chip->irq_eoi)
+		chip->irq_eoi(irq_data);
+}
+EXPORT_SYMBOL(eoi_fiq_with_irq_data);
+
+void eoi_fiq(int fiq)
+{
+	struct irq_data *d = lookup_fiq_irq_data(fiq);
+	BUG_ON(!d);
+	eoi_fiq_with_irq_data(d);
+}
+EXPORT_SYMBOL(eoi_fiq);
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -175,6 +194,9 @@ EXPORT_SYMBOL(disable_fiq);
 
 /*
  * Add a mapping between a normal IRQ and a FIQ shadow.
+ *
+ * By providing a mapping the interrupt controller is guaranteeing not
+ * to use spin locks from .irq_eoi
  */
 void fiq_add_mapping(int irq, int fiq_virq, unsigned int length)
 {
@@ -194,6 +216,12 @@ void fiq_add_mapping(int irq, int fiq_virq, unsigned int length)
 	mutex_unlock(&fiq_virq_mutex);
 }
 
+/*
+ * Set the offset between normal IRQs and their FIQ shadows.
+ *
+ * By providing an offset the interrupt controller is guaranteeing not
+ * to use spin locks from .irq_eoi
+ */
 void __init init_FIQ(int start)
 {
 	fiq_start = start;
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v3 3/9] irqchip: gic: Provide support for interrupt grouping
  2014-06-05  9:53     ` Daniel Thompson
@ 2014-06-05  9:53       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, Nicolas Pitre, kernel, kgdb-bugreport,
	Linus Walleij, Sricharan R, Jiri Slaby, Daniel Thompson,
	Dirk Behme, Russell King, Nicolas Pitre, Ian Campbell,
	Anton Vorontsov, David A. Long, linux-serial, Catalin Marinas,
	kernel-team, devicetree, linaro-kernel, Jason Cooper, Pawel Moll,
	patches, Kumar Gala, Rob Herring, John Stultz

All GIC hardware except GICv1 without TrustZone support provides a means
to group exceptions into group 0 (which can optionally be signally using
use FIQ) and group 1. The kernel currently provides no means to exploit
this. This patch alters the initialization of the GIC to place all
interrupts into group 1, this is a foundational requirement to meaningfully
use FIQ.

Note that the hardware functionality is unavailable to the kernel when a
secure monitor is present because access to the grouping registers are
prohibited outside "secure world". This allows grouping to be used to
allow hardware peripherals to send interrupts into the secure world.

On systems without TrustZone support the kernel has the power to
route interrupt sources to FIQ, potentially allowing a driver to exploit the
NMI-like properties of FIQ.

The registers involved are RAZ/WI when unimplemented or protected by
security policy. This patch therefore applies grouping unconditionally.

Tested on a qemu GICv2 model (self-written from GICv2 spec) and
an STiH416 (ARM Cortex A9, GICv1, TZ).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
Acked-by: Dirk Behme <dirk.behme@de.bosch.com>
---
 drivers/irqchip/irq-gic.c       | 35 ++++++++++++++++++++++++++++++-----
 include/linux/irqchip/arm-gic.h |  3 +++
 2 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 57d165e..aa8efe4 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -408,13 +408,27 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 		writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
 
 	/*
+	 * Set all global interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers a read-as-zero/write-ignored.
+	 */
+	for (i = 32; i < gic_irqs; i += 32)
+		writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
 	 * Disable all interrupts.  Leave the PPI and SGIs alone
 	 * as these enables are banked registers.
 	 */
 	for (i = 32; i < gic_irqs; i += 32)
 		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	writel_relaxed(GIC_DIST_CTRL_ENABLE_GRP0_BIT |
+		       GIC_DIST_CTRL_ENABLE_GRP1_BIT, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -452,8 +466,16 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	for (i = 0; i < 32; i += 4)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
 
+	/*
+	 * Set all PPI and SGI interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers are read-as-zero/write-ignored.
+	 */
+	writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -537,7 +559,9 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	writel_relaxed(GIC_DIST_CTRL_ENABLE_GRP0_BIT |
+			   GIC_DIST_CTRL_ENABLE_GRP1_BIT,
+		       dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -594,7 +618,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -670,7 +694,8 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+	writel_relaxed(map << 16 | irq | 0x8000,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 7ed92d0..919502f 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -37,6 +37,9 @@
 #define GIC_DIST_SGI_PENDING_CLEAR	0xf10
 #define GIC_DIST_SGI_PENDING_SET	0xf20
 
+#define GIC_DIST_CTRL_ENABLE_GRP0_BIT	(1 << 0)
+#define GIC_DIST_CTRL_ENABLE_GRP1_BIT	(1 << 1)
+
 #define GICH_HCR			0x0
 #define GICH_VTR			0x4
 #define GICH_VMCR			0x8
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v3 3/9] irqchip: gic: Provide support for interrupt grouping
@ 2014-06-05  9:53       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: linux-arm-kernel

All GIC hardware except GICv1 without TrustZone support provides a means
to group exceptions into group 0 (which can optionally be signally using
use FIQ) and group 1. The kernel currently provides no means to exploit
this. This patch alters the initialization of the GIC to place all
interrupts into group 1, this is a foundational requirement to meaningfully
use FIQ.

Note that the hardware functionality is unavailable to the kernel when a
secure monitor is present because access to the grouping registers are
prohibited outside "secure world". This allows grouping to be used to
allow hardware peripherals to send interrupts into the secure world.

On systems without TrustZone support the kernel has the power to
route interrupt sources to FIQ, potentially allowing a driver to exploit the
NMI-like properties of FIQ.

The registers involved are RAZ/WI when unimplemented or protected by
security policy. This patch therefore applies grouping unconditionally.

Tested on a qemu GICv2 model (self-written from GICv2 spec) and
an STiH416 (ARM Cortex A9, GICv1, TZ).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
Acked-by: Dirk Behme <dirk.behme@de.bosch.com>
---
 drivers/irqchip/irq-gic.c       | 35 ++++++++++++++++++++++++++++++-----
 include/linux/irqchip/arm-gic.h |  3 +++
 2 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 57d165e..aa8efe4 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -408,13 +408,27 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 		writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
 
 	/*
+	 * Set all global interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers a read-as-zero/write-ignored.
+	 */
+	for (i = 32; i < gic_irqs; i += 32)
+		writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
 	 * Disable all interrupts.  Leave the PPI and SGIs alone
 	 * as these enables are banked registers.
 	 */
 	for (i = 32; i < gic_irqs; i += 32)
 		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	writel_relaxed(GIC_DIST_CTRL_ENABLE_GRP0_BIT |
+		       GIC_DIST_CTRL_ENABLE_GRP1_BIT, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -452,8 +466,16 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	for (i = 0; i < 32; i += 4)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
 
+	/*
+	 * Set all PPI and SGI interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers are read-as-zero/write-ignored.
+	 */
+	writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -537,7 +559,9 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	writel_relaxed(GIC_DIST_CTRL_ENABLE_GRP0_BIT |
+			   GIC_DIST_CTRL_ENABLE_GRP1_BIT,
+		       dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -594,7 +618,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -670,7 +694,8 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+	writel_relaxed(map << 16 | irq | 0x8000,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 7ed92d0..919502f 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -37,6 +37,9 @@
 #define GIC_DIST_SGI_PENDING_CLEAR	0xf10
 #define GIC_DIST_SGI_PENDING_SET	0xf20
 
+#define GIC_DIST_CTRL_ENABLE_GRP0_BIT	(1 << 0)
+#define GIC_DIST_CTRL_ENABLE_GRP1_BIT	(1 << 1)
+
 #define GICH_HCR			0x0
 #define GICH_VTR			0x4
 #define GICH_VMCR			0x8
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v3 4/9] irqchip: gic: Introduce shadow irqs for FIQ
  2014-06-05  9:53     ` Daniel Thompson
@ 2014-06-05  9:53       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, Nicolas Pitre, kernel, kgdb-bugreport,
	Linus Walleij, Sricharan R, Jiri Slaby, Daniel Thompson,
	Dirk Behme, Russell King, Nicolas Pitre, Ian Campbell,
	Anton Vorontsov, David A. Long, linux-serial, Catalin Marinas,
	kernel-team, devicetree, linaro-kernel, Jason Cooper, Pawel Moll,
	patches, Kumar Gala, Rob Herring, John Stultz

This patch registers two virqs for each interrupt source it supports.
Using multiple virqs allows the GIC driver to automatically modify the group
register, allowing the new virqs to be used as argument to enable_fiq().
This also allows FIQ resources to be described in the device tree's
interrupt list using a special flag (currently 0x80).

Both these aspects combine and allow a driver to deploy a FIQ handler
without any machine specific knowledge; it can be used effectively on
multi-arch kernels.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
---
 drivers/irqchip/irq-gic.c | 62 ++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 56 insertions(+), 6 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index aa8efe4..9a4712d 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -42,12 +42,17 @@
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
 
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
 
 #include "irqchip.h"
 
+#define GIC_INTSPEC_IRQ_IS_FIQ (1 << 7)
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -65,6 +70,7 @@ struct gic_chip_data {
 #endif
 	struct irq_domain *domain;
 	unsigned int gic_irqs;
+	unsigned int fiq_shadow_offset;
 #ifdef CONFIG_GIC_NON_BANKED
 	void __iomem *(*get_base)(union gic_base *);
 #endif
@@ -143,11 +149,34 @@ static inline void __iomem *gic_cpu_base(struct irq_data *d)
 	return gic_data_cpu_base(gic_data);
 }
 
+static inline bool gic_is_fiq(struct irq_data *d)
+{
+	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
+	return d->hwirq > gic_data->gic_irqs;
+}
+
 static inline unsigned int gic_irq(struct irq_data *d)
 {
+	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
+	if (gic_is_fiq(d))
+		return d->hwirq - gic_data->fiq_shadow_offset;
 	return d->hwirq;
 }
 
+static void gic_set_group_irq(struct irq_data *d, int group)
+{
+	unsigned int reg = gic_irq(d) / 32 * 4;
+	u32 mask = 1 << (gic_irq(d) % 32);
+	u32 val;
+
+	val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + reg);
+	if (group)
+		val |= mask;
+	else
+		val &= ~mask;
+	writel_relaxed(val, gic_dist_base(d) + GIC_DIST_IGROUP + reg);
+}
+
 /*
  * Routines to acknowledge, disable and enable interrupts
  */
@@ -159,6 +188,8 @@ static void gic_mask_irq(struct irq_data *d)
 	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
 	if (gic_arch_extn.irq_mask)
 		gic_arch_extn.irq_mask(d);
+	if (gic_is_fiq(d))
+		gic_set_group_irq(d, 1);
 	raw_spin_unlock(&irq_controller_lock);
 }
 
@@ -167,6 +198,8 @@ static void gic_unmask_irq(struct irq_data *d)
 	u32 mask = 1 << (gic_irq(d) % 32);
 
 	raw_spin_lock(&irq_controller_lock);
+	if (gic_is_fiq(d))
+		gic_set_group_irq(d, 0);
 	if (gic_arch_extn.irq_unmask)
 		gic_arch_extn.irq_unmask(d);
 	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
@@ -940,7 +973,12 @@ static int gic_routable_irq_domain_xlate(struct irq_domain *d,
 				unsigned long *out_hwirq,
 				unsigned int *out_type)
 {
+	struct gic_chip_data *gic_data = d->host_data;
 	*out_hwirq += 16;
+
+	if (intspec[2] & GIC_INTSPEC_IRQ_IS_FIQ)
+		*out_hwirq += gic_data->fiq_shadow_offset;
+
 	return 0;
 }
 
@@ -1026,10 +1064,11 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 	gic->gic_irqs = gic_irqs;
 
 	gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
+	gic->fiq_shadow_offset = gic_irqs;
 
 	if (of_property_read_u32(node, "arm,routable-irqs",
 				 &nr_routable_irqs)) {
-		irq_base = irq_alloc_descs(irq_start, 16, gic_irqs,
+		irq_base = irq_alloc_descs(irq_start, 16, 2 * gic_irqs,
 					   numa_node_id());
 		if (IS_ERR_VALUE(irq_base)) {
 			WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
@@ -1037,17 +1076,28 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 			irq_base = irq_start;
 		}
 
-		gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
-					hwirq_base, &gic_irq_domain_ops, gic);
+		gic->domain =
+		    irq_domain_add_legacy(node, 2 * gic_irqs, irq_base,
+					  hwirq_base, &gic_irq_domain_ops, gic);
 	} else {
-		gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
-						    &gic_irq_domain_ops,
-						    gic);
+		gic->domain = irq_domain_add_linear(node, 2 * nr_routable_irqs,
+						    &gic_irq_domain_ops, gic);
 	}
 
 	if (WARN_ON(!gic->domain))
 		return;
 
+#ifdef CONFIG_FIQ
+	/* FIQ can only be supported on platforms without an extended irq_eoi
+	 * method (otherwise we take a lock during irq_eoi handling).
+	 */
+	if (!gic_arch_extn.irq_eoi)
+		fiq_add_mapping(
+		    irq_linear_revmap(gic->domain, hwirq_base),
+		    irq_linear_revmap(gic->domain, hwirq_base + gic_irqs),
+		    gic_irqs);
+#endif
+
 	if (gic_nr == 0) {
 #ifdef CONFIG_SMP
 		set_smp_cross_call(gic_raise_softirq);
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v3 4/9] irqchip: gic: Introduce shadow irqs for FIQ
@ 2014-06-05  9:53       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: linux-arm-kernel

This patch registers two virqs for each interrupt source it supports.
Using multiple virqs allows the GIC driver to automatically modify the group
register, allowing the new virqs to be used as argument to enable_fiq().
This also allows FIQ resources to be described in the device tree's
interrupt list using a special flag (currently 0x80).

Both these aspects combine and allow a driver to deploy a FIQ handler
without any machine specific knowledge; it can be used effectively on
multi-arch kernels.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
---
 drivers/irqchip/irq-gic.c | 62 ++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 56 insertions(+), 6 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index aa8efe4..9a4712d 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -42,12 +42,17 @@
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
 
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
 
 #include "irqchip.h"
 
+#define GIC_INTSPEC_IRQ_IS_FIQ (1 << 7)
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -65,6 +70,7 @@ struct gic_chip_data {
 #endif
 	struct irq_domain *domain;
 	unsigned int gic_irqs;
+	unsigned int fiq_shadow_offset;
 #ifdef CONFIG_GIC_NON_BANKED
 	void __iomem *(*get_base)(union gic_base *);
 #endif
@@ -143,11 +149,34 @@ static inline void __iomem *gic_cpu_base(struct irq_data *d)
 	return gic_data_cpu_base(gic_data);
 }
 
+static inline bool gic_is_fiq(struct irq_data *d)
+{
+	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
+	return d->hwirq > gic_data->gic_irqs;
+}
+
 static inline unsigned int gic_irq(struct irq_data *d)
 {
+	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
+	if (gic_is_fiq(d))
+		return d->hwirq - gic_data->fiq_shadow_offset;
 	return d->hwirq;
 }
 
+static void gic_set_group_irq(struct irq_data *d, int group)
+{
+	unsigned int reg = gic_irq(d) / 32 * 4;
+	u32 mask = 1 << (gic_irq(d) % 32);
+	u32 val;
+
+	val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + reg);
+	if (group)
+		val |= mask;
+	else
+		val &= ~mask;
+	writel_relaxed(val, gic_dist_base(d) + GIC_DIST_IGROUP + reg);
+}
+
 /*
  * Routines to acknowledge, disable and enable interrupts
  */
@@ -159,6 +188,8 @@ static void gic_mask_irq(struct irq_data *d)
 	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
 	if (gic_arch_extn.irq_mask)
 		gic_arch_extn.irq_mask(d);
+	if (gic_is_fiq(d))
+		gic_set_group_irq(d, 1);
 	raw_spin_unlock(&irq_controller_lock);
 }
 
@@ -167,6 +198,8 @@ static void gic_unmask_irq(struct irq_data *d)
 	u32 mask = 1 << (gic_irq(d) % 32);
 
 	raw_spin_lock(&irq_controller_lock);
+	if (gic_is_fiq(d))
+		gic_set_group_irq(d, 0);
 	if (gic_arch_extn.irq_unmask)
 		gic_arch_extn.irq_unmask(d);
 	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
@@ -940,7 +973,12 @@ static int gic_routable_irq_domain_xlate(struct irq_domain *d,
 				unsigned long *out_hwirq,
 				unsigned int *out_type)
 {
+	struct gic_chip_data *gic_data = d->host_data;
 	*out_hwirq += 16;
+
+	if (intspec[2] & GIC_INTSPEC_IRQ_IS_FIQ)
+		*out_hwirq += gic_data->fiq_shadow_offset;
+
 	return 0;
 }
 
@@ -1026,10 +1064,11 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 	gic->gic_irqs = gic_irqs;
 
 	gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
+	gic->fiq_shadow_offset = gic_irqs;
 
 	if (of_property_read_u32(node, "arm,routable-irqs",
 				 &nr_routable_irqs)) {
-		irq_base = irq_alloc_descs(irq_start, 16, gic_irqs,
+		irq_base = irq_alloc_descs(irq_start, 16, 2 * gic_irqs,
 					   numa_node_id());
 		if (IS_ERR_VALUE(irq_base)) {
 			WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
@@ -1037,17 +1076,28 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 			irq_base = irq_start;
 		}
 
-		gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
-					hwirq_base, &gic_irq_domain_ops, gic);
+		gic->domain =
+		    irq_domain_add_legacy(node, 2 * gic_irqs, irq_base,
+					  hwirq_base, &gic_irq_domain_ops, gic);
 	} else {
-		gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
-						    &gic_irq_domain_ops,
-						    gic);
+		gic->domain = irq_domain_add_linear(node, 2 * nr_routable_irqs,
+						    &gic_irq_domain_ops, gic);
 	}
 
 	if (WARN_ON(!gic->domain))
 		return;
 
+#ifdef CONFIG_FIQ
+	/* FIQ can only be supported on platforms without an extended irq_eoi
+	 * method (otherwise we take a lock during irq_eoi handling).
+	 */
+	if (!gic_arch_extn.irq_eoi)
+		fiq_add_mapping(
+		    irq_linear_revmap(gic->domain, hwirq_base),
+		    irq_linear_revmap(gic->domain, hwirq_base + gic_irqs),
+		    gic_irqs);
+#endif
+
 	if (gic_nr == 0) {
 #ifdef CONFIG_SMP
 		set_smp_cross_call(gic_raise_softirq);
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v3 5/9] irqchip: vic: Introduce shadow irqs for FIQ
  2014-06-05  9:53     ` Daniel Thompson
@ 2014-06-05  9:53       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Kukjin Kim,
	Jiri Slaby, Daniel Thompson, Dirk Behme, Russell King,
	Nicolas Pitre, Ian Campbell, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Jason Cooper, Pawel Moll, patches, Kumar Gala,
	Rob Herring, John Stultz, linux-samsung-soc, Ben

Currently on the ARM Versatile machine both FIQ and IRQ signals share
the same irq number. The effect of this is that enable_fiq() will
enable an interrupt but will leave it routed to IRQ. This requires a
driver utilizing FIQ to employ machine specific knowledge (i.e. that
the machine has a VIC).

By introducing shadow irqs to describe FIQs the VIC driver is able
to update the routing automatically during enable_fiq()/disable_fiq().

Changes to the vic_init() API allow individual machines to choose where
to fit the shadow irqs in the interrupt map and also to
choose not to have shadows at all.

This patch introduces shadows for mach-versatile whilst mach-ep93xx, mach-netx, mach-s3c64xx and plat-samsung retain unmodified interrupt maps.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: linux-samsung-soc@vger.kernel.org
---
 arch/arm/mach-ep93xx/core.c                 |   6 +-
 arch/arm/mach-netx/generic.c                |   3 +-
 arch/arm/mach-s3c64xx/common.c              |   6 +-
 arch/arm/mach-versatile/core.c              |   9 +--
 arch/arm/mach-versatile/include/mach/irqs.h |   5 +-
 arch/arm/plat-samsung/s5p-irq.c             |   3 +-
 drivers/irqchip/irq-vic.c                   | 102 +++++++++++++++++++++++-----
 include/linux/irqchip/arm-vic.h             |   8 ++-
 8 files changed, 113 insertions(+), 29 deletions(-)

diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 0e571f1..aa26411 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -185,8 +185,10 @@ void __init ep93xx_timer_init(void)
  *************************************************************************/
 void __init ep93xx_init_irq(void)
 {
-	vic_init(EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK, 0);
-	vic_init(EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK, 0);
+	vic_init(EP93XX_VIC1_BASE, 0, VIC_FIQ_START_NONE,
+		 EP93XX_VIC1_VALID_IRQ_MASK, 0);
+	vic_init(EP93XX_VIC2_BASE, 32, VIC_FIQ_START_NONE,
+		 EP93XX_VIC2_VALID_IRQ_MASK, 0);
 }
 
 
diff --git a/arch/arm/mach-netx/generic.c b/arch/arm/mach-netx/generic.c
index db25b0c..5398dcd 100644
--- a/arch/arm/mach-netx/generic.c
+++ b/arch/arm/mach-netx/generic.c
@@ -169,7 +169,8 @@ void __init netx_init_irq(void)
 {
 	int irq;
 
-	vic_init(io_p2v(NETX_PA_VIC), NETX_IRQ_VIC_START, ~0, 0);
+	vic_init(io_p2v(NETX_PA_VIC), NETX_IRQ_VIC_START, VIC_FIQ_START_NONE,
+		 ~0, 0);
 
 	for (irq = NETX_IRQ_HIF_CHAINED(0); irq <= NETX_IRQ_HIF_LAST; irq++) {
 		irq_set_chip_and_handler(irq, &netx_hif_chip,
diff --git a/arch/arm/mach-s3c64xx/common.c b/arch/arm/mach-s3c64xx/common.c
index 5c45aae..b98dd48 100644
--- a/arch/arm/mach-s3c64xx/common.c
+++ b/arch/arm/mach-s3c64xx/common.c
@@ -242,8 +242,10 @@ void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid)
 	printk(KERN_DEBUG "%s: initialising interrupts\n", __func__);
 
 	/* initialise the pair of VICs */
-	vic_init(VA_VIC0, IRQ_VIC0_BASE, vic0_valid, IRQ_VIC0_RESUME);
-	vic_init(VA_VIC1, IRQ_VIC1_BASE, vic1_valid, IRQ_VIC1_RESUME);
+	vic_init(VA_VIC0, IRQ_VIC0_BASE, VIC_FIQ_START_NONE, vic0_valid,
+		 IRQ_VIC0_RESUME);
+	vic_init(VA_VIC1, IRQ_VIC1_BASE, VIC_FIQ_START_NONE, vic1_valid,
+		 IRQ_VIC1_RESUME);
 }
 
 #define eint_offset(irq)	((irq) - IRQ_EINT(0))
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index f2c89fb..3444ca8 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -108,7 +108,8 @@ void __init versatile_init_irq(void)
 
 	np = of_find_matching_node_by_address(NULL, vic_of_match,
 					      VERSATILE_VIC_BASE);
-	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np);
+	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START,
+		   np ? -1 : FIQ_VIC_START, ~0, 0, np);
 
 	writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
 
@@ -614,9 +615,9 @@ static struct pl022_ssp_controller ssp0_plat_data = {
  * These devices are connected via the DMA APB bridge
  */
 #define SCI_IRQ		{ IRQ_SCIINT }
-#define UART0_IRQ	{ IRQ_UARTINT0 }
-#define UART1_IRQ	{ IRQ_UARTINT1 }
-#define UART2_IRQ	{ IRQ_UARTINT2 }
+#define UART0_IRQ	{ IRQ_UARTINT0, FIQ_UARTINT0 }
+#define UART1_IRQ	{ IRQ_UARTINT1, FIQ_UARTINT1 }
+#define UART2_IRQ	{ IRQ_UARTINT2, FIQ_UARTINT2 }
 #define SSP_IRQ		{ IRQ_SSPINT }
 
 /* FPGA Primecells */
diff --git a/arch/arm/mach-versatile/include/mach/irqs.h b/arch/arm/mach-versatile/include/mach/irqs.h
index 0fd771c..68171d9 100644
--- a/arch/arm/mach-versatile/include/mach/irqs.h
+++ b/arch/arm/mach-versatile/include/mach/irqs.h
@@ -131,4 +131,7 @@
 #define IRQ_GPIO3_START		(IRQ_GPIO2_END + 1)
 #define IRQ_GPIO3_END		(IRQ_GPIO3_START + 31)
 
-#define NR_IRQS			(IRQ_GPIO3_END + 1)
+#define FIQ_VIC_START		(IRQ_GPIO3_END + 1)
+#define FIQ_VIC_END		(FIQ_VIC_START + (IRQ_VIC_END - IRQ_VIC_START))
+
+#define NR_IRQS			(FIQ_VIC_END + 1)
diff --git a/arch/arm/plat-samsung/s5p-irq.c b/arch/arm/plat-samsung/s5p-irq.c
index ddfaca9..ddb1138 100644
--- a/arch/arm/plat-samsung/s5p-irq.c
+++ b/arch/arm/plat-samsung/s5p-irq.c
@@ -26,6 +26,7 @@ void __init s5p_init_irq(u32 *vic, u32 num_vic)
 
 	/* initialize the VICs */
 	for (irq = 0; irq < num_vic; irq++)
-		vic_init(VA_VIC(irq), VIC_BASE(irq), vic[irq], 0);
+		vic_init(VA_VIC(irq), VIC_BASE(irq), VIC_FIQ_START_NONE,
+			 vic[irq], 0);
 #endif
 }
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287..748c5af 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -36,6 +36,9 @@
 
 #include <asm/exception.h>
 #include <asm/irq.h>
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 
 #include "irqchip.h"
 
@@ -56,6 +59,8 @@
 
 #define VIC_PL192_VECT_ADDR		0xF00
 
+#define VIC_FIQ_SHADOW_OFFSET		32
+
 /**
  * struct vic_device - VIC PM device
  * @parent_irq: The parent IRQ number of the VIC if cascaded, or 0.
@@ -81,8 +86,11 @@ struct vic_device {
 	u32		soft_int;
 	u32		protect;
 	struct irq_domain *domain;
+	struct irq_domain *fiq_domain;
 };
 
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
 /* we cannot allocate memory when VICs are initially registered */
 static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
 
@@ -197,6 +205,9 @@ static int vic_irqdomain_map(struct irq_domain *d, unsigned int irq,
 {
 	struct vic_device *v = d->host_data;
 
+	if (hwirq > VIC_FIQ_SHADOW_OFFSET)
+		hwirq -= VIC_FIQ_SHADOW_OFFSET;
+
 	/* Skip invalid IRQs, only register handlers for the real ones */
 	if (!(v->valid_sources & (1 << hwirq)))
 		return -EPERM;
@@ -261,6 +272,15 @@ static struct irq_domain_ops vic_irqdomain_ops = {
 	.xlate = irq_domain_xlate_onetwocell,
 };
 
+#ifdef CONFIG_FIQ
+static void vic_map_fiq(int irq, int fiq, unsigned int length)
+{
+	fiq_add_mapping(irq, fiq, length);
+}
+#else
+static inline void vic_map_fiq(int irq, int fiq, unsigned int length) {}
+#endif
+
 /**
  * vic_register() - Register a VIC.
  * @base: The base address of the VIC.
@@ -277,7 +297,7 @@ static struct irq_domain_ops vic_irqdomain_ops = {
  * This also configures the IRQ domain for the VIC.
  */
 static void __init vic_register(void __iomem *base, unsigned int parent_irq,
-				unsigned int irq,
+				unsigned int irq, int fiq,
 				u32 valid_sources, u32 resume_sources,
 				struct device_node *node)
 {
@@ -307,6 +327,22 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 	for (i = 0; i < fls(valid_sources); i++)
 		if (valid_sources & (1 << i))
 			irq_create_mapping(v->domain, i);
+
+	/* create FIQ shadow mapping for each IRQ */
+	if (fiq >= 0) {
+		v->fiq_domain = irq_domain_add_legacy(
+				node, fls(valid_sources), fiq,
+				VIC_FIQ_SHADOW_OFFSET, &vic_irqdomain_ops, v);
+		/* create an IRQ mapping for each valid IRQ */
+		for (i = 0; i < fls(valid_sources); i++)
+			if (valid_sources & (1 << i)) {
+				int fiq_virq = irq_create_mapping(
+				    v->fiq_domain, i + VIC_FIQ_SHADOW_OFFSET);
+				vic_map_fiq(irq_find_mapping(v->domain, i),
+					    fiq_virq, 1);
+			}
+	}
+
 	/* If no base IRQ was passed, figure out our allocated base */
 	if (irq)
 		v->irq = irq;
@@ -314,10 +350,36 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 		v->irq = irq_find_mapping(v->domain, 0);
 }
 
+static inline bool vic_is_fiq(struct irq_data *d)
+{
+	return d->hwirq >= VIC_FIQ_SHADOW_OFFSET;
+}
+
+static inline unsigned int vic_irq(struct irq_data *d)
+{
+	return d->hwirq & (VIC_FIQ_SHADOW_OFFSET-1);
+}
+
+static void vic_set_fiq(struct irq_data *d, bool enable)
+{
+	void __iomem *base = irq_data_get_irq_chip_data(d);
+	unsigned int irq = vic_irq(d);
+	u32 val;
+
+	raw_spin_lock(&irq_controller_lock);
+	val = readl(base + VIC_INT_SELECT);
+	if (enable)
+		val |= 1 << irq;
+	else
+		val &= ~(1 << irq);
+	writel(val, base + VIC_INT_SELECT);
+	raw_spin_unlock(&irq_controller_lock);
+}
+
 static void vic_ack_irq(struct irq_data *d)
 {
 	void __iomem *base = irq_data_get_irq_chip_data(d);
-	unsigned int irq = d->hwirq;
+	unsigned int irq = vic_irq(d);
 	writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
 	/* moreover, clear the soft-triggered, in case it was the reason */
 	writel(1 << irq, base + VIC_INT_SOFT_CLEAR);
@@ -326,17 +388,22 @@ static void vic_ack_irq(struct irq_data *d)
 static void vic_mask_irq(struct irq_data *d)
 {
 	void __iomem *base = irq_data_get_irq_chip_data(d);
-	unsigned int irq = d->hwirq;
+	unsigned int irq = vic_irq(d);
+	if (vic_is_fiq(d))
+		vic_set_fiq(d, false);
 	writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
 }
 
 static void vic_unmask_irq(struct irq_data *d)
 {
 	void __iomem *base = irq_data_get_irq_chip_data(d);
-	unsigned int irq = d->hwirq;
+	unsigned int irq = vic_irq(d);
+	if (vic_is_fiq(d))
+		vic_set_fiq(d, true);
 	writel(1 << irq, base + VIC_INT_ENABLE);
 }
 
+
 #if defined(CONFIG_PM)
 static struct vic_device *vic_from_irq(unsigned int irq)
 {
@@ -355,7 +422,7 @@ static struct vic_device *vic_from_irq(unsigned int irq)
 static int vic_set_wake(struct irq_data *d, unsigned int on)
 {
 	struct vic_device *v = vic_from_irq(d->irq);
-	unsigned int off = d->hwirq;
+	unsigned int off = vic_irq(d);
 	u32 bit = 1 << off;
 
 	if (!v)
@@ -413,7 +480,8 @@ static void __init vic_clear_interrupts(void __iomem *base)
  *  and 020 within the page. We call this "second block".
  */
 static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
-			       u32 vic_sources, struct device_node *node)
+			       int fiq_start, u32 vic_sources,
+			       struct device_node *node)
 {
 	unsigned int i;
 	int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
@@ -439,12 +507,12 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
 		writel(32, base + VIC_PL190_DEF_VECT_ADDR);
 	}
 
-	vic_register(base, 0, irq_start, vic_sources, 0, node);
+	vic_register(base, 0, irq_start, fiq_start, vic_sources, 0, node);
 }
 
 void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
-			      u32 vic_sources, u32 resume_sources,
-			      struct device_node *node)
+		       int fiq_start, u32 vic_sources, u32 resume_sources,
+		       struct device_node *node)
 {
 	unsigned int i;
 	u32 cellid = 0;
@@ -462,7 +530,7 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	switch(vendor) {
 	case AMBA_VENDOR_ST:
-		vic_init_st(base, irq_start, vic_sources, node);
+		vic_init_st(base, irq_start, fiq_start, vic_sources, node);
 		return;
 	default:
 		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
@@ -479,7 +547,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	vic_init2(base);
 
-	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);
+	vic_register(base, parent_irq, irq_start, fiq_start, vic_sources,
+		     resume_sources, node);
 }
 
 /**
@@ -490,9 +559,9 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
  * @resume_sources: bitmask of interrupt sources to allow for resume
  */
 void __init vic_init(void __iomem *base, unsigned int irq_start,
-		     u32 vic_sources, u32 resume_sources)
+		     int fiq_start, u32 vic_sources, u32 resume_sources)
 {
-	__vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL);
+	__vic_init(base, 0, irq_start, -1, vic_sources, resume_sources, NULL);
 }
 
 /**
@@ -511,7 +580,7 @@ int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 	struct vic_device *v;
 
 	v = &vic_devices[vic_id];
-	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL);
+	__vic_init(base, parent_irq, 0, -1, vic_sources, resume_sources, NULL);
 	/* Return out acquired base */
 	return v->irq;
 }
@@ -535,9 +604,10 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
 	of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask);
 
 	/*
-	 * Passing 0 as first IRQ makes the simple domain allocate descriptors
+	 * Passing 0 as first IRQ (and first FIQ) makes the domain allocate
+	 * descriptors.
 	 */
-	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
+	__vic_init(regs, 0, 0, -1, interrupt_mask, wakeup_mask, node);
 
 	return 0;
 }
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index ba46c79..fae480d 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -26,12 +26,16 @@
 #define VIC_INT_ENABLE			0x10	/* 1 = enable, 0 = disable */
 #define VIC_INT_ENABLE_CLEAR		0x14
 
+#define VIC_FIQ_START_NONE -1
+
 struct device_node;
 struct pt_regs;
 
 void __vic_init(void __iomem *base, int parent_irq, int irq_start,
-		u32 vic_sources, u32 resume_sources, struct device_node *node);
-void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
+		int fiq_start, u32 vic_sources, u32 resume_sources,
+		struct device_node *node);
+void vic_init(void __iomem *base, unsigned int irq_start, int fiq_start,
+	      u32 vic_sources, u32 resume_sources);
 int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 		      u32 vic_sources, u32 resume_sources);
 
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v3 5/9] irqchip: vic: Introduce shadow irqs for FIQ
@ 2014-06-05  9:53       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: linux-arm-kernel

Currently on the ARM Versatile machine both FIQ and IRQ signals share
the same irq number. The effect of this is that enable_fiq() will
enable an interrupt but will leave it routed to IRQ. This requires a
driver utilizing FIQ to employ machine specific knowledge (i.e. that
the machine has a VIC).

By introducing shadow irqs to describe FIQs the VIC driver is able
to update the routing automatically during enable_fiq()/disable_fiq().

Changes to the vic_init() API allow individual machines to choose where
to fit the shadow irqs in the interrupt map and also to
choose not to have shadows at all.

This patch introduces shadows for mach-versatile whilst mach-ep93xx, mach-netx, mach-s3c64xx and plat-samsung retain unmodified interrupt maps.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: linux-samsung-soc at vger.kernel.org
---
 arch/arm/mach-ep93xx/core.c                 |   6 +-
 arch/arm/mach-netx/generic.c                |   3 +-
 arch/arm/mach-s3c64xx/common.c              |   6 +-
 arch/arm/mach-versatile/core.c              |   9 +--
 arch/arm/mach-versatile/include/mach/irqs.h |   5 +-
 arch/arm/plat-samsung/s5p-irq.c             |   3 +-
 drivers/irqchip/irq-vic.c                   | 102 +++++++++++++++++++++++-----
 include/linux/irqchip/arm-vic.h             |   8 ++-
 8 files changed, 113 insertions(+), 29 deletions(-)

diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 0e571f1..aa26411 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -185,8 +185,10 @@ void __init ep93xx_timer_init(void)
  *************************************************************************/
 void __init ep93xx_init_irq(void)
 {
-	vic_init(EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK, 0);
-	vic_init(EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK, 0);
+	vic_init(EP93XX_VIC1_BASE, 0, VIC_FIQ_START_NONE,
+		 EP93XX_VIC1_VALID_IRQ_MASK, 0);
+	vic_init(EP93XX_VIC2_BASE, 32, VIC_FIQ_START_NONE,
+		 EP93XX_VIC2_VALID_IRQ_MASK, 0);
 }
 
 
diff --git a/arch/arm/mach-netx/generic.c b/arch/arm/mach-netx/generic.c
index db25b0c..5398dcd 100644
--- a/arch/arm/mach-netx/generic.c
+++ b/arch/arm/mach-netx/generic.c
@@ -169,7 +169,8 @@ void __init netx_init_irq(void)
 {
 	int irq;
 
-	vic_init(io_p2v(NETX_PA_VIC), NETX_IRQ_VIC_START, ~0, 0);
+	vic_init(io_p2v(NETX_PA_VIC), NETX_IRQ_VIC_START, VIC_FIQ_START_NONE,
+		 ~0, 0);
 
 	for (irq = NETX_IRQ_HIF_CHAINED(0); irq <= NETX_IRQ_HIF_LAST; irq++) {
 		irq_set_chip_and_handler(irq, &netx_hif_chip,
diff --git a/arch/arm/mach-s3c64xx/common.c b/arch/arm/mach-s3c64xx/common.c
index 5c45aae..b98dd48 100644
--- a/arch/arm/mach-s3c64xx/common.c
+++ b/arch/arm/mach-s3c64xx/common.c
@@ -242,8 +242,10 @@ void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid)
 	printk(KERN_DEBUG "%s: initialising interrupts\n", __func__);
 
 	/* initialise the pair of VICs */
-	vic_init(VA_VIC0, IRQ_VIC0_BASE, vic0_valid, IRQ_VIC0_RESUME);
-	vic_init(VA_VIC1, IRQ_VIC1_BASE, vic1_valid, IRQ_VIC1_RESUME);
+	vic_init(VA_VIC0, IRQ_VIC0_BASE, VIC_FIQ_START_NONE, vic0_valid,
+		 IRQ_VIC0_RESUME);
+	vic_init(VA_VIC1, IRQ_VIC1_BASE, VIC_FIQ_START_NONE, vic1_valid,
+		 IRQ_VIC1_RESUME);
 }
 
 #define eint_offset(irq)	((irq) - IRQ_EINT(0))
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index f2c89fb..3444ca8 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -108,7 +108,8 @@ void __init versatile_init_irq(void)
 
 	np = of_find_matching_node_by_address(NULL, vic_of_match,
 					      VERSATILE_VIC_BASE);
-	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np);
+	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START,
+		   np ? -1 : FIQ_VIC_START, ~0, 0, np);
 
 	writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
 
@@ -614,9 +615,9 @@ static struct pl022_ssp_controller ssp0_plat_data = {
  * These devices are connected via the DMA APB bridge
  */
 #define SCI_IRQ		{ IRQ_SCIINT }
-#define UART0_IRQ	{ IRQ_UARTINT0 }
-#define UART1_IRQ	{ IRQ_UARTINT1 }
-#define UART2_IRQ	{ IRQ_UARTINT2 }
+#define UART0_IRQ	{ IRQ_UARTINT0, FIQ_UARTINT0 }
+#define UART1_IRQ	{ IRQ_UARTINT1, FIQ_UARTINT1 }
+#define UART2_IRQ	{ IRQ_UARTINT2, FIQ_UARTINT2 }
 #define SSP_IRQ		{ IRQ_SSPINT }
 
 /* FPGA Primecells */
diff --git a/arch/arm/mach-versatile/include/mach/irqs.h b/arch/arm/mach-versatile/include/mach/irqs.h
index 0fd771c..68171d9 100644
--- a/arch/arm/mach-versatile/include/mach/irqs.h
+++ b/arch/arm/mach-versatile/include/mach/irqs.h
@@ -131,4 +131,7 @@
 #define IRQ_GPIO3_START		(IRQ_GPIO2_END + 1)
 #define IRQ_GPIO3_END		(IRQ_GPIO3_START + 31)
 
-#define NR_IRQS			(IRQ_GPIO3_END + 1)
+#define FIQ_VIC_START		(IRQ_GPIO3_END + 1)
+#define FIQ_VIC_END		(FIQ_VIC_START + (IRQ_VIC_END - IRQ_VIC_START))
+
+#define NR_IRQS			(FIQ_VIC_END + 1)
diff --git a/arch/arm/plat-samsung/s5p-irq.c b/arch/arm/plat-samsung/s5p-irq.c
index ddfaca9..ddb1138 100644
--- a/arch/arm/plat-samsung/s5p-irq.c
+++ b/arch/arm/plat-samsung/s5p-irq.c
@@ -26,6 +26,7 @@ void __init s5p_init_irq(u32 *vic, u32 num_vic)
 
 	/* initialize the VICs */
 	for (irq = 0; irq < num_vic; irq++)
-		vic_init(VA_VIC(irq), VIC_BASE(irq), vic[irq], 0);
+		vic_init(VA_VIC(irq), VIC_BASE(irq), VIC_FIQ_START_NONE,
+			 vic[irq], 0);
 #endif
 }
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287..748c5af 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -36,6 +36,9 @@
 
 #include <asm/exception.h>
 #include <asm/irq.h>
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 
 #include "irqchip.h"
 
@@ -56,6 +59,8 @@
 
 #define VIC_PL192_VECT_ADDR		0xF00
 
+#define VIC_FIQ_SHADOW_OFFSET		32
+
 /**
  * struct vic_device - VIC PM device
  * @parent_irq: The parent IRQ number of the VIC if cascaded, or 0.
@@ -81,8 +86,11 @@ struct vic_device {
 	u32		soft_int;
 	u32		protect;
 	struct irq_domain *domain;
+	struct irq_domain *fiq_domain;
 };
 
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
 /* we cannot allocate memory when VICs are initially registered */
 static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
 
@@ -197,6 +205,9 @@ static int vic_irqdomain_map(struct irq_domain *d, unsigned int irq,
 {
 	struct vic_device *v = d->host_data;
 
+	if (hwirq > VIC_FIQ_SHADOW_OFFSET)
+		hwirq -= VIC_FIQ_SHADOW_OFFSET;
+
 	/* Skip invalid IRQs, only register handlers for the real ones */
 	if (!(v->valid_sources & (1 << hwirq)))
 		return -EPERM;
@@ -261,6 +272,15 @@ static struct irq_domain_ops vic_irqdomain_ops = {
 	.xlate = irq_domain_xlate_onetwocell,
 };
 
+#ifdef CONFIG_FIQ
+static void vic_map_fiq(int irq, int fiq, unsigned int length)
+{
+	fiq_add_mapping(irq, fiq, length);
+}
+#else
+static inline void vic_map_fiq(int irq, int fiq, unsigned int length) {}
+#endif
+
 /**
  * vic_register() - Register a VIC.
  * @base: The base address of the VIC.
@@ -277,7 +297,7 @@ static struct irq_domain_ops vic_irqdomain_ops = {
  * This also configures the IRQ domain for the VIC.
  */
 static void __init vic_register(void __iomem *base, unsigned int parent_irq,
-				unsigned int irq,
+				unsigned int irq, int fiq,
 				u32 valid_sources, u32 resume_sources,
 				struct device_node *node)
 {
@@ -307,6 +327,22 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 	for (i = 0; i < fls(valid_sources); i++)
 		if (valid_sources & (1 << i))
 			irq_create_mapping(v->domain, i);
+
+	/* create FIQ shadow mapping for each IRQ */
+	if (fiq >= 0) {
+		v->fiq_domain = irq_domain_add_legacy(
+				node, fls(valid_sources), fiq,
+				VIC_FIQ_SHADOW_OFFSET, &vic_irqdomain_ops, v);
+		/* create an IRQ mapping for each valid IRQ */
+		for (i = 0; i < fls(valid_sources); i++)
+			if (valid_sources & (1 << i)) {
+				int fiq_virq = irq_create_mapping(
+				    v->fiq_domain, i + VIC_FIQ_SHADOW_OFFSET);
+				vic_map_fiq(irq_find_mapping(v->domain, i),
+					    fiq_virq, 1);
+			}
+	}
+
 	/* If no base IRQ was passed, figure out our allocated base */
 	if (irq)
 		v->irq = irq;
@@ -314,10 +350,36 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 		v->irq = irq_find_mapping(v->domain, 0);
 }
 
+static inline bool vic_is_fiq(struct irq_data *d)
+{
+	return d->hwirq >= VIC_FIQ_SHADOW_OFFSET;
+}
+
+static inline unsigned int vic_irq(struct irq_data *d)
+{
+	return d->hwirq & (VIC_FIQ_SHADOW_OFFSET-1);
+}
+
+static void vic_set_fiq(struct irq_data *d, bool enable)
+{
+	void __iomem *base = irq_data_get_irq_chip_data(d);
+	unsigned int irq = vic_irq(d);
+	u32 val;
+
+	raw_spin_lock(&irq_controller_lock);
+	val = readl(base + VIC_INT_SELECT);
+	if (enable)
+		val |= 1 << irq;
+	else
+		val &= ~(1 << irq);
+	writel(val, base + VIC_INT_SELECT);
+	raw_spin_unlock(&irq_controller_lock);
+}
+
 static void vic_ack_irq(struct irq_data *d)
 {
 	void __iomem *base = irq_data_get_irq_chip_data(d);
-	unsigned int irq = d->hwirq;
+	unsigned int irq = vic_irq(d);
 	writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
 	/* moreover, clear the soft-triggered, in case it was the reason */
 	writel(1 << irq, base + VIC_INT_SOFT_CLEAR);
@@ -326,17 +388,22 @@ static void vic_ack_irq(struct irq_data *d)
 static void vic_mask_irq(struct irq_data *d)
 {
 	void __iomem *base = irq_data_get_irq_chip_data(d);
-	unsigned int irq = d->hwirq;
+	unsigned int irq = vic_irq(d);
+	if (vic_is_fiq(d))
+		vic_set_fiq(d, false);
 	writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
 }
 
 static void vic_unmask_irq(struct irq_data *d)
 {
 	void __iomem *base = irq_data_get_irq_chip_data(d);
-	unsigned int irq = d->hwirq;
+	unsigned int irq = vic_irq(d);
+	if (vic_is_fiq(d))
+		vic_set_fiq(d, true);
 	writel(1 << irq, base + VIC_INT_ENABLE);
 }
 
+
 #if defined(CONFIG_PM)
 static struct vic_device *vic_from_irq(unsigned int irq)
 {
@@ -355,7 +422,7 @@ static struct vic_device *vic_from_irq(unsigned int irq)
 static int vic_set_wake(struct irq_data *d, unsigned int on)
 {
 	struct vic_device *v = vic_from_irq(d->irq);
-	unsigned int off = d->hwirq;
+	unsigned int off = vic_irq(d);
 	u32 bit = 1 << off;
 
 	if (!v)
@@ -413,7 +480,8 @@ static void __init vic_clear_interrupts(void __iomem *base)
  *  and 020 within the page. We call this "second block".
  */
 static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
-			       u32 vic_sources, struct device_node *node)
+			       int fiq_start, u32 vic_sources,
+			       struct device_node *node)
 {
 	unsigned int i;
 	int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
@@ -439,12 +507,12 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
 		writel(32, base + VIC_PL190_DEF_VECT_ADDR);
 	}
 
-	vic_register(base, 0, irq_start, vic_sources, 0, node);
+	vic_register(base, 0, irq_start, fiq_start, vic_sources, 0, node);
 }
 
 void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
-			      u32 vic_sources, u32 resume_sources,
-			      struct device_node *node)
+		       int fiq_start, u32 vic_sources, u32 resume_sources,
+		       struct device_node *node)
 {
 	unsigned int i;
 	u32 cellid = 0;
@@ -462,7 +530,7 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	switch(vendor) {
 	case AMBA_VENDOR_ST:
-		vic_init_st(base, irq_start, vic_sources, node);
+		vic_init_st(base, irq_start, fiq_start, vic_sources, node);
 		return;
 	default:
 		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
@@ -479,7 +547,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	vic_init2(base);
 
-	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);
+	vic_register(base, parent_irq, irq_start, fiq_start, vic_sources,
+		     resume_sources, node);
 }
 
 /**
@@ -490,9 +559,9 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
  * @resume_sources: bitmask of interrupt sources to allow for resume
  */
 void __init vic_init(void __iomem *base, unsigned int irq_start,
-		     u32 vic_sources, u32 resume_sources)
+		     int fiq_start, u32 vic_sources, u32 resume_sources)
 {
-	__vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL);
+	__vic_init(base, 0, irq_start, -1, vic_sources, resume_sources, NULL);
 }
 
 /**
@@ -511,7 +580,7 @@ int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 	struct vic_device *v;
 
 	v = &vic_devices[vic_id];
-	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL);
+	__vic_init(base, parent_irq, 0, -1, vic_sources, resume_sources, NULL);
 	/* Return out acquired base */
 	return v->irq;
 }
@@ -535,9 +604,10 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
 	of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask);
 
 	/*
-	 * Passing 0 as first IRQ makes the simple domain allocate descriptors
+	 * Passing 0 as first IRQ (and first FIQ) makes the domain allocate
+	 * descriptors.
 	 */
-	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
+	__vic_init(regs, 0, 0, -1, interrupt_mask, wakeup_mask, node);
 
 	return 0;
 }
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index ba46c79..fae480d 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -26,12 +26,16 @@
 #define VIC_INT_ENABLE			0x10	/* 1 = enable, 0 = disable */
 #define VIC_INT_ENABLE_CLEAR		0x14
 
+#define VIC_FIQ_START_NONE -1
+
 struct device_node;
 struct pt_regs;
 
 void __vic_init(void __iomem *base, int parent_irq, int irq_start,
-		u32 vic_sources, u32 resume_sources, struct device_node *node);
-void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
+		int fiq_start, u32 vic_sources, u32 resume_sources,
+		struct device_node *node);
+void vic_init(void __iomem *base, unsigned int irq_start, int fiq_start,
+	      u32 vic_sources, u32 resume_sources);
 int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 		      u32 vic_sources, u32 resume_sources);
 
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v3 6/9] ARM: Move some macros from entry-armv to entry-header
  2014-06-05  9:53     ` Daniel Thompson
@ 2014-06-05  9:53       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Ian Campbell, Anton Vorontsov, David A. Long, linux-serial,
	Catalin Marinas, kernel-team, devicetree, linaro-kernel,
	Pawel Moll, patches, Kumar Gala, Rob Herring, John Stultz,
	Thomas Gleixner, linux-arm-kernel, Greg Kroah-Hartman

From: Anton Vorontsov <anton.vorontsov@linaro.org>

Just move the macros into header file as we would want to use them for
KGDB FIQ entry code.

The following macros were moved:

 - svc_entry
 - usr_entry
 - kuser_cmpxchg_check
 - vector_stub

To make kuser_cmpxchg_check actually work across different files, we
also have to make kuser_cmpxchg64_fixup global.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
---
 arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
 arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 150 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 1879e8d..ed95b95 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -140,53 +140,6 @@ ENDPROC(__und_invalid)
  * SVC mode handlers
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
-#define SPFIX(code...) code
-#else
-#define SPFIX(code...)
-#endif
-
-	.macro	svc_entry, stack_hole=0
- UNWIND(.fnstart		)
- UNWIND(.save {r0 - pc}		)
-	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
-#ifdef CONFIG_THUMB2_KERNEL
- SPFIX(	str	r0, [sp]	)	@ temporarily saved
- SPFIX(	mov	r0, sp		)
- SPFIX(	tst	r0, #4		)	@ test original stack alignment
- SPFIX(	ldr	r0, [sp]	)	@ restored
-#else
- SPFIX(	tst	sp, #4		)
-#endif
- SPFIX(	subeq	sp, sp, #4	)
-	stmia	sp, {r1 - r12}
-
-	ldmia	r0, {r3 - r5}
-	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""      ""       ""
-	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
- SPFIX(	addeq	r2, r2, #4	)
-	str	r3, [sp, #-4]!		@ save the "real" r0 copied
-					@ from the exception stack
-
-	mov	r3, lr
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r2 - sp_svc
-	@  r3 - lr_svc
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	stmia	r7, {r2 - r6}
-
-#ifdef CONFIG_TRACE_IRQFLAGS
-	bl	trace_hardirqs_off
-#endif
-	.endm
-
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -306,73 +259,8 @@ ENDPROC(__pabt_svc)
 
 /*
  * User mode handlers
- *
- * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
 	.align	5
 __dabt_usr:
 	usr_entry
@@ -819,6 +707,7 @@ __kuser_cmpxchg64:				@ 0xffff0f60
 	ldmfd	sp!, {r4, r5, r6, pc}
 
 	.text
+	.global kuser_cmpxchg64_fixup
 kuser_cmpxchg64_fixup:
 	@ Called from kuser_cmpxchg_fixup.
 	@ r4 = address of interrupted insn (must be preserved).
@@ -960,44 +849,6 @@ __kuser_helper_end:
  * SP points to a minimal amount of processor-private memory, the address
  * of which is copied into r0 for the mode specific abort handler.
  */
-	.macro	vector_stub, name, mode, correction=0
-	.align	5
-
-vector_\name:
-	.if \correction
-	sub	lr, lr, #\correction
-	.endif
-
-	@
-	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
-	@ (parent CPSR)
-	@
-	stmia	sp, {r0, lr}		@ save r0, lr
-	mrs	lr, spsr
-	str	lr, [sp, #8]		@ save spsr
-
-	@
-	@ Prepare for SVC32 mode.  IRQs remain disabled.
-	@
-	mrs	r0, cpsr
-	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
-	msr	spsr_cxsf, r0
-
-	@
-	@ the branch table must immediately follow this code
-	@
-	and	lr, lr, #0x0f
- THUMB(	adr	r0, 1f			)
- THUMB(	ldr	lr, [r0, lr, lsl #2]	)
-	mov	r0, sp
- ARM(	ldr	lr, [pc, lr, lsl #2]	)
-	movs	pc, lr			@ branch to handler in SVC mode
-ENDPROC(vector_\name)
-
-	.align	2
-	@ handler addresses follow this label
-1:
-	.endm
 
 	.section .stubs, "ax", %progbits
 __stubs_start:
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index efb208d..5d794d6 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -356,3 +356,167 @@ scno	.req	r7		@ syscall number
 tbl	.req	r8		@ syscall table pointer
 why	.req	r8		@ Linux syscall (!= 0)
 tsk	.req	r9		@ current thread_info
+
+/*
+ * SVC mode handler macros
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define SPFIX(code...) code
+#else
+#define SPFIX(code...)
+#endif
+
+	.macro	svc_entry, stack_hole=0
+ UNWIND(.fnstart		)
+ UNWIND(.save {r0 - pc}		)
+	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+#ifdef CONFIG_THUMB2_KERNEL
+ SPFIX(	str	r0, [sp]	)	@ temporarily saved
+ SPFIX(	mov	r0, sp		)
+ SPFIX(	tst	r0, #4		)	@ test original stack alignment
+ SPFIX(	ldr	r0, [sp]	)	@ restored
+#else
+ SPFIX(	tst	sp, #4		)
+#endif
+ SPFIX(	subeq	sp, sp, #4	)
+	stmia	sp, {r1 - r12}
+
+	ldmia	r0, {r3 - r5}
+	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""      ""       ""
+	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+ SPFIX(	addeq	r2, r2, #4	)
+	str	r3, [sp, #-4]!		@ save the "real" r0 copied
+					@ from the exception stack
+
+	mov	r3, lr
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r2 - sp_svc
+	@  r3 - lr_svc
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	stmia	r7, {r2 - r6}
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_off
+#endif
+	.endm
+
+/*
+ * User mode handler macros
+ *
+ * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+/*
+ * Vector stubs macro.
+ */
+	.macro	vector_stub, name, mode, correction=0
+	.align	5
+
+vector_\name:
+	.if \correction
+	sub	lr, lr, #\correction
+	.endif
+
+	@
+	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
+	@ (parent CPSR)
+	@
+	stmia	sp, {r0, lr}		@ save r0, lr
+	mrs	lr, spsr
+	str	lr, [sp, #8]		@ save spsr
+
+	@
+	@ Prepare for SVC32 mode.  IRQs remain disabled.
+	@
+	mrs	r0, cpsr
+	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
+	msr	spsr_cxsf, r0
+
+	@
+	@ the branch table must immediately follow this code
+	@
+	and	lr, lr, #0x0f
+ THUMB(	adr	r0, 1f			)
+ THUMB(	ldr	lr, [r0, lr, lsl #2]	)
+	mov	r0, sp
+ ARM(	ldr	lr, [pc, lr, lsl #2]	)
+	movs	pc, lr			@ branch to handler in SVC mode
+ENDPROC(vector_\name)
+
+	.align	2
+	@ handler addresses follow this label
+1:
+	.endm
+
+
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v3 6/9] ARM: Move some macros from entry-armv to entry-header
@ 2014-06-05  9:53       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: linux-arm-kernel

From: Anton Vorontsov <anton.vorontsov@linaro.org>

Just move the macros into header file as we would want to use them for
KGDB FIQ entry code.

The following macros were moved:

 - svc_entry
 - usr_entry
 - kuser_cmpxchg_check
 - vector_stub

To make kuser_cmpxchg_check actually work across different files, we
also have to make kuser_cmpxchg64_fixup global.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
---
 arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
 arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 150 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 1879e8d..ed95b95 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -140,53 +140,6 @@ ENDPROC(__und_invalid)
  * SVC mode handlers
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
-#define SPFIX(code...) code
-#else
-#define SPFIX(code...)
-#endif
-
-	.macro	svc_entry, stack_hole=0
- UNWIND(.fnstart		)
- UNWIND(.save {r0 - pc}		)
-	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
-#ifdef CONFIG_THUMB2_KERNEL
- SPFIX(	str	r0, [sp]	)	@ temporarily saved
- SPFIX(	mov	r0, sp		)
- SPFIX(	tst	r0, #4		)	@ test original stack alignment
- SPFIX(	ldr	r0, [sp]	)	@ restored
-#else
- SPFIX(	tst	sp, #4		)
-#endif
- SPFIX(	subeq	sp, sp, #4	)
-	stmia	sp, {r1 - r12}
-
-	ldmia	r0, {r3 - r5}
-	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""      ""       ""
-	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
- SPFIX(	addeq	r2, r2, #4	)
-	str	r3, [sp, #-4]!		@ save the "real" r0 copied
-					@ from the exception stack
-
-	mov	r3, lr
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r2 - sp_svc
-	@  r3 - lr_svc
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	stmia	r7, {r2 - r6}
-
-#ifdef CONFIG_TRACE_IRQFLAGS
-	bl	trace_hardirqs_off
-#endif
-	.endm
-
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -306,73 +259,8 @@ ENDPROC(__pabt_svc)
 
 /*
  * User mode handlers
- *
- * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
 	.align	5
 __dabt_usr:
 	usr_entry
@@ -819,6 +707,7 @@ __kuser_cmpxchg64:				@ 0xffff0f60
 	ldmfd	sp!, {r4, r5, r6, pc}
 
 	.text
+	.global kuser_cmpxchg64_fixup
 kuser_cmpxchg64_fixup:
 	@ Called from kuser_cmpxchg_fixup.
 	@ r4 = address of interrupted insn (must be preserved).
@@ -960,44 +849,6 @@ __kuser_helper_end:
  * SP points to a minimal amount of processor-private memory, the address
  * of which is copied into r0 for the mode specific abort handler.
  */
-	.macro	vector_stub, name, mode, correction=0
-	.align	5
-
-vector_\name:
-	.if \correction
-	sub	lr, lr, #\correction
-	.endif
-
-	@
-	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
-	@ (parent CPSR)
-	@
-	stmia	sp, {r0, lr}		@ save r0, lr
-	mrs	lr, spsr
-	str	lr, [sp, #8]		@ save spsr
-
-	@
-	@ Prepare for SVC32 mode.  IRQs remain disabled.
-	@
-	mrs	r0, cpsr
-	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
-	msr	spsr_cxsf, r0
-
-	@
-	@ the branch table must immediately follow this code
-	@
-	and	lr, lr, #0x0f
- THUMB(	adr	r0, 1f			)
- THUMB(	ldr	lr, [r0, lr, lsl #2]	)
-	mov	r0, sp
- ARM(	ldr	lr, [pc, lr, lsl #2]	)
-	movs	pc, lr			@ branch to handler in SVC mode
-ENDPROC(vector_\name)
-
-	.align	2
-	@ handler addresses follow this label
-1:
-	.endm
 
 	.section .stubs, "ax", %progbits
 __stubs_start:
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index efb208d..5d794d6 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -356,3 +356,167 @@ scno	.req	r7		@ syscall number
 tbl	.req	r8		@ syscall table pointer
 why	.req	r8		@ Linux syscall (!= 0)
 tsk	.req	r9		@ current thread_info
+
+/*
+ * SVC mode handler macros
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define SPFIX(code...) code
+#else
+#define SPFIX(code...)
+#endif
+
+	.macro	svc_entry, stack_hole=0
+ UNWIND(.fnstart		)
+ UNWIND(.save {r0 - pc}		)
+	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+#ifdef CONFIG_THUMB2_KERNEL
+ SPFIX(	str	r0, [sp]	)	@ temporarily saved
+ SPFIX(	mov	r0, sp		)
+ SPFIX(	tst	r0, #4		)	@ test original stack alignment
+ SPFIX(	ldr	r0, [sp]	)	@ restored
+#else
+ SPFIX(	tst	sp, #4		)
+#endif
+ SPFIX(	subeq	sp, sp, #4	)
+	stmia	sp, {r1 - r12}
+
+	ldmia	r0, {r3 - r5}
+	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""      ""       ""
+	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+ SPFIX(	addeq	r2, r2, #4	)
+	str	r3, [sp, #-4]!		@ save the "real" r0 copied
+					@ from the exception stack
+
+	mov	r3, lr
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r2 - sp_svc
+	@  r3 - lr_svc
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	stmia	r7, {r2 - r6}
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_off
+#endif
+	.endm
+
+/*
+ * User mode handler macros
+ *
+ * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+/*
+ * Vector stubs macro.
+ */
+	.macro	vector_stub, name, mode, correction=0
+	.align	5
+
+vector_\name:
+	.if \correction
+	sub	lr, lr, #\correction
+	.endif
+
+	@
+	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
+	@ (parent CPSR)
+	@
+	stmia	sp, {r0, lr}		@ save r0, lr
+	mrs	lr, spsr
+	str	lr, [sp, #8]		@ save spsr
+
+	@
+	@ Prepare for SVC32 mode.  IRQs remain disabled.
+	@
+	mrs	r0, cpsr
+	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
+	msr	spsr_cxsf, r0
+
+	@
+	@ the branch table must immediately follow this code
+	@
+	and	lr, lr, #0x0f
+ THUMB(	adr	r0, 1f			)
+ THUMB(	ldr	lr, [r0, lr, lsl #2]	)
+	mov	r0, sp
+ ARM(	ldr	lr, [pc, lr, lsl #2]	)
+	movs	pc, lr			@ branch to handler in SVC mode
+ENDPROC(vector_\name)
+
+	.align	2
+	@ handler addresses follow this label
+1:
+	.endm
+
+
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v3 7/9] ARM: Add KGDB/KDB FIQ debugger generic code
  2014-06-05  9:53     ` Daniel Thompson
@ 2014-06-05  9:53       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Ian Campbell, Anton Vorontsov, Ben Dooks, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, Dave Martin,
	devicetree, linaro-kernel, Pawel Moll, patches, Kumar Gala,
	Rob Herring, John Stultz, Thomas Gleixner

From: Anton Vorontsov <anton.vorontsov@linaro.org>

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

By default KGDB FIQ is disabled in runtime, but can be enabled with
kgdb_fiq.enable=1 kernel command line option.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben.dooks@codethink.co.uk>
Cc: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 ++++++
 arch/arm/include/asm/kgdb.h      |   7 +++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/kgdb_fiq.c       | 124 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S |  87 +++++++++++++++++++++++++++
 6 files changed, 239 insertions(+)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index db3c541..419fd0a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -307,6 +307,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -356,6 +357,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 6a2bcfd..1f1bec1 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,24 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be
+	  enabled with kgdb_fiq.enable=1 kernel command line option.
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..5de21f01 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,11 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern char kgdb_fiq_handler;
+extern char kgdb_fiq_handler_end;
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs);
+extern int kgdb_register_fiq(unsigned int fiq);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 040619c..251f651 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -67,6 +67,7 @@ endif
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
 obj-$(CONFIG_ARM_THUMBEE)	+= thumbee.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
+obj-$(CONFIG_KGDB_FIQ)		+= kgdb_fiq_entry.o kgdb_fiq.o
 obj-$(CONFIG_ARM_UNWIND)	+= unwind.o
 obj-$(CONFIG_HAVE_TCM)		+= tcm.o
 obj-$(CONFIG_OF)		+= devtree.o
diff --git a/arch/arm/kernel/kgdb_fiq.c b/arch/arm/kernel/kgdb_fiq.c
new file mode 100644
index 0000000..45f2a79
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq.c
@@ -0,0 +1,124 @@
+/*
+ * KGDB FIQ
+ *
+ * Copyright 2010 Google, Inc.
+ *		  Arve Hjønnevåg <arve@android.com>
+ *		  Colin Cross <ccross@android.com>
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/hardirq.h>
+#include <linux/atomic.h>
+#include <linux/kdb.h>
+#include <linux/kgdb.h>
+#include <asm/fiq.h>
+#include <asm/exception.h>
+
+static int kgdb_fiq_enabled;
+module_param_named(enable, kgdb_fiq_enabled, int, 0600);
+MODULE_PARM_DESC(enable, "set to 1 to enable FIQ KGDB");
+
+static unsigned int kgdb_fiq;
+
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs)
+{
+	if (kgdb_nmi_poll_knock()) {
+		nmi_enter();
+		kgdb_handle_exception(1, 0, 0, regs);
+		nmi_exit();
+	}
+
+	eoi_fiq(kgdb_fiq);
+}
+
+static struct fiq_handler kgdb_fiq_desc = {
+	.name = "kgdb",
+};
+
+static long kgdb_fiq_setup_stack(void *info)
+{
+	struct pt_regs regs;
+
+	regs.ARM_sp = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER) +
+			THREAD_START_SP;
+	WARN_ON(!regs.ARM_sp);
+
+	set_fiq_regs(&regs);
+	return 0;
+}
+
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * This function manages NMIs that usually cause KGDB to enter. That is, not
+ * all NMIs should be enabled or disabled, but only those that issue
+ * kgdb_handle_exception().
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	static atomic_t cnt;
+	int ret;
+
+	ret = atomic_add_return(on ? 1 : -1, &cnt);
+	if (ret > 1 && on) {
+		/*
+		 * There should be only one instance that calls this function
+		 * in "enable, disable" order. All other users must call
+		 * disable first, then enable. If not, something is wrong.
+		 */
+		WARN_ON(1);
+		return;
+	}
+
+	if (ret > 0)
+		enable_fiq(kgdb_fiq);
+	else
+		disable_fiq(kgdb_fiq);
+}
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	int err;
+	int cpu;
+
+	if (!kgdb_fiq_enabled)
+		return -ENODEV;
+
+	if (!lookup_fiq_irq_data(fiq)) {
+		pr_warn(
+		    "%s: Cannot register %u (no FIQ with this number)\n",
+		    __func__, fiq);
+		return -ENODEV;
+	}
+
+	kgdb_fiq = fiq;
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	for_each_possible_cpu(cpu)
+		work_on_cpu(cpu, kgdb_fiq_setup_stack, NULL);
+
+	set_fiq_handler(&kgdb_fiq_handler,
+			&kgdb_fiq_handler_end - &kgdb_fiq_handler);
+
+	arch_kgdb_ops.enable_nmi = kgdb_fiq_enable_nmi;
+	return 0;
+}
diff --git a/arch/arm/kernel/kgdb_fiq_entry.S b/arch/arm/kernel/kgdb_fiq_entry.S
new file mode 100644
index 0000000..d6becca
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq_entry.S
@@ -0,0 +1,87 @@
+/*
+ * KGDB FIQ entry
+ *
+ * Copyright 1996,1997,1998 Russell King.
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+#include <asm/unwind.h>
+#include "entry-header.S"
+
+	.text
+
+@ This is needed for usr_entry/alignment_trap
+.LCcralign:
+	.long	cr_alignment
+.LCdohandle:
+	.long	kgdb_fiq_do_handle
+
+	.macro	fiq_handler
+	ldr	r1, =.LCdohandle
+	mov	r0, sp
+	adr	lr, BSYM(9997f)
+	ldr	pc, [r1]
+9997:
+	.endm
+
+	.align	5
+__fiq_svc:
+	svc_entry
+	fiq_handler
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+	.ltorg
+
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+	.ltorg
+
+	.global kgdb_fiq_handler
+kgdb_fiq_handler:
+
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_svc			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
+
+	.global kgdb_fiq_handler_end
+kgdb_fiq_handler_end:
-- 
1.9.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v3 7/9] ARM: Add KGDB/KDB FIQ debugger generic code
@ 2014-06-05  9:53       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: linux-arm-kernel

From: Anton Vorontsov <anton.vorontsov@linaro.org>

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

By default KGDB FIQ is disabled in runtime, but can be enabled with
kgdb_fiq.enable=1 kernel command line option.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben.dooks@codethink.co.uk>
Cc: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 ++++++
 arch/arm/include/asm/kgdb.h      |   7 +++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/kgdb_fiq.c       | 124 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S |  87 +++++++++++++++++++++++++++
 6 files changed, 239 insertions(+)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index db3c541..419fd0a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -307,6 +307,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -356,6 +357,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 6a2bcfd..1f1bec1 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,24 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be
+	  enabled with kgdb_fiq.enable=1 kernel command line option.
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..5de21f01 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,11 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern char kgdb_fiq_handler;
+extern char kgdb_fiq_handler_end;
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs);
+extern int kgdb_register_fiq(unsigned int fiq);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 040619c..251f651 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -67,6 +67,7 @@ endif
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
 obj-$(CONFIG_ARM_THUMBEE)	+= thumbee.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
+obj-$(CONFIG_KGDB_FIQ)		+= kgdb_fiq_entry.o kgdb_fiq.o
 obj-$(CONFIG_ARM_UNWIND)	+= unwind.o
 obj-$(CONFIG_HAVE_TCM)		+= tcm.o
 obj-$(CONFIG_OF)		+= devtree.o
diff --git a/arch/arm/kernel/kgdb_fiq.c b/arch/arm/kernel/kgdb_fiq.c
new file mode 100644
index 0000000..45f2a79
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq.c
@@ -0,0 +1,124 @@
+/*
+ * KGDB FIQ
+ *
+ * Copyright 2010 Google, Inc.
+ *		  Arve Hj?nnev?g <arve@android.com>
+ *		  Colin Cross <ccross@android.com>
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/hardirq.h>
+#include <linux/atomic.h>
+#include <linux/kdb.h>
+#include <linux/kgdb.h>
+#include <asm/fiq.h>
+#include <asm/exception.h>
+
+static int kgdb_fiq_enabled;
+module_param_named(enable, kgdb_fiq_enabled, int, 0600);
+MODULE_PARM_DESC(enable, "set to 1 to enable FIQ KGDB");
+
+static unsigned int kgdb_fiq;
+
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs)
+{
+	if (kgdb_nmi_poll_knock()) {
+		nmi_enter();
+		kgdb_handle_exception(1, 0, 0, regs);
+		nmi_exit();
+	}
+
+	eoi_fiq(kgdb_fiq);
+}
+
+static struct fiq_handler kgdb_fiq_desc = {
+	.name = "kgdb",
+};
+
+static long kgdb_fiq_setup_stack(void *info)
+{
+	struct pt_regs regs;
+
+	regs.ARM_sp = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER) +
+			THREAD_START_SP;
+	WARN_ON(!regs.ARM_sp);
+
+	set_fiq_regs(&regs);
+	return 0;
+}
+
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * This function manages NMIs that usually cause KGDB to enter. That is, not
+ * all NMIs should be enabled or disabled, but only those that issue
+ * kgdb_handle_exception().
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	static atomic_t cnt;
+	int ret;
+
+	ret = atomic_add_return(on ? 1 : -1, &cnt);
+	if (ret > 1 && on) {
+		/*
+		 * There should be only one instance that calls this function
+		 * in "enable, disable" order. All other users must call
+		 * disable first, then enable. If not, something is wrong.
+		 */
+		WARN_ON(1);
+		return;
+	}
+
+	if (ret > 0)
+		enable_fiq(kgdb_fiq);
+	else
+		disable_fiq(kgdb_fiq);
+}
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	int err;
+	int cpu;
+
+	if (!kgdb_fiq_enabled)
+		return -ENODEV;
+
+	if (!lookup_fiq_irq_data(fiq)) {
+		pr_warn(
+		    "%s: Cannot register %u (no FIQ with this number)\n",
+		    __func__, fiq);
+		return -ENODEV;
+	}
+
+	kgdb_fiq = fiq;
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	for_each_possible_cpu(cpu)
+		work_on_cpu(cpu, kgdb_fiq_setup_stack, NULL);
+
+	set_fiq_handler(&kgdb_fiq_handler,
+			&kgdb_fiq_handler_end - &kgdb_fiq_handler);
+
+	arch_kgdb_ops.enable_nmi = kgdb_fiq_enable_nmi;
+	return 0;
+}
diff --git a/arch/arm/kernel/kgdb_fiq_entry.S b/arch/arm/kernel/kgdb_fiq_entry.S
new file mode 100644
index 0000000..d6becca
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq_entry.S
@@ -0,0 +1,87 @@
+/*
+ * KGDB FIQ entry
+ *
+ * Copyright 1996,1997,1998 Russell King.
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+#include <asm/unwind.h>
+#include "entry-header.S"
+
+	.text
+
+@ This is needed for usr_entry/alignment_trap
+.LCcralign:
+	.long	cr_alignment
+.LCdohandle:
+	.long	kgdb_fiq_do_handle
+
+	.macro	fiq_handler
+	ldr	r1, =.LCdohandle
+	mov	r0, sp
+	adr	lr, BSYM(9997f)
+	ldr	pc, [r1]
+9997:
+	.endm
+
+	.align	5
+__fiq_svc:
+	svc_entry
+	fiq_handler
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+	.ltorg
+
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+	.ltorg
+
+	.global kgdb_fiq_handler
+kgdb_fiq_handler:
+
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_svc			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
+
+	.global kgdb_fiq_handler_end
+kgdb_fiq_handler_end:
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v3 8/9] serial: amba-pl011: Pass on FIQ information to KGDB.
  2014-06-05  9:53     ` Daniel Thompson
@ 2014-06-05  9:53       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Ian Campbell, Anton Vorontsov, David A. Long, linux-serial,
	Catalin Marinas, kernel-team, devicetree, linaro-kernel,
	Pawel Moll, patches, Kumar Gala, Rob Herring, John Stultz,
	Thomas Gleixner, linux-arm-kernel, Greg Kroah-Hartman

If the AMBA bus has provided the pl011 with a FIQ resource (i.e. a
second IRQ) then speculatively register it with KGDB when the polling
driver is initialized.

By providing this information to KGDB the serial driver offers
"permission" for KGDB to route the UART interrupt signal from the
drivers own handler to KGDBs FIQ handler (which will eventually use the
UART's polled I/O callbacks to interact with the user). This permission
also implies the amba-pl011 driver has already unmasked RX interrupts
(otherwise the FIQ handler will never trigger).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 99 ++++++++++++++++++++++++-----------------
 1 file changed, 58 insertions(+), 41 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index dacf0a0..778fd38 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -58,6 +58,7 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/sizes.h>
 #include <linux/io.h>
+#include <linux/kgdb.h>
 
 #define UART_NR			14
 
@@ -1416,8 +1417,63 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
 	spin_unlock_irqrestore(&uap->port.lock, flags);
 }
 
+static int pl011_hwinit(struct uart_port *port)
+{
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	int retval;
+
+	/* Optionaly enable pins to be muxed in and configured */
+	pinctrl_pm_select_default_state(port->dev);
+
+	/*
+	 * Try to enable the clock producer.
+	 */
+	retval = clk_prepare_enable(uap->clk);
+	if (retval)
+		goto out;
+
+	uap->port.uartclk = clk_get_rate(uap->clk);
+
+	/* Clear pending error and receive interrupts */
+	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
+	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
+
+	/*
+	 * Save interrupts enable mask, and enable RX interrupts in case if
+	 * the interrupt is used for NMI entry.
+	 */
+	uap->im = readw(uap->port.membase + UART011_IMSC);
+	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
+
+	if (dev_get_platdata(uap->port.dev)) {
+		struct amba_pl011_data *plat;
+
+		plat = dev_get_platdata(uap->port.dev);
+		if (plat->init)
+			plat->init();
+	}
+	return 0;
+ out:
+	return retval;
+}
+
 #ifdef CONFIG_CONSOLE_POLL
 
+static int pl011_poll_init(struct uart_port *port)
+{
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	int retval;
+
+	retval = pl011_hwinit(port);
+
+#ifdef CONFIG_KGDB_FIQ
+	if (retval == 0)
+		kgdb_register_fiq(uap->port.irq);
+#endif
+
+	return retval;
+}
+
 static void pl011_quiesce_irqs(struct uart_port *port)
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1471,46 +1527,6 @@ static void pl011_put_poll_char(struct uart_port *port,
 
 #endif /* CONFIG_CONSOLE_POLL */
 
-static int pl011_hwinit(struct uart_port *port)
-{
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
-	int retval;
-
-	/* Optionaly enable pins to be muxed in and configured */
-	pinctrl_pm_select_default_state(port->dev);
-
-	/*
-	 * Try to enable the clock producer.
-	 */
-	retval = clk_prepare_enable(uap->clk);
-	if (retval)
-		goto out;
-
-	uap->port.uartclk = clk_get_rate(uap->clk);
-
-	/* Clear pending error and receive interrupts */
-	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
-	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
-
-	/*
-	 * Save interrupts enable mask, and enable RX interrupts in case if
-	 * the interrupt is used for NMI entry.
-	 */
-	uap->im = readw(uap->port.membase + UART011_IMSC);
-	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
-
-	if (dev_get_platdata(uap->port.dev)) {
-		struct amba_pl011_data *plat;
-
-		plat = dev_get_platdata(uap->port.dev);
-		if (plat->init)
-			plat->init();
-	}
-	return 0;
- out:
-	return retval;
-}
-
 static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
 {
 	writew(lcr_h, uap->port.membase + uap->lcrh_rx);
@@ -1890,7 +1906,7 @@ static struct uart_ops amba_pl011_pops = {
 	.config_port	= pl011_config_port,
 	.verify_port	= pl011_verify_port,
 #ifdef CONFIG_CONSOLE_POLL
-	.poll_init     = pl011_hwinit,
+	.poll_init     = pl011_poll_init,
 	.poll_get_char = pl011_get_poll_char,
 	.poll_put_char = pl011_put_poll_char,
 #endif
@@ -2169,6 +2185,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
 		uart_unregister_driver(&amba_reg);
 		pl011_dma_remove(uap);
 	}
+
  out:
 	return ret;
 }
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v3 8/9] serial: amba-pl011: Pass on FIQ information to KGDB.
@ 2014-06-05  9:53       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: linux-arm-kernel

If the AMBA bus has provided the pl011 with a FIQ resource (i.e. a
second IRQ) then speculatively register it with KGDB when the polling
driver is initialized.

By providing this information to KGDB the serial driver offers
"permission" for KGDB to route the UART interrupt signal from the
drivers own handler to KGDBs FIQ handler (which will eventually use the
UART's polled I/O callbacks to interact with the user). This permission
also implies the amba-pl011 driver has already unmasked RX interrupts
(otherwise the FIQ handler will never trigger).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 99 ++++++++++++++++++++++++-----------------
 1 file changed, 58 insertions(+), 41 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index dacf0a0..778fd38 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -58,6 +58,7 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/sizes.h>
 #include <linux/io.h>
+#include <linux/kgdb.h>
 
 #define UART_NR			14
 
@@ -1416,8 +1417,63 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
 	spin_unlock_irqrestore(&uap->port.lock, flags);
 }
 
+static int pl011_hwinit(struct uart_port *port)
+{
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	int retval;
+
+	/* Optionaly enable pins to be muxed in and configured */
+	pinctrl_pm_select_default_state(port->dev);
+
+	/*
+	 * Try to enable the clock producer.
+	 */
+	retval = clk_prepare_enable(uap->clk);
+	if (retval)
+		goto out;
+
+	uap->port.uartclk = clk_get_rate(uap->clk);
+
+	/* Clear pending error and receive interrupts */
+	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
+	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
+
+	/*
+	 * Save interrupts enable mask, and enable RX interrupts in case if
+	 * the interrupt is used for NMI entry.
+	 */
+	uap->im = readw(uap->port.membase + UART011_IMSC);
+	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
+
+	if (dev_get_platdata(uap->port.dev)) {
+		struct amba_pl011_data *plat;
+
+		plat = dev_get_platdata(uap->port.dev);
+		if (plat->init)
+			plat->init();
+	}
+	return 0;
+ out:
+	return retval;
+}
+
 #ifdef CONFIG_CONSOLE_POLL
 
+static int pl011_poll_init(struct uart_port *port)
+{
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	int retval;
+
+	retval = pl011_hwinit(port);
+
+#ifdef CONFIG_KGDB_FIQ
+	if (retval == 0)
+		kgdb_register_fiq(uap->port.irq);
+#endif
+
+	return retval;
+}
+
 static void pl011_quiesce_irqs(struct uart_port *port)
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1471,46 +1527,6 @@ static void pl011_put_poll_char(struct uart_port *port,
 
 #endif /* CONFIG_CONSOLE_POLL */
 
-static int pl011_hwinit(struct uart_port *port)
-{
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
-	int retval;
-
-	/* Optionaly enable pins to be muxed in and configured */
-	pinctrl_pm_select_default_state(port->dev);
-
-	/*
-	 * Try to enable the clock producer.
-	 */
-	retval = clk_prepare_enable(uap->clk);
-	if (retval)
-		goto out;
-
-	uap->port.uartclk = clk_get_rate(uap->clk);
-
-	/* Clear pending error and receive interrupts */
-	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
-	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
-
-	/*
-	 * Save interrupts enable mask, and enable RX interrupts in case if
-	 * the interrupt is used for NMI entry.
-	 */
-	uap->im = readw(uap->port.membase + UART011_IMSC);
-	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
-
-	if (dev_get_platdata(uap->port.dev)) {
-		struct amba_pl011_data *plat;
-
-		plat = dev_get_platdata(uap->port.dev);
-		if (plat->init)
-			plat->init();
-	}
-	return 0;
- out:
-	return retval;
-}
-
 static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
 {
 	writew(lcr_h, uap->port.membase + uap->lcrh_rx);
@@ -1890,7 +1906,7 @@ static struct uart_ops amba_pl011_pops = {
 	.config_port	= pl011_config_port,
 	.verify_port	= pl011_verify_port,
 #ifdef CONFIG_CONSOLE_POLL
-	.poll_init     = pl011_hwinit,
+	.poll_init     = pl011_poll_init,
 	.poll_get_char = pl011_get_poll_char,
 	.poll_put_char = pl011_put_poll_char,
 #endif
@@ -2169,6 +2185,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
 		uart_unregister_driver(&amba_reg);
 		pl011_dma_remove(uap);
 	}
+
  out:
 	return ret;
 }
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v3 9/9] serial: asc: Add support for KGDB's FIQ/NMI mode
  2014-06-05  9:53     ` Daniel Thompson
@ 2014-06-05  9:53       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij,
	Patrice Chotard, Jiri Slaby, Daniel Thompson, Dirk Behme,
	Russell King, Nicolas Pitre, Ian Campbell, Anton Vorontsov,
	David A. Long, linux-serial, Catalin Marinas, kernel-team,
	devicetree, linaro-kernel, Pawel Moll, patches, Kumar Gala,
	Rob Herring, John Stultz, Thomas Gleixner, linux-arm-kernel

If the platform bus has provided the st-asc with a FIQ resource (i.e. a
second IRQ) then speculatively register it with KGDB when the polling
driver is initialized.

By providing this information to KGDB the serial driver offers
"permission" for KGDB to route the UART interrupt signal from the
drivers own handler to KGDBs FIQ handler (which will eventually use the
UART's polled I/O callbacks to interact with the user). This permission
also implies the st-asc driver has already unmasked RX interrupts
(otherwise the FIQ handler will never trigger). This unmask is copied
from similar code in amba-pl011.c .

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel@stlinux.com
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index c7f61ac..4f376d8 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -30,6 +30,7 @@
 #include <linux/of_platform.h>
 #include <linux/serial_core.h>
 #include <linux/clk.h>
+#include <linux/kgdb.h>
 
 #define DRIVER_NAME "st-asc"
 #define ASC_SERIAL_NAME "ttyAS"
@@ -613,6 +614,25 @@ asc_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+
+#ifdef CONFIG_KGDB_FIQ
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int asc_poll_init(struct uart_port *port)
+{
+	struct asc_port *ascport = container_of(port, struct asc_port, port);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(ascport->port.irq);
+
+	/* enable RX interrupts in case the interrupt is used for NMI entry. */
+	asc_enable_rx_interrupts(port);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 /*
  * Console polling routines for writing and reading from the uart while
  * in an interrupt or debug context (i.e. kgdb).
@@ -656,6 +676,9 @@ static struct uart_ops asc_uart_ops = {
 	.verify_port	= asc_verify_port,
 	.pm		= asc_pm,
 #ifdef CONFIG_CONSOLE_POLL
+#ifdef CONFIG_KGDB_FIQ
+	.poll_init     = asc_poll_init,
+#endif /* CONFIG_KGDB_FIQ */
 	.poll_get_char = asc_get_poll_char,
 	.poll_put_char = asc_put_poll_char,
 #endif /* CONFIG_CONSOLE_POLL */
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC v3 9/9] serial: asc: Add support for KGDB's FIQ/NMI mode
@ 2014-06-05  9:53       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05  9:53 UTC (permalink / raw)
  To: linux-arm-kernel

If the platform bus has provided the st-asc with a FIQ resource (i.e. a
second IRQ) then speculatively register it with KGDB when the polling
driver is initialized.

By providing this information to KGDB the serial driver offers
"permission" for KGDB to route the UART interrupt signal from the
drivers own handler to KGDBs FIQ handler (which will eventually use the
UART's polled I/O callbacks to interact with the user). This permission
also implies the st-asc driver has already unmasked RX interrupts
(otherwise the FIQ handler will never trigger). This unmask is copied
from similar code in amba-pl011.c .

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel at stlinux.com
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index c7f61ac..4f376d8 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -30,6 +30,7 @@
 #include <linux/of_platform.h>
 #include <linux/serial_core.h>
 #include <linux/clk.h>
+#include <linux/kgdb.h>
 
 #define DRIVER_NAME "st-asc"
 #define ASC_SERIAL_NAME "ttyAS"
@@ -613,6 +614,25 @@ asc_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+
+#ifdef CONFIG_KGDB_FIQ
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int asc_poll_init(struct uart_port *port)
+{
+	struct asc_port *ascport = container_of(port, struct asc_port, port);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(ascport->port.irq);
+
+	/* enable RX interrupts in case the interrupt is used for NMI entry. */
+	asc_enable_rx_interrupts(port);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 /*
  * Console polling routines for writing and reading from the uart while
  * in an interrupt or debug context (i.e. kgdb).
@@ -656,6 +676,9 @@ static struct uart_ops asc_uart_ops = {
 	.verify_port	= asc_verify_port,
 	.pm		= asc_pm,
 #ifdef CONFIG_CONSOLE_POLL
+#ifdef CONFIG_KGDB_FIQ
+	.poll_init     = asc_poll_init,
+#endif /* CONFIG_KGDB_FIQ */
 	.poll_get_char = asc_get_poll_char,
 	.poll_put_char = asc_put_poll_char,
 #endif /* CONFIG_CONSOLE_POLL */
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* Re: [RFC v3 1/9] arm: fiq: arbitrary mappings from IRQ to FIQ virqs
  2014-06-05  9:53       ` Daniel Thompson
@ 2014-06-05 11:51         ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-06-05 11:51 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Mark Rutland, kernel, Catalin Marinas, Linus Walleij, Jiri Slaby,
	Dirk Behme, Nicolas Pitre, Fabio Estevam, patches,
	Anton Vorontsov, Kumar Gala, David A. Long, linux-serial,
	kgdb-bugreport, kernel-team, devicetree, linaro-kernel,
	Pawel Moll, Ian Campbell, Jason Wessel, Rob Herring, John Stultz,
	Thomas Gleixner, linux-arm-kernel, Greg Kroah-Hartman

On Thu, Jun 05, 2014 at 10:53:06AM +0100, Daniel Thompson wrote:
>  static int fiq_def_op(void *ref, int relinquish)
>  {
> -	if (!relinquish)
> +	if (!relinquish) {
> +		unsigned offset = FIQ_OFFSET;
> +		no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
>  		set_fiq_handler(&no_fiq_insn, sizeof(no_fiq_insn));
> +	}
...
>  void __init init_FIQ(int start)
>  {
> -	unsigned offset = FIQ_OFFSET;
> -	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
>  	fiq_start = start;
>  }

This is wrong - when the default handler is "reinstalled", this change has
the effect that we read the first instruction of the existing handler, and
then write that same instruction back, rather than replacing the first
instruction with the value that was there at boot.

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v3 1/9] arm: fiq: arbitrary mappings from IRQ to FIQ virqs
@ 2014-06-05 11:51         ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-06-05 11:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 05, 2014 at 10:53:06AM +0100, Daniel Thompson wrote:
>  static int fiq_def_op(void *ref, int relinquish)
>  {
> -	if (!relinquish)
> +	if (!relinquish) {
> +		unsigned offset = FIQ_OFFSET;
> +		no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
>  		set_fiq_handler(&no_fiq_insn, sizeof(no_fiq_insn));
> +	}
...
>  void __init init_FIQ(int start)
>  {
> -	unsigned offset = FIQ_OFFSET;
> -	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
>  	fiq_start = start;
>  }

This is wrong - when the default handler is "reinstalled", this change has
the effect that we read the first instruction of the existing handler, and
then write that same instruction back, rather than replacing the first
instruction with the value that was there at boot.

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [RFC v3 1/9] arm: fiq: arbitrary mappings from IRQ to FIQ virqs
  2014-06-05 11:51         ` Russell King - ARM Linux
@ 2014-06-05 13:08           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05 13:08 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Mark Rutland, kernel, Catalin Marinas, Linus Walleij, Jiri Slaby,
	Dirk Behme, Nicolas Pitre, Fabio Estevam, patches,
	Anton Vorontsov, Kumar Gala, David A. Long, linux-serial,
	kgdb-bugreport, kernel-team, devicetree, linaro-kernel,
	Pawel Moll, Ian Campbell, Jason Wessel, Rob Herring, John Stultz,
	Thomas Gleixner, linux-arm-kernel, Greg Kroah-Hartman

On 05/06/14 12:51, Russell King - ARM Linux wrote:
> On Thu, Jun 05, 2014 at 10:53:06AM +0100, Daniel Thompson wrote:
>>  static int fiq_def_op(void *ref, int relinquish)
>>  {
>> -	if (!relinquish)
>> +	if (!relinquish) {
>> +		unsigned offset = FIQ_OFFSET;
>> +		no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
>>  		set_fiq_handler(&no_fiq_insn, sizeof(no_fiq_insn));
>> +	}
> ...
>>  void __init init_FIQ(int start)
>>  {
>> -	unsigned offset = FIQ_OFFSET;
>> -	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
>>  	fiq_start = start;
>>  }
> 
> This is wrong - when the default handler is "reinstalled", this change has
> the effect that we read the first instruction of the existing handler, and
> then write that same instruction back, rather than replacing the first
> instruction with the value that was there at boot.

Thanks. I'll fix this.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v3 1/9] arm: fiq: arbitrary mappings from IRQ to FIQ virqs
@ 2014-06-05 13:08           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-05 13:08 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/06/14 12:51, Russell King - ARM Linux wrote:
> On Thu, Jun 05, 2014 at 10:53:06AM +0100, Daniel Thompson wrote:
>>  static int fiq_def_op(void *ref, int relinquish)
>>  {
>> -	if (!relinquish)
>> +	if (!relinquish) {
>> +		unsigned offset = FIQ_OFFSET;
>> +		no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
>>  		set_fiq_handler(&no_fiq_insn, sizeof(no_fiq_insn));
>> +	}
> ...
>>  void __init init_FIQ(int start)
>>  {
>> -	unsigned offset = FIQ_OFFSET;
>> -	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
>>  	fiq_start = start;
>>  }
> 
> This is wrong - when the default handler is "reinstalled", this change has
> the effect that we read the first instruction of the existing handler, and
> then write that same instruction back, rather than replacing the first
> instruction with the value that was there at boot.

Thanks. I'll fix this.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [RFC v3 3/9] irqchip: gic: Provide support for interrupt grouping
  2014-06-05  9:53       ` Daniel Thompson
@ 2014-06-05 19:50         ` Nicolas Pitre
  -1 siblings, 0 replies; 535+ messages in thread
From: Nicolas Pitre @ 2014-06-05 19:50 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Sricharan R,
	Colin Cross, Jiri Slaby, Dirk Behme, Russell King, patches,
	Anton Vorontsov, David A. Long, linux-serial, Catalin Marinas,
	kernel-team, devicetree, linaro-kernel, Jason Cooper, Pawel Moll,
	Ian Campbell, Kumar Gala, Rob Herring, John Stultz,
	Thomas Gleixner, linux-arm-kernel, Greg

On Thu, 5 Jun 2014, Daniel Thompson wrote:

> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index 57d165e..aa8efe4 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -408,13 +408,27 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
>  		writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
>  
>  	/*
> +	 * Set all global interrupts to be group 1.
> +	 *
> +	 * If grouping is not available (not implemented or prohibited by
> +	 * security mode) these registers a read-as-zero/write-ignored.
> +	 */
> +	for (i = 32; i < gic_irqs; i += 32)
> +		writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
> +
> +	/*
>  	 * Disable all interrupts.  Leave the PPI and SGIs alone
>  	 * as these enables are banked registers.
>  	 */
>  	for (i = 32; i < gic_irqs; i += 32)
>  		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
>  
> -	writel_relaxed(1, base + GIC_DIST_CTRL);
> +	/*
> +	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
> +	 * bit 1 ignored)
> +	 */
> +	writel_relaxed(GIC_DIST_CTRL_ENABLE_GRP0_BIT |
> +		       GIC_DIST_CTRL_ENABLE_GRP1_BIT, base + GIC_DIST_CTRL);

Could there be more meaningful defines than GIC_DIST_CTRL_ENABLE_GRP0_BIT
and GIC_DIST_CTRL_ENABLE_GRP1_BIT for those bits?  Otherwise the code 
would look just as clear and possibly cleaner by simply using 0x3.


Nicolas

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v3 3/9] irqchip: gic: Provide support for interrupt grouping
@ 2014-06-05 19:50         ` Nicolas Pitre
  0 siblings, 0 replies; 535+ messages in thread
From: Nicolas Pitre @ 2014-06-05 19:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 5 Jun 2014, Daniel Thompson wrote:

> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index 57d165e..aa8efe4 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -408,13 +408,27 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
>  		writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
>  
>  	/*
> +	 * Set all global interrupts to be group 1.
> +	 *
> +	 * If grouping is not available (not implemented or prohibited by
> +	 * security mode) these registers a read-as-zero/write-ignored.
> +	 */
> +	for (i = 32; i < gic_irqs; i += 32)
> +		writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
> +
> +	/*
>  	 * Disable all interrupts.  Leave the PPI and SGIs alone
>  	 * as these enables are banked registers.
>  	 */
>  	for (i = 32; i < gic_irqs; i += 32)
>  		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
>  
> -	writel_relaxed(1, base + GIC_DIST_CTRL);
> +	/*
> +	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
> +	 * bit 1 ignored)
> +	 */
> +	writel_relaxed(GIC_DIST_CTRL_ENABLE_GRP0_BIT |
> +		       GIC_DIST_CTRL_ENABLE_GRP1_BIT, base + GIC_DIST_CTRL);

Could there be more meaningful defines than GIC_DIST_CTRL_ENABLE_GRP0_BIT
and GIC_DIST_CTRL_ENABLE_GRP1_BIT for those bits?  Otherwise the code 
would look just as clear and possibly cleaner by simply using 0x3.


Nicolas

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [RFC v3 4/9] irqchip: gic: Introduce shadow irqs for FIQ
  2014-06-05  9:53       ` Daniel Thompson
@ 2014-06-06  7:46         ` Peter De Schrijver
  -1 siblings, 0 replies; 535+ messages in thread
From: Peter De Schrijver @ 2014-06-06  7:46 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Mark Rutland, Nicolas Pitre, kernel, kgdb-bugreport,
	Linus Walleij, Sricharan R, Colin Cross, Jiri Slaby, Dirk Behme,
	Russell King, Nicolas Pitre, patches, Anton Vorontsov,
	David A. Long, linux-serial, Catalin Marinas, kernel-team,
	devicetree, linaro-kernel, Jason Cooper

On Thu, Jun 05, 2014 at 11:53:09AM +0200, Daniel Thompson wrote:
> This patch registers two virqs for each interrupt source it supports.
> Using multiple virqs allows the GIC driver to automatically modify the group
> register, allowing the new virqs to be used as argument to enable_fiq().
> This also allows FIQ resources to be described in the device tree's
> interrupt list using a special flag (currently 0x80).
> 
> Both these aspects combine and allow a driver to deploy a FIQ handler
> without any machine specific knowledge; it can be used effectively on
> multi-arch kernels.
> 
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Jason Cooper <jason@lakedaemon.net>
> Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
> Cc: Christoffer Dall <christoffer.dall@linaro.org>
> Cc: Sricharan R <r.sricharan@ti.com>
> ---
>  drivers/irqchip/irq-gic.c | 62 ++++++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 56 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index aa8efe4..9a4712d 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -42,12 +42,17 @@
>  #include <linux/irqchip/chained_irq.h>
>  #include <linux/irqchip/arm-gic.h>
>  
> +#ifdef CONFIG_FIQ
> +#include <asm/fiq.h>
> +#endif
>  #include <asm/irq.h>
>  #include <asm/exception.h>
>  #include <asm/smp_plat.h>
>  
>  #include "irqchip.h"
>  
> +#define GIC_INTSPEC_IRQ_IS_FIQ (1 << 7)
> +
>  union gic_base {
>  	void __iomem *common_base;
>  	void __percpu * __iomem *percpu_base;
> @@ -65,6 +70,7 @@ struct gic_chip_data {
>  #endif
>  	struct irq_domain *domain;
>  	unsigned int gic_irqs;
> +	unsigned int fiq_shadow_offset;
>  #ifdef CONFIG_GIC_NON_BANKED
>  	void __iomem *(*get_base)(union gic_base *);
>  #endif
> @@ -143,11 +149,34 @@ static inline void __iomem *gic_cpu_base(struct irq_data *d)
>  	return gic_data_cpu_base(gic_data);
>  }
>  
> +static inline bool gic_is_fiq(struct irq_data *d)
> +{
> +	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
> +	return d->hwirq > gic_data->gic_irqs;
> +}
> +
>  static inline unsigned int gic_irq(struct irq_data *d)
>  {
> +	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
> +	if (gic_is_fiq(d))
> +		return d->hwirq - gic_data->fiq_shadow_offset;
>  	return d->hwirq;
>  }
>  
> +static void gic_set_group_irq(struct irq_data *d, int group)
> +{
> +	unsigned int reg = gic_irq(d) / 32 * 4;
> +	u32 mask = 1 << (gic_irq(d) % 32);
> +	u32 val;
> +
> +	val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + reg);
> +	if (group)
> +		val |= mask;
> +	else
> +		val &= ~mask;
> +	writel_relaxed(val, gic_dist_base(d) + GIC_DIST_IGROUP + reg);
> +}
> +
>  /*
>   * Routines to acknowledge, disable and enable interrupts
>   */
> @@ -159,6 +188,8 @@ static void gic_mask_irq(struct irq_data *d)
>  	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
>  	if (gic_arch_extn.irq_mask)
>  		gic_arch_extn.irq_mask(d);
> +	if (gic_is_fiq(d))
> +		gic_set_group_irq(d, 1);
>  	raw_spin_unlock(&irq_controller_lock);
>  }
>  
> @@ -167,6 +198,8 @@ static void gic_unmask_irq(struct irq_data *d)
>  	u32 mask = 1 << (gic_irq(d) % 32);
>  
>  	raw_spin_lock(&irq_controller_lock);
> +	if (gic_is_fiq(d))
> +		gic_set_group_irq(d, 0);
>  	if (gic_arch_extn.irq_unmask)
>  		gic_arch_extn.irq_unmask(d);
>  	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
> @@ -940,7 +973,12 @@ static int gic_routable_irq_domain_xlate(struct irq_domain *d,
>  				unsigned long *out_hwirq,
>  				unsigned int *out_type)
>  {
> +	struct gic_chip_data *gic_data = d->host_data;
>  	*out_hwirq += 16;
> +
> +	if (intspec[2] & GIC_INTSPEC_IRQ_IS_FIQ)
> +		*out_hwirq += gic_data->fiq_shadow_offset;
> +
>  	return 0;
>  }
>  
> @@ -1026,10 +1064,11 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>  	gic->gic_irqs = gic_irqs;
>  
>  	gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
> +	gic->fiq_shadow_offset = gic_irqs;
>  
>  	if (of_property_read_u32(node, "arm,routable-irqs",
>  				 &nr_routable_irqs)) {
> -		irq_base = irq_alloc_descs(irq_start, 16, gic_irqs,
> +		irq_base = irq_alloc_descs(irq_start, 16, 2 * gic_irqs,
>  					   numa_node_id());
>  		if (IS_ERR_VALUE(irq_base)) {
>  			WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
> @@ -1037,17 +1076,28 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>  			irq_base = irq_start;
>  		}
>  
> -		gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
> -					hwirq_base, &gic_irq_domain_ops, gic);
> +		gic->domain =
> +		    irq_domain_add_legacy(node, 2 * gic_irqs, irq_base,
> +					  hwirq_base, &gic_irq_domain_ops, gic);
>  	} else {
> -		gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
> -						    &gic_irq_domain_ops,
> -						    gic);
> +		gic->domain = irq_domain_add_linear(node, 2 * nr_routable_irqs,
> +						    &gic_irq_domain_ops, gic);
>  	}
>  
>  	if (WARN_ON(!gic->domain))
>  		return;
>  
> +#ifdef CONFIG_FIQ
> +	/* FIQ can only be supported on platforms without an extended irq_eoi
> +	 * method (otherwise we take a lock during irq_eoi handling).
> +	 */
> +	if (!gic_arch_extn.irq_eoi)
> +		fiq_add_mapping(
> +		    irq_linear_revmap(gic->domain, hwirq_base),
> +		    irq_linear_revmap(gic->domain, hwirq_base + gic_irqs),
> +		    gic_irqs);
> +#endif

This is rather unfortunate. On Tegra for example we don't need a lock for the
irq_eoi because the eoi ack can be handled with a single write to the
appropriate irq ack register.

Cheers,

Peter.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v3 4/9] irqchip: gic: Introduce shadow irqs for FIQ
@ 2014-06-06  7:46         ` Peter De Schrijver
  0 siblings, 0 replies; 535+ messages in thread
From: Peter De Schrijver @ 2014-06-06  7:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 05, 2014 at 11:53:09AM +0200, Daniel Thompson wrote:
> This patch registers two virqs for each interrupt source it supports.
> Using multiple virqs allows the GIC driver to automatically modify the group
> register, allowing the new virqs to be used as argument to enable_fiq().
> This also allows FIQ resources to be described in the device tree's
> interrupt list using a special flag (currently 0x80).
> 
> Both these aspects combine and allow a driver to deploy a FIQ handler
> without any machine specific knowledge; it can be used effectively on
> multi-arch kernels.
> 
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Jason Cooper <jason@lakedaemon.net>
> Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
> Cc: Christoffer Dall <christoffer.dall@linaro.org>
> Cc: Sricharan R <r.sricharan@ti.com>
> ---
>  drivers/irqchip/irq-gic.c | 62 ++++++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 56 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index aa8efe4..9a4712d 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -42,12 +42,17 @@
>  #include <linux/irqchip/chained_irq.h>
>  #include <linux/irqchip/arm-gic.h>
>  
> +#ifdef CONFIG_FIQ
> +#include <asm/fiq.h>
> +#endif
>  #include <asm/irq.h>
>  #include <asm/exception.h>
>  #include <asm/smp_plat.h>
>  
>  #include "irqchip.h"
>  
> +#define GIC_INTSPEC_IRQ_IS_FIQ (1 << 7)
> +
>  union gic_base {
>  	void __iomem *common_base;
>  	void __percpu * __iomem *percpu_base;
> @@ -65,6 +70,7 @@ struct gic_chip_data {
>  #endif
>  	struct irq_domain *domain;
>  	unsigned int gic_irqs;
> +	unsigned int fiq_shadow_offset;
>  #ifdef CONFIG_GIC_NON_BANKED
>  	void __iomem *(*get_base)(union gic_base *);
>  #endif
> @@ -143,11 +149,34 @@ static inline void __iomem *gic_cpu_base(struct irq_data *d)
>  	return gic_data_cpu_base(gic_data);
>  }
>  
> +static inline bool gic_is_fiq(struct irq_data *d)
> +{
> +	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
> +	return d->hwirq > gic_data->gic_irqs;
> +}
> +
>  static inline unsigned int gic_irq(struct irq_data *d)
>  {
> +	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
> +	if (gic_is_fiq(d))
> +		return d->hwirq - gic_data->fiq_shadow_offset;
>  	return d->hwirq;
>  }
>  
> +static void gic_set_group_irq(struct irq_data *d, int group)
> +{
> +	unsigned int reg = gic_irq(d) / 32 * 4;
> +	u32 mask = 1 << (gic_irq(d) % 32);
> +	u32 val;
> +
> +	val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + reg);
> +	if (group)
> +		val |= mask;
> +	else
> +		val &= ~mask;
> +	writel_relaxed(val, gic_dist_base(d) + GIC_DIST_IGROUP + reg);
> +}
> +
>  /*
>   * Routines to acknowledge, disable and enable interrupts
>   */
> @@ -159,6 +188,8 @@ static void gic_mask_irq(struct irq_data *d)
>  	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
>  	if (gic_arch_extn.irq_mask)
>  		gic_arch_extn.irq_mask(d);
> +	if (gic_is_fiq(d))
> +		gic_set_group_irq(d, 1);
>  	raw_spin_unlock(&irq_controller_lock);
>  }
>  
> @@ -167,6 +198,8 @@ static void gic_unmask_irq(struct irq_data *d)
>  	u32 mask = 1 << (gic_irq(d) % 32);
>  
>  	raw_spin_lock(&irq_controller_lock);
> +	if (gic_is_fiq(d))
> +		gic_set_group_irq(d, 0);
>  	if (gic_arch_extn.irq_unmask)
>  		gic_arch_extn.irq_unmask(d);
>  	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
> @@ -940,7 +973,12 @@ static int gic_routable_irq_domain_xlate(struct irq_domain *d,
>  				unsigned long *out_hwirq,
>  				unsigned int *out_type)
>  {
> +	struct gic_chip_data *gic_data = d->host_data;
>  	*out_hwirq += 16;
> +
> +	if (intspec[2] & GIC_INTSPEC_IRQ_IS_FIQ)
> +		*out_hwirq += gic_data->fiq_shadow_offset;
> +
>  	return 0;
>  }
>  
> @@ -1026,10 +1064,11 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>  	gic->gic_irqs = gic_irqs;
>  
>  	gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
> +	gic->fiq_shadow_offset = gic_irqs;
>  
>  	if (of_property_read_u32(node, "arm,routable-irqs",
>  				 &nr_routable_irqs)) {
> -		irq_base = irq_alloc_descs(irq_start, 16, gic_irqs,
> +		irq_base = irq_alloc_descs(irq_start, 16, 2 * gic_irqs,
>  					   numa_node_id());
>  		if (IS_ERR_VALUE(irq_base)) {
>  			WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
> @@ -1037,17 +1076,28 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>  			irq_base = irq_start;
>  		}
>  
> -		gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
> -					hwirq_base, &gic_irq_domain_ops, gic);
> +		gic->domain =
> +		    irq_domain_add_legacy(node, 2 * gic_irqs, irq_base,
> +					  hwirq_base, &gic_irq_domain_ops, gic);
>  	} else {
> -		gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
> -						    &gic_irq_domain_ops,
> -						    gic);
> +		gic->domain = irq_domain_add_linear(node, 2 * nr_routable_irqs,
> +						    &gic_irq_domain_ops, gic);
>  	}
>  
>  	if (WARN_ON(!gic->domain))
>  		return;
>  
> +#ifdef CONFIG_FIQ
> +	/* FIQ can only be supported on platforms without an extended irq_eoi
> +	 * method (otherwise we take a lock during irq_eoi handling).
> +	 */
> +	if (!gic_arch_extn.irq_eoi)
> +		fiq_add_mapping(
> +		    irq_linear_revmap(gic->domain, hwirq_base),
> +		    irq_linear_revmap(gic->domain, hwirq_base + gic_irqs),
> +		    gic_irqs);
> +#endif

This is rather unfortunate. On Tegra for example we don't need a lock for the
irq_eoi because the eoi ack can be handled with a single write to the
appropriate irq ack register.

Cheers,

Peter.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [RFC v3 4/9] irqchip: gic: Introduce shadow irqs for FIQ
  2014-06-06  7:46         ` Peter De Schrijver
@ 2014-06-06  9:23           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-06  9:23 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Mark Rutland, Nicolas Pitre, kernel, kgdb-bugreport,
	Linus Walleij, Sricharan R, Colin Cross, Jiri Slaby, Dirk Behme,
	Russell King, Nicolas Pitre, patches, Anton Vorontsov,
	David A. Long, linux-serial, Catalin Marinas, kernel-team,
	devicetree, linaro-kernel, Jason Cooper

On 06/06/14 08:46, Peter De Schrijver wrote:
>> @@ -1037,17 +1076,28 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>>  			irq_base = irq_start;
>>  		}
>>  
>> -		gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
>> -					hwirq_base, &gic_irq_domain_ops, gic);
>> +		gic->domain =
>> +		    irq_domain_add_legacy(node, 2 * gic_irqs, irq_base,
>> +					  hwirq_base, &gic_irq_domain_ops, gic);
>>  	} else {
>> -		gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
>> -						    &gic_irq_domain_ops,
>> -						    gic);
>> +		gic->domain = irq_domain_add_linear(node, 2 * nr_routable_irqs,
>> +						    &gic_irq_domain_ops, gic);
>>  	}
>>  
>>  	if (WARN_ON(!gic->domain))
>>  		return;
>>  
>> +#ifdef CONFIG_FIQ
>> +	/* FIQ can only be supported on platforms without an extended irq_eoi
>> +	 * method (otherwise we take a lock during irq_eoi handling).
>> +	 */
>> +	if (!gic_arch_extn.irq_eoi)
>> +		fiq_add_mapping(
>> +		    irq_linear_revmap(gic->domain, hwirq_base),
>> +		    irq_linear_revmap(gic->domain, hwirq_base + gic_irqs),
>> +		    gic_irqs);
>> +#endif
> 
> This is rather unfortunate. On Tegra for example we don't need a lock for the
> irq_eoi because the eoi ack can be handled with a single write to the
> appropriate irq ack register.

I believe that Tegra is the only platform that uses this hook so should
be safe to remove the locks from gic_irq_eoi().

Certainly looking back at the code history and the mailing list
discussions around this code[1] I cannot see any reasoning about the
locks that I have missed.

Any objections to just nuking the locks?


Daniel.


[1]
http://thread.gmane.org/gmane.linux.ports.arm.kernel/107474
http://thread.gmane.org/gmane.linux.ports.arm.kernel/108361
http://thread.gmane.org/gmane.linux.ports.arm.kernel/109690

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v3 4/9] irqchip: gic: Introduce shadow irqs for FIQ
@ 2014-06-06  9:23           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-06  9:23 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/06/14 08:46, Peter De Schrijver wrote:
>> @@ -1037,17 +1076,28 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>>  			irq_base = irq_start;
>>  		}
>>  
>> -		gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
>> -					hwirq_base, &gic_irq_domain_ops, gic);
>> +		gic->domain =
>> +		    irq_domain_add_legacy(node, 2 * gic_irqs, irq_base,
>> +					  hwirq_base, &gic_irq_domain_ops, gic);
>>  	} else {
>> -		gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
>> -						    &gic_irq_domain_ops,
>> -						    gic);
>> +		gic->domain = irq_domain_add_linear(node, 2 * nr_routable_irqs,
>> +						    &gic_irq_domain_ops, gic);
>>  	}
>>  
>>  	if (WARN_ON(!gic->domain))
>>  		return;
>>  
>> +#ifdef CONFIG_FIQ
>> +	/* FIQ can only be supported on platforms without an extended irq_eoi
>> +	 * method (otherwise we take a lock during irq_eoi handling).
>> +	 */
>> +	if (!gic_arch_extn.irq_eoi)
>> +		fiq_add_mapping(
>> +		    irq_linear_revmap(gic->domain, hwirq_base),
>> +		    irq_linear_revmap(gic->domain, hwirq_base + gic_irqs),
>> +		    gic_irqs);
>> +#endif
> 
> This is rather unfortunate. On Tegra for example we don't need a lock for the
> irq_eoi because the eoi ack can be handled with a single write to the
> appropriate irq ack register.

I believe that Tegra is the only platform that uses this hook so should
be safe to remove the locks from gic_irq_eoi().

Certainly looking back at the code history and the mailing list
discussions around this code[1] I cannot see any reasoning about the
locks that I have missed.

Any objections to just nuking the locks?


Daniel.


[1]
http://thread.gmane.org/gmane.linux.ports.arm.kernel/107474
http://thread.gmane.org/gmane.linux.ports.arm.kernel/108361
http://thread.gmane.org/gmane.linux.ports.arm.kernel/109690

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [RFC v3 1/9] arm: fiq: arbitrary mappings from IRQ to FIQ virqs
  2014-06-05  9:53       ` Daniel Thompson
@ 2014-06-12  8:37         ` Linus Walleij
  -1 siblings, 0 replies; 535+ messages in thread
From: Linus Walleij @ 2014-06-12  8:37 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Mark Rutland, kernel, kgdb-bugreport, Jiri Slaby, Dirk Behme,
	Russell King, Nicolas Pitre, Fabio Estevam, Patch Tracking,
	Anton Vorontsov, Kumar Gala, David A. Long, linux-serial,
	Catalin Marinas, kernel-team, devicetree, linaro-kernel,
	Pawel Moll, Ian Campbell, Jason Wessel, Rob Herring, John Stultz,
	Thomas Gleixner

On Thu, Jun 5, 2014 at 11:53 AM, Daniel Thompson
<daniel.thompson@linaro.org> wrote:

> Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
> virq into a FIQ virq. This is too inflexible for multi-platform kernels
> and makes runtime error checking impossible.
>
> We solve this by introducing a flexible mapping that allows interrupt
> controllers that support FIQ to register those mappings. This, in turn,
> makes it much possible for drivers in DT kernels to gain access to
> FIQ virqs.

I always had a big problem with the term "virq" which I take to mean
"virtual IRQ".

The distinction is:

- Hardware IRQ offsets/numbers - a number encoded in HW
  specs which we usually call hwirqs

- Linux IRQ numbers - just some number

Sometimes, just sometimes, the Linux IRQ number matches the
HW numbers, and then I guess the IRQ is regarded "non-virtual".
The only real effect being that the numbers shown in
/proc/interrupts are the same in both columns... the leftmost
column with the Linux IRQ number and the one right next to
the IRQ controller name which is the hwirq local offset.

But all Linux IRQ numbers are virtual by definition. It's just some
number that the kernel use as a cookie to look up the irq_desc.
And one day we may get rid of IRQ numbers altogether.

I would prefer just to s/virq/irq/g on this patch or if that is
disturbing something more to the point like s/virq/linux_irq/g.

Maybe this is a pointless battle, but still...

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v3 1/9] arm: fiq: arbitrary mappings from IRQ to FIQ virqs
@ 2014-06-12  8:37         ` Linus Walleij
  0 siblings, 0 replies; 535+ messages in thread
From: Linus Walleij @ 2014-06-12  8:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 5, 2014 at 11:53 AM, Daniel Thompson
<daniel.thompson@linaro.org> wrote:

> Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
> virq into a FIQ virq. This is too inflexible for multi-platform kernels
> and makes runtime error checking impossible.
>
> We solve this by introducing a flexible mapping that allows interrupt
> controllers that support FIQ to register those mappings. This, in turn,
> makes it much possible for drivers in DT kernels to gain access to
> FIQ virqs.

I always had a big problem with the term "virq" which I take to mean
"virtual IRQ".

The distinction is:

- Hardware IRQ offsets/numbers - a number encoded in HW
  specs which we usually call hwirqs

- Linux IRQ numbers - just some number

Sometimes, just sometimes, the Linux IRQ number matches the
HW numbers, and then I guess the IRQ is regarded "non-virtual".
The only real effect being that the numbers shown in
/proc/interrupts are the same in both columns... the leftmost
column with the Linux IRQ number and the one right next to
the IRQ controller name which is the hwirq local offset.

But all Linux IRQ numbers are virtual by definition. It's just some
number that the kernel use as a cookie to look up the irq_desc.
And one day we may get rid of IRQ numbers altogether.

I would prefer just to s/virq/irq/g on this patch or if that is
disturbing something more to the point like s/virq/linux_irq/g.

Maybe this is a pointless battle, but still...

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [RFC v3 1/9] arm: fiq: arbitrary mappings from IRQ to FIQ virqs
  2014-06-12  8:37         ` Linus Walleij
@ 2014-06-12  9:54           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-12  9:54 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Mark Rutland, kernel, kgdb-bugreport, Jiri Slaby, Dirk Behme,
	Russell King, Nicolas Pitre, Fabio Estevam, Patch Tracking,
	Anton Vorontsov, Kumar Gala, David A. Long, linux-serial,
	Catalin Marinas, kernel-team, devicetree, linaro-kernel,
	Pawel Moll, Ian Campbell, Jason Wessel, Rob Herring, John Stultz,
	Thomas Gleixner

On 12/06/14 09:37, Linus Walleij wrote:
> On Thu, Jun 5, 2014 at 11:53 AM, Daniel Thompson
> <daniel.thompson@linaro.org> wrote:
> 
>> Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
>> virq into a FIQ virq. This is too inflexible for multi-platform kernels
>> and makes runtime error checking impossible.
>>
>> We solve this by introducing a flexible mapping that allows interrupt
>> controllers that support FIQ to register those mappings. This, in turn,
>> makes it much possible for drivers in DT kernels to gain access to
>> FIQ virqs.
> 
> I always had a big problem with the term "virq" which I take to mean
> "virtual IRQ".

So do I...

That said, I think of it as the virtual as in virtual memory rather the
virtual contained within virtualization.


> The distinction is:
> 
> - Hardware IRQ offsets/numbers - a number encoded in HW
>   specs which we usually call hwirqs
> 
> - Linux IRQ numbers - just some number
> 
> Sometimes, just sometimes, the Linux IRQ number matches the
> HW numbers, and then I guess the IRQ is regarded "non-virtual".
> The only real effect being that the numbers shown in
> /proc/interrupts are the same in both columns... the leftmost
> column with the Linux IRQ number and the one right next to
> the IRQ controller name which is the hwirq local offset.
> 
> But all Linux IRQ numbers are virtual by definition. It's just some
> number that the kernel use as a cookie to look up the irq_desc.
> And one day we may get rid of IRQ numbers altogether.
> 
> I would prefer just to s/virq/irq/g on this patch or if that is
> disturbing something more to the point like s/virq/linux_irq/g.
> 
> Maybe this is a pointless battle, but still...

I chose the term not because I have a personal attachement but because
that is how they are spelt in the C symbols within irqdomain.[ch] which
my patch relies upon heavily. The english documentation and comments is
(very nearly) strict about using "Linux IRQ" so I'll happily change all
the English text.

However...

I don't fancy s/virq/irq/ since this risks confusion between Linux irq
and ARM IRQ and I don't fancy s/virq/linux_irq/ because in the kernel
today virq is ~750x more frequenctly used than 'linux_irq' (git grep and
wc suggests its 1507 versus 2).

How strongly do you feel about this?

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v3 1/9] arm: fiq: arbitrary mappings from IRQ to FIQ virqs
@ 2014-06-12  9:54           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-12  9:54 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/06/14 09:37, Linus Walleij wrote:
> On Thu, Jun 5, 2014 at 11:53 AM, Daniel Thompson
> <daniel.thompson@linaro.org> wrote:
> 
>> Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
>> virq into a FIQ virq. This is too inflexible for multi-platform kernels
>> and makes runtime error checking impossible.
>>
>> We solve this by introducing a flexible mapping that allows interrupt
>> controllers that support FIQ to register those mappings. This, in turn,
>> makes it much possible for drivers in DT kernels to gain access to
>> FIQ virqs.
> 
> I always had a big problem with the term "virq" which I take to mean
> "virtual IRQ".

So do I...

That said, I think of it as the virtual as in virtual memory rather the
virtual contained within virtualization.


> The distinction is:
> 
> - Hardware IRQ offsets/numbers - a number encoded in HW
>   specs which we usually call hwirqs
> 
> - Linux IRQ numbers - just some number
> 
> Sometimes, just sometimes, the Linux IRQ number matches the
> HW numbers, and then I guess the IRQ is regarded "non-virtual".
> The only real effect being that the numbers shown in
> /proc/interrupts are the same in both columns... the leftmost
> column with the Linux IRQ number and the one right next to
> the IRQ controller name which is the hwirq local offset.
> 
> But all Linux IRQ numbers are virtual by definition. It's just some
> number that the kernel use as a cookie to look up the irq_desc.
> And one day we may get rid of IRQ numbers altogether.
> 
> I would prefer just to s/virq/irq/g on this patch or if that is
> disturbing something more to the point like s/virq/linux_irq/g.
> 
> Maybe this is a pointless battle, but still...

I chose the term not because I have a personal attachement but because
that is how they are spelt in the C symbols within irqdomain.[ch] which
my patch relies upon heavily. The english documentation and comments is
(very nearly) strict about using "Linux IRQ" so I'll happily change all
the English text.

However...

I don't fancy s/virq/irq/ since this risks confusion between Linux irq
and ARM IRQ and I don't fancy s/virq/linux_irq/ because in the kernel
today virq is ~750x more frequenctly used than 'linux_irq' (git grep and
wc suggests its 1507 versus 2).

How strongly do you feel about this?

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [RFC v3 1/9] arm: fiq: arbitrary mappings from IRQ to FIQ virqs
  2014-06-05  9:53       ` Daniel Thompson
@ 2014-06-13 14:29         ` Rob Herring
  -1 siblings, 0 replies; 535+ messages in thread
From: Rob Herring @ 2014-06-13 14:29 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Dirk Behme, Russell King, Nicolas Pitre, Fabio Estevam,
	Linaro Patches, Anton Vorontsov, Kumar Gala, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, Ian Campbell, Jason Wessel,
	Rob Herring

On Thu, Jun 5, 2014 at 4:53 AM, Daniel Thompson
<daniel.thompson@linaro.org> wrote:
> Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
> virq into a FIQ virq. This is too inflexible for multi-platform kernels
> and makes runtime error checking impossible.
>
> We solve this by introducing a flexible mapping that allows interrupt
> controllers that support FIQ to register those mappings. This, in turn,
> makes it much possible for drivers in DT kernels to gain access to
> FIQ virqs.

I don't get why you need a separate linux irq numbers for FIQ. Isn't
enabling FIQ simply a property of an irq like edge vs. level trigger?
Also, given the constraints on FIQ, we can't really have more that 1
IRQ assigned to FIQ.

Rob

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v3 1/9] arm: fiq: arbitrary mappings from IRQ to FIQ virqs
@ 2014-06-13 14:29         ` Rob Herring
  0 siblings, 0 replies; 535+ messages in thread
From: Rob Herring @ 2014-06-13 14:29 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 5, 2014 at 4:53 AM, Daniel Thompson
<daniel.thompson@linaro.org> wrote:
> Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
> virq into a FIQ virq. This is too inflexible for multi-platform kernels
> and makes runtime error checking impossible.
>
> We solve this by introducing a flexible mapping that allows interrupt
> controllers that support FIQ to register those mappings. This, in turn,
> makes it much possible for drivers in DT kernels to gain access to
> FIQ virqs.

I don't get why you need a separate linux irq numbers for FIQ. Isn't
enabling FIQ simply a property of an irq like edge vs. level trigger?
Also, given the constraints on FIQ, we can't really have more that 1
IRQ assigned to FIQ.

Rob

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [RFC v3 1/9] arm: fiq: arbitrary mappings from IRQ to FIQ virqs
  2014-06-13 14:29         ` Rob Herring
@ 2014-06-18 11:24           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-18 11:24 UTC (permalink / raw)
  To: Rob Herring
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Dirk Behme, Russell King, Nicolas Pitre, Fabio Estevam,
	Linaro Patches, Anton Vorontsov, Kumar Gala, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, Ian Campbell, Jason Wessel,
	Rob Herring

On 13/06/14 15:29, Rob Herring wrote:
> On Thu, Jun 5, 2014 at 4:53 AM, Daniel Thompson
> <daniel.thompson@linaro.org> wrote:
>> Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
>> virq into a FIQ virq. This is too inflexible for multi-platform kernels
>> and makes runtime error checking impossible.
>>
>> We solve this by introducing a flexible mapping that allows interrupt
>> controllers that support FIQ to register those mappings. This, in turn,
>> makes it much possible for drivers in DT kernels to gain access to
>> FIQ virqs.
> 
> I don't get why you need a separate linux irq numbers for FIQ. Isn't
> enabling FIQ simply a property of an irq like edge vs. level trigger?
> Also, given the constraints on FIQ, we can't really have more that 1
> IRQ assigned to FIQ.

No particular reason. I mostly went that way because it mimics the
effect of fiq_start on enable_fiq/disable_fiq whilst supporting
multi-platform.

I'm tempted to keep the radix tree in the FIQ infrastructure but rather
than messing about with shadow virqs use it to lookup a fiq_chip
structure. I think this would keep a clean separation between the ARM
centric (and slightly weird) FIQ from the generic irq code.


Daniel.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC v3 1/9] arm: fiq: arbitrary mappings from IRQ to FIQ virqs
@ 2014-06-18 11:24           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-18 11:24 UTC (permalink / raw)
  To: linux-arm-kernel

On 13/06/14 15:29, Rob Herring wrote:
> On Thu, Jun 5, 2014 at 4:53 AM, Daniel Thompson
> <daniel.thompson@linaro.org> wrote:
>> Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
>> virq into a FIQ virq. This is too inflexible for multi-platform kernels
>> and makes runtime error checking impossible.
>>
>> We solve this by introducing a flexible mapping that allows interrupt
>> controllers that support FIQ to register those mappings. This, in turn,
>> makes it much possible for drivers in DT kernels to gain access to
>> FIQ virqs.
> 
> I don't get why you need a separate linux irq numbers for FIQ. Isn't
> enabling FIQ simply a property of an irq like edge vs. level trigger?
> Also, given the constraints on FIQ, we can't really have more that 1
> IRQ assigned to FIQ.

No particular reason. I mostly went that way because it mimics the
effect of fiq_start on enable_fiq/disable_fiq whilst supporting
multi-platform.

I'm tempted to keep the radix tree in the FIQ infrastructure but rather
than messing about with shadow virqs use it to lookup a fiq_chip
structure. I think this would keep a clean separation between the ARM
centric (and slightly weird) FIQ from the generic irq code.


Daniel.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v4 00/13] kgdb: NMI/FIQ support for ARM
  2014-06-05  9:53     ` Daniel Thompson
@ 2014-06-19 10:38       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Ian Campbell, Anton Vorontsov, David A. Long, linux-serial,
	Catalin Marinas, kernel-team, devicetree, linaro-kernel,
	Pawel Moll, patches, Kumar Gala, Rob Herring, John Stultz,
	Thomas Gleixner, linux-arm-kernel, Greg Kroah-Hartman

This patchset makes it possible to use the kgdb NMI infrastructure on
ARM platforms by providing a mutli-platform compatible means for drivers
to manage FIQ routings.

First a quick summary of how the already mainlined kgdb NMI
infrastructure (mostly found in drivers/tty/serial/kgdb_nmi.c) works.
The kgdb infrastructure will re-route the kgdb console UART's interrupt
signal from IRQ to FIQ. Naturally the UART will no longer function
normally and will instead be managed by kgdb using the polled I/O
functions. Any character delivered to the UART causes the kgdb handler
function to be called.

Note that, within this patchset a serial driver explicitly consents (or
not) to the abuse outlined above by calling the appropriate registration
during the .poll_init() callback. In so doing it also commits to honour
the stringent runtime requirements imposed on FIQ handlers within its
polled I/O handlers.

Major remaining TODO item is to modify the code to halt the other CPUs;
at present this code sends IPIs (which use a normal IRQ) and busy waits
for the other CPUs to halt. This means the benefits of invoking the
debugger via NMI are only partially realized on SMP systems. However
there are no cross dependencies so the code is "good to go" without this
feature implemented.

Changes since v3:

* Corrected the FIQ uninstall code (Russell King).

* Removed named constants for EnableGrp0 and EnableGrp1 (Nicolas Pitre).
 
* Remove spin locks from gic_eoi_irq (Peter De Schrijver).

* Massively simplified things by avoiding allocation of shadow IRQ (Rob
  Herring)

* Correctly set the priority of FIQ interrupts by making the top bit
  follow ARM recommendations. Fixes robustness problem in the debugger
  itself.
 
* Auto-detect whether the platform can support FIQ and act
  accordingly. This permits proper dead code elimination when CONFIG_FIQ
  is not set.

* Ported to and tested on iMX6 (Wandboard quad). Included a patch from
  Dirk Behme that is required to get this device working properly with
  kgdb.

* Avoid using writel() (which takes spin locks) in polled I/O callbacks
  of supported serial drivers.
  
Changes since v2:

* Use flexible mappings to link a normal virq to a FIQ virq. This
  replaces the device tree proposals from the previous RFC
  (review of Russell King and Rob Herring).

* Reviewed all use of spin locks within .irq_eoi callbacks (and fixed
  the issue identified). Added comments to the FIQ registration
  functions making clear the requirements imposed on interrupt
  controller that call the FIQ API (thanks Russell King).

* Fixed a few whitespace issues (review of Srinivas Kandagatla)

* ARM64/defconfig build tests (no problems found)

Changes since v1:

* Fully fledged multi-platform support.

* Tested for correct FIQ operation on STiH416/B2020 (Cortex A9),
  qemu/versatile and qemu/vexpress-a15 (with self-written mods to the
  GIC model to support FIQ).

* Regression tested (and resulting bugs fixed) on qemu/versatile+DT and
  qemu/integreatorcp.

Anton Vorontsov (2):
  ARM: Move some macros from entry-armv to entry-header
  ARM: Add KGDB/KDB FIQ debugger generic code

Daniel Thompson (10):
  arm: fiq: Add callbacks to manage FIQ routings
  arm: fiq: Allow EOI to be communicated to the intc
  irqchip: gic: Provide support for interrupt grouping
  irqchip: gic: Add support for FIQ management
  irqchip: gic: Remove spin locks from eoi_irq
  irqchip: vic: Add support for FIQ management
  serial: amba-pl011: Pass FIQ information to KGDB.
  serial: asc: Add support for KGDB's FIQ/NMI mode
  serial: asc: Adopt readl_/writel_relaxed()
  serial: imx: Add support for KGDB's FIQ/NMI mode

Dirk Behme (1):
  serial: imx: clean up imx_poll_get_char()

 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 +++++
 arch/arm/include/asm/fiq.h       |  13 ++++
 arch/arm/include/asm/kgdb.h      |   7 ++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/entry-armv.S     | 151 +----------------------------------
 arch/arm/kernel/entry-header.S   | 164 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/fiq.c            | 112 +++++++++++++++++++++++++-
 arch/arm/kernel/kgdb_fiq.c       | 124 +++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S |  87 +++++++++++++++++++++
 arch/arm/mach-versatile/core.c   |   2 +-
 drivers/irqchip/irq-gic.c        | 155 +++++++++++++++++++++++++++++++++---
 drivers/irqchip/irq-vic.c        |  92 +++++++++++++++++-----
 drivers/tty/serial/amba-pl011.c  |  99 +++++++++++++----------
 drivers/tty/serial/imx.c         |  88 ++++++++++++---------
 drivers/tty/serial/st-asc.c      |  34 +++++++-
 include/linux/irqchip/arm-vic.h  |   6 +-
 17 files changed, 892 insertions(+), 263 deletions(-)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

-- 
1.9.3

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v4 00/13] kgdb: NMI/FIQ support for ARM
@ 2014-06-19 10:38       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset makes it possible to use the kgdb NMI infrastructure on
ARM platforms by providing a mutli-platform compatible means for drivers
to manage FIQ routings.

First a quick summary of how the already mainlined kgdb NMI
infrastructure (mostly found in drivers/tty/serial/kgdb_nmi.c) works.
The kgdb infrastructure will re-route the kgdb console UART's interrupt
signal from IRQ to FIQ. Naturally the UART will no longer function
normally and will instead be managed by kgdb using the polled I/O
functions. Any character delivered to the UART causes the kgdb handler
function to be called.

Note that, within this patchset a serial driver explicitly consents (or
not) to the abuse outlined above by calling the appropriate registration
during the .poll_init() callback. In so doing it also commits to honour
the stringent runtime requirements imposed on FIQ handlers within its
polled I/O handlers.

Major remaining TODO item is to modify the code to halt the other CPUs;
at present this code sends IPIs (which use a normal IRQ) and busy waits
for the other CPUs to halt. This means the benefits of invoking the
debugger via NMI are only partially realized on SMP systems. However
there are no cross dependencies so the code is "good to go" without this
feature implemented.

Changes since v3:

* Corrected the FIQ uninstall code (Russell King).

* Removed named constants for EnableGrp0 and EnableGrp1 (Nicolas Pitre).
 
* Remove spin locks from gic_eoi_irq (Peter De Schrijver).

* Massively simplified things by avoiding allocation of shadow IRQ (Rob
  Herring)

* Correctly set the priority of FIQ interrupts by making the top bit
  follow ARM recommendations. Fixes robustness problem in the debugger
  itself.
 
* Auto-detect whether the platform can support FIQ and act
  accordingly. This permits proper dead code elimination when CONFIG_FIQ
  is not set.

* Ported to and tested on iMX6 (Wandboard quad). Included a patch from
  Dirk Behme that is required to get this device working properly with
  kgdb.

* Avoid using writel() (which takes spin locks) in polled I/O callbacks
  of supported serial drivers.
  
Changes since v2:

* Use flexible mappings to link a normal virq to a FIQ virq. This
  replaces the device tree proposals from the previous RFC
  (review of Russell King and Rob Herring).

* Reviewed all use of spin locks within .irq_eoi callbacks (and fixed
  the issue identified). Added comments to the FIQ registration
  functions making clear the requirements imposed on interrupt
  controller that call the FIQ API (thanks Russell King).

* Fixed a few whitespace issues (review of Srinivas Kandagatla)

* ARM64/defconfig build tests (no problems found)

Changes since v1:

* Fully fledged multi-platform support.

* Tested for correct FIQ operation on STiH416/B2020 (Cortex A9),
  qemu/versatile and qemu/vexpress-a15 (with self-written mods to the
  GIC model to support FIQ).

* Regression tested (and resulting bugs fixed) on qemu/versatile+DT and
  qemu/integreatorcp.

Anton Vorontsov (2):
  ARM: Move some macros from entry-armv to entry-header
  ARM: Add KGDB/KDB FIQ debugger generic code

Daniel Thompson (10):
  arm: fiq: Add callbacks to manage FIQ routings
  arm: fiq: Allow EOI to be communicated to the intc
  irqchip: gic: Provide support for interrupt grouping
  irqchip: gic: Add support for FIQ management
  irqchip: gic: Remove spin locks from eoi_irq
  irqchip: vic: Add support for FIQ management
  serial: amba-pl011: Pass FIQ information to KGDB.
  serial: asc: Add support for KGDB's FIQ/NMI mode
  serial: asc: Adopt readl_/writel_relaxed()
  serial: imx: Add support for KGDB's FIQ/NMI mode

Dirk Behme (1):
  serial: imx: clean up imx_poll_get_char()

 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 +++++
 arch/arm/include/asm/fiq.h       |  13 ++++
 arch/arm/include/asm/kgdb.h      |   7 ++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/entry-armv.S     | 151 +----------------------------------
 arch/arm/kernel/entry-header.S   | 164 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/fiq.c            | 112 +++++++++++++++++++++++++-
 arch/arm/kernel/kgdb_fiq.c       | 124 +++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S |  87 +++++++++++++++++++++
 arch/arm/mach-versatile/core.c   |   2 +-
 drivers/irqchip/irq-gic.c        | 155 +++++++++++++++++++++++++++++++++---
 drivers/irqchip/irq-vic.c        |  92 +++++++++++++++++-----
 drivers/tty/serial/amba-pl011.c  |  99 +++++++++++++----------
 drivers/tty/serial/imx.c         |  88 ++++++++++++---------
 drivers/tty/serial/st-asc.c      |  34 +++++++-
 include/linux/irqchip/arm-vic.h  |   6 +-
 17 files changed, 892 insertions(+), 263 deletions(-)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

-- 
1.9.3

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v4 01/13] arm: fiq: Add callbacks to manage FIQ routings
  2014-06-19 10:38       ` Daniel Thompson
@ 2014-06-19 10:38         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Fabio Estevam, Ian Campbell, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, patches, Kumar Gala, Rob Herring,
	John Stultz, Thomas Gleixner, linux-arm-kernel

Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
virq into a FIQ virq. This is too inflexible for multi-platform kernels
and makes runtime error checking impossible.

We solve this by introducing a flexible mapping that allows interrupt
controllers that support FIQ to register those mappings. This, in turn,
makes it much possible for drivers in DT kernels to install FIQ handlers
without knowing anything about the interrupt controller.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/include/asm/fiq.h |   7 +++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 108 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..a7806ef 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -18,6 +18,11 @@
 
 #include <asm/ptrace.h>
 
+struct fiq_chip {
+	void (*fiq_enable)(struct irq_data *data);
+	void (*fiq_disable)(struct irq_data *data);
+};
+
 struct fiq_handler {
 	struct fiq_handler *next;
 	/* Name
@@ -38,6 +43,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern bool has_fiq(int fiq);
+extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..567f8fd 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,9 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
+#include <linux/radix-tree.h>
+#include <linux/slab.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -52,7 +55,15 @@
 		(unsigned)&vector_fiq_offset;		\
 	})
 
+struct fiq_data {
+	struct fiq_chip *fiq_chip;
+	struct irq_data *irq_data;
+};
+
 static unsigned long no_fiq_insn;
+static int fiq_start = -1;
+static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
+static DEFINE_MUTEX(fiq_data_mutex);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -127,18 +138,65 @@ void release_fiq(struct fiq_handler *f)
 	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
 }
 
-static int fiq_start;
+static struct fiq_data *lookup_fiq_data(int fiq)
+{
+	struct fiq_data *data;
+
+	rcu_read_lock();
+	data = radix_tree_lookup(&fiq_data_tree, fiq);
+	rcu_read_unlock();
+
+	return data;
+}
 
 void enable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_enable)
+			data->fiq_chip->fiq_enable(data->irq_data);
+		enable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	enable_irq(fiq + fiq_start);
 }
 
 void disable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_disable)
+			data->fiq_chip->fiq_disable(data->irq_data);
+		disable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	disable_irq(fiq + fiq_start);
 }
 
+bool has_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data)
+		return true;
+
+	if (fiq_start == -1)
+		return false;
+
+	return fiq > fiq_start;
+}
+EXPORT_SYMBOL(has_fiq);
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -147,9 +205,50 @@ EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
 
+/*
+ * Add a mapping from a Linux irq to the fiq data.
+ */
+void fiq_register_mapping(int irq, struct fiq_chip *chip)
+{
+	struct fiq_data *fiq_data = NULL;
+	int res;
+
+	/* fiq_register_mapping can't be mixed with init_FIQ */
+	BUG_ON(fiq_start != -1);
+
+	fiq_data = kmalloc(sizeof(*fiq_data), GFP_KERNEL);
+	if (!fiq_data)
+		goto err;
+
+	fiq_data->fiq_chip = chip;
+	fiq_data->irq_data = irq_get_irq_data(irq);
+	BUG_ON(!fiq_data->irq_data);
+
+	mutex_lock(&fiq_data_mutex);
+	res = radix_tree_insert(&fiq_data_tree, irq, fiq_data);
+	mutex_unlock(&fiq_data_mutex);
+	if (res)
+		goto err;
+
+	return;
+
+err:
+	kfree(fiq_data);
+	pr_err("fiq: Cannot register mapping %d\n", irq);
+}
+
+/*
+ * Set the offset between normal IRQs and their FIQ shadows.
+ */
 void __init init_FIQ(int start)
 {
+	fiq_start = start;
+}
+
+static int __init init_default_fiq_handler(void)
+{
 	unsigned offset = FIQ_OFFSET;
 	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
-	fiq_start = start;
+	return 0;
 }
+pure_initcall(init_default_fiq_handler);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 01/13] arm: fiq: Add callbacks to manage FIQ routings
@ 2014-06-19 10:38         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
virq into a FIQ virq. This is too inflexible for multi-platform kernels
and makes runtime error checking impossible.

We solve this by introducing a flexible mapping that allows interrupt
controllers that support FIQ to register those mappings. This, in turn,
makes it much possible for drivers in DT kernels to install FIQ handlers
without knowing anything about the interrupt controller.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/include/asm/fiq.h |   7 +++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 108 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..a7806ef 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -18,6 +18,11 @@
 
 #include <asm/ptrace.h>
 
+struct fiq_chip {
+	void (*fiq_enable)(struct irq_data *data);
+	void (*fiq_disable)(struct irq_data *data);
+};
+
 struct fiq_handler {
 	struct fiq_handler *next;
 	/* Name
@@ -38,6 +43,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern bool has_fiq(int fiq);
+extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..567f8fd 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,9 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
+#include <linux/radix-tree.h>
+#include <linux/slab.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -52,7 +55,15 @@
 		(unsigned)&vector_fiq_offset;		\
 	})
 
+struct fiq_data {
+	struct fiq_chip *fiq_chip;
+	struct irq_data *irq_data;
+};
+
 static unsigned long no_fiq_insn;
+static int fiq_start = -1;
+static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
+static DEFINE_MUTEX(fiq_data_mutex);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -127,18 +138,65 @@ void release_fiq(struct fiq_handler *f)
 	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
 }
 
-static int fiq_start;
+static struct fiq_data *lookup_fiq_data(int fiq)
+{
+	struct fiq_data *data;
+
+	rcu_read_lock();
+	data = radix_tree_lookup(&fiq_data_tree, fiq);
+	rcu_read_unlock();
+
+	return data;
+}
 
 void enable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_enable)
+			data->fiq_chip->fiq_enable(data->irq_data);
+		enable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	enable_irq(fiq + fiq_start);
 }
 
 void disable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_disable)
+			data->fiq_chip->fiq_disable(data->irq_data);
+		disable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	disable_irq(fiq + fiq_start);
 }
 
+bool has_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data)
+		return true;
+
+	if (fiq_start == -1)
+		return false;
+
+	return fiq > fiq_start;
+}
+EXPORT_SYMBOL(has_fiq);
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -147,9 +205,50 @@ EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
 
+/*
+ * Add a mapping from a Linux irq to the fiq data.
+ */
+void fiq_register_mapping(int irq, struct fiq_chip *chip)
+{
+	struct fiq_data *fiq_data = NULL;
+	int res;
+
+	/* fiq_register_mapping can't be mixed with init_FIQ */
+	BUG_ON(fiq_start != -1);
+
+	fiq_data = kmalloc(sizeof(*fiq_data), GFP_KERNEL);
+	if (!fiq_data)
+		goto err;
+
+	fiq_data->fiq_chip = chip;
+	fiq_data->irq_data = irq_get_irq_data(irq);
+	BUG_ON(!fiq_data->irq_data);
+
+	mutex_lock(&fiq_data_mutex);
+	res = radix_tree_insert(&fiq_data_tree, irq, fiq_data);
+	mutex_unlock(&fiq_data_mutex);
+	if (res)
+		goto err;
+
+	return;
+
+err:
+	kfree(fiq_data);
+	pr_err("fiq: Cannot register mapping %d\n", irq);
+}
+
+/*
+ * Set the offset between normal IRQs and their FIQ shadows.
+ */
 void __init init_FIQ(int start)
 {
+	fiq_start = start;
+}
+
+static int __init init_default_fiq_handler(void)
+{
 	unsigned offset = FIQ_OFFSET;
 	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
-	fiq_start = start;
+	return 0;
 }
+pure_initcall(init_default_fiq_handler);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 02/13] arm: fiq: Allow EOI to be communicated to the intc
  2014-06-19 10:38       ` Daniel Thompson
@ 2014-06-19 10:38         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Fabio Estevam, Ian Campbell, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, patches, Kumar Gala, Rob Herring,
	John Stultz, Thomas Gleixner, linux-arm-kernel

Modern ARM systems require an EOI to be sent to the interrupt controller
on completion of both IRQ and FIQ. The FIQ code currently does not provide
any API to perform this. This patch provides this API, implemented by
adding a callback to the fiq_chip structure.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/include/asm/fiq.h | 6 ++++++
 arch/arm/kernel/fiq.c      | 9 +++++++++
 2 files changed, 15 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index a7806ef..e5d9458 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -21,6 +21,11 @@
 struct fiq_chip {
 	void (*fiq_enable)(struct irq_data *data);
 	void (*fiq_disable)(struct irq_data *data);
+
+	/* .fiq_eoi() will be called from the FIQ handler. For this
+	 * reason it must not use spin locks (or any other locks).
+	 */
+	void (*fiq_eoi)(struct irq_data *data);
 };
 
 struct fiq_handler {
@@ -43,6 +48,7 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 567f8fd..edde332 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -183,6 +183,15 @@ void disable_fiq(int fiq)
 	disable_irq(fiq + fiq_start);
 }
 
+void eoi_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_eoi)
+		data->fiq_chip->fiq_eoi(data->irq_data);
+}
+EXPORT_SYMBOL(eoi_fiq);
+
 bool has_fiq(int fiq)
 {
 	struct fiq_data *data = lookup_fiq_data(fiq);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 02/13] arm: fiq: Allow EOI to be communicated to the intc
@ 2014-06-19 10:38         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

Modern ARM systems require an EOI to be sent to the interrupt controller
on completion of both IRQ and FIQ. The FIQ code currently does not provide
any API to perform this. This patch provides this API, implemented by
adding a callback to the fiq_chip structure.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/include/asm/fiq.h | 6 ++++++
 arch/arm/kernel/fiq.c      | 9 +++++++++
 2 files changed, 15 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index a7806ef..e5d9458 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -21,6 +21,11 @@
 struct fiq_chip {
 	void (*fiq_enable)(struct irq_data *data);
 	void (*fiq_disable)(struct irq_data *data);
+
+	/* .fiq_eoi() will be called from the FIQ handler. For this
+	 * reason it must not use spin locks (or any other locks).
+	 */
+	void (*fiq_eoi)(struct irq_data *data);
 };
 
 struct fiq_handler {
@@ -43,6 +48,7 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 567f8fd..edde332 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -183,6 +183,15 @@ void disable_fiq(int fiq)
 	disable_irq(fiq + fiq_start);
 }
 
+void eoi_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_eoi)
+		data->fiq_chip->fiq_eoi(data->irq_data);
+}
+EXPORT_SYMBOL(eoi_fiq);
+
 bool has_fiq(int fiq)
 {
 	struct fiq_data *data = lookup_fiq_data(fiq);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 03/13] irqchip: gic: Provide support for interrupt grouping
  2014-06-19 10:38       ` Daniel Thompson
@ 2014-06-19 10:38         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, Nicolas Pitre, kernel, kgdb-bugreport,
	Linus Walleij, Sricharan R, Jiri Slaby, Daniel Thompson,
	Dirk Behme, Russell King, Nicolas Pitre, Ian Campbell,
	Anton Vorontsov, David A. Long, linux-serial, Catalin Marinas,
	kernel-team, devicetree, linaro-kernel, Jason Cooper, Pawel Moll,
	patches, Kumar Gala, Rob Herring, John Stultz

All GIC hardware except GICv1-without-TrustZone support provides a means
to group exceptions into group 0 (which can optionally be signally using
use FIQ) and group 1. The kernel currently provides no means to exploit
this. This patch alters the initialization of the GIC to place all
interrupts into group 1 which is the foundational requirement to meaningfully
use FIQ.

Note that the hardware functionality is unavailable to the kernel when a
secure monitor is present because access to the grouping registers are
prohibited outside "secure world" (this feature allows grouping to be
used to allow hardware peripherals to send interrupts into the secure
world). The GIC driver will automatically detect this and disable its
attempts to group interrupts.

On systems without TrustZone support the kernel has the power to route
interrupt sources to FIQ, potentially allowing a driver to exploit the
NMI-like properties of FIQ.

Tested on Freescale i.MX6 (quad A9), STiH416 (dual A9) and a self-written
qemu GICv2 model.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
Acked-by: Dirk Behme <dirk.behme@de.bosch.com>
---
 drivers/irqchip/irq-gic.c | 99 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 94 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 7e11c9d..bbffca3 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -42,6 +42,9 @@
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
 
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
@@ -68,6 +71,9 @@ struct gic_chip_data {
 #ifdef CONFIG_GIC_NON_BANKED
 	void __iomem *(*get_base)(union gic_base *);
 #endif
+#ifdef CONFIG_FIQ
+	bool fiq_enable;
+#endif
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
@@ -131,6 +137,16 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data,
 #define gic_set_base_accessor(d, f)
 #endif
 
+#ifdef CONFIG_FIQ
+static inline bool gic_data_fiq_enable(struct gic_chip_data *data)
+{
+	return data->fiq_enable;
+}
+#else
+static inline bool gic_data_fiq_enable(
+		struct gic_chip_data *data) { return false; }
+#endif
+
 static inline void __iomem *gic_dist_base(struct irq_data *d)
 {
 	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
@@ -349,6 +365,42 @@ static struct irq_chip gic_chip = {
 	.irq_set_wake		= gic_set_wake,
 };
 
+#ifdef CONFIG_FIQ
+static void __init gic_init_fiq(struct gic_chip_data *gic,
+				irq_hw_number_t first_irq,
+				unsigned int num_irqs)
+{
+	void __iomem *dist_base = gic_data_dist_base(gic_data);
+	unsigned int i;
+
+	/*
+	 * FIQ can only be supported on platforms without an extended irq_eoi
+	 * method (otherwise we take a lock during eoi handling).
+	 */
+	if (gic_arch_extn.irq_eoi)
+		return;
+
+	/*
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers a read-as-zero/write-ignored.
+	 * However as a precaution we restore the reset default regardless of
+	 * the result of the test.
+	 */
+	writel_relaxed(1, dist_base + GIC_DIST_IGROUP + 0);
+	gic->fiq_enable = readl_relaxed(dist_base + GIC_DIST_IGROUP + 0);
+	writel_relaxed(0, dist_base + GIC_DIST_IGROUP + 0);
+	pr_debug("gic: FIQ support %s\n",
+		 gic->fiq_enable ? "enabled" : "disabled");
+
+	if (!gic->fiq_enable)
+		return;
+}
+#else /* CONFIG_FIQ */
+static inline void gic_init_fiq(struct gic_chip_data *gic,
+				irq_hw_number_t first_irq,
+				unsigned int num_irqs) {}
+#endif /* CONFIG_FIQ */
+
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
 	if (gic_nr >= MAX_GIC_NR)
@@ -408,13 +460,28 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 		writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
 
 	/*
+	 * Optionally set all global interrupts to be group 1.
+	 */
+	if (gic_data_fiq_enable(gic))
+		for (i = 32; i < gic_irqs; i += 32)
+			writel_relaxed(0xffffffff,
+				       base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
 	 * Disable all interrupts.  Leave the PPI and SGIs alone
 	 * as these enables are banked registers.
 	 */
 	for (i = 32; i < gic_irqs; i += 32)
 		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(3, base + GIC_DIST_CTRL);
+	else
+		writel_relaxed(1, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -452,8 +519,20 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	for (i = 0; i < 32; i += 4)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
 
+	/*
+	 * Set all PPI and SGI interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers are read-as-zero/write-ignored.
+	 */
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
+	else
+		writel_relaxed(1, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -537,7 +616,10 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	if (gic_data_fiq_enable(&gic_data[gic_nr]))
+		writel_relaxed(3, dist_base + GIC_DIST_CTRL);
+	else
+		writel_relaxed(1, dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -594,7 +676,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -656,6 +738,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
 	unsigned long flags, map = 0;
+	unsigned long softint;
 
 	raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
@@ -670,7 +753,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+	softint = map << 16 | irq;
+	if (gic_data_fiq_enable(&gic_data[0]))
+		softint |= 0x8000;
+	writel_relaxed(softint,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
@@ -1014,6 +1101,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 
 		gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
 					hwirq_base, &gic_irq_domain_ops, gic);
+
+		gic_init_fiq(gic, irq_base, gic_irqs);
 	} else {
 		gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
 						    &gic_irq_domain_ops,
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 03/13] irqchip: gic: Provide support for interrupt grouping
@ 2014-06-19 10:38         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

All GIC hardware except GICv1-without-TrustZone support provides a means
to group exceptions into group 0 (which can optionally be signally using
use FIQ) and group 1. The kernel currently provides no means to exploit
this. This patch alters the initialization of the GIC to place all
interrupts into group 1 which is the foundational requirement to meaningfully
use FIQ.

Note that the hardware functionality is unavailable to the kernel when a
secure monitor is present because access to the grouping registers are
prohibited outside "secure world" (this feature allows grouping to be
used to allow hardware peripherals to send interrupts into the secure
world). The GIC driver will automatically detect this and disable its
attempts to group interrupts.

On systems without TrustZone support the kernel has the power to route
interrupt sources to FIQ, potentially allowing a driver to exploit the
NMI-like properties of FIQ.

Tested on Freescale i.MX6 (quad A9), STiH416 (dual A9) and a self-written
qemu GICv2 model.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
Acked-by: Dirk Behme <dirk.behme@de.bosch.com>
---
 drivers/irqchip/irq-gic.c | 99 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 94 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 7e11c9d..bbffca3 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -42,6 +42,9 @@
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
 
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
@@ -68,6 +71,9 @@ struct gic_chip_data {
 #ifdef CONFIG_GIC_NON_BANKED
 	void __iomem *(*get_base)(union gic_base *);
 #endif
+#ifdef CONFIG_FIQ
+	bool fiq_enable;
+#endif
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
@@ -131,6 +137,16 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data,
 #define gic_set_base_accessor(d, f)
 #endif
 
+#ifdef CONFIG_FIQ
+static inline bool gic_data_fiq_enable(struct gic_chip_data *data)
+{
+	return data->fiq_enable;
+}
+#else
+static inline bool gic_data_fiq_enable(
+		struct gic_chip_data *data) { return false; }
+#endif
+
 static inline void __iomem *gic_dist_base(struct irq_data *d)
 {
 	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
@@ -349,6 +365,42 @@ static struct irq_chip gic_chip = {
 	.irq_set_wake		= gic_set_wake,
 };
 
+#ifdef CONFIG_FIQ
+static void __init gic_init_fiq(struct gic_chip_data *gic,
+				irq_hw_number_t first_irq,
+				unsigned int num_irqs)
+{
+	void __iomem *dist_base = gic_data_dist_base(gic_data);
+	unsigned int i;
+
+	/*
+	 * FIQ can only be supported on platforms without an extended irq_eoi
+	 * method (otherwise we take a lock during eoi handling).
+	 */
+	if (gic_arch_extn.irq_eoi)
+		return;
+
+	/*
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers a read-as-zero/write-ignored.
+	 * However as a precaution we restore the reset default regardless of
+	 * the result of the test.
+	 */
+	writel_relaxed(1, dist_base + GIC_DIST_IGROUP + 0);
+	gic->fiq_enable = readl_relaxed(dist_base + GIC_DIST_IGROUP + 0);
+	writel_relaxed(0, dist_base + GIC_DIST_IGROUP + 0);
+	pr_debug("gic: FIQ support %s\n",
+		 gic->fiq_enable ? "enabled" : "disabled");
+
+	if (!gic->fiq_enable)
+		return;
+}
+#else /* CONFIG_FIQ */
+static inline void gic_init_fiq(struct gic_chip_data *gic,
+				irq_hw_number_t first_irq,
+				unsigned int num_irqs) {}
+#endif /* CONFIG_FIQ */
+
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
 	if (gic_nr >= MAX_GIC_NR)
@@ -408,13 +460,28 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 		writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
 
 	/*
+	 * Optionally set all global interrupts to be group 1.
+	 */
+	if (gic_data_fiq_enable(gic))
+		for (i = 32; i < gic_irqs; i += 32)
+			writel_relaxed(0xffffffff,
+				       base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
 	 * Disable all interrupts.  Leave the PPI and SGIs alone
 	 * as these enables are banked registers.
 	 */
 	for (i = 32; i < gic_irqs; i += 32)
 		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(3, base + GIC_DIST_CTRL);
+	else
+		writel_relaxed(1, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -452,8 +519,20 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	for (i = 0; i < 32; i += 4)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
 
+	/*
+	 * Set all PPI and SGI interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers are read-as-zero/write-ignored.
+	 */
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
+	else
+		writel_relaxed(1, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -537,7 +616,10 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	if (gic_data_fiq_enable(&gic_data[gic_nr]))
+		writel_relaxed(3, dist_base + GIC_DIST_CTRL);
+	else
+		writel_relaxed(1, dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -594,7 +676,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -656,6 +738,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
 	unsigned long flags, map = 0;
+	unsigned long softint;
 
 	raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
@@ -670,7 +753,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+	softint = map << 16 | irq;
+	if (gic_data_fiq_enable(&gic_data[0]))
+		softint |= 0x8000;
+	writel_relaxed(softint,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
@@ -1014,6 +1101,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 
 		gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
 					hwirq_base, &gic_irq_domain_ops, gic);
+
+		gic_init_fiq(gic, irq_base, gic_irqs);
 	} else {
 		gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
 						    &gic_irq_domain_ops,
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 04/13] irqchip: gic: Add support for FIQ management
  2014-06-19 10:38       ` Daniel Thompson
@ 2014-06-19 10:38         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, Nicolas Pitre, kernel, kgdb-bugreport,
	Linus Walleij, Sricharan R, Jiri Slaby, Daniel Thompson,
	Dirk Behme, Russell King, Nicolas Pitre, Ian Campbell,
	Anton Vorontsov, David A. Long, linux-serial, Catalin Marinas,
	kernel-team, devicetree, linaro-kernel, Jason Cooper, Pawel Moll,
	patches, Kumar Gala, Rob Herring, John Stultz

This patch introduces callbacks to route interrupts to or away
from the FIQ signal and registers these callbacks with the FIQ
infrastructure (if the device can supports it).

Both these aspects combine and allow a driver to deploy a FIQ handler
without any machine specific knowledge; it can be used effectively on
multi-platform kernels.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
---
 drivers/irqchip/irq-gic.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index bbffca3..0300c08 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -366,6 +366,58 @@ static struct irq_chip gic_chip = {
 };
 
 #ifdef CONFIG_FIQ
+/*
+ * Shift an interrupt between Group 0 and Group 1.
+ *
+ * In addition to changing the group we also modify the priority to
+ * match what "ARM strongly recommends" for a system where no Group 1
+ * interrupt must ever preempt a Group 0 interrupt.
+ */
+static void gic_set_group_irq(struct irq_data *d, int group)
+{
+	unsigned int grp_reg = gic_irq(d) / 32 * 4;
+	u32 grp_mask = 1 << (gic_irq(d) % 32);
+	u32 grp_val;
+
+	unsigned int pri_reg = (gic_irq(d) / 4) * 4;
+	u32 pri_mask = 1 << (7 + ((gic_irq(d) % 4) * 8));
+	u32 pri_val;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	grp_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+
+	if (group) {
+		grp_val |= grp_mask;
+		pri_val |= pri_mask;
+	} else {
+		grp_val &= ~grp_mask;
+		pri_val &= ~pri_mask;
+	}
+
+	writel_relaxed(grp_val, gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void gic_enable_fiq(struct irq_data *d)
+{
+	gic_set_group_irq(d, 0);
+}
+
+static void gic_disable_fiq(struct irq_data *d)
+{
+	gic_set_group_irq(d, 1);
+}
+
+static struct fiq_chip gic_fiq = {
+	.fiq_enable		= gic_enable_fiq,
+	.fiq_disable            = gic_disable_fiq,
+	.fiq_eoi		= gic_eoi_irq,
+};
+
 static void __init gic_init_fiq(struct gic_chip_data *gic,
 				irq_hw_number_t first_irq,
 				unsigned int num_irqs)
@@ -394,6 +446,12 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 
 	if (!gic->fiq_enable)
 		return;
+
+	/*
+	 * FIQ is supported on this device! Register our chip data.
+	 */
+	for (i = 0; i < num_irqs; i++)
+		fiq_register_mapping(first_irq + i, &gic_fiq);
 }
 #else /* CONFIG_FIQ */
 static inline void gic_init_fiq(struct gic_chip_data *gic,
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 04/13] irqchip: gic: Add support for FIQ management
@ 2014-06-19 10:38         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

This patch introduces callbacks to route interrupts to or away
from the FIQ signal and registers these callbacks with the FIQ
infrastructure (if the device can supports it).

Both these aspects combine and allow a driver to deploy a FIQ handler
without any machine specific knowledge; it can be used effectively on
multi-platform kernels.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
---
 drivers/irqchip/irq-gic.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index bbffca3..0300c08 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -366,6 +366,58 @@ static struct irq_chip gic_chip = {
 };
 
 #ifdef CONFIG_FIQ
+/*
+ * Shift an interrupt between Group 0 and Group 1.
+ *
+ * In addition to changing the group we also modify the priority to
+ * match what "ARM strongly recommends" for a system where no Group 1
+ * interrupt must ever preempt a Group 0 interrupt.
+ */
+static void gic_set_group_irq(struct irq_data *d, int group)
+{
+	unsigned int grp_reg = gic_irq(d) / 32 * 4;
+	u32 grp_mask = 1 << (gic_irq(d) % 32);
+	u32 grp_val;
+
+	unsigned int pri_reg = (gic_irq(d) / 4) * 4;
+	u32 pri_mask = 1 << (7 + ((gic_irq(d) % 4) * 8));
+	u32 pri_val;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	grp_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+
+	if (group) {
+		grp_val |= grp_mask;
+		pri_val |= pri_mask;
+	} else {
+		grp_val &= ~grp_mask;
+		pri_val &= ~pri_mask;
+	}
+
+	writel_relaxed(grp_val, gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void gic_enable_fiq(struct irq_data *d)
+{
+	gic_set_group_irq(d, 0);
+}
+
+static void gic_disable_fiq(struct irq_data *d)
+{
+	gic_set_group_irq(d, 1);
+}
+
+static struct fiq_chip gic_fiq = {
+	.fiq_enable		= gic_enable_fiq,
+	.fiq_disable            = gic_disable_fiq,
+	.fiq_eoi		= gic_eoi_irq,
+};
+
 static void __init gic_init_fiq(struct gic_chip_data *gic,
 				irq_hw_number_t first_irq,
 				unsigned int num_irqs)
@@ -394,6 +446,12 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 
 	if (!gic->fiq_enable)
 		return;
+
+	/*
+	 * FIQ is supported on this device! Register our chip data.
+	 */
+	for (i = 0; i < num_irqs; i++)
+		fiq_register_mapping(first_irq + i, &gic_fiq);
 }
 #else /* CONFIG_FIQ */
 static inline void gic_init_fiq(struct gic_chip_data *gic,
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 05/13] irqchip: gic: Remove spin locks from eoi_irq
  2014-06-19 10:38       ` Daniel Thompson
@ 2014-06-19 10:38         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Ian Campbell, Anton Vorontsov, David A. Long, linux-serial,
	Catalin Marinas, kernel-team, devicetree, linaro-kernel,
	Jason Cooper, Pawel Moll, patches, Kumar Gala, Rob Herring,
	John Stultz, Thomas Gleixner, linux-arm-kernel

This patch is motivated by the comment it removes from gic_init_fiq,
namely that the spin locks in eoi_irq preclude certain platforms from
supporting FIQ.

Currently there is only one upstream platform (tegra) that actually
hooks gic_arch_extn.irq_eoi and it does not require these spin locks.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Peter De Schrijver <pdeschrijver@nvidia.com>
---
 drivers/irqchip/irq-gic.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 0300c08..1cbff1d 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -191,11 +191,8 @@ static void gic_unmask_irq(struct irq_data *d)
 
 static void gic_eoi_irq(struct irq_data *d)
 {
-	if (gic_arch_extn.irq_eoi) {
-		raw_spin_lock(&irq_controller_lock);
+	if (gic_arch_extn.irq_eoi)
 		gic_arch_extn.irq_eoi(d);
-		raw_spin_unlock(&irq_controller_lock);
-	}
 
 	writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
 }
@@ -426,13 +423,6 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 	unsigned int i;
 
 	/*
-	 * FIQ can only be supported on platforms without an extended irq_eoi
-	 * method (otherwise we take a lock during eoi handling).
-	 */
-	if (gic_arch_extn.irq_eoi)
-		return;
-
-	/*
 	 * If grouping is not available (not implemented or prohibited by
 	 * security mode) these registers a read-as-zero/write-ignored.
 	 * However as a precaution we restore the reset default regardless of
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 05/13] irqchip: gic: Remove spin locks from eoi_irq
@ 2014-06-19 10:38         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

This patch is motivated by the comment it removes from gic_init_fiq,
namely that the spin locks in eoi_irq preclude certain platforms from
supporting FIQ.

Currently there is only one upstream platform (tegra) that actually
hooks gic_arch_extn.irq_eoi and it does not require these spin locks.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Peter De Schrijver <pdeschrijver@nvidia.com>
---
 drivers/irqchip/irq-gic.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 0300c08..1cbff1d 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -191,11 +191,8 @@ static void gic_unmask_irq(struct irq_data *d)
 
 static void gic_eoi_irq(struct irq_data *d)
 {
-	if (gic_arch_extn.irq_eoi) {
-		raw_spin_lock(&irq_controller_lock);
+	if (gic_arch_extn.irq_eoi)
 		gic_arch_extn.irq_eoi(d);
-		raw_spin_unlock(&irq_controller_lock);
-	}
 
 	writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
 }
@@ -426,13 +423,6 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 	unsigned int i;
 
 	/*
-	 * FIQ can only be supported on platforms without an extended irq_eoi
-	 * method (otherwise we take a lock during eoi handling).
-	 */
-	if (gic_arch_extn.irq_eoi)
-		return;
-
-	/*
 	 * If grouping is not available (not implemented or prohibited by
 	 * security mode) these registers a read-as-zero/write-ignored.
 	 * However as a precaution we restore the reset default regardless of
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 06/13] irqchip: vic: Add support for FIQ management
  2014-06-19 10:38       ` Daniel Thompson
@ 2014-06-19 10:38         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Kukjin Kim,
	Jiri Slaby, Daniel Thompson, Dirk Behme, Russell King,
	Nicolas Pitre, Ian Campbell, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Jason Cooper, Pawel Moll, patches, Kumar Gala,
	Rob Herring, John Stultz, linux-samsung-soc, Ben

This patch introduces callbacks to route interrupts to or away
from the FIQ signal. It also causes these callbacks to be registered
with the FIQ infrastructure.

This patch enable FIQ support for mach-versatile whilst mach-ep93xx,
mach-netx, mach-s3c64xx and plat-samsung are unmodified (and can therefore
continue to use init_FIQ() as before).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: linux-samsung-soc@vger.kernel.org
---
 arch/arm/mach-versatile/core.c  |  2 +-
 drivers/irqchip/irq-vic.c       | 92 ++++++++++++++++++++++++++++++++---------
 include/linux/irqchip/arm-vic.h |  6 ++-
 3 files changed, 78 insertions(+), 22 deletions(-)

diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index be83ba2..1abf360 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -108,7 +108,7 @@ void __init versatile_init_irq(void)
 
 	np = of_find_matching_node_by_address(NULL, vic_of_match,
 					      VERSATILE_VIC_BASE);
-	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np);
+	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np ? false : true, np);
 
 	writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
 
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287..22aa126 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -36,6 +36,9 @@
 
 #include <asm/exception.h>
 #include <asm/irq.h>
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 
 #include "irqchip.h"
 
@@ -261,11 +264,53 @@ static struct irq_domain_ops vic_irqdomain_ops = {
 	.xlate = irq_domain_xlate_onetwocell,
 };
 
+#ifdef CONFIG_FIQ
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
+static void vic_set_fiq(struct irq_data *d, bool enable)
+{
+	void __iomem *base = irq_data_get_irq_chip_data(d);
+	unsigned int irq = d->hwirq;
+	u32 val;
+
+	raw_spin_lock(&irq_controller_lock);
+	val = readl(base + VIC_INT_SELECT);
+	if (enable)
+		val |= 1 << irq;
+	else
+		val &= ~(1 << irq);
+	writel(val, base + VIC_INT_SELECT);
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void vic_enable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, true);
+}
+
+static void vic_disable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, false);
+}
+
+struct fiq_chip vic_fiq = {
+	.fiq_enable = vic_enable_fiq,
+	.fiq_disable = vic_disable_fiq,
+};
+
+static void vic_register_fiq(int irq)
+{
+	fiq_register_mapping(irq, &vic_fiq);
+}
+#else /* CONFIG_FIQ */
+static inline void vic_register_fiq(int irq) {}
+#endif /* CONFIG_FIQ */
+
 /**
  * vic_register() - Register a VIC.
  * @base: The base address of the VIC.
  * @parent_irq: The parent IRQ if cascaded, else 0.
- * @irq: The base IRQ for the VIC.
+ * @irq_start: The base IRQ for the VIC.
  * @valid_sources: bitmask of valid interrupts
  * @resume_sources: bitmask of interrupts allowed for resume sources.
  * @node: The device tree node associated with the VIC.
@@ -277,12 +322,13 @@ static struct irq_domain_ops vic_irqdomain_ops = {
  * This also configures the IRQ domain for the VIC.
  */
 static void __init vic_register(void __iomem *base, unsigned int parent_irq,
-				unsigned int irq,
+				unsigned int irq_start,
 				u32 valid_sources, u32 resume_sources,
-				struct device_node *node)
+				bool map_fiqs, struct device_node *node)
 {
 	struct vic_device *v;
 	int i;
+	unsigned int irq;
 
 	if (vic_id >= ARRAY_SIZE(vic_devices)) {
 		printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
@@ -301,15 +347,19 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 		irq_set_chained_handler(parent_irq, vic_handle_irq_cascaded);
 	}
 
-	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq,
+	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq_start,
 					  &vic_irqdomain_ops, v);
 	/* create an IRQ mapping for each valid IRQ */
-	for (i = 0; i < fls(valid_sources); i++)
-		if (valid_sources & (1 << i))
-			irq_create_mapping(v->domain, i);
+	for (i = 0; i < fls(valid_sources); i++) {
+		if (valid_sources & (1 << i)) {
+			irq = irq_create_mapping(v->domain, i);
+			vic_register_fiq(irq);
+		}
+	}
+
 	/* If no base IRQ was passed, figure out our allocated base */
-	if (irq)
-		v->irq = irq;
+	if (irq_start)
+		v->irq = irq_start;
 	else
 		v->irq = irq_find_mapping(v->domain, 0);
 }
@@ -413,7 +463,8 @@ static void __init vic_clear_interrupts(void __iomem *base)
  *  and 020 within the page. We call this "second block".
  */
 static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
-			       u32 vic_sources, struct device_node *node)
+			       u32 vic_sources, bool map_fiqs,
+			       struct device_node *node)
 {
 	unsigned int i;
 	int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
@@ -439,12 +490,12 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
 		writel(32, base + VIC_PL190_DEF_VECT_ADDR);
 	}
 
-	vic_register(base, 0, irq_start, vic_sources, 0, node);
+	vic_register(base, 0, irq_start, vic_sources, 0, map_fiqs, node);
 }
 
 void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
-			      u32 vic_sources, u32 resume_sources,
-			      struct device_node *node)
+		       u32 vic_sources, u32 resume_sources,
+		       bool map_fiqs, struct device_node *node)
 {
 	unsigned int i;
 	u32 cellid = 0;
@@ -462,7 +513,7 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	switch(vendor) {
 	case AMBA_VENDOR_ST:
-		vic_init_st(base, irq_start, vic_sources, node);
+		vic_init_st(base, irq_start, vic_sources, map_fiqs, node);
 		return;
 	default:
 		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
@@ -479,7 +530,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	vic_init2(base);
 
-	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);
+	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources,
+		     map_fiqs, node);
 }
 
 /**
@@ -492,7 +544,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 void __init vic_init(void __iomem *base, unsigned int irq_start,
 		     u32 vic_sources, u32 resume_sources)
 {
-	__vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL);
+	__vic_init(base, 0, irq_start, vic_sources, resume_sources,
+		   false, NULL);
 }
 
 /**
@@ -511,7 +564,8 @@ int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 	struct vic_device *v;
 
 	v = &vic_devices[vic_id];
-	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL);
+	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, false,
+		   NULL);
 	/* Return out acquired base */
 	return v->irq;
 }
@@ -535,9 +589,9 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
 	of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask);
 
 	/*
-	 * Passing 0 as first IRQ makes the simple domain allocate descriptors
+	 * Passing 0 as first IRQ makes the domain allocate descriptors.
 	 */
-	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
+	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, true, node);
 
 	return 0;
 }
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index ba46c79..30ab39f 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -30,8 +30,10 @@ struct device_node;
 struct pt_regs;
 
 void __vic_init(void __iomem *base, int parent_irq, int irq_start,
-		u32 vic_sources, u32 resume_sources, struct device_node *node);
-void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
+		u32 vic_sources, u32 resume_sources,
+		bool map_fiqs, struct device_node *node);
+void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources,
+	      u32 resume_sources);
 int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 		      u32 vic_sources, u32 resume_sources);
 
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 06/13] irqchip: vic: Add support for FIQ management
@ 2014-06-19 10:38         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

This patch introduces callbacks to route interrupts to or away
from the FIQ signal. It also causes these callbacks to be registered
with the FIQ infrastructure.

This patch enable FIQ support for mach-versatile whilst mach-ep93xx,
mach-netx, mach-s3c64xx and plat-samsung are unmodified (and can therefore
continue to use init_FIQ() as before).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: linux-samsung-soc at vger.kernel.org
---
 arch/arm/mach-versatile/core.c  |  2 +-
 drivers/irqchip/irq-vic.c       | 92 ++++++++++++++++++++++++++++++++---------
 include/linux/irqchip/arm-vic.h |  6 ++-
 3 files changed, 78 insertions(+), 22 deletions(-)

diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index be83ba2..1abf360 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -108,7 +108,7 @@ void __init versatile_init_irq(void)
 
 	np = of_find_matching_node_by_address(NULL, vic_of_match,
 					      VERSATILE_VIC_BASE);
-	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np);
+	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np ? false : true, np);
 
 	writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
 
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287..22aa126 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -36,6 +36,9 @@
 
 #include <asm/exception.h>
 #include <asm/irq.h>
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 
 #include "irqchip.h"
 
@@ -261,11 +264,53 @@ static struct irq_domain_ops vic_irqdomain_ops = {
 	.xlate = irq_domain_xlate_onetwocell,
 };
 
+#ifdef CONFIG_FIQ
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
+static void vic_set_fiq(struct irq_data *d, bool enable)
+{
+	void __iomem *base = irq_data_get_irq_chip_data(d);
+	unsigned int irq = d->hwirq;
+	u32 val;
+
+	raw_spin_lock(&irq_controller_lock);
+	val = readl(base + VIC_INT_SELECT);
+	if (enable)
+		val |= 1 << irq;
+	else
+		val &= ~(1 << irq);
+	writel(val, base + VIC_INT_SELECT);
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void vic_enable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, true);
+}
+
+static void vic_disable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, false);
+}
+
+struct fiq_chip vic_fiq = {
+	.fiq_enable = vic_enable_fiq,
+	.fiq_disable = vic_disable_fiq,
+};
+
+static void vic_register_fiq(int irq)
+{
+	fiq_register_mapping(irq, &vic_fiq);
+}
+#else /* CONFIG_FIQ */
+static inline void vic_register_fiq(int irq) {}
+#endif /* CONFIG_FIQ */
+
 /**
  * vic_register() - Register a VIC.
  * @base: The base address of the VIC.
  * @parent_irq: The parent IRQ if cascaded, else 0.
- * @irq: The base IRQ for the VIC.
+ * @irq_start: The base IRQ for the VIC.
  * @valid_sources: bitmask of valid interrupts
  * @resume_sources: bitmask of interrupts allowed for resume sources.
  * @node: The device tree node associated with the VIC.
@@ -277,12 +322,13 @@ static struct irq_domain_ops vic_irqdomain_ops = {
  * This also configures the IRQ domain for the VIC.
  */
 static void __init vic_register(void __iomem *base, unsigned int parent_irq,
-				unsigned int irq,
+				unsigned int irq_start,
 				u32 valid_sources, u32 resume_sources,
-				struct device_node *node)
+				bool map_fiqs, struct device_node *node)
 {
 	struct vic_device *v;
 	int i;
+	unsigned int irq;
 
 	if (vic_id >= ARRAY_SIZE(vic_devices)) {
 		printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
@@ -301,15 +347,19 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 		irq_set_chained_handler(parent_irq, vic_handle_irq_cascaded);
 	}
 
-	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq,
+	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq_start,
 					  &vic_irqdomain_ops, v);
 	/* create an IRQ mapping for each valid IRQ */
-	for (i = 0; i < fls(valid_sources); i++)
-		if (valid_sources & (1 << i))
-			irq_create_mapping(v->domain, i);
+	for (i = 0; i < fls(valid_sources); i++) {
+		if (valid_sources & (1 << i)) {
+			irq = irq_create_mapping(v->domain, i);
+			vic_register_fiq(irq);
+		}
+	}
+
 	/* If no base IRQ was passed, figure out our allocated base */
-	if (irq)
-		v->irq = irq;
+	if (irq_start)
+		v->irq = irq_start;
 	else
 		v->irq = irq_find_mapping(v->domain, 0);
 }
@@ -413,7 +463,8 @@ static void __init vic_clear_interrupts(void __iomem *base)
  *  and 020 within the page. We call this "second block".
  */
 static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
-			       u32 vic_sources, struct device_node *node)
+			       u32 vic_sources, bool map_fiqs,
+			       struct device_node *node)
 {
 	unsigned int i;
 	int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
@@ -439,12 +490,12 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
 		writel(32, base + VIC_PL190_DEF_VECT_ADDR);
 	}
 
-	vic_register(base, 0, irq_start, vic_sources, 0, node);
+	vic_register(base, 0, irq_start, vic_sources, 0, map_fiqs, node);
 }
 
 void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
-			      u32 vic_sources, u32 resume_sources,
-			      struct device_node *node)
+		       u32 vic_sources, u32 resume_sources,
+		       bool map_fiqs, struct device_node *node)
 {
 	unsigned int i;
 	u32 cellid = 0;
@@ -462,7 +513,7 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	switch(vendor) {
 	case AMBA_VENDOR_ST:
-		vic_init_st(base, irq_start, vic_sources, node);
+		vic_init_st(base, irq_start, vic_sources, map_fiqs, node);
 		return;
 	default:
 		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
@@ -479,7 +530,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	vic_init2(base);
 
-	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);
+	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources,
+		     map_fiqs, node);
 }
 
 /**
@@ -492,7 +544,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 void __init vic_init(void __iomem *base, unsigned int irq_start,
 		     u32 vic_sources, u32 resume_sources)
 {
-	__vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL);
+	__vic_init(base, 0, irq_start, vic_sources, resume_sources,
+		   false, NULL);
 }
 
 /**
@@ -511,7 +564,8 @@ int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 	struct vic_device *v;
 
 	v = &vic_devices[vic_id];
-	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL);
+	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, false,
+		   NULL);
 	/* Return out acquired base */
 	return v->irq;
 }
@@ -535,9 +589,9 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
 	of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask);
 
 	/*
-	 * Passing 0 as first IRQ makes the simple domain allocate descriptors
+	 * Passing 0 as first IRQ makes the domain allocate descriptors.
 	 */
-	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
+	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, true, node);
 
 	return 0;
 }
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index ba46c79..30ab39f 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -30,8 +30,10 @@ struct device_node;
 struct pt_regs;
 
 void __vic_init(void __iomem *base, int parent_irq, int irq_start,
-		u32 vic_sources, u32 resume_sources, struct device_node *node);
-void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
+		u32 vic_sources, u32 resume_sources,
+		bool map_fiqs, struct device_node *node);
+void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources,
+	      u32 resume_sources);
 int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 		      u32 vic_sources, u32 resume_sources);
 
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 07/13] ARM: Move some macros from entry-armv to entry-header
  2014-06-19 10:38       ` Daniel Thompson
@ 2014-06-19 10:38         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Ian Campbell, Anton Vorontsov, David A. Long, linux-serial,
	Catalin Marinas, kernel-team, devicetree, linaro-kernel,
	Pawel Moll, patches, Kumar Gala, Rob Herring, John Stultz,
	Thomas Gleixner, linux-arm-kernel, Greg Kroah-Hartman

From: Anton Vorontsov <anton.vorontsov@linaro.org>

Just move the macros into header file as we would want to use them for
KGDB FIQ entry code.

The following macros were moved:

 - svc_entry
 - usr_entry
 - kuser_cmpxchg_check
 - vector_stub

To make kuser_cmpxchg_check actually work across different files, we
also have to make kuser_cmpxchg64_fixup global.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
---
 arch/arm/kernel/entry-armv.S   | 151 +-----------------
 arch/arm/kernel/entry-header.S | 350 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 351 insertions(+), 150 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 52a949a..4172cd6 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -140,53 +140,6 @@ ENDPROC(__und_invalid)
  * SVC mode handlers
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
-#define SPFIX(code...) code
-#else
-#define SPFIX(code...)
-#endif
-
-	.macro	svc_entry, stack_hole=0
- UNWIND(.fnstart		)
- UNWIND(.save {r0 - pc}		)
-	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
-#ifdef CONFIG_THUMB2_KERNEL
- SPFIX(	str	r0, [sp]	)	@ temporarily saved
- SPFIX(	mov	r0, sp		)
- SPFIX(	tst	r0, #4		)	@ test original stack alignment
- SPFIX(	ldr	r0, [sp]	)	@ restored
-#else
- SPFIX(	tst	sp, #4		)
-#endif
- SPFIX(	subeq	sp, sp, #4	)
-	stmia	sp, {r1 - r12}
-
-	ldmia	r0, {r3 - r5}
-	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""      ""       ""
-	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
- SPFIX(	addeq	r2, r2, #4	)
-	str	r3, [sp, #-4]!		@ save the "real" r0 copied
-					@ from the exception stack
-
-	mov	r3, lr
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r2 - sp_svc
-	@  r3 - lr_svc
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	stmia	r7, {r2 - r6}
-
-#ifdef CONFIG_TRACE_IRQFLAGS
-	bl	trace_hardirqs_off
-#endif
-	.endm
-
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -306,73 +259,8 @@ ENDPROC(__pabt_svc)
 
 /*
  * User mode handlers
- *
- * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0, .LCcralign
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
 	.align	5
 __dabt_usr:
 	usr_entry
@@ -823,6 +711,7 @@ __kuser_cmpxchg64:				@ 0xffff0f60
 	ldmfd	sp!, {r4, r5, r6, pc}
 
 	.text
+	.global kuser_cmpxchg64_fixup
 kuser_cmpxchg64_fixup:
 	@ Called from kuser_cmpxchg_fixup.
 	@ r4 = address of interrupted insn (must be preserved).
@@ -964,44 +853,6 @@ __kuser_helper_end:
  * SP points to a minimal amount of processor-private memory, the address
  * of which is copied into r0 for the mode specific abort handler.
  */
-	.macro	vector_stub, name, mode, correction=0
-	.align	5
-
-vector_\name:
-	.if \correction
-	sub	lr, lr, #\correction
-	.endif
-
-	@
-	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
-	@ (parent CPSR)
-	@
-	stmia	sp, {r0, lr}		@ save r0, lr
-	mrs	lr, spsr
-	str	lr, [sp, #8]		@ save spsr
-
-	@
-	@ Prepare for SVC32 mode.  IRQs remain disabled.
-	@
-	mrs	r0, cpsr
-	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
-	msr	spsr_cxsf, r0
-
-	@
-	@ the branch table must immediately follow this code
-	@
-	and	lr, lr, #0x0f
- THUMB(	adr	r0, 1f			)
- THUMB(	ldr	lr, [r0, lr, lsl #2]	)
-	mov	r0, sp
- ARM(	ldr	lr, [pc, lr, lsl #2]	)
-	movs	pc, lr			@ branch to handler in SVC mode
-ENDPROC(vector_\name)
-
-	.align	2
-	@ handler addresses follow this label
-1:
-	.endm
 
 	.section .stubs, "ax", %progbits
 __stubs_start:
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 5d702f8..572f4b4 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -356,3 +356,353 @@ scno	.req	r7		@ syscall number
 tbl	.req	r8		@ syscall table pointer
 why	.req	r8		@ Linux syscall (!= 0)
 tsk	.req	r9		@ current thread_info
+
+/*
+ * SVC mode handler macros
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define SPFIX(code...) code
+#else
+#define SPFIX(code...)
+#endif
+
+	.macro	svc_entry, stack_hole=0
+ UNWIND(.fnstart		)
+ UNWIND(.save {r0 - pc}		)
+	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+#ifdef CONFIG_THUMB2_KERNEL
+ SPFIX(	str	r0, [sp]	)	@ temporarily saved
+ SPFIX(	mov	r0, sp		)
+ SPFIX(	tst	r0, #4		)	@ test original stack alignment
+ SPFIX(	ldr	r0, [sp]	)	@ restored
+#else
+ SPFIX(	tst	sp, #4		)
+#endif
+ SPFIX(	subeq	sp, sp, #4	)
+	stmia	sp, {r1 - r12}
+
+	ldmia	r0, {r3 - r5}
+	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""      ""       ""
+	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+ SPFIX(	addeq	r2, r2, #4	)
+	str	r3, [sp, #-4]!		@ save the "real" r0 copied
+					@ from the exception stack
+
+	mov	r3, lr
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r2 - sp_svc
+	@  r3 - lr_svc
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	stmia	r7, {r2 - r6}
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_off
+#endif
+	.endm
+
+/*
+ * User mode handler macros
+ *
+ * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0, .LCcralign
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0, .LCcralign
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0, .LCcralign
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+/*
+ * Vector stubs macro.
+ */
+	.macro	vector_stub, name, mode, correction=0
+	.align	5
+
+vector_\name:
+	.if \correction
+	sub	lr, lr, #\correction
+	.endif
+
+	@
+	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
+	@ (parent CPSR)
+	@
+	stmia	sp, {r0, lr}		@ save r0, lr
+	mrs	lr, spsr
+	str	lr, [sp, #8]		@ save spsr
+
+	@
+	@ Prepare for SVC32 mode.  IRQs remain disabled.
+	@
+	mrs	r0, cpsr
+	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
+	msr	spsr_cxsf, r0
+
+	@
+	@ the branch table must immediately follow this code
+	@
+	and	lr, lr, #0x0f
+ THUMB(	adr	r0, 1f			)
+ THUMB(	ldr	lr, [r0, lr, lsl #2]	)
+	mov	r0, sp
+ ARM(	ldr	lr, [pc, lr, lsl #2]	)
+	movs	pc, lr			@ branch to handler in SVC mode
+ENDPROC(vector_\name)
+
+	.align	2
+	@ handler addresses follow this label
+1:
+	.endm
+
+
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 07/13] ARM: Move some macros from entry-armv to entry-header
@ 2014-06-19 10:38         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

From: Anton Vorontsov <anton.vorontsov@linaro.org>

Just move the macros into header file as we would want to use them for
KGDB FIQ entry code.

The following macros were moved:

 - svc_entry
 - usr_entry
 - kuser_cmpxchg_check
 - vector_stub

To make kuser_cmpxchg_check actually work across different files, we
also have to make kuser_cmpxchg64_fixup global.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
---
 arch/arm/kernel/entry-armv.S   | 151 +-----------------
 arch/arm/kernel/entry-header.S | 350 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 351 insertions(+), 150 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 52a949a..4172cd6 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -140,53 +140,6 @@ ENDPROC(__und_invalid)
  * SVC mode handlers
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
-#define SPFIX(code...) code
-#else
-#define SPFIX(code...)
-#endif
-
-	.macro	svc_entry, stack_hole=0
- UNWIND(.fnstart		)
- UNWIND(.save {r0 - pc}		)
-	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
-#ifdef CONFIG_THUMB2_KERNEL
- SPFIX(	str	r0, [sp]	)	@ temporarily saved
- SPFIX(	mov	r0, sp		)
- SPFIX(	tst	r0, #4		)	@ test original stack alignment
- SPFIX(	ldr	r0, [sp]	)	@ restored
-#else
- SPFIX(	tst	sp, #4		)
-#endif
- SPFIX(	subeq	sp, sp, #4	)
-	stmia	sp, {r1 - r12}
-
-	ldmia	r0, {r3 - r5}
-	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""      ""       ""
-	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
- SPFIX(	addeq	r2, r2, #4	)
-	str	r3, [sp, #-4]!		@ save the "real" r0 copied
-					@ from the exception stack
-
-	mov	r3, lr
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r2 - sp_svc
-	@  r3 - lr_svc
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	stmia	r7, {r2 - r6}
-
-#ifdef CONFIG_TRACE_IRQFLAGS
-	bl	trace_hardirqs_off
-#endif
-	.endm
-
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -306,73 +259,8 @@ ENDPROC(__pabt_svc)
 
 /*
  * User mode handlers
- *
- * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0, .LCcralign
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
 	.align	5
 __dabt_usr:
 	usr_entry
@@ -823,6 +711,7 @@ __kuser_cmpxchg64:				@ 0xffff0f60
 	ldmfd	sp!, {r4, r5, r6, pc}
 
 	.text
+	.global kuser_cmpxchg64_fixup
 kuser_cmpxchg64_fixup:
 	@ Called from kuser_cmpxchg_fixup.
 	@ r4 = address of interrupted insn (must be preserved).
@@ -964,44 +853,6 @@ __kuser_helper_end:
  * SP points to a minimal amount of processor-private memory, the address
  * of which is copied into r0 for the mode specific abort handler.
  */
-	.macro	vector_stub, name, mode, correction=0
-	.align	5
-
-vector_\name:
-	.if \correction
-	sub	lr, lr, #\correction
-	.endif
-
-	@
-	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
-	@ (parent CPSR)
-	@
-	stmia	sp, {r0, lr}		@ save r0, lr
-	mrs	lr, spsr
-	str	lr, [sp, #8]		@ save spsr
-
-	@
-	@ Prepare for SVC32 mode.  IRQs remain disabled.
-	@
-	mrs	r0, cpsr
-	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
-	msr	spsr_cxsf, r0
-
-	@
-	@ the branch table must immediately follow this code
-	@
-	and	lr, lr, #0x0f
- THUMB(	adr	r0, 1f			)
- THUMB(	ldr	lr, [r0, lr, lsl #2]	)
-	mov	r0, sp
- ARM(	ldr	lr, [pc, lr, lsl #2]	)
-	movs	pc, lr			@ branch to handler in SVC mode
-ENDPROC(vector_\name)
-
-	.align	2
-	@ handler addresses follow this label
-1:
-	.endm
 
 	.section .stubs, "ax", %progbits
 __stubs_start:
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 5d702f8..572f4b4 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -356,3 +356,353 @@ scno	.req	r7		@ syscall number
 tbl	.req	r8		@ syscall table pointer
 why	.req	r8		@ Linux syscall (!= 0)
 tsk	.req	r9		@ current thread_info
+
+/*
+ * SVC mode handler macros
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define SPFIX(code...) code
+#else
+#define SPFIX(code...)
+#endif
+
+	.macro	svc_entry, stack_hole=0
+ UNWIND(.fnstart		)
+ UNWIND(.save {r0 - pc}		)
+	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+#ifdef CONFIG_THUMB2_KERNEL
+ SPFIX(	str	r0, [sp]	)	@ temporarily saved
+ SPFIX(	mov	r0, sp		)
+ SPFIX(	tst	r0, #4		)	@ test original stack alignment
+ SPFIX(	ldr	r0, [sp]	)	@ restored
+#else
+ SPFIX(	tst	sp, #4		)
+#endif
+ SPFIX(	subeq	sp, sp, #4	)
+	stmia	sp, {r1 - r12}
+
+	ldmia	r0, {r3 - r5}
+	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""      ""       ""
+	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+ SPFIX(	addeq	r2, r2, #4	)
+	str	r3, [sp, #-4]!		@ save the "real" r0 copied
+					@ from the exception stack
+
+	mov	r3, lr
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r2 - sp_svc
+	@  r3 - lr_svc
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	stmia	r7, {r2 - r6}
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_off
+#endif
+	.endm
+
+/*
+ * User mode handler macros
+ *
+ * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0, .LCcralign
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0, .LCcralign
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0, .LCcralign
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+/*
+ * Vector stubs macro.
+ */
+	.macro	vector_stub, name, mode, correction=0
+	.align	5
+
+vector_\name:
+	.if \correction
+	sub	lr, lr, #\correction
+	.endif
+
+	@
+	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
+	@ (parent CPSR)
+	@
+	stmia	sp, {r0, lr}		@ save r0, lr
+	mrs	lr, spsr
+	str	lr, [sp, #8]		@ save spsr
+
+	@
+	@ Prepare for SVC32 mode.  IRQs remain disabled.
+	@
+	mrs	r0, cpsr
+	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
+	msr	spsr_cxsf, r0
+
+	@
+	@ the branch table must immediately follow this code
+	@
+	and	lr, lr, #0x0f
+ THUMB(	adr	r0, 1f			)
+ THUMB(	ldr	lr, [r0, lr, lsl #2]	)
+	mov	r0, sp
+ ARM(	ldr	lr, [pc, lr, lsl #2]	)
+	movs	pc, lr			@ branch to handler in SVC mode
+ENDPROC(vector_\name)
+
+	.align	2
+	@ handler addresses follow this label
+1:
+	.endm
+
+
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 08/13] ARM: Add KGDB/KDB FIQ debugger generic code
  2014-06-19 10:38       ` Daniel Thompson
@ 2014-06-19 10:38         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Ian Campbell, Anton Vorontsov, Ben Dooks, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, Dave Martin,
	devicetree, linaro-kernel, Pawel Moll, patches, Kumar Gala,
	Rob Herring, John Stultz, Thomas Gleixner

From: Anton Vorontsov <anton.vorontsov@linaro.org>

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

By default KGDB FIQ is disabled in runtime, but can be enabled with
kgdb_fiq.enable=1 kernel command line option.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben.dooks@codethink.co.uk>
Cc: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 ++++
 arch/arm/include/asm/kgdb.h      |   7 ++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/entry-header.S   | 186 ---------------------------------------
 arch/arm/kernel/kgdb_fiq.c       | 124 ++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S |  87 ++++++++++++++++++
 7 files changed, 239 insertions(+), 186 deletions(-)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 87b63fd..32795c2 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -304,6 +304,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -354,6 +355,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 26536f7..c7342b6 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,24 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be
+	  enabled with kgdb_fiq.enable=1 kernel command line option.
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..5de21f01 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,11 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern char kgdb_fiq_handler;
+extern char kgdb_fiq_handler_end;
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs);
+extern int kgdb_register_fiq(unsigned int fiq);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 38ddd9f..30ee8f3 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -68,6 +68,7 @@ endif
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
 obj-$(CONFIG_ARM_THUMBEE)	+= thumbee.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
+obj-$(CONFIG_KGDB_FIQ)		+= kgdb_fiq_entry.o kgdb_fiq.o
 obj-$(CONFIG_ARM_UNWIND)	+= unwind.o
 obj-$(CONFIG_HAVE_TCM)		+= tcm.o
 obj-$(CONFIG_OF)		+= devtree.o
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 572f4b4..eb2c426 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -477,192 +477,6 @@ tsk	.req	r9		@ current thread_info
 #endif
 	.endm
 
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0, .LCcralign
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0, .LCcralign
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
 /*
  * Vector stubs macro.
  */
diff --git a/arch/arm/kernel/kgdb_fiq.c b/arch/arm/kernel/kgdb_fiq.c
new file mode 100644
index 0000000..dbf4873
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq.c
@@ -0,0 +1,124 @@
+/*
+ * KGDB FIQ
+ *
+ * Copyright 2010 Google, Inc.
+ *		  Arve Hjønnevåg <arve@android.com>
+ *		  Colin Cross <ccross@android.com>
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/hardirq.h>
+#include <linux/atomic.h>
+#include <linux/kdb.h>
+#include <linux/kgdb.h>
+#include <asm/fiq.h>
+#include <asm/exception.h>
+
+static int kgdb_fiq_enabled;
+module_param_named(enable, kgdb_fiq_enabled, int, 0600);
+MODULE_PARM_DESC(enable, "set to 1 to enable FIQ KGDB");
+
+static unsigned int kgdb_fiq;
+
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs)
+{
+	if (kgdb_nmi_poll_knock()) {
+		nmi_enter();
+		kgdb_handle_exception(1, 0, 0, regs);
+		nmi_exit();
+	}
+
+	eoi_fiq(kgdb_fiq);
+}
+
+static struct fiq_handler kgdb_fiq_desc = {
+	.name = "kgdb",
+};
+
+static long kgdb_fiq_setup_stack(void *info)
+{
+	struct pt_regs regs;
+
+	regs.ARM_sp = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER) +
+			THREAD_START_SP;
+	WARN_ON(!regs.ARM_sp);
+
+	set_fiq_regs(&regs);
+	return 0;
+}
+
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * This function manages NMIs that usually cause KGDB to enter. That is, not
+ * all NMIs should be enabled or disabled, but only those that issue
+ * kgdb_handle_exception().
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	static atomic_t cnt;
+	int ret;
+
+	ret = atomic_add_return(on ? 1 : -1, &cnt);
+	if (ret > 1 && on) {
+		/*
+		 * There should be only one instance that calls this function
+		 * in "enable, disable" order. All other users must call
+		 * disable first, then enable. If not, something is wrong.
+		 */
+		WARN_ON(1);
+		return;
+	}
+
+	if (ret > 0)
+		enable_fiq(kgdb_fiq);
+	else
+		disable_fiq(kgdb_fiq);
+}
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	int err;
+	int cpu;
+
+	if (!kgdb_fiq_enabled)
+		return -ENODEV;
+
+	if (!has_fiq(fiq)) {
+		pr_warn(
+		    "%s: Cannot register %u (no FIQ with this number)\n",
+		    __func__, fiq);
+		return -ENODEV;
+	}
+
+	kgdb_fiq = fiq;
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	for_each_possible_cpu(cpu)
+		work_on_cpu(cpu, kgdb_fiq_setup_stack, NULL);
+
+	set_fiq_handler(&kgdb_fiq_handler,
+			&kgdb_fiq_handler_end - &kgdb_fiq_handler);
+
+	arch_kgdb_ops.enable_nmi = kgdb_fiq_enable_nmi;
+	return 0;
+}
diff --git a/arch/arm/kernel/kgdb_fiq_entry.S b/arch/arm/kernel/kgdb_fiq_entry.S
new file mode 100644
index 0000000..d6becca
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq_entry.S
@@ -0,0 +1,87 @@
+/*
+ * KGDB FIQ entry
+ *
+ * Copyright 1996,1997,1998 Russell King.
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+#include <asm/unwind.h>
+#include "entry-header.S"
+
+	.text
+
+@ This is needed for usr_entry/alignment_trap
+.LCcralign:
+	.long	cr_alignment
+.LCdohandle:
+	.long	kgdb_fiq_do_handle
+
+	.macro	fiq_handler
+	ldr	r1, =.LCdohandle
+	mov	r0, sp
+	adr	lr, BSYM(9997f)
+	ldr	pc, [r1]
+9997:
+	.endm
+
+	.align	5
+__fiq_svc:
+	svc_entry
+	fiq_handler
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+	.ltorg
+
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+	.ltorg
+
+	.global kgdb_fiq_handler
+kgdb_fiq_handler:
+
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_svc			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
+
+	.global kgdb_fiq_handler_end
+kgdb_fiq_handler_end:
-- 
1.9.3


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 08/13] ARM: Add KGDB/KDB FIQ debugger generic code
@ 2014-06-19 10:38         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

From: Anton Vorontsov <anton.vorontsov@linaro.org>

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

By default KGDB FIQ is disabled in runtime, but can be enabled with
kgdb_fiq.enable=1 kernel command line option.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben.dooks@codethink.co.uk>
Cc: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 ++++
 arch/arm/include/asm/kgdb.h      |   7 ++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/entry-header.S   | 186 ---------------------------------------
 arch/arm/kernel/kgdb_fiq.c       | 124 ++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S |  87 ++++++++++++++++++
 7 files changed, 239 insertions(+), 186 deletions(-)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 87b63fd..32795c2 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -304,6 +304,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -354,6 +355,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 26536f7..c7342b6 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,24 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be
+	  enabled with kgdb_fiq.enable=1 kernel command line option.
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..5de21f01 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,11 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern char kgdb_fiq_handler;
+extern char kgdb_fiq_handler_end;
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs);
+extern int kgdb_register_fiq(unsigned int fiq);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 38ddd9f..30ee8f3 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -68,6 +68,7 @@ endif
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
 obj-$(CONFIG_ARM_THUMBEE)	+= thumbee.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
+obj-$(CONFIG_KGDB_FIQ)		+= kgdb_fiq_entry.o kgdb_fiq.o
 obj-$(CONFIG_ARM_UNWIND)	+= unwind.o
 obj-$(CONFIG_HAVE_TCM)		+= tcm.o
 obj-$(CONFIG_OF)		+= devtree.o
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 572f4b4..eb2c426 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -477,192 +477,6 @@ tsk	.req	r9		@ current thread_info
 #endif
 	.endm
 
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0, .LCcralign
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0, .LCcralign
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
 /*
  * Vector stubs macro.
  */
diff --git a/arch/arm/kernel/kgdb_fiq.c b/arch/arm/kernel/kgdb_fiq.c
new file mode 100644
index 0000000..dbf4873
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq.c
@@ -0,0 +1,124 @@
+/*
+ * KGDB FIQ
+ *
+ * Copyright 2010 Google, Inc.
+ *		  Arve Hj?nnev?g <arve@android.com>
+ *		  Colin Cross <ccross@android.com>
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/hardirq.h>
+#include <linux/atomic.h>
+#include <linux/kdb.h>
+#include <linux/kgdb.h>
+#include <asm/fiq.h>
+#include <asm/exception.h>
+
+static int kgdb_fiq_enabled;
+module_param_named(enable, kgdb_fiq_enabled, int, 0600);
+MODULE_PARM_DESC(enable, "set to 1 to enable FIQ KGDB");
+
+static unsigned int kgdb_fiq;
+
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs)
+{
+	if (kgdb_nmi_poll_knock()) {
+		nmi_enter();
+		kgdb_handle_exception(1, 0, 0, regs);
+		nmi_exit();
+	}
+
+	eoi_fiq(kgdb_fiq);
+}
+
+static struct fiq_handler kgdb_fiq_desc = {
+	.name = "kgdb",
+};
+
+static long kgdb_fiq_setup_stack(void *info)
+{
+	struct pt_regs regs;
+
+	regs.ARM_sp = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER) +
+			THREAD_START_SP;
+	WARN_ON(!regs.ARM_sp);
+
+	set_fiq_regs(&regs);
+	return 0;
+}
+
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * This function manages NMIs that usually cause KGDB to enter. That is, not
+ * all NMIs should be enabled or disabled, but only those that issue
+ * kgdb_handle_exception().
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	static atomic_t cnt;
+	int ret;
+
+	ret = atomic_add_return(on ? 1 : -1, &cnt);
+	if (ret > 1 && on) {
+		/*
+		 * There should be only one instance that calls this function
+		 * in "enable, disable" order. All other users must call
+		 * disable first, then enable. If not, something is wrong.
+		 */
+		WARN_ON(1);
+		return;
+	}
+
+	if (ret > 0)
+		enable_fiq(kgdb_fiq);
+	else
+		disable_fiq(kgdb_fiq);
+}
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	int err;
+	int cpu;
+
+	if (!kgdb_fiq_enabled)
+		return -ENODEV;
+
+	if (!has_fiq(fiq)) {
+		pr_warn(
+		    "%s: Cannot register %u (no FIQ with this number)\n",
+		    __func__, fiq);
+		return -ENODEV;
+	}
+
+	kgdb_fiq = fiq;
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	for_each_possible_cpu(cpu)
+		work_on_cpu(cpu, kgdb_fiq_setup_stack, NULL);
+
+	set_fiq_handler(&kgdb_fiq_handler,
+			&kgdb_fiq_handler_end - &kgdb_fiq_handler);
+
+	arch_kgdb_ops.enable_nmi = kgdb_fiq_enable_nmi;
+	return 0;
+}
diff --git a/arch/arm/kernel/kgdb_fiq_entry.S b/arch/arm/kernel/kgdb_fiq_entry.S
new file mode 100644
index 0000000..d6becca
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq_entry.S
@@ -0,0 +1,87 @@
+/*
+ * KGDB FIQ entry
+ *
+ * Copyright 1996,1997,1998 Russell King.
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+#include <asm/unwind.h>
+#include "entry-header.S"
+
+	.text
+
+@ This is needed for usr_entry/alignment_trap
+.LCcralign:
+	.long	cr_alignment
+.LCdohandle:
+	.long	kgdb_fiq_do_handle
+
+	.macro	fiq_handler
+	ldr	r1, =.LCdohandle
+	mov	r0, sp
+	adr	lr, BSYM(9997f)
+	ldr	pc, [r1]
+9997:
+	.endm
+
+	.align	5
+__fiq_svc:
+	svc_entry
+	fiq_handler
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+	.ltorg
+
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+	.ltorg
+
+	.global kgdb_fiq_handler
+kgdb_fiq_handler:
+
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_svc			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
+
+	.global kgdb_fiq_handler_end
+kgdb_fiq_handler_end:
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 09/13] serial: amba-pl011: Pass FIQ information to KGDB.
  2014-06-19 10:38       ` Daniel Thompson
@ 2014-06-19 10:38         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Ian Campbell, Anton Vorontsov, David A. Long, linux-serial,
	Catalin Marinas, kernel-team, devicetree, linaro-kernel,
	Pawel Moll, patches, Kumar Gala, Rob Herring, John Stultz,
	Thomas Gleixner, linux-arm-kernel, Greg Kroah-Hartman

If the AMBA bus has provided the pl011 with a FIQ resource (i.e. a
second IRQ) then speculatively register it with KGDB when the polling
driver is initialized.

By providing this information to KGDB the serial driver offers
"permission" for KGDB to route the UART interrupt signal from the
drivers own handler to KGDBs FIQ handler (which will eventually use the
UART's polled I/O callbacks to interact with the user). This permission
also implies the amba-pl011 driver has already unmasked RX interrupts
(otherwise the FIQ handler will never trigger).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 99 ++++++++++++++++++++++++-----------------
 1 file changed, 58 insertions(+), 41 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 908a6e3..00ba4b6 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -58,6 +58,7 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/sizes.h>
 #include <linux/io.h>
+#include <linux/kgdb.h>
 
 #define UART_NR			14
 
@@ -1416,8 +1417,63 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
 	spin_unlock_irqrestore(&uap->port.lock, flags);
 }
 
+static int pl011_hwinit(struct uart_port *port)
+{
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	int retval;
+
+	/* Optionaly enable pins to be muxed in and configured */
+	pinctrl_pm_select_default_state(port->dev);
+
+	/*
+	 * Try to enable the clock producer.
+	 */
+	retval = clk_prepare_enable(uap->clk);
+	if (retval)
+		goto out;
+
+	uap->port.uartclk = clk_get_rate(uap->clk);
+
+	/* Clear pending error and receive interrupts */
+	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
+	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
+
+	/*
+	 * Save interrupts enable mask, and enable RX interrupts in case if
+	 * the interrupt is used for NMI entry.
+	 */
+	uap->im = readw(uap->port.membase + UART011_IMSC);
+	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
+
+	if (dev_get_platdata(uap->port.dev)) {
+		struct amba_pl011_data *plat;
+
+		plat = dev_get_platdata(uap->port.dev);
+		if (plat->init)
+			plat->init();
+	}
+	return 0;
+ out:
+	return retval;
+}
+
 #ifdef CONFIG_CONSOLE_POLL
 
+static int pl011_poll_init(struct uart_port *port)
+{
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	int retval;
+
+	retval = pl011_hwinit(port);
+
+#ifdef CONFIG_KGDB_FIQ
+	if (retval == 0)
+		kgdb_register_fiq(uap->port.irq);
+#endif
+
+	return retval;
+}
+
 static void pl011_quiesce_irqs(struct uart_port *port)
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1471,46 +1527,6 @@ static void pl011_put_poll_char(struct uart_port *port,
 
 #endif /* CONFIG_CONSOLE_POLL */
 
-static int pl011_hwinit(struct uart_port *port)
-{
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
-	int retval;
-
-	/* Optionaly enable pins to be muxed in and configured */
-	pinctrl_pm_select_default_state(port->dev);
-
-	/*
-	 * Try to enable the clock producer.
-	 */
-	retval = clk_prepare_enable(uap->clk);
-	if (retval)
-		goto out;
-
-	uap->port.uartclk = clk_get_rate(uap->clk);
-
-	/* Clear pending error and receive interrupts */
-	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
-	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
-
-	/*
-	 * Save interrupts enable mask, and enable RX interrupts in case if
-	 * the interrupt is used for NMI entry.
-	 */
-	uap->im = readw(uap->port.membase + UART011_IMSC);
-	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
-
-	if (dev_get_platdata(uap->port.dev)) {
-		struct amba_pl011_data *plat;
-
-		plat = dev_get_platdata(uap->port.dev);
-		if (plat->init)
-			plat->init();
-	}
-	return 0;
- out:
-	return retval;
-}
-
 static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
 {
 	writew(lcr_h, uap->port.membase + uap->lcrh_rx);
@@ -1890,7 +1906,7 @@ static struct uart_ops amba_pl011_pops = {
 	.config_port	= pl011_config_port,
 	.verify_port	= pl011_verify_port,
 #ifdef CONFIG_CONSOLE_POLL
-	.poll_init     = pl011_hwinit,
+	.poll_init     = pl011_poll_init,
 	.poll_get_char = pl011_get_poll_char,
 	.poll_put_char = pl011_put_poll_char,
 #endif
@@ -2198,6 +2214,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
 		uart_unregister_driver(&amba_reg);
 		pl011_dma_remove(uap);
 	}
+
  out:
 	return ret;
 }
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 09/13] serial: amba-pl011: Pass FIQ information to KGDB.
@ 2014-06-19 10:38         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

If the AMBA bus has provided the pl011 with a FIQ resource (i.e. a
second IRQ) then speculatively register it with KGDB when the polling
driver is initialized.

By providing this information to KGDB the serial driver offers
"permission" for KGDB to route the UART interrupt signal from the
drivers own handler to KGDBs FIQ handler (which will eventually use the
UART's polled I/O callbacks to interact with the user). This permission
also implies the amba-pl011 driver has already unmasked RX interrupts
(otherwise the FIQ handler will never trigger).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 99 ++++++++++++++++++++++++-----------------
 1 file changed, 58 insertions(+), 41 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 908a6e3..00ba4b6 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -58,6 +58,7 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/sizes.h>
 #include <linux/io.h>
+#include <linux/kgdb.h>
 
 #define UART_NR			14
 
@@ -1416,8 +1417,63 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
 	spin_unlock_irqrestore(&uap->port.lock, flags);
 }
 
+static int pl011_hwinit(struct uart_port *port)
+{
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	int retval;
+
+	/* Optionaly enable pins to be muxed in and configured */
+	pinctrl_pm_select_default_state(port->dev);
+
+	/*
+	 * Try to enable the clock producer.
+	 */
+	retval = clk_prepare_enable(uap->clk);
+	if (retval)
+		goto out;
+
+	uap->port.uartclk = clk_get_rate(uap->clk);
+
+	/* Clear pending error and receive interrupts */
+	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
+	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
+
+	/*
+	 * Save interrupts enable mask, and enable RX interrupts in case if
+	 * the interrupt is used for NMI entry.
+	 */
+	uap->im = readw(uap->port.membase + UART011_IMSC);
+	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
+
+	if (dev_get_platdata(uap->port.dev)) {
+		struct amba_pl011_data *plat;
+
+		plat = dev_get_platdata(uap->port.dev);
+		if (plat->init)
+			plat->init();
+	}
+	return 0;
+ out:
+	return retval;
+}
+
 #ifdef CONFIG_CONSOLE_POLL
 
+static int pl011_poll_init(struct uart_port *port)
+{
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	int retval;
+
+	retval = pl011_hwinit(port);
+
+#ifdef CONFIG_KGDB_FIQ
+	if (retval == 0)
+		kgdb_register_fiq(uap->port.irq);
+#endif
+
+	return retval;
+}
+
 static void pl011_quiesce_irqs(struct uart_port *port)
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1471,46 +1527,6 @@ static void pl011_put_poll_char(struct uart_port *port,
 
 #endif /* CONFIG_CONSOLE_POLL */
 
-static int pl011_hwinit(struct uart_port *port)
-{
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
-	int retval;
-
-	/* Optionaly enable pins to be muxed in and configured */
-	pinctrl_pm_select_default_state(port->dev);
-
-	/*
-	 * Try to enable the clock producer.
-	 */
-	retval = clk_prepare_enable(uap->clk);
-	if (retval)
-		goto out;
-
-	uap->port.uartclk = clk_get_rate(uap->clk);
-
-	/* Clear pending error and receive interrupts */
-	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
-	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
-
-	/*
-	 * Save interrupts enable mask, and enable RX interrupts in case if
-	 * the interrupt is used for NMI entry.
-	 */
-	uap->im = readw(uap->port.membase + UART011_IMSC);
-	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
-
-	if (dev_get_platdata(uap->port.dev)) {
-		struct amba_pl011_data *plat;
-
-		plat = dev_get_platdata(uap->port.dev);
-		if (plat->init)
-			plat->init();
-	}
-	return 0;
- out:
-	return retval;
-}
-
 static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
 {
 	writew(lcr_h, uap->port.membase + uap->lcrh_rx);
@@ -1890,7 +1906,7 @@ static struct uart_ops amba_pl011_pops = {
 	.config_port	= pl011_config_port,
 	.verify_port	= pl011_verify_port,
 #ifdef CONFIG_CONSOLE_POLL
-	.poll_init     = pl011_hwinit,
+	.poll_init     = pl011_poll_init,
 	.poll_get_char = pl011_get_poll_char,
 	.poll_put_char = pl011_put_poll_char,
 #endif
@@ -2198,6 +2214,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
 		uart_unregister_driver(&amba_reg);
 		pl011_dma_remove(uap);
 	}
+
  out:
 	return ret;
 }
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 10/13] serial: asc: Add support for KGDB's FIQ/NMI mode
  2014-06-19 10:38       ` Daniel Thompson
@ 2014-06-19 10:38         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij,
	Patrice Chotard, Jiri Slaby, Daniel Thompson, Dirk Behme,
	Russell King, Nicolas Pitre, Ian Campbell, Anton Vorontsov,
	David A. Long, linux-serial, Catalin Marinas, kernel-team,
	devicetree, linaro-kernel, Pawel Moll, patches, Kumar Gala,
	Rob Herring, John Stultz, Thomas Gleixner, linux-arm-kernel

Add a .poll_init() function that enables UART RX and registers the
UART's irq with KGDB. By providing this information to KGDB the serial
driver offers "permission" for KGDB to route the UART interrupt signal
from the drivers own handler to KGDBs FIQ handler (which will eventually
use the UART's polled I/O callbacks to interact with the user).

Note that the RX is not only enabled but also unmasked. This is required
because otherwise the FIQ handler could never trigger. This unmask is
copied from similar code in amba-pl011.c .

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel@stlinux.com
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index c7f61ac..4f376d8 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -30,6 +30,7 @@
 #include <linux/of_platform.h>
 #include <linux/serial_core.h>
 #include <linux/clk.h>
+#include <linux/kgdb.h>
 
 #define DRIVER_NAME "st-asc"
 #define ASC_SERIAL_NAME "ttyAS"
@@ -613,6 +614,25 @@ asc_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+
+#ifdef CONFIG_KGDB_FIQ
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int asc_poll_init(struct uart_port *port)
+{
+	struct asc_port *ascport = container_of(port, struct asc_port, port);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(ascport->port.irq);
+
+	/* enable RX interrupts in case the interrupt is used for NMI entry. */
+	asc_enable_rx_interrupts(port);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 /*
  * Console polling routines for writing and reading from the uart while
  * in an interrupt or debug context (i.e. kgdb).
@@ -656,6 +676,9 @@ static struct uart_ops asc_uart_ops = {
 	.verify_port	= asc_verify_port,
 	.pm		= asc_pm,
 #ifdef CONFIG_CONSOLE_POLL
+#ifdef CONFIG_KGDB_FIQ
+	.poll_init     = asc_poll_init,
+#endif /* CONFIG_KGDB_FIQ */
 	.poll_get_char = asc_get_poll_char,
 	.poll_put_char = asc_put_poll_char,
 #endif /* CONFIG_CONSOLE_POLL */
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 10/13] serial: asc: Add support for KGDB's FIQ/NMI mode
@ 2014-06-19 10:38         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

Add a .poll_init() function that enables UART RX and registers the
UART's irq with KGDB. By providing this information to KGDB the serial
driver offers "permission" for KGDB to route the UART interrupt signal
from the drivers own handler to KGDBs FIQ handler (which will eventually
use the UART's polled I/O callbacks to interact with the user).

Note that the RX is not only enabled but also unmasked. This is required
because otherwise the FIQ handler could never trigger. This unmask is
copied from similar code in amba-pl011.c .

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel at stlinux.com
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index c7f61ac..4f376d8 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -30,6 +30,7 @@
 #include <linux/of_platform.h>
 #include <linux/serial_core.h>
 #include <linux/clk.h>
+#include <linux/kgdb.h>
 
 #define DRIVER_NAME "st-asc"
 #define ASC_SERIAL_NAME "ttyAS"
@@ -613,6 +614,25 @@ asc_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+
+#ifdef CONFIG_KGDB_FIQ
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int asc_poll_init(struct uart_port *port)
+{
+	struct asc_port *ascport = container_of(port, struct asc_port, port);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(ascport->port.irq);
+
+	/* enable RX interrupts in case the interrupt is used for NMI entry. */
+	asc_enable_rx_interrupts(port);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 /*
  * Console polling routines for writing and reading from the uart while
  * in an interrupt or debug context (i.e. kgdb).
@@ -656,6 +676,9 @@ static struct uart_ops asc_uart_ops = {
 	.verify_port	= asc_verify_port,
 	.pm		= asc_pm,
 #ifdef CONFIG_CONSOLE_POLL
+#ifdef CONFIG_KGDB_FIQ
+	.poll_init     = asc_poll_init,
+#endif /* CONFIG_KGDB_FIQ */
 	.poll_get_char = asc_get_poll_char,
 	.poll_put_char = asc_put_poll_char,
 #endif /* CONFIG_CONSOLE_POLL */
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 11/13] serial: asc: Adopt readl_/writel_relaxed()
  2014-06-19 10:38       ` Daniel Thompson
@ 2014-06-19 10:38         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij,
	Patrice Chotard, Jiri Slaby, Daniel Thompson, Dirk Behme,
	Russell King, Nicolas Pitre, Ian Campbell, Anton Vorontsov,
	David A. Long, linux-serial, Catalin Marinas, kernel-team,
	devicetree, linaro-kernel, Pawel Moll, patches, Kumar Gala,
	Rob Herring, John Stultz, Thomas Gleixner, linux-arm-kernel

The architectures supported by this driver have expensive
implementations of writel(), reliant on spin locks and explicit L2 cache
management. These architectures provide a cheaper writel_relaxed() which
is much better suited to peripherals that do not perform DMA. The
situation with readl()/readl_relaxed()is similar although less acute.

This driver does not use DMA and will be more power efficient and more
robust (due to absense of spin locks during console I/O) if it uses the
relaxed variants.

This driver is cross compilable for testing purposes and remains
compilable on all architectures by falling back to writel() when
writel_relaxed() does not exist. We also include explicit compiler
barriers. There are redundant on ARM and SH but important on
x86 because it defines "relaxed" differently.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel@stlinux.com
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 4f376d8..58aa1c6 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -152,12 +152,21 @@ static inline struct asc_port *to_asc_port(struct uart_port *port)
 
 static inline u32 asc_in(struct uart_port *port, u32 offset)
 {
-	return readl(port->membase + offset);
+	u32 r;
+
+	r = readl_relaxed(port->membase + offset);
+	barrier();
+	return r;
 }
 
 static inline void asc_out(struct uart_port *port, u32 offset, u32 value)
 {
+#ifdef writel_relaxed
+	writel_relaxed(value, port->membase + offset);
+	barrier();
+#else
 	writel(value, port->membase + offset);
+#endif
 }
 
 /*
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 11/13] serial: asc: Adopt readl_/writel_relaxed()
@ 2014-06-19 10:38         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

The architectures supported by this driver have expensive
implementations of writel(), reliant on spin locks and explicit L2 cache
management. These architectures provide a cheaper writel_relaxed() which
is much better suited to peripherals that do not perform DMA. The
situation with readl()/readl_relaxed()is similar although less acute.

This driver does not use DMA and will be more power efficient and more
robust (due to absense of spin locks during console I/O) if it uses the
relaxed variants.

This driver is cross compilable for testing purposes and remains
compilable on all architectures by falling back to writel() when
writel_relaxed() does not exist. We also include explicit compiler
barriers. There are redundant on ARM and SH but important on
x86 because it defines "relaxed" differently.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel at stlinux.com
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 4f376d8..58aa1c6 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -152,12 +152,21 @@ static inline struct asc_port *to_asc_port(struct uart_port *port)
 
 static inline u32 asc_in(struct uart_port *port, u32 offset)
 {
-	return readl(port->membase + offset);
+	u32 r;
+
+	r = readl_relaxed(port->membase + offset);
+	barrier();
+	return r;
 }
 
 static inline void asc_out(struct uart_port *port, u32 offset, u32 value)
 {
+#ifdef writel_relaxed
+	writel_relaxed(value, port->membase + offset);
+	barrier();
+#else
 	writel(value, port->membase + offset);
+#endif
 }
 
 /*
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 12/13] serial: imx: clean up imx_poll_get_char()
  2014-06-19 10:38       ` Daniel Thompson
@ 2014-06-19 10:38         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Ian Campbell, Anton Vorontsov, David A. Long, linux-serial,
	Catalin Marinas, kernel-team, devicetree, linaro-kernel,
	Pawel Moll, patches, Kumar Gala, Rob Herring, John Stultz,
	Thomas Gleixner, linux-arm-kernel, Greg Kroah-Hartman

From: Dirk Behme <dirk.behme@de.bosch.com>

Looking at the get_poll_char() function of the 8250.c serial driver,
we learn:

* poll_get_char() doesn't have to save/disable/restore the interrupt
  registers. No interrupt handling is needed in this function at all.
  Remove it.

* Don't block in case there is no data available. So instead blocking
  in the do {} while loop, just return with NO_POLL_CHAR, immediately .

Additionally, while the i.MX6 register URXD[7-0] contain the RX_DATA,
the upper bits of this register (URXD[15-10]) might contain some
control flags. To ensure that these are not returned with the data
read, just mask out URXD[7-0].

These changes fix the 'hang' working with kdb:

$ echo ttymxc3 > /sys/module/kgdboc/parameters/kgdboc
$ echo g >/proc/sysrq-trigger
[0]kdb> help
...
<hang>

Signed-off-by: Dirk Behme <dirk.behme@de.bosch.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/imx.c | 29 ++++-------------------------
 1 file changed, 4 insertions(+), 25 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index e2f9387..25ed1d2 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -80,6 +80,7 @@
 #define URXD_FRMERR	(1<<12)
 #define URXD_BRK	(1<<11)
 #define URXD_PRERR	(1<<10)
+#define URXD_RX_DATA	(0xFF<<0)
 #define UCR1_ADEN	(1<<15) /* Auto detect interrupt */
 #define UCR1_ADBR	(1<<14) /* Auto detect baud rate */
 #define UCR1_TRDYEN	(1<<13) /* Transmitter ready interrupt enable */
@@ -1503,32 +1504,10 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
 #if defined(CONFIG_CONSOLE_POLL)
 static int imx_poll_get_char(struct uart_port *port)
 {
-	struct imx_port_ucrs old_ucr;
-	unsigned int status;
-	unsigned char c;
-
-	/* save control registers */
-	imx_port_ucrs_save(port, &old_ucr);
-
-	/* disable interrupts */
-	writel(UCR1_UARTEN, port->membase + UCR1);
-	writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
-	       port->membase + UCR2);
-	writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
-	       port->membase + UCR3);
-
-	/* poll */
-	do {
-		status = readl(port->membase + USR2);
-	} while (~status & USR2_RDR);
-
-	/* read */
-	c = readl(port->membase + URXD0);
-
-	/* restore control registers */
-	imx_port_ucrs_restore(port, &old_ucr);
+	if (!(readl(port->membase + USR2) & USR2_RDR))
+		return NO_POLL_CHAR;
 
-	return c;
+	return readl(port->membase + URXD0) & URXD_RX_DATA;
 }
 
 static void imx_poll_put_char(struct uart_port *port, unsigned char c)
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 12/13] serial: imx: clean up imx_poll_get_char()
@ 2014-06-19 10:38         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

From: Dirk Behme <dirk.behme@de.bosch.com>

Looking at the get_poll_char() function of the 8250.c serial driver,
we learn:

* poll_get_char() doesn't have to save/disable/restore the interrupt
  registers. No interrupt handling is needed in this function at all.
  Remove it.

* Don't block in case there is no data available. So instead blocking
  in the do {} while loop, just return with NO_POLL_CHAR, immediately .

Additionally, while the i.MX6 register URXD[7-0] contain the RX_DATA,
the upper bits of this register (URXD[15-10]) might contain some
control flags. To ensure that these are not returned with the data
read, just mask out URXD[7-0].

These changes fix the 'hang' working with kdb:

$ echo ttymxc3 > /sys/module/kgdboc/parameters/kgdboc
$ echo g >/proc/sysrq-trigger
[0]kdb> help
...
<hang>

Signed-off-by: Dirk Behme <dirk.behme@de.bosch.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/imx.c | 29 ++++-------------------------
 1 file changed, 4 insertions(+), 25 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index e2f9387..25ed1d2 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -80,6 +80,7 @@
 #define URXD_FRMERR	(1<<12)
 #define URXD_BRK	(1<<11)
 #define URXD_PRERR	(1<<10)
+#define URXD_RX_DATA	(0xFF<<0)
 #define UCR1_ADEN	(1<<15) /* Auto detect interrupt */
 #define UCR1_ADBR	(1<<14) /* Auto detect baud rate */
 #define UCR1_TRDYEN	(1<<13) /* Transmitter ready interrupt enable */
@@ -1503,32 +1504,10 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
 #if defined(CONFIG_CONSOLE_POLL)
 static int imx_poll_get_char(struct uart_port *port)
 {
-	struct imx_port_ucrs old_ucr;
-	unsigned int status;
-	unsigned char c;
-
-	/* save control registers */
-	imx_port_ucrs_save(port, &old_ucr);
-
-	/* disable interrupts */
-	writel(UCR1_UARTEN, port->membase + UCR1);
-	writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
-	       port->membase + UCR2);
-	writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
-	       port->membase + UCR3);
-
-	/* poll */
-	do {
-		status = readl(port->membase + USR2);
-	} while (~status & USR2_RDR);
-
-	/* read */
-	c = readl(port->membase + URXD0);
-
-	/* restore control registers */
-	imx_port_ucrs_restore(port, &old_ucr);
+	if (!(readl(port->membase + USR2) & USR2_RDR))
+		return NO_POLL_CHAR;
 
-	return c;
+	return readl(port->membase + URXD0) & URXD_RX_DATA;
 }
 
 static void imx_poll_put_char(struct uart_port *port, unsigned char c)
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 13/13] serial: imx: Add support for KGDB's FIQ/NMI mode
  2014-06-19 10:38       ` Daniel Thompson
@ 2014-06-19 10:38         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Daniel Thompson, Dirk Behme, Russell King, Nicolas Pitre,
	Ian Campbell, Anton Vorontsov, David A. Long, linux-serial,
	Catalin Marinas, kernel-team, devicetree, linaro-kernel,
	Pawel Moll, patches, Kumar Gala, Rob Herring, John Stultz,
	Thomas Gleixner, linux-arm-kernel, Greg Kroah-Hartman

This patch makes it possible to use the imx uart with KGDB's FIQ/NMI
mode.

Main changes are:

.poll_init() will, if KGDB+FIQ are enabled, perform deeper hardware
initialization to ensure the serial port is always active (required
otherwise FIQ is not triggered by UART activity). This has an impact on
power usage so it is conservatively enabled.

imx_put_poll_char() has been simplified to remove the code to disable
interrupts. The present code can corrupt register state when re-entered
from FIQ handler.

Both imx_put_poll_char() and imx_get_poll_char() adopt _relaxed()
MMIO functions (which are safe for polled I/O and needed to avoid taking
spin locks).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/imx.c | 71 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 52 insertions(+), 19 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 25ed1d2..a2baf7e 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -49,6 +49,7 @@
 #include <linux/of_device.h>
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
+#include <linux/kgdb.h>
 
 #include <asm/irq.h>
 #include <linux/platform_data/serial-imx.h>
@@ -1502,44 +1503,73 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #if defined(CONFIG_CONSOLE_POLL)
+
+#if defined(CONFIG_KGDB_FIQ)
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int imx_poll_init(struct uart_port *port)
+{
+	struct imx_port *sport = (struct imx_port *)port;
+	unsigned long flags;
+	unsigned long temp;
+	int retval;
+
+	retval = clk_prepare_enable(sport->clk_ipg);
+	if (retval)
+		return retval;
+	retval = clk_prepare_enable(sport->clk_per);
+	if (retval)
+		clk_disable_unprepare(sport->clk_ipg);
+
+	imx_setup_ufcr(sport, 0);
+
+	spin_lock_irqsave(&sport->port.lock, flags);
+
+	temp = readl(sport->port.membase + UCR1);
+	if (is_imx1_uart(sport))
+		temp |= IMX1_UCR1_UARTCLKEN;
+	temp |= UCR1_UARTEN | UCR1_RRDYEN;
+	temp &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN);
+	writel(temp, sport->port.membase + UCR1);
+
+	temp = readl(sport->port.membase + UCR2);
+	temp |= UCR2_RXEN;
+	writel(temp, sport->port.membase + UCR2);
+
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(sport->port.irq);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 static int imx_poll_get_char(struct uart_port *port)
 {
-	if (!(readl(port->membase + USR2) & USR2_RDR))
+	if (!(readl_relaxed(port->membase + USR2) & USR2_RDR))
 		return NO_POLL_CHAR;
 
-	return readl(port->membase + URXD0) & URXD_RX_DATA;
+	return readl_relaxed(port->membase + URXD0) & URXD_RX_DATA;
 }
 
 static void imx_poll_put_char(struct uart_port *port, unsigned char c)
 {
-	struct imx_port_ucrs old_ucr;
 	unsigned int status;
 
-	/* save control registers */
-	imx_port_ucrs_save(port, &old_ucr);
-
-	/* disable interrupts */
-	writel(UCR1_UARTEN, port->membase + UCR1);
-	writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
-	       port->membase + UCR2);
-	writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
-	       port->membase + UCR3);
-
 	/* drain */
 	do {
-		status = readl(port->membase + USR1);
+		status = readl_relaxed(port->membase + USR1);
 	} while (~status & USR1_TRDY);
 
 	/* write */
-	writel(c, port->membase + URTX0);
+	writel_relaxed(c, port->membase + URTX0);
 
 	/* flush */
 	do {
-		status = readl(port->membase + USR2);
+		status = readl_relaxed(port->membase + USR2);
 	} while (~status & USR2_TXDC);
-
-	/* restore control registers */
-	imx_port_ucrs_restore(port, &old_ucr);
 }
 #endif
 
@@ -1560,6 +1590,9 @@ static struct uart_ops imx_pops = {
 	.config_port	= imx_config_port,
 	.verify_port	= imx_verify_port,
 #if defined(CONFIG_CONSOLE_POLL)
+#if defined(CONFIG_KGDB_FIQ)
+	.poll_init      = imx_poll_init,
+#endif
 	.poll_get_char  = imx_poll_get_char,
 	.poll_put_char  = imx_poll_put_char,
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 13/13] serial: imx: Add support for KGDB's FIQ/NMI mode
@ 2014-06-19 10:38         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

This patch makes it possible to use the imx uart with KGDB's FIQ/NMI
mode.

Main changes are:

.poll_init() will, if KGDB+FIQ are enabled, perform deeper hardware
initialization to ensure the serial port is always active (required
otherwise FIQ is not triggered by UART activity). This has an impact on
power usage so it is conservatively enabled.

imx_put_poll_char() has been simplified to remove the code to disable
interrupts. The present code can corrupt register state when re-entered
from FIQ handler.

Both imx_put_poll_char() and imx_get_poll_char() adopt _relaxed()
MMIO functions (which are safe for polled I/O and needed to avoid taking
spin locks).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/imx.c | 71 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 52 insertions(+), 19 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 25ed1d2..a2baf7e 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -49,6 +49,7 @@
 #include <linux/of_device.h>
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
+#include <linux/kgdb.h>
 
 #include <asm/irq.h>
 #include <linux/platform_data/serial-imx.h>
@@ -1502,44 +1503,73 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #if defined(CONFIG_CONSOLE_POLL)
+
+#if defined(CONFIG_KGDB_FIQ)
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int imx_poll_init(struct uart_port *port)
+{
+	struct imx_port *sport = (struct imx_port *)port;
+	unsigned long flags;
+	unsigned long temp;
+	int retval;
+
+	retval = clk_prepare_enable(sport->clk_ipg);
+	if (retval)
+		return retval;
+	retval = clk_prepare_enable(sport->clk_per);
+	if (retval)
+		clk_disable_unprepare(sport->clk_ipg);
+
+	imx_setup_ufcr(sport, 0);
+
+	spin_lock_irqsave(&sport->port.lock, flags);
+
+	temp = readl(sport->port.membase + UCR1);
+	if (is_imx1_uart(sport))
+		temp |= IMX1_UCR1_UARTCLKEN;
+	temp |= UCR1_UARTEN | UCR1_RRDYEN;
+	temp &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN);
+	writel(temp, sport->port.membase + UCR1);
+
+	temp = readl(sport->port.membase + UCR2);
+	temp |= UCR2_RXEN;
+	writel(temp, sport->port.membase + UCR2);
+
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(sport->port.irq);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 static int imx_poll_get_char(struct uart_port *port)
 {
-	if (!(readl(port->membase + USR2) & USR2_RDR))
+	if (!(readl_relaxed(port->membase + USR2) & USR2_RDR))
 		return NO_POLL_CHAR;
 
-	return readl(port->membase + URXD0) & URXD_RX_DATA;
+	return readl_relaxed(port->membase + URXD0) & URXD_RX_DATA;
 }
 
 static void imx_poll_put_char(struct uart_port *port, unsigned char c)
 {
-	struct imx_port_ucrs old_ucr;
 	unsigned int status;
 
-	/* save control registers */
-	imx_port_ucrs_save(port, &old_ucr);
-
-	/* disable interrupts */
-	writel(UCR1_UARTEN, port->membase + UCR1);
-	writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
-	       port->membase + UCR2);
-	writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
-	       port->membase + UCR3);
-
 	/* drain */
 	do {
-		status = readl(port->membase + USR1);
+		status = readl_relaxed(port->membase + USR1);
 	} while (~status & USR1_TRDY);
 
 	/* write */
-	writel(c, port->membase + URTX0);
+	writel_relaxed(c, port->membase + URTX0);
 
 	/* flush */
 	do {
-		status = readl(port->membase + USR2);
+		status = readl_relaxed(port->membase + USR2);
 	} while (~status & USR2_TXDC);
-
-	/* restore control registers */
-	imx_port_ucrs_restore(port, &old_ucr);
 }
 #endif
 
@@ -1560,6 +1590,9 @@ static struct uart_ops imx_pops = {
 	.config_port	= imx_config_port,
 	.verify_port	= imx_verify_port,
 #if defined(CONFIG_CONSOLE_POLL)
+#if defined(CONFIG_KGDB_FIQ)
+	.poll_init      = imx_poll_init,
+#endif
 	.poll_get_char  = imx_poll_get_char,
 	.poll_put_char  = imx_poll_put_char,
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* Re: [PATCH v4 11/13] serial: asc: Adopt readl_/writel_relaxed()
  2014-06-19 10:38         ` Daniel Thompson
@ 2014-06-19 11:29           ` Srinivas Kandagatla
  -1 siblings, 0 replies; 535+ messages in thread
From: Srinivas Kandagatla @ 2014-06-19 11:29 UTC (permalink / raw)
  To: Daniel Thompson, Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij,
	linux-kernel, Jiri Slaby, Dirk Behme, Russell King,
	Nicolas Pitre, patches, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, Ian Campbell, Colin Cross,
	Rob Herring, John Stultz, Thomas Gleixner, linux-arm-kernel,
	Maxime Coquelin, Greg

Hi Dan,

On 19/06/14 11:38, Daniel Thompson wrote:
> The architectures supported by this driver have expensive
> implementations of writel(), reliant on spin locks and explicit L2 cache
> management. These architectures provide a cheaper writel_relaxed() which
> is much better suited to peripherals that do not perform DMA. The
> situation with readl()/readl_relaxed()is similar although less acute.
>
> This driver does not use DMA and will be more power efficient and more
> robust (due to absense of spin locks during console I/O) if it uses the
> relaxed variants.
>
> This driver is cross compilable for testing purposes and remains
> compilable on all architectures by falling back to writel() when
> writel_relaxed() does not exist. We also include explicit compiler
> barriers. There are redundant on ARM and SH but important on
> x86 because it defines "relaxed" differently.
>
Why are we concern about x86 for this driver?
As per my understanding this IP is only seen on ARM and SH based CPUs so 
why cant we just use relaxed versions, why ifdefs?
I think, this would involve fixing the kconfig and make it depend on SH 
and ARM based platforms only.

On the other hand, This patch looks more generic and applicable to most 
of the drivers. Am not sure which way is the right one.


--srini

> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
> Cc: Maxime Coquelin <maxime.coquelin@st.com>
> Cc: Patrice Chotard <patrice.chotard@st.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Jiri Slaby <jslaby@suse.cz>
> Cc: kernel@stlinux.com
> Cc: linux-serial@vger.kernel.org
> ---
>   drivers/tty/serial/st-asc.c | 11 ++++++++++-
>   1 file changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
> index 4f376d8..58aa1c6 100644
> --- a/drivers/tty/serial/st-asc.c
> +++ b/drivers/tty/serial/st-asc.c
> @@ -152,12 +152,21 @@ static inline struct asc_port *to_asc_port(struct uart_port *port)
>
>   static inline u32 asc_in(struct uart_port *port, u32 offset)
>   {
> -	return readl(port->membase + offset);
> +	u32 r;
> +
> +	r = readl_relaxed(port->membase + offset);
> +	barrier();
> +	return r;
>   }
>
>   static inline void asc_out(struct uart_port *port, u32 offset, u32 value)
>   {
> +#ifdef writel_relaxed
> +	writel_relaxed(value, port->membase + offset);
> +	barrier();
> +#else
>   	writel(value, port->membase + offset);
> +#endif
>   }
>
>   /*
>

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v4 11/13] serial: asc: Adopt readl_/writel_relaxed()
@ 2014-06-19 11:29           ` Srinivas Kandagatla
  0 siblings, 0 replies; 535+ messages in thread
From: Srinivas Kandagatla @ 2014-06-19 11:29 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Dan,

On 19/06/14 11:38, Daniel Thompson wrote:
> The architectures supported by this driver have expensive
> implementations of writel(), reliant on spin locks and explicit L2 cache
> management. These architectures provide a cheaper writel_relaxed() which
> is much better suited to peripherals that do not perform DMA. The
> situation with readl()/readl_relaxed()is similar although less acute.
>
> This driver does not use DMA and will be more power efficient and more
> robust (due to absense of spin locks during console I/O) if it uses the
> relaxed variants.
>
> This driver is cross compilable for testing purposes and remains
> compilable on all architectures by falling back to writel() when
> writel_relaxed() does not exist. We also include explicit compiler
> barriers. There are redundant on ARM and SH but important on
> x86 because it defines "relaxed" differently.
>
Why are we concern about x86 for this driver?
As per my understanding this IP is only seen on ARM and SH based CPUs so 
why cant we just use relaxed versions, why ifdefs?
I think, this would involve fixing the kconfig and make it depend on SH 
and ARM based platforms only.

On the other hand, This patch looks more generic and applicable to most 
of the drivers. Am not sure which way is the right one.


--srini

> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
> Cc: Maxime Coquelin <maxime.coquelin@st.com>
> Cc: Patrice Chotard <patrice.chotard@st.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Jiri Slaby <jslaby@suse.cz>
> Cc: kernel at stlinux.com
> Cc: linux-serial at vger.kernel.org
> ---
>   drivers/tty/serial/st-asc.c | 11 ++++++++++-
>   1 file changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
> index 4f376d8..58aa1c6 100644
> --- a/drivers/tty/serial/st-asc.c
> +++ b/drivers/tty/serial/st-asc.c
> @@ -152,12 +152,21 @@ static inline struct asc_port *to_asc_port(struct uart_port *port)
>
>   static inline u32 asc_in(struct uart_port *port, u32 offset)
>   {
> -	return readl(port->membase + offset);
> +	u32 r;
> +
> +	r = readl_relaxed(port->membase + offset);
> +	barrier();
> +	return r;
>   }
>
>   static inline void asc_out(struct uart_port *port, u32 offset, u32 value)
>   {
> +#ifdef writel_relaxed
> +	writel_relaxed(value, port->membase + offset);
> +	barrier();
> +#else
>   	writel(value, port->membase + offset);
> +#endif
>   }
>
>   /*
>

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v4 11/13] serial: asc: Adopt readl_/writel_relaxed()
  2014-06-19 11:29           ` Srinivas Kandagatla
@ 2014-06-19 11:46             ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 11:46 UTC (permalink / raw)
  To: Srinivas Kandagatla, Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij,
	linux-kernel, Jiri Slaby, Dirk Behme, Russell King,
	Nicolas Pitre, patches, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, Ian Campbell, Colin Cross,
	Rob Herring, John Stultz, Thomas Gleixner, linux-arm-kernel,
	Maxime Coquelin, Greg

On 19/06/14 12:29, Srinivas Kandagatla wrote:
> Hi Dan,
> 
> On 19/06/14 11:38, Daniel Thompson wrote:
>> The architectures supported by this driver have expensive
>> implementations of writel(), reliant on spin locks and explicit L2 cache
>> management. These architectures provide a cheaper writel_relaxed() which
>> is much better suited to peripherals that do not perform DMA. The
>> situation with readl()/readl_relaxed()is similar although less acute.
>>
>> This driver does not use DMA and will be more power efficient and more
>> robust (due to absense of spin locks during console I/O) if it uses the
>> relaxed variants.
>>
>> This driver is cross compilable for testing purposes and remains
>> compilable on all architectures by falling back to writel() when
>> writel_relaxed() does not exist. We also include explicit compiler
>> barriers. There are redundant on ARM and SH but important on
>> x86 because it defines "relaxed" differently.
>>
> Why are we concern about x86 for this driver?
> As per my understanding this IP is only seen on ARM and SH based CPUs so
> why cant we just use relaxed versions, why ifdefs?
> I think, this would involve fixing the kconfig and make it depend on SH
> and ARM based platforms only.

You mean just drop the COMPILE_TEST?

In generally I like as much code as possible to compile on x86. Its
worthwhile protection against the excessive/accidental ARMisms which
could easily impact less common architectures (such as SH).


> On the other hand, This patch looks more generic and applicable to most
> of the drivers. Am not sure which way is the right one.

I'm particularly keen on doing the right thing where readl_relaxed() is
concerned because this function has a compiler barrier on ARM but not on
x86.

Since having asc_in/asc_out made it easy to portably make these changes
I decided is was better to be redundantly exemplary than conceal secret
portability issues.

Don't feel that strongly though. Can easily change it if you're unconvinced.



> 
> 
> --srini
> 
>> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
>> Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
>> Cc: Maxime Coquelin <maxime.coquelin@st.com>
>> Cc: Patrice Chotard <patrice.chotard@st.com>
>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>> Cc: Jiri Slaby <jslaby@suse.cz>
>> Cc: kernel@stlinux.com
>> Cc: linux-serial@vger.kernel.org
>> ---
>>   drivers/tty/serial/st-asc.c | 11 ++++++++++-
>>   1 file changed, 10 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
>> index 4f376d8..58aa1c6 100644
>> --- a/drivers/tty/serial/st-asc.c
>> +++ b/drivers/tty/serial/st-asc.c
>> @@ -152,12 +152,21 @@ static inline struct asc_port
>> *to_asc_port(struct uart_port *port)
>>
>>   static inline u32 asc_in(struct uart_port *port, u32 offset)
>>   {
>> -    return readl(port->membase + offset);
>> +    u32 r;
>> +
>> +    r = readl_relaxed(port->membase + offset);
>> +    barrier();
>> +    return r;
>>   }
>>
>>   static inline void asc_out(struct uart_port *port, u32 offset, u32
>> value)
>>   {
>> +#ifdef writel_relaxed
>> +    writel_relaxed(value, port->membase + offset);
>> +    barrier();
>> +#else
>>       writel(value, port->membase + offset);
>> +#endif
>>   }
>>
>>   /*
>>

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v4 11/13] serial: asc: Adopt readl_/writel_relaxed()
@ 2014-06-19 11:46             ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 11:46 UTC (permalink / raw)
  To: linux-arm-kernel

On 19/06/14 12:29, Srinivas Kandagatla wrote:
> Hi Dan,
> 
> On 19/06/14 11:38, Daniel Thompson wrote:
>> The architectures supported by this driver have expensive
>> implementations of writel(), reliant on spin locks and explicit L2 cache
>> management. These architectures provide a cheaper writel_relaxed() which
>> is much better suited to peripherals that do not perform DMA. The
>> situation with readl()/readl_relaxed()is similar although less acute.
>>
>> This driver does not use DMA and will be more power efficient and more
>> robust (due to absense of spin locks during console I/O) if it uses the
>> relaxed variants.
>>
>> This driver is cross compilable for testing purposes and remains
>> compilable on all architectures by falling back to writel() when
>> writel_relaxed() does not exist. We also include explicit compiler
>> barriers. There are redundant on ARM and SH but important on
>> x86 because it defines "relaxed" differently.
>>
> Why are we concern about x86 for this driver?
> As per my understanding this IP is only seen on ARM and SH based CPUs so
> why cant we just use relaxed versions, why ifdefs?
> I think, this would involve fixing the kconfig and make it depend on SH
> and ARM based platforms only.

You mean just drop the COMPILE_TEST?

In generally I like as much code as possible to compile on x86. Its
worthwhile protection against the excessive/accidental ARMisms which
could easily impact less common architectures (such as SH).


> On the other hand, This patch looks more generic and applicable to most
> of the drivers. Am not sure which way is the right one.

I'm particularly keen on doing the right thing where readl_relaxed() is
concerned because this function has a compiler barrier on ARM but not on
x86.

Since having asc_in/asc_out made it easy to portably make these changes
I decided is was better to be redundantly exemplary than conceal secret
portability issues.

Don't feel that strongly though. Can easily change it if you're unconvinced.



> 
> 
> --srini
> 
>> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
>> Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
>> Cc: Maxime Coquelin <maxime.coquelin@st.com>
>> Cc: Patrice Chotard <patrice.chotard@st.com>
>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>> Cc: Jiri Slaby <jslaby@suse.cz>
>> Cc: kernel at stlinux.com
>> Cc: linux-serial at vger.kernel.org
>> ---
>>   drivers/tty/serial/st-asc.c | 11 ++++++++++-
>>   1 file changed, 10 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
>> index 4f376d8..58aa1c6 100644
>> --- a/drivers/tty/serial/st-asc.c
>> +++ b/drivers/tty/serial/st-asc.c
>> @@ -152,12 +152,21 @@ static inline struct asc_port
>> *to_asc_port(struct uart_port *port)
>>
>>   static inline u32 asc_in(struct uart_port *port, u32 offset)
>>   {
>> -    return readl(port->membase + offset);
>> +    u32 r;
>> +
>> +    r = readl_relaxed(port->membase + offset);
>> +    barrier();
>> +    return r;
>>   }
>>
>>   static inline void asc_out(struct uart_port *port, u32 offset, u32
>> value)
>>   {
>> +#ifdef writel_relaxed
>> +    writel_relaxed(value, port->membase + offset);
>> +    barrier();
>> +#else
>>       writel(value, port->membase + offset);
>> +#endif
>>   }
>>
>>   /*
>>

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v4 11/13] serial: asc: Adopt readl_/writel_relaxed()
  2014-06-19 11:46             ` Daniel Thompson
@ 2014-06-19 11:58               ` Maxime Coquelin
  -1 siblings, 0 replies; 535+ messages in thread
From: Maxime Coquelin @ 2014-06-19 11:58 UTC (permalink / raw)
  To: Daniel Thompson, Srinivas Kandagatla, Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij,
	linux-kernel, Jiri Slaby, Dirk Behme, Russell King,
	Nicolas Pitre, patches, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, Ian Campbell, Colin Cross,
	Rob Herring, John Stultz, Thomas Gleixner, linux-arm-kernel,
	Greg Kroah-Hartman

Hi Daniel,

On 06/19/2014 01:46 PM, Daniel Thompson wrote:
> On 19/06/14 12:29, Srinivas Kandagatla wrote:
>> Hi Dan,
>> 
>> On 19/06/14 11:38, Daniel Thompson wrote:
>>> The architectures supported by this driver have expensive 
>>> implementations of writel(), reliant on spin locks and explicit
>>> L2 cache management. These architectures provide a cheaper
>>> writel_relaxed() which is much better suited to peripherals
>>> that do not perform DMA. The situation with
>>> readl()/readl_relaxed()is similar although less acute.
>>> 
>>> This driver does not use DMA and will be more power efficient
>>> and more robust (due to absense of spin locks during console
>>> I/O) if it uses the relaxed variants.
>>> 
>>> This driver is cross compilable for testing purposes and
>>> remains compilable on all architectures by falling back to
>>> writel() when writel_relaxed() does not exist. We also include
>>> explicit compiler barriers. There are redundant on ARM and SH
>>> but important on x86 because it defines "relaxed" differently.
>>> 
>> Why are we concern about x86 for this driver? As per my
>> understanding this IP is only seen on ARM and SH based CPUs so 
>> why cant we just use relaxed versions, why ifdefs? I think, this
>> would involve fixing the kconfig and make it depend on SH and ARM
>> based platforms only.
> 
> You mean just drop the COMPILE_TEST?
> 
> In generally I like as much code as possible to compile on x86.
> Its worthwhile protection against the excessive/accidental ARMisms
> which could easily impact less common architectures (such as SH).

Personally, dropping COMPILE_TEST is what I would prefer.

Thanks,
Maxime


> 
> 
>> On the other hand, This patch looks more generic and applicable
>> to most of the drivers. Am not sure which way is the right one.
> 
> I'm particularly keen on doing the right thing where
> readl_relaxed() is concerned because this function has a compiler
> barrier on ARM but not on x86.
> 
> Since having asc_in/asc_out made it easy to portably make these
> changes I decided is was better to be redundantly exemplary than
> conceal secret portability issues.
> 
> Don't feel that strongly though. Can easily change it if you're
> unconvinced.
> 
> 
> 
>> 
>> 
>> --srini
>> 
>>> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org> Cc:
>>> Srinivas Kandagatla <srinivas.kandagatla@gmail.com> Cc: Maxime
>>> Coquelin <maxime.coquelin@st.com> Cc: Patrice Chotard
>>> <patrice.chotard@st.com> Cc: Greg Kroah-Hartman
>>> <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jslaby@suse.cz> 
>>> Cc: kernel@stlinux.com Cc: linux-serial@vger.kernel.org --- 
>>> drivers/tty/serial/st-asc.c | 11 ++++++++++- 1 file changed, 10
>>> insertions(+), 1 deletion(-)
>>> 
>>> diff --git a/drivers/tty/serial/st-asc.c
>>> b/drivers/tty/serial/st-asc.c index 4f376d8..58aa1c6 100644 ---
>>> a/drivers/tty/serial/st-asc.c +++
>>> b/drivers/tty/serial/st-asc.c @@ -152,12 +152,21 @@ static
>>> inline struct asc_port *to_asc_port(struct uart_port *port)
>>> 
>>> static inline u32 asc_in(struct uart_port *port, u32 offset) { 
>>> -    return readl(port->membase + offset); +    u32 r; + +    r
>>> = readl_relaxed(port->membase + offset); +    barrier(); +
>>> return r; }
>>> 
>>> static inline void asc_out(struct uart_port *port, u32 offset,
>>> u32 value) { +#ifdef writel_relaxed +    writel_relaxed(value,
>>> port->membase + offset); +    barrier(); +#else writel(value,
>>> port->membase + offset); +#endif }
>>> 
>>> /*
>>> 
> 

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v4 11/13] serial: asc: Adopt readl_/writel_relaxed()
@ 2014-06-19 11:58               ` Maxime Coquelin
  0 siblings, 0 replies; 535+ messages in thread
From: Maxime Coquelin @ 2014-06-19 11:58 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Daniel,

On 06/19/2014 01:46 PM, Daniel Thompson wrote:
> On 19/06/14 12:29, Srinivas Kandagatla wrote:
>> Hi Dan,
>> 
>> On 19/06/14 11:38, Daniel Thompson wrote:
>>> The architectures supported by this driver have expensive 
>>> implementations of writel(), reliant on spin locks and explicit
>>> L2 cache management. These architectures provide a cheaper
>>> writel_relaxed() which is much better suited to peripherals
>>> that do not perform DMA. The situation with
>>> readl()/readl_relaxed()is similar although less acute.
>>> 
>>> This driver does not use DMA and will be more power efficient
>>> and more robust (due to absense of spin locks during console
>>> I/O) if it uses the relaxed variants.
>>> 
>>> This driver is cross compilable for testing purposes and
>>> remains compilable on all architectures by falling back to
>>> writel() when writel_relaxed() does not exist. We also include
>>> explicit compiler barriers. There are redundant on ARM and SH
>>> but important on x86 because it defines "relaxed" differently.
>>> 
>> Why are we concern about x86 for this driver? As per my
>> understanding this IP is only seen on ARM and SH based CPUs so 
>> why cant we just use relaxed versions, why ifdefs? I think, this
>> would involve fixing the kconfig and make it depend on SH and ARM
>> based platforms only.
> 
> You mean just drop the COMPILE_TEST?
> 
> In generally I like as much code as possible to compile on x86.
> Its worthwhile protection against the excessive/accidental ARMisms
> which could easily impact less common architectures (such as SH).

Personally, dropping COMPILE_TEST is what I would prefer.

Thanks,
Maxime


> 
> 
>> On the other hand, This patch looks more generic and applicable
>> to most of the drivers. Am not sure which way is the right one.
> 
> I'm particularly keen on doing the right thing where
> readl_relaxed() is concerned because this function has a compiler
> barrier on ARM but not on x86.
> 
> Since having asc_in/asc_out made it easy to portably make these
> changes I decided is was better to be redundantly exemplary than
> conceal secret portability issues.
> 
> Don't feel that strongly though. Can easily change it if you're
> unconvinced.
> 
> 
> 
>> 
>> 
>> --srini
>> 
>>> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org> Cc:
>>> Srinivas Kandagatla <srinivas.kandagatla@gmail.com> Cc: Maxime
>>> Coquelin <maxime.coquelin@st.com> Cc: Patrice Chotard
>>> <patrice.chotard@st.com> Cc: Greg Kroah-Hartman
>>> <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jslaby@suse.cz> 
>>> Cc: kernel at stlinux.com Cc: linux-serial at vger.kernel.org --- 
>>> drivers/tty/serial/st-asc.c | 11 ++++++++++- 1 file changed, 10
>>> insertions(+), 1 deletion(-)
>>> 
>>> diff --git a/drivers/tty/serial/st-asc.c
>>> b/drivers/tty/serial/st-asc.c index 4f376d8..58aa1c6 100644 ---
>>> a/drivers/tty/serial/st-asc.c +++
>>> b/drivers/tty/serial/st-asc.c @@ -152,12 +152,21 @@ static
>>> inline struct asc_port *to_asc_port(struct uart_port *port)
>>> 
>>> static inline u32 asc_in(struct uart_port *port, u32 offset) { 
>>> -    return readl(port->membase + offset); +    u32 r; + +    r
>>> = readl_relaxed(port->membase + offset); +    barrier(); +
>>> return r; }
>>> 
>>> static inline void asc_out(struct uart_port *port, u32 offset,
>>> u32 value) { +#ifdef writel_relaxed +    writel_relaxed(value,
>>> port->membase + offset); +    barrier(); +#else writel(value,
>>> port->membase + offset); +#endif }
>>> 
>>> /*
>>> 
> 

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v4 11/13] serial: asc: Adopt readl_/writel_relaxed()
  2014-06-19 11:46             ` Daniel Thompson
@ 2014-06-19 12:01               ` Srinivas Kandagatla
  -1 siblings, 0 replies; 535+ messages in thread
From: Srinivas Kandagatla @ 2014-06-19 12:01 UTC (permalink / raw)
  To: Daniel Thompson, Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij,
	linux-kernel, Jiri Slaby, Dirk Behme, Russell King,
	Nicolas Pitre, patches, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, Ian Campbell, Colin Cross,
	Rob Herring, John Stultz, Thomas Gleixner, linux-arm-kernel,
	Maxime Coquelin, Greg



On 19/06/14 12:46, Daniel Thompson wrote:
> On 19/06/14 12:29, Srinivas Kandagatla wrote:
>> Hi Dan,
>>
>> On 19/06/14 11:38, Daniel Thompson wrote:
>>> The architectures supported by this driver have expensive
>>> implementations of writel(), reliant on spin locks and explicit L2 cache
>>> management. These architectures provide a cheaper writel_relaxed() which
>>> is much better suited to peripherals that do not perform DMA. The
>>> situation with readl()/readl_relaxed()is similar although less acute.
>>>
>>> This driver does not use DMA and will be more power efficient and more
>>> robust (due to absense of spin locks during console I/O) if it uses the
>>> relaxed variants.
>>>
>>> This driver is cross compilable for testing purposes and remains
>>> compilable on all architectures by falling back to writel() when
>>> writel_relaxed() does not exist. We also include explicit compiler
>>> barriers. There are redundant on ARM and SH but important on
>>> x86 because it defines "relaxed" differently.
>>>
>> Why are we concern about x86 for this driver?
>> As per my understanding this IP is only seen on ARM and SH based CPUs so
>> why cant we just use relaxed versions, why ifdefs?
>> I think, this would involve fixing the kconfig and make it depend on SH
>> and ARM based platforms only.
>
> You mean just drop the COMPILE_TEST?
>
> In generally I like as much code as possible to compile on x86. Its
> worthwhile protection against the excessive/accidental ARMisms which
> could easily impact less common architectures (such as SH).

That's fair. Does this mean that we are going do similar changes to 
other ST drivers too?

>
TBH, there is no SH based SOCs in mainline which uses this driver. I 
don't think ST would add SH only SOCs to mainline in near future.

>
>> On the other hand, This patch looks more generic and applicable to most
>> of the drivers. Am not sure which way is the right one.
>
> I'm particularly keen on doing the right thing where readl_relaxed() is
> concerned because this function has a compiler barrier on ARM but not on
> x86.
>
My only concern is code duplication all across ST drivers.

> Since having asc_in/asc_out made it easy to portably make these changes
> I decided is was better to be redundantly exemplary than conceal secret
> portability issues.
Your change would fit in nicely with as asc_in/out are wrappers and fix 
st-asc but this would be just for asc driver.
What about other drivers which fall in same category?

So I think we should just drop COMPILE_TEST and possibly make it 
specific to ARM and SH or ARM only.

--srini

>
> Don't feel that strongly though. Can easily change it if you're unconvinced.
>
>
>
>>
>>
>> --srini
>>
>>> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
>>> Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
>>> Cc: Maxime Coquelin <maxime.coquelin@st.com>
>>> Cc: Patrice Chotard <patrice.chotard@st.com>
>>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>>> Cc: Jiri Slaby <jslaby@suse.cz>
>>> Cc: kernel@stlinux.com
>>> Cc: linux-serial@vger.kernel.org
>>> ---
>>>    drivers/tty/serial/st-asc.c | 11 ++++++++++-
>>>    1 file changed, 10 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
>>> index 4f376d8..58aa1c6 100644
>>> --- a/drivers/tty/serial/st-asc.c
>>> +++ b/drivers/tty/serial/st-asc.c
>>> @@ -152,12 +152,21 @@ static inline struct asc_port
>>> *to_asc_port(struct uart_port *port)
>>>
>>>    static inline u32 asc_in(struct uart_port *port, u32 offset)
>>>    {
>>> -    return readl(port->membase + offset);
>>> +    u32 r;
>>> +
>>> +    r = readl_relaxed(port->membase + offset);
>>> +    barrier();
>>> +    return r;
>>>    }
>>>
>>>    static inline void asc_out(struct uart_port *port, u32 offset, u32
>>> value)
>>>    {
>>> +#ifdef writel_relaxed
>>> +    writel_relaxed(value, port->membase + offset);
>>> +    barrier();
>>> +#else
>>>        writel(value, port->membase + offset);
>>> +#endif
>>>    }
>>>
>>>    /*
>>>
>

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v4 11/13] serial: asc: Adopt readl_/writel_relaxed()
@ 2014-06-19 12:01               ` Srinivas Kandagatla
  0 siblings, 0 replies; 535+ messages in thread
From: Srinivas Kandagatla @ 2014-06-19 12:01 UTC (permalink / raw)
  To: linux-arm-kernel



On 19/06/14 12:46, Daniel Thompson wrote:
> On 19/06/14 12:29, Srinivas Kandagatla wrote:
>> Hi Dan,
>>
>> On 19/06/14 11:38, Daniel Thompson wrote:
>>> The architectures supported by this driver have expensive
>>> implementations of writel(), reliant on spin locks and explicit L2 cache
>>> management. These architectures provide a cheaper writel_relaxed() which
>>> is much better suited to peripherals that do not perform DMA. The
>>> situation with readl()/readl_relaxed()is similar although less acute.
>>>
>>> This driver does not use DMA and will be more power efficient and more
>>> robust (due to absense of spin locks during console I/O) if it uses the
>>> relaxed variants.
>>>
>>> This driver is cross compilable for testing purposes and remains
>>> compilable on all architectures by falling back to writel() when
>>> writel_relaxed() does not exist. We also include explicit compiler
>>> barriers. There are redundant on ARM and SH but important on
>>> x86 because it defines "relaxed" differently.
>>>
>> Why are we concern about x86 for this driver?
>> As per my understanding this IP is only seen on ARM and SH based CPUs so
>> why cant we just use relaxed versions, why ifdefs?
>> I think, this would involve fixing the kconfig and make it depend on SH
>> and ARM based platforms only.
>
> You mean just drop the COMPILE_TEST?
>
> In generally I like as much code as possible to compile on x86. Its
> worthwhile protection against the excessive/accidental ARMisms which
> could easily impact less common architectures (such as SH).

That's fair. Does this mean that we are going do similar changes to 
other ST drivers too?

>
TBH, there is no SH based SOCs in mainline which uses this driver. I 
don't think ST would add SH only SOCs to mainline in near future.

>
>> On the other hand, This patch looks more generic and applicable to most
>> of the drivers. Am not sure which way is the right one.
>
> I'm particularly keen on doing the right thing where readl_relaxed() is
> concerned because this function has a compiler barrier on ARM but not on
> x86.
>
My only concern is code duplication all across ST drivers.

> Since having asc_in/asc_out made it easy to portably make these changes
> I decided is was better to be redundantly exemplary than conceal secret
> portability issues.
Your change would fit in nicely with as asc_in/out are wrappers and fix 
st-asc but this would be just for asc driver.
What about other drivers which fall in same category?

So I think we should just drop COMPILE_TEST and possibly make it 
specific to ARM and SH or ARM only.

--srini

>
> Don't feel that strongly though. Can easily change it if you're unconvinced.
>
>
>
>>
>>
>> --srini
>>
>>> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
>>> Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
>>> Cc: Maxime Coquelin <maxime.coquelin@st.com>
>>> Cc: Patrice Chotard <patrice.chotard@st.com>
>>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>>> Cc: Jiri Slaby <jslaby@suse.cz>
>>> Cc: kernel at stlinux.com
>>> Cc: linux-serial at vger.kernel.org
>>> ---
>>>    drivers/tty/serial/st-asc.c | 11 ++++++++++-
>>>    1 file changed, 10 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
>>> index 4f376d8..58aa1c6 100644
>>> --- a/drivers/tty/serial/st-asc.c
>>> +++ b/drivers/tty/serial/st-asc.c
>>> @@ -152,12 +152,21 @@ static inline struct asc_port
>>> *to_asc_port(struct uart_port *port)
>>>
>>>    static inline u32 asc_in(struct uart_port *port, u32 offset)
>>>    {
>>> -    return readl(port->membase + offset);
>>> +    u32 r;
>>> +
>>> +    r = readl_relaxed(port->membase + offset);
>>> +    barrier();
>>> +    return r;
>>>    }
>>>
>>>    static inline void asc_out(struct uart_port *port, u32 offset, u32
>>> value)
>>>    {
>>> +#ifdef writel_relaxed
>>> +    writel_relaxed(value, port->membase + offset);
>>> +    barrier();
>>> +#else
>>>        writel(value, port->membase + offset);
>>> +#endif
>>>    }
>>>
>>>    /*
>>>
>

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v4 11/13] serial: asc: Adopt readl_/writel_relaxed()
  2014-06-19 12:01               ` Srinivas Kandagatla
@ 2014-06-19 13:12                 ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 13:12 UTC (permalink / raw)
  To: Srinivas Kandagatla, Jason Wessel
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij,
	linux-kernel, Jiri Slaby, Dirk Behme, Russell King,
	Nicolas Pitre, patches, Anton Vorontsov, David A. Long,
	linux-serial, Catalin Marinas, kernel-team, devicetree,
	linaro-kernel, Pawel Moll, Ian Campbell, Colin Cross,
	Rob Herring, John Stultz, Thomas Gleixner, linux-arm-kernel,
	Maxime Coquelin, Greg

On 19/06/14 13:01, Srinivas Kandagatla wrote:
>>> Why are we concern about x86 for this driver?
>>> As per my understanding this IP is only seen on ARM and SH based CPUs so
>>> why cant we just use relaxed versions, why ifdefs?
>>> I think, this would involve fixing the kconfig and make it depend on SH
>>> and ARM based platforms only.
>>
>> You mean just drop the COMPILE_TEST?
>>
>> In generally I like as much code as possible to compile on x86. Its
>> worthwhile protection against the excessive/accidental ARMisms which
>> could easily impact less common architectures (such as SH).
> 
> That's fair. Does this mean that we are going do similar changes to
> other ST drivers too?

I didn't give any thought at all to other ST drivers. I don't see why a
*general* preference (of mine or anyone else) would override what is
right for any particular driver.

I don't think "both manage ST peripherals" means drivers have much in
common.


>>> On the other hand, This patch looks more generic and applicable to most
>>> of the drivers. Am not sure which way is the right one.
>>
>> I'm particularly keen on doing the right thing where readl_relaxed() is
>> concerned because this function has a compiler barrier on ARM but not on
>> x86.
>>
> My only concern is code duplication all across ST drivers.

I really struggle to understand this. Why would anyone copy code out of
the asc driver into the network driver (or any other ST driver)?


>> Since having asc_in/asc_out made it easy to portably make these changes
>> I decided is was better to be redundantly exemplary than conceal secret
>> portability issues.
> Your change would fit in nicely with as asc_in/out are wrappers and fix
> st-asc but this would be just for asc driver.
> What about other drivers which fall in same category?
> 
> So I think we should just drop COMPILE_TEST and possibly make it
> specific to ARM and SH or ARM only.

I'm slightly uneasy about this primarily because all the rationale above
describes a concern about drivers other than the one I seek to change.
They ought to be outside the scope of this change.

Nevertheless, since I said I don't feel that strongly about it, as you
wish...

I'll change this in v5.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v4 11/13] serial: asc: Adopt readl_/writel_relaxed()
@ 2014-06-19 13:12                 ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-19 13:12 UTC (permalink / raw)
  To: linux-arm-kernel

On 19/06/14 13:01, Srinivas Kandagatla wrote:
>>> Why are we concern about x86 for this driver?
>>> As per my understanding this IP is only seen on ARM and SH based CPUs so
>>> why cant we just use relaxed versions, why ifdefs?
>>> I think, this would involve fixing the kconfig and make it depend on SH
>>> and ARM based platforms only.
>>
>> You mean just drop the COMPILE_TEST?
>>
>> In generally I like as much code as possible to compile on x86. Its
>> worthwhile protection against the excessive/accidental ARMisms which
>> could easily impact less common architectures (such as SH).
> 
> That's fair. Does this mean that we are going do similar changes to
> other ST drivers too?

I didn't give any thought at all to other ST drivers. I don't see why a
*general* preference (of mine or anyone else) would override what is
right for any particular driver.

I don't think "both manage ST peripherals" means drivers have much in
common.


>>> On the other hand, This patch looks more generic and applicable to most
>>> of the drivers. Am not sure which way is the right one.
>>
>> I'm particularly keen on doing the right thing where readl_relaxed() is
>> concerned because this function has a compiler barrier on ARM but not on
>> x86.
>>
> My only concern is code duplication all across ST drivers.

I really struggle to understand this. Why would anyone copy code out of
the asc driver into the network driver (or any other ST driver)?


>> Since having asc_in/asc_out made it easy to portably make these changes
>> I decided is was better to be redundantly exemplary than conceal secret
>> portability issues.
> Your change would fit in nicely with as asc_in/out are wrappers and fix
> st-asc but this would be just for asc driver.
> What about other drivers which fall in same category?
> 
> So I think we should just drop COMPILE_TEST and possibly make it
> specific to ARM and SH or ARM only.

I'm slightly uneasy about this primarily because all the rationale above
describes a concern about drivers other than the one I seek to change.
They ought to be outside the scope of this change.

Nevertheless, since I said I don't feel that strongly about it, as you
wish...

I'll change this in v5.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v4 09/13] serial: amba-pl011: Pass FIQ information to KGDB.
  2014-06-19 10:38         ` Daniel Thompson
@ 2014-06-20  0:36           ` Greg Kroah-Hartman
  -1 siblings, 0 replies; 535+ messages in thread
From: Greg Kroah-Hartman @ 2014-06-20  0:36 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij, Jiri Slaby,
	Dirk Behme, Russell King, Nicolas Pitre, patches,
	Anton Vorontsov, Kumar Gala, David A. Long, linux-serial,
	Catalin Marinas, kernel-team, devicetree, linaro-kernel,
	Pawel Moll, Ian Campbell, Jason Wessel, Rob Herring, John Stultz,
	Thomas Gleixner, linux-arm-kernel, linux-kernel, Colin

On Thu, Jun 19, 2014 at 11:38:19AM +0100, Daniel Thompson wrote:
> If the AMBA bus has provided the pl011 with a FIQ resource (i.e. a
> second IRQ) then speculatively register it with KGDB when the polling
> driver is initialized.
> 
> By providing this information to KGDB the serial driver offers
> "permission" for KGDB to route the UART interrupt signal from the
> drivers own handler to KGDBs FIQ handler (which will eventually use the
> UART's polled I/O callbacks to interact with the user). This permission
> also implies the amba-pl011 driver has already unmasked RX interrupts
> (otherwise the FIQ handler will never trigger).
> 
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Jiri Slaby <jslaby@suse.cz>
> Cc: linux-serial@vger.kernel.org
> ---

Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v4 09/13] serial: amba-pl011: Pass FIQ information to KGDB.
@ 2014-06-20  0:36           ` Greg Kroah-Hartman
  0 siblings, 0 replies; 535+ messages in thread
From: Greg Kroah-Hartman @ 2014-06-20  0:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 19, 2014 at 11:38:19AM +0100, Daniel Thompson wrote:
> If the AMBA bus has provided the pl011 with a FIQ resource (i.e. a
> second IRQ) then speculatively register it with KGDB when the polling
> driver is initialized.
> 
> By providing this information to KGDB the serial driver offers
> "permission" for KGDB to route the UART interrupt signal from the
> drivers own handler to KGDBs FIQ handler (which will eventually use the
> UART's polled I/O callbacks to interact with the user). This permission
> also implies the amba-pl011 driver has already unmasked RX interrupts
> (otherwise the FIQ handler will never trigger).
> 
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Jiri Slaby <jslaby@suse.cz>
> Cc: linux-serial at vger.kernel.org
> ---

Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v4 10/13] serial: asc: Add support for KGDB's FIQ/NMI mode
  2014-06-19 10:38         ` Daniel Thompson
@ 2014-06-20  0:36           ` Greg Kroah-Hartman
  -1 siblings, 0 replies; 535+ messages in thread
From: Greg Kroah-Hartman @ 2014-06-20  0:36 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Mark Rutland, kernel, kgdb-bugreport, Linus Walleij,
	Patrice Chotard, Jiri Slaby, Dirk Behme, Russell King,
	Nicolas Pitre, patches, Anton Vorontsov, Kumar Gala,
	David A. Long, linux-serial, Catalin Marinas, kernel-team,
	devicetree, linaro-kernel, Pawel Moll, Ian Campbell,
	Jason Wessel, Rob Herring, John Stultz, Thomas Gleixner,
	linux-arm-kernel

On Thu, Jun 19, 2014 at 11:38:20AM +0100, Daniel Thompson wrote:
> Add a .poll_init() function that enables UART RX and registers the
> UART's irq with KGDB. By providing this information to KGDB the serial
> driver offers "permission" for KGDB to route the UART interrupt signal
> from the drivers own handler to KGDBs FIQ handler (which will eventually
> use the UART's polled I/O callbacks to interact with the user).
> 
> Note that the RX is not only enabled but also unmasked. This is required
> because otherwise the FIQ handler could never trigger. This unmask is
> copied from similar code in amba-pl011.c .
> 
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
> Cc: Maxime Coquelin <maxime.coquelin@st.com>
> Cc: Patrice Chotard <patrice.chotard@st.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Jiri Slaby <jslaby@suse.cz>
> Cc: kernel@stlinux.com
> Cc: linux-serial@vger.kernel.org
> ---
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v4 10/13] serial: asc: Add support for KGDB's FIQ/NMI mode
@ 2014-06-20  0:36           ` Greg Kroah-Hartman
  0 siblings, 0 replies; 535+ messages in thread
From: Greg Kroah-Hartman @ 2014-06-20  0:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 19, 2014 at 11:38:20AM +0100, Daniel Thompson wrote:
> Add a .poll_init() function that enables UART RX and registers the
> UART's irq with KGDB. By providing this information to KGDB the serial
> driver offers "permission" for KGDB to route the UART interrupt signal
> from the drivers own handler to KGDBs FIQ handler (which will eventually
> use the UART's polled I/O callbacks to interact with the user).
> 
> Note that the RX is not only enabled but also unmasked. This is required
> because otherwise the FIQ handler could never trigger. This unmask is
> copied from similar code in amba-pl011.c .
> 
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
> Cc: Maxime Coquelin <maxime.coquelin@st.com>
> Cc: Patrice Chotard <patrice.chotard@st.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Jiri Slaby <jslaby@suse.cz>
> Cc: kernel at stlinux.com
> Cc: linux-serial at vger.kernel.org
> ---
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v6 0/4] arm: KGDB NMI/FIQ support
  2014-06-19 10:38       ` Daniel Thompson
@ 2014-06-24 15:18         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-24 15:18 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

This patchset makes it possible to use kgdb's NMI infrastructure on ARM
platforms.

The patches have been previously circulated as part of a large patchset
mixing together ARM architecture code and driver changes
(http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901 ). This
patchset is dramatically cut down to include only the arch/arm code. The
driver code (irqchip and tty/serial) will follow when/if the arch code
is accepted.

The first two patches modify the FIQ infrastructure to allow interrupt
controller drivers to register callbacks (the fiq_chip structure) to
manage FIQ routings and to signal FIQ EOI. This makes it possible to
use FIQ in multi-platform kernels and with recent ARM interrupt
controllers.

The remaining two patches provide architecture support for KGDB's NMI
feature (and rely upon the preceding changes to the FIQ code).

Tested on qemu (versatile), STiH416 (B2020 board) and Freescale i.MX6
quad (wandboard).

Changes since v5:

- Separated anything not strictly impacting arch/arm.
- Fixed a spurious add/remove of code within the series (there was
  broken code in intermediate patches)

For previous changes see:
http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901


Anton Vorontsov (2):
  ARM: Move some macros from entry-armv to entry-header
  ARM: Add KGDB/KDB FIQ debugger generic code

Daniel Thompson (2):
  arm: fiq: Add callbacks to manage FIQ routings
  arm: fiq: Allow EOI to be communicated to the intc

 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 +++++
 arch/arm/include/asm/fiq.h       |  13 ++++
 arch/arm/include/asm/kgdb.h      |   7 ++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/entry-armv.S     | 151 +----------------------------------
 arch/arm/kernel/entry-header.S   | 164 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/fiq.c            | 112 +++++++++++++++++++++++++-
 arch/arm/kernel/kgdb_fiq.c       | 124 +++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S |  87 +++++++++++++++++++++
 10 files changed, 527 insertions(+), 152 deletions(-)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

--
1.9.3


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v6 0/4] arm: KGDB NMI/FIQ support
@ 2014-06-24 15:18         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-24 15:18 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset makes it possible to use kgdb's NMI infrastructure on ARM
platforms.

The patches have been previously circulated as part of a large patchset
mixing together ARM architecture code and driver changes
(http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901 ). This
patchset is dramatically cut down to include only the arch/arm code. The
driver code (irqchip and tty/serial) will follow when/if the arch code
is accepted.

The first two patches modify the FIQ infrastructure to allow interrupt
controller drivers to register callbacks (the fiq_chip structure) to
manage FIQ routings and to signal FIQ EOI. This makes it possible to
use FIQ in multi-platform kernels and with recent ARM interrupt
controllers.

The remaining two patches provide architecture support for KGDB's NMI
feature (and rely upon the preceding changes to the FIQ code).

Tested on qemu (versatile), STiH416 (B2020 board) and Freescale i.MX6
quad (wandboard).

Changes since v5:

- Separated anything not strictly impacting arch/arm.
- Fixed a spurious add/remove of code within the series (there was
  broken code in intermediate patches)

For previous changes see:
http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901


Anton Vorontsov (2):
  ARM: Move some macros from entry-armv to entry-header
  ARM: Add KGDB/KDB FIQ debugger generic code

Daniel Thompson (2):
  arm: fiq: Add callbacks to manage FIQ routings
  arm: fiq: Allow EOI to be communicated to the intc

 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 +++++
 arch/arm/include/asm/fiq.h       |  13 ++++
 arch/arm/include/asm/kgdb.h      |   7 ++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/entry-armv.S     | 151 +----------------------------------
 arch/arm/kernel/entry-header.S   | 164 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/fiq.c            | 112 +++++++++++++++++++++++++-
 arch/arm/kernel/kgdb_fiq.c       | 124 +++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S |  87 +++++++++++++++++++++
 10 files changed, 527 insertions(+), 152 deletions(-)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

--
1.9.3

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v6 1/4] arm: fiq: Add callbacks to manage FIQ routings
  2014-06-24 15:18         ` Daniel Thompson
@ 2014-06-24 15:18           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-24 15:18 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
virq into a FIQ virq. This is too inflexible for multi-platform kernels
and makes runtime error checking impossible.

We solve this by introducing a flexible mapping that allows interrupt
controllers that support FIQ to register those mappings. This, in turn,
makes it much possible for drivers in DT kernels to install FIQ handlers
without knowing anything about the interrupt controller.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/include/asm/fiq.h |   7 +++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 108 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..a7806ef 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -18,6 +18,11 @@
 
 #include <asm/ptrace.h>
 
+struct fiq_chip {
+	void (*fiq_enable)(struct irq_data *data);
+	void (*fiq_disable)(struct irq_data *data);
+};
+
 struct fiq_handler {
 	struct fiq_handler *next;
 	/* Name
@@ -38,6 +43,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern bool has_fiq(int fiq);
+extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..567f8fd 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,9 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
+#include <linux/radix-tree.h>
+#include <linux/slab.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -52,7 +55,15 @@
 		(unsigned)&vector_fiq_offset;		\
 	})
 
+struct fiq_data {
+	struct fiq_chip *fiq_chip;
+	struct irq_data *irq_data;
+};
+
 static unsigned long no_fiq_insn;
+static int fiq_start = -1;
+static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
+static DEFINE_MUTEX(fiq_data_mutex);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -127,18 +138,65 @@ void release_fiq(struct fiq_handler *f)
 	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
 }
 
-static int fiq_start;
+static struct fiq_data *lookup_fiq_data(int fiq)
+{
+	struct fiq_data *data;
+
+	rcu_read_lock();
+	data = radix_tree_lookup(&fiq_data_tree, fiq);
+	rcu_read_unlock();
+
+	return data;
+}
 
 void enable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_enable)
+			data->fiq_chip->fiq_enable(data->irq_data);
+		enable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	enable_irq(fiq + fiq_start);
 }
 
 void disable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_disable)
+			data->fiq_chip->fiq_disable(data->irq_data);
+		disable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	disable_irq(fiq + fiq_start);
 }
 
+bool has_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data)
+		return true;
+
+	if (fiq_start == -1)
+		return false;
+
+	return fiq > fiq_start;
+}
+EXPORT_SYMBOL(has_fiq);
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -147,9 +205,50 @@ EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
 
+/*
+ * Add a mapping from a Linux irq to the fiq data.
+ */
+void fiq_register_mapping(int irq, struct fiq_chip *chip)
+{
+	struct fiq_data *fiq_data = NULL;
+	int res;
+
+	/* fiq_register_mapping can't be mixed with init_FIQ */
+	BUG_ON(fiq_start != -1);
+
+	fiq_data = kmalloc(sizeof(*fiq_data), GFP_KERNEL);
+	if (!fiq_data)
+		goto err;
+
+	fiq_data->fiq_chip = chip;
+	fiq_data->irq_data = irq_get_irq_data(irq);
+	BUG_ON(!fiq_data->irq_data);
+
+	mutex_lock(&fiq_data_mutex);
+	res = radix_tree_insert(&fiq_data_tree, irq, fiq_data);
+	mutex_unlock(&fiq_data_mutex);
+	if (res)
+		goto err;
+
+	return;
+
+err:
+	kfree(fiq_data);
+	pr_err("fiq: Cannot register mapping %d\n", irq);
+}
+
+/*
+ * Set the offset between normal IRQs and their FIQ shadows.
+ */
 void __init init_FIQ(int start)
 {
+	fiq_start = start;
+}
+
+static int __init init_default_fiq_handler(void)
+{
 	unsigned offset = FIQ_OFFSET;
 	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
-	fiq_start = start;
+	return 0;
 }
+pure_initcall(init_default_fiq_handler);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v6 1/4] arm: fiq: Add callbacks to manage FIQ routings
@ 2014-06-24 15:18           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-24 15:18 UTC (permalink / raw)
  To: linux-arm-kernel

Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
virq into a FIQ virq. This is too inflexible for multi-platform kernels
and makes runtime error checking impossible.

We solve this by introducing a flexible mapping that allows interrupt
controllers that support FIQ to register those mappings. This, in turn,
makes it much possible for drivers in DT kernels to install FIQ handlers
without knowing anything about the interrupt controller.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/include/asm/fiq.h |   7 +++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 108 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..a7806ef 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -18,6 +18,11 @@
 
 #include <asm/ptrace.h>
 
+struct fiq_chip {
+	void (*fiq_enable)(struct irq_data *data);
+	void (*fiq_disable)(struct irq_data *data);
+};
+
 struct fiq_handler {
 	struct fiq_handler *next;
 	/* Name
@@ -38,6 +43,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern bool has_fiq(int fiq);
+extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..567f8fd 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,9 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
+#include <linux/radix-tree.h>
+#include <linux/slab.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -52,7 +55,15 @@
 		(unsigned)&vector_fiq_offset;		\
 	})
 
+struct fiq_data {
+	struct fiq_chip *fiq_chip;
+	struct irq_data *irq_data;
+};
+
 static unsigned long no_fiq_insn;
+static int fiq_start = -1;
+static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
+static DEFINE_MUTEX(fiq_data_mutex);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -127,18 +138,65 @@ void release_fiq(struct fiq_handler *f)
 	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
 }
 
-static int fiq_start;
+static struct fiq_data *lookup_fiq_data(int fiq)
+{
+	struct fiq_data *data;
+
+	rcu_read_lock();
+	data = radix_tree_lookup(&fiq_data_tree, fiq);
+	rcu_read_unlock();
+
+	return data;
+}
 
 void enable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_enable)
+			data->fiq_chip->fiq_enable(data->irq_data);
+		enable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	enable_irq(fiq + fiq_start);
 }
 
 void disable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_disable)
+			data->fiq_chip->fiq_disable(data->irq_data);
+		disable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	disable_irq(fiq + fiq_start);
 }
 
+bool has_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data)
+		return true;
+
+	if (fiq_start == -1)
+		return false;
+
+	return fiq > fiq_start;
+}
+EXPORT_SYMBOL(has_fiq);
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -147,9 +205,50 @@ EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
 
+/*
+ * Add a mapping from a Linux irq to the fiq data.
+ */
+void fiq_register_mapping(int irq, struct fiq_chip *chip)
+{
+	struct fiq_data *fiq_data = NULL;
+	int res;
+
+	/* fiq_register_mapping can't be mixed with init_FIQ */
+	BUG_ON(fiq_start != -1);
+
+	fiq_data = kmalloc(sizeof(*fiq_data), GFP_KERNEL);
+	if (!fiq_data)
+		goto err;
+
+	fiq_data->fiq_chip = chip;
+	fiq_data->irq_data = irq_get_irq_data(irq);
+	BUG_ON(!fiq_data->irq_data);
+
+	mutex_lock(&fiq_data_mutex);
+	res = radix_tree_insert(&fiq_data_tree, irq, fiq_data);
+	mutex_unlock(&fiq_data_mutex);
+	if (res)
+		goto err;
+
+	return;
+
+err:
+	kfree(fiq_data);
+	pr_err("fiq: Cannot register mapping %d\n", irq);
+}
+
+/*
+ * Set the offset between normal IRQs and their FIQ shadows.
+ */
 void __init init_FIQ(int start)
 {
+	fiq_start = start;
+}
+
+static int __init init_default_fiq_handler(void)
+{
 	unsigned offset = FIQ_OFFSET;
 	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
-	fiq_start = start;
+	return 0;
 }
+pure_initcall(init_default_fiq_handler);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v6 2/4] arm: fiq: Allow EOI to be communicated to the intc
  2014-06-24 15:18         ` Daniel Thompson
@ 2014-06-24 15:18           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-24 15:18 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

Modern ARM systems require an EOI to be sent to the interrupt controller
on completion of both IRQ and FIQ. The FIQ code currently does not provide
any API to perform this. This patch provides this API, implemented by
adding a callback to the fiq_chip structure.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/include/asm/fiq.h | 6 ++++++
 arch/arm/kernel/fiq.c      | 9 +++++++++
 2 files changed, 15 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index a7806ef..e5d9458 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -21,6 +21,11 @@
 struct fiq_chip {
 	void (*fiq_enable)(struct irq_data *data);
 	void (*fiq_disable)(struct irq_data *data);
+
+	/* .fiq_eoi() will be called from the FIQ handler. For this
+	 * reason it must not use spin locks (or any other locks).
+	 */
+	void (*fiq_eoi)(struct irq_data *data);
 };
 
 struct fiq_handler {
@@ -43,6 +48,7 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 567f8fd..edde332 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -183,6 +183,15 @@ void disable_fiq(int fiq)
 	disable_irq(fiq + fiq_start);
 }
 
+void eoi_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_eoi)
+		data->fiq_chip->fiq_eoi(data->irq_data);
+}
+EXPORT_SYMBOL(eoi_fiq);
+
 bool has_fiq(int fiq)
 {
 	struct fiq_data *data = lookup_fiq_data(fiq);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v6 2/4] arm: fiq: Allow EOI to be communicated to the intc
@ 2014-06-24 15:18           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-24 15:18 UTC (permalink / raw)
  To: linux-arm-kernel

Modern ARM systems require an EOI to be sent to the interrupt controller
on completion of both IRQ and FIQ. The FIQ code currently does not provide
any API to perform this. This patch provides this API, implemented by
adding a callback to the fiq_chip structure.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/include/asm/fiq.h | 6 ++++++
 arch/arm/kernel/fiq.c      | 9 +++++++++
 2 files changed, 15 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index a7806ef..e5d9458 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -21,6 +21,11 @@
 struct fiq_chip {
 	void (*fiq_enable)(struct irq_data *data);
 	void (*fiq_disable)(struct irq_data *data);
+
+	/* .fiq_eoi() will be called from the FIQ handler. For this
+	 * reason it must not use spin locks (or any other locks).
+	 */
+	void (*fiq_eoi)(struct irq_data *data);
 };
 
 struct fiq_handler {
@@ -43,6 +48,7 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 567f8fd..edde332 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -183,6 +183,15 @@ void disable_fiq(int fiq)
 	disable_irq(fiq + fiq_start);
 }
 
+void eoi_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_eoi)
+		data->fiq_chip->fiq_eoi(data->irq_data);
+}
+EXPORT_SYMBOL(eoi_fiq);
+
 bool has_fiq(int fiq)
 {
 	struct fiq_data *data = lookup_fiq_data(fiq);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v6 3/4] ARM: Move some macros from entry-armv to entry-header
  2014-06-24 15:18         ` Daniel Thompson
@ 2014-06-24 15:18           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-24 15:18 UTC (permalink / raw)
  To: Russell King
  Cc: Anton Vorontsov, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Colin Cross, kernel-team,
	Rob Herring, Linus Walleij, Ben Dooks, Catalin Marinas,
	Dave Martin, Fabio Estevam, Frederic Weisbecker, Nicolas Pitre,
	Daniel Thompson

From: Anton Vorontsov <anton.vorontsov@linaro.org>

Just move the macros into header file as we would want to use them for
KGDB FIQ entry code.

The following macros were moved:

 - svc_entry
 - usr_entry
 - kuser_cmpxchg_check
 - vector_stub

To make kuser_cmpxchg_check actually work across different files, we
also have to make kuser_cmpxchg64_fixup global.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
---
 arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
 arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 150 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 52a949a..4172cd6 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -140,53 +140,6 @@ ENDPROC(__und_invalid)
  * SVC mode handlers
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
-#define SPFIX(code...) code
-#else
-#define SPFIX(code...)
-#endif
-
-	.macro	svc_entry, stack_hole=0
- UNWIND(.fnstart		)
- UNWIND(.save {r0 - pc}		)
-	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
-#ifdef CONFIG_THUMB2_KERNEL
- SPFIX(	str	r0, [sp]	)	@ temporarily saved
- SPFIX(	mov	r0, sp		)
- SPFIX(	tst	r0, #4		)	@ test original stack alignment
- SPFIX(	ldr	r0, [sp]	)	@ restored
-#else
- SPFIX(	tst	sp, #4		)
-#endif
- SPFIX(	subeq	sp, sp, #4	)
-	stmia	sp, {r1 - r12}
-
-	ldmia	r0, {r3 - r5}
-	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""      ""       ""
-	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
- SPFIX(	addeq	r2, r2, #4	)
-	str	r3, [sp, #-4]!		@ save the "real" r0 copied
-					@ from the exception stack
-
-	mov	r3, lr
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r2 - sp_svc
-	@  r3 - lr_svc
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	stmia	r7, {r2 - r6}
-
-#ifdef CONFIG_TRACE_IRQFLAGS
-	bl	trace_hardirqs_off
-#endif
-	.endm
-
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -306,73 +259,8 @@ ENDPROC(__pabt_svc)
 
 /*
  * User mode handlers
- *
- * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0, .LCcralign
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
 	.align	5
 __dabt_usr:
 	usr_entry
@@ -823,6 +711,7 @@ __kuser_cmpxchg64:				@ 0xffff0f60
 	ldmfd	sp!, {r4, r5, r6, pc}
 
 	.text
+	.global kuser_cmpxchg64_fixup
 kuser_cmpxchg64_fixup:
 	@ Called from kuser_cmpxchg_fixup.
 	@ r4 = address of interrupted insn (must be preserved).
@@ -964,44 +853,6 @@ __kuser_helper_end:
  * SP points to a minimal amount of processor-private memory, the address
  * of which is copied into r0 for the mode specific abort handler.
  */
-	.macro	vector_stub, name, mode, correction=0
-	.align	5
-
-vector_\name:
-	.if \correction
-	sub	lr, lr, #\correction
-	.endif
-
-	@
-	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
-	@ (parent CPSR)
-	@
-	stmia	sp, {r0, lr}		@ save r0, lr
-	mrs	lr, spsr
-	str	lr, [sp, #8]		@ save spsr
-
-	@
-	@ Prepare for SVC32 mode.  IRQs remain disabled.
-	@
-	mrs	r0, cpsr
-	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
-	msr	spsr_cxsf, r0
-
-	@
-	@ the branch table must immediately follow this code
-	@
-	and	lr, lr, #0x0f
- THUMB(	adr	r0, 1f			)
- THUMB(	ldr	lr, [r0, lr, lsl #2]	)
-	mov	r0, sp
- ARM(	ldr	lr, [pc, lr, lsl #2]	)
-	movs	pc, lr			@ branch to handler in SVC mode
-ENDPROC(vector_\name)
-
-	.align	2
-	@ handler addresses follow this label
-1:
-	.endm
 
 	.section .stubs, "ax", %progbits
 __stubs_start:
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 5d702f8..eb2c426 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -356,3 +356,167 @@ scno	.req	r7		@ syscall number
 tbl	.req	r8		@ syscall table pointer
 why	.req	r8		@ Linux syscall (!= 0)
 tsk	.req	r9		@ current thread_info
+
+/*
+ * SVC mode handler macros
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define SPFIX(code...) code
+#else
+#define SPFIX(code...)
+#endif
+
+	.macro	svc_entry, stack_hole=0
+ UNWIND(.fnstart		)
+ UNWIND(.save {r0 - pc}		)
+	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+#ifdef CONFIG_THUMB2_KERNEL
+ SPFIX(	str	r0, [sp]	)	@ temporarily saved
+ SPFIX(	mov	r0, sp		)
+ SPFIX(	tst	r0, #4		)	@ test original stack alignment
+ SPFIX(	ldr	r0, [sp]	)	@ restored
+#else
+ SPFIX(	tst	sp, #4		)
+#endif
+ SPFIX(	subeq	sp, sp, #4	)
+	stmia	sp, {r1 - r12}
+
+	ldmia	r0, {r3 - r5}
+	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""      ""       ""
+	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+ SPFIX(	addeq	r2, r2, #4	)
+	str	r3, [sp, #-4]!		@ save the "real" r0 copied
+					@ from the exception stack
+
+	mov	r3, lr
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r2 - sp_svc
+	@  r3 - lr_svc
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	stmia	r7, {r2 - r6}
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_off
+#endif
+	.endm
+
+/*
+ * User mode handler macros
+ *
+ * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0, .LCcralign
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+/*
+ * Vector stubs macro.
+ */
+	.macro	vector_stub, name, mode, correction=0
+	.align	5
+
+vector_\name:
+	.if \correction
+	sub	lr, lr, #\correction
+	.endif
+
+	@
+	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
+	@ (parent CPSR)
+	@
+	stmia	sp, {r0, lr}		@ save r0, lr
+	mrs	lr, spsr
+	str	lr, [sp, #8]		@ save spsr
+
+	@
+	@ Prepare for SVC32 mode.  IRQs remain disabled.
+	@
+	mrs	r0, cpsr
+	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
+	msr	spsr_cxsf, r0
+
+	@
+	@ the branch table must immediately follow this code
+	@
+	and	lr, lr, #0x0f
+ THUMB(	adr	r0, 1f			)
+ THUMB(	ldr	lr, [r0, lr, lsl #2]	)
+	mov	r0, sp
+ ARM(	ldr	lr, [pc, lr, lsl #2]	)
+	movs	pc, lr			@ branch to handler in SVC mode
+ENDPROC(vector_\name)
+
+	.align	2
+	@ handler addresses follow this label
+1:
+	.endm
+
+
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v6 3/4] ARM: Move some macros from entry-armv to entry-header
@ 2014-06-24 15:18           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-24 15:18 UTC (permalink / raw)
  To: linux-arm-kernel

From: Anton Vorontsov <anton.vorontsov@linaro.org>

Just move the macros into header file as we would want to use them for
KGDB FIQ entry code.

The following macros were moved:

 - svc_entry
 - usr_entry
 - kuser_cmpxchg_check
 - vector_stub

To make kuser_cmpxchg_check actually work across different files, we
also have to make kuser_cmpxchg64_fixup global.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
---
 arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
 arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 150 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 52a949a..4172cd6 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -140,53 +140,6 @@ ENDPROC(__und_invalid)
  * SVC mode handlers
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
-#define SPFIX(code...) code
-#else
-#define SPFIX(code...)
-#endif
-
-	.macro	svc_entry, stack_hole=0
- UNWIND(.fnstart		)
- UNWIND(.save {r0 - pc}		)
-	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
-#ifdef CONFIG_THUMB2_KERNEL
- SPFIX(	str	r0, [sp]	)	@ temporarily saved
- SPFIX(	mov	r0, sp		)
- SPFIX(	tst	r0, #4		)	@ test original stack alignment
- SPFIX(	ldr	r0, [sp]	)	@ restored
-#else
- SPFIX(	tst	sp, #4		)
-#endif
- SPFIX(	subeq	sp, sp, #4	)
-	stmia	sp, {r1 - r12}
-
-	ldmia	r0, {r3 - r5}
-	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""      ""       ""
-	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
- SPFIX(	addeq	r2, r2, #4	)
-	str	r3, [sp, #-4]!		@ save the "real" r0 copied
-					@ from the exception stack
-
-	mov	r3, lr
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r2 - sp_svc
-	@  r3 - lr_svc
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	stmia	r7, {r2 - r6}
-
-#ifdef CONFIG_TRACE_IRQFLAGS
-	bl	trace_hardirqs_off
-#endif
-	.endm
-
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -306,73 +259,8 @@ ENDPROC(__pabt_svc)
 
 /*
  * User mode handlers
- *
- * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0, .LCcralign
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
 	.align	5
 __dabt_usr:
 	usr_entry
@@ -823,6 +711,7 @@ __kuser_cmpxchg64:				@ 0xffff0f60
 	ldmfd	sp!, {r4, r5, r6, pc}
 
 	.text
+	.global kuser_cmpxchg64_fixup
 kuser_cmpxchg64_fixup:
 	@ Called from kuser_cmpxchg_fixup.
 	@ r4 = address of interrupted insn (must be preserved).
@@ -964,44 +853,6 @@ __kuser_helper_end:
  * SP points to a minimal amount of processor-private memory, the address
  * of which is copied into r0 for the mode specific abort handler.
  */
-	.macro	vector_stub, name, mode, correction=0
-	.align	5
-
-vector_\name:
-	.if \correction
-	sub	lr, lr, #\correction
-	.endif
-
-	@
-	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
-	@ (parent CPSR)
-	@
-	stmia	sp, {r0, lr}		@ save r0, lr
-	mrs	lr, spsr
-	str	lr, [sp, #8]		@ save spsr
-
-	@
-	@ Prepare for SVC32 mode.  IRQs remain disabled.
-	@
-	mrs	r0, cpsr
-	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
-	msr	spsr_cxsf, r0
-
-	@
-	@ the branch table must immediately follow this code
-	@
-	and	lr, lr, #0x0f
- THUMB(	adr	r0, 1f			)
- THUMB(	ldr	lr, [r0, lr, lsl #2]	)
-	mov	r0, sp
- ARM(	ldr	lr, [pc, lr, lsl #2]	)
-	movs	pc, lr			@ branch to handler in SVC mode
-ENDPROC(vector_\name)
-
-	.align	2
-	@ handler addresses follow this label
-1:
-	.endm
 
 	.section .stubs, "ax", %progbits
 __stubs_start:
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 5d702f8..eb2c426 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -356,3 +356,167 @@ scno	.req	r7		@ syscall number
 tbl	.req	r8		@ syscall table pointer
 why	.req	r8		@ Linux syscall (!= 0)
 tsk	.req	r9		@ current thread_info
+
+/*
+ * SVC mode handler macros
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define SPFIX(code...) code
+#else
+#define SPFIX(code...)
+#endif
+
+	.macro	svc_entry, stack_hole=0
+ UNWIND(.fnstart		)
+ UNWIND(.save {r0 - pc}		)
+	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+#ifdef CONFIG_THUMB2_KERNEL
+ SPFIX(	str	r0, [sp]	)	@ temporarily saved
+ SPFIX(	mov	r0, sp		)
+ SPFIX(	tst	r0, #4		)	@ test original stack alignment
+ SPFIX(	ldr	r0, [sp]	)	@ restored
+#else
+ SPFIX(	tst	sp, #4		)
+#endif
+ SPFIX(	subeq	sp, sp, #4	)
+	stmia	sp, {r1 - r12}
+
+	ldmia	r0, {r3 - r5}
+	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""      ""       ""
+	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+ SPFIX(	addeq	r2, r2, #4	)
+	str	r3, [sp, #-4]!		@ save the "real" r0 copied
+					@ from the exception stack
+
+	mov	r3, lr
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r2 - sp_svc
+	@  r3 - lr_svc
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	stmia	r7, {r2 - r6}
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_off
+#endif
+	.endm
+
+/*
+ * User mode handler macros
+ *
+ * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0, .LCcralign
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+/*
+ * Vector stubs macro.
+ */
+	.macro	vector_stub, name, mode, correction=0
+	.align	5
+
+vector_\name:
+	.if \correction
+	sub	lr, lr, #\correction
+	.endif
+
+	@
+	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
+	@ (parent CPSR)
+	@
+	stmia	sp, {r0, lr}		@ save r0, lr
+	mrs	lr, spsr
+	str	lr, [sp, #8]		@ save spsr
+
+	@
+	@ Prepare for SVC32 mode.  IRQs remain disabled.
+	@
+	mrs	r0, cpsr
+	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
+	msr	spsr_cxsf, r0
+
+	@
+	@ the branch table must immediately follow this code
+	@
+	and	lr, lr, #0x0f
+ THUMB(	adr	r0, 1f			)
+ THUMB(	ldr	lr, [r0, lr, lsl #2]	)
+	mov	r0, sp
+ ARM(	ldr	lr, [pc, lr, lsl #2]	)
+	movs	pc, lr			@ branch to handler in SVC mode
+ENDPROC(vector_\name)
+
+	.align	2
+	@ handler addresses follow this label
+1:
+	.endm
+
+
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v6 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
  2014-06-24 15:18         ` Daniel Thompson
@ 2014-06-24 15:18           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-24 15:18 UTC (permalink / raw)
  To: Russell King
  Cc: Anton Vorontsov, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Colin Cross, kernel-team,
	Rob Herring, Linus Walleij, Ben Dooks, Catalin Marinas,
	Dave Martin, Fabio Estevam, Frederic Weisbecker, Nicolas Pitre,
	Daniel Thompson

From: Anton Vorontsov <anton.vorontsov@linaro.org>

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

By default KGDB FIQ is disabled in runtime, but can be enabled with
kgdb_fiq.enable=1 kernel command line option.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben.dooks@codethink.co.uk>
Cc: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 ++++++
 arch/arm/include/asm/kgdb.h      |   7 +++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/kgdb_fiq.c       | 124 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S |  87 +++++++++++++++++++++++++++
 6 files changed, 239 insertions(+)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 245058b..f385b27 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -297,6 +297,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -346,6 +347,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 26536f7..c7342b6 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,24 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be
+	  enabled with kgdb_fiq.enable=1 kernel command line option.
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..5de21f01 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,11 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern char kgdb_fiq_handler;
+extern char kgdb_fiq_handler_end;
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs);
+extern int kgdb_register_fiq(unsigned int fiq);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 38ddd9f..30ee8f3 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -68,6 +68,7 @@ endif
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
 obj-$(CONFIG_ARM_THUMBEE)	+= thumbee.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
+obj-$(CONFIG_KGDB_FIQ)		+= kgdb_fiq_entry.o kgdb_fiq.o
 obj-$(CONFIG_ARM_UNWIND)	+= unwind.o
 obj-$(CONFIG_HAVE_TCM)		+= tcm.o
 obj-$(CONFIG_OF)		+= devtree.o
diff --git a/arch/arm/kernel/kgdb_fiq.c b/arch/arm/kernel/kgdb_fiq.c
new file mode 100644
index 0000000..dbf4873
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq.c
@@ -0,0 +1,124 @@
+/*
+ * KGDB FIQ
+ *
+ * Copyright 2010 Google, Inc.
+ *		  Arve Hjønnevåg <arve@android.com>
+ *		  Colin Cross <ccross@android.com>
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/hardirq.h>
+#include <linux/atomic.h>
+#include <linux/kdb.h>
+#include <linux/kgdb.h>
+#include <asm/fiq.h>
+#include <asm/exception.h>
+
+static int kgdb_fiq_enabled;
+module_param_named(enable, kgdb_fiq_enabled, int, 0600);
+MODULE_PARM_DESC(enable, "set to 1 to enable FIQ KGDB");
+
+static unsigned int kgdb_fiq;
+
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs)
+{
+	if (kgdb_nmi_poll_knock()) {
+		nmi_enter();
+		kgdb_handle_exception(1, 0, 0, regs);
+		nmi_exit();
+	}
+
+	eoi_fiq(kgdb_fiq);
+}
+
+static struct fiq_handler kgdb_fiq_desc = {
+	.name = "kgdb",
+};
+
+static long kgdb_fiq_setup_stack(void *info)
+{
+	struct pt_regs regs;
+
+	regs.ARM_sp = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER) +
+			THREAD_START_SP;
+	WARN_ON(!regs.ARM_sp);
+
+	set_fiq_regs(&regs);
+	return 0;
+}
+
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * This function manages NMIs that usually cause KGDB to enter. That is, not
+ * all NMIs should be enabled or disabled, but only those that issue
+ * kgdb_handle_exception().
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	static atomic_t cnt;
+	int ret;
+
+	ret = atomic_add_return(on ? 1 : -1, &cnt);
+	if (ret > 1 && on) {
+		/*
+		 * There should be only one instance that calls this function
+		 * in "enable, disable" order. All other users must call
+		 * disable first, then enable. If not, something is wrong.
+		 */
+		WARN_ON(1);
+		return;
+	}
+
+	if (ret > 0)
+		enable_fiq(kgdb_fiq);
+	else
+		disable_fiq(kgdb_fiq);
+}
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	int err;
+	int cpu;
+
+	if (!kgdb_fiq_enabled)
+		return -ENODEV;
+
+	if (!has_fiq(fiq)) {
+		pr_warn(
+		    "%s: Cannot register %u (no FIQ with this number)\n",
+		    __func__, fiq);
+		return -ENODEV;
+	}
+
+	kgdb_fiq = fiq;
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	for_each_possible_cpu(cpu)
+		work_on_cpu(cpu, kgdb_fiq_setup_stack, NULL);
+
+	set_fiq_handler(&kgdb_fiq_handler,
+			&kgdb_fiq_handler_end - &kgdb_fiq_handler);
+
+	arch_kgdb_ops.enable_nmi = kgdb_fiq_enable_nmi;
+	return 0;
+}
diff --git a/arch/arm/kernel/kgdb_fiq_entry.S b/arch/arm/kernel/kgdb_fiq_entry.S
new file mode 100644
index 0000000..d6becca
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq_entry.S
@@ -0,0 +1,87 @@
+/*
+ * KGDB FIQ entry
+ *
+ * Copyright 1996,1997,1998 Russell King.
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+#include <asm/unwind.h>
+#include "entry-header.S"
+
+	.text
+
+@ This is needed for usr_entry/alignment_trap
+.LCcralign:
+	.long	cr_alignment
+.LCdohandle:
+	.long	kgdb_fiq_do_handle
+
+	.macro	fiq_handler
+	ldr	r1, =.LCdohandle
+	mov	r0, sp
+	adr	lr, BSYM(9997f)
+	ldr	pc, [r1]
+9997:
+	.endm
+
+	.align	5
+__fiq_svc:
+	svc_entry
+	fiq_handler
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+	.ltorg
+
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+	.ltorg
+
+	.global kgdb_fiq_handler
+kgdb_fiq_handler:
+
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_svc			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
+
+	.global kgdb_fiq_handler_end
+kgdb_fiq_handler_end:
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v6 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
@ 2014-06-24 15:18           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-24 15:18 UTC (permalink / raw)
  To: linux-arm-kernel

From: Anton Vorontsov <anton.vorontsov@linaro.org>

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

By default KGDB FIQ is disabled in runtime, but can be enabled with
kgdb_fiq.enable=1 kernel command line option.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben.dooks@codethink.co.uk>
Cc: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 ++++++
 arch/arm/include/asm/kgdb.h      |   7 +++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/kgdb_fiq.c       | 124 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S |  87 +++++++++++++++++++++++++++
 6 files changed, 239 insertions(+)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 245058b..f385b27 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -297,6 +297,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -346,6 +347,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 26536f7..c7342b6 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,24 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be
+	  enabled with kgdb_fiq.enable=1 kernel command line option.
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..5de21f01 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,11 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern char kgdb_fiq_handler;
+extern char kgdb_fiq_handler_end;
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs);
+extern int kgdb_register_fiq(unsigned int fiq);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 38ddd9f..30ee8f3 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -68,6 +68,7 @@ endif
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
 obj-$(CONFIG_ARM_THUMBEE)	+= thumbee.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
+obj-$(CONFIG_KGDB_FIQ)		+= kgdb_fiq_entry.o kgdb_fiq.o
 obj-$(CONFIG_ARM_UNWIND)	+= unwind.o
 obj-$(CONFIG_HAVE_TCM)		+= tcm.o
 obj-$(CONFIG_OF)		+= devtree.o
diff --git a/arch/arm/kernel/kgdb_fiq.c b/arch/arm/kernel/kgdb_fiq.c
new file mode 100644
index 0000000..dbf4873
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq.c
@@ -0,0 +1,124 @@
+/*
+ * KGDB FIQ
+ *
+ * Copyright 2010 Google, Inc.
+ *		  Arve Hj?nnev?g <arve@android.com>
+ *		  Colin Cross <ccross@android.com>
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/hardirq.h>
+#include <linux/atomic.h>
+#include <linux/kdb.h>
+#include <linux/kgdb.h>
+#include <asm/fiq.h>
+#include <asm/exception.h>
+
+static int kgdb_fiq_enabled;
+module_param_named(enable, kgdb_fiq_enabled, int, 0600);
+MODULE_PARM_DESC(enable, "set to 1 to enable FIQ KGDB");
+
+static unsigned int kgdb_fiq;
+
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs)
+{
+	if (kgdb_nmi_poll_knock()) {
+		nmi_enter();
+		kgdb_handle_exception(1, 0, 0, regs);
+		nmi_exit();
+	}
+
+	eoi_fiq(kgdb_fiq);
+}
+
+static struct fiq_handler kgdb_fiq_desc = {
+	.name = "kgdb",
+};
+
+static long kgdb_fiq_setup_stack(void *info)
+{
+	struct pt_regs regs;
+
+	regs.ARM_sp = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER) +
+			THREAD_START_SP;
+	WARN_ON(!regs.ARM_sp);
+
+	set_fiq_regs(&regs);
+	return 0;
+}
+
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * This function manages NMIs that usually cause KGDB to enter. That is, not
+ * all NMIs should be enabled or disabled, but only those that issue
+ * kgdb_handle_exception().
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	static atomic_t cnt;
+	int ret;
+
+	ret = atomic_add_return(on ? 1 : -1, &cnt);
+	if (ret > 1 && on) {
+		/*
+		 * There should be only one instance that calls this function
+		 * in "enable, disable" order. All other users must call
+		 * disable first, then enable. If not, something is wrong.
+		 */
+		WARN_ON(1);
+		return;
+	}
+
+	if (ret > 0)
+		enable_fiq(kgdb_fiq);
+	else
+		disable_fiq(kgdb_fiq);
+}
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	int err;
+	int cpu;
+
+	if (!kgdb_fiq_enabled)
+		return -ENODEV;
+
+	if (!has_fiq(fiq)) {
+		pr_warn(
+		    "%s: Cannot register %u (no FIQ with this number)\n",
+		    __func__, fiq);
+		return -ENODEV;
+	}
+
+	kgdb_fiq = fiq;
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	for_each_possible_cpu(cpu)
+		work_on_cpu(cpu, kgdb_fiq_setup_stack, NULL);
+
+	set_fiq_handler(&kgdb_fiq_handler,
+			&kgdb_fiq_handler_end - &kgdb_fiq_handler);
+
+	arch_kgdb_ops.enable_nmi = kgdb_fiq_enable_nmi;
+	return 0;
+}
diff --git a/arch/arm/kernel/kgdb_fiq_entry.S b/arch/arm/kernel/kgdb_fiq_entry.S
new file mode 100644
index 0000000..d6becca
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq_entry.S
@@ -0,0 +1,87 @@
+/*
+ * KGDB FIQ entry
+ *
+ * Copyright 1996,1997,1998 Russell King.
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+#include <asm/unwind.h>
+#include "entry-header.S"
+
+	.text
+
+@ This is needed for usr_entry/alignment_trap
+.LCcralign:
+	.long	cr_alignment
+.LCdohandle:
+	.long	kgdb_fiq_do_handle
+
+	.macro	fiq_handler
+	ldr	r1, =.LCdohandle
+	mov	r0, sp
+	adr	lr, BSYM(9997f)
+	ldr	pc, [r1]
+9997:
+	.endm
+
+	.align	5
+__fiq_svc:
+	svc_entry
+	fiq_handler
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+	.ltorg
+
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+	.ltorg
+
+	.global kgdb_fiq_handler
+kgdb_fiq_handler:
+
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_svc			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
+
+	.global kgdb_fiq_handler_end
+kgdb_fiq_handler_end:
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* Re: [PATCH v6 1/4] arm: fiq: Add callbacks to manage FIQ routings
  2014-06-24 15:18           ` Daniel Thompson
@ 2014-06-24 15:44             ` Nicolas Pitre
  -1 siblings, 0 replies; 535+ messages in thread
From: Nicolas Pitre @ 2014-06-24 15:44 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Russell King, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker

On Tue, 24 Jun 2014, Daniel Thompson wrote:

> Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
> virq into a FIQ virq. This is too inflexible for multi-platform kernels
> and makes runtime error checking impossible.
> 
> We solve this by introducing a flexible mapping that allows interrupt
> controllers that support FIQ to register those mappings. This, in turn,
> makes it much possible for drivers in DT kernels to install FIQ handlers
> without knowing anything about the interrupt controller.
> 
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Fabio Estevam <festevam@gmail.com>
> Cc: Nicolas Pitre <nico@linaro.org>
> ---
>  arch/arm/include/asm/fiq.h |   7 +++
>  arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 108 insertions(+), 2 deletions(-)

[...]

> +bool has_fiq(int fiq)
> +{
> +	struct fiq_data *data = lookup_fiq_data(fiq);
> +
> +	if (data)
> +		return true;
> +
> +	if (fiq_start == -1)
> +		return false;
> +
> +	return fiq > fiq_start;

Shouldn't this be fiq >= fiq_start ?

Other than that...

Acked-by: Nicolas Pitre <nico@linaro.org>


Nicolas

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v6 1/4] arm: fiq: Add callbacks to manage FIQ routings
@ 2014-06-24 15:44             ` Nicolas Pitre
  0 siblings, 0 replies; 535+ messages in thread
From: Nicolas Pitre @ 2014-06-24 15:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 24 Jun 2014, Daniel Thompson wrote:

> Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
> virq into a FIQ virq. This is too inflexible for multi-platform kernels
> and makes runtime error checking impossible.
> 
> We solve this by introducing a flexible mapping that allows interrupt
> controllers that support FIQ to register those mappings. This, in turn,
> makes it much possible for drivers in DT kernels to install FIQ handlers
> without knowing anything about the interrupt controller.
> 
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Fabio Estevam <festevam@gmail.com>
> Cc: Nicolas Pitre <nico@linaro.org>
> ---
>  arch/arm/include/asm/fiq.h |   7 +++
>  arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 108 insertions(+), 2 deletions(-)

[...]

> +bool has_fiq(int fiq)
> +{
> +	struct fiq_data *data = lookup_fiq_data(fiq);
> +
> +	if (data)
> +		return true;
> +
> +	if (fiq_start == -1)
> +		return false;
> +
> +	return fiq > fiq_start;

Shouldn't this be fiq >= fiq_start ?

Other than that...

Acked-by: Nicolas Pitre <nico@linaro.org>


Nicolas

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v6 2/4] arm: fiq: Allow EOI to be communicated to the intc
  2014-06-24 15:18           ` Daniel Thompson
@ 2014-06-24 15:46             ` Nicolas Pitre
  -1 siblings, 0 replies; 535+ messages in thread
From: Nicolas Pitre @ 2014-06-24 15:46 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Russell King, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker

On Tue, 24 Jun 2014, Daniel Thompson wrote:

> Modern ARM systems require an EOI to be sent to the interrupt controller
> on completion of both IRQ and FIQ. The FIQ code currently does not provide
> any API to perform this. This patch provides this API, implemented by
> adding a callback to the fiq_chip structure.
> 
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Fabio Estevam <festevam@gmail.com>
> Cc: Nicolas Pitre <nico@linaro.org>

Acked-by: Nicolas Pitre <nico@linaro.org>

> ---
>  arch/arm/include/asm/fiq.h | 6 ++++++
>  arch/arm/kernel/fiq.c      | 9 +++++++++
>  2 files changed, 15 insertions(+)
> 
> diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
> index a7806ef..e5d9458 100644
> --- a/arch/arm/include/asm/fiq.h
> +++ b/arch/arm/include/asm/fiq.h
> @@ -21,6 +21,11 @@
>  struct fiq_chip {
>  	void (*fiq_enable)(struct irq_data *data);
>  	void (*fiq_disable)(struct irq_data *data);
> +
> +	/* .fiq_eoi() will be called from the FIQ handler. For this
> +	 * reason it must not use spin locks (or any other locks).
> +	 */
> +	void (*fiq_eoi)(struct irq_data *data);
>  };
>  
>  struct fiq_handler {
> @@ -43,6 +48,7 @@ extern void release_fiq(struct fiq_handler *f);
>  extern void set_fiq_handler(void *start, unsigned int length);
>  extern void enable_fiq(int fiq);
>  extern void disable_fiq(int fiq);
> +extern void eoi_fiq(int fiq);
>  extern bool has_fiq(int fiq);
>  extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
>  
> diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
> index 567f8fd..edde332 100644
> --- a/arch/arm/kernel/fiq.c
> +++ b/arch/arm/kernel/fiq.c
> @@ -183,6 +183,15 @@ void disable_fiq(int fiq)
>  	disable_irq(fiq + fiq_start);
>  }
>  
> +void eoi_fiq(int fiq)
> +{
> +	struct fiq_data *data = lookup_fiq_data(fiq);
> +
> +	if (data && data->fiq_chip->fiq_eoi)
> +		data->fiq_chip->fiq_eoi(data->irq_data);
> +}
> +EXPORT_SYMBOL(eoi_fiq);
> +
>  bool has_fiq(int fiq)
>  {
>  	struct fiq_data *data = lookup_fiq_data(fiq);
> -- 
> 1.9.3
> 

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v6 2/4] arm: fiq: Allow EOI to be communicated to the intc
@ 2014-06-24 15:46             ` Nicolas Pitre
  0 siblings, 0 replies; 535+ messages in thread
From: Nicolas Pitre @ 2014-06-24 15:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 24 Jun 2014, Daniel Thompson wrote:

> Modern ARM systems require an EOI to be sent to the interrupt controller
> on completion of both IRQ and FIQ. The FIQ code currently does not provide
> any API to perform this. This patch provides this API, implemented by
> adding a callback to the fiq_chip structure.
> 
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Fabio Estevam <festevam@gmail.com>
> Cc: Nicolas Pitre <nico@linaro.org>

Acked-by: Nicolas Pitre <nico@linaro.org>

> ---
>  arch/arm/include/asm/fiq.h | 6 ++++++
>  arch/arm/kernel/fiq.c      | 9 +++++++++
>  2 files changed, 15 insertions(+)
> 
> diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
> index a7806ef..e5d9458 100644
> --- a/arch/arm/include/asm/fiq.h
> +++ b/arch/arm/include/asm/fiq.h
> @@ -21,6 +21,11 @@
>  struct fiq_chip {
>  	void (*fiq_enable)(struct irq_data *data);
>  	void (*fiq_disable)(struct irq_data *data);
> +
> +	/* .fiq_eoi() will be called from the FIQ handler. For this
> +	 * reason it must not use spin locks (or any other locks).
> +	 */
> +	void (*fiq_eoi)(struct irq_data *data);
>  };
>  
>  struct fiq_handler {
> @@ -43,6 +48,7 @@ extern void release_fiq(struct fiq_handler *f);
>  extern void set_fiq_handler(void *start, unsigned int length);
>  extern void enable_fiq(int fiq);
>  extern void disable_fiq(int fiq);
> +extern void eoi_fiq(int fiq);
>  extern bool has_fiq(int fiq);
>  extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
>  
> diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
> index 567f8fd..edde332 100644
> --- a/arch/arm/kernel/fiq.c
> +++ b/arch/arm/kernel/fiq.c
> @@ -183,6 +183,15 @@ void disable_fiq(int fiq)
>  	disable_irq(fiq + fiq_start);
>  }
>  
> +void eoi_fiq(int fiq)
> +{
> +	struct fiq_data *data = lookup_fiq_data(fiq);
> +
> +	if (data && data->fiq_chip->fiq_eoi)
> +		data->fiq_chip->fiq_eoi(data->irq_data);
> +}
> +EXPORT_SYMBOL(eoi_fiq);
> +
>  bool has_fiq(int fiq)
>  {
>  	struct fiq_data *data = lookup_fiq_data(fiq);
> -- 
> 1.9.3
> 

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v6 3/4] ARM: Move some macros from entry-armv to entry-header
  2014-06-24 15:18           ` Daniel Thompson
@ 2014-06-24 15:53             ` Nicolas Pitre
  -1 siblings, 0 replies; 535+ messages in thread
From: Nicolas Pitre @ 2014-06-24 15:53 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Russell King, Anton Vorontsov, linux-kernel, linux-arm-kernel,
	kgdb-bugreport, patches, linaro-kernel, John Stultz, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker

On Tue, 24 Jun 2014, Daniel Thompson wrote:

> From: Anton Vorontsov <anton.vorontsov@linaro.org>
> 
> Just move the macros into header file as we would want to use them for
> KGDB FIQ entry code.
> 
> The following macros were moved:
> 
>  - svc_entry
>  - usr_entry
>  - kuser_cmpxchg_check
>  - vector_stub
> 
> To make kuser_cmpxchg_check actually work across different files, we
> also have to make kuser_cmpxchg64_fixup global.
> 
> Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
> Signed-off-by: John Stultz <john.stultz@linaro.org>
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Nicolas Pitre <nico@linaro.org>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Frederic Weisbecker <fweisbec@gmail.com>

Acked-by: Nicolas Pitre <nico@linaro.org>


> ---
>  arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
>  arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 165 insertions(+), 150 deletions(-)
> 
> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> index 52a949a..4172cd6 100644
> --- a/arch/arm/kernel/entry-armv.S
> +++ b/arch/arm/kernel/entry-armv.S
> @@ -140,53 +140,6 @@ ENDPROC(__und_invalid)
>   * SVC mode handlers
>   */
>  
> -#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
> -#define SPFIX(code...) code
> -#else
> -#define SPFIX(code...)
> -#endif
> -
> -	.macro	svc_entry, stack_hole=0
> - UNWIND(.fnstart		)
> - UNWIND(.save {r0 - pc}		)
> -	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
> -#ifdef CONFIG_THUMB2_KERNEL
> - SPFIX(	str	r0, [sp]	)	@ temporarily saved
> - SPFIX(	mov	r0, sp		)
> - SPFIX(	tst	r0, #4		)	@ test original stack alignment
> - SPFIX(	ldr	r0, [sp]	)	@ restored
> -#else
> - SPFIX(	tst	sp, #4		)
> -#endif
> - SPFIX(	subeq	sp, sp, #4	)
> -	stmia	sp, {r1 - r12}
> -
> -	ldmia	r0, {r3 - r5}
> -	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
> -	mov	r6, #-1			@  ""  ""      ""       ""
> -	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
> - SPFIX(	addeq	r2, r2, #4	)
> -	str	r3, [sp, #-4]!		@ save the "real" r0 copied
> -					@ from the exception stack
> -
> -	mov	r3, lr
> -
> -	@
> -	@ We are now ready to fill in the remaining blanks on the stack:
> -	@
> -	@  r2 - sp_svc
> -	@  r3 - lr_svc
> -	@  r4 - lr_<exception>, already fixed up for correct return/restart
> -	@  r5 - spsr_<exception>
> -	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
> -	@
> -	stmia	r7, {r2 - r6}
> -
> -#ifdef CONFIG_TRACE_IRQFLAGS
> -	bl	trace_hardirqs_off
> -#endif
> -	.endm
> -
>  	.align	5
>  __dabt_svc:
>  	svc_entry
> @@ -306,73 +259,8 @@ ENDPROC(__pabt_svc)
>  
>  /*
>   * User mode handlers
> - *
> - * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
>   */
>  
> -#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
> -#error "sizeof(struct pt_regs) must be a multiple of 8"
> -#endif
> -
> -	.macro	usr_entry
> - UNWIND(.fnstart	)
> - UNWIND(.cantunwind	)	@ don't unwind the user space
> -	sub	sp, sp, #S_FRAME_SIZE
> - ARM(	stmib	sp, {r1 - r12}	)
> - THUMB(	stmia	sp, {r0 - r12}	)
> -
> -	ldmia	r0, {r3 - r5}
> -	add	r0, sp, #S_PC		@ here for interlock avoidance
> -	mov	r6, #-1			@  ""  ""     ""        ""
> -
> -	str	r3, [sp]		@ save the "real" r0 copied
> -					@ from the exception stack
> -
> -	@
> -	@ We are now ready to fill in the remaining blanks on the stack:
> -	@
> -	@  r4 - lr_<exception>, already fixed up for correct return/restart
> -	@  r5 - spsr_<exception>
> -	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
> -	@
> -	@ Also, separately save sp_usr and lr_usr
> -	@
> -	stmia	r0, {r4 - r6}
> - ARM(	stmdb	r0, {sp, lr}^			)
> - THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
> -
> -	@
> -	@ Enable the alignment trap while in kernel mode
> -	@
> -	alignment_trap r0, .LCcralign
> -
> -	@
> -	@ Clear FP to mark the first stack frame
> -	@
> -	zero_fp
> -
> -#ifdef CONFIG_IRQSOFF_TRACER
> -	bl	trace_hardirqs_off
> -#endif
> -	ct_user_exit save = 0
> -	.endm
> -
> -	.macro	kuser_cmpxchg_check
> -#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
> -    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
> -#ifndef CONFIG_MMU
> -#warning "NPTL on non MMU needs fixing"
> -#else
> -	@ Make sure our user space atomic helper is restarted
> -	@ if it was interrupted in a critical region.  Here we
> -	@ perform a quick test inline since it should be false
> -	@ 99.9999% of the time.  The rest is done out of line.
> -	cmp	r4, #TASK_SIZE
> -	blhs	kuser_cmpxchg64_fixup
> -#endif
> -#endif
> -	.endm
> -
>  	.align	5
>  __dabt_usr:
>  	usr_entry
> @@ -823,6 +711,7 @@ __kuser_cmpxchg64:				@ 0xffff0f60
>  	ldmfd	sp!, {r4, r5, r6, pc}
>  
>  	.text
> +	.global kuser_cmpxchg64_fixup
>  kuser_cmpxchg64_fixup:
>  	@ Called from kuser_cmpxchg_fixup.
>  	@ r4 = address of interrupted insn (must be preserved).
> @@ -964,44 +853,6 @@ __kuser_helper_end:
>   * SP points to a minimal amount of processor-private memory, the address
>   * of which is copied into r0 for the mode specific abort handler.
>   */
> -	.macro	vector_stub, name, mode, correction=0
> -	.align	5
> -
> -vector_\name:
> -	.if \correction
> -	sub	lr, lr, #\correction
> -	.endif
> -
> -	@
> -	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
> -	@ (parent CPSR)
> -	@
> -	stmia	sp, {r0, lr}		@ save r0, lr
> -	mrs	lr, spsr
> -	str	lr, [sp, #8]		@ save spsr
> -
> -	@
> -	@ Prepare for SVC32 mode.  IRQs remain disabled.
> -	@
> -	mrs	r0, cpsr
> -	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
> -	msr	spsr_cxsf, r0
> -
> -	@
> -	@ the branch table must immediately follow this code
> -	@
> -	and	lr, lr, #0x0f
> - THUMB(	adr	r0, 1f			)
> - THUMB(	ldr	lr, [r0, lr, lsl #2]	)
> -	mov	r0, sp
> - ARM(	ldr	lr, [pc, lr, lsl #2]	)
> -	movs	pc, lr			@ branch to handler in SVC mode
> -ENDPROC(vector_\name)
> -
> -	.align	2
> -	@ handler addresses follow this label
> -1:
> -	.endm
>  
>  	.section .stubs, "ax", %progbits
>  __stubs_start:
> diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
> index 5d702f8..eb2c426 100644
> --- a/arch/arm/kernel/entry-header.S
> +++ b/arch/arm/kernel/entry-header.S
> @@ -356,3 +356,167 @@ scno	.req	r7		@ syscall number
>  tbl	.req	r8		@ syscall table pointer
>  why	.req	r8		@ Linux syscall (!= 0)
>  tsk	.req	r9		@ current thread_info
> +
> +/*
> + * SVC mode handler macros
> + */
> +
> +#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
> +#define SPFIX(code...) code
> +#else
> +#define SPFIX(code...)
> +#endif
> +
> +	.macro	svc_entry, stack_hole=0
> + UNWIND(.fnstart		)
> + UNWIND(.save {r0 - pc}		)
> +	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
> +#ifdef CONFIG_THUMB2_KERNEL
> + SPFIX(	str	r0, [sp]	)	@ temporarily saved
> + SPFIX(	mov	r0, sp		)
> + SPFIX(	tst	r0, #4		)	@ test original stack alignment
> + SPFIX(	ldr	r0, [sp]	)	@ restored
> +#else
> + SPFIX(	tst	sp, #4		)
> +#endif
> + SPFIX(	subeq	sp, sp, #4	)
> +	stmia	sp, {r1 - r12}
> +
> +	ldmia	r0, {r3 - r5}
> +	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
> +	mov	r6, #-1			@  ""  ""      ""       ""
> +	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
> + SPFIX(	addeq	r2, r2, #4	)
> +	str	r3, [sp, #-4]!		@ save the "real" r0 copied
> +					@ from the exception stack
> +
> +	mov	r3, lr
> +
> +	@
> +	@ We are now ready to fill in the remaining blanks on the stack:
> +	@
> +	@  r2 - sp_svc
> +	@  r3 - lr_svc
> +	@  r4 - lr_<exception>, already fixed up for correct return/restart
> +	@  r5 - spsr_<exception>
> +	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
> +	@
> +	stmia	r7, {r2 - r6}
> +
> +#ifdef CONFIG_TRACE_IRQFLAGS
> +	bl	trace_hardirqs_off
> +#endif
> +	.endm
> +
> +/*
> + * User mode handler macros
> + *
> + * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
> + */
> +
> +#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
> +#error "sizeof(struct pt_regs) must be a multiple of 8"
> +#endif
> +
> +	.macro	usr_entry
> + UNWIND(.fnstart	)
> + UNWIND(.cantunwind	)	@ don't unwind the user space
> +	sub	sp, sp, #S_FRAME_SIZE
> + ARM(	stmib	sp, {r1 - r12}	)
> + THUMB(	stmia	sp, {r0 - r12}	)
> +
> +	ldmia	r0, {r3 - r5}
> +	add	r0, sp, #S_PC		@ here for interlock avoidance
> +	mov	r6, #-1			@  ""  ""     ""        ""
> +
> +	str	r3, [sp]		@ save the "real" r0 copied
> +					@ from the exception stack
> +
> +	@
> +	@ We are now ready to fill in the remaining blanks on the stack:
> +	@
> +	@  r4 - lr_<exception>, already fixed up for correct return/restart
> +	@  r5 - spsr_<exception>
> +	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
> +	@
> +	@ Also, separately save sp_usr and lr_usr
> +	@
> +	stmia	r0, {r4 - r6}
> + ARM(	stmdb	r0, {sp, lr}^			)
> + THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
> +
> +	@
> +	@ Enable the alignment trap while in kernel mode
> +	@
> +	alignment_trap r0, .LCcralign
> +
> +	@
> +	@ Clear FP to mark the first stack frame
> +	@
> +	zero_fp
> +
> +#ifdef CONFIG_IRQSOFF_TRACER
> +	bl	trace_hardirqs_off
> +#endif
> +	ct_user_exit save = 0
> +	.endm
> +
> +	.macro	kuser_cmpxchg_check
> +#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
> +    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
> +#ifndef CONFIG_MMU
> +#warning "NPTL on non MMU needs fixing"
> +#else
> +	@ Make sure our user space atomic helper is restarted
> +	@ if it was interrupted in a critical region.  Here we
> +	@ perform a quick test inline since it should be false
> +	@ 99.9999% of the time.  The rest is done out of line.
> +	cmp	r4, #TASK_SIZE
> +	blhs	kuser_cmpxchg64_fixup
> +#endif
> +#endif
> +	.endm
> +
> +/*
> + * Vector stubs macro.
> + */
> +	.macro	vector_stub, name, mode, correction=0
> +	.align	5
> +
> +vector_\name:
> +	.if \correction
> +	sub	lr, lr, #\correction
> +	.endif
> +
> +	@
> +	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
> +	@ (parent CPSR)
> +	@
> +	stmia	sp, {r0, lr}		@ save r0, lr
> +	mrs	lr, spsr
> +	str	lr, [sp, #8]		@ save spsr
> +
> +	@
> +	@ Prepare for SVC32 mode.  IRQs remain disabled.
> +	@
> +	mrs	r0, cpsr
> +	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
> +	msr	spsr_cxsf, r0
> +
> +	@
> +	@ the branch table must immediately follow this code
> +	@
> +	and	lr, lr, #0x0f
> + THUMB(	adr	r0, 1f			)
> + THUMB(	ldr	lr, [r0, lr, lsl #2]	)
> +	mov	r0, sp
> + ARM(	ldr	lr, [pc, lr, lsl #2]	)
> +	movs	pc, lr			@ branch to handler in SVC mode
> +ENDPROC(vector_\name)
> +
> +	.align	2
> +	@ handler addresses follow this label
> +1:
> +	.endm
> +
> +
> -- 
> 1.9.3
> 

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v6 3/4] ARM: Move some macros from entry-armv to entry-header
@ 2014-06-24 15:53             ` Nicolas Pitre
  0 siblings, 0 replies; 535+ messages in thread
From: Nicolas Pitre @ 2014-06-24 15:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 24 Jun 2014, Daniel Thompson wrote:

> From: Anton Vorontsov <anton.vorontsov@linaro.org>
> 
> Just move the macros into header file as we would want to use them for
> KGDB FIQ entry code.
> 
> The following macros were moved:
> 
>  - svc_entry
>  - usr_entry
>  - kuser_cmpxchg_check
>  - vector_stub
> 
> To make kuser_cmpxchg_check actually work across different files, we
> also have to make kuser_cmpxchg64_fixup global.
> 
> Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
> Signed-off-by: John Stultz <john.stultz@linaro.org>
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Nicolas Pitre <nico@linaro.org>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Frederic Weisbecker <fweisbec@gmail.com>

Acked-by: Nicolas Pitre <nico@linaro.org>


> ---
>  arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
>  arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 165 insertions(+), 150 deletions(-)
> 
> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> index 52a949a..4172cd6 100644
> --- a/arch/arm/kernel/entry-armv.S
> +++ b/arch/arm/kernel/entry-armv.S
> @@ -140,53 +140,6 @@ ENDPROC(__und_invalid)
>   * SVC mode handlers
>   */
>  
> -#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
> -#define SPFIX(code...) code
> -#else
> -#define SPFIX(code...)
> -#endif
> -
> -	.macro	svc_entry, stack_hole=0
> - UNWIND(.fnstart		)
> - UNWIND(.save {r0 - pc}		)
> -	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
> -#ifdef CONFIG_THUMB2_KERNEL
> - SPFIX(	str	r0, [sp]	)	@ temporarily saved
> - SPFIX(	mov	r0, sp		)
> - SPFIX(	tst	r0, #4		)	@ test original stack alignment
> - SPFIX(	ldr	r0, [sp]	)	@ restored
> -#else
> - SPFIX(	tst	sp, #4		)
> -#endif
> - SPFIX(	subeq	sp, sp, #4	)
> -	stmia	sp, {r1 - r12}
> -
> -	ldmia	r0, {r3 - r5}
> -	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
> -	mov	r6, #-1			@  ""  ""      ""       ""
> -	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
> - SPFIX(	addeq	r2, r2, #4	)
> -	str	r3, [sp, #-4]!		@ save the "real" r0 copied
> -					@ from the exception stack
> -
> -	mov	r3, lr
> -
> -	@
> -	@ We are now ready to fill in the remaining blanks on the stack:
> -	@
> -	@  r2 - sp_svc
> -	@  r3 - lr_svc
> -	@  r4 - lr_<exception>, already fixed up for correct return/restart
> -	@  r5 - spsr_<exception>
> -	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
> -	@
> -	stmia	r7, {r2 - r6}
> -
> -#ifdef CONFIG_TRACE_IRQFLAGS
> -	bl	trace_hardirqs_off
> -#endif
> -	.endm
> -
>  	.align	5
>  __dabt_svc:
>  	svc_entry
> @@ -306,73 +259,8 @@ ENDPROC(__pabt_svc)
>  
>  /*
>   * User mode handlers
> - *
> - * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
>   */
>  
> -#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
> -#error "sizeof(struct pt_regs) must be a multiple of 8"
> -#endif
> -
> -	.macro	usr_entry
> - UNWIND(.fnstart	)
> - UNWIND(.cantunwind	)	@ don't unwind the user space
> -	sub	sp, sp, #S_FRAME_SIZE
> - ARM(	stmib	sp, {r1 - r12}	)
> - THUMB(	stmia	sp, {r0 - r12}	)
> -
> -	ldmia	r0, {r3 - r5}
> -	add	r0, sp, #S_PC		@ here for interlock avoidance
> -	mov	r6, #-1			@  ""  ""     ""        ""
> -
> -	str	r3, [sp]		@ save the "real" r0 copied
> -					@ from the exception stack
> -
> -	@
> -	@ We are now ready to fill in the remaining blanks on the stack:
> -	@
> -	@  r4 - lr_<exception>, already fixed up for correct return/restart
> -	@  r5 - spsr_<exception>
> -	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
> -	@
> -	@ Also, separately save sp_usr and lr_usr
> -	@
> -	stmia	r0, {r4 - r6}
> - ARM(	stmdb	r0, {sp, lr}^			)
> - THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
> -
> -	@
> -	@ Enable the alignment trap while in kernel mode
> -	@
> -	alignment_trap r0, .LCcralign
> -
> -	@
> -	@ Clear FP to mark the first stack frame
> -	@
> -	zero_fp
> -
> -#ifdef CONFIG_IRQSOFF_TRACER
> -	bl	trace_hardirqs_off
> -#endif
> -	ct_user_exit save = 0
> -	.endm
> -
> -	.macro	kuser_cmpxchg_check
> -#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
> -    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
> -#ifndef CONFIG_MMU
> -#warning "NPTL on non MMU needs fixing"
> -#else
> -	@ Make sure our user space atomic helper is restarted
> -	@ if it was interrupted in a critical region.  Here we
> -	@ perform a quick test inline since it should be false
> -	@ 99.9999% of the time.  The rest is done out of line.
> -	cmp	r4, #TASK_SIZE
> -	blhs	kuser_cmpxchg64_fixup
> -#endif
> -#endif
> -	.endm
> -
>  	.align	5
>  __dabt_usr:
>  	usr_entry
> @@ -823,6 +711,7 @@ __kuser_cmpxchg64:				@ 0xffff0f60
>  	ldmfd	sp!, {r4, r5, r6, pc}
>  
>  	.text
> +	.global kuser_cmpxchg64_fixup
>  kuser_cmpxchg64_fixup:
>  	@ Called from kuser_cmpxchg_fixup.
>  	@ r4 = address of interrupted insn (must be preserved).
> @@ -964,44 +853,6 @@ __kuser_helper_end:
>   * SP points to a minimal amount of processor-private memory, the address
>   * of which is copied into r0 for the mode specific abort handler.
>   */
> -	.macro	vector_stub, name, mode, correction=0
> -	.align	5
> -
> -vector_\name:
> -	.if \correction
> -	sub	lr, lr, #\correction
> -	.endif
> -
> -	@
> -	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
> -	@ (parent CPSR)
> -	@
> -	stmia	sp, {r0, lr}		@ save r0, lr
> -	mrs	lr, spsr
> -	str	lr, [sp, #8]		@ save spsr
> -
> -	@
> -	@ Prepare for SVC32 mode.  IRQs remain disabled.
> -	@
> -	mrs	r0, cpsr
> -	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
> -	msr	spsr_cxsf, r0
> -
> -	@
> -	@ the branch table must immediately follow this code
> -	@
> -	and	lr, lr, #0x0f
> - THUMB(	adr	r0, 1f			)
> - THUMB(	ldr	lr, [r0, lr, lsl #2]	)
> -	mov	r0, sp
> - ARM(	ldr	lr, [pc, lr, lsl #2]	)
> -	movs	pc, lr			@ branch to handler in SVC mode
> -ENDPROC(vector_\name)
> -
> -	.align	2
> -	@ handler addresses follow this label
> -1:
> -	.endm
>  
>  	.section .stubs, "ax", %progbits
>  __stubs_start:
> diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
> index 5d702f8..eb2c426 100644
> --- a/arch/arm/kernel/entry-header.S
> +++ b/arch/arm/kernel/entry-header.S
> @@ -356,3 +356,167 @@ scno	.req	r7		@ syscall number
>  tbl	.req	r8		@ syscall table pointer
>  why	.req	r8		@ Linux syscall (!= 0)
>  tsk	.req	r9		@ current thread_info
> +
> +/*
> + * SVC mode handler macros
> + */
> +
> +#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
> +#define SPFIX(code...) code
> +#else
> +#define SPFIX(code...)
> +#endif
> +
> +	.macro	svc_entry, stack_hole=0
> + UNWIND(.fnstart		)
> + UNWIND(.save {r0 - pc}		)
> +	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
> +#ifdef CONFIG_THUMB2_KERNEL
> + SPFIX(	str	r0, [sp]	)	@ temporarily saved
> + SPFIX(	mov	r0, sp		)
> + SPFIX(	tst	r0, #4		)	@ test original stack alignment
> + SPFIX(	ldr	r0, [sp]	)	@ restored
> +#else
> + SPFIX(	tst	sp, #4		)
> +#endif
> + SPFIX(	subeq	sp, sp, #4	)
> +	stmia	sp, {r1 - r12}
> +
> +	ldmia	r0, {r3 - r5}
> +	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
> +	mov	r6, #-1			@  ""  ""      ""       ""
> +	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
> + SPFIX(	addeq	r2, r2, #4	)
> +	str	r3, [sp, #-4]!		@ save the "real" r0 copied
> +					@ from the exception stack
> +
> +	mov	r3, lr
> +
> +	@
> +	@ We are now ready to fill in the remaining blanks on the stack:
> +	@
> +	@  r2 - sp_svc
> +	@  r3 - lr_svc
> +	@  r4 - lr_<exception>, already fixed up for correct return/restart
> +	@  r5 - spsr_<exception>
> +	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
> +	@
> +	stmia	r7, {r2 - r6}
> +
> +#ifdef CONFIG_TRACE_IRQFLAGS
> +	bl	trace_hardirqs_off
> +#endif
> +	.endm
> +
> +/*
> + * User mode handler macros
> + *
> + * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
> + */
> +
> +#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
> +#error "sizeof(struct pt_regs) must be a multiple of 8"
> +#endif
> +
> +	.macro	usr_entry
> + UNWIND(.fnstart	)
> + UNWIND(.cantunwind	)	@ don't unwind the user space
> +	sub	sp, sp, #S_FRAME_SIZE
> + ARM(	stmib	sp, {r1 - r12}	)
> + THUMB(	stmia	sp, {r0 - r12}	)
> +
> +	ldmia	r0, {r3 - r5}
> +	add	r0, sp, #S_PC		@ here for interlock avoidance
> +	mov	r6, #-1			@  ""  ""     ""        ""
> +
> +	str	r3, [sp]		@ save the "real" r0 copied
> +					@ from the exception stack
> +
> +	@
> +	@ We are now ready to fill in the remaining blanks on the stack:
> +	@
> +	@  r4 - lr_<exception>, already fixed up for correct return/restart
> +	@  r5 - spsr_<exception>
> +	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
> +	@
> +	@ Also, separately save sp_usr and lr_usr
> +	@
> +	stmia	r0, {r4 - r6}
> + ARM(	stmdb	r0, {sp, lr}^			)
> + THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
> +
> +	@
> +	@ Enable the alignment trap while in kernel mode
> +	@
> +	alignment_trap r0, .LCcralign
> +
> +	@
> +	@ Clear FP to mark the first stack frame
> +	@
> +	zero_fp
> +
> +#ifdef CONFIG_IRQSOFF_TRACER
> +	bl	trace_hardirqs_off
> +#endif
> +	ct_user_exit save = 0
> +	.endm
> +
> +	.macro	kuser_cmpxchg_check
> +#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
> +    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
> +#ifndef CONFIG_MMU
> +#warning "NPTL on non MMU needs fixing"
> +#else
> +	@ Make sure our user space atomic helper is restarted
> +	@ if it was interrupted in a critical region.  Here we
> +	@ perform a quick test inline since it should be false
> +	@ 99.9999% of the time.  The rest is done out of line.
> +	cmp	r4, #TASK_SIZE
> +	blhs	kuser_cmpxchg64_fixup
> +#endif
> +#endif
> +	.endm
> +
> +/*
> + * Vector stubs macro.
> + */
> +	.macro	vector_stub, name, mode, correction=0
> +	.align	5
> +
> +vector_\name:
> +	.if \correction
> +	sub	lr, lr, #\correction
> +	.endif
> +
> +	@
> +	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
> +	@ (parent CPSR)
> +	@
> +	stmia	sp, {r0, lr}		@ save r0, lr
> +	mrs	lr, spsr
> +	str	lr, [sp, #8]		@ save spsr
> +
> +	@
> +	@ Prepare for SVC32 mode.  IRQs remain disabled.
> +	@
> +	mrs	r0, cpsr
> +	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
> +	msr	spsr_cxsf, r0
> +
> +	@
> +	@ the branch table must immediately follow this code
> +	@
> +	and	lr, lr, #0x0f
> + THUMB(	adr	r0, 1f			)
> + THUMB(	ldr	lr, [r0, lr, lsl #2]	)
> +	mov	r0, sp
> + ARM(	ldr	lr, [pc, lr, lsl #2]	)
> +	movs	pc, lr			@ branch to handler in SVC mode
> +ENDPROC(vector_\name)
> +
> +	.align	2
> +	@ handler addresses follow this label
> +1:
> +	.endm
> +
> +
> -- 
> 1.9.3
> 

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v6 1/4] arm: fiq: Add callbacks to manage FIQ routings
  2014-06-24 15:44             ` Nicolas Pitre
@ 2014-06-24 15:58               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-24 15:58 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: Russell King, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker

On 24/06/14 16:44, Nicolas Pitre wrote:
> On Tue, 24 Jun 2014, Daniel Thompson wrote:
> 
>> Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
>> virq into a FIQ virq. This is too inflexible for multi-platform kernels
>> and makes runtime error checking impossible.
>>
>> We solve this by introducing a flexible mapping that allows interrupt
>> controllers that support FIQ to register those mappings. This, in turn,
>> makes it much possible for drivers in DT kernels to install FIQ handlers
>> without knowing anything about the interrupt controller.
>>
>> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
>> Cc: Russell King <linux@arm.linux.org.uk>
>> Cc: Fabio Estevam <festevam@gmail.com>
>> Cc: Nicolas Pitre <nico@linaro.org>
>> ---
>>  arch/arm/include/asm/fiq.h |   7 +++
>>  arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
>>  2 files changed, 108 insertions(+), 2 deletions(-)
> 
> [...]
> 
>> +bool has_fiq(int fiq)
>> +{
>> +	struct fiq_data *data = lookup_fiq_data(fiq);
>> +
>> +	if (data)
>> +		return true;
>> +
>> +	if (fiq_start == -1)
>> +		return false;
>> +
>> +	return fiq > fiq_start;
> 
> Shouldn't this be fiq >= fiq_start ?

Absolutely! Will fix that shortly.


Thanks

Daniel.



^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v6 1/4] arm: fiq: Add callbacks to manage FIQ routings
@ 2014-06-24 15:58               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-24 15:58 UTC (permalink / raw)
  To: linux-arm-kernel

On 24/06/14 16:44, Nicolas Pitre wrote:
> On Tue, 24 Jun 2014, Daniel Thompson wrote:
> 
>> Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
>> virq into a FIQ virq. This is too inflexible for multi-platform kernels
>> and makes runtime error checking impossible.
>>
>> We solve this by introducing a flexible mapping that allows interrupt
>> controllers that support FIQ to register those mappings. This, in turn,
>> makes it much possible for drivers in DT kernels to install FIQ handlers
>> without knowing anything about the interrupt controller.
>>
>> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
>> Cc: Russell King <linux@arm.linux.org.uk>
>> Cc: Fabio Estevam <festevam@gmail.com>
>> Cc: Nicolas Pitre <nico@linaro.org>
>> ---
>>  arch/arm/include/asm/fiq.h |   7 +++
>>  arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
>>  2 files changed, 108 insertions(+), 2 deletions(-)
> 
> [...]
> 
>> +bool has_fiq(int fiq)
>> +{
>> +	struct fiq_data *data = lookup_fiq_data(fiq);
>> +
>> +	if (data)
>> +		return true;
>> +
>> +	if (fiq_start == -1)
>> +		return false;
>> +
>> +	return fiq > fiq_start;
> 
> Shouldn't this be fiq >= fiq_start ?

Absolutely! Will fix that shortly.


Thanks

Daniel.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v6 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
  2014-06-24 15:18           ` Daniel Thompson
@ 2014-06-24 16:08             ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-06-24 16:08 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Anton Vorontsov, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Colin Cross, kernel-team,
	Rob Herring, Linus Walleij, Ben Dooks, Catalin Marinas,
	Dave Martin, Fabio Estevam, Frederic Weisbecker, Nicolas Pitre

On Tue, Jun 24, 2014 at 04:18:17PM +0100, Daniel Thompson wrote:
> +	.align	5
> +__fiq_svc:
> +	svc_entry

Remember that the registers you have on the stack here are r0-r12, plus
the SVC banked sp and lr registers.  These may not be the registers
from the mode you took the FIQ (eg, if it was IRQ, or abort mode.)

Also bear in mind that svc_entry calls trace_hardirqs_off - is this
appropriate and safe for the FIQ to call?

> +	fiq_handler
> +	mov	r0, sp
> +	ldmib	r0, {r1 - r14}

So this restores r1 to r12, and the SVC mode sp and lr registers.
Nothing touches the SVC SPSR, so we hope that retains its value
throughout the FIQ processing.  Note that the stack pointer at this
point will be above state which we have not yet read, so we better
not take any exceptions from this instruction (not even an imprecise
abort).

> +	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT

Here we switch to FIQ mode.  What about the PSR_A_BIT which prevents
imprecise aborts on ARMv6+ ?

Nevertheless, I think it's safe because the A bit will be set by the
CPU when taking the FIQ exception, and it should remain set since
cpsr_c won't modify it.

> +	add	r8, r0, #S_PC
> +	ldr	r9, [r0, #S_PSR]
> +	msr	spsr_cxsf, r9

Here we update the FIQ SPSR with the calling mode's CPSR, ready to
return...

> +	ldr	r0, [r0, #S_R0]

Load the calling mode's R0 value.

> +	ldmia	r8, {pc}^

And return (restoring CPSR from SPSR_fiq).

This looks pretty good except for the niggles...

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v6 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
@ 2014-06-24 16:08             ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-06-24 16:08 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jun 24, 2014 at 04:18:17PM +0100, Daniel Thompson wrote:
> +	.align	5
> +__fiq_svc:
> +	svc_entry

Remember that the registers you have on the stack here are r0-r12, plus
the SVC banked sp and lr registers.  These may not be the registers
from the mode you took the FIQ (eg, if it was IRQ, or abort mode.)

Also bear in mind that svc_entry calls trace_hardirqs_off - is this
appropriate and safe for the FIQ to call?

> +	fiq_handler
> +	mov	r0, sp
> +	ldmib	r0, {r1 - r14}

So this restores r1 to r12, and the SVC mode sp and lr registers.
Nothing touches the SVC SPSR, so we hope that retains its value
throughout the FIQ processing.  Note that the stack pointer at this
point will be above state which we have not yet read, so we better
not take any exceptions from this instruction (not even an imprecise
abort).

> +	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT

Here we switch to FIQ mode.  What about the PSR_A_BIT which prevents
imprecise aborts on ARMv6+ ?

Nevertheless, I think it's safe because the A bit will be set by the
CPU when taking the FIQ exception, and it should remain set since
cpsr_c won't modify it.

> +	add	r8, r0, #S_PC
> +	ldr	r9, [r0, #S_PSR]
> +	msr	spsr_cxsf, r9

Here we update the FIQ SPSR with the calling mode's CPSR, ready to
return...

> +	ldr	r0, [r0, #S_R0]

Load the calling mode's R0 value.

> +	ldmia	r8, {pc}^

And return (restoring CPSR from SPSR_fiq).

This looks pretty good except for the niggles...

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v6 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
  2014-06-24 15:18           ` Daniel Thompson
@ 2014-06-24 16:22             ` Nicolas Pitre
  -1 siblings, 0 replies; 535+ messages in thread
From: Nicolas Pitre @ 2014-06-24 16:22 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Russell King, Anton Vorontsov, linux-kernel, linux-arm-kernel,
	kgdb-bugreport, patches, linaro-kernel, John Stultz, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker

On Tue, 24 Jun 2014, Daniel Thompson wrote:

> From: Anton Vorontsov <anton.vorontsov@linaro.org>
> 
> The FIQ debugger may be used to debug situations when the kernel stuck
> in uninterruptable sections, e.g. the kernel infinitely loops or
> deadlocked in an interrupt or with interrupts disabled.
> 
> By default KGDB FIQ is disabled in runtime, but can be enabled with
> kgdb_fiq.enable=1 kernel command line option.
> 
> Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
> Signed-off-by: John Stultz <john.stultz@linaro.org>
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Ben Dooks <ben.dooks@codethink.co.uk>
> Cc: Dave Martin <Dave.Martin@arm.com>
> ---
>  arch/arm/Kconfig                 |   2 +
>  arch/arm/Kconfig.debug           |  18 ++++++
>  arch/arm/include/asm/kgdb.h      |   7 +++
>  arch/arm/kernel/Makefile         |   1 +
>  arch/arm/kernel/kgdb_fiq.c       | 124 +++++++++++++++++++++++++++++++++++++++
>  arch/arm/kernel/kgdb_fiq_entry.S |  87 +++++++++++++++++++++++++++
>  6 files changed, 239 insertions(+)
>  create mode 100644 arch/arm/kernel/kgdb_fiq.c
>  create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

[...]

> +static long kgdb_fiq_setup_stack(void *info)
> +{
> +	struct pt_regs regs;
> +
> +	regs.ARM_sp = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER) +
> +			THREAD_START_SP;
> +	WARN_ON(!regs.ARM_sp);

Isn't this rather fatal if you can't allocate any stack? Why not using 
BUG_ON(), or better yet propagate a proper error code back?

> +
> +	set_fiq_regs(&regs);
> +	return 0;
> +}
> +
> +/**
> + * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
> + * @on: Flag to either enable or disable an NMI
> + *
> + * This function manages NMIs that usually cause KGDB to enter. That is, not
> + * all NMIs should be enabled or disabled, but only those that issue
> + * kgdb_handle_exception().
> + *
> + * The call counts disable requests, and thus allows to nest disables. But
> + * trying to enable already enabled NMI is an error.
> + */
> +static void kgdb_fiq_enable_nmi(bool on)
> +{
> +	static atomic_t cnt;
> +	int ret;
> +
> +	ret = atomic_add_return(on ? 1 : -1, &cnt);
> +	if (ret > 1 && on) {
> +		/*
> +		 * There should be only one instance that calls this function
> +		 * in "enable, disable" order. All other users must call
> +		 * disable first, then enable. If not, something is wrong.
> +		 */
> +		WARN_ON(1);
> +		return;
> +	}

Minor style suggestion:

	/*
	 * There should be only one instance that calls this function
	 * in "enable, disable" order. All other users must call
	 * disable first, then enable. If not, something is wrong.
	 */
	if (WARN_ON(ret > 1 && on))
		return;

Other than that...

Acked-by: Nicolas Pitre <nico@linaro.org>


Nicolas

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v6 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
@ 2014-06-24 16:22             ` Nicolas Pitre
  0 siblings, 0 replies; 535+ messages in thread
From: Nicolas Pitre @ 2014-06-24 16:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 24 Jun 2014, Daniel Thompson wrote:

> From: Anton Vorontsov <anton.vorontsov@linaro.org>
> 
> The FIQ debugger may be used to debug situations when the kernel stuck
> in uninterruptable sections, e.g. the kernel infinitely loops or
> deadlocked in an interrupt or with interrupts disabled.
> 
> By default KGDB FIQ is disabled in runtime, but can be enabled with
> kgdb_fiq.enable=1 kernel command line option.
> 
> Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
> Signed-off-by: John Stultz <john.stultz@linaro.org>
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Ben Dooks <ben.dooks@codethink.co.uk>
> Cc: Dave Martin <Dave.Martin@arm.com>
> ---
>  arch/arm/Kconfig                 |   2 +
>  arch/arm/Kconfig.debug           |  18 ++++++
>  arch/arm/include/asm/kgdb.h      |   7 +++
>  arch/arm/kernel/Makefile         |   1 +
>  arch/arm/kernel/kgdb_fiq.c       | 124 +++++++++++++++++++++++++++++++++++++++
>  arch/arm/kernel/kgdb_fiq_entry.S |  87 +++++++++++++++++++++++++++
>  6 files changed, 239 insertions(+)
>  create mode 100644 arch/arm/kernel/kgdb_fiq.c
>  create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

[...]

> +static long kgdb_fiq_setup_stack(void *info)
> +{
> +	struct pt_regs regs;
> +
> +	regs.ARM_sp = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER) +
> +			THREAD_START_SP;
> +	WARN_ON(!regs.ARM_sp);

Isn't this rather fatal if you can't allocate any stack? Why not using 
BUG_ON(), or better yet propagate a proper error code back?

> +
> +	set_fiq_regs(&regs);
> +	return 0;
> +}
> +
> +/**
> + * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
> + * @on: Flag to either enable or disable an NMI
> + *
> + * This function manages NMIs that usually cause KGDB to enter. That is, not
> + * all NMIs should be enabled or disabled, but only those that issue
> + * kgdb_handle_exception().
> + *
> + * The call counts disable requests, and thus allows to nest disables. But
> + * trying to enable already enabled NMI is an error.
> + */
> +static void kgdb_fiq_enable_nmi(bool on)
> +{
> +	static atomic_t cnt;
> +	int ret;
> +
> +	ret = atomic_add_return(on ? 1 : -1, &cnt);
> +	if (ret > 1 && on) {
> +		/*
> +		 * There should be only one instance that calls this function
> +		 * in "enable, disable" order. All other users must call
> +		 * disable first, then enable. If not, something is wrong.
> +		 */
> +		WARN_ON(1);
> +		return;
> +	}

Minor style suggestion:

	/*
	 * There should be only one instance that calls this function
	 * in "enable, disable" order. All other users must call
	 * disable first, then enable. If not, something is wrong.
	 */
	if (WARN_ON(ret > 1 && on))
		return;

Other than that...

Acked-by: Nicolas Pitre <nico@linaro.org>


Nicolas

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v6 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
  2014-06-24 16:08             ` Russell King - ARM Linux
@ 2014-06-26  9:54               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-26  9:54 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Anton Vorontsov, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Colin Cross, kernel-team,
	Rob Herring, Linus Walleij, Ben Dooks, Catalin Marinas,
	Dave Martin, Fabio Estevam, Frederic Weisbecker, Nicolas Pitre

On 24/06/14 17:08, Russell King - ARM Linux wrote:
> On Tue, Jun 24, 2014 at 04:18:17PM +0100, Daniel Thompson wrote:
>> +	.align	5
>> +__fiq_svc:
>> +	svc_entry
> 
> Remember that the registers you have on the stack here are r0-r12, plus
> the SVC banked sp and lr registers.  These may not be the registers
> from the mode you took the FIQ (eg, if it was IRQ, or abort mode.)

We probably ought to save/restore lr_abt and spsr_abt but I think sp_abt
and the state for irq and und can be neglected.

The stack pointers are constant anyway and I think it reasonable to
assume the FIQ handler doesn't unmask interrupts or attempt to execute
undefined instructions.


> Also bear in mind that svc_entry calls trace_hardirqs_off - is this
> appropriate and safe for the FIQ to call?

I personally think it appropriate and it looked safe on the lockdep side
of things. However I will look a bit deeper at this since I don't
remember how far I chased things back.

Naturally it is a problem that we don't currently call trace_hardirq_on.
I'll fix this.


>> +	fiq_handler
>> +	mov	r0, sp
>> +	ldmib	r0, {r1 - r14}
> 
> So this restores r1 to r12, and the SVC mode sp and lr registers.
> Nothing touches the SVC SPSR, so we hope that retains its value
> throughout the FIQ processing. 

Are you worried about something changing it?

I haven't thought of any good reason for it to change. The FIQ handler
can't safely execute a SVC instruction.


> Note that the stack pointer at this
> point will be above state which we have not yet read, so we better
> not take any exceptions from this instruction (not even an imprecise
> abort).

Can a comment cover this? We shouldn't get an abort reading the SVC
stack and imprecise abort is blocked.

Note we could copy these values back onto the FIQ stack before switching
modes if is there's a possibility of an abort we cannot avoid, however
I'm not know if this is worthwhile.


>> +	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
> 
> Here we switch to FIQ mode.  What about the PSR_A_BIT which prevents
> imprecise aborts on ARMv6+ ?
> 
> Nevertheless, I think it's safe because the A bit will be set by the
> CPU when taking the FIQ exception, and it should remain set since
> cpsr_c won't modify it.

Agreed.

Note that while double checking this I realized that this code will drop
the value of PSR_ISETSTATE (T bit) that the vector_stub macro set for
us. I'll fix this.


>> +	add	r8, r0, #S_PC
>> +	ldr	r9, [r0, #S_PSR]
>> +	msr	spsr_cxsf, r9
> 
> Here we update the FIQ SPSR with the calling mode's CPSR, ready to
> return...
> 
>> +	ldr	r0, [r0, #S_R0]
> 
> Load the calling mode's R0 value.
> 
>> +	ldmia	r8, {pc}^
> 
> And return (restoring CPSR from SPSR_fiq).
> 
> This looks pretty good except for the niggles...

Thanks.

I've picked out the following actions from the above:

1. Wrap a save and restore lr_abt and spsr_abt around the FIQ handler
2. Add a paired up trace_hardirqs_on() (and review more deeply).
3. Add comments explaining hazards w.r.t. data abort,
4. Correctly manage T bit during transition back to FIQ mode.

Do I miss anything?


Daniel.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v6 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
@ 2014-06-26  9:54               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-26  9:54 UTC (permalink / raw)
  To: linux-arm-kernel

On 24/06/14 17:08, Russell King - ARM Linux wrote:
> On Tue, Jun 24, 2014 at 04:18:17PM +0100, Daniel Thompson wrote:
>> +	.align	5
>> +__fiq_svc:
>> +	svc_entry
> 
> Remember that the registers you have on the stack here are r0-r12, plus
> the SVC banked sp and lr registers.  These may not be the registers
> from the mode you took the FIQ (eg, if it was IRQ, or abort mode.)

We probably ought to save/restore lr_abt and spsr_abt but I think sp_abt
and the state for irq and und can be neglected.

The stack pointers are constant anyway and I think it reasonable to
assume the FIQ handler doesn't unmask interrupts or attempt to execute
undefined instructions.


> Also bear in mind that svc_entry calls trace_hardirqs_off - is this
> appropriate and safe for the FIQ to call?

I personally think it appropriate and it looked safe on the lockdep side
of things. However I will look a bit deeper at this since I don't
remember how far I chased things back.

Naturally it is a problem that we don't currently call trace_hardirq_on.
I'll fix this.


>> +	fiq_handler
>> +	mov	r0, sp
>> +	ldmib	r0, {r1 - r14}
> 
> So this restores r1 to r12, and the SVC mode sp and lr registers.
> Nothing touches the SVC SPSR, so we hope that retains its value
> throughout the FIQ processing. 

Are you worried about something changing it?

I haven't thought of any good reason for it to change. The FIQ handler
can't safely execute a SVC instruction.


> Note that the stack pointer at this
> point will be above state which we have not yet read, so we better
> not take any exceptions from this instruction (not even an imprecise
> abort).

Can a comment cover this? We shouldn't get an abort reading the SVC
stack and imprecise abort is blocked.

Note we could copy these values back onto the FIQ stack before switching
modes if is there's a possibility of an abort we cannot avoid, however
I'm not know if this is worthwhile.


>> +	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
> 
> Here we switch to FIQ mode.  What about the PSR_A_BIT which prevents
> imprecise aborts on ARMv6+ ?
> 
> Nevertheless, I think it's safe because the A bit will be set by the
> CPU when taking the FIQ exception, and it should remain set since
> cpsr_c won't modify it.

Agreed.

Note that while double checking this I realized that this code will drop
the value of PSR_ISETSTATE (T bit) that the vector_stub macro set for
us. I'll fix this.


>> +	add	r8, r0, #S_PC
>> +	ldr	r9, [r0, #S_PSR]
>> +	msr	spsr_cxsf, r9
> 
> Here we update the FIQ SPSR with the calling mode's CPSR, ready to
> return...
> 
>> +	ldr	r0, [r0, #S_R0]
> 
> Load the calling mode's R0 value.
> 
>> +	ldmia	r8, {pc}^
> 
> And return (restoring CPSR from SPSR_fiq).
> 
> This looks pretty good except for the niggles...

Thanks.

I've picked out the following actions from the above:

1. Wrap a save and restore lr_abt and spsr_abt around the FIQ handler
2. Add a paired up trace_hardirqs_on() (and review more deeply).
3. Add comments explaining hazards w.r.t. data abort,
4. Correctly manage T bit during transition back to FIQ mode.

Do I miss anything?


Daniel.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v6 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
  2014-06-24 16:22             ` Nicolas Pitre
@ 2014-06-26 12:48               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-26 12:48 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: Russell King, Anton Vorontsov, linux-kernel, linux-arm-kernel,
	kgdb-bugreport, patches, linaro-kernel, John Stultz, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker

On 24/06/14 17:22, Nicolas Pitre wrote:
> On Tue, 24 Jun 2014, Daniel Thompson wrote:
> 
>> From: Anton Vorontsov <anton.vorontsov@linaro.org>
>>
>> The FIQ debugger may be used to debug situations when the kernel stuck
>> in uninterruptable sections, e.g. the kernel infinitely loops or
>> deadlocked in an interrupt or with interrupts disabled.
>>
>> By default KGDB FIQ is disabled in runtime, but can be enabled with
>> kgdb_fiq.enable=1 kernel command line option.
>>
>> Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
>> Signed-off-by: John Stultz <john.stultz@linaro.org>
>> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
>> Cc: Russell King <linux@arm.linux.org.uk>
>> Cc: Ben Dooks <ben.dooks@codethink.co.uk>
>> Cc: Dave Martin <Dave.Martin@arm.com>
>> ---
>>  arch/arm/Kconfig                 |   2 +
>>  arch/arm/Kconfig.debug           |  18 ++++++
>>  arch/arm/include/asm/kgdb.h      |   7 +++
>>  arch/arm/kernel/Makefile         |   1 +
>>  arch/arm/kernel/kgdb_fiq.c       | 124 +++++++++++++++++++++++++++++++++++++++
>>  arch/arm/kernel/kgdb_fiq_entry.S |  87 +++++++++++++++++++++++++++
>>  6 files changed, 239 insertions(+)
>>  create mode 100644 arch/arm/kernel/kgdb_fiq.c
>>  create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S
> 
> [...]
> 
>> +static long kgdb_fiq_setup_stack(void *info)
>> +{
>> +	struct pt_regs regs;
>> +
>> +	regs.ARM_sp = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER) +
>> +			THREAD_START_SP;
>> +	WARN_ON(!regs.ARM_sp);
> 
> Isn't this rather fatal if you can't allocate any stack? Why not using 
> BUG_ON(), or better yet propagate a proper error code back?

Thanks for raising this.

I think we can get rid of the allocation altogether. This stack is *way*
oversized (it only needs to be 12 bytes).


>> +
>> +	set_fiq_regs(&regs);
>> +	return 0;
>> +}
>> +
>> +/**
>> + * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
>> + * @on: Flag to either enable or disable an NMI
>> + *
>> + * This function manages NMIs that usually cause KGDB to enter. That is, not
>> + * all NMIs should be enabled or disabled, but only those that issue
>> + * kgdb_handle_exception().
>> + *
>> + * The call counts disable requests, and thus allows to nest disables. But
>> + * trying to enable already enabled NMI is an error.
>> + */
>> +static void kgdb_fiq_enable_nmi(bool on)
>> +{
>> +	static atomic_t cnt;
>> +	int ret;
>> +
>> +	ret = atomic_add_return(on ? 1 : -1, &cnt);
>> +	if (ret > 1 && on) {
>> +		/*
>> +		 * There should be only one instance that calls this function
>> +		 * in "enable, disable" order. All other users must call
>> +		 * disable first, then enable. If not, something is wrong.
>> +		 */
>> +		WARN_ON(1);
>> +		return;
>> +	}
> 
> Minor style suggestion:
> 
> 	/*
> 	 * There should be only one instance that calls this function
> 	 * in "enable, disable" order. All other users must call
> 	 * disable first, then enable. If not, something is wrong.
> 	 */
> 	if (WARN_ON(ret > 1 && on))
> 		return;

Will adopt this style.


> Other than that...
> 
> Acked-by: Nicolas Pitre <nico@linaro.org>

Thanks for review.


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v6 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
@ 2014-06-26 12:48               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-26 12:48 UTC (permalink / raw)
  To: linux-arm-kernel

On 24/06/14 17:22, Nicolas Pitre wrote:
> On Tue, 24 Jun 2014, Daniel Thompson wrote:
> 
>> From: Anton Vorontsov <anton.vorontsov@linaro.org>
>>
>> The FIQ debugger may be used to debug situations when the kernel stuck
>> in uninterruptable sections, e.g. the kernel infinitely loops or
>> deadlocked in an interrupt or with interrupts disabled.
>>
>> By default KGDB FIQ is disabled in runtime, but can be enabled with
>> kgdb_fiq.enable=1 kernel command line option.
>>
>> Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
>> Signed-off-by: John Stultz <john.stultz@linaro.org>
>> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
>> Cc: Russell King <linux@arm.linux.org.uk>
>> Cc: Ben Dooks <ben.dooks@codethink.co.uk>
>> Cc: Dave Martin <Dave.Martin@arm.com>
>> ---
>>  arch/arm/Kconfig                 |   2 +
>>  arch/arm/Kconfig.debug           |  18 ++++++
>>  arch/arm/include/asm/kgdb.h      |   7 +++
>>  arch/arm/kernel/Makefile         |   1 +
>>  arch/arm/kernel/kgdb_fiq.c       | 124 +++++++++++++++++++++++++++++++++++++++
>>  arch/arm/kernel/kgdb_fiq_entry.S |  87 +++++++++++++++++++++++++++
>>  6 files changed, 239 insertions(+)
>>  create mode 100644 arch/arm/kernel/kgdb_fiq.c
>>  create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S
> 
> [...]
> 
>> +static long kgdb_fiq_setup_stack(void *info)
>> +{
>> +	struct pt_regs regs;
>> +
>> +	regs.ARM_sp = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER) +
>> +			THREAD_START_SP;
>> +	WARN_ON(!regs.ARM_sp);
> 
> Isn't this rather fatal if you can't allocate any stack? Why not using 
> BUG_ON(), or better yet propagate a proper error code back?

Thanks for raising this.

I think we can get rid of the allocation altogether. This stack is *way*
oversized (it only needs to be 12 bytes).


>> +
>> +	set_fiq_regs(&regs);
>> +	return 0;
>> +}
>> +
>> +/**
>> + * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
>> + * @on: Flag to either enable or disable an NMI
>> + *
>> + * This function manages NMIs that usually cause KGDB to enter. That is, not
>> + * all NMIs should be enabled or disabled, but only those that issue
>> + * kgdb_handle_exception().
>> + *
>> + * The call counts disable requests, and thus allows to nest disables. But
>> + * trying to enable already enabled NMI is an error.
>> + */
>> +static void kgdb_fiq_enable_nmi(bool on)
>> +{
>> +	static atomic_t cnt;
>> +	int ret;
>> +
>> +	ret = atomic_add_return(on ? 1 : -1, &cnt);
>> +	if (ret > 1 && on) {
>> +		/*
>> +		 * There should be only one instance that calls this function
>> +		 * in "enable, disable" order. All other users must call
>> +		 * disable first, then enable. If not, something is wrong.
>> +		 */
>> +		WARN_ON(1);
>> +		return;
>> +	}
> 
> Minor style suggestion:
> 
> 	/*
> 	 * There should be only one instance that calls this function
> 	 * in "enable, disable" order. All other users must call
> 	 * disable first, then enable. If not, something is wrong.
> 	 */
> 	if (WARN_ON(ret > 1 && on))
> 		return;

Will adopt this style.


> Other than that...
> 
> Acked-by: Nicolas Pitre <nico@linaro.org>

Thanks for review.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v7 0/4] arm: KGDB NMI/FIQ support
  2014-06-24 15:18         ` Daniel Thompson
@ 2014-06-30  8:53           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-30  8:53 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

This patchset makes it possible to use kgdb's NMI infrastructure on ARM
platforms.

The patches have been previously circulated as part of a large patchset
mixing together ARM architecture code and driver changes
(http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901 ). This
patchset is dramatically cut down to include only the arch/arm code. The
driver code (irqchip and tty/serial) will follow when/if the arch code
is accepted.

The first two patches modify the FIQ infrastructure to allow interrupt
controller drivers to register callbacks (the fiq_chip structure) to
manage FIQ routings and to signal FIQ EOI. This makes it possible to
use FIQ in multi-platform kernels and with recent ARM interrupt
controllers.

The remaining two patches provide architecture support for KGDB's NMI
feature (and rely upon the preceding changes to the FIQ code).

Tested on qemu (versatile), STiH416 (B2020 board) and Freescale i.MX6
quad (wandboard).

Changes since v6:

- Corrected off-by-one comparison in has_fiq() (Nicolas Pitre)
- Rewrote the FIQ stack initialization (Nicolas Pitre). This fixes a
  serious data corruption bug due to bad stack mismanagement.
- Introduced __fiq_abt to ensure lr_abt and spsr_abt are saved and
  restored if we fast-interrupt an abort (Russell King).
- Significantly improved the commenting of the exception handlers.
- Added a call to trace_hardirqs_on() if we clear the I bit as we
  exit the exception handler.

Changes since v5:

- Separated anything not strictly impacting arch/arm.
- Fixed a spurious add/remove of code within the series (there was
  broken code in intermediate patches)

For previous changes see:
http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901


Anton Vorontsov (2):
  ARM: Move some macros from entry-armv to entry-header
  ARM: Add KGDB/KDB FIQ debugger generic code

Daniel Thompson (2):
  arm: fiq: Add callbacks to manage FIQ routings
  arm: fiq: Allow EOI to be communicated to the intc

 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 +++++
 arch/arm/include/asm/fiq.h       |  14 ++++
 arch/arm/include/asm/kgdb.h      |   7 ++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/entry-armv.S     | 151 +----------------------------------
 arch/arm/kernel/entry-header.S   | 164 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/fiq.c            | 112 +++++++++++++++++++++++++-
 arch/arm/kernel/kgdb_fiq.c       | 127 ++++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S | 130 +++++++++++++++++++++++++++++++
 10 files changed, 574 insertions(+), 152 deletions(-)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

--
1.9.3


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v7 0/4] arm: KGDB NMI/FIQ support
@ 2014-06-30  8:53           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-30  8:53 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset makes it possible to use kgdb's NMI infrastructure on ARM
platforms.

The patches have been previously circulated as part of a large patchset
mixing together ARM architecture code and driver changes
(http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901 ). This
patchset is dramatically cut down to include only the arch/arm code. The
driver code (irqchip and tty/serial) will follow when/if the arch code
is accepted.

The first two patches modify the FIQ infrastructure to allow interrupt
controller drivers to register callbacks (the fiq_chip structure) to
manage FIQ routings and to signal FIQ EOI. This makes it possible to
use FIQ in multi-platform kernels and with recent ARM interrupt
controllers.

The remaining two patches provide architecture support for KGDB's NMI
feature (and rely upon the preceding changes to the FIQ code).

Tested on qemu (versatile), STiH416 (B2020 board) and Freescale i.MX6
quad (wandboard).

Changes since v6:

- Corrected off-by-one comparison in has_fiq() (Nicolas Pitre)
- Rewrote the FIQ stack initialization (Nicolas Pitre). This fixes a
  serious data corruption bug due to bad stack mismanagement.
- Introduced __fiq_abt to ensure lr_abt and spsr_abt are saved and
  restored if we fast-interrupt an abort (Russell King).
- Significantly improved the commenting of the exception handlers.
- Added a call to trace_hardirqs_on() if we clear the I bit as we
  exit the exception handler.

Changes since v5:

- Separated anything not strictly impacting arch/arm.
- Fixed a spurious add/remove of code within the series (there was
  broken code in intermediate patches)

For previous changes see:
http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901


Anton Vorontsov (2):
  ARM: Move some macros from entry-armv to entry-header
  ARM: Add KGDB/KDB FIQ debugger generic code

Daniel Thompson (2):
  arm: fiq: Add callbacks to manage FIQ routings
  arm: fiq: Allow EOI to be communicated to the intc

 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 +++++
 arch/arm/include/asm/fiq.h       |  14 ++++
 arch/arm/include/asm/kgdb.h      |   7 ++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/entry-armv.S     | 151 +----------------------------------
 arch/arm/kernel/entry-header.S   | 164 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/fiq.c            | 112 +++++++++++++++++++++++++-
 arch/arm/kernel/kgdb_fiq.c       | 127 ++++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S | 130 +++++++++++++++++++++++++++++++
 10 files changed, 574 insertions(+), 152 deletions(-)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

--
1.9.3

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v7 1/4] arm: fiq: Add callbacks to manage FIQ routings
  2014-06-30  8:53           ` Daniel Thompson
@ 2014-06-30  8:53             ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-30  8:53 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
virq into a FIQ virq. This is too inflexible for multi-platform kernels
and makes runtime error checking impossible.

We solve this by introducing a flexible mapping that allows interrupt
controllers that support FIQ to register those mappings. This, in turn,
makes it much possible for drivers in DT kernels to install FIQ handlers
without knowing anything about the interrupt controller.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h |   8 ++++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..ed44528 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -16,8 +16,14 @@
 #ifndef __ASM_FIQ_H
 #define __ASM_FIQ_H
 
+#include <linux/irq.h>
 #include <asm/ptrace.h>
 
+struct fiq_chip {
+	void (*fiq_enable)(struct irq_data *data);
+	void (*fiq_disable)(struct irq_data *data);
+};
+
 struct fiq_handler {
 	struct fiq_handler *next;
 	/* Name
@@ -38,6 +44,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern bool has_fiq(int fiq);
+extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..5d831cf 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,9 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
+#include <linux/radix-tree.h>
+#include <linux/slab.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -52,7 +55,15 @@
 		(unsigned)&vector_fiq_offset;		\
 	})
 
+struct fiq_data {
+	struct fiq_chip *fiq_chip;
+	struct irq_data *irq_data;
+};
+
 static unsigned long no_fiq_insn;
+static int fiq_start = -1;
+static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
+static DEFINE_MUTEX(fiq_data_mutex);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -127,18 +138,65 @@ void release_fiq(struct fiq_handler *f)
 	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
 }
 
-static int fiq_start;
+static struct fiq_data *lookup_fiq_data(int fiq)
+{
+	struct fiq_data *data;
+
+	rcu_read_lock();
+	data = radix_tree_lookup(&fiq_data_tree, fiq);
+	rcu_read_unlock();
+
+	return data;
+}
 
 void enable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_enable)
+			data->fiq_chip->fiq_enable(data->irq_data);
+		enable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	enable_irq(fiq + fiq_start);
 }
 
 void disable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_disable)
+			data->fiq_chip->fiq_disable(data->irq_data);
+		disable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	disable_irq(fiq + fiq_start);
 }
 
+bool has_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data)
+		return true;
+
+	if (fiq_start == -1)
+		return false;
+
+	return fiq >= fiq_start;
+}
+EXPORT_SYMBOL(has_fiq);
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -147,9 +205,50 @@ EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
 
+/*
+ * Add a mapping from a Linux irq to the fiq data.
+ */
+void fiq_register_mapping(int irq, struct fiq_chip *chip)
+{
+	struct fiq_data *fiq_data = NULL;
+	int res;
+
+	/* fiq_register_mapping can't be mixed with init_FIQ */
+	BUG_ON(fiq_start != -1);
+
+	fiq_data = kmalloc(sizeof(*fiq_data), GFP_KERNEL);
+	if (!fiq_data)
+		goto err;
+
+	fiq_data->fiq_chip = chip;
+	fiq_data->irq_data = irq_get_irq_data(irq);
+	BUG_ON(!fiq_data->irq_data);
+
+	mutex_lock(&fiq_data_mutex);
+	res = radix_tree_insert(&fiq_data_tree, irq, fiq_data);
+	mutex_unlock(&fiq_data_mutex);
+	if (res)
+		goto err;
+
+	return;
+
+err:
+	kfree(fiq_data);
+	pr_err("fiq: Cannot register mapping %d\n", irq);
+}
+
+/*
+ * Set the offset between normal IRQs and their FIQ shadows.
+ */
 void __init init_FIQ(int start)
 {
+	fiq_start = start;
+}
+
+static int __init init_default_fiq_handler(void)
+{
 	unsigned offset = FIQ_OFFSET;
 	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
-	fiq_start = start;
+	return 0;
 }
+pure_initcall(init_default_fiq_handler);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v7 1/4] arm: fiq: Add callbacks to manage FIQ routings
@ 2014-06-30  8:53             ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-30  8:53 UTC (permalink / raw)
  To: linux-arm-kernel

Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
virq into a FIQ virq. This is too inflexible for multi-platform kernels
and makes runtime error checking impossible.

We solve this by introducing a flexible mapping that allows interrupt
controllers that support FIQ to register those mappings. This, in turn,
makes it much possible for drivers in DT kernels to install FIQ handlers
without knowing anything about the interrupt controller.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h |   8 ++++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..ed44528 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -16,8 +16,14 @@
 #ifndef __ASM_FIQ_H
 #define __ASM_FIQ_H
 
+#include <linux/irq.h>
 #include <asm/ptrace.h>
 
+struct fiq_chip {
+	void (*fiq_enable)(struct irq_data *data);
+	void (*fiq_disable)(struct irq_data *data);
+};
+
 struct fiq_handler {
 	struct fiq_handler *next;
 	/* Name
@@ -38,6 +44,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern bool has_fiq(int fiq);
+extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..5d831cf 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,9 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
+#include <linux/radix-tree.h>
+#include <linux/slab.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -52,7 +55,15 @@
 		(unsigned)&vector_fiq_offset;		\
 	})
 
+struct fiq_data {
+	struct fiq_chip *fiq_chip;
+	struct irq_data *irq_data;
+};
+
 static unsigned long no_fiq_insn;
+static int fiq_start = -1;
+static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
+static DEFINE_MUTEX(fiq_data_mutex);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -127,18 +138,65 @@ void release_fiq(struct fiq_handler *f)
 	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
 }
 
-static int fiq_start;
+static struct fiq_data *lookup_fiq_data(int fiq)
+{
+	struct fiq_data *data;
+
+	rcu_read_lock();
+	data = radix_tree_lookup(&fiq_data_tree, fiq);
+	rcu_read_unlock();
+
+	return data;
+}
 
 void enable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_enable)
+			data->fiq_chip->fiq_enable(data->irq_data);
+		enable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	enable_irq(fiq + fiq_start);
 }
 
 void disable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_disable)
+			data->fiq_chip->fiq_disable(data->irq_data);
+		disable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	disable_irq(fiq + fiq_start);
 }
 
+bool has_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data)
+		return true;
+
+	if (fiq_start == -1)
+		return false;
+
+	return fiq >= fiq_start;
+}
+EXPORT_SYMBOL(has_fiq);
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -147,9 +205,50 @@ EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
 
+/*
+ * Add a mapping from a Linux irq to the fiq data.
+ */
+void fiq_register_mapping(int irq, struct fiq_chip *chip)
+{
+	struct fiq_data *fiq_data = NULL;
+	int res;
+
+	/* fiq_register_mapping can't be mixed with init_FIQ */
+	BUG_ON(fiq_start != -1);
+
+	fiq_data = kmalloc(sizeof(*fiq_data), GFP_KERNEL);
+	if (!fiq_data)
+		goto err;
+
+	fiq_data->fiq_chip = chip;
+	fiq_data->irq_data = irq_get_irq_data(irq);
+	BUG_ON(!fiq_data->irq_data);
+
+	mutex_lock(&fiq_data_mutex);
+	res = radix_tree_insert(&fiq_data_tree, irq, fiq_data);
+	mutex_unlock(&fiq_data_mutex);
+	if (res)
+		goto err;
+
+	return;
+
+err:
+	kfree(fiq_data);
+	pr_err("fiq: Cannot register mapping %d\n", irq);
+}
+
+/*
+ * Set the offset between normal IRQs and their FIQ shadows.
+ */
 void __init init_FIQ(int start)
 {
+	fiq_start = start;
+}
+
+static int __init init_default_fiq_handler(void)
+{
 	unsigned offset = FIQ_OFFSET;
 	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
-	fiq_start = start;
+	return 0;
 }
+pure_initcall(init_default_fiq_handler);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v7 2/4] arm: fiq: Allow EOI to be communicated to the intc
  2014-06-30  8:53           ` Daniel Thompson
@ 2014-06-30  8:53             ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-30  8:53 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

Modern ARM systems require an EOI to be sent to the interrupt controller
on completion of both IRQ and FIQ. The FIQ code currently does not provide
any API to perform this. This patch provides this API, implemented by
adding a callback to the fiq_chip structure.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h | 6 ++++++
 arch/arm/kernel/fiq.c      | 9 +++++++++
 2 files changed, 15 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index ed44528..fbc0df1 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -22,6 +22,11 @@
 struct fiq_chip {
 	void (*fiq_enable)(struct irq_data *data);
 	void (*fiq_disable)(struct irq_data *data);
+
+	/* .fiq_eoi() will be called from the FIQ handler. For this
+	 * reason it must not use spin locks (or any other locks).
+	 */
+	void (*fiq_eoi)(struct irq_data *data);
 };
 
 struct fiq_handler {
@@ -44,6 +49,7 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 5d831cf..c35fd6a 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -183,6 +183,15 @@ void disable_fiq(int fiq)
 	disable_irq(fiq + fiq_start);
 }
 
+void eoi_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_eoi)
+		data->fiq_chip->fiq_eoi(data->irq_data);
+}
+EXPORT_SYMBOL(eoi_fiq);
+
 bool has_fiq(int fiq)
 {
 	struct fiq_data *data = lookup_fiq_data(fiq);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v7 2/4] arm: fiq: Allow EOI to be communicated to the intc
@ 2014-06-30  8:53             ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-30  8:53 UTC (permalink / raw)
  To: linux-arm-kernel

Modern ARM systems require an EOI to be sent to the interrupt controller
on completion of both IRQ and FIQ. The FIQ code currently does not provide
any API to perform this. This patch provides this API, implemented by
adding a callback to the fiq_chip structure.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h | 6 ++++++
 arch/arm/kernel/fiq.c      | 9 +++++++++
 2 files changed, 15 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index ed44528..fbc0df1 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -22,6 +22,11 @@
 struct fiq_chip {
 	void (*fiq_enable)(struct irq_data *data);
 	void (*fiq_disable)(struct irq_data *data);
+
+	/* .fiq_eoi() will be called from the FIQ handler. For this
+	 * reason it must not use spin locks (or any other locks).
+	 */
+	void (*fiq_eoi)(struct irq_data *data);
 };
 
 struct fiq_handler {
@@ -44,6 +49,7 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 5d831cf..c35fd6a 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -183,6 +183,15 @@ void disable_fiq(int fiq)
 	disable_irq(fiq + fiq_start);
 }
 
+void eoi_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_eoi)
+		data->fiq_chip->fiq_eoi(data->irq_data);
+}
+EXPORT_SYMBOL(eoi_fiq);
+
 bool has_fiq(int fiq)
 {
 	struct fiq_data *data = lookup_fiq_data(fiq);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v7 3/4] ARM: Move some macros from entry-armv to entry-header
  2014-06-30  8:53           ` Daniel Thompson
@ 2014-06-30  8:53             ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-30  8:53 UTC (permalink / raw)
  To: Russell King
  Cc: Anton Vorontsov, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Colin Cross, kernel-team,
	Rob Herring, Linus Walleij, Ben Dooks, Catalin Marinas,
	Dave Martin, Fabio Estevam, Frederic Weisbecker, Nicolas Pitre,
	Daniel Thompson

From: Anton Vorontsov <anton.vorontsov@linaro.org>

Just move the macros into header file as we would want to use them for
KGDB FIQ entry code.

The following macros were moved:

 - svc_entry
 - usr_entry
 - kuser_cmpxchg_check
 - vector_stub

To make kuser_cmpxchg_check actually work across different files, we
also have to make kuser_cmpxchg64_fixup global.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
---
 arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
 arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 150 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 52a949a..4172cd6 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -140,53 +140,6 @@ ENDPROC(__und_invalid)
  * SVC mode handlers
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
-#define SPFIX(code...) code
-#else
-#define SPFIX(code...)
-#endif
-
-	.macro	svc_entry, stack_hole=0
- UNWIND(.fnstart		)
- UNWIND(.save {r0 - pc}		)
-	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
-#ifdef CONFIG_THUMB2_KERNEL
- SPFIX(	str	r0, [sp]	)	@ temporarily saved
- SPFIX(	mov	r0, sp		)
- SPFIX(	tst	r0, #4		)	@ test original stack alignment
- SPFIX(	ldr	r0, [sp]	)	@ restored
-#else
- SPFIX(	tst	sp, #4		)
-#endif
- SPFIX(	subeq	sp, sp, #4	)
-	stmia	sp, {r1 - r12}
-
-	ldmia	r0, {r3 - r5}
-	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""      ""       ""
-	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
- SPFIX(	addeq	r2, r2, #4	)
-	str	r3, [sp, #-4]!		@ save the "real" r0 copied
-					@ from the exception stack
-
-	mov	r3, lr
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r2 - sp_svc
-	@  r3 - lr_svc
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	stmia	r7, {r2 - r6}
-
-#ifdef CONFIG_TRACE_IRQFLAGS
-	bl	trace_hardirqs_off
-#endif
-	.endm
-
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -306,73 +259,8 @@ ENDPROC(__pabt_svc)
 
 /*
  * User mode handlers
- *
- * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0, .LCcralign
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
 	.align	5
 __dabt_usr:
 	usr_entry
@@ -823,6 +711,7 @@ __kuser_cmpxchg64:				@ 0xffff0f60
 	ldmfd	sp!, {r4, r5, r6, pc}
 
 	.text
+	.global kuser_cmpxchg64_fixup
 kuser_cmpxchg64_fixup:
 	@ Called from kuser_cmpxchg_fixup.
 	@ r4 = address of interrupted insn (must be preserved).
@@ -964,44 +853,6 @@ __kuser_helper_end:
  * SP points to a minimal amount of processor-private memory, the address
  * of which is copied into r0 for the mode specific abort handler.
  */
-	.macro	vector_stub, name, mode, correction=0
-	.align	5
-
-vector_\name:
-	.if \correction
-	sub	lr, lr, #\correction
-	.endif
-
-	@
-	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
-	@ (parent CPSR)
-	@
-	stmia	sp, {r0, lr}		@ save r0, lr
-	mrs	lr, spsr
-	str	lr, [sp, #8]		@ save spsr
-
-	@
-	@ Prepare for SVC32 mode.  IRQs remain disabled.
-	@
-	mrs	r0, cpsr
-	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
-	msr	spsr_cxsf, r0
-
-	@
-	@ the branch table must immediately follow this code
-	@
-	and	lr, lr, #0x0f
- THUMB(	adr	r0, 1f			)
- THUMB(	ldr	lr, [r0, lr, lsl #2]	)
-	mov	r0, sp
- ARM(	ldr	lr, [pc, lr, lsl #2]	)
-	movs	pc, lr			@ branch to handler in SVC mode
-ENDPROC(vector_\name)
-
-	.align	2
-	@ handler addresses follow this label
-1:
-	.endm
 
 	.section .stubs, "ax", %progbits
 __stubs_start:
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 5d702f8..eb2c426 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -356,3 +356,167 @@ scno	.req	r7		@ syscall number
 tbl	.req	r8		@ syscall table pointer
 why	.req	r8		@ Linux syscall (!= 0)
 tsk	.req	r9		@ current thread_info
+
+/*
+ * SVC mode handler macros
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define SPFIX(code...) code
+#else
+#define SPFIX(code...)
+#endif
+
+	.macro	svc_entry, stack_hole=0
+ UNWIND(.fnstart		)
+ UNWIND(.save {r0 - pc}		)
+	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+#ifdef CONFIG_THUMB2_KERNEL
+ SPFIX(	str	r0, [sp]	)	@ temporarily saved
+ SPFIX(	mov	r0, sp		)
+ SPFIX(	tst	r0, #4		)	@ test original stack alignment
+ SPFIX(	ldr	r0, [sp]	)	@ restored
+#else
+ SPFIX(	tst	sp, #4		)
+#endif
+ SPFIX(	subeq	sp, sp, #4	)
+	stmia	sp, {r1 - r12}
+
+	ldmia	r0, {r3 - r5}
+	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""      ""       ""
+	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+ SPFIX(	addeq	r2, r2, #4	)
+	str	r3, [sp, #-4]!		@ save the "real" r0 copied
+					@ from the exception stack
+
+	mov	r3, lr
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r2 - sp_svc
+	@  r3 - lr_svc
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	stmia	r7, {r2 - r6}
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_off
+#endif
+	.endm
+
+/*
+ * User mode handler macros
+ *
+ * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0, .LCcralign
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+/*
+ * Vector stubs macro.
+ */
+	.macro	vector_stub, name, mode, correction=0
+	.align	5
+
+vector_\name:
+	.if \correction
+	sub	lr, lr, #\correction
+	.endif
+
+	@
+	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
+	@ (parent CPSR)
+	@
+	stmia	sp, {r0, lr}		@ save r0, lr
+	mrs	lr, spsr
+	str	lr, [sp, #8]		@ save spsr
+
+	@
+	@ Prepare for SVC32 mode.  IRQs remain disabled.
+	@
+	mrs	r0, cpsr
+	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
+	msr	spsr_cxsf, r0
+
+	@
+	@ the branch table must immediately follow this code
+	@
+	and	lr, lr, #0x0f
+ THUMB(	adr	r0, 1f			)
+ THUMB(	ldr	lr, [r0, lr, lsl #2]	)
+	mov	r0, sp
+ ARM(	ldr	lr, [pc, lr, lsl #2]	)
+	movs	pc, lr			@ branch to handler in SVC mode
+ENDPROC(vector_\name)
+
+	.align	2
+	@ handler addresses follow this label
+1:
+	.endm
+
+
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v7 3/4] ARM: Move some macros from entry-armv to entry-header
@ 2014-06-30  8:53             ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-30  8:53 UTC (permalink / raw)
  To: linux-arm-kernel

From: Anton Vorontsov <anton.vorontsov@linaro.org>

Just move the macros into header file as we would want to use them for
KGDB FIQ entry code.

The following macros were moved:

 - svc_entry
 - usr_entry
 - kuser_cmpxchg_check
 - vector_stub

To make kuser_cmpxchg_check actually work across different files, we
also have to make kuser_cmpxchg64_fixup global.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
---
 arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
 arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 150 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 52a949a..4172cd6 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -140,53 +140,6 @@ ENDPROC(__und_invalid)
  * SVC mode handlers
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
-#define SPFIX(code...) code
-#else
-#define SPFIX(code...)
-#endif
-
-	.macro	svc_entry, stack_hole=0
- UNWIND(.fnstart		)
- UNWIND(.save {r0 - pc}		)
-	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
-#ifdef CONFIG_THUMB2_KERNEL
- SPFIX(	str	r0, [sp]	)	@ temporarily saved
- SPFIX(	mov	r0, sp		)
- SPFIX(	tst	r0, #4		)	@ test original stack alignment
- SPFIX(	ldr	r0, [sp]	)	@ restored
-#else
- SPFIX(	tst	sp, #4		)
-#endif
- SPFIX(	subeq	sp, sp, #4	)
-	stmia	sp, {r1 - r12}
-
-	ldmia	r0, {r3 - r5}
-	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""      ""       ""
-	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
- SPFIX(	addeq	r2, r2, #4	)
-	str	r3, [sp, #-4]!		@ save the "real" r0 copied
-					@ from the exception stack
-
-	mov	r3, lr
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r2 - sp_svc
-	@  r3 - lr_svc
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	stmia	r7, {r2 - r6}
-
-#ifdef CONFIG_TRACE_IRQFLAGS
-	bl	trace_hardirqs_off
-#endif
-	.endm
-
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -306,73 +259,8 @@ ENDPROC(__pabt_svc)
 
 /*
  * User mode handlers
- *
- * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0, .LCcralign
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
 	.align	5
 __dabt_usr:
 	usr_entry
@@ -823,6 +711,7 @@ __kuser_cmpxchg64:				@ 0xffff0f60
 	ldmfd	sp!, {r4, r5, r6, pc}
 
 	.text
+	.global kuser_cmpxchg64_fixup
 kuser_cmpxchg64_fixup:
 	@ Called from kuser_cmpxchg_fixup.
 	@ r4 = address of interrupted insn (must be preserved).
@@ -964,44 +853,6 @@ __kuser_helper_end:
  * SP points to a minimal amount of processor-private memory, the address
  * of which is copied into r0 for the mode specific abort handler.
  */
-	.macro	vector_stub, name, mode, correction=0
-	.align	5
-
-vector_\name:
-	.if \correction
-	sub	lr, lr, #\correction
-	.endif
-
-	@
-	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
-	@ (parent CPSR)
-	@
-	stmia	sp, {r0, lr}		@ save r0, lr
-	mrs	lr, spsr
-	str	lr, [sp, #8]		@ save spsr
-
-	@
-	@ Prepare for SVC32 mode.  IRQs remain disabled.
-	@
-	mrs	r0, cpsr
-	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
-	msr	spsr_cxsf, r0
-
-	@
-	@ the branch table must immediately follow this code
-	@
-	and	lr, lr, #0x0f
- THUMB(	adr	r0, 1f			)
- THUMB(	ldr	lr, [r0, lr, lsl #2]	)
-	mov	r0, sp
- ARM(	ldr	lr, [pc, lr, lsl #2]	)
-	movs	pc, lr			@ branch to handler in SVC mode
-ENDPROC(vector_\name)
-
-	.align	2
-	@ handler addresses follow this label
-1:
-	.endm
 
 	.section .stubs, "ax", %progbits
 __stubs_start:
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 5d702f8..eb2c426 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -356,3 +356,167 @@ scno	.req	r7		@ syscall number
 tbl	.req	r8		@ syscall table pointer
 why	.req	r8		@ Linux syscall (!= 0)
 tsk	.req	r9		@ current thread_info
+
+/*
+ * SVC mode handler macros
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define SPFIX(code...) code
+#else
+#define SPFIX(code...)
+#endif
+
+	.macro	svc_entry, stack_hole=0
+ UNWIND(.fnstart		)
+ UNWIND(.save {r0 - pc}		)
+	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+#ifdef CONFIG_THUMB2_KERNEL
+ SPFIX(	str	r0, [sp]	)	@ temporarily saved
+ SPFIX(	mov	r0, sp		)
+ SPFIX(	tst	r0, #4		)	@ test original stack alignment
+ SPFIX(	ldr	r0, [sp]	)	@ restored
+#else
+ SPFIX(	tst	sp, #4		)
+#endif
+ SPFIX(	subeq	sp, sp, #4	)
+	stmia	sp, {r1 - r12}
+
+	ldmia	r0, {r3 - r5}
+	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""      ""       ""
+	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+ SPFIX(	addeq	r2, r2, #4	)
+	str	r3, [sp, #-4]!		@ save the "real" r0 copied
+					@ from the exception stack
+
+	mov	r3, lr
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r2 - sp_svc
+	@  r3 - lr_svc
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	stmia	r7, {r2 - r6}
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_off
+#endif
+	.endm
+
+/*
+ * User mode handler macros
+ *
+ * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0, .LCcralign
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+/*
+ * Vector stubs macro.
+ */
+	.macro	vector_stub, name, mode, correction=0
+	.align	5
+
+vector_\name:
+	.if \correction
+	sub	lr, lr, #\correction
+	.endif
+
+	@
+	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
+	@ (parent CPSR)
+	@
+	stmia	sp, {r0, lr}		@ save r0, lr
+	mrs	lr, spsr
+	str	lr, [sp, #8]		@ save spsr
+
+	@
+	@ Prepare for SVC32 mode.  IRQs remain disabled.
+	@
+	mrs	r0, cpsr
+	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
+	msr	spsr_cxsf, r0
+
+	@
+	@ the branch table must immediately follow this code
+	@
+	and	lr, lr, #0x0f
+ THUMB(	adr	r0, 1f			)
+ THUMB(	ldr	lr, [r0, lr, lsl #2]	)
+	mov	r0, sp
+ ARM(	ldr	lr, [pc, lr, lsl #2]	)
+	movs	pc, lr			@ branch to handler in SVC mode
+ENDPROC(vector_\name)
+
+	.align	2
+	@ handler addresses follow this label
+1:
+	.endm
+
+
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v7 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
  2014-06-30  8:53           ` Daniel Thompson
@ 2014-06-30  8:53             ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-30  8:53 UTC (permalink / raw)
  To: Russell King
  Cc: Anton Vorontsov, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Colin Cross, kernel-team,
	Rob Herring, Linus Walleij, Ben Dooks, Catalin Marinas,
	Dave Martin, Fabio Estevam, Frederic Weisbecker, Nicolas Pitre,
	Daniel Thompson

From: Anton Vorontsov <anton.vorontsov@linaro.org>

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

By default KGDB FIQ is disabled in runtime, but can be enabled with
kgdb_fiq.enable=1 kernel command line option.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
[daniel.thompson@linaro.org: Added __fiq_abt, rewrote stack init]
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben.dooks@codethink.co.uk>
Cc: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 ++++++
 arch/arm/include/asm/kgdb.h      |   7 +++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/kgdb_fiq.c       | 127 ++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S | 130 +++++++++++++++++++++++++++++++++++++++
 6 files changed, 285 insertions(+)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 245058b..f385b27 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -297,6 +297,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -346,6 +347,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 26536f7..c7342b6 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,24 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be
+	  enabled with kgdb_fiq.enable=1 kernel command line option.
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..5de21f01 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,11 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern char kgdb_fiq_handler;
+extern char kgdb_fiq_handler_end;
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs);
+extern int kgdb_register_fiq(unsigned int fiq);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 38ddd9f..30ee8f3 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -68,6 +68,7 @@ endif
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
 obj-$(CONFIG_ARM_THUMBEE)	+= thumbee.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
+obj-$(CONFIG_KGDB_FIQ)		+= kgdb_fiq_entry.o kgdb_fiq.o
 obj-$(CONFIG_ARM_UNWIND)	+= unwind.o
 obj-$(CONFIG_HAVE_TCM)		+= tcm.o
 obj-$(CONFIG_OF)		+= devtree.o
diff --git a/arch/arm/kernel/kgdb_fiq.c b/arch/arm/kernel/kgdb_fiq.c
new file mode 100644
index 0000000..99d23cc
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq.c
@@ -0,0 +1,127 @@
+/*
+ * KGDB FIQ
+ *
+ * Copyright 2010 Google, Inc.
+ *		  Arve Hjønnevåg <arve@android.com>
+ *		  Colin Cross <ccross@android.com>
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/hardirq.h>
+#include <linux/atomic.h>
+#include <linux/kdb.h>
+#include <linux/kgdb.h>
+#include <asm/fiq.h>
+#include <asm/exception.h>
+
+static int kgdb_fiq_enabled;
+module_param_named(enable, kgdb_fiq_enabled, int, 0600);
+MODULE_PARM_DESC(enable, "set to 1 to enable FIQ KGDB");
+
+static unsigned int kgdb_fiq;
+
+struct fiq_stack {
+	u32 fiq[3];
+} ____cacheline_aligned;
+
+static struct fiq_stack stacks[NR_CPUS];
+
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs)
+{
+	if (kgdb_nmi_poll_knock()) {
+		nmi_enter();
+		kgdb_handle_exception(1, 0, 0, regs);
+		nmi_exit();
+	}
+
+	eoi_fiq(kgdb_fiq);
+}
+
+static struct fiq_handler kgdb_fiq_desc = {
+	.name = "kgdb",
+};
+
+static long kgdb_fiq_setup_stack(void *info)
+{
+	struct pt_regs regs;
+
+	regs.ARM_sp = (unsigned long) stacks[smp_processor_id()].fiq;
+	set_fiq_regs(&regs);
+
+	return 0;
+}
+
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * This function manages NMIs that usually cause KGDB to enter. That is, not
+ * all NMIs should be enabled or disabled, but only those that issue
+ * kgdb_handle_exception().
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	static atomic_t cnt;
+	int ret;
+
+	ret = atomic_add_return(on ? 1 : -1, &cnt);
+
+	/*
+	 * There should be only one instance that calls this function
+	 * in "enable, disable" order. All other users must call
+	 * disable first, then enable. If not, something is wrong.
+	 */
+	if (WARN_ON(ret > 1 && on))
+		return;
+
+	if (ret > 0)
+		enable_fiq(kgdb_fiq);
+	else
+		disable_fiq(kgdb_fiq);
+}
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	int err;
+	int cpu;
+
+	if (!kgdb_fiq_enabled)
+		return -ENODEV;
+
+	if (!has_fiq(fiq)) {
+		pr_warn(
+		    "%s: Cannot register %u (no FIQ with this number)\n",
+		    __func__, fiq);
+		return -ENODEV;
+	}
+
+	kgdb_fiq = fiq;
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	for_each_possible_cpu(cpu)
+		work_on_cpu(cpu, kgdb_fiq_setup_stack, NULL);
+
+	set_fiq_handler(&kgdb_fiq_handler,
+			&kgdb_fiq_handler_end - &kgdb_fiq_handler);
+
+	arch_kgdb_ops.enable_nmi = kgdb_fiq_enable_nmi;
+	return 0;
+}
diff --git a/arch/arm/kernel/kgdb_fiq_entry.S b/arch/arm/kernel/kgdb_fiq_entry.S
new file mode 100644
index 0000000..50499c0
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq_entry.S
@@ -0,0 +1,130 @@
+/*
+ * KGDB FIQ entry
+ *
+ * Copyright 1996,1997,1998 Russell King.
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+#include <asm/unwind.h>
+#include "entry-header.S"
+
+	.text
+
+@ This is needed for usr_entry/alignment_trap
+.LCcralign:
+	.long	cr_alignment
+.LCdohandle:
+	.long	kgdb_fiq_do_handle
+
+	.macro	fiq_handler
+	ldr	r1, =.LCdohandle
+	mov	r0, sp
+	adr	lr, BSYM(9997f)
+	ldr	pc, [r1]
+9997:
+	.endm
+
+/*
+ * svc_exit_via_fiq
+ *
+ * This macro acts in a similar manner to svc_exit but switches to FIQ
+ * mode to restore the final part of the register state.
+ *
+ * We cannot use the normal svc_exit procedure because that would
+ * clobber spsr_svc (FIQ could be delivered during the first few instructions
+ * of vector_swi meaning its contents have not been saved anywhere).
+ */
+	.macro  svc_exit_via_fiq, rpsr
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+	tst	\rpsr, #PSR_I_BIT
+	bleq	trace_hardirqs_on
+#endif
+
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+	.endm
+
+	.align	5
+__fiq_svc:
+	svc_entry
+	fiq_handler
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+	.ltorg
+
+	.align 5
+__fiq_abt:
+	svc_entry
+
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	r0, lr		@ Save lr_abt
+	mrs	r1, spsr	@ Save spsr_abt, abort is now safe
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+	push	{r0 - r1}
+
+	fiq_handler
+
+	pop	{r0 - r1}
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	lr, r0		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r1	@ Restore spsr_abt
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+	.ltorg
+
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+	.ltorg
+
+	.global kgdb_fiq_handler
+kgdb_fiq_handler:
+
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
+
+	.global kgdb_fiq_handler_end
+kgdb_fiq_handler_end:
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v7 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
@ 2014-06-30  8:53             ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-30  8:53 UTC (permalink / raw)
  To: linux-arm-kernel

From: Anton Vorontsov <anton.vorontsov@linaro.org>

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

By default KGDB FIQ is disabled in runtime, but can be enabled with
kgdb_fiq.enable=1 kernel command line option.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
[daniel.thompson at linaro.org: Added __fiq_abt, rewrote stack init]
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben.dooks@codethink.co.uk>
Cc: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 ++++++
 arch/arm/include/asm/kgdb.h      |   7 +++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/kgdb_fiq.c       | 127 ++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S | 130 +++++++++++++++++++++++++++++++++++++++
 6 files changed, 285 insertions(+)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 245058b..f385b27 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -297,6 +297,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -346,6 +347,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 26536f7..c7342b6 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,24 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be
+	  enabled with kgdb_fiq.enable=1 kernel command line option.
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..5de21f01 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,11 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern char kgdb_fiq_handler;
+extern char kgdb_fiq_handler_end;
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs);
+extern int kgdb_register_fiq(unsigned int fiq);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 38ddd9f..30ee8f3 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -68,6 +68,7 @@ endif
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
 obj-$(CONFIG_ARM_THUMBEE)	+= thumbee.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
+obj-$(CONFIG_KGDB_FIQ)		+= kgdb_fiq_entry.o kgdb_fiq.o
 obj-$(CONFIG_ARM_UNWIND)	+= unwind.o
 obj-$(CONFIG_HAVE_TCM)		+= tcm.o
 obj-$(CONFIG_OF)		+= devtree.o
diff --git a/arch/arm/kernel/kgdb_fiq.c b/arch/arm/kernel/kgdb_fiq.c
new file mode 100644
index 0000000..99d23cc
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq.c
@@ -0,0 +1,127 @@
+/*
+ * KGDB FIQ
+ *
+ * Copyright 2010 Google, Inc.
+ *		  Arve Hj?nnev?g <arve@android.com>
+ *		  Colin Cross <ccross@android.com>
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/hardirq.h>
+#include <linux/atomic.h>
+#include <linux/kdb.h>
+#include <linux/kgdb.h>
+#include <asm/fiq.h>
+#include <asm/exception.h>
+
+static int kgdb_fiq_enabled;
+module_param_named(enable, kgdb_fiq_enabled, int, 0600);
+MODULE_PARM_DESC(enable, "set to 1 to enable FIQ KGDB");
+
+static unsigned int kgdb_fiq;
+
+struct fiq_stack {
+	u32 fiq[3];
+} ____cacheline_aligned;
+
+static struct fiq_stack stacks[NR_CPUS];
+
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs)
+{
+	if (kgdb_nmi_poll_knock()) {
+		nmi_enter();
+		kgdb_handle_exception(1, 0, 0, regs);
+		nmi_exit();
+	}
+
+	eoi_fiq(kgdb_fiq);
+}
+
+static struct fiq_handler kgdb_fiq_desc = {
+	.name = "kgdb",
+};
+
+static long kgdb_fiq_setup_stack(void *info)
+{
+	struct pt_regs regs;
+
+	regs.ARM_sp = (unsigned long) stacks[smp_processor_id()].fiq;
+	set_fiq_regs(&regs);
+
+	return 0;
+}
+
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * This function manages NMIs that usually cause KGDB to enter. That is, not
+ * all NMIs should be enabled or disabled, but only those that issue
+ * kgdb_handle_exception().
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	static atomic_t cnt;
+	int ret;
+
+	ret = atomic_add_return(on ? 1 : -1, &cnt);
+
+	/*
+	 * There should be only one instance that calls this function
+	 * in "enable, disable" order. All other users must call
+	 * disable first, then enable. If not, something is wrong.
+	 */
+	if (WARN_ON(ret > 1 && on))
+		return;
+
+	if (ret > 0)
+		enable_fiq(kgdb_fiq);
+	else
+		disable_fiq(kgdb_fiq);
+}
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	int err;
+	int cpu;
+
+	if (!kgdb_fiq_enabled)
+		return -ENODEV;
+
+	if (!has_fiq(fiq)) {
+		pr_warn(
+		    "%s: Cannot register %u (no FIQ with this number)\n",
+		    __func__, fiq);
+		return -ENODEV;
+	}
+
+	kgdb_fiq = fiq;
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	for_each_possible_cpu(cpu)
+		work_on_cpu(cpu, kgdb_fiq_setup_stack, NULL);
+
+	set_fiq_handler(&kgdb_fiq_handler,
+			&kgdb_fiq_handler_end - &kgdb_fiq_handler);
+
+	arch_kgdb_ops.enable_nmi = kgdb_fiq_enable_nmi;
+	return 0;
+}
diff --git a/arch/arm/kernel/kgdb_fiq_entry.S b/arch/arm/kernel/kgdb_fiq_entry.S
new file mode 100644
index 0000000..50499c0
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq_entry.S
@@ -0,0 +1,130 @@
+/*
+ * KGDB FIQ entry
+ *
+ * Copyright 1996,1997,1998 Russell King.
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+#include <asm/unwind.h>
+#include "entry-header.S"
+
+	.text
+
+@ This is needed for usr_entry/alignment_trap
+.LCcralign:
+	.long	cr_alignment
+.LCdohandle:
+	.long	kgdb_fiq_do_handle
+
+	.macro	fiq_handler
+	ldr	r1, =.LCdohandle
+	mov	r0, sp
+	adr	lr, BSYM(9997f)
+	ldr	pc, [r1]
+9997:
+	.endm
+
+/*
+ * svc_exit_via_fiq
+ *
+ * This macro acts in a similar manner to svc_exit but switches to FIQ
+ * mode to restore the final part of the register state.
+ *
+ * We cannot use the normal svc_exit procedure because that would
+ * clobber spsr_svc (FIQ could be delivered during the first few instructions
+ * of vector_swi meaning its contents have not been saved anywhere).
+ */
+	.macro  svc_exit_via_fiq, rpsr
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+	tst	\rpsr, #PSR_I_BIT
+	bleq	trace_hardirqs_on
+#endif
+
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+	.endm
+
+	.align	5
+__fiq_svc:
+	svc_entry
+	fiq_handler
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+	.ltorg
+
+	.align 5
+__fiq_abt:
+	svc_entry
+
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	r0, lr		@ Save lr_abt
+	mrs	r1, spsr	@ Save spsr_abt, abort is now safe
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+	push	{r0 - r1}
+
+	fiq_handler
+
+	pop	{r0 - r1}
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	lr, r0		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r1	@ Restore spsr_abt
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+	.ltorg
+
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+	.ltorg
+
+	.global kgdb_fiq_handler
+kgdb_fiq_handler:
+
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
+
+	.global kgdb_fiq_handler_end
+kgdb_fiq_handler_end:
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* Re: [PATCH v6 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
  2014-06-26  9:54               ` Daniel Thompson
@ 2014-06-30 13:54                 ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-30 13:54 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Anton Vorontsov, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Colin Cross, kernel-team,
	Rob Herring, Linus Walleij, Ben Dooks, Catalin Marinas,
	Dave Martin, Fabio Estevam, Frederic Weisbecker, Nicolas Pitre

On 26/06/14 10:54, Daniel Thompson wrote:
>> Also bear in mind that svc_entry calls trace_hardirqs_off - is this
>> appropriate and safe for the FIQ to call?
> 
> I personally think it appropriate and it looked safe on the lockdep side
> of things. However I will look a bit deeper at this since I don't
> remember how far I chased things back.

I've reviewed as far as I can.

Regarding safety I can't find anything much to upset the FIQ handler. I
think it might occasionally trigger the trace code's recursion avoidance
causing the trace event to be dropped but that's about it.

I admit I came very close to removing the trace_hardirqs calls from the
FIQ code but in the end I've left it. The hardirqs *are* off during FIQ
execution.


>>> +	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
>>
>> Here we switch to FIQ mode.  What about the PSR_A_BIT which prevents
>> imprecise aborts on ARMv6+ ?
>>
>> Nevertheless, I think it's safe because the A bit will be set by the
>> CPU when taking the FIQ exception, and it should remain set since
>> cpsr_c won't modify it.
> 
> Agreed.
> 
> Note that while double checking this I realized that this code will drop
> the value of PSR_ISETSTATE (T bit) that the vector_stub macro set for
> us. I'll fix this.

I was wrong about this. CPSR T bit is part of execution state can cannot
be modified by msr.


> I've picked out the following actions from the above:
> 
> 1. Wrap a save and restore lr_abt and spsr_abt around the FIQ handler

Done.

> 2. Add a paired up trace_hardirqs_on() (and review more deeply).

Done.

> 3. Add comments explaining hazards w.r.t. data abort,

Done.

> 4. Correctly manage T bit during transition back to FIQ mode.

Not applicable.

> Do I miss anything?

I hope not!


Daniel.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v6 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
@ 2014-06-30 13:54                 ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-06-30 13:54 UTC (permalink / raw)
  To: linux-arm-kernel

On 26/06/14 10:54, Daniel Thompson wrote:
>> Also bear in mind that svc_entry calls trace_hardirqs_off - is this
>> appropriate and safe for the FIQ to call?
> 
> I personally think it appropriate and it looked safe on the lockdep side
> of things. However I will look a bit deeper at this since I don't
> remember how far I chased things back.

I've reviewed as far as I can.

Regarding safety I can't find anything much to upset the FIQ handler. I
think it might occasionally trigger the trace code's recursion avoidance
causing the trace event to be dropped but that's about it.

I admit I came very close to removing the trace_hardirqs calls from the
FIQ code but in the end I've left it. The hardirqs *are* off during FIQ
execution.


>>> +	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
>>
>> Here we switch to FIQ mode.  What about the PSR_A_BIT which prevents
>> imprecise aborts on ARMv6+ ?
>>
>> Nevertheless, I think it's safe because the A bit will be set by the
>> CPU when taking the FIQ exception, and it should remain set since
>> cpsr_c won't modify it.
> 
> Agreed.
> 
> Note that while double checking this I realized that this code will drop
> the value of PSR_ISETSTATE (T bit) that the vector_stub macro set for
> us. I'll fix this.

I was wrong about this. CPSR T bit is part of execution state can cannot
be modified by msr.


> I've picked out the following actions from the above:
> 
> 1. Wrap a save and restore lr_abt and spsr_abt around the FIQ handler

Done.

> 2. Add a paired up trace_hardirqs_on() (and review more deeply).

Done.

> 3. Add comments explaining hazards w.r.t. data abort,

Done.

> 4. Correctly manage T bit during transition back to FIQ mode.

Not applicable.

> Do I miss anything?

I hope not!


Daniel.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v8 0/4] arm: KGDB NMI/FIQ support
  2014-06-30  8:53           ` Daniel Thompson
@ 2014-07-10  8:03             ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-10  8:03 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

This patchset makes it possible to use kgdb's NMI infrastructure on ARM
platforms.

The patches have been previously circulated as part of a large patchset
mixing together ARM architecture code and driver changes
(http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901 ). This
patchset is dramatically cut down to include only the arch/arm code. The
driver code (irqchip and tty/serial) will follow when/if the arch code
is accepted.

The first two patches modify the FIQ infrastructure to allow interrupt
controller drivers to register callbacks (the fiq_chip structure) to
manage FIQ routings and to ACK and EOI the FIQ. This makes it possible
to use FIQ in multi-platform kernels and with recent ARM interrupt
controllers.

The remaining two patches provide architecture support for KGDB's NMI
feature (and rely upon the preceding changes to the FIQ code).

Tested on qemu (versatile), STiH416 (B2020 board) and Freescale i.MX6
quad (wandboard).

Changes since v7:

- Introduced ack_fiq() to complement eoi_fiq(). Without this it is
  not possible to meet the GIC specification (previous versions worked
  when tested but are unpredictable according to the specification).
  ack_fiq() also makes is possible for drivers for devices with multiple
  interrupt lines to discover the interrupt source correctly.

Changes since v6:

- Corrected off-by-one comparison in has_fiq() (Nicolas Pitre)
- Rewrote the FIQ stack initialization (Nicolas Pitre). This fixes a
  serious data corruption bug due to bad stack mismanagement.
- Introduced __fiq_abt to ensure lr_abt and spsr_abt are saved and
  restored if we fast-interrupt an abort (Russell King).
- Significantly improved the commenting of the exception handlers.
- Added a call to trace_hardirqs_on() if we clear the I bit as we
  exit the exception handler.

Changes since v5:

- Separated anything not strictly impacting arch/arm.
- Fixed a spurious add/remove of code within the series (there was
  broken code in intermediate patches)

For previous changes see:
http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901

Anton Vorontsov (2):
  ARM: Move some macros from entry-armv to entry-header
  ARM: Add KGDB/KDB FIQ debugger generic code

Daniel Thompson (2):
  arm: fiq: Add callbacks to manage FIQ routings
  arm: fiq: Allow ACK and EOI to be passed to the intc

 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 +++++
 arch/arm/include/asm/fiq.h       |  17 ++++
 arch/arm/include/asm/kgdb.h      |   7 ++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/entry-armv.S     | 151 +----------------------------------
 arch/arm/kernel/entry-header.S   | 164 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/fiq.c            | 122 ++++++++++++++++++++++++++++-
 arch/arm/kernel/kgdb_fiq.c       | 132 +++++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S | 130 +++++++++++++++++++++++++++++++
 10 files changed, 592 insertions(+), 152 deletions(-)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

--
1.9.3


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v8 0/4] arm: KGDB NMI/FIQ support
@ 2014-07-10  8:03             ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-10  8:03 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset makes it possible to use kgdb's NMI infrastructure on ARM
platforms.

The patches have been previously circulated as part of a large patchset
mixing together ARM architecture code and driver changes
(http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901 ). This
patchset is dramatically cut down to include only the arch/arm code. The
driver code (irqchip and tty/serial) will follow when/if the arch code
is accepted.

The first two patches modify the FIQ infrastructure to allow interrupt
controller drivers to register callbacks (the fiq_chip structure) to
manage FIQ routings and to ACK and EOI the FIQ. This makes it possible
to use FIQ in multi-platform kernels and with recent ARM interrupt
controllers.

The remaining two patches provide architecture support for KGDB's NMI
feature (and rely upon the preceding changes to the FIQ code).

Tested on qemu (versatile), STiH416 (B2020 board) and Freescale i.MX6
quad (wandboard).

Changes since v7:

- Introduced ack_fiq() to complement eoi_fiq(). Without this it is
  not possible to meet the GIC specification (previous versions worked
  when tested but are unpredictable according to the specification).
  ack_fiq() also makes is possible for drivers for devices with multiple
  interrupt lines to discover the interrupt source correctly.

Changes since v6:

- Corrected off-by-one comparison in has_fiq() (Nicolas Pitre)
- Rewrote the FIQ stack initialization (Nicolas Pitre). This fixes a
  serious data corruption bug due to bad stack mismanagement.
- Introduced __fiq_abt to ensure lr_abt and spsr_abt are saved and
  restored if we fast-interrupt an abort (Russell King).
- Significantly improved the commenting of the exception handlers.
- Added a call to trace_hardirqs_on() if we clear the I bit as we
  exit the exception handler.

Changes since v5:

- Separated anything not strictly impacting arch/arm.
- Fixed a spurious add/remove of code within the series (there was
  broken code in intermediate patches)

For previous changes see:
http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901

Anton Vorontsov (2):
  ARM: Move some macros from entry-armv to entry-header
  ARM: Add KGDB/KDB FIQ debugger generic code

Daniel Thompson (2):
  arm: fiq: Add callbacks to manage FIQ routings
  arm: fiq: Allow ACK and EOI to be passed to the intc

 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 +++++
 arch/arm/include/asm/fiq.h       |  17 ++++
 arch/arm/include/asm/kgdb.h      |   7 ++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/entry-armv.S     | 151 +----------------------------------
 arch/arm/kernel/entry-header.S   | 164 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/fiq.c            | 122 ++++++++++++++++++++++++++++-
 arch/arm/kernel/kgdb_fiq.c       | 132 +++++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S | 130 +++++++++++++++++++++++++++++++
 10 files changed, 592 insertions(+), 152 deletions(-)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

--
1.9.3

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v8 1/4] arm: fiq: Add callbacks to manage FIQ routings
  2014-07-10  8:03             ` Daniel Thompson
@ 2014-07-10  8:03               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-10  8:03 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
virq into a FIQ virq. This is too inflexible for multi-platform kernels
and makes runtime error checking impossible.

We solve this by introducing a flexible mapping that allows interrupt
controllers that support FIQ to register those mappings. This, in turn,
makes it much possible for drivers in DT kernels to install FIQ handlers
without knowing anything about the interrupt controller.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h |   8 ++++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..ed44528 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -16,8 +16,14 @@
 #ifndef __ASM_FIQ_H
 #define __ASM_FIQ_H
 
+#include <linux/irq.h>
 #include <asm/ptrace.h>
 
+struct fiq_chip {
+	void (*fiq_enable)(struct irq_data *data);
+	void (*fiq_disable)(struct irq_data *data);
+};
+
 struct fiq_handler {
 	struct fiq_handler *next;
 	/* Name
@@ -38,6 +44,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern bool has_fiq(int fiq);
+extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..5d831cf 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,9 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
+#include <linux/radix-tree.h>
+#include <linux/slab.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -52,7 +55,15 @@
 		(unsigned)&vector_fiq_offset;		\
 	})
 
+struct fiq_data {
+	struct fiq_chip *fiq_chip;
+	struct irq_data *irq_data;
+};
+
 static unsigned long no_fiq_insn;
+static int fiq_start = -1;
+static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
+static DEFINE_MUTEX(fiq_data_mutex);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -127,18 +138,65 @@ void release_fiq(struct fiq_handler *f)
 	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
 }
 
-static int fiq_start;
+static struct fiq_data *lookup_fiq_data(int fiq)
+{
+	struct fiq_data *data;
+
+	rcu_read_lock();
+	data = radix_tree_lookup(&fiq_data_tree, fiq);
+	rcu_read_unlock();
+
+	return data;
+}
 
 void enable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_enable)
+			data->fiq_chip->fiq_enable(data->irq_data);
+		enable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	enable_irq(fiq + fiq_start);
 }
 
 void disable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_disable)
+			data->fiq_chip->fiq_disable(data->irq_data);
+		disable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	disable_irq(fiq + fiq_start);
 }
 
+bool has_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data)
+		return true;
+
+	if (fiq_start == -1)
+		return false;
+
+	return fiq >= fiq_start;
+}
+EXPORT_SYMBOL(has_fiq);
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -147,9 +205,50 @@ EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
 
+/*
+ * Add a mapping from a Linux irq to the fiq data.
+ */
+void fiq_register_mapping(int irq, struct fiq_chip *chip)
+{
+	struct fiq_data *fiq_data = NULL;
+	int res;
+
+	/* fiq_register_mapping can't be mixed with init_FIQ */
+	BUG_ON(fiq_start != -1);
+
+	fiq_data = kmalloc(sizeof(*fiq_data), GFP_KERNEL);
+	if (!fiq_data)
+		goto err;
+
+	fiq_data->fiq_chip = chip;
+	fiq_data->irq_data = irq_get_irq_data(irq);
+	BUG_ON(!fiq_data->irq_data);
+
+	mutex_lock(&fiq_data_mutex);
+	res = radix_tree_insert(&fiq_data_tree, irq, fiq_data);
+	mutex_unlock(&fiq_data_mutex);
+	if (res)
+		goto err;
+
+	return;
+
+err:
+	kfree(fiq_data);
+	pr_err("fiq: Cannot register mapping %d\n", irq);
+}
+
+/*
+ * Set the offset between normal IRQs and their FIQ shadows.
+ */
 void __init init_FIQ(int start)
 {
+	fiq_start = start;
+}
+
+static int __init init_default_fiq_handler(void)
+{
 	unsigned offset = FIQ_OFFSET;
 	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
-	fiq_start = start;
+	return 0;
 }
+pure_initcall(init_default_fiq_handler);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v8 1/4] arm: fiq: Add callbacks to manage FIQ routings
@ 2014-07-10  8:03               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-10  8:03 UTC (permalink / raw)
  To: linux-arm-kernel

Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
virq into a FIQ virq. This is too inflexible for multi-platform kernels
and makes runtime error checking impossible.

We solve this by introducing a flexible mapping that allows interrupt
controllers that support FIQ to register those mappings. This, in turn,
makes it much possible for drivers in DT kernels to install FIQ handlers
without knowing anything about the interrupt controller.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h |   8 ++++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..ed44528 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -16,8 +16,14 @@
 #ifndef __ASM_FIQ_H
 #define __ASM_FIQ_H
 
+#include <linux/irq.h>
 #include <asm/ptrace.h>
 
+struct fiq_chip {
+	void (*fiq_enable)(struct irq_data *data);
+	void (*fiq_disable)(struct irq_data *data);
+};
+
 struct fiq_handler {
 	struct fiq_handler *next;
 	/* Name
@@ -38,6 +44,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern bool has_fiq(int fiq);
+extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..5d831cf 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,9 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
+#include <linux/radix-tree.h>
+#include <linux/slab.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -52,7 +55,15 @@
 		(unsigned)&vector_fiq_offset;		\
 	})
 
+struct fiq_data {
+	struct fiq_chip *fiq_chip;
+	struct irq_data *irq_data;
+};
+
 static unsigned long no_fiq_insn;
+static int fiq_start = -1;
+static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
+static DEFINE_MUTEX(fiq_data_mutex);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -127,18 +138,65 @@ void release_fiq(struct fiq_handler *f)
 	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
 }
 
-static int fiq_start;
+static struct fiq_data *lookup_fiq_data(int fiq)
+{
+	struct fiq_data *data;
+
+	rcu_read_lock();
+	data = radix_tree_lookup(&fiq_data_tree, fiq);
+	rcu_read_unlock();
+
+	return data;
+}
 
 void enable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_enable)
+			data->fiq_chip->fiq_enable(data->irq_data);
+		enable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	enable_irq(fiq + fiq_start);
 }
 
 void disable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_disable)
+			data->fiq_chip->fiq_disable(data->irq_data);
+		disable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	disable_irq(fiq + fiq_start);
 }
 
+bool has_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data)
+		return true;
+
+	if (fiq_start == -1)
+		return false;
+
+	return fiq >= fiq_start;
+}
+EXPORT_SYMBOL(has_fiq);
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -147,9 +205,50 @@ EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
 
+/*
+ * Add a mapping from a Linux irq to the fiq data.
+ */
+void fiq_register_mapping(int irq, struct fiq_chip *chip)
+{
+	struct fiq_data *fiq_data = NULL;
+	int res;
+
+	/* fiq_register_mapping can't be mixed with init_FIQ */
+	BUG_ON(fiq_start != -1);
+
+	fiq_data = kmalloc(sizeof(*fiq_data), GFP_KERNEL);
+	if (!fiq_data)
+		goto err;
+
+	fiq_data->fiq_chip = chip;
+	fiq_data->irq_data = irq_get_irq_data(irq);
+	BUG_ON(!fiq_data->irq_data);
+
+	mutex_lock(&fiq_data_mutex);
+	res = radix_tree_insert(&fiq_data_tree, irq, fiq_data);
+	mutex_unlock(&fiq_data_mutex);
+	if (res)
+		goto err;
+
+	return;
+
+err:
+	kfree(fiq_data);
+	pr_err("fiq: Cannot register mapping %d\n", irq);
+}
+
+/*
+ * Set the offset between normal IRQs and their FIQ shadows.
+ */
 void __init init_FIQ(int start)
 {
+	fiq_start = start;
+}
+
+static int __init init_default_fiq_handler(void)
+{
 	unsigned offset = FIQ_OFFSET;
 	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
-	fiq_start = start;
+	return 0;
 }
+pure_initcall(init_default_fiq_handler);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v8 2/4] arm: fiq: Allow ACK and EOI to be passed to the intc
  2014-07-10  8:03             ` Daniel Thompson
@ 2014-07-10  8:03               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-10  8:03 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

Modern ARM interrupt controllers require an ACK as interrupts are taken
and an EOI on completion. The FIQ code currently does not provide any
API to perform this.

This patch provides this API, implemented by adding two callbacks to the
fiq_chip structure.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h |  9 +++++++++
 arch/arm/kernel/fiq.c      | 19 +++++++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index ed44528..a25c952 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -22,6 +22,13 @@
 struct fiq_chip {
 	void (*fiq_enable)(struct irq_data *data);
 	void (*fiq_disable)(struct irq_data *data);
+
+	/* .fiq_ack() and .fiq_eoi() will be called from the FIQ
+	 * handler. For this reason they must not use spin locks (or any
+	 * other locks).
+	 */
+	int (*fiq_ack)(struct irq_data *data);
+	void (*fiq_eoi)(struct irq_data *data);
 };
 
 struct fiq_handler {
@@ -44,6 +51,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern int ack_fiq(int fiq);
+extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 5d831cf..3ccaa8c 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -183,6 +183,25 @@ void disable_fiq(int fiq)
 	disable_irq(fiq + fiq_start);
 }
 
+int ack_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_ack)
+		return data->fiq_chip->fiq_ack(data->irq_data);
+
+	return fiq;
+}
+
+void eoi_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_eoi)
+		data->fiq_chip->fiq_eoi(data->irq_data);
+}
+EXPORT_SYMBOL(eoi_fiq);
+
 bool has_fiq(int fiq)
 {
 	struct fiq_data *data = lookup_fiq_data(fiq);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v8 2/4] arm: fiq: Allow ACK and EOI to be passed to the intc
@ 2014-07-10  8:03               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-10  8:03 UTC (permalink / raw)
  To: linux-arm-kernel

Modern ARM interrupt controllers require an ACK as interrupts are taken
and an EOI on completion. The FIQ code currently does not provide any
API to perform this.

This patch provides this API, implemented by adding two callbacks to the
fiq_chip structure.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h |  9 +++++++++
 arch/arm/kernel/fiq.c      | 19 +++++++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index ed44528..a25c952 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -22,6 +22,13 @@
 struct fiq_chip {
 	void (*fiq_enable)(struct irq_data *data);
 	void (*fiq_disable)(struct irq_data *data);
+
+	/* .fiq_ack() and .fiq_eoi() will be called from the FIQ
+	 * handler. For this reason they must not use spin locks (or any
+	 * other locks).
+	 */
+	int (*fiq_ack)(struct irq_data *data);
+	void (*fiq_eoi)(struct irq_data *data);
 };
 
 struct fiq_handler {
@@ -44,6 +51,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern int ack_fiq(int fiq);
+extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 5d831cf..3ccaa8c 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -183,6 +183,25 @@ void disable_fiq(int fiq)
 	disable_irq(fiq + fiq_start);
 }
 
+int ack_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_ack)
+		return data->fiq_chip->fiq_ack(data->irq_data);
+
+	return fiq;
+}
+
+void eoi_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_eoi)
+		data->fiq_chip->fiq_eoi(data->irq_data);
+}
+EXPORT_SYMBOL(eoi_fiq);
+
 bool has_fiq(int fiq)
 {
 	struct fiq_data *data = lookup_fiq_data(fiq);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v8 3/4] ARM: Move some macros from entry-armv to entry-header
  2014-07-10  8:03             ` Daniel Thompson
@ 2014-07-10  8:03               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-10  8:03 UTC (permalink / raw)
  To: Russell King
  Cc: Anton Vorontsov, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Colin Cross, kernel-team,
	Rob Herring, Linus Walleij, Ben Dooks, Catalin Marinas,
	Dave Martin, Fabio Estevam, Frederic Weisbecker, Nicolas Pitre,
	Daniel Thompson

From: Anton Vorontsov <anton.vorontsov@linaro.org>

Just move the macros into header file as we would want to use them for
KGDB FIQ entry code.

The following macros were moved:

 - svc_entry
 - usr_entry
 - kuser_cmpxchg_check
 - vector_stub

To make kuser_cmpxchg_check actually work across different files, we
also have to make kuser_cmpxchg64_fixup global.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
---
 arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
 arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 150 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 52a949a..4172cd6 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -140,53 +140,6 @@ ENDPROC(__und_invalid)
  * SVC mode handlers
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
-#define SPFIX(code...) code
-#else
-#define SPFIX(code...)
-#endif
-
-	.macro	svc_entry, stack_hole=0
- UNWIND(.fnstart		)
- UNWIND(.save {r0 - pc}		)
-	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
-#ifdef CONFIG_THUMB2_KERNEL
- SPFIX(	str	r0, [sp]	)	@ temporarily saved
- SPFIX(	mov	r0, sp		)
- SPFIX(	tst	r0, #4		)	@ test original stack alignment
- SPFIX(	ldr	r0, [sp]	)	@ restored
-#else
- SPFIX(	tst	sp, #4		)
-#endif
- SPFIX(	subeq	sp, sp, #4	)
-	stmia	sp, {r1 - r12}
-
-	ldmia	r0, {r3 - r5}
-	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""      ""       ""
-	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
- SPFIX(	addeq	r2, r2, #4	)
-	str	r3, [sp, #-4]!		@ save the "real" r0 copied
-					@ from the exception stack
-
-	mov	r3, lr
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r2 - sp_svc
-	@  r3 - lr_svc
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	stmia	r7, {r2 - r6}
-
-#ifdef CONFIG_TRACE_IRQFLAGS
-	bl	trace_hardirqs_off
-#endif
-	.endm
-
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -306,73 +259,8 @@ ENDPROC(__pabt_svc)
 
 /*
  * User mode handlers
- *
- * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0, .LCcralign
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
 	.align	5
 __dabt_usr:
 	usr_entry
@@ -823,6 +711,7 @@ __kuser_cmpxchg64:				@ 0xffff0f60
 	ldmfd	sp!, {r4, r5, r6, pc}
 
 	.text
+	.global kuser_cmpxchg64_fixup
 kuser_cmpxchg64_fixup:
 	@ Called from kuser_cmpxchg_fixup.
 	@ r4 = address of interrupted insn (must be preserved).
@@ -964,44 +853,6 @@ __kuser_helper_end:
  * SP points to a minimal amount of processor-private memory, the address
  * of which is copied into r0 for the mode specific abort handler.
  */
-	.macro	vector_stub, name, mode, correction=0
-	.align	5
-
-vector_\name:
-	.if \correction
-	sub	lr, lr, #\correction
-	.endif
-
-	@
-	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
-	@ (parent CPSR)
-	@
-	stmia	sp, {r0, lr}		@ save r0, lr
-	mrs	lr, spsr
-	str	lr, [sp, #8]		@ save spsr
-
-	@
-	@ Prepare for SVC32 mode.  IRQs remain disabled.
-	@
-	mrs	r0, cpsr
-	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
-	msr	spsr_cxsf, r0
-
-	@
-	@ the branch table must immediately follow this code
-	@
-	and	lr, lr, #0x0f
- THUMB(	adr	r0, 1f			)
- THUMB(	ldr	lr, [r0, lr, lsl #2]	)
-	mov	r0, sp
- ARM(	ldr	lr, [pc, lr, lsl #2]	)
-	movs	pc, lr			@ branch to handler in SVC mode
-ENDPROC(vector_\name)
-
-	.align	2
-	@ handler addresses follow this label
-1:
-	.endm
 
 	.section .stubs, "ax", %progbits
 __stubs_start:
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 5d702f8..eb2c426 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -356,3 +356,167 @@ scno	.req	r7		@ syscall number
 tbl	.req	r8		@ syscall table pointer
 why	.req	r8		@ Linux syscall (!= 0)
 tsk	.req	r9		@ current thread_info
+
+/*
+ * SVC mode handler macros
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define SPFIX(code...) code
+#else
+#define SPFIX(code...)
+#endif
+
+	.macro	svc_entry, stack_hole=0
+ UNWIND(.fnstart		)
+ UNWIND(.save {r0 - pc}		)
+	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+#ifdef CONFIG_THUMB2_KERNEL
+ SPFIX(	str	r0, [sp]	)	@ temporarily saved
+ SPFIX(	mov	r0, sp		)
+ SPFIX(	tst	r0, #4		)	@ test original stack alignment
+ SPFIX(	ldr	r0, [sp]	)	@ restored
+#else
+ SPFIX(	tst	sp, #4		)
+#endif
+ SPFIX(	subeq	sp, sp, #4	)
+	stmia	sp, {r1 - r12}
+
+	ldmia	r0, {r3 - r5}
+	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""      ""       ""
+	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+ SPFIX(	addeq	r2, r2, #4	)
+	str	r3, [sp, #-4]!		@ save the "real" r0 copied
+					@ from the exception stack
+
+	mov	r3, lr
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r2 - sp_svc
+	@  r3 - lr_svc
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	stmia	r7, {r2 - r6}
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_off
+#endif
+	.endm
+
+/*
+ * User mode handler macros
+ *
+ * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0, .LCcralign
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+/*
+ * Vector stubs macro.
+ */
+	.macro	vector_stub, name, mode, correction=0
+	.align	5
+
+vector_\name:
+	.if \correction
+	sub	lr, lr, #\correction
+	.endif
+
+	@
+	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
+	@ (parent CPSR)
+	@
+	stmia	sp, {r0, lr}		@ save r0, lr
+	mrs	lr, spsr
+	str	lr, [sp, #8]		@ save spsr
+
+	@
+	@ Prepare for SVC32 mode.  IRQs remain disabled.
+	@
+	mrs	r0, cpsr
+	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
+	msr	spsr_cxsf, r0
+
+	@
+	@ the branch table must immediately follow this code
+	@
+	and	lr, lr, #0x0f
+ THUMB(	adr	r0, 1f			)
+ THUMB(	ldr	lr, [r0, lr, lsl #2]	)
+	mov	r0, sp
+ ARM(	ldr	lr, [pc, lr, lsl #2]	)
+	movs	pc, lr			@ branch to handler in SVC mode
+ENDPROC(vector_\name)
+
+	.align	2
+	@ handler addresses follow this label
+1:
+	.endm
+
+
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v8 3/4] ARM: Move some macros from entry-armv to entry-header
@ 2014-07-10  8:03               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-10  8:03 UTC (permalink / raw)
  To: linux-arm-kernel

From: Anton Vorontsov <anton.vorontsov@linaro.org>

Just move the macros into header file as we would want to use them for
KGDB FIQ entry code.

The following macros were moved:

 - svc_entry
 - usr_entry
 - kuser_cmpxchg_check
 - vector_stub

To make kuser_cmpxchg_check actually work across different files, we
also have to make kuser_cmpxchg64_fixup global.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
---
 arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
 arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 150 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 52a949a..4172cd6 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -140,53 +140,6 @@ ENDPROC(__und_invalid)
  * SVC mode handlers
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
-#define SPFIX(code...) code
-#else
-#define SPFIX(code...)
-#endif
-
-	.macro	svc_entry, stack_hole=0
- UNWIND(.fnstart		)
- UNWIND(.save {r0 - pc}		)
-	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
-#ifdef CONFIG_THUMB2_KERNEL
- SPFIX(	str	r0, [sp]	)	@ temporarily saved
- SPFIX(	mov	r0, sp		)
- SPFIX(	tst	r0, #4		)	@ test original stack alignment
- SPFIX(	ldr	r0, [sp]	)	@ restored
-#else
- SPFIX(	tst	sp, #4		)
-#endif
- SPFIX(	subeq	sp, sp, #4	)
-	stmia	sp, {r1 - r12}
-
-	ldmia	r0, {r3 - r5}
-	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""      ""       ""
-	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
- SPFIX(	addeq	r2, r2, #4	)
-	str	r3, [sp, #-4]!		@ save the "real" r0 copied
-					@ from the exception stack
-
-	mov	r3, lr
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r2 - sp_svc
-	@  r3 - lr_svc
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	stmia	r7, {r2 - r6}
-
-#ifdef CONFIG_TRACE_IRQFLAGS
-	bl	trace_hardirqs_off
-#endif
-	.endm
-
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -306,73 +259,8 @@ ENDPROC(__pabt_svc)
 
 /*
  * User mode handlers
- *
- * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
  */
 
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
-#error "sizeof(struct pt_regs) must be a multiple of 8"
-#endif
-
-	.macro	usr_entry
- UNWIND(.fnstart	)
- UNWIND(.cantunwind	)	@ don't unwind the user space
-	sub	sp, sp, #S_FRAME_SIZE
- ARM(	stmib	sp, {r1 - r12}	)
- THUMB(	stmia	sp, {r0 - r12}	)
-
-	ldmia	r0, {r3 - r5}
-	add	r0, sp, #S_PC		@ here for interlock avoidance
-	mov	r6, #-1			@  ""  ""     ""        ""
-
-	str	r3, [sp]		@ save the "real" r0 copied
-					@ from the exception stack
-
-	@
-	@ We are now ready to fill in the remaining blanks on the stack:
-	@
-	@  r4 - lr_<exception>, already fixed up for correct return/restart
-	@  r5 - spsr_<exception>
-	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
-	@
-	@ Also, separately save sp_usr and lr_usr
-	@
-	stmia	r0, {r4 - r6}
- ARM(	stmdb	r0, {sp, lr}^			)
- THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
-
-	@
-	@ Enable the alignment trap while in kernel mode
-	@
-	alignment_trap r0, .LCcralign
-
-	@
-	@ Clear FP to mark the first stack frame
-	@
-	zero_fp
-
-#ifdef CONFIG_IRQSOFF_TRACER
-	bl	trace_hardirqs_off
-#endif
-	ct_user_exit save = 0
-	.endm
-
-	.macro	kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
-    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
-	@ Make sure our user space atomic helper is restarted
-	@ if it was interrupted in a critical region.  Here we
-	@ perform a quick test inline since it should be false
-	@ 99.9999% of the time.  The rest is done out of line.
-	cmp	r4, #TASK_SIZE
-	blhs	kuser_cmpxchg64_fixup
-#endif
-#endif
-	.endm
-
 	.align	5
 __dabt_usr:
 	usr_entry
@@ -823,6 +711,7 @@ __kuser_cmpxchg64:				@ 0xffff0f60
 	ldmfd	sp!, {r4, r5, r6, pc}
 
 	.text
+	.global kuser_cmpxchg64_fixup
 kuser_cmpxchg64_fixup:
 	@ Called from kuser_cmpxchg_fixup.
 	@ r4 = address of interrupted insn (must be preserved).
@@ -964,44 +853,6 @@ __kuser_helper_end:
  * SP points to a minimal amount of processor-private memory, the address
  * of which is copied into r0 for the mode specific abort handler.
  */
-	.macro	vector_stub, name, mode, correction=0
-	.align	5
-
-vector_\name:
-	.if \correction
-	sub	lr, lr, #\correction
-	.endif
-
-	@
-	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
-	@ (parent CPSR)
-	@
-	stmia	sp, {r0, lr}		@ save r0, lr
-	mrs	lr, spsr
-	str	lr, [sp, #8]		@ save spsr
-
-	@
-	@ Prepare for SVC32 mode.  IRQs remain disabled.
-	@
-	mrs	r0, cpsr
-	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
-	msr	spsr_cxsf, r0
-
-	@
-	@ the branch table must immediately follow this code
-	@
-	and	lr, lr, #0x0f
- THUMB(	adr	r0, 1f			)
- THUMB(	ldr	lr, [r0, lr, lsl #2]	)
-	mov	r0, sp
- ARM(	ldr	lr, [pc, lr, lsl #2]	)
-	movs	pc, lr			@ branch to handler in SVC mode
-ENDPROC(vector_\name)
-
-	.align	2
-	@ handler addresses follow this label
-1:
-	.endm
 
 	.section .stubs, "ax", %progbits
 __stubs_start:
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 5d702f8..eb2c426 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -356,3 +356,167 @@ scno	.req	r7		@ syscall number
 tbl	.req	r8		@ syscall table pointer
 why	.req	r8		@ Linux syscall (!= 0)
 tsk	.req	r9		@ current thread_info
+
+/*
+ * SVC mode handler macros
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define SPFIX(code...) code
+#else
+#define SPFIX(code...)
+#endif
+
+	.macro	svc_entry, stack_hole=0
+ UNWIND(.fnstart		)
+ UNWIND(.save {r0 - pc}		)
+	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+#ifdef CONFIG_THUMB2_KERNEL
+ SPFIX(	str	r0, [sp]	)	@ temporarily saved
+ SPFIX(	mov	r0, sp		)
+ SPFIX(	tst	r0, #4		)	@ test original stack alignment
+ SPFIX(	ldr	r0, [sp]	)	@ restored
+#else
+ SPFIX(	tst	sp, #4		)
+#endif
+ SPFIX(	subeq	sp, sp, #4	)
+	stmia	sp, {r1 - r12}
+
+	ldmia	r0, {r3 - r5}
+	add	r7, sp, #S_SP - 4	@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""      ""       ""
+	add	r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+ SPFIX(	addeq	r2, r2, #4	)
+	str	r3, [sp, #-4]!		@ save the "real" r0 copied
+					@ from the exception stack
+
+	mov	r3, lr
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r2 - sp_svc
+	@  r3 - lr_svc
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	stmia	r7, {r2 - r6}
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_off
+#endif
+	.endm
+
+/*
+ * User mode handler macros
+ *
+ * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
+ */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
+	.macro	usr_entry
+ UNWIND(.fnstart	)
+ UNWIND(.cantunwind	)	@ don't unwind the user space
+	sub	sp, sp, #S_FRAME_SIZE
+ ARM(	stmib	sp, {r1 - r12}	)
+ THUMB(	stmia	sp, {r0 - r12}	)
+
+	ldmia	r0, {r3 - r5}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r6, #-1			@  ""  ""     ""        ""
+
+	str	r3, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
+	@
+	@ We are now ready to fill in the remaining blanks on the stack:
+	@
+	@  r4 - lr_<exception>, already fixed up for correct return/restart
+	@  r5 - spsr_<exception>
+	@  r6 - orig_r0 (see pt_regs definition in ptrace.h)
+	@
+	@ Also, separately save sp_usr and lr_usr
+	@
+	stmia	r0, {r4 - r6}
+ ARM(	stmdb	r0, {sp, lr}^			)
+ THUMB(	store_user_sp_lr r0, r1, S_SP - S_PC	)
+
+	@
+	@ Enable the alignment trap while in kernel mode
+	@
+	alignment_trap r0, .LCcralign
+
+	@
+	@ Clear FP to mark the first stack frame
+	@
+	zero_fp
+
+#ifdef CONFIG_IRQSOFF_TRACER
+	bl	trace_hardirqs_off
+#endif
+	ct_user_exit save = 0
+	.endm
+
+	.macro	kuser_cmpxchg_check
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+	@ Make sure our user space atomic helper is restarted
+	@ if it was interrupted in a critical region.  Here we
+	@ perform a quick test inline since it should be false
+	@ 99.9999% of the time.  The rest is done out of line.
+	cmp	r4, #TASK_SIZE
+	blhs	kuser_cmpxchg64_fixup
+#endif
+#endif
+	.endm
+
+/*
+ * Vector stubs macro.
+ */
+	.macro	vector_stub, name, mode, correction=0
+	.align	5
+
+vector_\name:
+	.if \correction
+	sub	lr, lr, #\correction
+	.endif
+
+	@
+	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
+	@ (parent CPSR)
+	@
+	stmia	sp, {r0, lr}		@ save r0, lr
+	mrs	lr, spsr
+	str	lr, [sp, #8]		@ save spsr
+
+	@
+	@ Prepare for SVC32 mode.  IRQs remain disabled.
+	@
+	mrs	r0, cpsr
+	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
+	msr	spsr_cxsf, r0
+
+	@
+	@ the branch table must immediately follow this code
+	@
+	and	lr, lr, #0x0f
+ THUMB(	adr	r0, 1f			)
+ THUMB(	ldr	lr, [r0, lr, lsl #2]	)
+	mov	r0, sp
+ ARM(	ldr	lr, [pc, lr, lsl #2]	)
+	movs	pc, lr			@ branch to handler in SVC mode
+ENDPROC(vector_\name)
+
+	.align	2
+	@ handler addresses follow this label
+1:
+	.endm
+
+
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v8 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
  2014-07-10  8:03             ` Daniel Thompson
@ 2014-07-10  8:03               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-10  8:03 UTC (permalink / raw)
  To: Russell King
  Cc: Anton Vorontsov, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Colin Cross, kernel-team,
	Rob Herring, Linus Walleij, Ben Dooks, Catalin Marinas,
	Dave Martin, Fabio Estevam, Frederic Weisbecker, Nicolas Pitre,
	Daniel Thompson

From: Anton Vorontsov <anton.vorontsov@linaro.org>

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

By default KGDB FIQ is disabled in runtime, but can be enabled with
kgdb_fiq.enable=1 kernel command line option.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
[daniel.thompson@linaro.org: Added __fiq_abt, rewrote stack init]
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben.dooks@codethink.co.uk>
Cc: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 ++++++
 arch/arm/include/asm/kgdb.h      |   7 +++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/kgdb_fiq.c       | 132 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S | 130 ++++++++++++++++++++++++++++++++++++++
 6 files changed, 290 insertions(+)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 245058b..f385b27 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -297,6 +297,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -346,6 +347,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 26536f7..c7342b6 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,24 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be
+	  enabled with kgdb_fiq.enable=1 kernel command line option.
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..5de21f01 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,11 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern char kgdb_fiq_handler;
+extern char kgdb_fiq_handler_end;
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs);
+extern int kgdb_register_fiq(unsigned int fiq);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 38ddd9f..30ee8f3 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -68,6 +68,7 @@ endif
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
 obj-$(CONFIG_ARM_THUMBEE)	+= thumbee.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
+obj-$(CONFIG_KGDB_FIQ)		+= kgdb_fiq_entry.o kgdb_fiq.o
 obj-$(CONFIG_ARM_UNWIND)	+= unwind.o
 obj-$(CONFIG_HAVE_TCM)		+= tcm.o
 obj-$(CONFIG_OF)		+= devtree.o
diff --git a/arch/arm/kernel/kgdb_fiq.c b/arch/arm/kernel/kgdb_fiq.c
new file mode 100644
index 0000000..a894dde
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq.c
@@ -0,0 +1,132 @@
+/*
+ * KGDB FIQ
+ *
+ * Copyright 2010 Google, Inc.
+ *		  Arve Hjønnevåg <arve@android.com>
+ *		  Colin Cross <ccross@android.com>
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/hardirq.h>
+#include <linux/atomic.h>
+#include <linux/kdb.h>
+#include <linux/kgdb.h>
+#include <asm/fiq.h>
+#include <asm/exception.h>
+
+static int kgdb_fiq_enabled;
+module_param_named(enable, kgdb_fiq_enabled, int, 0600);
+MODULE_PARM_DESC(enable, "set to 1 to enable FIQ KGDB");
+
+static unsigned int kgdb_fiq;
+
+struct fiq_stack {
+	u32 fiq[3];
+} ____cacheline_aligned;
+
+static struct fiq_stack stacks[NR_CPUS];
+
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs)
+{
+	int actual;
+
+	nmi_enter();
+	actual = ack_fiq(kgdb_fiq);
+	WARN_ON(actual != kgdb_fiq);
+
+	/* there's no harm in doing this regardless of the above WARN_ON() */
+	if (kgdb_nmi_poll_knock())
+		kgdb_handle_exception(1, 0, 0, regs);
+
+	eoi_fiq(actual);
+	nmi_exit();
+}
+
+static struct fiq_handler kgdb_fiq_desc = {
+	.name = "kgdb",
+};
+
+static long kgdb_fiq_setup_stack(void *info)
+{
+	struct pt_regs regs;
+
+	regs.ARM_sp = (unsigned long) stacks[smp_processor_id()].fiq;
+	set_fiq_regs(&regs);
+
+	return 0;
+}
+
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * This function manages NMIs that usually cause KGDB to enter. That is, not
+ * all NMIs should be enabled or disabled, but only those that issue
+ * kgdb_handle_exception().
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	static atomic_t cnt;
+	int ret;
+
+	ret = atomic_add_return(on ? 1 : -1, &cnt);
+
+	/*
+	 * There should be only one instance that calls this function
+	 * in "enable, disable" order. All other users must call
+	 * disable first, then enable. If not, something is wrong.
+	 */
+	if (WARN_ON(ret > 1 && on))
+		return;
+
+	if (ret > 0)
+		enable_fiq(kgdb_fiq);
+	else
+		disable_fiq(kgdb_fiq);
+}
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	int err;
+	int cpu;
+
+	if (!kgdb_fiq_enabled)
+		return -ENODEV;
+
+	if (!has_fiq(fiq)) {
+		pr_warn(
+		    "%s: Cannot register %u (no FIQ with this number)\n",
+		    __func__, fiq);
+		return -ENODEV;
+	}
+
+	kgdb_fiq = fiq;
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	for_each_possible_cpu(cpu)
+		work_on_cpu(cpu, kgdb_fiq_setup_stack, NULL);
+
+	set_fiq_handler(&kgdb_fiq_handler,
+			&kgdb_fiq_handler_end - &kgdb_fiq_handler);
+
+	arch_kgdb_ops.enable_nmi = kgdb_fiq_enable_nmi;
+	return 0;
+}
diff --git a/arch/arm/kernel/kgdb_fiq_entry.S b/arch/arm/kernel/kgdb_fiq_entry.S
new file mode 100644
index 0000000..50499c0
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq_entry.S
@@ -0,0 +1,130 @@
+/*
+ * KGDB FIQ entry
+ *
+ * Copyright 1996,1997,1998 Russell King.
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+#include <asm/unwind.h>
+#include "entry-header.S"
+
+	.text
+
+@ This is needed for usr_entry/alignment_trap
+.LCcralign:
+	.long	cr_alignment
+.LCdohandle:
+	.long	kgdb_fiq_do_handle
+
+	.macro	fiq_handler
+	ldr	r1, =.LCdohandle
+	mov	r0, sp
+	adr	lr, BSYM(9997f)
+	ldr	pc, [r1]
+9997:
+	.endm
+
+/*
+ * svc_exit_via_fiq
+ *
+ * This macro acts in a similar manner to svc_exit but switches to FIQ
+ * mode to restore the final part of the register state.
+ *
+ * We cannot use the normal svc_exit procedure because that would
+ * clobber spsr_svc (FIQ could be delivered during the first few instructions
+ * of vector_swi meaning its contents have not been saved anywhere).
+ */
+	.macro  svc_exit_via_fiq, rpsr
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+	tst	\rpsr, #PSR_I_BIT
+	bleq	trace_hardirqs_on
+#endif
+
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+	.endm
+
+	.align	5
+__fiq_svc:
+	svc_entry
+	fiq_handler
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+	.ltorg
+
+	.align 5
+__fiq_abt:
+	svc_entry
+
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	r0, lr		@ Save lr_abt
+	mrs	r1, spsr	@ Save spsr_abt, abort is now safe
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+	push	{r0 - r1}
+
+	fiq_handler
+
+	pop	{r0 - r1}
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	lr, r0		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r1	@ Restore spsr_abt
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+	.ltorg
+
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+	.ltorg
+
+	.global kgdb_fiq_handler
+kgdb_fiq_handler:
+
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
+
+	.global kgdb_fiq_handler_end
+kgdb_fiq_handler_end:
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v8 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
@ 2014-07-10  8:03               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-10  8:03 UTC (permalink / raw)
  To: linux-arm-kernel

From: Anton Vorontsov <anton.vorontsov@linaro.org>

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

By default KGDB FIQ is disabled in runtime, but can be enabled with
kgdb_fiq.enable=1 kernel command line option.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
[daniel.thompson at linaro.org: Added __fiq_abt, rewrote stack init]
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben.dooks@codethink.co.uk>
Cc: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm/Kconfig                 |   2 +
 arch/arm/Kconfig.debug           |  18 ++++++
 arch/arm/include/asm/kgdb.h      |   7 +++
 arch/arm/kernel/Makefile         |   1 +
 arch/arm/kernel/kgdb_fiq.c       | 132 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/kgdb_fiq_entry.S | 130 ++++++++++++++++++++++++++++++++++++++
 6 files changed, 290 insertions(+)
 create mode 100644 arch/arm/kernel/kgdb_fiq.c
 create mode 100644 arch/arm/kernel/kgdb_fiq_entry.S

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 245058b..f385b27 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -297,6 +297,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -346,6 +347,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 26536f7..c7342b6 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,24 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be
+	  enabled with kgdb_fiq.enable=1 kernel command line option.
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..5de21f01 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,11 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern char kgdb_fiq_handler;
+extern char kgdb_fiq_handler_end;
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs);
+extern int kgdb_register_fiq(unsigned int fiq);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 38ddd9f..30ee8f3 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -68,6 +68,7 @@ endif
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
 obj-$(CONFIG_ARM_THUMBEE)	+= thumbee.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
+obj-$(CONFIG_KGDB_FIQ)		+= kgdb_fiq_entry.o kgdb_fiq.o
 obj-$(CONFIG_ARM_UNWIND)	+= unwind.o
 obj-$(CONFIG_HAVE_TCM)		+= tcm.o
 obj-$(CONFIG_OF)		+= devtree.o
diff --git a/arch/arm/kernel/kgdb_fiq.c b/arch/arm/kernel/kgdb_fiq.c
new file mode 100644
index 0000000..a894dde
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq.c
@@ -0,0 +1,132 @@
+/*
+ * KGDB FIQ
+ *
+ * Copyright 2010 Google, Inc.
+ *		  Arve Hj?nnev?g <arve@android.com>
+ *		  Colin Cross <ccross@android.com>
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/hardirq.h>
+#include <linux/atomic.h>
+#include <linux/kdb.h>
+#include <linux/kgdb.h>
+#include <asm/fiq.h>
+#include <asm/exception.h>
+
+static int kgdb_fiq_enabled;
+module_param_named(enable, kgdb_fiq_enabled, int, 0600);
+MODULE_PARM_DESC(enable, "set to 1 to enable FIQ KGDB");
+
+static unsigned int kgdb_fiq;
+
+struct fiq_stack {
+	u32 fiq[3];
+} ____cacheline_aligned;
+
+static struct fiq_stack stacks[NR_CPUS];
+
+asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs)
+{
+	int actual;
+
+	nmi_enter();
+	actual = ack_fiq(kgdb_fiq);
+	WARN_ON(actual != kgdb_fiq);
+
+	/* there's no harm in doing this regardless of the above WARN_ON() */
+	if (kgdb_nmi_poll_knock())
+		kgdb_handle_exception(1, 0, 0, regs);
+
+	eoi_fiq(actual);
+	nmi_exit();
+}
+
+static struct fiq_handler kgdb_fiq_desc = {
+	.name = "kgdb",
+};
+
+static long kgdb_fiq_setup_stack(void *info)
+{
+	struct pt_regs regs;
+
+	regs.ARM_sp = (unsigned long) stacks[smp_processor_id()].fiq;
+	set_fiq_regs(&regs);
+
+	return 0;
+}
+
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * This function manages NMIs that usually cause KGDB to enter. That is, not
+ * all NMIs should be enabled or disabled, but only those that issue
+ * kgdb_handle_exception().
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	static atomic_t cnt;
+	int ret;
+
+	ret = atomic_add_return(on ? 1 : -1, &cnt);
+
+	/*
+	 * There should be only one instance that calls this function
+	 * in "enable, disable" order. All other users must call
+	 * disable first, then enable. If not, something is wrong.
+	 */
+	if (WARN_ON(ret > 1 && on))
+		return;
+
+	if (ret > 0)
+		enable_fiq(kgdb_fiq);
+	else
+		disable_fiq(kgdb_fiq);
+}
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	int err;
+	int cpu;
+
+	if (!kgdb_fiq_enabled)
+		return -ENODEV;
+
+	if (!has_fiq(fiq)) {
+		pr_warn(
+		    "%s: Cannot register %u (no FIQ with this number)\n",
+		    __func__, fiq);
+		return -ENODEV;
+	}
+
+	kgdb_fiq = fiq;
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	for_each_possible_cpu(cpu)
+		work_on_cpu(cpu, kgdb_fiq_setup_stack, NULL);
+
+	set_fiq_handler(&kgdb_fiq_handler,
+			&kgdb_fiq_handler_end - &kgdb_fiq_handler);
+
+	arch_kgdb_ops.enable_nmi = kgdb_fiq_enable_nmi;
+	return 0;
+}
diff --git a/arch/arm/kernel/kgdb_fiq_entry.S b/arch/arm/kernel/kgdb_fiq_entry.S
new file mode 100644
index 0000000..50499c0
--- /dev/null
+++ b/arch/arm/kernel/kgdb_fiq_entry.S
@@ -0,0 +1,130 @@
+/*
+ * KGDB FIQ entry
+ *
+ * Copyright 1996,1997,1998 Russell King.
+ * Copyright 2012 Linaro Ltd.
+ *		  Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+#include <asm/unwind.h>
+#include "entry-header.S"
+
+	.text
+
+@ This is needed for usr_entry/alignment_trap
+.LCcralign:
+	.long	cr_alignment
+.LCdohandle:
+	.long	kgdb_fiq_do_handle
+
+	.macro	fiq_handler
+	ldr	r1, =.LCdohandle
+	mov	r0, sp
+	adr	lr, BSYM(9997f)
+	ldr	pc, [r1]
+9997:
+	.endm
+
+/*
+ * svc_exit_via_fiq
+ *
+ * This macro acts in a similar manner to svc_exit but switches to FIQ
+ * mode to restore the final part of the register state.
+ *
+ * We cannot use the normal svc_exit procedure because that would
+ * clobber spsr_svc (FIQ could be delivered during the first few instructions
+ * of vector_swi meaning its contents have not been saved anywhere).
+ */
+	.macro  svc_exit_via_fiq, rpsr
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+	tst	\rpsr, #PSR_I_BIT
+	bleq	trace_hardirqs_on
+#endif
+
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+	.endm
+
+	.align	5
+__fiq_svc:
+	svc_entry
+	fiq_handler
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+	.ltorg
+
+	.align 5
+__fiq_abt:
+	svc_entry
+
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	r0, lr		@ Save lr_abt
+	mrs	r1, spsr	@ Save spsr_abt, abort is now safe
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+	push	{r0 - r1}
+
+	fiq_handler
+
+	pop	{r0 - r1}
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	lr, r0		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r1	@ Restore spsr_abt
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+	.ltorg
+
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+	.ltorg
+
+	.global kgdb_fiq_handler
+kgdb_fiq_handler:
+
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
+
+	.global kgdb_fiq_handler_end
+kgdb_fiq_handler_end:
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support
  2014-07-10  8:03             ` Daniel Thompson
@ 2014-07-14 13:51               ` Harro Haan
  -1 siblings, 0 replies; 535+ messages in thread
From: Harro Haan @ 2014-07-14 13:51 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Russell King, linaro-kernel, Catalin Marinas, patches,
	kgdb-bugreport, Linus Walleij, Nicolas Pitre, linux-kernel,
	Frederic Weisbecker, Anton Vorontsov, Ben Dooks, John Stultz,
	Fabio Estevam, Colin Cross, kernel-team, Dave Martin,
	linux-arm-kernel

On 10 July 2014 10:03, Daniel Thompson <daniel.thompson@linaro.org> wrote:
>
> This patchset makes it possible to use kgdb's NMI infrastructure on ARM
> platforms.
>
> The patches have been previously circulated as part of a large patchset
> mixing together ARM architecture code and driver changes
> (http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901 ). This
> patchset is dramatically cut down to include only the arch/arm code. The
> driver code (irqchip and tty/serial) will follow when/if the arch code
> is accepted.
>
> The first two patches modify the FIQ infrastructure to allow interrupt
> controller drivers to register callbacks (the fiq_chip structure) to
> manage FIQ routings and to ACK and EOI the FIQ. This makes it possible
> to use FIQ in multi-platform kernels and with recent ARM interrupt
> controllers.
>

Daniel,

Thanks for the patches. I have tested the fiq and irq-gic patches on
an i.MX6 (SabreSD board) for a different purpose:
A FIQ timer interrupt at 1 kHz. The TWD watchdog block is used in
timer mode for this (interrupt ID 30). The GIC affinity is set to CPU
core 0 only for this interrupt ID.

I was surprised by the following behavior:
$ cat /proc/interrupts
           CPU0       CPU1       CPU2       CPU3
 29:       5459       3381       3175       3029       GIC  29  twd
 30:         11          0          0          0       GIC  30  fake-fiq

Once every few seconds is interrupt ID 30 handled by the regular GIC
handler instead of the FIQ exception path (which causes for example a
bit more latencies). The other thousands of FIQ's are handled by the
FIQ exception path. The problem is also confirmed by the following
stackframe of the Lauterbach tooling:
fake_fiq_handler(irq = 30, ...)
handle_percpu_devid_irq(irq = 30, ...)
generic_handle_irq(irq = 30)
handle_IRQ(irq = 30, ...)
gic_handle_irq
__irq_svc
-->exception

Notes:
- The problem will occur more often by executing the following command:
  $ while true; do hackbench 20; done &
- Reading the GIC_CPU_INTACK register returns the interrupt ID of the
highest priority pending interrupt.
- The GIC_CPU_INTACK register (used by fiq_ack) will return spurious
interrupt ID 0x3FF when read in fake_fiq_handler, because
GIC_CPU_INTACK is already read by gic_handle_irq.
- The FIQ exception will not occur anymore after gic_handle_irq
read/acknowledges the FIQ by reading the GIC_CPU_INTACK register

>From the behavior above I conclude that the GIC_CPU_INTACK register is
first updated before the FIQ exception is generated, so there is a
small period of time that gic_handle_irq can read/acknowledge the FIQ.

I can reduce the number of occurrences (not prevent it) by adding the
following hack to irq-gic.c
@@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
gic_handle_irq(struct pt_regs *regs
  u32 irqstat, irqnr;
  struct gic_chip_data *gic = &gic_data[0];
  void __iomem *cpu_base = gic_data_cpu_base(gic);

  do {
+ while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
& (1 << 30))
+   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
  irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
  irqnr = irqstat & ~0x1c00;

Regards,

Harro Haan

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v8 0/4] arm: KGDB NMI/FIQ support
@ 2014-07-14 13:51               ` Harro Haan
  0 siblings, 0 replies; 535+ messages in thread
From: Harro Haan @ 2014-07-14 13:51 UTC (permalink / raw)
  To: linux-arm-kernel

On 10 July 2014 10:03, Daniel Thompson <daniel.thompson@linaro.org> wrote:
>
> This patchset makes it possible to use kgdb's NMI infrastructure on ARM
> platforms.
>
> The patches have been previously circulated as part of a large patchset
> mixing together ARM architecture code and driver changes
> (http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901 ). This
> patchset is dramatically cut down to include only the arch/arm code. The
> driver code (irqchip and tty/serial) will follow when/if the arch code
> is accepted.
>
> The first two patches modify the FIQ infrastructure to allow interrupt
> controller drivers to register callbacks (the fiq_chip structure) to
> manage FIQ routings and to ACK and EOI the FIQ. This makes it possible
> to use FIQ in multi-platform kernels and with recent ARM interrupt
> controllers.
>

Daniel,

Thanks for the patches. I have tested the fiq and irq-gic patches on
an i.MX6 (SabreSD board) for a different purpose:
A FIQ timer interrupt at 1 kHz. The TWD watchdog block is used in
timer mode for this (interrupt ID 30). The GIC affinity is set to CPU
core 0 only for this interrupt ID.

I was surprised by the following behavior:
$ cat /proc/interrupts
           CPU0       CPU1       CPU2       CPU3
 29:       5459       3381       3175       3029       GIC  29  twd
 30:         11          0          0          0       GIC  30  fake-fiq

Once every few seconds is interrupt ID 30 handled by the regular GIC
handler instead of the FIQ exception path (which causes for example a
bit more latencies). The other thousands of FIQ's are handled by the
FIQ exception path. The problem is also confirmed by the following
stackframe of the Lauterbach tooling:
fake_fiq_handler(irq = 30, ...)
handle_percpu_devid_irq(irq = 30, ...)
generic_handle_irq(irq = 30)
handle_IRQ(irq = 30, ...)
gic_handle_irq
__irq_svc
-->exception

Notes:
- The problem will occur more often by executing the following command:
  $ while true; do hackbench 20; done &
- Reading the GIC_CPU_INTACK register returns the interrupt ID of the
highest priority pending interrupt.
- The GIC_CPU_INTACK register (used by fiq_ack) will return spurious
interrupt ID 0x3FF when read in fake_fiq_handler, because
GIC_CPU_INTACK is already read by gic_handle_irq.
- The FIQ exception will not occur anymore after gic_handle_irq
read/acknowledges the FIQ by reading the GIC_CPU_INTACK register

>From the behavior above I conclude that the GIC_CPU_INTACK register is
first updated before the FIQ exception is generated, so there is a
small period of time that gic_handle_irq can read/acknowledge the FIQ.

I can reduce the number of occurrences (not prevent it) by adding the
following hack to irq-gic.c
@@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
gic_handle_irq(struct pt_regs *regs
  u32 irqstat, irqnr;
  struct gic_chip_data *gic = &gic_data[0];
  void __iomem *cpu_base = gic_data_cpu_base(gic);

  do {
+ while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
& (1 << 30))
+   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
  irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
  irqnr = irqstat & ~0x1c00;

Regards,

Harro Haan

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support
  2014-07-14 13:51               ` Harro Haan
@ 2014-07-15  9:41                 ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-15  9:41 UTC (permalink / raw)
  To: Harro Haan
  Cc: Russell King, linaro-kernel, Catalin Marinas, patches,
	kgdb-bugreport, Linus Walleij, Nicolas Pitre, linux-kernel,
	Frederic Weisbecker, Anton Vorontsov, Ben Dooks, John Stultz,
	Fabio Estevam, Colin Cross, kernel-team, Dave Martin,
	linux-arm-kernel

On 14/07/14 14:51, Harro Haan wrote:
> On 10 July 2014 10:03, Daniel Thompson <daniel.thompson@linaro.org> wrote:
>>
>> This patchset makes it possible to use kgdb's NMI infrastructure on ARM
>> platforms.
>>
>> The patches have been previously circulated as part of a large patchset
>> mixing together ARM architecture code and driver changes
>> (http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901 ). This
>> patchset is dramatically cut down to include only the arch/arm code. The
>> driver code (irqchip and tty/serial) will follow when/if the arch code
>> is accepted.
>>
>> The first two patches modify the FIQ infrastructure to allow interrupt
>> controller drivers to register callbacks (the fiq_chip structure) to
>> manage FIQ routings and to ACK and EOI the FIQ. This makes it possible
>> to use FIQ in multi-platform kernels and with recent ARM interrupt
>> controllers.
>>
> 
> Daniel,
> 
> Thanks for the patches. I have tested the fiq and irq-gic patches on
> an i.MX6 (SabreSD board) for a different purpose:
> A FIQ timer interrupt at 1 kHz. The TWD watchdog block is used in
> timer mode for this (interrupt ID 30). The GIC affinity is set to CPU
> core 0 only for this interrupt ID.
> 
> I was surprised by the following behavior:
> $ cat /proc/interrupts
>            CPU0       CPU1       CPU2       CPU3
>  29:       5459       3381       3175       3029       GIC  29  twd
>  30:         11          0          0          0       GIC  30  fake-fiq
> 
> Once every few seconds is interrupt ID 30 handled by the regular GIC
> handler instead of the FIQ exception path (which causes for example a
> bit more latencies). The other thousands of FIQ's are handled by the
> FIQ exception path. The problem is also confirmed by the following
> stackframe of the Lauterbach tooling:
> fake_fiq_handler(irq = 30, ...)
> handle_percpu_devid_irq(irq = 30, ...)
> generic_handle_irq(irq = 30)
> handle_IRQ(irq = 30, ...)
> gic_handle_irq
> __irq_svc
> -->exception
> 
> Notes:
> - The problem will occur more often by executing the following command:
>   $ while true; do hackbench 20; done &
> - Reading the GIC_CPU_INTACK register returns the interrupt ID of the
> highest priority pending interrupt.
> - The GIC_CPU_INTACK register (used by fiq_ack) will return spurious
> interrupt ID 0x3FF when read in fake_fiq_handler, because
> GIC_CPU_INTACK is already read by gic_handle_irq.
> - The FIQ exception will not occur anymore after gic_handle_irq
> read/acknowledges the FIQ by reading the GIC_CPU_INTACK register
> 
> From the behavior above I conclude that the GIC_CPU_INTACK register is
> first updated before the FIQ exception is generated, so there is a
> small period of time that gic_handle_irq can read/acknowledge the FIQ.

Makes sense.

Avoiding this problem on GICv2 is easy (thanks to the aliased intack
register) but on iMX.6 we have only a GICv1.


> I can reduce the number of occurrences (not prevent it) by adding the
> following hack to irq-gic.c
> @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
> gic_handle_irq(struct pt_regs *regs
>   u32 irqstat, irqnr;
>   struct gic_chip_data *gic = &gic_data[0];
>   void __iomem *cpu_base = gic_data_cpu_base(gic);
> 
>   do {
> + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
> & (1 << 30))
> +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
>   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>   irqnr = irqstat & ~0x1c00;

I've made a more complete attempt to fix this. Could you test the
following? (and be prepared to fuzz the line numbers)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 73ae896..309bf2c 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -303,6 +303,28 @@ static int gic_set_wake(struct irq_data *d,
unsigned int on)
 #define gic_set_wake	NULL
 #endif

+/* Check for group 0 interrupt spuriously acked as a normal IRQ. This
+ * workaround will only work for level triggered interrupts (and in
+ * its current form is actively harmful on systems that don't support
+ * FIQ).
+ */
+static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32
irqstat)
+{
+	u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+
+	if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
+		return irqnr;
+
+	if (readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_IGROUP +
+			  (irqnr / 32 * 4)) &
+	    BIT(irqnr % 32))
+		return irqnr;
+
+	/* this interrupt was spurious (needs to be handled as FIQ) */
+	writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
+	return 1023;
+}
+
 static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
 	u32 irqstat, irqnr;
@@ -310,8 +332,10 @@ static void __exception_irq_entry
gic_handle_irq(struct pt_regs *regs)
 	void __iomem *cpu_base = gic_data_cpu_base(gic);

 	do {
+		local_fiq_disable();
 		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
-		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		irqnr = gic_handle_spurious_group_0(gic, irqstat);
+		local_fiq_enable();

 		if (likely(irqnr > 15 && irqnr < 1021)) {
 			irqnr = irq_find_mapping(gic->domain, irqnr);

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v8 0/4] arm: KGDB NMI/FIQ support
@ 2014-07-15  9:41                 ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-15  9:41 UTC (permalink / raw)
  To: linux-arm-kernel

On 14/07/14 14:51, Harro Haan wrote:
> On 10 July 2014 10:03, Daniel Thompson <daniel.thompson@linaro.org> wrote:
>>
>> This patchset makes it possible to use kgdb's NMI infrastructure on ARM
>> platforms.
>>
>> The patches have been previously circulated as part of a large patchset
>> mixing together ARM architecture code and driver changes
>> (http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901 ). This
>> patchset is dramatically cut down to include only the arch/arm code. The
>> driver code (irqchip and tty/serial) will follow when/if the arch code
>> is accepted.
>>
>> The first two patches modify the FIQ infrastructure to allow interrupt
>> controller drivers to register callbacks (the fiq_chip structure) to
>> manage FIQ routings and to ACK and EOI the FIQ. This makes it possible
>> to use FIQ in multi-platform kernels and with recent ARM interrupt
>> controllers.
>>
> 
> Daniel,
> 
> Thanks for the patches. I have tested the fiq and irq-gic patches on
> an i.MX6 (SabreSD board) for a different purpose:
> A FIQ timer interrupt at 1 kHz. The TWD watchdog block is used in
> timer mode for this (interrupt ID 30). The GIC affinity is set to CPU
> core 0 only for this interrupt ID.
> 
> I was surprised by the following behavior:
> $ cat /proc/interrupts
>            CPU0       CPU1       CPU2       CPU3
>  29:       5459       3381       3175       3029       GIC  29  twd
>  30:         11          0          0          0       GIC  30  fake-fiq
> 
> Once every few seconds is interrupt ID 30 handled by the regular GIC
> handler instead of the FIQ exception path (which causes for example a
> bit more latencies). The other thousands of FIQ's are handled by the
> FIQ exception path. The problem is also confirmed by the following
> stackframe of the Lauterbach tooling:
> fake_fiq_handler(irq = 30, ...)
> handle_percpu_devid_irq(irq = 30, ...)
> generic_handle_irq(irq = 30)
> handle_IRQ(irq = 30, ...)
> gic_handle_irq
> __irq_svc
> -->exception
> 
> Notes:
> - The problem will occur more often by executing the following command:
>   $ while true; do hackbench 20; done &
> - Reading the GIC_CPU_INTACK register returns the interrupt ID of the
> highest priority pending interrupt.
> - The GIC_CPU_INTACK register (used by fiq_ack) will return spurious
> interrupt ID 0x3FF when read in fake_fiq_handler, because
> GIC_CPU_INTACK is already read by gic_handle_irq.
> - The FIQ exception will not occur anymore after gic_handle_irq
> read/acknowledges the FIQ by reading the GIC_CPU_INTACK register
> 
> From the behavior above I conclude that the GIC_CPU_INTACK register is
> first updated before the FIQ exception is generated, so there is a
> small period of time that gic_handle_irq can read/acknowledge the FIQ.

Makes sense.

Avoiding this problem on GICv2 is easy (thanks to the aliased intack
register) but on iMX.6 we have only a GICv1.


> I can reduce the number of occurrences (not prevent it) by adding the
> following hack to irq-gic.c
> @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
> gic_handle_irq(struct pt_regs *regs
>   u32 irqstat, irqnr;
>   struct gic_chip_data *gic = &gic_data[0];
>   void __iomem *cpu_base = gic_data_cpu_base(gic);
> 
>   do {
> + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
> & (1 << 30))
> +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
>   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>   irqnr = irqstat & ~0x1c00;

I've made a more complete attempt to fix this. Could you test the
following? (and be prepared to fuzz the line numbers)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 73ae896..309bf2c 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -303,6 +303,28 @@ static int gic_set_wake(struct irq_data *d,
unsigned int on)
 #define gic_set_wake	NULL
 #endif

+/* Check for group 0 interrupt spuriously acked as a normal IRQ. This
+ * workaround will only work for level triggered interrupts (and in
+ * its current form is actively harmful on systems that don't support
+ * FIQ).
+ */
+static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32
irqstat)
+{
+	u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+
+	if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
+		return irqnr;
+
+	if (readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_IGROUP +
+			  (irqnr / 32 * 4)) &
+	    BIT(irqnr % 32))
+		return irqnr;
+
+	/* this interrupt was spurious (needs to be handled as FIQ) */
+	writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
+	return 1023;
+}
+
 static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
 	u32 irqstat, irqnr;
@@ -310,8 +332,10 @@ static void __exception_irq_entry
gic_handle_irq(struct pt_regs *regs)
 	void __iomem *cpu_base = gic_data_cpu_base(gic);

 	do {
+		local_fiq_disable();
 		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
-		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		irqnr = gic_handle_spurious_group_0(gic, irqstat);
+		local_fiq_enable();

 		if (likely(irqnr > 15 && irqnr < 1021)) {
 			irqnr = irq_find_mapping(gic->domain, irqnr);

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support
  2014-07-15  9:41                 ` Daniel Thompson
@ 2014-07-15 13:04                   ` Harro Haan
  -1 siblings, 0 replies; 535+ messages in thread
From: Harro Haan @ 2014-07-15 13:04 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Russell King, linaro-kernel, Catalin Marinas, patches,
	kgdb-bugreport, Linus Walleij, Nicolas Pitre, linux-kernel,
	Frederic Weisbecker, Anton Vorontsov, Ben Dooks, John Stultz,
	Fabio Estevam, Colin Cross, kernel-team, Dave Martin,
	linux-arm-kernel

On 15 July 2014 11:41, Daniel Thompson <daniel.thompson@linaro.org> wrote:
> On 14/07/14 14:51, Harro Haan wrote:
>> On 10 July 2014 10:03, Daniel Thompson <daniel.thompson@linaro.org> wrote:
>>>
>>> This patchset makes it possible to use kgdb's NMI infrastructure on ARM
>>> platforms.
>>>
>>> The patches have been previously circulated as part of a large patchset
>>> mixing together ARM architecture code and driver changes
>>> (http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901 ). This
>>> patchset is dramatically cut down to include only the arch/arm code. The
>>> driver code (irqchip and tty/serial) will follow when/if the arch code
>>> is accepted.
>>>
>>> The first two patches modify the FIQ infrastructure to allow interrupt
>>> controller drivers to register callbacks (the fiq_chip structure) to
>>> manage FIQ routings and to ACK and EOI the FIQ. This makes it possible
>>> to use FIQ in multi-platform kernels and with recent ARM interrupt
>>> controllers.
>>>
>>
>> Daniel,
>>
>> Thanks for the patches. I have tested the fiq and irq-gic patches on
>> an i.MX6 (SabreSD board) for a different purpose:
>> A FIQ timer interrupt at 1 kHz. The TWD watchdog block is used in
>> timer mode for this (interrupt ID 30). The GIC affinity is set to CPU
>> core 0 only for this interrupt ID.
>>
>> I was surprised by the following behavior:
>> $ cat /proc/interrupts
>>            CPU0       CPU1       CPU2       CPU3
>>  29:       5459       3381       3175       3029       GIC  29  twd
>>  30:         11          0          0          0       GIC  30  fake-fiq
>>
>> Once every few seconds is interrupt ID 30 handled by the regular GIC
>> handler instead of the FIQ exception path (which causes for example a
>> bit more latencies). The other thousands of FIQ's are handled by the
>> FIQ exception path. The problem is also confirmed by the following
>> stackframe of the Lauterbach tooling:
>> fake_fiq_handler(irq = 30, ...)
>> handle_percpu_devid_irq(irq = 30, ...)
>> generic_handle_irq(irq = 30)
>> handle_IRQ(irq = 30, ...)
>> gic_handle_irq
>> __irq_svc
>> -->exception
>>
>> Notes:
>> - The problem will occur more often by executing the following command:
>>   $ while true; do hackbench 20; done &
>> - Reading the GIC_CPU_INTACK register returns the interrupt ID of the
>> highest priority pending interrupt.
>> - The GIC_CPU_INTACK register (used by fiq_ack) will return spurious
>> interrupt ID 0x3FF when read in fake_fiq_handler, because
>> GIC_CPU_INTACK is already read by gic_handle_irq.
>> - The FIQ exception will not occur anymore after gic_handle_irq
>> read/acknowledges the FIQ by reading the GIC_CPU_INTACK register
>>
>> From the behavior above I conclude that the GIC_CPU_INTACK register is
>> first updated before the FIQ exception is generated, so there is a
>> small period of time that gic_handle_irq can read/acknowledge the FIQ.
>
> Makes sense.
>
> Avoiding this problem on GICv2 is easy (thanks to the aliased intack
> register) but on iMX.6 we have only a GICv1.
>
>
>> I can reduce the number of occurrences (not prevent it) by adding the
>> following hack to irq-gic.c
>> @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
>> gic_handle_irq(struct pt_regs *regs
>>   u32 irqstat, irqnr;
>>   struct gic_chip_data *gic = &gic_data[0];
>>   void __iomem *cpu_base = gic_data_cpu_base(gic);
>>
>>   do {
>> + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
>> & (1 << 30))
>> +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
>>   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>>   irqnr = irqstat & ~0x1c00;
>
> I've made a more complete attempt to fix this. Could you test the
> following? (and be prepared to fuzz the line numbers)

Thanks Daniel, I have tested it, see the comments below.

>
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index 73ae896..309bf2c 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -303,6 +303,28 @@ static int gic_set_wake(struct irq_data *d,
> unsigned int on)
>  #define gic_set_wake   NULL
>  #endif
>
> +/* Check for group 0 interrupt spuriously acked as a normal IRQ. This
> + * workaround will only work for level triggered interrupts (and in
> + * its current form is actively harmful on systems that don't support
> + * FIQ).
> + */
> +static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32
> irqstat)
> +{
> +       u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
> +
> +       if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
> +               return irqnr;
> +
> +       if (readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_IGROUP +
> +                         (irqnr / 32 * 4)) &
> +           BIT(irqnr % 32))
> +               return irqnr;
> +
> +       /* this interrupt was spurious (needs to be handled as FIQ) */
> +       writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);

This will NOT work, because of the note I mentioned above:
"The FIQ exception will not occur anymore after gic_handle_irq
read/acknowledges the FIQ by reading the GIC_CPU_INTACK register"
So with this code you will say End Of Interrupt at the GIC level,
without actually handling the interrupt, so you are missing an
interrupt.
I did the following test to confirm the missing interrupt:
I have changed the periodic timer interrupt by an one-shot timer
interrupt. The one-shot timer interrupt is programmed by the FIQ
handler for the next FIQ interrupt. As expected: When the problem
occurs, no more FIQ interrupts are generated.

> +       return 1023;
> +}
> +
>  static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
>  {
>         u32 irqstat, irqnr;
> @@ -310,8 +332,10 @@ static void __exception_irq_entry
> gic_handle_irq(struct pt_regs *regs)
>         void __iomem *cpu_base = gic_data_cpu_base(gic);
>
>         do {
> +               local_fiq_disable();

It is a bit weird to disable the "Non-Maskable Interrupt" at every
interrupt, because of a problem that occurs once every few thousand
interrupts

>                 irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
> -               irqnr = irqstat & GICC_IAR_INT_ID_MASK;
> +               irqnr = gic_handle_spurious_group_0(gic, irqstat);
> +               local_fiq_enable();
>
>                 if (likely(irqnr > 15 && irqnr < 1021)) {
>                         irqnr = irq_find_mapping(gic->domain, irqnr);


The following type of changes could fix the problem for me:

@@ -290,19 +290,66 @@ static int gic_set_wake(struct irq_data *d,
unsigned int on)

 #else
 #define gic_set_wake NULL
 #endif

+extern void (*fiq_handler)(void);
+
+/* Check for group 0 interrupt spuriously acked as a normal IRQ. This
+ * workaround will only work for level triggered interrupts (and in
+ * its current form is actively harmful on systems that don't support
+ * FIQ).
+ */
+static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32 irqstat)
+{
+ u32 irqnr = irqstat & ~0x1c00;
+
+ if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
+ return irqnr;
+
+ if (readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_IGROUP +
+  (irqnr / 32 * 4)) & BIT(irqnr % 32))
+ return irqnr;
+
+ /*
+ * The FIQ should be disabled before the next FIQ interrupt occurs,
+ * so this only works when the next FIQ interrupt is not "too fast"
+ * after the previous one.
+ */
+ local_fiq_disable();
+
+ /*
+ * Notes:
+ * - The FIQ exception will not occur anymore for this current
+ *   interrupt, because gic_handle_irq has already read/acknowledged
+ *   the GIC_CPU_INTACK register. So handle the FIQ here.
+ * - The fiq_handler below should not call ack_fiq and eoi_fiq,
+ *   because rereading the GIC_CPU_INTACK register returns spurious
+ *   interrupt ID 0x3FF. So probably you will have to add sometime like
+ *   the following to fiq_handler:
+ *   u32 cpsr, irqstat;
+ *   __asm__("mrs %0, cpsr" : "=r" (cpsr));
+ *   if ((cpsr & MODE_MASK) == FIQ_MODE)
+ *   irqstat = ack_fiq();
+ */
+ (*fiq_handler)();
+
+ writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
+ local_fiq_enable();
+
+ return 1023;
+}
+
 static asmlinkage void __exception_irq_entry gic_handle_irq(struct
pt_regs *regs)
 {
  u32 irqstat, irqnr;
  struct gic_chip_data *gic = &gic_data[0];
  void __iomem *cpu_base = gic_data_cpu_base(gic);

  do {
  irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
- irqnr = irqstat & ~0x1c00;
+ irqnr = gic_handle_spurious_group_0(gic, irqstat);

  if (likely(irqnr > 15 && irqnr < 1021)) {

Regards,

Harro

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v8 0/4] arm: KGDB NMI/FIQ support
@ 2014-07-15 13:04                   ` Harro Haan
  0 siblings, 0 replies; 535+ messages in thread
From: Harro Haan @ 2014-07-15 13:04 UTC (permalink / raw)
  To: linux-arm-kernel

On 15 July 2014 11:41, Daniel Thompson <daniel.thompson@linaro.org> wrote:
> On 14/07/14 14:51, Harro Haan wrote:
>> On 10 July 2014 10:03, Daniel Thompson <daniel.thompson@linaro.org> wrote:
>>>
>>> This patchset makes it possible to use kgdb's NMI infrastructure on ARM
>>> platforms.
>>>
>>> The patches have been previously circulated as part of a large patchset
>>> mixing together ARM architecture code and driver changes
>>> (http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901 ). This
>>> patchset is dramatically cut down to include only the arch/arm code. The
>>> driver code (irqchip and tty/serial) will follow when/if the arch code
>>> is accepted.
>>>
>>> The first two patches modify the FIQ infrastructure to allow interrupt
>>> controller drivers to register callbacks (the fiq_chip structure) to
>>> manage FIQ routings and to ACK and EOI the FIQ. This makes it possible
>>> to use FIQ in multi-platform kernels and with recent ARM interrupt
>>> controllers.
>>>
>>
>> Daniel,
>>
>> Thanks for the patches. I have tested the fiq and irq-gic patches on
>> an i.MX6 (SabreSD board) for a different purpose:
>> A FIQ timer interrupt at 1 kHz. The TWD watchdog block is used in
>> timer mode for this (interrupt ID 30). The GIC affinity is set to CPU
>> core 0 only for this interrupt ID.
>>
>> I was surprised by the following behavior:
>> $ cat /proc/interrupts
>>            CPU0       CPU1       CPU2       CPU3
>>  29:       5459       3381       3175       3029       GIC  29  twd
>>  30:         11          0          0          0       GIC  30  fake-fiq
>>
>> Once every few seconds is interrupt ID 30 handled by the regular GIC
>> handler instead of the FIQ exception path (which causes for example a
>> bit more latencies). The other thousands of FIQ's are handled by the
>> FIQ exception path. The problem is also confirmed by the following
>> stackframe of the Lauterbach tooling:
>> fake_fiq_handler(irq = 30, ...)
>> handle_percpu_devid_irq(irq = 30, ...)
>> generic_handle_irq(irq = 30)
>> handle_IRQ(irq = 30, ...)
>> gic_handle_irq
>> __irq_svc
>> -->exception
>>
>> Notes:
>> - The problem will occur more often by executing the following command:
>>   $ while true; do hackbench 20; done &
>> - Reading the GIC_CPU_INTACK register returns the interrupt ID of the
>> highest priority pending interrupt.
>> - The GIC_CPU_INTACK register (used by fiq_ack) will return spurious
>> interrupt ID 0x3FF when read in fake_fiq_handler, because
>> GIC_CPU_INTACK is already read by gic_handle_irq.
>> - The FIQ exception will not occur anymore after gic_handle_irq
>> read/acknowledges the FIQ by reading the GIC_CPU_INTACK register
>>
>> From the behavior above I conclude that the GIC_CPU_INTACK register is
>> first updated before the FIQ exception is generated, so there is a
>> small period of time that gic_handle_irq can read/acknowledge the FIQ.
>
> Makes sense.
>
> Avoiding this problem on GICv2 is easy (thanks to the aliased intack
> register) but on iMX.6 we have only a GICv1.
>
>
>> I can reduce the number of occurrences (not prevent it) by adding the
>> following hack to irq-gic.c
>> @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
>> gic_handle_irq(struct pt_regs *regs
>>   u32 irqstat, irqnr;
>>   struct gic_chip_data *gic = &gic_data[0];
>>   void __iomem *cpu_base = gic_data_cpu_base(gic);
>>
>>   do {
>> + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
>> & (1 << 30))
>> +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
>>   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>>   irqnr = irqstat & ~0x1c00;
>
> I've made a more complete attempt to fix this. Could you test the
> following? (and be prepared to fuzz the line numbers)

Thanks Daniel, I have tested it, see the comments below.

>
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index 73ae896..309bf2c 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -303,6 +303,28 @@ static int gic_set_wake(struct irq_data *d,
> unsigned int on)
>  #define gic_set_wake   NULL
>  #endif
>
> +/* Check for group 0 interrupt spuriously acked as a normal IRQ. This
> + * workaround will only work for level triggered interrupts (and in
> + * its current form is actively harmful on systems that don't support
> + * FIQ).
> + */
> +static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32
> irqstat)
> +{
> +       u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
> +
> +       if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
> +               return irqnr;
> +
> +       if (readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_IGROUP +
> +                         (irqnr / 32 * 4)) &
> +           BIT(irqnr % 32))
> +               return irqnr;
> +
> +       /* this interrupt was spurious (needs to be handled as FIQ) */
> +       writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);

This will NOT work, because of the note I mentioned above:
"The FIQ exception will not occur anymore after gic_handle_irq
read/acknowledges the FIQ by reading the GIC_CPU_INTACK register"
So with this code you will say End Of Interrupt at the GIC level,
without actually handling the interrupt, so you are missing an
interrupt.
I did the following test to confirm the missing interrupt:
I have changed the periodic timer interrupt by an one-shot timer
interrupt. The one-shot timer interrupt is programmed by the FIQ
handler for the next FIQ interrupt. As expected: When the problem
occurs, no more FIQ interrupts are generated.

> +       return 1023;
> +}
> +
>  static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
>  {
>         u32 irqstat, irqnr;
> @@ -310,8 +332,10 @@ static void __exception_irq_entry
> gic_handle_irq(struct pt_regs *regs)
>         void __iomem *cpu_base = gic_data_cpu_base(gic);
>
>         do {
> +               local_fiq_disable();

It is a bit weird to disable the "Non-Maskable Interrupt" at every
interrupt, because of a problem that occurs once every few thousand
interrupts

>                 irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
> -               irqnr = irqstat & GICC_IAR_INT_ID_MASK;
> +               irqnr = gic_handle_spurious_group_0(gic, irqstat);
> +               local_fiq_enable();
>
>                 if (likely(irqnr > 15 && irqnr < 1021)) {
>                         irqnr = irq_find_mapping(gic->domain, irqnr);


The following type of changes could fix the problem for me:

@@ -290,19 +290,66 @@ static int gic_set_wake(struct irq_data *d,
unsigned int on)

 #else
 #define gic_set_wake NULL
 #endif

+extern void (*fiq_handler)(void);
+
+/* Check for group 0 interrupt spuriously acked as a normal IRQ. This
+ * workaround will only work for level triggered interrupts (and in
+ * its current form is actively harmful on systems that don't support
+ * FIQ).
+ */
+static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32 irqstat)
+{
+ u32 irqnr = irqstat & ~0x1c00;
+
+ if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
+ return irqnr;
+
+ if (readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_IGROUP +
+  (irqnr / 32 * 4)) & BIT(irqnr % 32))
+ return irqnr;
+
+ /*
+ * The FIQ should be disabled before the next FIQ interrupt occurs,
+ * so this only works when the next FIQ interrupt is not "too fast"
+ * after the previous one.
+ */
+ local_fiq_disable();
+
+ /*
+ * Notes:
+ * - The FIQ exception will not occur anymore for this current
+ *   interrupt, because gic_handle_irq has already read/acknowledged
+ *   the GIC_CPU_INTACK register. So handle the FIQ here.
+ * - The fiq_handler below should not call ack_fiq and eoi_fiq,
+ *   because rereading the GIC_CPU_INTACK register returns spurious
+ *   interrupt ID 0x3FF. So probably you will have to add sometime like
+ *   the following to fiq_handler:
+ *   u32 cpsr, irqstat;
+ *   __asm__("mrs %0, cpsr" : "=r" (cpsr));
+ *   if ((cpsr & MODE_MASK) == FIQ_MODE)
+ *   irqstat = ack_fiq();
+ */
+ (*fiq_handler)();
+
+ writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
+ local_fiq_enable();
+
+ return 1023;
+}
+
 static asmlinkage void __exception_irq_entry gic_handle_irq(struct
pt_regs *regs)
 {
  u32 irqstat, irqnr;
  struct gic_chip_data *gic = &gic_data[0];
  void __iomem *cpu_base = gic_data_cpu_base(gic);

  do {
  irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
- irqnr = irqstat & ~0x1c00;
+ irqnr = gic_handle_spurious_group_0(gic, irqstat);

  if (likely(irqnr > 15 && irqnr < 1021)) {

Regards,

Harro

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support
  2014-07-15 13:04                   ` Harro Haan
@ 2014-07-15 14:52                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-15 14:52 UTC (permalink / raw)
  To: Harro Haan
  Cc: Russell King, linaro-kernel, Catalin Marinas, patches,
	kgdb-bugreport, Linus Walleij, Nicolas Pitre, linux-kernel,
	Frederic Weisbecker, Anton Vorontsov, Ben Dooks, John Stultz,
	Fabio Estevam, Colin Cross, kernel-team, Dave Martin,
	linux-arm-kernel

On 15/07/14 14:04, Harro Haan wrote:
>> Makes sense.
>>
>> Avoiding this problem on GICv2 is easy (thanks to the aliased intack
>> register) but on iMX.6 we have only a GICv1.
>>
>>
>>> I can reduce the number of occurrences (not prevent it) by adding the
>>> following hack to irq-gic.c
>>> @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
>>> gic_handle_irq(struct pt_regs *regs
>>>   u32 irqstat, irqnr;
>>>   struct gic_chip_data *gic = &gic_data[0];
>>>   void __iomem *cpu_base = gic_data_cpu_base(gic);
>>>
>>>   do {
>>> + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
>>> & (1 << 30))
>>> +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
>>>   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>>>   irqnr = irqstat & ~0x1c00;
>>
>> I've made a more complete attempt to fix this. Could you test the
>> following? (and be prepared to fuzz the line numbers)
> 
> Thanks Daniel, I have tested it, see the comments below.
> 
>>
>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>> index 73ae896..309bf2c 100644
>> --- a/drivers/irqchip/irq-gic.c
>> +++ b/drivers/irqchip/irq-gic.c
>> @@ -303,6 +303,28 @@ static int gic_set_wake(struct irq_data *d,
>> unsigned int on)
>>  #define gic_set_wake   NULL
>>  #endif
>>
>> +/* Check for group 0 interrupt spuriously acked as a normal IRQ. This
>> + * workaround will only work for level triggered interrupts (and in
>> + * its current form is actively harmful on systems that don't support
>> + * FIQ).
>> + */
>> +static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32
>> irqstat)
>> +{
>> +       u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
>> +
>> +       if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
>> +               return irqnr;
>> +
>> +       if (readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_IGROUP +
>> +                         (irqnr / 32 * 4)) &
>> +           BIT(irqnr % 32))
>> +               return irqnr;
>> +
>> +       /* this interrupt was spurious (needs to be handled as FIQ) */
>> +       writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
> 
> This will NOT work, because of the note I mentioned above:
> "The FIQ exception will not occur anymore after gic_handle_irq
> read/acknowledges the FIQ by reading the GIC_CPU_INTACK register"
> So with this code you will say End Of Interrupt at the GIC level,
> without actually handling the interrupt, so you are missing an
> interrupt.
> I did the following test to confirm the missing interrupt:
> I have changed the periodic timer interrupt by an one-shot timer
> interrupt. The one-shot timer interrupt is programmed by the FIQ
> handler for the next FIQ interrupt. As expected: When the problem
> occurs, no more FIQ interrupts are generated.

Can you confirm whether your timer interrupts are configured level or
edge triggered? Or whether EOIing the GIC causes them to be cleared by
some other means.

A level triggered interrupt that hasn't been serviced should return the
pending state (shouldn't it?).


>> +       return 1023;
>> +}
>> +
>>  static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
>>  {
>>         u32 irqstat, irqnr;
>> @@ -310,8 +332,10 @@ static void __exception_irq_entry
>> gic_handle_irq(struct pt_regs *regs)
>>         void __iomem *cpu_base = gic_data_cpu_base(gic);
>>
>>         do {
>> +               local_fiq_disable();
> 
> It is a bit weird to disable the "Non-Maskable Interrupt" at every
> interrupt, because of a problem that occurs once every few thousand
> interrupts

Given that simply reading from GIC_CPU_INTACK has significantly
interferes with FIQ reception means that I'm not too worried about this.

Note also that leaving the FIQ unmasked increases worst case latency
here because once we get a group 0 interrupt back from intack then
spurious entry to the FIQ handler (which would see an ACK of 1023) just
wastes cycles.


>>                 irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>> -               irqnr = irqstat & GICC_IAR_INT_ID_MASK;
>> +               irqnr = gic_handle_spurious_group_0(gic, irqstat);
>> +               local_fiq_enable();
>>
>>                 if (likely(irqnr > 15 && irqnr < 1021)) {
>>                         irqnr = irq_find_mapping(gic->domain, irqnr);
> 
> 
> The following type of changes could fix the problem for me:
> 
> @@ -290,19 +290,66 @@ static int gic_set_wake(struct irq_data *d,
> unsigned int on)
> 
>  #else
>  #define gic_set_wake NULL
>  #endif
> 
> +extern void (*fiq_handler)(void);
> +
> +/* Check for group 0 interrupt spuriously acked as a normal IRQ. This
> + * workaround will only work for level triggered interrupts (and in
> + * its current form is actively harmful on systems that don't support
> + * FIQ).
> + */
> +static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32 irqstat)
> +{
> + u32 irqnr = irqstat & ~0x1c00;
> +
> + if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
> + return irqnr;
> +
> + if (readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_IGROUP +
> +  (irqnr / 32 * 4)) & BIT(irqnr % 32))
> + return irqnr;
> +
> + /*
> + * The FIQ should be disabled before the next FIQ interrupt occurs,
> + * so this only works when the next FIQ interrupt is not "too fast"
> + * after the previous one.
> + */
> + local_fiq_disable();
> +
> + /*
> + * Notes:
> + * - The FIQ exception will not occur anymore for this current
> + *   interrupt, because gic_handle_irq has already read/acknowledged
> + *   the GIC_CPU_INTACK register. So handle the FIQ here.
> + * - The fiq_handler below should not call ack_fiq and eoi_fiq,
> + *   because rereading the GIC_CPU_INTACK register returns spurious
> + *   interrupt ID 0x3FF. So probably you will have to add sometime like
> + *   the following to fiq_handler:
> + *   u32 cpsr, irqstat;
> + *   __asm__("mrs %0, cpsr" : "=r" (cpsr));
> + *   if ((cpsr & MODE_MASK) == FIQ_MODE)
> + *   irqstat = ack_fiq();
> + */
> + (*fiq_handler)();

Any portable approach would have to switch to FIQ mode to run the
handler in order to provide the proper register banks for FIQ handlers
written in assembler.

If we can't get level triggering to work then we have to:

1. Write code to jump correctly into FIQ mode.

2. Modify the gic's ack_fiq() callback to automatically avoid reading
   intack when the workaround is deployed.

The above is why I wanted to see if we can make do with level triggering
(and automatic re-triggering for interrupts such as SGIs that are
cleared by EOI).



^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v8 0/4] arm: KGDB NMI/FIQ support
@ 2014-07-15 14:52                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-15 14:52 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/07/14 14:04, Harro Haan wrote:
>> Makes sense.
>>
>> Avoiding this problem on GICv2 is easy (thanks to the aliased intack
>> register) but on iMX.6 we have only a GICv1.
>>
>>
>>> I can reduce the number of occurrences (not prevent it) by adding the
>>> following hack to irq-gic.c
>>> @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
>>> gic_handle_irq(struct pt_regs *regs
>>>   u32 irqstat, irqnr;
>>>   struct gic_chip_data *gic = &gic_data[0];
>>>   void __iomem *cpu_base = gic_data_cpu_base(gic);
>>>
>>>   do {
>>> + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
>>> & (1 << 30))
>>> +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
>>>   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>>>   irqnr = irqstat & ~0x1c00;
>>
>> I've made a more complete attempt to fix this. Could you test the
>> following? (and be prepared to fuzz the line numbers)
> 
> Thanks Daniel, I have tested it, see the comments below.
> 
>>
>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>> index 73ae896..309bf2c 100644
>> --- a/drivers/irqchip/irq-gic.c
>> +++ b/drivers/irqchip/irq-gic.c
>> @@ -303,6 +303,28 @@ static int gic_set_wake(struct irq_data *d,
>> unsigned int on)
>>  #define gic_set_wake   NULL
>>  #endif
>>
>> +/* Check for group 0 interrupt spuriously acked as a normal IRQ. This
>> + * workaround will only work for level triggered interrupts (and in
>> + * its current form is actively harmful on systems that don't support
>> + * FIQ).
>> + */
>> +static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32
>> irqstat)
>> +{
>> +       u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
>> +
>> +       if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
>> +               return irqnr;
>> +
>> +       if (readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_IGROUP +
>> +                         (irqnr / 32 * 4)) &
>> +           BIT(irqnr % 32))
>> +               return irqnr;
>> +
>> +       /* this interrupt was spurious (needs to be handled as FIQ) */
>> +       writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
> 
> This will NOT work, because of the note I mentioned above:
> "The FIQ exception will not occur anymore after gic_handle_irq
> read/acknowledges the FIQ by reading the GIC_CPU_INTACK register"
> So with this code you will say End Of Interrupt at the GIC level,
> without actually handling the interrupt, so you are missing an
> interrupt.
> I did the following test to confirm the missing interrupt:
> I have changed the periodic timer interrupt by an one-shot timer
> interrupt. The one-shot timer interrupt is programmed by the FIQ
> handler for the next FIQ interrupt. As expected: When the problem
> occurs, no more FIQ interrupts are generated.

Can you confirm whether your timer interrupts are configured level or
edge triggered? Or whether EOIing the GIC causes them to be cleared by
some other means.

A level triggered interrupt that hasn't been serviced should return the
pending state (shouldn't it?).


>> +       return 1023;
>> +}
>> +
>>  static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
>>  {
>>         u32 irqstat, irqnr;
>> @@ -310,8 +332,10 @@ static void __exception_irq_entry
>> gic_handle_irq(struct pt_regs *regs)
>>         void __iomem *cpu_base = gic_data_cpu_base(gic);
>>
>>         do {
>> +               local_fiq_disable();
> 
> It is a bit weird to disable the "Non-Maskable Interrupt" at every
> interrupt, because of a problem that occurs once every few thousand
> interrupts

Given that simply reading from GIC_CPU_INTACK has significantly
interferes with FIQ reception means that I'm not too worried about this.

Note also that leaving the FIQ unmasked increases worst case latency
here because once we get a group 0 interrupt back from intack then
spurious entry to the FIQ handler (which would see an ACK of 1023) just
wastes cycles.


>>                 irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>> -               irqnr = irqstat & GICC_IAR_INT_ID_MASK;
>> +               irqnr = gic_handle_spurious_group_0(gic, irqstat);
>> +               local_fiq_enable();
>>
>>                 if (likely(irqnr > 15 && irqnr < 1021)) {
>>                         irqnr = irq_find_mapping(gic->domain, irqnr);
> 
> 
> The following type of changes could fix the problem for me:
> 
> @@ -290,19 +290,66 @@ static int gic_set_wake(struct irq_data *d,
> unsigned int on)
> 
>  #else
>  #define gic_set_wake NULL
>  #endif
> 
> +extern void (*fiq_handler)(void);
> +
> +/* Check for group 0 interrupt spuriously acked as a normal IRQ. This
> + * workaround will only work for level triggered interrupts (and in
> + * its current form is actively harmful on systems that don't support
> + * FIQ).
> + */
> +static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32 irqstat)
> +{
> + u32 irqnr = irqstat & ~0x1c00;
> +
> + if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
> + return irqnr;
> +
> + if (readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_IGROUP +
> +  (irqnr / 32 * 4)) & BIT(irqnr % 32))
> + return irqnr;
> +
> + /*
> + * The FIQ should be disabled before the next FIQ interrupt occurs,
> + * so this only works when the next FIQ interrupt is not "too fast"
> + * after the previous one.
> + */
> + local_fiq_disable();
> +
> + /*
> + * Notes:
> + * - The FIQ exception will not occur anymore for this current
> + *   interrupt, because gic_handle_irq has already read/acknowledged
> + *   the GIC_CPU_INTACK register. So handle the FIQ here.
> + * - The fiq_handler below should not call ack_fiq and eoi_fiq,
> + *   because rereading the GIC_CPU_INTACK register returns spurious
> + *   interrupt ID 0x3FF. So probably you will have to add sometime like
> + *   the following to fiq_handler:
> + *   u32 cpsr, irqstat;
> + *   __asm__("mrs %0, cpsr" : "=r" (cpsr));
> + *   if ((cpsr & MODE_MASK) == FIQ_MODE)
> + *   irqstat = ack_fiq();
> + */
> + (*fiq_handler)();

Any portable approach would have to switch to FIQ mode to run the
handler in order to provide the proper register banks for FIQ handlers
written in assembler.

If we can't get level triggering to work then we have to:

1. Write code to jump correctly into FIQ mode.

2. Modify the gic's ack_fiq() callback to automatically avoid reading
   intack when the workaround is deployed.

The above is why I wanted to see if we can make do with level triggering
(and automatic re-triggering for interrupts such as SGIs that are
cleared by EOI).

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support
  2014-07-15 14:52                     ` Daniel Thompson
@ 2014-07-15 15:59                       ` Harro Haan
  -1 siblings, 0 replies; 535+ messages in thread
From: Harro Haan @ 2014-07-15 15:59 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Russell King, linaro-kernel, Catalin Marinas, patches,
	kgdb-bugreport, Linus Walleij, Nicolas Pitre, linux-kernel,
	Frederic Weisbecker, Anton Vorontsov, Ben Dooks, John Stultz,
	Fabio Estevam, Colin Cross, kernel-team, Dave Martin,
	linux-arm-kernel

On 15 July 2014 16:52, Daniel Thompson <daniel.thompson@linaro.org> wrote:
> On 15/07/14 14:04, Harro Haan wrote:
>>> Makes sense.
>>>
>>> Avoiding this problem on GICv2 is easy (thanks to the aliased intack
>>> register) but on iMX.6 we have only a GICv1.
>>>
>>>
>>>> I can reduce the number of occurrences (not prevent it) by adding the
>>>> following hack to irq-gic.c
>>>> @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
>>>> gic_handle_irq(struct pt_regs *regs
>>>>   u32 irqstat, irqnr;
>>>>   struct gic_chip_data *gic = &gic_data[0];
>>>>   void __iomem *cpu_base = gic_data_cpu_base(gic);
>>>>
>>>>   do {
>>>> + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
>>>> & (1 << 30))
>>>> +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
>>>>   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>>>>   irqnr = irqstat & ~0x1c00;
>>>
>>> I've made a more complete attempt to fix this. Could you test the
>>> following? (and be prepared to fuzz the line numbers)
>>
>> Thanks Daniel, I have tested it, see the comments below.
>>
>>>
>>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>>> index 73ae896..309bf2c 100644
>>> --- a/drivers/irqchip/irq-gic.c
>>> +++ b/drivers/irqchip/irq-gic.c
>>> @@ -303,6 +303,28 @@ static int gic_set_wake(struct irq_data *d,
>>> unsigned int on)
>>>  #define gic_set_wake   NULL
>>>  #endif
>>>
>>> +/* Check for group 0 interrupt spuriously acked as a normal IRQ. This
>>> + * workaround will only work for level triggered interrupts (and in
>>> + * its current form is actively harmful on systems that don't support
>>> + * FIQ).
>>> + */
>>> +static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32
>>> irqstat)
>>> +{
>>> +       u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
>>> +
>>> +       if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
>>> +               return irqnr;
>>> +
>>> +       if (readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_IGROUP +
>>> +                         (irqnr / 32 * 4)) &
>>> +           BIT(irqnr % 32))
>>> +               return irqnr;
>>> +
>>> +       /* this interrupt was spurious (needs to be handled as FIQ) */
>>> +       writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
>>
>> This will NOT work, because of the note I mentioned above:
>> "The FIQ exception will not occur anymore after gic_handle_irq
>> read/acknowledges the FIQ by reading the GIC_CPU_INTACK register"
>> So with this code you will say End Of Interrupt at the GIC level,
>> without actually handling the interrupt, so you are missing an
>> interrupt.
>> I did the following test to confirm the missing interrupt:
>> I have changed the periodic timer interrupt by an one-shot timer
>> interrupt. The one-shot timer interrupt is programmed by the FIQ
>> handler for the next FIQ interrupt. As expected: When the problem
>> occurs, no more FIQ interrupts are generated.
>
> Can you confirm whether your timer interrupts are configured level or
> edge triggered? Or whether EOIing the GIC causes them to be cleared by
> some other means.

>From page 48 of DDI0407I_cortex_a9_mpcore_r4p1_trm.pdf:
Watchdog timers, PPI(3)
Each Cortex-A9 processor has its own watchdog timers that can generate
interrupts, using ID30.

>From page 56:
PPI[0], [2],and[3]:b11
interrupt is rising-edge sensitive.

>
> A level triggered interrupt that hasn't been serviced should return the
> pending state (shouldn't it?).
>
>
>>> +       return 1023;
>>> +}
>>> +
>>>  static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
>>>  {
>>>         u32 irqstat, irqnr;
>>> @@ -310,8 +332,10 @@ static void __exception_irq_entry
>>> gic_handle_irq(struct pt_regs *regs)
>>>         void __iomem *cpu_base = gic_data_cpu_base(gic);
>>>
>>>         do {
>>> +               local_fiq_disable();
>>
>> It is a bit weird to disable the "Non-Maskable Interrupt" at every
>> interrupt, because of a problem that occurs once every few thousand
>> interrupts
>
> Given that simply reading from GIC_CPU_INTACK has significantly
> interferes with FIQ reception means that I'm not too worried about this.
>
> Note also that leaving the FIQ unmasked increases worst case latency
> here because once we get a group 0 interrupt back from intack then
> spurious entry to the FIQ handler (which would see an ACK of 1023) just
> wastes cycles.
>
>
>>>                 irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>>> -               irqnr = irqstat & GICC_IAR_INT_ID_MASK;
>>> +               irqnr = gic_handle_spurious_group_0(gic, irqstat);
>>> +               local_fiq_enable();
>>>
>>>                 if (likely(irqnr > 15 && irqnr < 1021)) {
>>>                         irqnr = irq_find_mapping(gic->domain, irqnr);
>>
>>
>> The following type of changes could fix the problem for me:
>>
>> @@ -290,19 +290,66 @@ static int gic_set_wake(struct irq_data *d,
>> unsigned int on)
>>
>>  #else
>>  #define gic_set_wake NULL
>>  #endif
>>
>> +extern void (*fiq_handler)(void);
>> +
>> +/* Check for group 0 interrupt spuriously acked as a normal IRQ. This
>> + * workaround will only work for level triggered interrupts (and in
>> + * its current form is actively harmful on systems that don't support
>> + * FIQ).
>> + */
>> +static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32 irqstat)
>> +{
>> + u32 irqnr = irqstat & ~0x1c00;
>> +
>> + if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
>> + return irqnr;
>> +
>> + if (readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_IGROUP +
>> +  (irqnr / 32 * 4)) & BIT(irqnr % 32))
>> + return irqnr;
>> +
>> + /*
>> + * The FIQ should be disabled before the next FIQ interrupt occurs,
>> + * so this only works when the next FIQ interrupt is not "too fast"
>> + * after the previous one.
>> + */
>> + local_fiq_disable();
>> +
>> + /*
>> + * Notes:
>> + * - The FIQ exception will not occur anymore for this current
>> + *   interrupt, because gic_handle_irq has already read/acknowledged
>> + *   the GIC_CPU_INTACK register. So handle the FIQ here.
>> + * - The fiq_handler below should not call ack_fiq and eoi_fiq,
>> + *   because rereading the GIC_CPU_INTACK register returns spurious
>> + *   interrupt ID 0x3FF. So probably you will have to add sometime like
>> + *   the following to fiq_handler:
>> + *   u32 cpsr, irqstat;
>> + *   __asm__("mrs %0, cpsr" : "=r" (cpsr));
>> + *   if ((cpsr & MODE_MASK) == FIQ_MODE)
>> + *   irqstat = ack_fiq();
>> + */
>> + (*fiq_handler)();
>
> Any portable approach would have to switch to FIQ mode to run the
> handler in order to provide the proper register banks for FIQ handlers
> written in assembler.
>
> If we can't get level triggering to work then we have to:
>
> 1. Write code to jump correctly into FIQ mode.
>
> 2. Modify the gic's ack_fiq() callback to automatically avoid reading
>    intack when the workaround is deployed.
>
> The above is why I wanted to see if we can make do with level triggering
> (and automatic re-triggering for interrupts such as SGIs that are
> cleared by EOI).

But the re-triggering introduces extra latencies and a lot of use
cases of FIQ's try to avoid that.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v8 0/4] arm: KGDB NMI/FIQ support
@ 2014-07-15 15:59                       ` Harro Haan
  0 siblings, 0 replies; 535+ messages in thread
From: Harro Haan @ 2014-07-15 15:59 UTC (permalink / raw)
  To: linux-arm-kernel

On 15 July 2014 16:52, Daniel Thompson <daniel.thompson@linaro.org> wrote:
> On 15/07/14 14:04, Harro Haan wrote:
>>> Makes sense.
>>>
>>> Avoiding this problem on GICv2 is easy (thanks to the aliased intack
>>> register) but on iMX.6 we have only a GICv1.
>>>
>>>
>>>> I can reduce the number of occurrences (not prevent it) by adding the
>>>> following hack to irq-gic.c
>>>> @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
>>>> gic_handle_irq(struct pt_regs *regs
>>>>   u32 irqstat, irqnr;
>>>>   struct gic_chip_data *gic = &gic_data[0];
>>>>   void __iomem *cpu_base = gic_data_cpu_base(gic);
>>>>
>>>>   do {
>>>> + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
>>>> & (1 << 30))
>>>> +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
>>>>   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>>>>   irqnr = irqstat & ~0x1c00;
>>>
>>> I've made a more complete attempt to fix this. Could you test the
>>> following? (and be prepared to fuzz the line numbers)
>>
>> Thanks Daniel, I have tested it, see the comments below.
>>
>>>
>>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>>> index 73ae896..309bf2c 100644
>>> --- a/drivers/irqchip/irq-gic.c
>>> +++ b/drivers/irqchip/irq-gic.c
>>> @@ -303,6 +303,28 @@ static int gic_set_wake(struct irq_data *d,
>>> unsigned int on)
>>>  #define gic_set_wake   NULL
>>>  #endif
>>>
>>> +/* Check for group 0 interrupt spuriously acked as a normal IRQ. This
>>> + * workaround will only work for level triggered interrupts (and in
>>> + * its current form is actively harmful on systems that don't support
>>> + * FIQ).
>>> + */
>>> +static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32
>>> irqstat)
>>> +{
>>> +       u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
>>> +
>>> +       if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
>>> +               return irqnr;
>>> +
>>> +       if (readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_IGROUP +
>>> +                         (irqnr / 32 * 4)) &
>>> +           BIT(irqnr % 32))
>>> +               return irqnr;
>>> +
>>> +       /* this interrupt was spurious (needs to be handled as FIQ) */
>>> +       writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
>>
>> This will NOT work, because of the note I mentioned above:
>> "The FIQ exception will not occur anymore after gic_handle_irq
>> read/acknowledges the FIQ by reading the GIC_CPU_INTACK register"
>> So with this code you will say End Of Interrupt at the GIC level,
>> without actually handling the interrupt, so you are missing an
>> interrupt.
>> I did the following test to confirm the missing interrupt:
>> I have changed the periodic timer interrupt by an one-shot timer
>> interrupt. The one-shot timer interrupt is programmed by the FIQ
>> handler for the next FIQ interrupt. As expected: When the problem
>> occurs, no more FIQ interrupts are generated.
>
> Can you confirm whether your timer interrupts are configured level or
> edge triggered? Or whether EOIing the GIC causes them to be cleared by
> some other means.

>From page 48 of DDI0407I_cortex_a9_mpcore_r4p1_trm.pdf:
Watchdog timers, PPI(3)
Each Cortex-A9 processor has its own watchdog timers that can generate
interrupts, using ID30.

>From page 56:
PPI[0], [2],and[3]:b11
interrupt is rising-edge sensitive.

>
> A level triggered interrupt that hasn't been serviced should return the
> pending state (shouldn't it?).
>
>
>>> +       return 1023;
>>> +}
>>> +
>>>  static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
>>>  {
>>>         u32 irqstat, irqnr;
>>> @@ -310,8 +332,10 @@ static void __exception_irq_entry
>>> gic_handle_irq(struct pt_regs *regs)
>>>         void __iomem *cpu_base = gic_data_cpu_base(gic);
>>>
>>>         do {
>>> +               local_fiq_disable();
>>
>> It is a bit weird to disable the "Non-Maskable Interrupt" at every
>> interrupt, because of a problem that occurs once every few thousand
>> interrupts
>
> Given that simply reading from GIC_CPU_INTACK has significantly
> interferes with FIQ reception means that I'm not too worried about this.
>
> Note also that leaving the FIQ unmasked increases worst case latency
> here because once we get a group 0 interrupt back from intack then
> spurious entry to the FIQ handler (which would see an ACK of 1023) just
> wastes cycles.
>
>
>>>                 irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>>> -               irqnr = irqstat & GICC_IAR_INT_ID_MASK;
>>> +               irqnr = gic_handle_spurious_group_0(gic, irqstat);
>>> +               local_fiq_enable();
>>>
>>>                 if (likely(irqnr > 15 && irqnr < 1021)) {
>>>                         irqnr = irq_find_mapping(gic->domain, irqnr);
>>
>>
>> The following type of changes could fix the problem for me:
>>
>> @@ -290,19 +290,66 @@ static int gic_set_wake(struct irq_data *d,
>> unsigned int on)
>>
>>  #else
>>  #define gic_set_wake NULL
>>  #endif
>>
>> +extern void (*fiq_handler)(void);
>> +
>> +/* Check for group 0 interrupt spuriously acked as a normal IRQ. This
>> + * workaround will only work for level triggered interrupts (and in
>> + * its current form is actively harmful on systems that don't support
>> + * FIQ).
>> + */
>> +static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32 irqstat)
>> +{
>> + u32 irqnr = irqstat & ~0x1c00;
>> +
>> + if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
>> + return irqnr;
>> +
>> + if (readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_IGROUP +
>> +  (irqnr / 32 * 4)) & BIT(irqnr % 32))
>> + return irqnr;
>> +
>> + /*
>> + * The FIQ should be disabled before the next FIQ interrupt occurs,
>> + * so this only works when the next FIQ interrupt is not "too fast"
>> + * after the previous one.
>> + */
>> + local_fiq_disable();
>> +
>> + /*
>> + * Notes:
>> + * - The FIQ exception will not occur anymore for this current
>> + *   interrupt, because gic_handle_irq has already read/acknowledged
>> + *   the GIC_CPU_INTACK register. So handle the FIQ here.
>> + * - The fiq_handler below should not call ack_fiq and eoi_fiq,
>> + *   because rereading the GIC_CPU_INTACK register returns spurious
>> + *   interrupt ID 0x3FF. So probably you will have to add sometime like
>> + *   the following to fiq_handler:
>> + *   u32 cpsr, irqstat;
>> + *   __asm__("mrs %0, cpsr" : "=r" (cpsr));
>> + *   if ((cpsr & MODE_MASK) == FIQ_MODE)
>> + *   irqstat = ack_fiq();
>> + */
>> + (*fiq_handler)();
>
> Any portable approach would have to switch to FIQ mode to run the
> handler in order to provide the proper register banks for FIQ handlers
> written in assembler.
>
> If we can't get level triggering to work then we have to:
>
> 1. Write code to jump correctly into FIQ mode.
>
> 2. Modify the gic's ack_fiq() callback to automatically avoid reading
>    intack when the workaround is deployed.
>
> The above is why I wanted to see if we can make do with level triggering
> (and automatic re-triggering for interrupts such as SGIs that are
> cleared by EOI).

But the re-triggering introduces extra latencies and a lot of use
cases of FIQ's try to avoid that.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support
  2014-07-15 15:59                       ` Harro Haan
@ 2014-07-15 17:08                         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-15 17:08 UTC (permalink / raw)
  To: Harro Haan
  Cc: Russell King, linaro-kernel, Catalin Marinas, patches,
	kgdb-bugreport, Linus Walleij, Nicolas Pitre, linux-kernel,
	Frederic Weisbecker, Anton Vorontsov, Ben Dooks, John Stultz,
	Fabio Estevam, Colin Cross, kernel-team, Dave Martin,
	linux-arm-kernel

On 15/07/14 16:59, Harro Haan wrote:
> On 15 July 2014 16:52, Daniel Thompson <daniel.thompson@linaro.org> wrote:
>> On 15/07/14 14:04, Harro Haan wrote:
>>>> Makes sense.
>>>>
>>>> Avoiding this problem on GICv2 is easy (thanks to the aliased intack
>>>> register) but on iMX.6 we have only a GICv1.
>>>>
>>>>
>>>>> I can reduce the number of occurrences (not prevent it) by adding the
>>>>> following hack to irq-gic.c
>>>>> @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
>>>>> gic_handle_irq(struct pt_regs *regs
>>>>>   u32 irqstat, irqnr;
>>>>>   struct gic_chip_data *gic = &gic_data[0];
>>>>>   void __iomem *cpu_base = gic_data_cpu_base(gic);
>>>>>
>>>>>   do {
>>>>> + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
>>>>> & (1 << 30))
>>>>> +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
>>>>>   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>>>>>   irqnr = irqstat & ~0x1c00;
>>>>
>>>> I've made a more complete attempt to fix this. Could you test the
>>>> following? (and be prepared to fuzz the line numbers)
>>>
>>> Thanks Daniel, I have tested it, see the comments below.
>>>
>>>>
>>>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>>>> index 73ae896..309bf2c 100644
>>>> --- a/drivers/irqchip/irq-gic.c
>>>> +++ b/drivers/irqchip/irq-gic.c
>>>> @@ -303,6 +303,28 @@ static int gic_set_wake(struct irq_data *d,
>>>> unsigned int on)
>>>>  #define gic_set_wake   NULL
>>>>  #endif
>>>>
>>>> +/* Check for group 0 interrupt spuriously acked as a normal IRQ. This
>>>> + * workaround will only work for level triggered interrupts (and in
>>>> + * its current form is actively harmful on systems that don't support
>>>> + * FIQ).
>>>> + */
>>>> +static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32
>>>> irqstat)
>>>> +{
>>>> +       u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
>>>> +
>>>> +       if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
>>>> +               return irqnr;
>>>> +
>>>> +       if (readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_IGROUP +
>>>> +                         (irqnr / 32 * 4)) &
>>>> +           BIT(irqnr % 32))
>>>> +               return irqnr;
>>>> +
>>>> +       /* this interrupt was spurious (needs to be handled as FIQ) */
>>>> +       writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
>>>
>>> This will NOT work, because of the note I mentioned above:
>>> "The FIQ exception will not occur anymore after gic_handle_irq
>>> read/acknowledges the FIQ by reading the GIC_CPU_INTACK register"
>>> So with this code you will say End Of Interrupt at the GIC level,
>>> without actually handling the interrupt, so you are missing an
>>> interrupt.
>>> I did the following test to confirm the missing interrupt:
>>> I have changed the periodic timer interrupt by an one-shot timer
>>> interrupt. The one-shot timer interrupt is programmed by the FIQ
>>> handler for the next FIQ interrupt. As expected: When the problem
>>> occurs, no more FIQ interrupts are generated.
>>
>> Can you confirm whether your timer interrupts are configured level or
>> edge triggered? Or whether EOIing the GIC causes them to be cleared by
>> some other means.
> 
> From page 48 of DDI0407I_cortex_a9_mpcore_r4p1_trm.pdf:
> Watchdog timers, PPI(3)
> Each Cortex-A9 processor has its own watchdog timers that can generate
> interrupts, using ID30.
> 
> From page 56:
> PPI[0], [2],and[3]:b11
> interrupt is rising-edge sensitive.

Thanks. This is clear.


>> If we can't get level triggering to work then we have to:
>>
>> 1. Write code to jump correctly into FIQ mode.
>>
>> 2. Modify the gic's ack_fiq() callback to automatically avoid reading
>>    intack when the workaround is deployed.
>>
>> The above is why I wanted to see if we can make do with level triggering
>> (and automatic re-triggering for interrupts such as SGIs that are
>> cleared by EOI).
> 
> But the re-triggering introduces extra latencies and a lot of use
> cases of FIQ's try to avoid that.

I'm not really clear why retriggering should be significantly more
expensive than the dance required to fake up entry the FIQ handler.

On the other hand retriggering allows us to avoid hacks in the FIQ
handler to stop it acknowledging the interrupt. Given hacks like that
won't be needed on A7/A15 this seems like a good outcome.

Anyhow I've put together a new version of my earlier patch that I think
will retrigger all interrupts except SGIs (I'll look at SGIs and
compatibility with non-Freescale parts only if this improved approach
works).

Reported-by: Harro Haan <hrhaan@gmail.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/irqchip/irq-gic.c | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 73ae896..88f92e6 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -303,6 +303,33 @@ static int gic_set_wake(struct irq_data *d,
unsigned int on)
 #define gic_set_wake	NULL
 #endif

+/* This is a software emulation of the Aliased Interrupt Acknowledge
Register
+ * (GIC_AIAR) found in GICv2+.
+ */
+static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32
irqstat)
+{
+	u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	void __iomem *dist_base = gic_data_dist_base(gic);
+	u32 offset, mask;
+
+	if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
+		return irqnr;
+
+	offset = irqnr / 32 * 4;
+	mask = 1 << (irqnr % 32);
+	if (readl_relaxed(dist_base + GIC_DIST_IGROUP + offset) & mask)
+		return irqnr;
+
+	/* this interrupt must be taken as a FIQ so put it back into the
+	 * pending state and end our own servicing of it.
+	 */
+	writel_relaxed(mask, dist_base + GIC_DIST_PENDING_SET + offset);
+	readl_relaxed(dist_base + GIC_DIST_PENDING_SET + offset);
+	writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
+
+	return 1023;
+}
+
 static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
 	u32 irqstat, irqnr;
@@ -310,8 +337,10 @@ static void __exception_irq_entry
gic_handle_irq(struct pt_regs *regs)
 	void __iomem *cpu_base = gic_data_cpu_base(gic);

 	do {
+		local_fiq_disable();
 		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
-		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		irqnr = gic_handle_spurious_group_0(gic, irqstat);
+		local_fiq_enable();

 		if (likely(irqnr > 15 && irqnr < 1021)) {
 			irqnr = irq_find_mapping(gic->domain, irqnr);
-- 
1.9.3




^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v8 0/4] arm: KGDB NMI/FIQ support
@ 2014-07-15 17:08                         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-15 17:08 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/07/14 16:59, Harro Haan wrote:
> On 15 July 2014 16:52, Daniel Thompson <daniel.thompson@linaro.org> wrote:
>> On 15/07/14 14:04, Harro Haan wrote:
>>>> Makes sense.
>>>>
>>>> Avoiding this problem on GICv2 is easy (thanks to the aliased intack
>>>> register) but on iMX.6 we have only a GICv1.
>>>>
>>>>
>>>>> I can reduce the number of occurrences (not prevent it) by adding the
>>>>> following hack to irq-gic.c
>>>>> @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
>>>>> gic_handle_irq(struct pt_regs *regs
>>>>>   u32 irqstat, irqnr;
>>>>>   struct gic_chip_data *gic = &gic_data[0];
>>>>>   void __iomem *cpu_base = gic_data_cpu_base(gic);
>>>>>
>>>>>   do {
>>>>> + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
>>>>> & (1 << 30))
>>>>> +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
>>>>>   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>>>>>   irqnr = irqstat & ~0x1c00;
>>>>
>>>> I've made a more complete attempt to fix this. Could you test the
>>>> following? (and be prepared to fuzz the line numbers)
>>>
>>> Thanks Daniel, I have tested it, see the comments below.
>>>
>>>>
>>>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>>>> index 73ae896..309bf2c 100644
>>>> --- a/drivers/irqchip/irq-gic.c
>>>> +++ b/drivers/irqchip/irq-gic.c
>>>> @@ -303,6 +303,28 @@ static int gic_set_wake(struct irq_data *d,
>>>> unsigned int on)
>>>>  #define gic_set_wake   NULL
>>>>  #endif
>>>>
>>>> +/* Check for group 0 interrupt spuriously acked as a normal IRQ. This
>>>> + * workaround will only work for level triggered interrupts (and in
>>>> + * its current form is actively harmful on systems that don't support
>>>> + * FIQ).
>>>> + */
>>>> +static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32
>>>> irqstat)
>>>> +{
>>>> +       u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
>>>> +
>>>> +       if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
>>>> +               return irqnr;
>>>> +
>>>> +       if (readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_IGROUP +
>>>> +                         (irqnr / 32 * 4)) &
>>>> +           BIT(irqnr % 32))
>>>> +               return irqnr;
>>>> +
>>>> +       /* this interrupt was spurious (needs to be handled as FIQ) */
>>>> +       writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
>>>
>>> This will NOT work, because of the note I mentioned above:
>>> "The FIQ exception will not occur anymore after gic_handle_irq
>>> read/acknowledges the FIQ by reading the GIC_CPU_INTACK register"
>>> So with this code you will say End Of Interrupt at the GIC level,
>>> without actually handling the interrupt, so you are missing an
>>> interrupt.
>>> I did the following test to confirm the missing interrupt:
>>> I have changed the periodic timer interrupt by an one-shot timer
>>> interrupt. The one-shot timer interrupt is programmed by the FIQ
>>> handler for the next FIQ interrupt. As expected: When the problem
>>> occurs, no more FIQ interrupts are generated.
>>
>> Can you confirm whether your timer interrupts are configured level or
>> edge triggered? Or whether EOIing the GIC causes them to be cleared by
>> some other means.
> 
> From page 48 of DDI0407I_cortex_a9_mpcore_r4p1_trm.pdf:
> Watchdog timers, PPI(3)
> Each Cortex-A9 processor has its own watchdog timers that can generate
> interrupts, using ID30.
> 
> From page 56:
> PPI[0], [2],and[3]:b11
> interrupt is rising-edge sensitive.

Thanks. This is clear.


>> If we can't get level triggering to work then we have to:
>>
>> 1. Write code to jump correctly into FIQ mode.
>>
>> 2. Modify the gic's ack_fiq() callback to automatically avoid reading
>>    intack when the workaround is deployed.
>>
>> The above is why I wanted to see if we can make do with level triggering
>> (and automatic re-triggering for interrupts such as SGIs that are
>> cleared by EOI).
> 
> But the re-triggering introduces extra latencies and a lot of use
> cases of FIQ's try to avoid that.

I'm not really clear why retriggering should be significantly more
expensive than the dance required to fake up entry the FIQ handler.

On the other hand retriggering allows us to avoid hacks in the FIQ
handler to stop it acknowledging the interrupt. Given hacks like that
won't be needed on A7/A15 this seems like a good outcome.

Anyhow I've put together a new version of my earlier patch that I think
will retrigger all interrupts except SGIs (I'll look at SGIs and
compatibility with non-Freescale parts only if this improved approach
works).

Reported-by: Harro Haan <hrhaan@gmail.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/irqchip/irq-gic.c | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 73ae896..88f92e6 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -303,6 +303,33 @@ static int gic_set_wake(struct irq_data *d,
unsigned int on)
 #define gic_set_wake	NULL
 #endif

+/* This is a software emulation of the Aliased Interrupt Acknowledge
Register
+ * (GIC_AIAR) found in GICv2+.
+ */
+static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32
irqstat)
+{
+	u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	void __iomem *dist_base = gic_data_dist_base(gic);
+	u32 offset, mask;
+
+	if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
+		return irqnr;
+
+	offset = irqnr / 32 * 4;
+	mask = 1 << (irqnr % 32);
+	if (readl_relaxed(dist_base + GIC_DIST_IGROUP + offset) & mask)
+		return irqnr;
+
+	/* this interrupt must be taken as a FIQ so put it back into the
+	 * pending state and end our own servicing of it.
+	 */
+	writel_relaxed(mask, dist_base + GIC_DIST_PENDING_SET + offset);
+	readl_relaxed(dist_base + GIC_DIST_PENDING_SET + offset);
+	writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
+
+	return 1023;
+}
+
 static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
 	u32 irqstat, irqnr;
@@ -310,8 +337,10 @@ static void __exception_irq_entry
gic_handle_irq(struct pt_regs *regs)
 	void __iomem *cpu_base = gic_data_cpu_base(gic);

 	do {
+		local_fiq_disable();
 		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
-		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		irqnr = gic_handle_spurious_group_0(gic, irqstat);
+		local_fiq_enable();

 		if (likely(irqnr > 15 && irqnr < 1021)) {
 			irqnr = irq_find_mapping(gic->domain, irqnr);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support
  2014-07-15  9:41                 ` Daniel Thompson
@ 2014-07-15 18:45                   ` Marek Vasut
  -1 siblings, 0 replies; 535+ messages in thread
From: Marek Vasut @ 2014-07-15 18:45 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Daniel Thompson, Harro Haan, linaro-kernel, Russell King,
	patches, kgdb-bugreport, Linus Walleij, Nicolas Pitre,
	linux-kernel, Colin Cross, Anton Vorontsov, Ben Dooks,
	John Stultz, Fabio Estevam, Catalin Marinas, kernel-team,
	Frederic Weisbecker, Dave Martin, Detlev Zundel

On Tuesday, July 15, 2014 at 11:41:25 AM, Daniel Thompson wrote:
> On 14/07/14 14:51, Harro Haan wrote:
> > On 10 July 2014 10:03, Daniel Thompson <daniel.thompson@linaro.org> wrote:
> >> This patchset makes it possible to use kgdb's NMI infrastructure on ARM
> >> platforms.
> >> 
> >> The patches have been previously circulated as part of a large patchset
> >> mixing together ARM architecture code and driver changes
> >> (http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901 ). This
> >> patchset is dramatically cut down to include only the arch/arm code. The
> >> driver code (irqchip and tty/serial) will follow when/if the arch code
> >> is accepted.
> >> 
> >> The first two patches modify the FIQ infrastructure to allow interrupt
> >> controller drivers to register callbacks (the fiq_chip structure) to
> >> manage FIQ routings and to ACK and EOI the FIQ. This makes it possible
> >> to use FIQ in multi-platform kernels and with recent ARM interrupt
> >> controllers.
> > 
> > Daniel,
> > 
> > Thanks for the patches. I have tested the fiq and irq-gic patches on
> > an i.MX6 (SabreSD board) for a different purpose:
> > A FIQ timer interrupt at 1 kHz. The TWD watchdog block is used in
> > timer mode for this (interrupt ID 30). The GIC affinity is set to CPU
> > core 0 only for this interrupt ID.
> > 
> > I was surprised by the following behavior:
> > $ cat /proc/interrupts
> > 
> >            CPU0       CPU1       CPU2       CPU3
> >  
> >  29:       5459       3381       3175       3029       GIC  29  twd
> >  30:         11          0          0          0       GIC  30  fake-fiq
> > 
> > Once every few seconds is interrupt ID 30 handled by the regular GIC
> > handler instead of the FIQ exception path (which causes for example a
> > bit more latencies). The other thousands of FIQ's are handled by the
> > FIQ exception path. The problem is also confirmed by the following
> > stackframe of the Lauterbach tooling:
> > fake_fiq_handler(irq = 30, ...)
> > handle_percpu_devid_irq(irq = 30, ...)
> > generic_handle_irq(irq = 30)
> > handle_IRQ(irq = 30, ...)
> > gic_handle_irq
> > __irq_svc
> > -->exception
> > 
> > Notes:
> > 
> > - The problem will occur more often by executing the following command:
> >   $ while true; do hackbench 20; done &
> > 
> > - Reading the GIC_CPU_INTACK register returns the interrupt ID of the
> > highest priority pending interrupt.
> > - The GIC_CPU_INTACK register (used by fiq_ack) will return spurious
> > interrupt ID 0x3FF when read in fake_fiq_handler, because
> > GIC_CPU_INTACK is already read by gic_handle_irq.
> > - The FIQ exception will not occur anymore after gic_handle_irq
> > read/acknowledges the FIQ by reading the GIC_CPU_INTACK register
> > 
> > From the behavior above I conclude that the GIC_CPU_INTACK register is
> > first updated before the FIQ exception is generated, so there is a
> > small period of time that gic_handle_irq can read/acknowledge the FIQ.
> 
> Makes sense.
> 
> Avoiding this problem on GICv2 is easy (thanks to the aliased intack
> register) but on iMX.6 we have only a GICv1.

Yep.

> > I can reduce the number of occurrences (not prevent it) by adding the
> > following hack to irq-gic.c
> > @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
> > gic_handle_irq(struct pt_regs *regs
> > 
> >   u32 irqstat, irqnr;
> >   struct gic_chip_data *gic = &gic_data[0];
> >   void __iomem *cpu_base = gic_data_cpu_base(gic);
> >   
> >   do {
> > 
> > + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
> > & (1 << 30))
> > +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
> > 
> >   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
> >   irqnr = irqstat & ~0x1c00;
> 
> I've made a more complete attempt to fix this. Could you test the
> following? (and be prepared to fuzz the line numbers)

There's also another workaround, look at [1], but it's really a perverse hack 
thus far (blush). What I did there is I got hinted that an L1 page table can 
have this NS bit set. If this bit is set for a mapping, all accesses to memory 
area via that mapping will be non-secure. And then, in turn, by doing a non-
secure read of the INTACK register, it will not ever happen that the FIQ number 
will pop up in the INTACK. I only do a non-secure read of the INTACK register,
all other registers of the GICv1 are read via regular secure-mode accesses.

[1] http://git.denx.de/?p=linux-denx/linux-denx-
marex.git;a=shortlog;h=refs/heads/topic/socfpga/fiq-2014-07-10_01

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v8 0/4] arm: KGDB NMI/FIQ support
@ 2014-07-15 18:45                   ` Marek Vasut
  0 siblings, 0 replies; 535+ messages in thread
From: Marek Vasut @ 2014-07-15 18:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday, July 15, 2014 at 11:41:25 AM, Daniel Thompson wrote:
> On 14/07/14 14:51, Harro Haan wrote:
> > On 10 July 2014 10:03, Daniel Thompson <daniel.thompson@linaro.org> wrote:
> >> This patchset makes it possible to use kgdb's NMI infrastructure on ARM
> >> platforms.
> >> 
> >> The patches have been previously circulated as part of a large patchset
> >> mixing together ARM architecture code and driver changes
> >> (http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901 ). This
> >> patchset is dramatically cut down to include only the arch/arm code. The
> >> driver code (irqchip and tty/serial) will follow when/if the arch code
> >> is accepted.
> >> 
> >> The first two patches modify the FIQ infrastructure to allow interrupt
> >> controller drivers to register callbacks (the fiq_chip structure) to
> >> manage FIQ routings and to ACK and EOI the FIQ. This makes it possible
> >> to use FIQ in multi-platform kernels and with recent ARM interrupt
> >> controllers.
> > 
> > Daniel,
> > 
> > Thanks for the patches. I have tested the fiq and irq-gic patches on
> > an i.MX6 (SabreSD board) for a different purpose:
> > A FIQ timer interrupt at 1 kHz. The TWD watchdog block is used in
> > timer mode for this (interrupt ID 30). The GIC affinity is set to CPU
> > core 0 only for this interrupt ID.
> > 
> > I was surprised by the following behavior:
> > $ cat /proc/interrupts
> > 
> >            CPU0       CPU1       CPU2       CPU3
> >  
> >  29:       5459       3381       3175       3029       GIC  29  twd
> >  30:         11          0          0          0       GIC  30  fake-fiq
> > 
> > Once every few seconds is interrupt ID 30 handled by the regular GIC
> > handler instead of the FIQ exception path (which causes for example a
> > bit more latencies). The other thousands of FIQ's are handled by the
> > FIQ exception path. The problem is also confirmed by the following
> > stackframe of the Lauterbach tooling:
> > fake_fiq_handler(irq = 30, ...)
> > handle_percpu_devid_irq(irq = 30, ...)
> > generic_handle_irq(irq = 30)
> > handle_IRQ(irq = 30, ...)
> > gic_handle_irq
> > __irq_svc
> > -->exception
> > 
> > Notes:
> > 
> > - The problem will occur more often by executing the following command:
> >   $ while true; do hackbench 20; done &
> > 
> > - Reading the GIC_CPU_INTACK register returns the interrupt ID of the
> > highest priority pending interrupt.
> > - The GIC_CPU_INTACK register (used by fiq_ack) will return spurious
> > interrupt ID 0x3FF when read in fake_fiq_handler, because
> > GIC_CPU_INTACK is already read by gic_handle_irq.
> > - The FIQ exception will not occur anymore after gic_handle_irq
> > read/acknowledges the FIQ by reading the GIC_CPU_INTACK register
> > 
> > From the behavior above I conclude that the GIC_CPU_INTACK register is
> > first updated before the FIQ exception is generated, so there is a
> > small period of time that gic_handle_irq can read/acknowledge the FIQ.
> 
> Makes sense.
> 
> Avoiding this problem on GICv2 is easy (thanks to the aliased intack
> register) but on iMX.6 we have only a GICv1.

Yep.

> > I can reduce the number of occurrences (not prevent it) by adding the
> > following hack to irq-gic.c
> > @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
> > gic_handle_irq(struct pt_regs *regs
> > 
> >   u32 irqstat, irqnr;
> >   struct gic_chip_data *gic = &gic_data[0];
> >   void __iomem *cpu_base = gic_data_cpu_base(gic);
> >   
> >   do {
> > 
> > + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
> > & (1 << 30))
> > +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
> > 
> >   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
> >   irqnr = irqstat & ~0x1c00;
> 
> I've made a more complete attempt to fix this. Could you test the
> following? (and be prepared to fuzz the line numbers)

There's also another workaround, look at [1], but it's really a perverse hack 
thus far (blush). What I did there is I got hinted that an L1 page table can 
have this NS bit set. If this bit is set for a mapping, all accesses to memory 
area via that mapping will be non-secure. And then, in turn, by doing a non-
secure read of the INTACK register, it will not ever happen that the FIQ number 
will pop up in the INTACK. I only do a non-secure read of the INTACK register,
all other registers of the GICv1 are read via regular secure-mode accesses.

[1] http://git.denx.de/?p=linux-denx/linux-denx-
marex.git;a=shortlog;h=refs/heads/topic/socfpga/fiq-2014-07-10_01

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support
  2014-07-15 18:45                   ` Marek Vasut
@ 2014-07-16 12:54                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-16 12:54 UTC (permalink / raw)
  To: Marek Vasut, linux-arm-kernel
  Cc: Harro Haan, linaro-kernel, Russell King, patches, kgdb-bugreport,
	Linus Walleij, Nicolas Pitre, linux-kernel, Colin Cross,
	Anton Vorontsov, Ben Dooks, John Stultz, Fabio Estevam,
	Catalin Marinas, kernel-team, Frederic Weisbecker, Dave Martin,
	Detlev Zundel

On 15/07/14 19:45, Marek Vasut wrote:
>>> I can reduce the number of occurrences (not prevent it) by adding the
>>> following hack to irq-gic.c
>>> @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
>>> gic_handle_irq(struct pt_regs *regs
>>>
>>>   u32 irqstat, irqnr;
>>>   struct gic_chip_data *gic = &gic_data[0];
>>>   void __iomem *cpu_base = gic_data_cpu_base(gic);
>>>   
>>>   do {
>>>
>>> + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
>>> & (1 << 30))
>>> +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
>>>
>>>   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>>>   irqnr = irqstat & ~0x1c00;
>>
>> I've made a more complete attempt to fix this. Could you test the
>> following? (and be prepared to fuzz the line numbers)
> 
> There's also another workaround, look at [1], but it's really a perverse hack 
> thus far (blush). What I did there is I got hinted that an L1 page table can 
> have this NS bit set. If this bit is set for a mapping, all accesses to memory 
> area via that mapping will be non-secure. And then, in turn, by doing a non-
> secure read of the INTACK register, it will not ever happen that the FIQ number 
> will pop up in the INTACK. I only do a non-secure read of the INTACK register,
> all other registers of the GICv1 are read via regular secure-mode accesses.

I'll be looking into this approach.

It is technically a better approach than mine since it prevents the IRQ
handler from ever reading a group 0 interrupt from INTACK.

Unfortunately the tentacles of this workaround reach pretty deep in the
memory management code (rather than being concentrated in the GIC
driver) but the improved runtime behaviour might be worth it.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v8 0/4] arm: KGDB NMI/FIQ support
@ 2014-07-16 12:54                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-16 12:54 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/07/14 19:45, Marek Vasut wrote:
>>> I can reduce the number of occurrences (not prevent it) by adding the
>>> following hack to irq-gic.c
>>> @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
>>> gic_handle_irq(struct pt_regs *regs
>>>
>>>   u32 irqstat, irqnr;
>>>   struct gic_chip_data *gic = &gic_data[0];
>>>   void __iomem *cpu_base = gic_data_cpu_base(gic);
>>>   
>>>   do {
>>>
>>> + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
>>> & (1 << 30))
>>> +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
>>>
>>>   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>>>   irqnr = irqstat & ~0x1c00;
>>
>> I've made a more complete attempt to fix this. Could you test the
>> following? (and be prepared to fuzz the line numbers)
> 
> There's also another workaround, look at [1], but it's really a perverse hack 
> thus far (blush). What I did there is I got hinted that an L1 page table can 
> have this NS bit set. If this bit is set for a mapping, all accesses to memory 
> area via that mapping will be non-secure. And then, in turn, by doing a non-
> secure read of the INTACK register, it will not ever happen that the FIQ number 
> will pop up in the INTACK. I only do a non-secure read of the INTACK register,
> all other registers of the GICv1 are read via regular secure-mode accesses.

I'll be looking into this approach.

It is technically a better approach than mine since it prevents the IRQ
handler from ever reading a group 0 interrupt from INTACK.

Unfortunately the tentacles of this workaround reach pretty deep in the
memory management code (rather than being concentrated in the GIC
driver) but the improved runtime behaviour might be worth it.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support
  2014-07-15 17:08                         ` Daniel Thompson
@ 2014-07-16 17:15                           ` Harro Haan
  -1 siblings, 0 replies; 535+ messages in thread
From: Harro Haan @ 2014-07-16 17:15 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Russell King, linaro-kernel, Catalin Marinas, patches,
	kgdb-bugreport, Linus Walleij, Nicolas Pitre, linux-kernel,
	Frederic Weisbecker, Anton Vorontsov, Ben Dooks, John Stultz,
	Fabio Estevam, Colin Cross, kernel-team, Dave Martin,
	linux-arm-kernel

On 15 July 2014 19:08, Daniel Thompson <daniel.thompson@linaro.org> wrote:
> On 15/07/14 16:59, Harro Haan wrote:
>> On 15 July 2014 16:52, Daniel Thompson <daniel.thompson@linaro.org> wrote:
>>> On 15/07/14 14:04, Harro Haan wrote:
>>>>> Makes sense.
>>>>>
>>>>> Avoiding this problem on GICv2 is easy (thanks to the aliased intack
>>>>> register) but on iMX.6 we have only a GICv1.
>>>>>
>>>>>
>>>>>> I can reduce the number of occurrences (not prevent it) by adding the
>>>>>> following hack to irq-gic.c
>>>>>> @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
>>>>>> gic_handle_irq(struct pt_regs *regs
>>>>>>   u32 irqstat, irqnr;
>>>>>>   struct gic_chip_data *gic = &gic_data[0];
>>>>>>   void __iomem *cpu_base = gic_data_cpu_base(gic);
>>>>>>
>>>>>>   do {
>>>>>> + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
>>>>>> & (1 << 30))
>>>>>> +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
>>>>>>   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>>>>>>   irqnr = irqstat & ~0x1c00;
>>>>>
>>>>> I've made a more complete attempt to fix this. Could you test the
>>>>> following? (and be prepared to fuzz the line numbers)
>>>>
>>>> Thanks Daniel, I have tested it, see the comments below.
>>>>
>>>>>
>>>>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>>>>> index 73ae896..309bf2c 100644
>>>>> --- a/drivers/irqchip/irq-gic.c
>>>>> +++ b/drivers/irqchip/irq-gic.c
>>>>> @@ -303,6 +303,28 @@ static int gic_set_wake(struct irq_data *d,
>>>>> unsigned int on)
>>>>>  #define gic_set_wake   NULL
>>>>>  #endif
>>>>>
>>>>> +/* Check for group 0 interrupt spuriously acked as a normal IRQ. This
>>>>> + * workaround will only work for level triggered interrupts (and in
>>>>> + * its current form is actively harmful on systems that don't support
>>>>> + * FIQ).
>>>>> + */
>>>>> +static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32
>>>>> irqstat)
>>>>> +{
>>>>> +       u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
>>>>> +
>>>>> +       if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
>>>>> +               return irqnr;
>>>>> +
>>>>> +       if (readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_IGROUP +
>>>>> +                         (irqnr / 32 * 4)) &
>>>>> +           BIT(irqnr % 32))
>>>>> +               return irqnr;
>>>>> +
>>>>> +       /* this interrupt was spurious (needs to be handled as FIQ) */
>>>>> +       writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
>>>>
>>>> This will NOT work, because of the note I mentioned above:
>>>> "The FIQ exception will not occur anymore after gic_handle_irq
>>>> read/acknowledges the FIQ by reading the GIC_CPU_INTACK register"
>>>> So with this code you will say End Of Interrupt at the GIC level,
>>>> without actually handling the interrupt, so you are missing an
>>>> interrupt.
>>>> I did the following test to confirm the missing interrupt:
>>>> I have changed the periodic timer interrupt by an one-shot timer
>>>> interrupt. The one-shot timer interrupt is programmed by the FIQ
>>>> handler for the next FIQ interrupt. As expected: When the problem
>>>> occurs, no more FIQ interrupts are generated.
>>>
>>> Can you confirm whether your timer interrupts are configured level or
>>> edge triggered? Or whether EOIing the GIC causes them to be cleared by
>>> some other means.
>>
>> From page 48 of DDI0407I_cortex_a9_mpcore_r4p1_trm.pdf:
>> Watchdog timers, PPI(3)
>> Each Cortex-A9 processor has its own watchdog timers that can generate
>> interrupts, using ID30.
>>
>> From page 56:
>> PPI[0], [2],and[3]:b11
>> interrupt is rising-edge sensitive.
>
> Thanks. This is clear.
>
>
>>> If we can't get level triggering to work then we have to:
>>>
>>> 1. Write code to jump correctly into FIQ mode.
>>>
>>> 2. Modify the gic's ack_fiq() callback to automatically avoid reading
>>>    intack when the workaround is deployed.
>>>
>>> The above is why I wanted to see if we can make do with level triggering
>>> (and automatic re-triggering for interrupts such as SGIs that are
>>> cleared by EOI).
>>
>> But the re-triggering introduces extra latencies and a lot of use
>> cases of FIQ's try to avoid that.
>
> I'm not really clear why retriggering should be significantly more
> expensive than the dance required to fake up entry the FIQ handler.
>
> On the other hand retriggering allows us to avoid hacks in the FIQ
> handler to stop it acknowledging the interrupt. Given hacks like that
> won't be needed on A7/A15 this seems like a good outcome.
>
> Anyhow I've put together a new version of my earlier patch that I think
> will retrigger all interrupts except SGIs (I'll look at SGIs and
> compatibility with non-Freescale parts only if this improved approach
> works).
>
> Reported-by: Harro Haan <hrhaan@gmail.com>
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> ---
>  drivers/irqchip/irq-gic.c | 31 ++++++++++++++++++++++++++++++-
>  1 file changed, 30 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index 73ae896..88f92e6 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -303,6 +303,33 @@ static int gic_set_wake(struct irq_data *d,
> unsigned int on)
>  #define gic_set_wake   NULL
>  #endif
>
> +/* This is a software emulation of the Aliased Interrupt Acknowledge
> Register
> + * (GIC_AIAR) found in GICv2+.
> + */
> +static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32
> irqstat)
> +{
> +       u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
> +       void __iomem *dist_base = gic_data_dist_base(gic);
> +       u32 offset, mask;
> +
> +       if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
> +               return irqnr;
> +
> +       offset = irqnr / 32 * 4;
> +       mask = 1 << (irqnr % 32);
> +       if (readl_relaxed(dist_base + GIC_DIST_IGROUP + offset) & mask)
> +               return irqnr;
> +
> +       /* this interrupt must be taken as a FIQ so put it back into the
> +        * pending state and end our own servicing of it.
> +        */
> +       writel_relaxed(mask, dist_base + GIC_DIST_PENDING_SET + offset);
> +       readl_relaxed(dist_base + GIC_DIST_PENDING_SET + offset);
> +       writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
> +
> +       return 1023;
> +}
> +
>  static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
>  {
>         u32 irqstat, irqnr;
> @@ -310,8 +337,10 @@ static void __exception_irq_entry
> gic_handle_irq(struct pt_regs *regs)
>         void __iomem *cpu_base = gic_data_cpu_base(gic);
>
>         do {
> +               local_fiq_disable();
>                 irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
> -               irqnr = irqstat & GICC_IAR_INT_ID_MASK;
> +               irqnr = gic_handle_spurious_group_0(gic, irqstat);
> +               local_fiq_enable();
>
>                 if (likely(irqnr > 15 && irqnr < 1021)) {
>                         irqnr = irq_find_mapping(gic->domain, irqnr);
> --
> 1.9.3
>
>
>

I just tested the above code. This approach also works as expected for
edge sensitive interrupts.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v8 0/4] arm: KGDB NMI/FIQ support
@ 2014-07-16 17:15                           ` Harro Haan
  0 siblings, 0 replies; 535+ messages in thread
From: Harro Haan @ 2014-07-16 17:15 UTC (permalink / raw)
  To: linux-arm-kernel

On 15 July 2014 19:08, Daniel Thompson <daniel.thompson@linaro.org> wrote:
> On 15/07/14 16:59, Harro Haan wrote:
>> On 15 July 2014 16:52, Daniel Thompson <daniel.thompson@linaro.org> wrote:
>>> On 15/07/14 14:04, Harro Haan wrote:
>>>>> Makes sense.
>>>>>
>>>>> Avoiding this problem on GICv2 is easy (thanks to the aliased intack
>>>>> register) but on iMX.6 we have only a GICv1.
>>>>>
>>>>>
>>>>>> I can reduce the number of occurrences (not prevent it) by adding the
>>>>>> following hack to irq-gic.c
>>>>>> @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
>>>>>> gic_handle_irq(struct pt_regs *regs
>>>>>>   u32 irqstat, irqnr;
>>>>>>   struct gic_chip_data *gic = &gic_data[0];
>>>>>>   void __iomem *cpu_base = gic_data_cpu_base(gic);
>>>>>>
>>>>>>   do {
>>>>>> + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
>>>>>> & (1 << 30))
>>>>>> +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
>>>>>>   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>>>>>>   irqnr = irqstat & ~0x1c00;
>>>>>
>>>>> I've made a more complete attempt to fix this. Could you test the
>>>>> following? (and be prepared to fuzz the line numbers)
>>>>
>>>> Thanks Daniel, I have tested it, see the comments below.
>>>>
>>>>>
>>>>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>>>>> index 73ae896..309bf2c 100644
>>>>> --- a/drivers/irqchip/irq-gic.c
>>>>> +++ b/drivers/irqchip/irq-gic.c
>>>>> @@ -303,6 +303,28 @@ static int gic_set_wake(struct irq_data *d,
>>>>> unsigned int on)
>>>>>  #define gic_set_wake   NULL
>>>>>  #endif
>>>>>
>>>>> +/* Check for group 0 interrupt spuriously acked as a normal IRQ. This
>>>>> + * workaround will only work for level triggered interrupts (and in
>>>>> + * its current form is actively harmful on systems that don't support
>>>>> + * FIQ).
>>>>> + */
>>>>> +static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32
>>>>> irqstat)
>>>>> +{
>>>>> +       u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
>>>>> +
>>>>> +       if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
>>>>> +               return irqnr;
>>>>> +
>>>>> +       if (readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_IGROUP +
>>>>> +                         (irqnr / 32 * 4)) &
>>>>> +           BIT(irqnr % 32))
>>>>> +               return irqnr;
>>>>> +
>>>>> +       /* this interrupt was spurious (needs to be handled as FIQ) */
>>>>> +       writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
>>>>
>>>> This will NOT work, because of the note I mentioned above:
>>>> "The FIQ exception will not occur anymore after gic_handle_irq
>>>> read/acknowledges the FIQ by reading the GIC_CPU_INTACK register"
>>>> So with this code you will say End Of Interrupt at the GIC level,
>>>> without actually handling the interrupt, so you are missing an
>>>> interrupt.
>>>> I did the following test to confirm the missing interrupt:
>>>> I have changed the periodic timer interrupt by an one-shot timer
>>>> interrupt. The one-shot timer interrupt is programmed by the FIQ
>>>> handler for the next FIQ interrupt. As expected: When the problem
>>>> occurs, no more FIQ interrupts are generated.
>>>
>>> Can you confirm whether your timer interrupts are configured level or
>>> edge triggered? Or whether EOIing the GIC causes them to be cleared by
>>> some other means.
>>
>> From page 48 of DDI0407I_cortex_a9_mpcore_r4p1_trm.pdf:
>> Watchdog timers, PPI(3)
>> Each Cortex-A9 processor has its own watchdog timers that can generate
>> interrupts, using ID30.
>>
>> From page 56:
>> PPI[0], [2],and[3]:b11
>> interrupt is rising-edge sensitive.
>
> Thanks. This is clear.
>
>
>>> If we can't get level triggering to work then we have to:
>>>
>>> 1. Write code to jump correctly into FIQ mode.
>>>
>>> 2. Modify the gic's ack_fiq() callback to automatically avoid reading
>>>    intack when the workaround is deployed.
>>>
>>> The above is why I wanted to see if we can make do with level triggering
>>> (and automatic re-triggering for interrupts such as SGIs that are
>>> cleared by EOI).
>>
>> But the re-triggering introduces extra latencies and a lot of use
>> cases of FIQ's try to avoid that.
>
> I'm not really clear why retriggering should be significantly more
> expensive than the dance required to fake up entry the FIQ handler.
>
> On the other hand retriggering allows us to avoid hacks in the FIQ
> handler to stop it acknowledging the interrupt. Given hacks like that
> won't be needed on A7/A15 this seems like a good outcome.
>
> Anyhow I've put together a new version of my earlier patch that I think
> will retrigger all interrupts except SGIs (I'll look at SGIs and
> compatibility with non-Freescale parts only if this improved approach
> works).
>
> Reported-by: Harro Haan <hrhaan@gmail.com>
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> ---
>  drivers/irqchip/irq-gic.c | 31 ++++++++++++++++++++++++++++++-
>  1 file changed, 30 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index 73ae896..88f92e6 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -303,6 +303,33 @@ static int gic_set_wake(struct irq_data *d,
> unsigned int on)
>  #define gic_set_wake   NULL
>  #endif
>
> +/* This is a software emulation of the Aliased Interrupt Acknowledge
> Register
> + * (GIC_AIAR) found in GICv2+.
> + */
> +static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32
> irqstat)
> +{
> +       u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
> +       void __iomem *dist_base = gic_data_dist_base(gic);
> +       u32 offset, mask;
> +
> +       if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
> +               return irqnr;
> +
> +       offset = irqnr / 32 * 4;
> +       mask = 1 << (irqnr % 32);
> +       if (readl_relaxed(dist_base + GIC_DIST_IGROUP + offset) & mask)
> +               return irqnr;
> +
> +       /* this interrupt must be taken as a FIQ so put it back into the
> +        * pending state and end our own servicing of it.
> +        */
> +       writel_relaxed(mask, dist_base + GIC_DIST_PENDING_SET + offset);
> +       readl_relaxed(dist_base + GIC_DIST_PENDING_SET + offset);
> +       writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
> +
> +       return 1023;
> +}
> +
>  static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
>  {
>         u32 irqstat, irqnr;
> @@ -310,8 +337,10 @@ static void __exception_irq_entry
> gic_handle_irq(struct pt_regs *regs)
>         void __iomem *cpu_base = gic_data_cpu_base(gic);
>
>         do {
> +               local_fiq_disable();
>                 irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
> -               irqnr = irqstat & GICC_IAR_INT_ID_MASK;
> +               irqnr = gic_handle_spurious_group_0(gic, irqstat);
> +               local_fiq_enable();
>
>                 if (likely(irqnr > 15 && irqnr < 1021)) {
>                         irqnr = irq_find_mapping(gic->domain, irqnr);
> --
> 1.9.3
>
>
>

I just tested the above code. This approach also works as expected for
edge sensitive interrupts.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support
  2014-07-16 12:54                     ` Daniel Thompson
@ 2014-07-16 17:21                       ` Harro Haan
  -1 siblings, 0 replies; 535+ messages in thread
From: Harro Haan @ 2014-07-16 17:21 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Marek Vasut, linux-arm-kernel, linaro-kernel, Russell King,
	patches, kgdb-bugreport, Linus Walleij, Nicolas Pitre,
	linux-kernel, Colin Cross, Anton Vorontsov, Ben Dooks,
	John Stultz, Fabio Estevam, Catalin Marinas, kernel-team,
	Frederic Weisbecker, Dave Martin, Detlev Zundel

On 16 July 2014 14:54, Daniel Thompson <daniel.thompson@linaro.org> wrote:
> On 15/07/14 19:45, Marek Vasut wrote:
>>>> I can reduce the number of occurrences (not prevent it) by adding the
>>>> following hack to irq-gic.c
>>>> @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
>>>> gic_handle_irq(struct pt_regs *regs
>>>>
>>>>   u32 irqstat, irqnr;
>>>>   struct gic_chip_data *gic = &gic_data[0];
>>>>   void __iomem *cpu_base = gic_data_cpu_base(gic);
>>>>
>>>>   do {
>>>>
>>>> + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
>>>> & (1 << 30))
>>>> +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
>>>>
>>>>   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>>>>   irqnr = irqstat & ~0x1c00;
>>>
>>> I've made a more complete attempt to fix this. Could you test the
>>> following? (and be prepared to fuzz the line numbers)
>>
>> There's also another workaround, look at [1], but it's really a perverse hack
>> thus far (blush). What I did there is I got hinted that an L1 page table can
>> have this NS bit set. If this bit is set for a mapping, all accesses to memory
>> area via that mapping will be non-secure. And then, in turn, by doing a non-
>> secure read of the INTACK register, it will not ever happen that the FIQ number
>> will pop up in the INTACK. I only do a non-secure read of the INTACK register,
>> all other registers of the GICv1 are read via regular secure-mode accesses.
>
> I'll be looking into this approach.
>
> It is technically a better approach than mine since it prevents the IRQ
> handler from ever reading a group 0 interrupt from INTACK.

Agree, preventing the problem is better than fixing it afterwards.

>
> Unfortunately the tentacles of this workaround reach pretty deep in the
> memory management code (rather than being concentrated in the GIC
> driver) but the improved runtime behaviour might be worth it.

I did some worst case measurements on the SabreSD while running:
$ while true; do hackbench 20; done &

Use banked non-secure GIC_CPU_INTACK register for regular interrupts
(patches by Marek):
The FIQ handler reads the TWD_TIMER_COUNTER 2570 ticks (which is x
1000 / 498 = 5161 nsec) after FIQ interrupt ID30 is generated.
The average is around 497 ticks.
The minimum is around 34 ticks.

Use re-trigger approach by putting it back to pending state (latest
patch by Daniel):
The FIQ handler reads the TWD_TIMER_COUNTER 2678 ticks (which is x
1000 / 498 = 5378 nsec) after FIQ interrupt ID30 is generated.
The average is around 563 ticks (note: almost everything is normal path)
The minimum is around 34 ticks (note: this is the normal path, not the
re-trigger path)

So the results are quite similar.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v8 0/4] arm: KGDB NMI/FIQ support
@ 2014-07-16 17:21                       ` Harro Haan
  0 siblings, 0 replies; 535+ messages in thread
From: Harro Haan @ 2014-07-16 17:21 UTC (permalink / raw)
  To: linux-arm-kernel

On 16 July 2014 14:54, Daniel Thompson <daniel.thompson@linaro.org> wrote:
> On 15/07/14 19:45, Marek Vasut wrote:
>>>> I can reduce the number of occurrences (not prevent it) by adding the
>>>> following hack to irq-gic.c
>>>> @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
>>>> gic_handle_irq(struct pt_regs *regs
>>>>
>>>>   u32 irqstat, irqnr;
>>>>   struct gic_chip_data *gic = &gic_data[0];
>>>>   void __iomem *cpu_base = gic_data_cpu_base(gic);
>>>>
>>>>   do {
>>>>
>>>> + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
>>>> & (1 << 30))
>>>> +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
>>>>
>>>>   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>>>>   irqnr = irqstat & ~0x1c00;
>>>
>>> I've made a more complete attempt to fix this. Could you test the
>>> following? (and be prepared to fuzz the line numbers)
>>
>> There's also another workaround, look at [1], but it's really a perverse hack
>> thus far (blush). What I did there is I got hinted that an L1 page table can
>> have this NS bit set. If this bit is set for a mapping, all accesses to memory
>> area via that mapping will be non-secure. And then, in turn, by doing a non-
>> secure read of the INTACK register, it will not ever happen that the FIQ number
>> will pop up in the INTACK. I only do a non-secure read of the INTACK register,
>> all other registers of the GICv1 are read via regular secure-mode accesses.
>
> I'll be looking into this approach.
>
> It is technically a better approach than mine since it prevents the IRQ
> handler from ever reading a group 0 interrupt from INTACK.

Agree, preventing the problem is better than fixing it afterwards.

>
> Unfortunately the tentacles of this workaround reach pretty deep in the
> memory management code (rather than being concentrated in the GIC
> driver) but the improved runtime behaviour might be worth it.

I did some worst case measurements on the SabreSD while running:
$ while true; do hackbench 20; done &

Use banked non-secure GIC_CPU_INTACK register for regular interrupts
(patches by Marek):
The FIQ handler reads the TWD_TIMER_COUNTER 2570 ticks (which is x
1000 / 498 = 5161 nsec) after FIQ interrupt ID30 is generated.
The average is around 497 ticks.
The minimum is around 34 ticks.

Use re-trigger approach by putting it back to pending state (latest
patch by Daniel):
The FIQ handler reads the TWD_TIMER_COUNTER 2678 ticks (which is x
1000 / 498 = 5378 nsec) after FIQ interrupt ID30 is generated.
The average is around 563 ticks (note: almost everything is normal path)
The minimum is around 34 ticks (note: this is the normal path, not the
re-trigger path)

So the results are quite similar.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support
  2014-07-16 17:15                           ` Harro Haan
@ 2014-07-17  9:01                             ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-17  9:01 UTC (permalink / raw)
  To: Harro Haan
  Cc: Russell King, linaro-kernel, Catalin Marinas, patches,
	kgdb-bugreport, Linus Walleij, Nicolas Pitre, linux-kernel,
	Frederic Weisbecker, Anton Vorontsov, Ben Dooks, John Stultz,
	Fabio Estevam, Colin Cross, kernel-team, Dave Martin,
	linux-arm-kernel

On 16/07/14 18:15, Harro Haan wrote:
>> Anyhow I've put together a new version of my earlier patch that I think
>> will retrigger all interrupts except SGIs (I'll look at SGIs and
>> compatibility with non-Freescale parts only if this improved approach
>> works).
>>
>> Reported-by: Harro Haan <hrhaan@gmail.com>
>> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
>> ---
>>  drivers/irqchip/irq-gic.c | 31 ++++++++++++++++++++++++++++++-
>>  1 file changed, 30 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>> index 73ae896..88f92e6 100644
>> --- a/drivers/irqchip/irq-gic.c
>> +++ b/drivers/irqchip/irq-gic.c
>> @@ -303,6 +303,33 @@ static int gic_set_wake(struct irq_data *d,
>> unsigned int on)
>>  #define gic_set_wake   NULL
>>  #endif
>>
>> +/* This is a software emulation of the Aliased Interrupt Acknowledge
>> Register
>> + * (GIC_AIAR) found in GICv2+.
>> + */
>> +static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32
>> irqstat)
>> +{
>> +       u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
>> +       void __iomem *dist_base = gic_data_dist_base(gic);
>> +       u32 offset, mask;
>> +
>> +       if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
>> +               return irqnr;
>> +
>> +       offset = irqnr / 32 * 4;
>> +       mask = 1 << (irqnr % 32);
>> +       if (readl_relaxed(dist_base + GIC_DIST_IGROUP + offset) & mask)
>> +               return irqnr;
>> +
>> +       /* this interrupt must be taken as a FIQ so put it back into the
>> +        * pending state and end our own servicing of it.
>> +        */
>> +       writel_relaxed(mask, dist_base + GIC_DIST_PENDING_SET + offset);
>> +       readl_relaxed(dist_base + GIC_DIST_PENDING_SET + offset);
>> +       writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
>> +
>> +       return 1023;
>> +}
>> +
>>  static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
>>  {
>>         u32 irqstat, irqnr;
>> @@ -310,8 +337,10 @@ static void __exception_irq_entry
>> gic_handle_irq(struct pt_regs *regs)
>>         void __iomem *cpu_base = gic_data_cpu_base(gic);
>>
>>         do {
>> +               local_fiq_disable();
>>                 irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>> -               irqnr = irqstat & GICC_IAR_INT_ID_MASK;
>> +               irqnr = gic_handle_spurious_group_0(gic, irqstat);
>> +               local_fiq_enable();
>>
>>                 if (likely(irqnr > 15 && irqnr < 1021)) {
>>                         irqnr = irq_find_mapping(gic->domain, irqnr);
>> --
>> 1.9.3
>>
>>
>>
> 
> I just tested the above code. This approach also works as expected for
> edge sensitive interrupts.

Awesome [and also a personal relief to get it right this time around ;-) ].

So we have two completely different confirmed-as-working workarounds!


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v8 0/4] arm: KGDB NMI/FIQ support
@ 2014-07-17  9:01                             ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-17  9:01 UTC (permalink / raw)
  To: linux-arm-kernel

On 16/07/14 18:15, Harro Haan wrote:
>> Anyhow I've put together a new version of my earlier patch that I think
>> will retrigger all interrupts except SGIs (I'll look at SGIs and
>> compatibility with non-Freescale parts only if this improved approach
>> works).
>>
>> Reported-by: Harro Haan <hrhaan@gmail.com>
>> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
>> ---
>>  drivers/irqchip/irq-gic.c | 31 ++++++++++++++++++++++++++++++-
>>  1 file changed, 30 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>> index 73ae896..88f92e6 100644
>> --- a/drivers/irqchip/irq-gic.c
>> +++ b/drivers/irqchip/irq-gic.c
>> @@ -303,6 +303,33 @@ static int gic_set_wake(struct irq_data *d,
>> unsigned int on)
>>  #define gic_set_wake   NULL
>>  #endif
>>
>> +/* This is a software emulation of the Aliased Interrupt Acknowledge
>> Register
>> + * (GIC_AIAR) found in GICv2+.
>> + */
>> +static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32
>> irqstat)
>> +{
>> +       u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
>> +       void __iomem *dist_base = gic_data_dist_base(gic);
>> +       u32 offset, mask;
>> +
>> +       if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
>> +               return irqnr;
>> +
>> +       offset = irqnr / 32 * 4;
>> +       mask = 1 << (irqnr % 32);
>> +       if (readl_relaxed(dist_base + GIC_DIST_IGROUP + offset) & mask)
>> +               return irqnr;
>> +
>> +       /* this interrupt must be taken as a FIQ so put it back into the
>> +        * pending state and end our own servicing of it.
>> +        */
>> +       writel_relaxed(mask, dist_base + GIC_DIST_PENDING_SET + offset);
>> +       readl_relaxed(dist_base + GIC_DIST_PENDING_SET + offset);
>> +       writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
>> +
>> +       return 1023;
>> +}
>> +
>>  static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
>>  {
>>         u32 irqstat, irqnr;
>> @@ -310,8 +337,10 @@ static void __exception_irq_entry
>> gic_handle_irq(struct pt_regs *regs)
>>         void __iomem *cpu_base = gic_data_cpu_base(gic);
>>
>>         do {
>> +               local_fiq_disable();
>>                 irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>> -               irqnr = irqstat & GICC_IAR_INT_ID_MASK;
>> +               irqnr = gic_handle_spurious_group_0(gic, irqstat);
>> +               local_fiq_enable();
>>
>>                 if (likely(irqnr > 15 && irqnr < 1021)) {
>>                         irqnr = irq_find_mapping(gic->domain, irqnr);
>> --
>> 1.9.3
>>
>>
>>
> 
> I just tested the above code. This approach also works as expected for
> edge sensitive interrupts.

Awesome [and also a personal relief to get it right this time around ;-) ].

So we have two completely different confirmed-as-working workarounds!

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support
  2014-07-16 17:21                       ` Harro Haan
@ 2014-07-17  9:20                         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-17  9:20 UTC (permalink / raw)
  To: Harro Haan
  Cc: Marek Vasut, linux-arm-kernel, linaro-kernel, Russell King,
	patches, kgdb-bugreport, Linus Walleij, Nicolas Pitre,
	linux-kernel, Colin Cross, Anton Vorontsov, Ben Dooks,
	John Stultz, Fabio Estevam, Catalin Marinas, kernel-team,
	Frederic Weisbecker, Dave Martin, Detlev Zundel

On 16/07/14 18:21, Harro Haan wrote:
> On 16 July 2014 14:54, Daniel Thompson <daniel.thompson@linaro.org> wrote:
>> On 15/07/14 19:45, Marek Vasut wrote:
>>>>> I can reduce the number of occurrences (not prevent it) by adding the
>>>>> following hack to irq-gic.c
>>>>> @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
>>>>> gic_handle_irq(struct pt_regs *regs
>>>>>
>>>>>   u32 irqstat, irqnr;
>>>>>   struct gic_chip_data *gic = &gic_data[0];
>>>>>   void __iomem *cpu_base = gic_data_cpu_base(gic);
>>>>>
>>>>>   do {
>>>>>
>>>>> + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
>>>>> & (1 << 30))
>>>>> +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
>>>>>
>>>>>   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>>>>>   irqnr = irqstat & ~0x1c00;
>>>>
>>>> I've made a more complete attempt to fix this. Could you test the
>>>> following? (and be prepared to fuzz the line numbers)
>>>
>>> There's also another workaround, look at [1], but it's really a perverse hack
>>> thus far (blush). What I did there is I got hinted that an L1 page table can
>>> have this NS bit set. If this bit is set for a mapping, all accesses to memory
>>> area via that mapping will be non-secure. And then, in turn, by doing a non-
>>> secure read of the INTACK register, it will not ever happen that the FIQ number
>>> will pop up in the INTACK. I only do a non-secure read of the INTACK register,
>>> all other registers of the GICv1 are read via regular secure-mode accesses.
>>
>> I'll be looking into this approach.
>>
>> It is technically a better approach than mine since it prevents the IRQ
>> handler from ever reading a group 0 interrupt from INTACK.
> 
> Agree, preventing the problem is better than fixing it afterwards.
> 
>>
>> Unfortunately the tentacles of this workaround reach pretty deep in the
>> memory management code (rather than being concentrated in the GIC
>> driver) but the improved runtime behaviour might be worth it.
> 
> I did some worst case measurements on the SabreSD while running:
> $ while true; do hackbench 20; done &
> 
> Use banked non-secure GIC_CPU_INTACK register for regular interrupts
> (patches by Marek):
> The FIQ handler reads the TWD_TIMER_COUNTER 2570 ticks (which is x
> 1000 / 498 = 5161 nsec) after FIQ interrupt ID30 is generated.
> The average is around 497 ticks.
> The minimum is around 34 ticks.
> 
> Use re-trigger approach by putting it back to pending state (latest
> patch by Daniel):
> The FIQ handler reads the TWD_TIMER_COUNTER 2678 ticks (which is x
> 1000 / 498 = 5378 nsec) after FIQ interrupt ID30 is generated.
> The average is around 563 ticks (note: almost everything is normal path)
> The minimum is around 34 ticks (note: this is the normal path, not the
> re-trigger path)
> 
> So the results are quite similar.

This is great work.

Be aware that I'd also expect the the performance of my workaround would
drop a little bit when when support for SGIs is added (mostly due to due
to increased code size).


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v8 0/4] arm: KGDB NMI/FIQ support
@ 2014-07-17  9:20                         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-07-17  9:20 UTC (permalink / raw)
  To: linux-arm-kernel

On 16/07/14 18:21, Harro Haan wrote:
> On 16 July 2014 14:54, Daniel Thompson <daniel.thompson@linaro.org> wrote:
>> On 15/07/14 19:45, Marek Vasut wrote:
>>>>> I can reduce the number of occurrences (not prevent it) by adding the
>>>>> following hack to irq-gic.c
>>>>> @@ -297,10 +309,12 @@ static asmlinkage void __exception_irq_entry
>>>>> gic_handle_irq(struct pt_regs *regs
>>>>>
>>>>>   u32 irqstat, irqnr;
>>>>>   struct gic_chip_data *gic = &gic_data[0];
>>>>>   void __iomem *cpu_base = gic_data_cpu_base(gic);
>>>>>
>>>>>   do {
>>>>>
>>>>> + while(readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_PENDING_SET)
>>>>> & (1 << 30))
>>>>> +   printk(KERN_ERR "TEMP: gic_handle_irq: wait for FIQ exception\n");
>>>>>
>>>>>   irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
>>>>>   irqnr = irqstat & ~0x1c00;
>>>>
>>>> I've made a more complete attempt to fix this. Could you test the
>>>> following? (and be prepared to fuzz the line numbers)
>>>
>>> There's also another workaround, look at [1], but it's really a perverse hack
>>> thus far (blush). What I did there is I got hinted that an L1 page table can
>>> have this NS bit set. If this bit is set for a mapping, all accesses to memory
>>> area via that mapping will be non-secure. And then, in turn, by doing a non-
>>> secure read of the INTACK register, it will not ever happen that the FIQ number
>>> will pop up in the INTACK. I only do a non-secure read of the INTACK register,
>>> all other registers of the GICv1 are read via regular secure-mode accesses.
>>
>> I'll be looking into this approach.
>>
>> It is technically a better approach than mine since it prevents the IRQ
>> handler from ever reading a group 0 interrupt from INTACK.
> 
> Agree, preventing the problem is better than fixing it afterwards.
> 
>>
>> Unfortunately the tentacles of this workaround reach pretty deep in the
>> memory management code (rather than being concentrated in the GIC
>> driver) but the improved runtime behaviour might be worth it.
> 
> I did some worst case measurements on the SabreSD while running:
> $ while true; do hackbench 20; done &
> 
> Use banked non-secure GIC_CPU_INTACK register for regular interrupts
> (patches by Marek):
> The FIQ handler reads the TWD_TIMER_COUNTER 2570 ticks (which is x
> 1000 / 498 = 5161 nsec) after FIQ interrupt ID30 is generated.
> The average is around 497 ticks.
> The minimum is around 34 ticks.
> 
> Use re-trigger approach by putting it back to pending state (latest
> patch by Daniel):
> The FIQ handler reads the TWD_TIMER_COUNTER 2678 ticks (which is x
> 1000 / 498 = 5378 nsec) after FIQ interrupt ID30 is generated.
> The average is around 563 ticks (note: almost everything is normal path)
> The minimum is around 34 ticks (note: this is the normal path, not the
> re-trigger path)
> 
> So the results are quite similar.

This is great work.

Be aware that I'd also expect the the performance of my workaround would
drop a little bit when when support for SGIs is added (mostly due to due
to increased code size).

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v8 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
  2014-07-10  8:03               ` Daniel Thompson
@ 2014-08-13 21:45                 ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-08-13 21:45 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Anton Vorontsov, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Colin Cross, kernel-team,
	Rob Herring, Linus Walleij, Ben Dooks, Catalin Marinas,
	Dave Martin, Fabio Estevam, Frederic Weisbecker, Nicolas Pitre

On Thu, Jul 10, 2014 at 09:03:47AM +0100, Daniel Thompson wrote:
> From: Anton Vorontsov <anton.vorontsov@linaro.org>
> 
> The FIQ debugger may be used to debug situations when the kernel stuck
> in uninterruptable sections, e.g. the kernel infinitely loops or
> deadlocked in an interrupt or with interrupts disabled.
> 
> By default KGDB FIQ is disabled in runtime, but can be enabled with
> kgdb_fiq.enable=1 kernel command line option.

I know you've been around the loop on this patch set quite a number of
times.  However, there are two issues.  The first is a simple concern,
the second is more a design decision...

I've recently been hitting a problem on iMX6Q with a irqs-off deadlock
on CPU0 (somehow, it always hit CPU0 every time I tested.)  This wasn't
particularly good as it prevented much in the way of diagnosis.

Of course, things like the spinlock lockup fired... but nothing could
give me a trace from CPU0.

On x86, they have this fixed by using the NMI to trigger a backtrace
on all CPUs when a RCU lockup or spinlock lockup occurs.  There's a
generic hook for this called arch_trigger_all_cpu_backtrace().

So, I set about using the contents of some of your patches to implement
this for ARM, and I came out with something which works.  In doing this,
I started wondering whether the default FIQ handler should not be just
"subs pc, lr, #4" but mostly your FIQ assembly code you have below.
This, along with your GIC patches to move all IRQs to group 1, then
gives us a way to send a FIQ IPI to CPUs in the system - and the FIQ
IPI could be caught and used to dump a backtrace.

Here's the changes I did for that, which are a tad hacky:

irq-gic.c - SGI 8 gets used to trigger a backtrace.  Note it must be
high priority too.

gic_cpu_init()
+       /*
+        * Set all PPI and SGI interrupts to be group 1.
+        *
+        * If grouping is not available (not implemented or prohibited by
+        * security mode) these registers are read-as-zero/write-ignored.
+        */
+       writel_relaxed(0xfffffeff, dist_base + GIC_DIST_IGROUP + 0);
+       writel_relaxed(0xa0a0a000, dist_base + GIC_DIST_PRI + 8);

gic_raise_softirq()
+       softirq = map << 16 | irq;
+       if (irq != 8)
+               softirq |= 0x8000;
+

arch/arm/kernel/smp.c:
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
+
...
+static void ipi_cpu_backtrace(struct pt_regs *regs)
+{
+       int cpu = smp_processor_id();
+
+       if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
+               static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
+
+               arch_spin_lock(&lock);
+               printk(KERN_WARNING "FIQ backtrace for cpu %d\n", cpu);
+               show_regs(regs);
+               arch_spin_unlock(&lock);
+               cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+       }
+}
+
...
+void arch_trigger_all_cpu_backtrace(bool include_self)
+{
+       static unsigned long backtrace_flag;
+       int i, cpu = get_cpu();
+
+       if (test_and_set_bit(0, &backtrace_flag)) {
+               /*
+                * If there is already a trigger_all_cpu_backtrace() in progress
+                * (backtrace_flag == 1), don't output double cpu dump infos.
+                */
+               put_cpu();
+               return;
+       }
+
+       cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
+       if (!include_self)
+               cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+
+       if (!cpumask_empty(to_cpumask(backtrace_mask))) {
+               pr_info("Sending FIQ to %s CPUs:\n",
+                       (include_self ? "all" : "other"));
+               smp_cross_call(to_cpumask(backtrace_mask), IPI_CPU_BACKTRACE);
+       }
+
+       /* Wait for up to 10 seconds for all CPUs to do the backtrace */
+       for (i = 0; i < 10 * 1000; i++) {
+               if (cpumask_empty(to_cpumask(backtrace_mask)))
+                       break;
+
+               mdelay(1);
+       }
+
+       clear_bit(0, &backtrace_flag);
+       smp_mb__after_atomic();
+       put_cpu();
+}
+
+void __fiq_handle(struct pt_regs *regs)
+{
+       ipi_cpu_backtrace(regs);
+}

arch/arm/kernel/setup.c:
+static unsigned int fiq_stack[4][1024];
+
...
cpu_init()
-       "msr    cpsr_c, %7"
+       "msr    cpsr_c, %7\n\t"
+       "mov    sp, %8\n\t"
+       "msr    cpsr_c, %9"
...
+             PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+             "r" (&fiq_stack[cpu][1024]),

The FIQ assembly code is basically the same as yours, but with:

+       .macro  fiq_handler
+       bl      __fiq_handle
+       .endm

and the code in svc_exit_via_fiq testing the PSR I flag and calling
trace_hardirqs_on removed.

This does have one deficiency, and that is it doesn't EOI the FIQ
interrupt - that's something which should be fixed, but for my
purposes to track down where the locked CPU was, it wasn't strictly
necessary that the system continued to work after this point.

This brings me to my second concern, and is the reason I decided not
to ask for it for this merge window.

Calling the trace_* functions is a no-no from FIQ code.
trace_hardirqs_on() can itself take locks, which can result in a
deadlock.

I thought I'd made it clear that FIQ code can't take locks because
there's no way of knowing what state they're in at the point that the
FIQ fires - _irq() variants won't save you - and that's kind of the
point of FIQ.  It's almost never masked by the kernel.

Now, You'll be forgiven if you now point out that in the code above,
I'm taking a spinlock.  That's absolutely true.  Analyse the code
a little closer and you'll notice it's done in a safe way.  There's
only one time where that spinlock is taken and that's from FIQ code,
never from any other code, and only once per CPU - notice how
arch_trigger_all_cpu_backtrace() protects itself against multiple
callers, and how ipi_cpu_backtrace() is careful to check that its
CPU bit is set.  This is exactly the same method which x86 code uses
(in fact, much of the above code was stolen from x86!)

So, how about moving the FIQ assembly code to entry-armv.S and making
it less kgdb specific?  (Though... we do want to keep a /very/ close
eye on users to ensure that they don't do silly stuff with locking.)

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v8 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
@ 2014-08-13 21:45                 ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-08-13 21:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jul 10, 2014 at 09:03:47AM +0100, Daniel Thompson wrote:
> From: Anton Vorontsov <anton.vorontsov@linaro.org>
> 
> The FIQ debugger may be used to debug situations when the kernel stuck
> in uninterruptable sections, e.g. the kernel infinitely loops or
> deadlocked in an interrupt or with interrupts disabled.
> 
> By default KGDB FIQ is disabled in runtime, but can be enabled with
> kgdb_fiq.enable=1 kernel command line option.

I know you've been around the loop on this patch set quite a number of
times.  However, there are two issues.  The first is a simple concern,
the second is more a design decision...

I've recently been hitting a problem on iMX6Q with a irqs-off deadlock
on CPU0 (somehow, it always hit CPU0 every time I tested.)  This wasn't
particularly good as it prevented much in the way of diagnosis.

Of course, things like the spinlock lockup fired... but nothing could
give me a trace from CPU0.

On x86, they have this fixed by using the NMI to trigger a backtrace
on all CPUs when a RCU lockup or spinlock lockup occurs.  There's a
generic hook for this called arch_trigger_all_cpu_backtrace().

So, I set about using the contents of some of your patches to implement
this for ARM, and I came out with something which works.  In doing this,
I started wondering whether the default FIQ handler should not be just
"subs pc, lr, #4" but mostly your FIQ assembly code you have below.
This, along with your GIC patches to move all IRQs to group 1, then
gives us a way to send a FIQ IPI to CPUs in the system - and the FIQ
IPI could be caught and used to dump a backtrace.

Here's the changes I did for that, which are a tad hacky:

irq-gic.c - SGI 8 gets used to trigger a backtrace.  Note it must be
high priority too.

gic_cpu_init()
+       /*
+        * Set all PPI and SGI interrupts to be group 1.
+        *
+        * If grouping is not available (not implemented or prohibited by
+        * security mode) these registers are read-as-zero/write-ignored.
+        */
+       writel_relaxed(0xfffffeff, dist_base + GIC_DIST_IGROUP + 0);
+       writel_relaxed(0xa0a0a000, dist_base + GIC_DIST_PRI + 8);

gic_raise_softirq()
+       softirq = map << 16 | irq;
+       if (irq != 8)
+               softirq |= 0x8000;
+

arch/arm/kernel/smp.c:
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
+
...
+static void ipi_cpu_backtrace(struct pt_regs *regs)
+{
+       int cpu = smp_processor_id();
+
+       if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
+               static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
+
+               arch_spin_lock(&lock);
+               printk(KERN_WARNING "FIQ backtrace for cpu %d\n", cpu);
+               show_regs(regs);
+               arch_spin_unlock(&lock);
+               cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+       }
+}
+
...
+void arch_trigger_all_cpu_backtrace(bool include_self)
+{
+       static unsigned long backtrace_flag;
+       int i, cpu = get_cpu();
+
+       if (test_and_set_bit(0, &backtrace_flag)) {
+               /*
+                * If there is already a trigger_all_cpu_backtrace() in progress
+                * (backtrace_flag == 1), don't output double cpu dump infos.
+                */
+               put_cpu();
+               return;
+       }
+
+       cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
+       if (!include_self)
+               cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+
+       if (!cpumask_empty(to_cpumask(backtrace_mask))) {
+               pr_info("Sending FIQ to %s CPUs:\n",
+                       (include_self ? "all" : "other"));
+               smp_cross_call(to_cpumask(backtrace_mask), IPI_CPU_BACKTRACE);
+       }
+
+       /* Wait for up to 10 seconds for all CPUs to do the backtrace */
+       for (i = 0; i < 10 * 1000; i++) {
+               if (cpumask_empty(to_cpumask(backtrace_mask)))
+                       break;
+
+               mdelay(1);
+       }
+
+       clear_bit(0, &backtrace_flag);
+       smp_mb__after_atomic();
+       put_cpu();
+}
+
+void __fiq_handle(struct pt_regs *regs)
+{
+       ipi_cpu_backtrace(regs);
+}

arch/arm/kernel/setup.c:
+static unsigned int fiq_stack[4][1024];
+
...
cpu_init()
-       "msr    cpsr_c, %7"
+       "msr    cpsr_c, %7\n\t"
+       "mov    sp, %8\n\t"
+       "msr    cpsr_c, %9"
...
+             PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+             "r" (&fiq_stack[cpu][1024]),

The FIQ assembly code is basically the same as yours, but with:

+       .macro  fiq_handler
+       bl      __fiq_handle
+       .endm

and the code in svc_exit_via_fiq testing the PSR I flag and calling
trace_hardirqs_on removed.

This does have one deficiency, and that is it doesn't EOI the FIQ
interrupt - that's something which should be fixed, but for my
purposes to track down where the locked CPU was, it wasn't strictly
necessary that the system continued to work after this point.

This brings me to my second concern, and is the reason I decided not
to ask for it for this merge window.

Calling the trace_* functions is a no-no from FIQ code.
trace_hardirqs_on() can itself take locks, which can result in a
deadlock.

I thought I'd made it clear that FIQ code can't take locks because
there's no way of knowing what state they're in at the point that the
FIQ fires - _irq() variants won't save you - and that's kind of the
point of FIQ.  It's almost never masked by the kernel.

Now, You'll be forgiven if you now point out that in the code above,
I'm taking a spinlock.  That's absolutely true.  Analyse the code
a little closer and you'll notice it's done in a safe way.  There's
only one time where that spinlock is taken and that's from FIQ code,
never from any other code, and only once per CPU - notice how
arch_trigger_all_cpu_backtrace() protects itself against multiple
callers, and how ipi_cpu_backtrace() is careful to check that its
CPU bit is set.  This is exactly the same method which x86 code uses
(in fact, much of the above code was stolen from x86!)

So, how about moving the FIQ assembly code to entry-armv.S and making
it less kgdb specific?  (Though... we do want to keep a /very/ close
eye on users to ensure that they don't do silly stuff with locking.)

-- 
FTTC broadband for 0.8mile line: currently@9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v8 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
  2014-08-13 21:45                 ` Russell King - ARM Linux
@ 2014-08-14 10:48                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-14 10:48 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Anton Vorontsov, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Colin Cross, kernel-team,
	Rob Herring, Linus Walleij, Ben Dooks, Catalin Marinas,
	Dave Martin, Fabio Estevam, Frederic Weisbecker, Nicolas Pitre

On 13/08/14 22:45, Russell King - ARM Linux wrote:
> On Thu, Jul 10, 2014 at 09:03:47AM +0100, Daniel Thompson wrote:
>> From: Anton Vorontsov <anton.vorontsov@linaro.org>
>>
>> The FIQ debugger may be used to debug situations when the kernel stuck
>> in uninterruptable sections, e.g. the kernel infinitely loops or
>> deadlocked in an interrupt or with interrupts disabled.
>>
>> By default KGDB FIQ is disabled in runtime, but can be enabled with
>> kgdb_fiq.enable=1 kernel command line option.
> 
> I know you've been around the loop on this patch set quite a number of
> times.  However, there are two issues.  The first is a simple concern,
> the second is more a design decision...
> 
> I've recently been hitting a problem on iMX6Q with a irqs-off deadlock
> on CPU0 (somehow, it always hit CPU0 every time I tested.)  This wasn't
> particularly good as it prevented much in the way of diagnosis.
> 
> Of course, things like the spinlock lockup fired... but nothing could
> give me a trace from CPU0.
> 
> On x86, they have this fixed by using the NMI to trigger a backtrace
> on all CPUs when a RCU lockup or spinlock lockup occurs.  There's a
> generic hook for this called arch_trigger_all_cpu_backtrace().
> 
> So, I set about using the contents of some of your patches to implement
> this for ARM, and I came out with something which works.  In doing this,
> I started wondering whether the default FIQ handler should not be just
> "subs pc, lr, #4" but mostly your FIQ assembly code you have below.
> This, along with your GIC patches to move all IRQs to group 1, then
> gives us a way to send a FIQ IPI to CPUs in the system - and the FIQ
> IPI could be caught and used to dump a backtrace.
> 
> Here's the changes I did for that, which are a tad hacky:
> 
> irq-gic.c - SGI 8 gets used to trigger a backtrace.  Note it must be
> high priority too.
> 
> gic_cpu_init()
> +       /*
> +        * Set all PPI and SGI interrupts to be group 1.
> +        *
> +        * If grouping is not available (not implemented or prohibited by
> +        * security mode) these registers are read-as-zero/write-ignored.
> +        */
> +       writel_relaxed(0xfffffeff, dist_base + GIC_DIST_IGROUP + 0);
> +       writel_relaxed(0xa0a0a000, dist_base + GIC_DIST_PRI + 8);
> 
> gic_raise_softirq()
> +       softirq = map << 16 | irq;
> +       if (irq != 8)
> +               softirq |= 0x8000;
> +

Let me dig out some of my patches in this area.

I've added an IPI to be used to quiesce the CPUs for KGDB. My code is in
essence the same as yours but uses a bitmask for the IPIs that should be
delivered using FIQ (in fact I wrote that deliberately to leave space to
easily implement arch_trigger_all_cpu_backtrace() )

> arch/arm/kernel/smp.c:
> +/* For reliability, we're prepared to waste bits here. */
> +static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
> +
> ...
> +static void ipi_cpu_backtrace(struct pt_regs *regs)
> +{
> +       int cpu = smp_processor_id();
> +
> +       if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
> +               static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
> +
> +               arch_spin_lock(&lock);
> +               printk(KERN_WARNING "FIQ backtrace for cpu %d\n", cpu);
> +               show_regs(regs);
> +               arch_spin_unlock(&lock);
> +               cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
> +       }
> +}
> +
> ...
> +void arch_trigger_all_cpu_backtrace(bool include_self)
> +{
> +       static unsigned long backtrace_flag;
> +       int i, cpu = get_cpu();
> +
> +       if (test_and_set_bit(0, &backtrace_flag)) {
> +               /*
> +                * If there is already a trigger_all_cpu_backtrace() in progress
> +                * (backtrace_flag == 1), don't output double cpu dump infos.
> +                */
> +               put_cpu();
> +               return;
> +       }
> +
> +       cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
> +       if (!include_self)
> +               cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
> +
> +       if (!cpumask_empty(to_cpumask(backtrace_mask))) {
> +               pr_info("Sending FIQ to %s CPUs:\n",
> +                       (include_self ? "all" : "other"));
> +               smp_cross_call(to_cpumask(backtrace_mask), IPI_CPU_BACKTRACE);
> +       }
> +
> +       /* Wait for up to 10 seconds for all CPUs to do the backtrace */
> +       for (i = 0; i < 10 * 1000; i++) {
> +               if (cpumask_empty(to_cpumask(backtrace_mask)))
> +                       break;
> +
> +               mdelay(1);
> +       }
> +
> +       clear_bit(0, &backtrace_flag);
> +       smp_mb__after_atomic();
> +       put_cpu();
> +}
> +
> +void __fiq_handle(struct pt_regs *regs)
> +{
> +       ipi_cpu_backtrace(regs);
> +}
> 
> arch/arm/kernel/setup.c:
> +static unsigned int fiq_stack[4][1024];
> +
> ...
> cpu_init()
> -       "msr    cpsr_c, %7"
> +       "msr    cpsr_c, %7\n\t"
> +       "mov    sp, %8\n\t"
> +       "msr    cpsr_c, %9"
> ...
> +             PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
> +             "r" (&fiq_stack[cpu][1024]),
> 
> The FIQ assembly code is basically the same as yours, but with:
> 
> +       .macro  fiq_handler
> +       bl      __fiq_handle
> +       .endm
> 
> and the code in svc_exit_via_fiq testing the PSR I flag and calling
> trace_hardirqs_on removed.
> 
> This does have one deficiency, and that is it doesn't EOI the FIQ
> interrupt - that's something which should be fixed, but for my
> purposes to track down where the locked CPU was, it wasn't strictly
> necessary that the system continued to work after this point.

EOIing IPIs should be pretty easy (it is safe to EOI them immediately
after the ack). This is also included in my existing IPI patches.


> This brings me to my second concern, and is the reason I decided not
> to ask for it for this merge window.
> 
> Calling the trace_* functions is a no-no from FIQ code.
> trace_hardirqs_on() can itself take locks, which can result in a
> deadlock.
> 
> I thought I'd made it clear that FIQ code can't take locks because
> there's no way of knowing what state they're in at the point that the
> FIQ fires - _irq() variants won't save you - and that's kind of the
> point of FIQ.  It's almost never masked by the kernel.

Don't worry, you certainly did make it clear!

I actually went as far as removing the trace_* calls before having a
change of heart. As a result I spent some time looking at the
trace_hardirqs_on() code and, as far as I remember, I couldn't find a
lock in the code that wasn't bypassed when in_nmi() returned true.

However the code is pretty complex and its certainly possible that I
missed something. Are you in a position to point any particular lock to
show I messed this up or are you working from memory?


> Now, You'll be forgiven if you now point out that in the code above,
> I'm taking a spinlock.  That's absolutely true.  Analyse the code
> a little closer and you'll notice it's done in a safe way.  There's
> only one time where that spinlock is taken and that's from FIQ code,
> never from any other code, and only once per CPU - notice how
> arch_trigger_all_cpu_backtrace() protects itself against multiple
> callers, and how ipi_cpu_backtrace() is careful to check that its
> CPU bit is set.  This is exactly the same method which x86 code uses
> (in fact, much of the above code was stolen from x86!)

Agreed. I also plan to use FIQ-safe locks in the GIC code to raise an
IPI. The b.L switcher code explicitly calls local_fiq_disable() so
providing the locks are contested only between the b.L switcher logic
and FIQ handlers it will be safe.

That said my original approach (again, I'll post it in a moment) was
pretty ugly which is why I'm so pleased with Stephen Boyd's recently
proposed change.


> So, how about moving the FIQ assembly code to entry-armv.S and making
> it less kgdb specific?  (Though... we do want to keep a /very/ close
> eye on users to ensure that they don't do silly stuff with locking.)

I think I can do that.

Something like this?

1. Install the current trap handler code by default (either with or
   without trace_* calls).

2. Have default trap handler call an RCU notifier chain to allow it to
   hook up with "normal" code without any hard coding (kgdb, IPI
   handling, etc)

3. Retain existing install_fiq() behaviour for people who want FIQ
   to be a fast-interrupt rather than an NMI (for example, the
   Raspberry pi USB optimizations).

4. Ensure default handler is an exported symbol to allow the meths
   drinkers from #3 to chain to logic for NMI/debug features
   if they want to.


Daniel.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v8 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
@ 2014-08-14 10:48                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-14 10:48 UTC (permalink / raw)
  To: linux-arm-kernel

On 13/08/14 22:45, Russell King - ARM Linux wrote:
> On Thu, Jul 10, 2014 at 09:03:47AM +0100, Daniel Thompson wrote:
>> From: Anton Vorontsov <anton.vorontsov@linaro.org>
>>
>> The FIQ debugger may be used to debug situations when the kernel stuck
>> in uninterruptable sections, e.g. the kernel infinitely loops or
>> deadlocked in an interrupt or with interrupts disabled.
>>
>> By default KGDB FIQ is disabled in runtime, but can be enabled with
>> kgdb_fiq.enable=1 kernel command line option.
> 
> I know you've been around the loop on this patch set quite a number of
> times.  However, there are two issues.  The first is a simple concern,
> the second is more a design decision...
> 
> I've recently been hitting a problem on iMX6Q with a irqs-off deadlock
> on CPU0 (somehow, it always hit CPU0 every time I tested.)  This wasn't
> particularly good as it prevented much in the way of diagnosis.
> 
> Of course, things like the spinlock lockup fired... but nothing could
> give me a trace from CPU0.
> 
> On x86, they have this fixed by using the NMI to trigger a backtrace
> on all CPUs when a RCU lockup or spinlock lockup occurs.  There's a
> generic hook for this called arch_trigger_all_cpu_backtrace().
> 
> So, I set about using the contents of some of your patches to implement
> this for ARM, and I came out with something which works.  In doing this,
> I started wondering whether the default FIQ handler should not be just
> "subs pc, lr, #4" but mostly your FIQ assembly code you have below.
> This, along with your GIC patches to move all IRQs to group 1, then
> gives us a way to send a FIQ IPI to CPUs in the system - and the FIQ
> IPI could be caught and used to dump a backtrace.
> 
> Here's the changes I did for that, which are a tad hacky:
> 
> irq-gic.c - SGI 8 gets used to trigger a backtrace.  Note it must be
> high priority too.
> 
> gic_cpu_init()
> +       /*
> +        * Set all PPI and SGI interrupts to be group 1.
> +        *
> +        * If grouping is not available (not implemented or prohibited by
> +        * security mode) these registers are read-as-zero/write-ignored.
> +        */
> +       writel_relaxed(0xfffffeff, dist_base + GIC_DIST_IGROUP + 0);
> +       writel_relaxed(0xa0a0a000, dist_base + GIC_DIST_PRI + 8);
> 
> gic_raise_softirq()
> +       softirq = map << 16 | irq;
> +       if (irq != 8)
> +               softirq |= 0x8000;
> +

Let me dig out some of my patches in this area.

I've added an IPI to be used to quiesce the CPUs for KGDB. My code is in
essence the same as yours but uses a bitmask for the IPIs that should be
delivered using FIQ (in fact I wrote that deliberately to leave space to
easily implement arch_trigger_all_cpu_backtrace() )

> arch/arm/kernel/smp.c:
> +/* For reliability, we're prepared to waste bits here. */
> +static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
> +
> ...
> +static void ipi_cpu_backtrace(struct pt_regs *regs)
> +{
> +       int cpu = smp_processor_id();
> +
> +       if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
> +               static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
> +
> +               arch_spin_lock(&lock);
> +               printk(KERN_WARNING "FIQ backtrace for cpu %d\n", cpu);
> +               show_regs(regs);
> +               arch_spin_unlock(&lock);
> +               cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
> +       }
> +}
> +
> ...
> +void arch_trigger_all_cpu_backtrace(bool include_self)
> +{
> +       static unsigned long backtrace_flag;
> +       int i, cpu = get_cpu();
> +
> +       if (test_and_set_bit(0, &backtrace_flag)) {
> +               /*
> +                * If there is already a trigger_all_cpu_backtrace() in progress
> +                * (backtrace_flag == 1), don't output double cpu dump infos.
> +                */
> +               put_cpu();
> +               return;
> +       }
> +
> +       cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
> +       if (!include_self)
> +               cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
> +
> +       if (!cpumask_empty(to_cpumask(backtrace_mask))) {
> +               pr_info("Sending FIQ to %s CPUs:\n",
> +                       (include_self ? "all" : "other"));
> +               smp_cross_call(to_cpumask(backtrace_mask), IPI_CPU_BACKTRACE);
> +       }
> +
> +       /* Wait for up to 10 seconds for all CPUs to do the backtrace */
> +       for (i = 0; i < 10 * 1000; i++) {
> +               if (cpumask_empty(to_cpumask(backtrace_mask)))
> +                       break;
> +
> +               mdelay(1);
> +       }
> +
> +       clear_bit(0, &backtrace_flag);
> +       smp_mb__after_atomic();
> +       put_cpu();
> +}
> +
> +void __fiq_handle(struct pt_regs *regs)
> +{
> +       ipi_cpu_backtrace(regs);
> +}
> 
> arch/arm/kernel/setup.c:
> +static unsigned int fiq_stack[4][1024];
> +
> ...
> cpu_init()
> -       "msr    cpsr_c, %7"
> +       "msr    cpsr_c, %7\n\t"
> +       "mov    sp, %8\n\t"
> +       "msr    cpsr_c, %9"
> ...
> +             PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
> +             "r" (&fiq_stack[cpu][1024]),
> 
> The FIQ assembly code is basically the same as yours, but with:
> 
> +       .macro  fiq_handler
> +       bl      __fiq_handle
> +       .endm
> 
> and the code in svc_exit_via_fiq testing the PSR I flag and calling
> trace_hardirqs_on removed.
> 
> This does have one deficiency, and that is it doesn't EOI the FIQ
> interrupt - that's something which should be fixed, but for my
> purposes to track down where the locked CPU was, it wasn't strictly
> necessary that the system continued to work after this point.

EOIing IPIs should be pretty easy (it is safe to EOI them immediately
after the ack). This is also included in my existing IPI patches.


> This brings me to my second concern, and is the reason I decided not
> to ask for it for this merge window.
> 
> Calling the trace_* functions is a no-no from FIQ code.
> trace_hardirqs_on() can itself take locks, which can result in a
> deadlock.
> 
> I thought I'd made it clear that FIQ code can't take locks because
> there's no way of knowing what state they're in at the point that the
> FIQ fires - _irq() variants won't save you - and that's kind of the
> point of FIQ.  It's almost never masked by the kernel.

Don't worry, you certainly did make it clear!

I actually went as far as removing the trace_* calls before having a
change of heart. As a result I spent some time looking at the
trace_hardirqs_on() code and, as far as I remember, I couldn't find a
lock in the code that wasn't bypassed when in_nmi() returned true.

However the code is pretty complex and its certainly possible that I
missed something. Are you in a position to point any particular lock to
show I messed this up or are you working from memory?


> Now, You'll be forgiven if you now point out that in the code above,
> I'm taking a spinlock.  That's absolutely true.  Analyse the code
> a little closer and you'll notice it's done in a safe way.  There's
> only one time where that spinlock is taken and that's from FIQ code,
> never from any other code, and only once per CPU - notice how
> arch_trigger_all_cpu_backtrace() protects itself against multiple
> callers, and how ipi_cpu_backtrace() is careful to check that its
> CPU bit is set.  This is exactly the same method which x86 code uses
> (in fact, much of the above code was stolen from x86!)

Agreed. I also plan to use FIQ-safe locks in the GIC code to raise an
IPI. The b.L switcher code explicitly calls local_fiq_disable() so
providing the locks are contested only between the b.L switcher logic
and FIQ handlers it will be safe.

That said my original approach (again, I'll post it in a moment) was
pretty ugly which is why I'm so pleased with Stephen Boyd's recently
proposed change.


> So, how about moving the FIQ assembly code to entry-armv.S and making
> it less kgdb specific?  (Though... we do want to keep a /very/ close
> eye on users to ensure that they don't do silly stuff with locking.)

I think I can do that.

Something like this?

1. Install the current trap handler code by default (either with or
   without trace_* calls).

2. Have default trap handler call an RCU notifier chain to allow it to
   hook up with "normal" code without any hard coding (kgdb, IPI
   handling, etc)

3. Retain existing install_fiq() behaviour for people who want FIQ
   to be a fast-interrupt rather than an NMI (for example, the
   Raspberry pi USB optimizations).

4. Ensure default handler is an exported symbol to allow the meths
   drinkers from #3 to chain to logic for NMI/debug features
   if they want to.


Daniel.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC PATCH 0/3] arm: FIQ IPI support
  2014-08-14 10:48                   ` Daniel Thompson
@ 2014-08-14 11:15                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-14 11:15 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

This is a work-in-progress set of patches to add support for
implementing IPIs using FIQ. Currently KGDB is the only user
of this feature although others could easily be added due to
the use of notifier chains.

Patches depend on the KGDB NMI/FIQ patch series. I'll send
a complete patchset for the KGDB NMI/FIQ shortly after 3.17rc1 comes
out.

--
1.9.3


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC PATCH 0/3] arm: FIQ IPI support
@ 2014-08-14 11:15                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-14 11:15 UTC (permalink / raw)
  To: linux-arm-kernel

This is a work-in-progress set of patches to add support for
implementing IPIs using FIQ. Currently KGDB is the only user
of this feature although others could easily be added due to
the use of notifier chains.

Patches depend on the KGDB NMI/FIQ patch series. I'll send
a complete patchset for the KGDB NMI/FIQ shortly after 3.17rc1 comes
out.

--
1.9.3

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [RFC PATCH 1/3] arm: smp: Introduce a special IPI signalled using FIQ
  2014-08-14 11:15                     ` Daniel Thompson
@ 2014-08-14 11:15                       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-14 11:15 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

Cross CPU signalling based on FIQ is especially useful for kgdb since
it makes stopping all the CPUs during breakpointing more robust (some
of the other architectures already roundup the CPUs using NMIs).

The approach taken provides infrastructure that can be called (or not) by
the driver's FIQ handler depending upon it requirements. In other words
nothing is added here that prevents the driver from accessing "bare metal"
performance.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/hardirq.h |  2 +-
 arch/arm/include/asm/smp.h     | 11 +++++++++++
 arch/arm/kernel/smp.c          | 44 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
index fe3ea77..5df33e3 100644
--- a/arch/arm/include/asm/hardirq.h
+++ b/arch/arm/include/asm/hardirq.h
@@ -5,7 +5,7 @@
 #include <linux/threads.h>
 #include <asm/irq.h>
 
-#define NR_IPI	8
+#define NR_IPI	9
 
 typedef struct {
 	unsigned int __softirq_pending;
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2ec765c..6a969f8 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -20,6 +20,9 @@
 
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
+/* bitmap of IPIs that must be signalled using FIQ */
+#define SMP_IPI_FIQ_MASK 0x0100
+
 struct seq_file;
 
 /*
@@ -87,6 +90,14 @@ extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
 
 extern int register_ipi_completion(struct completion *completion, int cpu);
 
+#ifdef CONFIG_FIQ
+extern void send_fiq_ipi_mask(const struct cpumask *);
+extern int __init register_fiq_ipi_notifier(struct notifier_block *nb);
+void handle_IPI_FIQ(struct pt_regs *regs);
+#else
+#define register_fiq_ipi_notifier(nb)
+#endif
+
 struct smp_operations {
 #ifdef CONFIG_SMP
 	/*
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9388a3d..71557bc 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -72,6 +72,7 @@ enum ipi_msg_type {
 	IPI_CPU_STOP,
 	IPI_IRQ_WORK,
 	IPI_COMPLETION,
+	IPI_FIQ,
 };
 
 static DECLARE_COMPLETION(cpu_running);
@@ -451,6 +452,7 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
 	S(IPI_CPU_STOP, "CPU stop interrupts"),
 	S(IPI_IRQ_WORK, "IRQ work interrupts"),
 	S(IPI_COMPLETION, "completion interrupts"),
+	S(IPI_FIQ, "FIQ interrupts"),
 };
 
 static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
@@ -552,6 +554,42 @@ static void ipi_complete(unsigned int cpu)
 	complete(per_cpu(cpu_completion, cpu));
 }
 
+#ifdef CONFIG_FIQ
+static ATOMIC_NOTIFIER_HEAD(fiq_ipi_chain);
+
+/*
+ * Caller must ensure a FIQ handler that can clear the IPI is installed
+ * before calling this function. This is normally achieved by calling
+ * handle_IPI_FIQ() from the FIQ handler.
+ */
+void send_fiq_ipi_mask(const struct cpumask *mask)
+{
+	smp_cross_call(mask, IPI_FIQ);
+}
+
+int __init register_fiq_ipi_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&fiq_ipi_chain, nb);
+}
+
+void handle_IPI_FIQ(struct pt_regs *regs)
+{
+	unsigned int cpu = smp_processor_id();
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	/* Make sure the FIQ mask matches our assumptions */
+	BUILD_BUG_ON(SMP_IPI_FIQ_MASK ^ (1 << IPI_FIQ));
+
+	__inc_irq_stat(cpu, ipi_irqs[IPI_FIQ]);
+
+	nmi_enter();
+	atomic_notifier_call_chain(&fiq_ipi_chain, IPI_FIQ, NULL);
+	nmi_exit();
+
+	set_irq_regs(old_regs);
+}
+#endif
+
 /*
  * Main handler for inter-processor interrupts
  */
@@ -618,6 +656,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		irq_exit();
 		break;
 
+#ifdef CONFIG_FIQ
+	case IPI_FIQ:
+		pr_crit("CPU%u: IPI FIQ delivered via IRQ vector\n", cpu);
+		break;
+#endif
+
 	default:
 		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
 		       cpu, ipinr);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC PATCH 1/3] arm: smp: Introduce a special IPI signalled using FIQ
@ 2014-08-14 11:15                       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-14 11:15 UTC (permalink / raw)
  To: linux-arm-kernel

Cross CPU signalling based on FIQ is especially useful for kgdb since
it makes stopping all the CPUs during breakpointing more robust (some
of the other architectures already roundup the CPUs using NMIs).

The approach taken provides infrastructure that can be called (or not) by
the driver's FIQ handler depending upon it requirements. In other words
nothing is added here that prevents the driver from accessing "bare metal"
performance.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/hardirq.h |  2 +-
 arch/arm/include/asm/smp.h     | 11 +++++++++++
 arch/arm/kernel/smp.c          | 44 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
index fe3ea77..5df33e3 100644
--- a/arch/arm/include/asm/hardirq.h
+++ b/arch/arm/include/asm/hardirq.h
@@ -5,7 +5,7 @@
 #include <linux/threads.h>
 #include <asm/irq.h>
 
-#define NR_IPI	8
+#define NR_IPI	9
 
 typedef struct {
 	unsigned int __softirq_pending;
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2ec765c..6a969f8 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -20,6 +20,9 @@
 
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
+/* bitmap of IPIs that must be signalled using FIQ */
+#define SMP_IPI_FIQ_MASK 0x0100
+
 struct seq_file;
 
 /*
@@ -87,6 +90,14 @@ extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
 
 extern int register_ipi_completion(struct completion *completion, int cpu);
 
+#ifdef CONFIG_FIQ
+extern void send_fiq_ipi_mask(const struct cpumask *);
+extern int __init register_fiq_ipi_notifier(struct notifier_block *nb);
+void handle_IPI_FIQ(struct pt_regs *regs);
+#else
+#define register_fiq_ipi_notifier(nb)
+#endif
+
 struct smp_operations {
 #ifdef CONFIG_SMP
 	/*
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9388a3d..71557bc 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -72,6 +72,7 @@ enum ipi_msg_type {
 	IPI_CPU_STOP,
 	IPI_IRQ_WORK,
 	IPI_COMPLETION,
+	IPI_FIQ,
 };
 
 static DECLARE_COMPLETION(cpu_running);
@@ -451,6 +452,7 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
 	S(IPI_CPU_STOP, "CPU stop interrupts"),
 	S(IPI_IRQ_WORK, "IRQ work interrupts"),
 	S(IPI_COMPLETION, "completion interrupts"),
+	S(IPI_FIQ, "FIQ interrupts"),
 };
 
 static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
@@ -552,6 +554,42 @@ static void ipi_complete(unsigned int cpu)
 	complete(per_cpu(cpu_completion, cpu));
 }
 
+#ifdef CONFIG_FIQ
+static ATOMIC_NOTIFIER_HEAD(fiq_ipi_chain);
+
+/*
+ * Caller must ensure a FIQ handler that can clear the IPI is installed
+ * before calling this function. This is normally achieved by calling
+ * handle_IPI_FIQ() from the FIQ handler.
+ */
+void send_fiq_ipi_mask(const struct cpumask *mask)
+{
+	smp_cross_call(mask, IPI_FIQ);
+}
+
+int __init register_fiq_ipi_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&fiq_ipi_chain, nb);
+}
+
+void handle_IPI_FIQ(struct pt_regs *regs)
+{
+	unsigned int cpu = smp_processor_id();
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	/* Make sure the FIQ mask matches our assumptions */
+	BUILD_BUG_ON(SMP_IPI_FIQ_MASK ^ (1 << IPI_FIQ));
+
+	__inc_irq_stat(cpu, ipi_irqs[IPI_FIQ]);
+
+	nmi_enter();
+	atomic_notifier_call_chain(&fiq_ipi_chain, IPI_FIQ, NULL);
+	nmi_exit();
+
+	set_irq_regs(old_regs);
+}
+#endif
+
 /*
  * Main handler for inter-processor interrupts
  */
@@ -618,6 +656,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		irq_exit();
 		break;
 
+#ifdef CONFIG_FIQ
+	case IPI_FIQ:
+		pr_crit("CPU%u: IPI FIQ delivered via IRQ vector\n", cpu);
+		break;
+#endif
+
 	default:
 		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
 		       cpu, ipinr);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC PATCH 2/3] arm: kgdb: Add support for IPI FIQ roundup
  2014-08-14 11:15                     ` Daniel Thompson
@ 2014-08-14 11:15                       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-14 11:15 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

Rounding up the other CPUs using FIQ improves debugger robustness.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/kgdb.h |  1 +
 arch/arm/kernel/kgdb.c      | 20 ++++++++++++++++----
 arch/arm/kernel/kgdb_fiq.c  |  7 ++++++-
 3 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 5de21f01..ceb466f 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -50,6 +50,7 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern int kgdb_fiq_enabled;
 extern char kgdb_fiq_handler;
 extern char kgdb_fiq_handler_end;
 asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs);
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
index a74b53c..e5c3ec0 100644
--- a/arch/arm/kernel/kgdb.c
+++ b/arch/arm/kernel/kgdb.c
@@ -175,14 +175,26 @@ static struct undef_hook kgdb_compiled_brkpt_hook = {
 
 static void kgdb_call_nmi_hook(void *ignored)
 {
-       kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+	kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
 }
 
 void kgdb_roundup_cpus(unsigned long flags)
 {
-       local_irq_enable();
-       smp_call_function(kgdb_call_nmi_hook, NULL, 0);
-       local_irq_disable();
+#ifdef CONFIG_FIQ
+	struct cpumask mask;
+
+	if (kgdb_fiq_enabled) {
+		cpumask_copy(&mask, cpu_online_mask);
+		cpumask_clear_cpu(raw_smp_processor_id(), &mask);
+		if (!cpumask_empty(&mask))
+			send_fiq_ipi_mask(&mask);
+		return;
+	}
+#endif
+
+	local_irq_enable();
+	smp_call_function(kgdb_call_nmi_hook, NULL, 0);
+	local_irq_disable();
 }
 
 static int __kgdb_notify(struct die_args *args, unsigned long cmd)
diff --git a/arch/arm/kernel/kgdb_fiq.c b/arch/arm/kernel/kgdb_fiq.c
index a894dde..f7a2c3d 100644
--- a/arch/arm/kernel/kgdb_fiq.c
+++ b/arch/arm/kernel/kgdb_fiq.c
@@ -24,7 +24,7 @@
 #include <asm/fiq.h>
 #include <asm/exception.h>
 
-static int kgdb_fiq_enabled;
+int kgdb_fiq_enabled;
 module_param_named(enable, kgdb_fiq_enabled, int, 0600);
 MODULE_PARM_DESC(enable, "set to 1 to enable FIQ KGDB");
 
@@ -40,6 +40,11 @@ asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs)
 {
 	int actual;
 
+	if (!kgdb_nmicallback(raw_smp_processor_id(), regs)) {
+		handle_IPI_FIQ(regs);
+		return;
+	}
+
 	nmi_enter();
 	actual = ack_fiq(kgdb_fiq);
 	WARN_ON(actual != kgdb_fiq);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC PATCH 2/3] arm: kgdb: Add support for IPI FIQ roundup
@ 2014-08-14 11:15                       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-14 11:15 UTC (permalink / raw)
  To: linux-arm-kernel

Rounding up the other CPUs using FIQ improves debugger robustness.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/kgdb.h |  1 +
 arch/arm/kernel/kgdb.c      | 20 ++++++++++++++++----
 arch/arm/kernel/kgdb_fiq.c  |  7 ++++++-
 3 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 5de21f01..ceb466f 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -50,6 +50,7 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern int kgdb_fiq_enabled;
 extern char kgdb_fiq_handler;
 extern char kgdb_fiq_handler_end;
 asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs);
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
index a74b53c..e5c3ec0 100644
--- a/arch/arm/kernel/kgdb.c
+++ b/arch/arm/kernel/kgdb.c
@@ -175,14 +175,26 @@ static struct undef_hook kgdb_compiled_brkpt_hook = {
 
 static void kgdb_call_nmi_hook(void *ignored)
 {
-       kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+	kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
 }
 
 void kgdb_roundup_cpus(unsigned long flags)
 {
-       local_irq_enable();
-       smp_call_function(kgdb_call_nmi_hook, NULL, 0);
-       local_irq_disable();
+#ifdef CONFIG_FIQ
+	struct cpumask mask;
+
+	if (kgdb_fiq_enabled) {
+		cpumask_copy(&mask, cpu_online_mask);
+		cpumask_clear_cpu(raw_smp_processor_id(), &mask);
+		if (!cpumask_empty(&mask))
+			send_fiq_ipi_mask(&mask);
+		return;
+	}
+#endif
+
+	local_irq_enable();
+	smp_call_function(kgdb_call_nmi_hook, NULL, 0);
+	local_irq_disable();
 }
 
 static int __kgdb_notify(struct die_args *args, unsigned long cmd)
diff --git a/arch/arm/kernel/kgdb_fiq.c b/arch/arm/kernel/kgdb_fiq.c
index a894dde..f7a2c3d 100644
--- a/arch/arm/kernel/kgdb_fiq.c
+++ b/arch/arm/kernel/kgdb_fiq.c
@@ -24,7 +24,7 @@
 #include <asm/fiq.h>
 #include <asm/exception.h>
 
-static int kgdb_fiq_enabled;
+int kgdb_fiq_enabled;
 module_param_named(enable, kgdb_fiq_enabled, int, 0600);
 MODULE_PARM_DESC(enable, "set to 1 to enable FIQ KGDB");
 
@@ -40,6 +40,11 @@ asmlinkage void __exception_irq_entry kgdb_fiq_do_handle(struct pt_regs *regs)
 {
 	int actual;
 
+	if (!kgdb_nmicallback(raw_smp_processor_id(), regs)) {
+		handle_IPI_FIQ(regs);
+		return;
+	}
+
 	nmi_enter();
 	actual = ack_fiq(kgdb_fiq);
 	WARN_ON(actual != kgdb_fiq);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC PATCH 3/3] irqchip: gic: Add support for IPI FIQ
  2014-08-14 11:15                     ` Daniel Thompson
@ 2014-08-14 11:15                       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-14 11:15 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

To support IPI FIQ we alter gic_cpu_init() to honour SMP_IPI_FIQ_MASK and
register a fairly high priority notifier to acknowledge and clear the IPI
when it is triggered.

For the IPI FIQ to be useful we must also make it safe to call
gic_raise_softirq() from the FIQ handler by altering the locking
strategy slightly.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/irqchip/irq-gic.c | 126 +++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 107 insertions(+), 19 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index d928912..240cc87 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,6 +39,7 @@
 #include <linux/slab.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/ratelimit.h>
 
 #include <asm/cputype.h>
 #ifdef CONFIG_FIQ
@@ -51,6 +52,10 @@
 #include "irq-gic-common.h"
 #include "irqchip.h"
 
+#ifndef SMP_IPI_FIQ_MASK
+#define SMP_IPI_FIQ_MASK 0
+#endif
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -77,6 +82,8 @@ struct gic_chip_data {
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+/* A fiq-safe spinlock must only be locked when the FIQ is masked */
+static DEFINE_RAW_SPINLOCK(fiq_safe_migration_lock);
 
 /*
  * The GIC mapping of CPU interfaces does not necessarily match
@@ -346,20 +353,21 @@ static struct irq_chip gic_chip = {
  * match what "ARM strongly recommends" for a system where no Group 1
  * interrupt must ever preempt a Group 0 interrupt.
  */
-static void gic_set_group_irq(struct irq_data *d, int group)
+static void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				int group)
 {
-	unsigned int grp_reg = gic_irq(d) / 32 * 4;
-	u32 grp_mask = 1 << (gic_irq(d) % 32);
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_mask = 1 << (hwirq % 32);
 	u32 grp_val;
 
-	unsigned int pri_reg = (gic_irq(d) / 4) * 4;
-	u32 pri_mask = 1 << (7 + ((gic_irq(d) % 4) * 8));
+	unsigned int pri_reg = (hwirq / 4) * 4;
+	u32 pri_mask = 1 << (7 + ((hwirq % 4) * 8));
 	u32 pri_val;
 
 	raw_spin_lock(&irq_controller_lock);
 
-	grp_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
-	pri_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(base + GIC_DIST_PRI + pri_reg);
 
 	if (group) {
 		grp_val |= grp_mask;
@@ -369,20 +377,20 @@ static void gic_set_group_irq(struct irq_data *d, int group)
 		pri_val &= ~pri_mask;
 	}
 
-	writel_relaxed(grp_val, gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
-	writel_relaxed(pri_val, gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+	writel_relaxed(grp_val, base + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, base + GIC_DIST_PRI + pri_reg);
 
 	raw_spin_unlock(&irq_controller_lock);
 }
 
 static void gic_enable_fiq(struct irq_data *d)
 {
-	gic_set_group_irq(d, 0);
+	gic_set_group_irq(gic_dist_base(d), gic_irq(d), 0);
 }
 
 static void gic_disable_fiq(struct irq_data *d)
 {
-	gic_set_group_irq(d, 1);
+	gic_set_group_irq(gic_dist_base(d), gic_irq(d), 1);
 }
 
 static int gic_ack_fiq(struct irq_data *d)
@@ -430,7 +438,63 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 	for (i = 0; i < num_irqs; i++)
 		fiq_register_mapping(first_irq + i, &gic_fiq);
 }
+
+/*
+ * Fully acknowledge (both ack and eoi) a FIQ-based IPI
+ */
+static int gic_eoi_fiq_ipi(struct notifier_block *nb, unsigned long expected,
+			   void *data)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	unsigned long irqstat, irqnr, last_irqnr;
+
+	if (WARN_ON(!in_nmi()))
+		return NOTIFY_BAD;
+
+	irqnr = -1;
+	do {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+
+		last_irqnr = irqnr;
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		if (likely(irqnr == expected))
+			return NOTIFY_OK;
+
+		/* We're in pretty serious trouble if we get here. We cannot
+		 * safely call the handler for the unexpected interrupt either
+		 * because we don't know how (if it is a FIQ) or we can't do so
+		 * safely (if it is an IRQ). The only recovery possible is to
+		 * spuriously EOI (which we've already done by this point) and
+		 * hope this is sufficient to clear the spurious FIQ.
+		 */
+		WARN_RATELIMIT(1, "Unexpected irqnr %lu (expected %lu)\n",
+			       irqnr, expected);
+	} while (last_irqnr != irqnr);
+
+	/* We've become stuck EOIing the same interrupt. There's nothing
+	 * more we can do here except hope that "something has changed" and
+	 * that the FIQ handler doesn't re-enter.
+	 *
+	 * We ratelimit the message because expecting something to change
+	 * is really quite optimistic.
+	 */
+	pr_crit_ratelimited("gic_eoi_fiq_ipi: Stuck on %lu, giving up\n",
+			    irqnr);
+	return NOTIFY_BAD;
+}
+
+/*
+ * Notifier to ensure IPI FIQ is acknowledged correctly.
+ */
+static struct notifier_block gic_fiq_ipi_notifier = {
+	.notifier_call = gic_eoi_fiq_ipi,
+	.priority = 100,
+};
 #else /* CONFIG_FIQ */
+static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				     int group) {}
 static inline void gic_init_fiq(struct gic_chip_data *gic,
 				irq_hw_number_t first_irq,
 				unsigned int num_irqs) {}
@@ -508,6 +572,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	void __iomem *base = gic_data_cpu_base(gic);
 	unsigned int cpu_mask, cpu = smp_processor_id();
 	int i;
+	u32 val;
 
 	/*
 	 * Get what the GIC says our CPU mask is.
@@ -527,14 +592,19 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	gic_cpu_config(dist_base, NULL);
 
 	/*
-	 * Set all PPI and SGI interrupts to be group 1.
-	 *
-	 * If grouping is not available (not implemented or prohibited by
-	 * security mode) these registers are read-as-zero/write-ignored.
+	 * Optionally set all PPI and SGI interrupts to be group 1.
 	 */
 	if (gic_data_fiq_enable(gic))
 		writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
 
+	/*
+	 * Optionally shift the FIQ based IPIs to group 0.
+	 */
+	if (gic_data_fiq_enable(gic))
+		for (i = 0; i < 16; i++)
+			if (SMP_IPI_FIQ_MASK & (1 << i))
+				gic_set_group_irq(dist_base, i, 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
 	if (gic_data_fiq_enable(gic))
 		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
@@ -747,7 +817,17 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	unsigned long flags, map = 0;
 	unsigned long softint;
 
-	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+	/*
+	 * The locking in this function ensures we don't use stale cpu mappings
+	 * and thus we never route an IPI to the wrong physical core during a
+	 * big.LITTLE switch. The switch code takes both of these locks meaning
+	 * we can choose whichever lock is safe to use from our current calling
+	 * context.
+	 */
+	if (in_nmi())
+		raw_spin_lock(&fiq_safe_migration_lock);
+	else
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
 	/* Convert our logical CPU mask into a physical one. */
 	for_each_cpu(cpu, mask)
@@ -761,12 +841,16 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 
 	/* this always happens on GIC0 */
 	softint = map << 16 | irq;
-	if (gic_data_fiq_enable(&gic_data[0]))
+	if (gic_data_fiq_enable(&gic_data[0]) &&
+	    !(SMP_IPI_FIQ_MASK & (1 << irq)))
 		softint |= 0x8000;
 	writel_relaxed(softint,
 		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
-	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+	if (in_nmi())
+		raw_spin_unlock(&fiq_safe_migration_lock);
+	else
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 #endif
 
@@ -814,7 +898,7 @@ int gic_get_cpu_id(unsigned int cpu)
  * Migrate all peripheral interrupts with a target matching the current CPU
  * to the interface corresponding to @new_cpu_id.  The CPU interface mapping
  * is also updated.  Targets to other CPU interfaces are unchanged.
- * This must be called with IRQs locally disabled.
+ * This must be called with IRQ and FIQ locally disabled.
  */
 void gic_migrate_target(unsigned int new_cpu_id)
 {
@@ -836,6 +920,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 	ror_val = (cur_cpu_id - new_cpu_id) & 31;
 
 	raw_spin_lock(&irq_controller_lock);
+	raw_spin_lock(&fiq_safe_migration_lock);
 
 	/* Update the target interface for this logical CPU */
 	gic_cpu_map[cpu] = 1 << new_cpu_id;
@@ -855,6 +940,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 		}
 	}
 
+	raw_spin_unlock(&fiq_safe_migration_lock);
 	raw_spin_unlock(&irq_controller_lock);
 
 	/*
@@ -1125,6 +1211,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 #ifdef CONFIG_SMP
 		set_smp_cross_call(gic_raise_softirq);
 		register_cpu_notifier(&gic_cpu_notifier);
+		if (gic_data_fiq_enable(gic))
+			register_fiq_ipi_notifier(&gic_fiq_ipi_notifier);
 #endif
 		set_handle_irq(gic_handle_irq);
 	}
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [RFC PATCH 3/3] irqchip: gic: Add support for IPI FIQ
@ 2014-08-14 11:15                       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-14 11:15 UTC (permalink / raw)
  To: linux-arm-kernel

To support IPI FIQ we alter gic_cpu_init() to honour SMP_IPI_FIQ_MASK and
register a fairly high priority notifier to acknowledge and clear the IPI
when it is triggered.

For the IPI FIQ to be useful we must also make it safe to call
gic_raise_softirq() from the FIQ handler by altering the locking
strategy slightly.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/irqchip/irq-gic.c | 126 +++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 107 insertions(+), 19 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index d928912..240cc87 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,6 +39,7 @@
 #include <linux/slab.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/ratelimit.h>
 
 #include <asm/cputype.h>
 #ifdef CONFIG_FIQ
@@ -51,6 +52,10 @@
 #include "irq-gic-common.h"
 #include "irqchip.h"
 
+#ifndef SMP_IPI_FIQ_MASK
+#define SMP_IPI_FIQ_MASK 0
+#endif
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -77,6 +82,8 @@ struct gic_chip_data {
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+/* A fiq-safe spinlock must only be locked when the FIQ is masked */
+static DEFINE_RAW_SPINLOCK(fiq_safe_migration_lock);
 
 /*
  * The GIC mapping of CPU interfaces does not necessarily match
@@ -346,20 +353,21 @@ static struct irq_chip gic_chip = {
  * match what "ARM strongly recommends" for a system where no Group 1
  * interrupt must ever preempt a Group 0 interrupt.
  */
-static void gic_set_group_irq(struct irq_data *d, int group)
+static void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				int group)
 {
-	unsigned int grp_reg = gic_irq(d) / 32 * 4;
-	u32 grp_mask = 1 << (gic_irq(d) % 32);
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_mask = 1 << (hwirq % 32);
 	u32 grp_val;
 
-	unsigned int pri_reg = (gic_irq(d) / 4) * 4;
-	u32 pri_mask = 1 << (7 + ((gic_irq(d) % 4) * 8));
+	unsigned int pri_reg = (hwirq / 4) * 4;
+	u32 pri_mask = 1 << (7 + ((hwirq % 4) * 8));
 	u32 pri_val;
 
 	raw_spin_lock(&irq_controller_lock);
 
-	grp_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
-	pri_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(base + GIC_DIST_PRI + pri_reg);
 
 	if (group) {
 		grp_val |= grp_mask;
@@ -369,20 +377,20 @@ static void gic_set_group_irq(struct irq_data *d, int group)
 		pri_val &= ~pri_mask;
 	}
 
-	writel_relaxed(grp_val, gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
-	writel_relaxed(pri_val, gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+	writel_relaxed(grp_val, base + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, base + GIC_DIST_PRI + pri_reg);
 
 	raw_spin_unlock(&irq_controller_lock);
 }
 
 static void gic_enable_fiq(struct irq_data *d)
 {
-	gic_set_group_irq(d, 0);
+	gic_set_group_irq(gic_dist_base(d), gic_irq(d), 0);
 }
 
 static void gic_disable_fiq(struct irq_data *d)
 {
-	gic_set_group_irq(d, 1);
+	gic_set_group_irq(gic_dist_base(d), gic_irq(d), 1);
 }
 
 static int gic_ack_fiq(struct irq_data *d)
@@ -430,7 +438,63 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 	for (i = 0; i < num_irqs; i++)
 		fiq_register_mapping(first_irq + i, &gic_fiq);
 }
+
+/*
+ * Fully acknowledge (both ack and eoi) a FIQ-based IPI
+ */
+static int gic_eoi_fiq_ipi(struct notifier_block *nb, unsigned long expected,
+			   void *data)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	unsigned long irqstat, irqnr, last_irqnr;
+
+	if (WARN_ON(!in_nmi()))
+		return NOTIFY_BAD;
+
+	irqnr = -1;
+	do {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+
+		last_irqnr = irqnr;
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		if (likely(irqnr == expected))
+			return NOTIFY_OK;
+
+		/* We're in pretty serious trouble if we get here. We cannot
+		 * safely call the handler for the unexpected interrupt either
+		 * because we don't know how (if it is a FIQ) or we can't do so
+		 * safely (if it is an IRQ). The only recovery possible is to
+		 * spuriously EOI (which we've already done by this point) and
+		 * hope this is sufficient to clear the spurious FIQ.
+		 */
+		WARN_RATELIMIT(1, "Unexpected irqnr %lu (expected %lu)\n",
+			       irqnr, expected);
+	} while (last_irqnr != irqnr);
+
+	/* We've become stuck EOIing the same interrupt. There's nothing
+	 * more we can do here except hope that "something has changed" and
+	 * that the FIQ handler doesn't re-enter.
+	 *
+	 * We ratelimit the message because expecting something to change
+	 * is really quite optimistic.
+	 */
+	pr_crit_ratelimited("gic_eoi_fiq_ipi: Stuck on %lu, giving up\n",
+			    irqnr);
+	return NOTIFY_BAD;
+}
+
+/*
+ * Notifier to ensure IPI FIQ is acknowledged correctly.
+ */
+static struct notifier_block gic_fiq_ipi_notifier = {
+	.notifier_call = gic_eoi_fiq_ipi,
+	.priority = 100,
+};
 #else /* CONFIG_FIQ */
+static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				     int group) {}
 static inline void gic_init_fiq(struct gic_chip_data *gic,
 				irq_hw_number_t first_irq,
 				unsigned int num_irqs) {}
@@ -508,6 +572,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	void __iomem *base = gic_data_cpu_base(gic);
 	unsigned int cpu_mask, cpu = smp_processor_id();
 	int i;
+	u32 val;
 
 	/*
 	 * Get what the GIC says our CPU mask is.
@@ -527,14 +592,19 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	gic_cpu_config(dist_base, NULL);
 
 	/*
-	 * Set all PPI and SGI interrupts to be group 1.
-	 *
-	 * If grouping is not available (not implemented or prohibited by
-	 * security mode) these registers are read-as-zero/write-ignored.
+	 * Optionally set all PPI and SGI interrupts to be group 1.
 	 */
 	if (gic_data_fiq_enable(gic))
 		writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
 
+	/*
+	 * Optionally shift the FIQ based IPIs to group 0.
+	 */
+	if (gic_data_fiq_enable(gic))
+		for (i = 0; i < 16; i++)
+			if (SMP_IPI_FIQ_MASK & (1 << i))
+				gic_set_group_irq(dist_base, i, 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
 	if (gic_data_fiq_enable(gic))
 		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
@@ -747,7 +817,17 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	unsigned long flags, map = 0;
 	unsigned long softint;
 
-	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+	/*
+	 * The locking in this function ensures we don't use stale cpu mappings
+	 * and thus we never route an IPI to the wrong physical core during a
+	 * big.LITTLE switch. The switch code takes both of these locks meaning
+	 * we can choose whichever lock is safe to use from our current calling
+	 * context.
+	 */
+	if (in_nmi())
+		raw_spin_lock(&fiq_safe_migration_lock);
+	else
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
 	/* Convert our logical CPU mask into a physical one. */
 	for_each_cpu(cpu, mask)
@@ -761,12 +841,16 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 
 	/* this always happens on GIC0 */
 	softint = map << 16 | irq;
-	if (gic_data_fiq_enable(&gic_data[0]))
+	if (gic_data_fiq_enable(&gic_data[0]) &&
+	    !(SMP_IPI_FIQ_MASK & (1 << irq)))
 		softint |= 0x8000;
 	writel_relaxed(softint,
 		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
-	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+	if (in_nmi())
+		raw_spin_unlock(&fiq_safe_migration_lock);
+	else
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 #endif
 
@@ -814,7 +898,7 @@ int gic_get_cpu_id(unsigned int cpu)
  * Migrate all peripheral interrupts with a target matching the current CPU
  * to the interface corresponding to @new_cpu_id.  The CPU interface mapping
  * is also updated.  Targets to other CPU interfaces are unchanged.
- * This must be called with IRQs locally disabled.
+ * This must be called with IRQ and FIQ locally disabled.
  */
 void gic_migrate_target(unsigned int new_cpu_id)
 {
@@ -836,6 +920,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 	ror_val = (cur_cpu_id - new_cpu_id) & 31;
 
 	raw_spin_lock(&irq_controller_lock);
+	raw_spin_lock(&fiq_safe_migration_lock);
 
 	/* Update the target interface for this logical CPU */
 	gic_cpu_map[cpu] = 1 << new_cpu_id;
@@ -855,6 +940,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 		}
 	}
 
+	raw_spin_unlock(&fiq_safe_migration_lock);
 	raw_spin_unlock(&irq_controller_lock);
 
 	/*
@@ -1125,6 +1211,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 #ifdef CONFIG_SMP
 		set_smp_cross_call(gic_raise_softirq);
 		register_cpu_notifier(&gic_cpu_notifier);
+		if (gic_data_fiq_enable(gic))
+			register_fiq_ipi_notifier(&gic_fiq_ipi_notifier);
 #endif
 		set_handle_irq(gic_handle_irq);
 	}
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* Re: [PATCH v8 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
  2014-08-14 10:48                   ` Daniel Thompson
@ 2014-08-14 12:36                     ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-08-14 12:36 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Anton Vorontsov, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Colin Cross, kernel-team,
	Rob Herring, Linus Walleij, Ben Dooks, Catalin Marinas,
	Dave Martin, Fabio Estevam, Frederic Weisbecker, Nicolas Pitre

On Thu, Aug 14, 2014 at 11:48:36AM +0100, Daniel Thompson wrote:
> Don't worry, you certainly did make it clear!
> 
> I actually went as far as removing the trace_* calls before having a
> change of heart. As a result I spent some time looking at the
> trace_hardirqs_on() code and, as far as I remember, I couldn't find a
> lock in the code that wasn't bypassed when in_nmi() returned true.
> 
> However the code is pretty complex and its certainly possible that I
> missed something. Are you in a position to point any particular lock to
> show I messed this up or are you working from memory?

The complexity alone is an argument against calling it from FIQ context,
because there's no guarantee that what's there will stay that way.

trace_hardirqs_on() is made more complex because there's not one function
with that name, but two.  One is in the trace code, the other is in the
lockdep code.  Here's the trace code, which has at least two problems:

trace_hardirqs_on
 -> stop_critical_timing
  -> check_critical_timing
   -> raw_spin_lock_irqsave(&max_trace_lock, flags);
   -> __trace_stack
    -> __ftrace_trace_stack
     -> save_stack_trace
      -> __save_stack_trace
       -> walk_stackframe
        -> unwind_frame
         -> unwind_find_idx
          -> spin_lock_irqsave(&unwind_lock, flags);

> > So, how about moving the FIQ assembly code to entry-armv.S and making
> > it less kgdb specific?  (Though... we do want to keep a /very/ close
> > eye on users to ensure that they don't do silly stuff with locking.)
> 
> I think I can do that.
> 
> Something like this?
> 
> 1. Install the current trap handler code by default (either with or
>    without trace_* calls).

Without trace_* calls.  The FIQ should be transparent to tracing -
tracing and lockdep is too much of an unknown (due to size and
complexity) to ensure that it always follows the rules.

> 2. Have default trap handler call an RCU notifier chain to allow it to
>    hook up with "normal" code without any hard coding (kgdb, IPI
>    handling, etc)

Maybe... that sounds like it opens up FIQ for general purpose use which
is something I want to avoid - I've little motivation to ensure that
everyone plays by the rules.  Given the choice, I'd rather maintain our
present stance that using FIQs is hard and requires a lot of thought.

> 3. Retain existing install_fiq() behaviour for people who want FIQ
>    to be a fast-interrupt rather than an NMI (for example, the
>    Raspberry pi USB optimizations).

Yes, arch/arm/kernel/fiq.c should be relatively untouched by the core
mods I suggested - we're just replacing the default "subs" instruction
(which just ignores the FIQ) with something which can do something
with it.

It should be noted that using arch/arm/kernel/fiq.c would override this
default FIQ handler - and that's a feature of it - fiq.c is based on
the premise that there is only one single owner of the FIQ at any one
time and there is no sharing of it, and that's something we want to
retain.

> 4. Ensure default handler is an exported symbol to allow the meths
>    drinkers from #3 to chain to logic for NMI/debug features
>    if they want to.

That's not something I particularly want to permit - especially as the
requirements for each "handler" are different - this new default code
relies upon r13 pointing at some storage to save some registers, which
may not be true of other FIQ handlers.  Chaining it means that we
force that use of r13 on others, and we then have to also come up with
some way to export the correct r13 value.

Given that fiq.c doesn't work with SMP, this isn't something I want to
encourage.

Further more, I can't get excited about Raspberry Pi "optimisations"
using FIQ until I see the code, and I see no reason to think about
catering for such stuff until the patches become visible here.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v8 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
@ 2014-08-14 12:36                     ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-08-14 12:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 14, 2014 at 11:48:36AM +0100, Daniel Thompson wrote:
> Don't worry, you certainly did make it clear!
> 
> I actually went as far as removing the trace_* calls before having a
> change of heart. As a result I spent some time looking at the
> trace_hardirqs_on() code and, as far as I remember, I couldn't find a
> lock in the code that wasn't bypassed when in_nmi() returned true.
> 
> However the code is pretty complex and its certainly possible that I
> missed something. Are you in a position to point any particular lock to
> show I messed this up or are you working from memory?

The complexity alone is an argument against calling it from FIQ context,
because there's no guarantee that what's there will stay that way.

trace_hardirqs_on() is made more complex because there's not one function
with that name, but two.  One is in the trace code, the other is in the
lockdep code.  Here's the trace code, which has at least two problems:

trace_hardirqs_on
 -> stop_critical_timing
  -> check_critical_timing
   -> raw_spin_lock_irqsave(&max_trace_lock, flags);
   -> __trace_stack
    -> __ftrace_trace_stack
     -> save_stack_trace
      -> __save_stack_trace
       -> walk_stackframe
        -> unwind_frame
         -> unwind_find_idx
          -> spin_lock_irqsave(&unwind_lock, flags);

> > So, how about moving the FIQ assembly code to entry-armv.S and making
> > it less kgdb specific?  (Though... we do want to keep a /very/ close
> > eye on users to ensure that they don't do silly stuff with locking.)
> 
> I think I can do that.
> 
> Something like this?
> 
> 1. Install the current trap handler code by default (either with or
>    without trace_* calls).

Without trace_* calls.  The FIQ should be transparent to tracing -
tracing and lockdep is too much of an unknown (due to size and
complexity) to ensure that it always follows the rules.

> 2. Have default trap handler call an RCU notifier chain to allow it to
>    hook up with "normal" code without any hard coding (kgdb, IPI
>    handling, etc)

Maybe... that sounds like it opens up FIQ for general purpose use which
is something I want to avoid - I've little motivation to ensure that
everyone plays by the rules.  Given the choice, I'd rather maintain our
present stance that using FIQs is hard and requires a lot of thought.

> 3. Retain existing install_fiq() behaviour for people who want FIQ
>    to be a fast-interrupt rather than an NMI (for example, the
>    Raspberry pi USB optimizations).

Yes, arch/arm/kernel/fiq.c should be relatively untouched by the core
mods I suggested - we're just replacing the default "subs" instruction
(which just ignores the FIQ) with something which can do something
with it.

It should be noted that using arch/arm/kernel/fiq.c would override this
default FIQ handler - and that's a feature of it - fiq.c is based on
the premise that there is only one single owner of the FIQ at any one
time and there is no sharing of it, and that's something we want to
retain.

> 4. Ensure default handler is an exported symbol to allow the meths
>    drinkers from #3 to chain to logic for NMI/debug features
>    if they want to.

That's not something I particularly want to permit - especially as the
requirements for each "handler" are different - this new default code
relies upon r13 pointing at some storage to save some registers, which
may not be true of other FIQ handlers.  Chaining it means that we
force that use of r13 on others, and we then have to also come up with
some way to export the correct r13 value.

Given that fiq.c doesn't work with SMP, this isn't something I want to
encourage.

Further more, I can't get excited about Raspberry Pi "optimisations"
using FIQ until I see the code, and I see no reason to think about
catering for such stuff until the patches become visible here.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v8 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
  2014-08-14 12:36                     ` Russell King - ARM Linux
@ 2014-08-14 15:02                       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-14 15:02 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Anton Vorontsov, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Colin Cross, kernel-team,
	Rob Herring, Linus Walleij, Ben Dooks, Catalin Marinas,
	Dave Martin, Fabio Estevam, Frederic Weisbecker, Nicolas Pitre

On 14/08/14 13:36, Russell King - ARM Linux wrote:
> On Thu, Aug 14, 2014 at 11:48:36AM +0100, Daniel Thompson wrote:
>> Don't worry, you certainly did make it clear!
>>
>> I actually went as far as removing the trace_* calls before having a
>> change of heart. As a result I spent some time looking at the
>> trace_hardirqs_on() code and, as far as I remember, I couldn't find a
>> lock in the code that wasn't bypassed when in_nmi() returned true.
>>
>> However the code is pretty complex and its certainly possible that I
>> missed something. Are you in a position to point any particular lock to
>> show I messed this up or are you working from memory?
> 
> The complexity alone is an argument against calling it from FIQ context,
> because there's no guarantee that what's there will stay that way.
> 
> trace_hardirqs_on() is made more complex because there's not one function
> with that name, but two.  One is in the trace code, the other is in the
> lockdep code.  Here's the trace code, which has at least two problems:
> 
> trace_hardirqs_on
>  -> stop_critical_timing
>   -> check_critical_timing
>    -> raw_spin_lock_irqsave(&max_trace_lock, flags);
>    -> __trace_stack
>     -> __ftrace_trace_stack
>      -> save_stack_trace
>       -> __save_stack_trace
>        -> walk_stackframe
>         -> unwind_frame
>          -> unwind_find_idx
>           -> spin_lock_irqsave(&unwind_lock, flags);

Looks like I had an out-by-one error when reviewing this... sadly the
value was boolean.

Thanks this is very clear.


>>> So, how about moving the FIQ assembly code to entry-armv.S and making
>>> it less kgdb specific?  (Though... we do want to keep a /very/ close
>>> eye on users to ensure that they don't do silly stuff with locking.)
>>
>> I think I can do that.
>>
>> Something like this?
>>
>> 1. Install the current trap handler code by default (either with or
>>    without trace_* calls).
> 
> Without trace_* calls.  The FIQ should be transparent to tracing -
> tracing and lockdep is too much of an unknown (due to size and
> complexity) to ensure that it always follows the rules.

Will do.


>> 2. Have default trap handler call an RCU notifier chain to allow it to
>>    hook up with "normal" code without any hard coding (kgdb, IPI
>>    handling, etc)
> 
> Maybe... that sounds like it opens up FIQ for general purpose use which
> is something I want to avoid - I've little motivation to ensure that
> everyone plays by the rules.  Given the choice, I'd rather maintain our
> present stance that using FIQs is hard and requires a lot of thought.

I'll see what feels natural. Not exporting the symbol to register for
notification would go some way to preventing abuse whilst still allowing
decoupling from kgdb (which cannot be a module).


>> 3. Retain existing install_fiq() behaviour for people who want FIQ
>>    to be a fast-interrupt rather than an NMI (for example, the
>>    Raspberry pi USB optimizations).
> 
> Yes, arch/arm/kernel/fiq.c should be relatively untouched by the core
> mods I suggested - we're just replacing the default "subs" instruction
> (which just ignores the FIQ) with something which can do something
> with it.
> 
> It should be noted that using arch/arm/kernel/fiq.c would override this
> default FIQ handler - and that's a feature of it - fiq.c is based on
> the premise that there is only one single owner of the FIQ at any one
> time and there is no sharing of it, and that's something we want to
> retain.

However, particularly for IPIs, if we've build useful debug features
using them it would be nice to provide hooks that the owner can use to
keep them working if they wish.

However I agree with your response to #4; interfacing at a level lower
than C ABI isn't right. To use any hooks the owner must first make it
safe to call C.


>> 4. Ensure default handler is an exported symbol to allow the meths
>>    drinkers from #3 to chain to logic for NMI/debug features
>>    if they want to.
> 
> That's not something I particularly want to permit - especially as the
> requirements for each "handler" are different - this new default code
> relies upon r13 pointing at some storage to save some registers, which
> may not be true of other FIQ handlers.  Chaining it means that we
> force that use of r13 on others, and we then have to also come up with
> some way to export the correct r13 value.
> 
> Given that fiq.c doesn't work with SMP, this isn't something I want to
> encourage.

Makes sense.


> Further more, I can't get excited about Raspberry Pi "optimisations"
> using FIQ until I see the code, and I see no reason to think about
> catering for such stuff until the patches become visible here.

IIRC they don't add any use-cases beyond the existing in-kernel FIQ
users (such as R-PC floppy disc). It's just that they do it on more
recent hardware (and as you say, out-of-tree).


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v8 4/4] ARM: Add KGDB/KDB FIQ debugger generic code
@ 2014-08-14 15:02                       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-14 15:02 UTC (permalink / raw)
  To: linux-arm-kernel

On 14/08/14 13:36, Russell King - ARM Linux wrote:
> On Thu, Aug 14, 2014 at 11:48:36AM +0100, Daniel Thompson wrote:
>> Don't worry, you certainly did make it clear!
>>
>> I actually went as far as removing the trace_* calls before having a
>> change of heart. As a result I spent some time looking at the
>> trace_hardirqs_on() code and, as far as I remember, I couldn't find a
>> lock in the code that wasn't bypassed when in_nmi() returned true.
>>
>> However the code is pretty complex and its certainly possible that I
>> missed something. Are you in a position to point any particular lock to
>> show I messed this up or are you working from memory?
> 
> The complexity alone is an argument against calling it from FIQ context,
> because there's no guarantee that what's there will stay that way.
> 
> trace_hardirqs_on() is made more complex because there's not one function
> with that name, but two.  One is in the trace code, the other is in the
> lockdep code.  Here's the trace code, which has at least two problems:
> 
> trace_hardirqs_on
>  -> stop_critical_timing
>   -> check_critical_timing
>    -> raw_spin_lock_irqsave(&max_trace_lock, flags);
>    -> __trace_stack
>     -> __ftrace_trace_stack
>      -> save_stack_trace
>       -> __save_stack_trace
>        -> walk_stackframe
>         -> unwind_frame
>          -> unwind_find_idx
>           -> spin_lock_irqsave(&unwind_lock, flags);

Looks like I had an out-by-one error when reviewing this... sadly the
value was boolean.

Thanks this is very clear.


>>> So, how about moving the FIQ assembly code to entry-armv.S and making
>>> it less kgdb specific?  (Though... we do want to keep a /very/ close
>>> eye on users to ensure that they don't do silly stuff with locking.)
>>
>> I think I can do that.
>>
>> Something like this?
>>
>> 1. Install the current trap handler code by default (either with or
>>    without trace_* calls).
> 
> Without trace_* calls.  The FIQ should be transparent to tracing -
> tracing and lockdep is too much of an unknown (due to size and
> complexity) to ensure that it always follows the rules.

Will do.


>> 2. Have default trap handler call an RCU notifier chain to allow it to
>>    hook up with "normal" code without any hard coding (kgdb, IPI
>>    handling, etc)
> 
> Maybe... that sounds like it opens up FIQ for general purpose use which
> is something I want to avoid - I've little motivation to ensure that
> everyone plays by the rules.  Given the choice, I'd rather maintain our
> present stance that using FIQs is hard and requires a lot of thought.

I'll see what feels natural. Not exporting the symbol to register for
notification would go some way to preventing abuse whilst still allowing
decoupling from kgdb (which cannot be a module).


>> 3. Retain existing install_fiq() behaviour for people who want FIQ
>>    to be a fast-interrupt rather than an NMI (for example, the
>>    Raspberry pi USB optimizations).
> 
> Yes, arch/arm/kernel/fiq.c should be relatively untouched by the core
> mods I suggested - we're just replacing the default "subs" instruction
> (which just ignores the FIQ) with something which can do something
> with it.
> 
> It should be noted that using arch/arm/kernel/fiq.c would override this
> default FIQ handler - and that's a feature of it - fiq.c is based on
> the premise that there is only one single owner of the FIQ at any one
> time and there is no sharing of it, and that's something we want to
> retain.

However, particularly for IPIs, if we've build useful debug features
using them it would be nice to provide hooks that the owner can use to
keep them working if they wish.

However I agree with your response to #4; interfacing at a level lower
than C ABI isn't right. To use any hooks the owner must first make it
safe to call C.


>> 4. Ensure default handler is an exported symbol to allow the meths
>>    drinkers from #3 to chain to logic for NMI/debug features
>>    if they want to.
> 
> That's not something I particularly want to permit - especially as the
> requirements for each "handler" are different - this new default code
> relies upon r13 pointing at some storage to save some registers, which
> may not be true of other FIQ handlers.  Chaining it means that we
> force that use of r13 on others, and we then have to also come up with
> some way to export the correct r13 value.
> 
> Given that fiq.c doesn't work with SMP, this isn't something I want to
> encourage.

Makes sense.


> Further more, I can't get excited about Raspberry Pi "optimisations"
> using FIQ until I see the code, and I see no reason to think about
> catering for such stuff until the patches become visible here.

IIRC they don't add any use-cases beyond the existing in-kernel FIQ
users (such as R-PC floppy disc). It's just that they do it on more
recent hardware (and as you say, out-of-tree).

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v9 00/16] arm: KGDB NMI/FIQ support
  2014-07-10  8:03             ` Daniel Thompson
@ 2014-08-18 13:40               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 13:40 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

This patchset makes it possible to use kgdb's NMI infrastructure on ARM
platforms.

The patches are seperated into three distinct groups:

1. arm specific changes; these provide multi-platform support for FIQ
   (including raising an IPI using FIQ to ensure effective SMP support)
   and extend ARM KGDB support to use the features provided.

2. irqchip changes; updates to the gic and vic drivers to provide
   support for routing certain interrupt sources to FIQ.

3. serial changes; driver support to allow the UART interrupt to be
   routed to FIQ. The already mainlined kgdb NMI infrastructure (mostly
   found in drivers/tty/serial/kgdb_nmi.c) will re-route the kgdb
   console UART's interrupt signal from IRQ to FIQ. Naturally the UART
   will no longer function normally and will instead be managed by kgdb
   using the polled I/O functions. Any character delivered to the UART
   causes the kgdb handler function to be called.

Tested on qemu (versatile), STiH416 (B2020 board) and Freescale i.MX6
quad (wandboard).

Changes since v8:

- Significant rework to separate the FIQ exception handler from kgdb.
  This allows other features typically implemented using NMI on x86
  to reuse the same exception handling code (Russell King)
- Reunited arch/arm and driver code into a single patch series again.
- Added support for raising IPIs using FIQ (makes kgdb quiesce must
  more robust).
- Introduced a workaround for GICv1 devices to avoid FIQs being
  spuriously handled as IRQs.

Changes since v7:

- Introduced ack_fiq() to complement eoi_fiq(). Without this it is
  not possible to meet the GIC specification (previous versions worked
  when tested but are unpredictable according to the specification).
  ack_fiq() also makes is possible for drivers for devices with multiple
  interrupt lines to discover the interrupt source correctly.

Changes since v6:

- Corrected off-by-one comparison in has_fiq() (Nicolas Pitre)
- Rewrote the FIQ stack initialization (Nicolas Pitre). This fixes a
  serious data corruption bug due to bad stack mismanagement.
- Introduced __fiq_abt to ensure lr_abt and spsr_abt are saved and
  restored if we fast-interrupt an abort (Russell King).
- Significantly improved the commenting of the exception handlers.
- Added a call to trace_hardirqs_on() if we clear the I bit as we
  exit the exception handler.

Changes since v5:

- Separated anything not strictly impacting arch/arm.
- Fixed a spurious add/remove of code within the series (there was
  broken code in intermediate patches)

For previous changes see:
http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901

Daniel Thompson (15):
  arm: fiq: Add callbacks to manage FIQ routings
  arm: fiq: Allow ACK and EOI to be passed to the intc
  arm: fiq: Replace default FIQ handler
  arm: smp: Introduce a special IPI signalled using FIQ
  arm: KGDB/KDB FIQ support
  irqchip: gic: Provide support for interrupt grouping
  irqchip: gic: Add support for FIQ management
  irqchip: gic: Remove spin locks from eoi_irq
  irqchip: gic: Add support for IPI FIQ
  irqchip: gic: Group 0 workaround.
  irqchip: vic: Add support for FIQ management
  serial: amba-pl011: Pass FIQ information to KGDB.
  serial: asc: Add support for KGDB's FIQ/NMI mode
  serial: asc: Adopt readl_/writel_relaxed()
  serial: imx: Add support for KGDB's FIQ/NMI mode

Dirk Behme (1):
  serial: imx: clean up imx_poll_get_char()

 arch/arm/Kconfig                |   2 +
 arch/arm/Kconfig.debug          |  19 +++
 arch/arm/include/asm/fiq.h      |  18 +++
 arch/arm/include/asm/hardirq.h  |   2 +-
 arch/arm/include/asm/kgdb.h     |   4 +
 arch/arm/include/asm/smp.h      |   7 +
 arch/arm/kernel/entry-armv.S    | 125 ++++++++++++++--
 arch/arm/kernel/fiq.c           | 139 +++++++++++++++++-
 arch/arm/kernel/kgdb.c          | 115 ++++++++++++++-
 arch/arm/kernel/setup.c         |   8 +-
 arch/arm/kernel/smp.c           |  15 ++
 arch/arm/mach-versatile/core.c  |   2 +-
 drivers/irqchip/irq-gic.c       | 307 +++++++++++++++++++++++++++++++++++++---
 drivers/irqchip/irq-vic.c       |  92 +++++++++---
 drivers/tty/serial/Kconfig      |   2 +-
 drivers/tty/serial/amba-pl011.c |  94 +++++++-----
 drivers/tty/serial/imx.c        |  88 +++++++-----
 drivers/tty/serial/st-asc.c     |  27 +++-
 include/linux/irqchip/arm-vic.h |   6 +-
 19 files changed, 934 insertions(+), 138 deletions(-)

--
1.9.3


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v9 00/16] arm: KGDB NMI/FIQ support
@ 2014-08-18 13:40               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 13:40 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset makes it possible to use kgdb's NMI infrastructure on ARM
platforms.

The patches are seperated into three distinct groups:

1. arm specific changes; these provide multi-platform support for FIQ
   (including raising an IPI using FIQ to ensure effective SMP support)
   and extend ARM KGDB support to use the features provided.

2. irqchip changes; updates to the gic and vic drivers to provide
   support for routing certain interrupt sources to FIQ.

3. serial changes; driver support to allow the UART interrupt to be
   routed to FIQ. The already mainlined kgdb NMI infrastructure (mostly
   found in drivers/tty/serial/kgdb_nmi.c) will re-route the kgdb
   console UART's interrupt signal from IRQ to FIQ. Naturally the UART
   will no longer function normally and will instead be managed by kgdb
   using the polled I/O functions. Any character delivered to the UART
   causes the kgdb handler function to be called.

Tested on qemu (versatile), STiH416 (B2020 board) and Freescale i.MX6
quad (wandboard).

Changes since v8:

- Significant rework to separate the FIQ exception handler from kgdb.
  This allows other features typically implemented using NMI on x86
  to reuse the same exception handling code (Russell King)
- Reunited arch/arm and driver code into a single patch series again.
- Added support for raising IPIs using FIQ (makes kgdb quiesce must
  more robust).
- Introduced a workaround for GICv1 devices to avoid FIQs being
  spuriously handled as IRQs.

Changes since v7:

- Introduced ack_fiq() to complement eoi_fiq(). Without this it is
  not possible to meet the GIC specification (previous versions worked
  when tested but are unpredictable according to the specification).
  ack_fiq() also makes is possible for drivers for devices with multiple
  interrupt lines to discover the interrupt source correctly.

Changes since v6:

- Corrected off-by-one comparison in has_fiq() (Nicolas Pitre)
- Rewrote the FIQ stack initialization (Nicolas Pitre). This fixes a
  serious data corruption bug due to bad stack mismanagement.
- Introduced __fiq_abt to ensure lr_abt and spsr_abt are saved and
  restored if we fast-interrupt an abort (Russell King).
- Significantly improved the commenting of the exception handlers.
- Added a call to trace_hardirqs_on() if we clear the I bit as we
  exit the exception handler.

Changes since v5:

- Separated anything not strictly impacting arch/arm.
- Fixed a spurious add/remove of code within the series (there was
  broken code in intermediate patches)

For previous changes see:
http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901

Daniel Thompson (15):
  arm: fiq: Add callbacks to manage FIQ routings
  arm: fiq: Allow ACK and EOI to be passed to the intc
  arm: fiq: Replace default FIQ handler
  arm: smp: Introduce a special IPI signalled using FIQ
  arm: KGDB/KDB FIQ support
  irqchip: gic: Provide support for interrupt grouping
  irqchip: gic: Add support for FIQ management
  irqchip: gic: Remove spin locks from eoi_irq
  irqchip: gic: Add support for IPI FIQ
  irqchip: gic: Group 0 workaround.
  irqchip: vic: Add support for FIQ management
  serial: amba-pl011: Pass FIQ information to KGDB.
  serial: asc: Add support for KGDB's FIQ/NMI mode
  serial: asc: Adopt readl_/writel_relaxed()
  serial: imx: Add support for KGDB's FIQ/NMI mode

Dirk Behme (1):
  serial: imx: clean up imx_poll_get_char()

 arch/arm/Kconfig                |   2 +
 arch/arm/Kconfig.debug          |  19 +++
 arch/arm/include/asm/fiq.h      |  18 +++
 arch/arm/include/asm/hardirq.h  |   2 +-
 arch/arm/include/asm/kgdb.h     |   4 +
 arch/arm/include/asm/smp.h      |   7 +
 arch/arm/kernel/entry-armv.S    | 125 ++++++++++++++--
 arch/arm/kernel/fiq.c           | 139 +++++++++++++++++-
 arch/arm/kernel/kgdb.c          | 115 ++++++++++++++-
 arch/arm/kernel/setup.c         |   8 +-
 arch/arm/kernel/smp.c           |  15 ++
 arch/arm/mach-versatile/core.c  |   2 +-
 drivers/irqchip/irq-gic.c       | 307 +++++++++++++++++++++++++++++++++++++---
 drivers/irqchip/irq-vic.c       |  92 +++++++++---
 drivers/tty/serial/Kconfig      |   2 +-
 drivers/tty/serial/amba-pl011.c |  94 +++++++-----
 drivers/tty/serial/imx.c        |  88 +++++++-----
 drivers/tty/serial/st-asc.c     |  27 +++-
 include/linux/irqchip/arm-vic.h |   6 +-
 19 files changed, 934 insertions(+), 138 deletions(-)

--
1.9.3

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v9 01/16] arm: fiq: Add callbacks to manage FIQ routings
  2014-08-18 13:40               ` Daniel Thompson
@ 2014-08-18 13:40                 ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 13:40 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
virq into a FIQ virq. This is too inflexible for multi-platform kernels
and makes runtime error checking impossible.

We solve this by introducing a flexible mapping that allows interrupt
controllers that support FIQ to register those mappings. This, in turn,
makes it much possible for drivers in DT kernels to install FIQ handlers
without knowing anything about the interrupt controller.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h |   8 ++++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..ed44528 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -16,8 +16,14 @@
 #ifndef __ASM_FIQ_H
 #define __ASM_FIQ_H
 
+#include <linux/irq.h>
 #include <asm/ptrace.h>
 
+struct fiq_chip {
+	void (*fiq_enable)(struct irq_data *data);
+	void (*fiq_disable)(struct irq_data *data);
+};
+
 struct fiq_handler {
 	struct fiq_handler *next;
 	/* Name
@@ -38,6 +44,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern bool has_fiq(int fiq);
+extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..5d831cf 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,9 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
+#include <linux/radix-tree.h>
+#include <linux/slab.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -52,7 +55,15 @@
 		(unsigned)&vector_fiq_offset;		\
 	})
 
+struct fiq_data {
+	struct fiq_chip *fiq_chip;
+	struct irq_data *irq_data;
+};
+
 static unsigned long no_fiq_insn;
+static int fiq_start = -1;
+static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
+static DEFINE_MUTEX(fiq_data_mutex);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -127,18 +138,65 @@ void release_fiq(struct fiq_handler *f)
 	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
 }
 
-static int fiq_start;
+static struct fiq_data *lookup_fiq_data(int fiq)
+{
+	struct fiq_data *data;
+
+	rcu_read_lock();
+	data = radix_tree_lookup(&fiq_data_tree, fiq);
+	rcu_read_unlock();
+
+	return data;
+}
 
 void enable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_enable)
+			data->fiq_chip->fiq_enable(data->irq_data);
+		enable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	enable_irq(fiq + fiq_start);
 }
 
 void disable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_disable)
+			data->fiq_chip->fiq_disable(data->irq_data);
+		disable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	disable_irq(fiq + fiq_start);
 }
 
+bool has_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data)
+		return true;
+
+	if (fiq_start == -1)
+		return false;
+
+	return fiq >= fiq_start;
+}
+EXPORT_SYMBOL(has_fiq);
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -147,9 +205,50 @@ EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
 
+/*
+ * Add a mapping from a Linux irq to the fiq data.
+ */
+void fiq_register_mapping(int irq, struct fiq_chip *chip)
+{
+	struct fiq_data *fiq_data = NULL;
+	int res;
+
+	/* fiq_register_mapping can't be mixed with init_FIQ */
+	BUG_ON(fiq_start != -1);
+
+	fiq_data = kmalloc(sizeof(*fiq_data), GFP_KERNEL);
+	if (!fiq_data)
+		goto err;
+
+	fiq_data->fiq_chip = chip;
+	fiq_data->irq_data = irq_get_irq_data(irq);
+	BUG_ON(!fiq_data->irq_data);
+
+	mutex_lock(&fiq_data_mutex);
+	res = radix_tree_insert(&fiq_data_tree, irq, fiq_data);
+	mutex_unlock(&fiq_data_mutex);
+	if (res)
+		goto err;
+
+	return;
+
+err:
+	kfree(fiq_data);
+	pr_err("fiq: Cannot register mapping %d\n", irq);
+}
+
+/*
+ * Set the offset between normal IRQs and their FIQ shadows.
+ */
 void __init init_FIQ(int start)
 {
+	fiq_start = start;
+}
+
+static int __init init_default_fiq_handler(void)
+{
 	unsigned offset = FIQ_OFFSET;
 	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
-	fiq_start = start;
+	return 0;
 }
+pure_initcall(init_default_fiq_handler);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 01/16] arm: fiq: Add callbacks to manage FIQ routings
@ 2014-08-18 13:40                 ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 13:40 UTC (permalink / raw)
  To: linux-arm-kernel

Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
virq into a FIQ virq. This is too inflexible for multi-platform kernels
and makes runtime error checking impossible.

We solve this by introducing a flexible mapping that allows interrupt
controllers that support FIQ to register those mappings. This, in turn,
makes it much possible for drivers in DT kernels to install FIQ handlers
without knowing anything about the interrupt controller.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h |   8 ++++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..ed44528 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -16,8 +16,14 @@
 #ifndef __ASM_FIQ_H
 #define __ASM_FIQ_H
 
+#include <linux/irq.h>
 #include <asm/ptrace.h>
 
+struct fiq_chip {
+	void (*fiq_enable)(struct irq_data *data);
+	void (*fiq_disable)(struct irq_data *data);
+};
+
 struct fiq_handler {
 	struct fiq_handler *next;
 	/* Name
@@ -38,6 +44,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern bool has_fiq(int fiq);
+extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..5d831cf 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,9 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
+#include <linux/radix-tree.h>
+#include <linux/slab.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -52,7 +55,15 @@
 		(unsigned)&vector_fiq_offset;		\
 	})
 
+struct fiq_data {
+	struct fiq_chip *fiq_chip;
+	struct irq_data *irq_data;
+};
+
 static unsigned long no_fiq_insn;
+static int fiq_start = -1;
+static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
+static DEFINE_MUTEX(fiq_data_mutex);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -127,18 +138,65 @@ void release_fiq(struct fiq_handler *f)
 	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
 }
 
-static int fiq_start;
+static struct fiq_data *lookup_fiq_data(int fiq)
+{
+	struct fiq_data *data;
+
+	rcu_read_lock();
+	data = radix_tree_lookup(&fiq_data_tree, fiq);
+	rcu_read_unlock();
+
+	return data;
+}
 
 void enable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_enable)
+			data->fiq_chip->fiq_enable(data->irq_data);
+		enable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	enable_irq(fiq + fiq_start);
 }
 
 void disable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_disable)
+			data->fiq_chip->fiq_disable(data->irq_data);
+		disable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	disable_irq(fiq + fiq_start);
 }
 
+bool has_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data)
+		return true;
+
+	if (fiq_start == -1)
+		return false;
+
+	return fiq >= fiq_start;
+}
+EXPORT_SYMBOL(has_fiq);
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -147,9 +205,50 @@ EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
 
+/*
+ * Add a mapping from a Linux irq to the fiq data.
+ */
+void fiq_register_mapping(int irq, struct fiq_chip *chip)
+{
+	struct fiq_data *fiq_data = NULL;
+	int res;
+
+	/* fiq_register_mapping can't be mixed with init_FIQ */
+	BUG_ON(fiq_start != -1);
+
+	fiq_data = kmalloc(sizeof(*fiq_data), GFP_KERNEL);
+	if (!fiq_data)
+		goto err;
+
+	fiq_data->fiq_chip = chip;
+	fiq_data->irq_data = irq_get_irq_data(irq);
+	BUG_ON(!fiq_data->irq_data);
+
+	mutex_lock(&fiq_data_mutex);
+	res = radix_tree_insert(&fiq_data_tree, irq, fiq_data);
+	mutex_unlock(&fiq_data_mutex);
+	if (res)
+		goto err;
+
+	return;
+
+err:
+	kfree(fiq_data);
+	pr_err("fiq: Cannot register mapping %d\n", irq);
+}
+
+/*
+ * Set the offset between normal IRQs and their FIQ shadows.
+ */
 void __init init_FIQ(int start)
 {
+	fiq_start = start;
+}
+
+static int __init init_default_fiq_handler(void)
+{
 	unsigned offset = FIQ_OFFSET;
 	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
-	fiq_start = start;
+	return 0;
 }
+pure_initcall(init_default_fiq_handler);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 02/16] arm: fiq: Allow ACK and EOI to be passed to the intc
  2014-08-18 13:40               ` Daniel Thompson
@ 2014-08-18 13:40                 ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 13:40 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

Modern ARM interrupt controllers require an ACK as interrupts are taken
and an EOI on completion. The FIQ code currently does not provide any
API to perform this.

This patch provides this API, implemented by adding two callbacks to the
fiq_chip structure.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h |  9 +++++++++
 arch/arm/kernel/fiq.c      | 19 +++++++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index ed44528..a25c952 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -22,6 +22,13 @@
 struct fiq_chip {
 	void (*fiq_enable)(struct irq_data *data);
 	void (*fiq_disable)(struct irq_data *data);
+
+	/* .fiq_ack() and .fiq_eoi() will be called from the FIQ
+	 * handler. For this reason they must not use spin locks (or any
+	 * other locks).
+	 */
+	int (*fiq_ack)(struct irq_data *data);
+	void (*fiq_eoi)(struct irq_data *data);
 };
 
 struct fiq_handler {
@@ -44,6 +51,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern int ack_fiq(int fiq);
+extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 5d831cf..3ccaa8c 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -183,6 +183,25 @@ void disable_fiq(int fiq)
 	disable_irq(fiq + fiq_start);
 }
 
+int ack_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_ack)
+		return data->fiq_chip->fiq_ack(data->irq_data);
+
+	return fiq;
+}
+
+void eoi_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_eoi)
+		data->fiq_chip->fiq_eoi(data->irq_data);
+}
+EXPORT_SYMBOL(eoi_fiq);
+
 bool has_fiq(int fiq)
 {
 	struct fiq_data *data = lookup_fiq_data(fiq);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 02/16] arm: fiq: Allow ACK and EOI to be passed to the intc
@ 2014-08-18 13:40                 ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 13:40 UTC (permalink / raw)
  To: linux-arm-kernel

Modern ARM interrupt controllers require an ACK as interrupts are taken
and an EOI on completion. The FIQ code currently does not provide any
API to perform this.

This patch provides this API, implemented by adding two callbacks to the
fiq_chip structure.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h |  9 +++++++++
 arch/arm/kernel/fiq.c      | 19 +++++++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index ed44528..a25c952 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -22,6 +22,13 @@
 struct fiq_chip {
 	void (*fiq_enable)(struct irq_data *data);
 	void (*fiq_disable)(struct irq_data *data);
+
+	/* .fiq_ack() and .fiq_eoi() will be called from the FIQ
+	 * handler. For this reason they must not use spin locks (or any
+	 * other locks).
+	 */
+	int (*fiq_ack)(struct irq_data *data);
+	void (*fiq_eoi)(struct irq_data *data);
 };
 
 struct fiq_handler {
@@ -44,6 +51,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern int ack_fiq(int fiq);
+extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 5d831cf..3ccaa8c 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -183,6 +183,25 @@ void disable_fiq(int fiq)
 	disable_irq(fiq + fiq_start);
 }
 
+int ack_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_ack)
+		return data->fiq_chip->fiq_ack(data->irq_data);
+
+	return fiq;
+}
+
+void eoi_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_eoi)
+		data->fiq_chip->fiq_eoi(data->irq_data);
+}
+EXPORT_SYMBOL(eoi_fiq);
+
 bool has_fiq(int fiq)
 {
 	struct fiq_data *data = lookup_fiq_data(fiq);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 03/16] arm: fiq: Replace default FIQ handler
  2014-08-18 13:40               ` Daniel Thompson
@ 2014-08-18 13:40                 ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 13:40 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

This patch introduces a new default FIQ handler that is structured in a
similar way to the existing ARM exception handler and result in the FIQ
being handled by C code running on the SVC stack (despite this code run
in the FIQ handler is subject to severe limitations with respect to
locking making normal interaction with the kernel impossible).

This default handler allows concepts that on x86 would be handled using
NMIs to be realized on ARM.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of small fragments
    survive, however without Anton's work to build from this patch would
    not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
---
 arch/arm/include/asm/fiq.h   |   1 +
 arch/arm/kernel/entry-armv.S | 125 +++++++++++++++++++++++++++++++++++++++----
 arch/arm/kernel/fiq.c        |  17 ++++++
 arch/arm/kernel/setup.c      |   8 ++-
 4 files changed, 140 insertions(+), 11 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index a25c952..175bfed 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -54,6 +54,7 @@ extern void disable_fiq(int fiq);
 extern int ack_fiq(int fiq);
 extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
+extern int register_fiq_nmi_notifier(struct notifier_block *nb);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 36276cd..ba0234b 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -79,6 +79,15 @@
 #endif
 	.endm
 
+	.macro	fiq_handler
+	ldr	r1, =.LChandle_fiq
+	mov	r0, sp
+	adr	lr, BSYM(9998f)
+	ldr	pc, [r1]
+9998:
+	.endm
+
+
 #ifdef CONFIG_KPROBES
 	.section	.kprobes.text,"ax",%progbits
 #else
@@ -146,7 +155,7 @@ ENDPROC(__und_invalid)
 #define SPFIX(code...)
 #endif
 
-	.macro	svc_entry, stack_hole=0
+	.macro	svc_entry, stack_hole=0, call_trace=1
  UNWIND(.fnstart		)
  UNWIND(.save {r0 - pc}		)
 	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
@@ -183,10 +192,35 @@ ENDPROC(__und_invalid)
 	stmia	r7, {r2 - r6}
 
 #ifdef CONFIG_TRACE_IRQFLAGS
+	.if \call_trace
 	bl	trace_hardirqs_off
+	.endif
 #endif
 	.endm
 
+@
+@ svc_exit_via_fiq - similar to svc_exit but switches to FIQ mode before exit
+@
+@ This macro acts in a similar manner to svc_exit but switches to FIQ
+@ mode to restore the final part of the register state.
+@
+@ We cannot use the normal svc_exit procedure because that would
+@ clobber spsr_svc (FIQ could be delivered during the first few instructions
+@ of vector_swi meaning its contents have not been saved anywhere).
+@
+	.macro  svc_exit_via_fiq, rpsr
+
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+	.endm
+
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -295,6 +329,14 @@ __pabt_svc:
 ENDPROC(__pabt_svc)
 
 	.align	5
+__fiq_svc:
+	svc_entry 0, 0
+	fiq_handler
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+	.align	5
 .LCcralign:
 	.word	cr_alignment
 #ifdef MULTI_DABORT
@@ -303,6 +345,39 @@ ENDPROC(__pabt_svc)
 #endif
 .LCfp:
 	.word	fp_enter
+.LChandle_fiq:
+	.word	fiq_nmi_handler
+
+/*
+ * Abort mode handlers
+ */
+
+@
+@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
+@ and reuses the same macros. However in abort mode we must also
+@ save/restore lr_abt and spsr_abt to make nested aborts safe.
+@
+	.align 5
+__fiq_abt:
+	svc_entry 0, 0
+
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	r0, lr		@ Save lr_abt
+	mrs	r1, spsr	@ Save spsr_abt, abort is now safe
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+	push	{r0 - r1}
+
+	fiq_handler
+
+	pop	{r0 - r1}
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	lr, r0		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r1	@ Restore spsr_abt
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
 
 /*
  * User mode handlers
@@ -683,6 +758,17 @@ ENTRY(ret_from_exception)
 ENDPROC(__pabt_usr)
 ENDPROC(ret_from_exception)
 
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+
 /*
  * Register switch for ARMv3 and ARMv4 processors
  * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
@@ -1118,17 +1204,36 @@ vector_addrexcptn:
 	b	vector_addrexcptn
 
 /*=============================================================================
- * Undefined FIQs
+ * FIQ "NMI" handler
  *-----------------------------------------------------------------------------
- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
- * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
- * Basically to switch modes, we *HAVE* to clobber one register...  brain
- * damage alert!  I don't think that we can execute any code in here in any
- * other mode than FIQ...  Ok you can switch to another mode, but you can't
- * get out of that mode without clobbering one register.
+ * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
+ * systems. The runtime environment for NMIs is extremely restrictive
+ * (NMIs can pre-empt critical sections meaning almost all locking is
+ * forbidden) meaning this default FIQ handling must only be used in
+ * circumstances where non-maskability improves robustness, such as
+ * watchdog or debug logic.
+ *
+ * This handler is inappropriate for high performance (fast) interrupt
+ * servicing and can be overridden using set_fiq_handler.
  */
-vector_fiq:
-	subs	pc, lr, #4
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
 
 	.globl	vector_fiq_offset
 	.equ	vector_fiq_offset, vector_fiq
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 3ccaa8c..b2bd1c7 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -46,6 +46,7 @@
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
+#include <asm/exception.h>
 #include <asm/fiq.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
@@ -64,6 +65,7 @@ static unsigned long no_fiq_insn;
 static int fiq_start = -1;
 static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
 static DEFINE_MUTEX(fiq_data_mutex);
+static ATOMIC_NOTIFIER_HEAD(fiq_nmi_chain);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -216,6 +218,21 @@ bool has_fiq(int fiq)
 }
 EXPORT_SYMBOL(has_fiq);
 
+int register_fiq_nmi_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
+}
+
+asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
+{
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	nmi_enter();
+	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
+	nmi_exit();
+	set_irq_regs(old_regs);
+}
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 84db893d..c031063 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -133,6 +133,7 @@ struct stack {
 	u32 irq[3];
 	u32 abt[3];
 	u32 und[3];
+	u32 fiq[3];
 } ____cacheline_aligned;
 
 #ifndef CONFIG_CPU_V7M
@@ -470,7 +471,10 @@ void notrace cpu_init(void)
 	"msr	cpsr_c, %5\n\t"
 	"add	r14, %0, %6\n\t"
 	"mov	sp, r14\n\t"
-	"msr	cpsr_c, %7"
+	"msr	cpsr_c, %7\n\t"
+	"add	r14, %0, %8\n\t"
+	"mov	sp, r14\n\t"
+	"msr	cpsr_c, %9"
 	    :
 	    : "r" (stk),
 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
@@ -479,6 +483,8 @@ void notrace cpu_init(void)
 	      "I" (offsetof(struct stack, abt[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
 	      "I" (offsetof(struct stack, und[0])),
+	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+	      "I" (offsetof(struct stack, fiq[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
 	    : "r14");
 #endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 03/16] arm: fiq: Replace default FIQ handler
@ 2014-08-18 13:40                 ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 13:40 UTC (permalink / raw)
  To: linux-arm-kernel

This patch introduces a new default FIQ handler that is structured in a
similar way to the existing ARM exception handler and result in the FIQ
being handled by C code running on the SVC stack (despite this code run
in the FIQ handler is subject to severe limitations with respect to
locking making normal interaction with the kernel impossible).

This default handler allows concepts that on x86 would be handled using
NMIs to be realized on ARM.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of small fragments
    survive, however without Anton's work to build from this patch would
    not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
---
 arch/arm/include/asm/fiq.h   |   1 +
 arch/arm/kernel/entry-armv.S | 125 +++++++++++++++++++++++++++++++++++++++----
 arch/arm/kernel/fiq.c        |  17 ++++++
 arch/arm/kernel/setup.c      |   8 ++-
 4 files changed, 140 insertions(+), 11 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index a25c952..175bfed 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -54,6 +54,7 @@ extern void disable_fiq(int fiq);
 extern int ack_fiq(int fiq);
 extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
+extern int register_fiq_nmi_notifier(struct notifier_block *nb);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 36276cd..ba0234b 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -79,6 +79,15 @@
 #endif
 	.endm
 
+	.macro	fiq_handler
+	ldr	r1, =.LChandle_fiq
+	mov	r0, sp
+	adr	lr, BSYM(9998f)
+	ldr	pc, [r1]
+9998:
+	.endm
+
+
 #ifdef CONFIG_KPROBES
 	.section	.kprobes.text,"ax",%progbits
 #else
@@ -146,7 +155,7 @@ ENDPROC(__und_invalid)
 #define SPFIX(code...)
 #endif
 
-	.macro	svc_entry, stack_hole=0
+	.macro	svc_entry, stack_hole=0, call_trace=1
  UNWIND(.fnstart		)
  UNWIND(.save {r0 - pc}		)
 	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
@@ -183,10 +192,35 @@ ENDPROC(__und_invalid)
 	stmia	r7, {r2 - r6}
 
 #ifdef CONFIG_TRACE_IRQFLAGS
+	.if \call_trace
 	bl	trace_hardirqs_off
+	.endif
 #endif
 	.endm
 
+@
+@ svc_exit_via_fiq - similar to svc_exit but switches to FIQ mode before exit
+@
+@ This macro acts in a similar manner to svc_exit but switches to FIQ
+@ mode to restore the final part of the register state.
+@
+@ We cannot use the normal svc_exit procedure because that would
+@ clobber spsr_svc (FIQ could be delivered during the first few instructions
+@ of vector_swi meaning its contents have not been saved anywhere).
+@
+	.macro  svc_exit_via_fiq, rpsr
+
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+	.endm
+
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -295,6 +329,14 @@ __pabt_svc:
 ENDPROC(__pabt_svc)
 
 	.align	5
+__fiq_svc:
+	svc_entry 0, 0
+	fiq_handler
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+	.align	5
 .LCcralign:
 	.word	cr_alignment
 #ifdef MULTI_DABORT
@@ -303,6 +345,39 @@ ENDPROC(__pabt_svc)
 #endif
 .LCfp:
 	.word	fp_enter
+.LChandle_fiq:
+	.word	fiq_nmi_handler
+
+/*
+ * Abort mode handlers
+ */
+
+@
+@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
+@ and reuses the same macros. However in abort mode we must also
+@ save/restore lr_abt and spsr_abt to make nested aborts safe.
+@
+	.align 5
+__fiq_abt:
+	svc_entry 0, 0
+
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	r0, lr		@ Save lr_abt
+	mrs	r1, spsr	@ Save spsr_abt, abort is now safe
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+	push	{r0 - r1}
+
+	fiq_handler
+
+	pop	{r0 - r1}
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	lr, r0		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r1	@ Restore spsr_abt
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
 
 /*
  * User mode handlers
@@ -683,6 +758,17 @@ ENTRY(ret_from_exception)
 ENDPROC(__pabt_usr)
 ENDPROC(ret_from_exception)
 
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+
 /*
  * Register switch for ARMv3 and ARMv4 processors
  * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
@@ -1118,17 +1204,36 @@ vector_addrexcptn:
 	b	vector_addrexcptn
 
 /*=============================================================================
- * Undefined FIQs
+ * FIQ "NMI" handler
  *-----------------------------------------------------------------------------
- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
- * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
- * Basically to switch modes, we *HAVE* to clobber one register...  brain
- * damage alert!  I don't think that we can execute any code in here in any
- * other mode than FIQ...  Ok you can switch to another mode, but you can't
- * get out of that mode without clobbering one register.
+ * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
+ * systems. The runtime environment for NMIs is extremely restrictive
+ * (NMIs can pre-empt critical sections meaning almost all locking is
+ * forbidden) meaning this default FIQ handling must only be used in
+ * circumstances where non-maskability improves robustness, such as
+ * watchdog or debug logic.
+ *
+ * This handler is inappropriate for high performance (fast) interrupt
+ * servicing and can be overridden using set_fiq_handler.
  */
-vector_fiq:
-	subs	pc, lr, #4
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
 
 	.globl	vector_fiq_offset
 	.equ	vector_fiq_offset, vector_fiq
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 3ccaa8c..b2bd1c7 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -46,6 +46,7 @@
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
+#include <asm/exception.h>
 #include <asm/fiq.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
@@ -64,6 +65,7 @@ static unsigned long no_fiq_insn;
 static int fiq_start = -1;
 static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
 static DEFINE_MUTEX(fiq_data_mutex);
+static ATOMIC_NOTIFIER_HEAD(fiq_nmi_chain);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -216,6 +218,21 @@ bool has_fiq(int fiq)
 }
 EXPORT_SYMBOL(has_fiq);
 
+int register_fiq_nmi_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
+}
+
+asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
+{
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	nmi_enter();
+	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
+	nmi_exit();
+	set_irq_regs(old_regs);
+}
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 84db893d..c031063 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -133,6 +133,7 @@ struct stack {
 	u32 irq[3];
 	u32 abt[3];
 	u32 und[3];
+	u32 fiq[3];
 } ____cacheline_aligned;
 
 #ifndef CONFIG_CPU_V7M
@@ -470,7 +471,10 @@ void notrace cpu_init(void)
 	"msr	cpsr_c, %5\n\t"
 	"add	r14, %0, %6\n\t"
 	"mov	sp, r14\n\t"
-	"msr	cpsr_c, %7"
+	"msr	cpsr_c, %7\n\t"
+	"add	r14, %0, %8\n\t"
+	"mov	sp, r14\n\t"
+	"msr	cpsr_c, %9"
 	    :
 	    : "r" (stk),
 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
@@ -479,6 +483,8 @@ void notrace cpu_init(void)
 	      "I" (offsetof(struct stack, abt[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
 	      "I" (offsetof(struct stack, und[0])),
+	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+	      "I" (offsetof(struct stack, fiq[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
 	    : "r14");
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 04/16] arm: smp: Introduce a special IPI signalled using FIQ
  2014-08-18 13:40               ` Daniel Thompson
@ 2014-08-18 13:40                 ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 13:40 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

Cross CPU signalling based on FIQ is especially useful for kgdb since
it makes stopping all the CPUs during breakpointing more robust (some
of the other architectures already roundup the CPUs using NMIs).

The approach taken provides infrastructure that can be called (or not) by
the driver's FIQ handler depending upon it requirements. In other words
nothing is added here that prevents the driver from accessing "bare metal"
performance.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/hardirq.h |  2 +-
 arch/arm/include/asm/smp.h     |  7 +++++++
 arch/arm/kernel/smp.c          | 15 +++++++++++++++
 3 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
index fe3ea77..5df33e3 100644
--- a/arch/arm/include/asm/hardirq.h
+++ b/arch/arm/include/asm/hardirq.h
@@ -5,7 +5,7 @@
 #include <linux/threads.h>
 #include <asm/irq.h>
 
-#define NR_IPI	8
+#define NR_IPI	9
 
 typedef struct {
 	unsigned int __softirq_pending;
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2ec765c..215c927 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -20,6 +20,9 @@
 
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
+/* bitmap of IPIs that must be signalled using FIQ */
+#define SMP_IPI_FIQ_MASK 0x0100
+
 struct seq_file;
 
 /*
@@ -87,6 +90,10 @@ extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
 
 extern int register_ipi_completion(struct completion *completion, int cpu);
 
+#ifdef CONFIG_FIQ
+extern void send_fiq_ipi_mask(const struct cpumask *);
+#endif
+
 struct smp_operations {
 #ifdef CONFIG_SMP
 	/*
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9388a3d..d386c32 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -72,6 +72,7 @@ enum ipi_msg_type {
 	IPI_CPU_STOP,
 	IPI_IRQ_WORK,
 	IPI_COMPLETION,
+	IPI_FIQ,
 };
 
 static DECLARE_COMPLETION(cpu_running);
@@ -451,6 +452,7 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
 	S(IPI_CPU_STOP, "CPU stop interrupts"),
 	S(IPI_IRQ_WORK, "IRQ work interrupts"),
 	S(IPI_COMPLETION, "completion interrupts"),
+	S(IPI_FIQ, "FIQ interrupts"),
 };
 
 static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
@@ -552,6 +554,13 @@ static void ipi_complete(unsigned int cpu)
 	complete(per_cpu(cpu_completion, cpu));
 }
 
+#ifdef CONFIG_FIQ
+void send_fiq_ipi_mask(const struct cpumask *mask)
+{
+	smp_cross_call(mask, IPI_FIQ);
+}
+#endif
+
 /*
  * Main handler for inter-processor interrupts
  */
@@ -618,6 +627,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		irq_exit();
 		break;
 
+#ifdef CONFIG_FIQ
+	case IPI_FIQ:
+		pr_crit("CPU%u: IPI FIQ delivered via IRQ vector\n", cpu);
+		break;
+#endif
+
 	default:
 		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
 		       cpu, ipinr);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 04/16] arm: smp: Introduce a special IPI signalled using FIQ
@ 2014-08-18 13:40                 ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 13:40 UTC (permalink / raw)
  To: linux-arm-kernel

Cross CPU signalling based on FIQ is especially useful for kgdb since
it makes stopping all the CPUs during breakpointing more robust (some
of the other architectures already roundup the CPUs using NMIs).

The approach taken provides infrastructure that can be called (or not) by
the driver's FIQ handler depending upon it requirements. In other words
nothing is added here that prevents the driver from accessing "bare metal"
performance.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/hardirq.h |  2 +-
 arch/arm/include/asm/smp.h     |  7 +++++++
 arch/arm/kernel/smp.c          | 15 +++++++++++++++
 3 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
index fe3ea77..5df33e3 100644
--- a/arch/arm/include/asm/hardirq.h
+++ b/arch/arm/include/asm/hardirq.h
@@ -5,7 +5,7 @@
 #include <linux/threads.h>
 #include <asm/irq.h>
 
-#define NR_IPI	8
+#define NR_IPI	9
 
 typedef struct {
 	unsigned int __softirq_pending;
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2ec765c..215c927 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -20,6 +20,9 @@
 
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
+/* bitmap of IPIs that must be signalled using FIQ */
+#define SMP_IPI_FIQ_MASK 0x0100
+
 struct seq_file;
 
 /*
@@ -87,6 +90,10 @@ extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
 
 extern int register_ipi_completion(struct completion *completion, int cpu);
 
+#ifdef CONFIG_FIQ
+extern void send_fiq_ipi_mask(const struct cpumask *);
+#endif
+
 struct smp_operations {
 #ifdef CONFIG_SMP
 	/*
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9388a3d..d386c32 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -72,6 +72,7 @@ enum ipi_msg_type {
 	IPI_CPU_STOP,
 	IPI_IRQ_WORK,
 	IPI_COMPLETION,
+	IPI_FIQ,
 };
 
 static DECLARE_COMPLETION(cpu_running);
@@ -451,6 +452,7 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
 	S(IPI_CPU_STOP, "CPU stop interrupts"),
 	S(IPI_IRQ_WORK, "IRQ work interrupts"),
 	S(IPI_COMPLETION, "completion interrupts"),
+	S(IPI_FIQ, "FIQ interrupts"),
 };
 
 static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
@@ -552,6 +554,13 @@ static void ipi_complete(unsigned int cpu)
 	complete(per_cpu(cpu_completion, cpu));
 }
 
+#ifdef CONFIG_FIQ
+void send_fiq_ipi_mask(const struct cpumask *mask)
+{
+	smp_cross_call(mask, IPI_FIQ);
+}
+#endif
+
 /*
  * Main handler for inter-processor interrupts
  */
@@ -618,6 +627,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		irq_exit();
 		break;
 
+#ifdef CONFIG_FIQ
+	case IPI_FIQ:
+		pr_crit("CPU%u: IPI FIQ delivered via IRQ vector\n", cpu);
+		break;
+#endif
+
 	default:
 		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
 		       cpu, ipinr);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 05/16] arm: KGDB/KDB FIQ support
  2014-08-18 13:40               ` Daniel Thompson
@ 2014-08-18 13:40                 ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 13:40 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Omar Sandoval

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of comments and
    other small fragments still survive, however without Anton's work
    to build from this patch would not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben.dooks@codethink.co.uk>
Cc: Omar Sandoval <osandov@osandov.com>
---
 arch/arm/Kconfig            |   2 +
 arch/arm/Kconfig.debug      |  19 ++++++++
 arch/arm/include/asm/kgdb.h |   4 ++
 arch/arm/kernel/kgdb.c      | 115 +++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 134 insertions(+), 6 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c49a775..e6380b3 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -305,6 +305,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -352,6 +353,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index f304694..a99f8d2 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,25 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be enabled
+	  by setting the console to ttyNMI0 (and choosing the underlying
+	  serial port using kgdboc)
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..6563da0 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,8 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern int kgdb_register_fiq(unsigned int fiq);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
index a74b53c..928c205 100644
--- a/arch/arm/kernel/kgdb.c
+++ b/arch/arm/kernel/kgdb.c
@@ -12,8 +12,11 @@
 #include <linux/irq.h>
 #include <linux/kdebug.h>
 #include <linux/kgdb.h>
+#include <asm/fiq.h>
 #include <asm/traps.h>
 
+static unsigned int kgdb_fiq;
+
 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
 {
 	{ "r0", 4, offsetof(struct pt_regs, ARM_r0)},
@@ -175,14 +178,26 @@ static struct undef_hook kgdb_compiled_brkpt_hook = {
 
 static void kgdb_call_nmi_hook(void *ignored)
 {
-       kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+	kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
 }
 
 void kgdb_roundup_cpus(unsigned long flags)
 {
-       local_irq_enable();
-       smp_call_function(kgdb_call_nmi_hook, NULL, 0);
-       local_irq_disable();
+#if defined CONFIG_KGDB_FIQ && defined CONFIG_SMP
+	struct cpumask mask;
+
+	if (in_nmi()) {
+		cpumask_copy(&mask, cpu_online_mask);
+		cpumask_clear_cpu(raw_smp_processor_id(), &mask);
+		if (!cpumask_empty(&mask))
+			send_fiq_ipi_mask(&mask);
+		return;
+	}
+#endif
+
+	local_irq_enable();
+	smp_call_function(kgdb_call_nmi_hook, NULL, 0);
+	local_irq_disable();
 }
 
 static int __kgdb_notify(struct die_args *args, unsigned long cmd)
@@ -244,6 +259,41 @@ void kgdb_arch_exit(void)
 	unregister_die_notifier(&kgdb_notifier);
 }
 
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	/* warn if ttyNMI0 is active but brings no benefit */
+	if (WARN_ONCE(!kgdb_fiq, "kgdb: no FIQ available\n"))
+		return;
+
+#ifdef CONFIG_KGDB_FIQ
+	static atomic_t cnt;
+	int ret;
+
+	ret = atomic_add_return(on ? 1 : -1, &cnt);
+
+	/*
+	 * There should be only one instance that calls this function
+	 * in "enable, disable" order. All other users must call
+	 * disable first, then enable. If not, something is wrong.
+	 */
+	if (WARN_ON(ret > 1 && on))
+		return;
+
+	if (ret > 0)
+		enable_fiq(kgdb_fiq);
+	else
+		disable_fiq(kgdb_fiq);
+#endif
+}
+
+
 /*
  * Register our undef instruction hooks with ARM undef core.
  * We regsiter a hook specifically looking for the KGB break inst
@@ -252,8 +302,61 @@ void kgdb_arch_exit(void)
  */
 struct kgdb_arch arch_kgdb_ops = {
 #ifndef __ARMEB__
-	.gdb_bpt_instr		= {0xfe, 0xde, 0xff, 0xe7}
+	.gdb_bpt_instr		= {0xfe, 0xde, 0xff, 0xe7},
 #else /* ! __ARMEB__ */
-	.gdb_bpt_instr		= {0xe7, 0xff, 0xde, 0xfe}
+	.gdb_bpt_instr		= {0xe7, 0xff, 0xde, 0xfe},
 #endif
+	.enable_nmi		= kgdb_fiq_enable_nmi
 };
+
+#ifdef CONFIG_KGDB_FIQ
+static int kgdb_handle_fiq(struct notifier_block *nb, unsigned long arg,
+			   void *data)
+{
+	struct pt_regs *regs = (void *) arg;
+	int actual;
+
+	if (!kgdb_nmicallback(raw_smp_processor_id(), regs))
+		return NOTIFY_OK;
+
+	actual = ack_fiq(kgdb_fiq);
+	WARN_ON(actual != kgdb_fiq);
+
+	/* there's no harm in doing this regardless of the above WARN_ON() */
+	if (kgdb_nmi_poll_knock())
+		kgdb_handle_exception(1, 0, 0, regs);
+
+	eoi_fiq(actual);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block kgdb_fiq_notifier = {
+	.notifier_call = kgdb_handle_fiq,
+	.priority = 100,
+};
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	static struct fiq_handler kgdb_fiq_desc = { .name = "kgdb", };
+	int err;
+
+	if (!has_fiq(fiq)) {
+		pr_warn(
+		    "%s: Cannot register %u (no FIQ with this number)\n",
+		    __func__, fiq);
+		return -ENODEV;
+	}
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	kgdb_fiq = fiq;
+	register_fiq_nmi_notifier(&kgdb_fiq_notifier);
+
+	return 0;
+}
+#endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 05/16] arm: KGDB/KDB FIQ support
@ 2014-08-18 13:40                 ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 13:40 UTC (permalink / raw)
  To: linux-arm-kernel

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of comments and
    other small fragments still survive, however without Anton's work
    to build from this patch would not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben.dooks@codethink.co.uk>
Cc: Omar Sandoval <osandov@osandov.com>
---
 arch/arm/Kconfig            |   2 +
 arch/arm/Kconfig.debug      |  19 ++++++++
 arch/arm/include/asm/kgdb.h |   4 ++
 arch/arm/kernel/kgdb.c      | 115 +++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 134 insertions(+), 6 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c49a775..e6380b3 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -305,6 +305,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -352,6 +353,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index f304694..a99f8d2 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,25 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be enabled
+	  by setting the console to ttyNMI0 (and choosing the underlying
+	  serial port using kgdboc)
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..6563da0 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,8 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern int kgdb_register_fiq(unsigned int fiq);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
index a74b53c..928c205 100644
--- a/arch/arm/kernel/kgdb.c
+++ b/arch/arm/kernel/kgdb.c
@@ -12,8 +12,11 @@
 #include <linux/irq.h>
 #include <linux/kdebug.h>
 #include <linux/kgdb.h>
+#include <asm/fiq.h>
 #include <asm/traps.h>
 
+static unsigned int kgdb_fiq;
+
 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
 {
 	{ "r0", 4, offsetof(struct pt_regs, ARM_r0)},
@@ -175,14 +178,26 @@ static struct undef_hook kgdb_compiled_brkpt_hook = {
 
 static void kgdb_call_nmi_hook(void *ignored)
 {
-       kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+	kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
 }
 
 void kgdb_roundup_cpus(unsigned long flags)
 {
-       local_irq_enable();
-       smp_call_function(kgdb_call_nmi_hook, NULL, 0);
-       local_irq_disable();
+#if defined CONFIG_KGDB_FIQ && defined CONFIG_SMP
+	struct cpumask mask;
+
+	if (in_nmi()) {
+		cpumask_copy(&mask, cpu_online_mask);
+		cpumask_clear_cpu(raw_smp_processor_id(), &mask);
+		if (!cpumask_empty(&mask))
+			send_fiq_ipi_mask(&mask);
+		return;
+	}
+#endif
+
+	local_irq_enable();
+	smp_call_function(kgdb_call_nmi_hook, NULL, 0);
+	local_irq_disable();
 }
 
 static int __kgdb_notify(struct die_args *args, unsigned long cmd)
@@ -244,6 +259,41 @@ void kgdb_arch_exit(void)
 	unregister_die_notifier(&kgdb_notifier);
 }
 
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	/* warn if ttyNMI0 is active but brings no benefit */
+	if (WARN_ONCE(!kgdb_fiq, "kgdb: no FIQ available\n"))
+		return;
+
+#ifdef CONFIG_KGDB_FIQ
+	static atomic_t cnt;
+	int ret;
+
+	ret = atomic_add_return(on ? 1 : -1, &cnt);
+
+	/*
+	 * There should be only one instance that calls this function
+	 * in "enable, disable" order. All other users must call
+	 * disable first, then enable. If not, something is wrong.
+	 */
+	if (WARN_ON(ret > 1 && on))
+		return;
+
+	if (ret > 0)
+		enable_fiq(kgdb_fiq);
+	else
+		disable_fiq(kgdb_fiq);
+#endif
+}
+
+
 /*
  * Register our undef instruction hooks with ARM undef core.
  * We regsiter a hook specifically looking for the KGB break inst
@@ -252,8 +302,61 @@ void kgdb_arch_exit(void)
  */
 struct kgdb_arch arch_kgdb_ops = {
 #ifndef __ARMEB__
-	.gdb_bpt_instr		= {0xfe, 0xde, 0xff, 0xe7}
+	.gdb_bpt_instr		= {0xfe, 0xde, 0xff, 0xe7},
 #else /* ! __ARMEB__ */
-	.gdb_bpt_instr		= {0xe7, 0xff, 0xde, 0xfe}
+	.gdb_bpt_instr		= {0xe7, 0xff, 0xde, 0xfe},
 #endif
+	.enable_nmi		= kgdb_fiq_enable_nmi
 };
+
+#ifdef CONFIG_KGDB_FIQ
+static int kgdb_handle_fiq(struct notifier_block *nb, unsigned long arg,
+			   void *data)
+{
+	struct pt_regs *regs = (void *) arg;
+	int actual;
+
+	if (!kgdb_nmicallback(raw_smp_processor_id(), regs))
+		return NOTIFY_OK;
+
+	actual = ack_fiq(kgdb_fiq);
+	WARN_ON(actual != kgdb_fiq);
+
+	/* there's no harm in doing this regardless of the above WARN_ON() */
+	if (kgdb_nmi_poll_knock())
+		kgdb_handle_exception(1, 0, 0, regs);
+
+	eoi_fiq(actual);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block kgdb_fiq_notifier = {
+	.notifier_call = kgdb_handle_fiq,
+	.priority = 100,
+};
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	static struct fiq_handler kgdb_fiq_desc = { .name = "kgdb", };
+	int err;
+
+	if (!has_fiq(fiq)) {
+		pr_warn(
+		    "%s: Cannot register %u (no FIQ with this number)\n",
+		    __func__, fiq);
+		return -ENODEV;
+	}
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	kgdb_fiq = fiq;
+	register_fiq_nmi_notifier(&kgdb_fiq_notifier);
+
+	return 0;
+}
+#endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 06/16] irqchip: gic: Provide support for interrupt grouping
  2014-07-10  8:03             ` Daniel Thompson
@ 2014-08-18 14:12               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:12 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Thomas Gleixner, Jason Cooper, Nicolas Pitre,
	Christoffer Dall, Sricharan R, Marc Zyngier

All GIC hardware except GICv1-without-TrustZone support provides a means
to group exceptions into group 0 (which can optionally be signally using
use FIQ) and group 1. The kernel currently provides no means to exploit
this. This patch alters the initialization of the GIC to place all
interrupts into group 1 which is the foundational requirement to meaningfully
use FIQ.

Note that the hardware functionality is unavailable to the kernel when a
secure monitor is present because access to the grouping registers are
prohibited outside "secure world" (this feature allows grouping to be
used to allow hardware peripherals to send interrupts into the secure
world). The GIC driver will automatically detect this and disable its
attempts to group interrupts.

On systems without TrustZone support the kernel has the power to route
interrupt sources to FIQ, potentially allowing a driver to exploit the
NMI-like properties of FIQ.

Tested on Freescale i.MX6 (quad A9), STiH416 (dual A9) and a self-written
qemu GICv2 model.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Dirk Behme <dirk.behme@de.bosch.com>
---
 drivers/irqchip/irq-gic.c | 99 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 94 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4b959e6..423707c 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -41,6 +41,9 @@
 #include <linux/irqchip/arm-gic.h>
 
 #include <asm/cputype.h>
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
@@ -68,6 +71,9 @@ struct gic_chip_data {
 #ifdef CONFIG_GIC_NON_BANKED
 	void __iomem *(*get_base)(union gic_base *);
 #endif
+#ifdef CONFIG_FIQ
+	bool fiq_enable;
+#endif
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
@@ -131,6 +137,16 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data,
 #define gic_set_base_accessor(d, f)
 #endif
 
+#ifdef CONFIG_FIQ
+static inline bool gic_data_fiq_enable(struct gic_chip_data *data)
+{
+	return data->fiq_enable;
+}
+#else
+static inline bool gic_data_fiq_enable(
+		struct gic_chip_data *data) { return false; }
+#endif
+
 static inline void __iomem *gic_dist_base(struct irq_data *d)
 {
 	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
@@ -325,6 +341,42 @@ static struct irq_chip gic_chip = {
 	.irq_set_wake		= gic_set_wake,
 };
 
+#ifdef CONFIG_FIQ
+static void __init gic_init_fiq(struct gic_chip_data *gic,
+				irq_hw_number_t first_irq,
+				unsigned int num_irqs)
+{
+	void __iomem *dist_base = gic_data_dist_base(gic_data);
+	unsigned int i;
+
+	/*
+	 * FIQ can only be supported on platforms without an extended irq_eoi
+	 * method (otherwise we take a lock during eoi handling).
+	 */
+	if (gic_arch_extn.irq_eoi)
+		return;
+
+	/*
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers a read-as-zero/write-ignored.
+	 * However as a precaution we restore the reset default regardless of
+	 * the result of the test.
+	 */
+	writel_relaxed(1, dist_base + GIC_DIST_IGROUP + 0);
+	gic->fiq_enable = readl_relaxed(dist_base + GIC_DIST_IGROUP + 0);
+	writel_relaxed(0, dist_base + GIC_DIST_IGROUP + 0);
+	pr_debug("gic: FIQ support %s\n",
+		 gic->fiq_enable ? "enabled" : "disabled");
+
+	if (!gic->fiq_enable)
+		return;
+}
+#else /* CONFIG_FIQ */
+static inline void gic_init_fiq(struct gic_chip_data *gic,
+				irq_hw_number_t first_irq,
+				unsigned int num_irqs) {}
+#endif /* CONFIG_FIQ */
+
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
 	if (gic_nr >= MAX_GIC_NR)
@@ -373,7 +425,22 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 
 	gic_dist_config(base, gic_irqs, NULL);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Optionally set all global interrupts to be group 1.
+	 */
+	if (gic_data_fiq_enable(gic))
+		for (i = 32; i < gic_irqs; i += 32)
+			writel_relaxed(0xffffffff,
+				       base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(3, base + GIC_DIST_CTRL);
+	else
+		writel_relaxed(1, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -400,8 +467,20 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 
 	gic_cpu_config(dist_base, NULL);
 
+	/*
+	 * Set all PPI and SGI interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers are read-as-zero/write-ignored.
+	 */
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
+	else
+		writel_relaxed(1, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -485,7 +564,10 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	if (gic_data_fiq_enable(&gic_data[gic_nr]))
+		writel_relaxed(3, dist_base + GIC_DIST_CTRL);
+	else
+		writel_relaxed(1, dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -542,7 +624,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -604,6 +686,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
 	unsigned long flags, map = 0;
+	unsigned long softint;
 
 	raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
@@ -618,7 +701,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+	softint = map << 16 | irq;
+	if (gic_data_fiq_enable(&gic_data[0]))
+		softint |= 0x8000;
+	writel_relaxed(softint,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
@@ -964,6 +1051,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 
 		gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
 					hwirq_base, &gic_irq_domain_ops, gic);
+
+		gic_init_fiq(gic, irq_base, gic_irqs);
 	} else {
 		gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
 						    &gic_irq_domain_ops,
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 06/16] irqchip: gic: Provide support for interrupt grouping
@ 2014-08-18 14:12               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:12 UTC (permalink / raw)
  To: linux-arm-kernel

All GIC hardware except GICv1-without-TrustZone support provides a means
to group exceptions into group 0 (which can optionally be signally using
use FIQ) and group 1. The kernel currently provides no means to exploit
this. This patch alters the initialization of the GIC to place all
interrupts into group 1 which is the foundational requirement to meaningfully
use FIQ.

Note that the hardware functionality is unavailable to the kernel when a
secure monitor is present because access to the grouping registers are
prohibited outside "secure world" (this feature allows grouping to be
used to allow hardware peripherals to send interrupts into the secure
world). The GIC driver will automatically detect this and disable its
attempts to group interrupts.

On systems without TrustZone support the kernel has the power to route
interrupt sources to FIQ, potentially allowing a driver to exploit the
NMI-like properties of FIQ.

Tested on Freescale i.MX6 (quad A9), STiH416 (dual A9) and a self-written
qemu GICv2 model.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Dirk Behme <dirk.behme@de.bosch.com>
---
 drivers/irqchip/irq-gic.c | 99 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 94 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4b959e6..423707c 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -41,6 +41,9 @@
 #include <linux/irqchip/arm-gic.h>
 
 #include <asm/cputype.h>
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
@@ -68,6 +71,9 @@ struct gic_chip_data {
 #ifdef CONFIG_GIC_NON_BANKED
 	void __iomem *(*get_base)(union gic_base *);
 #endif
+#ifdef CONFIG_FIQ
+	bool fiq_enable;
+#endif
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
@@ -131,6 +137,16 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data,
 #define gic_set_base_accessor(d, f)
 #endif
 
+#ifdef CONFIG_FIQ
+static inline bool gic_data_fiq_enable(struct gic_chip_data *data)
+{
+	return data->fiq_enable;
+}
+#else
+static inline bool gic_data_fiq_enable(
+		struct gic_chip_data *data) { return false; }
+#endif
+
 static inline void __iomem *gic_dist_base(struct irq_data *d)
 {
 	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
@@ -325,6 +341,42 @@ static struct irq_chip gic_chip = {
 	.irq_set_wake		= gic_set_wake,
 };
 
+#ifdef CONFIG_FIQ
+static void __init gic_init_fiq(struct gic_chip_data *gic,
+				irq_hw_number_t first_irq,
+				unsigned int num_irqs)
+{
+	void __iomem *dist_base = gic_data_dist_base(gic_data);
+	unsigned int i;
+
+	/*
+	 * FIQ can only be supported on platforms without an extended irq_eoi
+	 * method (otherwise we take a lock during eoi handling).
+	 */
+	if (gic_arch_extn.irq_eoi)
+		return;
+
+	/*
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers a read-as-zero/write-ignored.
+	 * However as a precaution we restore the reset default regardless of
+	 * the result of the test.
+	 */
+	writel_relaxed(1, dist_base + GIC_DIST_IGROUP + 0);
+	gic->fiq_enable = readl_relaxed(dist_base + GIC_DIST_IGROUP + 0);
+	writel_relaxed(0, dist_base + GIC_DIST_IGROUP + 0);
+	pr_debug("gic: FIQ support %s\n",
+		 gic->fiq_enable ? "enabled" : "disabled");
+
+	if (!gic->fiq_enable)
+		return;
+}
+#else /* CONFIG_FIQ */
+static inline void gic_init_fiq(struct gic_chip_data *gic,
+				irq_hw_number_t first_irq,
+				unsigned int num_irqs) {}
+#endif /* CONFIG_FIQ */
+
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
 	if (gic_nr >= MAX_GIC_NR)
@@ -373,7 +425,22 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 
 	gic_dist_config(base, gic_irqs, NULL);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Optionally set all global interrupts to be group 1.
+	 */
+	if (gic_data_fiq_enable(gic))
+		for (i = 32; i < gic_irqs; i += 32)
+			writel_relaxed(0xffffffff,
+				       base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(3, base + GIC_DIST_CTRL);
+	else
+		writel_relaxed(1, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -400,8 +467,20 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 
 	gic_cpu_config(dist_base, NULL);
 
+	/*
+	 * Set all PPI and SGI interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers are read-as-zero/write-ignored.
+	 */
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
+	else
+		writel_relaxed(1, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -485,7 +564,10 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	if (gic_data_fiq_enable(&gic_data[gic_nr]))
+		writel_relaxed(3, dist_base + GIC_DIST_CTRL);
+	else
+		writel_relaxed(1, dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -542,7 +624,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -604,6 +686,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
 	unsigned long flags, map = 0;
+	unsigned long softint;
 
 	raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
@@ -618,7 +701,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+	softint = map << 16 | irq;
+	if (gic_data_fiq_enable(&gic_data[0]))
+		softint |= 0x8000;
+	writel_relaxed(softint,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
@@ -964,6 +1051,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 
 		gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
 					hwirq_base, &gic_irq_domain_ops, gic);
+
+		gic_init_fiq(gic, irq_base, gic_irqs);
 	} else {
 		gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
 						    &gic_irq_domain_ops,
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 07/16] irqchip: gic: Add support for FIQ management
  2014-07-10  8:03             ` Daniel Thompson
@ 2014-08-18 14:12               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:12 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Thomas Gleixner, Jason Cooper, Nicolas Pitre,
	Christoffer Dall, Sricharan R

This patch introduces callbacks to route interrupts to or away
from the FIQ signal and registers these callbacks with the FIQ
infrastructure (if the device can supports it).

Both these aspects combine and allow a driver to deploy a FIQ handler
without any machine specific knowledge; it can be used effectively on
multi-platform kernels.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
---
 drivers/irqchip/irq-gic.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 423707c..6fa0542 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -342,6 +342,69 @@ static struct irq_chip gic_chip = {
 };
 
 #ifdef CONFIG_FIQ
+/*
+ * Shift an interrupt between Group 0 and Group 1.
+ *
+ * In addition to changing the group we also modify the priority to
+ * match what "ARM strongly recommends" for a system where no Group 1
+ * interrupt must ever preempt a Group 0 interrupt.
+ */
+static void gic_set_group_irq(struct irq_data *d, int group)
+{
+	unsigned int grp_reg = gic_irq(d) / 32 * 4;
+	u32 grp_mask = 1 << (gic_irq(d) % 32);
+	u32 grp_val;
+
+	unsigned int pri_reg = (gic_irq(d) / 4) * 4;
+	u32 pri_mask = 1 << (7 + ((gic_irq(d) % 4) * 8));
+	u32 pri_val;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	grp_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+
+	if (group) {
+		grp_val |= grp_mask;
+		pri_val |= pri_mask;
+	} else {
+		grp_val &= ~grp_mask;
+		pri_val &= ~pri_mask;
+	}
+
+	writel_relaxed(grp_val, gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void gic_enable_fiq(struct irq_data *d)
+{
+	gic_set_group_irq(d, 0);
+}
+
+static void gic_disable_fiq(struct irq_data *d)
+{
+	gic_set_group_irq(d, 1);
+}
+
+static int gic_ack_fiq(struct irq_data *d)
+{
+	struct gic_chip_data *gic = irq_data_get_irq_chip_data(d);
+	u32 irqstat, irqnr;
+
+	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+	irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	return irq_find_mapping(gic->domain, irqnr);
+}
+
+static struct fiq_chip gic_fiq = {
+	.fiq_enable		= gic_enable_fiq,
+	.fiq_disable            = gic_disable_fiq,
+	.fiq_ack		= gic_ack_fiq,
+	.fiq_eoi		= gic_eoi_irq,
+};
+
 static void __init gic_init_fiq(struct gic_chip_data *gic,
 				irq_hw_number_t first_irq,
 				unsigned int num_irqs)
@@ -370,6 +433,12 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 
 	if (!gic->fiq_enable)
 		return;
+
+	/*
+	 * FIQ is supported on this device! Register our chip data.
+	 */
+	for (i = 0; i < num_irqs; i++)
+		fiq_register_mapping(first_irq + i, &gic_fiq);
 }
 #else /* CONFIG_FIQ */
 static inline void gic_init_fiq(struct gic_chip_data *gic,
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 07/16] irqchip: gic: Add support for FIQ management
@ 2014-08-18 14:12               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:12 UTC (permalink / raw)
  To: linux-arm-kernel

This patch introduces callbacks to route interrupts to or away
from the FIQ signal and registers these callbacks with the FIQ
infrastructure (if the device can supports it).

Both these aspects combine and allow a driver to deploy a FIQ handler
without any machine specific knowledge; it can be used effectively on
multi-platform kernels.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
---
 drivers/irqchip/irq-gic.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 423707c..6fa0542 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -342,6 +342,69 @@ static struct irq_chip gic_chip = {
 };
 
 #ifdef CONFIG_FIQ
+/*
+ * Shift an interrupt between Group 0 and Group 1.
+ *
+ * In addition to changing the group we also modify the priority to
+ * match what "ARM strongly recommends" for a system where no Group 1
+ * interrupt must ever preempt a Group 0 interrupt.
+ */
+static void gic_set_group_irq(struct irq_data *d, int group)
+{
+	unsigned int grp_reg = gic_irq(d) / 32 * 4;
+	u32 grp_mask = 1 << (gic_irq(d) % 32);
+	u32 grp_val;
+
+	unsigned int pri_reg = (gic_irq(d) / 4) * 4;
+	u32 pri_mask = 1 << (7 + ((gic_irq(d) % 4) * 8));
+	u32 pri_val;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	grp_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+
+	if (group) {
+		grp_val |= grp_mask;
+		pri_val |= pri_mask;
+	} else {
+		grp_val &= ~grp_mask;
+		pri_val &= ~pri_mask;
+	}
+
+	writel_relaxed(grp_val, gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void gic_enable_fiq(struct irq_data *d)
+{
+	gic_set_group_irq(d, 0);
+}
+
+static void gic_disable_fiq(struct irq_data *d)
+{
+	gic_set_group_irq(d, 1);
+}
+
+static int gic_ack_fiq(struct irq_data *d)
+{
+	struct gic_chip_data *gic = irq_data_get_irq_chip_data(d);
+	u32 irqstat, irqnr;
+
+	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+	irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	return irq_find_mapping(gic->domain, irqnr);
+}
+
+static struct fiq_chip gic_fiq = {
+	.fiq_enable		= gic_enable_fiq,
+	.fiq_disable            = gic_disable_fiq,
+	.fiq_ack		= gic_ack_fiq,
+	.fiq_eoi		= gic_eoi_irq,
+};
+
 static void __init gic_init_fiq(struct gic_chip_data *gic,
 				irq_hw_number_t first_irq,
 				unsigned int num_irqs)
@@ -370,6 +433,12 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 
 	if (!gic->fiq_enable)
 		return;
+
+	/*
+	 * FIQ is supported on this device! Register our chip data.
+	 */
+	for (i = 0; i < num_irqs; i++)
+		fiq_register_mapping(first_irq + i, &gic_fiq);
 }
 #else /* CONFIG_FIQ */
 static inline void gic_init_fiq(struct gic_chip_data *gic,
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 08/16] irqchip: gic: Remove spin locks from eoi_irq
  2014-07-10  8:03             ` Daniel Thompson
@ 2014-08-18 14:12               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:12 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Thomas Gleixner, Jason Cooper, Peter De Schrijver

This patch is motivated by the comment it removes from gic_init_fiq,
namely that the spin locks in eoi_irq preclude certain platforms from
supporting FIQ.

Currently there is only one upstream platform (tegra) that actually
hooks gic_arch_extn.irq_eoi and it does not require these spin locks.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Peter De Schrijver <pdeschrijver@nvidia.com>
---
 drivers/irqchip/irq-gic.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 6fa0542..d928912 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -191,11 +191,8 @@ static void gic_unmask_irq(struct irq_data *d)
 
 static void gic_eoi_irq(struct irq_data *d)
 {
-	if (gic_arch_extn.irq_eoi) {
-		raw_spin_lock(&irq_controller_lock);
+	if (gic_arch_extn.irq_eoi)
 		gic_arch_extn.irq_eoi(d);
-		raw_spin_unlock(&irq_controller_lock);
-	}
 
 	writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
 }
@@ -413,13 +410,6 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 	unsigned int i;
 
 	/*
-	 * FIQ can only be supported on platforms without an extended irq_eoi
-	 * method (otherwise we take a lock during eoi handling).
-	 */
-	if (gic_arch_extn.irq_eoi)
-		return;
-
-	/*
 	 * If grouping is not available (not implemented or prohibited by
 	 * security mode) these registers a read-as-zero/write-ignored.
 	 * However as a precaution we restore the reset default regardless of
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 08/16] irqchip: gic: Remove spin locks from eoi_irq
@ 2014-08-18 14:12               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:12 UTC (permalink / raw)
  To: linux-arm-kernel

This patch is motivated by the comment it removes from gic_init_fiq,
namely that the spin locks in eoi_irq preclude certain platforms from
supporting FIQ.

Currently there is only one upstream platform (tegra) that actually
hooks gic_arch_extn.irq_eoi and it does not require these spin locks.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Peter De Schrijver <pdeschrijver@nvidia.com>
---
 drivers/irqchip/irq-gic.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 6fa0542..d928912 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -191,11 +191,8 @@ static void gic_unmask_irq(struct irq_data *d)
 
 static void gic_eoi_irq(struct irq_data *d)
 {
-	if (gic_arch_extn.irq_eoi) {
-		raw_spin_lock(&irq_controller_lock);
+	if (gic_arch_extn.irq_eoi)
 		gic_arch_extn.irq_eoi(d);
-		raw_spin_unlock(&irq_controller_lock);
-	}
 
 	writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
 }
@@ -413,13 +410,6 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 	unsigned int i;
 
 	/*
-	 * FIQ can only be supported on platforms without an extended irq_eoi
-	 * method (otherwise we take a lock during eoi handling).
-	 */
-	if (gic_arch_extn.irq_eoi)
-		return;
-
-	/*
 	 * If grouping is not available (not implemented or prohibited by
 	 * security mode) these registers a read-as-zero/write-ignored.
 	 * However as a precaution we restore the reset default regardless of
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 09/16] irqchip: gic: Add support for IPI FIQ
  2014-07-10  8:03             ` Daniel Thompson
@ 2014-08-18 14:12               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:12 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

To support IPI FIQ we alter gic_cpu_init() to honour SMP_IPI_FIQ_MASK and
register a fairly high priority notifier to acknowledge and clear the IPI
when it is triggered.

For the IPI FIQ to be useful we must also make it safe to call
gic_raise_softirq() from the FIQ handler by altering the locking
strategy slightly.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/irqchip/irq-gic.c | 123 ++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 102 insertions(+), 21 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index d928912..3fa824e 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,6 +39,7 @@
 #include <linux/slab.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/ratelimit.h>
 
 #include <asm/cputype.h>
 #ifdef CONFIG_FIQ
@@ -51,6 +52,10 @@
 #include "irq-gic-common.h"
 #include "irqchip.h"
 
+#ifndef SMP_IPI_FIQ_MASK
+#define SMP_IPI_FIQ_MASK 0
+#endif
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -77,6 +82,8 @@ struct gic_chip_data {
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+/* A fiq-safe spinlock must only be locked when the FIQ is masked */
+static DEFINE_RAW_SPINLOCK(fiq_safe_migration_lock);
 
 /*
  * The GIC mapping of CPU interfaces does not necessarily match
@@ -346,20 +353,21 @@ static struct irq_chip gic_chip = {
  * match what "ARM strongly recommends" for a system where no Group 1
  * interrupt must ever preempt a Group 0 interrupt.
  */
-static void gic_set_group_irq(struct irq_data *d, int group)
+static void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				int group)
 {
-	unsigned int grp_reg = gic_irq(d) / 32 * 4;
-	u32 grp_mask = 1 << (gic_irq(d) % 32);
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_mask = 1 << (hwirq % 32);
 	u32 grp_val;
 
-	unsigned int pri_reg = (gic_irq(d) / 4) * 4;
-	u32 pri_mask = 1 << (7 + ((gic_irq(d) % 4) * 8));
+	unsigned int pri_reg = (hwirq / 4) * 4;
+	u32 pri_mask = 1 << (7 + ((hwirq % 4) * 8));
 	u32 pri_val;
 
 	raw_spin_lock(&irq_controller_lock);
 
-	grp_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
-	pri_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(base + GIC_DIST_PRI + pri_reg);
 
 	if (group) {
 		grp_val |= grp_mask;
@@ -369,20 +377,20 @@ static void gic_set_group_irq(struct irq_data *d, int group)
 		pri_val &= ~pri_mask;
 	}
 
-	writel_relaxed(grp_val, gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
-	writel_relaxed(pri_val, gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+	writel_relaxed(grp_val, base + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, base + GIC_DIST_PRI + pri_reg);
 
 	raw_spin_unlock(&irq_controller_lock);
 }
 
 static void gic_enable_fiq(struct irq_data *d)
 {
-	gic_set_group_irq(d, 0);
+	gic_set_group_irq(gic_dist_base(d), gic_irq(d), 0);
 }
 
 static void gic_disable_fiq(struct irq_data *d)
 {
-	gic_set_group_irq(d, 1);
+	gic_set_group_irq(gic_dist_base(d), gic_irq(d), 1);
 }
 
 static int gic_ack_fiq(struct irq_data *d)
@@ -390,8 +398,22 @@ static int gic_ack_fiq(struct irq_data *d)
 	struct gic_chip_data *gic = irq_data_get_irq_chip_data(d);
 	u32 irqstat, irqnr;
 
-	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
-	irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	while (1) {
+		writel_relaxed(0x70, gic_data_cpu_base(gic) + GIC_CPU_PRIMASK);
+		irqstat =
+		    readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+		writel_relaxed(0xf0, gic_data_cpu_base(gic) + GIC_CPU_PRIMASK);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		if (irqnr > 15)
+			break;
+
+		/* we've got an IPI which we can simply acknowledge
+		 * and move on
+		 */
+		gic_eoi_irq(d);
+	}
+
 	return irq_find_mapping(gic->domain, irqnr);
 }
 
@@ -430,7 +452,43 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 	for (i = 0; i < num_irqs; i++)
 		fiq_register_mapping(first_irq + i, &gic_fiq);
 }
+
+/*
+ * Fully acknowledge (both ack and eoi) a FIQ-based IPI
+ */
+static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
+			   void *data)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	unsigned long irqstat, irqnr;
+
+	if (WARN_ON(!in_nmi()))
+		return NOTIFY_BAD;
+
+	while ((1u << readl_relaxed(cpu_base + GIC_CPU_HIGHPRI)) &
+	       SMP_IPI_FIQ_MASK) {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		WARN_RATELIMIT(irqnr > 16,
+			       "Unexpected irqnr %lu (bad prioritization?)\n",
+			       irqnr);
+	}
+
+	return NOTIFY_OK;
+}
+
+/*
+ * Notifier to ensure IPI FIQ is acknowledged correctly.
+ */
+static struct notifier_block gic_fiq_ipi_notifier = {
+	.notifier_call = gic_handle_fiq_ipi,
+};
 #else /* CONFIG_FIQ */
+static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				     int group) {}
 static inline void gic_init_fiq(struct gic_chip_data *gic,
 				irq_hw_number_t first_irq,
 				unsigned int num_irqs) {}
@@ -527,14 +585,19 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	gic_cpu_config(dist_base, NULL);
 
 	/*
-	 * Set all PPI and SGI interrupts to be group 1.
-	 *
-	 * If grouping is not available (not implemented or prohibited by
-	 * security mode) these registers are read-as-zero/write-ignored.
+	 * Optionally set all PPI and SGI interrupts to be group 1.
 	 */
 	if (gic_data_fiq_enable(gic))
 		writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
 
+	/*
+	 * Optionally shift the FIQ based IPIs to group 0.
+	 */
+	if (gic_data_fiq_enable(gic))
+		for (i = 0; i < 16; i++)
+			if (SMP_IPI_FIQ_MASK & (1 << i))
+				gic_set_group_irq(dist_base, i, 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
 	if (gic_data_fiq_enable(gic))
 		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
@@ -747,7 +810,17 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	unsigned long flags, map = 0;
 	unsigned long softint;
 
-	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+	/*
+	 * The locking in this function ensures we don't use stale cpu mappings
+	 * and thus we never route an IPI to the wrong physical core during a
+	 * big.LITTLE switch. The switch code takes both of these locks meaning
+	 * we can choose whichever lock is safe to use from our current calling
+	 * context.
+	 */
+	if (in_nmi())
+		raw_spin_lock(&fiq_safe_migration_lock);
+	else
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
 	/* Convert our logical CPU mask into a physical one. */
 	for_each_cpu(cpu, mask)
@@ -761,12 +834,16 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 
 	/* this always happens on GIC0 */
 	softint = map << 16 | irq;
-	if (gic_data_fiq_enable(&gic_data[0]))
+	if (gic_data_fiq_enable(&gic_data[0]) &&
+	    !(SMP_IPI_FIQ_MASK & (1 << irq)))
 		softint |= 0x8000;
 	writel_relaxed(softint,
 		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
-	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+	if (in_nmi())
+		raw_spin_unlock(&fiq_safe_migration_lock);
+	else
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 #endif
 
@@ -814,7 +891,7 @@ int gic_get_cpu_id(unsigned int cpu)
  * Migrate all peripheral interrupts with a target matching the current CPU
  * to the interface corresponding to @new_cpu_id.  The CPU interface mapping
  * is also updated.  Targets to other CPU interfaces are unchanged.
- * This must be called with IRQs locally disabled.
+ * This must be called with IRQ and FIQ locally disabled.
  */
 void gic_migrate_target(unsigned int new_cpu_id)
 {
@@ -836,6 +913,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 	ror_val = (cur_cpu_id - new_cpu_id) & 31;
 
 	raw_spin_lock(&irq_controller_lock);
+	raw_spin_lock(&fiq_safe_migration_lock);
 
 	/* Update the target interface for this logical CPU */
 	gic_cpu_map[cpu] = 1 << new_cpu_id;
@@ -855,6 +933,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 		}
 	}
 
+	raw_spin_unlock(&fiq_safe_migration_lock);
 	raw_spin_unlock(&irq_controller_lock);
 
 	/*
@@ -1125,6 +1204,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 #ifdef CONFIG_SMP
 		set_smp_cross_call(gic_raise_softirq);
 		register_cpu_notifier(&gic_cpu_notifier);
+		if (gic_data_fiq_enable(gic))
+			register_fiq_nmi_notifier(&gic_fiq_ipi_notifier);
 #endif
 		set_handle_irq(gic_handle_irq);
 	}
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 09/16] irqchip: gic: Add support for IPI FIQ
@ 2014-08-18 14:12               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:12 UTC (permalink / raw)
  To: linux-arm-kernel

To support IPI FIQ we alter gic_cpu_init() to honour SMP_IPI_FIQ_MASK and
register a fairly high priority notifier to acknowledge and clear the IPI
when it is triggered.

For the IPI FIQ to be useful we must also make it safe to call
gic_raise_softirq() from the FIQ handler by altering the locking
strategy slightly.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/irqchip/irq-gic.c | 123 ++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 102 insertions(+), 21 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index d928912..3fa824e 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,6 +39,7 @@
 #include <linux/slab.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/ratelimit.h>
 
 #include <asm/cputype.h>
 #ifdef CONFIG_FIQ
@@ -51,6 +52,10 @@
 #include "irq-gic-common.h"
 #include "irqchip.h"
 
+#ifndef SMP_IPI_FIQ_MASK
+#define SMP_IPI_FIQ_MASK 0
+#endif
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -77,6 +82,8 @@ struct gic_chip_data {
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+/* A fiq-safe spinlock must only be locked when the FIQ is masked */
+static DEFINE_RAW_SPINLOCK(fiq_safe_migration_lock);
 
 /*
  * The GIC mapping of CPU interfaces does not necessarily match
@@ -346,20 +353,21 @@ static struct irq_chip gic_chip = {
  * match what "ARM strongly recommends" for a system where no Group 1
  * interrupt must ever preempt a Group 0 interrupt.
  */
-static void gic_set_group_irq(struct irq_data *d, int group)
+static void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				int group)
 {
-	unsigned int grp_reg = gic_irq(d) / 32 * 4;
-	u32 grp_mask = 1 << (gic_irq(d) % 32);
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_mask = 1 << (hwirq % 32);
 	u32 grp_val;
 
-	unsigned int pri_reg = (gic_irq(d) / 4) * 4;
-	u32 pri_mask = 1 << (7 + ((gic_irq(d) % 4) * 8));
+	unsigned int pri_reg = (hwirq / 4) * 4;
+	u32 pri_mask = 1 << (7 + ((hwirq % 4) * 8));
 	u32 pri_val;
 
 	raw_spin_lock(&irq_controller_lock);
 
-	grp_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
-	pri_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(base + GIC_DIST_PRI + pri_reg);
 
 	if (group) {
 		grp_val |= grp_mask;
@@ -369,20 +377,20 @@ static void gic_set_group_irq(struct irq_data *d, int group)
 		pri_val &= ~pri_mask;
 	}
 
-	writel_relaxed(grp_val, gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
-	writel_relaxed(pri_val, gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+	writel_relaxed(grp_val, base + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, base + GIC_DIST_PRI + pri_reg);
 
 	raw_spin_unlock(&irq_controller_lock);
 }
 
 static void gic_enable_fiq(struct irq_data *d)
 {
-	gic_set_group_irq(d, 0);
+	gic_set_group_irq(gic_dist_base(d), gic_irq(d), 0);
 }
 
 static void gic_disable_fiq(struct irq_data *d)
 {
-	gic_set_group_irq(d, 1);
+	gic_set_group_irq(gic_dist_base(d), gic_irq(d), 1);
 }
 
 static int gic_ack_fiq(struct irq_data *d)
@@ -390,8 +398,22 @@ static int gic_ack_fiq(struct irq_data *d)
 	struct gic_chip_data *gic = irq_data_get_irq_chip_data(d);
 	u32 irqstat, irqnr;
 
-	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
-	irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	while (1) {
+		writel_relaxed(0x70, gic_data_cpu_base(gic) + GIC_CPU_PRIMASK);
+		irqstat =
+		    readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+		writel_relaxed(0xf0, gic_data_cpu_base(gic) + GIC_CPU_PRIMASK);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		if (irqnr > 15)
+			break;
+
+		/* we've got an IPI which we can simply acknowledge
+		 * and move on
+		 */
+		gic_eoi_irq(d);
+	}
+
 	return irq_find_mapping(gic->domain, irqnr);
 }
 
@@ -430,7 +452,43 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 	for (i = 0; i < num_irqs; i++)
 		fiq_register_mapping(first_irq + i, &gic_fiq);
 }
+
+/*
+ * Fully acknowledge (both ack and eoi) a FIQ-based IPI
+ */
+static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
+			   void *data)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	unsigned long irqstat, irqnr;
+
+	if (WARN_ON(!in_nmi()))
+		return NOTIFY_BAD;
+
+	while ((1u << readl_relaxed(cpu_base + GIC_CPU_HIGHPRI)) &
+	       SMP_IPI_FIQ_MASK) {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		WARN_RATELIMIT(irqnr > 16,
+			       "Unexpected irqnr %lu (bad prioritization?)\n",
+			       irqnr);
+	}
+
+	return NOTIFY_OK;
+}
+
+/*
+ * Notifier to ensure IPI FIQ is acknowledged correctly.
+ */
+static struct notifier_block gic_fiq_ipi_notifier = {
+	.notifier_call = gic_handle_fiq_ipi,
+};
 #else /* CONFIG_FIQ */
+static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				     int group) {}
 static inline void gic_init_fiq(struct gic_chip_data *gic,
 				irq_hw_number_t first_irq,
 				unsigned int num_irqs) {}
@@ -527,14 +585,19 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	gic_cpu_config(dist_base, NULL);
 
 	/*
-	 * Set all PPI and SGI interrupts to be group 1.
-	 *
-	 * If grouping is not available (not implemented or prohibited by
-	 * security mode) these registers are read-as-zero/write-ignored.
+	 * Optionally set all PPI and SGI interrupts to be group 1.
 	 */
 	if (gic_data_fiq_enable(gic))
 		writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
 
+	/*
+	 * Optionally shift the FIQ based IPIs to group 0.
+	 */
+	if (gic_data_fiq_enable(gic))
+		for (i = 0; i < 16; i++)
+			if (SMP_IPI_FIQ_MASK & (1 << i))
+				gic_set_group_irq(dist_base, i, 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
 	if (gic_data_fiq_enable(gic))
 		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
@@ -747,7 +810,17 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	unsigned long flags, map = 0;
 	unsigned long softint;
 
-	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+	/*
+	 * The locking in this function ensures we don't use stale cpu mappings
+	 * and thus we never route an IPI to the wrong physical core during a
+	 * big.LITTLE switch. The switch code takes both of these locks meaning
+	 * we can choose whichever lock is safe to use from our current calling
+	 * context.
+	 */
+	if (in_nmi())
+		raw_spin_lock(&fiq_safe_migration_lock);
+	else
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
 	/* Convert our logical CPU mask into a physical one. */
 	for_each_cpu(cpu, mask)
@@ -761,12 +834,16 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 
 	/* this always happens on GIC0 */
 	softint = map << 16 | irq;
-	if (gic_data_fiq_enable(&gic_data[0]))
+	if (gic_data_fiq_enable(&gic_data[0]) &&
+	    !(SMP_IPI_FIQ_MASK & (1 << irq)))
 		softint |= 0x8000;
 	writel_relaxed(softint,
 		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
-	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+	if (in_nmi())
+		raw_spin_unlock(&fiq_safe_migration_lock);
+	else
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 #endif
 
@@ -814,7 +891,7 @@ int gic_get_cpu_id(unsigned int cpu)
  * Migrate all peripheral interrupts with a target matching the current CPU
  * to the interface corresponding to @new_cpu_id.  The CPU interface mapping
  * is also updated.  Targets to other CPU interfaces are unchanged.
- * This must be called with IRQs locally disabled.
+ * This must be called with IRQ and FIQ locally disabled.
  */
 void gic_migrate_target(unsigned int new_cpu_id)
 {
@@ -836,6 +913,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 	ror_val = (cur_cpu_id - new_cpu_id) & 31;
 
 	raw_spin_lock(&irq_controller_lock);
+	raw_spin_lock(&fiq_safe_migration_lock);
 
 	/* Update the target interface for this logical CPU */
 	gic_cpu_map[cpu] = 1 << new_cpu_id;
@@ -855,6 +933,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 		}
 	}
 
+	raw_spin_unlock(&fiq_safe_migration_lock);
 	raw_spin_unlock(&irq_controller_lock);
 
 	/*
@@ -1125,6 +1204,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 #ifdef CONFIG_SMP
 		set_smp_cross_call(gic_raise_softirq);
 		register_cpu_notifier(&gic_cpu_notifier);
+		if (gic_data_fiq_enable(gic))
+			register_fiq_nmi_notifier(&gic_fiq_ipi_notifier);
 #endif
 		set_handle_irq(gic_handle_irq);
 	}
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 10/16] irqchip: gic: Group 0 workaround.
  2014-07-10  8:03             ` Daniel Thompson
@ 2014-08-18 14:12               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:12 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Thomas Gleixner, Jason Cooper

An ARM system based on GICv1 that runs by default in secure mode and
uses both group 0 and group 1 interrupts (in order to exploit FIQ)
will suffer a problem where the IRQ handler occasionally spuriously
acknowledges a group 0 (FIQ) interrupt.

This can be prevented by ensuring the IRQ handler makes non-secure
memory access to the GIC registers but this is complex because
the non-secure bits cannot be apply to 4k pages (the bit is one level
up in the page table and applies to 1MB at a time).

This workaround uses an alternative approach that spots the spurious
acknowledgment and regenerates the FIQ. This keeps the workaround
exclusively within the GIC driver (although there is a runtime
perforamnce penalty resulting from this approach).

Reported-by: Harro Haan <hrhaan@gmail.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Tested-by: Harro Haan <hrhaan@gmail.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
---
 drivers/irqchip/irq-gic.c | 52 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 49 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 3fa824e..a670e72 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -279,14 +279,59 @@ static int gic_set_wake(struct irq_data *d, unsigned int on)
 #define gic_set_wake	NULL
 #endif
 
+#ifdef CONFIG_FIQ
+/* This is a software emulation of the Aliased Interrupt Acknowledge Register
+ * (GIC_AIAR) found in GICv2+.
+ */
+static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32 irqstat)
+{
+	u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	void __iomem *dist_base = gic_data_dist_base(gic);
+	u32 offset, mask;
+
+	if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
+		return irqstat;
+
+	offset = irqnr / 32 * 4;
+	mask = 1 << (irqnr % 32);
+	if (readl_relaxed(dist_base + GIC_DIST_IGROUP + offset) & mask)
+		return irqstat;
+
+	/* this interrupt must be taken as a FIQ so put it back into the
+	 * pending state and end our own servicing of it.
+	 */
+	writel_relaxed(mask, dist_base + GIC_DIST_PENDING_SET + offset);
+	readl_relaxed(dist_base + GIC_DIST_PENDING_SET + offset);
+	writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
+
+	return 1023;
+}
+
+static u32 gic_ack_irq(struct gic_chip_data *gic)
+{
+	u32 irqstat;
+
+	local_fiq_disable();
+	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+	irqstat = gic_handle_spurious_group_0(gic, irqstat);
+	local_fiq_enable();
+
+	return irqstat;
+}
+#else
+static u32 gic_ack_irq(struct gic_chip_data *gic)
+{
+	return readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+}
+#endif
+
 static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
 	u32 irqstat, irqnr;
 	struct gic_chip_data *gic = &gic_data[0];
-	void __iomem *cpu_base = gic_data_cpu_base(gic);
 
 	do {
-		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		irqstat = gic_ack_irq(gic);
 		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
 
 		if (likely(irqnr > 15 && irqnr < 1021)) {
@@ -295,7 +340,8 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 			continue;
 		}
 		if (irqnr < 16) {
-			writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+			writel_relaxed(irqstat,
+				       gic_data_cpu_base(gic) + GIC_CPU_EOI);
 #ifdef CONFIG_SMP
 			handle_IPI(irqnr, regs);
 #endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 10/16] irqchip: gic: Group 0 workaround.
@ 2014-08-18 14:12               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:12 UTC (permalink / raw)
  To: linux-arm-kernel

An ARM system based on GICv1 that runs by default in secure mode and
uses both group 0 and group 1 interrupts (in order to exploit FIQ)
will suffer a problem where the IRQ handler occasionally spuriously
acknowledges a group 0 (FIQ) interrupt.

This can be prevented by ensuring the IRQ handler makes non-secure
memory access to the GIC registers but this is complex because
the non-secure bits cannot be apply to 4k pages (the bit is one level
up in the page table and applies to 1MB at a time).

This workaround uses an alternative approach that spots the spurious
acknowledgment and regenerates the FIQ. This keeps the workaround
exclusively within the GIC driver (although there is a runtime
perforamnce penalty resulting from this approach).

Reported-by: Harro Haan <hrhaan@gmail.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Tested-by: Harro Haan <hrhaan@gmail.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
---
 drivers/irqchip/irq-gic.c | 52 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 49 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 3fa824e..a670e72 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -279,14 +279,59 @@ static int gic_set_wake(struct irq_data *d, unsigned int on)
 #define gic_set_wake	NULL
 #endif
 
+#ifdef CONFIG_FIQ
+/* This is a software emulation of the Aliased Interrupt Acknowledge Register
+ * (GIC_AIAR) found in GICv2+.
+ */
+static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32 irqstat)
+{
+	u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	void __iomem *dist_base = gic_data_dist_base(gic);
+	u32 offset, mask;
+
+	if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
+		return irqstat;
+
+	offset = irqnr / 32 * 4;
+	mask = 1 << (irqnr % 32);
+	if (readl_relaxed(dist_base + GIC_DIST_IGROUP + offset) & mask)
+		return irqstat;
+
+	/* this interrupt must be taken as a FIQ so put it back into the
+	 * pending state and end our own servicing of it.
+	 */
+	writel_relaxed(mask, dist_base + GIC_DIST_PENDING_SET + offset);
+	readl_relaxed(dist_base + GIC_DIST_PENDING_SET + offset);
+	writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
+
+	return 1023;
+}
+
+static u32 gic_ack_irq(struct gic_chip_data *gic)
+{
+	u32 irqstat;
+
+	local_fiq_disable();
+	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+	irqstat = gic_handle_spurious_group_0(gic, irqstat);
+	local_fiq_enable();
+
+	return irqstat;
+}
+#else
+static u32 gic_ack_irq(struct gic_chip_data *gic)
+{
+	return readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+}
+#endif
+
 static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
 	u32 irqstat, irqnr;
 	struct gic_chip_data *gic = &gic_data[0];
-	void __iomem *cpu_base = gic_data_cpu_base(gic);
 
 	do {
-		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		irqstat = gic_ack_irq(gic);
 		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
 
 		if (likely(irqnr > 15 && irqnr < 1021)) {
@@ -295,7 +340,8 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 			continue;
 		}
 		if (irqnr < 16) {
-			writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+			writel_relaxed(irqstat,
+				       gic_data_cpu_base(gic) + GIC_CPU_EOI);
 #ifdef CONFIG_SMP
 			handle_IPI(irqnr, regs);
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 11/16] irqchip: vic: Add support for FIQ management
  2014-07-10  8:03             ` Daniel Thompson
  (?)
@ 2014-08-18 14:12               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:12 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Hartley Sweeten, Ryan Mallon, Ben Dooks,
	Kukjin Kim, Thomas Gleixner, Jason Cooper, linux-samsung-soc

This patch introduces callbacks to route interrupts to or away
from the FIQ signal. It also causes these callbacks to be registered
with the FIQ infrastructure.

This patch enable FIQ support for mach-versatile whilst mach-ep93xx,
mach-netx, mach-s3c64xx and plat-samsung are unmodified (and can therefore
continue to use init_FIQ() as before).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: linux-samsung-soc@vger.kernel.org
---
 arch/arm/mach-versatile/core.c  |  2 +-
 drivers/irqchip/irq-vic.c       | 92 ++++++++++++++++++++++++++++++++---------
 include/linux/irqchip/arm-vic.h |  6 ++-
 3 files changed, 78 insertions(+), 22 deletions(-)

diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 08fb8c8..bad1d30 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -108,7 +108,7 @@ void __init versatile_init_irq(void)
 
 	np = of_find_matching_node_by_address(NULL, vic_of_match,
 					      VERSATILE_VIC_BASE);
-	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np);
+	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np ? false : true, np);
 
 	writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
 
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287..22aa126 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -36,6 +36,9 @@
 
 #include <asm/exception.h>
 #include <asm/irq.h>
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 
 #include "irqchip.h"
 
@@ -261,11 +264,53 @@ static struct irq_domain_ops vic_irqdomain_ops = {
 	.xlate = irq_domain_xlate_onetwocell,
 };
 
+#ifdef CONFIG_FIQ
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
+static void vic_set_fiq(struct irq_data *d, bool enable)
+{
+	void __iomem *base = irq_data_get_irq_chip_data(d);
+	unsigned int irq = d->hwirq;
+	u32 val;
+
+	raw_spin_lock(&irq_controller_lock);
+	val = readl(base + VIC_INT_SELECT);
+	if (enable)
+		val |= 1 << irq;
+	else
+		val &= ~(1 << irq);
+	writel(val, base + VIC_INT_SELECT);
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void vic_enable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, true);
+}
+
+static void vic_disable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, false);
+}
+
+struct fiq_chip vic_fiq = {
+	.fiq_enable = vic_enable_fiq,
+	.fiq_disable = vic_disable_fiq,
+};
+
+static void vic_register_fiq(int irq)
+{
+	fiq_register_mapping(irq, &vic_fiq);
+}
+#else /* CONFIG_FIQ */
+static inline void vic_register_fiq(int irq) {}
+#endif /* CONFIG_FIQ */
+
 /**
  * vic_register() - Register a VIC.
  * @base: The base address of the VIC.
  * @parent_irq: The parent IRQ if cascaded, else 0.
- * @irq: The base IRQ for the VIC.
+ * @irq_start: The base IRQ for the VIC.
  * @valid_sources: bitmask of valid interrupts
  * @resume_sources: bitmask of interrupts allowed for resume sources.
  * @node: The device tree node associated with the VIC.
@@ -277,12 +322,13 @@ static struct irq_domain_ops vic_irqdomain_ops = {
  * This also configures the IRQ domain for the VIC.
  */
 static void __init vic_register(void __iomem *base, unsigned int parent_irq,
-				unsigned int irq,
+				unsigned int irq_start,
 				u32 valid_sources, u32 resume_sources,
-				struct device_node *node)
+				bool map_fiqs, struct device_node *node)
 {
 	struct vic_device *v;
 	int i;
+	unsigned int irq;
 
 	if (vic_id >= ARRAY_SIZE(vic_devices)) {
 		printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
@@ -301,15 +347,19 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 		irq_set_chained_handler(parent_irq, vic_handle_irq_cascaded);
 	}
 
-	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq,
+	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq_start,
 					  &vic_irqdomain_ops, v);
 	/* create an IRQ mapping for each valid IRQ */
-	for (i = 0; i < fls(valid_sources); i++)
-		if (valid_sources & (1 << i))
-			irq_create_mapping(v->domain, i);
+	for (i = 0; i < fls(valid_sources); i++) {
+		if (valid_sources & (1 << i)) {
+			irq = irq_create_mapping(v->domain, i);
+			vic_register_fiq(irq);
+		}
+	}
+
 	/* If no base IRQ was passed, figure out our allocated base */
-	if (irq)
-		v->irq = irq;
+	if (irq_start)
+		v->irq = irq_start;
 	else
 		v->irq = irq_find_mapping(v->domain, 0);
 }
@@ -413,7 +463,8 @@ static void __init vic_clear_interrupts(void __iomem *base)
  *  and 020 within the page. We call this "second block".
  */
 static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
-			       u32 vic_sources, struct device_node *node)
+			       u32 vic_sources, bool map_fiqs,
+			       struct device_node *node)
 {
 	unsigned int i;
 	int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
@@ -439,12 +490,12 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
 		writel(32, base + VIC_PL190_DEF_VECT_ADDR);
 	}
 
-	vic_register(base, 0, irq_start, vic_sources, 0, node);
+	vic_register(base, 0, irq_start, vic_sources, 0, map_fiqs, node);
 }
 
 void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
-			      u32 vic_sources, u32 resume_sources,
-			      struct device_node *node)
+		       u32 vic_sources, u32 resume_sources,
+		       bool map_fiqs, struct device_node *node)
 {
 	unsigned int i;
 	u32 cellid = 0;
@@ -462,7 +513,7 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	switch(vendor) {
 	case AMBA_VENDOR_ST:
-		vic_init_st(base, irq_start, vic_sources, node);
+		vic_init_st(base, irq_start, vic_sources, map_fiqs, node);
 		return;
 	default:
 		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
@@ -479,7 +530,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	vic_init2(base);
 
-	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);
+	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources,
+		     map_fiqs, node);
 }
 
 /**
@@ -492,7 +544,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 void __init vic_init(void __iomem *base, unsigned int irq_start,
 		     u32 vic_sources, u32 resume_sources)
 {
-	__vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL);
+	__vic_init(base, 0, irq_start, vic_sources, resume_sources,
+		   false, NULL);
 }
 
 /**
@@ -511,7 +564,8 @@ int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 	struct vic_device *v;
 
 	v = &vic_devices[vic_id];
-	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL);
+	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, false,
+		   NULL);
 	/* Return out acquired base */
 	return v->irq;
 }
@@ -535,9 +589,9 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
 	of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask);
 
 	/*
-	 * Passing 0 as first IRQ makes the simple domain allocate descriptors
+	 * Passing 0 as first IRQ makes the domain allocate descriptors.
 	 */
-	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
+	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, true, node);
 
 	return 0;
 }
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index ba46c79..30ab39f 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -30,8 +30,10 @@ struct device_node;
 struct pt_regs;
 
 void __vic_init(void __iomem *base, int parent_irq, int irq_start,
-		u32 vic_sources, u32 resume_sources, struct device_node *node);
-void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
+		u32 vic_sources, u32 resume_sources,
+		bool map_fiqs, struct device_node *node);
+void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources,
+	      u32 resume_sources);
 int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 		      u32 vic_sources, u32 resume_sources);
 
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 11/16] irqchip: vic: Add support for FIQ management
@ 2014-08-18 14:12               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:12 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Hartley Sweeten, Ryan Mallon, Ben Dooks,
	Kukjin Kim, Thomas Gleixner, Jason Cooper

This patch introduces callbacks to route interrupts to or away
from the FIQ signal. It also causes these callbacks to be registered
with the FIQ infrastructure.

This patch enable FIQ support for mach-versatile whilst mach-ep93xx,
mach-netx, mach-s3c64xx and plat-samsung are unmodified (and can therefore
continue to use init_FIQ() as before).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: linux-samsung-soc@vger.kernel.org
---
 arch/arm/mach-versatile/core.c  |  2 +-
 drivers/irqchip/irq-vic.c       | 92 ++++++++++++++++++++++++++++++++---------
 include/linux/irqchip/arm-vic.h |  6 ++-
 3 files changed, 78 insertions(+), 22 deletions(-)

diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 08fb8c8..bad1d30 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -108,7 +108,7 @@ void __init versatile_init_irq(void)
 
 	np = of_find_matching_node_by_address(NULL, vic_of_match,
 					      VERSATILE_VIC_BASE);
-	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np);
+	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np ? false : true, np);
 
 	writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
 
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287..22aa126 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -36,6 +36,9 @@
 
 #include <asm/exception.h>
 #include <asm/irq.h>
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 
 #include "irqchip.h"
 
@@ -261,11 +264,53 @@ static struct irq_domain_ops vic_irqdomain_ops = {
 	.xlate = irq_domain_xlate_onetwocell,
 };
 
+#ifdef CONFIG_FIQ
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
+static void vic_set_fiq(struct irq_data *d, bool enable)
+{
+	void __iomem *base = irq_data_get_irq_chip_data(d);
+	unsigned int irq = d->hwirq;
+	u32 val;
+
+	raw_spin_lock(&irq_controller_lock);
+	val = readl(base + VIC_INT_SELECT);
+	if (enable)
+		val |= 1 << irq;
+	else
+		val &= ~(1 << irq);
+	writel(val, base + VIC_INT_SELECT);
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void vic_enable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, true);
+}
+
+static void vic_disable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, false);
+}
+
+struct fiq_chip vic_fiq = {
+	.fiq_enable = vic_enable_fiq,
+	.fiq_disable = vic_disable_fiq,
+};
+
+static void vic_register_fiq(int irq)
+{
+	fiq_register_mapping(irq, &vic_fiq);
+}
+#else /* CONFIG_FIQ */
+static inline void vic_register_fiq(int irq) {}
+#endif /* CONFIG_FIQ */
+
 /**
  * vic_register() - Register a VIC.
  * @base: The base address of the VIC.
  * @parent_irq: The parent IRQ if cascaded, else 0.
- * @irq: The base IRQ for the VIC.
+ * @irq_start: The base IRQ for the VIC.
  * @valid_sources: bitmask of valid interrupts
  * @resume_sources: bitmask of interrupts allowed for resume sources.
  * @node: The device tree node associated with the VIC.
@@ -277,12 +322,13 @@ static struct irq_domain_ops vic_irqdomain_ops = {
  * This also configures the IRQ domain for the VIC.
  */
 static void __init vic_register(void __iomem *base, unsigned int parent_irq,
-				unsigned int irq,
+				unsigned int irq_start,
 				u32 valid_sources, u32 resume_sources,
-				struct device_node *node)
+				bool map_fiqs, struct device_node *node)
 {
 	struct vic_device *v;
 	int i;
+	unsigned int irq;
 
 	if (vic_id >= ARRAY_SIZE(vic_devices)) {
 		printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
@@ -301,15 +347,19 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 		irq_set_chained_handler(parent_irq, vic_handle_irq_cascaded);
 	}
 
-	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq,
+	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq_start,
 					  &vic_irqdomain_ops, v);
 	/* create an IRQ mapping for each valid IRQ */
-	for (i = 0; i < fls(valid_sources); i++)
-		if (valid_sources & (1 << i))
-			irq_create_mapping(v->domain, i);
+	for (i = 0; i < fls(valid_sources); i++) {
+		if (valid_sources & (1 << i)) {
+			irq = irq_create_mapping(v->domain, i);
+			vic_register_fiq(irq);
+		}
+	}
+
 	/* If no base IRQ was passed, figure out our allocated base */
-	if (irq)
-		v->irq = irq;
+	if (irq_start)
+		v->irq = irq_start;
 	else
 		v->irq = irq_find_mapping(v->domain, 0);
 }
@@ -413,7 +463,8 @@ static void __init vic_clear_interrupts(void __iomem *base)
  *  and 020 within the page. We call this "second block".
  */
 static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
-			       u32 vic_sources, struct device_node *node)
+			       u32 vic_sources, bool map_fiqs,
+			       struct device_node *node)
 {
 	unsigned int i;
 	int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
@@ -439,12 +490,12 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
 		writel(32, base + VIC_PL190_DEF_VECT_ADDR);
 	}
 
-	vic_register(base, 0, irq_start, vic_sources, 0, node);
+	vic_register(base, 0, irq_start, vic_sources, 0, map_fiqs, node);
 }
 
 void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
-			      u32 vic_sources, u32 resume_sources,
-			      struct device_node *node)
+		       u32 vic_sources, u32 resume_sources,
+		       bool map_fiqs, struct device_node *node)
 {
 	unsigned int i;
 	u32 cellid = 0;
@@ -462,7 +513,7 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	switch(vendor) {
 	case AMBA_VENDOR_ST:
-		vic_init_st(base, irq_start, vic_sources, node);
+		vic_init_st(base, irq_start, vic_sources, map_fiqs, node);
 		return;
 	default:
 		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
@@ -479,7 +530,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	vic_init2(base);
 
-	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);
+	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources,
+		     map_fiqs, node);
 }
 
 /**
@@ -492,7 +544,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 void __init vic_init(void __iomem *base, unsigned int irq_start,
 		     u32 vic_sources, u32 resume_sources)
 {
-	__vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL);
+	__vic_init(base, 0, irq_start, vic_sources, resume_sources,
+		   false, NULL);
 }
 
 /**
@@ -511,7 +564,8 @@ int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 	struct vic_device *v;
 
 	v = &vic_devices[vic_id];
-	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL);
+	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, false,
+		   NULL);
 	/* Return out acquired base */
 	return v->irq;
 }
@@ -535,9 +589,9 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
 	of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask);
 
 	/*
-	 * Passing 0 as first IRQ makes the simple domain allocate descriptors
+	 * Passing 0 as first IRQ makes the domain allocate descriptors.
 	 */
-	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
+	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, true, node);
 
 	return 0;
 }
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index ba46c79..30ab39f 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -30,8 +30,10 @@ struct device_node;
 struct pt_regs;
 
 void __vic_init(void __iomem *base, int parent_irq, int irq_start,
-		u32 vic_sources, u32 resume_sources, struct device_node *node);
-void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
+		u32 vic_sources, u32 resume_sources,
+		bool map_fiqs, struct device_node *node);
+void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources,
+	      u32 resume_sources);
 int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 		      u32 vic_sources, u32 resume_sources);
 
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 11/16] irqchip: vic: Add support for FIQ management
@ 2014-08-18 14:12               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:12 UTC (permalink / raw)
  To: linux-arm-kernel

This patch introduces callbacks to route interrupts to or away
from the FIQ signal. It also causes these callbacks to be registered
with the FIQ infrastructure.

This patch enable FIQ support for mach-versatile whilst mach-ep93xx,
mach-netx, mach-s3c64xx and plat-samsung are unmodified (and can therefore
continue to use init_FIQ() as before).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: linux-samsung-soc at vger.kernel.org
---
 arch/arm/mach-versatile/core.c  |  2 +-
 drivers/irqchip/irq-vic.c       | 92 ++++++++++++++++++++++++++++++++---------
 include/linux/irqchip/arm-vic.h |  6 ++-
 3 files changed, 78 insertions(+), 22 deletions(-)

diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 08fb8c8..bad1d30 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -108,7 +108,7 @@ void __init versatile_init_irq(void)
 
 	np = of_find_matching_node_by_address(NULL, vic_of_match,
 					      VERSATILE_VIC_BASE);
-	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np);
+	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np ? false : true, np);
 
 	writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
 
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287..22aa126 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -36,6 +36,9 @@
 
 #include <asm/exception.h>
 #include <asm/irq.h>
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 
 #include "irqchip.h"
 
@@ -261,11 +264,53 @@ static struct irq_domain_ops vic_irqdomain_ops = {
 	.xlate = irq_domain_xlate_onetwocell,
 };
 
+#ifdef CONFIG_FIQ
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
+static void vic_set_fiq(struct irq_data *d, bool enable)
+{
+	void __iomem *base = irq_data_get_irq_chip_data(d);
+	unsigned int irq = d->hwirq;
+	u32 val;
+
+	raw_spin_lock(&irq_controller_lock);
+	val = readl(base + VIC_INT_SELECT);
+	if (enable)
+		val |= 1 << irq;
+	else
+		val &= ~(1 << irq);
+	writel(val, base + VIC_INT_SELECT);
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void vic_enable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, true);
+}
+
+static void vic_disable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, false);
+}
+
+struct fiq_chip vic_fiq = {
+	.fiq_enable = vic_enable_fiq,
+	.fiq_disable = vic_disable_fiq,
+};
+
+static void vic_register_fiq(int irq)
+{
+	fiq_register_mapping(irq, &vic_fiq);
+}
+#else /* CONFIG_FIQ */
+static inline void vic_register_fiq(int irq) {}
+#endif /* CONFIG_FIQ */
+
 /**
  * vic_register() - Register a VIC.
  * @base: The base address of the VIC.
  * @parent_irq: The parent IRQ if cascaded, else 0.
- * @irq: The base IRQ for the VIC.
+ * @irq_start: The base IRQ for the VIC.
  * @valid_sources: bitmask of valid interrupts
  * @resume_sources: bitmask of interrupts allowed for resume sources.
  * @node: The device tree node associated with the VIC.
@@ -277,12 +322,13 @@ static struct irq_domain_ops vic_irqdomain_ops = {
  * This also configures the IRQ domain for the VIC.
  */
 static void __init vic_register(void __iomem *base, unsigned int parent_irq,
-				unsigned int irq,
+				unsigned int irq_start,
 				u32 valid_sources, u32 resume_sources,
-				struct device_node *node)
+				bool map_fiqs, struct device_node *node)
 {
 	struct vic_device *v;
 	int i;
+	unsigned int irq;
 
 	if (vic_id >= ARRAY_SIZE(vic_devices)) {
 		printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
@@ -301,15 +347,19 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 		irq_set_chained_handler(parent_irq, vic_handle_irq_cascaded);
 	}
 
-	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq,
+	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq_start,
 					  &vic_irqdomain_ops, v);
 	/* create an IRQ mapping for each valid IRQ */
-	for (i = 0; i < fls(valid_sources); i++)
-		if (valid_sources & (1 << i))
-			irq_create_mapping(v->domain, i);
+	for (i = 0; i < fls(valid_sources); i++) {
+		if (valid_sources & (1 << i)) {
+			irq = irq_create_mapping(v->domain, i);
+			vic_register_fiq(irq);
+		}
+	}
+
 	/* If no base IRQ was passed, figure out our allocated base */
-	if (irq)
-		v->irq = irq;
+	if (irq_start)
+		v->irq = irq_start;
 	else
 		v->irq = irq_find_mapping(v->domain, 0);
 }
@@ -413,7 +463,8 @@ static void __init vic_clear_interrupts(void __iomem *base)
  *  and 020 within the page. We call this "second block".
  */
 static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
-			       u32 vic_sources, struct device_node *node)
+			       u32 vic_sources, bool map_fiqs,
+			       struct device_node *node)
 {
 	unsigned int i;
 	int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
@@ -439,12 +490,12 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
 		writel(32, base + VIC_PL190_DEF_VECT_ADDR);
 	}
 
-	vic_register(base, 0, irq_start, vic_sources, 0, node);
+	vic_register(base, 0, irq_start, vic_sources, 0, map_fiqs, node);
 }
 
 void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
-			      u32 vic_sources, u32 resume_sources,
-			      struct device_node *node)
+		       u32 vic_sources, u32 resume_sources,
+		       bool map_fiqs, struct device_node *node)
 {
 	unsigned int i;
 	u32 cellid = 0;
@@ -462,7 +513,7 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	switch(vendor) {
 	case AMBA_VENDOR_ST:
-		vic_init_st(base, irq_start, vic_sources, node);
+		vic_init_st(base, irq_start, vic_sources, map_fiqs, node);
 		return;
 	default:
 		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
@@ -479,7 +530,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	vic_init2(base);
 
-	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);
+	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources,
+		     map_fiqs, node);
 }
 
 /**
@@ -492,7 +544,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 void __init vic_init(void __iomem *base, unsigned int irq_start,
 		     u32 vic_sources, u32 resume_sources)
 {
-	__vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL);
+	__vic_init(base, 0, irq_start, vic_sources, resume_sources,
+		   false, NULL);
 }
 
 /**
@@ -511,7 +564,8 @@ int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 	struct vic_device *v;
 
 	v = &vic_devices[vic_id];
-	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL);
+	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, false,
+		   NULL);
 	/* Return out acquired base */
 	return v->irq;
 }
@@ -535,9 +589,9 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
 	of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask);
 
 	/*
-	 * Passing 0 as first IRQ makes the simple domain allocate descriptors
+	 * Passing 0 as first IRQ makes the domain allocate descriptors.
 	 */
-	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
+	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, true, node);
 
 	return 0;
 }
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index ba46c79..30ab39f 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -30,8 +30,10 @@ struct device_node;
 struct pt_regs;
 
 void __vic_init(void __iomem *base, int parent_irq, int irq_start,
-		u32 vic_sources, u32 resume_sources, struct device_node *node);
-void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
+		u32 vic_sources, u32 resume_sources,
+		bool map_fiqs, struct device_node *node);
+void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources,
+	      u32 resume_sources);
 int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 		      u32 vic_sources, u32 resume_sources);
 
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 12/16] serial: amba-pl011: Pass FIQ information to KGDB.
  2014-07-10  8:03             ` Daniel Thompson
@ 2014-08-18 14:28               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:28 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Greg Kroah-Hartman, Jiri Slaby, linux-serial

Speculatively register a FIQ resource with KGDB. KGDB will only
accept it if the kgdb/fiq feature is enabled (both with compile time and
runtime switches) and the interrupt controller supports FIQ.

By providing this information to KGDB the serial driver offers
"permission" for KGDB to route the UART interrupt signal from the
drivers own handler to KGDBs FIQ handler (which will eventually use the
UART's polled I/O callbacks to interact with the user). This permission
also implies the amba-pl011 driver has already unmasked RX interrupts
(otherwise the FIQ handler will never trigger).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 94 ++++++++++++++++++++++++-----------------
 1 file changed, 55 insertions(+), 39 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 8572f2a..ec8ddc7 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -58,6 +58,7 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/sizes.h>
 #include <linux/io.h>
+#include <linux/kgdb.h>
 
 #define UART_NR			14
 
@@ -1416,8 +1417,61 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
 	spin_unlock_irqrestore(&uap->port.lock, flags);
 }
 
+static int pl011_hwinit(struct uart_port *port)
+{
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	int retval;
+
+	/* Optionaly enable pins to be muxed in and configured */
+	pinctrl_pm_select_default_state(port->dev);
+
+	/*
+	 * Try to enable the clock producer.
+	 */
+	retval = clk_prepare_enable(uap->clk);
+	if (retval)
+		return retval;
+
+	uap->port.uartclk = clk_get_rate(uap->clk);
+
+	/* Clear pending error and receive interrupts */
+	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
+	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
+
+	/*
+	 * Save interrupts enable mask, and enable RX interrupts in case if
+	 * the interrupt is used for NMI entry.
+	 */
+	uap->im = readw(uap->port.membase + UART011_IMSC);
+	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
+
+	if (dev_get_platdata(uap->port.dev)) {
+		struct amba_pl011_data *plat;
+
+		plat = dev_get_platdata(uap->port.dev);
+		if (plat->init)
+			plat->init();
+	}
+	return 0;
+}
+
 #ifdef CONFIG_CONSOLE_POLL
 
+static int pl011_poll_init(struct uart_port *port)
+{
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	int retval;
+
+	retval = pl011_hwinit(port);
+
+#ifdef CONFIG_KGDB_FIQ
+	if (retval == 0)
+		kgdb_register_fiq(uap->port.irq);
+#endif
+
+	return retval;
+}
+
 static void pl011_quiesce_irqs(struct uart_port *port)
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1471,44 +1525,6 @@ static void pl011_put_poll_char(struct uart_port *port,
 
 #endif /* CONFIG_CONSOLE_POLL */
 
-static int pl011_hwinit(struct uart_port *port)
-{
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
-	int retval;
-
-	/* Optionaly enable pins to be muxed in and configured */
-	pinctrl_pm_select_default_state(port->dev);
-
-	/*
-	 * Try to enable the clock producer.
-	 */
-	retval = clk_prepare_enable(uap->clk);
-	if (retval)
-		return retval;
-
-	uap->port.uartclk = clk_get_rate(uap->clk);
-
-	/* Clear pending error and receive interrupts */
-	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
-	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
-
-	/*
-	 * Save interrupts enable mask, and enable RX interrupts in case if
-	 * the interrupt is used for NMI entry.
-	 */
-	uap->im = readw(uap->port.membase + UART011_IMSC);
-	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
-
-	if (dev_get_platdata(uap->port.dev)) {
-		struct amba_pl011_data *plat;
-
-		plat = dev_get_platdata(uap->port.dev);
-		if (plat->init)
-			plat->init();
-	}
-	return 0;
-}
-
 static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
 {
 	writew(lcr_h, uap->port.membase + uap->lcrh_rx);
@@ -1888,7 +1904,7 @@ static struct uart_ops amba_pl011_pops = {
 	.config_port	= pl011_config_port,
 	.verify_port	= pl011_verify_port,
 #ifdef CONFIG_CONSOLE_POLL
-	.poll_init     = pl011_hwinit,
+	.poll_init     = pl011_poll_init,
 	.poll_get_char = pl011_get_poll_char,
 	.poll_put_char = pl011_put_poll_char,
 #endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 12/16] serial: amba-pl011: Pass FIQ information to KGDB.
@ 2014-08-18 14:28               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

Speculatively register a FIQ resource with KGDB. KGDB will only
accept it if the kgdb/fiq feature is enabled (both with compile time and
runtime switches) and the interrupt controller supports FIQ.

By providing this information to KGDB the serial driver offers
"permission" for KGDB to route the UART interrupt signal from the
drivers own handler to KGDBs FIQ handler (which will eventually use the
UART's polled I/O callbacks to interact with the user). This permission
also implies the amba-pl011 driver has already unmasked RX interrupts
(otherwise the FIQ handler will never trigger).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 94 ++++++++++++++++++++++++-----------------
 1 file changed, 55 insertions(+), 39 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 8572f2a..ec8ddc7 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -58,6 +58,7 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/sizes.h>
 #include <linux/io.h>
+#include <linux/kgdb.h>
 
 #define UART_NR			14
 
@@ -1416,8 +1417,61 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
 	spin_unlock_irqrestore(&uap->port.lock, flags);
 }
 
+static int pl011_hwinit(struct uart_port *port)
+{
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	int retval;
+
+	/* Optionaly enable pins to be muxed in and configured */
+	pinctrl_pm_select_default_state(port->dev);
+
+	/*
+	 * Try to enable the clock producer.
+	 */
+	retval = clk_prepare_enable(uap->clk);
+	if (retval)
+		return retval;
+
+	uap->port.uartclk = clk_get_rate(uap->clk);
+
+	/* Clear pending error and receive interrupts */
+	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
+	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
+
+	/*
+	 * Save interrupts enable mask, and enable RX interrupts in case if
+	 * the interrupt is used for NMI entry.
+	 */
+	uap->im = readw(uap->port.membase + UART011_IMSC);
+	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
+
+	if (dev_get_platdata(uap->port.dev)) {
+		struct amba_pl011_data *plat;
+
+		plat = dev_get_platdata(uap->port.dev);
+		if (plat->init)
+			plat->init();
+	}
+	return 0;
+}
+
 #ifdef CONFIG_CONSOLE_POLL
 
+static int pl011_poll_init(struct uart_port *port)
+{
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	int retval;
+
+	retval = pl011_hwinit(port);
+
+#ifdef CONFIG_KGDB_FIQ
+	if (retval == 0)
+		kgdb_register_fiq(uap->port.irq);
+#endif
+
+	return retval;
+}
+
 static void pl011_quiesce_irqs(struct uart_port *port)
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1471,44 +1525,6 @@ static void pl011_put_poll_char(struct uart_port *port,
 
 #endif /* CONFIG_CONSOLE_POLL */
 
-static int pl011_hwinit(struct uart_port *port)
-{
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
-	int retval;
-
-	/* Optionaly enable pins to be muxed in and configured */
-	pinctrl_pm_select_default_state(port->dev);
-
-	/*
-	 * Try to enable the clock producer.
-	 */
-	retval = clk_prepare_enable(uap->clk);
-	if (retval)
-		return retval;
-
-	uap->port.uartclk = clk_get_rate(uap->clk);
-
-	/* Clear pending error and receive interrupts */
-	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
-	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
-
-	/*
-	 * Save interrupts enable mask, and enable RX interrupts in case if
-	 * the interrupt is used for NMI entry.
-	 */
-	uap->im = readw(uap->port.membase + UART011_IMSC);
-	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
-
-	if (dev_get_platdata(uap->port.dev)) {
-		struct amba_pl011_data *plat;
-
-		plat = dev_get_platdata(uap->port.dev);
-		if (plat->init)
-			plat->init();
-	}
-	return 0;
-}
-
 static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
 {
 	writew(lcr_h, uap->port.membase + uap->lcrh_rx);
@@ -1888,7 +1904,7 @@ static struct uart_ops amba_pl011_pops = {
 	.config_port	= pl011_config_port,
 	.verify_port	= pl011_verify_port,
 #ifdef CONFIG_CONSOLE_POLL
-	.poll_init     = pl011_hwinit,
+	.poll_init     = pl011_poll_init,
 	.poll_get_char = pl011_get_poll_char,
 	.poll_put_char = pl011_put_poll_char,
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 13/16] serial: asc: Add support for KGDB's FIQ/NMI mode
  2014-07-10  8:03             ` Daniel Thompson
  (?)
@ 2014-08-18 14:28               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:28 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Srinivas Kandagatla, Maxime Coquelin,
	Patrice Chotard, Greg Kroah-Hartman, Jiri Slaby, kernel,
	linux-serial

Add a .poll_init() function that enables UART RX and registers the
UART's irq with KGDB. By providing this information to KGDB the serial
driver offers "permission" for KGDB to route the UART interrupt signal
from the drivers own handler to KGDBs FIQ handler (which will eventually
use the UART's polled I/O callbacks to interact with the user).

Note that the RX is not only enabled but also unmasked. This is required
because otherwise the FIQ handler could never trigger. This unmask is
copied from similar code in amba-pl011.c .

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel@stlinux.com
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 8b2d735..2b5eb6e 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -30,6 +30,7 @@
 #include <linux/of_platform.h>
 #include <linux/serial_core.h>
 #include <linux/clk.h>
+#include <linux/kgdb.h>
 
 #define DRIVER_NAME "st-asc"
 #define ASC_SERIAL_NAME "ttyAS"
@@ -607,6 +608,25 @@ asc_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+
+#ifdef CONFIG_KGDB_FIQ
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int asc_poll_init(struct uart_port *port)
+{
+	struct asc_port *ascport = container_of(port, struct asc_port, port);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(ascport->port.irq);
+
+	/* enable RX interrupts in case the interrupt is used for NMI entry. */
+	asc_enable_rx_interrupts(port);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 /*
  * Console polling routines for writing and reading from the uart while
  * in an interrupt or debug context (i.e. kgdb).
@@ -649,6 +669,9 @@ static struct uart_ops asc_uart_ops = {
 	.verify_port	= asc_verify_port,
 	.pm		= asc_pm,
 #ifdef CONFIG_CONSOLE_POLL
+#ifdef CONFIG_KGDB_FIQ
+	.poll_init     = asc_poll_init,
+#endif /* CONFIG_KGDB_FIQ */
 	.poll_get_char = asc_get_poll_char,
 	.poll_put_char = asc_put_poll_char,
 #endif /* CONFIG_CONSOLE_POLL */
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 13/16] serial: asc: Add support for KGDB's FIQ/NMI mode
@ 2014-08-18 14:28               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:28 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Srinivas Kandagatla, Maxime Coquelin,
	Patrice Chotard, Greg Kroah-Hartman, Jiri Slaby, kernel

Add a .poll_init() function that enables UART RX and registers the
UART's irq with KGDB. By providing this information to KGDB the serial
driver offers "permission" for KGDB to route the UART interrupt signal
from the drivers own handler to KGDBs FIQ handler (which will eventually
use the UART's polled I/O callbacks to interact with the user).

Note that the RX is not only enabled but also unmasked. This is required
because otherwise the FIQ handler could never trigger. This unmask is
copied from similar code in amba-pl011.c .

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel@stlinux.com
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 8b2d735..2b5eb6e 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -30,6 +30,7 @@
 #include <linux/of_platform.h>
 #include <linux/serial_core.h>
 #include <linux/clk.h>
+#include <linux/kgdb.h>
 
 #define DRIVER_NAME "st-asc"
 #define ASC_SERIAL_NAME "ttyAS"
@@ -607,6 +608,25 @@ asc_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+
+#ifdef CONFIG_KGDB_FIQ
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int asc_poll_init(struct uart_port *port)
+{
+	struct asc_port *ascport = container_of(port, struct asc_port, port);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(ascport->port.irq);
+
+	/* enable RX interrupts in case the interrupt is used for NMI entry. */
+	asc_enable_rx_interrupts(port);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 /*
  * Console polling routines for writing and reading from the uart while
  * in an interrupt or debug context (i.e. kgdb).
@@ -649,6 +669,9 @@ static struct uart_ops asc_uart_ops = {
 	.verify_port	= asc_verify_port,
 	.pm		= asc_pm,
 #ifdef CONFIG_CONSOLE_POLL
+#ifdef CONFIG_KGDB_FIQ
+	.poll_init     = asc_poll_init,
+#endif /* CONFIG_KGDB_FIQ */
 	.poll_get_char = asc_get_poll_char,
 	.poll_put_char = asc_put_poll_char,
 #endif /* CONFIG_CONSOLE_POLL */
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 13/16] serial: asc: Add support for KGDB's FIQ/NMI mode
@ 2014-08-18 14:28               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

Add a .poll_init() function that enables UART RX and registers the
UART's irq with KGDB. By providing this information to KGDB the serial
driver offers "permission" for KGDB to route the UART interrupt signal
from the drivers own handler to KGDBs FIQ handler (which will eventually
use the UART's polled I/O callbacks to interact with the user).

Note that the RX is not only enabled but also unmasked. This is required
because otherwise the FIQ handler could never trigger. This unmask is
copied from similar code in amba-pl011.c .

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel at stlinux.com
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 8b2d735..2b5eb6e 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -30,6 +30,7 @@
 #include <linux/of_platform.h>
 #include <linux/serial_core.h>
 #include <linux/clk.h>
+#include <linux/kgdb.h>
 
 #define DRIVER_NAME "st-asc"
 #define ASC_SERIAL_NAME "ttyAS"
@@ -607,6 +608,25 @@ asc_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+
+#ifdef CONFIG_KGDB_FIQ
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int asc_poll_init(struct uart_port *port)
+{
+	struct asc_port *ascport = container_of(port, struct asc_port, port);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(ascport->port.irq);
+
+	/* enable RX interrupts in case the interrupt is used for NMI entry. */
+	asc_enable_rx_interrupts(port);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 /*
  * Console polling routines for writing and reading from the uart while
  * in an interrupt or debug context (i.e. kgdb).
@@ -649,6 +669,9 @@ static struct uart_ops asc_uart_ops = {
 	.verify_port	= asc_verify_port,
 	.pm		= asc_pm,
 #ifdef CONFIG_CONSOLE_POLL
+#ifdef CONFIG_KGDB_FIQ
+	.poll_init     = asc_poll_init,
+#endif /* CONFIG_KGDB_FIQ */
 	.poll_get_char = asc_get_poll_char,
 	.poll_put_char = asc_put_poll_char,
 #endif /* CONFIG_CONSOLE_POLL */
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 14/16] serial: asc: Adopt readl_/writel_relaxed()
  2014-07-10  8:03             ` Daniel Thompson
  (?)
@ 2014-08-18 14:28               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:28 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Srinivas Kandagatla, Maxime Coquelin,
	Patrice Chotard, Greg Kroah-Hartman, Jiri Slaby, kernel,
	linux-serial

The architectures where this peripheral exists (ARM and SH) have expensive
implementations of writel(), reliant on spin locks and explicit L2 cache
management. These architectures provide a cheaper writel_relaxed() which
is much better suited to peripherals that do not perform DMA. The
situation with readl()/readl_relaxed()is similar although less acute.

This driver does not use DMA and will be more power efficient and more
robust (due to absense of spin locks during console I/O) if it uses the
relaxed variants.

This change means the driver is no longer portable and therefore no
longer suitable for compile testing.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel@stlinux.com
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/Kconfig  | 2 +-
 drivers/tty/serial/st-asc.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 26cec64..e9b1735 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1527,7 +1527,7 @@ config SERIAL_FSL_LPUART_CONSOLE
 config SERIAL_ST_ASC
 	tristate "ST ASC serial port support"
 	select SERIAL_CORE
-	depends on ARM || COMPILE_TEST
+	depends on ARM
 	help
 	  This driver is for the on-chip Asychronous Serial Controller on
 	  STMicroelectronics STi SoCs.
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 2b5eb6e..df709ee 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -152,12 +152,12 @@ static inline struct asc_port *to_asc_port(struct uart_port *port)
 
 static inline u32 asc_in(struct uart_port *port, u32 offset)
 {
-	return readl(port->membase + offset);
+	return readl_relaxed(port->membase + offset);
 }
 
 static inline void asc_out(struct uart_port *port, u32 offset, u32 value)
 {
-	writel(value, port->membase + offset);
+	writel_relaxed(value, port->membase + offset);
 }
 
 /*
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 14/16] serial: asc: Adopt readl_/writel_relaxed()
@ 2014-08-18 14:28               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:28 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Srinivas Kandagatla, Maxime Coquelin,
	Patrice Chotard, Greg Kroah-Hartman, Jiri Slaby, kernel

The architectures where this peripheral exists (ARM and SH) have expensive
implementations of writel(), reliant on spin locks and explicit L2 cache
management. These architectures provide a cheaper writel_relaxed() which
is much better suited to peripherals that do not perform DMA. The
situation with readl()/readl_relaxed()is similar although less acute.

This driver does not use DMA and will be more power efficient and more
robust (due to absense of spin locks during console I/O) if it uses the
relaxed variants.

This change means the driver is no longer portable and therefore no
longer suitable for compile testing.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel@stlinux.com
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/Kconfig  | 2 +-
 drivers/tty/serial/st-asc.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 26cec64..e9b1735 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1527,7 +1527,7 @@ config SERIAL_FSL_LPUART_CONSOLE
 config SERIAL_ST_ASC
 	tristate "ST ASC serial port support"
 	select SERIAL_CORE
-	depends on ARM || COMPILE_TEST
+	depends on ARM
 	help
 	  This driver is for the on-chip Asychronous Serial Controller on
 	  STMicroelectronics STi SoCs.
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 2b5eb6e..df709ee 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -152,12 +152,12 @@ static inline struct asc_port *to_asc_port(struct uart_port *port)
 
 static inline u32 asc_in(struct uart_port *port, u32 offset)
 {
-	return readl(port->membase + offset);
+	return readl_relaxed(port->membase + offset);
 }
 
 static inline void asc_out(struct uart_port *port, u32 offset, u32 value)
 {
-	writel(value, port->membase + offset);
+	writel_relaxed(value, port->membase + offset);
 }
 
 /*
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 14/16] serial: asc: Adopt readl_/writel_relaxed()
@ 2014-08-18 14:28               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

The architectures where this peripheral exists (ARM and SH) have expensive
implementations of writel(), reliant on spin locks and explicit L2 cache
management. These architectures provide a cheaper writel_relaxed() which
is much better suited to peripherals that do not perform DMA. The
situation with readl()/readl_relaxed()is similar although less acute.

This driver does not use DMA and will be more power efficient and more
robust (due to absense of spin locks during console I/O) if it uses the
relaxed variants.

This change means the driver is no longer portable and therefore no
longer suitable for compile testing.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel at stlinux.com
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/Kconfig  | 2 +-
 drivers/tty/serial/st-asc.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 26cec64..e9b1735 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1527,7 +1527,7 @@ config SERIAL_FSL_LPUART_CONSOLE
 config SERIAL_ST_ASC
 	tristate "ST ASC serial port support"
 	select SERIAL_CORE
-	depends on ARM || COMPILE_TEST
+	depends on ARM
 	help
 	  This driver is for the on-chip Asychronous Serial Controller on
 	  STMicroelectronics STi SoCs.
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 2b5eb6e..df709ee 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -152,12 +152,12 @@ static inline struct asc_port *to_asc_port(struct uart_port *port)
 
 static inline u32 asc_in(struct uart_port *port, u32 offset)
 {
-	return readl(port->membase + offset);
+	return readl_relaxed(port->membase + offset);
 }
 
 static inline void asc_out(struct uart_port *port, u32 offset, u32 value)
 {
-	writel(value, port->membase + offset);
+	writel_relaxed(value, port->membase + offset);
 }
 
 /*
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 15/16] serial: imx: clean up imx_poll_get_char()
  2014-07-10  8:03             ` Daniel Thompson
@ 2014-08-18 14:28               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:28 UTC (permalink / raw)
  To: Russell King
  Cc: Dirk Behme, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Daniel Thompson, Greg Kroah-Hartman, Jiri Slaby,
	linux-serial

From: Dirk Behme <dirk.behme@de.bosch.com>

Looking at the get_poll_char() function of the 8250.c serial driver,
we learn:

* poll_get_char() doesn't have to save/disable/restore the interrupt
  registers. No interrupt handling is needed in this function at all.
  Remove it.

* Don't block in case there is no data available. So instead blocking
  in the do {} while loop, just return with NO_POLL_CHAR, immediately .

Additionally, while the i.MX6 register URXD[7-0] contain the RX_DATA,
the upper bits of this register (URXD[15-10]) might contain some
control flags. To ensure that these are not returned with the data
read, just mask out URXD[7-0].

These changes fix the 'hang' working with kdb:

$ echo ttymxc3 > /sys/module/kgdboc/parameters/kgdboc
$ echo g >/proc/sysrq-trigger
[0]kdb> help
...
<hang>

Signed-off-by: Dirk Behme <dirk.behme@de.bosch.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/imx.c | 29 ++++-------------------------
 1 file changed, 4 insertions(+), 25 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 044e86d..983668a 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -80,6 +80,7 @@
 #define URXD_FRMERR	(1<<12)
 #define URXD_BRK	(1<<11)
 #define URXD_PRERR	(1<<10)
+#define URXD_RX_DATA	(0xFF<<0)
 #define UCR1_ADEN	(1<<15) /* Auto detect interrupt */
 #define UCR1_ADBR	(1<<14) /* Auto detect baud rate */
 #define UCR1_TRDYEN	(1<<13) /* Transmitter ready interrupt enable */
@@ -1506,32 +1507,10 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
 #if defined(CONFIG_CONSOLE_POLL)
 static int imx_poll_get_char(struct uart_port *port)
 {
-	struct imx_port_ucrs old_ucr;
-	unsigned int status;
-	unsigned char c;
-
-	/* save control registers */
-	imx_port_ucrs_save(port, &old_ucr);
-
-	/* disable interrupts */
-	writel(UCR1_UARTEN, port->membase + UCR1);
-	writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
-	       port->membase + UCR2);
-	writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
-	       port->membase + UCR3);
-
-	/* poll */
-	do {
-		status = readl(port->membase + USR2);
-	} while (~status & USR2_RDR);
-
-	/* read */
-	c = readl(port->membase + URXD0);
-
-	/* restore control registers */
-	imx_port_ucrs_restore(port, &old_ucr);
+	if (!(readl(port->membase + USR2) & USR2_RDR))
+		return NO_POLL_CHAR;
 
-	return c;
+	return readl(port->membase + URXD0) & URXD_RX_DATA;
 }
 
 static void imx_poll_put_char(struct uart_port *port, unsigned char c)
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 15/16] serial: imx: clean up imx_poll_get_char()
@ 2014-08-18 14:28               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

From: Dirk Behme <dirk.behme@de.bosch.com>

Looking at the get_poll_char() function of the 8250.c serial driver,
we learn:

* poll_get_char() doesn't have to save/disable/restore the interrupt
  registers. No interrupt handling is needed in this function at all.
  Remove it.

* Don't block in case there is no data available. So instead blocking
  in the do {} while loop, just return with NO_POLL_CHAR, immediately .

Additionally, while the i.MX6 register URXD[7-0] contain the RX_DATA,
the upper bits of this register (URXD[15-10]) might contain some
control flags. To ensure that these are not returned with the data
read, just mask out URXD[7-0].

These changes fix the 'hang' working with kdb:

$ echo ttymxc3 > /sys/module/kgdboc/parameters/kgdboc
$ echo g >/proc/sysrq-trigger
[0]kdb> help
...
<hang>

Signed-off-by: Dirk Behme <dirk.behme@de.bosch.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/imx.c | 29 ++++-------------------------
 1 file changed, 4 insertions(+), 25 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 044e86d..983668a 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -80,6 +80,7 @@
 #define URXD_FRMERR	(1<<12)
 #define URXD_BRK	(1<<11)
 #define URXD_PRERR	(1<<10)
+#define URXD_RX_DATA	(0xFF<<0)
 #define UCR1_ADEN	(1<<15) /* Auto detect interrupt */
 #define UCR1_ADBR	(1<<14) /* Auto detect baud rate */
 #define UCR1_TRDYEN	(1<<13) /* Transmitter ready interrupt enable */
@@ -1506,32 +1507,10 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
 #if defined(CONFIG_CONSOLE_POLL)
 static int imx_poll_get_char(struct uart_port *port)
 {
-	struct imx_port_ucrs old_ucr;
-	unsigned int status;
-	unsigned char c;
-
-	/* save control registers */
-	imx_port_ucrs_save(port, &old_ucr);
-
-	/* disable interrupts */
-	writel(UCR1_UARTEN, port->membase + UCR1);
-	writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
-	       port->membase + UCR2);
-	writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
-	       port->membase + UCR3);
-
-	/* poll */
-	do {
-		status = readl(port->membase + USR2);
-	} while (~status & USR2_RDR);
-
-	/* read */
-	c = readl(port->membase + URXD0);
-
-	/* restore control registers */
-	imx_port_ucrs_restore(port, &old_ucr);
+	if (!(readl(port->membase + USR2) & USR2_RDR))
+		return NO_POLL_CHAR;
 
-	return c;
+	return readl(port->membase + URXD0) & URXD_RX_DATA;
 }
 
 static void imx_poll_put_char(struct uart_port *port, unsigned char c)
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 16/16] serial: imx: Add support for KGDB's FIQ/NMI mode
  2014-07-10  8:03             ` Daniel Thompson
@ 2014-08-18 14:28               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:28 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Greg Kroah-Hartman, Jiri Slaby, linux-serial

This patch makes it possible to use the imx uart with KGDB's FIQ/NMI
mode.

Main changes are:

.poll_init() will, if KGDB+FIQ are enabled, perform deeper hardware
initialization to ensure the serial port is always active (required
otherwise FIQ is not triggered by UART activity). This has an impact on
power usage so it is conservatively enabled.

imx_put_poll_char() has been simplified to remove the code to disable
interrupts. The present code can corrupt register state when re-entered
from FIQ handler.

Both imx_put_poll_char() and imx_get_poll_char() adopt _relaxed()
MMIO functions (which are safe for polled I/O and needed to avoid taking
spin locks).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/imx.c | 71 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 52 insertions(+), 19 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 983668a..a201c61 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -49,6 +49,7 @@
 #include <linux/of_device.h>
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
+#include <linux/kgdb.h>
 
 #include <asm/irq.h>
 #include <linux/platform_data/serial-imx.h>
@@ -1505,44 +1506,73 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #if defined(CONFIG_CONSOLE_POLL)
+
+#if defined(CONFIG_KGDB_FIQ)
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int imx_poll_init(struct uart_port *port)
+{
+	struct imx_port *sport = (struct imx_port *)port;
+	unsigned long flags;
+	unsigned long temp;
+	int retval;
+
+	retval = clk_prepare_enable(sport->clk_ipg);
+	if (retval)
+		return retval;
+	retval = clk_prepare_enable(sport->clk_per);
+	if (retval)
+		clk_disable_unprepare(sport->clk_ipg);
+
+	imx_setup_ufcr(sport, 0);
+
+	spin_lock_irqsave(&sport->port.lock, flags);
+
+	temp = readl(sport->port.membase + UCR1);
+	if (is_imx1_uart(sport))
+		temp |= IMX1_UCR1_UARTCLKEN;
+	temp |= UCR1_UARTEN | UCR1_RRDYEN;
+	temp &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN);
+	writel(temp, sport->port.membase + UCR1);
+
+	temp = readl(sport->port.membase + UCR2);
+	temp |= UCR2_RXEN;
+	writel(temp, sport->port.membase + UCR2);
+
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(sport->port.irq);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 static int imx_poll_get_char(struct uart_port *port)
 {
-	if (!(readl(port->membase + USR2) & USR2_RDR))
+	if (!(readl_relaxed(port->membase + USR2) & USR2_RDR))
 		return NO_POLL_CHAR;
 
-	return readl(port->membase + URXD0) & URXD_RX_DATA;
+	return readl_relaxed(port->membase + URXD0) & URXD_RX_DATA;
 }
 
 static void imx_poll_put_char(struct uart_port *port, unsigned char c)
 {
-	struct imx_port_ucrs old_ucr;
 	unsigned int status;
 
-	/* save control registers */
-	imx_port_ucrs_save(port, &old_ucr);
-
-	/* disable interrupts */
-	writel(UCR1_UARTEN, port->membase + UCR1);
-	writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
-	       port->membase + UCR2);
-	writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
-	       port->membase + UCR3);
-
 	/* drain */
 	do {
-		status = readl(port->membase + USR1);
+		status = readl_relaxed(port->membase + USR1);
 	} while (~status & USR1_TRDY);
 
 	/* write */
-	writel(c, port->membase + URTX0);
+	writel_relaxed(c, port->membase + URTX0);
 
 	/* flush */
 	do {
-		status = readl(port->membase + USR2);
+		status = readl_relaxed(port->membase + USR2);
 	} while (~status & USR2_TXDC);
-
-	/* restore control registers */
-	imx_port_ucrs_restore(port, &old_ucr);
 }
 #endif
 
@@ -1563,6 +1593,9 @@ static struct uart_ops imx_pops = {
 	.config_port	= imx_config_port,
 	.verify_port	= imx_verify_port,
 #if defined(CONFIG_CONSOLE_POLL)
+#if defined(CONFIG_KGDB_FIQ)
+	.poll_init      = imx_poll_init,
+#endif
 	.poll_get_char  = imx_poll_get_char,
 	.poll_put_char  = imx_poll_put_char,
 #endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v9 16/16] serial: imx: Add support for KGDB's FIQ/NMI mode
@ 2014-08-18 14:28               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-18 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

This patch makes it possible to use the imx uart with KGDB's FIQ/NMI
mode.

Main changes are:

.poll_init() will, if KGDB+FIQ are enabled, perform deeper hardware
initialization to ensure the serial port is always active (required
otherwise FIQ is not triggered by UART activity). This has an impact on
power usage so it is conservatively enabled.

imx_put_poll_char() has been simplified to remove the code to disable
interrupts. The present code can corrupt register state when re-entered
from FIQ handler.

Both imx_put_poll_char() and imx_get_poll_char() adopt _relaxed()
MMIO functions (which are safe for polled I/O and needed to avoid taking
spin locks).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/imx.c | 71 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 52 insertions(+), 19 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 983668a..a201c61 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -49,6 +49,7 @@
 #include <linux/of_device.h>
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
+#include <linux/kgdb.h>
 
 #include <asm/irq.h>
 #include <linux/platform_data/serial-imx.h>
@@ -1505,44 +1506,73 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #if defined(CONFIG_CONSOLE_POLL)
+
+#if defined(CONFIG_KGDB_FIQ)
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int imx_poll_init(struct uart_port *port)
+{
+	struct imx_port *sport = (struct imx_port *)port;
+	unsigned long flags;
+	unsigned long temp;
+	int retval;
+
+	retval = clk_prepare_enable(sport->clk_ipg);
+	if (retval)
+		return retval;
+	retval = clk_prepare_enable(sport->clk_per);
+	if (retval)
+		clk_disable_unprepare(sport->clk_ipg);
+
+	imx_setup_ufcr(sport, 0);
+
+	spin_lock_irqsave(&sport->port.lock, flags);
+
+	temp = readl(sport->port.membase + UCR1);
+	if (is_imx1_uart(sport))
+		temp |= IMX1_UCR1_UARTCLKEN;
+	temp |= UCR1_UARTEN | UCR1_RRDYEN;
+	temp &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN);
+	writel(temp, sport->port.membase + UCR1);
+
+	temp = readl(sport->port.membase + UCR2);
+	temp |= UCR2_RXEN;
+	writel(temp, sport->port.membase + UCR2);
+
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(sport->port.irq);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 static int imx_poll_get_char(struct uart_port *port)
 {
-	if (!(readl(port->membase + USR2) & USR2_RDR))
+	if (!(readl_relaxed(port->membase + USR2) & USR2_RDR))
 		return NO_POLL_CHAR;
 
-	return readl(port->membase + URXD0) & URXD_RX_DATA;
+	return readl_relaxed(port->membase + URXD0) & URXD_RX_DATA;
 }
 
 static void imx_poll_put_char(struct uart_port *port, unsigned char c)
 {
-	struct imx_port_ucrs old_ucr;
 	unsigned int status;
 
-	/* save control registers */
-	imx_port_ucrs_save(port, &old_ucr);
-
-	/* disable interrupts */
-	writel(UCR1_UARTEN, port->membase + UCR1);
-	writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
-	       port->membase + UCR2);
-	writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
-	       port->membase + UCR3);
-
 	/* drain */
 	do {
-		status = readl(port->membase + USR1);
+		status = readl_relaxed(port->membase + USR1);
 	} while (~status & USR1_TRDY);
 
 	/* write */
-	writel(c, port->membase + URTX0);
+	writel_relaxed(c, port->membase + URTX0);
 
 	/* flush */
 	do {
-		status = readl(port->membase + USR2);
+		status = readl_relaxed(port->membase + USR2);
 	} while (~status & USR2_TXDC);
-
-	/* restore control registers */
-	imx_port_ucrs_restore(port, &old_ucr);
 }
 #endif
 
@@ -1563,6 +1593,9 @@ static struct uart_ops imx_pops = {
 	.config_port	= imx_config_port,
 	.verify_port	= imx_verify_port,
 #if defined(CONFIG_CONSOLE_POLL)
+#if defined(CONFIG_KGDB_FIQ)
+	.poll_init      = imx_poll_init,
+#endif
 	.poll_get_char  = imx_poll_get_char,
 	.poll_put_char  = imx_poll_put_char,
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* Re: [PATCH v9 16/16] serial: imx: Add support for KGDB's FIQ/NMI mode
  2014-08-18 14:28               ` Daniel Thompson
@ 2014-08-18 17:32                 ` Dirk Behme
  -1 siblings, 0 replies; 535+ messages in thread
From: Dirk Behme @ 2014-08-18 17:32 UTC (permalink / raw)
  To: Daniel Thompson, Russell King
  Cc: linux-kernel, linux-arm-kernel, kgdb-bugreport, patches,
	linaro-kernel, John Stultz, Anton Vorontsov, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Greg Kroah-Hartman, Jiri Slaby, linux-serial

On 18.08.2014 16:28, Daniel Thompson wrote:
> This patch makes it possible to use the imx uart with KGDB's FIQ/NMI
> mode.
>
> Main changes are:
>
> .poll_init() will, if KGDB+FIQ are enabled, perform deeper hardware
> initialization to ensure the serial port is always active (required
> otherwise FIQ is not triggered by UART activity). This has an impact on
> power usage so it is conservatively enabled.
>
> imx_put_poll_char() has been simplified to remove the code to disable
> interrupts. The present code can corrupt register state when re-entered
> from FIQ handler.
>
> Both imx_put_poll_char() and imx_get_poll_char() adopt _relaxed()
> MMIO functions (which are safe for polled I/O and needed to avoid taking
> spin locks).
>
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Jiri Slaby <jslaby@suse.cz>
> Cc: linux-serial@vger.kernel.org

Acked-by: Dirk Behme <dirk.behme@de.bosch.com>

Thanks

Dirk


> ---
>   drivers/tty/serial/imx.c | 71 +++++++++++++++++++++++++++++++++++-------------
>   1 file changed, 52 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
> index 983668a..a201c61 100644
> --- a/drivers/tty/serial/imx.c
> +++ b/drivers/tty/serial/imx.c
> @@ -49,6 +49,7 @@
>   #include <linux/of_device.h>
>   #include <linux/io.h>
>   #include <linux/dma-mapping.h>
> +#include <linux/kgdb.h>
>
>   #include <asm/irq.h>
>   #include <linux/platform_data/serial-imx.h>
> @@ -1505,44 +1506,73 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
>   }
>
>   #if defined(CONFIG_CONSOLE_POLL)
> +
> +#if defined(CONFIG_KGDB_FIQ)
> +/*
> + * Prepare the UART to be used from kgdb's NMI support.
> + */
> +static int imx_poll_init(struct uart_port *port)
> +{
> +	struct imx_port *sport = (struct imx_port *)port;
> +	unsigned long flags;
> +	unsigned long temp;
> +	int retval;
> +
> +	retval = clk_prepare_enable(sport->clk_ipg);
> +	if (retval)
> +		return retval;
> +	retval = clk_prepare_enable(sport->clk_per);
> +	if (retval)
> +		clk_disable_unprepare(sport->clk_ipg);
> +
> +	imx_setup_ufcr(sport, 0);
> +
> +	spin_lock_irqsave(&sport->port.lock, flags);
> +
> +	temp = readl(sport->port.membase + UCR1);
> +	if (is_imx1_uart(sport))
> +		temp |= IMX1_UCR1_UARTCLKEN;
> +	temp |= UCR1_UARTEN | UCR1_RRDYEN;
> +	temp &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN);
> +	writel(temp, sport->port.membase + UCR1);
> +
> +	temp = readl(sport->port.membase + UCR2);
> +	temp |= UCR2_RXEN;
> +	writel(temp, sport->port.membase + UCR2);
> +
> +	spin_unlock_irqrestore(&sport->port.lock, flags);
> +
> +	/* register the FIQ with kgdb */
> +	kgdb_register_fiq(sport->port.irq);
> +
> +	return 0;
> +}
> +#endif /* CONFIG_KGDB_FIQ */
> +
>   static int imx_poll_get_char(struct uart_port *port)
>   {
> -	if (!(readl(port->membase + USR2) & USR2_RDR))
> +	if (!(readl_relaxed(port->membase + USR2) & USR2_RDR))
>   		return NO_POLL_CHAR;
>
> -	return readl(port->membase + URXD0) & URXD_RX_DATA;
> +	return readl_relaxed(port->membase + URXD0) & URXD_RX_DATA;
>   }
>
>   static void imx_poll_put_char(struct uart_port *port, unsigned char c)
>   {
> -	struct imx_port_ucrs old_ucr;
>   	unsigned int status;
>
> -	/* save control registers */
> -	imx_port_ucrs_save(port, &old_ucr);
> -
> -	/* disable interrupts */
> -	writel(UCR1_UARTEN, port->membase + UCR1);
> -	writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
> -	       port->membase + UCR2);
> -	writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
> -	       port->membase + UCR3);
> -
>   	/* drain */
>   	do {
> -		status = readl(port->membase + USR1);
> +		status = readl_relaxed(port->membase + USR1);
>   	} while (~status & USR1_TRDY);
>
>   	/* write */
> -	writel(c, port->membase + URTX0);
> +	writel_relaxed(c, port->membase + URTX0);
>
>   	/* flush */
>   	do {
> -		status = readl(port->membase + USR2);
> +		status = readl_relaxed(port->membase + USR2);
>   	} while (~status & USR2_TXDC);
> -
> -	/* restore control registers */
> -	imx_port_ucrs_restore(port, &old_ucr);
>   }
>   #endif
>
> @@ -1563,6 +1593,9 @@ static struct uart_ops imx_pops = {
>   	.config_port	= imx_config_port,
>   	.verify_port	= imx_verify_port,
>   #if defined(CONFIG_CONSOLE_POLL)
> +#if defined(CONFIG_KGDB_FIQ)
> +	.poll_init      = imx_poll_init,
> +#endif
>   	.poll_get_char  = imx_poll_get_char,
>   	.poll_put_char  = imx_poll_put_char,
>   #endif
>


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v9 16/16] serial: imx: Add support for KGDB's FIQ/NMI mode
@ 2014-08-18 17:32                 ` Dirk Behme
  0 siblings, 0 replies; 535+ messages in thread
From: Dirk Behme @ 2014-08-18 17:32 UTC (permalink / raw)
  To: linux-arm-kernel

On 18.08.2014 16:28, Daniel Thompson wrote:
> This patch makes it possible to use the imx uart with KGDB's FIQ/NMI
> mode.
>
> Main changes are:
>
> .poll_init() will, if KGDB+FIQ are enabled, perform deeper hardware
> initialization to ensure the serial port is always active (required
> otherwise FIQ is not triggered by UART activity). This has an impact on
> power usage so it is conservatively enabled.
>
> imx_put_poll_char() has been simplified to remove the code to disable
> interrupts. The present code can corrupt register state when re-entered
> from FIQ handler.
>
> Both imx_put_poll_char() and imx_get_poll_char() adopt _relaxed()
> MMIO functions (which are safe for polled I/O and needed to avoid taking
> spin locks).
>
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Jiri Slaby <jslaby@suse.cz>
> Cc: linux-serial at vger.kernel.org

Acked-by: Dirk Behme <dirk.behme@de.bosch.com>

Thanks

Dirk


> ---
>   drivers/tty/serial/imx.c | 71 +++++++++++++++++++++++++++++++++++-------------
>   1 file changed, 52 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
> index 983668a..a201c61 100644
> --- a/drivers/tty/serial/imx.c
> +++ b/drivers/tty/serial/imx.c
> @@ -49,6 +49,7 @@
>   #include <linux/of_device.h>
>   #include <linux/io.h>
>   #include <linux/dma-mapping.h>
> +#include <linux/kgdb.h>
>
>   #include <asm/irq.h>
>   #include <linux/platform_data/serial-imx.h>
> @@ -1505,44 +1506,73 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
>   }
>
>   #if defined(CONFIG_CONSOLE_POLL)
> +
> +#if defined(CONFIG_KGDB_FIQ)
> +/*
> + * Prepare the UART to be used from kgdb's NMI support.
> + */
> +static int imx_poll_init(struct uart_port *port)
> +{
> +	struct imx_port *sport = (struct imx_port *)port;
> +	unsigned long flags;
> +	unsigned long temp;
> +	int retval;
> +
> +	retval = clk_prepare_enable(sport->clk_ipg);
> +	if (retval)
> +		return retval;
> +	retval = clk_prepare_enable(sport->clk_per);
> +	if (retval)
> +		clk_disable_unprepare(sport->clk_ipg);
> +
> +	imx_setup_ufcr(sport, 0);
> +
> +	spin_lock_irqsave(&sport->port.lock, flags);
> +
> +	temp = readl(sport->port.membase + UCR1);
> +	if (is_imx1_uart(sport))
> +		temp |= IMX1_UCR1_UARTCLKEN;
> +	temp |= UCR1_UARTEN | UCR1_RRDYEN;
> +	temp &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN);
> +	writel(temp, sport->port.membase + UCR1);
> +
> +	temp = readl(sport->port.membase + UCR2);
> +	temp |= UCR2_RXEN;
> +	writel(temp, sport->port.membase + UCR2);
> +
> +	spin_unlock_irqrestore(&sport->port.lock, flags);
> +
> +	/* register the FIQ with kgdb */
> +	kgdb_register_fiq(sport->port.irq);
> +
> +	return 0;
> +}
> +#endif /* CONFIG_KGDB_FIQ */
> +
>   static int imx_poll_get_char(struct uart_port *port)
>   {
> -	if (!(readl(port->membase + USR2) & USR2_RDR))
> +	if (!(readl_relaxed(port->membase + USR2) & USR2_RDR))
>   		return NO_POLL_CHAR;
>
> -	return readl(port->membase + URXD0) & URXD_RX_DATA;
> +	return readl_relaxed(port->membase + URXD0) & URXD_RX_DATA;
>   }
>
>   static void imx_poll_put_char(struct uart_port *port, unsigned char c)
>   {
> -	struct imx_port_ucrs old_ucr;
>   	unsigned int status;
>
> -	/* save control registers */
> -	imx_port_ucrs_save(port, &old_ucr);
> -
> -	/* disable interrupts */
> -	writel(UCR1_UARTEN, port->membase + UCR1);
> -	writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
> -	       port->membase + UCR2);
> -	writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
> -	       port->membase + UCR3);
> -
>   	/* drain */
>   	do {
> -		status = readl(port->membase + USR1);
> +		status = readl_relaxed(port->membase + USR1);
>   	} while (~status & USR1_TRDY);
>
>   	/* write */
> -	writel(c, port->membase + URTX0);
> +	writel_relaxed(c, port->membase + URTX0);
>
>   	/* flush */
>   	do {
> -		status = readl(port->membase + USR2);
> +		status = readl_relaxed(port->membase + USR2);
>   	} while (~status & USR2_TXDC);
> -
> -	/* restore control registers */
> -	imx_port_ucrs_restore(port, &old_ucr);
>   }
>   #endif
>
> @@ -1563,6 +1593,9 @@ static struct uart_ops imx_pops = {
>   	.config_port	= imx_config_port,
>   	.verify_port	= imx_verify_port,
>   #if defined(CONFIG_CONSOLE_POLL)
> +#if defined(CONFIG_KGDB_FIQ)
> +	.poll_init      = imx_poll_init,
> +#endif
>   	.poll_get_char  = imx_poll_get_char,
>   	.poll_put_char  = imx_poll_put_char,
>   #endif
>

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v9 12/16] serial: amba-pl011: Pass FIQ information to KGDB.
  2014-08-18 14:28               ` Daniel Thompson
@ 2014-08-18 18:30                 ` Peter Hurley
  -1 siblings, 0 replies; 535+ messages in thread
From: Peter Hurley @ 2014-08-18 18:30 UTC (permalink / raw)
  To: Daniel Thompson, Russell King
  Cc: linux-kernel, linux-arm-kernel, kgdb-bugreport, patches,
	linaro-kernel, John Stultz, Anton Vorontsov, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Greg Kroah-Hartman, Jiri Slaby, linux-serial

Hi Daniel,

On 08/18/2014 10:28 AM, Daniel Thompson wrote:
> Speculatively register a FIQ resource with KGDB. KGDB will only
> accept it if the kgdb/fiq feature is enabled (both with compile time and
> runtime switches) and the interrupt controller supports FIQ.
> 
> By providing this information to KGDB the serial driver offers
> "permission" for KGDB to route the UART interrupt signal from the
> drivers own handler to KGDBs FIQ handler (which will eventually use the
> UART's polled I/O callbacks to interact with the user). This permission
> also implies the amba-pl011 driver has already unmasked RX interrupts
> (otherwise the FIQ handler will never trigger).
> 
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Jiri Slaby <jslaby@suse.cz>
> Cc: linux-serial@vger.kernel.org
> ---
>  drivers/tty/serial/amba-pl011.c | 94 ++++++++++++++++++++++++-----------------
>  1 file changed, 55 insertions(+), 39 deletions(-)
> 
> diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
> index 8572f2a..ec8ddc7 100644
> --- a/drivers/tty/serial/amba-pl011.c
> +++ b/drivers/tty/serial/amba-pl011.c
> @@ -58,6 +58,7 @@
>  #include <linux/pinctrl/consumer.h>
>  #include <linux/sizes.h>
>  #include <linux/io.h>
> +#include <linux/kgdb.h>
>  
>  #define UART_NR			14
>  
> @@ -1416,8 +1417,61 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
>  	spin_unlock_irqrestore(&uap->port.lock, flags);
>  }
>  

Is pl011_hwinit() just being relocated in source to avoid the forward
declaration? If so, this is usually split into its own commit.

> +static int pl011_hwinit(struct uart_port *port)
> +{
> +	struct uart_amba_port *uap = (struct uart_amba_port *)port;
> +	int retval;
> +
> +	/* Optionaly enable pins to be muxed in and configured */
> +	pinctrl_pm_select_default_state(port->dev);
> +
> +	/*
> +	 * Try to enable the clock producer.
> +	 */
> +	retval = clk_prepare_enable(uap->clk);
> +	if (retval)
> +		return retval;
> +
> +	uap->port.uartclk = clk_get_rate(uap->clk);
> +
> +	/* Clear pending error and receive interrupts */
> +	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
> +	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
> +
> +	/*
> +	 * Save interrupts enable mask, and enable RX interrupts in case if
> +	 * the interrupt is used for NMI entry.
> +	 */
> +	uap->im = readw(uap->port.membase + UART011_IMSC);
> +	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
> +
> +	if (dev_get_platdata(uap->port.dev)) {
> +		struct amba_pl011_data *plat;
> +
> +		plat = dev_get_platdata(uap->port.dev);
> +		if (plat->init)
> +			plat->init();
> +	}
> +	return 0;
> +}
> +
>  #ifdef CONFIG_CONSOLE_POLL
>  
> +static int pl011_poll_init(struct uart_port *port)
> +{
> +	struct uart_amba_port *uap = (struct uart_amba_port *)port;

Please use container_of() in new code.

> +	int retval;
> +
> +	retval = pl011_hwinit(port);
> +
> +#ifdef CONFIG_KGDB_FIQ
> +	if (retval == 0)
> +		kgdb_register_fiq(uap->port.irq);

The uap->port dereference is unnecessary since the port parameter
is the same thing.

		kgdb_register_fiq(port->irq);

Regards,
Peter Hurley

> +#endif
> +
> +	return retval;
> +}
> +
>  static void pl011_quiesce_irqs(struct uart_port *port)
>  {
>  	struct uart_amba_port *uap = (struct uart_amba_port *)port;
> @@ -1471,44 +1525,6 @@ static void pl011_put_poll_char(struct uart_port *port,
>  
>  #endif /* CONFIG_CONSOLE_POLL */
>  
> -static int pl011_hwinit(struct uart_port *port)
> -{
> -	struct uart_amba_port *uap = (struct uart_amba_port *)port;
> -	int retval;
> -
> -	/* Optionaly enable pins to be muxed in and configured */
> -	pinctrl_pm_select_default_state(port->dev);
> -
> -	/*
> -	 * Try to enable the clock producer.
> -	 */
> -	retval = clk_prepare_enable(uap->clk);
> -	if (retval)
> -		return retval;
> -
> -	uap->port.uartclk = clk_get_rate(uap->clk);
> -
> -	/* Clear pending error and receive interrupts */
> -	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
> -	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
> -
> -	/*
> -	 * Save interrupts enable mask, and enable RX interrupts in case if
> -	 * the interrupt is used for NMI entry.
> -	 */
> -	uap->im = readw(uap->port.membase + UART011_IMSC);
> -	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
> -
> -	if (dev_get_platdata(uap->port.dev)) {
> -		struct amba_pl011_data *plat;
> -
> -		plat = dev_get_platdata(uap->port.dev);
> -		if (plat->init)
> -			plat->init();
> -	}
> -	return 0;
> -}
> -
>  static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
>  {
>  	writew(lcr_h, uap->port.membase + uap->lcrh_rx);
> @@ -1888,7 +1904,7 @@ static struct uart_ops amba_pl011_pops = {
>  	.config_port	= pl011_config_port,
>  	.verify_port	= pl011_verify_port,
>  #ifdef CONFIG_CONSOLE_POLL
> -	.poll_init     = pl011_hwinit,
> +	.poll_init     = pl011_poll_init,
>  	.poll_get_char = pl011_get_poll_char,
>  	.poll_put_char = pl011_put_poll_char,
>  #endif
> 


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v9 12/16] serial: amba-pl011: Pass FIQ information to KGDB.
@ 2014-08-18 18:30                 ` Peter Hurley
  0 siblings, 0 replies; 535+ messages in thread
From: Peter Hurley @ 2014-08-18 18:30 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Daniel,

On 08/18/2014 10:28 AM, Daniel Thompson wrote:
> Speculatively register a FIQ resource with KGDB. KGDB will only
> accept it if the kgdb/fiq feature is enabled (both with compile time and
> runtime switches) and the interrupt controller supports FIQ.
> 
> By providing this information to KGDB the serial driver offers
> "permission" for KGDB to route the UART interrupt signal from the
> drivers own handler to KGDBs FIQ handler (which will eventually use the
> UART's polled I/O callbacks to interact with the user). This permission
> also implies the amba-pl011 driver has already unmasked RX interrupts
> (otherwise the FIQ handler will never trigger).
> 
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Jiri Slaby <jslaby@suse.cz>
> Cc: linux-serial at vger.kernel.org
> ---
>  drivers/tty/serial/amba-pl011.c | 94 ++++++++++++++++++++++++-----------------
>  1 file changed, 55 insertions(+), 39 deletions(-)
> 
> diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
> index 8572f2a..ec8ddc7 100644
> --- a/drivers/tty/serial/amba-pl011.c
> +++ b/drivers/tty/serial/amba-pl011.c
> @@ -58,6 +58,7 @@
>  #include <linux/pinctrl/consumer.h>
>  #include <linux/sizes.h>
>  #include <linux/io.h>
> +#include <linux/kgdb.h>
>  
>  #define UART_NR			14
>  
> @@ -1416,8 +1417,61 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
>  	spin_unlock_irqrestore(&uap->port.lock, flags);
>  }
>  

Is pl011_hwinit() just being relocated in source to avoid the forward
declaration? If so, this is usually split into its own commit.

> +static int pl011_hwinit(struct uart_port *port)
> +{
> +	struct uart_amba_port *uap = (struct uart_amba_port *)port;
> +	int retval;
> +
> +	/* Optionaly enable pins to be muxed in and configured */
> +	pinctrl_pm_select_default_state(port->dev);
> +
> +	/*
> +	 * Try to enable the clock producer.
> +	 */
> +	retval = clk_prepare_enable(uap->clk);
> +	if (retval)
> +		return retval;
> +
> +	uap->port.uartclk = clk_get_rate(uap->clk);
> +
> +	/* Clear pending error and receive interrupts */
> +	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
> +	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
> +
> +	/*
> +	 * Save interrupts enable mask, and enable RX interrupts in case if
> +	 * the interrupt is used for NMI entry.
> +	 */
> +	uap->im = readw(uap->port.membase + UART011_IMSC);
> +	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
> +
> +	if (dev_get_platdata(uap->port.dev)) {
> +		struct amba_pl011_data *plat;
> +
> +		plat = dev_get_platdata(uap->port.dev);
> +		if (plat->init)
> +			plat->init();
> +	}
> +	return 0;
> +}
> +
>  #ifdef CONFIG_CONSOLE_POLL
>  
> +static int pl011_poll_init(struct uart_port *port)
> +{
> +	struct uart_amba_port *uap = (struct uart_amba_port *)port;

Please use container_of() in new code.

> +	int retval;
> +
> +	retval = pl011_hwinit(port);
> +
> +#ifdef CONFIG_KGDB_FIQ
> +	if (retval == 0)
> +		kgdb_register_fiq(uap->port.irq);

The uap->port dereference is unnecessary since the port parameter
is the same thing.

		kgdb_register_fiq(port->irq);

Regards,
Peter Hurley

> +#endif
> +
> +	return retval;
> +}
> +
>  static void pl011_quiesce_irqs(struct uart_port *port)
>  {
>  	struct uart_amba_port *uap = (struct uart_amba_port *)port;
> @@ -1471,44 +1525,6 @@ static void pl011_put_poll_char(struct uart_port *port,
>  
>  #endif /* CONFIG_CONSOLE_POLL */
>  
> -static int pl011_hwinit(struct uart_port *port)
> -{
> -	struct uart_amba_port *uap = (struct uart_amba_port *)port;
> -	int retval;
> -
> -	/* Optionaly enable pins to be muxed in and configured */
> -	pinctrl_pm_select_default_state(port->dev);
> -
> -	/*
> -	 * Try to enable the clock producer.
> -	 */
> -	retval = clk_prepare_enable(uap->clk);
> -	if (retval)
> -		return retval;
> -
> -	uap->port.uartclk = clk_get_rate(uap->clk);
> -
> -	/* Clear pending error and receive interrupts */
> -	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
> -	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
> -
> -	/*
> -	 * Save interrupts enable mask, and enable RX interrupts in case if
> -	 * the interrupt is used for NMI entry.
> -	 */
> -	uap->im = readw(uap->port.membase + UART011_IMSC);
> -	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
> -
> -	if (dev_get_platdata(uap->port.dev)) {
> -		struct amba_pl011_data *plat;
> -
> -		plat = dev_get_platdata(uap->port.dev);
> -		if (plat->init)
> -			plat->init();
> -	}
> -	return 0;
> -}
> -
>  static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
>  {
>  	writew(lcr_h, uap->port.membase + uap->lcrh_rx);
> @@ -1888,7 +1904,7 @@ static struct uart_ops amba_pl011_pops = {
>  	.config_port	= pl011_config_port,
>  	.verify_port	= pl011_verify_port,
>  #ifdef CONFIG_CONSOLE_POLL
> -	.poll_init     = pl011_hwinit,
> +	.poll_init     = pl011_poll_init,
>  	.poll_get_char = pl011_get_poll_char,
>  	.poll_put_char = pl011_put_poll_char,
>  #endif
> 

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v9 12/16] serial: amba-pl011: Pass FIQ information to KGDB.
  2014-08-18 18:30                 ` Peter Hurley
@ 2014-08-19  9:08                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19  9:08 UTC (permalink / raw)
  To: Peter Hurley, Russell King
  Cc: linux-kernel, linux-arm-kernel, kgdb-bugreport, patches,
	linaro-kernel, John Stultz, Anton Vorontsov, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Greg Kroah-Hartman, Jiri Slaby, linux-serial

On 18/08/14 19:30, Peter Hurley wrote:
> Hi Daniel,
> 
> On 08/18/2014 10:28 AM, Daniel Thompson wrote:
>> Speculatively register a FIQ resource with KGDB. KGDB will only
>> accept it if the kgdb/fiq feature is enabled (both with compile time and
>> runtime switches) and the interrupt controller supports FIQ.
>>
>> By providing this information to KGDB the serial driver offers
>> "permission" for KGDB to route the UART interrupt signal from the
>> drivers own handler to KGDBs FIQ handler (which will eventually use the
>> UART's polled I/O callbacks to interact with the user). This permission
>> also implies the amba-pl011 driver has already unmasked RX interrupts
>> (otherwise the FIQ handler will never trigger).
>>
>> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
>> Cc: Russell King <linux@arm.linux.org.uk>
>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>> Cc: Jiri Slaby <jslaby@suse.cz>
>> Cc: linux-serial@vger.kernel.org
>> ---
>>  drivers/tty/serial/amba-pl011.c | 94 ++++++++++++++++++++++++-----------------
>>  1 file changed, 55 insertions(+), 39 deletions(-)#

Thanks for the review.


>> diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
>> index 8572f2a..ec8ddc7 100644
>> --- a/drivers/tty/serial/amba-pl011.c
>> +++ b/drivers/tty/serial/amba-pl011.c
>> @@ -58,6 +58,7 @@
>>  #include <linux/pinctrl/consumer.h>
>>  #include <linux/sizes.h>
>>  #include <linux/io.h>
>> +#include <linux/kgdb.h>
>>  
>>  #define UART_NR			14
>>  
>> @@ -1416,8 +1417,61 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
>>  	spin_unlock_irqrestore(&uap->port.lock, flags);
>>  }
>>  
> 
> Is pl011_hwinit() just being relocated in source to avoid the forward
> declaration? If so, this is usually split into its own commit.

Ok. I'll do this.


>> +static int pl011_hwinit(struct uart_port *port)
>> +{
>> +	struct uart_amba_port *uap = (struct uart_amba_port *)port;
>> +	int retval;
>> +
>> +	/* Optionaly enable pins to be muxed in and configured */
>> +	pinctrl_pm_select_default_state(port->dev);
>> +
>> +	/*
>> +	 * Try to enable the clock producer.
>> +	 */
>> +	retval = clk_prepare_enable(uap->clk);
>> +	if (retval)
>> +		return retval;
>> +
>> +	uap->port.uartclk = clk_get_rate(uap->clk);
>> +
>> +	/* Clear pending error and receive interrupts */
>> +	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
>> +	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
>> +
>> +	/*
>> +	 * Save interrupts enable mask, and enable RX interrupts in case if
>> +	 * the interrupt is used for NMI entry.
>> +	 */
>> +	uap->im = readw(uap->port.membase + UART011_IMSC);
>> +	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
>> +
>> +	if (dev_get_platdata(uap->port.dev)) {
>> +		struct amba_pl011_data *plat;
>> +
>> +		plat = dev_get_platdata(uap->port.dev);
>> +		if (plat->init)
>> +			plat->init();
>> +	}
>> +	return 0;
>> +}
>> +
>>  #ifdef CONFIG_CONSOLE_POLL
>>  
>> +static int pl011_poll_init(struct uart_port *port)
>> +{
>> +	struct uart_amba_port *uap = (struct uart_amba_port *)port;
> 
> Please use container_of() in new code.

Ok.

Personally I dislike a file that mixes casts and conatiner_of but I
guess I can make both of us happy by switching the whole driver to
container_of. Separate patch again?


>> +	int retval;
>> +
>> +	retval = pl011_hwinit(port);
>> +
>> +#ifdef CONFIG_KGDB_FIQ
>> +	if (retval == 0)
>> +		kgdb_register_fiq(uap->port.irq);
> 
> The uap->port dereference is unnecessary since the port parameter
> is the same thing.
> 
> 		kgdb_register_fiq(port->irq);

Ok.


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v9 12/16] serial: amba-pl011: Pass FIQ information to KGDB.
@ 2014-08-19  9:08                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19  9:08 UTC (permalink / raw)
  To: linux-arm-kernel

On 18/08/14 19:30, Peter Hurley wrote:
> Hi Daniel,
> 
> On 08/18/2014 10:28 AM, Daniel Thompson wrote:
>> Speculatively register a FIQ resource with KGDB. KGDB will only
>> accept it if the kgdb/fiq feature is enabled (both with compile time and
>> runtime switches) and the interrupt controller supports FIQ.
>>
>> By providing this information to KGDB the serial driver offers
>> "permission" for KGDB to route the UART interrupt signal from the
>> drivers own handler to KGDBs FIQ handler (which will eventually use the
>> UART's polled I/O callbacks to interact with the user). This permission
>> also implies the amba-pl011 driver has already unmasked RX interrupts
>> (otherwise the FIQ handler will never trigger).
>>
>> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
>> Cc: Russell King <linux@arm.linux.org.uk>
>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>> Cc: Jiri Slaby <jslaby@suse.cz>
>> Cc: linux-serial at vger.kernel.org
>> ---
>>  drivers/tty/serial/amba-pl011.c | 94 ++++++++++++++++++++++++-----------------
>>  1 file changed, 55 insertions(+), 39 deletions(-)#

Thanks for the review.


>> diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
>> index 8572f2a..ec8ddc7 100644
>> --- a/drivers/tty/serial/amba-pl011.c
>> +++ b/drivers/tty/serial/amba-pl011.c
>> @@ -58,6 +58,7 @@
>>  #include <linux/pinctrl/consumer.h>
>>  #include <linux/sizes.h>
>>  #include <linux/io.h>
>> +#include <linux/kgdb.h>
>>  
>>  #define UART_NR			14
>>  
>> @@ -1416,8 +1417,61 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
>>  	spin_unlock_irqrestore(&uap->port.lock, flags);
>>  }
>>  
> 
> Is pl011_hwinit() just being relocated in source to avoid the forward
> declaration? If so, this is usually split into its own commit.

Ok. I'll do this.


>> +static int pl011_hwinit(struct uart_port *port)
>> +{
>> +	struct uart_amba_port *uap = (struct uart_amba_port *)port;
>> +	int retval;
>> +
>> +	/* Optionaly enable pins to be muxed in and configured */
>> +	pinctrl_pm_select_default_state(port->dev);
>> +
>> +	/*
>> +	 * Try to enable the clock producer.
>> +	 */
>> +	retval = clk_prepare_enable(uap->clk);
>> +	if (retval)
>> +		return retval;
>> +
>> +	uap->port.uartclk = clk_get_rate(uap->clk);
>> +
>> +	/* Clear pending error and receive interrupts */
>> +	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
>> +	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
>> +
>> +	/*
>> +	 * Save interrupts enable mask, and enable RX interrupts in case if
>> +	 * the interrupt is used for NMI entry.
>> +	 */
>> +	uap->im = readw(uap->port.membase + UART011_IMSC);
>> +	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
>> +
>> +	if (dev_get_platdata(uap->port.dev)) {
>> +		struct amba_pl011_data *plat;
>> +
>> +		plat = dev_get_platdata(uap->port.dev);
>> +		if (plat->init)
>> +			plat->init();
>> +	}
>> +	return 0;
>> +}
>> +
>>  #ifdef CONFIG_CONSOLE_POLL
>>  
>> +static int pl011_poll_init(struct uart_port *port)
>> +{
>> +	struct uart_amba_port *uap = (struct uart_amba_port *)port;
> 
> Please use container_of() in new code.

Ok.

Personally I dislike a file that mixes casts and conatiner_of but I
guess I can make both of us happy by switching the whole driver to
container_of. Separate patch again?


>> +	int retval;
>> +
>> +	retval = pl011_hwinit(port);
>> +
>> +#ifdef CONFIG_KGDB_FIQ
>> +	if (retval == 0)
>> +		kgdb_register_fiq(uap->port.irq);
> 
> The uap->port dereference is unnecessary since the port parameter
> is the same thing.
> 
> 		kgdb_register_fiq(port->irq);

Ok.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v9 12/16] serial: amba-pl011: Pass FIQ information to KGDB.
  2014-08-19  9:08                   ` Daniel Thompson
@ 2014-08-19 11:58                     ` Peter Hurley
  -1 siblings, 0 replies; 535+ messages in thread
From: Peter Hurley @ 2014-08-19 11:58 UTC (permalink / raw)
  To: Daniel Thompson, Russell King
  Cc: linux-kernel, linux-arm-kernel, kgdb-bugreport, patches,
	linaro-kernel, John Stultz, Anton Vorontsov, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Greg Kroah-Hartman, Jiri Slaby, linux-serial

On 08/19/2014 05:08 AM, Daniel Thompson wrote:
> On 18/08/14 19:30, Peter Hurley wrote:

[cut]
  
>>> +static int pl011_poll_init(struct uart_port *port)
>>> +{
>>> +	struct uart_amba_port *uap = (struct uart_amba_port *)port;
>>
>> Please use container_of() in new code.
> 
> Ok.
> 
> Personally I dislike a file that mixes casts and conatiner_of but I
> guess I can make both of us happy by switching the whole driver to
> container_of. Separate patch again?

The change below makes the uap local unnecessary, so you can skip the
container_of() change, if you'd prefer.

>>> +	int retval;
>>> +
>>> +	retval = pl011_hwinit(port);
>>> +
>>> +#ifdef CONFIG_KGDB_FIQ
>>> +	if (retval == 0)
>>> +		kgdb_register_fiq(uap->port.irq);
>>
>> The uap->port dereference is unnecessary since the port parameter
>> is the same thing.
>>
>> 		kgdb_register_fiq(port->irq);
> 
> Ok.

Thanks,
Peter Hurley

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v9 12/16] serial: amba-pl011: Pass FIQ information to KGDB.
@ 2014-08-19 11:58                     ` Peter Hurley
  0 siblings, 0 replies; 535+ messages in thread
From: Peter Hurley @ 2014-08-19 11:58 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/19/2014 05:08 AM, Daniel Thompson wrote:
> On 18/08/14 19:30, Peter Hurley wrote:

[cut]
  
>>> +static int pl011_poll_init(struct uart_port *port)
>>> +{
>>> +	struct uart_amba_port *uap = (struct uart_amba_port *)port;
>>
>> Please use container_of() in new code.
> 
> Ok.
> 
> Personally I dislike a file that mixes casts and conatiner_of but I
> guess I can make both of us happy by switching the whole driver to
> container_of. Separate patch again?

The change below makes the uap local unnecessary, so you can skip the
container_of() change, if you'd prefer.

>>> +	int retval;
>>> +
>>> +	retval = pl011_hwinit(port);
>>> +
>>> +#ifdef CONFIG_KGDB_FIQ
>>> +	if (retval == 0)
>>> +		kgdb_register_fiq(uap->port.irq);
>>
>> The uap->port dereference is unnecessary since the port parameter
>> is the same thing.
>>
>> 		kgdb_register_fiq(port->irq);
> 
> Ok.

Thanks,
Peter Hurley

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v9 12/16] serial: amba-pl011: Pass FIQ information to KGDB.
  2014-08-19 11:58                     ` Peter Hurley
@ 2014-08-19 12:51                       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 12:51 UTC (permalink / raw)
  To: Peter Hurley, Russell King
  Cc: linux-kernel, linux-arm-kernel, kgdb-bugreport, patches,
	linaro-kernel, John Stultz, Anton Vorontsov, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Greg Kroah-Hartman, Jiri Slaby, linux-serial

On 19/08/14 12:58, Peter Hurley wrote:
> On 08/19/2014 05:08 AM, Daniel Thompson wrote:
>> On 18/08/14 19:30, Peter Hurley wrote:
> 
> [cut]
>   
>>>> +static int pl011_poll_init(struct uart_port *port)
>>>> +{
>>>> +	struct uart_amba_port *uap = (struct uart_amba_port *)port;
>>>
>>> Please use container_of() in new code.
>>
>> Ok.
>>
>> Personally I dislike a file that mixes casts and conatiner_of but I
>> guess I can make both of us happy by switching the whole driver to
>> container_of. Separate patch again?
> 
> The change below makes the uap local unnecessary, so you can skip the
> container_of() change, if you'd prefer.

I realized that myself although not until after I'd replaced all the
casts with container_of()...

So I'll keep the patch for now but can drop it if anyone takes against it.



Thanks

Daniel.




> 
>>>> +	int retval;
>>>> +
>>>> +	retval = pl011_hwinit(port);
>>>> +
>>>> +#ifdef CONFIG_KGDB_FIQ
>>>> +	if (retval == 0)
>>>> +		kgdb_register_fiq(uap->port.irq);
>>>
>>> The uap->port dereference is unnecessary since the port parameter
>>> is the same thing.
>>>
>>> 		kgdb_register_fiq(port->irq);
>>
>> Ok.
> 
> Thanks,
> Peter Hurley
> 


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v9 12/16] serial: amba-pl011: Pass FIQ information to KGDB.
@ 2014-08-19 12:51                       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 12:51 UTC (permalink / raw)
  To: linux-arm-kernel

On 19/08/14 12:58, Peter Hurley wrote:
> On 08/19/2014 05:08 AM, Daniel Thompson wrote:
>> On 18/08/14 19:30, Peter Hurley wrote:
> 
> [cut]
>   
>>>> +static int pl011_poll_init(struct uart_port *port)
>>>> +{
>>>> +	struct uart_amba_port *uap = (struct uart_amba_port *)port;
>>>
>>> Please use container_of() in new code.
>>
>> Ok.
>>
>> Personally I dislike a file that mixes casts and conatiner_of but I
>> guess I can make both of us happy by switching the whole driver to
>> container_of. Separate patch again?
> 
> The change below makes the uap local unnecessary, so you can skip the
> container_of() change, if you'd prefer.

I realized that myself although not until after I'd replaced all the
casts with container_of()...

So I'll keep the patch for now but can drop it if anyone takes against it.



Thanks

Daniel.




> 
>>>> +	int retval;
>>>> +
>>>> +	retval = pl011_hwinit(port);
>>>> +
>>>> +#ifdef CONFIG_KGDB_FIQ
>>>> +	if (retval == 0)
>>>> +		kgdb_register_fiq(uap->port.irq);
>>>
>>> The uap->port dereference is unnecessary since the port parameter
>>> is the same thing.
>>>
>>> 		kgdb_register_fiq(port->irq);
>>
>> Ok.
> 
> Thanks,
> Peter Hurley
> 

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v10 00/19] arm: KGDB NMI/FIQ support
  2014-08-18 13:40               ` Daniel Thompson
@ 2014-08-19 16:45                 ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

This patchset makes it possible to use kgdb's NMI infrastructure on ARM
platforms.

The patches are seperated into three distinct groups:

1. arm specific changes; these provide multi-platform support for FIQ
   (including raising an IPI using FIQ to ensure effective SMP support)
   and extend ARM KGDB support to use the features provided.

2. irqchip changes; updates to the gic and vic drivers to provide
   support for routing certain interrupt sources to FIQ.

3. serial changes; driver support to allow the UART interrupt to be
   routed to FIQ. The already mainlined kgdb NMI infrastructure (mostly
   found in drivers/tty/serial/kgdb_nmi.c) will re-route the kgdb
   console UART's interrupt signal from IRQ to FIQ. Naturally the UART
   will no longer function normally and will instead be managed by kgdb
   using the polled I/O functions. Any character delivered to the UART
   causes the kgdb handler function to be called.

Tested on qemu (versatile), STiH416 (B2020 board) and Freescale i.MX6
quad (wandboard).

Changes since v9:

- Split PL011 code movement into a seperate patch (Peter Hurley)
- Use container_of() to convert pointers to uart_amba_port (Peter
  Hurley)
- Clean up redundant code from pl011_poll_init (Peter Hurley)
- Call do_unexp_fiq() if we receive a FIQ and CONFIG_FIQ is not set.
- Ensure irq-gic.c does not call FIQ functions unless CONFIG_FIQ is set.
- Introduced patch to avoid ttyNMI0 being enabled by default
  (replaces architecture dependant enable/disable logic).
- Fixed bug in kgdb_fiq_enable_nmi() that causes SysRq-g (non-NMI
  debugging) to wedge the debugger.

Changes since v8:

- Significant rework to separate the FIQ exception handler from kgdb.
  This allows other features typically implemented using NMI on x86
  to reuse the same exception handling code (Russell King)
- Reunited arch/arm and driver code into a single patch series again.
- Added support for raising IPIs using FIQ (makes kgdb quiesce must
  more robust).
- Introduced a workaround for GICv1 devices to avoid FIQs being
  spuriously handled as IRQs.

Changes since v7:

- Introduced ack_fiq() to complement eoi_fiq(). Without this it is
  not possible to meet the GIC specification (previous versions worked
  when tested but are unpredictable according to the specification).
  ack_fiq() also makes is possible for drivers for devices with multiple
  interrupt lines to discover the interrupt source correctly.

Changes since v6:

- Corrected off-by-one comparison in has_fiq() (Nicolas Pitre)
- Rewrote the FIQ stack initialization (Nicolas Pitre). This fixes a
  serious data corruption bug due to bad stack mismanagement.
- Introduced __fiq_abt to ensure lr_abt and spsr_abt are saved and
  restored if we fast-interrupt an abort (Russell King).
- Significantly improved the commenting of the exception handlers.
- Added a call to trace_hardirqs_on() if we clear the I bit as we
  exit the exception handler.

Changes since v5:

- Separated anything not strictly impacting arch/arm.
- Fixed a spurious add/remove of code within the series (there was
  broken code in intermediate patches)

For previous changes see:
http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901

Daniel Thompson (18):
  arm: fiq: Add callbacks to manage FIQ routings
  arm: fiq: Allow ACK and EOI to be passed to the intc
  arm: fiq: Replace default FIQ handler
  arm: smp: Introduce a special IPI signalled using FIQ
  arm: KGDB/KDB FIQ support
  irqchip: gic: Provide support for interrupt grouping
  irqchip: gic: Add support for FIQ management
  irqchip: gic: Remove spin locks from eoi_irq
  irqchip: gic: Add support for IPI FIQ
  irqchip: gic: Group 0 workaround.
  irqchip: vic: Add support for FIQ management
  serial: kgdb_nmi: No CON_ENABLED by default
  serial: amba-pl011: Use container_of() to get uart_amba_port
  serial: amba-pl011: Move pl011_hwinit()
  serial: amba-pl011: Pass FIQ information to KGDB.
  serial: asc: Add support for KGDB's FIQ/NMI mode
  serial: asc: Adopt readl_/writel_relaxed()
  serial: imx: Add support for KGDB's FIQ/NMI mode

Dirk Behme (1):
  serial: imx: clean up imx_poll_get_char()

 arch/arm/Kconfig                |   2 +
 arch/arm/Kconfig.debug          |  19 +++
 arch/arm/include/asm/fiq.h      |  18 +++
 arch/arm/include/asm/hardirq.h  |   2 +-
 arch/arm/include/asm/kgdb.h     |   4 +
 arch/arm/include/asm/smp.h      |   7 +
 arch/arm/kernel/entry-armv.S    | 129 +++++++++++++++--
 arch/arm/kernel/fiq.c           | 139 +++++++++++++++++-
 arch/arm/kernel/kgdb.c          | 117 ++++++++++++++-
 arch/arm/kernel/setup.c         |   8 +-
 arch/arm/kernel/smp.c           |  15 ++
 arch/arm/mach-versatile/core.c  |   2 +-
 drivers/irqchip/irq-gic.c       | 309 +++++++++++++++++++++++++++++++++++++---
 drivers/irqchip/irq-vic.c       |  92 +++++++++---
 drivers/tty/serial/Kconfig      |   2 +-
 drivers/tty/serial/amba-pl011.c | 143 +++++++++++--------
 drivers/tty/serial/imx.c        |  88 +++++++-----
 drivers/tty/serial/kgdb_nmi.c   |   5 +-
 drivers/tty/serial/st-asc.c     |  27 +++-
 include/linux/irqchip/arm-vic.h |   6 +-
 20 files changed, 977 insertions(+), 157 deletions(-)

--
1.9.3


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v10 00/19] arm: KGDB NMI/FIQ support
@ 2014-08-19 16:45                 ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset makes it possible to use kgdb's NMI infrastructure on ARM
platforms.

The patches are seperated into three distinct groups:

1. arm specific changes; these provide multi-platform support for FIQ
   (including raising an IPI using FIQ to ensure effective SMP support)
   and extend ARM KGDB support to use the features provided.

2. irqchip changes; updates to the gic and vic drivers to provide
   support for routing certain interrupt sources to FIQ.

3. serial changes; driver support to allow the UART interrupt to be
   routed to FIQ. The already mainlined kgdb NMI infrastructure (mostly
   found in drivers/tty/serial/kgdb_nmi.c) will re-route the kgdb
   console UART's interrupt signal from IRQ to FIQ. Naturally the UART
   will no longer function normally and will instead be managed by kgdb
   using the polled I/O functions. Any character delivered to the UART
   causes the kgdb handler function to be called.

Tested on qemu (versatile), STiH416 (B2020 board) and Freescale i.MX6
quad (wandboard).

Changes since v9:

- Split PL011 code movement into a seperate patch (Peter Hurley)
- Use container_of() to convert pointers to uart_amba_port (Peter
  Hurley)
- Clean up redundant code from pl011_poll_init (Peter Hurley)
- Call do_unexp_fiq() if we receive a FIQ and CONFIG_FIQ is not set.
- Ensure irq-gic.c does not call FIQ functions unless CONFIG_FIQ is set.
- Introduced patch to avoid ttyNMI0 being enabled by default
  (replaces architecture dependant enable/disable logic).
- Fixed bug in kgdb_fiq_enable_nmi() that causes SysRq-g (non-NMI
  debugging) to wedge the debugger.

Changes since v8:

- Significant rework to separate the FIQ exception handler from kgdb.
  This allows other features typically implemented using NMI on x86
  to reuse the same exception handling code (Russell King)
- Reunited arch/arm and driver code into a single patch series again.
- Added support for raising IPIs using FIQ (makes kgdb quiesce must
  more robust).
- Introduced a workaround for GICv1 devices to avoid FIQs being
  spuriously handled as IRQs.

Changes since v7:

- Introduced ack_fiq() to complement eoi_fiq(). Without this it is
  not possible to meet the GIC specification (previous versions worked
  when tested but are unpredictable according to the specification).
  ack_fiq() also makes is possible for drivers for devices with multiple
  interrupt lines to discover the interrupt source correctly.

Changes since v6:

- Corrected off-by-one comparison in has_fiq() (Nicolas Pitre)
- Rewrote the FIQ stack initialization (Nicolas Pitre). This fixes a
  serious data corruption bug due to bad stack mismanagement.
- Introduced __fiq_abt to ensure lr_abt and spsr_abt are saved and
  restored if we fast-interrupt an abort (Russell King).
- Significantly improved the commenting of the exception handlers.
- Added a call to trace_hardirqs_on() if we clear the I bit as we
  exit the exception handler.

Changes since v5:

- Separated anything not strictly impacting arch/arm.
- Fixed a spurious add/remove of code within the series (there was
  broken code in intermediate patches)

For previous changes see:
http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901

Daniel Thompson (18):
  arm: fiq: Add callbacks to manage FIQ routings
  arm: fiq: Allow ACK and EOI to be passed to the intc
  arm: fiq: Replace default FIQ handler
  arm: smp: Introduce a special IPI signalled using FIQ
  arm: KGDB/KDB FIQ support
  irqchip: gic: Provide support for interrupt grouping
  irqchip: gic: Add support for FIQ management
  irqchip: gic: Remove spin locks from eoi_irq
  irqchip: gic: Add support for IPI FIQ
  irqchip: gic: Group 0 workaround.
  irqchip: vic: Add support for FIQ management
  serial: kgdb_nmi: No CON_ENABLED by default
  serial: amba-pl011: Use container_of() to get uart_amba_port
  serial: amba-pl011: Move pl011_hwinit()
  serial: amba-pl011: Pass FIQ information to KGDB.
  serial: asc: Add support for KGDB's FIQ/NMI mode
  serial: asc: Adopt readl_/writel_relaxed()
  serial: imx: Add support for KGDB's FIQ/NMI mode

Dirk Behme (1):
  serial: imx: clean up imx_poll_get_char()

 arch/arm/Kconfig                |   2 +
 arch/arm/Kconfig.debug          |  19 +++
 arch/arm/include/asm/fiq.h      |  18 +++
 arch/arm/include/asm/hardirq.h  |   2 +-
 arch/arm/include/asm/kgdb.h     |   4 +
 arch/arm/include/asm/smp.h      |   7 +
 arch/arm/kernel/entry-armv.S    | 129 +++++++++++++++--
 arch/arm/kernel/fiq.c           | 139 +++++++++++++++++-
 arch/arm/kernel/kgdb.c          | 117 ++++++++++++++-
 arch/arm/kernel/setup.c         |   8 +-
 arch/arm/kernel/smp.c           |  15 ++
 arch/arm/mach-versatile/core.c  |   2 +-
 drivers/irqchip/irq-gic.c       | 309 +++++++++++++++++++++++++++++++++++++---
 drivers/irqchip/irq-vic.c       |  92 +++++++++---
 drivers/tty/serial/Kconfig      |   2 +-
 drivers/tty/serial/amba-pl011.c | 143 +++++++++++--------
 drivers/tty/serial/imx.c        |  88 +++++++-----
 drivers/tty/serial/kgdb_nmi.c   |   5 +-
 drivers/tty/serial/st-asc.c     |  27 +++-
 include/linux/irqchip/arm-vic.h |   6 +-
 20 files changed, 977 insertions(+), 157 deletions(-)

--
1.9.3

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v10 01/19] arm: fiq: Add callbacks to manage FIQ routings
  2014-08-19 16:45                 ` Daniel Thompson
@ 2014-08-19 16:45                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
virq into a FIQ virq. This is too inflexible for multi-platform kernels
and makes runtime error checking impossible.

We solve this by introducing a flexible mapping that allows interrupt
controllers that support FIQ to register those mappings. This, in turn,
makes it much possible for drivers in DT kernels to install FIQ handlers
without knowing anything about the interrupt controller.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h |   8 ++++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..ed44528 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -16,8 +16,14 @@
 #ifndef __ASM_FIQ_H
 #define __ASM_FIQ_H
 
+#include <linux/irq.h>
 #include <asm/ptrace.h>
 
+struct fiq_chip {
+	void (*fiq_enable)(struct irq_data *data);
+	void (*fiq_disable)(struct irq_data *data);
+};
+
 struct fiq_handler {
 	struct fiq_handler *next;
 	/* Name
@@ -38,6 +44,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern bool has_fiq(int fiq);
+extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..5d831cf 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,9 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
+#include <linux/radix-tree.h>
+#include <linux/slab.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -52,7 +55,15 @@
 		(unsigned)&vector_fiq_offset;		\
 	})
 
+struct fiq_data {
+	struct fiq_chip *fiq_chip;
+	struct irq_data *irq_data;
+};
+
 static unsigned long no_fiq_insn;
+static int fiq_start = -1;
+static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
+static DEFINE_MUTEX(fiq_data_mutex);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -127,18 +138,65 @@ void release_fiq(struct fiq_handler *f)
 	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
 }
 
-static int fiq_start;
+static struct fiq_data *lookup_fiq_data(int fiq)
+{
+	struct fiq_data *data;
+
+	rcu_read_lock();
+	data = radix_tree_lookup(&fiq_data_tree, fiq);
+	rcu_read_unlock();
+
+	return data;
+}
 
 void enable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_enable)
+			data->fiq_chip->fiq_enable(data->irq_data);
+		enable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	enable_irq(fiq + fiq_start);
 }
 
 void disable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_disable)
+			data->fiq_chip->fiq_disable(data->irq_data);
+		disable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	disable_irq(fiq + fiq_start);
 }
 
+bool has_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data)
+		return true;
+
+	if (fiq_start == -1)
+		return false;
+
+	return fiq >= fiq_start;
+}
+EXPORT_SYMBOL(has_fiq);
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -147,9 +205,50 @@ EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
 
+/*
+ * Add a mapping from a Linux irq to the fiq data.
+ */
+void fiq_register_mapping(int irq, struct fiq_chip *chip)
+{
+	struct fiq_data *fiq_data = NULL;
+	int res;
+
+	/* fiq_register_mapping can't be mixed with init_FIQ */
+	BUG_ON(fiq_start != -1);
+
+	fiq_data = kmalloc(sizeof(*fiq_data), GFP_KERNEL);
+	if (!fiq_data)
+		goto err;
+
+	fiq_data->fiq_chip = chip;
+	fiq_data->irq_data = irq_get_irq_data(irq);
+	BUG_ON(!fiq_data->irq_data);
+
+	mutex_lock(&fiq_data_mutex);
+	res = radix_tree_insert(&fiq_data_tree, irq, fiq_data);
+	mutex_unlock(&fiq_data_mutex);
+	if (res)
+		goto err;
+
+	return;
+
+err:
+	kfree(fiq_data);
+	pr_err("fiq: Cannot register mapping %d\n", irq);
+}
+
+/*
+ * Set the offset between normal IRQs and their FIQ shadows.
+ */
 void __init init_FIQ(int start)
 {
+	fiq_start = start;
+}
+
+static int __init init_default_fiq_handler(void)
+{
 	unsigned offset = FIQ_OFFSET;
 	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
-	fiq_start = start;
+	return 0;
 }
+pure_initcall(init_default_fiq_handler);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 01/19] arm: fiq: Add callbacks to manage FIQ routings
@ 2014-08-19 16:45                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: linux-arm-kernel

Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
virq into a FIQ virq. This is too inflexible for multi-platform kernels
and makes runtime error checking impossible.

We solve this by introducing a flexible mapping that allows interrupt
controllers that support FIQ to register those mappings. This, in turn,
makes it much possible for drivers in DT kernels to install FIQ handlers
without knowing anything about the interrupt controller.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h |   8 ++++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..ed44528 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -16,8 +16,14 @@
 #ifndef __ASM_FIQ_H
 #define __ASM_FIQ_H
 
+#include <linux/irq.h>
 #include <asm/ptrace.h>
 
+struct fiq_chip {
+	void (*fiq_enable)(struct irq_data *data);
+	void (*fiq_disable)(struct irq_data *data);
+};
+
 struct fiq_handler {
 	struct fiq_handler *next;
 	/* Name
@@ -38,6 +44,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern bool has_fiq(int fiq);
+extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..5d831cf 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,9 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
+#include <linux/radix-tree.h>
+#include <linux/slab.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -52,7 +55,15 @@
 		(unsigned)&vector_fiq_offset;		\
 	})
 
+struct fiq_data {
+	struct fiq_chip *fiq_chip;
+	struct irq_data *irq_data;
+};
+
 static unsigned long no_fiq_insn;
+static int fiq_start = -1;
+static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
+static DEFINE_MUTEX(fiq_data_mutex);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -127,18 +138,65 @@ void release_fiq(struct fiq_handler *f)
 	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
 }
 
-static int fiq_start;
+static struct fiq_data *lookup_fiq_data(int fiq)
+{
+	struct fiq_data *data;
+
+	rcu_read_lock();
+	data = radix_tree_lookup(&fiq_data_tree, fiq);
+	rcu_read_unlock();
+
+	return data;
+}
 
 void enable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_enable)
+			data->fiq_chip->fiq_enable(data->irq_data);
+		enable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	enable_irq(fiq + fiq_start);
 }
 
 void disable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_disable)
+			data->fiq_chip->fiq_disable(data->irq_data);
+		disable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	disable_irq(fiq + fiq_start);
 }
 
+bool has_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data)
+		return true;
+
+	if (fiq_start == -1)
+		return false;
+
+	return fiq >= fiq_start;
+}
+EXPORT_SYMBOL(has_fiq);
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -147,9 +205,50 @@ EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
 
+/*
+ * Add a mapping from a Linux irq to the fiq data.
+ */
+void fiq_register_mapping(int irq, struct fiq_chip *chip)
+{
+	struct fiq_data *fiq_data = NULL;
+	int res;
+
+	/* fiq_register_mapping can't be mixed with init_FIQ */
+	BUG_ON(fiq_start != -1);
+
+	fiq_data = kmalloc(sizeof(*fiq_data), GFP_KERNEL);
+	if (!fiq_data)
+		goto err;
+
+	fiq_data->fiq_chip = chip;
+	fiq_data->irq_data = irq_get_irq_data(irq);
+	BUG_ON(!fiq_data->irq_data);
+
+	mutex_lock(&fiq_data_mutex);
+	res = radix_tree_insert(&fiq_data_tree, irq, fiq_data);
+	mutex_unlock(&fiq_data_mutex);
+	if (res)
+		goto err;
+
+	return;
+
+err:
+	kfree(fiq_data);
+	pr_err("fiq: Cannot register mapping %d\n", irq);
+}
+
+/*
+ * Set the offset between normal IRQs and their FIQ shadows.
+ */
 void __init init_FIQ(int start)
 {
+	fiq_start = start;
+}
+
+static int __init init_default_fiq_handler(void)
+{
 	unsigned offset = FIQ_OFFSET;
 	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
-	fiq_start = start;
+	return 0;
 }
+pure_initcall(init_default_fiq_handler);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 02/19] arm: fiq: Allow ACK and EOI to be passed to the intc
  2014-08-19 16:45                 ` Daniel Thompson
@ 2014-08-19 16:45                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

Modern ARM interrupt controllers require an ACK as interrupts are taken
and an EOI on completion. The FIQ code currently does not provide any
API to perform this.

This patch provides this API, implemented by adding two callbacks to the
fiq_chip structure.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h |  9 +++++++++
 arch/arm/kernel/fiq.c      | 19 +++++++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index ed44528..a25c952 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -22,6 +22,13 @@
 struct fiq_chip {
 	void (*fiq_enable)(struct irq_data *data);
 	void (*fiq_disable)(struct irq_data *data);
+
+	/* .fiq_ack() and .fiq_eoi() will be called from the FIQ
+	 * handler. For this reason they must not use spin locks (or any
+	 * other locks).
+	 */
+	int (*fiq_ack)(struct irq_data *data);
+	void (*fiq_eoi)(struct irq_data *data);
 };
 
 struct fiq_handler {
@@ -44,6 +51,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern int ack_fiq(int fiq);
+extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 5d831cf..3ccaa8c 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -183,6 +183,25 @@ void disable_fiq(int fiq)
 	disable_irq(fiq + fiq_start);
 }
 
+int ack_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_ack)
+		return data->fiq_chip->fiq_ack(data->irq_data);
+
+	return fiq;
+}
+
+void eoi_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_eoi)
+		data->fiq_chip->fiq_eoi(data->irq_data);
+}
+EXPORT_SYMBOL(eoi_fiq);
+
 bool has_fiq(int fiq)
 {
 	struct fiq_data *data = lookup_fiq_data(fiq);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 02/19] arm: fiq: Allow ACK and EOI to be passed to the intc
@ 2014-08-19 16:45                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: linux-arm-kernel

Modern ARM interrupt controllers require an ACK as interrupts are taken
and an EOI on completion. The FIQ code currently does not provide any
API to perform this.

This patch provides this API, implemented by adding two callbacks to the
fiq_chip structure.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h |  9 +++++++++
 arch/arm/kernel/fiq.c      | 19 +++++++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index ed44528..a25c952 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -22,6 +22,13 @@
 struct fiq_chip {
 	void (*fiq_enable)(struct irq_data *data);
 	void (*fiq_disable)(struct irq_data *data);
+
+	/* .fiq_ack() and .fiq_eoi() will be called from the FIQ
+	 * handler. For this reason they must not use spin locks (or any
+	 * other locks).
+	 */
+	int (*fiq_ack)(struct irq_data *data);
+	void (*fiq_eoi)(struct irq_data *data);
 };
 
 struct fiq_handler {
@@ -44,6 +51,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern int ack_fiq(int fiq);
+extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 5d831cf..3ccaa8c 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -183,6 +183,25 @@ void disable_fiq(int fiq)
 	disable_irq(fiq + fiq_start);
 }
 
+int ack_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_ack)
+		return data->fiq_chip->fiq_ack(data->irq_data);
+
+	return fiq;
+}
+
+void eoi_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_eoi)
+		data->fiq_chip->fiq_eoi(data->irq_data);
+}
+EXPORT_SYMBOL(eoi_fiq);
+
 bool has_fiq(int fiq)
 {
 	struct fiq_data *data = lookup_fiq_data(fiq);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
  2014-08-19 16:45                 ` Daniel Thompson
@ 2014-08-19 16:45                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

This patch introduces a new default FIQ handler that is structured in a
similar way to the existing ARM exception handler and result in the FIQ
being handled by C code running on the SVC stack (despite this code run
in the FIQ handler is subject to severe limitations with respect to
locking making normal interaction with the kernel impossible).

This default handler allows concepts that on x86 would be handled using
NMIs to be realized on ARM.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of small fragments
    survive, however without Anton's work to build from this patch would
    not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
---
 arch/arm/include/asm/fiq.h   |   1 +
 arch/arm/kernel/entry-armv.S | 129 +++++++++++++++++++++++++++++++++++++++----
 arch/arm/kernel/fiq.c        |  17 ++++++
 arch/arm/kernel/setup.c      |   8 ++-
 4 files changed, 144 insertions(+), 11 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index a25c952..175bfed 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -54,6 +54,7 @@ extern void disable_fiq(int fiq);
 extern int ack_fiq(int fiq);
 extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
+extern int register_fiq_nmi_notifier(struct notifier_block *nb);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 36276cd..ef64333 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -79,6 +79,15 @@
 #endif
 	.endm
 
+	.macro	fiq_handler
+	ldr	r1, =.LChandle_fiq
+	mov	r0, sp
+	adr	lr, BSYM(9998f)
+	ldr	pc, [r1]
+9998:
+	.endm
+
+
 #ifdef CONFIG_KPROBES
 	.section	.kprobes.text,"ax",%progbits
 #else
@@ -146,7 +155,7 @@ ENDPROC(__und_invalid)
 #define SPFIX(code...)
 #endif
 
-	.macro	svc_entry, stack_hole=0
+	.macro	svc_entry, stack_hole=0, call_trace=1
  UNWIND(.fnstart		)
  UNWIND(.save {r0 - pc}		)
 	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
@@ -183,10 +192,35 @@ ENDPROC(__und_invalid)
 	stmia	r7, {r2 - r6}
 
 #ifdef CONFIG_TRACE_IRQFLAGS
+	.if \call_trace
 	bl	trace_hardirqs_off
+	.endif
 #endif
 	.endm
 
+@
+@ svc_exit_via_fiq - similar to svc_exit but switches to FIQ mode before exit
+@
+@ This macro acts in a similar manner to svc_exit but switches to FIQ
+@ mode to restore the final part of the register state.
+@
+@ We cannot use the normal svc_exit procedure because that would
+@ clobber spsr_svc (FIQ could be delivered during the first few instructions
+@ of vector_swi meaning its contents have not been saved anywhere).
+@
+	.macro  svc_exit_via_fiq, rpsr
+
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+	.endm
+
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -295,6 +329,14 @@ __pabt_svc:
 ENDPROC(__pabt_svc)
 
 	.align	5
+__fiq_svc:
+	svc_entry 0, 0
+	fiq_handler
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+	.align	5
 .LCcralign:
 	.word	cr_alignment
 #ifdef MULTI_DABORT
@@ -303,6 +345,43 @@ ENDPROC(__pabt_svc)
 #endif
 .LCfp:
 	.word	fp_enter
+.LChandle_fiq:
+#ifdef CONFIG_FIQ
+	.word	fiq_nmi_handler
+#else
+	.word	do_unexp_fiq
+#endif
+
+/*
+ * Abort mode handlers
+ */
+
+@
+@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
+@ and reuses the same macros. However in abort mode we must also
+@ save/restore lr_abt and spsr_abt to make nested aborts safe.
+@
+	.align 5
+__fiq_abt:
+	svc_entry 0, 0
+
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	r0, lr		@ Save lr_abt
+	mrs	r1, spsr	@ Save spsr_abt, abort is now safe
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+	push	{r0 - r1}
+
+	fiq_handler
+
+	pop	{r0 - r1}
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	lr, r0		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r1	@ Restore spsr_abt
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
 
 /*
  * User mode handlers
@@ -683,6 +762,17 @@ ENTRY(ret_from_exception)
 ENDPROC(__pabt_usr)
 ENDPROC(ret_from_exception)
 
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+
 /*
  * Register switch for ARMv3 and ARMv4 processors
  * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
@@ -1118,17 +1208,36 @@ vector_addrexcptn:
 	b	vector_addrexcptn
 
 /*=============================================================================
- * Undefined FIQs
+ * FIQ "NMI" handler
  *-----------------------------------------------------------------------------
- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
- * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
- * Basically to switch modes, we *HAVE* to clobber one register...  brain
- * damage alert!  I don't think that we can execute any code in here in any
- * other mode than FIQ...  Ok you can switch to another mode, but you can't
- * get out of that mode without clobbering one register.
+ * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
+ * systems. The runtime environment for NMIs is extremely restrictive
+ * (NMIs can pre-empt critical sections meaning almost all locking is
+ * forbidden) meaning this default FIQ handling must only be used in
+ * circumstances where non-maskability improves robustness, such as
+ * watchdog or debug logic.
+ *
+ * This handler is inappropriate for high performance (fast) interrupt
+ * servicing and can be overridden using set_fiq_handler.
  */
-vector_fiq:
-	subs	pc, lr, #4
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
 
 	.globl	vector_fiq_offset
 	.equ	vector_fiq_offset, vector_fiq
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 3ccaa8c..b2bd1c7 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -46,6 +46,7 @@
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
+#include <asm/exception.h>
 #include <asm/fiq.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
@@ -64,6 +65,7 @@ static unsigned long no_fiq_insn;
 static int fiq_start = -1;
 static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
 static DEFINE_MUTEX(fiq_data_mutex);
+static ATOMIC_NOTIFIER_HEAD(fiq_nmi_chain);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -216,6 +218,21 @@ bool has_fiq(int fiq)
 }
 EXPORT_SYMBOL(has_fiq);
 
+int register_fiq_nmi_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
+}
+
+asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
+{
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	nmi_enter();
+	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
+	nmi_exit();
+	set_irq_regs(old_regs);
+}
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 84db893d..c031063 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -133,6 +133,7 @@ struct stack {
 	u32 irq[3];
 	u32 abt[3];
 	u32 und[3];
+	u32 fiq[3];
 } ____cacheline_aligned;
 
 #ifndef CONFIG_CPU_V7M
@@ -470,7 +471,10 @@ void notrace cpu_init(void)
 	"msr	cpsr_c, %5\n\t"
 	"add	r14, %0, %6\n\t"
 	"mov	sp, r14\n\t"
-	"msr	cpsr_c, %7"
+	"msr	cpsr_c, %7\n\t"
+	"add	r14, %0, %8\n\t"
+	"mov	sp, r14\n\t"
+	"msr	cpsr_c, %9"
 	    :
 	    : "r" (stk),
 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
@@ -479,6 +483,8 @@ void notrace cpu_init(void)
 	      "I" (offsetof(struct stack, abt[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
 	      "I" (offsetof(struct stack, und[0])),
+	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+	      "I" (offsetof(struct stack, fiq[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
 	    : "r14");
 #endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
@ 2014-08-19 16:45                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: linux-arm-kernel

This patch introduces a new default FIQ handler that is structured in a
similar way to the existing ARM exception handler and result in the FIQ
being handled by C code running on the SVC stack (despite this code run
in the FIQ handler is subject to severe limitations with respect to
locking making normal interaction with the kernel impossible).

This default handler allows concepts that on x86 would be handled using
NMIs to be realized on ARM.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of small fragments
    survive, however without Anton's work to build from this patch would
    not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
---
 arch/arm/include/asm/fiq.h   |   1 +
 arch/arm/kernel/entry-armv.S | 129 +++++++++++++++++++++++++++++++++++++++----
 arch/arm/kernel/fiq.c        |  17 ++++++
 arch/arm/kernel/setup.c      |   8 ++-
 4 files changed, 144 insertions(+), 11 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index a25c952..175bfed 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -54,6 +54,7 @@ extern void disable_fiq(int fiq);
 extern int ack_fiq(int fiq);
 extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
+extern int register_fiq_nmi_notifier(struct notifier_block *nb);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 36276cd..ef64333 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -79,6 +79,15 @@
 #endif
 	.endm
 
+	.macro	fiq_handler
+	ldr	r1, =.LChandle_fiq
+	mov	r0, sp
+	adr	lr, BSYM(9998f)
+	ldr	pc, [r1]
+9998:
+	.endm
+
+
 #ifdef CONFIG_KPROBES
 	.section	.kprobes.text,"ax",%progbits
 #else
@@ -146,7 +155,7 @@ ENDPROC(__und_invalid)
 #define SPFIX(code...)
 #endif
 
-	.macro	svc_entry, stack_hole=0
+	.macro	svc_entry, stack_hole=0, call_trace=1
  UNWIND(.fnstart		)
  UNWIND(.save {r0 - pc}		)
 	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
@@ -183,10 +192,35 @@ ENDPROC(__und_invalid)
 	stmia	r7, {r2 - r6}
 
 #ifdef CONFIG_TRACE_IRQFLAGS
+	.if \call_trace
 	bl	trace_hardirqs_off
+	.endif
 #endif
 	.endm
 
+@
+@ svc_exit_via_fiq - similar to svc_exit but switches to FIQ mode before exit
+@
+@ This macro acts in a similar manner to svc_exit but switches to FIQ
+@ mode to restore the final part of the register state.
+@
+@ We cannot use the normal svc_exit procedure because that would
+@ clobber spsr_svc (FIQ could be delivered during the first few instructions
+@ of vector_swi meaning its contents have not been saved anywhere).
+@
+	.macro  svc_exit_via_fiq, rpsr
+
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+	.endm
+
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -295,6 +329,14 @@ __pabt_svc:
 ENDPROC(__pabt_svc)
 
 	.align	5
+__fiq_svc:
+	svc_entry 0, 0
+	fiq_handler
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+	.align	5
 .LCcralign:
 	.word	cr_alignment
 #ifdef MULTI_DABORT
@@ -303,6 +345,43 @@ ENDPROC(__pabt_svc)
 #endif
 .LCfp:
 	.word	fp_enter
+.LChandle_fiq:
+#ifdef CONFIG_FIQ
+	.word	fiq_nmi_handler
+#else
+	.word	do_unexp_fiq
+#endif
+
+/*
+ * Abort mode handlers
+ */
+
+@
+@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
+@ and reuses the same macros. However in abort mode we must also
+@ save/restore lr_abt and spsr_abt to make nested aborts safe.
+@
+	.align 5
+__fiq_abt:
+	svc_entry 0, 0
+
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	r0, lr		@ Save lr_abt
+	mrs	r1, spsr	@ Save spsr_abt, abort is now safe
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+	push	{r0 - r1}
+
+	fiq_handler
+
+	pop	{r0 - r1}
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	lr, r0		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r1	@ Restore spsr_abt
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
 
 /*
  * User mode handlers
@@ -683,6 +762,17 @@ ENTRY(ret_from_exception)
 ENDPROC(__pabt_usr)
 ENDPROC(ret_from_exception)
 
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+
 /*
  * Register switch for ARMv3 and ARMv4 processors
  * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
@@ -1118,17 +1208,36 @@ vector_addrexcptn:
 	b	vector_addrexcptn
 
 /*=============================================================================
- * Undefined FIQs
+ * FIQ "NMI" handler
  *-----------------------------------------------------------------------------
- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
- * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
- * Basically to switch modes, we *HAVE* to clobber one register...  brain
- * damage alert!  I don't think that we can execute any code in here in any
- * other mode than FIQ...  Ok you can switch to another mode, but you can't
- * get out of that mode without clobbering one register.
+ * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
+ * systems. The runtime environment for NMIs is extremely restrictive
+ * (NMIs can pre-empt critical sections meaning almost all locking is
+ * forbidden) meaning this default FIQ handling must only be used in
+ * circumstances where non-maskability improves robustness, such as
+ * watchdog or debug logic.
+ *
+ * This handler is inappropriate for high performance (fast) interrupt
+ * servicing and can be overridden using set_fiq_handler.
  */
-vector_fiq:
-	subs	pc, lr, #4
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
 
 	.globl	vector_fiq_offset
 	.equ	vector_fiq_offset, vector_fiq
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 3ccaa8c..b2bd1c7 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -46,6 +46,7 @@
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
+#include <asm/exception.h>
 #include <asm/fiq.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
@@ -64,6 +65,7 @@ static unsigned long no_fiq_insn;
 static int fiq_start = -1;
 static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
 static DEFINE_MUTEX(fiq_data_mutex);
+static ATOMIC_NOTIFIER_HEAD(fiq_nmi_chain);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -216,6 +218,21 @@ bool has_fiq(int fiq)
 }
 EXPORT_SYMBOL(has_fiq);
 
+int register_fiq_nmi_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
+}
+
+asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
+{
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	nmi_enter();
+	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
+	nmi_exit();
+	set_irq_regs(old_regs);
+}
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 84db893d..c031063 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -133,6 +133,7 @@ struct stack {
 	u32 irq[3];
 	u32 abt[3];
 	u32 und[3];
+	u32 fiq[3];
 } ____cacheline_aligned;
 
 #ifndef CONFIG_CPU_V7M
@@ -470,7 +471,10 @@ void notrace cpu_init(void)
 	"msr	cpsr_c, %5\n\t"
 	"add	r14, %0, %6\n\t"
 	"mov	sp, r14\n\t"
-	"msr	cpsr_c, %7"
+	"msr	cpsr_c, %7\n\t"
+	"add	r14, %0, %8\n\t"
+	"mov	sp, r14\n\t"
+	"msr	cpsr_c, %9"
 	    :
 	    : "r" (stk),
 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
@@ -479,6 +483,8 @@ void notrace cpu_init(void)
 	      "I" (offsetof(struct stack, abt[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
 	      "I" (offsetof(struct stack, und[0])),
+	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+	      "I" (offsetof(struct stack, fiq[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
 	    : "r14");
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 04/19] arm: smp: Introduce a special IPI signalled using FIQ
  2014-08-19 16:45                 ` Daniel Thompson
@ 2014-08-19 16:45                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

Cross CPU signalling based on FIQ is especially useful for kgdb since
it makes stopping all the CPUs during breakpointing more robust (some
of the other architectures already roundup the CPUs using NMIs).

The approach taken provides infrastructure that can be called (or not) by
the driver's FIQ handler depending upon it requirements. In other words
nothing is added here that prevents the driver from accessing "bare metal"
performance.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/hardirq.h |  2 +-
 arch/arm/include/asm/smp.h     |  7 +++++++
 arch/arm/kernel/smp.c          | 15 +++++++++++++++
 3 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
index fe3ea77..5df33e3 100644
--- a/arch/arm/include/asm/hardirq.h
+++ b/arch/arm/include/asm/hardirq.h
@@ -5,7 +5,7 @@
 #include <linux/threads.h>
 #include <asm/irq.h>
 
-#define NR_IPI	8
+#define NR_IPI	9
 
 typedef struct {
 	unsigned int __softirq_pending;
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2ec765c..215c927 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -20,6 +20,9 @@
 
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
+/* bitmap of IPIs that must be signalled using FIQ */
+#define SMP_IPI_FIQ_MASK 0x0100
+
 struct seq_file;
 
 /*
@@ -87,6 +90,10 @@ extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
 
 extern int register_ipi_completion(struct completion *completion, int cpu);
 
+#ifdef CONFIG_FIQ
+extern void send_fiq_ipi_mask(const struct cpumask *);
+#endif
+
 struct smp_operations {
 #ifdef CONFIG_SMP
 	/*
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9388a3d..d386c32 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -72,6 +72,7 @@ enum ipi_msg_type {
 	IPI_CPU_STOP,
 	IPI_IRQ_WORK,
 	IPI_COMPLETION,
+	IPI_FIQ,
 };
 
 static DECLARE_COMPLETION(cpu_running);
@@ -451,6 +452,7 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
 	S(IPI_CPU_STOP, "CPU stop interrupts"),
 	S(IPI_IRQ_WORK, "IRQ work interrupts"),
 	S(IPI_COMPLETION, "completion interrupts"),
+	S(IPI_FIQ, "FIQ interrupts"),
 };
 
 static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
@@ -552,6 +554,13 @@ static void ipi_complete(unsigned int cpu)
 	complete(per_cpu(cpu_completion, cpu));
 }
 
+#ifdef CONFIG_FIQ
+void send_fiq_ipi_mask(const struct cpumask *mask)
+{
+	smp_cross_call(mask, IPI_FIQ);
+}
+#endif
+
 /*
  * Main handler for inter-processor interrupts
  */
@@ -618,6 +627,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		irq_exit();
 		break;
 
+#ifdef CONFIG_FIQ
+	case IPI_FIQ:
+		pr_crit("CPU%u: IPI FIQ delivered via IRQ vector\n", cpu);
+		break;
+#endif
+
 	default:
 		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
 		       cpu, ipinr);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 04/19] arm: smp: Introduce a special IPI signalled using FIQ
@ 2014-08-19 16:45                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: linux-arm-kernel

Cross CPU signalling based on FIQ is especially useful for kgdb since
it makes stopping all the CPUs during breakpointing more robust (some
of the other architectures already roundup the CPUs using NMIs).

The approach taken provides infrastructure that can be called (or not) by
the driver's FIQ handler depending upon it requirements. In other words
nothing is added here that prevents the driver from accessing "bare metal"
performance.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/hardirq.h |  2 +-
 arch/arm/include/asm/smp.h     |  7 +++++++
 arch/arm/kernel/smp.c          | 15 +++++++++++++++
 3 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
index fe3ea77..5df33e3 100644
--- a/arch/arm/include/asm/hardirq.h
+++ b/arch/arm/include/asm/hardirq.h
@@ -5,7 +5,7 @@
 #include <linux/threads.h>
 #include <asm/irq.h>
 
-#define NR_IPI	8
+#define NR_IPI	9
 
 typedef struct {
 	unsigned int __softirq_pending;
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2ec765c..215c927 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -20,6 +20,9 @@
 
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
+/* bitmap of IPIs that must be signalled using FIQ */
+#define SMP_IPI_FIQ_MASK 0x0100
+
 struct seq_file;
 
 /*
@@ -87,6 +90,10 @@ extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
 
 extern int register_ipi_completion(struct completion *completion, int cpu);
 
+#ifdef CONFIG_FIQ
+extern void send_fiq_ipi_mask(const struct cpumask *);
+#endif
+
 struct smp_operations {
 #ifdef CONFIG_SMP
 	/*
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9388a3d..d386c32 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -72,6 +72,7 @@ enum ipi_msg_type {
 	IPI_CPU_STOP,
 	IPI_IRQ_WORK,
 	IPI_COMPLETION,
+	IPI_FIQ,
 };
 
 static DECLARE_COMPLETION(cpu_running);
@@ -451,6 +452,7 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
 	S(IPI_CPU_STOP, "CPU stop interrupts"),
 	S(IPI_IRQ_WORK, "IRQ work interrupts"),
 	S(IPI_COMPLETION, "completion interrupts"),
+	S(IPI_FIQ, "FIQ interrupts"),
 };
 
 static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
@@ -552,6 +554,13 @@ static void ipi_complete(unsigned int cpu)
 	complete(per_cpu(cpu_completion, cpu));
 }
 
+#ifdef CONFIG_FIQ
+void send_fiq_ipi_mask(const struct cpumask *mask)
+{
+	smp_cross_call(mask, IPI_FIQ);
+}
+#endif
+
 /*
  * Main handler for inter-processor interrupts
  */
@@ -618,6 +627,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		irq_exit();
 		break;
 
+#ifdef CONFIG_FIQ
+	case IPI_FIQ:
+		pr_crit("CPU%u: IPI FIQ delivered via IRQ vector\n", cpu);
+		break;
+#endif
+
 	default:
 		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
 		       cpu, ipinr);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 05/19] arm: KGDB/KDB FIQ support
  2014-08-19 16:45                 ` Daniel Thompson
@ 2014-08-19 16:45                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Omar Sandoval

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of comments and
    other small fragments still survive, however without Anton's work
    to build from this patch would not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben.dooks@codethink.co.uk>
Cc: Omar Sandoval <osandov@osandov.com>
---
 arch/arm/Kconfig            |   2 +
 arch/arm/Kconfig.debug      |  19 +++++++
 arch/arm/include/asm/kgdb.h |   4 ++
 arch/arm/kernel/kgdb.c      | 117 +++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 136 insertions(+), 6 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c49a775..e6380b3 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -305,6 +305,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -352,6 +353,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index b11ad54..df3f0bf 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,25 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be enabled
+	  by setting the console to ttyNMI0 (and choosing the underlying
+	  serial port using kgdboc)
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..6563da0 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,8 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern int kgdb_register_fiq(unsigned int fiq);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
index a74b53c..b77b885 100644
--- a/arch/arm/kernel/kgdb.c
+++ b/arch/arm/kernel/kgdb.c
@@ -12,8 +12,11 @@
 #include <linux/irq.h>
 #include <linux/kdebug.h>
 #include <linux/kgdb.h>
+#include <asm/fiq.h>
 #include <asm/traps.h>
 
+static unsigned int kgdb_fiq;
+
 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
 {
 	{ "r0", 4, offsetof(struct pt_regs, ARM_r0)},
@@ -175,14 +178,26 @@ static struct undef_hook kgdb_compiled_brkpt_hook = {
 
 static void kgdb_call_nmi_hook(void *ignored)
 {
-       kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+	kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
 }
 
 void kgdb_roundup_cpus(unsigned long flags)
 {
-       local_irq_enable();
-       smp_call_function(kgdb_call_nmi_hook, NULL, 0);
-       local_irq_disable();
+#if defined CONFIG_KGDB_FIQ && defined CONFIG_SMP
+	struct cpumask mask;
+
+	if (in_nmi()) {
+		cpumask_copy(&mask, cpu_online_mask);
+		cpumask_clear_cpu(raw_smp_processor_id(), &mask);
+		if (!cpumask_empty(&mask))
+			send_fiq_ipi_mask(&mask);
+		return;
+	}
+#endif
+
+	local_irq_enable();
+	smp_call_function(kgdb_call_nmi_hook, NULL, 0);
+	local_irq_disable();
 }
 
 static int __kgdb_notify(struct die_args *args, unsigned long cmd)
@@ -244,6 +259,43 @@ void kgdb_arch_exit(void)
 	unregister_die_notifier(&kgdb_notifier);
 }
 
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	if (!kgdb_fiq)
+		return;
+
+#ifdef CONFIG_KGDB_FIQ
+	static atomic_t cnt;
+	int ret;
+
+	if (on) {
+		ret = atomic_add_return(1, &cnt);
+		if (ret == 1)
+			enable_fiq(kgdb_fiq);
+
+		/*
+		 * There should be only one instance that calls this function
+		 * in "enable, disable" order. All other users must call
+		 * disable first, then enable. If not, something is wrong.
+		 */
+		if (WARN_ON(ret > 1))
+			return;
+	} else {
+		ret = atomic_add_return(-1, &cnt);
+		if (ret == 0)
+			disable_fiq(kgdb_fiq);
+	}
+#endif
+}
+
+
 /*
  * Register our undef instruction hooks with ARM undef core.
  * We regsiter a hook specifically looking for the KGB break inst
@@ -252,8 +304,61 @@ void kgdb_arch_exit(void)
  */
 struct kgdb_arch arch_kgdb_ops = {
 #ifndef __ARMEB__
-	.gdb_bpt_instr		= {0xfe, 0xde, 0xff, 0xe7}
+	.gdb_bpt_instr		= {0xfe, 0xde, 0xff, 0xe7},
 #else /* ! __ARMEB__ */
-	.gdb_bpt_instr		= {0xe7, 0xff, 0xde, 0xfe}
+	.gdb_bpt_instr		= {0xe7, 0xff, 0xde, 0xfe},
 #endif
+	.enable_nmi		= kgdb_fiq_enable_nmi
 };
+
+#ifdef CONFIG_KGDB_FIQ
+static int kgdb_handle_fiq(struct notifier_block *nb, unsigned long arg,
+			   void *data)
+{
+	struct pt_regs *regs = (void *) arg;
+	int actual;
+
+	if (!kgdb_nmicallback(raw_smp_processor_id(), regs))
+		return NOTIFY_OK;
+
+	actual = ack_fiq(kgdb_fiq);
+	WARN_ON(actual != kgdb_fiq);
+
+	/* there's no harm in doing this regardless of the above WARN_ON() */
+	if (kgdb_nmi_poll_knock())
+		kgdb_handle_exception(1, 0, 0, regs);
+
+	eoi_fiq(actual);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block kgdb_fiq_notifier = {
+	.notifier_call = kgdb_handle_fiq,
+	.priority = 100,
+};
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	static struct fiq_handler kgdb_fiq_desc = { .name = "kgdb", };
+	int err;
+
+	if (!has_fiq(fiq)) {
+		pr_warn(
+		    "%s: Cannot register %u (no FIQ with this number)\n",
+		    __func__, fiq);
+		return -ENODEV;
+	}
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	kgdb_fiq = fiq;
+	register_fiq_nmi_notifier(&kgdb_fiq_notifier);
+
+	return 0;
+}
+#endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 05/19] arm: KGDB/KDB FIQ support
@ 2014-08-19 16:45                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: linux-arm-kernel

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of comments and
    other small fragments still survive, however without Anton's work
    to build from this patch would not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben.dooks@codethink.co.uk>
Cc: Omar Sandoval <osandov@osandov.com>
---
 arch/arm/Kconfig            |   2 +
 arch/arm/Kconfig.debug      |  19 +++++++
 arch/arm/include/asm/kgdb.h |   4 ++
 arch/arm/kernel/kgdb.c      | 117 +++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 136 insertions(+), 6 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c49a775..e6380b3 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -305,6 +305,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -352,6 +353,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index b11ad54..df3f0bf 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,25 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be enabled
+	  by setting the console to ttyNMI0 (and choosing the underlying
+	  serial port using kgdboc)
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..6563da0 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,8 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern int kgdb_register_fiq(unsigned int fiq);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
index a74b53c..b77b885 100644
--- a/arch/arm/kernel/kgdb.c
+++ b/arch/arm/kernel/kgdb.c
@@ -12,8 +12,11 @@
 #include <linux/irq.h>
 #include <linux/kdebug.h>
 #include <linux/kgdb.h>
+#include <asm/fiq.h>
 #include <asm/traps.h>
 
+static unsigned int kgdb_fiq;
+
 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
 {
 	{ "r0", 4, offsetof(struct pt_regs, ARM_r0)},
@@ -175,14 +178,26 @@ static struct undef_hook kgdb_compiled_brkpt_hook = {
 
 static void kgdb_call_nmi_hook(void *ignored)
 {
-       kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+	kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
 }
 
 void kgdb_roundup_cpus(unsigned long flags)
 {
-       local_irq_enable();
-       smp_call_function(kgdb_call_nmi_hook, NULL, 0);
-       local_irq_disable();
+#if defined CONFIG_KGDB_FIQ && defined CONFIG_SMP
+	struct cpumask mask;
+
+	if (in_nmi()) {
+		cpumask_copy(&mask, cpu_online_mask);
+		cpumask_clear_cpu(raw_smp_processor_id(), &mask);
+		if (!cpumask_empty(&mask))
+			send_fiq_ipi_mask(&mask);
+		return;
+	}
+#endif
+
+	local_irq_enable();
+	smp_call_function(kgdb_call_nmi_hook, NULL, 0);
+	local_irq_disable();
 }
 
 static int __kgdb_notify(struct die_args *args, unsigned long cmd)
@@ -244,6 +259,43 @@ void kgdb_arch_exit(void)
 	unregister_die_notifier(&kgdb_notifier);
 }
 
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	if (!kgdb_fiq)
+		return;
+
+#ifdef CONFIG_KGDB_FIQ
+	static atomic_t cnt;
+	int ret;
+
+	if (on) {
+		ret = atomic_add_return(1, &cnt);
+		if (ret == 1)
+			enable_fiq(kgdb_fiq);
+
+		/*
+		 * There should be only one instance that calls this function
+		 * in "enable, disable" order. All other users must call
+		 * disable first, then enable. If not, something is wrong.
+		 */
+		if (WARN_ON(ret > 1))
+			return;
+	} else {
+		ret = atomic_add_return(-1, &cnt);
+		if (ret == 0)
+			disable_fiq(kgdb_fiq);
+	}
+#endif
+}
+
+
 /*
  * Register our undef instruction hooks with ARM undef core.
  * We regsiter a hook specifically looking for the KGB break inst
@@ -252,8 +304,61 @@ void kgdb_arch_exit(void)
  */
 struct kgdb_arch arch_kgdb_ops = {
 #ifndef __ARMEB__
-	.gdb_bpt_instr		= {0xfe, 0xde, 0xff, 0xe7}
+	.gdb_bpt_instr		= {0xfe, 0xde, 0xff, 0xe7},
 #else /* ! __ARMEB__ */
-	.gdb_bpt_instr		= {0xe7, 0xff, 0xde, 0xfe}
+	.gdb_bpt_instr		= {0xe7, 0xff, 0xde, 0xfe},
 #endif
+	.enable_nmi		= kgdb_fiq_enable_nmi
 };
+
+#ifdef CONFIG_KGDB_FIQ
+static int kgdb_handle_fiq(struct notifier_block *nb, unsigned long arg,
+			   void *data)
+{
+	struct pt_regs *regs = (void *) arg;
+	int actual;
+
+	if (!kgdb_nmicallback(raw_smp_processor_id(), regs))
+		return NOTIFY_OK;
+
+	actual = ack_fiq(kgdb_fiq);
+	WARN_ON(actual != kgdb_fiq);
+
+	/* there's no harm in doing this regardless of the above WARN_ON() */
+	if (kgdb_nmi_poll_knock())
+		kgdb_handle_exception(1, 0, 0, regs);
+
+	eoi_fiq(actual);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block kgdb_fiq_notifier = {
+	.notifier_call = kgdb_handle_fiq,
+	.priority = 100,
+};
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	static struct fiq_handler kgdb_fiq_desc = { .name = "kgdb", };
+	int err;
+
+	if (!has_fiq(fiq)) {
+		pr_warn(
+		    "%s: Cannot register %u (no FIQ with this number)\n",
+		    __func__, fiq);
+		return -ENODEV;
+	}
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	kgdb_fiq = fiq;
+	register_fiq_nmi_notifier(&kgdb_fiq_notifier);
+
+	return 0;
+}
+#endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 06/19] irqchip: gic: Provide support for interrupt grouping
  2014-08-19 16:45                 ` Daniel Thompson
@ 2014-08-19 16:45                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Thomas Gleixner, Jason Cooper, Nicolas Pitre,
	Christoffer Dall, Sricharan R, Marc Zyngier

All GIC hardware except GICv1-without-TrustZone support provides a means
to group exceptions into group 0 (which can optionally be signally using
use FIQ) and group 1. The kernel currently provides no means to exploit
this. This patch alters the initialization of the GIC to place all
interrupts into group 1 which is the foundational requirement to meaningfully
use FIQ.

Note that the hardware functionality is unavailable to the kernel when a
secure monitor is present because access to the grouping registers are
prohibited outside "secure world" (this feature allows grouping to be
used to allow hardware peripherals to send interrupts into the secure
world). The GIC driver will automatically detect this and disable its
attempts to group interrupts.

On systems without TrustZone support the kernel has the power to route
interrupt sources to FIQ, potentially allowing a driver to exploit the
NMI-like properties of FIQ.

Tested on Freescale i.MX6 (quad A9), STiH416 (dual A9) and a self-written
qemu GICv2 model.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Dirk Behme <dirk.behme@de.bosch.com>
---
 drivers/irqchip/irq-gic.c | 99 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 94 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4b959e6..423707c 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -41,6 +41,9 @@
 #include <linux/irqchip/arm-gic.h>
 
 #include <asm/cputype.h>
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
@@ -68,6 +71,9 @@ struct gic_chip_data {
 #ifdef CONFIG_GIC_NON_BANKED
 	void __iomem *(*get_base)(union gic_base *);
 #endif
+#ifdef CONFIG_FIQ
+	bool fiq_enable;
+#endif
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
@@ -131,6 +137,16 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data,
 #define gic_set_base_accessor(d, f)
 #endif
 
+#ifdef CONFIG_FIQ
+static inline bool gic_data_fiq_enable(struct gic_chip_data *data)
+{
+	return data->fiq_enable;
+}
+#else
+static inline bool gic_data_fiq_enable(
+		struct gic_chip_data *data) { return false; }
+#endif
+
 static inline void __iomem *gic_dist_base(struct irq_data *d)
 {
 	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
@@ -325,6 +341,42 @@ static struct irq_chip gic_chip = {
 	.irq_set_wake		= gic_set_wake,
 };
 
+#ifdef CONFIG_FIQ
+static void __init gic_init_fiq(struct gic_chip_data *gic,
+				irq_hw_number_t first_irq,
+				unsigned int num_irqs)
+{
+	void __iomem *dist_base = gic_data_dist_base(gic_data);
+	unsigned int i;
+
+	/*
+	 * FIQ can only be supported on platforms without an extended irq_eoi
+	 * method (otherwise we take a lock during eoi handling).
+	 */
+	if (gic_arch_extn.irq_eoi)
+		return;
+
+	/*
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers a read-as-zero/write-ignored.
+	 * However as a precaution we restore the reset default regardless of
+	 * the result of the test.
+	 */
+	writel_relaxed(1, dist_base + GIC_DIST_IGROUP + 0);
+	gic->fiq_enable = readl_relaxed(dist_base + GIC_DIST_IGROUP + 0);
+	writel_relaxed(0, dist_base + GIC_DIST_IGROUP + 0);
+	pr_debug("gic: FIQ support %s\n",
+		 gic->fiq_enable ? "enabled" : "disabled");
+
+	if (!gic->fiq_enable)
+		return;
+}
+#else /* CONFIG_FIQ */
+static inline void gic_init_fiq(struct gic_chip_data *gic,
+				irq_hw_number_t first_irq,
+				unsigned int num_irqs) {}
+#endif /* CONFIG_FIQ */
+
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
 	if (gic_nr >= MAX_GIC_NR)
@@ -373,7 +425,22 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 
 	gic_dist_config(base, gic_irqs, NULL);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Optionally set all global interrupts to be group 1.
+	 */
+	if (gic_data_fiq_enable(gic))
+		for (i = 32; i < gic_irqs; i += 32)
+			writel_relaxed(0xffffffff,
+				       base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(3, base + GIC_DIST_CTRL);
+	else
+		writel_relaxed(1, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -400,8 +467,20 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 
 	gic_cpu_config(dist_base, NULL);
 
+	/*
+	 * Set all PPI and SGI interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers are read-as-zero/write-ignored.
+	 */
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
+	else
+		writel_relaxed(1, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -485,7 +564,10 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	if (gic_data_fiq_enable(&gic_data[gic_nr]))
+		writel_relaxed(3, dist_base + GIC_DIST_CTRL);
+	else
+		writel_relaxed(1, dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -542,7 +624,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -604,6 +686,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
 	unsigned long flags, map = 0;
+	unsigned long softint;
 
 	raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
@@ -618,7 +701,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+	softint = map << 16 | irq;
+	if (gic_data_fiq_enable(&gic_data[0]))
+		softint |= 0x8000;
+	writel_relaxed(softint,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
@@ -964,6 +1051,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 
 		gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
 					hwirq_base, &gic_irq_domain_ops, gic);
+
+		gic_init_fiq(gic, irq_base, gic_irqs);
 	} else {
 		gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
 						    &gic_irq_domain_ops,
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 06/19] irqchip: gic: Provide support for interrupt grouping
@ 2014-08-19 16:45                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: linux-arm-kernel

All GIC hardware except GICv1-without-TrustZone support provides a means
to group exceptions into group 0 (which can optionally be signally using
use FIQ) and group 1. The kernel currently provides no means to exploit
this. This patch alters the initialization of the GIC to place all
interrupts into group 1 which is the foundational requirement to meaningfully
use FIQ.

Note that the hardware functionality is unavailable to the kernel when a
secure monitor is present because access to the grouping registers are
prohibited outside "secure world" (this feature allows grouping to be
used to allow hardware peripherals to send interrupts into the secure
world). The GIC driver will automatically detect this and disable its
attempts to group interrupts.

On systems without TrustZone support the kernel has the power to route
interrupt sources to FIQ, potentially allowing a driver to exploit the
NMI-like properties of FIQ.

Tested on Freescale i.MX6 (quad A9), STiH416 (dual A9) and a self-written
qemu GICv2 model.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Dirk Behme <dirk.behme@de.bosch.com>
---
 drivers/irqchip/irq-gic.c | 99 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 94 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4b959e6..423707c 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -41,6 +41,9 @@
 #include <linux/irqchip/arm-gic.h>
 
 #include <asm/cputype.h>
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
@@ -68,6 +71,9 @@ struct gic_chip_data {
 #ifdef CONFIG_GIC_NON_BANKED
 	void __iomem *(*get_base)(union gic_base *);
 #endif
+#ifdef CONFIG_FIQ
+	bool fiq_enable;
+#endif
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
@@ -131,6 +137,16 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data,
 #define gic_set_base_accessor(d, f)
 #endif
 
+#ifdef CONFIG_FIQ
+static inline bool gic_data_fiq_enable(struct gic_chip_data *data)
+{
+	return data->fiq_enable;
+}
+#else
+static inline bool gic_data_fiq_enable(
+		struct gic_chip_data *data) { return false; }
+#endif
+
 static inline void __iomem *gic_dist_base(struct irq_data *d)
 {
 	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
@@ -325,6 +341,42 @@ static struct irq_chip gic_chip = {
 	.irq_set_wake		= gic_set_wake,
 };
 
+#ifdef CONFIG_FIQ
+static void __init gic_init_fiq(struct gic_chip_data *gic,
+				irq_hw_number_t first_irq,
+				unsigned int num_irqs)
+{
+	void __iomem *dist_base = gic_data_dist_base(gic_data);
+	unsigned int i;
+
+	/*
+	 * FIQ can only be supported on platforms without an extended irq_eoi
+	 * method (otherwise we take a lock during eoi handling).
+	 */
+	if (gic_arch_extn.irq_eoi)
+		return;
+
+	/*
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers a read-as-zero/write-ignored.
+	 * However as a precaution we restore the reset default regardless of
+	 * the result of the test.
+	 */
+	writel_relaxed(1, dist_base + GIC_DIST_IGROUP + 0);
+	gic->fiq_enable = readl_relaxed(dist_base + GIC_DIST_IGROUP + 0);
+	writel_relaxed(0, dist_base + GIC_DIST_IGROUP + 0);
+	pr_debug("gic: FIQ support %s\n",
+		 gic->fiq_enable ? "enabled" : "disabled");
+
+	if (!gic->fiq_enable)
+		return;
+}
+#else /* CONFIG_FIQ */
+static inline void gic_init_fiq(struct gic_chip_data *gic,
+				irq_hw_number_t first_irq,
+				unsigned int num_irqs) {}
+#endif /* CONFIG_FIQ */
+
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
 	if (gic_nr >= MAX_GIC_NR)
@@ -373,7 +425,22 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 
 	gic_dist_config(base, gic_irqs, NULL);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Optionally set all global interrupts to be group 1.
+	 */
+	if (gic_data_fiq_enable(gic))
+		for (i = 32; i < gic_irqs; i += 32)
+			writel_relaxed(0xffffffff,
+				       base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(3, base + GIC_DIST_CTRL);
+	else
+		writel_relaxed(1, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -400,8 +467,20 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 
 	gic_cpu_config(dist_base, NULL);
 
+	/*
+	 * Set all PPI and SGI interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers are read-as-zero/write-ignored.
+	 */
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
+	else
+		writel_relaxed(1, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -485,7 +564,10 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	if (gic_data_fiq_enable(&gic_data[gic_nr]))
+		writel_relaxed(3, dist_base + GIC_DIST_CTRL);
+	else
+		writel_relaxed(1, dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -542,7 +624,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -604,6 +686,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
 	unsigned long flags, map = 0;
+	unsigned long softint;
 
 	raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
@@ -618,7 +701,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+	softint = map << 16 | irq;
+	if (gic_data_fiq_enable(&gic_data[0]))
+		softint |= 0x8000;
+	writel_relaxed(softint,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
@@ -964,6 +1051,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 
 		gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
 					hwirq_base, &gic_irq_domain_ops, gic);
+
+		gic_init_fiq(gic, irq_base, gic_irqs);
 	} else {
 		gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
 						    &gic_irq_domain_ops,
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 07/19] irqchip: gic: Add support for FIQ management
  2014-08-19 16:45                 ` Daniel Thompson
@ 2014-08-19 16:45                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Thomas Gleixner, Jason Cooper, Nicolas Pitre,
	Christoffer Dall, Sricharan R

This patch introduces callbacks to route interrupts to or away
from the FIQ signal and registers these callbacks with the FIQ
infrastructure (if the device can supports it).

Both these aspects combine and allow a driver to deploy a FIQ handler
without any machine specific knowledge; it can be used effectively on
multi-platform kernels.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
---
 drivers/irqchip/irq-gic.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 423707c..6fa0542 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -342,6 +342,69 @@ static struct irq_chip gic_chip = {
 };
 
 #ifdef CONFIG_FIQ
+/*
+ * Shift an interrupt between Group 0 and Group 1.
+ *
+ * In addition to changing the group we also modify the priority to
+ * match what "ARM strongly recommends" for a system where no Group 1
+ * interrupt must ever preempt a Group 0 interrupt.
+ */
+static void gic_set_group_irq(struct irq_data *d, int group)
+{
+	unsigned int grp_reg = gic_irq(d) / 32 * 4;
+	u32 grp_mask = 1 << (gic_irq(d) % 32);
+	u32 grp_val;
+
+	unsigned int pri_reg = (gic_irq(d) / 4) * 4;
+	u32 pri_mask = 1 << (7 + ((gic_irq(d) % 4) * 8));
+	u32 pri_val;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	grp_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+
+	if (group) {
+		grp_val |= grp_mask;
+		pri_val |= pri_mask;
+	} else {
+		grp_val &= ~grp_mask;
+		pri_val &= ~pri_mask;
+	}
+
+	writel_relaxed(grp_val, gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void gic_enable_fiq(struct irq_data *d)
+{
+	gic_set_group_irq(d, 0);
+}
+
+static void gic_disable_fiq(struct irq_data *d)
+{
+	gic_set_group_irq(d, 1);
+}
+
+static int gic_ack_fiq(struct irq_data *d)
+{
+	struct gic_chip_data *gic = irq_data_get_irq_chip_data(d);
+	u32 irqstat, irqnr;
+
+	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+	irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	return irq_find_mapping(gic->domain, irqnr);
+}
+
+static struct fiq_chip gic_fiq = {
+	.fiq_enable		= gic_enable_fiq,
+	.fiq_disable            = gic_disable_fiq,
+	.fiq_ack		= gic_ack_fiq,
+	.fiq_eoi		= gic_eoi_irq,
+};
+
 static void __init gic_init_fiq(struct gic_chip_data *gic,
 				irq_hw_number_t first_irq,
 				unsigned int num_irqs)
@@ -370,6 +433,12 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 
 	if (!gic->fiq_enable)
 		return;
+
+	/*
+	 * FIQ is supported on this device! Register our chip data.
+	 */
+	for (i = 0; i < num_irqs; i++)
+		fiq_register_mapping(first_irq + i, &gic_fiq);
 }
 #else /* CONFIG_FIQ */
 static inline void gic_init_fiq(struct gic_chip_data *gic,
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 07/19] irqchip: gic: Add support for FIQ management
@ 2014-08-19 16:45                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: linux-arm-kernel

This patch introduces callbacks to route interrupts to or away
from the FIQ signal and registers these callbacks with the FIQ
infrastructure (if the device can supports it).

Both these aspects combine and allow a driver to deploy a FIQ handler
without any machine specific knowledge; it can be used effectively on
multi-platform kernels.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
---
 drivers/irqchip/irq-gic.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 423707c..6fa0542 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -342,6 +342,69 @@ static struct irq_chip gic_chip = {
 };
 
 #ifdef CONFIG_FIQ
+/*
+ * Shift an interrupt between Group 0 and Group 1.
+ *
+ * In addition to changing the group we also modify the priority to
+ * match what "ARM strongly recommends" for a system where no Group 1
+ * interrupt must ever preempt a Group 0 interrupt.
+ */
+static void gic_set_group_irq(struct irq_data *d, int group)
+{
+	unsigned int grp_reg = gic_irq(d) / 32 * 4;
+	u32 grp_mask = 1 << (gic_irq(d) % 32);
+	u32 grp_val;
+
+	unsigned int pri_reg = (gic_irq(d) / 4) * 4;
+	u32 pri_mask = 1 << (7 + ((gic_irq(d) % 4) * 8));
+	u32 pri_val;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	grp_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+
+	if (group) {
+		grp_val |= grp_mask;
+		pri_val |= pri_mask;
+	} else {
+		grp_val &= ~grp_mask;
+		pri_val &= ~pri_mask;
+	}
+
+	writel_relaxed(grp_val, gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void gic_enable_fiq(struct irq_data *d)
+{
+	gic_set_group_irq(d, 0);
+}
+
+static void gic_disable_fiq(struct irq_data *d)
+{
+	gic_set_group_irq(d, 1);
+}
+
+static int gic_ack_fiq(struct irq_data *d)
+{
+	struct gic_chip_data *gic = irq_data_get_irq_chip_data(d);
+	u32 irqstat, irqnr;
+
+	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+	irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	return irq_find_mapping(gic->domain, irqnr);
+}
+
+static struct fiq_chip gic_fiq = {
+	.fiq_enable		= gic_enable_fiq,
+	.fiq_disable            = gic_disable_fiq,
+	.fiq_ack		= gic_ack_fiq,
+	.fiq_eoi		= gic_eoi_irq,
+};
+
 static void __init gic_init_fiq(struct gic_chip_data *gic,
 				irq_hw_number_t first_irq,
 				unsigned int num_irqs)
@@ -370,6 +433,12 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 
 	if (!gic->fiq_enable)
 		return;
+
+	/*
+	 * FIQ is supported on this device! Register our chip data.
+	 */
+	for (i = 0; i < num_irqs; i++)
+		fiq_register_mapping(first_irq + i, &gic_fiq);
 }
 #else /* CONFIG_FIQ */
 static inline void gic_init_fiq(struct gic_chip_data *gic,
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 08/19] irqchip: gic: Remove spin locks from eoi_irq
  2014-08-19 16:45                 ` Daniel Thompson
@ 2014-08-19 16:45                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Thomas Gleixner, Jason Cooper, Peter De Schrijver

This patch is motivated by the comment it removes from gic_init_fiq,
namely that the spin locks in eoi_irq preclude certain platforms from
supporting FIQ.

Currently there is only one upstream platform (tegra) that actually
hooks gic_arch_extn.irq_eoi and it does not require these spin locks.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Peter De Schrijver <pdeschrijver@nvidia.com>
---
 drivers/irqchip/irq-gic.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 6fa0542..d928912 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -191,11 +191,8 @@ static void gic_unmask_irq(struct irq_data *d)
 
 static void gic_eoi_irq(struct irq_data *d)
 {
-	if (gic_arch_extn.irq_eoi) {
-		raw_spin_lock(&irq_controller_lock);
+	if (gic_arch_extn.irq_eoi)
 		gic_arch_extn.irq_eoi(d);
-		raw_spin_unlock(&irq_controller_lock);
-	}
 
 	writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
 }
@@ -413,13 +410,6 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 	unsigned int i;
 
 	/*
-	 * FIQ can only be supported on platforms without an extended irq_eoi
-	 * method (otherwise we take a lock during eoi handling).
-	 */
-	if (gic_arch_extn.irq_eoi)
-		return;
-
-	/*
 	 * If grouping is not available (not implemented or prohibited by
 	 * security mode) these registers a read-as-zero/write-ignored.
 	 * However as a precaution we restore the reset default regardless of
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 08/19] irqchip: gic: Remove spin locks from eoi_irq
@ 2014-08-19 16:45                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: linux-arm-kernel

This patch is motivated by the comment it removes from gic_init_fiq,
namely that the spin locks in eoi_irq preclude certain platforms from
supporting FIQ.

Currently there is only one upstream platform (tegra) that actually
hooks gic_arch_extn.irq_eoi and it does not require these spin locks.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Peter De Schrijver <pdeschrijver@nvidia.com>
---
 drivers/irqchip/irq-gic.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 6fa0542..d928912 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -191,11 +191,8 @@ static void gic_unmask_irq(struct irq_data *d)
 
 static void gic_eoi_irq(struct irq_data *d)
 {
-	if (gic_arch_extn.irq_eoi) {
-		raw_spin_lock(&irq_controller_lock);
+	if (gic_arch_extn.irq_eoi)
 		gic_arch_extn.irq_eoi(d);
-		raw_spin_unlock(&irq_controller_lock);
-	}
 
 	writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
 }
@@ -413,13 +410,6 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 	unsigned int i;
 
 	/*
-	 * FIQ can only be supported on platforms without an extended irq_eoi
-	 * method (otherwise we take a lock during eoi handling).
-	 */
-	if (gic_arch_extn.irq_eoi)
-		return;
-
-	/*
 	 * If grouping is not available (not implemented or prohibited by
 	 * security mode) these registers a read-as-zero/write-ignored.
 	 * However as a precaution we restore the reset default regardless of
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 09/19] irqchip: gic: Add support for IPI FIQ
  2014-08-19 16:45                 ` Daniel Thompson
@ 2014-08-19 16:45                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

To support IPI FIQ we alter gic_cpu_init() to honour SMP_IPI_FIQ_MASK and
register a fairly high priority notifier to acknowledge and clear the IPI
when it is triggered.

For the IPI FIQ to be useful we must also make it safe to call
gic_raise_softirq() from the FIQ handler by altering the locking
strategy slightly.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/irqchip/irq-gic.c | 125 ++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 104 insertions(+), 21 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index d928912..8834749 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,6 +39,7 @@
 #include <linux/slab.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/ratelimit.h>
 
 #include <asm/cputype.h>
 #ifdef CONFIG_FIQ
@@ -51,6 +52,10 @@
 #include "irq-gic-common.h"
 #include "irqchip.h"
 
+#ifndef SMP_IPI_FIQ_MASK
+#define SMP_IPI_FIQ_MASK 0
+#endif
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -77,6 +82,8 @@ struct gic_chip_data {
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+/* A fiq-safe spinlock must only be locked when the FIQ is masked */
+static DEFINE_RAW_SPINLOCK(fiq_safe_migration_lock);
 
 /*
  * The GIC mapping of CPU interfaces does not necessarily match
@@ -346,20 +353,21 @@ static struct irq_chip gic_chip = {
  * match what "ARM strongly recommends" for a system where no Group 1
  * interrupt must ever preempt a Group 0 interrupt.
  */
-static void gic_set_group_irq(struct irq_data *d, int group)
+static void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				int group)
 {
-	unsigned int grp_reg = gic_irq(d) / 32 * 4;
-	u32 grp_mask = 1 << (gic_irq(d) % 32);
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_mask = 1 << (hwirq % 32);
 	u32 grp_val;
 
-	unsigned int pri_reg = (gic_irq(d) / 4) * 4;
-	u32 pri_mask = 1 << (7 + ((gic_irq(d) % 4) * 8));
+	unsigned int pri_reg = (hwirq / 4) * 4;
+	u32 pri_mask = 1 << (7 + ((hwirq % 4) * 8));
 	u32 pri_val;
 
 	raw_spin_lock(&irq_controller_lock);
 
-	grp_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
-	pri_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(base + GIC_DIST_PRI + pri_reg);
 
 	if (group) {
 		grp_val |= grp_mask;
@@ -369,20 +377,20 @@ static void gic_set_group_irq(struct irq_data *d, int group)
 		pri_val &= ~pri_mask;
 	}
 
-	writel_relaxed(grp_val, gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
-	writel_relaxed(pri_val, gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+	writel_relaxed(grp_val, base + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, base + GIC_DIST_PRI + pri_reg);
 
 	raw_spin_unlock(&irq_controller_lock);
 }
 
 static void gic_enable_fiq(struct irq_data *d)
 {
-	gic_set_group_irq(d, 0);
+	gic_set_group_irq(gic_dist_base(d), gic_irq(d), 0);
 }
 
 static void gic_disable_fiq(struct irq_data *d)
 {
-	gic_set_group_irq(d, 1);
+	gic_set_group_irq(gic_dist_base(d), gic_irq(d), 1);
 }
 
 static int gic_ack_fiq(struct irq_data *d)
@@ -390,8 +398,22 @@ static int gic_ack_fiq(struct irq_data *d)
 	struct gic_chip_data *gic = irq_data_get_irq_chip_data(d);
 	u32 irqstat, irqnr;
 
-	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
-	irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	while (1) {
+		writel_relaxed(0x70, gic_data_cpu_base(gic) + GIC_CPU_PRIMASK);
+		irqstat =
+		    readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+		writel_relaxed(0xf0, gic_data_cpu_base(gic) + GIC_CPU_PRIMASK);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		if (irqnr > 15)
+			break;
+
+		/* we've got an IPI which we can simply acknowledge
+		 * and move on
+		 */
+		gic_eoi_irq(d);
+	}
+
 	return irq_find_mapping(gic->domain, irqnr);
 }
 
@@ -430,7 +452,43 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 	for (i = 0; i < num_irqs; i++)
 		fiq_register_mapping(first_irq + i, &gic_fiq);
 }
+
+/*
+ * Fully acknowledge (both ack and eoi) a FIQ-based IPI
+ */
+static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
+			   void *data)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	unsigned long irqstat, irqnr;
+
+	if (WARN_ON(!in_nmi()))
+		return NOTIFY_BAD;
+
+	while ((1u << readl_relaxed(cpu_base + GIC_CPU_HIGHPRI)) &
+	       SMP_IPI_FIQ_MASK) {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		WARN_RATELIMIT(irqnr > 16,
+			       "Unexpected irqnr %lu (bad prioritization?)\n",
+			       irqnr);
+	}
+
+	return NOTIFY_OK;
+}
+
+/*
+ * Notifier to ensure IPI FIQ is acknowledged correctly.
+ */
+static struct notifier_block gic_fiq_ipi_notifier = {
+	.notifier_call = gic_handle_fiq_ipi,
+};
 #else /* CONFIG_FIQ */
+static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				     int group) {}
 static inline void gic_init_fiq(struct gic_chip_data *gic,
 				irq_hw_number_t first_irq,
 				unsigned int num_irqs) {}
@@ -527,14 +585,19 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	gic_cpu_config(dist_base, NULL);
 
 	/*
-	 * Set all PPI and SGI interrupts to be group 1.
-	 *
-	 * If grouping is not available (not implemented or prohibited by
-	 * security mode) these registers are read-as-zero/write-ignored.
+	 * Optionally set all PPI and SGI interrupts to be group 1.
 	 */
 	if (gic_data_fiq_enable(gic))
 		writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
 
+	/*
+	 * Optionally shift the FIQ based IPIs to group 0.
+	 */
+	if (gic_data_fiq_enable(gic))
+		for (i = 0; i < 16; i++)
+			if (SMP_IPI_FIQ_MASK & (1 << i))
+				gic_set_group_irq(dist_base, i, 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
 	if (gic_data_fiq_enable(gic))
 		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
@@ -747,7 +810,17 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	unsigned long flags, map = 0;
 	unsigned long softint;
 
-	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+	/*
+	 * The locking in this function ensures we don't use stale cpu mappings
+	 * and thus we never route an IPI to the wrong physical core during a
+	 * big.LITTLE switch. The switch code takes both of these locks meaning
+	 * we can choose whichever lock is safe to use from our current calling
+	 * context.
+	 */
+	if (in_nmi())
+		raw_spin_lock(&fiq_safe_migration_lock);
+	else
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
 	/* Convert our logical CPU mask into a physical one. */
 	for_each_cpu(cpu, mask)
@@ -761,12 +834,16 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 
 	/* this always happens on GIC0 */
 	softint = map << 16 | irq;
-	if (gic_data_fiq_enable(&gic_data[0]))
+	if (gic_data_fiq_enable(&gic_data[0]) &&
+	    !(SMP_IPI_FIQ_MASK & (1 << irq)))
 		softint |= 0x8000;
 	writel_relaxed(softint,
 		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
-	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+	if (in_nmi())
+		raw_spin_unlock(&fiq_safe_migration_lock);
+	else
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 #endif
 
@@ -814,7 +891,7 @@ int gic_get_cpu_id(unsigned int cpu)
  * Migrate all peripheral interrupts with a target matching the current CPU
  * to the interface corresponding to @new_cpu_id.  The CPU interface mapping
  * is also updated.  Targets to other CPU interfaces are unchanged.
- * This must be called with IRQs locally disabled.
+ * This must be called with IRQ and FIQ locally disabled.
  */
 void gic_migrate_target(unsigned int new_cpu_id)
 {
@@ -836,6 +913,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 	ror_val = (cur_cpu_id - new_cpu_id) & 31;
 
 	raw_spin_lock(&irq_controller_lock);
+	raw_spin_lock(&fiq_safe_migration_lock);
 
 	/* Update the target interface for this logical CPU */
 	gic_cpu_map[cpu] = 1 << new_cpu_id;
@@ -855,6 +933,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 		}
 	}
 
+	raw_spin_unlock(&fiq_safe_migration_lock);
 	raw_spin_unlock(&irq_controller_lock);
 
 	/*
@@ -1125,6 +1204,10 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 #ifdef CONFIG_SMP
 		set_smp_cross_call(gic_raise_softirq);
 		register_cpu_notifier(&gic_cpu_notifier);
+#ifdef CONFIG_FIQ
+		if (gic_data_fiq_enable(gic))
+			register_fiq_nmi_notifier(&gic_fiq_ipi_notifier);
+#endif
 #endif
 		set_handle_irq(gic_handle_irq);
 	}
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 09/19] irqchip: gic: Add support for IPI FIQ
@ 2014-08-19 16:45                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:45 UTC (permalink / raw)
  To: linux-arm-kernel

To support IPI FIQ we alter gic_cpu_init() to honour SMP_IPI_FIQ_MASK and
register a fairly high priority notifier to acknowledge and clear the IPI
when it is triggered.

For the IPI FIQ to be useful we must also make it safe to call
gic_raise_softirq() from the FIQ handler by altering the locking
strategy slightly.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/irqchip/irq-gic.c | 125 ++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 104 insertions(+), 21 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index d928912..8834749 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,6 +39,7 @@
 #include <linux/slab.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/ratelimit.h>
 
 #include <asm/cputype.h>
 #ifdef CONFIG_FIQ
@@ -51,6 +52,10 @@
 #include "irq-gic-common.h"
 #include "irqchip.h"
 
+#ifndef SMP_IPI_FIQ_MASK
+#define SMP_IPI_FIQ_MASK 0
+#endif
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -77,6 +82,8 @@ struct gic_chip_data {
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+/* A fiq-safe spinlock must only be locked when the FIQ is masked */
+static DEFINE_RAW_SPINLOCK(fiq_safe_migration_lock);
 
 /*
  * The GIC mapping of CPU interfaces does not necessarily match
@@ -346,20 +353,21 @@ static struct irq_chip gic_chip = {
  * match what "ARM strongly recommends" for a system where no Group 1
  * interrupt must ever preempt a Group 0 interrupt.
  */
-static void gic_set_group_irq(struct irq_data *d, int group)
+static void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				int group)
 {
-	unsigned int grp_reg = gic_irq(d) / 32 * 4;
-	u32 grp_mask = 1 << (gic_irq(d) % 32);
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_mask = 1 << (hwirq % 32);
 	u32 grp_val;
 
-	unsigned int pri_reg = (gic_irq(d) / 4) * 4;
-	u32 pri_mask = 1 << (7 + ((gic_irq(d) % 4) * 8));
+	unsigned int pri_reg = (hwirq / 4) * 4;
+	u32 pri_mask = 1 << (7 + ((hwirq % 4) * 8));
 	u32 pri_val;
 
 	raw_spin_lock(&irq_controller_lock);
 
-	grp_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
-	pri_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(base + GIC_DIST_PRI + pri_reg);
 
 	if (group) {
 		grp_val |= grp_mask;
@@ -369,20 +377,20 @@ static void gic_set_group_irq(struct irq_data *d, int group)
 		pri_val &= ~pri_mask;
 	}
 
-	writel_relaxed(grp_val, gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
-	writel_relaxed(pri_val, gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+	writel_relaxed(grp_val, base + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, base + GIC_DIST_PRI + pri_reg);
 
 	raw_spin_unlock(&irq_controller_lock);
 }
 
 static void gic_enable_fiq(struct irq_data *d)
 {
-	gic_set_group_irq(d, 0);
+	gic_set_group_irq(gic_dist_base(d), gic_irq(d), 0);
 }
 
 static void gic_disable_fiq(struct irq_data *d)
 {
-	gic_set_group_irq(d, 1);
+	gic_set_group_irq(gic_dist_base(d), gic_irq(d), 1);
 }
 
 static int gic_ack_fiq(struct irq_data *d)
@@ -390,8 +398,22 @@ static int gic_ack_fiq(struct irq_data *d)
 	struct gic_chip_data *gic = irq_data_get_irq_chip_data(d);
 	u32 irqstat, irqnr;
 
-	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
-	irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	while (1) {
+		writel_relaxed(0x70, gic_data_cpu_base(gic) + GIC_CPU_PRIMASK);
+		irqstat =
+		    readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+		writel_relaxed(0xf0, gic_data_cpu_base(gic) + GIC_CPU_PRIMASK);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		if (irqnr > 15)
+			break;
+
+		/* we've got an IPI which we can simply acknowledge
+		 * and move on
+		 */
+		gic_eoi_irq(d);
+	}
+
 	return irq_find_mapping(gic->domain, irqnr);
 }
 
@@ -430,7 +452,43 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 	for (i = 0; i < num_irqs; i++)
 		fiq_register_mapping(first_irq + i, &gic_fiq);
 }
+
+/*
+ * Fully acknowledge (both ack and eoi) a FIQ-based IPI
+ */
+static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
+			   void *data)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	unsigned long irqstat, irqnr;
+
+	if (WARN_ON(!in_nmi()))
+		return NOTIFY_BAD;
+
+	while ((1u << readl_relaxed(cpu_base + GIC_CPU_HIGHPRI)) &
+	       SMP_IPI_FIQ_MASK) {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		WARN_RATELIMIT(irqnr > 16,
+			       "Unexpected irqnr %lu (bad prioritization?)\n",
+			       irqnr);
+	}
+
+	return NOTIFY_OK;
+}
+
+/*
+ * Notifier to ensure IPI FIQ is acknowledged correctly.
+ */
+static struct notifier_block gic_fiq_ipi_notifier = {
+	.notifier_call = gic_handle_fiq_ipi,
+};
 #else /* CONFIG_FIQ */
+static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				     int group) {}
 static inline void gic_init_fiq(struct gic_chip_data *gic,
 				irq_hw_number_t first_irq,
 				unsigned int num_irqs) {}
@@ -527,14 +585,19 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	gic_cpu_config(dist_base, NULL);
 
 	/*
-	 * Set all PPI and SGI interrupts to be group 1.
-	 *
-	 * If grouping is not available (not implemented or prohibited by
-	 * security mode) these registers are read-as-zero/write-ignored.
+	 * Optionally set all PPI and SGI interrupts to be group 1.
 	 */
 	if (gic_data_fiq_enable(gic))
 		writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
 
+	/*
+	 * Optionally shift the FIQ based IPIs to group 0.
+	 */
+	if (gic_data_fiq_enable(gic))
+		for (i = 0; i < 16; i++)
+			if (SMP_IPI_FIQ_MASK & (1 << i))
+				gic_set_group_irq(dist_base, i, 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
 	if (gic_data_fiq_enable(gic))
 		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
@@ -747,7 +810,17 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	unsigned long flags, map = 0;
 	unsigned long softint;
 
-	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+	/*
+	 * The locking in this function ensures we don't use stale cpu mappings
+	 * and thus we never route an IPI to the wrong physical core during a
+	 * big.LITTLE switch. The switch code takes both of these locks meaning
+	 * we can choose whichever lock is safe to use from our current calling
+	 * context.
+	 */
+	if (in_nmi())
+		raw_spin_lock(&fiq_safe_migration_lock);
+	else
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
 	/* Convert our logical CPU mask into a physical one. */
 	for_each_cpu(cpu, mask)
@@ -761,12 +834,16 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 
 	/* this always happens on GIC0 */
 	softint = map << 16 | irq;
-	if (gic_data_fiq_enable(&gic_data[0]))
+	if (gic_data_fiq_enable(&gic_data[0]) &&
+	    !(SMP_IPI_FIQ_MASK & (1 << irq)))
 		softint |= 0x8000;
 	writel_relaxed(softint,
 		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
-	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+	if (in_nmi())
+		raw_spin_unlock(&fiq_safe_migration_lock);
+	else
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 #endif
 
@@ -814,7 +891,7 @@ int gic_get_cpu_id(unsigned int cpu)
  * Migrate all peripheral interrupts with a target matching the current CPU
  * to the interface corresponding to @new_cpu_id.  The CPU interface mapping
  * is also updated.  Targets to other CPU interfaces are unchanged.
- * This must be called with IRQs locally disabled.
+ * This must be called with IRQ and FIQ locally disabled.
  */
 void gic_migrate_target(unsigned int new_cpu_id)
 {
@@ -836,6 +913,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 	ror_val = (cur_cpu_id - new_cpu_id) & 31;
 
 	raw_spin_lock(&irq_controller_lock);
+	raw_spin_lock(&fiq_safe_migration_lock);
 
 	/* Update the target interface for this logical CPU */
 	gic_cpu_map[cpu] = 1 << new_cpu_id;
@@ -855,6 +933,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 		}
 	}
 
+	raw_spin_unlock(&fiq_safe_migration_lock);
 	raw_spin_unlock(&irq_controller_lock);
 
 	/*
@@ -1125,6 +1204,10 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 #ifdef CONFIG_SMP
 		set_smp_cross_call(gic_raise_softirq);
 		register_cpu_notifier(&gic_cpu_notifier);
+#ifdef CONFIG_FIQ
+		if (gic_data_fiq_enable(gic))
+			register_fiq_nmi_notifier(&gic_fiq_ipi_notifier);
+#endif
 #endif
 		set_handle_irq(gic_handle_irq);
 	}
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 10/19] irqchip: gic: Group 0 workaround.
  2014-08-19 16:45                 ` Daniel Thompson
@ 2014-08-19 16:46                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Thomas Gleixner, Jason Cooper

An ARM system based on GICv1 that runs by default in secure mode and
uses both group 0 and group 1 interrupts (in order to exploit FIQ)
will suffer a problem where the IRQ handler occasionally spuriously
acknowledges a group 0 (FIQ) interrupt.

This can be prevented by ensuring the IRQ handler makes non-secure
memory access to the GIC registers but this is complex because
the non-secure bits cannot be apply to 4k pages (the bit is one level
up in the page table and applies to 1MB at a time).

This workaround uses an alternative approach that spots the spurious
acknowledgment and regenerates the FIQ. This keeps the workaround
exclusively within the GIC driver (although there is a runtime
perforamnce penalty resulting from this approach).

Reported-by: Harro Haan <hrhaan@gmail.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Tested-by: Harro Haan <hrhaan@gmail.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
---
 drivers/irqchip/irq-gic.c | 52 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 49 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 8834749..bda5a91 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -279,14 +279,59 @@ static int gic_set_wake(struct irq_data *d, unsigned int on)
 #define gic_set_wake	NULL
 #endif
 
+#ifdef CONFIG_FIQ
+/* This is a software emulation of the Aliased Interrupt Acknowledge Register
+ * (GIC_AIAR) found in GICv2+.
+ */
+static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32 irqstat)
+{
+	u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	void __iomem *dist_base = gic_data_dist_base(gic);
+	u32 offset, mask;
+
+	if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
+		return irqstat;
+
+	offset = irqnr / 32 * 4;
+	mask = 1 << (irqnr % 32);
+	if (readl_relaxed(dist_base + GIC_DIST_IGROUP + offset) & mask)
+		return irqstat;
+
+	/* this interrupt must be taken as a FIQ so put it back into the
+	 * pending state and end our own servicing of it.
+	 */
+	writel_relaxed(mask, dist_base + GIC_DIST_PENDING_SET + offset);
+	readl_relaxed(dist_base + GIC_DIST_PENDING_SET + offset);
+	writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
+
+	return 1023;
+}
+
+static u32 gic_ack_irq(struct gic_chip_data *gic)
+{
+	u32 irqstat;
+
+	local_fiq_disable();
+	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+	irqstat = gic_handle_spurious_group_0(gic, irqstat);
+	local_fiq_enable();
+
+	return irqstat;
+}
+#else
+static u32 gic_ack_irq(struct gic_chip_data *gic)
+{
+	return readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+}
+#endif
+
 static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
 	u32 irqstat, irqnr;
 	struct gic_chip_data *gic = &gic_data[0];
-	void __iomem *cpu_base = gic_data_cpu_base(gic);
 
 	do {
-		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		irqstat = gic_ack_irq(gic);
 		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
 
 		if (likely(irqnr > 15 && irqnr < 1021)) {
@@ -295,7 +340,8 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 			continue;
 		}
 		if (irqnr < 16) {
-			writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+			writel_relaxed(irqstat,
+				       gic_data_cpu_base(gic) + GIC_CPU_EOI);
 #ifdef CONFIG_SMP
 			handle_IPI(irqnr, regs);
 #endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 10/19] irqchip: gic: Group 0 workaround.
@ 2014-08-19 16:46                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: linux-arm-kernel

An ARM system based on GICv1 that runs by default in secure mode and
uses both group 0 and group 1 interrupts (in order to exploit FIQ)
will suffer a problem where the IRQ handler occasionally spuriously
acknowledges a group 0 (FIQ) interrupt.

This can be prevented by ensuring the IRQ handler makes non-secure
memory access to the GIC registers but this is complex because
the non-secure bits cannot be apply to 4k pages (the bit is one level
up in the page table and applies to 1MB at a time).

This workaround uses an alternative approach that spots the spurious
acknowledgment and regenerates the FIQ. This keeps the workaround
exclusively within the GIC driver (although there is a runtime
perforamnce penalty resulting from this approach).

Reported-by: Harro Haan <hrhaan@gmail.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Tested-by: Harro Haan <hrhaan@gmail.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
---
 drivers/irqchip/irq-gic.c | 52 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 49 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 8834749..bda5a91 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -279,14 +279,59 @@ static int gic_set_wake(struct irq_data *d, unsigned int on)
 #define gic_set_wake	NULL
 #endif
 
+#ifdef CONFIG_FIQ
+/* This is a software emulation of the Aliased Interrupt Acknowledge Register
+ * (GIC_AIAR) found in GICv2+.
+ */
+static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32 irqstat)
+{
+	u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	void __iomem *dist_base = gic_data_dist_base(gic);
+	u32 offset, mask;
+
+	if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
+		return irqstat;
+
+	offset = irqnr / 32 * 4;
+	mask = 1 << (irqnr % 32);
+	if (readl_relaxed(dist_base + GIC_DIST_IGROUP + offset) & mask)
+		return irqstat;
+
+	/* this interrupt must be taken as a FIQ so put it back into the
+	 * pending state and end our own servicing of it.
+	 */
+	writel_relaxed(mask, dist_base + GIC_DIST_PENDING_SET + offset);
+	readl_relaxed(dist_base + GIC_DIST_PENDING_SET + offset);
+	writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
+
+	return 1023;
+}
+
+static u32 gic_ack_irq(struct gic_chip_data *gic)
+{
+	u32 irqstat;
+
+	local_fiq_disable();
+	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+	irqstat = gic_handle_spurious_group_0(gic, irqstat);
+	local_fiq_enable();
+
+	return irqstat;
+}
+#else
+static u32 gic_ack_irq(struct gic_chip_data *gic)
+{
+	return readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+}
+#endif
+
 static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
 	u32 irqstat, irqnr;
 	struct gic_chip_data *gic = &gic_data[0];
-	void __iomem *cpu_base = gic_data_cpu_base(gic);
 
 	do {
-		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		irqstat = gic_ack_irq(gic);
 		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
 
 		if (likely(irqnr > 15 && irqnr < 1021)) {
@@ -295,7 +340,8 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 			continue;
 		}
 		if (irqnr < 16) {
-			writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+			writel_relaxed(irqstat,
+				       gic_data_cpu_base(gic) + GIC_CPU_EOI);
 #ifdef CONFIG_SMP
 			handle_IPI(irqnr, regs);
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 11/19] irqchip: vic: Add support for FIQ management
  2014-08-19 16:45                 ` Daniel Thompson
  (?)
@ 2014-08-19 16:46                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Hartley Sweeten, Ryan Mallon, Ben Dooks,
	Kukjin Kim, Thomas Gleixner, Jason Cooper, linux-samsung-soc

This patch introduces callbacks to route interrupts to or away
from the FIQ signal. It also causes these callbacks to be registered
with the FIQ infrastructure.

This patch enable FIQ support for mach-versatile whilst mach-ep93xx,
mach-netx, mach-s3c64xx and plat-samsung are unmodified (and can therefore
continue to use init_FIQ() as before).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: linux-samsung-soc@vger.kernel.org
---
 arch/arm/mach-versatile/core.c  |  2 +-
 drivers/irqchip/irq-vic.c       | 92 ++++++++++++++++++++++++++++++++---------
 include/linux/irqchip/arm-vic.h |  6 ++-
 3 files changed, 78 insertions(+), 22 deletions(-)

diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 08fb8c8..bad1d30 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -108,7 +108,7 @@ void __init versatile_init_irq(void)
 
 	np = of_find_matching_node_by_address(NULL, vic_of_match,
 					      VERSATILE_VIC_BASE);
-	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np);
+	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np ? false : true, np);
 
 	writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
 
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287..22aa126 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -36,6 +36,9 @@
 
 #include <asm/exception.h>
 #include <asm/irq.h>
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 
 #include "irqchip.h"
 
@@ -261,11 +264,53 @@ static struct irq_domain_ops vic_irqdomain_ops = {
 	.xlate = irq_domain_xlate_onetwocell,
 };
 
+#ifdef CONFIG_FIQ
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
+static void vic_set_fiq(struct irq_data *d, bool enable)
+{
+	void __iomem *base = irq_data_get_irq_chip_data(d);
+	unsigned int irq = d->hwirq;
+	u32 val;
+
+	raw_spin_lock(&irq_controller_lock);
+	val = readl(base + VIC_INT_SELECT);
+	if (enable)
+		val |= 1 << irq;
+	else
+		val &= ~(1 << irq);
+	writel(val, base + VIC_INT_SELECT);
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void vic_enable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, true);
+}
+
+static void vic_disable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, false);
+}
+
+struct fiq_chip vic_fiq = {
+	.fiq_enable = vic_enable_fiq,
+	.fiq_disable = vic_disable_fiq,
+};
+
+static void vic_register_fiq(int irq)
+{
+	fiq_register_mapping(irq, &vic_fiq);
+}
+#else /* CONFIG_FIQ */
+static inline void vic_register_fiq(int irq) {}
+#endif /* CONFIG_FIQ */
+
 /**
  * vic_register() - Register a VIC.
  * @base: The base address of the VIC.
  * @parent_irq: The parent IRQ if cascaded, else 0.
- * @irq: The base IRQ for the VIC.
+ * @irq_start: The base IRQ for the VIC.
  * @valid_sources: bitmask of valid interrupts
  * @resume_sources: bitmask of interrupts allowed for resume sources.
  * @node: The device tree node associated with the VIC.
@@ -277,12 +322,13 @@ static struct irq_domain_ops vic_irqdomain_ops = {
  * This also configures the IRQ domain for the VIC.
  */
 static void __init vic_register(void __iomem *base, unsigned int parent_irq,
-				unsigned int irq,
+				unsigned int irq_start,
 				u32 valid_sources, u32 resume_sources,
-				struct device_node *node)
+				bool map_fiqs, struct device_node *node)
 {
 	struct vic_device *v;
 	int i;
+	unsigned int irq;
 
 	if (vic_id >= ARRAY_SIZE(vic_devices)) {
 		printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
@@ -301,15 +347,19 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 		irq_set_chained_handler(parent_irq, vic_handle_irq_cascaded);
 	}
 
-	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq,
+	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq_start,
 					  &vic_irqdomain_ops, v);
 	/* create an IRQ mapping for each valid IRQ */
-	for (i = 0; i < fls(valid_sources); i++)
-		if (valid_sources & (1 << i))
-			irq_create_mapping(v->domain, i);
+	for (i = 0; i < fls(valid_sources); i++) {
+		if (valid_sources & (1 << i)) {
+			irq = irq_create_mapping(v->domain, i);
+			vic_register_fiq(irq);
+		}
+	}
+
 	/* If no base IRQ was passed, figure out our allocated base */
-	if (irq)
-		v->irq = irq;
+	if (irq_start)
+		v->irq = irq_start;
 	else
 		v->irq = irq_find_mapping(v->domain, 0);
 }
@@ -413,7 +463,8 @@ static void __init vic_clear_interrupts(void __iomem *base)
  *  and 020 within the page. We call this "second block".
  */
 static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
-			       u32 vic_sources, struct device_node *node)
+			       u32 vic_sources, bool map_fiqs,
+			       struct device_node *node)
 {
 	unsigned int i;
 	int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
@@ -439,12 +490,12 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
 		writel(32, base + VIC_PL190_DEF_VECT_ADDR);
 	}
 
-	vic_register(base, 0, irq_start, vic_sources, 0, node);
+	vic_register(base, 0, irq_start, vic_sources, 0, map_fiqs, node);
 }
 
 void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
-			      u32 vic_sources, u32 resume_sources,
-			      struct device_node *node)
+		       u32 vic_sources, u32 resume_sources,
+		       bool map_fiqs, struct device_node *node)
 {
 	unsigned int i;
 	u32 cellid = 0;
@@ -462,7 +513,7 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	switch(vendor) {
 	case AMBA_VENDOR_ST:
-		vic_init_st(base, irq_start, vic_sources, node);
+		vic_init_st(base, irq_start, vic_sources, map_fiqs, node);
 		return;
 	default:
 		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
@@ -479,7 +530,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	vic_init2(base);
 
-	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);
+	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources,
+		     map_fiqs, node);
 }
 
 /**
@@ -492,7 +544,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 void __init vic_init(void __iomem *base, unsigned int irq_start,
 		     u32 vic_sources, u32 resume_sources)
 {
-	__vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL);
+	__vic_init(base, 0, irq_start, vic_sources, resume_sources,
+		   false, NULL);
 }
 
 /**
@@ -511,7 +564,8 @@ int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 	struct vic_device *v;
 
 	v = &vic_devices[vic_id];
-	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL);
+	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, false,
+		   NULL);
 	/* Return out acquired base */
 	return v->irq;
 }
@@ -535,9 +589,9 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
 	of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask);
 
 	/*
-	 * Passing 0 as first IRQ makes the simple domain allocate descriptors
+	 * Passing 0 as first IRQ makes the domain allocate descriptors.
 	 */
-	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
+	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, true, node);
 
 	return 0;
 }
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index ba46c79..30ab39f 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -30,8 +30,10 @@ struct device_node;
 struct pt_regs;
 
 void __vic_init(void __iomem *base, int parent_irq, int irq_start,
-		u32 vic_sources, u32 resume_sources, struct device_node *node);
-void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
+		u32 vic_sources, u32 resume_sources,
+		bool map_fiqs, struct device_node *node);
+void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources,
+	      u32 resume_sources);
 int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 		      u32 vic_sources, u32 resume_sources);
 
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 11/19] irqchip: vic: Add support for FIQ management
@ 2014-08-19 16:46                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Hartley Sweeten, Ryan Mallon, Ben Dooks,
	Kukjin Kim, Thomas Gleixner, Jason Cooper

This patch introduces callbacks to route interrupts to or away
from the FIQ signal. It also causes these callbacks to be registered
with the FIQ infrastructure.

This patch enable FIQ support for mach-versatile whilst mach-ep93xx,
mach-netx, mach-s3c64xx and plat-samsung are unmodified (and can therefore
continue to use init_FIQ() as before).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: linux-samsung-soc@vger.kernel.org
---
 arch/arm/mach-versatile/core.c  |  2 +-
 drivers/irqchip/irq-vic.c       | 92 ++++++++++++++++++++++++++++++++---------
 include/linux/irqchip/arm-vic.h |  6 ++-
 3 files changed, 78 insertions(+), 22 deletions(-)

diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 08fb8c8..bad1d30 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -108,7 +108,7 @@ void __init versatile_init_irq(void)
 
 	np = of_find_matching_node_by_address(NULL, vic_of_match,
 					      VERSATILE_VIC_BASE);
-	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np);
+	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np ? false : true, np);
 
 	writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
 
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287..22aa126 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -36,6 +36,9 @@
 
 #include <asm/exception.h>
 #include <asm/irq.h>
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 
 #include "irqchip.h"
 
@@ -261,11 +264,53 @@ static struct irq_domain_ops vic_irqdomain_ops = {
 	.xlate = irq_domain_xlate_onetwocell,
 };
 
+#ifdef CONFIG_FIQ
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
+static void vic_set_fiq(struct irq_data *d, bool enable)
+{
+	void __iomem *base = irq_data_get_irq_chip_data(d);
+	unsigned int irq = d->hwirq;
+	u32 val;
+
+	raw_spin_lock(&irq_controller_lock);
+	val = readl(base + VIC_INT_SELECT);
+	if (enable)
+		val |= 1 << irq;
+	else
+		val &= ~(1 << irq);
+	writel(val, base + VIC_INT_SELECT);
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void vic_enable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, true);
+}
+
+static void vic_disable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, false);
+}
+
+struct fiq_chip vic_fiq = {
+	.fiq_enable = vic_enable_fiq,
+	.fiq_disable = vic_disable_fiq,
+};
+
+static void vic_register_fiq(int irq)
+{
+	fiq_register_mapping(irq, &vic_fiq);
+}
+#else /* CONFIG_FIQ */
+static inline void vic_register_fiq(int irq) {}
+#endif /* CONFIG_FIQ */
+
 /**
  * vic_register() - Register a VIC.
  * @base: The base address of the VIC.
  * @parent_irq: The parent IRQ if cascaded, else 0.
- * @irq: The base IRQ for the VIC.
+ * @irq_start: The base IRQ for the VIC.
  * @valid_sources: bitmask of valid interrupts
  * @resume_sources: bitmask of interrupts allowed for resume sources.
  * @node: The device tree node associated with the VIC.
@@ -277,12 +322,13 @@ static struct irq_domain_ops vic_irqdomain_ops = {
  * This also configures the IRQ domain for the VIC.
  */
 static void __init vic_register(void __iomem *base, unsigned int parent_irq,
-				unsigned int irq,
+				unsigned int irq_start,
 				u32 valid_sources, u32 resume_sources,
-				struct device_node *node)
+				bool map_fiqs, struct device_node *node)
 {
 	struct vic_device *v;
 	int i;
+	unsigned int irq;
 
 	if (vic_id >= ARRAY_SIZE(vic_devices)) {
 		printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
@@ -301,15 +347,19 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 		irq_set_chained_handler(parent_irq, vic_handle_irq_cascaded);
 	}
 
-	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq,
+	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq_start,
 					  &vic_irqdomain_ops, v);
 	/* create an IRQ mapping for each valid IRQ */
-	for (i = 0; i < fls(valid_sources); i++)
-		if (valid_sources & (1 << i))
-			irq_create_mapping(v->domain, i);
+	for (i = 0; i < fls(valid_sources); i++) {
+		if (valid_sources & (1 << i)) {
+			irq = irq_create_mapping(v->domain, i);
+			vic_register_fiq(irq);
+		}
+	}
+
 	/* If no base IRQ was passed, figure out our allocated base */
-	if (irq)
-		v->irq = irq;
+	if (irq_start)
+		v->irq = irq_start;
 	else
 		v->irq = irq_find_mapping(v->domain, 0);
 }
@@ -413,7 +463,8 @@ static void __init vic_clear_interrupts(void __iomem *base)
  *  and 020 within the page. We call this "second block".
  */
 static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
-			       u32 vic_sources, struct device_node *node)
+			       u32 vic_sources, bool map_fiqs,
+			       struct device_node *node)
 {
 	unsigned int i;
 	int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
@@ -439,12 +490,12 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
 		writel(32, base + VIC_PL190_DEF_VECT_ADDR);
 	}
 
-	vic_register(base, 0, irq_start, vic_sources, 0, node);
+	vic_register(base, 0, irq_start, vic_sources, 0, map_fiqs, node);
 }
 
 void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
-			      u32 vic_sources, u32 resume_sources,
-			      struct device_node *node)
+		       u32 vic_sources, u32 resume_sources,
+		       bool map_fiqs, struct device_node *node)
 {
 	unsigned int i;
 	u32 cellid = 0;
@@ -462,7 +513,7 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	switch(vendor) {
 	case AMBA_VENDOR_ST:
-		vic_init_st(base, irq_start, vic_sources, node);
+		vic_init_st(base, irq_start, vic_sources, map_fiqs, node);
 		return;
 	default:
 		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
@@ -479,7 +530,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	vic_init2(base);
 
-	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);
+	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources,
+		     map_fiqs, node);
 }
 
 /**
@@ -492,7 +544,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 void __init vic_init(void __iomem *base, unsigned int irq_start,
 		     u32 vic_sources, u32 resume_sources)
 {
-	__vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL);
+	__vic_init(base, 0, irq_start, vic_sources, resume_sources,
+		   false, NULL);
 }
 
 /**
@@ -511,7 +564,8 @@ int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 	struct vic_device *v;
 
 	v = &vic_devices[vic_id];
-	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL);
+	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, false,
+		   NULL);
 	/* Return out acquired base */
 	return v->irq;
 }
@@ -535,9 +589,9 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
 	of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask);
 
 	/*
-	 * Passing 0 as first IRQ makes the simple domain allocate descriptors
+	 * Passing 0 as first IRQ makes the domain allocate descriptors.
 	 */
-	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
+	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, true, node);
 
 	return 0;
 }
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index ba46c79..30ab39f 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -30,8 +30,10 @@ struct device_node;
 struct pt_regs;
 
 void __vic_init(void __iomem *base, int parent_irq, int irq_start,
-		u32 vic_sources, u32 resume_sources, struct device_node *node);
-void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
+		u32 vic_sources, u32 resume_sources,
+		bool map_fiqs, struct device_node *node);
+void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources,
+	      u32 resume_sources);
 int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 		      u32 vic_sources, u32 resume_sources);
 
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 11/19] irqchip: vic: Add support for FIQ management
@ 2014-08-19 16:46                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: linux-arm-kernel

This patch introduces callbacks to route interrupts to or away
from the FIQ signal. It also causes these callbacks to be registered
with the FIQ infrastructure.

This patch enable FIQ support for mach-versatile whilst mach-ep93xx,
mach-netx, mach-s3c64xx and plat-samsung are unmodified (and can therefore
continue to use init_FIQ() as before).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: linux-samsung-soc at vger.kernel.org
---
 arch/arm/mach-versatile/core.c  |  2 +-
 drivers/irqchip/irq-vic.c       | 92 ++++++++++++++++++++++++++++++++---------
 include/linux/irqchip/arm-vic.h |  6 ++-
 3 files changed, 78 insertions(+), 22 deletions(-)

diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 08fb8c8..bad1d30 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -108,7 +108,7 @@ void __init versatile_init_irq(void)
 
 	np = of_find_matching_node_by_address(NULL, vic_of_match,
 					      VERSATILE_VIC_BASE);
-	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np);
+	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np ? false : true, np);
 
 	writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
 
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287..22aa126 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -36,6 +36,9 @@
 
 #include <asm/exception.h>
 #include <asm/irq.h>
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 
 #include "irqchip.h"
 
@@ -261,11 +264,53 @@ static struct irq_domain_ops vic_irqdomain_ops = {
 	.xlate = irq_domain_xlate_onetwocell,
 };
 
+#ifdef CONFIG_FIQ
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
+static void vic_set_fiq(struct irq_data *d, bool enable)
+{
+	void __iomem *base = irq_data_get_irq_chip_data(d);
+	unsigned int irq = d->hwirq;
+	u32 val;
+
+	raw_spin_lock(&irq_controller_lock);
+	val = readl(base + VIC_INT_SELECT);
+	if (enable)
+		val |= 1 << irq;
+	else
+		val &= ~(1 << irq);
+	writel(val, base + VIC_INT_SELECT);
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void vic_enable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, true);
+}
+
+static void vic_disable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, false);
+}
+
+struct fiq_chip vic_fiq = {
+	.fiq_enable = vic_enable_fiq,
+	.fiq_disable = vic_disable_fiq,
+};
+
+static void vic_register_fiq(int irq)
+{
+	fiq_register_mapping(irq, &vic_fiq);
+}
+#else /* CONFIG_FIQ */
+static inline void vic_register_fiq(int irq) {}
+#endif /* CONFIG_FIQ */
+
 /**
  * vic_register() - Register a VIC.
  * @base: The base address of the VIC.
  * @parent_irq: The parent IRQ if cascaded, else 0.
- * @irq: The base IRQ for the VIC.
+ * @irq_start: The base IRQ for the VIC.
  * @valid_sources: bitmask of valid interrupts
  * @resume_sources: bitmask of interrupts allowed for resume sources.
  * @node: The device tree node associated with the VIC.
@@ -277,12 +322,13 @@ static struct irq_domain_ops vic_irqdomain_ops = {
  * This also configures the IRQ domain for the VIC.
  */
 static void __init vic_register(void __iomem *base, unsigned int parent_irq,
-				unsigned int irq,
+				unsigned int irq_start,
 				u32 valid_sources, u32 resume_sources,
-				struct device_node *node)
+				bool map_fiqs, struct device_node *node)
 {
 	struct vic_device *v;
 	int i;
+	unsigned int irq;
 
 	if (vic_id >= ARRAY_SIZE(vic_devices)) {
 		printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
@@ -301,15 +347,19 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 		irq_set_chained_handler(parent_irq, vic_handle_irq_cascaded);
 	}
 
-	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq,
+	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq_start,
 					  &vic_irqdomain_ops, v);
 	/* create an IRQ mapping for each valid IRQ */
-	for (i = 0; i < fls(valid_sources); i++)
-		if (valid_sources & (1 << i))
-			irq_create_mapping(v->domain, i);
+	for (i = 0; i < fls(valid_sources); i++) {
+		if (valid_sources & (1 << i)) {
+			irq = irq_create_mapping(v->domain, i);
+			vic_register_fiq(irq);
+		}
+	}
+
 	/* If no base IRQ was passed, figure out our allocated base */
-	if (irq)
-		v->irq = irq;
+	if (irq_start)
+		v->irq = irq_start;
 	else
 		v->irq = irq_find_mapping(v->domain, 0);
 }
@@ -413,7 +463,8 @@ static void __init vic_clear_interrupts(void __iomem *base)
  *  and 020 within the page. We call this "second block".
  */
 static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
-			       u32 vic_sources, struct device_node *node)
+			       u32 vic_sources, bool map_fiqs,
+			       struct device_node *node)
 {
 	unsigned int i;
 	int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
@@ -439,12 +490,12 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
 		writel(32, base + VIC_PL190_DEF_VECT_ADDR);
 	}
 
-	vic_register(base, 0, irq_start, vic_sources, 0, node);
+	vic_register(base, 0, irq_start, vic_sources, 0, map_fiqs, node);
 }
 
 void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
-			      u32 vic_sources, u32 resume_sources,
-			      struct device_node *node)
+		       u32 vic_sources, u32 resume_sources,
+		       bool map_fiqs, struct device_node *node)
 {
 	unsigned int i;
 	u32 cellid = 0;
@@ -462,7 +513,7 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	switch(vendor) {
 	case AMBA_VENDOR_ST:
-		vic_init_st(base, irq_start, vic_sources, node);
+		vic_init_st(base, irq_start, vic_sources, map_fiqs, node);
 		return;
 	default:
 		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
@@ -479,7 +530,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	vic_init2(base);
 
-	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);
+	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources,
+		     map_fiqs, node);
 }
 
 /**
@@ -492,7 +544,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 void __init vic_init(void __iomem *base, unsigned int irq_start,
 		     u32 vic_sources, u32 resume_sources)
 {
-	__vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL);
+	__vic_init(base, 0, irq_start, vic_sources, resume_sources,
+		   false, NULL);
 }
 
 /**
@@ -511,7 +564,8 @@ int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 	struct vic_device *v;
 
 	v = &vic_devices[vic_id];
-	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL);
+	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, false,
+		   NULL);
 	/* Return out acquired base */
 	return v->irq;
 }
@@ -535,9 +589,9 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
 	of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask);
 
 	/*
-	 * Passing 0 as first IRQ makes the simple domain allocate descriptors
+	 * Passing 0 as first IRQ makes the domain allocate descriptors.
 	 */
-	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
+	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, true, node);
 
 	return 0;
 }
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index ba46c79..30ab39f 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -30,8 +30,10 @@ struct device_node;
 struct pt_regs;
 
 void __vic_init(void __iomem *base, int parent_irq, int irq_start,
-		u32 vic_sources, u32 resume_sources, struct device_node *node);
-void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
+		u32 vic_sources, u32 resume_sources,
+		bool map_fiqs, struct device_node *node);
+void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources,
+	      u32 resume_sources);
 int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 		      u32 vic_sources, u32 resume_sources);
 
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 12/19] serial: kgdb_nmi: No CON_ENABLED by default
  2014-08-19 16:45                 ` Daniel Thompson
@ 2014-08-19 16:46                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

At present this console is selectively enabled/disabled by NULL checking
arch_kgdb_ops.enable_nmi. In practice this requires the architecture
dependant code to implement some kind of control (e.g. module arguments)
to enable/disable the feature.

The kernel already provide the perfectly adequade console= argument to
do this. Let's us that instead, if nothing else, it makes any
documentation architecture neutral.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/tty/serial/kgdb_nmi.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c
index 6ec7501..129dc5b 100644
--- a/drivers/tty/serial/kgdb_nmi.c
+++ b/drivers/tty/serial/kgdb_nmi.c
@@ -46,6 +46,8 @@ static atomic_t kgdb_nmi_num_readers = ATOMIC_INIT(0);
 
 static int kgdb_nmi_console_setup(struct console *co, char *options)
 {
+	arch_kgdb_ops.enable_nmi(1);
+
 	/* The NMI console uses the dbg_io_ops to issue console messages. To
 	 * avoid duplicate messages during kdb sessions we must inform kdb's
 	 * I/O utilities that messages sent to the console will automatically
@@ -77,7 +79,7 @@ static struct console kgdb_nmi_console = {
 	.setup  = kgdb_nmi_console_setup,
 	.write	= kgdb_nmi_console_write,
 	.device	= kgdb_nmi_console_device,
-	.flags	= CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED,
+	.flags	= CON_PRINTBUFFER | CON_ANYTIME,
 	.index	= -1,
 };
 
@@ -354,7 +356,6 @@ int kgdb_register_nmi_console(void)
 	}
 
 	register_console(&kgdb_nmi_console);
-	arch_kgdb_ops.enable_nmi(1);
 
 	return 0;
 err_drv_reg:
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 12/19] serial: kgdb_nmi: No CON_ENABLED by default
@ 2014-08-19 16:46                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: linux-arm-kernel

At present this console is selectively enabled/disabled by NULL checking
arch_kgdb_ops.enable_nmi. In practice this requires the architecture
dependant code to implement some kind of control (e.g. module arguments)
to enable/disable the feature.

The kernel already provide the perfectly adequade console= argument to
do this. Let's us that instead, if nothing else, it makes any
documentation architecture neutral.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/tty/serial/kgdb_nmi.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c
index 6ec7501..129dc5b 100644
--- a/drivers/tty/serial/kgdb_nmi.c
+++ b/drivers/tty/serial/kgdb_nmi.c
@@ -46,6 +46,8 @@ static atomic_t kgdb_nmi_num_readers = ATOMIC_INIT(0);
 
 static int kgdb_nmi_console_setup(struct console *co, char *options)
 {
+	arch_kgdb_ops.enable_nmi(1);
+
 	/* The NMI console uses the dbg_io_ops to issue console messages. To
 	 * avoid duplicate messages during kdb sessions we must inform kdb's
 	 * I/O utilities that messages sent to the console will automatically
@@ -77,7 +79,7 @@ static struct console kgdb_nmi_console = {
 	.setup  = kgdb_nmi_console_setup,
 	.write	= kgdb_nmi_console_write,
 	.device	= kgdb_nmi_console_device,
-	.flags	= CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED,
+	.flags	= CON_PRINTBUFFER | CON_ANYTIME,
 	.index	= -1,
 };
 
@@ -354,7 +356,6 @@ int kgdb_register_nmi_console(void)
 	}
 
 	register_console(&kgdb_nmi_console);
-	arch_kgdb_ops.enable_nmi(1);
 
 	return 0;
 err_drv_reg:
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 13/19] serial: amba-pl011: Use container_of() to get uart_amba_port
  2014-08-19 16:45                 ` Daniel Thompson
@ 2014-08-19 16:46                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

Universally adopt container_of() for all pointer conversion from
uart_port to uart_amba_port.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/tty/serial/amba-pl011.c | 54 +++++++++++++++++++++++++++--------------
 1 file changed, 36 insertions(+), 18 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 8572f2a..02016fc 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -678,7 +678,8 @@ static void pl011_dma_flush_buffer(struct uart_port *port)
 __releases(&uap->port.lock)
 __acquires(&uap->port.lock)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	if (!uap->using_tx_dma)
 		return;
@@ -1163,7 +1164,8 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
 
 static void pl011_stop_tx(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	uap->im &= ~UART011_TXIM;
 	writew(uap->im, uap->port.membase + UART011_IMSC);
@@ -1172,7 +1174,8 @@ static void pl011_stop_tx(struct uart_port *port)
 
 static void pl011_start_tx(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	if (!pl011_dma_tx_start(uap)) {
 		uap->im |= UART011_TXIM;
@@ -1182,7 +1185,8 @@ static void pl011_start_tx(struct uart_port *port)
 
 static void pl011_stop_rx(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
 		     UART011_PEIM|UART011_BEIM|UART011_OEIM);
@@ -1193,7 +1197,8 @@ static void pl011_stop_rx(struct uart_port *port)
 
 static void pl011_enable_ms(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM;
 	writew(uap->im, uap->port.membase + UART011_IMSC);
@@ -1349,14 +1354,16 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
 
 static unsigned int pl011_tx_empty(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int status = readw(uap->port.membase + UART01x_FR);
 	return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
 }
 
 static unsigned int pl011_get_mctrl(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int result = 0;
 	unsigned int status = readw(uap->port.membase + UART01x_FR);
 
@@ -1374,7 +1381,8 @@ static unsigned int pl011_get_mctrl(struct uart_port *port)
 
 static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int cr;
 
 	cr = readw(uap->port.membase + UART011_CR);
@@ -1402,7 +1410,8 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
 
 static void pl011_break_ctl(struct uart_port *port, int break_state)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned long flags;
 	unsigned int lcr_h;
 
@@ -1420,7 +1429,8 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
 
 static void pl011_quiesce_irqs(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned char __iomem *regs = uap->port.membase;
 
 	writew(readw(regs + UART011_MIS), regs + UART011_ICR);
@@ -1442,7 +1452,8 @@ static void pl011_quiesce_irqs(struct uart_port *port)
 
 static int pl011_get_poll_char(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int status;
 
 	/*
@@ -1461,7 +1472,8 @@ static int pl011_get_poll_char(struct uart_port *port)
 static void pl011_put_poll_char(struct uart_port *port,
 			 unsigned char ch)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
 		barrier();
@@ -1473,7 +1485,8 @@ static void pl011_put_poll_char(struct uart_port *port,
 
 static int pl011_hwinit(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	int retval;
 
 	/* Optionaly enable pins to be muxed in and configured */
@@ -1526,7 +1539,8 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
 
 static int pl011_startup(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int cr, lcr_h, fbrd, ibrd;
 	int retval;
 
@@ -1618,7 +1632,8 @@ static void pl011_shutdown_channel(struct uart_amba_port *uap,
 
 static void pl011_shutdown(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int cr;
 
 	/*
@@ -1680,7 +1695,8 @@ static void
 pl011_set_termios(struct uart_port *port, struct ktermios *termios,
 		     struct ktermios *old)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int lcr_h, old_cr;
 	unsigned long flags;
 	unsigned int baud, quot, clkdiv;
@@ -1822,7 +1838,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
 
 static const char *pl011_type(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	return uap->port.type == PORT_AMBA ? uap->type : NULL;
 }
 
@@ -1900,7 +1917,8 @@ static struct uart_amba_port *amba_ports[UART_NR];
 
 static void pl011_console_putchar(struct uart_port *port, int ch)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
 		barrier();
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 13/19] serial: amba-pl011: Use container_of() to get uart_amba_port
@ 2014-08-19 16:46                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: linux-arm-kernel

Universally adopt container_of() for all pointer conversion from
uart_port to uart_amba_port.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/tty/serial/amba-pl011.c | 54 +++++++++++++++++++++++++++--------------
 1 file changed, 36 insertions(+), 18 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 8572f2a..02016fc 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -678,7 +678,8 @@ static void pl011_dma_flush_buffer(struct uart_port *port)
 __releases(&uap->port.lock)
 __acquires(&uap->port.lock)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	if (!uap->using_tx_dma)
 		return;
@@ -1163,7 +1164,8 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
 
 static void pl011_stop_tx(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	uap->im &= ~UART011_TXIM;
 	writew(uap->im, uap->port.membase + UART011_IMSC);
@@ -1172,7 +1174,8 @@ static void pl011_stop_tx(struct uart_port *port)
 
 static void pl011_start_tx(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	if (!pl011_dma_tx_start(uap)) {
 		uap->im |= UART011_TXIM;
@@ -1182,7 +1185,8 @@ static void pl011_start_tx(struct uart_port *port)
 
 static void pl011_stop_rx(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
 		     UART011_PEIM|UART011_BEIM|UART011_OEIM);
@@ -1193,7 +1197,8 @@ static void pl011_stop_rx(struct uart_port *port)
 
 static void pl011_enable_ms(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM;
 	writew(uap->im, uap->port.membase + UART011_IMSC);
@@ -1349,14 +1354,16 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
 
 static unsigned int pl011_tx_empty(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int status = readw(uap->port.membase + UART01x_FR);
 	return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
 }
 
 static unsigned int pl011_get_mctrl(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int result = 0;
 	unsigned int status = readw(uap->port.membase + UART01x_FR);
 
@@ -1374,7 +1381,8 @@ static unsigned int pl011_get_mctrl(struct uart_port *port)
 
 static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int cr;
 
 	cr = readw(uap->port.membase + UART011_CR);
@@ -1402,7 +1410,8 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
 
 static void pl011_break_ctl(struct uart_port *port, int break_state)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned long flags;
 	unsigned int lcr_h;
 
@@ -1420,7 +1429,8 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
 
 static void pl011_quiesce_irqs(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned char __iomem *regs = uap->port.membase;
 
 	writew(readw(regs + UART011_MIS), regs + UART011_ICR);
@@ -1442,7 +1452,8 @@ static void pl011_quiesce_irqs(struct uart_port *port)
 
 static int pl011_get_poll_char(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int status;
 
 	/*
@@ -1461,7 +1472,8 @@ static int pl011_get_poll_char(struct uart_port *port)
 static void pl011_put_poll_char(struct uart_port *port,
 			 unsigned char ch)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
 		barrier();
@@ -1473,7 +1485,8 @@ static void pl011_put_poll_char(struct uart_port *port,
 
 static int pl011_hwinit(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	int retval;
 
 	/* Optionaly enable pins to be muxed in and configured */
@@ -1526,7 +1539,8 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
 
 static int pl011_startup(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int cr, lcr_h, fbrd, ibrd;
 	int retval;
 
@@ -1618,7 +1632,8 @@ static void pl011_shutdown_channel(struct uart_amba_port *uap,
 
 static void pl011_shutdown(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int cr;
 
 	/*
@@ -1680,7 +1695,8 @@ static void
 pl011_set_termios(struct uart_port *port, struct ktermios *termios,
 		     struct ktermios *old)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int lcr_h, old_cr;
 	unsigned long flags;
 	unsigned int baud, quot, clkdiv;
@@ -1822,7 +1838,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
 
 static const char *pl011_type(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	return uap->port.type == PORT_AMBA ? uap->type : NULL;
 }
 
@@ -1900,7 +1917,8 @@ static struct uart_amba_port *amba_ports[UART_NR];
 
 static void pl011_console_putchar(struct uart_port *port, int ch)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
 		barrier();
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 14/19] serial: amba-pl011: Move pl011_hwinit()
  2014-08-19 16:45                 ` Daniel Thompson
@ 2014-08-19 16:46                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Greg Kroah-Hartman, Jiri Slaby, linux-serial

This patch hoists pl011_hwinit() further up within the driver. This
permits a later patch to introduce an extended .poll_init callback
that does more than pure hardware initialization.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 78 ++++++++++++++++++++---------------------
 1 file changed, 39 insertions(+), 39 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 02016fc..0b06dcf 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1425,6 +1425,45 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
 	spin_unlock_irqrestore(&uap->port.lock, flags);
 }
 
+static int pl011_hwinit(struct uart_port *port)
+{
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
+	int retval;
+
+	/* Optionaly enable pins to be muxed in and configured */
+	pinctrl_pm_select_default_state(port->dev);
+
+	/*
+	 * Try to enable the clock producer.
+	 */
+	retval = clk_prepare_enable(uap->clk);
+	if (retval)
+		return retval;
+
+	uap->port.uartclk = clk_get_rate(uap->clk);
+
+	/* Clear pending error and receive interrupts */
+	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
+	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
+
+	/*
+	 * Save interrupts enable mask, and enable RX interrupts in case if
+	 * the interrupt is used for NMI entry.
+	 */
+	uap->im = readw(uap->port.membase + UART011_IMSC);
+	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
+
+	if (dev_get_platdata(uap->port.dev)) {
+		struct amba_pl011_data *plat;
+
+		plat = dev_get_platdata(uap->port.dev);
+		if (plat->init)
+			plat->init();
+	}
+	return 0;
+}
+
 #ifdef CONFIG_CONSOLE_POLL
 
 static void pl011_quiesce_irqs(struct uart_port *port)
@@ -1483,45 +1522,6 @@ static void pl011_put_poll_char(struct uart_port *port,
 
 #endif /* CONFIG_CONSOLE_POLL */
 
-static int pl011_hwinit(struct uart_port *port)
-{
-	struct uart_amba_port *uap =
-	    container_of(port, struct uart_amba_port, port);
-	int retval;
-
-	/* Optionaly enable pins to be muxed in and configured */
-	pinctrl_pm_select_default_state(port->dev);
-
-	/*
-	 * Try to enable the clock producer.
-	 */
-	retval = clk_prepare_enable(uap->clk);
-	if (retval)
-		return retval;
-
-	uap->port.uartclk = clk_get_rate(uap->clk);
-
-	/* Clear pending error and receive interrupts */
-	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
-	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
-
-	/*
-	 * Save interrupts enable mask, and enable RX interrupts in case if
-	 * the interrupt is used for NMI entry.
-	 */
-	uap->im = readw(uap->port.membase + UART011_IMSC);
-	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
-
-	if (dev_get_platdata(uap->port.dev)) {
-		struct amba_pl011_data *plat;
-
-		plat = dev_get_platdata(uap->port.dev);
-		if (plat->init)
-			plat->init();
-	}
-	return 0;
-}
-
 static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
 {
 	writew(lcr_h, uap->port.membase + uap->lcrh_rx);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 14/19] serial: amba-pl011: Move pl011_hwinit()
@ 2014-08-19 16:46                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: linux-arm-kernel

This patch hoists pl011_hwinit() further up within the driver. This
permits a later patch to introduce an extended .poll_init callback
that does more than pure hardware initialization.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 78 ++++++++++++++++++++---------------------
 1 file changed, 39 insertions(+), 39 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 02016fc..0b06dcf 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1425,6 +1425,45 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
 	spin_unlock_irqrestore(&uap->port.lock, flags);
 }
 
+static int pl011_hwinit(struct uart_port *port)
+{
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
+	int retval;
+
+	/* Optionaly enable pins to be muxed in and configured */
+	pinctrl_pm_select_default_state(port->dev);
+
+	/*
+	 * Try to enable the clock producer.
+	 */
+	retval = clk_prepare_enable(uap->clk);
+	if (retval)
+		return retval;
+
+	uap->port.uartclk = clk_get_rate(uap->clk);
+
+	/* Clear pending error and receive interrupts */
+	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
+	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
+
+	/*
+	 * Save interrupts enable mask, and enable RX interrupts in case if
+	 * the interrupt is used for NMI entry.
+	 */
+	uap->im = readw(uap->port.membase + UART011_IMSC);
+	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
+
+	if (dev_get_platdata(uap->port.dev)) {
+		struct amba_pl011_data *plat;
+
+		plat = dev_get_platdata(uap->port.dev);
+		if (plat->init)
+			plat->init();
+	}
+	return 0;
+}
+
 #ifdef CONFIG_CONSOLE_POLL
 
 static void pl011_quiesce_irqs(struct uart_port *port)
@@ -1483,45 +1522,6 @@ static void pl011_put_poll_char(struct uart_port *port,
 
 #endif /* CONFIG_CONSOLE_POLL */
 
-static int pl011_hwinit(struct uart_port *port)
-{
-	struct uart_amba_port *uap =
-	    container_of(port, struct uart_amba_port, port);
-	int retval;
-
-	/* Optionaly enable pins to be muxed in and configured */
-	pinctrl_pm_select_default_state(port->dev);
-
-	/*
-	 * Try to enable the clock producer.
-	 */
-	retval = clk_prepare_enable(uap->clk);
-	if (retval)
-		return retval;
-
-	uap->port.uartclk = clk_get_rate(uap->clk);
-
-	/* Clear pending error and receive interrupts */
-	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
-	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
-
-	/*
-	 * Save interrupts enable mask, and enable RX interrupts in case if
-	 * the interrupt is used for NMI entry.
-	 */
-	uap->im = readw(uap->port.membase + UART011_IMSC);
-	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
-
-	if (dev_get_platdata(uap->port.dev)) {
-		struct amba_pl011_data *plat;
-
-		plat = dev_get_platdata(uap->port.dev);
-		if (plat->init)
-			plat->init();
-	}
-	return 0;
-}
-
 static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
 {
 	writew(lcr_h, uap->port.membase + uap->lcrh_rx);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 15/19] serial: amba-pl011: Pass FIQ information to KGDB.
  2014-08-19 16:45                 ` Daniel Thompson
@ 2014-08-19 16:46                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Greg Kroah-Hartman, Jiri Slaby, linux-serial

Speculatively register a FIQ resource with KGDB. KGDB will only
accept it if the kgdb/fiq feature is enabled (both with compile time and
runtime switches) and the interrupt controller supports FIQ.

By providing this information to KGDB the serial driver offers
"permission" for KGDB to route the UART interrupt signal from the
drivers own handler to KGDBs FIQ handler (which will eventually use the
UART's polled I/O callbacks to interact with the user). This permission
also implies the amba-pl011 driver has already unmasked RX interrupts
(otherwise the FIQ handler will never trigger).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 0b06dcf..63c67b0 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -58,6 +58,7 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/sizes.h>
 #include <linux/io.h>
+#include <linux/kgdb.h>
 
 #define UART_NR			14
 
@@ -1466,6 +1467,18 @@ static int pl011_hwinit(struct uart_port *port)
 
 #ifdef CONFIG_CONSOLE_POLL
 
+static int pl011_poll_init(struct uart_port *port)
+{
+	int retval = pl011_hwinit(port);
+
+#ifdef CONFIG_KGDB_FIQ
+	if (retval == 0)
+		kgdb_register_fiq(port->irq);
+#endif
+
+	return retval;
+}
+
 static void pl011_quiesce_irqs(struct uart_port *port)
 {
 	struct uart_amba_port *uap =
@@ -1905,7 +1918,7 @@ static struct uart_ops amba_pl011_pops = {
 	.config_port	= pl011_config_port,
 	.verify_port	= pl011_verify_port,
 #ifdef CONFIG_CONSOLE_POLL
-	.poll_init     = pl011_hwinit,
+	.poll_init     = pl011_poll_init,
 	.poll_get_char = pl011_get_poll_char,
 	.poll_put_char = pl011_put_poll_char,
 #endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 15/19] serial: amba-pl011: Pass FIQ information to KGDB.
@ 2014-08-19 16:46                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: linux-arm-kernel

Speculatively register a FIQ resource with KGDB. KGDB will only
accept it if the kgdb/fiq feature is enabled (both with compile time and
runtime switches) and the interrupt controller supports FIQ.

By providing this information to KGDB the serial driver offers
"permission" for KGDB to route the UART interrupt signal from the
drivers own handler to KGDBs FIQ handler (which will eventually use the
UART's polled I/O callbacks to interact with the user). This permission
also implies the amba-pl011 driver has already unmasked RX interrupts
(otherwise the FIQ handler will never trigger).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 0b06dcf..63c67b0 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -58,6 +58,7 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/sizes.h>
 #include <linux/io.h>
+#include <linux/kgdb.h>
 
 #define UART_NR			14
 
@@ -1466,6 +1467,18 @@ static int pl011_hwinit(struct uart_port *port)
 
 #ifdef CONFIG_CONSOLE_POLL
 
+static int pl011_poll_init(struct uart_port *port)
+{
+	int retval = pl011_hwinit(port);
+
+#ifdef CONFIG_KGDB_FIQ
+	if (retval == 0)
+		kgdb_register_fiq(port->irq);
+#endif
+
+	return retval;
+}
+
 static void pl011_quiesce_irqs(struct uart_port *port)
 {
 	struct uart_amba_port *uap =
@@ -1905,7 +1918,7 @@ static struct uart_ops amba_pl011_pops = {
 	.config_port	= pl011_config_port,
 	.verify_port	= pl011_verify_port,
 #ifdef CONFIG_CONSOLE_POLL
-	.poll_init     = pl011_hwinit,
+	.poll_init     = pl011_poll_init,
 	.poll_get_char = pl011_get_poll_char,
 	.poll_put_char = pl011_put_poll_char,
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 16/19] serial: asc: Add support for KGDB's FIQ/NMI mode
  2014-08-19 16:45                 ` Daniel Thompson
  (?)
@ 2014-08-19 16:46                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Srinivas Kandagatla, Maxime Coquelin,
	Patrice Chotard, Greg Kroah-Hartman, Jiri Slaby, kernel,
	linux-serial

Add a .poll_init() function that enables UART RX and registers the
UART's irq with KGDB. By providing this information to KGDB the serial
driver offers "permission" for KGDB to route the UART interrupt signal
from the drivers own handler to KGDBs FIQ handler (which will eventually
use the UART's polled I/O callbacks to interact with the user).

Note that the RX is not only enabled but also unmasked. This is required
because otherwise the FIQ handler could never trigger. This unmask is
copied from similar code in amba-pl011.c .

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel@stlinux.com
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 8b2d735..2b5eb6e 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -30,6 +30,7 @@
 #include <linux/of_platform.h>
 #include <linux/serial_core.h>
 #include <linux/clk.h>
+#include <linux/kgdb.h>
 
 #define DRIVER_NAME "st-asc"
 #define ASC_SERIAL_NAME "ttyAS"
@@ -607,6 +608,25 @@ asc_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+
+#ifdef CONFIG_KGDB_FIQ
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int asc_poll_init(struct uart_port *port)
+{
+	struct asc_port *ascport = container_of(port, struct asc_port, port);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(ascport->port.irq);
+
+	/* enable RX interrupts in case the interrupt is used for NMI entry. */
+	asc_enable_rx_interrupts(port);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 /*
  * Console polling routines for writing and reading from the uart while
  * in an interrupt or debug context (i.e. kgdb).
@@ -649,6 +669,9 @@ static struct uart_ops asc_uart_ops = {
 	.verify_port	= asc_verify_port,
 	.pm		= asc_pm,
 #ifdef CONFIG_CONSOLE_POLL
+#ifdef CONFIG_KGDB_FIQ
+	.poll_init     = asc_poll_init,
+#endif /* CONFIG_KGDB_FIQ */
 	.poll_get_char = asc_get_poll_char,
 	.poll_put_char = asc_put_poll_char,
 #endif /* CONFIG_CONSOLE_POLL */
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 16/19] serial: asc: Add support for KGDB's FIQ/NMI mode
@ 2014-08-19 16:46                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Srinivas Kandagatla, Maxime Coquelin,
	Patrice Chotard, Greg Kroah-Hartman, Jiri Slaby, kernel

Add a .poll_init() function that enables UART RX and registers the
UART's irq with KGDB. By providing this information to KGDB the serial
driver offers "permission" for KGDB to route the UART interrupt signal
from the drivers own handler to KGDBs FIQ handler (which will eventually
use the UART's polled I/O callbacks to interact with the user).

Note that the RX is not only enabled but also unmasked. This is required
because otherwise the FIQ handler could never trigger. This unmask is
copied from similar code in amba-pl011.c .

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel@stlinux.com
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 8b2d735..2b5eb6e 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -30,6 +30,7 @@
 #include <linux/of_platform.h>
 #include <linux/serial_core.h>
 #include <linux/clk.h>
+#include <linux/kgdb.h>
 
 #define DRIVER_NAME "st-asc"
 #define ASC_SERIAL_NAME "ttyAS"
@@ -607,6 +608,25 @@ asc_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+
+#ifdef CONFIG_KGDB_FIQ
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int asc_poll_init(struct uart_port *port)
+{
+	struct asc_port *ascport = container_of(port, struct asc_port, port);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(ascport->port.irq);
+
+	/* enable RX interrupts in case the interrupt is used for NMI entry. */
+	asc_enable_rx_interrupts(port);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 /*
  * Console polling routines for writing and reading from the uart while
  * in an interrupt or debug context (i.e. kgdb).
@@ -649,6 +669,9 @@ static struct uart_ops asc_uart_ops = {
 	.verify_port	= asc_verify_port,
 	.pm		= asc_pm,
 #ifdef CONFIG_CONSOLE_POLL
+#ifdef CONFIG_KGDB_FIQ
+	.poll_init     = asc_poll_init,
+#endif /* CONFIG_KGDB_FIQ */
 	.poll_get_char = asc_get_poll_char,
 	.poll_put_char = asc_put_poll_char,
 #endif /* CONFIG_CONSOLE_POLL */
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 16/19] serial: asc: Add support for KGDB's FIQ/NMI mode
@ 2014-08-19 16:46                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: linux-arm-kernel

Add a .poll_init() function that enables UART RX and registers the
UART's irq with KGDB. By providing this information to KGDB the serial
driver offers "permission" for KGDB to route the UART interrupt signal
from the drivers own handler to KGDBs FIQ handler (which will eventually
use the UART's polled I/O callbacks to interact with the user).

Note that the RX is not only enabled but also unmasked. This is required
because otherwise the FIQ handler could never trigger. This unmask is
copied from similar code in amba-pl011.c .

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel at stlinux.com
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 8b2d735..2b5eb6e 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -30,6 +30,7 @@
 #include <linux/of_platform.h>
 #include <linux/serial_core.h>
 #include <linux/clk.h>
+#include <linux/kgdb.h>
 
 #define DRIVER_NAME "st-asc"
 #define ASC_SERIAL_NAME "ttyAS"
@@ -607,6 +608,25 @@ asc_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+
+#ifdef CONFIG_KGDB_FIQ
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int asc_poll_init(struct uart_port *port)
+{
+	struct asc_port *ascport = container_of(port, struct asc_port, port);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(ascport->port.irq);
+
+	/* enable RX interrupts in case the interrupt is used for NMI entry. */
+	asc_enable_rx_interrupts(port);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 /*
  * Console polling routines for writing and reading from the uart while
  * in an interrupt or debug context (i.e. kgdb).
@@ -649,6 +669,9 @@ static struct uart_ops asc_uart_ops = {
 	.verify_port	= asc_verify_port,
 	.pm		= asc_pm,
 #ifdef CONFIG_CONSOLE_POLL
+#ifdef CONFIG_KGDB_FIQ
+	.poll_init     = asc_poll_init,
+#endif /* CONFIG_KGDB_FIQ */
 	.poll_get_char = asc_get_poll_char,
 	.poll_put_char = asc_put_poll_char,
 #endif /* CONFIG_CONSOLE_POLL */
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 17/19] serial: asc: Adopt readl_/writel_relaxed()
  2014-08-19 16:45                 ` Daniel Thompson
  (?)
@ 2014-08-19 16:46                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Srinivas Kandagatla, Maxime Coquelin,
	Patrice Chotard, Greg Kroah-Hartman, Jiri Slaby, kernel,
	linux-serial

The architectures where this peripheral exists (ARM and SH) have expensive
implementations of writel(), reliant on spin locks and explicit L2 cache
management. These architectures provide a cheaper writel_relaxed() which
is much better suited to peripherals that do not perform DMA. The
situation with readl()/readl_relaxed()is similar although less acute.

This driver does not use DMA and will be more power efficient and more
robust (due to absense of spin locks during console I/O) if it uses the
relaxed variants.

This change means the driver is no longer portable and therefore no
longer suitable for compile testing.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel@stlinux.com
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/Kconfig  | 2 +-
 drivers/tty/serial/st-asc.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 26cec64..e9b1735 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1527,7 +1527,7 @@ config SERIAL_FSL_LPUART_CONSOLE
 config SERIAL_ST_ASC
 	tristate "ST ASC serial port support"
 	select SERIAL_CORE
-	depends on ARM || COMPILE_TEST
+	depends on ARM
 	help
 	  This driver is for the on-chip Asychronous Serial Controller on
 	  STMicroelectronics STi SoCs.
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 2b5eb6e..df709ee 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -152,12 +152,12 @@ static inline struct asc_port *to_asc_port(struct uart_port *port)
 
 static inline u32 asc_in(struct uart_port *port, u32 offset)
 {
-	return readl(port->membase + offset);
+	return readl_relaxed(port->membase + offset);
 }
 
 static inline void asc_out(struct uart_port *port, u32 offset, u32 value)
 {
-	writel(value, port->membase + offset);
+	writel_relaxed(value, port->membase + offset);
 }
 
 /*
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 17/19] serial: asc: Adopt readl_/writel_relaxed()
@ 2014-08-19 16:46                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Srinivas Kandagatla, Maxime Coquelin,
	Patrice Chotard, Greg Kroah-Hartman, Jiri Slaby, kernel

The architectures where this peripheral exists (ARM and SH) have expensive
implementations of writel(), reliant on spin locks and explicit L2 cache
management. These architectures provide a cheaper writel_relaxed() which
is much better suited to peripherals that do not perform DMA. The
situation with readl()/readl_relaxed()is similar although less acute.

This driver does not use DMA and will be more power efficient and more
robust (due to absense of spin locks during console I/O) if it uses the
relaxed variants.

This change means the driver is no longer portable and therefore no
longer suitable for compile testing.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel@stlinux.com
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/Kconfig  | 2 +-
 drivers/tty/serial/st-asc.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 26cec64..e9b1735 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1527,7 +1527,7 @@ config SERIAL_FSL_LPUART_CONSOLE
 config SERIAL_ST_ASC
 	tristate "ST ASC serial port support"
 	select SERIAL_CORE
-	depends on ARM || COMPILE_TEST
+	depends on ARM
 	help
 	  This driver is for the on-chip Asychronous Serial Controller on
 	  STMicroelectronics STi SoCs.
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 2b5eb6e..df709ee 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -152,12 +152,12 @@ static inline struct asc_port *to_asc_port(struct uart_port *port)
 
 static inline u32 asc_in(struct uart_port *port, u32 offset)
 {
-	return readl(port->membase + offset);
+	return readl_relaxed(port->membase + offset);
 }
 
 static inline void asc_out(struct uart_port *port, u32 offset, u32 value)
 {
-	writel(value, port->membase + offset);
+	writel_relaxed(value, port->membase + offset);
 }
 
 /*
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 17/19] serial: asc: Adopt readl_/writel_relaxed()
@ 2014-08-19 16:46                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: linux-arm-kernel

The architectures where this peripheral exists (ARM and SH) have expensive
implementations of writel(), reliant on spin locks and explicit L2 cache
management. These architectures provide a cheaper writel_relaxed() which
is much better suited to peripherals that do not perform DMA. The
situation with readl()/readl_relaxed()is similar although less acute.

This driver does not use DMA and will be more power efficient and more
robust (due to absense of spin locks during console I/O) if it uses the
relaxed variants.

This change means the driver is no longer portable and therefore no
longer suitable for compile testing.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel at stlinux.com
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/Kconfig  | 2 +-
 drivers/tty/serial/st-asc.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 26cec64..e9b1735 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1527,7 +1527,7 @@ config SERIAL_FSL_LPUART_CONSOLE
 config SERIAL_ST_ASC
 	tristate "ST ASC serial port support"
 	select SERIAL_CORE
-	depends on ARM || COMPILE_TEST
+	depends on ARM
 	help
 	  This driver is for the on-chip Asychronous Serial Controller on
 	  STMicroelectronics STi SoCs.
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 2b5eb6e..df709ee 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -152,12 +152,12 @@ static inline struct asc_port *to_asc_port(struct uart_port *port)
 
 static inline u32 asc_in(struct uart_port *port, u32 offset)
 {
-	return readl(port->membase + offset);
+	return readl_relaxed(port->membase + offset);
 }
 
 static inline void asc_out(struct uart_port *port, u32 offset, u32 value)
 {
-	writel(value, port->membase + offset);
+	writel_relaxed(value, port->membase + offset);
 }
 
 /*
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 18/19] serial: imx: clean up imx_poll_get_char()
  2014-08-19 16:45                 ` Daniel Thompson
@ 2014-08-19 16:46                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: Russell King
  Cc: Dirk Behme, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Daniel Thompson, Greg Kroah-Hartman, Jiri Slaby,
	linux-serial

From: Dirk Behme <dirk.behme@de.bosch.com>

Looking at the get_poll_char() function of the 8250.c serial driver,
we learn:

* poll_get_char() doesn't have to save/disable/restore the interrupt
  registers. No interrupt handling is needed in this function at all.
  Remove it.

* Don't block in case there is no data available. So instead blocking
  in the do {} while loop, just return with NO_POLL_CHAR, immediately .

Additionally, while the i.MX6 register URXD[7-0] contain the RX_DATA,
the upper bits of this register (URXD[15-10]) might contain some
control flags. To ensure that these are not returned with the data
read, just mask out URXD[7-0].

These changes fix the 'hang' working with kdb:

$ echo ttymxc3 > /sys/module/kgdboc/parameters/kgdboc
$ echo g >/proc/sysrq-trigger
[0]kdb> help
...
<hang>

Signed-off-by: Dirk Behme <dirk.behme@de.bosch.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/imx.c | 29 ++++-------------------------
 1 file changed, 4 insertions(+), 25 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 044e86d..983668a 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -80,6 +80,7 @@
 #define URXD_FRMERR	(1<<12)
 #define URXD_BRK	(1<<11)
 #define URXD_PRERR	(1<<10)
+#define URXD_RX_DATA	(0xFF<<0)
 #define UCR1_ADEN	(1<<15) /* Auto detect interrupt */
 #define UCR1_ADBR	(1<<14) /* Auto detect baud rate */
 #define UCR1_TRDYEN	(1<<13) /* Transmitter ready interrupt enable */
@@ -1506,32 +1507,10 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
 #if defined(CONFIG_CONSOLE_POLL)
 static int imx_poll_get_char(struct uart_port *port)
 {
-	struct imx_port_ucrs old_ucr;
-	unsigned int status;
-	unsigned char c;
-
-	/* save control registers */
-	imx_port_ucrs_save(port, &old_ucr);
-
-	/* disable interrupts */
-	writel(UCR1_UARTEN, port->membase + UCR1);
-	writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
-	       port->membase + UCR2);
-	writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
-	       port->membase + UCR3);
-
-	/* poll */
-	do {
-		status = readl(port->membase + USR2);
-	} while (~status & USR2_RDR);
-
-	/* read */
-	c = readl(port->membase + URXD0);
-
-	/* restore control registers */
-	imx_port_ucrs_restore(port, &old_ucr);
+	if (!(readl(port->membase + USR2) & USR2_RDR))
+		return NO_POLL_CHAR;
 
-	return c;
+	return readl(port->membase + URXD0) & URXD_RX_DATA;
 }
 
 static void imx_poll_put_char(struct uart_port *port, unsigned char c)
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 18/19] serial: imx: clean up imx_poll_get_char()
@ 2014-08-19 16:46                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: linux-arm-kernel

From: Dirk Behme <dirk.behme@de.bosch.com>

Looking at the get_poll_char() function of the 8250.c serial driver,
we learn:

* poll_get_char() doesn't have to save/disable/restore the interrupt
  registers. No interrupt handling is needed in this function at all.
  Remove it.

* Don't block in case there is no data available. So instead blocking
  in the do {} while loop, just return with NO_POLL_CHAR, immediately .

Additionally, while the i.MX6 register URXD[7-0] contain the RX_DATA,
the upper bits of this register (URXD[15-10]) might contain some
control flags. To ensure that these are not returned with the data
read, just mask out URXD[7-0].

These changes fix the 'hang' working with kdb:

$ echo ttymxc3 > /sys/module/kgdboc/parameters/kgdboc
$ echo g >/proc/sysrq-trigger
[0]kdb> help
...
<hang>

Signed-off-by: Dirk Behme <dirk.behme@de.bosch.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/imx.c | 29 ++++-------------------------
 1 file changed, 4 insertions(+), 25 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 044e86d..983668a 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -80,6 +80,7 @@
 #define URXD_FRMERR	(1<<12)
 #define URXD_BRK	(1<<11)
 #define URXD_PRERR	(1<<10)
+#define URXD_RX_DATA	(0xFF<<0)
 #define UCR1_ADEN	(1<<15) /* Auto detect interrupt */
 #define UCR1_ADBR	(1<<14) /* Auto detect baud rate */
 #define UCR1_TRDYEN	(1<<13) /* Transmitter ready interrupt enable */
@@ -1506,32 +1507,10 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
 #if defined(CONFIG_CONSOLE_POLL)
 static int imx_poll_get_char(struct uart_port *port)
 {
-	struct imx_port_ucrs old_ucr;
-	unsigned int status;
-	unsigned char c;
-
-	/* save control registers */
-	imx_port_ucrs_save(port, &old_ucr);
-
-	/* disable interrupts */
-	writel(UCR1_UARTEN, port->membase + UCR1);
-	writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
-	       port->membase + UCR2);
-	writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
-	       port->membase + UCR3);
-
-	/* poll */
-	do {
-		status = readl(port->membase + USR2);
-	} while (~status & USR2_RDR);
-
-	/* read */
-	c = readl(port->membase + URXD0);
-
-	/* restore control registers */
-	imx_port_ucrs_restore(port, &old_ucr);
+	if (!(readl(port->membase + USR2) & USR2_RDR))
+		return NO_POLL_CHAR;
 
-	return c;
+	return readl(port->membase + URXD0) & URXD_RX_DATA;
 }
 
 static void imx_poll_put_char(struct uart_port *port, unsigned char c)
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 19/19] serial: imx: Add support for KGDB's FIQ/NMI mode
  2014-08-19 16:45                 ` Daniel Thompson
@ 2014-08-19 16:46                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Greg Kroah-Hartman, Jiri Slaby, linux-serial

This patch makes it possible to use the imx uart with KGDB's FIQ/NMI
mode.

Main changes are:

.poll_init() will, if KGDB+FIQ are enabled, perform deeper hardware
initialization to ensure the serial port is always active (required
otherwise FIQ is not triggered by UART activity). This has an impact on
power usage so it is conservatively enabled.

imx_put_poll_char() has been simplified to remove the code to disable
interrupts. The present code can corrupt register state when re-entered
from FIQ handler.

Both imx_put_poll_char() and imx_get_poll_char() adopt _relaxed()
MMIO functions (which are safe for polled I/O and needed to avoid taking
spin locks).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
Acked-by: Dirk Behme <dirk.behme@de.bosch.com>
---
 drivers/tty/serial/imx.c | 71 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 52 insertions(+), 19 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 983668a..a201c61 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -49,6 +49,7 @@
 #include <linux/of_device.h>
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
+#include <linux/kgdb.h>
 
 #include <asm/irq.h>
 #include <linux/platform_data/serial-imx.h>
@@ -1505,44 +1506,73 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #if defined(CONFIG_CONSOLE_POLL)
+
+#if defined(CONFIG_KGDB_FIQ)
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int imx_poll_init(struct uart_port *port)
+{
+	struct imx_port *sport = (struct imx_port *)port;
+	unsigned long flags;
+	unsigned long temp;
+	int retval;
+
+	retval = clk_prepare_enable(sport->clk_ipg);
+	if (retval)
+		return retval;
+	retval = clk_prepare_enable(sport->clk_per);
+	if (retval)
+		clk_disable_unprepare(sport->clk_ipg);
+
+	imx_setup_ufcr(sport, 0);
+
+	spin_lock_irqsave(&sport->port.lock, flags);
+
+	temp = readl(sport->port.membase + UCR1);
+	if (is_imx1_uart(sport))
+		temp |= IMX1_UCR1_UARTCLKEN;
+	temp |= UCR1_UARTEN | UCR1_RRDYEN;
+	temp &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN);
+	writel(temp, sport->port.membase + UCR1);
+
+	temp = readl(sport->port.membase + UCR2);
+	temp |= UCR2_RXEN;
+	writel(temp, sport->port.membase + UCR2);
+
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(sport->port.irq);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 static int imx_poll_get_char(struct uart_port *port)
 {
-	if (!(readl(port->membase + USR2) & USR2_RDR))
+	if (!(readl_relaxed(port->membase + USR2) & USR2_RDR))
 		return NO_POLL_CHAR;
 
-	return readl(port->membase + URXD0) & URXD_RX_DATA;
+	return readl_relaxed(port->membase + URXD0) & URXD_RX_DATA;
 }
 
 static void imx_poll_put_char(struct uart_port *port, unsigned char c)
 {
-	struct imx_port_ucrs old_ucr;
 	unsigned int status;
 
-	/* save control registers */
-	imx_port_ucrs_save(port, &old_ucr);
-
-	/* disable interrupts */
-	writel(UCR1_UARTEN, port->membase + UCR1);
-	writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
-	       port->membase + UCR2);
-	writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
-	       port->membase + UCR3);
-
 	/* drain */
 	do {
-		status = readl(port->membase + USR1);
+		status = readl_relaxed(port->membase + USR1);
 	} while (~status & USR1_TRDY);
 
 	/* write */
-	writel(c, port->membase + URTX0);
+	writel_relaxed(c, port->membase + URTX0);
 
 	/* flush */
 	do {
-		status = readl(port->membase + USR2);
+		status = readl_relaxed(port->membase + USR2);
 	} while (~status & USR2_TXDC);
-
-	/* restore control registers */
-	imx_port_ucrs_restore(port, &old_ucr);
 }
 #endif
 
@@ -1563,6 +1593,9 @@ static struct uart_ops imx_pops = {
 	.config_port	= imx_config_port,
 	.verify_port	= imx_verify_port,
 #if defined(CONFIG_CONSOLE_POLL)
+#if defined(CONFIG_KGDB_FIQ)
+	.poll_init      = imx_poll_init,
+#endif
 	.poll_get_char  = imx_poll_get_char,
 	.poll_put_char  = imx_poll_put_char,
 #endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 19/19] serial: imx: Add support for KGDB's FIQ/NMI mode
@ 2014-08-19 16:46                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 16:46 UTC (permalink / raw)
  To: linux-arm-kernel

This patch makes it possible to use the imx uart with KGDB's FIQ/NMI
mode.

Main changes are:

.poll_init() will, if KGDB+FIQ are enabled, perform deeper hardware
initialization to ensure the serial port is always active (required
otherwise FIQ is not triggered by UART activity). This has an impact on
power usage so it is conservatively enabled.

imx_put_poll_char() has been simplified to remove the code to disable
interrupts. The present code can corrupt register state when re-entered
from FIQ handler.

Both imx_put_poll_char() and imx_get_poll_char() adopt _relaxed()
MMIO functions (which are safe for polled I/O and needed to avoid taking
spin locks).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial at vger.kernel.org
Acked-by: Dirk Behme <dirk.behme@de.bosch.com>
---
 drivers/tty/serial/imx.c | 71 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 52 insertions(+), 19 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 983668a..a201c61 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -49,6 +49,7 @@
 #include <linux/of_device.h>
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
+#include <linux/kgdb.h>
 
 #include <asm/irq.h>
 #include <linux/platform_data/serial-imx.h>
@@ -1505,44 +1506,73 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #if defined(CONFIG_CONSOLE_POLL)
+
+#if defined(CONFIG_KGDB_FIQ)
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int imx_poll_init(struct uart_port *port)
+{
+	struct imx_port *sport = (struct imx_port *)port;
+	unsigned long flags;
+	unsigned long temp;
+	int retval;
+
+	retval = clk_prepare_enable(sport->clk_ipg);
+	if (retval)
+		return retval;
+	retval = clk_prepare_enable(sport->clk_per);
+	if (retval)
+		clk_disable_unprepare(sport->clk_ipg);
+
+	imx_setup_ufcr(sport, 0);
+
+	spin_lock_irqsave(&sport->port.lock, flags);
+
+	temp = readl(sport->port.membase + UCR1);
+	if (is_imx1_uart(sport))
+		temp |= IMX1_UCR1_UARTCLKEN;
+	temp |= UCR1_UARTEN | UCR1_RRDYEN;
+	temp &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN);
+	writel(temp, sport->port.membase + UCR1);
+
+	temp = readl(sport->port.membase + UCR2);
+	temp |= UCR2_RXEN;
+	writel(temp, sport->port.membase + UCR2);
+
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(sport->port.irq);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 static int imx_poll_get_char(struct uart_port *port)
 {
-	if (!(readl(port->membase + USR2) & USR2_RDR))
+	if (!(readl_relaxed(port->membase + USR2) & USR2_RDR))
 		return NO_POLL_CHAR;
 
-	return readl(port->membase + URXD0) & URXD_RX_DATA;
+	return readl_relaxed(port->membase + URXD0) & URXD_RX_DATA;
 }
 
 static void imx_poll_put_char(struct uart_port *port, unsigned char c)
 {
-	struct imx_port_ucrs old_ucr;
 	unsigned int status;
 
-	/* save control registers */
-	imx_port_ucrs_save(port, &old_ucr);
-
-	/* disable interrupts */
-	writel(UCR1_UARTEN, port->membase + UCR1);
-	writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
-	       port->membase + UCR2);
-	writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
-	       port->membase + UCR3);
-
 	/* drain */
 	do {
-		status = readl(port->membase + USR1);
+		status = readl_relaxed(port->membase + USR1);
 	} while (~status & USR1_TRDY);
 
 	/* write */
-	writel(c, port->membase + URTX0);
+	writel_relaxed(c, port->membase + URTX0);
 
 	/* flush */
 	do {
-		status = readl(port->membase + USR2);
+		status = readl_relaxed(port->membase + USR2);
 	} while (~status & USR2_TXDC);
-
-	/* restore control registers */
-	imx_port_ucrs_restore(port, &old_ucr);
 }
 #endif
 
@@ -1563,6 +1593,9 @@ static struct uart_ops imx_pops = {
 	.config_port	= imx_config_port,
 	.verify_port	= imx_verify_port,
 #if defined(CONFIG_CONSOLE_POLL)
+#if defined(CONFIG_KGDB_FIQ)
+	.poll_init      = imx_poll_init,
+#endif
 	.poll_get_char  = imx_poll_get_char,
 	.poll_put_char  = imx_poll_put_char,
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
  2014-08-19 16:45                   ` Daniel Thompson
@ 2014-08-19 17:37                     ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-08-19 17:37 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: linux-kernel, linux-arm-kernel, kgdb-bugreport, patches,
	linaro-kernel, John Stultz, Anton Vorontsov, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

On Tue, Aug 19, 2014 at 05:45:53PM +0100, Daniel Thompson wrote:
> +int register_fiq_nmi_notifier(struct notifier_block *nb)
> +{
> +	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
> +}
> +
> +asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
> +{
> +	struct pt_regs *old_regs = set_irq_regs(regs);
> +
> +	nmi_enter();
> +	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
> +	nmi_exit();
> +	set_irq_regs(old_regs);
> +}

Really not happy with this.  What happens if a FIQ occurs while we're
inside register_fiq_nmi_notifier() - more specifically inside
atomic_notifier_chain_register() ?

This is how easy it is to end up with a deadlock-able situation with
FIQs, and it is why I said:

| > 2. Have default trap handler call an RCU notifier chain to allow it to
| >    hook up with "normal" code without any hard coding (kgdb, IPI
| >    handling, etc)
| 
| Maybe... that sounds like it opens up FIQ for general purpose use which
| is something I want to avoid - I've little motivation to ensure that
| everyone plays by the rules.  Given the choice, I'd rather maintain our
| present stance that using FIQs is hard and requires a lot of thought.

You've just proven my point.

So, what I want is to make FIQs hard to use.  No notifier chain at all
please, people can't be trusted to know all the details (even if they
do know the details, it's just been proven that it's incredibly difficult
to do it right.)

What I instead want to see is that users get added to the above code
fragment with #ifdef's around the calls - that way ensuring that people
have to modify this file, and therefore /should/ be copying me with
their patches.  That means less chance for someone to sneak a change
in by merely calling some register function without first having to
copy this mailing list.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
@ 2014-08-19 17:37                     ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-08-19 17:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Aug 19, 2014 at 05:45:53PM +0100, Daniel Thompson wrote:
> +int register_fiq_nmi_notifier(struct notifier_block *nb)
> +{
> +	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
> +}
> +
> +asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
> +{
> +	struct pt_regs *old_regs = set_irq_regs(regs);
> +
> +	nmi_enter();
> +	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
> +	nmi_exit();
> +	set_irq_regs(old_regs);
> +}

Really not happy with this.  What happens if a FIQ occurs while we're
inside register_fiq_nmi_notifier() - more specifically inside
atomic_notifier_chain_register() ?

This is how easy it is to end up with a deadlock-able situation with
FIQs, and it is why I said:

| > 2. Have default trap handler call an RCU notifier chain to allow it to
| >    hook up with "normal" code without any hard coding (kgdb, IPI
| >    handling, etc)
| 
| Maybe... that sounds like it opens up FIQ for general purpose use which
| is something I want to avoid - I've little motivation to ensure that
| everyone plays by the rules.  Given the choice, I'd rather maintain our
| present stance that using FIQs is hard and requires a lot of thought.

You've just proven my point.

So, what I want is to make FIQs hard to use.  No notifier chain at all
please, people can't be trusted to know all the details (even if they
do know the details, it's just been proven that it's incredibly difficult
to do it right.)

What I instead want to see is that users get added to the above code
fragment with #ifdef's around the calls - that way ensuring that people
have to modify this file, and therefore /should/ be copying me with
their patches.  That means less chance for someone to sneak a change
in by merely calling some register function without first having to
copy this mailing list.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
  2014-08-19 17:37                     ` Russell King - ARM Linux
@ 2014-08-19 18:12                       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 18:12 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linux-kernel, linux-arm-kernel, kgdb-bugreport, patches,
	linaro-kernel, John Stultz, Anton Vorontsov, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

On 19/08/14 18:37, Russell King - ARM Linux wrote:
> On Tue, Aug 19, 2014 at 05:45:53PM +0100, Daniel Thompson wrote:
>> +int register_fiq_nmi_notifier(struct notifier_block *nb)
>> +{
>> +	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
>> +}
>> +
>> +asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
>> +{
>> +	struct pt_regs *old_regs = set_irq_regs(regs);
>> +
>> +	nmi_enter();
>> +	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
>> +	nmi_exit();
>> +	set_irq_regs(old_regs);
>> +}
> 
> Really not happy with this.  What happens if a FIQ occurs while we're
> inside register_fiq_nmi_notifier() - more specifically inside
> atomic_notifier_chain_register() ?

Should depend on which side of the rcu update we're on.


> This is how easy it is to end up with a deadlock-able situation with
> FIQs, and it is why I said:
> 
> | > 2. Have default trap handler call an RCU notifier chain to allow it to
> | >    hook up with "normal" code without any hard coding (kgdb, IPI
> | >    handling, etc)
> | 
> | Maybe... that sounds like it opens up FIQ for general purpose use which
> | is something I want to avoid - I've little motivation to ensure that
> | everyone plays by the rules.  Given the choice, I'd rather maintain our
> | present stance that using FIQs is hard and requires a lot of thought.
> 
> You've just proven my point.
> 
> So, what I want is to make FIQs hard to use.  No notifier chain at all
> please, people can't be trusted to know all the details (even if they
> do know the details, it's just been proven that it's incredibly difficult
> to do it right.)

For what its worth the reason I stuck to the notifier idea was that
there has to be some dynamic registration; the gic is registering
something to clear IPIs. Once I had dynamic registration notifiers felt
most elegant.

However, the dynamic registration requirement is in fact very basic
since and can be registered by function pointer since only irqchip
instance is responsible for IPIs. It might even be possible to hardcode
direct calls into the gic driver and have the gic driver maintain a flag.


> What I instead want to see is that users get added to the above code
> fragment with #ifdef's around the calls - that way ensuring that people
> have to modify this file, and therefore /should/ be copying me with
> their patches.  That means less chance for someone to sneak a change
> in by merely calling some register function without first having to
> copy this mailing list.

I can do this.

Note that I'm about to go and live in a field for a week so there will
be a bit of a delay since the field interferes substantially with
hacking time.


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
@ 2014-08-19 18:12                       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-19 18:12 UTC (permalink / raw)
  To: linux-arm-kernel

On 19/08/14 18:37, Russell King - ARM Linux wrote:
> On Tue, Aug 19, 2014 at 05:45:53PM +0100, Daniel Thompson wrote:
>> +int register_fiq_nmi_notifier(struct notifier_block *nb)
>> +{
>> +	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
>> +}
>> +
>> +asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
>> +{
>> +	struct pt_regs *old_regs = set_irq_regs(regs);
>> +
>> +	nmi_enter();
>> +	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
>> +	nmi_exit();
>> +	set_irq_regs(old_regs);
>> +}
> 
> Really not happy with this.  What happens if a FIQ occurs while we're
> inside register_fiq_nmi_notifier() - more specifically inside
> atomic_notifier_chain_register() ?

Should depend on which side of the rcu update we're on.


> This is how easy it is to end up with a deadlock-able situation with
> FIQs, and it is why I said:
> 
> | > 2. Have default trap handler call an RCU notifier chain to allow it to
> | >    hook up with "normal" code without any hard coding (kgdb, IPI
> | >    handling, etc)
> | 
> | Maybe... that sounds like it opens up FIQ for general purpose use which
> | is something I want to avoid - I've little motivation to ensure that
> | everyone plays by the rules.  Given the choice, I'd rather maintain our
> | present stance that using FIQs is hard and requires a lot of thought.
> 
> You've just proven my point.
> 
> So, what I want is to make FIQs hard to use.  No notifier chain at all
> please, people can't be trusted to know all the details (even if they
> do know the details, it's just been proven that it's incredibly difficult
> to do it right.)

For what its worth the reason I stuck to the notifier idea was that
there has to be some dynamic registration; the gic is registering
something to clear IPIs. Once I had dynamic registration notifiers felt
most elegant.

However, the dynamic registration requirement is in fact very basic
since and can be registered by function pointer since only irqchip
instance is responsible for IPIs. It might even be possible to hardcode
direct calls into the gic driver and have the gic driver maintain a flag.


> What I instead want to see is that users get added to the above code
> fragment with #ifdef's around the calls - that way ensuring that people
> have to modify this file, and therefore /should/ be copying me with
> their patches.  That means less chance for someone to sneak a change
> in by merely calling some register function without first having to
> copy this mailing list.

I can do this.

Note that I'm about to go and live in a field for a week so there will
be a bit of a delay since the field interferes substantially with
hacking time.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
  2014-08-19 18:12                       ` Daniel Thompson
@ 2014-08-28 15:01                         ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-08-28 15:01 UTC (permalink / raw)
  To: Daniel Thompson, Paul E. McKenney
  Cc: linux-kernel, linux-arm-kernel, kgdb-bugreport, patches,
	linaro-kernel, John Stultz, Anton Vorontsov, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

On Tue, Aug 19, 2014 at 07:12:07PM +0100, Daniel Thompson wrote:
> On 19/08/14 18:37, Russell King - ARM Linux wrote:
> > On Tue, Aug 19, 2014 at 05:45:53PM +0100, Daniel Thompson wrote:
> >> +int register_fiq_nmi_notifier(struct notifier_block *nb)
> >> +{
> >> +	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
> >> +}
> >> +
> >> +asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
> >> +{
> >> +	struct pt_regs *old_regs = set_irq_regs(regs);
> >> +
> >> +	nmi_enter();
> >> +	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
> >> +	nmi_exit();
> >> +	set_irq_regs(old_regs);
> >> +}
> > 
> > Really not happy with this.  What happens if a FIQ occurs while we're
> > inside register_fiq_nmi_notifier() - more specifically inside
> > atomic_notifier_chain_register() ?
> 
> Should depend on which side of the rcu update we're on.

I just asked Paul McKenney, our RCU expert... essentially, yes, RCU
stuff itself is safe in this context.  However, RCU stuff can call into
lockdep if lockdep is configured, and there are questions over lockdep.

There's some things which can be done to reduce the lockdep exposure
to it, such as ensuring that rcu_read_lock() is first called outside
of FIQ context.

There's concerns with whether either printk() in check_flags() could
be reached too (flags there should always indicate that IRQs were
disabled, so that reduces down to a question about just the first
printk() there.)

There's also the very_verbose() stuff for RCU lockdep classes which
Paul says must not be enabled.

Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
lockdep doing the deadlock checking as a result of the above call.

So... this coupled with my feeling that notifiers make it too easy for
unreviewed code to be hooked into this path, I'm fairly sure that we
don't want to be calling atomic notifier chains from FIQ context.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
@ 2014-08-28 15:01                         ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-08-28 15:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Aug 19, 2014 at 07:12:07PM +0100, Daniel Thompson wrote:
> On 19/08/14 18:37, Russell King - ARM Linux wrote:
> > On Tue, Aug 19, 2014 at 05:45:53PM +0100, Daniel Thompson wrote:
> >> +int register_fiq_nmi_notifier(struct notifier_block *nb)
> >> +{
> >> +	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
> >> +}
> >> +
> >> +asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
> >> +{
> >> +	struct pt_regs *old_regs = set_irq_regs(regs);
> >> +
> >> +	nmi_enter();
> >> +	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
> >> +	nmi_exit();
> >> +	set_irq_regs(old_regs);
> >> +}
> > 
> > Really not happy with this.  What happens if a FIQ occurs while we're
> > inside register_fiq_nmi_notifier() - more specifically inside
> > atomic_notifier_chain_register() ?
> 
> Should depend on which side of the rcu update we're on.

I just asked Paul McKenney, our RCU expert... essentially, yes, RCU
stuff itself is safe in this context.  However, RCU stuff can call into
lockdep if lockdep is configured, and there are questions over lockdep.

There's some things which can be done to reduce the lockdep exposure
to it, such as ensuring that rcu_read_lock() is first called outside
of FIQ context.

There's concerns with whether either printk() in check_flags() could
be reached too (flags there should always indicate that IRQs were
disabled, so that reduces down to a question about just the first
printk() there.)

There's also the very_verbose() stuff for RCU lockdep classes which
Paul says must not be enabled.

Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
lockdep doing the deadlock checking as a result of the above call.

So... this coupled with my feeling that notifiers make it too easy for
unreviewed code to be hooked into this path, I'm fairly sure that we
don't want to be calling atomic notifier chains from FIQ context.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
  2014-08-28 15:01                         ` Russell King - ARM Linux
@ 2014-08-28 15:43                           ` Paul E. McKenney
  -1 siblings, 0 replies; 535+ messages in thread
From: Paul E. McKenney @ 2014-08-28 15:43 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

On Thu, Aug 28, 2014 at 04:01:12PM +0100, Russell King - ARM Linux wrote:
> On Tue, Aug 19, 2014 at 07:12:07PM +0100, Daniel Thompson wrote:
> > On 19/08/14 18:37, Russell King - ARM Linux wrote:
> > > On Tue, Aug 19, 2014 at 05:45:53PM +0100, Daniel Thompson wrote:
> > >> +int register_fiq_nmi_notifier(struct notifier_block *nb)
> > >> +{
> > >> +	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
> > >> +}
> > >> +
> > >> +asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
> > >> +{
> > >> +	struct pt_regs *old_regs = set_irq_regs(regs);
> > >> +
> > >> +	nmi_enter();
> > >> +	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
> > >> +	nmi_exit();
> > >> +	set_irq_regs(old_regs);
> > >> +}
> > > 
> > > Really not happy with this.  What happens if a FIQ occurs while we're
> > > inside register_fiq_nmi_notifier() - more specifically inside
> > > atomic_notifier_chain_register() ?
> > 
> > Should depend on which side of the rcu update we're on.
> 
> I just asked Paul McKenney, our RCU expert... essentially, yes, RCU
> stuff itself is safe in this context.  However, RCU stuff can call into
> lockdep if lockdep is configured, and there are questions over lockdep.
> 
> There's some things which can be done to reduce the lockdep exposure
> to it, such as ensuring that rcu_read_lock() is first called outside
> of FIQ context.
> 
> There's concerns with whether either printk() in check_flags() could
> be reached too (flags there should always indicate that IRQs were
> disabled, so that reduces down to a question about just the first
> printk() there.)
> 
> There's also the very_verbose() stuff for RCU lockdep classes which
> Paul says must not be enabled.
> 
> Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
> lockdep doing the deadlock checking as a result of the above call.
> 
> So... this coupled with my feeling that notifiers make it too easy for
> unreviewed code to be hooked into this path, I'm fairly sure that we
> don't want to be calling atomic notifier chains from FIQ context.

In the worst case, it would be possible to create a parallel notifier
that was intended for use from NMI.  There would be no need for
rcu_read_lock() in that case, we would instead be using RCU-sched,
for which NMI handlers are automatically RCU-sched read-side critical
sections.  Instead of synchronize_rcu(), this NMI version would use
synchronize_sched().

But if lockdep works from NMI, then the current notifiers would work
just fine.

							Thanx, Paul


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
@ 2014-08-28 15:43                           ` Paul E. McKenney
  0 siblings, 0 replies; 535+ messages in thread
From: Paul E. McKenney @ 2014-08-28 15:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 28, 2014 at 04:01:12PM +0100, Russell King - ARM Linux wrote:
> On Tue, Aug 19, 2014 at 07:12:07PM +0100, Daniel Thompson wrote:
> > On 19/08/14 18:37, Russell King - ARM Linux wrote:
> > > On Tue, Aug 19, 2014 at 05:45:53PM +0100, Daniel Thompson wrote:
> > >> +int register_fiq_nmi_notifier(struct notifier_block *nb)
> > >> +{
> > >> +	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
> > >> +}
> > >> +
> > >> +asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
> > >> +{
> > >> +	struct pt_regs *old_regs = set_irq_regs(regs);
> > >> +
> > >> +	nmi_enter();
> > >> +	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
> > >> +	nmi_exit();
> > >> +	set_irq_regs(old_regs);
> > >> +}
> > > 
> > > Really not happy with this.  What happens if a FIQ occurs while we're
> > > inside register_fiq_nmi_notifier() - more specifically inside
> > > atomic_notifier_chain_register() ?
> > 
> > Should depend on which side of the rcu update we're on.
> 
> I just asked Paul McKenney, our RCU expert... essentially, yes, RCU
> stuff itself is safe in this context.  However, RCU stuff can call into
> lockdep if lockdep is configured, and there are questions over lockdep.
> 
> There's some things which can be done to reduce the lockdep exposure
> to it, such as ensuring that rcu_read_lock() is first called outside
> of FIQ context.
> 
> There's concerns with whether either printk() in check_flags() could
> be reached too (flags there should always indicate that IRQs were
> disabled, so that reduces down to a question about just the first
> printk() there.)
> 
> There's also the very_verbose() stuff for RCU lockdep classes which
> Paul says must not be enabled.
> 
> Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
> lockdep doing the deadlock checking as a result of the above call.
> 
> So... this coupled with my feeling that notifiers make it too easy for
> unreviewed code to be hooked into this path, I'm fairly sure that we
> don't want to be calling atomic notifier chains from FIQ context.

In the worst case, it would be possible to create a parallel notifier
that was intended for use from NMI.  There would be no need for
rcu_read_lock() in that case, we would instead be using RCU-sched,
for which NMI handlers are automatically RCU-sched read-side critical
sections.  Instead of synchronize_rcu(), this NMI version would use
synchronize_sched().

But if lockdep works from NMI, then the current notifiers would work
just fine.

							Thanx, Paul

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
  2014-08-28 15:01                         ` Russell King - ARM Linux
@ 2014-08-28 15:54                           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-28 15:54 UTC (permalink / raw)
  To: Russell King - ARM Linux, Paul E. McKenney
  Cc: linux-kernel, linux-arm-kernel, kgdb-bugreport, patches,
	linaro-kernel, John Stultz, Anton Vorontsov, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

On 28/08/14 16:01, Russell King - ARM Linux wrote:
> On Tue, Aug 19, 2014 at 07:12:07PM +0100, Daniel Thompson wrote:
>> On 19/08/14 18:37, Russell King - ARM Linux wrote:
>>> On Tue, Aug 19, 2014 at 05:45:53PM +0100, Daniel Thompson wrote:
>>>> +int register_fiq_nmi_notifier(struct notifier_block *nb)
>>>> +{
>>>> +	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
>>>> +}
>>>> +
>>>> +asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
>>>> +{
>>>> +	struct pt_regs *old_regs = set_irq_regs(regs);
>>>> +
>>>> +	nmi_enter();
>>>> +	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
>>>> +	nmi_exit();
>>>> +	set_irq_regs(old_regs);
>>>> +}
>>>
>>> Really not happy with this.  What happens if a FIQ occurs while we're
>>> inside register_fiq_nmi_notifier() - more specifically inside
>>> atomic_notifier_chain_register() ?
>>
>> Should depend on which side of the rcu update we're on.
> 
> I just asked Paul McKenney, our RCU expert... essentially, yes, RCU
> stuff itself is safe in this context.  However, RCU stuff can call into
> lockdep if lockdep is configured, and there are questions over lockdep.

Thanks for following this up.

I originally formed the opinion RCU was safe from FIQ because it is also
used to manage the NMI notification handlers for x86
(register_nmi_handler) and I understood the runtime constraints on FIQ
to be very similar.

Note that x86 manages the notifiers itself so it uses
list_for_each_entry_rcu() rather atomic_notifier_call_chain() but
nevertheless I think this boils down to the same thing w.r.t. safety
concerns.


> There's some things which can be done to reduce the lockdep exposure
> to it, such as ensuring that rcu_read_lock() is first called outside
> of FIQ context.

lockdep is automatically disabled by calling nmi_enter() so all the
lockdep calls should end up following the early exit path based on
current->lockdep_recursion.


> There's concerns with whether either printk() in check_flags() could
> be reached too (flags there should always indicate that IRQs were
> disabled, so that reduces down to a question about just the first
> printk() there.)
> 
> There's also the very_verbose() stuff for RCU lockdep classes which
> Paul says must not be enabled.
> 
> Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
> lockdep doing the deadlock checking as a result of the above call.
>
> So... this coupled with my feeling that notifiers make it too easy for
> unreviewed code to be hooked into this path, I'm fairly sure that we
> don't want to be calling atomic notifier chains from FIQ context.




^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
@ 2014-08-28 15:54                           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-08-28 15:54 UTC (permalink / raw)
  To: linux-arm-kernel

On 28/08/14 16:01, Russell King - ARM Linux wrote:
> On Tue, Aug 19, 2014 at 07:12:07PM +0100, Daniel Thompson wrote:
>> On 19/08/14 18:37, Russell King - ARM Linux wrote:
>>> On Tue, Aug 19, 2014 at 05:45:53PM +0100, Daniel Thompson wrote:
>>>> +int register_fiq_nmi_notifier(struct notifier_block *nb)
>>>> +{
>>>> +	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
>>>> +}
>>>> +
>>>> +asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
>>>> +{
>>>> +	struct pt_regs *old_regs = set_irq_regs(regs);
>>>> +
>>>> +	nmi_enter();
>>>> +	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
>>>> +	nmi_exit();
>>>> +	set_irq_regs(old_regs);
>>>> +}
>>>
>>> Really not happy with this.  What happens if a FIQ occurs while we're
>>> inside register_fiq_nmi_notifier() - more specifically inside
>>> atomic_notifier_chain_register() ?
>>
>> Should depend on which side of the rcu update we're on.
> 
> I just asked Paul McKenney, our RCU expert... essentially, yes, RCU
> stuff itself is safe in this context.  However, RCU stuff can call into
> lockdep if lockdep is configured, and there are questions over lockdep.

Thanks for following this up.

I originally formed the opinion RCU was safe from FIQ because it is also
used to manage the NMI notification handlers for x86
(register_nmi_handler) and I understood the runtime constraints on FIQ
to be very similar.

Note that x86 manages the notifiers itself so it uses
list_for_each_entry_rcu() rather atomic_notifier_call_chain() but
nevertheless I think this boils down to the same thing w.r.t. safety
concerns.


> There's some things which can be done to reduce the lockdep exposure
> to it, such as ensuring that rcu_read_lock() is first called outside
> of FIQ context.

lockdep is automatically disabled by calling nmi_enter() so all the
lockdep calls should end up following the early exit path based on
current->lockdep_recursion.


> There's concerns with whether either printk() in check_flags() could
> be reached too (flags there should always indicate that IRQs were
> disabled, so that reduces down to a question about just the first
> printk() there.)
> 
> There's also the very_verbose() stuff for RCU lockdep classes which
> Paul says must not be enabled.
> 
> Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
> lockdep doing the deadlock checking as a result of the above call.
>
> So... this coupled with my feeling that notifiers make it too easy for
> unreviewed code to be hooked into this path, I'm fairly sure that we
> don't want to be calling atomic notifier chains from FIQ context.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
  2014-08-28 15:54                           ` Daniel Thompson
@ 2014-08-28 16:15                             ` Paul E. McKenney
  -1 siblings, 0 replies; 535+ messages in thread
From: Paul E. McKenney @ 2014-08-28 16:15 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Russell King - ARM Linux, linux-kernel, linux-arm-kernel,
	kgdb-bugreport, patches, linaro-kernel, John Stultz,
	Anton Vorontsov, Colin Cross, kernel-team, Rob Herring,
	Linus Walleij, Ben Dooks, Catalin Marinas, Dave Martin,
	Fabio Estevam, Frederic Weisbecker, Nicolas Pitre

On Thu, Aug 28, 2014 at 04:54:25PM +0100, Daniel Thompson wrote:
> On 28/08/14 16:01, Russell King - ARM Linux wrote:
> > On Tue, Aug 19, 2014 at 07:12:07PM +0100, Daniel Thompson wrote:
> >> On 19/08/14 18:37, Russell King - ARM Linux wrote:
> >>> On Tue, Aug 19, 2014 at 05:45:53PM +0100, Daniel Thompson wrote:
> >>>> +int register_fiq_nmi_notifier(struct notifier_block *nb)
> >>>> +{
> >>>> +	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
> >>>> +}
> >>>> +
> >>>> +asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
> >>>> +{
> >>>> +	struct pt_regs *old_regs = set_irq_regs(regs);
> >>>> +
> >>>> +	nmi_enter();
> >>>> +	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
> >>>> +	nmi_exit();
> >>>> +	set_irq_regs(old_regs);
> >>>> +}
> >>>
> >>> Really not happy with this.  What happens if a FIQ occurs while we're
> >>> inside register_fiq_nmi_notifier() - more specifically inside
> >>> atomic_notifier_chain_register() ?
> >>
> >> Should depend on which side of the rcu update we're on.
> > 
> > I just asked Paul McKenney, our RCU expert... essentially, yes, RCU
> > stuff itself is safe in this context.  However, RCU stuff can call into
> > lockdep if lockdep is configured, and there are questions over lockdep.
> 
> Thanks for following this up.
> 
> I originally formed the opinion RCU was safe from FIQ because it is also
> used to manage the NMI notification handlers for x86
> (register_nmi_handler) and I understood the runtime constraints on FIQ
> to be very similar.
> 
> Note that x86 manages the notifiers itself so it uses
> list_for_each_entry_rcu() rather atomic_notifier_call_chain() but
> nevertheless I think this boils down to the same thing w.r.t. safety
> concerns.
> 
> 
> > There's some things which can be done to reduce the lockdep exposure
> > to it, such as ensuring that rcu_read_lock() is first called outside
> > of FIQ context.
> 
> lockdep is automatically disabled by calling nmi_enter() so all the
> lockdep calls should end up following the early exit path based on
> current->lockdep_recursion.

Ah, that was what I was missing.  Then the notification should be
safe from NMI, so have at it!  ;-)

							Thanx, Paul

> > There's concerns with whether either printk() in check_flags() could
> > be reached too (flags there should always indicate that IRQs were
> > disabled, so that reduces down to a question about just the first
> > printk() there.)
> > 
> > There's also the very_verbose() stuff for RCU lockdep classes which
> > Paul says must not be enabled.
> > 
> > Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
> > lockdep doing the deadlock checking as a result of the above call.
> >
> > So... this coupled with my feeling that notifiers make it too easy for
> > unreviewed code to be hooked into this path, I'm fairly sure that we
> > don't want to be calling atomic notifier chains from FIQ context.
> 
> 
> 


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
@ 2014-08-28 16:15                             ` Paul E. McKenney
  0 siblings, 0 replies; 535+ messages in thread
From: Paul E. McKenney @ 2014-08-28 16:15 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 28, 2014 at 04:54:25PM +0100, Daniel Thompson wrote:
> On 28/08/14 16:01, Russell King - ARM Linux wrote:
> > On Tue, Aug 19, 2014 at 07:12:07PM +0100, Daniel Thompson wrote:
> >> On 19/08/14 18:37, Russell King - ARM Linux wrote:
> >>> On Tue, Aug 19, 2014 at 05:45:53PM +0100, Daniel Thompson wrote:
> >>>> +int register_fiq_nmi_notifier(struct notifier_block *nb)
> >>>> +{
> >>>> +	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
> >>>> +}
> >>>> +
> >>>> +asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
> >>>> +{
> >>>> +	struct pt_regs *old_regs = set_irq_regs(regs);
> >>>> +
> >>>> +	nmi_enter();
> >>>> +	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
> >>>> +	nmi_exit();
> >>>> +	set_irq_regs(old_regs);
> >>>> +}
> >>>
> >>> Really not happy with this.  What happens if a FIQ occurs while we're
> >>> inside register_fiq_nmi_notifier() - more specifically inside
> >>> atomic_notifier_chain_register() ?
> >>
> >> Should depend on which side of the rcu update we're on.
> > 
> > I just asked Paul McKenney, our RCU expert... essentially, yes, RCU
> > stuff itself is safe in this context.  However, RCU stuff can call into
> > lockdep if lockdep is configured, and there are questions over lockdep.
> 
> Thanks for following this up.
> 
> I originally formed the opinion RCU was safe from FIQ because it is also
> used to manage the NMI notification handlers for x86
> (register_nmi_handler) and I understood the runtime constraints on FIQ
> to be very similar.
> 
> Note that x86 manages the notifiers itself so it uses
> list_for_each_entry_rcu() rather atomic_notifier_call_chain() but
> nevertheless I think this boils down to the same thing w.r.t. safety
> concerns.
> 
> 
> > There's some things which can be done to reduce the lockdep exposure
> > to it, such as ensuring that rcu_read_lock() is first called outside
> > of FIQ context.
> 
> lockdep is automatically disabled by calling nmi_enter() so all the
> lockdep calls should end up following the early exit path based on
> current->lockdep_recursion.

Ah, that was what I was missing.  Then the notification should be
safe from NMI, so have at it!  ;-)

							Thanx, Paul

> > There's concerns with whether either printk() in check_flags() could
> > be reached too (flags there should always indicate that IRQs were
> > disabled, so that reduces down to a question about just the first
> > printk() there.)
> > 
> > There's also the very_verbose() stuff for RCU lockdep classes which
> > Paul says must not be enabled.
> > 
> > Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
> > lockdep doing the deadlock checking as a result of the above call.
> >
> > So... this coupled with my feeling that notifiers make it too easy for
> > unreviewed code to be hooked into this path, I'm fairly sure that we
> > don't want to be calling atomic notifier chains from FIQ context.
> 
> 
> 

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
  2014-08-28 16:15                             ` Paul E. McKenney
@ 2014-09-02 11:03                               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 11:03 UTC (permalink / raw)
  To: paulmck
  Cc: Russell King - ARM Linux, linux-kernel, linux-arm-kernel,
	kgdb-bugreport, patches, linaro-kernel, John Stultz,
	Anton Vorontsov, Colin Cross, kernel-team, Rob Herring,
	Linus Walleij, Ben Dooks, Catalin Marinas, Dave Martin,
	Fabio Estevam, Frederic Weisbecker, Nicolas Pitre

On 28/08/14 17:15, Paul E. McKenney wrote:
> On Thu, Aug 28, 2014 at 04:54:25PM +0100, Daniel Thompson wrote:
>> On 28/08/14 16:01, Russell King - ARM Linux wrote:
>>> On Tue, Aug 19, 2014 at 07:12:07PM +0100, Daniel Thompson wrote:
>>>> On 19/08/14 18:37, Russell King - ARM Linux wrote:
>>>>> On Tue, Aug 19, 2014 at 05:45:53PM +0100, Daniel Thompson wrote:
>>>>>> +int register_fiq_nmi_notifier(struct notifier_block *nb)
>>>>>> +{
>>>>>> +	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
>>>>>> +}
>>>>>> +
>>>>>> +asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
>>>>>> +{
>>>>>> +	struct pt_regs *old_regs = set_irq_regs(regs);
>>>>>> +
>>>>>> +	nmi_enter();
>>>>>> +	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
>>>>>> +	nmi_exit();
>>>>>> +	set_irq_regs(old_regs);
>>>>>> +}
>>>>>
>>>>> Really not happy with this.  What happens if a FIQ occurs while we're
>>>>> inside register_fiq_nmi_notifier() - more specifically inside
>>>>> atomic_notifier_chain_register() ?
>>>>
>>>> Should depend on which side of the rcu update we're on.
>>>
>>> I just asked Paul McKenney, our RCU expert... essentially, yes, RCU
>>> stuff itself is safe in this context.  However, RCU stuff can call into
>>> lockdep if lockdep is configured, and there are questions over lockdep.
>>
>> Thanks for following this up.
>>
>> I originally formed the opinion RCU was safe from FIQ because it is also
>> used to manage the NMI notification handlers for x86
>> (register_nmi_handler) and I understood the runtime constraints on FIQ
>> to be very similar.
>>
>> Note that x86 manages the notifiers itself so it uses
>> list_for_each_entry_rcu() rather atomic_notifier_call_chain() but
>> nevertheless I think this boils down to the same thing w.r.t. safety
>> concerns.
>>
>>
>>> There's some things which can be done to reduce the lockdep exposure
>>> to it, such as ensuring that rcu_read_lock() is first called outside
>>> of FIQ context.
>>
>> lockdep is automatically disabled by calling nmi_enter() so all the
>> lockdep calls should end up following the early exit path based on
>> current->lockdep_recursion.
> 
> Ah, that was what I was missing.  Then the notification should be
> safe from NMI, so have at it!  ;-)
> 
> 							Thanx, Paul
> 
>>> There's concerns with whether either printk() in check_flags() could
>>> be reached too (flags there should always indicate that IRQs were
>>> disabled, so that reduces down to a question about just the first
>>> printk() there.)
>>>
>>> There's also the very_verbose() stuff for RCU lockdep classes which
>>> Paul says must not be enabled.
>>>
>>> Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
>>> lockdep doing the deadlock checking as a result of the above call.
>>>
>>> So... this coupled with my feeling that notifiers make it too easy for
>>> unreviewed code to be hooked into this path, I'm fairly sure that we
>>> don't want to be calling atomic notifier chains from FIQ context.

Having esablished (above) that RCU usage is safe from FIQ I have been
working on the assumption that your feeling regarding unreviewed code
is sufficient on its own to avoid using notifiers (and also to avoid
a list of function pointers like on x86).

Therefore I have made these changes I've produced a before/after patch
to show the impact of this. I will merge this into the FIQ patchset
shortly.

Personally I still favour using notifiers and think the coupling below is
excessive. Nevertheless I've run a couple of basic tests on the code
below and it works fine.

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index 175bfed..a25c952 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -54,7 +54,6 @@ extern void disable_fiq(int fiq);
 extern int ack_fiq(int fiq);
 extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
-extern int register_fiq_nmi_notifier(struct notifier_block *nb);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 6563da0..cb5ccd6 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -51,6 +51,7 @@ extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
 extern int kgdb_register_fiq(unsigned int fiq);
+extern void kgdb_handle_fiq(struct pt_regs *regs);
 
 #endif /* !__ASSEMBLY__ */
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index b2bd1c7..7422b58 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -43,12 +43,14 @@
 #include <linux/irq.h>
 #include <linux/radix-tree.h>
 #include <linux/slab.h>
+#include <linux/irqchip/arm-gic.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
 #include <asm/exception.h>
 #include <asm/fiq.h>
 #include <asm/irq.h>
+#include <asm/kgdb.h>
 #include <asm/traps.h>
 
 #define FIQ_OFFSET ({					\
@@ -65,7 +67,6 @@ static unsigned long no_fiq_insn;
 static int fiq_start = -1;
 static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
 static DEFINE_MUTEX(fiq_data_mutex);
-static ATOMIC_NOTIFIER_HEAD(fiq_nmi_chain);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -218,17 +219,19 @@ bool has_fiq(int fiq)
 }
 EXPORT_SYMBOL(has_fiq);
 
-int register_fiq_nmi_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
-}
-
 asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
 	nmi_enter();
-	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
+
+	/* these callbacks deliberately avoid using a notifier chain in
+	 * order to ensure code review happens (drivers cannot "secretly"
+	 * employ FIQ without modifying this chain of calls).
+	 */
+	kgdb_handle_fiq(regs);
+	gic_handle_fiq_ipi();
+
 	nmi_exit();
 	set_irq_regs(old_regs);
 }
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
index b77b885..630a3ef 100644
--- a/arch/arm/kernel/kgdb.c
+++ b/arch/arm/kernel/kgdb.c
@@ -312,12 +312,13 @@ struct kgdb_arch arch_kgdb_ops = {
 };
 
 #ifdef CONFIG_KGDB_FIQ
-static int kgdb_handle_fiq(struct notifier_block *nb, unsigned long arg,
-			   void *data)
+void kgdb_handle_fiq(struct pt_regs *regs)
 {
-	struct pt_regs *regs = (void *) arg;
 	int actual;
 
+	if (!kgdb_fiq)
+		return;
+
 	if (!kgdb_nmicallback(raw_smp_processor_id(), regs))
 		return NOTIFY_OK;
 
@@ -333,11 +334,6 @@ static int kgdb_handle_fiq(struct notifier_block *nb, unsigned long arg,
 	return NOTIFY_OK;
 }
 
-static struct notifier_block kgdb_fiq_notifier = {
-	.notifier_call = kgdb_handle_fiq,
-	.priority = 100,
-};
-
 int kgdb_register_fiq(unsigned int fiq)
 {
 	static struct fiq_handler kgdb_fiq_desc = { .name = "kgdb", };
@@ -357,7 +353,6 @@ int kgdb_register_fiq(unsigned int fiq)
 	}
 
 	kgdb_fiq = fiq;
-	register_fiq_nmi_notifier(&kgdb_fiq_notifier);
 
 	return 0;
 }
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index bda5a91..8821160 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -502,13 +502,17 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 /*
  * Fully acknowledge (both ack and eoi) a FIQ-based IPI
  */
-static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
-			   void *data)
+void gic_handle_fiq_ipi(void)
 {
 	struct gic_chip_data *gic = &gic_data[0];
-	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	void __iomem *cpu_base;
 	unsigned long irqstat, irqnr;
 
+	if (!gic || !gic->fiq_enable)
+		return;
+
+	cpu_base = gic_data_cpu_base(gic);
+
 	if (WARN_ON(!in_nmi()))
 		return NOTIFY_BAD;
 
@@ -525,13 +529,6 @@ static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
 
 	return NOTIFY_OK;
 }
-
-/*
- * Notifier to ensure IPI FIQ is acknowledged correctly.
- */
-static struct notifier_block gic_fiq_ipi_notifier = {
-	.notifier_call = gic_handle_fiq_ipi,
-};
 #else /* CONFIG_FIQ */
 static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
 				     int group) {}
@@ -1250,10 +1247,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 #ifdef CONFIG_SMP
 		set_smp_cross_call(gic_raise_softirq);
 		register_cpu_notifier(&gic_cpu_notifier);
-#ifdef CONFIG_FIQ
-		if (gic_data_fiq_enable(gic))
-			register_fiq_nmi_notifier(&gic_fiq_ipi_notifier);
-#endif
 #endif
 		set_handle_irq(gic_handle_irq);
 	}
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 45e2d8c..52a5676 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops
 {
 	gic_routable_irq_domain_ops = ops;
 }
+
+void gic_handle_fiq_ipi(void);
+
 #endif /* __ASSEMBLY */
 #endif

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
@ 2014-09-02 11:03                               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 11:03 UTC (permalink / raw)
  To: linux-arm-kernel

On 28/08/14 17:15, Paul E. McKenney wrote:
> On Thu, Aug 28, 2014 at 04:54:25PM +0100, Daniel Thompson wrote:
>> On 28/08/14 16:01, Russell King - ARM Linux wrote:
>>> On Tue, Aug 19, 2014 at 07:12:07PM +0100, Daniel Thompson wrote:
>>>> On 19/08/14 18:37, Russell King - ARM Linux wrote:
>>>>> On Tue, Aug 19, 2014 at 05:45:53PM +0100, Daniel Thompson wrote:
>>>>>> +int register_fiq_nmi_notifier(struct notifier_block *nb)
>>>>>> +{
>>>>>> +	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
>>>>>> +}
>>>>>> +
>>>>>> +asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
>>>>>> +{
>>>>>> +	struct pt_regs *old_regs = set_irq_regs(regs);
>>>>>> +
>>>>>> +	nmi_enter();
>>>>>> +	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
>>>>>> +	nmi_exit();
>>>>>> +	set_irq_regs(old_regs);
>>>>>> +}
>>>>>
>>>>> Really not happy with this.  What happens if a FIQ occurs while we're
>>>>> inside register_fiq_nmi_notifier() - more specifically inside
>>>>> atomic_notifier_chain_register() ?
>>>>
>>>> Should depend on which side of the rcu update we're on.
>>>
>>> I just asked Paul McKenney, our RCU expert... essentially, yes, RCU
>>> stuff itself is safe in this context.  However, RCU stuff can call into
>>> lockdep if lockdep is configured, and there are questions over lockdep.
>>
>> Thanks for following this up.
>>
>> I originally formed the opinion RCU was safe from FIQ because it is also
>> used to manage the NMI notification handlers for x86
>> (register_nmi_handler) and I understood the runtime constraints on FIQ
>> to be very similar.
>>
>> Note that x86 manages the notifiers itself so it uses
>> list_for_each_entry_rcu() rather atomic_notifier_call_chain() but
>> nevertheless I think this boils down to the same thing w.r.t. safety
>> concerns.
>>
>>
>>> There's some things which can be done to reduce the lockdep exposure
>>> to it, such as ensuring that rcu_read_lock() is first called outside
>>> of FIQ context.
>>
>> lockdep is automatically disabled by calling nmi_enter() so all the
>> lockdep calls should end up following the early exit path based on
>> current->lockdep_recursion.
> 
> Ah, that was what I was missing.  Then the notification should be
> safe from NMI, so have at it!  ;-)
> 
> 							Thanx, Paul
> 
>>> There's concerns with whether either printk() in check_flags() could
>>> be reached too (flags there should always indicate that IRQs were
>>> disabled, so that reduces down to a question about just the first
>>> printk() there.)
>>>
>>> There's also the very_verbose() stuff for RCU lockdep classes which
>>> Paul says must not be enabled.
>>>
>>> Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
>>> lockdep doing the deadlock checking as a result of the above call.
>>>
>>> So... this coupled with my feeling that notifiers make it too easy for
>>> unreviewed code to be hooked into this path, I'm fairly sure that we
>>> don't want to be calling atomic notifier chains from FIQ context.

Having esablished (above) that RCU usage is safe from FIQ I have been
working on the assumption that your feeling regarding unreviewed code
is sufficient on its own to avoid using notifiers (and also to avoid
a list of function pointers like on x86).

Therefore I have made these changes I've produced a before/after patch
to show the impact of this. I will merge this into the FIQ patchset
shortly.

Personally I still favour using notifiers and think the coupling below is
excessive. Nevertheless I've run a couple of basic tests on the code
below and it works fine.

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index 175bfed..a25c952 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -54,7 +54,6 @@ extern void disable_fiq(int fiq);
 extern int ack_fiq(int fiq);
 extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
-extern int register_fiq_nmi_notifier(struct notifier_block *nb);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 6563da0..cb5ccd6 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -51,6 +51,7 @@ extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
 extern int kgdb_register_fiq(unsigned int fiq);
+extern void kgdb_handle_fiq(struct pt_regs *regs);
 
 #endif /* !__ASSEMBLY__ */
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index b2bd1c7..7422b58 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -43,12 +43,14 @@
 #include <linux/irq.h>
 #include <linux/radix-tree.h>
 #include <linux/slab.h>
+#include <linux/irqchip/arm-gic.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
 #include <asm/exception.h>
 #include <asm/fiq.h>
 #include <asm/irq.h>
+#include <asm/kgdb.h>
 #include <asm/traps.h>
 
 #define FIQ_OFFSET ({					\
@@ -65,7 +67,6 @@ static unsigned long no_fiq_insn;
 static int fiq_start = -1;
 static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
 static DEFINE_MUTEX(fiq_data_mutex);
-static ATOMIC_NOTIFIER_HEAD(fiq_nmi_chain);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -218,17 +219,19 @@ bool has_fiq(int fiq)
 }
 EXPORT_SYMBOL(has_fiq);
 
-int register_fiq_nmi_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
-}
-
 asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
 	nmi_enter();
-	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
+
+	/* these callbacks deliberately avoid using a notifier chain in
+	 * order to ensure code review happens (drivers cannot "secretly"
+	 * employ FIQ without modifying this chain of calls).
+	 */
+	kgdb_handle_fiq(regs);
+	gic_handle_fiq_ipi();
+
 	nmi_exit();
 	set_irq_regs(old_regs);
 }
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
index b77b885..630a3ef 100644
--- a/arch/arm/kernel/kgdb.c
+++ b/arch/arm/kernel/kgdb.c
@@ -312,12 +312,13 @@ struct kgdb_arch arch_kgdb_ops = {
 };
 
 #ifdef CONFIG_KGDB_FIQ
-static int kgdb_handle_fiq(struct notifier_block *nb, unsigned long arg,
-			   void *data)
+void kgdb_handle_fiq(struct pt_regs *regs)
 {
-	struct pt_regs *regs = (void *) arg;
 	int actual;
 
+	if (!kgdb_fiq)
+		return;
+
 	if (!kgdb_nmicallback(raw_smp_processor_id(), regs))
 		return NOTIFY_OK;
 
@@ -333,11 +334,6 @@ static int kgdb_handle_fiq(struct notifier_block *nb, unsigned long arg,
 	return NOTIFY_OK;
 }
 
-static struct notifier_block kgdb_fiq_notifier = {
-	.notifier_call = kgdb_handle_fiq,
-	.priority = 100,
-};
-
 int kgdb_register_fiq(unsigned int fiq)
 {
 	static struct fiq_handler kgdb_fiq_desc = { .name = "kgdb", };
@@ -357,7 +353,6 @@ int kgdb_register_fiq(unsigned int fiq)
 	}
 
 	kgdb_fiq = fiq;
-	register_fiq_nmi_notifier(&kgdb_fiq_notifier);
 
 	return 0;
 }
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index bda5a91..8821160 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -502,13 +502,17 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 /*
  * Fully acknowledge (both ack and eoi) a FIQ-based IPI
  */
-static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
-			   void *data)
+void gic_handle_fiq_ipi(void)
 {
 	struct gic_chip_data *gic = &gic_data[0];
-	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	void __iomem *cpu_base;
 	unsigned long irqstat, irqnr;
 
+	if (!gic || !gic->fiq_enable)
+		return;
+
+	cpu_base = gic_data_cpu_base(gic);
+
 	if (WARN_ON(!in_nmi()))
 		return NOTIFY_BAD;
 
@@ -525,13 +529,6 @@ static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
 
 	return NOTIFY_OK;
 }
-
-/*
- * Notifier to ensure IPI FIQ is acknowledged correctly.
- */
-static struct notifier_block gic_fiq_ipi_notifier = {
-	.notifier_call = gic_handle_fiq_ipi,
-};
 #else /* CONFIG_FIQ */
 static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
 				     int group) {}
@@ -1250,10 +1247,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 #ifdef CONFIG_SMP
 		set_smp_cross_call(gic_raise_softirq);
 		register_cpu_notifier(&gic_cpu_notifier);
-#ifdef CONFIG_FIQ
-		if (gic_data_fiq_enable(gic))
-			register_fiq_nmi_notifier(&gic_fiq_ipi_notifier);
-#endif
 #endif
 		set_handle_irq(gic_handle_irq);
 	}
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 45e2d8c..52a5676 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops
 {
 	gic_routable_irq_domain_ops = ops;
 }
+
+void gic_handle_fiq_ipi(void);
+
 #endif /* __ASSEMBLY */
 #endif

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
  2014-09-02 11:03                               ` Daniel Thompson
@ 2014-09-02 11:36                                 ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-02 11:36 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: paulmck, linux-kernel, linux-arm-kernel, kgdb-bugreport, patches,
	linaro-kernel, John Stultz, Anton Vorontsov, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

On Tue, Sep 02, 2014 at 12:03:11PM +0100, Daniel Thompson wrote:
> On 28/08/14 17:15, Paul E. McKenney wrote:
> > On Thu, Aug 28, 2014 at 04:54:25PM +0100, Daniel Thompson wrote:
> >> On 28/08/14 16:01, Russell King - ARM Linux wrote:
> >>> There's concerns with whether either printk() in check_flags() could
> >>> be reached too (flags there should always indicate that IRQs were
> >>> disabled, so that reduces down to a question about just the first
> >>> printk() there.)
> >>>
> >>> There's also the very_verbose() stuff for RCU lockdep classes which
> >>> Paul says must not be enabled.
> >>>
> >>> Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
> >>> lockdep doing the deadlock checking as a result of the above call.
> >>>
> >>> So... this coupled with my feeling that notifiers make it too easy for
> >>> unreviewed code to be hooked into this path, I'm fairly sure that we
> >>> don't want to be calling atomic notifier chains from FIQ context.
> 
> Having esablished (above) that RCU usage is safe from FIQ I have been
> working on the assumption that your feeling regarding unreviewed code
> is sufficient on its own to avoid using notifiers (and also to avoid
> a list of function pointers like on x86).

I'm assuming that "your" above refers to Paul here, since you addressed
your message To: Paul and only copied me for information purposes.

If not, please address your message more appropriately so as to avoid
confusion.

Thanks.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
@ 2014-09-02 11:36                                 ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-02 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 02, 2014 at 12:03:11PM +0100, Daniel Thompson wrote:
> On 28/08/14 17:15, Paul E. McKenney wrote:
> > On Thu, Aug 28, 2014 at 04:54:25PM +0100, Daniel Thompson wrote:
> >> On 28/08/14 16:01, Russell King - ARM Linux wrote:
> >>> There's concerns with whether either printk() in check_flags() could
> >>> be reached too (flags there should always indicate that IRQs were
> >>> disabled, so that reduces down to a question about just the first
> >>> printk() there.)
> >>>
> >>> There's also the very_verbose() stuff for RCU lockdep classes which
> >>> Paul says must not be enabled.
> >>>
> >>> Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
> >>> lockdep doing the deadlock checking as a result of the above call.
> >>>
> >>> So... this coupled with my feeling that notifiers make it too easy for
> >>> unreviewed code to be hooked into this path, I'm fairly sure that we
> >>> don't want to be calling atomic notifier chains from FIQ context.
> 
> Having esablished (above) that RCU usage is safe from FIQ I have been
> working on the assumption that your feeling regarding unreviewed code
> is sufficient on its own to avoid using notifiers (and also to avoid
> a list of function pointers like on x86).

I'm assuming that "your" above refers to Paul here, since you addressed
your message To: Paul and only copied me for information purposes.

If not, please address your message more appropriately so as to avoid
confusion.

Thanks.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
  2014-08-28 15:01                         ` Russell King - ARM Linux
@ 2014-09-02 11:49                           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 11:49 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Paul E. McKenney, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

On 28/08/14 16:01, Russell King - ARM Linux wrote:
> On Tue, Aug 19, 2014 at 07:12:07PM +0100, Daniel Thompson wrote:
>> On 19/08/14 18:37, Russell King - ARM Linux wrote:
>>> On Tue, Aug 19, 2014 at 05:45:53PM +0100, Daniel Thompson wrote:
>>>> +int register_fiq_nmi_notifier(struct notifier_block *nb)
>>>> +{
>>>> +	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
>>>> +}
>>>> +
>>>> +asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
>>>> +{
>>>> +	struct pt_regs *old_regs = set_irq_regs(regs);
>>>> +
>>>> +	nmi_enter();
>>>> +	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
>>>> +	nmi_exit();
>>>> +	set_irq_regs(old_regs);
>>>> +}
>>>
>>> Really not happy with this.  What happens if a FIQ occurs while we're
>>> inside register_fiq_nmi_notifier() - more specifically inside
>>> atomic_notifier_chain_register() ?
>>
>> Should depend on which side of the rcu update we're on.
> 
> I just asked Paul McKenney, our RCU expert... essentially, yes, RCU
> stuff itself is safe in this context.  However, RCU stuff can call into
> lockdep if lockdep is configured, and there are questions over lockdep.
> 
> There's some things which can be done to reduce the lockdep exposure
> to it, such as ensuring that rcu_read_lock() is first called outside
> of FIQ context.
> 
> There's concerns with whether either printk() in check_flags() could
> be reached too (flags there should always indicate that IRQs were
> disabled, so that reduces down to a question about just the first
> printk() there.)
> 
> There's also the very_verbose() stuff for RCU lockdep classes which
> Paul says must not be enabled.
> 
> Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
> lockdep doing the deadlock checking as a result of the above call.
> 
> So... this coupled with my feeling that notifiers make it too easy for
> unreviewed code to be hooked into this path, I'm fairly sure that we
> don't want to be calling atomic notifier chains from FIQ context.

Having esablished (elsewhere in the thread) that RCU usage is safe
from FIQ I have been working on the assumption that your feeling
regarding unreviewed code is sufficient on its own to avoid using
notifiers (and also to avoid a list of function pointers like on x86).

Therefore I have made the changes requested and produced a
before/after patch to show the impact of this. I will merge this
into the FIQ patchset shortly (I need to run a few more build tests
first).

Personally I still favour using notifiers and think the coupling below is
excessive. Nevertheless I've run a couple of basic tests on the code
below and it works fine.


diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index 175bfed..a25c952 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -54,7 +54,6 @@ extern void disable_fiq(int fiq);
 extern int ack_fiq(int fiq);
 extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
-extern int register_fiq_nmi_notifier(struct notifier_block *nb);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 6563da0..cb5ccd6 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -51,6 +51,7 @@ extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
 extern int kgdb_register_fiq(unsigned int fiq);
+extern void kgdb_handle_fiq(struct pt_regs *regs);
 
 #endif /* !__ASSEMBLY__ */
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index b2bd1c7..7422b58 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -43,12 +43,14 @@
 #include <linux/irq.h>
 #include <linux/radix-tree.h>
 #include <linux/slab.h>
+#include <linux/irqchip/arm-gic.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
 #include <asm/exception.h>
 #include <asm/fiq.h>
 #include <asm/irq.h>
+#include <asm/kgdb.h>
 #include <asm/traps.h>
 
 #define FIQ_OFFSET ({					\
@@ -65,7 +67,6 @@ static unsigned long no_fiq_insn;
 static int fiq_start = -1;
 static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
 static DEFINE_MUTEX(fiq_data_mutex);
-static ATOMIC_NOTIFIER_HEAD(fiq_nmi_chain);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -218,17 +219,23 @@ bool has_fiq(int fiq)
 }
 EXPORT_SYMBOL(has_fiq);
 
-int register_fiq_nmi_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
-}
-
 asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
 	nmi_enter();
-	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
+
+	/* these callbacks deliberately avoid using a notifier chain in
+	 * order to ensure code review happens (drivers cannot "secretly"
+	 * employ FIQ without modifying this chain of calls).
+	 */
+#ifdef CONFIG_KGDB_FIQ
+	kgdb_handle_fiq(regs);
+#endif
+#ifdef CONFIG_ARM_GIC
+	gic_handle_fiq_ipi();
+#endif
+
 	nmi_exit();
 	set_irq_regs(old_regs);
 }
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
index b77b885..630a3ef 100644
--- a/arch/arm/kernel/kgdb.c
+++ b/arch/arm/kernel/kgdb.c
@@ -312,12 +312,13 @@ struct kgdb_arch arch_kgdb_ops = {
 };
 
 #ifdef CONFIG_KGDB_FIQ
-static int kgdb_handle_fiq(struct notifier_block *nb, unsigned long arg,
-			   void *data)
+void kgdb_handle_fiq(struct pt_regs *regs)
 {
-	struct pt_regs *regs = (void *) arg;
 	int actual;
 
+	if (!kgdb_fiq)
+		return;
+
 	if (!kgdb_nmicallback(raw_smp_processor_id(), regs))
 		return NOTIFY_OK;
 
@@ -333,11 +334,6 @@ static int kgdb_handle_fiq(struct notifier_block *nb, unsigned long arg,
 	return NOTIFY_OK;
 }
 
-static struct notifier_block kgdb_fiq_notifier = {
-	.notifier_call = kgdb_handle_fiq,
-	.priority = 100,
-};
-
 int kgdb_register_fiq(unsigned int fiq)
 {
 	static struct fiq_handler kgdb_fiq_desc = { .name = "kgdb", };
@@ -357,7 +353,6 @@ int kgdb_register_fiq(unsigned int fiq)
 	}
 
 	kgdb_fiq = fiq;
-	register_fiq_nmi_notifier(&kgdb_fiq_notifier);
 
 	return 0;
 }
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index bda5a91..8821160 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -502,13 +502,17 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 /*
  * Fully acknowledge (both ack and eoi) a FIQ-based IPI
  */
-static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
-			   void *data)
+void gic_handle_fiq_ipi(void)
 {
 	struct gic_chip_data *gic = &gic_data[0];
-	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	void __iomem *cpu_base;
 	unsigned long irqstat, irqnr;
 
+	if (!gic || !gic->fiq_enable)
+		return;
+
+	cpu_base = gic_data_cpu_base(gic);
+
 	if (WARN_ON(!in_nmi()))
 		return NOTIFY_BAD;
 
@@ -525,13 +529,6 @@ static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
 
 	return NOTIFY_OK;
 }
-
-/*
- * Notifier to ensure IPI FIQ is acknowledged correctly.
- */
-static struct notifier_block gic_fiq_ipi_notifier = {
-	.notifier_call = gic_handle_fiq_ipi,
-};
 #else /* CONFIG_FIQ */
 static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
 				     int group) {}
@@ -1250,10 +1247,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 #ifdef CONFIG_SMP
 		set_smp_cross_call(gic_raise_softirq);
 		register_cpu_notifier(&gic_cpu_notifier);
-#ifdef CONFIG_FIQ
-		if (gic_data_fiq_enable(gic))
-			register_fiq_nmi_notifier(&gic_fiq_ipi_notifier);
-#endif
 #endif
 		set_handle_irq(gic_handle_irq);
 	}
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 45e2d8c..52a5676 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops
 {
 	gic_routable_irq_domain_ops = ops;
 }
+
+void gic_handle_fiq_ipi(void);
+
 #endif /* __ASSEMBLY */
 #endif



^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
@ 2014-09-02 11:49                           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

On 28/08/14 16:01, Russell King - ARM Linux wrote:
> On Tue, Aug 19, 2014 at 07:12:07PM +0100, Daniel Thompson wrote:
>> On 19/08/14 18:37, Russell King - ARM Linux wrote:
>>> On Tue, Aug 19, 2014 at 05:45:53PM +0100, Daniel Thompson wrote:
>>>> +int register_fiq_nmi_notifier(struct notifier_block *nb)
>>>> +{
>>>> +	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
>>>> +}
>>>> +
>>>> +asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
>>>> +{
>>>> +	struct pt_regs *old_regs = set_irq_regs(regs);
>>>> +
>>>> +	nmi_enter();
>>>> +	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
>>>> +	nmi_exit();
>>>> +	set_irq_regs(old_regs);
>>>> +}
>>>
>>> Really not happy with this.  What happens if a FIQ occurs while we're
>>> inside register_fiq_nmi_notifier() - more specifically inside
>>> atomic_notifier_chain_register() ?
>>
>> Should depend on which side of the rcu update we're on.
> 
> I just asked Paul McKenney, our RCU expert... essentially, yes, RCU
> stuff itself is safe in this context.  However, RCU stuff can call into
> lockdep if lockdep is configured, and there are questions over lockdep.
> 
> There's some things which can be done to reduce the lockdep exposure
> to it, such as ensuring that rcu_read_lock() is first called outside
> of FIQ context.
> 
> There's concerns with whether either printk() in check_flags() could
> be reached too (flags there should always indicate that IRQs were
> disabled, so that reduces down to a question about just the first
> printk() there.)
> 
> There's also the very_verbose() stuff for RCU lockdep classes which
> Paul says must not be enabled.
> 
> Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
> lockdep doing the deadlock checking as a result of the above call.
> 
> So... this coupled with my feeling that notifiers make it too easy for
> unreviewed code to be hooked into this path, I'm fairly sure that we
> don't want to be calling atomic notifier chains from FIQ context.

Having esablished (elsewhere in the thread) that RCU usage is safe
from FIQ I have been working on the assumption that your feeling
regarding unreviewed code is sufficient on its own to avoid using
notifiers (and also to avoid a list of function pointers like on x86).

Therefore I have made the changes requested and produced a
before/after patch to show the impact of this. I will merge this
into the FIQ patchset shortly (I need to run a few more build tests
first).

Personally I still favour using notifiers and think the coupling below is
excessive. Nevertheless I've run a couple of basic tests on the code
below and it works fine.


diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index 175bfed..a25c952 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -54,7 +54,6 @@ extern void disable_fiq(int fiq);
 extern int ack_fiq(int fiq);
 extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
-extern int register_fiq_nmi_notifier(struct notifier_block *nb);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 6563da0..cb5ccd6 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -51,6 +51,7 @@ extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
 extern int kgdb_register_fiq(unsigned int fiq);
+extern void kgdb_handle_fiq(struct pt_regs *regs);
 
 #endif /* !__ASSEMBLY__ */
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index b2bd1c7..7422b58 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -43,12 +43,14 @@
 #include <linux/irq.h>
 #include <linux/radix-tree.h>
 #include <linux/slab.h>
+#include <linux/irqchip/arm-gic.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
 #include <asm/exception.h>
 #include <asm/fiq.h>
 #include <asm/irq.h>
+#include <asm/kgdb.h>
 #include <asm/traps.h>
 
 #define FIQ_OFFSET ({					\
@@ -65,7 +67,6 @@ static unsigned long no_fiq_insn;
 static int fiq_start = -1;
 static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
 static DEFINE_MUTEX(fiq_data_mutex);
-static ATOMIC_NOTIFIER_HEAD(fiq_nmi_chain);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -218,17 +219,23 @@ bool has_fiq(int fiq)
 }
 EXPORT_SYMBOL(has_fiq);
 
-int register_fiq_nmi_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
-}
-
 asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
 	nmi_enter();
-	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
+
+	/* these callbacks deliberately avoid using a notifier chain in
+	 * order to ensure code review happens (drivers cannot "secretly"
+	 * employ FIQ without modifying this chain of calls).
+	 */
+#ifdef CONFIG_KGDB_FIQ
+	kgdb_handle_fiq(regs);
+#endif
+#ifdef CONFIG_ARM_GIC
+	gic_handle_fiq_ipi();
+#endif
+
 	nmi_exit();
 	set_irq_regs(old_regs);
 }
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
index b77b885..630a3ef 100644
--- a/arch/arm/kernel/kgdb.c
+++ b/arch/arm/kernel/kgdb.c
@@ -312,12 +312,13 @@ struct kgdb_arch arch_kgdb_ops = {
 };
 
 #ifdef CONFIG_KGDB_FIQ
-static int kgdb_handle_fiq(struct notifier_block *nb, unsigned long arg,
-			   void *data)
+void kgdb_handle_fiq(struct pt_regs *regs)
 {
-	struct pt_regs *regs = (void *) arg;
 	int actual;
 
+	if (!kgdb_fiq)
+		return;
+
 	if (!kgdb_nmicallback(raw_smp_processor_id(), regs))
 		return NOTIFY_OK;
 
@@ -333,11 +334,6 @@ static int kgdb_handle_fiq(struct notifier_block *nb, unsigned long arg,
 	return NOTIFY_OK;
 }
 
-static struct notifier_block kgdb_fiq_notifier = {
-	.notifier_call = kgdb_handle_fiq,
-	.priority = 100,
-};
-
 int kgdb_register_fiq(unsigned int fiq)
 {
 	static struct fiq_handler kgdb_fiq_desc = { .name = "kgdb", };
@@ -357,7 +353,6 @@ int kgdb_register_fiq(unsigned int fiq)
 	}
 
 	kgdb_fiq = fiq;
-	register_fiq_nmi_notifier(&kgdb_fiq_notifier);
 
 	return 0;
 }
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index bda5a91..8821160 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -502,13 +502,17 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 /*
  * Fully acknowledge (both ack and eoi) a FIQ-based IPI
  */
-static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
-			   void *data)
+void gic_handle_fiq_ipi(void)
 {
 	struct gic_chip_data *gic = &gic_data[0];
-	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	void __iomem *cpu_base;
 	unsigned long irqstat, irqnr;
 
+	if (!gic || !gic->fiq_enable)
+		return;
+
+	cpu_base = gic_data_cpu_base(gic);
+
 	if (WARN_ON(!in_nmi()))
 		return NOTIFY_BAD;
 
@@ -525,13 +529,6 @@ static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
 
 	return NOTIFY_OK;
 }
-
-/*
- * Notifier to ensure IPI FIQ is acknowledged correctly.
- */
-static struct notifier_block gic_fiq_ipi_notifier = {
-	.notifier_call = gic_handle_fiq_ipi,
-};
 #else /* CONFIG_FIQ */
 static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
 				     int group) {}
@@ -1250,10 +1247,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 #ifdef CONFIG_SMP
 		set_smp_cross_call(gic_raise_softirq);
 		register_cpu_notifier(&gic_cpu_notifier);
-#ifdef CONFIG_FIQ
-		if (gic_data_fiq_enable(gic))
-			register_fiq_nmi_notifier(&gic_fiq_ipi_notifier);
-#endif
 #endif
 		set_handle_irq(gic_handle_irq);
 	}
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 45e2d8c..52a5676 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops
 {
 	gic_routable_irq_domain_ops = ops;
 }
+
+void gic_handle_fiq_ipi(void);
+
 #endif /* __ASSEMBLY */
 #endif

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 00/19] arm: KGDB NMI/FIQ support
  2014-08-19 16:45                 ` Daniel Thompson
@ 2014-09-02 13:00                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

This patchset makes it possible to use kgdb's NMI infrastructure on ARM
platforms.

The patches are seperated into three distinct groups:

1. arm specific changes; these provide multi-platform support for FIQ
   (including raising an IPI using FIQ to ensure effective SMP support)
   and extend ARM KGDB support to use the features provided.

2. irqchip changes; updates to the gic and vic drivers to provide
   support for routing certain interrupt sources to FIQ.

3. serial changes; driver support to allow the UART interrupt to be
   routed to FIQ. The already mainlined kgdb NMI infrastructure (mostly
   found in drivers/tty/serial/kgdb_nmi.c) will re-route the kgdb
   console UART's interrupt signal from IRQ to FIQ. Naturally the UART
   will no longer function normally and will instead be managed by kgdb
   using the polled I/O functions. Any character delivered to the UART
   causes the kgdb handler function to be called.

Tested on qemu (versatile), STiH416 (B2020 board) and Freescale i.MX6
quad (wandboard).

Changes since v10:

- Removed use of RCU notifier chains to encourage code review by
  ensuring no driver can use FIQ without touching code in arch/arm/kernel
  (Russell King)

Changes since v9:

- Split PL011 code movement into a seperate patch (Peter Hurley)
- Use container_of() to convert pointers to uart_amba_port (Peter
  Hurley)
- Clean up redundant code from pl011_poll_init (Peter Hurley)
- Call do_unexp_fiq() if we receive a FIQ and CONFIG_FIQ is not set.
- Ensure irq-gic.c does not call FIQ functions unless CONFIG_FIQ is set.
- Introduced patch to avoid ttyNMI0 being enabled by default
  (replaces architecture dependant enable/disable logic).
- Fixed bug in kgdb_fiq_enable_nmi() that causes SysRq-g (non-NMI
  debugging) to wedge the debugger.

Changes since v8:

- Significant rework to separate the FIQ exception handler from kgdb.
  This allows other features typically implemented using NMI on x86
  to reuse the same exception handling code (Russell King)
- Reunited arch/arm and driver code into a single patch series again.
- Added support for raising IPIs using FIQ (makes kgdb quiesce must
  more robust).
- Introduced a workaround for GICv1 devices to avoid FIQs being
  spuriously handled as IRQs.

Changes since v7:

- Introduced ack_fiq() to complement eoi_fiq(). Without this it is
  not possible to meet the GIC specification (previous versions worked
  when tested but are unpredictable according to the specification).
  ack_fiq() also makes is possible for drivers for devices with multiple
  interrupt lines to discover the interrupt source correctly.

Changes since v6:

- Corrected off-by-one comparison in has_fiq() (Nicolas Pitre)
- Rewrote the FIQ stack initialization (Nicolas Pitre). This fixes a
  serious data corruption bug due to bad stack mismanagement.
- Introduced __fiq_abt to ensure lr_abt and spsr_abt are saved and
  restored if we fast-interrupt an abort (Russell King).
- Significantly improved the commenting of the exception handlers.
- Added a call to trace_hardirqs_on() if we clear the I bit as we
  exit the exception handler.

Changes since v5:

- Separated anything not strictly impacting arch/arm.
- Fixed a spurious add/remove of code within the series (there was
  broken code in intermediate patches)

For previous changes see:
http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901

Daniel Thompson (18):
  arm: fiq: Add callbacks to manage FIQ routings
  arm: fiq: Allow ACK and EOI to be passed to the intc
  arm: fiq: Replace default FIQ handler
  arm: smp: Introduce a special IPI signalled using FIQ
  arm: KGDB/KDB FIQ support
  irqchip: gic: Provide support for interrupt grouping
  irqchip: gic: Add support for FIQ management
  irqchip: gic: Remove spin locks from eoi_irq
  irqchip: gic: Add support for IPI FIQ
  irqchip: gic: Group 0 workaround.
  irqchip: vic: Add support for FIQ management
  serial: kgdb_nmi: No CON_ENABLED by default
  serial: amba-pl011: Use container_of() to get uart_amba_port
  serial: amba-pl011: Move pl011_hwinit()
  serial: amba-pl011: Pass FIQ information to KGDB.
  serial: asc: Add support for KGDB's FIQ/NMI mode
  serial: asc: Adopt readl_/writel_relaxed()
  serial: imx: Add support for KGDB's FIQ/NMI mode

Dirk Behme (1):
  serial: imx: clean up imx_poll_get_char()

 arch/arm/Kconfig                |   2 +
 arch/arm/Kconfig.debug          |  19 +++
 arch/arm/include/asm/fiq.h      |  17 +++
 arch/arm/include/asm/hardirq.h  |   2 +-
 arch/arm/include/asm/kgdb.h     |   5 +
 arch/arm/include/asm/smp.h      |   7 +
 arch/arm/kernel/entry-armv.S    | 129 +++++++++++++++--
 arch/arm/kernel/fiq.c           | 146 ++++++++++++++++++-
 arch/arm/kernel/kgdb.c          | 112 ++++++++++++++-
 arch/arm/kernel/setup.c         |   8 +-
 arch/arm/kernel/smp.c           |  15 ++
 arch/arm/mach-versatile/core.c  |   2 +-
 drivers/irqchip/irq-gic.c       | 302 +++++++++++++++++++++++++++++++++++++---
 drivers/irqchip/irq-vic.c       |  92 +++++++++---
 drivers/tty/serial/Kconfig      |   2 +-
 drivers/tty/serial/amba-pl011.c | 143 +++++++++++--------
 drivers/tty/serial/imx.c        |  88 +++++++-----
 drivers/tty/serial/kgdb_nmi.c   |   5 +-
 drivers/tty/serial/st-asc.c     |  27 +++-
 include/linux/irqchip/arm-gic.h |   3 +
 include/linux/irqchip/arm-vic.h |   6 +-
 21 files changed, 975 insertions(+), 157 deletions(-)

--
1.9.3


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v11 00/19] arm: KGDB NMI/FIQ support
@ 2014-09-02 13:00                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset makes it possible to use kgdb's NMI infrastructure on ARM
platforms.

The patches are seperated into three distinct groups:

1. arm specific changes; these provide multi-platform support for FIQ
   (including raising an IPI using FIQ to ensure effective SMP support)
   and extend ARM KGDB support to use the features provided.

2. irqchip changes; updates to the gic and vic drivers to provide
   support for routing certain interrupt sources to FIQ.

3. serial changes; driver support to allow the UART interrupt to be
   routed to FIQ. The already mainlined kgdb NMI infrastructure (mostly
   found in drivers/tty/serial/kgdb_nmi.c) will re-route the kgdb
   console UART's interrupt signal from IRQ to FIQ. Naturally the UART
   will no longer function normally and will instead be managed by kgdb
   using the polled I/O functions. Any character delivered to the UART
   causes the kgdb handler function to be called.

Tested on qemu (versatile), STiH416 (B2020 board) and Freescale i.MX6
quad (wandboard).

Changes since v10:

- Removed use of RCU notifier chains to encourage code review by
  ensuring no driver can use FIQ without touching code in arch/arm/kernel
  (Russell King)

Changes since v9:

- Split PL011 code movement into a seperate patch (Peter Hurley)
- Use container_of() to convert pointers to uart_amba_port (Peter
  Hurley)
- Clean up redundant code from pl011_poll_init (Peter Hurley)
- Call do_unexp_fiq() if we receive a FIQ and CONFIG_FIQ is not set.
- Ensure irq-gic.c does not call FIQ functions unless CONFIG_FIQ is set.
- Introduced patch to avoid ttyNMI0 being enabled by default
  (replaces architecture dependant enable/disable logic).
- Fixed bug in kgdb_fiq_enable_nmi() that causes SysRq-g (non-NMI
  debugging) to wedge the debugger.

Changes since v8:

- Significant rework to separate the FIQ exception handler from kgdb.
  This allows other features typically implemented using NMI on x86
  to reuse the same exception handling code (Russell King)
- Reunited arch/arm and driver code into a single patch series again.
- Added support for raising IPIs using FIQ (makes kgdb quiesce must
  more robust).
- Introduced a workaround for GICv1 devices to avoid FIQs being
  spuriously handled as IRQs.

Changes since v7:

- Introduced ack_fiq() to complement eoi_fiq(). Without this it is
  not possible to meet the GIC specification (previous versions worked
  when tested but are unpredictable according to the specification).
  ack_fiq() also makes is possible for drivers for devices with multiple
  interrupt lines to discover the interrupt source correctly.

Changes since v6:

- Corrected off-by-one comparison in has_fiq() (Nicolas Pitre)
- Rewrote the FIQ stack initialization (Nicolas Pitre). This fixes a
  serious data corruption bug due to bad stack mismanagement.
- Introduced __fiq_abt to ensure lr_abt and spsr_abt are saved and
  restored if we fast-interrupt an abort (Russell King).
- Significantly improved the commenting of the exception handlers.
- Added a call to trace_hardirqs_on() if we clear the I bit as we
  exit the exception handler.

Changes since v5:

- Separated anything not strictly impacting arch/arm.
- Fixed a spurious add/remove of code within the series (there was
  broken code in intermediate patches)

For previous changes see:
http://thread.gmane.org/gmane.linux.ports.arm.kernel/333901

Daniel Thompson (18):
  arm: fiq: Add callbacks to manage FIQ routings
  arm: fiq: Allow ACK and EOI to be passed to the intc
  arm: fiq: Replace default FIQ handler
  arm: smp: Introduce a special IPI signalled using FIQ
  arm: KGDB/KDB FIQ support
  irqchip: gic: Provide support for interrupt grouping
  irqchip: gic: Add support for FIQ management
  irqchip: gic: Remove spin locks from eoi_irq
  irqchip: gic: Add support for IPI FIQ
  irqchip: gic: Group 0 workaround.
  irqchip: vic: Add support for FIQ management
  serial: kgdb_nmi: No CON_ENABLED by default
  serial: amba-pl011: Use container_of() to get uart_amba_port
  serial: amba-pl011: Move pl011_hwinit()
  serial: amba-pl011: Pass FIQ information to KGDB.
  serial: asc: Add support for KGDB's FIQ/NMI mode
  serial: asc: Adopt readl_/writel_relaxed()
  serial: imx: Add support for KGDB's FIQ/NMI mode

Dirk Behme (1):
  serial: imx: clean up imx_poll_get_char()

 arch/arm/Kconfig                |   2 +
 arch/arm/Kconfig.debug          |  19 +++
 arch/arm/include/asm/fiq.h      |  17 +++
 arch/arm/include/asm/hardirq.h  |   2 +-
 arch/arm/include/asm/kgdb.h     |   5 +
 arch/arm/include/asm/smp.h      |   7 +
 arch/arm/kernel/entry-armv.S    | 129 +++++++++++++++--
 arch/arm/kernel/fiq.c           | 146 ++++++++++++++++++-
 arch/arm/kernel/kgdb.c          | 112 ++++++++++++++-
 arch/arm/kernel/setup.c         |   8 +-
 arch/arm/kernel/smp.c           |  15 ++
 arch/arm/mach-versatile/core.c  |   2 +-
 drivers/irqchip/irq-gic.c       | 302 +++++++++++++++++++++++++++++++++++++---
 drivers/irqchip/irq-vic.c       |  92 +++++++++---
 drivers/tty/serial/Kconfig      |   2 +-
 drivers/tty/serial/amba-pl011.c | 143 +++++++++++--------
 drivers/tty/serial/imx.c        |  88 +++++++-----
 drivers/tty/serial/kgdb_nmi.c   |   5 +-
 drivers/tty/serial/st-asc.c     |  27 +++-
 include/linux/irqchip/arm-gic.h |   3 +
 include/linux/irqchip/arm-vic.h |   6 +-
 21 files changed, 975 insertions(+), 157 deletions(-)

--
1.9.3

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v11 01/19] arm: fiq: Add callbacks to manage FIQ routings
  2014-09-02 13:00                   ` Daniel Thompson
@ 2014-09-02 13:00                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
virq into a FIQ virq. This is too inflexible for multi-platform kernels
and makes runtime error checking impossible.

We solve this by introducing a flexible mapping that allows interrupt
controllers that support FIQ to register those mappings. This, in turn,
makes it much possible for drivers in DT kernels to install FIQ handlers
without knowing anything about the interrupt controller.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h |   8 ++++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..ed44528 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -16,8 +16,14 @@
 #ifndef __ASM_FIQ_H
 #define __ASM_FIQ_H
 
+#include <linux/irq.h>
 #include <asm/ptrace.h>
 
+struct fiq_chip {
+	void (*fiq_enable)(struct irq_data *data);
+	void (*fiq_disable)(struct irq_data *data);
+};
+
 struct fiq_handler {
 	struct fiq_handler *next;
 	/* Name
@@ -38,6 +44,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern bool has_fiq(int fiq);
+extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..5d831cf 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,9 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
+#include <linux/radix-tree.h>
+#include <linux/slab.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -52,7 +55,15 @@
 		(unsigned)&vector_fiq_offset;		\
 	})
 
+struct fiq_data {
+	struct fiq_chip *fiq_chip;
+	struct irq_data *irq_data;
+};
+
 static unsigned long no_fiq_insn;
+static int fiq_start = -1;
+static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
+static DEFINE_MUTEX(fiq_data_mutex);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -127,18 +138,65 @@ void release_fiq(struct fiq_handler *f)
 	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
 }
 
-static int fiq_start;
+static struct fiq_data *lookup_fiq_data(int fiq)
+{
+	struct fiq_data *data;
+
+	rcu_read_lock();
+	data = radix_tree_lookup(&fiq_data_tree, fiq);
+	rcu_read_unlock();
+
+	return data;
+}
 
 void enable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_enable)
+			data->fiq_chip->fiq_enable(data->irq_data);
+		enable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	enable_irq(fiq + fiq_start);
 }
 
 void disable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_disable)
+			data->fiq_chip->fiq_disable(data->irq_data);
+		disable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	disable_irq(fiq + fiq_start);
 }
 
+bool has_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data)
+		return true;
+
+	if (fiq_start == -1)
+		return false;
+
+	return fiq >= fiq_start;
+}
+EXPORT_SYMBOL(has_fiq);
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -147,9 +205,50 @@ EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
 
+/*
+ * Add a mapping from a Linux irq to the fiq data.
+ */
+void fiq_register_mapping(int irq, struct fiq_chip *chip)
+{
+	struct fiq_data *fiq_data = NULL;
+	int res;
+
+	/* fiq_register_mapping can't be mixed with init_FIQ */
+	BUG_ON(fiq_start != -1);
+
+	fiq_data = kmalloc(sizeof(*fiq_data), GFP_KERNEL);
+	if (!fiq_data)
+		goto err;
+
+	fiq_data->fiq_chip = chip;
+	fiq_data->irq_data = irq_get_irq_data(irq);
+	BUG_ON(!fiq_data->irq_data);
+
+	mutex_lock(&fiq_data_mutex);
+	res = radix_tree_insert(&fiq_data_tree, irq, fiq_data);
+	mutex_unlock(&fiq_data_mutex);
+	if (res)
+		goto err;
+
+	return;
+
+err:
+	kfree(fiq_data);
+	pr_err("fiq: Cannot register mapping %d\n", irq);
+}
+
+/*
+ * Set the offset between normal IRQs and their FIQ shadows.
+ */
 void __init init_FIQ(int start)
 {
+	fiq_start = start;
+}
+
+static int __init init_default_fiq_handler(void)
+{
 	unsigned offset = FIQ_OFFSET;
 	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
-	fiq_start = start;
+	return 0;
 }
+pure_initcall(init_default_fiq_handler);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 01/19] arm: fiq: Add callbacks to manage FIQ routings
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
virq into a FIQ virq. This is too inflexible for multi-platform kernels
and makes runtime error checking impossible.

We solve this by introducing a flexible mapping that allows interrupt
controllers that support FIQ to register those mappings. This, in turn,
makes it much possible for drivers in DT kernels to install FIQ handlers
without knowing anything about the interrupt controller.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h |   8 ++++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..ed44528 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -16,8 +16,14 @@
 #ifndef __ASM_FIQ_H
 #define __ASM_FIQ_H
 
+#include <linux/irq.h>
 #include <asm/ptrace.h>
 
+struct fiq_chip {
+	void (*fiq_enable)(struct irq_data *data);
+	void (*fiq_disable)(struct irq_data *data);
+};
+
 struct fiq_handler {
 	struct fiq_handler *next;
 	/* Name
@@ -38,6 +44,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern bool has_fiq(int fiq);
+extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d..5d831cf 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -40,6 +40,9 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
+#include <linux/irq.h>
+#include <linux/radix-tree.h>
+#include <linux/slab.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
@@ -52,7 +55,15 @@
 		(unsigned)&vector_fiq_offset;		\
 	})
 
+struct fiq_data {
+	struct fiq_chip *fiq_chip;
+	struct irq_data *irq_data;
+};
+
 static unsigned long no_fiq_insn;
+static int fiq_start = -1;
+static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
+static DEFINE_MUTEX(fiq_data_mutex);
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -127,18 +138,65 @@ void release_fiq(struct fiq_handler *f)
 	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
 }
 
-static int fiq_start;
+static struct fiq_data *lookup_fiq_data(int fiq)
+{
+	struct fiq_data *data;
+
+	rcu_read_lock();
+	data = radix_tree_lookup(&fiq_data_tree, fiq);
+	rcu_read_unlock();
+
+	return data;
+}
 
 void enable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_enable)
+			data->fiq_chip->fiq_enable(data->irq_data);
+		enable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	enable_irq(fiq + fiq_start);
 }
 
 void disable_fiq(int fiq)
 {
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data) {
+		if (data->fiq_chip->fiq_disable)
+			data->fiq_chip->fiq_disable(data->irq_data);
+		disable_irq(fiq);
+		return;
+	}
+
+	if (WARN_ON(fiq_start == -1))
+		return;
+
 	disable_irq(fiq + fiq_start);
 }
 
+bool has_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data)
+		return true;
+
+	if (fiq_start == -1)
+		return false;
+
+	return fiq >= fiq_start;
+}
+EXPORT_SYMBOL(has_fiq);
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
@@ -147,9 +205,50 @@ EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
 EXPORT_SYMBOL(disable_fiq);
 
+/*
+ * Add a mapping from a Linux irq to the fiq data.
+ */
+void fiq_register_mapping(int irq, struct fiq_chip *chip)
+{
+	struct fiq_data *fiq_data = NULL;
+	int res;
+
+	/* fiq_register_mapping can't be mixed with init_FIQ */
+	BUG_ON(fiq_start != -1);
+
+	fiq_data = kmalloc(sizeof(*fiq_data), GFP_KERNEL);
+	if (!fiq_data)
+		goto err;
+
+	fiq_data->fiq_chip = chip;
+	fiq_data->irq_data = irq_get_irq_data(irq);
+	BUG_ON(!fiq_data->irq_data);
+
+	mutex_lock(&fiq_data_mutex);
+	res = radix_tree_insert(&fiq_data_tree, irq, fiq_data);
+	mutex_unlock(&fiq_data_mutex);
+	if (res)
+		goto err;
+
+	return;
+
+err:
+	kfree(fiq_data);
+	pr_err("fiq: Cannot register mapping %d\n", irq);
+}
+
+/*
+ * Set the offset between normal IRQs and their FIQ shadows.
+ */
 void __init init_FIQ(int start)
 {
+	fiq_start = start;
+}
+
+static int __init init_default_fiq_handler(void)
+{
 	unsigned offset = FIQ_OFFSET;
 	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
-	fiq_start = start;
+	return 0;
 }
+pure_initcall(init_default_fiq_handler);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 02/19] arm: fiq: Allow ACK and EOI to be passed to the intc
  2014-09-02 13:00                   ` Daniel Thompson
@ 2014-09-02 13:00                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

Modern ARM interrupt controllers require an ACK as interrupts are taken
and an EOI on completion. The FIQ code currently does not provide any
API to perform this.

This patch provides this API, implemented by adding two callbacks to the
fiq_chip structure.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h |  9 +++++++++
 arch/arm/kernel/fiq.c      | 19 +++++++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index ed44528..a25c952 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -22,6 +22,13 @@
 struct fiq_chip {
 	void (*fiq_enable)(struct irq_data *data);
 	void (*fiq_disable)(struct irq_data *data);
+
+	/* .fiq_ack() and .fiq_eoi() will be called from the FIQ
+	 * handler. For this reason they must not use spin locks (or any
+	 * other locks).
+	 */
+	int (*fiq_ack)(struct irq_data *data);
+	void (*fiq_eoi)(struct irq_data *data);
 };
 
 struct fiq_handler {
@@ -44,6 +51,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern int ack_fiq(int fiq);
+extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 5d831cf..3ccaa8c 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -183,6 +183,25 @@ void disable_fiq(int fiq)
 	disable_irq(fiq + fiq_start);
 }
 
+int ack_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_ack)
+		return data->fiq_chip->fiq_ack(data->irq_data);
+
+	return fiq;
+}
+
+void eoi_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_eoi)
+		data->fiq_chip->fiq_eoi(data->irq_data);
+}
+EXPORT_SYMBOL(eoi_fiq);
+
 bool has_fiq(int fiq)
 {
 	struct fiq_data *data = lookup_fiq_data(fiq);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 02/19] arm: fiq: Allow ACK and EOI to be passed to the intc
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

Modern ARM interrupt controllers require an ACK as interrupts are taken
and an EOI on completion. The FIQ code currently does not provide any
API to perform this.

This patch provides this API, implemented by adding two callbacks to the
fiq_chip structure.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Acked-by: Nicolas Pitre <nico@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Fabio Estevam <festevam@gmail.com>
---
 arch/arm/include/asm/fiq.h |  9 +++++++++
 arch/arm/kernel/fiq.c      | 19 +++++++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index ed44528..a25c952 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -22,6 +22,13 @@
 struct fiq_chip {
 	void (*fiq_enable)(struct irq_data *data);
 	void (*fiq_disable)(struct irq_data *data);
+
+	/* .fiq_ack() and .fiq_eoi() will be called from the FIQ
+	 * handler. For this reason they must not use spin locks (or any
+	 * other locks).
+	 */
+	int (*fiq_ack)(struct irq_data *data);
+	void (*fiq_eoi)(struct irq_data *data);
 };
 
 struct fiq_handler {
@@ -44,6 +51,8 @@ extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+extern int ack_fiq(int fiq);
+extern void eoi_fiq(int fiq);
 extern bool has_fiq(int fiq);
 extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 5d831cf..3ccaa8c 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -183,6 +183,25 @@ void disable_fiq(int fiq)
 	disable_irq(fiq + fiq_start);
 }
 
+int ack_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_ack)
+		return data->fiq_chip->fiq_ack(data->irq_data);
+
+	return fiq;
+}
+
+void eoi_fiq(int fiq)
+{
+	struct fiq_data *data = lookup_fiq_data(fiq);
+
+	if (data && data->fiq_chip->fiq_eoi)
+		data->fiq_chip->fiq_eoi(data->irq_data);
+}
+EXPORT_SYMBOL(eoi_fiq);
+
 bool has_fiq(int fiq)
 {
 	struct fiq_data *data = lookup_fiq_data(fiq);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 03/19] arm: fiq: Replace default FIQ handler
  2014-09-02 13:00                   ` Daniel Thompson
@ 2014-09-02 13:00                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

This patch introduces a new default FIQ handler that is structured in a
similar way to the existing ARM exception handler and result in the FIQ
being handled by C code running on the SVC stack (despite this code run
in the FIQ handler is subject to severe limitations with respect to
locking making normal interaction with the kernel impossible).

This default handler allows concepts that on x86 would be handled using
NMIs to be realized on ARM.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of small fragments
    survive, however without Anton's work to build from this patch would
    not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
---
 arch/arm/kernel/entry-armv.S | 129 +++++++++++++++++++++++++++++++++++++++----
 arch/arm/kernel/fiq.c        |  19 +++++++
 arch/arm/kernel/setup.c      |   8 ++-
 3 files changed, 145 insertions(+), 11 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 36276cd..ef64333 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -79,6 +79,15 @@
 #endif
 	.endm
 
+	.macro	fiq_handler
+	ldr	r1, =.LChandle_fiq
+	mov	r0, sp
+	adr	lr, BSYM(9998f)
+	ldr	pc, [r1]
+9998:
+	.endm
+
+
 #ifdef CONFIG_KPROBES
 	.section	.kprobes.text,"ax",%progbits
 #else
@@ -146,7 +155,7 @@ ENDPROC(__und_invalid)
 #define SPFIX(code...)
 #endif
 
-	.macro	svc_entry, stack_hole=0
+	.macro	svc_entry, stack_hole=0, call_trace=1
  UNWIND(.fnstart		)
  UNWIND(.save {r0 - pc}		)
 	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
@@ -183,10 +192,35 @@ ENDPROC(__und_invalid)
 	stmia	r7, {r2 - r6}
 
 #ifdef CONFIG_TRACE_IRQFLAGS
+	.if \call_trace
 	bl	trace_hardirqs_off
+	.endif
 #endif
 	.endm
 
+@
+@ svc_exit_via_fiq - similar to svc_exit but switches to FIQ mode before exit
+@
+@ This macro acts in a similar manner to svc_exit but switches to FIQ
+@ mode to restore the final part of the register state.
+@
+@ We cannot use the normal svc_exit procedure because that would
+@ clobber spsr_svc (FIQ could be delivered during the first few instructions
+@ of vector_swi meaning its contents have not been saved anywhere).
+@
+	.macro  svc_exit_via_fiq, rpsr
+
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+	.endm
+
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -295,6 +329,14 @@ __pabt_svc:
 ENDPROC(__pabt_svc)
 
 	.align	5
+__fiq_svc:
+	svc_entry 0, 0
+	fiq_handler
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+	.align	5
 .LCcralign:
 	.word	cr_alignment
 #ifdef MULTI_DABORT
@@ -303,6 +345,43 @@ ENDPROC(__pabt_svc)
 #endif
 .LCfp:
 	.word	fp_enter
+.LChandle_fiq:
+#ifdef CONFIG_FIQ
+	.word	fiq_nmi_handler
+#else
+	.word	do_unexp_fiq
+#endif
+
+/*
+ * Abort mode handlers
+ */
+
+@
+@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
+@ and reuses the same macros. However in abort mode we must also
+@ save/restore lr_abt and spsr_abt to make nested aborts safe.
+@
+	.align 5
+__fiq_abt:
+	svc_entry 0, 0
+
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	r0, lr		@ Save lr_abt
+	mrs	r1, spsr	@ Save spsr_abt, abort is now safe
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+	push	{r0 - r1}
+
+	fiq_handler
+
+	pop	{r0 - r1}
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	lr, r0		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r1	@ Restore spsr_abt
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
 
 /*
  * User mode handlers
@@ -683,6 +762,17 @@ ENTRY(ret_from_exception)
 ENDPROC(__pabt_usr)
 ENDPROC(ret_from_exception)
 
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+
 /*
  * Register switch for ARMv3 and ARMv4 processors
  * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
@@ -1118,17 +1208,36 @@ vector_addrexcptn:
 	b	vector_addrexcptn
 
 /*=============================================================================
- * Undefined FIQs
+ * FIQ "NMI" handler
  *-----------------------------------------------------------------------------
- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
- * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
- * Basically to switch modes, we *HAVE* to clobber one register...  brain
- * damage alert!  I don't think that we can execute any code in here in any
- * other mode than FIQ...  Ok you can switch to another mode, but you can't
- * get out of that mode without clobbering one register.
+ * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
+ * systems. The runtime environment for NMIs is extremely restrictive
+ * (NMIs can pre-empt critical sections meaning almost all locking is
+ * forbidden) meaning this default FIQ handling must only be used in
+ * circumstances where non-maskability improves robustness, such as
+ * watchdog or debug logic.
+ *
+ * This handler is inappropriate for high performance (fast) interrupt
+ * servicing and can be overridden using set_fiq_handler.
  */
-vector_fiq:
-	subs	pc, lr, #4
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
 
 	.globl	vector_fiq_offset
 	.equ	vector_fiq_offset, vector_fiq
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 3ccaa8c..77c62b2 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -43,11 +43,14 @@
 #include <linux/irq.h>
 #include <linux/radix-tree.h>
 #include <linux/slab.h>
+#include <linux/irqchip/arm-gic.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
+#include <asm/exception.h>
 #include <asm/fiq.h>
 #include <asm/irq.h>
+#include <asm/kgdb.h>
 #include <asm/traps.h>
 
 #define FIQ_OFFSET ({					\
@@ -216,6 +219,22 @@ bool has_fiq(int fiq)
 }
 EXPORT_SYMBOL(has_fiq);
 
+asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
+{
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	nmi_enter();
+
+	/* these callbacks deliberately avoid using a notifier chain in
+	 * order to ensure code review happens (drivers cannot "secretly"
+	 * employ FIQ without modifying this chain of calls).
+	 */
+	/* list is currently empty */
+
+	nmi_exit();
+	set_irq_regs(old_regs);
+}
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 84db893d..c031063 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -133,6 +133,7 @@ struct stack {
 	u32 irq[3];
 	u32 abt[3];
 	u32 und[3];
+	u32 fiq[3];
 } ____cacheline_aligned;
 
 #ifndef CONFIG_CPU_V7M
@@ -470,7 +471,10 @@ void notrace cpu_init(void)
 	"msr	cpsr_c, %5\n\t"
 	"add	r14, %0, %6\n\t"
 	"mov	sp, r14\n\t"
-	"msr	cpsr_c, %7"
+	"msr	cpsr_c, %7\n\t"
+	"add	r14, %0, %8\n\t"
+	"mov	sp, r14\n\t"
+	"msr	cpsr_c, %9"
 	    :
 	    : "r" (stk),
 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
@@ -479,6 +483,8 @@ void notrace cpu_init(void)
 	      "I" (offsetof(struct stack, abt[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
 	      "I" (offsetof(struct stack, und[0])),
+	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+	      "I" (offsetof(struct stack, fiq[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
 	    : "r14");
 #endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 03/19] arm: fiq: Replace default FIQ handler
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

This patch introduces a new default FIQ handler that is structured in a
similar way to the existing ARM exception handler and result in the FIQ
being handled by C code running on the SVC stack (despite this code run
in the FIQ handler is subject to severe limitations with respect to
locking making normal interaction with the kernel impossible).

This default handler allows concepts that on x86 would be handled using
NMIs to be realized on ARM.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of small fragments
    survive, however without Anton's work to build from this patch would
    not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
---
 arch/arm/kernel/entry-armv.S | 129 +++++++++++++++++++++++++++++++++++++++----
 arch/arm/kernel/fiq.c        |  19 +++++++
 arch/arm/kernel/setup.c      |   8 ++-
 3 files changed, 145 insertions(+), 11 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 36276cd..ef64333 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -79,6 +79,15 @@
 #endif
 	.endm
 
+	.macro	fiq_handler
+	ldr	r1, =.LChandle_fiq
+	mov	r0, sp
+	adr	lr, BSYM(9998f)
+	ldr	pc, [r1]
+9998:
+	.endm
+
+
 #ifdef CONFIG_KPROBES
 	.section	.kprobes.text,"ax",%progbits
 #else
@@ -146,7 +155,7 @@ ENDPROC(__und_invalid)
 #define SPFIX(code...)
 #endif
 
-	.macro	svc_entry, stack_hole=0
+	.macro	svc_entry, stack_hole=0, call_trace=1
  UNWIND(.fnstart		)
  UNWIND(.save {r0 - pc}		)
 	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
@@ -183,10 +192,35 @@ ENDPROC(__und_invalid)
 	stmia	r7, {r2 - r6}
 
 #ifdef CONFIG_TRACE_IRQFLAGS
+	.if \call_trace
 	bl	trace_hardirqs_off
+	.endif
 #endif
 	.endm
 
+@
+@ svc_exit_via_fiq - similar to svc_exit but switches to FIQ mode before exit
+@
+@ This macro acts in a similar manner to svc_exit but switches to FIQ
+@ mode to restore the final part of the register state.
+@
+@ We cannot use the normal svc_exit procedure because that would
+@ clobber spsr_svc (FIQ could be delivered during the first few instructions
+@ of vector_swi meaning its contents have not been saved anywhere).
+@
+	.macro  svc_exit_via_fiq, rpsr
+
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+	.endm
+
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -295,6 +329,14 @@ __pabt_svc:
 ENDPROC(__pabt_svc)
 
 	.align	5
+__fiq_svc:
+	svc_entry 0, 0
+	fiq_handler
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+	.align	5
 .LCcralign:
 	.word	cr_alignment
 #ifdef MULTI_DABORT
@@ -303,6 +345,43 @@ ENDPROC(__pabt_svc)
 #endif
 .LCfp:
 	.word	fp_enter
+.LChandle_fiq:
+#ifdef CONFIG_FIQ
+	.word	fiq_nmi_handler
+#else
+	.word	do_unexp_fiq
+#endif
+
+/*
+ * Abort mode handlers
+ */
+
+@
+@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
+@ and reuses the same macros. However in abort mode we must also
+@ save/restore lr_abt and spsr_abt to make nested aborts safe.
+@
+	.align 5
+__fiq_abt:
+	svc_entry 0, 0
+
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	r0, lr		@ Save lr_abt
+	mrs	r1, spsr	@ Save spsr_abt, abort is now safe
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+	push	{r0 - r1}
+
+	fiq_handler
+
+	pop	{r0 - r1}
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	lr, r0		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r1	@ Restore spsr_abt
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
 
 /*
  * User mode handlers
@@ -683,6 +762,17 @@ ENTRY(ret_from_exception)
 ENDPROC(__pabt_usr)
 ENDPROC(ret_from_exception)
 
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	fiq_handler
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+
 /*
  * Register switch for ARMv3 and ARMv4 processors
  * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
@@ -1118,17 +1208,36 @@ vector_addrexcptn:
 	b	vector_addrexcptn
 
 /*=============================================================================
- * Undefined FIQs
+ * FIQ "NMI" handler
  *-----------------------------------------------------------------------------
- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
- * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
- * Basically to switch modes, we *HAVE* to clobber one register...  brain
- * damage alert!  I don't think that we can execute any code in here in any
- * other mode than FIQ...  Ok you can switch to another mode, but you can't
- * get out of that mode without clobbering one register.
+ * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
+ * systems. The runtime environment for NMIs is extremely restrictive
+ * (NMIs can pre-empt critical sections meaning almost all locking is
+ * forbidden) meaning this default FIQ handling must only be used in
+ * circumstances where non-maskability improves robustness, such as
+ * watchdog or debug logic.
+ *
+ * This handler is inappropriate for high performance (fast) interrupt
+ * servicing and can be overridden using set_fiq_handler.
  */
-vector_fiq:
-	subs	pc, lr, #4
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
 
 	.globl	vector_fiq_offset
 	.equ	vector_fiq_offset, vector_fiq
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 3ccaa8c..77c62b2 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -43,11 +43,14 @@
 #include <linux/irq.h>
 #include <linux/radix-tree.h>
 #include <linux/slab.h>
+#include <linux/irqchip/arm-gic.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
+#include <asm/exception.h>
 #include <asm/fiq.h>
 #include <asm/irq.h>
+#include <asm/kgdb.h>
 #include <asm/traps.h>
 
 #define FIQ_OFFSET ({					\
@@ -216,6 +219,22 @@ bool has_fiq(int fiq)
 }
 EXPORT_SYMBOL(has_fiq);
 
+asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
+{
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	nmi_enter();
+
+	/* these callbacks deliberately avoid using a notifier chain in
+	 * order to ensure code review happens (drivers cannot "secretly"
+	 * employ FIQ without modifying this chain of calls).
+	 */
+	/* list is currently empty */
+
+	nmi_exit();
+	set_irq_regs(old_regs);
+}
+
 EXPORT_SYMBOL(set_fiq_handler);
 EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
 EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 84db893d..c031063 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -133,6 +133,7 @@ struct stack {
 	u32 irq[3];
 	u32 abt[3];
 	u32 und[3];
+	u32 fiq[3];
 } ____cacheline_aligned;
 
 #ifndef CONFIG_CPU_V7M
@@ -470,7 +471,10 @@ void notrace cpu_init(void)
 	"msr	cpsr_c, %5\n\t"
 	"add	r14, %0, %6\n\t"
 	"mov	sp, r14\n\t"
-	"msr	cpsr_c, %7"
+	"msr	cpsr_c, %7\n\t"
+	"add	r14, %0, %8\n\t"
+	"mov	sp, r14\n\t"
+	"msr	cpsr_c, %9"
 	    :
 	    : "r" (stk),
 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
@@ -479,6 +483,8 @@ void notrace cpu_init(void)
 	      "I" (offsetof(struct stack, abt[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
 	      "I" (offsetof(struct stack, und[0])),
+	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+	      "I" (offsetof(struct stack, fiq[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
 	    : "r14");
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 04/19] arm: smp: Introduce a special IPI signalled using FIQ
  2014-09-02 13:00                   ` Daniel Thompson
@ 2014-09-02 13:00                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

Cross CPU signalling based on FIQ is especially useful for kgdb since
it makes stopping all the CPUs during breakpointing more robust (some
of the other architectures already roundup the CPUs using NMIs).

The approach taken provides infrastructure that can be called (or not) by
the driver's FIQ handler depending upon it requirements. In other words
nothing is added here that prevents the driver from accessing "bare metal"
performance.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/hardirq.h |  2 +-
 arch/arm/include/asm/smp.h     |  7 +++++++
 arch/arm/kernel/smp.c          | 15 +++++++++++++++
 3 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
index fe3ea77..5df33e3 100644
--- a/arch/arm/include/asm/hardirq.h
+++ b/arch/arm/include/asm/hardirq.h
@@ -5,7 +5,7 @@
 #include <linux/threads.h>
 #include <asm/irq.h>
 
-#define NR_IPI	8
+#define NR_IPI	9
 
 typedef struct {
 	unsigned int __softirq_pending;
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2ec765c..215c927 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -20,6 +20,9 @@
 
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
+/* bitmap of IPIs that must be signalled using FIQ */
+#define SMP_IPI_FIQ_MASK 0x0100
+
 struct seq_file;
 
 /*
@@ -87,6 +90,10 @@ extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
 
 extern int register_ipi_completion(struct completion *completion, int cpu);
 
+#ifdef CONFIG_FIQ
+extern void send_fiq_ipi_mask(const struct cpumask *);
+#endif
+
 struct smp_operations {
 #ifdef CONFIG_SMP
 	/*
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9388a3d..d386c32 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -72,6 +72,7 @@ enum ipi_msg_type {
 	IPI_CPU_STOP,
 	IPI_IRQ_WORK,
 	IPI_COMPLETION,
+	IPI_FIQ,
 };
 
 static DECLARE_COMPLETION(cpu_running);
@@ -451,6 +452,7 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
 	S(IPI_CPU_STOP, "CPU stop interrupts"),
 	S(IPI_IRQ_WORK, "IRQ work interrupts"),
 	S(IPI_COMPLETION, "completion interrupts"),
+	S(IPI_FIQ, "FIQ interrupts"),
 };
 
 static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
@@ -552,6 +554,13 @@ static void ipi_complete(unsigned int cpu)
 	complete(per_cpu(cpu_completion, cpu));
 }
 
+#ifdef CONFIG_FIQ
+void send_fiq_ipi_mask(const struct cpumask *mask)
+{
+	smp_cross_call(mask, IPI_FIQ);
+}
+#endif
+
 /*
  * Main handler for inter-processor interrupts
  */
@@ -618,6 +627,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		irq_exit();
 		break;
 
+#ifdef CONFIG_FIQ
+	case IPI_FIQ:
+		pr_crit("CPU%u: IPI FIQ delivered via IRQ vector\n", cpu);
+		break;
+#endif
+
 	default:
 		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
 		       cpu, ipinr);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 04/19] arm: smp: Introduce a special IPI signalled using FIQ
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

Cross CPU signalling based on FIQ is especially useful for kgdb since
it makes stopping all the CPUs during breakpointing more robust (some
of the other architectures already roundup the CPUs using NMIs).

The approach taken provides infrastructure that can be called (or not) by
the driver's FIQ handler depending upon it requirements. In other words
nothing is added here that prevents the driver from accessing "bare metal"
performance.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/hardirq.h |  2 +-
 arch/arm/include/asm/smp.h     |  7 +++++++
 arch/arm/kernel/smp.c          | 15 +++++++++++++++
 3 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
index fe3ea77..5df33e3 100644
--- a/arch/arm/include/asm/hardirq.h
+++ b/arch/arm/include/asm/hardirq.h
@@ -5,7 +5,7 @@
 #include <linux/threads.h>
 #include <asm/irq.h>
 
-#define NR_IPI	8
+#define NR_IPI	9
 
 typedef struct {
 	unsigned int __softirq_pending;
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2ec765c..215c927 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -20,6 +20,9 @@
 
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
+/* bitmap of IPIs that must be signalled using FIQ */
+#define SMP_IPI_FIQ_MASK 0x0100
+
 struct seq_file;
 
 /*
@@ -87,6 +90,10 @@ extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
 
 extern int register_ipi_completion(struct completion *completion, int cpu);
 
+#ifdef CONFIG_FIQ
+extern void send_fiq_ipi_mask(const struct cpumask *);
+#endif
+
 struct smp_operations {
 #ifdef CONFIG_SMP
 	/*
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9388a3d..d386c32 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -72,6 +72,7 @@ enum ipi_msg_type {
 	IPI_CPU_STOP,
 	IPI_IRQ_WORK,
 	IPI_COMPLETION,
+	IPI_FIQ,
 };
 
 static DECLARE_COMPLETION(cpu_running);
@@ -451,6 +452,7 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
 	S(IPI_CPU_STOP, "CPU stop interrupts"),
 	S(IPI_IRQ_WORK, "IRQ work interrupts"),
 	S(IPI_COMPLETION, "completion interrupts"),
+	S(IPI_FIQ, "FIQ interrupts"),
 };
 
 static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
@@ -552,6 +554,13 @@ static void ipi_complete(unsigned int cpu)
 	complete(per_cpu(cpu_completion, cpu));
 }
 
+#ifdef CONFIG_FIQ
+void send_fiq_ipi_mask(const struct cpumask *mask)
+{
+	smp_cross_call(mask, IPI_FIQ);
+}
+#endif
+
 /*
  * Main handler for inter-processor interrupts
  */
@@ -618,6 +627,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		irq_exit();
 		break;
 
+#ifdef CONFIG_FIQ
+	case IPI_FIQ:
+		pr_crit("CPU%u: IPI FIQ delivered via IRQ vector\n", cpu);
+		break;
+#endif
+
 	default:
 		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
 		       cpu, ipinr);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 05/19] arm: KGDB/KDB FIQ support
  2014-09-02 13:00                   ` Daniel Thompson
@ 2014-09-02 13:00                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Omar Sandoval

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of comments and
    other small fragments still survive, however without Anton's work
    to build from this patch would not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben.dooks@codethink.co.uk>
Cc: Omar Sandoval <osandov@osandov.com>
---
 arch/arm/Kconfig            |   2 +
 arch/arm/Kconfig.debug      |  19 ++++++++
 arch/arm/include/asm/kgdb.h |   5 ++
 arch/arm/kernel/fiq.c       |   4 +-
 arch/arm/kernel/kgdb.c      | 112 +++++++++++++++++++++++++++++++++++++++++---
 5 files changed, 135 insertions(+), 7 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c49a775..e6380b3 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -305,6 +305,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -352,6 +353,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index b11ad54..df3f0bf 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,25 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be enabled
+	  by setting the console to ttyNMI0 (and choosing the underlying
+	  serial port using kgdboc)
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..cb5ccd6 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,9 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern int kgdb_register_fiq(unsigned int fiq);
+extern void kgdb_handle_fiq(struct pt_regs *regs);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 77c62b2..c6b3bed 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -229,7 +229,9 @@ asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
 	 * order to ensure code review happens (drivers cannot "secretly"
 	 * employ FIQ without modifying this chain of calls).
 	 */
-	/* list is currently empty */
+#ifdef CONFIG_KGDB_FIQ
+	kgdb_handle_fiq(regs);
+#endif
 
 	nmi_exit();
 	set_irq_regs(old_regs);
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
index a74b53c..630a3ef 100644
--- a/arch/arm/kernel/kgdb.c
+++ b/arch/arm/kernel/kgdb.c
@@ -12,8 +12,11 @@
 #include <linux/irq.h>
 #include <linux/kdebug.h>
 #include <linux/kgdb.h>
+#include <asm/fiq.h>
 #include <asm/traps.h>
 
+static unsigned int kgdb_fiq;
+
 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
 {
 	{ "r0", 4, offsetof(struct pt_regs, ARM_r0)},
@@ -175,14 +178,26 @@ static struct undef_hook kgdb_compiled_brkpt_hook = {
 
 static void kgdb_call_nmi_hook(void *ignored)
 {
-       kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+	kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
 }
 
 void kgdb_roundup_cpus(unsigned long flags)
 {
-       local_irq_enable();
-       smp_call_function(kgdb_call_nmi_hook, NULL, 0);
-       local_irq_disable();
+#if defined CONFIG_KGDB_FIQ && defined CONFIG_SMP
+	struct cpumask mask;
+
+	if (in_nmi()) {
+		cpumask_copy(&mask, cpu_online_mask);
+		cpumask_clear_cpu(raw_smp_processor_id(), &mask);
+		if (!cpumask_empty(&mask))
+			send_fiq_ipi_mask(&mask);
+		return;
+	}
+#endif
+
+	local_irq_enable();
+	smp_call_function(kgdb_call_nmi_hook, NULL, 0);
+	local_irq_disable();
 }
 
 static int __kgdb_notify(struct die_args *args, unsigned long cmd)
@@ -244,6 +259,43 @@ void kgdb_arch_exit(void)
 	unregister_die_notifier(&kgdb_notifier);
 }
 
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	if (!kgdb_fiq)
+		return;
+
+#ifdef CONFIG_KGDB_FIQ
+	static atomic_t cnt;
+	int ret;
+
+	if (on) {
+		ret = atomic_add_return(1, &cnt);
+		if (ret == 1)
+			enable_fiq(kgdb_fiq);
+
+		/*
+		 * There should be only one instance that calls this function
+		 * in "enable, disable" order. All other users must call
+		 * disable first, then enable. If not, something is wrong.
+		 */
+		if (WARN_ON(ret > 1))
+			return;
+	} else {
+		ret = atomic_add_return(-1, &cnt);
+		if (ret == 0)
+			disable_fiq(kgdb_fiq);
+	}
+#endif
+}
+
+
 /*
  * Register our undef instruction hooks with ARM undef core.
  * We regsiter a hook specifically looking for the KGB break inst
@@ -252,8 +304,56 @@ void kgdb_arch_exit(void)
  */
 struct kgdb_arch arch_kgdb_ops = {
 #ifndef __ARMEB__
-	.gdb_bpt_instr		= {0xfe, 0xde, 0xff, 0xe7}
+	.gdb_bpt_instr		= {0xfe, 0xde, 0xff, 0xe7},
 #else /* ! __ARMEB__ */
-	.gdb_bpt_instr		= {0xe7, 0xff, 0xde, 0xfe}
+	.gdb_bpt_instr		= {0xe7, 0xff, 0xde, 0xfe},
 #endif
+	.enable_nmi		= kgdb_fiq_enable_nmi
 };
+
+#ifdef CONFIG_KGDB_FIQ
+void kgdb_handle_fiq(struct pt_regs *regs)
+{
+	int actual;
+
+	if (!kgdb_fiq)
+		return;
+
+	if (!kgdb_nmicallback(raw_smp_processor_id(), regs))
+		return NOTIFY_OK;
+
+	actual = ack_fiq(kgdb_fiq);
+	WARN_ON(actual != kgdb_fiq);
+
+	/* there's no harm in doing this regardless of the above WARN_ON() */
+	if (kgdb_nmi_poll_knock())
+		kgdb_handle_exception(1, 0, 0, regs);
+
+	eoi_fiq(actual);
+
+	return NOTIFY_OK;
+}
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	static struct fiq_handler kgdb_fiq_desc = { .name = "kgdb", };
+	int err;
+
+	if (!has_fiq(fiq)) {
+		pr_warn(
+		    "%s: Cannot register %u (no FIQ with this number)\n",
+		    __func__, fiq);
+		return -ENODEV;
+	}
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	kgdb_fiq = fiq;
+
+	return 0;
+}
+#endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 05/19] arm: KGDB/KDB FIQ support
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

The FIQ debugger may be used to debug situations when the kernel stuck
in uninterruptable sections, e.g. the kernel infinitely loops or
deadlocked in an interrupt or with interrupts disabled.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of comments and
    other small fragments still survive, however without Anton's work
    to build from this patch would not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben.dooks@codethink.co.uk>
Cc: Omar Sandoval <osandov@osandov.com>
---
 arch/arm/Kconfig            |   2 +
 arch/arm/Kconfig.debug      |  19 ++++++++
 arch/arm/include/asm/kgdb.h |   5 ++
 arch/arm/kernel/fiq.c       |   4 +-
 arch/arm/kernel/kgdb.c      | 112 +++++++++++++++++++++++++++++++++++++++++---
 5 files changed, 135 insertions(+), 7 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c49a775..e6380b3 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -305,6 +305,7 @@ choice
 config ARCH_MULTIPLATFORM
 	bool "Allow multiple platforms to be selected"
 	depends on MMU
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_HAS_SG_CHAIN
 	select ARM_PATCH_PHYS_VIRT
@@ -352,6 +353,7 @@ config ARCH_REALVIEW
 
 config ARCH_VERSATILE
 	bool "ARM Ltd. Versatile family"
+	select ARCH_MIGHT_HAVE_KGDB_FIQ
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_TIMER_SP804
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index b11ad54..df3f0bf 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -2,6 +2,25 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config ARCH_MIGHT_HAVE_KGDB_FIQ
+	bool
+
+config KGDB_FIQ
+	bool "KGDB FIQ support"
+	depends on KGDB_KDB && ARCH_MIGHT_HAVE_KGDB_FIQ && !THUMB2_KERNEL
+	select FIQ
+	help
+	  The FIQ debugger may be used to debug situations when the
+	  kernel stuck in uninterruptable sections, e.g. the kernel
+	  infinitely loops or deadlocked in an interrupt or with
+	  interrupts disabled.
+
+	  By default KGDB FIQ is disabled at runtime, but can be enabled
+	  by setting the console to ttyNMI0 (and choosing the underlying
+	  serial port using kgdboc)
+
+	  If unsure, say N.
+
 config ARM_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 0a9d5dd..cb5ccd6 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,7 +11,9 @@
 #define __ARM_KGDB_H__
 
 #include <linux/ptrace.h>
+#include <linux/linkage.h>
 #include <asm/opcodes.h>
+#include <asm/exception.h>
 
 /*
  * GDB assumes that we're a user process being debugged, so
@@ -48,6 +50,9 @@ static inline void arch_kgdb_breakpoint(void)
 extern void kgdb_handle_bus_error(void);
 extern int kgdb_fault_expected;
 
+extern int kgdb_register_fiq(unsigned int fiq);
+extern void kgdb_handle_fiq(struct pt_regs *regs);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 77c62b2..c6b3bed 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -229,7 +229,9 @@ asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
 	 * order to ensure code review happens (drivers cannot "secretly"
 	 * employ FIQ without modifying this chain of calls).
 	 */
-	/* list is currently empty */
+#ifdef CONFIG_KGDB_FIQ
+	kgdb_handle_fiq(regs);
+#endif
 
 	nmi_exit();
 	set_irq_regs(old_regs);
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
index a74b53c..630a3ef 100644
--- a/arch/arm/kernel/kgdb.c
+++ b/arch/arm/kernel/kgdb.c
@@ -12,8 +12,11 @@
 #include <linux/irq.h>
 #include <linux/kdebug.h>
 #include <linux/kgdb.h>
+#include <asm/fiq.h>
 #include <asm/traps.h>
 
+static unsigned int kgdb_fiq;
+
 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
 {
 	{ "r0", 4, offsetof(struct pt_regs, ARM_r0)},
@@ -175,14 +178,26 @@ static struct undef_hook kgdb_compiled_brkpt_hook = {
 
 static void kgdb_call_nmi_hook(void *ignored)
 {
-       kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+	kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
 }
 
 void kgdb_roundup_cpus(unsigned long flags)
 {
-       local_irq_enable();
-       smp_call_function(kgdb_call_nmi_hook, NULL, 0);
-       local_irq_disable();
+#if defined CONFIG_KGDB_FIQ && defined CONFIG_SMP
+	struct cpumask mask;
+
+	if (in_nmi()) {
+		cpumask_copy(&mask, cpu_online_mask);
+		cpumask_clear_cpu(raw_smp_processor_id(), &mask);
+		if (!cpumask_empty(&mask))
+			send_fiq_ipi_mask(&mask);
+		return;
+	}
+#endif
+
+	local_irq_enable();
+	smp_call_function(kgdb_call_nmi_hook, NULL, 0);
+	local_irq_disable();
 }
 
 static int __kgdb_notify(struct die_args *args, unsigned long cmd)
@@ -244,6 +259,43 @@ void kgdb_arch_exit(void)
 	unregister_die_notifier(&kgdb_notifier);
 }
 
+/**
+ * kgdb_fiq_enable_nmi - Manage NMI-triggered entry to KGDB
+ * @on: Flag to either enable or disable an NMI
+ *
+ * The call counts disable requests, and thus allows to nest disables. But
+ * trying to enable already enabled NMI is an error.
+ */
+static void kgdb_fiq_enable_nmi(bool on)
+{
+	if (!kgdb_fiq)
+		return;
+
+#ifdef CONFIG_KGDB_FIQ
+	static atomic_t cnt;
+	int ret;
+
+	if (on) {
+		ret = atomic_add_return(1, &cnt);
+		if (ret == 1)
+			enable_fiq(kgdb_fiq);
+
+		/*
+		 * There should be only one instance that calls this function
+		 * in "enable, disable" order. All other users must call
+		 * disable first, then enable. If not, something is wrong.
+		 */
+		if (WARN_ON(ret > 1))
+			return;
+	} else {
+		ret = atomic_add_return(-1, &cnt);
+		if (ret == 0)
+			disable_fiq(kgdb_fiq);
+	}
+#endif
+}
+
+
 /*
  * Register our undef instruction hooks with ARM undef core.
  * We regsiter a hook specifically looking for the KGB break inst
@@ -252,8 +304,56 @@ void kgdb_arch_exit(void)
  */
 struct kgdb_arch arch_kgdb_ops = {
 #ifndef __ARMEB__
-	.gdb_bpt_instr		= {0xfe, 0xde, 0xff, 0xe7}
+	.gdb_bpt_instr		= {0xfe, 0xde, 0xff, 0xe7},
 #else /* ! __ARMEB__ */
-	.gdb_bpt_instr		= {0xe7, 0xff, 0xde, 0xfe}
+	.gdb_bpt_instr		= {0xe7, 0xff, 0xde, 0xfe},
 #endif
+	.enable_nmi		= kgdb_fiq_enable_nmi
 };
+
+#ifdef CONFIG_KGDB_FIQ
+void kgdb_handle_fiq(struct pt_regs *regs)
+{
+	int actual;
+
+	if (!kgdb_fiq)
+		return;
+
+	if (!kgdb_nmicallback(raw_smp_processor_id(), regs))
+		return NOTIFY_OK;
+
+	actual = ack_fiq(kgdb_fiq);
+	WARN_ON(actual != kgdb_fiq);
+
+	/* there's no harm in doing this regardless of the above WARN_ON() */
+	if (kgdb_nmi_poll_knock())
+		kgdb_handle_exception(1, 0, 0, regs);
+
+	eoi_fiq(actual);
+
+	return NOTIFY_OK;
+}
+
+int kgdb_register_fiq(unsigned int fiq)
+{
+	static struct fiq_handler kgdb_fiq_desc = { .name = "kgdb", };
+	int err;
+
+	if (!has_fiq(fiq)) {
+		pr_warn(
+		    "%s: Cannot register %u (no FIQ with this number)\n",
+		    __func__, fiq);
+		return -ENODEV;
+	}
+
+	err = claim_fiq(&kgdb_fiq_desc);
+	if (err) {
+		pr_warn("%s: unable to claim fiq", __func__);
+		return err;
+	}
+
+	kgdb_fiq = fiq;
+
+	return 0;
+}
+#endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 06/19] irqchip: gic: Provide support for interrupt grouping
  2014-09-02 13:00                   ` Daniel Thompson
@ 2014-09-02 13:00                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Thomas Gleixner, Jason Cooper, Nicolas Pitre,
	Christoffer Dall, Sricharan R, Marc Zyngier

All GIC hardware except GICv1-without-TrustZone support provides a means
to group exceptions into group 0 (which can optionally be signally using
use FIQ) and group 1. The kernel currently provides no means to exploit
this. This patch alters the initialization of the GIC to place all
interrupts into group 1 which is the foundational requirement to meaningfully
use FIQ.

Note that the hardware functionality is unavailable to the kernel when a
secure monitor is present because access to the grouping registers are
prohibited outside "secure world" (this feature allows grouping to be
used to allow hardware peripherals to send interrupts into the secure
world). The GIC driver will automatically detect this and disable its
attempts to group interrupts.

On systems without TrustZone support the kernel has the power to route
interrupt sources to FIQ, potentially allowing a driver to exploit the
NMI-like properties of FIQ.

Tested on Freescale i.MX6 (quad A9), STiH416 (dual A9) and a self-written
qemu GICv2 model.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Dirk Behme <dirk.behme@de.bosch.com>
---
 drivers/irqchip/irq-gic.c | 99 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 94 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4b959e6..423707c 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -41,6 +41,9 @@
 #include <linux/irqchip/arm-gic.h>
 
 #include <asm/cputype.h>
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
@@ -68,6 +71,9 @@ struct gic_chip_data {
 #ifdef CONFIG_GIC_NON_BANKED
 	void __iomem *(*get_base)(union gic_base *);
 #endif
+#ifdef CONFIG_FIQ
+	bool fiq_enable;
+#endif
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
@@ -131,6 +137,16 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data,
 #define gic_set_base_accessor(d, f)
 #endif
 
+#ifdef CONFIG_FIQ
+static inline bool gic_data_fiq_enable(struct gic_chip_data *data)
+{
+	return data->fiq_enable;
+}
+#else
+static inline bool gic_data_fiq_enable(
+		struct gic_chip_data *data) { return false; }
+#endif
+
 static inline void __iomem *gic_dist_base(struct irq_data *d)
 {
 	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
@@ -325,6 +341,42 @@ static struct irq_chip gic_chip = {
 	.irq_set_wake		= gic_set_wake,
 };
 
+#ifdef CONFIG_FIQ
+static void __init gic_init_fiq(struct gic_chip_data *gic,
+				irq_hw_number_t first_irq,
+				unsigned int num_irqs)
+{
+	void __iomem *dist_base = gic_data_dist_base(gic_data);
+	unsigned int i;
+
+	/*
+	 * FIQ can only be supported on platforms without an extended irq_eoi
+	 * method (otherwise we take a lock during eoi handling).
+	 */
+	if (gic_arch_extn.irq_eoi)
+		return;
+
+	/*
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers a read-as-zero/write-ignored.
+	 * However as a precaution we restore the reset default regardless of
+	 * the result of the test.
+	 */
+	writel_relaxed(1, dist_base + GIC_DIST_IGROUP + 0);
+	gic->fiq_enable = readl_relaxed(dist_base + GIC_DIST_IGROUP + 0);
+	writel_relaxed(0, dist_base + GIC_DIST_IGROUP + 0);
+	pr_debug("gic: FIQ support %s\n",
+		 gic->fiq_enable ? "enabled" : "disabled");
+
+	if (!gic->fiq_enable)
+		return;
+}
+#else /* CONFIG_FIQ */
+static inline void gic_init_fiq(struct gic_chip_data *gic,
+				irq_hw_number_t first_irq,
+				unsigned int num_irqs) {}
+#endif /* CONFIG_FIQ */
+
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
 	if (gic_nr >= MAX_GIC_NR)
@@ -373,7 +425,22 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 
 	gic_dist_config(base, gic_irqs, NULL);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Optionally set all global interrupts to be group 1.
+	 */
+	if (gic_data_fiq_enable(gic))
+		for (i = 32; i < gic_irqs; i += 32)
+			writel_relaxed(0xffffffff,
+				       base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(3, base + GIC_DIST_CTRL);
+	else
+		writel_relaxed(1, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -400,8 +467,20 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 
 	gic_cpu_config(dist_base, NULL);
 
+	/*
+	 * Set all PPI and SGI interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers are read-as-zero/write-ignored.
+	 */
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
+	else
+		writel_relaxed(1, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -485,7 +564,10 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	if (gic_data_fiq_enable(&gic_data[gic_nr]))
+		writel_relaxed(3, dist_base + GIC_DIST_CTRL);
+	else
+		writel_relaxed(1, dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -542,7 +624,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -604,6 +686,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
 	unsigned long flags, map = 0;
+	unsigned long softint;
 
 	raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
@@ -618,7 +701,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+	softint = map << 16 | irq;
+	if (gic_data_fiq_enable(&gic_data[0]))
+		softint |= 0x8000;
+	writel_relaxed(softint,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
@@ -964,6 +1051,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 
 		gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
 					hwirq_base, &gic_irq_domain_ops, gic);
+
+		gic_init_fiq(gic, irq_base, gic_irqs);
 	} else {
 		gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
 						    &gic_irq_domain_ops,
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 06/19] irqchip: gic: Provide support for interrupt grouping
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

All GIC hardware except GICv1-without-TrustZone support provides a means
to group exceptions into group 0 (which can optionally be signally using
use FIQ) and group 1. The kernel currently provides no means to exploit
this. This patch alters the initialization of the GIC to place all
interrupts into group 1 which is the foundational requirement to meaningfully
use FIQ.

Note that the hardware functionality is unavailable to the kernel when a
secure monitor is present because access to the grouping registers are
prohibited outside "secure world" (this feature allows grouping to be
used to allow hardware peripherals to send interrupts into the secure
world). The GIC driver will automatically detect this and disable its
attempts to group interrupts.

On systems without TrustZone support the kernel has the power to route
interrupt sources to FIQ, potentially allowing a driver to exploit the
NMI-like properties of FIQ.

Tested on Freescale i.MX6 (quad A9), STiH416 (dual A9) and a self-written
qemu GICv2 model.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Dirk Behme <dirk.behme@de.bosch.com>
---
 drivers/irqchip/irq-gic.c | 99 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 94 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4b959e6..423707c 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -41,6 +41,9 @@
 #include <linux/irqchip/arm-gic.h>
 
 #include <asm/cputype.h>
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
@@ -68,6 +71,9 @@ struct gic_chip_data {
 #ifdef CONFIG_GIC_NON_BANKED
 	void __iomem *(*get_base)(union gic_base *);
 #endif
+#ifdef CONFIG_FIQ
+	bool fiq_enable;
+#endif
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
@@ -131,6 +137,16 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data,
 #define gic_set_base_accessor(d, f)
 #endif
 
+#ifdef CONFIG_FIQ
+static inline bool gic_data_fiq_enable(struct gic_chip_data *data)
+{
+	return data->fiq_enable;
+}
+#else
+static inline bool gic_data_fiq_enable(
+		struct gic_chip_data *data) { return false; }
+#endif
+
 static inline void __iomem *gic_dist_base(struct irq_data *d)
 {
 	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
@@ -325,6 +341,42 @@ static struct irq_chip gic_chip = {
 	.irq_set_wake		= gic_set_wake,
 };
 
+#ifdef CONFIG_FIQ
+static void __init gic_init_fiq(struct gic_chip_data *gic,
+				irq_hw_number_t first_irq,
+				unsigned int num_irqs)
+{
+	void __iomem *dist_base = gic_data_dist_base(gic_data);
+	unsigned int i;
+
+	/*
+	 * FIQ can only be supported on platforms without an extended irq_eoi
+	 * method (otherwise we take a lock during eoi handling).
+	 */
+	if (gic_arch_extn.irq_eoi)
+		return;
+
+	/*
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers a read-as-zero/write-ignored.
+	 * However as a precaution we restore the reset default regardless of
+	 * the result of the test.
+	 */
+	writel_relaxed(1, dist_base + GIC_DIST_IGROUP + 0);
+	gic->fiq_enable = readl_relaxed(dist_base + GIC_DIST_IGROUP + 0);
+	writel_relaxed(0, dist_base + GIC_DIST_IGROUP + 0);
+	pr_debug("gic: FIQ support %s\n",
+		 gic->fiq_enable ? "enabled" : "disabled");
+
+	if (!gic->fiq_enable)
+		return;
+}
+#else /* CONFIG_FIQ */
+static inline void gic_init_fiq(struct gic_chip_data *gic,
+				irq_hw_number_t first_irq,
+				unsigned int num_irqs) {}
+#endif /* CONFIG_FIQ */
+
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
 	if (gic_nr >= MAX_GIC_NR)
@@ -373,7 +425,22 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 
 	gic_dist_config(base, gic_irqs, NULL);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Optionally set all global interrupts to be group 1.
+	 */
+	if (gic_data_fiq_enable(gic))
+		for (i = 32; i < gic_irqs; i += 32)
+			writel_relaxed(0xffffffff,
+				       base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(3, base + GIC_DIST_CTRL);
+	else
+		writel_relaxed(1, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -400,8 +467,20 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 
 	gic_cpu_config(dist_base, NULL);
 
+	/*
+	 * Set all PPI and SGI interrupts to be group 1.
+	 *
+	 * If grouping is not available (not implemented or prohibited by
+	 * security mode) these registers are read-as-zero/write-ignored.
+	 */
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+	if (gic_data_fiq_enable(gic))
+		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
+	else
+		writel_relaxed(1, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -485,7 +564,10 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	if (gic_data_fiq_enable(&gic_data[gic_nr]))
+		writel_relaxed(3, dist_base + GIC_DIST_CTRL);
+	else
+		writel_relaxed(1, dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -542,7 +624,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -604,6 +686,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
 	unsigned long flags, map = 0;
+	unsigned long softint;
 
 	raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
@@ -618,7 +701,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+	softint = map << 16 | irq;
+	if (gic_data_fiq_enable(&gic_data[0]))
+		softint |= 0x8000;
+	writel_relaxed(softint,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
@@ -964,6 +1051,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 
 		gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
 					hwirq_base, &gic_irq_domain_ops, gic);
+
+		gic_init_fiq(gic, irq_base, gic_irqs);
 	} else {
 		gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
 						    &gic_irq_domain_ops,
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 07/19] irqchip: gic: Add support for FIQ management
  2014-09-02 13:00                   ` Daniel Thompson
@ 2014-09-02 13:00                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Thomas Gleixner, Jason Cooper, Nicolas Pitre,
	Christoffer Dall, Sricharan R

This patch introduces callbacks to route interrupts to or away
from the FIQ signal and registers these callbacks with the FIQ
infrastructure (if the device can supports it).

Both these aspects combine and allow a driver to deploy a FIQ handler
without any machine specific knowledge; it can be used effectively on
multi-platform kernels.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
---
 drivers/irqchip/irq-gic.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 423707c..6fa0542 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -342,6 +342,69 @@ static struct irq_chip gic_chip = {
 };
 
 #ifdef CONFIG_FIQ
+/*
+ * Shift an interrupt between Group 0 and Group 1.
+ *
+ * In addition to changing the group we also modify the priority to
+ * match what "ARM strongly recommends" for a system where no Group 1
+ * interrupt must ever preempt a Group 0 interrupt.
+ */
+static void gic_set_group_irq(struct irq_data *d, int group)
+{
+	unsigned int grp_reg = gic_irq(d) / 32 * 4;
+	u32 grp_mask = 1 << (gic_irq(d) % 32);
+	u32 grp_val;
+
+	unsigned int pri_reg = (gic_irq(d) / 4) * 4;
+	u32 pri_mask = 1 << (7 + ((gic_irq(d) % 4) * 8));
+	u32 pri_val;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	grp_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+
+	if (group) {
+		grp_val |= grp_mask;
+		pri_val |= pri_mask;
+	} else {
+		grp_val &= ~grp_mask;
+		pri_val &= ~pri_mask;
+	}
+
+	writel_relaxed(grp_val, gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void gic_enable_fiq(struct irq_data *d)
+{
+	gic_set_group_irq(d, 0);
+}
+
+static void gic_disable_fiq(struct irq_data *d)
+{
+	gic_set_group_irq(d, 1);
+}
+
+static int gic_ack_fiq(struct irq_data *d)
+{
+	struct gic_chip_data *gic = irq_data_get_irq_chip_data(d);
+	u32 irqstat, irqnr;
+
+	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+	irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	return irq_find_mapping(gic->domain, irqnr);
+}
+
+static struct fiq_chip gic_fiq = {
+	.fiq_enable		= gic_enable_fiq,
+	.fiq_disable            = gic_disable_fiq,
+	.fiq_ack		= gic_ack_fiq,
+	.fiq_eoi		= gic_eoi_irq,
+};
+
 static void __init gic_init_fiq(struct gic_chip_data *gic,
 				irq_hw_number_t first_irq,
 				unsigned int num_irqs)
@@ -370,6 +433,12 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 
 	if (!gic->fiq_enable)
 		return;
+
+	/*
+	 * FIQ is supported on this device! Register our chip data.
+	 */
+	for (i = 0; i < num_irqs; i++)
+		fiq_register_mapping(first_irq + i, &gic_fiq);
 }
 #else /* CONFIG_FIQ */
 static inline void gic_init_fiq(struct gic_chip_data *gic,
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 07/19] irqchip: gic: Add support for FIQ management
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

This patch introduces callbacks to route interrupts to or away
from the FIQ signal and registers these callbacks with the FIQ
infrastructure (if the device can supports it).

Both these aspects combine and allow a driver to deploy a FIQ handler
without any machine specific knowledge; it can be used effectively on
multi-platform kernels.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sricharan R <r.sricharan@ti.com>
---
 drivers/irqchip/irq-gic.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 423707c..6fa0542 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -342,6 +342,69 @@ static struct irq_chip gic_chip = {
 };
 
 #ifdef CONFIG_FIQ
+/*
+ * Shift an interrupt between Group 0 and Group 1.
+ *
+ * In addition to changing the group we also modify the priority to
+ * match what "ARM strongly recommends" for a system where no Group 1
+ * interrupt must ever preempt a Group 0 interrupt.
+ */
+static void gic_set_group_irq(struct irq_data *d, int group)
+{
+	unsigned int grp_reg = gic_irq(d) / 32 * 4;
+	u32 grp_mask = 1 << (gic_irq(d) % 32);
+	u32 grp_val;
+
+	unsigned int pri_reg = (gic_irq(d) / 4) * 4;
+	u32 pri_mask = 1 << (7 + ((gic_irq(d) % 4) * 8));
+	u32 pri_val;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	grp_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+
+	if (group) {
+		grp_val |= grp_mask;
+		pri_val |= pri_mask;
+	} else {
+		grp_val &= ~grp_mask;
+		pri_val &= ~pri_mask;
+	}
+
+	writel_relaxed(grp_val, gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void gic_enable_fiq(struct irq_data *d)
+{
+	gic_set_group_irq(d, 0);
+}
+
+static void gic_disable_fiq(struct irq_data *d)
+{
+	gic_set_group_irq(d, 1);
+}
+
+static int gic_ack_fiq(struct irq_data *d)
+{
+	struct gic_chip_data *gic = irq_data_get_irq_chip_data(d);
+	u32 irqstat, irqnr;
+
+	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+	irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	return irq_find_mapping(gic->domain, irqnr);
+}
+
+static struct fiq_chip gic_fiq = {
+	.fiq_enable		= gic_enable_fiq,
+	.fiq_disable            = gic_disable_fiq,
+	.fiq_ack		= gic_ack_fiq,
+	.fiq_eoi		= gic_eoi_irq,
+};
+
 static void __init gic_init_fiq(struct gic_chip_data *gic,
 				irq_hw_number_t first_irq,
 				unsigned int num_irqs)
@@ -370,6 +433,12 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 
 	if (!gic->fiq_enable)
 		return;
+
+	/*
+	 * FIQ is supported on this device! Register our chip data.
+	 */
+	for (i = 0; i < num_irqs; i++)
+		fiq_register_mapping(first_irq + i, &gic_fiq);
 }
 #else /* CONFIG_FIQ */
 static inline void gic_init_fiq(struct gic_chip_data *gic,
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 08/19] irqchip: gic: Remove spin locks from eoi_irq
  2014-09-02 13:00                   ` Daniel Thompson
@ 2014-09-02 13:00                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Thomas Gleixner, Jason Cooper, Peter De Schrijver

This patch is motivated by the comment it removes from gic_init_fiq,
namely that the spin locks in eoi_irq preclude certain platforms from
supporting FIQ.

Currently there is only one upstream platform (tegra) that actually
hooks gic_arch_extn.irq_eoi and it does not require these spin locks.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Peter De Schrijver <pdeschrijver@nvidia.com>
---
 drivers/irqchip/irq-gic.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 6fa0542..d928912 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -191,11 +191,8 @@ static void gic_unmask_irq(struct irq_data *d)
 
 static void gic_eoi_irq(struct irq_data *d)
 {
-	if (gic_arch_extn.irq_eoi) {
-		raw_spin_lock(&irq_controller_lock);
+	if (gic_arch_extn.irq_eoi)
 		gic_arch_extn.irq_eoi(d);
-		raw_spin_unlock(&irq_controller_lock);
-	}
 
 	writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
 }
@@ -413,13 +410,6 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 	unsigned int i;
 
 	/*
-	 * FIQ can only be supported on platforms without an extended irq_eoi
-	 * method (otherwise we take a lock during eoi handling).
-	 */
-	if (gic_arch_extn.irq_eoi)
-		return;
-
-	/*
 	 * If grouping is not available (not implemented or prohibited by
 	 * security mode) these registers a read-as-zero/write-ignored.
 	 * However as a precaution we restore the reset default regardless of
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 08/19] irqchip: gic: Remove spin locks from eoi_irq
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

This patch is motivated by the comment it removes from gic_init_fiq,
namely that the spin locks in eoi_irq preclude certain platforms from
supporting FIQ.

Currently there is only one upstream platform (tegra) that actually
hooks gic_arch_extn.irq_eoi and it does not require these spin locks.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Peter De Schrijver <pdeschrijver@nvidia.com>
---
 drivers/irqchip/irq-gic.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 6fa0542..d928912 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -191,11 +191,8 @@ static void gic_unmask_irq(struct irq_data *d)
 
 static void gic_eoi_irq(struct irq_data *d)
 {
-	if (gic_arch_extn.irq_eoi) {
-		raw_spin_lock(&irq_controller_lock);
+	if (gic_arch_extn.irq_eoi)
 		gic_arch_extn.irq_eoi(d);
-		raw_spin_unlock(&irq_controller_lock);
-	}
 
 	writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
 }
@@ -413,13 +410,6 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 	unsigned int i;
 
 	/*
-	 * FIQ can only be supported on platforms without an extended irq_eoi
-	 * method (otherwise we take a lock during eoi handling).
-	 */
-	if (gic_arch_extn.irq_eoi)
-		return;
-
-	/*
 	 * If grouping is not available (not implemented or prohibited by
 	 * security mode) these registers a read-as-zero/write-ignored.
 	 * However as a precaution we restore the reset default regardless of
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 09/19] irqchip: gic: Add support for IPI FIQ
  2014-09-02 13:00                   ` Daniel Thompson
@ 2014-09-02 13:00                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

To support IPI FIQ we alter gic_cpu_init() to honour SMP_IPI_FIQ_MASK and
register a fairly high priority notifier to acknowledge and clear the IPI
when it is triggered.

For the IPI FIQ to be useful we must also make it safe to call
gic_raise_softirq() from the FIQ handler by altering the locking
strategy slightly.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/kernel/fiq.c     |   3 ++
 drivers/irqchip/irq-gic.c | 125 ++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 107 insertions(+), 21 deletions(-)

diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index c6b3bed..115d319 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -232,6 +232,9 @@ asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
 #ifdef CONFIG_KGDB_FIQ
 	kgdb_handle_fiq(regs);
 #endif
+#ifdef CONFIG_ARM_GIC
+	gic_handle_fiq_ipi();
+#endif
 
 	nmi_exit();
 	set_irq_regs(old_regs);
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index d928912..8834749 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,6 +39,7 @@
 #include <linux/slab.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/ratelimit.h>
 
 #include <asm/cputype.h>
 #ifdef CONFIG_FIQ
@@ -51,6 +52,10 @@
 #include "irq-gic-common.h"
 #include "irqchip.h"
 
+#ifndef SMP_IPI_FIQ_MASK
+#define SMP_IPI_FIQ_MASK 0
+#endif
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -77,6 +82,8 @@ struct gic_chip_data {
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+/* A fiq-safe spinlock must only be locked when the FIQ is masked */
+static DEFINE_RAW_SPINLOCK(fiq_safe_migration_lock);
 
 /*
  * The GIC mapping of CPU interfaces does not necessarily match
@@ -346,20 +353,21 @@ static struct irq_chip gic_chip = {
  * match what "ARM strongly recommends" for a system where no Group 1
  * interrupt must ever preempt a Group 0 interrupt.
  */
-static void gic_set_group_irq(struct irq_data *d, int group)
+static void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				int group)
 {
-	unsigned int grp_reg = gic_irq(d) / 32 * 4;
-	u32 grp_mask = 1 << (gic_irq(d) % 32);
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_mask = 1 << (hwirq % 32);
 	u32 grp_val;
 
-	unsigned int pri_reg = (gic_irq(d) / 4) * 4;
-	u32 pri_mask = 1 << (7 + ((gic_irq(d) % 4) * 8));
+	unsigned int pri_reg = (hwirq / 4) * 4;
+	u32 pri_mask = 1 << (7 + ((hwirq % 4) * 8));
 	u32 pri_val;
 
 	raw_spin_lock(&irq_controller_lock);
 
-	grp_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
-	pri_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(base + GIC_DIST_PRI + pri_reg);
 
 	if (group) {
 		grp_val |= grp_mask;
@@ -369,20 +377,20 @@ static void gic_set_group_irq(struct irq_data *d, int group)
 		pri_val &= ~pri_mask;
 	}
 
-	writel_relaxed(grp_val, gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
-	writel_relaxed(pri_val, gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+	writel_relaxed(grp_val, base + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, base + GIC_DIST_PRI + pri_reg);
 
 	raw_spin_unlock(&irq_controller_lock);
 }
 
 static void gic_enable_fiq(struct irq_data *d)
 {
-	gic_set_group_irq(d, 0);
+	gic_set_group_irq(gic_dist_base(d), gic_irq(d), 0);
 }
 
 static void gic_disable_fiq(struct irq_data *d)
 {
-	gic_set_group_irq(d, 1);
+	gic_set_group_irq(gic_dist_base(d), gic_irq(d), 1);
 }
 
 static int gic_ack_fiq(struct irq_data *d)
@@ -390,8 +398,22 @@ static int gic_ack_fiq(struct irq_data *d)
 	struct gic_chip_data *gic = irq_data_get_irq_chip_data(d);
 	u32 irqstat, irqnr;
 
-	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
-	irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	while (1) {
+		writel_relaxed(0x70, gic_data_cpu_base(gic) + GIC_CPU_PRIMASK);
+		irqstat =
+		    readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+		writel_relaxed(0xf0, gic_data_cpu_base(gic) + GIC_CPU_PRIMASK);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		if (irqnr > 15)
+			break;
+
+		/* we've got an IPI which we can simply acknowledge
+		 * and move on
+		 */
+		gic_eoi_irq(d);
+	}
+
 	return irq_find_mapping(gic->domain, irqnr);
 }
 
@@ -430,7 +452,43 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 	for (i = 0; i < num_irqs; i++)
 		fiq_register_mapping(first_irq + i, &gic_fiq);
 }
+
+/*
+ * Fully acknowledge (both ack and eoi) a FIQ-based IPI
+ */
+static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
+			   void *data)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	unsigned long irqstat, irqnr;
+
+	if (WARN_ON(!in_nmi()))
+		return NOTIFY_BAD;
+
+	while ((1u << readl_relaxed(cpu_base + GIC_CPU_HIGHPRI)) &
+	       SMP_IPI_FIQ_MASK) {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		WARN_RATELIMIT(irqnr > 16,
+			       "Unexpected irqnr %lu (bad prioritization?)\n",
+			       irqnr);
+	}
+
+	return NOTIFY_OK;
+}
+
+/*
+ * Notifier to ensure IPI FIQ is acknowledged correctly.
+ */
+static struct notifier_block gic_fiq_ipi_notifier = {
+	.notifier_call = gic_handle_fiq_ipi,
+};
 #else /* CONFIG_FIQ */
+static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				     int group) {}
 static inline void gic_init_fiq(struct gic_chip_data *gic,
 				irq_hw_number_t first_irq,
 				unsigned int num_irqs) {}
@@ -527,14 +585,19 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	gic_cpu_config(dist_base, NULL);
 
 	/*
-	 * Set all PPI and SGI interrupts to be group 1.
-	 *
-	 * If grouping is not available (not implemented or prohibited by
-	 * security mode) these registers are read-as-zero/write-ignored.
+	 * Optionally set all PPI and SGI interrupts to be group 1.
 	 */
 	if (gic_data_fiq_enable(gic))
 		writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
 
+	/*
+	 * Optionally shift the FIQ based IPIs to group 0.
+	 */
+	if (gic_data_fiq_enable(gic))
+		for (i = 0; i < 16; i++)
+			if (SMP_IPI_FIQ_MASK & (1 << i))
+				gic_set_group_irq(dist_base, i, 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
 	if (gic_data_fiq_enable(gic))
 		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
@@ -747,7 +810,17 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	unsigned long flags, map = 0;
 	unsigned long softint;
 
-	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+	/*
+	 * The locking in this function ensures we don't use stale cpu mappings
+	 * and thus we never route an IPI to the wrong physical core during a
+	 * big.LITTLE switch. The switch code takes both of these locks meaning
+	 * we can choose whichever lock is safe to use from our current calling
+	 * context.
+	 */
+	if (in_nmi())
+		raw_spin_lock(&fiq_safe_migration_lock);
+	else
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
 	/* Convert our logical CPU mask into a physical one. */
 	for_each_cpu(cpu, mask)
@@ -761,12 +834,16 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 
 	/* this always happens on GIC0 */
 	softint = map << 16 | irq;
-	if (gic_data_fiq_enable(&gic_data[0]))
+	if (gic_data_fiq_enable(&gic_data[0]) &&
+	    !(SMP_IPI_FIQ_MASK & (1 << irq)))
 		softint |= 0x8000;
 	writel_relaxed(softint,
 		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
-	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+	if (in_nmi())
+		raw_spin_unlock(&fiq_safe_migration_lock);
+	else
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 #endif
 
@@ -814,7 +891,7 @@ int gic_get_cpu_id(unsigned int cpu)
  * Migrate all peripheral interrupts with a target matching the current CPU
  * to the interface corresponding to @new_cpu_id.  The CPU interface mapping
  * is also updated.  Targets to other CPU interfaces are unchanged.
- * This must be called with IRQs locally disabled.
+ * This must be called with IRQ and FIQ locally disabled.
  */
 void gic_migrate_target(unsigned int new_cpu_id)
 {
@@ -836,6 +913,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 	ror_val = (cur_cpu_id - new_cpu_id) & 31;
 
 	raw_spin_lock(&irq_controller_lock);
+	raw_spin_lock(&fiq_safe_migration_lock);
 
 	/* Update the target interface for this logical CPU */
 	gic_cpu_map[cpu] = 1 << new_cpu_id;
@@ -855,6 +933,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 		}
 	}
 
+	raw_spin_unlock(&fiq_safe_migration_lock);
 	raw_spin_unlock(&irq_controller_lock);
 
 	/*
@@ -1125,6 +1204,10 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 #ifdef CONFIG_SMP
 		set_smp_cross_call(gic_raise_softirq);
 		register_cpu_notifier(&gic_cpu_notifier);
+#ifdef CONFIG_FIQ
+		if (gic_data_fiq_enable(gic))
+			register_fiq_nmi_notifier(&gic_fiq_ipi_notifier);
+#endif
 #endif
 		set_handle_irq(gic_handle_irq);
 	}
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 09/19] irqchip: gic: Add support for IPI FIQ
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

To support IPI FIQ we alter gic_cpu_init() to honour SMP_IPI_FIQ_MASK and
register a fairly high priority notifier to acknowledge and clear the IPI
when it is triggered.

For the IPI FIQ to be useful we must also make it safe to call
gic_raise_softirq() from the FIQ handler by altering the locking
strategy slightly.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/kernel/fiq.c     |   3 ++
 drivers/irqchip/irq-gic.c | 125 ++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 107 insertions(+), 21 deletions(-)

diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index c6b3bed..115d319 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -232,6 +232,9 @@ asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
 #ifdef CONFIG_KGDB_FIQ
 	kgdb_handle_fiq(regs);
 #endif
+#ifdef CONFIG_ARM_GIC
+	gic_handle_fiq_ipi();
+#endif
 
 	nmi_exit();
 	set_irq_regs(old_regs);
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index d928912..8834749 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,6 +39,7 @@
 #include <linux/slab.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/ratelimit.h>
 
 #include <asm/cputype.h>
 #ifdef CONFIG_FIQ
@@ -51,6 +52,10 @@
 #include "irq-gic-common.h"
 #include "irqchip.h"
 
+#ifndef SMP_IPI_FIQ_MASK
+#define SMP_IPI_FIQ_MASK 0
+#endif
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -77,6 +82,8 @@ struct gic_chip_data {
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+/* A fiq-safe spinlock must only be locked when the FIQ is masked */
+static DEFINE_RAW_SPINLOCK(fiq_safe_migration_lock);
 
 /*
  * The GIC mapping of CPU interfaces does not necessarily match
@@ -346,20 +353,21 @@ static struct irq_chip gic_chip = {
  * match what "ARM strongly recommends" for a system where no Group 1
  * interrupt must ever preempt a Group 0 interrupt.
  */
-static void gic_set_group_irq(struct irq_data *d, int group)
+static void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				int group)
 {
-	unsigned int grp_reg = gic_irq(d) / 32 * 4;
-	u32 grp_mask = 1 << (gic_irq(d) % 32);
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_mask = 1 << (hwirq % 32);
 	u32 grp_val;
 
-	unsigned int pri_reg = (gic_irq(d) / 4) * 4;
-	u32 pri_mask = 1 << (7 + ((gic_irq(d) % 4) * 8));
+	unsigned int pri_reg = (hwirq / 4) * 4;
+	u32 pri_mask = 1 << (7 + ((hwirq % 4) * 8));
 	u32 pri_val;
 
 	raw_spin_lock(&irq_controller_lock);
 
-	grp_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
-	pri_val = readl_relaxed(gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(base + GIC_DIST_PRI + pri_reg);
 
 	if (group) {
 		grp_val |= grp_mask;
@@ -369,20 +377,20 @@ static void gic_set_group_irq(struct irq_data *d, int group)
 		pri_val &= ~pri_mask;
 	}
 
-	writel_relaxed(grp_val, gic_dist_base(d) + GIC_DIST_IGROUP + grp_reg);
-	writel_relaxed(pri_val, gic_dist_base(d) + GIC_DIST_PRI + pri_reg);
+	writel_relaxed(grp_val, base + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, base + GIC_DIST_PRI + pri_reg);
 
 	raw_spin_unlock(&irq_controller_lock);
 }
 
 static void gic_enable_fiq(struct irq_data *d)
 {
-	gic_set_group_irq(d, 0);
+	gic_set_group_irq(gic_dist_base(d), gic_irq(d), 0);
 }
 
 static void gic_disable_fiq(struct irq_data *d)
 {
-	gic_set_group_irq(d, 1);
+	gic_set_group_irq(gic_dist_base(d), gic_irq(d), 1);
 }
 
 static int gic_ack_fiq(struct irq_data *d)
@@ -390,8 +398,22 @@ static int gic_ack_fiq(struct irq_data *d)
 	struct gic_chip_data *gic = irq_data_get_irq_chip_data(d);
 	u32 irqstat, irqnr;
 
-	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
-	irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	while (1) {
+		writel_relaxed(0x70, gic_data_cpu_base(gic) + GIC_CPU_PRIMASK);
+		irqstat =
+		    readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+		writel_relaxed(0xf0, gic_data_cpu_base(gic) + GIC_CPU_PRIMASK);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		if (irqnr > 15)
+			break;
+
+		/* we've got an IPI which we can simply acknowledge
+		 * and move on
+		 */
+		gic_eoi_irq(d);
+	}
+
 	return irq_find_mapping(gic->domain, irqnr);
 }
 
@@ -430,7 +452,43 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 	for (i = 0; i < num_irqs; i++)
 		fiq_register_mapping(first_irq + i, &gic_fiq);
 }
+
+/*
+ * Fully acknowledge (both ack and eoi) a FIQ-based IPI
+ */
+static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
+			   void *data)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	unsigned long irqstat, irqnr;
+
+	if (WARN_ON(!in_nmi()))
+		return NOTIFY_BAD;
+
+	while ((1u << readl_relaxed(cpu_base + GIC_CPU_HIGHPRI)) &
+	       SMP_IPI_FIQ_MASK) {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		WARN_RATELIMIT(irqnr > 16,
+			       "Unexpected irqnr %lu (bad prioritization?)\n",
+			       irqnr);
+	}
+
+	return NOTIFY_OK;
+}
+
+/*
+ * Notifier to ensure IPI FIQ is acknowledged correctly.
+ */
+static struct notifier_block gic_fiq_ipi_notifier = {
+	.notifier_call = gic_handle_fiq_ipi,
+};
 #else /* CONFIG_FIQ */
+static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				     int group) {}
 static inline void gic_init_fiq(struct gic_chip_data *gic,
 				irq_hw_number_t first_irq,
 				unsigned int num_irqs) {}
@@ -527,14 +585,19 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	gic_cpu_config(dist_base, NULL);
 
 	/*
-	 * Set all PPI and SGI interrupts to be group 1.
-	 *
-	 * If grouping is not available (not implemented or prohibited by
-	 * security mode) these registers are read-as-zero/write-ignored.
+	 * Optionally set all PPI and SGI interrupts to be group 1.
 	 */
 	if (gic_data_fiq_enable(gic))
 		writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0);
 
+	/*
+	 * Optionally shift the FIQ based IPIs to group 0.
+	 */
+	if (gic_data_fiq_enable(gic))
+		for (i = 0; i < 16; i++)
+			if (SMP_IPI_FIQ_MASK & (1 << i))
+				gic_set_group_irq(dist_base, i, 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
 	if (gic_data_fiq_enable(gic))
 		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
@@ -747,7 +810,17 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	unsigned long flags, map = 0;
 	unsigned long softint;
 
-	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+	/*
+	 * The locking in this function ensures we don't use stale cpu mappings
+	 * and thus we never route an IPI to the wrong physical core during a
+	 * big.LITTLE switch. The switch code takes both of these locks meaning
+	 * we can choose whichever lock is safe to use from our current calling
+	 * context.
+	 */
+	if (in_nmi())
+		raw_spin_lock(&fiq_safe_migration_lock);
+	else
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
 	/* Convert our logical CPU mask into a physical one. */
 	for_each_cpu(cpu, mask)
@@ -761,12 +834,16 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 
 	/* this always happens on GIC0 */
 	softint = map << 16 | irq;
-	if (gic_data_fiq_enable(&gic_data[0]))
+	if (gic_data_fiq_enable(&gic_data[0]) &&
+	    !(SMP_IPI_FIQ_MASK & (1 << irq)))
 		softint |= 0x8000;
 	writel_relaxed(softint,
 		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
-	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+	if (in_nmi())
+		raw_spin_unlock(&fiq_safe_migration_lock);
+	else
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 #endif
 
@@ -814,7 +891,7 @@ int gic_get_cpu_id(unsigned int cpu)
  * Migrate all peripheral interrupts with a target matching the current CPU
  * to the interface corresponding to @new_cpu_id.  The CPU interface mapping
  * is also updated.  Targets to other CPU interfaces are unchanged.
- * This must be called with IRQs locally disabled.
+ * This must be called with IRQ and FIQ locally disabled.
  */
 void gic_migrate_target(unsigned int new_cpu_id)
 {
@@ -836,6 +913,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 	ror_val = (cur_cpu_id - new_cpu_id) & 31;
 
 	raw_spin_lock(&irq_controller_lock);
+	raw_spin_lock(&fiq_safe_migration_lock);
 
 	/* Update the target interface for this logical CPU */
 	gic_cpu_map[cpu] = 1 << new_cpu_id;
@@ -855,6 +933,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 		}
 	}
 
+	raw_spin_unlock(&fiq_safe_migration_lock);
 	raw_spin_unlock(&irq_controller_lock);
 
 	/*
@@ -1125,6 +1204,10 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 #ifdef CONFIG_SMP
 		set_smp_cross_call(gic_raise_softirq);
 		register_cpu_notifier(&gic_cpu_notifier);
+#ifdef CONFIG_FIQ
+		if (gic_data_fiq_enable(gic))
+			register_fiq_nmi_notifier(&gic_fiq_ipi_notifier);
+#endif
 #endif
 		set_handle_irq(gic_handle_irq);
 	}
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 10/19] irqchip: gic: Group 0 workaround.
  2014-09-02 13:00                   ` Daniel Thompson
@ 2014-09-02 13:00                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Thomas Gleixner, Jason Cooper

An ARM system based on GICv1 that runs by default in secure mode and
uses both group 0 and group 1 interrupts (in order to exploit FIQ)
will suffer a problem where the IRQ handler occasionally spuriously
acknowledges a group 0 (FIQ) interrupt.

This can be prevented by ensuring the IRQ handler makes non-secure
memory access to the GIC registers but this is complex because
the non-secure bits cannot be apply to 4k pages (the bit is one level
up in the page table and applies to 1MB at a time).

This workaround uses an alternative approach that spots the spurious
acknowledgment and regenerates the FIQ. This keeps the workaround
exclusively within the GIC driver (although there is a runtime
perforamnce penalty resulting from this approach).

Reported-by: Harro Haan <hrhaan@gmail.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Tested-by: Harro Haan <hrhaan@gmail.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
---
 drivers/irqchip/irq-gic.c | 52 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 49 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 8834749..bda5a91 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -279,14 +279,59 @@ static int gic_set_wake(struct irq_data *d, unsigned int on)
 #define gic_set_wake	NULL
 #endif
 
+#ifdef CONFIG_FIQ
+/* This is a software emulation of the Aliased Interrupt Acknowledge Register
+ * (GIC_AIAR) found in GICv2+.
+ */
+static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32 irqstat)
+{
+	u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	void __iomem *dist_base = gic_data_dist_base(gic);
+	u32 offset, mask;
+
+	if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
+		return irqstat;
+
+	offset = irqnr / 32 * 4;
+	mask = 1 << (irqnr % 32);
+	if (readl_relaxed(dist_base + GIC_DIST_IGROUP + offset) & mask)
+		return irqstat;
+
+	/* this interrupt must be taken as a FIQ so put it back into the
+	 * pending state and end our own servicing of it.
+	 */
+	writel_relaxed(mask, dist_base + GIC_DIST_PENDING_SET + offset);
+	readl_relaxed(dist_base + GIC_DIST_PENDING_SET + offset);
+	writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
+
+	return 1023;
+}
+
+static u32 gic_ack_irq(struct gic_chip_data *gic)
+{
+	u32 irqstat;
+
+	local_fiq_disable();
+	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+	irqstat = gic_handle_spurious_group_0(gic, irqstat);
+	local_fiq_enable();
+
+	return irqstat;
+}
+#else
+static u32 gic_ack_irq(struct gic_chip_data *gic)
+{
+	return readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+}
+#endif
+
 static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
 	u32 irqstat, irqnr;
 	struct gic_chip_data *gic = &gic_data[0];
-	void __iomem *cpu_base = gic_data_cpu_base(gic);
 
 	do {
-		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		irqstat = gic_ack_irq(gic);
 		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
 
 		if (likely(irqnr > 15 && irqnr < 1021)) {
@@ -295,7 +340,8 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 			continue;
 		}
 		if (irqnr < 16) {
-			writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+			writel_relaxed(irqstat,
+				       gic_data_cpu_base(gic) + GIC_CPU_EOI);
 #ifdef CONFIG_SMP
 			handle_IPI(irqnr, regs);
 #endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 10/19] irqchip: gic: Group 0 workaround.
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

An ARM system based on GICv1 that runs by default in secure mode and
uses both group 0 and group 1 interrupts (in order to exploit FIQ)
will suffer a problem where the IRQ handler occasionally spuriously
acknowledges a group 0 (FIQ) interrupt.

This can be prevented by ensuring the IRQ handler makes non-secure
memory access to the GIC registers but this is complex because
the non-secure bits cannot be apply to 4k pages (the bit is one level
up in the page table and applies to 1MB at a time).

This workaround uses an alternative approach that spots the spurious
acknowledgment and regenerates the FIQ. This keeps the workaround
exclusively within the GIC driver (although there is a runtime
perforamnce penalty resulting from this approach).

Reported-by: Harro Haan <hrhaan@gmail.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Tested-by: Harro Haan <hrhaan@gmail.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
---
 drivers/irqchip/irq-gic.c | 52 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 49 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 8834749..bda5a91 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -279,14 +279,59 @@ static int gic_set_wake(struct irq_data *d, unsigned int on)
 #define gic_set_wake	NULL
 #endif
 
+#ifdef CONFIG_FIQ
+/* This is a software emulation of the Aliased Interrupt Acknowledge Register
+ * (GIC_AIAR) found in GICv2+.
+ */
+static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32 irqstat)
+{
+	u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	void __iomem *dist_base = gic_data_dist_base(gic);
+	u32 offset, mask;
+
+	if (!gic_data_fiq_enable(gic) || irqnr >= 1021)
+		return irqstat;
+
+	offset = irqnr / 32 * 4;
+	mask = 1 << (irqnr % 32);
+	if (readl_relaxed(dist_base + GIC_DIST_IGROUP + offset) & mask)
+		return irqstat;
+
+	/* this interrupt must be taken as a FIQ so put it back into the
+	 * pending state and end our own servicing of it.
+	 */
+	writel_relaxed(mask, dist_base + GIC_DIST_PENDING_SET + offset);
+	readl_relaxed(dist_base + GIC_DIST_PENDING_SET + offset);
+	writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
+
+	return 1023;
+}
+
+static u32 gic_ack_irq(struct gic_chip_data *gic)
+{
+	u32 irqstat;
+
+	local_fiq_disable();
+	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+	irqstat = gic_handle_spurious_group_0(gic, irqstat);
+	local_fiq_enable();
+
+	return irqstat;
+}
+#else
+static u32 gic_ack_irq(struct gic_chip_data *gic)
+{
+	return readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+}
+#endif
+
 static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
 	u32 irqstat, irqnr;
 	struct gic_chip_data *gic = &gic_data[0];
-	void __iomem *cpu_base = gic_data_cpu_base(gic);
 
 	do {
-		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		irqstat = gic_ack_irq(gic);
 		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
 
 		if (likely(irqnr > 15 && irqnr < 1021)) {
@@ -295,7 +340,8 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 			continue;
 		}
 		if (irqnr < 16) {
-			writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+			writel_relaxed(irqstat,
+				       gic_data_cpu_base(gic) + GIC_CPU_EOI);
 #ifdef CONFIG_SMP
 			handle_IPI(irqnr, regs);
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 11/19] irqchip: vic: Add support for FIQ management
  2014-09-02 13:00                   ` Daniel Thompson
  (?)
@ 2014-09-02 13:00                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Hartley Sweeten, Ryan Mallon, Ben Dooks,
	Kukjin Kim, Thomas Gleixner, Jason Cooper, linux-samsung-soc

This patch introduces callbacks to route interrupts to or away
from the FIQ signal. It also causes these callbacks to be registered
with the FIQ infrastructure.

This patch enable FIQ support for mach-versatile whilst mach-ep93xx,
mach-netx, mach-s3c64xx and plat-samsung are unmodified (and can therefore
continue to use init_FIQ() as before).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: linux-samsung-soc@vger.kernel.org
---
 arch/arm/mach-versatile/core.c  |  2 +-
 drivers/irqchip/irq-gic.c       | 21 ++++------
 drivers/irqchip/irq-vic.c       | 92 ++++++++++++++++++++++++++++++++---------
 include/linux/irqchip/arm-gic.h |  3 ++
 include/linux/irqchip/arm-vic.h |  6 ++-
 5 files changed, 88 insertions(+), 36 deletions(-)

diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 08fb8c8..bad1d30 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -108,7 +108,7 @@ void __init versatile_init_irq(void)
 
 	np = of_find_matching_node_by_address(NULL, vic_of_match,
 					      VERSATILE_VIC_BASE);
-	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np);
+	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np ? false : true, np);
 
 	writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
 
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index bda5a91..8821160 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -502,13 +502,17 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 /*
  * Fully acknowledge (both ack and eoi) a FIQ-based IPI
  */
-static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
-			   void *data)
+void gic_handle_fiq_ipi(void)
 {
 	struct gic_chip_data *gic = &gic_data[0];
-	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	void __iomem *cpu_base;
 	unsigned long irqstat, irqnr;
 
+	if (!gic || !gic->fiq_enable)
+		return;
+
+	cpu_base = gic_data_cpu_base(gic);
+
 	if (WARN_ON(!in_nmi()))
 		return NOTIFY_BAD;
 
@@ -525,13 +529,6 @@ static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
 
 	return NOTIFY_OK;
 }
-
-/*
- * Notifier to ensure IPI FIQ is acknowledged correctly.
- */
-static struct notifier_block gic_fiq_ipi_notifier = {
-	.notifier_call = gic_handle_fiq_ipi,
-};
 #else /* CONFIG_FIQ */
 static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
 				     int group) {}
@@ -1250,10 +1247,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 #ifdef CONFIG_SMP
 		set_smp_cross_call(gic_raise_softirq);
 		register_cpu_notifier(&gic_cpu_notifier);
-#ifdef CONFIG_FIQ
-		if (gic_data_fiq_enable(gic))
-			register_fiq_nmi_notifier(&gic_fiq_ipi_notifier);
-#endif
 #endif
 		set_handle_irq(gic_handle_irq);
 	}
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287..22aa126 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -36,6 +36,9 @@
 
 #include <asm/exception.h>
 #include <asm/irq.h>
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 
 #include "irqchip.h"
 
@@ -261,11 +264,53 @@ static struct irq_domain_ops vic_irqdomain_ops = {
 	.xlate = irq_domain_xlate_onetwocell,
 };
 
+#ifdef CONFIG_FIQ
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
+static void vic_set_fiq(struct irq_data *d, bool enable)
+{
+	void __iomem *base = irq_data_get_irq_chip_data(d);
+	unsigned int irq = d->hwirq;
+	u32 val;
+
+	raw_spin_lock(&irq_controller_lock);
+	val = readl(base + VIC_INT_SELECT);
+	if (enable)
+		val |= 1 << irq;
+	else
+		val &= ~(1 << irq);
+	writel(val, base + VIC_INT_SELECT);
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void vic_enable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, true);
+}
+
+static void vic_disable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, false);
+}
+
+struct fiq_chip vic_fiq = {
+	.fiq_enable = vic_enable_fiq,
+	.fiq_disable = vic_disable_fiq,
+};
+
+static void vic_register_fiq(int irq)
+{
+	fiq_register_mapping(irq, &vic_fiq);
+}
+#else /* CONFIG_FIQ */
+static inline void vic_register_fiq(int irq) {}
+#endif /* CONFIG_FIQ */
+
 /**
  * vic_register() - Register a VIC.
  * @base: The base address of the VIC.
  * @parent_irq: The parent IRQ if cascaded, else 0.
- * @irq: The base IRQ for the VIC.
+ * @irq_start: The base IRQ for the VIC.
  * @valid_sources: bitmask of valid interrupts
  * @resume_sources: bitmask of interrupts allowed for resume sources.
  * @node: The device tree node associated with the VIC.
@@ -277,12 +322,13 @@ static struct irq_domain_ops vic_irqdomain_ops = {
  * This also configures the IRQ domain for the VIC.
  */
 static void __init vic_register(void __iomem *base, unsigned int parent_irq,
-				unsigned int irq,
+				unsigned int irq_start,
 				u32 valid_sources, u32 resume_sources,
-				struct device_node *node)
+				bool map_fiqs, struct device_node *node)
 {
 	struct vic_device *v;
 	int i;
+	unsigned int irq;
 
 	if (vic_id >= ARRAY_SIZE(vic_devices)) {
 		printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
@@ -301,15 +347,19 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 		irq_set_chained_handler(parent_irq, vic_handle_irq_cascaded);
 	}
 
-	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq,
+	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq_start,
 					  &vic_irqdomain_ops, v);
 	/* create an IRQ mapping for each valid IRQ */
-	for (i = 0; i < fls(valid_sources); i++)
-		if (valid_sources & (1 << i))
-			irq_create_mapping(v->domain, i);
+	for (i = 0; i < fls(valid_sources); i++) {
+		if (valid_sources & (1 << i)) {
+			irq = irq_create_mapping(v->domain, i);
+			vic_register_fiq(irq);
+		}
+	}
+
 	/* If no base IRQ was passed, figure out our allocated base */
-	if (irq)
-		v->irq = irq;
+	if (irq_start)
+		v->irq = irq_start;
 	else
 		v->irq = irq_find_mapping(v->domain, 0);
 }
@@ -413,7 +463,8 @@ static void __init vic_clear_interrupts(void __iomem *base)
  *  and 020 within the page. We call this "second block".
  */
 static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
-			       u32 vic_sources, struct device_node *node)
+			       u32 vic_sources, bool map_fiqs,
+			       struct device_node *node)
 {
 	unsigned int i;
 	int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
@@ -439,12 +490,12 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
 		writel(32, base + VIC_PL190_DEF_VECT_ADDR);
 	}
 
-	vic_register(base, 0, irq_start, vic_sources, 0, node);
+	vic_register(base, 0, irq_start, vic_sources, 0, map_fiqs, node);
 }
 
 void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
-			      u32 vic_sources, u32 resume_sources,
-			      struct device_node *node)
+		       u32 vic_sources, u32 resume_sources,
+		       bool map_fiqs, struct device_node *node)
 {
 	unsigned int i;
 	u32 cellid = 0;
@@ -462,7 +513,7 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	switch(vendor) {
 	case AMBA_VENDOR_ST:
-		vic_init_st(base, irq_start, vic_sources, node);
+		vic_init_st(base, irq_start, vic_sources, map_fiqs, node);
 		return;
 	default:
 		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
@@ -479,7 +530,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	vic_init2(base);
 
-	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);
+	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources,
+		     map_fiqs, node);
 }
 
 /**
@@ -492,7 +544,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 void __init vic_init(void __iomem *base, unsigned int irq_start,
 		     u32 vic_sources, u32 resume_sources)
 {
-	__vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL);
+	__vic_init(base, 0, irq_start, vic_sources, resume_sources,
+		   false, NULL);
 }
 
 /**
@@ -511,7 +564,8 @@ int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 	struct vic_device *v;
 
 	v = &vic_devices[vic_id];
-	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL);
+	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, false,
+		   NULL);
 	/* Return out acquired base */
 	return v->irq;
 }
@@ -535,9 +589,9 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
 	of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask);
 
 	/*
-	 * Passing 0 as first IRQ makes the simple domain allocate descriptors
+	 * Passing 0 as first IRQ makes the domain allocate descriptors.
 	 */
-	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
+	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, true, node);
 
 	return 0;
 }
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 45e2d8c..52a5676 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops
 {
 	gic_routable_irq_domain_ops = ops;
 }
+
+void gic_handle_fiq_ipi(void);
+
 #endif /* __ASSEMBLY */
 #endif
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index ba46c79..30ab39f 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -30,8 +30,10 @@ struct device_node;
 struct pt_regs;
 
 void __vic_init(void __iomem *base, int parent_irq, int irq_start,
-		u32 vic_sources, u32 resume_sources, struct device_node *node);
-void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
+		u32 vic_sources, u32 resume_sources,
+		bool map_fiqs, struct device_node *node);
+void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources,
+	      u32 resume_sources);
 int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 		      u32 vic_sources, u32 resume_sources);
 
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 11/19] irqchip: vic: Add support for FIQ management
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Hartley Sweeten, Ryan Mallon, Ben Dooks,
	Kukjin Kim, Thomas Gleixner, Jason Cooper

This patch introduces callbacks to route interrupts to or away
from the FIQ signal. It also causes these callbacks to be registered
with the FIQ infrastructure.

This patch enable FIQ support for mach-versatile whilst mach-ep93xx,
mach-netx, mach-s3c64xx and plat-samsung are unmodified (and can therefore
continue to use init_FIQ() as before).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: linux-samsung-soc@vger.kernel.org
---
 arch/arm/mach-versatile/core.c  |  2 +-
 drivers/irqchip/irq-gic.c       | 21 ++++------
 drivers/irqchip/irq-vic.c       | 92 ++++++++++++++++++++++++++++++++---------
 include/linux/irqchip/arm-gic.h |  3 ++
 include/linux/irqchip/arm-vic.h |  6 ++-
 5 files changed, 88 insertions(+), 36 deletions(-)

diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 08fb8c8..bad1d30 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -108,7 +108,7 @@ void __init versatile_init_irq(void)
 
 	np = of_find_matching_node_by_address(NULL, vic_of_match,
 					      VERSATILE_VIC_BASE);
-	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np);
+	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np ? false : true, np);
 
 	writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
 
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index bda5a91..8821160 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -502,13 +502,17 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 /*
  * Fully acknowledge (both ack and eoi) a FIQ-based IPI
  */
-static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
-			   void *data)
+void gic_handle_fiq_ipi(void)
 {
 	struct gic_chip_data *gic = &gic_data[0];
-	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	void __iomem *cpu_base;
 	unsigned long irqstat, irqnr;
 
+	if (!gic || !gic->fiq_enable)
+		return;
+
+	cpu_base = gic_data_cpu_base(gic);
+
 	if (WARN_ON(!in_nmi()))
 		return NOTIFY_BAD;
 
@@ -525,13 +529,6 @@ static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
 
 	return NOTIFY_OK;
 }
-
-/*
- * Notifier to ensure IPI FIQ is acknowledged correctly.
- */
-static struct notifier_block gic_fiq_ipi_notifier = {
-	.notifier_call = gic_handle_fiq_ipi,
-};
 #else /* CONFIG_FIQ */
 static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
 				     int group) {}
@@ -1250,10 +1247,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 #ifdef CONFIG_SMP
 		set_smp_cross_call(gic_raise_softirq);
 		register_cpu_notifier(&gic_cpu_notifier);
-#ifdef CONFIG_FIQ
-		if (gic_data_fiq_enable(gic))
-			register_fiq_nmi_notifier(&gic_fiq_ipi_notifier);
-#endif
 #endif
 		set_handle_irq(gic_handle_irq);
 	}
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287..22aa126 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -36,6 +36,9 @@
 
 #include <asm/exception.h>
 #include <asm/irq.h>
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 
 #include "irqchip.h"
 
@@ -261,11 +264,53 @@ static struct irq_domain_ops vic_irqdomain_ops = {
 	.xlate = irq_domain_xlate_onetwocell,
 };
 
+#ifdef CONFIG_FIQ
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
+static void vic_set_fiq(struct irq_data *d, bool enable)
+{
+	void __iomem *base = irq_data_get_irq_chip_data(d);
+	unsigned int irq = d->hwirq;
+	u32 val;
+
+	raw_spin_lock(&irq_controller_lock);
+	val = readl(base + VIC_INT_SELECT);
+	if (enable)
+		val |= 1 << irq;
+	else
+		val &= ~(1 << irq);
+	writel(val, base + VIC_INT_SELECT);
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void vic_enable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, true);
+}
+
+static void vic_disable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, false);
+}
+
+struct fiq_chip vic_fiq = {
+	.fiq_enable = vic_enable_fiq,
+	.fiq_disable = vic_disable_fiq,
+};
+
+static void vic_register_fiq(int irq)
+{
+	fiq_register_mapping(irq, &vic_fiq);
+}
+#else /* CONFIG_FIQ */
+static inline void vic_register_fiq(int irq) {}
+#endif /* CONFIG_FIQ */
+
 /**
  * vic_register() - Register a VIC.
  * @base: The base address of the VIC.
  * @parent_irq: The parent IRQ if cascaded, else 0.
- * @irq: The base IRQ for the VIC.
+ * @irq_start: The base IRQ for the VIC.
  * @valid_sources: bitmask of valid interrupts
  * @resume_sources: bitmask of interrupts allowed for resume sources.
  * @node: The device tree node associated with the VIC.
@@ -277,12 +322,13 @@ static struct irq_domain_ops vic_irqdomain_ops = {
  * This also configures the IRQ domain for the VIC.
  */
 static void __init vic_register(void __iomem *base, unsigned int parent_irq,
-				unsigned int irq,
+				unsigned int irq_start,
 				u32 valid_sources, u32 resume_sources,
-				struct device_node *node)
+				bool map_fiqs, struct device_node *node)
 {
 	struct vic_device *v;
 	int i;
+	unsigned int irq;
 
 	if (vic_id >= ARRAY_SIZE(vic_devices)) {
 		printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
@@ -301,15 +347,19 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 		irq_set_chained_handler(parent_irq, vic_handle_irq_cascaded);
 	}
 
-	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq,
+	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq_start,
 					  &vic_irqdomain_ops, v);
 	/* create an IRQ mapping for each valid IRQ */
-	for (i = 0; i < fls(valid_sources); i++)
-		if (valid_sources & (1 << i))
-			irq_create_mapping(v->domain, i);
+	for (i = 0; i < fls(valid_sources); i++) {
+		if (valid_sources & (1 << i)) {
+			irq = irq_create_mapping(v->domain, i);
+			vic_register_fiq(irq);
+		}
+	}
+
 	/* If no base IRQ was passed, figure out our allocated base */
-	if (irq)
-		v->irq = irq;
+	if (irq_start)
+		v->irq = irq_start;
 	else
 		v->irq = irq_find_mapping(v->domain, 0);
 }
@@ -413,7 +463,8 @@ static void __init vic_clear_interrupts(void __iomem *base)
  *  and 020 within the page. We call this "second block".
  */
 static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
-			       u32 vic_sources, struct device_node *node)
+			       u32 vic_sources, bool map_fiqs,
+			       struct device_node *node)
 {
 	unsigned int i;
 	int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
@@ -439,12 +490,12 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
 		writel(32, base + VIC_PL190_DEF_VECT_ADDR);
 	}
 
-	vic_register(base, 0, irq_start, vic_sources, 0, node);
+	vic_register(base, 0, irq_start, vic_sources, 0, map_fiqs, node);
 }
 
 void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
-			      u32 vic_sources, u32 resume_sources,
-			      struct device_node *node)
+		       u32 vic_sources, u32 resume_sources,
+		       bool map_fiqs, struct device_node *node)
 {
 	unsigned int i;
 	u32 cellid = 0;
@@ -462,7 +513,7 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	switch(vendor) {
 	case AMBA_VENDOR_ST:
-		vic_init_st(base, irq_start, vic_sources, node);
+		vic_init_st(base, irq_start, vic_sources, map_fiqs, node);
 		return;
 	default:
 		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
@@ -479,7 +530,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	vic_init2(base);
 
-	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);
+	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources,
+		     map_fiqs, node);
 }
 
 /**
@@ -492,7 +544,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 void __init vic_init(void __iomem *base, unsigned int irq_start,
 		     u32 vic_sources, u32 resume_sources)
 {
-	__vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL);
+	__vic_init(base, 0, irq_start, vic_sources, resume_sources,
+		   false, NULL);
 }
 
 /**
@@ -511,7 +564,8 @@ int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 	struct vic_device *v;
 
 	v = &vic_devices[vic_id];
-	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL);
+	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, false,
+		   NULL);
 	/* Return out acquired base */
 	return v->irq;
 }
@@ -535,9 +589,9 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
 	of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask);
 
 	/*
-	 * Passing 0 as first IRQ makes the simple domain allocate descriptors
+	 * Passing 0 as first IRQ makes the domain allocate descriptors.
 	 */
-	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
+	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, true, node);
 
 	return 0;
 }
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 45e2d8c..52a5676 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops
 {
 	gic_routable_irq_domain_ops = ops;
 }
+
+void gic_handle_fiq_ipi(void);
+
 #endif /* __ASSEMBLY */
 #endif
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index ba46c79..30ab39f 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -30,8 +30,10 @@ struct device_node;
 struct pt_regs;
 
 void __vic_init(void __iomem *base, int parent_irq, int irq_start,
-		u32 vic_sources, u32 resume_sources, struct device_node *node);
-void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
+		u32 vic_sources, u32 resume_sources,
+		bool map_fiqs, struct device_node *node);
+void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources,
+	      u32 resume_sources);
 int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 		      u32 vic_sources, u32 resume_sources);
 
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 11/19] irqchip: vic: Add support for FIQ management
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

This patch introduces callbacks to route interrupts to or away
from the FIQ signal. It also causes these callbacks to be registered
with the FIQ infrastructure.

This patch enable FIQ support for mach-versatile whilst mach-ep93xx,
mach-netx, mach-s3c64xx and plat-samsung are unmodified (and can therefore
continue to use init_FIQ() as before).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: linux-samsung-soc at vger.kernel.org
---
 arch/arm/mach-versatile/core.c  |  2 +-
 drivers/irqchip/irq-gic.c       | 21 ++++------
 drivers/irqchip/irq-vic.c       | 92 ++++++++++++++++++++++++++++++++---------
 include/linux/irqchip/arm-gic.h |  3 ++
 include/linux/irqchip/arm-vic.h |  6 ++-
 5 files changed, 88 insertions(+), 36 deletions(-)

diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 08fb8c8..bad1d30 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -108,7 +108,7 @@ void __init versatile_init_irq(void)
 
 	np = of_find_matching_node_by_address(NULL, vic_of_match,
 					      VERSATILE_VIC_BASE);
-	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np);
+	__vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np ? false : true, np);
 
 	writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
 
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index bda5a91..8821160 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -502,13 +502,17 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
 /*
  * Fully acknowledge (both ack and eoi) a FIQ-based IPI
  */
-static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
-			   void *data)
+void gic_handle_fiq_ipi(void)
 {
 	struct gic_chip_data *gic = &gic_data[0];
-	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	void __iomem *cpu_base;
 	unsigned long irqstat, irqnr;
 
+	if (!gic || !gic->fiq_enable)
+		return;
+
+	cpu_base = gic_data_cpu_base(gic);
+
 	if (WARN_ON(!in_nmi()))
 		return NOTIFY_BAD;
 
@@ -525,13 +529,6 @@ static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
 
 	return NOTIFY_OK;
 }
-
-/*
- * Notifier to ensure IPI FIQ is acknowledged correctly.
- */
-static struct notifier_block gic_fiq_ipi_notifier = {
-	.notifier_call = gic_handle_fiq_ipi,
-};
 #else /* CONFIG_FIQ */
 static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
 				     int group) {}
@@ -1250,10 +1247,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 #ifdef CONFIG_SMP
 		set_smp_cross_call(gic_raise_softirq);
 		register_cpu_notifier(&gic_cpu_notifier);
-#ifdef CONFIG_FIQ
-		if (gic_data_fiq_enable(gic))
-			register_fiq_nmi_notifier(&gic_fiq_ipi_notifier);
-#endif
 #endif
 		set_handle_irq(gic_handle_irq);
 	}
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287..22aa126 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -36,6 +36,9 @@
 
 #include <asm/exception.h>
 #include <asm/irq.h>
+#ifdef CONFIG_FIQ
+#include <asm/fiq.h>
+#endif
 
 #include "irqchip.h"
 
@@ -261,11 +264,53 @@ static struct irq_domain_ops vic_irqdomain_ops = {
 	.xlate = irq_domain_xlate_onetwocell,
 };
 
+#ifdef CONFIG_FIQ
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
+static void vic_set_fiq(struct irq_data *d, bool enable)
+{
+	void __iomem *base = irq_data_get_irq_chip_data(d);
+	unsigned int irq = d->hwirq;
+	u32 val;
+
+	raw_spin_lock(&irq_controller_lock);
+	val = readl(base + VIC_INT_SELECT);
+	if (enable)
+		val |= 1 << irq;
+	else
+		val &= ~(1 << irq);
+	writel(val, base + VIC_INT_SELECT);
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+static void vic_enable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, true);
+}
+
+static void vic_disable_fiq(struct irq_data *d)
+{
+	vic_set_fiq(d, false);
+}
+
+struct fiq_chip vic_fiq = {
+	.fiq_enable = vic_enable_fiq,
+	.fiq_disable = vic_disable_fiq,
+};
+
+static void vic_register_fiq(int irq)
+{
+	fiq_register_mapping(irq, &vic_fiq);
+}
+#else /* CONFIG_FIQ */
+static inline void vic_register_fiq(int irq) {}
+#endif /* CONFIG_FIQ */
+
 /**
  * vic_register() - Register a VIC.
  * @base: The base address of the VIC.
  * @parent_irq: The parent IRQ if cascaded, else 0.
- * @irq: The base IRQ for the VIC.
+ * @irq_start: The base IRQ for the VIC.
  * @valid_sources: bitmask of valid interrupts
  * @resume_sources: bitmask of interrupts allowed for resume sources.
  * @node: The device tree node associated with the VIC.
@@ -277,12 +322,13 @@ static struct irq_domain_ops vic_irqdomain_ops = {
  * This also configures the IRQ domain for the VIC.
  */
 static void __init vic_register(void __iomem *base, unsigned int parent_irq,
-				unsigned int irq,
+				unsigned int irq_start,
 				u32 valid_sources, u32 resume_sources,
-				struct device_node *node)
+				bool map_fiqs, struct device_node *node)
 {
 	struct vic_device *v;
 	int i;
+	unsigned int irq;
 
 	if (vic_id >= ARRAY_SIZE(vic_devices)) {
 		printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
@@ -301,15 +347,19 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 		irq_set_chained_handler(parent_irq, vic_handle_irq_cascaded);
 	}
 
-	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq,
+	v->domain = irq_domain_add_simple(node, fls(valid_sources), irq_start,
 					  &vic_irqdomain_ops, v);
 	/* create an IRQ mapping for each valid IRQ */
-	for (i = 0; i < fls(valid_sources); i++)
-		if (valid_sources & (1 << i))
-			irq_create_mapping(v->domain, i);
+	for (i = 0; i < fls(valid_sources); i++) {
+		if (valid_sources & (1 << i)) {
+			irq = irq_create_mapping(v->domain, i);
+			vic_register_fiq(irq);
+		}
+	}
+
 	/* If no base IRQ was passed, figure out our allocated base */
-	if (irq)
-		v->irq = irq;
+	if (irq_start)
+		v->irq = irq_start;
 	else
 		v->irq = irq_find_mapping(v->domain, 0);
 }
@@ -413,7 +463,8 @@ static void __init vic_clear_interrupts(void __iomem *base)
  *  and 020 within the page. We call this "second block".
  */
 static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
-			       u32 vic_sources, struct device_node *node)
+			       u32 vic_sources, bool map_fiqs,
+			       struct device_node *node)
 {
 	unsigned int i;
 	int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
@@ -439,12 +490,12 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
 		writel(32, base + VIC_PL190_DEF_VECT_ADDR);
 	}
 
-	vic_register(base, 0, irq_start, vic_sources, 0, node);
+	vic_register(base, 0, irq_start, vic_sources, 0, map_fiqs, node);
 }
 
 void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
-			      u32 vic_sources, u32 resume_sources,
-			      struct device_node *node)
+		       u32 vic_sources, u32 resume_sources,
+		       bool map_fiqs, struct device_node *node)
 {
 	unsigned int i;
 	u32 cellid = 0;
@@ -462,7 +513,7 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	switch(vendor) {
 	case AMBA_VENDOR_ST:
-		vic_init_st(base, irq_start, vic_sources, node);
+		vic_init_st(base, irq_start, vic_sources, map_fiqs, node);
 		return;
 	default:
 		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
@@ -479,7 +530,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 
 	vic_init2(base);
 
-	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);
+	vic_register(base, parent_irq, irq_start, vic_sources, resume_sources,
+		     map_fiqs, node);
 }
 
 /**
@@ -492,7 +544,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 void __init vic_init(void __iomem *base, unsigned int irq_start,
 		     u32 vic_sources, u32 resume_sources)
 {
-	__vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL);
+	__vic_init(base, 0, irq_start, vic_sources, resume_sources,
+		   false, NULL);
 }
 
 /**
@@ -511,7 +564,8 @@ int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 	struct vic_device *v;
 
 	v = &vic_devices[vic_id];
-	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL);
+	__vic_init(base, parent_irq, 0, vic_sources, resume_sources, false,
+		   NULL);
 	/* Return out acquired base */
 	return v->irq;
 }
@@ -535,9 +589,9 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
 	of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask);
 
 	/*
-	 * Passing 0 as first IRQ makes the simple domain allocate descriptors
+	 * Passing 0 as first IRQ makes the domain allocate descriptors.
 	 */
-	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
+	__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, true, node);
 
 	return 0;
 }
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 45e2d8c..52a5676 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops
 {
 	gic_routable_irq_domain_ops = ops;
 }
+
+void gic_handle_fiq_ipi(void);
+
 #endif /* __ASSEMBLY */
 #endif
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index ba46c79..30ab39f 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -30,8 +30,10 @@ struct device_node;
 struct pt_regs;
 
 void __vic_init(void __iomem *base, int parent_irq, int irq_start,
-		u32 vic_sources, u32 resume_sources, struct device_node *node);
-void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
+		u32 vic_sources, u32 resume_sources,
+		bool map_fiqs, struct device_node *node);
+void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources,
+	      u32 resume_sources);
 int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 		      u32 vic_sources, u32 resume_sources);
 
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 12/19] serial: kgdb_nmi: No CON_ENABLED by default
  2014-09-02 13:00                   ` Daniel Thompson
@ 2014-09-02 13:00                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

At present this console is selectively enabled/disabled by NULL checking
arch_kgdb_ops.enable_nmi. In practice this requires the architecture
dependant code to implement some kind of control (e.g. module arguments)
to enable/disable the feature.

The kernel already provide the perfectly adequade console= argument to
do this. Let's us that instead, if nothing else, it makes any
documentation architecture neutral.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/tty/serial/kgdb_nmi.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c
index 6ec7501..129dc5b 100644
--- a/drivers/tty/serial/kgdb_nmi.c
+++ b/drivers/tty/serial/kgdb_nmi.c
@@ -46,6 +46,8 @@ static atomic_t kgdb_nmi_num_readers = ATOMIC_INIT(0);
 
 static int kgdb_nmi_console_setup(struct console *co, char *options)
 {
+	arch_kgdb_ops.enable_nmi(1);
+
 	/* The NMI console uses the dbg_io_ops to issue console messages. To
 	 * avoid duplicate messages during kdb sessions we must inform kdb's
 	 * I/O utilities that messages sent to the console will automatically
@@ -77,7 +79,7 @@ static struct console kgdb_nmi_console = {
 	.setup  = kgdb_nmi_console_setup,
 	.write	= kgdb_nmi_console_write,
 	.device	= kgdb_nmi_console_device,
-	.flags	= CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED,
+	.flags	= CON_PRINTBUFFER | CON_ANYTIME,
 	.index	= -1,
 };
 
@@ -354,7 +356,6 @@ int kgdb_register_nmi_console(void)
 	}
 
 	register_console(&kgdb_nmi_console);
-	arch_kgdb_ops.enable_nmi(1);
 
 	return 0;
 err_drv_reg:
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 12/19] serial: kgdb_nmi: No CON_ENABLED by default
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

At present this console is selectively enabled/disabled by NULL checking
arch_kgdb_ops.enable_nmi. In practice this requires the architecture
dependant code to implement some kind of control (e.g. module arguments)
to enable/disable the feature.

The kernel already provide the perfectly adequade console= argument to
do this. Let's us that instead, if nothing else, it makes any
documentation architecture neutral.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/tty/serial/kgdb_nmi.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c
index 6ec7501..129dc5b 100644
--- a/drivers/tty/serial/kgdb_nmi.c
+++ b/drivers/tty/serial/kgdb_nmi.c
@@ -46,6 +46,8 @@ static atomic_t kgdb_nmi_num_readers = ATOMIC_INIT(0);
 
 static int kgdb_nmi_console_setup(struct console *co, char *options)
 {
+	arch_kgdb_ops.enable_nmi(1);
+
 	/* The NMI console uses the dbg_io_ops to issue console messages. To
 	 * avoid duplicate messages during kdb sessions we must inform kdb's
 	 * I/O utilities that messages sent to the console will automatically
@@ -77,7 +79,7 @@ static struct console kgdb_nmi_console = {
 	.setup  = kgdb_nmi_console_setup,
 	.write	= kgdb_nmi_console_write,
 	.device	= kgdb_nmi_console_device,
-	.flags	= CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED,
+	.flags	= CON_PRINTBUFFER | CON_ANYTIME,
 	.index	= -1,
 };
 
@@ -354,7 +356,6 @@ int kgdb_register_nmi_console(void)
 	}
 
 	register_console(&kgdb_nmi_console);
-	arch_kgdb_ops.enable_nmi(1);
 
 	return 0;
 err_drv_reg:
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 13/19] serial: amba-pl011: Use container_of() to get uart_amba_port
  2014-09-02 13:00                   ` Daniel Thompson
@ 2014-09-02 13:00                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

Universally adopt container_of() for all pointer conversion from
uart_port to uart_amba_port.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/tty/serial/amba-pl011.c | 54 +++++++++++++++++++++++++++--------------
 1 file changed, 36 insertions(+), 18 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 8572f2a..02016fc 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -678,7 +678,8 @@ static void pl011_dma_flush_buffer(struct uart_port *port)
 __releases(&uap->port.lock)
 __acquires(&uap->port.lock)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	if (!uap->using_tx_dma)
 		return;
@@ -1163,7 +1164,8 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
 
 static void pl011_stop_tx(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	uap->im &= ~UART011_TXIM;
 	writew(uap->im, uap->port.membase + UART011_IMSC);
@@ -1172,7 +1174,8 @@ static void pl011_stop_tx(struct uart_port *port)
 
 static void pl011_start_tx(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	if (!pl011_dma_tx_start(uap)) {
 		uap->im |= UART011_TXIM;
@@ -1182,7 +1185,8 @@ static void pl011_start_tx(struct uart_port *port)
 
 static void pl011_stop_rx(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
 		     UART011_PEIM|UART011_BEIM|UART011_OEIM);
@@ -1193,7 +1197,8 @@ static void pl011_stop_rx(struct uart_port *port)
 
 static void pl011_enable_ms(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM;
 	writew(uap->im, uap->port.membase + UART011_IMSC);
@@ -1349,14 +1354,16 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
 
 static unsigned int pl011_tx_empty(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int status = readw(uap->port.membase + UART01x_FR);
 	return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
 }
 
 static unsigned int pl011_get_mctrl(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int result = 0;
 	unsigned int status = readw(uap->port.membase + UART01x_FR);
 
@@ -1374,7 +1381,8 @@ static unsigned int pl011_get_mctrl(struct uart_port *port)
 
 static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int cr;
 
 	cr = readw(uap->port.membase + UART011_CR);
@@ -1402,7 +1410,8 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
 
 static void pl011_break_ctl(struct uart_port *port, int break_state)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned long flags;
 	unsigned int lcr_h;
 
@@ -1420,7 +1429,8 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
 
 static void pl011_quiesce_irqs(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned char __iomem *regs = uap->port.membase;
 
 	writew(readw(regs + UART011_MIS), regs + UART011_ICR);
@@ -1442,7 +1452,8 @@ static void pl011_quiesce_irqs(struct uart_port *port)
 
 static int pl011_get_poll_char(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int status;
 
 	/*
@@ -1461,7 +1472,8 @@ static int pl011_get_poll_char(struct uart_port *port)
 static void pl011_put_poll_char(struct uart_port *port,
 			 unsigned char ch)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
 		barrier();
@@ -1473,7 +1485,8 @@ static void pl011_put_poll_char(struct uart_port *port,
 
 static int pl011_hwinit(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	int retval;
 
 	/* Optionaly enable pins to be muxed in and configured */
@@ -1526,7 +1539,8 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
 
 static int pl011_startup(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int cr, lcr_h, fbrd, ibrd;
 	int retval;
 
@@ -1618,7 +1632,8 @@ static void pl011_shutdown_channel(struct uart_amba_port *uap,
 
 static void pl011_shutdown(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int cr;
 
 	/*
@@ -1680,7 +1695,8 @@ static void
 pl011_set_termios(struct uart_port *port, struct ktermios *termios,
 		     struct ktermios *old)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int lcr_h, old_cr;
 	unsigned long flags;
 	unsigned int baud, quot, clkdiv;
@@ -1822,7 +1838,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
 
 static const char *pl011_type(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	return uap->port.type == PORT_AMBA ? uap->type : NULL;
 }
 
@@ -1900,7 +1917,8 @@ static struct uart_amba_port *amba_ports[UART_NR];
 
 static void pl011_console_putchar(struct uart_port *port, int ch)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
 		barrier();
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 13/19] serial: amba-pl011: Use container_of() to get uart_amba_port
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

Universally adopt container_of() for all pointer conversion from
uart_port to uart_amba_port.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/tty/serial/amba-pl011.c | 54 +++++++++++++++++++++++++++--------------
 1 file changed, 36 insertions(+), 18 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 8572f2a..02016fc 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -678,7 +678,8 @@ static void pl011_dma_flush_buffer(struct uart_port *port)
 __releases(&uap->port.lock)
 __acquires(&uap->port.lock)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	if (!uap->using_tx_dma)
 		return;
@@ -1163,7 +1164,8 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
 
 static void pl011_stop_tx(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	uap->im &= ~UART011_TXIM;
 	writew(uap->im, uap->port.membase + UART011_IMSC);
@@ -1172,7 +1174,8 @@ static void pl011_stop_tx(struct uart_port *port)
 
 static void pl011_start_tx(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	if (!pl011_dma_tx_start(uap)) {
 		uap->im |= UART011_TXIM;
@@ -1182,7 +1185,8 @@ static void pl011_start_tx(struct uart_port *port)
 
 static void pl011_stop_rx(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
 		     UART011_PEIM|UART011_BEIM|UART011_OEIM);
@@ -1193,7 +1197,8 @@ static void pl011_stop_rx(struct uart_port *port)
 
 static void pl011_enable_ms(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM;
 	writew(uap->im, uap->port.membase + UART011_IMSC);
@@ -1349,14 +1354,16 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
 
 static unsigned int pl011_tx_empty(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int status = readw(uap->port.membase + UART01x_FR);
 	return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
 }
 
 static unsigned int pl011_get_mctrl(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int result = 0;
 	unsigned int status = readw(uap->port.membase + UART01x_FR);
 
@@ -1374,7 +1381,8 @@ static unsigned int pl011_get_mctrl(struct uart_port *port)
 
 static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int cr;
 
 	cr = readw(uap->port.membase + UART011_CR);
@@ -1402,7 +1410,8 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
 
 static void pl011_break_ctl(struct uart_port *port, int break_state)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned long flags;
 	unsigned int lcr_h;
 
@@ -1420,7 +1429,8 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
 
 static void pl011_quiesce_irqs(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned char __iomem *regs = uap->port.membase;
 
 	writew(readw(regs + UART011_MIS), regs + UART011_ICR);
@@ -1442,7 +1452,8 @@ static void pl011_quiesce_irqs(struct uart_port *port)
 
 static int pl011_get_poll_char(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int status;
 
 	/*
@@ -1461,7 +1472,8 @@ static int pl011_get_poll_char(struct uart_port *port)
 static void pl011_put_poll_char(struct uart_port *port,
 			 unsigned char ch)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
 		barrier();
@@ -1473,7 +1485,8 @@ static void pl011_put_poll_char(struct uart_port *port,
 
 static int pl011_hwinit(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	int retval;
 
 	/* Optionaly enable pins to be muxed in and configured */
@@ -1526,7 +1539,8 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
 
 static int pl011_startup(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int cr, lcr_h, fbrd, ibrd;
 	int retval;
 
@@ -1618,7 +1632,8 @@ static void pl011_shutdown_channel(struct uart_amba_port *uap,
 
 static void pl011_shutdown(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int cr;
 
 	/*
@@ -1680,7 +1695,8 @@ static void
 pl011_set_termios(struct uart_port *port, struct ktermios *termios,
 		     struct ktermios *old)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	unsigned int lcr_h, old_cr;
 	unsigned long flags;
 	unsigned int baud, quot, clkdiv;
@@ -1822,7 +1838,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
 
 static const char *pl011_type(struct uart_port *port)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 	return uap->port.type == PORT_AMBA ? uap->type : NULL;
 }
 
@@ -1900,7 +1917,8 @@ static struct uart_amba_port *amba_ports[UART_NR];
 
 static void pl011_console_putchar(struct uart_port *port, int ch)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
 
 	while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
 		barrier();
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 14/19] serial: amba-pl011: Move pl011_hwinit()
  2014-09-02 13:00                   ` Daniel Thompson
  (?)
@ 2014-09-02 13:00                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Greg Kroah-Hartman, Jiri Slaby, linux-serial

This patch hoists pl011_hwinit() further up within the driver. This
permits a later patch to introduce an extended .poll_init callback
that does more than pure hardware initialization.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 78 ++++++++++++++++++++---------------------
 1 file changed, 39 insertions(+), 39 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 02016fc..0b06dcf 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1425,6 +1425,45 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
 	spin_unlock_irqrestore(&uap->port.lock, flags);
 }
 
+static int pl011_hwinit(struct uart_port *port)
+{
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
+	int retval;
+
+	/* Optionaly enable pins to be muxed in and configured */
+	pinctrl_pm_select_default_state(port->dev);
+
+	/*
+	 * Try to enable the clock producer.
+	 */
+	retval = clk_prepare_enable(uap->clk);
+	if (retval)
+		return retval;
+
+	uap->port.uartclk = clk_get_rate(uap->clk);
+
+	/* Clear pending error and receive interrupts */
+	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
+	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
+
+	/*
+	 * Save interrupts enable mask, and enable RX interrupts in case if
+	 * the interrupt is used for NMI entry.
+	 */
+	uap->im = readw(uap->port.membase + UART011_IMSC);
+	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
+
+	if (dev_get_platdata(uap->port.dev)) {
+		struct amba_pl011_data *plat;
+
+		plat = dev_get_platdata(uap->port.dev);
+		if (plat->init)
+			plat->init();
+	}
+	return 0;
+}
+
 #ifdef CONFIG_CONSOLE_POLL
 
 static void pl011_quiesce_irqs(struct uart_port *port)
@@ -1483,45 +1522,6 @@ static void pl011_put_poll_char(struct uart_port *port,
 
 #endif /* CONFIG_CONSOLE_POLL */
 
-static int pl011_hwinit(struct uart_port *port)
-{
-	struct uart_amba_port *uap =
-	    container_of(port, struct uart_amba_port, port);
-	int retval;
-
-	/* Optionaly enable pins to be muxed in and configured */
-	pinctrl_pm_select_default_state(port->dev);
-
-	/*
-	 * Try to enable the clock producer.
-	 */
-	retval = clk_prepare_enable(uap->clk);
-	if (retval)
-		return retval;
-
-	uap->port.uartclk = clk_get_rate(uap->clk);
-
-	/* Clear pending error and receive interrupts */
-	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
-	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
-
-	/*
-	 * Save interrupts enable mask, and enable RX interrupts in case if
-	 * the interrupt is used for NMI entry.
-	 */
-	uap->im = readw(uap->port.membase + UART011_IMSC);
-	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
-
-	if (dev_get_platdata(uap->port.dev)) {
-		struct amba_pl011_data *plat;
-
-		plat = dev_get_platdata(uap->port.dev);
-		if (plat->init)
-			plat->init();
-	}
-	return 0;
-}
-
 static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
 {
 	writew(lcr_h, uap->port.membase + uap->lcrh_rx);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 14/19] serial: amba-pl011: Move pl011_hwinit()
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linaro-kernel, Catalin Marinas, linux-serial,
	patches, kgdb-bugreport, Linus Walleij, Nicolas Pitre,
	linux-kernel, Frederic Weisbecker, Anton Vorontsov,
	Greg Kroah-Hartman, Ben Dooks, John Stultz, Fabio Estevam,
	Colin Cross, Jiri Slaby, kernel-team, Dave Martin,
	linux-arm-kernel

This patch hoists pl011_hwinit() further up within the driver. This
permits a later patch to introduce an extended .poll_init callback
that does more than pure hardware initialization.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 78 ++++++++++++++++++++---------------------
 1 file changed, 39 insertions(+), 39 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 02016fc..0b06dcf 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1425,6 +1425,45 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
 	spin_unlock_irqrestore(&uap->port.lock, flags);
 }
 
+static int pl011_hwinit(struct uart_port *port)
+{
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
+	int retval;
+
+	/* Optionaly enable pins to be muxed in and configured */
+	pinctrl_pm_select_default_state(port->dev);
+
+	/*
+	 * Try to enable the clock producer.
+	 */
+	retval = clk_prepare_enable(uap->clk);
+	if (retval)
+		return retval;
+
+	uap->port.uartclk = clk_get_rate(uap->clk);
+
+	/* Clear pending error and receive interrupts */
+	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
+	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
+
+	/*
+	 * Save interrupts enable mask, and enable RX interrupts in case if
+	 * the interrupt is used for NMI entry.
+	 */
+	uap->im = readw(uap->port.membase + UART011_IMSC);
+	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
+
+	if (dev_get_platdata(uap->port.dev)) {
+		struct amba_pl011_data *plat;
+
+		plat = dev_get_platdata(uap->port.dev);
+		if (plat->init)
+			plat->init();
+	}
+	return 0;
+}
+
 #ifdef CONFIG_CONSOLE_POLL
 
 static void pl011_quiesce_irqs(struct uart_port *port)
@@ -1483,45 +1522,6 @@ static void pl011_put_poll_char(struct uart_port *port,
 
 #endif /* CONFIG_CONSOLE_POLL */
 
-static int pl011_hwinit(struct uart_port *port)
-{
-	struct uart_amba_port *uap =
-	    container_of(port, struct uart_amba_port, port);
-	int retval;
-
-	/* Optionaly enable pins to be muxed in and configured */
-	pinctrl_pm_select_default_state(port->dev);
-
-	/*
-	 * Try to enable the clock producer.
-	 */
-	retval = clk_prepare_enable(uap->clk);
-	if (retval)
-		return retval;
-
-	uap->port.uartclk = clk_get_rate(uap->clk);
-
-	/* Clear pending error and receive interrupts */
-	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
-	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
-
-	/*
-	 * Save interrupts enable mask, and enable RX interrupts in case if
-	 * the interrupt is used for NMI entry.
-	 */
-	uap->im = readw(uap->port.membase + UART011_IMSC);
-	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
-
-	if (dev_get_platdata(uap->port.dev)) {
-		struct amba_pl011_data *plat;
-
-		plat = dev_get_platdata(uap->port.dev);
-		if (plat->init)
-			plat->init();
-	}
-	return 0;
-}
-
 static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
 {
 	writew(lcr_h, uap->port.membase + uap->lcrh_rx);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 14/19] serial: amba-pl011: Move pl011_hwinit()
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

This patch hoists pl011_hwinit() further up within the driver. This
permits a later patch to introduce an extended .poll_init callback
that does more than pure hardware initialization.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 78 ++++++++++++++++++++---------------------
 1 file changed, 39 insertions(+), 39 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 02016fc..0b06dcf 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1425,6 +1425,45 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
 	spin_unlock_irqrestore(&uap->port.lock, flags);
 }
 
+static int pl011_hwinit(struct uart_port *port)
+{
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
+	int retval;
+
+	/* Optionaly enable pins to be muxed in and configured */
+	pinctrl_pm_select_default_state(port->dev);
+
+	/*
+	 * Try to enable the clock producer.
+	 */
+	retval = clk_prepare_enable(uap->clk);
+	if (retval)
+		return retval;
+
+	uap->port.uartclk = clk_get_rate(uap->clk);
+
+	/* Clear pending error and receive interrupts */
+	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
+	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
+
+	/*
+	 * Save interrupts enable mask, and enable RX interrupts in case if
+	 * the interrupt is used for NMI entry.
+	 */
+	uap->im = readw(uap->port.membase + UART011_IMSC);
+	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
+
+	if (dev_get_platdata(uap->port.dev)) {
+		struct amba_pl011_data *plat;
+
+		plat = dev_get_platdata(uap->port.dev);
+		if (plat->init)
+			plat->init();
+	}
+	return 0;
+}
+
 #ifdef CONFIG_CONSOLE_POLL
 
 static void pl011_quiesce_irqs(struct uart_port *port)
@@ -1483,45 +1522,6 @@ static void pl011_put_poll_char(struct uart_port *port,
 
 #endif /* CONFIG_CONSOLE_POLL */
 
-static int pl011_hwinit(struct uart_port *port)
-{
-	struct uart_amba_port *uap =
-	    container_of(port, struct uart_amba_port, port);
-	int retval;
-
-	/* Optionaly enable pins to be muxed in and configured */
-	pinctrl_pm_select_default_state(port->dev);
-
-	/*
-	 * Try to enable the clock producer.
-	 */
-	retval = clk_prepare_enable(uap->clk);
-	if (retval)
-		return retval;
-
-	uap->port.uartclk = clk_get_rate(uap->clk);
-
-	/* Clear pending error and receive interrupts */
-	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
-	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
-
-	/*
-	 * Save interrupts enable mask, and enable RX interrupts in case if
-	 * the interrupt is used for NMI entry.
-	 */
-	uap->im = readw(uap->port.membase + UART011_IMSC);
-	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
-
-	if (dev_get_platdata(uap->port.dev)) {
-		struct amba_pl011_data *plat;
-
-		plat = dev_get_platdata(uap->port.dev);
-		if (plat->init)
-			plat->init();
-	}
-	return 0;
-}
-
 static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
 {
 	writew(lcr_h, uap->port.membase + uap->lcrh_rx);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 15/19] serial: amba-pl011: Pass FIQ information to KGDB.
  2014-09-02 13:00                   ` Daniel Thompson
@ 2014-09-02 13:00                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Greg Kroah-Hartman, Jiri Slaby, linux-serial

Speculatively register a FIQ resource with KGDB. KGDB will only
accept it if the kgdb/fiq feature is enabled (both with compile time and
runtime switches) and the interrupt controller supports FIQ.

By providing this information to KGDB the serial driver offers
"permission" for KGDB to route the UART interrupt signal from the
drivers own handler to KGDBs FIQ handler (which will eventually use the
UART's polled I/O callbacks to interact with the user). This permission
also implies the amba-pl011 driver has already unmasked RX interrupts
(otherwise the FIQ handler will never trigger).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 0b06dcf..63c67b0 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -58,6 +58,7 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/sizes.h>
 #include <linux/io.h>
+#include <linux/kgdb.h>
 
 #define UART_NR			14
 
@@ -1466,6 +1467,18 @@ static int pl011_hwinit(struct uart_port *port)
 
 #ifdef CONFIG_CONSOLE_POLL
 
+static int pl011_poll_init(struct uart_port *port)
+{
+	int retval = pl011_hwinit(port);
+
+#ifdef CONFIG_KGDB_FIQ
+	if (retval == 0)
+		kgdb_register_fiq(port->irq);
+#endif
+
+	return retval;
+}
+
 static void pl011_quiesce_irqs(struct uart_port *port)
 {
 	struct uart_amba_port *uap =
@@ -1905,7 +1918,7 @@ static struct uart_ops amba_pl011_pops = {
 	.config_port	= pl011_config_port,
 	.verify_port	= pl011_verify_port,
 #ifdef CONFIG_CONSOLE_POLL
-	.poll_init     = pl011_hwinit,
+	.poll_init     = pl011_poll_init,
 	.poll_get_char = pl011_get_poll_char,
 	.poll_put_char = pl011_put_poll_char,
 #endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 15/19] serial: amba-pl011: Pass FIQ information to KGDB.
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

Speculatively register a FIQ resource with KGDB. KGDB will only
accept it if the kgdb/fiq feature is enabled (both with compile time and
runtime switches) and the interrupt controller supports FIQ.

By providing this information to KGDB the serial driver offers
"permission" for KGDB to route the UART interrupt signal from the
drivers own handler to KGDBs FIQ handler (which will eventually use the
UART's polled I/O callbacks to interact with the user). This permission
also implies the amba-pl011 driver has already unmasked RX interrupts
(otherwise the FIQ handler will never trigger).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 0b06dcf..63c67b0 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -58,6 +58,7 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/sizes.h>
 #include <linux/io.h>
+#include <linux/kgdb.h>
 
 #define UART_NR			14
 
@@ -1466,6 +1467,18 @@ static int pl011_hwinit(struct uart_port *port)
 
 #ifdef CONFIG_CONSOLE_POLL
 
+static int pl011_poll_init(struct uart_port *port)
+{
+	int retval = pl011_hwinit(port);
+
+#ifdef CONFIG_KGDB_FIQ
+	if (retval == 0)
+		kgdb_register_fiq(port->irq);
+#endif
+
+	return retval;
+}
+
 static void pl011_quiesce_irqs(struct uart_port *port)
 {
 	struct uart_amba_port *uap =
@@ -1905,7 +1918,7 @@ static struct uart_ops amba_pl011_pops = {
 	.config_port	= pl011_config_port,
 	.verify_port	= pl011_verify_port,
 #ifdef CONFIG_CONSOLE_POLL
-	.poll_init     = pl011_hwinit,
+	.poll_init     = pl011_poll_init,
 	.poll_get_char = pl011_get_poll_char,
 	.poll_put_char = pl011_put_poll_char,
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 16/19] serial: asc: Add support for KGDB's FIQ/NMI mode
  2014-09-02 13:00                   ` Daniel Thompson
  (?)
@ 2014-09-02 13:00                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Srinivas Kandagatla, Maxime Coquelin,
	Patrice Chotard, Greg Kroah-Hartman, Jiri Slaby, kernel,
	linux-serial

Add a .poll_init() function that enables UART RX and registers the
UART's irq with KGDB. By providing this information to KGDB the serial
driver offers "permission" for KGDB to route the UART interrupt signal
from the drivers own handler to KGDBs FIQ handler (which will eventually
use the UART's polled I/O callbacks to interact with the user).

Note that the RX is not only enabled but also unmasked. This is required
because otherwise the FIQ handler could never trigger. This unmask is
copied from similar code in amba-pl011.c .

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel@stlinux.com
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 8b2d735..2b5eb6e 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -30,6 +30,7 @@
 #include <linux/of_platform.h>
 #include <linux/serial_core.h>
 #include <linux/clk.h>
+#include <linux/kgdb.h>
 
 #define DRIVER_NAME "st-asc"
 #define ASC_SERIAL_NAME "ttyAS"
@@ -607,6 +608,25 @@ asc_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+
+#ifdef CONFIG_KGDB_FIQ
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int asc_poll_init(struct uart_port *port)
+{
+	struct asc_port *ascport = container_of(port, struct asc_port, port);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(ascport->port.irq);
+
+	/* enable RX interrupts in case the interrupt is used for NMI entry. */
+	asc_enable_rx_interrupts(port);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 /*
  * Console polling routines for writing and reading from the uart while
  * in an interrupt or debug context (i.e. kgdb).
@@ -649,6 +669,9 @@ static struct uart_ops asc_uart_ops = {
 	.verify_port	= asc_verify_port,
 	.pm		= asc_pm,
 #ifdef CONFIG_CONSOLE_POLL
+#ifdef CONFIG_KGDB_FIQ
+	.poll_init     = asc_poll_init,
+#endif /* CONFIG_KGDB_FIQ */
 	.poll_get_char = asc_get_poll_char,
 	.poll_put_char = asc_put_poll_char,
 #endif /* CONFIG_CONSOLE_POLL */
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 16/19] serial: asc: Add support for KGDB's FIQ/NMI mode
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Srinivas Kandagatla, Maxime Coquelin,
	Patrice Chotard, Greg Kroah-Hartman, Jiri Slaby, kernel

Add a .poll_init() function that enables UART RX and registers the
UART's irq with KGDB. By providing this information to KGDB the serial
driver offers "permission" for KGDB to route the UART interrupt signal
from the drivers own handler to KGDBs FIQ handler (which will eventually
use the UART's polled I/O callbacks to interact with the user).

Note that the RX is not only enabled but also unmasked. This is required
because otherwise the FIQ handler could never trigger. This unmask is
copied from similar code in amba-pl011.c .

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel@stlinux.com
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 8b2d735..2b5eb6e 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -30,6 +30,7 @@
 #include <linux/of_platform.h>
 #include <linux/serial_core.h>
 #include <linux/clk.h>
+#include <linux/kgdb.h>
 
 #define DRIVER_NAME "st-asc"
 #define ASC_SERIAL_NAME "ttyAS"
@@ -607,6 +608,25 @@ asc_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+
+#ifdef CONFIG_KGDB_FIQ
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int asc_poll_init(struct uart_port *port)
+{
+	struct asc_port *ascport = container_of(port, struct asc_port, port);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(ascport->port.irq);
+
+	/* enable RX interrupts in case the interrupt is used for NMI entry. */
+	asc_enable_rx_interrupts(port);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 /*
  * Console polling routines for writing and reading from the uart while
  * in an interrupt or debug context (i.e. kgdb).
@@ -649,6 +669,9 @@ static struct uart_ops asc_uart_ops = {
 	.verify_port	= asc_verify_port,
 	.pm		= asc_pm,
 #ifdef CONFIG_CONSOLE_POLL
+#ifdef CONFIG_KGDB_FIQ
+	.poll_init     = asc_poll_init,
+#endif /* CONFIG_KGDB_FIQ */
 	.poll_get_char = asc_get_poll_char,
 	.poll_put_char = asc_put_poll_char,
 #endif /* CONFIG_CONSOLE_POLL */
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 16/19] serial: asc: Add support for KGDB's FIQ/NMI mode
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

Add a .poll_init() function that enables UART RX and registers the
UART's irq with KGDB. By providing this information to KGDB the serial
driver offers "permission" for KGDB to route the UART interrupt signal
from the drivers own handler to KGDBs FIQ handler (which will eventually
use the UART's polled I/O callbacks to interact with the user).

Note that the RX is not only enabled but also unmasked. This is required
because otherwise the FIQ handler could never trigger. This unmask is
copied from similar code in amba-pl011.c .

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel at stlinux.com
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 8b2d735..2b5eb6e 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -30,6 +30,7 @@
 #include <linux/of_platform.h>
 #include <linux/serial_core.h>
 #include <linux/clk.h>
+#include <linux/kgdb.h>
 
 #define DRIVER_NAME "st-asc"
 #define ASC_SERIAL_NAME "ttyAS"
@@ -607,6 +608,25 @@ asc_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+
+#ifdef CONFIG_KGDB_FIQ
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int asc_poll_init(struct uart_port *port)
+{
+	struct asc_port *ascport = container_of(port, struct asc_port, port);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(ascport->port.irq);
+
+	/* enable RX interrupts in case the interrupt is used for NMI entry. */
+	asc_enable_rx_interrupts(port);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 /*
  * Console polling routines for writing and reading from the uart while
  * in an interrupt or debug context (i.e. kgdb).
@@ -649,6 +669,9 @@ static struct uart_ops asc_uart_ops = {
 	.verify_port	= asc_verify_port,
 	.pm		= asc_pm,
 #ifdef CONFIG_CONSOLE_POLL
+#ifdef CONFIG_KGDB_FIQ
+	.poll_init     = asc_poll_init,
+#endif /* CONFIG_KGDB_FIQ */
 	.poll_get_char = asc_get_poll_char,
 	.poll_put_char = asc_put_poll_char,
 #endif /* CONFIG_CONSOLE_POLL */
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 17/19] serial: asc: Adopt readl_/writel_relaxed()
  2014-09-02 13:00                   ` Daniel Thompson
  (?)
@ 2014-09-02 13:00                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Srinivas Kandagatla, Maxime Coquelin,
	Patrice Chotard, Greg Kroah-Hartman, Jiri Slaby, kernel,
	linux-serial

The architectures where this peripheral exists (ARM and SH) have expensive
implementations of writel(), reliant on spin locks and explicit L2 cache
management. These architectures provide a cheaper writel_relaxed() which
is much better suited to peripherals that do not perform DMA. The
situation with readl()/readl_relaxed()is similar although less acute.

This driver does not use DMA and will be more power efficient and more
robust (due to absense of spin locks during console I/O) if it uses the
relaxed variants.

This change means the driver is no longer portable and therefore no
longer suitable for compile testing.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel@stlinux.com
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/Kconfig  | 2 +-
 drivers/tty/serial/st-asc.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 26cec64d..e9b1735 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1527,7 +1527,7 @@ config SERIAL_FSL_LPUART_CONSOLE
 config SERIAL_ST_ASC
 	tristate "ST ASC serial port support"
 	select SERIAL_CORE
-	depends on ARM || COMPILE_TEST
+	depends on ARM
 	help
 	  This driver is for the on-chip Asychronous Serial Controller on
 	  STMicroelectronics STi SoCs.
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 2b5eb6e..df709ee 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -152,12 +152,12 @@ static inline struct asc_port *to_asc_port(struct uart_port *port)
 
 static inline u32 asc_in(struct uart_port *port, u32 offset)
 {
-	return readl(port->membase + offset);
+	return readl_relaxed(port->membase + offset);
 }
 
 static inline void asc_out(struct uart_port *port, u32 offset, u32 value)
 {
-	writel(value, port->membase + offset);
+	writel_relaxed(value, port->membase + offset);
 }
 
 /*
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 17/19] serial: asc: Adopt readl_/writel_relaxed()
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Srinivas Kandagatla, Maxime Coquelin,
	Patrice Chotard, Greg Kroah-Hartman, Jiri Slaby, kernel

The architectures where this peripheral exists (ARM and SH) have expensive
implementations of writel(), reliant on spin locks and explicit L2 cache
management. These architectures provide a cheaper writel_relaxed() which
is much better suited to peripherals that do not perform DMA. The
situation with readl()/readl_relaxed()is similar although less acute.

This driver does not use DMA and will be more power efficient and more
robust (due to absense of spin locks during console I/O) if it uses the
relaxed variants.

This change means the driver is no longer portable and therefore no
longer suitable for compile testing.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel@stlinux.com
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/Kconfig  | 2 +-
 drivers/tty/serial/st-asc.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 26cec64d..e9b1735 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1527,7 +1527,7 @@ config SERIAL_FSL_LPUART_CONSOLE
 config SERIAL_ST_ASC
 	tristate "ST ASC serial port support"
 	select SERIAL_CORE
-	depends on ARM || COMPILE_TEST
+	depends on ARM
 	help
 	  This driver is for the on-chip Asychronous Serial Controller on
 	  STMicroelectronics STi SoCs.
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 2b5eb6e..df709ee 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -152,12 +152,12 @@ static inline struct asc_port *to_asc_port(struct uart_port *port)
 
 static inline u32 asc_in(struct uart_port *port, u32 offset)
 {
-	return readl(port->membase + offset);
+	return readl_relaxed(port->membase + offset);
 }
 
 static inline void asc_out(struct uart_port *port, u32 offset, u32 value)
 {
-	writel(value, port->membase + offset);
+	writel_relaxed(value, port->membase + offset);
 }
 
 /*
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 17/19] serial: asc: Adopt readl_/writel_relaxed()
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

The architectures where this peripheral exists (ARM and SH) have expensive
implementations of writel(), reliant on spin locks and explicit L2 cache
management. These architectures provide a cheaper writel_relaxed() which
is much better suited to peripherals that do not perform DMA. The
situation with readl()/readl_relaxed()is similar although less acute.

This driver does not use DMA and will be more power efficient and more
robust (due to absense of spin locks during console I/O) if it uses the
relaxed variants.

This change means the driver is no longer portable and therefore no
longer suitable for compile testing.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
Cc: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Patrice Chotard <patrice.chotard@st.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: kernel at stlinux.com
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/Kconfig  | 2 +-
 drivers/tty/serial/st-asc.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 26cec64d..e9b1735 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1527,7 +1527,7 @@ config SERIAL_FSL_LPUART_CONSOLE
 config SERIAL_ST_ASC
 	tristate "ST ASC serial port support"
 	select SERIAL_CORE
-	depends on ARM || COMPILE_TEST
+	depends on ARM
 	help
 	  This driver is for the on-chip Asychronous Serial Controller on
 	  STMicroelectronics STi SoCs.
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 2b5eb6e..df709ee 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -152,12 +152,12 @@ static inline struct asc_port *to_asc_port(struct uart_port *port)
 
 static inline u32 asc_in(struct uart_port *port, u32 offset)
 {
-	return readl(port->membase + offset);
+	return readl_relaxed(port->membase + offset);
 }
 
 static inline void asc_out(struct uart_port *port, u32 offset, u32 value)
 {
-	writel(value, port->membase + offset);
+	writel_relaxed(value, port->membase + offset);
 }
 
 /*
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 18/19] serial: imx: clean up imx_poll_get_char()
  2014-09-02 13:00                   ` Daniel Thompson
@ 2014-09-02 13:00                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Dirk Behme, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Daniel Thompson, Greg Kroah-Hartman, Jiri Slaby,
	linux-serial

From: Dirk Behme <dirk.behme@de.bosch.com>

Looking at the get_poll_char() function of the 8250.c serial driver,
we learn:

* poll_get_char() doesn't have to save/disable/restore the interrupt
  registers. No interrupt handling is needed in this function at all.
  Remove it.

* Don't block in case there is no data available. So instead blocking
  in the do {} while loop, just return with NO_POLL_CHAR, immediately .

Additionally, while the i.MX6 register URXD[7-0] contain the RX_DATA,
the upper bits of this register (URXD[15-10]) might contain some
control flags. To ensure that these are not returned with the data
read, just mask out URXD[7-0].

These changes fix the 'hang' working with kdb:

$ echo ttymxc3 > /sys/module/kgdboc/parameters/kgdboc
$ echo g >/proc/sysrq-trigger
[0]kdb> help
...
<hang>

Signed-off-by: Dirk Behme <dirk.behme@de.bosch.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
---
 drivers/tty/serial/imx.c | 29 ++++-------------------------
 1 file changed, 4 insertions(+), 25 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 044e86d..983668a 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -80,6 +80,7 @@
 #define URXD_FRMERR	(1<<12)
 #define URXD_BRK	(1<<11)
 #define URXD_PRERR	(1<<10)
+#define URXD_RX_DATA	(0xFF<<0)
 #define UCR1_ADEN	(1<<15) /* Auto detect interrupt */
 #define UCR1_ADBR	(1<<14) /* Auto detect baud rate */
 #define UCR1_TRDYEN	(1<<13) /* Transmitter ready interrupt enable */
@@ -1506,32 +1507,10 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
 #if defined(CONFIG_CONSOLE_POLL)
 static int imx_poll_get_char(struct uart_port *port)
 {
-	struct imx_port_ucrs old_ucr;
-	unsigned int status;
-	unsigned char c;
-
-	/* save control registers */
-	imx_port_ucrs_save(port, &old_ucr);
-
-	/* disable interrupts */
-	writel(UCR1_UARTEN, port->membase + UCR1);
-	writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
-	       port->membase + UCR2);
-	writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
-	       port->membase + UCR3);
-
-	/* poll */
-	do {
-		status = readl(port->membase + USR2);
-	} while (~status & USR2_RDR);
-
-	/* read */
-	c = readl(port->membase + URXD0);
-
-	/* restore control registers */
-	imx_port_ucrs_restore(port, &old_ucr);
+	if (!(readl(port->membase + USR2) & USR2_RDR))
+		return NO_POLL_CHAR;
 
-	return c;
+	return readl(port->membase + URXD0) & URXD_RX_DATA;
 }
 
 static void imx_poll_put_char(struct uart_port *port, unsigned char c)
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 18/19] serial: imx: clean up imx_poll_get_char()
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

From: Dirk Behme <dirk.behme@de.bosch.com>

Looking at the get_poll_char() function of the 8250.c serial driver,
we learn:

* poll_get_char() doesn't have to save/disable/restore the interrupt
  registers. No interrupt handling is needed in this function at all.
  Remove it.

* Don't block in case there is no data available. So instead blocking
  in the do {} while loop, just return with NO_POLL_CHAR, immediately .

Additionally, while the i.MX6 register URXD[7-0] contain the RX_DATA,
the upper bits of this register (URXD[15-10]) might contain some
control flags. To ensure that these are not returned with the data
read, just mask out URXD[7-0].

These changes fix the 'hang' working with kdb:

$ echo ttymxc3 > /sys/module/kgdboc/parameters/kgdboc
$ echo g >/proc/sysrq-trigger
[0]kdb> help
...
<hang>

Signed-off-by: Dirk Behme <dirk.behme@de.bosch.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial at vger.kernel.org
---
 drivers/tty/serial/imx.c | 29 ++++-------------------------
 1 file changed, 4 insertions(+), 25 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 044e86d..983668a 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -80,6 +80,7 @@
 #define URXD_FRMERR	(1<<12)
 #define URXD_BRK	(1<<11)
 #define URXD_PRERR	(1<<10)
+#define URXD_RX_DATA	(0xFF<<0)
 #define UCR1_ADEN	(1<<15) /* Auto detect interrupt */
 #define UCR1_ADBR	(1<<14) /* Auto detect baud rate */
 #define UCR1_TRDYEN	(1<<13) /* Transmitter ready interrupt enable */
@@ -1506,32 +1507,10 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
 #if defined(CONFIG_CONSOLE_POLL)
 static int imx_poll_get_char(struct uart_port *port)
 {
-	struct imx_port_ucrs old_ucr;
-	unsigned int status;
-	unsigned char c;
-
-	/* save control registers */
-	imx_port_ucrs_save(port, &old_ucr);
-
-	/* disable interrupts */
-	writel(UCR1_UARTEN, port->membase + UCR1);
-	writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
-	       port->membase + UCR2);
-	writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
-	       port->membase + UCR3);
-
-	/* poll */
-	do {
-		status = readl(port->membase + USR2);
-	} while (~status & USR2_RDR);
-
-	/* read */
-	c = readl(port->membase + URXD0);
-
-	/* restore control registers */
-	imx_port_ucrs_restore(port, &old_ucr);
+	if (!(readl(port->membase + USR2) & USR2_RDR))
+		return NO_POLL_CHAR;
 
-	return c;
+	return readl(port->membase + URXD0) & URXD_RX_DATA;
 }
 
 static void imx_poll_put_char(struct uart_port *port, unsigned char c)
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 19/19] serial: imx: Add support for KGDB's FIQ/NMI mode
  2014-09-02 13:00                   ` Daniel Thompson
@ 2014-09-02 13:00                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Greg Kroah-Hartman, Jiri Slaby, linux-serial

This patch makes it possible to use the imx uart with KGDB's FIQ/NMI
mode.

Main changes are:

.poll_init() will, if KGDB+FIQ are enabled, perform deeper hardware
initialization to ensure the serial port is always active (required
otherwise FIQ is not triggered by UART activity). This has an impact on
power usage so it is conservatively enabled.

imx_put_poll_char() has been simplified to remove the code to disable
interrupts. The present code can corrupt register state when re-entered
from FIQ handler.

Both imx_put_poll_char() and imx_get_poll_char() adopt _relaxed()
MMIO functions (which are safe for polled I/O and needed to avoid taking
spin locks).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
Acked-by: Dirk Behme <dirk.behme@de.bosch.com>
---
 drivers/tty/serial/imx.c | 71 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 52 insertions(+), 19 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 983668a..a201c61 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -49,6 +49,7 @@
 #include <linux/of_device.h>
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
+#include <linux/kgdb.h>
 
 #include <asm/irq.h>
 #include <linux/platform_data/serial-imx.h>
@@ -1505,44 +1506,73 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #if defined(CONFIG_CONSOLE_POLL)
+
+#if defined(CONFIG_KGDB_FIQ)
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int imx_poll_init(struct uart_port *port)
+{
+	struct imx_port *sport = (struct imx_port *)port;
+	unsigned long flags;
+	unsigned long temp;
+	int retval;
+
+	retval = clk_prepare_enable(sport->clk_ipg);
+	if (retval)
+		return retval;
+	retval = clk_prepare_enable(sport->clk_per);
+	if (retval)
+		clk_disable_unprepare(sport->clk_ipg);
+
+	imx_setup_ufcr(sport, 0);
+
+	spin_lock_irqsave(&sport->port.lock, flags);
+
+	temp = readl(sport->port.membase + UCR1);
+	if (is_imx1_uart(sport))
+		temp |= IMX1_UCR1_UARTCLKEN;
+	temp |= UCR1_UARTEN | UCR1_RRDYEN;
+	temp &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN);
+	writel(temp, sport->port.membase + UCR1);
+
+	temp = readl(sport->port.membase + UCR2);
+	temp |= UCR2_RXEN;
+	writel(temp, sport->port.membase + UCR2);
+
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(sport->port.irq);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 static int imx_poll_get_char(struct uart_port *port)
 {
-	if (!(readl(port->membase + USR2) & USR2_RDR))
+	if (!(readl_relaxed(port->membase + USR2) & USR2_RDR))
 		return NO_POLL_CHAR;
 
-	return readl(port->membase + URXD0) & URXD_RX_DATA;
+	return readl_relaxed(port->membase + URXD0) & URXD_RX_DATA;
 }
 
 static void imx_poll_put_char(struct uart_port *port, unsigned char c)
 {
-	struct imx_port_ucrs old_ucr;
 	unsigned int status;
 
-	/* save control registers */
-	imx_port_ucrs_save(port, &old_ucr);
-
-	/* disable interrupts */
-	writel(UCR1_UARTEN, port->membase + UCR1);
-	writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
-	       port->membase + UCR2);
-	writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
-	       port->membase + UCR3);
-
 	/* drain */
 	do {
-		status = readl(port->membase + USR1);
+		status = readl_relaxed(port->membase + USR1);
 	} while (~status & USR1_TRDY);
 
 	/* write */
-	writel(c, port->membase + URTX0);
+	writel_relaxed(c, port->membase + URTX0);
 
 	/* flush */
 	do {
-		status = readl(port->membase + USR2);
+		status = readl_relaxed(port->membase + USR2);
 	} while (~status & USR2_TXDC);
-
-	/* restore control registers */
-	imx_port_ucrs_restore(port, &old_ucr);
 }
 #endif
 
@@ -1563,6 +1593,9 @@ static struct uart_ops imx_pops = {
 	.config_port	= imx_config_port,
 	.verify_port	= imx_verify_port,
 #if defined(CONFIG_CONSOLE_POLL)
+#if defined(CONFIG_KGDB_FIQ)
+	.poll_init      = imx_poll_init,
+#endif
 	.poll_get_char  = imx_poll_get_char,
 	.poll_put_char  = imx_poll_put_char,
 #endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v11 19/19] serial: imx: Add support for KGDB's FIQ/NMI mode
@ 2014-09-02 13:00                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-02 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

This patch makes it possible to use the imx uart with KGDB's FIQ/NMI
mode.

Main changes are:

.poll_init() will, if KGDB+FIQ are enabled, perform deeper hardware
initialization to ensure the serial port is always active (required
otherwise FIQ is not triggered by UART activity). This has an impact on
power usage so it is conservatively enabled.

imx_put_poll_char() has been simplified to remove the code to disable
interrupts. The present code can corrupt register state when re-entered
from FIQ handler.

Both imx_put_poll_char() and imx_get_poll_char() adopt _relaxed()
MMIO functions (which are safe for polled I/O and needed to avoid taking
spin locks).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial at vger.kernel.org
Acked-by: Dirk Behme <dirk.behme@de.bosch.com>
---
 drivers/tty/serial/imx.c | 71 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 52 insertions(+), 19 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 983668a..a201c61 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -49,6 +49,7 @@
 #include <linux/of_device.h>
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
+#include <linux/kgdb.h>
 
 #include <asm/irq.h>
 #include <linux/platform_data/serial-imx.h>
@@ -1505,44 +1506,73 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 #if defined(CONFIG_CONSOLE_POLL)
+
+#if defined(CONFIG_KGDB_FIQ)
+/*
+ * Prepare the UART to be used from kgdb's NMI support.
+ */
+static int imx_poll_init(struct uart_port *port)
+{
+	struct imx_port *sport = (struct imx_port *)port;
+	unsigned long flags;
+	unsigned long temp;
+	int retval;
+
+	retval = clk_prepare_enable(sport->clk_ipg);
+	if (retval)
+		return retval;
+	retval = clk_prepare_enable(sport->clk_per);
+	if (retval)
+		clk_disable_unprepare(sport->clk_ipg);
+
+	imx_setup_ufcr(sport, 0);
+
+	spin_lock_irqsave(&sport->port.lock, flags);
+
+	temp = readl(sport->port.membase + UCR1);
+	if (is_imx1_uart(sport))
+		temp |= IMX1_UCR1_UARTCLKEN;
+	temp |= UCR1_UARTEN | UCR1_RRDYEN;
+	temp &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN);
+	writel(temp, sport->port.membase + UCR1);
+
+	temp = readl(sport->port.membase + UCR2);
+	temp |= UCR2_RXEN;
+	writel(temp, sport->port.membase + UCR2);
+
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+
+	/* register the FIQ with kgdb */
+	kgdb_register_fiq(sport->port.irq);
+
+	return 0;
+}
+#endif /* CONFIG_KGDB_FIQ */
+
 static int imx_poll_get_char(struct uart_port *port)
 {
-	if (!(readl(port->membase + USR2) & USR2_RDR))
+	if (!(readl_relaxed(port->membase + USR2) & USR2_RDR))
 		return NO_POLL_CHAR;
 
-	return readl(port->membase + URXD0) & URXD_RX_DATA;
+	return readl_relaxed(port->membase + URXD0) & URXD_RX_DATA;
 }
 
 static void imx_poll_put_char(struct uart_port *port, unsigned char c)
 {
-	struct imx_port_ucrs old_ucr;
 	unsigned int status;
 
-	/* save control registers */
-	imx_port_ucrs_save(port, &old_ucr);
-
-	/* disable interrupts */
-	writel(UCR1_UARTEN, port->membase + UCR1);
-	writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
-	       port->membase + UCR2);
-	writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
-	       port->membase + UCR3);
-
 	/* drain */
 	do {
-		status = readl(port->membase + USR1);
+		status = readl_relaxed(port->membase + USR1);
 	} while (~status & USR1_TRDY);
 
 	/* write */
-	writel(c, port->membase + URTX0);
+	writel_relaxed(c, port->membase + URTX0);
 
 	/* flush */
 	do {
-		status = readl(port->membase + USR2);
+		status = readl_relaxed(port->membase + USR2);
 	} while (~status & USR2_TXDC);
-
-	/* restore control registers */
-	imx_port_ucrs_restore(port, &old_ucr);
 }
 #endif
 
@@ -1563,6 +1593,9 @@ static struct uart_ops imx_pops = {
 	.config_port	= imx_config_port,
 	.verify_port	= imx_verify_port,
 #if defined(CONFIG_CONSOLE_POLL)
+#if defined(CONFIG_KGDB_FIQ)
+	.poll_init      = imx_poll_init,
+#endif
 	.poll_get_char  = imx_poll_get_char,
 	.poll_put_char  = imx_poll_put_char,
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* Re: [STLinux Kernel] [PATCH v11 17/19] serial: asc: Adopt readl_/writel_relaxed()
  2014-09-02 13:00                     ` Daniel Thompson
@ 2014-09-02 13:42                       ` Peter Griffin
  -1 siblings, 0 replies; 535+ messages in thread
From: Peter Griffin @ 2014-09-02 13:42 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Russell King, kernel, Catalin Marinas, Linus Walleij,
	Fabio Estevam, Nicolas Pitre, Jiri Slaby, Anton Vorontsov,
	Ben Dooks, Rob Herring, linux-serial, kgdb-bugreport,
	kernel-team, Dave Martin, linaro-kernel, patches, John Stultz,
	linux-arm-kernel, Greg Kroah-Hartman, linux-kernel, Colin Cross,
	Frederic Weisbecker, Srinivas Kandagatla

On Tue, 02 Sep 2014, Daniel Thompson wrote:

> The architectures where this peripheral exists (ARM and SH) have expensive
> implementations of writel(), reliant on spin locks and explicit L2 cache
> management. These architectures provide a cheaper writel_relaxed() which
> is much better suited to peripherals that do not perform DMA. The
> situation with readl()/readl_relaxed()is similar although less acute.
> 
> This driver does not use DMA and will be more power efficient and more
> robust (due to absense of spin locks during console I/O) if it uses the
> relaxed variants.
> 
> This change means the driver is no longer portable and therefore no
> longer suitable for compile testing.
> 
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
> Cc: Maxime Coquelin <maxime.coquelin@st.com>
> Cc: Patrice Chotard <patrice.chotard@st.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Jiri Slaby <jslaby@suse.cz>
> Cc: kernel@stlinux.com
> Cc: linux-serial@vger.kernel.org

Acked-by: Peter Griffin <peter.griffin@linaro.org>


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [STLinux Kernel] [PATCH v11 17/19] serial: asc: Adopt readl_/writel_relaxed()
@ 2014-09-02 13:42                       ` Peter Griffin
  0 siblings, 0 replies; 535+ messages in thread
From: Peter Griffin @ 2014-09-02 13:42 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 02 Sep 2014, Daniel Thompson wrote:

> The architectures where this peripheral exists (ARM and SH) have expensive
> implementations of writel(), reliant on spin locks and explicit L2 cache
> management. These architectures provide a cheaper writel_relaxed() which
> is much better suited to peripherals that do not perform DMA. The
> situation with readl()/readl_relaxed()is similar although less acute.
> 
> This driver does not use DMA and will be more power efficient and more
> robust (due to absense of spin locks during console I/O) if it uses the
> relaxed variants.
> 
> This change means the driver is no longer portable and therefore no
> longer suitable for compile testing.
> 
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
> Cc: Maxime Coquelin <maxime.coquelin@st.com>
> Cc: Patrice Chotard <patrice.chotard@st.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Jiri Slaby <jslaby@suse.cz>
> Cc: kernel at stlinux.com
> Cc: linux-serial at vger.kernel.org

Acked-by: Peter Griffin <peter.griffin@linaro.org>

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v11 17/19] serial: asc: Adopt readl_/writel_relaxed()
  2014-09-02 13:00                     ` Daniel Thompson
  (?)
@ 2014-09-02 13:55                       ` Maxime Coquelin
  -1 siblings, 0 replies; 535+ messages in thread
From: Maxime Coquelin @ 2014-09-02 13:55 UTC (permalink / raw)
  To: Daniel Thompson, Russell King
  Cc: linux-kernel, linux-arm-kernel, kgdb-bugreport, patches,
	linaro-kernel, John Stultz, Anton Vorontsov, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Srinivas Kandagatla, Patrice Chotard,
	Greg Kroah-Hartman, Jiri Slaby, kernel, linux-serial

Hi Daniel,

On 09/02/2014 03:00 PM, Daniel Thompson wrote:
> The architectures where this peripheral exists (ARM and SH) have expensive
> implementations of writel(), reliant on spin locks and explicit L2 cache
> management. These architectures provide a cheaper writel_relaxed() which
> is much better suited to peripherals that do not perform DMA. The
> situation with readl()/readl_relaxed()is similar although less acute.
>
> This driver does not use DMA and will be more power efficient and more
> robust (due to absense of spin locks during console I/O) if it uses the
> relaxed variants.
>
> This change means the driver is no longer portable and therefore no
> longer suitable for compile testing.
>
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
> Cc: Maxime Coquelin <maxime.coquelin@st.com>
> Cc: Patrice Chotard <patrice.chotard@st.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Jiri Slaby <jslaby@suse.cz>
> Cc: kernel@stlinux.com
> Cc: linux-serial@vger.kernel.org
> ---
>   drivers/tty/serial/Kconfig  | 2 +-
>   drivers/tty/serial/st-asc.c | 4 ++--
>   2 files changed, 3 insertions(+), 3 deletions(-)



You can add my:
Acked-by: Maxime Coquelin <maxime.coquelin@st.com>

thanks!
Maxime


^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v11 17/19] serial: asc: Adopt readl_/writel_relaxed()
@ 2014-09-02 13:55                       ` Maxime Coquelin
  0 siblings, 0 replies; 535+ messages in thread
From: Maxime Coquelin @ 2014-09-02 13:55 UTC (permalink / raw)
  To: Daniel Thompson, Russell King
  Cc: linux-kernel, linux-arm-kernel, kgdb-bugreport, patches,
	linaro-kernel, John Stultz, Anton Vorontsov, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Srinivas Kandagatla, Patrice Chotard,
	Greg Kroah-Hartman, Jiri Slaby, kernel, linux-serial

Hi Daniel,

On 09/02/2014 03:00 PM, Daniel Thompson wrote:
> The architectures where this peripheral exists (ARM and SH) have expensive
> implementations of writel(), reliant on spin locks and explicit L2 cache
> management. These architectures provide a cheaper writel_relaxed() which
> is much better suited to peripherals that do not perform DMA. The
> situation with readl()/readl_relaxed()is similar although less acute.
>
> This driver does not use DMA and will be more power efficient and more
> robust (due to absense of spin locks during console I/O) if it uses the
> relaxed variants.
>
> This change means the driver is no longer portable and therefore no
> longer suitable for compile testing.
>
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
> Cc: Maxime Coquelin <maxime.coquelin@st.com>
> Cc: Patrice Chotard <patrice.chotard@st.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Jiri Slaby <jslaby@suse.cz>
> Cc: kernel@stlinux.com
> Cc: linux-serial@vger.kernel.org
> ---
>   drivers/tty/serial/Kconfig  | 2 +-
>   drivers/tty/serial/st-asc.c | 4 ++--
>   2 files changed, 3 insertions(+), 3 deletions(-)



You can add my:
Acked-by: Maxime Coquelin <maxime.coquelin@st.com>

thanks!
Maxime


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v11 17/19] serial: asc: Adopt readl_/writel_relaxed()
@ 2014-09-02 13:55                       ` Maxime Coquelin
  0 siblings, 0 replies; 535+ messages in thread
From: Maxime Coquelin @ 2014-09-02 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Daniel,

On 09/02/2014 03:00 PM, Daniel Thompson wrote:
> The architectures where this peripheral exists (ARM and SH) have expensive
> implementations of writel(), reliant on spin locks and explicit L2 cache
> management. These architectures provide a cheaper writel_relaxed() which
> is much better suited to peripherals that do not perform DMA. The
> situation with readl()/readl_relaxed()is similar although less acute.
>
> This driver does not use DMA and will be more power efficient and more
> robust (due to absense of spin locks during console I/O) if it uses the
> relaxed variants.
>
> This change means the driver is no longer portable and therefore no
> longer suitable for compile testing.
>
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
> Cc: Maxime Coquelin <maxime.coquelin@st.com>
> Cc: Patrice Chotard <patrice.chotard@st.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Jiri Slaby <jslaby@suse.cz>
> Cc: kernel at stlinux.com
> Cc: linux-serial at vger.kernel.org
> ---
>   drivers/tty/serial/Kconfig  | 2 +-
>   drivers/tty/serial/st-asc.c | 4 ++--
>   2 files changed, 3 insertions(+), 3 deletions(-)



You can add my:
Acked-by: Maxime Coquelin <maxime.coquelin@st.com>

thanks!
Maxime

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
  2014-09-02 11:49                           ` Daniel Thompson
@ 2014-09-02 14:23                             ` Paul E. McKenney
  -1 siblings, 0 replies; 535+ messages in thread
From: Paul E. McKenney @ 2014-09-02 14:23 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Russell King - ARM Linux, linux-kernel, linux-arm-kernel,
	kgdb-bugreport, patches, linaro-kernel, John Stultz,
	Anton Vorontsov, Colin Cross, kernel-team, Rob Herring,
	Linus Walleij, Ben Dooks, Catalin Marinas, Dave Martin,
	Fabio Estevam, Frederic Weisbecker, Nicolas Pitre

On Tue, Sep 02, 2014 at 12:49:16PM +0100, Daniel Thompson wrote:
> On 28/08/14 16:01, Russell King - ARM Linux wrote:
> > On Tue, Aug 19, 2014 at 07:12:07PM +0100, Daniel Thompson wrote:
> >> On 19/08/14 18:37, Russell King - ARM Linux wrote:
> >>> On Tue, Aug 19, 2014 at 05:45:53PM +0100, Daniel Thompson wrote:
> >>>> +int register_fiq_nmi_notifier(struct notifier_block *nb)
> >>>> +{
> >>>> +	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
> >>>> +}
> >>>> +
> >>>> +asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
> >>>> +{
> >>>> +	struct pt_regs *old_regs = set_irq_regs(regs);
> >>>> +
> >>>> +	nmi_enter();
> >>>> +	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
> >>>> +	nmi_exit();
> >>>> +	set_irq_regs(old_regs);
> >>>> +}
> >>>
> >>> Really not happy with this.  What happens if a FIQ occurs while we're
> >>> inside register_fiq_nmi_notifier() - more specifically inside
> >>> atomic_notifier_chain_register() ?
> >>
> >> Should depend on which side of the rcu update we're on.
> > 
> > I just asked Paul McKenney, our RCU expert... essentially, yes, RCU
> > stuff itself is safe in this context.  However, RCU stuff can call into
> > lockdep if lockdep is configured, and there are questions over lockdep.
> > 
> > There's some things which can be done to reduce the lockdep exposure
> > to it, such as ensuring that rcu_read_lock() is first called outside
> > of FIQ context.
> > 
> > There's concerns with whether either printk() in check_flags() could
> > be reached too (flags there should always indicate that IRQs were
> > disabled, so that reduces down to a question about just the first
> > printk() there.)
> > 
> > There's also the very_verbose() stuff for RCU lockdep classes which
> > Paul says must not be enabled.
> > 
> > Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
> > lockdep doing the deadlock checking as a result of the above call.
> > 
> > So... this coupled with my feeling that notifiers make it too easy for
> > unreviewed code to be hooked into this path, I'm fairly sure that we
> > don't want to be calling atomic notifier chains from FIQ context.
> 
> Having esablished (elsewhere in the thread) that RCU usage is safe
> from FIQ I have been working on the assumption that your feeling
> regarding unreviewed code is sufficient on its own to avoid using
> notifiers (and also to avoid a list of function pointers like on x86).

There was a later clarification from a lockdep expert showing that the
code was in fact safe, so the notifier approach should be just fine.

							Thanx, Paul

> Therefore I have made the changes requested and produced a
> before/after patch to show the impact of this. I will merge this
> into the FIQ patchset shortly (I need to run a few more build tests
> first).
> 
> Personally I still favour using notifiers and think the coupling below is
> excessive. Nevertheless I've run a couple of basic tests on the code
> below and it works fine.
> 
> 
> diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
> index 175bfed..a25c952 100644
> --- a/arch/arm/include/asm/fiq.h
> +++ b/arch/arm/include/asm/fiq.h
> @@ -54,7 +54,6 @@ extern void disable_fiq(int fiq);
>  extern int ack_fiq(int fiq);
>  extern void eoi_fiq(int fiq);
>  extern bool has_fiq(int fiq);
> -extern int register_fiq_nmi_notifier(struct notifier_block *nb);
>  extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
> 
>  /* helpers defined in fiqasm.S: */
> diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
> index 6563da0..cb5ccd6 100644
> --- a/arch/arm/include/asm/kgdb.h
> +++ b/arch/arm/include/asm/kgdb.h
> @@ -51,6 +51,7 @@ extern void kgdb_handle_bus_error(void);
>  extern int kgdb_fault_expected;
> 
>  extern int kgdb_register_fiq(unsigned int fiq);
> +extern void kgdb_handle_fiq(struct pt_regs *regs);
> 
>  #endif /* !__ASSEMBLY__ */
> 
> diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
> index b2bd1c7..7422b58 100644
> --- a/arch/arm/kernel/fiq.c
> +++ b/arch/arm/kernel/fiq.c
> @@ -43,12 +43,14 @@
>  #include <linux/irq.h>
>  #include <linux/radix-tree.h>
>  #include <linux/slab.h>
> +#include <linux/irqchip/arm-gic.h>
> 
>  #include <asm/cacheflush.h>
>  #include <asm/cp15.h>
>  #include <asm/exception.h>
>  #include <asm/fiq.h>
>  #include <asm/irq.h>
> +#include <asm/kgdb.h>
>  #include <asm/traps.h>
> 
>  #define FIQ_OFFSET ({					\
> @@ -65,7 +67,6 @@ static unsigned long no_fiq_insn;
>  static int fiq_start = -1;
>  static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
>  static DEFINE_MUTEX(fiq_data_mutex);
> -static ATOMIC_NOTIFIER_HEAD(fiq_nmi_chain);
> 
>  /* Default reacquire function
>   * - we always relinquish FIQ control
> @@ -218,17 +219,23 @@ bool has_fiq(int fiq)
>  }
>  EXPORT_SYMBOL(has_fiq);
> 
> -int register_fiq_nmi_notifier(struct notifier_block *nb)
> -{
> -	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
> -}
> -
>  asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
>  {
>  	struct pt_regs *old_regs = set_irq_regs(regs);
> 
>  	nmi_enter();
> -	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
> +
> +	/* these callbacks deliberately avoid using a notifier chain in
> +	 * order to ensure code review happens (drivers cannot "secretly"
> +	 * employ FIQ without modifying this chain of calls).
> +	 */
> +#ifdef CONFIG_KGDB_FIQ
> +	kgdb_handle_fiq(regs);
> +#endif
> +#ifdef CONFIG_ARM_GIC
> +	gic_handle_fiq_ipi();
> +#endif
> +
>  	nmi_exit();
>  	set_irq_regs(old_regs);
>  }
> diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
> index b77b885..630a3ef 100644
> --- a/arch/arm/kernel/kgdb.c
> +++ b/arch/arm/kernel/kgdb.c
> @@ -312,12 +312,13 @@ struct kgdb_arch arch_kgdb_ops = {
>  };
> 
>  #ifdef CONFIG_KGDB_FIQ
> -static int kgdb_handle_fiq(struct notifier_block *nb, unsigned long arg,
> -			   void *data)
> +void kgdb_handle_fiq(struct pt_regs *regs)
>  {
> -	struct pt_regs *regs = (void *) arg;
>  	int actual;
> 
> +	if (!kgdb_fiq)
> +		return;
> +
>  	if (!kgdb_nmicallback(raw_smp_processor_id(), regs))
>  		return NOTIFY_OK;
> 
> @@ -333,11 +334,6 @@ static int kgdb_handle_fiq(struct notifier_block *nb, unsigned long arg,
>  	return NOTIFY_OK;
>  }
> 
> -static struct notifier_block kgdb_fiq_notifier = {
> -	.notifier_call = kgdb_handle_fiq,
> -	.priority = 100,
> -};
> -
>  int kgdb_register_fiq(unsigned int fiq)
>  {
>  	static struct fiq_handler kgdb_fiq_desc = { .name = "kgdb", };
> @@ -357,7 +353,6 @@ int kgdb_register_fiq(unsigned int fiq)
>  	}
> 
>  	kgdb_fiq = fiq;
> -	register_fiq_nmi_notifier(&kgdb_fiq_notifier);
> 
>  	return 0;
>  }
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index bda5a91..8821160 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -502,13 +502,17 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
>  /*
>   * Fully acknowledge (both ack and eoi) a FIQ-based IPI
>   */
> -static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
> -			   void *data)
> +void gic_handle_fiq_ipi(void)
>  {
>  	struct gic_chip_data *gic = &gic_data[0];
> -	void __iomem *cpu_base = gic_data_cpu_base(gic);
> +	void __iomem *cpu_base;
>  	unsigned long irqstat, irqnr;
> 
> +	if (!gic || !gic->fiq_enable)
> +		return;
> +
> +	cpu_base = gic_data_cpu_base(gic);
> +
>  	if (WARN_ON(!in_nmi()))
>  		return NOTIFY_BAD;
> 
> @@ -525,13 +529,6 @@ static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
> 
>  	return NOTIFY_OK;
>  }
> -
> -/*
> - * Notifier to ensure IPI FIQ is acknowledged correctly.
> - */
> -static struct notifier_block gic_fiq_ipi_notifier = {
> -	.notifier_call = gic_handle_fiq_ipi,
> -};
>  #else /* CONFIG_FIQ */
>  static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
>  				     int group) {}
> @@ -1250,10 +1247,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>  #ifdef CONFIG_SMP
>  		set_smp_cross_call(gic_raise_softirq);
>  		register_cpu_notifier(&gic_cpu_notifier);
> -#ifdef CONFIG_FIQ
> -		if (gic_data_fiq_enable(gic))
> -			register_fiq_nmi_notifier(&gic_fiq_ipi_notifier);
> -#endif
>  #endif
>  		set_handle_irq(gic_handle_irq);
>  	}
> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> index 45e2d8c..52a5676 100644
> --- a/include/linux/irqchip/arm-gic.h
> +++ b/include/linux/irqchip/arm-gic.h
> @@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops
>  {
>  	gic_routable_irq_domain_ops = ops;
>  }
> +
> +void gic_handle_fiq_ipi(void);
> +
>  #endif /* __ASSEMBLY */
>  #endif
> 
> 


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
@ 2014-09-02 14:23                             ` Paul E. McKenney
  0 siblings, 0 replies; 535+ messages in thread
From: Paul E. McKenney @ 2014-09-02 14:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 02, 2014 at 12:49:16PM +0100, Daniel Thompson wrote:
> On 28/08/14 16:01, Russell King - ARM Linux wrote:
> > On Tue, Aug 19, 2014 at 07:12:07PM +0100, Daniel Thompson wrote:
> >> On 19/08/14 18:37, Russell King - ARM Linux wrote:
> >>> On Tue, Aug 19, 2014 at 05:45:53PM +0100, Daniel Thompson wrote:
> >>>> +int register_fiq_nmi_notifier(struct notifier_block *nb)
> >>>> +{
> >>>> +	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
> >>>> +}
> >>>> +
> >>>> +asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
> >>>> +{
> >>>> +	struct pt_regs *old_regs = set_irq_regs(regs);
> >>>> +
> >>>> +	nmi_enter();
> >>>> +	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
> >>>> +	nmi_exit();
> >>>> +	set_irq_regs(old_regs);
> >>>> +}
> >>>
> >>> Really not happy with this.  What happens if a FIQ occurs while we're
> >>> inside register_fiq_nmi_notifier() - more specifically inside
> >>> atomic_notifier_chain_register() ?
> >>
> >> Should depend on which side of the rcu update we're on.
> > 
> > I just asked Paul McKenney, our RCU expert... essentially, yes, RCU
> > stuff itself is safe in this context.  However, RCU stuff can call into
> > lockdep if lockdep is configured, and there are questions over lockdep.
> > 
> > There's some things which can be done to reduce the lockdep exposure
> > to it, such as ensuring that rcu_read_lock() is first called outside
> > of FIQ context.
> > 
> > There's concerns with whether either printk() in check_flags() could
> > be reached too (flags there should always indicate that IRQs were
> > disabled, so that reduces down to a question about just the first
> > printk() there.)
> > 
> > There's also the very_verbose() stuff for RCU lockdep classes which
> > Paul says must not be enabled.
> > 
> > Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
> > lockdep doing the deadlock checking as a result of the above call.
> > 
> > So... this coupled with my feeling that notifiers make it too easy for
> > unreviewed code to be hooked into this path, I'm fairly sure that we
> > don't want to be calling atomic notifier chains from FIQ context.
> 
> Having esablished (elsewhere in the thread) that RCU usage is safe
> from FIQ I have been working on the assumption that your feeling
> regarding unreviewed code is sufficient on its own to avoid using
> notifiers (and also to avoid a list of function pointers like on x86).

There was a later clarification from a lockdep expert showing that the
code was in fact safe, so the notifier approach should be just fine.

							Thanx, Paul

> Therefore I have made the changes requested and produced a
> before/after patch to show the impact of this. I will merge this
> into the FIQ patchset shortly (I need to run a few more build tests
> first).
> 
> Personally I still favour using notifiers and think the coupling below is
> excessive. Nevertheless I've run a couple of basic tests on the code
> below and it works fine.
> 
> 
> diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
> index 175bfed..a25c952 100644
> --- a/arch/arm/include/asm/fiq.h
> +++ b/arch/arm/include/asm/fiq.h
> @@ -54,7 +54,6 @@ extern void disable_fiq(int fiq);
>  extern int ack_fiq(int fiq);
>  extern void eoi_fiq(int fiq);
>  extern bool has_fiq(int fiq);
> -extern int register_fiq_nmi_notifier(struct notifier_block *nb);
>  extern void fiq_register_mapping(int irq, struct fiq_chip *chip);
> 
>  /* helpers defined in fiqasm.S: */
> diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
> index 6563da0..cb5ccd6 100644
> --- a/arch/arm/include/asm/kgdb.h
> +++ b/arch/arm/include/asm/kgdb.h
> @@ -51,6 +51,7 @@ extern void kgdb_handle_bus_error(void);
>  extern int kgdb_fault_expected;
> 
>  extern int kgdb_register_fiq(unsigned int fiq);
> +extern void kgdb_handle_fiq(struct pt_regs *regs);
> 
>  #endif /* !__ASSEMBLY__ */
> 
> diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
> index b2bd1c7..7422b58 100644
> --- a/arch/arm/kernel/fiq.c
> +++ b/arch/arm/kernel/fiq.c
> @@ -43,12 +43,14 @@
>  #include <linux/irq.h>
>  #include <linux/radix-tree.h>
>  #include <linux/slab.h>
> +#include <linux/irqchip/arm-gic.h>
> 
>  #include <asm/cacheflush.h>
>  #include <asm/cp15.h>
>  #include <asm/exception.h>
>  #include <asm/fiq.h>
>  #include <asm/irq.h>
> +#include <asm/kgdb.h>
>  #include <asm/traps.h>
> 
>  #define FIQ_OFFSET ({					\
> @@ -65,7 +67,6 @@ static unsigned long no_fiq_insn;
>  static int fiq_start = -1;
>  static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
>  static DEFINE_MUTEX(fiq_data_mutex);
> -static ATOMIC_NOTIFIER_HEAD(fiq_nmi_chain);
> 
>  /* Default reacquire function
>   * - we always relinquish FIQ control
> @@ -218,17 +219,23 @@ bool has_fiq(int fiq)
>  }
>  EXPORT_SYMBOL(has_fiq);
> 
> -int register_fiq_nmi_notifier(struct notifier_block *nb)
> -{
> -	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
> -}
> -
>  asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs)
>  {
>  	struct pt_regs *old_regs = set_irq_regs(regs);
> 
>  	nmi_enter();
> -	atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL);
> +
> +	/* these callbacks deliberately avoid using a notifier chain in
> +	 * order to ensure code review happens (drivers cannot "secretly"
> +	 * employ FIQ without modifying this chain of calls).
> +	 */
> +#ifdef CONFIG_KGDB_FIQ
> +	kgdb_handle_fiq(regs);
> +#endif
> +#ifdef CONFIG_ARM_GIC
> +	gic_handle_fiq_ipi();
> +#endif
> +
>  	nmi_exit();
>  	set_irq_regs(old_regs);
>  }
> diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
> index b77b885..630a3ef 100644
> --- a/arch/arm/kernel/kgdb.c
> +++ b/arch/arm/kernel/kgdb.c
> @@ -312,12 +312,13 @@ struct kgdb_arch arch_kgdb_ops = {
>  };
> 
>  #ifdef CONFIG_KGDB_FIQ
> -static int kgdb_handle_fiq(struct notifier_block *nb, unsigned long arg,
> -			   void *data)
> +void kgdb_handle_fiq(struct pt_regs *regs)
>  {
> -	struct pt_regs *regs = (void *) arg;
>  	int actual;
> 
> +	if (!kgdb_fiq)
> +		return;
> +
>  	if (!kgdb_nmicallback(raw_smp_processor_id(), regs))
>  		return NOTIFY_OK;
> 
> @@ -333,11 +334,6 @@ static int kgdb_handle_fiq(struct notifier_block *nb, unsigned long arg,
>  	return NOTIFY_OK;
>  }
> 
> -static struct notifier_block kgdb_fiq_notifier = {
> -	.notifier_call = kgdb_handle_fiq,
> -	.priority = 100,
> -};
> -
>  int kgdb_register_fiq(unsigned int fiq)
>  {
>  	static struct fiq_handler kgdb_fiq_desc = { .name = "kgdb", };
> @@ -357,7 +353,6 @@ int kgdb_register_fiq(unsigned int fiq)
>  	}
> 
>  	kgdb_fiq = fiq;
> -	register_fiq_nmi_notifier(&kgdb_fiq_notifier);
> 
>  	return 0;
>  }
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index bda5a91..8821160 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -502,13 +502,17 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
>  /*
>   * Fully acknowledge (both ack and eoi) a FIQ-based IPI
>   */
> -static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
> -			   void *data)
> +void gic_handle_fiq_ipi(void)
>  {
>  	struct gic_chip_data *gic = &gic_data[0];
> -	void __iomem *cpu_base = gic_data_cpu_base(gic);
> +	void __iomem *cpu_base;
>  	unsigned long irqstat, irqnr;
> 
> +	if (!gic || !gic->fiq_enable)
> +		return;
> +
> +	cpu_base = gic_data_cpu_base(gic);
> +
>  	if (WARN_ON(!in_nmi()))
>  		return NOTIFY_BAD;
> 
> @@ -525,13 +529,6 @@ static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
> 
>  	return NOTIFY_OK;
>  }
> -
> -/*
> - * Notifier to ensure IPI FIQ is acknowledged correctly.
> - */
> -static struct notifier_block gic_fiq_ipi_notifier = {
> -	.notifier_call = gic_handle_fiq_ipi,
> -};
>  #else /* CONFIG_FIQ */
>  static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
>  				     int group) {}
> @@ -1250,10 +1247,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>  #ifdef CONFIG_SMP
>  		set_smp_cross_call(gic_raise_softirq);
>  		register_cpu_notifier(&gic_cpu_notifier);
> -#ifdef CONFIG_FIQ
> -		if (gic_data_fiq_enable(gic))
> -			register_fiq_nmi_notifier(&gic_fiq_ipi_notifier);
> -#endif
>  #endif
>  		set_handle_irq(gic_handle_irq);
>  	}
> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> index 45e2d8c..52a5676 100644
> --- a/include/linux/irqchip/arm-gic.h
> +++ b/include/linux/irqchip/arm-gic.h
> @@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops
>  {
>  	gic_routable_irq_domain_ops = ops;
>  }
> +
> +void gic_handle_fiq_ipi(void);
> +
>  #endif /* __ASSEMBLY */
>  #endif
> 
> 

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
  2014-09-02 11:49                           ` Daniel Thompson
@ 2014-09-02 16:42                             ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-02 16:42 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Paul E. McKenney, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

On Tue, Sep 02, 2014 at 12:49:16PM +0100, Daniel Thompson wrote:
> On 28/08/14 16:01, Russell King - ARM Linux wrote:
> > I just asked Paul McKenney, our RCU expert... essentially, yes, RCU
> > stuff itself is safe in this context.  However, RCU stuff can call into
> > lockdep if lockdep is configured, and there are questions over lockdep.
> > 
> > There's some things which can be done to reduce the lockdep exposure
> > to it, such as ensuring that rcu_read_lock() is first called outside
> > of FIQ context.
> > 
> > There's concerns with whether either printk() in check_flags() could
> > be reached too (flags there should always indicate that IRQs were
> > disabled, so that reduces down to a question about just the first
> > printk() there.)
> > 
> > There's also the very_verbose() stuff for RCU lockdep classes which
> > Paul says must not be enabled.
> > 
> > Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
> > lockdep doing the deadlock checking as a result of the above call.
> > 
> > So... this coupled with my feeling that notifiers make it too easy for
> > unreviewed code to be hooked into this path, I'm fairly sure that we
> > don't want to be calling atomic notifier chains from FIQ context.
> 
> Having esablished (elsewhere in the thread) that RCU usage is safe
> from FIQ I have been working on the assumption that your feeling
> regarding unreviewed code is sufficient on its own to avoid using
> notifiers (and also to avoid a list of function pointers like on x86).

Yes, it does, because unlike the x86 community, we have a wide range
of platforms, and platform code does not go through the same path or
get the same review as core ARM code.

As I already pointed out, with a notifier, it's very easy to sneak
something into the FIQ path by submitting a patch for platform code
which calls the registration function.  That's going to be pretty
difficult to spot amongst the 3000+ messages on the linux-arm-kernel
list each month in order to give it the review that it would need.
That's especially true as I now ignore almost all most platform
code patches as we have Arnd and Olof to look at that.

So, unless you can come up with a proposal which ensures that there
is sufficient review triggered when someone decides to call the
notifier registration function...

How about something like:

static const char *allowable_callers[] = {
	...
};

	snprintf(caller, sizeof(caller), "%pf", __builtin_return_address(0));

	for (i = 0; i < ARRAY_SIZE(allowable_callers); i++)
		if (!strcmp(caller, allowable_callers[i]))
			break;

	if (i == ARRAY_SIZE(allowable_callers)) {
		printk(KERN_ERR "%s is not permitted to register a FIQ notifer\n",
			caller);
		return;
	}

This gives us the advantage of using the notifier, but also gives us the
requirement that the file has to be modified to permit new registrations,
thereby triggering the closer review.

The other question I have is that if we permit kgdb and nmi tracing with
this mechanism, how do the hooked callers distinguish between these
different purposes?  I don't see how that works with your notifier
setup.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
@ 2014-09-02 16:42                             ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-02 16:42 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 02, 2014 at 12:49:16PM +0100, Daniel Thompson wrote:
> On 28/08/14 16:01, Russell King - ARM Linux wrote:
> > I just asked Paul McKenney, our RCU expert... essentially, yes, RCU
> > stuff itself is safe in this context.  However, RCU stuff can call into
> > lockdep if lockdep is configured, and there are questions over lockdep.
> > 
> > There's some things which can be done to reduce the lockdep exposure
> > to it, such as ensuring that rcu_read_lock() is first called outside
> > of FIQ context.
> > 
> > There's concerns with whether either printk() in check_flags() could
> > be reached too (flags there should always indicate that IRQs were
> > disabled, so that reduces down to a question about just the first
> > printk() there.)
> > 
> > There's also the very_verbose() stuff for RCU lockdep classes which
> > Paul says must not be enabled.
> > 
> > Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
> > lockdep doing the deadlock checking as a result of the above call.
> > 
> > So... this coupled with my feeling that notifiers make it too easy for
> > unreviewed code to be hooked into this path, I'm fairly sure that we
> > don't want to be calling atomic notifier chains from FIQ context.
> 
> Having esablished (elsewhere in the thread) that RCU usage is safe
> from FIQ I have been working on the assumption that your feeling
> regarding unreviewed code is sufficient on its own to avoid using
> notifiers (and also to avoid a list of function pointers like on x86).

Yes, it does, because unlike the x86 community, we have a wide range
of platforms, and platform code does not go through the same path or
get the same review as core ARM code.

As I already pointed out, with a notifier, it's very easy to sneak
something into the FIQ path by submitting a patch for platform code
which calls the registration function.  That's going to be pretty
difficult to spot amongst the 3000+ messages on the linux-arm-kernel
list each month in order to give it the review that it would need.
That's especially true as I now ignore almost all most platform
code patches as we have Arnd and Olof to look at that.

So, unless you can come up with a proposal which ensures that there
is sufficient review triggered when someone decides to call the
notifier registration function...

How about something like:

static const char *allowable_callers[] = {
	...
};

	snprintf(caller, sizeof(caller), "%pf", __builtin_return_address(0));

	for (i = 0; i < ARRAY_SIZE(allowable_callers); i++)
		if (!strcmp(caller, allowable_callers[i]))
			break;

	if (i == ARRAY_SIZE(allowable_callers)) {
		printk(KERN_ERR "%s is not permitted to register a FIQ notifer\n",
			caller);
		return;
	}

This gives us the advantage of using the notifier, but also gives us the
requirement that the file has to be modified to permit new registrations,
thereby triggering the closer review.

The other question I have is that if we permit kgdb and nmi tracing with
this mechanism, how do the hooked callers distinguish between these
different purposes?  I don't see how that works with your notifier
setup.

-- 
FTTC broadband for 0.8mile line: currently@9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v11 01/19] arm: fiq: Add callbacks to manage FIQ routings
  2014-09-02 13:00                     ` Daniel Thompson
@ 2014-09-02 18:51                       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-02 18:51 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: linux-kernel, linux-arm-kernel, kgdb-bugreport, patches,
	linaro-kernel, John Stultz, Anton Vorontsov, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

On Tue, Sep 02, 2014 at 02:00:35PM +0100, Daniel Thompson wrote:
>  void enable_fiq(int fiq)
>  {
> +	struct fiq_data *data = lookup_fiq_data(fiq);
> +
> +	if (data) {
> +		if (data->fiq_chip->fiq_enable)
> +			data->fiq_chip->fiq_enable(data->irq_data);
> +		enable_irq(fiq);

Why do we call the FIQ chip's enable and enable_irq() as well?

>  void disable_fiq(int fiq)
>  {
> +	struct fiq_data *data = lookup_fiq_data(fiq);
> +
> +	if (data) {
> +		if (data->fiq_chip->fiq_disable)
> +			data->fiq_chip->fiq_disable(data->irq_data);
> +		disable_irq(fiq);

Same question here.

> +bool has_fiq(int fiq)
> +{
> +	struct fiq_data *data = lookup_fiq_data(fiq);
> +
> +	if (data)
> +		return true;
> +
> +	if (fiq_start == -1)
> +		return false;
> +
> +	return fiq >= fiq_start;

Are you sure this is correct... it looks wrong to me.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v11 01/19] arm: fiq: Add callbacks to manage FIQ routings
@ 2014-09-02 18:51                       ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-02 18:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 02, 2014 at 02:00:35PM +0100, Daniel Thompson wrote:
>  void enable_fiq(int fiq)
>  {
> +	struct fiq_data *data = lookup_fiq_data(fiq);
> +
> +	if (data) {
> +		if (data->fiq_chip->fiq_enable)
> +			data->fiq_chip->fiq_enable(data->irq_data);
> +		enable_irq(fiq);

Why do we call the FIQ chip's enable and enable_irq() as well?

>  void disable_fiq(int fiq)
>  {
> +	struct fiq_data *data = lookup_fiq_data(fiq);
> +
> +	if (data) {
> +		if (data->fiq_chip->fiq_disable)
> +			data->fiq_chip->fiq_disable(data->irq_data);
> +		disable_irq(fiq);

Same question here.

> +bool has_fiq(int fiq)
> +{
> +	struct fiq_data *data = lookup_fiq_data(fiq);
> +
> +	if (data)
> +		return true;
> +
> +	if (fiq_start == -1)
> +		return false;
> +
> +	return fiq >= fiq_start;

Are you sure this is correct... it looks wrong to me.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v11 06/19] irqchip: gic: Provide support for interrupt grouping
  2014-09-02 13:00                     ` Daniel Thompson
@ 2014-09-02 19:33                       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-02 19:33 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: linux-kernel, linux-arm-kernel, kgdb-bugreport, patches,
	linaro-kernel, John Stultz, Anton Vorontsov, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Thomas Gleixner, Jason Cooper, Nicolas Pitre,
	Christoffer Dall, Sricharan R, Marc Zyngier

On Tue, Sep 02, 2014 at 02:00:40PM +0100, Daniel Thompson wrote:
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index 4b959e6..423707c 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -41,6 +41,9 @@
>  #include <linux/irqchip/arm-gic.h>
>  
>  #include <asm/cputype.h>
> +#ifdef CONFIG_FIQ
> +#include <asm/fiq.h>
> +#endif

Is there much advantage to this ifdef over providing a dummy asm/fiq.h
in ARM64?

>  #include <asm/irq.h>
>  #include <asm/exception.h>
>  #include <asm/smp_plat.h>
> @@ -68,6 +71,9 @@ struct gic_chip_data {
>  #ifdef CONFIG_GIC_NON_BANKED
>  	void __iomem *(*get_base)(union gic_base *);
>  #endif
> +#ifdef CONFIG_FIQ
> +	bool fiq_enable;
> +#endif
>  };
>  
>  static DEFINE_RAW_SPINLOCK(irq_controller_lock);
> @@ -131,6 +137,16 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data,
>  #define gic_set_base_accessor(d, f)
>  #endif
>  
> +#ifdef CONFIG_FIQ
> +static inline bool gic_data_fiq_enable(struct gic_chip_data *data)
> +{
> +	return data->fiq_enable;
> +}
> +#else
> +static inline bool gic_data_fiq_enable(
> +		struct gic_chip_data *data) { return false; }

I really hate this style.  Just lay it out as a normal function.

> +	/*
> +	 * If grouping is not available (not implemented or prohibited by
> +	 * security mode) these registers a read-as-zero/write-ignored.
> +	 * However as a precaution we restore the reset default regardless of
> +	 * the result of the test.
> +	 */

Have we found that this additional complexity is actually necessary?
If not, we're over-engineering the code, making it more complex (and
hence more likely to be buggy) for very little reason.

Last night, I booted an unconditional version of this on OMAP3430, and
OMAP4430.  It's also been booted on the range of iMX6 CPUs.  Nothing
here has shown any signs of problems to having these registers written.

> +	/*
> +	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
> +	 * bit 1 ignored)
> +	 */
> +	if (gic_data_fiq_enable(gic))
> +		writel_relaxed(3, base + GIC_DIST_CTRL);
> +	else
> +		writel_relaxed(1, base + GIC_DIST_CTRL);

If we are going to do this conditionally, and the only thing which
is variable is the value to be written, I much prefer the conditional
bit to be on the value and not the write.  The compiler doesn't always
optimise these things very well.  So:

	writel_relaxed(gic_data_fiq_enable(gic) ? 3 : 1, base + GIC_DIST_CTRL);

works well enough for me.  If you feel better by using a temporary
local, that works for me too.

> +	if (gic_data_fiq_enable(gic))
> +		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
> +	else
> +		writel_relaxed(1, base + GIC_CPU_CTRL);

Same here.

> @@ -485,7 +564,10 @@ static void gic_dist_restore(unsigned int gic_nr)
>  		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
>  			dist_base + GIC_DIST_ENABLE_SET + i * 4);
>  
> -	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
> +	if (gic_data_fiq_enable(&gic_data[gic_nr]))
> +		writel_relaxed(3, dist_base + GIC_DIST_CTRL);
> +	else
> +		writel_relaxed(1, dist_base + GIC_DIST_CTRL);

And here.

> @@ -542,7 +624,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
>  		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
>  
>  	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
> -	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
> +	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);

Interestingly, here you write 0x1f unconditionally.
>  }
>  
>  static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
> @@ -604,6 +686,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
>  {
>  	int cpu;
>  	unsigned long flags, map = 0;
> +	unsigned long softint;
>  
>  	raw_spin_lock_irqsave(&irq_controller_lock, flags);
>  
> @@ -618,7 +701,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
>  	dmb(ishst);
>  
>  	/* this always happens on GIC0 */
> -	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
> +	softint = map << 16 | irq;
> +	if (gic_data_fiq_enable(&gic_data[0]))
> +		softint |= 0x8000;

I guess that this always has to be done conditionally.  I'd prefer this
test to be done slightly differently (and we might as well wrap in a bit
of patch 9 here):

	if (sgi_is_nonsecure(irq, &gic_data[0]))
		softint |= 0x8000;

which follows the true purpose of that bit.  This bit only has effect if
we are running in secure mode, where it must match the status of the
target interrupt (as programmed into GIC_DIST_IGROUP).

We probably should do this based on a bitmask of SGIs in the
gic_chip_data, which is initialised according to how we've been able
to setup the GIC_DIST_IGROUP register(s).

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v11 06/19] irqchip: gic: Provide support for interrupt grouping
@ 2014-09-02 19:33                       ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-02 19:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 02, 2014 at 02:00:40PM +0100, Daniel Thompson wrote:
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index 4b959e6..423707c 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -41,6 +41,9 @@
>  #include <linux/irqchip/arm-gic.h>
>  
>  #include <asm/cputype.h>
> +#ifdef CONFIG_FIQ
> +#include <asm/fiq.h>
> +#endif

Is there much advantage to this ifdef over providing a dummy asm/fiq.h
in ARM64?

>  #include <asm/irq.h>
>  #include <asm/exception.h>
>  #include <asm/smp_plat.h>
> @@ -68,6 +71,9 @@ struct gic_chip_data {
>  #ifdef CONFIG_GIC_NON_BANKED
>  	void __iomem *(*get_base)(union gic_base *);
>  #endif
> +#ifdef CONFIG_FIQ
> +	bool fiq_enable;
> +#endif
>  };
>  
>  static DEFINE_RAW_SPINLOCK(irq_controller_lock);
> @@ -131,6 +137,16 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data,
>  #define gic_set_base_accessor(d, f)
>  #endif
>  
> +#ifdef CONFIG_FIQ
> +static inline bool gic_data_fiq_enable(struct gic_chip_data *data)
> +{
> +	return data->fiq_enable;
> +}
> +#else
> +static inline bool gic_data_fiq_enable(
> +		struct gic_chip_data *data) { return false; }

I really hate this style.  Just lay it out as a normal function.

> +	/*
> +	 * If grouping is not available (not implemented or prohibited by
> +	 * security mode) these registers a read-as-zero/write-ignored.
> +	 * However as a precaution we restore the reset default regardless of
> +	 * the result of the test.
> +	 */

Have we found that this additional complexity is actually necessary?
If not, we're over-engineering the code, making it more complex (and
hence more likely to be buggy) for very little reason.

Last night, I booted an unconditional version of this on OMAP3430, and
OMAP4430.  It's also been booted on the range of iMX6 CPUs.  Nothing
here has shown any signs of problems to having these registers written.

> +	/*
> +	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
> +	 * bit 1 ignored)
> +	 */
> +	if (gic_data_fiq_enable(gic))
> +		writel_relaxed(3, base + GIC_DIST_CTRL);
> +	else
> +		writel_relaxed(1, base + GIC_DIST_CTRL);

If we are going to do this conditionally, and the only thing which
is variable is the value to be written, I much prefer the conditional
bit to be on the value and not the write.  The compiler doesn't always
optimise these things very well.  So:

	writel_relaxed(gic_data_fiq_enable(gic) ? 3 : 1, base + GIC_DIST_CTRL);

works well enough for me.  If you feel better by using a temporary
local, that works for me too.

> +	if (gic_data_fiq_enable(gic))
> +		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
> +	else
> +		writel_relaxed(1, base + GIC_CPU_CTRL);

Same here.

> @@ -485,7 +564,10 @@ static void gic_dist_restore(unsigned int gic_nr)
>  		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
>  			dist_base + GIC_DIST_ENABLE_SET + i * 4);
>  
> -	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
> +	if (gic_data_fiq_enable(&gic_data[gic_nr]))
> +		writel_relaxed(3, dist_base + GIC_DIST_CTRL);
> +	else
> +		writel_relaxed(1, dist_base + GIC_DIST_CTRL);

And here.

> @@ -542,7 +624,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
>  		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
>  
>  	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
> -	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
> +	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);

Interestingly, here you write 0x1f unconditionally.
>  }
>  
>  static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
> @@ -604,6 +686,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
>  {
>  	int cpu;
>  	unsigned long flags, map = 0;
> +	unsigned long softint;
>  
>  	raw_spin_lock_irqsave(&irq_controller_lock, flags);
>  
> @@ -618,7 +701,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
>  	dmb(ishst);
>  
>  	/* this always happens on GIC0 */
> -	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
> +	softint = map << 16 | irq;
> +	if (gic_data_fiq_enable(&gic_data[0]))
> +		softint |= 0x8000;

I guess that this always has to be done conditionally.  I'd prefer this
test to be done slightly differently (and we might as well wrap in a bit
of patch 9 here):

	if (sgi_is_nonsecure(irq, &gic_data[0]))
		softint |= 0x8000;

which follows the true purpose of that bit.  This bit only has effect if
we are running in secure mode, where it must match the status of the
target interrupt (as programmed into GIC_DIST_IGROUP).

We probably should do this based on a bitmask of SGIs in the
gic_chip_data, which is initialised according to how we've been able
to setup the GIC_DIST_IGROUP register(s).

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v11 07/19] irqchip: gic: Add support for FIQ management
  2014-09-02 13:00                     ` Daniel Thompson
@ 2014-09-02 19:36                       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-02 19:36 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: linux-kernel, linux-arm-kernel, kgdb-bugreport, patches,
	linaro-kernel, John Stultz, Anton Vorontsov, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Thomas Gleixner, Jason Cooper, Nicolas Pitre,
	Christoffer Dall, Sricharan R

On Tue, Sep 02, 2014 at 02:00:41PM +0100, Daniel Thompson wrote:
> +static void gic_enable_fiq(struct irq_data *d)
> +{
> +	gic_set_group_irq(d, 0);
> +}
> +
> +static void gic_disable_fiq(struct irq_data *d)
> +{
> +	gic_set_group_irq(d, 1);
> +}

I think both the above functions should also call gic_unmask_irq() and
gic_mask_irq() directly rather than looping through enable_irq()/
disable_irq().

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v11 07/19] irqchip: gic: Add support for FIQ management
@ 2014-09-02 19:36                       ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-02 19:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 02, 2014 at 02:00:41PM +0100, Daniel Thompson wrote:
> +static void gic_enable_fiq(struct irq_data *d)
> +{
> +	gic_set_group_irq(d, 0);
> +}
> +
> +static void gic_disable_fiq(struct irq_data *d)
> +{
> +	gic_set_group_irq(d, 1);
> +}

I think both the above functions should also call gic_unmask_irq() and
gic_mask_irq() directly rather than looping through enable_irq()/
disable_irq().

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v11 11/19] irqchip: vic: Add support for FIQ management
  2014-09-02 13:00                     ` Daniel Thompson
@ 2014-09-02 19:40                       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-02 19:40 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: linux-kernel, linux-arm-kernel, kgdb-bugreport, patches,
	linaro-kernel, John Stultz, Anton Vorontsov, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Hartley Sweeten, Ryan Mallon, Ben Dooks,
	Kukjin Kim, Thomas Gleixner, Jason Cooper, linux-samsung-soc

On Tue, Sep 02, 2014 at 02:00:45PM +0100, Daniel Thompson wrote:
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index bda5a91..8821160 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -502,13 +502,17 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
>  /*
>   * Fully acknowledge (both ack and eoi) a FIQ-based IPI
>   */
> -static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
> -			   void *data)
> +void gic_handle_fiq_ipi(void)
>  {
>  	struct gic_chip_data *gic = &gic_data[0];
> -	void __iomem *cpu_base = gic_data_cpu_base(gic);
> +	void __iomem *cpu_base;
>  	unsigned long irqstat, irqnr;
>  
> +	if (!gic || !gic->fiq_enable)
> +		return;
> +
> +	cpu_base = gic_data_cpu_base(gic);
> +
>  	if (WARN_ON(!in_nmi()))
>  		return NOTIFY_BAD;
>  
> @@ -525,13 +529,6 @@ static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
>  
>  	return NOTIFY_OK;
>  }
> -
> -/*
> - * Notifier to ensure IPI FIQ is acknowledged correctly.
> - */
> -static struct notifier_block gic_fiq_ipi_notifier = {
> -	.notifier_call = gic_handle_fiq_ipi,
> -};
>  #else /* CONFIG_FIQ */
>  static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
>  				     int group) {}
> @@ -1250,10 +1247,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>  #ifdef CONFIG_SMP
>  		set_smp_cross_call(gic_raise_softirq);
>  		register_cpu_notifier(&gic_cpu_notifier);
> -#ifdef CONFIG_FIQ
> -		if (gic_data_fiq_enable(gic))
> -			register_fiq_nmi_notifier(&gic_fiq_ipi_notifier);
> -#endif
>  #endif
>  		set_handle_irq(gic_handle_irq);
>  	}

Shouldn't this be merged into some other patch?

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v11 11/19] irqchip: vic: Add support for FIQ management
@ 2014-09-02 19:40                       ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-02 19:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 02, 2014 at 02:00:45PM +0100, Daniel Thompson wrote:
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index bda5a91..8821160 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -502,13 +502,17 @@ static void __init gic_init_fiq(struct gic_chip_data *gic,
>  /*
>   * Fully acknowledge (both ack and eoi) a FIQ-based IPI
>   */
> -static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
> -			   void *data)
> +void gic_handle_fiq_ipi(void)
>  {
>  	struct gic_chip_data *gic = &gic_data[0];
> -	void __iomem *cpu_base = gic_data_cpu_base(gic);
> +	void __iomem *cpu_base;
>  	unsigned long irqstat, irqnr;
>  
> +	if (!gic || !gic->fiq_enable)
> +		return;
> +
> +	cpu_base = gic_data_cpu_base(gic);
> +
>  	if (WARN_ON(!in_nmi()))
>  		return NOTIFY_BAD;
>  
> @@ -525,13 +529,6 @@ static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs,
>  
>  	return NOTIFY_OK;
>  }
> -
> -/*
> - * Notifier to ensure IPI FIQ is acknowledged correctly.
> - */
> -static struct notifier_block gic_fiq_ipi_notifier = {
> -	.notifier_call = gic_handle_fiq_ipi,
> -};
>  #else /* CONFIG_FIQ */
>  static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
>  				     int group) {}
> @@ -1250,10 +1247,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>  #ifdef CONFIG_SMP
>  		set_smp_cross_call(gic_raise_softirq);
>  		register_cpu_notifier(&gic_cpu_notifier);
> -#ifdef CONFIG_FIQ
> -		if (gic_data_fiq_enable(gic))
> -			register_fiq_nmi_notifier(&gic_fiq_ipi_notifier);
> -#endif
>  #endif
>  		set_handle_irq(gic_handle_irq);
>  	}

Shouldn't this be merged into some other patch?

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v11 06/19] irqchip: gic: Provide support for interrupt grouping
  2014-09-02 19:33                       ` Russell King - ARM Linux
@ 2014-09-02 21:36                         ` Catalin Marinas
  -1 siblings, 0 replies; 535+ messages in thread
From: Catalin Marinas @ 2014-09-02 21:36 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Dave P Martin, Fabio Estevam, Frederic Weisbecker, Nicolas Pitre,
	Thomas Gleixner, Jason Cooper, Nicolas Pitre, Christoffer Dall,
	Sricharan R, Marc Zyngier

On 2 Sep 2014, at 20:33, Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:
> On Tue, Sep 02, 2014 at 02:00:40PM +0100, Daniel Thompson wrote:
>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>> index 4b959e6..423707c 100644
>> --- a/drivers/irqchip/irq-gic.c
>> +++ b/drivers/irqchip/irq-gic.c
>> @@ -41,6 +41,9 @@
>> #include <linux/irqchip/arm-gic.h>
>> 
>> #include <asm/cputype.h>
>> +#ifdef CONFIG_FIQ
>> +#include <asm/fiq.h>
>> +#endif
> 
> Is there much advantage to this ifdef over providing a dummy asm/fiq.h
> in ARM64?

While it’s unlikely we’ll use FIQs on arm64 (they are generally
reserved for the secure world/firmware), I don’t mind an empty
asm/fiq.h file.

Catalin

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v11 06/19] irqchip: gic: Provide support for interrupt grouping
@ 2014-09-02 21:36                         ` Catalin Marinas
  0 siblings, 0 replies; 535+ messages in thread
From: Catalin Marinas @ 2014-09-02 21:36 UTC (permalink / raw)
  To: linux-arm-kernel

On 2 Sep 2014, at 20:33, Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:
> On Tue, Sep 02, 2014 at 02:00:40PM +0100, Daniel Thompson wrote:
>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>> index 4b959e6..423707c 100644
>> --- a/drivers/irqchip/irq-gic.c
>> +++ b/drivers/irqchip/irq-gic.c
>> @@ -41,6 +41,9 @@
>> #include <linux/irqchip/arm-gic.h>
>> 
>> #include <asm/cputype.h>
>> +#ifdef CONFIG_FIQ
>> +#include <asm/fiq.h>
>> +#endif
> 
> Is there much advantage to this ifdef over providing a dummy asm/fiq.h
> in ARM64?

While it?s unlikely we?ll use FIQs on arm64 (they are generally
reserved for the secure world/firmware), I don?t mind an empty
asm/fiq.h file.

Catalin

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v11 00/19] arm: KGDB NMI/FIQ support
  2014-09-02 13:00                   ` Daniel Thompson
@ 2014-09-02 23:02                     ` Thomas Gleixner
  -1 siblings, 0 replies; 535+ messages in thread
From: Thomas Gleixner @ 2014-09-02 23:02 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Russell King, linaro-kernel, Catalin Marinas, patches,
	kgdb-bugreport, Nicolas Pitre, linux-kernel, Frederic Weisbecker,
	Anton Vorontsov, Ben Dooks, Fabio Estevam, Colin Cross,
	kernel-team, Dave Martin, linux-arm-kernel

On Tue, 2 Sep 2014, Daniel Thompson wrote:

> This patchset makes it possible to use kgdb's NMI infrastructure on ARM
> platforms.
> 
> The patches are seperated into three distinct groups:
> 
> 1. arm specific changes; these provide multi-platform support for FIQ
>    (including raising an IPI using FIQ to ensure effective SMP support)
>    and extend ARM KGDB support to use the features provided.
> 
> 2. irqchip changes; updates to the gic and vic drivers to provide
>    support for routing certain interrupt sources to FIQ.
> 
> 3. serial changes; driver support to allow the UART interrupt to be
>    routed to FIQ. The already mainlined kgdb NMI infrastructure (mostly
>    found in drivers/tty/serial/kgdb_nmi.c) will re-route the kgdb
>    console UART's interrupt signal from IRQ to FIQ. Naturally the UART
>    will no longer function normally and will instead be managed by kgdb
>    using the polled I/O functions. Any character delivered to the UART
>    causes the kgdb handler function to be called.

To be honest, what you are doing is just ass backwards.

The use case you are looking for is the most irrelevant of all. Just
because KGDB is on some managerial "must have items" checklist does
not make it useful.

The only relevant use cases of FIQs are the same as those of NMIs on
x86:

  - Watchdog to detect stuck cpus and issue stack traces

  - Performace monitoring

KGDB falls into place once you solved the above.

That said for the general approach, I'll have a look at the irq
related patches in a minute.

Thanks,

	tglx


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v11 00/19] arm: KGDB NMI/FIQ support
@ 2014-09-02 23:02                     ` Thomas Gleixner
  0 siblings, 0 replies; 535+ messages in thread
From: Thomas Gleixner @ 2014-09-02 23:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2 Sep 2014, Daniel Thompson wrote:

> This patchset makes it possible to use kgdb's NMI infrastructure on ARM
> platforms.
> 
> The patches are seperated into three distinct groups:
> 
> 1. arm specific changes; these provide multi-platform support for FIQ
>    (including raising an IPI using FIQ to ensure effective SMP support)
>    and extend ARM KGDB support to use the features provided.
> 
> 2. irqchip changes; updates to the gic and vic drivers to provide
>    support for routing certain interrupt sources to FIQ.
> 
> 3. serial changes; driver support to allow the UART interrupt to be
>    routed to FIQ. The already mainlined kgdb NMI infrastructure (mostly
>    found in drivers/tty/serial/kgdb_nmi.c) will re-route the kgdb
>    console UART's interrupt signal from IRQ to FIQ. Naturally the UART
>    will no longer function normally and will instead be managed by kgdb
>    using the polled I/O functions. Any character delivered to the UART
>    causes the kgdb handler function to be called.

To be honest, what you are doing is just ass backwards.

The use case you are looking for is the most irrelevant of all. Just
because KGDB is on some managerial "must have items" checklist does
not make it useful.

The only relevant use cases of FIQs are the same as those of NMIs on
x86:

  - Watchdog to detect stuck cpus and issue stack traces

  - Performace monitoring

KGDB falls into place once you solved the above.

That said for the general approach, I'll have a look at the irq
related patches in a minute.

Thanks,

	tglx

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v11 01/19] arm: fiq: Add callbacks to manage FIQ routings
  2014-09-02 13:00                     ` Daniel Thompson
@ 2014-09-03  0:03                       ` Thomas Gleixner
  -1 siblings, 0 replies; 535+ messages in thread
From: Thomas Gleixner @ 2014-09-03  0:03 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Russell King, linaro-kernel, Catalin Marinas, patches,
	kgdb-bugreport, Nicolas Pitre, linux-kernel, Frederic Weisbecker,
	Anton Vorontsov, Ben Dooks, Fabio Estevam, Colin Cross,
	kernel-team, Dave Martin, linux-arm-kernel

On Tue, 2 Sep 2014, Daniel Thompson wrote:

> Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
> virq into a FIQ virq. This is too inflexible for multi-platform kernels
> and makes runtime error checking impossible.

You are missing to explain WHY it is too inflexible ....
 
> We solve this by introducing a flexible mapping that allows interrupt

Flexible in that context reads like random semantics. And that's
definitely nothing we want to see in the context of interrupts/fiqs

> controllers that support FIQ to register those mappings. This, in turn,
> makes it much possible for drivers in DT kernels to install FIQ handlers
> without knowing anything about the interrupt controller.

> +#include <linux/irq.h>
>  #include <asm/ptrace.h>
>  
> +struct fiq_chip {
> +	void (*fiq_enable)(struct irq_data *data);
> +	void (*fiq_disable)(struct irq_data *data);
> +};

So you define an ARM specific extension to the irq infrastructure
which is completely ignoring that there might be other architectures
which have the same issue?

Aside of that you define that structure w/o documenting in any way
what the semantics of the callbacks are and how struct irq_data is
supposed to be (ab)used there.

> +struct fiq_data {
> +	struct fiq_chip *fiq_chip;
> +	struct irq_data *irq_data;
> +};

Nice. Another completely undocumented data structure.

>  static unsigned long no_fiq_insn;
> +static int fiq_start = -1;
> +static RADIX_TREE(fiq_data_tree, GFP_KERNEL);

Along with a radix tree, which again lacks any form of documentation.

> -static int fiq_start;
> +static struct fiq_data *lookup_fiq_data(int fiq)
> +{
> +	struct fiq_data *data;
> +
> +	rcu_read_lock();
> +	data = radix_tree_lookup(&fiq_data_tree, fiq);
> +	rcu_read_unlock();
> +
> +	return data;

That makes a lot of sense. NOT!

What kind of protection is that rcu_read_lock/unlock pair providing
for the return value? Just that it has been valid at lookup time?

What protects against concurrent calls to the various usage sites
which shine by the lack of serialization ...

>  void enable_fiq(int fiq)
>  {
> +	struct fiq_data *data = lookup_fiq_data(fiq);
> +
> +	if (data) {
> +		if (data->fiq_chip->fiq_enable)
> +			data->fiq_chip->fiq_enable(data->irq_data);
> +		enable_irq(fiq);

This is ass backwards, really.

The FIQ target is a property of the interrupt line right?

So why the heck do you need a separate chip/data representation
including a radix tree and whatever? Just because you can?

What is wrong to tell the irq core code via a flag that a particular
interrupt should be targeted at FIQ instead of a regular interrupt?

Nothing as far as I can tell. And that would even allow to retarget an
already enabled interrupt to FIQ or vice versa.

So all your patch does is trying to (ab)use an existing interface
which was created in the last millenium for totally different reasons
and in a totally different context.

But you fail completely to understand what that interface is doing:

    It merily maps the Linux virq to a FIQ via an offset.

While I understand that this is not workable on multiplatform kernels,
I really cannot understand your attempt to change this by adding
complex functionality to a primitive offset mapping function.

You just add some randomly defined new chip/data combination which
abuses the irq_data structure under the hood instead of properly
integrating that irq chip property into irqchip/irqdata itself.

So instead of thinking about the properties of the hardware and
questioning the existing mechanism, you just bolt some crap onto it
and inflict a gazillion of pointless modifications to the irq chip
drivers without any value.

So all it needs is

 1) Adding a property flag to the irq chip which signals that it
    supports FIQ/NMI targets

 2) Adding a interface which allows to flag a particular interrupt
    line targeted to either the regular or the FIQ/NMI which consults
    the flag added by #1

 3) Let the chip driver deal with the target flag at a minimal
    intrusive level w/o registering racy callbacks designed in hell
    and imposing arch specific data structures, storage etc. for no
    value

Thanks,

	tglx


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v11 01/19] arm: fiq: Add callbacks to manage FIQ routings
@ 2014-09-03  0:03                       ` Thomas Gleixner
  0 siblings, 0 replies; 535+ messages in thread
From: Thomas Gleixner @ 2014-09-03  0:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2 Sep 2014, Daniel Thompson wrote:

> Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
> virq into a FIQ virq. This is too inflexible for multi-platform kernels
> and makes runtime error checking impossible.

You are missing to explain WHY it is too inflexible ....
 
> We solve this by introducing a flexible mapping that allows interrupt

Flexible in that context reads like random semantics. And that's
definitely nothing we want to see in the context of interrupts/fiqs

> controllers that support FIQ to register those mappings. This, in turn,
> makes it much possible for drivers in DT kernels to install FIQ handlers
> without knowing anything about the interrupt controller.

> +#include <linux/irq.h>
>  #include <asm/ptrace.h>
>  
> +struct fiq_chip {
> +	void (*fiq_enable)(struct irq_data *data);
> +	void (*fiq_disable)(struct irq_data *data);
> +};

So you define an ARM specific extension to the irq infrastructure
which is completely ignoring that there might be other architectures
which have the same issue?

Aside of that you define that structure w/o documenting in any way
what the semantics of the callbacks are and how struct irq_data is
supposed to be (ab)used there.

> +struct fiq_data {
> +	struct fiq_chip *fiq_chip;
> +	struct irq_data *irq_data;
> +};

Nice. Another completely undocumented data structure.

>  static unsigned long no_fiq_insn;
> +static int fiq_start = -1;
> +static RADIX_TREE(fiq_data_tree, GFP_KERNEL);

Along with a radix tree, which again lacks any form of documentation.

> -static int fiq_start;
> +static struct fiq_data *lookup_fiq_data(int fiq)
> +{
> +	struct fiq_data *data;
> +
> +	rcu_read_lock();
> +	data = radix_tree_lookup(&fiq_data_tree, fiq);
> +	rcu_read_unlock();
> +
> +	return data;

That makes a lot of sense. NOT!

What kind of protection is that rcu_read_lock/unlock pair providing
for the return value? Just that it has been valid at lookup time?

What protects against concurrent calls to the various usage sites
which shine by the lack of serialization ...

>  void enable_fiq(int fiq)
>  {
> +	struct fiq_data *data = lookup_fiq_data(fiq);
> +
> +	if (data) {
> +		if (data->fiq_chip->fiq_enable)
> +			data->fiq_chip->fiq_enable(data->irq_data);
> +		enable_irq(fiq);

This is ass backwards, really.

The FIQ target is a property of the interrupt line right?

So why the heck do you need a separate chip/data representation
including a radix tree and whatever? Just because you can?

What is wrong to tell the irq core code via a flag that a particular
interrupt should be targeted at FIQ instead of a regular interrupt?

Nothing as far as I can tell. And that would even allow to retarget an
already enabled interrupt to FIQ or vice versa.

So all your patch does is trying to (ab)use an existing interface
which was created in the last millenium for totally different reasons
and in a totally different context.

But you fail completely to understand what that interface is doing:

    It merily maps the Linux virq to a FIQ via an offset.

While I understand that this is not workable on multiplatform kernels,
I really cannot understand your attempt to change this by adding
complex functionality to a primitive offset mapping function.

You just add some randomly defined new chip/data combination which
abuses the irq_data structure under the hood instead of properly
integrating that irq chip property into irqchip/irqdata itself.

So instead of thinking about the properties of the hardware and
questioning the existing mechanism, you just bolt some crap onto it
and inflict a gazillion of pointless modifications to the irq chip
drivers without any value.

So all it needs is

 1) Adding a property flag to the irq chip which signals that it
    supports FIQ/NMI targets

 2) Adding a interface which allows to flag a particular interrupt
    line targeted to either the regular or the FIQ/NMI which consults
    the flag added by #1

 3) Let the chip driver deal with the target flag at a minimal
    intrusive level w/o registering racy callbacks designed in hell
    and imposing arch specific data structures, storage etc. for no
    value

Thanks,

	tglx

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v11 01/19] arm: fiq: Add callbacks to manage FIQ routings
  2014-09-03  0:03                       ` Thomas Gleixner
@ 2014-09-03  8:27                         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-03  8:27 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Russell King, linaro-kernel, Catalin Marinas, patches,
	kgdb-bugreport, Nicolas Pitre, linux-kernel, Frederic Weisbecker,
	Anton Vorontsov, Ben Dooks, Fabio Estevam, Colin Cross,
	kernel-team, Dave Martin, linux-arm-kernel

On 03/09/14 01:03, Thomas Gleixner wrote:
> On Tue, 2 Sep 2014, Daniel Thompson wrote:
> 
>> Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
>> virq into a FIQ virq. This is too inflexible for multi-platform kernels
>> and makes runtime error checking impossible.
> 
> You are missing to explain WHY it is too inflexible ....
>  
>> We solve this by introducing a flexible mapping that allows interrupt
> 
> Flexible in that context reads like random semantics. And that's
> definitely nothing we want to see in the context of interrupts/fiqs
> 
>> controllers that support FIQ to register those mappings. This, in turn,
>> makes it much possible for drivers in DT kernels to install FIQ handlers
>> without knowing anything about the interrupt controller.
> 
>> +#include <linux/irq.h>
>>  #include <asm/ptrace.h>
>>  
>> +struct fiq_chip {
>> +	void (*fiq_enable)(struct irq_data *data);
>> +	void (*fiq_disable)(struct irq_data *data);
>> +};
> 
> So you define an ARM specific extension to the irq infrastructure
> which is completely ignoring that there might be other architectures
> which have the same issue?
> 
> Aside of that you define that structure w/o documenting in any way
> what the semantics of the callbacks are and how struct irq_data is
> supposed to be (ab)used there.
> 
>> +struct fiq_data {
>> +	struct fiq_chip *fiq_chip;
>> +	struct irq_data *irq_data;
>> +};
> 
> Nice. Another completely undocumented data structure.
> 
>>  static unsigned long no_fiq_insn;
>> +static int fiq_start = -1;
>> +static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
> 
> Along with a radix tree, which again lacks any form of documentation.
> 
>> -static int fiq_start;
>> +static struct fiq_data *lookup_fiq_data(int fiq)
>> +{
>> +	struct fiq_data *data;
>> +
>> +	rcu_read_lock();
>> +	data = radix_tree_lookup(&fiq_data_tree, fiq);
>> +	rcu_read_unlock();
>> +
>> +	return data;
> 
> That makes a lot of sense. NOT!
> 
> What kind of protection is that rcu_read_lock/unlock pair providing
> for the return value? Just that it has been valid at lookup time?
> 
> What protects against concurrent calls to the various usage sites
> which shine by the lack of serialization ...

The locking here ought to safe because there is no means to unregister
fiq data (the two irqchip drivers I looked at has no need for that) so
once looked up the data will be valid.

Thus it's only purpose was to prevent incorrect traversals of the radix
tree.

That said, this doesn't make it right.


>>  void enable_fiq(int fiq)
>>  {
>> +	struct fiq_data *data = lookup_fiq_data(fiq);
>> +
>> +	if (data) {
>> +		if (data->fiq_chip->fiq_enable)
>> +			data->fiq_chip->fiq_enable(data->irq_data);
>> +		enable_irq(fiq);
> 
> This is ass backwards, really.
> 
> The FIQ target is a property of the interrupt line right?
> 
> So why the heck do you need a separate chip/data representation
> including a radix tree and whatever? Just because you can?
> 
> What is wrong to tell the irq core code via a flag that a particular
> interrupt should be targeted at FIQ instead of a regular interrupt?
> 
> Nothing as far as I can tell. And that would even allow to retarget an
> already enabled interrupt to FIQ or vice versa.
> 
> So all your patch does is trying to (ab)use an existing interface
> which was created in the last millenium for totally different reasons
> and in a totally different context.
> 
> But you fail completely to understand what that interface is doing:
> 
>     It merily maps the Linux virq to a FIQ via an offset.
> 
> While I understand that this is not workable on multiplatform kernels,
> I really cannot understand your attempt to change this by adding
> complex functionality to a primitive offset mapping function.
> 
> You just add some randomly defined new chip/data combination which
> abuses the irq_data structure under the hood instead of properly
> integrating that irq chip property into irqchip/irqdata itself.
> 
> So instead of thinking about the properties of the hardware and
> questioning the existing mechanism, you just bolt some crap onto it
> and inflict a gazillion of pointless modifications to the irq chip
> drivers without any value.
> 
> So all it needs is
> 
>  1) Adding a property flag to the irq chip which signals that it
>     supports FIQ/NMI targets
> 
>  2) Adding a interface which allows to flag a particular interrupt
>     line targeted to either the regular or the FIQ/NMI which consults
>     the flag added by #1
> 
>  3) Let the chip driver deal with the target flag at a minimal
>     intrusive level w/o registering racy callbacks designed in hell
>     and imposing arch specific data structures, storage etc. for no
>     value

Thanks for the comments.

I'll get working along these lines.



^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v11 01/19] arm: fiq: Add callbacks to manage FIQ routings
@ 2014-09-03  8:27                         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-03  8:27 UTC (permalink / raw)
  To: linux-arm-kernel

On 03/09/14 01:03, Thomas Gleixner wrote:
> On Tue, 2 Sep 2014, Daniel Thompson wrote:
> 
>> Currently enable_fiq/disable_fiq use a simple offset to convert an IRQ
>> virq into a FIQ virq. This is too inflexible for multi-platform kernels
>> and makes runtime error checking impossible.
> 
> You are missing to explain WHY it is too inflexible ....
>  
>> We solve this by introducing a flexible mapping that allows interrupt
> 
> Flexible in that context reads like random semantics. And that's
> definitely nothing we want to see in the context of interrupts/fiqs
> 
>> controllers that support FIQ to register those mappings. This, in turn,
>> makes it much possible for drivers in DT kernels to install FIQ handlers
>> without knowing anything about the interrupt controller.
> 
>> +#include <linux/irq.h>
>>  #include <asm/ptrace.h>
>>  
>> +struct fiq_chip {
>> +	void (*fiq_enable)(struct irq_data *data);
>> +	void (*fiq_disable)(struct irq_data *data);
>> +};
> 
> So you define an ARM specific extension to the irq infrastructure
> which is completely ignoring that there might be other architectures
> which have the same issue?
> 
> Aside of that you define that structure w/o documenting in any way
> what the semantics of the callbacks are and how struct irq_data is
> supposed to be (ab)used there.
> 
>> +struct fiq_data {
>> +	struct fiq_chip *fiq_chip;
>> +	struct irq_data *irq_data;
>> +};
> 
> Nice. Another completely undocumented data structure.
> 
>>  static unsigned long no_fiq_insn;
>> +static int fiq_start = -1;
>> +static RADIX_TREE(fiq_data_tree, GFP_KERNEL);
> 
> Along with a radix tree, which again lacks any form of documentation.
> 
>> -static int fiq_start;
>> +static struct fiq_data *lookup_fiq_data(int fiq)
>> +{
>> +	struct fiq_data *data;
>> +
>> +	rcu_read_lock();
>> +	data = radix_tree_lookup(&fiq_data_tree, fiq);
>> +	rcu_read_unlock();
>> +
>> +	return data;
> 
> That makes a lot of sense. NOT!
> 
> What kind of protection is that rcu_read_lock/unlock pair providing
> for the return value? Just that it has been valid at lookup time?
> 
> What protects against concurrent calls to the various usage sites
> which shine by the lack of serialization ...

The locking here ought to safe because there is no means to unregister
fiq data (the two irqchip drivers I looked at has no need for that) so
once looked up the data will be valid.

Thus it's only purpose was to prevent incorrect traversals of the radix
tree.

That said, this doesn't make it right.


>>  void enable_fiq(int fiq)
>>  {
>> +	struct fiq_data *data = lookup_fiq_data(fiq);
>> +
>> +	if (data) {
>> +		if (data->fiq_chip->fiq_enable)
>> +			data->fiq_chip->fiq_enable(data->irq_data);
>> +		enable_irq(fiq);
> 
> This is ass backwards, really.
> 
> The FIQ target is a property of the interrupt line right?
> 
> So why the heck do you need a separate chip/data representation
> including a radix tree and whatever? Just because you can?
> 
> What is wrong to tell the irq core code via a flag that a particular
> interrupt should be targeted at FIQ instead of a regular interrupt?
> 
> Nothing as far as I can tell. And that would even allow to retarget an
> already enabled interrupt to FIQ or vice versa.
> 
> So all your patch does is trying to (ab)use an existing interface
> which was created in the last millenium for totally different reasons
> and in a totally different context.
> 
> But you fail completely to understand what that interface is doing:
> 
>     It merily maps the Linux virq to a FIQ via an offset.
> 
> While I understand that this is not workable on multiplatform kernels,
> I really cannot understand your attempt to change this by adding
> complex functionality to a primitive offset mapping function.
> 
> You just add some randomly defined new chip/data combination which
> abuses the irq_data structure under the hood instead of properly
> integrating that irq chip property into irqchip/irqdata itself.
> 
> So instead of thinking about the properties of the hardware and
> questioning the existing mechanism, you just bolt some crap onto it
> and inflict a gazillion of pointless modifications to the irq chip
> drivers without any value.
> 
> So all it needs is
> 
>  1) Adding a property flag to the irq chip which signals that it
>     supports FIQ/NMI targets
> 
>  2) Adding a interface which allows to flag a particular interrupt
>     line targeted to either the regular or the FIQ/NMI which consults
>     the flag added by #1
> 
>  3) Let the chip driver deal with the target flag at a minimal
>     intrusive level w/o registering racy callbacks designed in hell
>     and imposing arch specific data structures, storage etc. for no
>     value

Thanks for the comments.

I'll get working along these lines.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v11 00/19] arm: KGDB NMI/FIQ support
  2014-09-02 23:02                     ` Thomas Gleixner
@ 2014-09-03  9:02                       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-03  9:02 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Russell King, linaro-kernel, Catalin Marinas, patches,
	kgdb-bugreport, Nicolas Pitre, linux-kernel, Frederic Weisbecker,
	Anton Vorontsov, Ben Dooks, Fabio Estevam, Colin Cross,
	kernel-team, Dave Martin, linux-arm-kernel

On 03/09/14 00:02, Thomas Gleixner wrote:
> On Tue, 2 Sep 2014, Daniel Thompson wrote:
> 
>> This patchset makes it possible to use kgdb's NMI infrastructure on ARM
>> platforms.
>>
>> The patches are seperated into three distinct groups:
>>
>> 1. arm specific changes; these provide multi-platform support for FIQ
>>    (including raising an IPI using FIQ to ensure effective SMP support)
>>    and extend ARM KGDB support to use the features provided.
>>
>> 2. irqchip changes; updates to the gic and vic drivers to provide
>>    support for routing certain interrupt sources to FIQ.
>>
>> 3. serial changes; driver support to allow the UART interrupt to be
>>    routed to FIQ. The already mainlined kgdb NMI infrastructure (mostly
>>    found in drivers/tty/serial/kgdb_nmi.c) will re-route the kgdb
>>    console UART's interrupt signal from IRQ to FIQ. Naturally the UART
>>    will no longer function normally and will instead be managed by kgdb
>>    using the polled I/O functions. Any character delivered to the UART
>>    causes the kgdb handler function to be called.
> 
> To be honest, what you are doing is just ass backwards.
> 
> The use case you are looking for is the most irrelevant of all. Just
> because KGDB is on some managerial "must have items" checklist does
> not make it useful.

The FIQ based interactive debugger use case is fairly common on Android,
especially for Nexus devices (they have an out-of-tree debugger similar
to kdb for this).

I think it finds favour there because during the development phases
where the console is unplugged to allow developers to go walkabout live
with a prototype phone. The interactive debugger is used for
post-morteming when something breaks. At this stage of development are
reluctant to expose/consume hardware resources (JTAG pins, RAM, FLASH)
for JTAG or kexec/kdump post-mortems.


> The only relevant use cases of FIQs are the same as those of NMIs on
> x86:
> 
>   - Watchdog to detect stuck cpus and issue stack traces

Russell put together a quick 'n dirty version of the NMI stack trace
code based on a subset of my patchset. Based on his feedback, later
revisions of my patchset are structured to simplify adding this code.


Daniel.


>   - Performace monitoring
> 
> KGDB falls into place once you solved the above.
>
> That said for the general approach, I'll have a look at the irq
> related patches in a minute.
> 
> Thanks,
> 
> 	tglx



^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v11 00/19] arm: KGDB NMI/FIQ support
@ 2014-09-03  9:02                       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-03  9:02 UTC (permalink / raw)
  To: linux-arm-kernel

On 03/09/14 00:02, Thomas Gleixner wrote:
> On Tue, 2 Sep 2014, Daniel Thompson wrote:
> 
>> This patchset makes it possible to use kgdb's NMI infrastructure on ARM
>> platforms.
>>
>> The patches are seperated into three distinct groups:
>>
>> 1. arm specific changes; these provide multi-platform support for FIQ
>>    (including raising an IPI using FIQ to ensure effective SMP support)
>>    and extend ARM KGDB support to use the features provided.
>>
>> 2. irqchip changes; updates to the gic and vic drivers to provide
>>    support for routing certain interrupt sources to FIQ.
>>
>> 3. serial changes; driver support to allow the UART interrupt to be
>>    routed to FIQ. The already mainlined kgdb NMI infrastructure (mostly
>>    found in drivers/tty/serial/kgdb_nmi.c) will re-route the kgdb
>>    console UART's interrupt signal from IRQ to FIQ. Naturally the UART
>>    will no longer function normally and will instead be managed by kgdb
>>    using the polled I/O functions. Any character delivered to the UART
>>    causes the kgdb handler function to be called.
> 
> To be honest, what you are doing is just ass backwards.
> 
> The use case you are looking for is the most irrelevant of all. Just
> because KGDB is on some managerial "must have items" checklist does
> not make it useful.

The FIQ based interactive debugger use case is fairly common on Android,
especially for Nexus devices (they have an out-of-tree debugger similar
to kdb for this).

I think it finds favour there because during the development phases
where the console is unplugged to allow developers to go walkabout live
with a prototype phone. The interactive debugger is used for
post-morteming when something breaks. At this stage of development are
reluctant to expose/consume hardware resources (JTAG pins, RAM, FLASH)
for JTAG or kexec/kdump post-mortems.


> The only relevant use cases of FIQs are the same as those of NMIs on
> x86:
> 
>   - Watchdog to detect stuck cpus and issue stack traces

Russell put together a quick 'n dirty version of the NMI stack trace
code based on a subset of my patchset. Based on his feedback, later
revisions of my patchset are structured to simplify adding this code.


Daniel.


>   - Performace monitoring
> 
> KGDB falls into place once you solved the above.
>
> That said for the general approach, I'll have a look at the irq
> related patches in a minute.
> 
> Thanks,
> 
> 	tglx

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v11 06/19] irqchip: gic: Provide support for interrupt grouping
  2014-09-02 19:33                       ` Russell King - ARM Linux
@ 2014-09-03  9:28                         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-03  9:28 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linux-kernel, linux-arm-kernel, kgdb-bugreport, patches,
	linaro-kernel, John Stultz, Anton Vorontsov, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Thomas Gleixner, Jason Cooper, Nicolas Pitre,
	Christoffer Dall, Sricharan R, Marc Zyngier

On 02/09/14 20:33, Russell King - ARM Linux wrote:
> On Tue, Sep 02, 2014 at 02:00:40PM +0100, Daniel Thompson wrote:
>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>> index 4b959e6..423707c 100644
>> --- a/drivers/irqchip/irq-gic.c
>> +++ b/drivers/irqchip/irq-gic.c
>> @@ -41,6 +41,9 @@
>>  #include <linux/irqchip/arm-gic.h>
>>  
>>  #include <asm/cputype.h>
>> +#ifdef CONFIG_FIQ
>> +#include <asm/fiq.h>
>> +#endif
> 
> Is there much advantage to this ifdef over providing a dummy asm/fiq.h
> in ARM64?
> 
>>  #include <asm/irq.h>
>>  #include <asm/exception.h>
>>  #include <asm/smp_plat.h>
>> @@ -68,6 +71,9 @@ struct gic_chip_data {
>>  #ifdef CONFIG_GIC_NON_BANKED
>>  	void __iomem *(*get_base)(union gic_base *);
>>  #endif
>> +#ifdef CONFIG_FIQ
>> +	bool fiq_enable;
>> +#endif
>>  };
>>  
>>  static DEFINE_RAW_SPINLOCK(irq_controller_lock);
>> @@ -131,6 +137,16 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data,
>>  #define gic_set_base_accessor(d, f)
>>  #endif
>>  
>> +#ifdef CONFIG_FIQ
>> +static inline bool gic_data_fiq_enable(struct gic_chip_data *data)
>> +{
>> +	return data->fiq_enable;
>> +}
>> +#else
>> +static inline bool gic_data_fiq_enable(
>> +		struct gic_chip_data *data) { return false; }
> 
> I really hate this style.  Just lay it out as a normal function.

Will do.


>> +	/*
>> +	 * If grouping is not available (not implemented or prohibited by
>> +	 * security mode) these registers a read-as-zero/write-ignored.
>> +	 * However as a precaution we restore the reset default regardless of
>> +	 * the result of the test.
>> +	 */
> 
> Have we found that this additional complexity is actually necessary?
> If not, we're over-engineering the code, making it more complex (and
> hence more likely to be buggy) for very little reason.
>
> Last night, I booted an unconditional version of this on OMAP3430, and
> OMAP4430.  It's also been booted on the range of iMX6 CPUs.  Nothing
> here has shown any signs of problems to having these registers written.

No, I haven't proven that most of the conditional code based on
gic_data_fiq_enable() is required.

I should certainly be safe to remove the conditional code from registers
specified was RAZ/WI.

I suspect we could also remove it from registers with bits that are
reserved (although spec. doesn't not state this explicitly).

I could aggressively remove the conditionals and keep the current code
on a branch to make it quicker to support any reported regressions.


>> +	/*
>> +	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
>> +	 * bit 1 ignored)
>> +	 */
>> +	if (gic_data_fiq_enable(gic))
>> +		writel_relaxed(3, base + GIC_DIST_CTRL);
>> +	else
>> +		writel_relaxed(1, base + GIC_DIST_CTRL);
> 
> If we are going to do this conditionally, and the only thing which
> is variable is the value to be written, I much prefer the conditional
> bit to be on the value and not the write.  The compiler doesn't always
> optimise these things very well.  So:
> 
> 	writel_relaxed(gic_data_fiq_enable(gic) ? 3 : 1, base + GIC_DIST_CTRL);
> 
> works well enough for me.  If you feel better by using a temporary
> local, that works for me too.

Ternary is fine by me although I'm inclined to be more aggressive with
removal of conditional code.

> 
>> +	if (gic_data_fiq_enable(gic))
>> +		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
>> +	else
>> +		writel_relaxed(1, base + GIC_CPU_CTRL);
> 
> Same here.

Ok.

>> @@ -485,7 +564,10 @@ static void gic_dist_restore(unsigned int gic_nr)
>>  		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
>>  			dist_base + GIC_DIST_ENABLE_SET + i * 4);
>>  
>> -	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
>> +	if (gic_data_fiq_enable(&gic_data[gic_nr]))
>> +		writel_relaxed(3, dist_base + GIC_DIST_CTRL);
>> +	else
>> +		writel_relaxed(1, dist_base + GIC_DIST_CTRL);
> 
> And here.

Ok.

>> @@ -542,7 +624,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
>>  		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
>>  
>>  	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
>> -	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
>> +	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
> 
> Interestingly, here you write 0x1f unconditionally.

Oops. Can I pretend this was was a premonition?


>>  }
>>  
>>  static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
>> @@ -604,6 +686,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
>>  {
>>  	int cpu;
>>  	unsigned long flags, map = 0;
>> +	unsigned long softint;
>>  
>>  	raw_spin_lock_irqsave(&irq_controller_lock, flags);
>>  
>> @@ -618,7 +701,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
>>  	dmb(ishst);
>>  
>>  	/* this always happens on GIC0 */
>> -	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
>> +	softint = map << 16 | irq;
>> +	if (gic_data_fiq_enable(&gic_data[0]))
>> +		softint |= 0x8000;
> 
> I guess that this always has to be done conditionally.  I'd prefer this
> test to be done slightly differently (and we might as well wrap in a bit
> of patch 9 here):
> 
> 	if (sgi_is_nonsecure(irq, &gic_data[0]))
> 		softint |= 0x8000;
> 
> which follows the true purpose of that bit.  This bit only has effect if
> we are running in secure mode, where it must match the status of the
> target interrupt (as programmed into GIC_DIST_IGROUP).
> 
> We probably should do this based on a bitmask of SGIs in the
> gic_chip_data, which is initialised according to how we've been able
> to setup the GIC_DIST_IGROUP register(s).

Will do.


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v11 06/19] irqchip: gic: Provide support for interrupt grouping
@ 2014-09-03  9:28                         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-03  9:28 UTC (permalink / raw)
  To: linux-arm-kernel

On 02/09/14 20:33, Russell King - ARM Linux wrote:
> On Tue, Sep 02, 2014 at 02:00:40PM +0100, Daniel Thompson wrote:
>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>> index 4b959e6..423707c 100644
>> --- a/drivers/irqchip/irq-gic.c
>> +++ b/drivers/irqchip/irq-gic.c
>> @@ -41,6 +41,9 @@
>>  #include <linux/irqchip/arm-gic.h>
>>  
>>  #include <asm/cputype.h>
>> +#ifdef CONFIG_FIQ
>> +#include <asm/fiq.h>
>> +#endif
> 
> Is there much advantage to this ifdef over providing a dummy asm/fiq.h
> in ARM64?
> 
>>  #include <asm/irq.h>
>>  #include <asm/exception.h>
>>  #include <asm/smp_plat.h>
>> @@ -68,6 +71,9 @@ struct gic_chip_data {
>>  #ifdef CONFIG_GIC_NON_BANKED
>>  	void __iomem *(*get_base)(union gic_base *);
>>  #endif
>> +#ifdef CONFIG_FIQ
>> +	bool fiq_enable;
>> +#endif
>>  };
>>  
>>  static DEFINE_RAW_SPINLOCK(irq_controller_lock);
>> @@ -131,6 +137,16 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data,
>>  #define gic_set_base_accessor(d, f)
>>  #endif
>>  
>> +#ifdef CONFIG_FIQ
>> +static inline bool gic_data_fiq_enable(struct gic_chip_data *data)
>> +{
>> +	return data->fiq_enable;
>> +}
>> +#else
>> +static inline bool gic_data_fiq_enable(
>> +		struct gic_chip_data *data) { return false; }
> 
> I really hate this style.  Just lay it out as a normal function.

Will do.


>> +	/*
>> +	 * If grouping is not available (not implemented or prohibited by
>> +	 * security mode) these registers a read-as-zero/write-ignored.
>> +	 * However as a precaution we restore the reset default regardless of
>> +	 * the result of the test.
>> +	 */
> 
> Have we found that this additional complexity is actually necessary?
> If not, we're over-engineering the code, making it more complex (and
> hence more likely to be buggy) for very little reason.
>
> Last night, I booted an unconditional version of this on OMAP3430, and
> OMAP4430.  It's also been booted on the range of iMX6 CPUs.  Nothing
> here has shown any signs of problems to having these registers written.

No, I haven't proven that most of the conditional code based on
gic_data_fiq_enable() is required.

I should certainly be safe to remove the conditional code from registers
specified was RAZ/WI.

I suspect we could also remove it from registers with bits that are
reserved (although spec. doesn't not state this explicitly).

I could aggressively remove the conditionals and keep the current code
on a branch to make it quicker to support any reported regressions.


>> +	/*
>> +	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
>> +	 * bit 1 ignored)
>> +	 */
>> +	if (gic_data_fiq_enable(gic))
>> +		writel_relaxed(3, base + GIC_DIST_CTRL);
>> +	else
>> +		writel_relaxed(1, base + GIC_DIST_CTRL);
> 
> If we are going to do this conditionally, and the only thing which
> is variable is the value to be written, I much prefer the conditional
> bit to be on the value and not the write.  The compiler doesn't always
> optimise these things very well.  So:
> 
> 	writel_relaxed(gic_data_fiq_enable(gic) ? 3 : 1, base + GIC_DIST_CTRL);
> 
> works well enough for me.  If you feel better by using a temporary
> local, that works for me too.

Ternary is fine by me although I'm inclined to be more aggressive with
removal of conditional code.

> 
>> +	if (gic_data_fiq_enable(gic))
>> +		writel_relaxed(0x1f, base + GIC_CPU_CTRL);
>> +	else
>> +		writel_relaxed(1, base + GIC_CPU_CTRL);
> 
> Same here.

Ok.

>> @@ -485,7 +564,10 @@ static void gic_dist_restore(unsigned int gic_nr)
>>  		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
>>  			dist_base + GIC_DIST_ENABLE_SET + i * 4);
>>  
>> -	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
>> +	if (gic_data_fiq_enable(&gic_data[gic_nr]))
>> +		writel_relaxed(3, dist_base + GIC_DIST_CTRL);
>> +	else
>> +		writel_relaxed(1, dist_base + GIC_DIST_CTRL);
> 
> And here.

Ok.

>> @@ -542,7 +624,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
>>  		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
>>  
>>  	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
>> -	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
>> +	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
> 
> Interestingly, here you write 0x1f unconditionally.

Oops. Can I pretend this was was a premonition?


>>  }
>>  
>>  static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
>> @@ -604,6 +686,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
>>  {
>>  	int cpu;
>>  	unsigned long flags, map = 0;
>> +	unsigned long softint;
>>  
>>  	raw_spin_lock_irqsave(&irq_controller_lock, flags);
>>  
>> @@ -618,7 +701,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
>>  	dmb(ishst);
>>  
>>  	/* this always happens on GIC0 */
>> -	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
>> +	softint = map << 16 | irq;
>> +	if (gic_data_fiq_enable(&gic_data[0]))
>> +		softint |= 0x8000;
> 
> I guess that this always has to be done conditionally.  I'd prefer this
> test to be done slightly differently (and we might as well wrap in a bit
> of patch 9 here):
> 
> 	if (sgi_is_nonsecure(irq, &gic_data[0]))
> 		softint |= 0x8000;
> 
> which follows the true purpose of that bit.  This bit only has effect if
> we are running in secure mode, where it must match the status of the
> target interrupt (as programmed into GIC_DIST_IGROUP).
> 
> We probably should do this based on a bitmask of SGIs in the
> gic_chip_data, which is initialised according to how we've been able
> to setup the GIC_DIST_IGROUP register(s).

Will do.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v11 06/19] irqchip: gic: Provide support for interrupt grouping
  2014-09-02 21:36                         ` Catalin Marinas
@ 2014-09-03  9:44                           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-03  9:44 UTC (permalink / raw)
  To: Catalin Marinas, Russell King - ARM Linux
  Cc: linux-kernel, linux-arm-kernel, kgdb-bugreport, patches,
	linaro-kernel, John Stultz, Anton Vorontsov, Colin Cross,
	kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Dave P Martin, Fabio Estevam, Frederic Weisbecker, Nicolas Pitre,
	Thomas Gleixner, Jason Cooper, Nicolas Pitre, Christoffer Dall,
	Sricharan R, Marc Zyngier

On 02/09/14 22:36, Catalin Marinas wrote:
> On 2 Sep 2014, at 20:33, Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:
>> On Tue, Sep 02, 2014 at 02:00:40PM +0100, Daniel Thompson wrote:
>>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>>> index 4b959e6..423707c 100644
>>> --- a/drivers/irqchip/irq-gic.c
>>> +++ b/drivers/irqchip/irq-gic.c
>>> @@ -41,6 +41,9 @@
>>> #include <linux/irqchip/arm-gic.h>
>>>
>>> #include <asm/cputype.h>
>>> +#ifdef CONFIG_FIQ
>>> +#include <asm/fiq.h>
>>> +#endif
>>
>> Is there much advantage to this ifdef over providing a dummy asm/fiq.h
>> in ARM64?
> 
> While it’s unlikely we’ll use FIQs on arm64 (they are generally
> reserved for the secure world/firmware), I don’t mind an empty
> asm/fiq.h file.

Thanks Catalin, Thanks Russell.

I will do this.


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v11 06/19] irqchip: gic: Provide support for interrupt grouping
@ 2014-09-03  9:44                           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-03  9:44 UTC (permalink / raw)
  To: linux-arm-kernel

On 02/09/14 22:36, Catalin Marinas wrote:
> On 2 Sep 2014, at 20:33, Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:
>> On Tue, Sep 02, 2014 at 02:00:40PM +0100, Daniel Thompson wrote:
>>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>>> index 4b959e6..423707c 100644
>>> --- a/drivers/irqchip/irq-gic.c
>>> +++ b/drivers/irqchip/irq-gic.c
>>> @@ -41,6 +41,9 @@
>>> #include <linux/irqchip/arm-gic.h>
>>>
>>> #include <asm/cputype.h>
>>> +#ifdef CONFIG_FIQ
>>> +#include <asm/fiq.h>
>>> +#endif
>>
>> Is there much advantage to this ifdef over providing a dummy asm/fiq.h
>> in ARM64?
> 
> While it?s unlikely we?ll use FIQs on arm64 (they are generally
> reserved for the secure world/firmware), I don?t mind an empty
> asm/fiq.h file.

Thanks Catalin, Thanks Russell.

I will do this.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v11 00/19] arm: KGDB NMI/FIQ support
  2014-09-03  9:02                       ` Daniel Thompson
@ 2014-09-03 10:06                         ` Thomas Gleixner
  -1 siblings, 0 replies; 535+ messages in thread
From: Thomas Gleixner @ 2014-09-03 10:06 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Russell King, linaro-kernel, Catalin Marinas, patches,
	kgdb-bugreport, Nicolas Pitre, linux-kernel, Frederic Weisbecker,
	Anton Vorontsov, Ben Dooks, Fabio Estevam, Colin Cross,
	kernel-team, Dave Martin, linux-arm-kernel

On Wed, 3 Sep 2014, Daniel Thompson wrote:
> On 03/09/14 00:02, Thomas Gleixner wrote:
> > The use case you are looking for is the most irrelevant of all. Just
> > because KGDB is on some managerial "must have items" checklist does
> > not make it useful.
> 
> The FIQ based interactive debugger use case is fairly common on Android,
> especially for Nexus devices (they have an out-of-tree debugger similar
> to kdb for this).
> 
> I think it finds favour there because during the development phases
> where the console is unplugged to allow developers to go walkabout live
> with a prototype phone. The interactive debugger is used for
> post-morteming when something breaks. At this stage of development are
> reluctant to expose/consume hardware resources (JTAG pins, RAM, FLASH)
> for JTAG or kexec/kdump post-mortems.

If things are common and favoured for whatever reasons, that does not
make them a proper solution per se.

I rather have a kexec debug kernel started if my production/test
kernel explodes than hooking up a lousy debugger via serial, but thats
a matter of taste and reason.

> > The only relevant use cases of FIQs are the same as those of NMIs on
> > x86:
> > 
> >   - Watchdog to detect stuck cpus and issue stack traces
> 
> Russell put together a quick 'n dirty version of the NMI stack trace
> code based on a subset of my patchset. Based on his feedback, later
> revisions of my patchset are structured to simplify adding this code.

And I still say, that this is the first use case which should be
provided as it is simple enough, immediately usefull and testable for
everyone.

So, really what I want to see in the first place is a minimalistic
patch series which

 1) Implements the core infrastructure for FIQ support

 2) Converts a single interrupt controller to play with #1

 3) Provides the simplest useful use case using #1

That's at max 5 patches, which are easy enough to review, and not a
patch series which changes the world and some more in one go.

We need to get the design and the infrastructure right in the first
place. What I've seen so far is just a complete lack of design. If you
take off your KGDB blinkers, you might notice that yourself.

As I said before:

> > KGDB falls into place once you solved the above.

Thanks,

	tglx

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v11 00/19] arm: KGDB NMI/FIQ support
@ 2014-09-03 10:06                         ` Thomas Gleixner
  0 siblings, 0 replies; 535+ messages in thread
From: Thomas Gleixner @ 2014-09-03 10:06 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 3 Sep 2014, Daniel Thompson wrote:
> On 03/09/14 00:02, Thomas Gleixner wrote:
> > The use case you are looking for is the most irrelevant of all. Just
> > because KGDB is on some managerial "must have items" checklist does
> > not make it useful.
> 
> The FIQ based interactive debugger use case is fairly common on Android,
> especially for Nexus devices (they have an out-of-tree debugger similar
> to kdb for this).
> 
> I think it finds favour there because during the development phases
> where the console is unplugged to allow developers to go walkabout live
> with a prototype phone. The interactive debugger is used for
> post-morteming when something breaks. At this stage of development are
> reluctant to expose/consume hardware resources (JTAG pins, RAM, FLASH)
> for JTAG or kexec/kdump post-mortems.

If things are common and favoured for whatever reasons, that does not
make them a proper solution per se.

I rather have a kexec debug kernel started if my production/test
kernel explodes than hooking up a lousy debugger via serial, but thats
a matter of taste and reason.

> > The only relevant use cases of FIQs are the same as those of NMIs on
> > x86:
> > 
> >   - Watchdog to detect stuck cpus and issue stack traces
> 
> Russell put together a quick 'n dirty version of the NMI stack trace
> code based on a subset of my patchset. Based on his feedback, later
> revisions of my patchset are structured to simplify adding this code.

And I still say, that this is the first use case which should be
provided as it is simple enough, immediately usefull and testable for
everyone.

So, really what I want to see in the first place is a minimalistic
patch series which

 1) Implements the core infrastructure for FIQ support

 2) Converts a single interrupt controller to play with #1

 3) Provides the simplest useful use case using #1

That's at max 5 patches, which are easy enough to review, and not a
patch series which changes the world and some more in one go.

We need to get the design and the infrastructure right in the first
place. What I've seen so far is just a complete lack of design. If you
take off your KGDB blinkers, you might notice that yourself.

As I said before:

> > KGDB falls into place once you solved the above.

Thanks,

	tglx

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
  2014-09-02 16:42                             ` Russell King - ARM Linux
@ 2014-09-03 10:21                               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-03 10:21 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Paul E. McKenney, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

On 02/09/14 17:42, Russell King - ARM Linux wrote:
> On Tue, Sep 02, 2014 at 12:49:16PM +0100, Daniel Thompson wrote:
>> On 28/08/14 16:01, Russell King - ARM Linux wrote:
>>> I just asked Paul McKenney, our RCU expert... essentially, yes, RCU
>>> stuff itself is safe in this context.  However, RCU stuff can call into
>>> lockdep if lockdep is configured, and there are questions over lockdep.
>>>
>>> There's some things which can be done to reduce the lockdep exposure
>>> to it, such as ensuring that rcu_read_lock() is first called outside
>>> of FIQ context.
>>>
>>> There's concerns with whether either printk() in check_flags() could
>>> be reached too (flags there should always indicate that IRQs were
>>> disabled, so that reduces down to a question about just the first
>>> printk() there.)
>>>
>>> There's also the very_verbose() stuff for RCU lockdep classes which
>>> Paul says must not be enabled.
>>>
>>> Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
>>> lockdep doing the deadlock checking as a result of the above call.
>>>
>>> So... this coupled with my feeling that notifiers make it too easy for
>>> unreviewed code to be hooked into this path, I'm fairly sure that we
>>> don't want to be calling atomic notifier chains from FIQ context.
>>
>> Having esablished (elsewhere in the thread) that RCU usage is safe
>> from FIQ I have been working on the assumption that your feeling
>> regarding unreviewed code is sufficient on its own to avoid using
>> notifiers (and also to avoid a list of function pointers like on x86).
> 
> Yes, it does, because unlike the x86 community, we have a wide range
> of platforms, and platform code does not go through the same path or
> get the same review as core ARM code.
> 
> As I already pointed out, with a notifier, it's very easy to sneak
> something into the FIQ path by submitting a patch for platform code
> which calls the registration function.  That's going to be pretty
> difficult to spot amongst the 3000+ messages on the linux-arm-kernel
> list each month in order to give it the review that it would need.
> That's especially true as I now ignore almost all most platform
> code patches as we have Arnd and Olof to look at that.
> 
> So, unless you can come up with a proposal which ensures that there
> is sufficient review triggered when someone decides to call the
> notifier registration function...

Reflecting upon this and upon Thomas' comments about only using FIQ for
watchdog, backtrace and performance monitoring...

The short version is, "I was wrong and should have done what you said in
the first place".

The long version adds, "because the coupling concerns were spurious; the
only proposed users of the default FIQ handler outside of core ARM code,
are ARM-centric irqchip drivers."


> How about something like:
> 
> static const char *allowable_callers[] = {
> 	...
> };
> 
> 	snprintf(caller, sizeof(caller), "%pf", __builtin_return_address(0));
> 
> 	for (i = 0; i < ARRAY_SIZE(allowable_callers); i++)
> 		if (!strcmp(caller, allowable_callers[i]))
> 			break;
> 
> 	if (i == ARRAY_SIZE(allowable_callers)) {
> 		printk(KERN_ERR "%s is not permitted to register a FIQ notifer\n",
> 			caller);
> 		return;
> 	}
> 
> This gives us the advantage of using the notifier, but also gives us the
> requirement that the file has to be modified to permit new registrations,
> thereby triggering the closer review.

Cool trick. However since I'm wrong...


> The other question I have is that if we permit kgdb and nmi tracing with
> this mechanism, how do the hooked callers distinguish between these
> different purposes?  I don't see how that works with your notifier
> setup.

The notifier as found in the existing patchs allowed the sharing only of
IPI FIQ (for example between stack dump code and kgdb).

This worked due to the way IPIs can be automatically EOIed and, because
they are software generated, software can use flags. In fact the kgdb
handler already uses this to discriminate between IPI FIQ and UART
interrupts (although the flag is set kgdb core logic rather than in the
ARM code).

For SPIs it's safety depended upon drivers using claim_fiq() to
arbitrate. There was no enforcement mechanism to prevent abuse.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
@ 2014-09-03 10:21                               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-03 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

On 02/09/14 17:42, Russell King - ARM Linux wrote:
> On Tue, Sep 02, 2014 at 12:49:16PM +0100, Daniel Thompson wrote:
>> On 28/08/14 16:01, Russell King - ARM Linux wrote:
>>> I just asked Paul McKenney, our RCU expert... essentially, yes, RCU
>>> stuff itself is safe in this context.  However, RCU stuff can call into
>>> lockdep if lockdep is configured, and there are questions over lockdep.
>>>
>>> There's some things which can be done to reduce the lockdep exposure
>>> to it, such as ensuring that rcu_read_lock() is first called outside
>>> of FIQ context.
>>>
>>> There's concerns with whether either printk() in check_flags() could
>>> be reached too (flags there should always indicate that IRQs were
>>> disabled, so that reduces down to a question about just the first
>>> printk() there.)
>>>
>>> There's also the very_verbose() stuff for RCU lockdep classes which
>>> Paul says must not be enabled.
>>>
>>> Lastly, Paul isn't a lockdep expert, but he sees nothing that prevents
>>> lockdep doing the deadlock checking as a result of the above call.
>>>
>>> So... this coupled with my feeling that notifiers make it too easy for
>>> unreviewed code to be hooked into this path, I'm fairly sure that we
>>> don't want to be calling atomic notifier chains from FIQ context.
>>
>> Having esablished (elsewhere in the thread) that RCU usage is safe
>> from FIQ I have been working on the assumption that your feeling
>> regarding unreviewed code is sufficient on its own to avoid using
>> notifiers (and also to avoid a list of function pointers like on x86).
> 
> Yes, it does, because unlike the x86 community, we have a wide range
> of platforms, and platform code does not go through the same path or
> get the same review as core ARM code.
> 
> As I already pointed out, with a notifier, it's very easy to sneak
> something into the FIQ path by submitting a patch for platform code
> which calls the registration function.  That's going to be pretty
> difficult to spot amongst the 3000+ messages on the linux-arm-kernel
> list each month in order to give it the review that it would need.
> That's especially true as I now ignore almost all most platform
> code patches as we have Arnd and Olof to look at that.
> 
> So, unless you can come up with a proposal which ensures that there
> is sufficient review triggered when someone decides to call the
> notifier registration function...

Reflecting upon this and upon Thomas' comments about only using FIQ for
watchdog, backtrace and performance monitoring...

The short version is, "I was wrong and should have done what you said in
the first place".

The long version adds, "because the coupling concerns were spurious; the
only proposed users of the default FIQ handler outside of core ARM code,
are ARM-centric irqchip drivers."


> How about something like:
> 
> static const char *allowable_callers[] = {
> 	...
> };
> 
> 	snprintf(caller, sizeof(caller), "%pf", __builtin_return_address(0));
> 
> 	for (i = 0; i < ARRAY_SIZE(allowable_callers); i++)
> 		if (!strcmp(caller, allowable_callers[i]))
> 			break;
> 
> 	if (i == ARRAY_SIZE(allowable_callers)) {
> 		printk(KERN_ERR "%s is not permitted to register a FIQ notifer\n",
> 			caller);
> 		return;
> 	}
> 
> This gives us the advantage of using the notifier, but also gives us the
> requirement that the file has to be modified to permit new registrations,
> thereby triggering the closer review.

Cool trick. However since I'm wrong...


> The other question I have is that if we permit kgdb and nmi tracing with
> this mechanism, how do the hooked callers distinguish between these
> different purposes?  I don't see how that works with your notifier
> setup.

The notifier as found in the existing patchs allowed the sharing only of
IPI FIQ (for example between stack dump code and kgdb).

This worked due to the way IPIs can be automatically EOIed and, because
they are software generated, software can use flags. In fact the kgdb
handler already uses this to discriminate between IPI FIQ and UART
interrupts (although the flag is set kgdb core logic rather than in the
ARM code).

For SPIs it's safety depended upon drivers using claim_fiq() to
arbitrate. There was no enforcement mechanism to prevent abuse.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v11 00/19] arm: KGDB NMI/FIQ support
  2014-09-03 10:06                         ` Thomas Gleixner
@ 2014-09-03 10:30                           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-03 10:30 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Russell King, linaro-kernel, Catalin Marinas, patches,
	kgdb-bugreport, Nicolas Pitre, linux-kernel, Frederic Weisbecker,
	Anton Vorontsov, Ben Dooks, Fabio Estevam, Colin Cross,
	kernel-team, Dave Martin, linux-arm-kernel

On 03/09/14 11:06, Thomas Gleixner wrote:
> On Wed, 3 Sep 2014, Daniel Thompson wrote:
>> On 03/09/14 00:02, Thomas Gleixner wrote:
>>> The use case you are looking for is the most irrelevant of all. Just
>>> because KGDB is on some managerial "must have items" checklist does
>>> not make it useful.
>>
>> The FIQ based interactive debugger use case is fairly common on Android,
>> especially for Nexus devices (they have an out-of-tree debugger similar
>> to kdb for this).
>>
>> I think it finds favour there because during the development phases
>> where the console is unplugged to allow developers to go walkabout live
>> with a prototype phone. The interactive debugger is used for
>> post-morteming when something breaks. At this stage of development are
>> reluctant to expose/consume hardware resources (JTAG pins, RAM, FLASH)
>> for JTAG or kexec/kdump post-mortems.
> 
> If things are common and favoured for whatever reasons, that does not
> make them a proper solution per se.
> 
> I rather have a kexec debug kernel started if my production/test
> kernel explodes than hooking up a lousy debugger via serial, but thats
> a matter of taste and reason.
> 
>>> The only relevant use cases of FIQs are the same as those of NMIs on
>>> x86:
>>>
>>>   - Watchdog to detect stuck cpus and issue stack traces
>>
>> Russell put together a quick 'n dirty version of the NMI stack trace
>> code based on a subset of my patchset. Based on his feedback, later
>> revisions of my patchset are structured to simplify adding this code.
> 
> And I still say, that this is the first use case which should be
> provided as it is simple enough, immediately usefull and testable for
> everyone.
> 
> So, really what I want to see in the first place is a minimalistic
> patch series which
> 
>  1) Implements the core infrastructure for FIQ support
> 
>  2) Converts a single interrupt controller to play with #1
> 
>  3) Provides the simplest useful use case using #1
> 
> That's at max 5 patches, which are easy enough to review, and not a
> patch series which changes the world and some more in one go.

Ok. I'll look into this.


> We need to get the design and the infrastructure right in the first
> place. What I've seen so far is just a complete lack of design. If you
> take off your KGDB blinkers, you might notice that yourself.

Good point. I have tried shrinking the patchset previously but I ended
up splitting it by sub-system rather than simplifying the use-case.

The guess the effect of shrinking the patchset in this way was more to
shrink the pool of likely reviewers than to shrink the size of the
problem... Clearly not a good idea (and not intentional on my part).


> As I said before:
> 
>>> KGDB falls into place once you solved the above.

I hope so...

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v11 00/19] arm: KGDB NMI/FIQ support
@ 2014-09-03 10:30                           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-03 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

On 03/09/14 11:06, Thomas Gleixner wrote:
> On Wed, 3 Sep 2014, Daniel Thompson wrote:
>> On 03/09/14 00:02, Thomas Gleixner wrote:
>>> The use case you are looking for is the most irrelevant of all. Just
>>> because KGDB is on some managerial "must have items" checklist does
>>> not make it useful.
>>
>> The FIQ based interactive debugger use case is fairly common on Android,
>> especially for Nexus devices (they have an out-of-tree debugger similar
>> to kdb for this).
>>
>> I think it finds favour there because during the development phases
>> where the console is unplugged to allow developers to go walkabout live
>> with a prototype phone. The interactive debugger is used for
>> post-morteming when something breaks. At this stage of development are
>> reluctant to expose/consume hardware resources (JTAG pins, RAM, FLASH)
>> for JTAG or kexec/kdump post-mortems.
> 
> If things are common and favoured for whatever reasons, that does not
> make them a proper solution per se.
> 
> I rather have a kexec debug kernel started if my production/test
> kernel explodes than hooking up a lousy debugger via serial, but thats
> a matter of taste and reason.
> 
>>> The only relevant use cases of FIQs are the same as those of NMIs on
>>> x86:
>>>
>>>   - Watchdog to detect stuck cpus and issue stack traces
>>
>> Russell put together a quick 'n dirty version of the NMI stack trace
>> code based on a subset of my patchset. Based on his feedback, later
>> revisions of my patchset are structured to simplify adding this code.
> 
> And I still say, that this is the first use case which should be
> provided as it is simple enough, immediately usefull and testable for
> everyone.
> 
> So, really what I want to see in the first place is a minimalistic
> patch series which
> 
>  1) Implements the core infrastructure for FIQ support
> 
>  2) Converts a single interrupt controller to play with #1
> 
>  3) Provides the simplest useful use case using #1
> 
> That's at max 5 patches, which are easy enough to review, and not a
> patch series which changes the world and some more in one go.

Ok. I'll look into this.


> We need to get the design and the infrastructure right in the first
> place. What I've seen so far is just a complete lack of design. If you
> take off your KGDB blinkers, you might notice that yourself.

Good point. I have tried shrinking the patchset previously but I ended
up splitting it by sub-system rather than simplifying the use-case.

The guess the effect of shrinking the patchset in this way was more to
shrink the pool of likely reviewers than to shrink the size of the
problem... Clearly not a good idea (and not intentional on my part).


> As I said before:
> 
>>> KGDB falls into place once you solved the above.

I hope so...

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
  2014-09-03 10:21                               ` Daniel Thompson
@ 2014-09-03 19:34                                 ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-03 19:34 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Paul E. McKenney, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre

On Wed, Sep 03, 2014 at 11:21:30AM +0100, Daniel Thompson wrote:
> On 02/09/14 17:42, Russell King - ARM Linux wrote:
> > Yes, it does, because unlike the x86 community, we have a wide range
> > of platforms, and platform code does not go through the same path or
> > get the same review as core ARM code.
> > 
> > As I already pointed out, with a notifier, it's very easy to sneak
> > something into the FIQ path by submitting a patch for platform code
> > which calls the registration function.  That's going to be pretty
> > difficult to spot amongst the 3000+ messages on the linux-arm-kernel
> > list each month in order to give it the review that it would need.
> > That's especially true as I now ignore almost all most platform
> > code patches as we have Arnd and Olof to look at that.
> > 
> > So, unless you can come up with a proposal which ensures that there
> > is sufficient review triggered when someone decides to call the
> > notifier registration function...
> 
> Reflecting upon this and upon Thomas' comments about only using FIQ for
> watchdog, backtrace and performance monitoring...
> 
> The short version is, "I was wrong and should have done what you said in
> the first place".
> 
> The long version adds, "because the coupling concerns were spurious; the
> only proposed users of the default FIQ handler outside of core ARM code,
> are ARM-centric irqchip drivers."

I would say that the ARM specific changes to entry-armv.S and setup.c
are correct.  All that you're doing there is to replace the existing
default no-op FIQ handler with some additional code which gets us into
SVC mode and back out, but itself is also a no-op.  In other words, no
real change.

That's a good first patch, and one which I would actually like to have
in my tree sooner rather than later, so that I can split that out from
my prototype code.

I can also split out from it the ARM generic changes for implementing
the FIQ dumping too, which gives us a second patch.  With a bit of
additional work, much of that should actually be generic code, not
ARM or x86 specific code.  That's going to annoy x86 people a little
because some of that is being reworked...

That will leave the problem of how to deal with the IRQ controller
specifics, and how to properly wire it together with the IRQ controller
in the loop - that is where Thomas' concerns are focused.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
@ 2014-09-03 19:34                                 ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-03 19:34 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Sep 03, 2014 at 11:21:30AM +0100, Daniel Thompson wrote:
> On 02/09/14 17:42, Russell King - ARM Linux wrote:
> > Yes, it does, because unlike the x86 community, we have a wide range
> > of platforms, and platform code does not go through the same path or
> > get the same review as core ARM code.
> > 
> > As I already pointed out, with a notifier, it's very easy to sneak
> > something into the FIQ path by submitting a patch for platform code
> > which calls the registration function.  That's going to be pretty
> > difficult to spot amongst the 3000+ messages on the linux-arm-kernel
> > list each month in order to give it the review that it would need.
> > That's especially true as I now ignore almost all most platform
> > code patches as we have Arnd and Olof to look at that.
> > 
> > So, unless you can come up with a proposal which ensures that there
> > is sufficient review triggered when someone decides to call the
> > notifier registration function...
> 
> Reflecting upon this and upon Thomas' comments about only using FIQ for
> watchdog, backtrace and performance monitoring...
> 
> The short version is, "I was wrong and should have done what you said in
> the first place".
> 
> The long version adds, "because the coupling concerns were spurious; the
> only proposed users of the default FIQ handler outside of core ARM code,
> are ARM-centric irqchip drivers."

I would say that the ARM specific changes to entry-armv.S and setup.c
are correct.  All that you're doing there is to replace the existing
default no-op FIQ handler with some additional code which gets us into
SVC mode and back out, but itself is also a no-op.  In other words, no
real change.

That's a good first patch, and one which I would actually like to have
in my tree sooner rather than later, so that I can split that out from
my prototype code.

I can also split out from it the ARM generic changes for implementing
the FIQ dumping too, which gives us a second patch.  With a bit of
additional work, much of that should actually be generic code, not
ARM or x86 specific code.  That's going to annoy x86 people a little
because some of that is being reworked...

That will leave the problem of how to deal with the IRQ controller
specifics, and how to properly wire it together with the IRQ controller
in the loop - that is where Thomas' concerns are focused.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
  2014-09-03 19:34                                 ` Russell King - ARM Linux
@ 2014-09-04  9:09                                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-04  9:09 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Paul E. McKenney, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Thomas Gleixner

On 03/09/14 20:34, Russell King - ARM Linux wrote:
> On Wed, Sep 03, 2014 at 11:21:30AM +0100, Daniel Thompson wrote:
>> On 02/09/14 17:42, Russell King - ARM Linux wrote:
>>> Yes, it does, because unlike the x86 community, we have a wide range
>>> of platforms, and platform code does not go through the same path or
>>> get the same review as core ARM code.
>>>
>>> As I already pointed out, with a notifier, it's very easy to sneak
>>> something into the FIQ path by submitting a patch for platform code
>>> which calls the registration function.  That's going to be pretty
>>> difficult to spot amongst the 3000+ messages on the linux-arm-kernel
>>> list each month in order to give it the review that it would need.
>>> That's especially true as I now ignore almost all most platform
>>> code patches as we have Arnd and Olof to look at that.
>>>
>>> So, unless you can come up with a proposal which ensures that there
>>> is sufficient review triggered when someone decides to call the
>>> notifier registration function...
>>
>> Reflecting upon this and upon Thomas' comments about only using FIQ for
>> watchdog, backtrace and performance monitoring...
>>
>> The short version is, "I was wrong and should have done what you said in
>> the first place".
>>
>> The long version adds, "because the coupling concerns were spurious; the
>> only proposed users of the default FIQ handler outside of core ARM code,
>> are ARM-centric irqchip drivers."
> 
> I would say that the ARM specific changes to entry-armv.S and setup.c
> are correct.  All that you're doing there is to replace the existing
> default no-op FIQ handler with some additional code which gets us into
> SVC mode and back out, but itself is also a no-op.  In other words, no
> real change.
> 
> That's a good first patch, and one which I would actually like to have
> in my tree sooner rather than later, so that I can split that out from
> my prototype code.

So would I!

I did some rebasing yesterday to put anything to do with kgdb right at
the back of the queue. This "good first patch" is now actually the first
patch; where the nofifier used to be it currently calls do_unexp_fiq()
making it very close to "no real change".

BTW do_unexp_fiq() calls printk() but

> I can also split out from it the ARM generic changes for implementing
> the FIQ dumping too, which gives us a second patch.  With a bit of
> additional work, much of that should actually be generic code, not
> ARM or x86 specific code.  That's going to annoy x86 people a little
> because some of that is being reworked...

So far I have been testing the action after patch review using the big
kgdb patches on top of it.

Today I plan to remove the kgdb stuff, drop in your version of
arch_trigger_all_cpu_backtrace() and test the results. I was going to
use the code you shared on 13 August meaning all the cpu mask bit
manipulation is in the arm-only code.

If you want me to work with something more recent then feel free to
point me at it...


> That will leave the problem of how to deal with the IRQ controller
> specifics, and how to properly wire it together with the IRQ controller
> in the loop - that is where Thomas' concerns are focused.

I'm working on those and its looking pretty good so far. This is mostly
because SGIs don't need to allocate virqs so the controversial bits of
my last patchset disappear completely.


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
@ 2014-09-04  9:09                                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-04  9:09 UTC (permalink / raw)
  To: linux-arm-kernel

On 03/09/14 20:34, Russell King - ARM Linux wrote:
> On Wed, Sep 03, 2014 at 11:21:30AM +0100, Daniel Thompson wrote:
>> On 02/09/14 17:42, Russell King - ARM Linux wrote:
>>> Yes, it does, because unlike the x86 community, we have a wide range
>>> of platforms, and platform code does not go through the same path or
>>> get the same review as core ARM code.
>>>
>>> As I already pointed out, with a notifier, it's very easy to sneak
>>> something into the FIQ path by submitting a patch for platform code
>>> which calls the registration function.  That's going to be pretty
>>> difficult to spot amongst the 3000+ messages on the linux-arm-kernel
>>> list each month in order to give it the review that it would need.
>>> That's especially true as I now ignore almost all most platform
>>> code patches as we have Arnd and Olof to look at that.
>>>
>>> So, unless you can come up with a proposal which ensures that there
>>> is sufficient review triggered when someone decides to call the
>>> notifier registration function...
>>
>> Reflecting upon this and upon Thomas' comments about only using FIQ for
>> watchdog, backtrace and performance monitoring...
>>
>> The short version is, "I was wrong and should have done what you said in
>> the first place".
>>
>> The long version adds, "because the coupling concerns were spurious; the
>> only proposed users of the default FIQ handler outside of core ARM code,
>> are ARM-centric irqchip drivers."
> 
> I would say that the ARM specific changes to entry-armv.S and setup.c
> are correct.  All that you're doing there is to replace the existing
> default no-op FIQ handler with some additional code which gets us into
> SVC mode and back out, but itself is also a no-op.  In other words, no
> real change.
> 
> That's a good first patch, and one which I would actually like to have
> in my tree sooner rather than later, so that I can split that out from
> my prototype code.

So would I!

I did some rebasing yesterday to put anything to do with kgdb right at
the back of the queue. This "good first patch" is now actually the first
patch; where the nofifier used to be it currently calls do_unexp_fiq()
making it very close to "no real change".

BTW do_unexp_fiq() calls printk() but

> I can also split out from it the ARM generic changes for implementing
> the FIQ dumping too, which gives us a second patch.  With a bit of
> additional work, much of that should actually be generic code, not
> ARM or x86 specific code.  That's going to annoy x86 people a little
> because some of that is being reworked...

So far I have been testing the action after patch review using the big
kgdb patches on top of it.

Today I plan to remove the kgdb stuff, drop in your version of
arch_trigger_all_cpu_backtrace() and test the results. I was going to
use the code you shared on 13 August meaning all the cpu mask bit
manipulation is in the arm-only code.

If you want me to work with something more recent then feel free to
point me at it...


> That will leave the problem of how to deal with the IRQ controller
> specifics, and how to properly wire it together with the IRQ controller
> in the loop - that is where Thomas' concerns are focused.

I'm working on those and its looking pretty good so far. This is mostly
because SGIs don't need to allocate virqs so the controversial bits of
my last patchset disappear completely.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
  2014-09-04  9:09                                   ` Daniel Thompson
@ 2014-09-04  9:45                                     ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-04  9:45 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Paul E. McKenney, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Thomas Gleixner

On Thu, Sep 04, 2014 at 10:09:20AM +0100, Daniel Thompson wrote:
> On 03/09/14 20:34, Russell King - ARM Linux wrote:
> > I would say that the ARM specific changes to entry-armv.S and setup.c
> > are correct.  All that you're doing there is to replace the existing
> > default no-op FIQ handler with some additional code which gets us into
> > SVC mode and back out, but itself is also a no-op.  In other words, no
> > real change.
> > 
> > That's a good first patch, and one which I would actually like to have
> > in my tree sooner rather than later, so that I can split that out from
> > my prototype code.
> 
> So would I!
> 
> I did some rebasing yesterday to put anything to do with kgdb right at
> the back of the queue. This "good first patch" is now actually the first
> patch; where the nofifier used to be it currently calls do_unexp_fiq()
> making it very close to "no real change".
> 
> BTW do_unexp_fiq() calls printk() but

You're making the assumption that something called do_unexp_fiq() before
your patches.  It seems that that function is dead code, and now that
you've pointed that out, I will kill this function.

The current situation is that if the CPU receives a FIQ, it enters the
FIQ vector, which contains an immediate return instruction.

> If you want me to work with something more recent then feel free to
> point me at it...

I'll post some of that stuff later today, probably this evening.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
@ 2014-09-04  9:45                                     ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-04  9:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Sep 04, 2014 at 10:09:20AM +0100, Daniel Thompson wrote:
> On 03/09/14 20:34, Russell King - ARM Linux wrote:
> > I would say that the ARM specific changes to entry-armv.S and setup.c
> > are correct.  All that you're doing there is to replace the existing
> > default no-op FIQ handler with some additional code which gets us into
> > SVC mode and back out, but itself is also a no-op.  In other words, no
> > real change.
> > 
> > That's a good first patch, and one which I would actually like to have
> > in my tree sooner rather than later, so that I can split that out from
> > my prototype code.
> 
> So would I!
> 
> I did some rebasing yesterday to put anything to do with kgdb right at
> the back of the queue. This "good first patch" is now actually the first
> patch; where the nofifier used to be it currently calls do_unexp_fiq()
> making it very close to "no real change".
> 
> BTW do_unexp_fiq() calls printk() but

You're making the assumption that something called do_unexp_fiq() before
your patches.  It seems that that function is dead code, and now that
you've pointed that out, I will kill this function.

The current situation is that if the CPU receives a FIQ, it enters the
FIQ vector, which contains an immediate return instruction.

> If you want me to work with something more recent then feel free to
> point me at it...

I'll post some of that stuff later today, probably this evening.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
  2014-09-04  9:45                                     ` Russell King - ARM Linux
@ 2014-09-04 10:04                                       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-04 10:04 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Paul E. McKenney, linux-kernel, linux-arm-kernel, kgdb-bugreport,
	patches, linaro-kernel, John Stultz, Anton Vorontsov,
	Colin Cross, kernel-team, Rob Herring, Linus Walleij, Ben Dooks,
	Catalin Marinas, Dave Martin, Fabio Estevam, Frederic Weisbecker,
	Nicolas Pitre, Thomas Gleixner

On 04/09/14 10:45, Russell King - ARM Linux wrote:
> On Thu, Sep 04, 2014 at 10:09:20AM +0100, Daniel Thompson wrote:
>> On 03/09/14 20:34, Russell King - ARM Linux wrote:
>>> I would say that the ARM specific changes to entry-armv.S and setup.c
>>> are correct.  All that you're doing there is to replace the existing
>>> default no-op FIQ handler with some additional code which gets us into
>>> SVC mode and back out, but itself is also a no-op.  In other words, no
>>> real change.
>>>
>>> That's a good first patch, and one which I would actually like to have
>>> in my tree sooner rather than later, so that I can split that out from
>>> my prototype code.
>>
>> So would I!
>>
>> I did some rebasing yesterday to put anything to do with kgdb right at
>> the back of the queue. This "good first patch" is now actually the first
>> patch; where the nofifier used to be it currently calls do_unexp_fiq()
>> making it very close to "no real change".
>>
>> BTW do_unexp_fiq() calls printk() but
> 
> You're making the assumption that something called do_unexp_fiq() before
> your patches.  It seems that that function is dead code, and now that
> you've pointed that out, I will kill this function.
>
> The current situation is that if the CPU receives a FIQ, it enters the
> FIQ vector, which contains an immediate return instruction.

Actually it was the comment above the return instruction in the original
code about getting a message out that made me try to reconnect
do_unexp_fiq().

printk() has reasonably strong defences against being called twice by
the same CPU in that we ought to avoid deadlock if the current CPU owns
the printk locks (although the message would be dropped). I therefore
thought do_unexp_fiq() was a best-effort attempt to inform the user.

That said, assuming the FIQ re-enters, then without a rate limiter the
message will be rather insistent.

For now I will remove calls to do_unexp_fiq().


>> If you want me to work with something more recent then feel free to
>> point me at it...
> 
> I'll post some of that stuff later today, probably this evening.

Hopefully so shall I.


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v10 03/19] arm: fiq: Replace default FIQ handler
@ 2014-09-04 10:04                                       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-04 10:04 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/09/14 10:45, Russell King - ARM Linux wrote:
> On Thu, Sep 04, 2014 at 10:09:20AM +0100, Daniel Thompson wrote:
>> On 03/09/14 20:34, Russell King - ARM Linux wrote:
>>> I would say that the ARM specific changes to entry-armv.S and setup.c
>>> are correct.  All that you're doing there is to replace the existing
>>> default no-op FIQ handler with some additional code which gets us into
>>> SVC mode and back out, but itself is also a no-op.  In other words, no
>>> real change.
>>>
>>> That's a good first patch, and one which I would actually like to have
>>> in my tree sooner rather than later, so that I can split that out from
>>> my prototype code.
>>
>> So would I!
>>
>> I did some rebasing yesterday to put anything to do with kgdb right at
>> the back of the queue. This "good first patch" is now actually the first
>> patch; where the nofifier used to be it currently calls do_unexp_fiq()
>> making it very close to "no real change".
>>
>> BTW do_unexp_fiq() calls printk() but
> 
> You're making the assumption that something called do_unexp_fiq() before
> your patches.  It seems that that function is dead code, and now that
> you've pointed that out, I will kill this function.
>
> The current situation is that if the CPU receives a FIQ, it enters the
> FIQ vector, which contains an immediate return instruction.

Actually it was the comment above the return instruction in the original
code about getting a message out that made me try to reconnect
do_unexp_fiq().

printk() has reasonably strong defences against being called twice by
the same CPU in that we ought to avoid deadlock if the current CPU owns
the printk locks (although the message would be dropped). I therefore
thought do_unexp_fiq() was a best-effort attempt to inform the user.

That said, assuming the FIQ re-enters, then without a rate limiter the
message will be rather insistent.

For now I will remove calls to do_unexp_fiq().


>> If you want me to work with something more recent then feel free to
>> point me at it...
> 
> I'll post some of that stuff later today, probably this evening.

Hopefully so shall I.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v1 0/6] arm: Implement arch_trigger_all_cpu_backtrace
  2014-09-02 13:00                   ` Daniel Thompson
@ 2014-09-04 16:03                     ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-04 16:03 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal

This patchset implements arch_trigger_all_cpu_backtrace for arm.

Non-maskable signalling relies on the kernel being able to access FIQ
and therefore, for devices that implement TrustZone, it will work only on
systems that boot the kernel in secure mode.

Tested on Freescale iMX.6 (both via SysRq-l and by deliberately locking
up the kernel with CONFIG_DEBUG_SPINLOCK=y).

Changes *before* v1:

- This patchset is a hugely cut-down successor to "[PATCH v11 00/19]
  arm: KGDB NMI/FIQ support". Thanks to Thomas Gleixner for suggesting
  the new structure. For historic details see:
        https://lkml.org/lkml/2014/9/2/227

- Fix bug in __fiq_abt (no longer passes a bad struct pt_regs value).
  In fixing this we also remove the useless indirection previously
  found in the fiq_handler macro.

- Make default fiq handler "always on" by migrating from fiq.c to
  traps.c and replace do_unexp_fiq with the new handler (Russell
  King).

- Add arm64 version of fiq.h (Russell King)

- Removed conditional branching and code from irq-gic.c, this is
  replaced by much simpler code that relies on the GIC specification's
  heavy use of read-as-zero/write-ignored (Russell King)


Daniel Thompson (5):
  arm: fiq: Replace default FIQ handler
  arm: smp: Introduce a non-maskable IPI
  arm64: Introduce dummy version of asm/fiq.h
  irqchip: gic: Add support for IPI FIQ
  irqchip: gic: Group 0 workaround.

Russell King (1):
  arm: Implement arch_trigger_all_cpu_backtrace

 arch/arm/Kconfig.debug          |  14 +++
 arch/arm/include/asm/hardirq.h  |   2 +-
 arch/arm/include/asm/irq.h      |   5 +
 arch/arm/include/asm/smp.h      |   7 ++
 arch/arm/kernel/entry-armv.S    | 110 ++++++++++++++++++--
 arch/arm/kernel/setup.c         |   8 +-
 arch/arm/kernel/smp.c           |  67 ++++++++++++
 arch/arm/kernel/traps.c         |  34 +++++-
 arch/arm64/include/asm/fiq.h    |  18 ++++
 drivers/irqchip/irq-gic.c       | 223 +++++++++++++++++++++++++++++++++++++---
 include/linux/irqchip/arm-gic.h |   3 +
 11 files changed, 464 insertions(+), 27 deletions(-)
 create mode 100644 arch/arm64/include/asm/fiq.h

--
1.9.3


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v1 0/6] arm: Implement arch_trigger_all_cpu_backtrace
@ 2014-09-04 16:03                     ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-04 16:03 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset implements arch_trigger_all_cpu_backtrace for arm.

Non-maskable signalling relies on the kernel being able to access FIQ
and therefore, for devices that implement TrustZone, it will work only on
systems that boot the kernel in secure mode.

Tested on Freescale iMX.6 (both via SysRq-l and by deliberately locking
up the kernel with CONFIG_DEBUG_SPINLOCK=y).

Changes *before* v1:

- This patchset is a hugely cut-down successor to "[PATCH v11 00/19]
  arm: KGDB NMI/FIQ support". Thanks to Thomas Gleixner for suggesting
  the new structure. For historic details see:
        https://lkml.org/lkml/2014/9/2/227

- Fix bug in __fiq_abt (no longer passes a bad struct pt_regs value).
  In fixing this we also remove the useless indirection previously
  found in the fiq_handler macro.

- Make default fiq handler "always on" by migrating from fiq.c to
  traps.c and replace do_unexp_fiq with the new handler (Russell
  King).

- Add arm64 version of fiq.h (Russell King)

- Removed conditional branching and code from irq-gic.c, this is
  replaced by much simpler code that relies on the GIC specification's
  heavy use of read-as-zero/write-ignored (Russell King)


Daniel Thompson (5):
  arm: fiq: Replace default FIQ handler
  arm: smp: Introduce a non-maskable IPI
  arm64: Introduce dummy version of asm/fiq.h
  irqchip: gic: Add support for IPI FIQ
  irqchip: gic: Group 0 workaround.

Russell King (1):
  arm: Implement arch_trigger_all_cpu_backtrace

 arch/arm/Kconfig.debug          |  14 +++
 arch/arm/include/asm/hardirq.h  |   2 +-
 arch/arm/include/asm/irq.h      |   5 +
 arch/arm/include/asm/smp.h      |   7 ++
 arch/arm/kernel/entry-armv.S    | 110 ++++++++++++++++++--
 arch/arm/kernel/setup.c         |   8 +-
 arch/arm/kernel/smp.c           |  67 ++++++++++++
 arch/arm/kernel/traps.c         |  34 +++++-
 arch/arm64/include/asm/fiq.h    |  18 ++++
 drivers/irqchip/irq-gic.c       | 223 +++++++++++++++++++++++++++++++++++++---
 include/linux/irqchip/arm-gic.h |   3 +
 11 files changed, 464 insertions(+), 27 deletions(-)
 create mode 100644 arch/arm64/include/asm/fiq.h

--
1.9.3

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v1 1/6] arm: fiq: Replace default FIQ handler
  2014-09-04 16:03                     ` Daniel Thompson
@ 2014-09-04 16:03                       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-04 16:03 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Nicolas Pitre, Catalin Marinas

This patch introduces a new default FIQ handler that is structured in a
similar way to the existing ARM exception handler and result in the FIQ
being handled by C code running on the SVC stack (despite this code run
in the FIQ handler is subject to severe limitations with respect to
locking making normal interaction with the kernel impossible).

This default handler allows concepts that on x86 would be handled using
NMIs to be realized on ARM.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of small fragments
    survive, however without Anton's work to build from this patch would
    not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
---
 arch/arm/kernel/entry-armv.S | 110 +++++++++++++++++++++++++++++++++++++++----
 arch/arm/kernel/setup.c      |   8 +++-
 arch/arm/kernel/traps.c      |  26 ++++++++--
 3 files changed, 130 insertions(+), 14 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 36276cd..03dc0e0 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -146,7 +146,7 @@ ENDPROC(__und_invalid)
 #define SPFIX(code...)
 #endif
 
-	.macro	svc_entry, stack_hole=0
+	.macro	svc_entry, stack_hole=0, call_trace=1
  UNWIND(.fnstart		)
  UNWIND(.save {r0 - pc}		)
 	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
@@ -183,10 +183,35 @@ ENDPROC(__und_invalid)
 	stmia	r7, {r2 - r6}
 
 #ifdef CONFIG_TRACE_IRQFLAGS
+	.if \call_trace
 	bl	trace_hardirqs_off
+	.endif
 #endif
 	.endm
 
+@
+@ svc_exit_via_fiq - similar to svc_exit but switches to FIQ mode before exit
+@
+@ This macro acts in a similar manner to svc_exit but switches to FIQ
+@ mode to restore the final part of the register state.
+@
+@ We cannot use the normal svc_exit procedure because that would
+@ clobber spsr_svc (FIQ could be delivered during the first few instructions
+@ of vector_swi meaning its contents have not been saved anywhere).
+@
+	.macro  svc_exit_via_fiq, rpsr
+
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+	.endm
+
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -295,6 +320,15 @@ __pabt_svc:
 ENDPROC(__pabt_svc)
 
 	.align	5
+__fiq_svc:
+	svc_entry 0, 0
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+	.align	5
 .LCcralign:
 	.word	cr_alignment
 #ifdef MULTI_DABORT
@@ -305,6 +339,38 @@ ENDPROC(__pabt_svc)
 	.word	fp_enter
 
 /*
+ * Abort mode handlers
+ */
+
+@
+@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
+@ and reuses the same macros. However in abort mode we must also
+@ save/restore lr_abt and spsr_abt to make nested aborts safe.
+@
+	.align 5
+__fiq_abt:
+	svc_entry 0, 0
+
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	r0, lr		@ Save lr_abt
+	mrs	r1, spsr	@ Save spsr_abt, abort is now safe
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+	push	{r0 - r1}
+
+	sub	r0, sp, #8			@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+
+	pop	{r0 - r1}
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	lr, r0		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r1	@ Restore spsr_abt
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+/*
  * User mode handlers
  *
  * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
@@ -683,6 +749,18 @@ ENTRY(ret_from_exception)
 ENDPROC(__pabt_usr)
 ENDPROC(ret_from_exception)
 
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+
 /*
  * Register switch for ARMv3 and ARMv4 processors
  * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
@@ -1118,17 +1196,29 @@ vector_addrexcptn:
 	b	vector_addrexcptn
 
 /*=============================================================================
- * Undefined FIQs
+ * FIQ "NMI" handler
  *-----------------------------------------------------------------------------
- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
- * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
- * Basically to switch modes, we *HAVE* to clobber one register...  brain
- * damage alert!  I don't think that we can execute any code in here in any
- * other mode than FIQ...  Ok you can switch to another mode, but you can't
- * get out of that mode without clobbering one register.
+ * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
+ * systems.
  */
-vector_fiq:
-	subs	pc, lr, #4
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
 
 	.globl	vector_fiq_offset
 	.equ	vector_fiq_offset, vector_fiq
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 84db893d..c031063 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -133,6 +133,7 @@ struct stack {
 	u32 irq[3];
 	u32 abt[3];
 	u32 und[3];
+	u32 fiq[3];
 } ____cacheline_aligned;
 
 #ifndef CONFIG_CPU_V7M
@@ -470,7 +471,10 @@ void notrace cpu_init(void)
 	"msr	cpsr_c, %5\n\t"
 	"add	r14, %0, %6\n\t"
 	"mov	sp, r14\n\t"
-	"msr	cpsr_c, %7"
+	"msr	cpsr_c, %7\n\t"
+	"add	r14, %0, %8\n\t"
+	"mov	sp, r14\n\t"
+	"msr	cpsr_c, %9"
 	    :
 	    : "r" (stk),
 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
@@ -479,6 +483,8 @@ void notrace cpu_init(void)
 	      "I" (offsetof(struct stack, abt[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
 	      "I" (offsetof(struct stack, und[0])),
+	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+	      "I" (offsetof(struct stack, fiq[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
 	    : "r14");
 #endif
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index c8e4bb7..7912a9e 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -25,6 +25,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/irq.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -460,10 +461,29 @@ die_sig:
 	arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
 }
 
-asmlinkage void do_unexp_fiq (struct pt_regs *regs)
+/*
+ * Handle FIQ similarly to NMI on x86 systems.
+ *
+ * The runtime environment for NMIs is extremely restrictive
+ * (NMIs can pre-empt critical sections meaning almost all locking is
+ * forbidden) meaning this default FIQ handling must only be used in
+ * circumstances where non-maskability improves robustness, such as
+ * watchdog or debug logic.
+ *
+ * This handler is not appropriate for general purpose use in drivers
+ * platform code and can be overrideen using set_fiq_handler.
+ */
+asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
 {
-	printk("Hmm.  Unexpected FIQ received, but trying to continue\n");
-	printk("You may have a hardware problem...\n");
+#ifdef CONFIG_FIQ
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	nmi_enter();
+	/* nop for now */
+	nmi_exit();
+
+	set_irq_regs(old_regs);
+#endif
 }
 
 /*
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v1 1/6] arm: fiq: Replace default FIQ handler
@ 2014-09-04 16:03                       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-04 16:03 UTC (permalink / raw)
  To: linux-arm-kernel

This patch introduces a new default FIQ handler that is structured in a
similar way to the existing ARM exception handler and result in the FIQ
being handled by C code running on the SVC stack (despite this code run
in the FIQ handler is subject to severe limitations with respect to
locking making normal interaction with the kernel impossible).

This default handler allows concepts that on x86 would be handled using
NMIs to be realized on ARM.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of small fragments
    survive, however without Anton's work to build from this patch would
    not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
---
 arch/arm/kernel/entry-armv.S | 110 +++++++++++++++++++++++++++++++++++++++----
 arch/arm/kernel/setup.c      |   8 +++-
 arch/arm/kernel/traps.c      |  26 ++++++++--
 3 files changed, 130 insertions(+), 14 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 36276cd..03dc0e0 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -146,7 +146,7 @@ ENDPROC(__und_invalid)
 #define SPFIX(code...)
 #endif
 
-	.macro	svc_entry, stack_hole=0
+	.macro	svc_entry, stack_hole=0, call_trace=1
  UNWIND(.fnstart		)
  UNWIND(.save {r0 - pc}		)
 	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
@@ -183,10 +183,35 @@ ENDPROC(__und_invalid)
 	stmia	r7, {r2 - r6}
 
 #ifdef CONFIG_TRACE_IRQFLAGS
+	.if \call_trace
 	bl	trace_hardirqs_off
+	.endif
 #endif
 	.endm
 
+@
+@ svc_exit_via_fiq - similar to svc_exit but switches to FIQ mode before exit
+@
+@ This macro acts in a similar manner to svc_exit but switches to FIQ
+@ mode to restore the final part of the register state.
+@
+@ We cannot use the normal svc_exit procedure because that would
+@ clobber spsr_svc (FIQ could be delivered during the first few instructions
+@ of vector_swi meaning its contents have not been saved anywhere).
+@
+	.macro  svc_exit_via_fiq, rpsr
+
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+	.endm
+
 	.align	5
 __dabt_svc:
 	svc_entry
@@ -295,6 +320,15 @@ __pabt_svc:
 ENDPROC(__pabt_svc)
 
 	.align	5
+__fiq_svc:
+	svc_entry 0, 0
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+	.align	5
 .LCcralign:
 	.word	cr_alignment
 #ifdef MULTI_DABORT
@@ -305,6 +339,38 @@ ENDPROC(__pabt_svc)
 	.word	fp_enter
 
 /*
+ * Abort mode handlers
+ */
+
+@
+@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
+@ and reuses the same macros. However in abort mode we must also
+@ save/restore lr_abt and spsr_abt to make nested aborts safe.
+@
+	.align 5
+__fiq_abt:
+	svc_entry 0, 0
+
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	r0, lr		@ Save lr_abt
+	mrs	r1, spsr	@ Save spsr_abt, abort is now safe
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+	push	{r0 - r1}
+
+	sub	r0, sp, #8			@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+
+	pop	{r0 - r1}
+	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
+	mov	lr, r0		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r1	@ Restore spsr_abt
+	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
+
+	svc_exit_via_fiq r5
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+/*
  * User mode handlers
  *
  * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
@@ -683,6 +749,18 @@ ENTRY(ret_from_exception)
 ENDPROC(__pabt_usr)
 ENDPROC(ret_from_exception)
 
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+
 /*
  * Register switch for ARMv3 and ARMv4 processors
  * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
@@ -1118,17 +1196,29 @@ vector_addrexcptn:
 	b	vector_addrexcptn
 
 /*=============================================================================
- * Undefined FIQs
+ * FIQ "NMI" handler
  *-----------------------------------------------------------------------------
- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
- * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
- * Basically to switch modes, we *HAVE* to clobber one register...  brain
- * damage alert!  I don't think that we can execute any code in here in any
- * other mode than FIQ...  Ok you can switch to another mode, but you can't
- * get out of that mode without clobbering one register.
+ * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
+ * systems.
  */
-vector_fiq:
-	subs	pc, lr, #4
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
 
 	.globl	vector_fiq_offset
 	.equ	vector_fiq_offset, vector_fiq
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 84db893d..c031063 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -133,6 +133,7 @@ struct stack {
 	u32 irq[3];
 	u32 abt[3];
 	u32 und[3];
+	u32 fiq[3];
 } ____cacheline_aligned;
 
 #ifndef CONFIG_CPU_V7M
@@ -470,7 +471,10 @@ void notrace cpu_init(void)
 	"msr	cpsr_c, %5\n\t"
 	"add	r14, %0, %6\n\t"
 	"mov	sp, r14\n\t"
-	"msr	cpsr_c, %7"
+	"msr	cpsr_c, %7\n\t"
+	"add	r14, %0, %8\n\t"
+	"mov	sp, r14\n\t"
+	"msr	cpsr_c, %9"
 	    :
 	    : "r" (stk),
 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
@@ -479,6 +483,8 @@ void notrace cpu_init(void)
 	      "I" (offsetof(struct stack, abt[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
 	      "I" (offsetof(struct stack, und[0])),
+	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+	      "I" (offsetof(struct stack, fiq[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
 	    : "r14");
 #endif
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index c8e4bb7..7912a9e 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -25,6 +25,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/irq.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -460,10 +461,29 @@ die_sig:
 	arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
 }
 
-asmlinkage void do_unexp_fiq (struct pt_regs *regs)
+/*
+ * Handle FIQ similarly to NMI on x86 systems.
+ *
+ * The runtime environment for NMIs is extremely restrictive
+ * (NMIs can pre-empt critical sections meaning almost all locking is
+ * forbidden) meaning this default FIQ handling must only be used in
+ * circumstances where non-maskability improves robustness, such as
+ * watchdog or debug logic.
+ *
+ * This handler is not appropriate for general purpose use in drivers
+ * platform code and can be overrideen using set_fiq_handler.
+ */
+asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
 {
-	printk("Hmm.  Unexpected FIQ received, but trying to continue\n");
-	printk("You may have a hardware problem...\n");
+#ifdef CONFIG_FIQ
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	nmi_enter();
+	/* nop for now */
+	nmi_exit();
+
+	set_irq_regs(old_regs);
+#endif
 }
 
 /*
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v1 2/6] arm: smp: Introduce a non-maskable IPI
  2014-09-04 16:03                     ` Daniel Thompson
@ 2014-09-04 16:03                       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-04 16:03 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal

This patch introduces a new IPI intended to be routed to FIQ rather
than IRQ. An IPI based upon FIQ can be used to implement debug
features that require non-maskable interrupts.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
---
 arch/arm/include/asm/hardirq.h | 2 +-
 arch/arm/include/asm/smp.h     | 3 +++
 arch/arm/kernel/smp.c          | 7 +++++++
 3 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
index fe3ea77..5df33e3 100644
--- a/arch/arm/include/asm/hardirq.h
+++ b/arch/arm/include/asm/hardirq.h
@@ -5,7 +5,7 @@
 #include <linux/threads.h>
 #include <asm/irq.h>
 
-#define NR_IPI	8
+#define NR_IPI	9
 
 typedef struct {
 	unsigned int __softirq_pending;
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2ec765c..0e23384 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -20,6 +20,9 @@
 
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
+/* bitmap of IPIs that must be signalled using FIQ */
+#define SMP_IPI_FIQ_MASK 0x0100
+
 struct seq_file;
 
 /*
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9388a3d..b2404d0 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -72,6 +72,7 @@ enum ipi_msg_type {
 	IPI_CPU_STOP,
 	IPI_IRQ_WORK,
 	IPI_COMPLETION,
+	IPI_FIQ,
 };
 
 static DECLARE_COMPLETION(cpu_running);
@@ -451,6 +452,7 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
 	S(IPI_CPU_STOP, "CPU stop interrupts"),
 	S(IPI_IRQ_WORK, "IRQ work interrupts"),
 	S(IPI_COMPLETION, "completion interrupts"),
+	S(IPI_FIQ, "FIQ interrupts"),
 };
 
 static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
@@ -618,6 +620,11 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		irq_exit();
 		break;
 
+	case IPI_FIQ:
+		BUILD_BUG_ON(SMP_IPI_FIQ_MASK != BIT(IPI_FIQ));
+		pr_warn("CPU%u: IPI FIQ delivered via IRQ vector\n", cpu);
+		break;
+
 	default:
 		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
 		       cpu, ipinr);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v1 2/6] arm: smp: Introduce a non-maskable IPI
@ 2014-09-04 16:03                       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-04 16:03 UTC (permalink / raw)
  To: linux-arm-kernel

This patch introduces a new IPI intended to be routed to FIQ rather
than IRQ. An IPI based upon FIQ can be used to implement debug
features that require non-maskable interrupts.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
---
 arch/arm/include/asm/hardirq.h | 2 +-
 arch/arm/include/asm/smp.h     | 3 +++
 arch/arm/kernel/smp.c          | 7 +++++++
 3 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
index fe3ea77..5df33e3 100644
--- a/arch/arm/include/asm/hardirq.h
+++ b/arch/arm/include/asm/hardirq.h
@@ -5,7 +5,7 @@
 #include <linux/threads.h>
 #include <asm/irq.h>
 
-#define NR_IPI	8
+#define NR_IPI	9
 
 typedef struct {
 	unsigned int __softirq_pending;
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2ec765c..0e23384 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -20,6 +20,9 @@
 
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
+/* bitmap of IPIs that must be signalled using FIQ */
+#define SMP_IPI_FIQ_MASK 0x0100
+
 struct seq_file;
 
 /*
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9388a3d..b2404d0 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -72,6 +72,7 @@ enum ipi_msg_type {
 	IPI_CPU_STOP,
 	IPI_IRQ_WORK,
 	IPI_COMPLETION,
+	IPI_FIQ,
 };
 
 static DECLARE_COMPLETION(cpu_running);
@@ -451,6 +452,7 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
 	S(IPI_CPU_STOP, "CPU stop interrupts"),
 	S(IPI_IRQ_WORK, "IRQ work interrupts"),
 	S(IPI_COMPLETION, "completion interrupts"),
+	S(IPI_FIQ, "FIQ interrupts"),
 };
 
 static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
@@ -618,6 +620,11 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		irq_exit();
 		break;
 
+	case IPI_FIQ:
+		BUILD_BUG_ON(SMP_IPI_FIQ_MASK != BIT(IPI_FIQ));
+		pr_warn("CPU%u: IPI FIQ delivered via IRQ vector\n", cpu);
+		break;
+
 	default:
 		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
 		       cpu, ipinr);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v1 3/6] arm64: Introduce dummy version of asm/fiq.h
  2014-09-04 16:03                     ` Daniel Thompson
@ 2014-09-04 16:03                       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-04 16:03 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Catalin Marinas, Will Deacon

Drivers that are shared between arm and arm64 and which employ
FIQ on arm cannot include asm/fiq.h without #ifdef'ing. This patch
introduces a dummy version of asm/fiq.h to arm64 to avoid this.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
 arch/arm64/include/asm/fiq.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 arch/arm64/include/asm/fiq.h

diff --git a/arch/arm64/include/asm/fiq.h b/arch/arm64/include/asm/fiq.h
new file mode 100644
index 0000000..909ec54
--- /dev/null
+++ b/arch/arm64/include/asm/fiq.h
@@ -0,0 +1,18 @@
+/*
+ * arch/arm64/include/asm/fiq.h
+ *
+ * Placeholder to reduce #ifdef'ing in shared arm/arm64 drivers.
+ */
+
+#ifndef __ASM_FIQ_H
+#define __ASM_FIQ_H
+
+/*
+ * This placeholder allows code of the following form to be simplified:
+ *
+ * #ifdef CONFIG_FIQ
+ * #include <asm/fiq.h>
+ * #endif
+ */
+
+#endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v1 3/6] arm64: Introduce dummy version of asm/fiq.h
@ 2014-09-04 16:03                       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-04 16:03 UTC (permalink / raw)
  To: linux-arm-kernel

Drivers that are shared between arm and arm64 and which employ
FIQ on arm cannot include asm/fiq.h without #ifdef'ing. This patch
introduces a dummy version of asm/fiq.h to arm64 to avoid this.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
 arch/arm64/include/asm/fiq.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 arch/arm64/include/asm/fiq.h

diff --git a/arch/arm64/include/asm/fiq.h b/arch/arm64/include/asm/fiq.h
new file mode 100644
index 0000000..909ec54
--- /dev/null
+++ b/arch/arm64/include/asm/fiq.h
@@ -0,0 +1,18 @@
+/*
+ * arch/arm64/include/asm/fiq.h
+ *
+ * Placeholder to reduce #ifdef'ing in shared arm/arm64 drivers.
+ */
+
+#ifndef __ASM_FIQ_H
+#define __ASM_FIQ_H
+
+/*
+ * This placeholder allows code of the following form to be simplified:
+ *
+ * #ifdef CONFIG_FIQ
+ * #include <asm/fiq.h>
+ * #endif
+ */
+
+#endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v1 4/6] irqchip: gic: Add support for IPI FIQ
  2014-09-04 16:03                     ` Daniel Thompson
@ 2014-09-04 16:03                       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-04 16:03 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Jason Cooper

This patch provides support for arm's newly added IPI FIQ. It works
by placing all interrupt sources *except* IPI FIQ in group 1 and
then flips a configuration bit in the GIC such that group 1
interrupts use IRQ and group 0 interrupts use FIQ.

All GIC hardware except GICv1-without-TrustZone support provides a means
to group exceptions into group 0 and group 1. However the hardware
functionality is unavailable to the kernel when a secure monitor is
present because access to the grouping registers are prohibited outside
"secure world" (a feature that allows grouping to be used to allow
hardware peripherals to send interrupts into the secure world). However
when grouping is not available we can rely on the GIC's RAZ/WI semantics
and avoid conditional code.

Tested on Freescale i.MX6 (quad A9, GICv1-with-TrustZone running in
secure mode).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
---
 arch/arm/kernel/traps.c         |   7 +-
 drivers/irqchip/irq-gic.c       | 171 +++++++++++++++++++++++++++++++++++++---
 include/linux/irqchip/arm-gic.h |   3 +
 3 files changed, 171 insertions(+), 10 deletions(-)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 7912a9e..2c219c7 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/irq.h>
+#include <linux/irqchip/arm-gic.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -479,7 +480,11 @@ asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
 	nmi_enter();
-	/* nop for now */
+
+#ifdef CONFIG_ARM_GIC
+	gic_handle_fiq_ipi();
+#endif
+
 	nmi_exit();
 
 	set_irq_regs(old_regs);
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4b959e6..ffc64ed 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,8 +39,10 @@
 #include <linux/slab.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/ratelimit.h>
 
 #include <asm/cputype.h>
+#include <asm/fiq.h>
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
@@ -48,6 +50,10 @@
 #include "irq-gic-common.h"
 #include "irqchip.h"
 
+#ifndef SMP_IPI_FIQ_MASK
+#define SMP_IPI_FIQ_MASK 0
+#endif
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -71,6 +77,8 @@ struct gic_chip_data {
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+/* A fiq-safe spinlock must only be locked when the FIQ is masked */
+static DEFINE_RAW_SPINLOCK(fiq_safe_migration_lock);
 
 /*
  * The GIC mapping of CPU interfaces does not necessarily match
@@ -325,6 +333,106 @@ static struct irq_chip gic_chip = {
 	.irq_set_wake		= gic_set_wake,
 };
 
+#ifdef CONFIG_FIQ
+/*
+ * Shift an interrupt between Group 0 and Group 1.
+ *
+ * In addition to changing the group we also modify the priority to
+ * match what "ARM strongly recommends" for a system where no Group 1
+ * interrupt must ever preempt a Group 0 interrupt.
+ *
+ * If is safe to call this function on systems which do not support
+ * grouping (it will have no effect).
+ */
+static void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				int group)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_mask = BIT(hwirq % 32);
+	u32 grp_val;
+
+	unsigned int pri_reg = (hwirq / 4) * 4;
+	u32 pri_mask = BIT(7 + ((hwirq % 4) * 8));
+	u32 pri_val;
+
+	/*
+	 * Systems which do not support grouping will have no bits
+	 * set in IGROUP[0] (and all systems which do will have set bits).
+	 */
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + 0);
+	if (!grp_val)
+		return;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(base + GIC_DIST_PRI + pri_reg);
+
+	if (group) {
+		grp_val |= grp_mask;
+		pri_val |= pri_mask;
+	} else {
+		grp_val &= ~grp_mask;
+		pri_val &= ~pri_mask;
+	}
+
+	writel_relaxed(grp_val, base + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, base + GIC_DIST_PRI + pri_reg);
+
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+/*
+ * Test which group an interrupt belongs to.
+ *
+ * Returns 0 if the controller does not support grouping.
+ */
+static int gic_get_group_irq(void __iomem *base, unsigned int hwirq)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_val;
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+
+	return (grp_val >> (hwirq % 32)) & 1;
+}
+
+/*
+ * Fully acknowledge (both ack and eoi) any outstanding FIQ-based IPI,
+ * otherwise do nothing.
+ */
+void gic_handle_fiq_ipi(void)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	unsigned long irqstat, irqnr;
+
+	if (WARN_ON(!in_nmi()))
+		return;
+
+	while ((1u << readl_relaxed(cpu_base + GIC_CPU_HIGHPRI)) &
+	       SMP_IPI_FIQ_MASK) {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		WARN_RATELIMIT(irqnr > 16,
+			       "Unexpected irqnr %lu (bad prioritization?)\n",
+			       irqnr);
+	}
+}
+#else /* CONFIG_FIQ */
+static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				     int group)
+{
+}
+
+static inline int gic_get_group_irq(void __iomem *base, unsigned int hwirq)
+{
+	return 0;
+}
+#endif /* CONFIG_FIQ */
+
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
 	if (gic_nr >= MAX_GIC_NR)
@@ -373,7 +481,18 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 
 	gic_dist_config(base, gic_irqs, NULL);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Set all global interrupts to be group 1 (RAZ/WI when not
+	 * available)
+	 */
+	for (i = 32; i < gic_irqs; i += 32)
+		writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	writel_relaxed(3, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -382,6 +501,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	void __iomem *base = gic_data_cpu_base(gic);
 	unsigned int cpu_mask, cpu = smp_processor_id();
 	int i;
+	unsigned long secure_irqs, secure_irq;
 
 	/*
 	 * Get what the GIC says our CPU mask is.
@@ -400,8 +520,21 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 
 	gic_cpu_config(dist_base, NULL);
 
+	/*
+	 * Set any PPI and SGI interrupts not set in SMP_IPI_FIQ_MASK
+	 * to be group 1 (RAZ/WI when not available)
+	 */
+	writel_relaxed(~SMP_IPI_FIQ_MASK, dist_base + GIC_DIST_IGROUP + 0);
+
+	/*
+	 * Update the priority of any resulting group0 interrupts.
+	 */
+	secure_irqs = ~readl_relaxed(dist_base + GIC_DIST_IGROUP + 0);
+	for_each_set_bit(secure_irq, &secure_irqs, 16)
+		gic_set_group_irq(dist_base, i, 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -485,7 +618,7 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	writel_relaxed(3, dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -542,7 +675,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -604,8 +737,19 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
 	unsigned long flags, map = 0;
+	unsigned long softint;
 
-	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+	/*
+	 * The locking in this function ensures we don't use stale cpu mappings
+	 * and thus we never route an IPI to the wrong physical core during a
+	 * big.LITTLE switch. The switch code takes both of these locks meaning
+	 * we can choose whichever lock is safe to use from our current calling
+	 * context.
+	 */
+	if (in_nmi())
+		raw_spin_lock(&fiq_safe_migration_lock);
+	else
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
 	/* Convert our logical CPU mask into a physical one. */
 	for_each_cpu(cpu, mask)
@@ -618,9 +762,16 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
-
-	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+	softint = map << 16 | irq;
+	if (gic_get_group_irq(gic_data_dist_base(&gic_data[0]), irq))
+		softint |= 0x8000;
+	writel_relaxed(softint,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+
+	if (in_nmi())
+		raw_spin_unlock(&fiq_safe_migration_lock);
+	else
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 #endif
 
@@ -668,7 +819,7 @@ int gic_get_cpu_id(unsigned int cpu)
  * Migrate all peripheral interrupts with a target matching the current CPU
  * to the interface corresponding to @new_cpu_id.  The CPU interface mapping
  * is also updated.  Targets to other CPU interfaces are unchanged.
- * This must be called with IRQs locally disabled.
+ * This must be called with IRQ and FIQ locally disabled.
  */
 void gic_migrate_target(unsigned int new_cpu_id)
 {
@@ -690,6 +841,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 	ror_val = (cur_cpu_id - new_cpu_id) & 31;
 
 	raw_spin_lock(&irq_controller_lock);
+	raw_spin_lock(&fiq_safe_migration_lock);
 
 	/* Update the target interface for this logical CPU */
 	gic_cpu_map[cpu] = 1 << new_cpu_id;
@@ -709,6 +861,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 		}
 	}
 
+	raw_spin_unlock(&fiq_safe_migration_lock);
 	raw_spin_unlock(&irq_controller_lock);
 
 	/*
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 45e2d8c..52a5676 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops
 {
 	gic_routable_irq_domain_ops = ops;
 }
+
+void gic_handle_fiq_ipi(void);
+
 #endif /* __ASSEMBLY */
 #endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v1 4/6] irqchip: gic: Add support for IPI FIQ
@ 2014-09-04 16:03                       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-04 16:03 UTC (permalink / raw)
  To: linux-arm-kernel

This patch provides support for arm's newly added IPI FIQ. It works
by placing all interrupt sources *except* IPI FIQ in group 1 and
then flips a configuration bit in the GIC such that group 1
interrupts use IRQ and group 0 interrupts use FIQ.

All GIC hardware except GICv1-without-TrustZone support provides a means
to group exceptions into group 0 and group 1. However the hardware
functionality is unavailable to the kernel when a secure monitor is
present because access to the grouping registers are prohibited outside
"secure world" (a feature that allows grouping to be used to allow
hardware peripherals to send interrupts into the secure world). However
when grouping is not available we can rely on the GIC's RAZ/WI semantics
and avoid conditional code.

Tested on Freescale i.MX6 (quad A9, GICv1-with-TrustZone running in
secure mode).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
---
 arch/arm/kernel/traps.c         |   7 +-
 drivers/irqchip/irq-gic.c       | 171 +++++++++++++++++++++++++++++++++++++---
 include/linux/irqchip/arm-gic.h |   3 +
 3 files changed, 171 insertions(+), 10 deletions(-)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 7912a9e..2c219c7 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/irq.h>
+#include <linux/irqchip/arm-gic.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -479,7 +480,11 @@ asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
 	nmi_enter();
-	/* nop for now */
+
+#ifdef CONFIG_ARM_GIC
+	gic_handle_fiq_ipi();
+#endif
+
 	nmi_exit();
 
 	set_irq_regs(old_regs);
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4b959e6..ffc64ed 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,8 +39,10 @@
 #include <linux/slab.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/ratelimit.h>
 
 #include <asm/cputype.h>
+#include <asm/fiq.h>
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
@@ -48,6 +50,10 @@
 #include "irq-gic-common.h"
 #include "irqchip.h"
 
+#ifndef SMP_IPI_FIQ_MASK
+#define SMP_IPI_FIQ_MASK 0
+#endif
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -71,6 +77,8 @@ struct gic_chip_data {
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+/* A fiq-safe spinlock must only be locked when the FIQ is masked */
+static DEFINE_RAW_SPINLOCK(fiq_safe_migration_lock);
 
 /*
  * The GIC mapping of CPU interfaces does not necessarily match
@@ -325,6 +333,106 @@ static struct irq_chip gic_chip = {
 	.irq_set_wake		= gic_set_wake,
 };
 
+#ifdef CONFIG_FIQ
+/*
+ * Shift an interrupt between Group 0 and Group 1.
+ *
+ * In addition to changing the group we also modify the priority to
+ * match what "ARM strongly recommends" for a system where no Group 1
+ * interrupt must ever preempt a Group 0 interrupt.
+ *
+ * If is safe to call this function on systems which do not support
+ * grouping (it will have no effect).
+ */
+static void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				int group)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_mask = BIT(hwirq % 32);
+	u32 grp_val;
+
+	unsigned int pri_reg = (hwirq / 4) * 4;
+	u32 pri_mask = BIT(7 + ((hwirq % 4) * 8));
+	u32 pri_val;
+
+	/*
+	 * Systems which do not support grouping will have no bits
+	 * set in IGROUP[0] (and all systems which do will have set bits).
+	 */
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + 0);
+	if (!grp_val)
+		return;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(base + GIC_DIST_PRI + pri_reg);
+
+	if (group) {
+		grp_val |= grp_mask;
+		pri_val |= pri_mask;
+	} else {
+		grp_val &= ~grp_mask;
+		pri_val &= ~pri_mask;
+	}
+
+	writel_relaxed(grp_val, base + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, base + GIC_DIST_PRI + pri_reg);
+
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+/*
+ * Test which group an interrupt belongs to.
+ *
+ * Returns 0 if the controller does not support grouping.
+ */
+static int gic_get_group_irq(void __iomem *base, unsigned int hwirq)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_val;
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+
+	return (grp_val >> (hwirq % 32)) & 1;
+}
+
+/*
+ * Fully acknowledge (both ack and eoi) any outstanding FIQ-based IPI,
+ * otherwise do nothing.
+ */
+void gic_handle_fiq_ipi(void)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	unsigned long irqstat, irqnr;
+
+	if (WARN_ON(!in_nmi()))
+		return;
+
+	while ((1u << readl_relaxed(cpu_base + GIC_CPU_HIGHPRI)) &
+	       SMP_IPI_FIQ_MASK) {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		WARN_RATELIMIT(irqnr > 16,
+			       "Unexpected irqnr %lu (bad prioritization?)\n",
+			       irqnr);
+	}
+}
+#else /* CONFIG_FIQ */
+static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				     int group)
+{
+}
+
+static inline int gic_get_group_irq(void __iomem *base, unsigned int hwirq)
+{
+	return 0;
+}
+#endif /* CONFIG_FIQ */
+
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
 	if (gic_nr >= MAX_GIC_NR)
@@ -373,7 +481,18 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 
 	gic_dist_config(base, gic_irqs, NULL);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Set all global interrupts to be group 1 (RAZ/WI when not
+	 * available)
+	 */
+	for (i = 32; i < gic_irqs; i += 32)
+		writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	writel_relaxed(3, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -382,6 +501,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	void __iomem *base = gic_data_cpu_base(gic);
 	unsigned int cpu_mask, cpu = smp_processor_id();
 	int i;
+	unsigned long secure_irqs, secure_irq;
 
 	/*
 	 * Get what the GIC says our CPU mask is.
@@ -400,8 +520,21 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 
 	gic_cpu_config(dist_base, NULL);
 
+	/*
+	 * Set any PPI and SGI interrupts not set in SMP_IPI_FIQ_MASK
+	 * to be group 1 (RAZ/WI when not available)
+	 */
+	writel_relaxed(~SMP_IPI_FIQ_MASK, dist_base + GIC_DIST_IGROUP + 0);
+
+	/*
+	 * Update the priority of any resulting group0 interrupts.
+	 */
+	secure_irqs = ~readl_relaxed(dist_base + GIC_DIST_IGROUP + 0);
+	for_each_set_bit(secure_irq, &secure_irqs, 16)
+		gic_set_group_irq(dist_base, i, 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -485,7 +618,7 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	writel_relaxed(3, dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -542,7 +675,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -604,8 +737,19 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
 	unsigned long flags, map = 0;
+	unsigned long softint;
 
-	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+	/*
+	 * The locking in this function ensures we don't use stale cpu mappings
+	 * and thus we never route an IPI to the wrong physical core during a
+	 * big.LITTLE switch. The switch code takes both of these locks meaning
+	 * we can choose whichever lock is safe to use from our current calling
+	 * context.
+	 */
+	if (in_nmi())
+		raw_spin_lock(&fiq_safe_migration_lock);
+	else
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
 	/* Convert our logical CPU mask into a physical one. */
 	for_each_cpu(cpu, mask)
@@ -618,9 +762,16 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
-
-	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+	softint = map << 16 | irq;
+	if (gic_get_group_irq(gic_data_dist_base(&gic_data[0]), irq))
+		softint |= 0x8000;
+	writel_relaxed(softint,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+
+	if (in_nmi())
+		raw_spin_unlock(&fiq_safe_migration_lock);
+	else
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 #endif
 
@@ -668,7 +819,7 @@ int gic_get_cpu_id(unsigned int cpu)
  * Migrate all peripheral interrupts with a target matching the current CPU
  * to the interface corresponding to @new_cpu_id.  The CPU interface mapping
  * is also updated.  Targets to other CPU interfaces are unchanged.
- * This must be called with IRQs locally disabled.
+ * This must be called with IRQ and FIQ locally disabled.
  */
 void gic_migrate_target(unsigned int new_cpu_id)
 {
@@ -690,6 +841,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 	ror_val = (cur_cpu_id - new_cpu_id) & 31;
 
 	raw_spin_lock(&irq_controller_lock);
+	raw_spin_lock(&fiq_safe_migration_lock);
 
 	/* Update the target interface for this logical CPU */
 	gic_cpu_map[cpu] = 1 << new_cpu_id;
@@ -709,6 +861,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 		}
 	}
 
+	raw_spin_unlock(&fiq_safe_migration_lock);
 	raw_spin_unlock(&irq_controller_lock);
 
 	/*
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 45e2d8c..52a5676 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops
 {
 	gic_routable_irq_domain_ops = ops;
 }
+
+void gic_handle_fiq_ipi(void);
+
 #endif /* __ASSEMBLY */
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v1 5/6] irqchip: gic: Group 0 workaround.
  2014-09-04 16:03                     ` Daniel Thompson
@ 2014-09-04 16:03                       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-04 16:03 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Jason Cooper

An ARM system based on GICv1 that runs by default in secure mode and
uses both group 0 and group 1 interrupts (in order to exploit FIQ)
will suffer a problem where the IRQ handler occasionally spuriously
acknowledges a group 0 (FIQ) interrupt.

This can be prevented by ensuring the IRQ handler makes non-secure
memory access to the GIC registers but this is complex because
the non-secure bits cannot be apply to 4k pages (the bit is one level
up in the page table and applies to 1MB at a time).

This workaround uses an alternative approach that spots the spurious
acknowledgment and regenerates the FIQ. This keeps the workaround
exclusively within the GIC driver (although there is a runtime
perforamnce penalty resulting from this approach).

Reported-by: Harro Haan <hrhaan@gmail.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Tested-by: Harro Haan <hrhaan@gmail.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
---
 drivers/irqchip/irq-gic.c | 52 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 49 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index ffc64ed..4b25ed9 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -267,14 +267,59 @@ static int gic_set_wake(struct irq_data *d, unsigned int on)
 #define gic_set_wake	NULL
 #endif
 
+#ifdef CONFIG_FIQ
+/* This is a software emulation of the Aliased Interrupt Acknowledge Register
+ * (GIC_AIAR) found in GICv2+.
+ */
+static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32 irqstat)
+{
+	u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	void __iomem *dist_base = gic_data_dist_base(gic);
+	u32 offset, mask;
+
+	if (readl_relaxed(dist_base + GIC_DIST_IGROUP + 0) || irqnr >= 1021)
+		return irqstat;
+
+	offset = irqnr / 32 * 4;
+	mask = 1 << (irqnr % 32);
+	if (readl_relaxed(dist_base + GIC_DIST_IGROUP + offset) & mask)
+		return irqstat;
+
+	/* this interrupt must be taken as a FIQ so put it back into the
+	 * pending state and end our own servicing of it.
+	 */
+	writel_relaxed(mask, dist_base + GIC_DIST_PENDING_SET + offset);
+	readl_relaxed(dist_base + GIC_DIST_PENDING_SET + offset);
+	writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
+
+	return 1023;
+}
+
+static u32 gic_ack_irq(struct gic_chip_data *gic)
+{
+	u32 irqstat;
+
+	local_fiq_disable();
+	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+	irqstat = gic_handle_spurious_group_0(gic, irqstat);
+	local_fiq_enable();
+
+	return irqstat;
+}
+#else
+static u32 gic_ack_irq(struct gic_chip_data *gic)
+{
+	return readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+}
+#endif
+
 static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
 	u32 irqstat, irqnr;
 	struct gic_chip_data *gic = &gic_data[0];
-	void __iomem *cpu_base = gic_data_cpu_base(gic);
 
 	do {
-		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		irqstat = gic_ack_irq(gic);
 		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
 
 		if (likely(irqnr > 15 && irqnr < 1021)) {
@@ -283,7 +328,8 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 			continue;
 		}
 		if (irqnr < 16) {
-			writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+			writel_relaxed(irqstat,
+				       gic_data_cpu_base(gic) + GIC_CPU_EOI);
 #ifdef CONFIG_SMP
 			handle_IPI(irqnr, regs);
 #endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v1 5/6] irqchip: gic: Group 0 workaround.
@ 2014-09-04 16:03                       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-04 16:03 UTC (permalink / raw)
  To: linux-arm-kernel

An ARM system based on GICv1 that runs by default in secure mode and
uses both group 0 and group 1 interrupts (in order to exploit FIQ)
will suffer a problem where the IRQ handler occasionally spuriously
acknowledges a group 0 (FIQ) interrupt.

This can be prevented by ensuring the IRQ handler makes non-secure
memory access to the GIC registers but this is complex because
the non-secure bits cannot be apply to 4k pages (the bit is one level
up in the page table and applies to 1MB at a time).

This workaround uses an alternative approach that spots the spurious
acknowledgment and regenerates the FIQ. This keeps the workaround
exclusively within the GIC driver (although there is a runtime
perforamnce penalty resulting from this approach).

Reported-by: Harro Haan <hrhaan@gmail.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Tested-by: Harro Haan <hrhaan@gmail.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
---
 drivers/irqchip/irq-gic.c | 52 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 49 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index ffc64ed..4b25ed9 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -267,14 +267,59 @@ static int gic_set_wake(struct irq_data *d, unsigned int on)
 #define gic_set_wake	NULL
 #endif
 
+#ifdef CONFIG_FIQ
+/* This is a software emulation of the Aliased Interrupt Acknowledge Register
+ * (GIC_AIAR) found in GICv2+.
+ */
+static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32 irqstat)
+{
+	u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	void __iomem *dist_base = gic_data_dist_base(gic);
+	u32 offset, mask;
+
+	if (readl_relaxed(dist_base + GIC_DIST_IGROUP + 0) || irqnr >= 1021)
+		return irqstat;
+
+	offset = irqnr / 32 * 4;
+	mask = 1 << (irqnr % 32);
+	if (readl_relaxed(dist_base + GIC_DIST_IGROUP + offset) & mask)
+		return irqstat;
+
+	/* this interrupt must be taken as a FIQ so put it back into the
+	 * pending state and end our own servicing of it.
+	 */
+	writel_relaxed(mask, dist_base + GIC_DIST_PENDING_SET + offset);
+	readl_relaxed(dist_base + GIC_DIST_PENDING_SET + offset);
+	writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
+
+	return 1023;
+}
+
+static u32 gic_ack_irq(struct gic_chip_data *gic)
+{
+	u32 irqstat;
+
+	local_fiq_disable();
+	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+	irqstat = gic_handle_spurious_group_0(gic, irqstat);
+	local_fiq_enable();
+
+	return irqstat;
+}
+#else
+static u32 gic_ack_irq(struct gic_chip_data *gic)
+{
+	return readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+}
+#endif
+
 static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
 	u32 irqstat, irqnr;
 	struct gic_chip_data *gic = &gic_data[0];
-	void __iomem *cpu_base = gic_data_cpu_base(gic);
 
 	do {
-		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		irqstat = gic_ack_irq(gic);
 		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
 
 		if (likely(irqnr > 15 && irqnr < 1021)) {
@@ -283,7 +328,8 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 			continue;
 		}
 		if (irqnr < 16) {
-			writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+			writel_relaxed(irqstat,
+				       gic_data_cpu_base(gic) + GIC_CPU_EOI);
 #ifdef CONFIG_SMP
 			handle_IPI(irqnr, regs);
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v1 6/6] arm: Implement arch_trigger_all_cpu_backtrace
  2014-09-04 16:03                     ` Daniel Thompson
@ 2014-09-04 16:03                       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-04 16:03 UTC (permalink / raw)
  To: Russell King
  Cc: linux-kernel, linux-arm-kernel, patches, linaro-kernel,
	John Stultz, Thomas Gleixner, Sumit Semwal, Daniel Thompson

From: Russell King <linux@arm.linux.org.uk>

Currently arm does not implement arch_trigger_all_cpu_backtrace because,
on SMP systems, there has never before been a means to route a
non-maskable interrupt to the other CPUs in the system. With the
introduction of IPI FIQ this is no longer the case. This patch
provides an implementation of arch_trigger_all_cpu_backtrace and
the associated KConfig machinary to enable it.

This is mostly Russell's code but since it was shared as an example rather
than a fully fledged patch currently this code is currently
Not-yet-signed-off-by: Russell King <linux@arm.linux.org.uk>

[Fill in headers and Kconfig, checkpatch.pl substitutions: CONFIG_NR_CPUS
for NR_CPUS and pr_warn() for printk(KERN_WARNING, )]
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/Kconfig.debug     | 14 +++++++++++
 arch/arm/include/asm/irq.h |  5 ++++
 arch/arm/include/asm/smp.h |  4 ++++
 arch/arm/kernel/smp.c      | 60 ++++++++++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/traps.c    |  3 +++
 5 files changed, 86 insertions(+)

diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index b11ad54..2fa932d 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -1281,4 +1281,18 @@ config DEBUG_SET_MODULE_RONX
 	  against certain classes of kernel exploits.
 	  If in doubt, say "N".
 
+config ARM_BACKTRACE_TRIGGERING
+	bool "Support non-maskable backtrace triggering"
+	depends on SMP
+	select FIQ
+	help
+	  Say Y here if you want to provide support for non-maskable
+	  backtrace triggering. This is used to generate a backtrace
+	  from all CPUs in a non-responsive system. Backtrace requests
+	  can be issued by lockup and hung task detectors, spin lock
+	  debugging or magic sysrq.
+
+	  This option is only effective when the kernel is run on a
+	  platform capable of generating FIQs.
+
 endmenu
diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h
index 53c15de..a5cc2ed 100644
--- a/arch/arm/include/asm/irq.h
+++ b/arch/arm/include/asm/irq.h
@@ -35,6 +35,11 @@ extern void (*handle_arch_irq)(struct pt_regs *);
 extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
 #endif
 
+#ifdef CONFIG_ARM_BACKTRACE_TRIGGERING
+void arch_trigger_all_cpu_backtrace(bool);
+#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace
+#endif
+
 #endif
 
 #endif
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 0e23384..d20bd95 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -90,6 +90,10 @@ extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
 
 extern int register_ipi_completion(struct completion *completion, int cpu);
 
+#ifdef CONFIG_ARM_BACKTRACE_TRIGGERING
+extern void ipi_cpu_backtrace(struct pt_regs *regs);
+#endif
+
 struct smp_operations {
 #ifdef CONFIG_SMP
 	/*
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index b2404d0..d1765a6 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -554,6 +554,63 @@ static void ipi_complete(unsigned int cpu)
 	complete(per_cpu(cpu_completion, cpu));
 }
 
+#ifdef CONFIG_ARM_BACKTRACE_TRIGGERING
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, CONFIG_NR_CPUS) __read_mostly;
+
+void ipi_cpu_backtrace(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+
+	if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
+		static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
+
+		arch_spin_lock(&lock);
+		pr_warn("FIQ backtrace for cpu %d\n", cpu);
+		show_regs(regs);
+		arch_spin_unlock(&lock);
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+	}
+}
+
+void arch_trigger_all_cpu_backtrace(bool include_self)
+{
+	static unsigned long backtrace_flag;
+	int i, cpu = get_cpu();
+
+	if (test_and_set_bit(0, &backtrace_flag)) {
+		/*
+		 * If there is already a trigger_all_cpu_backtrace() in progress
+		 * (backtrace_flag == 1), don't output double cpu dump infos.
+		 */
+		put_cpu();
+		return;
+	}
+
+	cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
+	if (!include_self)
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+
+	if (!cpumask_empty(to_cpumask(backtrace_mask))) {
+		pr_info("Sending FIQ to %s CPUs:\n",
+			(include_self ? "all" : "other"));
+		smp_cross_call(to_cpumask(backtrace_mask), IPI_FIQ);
+	}
+
+	/* Wait for up to 10 seconds for all CPUs to do the backtrace */
+	for (i = 0; i < 10 * 1000; i++) {
+		if (cpumask_empty(to_cpumask(backtrace_mask)))
+			break;
+
+		mdelay(1);
+	}
+
+	clear_bit(0, &backtrace_flag);
+	smp_mb__after_atomic();
+	put_cpu();
+}
+#endif
+
 /*
  * Main handler for inter-processor interrupts
  */
@@ -623,6 +680,9 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 	case IPI_FIQ:
 		BUILD_BUG_ON(SMP_IPI_FIQ_MASK != BIT(IPI_FIQ));
 		pr_warn("CPU%u: IPI FIQ delivered via IRQ vector\n", cpu);
+#ifdef CONFIG_ARM_BACKTRACE_TRIGGERING
+		ipi_cpu_backtrace(regs);
+#endif
 		break;
 
 	default:
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 2c219c7..b7e1e85 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -484,6 +484,9 @@ asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
 #ifdef CONFIG_ARM_GIC
 	gic_handle_fiq_ipi();
 #endif
+#ifdef CONFIG_ARM_BACKTRACE_TRIGGERING
+	ipi_cpu_backtrace(regs);
+#endif
 
 	nmi_exit();
 
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v1 6/6] arm: Implement arch_trigger_all_cpu_backtrace
@ 2014-09-04 16:03                       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-04 16:03 UTC (permalink / raw)
  To: linux-arm-kernel

From: Russell King <linux@arm.linux.org.uk>

Currently arm does not implement arch_trigger_all_cpu_backtrace because,
on SMP systems, there has never before been a means to route a
non-maskable interrupt to the other CPUs in the system. With the
introduction of IPI FIQ this is no longer the case. This patch
provides an implementation of arch_trigger_all_cpu_backtrace and
the associated KConfig machinary to enable it.

This is mostly Russell's code but since it was shared as an example rather
than a fully fledged patch currently this code is currently
Not-yet-signed-off-by: Russell King <linux@arm.linux.org.uk>

[Fill in headers and Kconfig, checkpatch.pl substitutions: CONFIG_NR_CPUS
for NR_CPUS and pr_warn() for printk(KERN_WARNING, )]
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/Kconfig.debug     | 14 +++++++++++
 arch/arm/include/asm/irq.h |  5 ++++
 arch/arm/include/asm/smp.h |  4 ++++
 arch/arm/kernel/smp.c      | 60 ++++++++++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/traps.c    |  3 +++
 5 files changed, 86 insertions(+)

diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index b11ad54..2fa932d 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -1281,4 +1281,18 @@ config DEBUG_SET_MODULE_RONX
 	  against certain classes of kernel exploits.
 	  If in doubt, say "N".
 
+config ARM_BACKTRACE_TRIGGERING
+	bool "Support non-maskable backtrace triggering"
+	depends on SMP
+	select FIQ
+	help
+	  Say Y here if you want to provide support for non-maskable
+	  backtrace triggering. This is used to generate a backtrace
+	  from all CPUs in a non-responsive system. Backtrace requests
+	  can be issued by lockup and hung task detectors, spin lock
+	  debugging or magic sysrq.
+
+	  This option is only effective when the kernel is run on a
+	  platform capable of generating FIQs.
+
 endmenu
diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h
index 53c15de..a5cc2ed 100644
--- a/arch/arm/include/asm/irq.h
+++ b/arch/arm/include/asm/irq.h
@@ -35,6 +35,11 @@ extern void (*handle_arch_irq)(struct pt_regs *);
 extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
 #endif
 
+#ifdef CONFIG_ARM_BACKTRACE_TRIGGERING
+void arch_trigger_all_cpu_backtrace(bool);
+#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace
+#endif
+
 #endif
 
 #endif
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 0e23384..d20bd95 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -90,6 +90,10 @@ extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
 
 extern int register_ipi_completion(struct completion *completion, int cpu);
 
+#ifdef CONFIG_ARM_BACKTRACE_TRIGGERING
+extern void ipi_cpu_backtrace(struct pt_regs *regs);
+#endif
+
 struct smp_operations {
 #ifdef CONFIG_SMP
 	/*
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index b2404d0..d1765a6 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -554,6 +554,63 @@ static void ipi_complete(unsigned int cpu)
 	complete(per_cpu(cpu_completion, cpu));
 }
 
+#ifdef CONFIG_ARM_BACKTRACE_TRIGGERING
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, CONFIG_NR_CPUS) __read_mostly;
+
+void ipi_cpu_backtrace(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+
+	if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
+		static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
+
+		arch_spin_lock(&lock);
+		pr_warn("FIQ backtrace for cpu %d\n", cpu);
+		show_regs(regs);
+		arch_spin_unlock(&lock);
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+	}
+}
+
+void arch_trigger_all_cpu_backtrace(bool include_self)
+{
+	static unsigned long backtrace_flag;
+	int i, cpu = get_cpu();
+
+	if (test_and_set_bit(0, &backtrace_flag)) {
+		/*
+		 * If there is already a trigger_all_cpu_backtrace() in progress
+		 * (backtrace_flag == 1), don't output double cpu dump infos.
+		 */
+		put_cpu();
+		return;
+	}
+
+	cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
+	if (!include_self)
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+
+	if (!cpumask_empty(to_cpumask(backtrace_mask))) {
+		pr_info("Sending FIQ to %s CPUs:\n",
+			(include_self ? "all" : "other"));
+		smp_cross_call(to_cpumask(backtrace_mask), IPI_FIQ);
+	}
+
+	/* Wait for up to 10 seconds for all CPUs to do the backtrace */
+	for (i = 0; i < 10 * 1000; i++) {
+		if (cpumask_empty(to_cpumask(backtrace_mask)))
+			break;
+
+		mdelay(1);
+	}
+
+	clear_bit(0, &backtrace_flag);
+	smp_mb__after_atomic();
+	put_cpu();
+}
+#endif
+
 /*
  * Main handler for inter-processor interrupts
  */
@@ -623,6 +680,9 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 	case IPI_FIQ:
 		BUILD_BUG_ON(SMP_IPI_FIQ_MASK != BIT(IPI_FIQ));
 		pr_warn("CPU%u: IPI FIQ delivered via IRQ vector\n", cpu);
+#ifdef CONFIG_ARM_BACKTRACE_TRIGGERING
+		ipi_cpu_backtrace(regs);
+#endif
 		break;
 
 	default:
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 2c219c7..b7e1e85 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -484,6 +484,9 @@ asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
 #ifdef CONFIG_ARM_GIC
 	gic_handle_fiq_ipi();
 #endif
+#ifdef CONFIG_ARM_BACKTRACE_TRIGGERING
+	ipi_cpu_backtrace(regs);
+#endif
 
 	nmi_exit();
 
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* Re: [PATCH v1 1/6] arm: fiq: Replace default FIQ handler
  2014-09-04 16:03                       ` Daniel Thompson
@ 2014-09-04 18:57                         ` Nicolas Pitre
  -1 siblings, 0 replies; 535+ messages in thread
From: Nicolas Pitre @ 2014-09-04 18:57 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Russell King, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Catalin Marinas

On Thu, 4 Sep 2014, Daniel Thompson wrote:

> This patch introduces a new default FIQ handler that is structured in a
> similar way to the existing ARM exception handler and result in the FIQ
> being handled by C code running on the SVC stack (despite this code run
> in the FIQ handler is subject to severe limitations with respect to
> locking making normal interaction with the kernel impossible).
> 
> This default handler allows concepts that on x86 would be handled using
> NMIs to be realized on ARM.
> 
> Credit:
> 
>     This patch is a near complete re-write of a patch originally
>     provided by Anton Vorontsov. Today only a couple of small fragments
>     survive, however without Anton's work to build from this patch would
>     not exist.
> 
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Nicolas Pitre <nico@linaro.org>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> ---
>  arch/arm/kernel/entry-armv.S | 110 +++++++++++++++++++++++++++++++++++++++----
>  arch/arm/kernel/setup.c      |   8 +++-
>  arch/arm/kernel/traps.c      |  26 ++++++++--
>  3 files changed, 130 insertions(+), 14 deletions(-)
> 
> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> index 36276cd..03dc0e0 100644
> --- a/arch/arm/kernel/entry-armv.S
> +++ b/arch/arm/kernel/entry-armv.S
> @@ -146,7 +146,7 @@ ENDPROC(__und_invalid)
>  #define SPFIX(code...)
>  #endif
>  
> -	.macro	svc_entry, stack_hole=0
> +	.macro	svc_entry, stack_hole=0, call_trace=1
>   UNWIND(.fnstart		)
>   UNWIND(.save {r0 - pc}		)
>  	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
> @@ -183,10 +183,35 @@ ENDPROC(__und_invalid)
>  	stmia	r7, {r2 - r6}
>  
>  #ifdef CONFIG_TRACE_IRQFLAGS
> +	.if \call_trace
>  	bl	trace_hardirqs_off
> +	.endif
>  #endif
>  	.endm
>  
> +@
> +@ svc_exit_via_fiq - similar to svc_exit but switches to FIQ mode before exit
> +@
> +@ This macro acts in a similar manner to svc_exit but switches to FIQ
> +@ mode to restore the final part of the register state.
> +@
> +@ We cannot use the normal svc_exit procedure because that would
> +@ clobber spsr_svc (FIQ could be delivered during the first few instructions
> +@ of vector_swi meaning its contents have not been saved anywhere).
> +@

Wouldn't it be better for this macro to live in entry-header.S alongside 
the others?  Also you should probably create a Thumb2 version.

> +	.macro  svc_exit_via_fiq, rpsr
> +
> +	mov	r0, sp
> +	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
> +				@ clobber state restored below)
> +	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
> +	add	r8, r0, #S_PC
> +	ldr	r9, [r0, #S_PSR]
> +	msr	spsr_cxsf, r9
> +	ldr	r0, [r0, #S_R0]
> +	ldmia	r8, {pc}^
> +	.endm
> +
>  	.align	5
>  __dabt_svc:
>  	svc_entry
> @@ -295,6 +320,15 @@ __pabt_svc:
>  ENDPROC(__pabt_svc)
>  
>  	.align	5
> +__fiq_svc:
> +	svc_entry 0, 0
> +	mov	r0, sp				@ struct pt_regs *regs
> +	bl	handle_fiq_as_nmi
> +	svc_exit_via_fiq r5
> + UNWIND(.fnend		)
> +ENDPROC(__fiq_svc)
> +
> +	.align	5
>  .LCcralign:
>  	.word	cr_alignment
>  #ifdef MULTI_DABORT
> @@ -305,6 +339,38 @@ ENDPROC(__pabt_svc)
>  	.word	fp_enter
>  
>  /*
> + * Abort mode handlers
> + */
> +
> +@
> +@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
> +@ and reuses the same macros. However in abort mode we must also
> +@ save/restore lr_abt and spsr_abt to make nested aborts safe.
> +@
> +	.align 5
> +__fiq_abt:
> +	svc_entry 0, 0
> +
> +	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
> +	mov	r0, lr		@ Save lr_abt
> +	mrs	r1, spsr	@ Save spsr_abt, abort is now safe
> +	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
> +	push	{r0 - r1}
> +
> +	sub	r0, sp, #8			@ struct pt_regs *regs
> +	bl	handle_fiq_as_nmi
> +
> +	pop	{r0 - r1}
> +	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
> +	mov	lr, r0		@ Restore lr_abt, abort is unsafe
> +	msr	spsr_cxsf, r1	@ Restore spsr_abt
> +	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
> +
> +	svc_exit_via_fiq r5
> + UNWIND(.fnend		)
> +ENDPROC(__fiq_svc)
> +
> +/*
>   * User mode handlers
>   *
>   * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
> @@ -683,6 +749,18 @@ ENTRY(ret_from_exception)
>  ENDPROC(__pabt_usr)
>  ENDPROC(ret_from_exception)
>  
> +	.align	5
> +__fiq_usr:
> +	usr_entry
> +	kuser_cmpxchg_check
> +	mov	r0, sp				@ struct pt_regs *regs
> +	bl	handle_fiq_as_nmi
> +	get_thread_info tsk
> +	mov	why, #0
> +	b	ret_to_user_from_irq
> + UNWIND(.fnend		)
> +ENDPROC(__fiq_usr)
> +
>  /*
>   * Register switch for ARMv3 and ARMv4 processors
>   * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
> @@ -1118,17 +1196,29 @@ vector_addrexcptn:
>  	b	vector_addrexcptn
>  
>  /*=============================================================================
> - * Undefined FIQs
> + * FIQ "NMI" handler
>   *-----------------------------------------------------------------------------
> - * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
> - * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
> - * Basically to switch modes, we *HAVE* to clobber one register...  brain
> - * damage alert!  I don't think that we can execute any code in here in any
> - * other mode than FIQ...  Ok you can switch to another mode, but you can't
> - * get out of that mode without clobbering one register.
> + * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
> + * systems.
>   */
> -vector_fiq:
> -	subs	pc, lr, #4
> +	vector_stub	fiq, FIQ_MODE, 4
> +
> +	.long	__fiq_usr			@  0  (USR_26 / USR_32)
> +	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
> +	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
> +	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
> +	.long	__fiq_svc			@  4
> +	.long	__fiq_svc			@  5
> +	.long	__fiq_svc			@  6
> +	.long	__fiq_abt			@  7
> +	.long	__fiq_svc			@  8
> +	.long	__fiq_svc			@  9
> +	.long	__fiq_svc			@  a
> +	.long	__fiq_svc			@  b
> +	.long	__fiq_svc			@  c
> +	.long	__fiq_svc			@  d
> +	.long	__fiq_svc			@  e
> +	.long	__fiq_svc			@  f
>  
>  	.globl	vector_fiq_offset
>  	.equ	vector_fiq_offset, vector_fiq
> diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
> index 84db893d..c031063 100644
> --- a/arch/arm/kernel/setup.c
> +++ b/arch/arm/kernel/setup.c
> @@ -133,6 +133,7 @@ struct stack {
>  	u32 irq[3];
>  	u32 abt[3];
>  	u32 und[3];
> +	u32 fiq[3];
>  } ____cacheline_aligned;
>  
>  #ifndef CONFIG_CPU_V7M
> @@ -470,7 +471,10 @@ void notrace cpu_init(void)
>  	"msr	cpsr_c, %5\n\t"
>  	"add	r14, %0, %6\n\t"
>  	"mov	sp, r14\n\t"
> -	"msr	cpsr_c, %7"
> +	"msr	cpsr_c, %7\n\t"
> +	"add	r14, %0, %8\n\t"
> +	"mov	sp, r14\n\t"
> +	"msr	cpsr_c, %9"
>  	    :
>  	    : "r" (stk),
>  	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
> @@ -479,6 +483,8 @@ void notrace cpu_init(void)
>  	      "I" (offsetof(struct stack, abt[0])),
>  	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
>  	      "I" (offsetof(struct stack, und[0])),
> +	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
> +	      "I" (offsetof(struct stack, fiq[0])),
>  	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
>  	    : "r14");
>  #endif
> diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
> index c8e4bb7..7912a9e 100644
> --- a/arch/arm/kernel/traps.c
> +++ b/arch/arm/kernel/traps.c
> @@ -25,6 +25,7 @@
>  #include <linux/delay.h>
>  #include <linux/init.h>
>  #include <linux/sched.h>
> +#include <linux/irq.h>
>  
>  #include <linux/atomic.h>
>  #include <asm/cacheflush.h>
> @@ -460,10 +461,29 @@ die_sig:
>  	arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
>  }
>  
> -asmlinkage void do_unexp_fiq (struct pt_regs *regs)
> +/*
> + * Handle FIQ similarly to NMI on x86 systems.
> + *
> + * The runtime environment for NMIs is extremely restrictive
> + * (NMIs can pre-empt critical sections meaning almost all locking is
> + * forbidden) meaning this default FIQ handling must only be used in
> + * circumstances where non-maskability improves robustness, such as
> + * watchdog or debug logic.
> + *
> + * This handler is not appropriate for general purpose use in drivers
> + * platform code and can be overrideen using set_fiq_handler.
> + */
> +asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
>  {
> -	printk("Hmm.  Unexpected FIQ received, but trying to continue\n");
> -	printk("You may have a hardware problem...\n");
> +#ifdef CONFIG_FIQ
> +	struct pt_regs *old_regs = set_irq_regs(regs);
> +
> +	nmi_enter();
> +	/* nop for now */
> +	nmi_exit();
> +
> +	set_irq_regs(old_regs);
> +#endif
>  }
>  
>  /*
> -- 
> 1.9.3
> 
> 

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v1 1/6] arm: fiq: Replace default FIQ handler
@ 2014-09-04 18:57                         ` Nicolas Pitre
  0 siblings, 0 replies; 535+ messages in thread
From: Nicolas Pitre @ 2014-09-04 18:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 4 Sep 2014, Daniel Thompson wrote:

> This patch introduces a new default FIQ handler that is structured in a
> similar way to the existing ARM exception handler and result in the FIQ
> being handled by C code running on the SVC stack (despite this code run
> in the FIQ handler is subject to severe limitations with respect to
> locking making normal interaction with the kernel impossible).
> 
> This default handler allows concepts that on x86 would be handled using
> NMIs to be realized on ARM.
> 
> Credit:
> 
>     This patch is a near complete re-write of a patch originally
>     provided by Anton Vorontsov. Today only a couple of small fragments
>     survive, however without Anton's work to build from this patch would
>     not exist.
> 
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Nicolas Pitre <nico@linaro.org>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> ---
>  arch/arm/kernel/entry-armv.S | 110 +++++++++++++++++++++++++++++++++++++++----
>  arch/arm/kernel/setup.c      |   8 +++-
>  arch/arm/kernel/traps.c      |  26 ++++++++--
>  3 files changed, 130 insertions(+), 14 deletions(-)
> 
> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> index 36276cd..03dc0e0 100644
> --- a/arch/arm/kernel/entry-armv.S
> +++ b/arch/arm/kernel/entry-armv.S
> @@ -146,7 +146,7 @@ ENDPROC(__und_invalid)
>  #define SPFIX(code...)
>  #endif
>  
> -	.macro	svc_entry, stack_hole=0
> +	.macro	svc_entry, stack_hole=0, call_trace=1
>   UNWIND(.fnstart		)
>   UNWIND(.save {r0 - pc}		)
>  	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
> @@ -183,10 +183,35 @@ ENDPROC(__und_invalid)
>  	stmia	r7, {r2 - r6}
>  
>  #ifdef CONFIG_TRACE_IRQFLAGS
> +	.if \call_trace
>  	bl	trace_hardirqs_off
> +	.endif
>  #endif
>  	.endm
>  
> +@
> +@ svc_exit_via_fiq - similar to svc_exit but switches to FIQ mode before exit
> +@
> +@ This macro acts in a similar manner to svc_exit but switches to FIQ
> +@ mode to restore the final part of the register state.
> +@
> +@ We cannot use the normal svc_exit procedure because that would
> +@ clobber spsr_svc (FIQ could be delivered during the first few instructions
> +@ of vector_swi meaning its contents have not been saved anywhere).
> +@

Wouldn't it be better for this macro to live in entry-header.S alongside 
the others?  Also you should probably create a Thumb2 version.

> +	.macro  svc_exit_via_fiq, rpsr
> +
> +	mov	r0, sp
> +	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
> +				@ clobber state restored below)
> +	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
> +	add	r8, r0, #S_PC
> +	ldr	r9, [r0, #S_PSR]
> +	msr	spsr_cxsf, r9
> +	ldr	r0, [r0, #S_R0]
> +	ldmia	r8, {pc}^
> +	.endm
> +
>  	.align	5
>  __dabt_svc:
>  	svc_entry
> @@ -295,6 +320,15 @@ __pabt_svc:
>  ENDPROC(__pabt_svc)
>  
>  	.align	5
> +__fiq_svc:
> +	svc_entry 0, 0
> +	mov	r0, sp				@ struct pt_regs *regs
> +	bl	handle_fiq_as_nmi
> +	svc_exit_via_fiq r5
> + UNWIND(.fnend		)
> +ENDPROC(__fiq_svc)
> +
> +	.align	5
>  .LCcralign:
>  	.word	cr_alignment
>  #ifdef MULTI_DABORT
> @@ -305,6 +339,38 @@ ENDPROC(__pabt_svc)
>  	.word	fp_enter
>  
>  /*
> + * Abort mode handlers
> + */
> +
> +@
> +@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
> +@ and reuses the same macros. However in abort mode we must also
> +@ save/restore lr_abt and spsr_abt to make nested aborts safe.
> +@
> +	.align 5
> +__fiq_abt:
> +	svc_entry 0, 0
> +
> +	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
> +	mov	r0, lr		@ Save lr_abt
> +	mrs	r1, spsr	@ Save spsr_abt, abort is now safe
> +	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
> +	push	{r0 - r1}
> +
> +	sub	r0, sp, #8			@ struct pt_regs *regs
> +	bl	handle_fiq_as_nmi
> +
> +	pop	{r0 - r1}
> +	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
> +	mov	lr, r0		@ Restore lr_abt, abort is unsafe
> +	msr	spsr_cxsf, r1	@ Restore spsr_abt
> +	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
> +
> +	svc_exit_via_fiq r5
> + UNWIND(.fnend		)
> +ENDPROC(__fiq_svc)
> +
> +/*
>   * User mode handlers
>   *
>   * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
> @@ -683,6 +749,18 @@ ENTRY(ret_from_exception)
>  ENDPROC(__pabt_usr)
>  ENDPROC(ret_from_exception)
>  
> +	.align	5
> +__fiq_usr:
> +	usr_entry
> +	kuser_cmpxchg_check
> +	mov	r0, sp				@ struct pt_regs *regs
> +	bl	handle_fiq_as_nmi
> +	get_thread_info tsk
> +	mov	why, #0
> +	b	ret_to_user_from_irq
> + UNWIND(.fnend		)
> +ENDPROC(__fiq_usr)
> +
>  /*
>   * Register switch for ARMv3 and ARMv4 processors
>   * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
> @@ -1118,17 +1196,29 @@ vector_addrexcptn:
>  	b	vector_addrexcptn
>  
>  /*=============================================================================
> - * Undefined FIQs
> + * FIQ "NMI" handler
>   *-----------------------------------------------------------------------------
> - * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
> - * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
> - * Basically to switch modes, we *HAVE* to clobber one register...  brain
> - * damage alert!  I don't think that we can execute any code in here in any
> - * other mode than FIQ...  Ok you can switch to another mode, but you can't
> - * get out of that mode without clobbering one register.
> + * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
> + * systems.
>   */
> -vector_fiq:
> -	subs	pc, lr, #4
> +	vector_stub	fiq, FIQ_MODE, 4
> +
> +	.long	__fiq_usr			@  0  (USR_26 / USR_32)
> +	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
> +	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
> +	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
> +	.long	__fiq_svc			@  4
> +	.long	__fiq_svc			@  5
> +	.long	__fiq_svc			@  6
> +	.long	__fiq_abt			@  7
> +	.long	__fiq_svc			@  8
> +	.long	__fiq_svc			@  9
> +	.long	__fiq_svc			@  a
> +	.long	__fiq_svc			@  b
> +	.long	__fiq_svc			@  c
> +	.long	__fiq_svc			@  d
> +	.long	__fiq_svc			@  e
> +	.long	__fiq_svc			@  f
>  
>  	.globl	vector_fiq_offset
>  	.equ	vector_fiq_offset, vector_fiq
> diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
> index 84db893d..c031063 100644
> --- a/arch/arm/kernel/setup.c
> +++ b/arch/arm/kernel/setup.c
> @@ -133,6 +133,7 @@ struct stack {
>  	u32 irq[3];
>  	u32 abt[3];
>  	u32 und[3];
> +	u32 fiq[3];
>  } ____cacheline_aligned;
>  
>  #ifndef CONFIG_CPU_V7M
> @@ -470,7 +471,10 @@ void notrace cpu_init(void)
>  	"msr	cpsr_c, %5\n\t"
>  	"add	r14, %0, %6\n\t"
>  	"mov	sp, r14\n\t"
> -	"msr	cpsr_c, %7"
> +	"msr	cpsr_c, %7\n\t"
> +	"add	r14, %0, %8\n\t"
> +	"mov	sp, r14\n\t"
> +	"msr	cpsr_c, %9"
>  	    :
>  	    : "r" (stk),
>  	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
> @@ -479,6 +483,8 @@ void notrace cpu_init(void)
>  	      "I" (offsetof(struct stack, abt[0])),
>  	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
>  	      "I" (offsetof(struct stack, und[0])),
> +	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
> +	      "I" (offsetof(struct stack, fiq[0])),
>  	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
>  	    : "r14");
>  #endif
> diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
> index c8e4bb7..7912a9e 100644
> --- a/arch/arm/kernel/traps.c
> +++ b/arch/arm/kernel/traps.c
> @@ -25,6 +25,7 @@
>  #include <linux/delay.h>
>  #include <linux/init.h>
>  #include <linux/sched.h>
> +#include <linux/irq.h>
>  
>  #include <linux/atomic.h>
>  #include <asm/cacheflush.h>
> @@ -460,10 +461,29 @@ die_sig:
>  	arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
>  }
>  
> -asmlinkage void do_unexp_fiq (struct pt_regs *regs)
> +/*
> + * Handle FIQ similarly to NMI on x86 systems.
> + *
> + * The runtime environment for NMIs is extremely restrictive
> + * (NMIs can pre-empt critical sections meaning almost all locking is
> + * forbidden) meaning this default FIQ handling must only be used in
> + * circumstances where non-maskability improves robustness, such as
> + * watchdog or debug logic.
> + *
> + * This handler is not appropriate for general purpose use in drivers
> + * platform code and can be overrideen using set_fiq_handler.
> + */
> +asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
>  {
> -	printk("Hmm.  Unexpected FIQ received, but trying to continue\n");
> -	printk("You may have a hardware problem...\n");
> +#ifdef CONFIG_FIQ
> +	struct pt_regs *old_regs = set_irq_regs(regs);
> +
> +	nmi_enter();
> +	/* nop for now */
> +	nmi_exit();
> +
> +	set_irq_regs(old_regs);
> +#endif
>  }
>  
>  /*
> -- 
> 1.9.3
> 
> 

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v1 1/6] arm: fiq: Replace default FIQ handler
  2014-09-04 18:57                         ` Nicolas Pitre
@ 2014-09-05  9:03                           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-05  9:03 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: Russell King, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Catalin Marinas

On 04/09/14 19:57, Nicolas Pitre wrote:
> On Thu, 4 Sep 2014, Daniel Thompson wrote:
> 
>> This patch introduces a new default FIQ handler that is structured in a
>> similar way to the existing ARM exception handler and result in the FIQ
>> being handled by C code running on the SVC stack (despite this code run
>> in the FIQ handler is subject to severe limitations with respect to
>> locking making normal interaction with the kernel impossible).
>>
>> This default handler allows concepts that on x86 would be handled using
>> NMIs to be realized on ARM.
>>
>> Credit:
>>
>>     This patch is a near complete re-write of a patch originally
>>     provided by Anton Vorontsov. Today only a couple of small fragments
>>     survive, however without Anton's work to build from this patch would
>>     not exist.
>>
>> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
>> Cc: Russell King <linux@arm.linux.org.uk>
>> Cc: Nicolas Pitre <nico@linaro.org>
>> Cc: Catalin Marinas <catalin.marinas@arm.com>
>> ---
>>  arch/arm/kernel/entry-armv.S | 110 +++++++++++++++++++++++++++++++++++++++----
>>  arch/arm/kernel/setup.c      |   8 +++-
>>  arch/arm/kernel/traps.c      |  26 ++++++++--
>>  3 files changed, 130 insertions(+), 14 deletions(-)
>>
>> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
>> index 36276cd..03dc0e0 100644
>> --- a/arch/arm/kernel/entry-armv.S
>> +++ b/arch/arm/kernel/entry-armv.S
>> @@ -146,7 +146,7 @@ ENDPROC(__und_invalid)
>>  #define SPFIX(code...)
>>  #endif
>>  
>> -	.macro	svc_entry, stack_hole=0
>> +	.macro	svc_entry, stack_hole=0, call_trace=1
>>   UNWIND(.fnstart		)
>>   UNWIND(.save {r0 - pc}		)
>>  	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
>> @@ -183,10 +183,35 @@ ENDPROC(__und_invalid)
>>  	stmia	r7, {r2 - r6}
>>  
>>  #ifdef CONFIG_TRACE_IRQFLAGS
>> +	.if \call_trace
>>  	bl	trace_hardirqs_off
>> +	.endif
>>  #endif
>>  	.endm
>>  
>> +@
>> +@ svc_exit_via_fiq - similar to svc_exit but switches to FIQ mode before exit
>> +@
>> +@ This macro acts in a similar manner to svc_exit but switches to FIQ
>> +@ mode to restore the final part of the register state.
>> +@
>> +@ We cannot use the normal svc_exit procedure because that would
>> +@ clobber spsr_svc (FIQ could be delivered during the first few instructions
>> +@ of vector_swi meaning its contents have not been saved anywhere).
>> +@
> 
> Wouldn't it be better for this macro to live in entry-header.S alongside 
> the others?

I'm not sure either way.

svc_exit_from_fiq isn't needed by entry-common.S and cannot be used by
entry-v7m.S because v7m has no FIQ. For that reason I decided to place
it alongside svc_entry in entry-armv.S rather than alongside svc_exit in
entry-header.S .

I am happy to move it if you have a strong preference here. Please let
me know.


> Also you should probably create a Thumb2 version.

I'll look at this.


Daniel.


>> +	.macro  svc_exit_via_fiq, rpsr
>> +
>> +	mov	r0, sp
>> +	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
>> +				@ clobber state restored below)
>> +	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
>> +	add	r8, r0, #S_PC
>> +	ldr	r9, [r0, #S_PSR]
>> +	msr	spsr_cxsf, r9
>> +	ldr	r0, [r0, #S_R0]
>> +	ldmia	r8, {pc}^
>> +	.endm
>> +
>>  	.align	5
>>  __dabt_svc:
>>  	svc_entry
>> @@ -295,6 +320,15 @@ __pabt_svc:
>>  ENDPROC(__pabt_svc)
>>  
>>  	.align	5
>> +__fiq_svc:
>> +	svc_entry 0, 0
>> +	mov	r0, sp				@ struct pt_regs *regs
>> +	bl	handle_fiq_as_nmi
>> +	svc_exit_via_fiq r5
>> + UNWIND(.fnend		)
>> +ENDPROC(__fiq_svc)
>> +
>> +	.align	5
>>  .LCcralign:
>>  	.word	cr_alignment
>>  #ifdef MULTI_DABORT
>> @@ -305,6 +339,38 @@ ENDPROC(__pabt_svc)
>>  	.word	fp_enter
>>  
>>  /*
>> + * Abort mode handlers
>> + */
>> +
>> +@
>> +@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
>> +@ and reuses the same macros. However in abort mode we must also
>> +@ save/restore lr_abt and spsr_abt to make nested aborts safe.
>> +@
>> +	.align 5
>> +__fiq_abt:
>> +	svc_entry 0, 0
>> +
>> +	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
>> +	mov	r0, lr		@ Save lr_abt
>> +	mrs	r1, spsr	@ Save spsr_abt, abort is now safe
>> +	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
>> +	push	{r0 - r1}
>> +
>> +	sub	r0, sp, #8			@ struct pt_regs *regs
>> +	bl	handle_fiq_as_nmi
>> +
>> +	pop	{r0 - r1}
>> +	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
>> +	mov	lr, r0		@ Restore lr_abt, abort is unsafe
>> +	msr	spsr_cxsf, r1	@ Restore spsr_abt
>> +	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
>> +
>> +	svc_exit_via_fiq r5
>> + UNWIND(.fnend		)
>> +ENDPROC(__fiq_svc)
>> +
>> +/*
>>   * User mode handlers
>>   *
>>   * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
>> @@ -683,6 +749,18 @@ ENTRY(ret_from_exception)
>>  ENDPROC(__pabt_usr)
>>  ENDPROC(ret_from_exception)
>>  
>> +	.align	5
>> +__fiq_usr:
>> +	usr_entry
>> +	kuser_cmpxchg_check
>> +	mov	r0, sp				@ struct pt_regs *regs
>> +	bl	handle_fiq_as_nmi
>> +	get_thread_info tsk
>> +	mov	why, #0
>> +	b	ret_to_user_from_irq
>> + UNWIND(.fnend		)
>> +ENDPROC(__fiq_usr)
>> +
>>  /*
>>   * Register switch for ARMv3 and ARMv4 processors
>>   * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
>> @@ -1118,17 +1196,29 @@ vector_addrexcptn:
>>  	b	vector_addrexcptn
>>  
>>  /*=============================================================================
>> - * Undefined FIQs
>> + * FIQ "NMI" handler
>>   *-----------------------------------------------------------------------------
>> - * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
>> - * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
>> - * Basically to switch modes, we *HAVE* to clobber one register...  brain
>> - * damage alert!  I don't think that we can execute any code in here in any
>> - * other mode than FIQ...  Ok you can switch to another mode, but you can't
>> - * get out of that mode without clobbering one register.
>> + * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
>> + * systems.
>>   */
>> -vector_fiq:
>> -	subs	pc, lr, #4
>> +	vector_stub	fiq, FIQ_MODE, 4
>> +
>> +	.long	__fiq_usr			@  0  (USR_26 / USR_32)
>> +	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
>> +	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
>> +	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
>> +	.long	__fiq_svc			@  4
>> +	.long	__fiq_svc			@  5
>> +	.long	__fiq_svc			@  6
>> +	.long	__fiq_abt			@  7
>> +	.long	__fiq_svc			@  8
>> +	.long	__fiq_svc			@  9
>> +	.long	__fiq_svc			@  a
>> +	.long	__fiq_svc			@  b
>> +	.long	__fiq_svc			@  c
>> +	.long	__fiq_svc			@  d
>> +	.long	__fiq_svc			@  e
>> +	.long	__fiq_svc			@  f
>>  
>>  	.globl	vector_fiq_offset
>>  	.equ	vector_fiq_offset, vector_fiq
>> diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
>> index 84db893d..c031063 100644
>> --- a/arch/arm/kernel/setup.c
>> +++ b/arch/arm/kernel/setup.c
>> @@ -133,6 +133,7 @@ struct stack {
>>  	u32 irq[3];
>>  	u32 abt[3];
>>  	u32 und[3];
>> +	u32 fiq[3];
>>  } ____cacheline_aligned;
>>  
>>  #ifndef CONFIG_CPU_V7M
>> @@ -470,7 +471,10 @@ void notrace cpu_init(void)
>>  	"msr	cpsr_c, %5\n\t"
>>  	"add	r14, %0, %6\n\t"
>>  	"mov	sp, r14\n\t"
>> -	"msr	cpsr_c, %7"
>> +	"msr	cpsr_c, %7\n\t"
>> +	"add	r14, %0, %8\n\t"
>> +	"mov	sp, r14\n\t"
>> +	"msr	cpsr_c, %9"
>>  	    :
>>  	    : "r" (stk),
>>  	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
>> @@ -479,6 +483,8 @@ void notrace cpu_init(void)
>>  	      "I" (offsetof(struct stack, abt[0])),
>>  	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
>>  	      "I" (offsetof(struct stack, und[0])),
>> +	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
>> +	      "I" (offsetof(struct stack, fiq[0])),
>>  	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
>>  	    : "r14");
>>  #endif
>> diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
>> index c8e4bb7..7912a9e 100644
>> --- a/arch/arm/kernel/traps.c
>> +++ b/arch/arm/kernel/traps.c
>> @@ -25,6 +25,7 @@
>>  #include <linux/delay.h>
>>  #include <linux/init.h>
>>  #include <linux/sched.h>
>> +#include <linux/irq.h>
>>  
>>  #include <linux/atomic.h>
>>  #include <asm/cacheflush.h>
>> @@ -460,10 +461,29 @@ die_sig:
>>  	arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
>>  }
>>  
>> -asmlinkage void do_unexp_fiq (struct pt_regs *regs)
>> +/*
>> + * Handle FIQ similarly to NMI on x86 systems.
>> + *
>> + * The runtime environment for NMIs is extremely restrictive
>> + * (NMIs can pre-empt critical sections meaning almost all locking is
>> + * forbidden) meaning this default FIQ handling must only be used in
>> + * circumstances where non-maskability improves robustness, such as
>> + * watchdog or debug logic.
>> + *
>> + * This handler is not appropriate for general purpose use in drivers
>> + * platform code and can be overrideen using set_fiq_handler.
>> + */
>> +asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
>>  {
>> -	printk("Hmm.  Unexpected FIQ received, but trying to continue\n");
>> -	printk("You may have a hardware problem...\n");
>> +#ifdef CONFIG_FIQ
>> +	struct pt_regs *old_regs = set_irq_regs(regs);
>> +
>> +	nmi_enter();
>> +	/* nop for now */
>> +	nmi_exit();
>> +
>> +	set_irq_regs(old_regs);
>> +#endif
>>  }
>>  
>>  /*
>> -- 
>> 1.9.3
>>
>>


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v1 1/6] arm: fiq: Replace default FIQ handler
@ 2014-09-05  9:03                           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-05  9:03 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/09/14 19:57, Nicolas Pitre wrote:
> On Thu, 4 Sep 2014, Daniel Thompson wrote:
> 
>> This patch introduces a new default FIQ handler that is structured in a
>> similar way to the existing ARM exception handler and result in the FIQ
>> being handled by C code running on the SVC stack (despite this code run
>> in the FIQ handler is subject to severe limitations with respect to
>> locking making normal interaction with the kernel impossible).
>>
>> This default handler allows concepts that on x86 would be handled using
>> NMIs to be realized on ARM.
>>
>> Credit:
>>
>>     This patch is a near complete re-write of a patch originally
>>     provided by Anton Vorontsov. Today only a couple of small fragments
>>     survive, however without Anton's work to build from this patch would
>>     not exist.
>>
>> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
>> Cc: Russell King <linux@arm.linux.org.uk>
>> Cc: Nicolas Pitre <nico@linaro.org>
>> Cc: Catalin Marinas <catalin.marinas@arm.com>
>> ---
>>  arch/arm/kernel/entry-armv.S | 110 +++++++++++++++++++++++++++++++++++++++----
>>  arch/arm/kernel/setup.c      |   8 +++-
>>  arch/arm/kernel/traps.c      |  26 ++++++++--
>>  3 files changed, 130 insertions(+), 14 deletions(-)
>>
>> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
>> index 36276cd..03dc0e0 100644
>> --- a/arch/arm/kernel/entry-armv.S
>> +++ b/arch/arm/kernel/entry-armv.S
>> @@ -146,7 +146,7 @@ ENDPROC(__und_invalid)
>>  #define SPFIX(code...)
>>  #endif
>>  
>> -	.macro	svc_entry, stack_hole=0
>> +	.macro	svc_entry, stack_hole=0, call_trace=1
>>   UNWIND(.fnstart		)
>>   UNWIND(.save {r0 - pc}		)
>>  	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
>> @@ -183,10 +183,35 @@ ENDPROC(__und_invalid)
>>  	stmia	r7, {r2 - r6}
>>  
>>  #ifdef CONFIG_TRACE_IRQFLAGS
>> +	.if \call_trace
>>  	bl	trace_hardirqs_off
>> +	.endif
>>  #endif
>>  	.endm
>>  
>> +@
>> +@ svc_exit_via_fiq - similar to svc_exit but switches to FIQ mode before exit
>> +@
>> +@ This macro acts in a similar manner to svc_exit but switches to FIQ
>> +@ mode to restore the final part of the register state.
>> +@
>> +@ We cannot use the normal svc_exit procedure because that would
>> +@ clobber spsr_svc (FIQ could be delivered during the first few instructions
>> +@ of vector_swi meaning its contents have not been saved anywhere).
>> +@
> 
> Wouldn't it be better for this macro to live in entry-header.S alongside 
> the others?

I'm not sure either way.

svc_exit_from_fiq isn't needed by entry-common.S and cannot be used by
entry-v7m.S because v7m has no FIQ. For that reason I decided to place
it alongside svc_entry in entry-armv.S rather than alongside svc_exit in
entry-header.S .

I am happy to move it if you have a strong preference here. Please let
me know.


> Also you should probably create a Thumb2 version.

I'll look at this.


Daniel.


>> +	.macro  svc_exit_via_fiq, rpsr
>> +
>> +	mov	r0, sp
>> +	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
>> +				@ clobber state restored below)
>> +	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
>> +	add	r8, r0, #S_PC
>> +	ldr	r9, [r0, #S_PSR]
>> +	msr	spsr_cxsf, r9
>> +	ldr	r0, [r0, #S_R0]
>> +	ldmia	r8, {pc}^
>> +	.endm
>> +
>>  	.align	5
>>  __dabt_svc:
>>  	svc_entry
>> @@ -295,6 +320,15 @@ __pabt_svc:
>>  ENDPROC(__pabt_svc)
>>  
>>  	.align	5
>> +__fiq_svc:
>> +	svc_entry 0, 0
>> +	mov	r0, sp				@ struct pt_regs *regs
>> +	bl	handle_fiq_as_nmi
>> +	svc_exit_via_fiq r5
>> + UNWIND(.fnend		)
>> +ENDPROC(__fiq_svc)
>> +
>> +	.align	5
>>  .LCcralign:
>>  	.word	cr_alignment
>>  #ifdef MULTI_DABORT
>> @@ -305,6 +339,38 @@ ENDPROC(__pabt_svc)
>>  	.word	fp_enter
>>  
>>  /*
>> + * Abort mode handlers
>> + */
>> +
>> +@
>> +@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
>> +@ and reuses the same macros. However in abort mode we must also
>> +@ save/restore lr_abt and spsr_abt to make nested aborts safe.
>> +@
>> +	.align 5
>> +__fiq_abt:
>> +	svc_entry 0, 0
>> +
>> +	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
>> +	mov	r0, lr		@ Save lr_abt
>> +	mrs	r1, spsr	@ Save spsr_abt, abort is now safe
>> +	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
>> +	push	{r0 - r1}
>> +
>> +	sub	r0, sp, #8			@ struct pt_regs *regs
>> +	bl	handle_fiq_as_nmi
>> +
>> +	pop	{r0 - r1}
>> +	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT
>> +	mov	lr, r0		@ Restore lr_abt, abort is unsafe
>> +	msr	spsr_cxsf, r1	@ Restore spsr_abt
>> +	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT
>> +
>> +	svc_exit_via_fiq r5
>> + UNWIND(.fnend		)
>> +ENDPROC(__fiq_svc)
>> +
>> +/*
>>   * User mode handlers
>>   *
>>   * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
>> @@ -683,6 +749,18 @@ ENTRY(ret_from_exception)
>>  ENDPROC(__pabt_usr)
>>  ENDPROC(ret_from_exception)
>>  
>> +	.align	5
>> +__fiq_usr:
>> +	usr_entry
>> +	kuser_cmpxchg_check
>> +	mov	r0, sp				@ struct pt_regs *regs
>> +	bl	handle_fiq_as_nmi
>> +	get_thread_info tsk
>> +	mov	why, #0
>> +	b	ret_to_user_from_irq
>> + UNWIND(.fnend		)
>> +ENDPROC(__fiq_usr)
>> +
>>  /*
>>   * Register switch for ARMv3 and ARMv4 processors
>>   * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
>> @@ -1118,17 +1196,29 @@ vector_addrexcptn:
>>  	b	vector_addrexcptn
>>  
>>  /*=============================================================================
>> - * Undefined FIQs
>> + * FIQ "NMI" handler
>>   *-----------------------------------------------------------------------------
>> - * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
>> - * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
>> - * Basically to switch modes, we *HAVE* to clobber one register...  brain
>> - * damage alert!  I don't think that we can execute any code in here in any
>> - * other mode than FIQ...  Ok you can switch to another mode, but you can't
>> - * get out of that mode without clobbering one register.
>> + * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
>> + * systems.
>>   */
>> -vector_fiq:
>> -	subs	pc, lr, #4
>> +	vector_stub	fiq, FIQ_MODE, 4
>> +
>> +	.long	__fiq_usr			@  0  (USR_26 / USR_32)
>> +	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
>> +	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
>> +	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
>> +	.long	__fiq_svc			@  4
>> +	.long	__fiq_svc			@  5
>> +	.long	__fiq_svc			@  6
>> +	.long	__fiq_abt			@  7
>> +	.long	__fiq_svc			@  8
>> +	.long	__fiq_svc			@  9
>> +	.long	__fiq_svc			@  a
>> +	.long	__fiq_svc			@  b
>> +	.long	__fiq_svc			@  c
>> +	.long	__fiq_svc			@  d
>> +	.long	__fiq_svc			@  e
>> +	.long	__fiq_svc			@  f
>>  
>>  	.globl	vector_fiq_offset
>>  	.equ	vector_fiq_offset, vector_fiq
>> diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
>> index 84db893d..c031063 100644
>> --- a/arch/arm/kernel/setup.c
>> +++ b/arch/arm/kernel/setup.c
>> @@ -133,6 +133,7 @@ struct stack {
>>  	u32 irq[3];
>>  	u32 abt[3];
>>  	u32 und[3];
>> +	u32 fiq[3];
>>  } ____cacheline_aligned;
>>  
>>  #ifndef CONFIG_CPU_V7M
>> @@ -470,7 +471,10 @@ void notrace cpu_init(void)
>>  	"msr	cpsr_c, %5\n\t"
>>  	"add	r14, %0, %6\n\t"
>>  	"mov	sp, r14\n\t"
>> -	"msr	cpsr_c, %7"
>> +	"msr	cpsr_c, %7\n\t"
>> +	"add	r14, %0, %8\n\t"
>> +	"mov	sp, r14\n\t"
>> +	"msr	cpsr_c, %9"
>>  	    :
>>  	    : "r" (stk),
>>  	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
>> @@ -479,6 +483,8 @@ void notrace cpu_init(void)
>>  	      "I" (offsetof(struct stack, abt[0])),
>>  	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
>>  	      "I" (offsetof(struct stack, und[0])),
>> +	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
>> +	      "I" (offsetof(struct stack, fiq[0])),
>>  	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
>>  	    : "r14");
>>  #endif
>> diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
>> index c8e4bb7..7912a9e 100644
>> --- a/arch/arm/kernel/traps.c
>> +++ b/arch/arm/kernel/traps.c
>> @@ -25,6 +25,7 @@
>>  #include <linux/delay.h>
>>  #include <linux/init.h>
>>  #include <linux/sched.h>
>> +#include <linux/irq.h>
>>  
>>  #include <linux/atomic.h>
>>  #include <asm/cacheflush.h>
>> @@ -460,10 +461,29 @@ die_sig:
>>  	arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
>>  }
>>  
>> -asmlinkage void do_unexp_fiq (struct pt_regs *regs)
>> +/*
>> + * Handle FIQ similarly to NMI on x86 systems.
>> + *
>> + * The runtime environment for NMIs is extremely restrictive
>> + * (NMIs can pre-empt critical sections meaning almost all locking is
>> + * forbidden) meaning this default FIQ handling must only be used in
>> + * circumstances where non-maskability improves robustness, such as
>> + * watchdog or debug logic.
>> + *
>> + * This handler is not appropriate for general purpose use in drivers
>> + * platform code and can be overrideen using set_fiq_handler.
>> + */
>> +asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
>>  {
>> -	printk("Hmm.  Unexpected FIQ received, but trying to continue\n");
>> -	printk("You may have a hardware problem...\n");
>> +#ifdef CONFIG_FIQ
>> +	struct pt_regs *old_regs = set_irq_regs(regs);
>> +
>> +	nmi_enter();
>> +	/* nop for now */
>> +	nmi_exit();
>> +
>> +	set_irq_regs(old_regs);
>> +#endif
>>  }
>>  
>>  /*
>> -- 
>> 1.9.3
>>
>>

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v2 0/5] arm: Implement arch_trigger_all_cpu_backtrace
  2014-09-04 16:03                     ` Daniel Thompson
@ 2014-09-05 15:33                       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-05 15:33 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal

This patchset implements arch_trigger_all_cpu_backtrace for arm.

Non-maskable signalling relies on the kernel being able to access FIQ
and therefore, for devices that implement TrustZone, it will work only on
systems that boot the kernel in secure mode.

Tested on Freescale iMX.6 (both via SysRq-l and by deliberately locking
up the kernel with CONFIG_DEBUG_SPINLOCK=y).

Changes since v1:

* Restructured to sit nicely on a similar FYI patchset from Russell
  King. It now effectively replaces the work in progress final patch
  with something much more complete.

* Implemented (and tested) a Thumb-2 implementation of svc_exit_via_fiq
  (review of Nicolas Pitre)

* Dropped the GIC group 0 workaround patch. The issue of FIQ interrupts
  being acknowledged by the IRQ handler does still exist but should be
  harmless because the IRQ handler will still wind up calling
  ipi_cpu_backtrace().

* Removed any dependency on CONFIG_FIQ; all cpu backtrace effectively
  becomes a platform feature (although the use of non-maskable
  interrupts to implement it is best effort rather than guaranteed).

* Better comments highlighting usage of RAZ/WI registers (and parts of
  registers) in the GIC code.

Changes *before* v1:

* This patchset is a hugely cut-down successor to "[PATCH v11 00/19]
  arm: KGDB NMI/FIQ support". Thanks to Thomas Gleixner for suggesting
  the new structure. For historic details see:
        https://lkml.org/lkml/2014/9/2/227

* Fix bug in __fiq_abt (no longer passes a bad struct pt_regs value).
  In fixing this we also remove the useless indirection previously
  found in the fiq_handler macro.

* Make default fiq handler "always on" by migrating from fiq.c to
  traps.c and replace do_unexp_fiq with the new handler (review
  of Russell King).

* Add arm64 version of fiq.h (review of Russell King)

* Removed conditional branching and code from irq-gic.c, this is
  replaced by much simpler code that relies on the GIC specification's
  heavy use of read-as-zero/write-ignored (review of Russell King)


Daniel Thompson (3):
  arm: fiq: Replace default FIQ handler
  arm64: Introduce dummy version of asm/fiq.h
  irqchip: gic: Add support for IPI FIQ

Russell King (2):
  ARM: remove unused do_unexp_fiq() function
  ARM: add basic support for on-demand backtrace of other CPUs

 arch/arm/include/asm/irq.h      |   5 ++
 arch/arm/include/asm/smp.h      |   3 +
 arch/arm/kernel/entry-armv.S    | 137 ++++++++++++++++++++++++++++++---
 arch/arm/kernel/setup.c         |   8 +-
 arch/arm/kernel/smp.c           |  64 ++++++++++++++++
 arch/arm/kernel/traps.c         |  32 +++++++-
 arch/arm64/include/asm/fiq.h    |  18 +++++
 drivers/irqchip/irq-gic.c       | 165 +++++++++++++++++++++++++++++++++++++---
 include/linux/irqchip/arm-gic.h |   3 +
 9 files changed, 412 insertions(+), 23 deletions(-)
 create mode 100644 arch/arm64/include/asm/fiq.h

--
1.9.3


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v2 0/5] arm: Implement arch_trigger_all_cpu_backtrace
@ 2014-09-05 15:33                       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-05 15:33 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset implements arch_trigger_all_cpu_backtrace for arm.

Non-maskable signalling relies on the kernel being able to access FIQ
and therefore, for devices that implement TrustZone, it will work only on
systems that boot the kernel in secure mode.

Tested on Freescale iMX.6 (both via SysRq-l and by deliberately locking
up the kernel with CONFIG_DEBUG_SPINLOCK=y).

Changes since v1:

* Restructured to sit nicely on a similar FYI patchset from Russell
  King. It now effectively replaces the work in progress final patch
  with something much more complete.

* Implemented (and tested) a Thumb-2 implementation of svc_exit_via_fiq
  (review of Nicolas Pitre)

* Dropped the GIC group 0 workaround patch. The issue of FIQ interrupts
  being acknowledged by the IRQ handler does still exist but should be
  harmless because the IRQ handler will still wind up calling
  ipi_cpu_backtrace().

* Removed any dependency on CONFIG_FIQ; all cpu backtrace effectively
  becomes a platform feature (although the use of non-maskable
  interrupts to implement it is best effort rather than guaranteed).

* Better comments highlighting usage of RAZ/WI registers (and parts of
  registers) in the GIC code.

Changes *before* v1:

* This patchset is a hugely cut-down successor to "[PATCH v11 00/19]
  arm: KGDB NMI/FIQ support". Thanks to Thomas Gleixner for suggesting
  the new structure. For historic details see:
        https://lkml.org/lkml/2014/9/2/227

* Fix bug in __fiq_abt (no longer passes a bad struct pt_regs value).
  In fixing this we also remove the useless indirection previously
  found in the fiq_handler macro.

* Make default fiq handler "always on" by migrating from fiq.c to
  traps.c and replace do_unexp_fiq with the new handler (review
  of Russell King).

* Add arm64 version of fiq.h (review of Russell King)

* Removed conditional branching and code from irq-gic.c, this is
  replaced by much simpler code that relies on the GIC specification's
  heavy use of read-as-zero/write-ignored (review of Russell King)


Daniel Thompson (3):
  arm: fiq: Replace default FIQ handler
  arm64: Introduce dummy version of asm/fiq.h
  irqchip: gic: Add support for IPI FIQ

Russell King (2):
  ARM: remove unused do_unexp_fiq() function
  ARM: add basic support for on-demand backtrace of other CPUs

 arch/arm/include/asm/irq.h      |   5 ++
 arch/arm/include/asm/smp.h      |   3 +
 arch/arm/kernel/entry-armv.S    | 137 ++++++++++++++++++++++++++++++---
 arch/arm/kernel/setup.c         |   8 +-
 arch/arm/kernel/smp.c           |  64 ++++++++++++++++
 arch/arm/kernel/traps.c         |  32 +++++++-
 arch/arm64/include/asm/fiq.h    |  18 +++++
 drivers/irqchip/irq-gic.c       | 165 +++++++++++++++++++++++++++++++++++++---
 include/linux/irqchip/arm-gic.h |   3 +
 9 files changed, 412 insertions(+), 23 deletions(-)
 create mode 100644 arch/arm64/include/asm/fiq.h

--
1.9.3

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v2 1/5] ARM: remove unused do_unexp_fiq() function
  2014-09-05 15:33                       ` Daniel Thompson
@ 2014-09-05 15:33                         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-05 15:33 UTC (permalink / raw)
  To: Russell King
  Cc: Russell King, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal

From: Russell King <rmk+kernel@arm.linux.org.uk>

do_unexp_fiq() has never been called by any code in the last 10 years,
it's about time it was removed!

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/kernel/traps.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index c8e4bb7..a447dcc 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -460,12 +460,6 @@ die_sig:
 	arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
 }
 
-asmlinkage void do_unexp_fiq (struct pt_regs *regs)
-{
-	printk("Hmm.  Unexpected FIQ received, but trying to continue\n");
-	printk("You may have a hardware problem...\n");
-}
-
 /*
  * bad_mode handles the impossible case in the vectors.  If you see one of
  * these, then it's extremely serious, and could mean you have buggy hardware.
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v2 1/5] ARM: remove unused do_unexp_fiq() function
@ 2014-09-05 15:33                         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-05 15:33 UTC (permalink / raw)
  To: linux-arm-kernel

From: Russell King <rmk+kernel@arm.linux.org.uk>

do_unexp_fiq() has never been called by any code in the last 10 years,
it's about time it was removed!

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/kernel/traps.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index c8e4bb7..a447dcc 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -460,12 +460,6 @@ die_sig:
 	arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
 }
 
-asmlinkage void do_unexp_fiq (struct pt_regs *regs)
-{
-	printk("Hmm.  Unexpected FIQ received, but trying to continue\n");
-	printk("You may have a hardware problem...\n");
-}
-
 /*
  * bad_mode handles the impossible case in the vectors.  If you see one of
  * these, then it's extremely serious, and could mean you have buggy hardware.
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v2 2/5] ARM: add basic support for on-demand backtrace of other CPUs
  2014-09-05 15:33                       ` Daniel Thompson
@ 2014-09-05 15:33                         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-05 15:33 UTC (permalink / raw)
  To: Russell King
  Cc: Russell King, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal

From: Russell King <rmk+kernel@arm.linux.org.uk>

Add basic infrastructure for triggering a backtrace of other CPUs
via an IPI, preferably at FIQ level.  It is intended that this shall
be used for cases where we have detected that something has already
failed in the kernel.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/include/asm/irq.h |  5 ++++
 arch/arm/kernel/smp.c      | 62 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+)

diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h
index 53c15de..be1d07d 100644
--- a/arch/arm/include/asm/irq.h
+++ b/arch/arm/include/asm/irq.h
@@ -35,6 +35,11 @@ extern void (*handle_arch_irq)(struct pt_regs *);
 extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
 #endif
 
+#ifdef CONFIG_SMP
+extern void arch_trigger_all_cpu_backtrace(bool);
+#define arch_trigger_all_cpu_backtrace(x) arch_trigger_all_cpu_backtrace(x)
+#endif
+
 #endif
 
 #endif
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9388a3d..94959f9 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -72,8 +72,12 @@ enum ipi_msg_type {
 	IPI_CPU_STOP,
 	IPI_IRQ_WORK,
 	IPI_COMPLETION,
+	IPI_CPU_BACKTRACE,
 };
 
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
+
 static DECLARE_COMPLETION(cpu_running);
 
 static struct smp_operations smp_ops;
@@ -539,6 +543,21 @@ static void ipi_cpu_stop(unsigned int cpu)
 		cpu_relax();
 }
 
+static void ipi_cpu_backtrace(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+
+	if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
+		static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
+
+		arch_spin_lock(&lock);
+		printk(KERN_WARNING "FIQ backtrace for cpu %d\n", cpu);
+		show_regs(regs);
+		arch_spin_unlock(&lock);
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+	}
+}
+
 static DEFINE_PER_CPU(struct completion *, cpu_completion);
 
 int register_ipi_completion(struct completion *completion, int cpu)
@@ -618,6 +637,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		irq_exit();
 		break;
 
+	case IPI_CPU_BACKTRACE:
+		irq_enter();
+		ipi_cpu_backtrace(regs);
+		irq_exit();
+		break;
+
 	default:
 		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
 		       cpu, ipinr);
@@ -712,3 +737,40 @@ static int __init register_cpufreq_notifier(void)
 core_initcall(register_cpufreq_notifier);
 
 #endif
+
+void arch_trigger_all_cpu_backtrace(bool include_self)
+{
+	static unsigned long backtrace_flag;
+	int i, cpu = get_cpu();
+
+	if (test_and_set_bit(0, &backtrace_flag)) {
+		/*
+		 * If there is already a trigger_all_cpu_backtrace() in progress
+		 * (backtrace_flag == 1), don't output double cpu dump infos.
+		 */
+		put_cpu();
+		return;
+	}
+
+	cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
+	if (!include_self)
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+
+	if (!cpumask_empty(to_cpumask(backtrace_mask))) {
+		pr_info("Sending FIQ to %s CPUs:\n",
+			(include_self ? "all" : "other"));
+		smp_cross_call(to_cpumask(backtrace_mask), IPI_CPU_BACKTRACE);
+	}
+
+	/* Wait for up to 10 seconds for all CPUs to do the backtrace */
+	for (i = 0; i < 10 * 1000; i++) {
+		if (cpumask_empty(to_cpumask(backtrace_mask)))
+			break;
+
+		mdelay(1);
+	}
+
+	clear_bit(0, &backtrace_flag);
+	smp_mb__after_atomic();
+	put_cpu();
+}
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v2 2/5] ARM: add basic support for on-demand backtrace of other CPUs
@ 2014-09-05 15:33                         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-05 15:33 UTC (permalink / raw)
  To: linux-arm-kernel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Add basic infrastructure for triggering a backtrace of other CPUs
via an IPI, preferably at FIQ level.  It is intended that this shall
be used for cases where we have detected that something has already
failed in the kernel.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/include/asm/irq.h |  5 ++++
 arch/arm/kernel/smp.c      | 62 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+)

diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h
index 53c15de..be1d07d 100644
--- a/arch/arm/include/asm/irq.h
+++ b/arch/arm/include/asm/irq.h
@@ -35,6 +35,11 @@ extern void (*handle_arch_irq)(struct pt_regs *);
 extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
 #endif
 
+#ifdef CONFIG_SMP
+extern void arch_trigger_all_cpu_backtrace(bool);
+#define arch_trigger_all_cpu_backtrace(x) arch_trigger_all_cpu_backtrace(x)
+#endif
+
 #endif
 
 #endif
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9388a3d..94959f9 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -72,8 +72,12 @@ enum ipi_msg_type {
 	IPI_CPU_STOP,
 	IPI_IRQ_WORK,
 	IPI_COMPLETION,
+	IPI_CPU_BACKTRACE,
 };
 
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
+
 static DECLARE_COMPLETION(cpu_running);
 
 static struct smp_operations smp_ops;
@@ -539,6 +543,21 @@ static void ipi_cpu_stop(unsigned int cpu)
 		cpu_relax();
 }
 
+static void ipi_cpu_backtrace(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+
+	if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
+		static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
+
+		arch_spin_lock(&lock);
+		printk(KERN_WARNING "FIQ backtrace for cpu %d\n", cpu);
+		show_regs(regs);
+		arch_spin_unlock(&lock);
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+	}
+}
+
 static DEFINE_PER_CPU(struct completion *, cpu_completion);
 
 int register_ipi_completion(struct completion *completion, int cpu)
@@ -618,6 +637,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		irq_exit();
 		break;
 
+	case IPI_CPU_BACKTRACE:
+		irq_enter();
+		ipi_cpu_backtrace(regs);
+		irq_exit();
+		break;
+
 	default:
 		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
 		       cpu, ipinr);
@@ -712,3 +737,40 @@ static int __init register_cpufreq_notifier(void)
 core_initcall(register_cpufreq_notifier);
 
 #endif
+
+void arch_trigger_all_cpu_backtrace(bool include_self)
+{
+	static unsigned long backtrace_flag;
+	int i, cpu = get_cpu();
+
+	if (test_and_set_bit(0, &backtrace_flag)) {
+		/*
+		 * If there is already a trigger_all_cpu_backtrace() in progress
+		 * (backtrace_flag == 1), don't output double cpu dump infos.
+		 */
+		put_cpu();
+		return;
+	}
+
+	cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
+	if (!include_self)
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+
+	if (!cpumask_empty(to_cpumask(backtrace_mask))) {
+		pr_info("Sending FIQ to %s CPUs:\n",
+			(include_self ? "all" : "other"));
+		smp_cross_call(to_cpumask(backtrace_mask), IPI_CPU_BACKTRACE);
+	}
+
+	/* Wait for up to 10 seconds for all CPUs to do the backtrace */
+	for (i = 0; i < 10 * 1000; i++) {
+		if (cpumask_empty(to_cpumask(backtrace_mask)))
+			break;
+
+		mdelay(1);
+	}
+
+	clear_bit(0, &backtrace_flag);
+	smp_mb__after_atomic();
+	put_cpu();
+}
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v2 3/5] arm: fiq: Replace default FIQ handler
  2014-09-05 15:33                       ` Daniel Thompson
@ 2014-09-05 15:33                         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-05 15:33 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Nicolas Pitre, Catalin Marinas

This patch introduces a new default FIQ handler that is structured in a
similar way to the existing ARM exception handler and result in the FIQ
being handled by C code running on the SVC stack (despite this code run
in the FIQ handler is subject to severe limitations with respect to
locking making normal interaction with the kernel impossible).

This default handler allows concepts that on x86 would be handled using
NMIs to be realized on ARM.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of small fragments
    survive, however without Anton's work to build from this patch would
    not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
---
 arch/arm/include/asm/smp.h   |   3 +
 arch/arm/kernel/entry-armv.S | 137 +++++++++++++++++++++++++++++++++++++++----
 arch/arm/kernel/setup.c      |   8 ++-
 arch/arm/kernel/smp.c        |   4 +-
 arch/arm/kernel/traps.c      |  28 +++++++++
 5 files changed, 168 insertions(+), 12 deletions(-)

diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2ec765c..0580270 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -18,6 +18,8 @@
 # error "<asm/smp.h> included in non-SMP build"
 #endif
 
+#define SMP_IPI_FIQ_MASK 0x0100
+
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
 struct seq_file;
@@ -85,6 +87,7 @@ extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
 
+extern void ipi_cpu_backtrace(struct pt_regs *regs);
 extern int register_ipi_completion(struct completion *completion, int cpu);
 
 struct smp_operations {
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 36276cd..eb37aa5 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -146,7 +146,7 @@ ENDPROC(__und_invalid)
 #define SPFIX(code...)
 #endif
 
-	.macro	svc_entry, stack_hole=0
+	.macro	svc_entry, stack_hole=0, call_trace=1
  UNWIND(.fnstart		)
  UNWIND(.save {r0 - pc}		)
 	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
@@ -183,7 +183,51 @@ ENDPROC(__und_invalid)
 	stmia	r7, {r2 - r6}
 
 #ifdef CONFIG_TRACE_IRQFLAGS
+	.if \call_trace
 	bl	trace_hardirqs_off
+	.endif
+#endif
+	.endm
+
+@
+@ svc_exit_via_fiq - similar to svc_exit but switches to FIQ mode before exit
+@
+@ This macro acts in a similar manner to svc_exit but switches to FIQ
+@ mode to restore the final part of the register state.
+@
+@ We cannot use the normal svc_exit procedure because that would
+@ clobber spsr_svc (FIQ could be delivered during the first few instructions
+@ of vector_swi meaning its contents have not been saved anywhere).
+@
+@ Note that, unlike svc_exit, this macro also does not allow a caller
+@ supplied rpsr. This is because the FIQ exceptions are not re-entrant
+@ and the handlers cannot call into the scheduler (meaning the value
+@ on the stack remains correct).
+@
+	.macro  svc_exit_via_fiq
+
+#ifndef CONFIG_THUMB2_KERNEL
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+#else
+	add	r0, sp, #S_R2
+	ldr	lr, [sp, #S_LR]
+	ldr	sp, [sp, #S_SP] @ abort is deadly from here onward (it will
+			        @ clobber state restored below)
+	ldmia	r0, {r2 - r12}
+	mov	r1, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	msr	cpsr_c, r1
+	sub	r0, #S_R2
+	add	r8, r0, #S_PC
+	ldmia	r0, {r0 - r1}
+	rfeia	r8
 #endif
 	.endm
 
@@ -295,6 +339,15 @@ __pabt_svc:
 ENDPROC(__pabt_svc)
 
 	.align	5
+__fiq_svc:
+	svc_entry 0, 0
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	svc_exit_via_fiq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+	.align	5
 .LCcralign:
 	.word	cr_alignment
 #ifdef MULTI_DABORT
@@ -305,6 +358,46 @@ ENDPROC(__pabt_svc)
 	.word	fp_enter
 
 /*
+ * Abort mode handlers
+ */
+
+@
+@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
+@ and reuses the same macros. However in abort mode we must also
+@ save/restore lr_abt and spsr_abt to make nested aborts safe.
+@
+	.align 5
+__fiq_abt:
+	svc_entry 0, 0
+
+ ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	mov	r1, lr		@ Save lr_abt
+	mrs	r2, spsr	@ Save spsr_abt, abort is now safe
+ ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	push	{r1 - r2}
+
+	sub	r0, sp, #8			@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+
+	pop	{r1 - r2}
+ ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	mov	lr, r1		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r2	@ Restore spsr_abt
+ ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+
+	svc_exit_via_fiq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+/*
  * User mode handlers
  *
  * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
@@ -683,6 +776,18 @@ ENTRY(ret_from_exception)
 ENDPROC(__pabt_usr)
 ENDPROC(ret_from_exception)
 
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+
 /*
  * Register switch for ARMv3 and ARMv4 processors
  * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
@@ -1118,17 +1223,29 @@ vector_addrexcptn:
 	b	vector_addrexcptn
 
 /*=============================================================================
- * Undefined FIQs
+ * FIQ "NMI" handler
  *-----------------------------------------------------------------------------
- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
- * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
- * Basically to switch modes, we *HAVE* to clobber one register...  brain
- * damage alert!  I don't think that we can execute any code in here in any
- * other mode than FIQ...  Ok you can switch to another mode, but you can't
- * get out of that mode without clobbering one register.
+ * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
+ * systems.
  */
-vector_fiq:
-	subs	pc, lr, #4
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
 
 	.globl	vector_fiq_offset
 	.equ	vector_fiq_offset, vector_fiq
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 84db893d..c031063 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -133,6 +133,7 @@ struct stack {
 	u32 irq[3];
 	u32 abt[3];
 	u32 und[3];
+	u32 fiq[3];
 } ____cacheline_aligned;
 
 #ifndef CONFIG_CPU_V7M
@@ -470,7 +471,10 @@ void notrace cpu_init(void)
 	"msr	cpsr_c, %5\n\t"
 	"add	r14, %0, %6\n\t"
 	"mov	sp, r14\n\t"
-	"msr	cpsr_c, %7"
+	"msr	cpsr_c, %7\n\t"
+	"add	r14, %0, %8\n\t"
+	"mov	sp, r14\n\t"
+	"msr	cpsr_c, %9"
 	    :
 	    : "r" (stk),
 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
@@ -479,6 +483,8 @@ void notrace cpu_init(void)
 	      "I" (offsetof(struct stack, abt[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
 	      "I" (offsetof(struct stack, und[0])),
+	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+	      "I" (offsetof(struct stack, fiq[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
 	    : "r14");
 #endif
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 94959f9..7a79d11 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -543,7 +543,7 @@ static void ipi_cpu_stop(unsigned int cpu)
 		cpu_relax();
 }
 
-static void ipi_cpu_backtrace(struct pt_regs *regs)
+void ipi_cpu_backtrace(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
 
@@ -584,6 +584,8 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 	unsigned int cpu = smp_processor_id();
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
+	BUILD_BUG_ON(SMP_IPI_FIQ_MASK != BIT(IPI_CPU_BACKTRACE));
+
 	if ((unsigned)ipinr < NR_IPI) {
 		trace_ipi_entry(ipi_types[ipinr]);
 		__inc_irq_stat(cpu, ipi_irqs[ipinr]);
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index a447dcc..f8189c2 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -25,6 +25,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/irq.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -461,6 +462,33 @@ die_sig:
 }
 
 /*
+ * Handle FIQ similarly to NMI on x86 systems.
+ *
+ * The runtime environment for NMIs is extremely restrictive
+ * (NMIs can pre-empt critical sections meaning almost all locking is
+ * forbidden) meaning this default FIQ handling must only be used in
+ * circumstances where non-maskability improves robustness, such as
+ * watchdog or debug logic.
+ *
+ * This handler is not appropriate for general purpose use in drivers
+ * platform code and can be overrideen using set_fiq_handler.
+ */
+asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
+{
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	nmi_enter();
+
+#ifdef CONFIG_SMP
+	ipi_cpu_backtrace(regs);
+#endif
+
+	nmi_exit();
+
+	set_irq_regs(old_regs);
+}
+
+/*
  * bad_mode handles the impossible case in the vectors.  If you see one of
  * these, then it's extremely serious, and could mean you have buggy hardware.
  * It never returns, and never tries to sync.  We hope that we can at least
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v2 3/5] arm: fiq: Replace default FIQ handler
@ 2014-09-05 15:33                         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-05 15:33 UTC (permalink / raw)
  To: linux-arm-kernel

This patch introduces a new default FIQ handler that is structured in a
similar way to the existing ARM exception handler and result in the FIQ
being handled by C code running on the SVC stack (despite this code run
in the FIQ handler is subject to severe limitations with respect to
locking making normal interaction with the kernel impossible).

This default handler allows concepts that on x86 would be handled using
NMIs to be realized on ARM.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of small fragments
    survive, however without Anton's work to build from this patch would
    not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
---
 arch/arm/include/asm/smp.h   |   3 +
 arch/arm/kernel/entry-armv.S | 137 +++++++++++++++++++++++++++++++++++++++----
 arch/arm/kernel/setup.c      |   8 ++-
 arch/arm/kernel/smp.c        |   4 +-
 arch/arm/kernel/traps.c      |  28 +++++++++
 5 files changed, 168 insertions(+), 12 deletions(-)

diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2ec765c..0580270 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -18,6 +18,8 @@
 # error "<asm/smp.h> included in non-SMP build"
 #endif
 
+#define SMP_IPI_FIQ_MASK 0x0100
+
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
 struct seq_file;
@@ -85,6 +87,7 @@ extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
 
+extern void ipi_cpu_backtrace(struct pt_regs *regs);
 extern int register_ipi_completion(struct completion *completion, int cpu);
 
 struct smp_operations {
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 36276cd..eb37aa5 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -146,7 +146,7 @@ ENDPROC(__und_invalid)
 #define SPFIX(code...)
 #endif
 
-	.macro	svc_entry, stack_hole=0
+	.macro	svc_entry, stack_hole=0, call_trace=1
  UNWIND(.fnstart		)
  UNWIND(.save {r0 - pc}		)
 	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
@@ -183,7 +183,51 @@ ENDPROC(__und_invalid)
 	stmia	r7, {r2 - r6}
 
 #ifdef CONFIG_TRACE_IRQFLAGS
+	.if \call_trace
 	bl	trace_hardirqs_off
+	.endif
+#endif
+	.endm
+
+@
+@ svc_exit_via_fiq - similar to svc_exit but switches to FIQ mode before exit
+@
+@ This macro acts in a similar manner to svc_exit but switches to FIQ
+@ mode to restore the final part of the register state.
+@
+@ We cannot use the normal svc_exit procedure because that would
+@ clobber spsr_svc (FIQ could be delivered during the first few instructions
+@ of vector_swi meaning its contents have not been saved anywhere).
+@
+@ Note that, unlike svc_exit, this macro also does not allow a caller
+@ supplied rpsr. This is because the FIQ exceptions are not re-entrant
+@ and the handlers cannot call into the scheduler (meaning the value
+@ on the stack remains correct).
+@
+	.macro  svc_exit_via_fiq
+
+#ifndef CONFIG_THUMB2_KERNEL
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+#else
+	add	r0, sp, #S_R2
+	ldr	lr, [sp, #S_LR]
+	ldr	sp, [sp, #S_SP] @ abort is deadly from here onward (it will
+			        @ clobber state restored below)
+	ldmia	r0, {r2 - r12}
+	mov	r1, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	msr	cpsr_c, r1
+	sub	r0, #S_R2
+	add	r8, r0, #S_PC
+	ldmia	r0, {r0 - r1}
+	rfeia	r8
 #endif
 	.endm
 
@@ -295,6 +339,15 @@ __pabt_svc:
 ENDPROC(__pabt_svc)
 
 	.align	5
+__fiq_svc:
+	svc_entry 0, 0
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	svc_exit_via_fiq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+	.align	5
 .LCcralign:
 	.word	cr_alignment
 #ifdef MULTI_DABORT
@@ -305,6 +358,46 @@ ENDPROC(__pabt_svc)
 	.word	fp_enter
 
 /*
+ * Abort mode handlers
+ */
+
+@
+@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
+@ and reuses the same macros. However in abort mode we must also
+@ save/restore lr_abt and spsr_abt to make nested aborts safe.
+@
+	.align 5
+__fiq_abt:
+	svc_entry 0, 0
+
+ ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	mov	r1, lr		@ Save lr_abt
+	mrs	r2, spsr	@ Save spsr_abt, abort is now safe
+ ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	push	{r1 - r2}
+
+	sub	r0, sp, #8			@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+
+	pop	{r1 - r2}
+ ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	mov	lr, r1		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r2	@ Restore spsr_abt
+ ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+
+	svc_exit_via_fiq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+/*
  * User mode handlers
  *
  * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
@@ -683,6 +776,18 @@ ENTRY(ret_from_exception)
 ENDPROC(__pabt_usr)
 ENDPROC(ret_from_exception)
 
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+
 /*
  * Register switch for ARMv3 and ARMv4 processors
  * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
@@ -1118,17 +1223,29 @@ vector_addrexcptn:
 	b	vector_addrexcptn
 
 /*=============================================================================
- * Undefined FIQs
+ * FIQ "NMI" handler
  *-----------------------------------------------------------------------------
- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
- * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
- * Basically to switch modes, we *HAVE* to clobber one register...  brain
- * damage alert!  I don't think that we can execute any code in here in any
- * other mode than FIQ...  Ok you can switch to another mode, but you can't
- * get out of that mode without clobbering one register.
+ * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
+ * systems.
  */
-vector_fiq:
-	subs	pc, lr, #4
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
 
 	.globl	vector_fiq_offset
 	.equ	vector_fiq_offset, vector_fiq
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 84db893d..c031063 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -133,6 +133,7 @@ struct stack {
 	u32 irq[3];
 	u32 abt[3];
 	u32 und[3];
+	u32 fiq[3];
 } ____cacheline_aligned;
 
 #ifndef CONFIG_CPU_V7M
@@ -470,7 +471,10 @@ void notrace cpu_init(void)
 	"msr	cpsr_c, %5\n\t"
 	"add	r14, %0, %6\n\t"
 	"mov	sp, r14\n\t"
-	"msr	cpsr_c, %7"
+	"msr	cpsr_c, %7\n\t"
+	"add	r14, %0, %8\n\t"
+	"mov	sp, r14\n\t"
+	"msr	cpsr_c, %9"
 	    :
 	    : "r" (stk),
 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
@@ -479,6 +483,8 @@ void notrace cpu_init(void)
 	      "I" (offsetof(struct stack, abt[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
 	      "I" (offsetof(struct stack, und[0])),
+	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+	      "I" (offsetof(struct stack, fiq[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
 	    : "r14");
 #endif
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 94959f9..7a79d11 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -543,7 +543,7 @@ static void ipi_cpu_stop(unsigned int cpu)
 		cpu_relax();
 }
 
-static void ipi_cpu_backtrace(struct pt_regs *regs)
+void ipi_cpu_backtrace(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
 
@@ -584,6 +584,8 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 	unsigned int cpu = smp_processor_id();
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
+	BUILD_BUG_ON(SMP_IPI_FIQ_MASK != BIT(IPI_CPU_BACKTRACE));
+
 	if ((unsigned)ipinr < NR_IPI) {
 		trace_ipi_entry(ipi_types[ipinr]);
 		__inc_irq_stat(cpu, ipi_irqs[ipinr]);
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index a447dcc..f8189c2 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -25,6 +25,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/irq.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -461,6 +462,33 @@ die_sig:
 }
 
 /*
+ * Handle FIQ similarly to NMI on x86 systems.
+ *
+ * The runtime environment for NMIs is extremely restrictive
+ * (NMIs can pre-empt critical sections meaning almost all locking is
+ * forbidden) meaning this default FIQ handling must only be used in
+ * circumstances where non-maskability improves robustness, such as
+ * watchdog or debug logic.
+ *
+ * This handler is not appropriate for general purpose use in drivers
+ * platform code and can be overrideen using set_fiq_handler.
+ */
+asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
+{
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	nmi_enter();
+
+#ifdef CONFIG_SMP
+	ipi_cpu_backtrace(regs);
+#endif
+
+	nmi_exit();
+
+	set_irq_regs(old_regs);
+}
+
+/*
  * bad_mode handles the impossible case in the vectors.  If you see one of
  * these, then it's extremely serious, and could mean you have buggy hardware.
  * It never returns, and never tries to sync.  We hope that we can at least
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v2 4/5] arm64: Introduce dummy version of asm/fiq.h
  2014-09-05 15:33                       ` Daniel Thompson
@ 2014-09-05 15:33                         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-05 15:33 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Catalin Marinas, Will Deacon

Drivers that are shared between arm and arm64 and which employ
FIQ on arm cannot include asm/fiq.h without #ifdef'ing. This patch
introduces a dummy version of asm/fiq.h to arm64 to avoid this.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
 arch/arm64/include/asm/fiq.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 arch/arm64/include/asm/fiq.h

diff --git a/arch/arm64/include/asm/fiq.h b/arch/arm64/include/asm/fiq.h
new file mode 100644
index 0000000..909ec54
--- /dev/null
+++ b/arch/arm64/include/asm/fiq.h
@@ -0,0 +1,18 @@
+/*
+ * arch/arm64/include/asm/fiq.h
+ *
+ * Placeholder to reduce #ifdef'ing in shared arm/arm64 drivers.
+ */
+
+#ifndef __ASM_FIQ_H
+#define __ASM_FIQ_H
+
+/*
+ * This placeholder allows code of the following form to be simplified:
+ *
+ * #ifdef CONFIG_FIQ
+ * #include <asm/fiq.h>
+ * #endif
+ */
+
+#endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v2 4/5] arm64: Introduce dummy version of asm/fiq.h
@ 2014-09-05 15:33                         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-05 15:33 UTC (permalink / raw)
  To: linux-arm-kernel

Drivers that are shared between arm and arm64 and which employ
FIQ on arm cannot include asm/fiq.h without #ifdef'ing. This patch
introduces a dummy version of asm/fiq.h to arm64 to avoid this.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
 arch/arm64/include/asm/fiq.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 arch/arm64/include/asm/fiq.h

diff --git a/arch/arm64/include/asm/fiq.h b/arch/arm64/include/asm/fiq.h
new file mode 100644
index 0000000..909ec54
--- /dev/null
+++ b/arch/arm64/include/asm/fiq.h
@@ -0,0 +1,18 @@
+/*
+ * arch/arm64/include/asm/fiq.h
+ *
+ * Placeholder to reduce #ifdef'ing in shared arm/arm64 drivers.
+ */
+
+#ifndef __ASM_FIQ_H
+#define __ASM_FIQ_H
+
+/*
+ * This placeholder allows code of the following form to be simplified:
+ *
+ * #ifdef CONFIG_FIQ
+ * #include <asm/fiq.h>
+ * #endif
+ */
+
+#endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v2 5/5] irqchip: gic: Add support for IPI FIQ
  2014-09-05 15:33                       ` Daniel Thompson
@ 2014-09-05 15:33                         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-05 15:33 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Jason Cooper

This patch provides support for arm's newly added IPI FIQ. It works
by placing all interrupt sources *except* IPI FIQ in group 1 and
then flips a configuration bit in the GIC such that group 1
interrupts use IRQ and group 0 interrupts use FIQ.

All GIC hardware except GICv1-without-TrustZone support provides a means
to group exceptions into group 0 and group 1. However the hardware
functionality is unavailable to the kernel when a secure monitor is
present because access to the grouping registers are prohibited outside
"secure world" (a feature that allows grouping to be used to allow
hardware peripherals to send interrupts into the secure world). However
when grouping is not available we can rely on the GIC's RAZ/WI semantics
and avoid conditional code.

Tested on Freescale i.MX6 (quad A9, GICv1-with-TrustZone running in
secure mode).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
---
 arch/arm/kernel/traps.c         |   4 +
 drivers/irqchip/irq-gic.c       | 165 +++++++++++++++++++++++++++++++++++++---
 include/linux/irqchip/arm-gic.h |   3 +
 3 files changed, 163 insertions(+), 9 deletions(-)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index f8189c2..40b1de7 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/irq.h>
+#include <linux/irqchip/arm-gic.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -479,6 +480,9 @@ asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
 
 	nmi_enter();
 
+#ifdef CONFIG_ARM_GIC
+	gic_handle_fiq_ipi();
+#endif
 #ifdef CONFIG_SMP
 	ipi_cpu_backtrace(regs);
 #endif
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4b959e6..f554ee5 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,8 +39,10 @@
 #include <linux/slab.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/ratelimit.h>
 
 #include <asm/cputype.h>
+#include <asm/fiq.h>
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
@@ -48,6 +50,10 @@
 #include "irq-gic-common.h"
 #include "irqchip.h"
 
+#ifndef SMP_IPI_FIQ_MASK
+#define SMP_IPI_FIQ_MASK 0
+#endif
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -71,6 +77,8 @@ struct gic_chip_data {
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+/* A fiq-safe spinlock must only be locked when the FIQ is masked */
+static DEFINE_RAW_SPINLOCK(fiq_safe_migration_lock);
 
 /*
  * The GIC mapping of CPU interfaces does not necessarily match
@@ -325,6 +333,94 @@ static struct irq_chip gic_chip = {
 	.irq_set_wake		= gic_set_wake,
 };
 
+/*
+ * Shift an interrupt between Group 0 and Group 1.
+ *
+ * In addition to changing the group we also modify the priority to
+ * match what "ARM strongly recommends" for a system where no Group 1
+ * interrupt must ever preempt a Group 0 interrupt.
+ *
+ * If is safe to call this function on systems which do not support
+ * grouping (it will have no effect).
+ */
+static void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				int group)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_mask = BIT(hwirq % 32);
+	u32 grp_val;
+
+	unsigned int pri_reg = (hwirq / 4) * 4;
+	u32 pri_mask = BIT(7 + ((hwirq % 4) * 8));
+	u32 pri_val;
+
+	/*
+	 * Systems which do not support grouping will have no bits
+	 * set in IGROUP[0] (and all systems which do will have set bits).
+	 */
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + 0);
+	if (!grp_val)
+		return;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(base + GIC_DIST_PRI + pri_reg);
+
+	if (group) {
+		grp_val |= grp_mask;
+		pri_val |= pri_mask;
+	} else {
+		grp_val &= ~grp_mask;
+		pri_val &= ~pri_mask;
+	}
+
+	writel_relaxed(grp_val, base + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, base + GIC_DIST_PRI + pri_reg);
+
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+/*
+ * Test which group an interrupt belongs to.
+ *
+ * Returns 0 if the controller does not support grouping.
+ */
+static int gic_get_group_irq(void __iomem *base, unsigned int hwirq)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_val;
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+
+	return (grp_val >> (hwirq % 32)) & 1;
+}
+
+/*
+ * Fully acknowledge (both ack and eoi) any outstanding FIQ-based IPI,
+ * otherwise do nothing.
+ */
+void gic_handle_fiq_ipi(void)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	unsigned long irqstat, irqnr;
+
+	if (WARN_ON(!in_nmi()))
+		return;
+
+	while ((1u << readl_relaxed(cpu_base + GIC_CPU_HIGHPRI)) &
+	       SMP_IPI_FIQ_MASK) {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		WARN_RATELIMIT(irqnr > 16,
+			       "Unexpected irqnr %lu (bad prioritization?)\n",
+			       irqnr);
+	}
+}
+
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
 	if (gic_nr >= MAX_GIC_NR)
@@ -373,7 +469,18 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 
 	gic_dist_config(base, gic_irqs, NULL);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Set all global interrupts to be group 1 (this register is
+	 * RAZ/WI if not accessible in current mode)
+	 */
+	for (i = 32; i < gic_irqs; i += 32)
+		writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	writel_relaxed(3, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -382,6 +489,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	void __iomem *base = gic_data_cpu_base(gic);
 	unsigned int cpu_mask, cpu = smp_processor_id();
 	int i;
+	unsigned long secure_irqs, secure_irq;
 
 	/*
 	 * Get what the GIC says our CPU mask is.
@@ -400,8 +508,27 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 
 	gic_cpu_config(dist_base, NULL);
 
+	/*
+	 * Set any PPI and SGI interrupts not set in SMP_IPI_FIQ_MASK
+	 * to be group 1 (this register is RAZ/WI if not accessible)
+	 */
+	writel_relaxed(~SMP_IPI_FIQ_MASK, dist_base + GIC_DIST_IGROUP + 0);
+
+	/*
+	 * Update the priority of any resulting group0 interrupts.
+	 */
+	secure_irqs = ~readl_relaxed(dist_base + GIC_DIST_IGROUP + 0);
+	for_each_set_bit(secure_irq, &secure_irqs, 16)
+		gic_set_group_irq(dist_base, i, 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+
+	/* The bottom most bit will be set for all GIC variants (and is
+	 * called Enable or EnableGrp0 depending on operating mode). The
+	 * remaining four bits (CBPR, FIQEn, AckCtl and EnableGrp1) are
+	 * RAZ/WI if not accessible.
+	 */
+	writel_relaxed(0x1f, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -485,7 +612,7 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	writel_relaxed(3, dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -542,7 +669,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -604,8 +731,19 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
 	unsigned long flags, map = 0;
+	unsigned long softint;
 
-	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+	/*
+	 * The locking in this function ensures we don't use stale cpu mappings
+	 * and thus we never route an IPI to the wrong physical core during a
+	 * big.LITTLE switch. The switch code takes both of these locks meaning
+	 * we can choose whichever lock is safe to use from our current calling
+	 * context.
+	 */
+	if (in_nmi())
+		raw_spin_lock(&fiq_safe_migration_lock);
+	else
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
 	/* Convert our logical CPU mask into a physical one. */
 	for_each_cpu(cpu, mask)
@@ -618,9 +756,16 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
-
-	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+	softint = map << 16 | irq;
+	if (gic_get_group_irq(gic_data_dist_base(&gic_data[0]), irq))
+		softint |= 0x8000;
+	writel_relaxed(softint,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+
+	if (in_nmi())
+		raw_spin_unlock(&fiq_safe_migration_lock);
+	else
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 #endif
 
@@ -668,7 +813,7 @@ int gic_get_cpu_id(unsigned int cpu)
  * Migrate all peripheral interrupts with a target matching the current CPU
  * to the interface corresponding to @new_cpu_id.  The CPU interface mapping
  * is also updated.  Targets to other CPU interfaces are unchanged.
- * This must be called with IRQs locally disabled.
+ * This must be called with IRQ and FIQ locally disabled.
  */
 void gic_migrate_target(unsigned int new_cpu_id)
 {
@@ -690,6 +835,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 	ror_val = (cur_cpu_id - new_cpu_id) & 31;
 
 	raw_spin_lock(&irq_controller_lock);
+	raw_spin_lock(&fiq_safe_migration_lock);
 
 	/* Update the target interface for this logical CPU */
 	gic_cpu_map[cpu] = 1 << new_cpu_id;
@@ -709,6 +855,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 		}
 	}
 
+	raw_spin_unlock(&fiq_safe_migration_lock);
 	raw_spin_unlock(&irq_controller_lock);
 
 	/*
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 45e2d8c..52a5676 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops
 {
 	gic_routable_irq_domain_ops = ops;
 }
+
+void gic_handle_fiq_ipi(void);
+
 #endif /* __ASSEMBLY */
 #endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v2 5/5] irqchip: gic: Add support for IPI FIQ
@ 2014-09-05 15:33                         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-05 15:33 UTC (permalink / raw)
  To: linux-arm-kernel

This patch provides support for arm's newly added IPI FIQ. It works
by placing all interrupt sources *except* IPI FIQ in group 1 and
then flips a configuration bit in the GIC such that group 1
interrupts use IRQ and group 0 interrupts use FIQ.

All GIC hardware except GICv1-without-TrustZone support provides a means
to group exceptions into group 0 and group 1. However the hardware
functionality is unavailable to the kernel when a secure monitor is
present because access to the grouping registers are prohibited outside
"secure world" (a feature that allows grouping to be used to allow
hardware peripherals to send interrupts into the secure world). However
when grouping is not available we can rely on the GIC's RAZ/WI semantics
and avoid conditional code.

Tested on Freescale i.MX6 (quad A9, GICv1-with-TrustZone running in
secure mode).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
---
 arch/arm/kernel/traps.c         |   4 +
 drivers/irqchip/irq-gic.c       | 165 +++++++++++++++++++++++++++++++++++++---
 include/linux/irqchip/arm-gic.h |   3 +
 3 files changed, 163 insertions(+), 9 deletions(-)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index f8189c2..40b1de7 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/irq.h>
+#include <linux/irqchip/arm-gic.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -479,6 +480,9 @@ asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
 
 	nmi_enter();
 
+#ifdef CONFIG_ARM_GIC
+	gic_handle_fiq_ipi();
+#endif
 #ifdef CONFIG_SMP
 	ipi_cpu_backtrace(regs);
 #endif
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4b959e6..f554ee5 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,8 +39,10 @@
 #include <linux/slab.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/ratelimit.h>
 
 #include <asm/cputype.h>
+#include <asm/fiq.h>
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
@@ -48,6 +50,10 @@
 #include "irq-gic-common.h"
 #include "irqchip.h"
 
+#ifndef SMP_IPI_FIQ_MASK
+#define SMP_IPI_FIQ_MASK 0
+#endif
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -71,6 +77,8 @@ struct gic_chip_data {
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+/* A fiq-safe spinlock must only be locked when the FIQ is masked */
+static DEFINE_RAW_SPINLOCK(fiq_safe_migration_lock);
 
 /*
  * The GIC mapping of CPU interfaces does not necessarily match
@@ -325,6 +333,94 @@ static struct irq_chip gic_chip = {
 	.irq_set_wake		= gic_set_wake,
 };
 
+/*
+ * Shift an interrupt between Group 0 and Group 1.
+ *
+ * In addition to changing the group we also modify the priority to
+ * match what "ARM strongly recommends" for a system where no Group 1
+ * interrupt must ever preempt a Group 0 interrupt.
+ *
+ * If is safe to call this function on systems which do not support
+ * grouping (it will have no effect).
+ */
+static void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				int group)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_mask = BIT(hwirq % 32);
+	u32 grp_val;
+
+	unsigned int pri_reg = (hwirq / 4) * 4;
+	u32 pri_mask = BIT(7 + ((hwirq % 4) * 8));
+	u32 pri_val;
+
+	/*
+	 * Systems which do not support grouping will have no bits
+	 * set in IGROUP[0] (and all systems which do will have set bits).
+	 */
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + 0);
+	if (!grp_val)
+		return;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(base + GIC_DIST_PRI + pri_reg);
+
+	if (group) {
+		grp_val |= grp_mask;
+		pri_val |= pri_mask;
+	} else {
+		grp_val &= ~grp_mask;
+		pri_val &= ~pri_mask;
+	}
+
+	writel_relaxed(grp_val, base + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, base + GIC_DIST_PRI + pri_reg);
+
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+/*
+ * Test which group an interrupt belongs to.
+ *
+ * Returns 0 if the controller does not support grouping.
+ */
+static int gic_get_group_irq(void __iomem *base, unsigned int hwirq)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_val;
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+
+	return (grp_val >> (hwirq % 32)) & 1;
+}
+
+/*
+ * Fully acknowledge (both ack and eoi) any outstanding FIQ-based IPI,
+ * otherwise do nothing.
+ */
+void gic_handle_fiq_ipi(void)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	unsigned long irqstat, irqnr;
+
+	if (WARN_ON(!in_nmi()))
+		return;
+
+	while ((1u << readl_relaxed(cpu_base + GIC_CPU_HIGHPRI)) &
+	       SMP_IPI_FIQ_MASK) {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		WARN_RATELIMIT(irqnr > 16,
+			       "Unexpected irqnr %lu (bad prioritization?)\n",
+			       irqnr);
+	}
+}
+
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
 	if (gic_nr >= MAX_GIC_NR)
@@ -373,7 +469,18 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 
 	gic_dist_config(base, gic_irqs, NULL);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Set all global interrupts to be group 1 (this register is
+	 * RAZ/WI if not accessible in current mode)
+	 */
+	for (i = 32; i < gic_irqs; i += 32)
+		writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	writel_relaxed(3, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -382,6 +489,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	void __iomem *base = gic_data_cpu_base(gic);
 	unsigned int cpu_mask, cpu = smp_processor_id();
 	int i;
+	unsigned long secure_irqs, secure_irq;
 
 	/*
 	 * Get what the GIC says our CPU mask is.
@@ -400,8 +508,27 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 
 	gic_cpu_config(dist_base, NULL);
 
+	/*
+	 * Set any PPI and SGI interrupts not set in SMP_IPI_FIQ_MASK
+	 * to be group 1 (this register is RAZ/WI if not accessible)
+	 */
+	writel_relaxed(~SMP_IPI_FIQ_MASK, dist_base + GIC_DIST_IGROUP + 0);
+
+	/*
+	 * Update the priority of any resulting group0 interrupts.
+	 */
+	secure_irqs = ~readl_relaxed(dist_base + GIC_DIST_IGROUP + 0);
+	for_each_set_bit(secure_irq, &secure_irqs, 16)
+		gic_set_group_irq(dist_base, i, 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+
+	/* The bottom most bit will be set for all GIC variants (and is
+	 * called Enable or EnableGrp0 depending on operating mode). The
+	 * remaining four bits (CBPR, FIQEn, AckCtl and EnableGrp1) are
+	 * RAZ/WI if not accessible.
+	 */
+	writel_relaxed(0x1f, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -485,7 +612,7 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	writel_relaxed(3, dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -542,7 +669,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -604,8 +731,19 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
 	unsigned long flags, map = 0;
+	unsigned long softint;
 
-	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+	/*
+	 * The locking in this function ensures we don't use stale cpu mappings
+	 * and thus we never route an IPI to the wrong physical core during a
+	 * big.LITTLE switch. The switch code takes both of these locks meaning
+	 * we can choose whichever lock is safe to use from our current calling
+	 * context.
+	 */
+	if (in_nmi())
+		raw_spin_lock(&fiq_safe_migration_lock);
+	else
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
 	/* Convert our logical CPU mask into a physical one. */
 	for_each_cpu(cpu, mask)
@@ -618,9 +756,16 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
-
-	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+	softint = map << 16 | irq;
+	if (gic_get_group_irq(gic_data_dist_base(&gic_data[0]), irq))
+		softint |= 0x8000;
+	writel_relaxed(softint,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+
+	if (in_nmi())
+		raw_spin_unlock(&fiq_safe_migration_lock);
+	else
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 #endif
 
@@ -668,7 +813,7 @@ int gic_get_cpu_id(unsigned int cpu)
  * Migrate all peripheral interrupts with a target matching the current CPU
  * to the interface corresponding to @new_cpu_id.  The CPU interface mapping
  * is also updated.  Targets to other CPU interfaces are unchanged.
- * This must be called with IRQs locally disabled.
+ * This must be called with IRQ and FIQ locally disabled.
  */
 void gic_migrate_target(unsigned int new_cpu_id)
 {
@@ -690,6 +835,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 	ror_val = (cur_cpu_id - new_cpu_id) & 31;
 
 	raw_spin_lock(&irq_controller_lock);
+	raw_spin_lock(&fiq_safe_migration_lock);
 
 	/* Update the target interface for this logical CPU */
 	gic_cpu_map[cpu] = 1 << new_cpu_id;
@@ -709,6 +855,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 		}
 	}
 
+	raw_spin_unlock(&fiq_safe_migration_lock);
 	raw_spin_unlock(&irq_controller_lock);
 
 	/*
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 45e2d8c..52a5676 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops
 {
 	gic_routable_irq_domain_ops = ops;
 }
+
+void gic_handle_fiq_ipi(void);
+
 #endif /* __ASSEMBLY */
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* Re: [PATCH v2 4/5] arm64: Introduce dummy version of asm/fiq.h
  2014-09-05 15:33                         ` Daniel Thompson
@ 2014-09-05 16:50                           ` Catalin Marinas
  -1 siblings, 0 replies; 535+ messages in thread
From: Catalin Marinas @ 2014-09-05 16:50 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Russell King, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Will Deacon

On Fri, Sep 05, 2014 at 04:33:17PM +0100, Daniel Thompson wrote:
> Drivers that are shared between arm and arm64 and which employ
> FIQ on arm cannot include asm/fiq.h without #ifdef'ing. This patch
> introduces a dummy version of asm/fiq.h to arm64 to avoid this.
> 
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> ---
>  arch/arm64/include/asm/fiq.h | 18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)
>  create mode 100644 arch/arm64/include/asm/fiq.h
> 
> diff --git a/arch/arm64/include/asm/fiq.h b/arch/arm64/include/asm/fiq.h
> new file mode 100644
> index 0000000..909ec54
> --- /dev/null
> +++ b/arch/arm64/include/asm/fiq.h
> @@ -0,0 +1,18 @@
> +/*
> + * arch/arm64/include/asm/fiq.h
> + *
> + * Placeholder to reduce #ifdef'ing in shared arm/arm64 drivers.
> + */
> +
> +#ifndef __ASM_FIQ_H
> +#define __ASM_FIQ_H
> +
> +/*
> + * This placeholder allows code of the following form to be simplified:
> + *
> + * #ifdef CONFIG_FIQ
> + * #include <asm/fiq.h>
> + * #endif
> + */
> +
> +#endif

OK, we add a dummy file, but please keep it simple. Comments are fine
but no need for header guards (nor the file name, on arm64 we try to get
rid of them, though some still slip through).

Thanks.

-- 
Catalin

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v2 4/5] arm64: Introduce dummy version of asm/fiq.h
@ 2014-09-05 16:50                           ` Catalin Marinas
  0 siblings, 0 replies; 535+ messages in thread
From: Catalin Marinas @ 2014-09-05 16:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Sep 05, 2014 at 04:33:17PM +0100, Daniel Thompson wrote:
> Drivers that are shared between arm and arm64 and which employ
> FIQ on arm cannot include asm/fiq.h without #ifdef'ing. This patch
> introduces a dummy version of asm/fiq.h to arm64 to avoid this.
> 
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> ---
>  arch/arm64/include/asm/fiq.h | 18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)
>  create mode 100644 arch/arm64/include/asm/fiq.h
> 
> diff --git a/arch/arm64/include/asm/fiq.h b/arch/arm64/include/asm/fiq.h
> new file mode 100644
> index 0000000..909ec54
> --- /dev/null
> +++ b/arch/arm64/include/asm/fiq.h
> @@ -0,0 +1,18 @@
> +/*
> + * arch/arm64/include/asm/fiq.h
> + *
> + * Placeholder to reduce #ifdef'ing in shared arm/arm64 drivers.
> + */
> +
> +#ifndef __ASM_FIQ_H
> +#define __ASM_FIQ_H
> +
> +/*
> + * This placeholder allows code of the following form to be simplified:
> + *
> + * #ifdef CONFIG_FIQ
> + * #include <asm/fiq.h>
> + * #endif
> + */
> +
> +#endif

OK, we add a dummy file, but please keep it simple. Comments are fine
but no need for header guards (nor the file name, on arm64 we try to get
rid of them, though some still slip through).

Thanks.

-- 
Catalin

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v1 1/6] arm: fiq: Replace default FIQ handler
  2014-09-05  9:03                           ` Daniel Thompson
@ 2014-09-05 18:04                             ` Nicolas Pitre
  -1 siblings, 0 replies; 535+ messages in thread
From: Nicolas Pitre @ 2014-09-05 18:04 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Russell King, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Catalin Marinas

On Fri, 5 Sep 2014, Daniel Thompson wrote:

> On 04/09/14 19:57, Nicolas Pitre wrote:
> > On Thu, 4 Sep 2014, Daniel Thompson wrote:
> > 
> >> +@ svc_exit_via_fiq - similar to svc_exit but switches to FIQ mode before exit
> >> +@
> >> +@ This macro acts in a similar manner to svc_exit but switches to FIQ
> >> +@ mode to restore the final part of the register state.
> >> +@
> >> +@ We cannot use the normal svc_exit procedure because that would
> >> +@ clobber spsr_svc (FIQ could be delivered during the first few instructions
> >> +@ of vector_swi meaning its contents have not been saved anywhere).
> >> +@
> > 
> > Wouldn't it be better for this macro to live in entry-header.S alongside 
> > the others?
> 
> I'm not sure either way.
> 
> svc_exit_from_fiq isn't needed by entry-common.S and cannot be used by
> entry-v7m.S because v7m has no FIQ. For that reason I decided to place
> it alongside svc_entry in entry-armv.S rather than alongside svc_exit in
> entry-header.S .

Here's a list of macros from entry-headers.S that I don't see being used 
in entry-v7m.S: zero_fp, alignment_trap, store_user_sp_lr, 
load_user_sp_lr, svc_exit, ct_user_exit, ct_user_enter.

Yet, entry-header.S contains macros such as v7m_exception_entry and 
v7m_exception_slow_exit which are unlikely to ever be used in 
entry-armv.S.

> I am happy to move it if you have a strong preference here. Please let
> me know.

I don't have a strong preference, but a preference nevertheless.

It just looks odd that a file is already dedicated to gather all those 
macros for similar purposes and this one is not there.  That makes 
future code review/maintenance a bit annoying if similar things are not 
kept in one place.


Nicolas

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v1 1/6] arm: fiq: Replace default FIQ handler
@ 2014-09-05 18:04                             ` Nicolas Pitre
  0 siblings, 0 replies; 535+ messages in thread
From: Nicolas Pitre @ 2014-09-05 18:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, 5 Sep 2014, Daniel Thompson wrote:

> On 04/09/14 19:57, Nicolas Pitre wrote:
> > On Thu, 4 Sep 2014, Daniel Thompson wrote:
> > 
> >> +@ svc_exit_via_fiq - similar to svc_exit but switches to FIQ mode before exit
> >> +@
> >> +@ This macro acts in a similar manner to svc_exit but switches to FIQ
> >> +@ mode to restore the final part of the register state.
> >> +@
> >> +@ We cannot use the normal svc_exit procedure because that would
> >> +@ clobber spsr_svc (FIQ could be delivered during the first few instructions
> >> +@ of vector_swi meaning its contents have not been saved anywhere).
> >> +@
> > 
> > Wouldn't it be better for this macro to live in entry-header.S alongside 
> > the others?
> 
> I'm not sure either way.
> 
> svc_exit_from_fiq isn't needed by entry-common.S and cannot be used by
> entry-v7m.S because v7m has no FIQ. For that reason I decided to place
> it alongside svc_entry in entry-armv.S rather than alongside svc_exit in
> entry-header.S .

Here's a list of macros from entry-headers.S that I don't see being used 
in entry-v7m.S: zero_fp, alignment_trap, store_user_sp_lr, 
load_user_sp_lr, svc_exit, ct_user_exit, ct_user_enter.

Yet, entry-header.S contains macros such as v7m_exception_entry and 
v7m_exception_slow_exit which are unlikely to ever be used in 
entry-armv.S.

> I am happy to move it if you have a strong preference here. Please let
> me know.

I don't have a strong preference, but a preference nevertheless.

It just looks odd that a file is already dedicated to gather all those 
macros for similar purposes and this one is not there.  That makes 
future code review/maintenance a bit annoying if similar things are not 
kept in one place.


Nicolas

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v2 4/5] arm64: Introduce dummy version of asm/fiq.h
  2014-09-05 16:50                           ` Catalin Marinas
@ 2014-09-08 11:03                             ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-08 11:03 UTC (permalink / raw)
  To: Catalin Marinas
  Cc: Russell King, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Will Deacon

On 05/09/14 17:50, Catalin Marinas wrote:
> On Fri, Sep 05, 2014 at 04:33:17PM +0100, Daniel Thompson wrote:
>> Drivers that are shared between arm and arm64 and which employ
>> FIQ on arm cannot include asm/fiq.h without #ifdef'ing. This patch
>> introduces a dummy version of asm/fiq.h to arm64 to avoid this.
>>
>> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
>> Cc: Catalin Marinas <catalin.marinas@arm.com>
>> Cc: Will Deacon <will.deacon@arm.com>
>> ---
>>  arch/arm64/include/asm/fiq.h | 18 ++++++++++++++++++
>>  1 file changed, 18 insertions(+)
>>  create mode 100644 arch/arm64/include/asm/fiq.h
>>
>> diff --git a/arch/arm64/include/asm/fiq.h b/arch/arm64/include/asm/fiq.h
>> new file mode 100644
>> index 0000000..909ec54
>> --- /dev/null
>> +++ b/arch/arm64/include/asm/fiq.h
>> @@ -0,0 +1,18 @@
>> +/*
>> + * arch/arm64/include/asm/fiq.h
>> + *
>> + * Placeholder to reduce #ifdef'ing in shared arm/arm64 drivers.
>> + */
>> +
>> +#ifndef __ASM_FIQ_H
>> +#define __ASM_FIQ_H
>> +
>> +/*
>> + * This placeholder allows code of the following form to be simplified:
>> + *
>> + * #ifdef CONFIG_FIQ
>> + * #include <asm/fiq.h>
>> + * #endif
>> + */
>> +
>> +#endif
> 
> OK, we add a dummy file, but please keep it simple. Comments are fine
> but no need for header guards (nor the file name, on arm64 we try to get
> rid of them, though some still slip through).

Ok. I'll fix this.


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v2 4/5] arm64: Introduce dummy version of asm/fiq.h
@ 2014-09-08 11:03                             ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-08 11:03 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/09/14 17:50, Catalin Marinas wrote:
> On Fri, Sep 05, 2014 at 04:33:17PM +0100, Daniel Thompson wrote:
>> Drivers that are shared between arm and arm64 and which employ
>> FIQ on arm cannot include asm/fiq.h without #ifdef'ing. This patch
>> introduces a dummy version of asm/fiq.h to arm64 to avoid this.
>>
>> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
>> Cc: Catalin Marinas <catalin.marinas@arm.com>
>> Cc: Will Deacon <will.deacon@arm.com>
>> ---
>>  arch/arm64/include/asm/fiq.h | 18 ++++++++++++++++++
>>  1 file changed, 18 insertions(+)
>>  create mode 100644 arch/arm64/include/asm/fiq.h
>>
>> diff --git a/arch/arm64/include/asm/fiq.h b/arch/arm64/include/asm/fiq.h
>> new file mode 100644
>> index 0000000..909ec54
>> --- /dev/null
>> +++ b/arch/arm64/include/asm/fiq.h
>> @@ -0,0 +1,18 @@
>> +/*
>> + * arch/arm64/include/asm/fiq.h
>> + *
>> + * Placeholder to reduce #ifdef'ing in shared arm/arm64 drivers.
>> + */
>> +
>> +#ifndef __ASM_FIQ_H
>> +#define __ASM_FIQ_H
>> +
>> +/*
>> + * This placeholder allows code of the following form to be simplified:
>> + *
>> + * #ifdef CONFIG_FIQ
>> + * #include <asm/fiq.h>
>> + * #endif
>> + */
>> +
>> +#endif
> 
> OK, we add a dummy file, but please keep it simple. Comments are fine
> but no need for header guards (nor the file name, on arm64 we try to get
> rid of them, though some still slip through).

Ok. I'll fix this.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v1 1/6] arm: fiq: Replace default FIQ handler
  2014-09-05 18:04                             ` Nicolas Pitre
@ 2014-09-08 13:22                               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-08 13:22 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: Russell King, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Catalin Marinas, Tobias Klauser

On 05/09/14 19:04, Nicolas Pitre wrote:
> On Fri, 5 Sep 2014, Daniel Thompson wrote:
> 
>> On 04/09/14 19:57, Nicolas Pitre wrote:
>>> On Thu, 4 Sep 2014, Daniel Thompson wrote:
>>>
>>>> +@ svc_exit_via_fiq - similar to svc_exit but switches to FIQ mode before exit
>>>> +@
>>>> +@ This macro acts in a similar manner to svc_exit but switches to FIQ
>>>> +@ mode to restore the final part of the register state.
>>>> +@
>>>> +@ We cannot use the normal svc_exit procedure because that would
>>>> +@ clobber spsr_svc (FIQ could be delivered during the first few instructions
>>>> +@ of vector_swi meaning its contents have not been saved anywhere).
>>>> +@
>>>
>>> Wouldn't it be better for this macro to live in entry-header.S alongside 
>>> the others?
>>
>> I'm not sure either way.
>>
>> svc_exit_from_fiq isn't needed by entry-common.S and cannot be used by
>> entry-v7m.S because v7m has no FIQ. For that reason I decided to place
>> it alongside svc_entry in entry-armv.S rather than alongside svc_exit in
>> entry-header.S .
> 
> Here's a list of macros from entry-headers.S that I don't see being used 
> in entry-v7m.S: zero_fp, alignment_trap, store_user_sp_lr, 
> load_user_sp_lr, svc_exit, ct_user_exit, ct_user_enter.

All except one of of these are consumed either by entry-common.S or by
entry-header.S itself.

svc_exit is the only exception, it is exclusively consumed by entry-armv.S.


> Yet, entry-header.S contains macros such as v7m_exception_entry and 
> v7m_exception_slow_exit which are unlikely to ever be used in 
> entry-armv.S.

Although these macros are v7m specific they are used in
conditionally compiled code within entry-common.S in order to implement
system call handlers.


>> I am happy to move it if you have a strong preference here. Please let
>> me know.
> 
> I don't have a strong preference, but a preference nevertheless.
> 
> It just looks odd that a file is already dedicated to gather all those 
> macros for similar purposes and this one is not there.  That makes 
> future code review/maintenance a bit annoying if similar things are not 
> kept in one place.

I will move the macro to entry-common.S in order to keep it alongside
its workalike function svc_exit.

That said, I do retain a (pretty weakly held) view that both these
macros might be better off moved to entry-armv.S .



^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v1 1/6] arm: fiq: Replace default FIQ handler
@ 2014-09-08 13:22                               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-08 13:22 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/09/14 19:04, Nicolas Pitre wrote:
> On Fri, 5 Sep 2014, Daniel Thompson wrote:
> 
>> On 04/09/14 19:57, Nicolas Pitre wrote:
>>> On Thu, 4 Sep 2014, Daniel Thompson wrote:
>>>
>>>> +@ svc_exit_via_fiq - similar to svc_exit but switches to FIQ mode before exit
>>>> +@
>>>> +@ This macro acts in a similar manner to svc_exit but switches to FIQ
>>>> +@ mode to restore the final part of the register state.
>>>> +@
>>>> +@ We cannot use the normal svc_exit procedure because that would
>>>> +@ clobber spsr_svc (FIQ could be delivered during the first few instructions
>>>> +@ of vector_swi meaning its contents have not been saved anywhere).
>>>> +@
>>>
>>> Wouldn't it be better for this macro to live in entry-header.S alongside 
>>> the others?
>>
>> I'm not sure either way.
>>
>> svc_exit_from_fiq isn't needed by entry-common.S and cannot be used by
>> entry-v7m.S because v7m has no FIQ. For that reason I decided to place
>> it alongside svc_entry in entry-armv.S rather than alongside svc_exit in
>> entry-header.S .
> 
> Here's a list of macros from entry-headers.S that I don't see being used 
> in entry-v7m.S: zero_fp, alignment_trap, store_user_sp_lr, 
> load_user_sp_lr, svc_exit, ct_user_exit, ct_user_enter.

All except one of of these are consumed either by entry-common.S or by
entry-header.S itself.

svc_exit is the only exception, it is exclusively consumed by entry-armv.S.


> Yet, entry-header.S contains macros such as v7m_exception_entry and 
> v7m_exception_slow_exit which are unlikely to ever be used in 
> entry-armv.S.

Although these macros are v7m specific they are used in
conditionally compiled code within entry-common.S in order to implement
system call handlers.


>> I am happy to move it if you have a strong preference here. Please let
>> me know.
> 
> I don't have a strong preference, but a preference nevertheless.
> 
> It just looks odd that a file is already dedicated to gather all those 
> macros for similar purposes and this one is not there.  That makes 
> future code review/maintenance a bit annoying if similar things are not 
> kept in one place.

I will move the macro to entry-common.S in order to keep it alongside
its workalike function svc_exit.

That said, I do retain a (pretty weakly held) view that both these
macros might be better off moved to entry-armv.S .

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v3 0/5] arm: Implement arch_trigger_all_cpu_backtrace
  2014-09-05 15:33                       ` Daniel Thompson
@ 2014-09-08 15:28                         ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-08 15:28 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal

This patchset implements arch_trigger_all_cpu_backtrace for arm.

Non-maskable signalling relies on the kernel being able to access FIQ
and therefore, for devices that implement TrustZone, it will work only on
systems that boot the kernel in secure mode.

Tested on Freescale iMX.6 (both via SysRq-l and by deliberately locking
up the kernel with CONFIG_DEBUG_SPINLOCK=y).

Changes since v2:

* Removed redundant header guards from arch/arm64/include/asm/fiq.h
  (review of Catalin Marinas).

* Moved svc_exit_via_fiq macro to entry-header.S (review of Nicolas
  Pitre).

Changes since v1:

* Restructured to sit nicely on a similar FYI patchset from Russell
  King. It now effectively replaces the work in progress final patch
  with something much more complete.

* Implemented (and tested) a Thumb-2 implementation of svc_exit_via_fiq
  (review of Nicolas Pitre)

* Dropped the GIC group 0 workaround patch. The issue of FIQ interrupts
  being acknowledged by the IRQ handler does still exist but should be
  harmless because the IRQ handler will still wind up calling
  ipi_cpu_backtrace().

* Removed any dependency on CONFIG_FIQ; all cpu backtrace effectively
  becomes a platform feature (although the use of non-maskable
  interrupts to implement it is best effort rather than guaranteed).

* Better comments highlighting usage of RAZ/WI registers (and parts of
  registers) in the GIC code.

Changes *before* v1:

* This patchset is a hugely cut-down successor to "[PATCH v11 00/19]
  arm: KGDB NMI/FIQ support". Thanks to Thomas Gleixner for suggesting
  the new structure. For historic details see:
        https://lkml.org/lkml/2014/9/2/227

* Fix bug in __fiq_abt (no longer passes a bad struct pt_regs value).
  In fixing this we also remove the useless indirection previously
  found in the fiq_handler macro.

* Make default fiq handler "always on" by migrating from fiq.c to
  traps.c and replace do_unexp_fiq with the new handler (review
  of Russell King).

* Add arm64 version of fiq.h (review of Russell King)

* Removed conditional branching and code from irq-gic.c, this is
  replaced by much simpler code that relies on the GIC specification's
  heavy use of read-as-zero/write-ignored (review of Russell King)


Daniel Thompson (3):
  arm: fiq: Replace default FIQ handler
  arm64: Introduce dummy version of asm/fiq.h
  irqchip: gic: Add support for IPI FIQ

Russell King (2):
  ARM: remove unused do_unexp_fiq() function
  ARM: add basic support for on-demand backtrace of other CPUs

 arch/arm/include/asm/irq.h      |   5 ++
 arch/arm/include/asm/smp.h      |   3 +
 arch/arm/kernel/entry-armv.S    |  95 ++++++++++++++++++++---
 arch/arm/kernel/entry-header.S  |  47 ++++++++++++
 arch/arm/kernel/setup.c         |   8 +-
 arch/arm/kernel/smp.c           |  64 ++++++++++++++++
 arch/arm/kernel/traps.c         |  32 +++++++-
 arch/arm64/include/asm/fiq.h    |   8 ++
 drivers/irqchip/irq-gic.c       | 165 +++++++++++++++++++++++++++++++++++++---
 include/linux/irqchip/arm-gic.h |   3 +
 10 files changed, 407 insertions(+), 23 deletions(-)
 create mode 100644 arch/arm64/include/asm/fiq.h

--
1.9.3


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v3 0/5] arm: Implement arch_trigger_all_cpu_backtrace
@ 2014-09-08 15:28                         ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-08 15:28 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset implements arch_trigger_all_cpu_backtrace for arm.

Non-maskable signalling relies on the kernel being able to access FIQ
and therefore, for devices that implement TrustZone, it will work only on
systems that boot the kernel in secure mode.

Tested on Freescale iMX.6 (both via SysRq-l and by deliberately locking
up the kernel with CONFIG_DEBUG_SPINLOCK=y).

Changes since v2:

* Removed redundant header guards from arch/arm64/include/asm/fiq.h
  (review of Catalin Marinas).

* Moved svc_exit_via_fiq macro to entry-header.S (review of Nicolas
  Pitre).

Changes since v1:

* Restructured to sit nicely on a similar FYI patchset from Russell
  King. It now effectively replaces the work in progress final patch
  with something much more complete.

* Implemented (and tested) a Thumb-2 implementation of svc_exit_via_fiq
  (review of Nicolas Pitre)

* Dropped the GIC group 0 workaround patch. The issue of FIQ interrupts
  being acknowledged by the IRQ handler does still exist but should be
  harmless because the IRQ handler will still wind up calling
  ipi_cpu_backtrace().

* Removed any dependency on CONFIG_FIQ; all cpu backtrace effectively
  becomes a platform feature (although the use of non-maskable
  interrupts to implement it is best effort rather than guaranteed).

* Better comments highlighting usage of RAZ/WI registers (and parts of
  registers) in the GIC code.

Changes *before* v1:

* This patchset is a hugely cut-down successor to "[PATCH v11 00/19]
  arm: KGDB NMI/FIQ support". Thanks to Thomas Gleixner for suggesting
  the new structure. For historic details see:
        https://lkml.org/lkml/2014/9/2/227

* Fix bug in __fiq_abt (no longer passes a bad struct pt_regs value).
  In fixing this we also remove the useless indirection previously
  found in the fiq_handler macro.

* Make default fiq handler "always on" by migrating from fiq.c to
  traps.c and replace do_unexp_fiq with the new handler (review
  of Russell King).

* Add arm64 version of fiq.h (review of Russell King)

* Removed conditional branching and code from irq-gic.c, this is
  replaced by much simpler code that relies on the GIC specification's
  heavy use of read-as-zero/write-ignored (review of Russell King)


Daniel Thompson (3):
  arm: fiq: Replace default FIQ handler
  arm64: Introduce dummy version of asm/fiq.h
  irqchip: gic: Add support for IPI FIQ

Russell King (2):
  ARM: remove unused do_unexp_fiq() function
  ARM: add basic support for on-demand backtrace of other CPUs

 arch/arm/include/asm/irq.h      |   5 ++
 arch/arm/include/asm/smp.h      |   3 +
 arch/arm/kernel/entry-armv.S    |  95 ++++++++++++++++++++---
 arch/arm/kernel/entry-header.S  |  47 ++++++++++++
 arch/arm/kernel/setup.c         |   8 +-
 arch/arm/kernel/smp.c           |  64 ++++++++++++++++
 arch/arm/kernel/traps.c         |  32 +++++++-
 arch/arm64/include/asm/fiq.h    |   8 ++
 drivers/irqchip/irq-gic.c       | 165 +++++++++++++++++++++++++++++++++++++---
 include/linux/irqchip/arm-gic.h |   3 +
 10 files changed, 407 insertions(+), 23 deletions(-)
 create mode 100644 arch/arm64/include/asm/fiq.h

--
1.9.3

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v3 1/5] ARM: remove unused do_unexp_fiq() function
  2014-09-08 15:28                         ` Daniel Thompson
@ 2014-09-08 15:28                           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-08 15:28 UTC (permalink / raw)
  To: Russell King
  Cc: Russell King, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal

From: Russell King <rmk+kernel@arm.linux.org.uk>

do_unexp_fiq() has never been called by any code in the last 10 years,
it's about time it was removed!

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/kernel/traps.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index c8e4bb7..a447dcc 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -460,12 +460,6 @@ die_sig:
 	arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
 }
 
-asmlinkage void do_unexp_fiq (struct pt_regs *regs)
-{
-	printk("Hmm.  Unexpected FIQ received, but trying to continue\n");
-	printk("You may have a hardware problem...\n");
-}
-
 /*
  * bad_mode handles the impossible case in the vectors.  If you see one of
  * these, then it's extremely serious, and could mean you have buggy hardware.
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v3 1/5] ARM: remove unused do_unexp_fiq() function
@ 2014-09-08 15:28                           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-08 15:28 UTC (permalink / raw)
  To: linux-arm-kernel

From: Russell King <rmk+kernel@arm.linux.org.uk>

do_unexp_fiq() has never been called by any code in the last 10 years,
it's about time it was removed!

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/kernel/traps.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index c8e4bb7..a447dcc 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -460,12 +460,6 @@ die_sig:
 	arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
 }
 
-asmlinkage void do_unexp_fiq (struct pt_regs *regs)
-{
-	printk("Hmm.  Unexpected FIQ received, but trying to continue\n");
-	printk("You may have a hardware problem...\n");
-}
-
 /*
  * bad_mode handles the impossible case in the vectors.  If you see one of
  * these, then it's extremely serious, and could mean you have buggy hardware.
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v3 2/5] ARM: add basic support for on-demand backtrace of other CPUs
  2014-09-08 15:28                         ` Daniel Thompson
@ 2014-09-08 15:28                           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-08 15:28 UTC (permalink / raw)
  To: Russell King
  Cc: Russell King, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal

From: Russell King <rmk+kernel@arm.linux.org.uk>

Add basic infrastructure for triggering a backtrace of other CPUs
via an IPI, preferably at FIQ level.  It is intended that this shall
be used for cases where we have detected that something has already
failed in the kernel.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/include/asm/irq.h |  5 ++++
 arch/arm/kernel/smp.c      | 62 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+)

diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h
index 53c15de..be1d07d 100644
--- a/arch/arm/include/asm/irq.h
+++ b/arch/arm/include/asm/irq.h
@@ -35,6 +35,11 @@ extern void (*handle_arch_irq)(struct pt_regs *);
 extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
 #endif
 
+#ifdef CONFIG_SMP
+extern void arch_trigger_all_cpu_backtrace(bool);
+#define arch_trigger_all_cpu_backtrace(x) arch_trigger_all_cpu_backtrace(x)
+#endif
+
 #endif
 
 #endif
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9388a3d..94959f9 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -72,8 +72,12 @@ enum ipi_msg_type {
 	IPI_CPU_STOP,
 	IPI_IRQ_WORK,
 	IPI_COMPLETION,
+	IPI_CPU_BACKTRACE,
 };
 
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
+
 static DECLARE_COMPLETION(cpu_running);
 
 static struct smp_operations smp_ops;
@@ -539,6 +543,21 @@ static void ipi_cpu_stop(unsigned int cpu)
 		cpu_relax();
 }
 
+static void ipi_cpu_backtrace(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+
+	if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
+		static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
+
+		arch_spin_lock(&lock);
+		printk(KERN_WARNING "FIQ backtrace for cpu %d\n", cpu);
+		show_regs(regs);
+		arch_spin_unlock(&lock);
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+	}
+}
+
 static DEFINE_PER_CPU(struct completion *, cpu_completion);
 
 int register_ipi_completion(struct completion *completion, int cpu)
@@ -618,6 +637,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		irq_exit();
 		break;
 
+	case IPI_CPU_BACKTRACE:
+		irq_enter();
+		ipi_cpu_backtrace(regs);
+		irq_exit();
+		break;
+
 	default:
 		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
 		       cpu, ipinr);
@@ -712,3 +737,40 @@ static int __init register_cpufreq_notifier(void)
 core_initcall(register_cpufreq_notifier);
 
 #endif
+
+void arch_trigger_all_cpu_backtrace(bool include_self)
+{
+	static unsigned long backtrace_flag;
+	int i, cpu = get_cpu();
+
+	if (test_and_set_bit(0, &backtrace_flag)) {
+		/*
+		 * If there is already a trigger_all_cpu_backtrace() in progress
+		 * (backtrace_flag == 1), don't output double cpu dump infos.
+		 */
+		put_cpu();
+		return;
+	}
+
+	cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
+	if (!include_self)
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+
+	if (!cpumask_empty(to_cpumask(backtrace_mask))) {
+		pr_info("Sending FIQ to %s CPUs:\n",
+			(include_self ? "all" : "other"));
+		smp_cross_call(to_cpumask(backtrace_mask), IPI_CPU_BACKTRACE);
+	}
+
+	/* Wait for up to 10 seconds for all CPUs to do the backtrace */
+	for (i = 0; i < 10 * 1000; i++) {
+		if (cpumask_empty(to_cpumask(backtrace_mask)))
+			break;
+
+		mdelay(1);
+	}
+
+	clear_bit(0, &backtrace_flag);
+	smp_mb__after_atomic();
+	put_cpu();
+}
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v3 2/5] ARM: add basic support for on-demand backtrace of other CPUs
@ 2014-09-08 15:28                           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-08 15:28 UTC (permalink / raw)
  To: linux-arm-kernel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Add basic infrastructure for triggering a backtrace of other CPUs
via an IPI, preferably at FIQ level.  It is intended that this shall
be used for cases where we have detected that something has already
failed in the kernel.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/include/asm/irq.h |  5 ++++
 arch/arm/kernel/smp.c      | 62 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+)

diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h
index 53c15de..be1d07d 100644
--- a/arch/arm/include/asm/irq.h
+++ b/arch/arm/include/asm/irq.h
@@ -35,6 +35,11 @@ extern void (*handle_arch_irq)(struct pt_regs *);
 extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
 #endif
 
+#ifdef CONFIG_SMP
+extern void arch_trigger_all_cpu_backtrace(bool);
+#define arch_trigger_all_cpu_backtrace(x) arch_trigger_all_cpu_backtrace(x)
+#endif
+
 #endif
 
 #endif
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9388a3d..94959f9 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -72,8 +72,12 @@ enum ipi_msg_type {
 	IPI_CPU_STOP,
 	IPI_IRQ_WORK,
 	IPI_COMPLETION,
+	IPI_CPU_BACKTRACE,
 };
 
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
+
 static DECLARE_COMPLETION(cpu_running);
 
 static struct smp_operations smp_ops;
@@ -539,6 +543,21 @@ static void ipi_cpu_stop(unsigned int cpu)
 		cpu_relax();
 }
 
+static void ipi_cpu_backtrace(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+
+	if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
+		static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
+
+		arch_spin_lock(&lock);
+		printk(KERN_WARNING "FIQ backtrace for cpu %d\n", cpu);
+		show_regs(regs);
+		arch_spin_unlock(&lock);
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+	}
+}
+
 static DEFINE_PER_CPU(struct completion *, cpu_completion);
 
 int register_ipi_completion(struct completion *completion, int cpu)
@@ -618,6 +637,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		irq_exit();
 		break;
 
+	case IPI_CPU_BACKTRACE:
+		irq_enter();
+		ipi_cpu_backtrace(regs);
+		irq_exit();
+		break;
+
 	default:
 		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
 		       cpu, ipinr);
@@ -712,3 +737,40 @@ static int __init register_cpufreq_notifier(void)
 core_initcall(register_cpufreq_notifier);
 
 #endif
+
+void arch_trigger_all_cpu_backtrace(bool include_self)
+{
+	static unsigned long backtrace_flag;
+	int i, cpu = get_cpu();
+
+	if (test_and_set_bit(0, &backtrace_flag)) {
+		/*
+		 * If there is already a trigger_all_cpu_backtrace() in progress
+		 * (backtrace_flag == 1), don't output double cpu dump infos.
+		 */
+		put_cpu();
+		return;
+	}
+
+	cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
+	if (!include_self)
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+
+	if (!cpumask_empty(to_cpumask(backtrace_mask))) {
+		pr_info("Sending FIQ to %s CPUs:\n",
+			(include_self ? "all" : "other"));
+		smp_cross_call(to_cpumask(backtrace_mask), IPI_CPU_BACKTRACE);
+	}
+
+	/* Wait for up to 10 seconds for all CPUs to do the backtrace */
+	for (i = 0; i < 10 * 1000; i++) {
+		if (cpumask_empty(to_cpumask(backtrace_mask)))
+			break;
+
+		mdelay(1);
+	}
+
+	clear_bit(0, &backtrace_flag);
+	smp_mb__after_atomic();
+	put_cpu();
+}
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v3 3/5] arm: fiq: Replace default FIQ handler
  2014-09-08 15:28                         ` Daniel Thompson
@ 2014-09-08 15:28                           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-08 15:28 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Nicolas Pitre, Catalin Marinas

This patch introduces a new default FIQ handler that is structured in a
similar way to the existing ARM exception handler and result in the FIQ
being handled by C code running on the SVC stack (despite this code run
in the FIQ handler is subject to severe limitations with respect to
locking making normal interaction with the kernel impossible).

This default handler allows concepts that on x86 would be handled using
NMIs to be realized on ARM.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of small fragments
    survive, however without Anton's work to build from this patch would
    not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
---
 arch/arm/include/asm/smp.h     |  3 ++
 arch/arm/kernel/entry-armv.S   | 95 +++++++++++++++++++++++++++++++++++++-----
 arch/arm/kernel/entry-header.S | 47 +++++++++++++++++++++
 arch/arm/kernel/setup.c        |  8 +++-
 arch/arm/kernel/smp.c          |  4 +-
 arch/arm/kernel/traps.c        | 28 +++++++++++++
 6 files changed, 173 insertions(+), 12 deletions(-)

diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2ec765c..0580270 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -18,6 +18,8 @@
 # error "<asm/smp.h> included in non-SMP build"
 #endif
 
+#define SMP_IPI_FIQ_MASK 0x0100
+
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
 struct seq_file;
@@ -85,6 +87,7 @@ extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
 
+extern void ipi_cpu_backtrace(struct pt_regs *regs);
 extern int register_ipi_completion(struct completion *completion, int cpu);
 
 struct smp_operations {
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 36276cd..7cf6b37 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -146,7 +146,7 @@ ENDPROC(__und_invalid)
 #define SPFIX(code...)
 #endif
 
-	.macro	svc_entry, stack_hole=0
+	.macro	svc_entry, stack_hole=0, call_trace=1
  UNWIND(.fnstart		)
  UNWIND(.save {r0 - pc}		)
 	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
@@ -183,7 +183,9 @@ ENDPROC(__und_invalid)
 	stmia	r7, {r2 - r6}
 
 #ifdef CONFIG_TRACE_IRQFLAGS
+	.if \call_trace
 	bl	trace_hardirqs_off
+	.endif
 #endif
 	.endm
 
@@ -295,6 +297,15 @@ __pabt_svc:
 ENDPROC(__pabt_svc)
 
 	.align	5
+__fiq_svc:
+	svc_entry 0, 0
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	svc_exit_via_fiq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+	.align	5
 .LCcralign:
 	.word	cr_alignment
 #ifdef MULTI_DABORT
@@ -305,6 +316,46 @@ ENDPROC(__pabt_svc)
 	.word	fp_enter
 
 /*
+ * Abort mode handlers
+ */
+
+@
+@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
+@ and reuses the same macros. However in abort mode we must also
+@ save/restore lr_abt and spsr_abt to make nested aborts safe.
+@
+	.align 5
+__fiq_abt:
+	svc_entry 0, 0
+
+ ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	mov	r1, lr		@ Save lr_abt
+	mrs	r2, spsr	@ Save spsr_abt, abort is now safe
+ ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	push	{r1 - r2}
+
+	sub	r0, sp, #8			@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+
+	pop	{r1 - r2}
+ ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	mov	lr, r1		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r2	@ Restore spsr_abt
+ ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+
+	svc_exit_via_fiq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+/*
  * User mode handlers
  *
  * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
@@ -683,6 +734,18 @@ ENTRY(ret_from_exception)
 ENDPROC(__pabt_usr)
 ENDPROC(ret_from_exception)
 
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+
 /*
  * Register switch for ARMv3 and ARMv4 processors
  * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
@@ -1118,17 +1181,29 @@ vector_addrexcptn:
 	b	vector_addrexcptn
 
 /*=============================================================================
- * Undefined FIQs
+ * FIQ "NMI" handler
  *-----------------------------------------------------------------------------
- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
- * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
- * Basically to switch modes, we *HAVE* to clobber one register...  brain
- * damage alert!  I don't think that we can execute any code in here in any
- * other mode than FIQ...  Ok you can switch to another mode, but you can't
- * get out of that mode without clobbering one register.
+ * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
+ * systems.
  */
-vector_fiq:
-	subs	pc, lr, #4
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
 
 	.globl	vector_fiq_offset
 	.equ	vector_fiq_offset, vector_fiq
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 2fdf867..0d91ca0 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -216,6 +216,34 @@
 	ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
 	.endm
 
+	@
+	@ svc_exit_via_fiq - like svc_exit but switches to FIQ mode before exit
+	@
+	@ This macro acts in a similar manner to svc_exit but switches to FIQ
+	@ mode to restore the final part of the register state.
+	@
+	@ We cannot use the normal svc_exit procedure because that would
+	@ clobber spsr_svc (FIQ could be delivered during the first few
+	@ instructions of vector_swi meaning its contents have not been
+	@ saved anywhere).
+	@
+	@ Note that, unlike svc_exit, this macro also does not allow a caller
+	@ supplied rpsr. This is because the FIQ exceptions are not re-entrant
+	@ and the handlers cannot call into the scheduler (meaning the value
+	@ on the stack remains correct).
+	@
+	.macro  svc_exit_via_fiq
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+	.endm
+
 	.macro	restore_user_regs, fast = 0, offset = 0
 	ldr	r1, [sp, #\offset + S_PSR]	@ get calling cpsr
 	ldr	lr, [sp, #\offset + S_PC]!	@ get pc
@@ -267,6 +295,25 @@
 	rfeia	sp!
 	.endm
 
+	@
+	@ svc_exit_via_fiq - like svc_exit but switches to FIQ mode before exit
+	@
+	@ For full details see non-Thumb implementation above.
+	@
+	.macro  svc_exit_via_fiq
+	add	r0, sp, #S_R2
+	ldr	lr, [sp, #S_LR]
+	ldr	sp, [sp, #S_SP] @ abort is deadly from here onward (it will
+			        @ clobber state restored below)
+	ldmia	r0, {r2 - r12}
+	mov	r1, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	msr	cpsr_c, r1
+	sub	r0, #S_R2
+	add	r8, r0, #S_PC
+	ldmia	r0, {r0 - r1}
+	rfeia	r8
+	.endm
+
 #ifdef CONFIG_CPU_V7M
 	/*
 	 * Note we don't need to do clrex here as clearing the local monitor is
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 84db893d..c031063 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -133,6 +133,7 @@ struct stack {
 	u32 irq[3];
 	u32 abt[3];
 	u32 und[3];
+	u32 fiq[3];
 } ____cacheline_aligned;
 
 #ifndef CONFIG_CPU_V7M
@@ -470,7 +471,10 @@ void notrace cpu_init(void)
 	"msr	cpsr_c, %5\n\t"
 	"add	r14, %0, %6\n\t"
 	"mov	sp, r14\n\t"
-	"msr	cpsr_c, %7"
+	"msr	cpsr_c, %7\n\t"
+	"add	r14, %0, %8\n\t"
+	"mov	sp, r14\n\t"
+	"msr	cpsr_c, %9"
 	    :
 	    : "r" (stk),
 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
@@ -479,6 +483,8 @@ void notrace cpu_init(void)
 	      "I" (offsetof(struct stack, abt[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
 	      "I" (offsetof(struct stack, und[0])),
+	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+	      "I" (offsetof(struct stack, fiq[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
 	    : "r14");
 #endif
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 94959f9..7a79d11 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -543,7 +543,7 @@ static void ipi_cpu_stop(unsigned int cpu)
 		cpu_relax();
 }
 
-static void ipi_cpu_backtrace(struct pt_regs *regs)
+void ipi_cpu_backtrace(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
 
@@ -584,6 +584,8 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 	unsigned int cpu = smp_processor_id();
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
+	BUILD_BUG_ON(SMP_IPI_FIQ_MASK != BIT(IPI_CPU_BACKTRACE));
+
 	if ((unsigned)ipinr < NR_IPI) {
 		trace_ipi_entry(ipi_types[ipinr]);
 		__inc_irq_stat(cpu, ipi_irqs[ipinr]);
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index a447dcc..f8189c2 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -25,6 +25,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/irq.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -461,6 +462,33 @@ die_sig:
 }
 
 /*
+ * Handle FIQ similarly to NMI on x86 systems.
+ *
+ * The runtime environment for NMIs is extremely restrictive
+ * (NMIs can pre-empt critical sections meaning almost all locking is
+ * forbidden) meaning this default FIQ handling must only be used in
+ * circumstances where non-maskability improves robustness, such as
+ * watchdog or debug logic.
+ *
+ * This handler is not appropriate for general purpose use in drivers
+ * platform code and can be overrideen using set_fiq_handler.
+ */
+asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
+{
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	nmi_enter();
+
+#ifdef CONFIG_SMP
+	ipi_cpu_backtrace(regs);
+#endif
+
+	nmi_exit();
+
+	set_irq_regs(old_regs);
+}
+
+/*
  * bad_mode handles the impossible case in the vectors.  If you see one of
  * these, then it's extremely serious, and could mean you have buggy hardware.
  * It never returns, and never tries to sync.  We hope that we can at least
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v3 3/5] arm: fiq: Replace default FIQ handler
@ 2014-09-08 15:28                           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-08 15:28 UTC (permalink / raw)
  To: linux-arm-kernel

This patch introduces a new default FIQ handler that is structured in a
similar way to the existing ARM exception handler and result in the FIQ
being handled by C code running on the SVC stack (despite this code run
in the FIQ handler is subject to severe limitations with respect to
locking making normal interaction with the kernel impossible).

This default handler allows concepts that on x86 would be handled using
NMIs to be realized on ARM.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of small fragments
    survive, however without Anton's work to build from this patch would
    not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
---
 arch/arm/include/asm/smp.h     |  3 ++
 arch/arm/kernel/entry-armv.S   | 95 +++++++++++++++++++++++++++++++++++++-----
 arch/arm/kernel/entry-header.S | 47 +++++++++++++++++++++
 arch/arm/kernel/setup.c        |  8 +++-
 arch/arm/kernel/smp.c          |  4 +-
 arch/arm/kernel/traps.c        | 28 +++++++++++++
 6 files changed, 173 insertions(+), 12 deletions(-)

diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2ec765c..0580270 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -18,6 +18,8 @@
 # error "<asm/smp.h> included in non-SMP build"
 #endif
 
+#define SMP_IPI_FIQ_MASK 0x0100
+
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
 struct seq_file;
@@ -85,6 +87,7 @@ extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
 
+extern void ipi_cpu_backtrace(struct pt_regs *regs);
 extern int register_ipi_completion(struct completion *completion, int cpu);
 
 struct smp_operations {
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 36276cd..7cf6b37 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -146,7 +146,7 @@ ENDPROC(__und_invalid)
 #define SPFIX(code...)
 #endif
 
-	.macro	svc_entry, stack_hole=0
+	.macro	svc_entry, stack_hole=0, call_trace=1
  UNWIND(.fnstart		)
  UNWIND(.save {r0 - pc}		)
 	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
@@ -183,7 +183,9 @@ ENDPROC(__und_invalid)
 	stmia	r7, {r2 - r6}
 
 #ifdef CONFIG_TRACE_IRQFLAGS
+	.if \call_trace
 	bl	trace_hardirqs_off
+	.endif
 #endif
 	.endm
 
@@ -295,6 +297,15 @@ __pabt_svc:
 ENDPROC(__pabt_svc)
 
 	.align	5
+__fiq_svc:
+	svc_entry 0, 0
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	svc_exit_via_fiq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+	.align	5
 .LCcralign:
 	.word	cr_alignment
 #ifdef MULTI_DABORT
@@ -305,6 +316,46 @@ ENDPROC(__pabt_svc)
 	.word	fp_enter
 
 /*
+ * Abort mode handlers
+ */
+
+@
+@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
+@ and reuses the same macros. However in abort mode we must also
+@ save/restore lr_abt and spsr_abt to make nested aborts safe.
+@
+	.align 5
+__fiq_abt:
+	svc_entry 0, 0
+
+ ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	mov	r1, lr		@ Save lr_abt
+	mrs	r2, spsr	@ Save spsr_abt, abort is now safe
+ ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	push	{r1 - r2}
+
+	sub	r0, sp, #8			@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+
+	pop	{r1 - r2}
+ ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	mov	lr, r1		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r2	@ Restore spsr_abt
+ ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+
+	svc_exit_via_fiq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+/*
  * User mode handlers
  *
  * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
@@ -683,6 +734,18 @@ ENTRY(ret_from_exception)
 ENDPROC(__pabt_usr)
 ENDPROC(ret_from_exception)
 
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+
 /*
  * Register switch for ARMv3 and ARMv4 processors
  * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
@@ -1118,17 +1181,29 @@ vector_addrexcptn:
 	b	vector_addrexcptn
 
 /*=============================================================================
- * Undefined FIQs
+ * FIQ "NMI" handler
  *-----------------------------------------------------------------------------
- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
- * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
- * Basically to switch modes, we *HAVE* to clobber one register...  brain
- * damage alert!  I don't think that we can execute any code in here in any
- * other mode than FIQ...  Ok you can switch to another mode, but you can't
- * get out of that mode without clobbering one register.
+ * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
+ * systems.
  */
-vector_fiq:
-	subs	pc, lr, #4
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
 
 	.globl	vector_fiq_offset
 	.equ	vector_fiq_offset, vector_fiq
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 2fdf867..0d91ca0 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -216,6 +216,34 @@
 	ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
 	.endm
 
+	@
+	@ svc_exit_via_fiq - like svc_exit but switches to FIQ mode before exit
+	@
+	@ This macro acts in a similar manner to svc_exit but switches to FIQ
+	@ mode to restore the final part of the register state.
+	@
+	@ We cannot use the normal svc_exit procedure because that would
+	@ clobber spsr_svc (FIQ could be delivered during the first few
+	@ instructions of vector_swi meaning its contents have not been
+	@ saved anywhere).
+	@
+	@ Note that, unlike svc_exit, this macro also does not allow a caller
+	@ supplied rpsr. This is because the FIQ exceptions are not re-entrant
+	@ and the handlers cannot call into the scheduler (meaning the value
+	@ on the stack remains correct).
+	@
+	.macro  svc_exit_via_fiq
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+	.endm
+
 	.macro	restore_user_regs, fast = 0, offset = 0
 	ldr	r1, [sp, #\offset + S_PSR]	@ get calling cpsr
 	ldr	lr, [sp, #\offset + S_PC]!	@ get pc
@@ -267,6 +295,25 @@
 	rfeia	sp!
 	.endm
 
+	@
+	@ svc_exit_via_fiq - like svc_exit but switches to FIQ mode before exit
+	@
+	@ For full details see non-Thumb implementation above.
+	@
+	.macro  svc_exit_via_fiq
+	add	r0, sp, #S_R2
+	ldr	lr, [sp, #S_LR]
+	ldr	sp, [sp, #S_SP] @ abort is deadly from here onward (it will
+			        @ clobber state restored below)
+	ldmia	r0, {r2 - r12}
+	mov	r1, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	msr	cpsr_c, r1
+	sub	r0, #S_R2
+	add	r8, r0, #S_PC
+	ldmia	r0, {r0 - r1}
+	rfeia	r8
+	.endm
+
 #ifdef CONFIG_CPU_V7M
 	/*
 	 * Note we don't need to do clrex here as clearing the local monitor is
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 84db893d..c031063 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -133,6 +133,7 @@ struct stack {
 	u32 irq[3];
 	u32 abt[3];
 	u32 und[3];
+	u32 fiq[3];
 } ____cacheline_aligned;
 
 #ifndef CONFIG_CPU_V7M
@@ -470,7 +471,10 @@ void notrace cpu_init(void)
 	"msr	cpsr_c, %5\n\t"
 	"add	r14, %0, %6\n\t"
 	"mov	sp, r14\n\t"
-	"msr	cpsr_c, %7"
+	"msr	cpsr_c, %7\n\t"
+	"add	r14, %0, %8\n\t"
+	"mov	sp, r14\n\t"
+	"msr	cpsr_c, %9"
 	    :
 	    : "r" (stk),
 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
@@ -479,6 +483,8 @@ void notrace cpu_init(void)
 	      "I" (offsetof(struct stack, abt[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
 	      "I" (offsetof(struct stack, und[0])),
+	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+	      "I" (offsetof(struct stack, fiq[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
 	    : "r14");
 #endif
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 94959f9..7a79d11 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -543,7 +543,7 @@ static void ipi_cpu_stop(unsigned int cpu)
 		cpu_relax();
 }
 
-static void ipi_cpu_backtrace(struct pt_regs *regs)
+void ipi_cpu_backtrace(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
 
@@ -584,6 +584,8 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 	unsigned int cpu = smp_processor_id();
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
+	BUILD_BUG_ON(SMP_IPI_FIQ_MASK != BIT(IPI_CPU_BACKTRACE));
+
 	if ((unsigned)ipinr < NR_IPI) {
 		trace_ipi_entry(ipi_types[ipinr]);
 		__inc_irq_stat(cpu, ipi_irqs[ipinr]);
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index a447dcc..f8189c2 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -25,6 +25,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/irq.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -461,6 +462,33 @@ die_sig:
 }
 
 /*
+ * Handle FIQ similarly to NMI on x86 systems.
+ *
+ * The runtime environment for NMIs is extremely restrictive
+ * (NMIs can pre-empt critical sections meaning almost all locking is
+ * forbidden) meaning this default FIQ handling must only be used in
+ * circumstances where non-maskability improves robustness, such as
+ * watchdog or debug logic.
+ *
+ * This handler is not appropriate for general purpose use in drivers
+ * platform code and can be overrideen using set_fiq_handler.
+ */
+asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
+{
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	nmi_enter();
+
+#ifdef CONFIG_SMP
+	ipi_cpu_backtrace(regs);
+#endif
+
+	nmi_exit();
+
+	set_irq_regs(old_regs);
+}
+
+/*
  * bad_mode handles the impossible case in the vectors.  If you see one of
  * these, then it's extremely serious, and could mean you have buggy hardware.
  * It never returns, and never tries to sync.  We hope that we can at least
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v3 4/5] arm64: Introduce dummy version of asm/fiq.h
  2014-09-08 15:28                         ` Daniel Thompson
@ 2014-09-08 15:28                           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-08 15:28 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Catalin Marinas, Will Deacon

Drivers that are shared between arm and arm64 and which employ
FIQ on arm cannot include asm/fiq.h without #ifdef'ing. This patch
introduces a dummy version of asm/fiq.h to arm64 to avoid this.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
 arch/arm64/include/asm/fiq.h | 8 ++++++++
 1 file changed, 8 insertions(+)
 create mode 100644 arch/arm64/include/asm/fiq.h

diff --git a/arch/arm64/include/asm/fiq.h b/arch/arm64/include/asm/fiq.h
new file mode 100644
index 0000000..d3776b8
--- /dev/null
+++ b/arch/arm64/include/asm/fiq.h
@@ -0,0 +1,8 @@
+/*
+ * Placeholder to reduce #ifdef'ing in shared arm/arm64 drivers. It
+ * allows code of the following form to be made unconditional.
+ *
+ * #ifdef CONFIG_FIQ
+ * #include <asm/fiq.h>
+ * #endif
+ */
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v3 4/5] arm64: Introduce dummy version of asm/fiq.h
@ 2014-09-08 15:28                           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-08 15:28 UTC (permalink / raw)
  To: linux-arm-kernel

Drivers that are shared between arm and arm64 and which employ
FIQ on arm cannot include asm/fiq.h without #ifdef'ing. This patch
introduces a dummy version of asm/fiq.h to arm64 to avoid this.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
 arch/arm64/include/asm/fiq.h | 8 ++++++++
 1 file changed, 8 insertions(+)
 create mode 100644 arch/arm64/include/asm/fiq.h

diff --git a/arch/arm64/include/asm/fiq.h b/arch/arm64/include/asm/fiq.h
new file mode 100644
index 0000000..d3776b8
--- /dev/null
+++ b/arch/arm64/include/asm/fiq.h
@@ -0,0 +1,8 @@
+/*
+ * Placeholder to reduce #ifdef'ing in shared arm/arm64 drivers. It
+ * allows code of the following form to be made unconditional.
+ *
+ * #ifdef CONFIG_FIQ
+ * #include <asm/fiq.h>
+ * #endif
+ */
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v3 5/5] irqchip: gic: Add support for IPI FIQ
  2014-09-08 15:28                         ` Daniel Thompson
@ 2014-09-08 15:28                           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-08 15:28 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Jason Cooper

This patch provides support for arm's newly added IPI FIQ. It works
by placing all interrupt sources *except* IPI FIQ in group 1 and
then flips a configuration bit in the GIC such that group 1
interrupts use IRQ and group 0 interrupts use FIQ.

All GIC hardware except GICv1-without-TrustZone support provides a means
to group exceptions into group 0 and group 1. However the hardware
functionality is unavailable to the kernel when a secure monitor is
present because access to the grouping registers are prohibited outside
"secure world" (a feature that allows grouping to be used to allow
hardware peripherals to send interrupts into the secure world). However
when grouping is not available we can rely on the GIC's RAZ/WI semantics
and avoid conditional code.

Tested on Freescale i.MX6 (quad A9, GICv1-with-TrustZone running in
secure mode).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
---
 arch/arm/kernel/traps.c         |   4 +
 drivers/irqchip/irq-gic.c       | 165 +++++++++++++++++++++++++++++++++++++---
 include/linux/irqchip/arm-gic.h |   3 +
 3 files changed, 163 insertions(+), 9 deletions(-)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index f8189c2..40b1de7 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/irq.h>
+#include <linux/irqchip/arm-gic.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -479,6 +480,9 @@ asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
 
 	nmi_enter();
 
+#ifdef CONFIG_ARM_GIC
+	gic_handle_fiq_ipi();
+#endif
 #ifdef CONFIG_SMP
 	ipi_cpu_backtrace(regs);
 #endif
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4b959e6..f554ee5 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,8 +39,10 @@
 #include <linux/slab.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/ratelimit.h>
 
 #include <asm/cputype.h>
+#include <asm/fiq.h>
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
@@ -48,6 +50,10 @@
 #include "irq-gic-common.h"
 #include "irqchip.h"
 
+#ifndef SMP_IPI_FIQ_MASK
+#define SMP_IPI_FIQ_MASK 0
+#endif
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -71,6 +77,8 @@ struct gic_chip_data {
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+/* A fiq-safe spinlock must only be locked when the FIQ is masked */
+static DEFINE_RAW_SPINLOCK(fiq_safe_migration_lock);
 
 /*
  * The GIC mapping of CPU interfaces does not necessarily match
@@ -325,6 +333,94 @@ static struct irq_chip gic_chip = {
 	.irq_set_wake		= gic_set_wake,
 };
 
+/*
+ * Shift an interrupt between Group 0 and Group 1.
+ *
+ * In addition to changing the group we also modify the priority to
+ * match what "ARM strongly recommends" for a system where no Group 1
+ * interrupt must ever preempt a Group 0 interrupt.
+ *
+ * If is safe to call this function on systems which do not support
+ * grouping (it will have no effect).
+ */
+static void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				int group)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_mask = BIT(hwirq % 32);
+	u32 grp_val;
+
+	unsigned int pri_reg = (hwirq / 4) * 4;
+	u32 pri_mask = BIT(7 + ((hwirq % 4) * 8));
+	u32 pri_val;
+
+	/*
+	 * Systems which do not support grouping will have no bits
+	 * set in IGROUP[0] (and all systems which do will have set bits).
+	 */
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + 0);
+	if (!grp_val)
+		return;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(base + GIC_DIST_PRI + pri_reg);
+
+	if (group) {
+		grp_val |= grp_mask;
+		pri_val |= pri_mask;
+	} else {
+		grp_val &= ~grp_mask;
+		pri_val &= ~pri_mask;
+	}
+
+	writel_relaxed(grp_val, base + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, base + GIC_DIST_PRI + pri_reg);
+
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+/*
+ * Test which group an interrupt belongs to.
+ *
+ * Returns 0 if the controller does not support grouping.
+ */
+static int gic_get_group_irq(void __iomem *base, unsigned int hwirq)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_val;
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+
+	return (grp_val >> (hwirq % 32)) & 1;
+}
+
+/*
+ * Fully acknowledge (both ack and eoi) any outstanding FIQ-based IPI,
+ * otherwise do nothing.
+ */
+void gic_handle_fiq_ipi(void)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	unsigned long irqstat, irqnr;
+
+	if (WARN_ON(!in_nmi()))
+		return;
+
+	while ((1u << readl_relaxed(cpu_base + GIC_CPU_HIGHPRI)) &
+	       SMP_IPI_FIQ_MASK) {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		WARN_RATELIMIT(irqnr > 16,
+			       "Unexpected irqnr %lu (bad prioritization?)\n",
+			       irqnr);
+	}
+}
+
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
 	if (gic_nr >= MAX_GIC_NR)
@@ -373,7 +469,18 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 
 	gic_dist_config(base, gic_irqs, NULL);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Set all global interrupts to be group 1 (this register is
+	 * RAZ/WI if not accessible in current mode)
+	 */
+	for (i = 32; i < gic_irqs; i += 32)
+		writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	writel_relaxed(3, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -382,6 +489,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	void __iomem *base = gic_data_cpu_base(gic);
 	unsigned int cpu_mask, cpu = smp_processor_id();
 	int i;
+	unsigned long secure_irqs, secure_irq;
 
 	/*
 	 * Get what the GIC says our CPU mask is.
@@ -400,8 +508,27 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 
 	gic_cpu_config(dist_base, NULL);
 
+	/*
+	 * Set any PPI and SGI interrupts not set in SMP_IPI_FIQ_MASK
+	 * to be group 1 (this register is RAZ/WI if not accessible)
+	 */
+	writel_relaxed(~SMP_IPI_FIQ_MASK, dist_base + GIC_DIST_IGROUP + 0);
+
+	/*
+	 * Update the priority of any resulting group0 interrupts.
+	 */
+	secure_irqs = ~readl_relaxed(dist_base + GIC_DIST_IGROUP + 0);
+	for_each_set_bit(secure_irq, &secure_irqs, 16)
+		gic_set_group_irq(dist_base, i, 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+
+	/* The bottom most bit will be set for all GIC variants (and is
+	 * called Enable or EnableGrp0 depending on operating mode). The
+	 * remaining four bits (CBPR, FIQEn, AckCtl and EnableGrp1) are
+	 * RAZ/WI if not accessible.
+	 */
+	writel_relaxed(0x1f, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -485,7 +612,7 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	writel_relaxed(3, dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -542,7 +669,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -604,8 +731,19 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
 	unsigned long flags, map = 0;
+	unsigned long softint;
 
-	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+	/*
+	 * The locking in this function ensures we don't use stale cpu mappings
+	 * and thus we never route an IPI to the wrong physical core during a
+	 * big.LITTLE switch. The switch code takes both of these locks meaning
+	 * we can choose whichever lock is safe to use from our current calling
+	 * context.
+	 */
+	if (in_nmi())
+		raw_spin_lock(&fiq_safe_migration_lock);
+	else
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
 	/* Convert our logical CPU mask into a physical one. */
 	for_each_cpu(cpu, mask)
@@ -618,9 +756,16 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
-
-	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+	softint = map << 16 | irq;
+	if (gic_get_group_irq(gic_data_dist_base(&gic_data[0]), irq))
+		softint |= 0x8000;
+	writel_relaxed(softint,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+
+	if (in_nmi())
+		raw_spin_unlock(&fiq_safe_migration_lock);
+	else
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 #endif
 
@@ -668,7 +813,7 @@ int gic_get_cpu_id(unsigned int cpu)
  * Migrate all peripheral interrupts with a target matching the current CPU
  * to the interface corresponding to @new_cpu_id.  The CPU interface mapping
  * is also updated.  Targets to other CPU interfaces are unchanged.
- * This must be called with IRQs locally disabled.
+ * This must be called with IRQ and FIQ locally disabled.
  */
 void gic_migrate_target(unsigned int new_cpu_id)
 {
@@ -690,6 +835,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 	ror_val = (cur_cpu_id - new_cpu_id) & 31;
 
 	raw_spin_lock(&irq_controller_lock);
+	raw_spin_lock(&fiq_safe_migration_lock);
 
 	/* Update the target interface for this logical CPU */
 	gic_cpu_map[cpu] = 1 << new_cpu_id;
@@ -709,6 +855,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 		}
 	}
 
+	raw_spin_unlock(&fiq_safe_migration_lock);
 	raw_spin_unlock(&irq_controller_lock);
 
 	/*
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 45e2d8c..52a5676 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops
 {
 	gic_routable_irq_domain_ops = ops;
 }
+
+void gic_handle_fiq_ipi(void);
+
 #endif /* __ASSEMBLY */
 #endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v3 5/5] irqchip: gic: Add support for IPI FIQ
@ 2014-09-08 15:28                           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-08 15:28 UTC (permalink / raw)
  To: linux-arm-kernel

This patch provides support for arm's newly added IPI FIQ. It works
by placing all interrupt sources *except* IPI FIQ in group 1 and
then flips a configuration bit in the GIC such that group 1
interrupts use IRQ and group 0 interrupts use FIQ.

All GIC hardware except GICv1-without-TrustZone support provides a means
to group exceptions into group 0 and group 1. However the hardware
functionality is unavailable to the kernel when a secure monitor is
present because access to the grouping registers are prohibited outside
"secure world" (a feature that allows grouping to be used to allow
hardware peripherals to send interrupts into the secure world). However
when grouping is not available we can rely on the GIC's RAZ/WI semantics
and avoid conditional code.

Tested on Freescale i.MX6 (quad A9, GICv1-with-TrustZone running in
secure mode).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
---
 arch/arm/kernel/traps.c         |   4 +
 drivers/irqchip/irq-gic.c       | 165 +++++++++++++++++++++++++++++++++++++---
 include/linux/irqchip/arm-gic.h |   3 +
 3 files changed, 163 insertions(+), 9 deletions(-)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index f8189c2..40b1de7 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/irq.h>
+#include <linux/irqchip/arm-gic.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -479,6 +480,9 @@ asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
 
 	nmi_enter();
 
+#ifdef CONFIG_ARM_GIC
+	gic_handle_fiq_ipi();
+#endif
 #ifdef CONFIG_SMP
 	ipi_cpu_backtrace(regs);
 #endif
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4b959e6..f554ee5 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,8 +39,10 @@
 #include <linux/slab.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/ratelimit.h>
 
 #include <asm/cputype.h>
+#include <asm/fiq.h>
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
@@ -48,6 +50,10 @@
 #include "irq-gic-common.h"
 #include "irqchip.h"
 
+#ifndef SMP_IPI_FIQ_MASK
+#define SMP_IPI_FIQ_MASK 0
+#endif
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -71,6 +77,8 @@ struct gic_chip_data {
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+/* A fiq-safe spinlock must only be locked when the FIQ is masked */
+static DEFINE_RAW_SPINLOCK(fiq_safe_migration_lock);
 
 /*
  * The GIC mapping of CPU interfaces does not necessarily match
@@ -325,6 +333,94 @@ static struct irq_chip gic_chip = {
 	.irq_set_wake		= gic_set_wake,
 };
 
+/*
+ * Shift an interrupt between Group 0 and Group 1.
+ *
+ * In addition to changing the group we also modify the priority to
+ * match what "ARM strongly recommends" for a system where no Group 1
+ * interrupt must ever preempt a Group 0 interrupt.
+ *
+ * If is safe to call this function on systems which do not support
+ * grouping (it will have no effect).
+ */
+static void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				int group)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_mask = BIT(hwirq % 32);
+	u32 grp_val;
+
+	unsigned int pri_reg = (hwirq / 4) * 4;
+	u32 pri_mask = BIT(7 + ((hwirq % 4) * 8));
+	u32 pri_val;
+
+	/*
+	 * Systems which do not support grouping will have no bits
+	 * set in IGROUP[0] (and all systems which do will have set bits).
+	 */
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + 0);
+	if (!grp_val)
+		return;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(base + GIC_DIST_PRI + pri_reg);
+
+	if (group) {
+		grp_val |= grp_mask;
+		pri_val |= pri_mask;
+	} else {
+		grp_val &= ~grp_mask;
+		pri_val &= ~pri_mask;
+	}
+
+	writel_relaxed(grp_val, base + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, base + GIC_DIST_PRI + pri_reg);
+
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+/*
+ * Test which group an interrupt belongs to.
+ *
+ * Returns 0 if the controller does not support grouping.
+ */
+static int gic_get_group_irq(void __iomem *base, unsigned int hwirq)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_val;
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+
+	return (grp_val >> (hwirq % 32)) & 1;
+}
+
+/*
+ * Fully acknowledge (both ack and eoi) any outstanding FIQ-based IPI,
+ * otherwise do nothing.
+ */
+void gic_handle_fiq_ipi(void)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	unsigned long irqstat, irqnr;
+
+	if (WARN_ON(!in_nmi()))
+		return;
+
+	while ((1u << readl_relaxed(cpu_base + GIC_CPU_HIGHPRI)) &
+	       SMP_IPI_FIQ_MASK) {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		WARN_RATELIMIT(irqnr > 16,
+			       "Unexpected irqnr %lu (bad prioritization?)\n",
+			       irqnr);
+	}
+}
+
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
 	if (gic_nr >= MAX_GIC_NR)
@@ -373,7 +469,18 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 
 	gic_dist_config(base, gic_irqs, NULL);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Set all global interrupts to be group 1 (this register is
+	 * RAZ/WI if not accessible in current mode)
+	 */
+	for (i = 32; i < gic_irqs; i += 32)
+		writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	writel_relaxed(3, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -382,6 +489,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	void __iomem *base = gic_data_cpu_base(gic);
 	unsigned int cpu_mask, cpu = smp_processor_id();
 	int i;
+	unsigned long secure_irqs, secure_irq;
 
 	/*
 	 * Get what the GIC says our CPU mask is.
@@ -400,8 +508,27 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 
 	gic_cpu_config(dist_base, NULL);
 
+	/*
+	 * Set any PPI and SGI interrupts not set in SMP_IPI_FIQ_MASK
+	 * to be group 1 (this register is RAZ/WI if not accessible)
+	 */
+	writel_relaxed(~SMP_IPI_FIQ_MASK, dist_base + GIC_DIST_IGROUP + 0);
+
+	/*
+	 * Update the priority of any resulting group0 interrupts.
+	 */
+	secure_irqs = ~readl_relaxed(dist_base + GIC_DIST_IGROUP + 0);
+	for_each_set_bit(secure_irq, &secure_irqs, 16)
+		gic_set_group_irq(dist_base, i, 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+
+	/* The bottom most bit will be set for all GIC variants (and is
+	 * called Enable or EnableGrp0 depending on operating mode). The
+	 * remaining four bits (CBPR, FIQEn, AckCtl and EnableGrp1) are
+	 * RAZ/WI if not accessible.
+	 */
+	writel_relaxed(0x1f, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -485,7 +612,7 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	writel_relaxed(3, dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -542,7 +669,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -604,8 +731,19 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
 	unsigned long flags, map = 0;
+	unsigned long softint;
 
-	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+	/*
+	 * The locking in this function ensures we don't use stale cpu mappings
+	 * and thus we never route an IPI to the wrong physical core during a
+	 * big.LITTLE switch. The switch code takes both of these locks meaning
+	 * we can choose whichever lock is safe to use from our current calling
+	 * context.
+	 */
+	if (in_nmi())
+		raw_spin_lock(&fiq_safe_migration_lock);
+	else
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
 	/* Convert our logical CPU mask into a physical one. */
 	for_each_cpu(cpu, mask)
@@ -618,9 +756,16 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
-
-	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+	softint = map << 16 | irq;
+	if (gic_get_group_irq(gic_data_dist_base(&gic_data[0]), irq))
+		softint |= 0x8000;
+	writel_relaxed(softint,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+
+	if (in_nmi())
+		raw_spin_unlock(&fiq_safe_migration_lock);
+	else
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 #endif
 
@@ -668,7 +813,7 @@ int gic_get_cpu_id(unsigned int cpu)
  * Migrate all peripheral interrupts with a target matching the current CPU
  * to the interface corresponding to @new_cpu_id.  The CPU interface mapping
  * is also updated.  Targets to other CPU interfaces are unchanged.
- * This must be called with IRQs locally disabled.
+ * This must be called with IRQ and FIQ locally disabled.
  */
 void gic_migrate_target(unsigned int new_cpu_id)
 {
@@ -690,6 +835,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 	ror_val = (cur_cpu_id - new_cpu_id) & 31;
 
 	raw_spin_lock(&irq_controller_lock);
+	raw_spin_lock(&fiq_safe_migration_lock);
 
 	/* Update the target interface for this logical CPU */
 	gic_cpu_map[cpu] = 1 << new_cpu_id;
@@ -709,6 +855,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
 		}
 	}
 
+	raw_spin_unlock(&fiq_safe_migration_lock);
 	raw_spin_unlock(&irq_controller_lock);
 
 	/*
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 45e2d8c..52a5676 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops
 {
 	gic_routable_irq_domain_ops = ops;
 }
+
+void gic_handle_fiq_ipi(void);
+
 #endif /* __ASSEMBLY */
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* Re: [PATCH v3 3/5] arm: fiq: Replace default FIQ handler
  2014-09-08 15:28                           ` Daniel Thompson
@ 2014-09-08 15:49                             ` Nicolas Pitre
  -1 siblings, 0 replies; 535+ messages in thread
From: Nicolas Pitre @ 2014-09-08 15:49 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Russell King, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Catalin Marinas

On Mon, 8 Sep 2014, Daniel Thompson wrote:

> +@
> +@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
> +@ and reuses the same macros. However in abort mode we must also
> +@ save/restore lr_abt and spsr_abt to make nested aborts safe.
> +@
> +	.align 5
> +__fiq_abt:
> +	svc_entry 0, 0
> +
> + ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
> + THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
> + THUMB( msr	cpsr_c, r0 )
> +	mov	r1, lr		@ Save lr_abt
> +	mrs	r2, spsr	@ Save spsr_abt, abort is now safe
> + ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
> + THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
> + THUMB( msr	cpsr_c, r0 )
> +	push	{r1 - r2}

	stmfd sp!, {r1 - r2}

> +
> +	sub	r0, sp, #8			@ struct pt_regs *regs
> +	bl	handle_fiq_as_nmi
> +
> +	pop	{r1 - r2}

	ldmfd sp!, {r1 - r2}

... so that old binutils we still accept to compile the kernel (in ARM 
mode) are happy.

Otherwise...

Acked-by: Nicolas Pitre <nico@linaro.org>


Nicolas

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v3 3/5] arm: fiq: Replace default FIQ handler
@ 2014-09-08 15:49                             ` Nicolas Pitre
  0 siblings, 0 replies; 535+ messages in thread
From: Nicolas Pitre @ 2014-09-08 15:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 8 Sep 2014, Daniel Thompson wrote:

> +@
> +@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
> +@ and reuses the same macros. However in abort mode we must also
> +@ save/restore lr_abt and spsr_abt to make nested aborts safe.
> +@
> +	.align 5
> +__fiq_abt:
> +	svc_entry 0, 0
> +
> + ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
> + THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
> + THUMB( msr	cpsr_c, r0 )
> +	mov	r1, lr		@ Save lr_abt
> +	mrs	r2, spsr	@ Save spsr_abt, abort is now safe
> + ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
> + THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
> + THUMB( msr	cpsr_c, r0 )
> +	push	{r1 - r2}

	stmfd sp!, {r1 - r2}

> +
> +	sub	r0, sp, #8			@ struct pt_regs *regs
> +	bl	handle_fiq_as_nmi
> +
> +	pop	{r1 - r2}

	ldmfd sp!, {r1 - r2}

... so that old binutils we still accept to compile the kernel (in ARM 
mode) are happy.

Otherwise...

Acked-by: Nicolas Pitre <nico@linaro.org>


Nicolas

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v3 3/5] arm: fiq: Replace default FIQ handler
  2014-09-08 15:49                             ` Nicolas Pitre
@ 2014-09-08 15:57                               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-08 15:57 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: Russell King, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Catalin Marinas

On 08/09/14 16:49, Nicolas Pitre wrote:
> On Mon, 8 Sep 2014, Daniel Thompson wrote:
> 
>> +@
>> +@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
>> +@ and reuses the same macros. However in abort mode we must also
>> +@ save/restore lr_abt and spsr_abt to make nested aborts safe.
>> +@
>> +	.align 5
>> +__fiq_abt:
>> +	svc_entry 0, 0
>> +
>> + ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
>> + THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
>> + THUMB( msr	cpsr_c, r0 )
>> +	mov	r1, lr		@ Save lr_abt
>> +	mrs	r2, spsr	@ Save spsr_abt, abort is now safe
>> + ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
>> + THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
>> + THUMB( msr	cpsr_c, r0 )
>> +	push	{r1 - r2}
> 
> 	stmfd sp!, {r1 - r2}
> 
>> +
>> +	sub	r0, sp, #8			@ struct pt_regs *regs
>> +	bl	handle_fiq_as_nmi
>> +
>> +	pop	{r1 - r2}
> 
> 	ldmfd sp!, {r1 - r2}
> 
> ... so that old binutils we still accept to compile the kernel (in ARM 
> mode) are happy.

Will do.


> Otherwise...
> 
> Acked-by: Nicolas Pitre <nico@linaro.org>

Thanks :-)


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v3 3/5] arm: fiq: Replace default FIQ handler
@ 2014-09-08 15:57                               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-08 15:57 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/09/14 16:49, Nicolas Pitre wrote:
> On Mon, 8 Sep 2014, Daniel Thompson wrote:
> 
>> +@
>> +@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
>> +@ and reuses the same macros. However in abort mode we must also
>> +@ save/restore lr_abt and spsr_abt to make nested aborts safe.
>> +@
>> +	.align 5
>> +__fiq_abt:
>> +	svc_entry 0, 0
>> +
>> + ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
>> + THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
>> + THUMB( msr	cpsr_c, r0 )
>> +	mov	r1, lr		@ Save lr_abt
>> +	mrs	r2, spsr	@ Save spsr_abt, abort is now safe
>> + ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
>> + THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
>> + THUMB( msr	cpsr_c, r0 )
>> +	push	{r1 - r2}
> 
> 	stmfd sp!, {r1 - r2}
> 
>> +
>> +	sub	r0, sp, #8			@ struct pt_regs *regs
>> +	bl	handle_fiq_as_nmi
>> +
>> +	pop	{r1 - r2}
> 
> 	ldmfd sp!, {r1 - r2}
> 
> ... so that old binutils we still accept to compile the kernel (in ARM 
> mode) are happy.

Will do.


> Otherwise...
> 
> Acked-by: Nicolas Pitre <nico@linaro.org>

Thanks :-)

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v3 5/5] irqchip: gic: Add support for IPI FIQ
  2014-09-08 15:28                           ` Daniel Thompson
@ 2014-09-08 16:23                             ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-08 16:23 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: linux-kernel, linux-arm-kernel, patches, linaro-kernel,
	John Stultz, Thomas Gleixner, Sumit Semwal, Jason Cooper

On Mon, Sep 08, 2014 at 04:28:35PM +0100, Daniel Thompson wrote:
> @@ -604,8 +731,19 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
>  {
>  	int cpu;
>  	unsigned long flags, map = 0;
> +	unsigned long softint;
>  
> -	raw_spin_lock_irqsave(&irq_controller_lock, flags);
> +	/*
> +	 * The locking in this function ensures we don't use stale cpu mappings
> +	 * and thus we never route an IPI to the wrong physical core during a
> +	 * big.LITTLE switch. The switch code takes both of these locks meaning
> +	 * we can choose whichever lock is safe to use from our current calling
> +	 * context.
> +	 */
> +	if (in_nmi())
> +		raw_spin_lock(&fiq_safe_migration_lock);
> +	else
> +		raw_spin_lock_irqsave(&irq_controller_lock, flags);

Firstly, why would gic_raise_softirq() be called in FIQ context?  Secondly,
this doesn't save you.  If you were in the middle of gic_migrate_target()
when the FIQ happened that (for some reason prompted you to call this),
you would immediately deadlock trying to that this IRQ.

I suggest not even trying to solve this "race" which I don't think is
one which needs to even be considered (due to the first point.)

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v3 5/5] irqchip: gic: Add support for IPI FIQ
@ 2014-09-08 16:23                             ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-08 16:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Sep 08, 2014 at 04:28:35PM +0100, Daniel Thompson wrote:
> @@ -604,8 +731,19 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
>  {
>  	int cpu;
>  	unsigned long flags, map = 0;
> +	unsigned long softint;
>  
> -	raw_spin_lock_irqsave(&irq_controller_lock, flags);
> +	/*
> +	 * The locking in this function ensures we don't use stale cpu mappings
> +	 * and thus we never route an IPI to the wrong physical core during a
> +	 * big.LITTLE switch. The switch code takes both of these locks meaning
> +	 * we can choose whichever lock is safe to use from our current calling
> +	 * context.
> +	 */
> +	if (in_nmi())
> +		raw_spin_lock(&fiq_safe_migration_lock);
> +	else
> +		raw_spin_lock_irqsave(&irq_controller_lock, flags);

Firstly, why would gic_raise_softirq() be called in FIQ context?  Secondly,
this doesn't save you.  If you were in the middle of gic_migrate_target()
when the FIQ happened that (for some reason prompted you to call this),
you would immediately deadlock trying to that this IRQ.

I suggest not even trying to solve this "race" which I don't think is
one which needs to even be considered (due to the first point.)

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v3 0/5] arm: Implement arch_trigger_all_cpu_backtrace
  2014-09-08 15:28                         ` Daniel Thompson
@ 2014-09-08 16:24                           ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-08 16:24 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: linux-kernel, linux-arm-kernel, patches, linaro-kernel,
	John Stultz, Thomas Gleixner, Sumit Semwal

On Mon, Sep 08, 2014 at 04:28:30PM +0100, Daniel Thompson wrote:
> * Restructured to sit nicely on a similar FYI patchset from Russell
>   King. It now effectively replaces the work in progress final patch
>   with something much more complete.

I'd suggest that patch 2 should be in a different place - get the FIQ
infrastructure in place first before adding any users of it would be
a much more sensible patch ordering.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v3 0/5] arm: Implement arch_trigger_all_cpu_backtrace
@ 2014-09-08 16:24                           ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-08 16:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Sep 08, 2014 at 04:28:30PM +0100, Daniel Thompson wrote:
> * Restructured to sit nicely on a similar FYI patchset from Russell
>   King. It now effectively replaces the work in progress final patch
>   with something much more complete.

I'd suggest that patch 2 should be in a different place - get the FIQ
infrastructure in place first before adding any users of it would be
a much more sensible patch ordering.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v3 5/5] irqchip: gic: Add support for IPI FIQ
  2014-09-08 16:23                             ` Russell King - ARM Linux
@ 2014-09-09  8:24                               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-09  8:24 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linux-kernel, linux-arm-kernel, patches, linaro-kernel,
	John Stultz, Thomas Gleixner, Sumit Semwal, Jason Cooper

On 08/09/14 17:23, Russell King - ARM Linux wrote:
> On Mon, Sep 08, 2014 at 04:28:35PM +0100, Daniel Thompson wrote:
>> @@ -604,8 +731,19 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
>>  {
>>  	int cpu;
>>  	unsigned long flags, map = 0;
>> +	unsigned long softint;
>>  
>> -	raw_spin_lock_irqsave(&irq_controller_lock, flags);
>> +	/*
>> +	 * The locking in this function ensures we don't use stale cpu mappings
>> +	 * and thus we never route an IPI to the wrong physical core during a
>> +	 * big.LITTLE switch. The switch code takes both of these locks meaning
>> +	 * we can choose whichever lock is safe to use from our current calling
>> +	 * context.
>> +	 */
>> +	if (in_nmi())
>> +		raw_spin_lock(&fiq_safe_migration_lock);
>> +	else
>> +		raw_spin_lock_irqsave(&irq_controller_lock, flags);
> 
> Firstly, why would gic_raise_softirq() be called in FIQ context?

Oops.

This code should have been removed. It *is* required for kgdb (which
needs to send FIQ to other processors via IPI and may itself be running
from FIQ) but it not needed for the currently targeted use case.


> Secondly,
> this doesn't save you.  If you were in the middle of gic_migrate_target()
> when the FIQ happened that (for some reason prompted you to call this),
> you would immediately deadlock trying to that this IRQ.

This cannot happen because gic_migrate_target() runs with FIQ disabled.


> I suggest not even trying to solve this "race" which I don't think is
> one which needs to even be considered (due to the first point.)

As mentioned above I believe it eventually needs to be addressed by some
means but it certainly doesn't belong in the current patchset.

I will remove it.


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v3 5/5] irqchip: gic: Add support for IPI FIQ
@ 2014-09-09  8:24                               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-09  8:24 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/09/14 17:23, Russell King - ARM Linux wrote:
> On Mon, Sep 08, 2014 at 04:28:35PM +0100, Daniel Thompson wrote:
>> @@ -604,8 +731,19 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
>>  {
>>  	int cpu;
>>  	unsigned long flags, map = 0;
>> +	unsigned long softint;
>>  
>> -	raw_spin_lock_irqsave(&irq_controller_lock, flags);
>> +	/*
>> +	 * The locking in this function ensures we don't use stale cpu mappings
>> +	 * and thus we never route an IPI to the wrong physical core during a
>> +	 * big.LITTLE switch. The switch code takes both of these locks meaning
>> +	 * we can choose whichever lock is safe to use from our current calling
>> +	 * context.
>> +	 */
>> +	if (in_nmi())
>> +		raw_spin_lock(&fiq_safe_migration_lock);
>> +	else
>> +		raw_spin_lock_irqsave(&irq_controller_lock, flags);
> 
> Firstly, why would gic_raise_softirq() be called in FIQ context?

Oops.

This code should have been removed. It *is* required for kgdb (which
needs to send FIQ to other processors via IPI and may itself be running
from FIQ) but it not needed for the currently targeted use case.


> Secondly,
> this doesn't save you.  If you were in the middle of gic_migrate_target()
> when the FIQ happened that (for some reason prompted you to call this),
> you would immediately deadlock trying to that this IRQ.

This cannot happen because gic_migrate_target() runs with FIQ disabled.


> I suggest not even trying to solve this "race" which I don't think is
> one which needs to even be considered (due to the first point.)

As mentioned above I believe it eventually needs to be addressed by some
means but it certainly doesn't belong in the current patchset.

I will remove it.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v3 0/5] arm: Implement arch_trigger_all_cpu_backtrace
  2014-09-08 16:24                           ` Russell King - ARM Linux
@ 2014-09-09  8:26                             ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-09  8:26 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linux-kernel, linux-arm-kernel, patches, linaro-kernel,
	John Stultz, Thomas Gleixner, Sumit Semwal

On 08/09/14 17:24, Russell King - ARM Linux wrote:
> On Mon, Sep 08, 2014 at 04:28:30PM +0100, Daniel Thompson wrote:
>> * Restructured to sit nicely on a similar FYI patchset from Russell
>>   King. It now effectively replaces the work in progress final patch
>>   with something much more complete.
> 
> I'd suggest that patch 2 should be in a different place - get the FIQ
> infrastructure in place first before adding any users of it would be
> a much more sensible patch ordering.

Ok. I will push this to the back.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v3 0/5] arm: Implement arch_trigger_all_cpu_backtrace
@ 2014-09-09  8:26                             ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-09  8:26 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/09/14 17:24, Russell King - ARM Linux wrote:
> On Mon, Sep 08, 2014 at 04:28:30PM +0100, Daniel Thompson wrote:
>> * Restructured to sit nicely on a similar FYI patchset from Russell
>>   King. It now effectively replaces the work in progress final patch
>>   with something much more complete.
> 
> I'd suggest that patch 2 should be in a different place - get the FIQ
> infrastructure in place first before adding any users of it would be
> a much more sensible patch ordering.

Ok. I will push this to the back.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v4 0/6] arm: Implement arch_trigger_all_cpu_backtrace
  2014-09-08 15:28                         ` Daniel Thompson
@ 2014-09-09 14:15                           ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-09 14:15 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal

This patchset implements arch_trigger_all_cpu_backtrace for arm.

Non-maskable signalling relies on the kernel being able to access FIQ
and therefore, for devices that implement TrustZone, it will work only on
systems that boot the kernel in secure mode.

Tested on Freescale iMX.6 (both via SysRq-l and by deliberately locking
up the kernel with CONFIG_DEBUG_SPINLOCK=y).

Changes since v3:

* Replaced push/pop with stmfd/ldmfd respectively (review of Nicolas
  Pitre).

* Really fix bad pt_regs pointer generation in __fiq_abt.

* Remove fiq_safe_migration_lock and associated logic in
  gic_raise_softirq() (review of Russell King)

* Restructured to introduce the default FIQ handler first, before the
  new features (review of Russell King).

Changes since v2:

* Removed redundant header guards from arch/arm64/include/asm/fiq.h
  (review of Catalin Marinas).

* Moved svc_exit_via_fiq macro to entry-header.S (review of Nicolas
  Pitre).

Changes since v1:

* Restructured to sit nicely on a similar FYI patchset from Russell
  King. It now effectively replaces the work in progress final patch
  with something much more complete.

* Implemented (and tested) a Thumb-2 implementation of svc_exit_via_fiq
  (review of Nicolas Pitre)

* Dropped the GIC group 0 workaround patch. The issue of FIQ interrupts
  being acknowledged by the IRQ handler does still exist but should be
  harmless because the IRQ handler will still wind up calling
  ipi_cpu_backtrace().

* Removed any dependency on CONFIG_FIQ; all cpu backtrace effectively
  becomes a platform feature (although the use of non-maskable
  interrupts to implement it is best effort rather than guaranteed).

* Better comments highlighting usage of RAZ/WI registers (and parts of
  registers) in the GIC code.

Changes *before* v1:

* This patchset is a hugely cut-down successor to "[PATCH v11 00/19]
  arm: KGDB NMI/FIQ support". Thanks to Thomas Gleixner for suggesting
  the new structure. For historic details see:
        https://lkml.org/lkml/2014/9/2/227

* Fix bug in __fiq_abt (no longer passes a bad struct pt_regs value).
  In fixing this we also remove the useless indirection previously
  found in the fiq_handler macro.

* Make default fiq handler "always on" by migrating from fiq.c to
  traps.c and replace do_unexp_fiq with the new handler (review
  of Russell King).

* Add arm64 version of fiq.h (review of Russell King)

* Removed conditional branching and code from irq-gic.c, this is
  replaced by much simpler code that relies on the GIC specification's
  heavy use of read-as-zero/write-ignored (review of Russell King)


Daniel Thompson (4):
  arm: fiq: Replace default FIQ handler
  arm64: Introduce dummy version of asm/fiq.h
  irqchip: gic: Add support for IPI FIQ
  arm: smp: Handle ipi_cpu_backtrace() using FIQ (if available)

Russell King (2):
  ARM: remove unused do_unexp_fiq() function
  ARM: add basic support for on-demand backtrace of other CPUs

 arch/arm/include/asm/irq.h      |   5 ++
 arch/arm/include/asm/smp.h      |   3 +
 arch/arm/kernel/entry-armv.S    |  95 ++++++++++++++++++++++++---
 arch/arm/kernel/entry-header.S  |  47 ++++++++++++++
 arch/arm/kernel/setup.c         |   8 ++-
 arch/arm/kernel/smp.c           |  65 +++++++++++++++++++
 arch/arm/kernel/traps.c         |  32 ++++++++-
 arch/arm64/include/asm/fiq.h    |   8 +++
 drivers/irqchip/irq-gic.c       | 140 ++++++++++++++++++++++++++++++++++++++--
 include/linux/irqchip/arm-gic.h |   3 +
 10 files changed, 387 insertions(+), 19 deletions(-)
 create mode 100644 arch/arm64/include/asm/fiq.h

--
1.9.3


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v4 0/6] arm: Implement arch_trigger_all_cpu_backtrace
@ 2014-09-09 14:15                           ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-09 14:15 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset implements arch_trigger_all_cpu_backtrace for arm.

Non-maskable signalling relies on the kernel being able to access FIQ
and therefore, for devices that implement TrustZone, it will work only on
systems that boot the kernel in secure mode.

Tested on Freescale iMX.6 (both via SysRq-l and by deliberately locking
up the kernel with CONFIG_DEBUG_SPINLOCK=y).

Changes since v3:

* Replaced push/pop with stmfd/ldmfd respectively (review of Nicolas
  Pitre).

* Really fix bad pt_regs pointer generation in __fiq_abt.

* Remove fiq_safe_migration_lock and associated logic in
  gic_raise_softirq() (review of Russell King)

* Restructured to introduce the default FIQ handler first, before the
  new features (review of Russell King).

Changes since v2:

* Removed redundant header guards from arch/arm64/include/asm/fiq.h
  (review of Catalin Marinas).

* Moved svc_exit_via_fiq macro to entry-header.S (review of Nicolas
  Pitre).

Changes since v1:

* Restructured to sit nicely on a similar FYI patchset from Russell
  King. It now effectively replaces the work in progress final patch
  with something much more complete.

* Implemented (and tested) a Thumb-2 implementation of svc_exit_via_fiq
  (review of Nicolas Pitre)

* Dropped the GIC group 0 workaround patch. The issue of FIQ interrupts
  being acknowledged by the IRQ handler does still exist but should be
  harmless because the IRQ handler will still wind up calling
  ipi_cpu_backtrace().

* Removed any dependency on CONFIG_FIQ; all cpu backtrace effectively
  becomes a platform feature (although the use of non-maskable
  interrupts to implement it is best effort rather than guaranteed).

* Better comments highlighting usage of RAZ/WI registers (and parts of
  registers) in the GIC code.

Changes *before* v1:

* This patchset is a hugely cut-down successor to "[PATCH v11 00/19]
  arm: KGDB NMI/FIQ support". Thanks to Thomas Gleixner for suggesting
  the new structure. For historic details see:
        https://lkml.org/lkml/2014/9/2/227

* Fix bug in __fiq_abt (no longer passes a bad struct pt_regs value).
  In fixing this we also remove the useless indirection previously
  found in the fiq_handler macro.

* Make default fiq handler "always on" by migrating from fiq.c to
  traps.c and replace do_unexp_fiq with the new handler (review
  of Russell King).

* Add arm64 version of fiq.h (review of Russell King)

* Removed conditional branching and code from irq-gic.c, this is
  replaced by much simpler code that relies on the GIC specification's
  heavy use of read-as-zero/write-ignored (review of Russell King)


Daniel Thompson (4):
  arm: fiq: Replace default FIQ handler
  arm64: Introduce dummy version of asm/fiq.h
  irqchip: gic: Add support for IPI FIQ
  arm: smp: Handle ipi_cpu_backtrace() using FIQ (if available)

Russell King (2):
  ARM: remove unused do_unexp_fiq() function
  ARM: add basic support for on-demand backtrace of other CPUs

 arch/arm/include/asm/irq.h      |   5 ++
 arch/arm/include/asm/smp.h      |   3 +
 arch/arm/kernel/entry-armv.S    |  95 ++++++++++++++++++++++++---
 arch/arm/kernel/entry-header.S  |  47 ++++++++++++++
 arch/arm/kernel/setup.c         |   8 ++-
 arch/arm/kernel/smp.c           |  65 +++++++++++++++++++
 arch/arm/kernel/traps.c         |  32 ++++++++-
 arch/arm64/include/asm/fiq.h    |   8 +++
 drivers/irqchip/irq-gic.c       | 140 ++++++++++++++++++++++++++++++++++++++--
 include/linux/irqchip/arm-gic.h |   3 +
 10 files changed, 387 insertions(+), 19 deletions(-)
 create mode 100644 arch/arm64/include/asm/fiq.h

--
1.9.3

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v4 1/6] ARM: remove unused do_unexp_fiq() function
  2014-09-09 14:15                           ` Daniel Thompson
@ 2014-09-09 14:15                             ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-09 14:15 UTC (permalink / raw)
  To: Russell King
  Cc: Russell King, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Daniel Thompson

From: Russell King <rmk+kernel@arm.linux.org.uk>

do_unexp_fiq() has never been called by any code in the last 10 years,
it's about time it was removed!

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/kernel/traps.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index c8e4bb7..a447dcc 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -460,12 +460,6 @@ die_sig:
 	arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
 }
 
-asmlinkage void do_unexp_fiq (struct pt_regs *regs)
-{
-	printk("Hmm.  Unexpected FIQ received, but trying to continue\n");
-	printk("You may have a hardware problem...\n");
-}
-
 /*
  * bad_mode handles the impossible case in the vectors.  If you see one of
  * these, then it's extremely serious, and could mean you have buggy hardware.
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 1/6] ARM: remove unused do_unexp_fiq() function
@ 2014-09-09 14:15                             ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-09 14:15 UTC (permalink / raw)
  To: linux-arm-kernel

From: Russell King <rmk+kernel@arm.linux.org.uk>

do_unexp_fiq() has never been called by any code in the last 10 years,
it's about time it was removed!

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/kernel/traps.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index c8e4bb7..a447dcc 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -460,12 +460,6 @@ die_sig:
 	arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
 }
 
-asmlinkage void do_unexp_fiq (struct pt_regs *regs)
-{
-	printk("Hmm.  Unexpected FIQ received, but trying to continue\n");
-	printk("You may have a hardware problem...\n");
-}
-
 /*
  * bad_mode handles the impossible case in the vectors.  If you see one of
  * these, then it's extremely serious, and could mean you have buggy hardware.
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 2/6] arm: fiq: Replace default FIQ handler
  2014-09-09 14:15                           ` Daniel Thompson
@ 2014-09-09 14:15                             ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-09 14:15 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Catalin Marinas

This patch introduces a new default FIQ handler that is structured in a
similar way to the existing ARM exception handler and result in the FIQ
being handled by C code running on the SVC stack (despite this code run
in the FIQ handler is subject to severe limitations with respect to
locking making normal interaction with the kernel impossible).

This default handler allows concepts that on x86 would be handled using
NMIs to be realized on ARM.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of small fragments
    survive, however without Anton's work to build from this patch would
    not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/kernel/entry-armv.S   | 95 +++++++++++++++++++++++++++++++++++++-----
 arch/arm/kernel/entry-header.S | 47 +++++++++++++++++++++
 arch/arm/kernel/setup.c        |  8 +++-
 arch/arm/kernel/traps.c        | 26 ++++++++++++
 4 files changed, 165 insertions(+), 11 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 36276cd..0c70fee 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -146,7 +146,7 @@ ENDPROC(__und_invalid)
 #define SPFIX(code...)
 #endif
 
-	.macro	svc_entry, stack_hole=0
+	.macro	svc_entry, stack_hole=0, call_trace=1
  UNWIND(.fnstart		)
  UNWIND(.save {r0 - pc}		)
 	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
@@ -183,7 +183,9 @@ ENDPROC(__und_invalid)
 	stmia	r7, {r2 - r6}
 
 #ifdef CONFIG_TRACE_IRQFLAGS
+	.if \call_trace
 	bl	trace_hardirqs_off
+	.endif
 #endif
 	.endm
 
@@ -295,6 +297,15 @@ __pabt_svc:
 ENDPROC(__pabt_svc)
 
 	.align	5
+__fiq_svc:
+	svc_entry 0, 0
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	svc_exit_via_fiq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+	.align	5
 .LCcralign:
 	.word	cr_alignment
 #ifdef MULTI_DABORT
@@ -305,6 +316,46 @@ ENDPROC(__pabt_svc)
 	.word	fp_enter
 
 /*
+ * Abort mode handlers
+ */
+
+@
+@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
+@ and reuses the same macros. However in abort mode we must also
+@ save/restore lr_abt and spsr_abt to make nested aborts safe.
+@
+	.align 5
+__fiq_abt:
+	svc_entry 0, 0
+
+ ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	mov	r1, lr		@ Save lr_abt
+	mrs	r2, spsr	@ Save spsr_abt, abort is now safe
+ ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	stmfd	sp!, {r1 - r2}
+
+	add	r0, sp, #8			@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+
+	ldmfd	sp!, {r1 - r2}
+ ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	mov	lr, r1		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r2	@ Restore spsr_abt
+ ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+
+	svc_exit_via_fiq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+/*
  * User mode handlers
  *
  * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
@@ -683,6 +734,18 @@ ENTRY(ret_from_exception)
 ENDPROC(__pabt_usr)
 ENDPROC(ret_from_exception)
 
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+
 /*
  * Register switch for ARMv3 and ARMv4 processors
  * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
@@ -1118,17 +1181,29 @@ vector_addrexcptn:
 	b	vector_addrexcptn
 
 /*=============================================================================
- * Undefined FIQs
+ * FIQ "NMI" handler
  *-----------------------------------------------------------------------------
- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
- * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
- * Basically to switch modes, we *HAVE* to clobber one register...  brain
- * damage alert!  I don't think that we can execute any code in here in any
- * other mode than FIQ...  Ok you can switch to another mode, but you can't
- * get out of that mode without clobbering one register.
+ * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
+ * systems.
  */
-vector_fiq:
-	subs	pc, lr, #4
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
 
 	.globl	vector_fiq_offset
 	.equ	vector_fiq_offset, vector_fiq
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 2fdf867..0d91ca0 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -216,6 +216,34 @@
 	ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
 	.endm
 
+	@
+	@ svc_exit_via_fiq - like svc_exit but switches to FIQ mode before exit
+	@
+	@ This macro acts in a similar manner to svc_exit but switches to FIQ
+	@ mode to restore the final part of the register state.
+	@
+	@ We cannot use the normal svc_exit procedure because that would
+	@ clobber spsr_svc (FIQ could be delivered during the first few
+	@ instructions of vector_swi meaning its contents have not been
+	@ saved anywhere).
+	@
+	@ Note that, unlike svc_exit, this macro also does not allow a caller
+	@ supplied rpsr. This is because the FIQ exceptions are not re-entrant
+	@ and the handlers cannot call into the scheduler (meaning the value
+	@ on the stack remains correct).
+	@
+	.macro  svc_exit_via_fiq
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+	.endm
+
 	.macro	restore_user_regs, fast = 0, offset = 0
 	ldr	r1, [sp, #\offset + S_PSR]	@ get calling cpsr
 	ldr	lr, [sp, #\offset + S_PC]!	@ get pc
@@ -267,6 +295,25 @@
 	rfeia	sp!
 	.endm
 
+	@
+	@ svc_exit_via_fiq - like svc_exit but switches to FIQ mode before exit
+	@
+	@ For full details see non-Thumb implementation above.
+	@
+	.macro  svc_exit_via_fiq
+	add	r0, sp, #S_R2
+	ldr	lr, [sp, #S_LR]
+	ldr	sp, [sp, #S_SP] @ abort is deadly from here onward (it will
+			        @ clobber state restored below)
+	ldmia	r0, {r2 - r12}
+	mov	r1, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	msr	cpsr_c, r1
+	sub	r0, #S_R2
+	add	r8, r0, #S_PC
+	ldmia	r0, {r0 - r1}
+	rfeia	r8
+	.endm
+
 #ifdef CONFIG_CPU_V7M
 	/*
 	 * Note we don't need to do clrex here as clearing the local monitor is
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 84db893d..c031063 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -133,6 +133,7 @@ struct stack {
 	u32 irq[3];
 	u32 abt[3];
 	u32 und[3];
+	u32 fiq[3];
 } ____cacheline_aligned;
 
 #ifndef CONFIG_CPU_V7M
@@ -470,7 +471,10 @@ void notrace cpu_init(void)
 	"msr	cpsr_c, %5\n\t"
 	"add	r14, %0, %6\n\t"
 	"mov	sp, r14\n\t"
-	"msr	cpsr_c, %7"
+	"msr	cpsr_c, %7\n\t"
+	"add	r14, %0, %8\n\t"
+	"mov	sp, r14\n\t"
+	"msr	cpsr_c, %9"
 	    :
 	    : "r" (stk),
 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
@@ -479,6 +483,8 @@ void notrace cpu_init(void)
 	      "I" (offsetof(struct stack, abt[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
 	      "I" (offsetof(struct stack, und[0])),
+	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+	      "I" (offsetof(struct stack, fiq[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
 	    : "r14");
 #endif
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index a447dcc..439138d 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -25,6 +25,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/irq.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -461,6 +462,31 @@ die_sig:
 }
 
 /*
+ * Handle FIQ similarly to NMI on x86 systems.
+ *
+ * The runtime environment for NMIs is extremely restrictive
+ * (NMIs can pre-empt critical sections meaning almost all locking is
+ * forbidden) meaning this default FIQ handling must only be used in
+ * circumstances where non-maskability improves robustness, such as
+ * watchdog or debug logic.
+ *
+ * This handler is not appropriate for general purpose use in drivers
+ * platform code and can be overrideen using set_fiq_handler.
+ */
+asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
+{
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	nmi_enter();
+
+	/* nop. FIQ handlers for special arch/arm features can be added here. */
+
+	nmi_exit();
+
+	set_irq_regs(old_regs);
+}
+
+/*
  * bad_mode handles the impossible case in the vectors.  If you see one of
  * these, then it's extremely serious, and could mean you have buggy hardware.
  * It never returns, and never tries to sync.  We hope that we can at least
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 2/6] arm: fiq: Replace default FIQ handler
@ 2014-09-09 14:15                             ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-09 14:15 UTC (permalink / raw)
  To: linux-arm-kernel

This patch introduces a new default FIQ handler that is structured in a
similar way to the existing ARM exception handler and result in the FIQ
being handled by C code running on the SVC stack (despite this code run
in the FIQ handler is subject to severe limitations with respect to
locking making normal interaction with the kernel impossible).

This default handler allows concepts that on x86 would be handled using
NMIs to be realized on ARM.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of small fragments
    survive, however without Anton's work to build from this patch would
    not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/kernel/entry-armv.S   | 95 +++++++++++++++++++++++++++++++++++++-----
 arch/arm/kernel/entry-header.S | 47 +++++++++++++++++++++
 arch/arm/kernel/setup.c        |  8 +++-
 arch/arm/kernel/traps.c        | 26 ++++++++++++
 4 files changed, 165 insertions(+), 11 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 36276cd..0c70fee 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -146,7 +146,7 @@ ENDPROC(__und_invalid)
 #define SPFIX(code...)
 #endif
 
-	.macro	svc_entry, stack_hole=0
+	.macro	svc_entry, stack_hole=0, call_trace=1
  UNWIND(.fnstart		)
  UNWIND(.save {r0 - pc}		)
 	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
@@ -183,7 +183,9 @@ ENDPROC(__und_invalid)
 	stmia	r7, {r2 - r6}
 
 #ifdef CONFIG_TRACE_IRQFLAGS
+	.if \call_trace
 	bl	trace_hardirqs_off
+	.endif
 #endif
 	.endm
 
@@ -295,6 +297,15 @@ __pabt_svc:
 ENDPROC(__pabt_svc)
 
 	.align	5
+__fiq_svc:
+	svc_entry 0, 0
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	svc_exit_via_fiq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+	.align	5
 .LCcralign:
 	.word	cr_alignment
 #ifdef MULTI_DABORT
@@ -305,6 +316,46 @@ ENDPROC(__pabt_svc)
 	.word	fp_enter
 
 /*
+ * Abort mode handlers
+ */
+
+@
+@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
+@ and reuses the same macros. However in abort mode we must also
+@ save/restore lr_abt and spsr_abt to make nested aborts safe.
+@
+	.align 5
+__fiq_abt:
+	svc_entry 0, 0
+
+ ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	mov	r1, lr		@ Save lr_abt
+	mrs	r2, spsr	@ Save spsr_abt, abort is now safe
+ ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	stmfd	sp!, {r1 - r2}
+
+	add	r0, sp, #8			@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+
+	ldmfd	sp!, {r1 - r2}
+ ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	mov	lr, r1		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r2	@ Restore spsr_abt
+ ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+
+	svc_exit_via_fiq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+/*
  * User mode handlers
  *
  * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
@@ -683,6 +734,18 @@ ENTRY(ret_from_exception)
 ENDPROC(__pabt_usr)
 ENDPROC(ret_from_exception)
 
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+
 /*
  * Register switch for ARMv3 and ARMv4 processors
  * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
@@ -1118,17 +1181,29 @@ vector_addrexcptn:
 	b	vector_addrexcptn
 
 /*=============================================================================
- * Undefined FIQs
+ * FIQ "NMI" handler
  *-----------------------------------------------------------------------------
- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
- * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
- * Basically to switch modes, we *HAVE* to clobber one register...  brain
- * damage alert!  I don't think that we can execute any code in here in any
- * other mode than FIQ...  Ok you can switch to another mode, but you can't
- * get out of that mode without clobbering one register.
+ * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
+ * systems.
  */
-vector_fiq:
-	subs	pc, lr, #4
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
 
 	.globl	vector_fiq_offset
 	.equ	vector_fiq_offset, vector_fiq
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 2fdf867..0d91ca0 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -216,6 +216,34 @@
 	ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
 	.endm
 
+	@
+	@ svc_exit_via_fiq - like svc_exit but switches to FIQ mode before exit
+	@
+	@ This macro acts in a similar manner to svc_exit but switches to FIQ
+	@ mode to restore the final part of the register state.
+	@
+	@ We cannot use the normal svc_exit procedure because that would
+	@ clobber spsr_svc (FIQ could be delivered during the first few
+	@ instructions of vector_swi meaning its contents have not been
+	@ saved anywhere).
+	@
+	@ Note that, unlike svc_exit, this macro also does not allow a caller
+	@ supplied rpsr. This is because the FIQ exceptions are not re-entrant
+	@ and the handlers cannot call into the scheduler (meaning the value
+	@ on the stack remains correct).
+	@
+	.macro  svc_exit_via_fiq
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+	.endm
+
 	.macro	restore_user_regs, fast = 0, offset = 0
 	ldr	r1, [sp, #\offset + S_PSR]	@ get calling cpsr
 	ldr	lr, [sp, #\offset + S_PC]!	@ get pc
@@ -267,6 +295,25 @@
 	rfeia	sp!
 	.endm
 
+	@
+	@ svc_exit_via_fiq - like svc_exit but switches to FIQ mode before exit
+	@
+	@ For full details see non-Thumb implementation above.
+	@
+	.macro  svc_exit_via_fiq
+	add	r0, sp, #S_R2
+	ldr	lr, [sp, #S_LR]
+	ldr	sp, [sp, #S_SP] @ abort is deadly from here onward (it will
+			        @ clobber state restored below)
+	ldmia	r0, {r2 - r12}
+	mov	r1, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	msr	cpsr_c, r1
+	sub	r0, #S_R2
+	add	r8, r0, #S_PC
+	ldmia	r0, {r0 - r1}
+	rfeia	r8
+	.endm
+
 #ifdef CONFIG_CPU_V7M
 	/*
 	 * Note we don't need to do clrex here as clearing the local monitor is
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 84db893d..c031063 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -133,6 +133,7 @@ struct stack {
 	u32 irq[3];
 	u32 abt[3];
 	u32 und[3];
+	u32 fiq[3];
 } ____cacheline_aligned;
 
 #ifndef CONFIG_CPU_V7M
@@ -470,7 +471,10 @@ void notrace cpu_init(void)
 	"msr	cpsr_c, %5\n\t"
 	"add	r14, %0, %6\n\t"
 	"mov	sp, r14\n\t"
-	"msr	cpsr_c, %7"
+	"msr	cpsr_c, %7\n\t"
+	"add	r14, %0, %8\n\t"
+	"mov	sp, r14\n\t"
+	"msr	cpsr_c, %9"
 	    :
 	    : "r" (stk),
 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
@@ -479,6 +483,8 @@ void notrace cpu_init(void)
 	      "I" (offsetof(struct stack, abt[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
 	      "I" (offsetof(struct stack, und[0])),
+	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+	      "I" (offsetof(struct stack, fiq[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
 	    : "r14");
 #endif
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index a447dcc..439138d 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -25,6 +25,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/irq.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -461,6 +462,31 @@ die_sig:
 }
 
 /*
+ * Handle FIQ similarly to NMI on x86 systems.
+ *
+ * The runtime environment for NMIs is extremely restrictive
+ * (NMIs can pre-empt critical sections meaning almost all locking is
+ * forbidden) meaning this default FIQ handling must only be used in
+ * circumstances where non-maskability improves robustness, such as
+ * watchdog or debug logic.
+ *
+ * This handler is not appropriate for general purpose use in drivers
+ * platform code and can be overrideen using set_fiq_handler.
+ */
+asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
+{
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	nmi_enter();
+
+	/* nop. FIQ handlers for special arch/arm features can be added here. */
+
+	nmi_exit();
+
+	set_irq_regs(old_regs);
+}
+
+/*
  * bad_mode handles the impossible case in the vectors.  If you see one of
  * these, then it's extremely serious, and could mean you have buggy hardware.
  * It never returns, and never tries to sync.  We hope that we can at least
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 3/6] arm64: Introduce dummy version of asm/fiq.h
  2014-09-09 14:15                           ` Daniel Thompson
@ 2014-09-09 14:15                             ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-09 14:15 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Catalin Marinas, Will Deacon

Drivers that are shared between arm and arm64 and which employ
FIQ on arm cannot include asm/fiq.h without #ifdef'ing. This patch
introduces a dummy version of asm/fiq.h to arm64 to avoid this.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
 arch/arm64/include/asm/fiq.h | 8 ++++++++
 1 file changed, 8 insertions(+)
 create mode 100644 arch/arm64/include/asm/fiq.h

diff --git a/arch/arm64/include/asm/fiq.h b/arch/arm64/include/asm/fiq.h
new file mode 100644
index 0000000..d3776b8
--- /dev/null
+++ b/arch/arm64/include/asm/fiq.h
@@ -0,0 +1,8 @@
+/*
+ * Placeholder to reduce #ifdef'ing in shared arm/arm64 drivers. It
+ * allows code of the following form to be made unconditional.
+ *
+ * #ifdef CONFIG_FIQ
+ * #include <asm/fiq.h>
+ * #endif
+ */
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 3/6] arm64: Introduce dummy version of asm/fiq.h
@ 2014-09-09 14:15                             ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-09 14:15 UTC (permalink / raw)
  To: linux-arm-kernel

Drivers that are shared between arm and arm64 and which employ
FIQ on arm cannot include asm/fiq.h without #ifdef'ing. This patch
introduces a dummy version of asm/fiq.h to arm64 to avoid this.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
 arch/arm64/include/asm/fiq.h | 8 ++++++++
 1 file changed, 8 insertions(+)
 create mode 100644 arch/arm64/include/asm/fiq.h

diff --git a/arch/arm64/include/asm/fiq.h b/arch/arm64/include/asm/fiq.h
new file mode 100644
index 0000000..d3776b8
--- /dev/null
+++ b/arch/arm64/include/asm/fiq.h
@@ -0,0 +1,8 @@
+/*
+ * Placeholder to reduce #ifdef'ing in shared arm/arm64 drivers. It
+ * allows code of the following form to be made unconditional.
+ *
+ * #ifdef CONFIG_FIQ
+ * #include <asm/fiq.h>
+ * #endif
+ */
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 4/6] irqchip: gic: Add support for IPI FIQ
  2014-09-09 14:15                           ` Daniel Thompson
@ 2014-09-09 14:15                             ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-09 14:15 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Jason Cooper

This patch provides support for arm's newly added IPI FIQ. It works
by placing all interrupt sources *except* IPI FIQ in group 1 and
then flips a configuration bit in the GIC such that group 1
interrupts use IRQ and group 0 interrupts use FIQ.

All GIC hardware except GICv1-without-TrustZone support provides a means
to group exceptions into group 0 and group 1. However the hardware
functionality is unavailable to the kernel when a secure monitor is
present because access to the grouping registers are prohibited outside
"secure world" (a feature that allows grouping to be used to allow
hardware peripherals to send interrupts into the secure world). However
when grouping is not available we can rely on the GIC's RAZ/WI semantics
and avoid conditional code.

Tested on Freescale i.MX6 (quad A9, GICv1-with-TrustZone running in
secure mode).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
---
 arch/arm/kernel/traps.c         |   5 +-
 drivers/irqchip/irq-gic.c       | 140 ++++++++++++++++++++++++++++++++++++++--
 include/linux/irqchip/arm-gic.h |   3 +
 3 files changed, 142 insertions(+), 6 deletions(-)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 439138d..92c4ea1 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/irq.h>
+#include <linux/irqchip/arm-gic.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -479,7 +480,9 @@ asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
 
 	nmi_enter();
 
-	/* nop. FIQ handlers for special arch/arm features can be added here. */
+#ifdef CONFIG_ARM_GIC
+	gic_handle_fiq_ipi();
+#endif
 
 	nmi_exit();
 
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4b959e6..0d67b0e 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,8 +39,10 @@
 #include <linux/slab.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/ratelimit.h>
 
 #include <asm/cputype.h>
+#include <asm/fiq.h>
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
@@ -48,6 +50,10 @@
 #include "irq-gic-common.h"
 #include "irqchip.h"
 
+#ifndef SMP_IPI_FIQ_MASK
+#define SMP_IPI_FIQ_MASK 0
+#endif
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -325,6 +331,94 @@ static struct irq_chip gic_chip = {
 	.irq_set_wake		= gic_set_wake,
 };
 
+/*
+ * Shift an interrupt between Group 0 and Group 1.
+ *
+ * In addition to changing the group we also modify the priority to
+ * match what "ARM strongly recommends" for a system where no Group 1
+ * interrupt must ever preempt a Group 0 interrupt.
+ *
+ * If is safe to call this function on systems which do not support
+ * grouping (it will have no effect).
+ */
+static void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				int group)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_mask = BIT(hwirq % 32);
+	u32 grp_val;
+
+	unsigned int pri_reg = (hwirq / 4) * 4;
+	u32 pri_mask = BIT(7 + ((hwirq % 4) * 8));
+	u32 pri_val;
+
+	/*
+	 * Systems which do not support grouping will have no bits
+	 * set in IGROUP[0] (and all systems which do will have set bits).
+	 */
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + 0);
+	if (!grp_val)
+		return;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(base + GIC_DIST_PRI + pri_reg);
+
+	if (group) {
+		grp_val |= grp_mask;
+		pri_val |= pri_mask;
+	} else {
+		grp_val &= ~grp_mask;
+		pri_val &= ~pri_mask;
+	}
+
+	writel_relaxed(grp_val, base + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, base + GIC_DIST_PRI + pri_reg);
+
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+/*
+ * Test which group an interrupt belongs to.
+ *
+ * Returns 0 if the controller does not support grouping.
+ */
+static int gic_get_group_irq(void __iomem *base, unsigned int hwirq)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_val;
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+
+	return (grp_val >> (hwirq % 32)) & 1;
+}
+
+/*
+ * Fully acknowledge (both ack and eoi) any outstanding FIQ-based IPI,
+ * otherwise do nothing.
+ */
+void gic_handle_fiq_ipi(void)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	unsigned long irqstat, irqnr;
+
+	if (WARN_ON(!in_nmi()))
+		return;
+
+	while ((1u << readl_relaxed(cpu_base + GIC_CPU_HIGHPRI)) &
+	       SMP_IPI_FIQ_MASK) {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		WARN_RATELIMIT(irqnr > 16,
+			       "Unexpected irqnr %lu (bad prioritization?)\n",
+			       irqnr);
+	}
+}
+
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
 	if (gic_nr >= MAX_GIC_NR)
@@ -373,7 +467,18 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 
 	gic_dist_config(base, gic_irqs, NULL);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Set all global interrupts to be group 1 (this register is
+	 * RAZ/WI if not accessible in current mode)
+	 */
+	for (i = 32; i < gic_irqs; i += 32)
+		writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	writel_relaxed(3, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -382,6 +487,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	void __iomem *base = gic_data_cpu_base(gic);
 	unsigned int cpu_mask, cpu = smp_processor_id();
 	int i;
+	unsigned long secure_irqs, secure_irq;
 
 	/*
 	 * Get what the GIC says our CPU mask is.
@@ -400,8 +506,27 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 
 	gic_cpu_config(dist_base, NULL);
 
+	/*
+	 * Set any PPI and SGI interrupts not set in SMP_IPI_FIQ_MASK
+	 * to be group 1 (this register is RAZ/WI if not accessible)
+	 */
+	writel_relaxed(~SMP_IPI_FIQ_MASK, dist_base + GIC_DIST_IGROUP + 0);
+
+	/*
+	 * Update the priority of any resulting group0 interrupts.
+	 */
+	secure_irqs = ~readl_relaxed(dist_base + GIC_DIST_IGROUP + 0);
+	for_each_set_bit(secure_irq, &secure_irqs, 16)
+		gic_set_group_irq(dist_base, i, 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+
+	/* The bottom most bit will be set for all GIC variants (and is
+	 * called Enable or EnableGrp0 depending on operating mode). The
+	 * remaining four bits (CBPR, FIQEn, AckCtl and EnableGrp1) are
+	 * RAZ/WI if not accessible.
+	 */
+	writel_relaxed(0x1f, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -485,7 +610,7 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	writel_relaxed(3, dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -542,7 +667,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -604,6 +729,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
 	unsigned long flags, map = 0;
+	unsigned long softint;
 
 	raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
@@ -618,7 +744,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+	softint = map << 16 | irq;
+	if (gic_get_group_irq(gic_data_dist_base(&gic_data[0]), irq))
+		softint |= 0x8000;
+	writel_relaxed(softint,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 45e2d8c..52a5676 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops
 {
 	gic_routable_irq_domain_ops = ops;
 }
+
+void gic_handle_fiq_ipi(void);
+
 #endif /* __ASSEMBLY */
 #endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 4/6] irqchip: gic: Add support for IPI FIQ
@ 2014-09-09 14:15                             ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-09 14:15 UTC (permalink / raw)
  To: linux-arm-kernel

This patch provides support for arm's newly added IPI FIQ. It works
by placing all interrupt sources *except* IPI FIQ in group 1 and
then flips a configuration bit in the GIC such that group 1
interrupts use IRQ and group 0 interrupts use FIQ.

All GIC hardware except GICv1-without-TrustZone support provides a means
to group exceptions into group 0 and group 1. However the hardware
functionality is unavailable to the kernel when a secure monitor is
present because access to the grouping registers are prohibited outside
"secure world" (a feature that allows grouping to be used to allow
hardware peripherals to send interrupts into the secure world). However
when grouping is not available we can rely on the GIC's RAZ/WI semantics
and avoid conditional code.

Tested on Freescale i.MX6 (quad A9, GICv1-with-TrustZone running in
secure mode).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
---
 arch/arm/kernel/traps.c         |   5 +-
 drivers/irqchip/irq-gic.c       | 140 ++++++++++++++++++++++++++++++++++++++--
 include/linux/irqchip/arm-gic.h |   3 +
 3 files changed, 142 insertions(+), 6 deletions(-)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 439138d..92c4ea1 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/irq.h>
+#include <linux/irqchip/arm-gic.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -479,7 +480,9 @@ asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
 
 	nmi_enter();
 
-	/* nop. FIQ handlers for special arch/arm features can be added here. */
+#ifdef CONFIG_ARM_GIC
+	gic_handle_fiq_ipi();
+#endif
 
 	nmi_exit();
 
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4b959e6..0d67b0e 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,8 +39,10 @@
 #include <linux/slab.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/ratelimit.h>
 
 #include <asm/cputype.h>
+#include <asm/fiq.h>
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
@@ -48,6 +50,10 @@
 #include "irq-gic-common.h"
 #include "irqchip.h"
 
+#ifndef SMP_IPI_FIQ_MASK
+#define SMP_IPI_FIQ_MASK 0
+#endif
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -325,6 +331,94 @@ static struct irq_chip gic_chip = {
 	.irq_set_wake		= gic_set_wake,
 };
 
+/*
+ * Shift an interrupt between Group 0 and Group 1.
+ *
+ * In addition to changing the group we also modify the priority to
+ * match what "ARM strongly recommends" for a system where no Group 1
+ * interrupt must ever preempt a Group 0 interrupt.
+ *
+ * If is safe to call this function on systems which do not support
+ * grouping (it will have no effect).
+ */
+static void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				int group)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_mask = BIT(hwirq % 32);
+	u32 grp_val;
+
+	unsigned int pri_reg = (hwirq / 4) * 4;
+	u32 pri_mask = BIT(7 + ((hwirq % 4) * 8));
+	u32 pri_val;
+
+	/*
+	 * Systems which do not support grouping will have no bits
+	 * set in IGROUP[0] (and all systems which do will have set bits).
+	 */
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + 0);
+	if (!grp_val)
+		return;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(base + GIC_DIST_PRI + pri_reg);
+
+	if (group) {
+		grp_val |= grp_mask;
+		pri_val |= pri_mask;
+	} else {
+		grp_val &= ~grp_mask;
+		pri_val &= ~pri_mask;
+	}
+
+	writel_relaxed(grp_val, base + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, base + GIC_DIST_PRI + pri_reg);
+
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+/*
+ * Test which group an interrupt belongs to.
+ *
+ * Returns 0 if the controller does not support grouping.
+ */
+static int gic_get_group_irq(void __iomem *base, unsigned int hwirq)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_val;
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+
+	return (grp_val >> (hwirq % 32)) & 1;
+}
+
+/*
+ * Fully acknowledge (both ack and eoi) any outstanding FIQ-based IPI,
+ * otherwise do nothing.
+ */
+void gic_handle_fiq_ipi(void)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	unsigned long irqstat, irqnr;
+
+	if (WARN_ON(!in_nmi()))
+		return;
+
+	while ((1u << readl_relaxed(cpu_base + GIC_CPU_HIGHPRI)) &
+	       SMP_IPI_FIQ_MASK) {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		WARN_RATELIMIT(irqnr > 16,
+			       "Unexpected irqnr %lu (bad prioritization?)\n",
+			       irqnr);
+	}
+}
+
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
 	if (gic_nr >= MAX_GIC_NR)
@@ -373,7 +467,18 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 
 	gic_dist_config(base, gic_irqs, NULL);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Set all global interrupts to be group 1 (this register is
+	 * RAZ/WI if not accessible in current mode)
+	 */
+	for (i = 32; i < gic_irqs; i += 32)
+		writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	writel_relaxed(3, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -382,6 +487,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	void __iomem *base = gic_data_cpu_base(gic);
 	unsigned int cpu_mask, cpu = smp_processor_id();
 	int i;
+	unsigned long secure_irqs, secure_irq;
 
 	/*
 	 * Get what the GIC says our CPU mask is.
@@ -400,8 +506,27 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 
 	gic_cpu_config(dist_base, NULL);
 
+	/*
+	 * Set any PPI and SGI interrupts not set in SMP_IPI_FIQ_MASK
+	 * to be group 1 (this register is RAZ/WI if not accessible)
+	 */
+	writel_relaxed(~SMP_IPI_FIQ_MASK, dist_base + GIC_DIST_IGROUP + 0);
+
+	/*
+	 * Update the priority of any resulting group0 interrupts.
+	 */
+	secure_irqs = ~readl_relaxed(dist_base + GIC_DIST_IGROUP + 0);
+	for_each_set_bit(secure_irq, &secure_irqs, 16)
+		gic_set_group_irq(dist_base, i, 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+
+	/* The bottom most bit will be set for all GIC variants (and is
+	 * called Enable or EnableGrp0 depending on operating mode). The
+	 * remaining four bits (CBPR, FIQEn, AckCtl and EnableGrp1) are
+	 * RAZ/WI if not accessible.
+	 */
+	writel_relaxed(0x1f, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -485,7 +610,7 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	writel_relaxed(3, dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -542,7 +667,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -604,6 +729,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
 	unsigned long flags, map = 0;
+	unsigned long softint;
 
 	raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
@@ -618,7 +744,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+	softint = map << 16 | irq;
+	if (gic_get_group_irq(gic_data_dist_base(&gic_data[0]), irq))
+		softint |= 0x8000;
+	writel_relaxed(softint,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 45e2d8c..52a5676 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops
 {
 	gic_routable_irq_domain_ops = ops;
 }
+
+void gic_handle_fiq_ipi(void);
+
 #endif /* __ASSEMBLY */
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 5/6] ARM: add basic support for on-demand backtrace of other CPUs
  2014-09-09 14:15                           ` Daniel Thompson
@ 2014-09-09 14:15                             ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-09 14:15 UTC (permalink / raw)
  To: Russell King
  Cc: Russell King, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Daniel Thompson

From: Russell King <rmk+kernel@arm.linux.org.uk>

Add basic infrastructure for triggering a backtrace of other CPUs
via an IPI, preferably at FIQ level.  It is intended that this shall
be used for cases where we have detected that something has already
failed in the kernel.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/irq.h |  5 ++++
 arch/arm/kernel/smp.c      | 62 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+)

diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h
index 53c15de..be1d07d 100644
--- a/arch/arm/include/asm/irq.h
+++ b/arch/arm/include/asm/irq.h
@@ -35,6 +35,11 @@ extern void (*handle_arch_irq)(struct pt_regs *);
 extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
 #endif
 
+#ifdef CONFIG_SMP
+extern void arch_trigger_all_cpu_backtrace(bool);
+#define arch_trigger_all_cpu_backtrace(x) arch_trigger_all_cpu_backtrace(x)
+#endif
+
 #endif
 
 #endif
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9388a3d..94959f9 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -72,8 +72,12 @@ enum ipi_msg_type {
 	IPI_CPU_STOP,
 	IPI_IRQ_WORK,
 	IPI_COMPLETION,
+	IPI_CPU_BACKTRACE,
 };
 
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
+
 static DECLARE_COMPLETION(cpu_running);
 
 static struct smp_operations smp_ops;
@@ -539,6 +543,21 @@ static void ipi_cpu_stop(unsigned int cpu)
 		cpu_relax();
 }
 
+static void ipi_cpu_backtrace(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+
+	if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
+		static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
+
+		arch_spin_lock(&lock);
+		printk(KERN_WARNING "FIQ backtrace for cpu %d\n", cpu);
+		show_regs(regs);
+		arch_spin_unlock(&lock);
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+	}
+}
+
 static DEFINE_PER_CPU(struct completion *, cpu_completion);
 
 int register_ipi_completion(struct completion *completion, int cpu)
@@ -618,6 +637,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		irq_exit();
 		break;
 
+	case IPI_CPU_BACKTRACE:
+		irq_enter();
+		ipi_cpu_backtrace(regs);
+		irq_exit();
+		break;
+
 	default:
 		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
 		       cpu, ipinr);
@@ -712,3 +737,40 @@ static int __init register_cpufreq_notifier(void)
 core_initcall(register_cpufreq_notifier);
 
 #endif
+
+void arch_trigger_all_cpu_backtrace(bool include_self)
+{
+	static unsigned long backtrace_flag;
+	int i, cpu = get_cpu();
+
+	if (test_and_set_bit(0, &backtrace_flag)) {
+		/*
+		 * If there is already a trigger_all_cpu_backtrace() in progress
+		 * (backtrace_flag == 1), don't output double cpu dump infos.
+		 */
+		put_cpu();
+		return;
+	}
+
+	cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
+	if (!include_self)
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+
+	if (!cpumask_empty(to_cpumask(backtrace_mask))) {
+		pr_info("Sending FIQ to %s CPUs:\n",
+			(include_self ? "all" : "other"));
+		smp_cross_call(to_cpumask(backtrace_mask), IPI_CPU_BACKTRACE);
+	}
+
+	/* Wait for up to 10 seconds for all CPUs to do the backtrace */
+	for (i = 0; i < 10 * 1000; i++) {
+		if (cpumask_empty(to_cpumask(backtrace_mask)))
+			break;
+
+		mdelay(1);
+	}
+
+	clear_bit(0, &backtrace_flag);
+	smp_mb__after_atomic();
+	put_cpu();
+}
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 5/6] ARM: add basic support for on-demand backtrace of other CPUs
@ 2014-09-09 14:15                             ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-09 14:15 UTC (permalink / raw)
  To: linux-arm-kernel

From: Russell King <rmk+kernel@arm.linux.org.uk>

Add basic infrastructure for triggering a backtrace of other CPUs
via an IPI, preferably at FIQ level.  It is intended that this shall
be used for cases where we have detected that something has already
failed in the kernel.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/irq.h |  5 ++++
 arch/arm/kernel/smp.c      | 62 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+)

diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h
index 53c15de..be1d07d 100644
--- a/arch/arm/include/asm/irq.h
+++ b/arch/arm/include/asm/irq.h
@@ -35,6 +35,11 @@ extern void (*handle_arch_irq)(struct pt_regs *);
 extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
 #endif
 
+#ifdef CONFIG_SMP
+extern void arch_trigger_all_cpu_backtrace(bool);
+#define arch_trigger_all_cpu_backtrace(x) arch_trigger_all_cpu_backtrace(x)
+#endif
+
 #endif
 
 #endif
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9388a3d..94959f9 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -72,8 +72,12 @@ enum ipi_msg_type {
 	IPI_CPU_STOP,
 	IPI_IRQ_WORK,
 	IPI_COMPLETION,
+	IPI_CPU_BACKTRACE,
 };
 
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
+
 static DECLARE_COMPLETION(cpu_running);
 
 static struct smp_operations smp_ops;
@@ -539,6 +543,21 @@ static void ipi_cpu_stop(unsigned int cpu)
 		cpu_relax();
 }
 
+static void ipi_cpu_backtrace(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+
+	if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
+		static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
+
+		arch_spin_lock(&lock);
+		printk(KERN_WARNING "FIQ backtrace for cpu %d\n", cpu);
+		show_regs(regs);
+		arch_spin_unlock(&lock);
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+	}
+}
+
 static DEFINE_PER_CPU(struct completion *, cpu_completion);
 
 int register_ipi_completion(struct completion *completion, int cpu)
@@ -618,6 +637,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		irq_exit();
 		break;
 
+	case IPI_CPU_BACKTRACE:
+		irq_enter();
+		ipi_cpu_backtrace(regs);
+		irq_exit();
+		break;
+
 	default:
 		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
 		       cpu, ipinr);
@@ -712,3 +737,40 @@ static int __init register_cpufreq_notifier(void)
 core_initcall(register_cpufreq_notifier);
 
 #endif
+
+void arch_trigger_all_cpu_backtrace(bool include_self)
+{
+	static unsigned long backtrace_flag;
+	int i, cpu = get_cpu();
+
+	if (test_and_set_bit(0, &backtrace_flag)) {
+		/*
+		 * If there is already a trigger_all_cpu_backtrace() in progress
+		 * (backtrace_flag == 1), don't output double cpu dump infos.
+		 */
+		put_cpu();
+		return;
+	}
+
+	cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
+	if (!include_self)
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+
+	if (!cpumask_empty(to_cpumask(backtrace_mask))) {
+		pr_info("Sending FIQ to %s CPUs:\n",
+			(include_self ? "all" : "other"));
+		smp_cross_call(to_cpumask(backtrace_mask), IPI_CPU_BACKTRACE);
+	}
+
+	/* Wait for up to 10 seconds for all CPUs to do the backtrace */
+	for (i = 0; i < 10 * 1000; i++) {
+		if (cpumask_empty(to_cpumask(backtrace_mask)))
+			break;
+
+		mdelay(1);
+	}
+
+	clear_bit(0, &backtrace_flag);
+	smp_mb__after_atomic();
+	put_cpu();
+}
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 6/6] arm: smp: Handle ipi_cpu_backtrace() using FIQ (if available)
  2014-09-09 14:15                           ` Daniel Thompson
@ 2014-09-09 14:15                             ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-09 14:15 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal

Previous changes have introduced a replacement default FIQ handler and
an implementation of arch_trigger_all_cpu_backtrace for ARM but these
are currently independant.

This patch plumbs together these features making it possible, on platforms
that support it, to trigger backtrace using FIQ.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/smp.h | 3 +++
 arch/arm/kernel/smp.c      | 5 ++++-
 arch/arm/kernel/traps.c    | 3 +++
 3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2ec765c..0580270 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -18,6 +18,8 @@
 # error "<asm/smp.h> included in non-SMP build"
 #endif
 
+#define SMP_IPI_FIQ_MASK 0x0100
+
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
 struct seq_file;
@@ -85,6 +87,7 @@ extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
 
+extern void ipi_cpu_backtrace(struct pt_regs *regs);
 extern int register_ipi_completion(struct completion *completion, int cpu);
 
 struct smp_operations {
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 94959f9..2a33bab 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -455,6 +455,7 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
 	S(IPI_CPU_STOP, "CPU stop interrupts"),
 	S(IPI_IRQ_WORK, "IRQ work interrupts"),
 	S(IPI_COMPLETION, "completion interrupts"),
+	S(IPI_BACKTRACE, "backtrace trigger interrupts"),
 };
 
 static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
@@ -543,7 +544,7 @@ static void ipi_cpu_stop(unsigned int cpu)
 		cpu_relax();
 }
 
-static void ipi_cpu_backtrace(struct pt_regs *regs)
+void ipi_cpu_backtrace(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
 
@@ -584,6 +585,8 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 	unsigned int cpu = smp_processor_id();
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
+	BUILD_BUG_ON(SMP_IPI_FIQ_MASK != BIT(IPI_CPU_BACKTRACE));
+
 	if ((unsigned)ipinr < NR_IPI) {
 		trace_ipi_entry(ipi_types[ipinr]);
 		__inc_irq_stat(cpu, ipi_irqs[ipinr]);
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 92c4ea1..40b1de7 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -483,6 +483,9 @@ asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
 #ifdef CONFIG_ARM_GIC
 	gic_handle_fiq_ipi();
 #endif
+#ifdef CONFIG_SMP
+	ipi_cpu_backtrace(regs);
+#endif
 
 	nmi_exit();
 
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH v4 6/6] arm: smp: Handle ipi_cpu_backtrace() using FIQ (if available)
@ 2014-09-09 14:15                             ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-09 14:15 UTC (permalink / raw)
  To: linux-arm-kernel

Previous changes have introduced a replacement default FIQ handler and
an implementation of arch_trigger_all_cpu_backtrace for ARM but these
are currently independant.

This patch plumbs together these features making it possible, on platforms
that support it, to trigger backtrace using FIQ.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/smp.h | 3 +++
 arch/arm/kernel/smp.c      | 5 ++++-
 arch/arm/kernel/traps.c    | 3 +++
 3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2ec765c..0580270 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -18,6 +18,8 @@
 # error "<asm/smp.h> included in non-SMP build"
 #endif
 
+#define SMP_IPI_FIQ_MASK 0x0100
+
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
 struct seq_file;
@@ -85,6 +87,7 @@ extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
 
+extern void ipi_cpu_backtrace(struct pt_regs *regs);
 extern int register_ipi_completion(struct completion *completion, int cpu);
 
 struct smp_operations {
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 94959f9..2a33bab 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -455,6 +455,7 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
 	S(IPI_CPU_STOP, "CPU stop interrupts"),
 	S(IPI_IRQ_WORK, "IRQ work interrupts"),
 	S(IPI_COMPLETION, "completion interrupts"),
+	S(IPI_BACKTRACE, "backtrace trigger interrupts"),
 };
 
 static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
@@ -543,7 +544,7 @@ static void ipi_cpu_stop(unsigned int cpu)
 		cpu_relax();
 }
 
-static void ipi_cpu_backtrace(struct pt_regs *regs)
+void ipi_cpu_backtrace(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
 
@@ -584,6 +585,8 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 	unsigned int cpu = smp_processor_id();
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
+	BUILD_BUG_ON(SMP_IPI_FIQ_MASK != BIT(IPI_CPU_BACKTRACE));
+
 	if ((unsigned)ipinr < NR_IPI) {
 		trace_ipi_entry(ipi_types[ipinr]);
 		__inc_irq_stat(cpu, ipi_irqs[ipinr]);
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 92c4ea1..40b1de7 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -483,6 +483,9 @@ asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
 #ifdef CONFIG_ARM_GIC
 	gic_handle_fiq_ipi();
 #endif
+#ifdef CONFIG_SMP
+	ipi_cpu_backtrace(regs);
+#endif
 
 	nmi_exit();
 
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 0/6] arm: Implement arch_trigger_all_cpu_backtrace
  2014-09-09 14:15                           ` Daniel Thompson
@ 2014-09-11 11:31                             ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-11 11:31 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal

This patchset implements arch_trigger_all_cpu_backtrace for arm.

Non-maskable signalling relies on the kernel being able to access FIQ
and therefore, for devices that implement TrustZone, it will work only on
systems that boot the kernel in secure mode.

Tested on Freescale iMX.6 (both via SysRq-l and by deliberately locking
up the kernel with CONFIG_DEBUG_SPINLOCK=y).

Changes since v4:

* Rebased on 3.17-rc4.

* Removed a spurious line from the final "glue it together" patch
  that broke the build.

Changes since v3:

* Replaced push/pop with stmfd/ldmfd respectively (review of Nicolas
  Pitre).

* Really fix bad pt_regs pointer generation in __fiq_abt.

* Remove fiq_safe_migration_lock and associated logic in
  gic_raise_softirq() (review of Russell King)

* Restructured to introduce the default FIQ handler first, before the
  new features (review of Russell King).

Changes since v2:

* Removed redundant header guards from arch/arm64/include/asm/fiq.h
  (review of Catalin Marinas).

* Moved svc_exit_via_fiq macro to entry-header.S (review of Nicolas
  Pitre).

Changes since v1:

* Restructured to sit nicely on a similar FYI patchset from Russell
  King. It now effectively replaces the work in progress final patch
  with something much more complete.

* Implemented (and tested) a Thumb-2 implementation of svc_exit_via_fiq
  (review of Nicolas Pitre)

* Dropped the GIC group 0 workaround patch. The issue of FIQ interrupts
  being acknowledged by the IRQ handler does still exist but should be
  harmless because the IRQ handler will still wind up calling
  ipi_cpu_backtrace().

* Removed any dependency on CONFIG_FIQ; all cpu backtrace effectively
  becomes a platform feature (although the use of non-maskable
  interrupts to implement it is best effort rather than guaranteed).

* Better comments highlighting usage of RAZ/WI registers (and parts of
  registers) in the GIC code.

Changes *before* v1:

* This patchset is a hugely cut-down successor to "[PATCH v11 00/19]
  arm: KGDB NMI/FIQ support". Thanks to Thomas Gleixner for suggesting
  the new structure. For historic details see:
        https://lkml.org/lkml/2014/9/2/227

* Fix bug in __fiq_abt (no longer passes a bad struct pt_regs value).
  In fixing this we also remove the useless indirection previously
  found in the fiq_handler macro.

* Make default fiq handler "always on" by migrating from fiq.c to
  traps.c and replace do_unexp_fiq with the new handler (review
  of Russell King).

* Add arm64 version of fiq.h (review of Russell King)

* Removed conditional branching and code from irq-gic.c, this is
  replaced by much simpler code that relies on the GIC specification's
  heavy use of read-as-zero/write-ignored (review of Russell King)


Daniel Thompson (5):
  arm: fiq: Replace default FIQ handler
  arm64: Introduce dummy version of asm/fiq.h
  irqchip: gic: Add support for IPI FIQ
  ARM: add basic support for on-demand backtrace of other CPUs
  arm: smp: Handle ipi_cpu_backtrace() using FIQ (if available)

Russell King (1):
  ARM: remove unused do_unexp_fiq() function

 arch/arm/include/asm/irq.h      |   5 ++
 arch/arm/include/asm/smp.h      |   3 +
 arch/arm/kernel/entry-armv.S    |  95 ++++++++++++++++++++++++---
 arch/arm/kernel/entry-header.S  |  47 ++++++++++++++
 arch/arm/kernel/setup.c         |   8 ++-
 arch/arm/kernel/smp.c           |  64 ++++++++++++++++++
 arch/arm/kernel/traps.c         |  32 ++++++++-
 arch/arm64/include/asm/fiq.h    |   8 +++
 drivers/irqchip/irq-gic.c       | 140 ++++++++++++++++++++++++++++++++++++++--
 include/linux/irqchip/arm-gic.h |   3 +
 10 files changed, 386 insertions(+), 19 deletions(-)
 create mode 100644 arch/arm64/include/asm/fiq.h

--
1.9.3


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 0/6] arm: Implement arch_trigger_all_cpu_backtrace
@ 2014-09-11 11:31                             ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-11 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset implements arch_trigger_all_cpu_backtrace for arm.

Non-maskable signalling relies on the kernel being able to access FIQ
and therefore, for devices that implement TrustZone, it will work only on
systems that boot the kernel in secure mode.

Tested on Freescale iMX.6 (both via SysRq-l and by deliberately locking
up the kernel with CONFIG_DEBUG_SPINLOCK=y).

Changes since v4:

* Rebased on 3.17-rc4.

* Removed a spurious line from the final "glue it together" patch
  that broke the build.

Changes since v3:

* Replaced push/pop with stmfd/ldmfd respectively (review of Nicolas
  Pitre).

* Really fix bad pt_regs pointer generation in __fiq_abt.

* Remove fiq_safe_migration_lock and associated logic in
  gic_raise_softirq() (review of Russell King)

* Restructured to introduce the default FIQ handler first, before the
  new features (review of Russell King).

Changes since v2:

* Removed redundant header guards from arch/arm64/include/asm/fiq.h
  (review of Catalin Marinas).

* Moved svc_exit_via_fiq macro to entry-header.S (review of Nicolas
  Pitre).

Changes since v1:

* Restructured to sit nicely on a similar FYI patchset from Russell
  King. It now effectively replaces the work in progress final patch
  with something much more complete.

* Implemented (and tested) a Thumb-2 implementation of svc_exit_via_fiq
  (review of Nicolas Pitre)

* Dropped the GIC group 0 workaround patch. The issue of FIQ interrupts
  being acknowledged by the IRQ handler does still exist but should be
  harmless because the IRQ handler will still wind up calling
  ipi_cpu_backtrace().

* Removed any dependency on CONFIG_FIQ; all cpu backtrace effectively
  becomes a platform feature (although the use of non-maskable
  interrupts to implement it is best effort rather than guaranteed).

* Better comments highlighting usage of RAZ/WI registers (and parts of
  registers) in the GIC code.

Changes *before* v1:

* This patchset is a hugely cut-down successor to "[PATCH v11 00/19]
  arm: KGDB NMI/FIQ support". Thanks to Thomas Gleixner for suggesting
  the new structure. For historic details see:
        https://lkml.org/lkml/2014/9/2/227

* Fix bug in __fiq_abt (no longer passes a bad struct pt_regs value).
  In fixing this we also remove the useless indirection previously
  found in the fiq_handler macro.

* Make default fiq handler "always on" by migrating from fiq.c to
  traps.c and replace do_unexp_fiq with the new handler (review
  of Russell King).

* Add arm64 version of fiq.h (review of Russell King)

* Removed conditional branching and code from irq-gic.c, this is
  replaced by much simpler code that relies on the GIC specification's
  heavy use of read-as-zero/write-ignored (review of Russell King)


Daniel Thompson (5):
  arm: fiq: Replace default FIQ handler
  arm64: Introduce dummy version of asm/fiq.h
  irqchip: gic: Add support for IPI FIQ
  ARM: add basic support for on-demand backtrace of other CPUs
  arm: smp: Handle ipi_cpu_backtrace() using FIQ (if available)

Russell King (1):
  ARM: remove unused do_unexp_fiq() function

 arch/arm/include/asm/irq.h      |   5 ++
 arch/arm/include/asm/smp.h      |   3 +
 arch/arm/kernel/entry-armv.S    |  95 ++++++++++++++++++++++++---
 arch/arm/kernel/entry-header.S  |  47 ++++++++++++++
 arch/arm/kernel/setup.c         |   8 ++-
 arch/arm/kernel/smp.c           |  64 ++++++++++++++++++
 arch/arm/kernel/traps.c         |  32 ++++++++-
 arch/arm64/include/asm/fiq.h    |   8 +++
 drivers/irqchip/irq-gic.c       | 140 ++++++++++++++++++++++++++++++++++++++--
 include/linux/irqchip/arm-gic.h |   3 +
 10 files changed, 386 insertions(+), 19 deletions(-)
 create mode 100644 arch/arm64/include/asm/fiq.h

--
1.9.3

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 1/6] ARM: remove unused do_unexp_fiq() function
  2014-09-11 11:31                             ` Daniel Thompson
@ 2014-09-11 11:31                               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-11 11:31 UTC (permalink / raw)
  To: Russell King
  Cc: Russell King, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Daniel Thompson

From: Russell King <rmk+kernel@arm.linux.org.uk>

do_unexp_fiq() has never been called by any code in the last 10 years,
it's about time it was removed!

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/kernel/traps.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index c8e4bb7..a447dcc 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -460,12 +460,6 @@ die_sig:
 	arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
 }
 
-asmlinkage void do_unexp_fiq (struct pt_regs *regs)
-{
-	printk("Hmm.  Unexpected FIQ received, but trying to continue\n");
-	printk("You may have a hardware problem...\n");
-}
-
 /*
  * bad_mode handles the impossible case in the vectors.  If you see one of
  * these, then it's extremely serious, and could mean you have buggy hardware.
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 1/6] ARM: remove unused do_unexp_fiq() function
@ 2014-09-11 11:31                               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-11 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

From: Russell King <rmk+kernel@arm.linux.org.uk>

do_unexp_fiq() has never been called by any code in the last 10 years,
it's about time it was removed!

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/kernel/traps.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index c8e4bb7..a447dcc 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -460,12 +460,6 @@ die_sig:
 	arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
 }
 
-asmlinkage void do_unexp_fiq (struct pt_regs *regs)
-{
-	printk("Hmm.  Unexpected FIQ received, but trying to continue\n");
-	printk("You may have a hardware problem...\n");
-}
-
 /*
  * bad_mode handles the impossible case in the vectors.  If you see one of
  * these, then it's extremely serious, and could mean you have buggy hardware.
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
  2014-09-11 11:31                             ` Daniel Thompson
@ 2014-09-11 11:31                               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-11 11:31 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Catalin Marinas

This patch introduces a new default FIQ handler that is structured in a
similar way to the existing ARM exception handler and result in the FIQ
being handled by C code running on the SVC stack (despite this code run
in the FIQ handler is subject to severe limitations with respect to
locking making normal interaction with the kernel impossible).

This default handler allows concepts that on x86 would be handled using
NMIs to be realized on ARM.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of small fragments
    survive, however without Anton's work to build from this patch would
    not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/kernel/entry-armv.S   | 95 +++++++++++++++++++++++++++++++++++++-----
 arch/arm/kernel/entry-header.S | 47 +++++++++++++++++++++
 arch/arm/kernel/setup.c        |  8 +++-
 arch/arm/kernel/traps.c        | 26 ++++++++++++
 4 files changed, 165 insertions(+), 11 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 36276cd..0c70fee 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -146,7 +146,7 @@ ENDPROC(__und_invalid)
 #define SPFIX(code...)
 #endif
 
-	.macro	svc_entry, stack_hole=0
+	.macro	svc_entry, stack_hole=0, call_trace=1
  UNWIND(.fnstart		)
  UNWIND(.save {r0 - pc}		)
 	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
@@ -183,7 +183,9 @@ ENDPROC(__und_invalid)
 	stmia	r7, {r2 - r6}
 
 #ifdef CONFIG_TRACE_IRQFLAGS
+	.if \call_trace
 	bl	trace_hardirqs_off
+	.endif
 #endif
 	.endm
 
@@ -295,6 +297,15 @@ __pabt_svc:
 ENDPROC(__pabt_svc)
 
 	.align	5
+__fiq_svc:
+	svc_entry 0, 0
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	svc_exit_via_fiq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+	.align	5
 .LCcralign:
 	.word	cr_alignment
 #ifdef MULTI_DABORT
@@ -305,6 +316,46 @@ ENDPROC(__pabt_svc)
 	.word	fp_enter
 
 /*
+ * Abort mode handlers
+ */
+
+@
+@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
+@ and reuses the same macros. However in abort mode we must also
+@ save/restore lr_abt and spsr_abt to make nested aborts safe.
+@
+	.align 5
+__fiq_abt:
+	svc_entry 0, 0
+
+ ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	mov	r1, lr		@ Save lr_abt
+	mrs	r2, spsr	@ Save spsr_abt, abort is now safe
+ ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	stmfd	sp!, {r1 - r2}
+
+	add	r0, sp, #8			@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+
+	ldmfd	sp!, {r1 - r2}
+ ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	mov	lr, r1		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r2	@ Restore spsr_abt
+ ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+
+	svc_exit_via_fiq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+/*
  * User mode handlers
  *
  * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
@@ -683,6 +734,18 @@ ENTRY(ret_from_exception)
 ENDPROC(__pabt_usr)
 ENDPROC(ret_from_exception)
 
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+
 /*
  * Register switch for ARMv3 and ARMv4 processors
  * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
@@ -1118,17 +1181,29 @@ vector_addrexcptn:
 	b	vector_addrexcptn
 
 /*=============================================================================
- * Undefined FIQs
+ * FIQ "NMI" handler
  *-----------------------------------------------------------------------------
- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
- * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
- * Basically to switch modes, we *HAVE* to clobber one register...  brain
- * damage alert!  I don't think that we can execute any code in here in any
- * other mode than FIQ...  Ok you can switch to another mode, but you can't
- * get out of that mode without clobbering one register.
+ * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
+ * systems.
  */
-vector_fiq:
-	subs	pc, lr, #4
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
 
 	.globl	vector_fiq_offset
 	.equ	vector_fiq_offset, vector_fiq
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 2fdf867..0d91ca0 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -216,6 +216,34 @@
 	ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
 	.endm
 
+	@
+	@ svc_exit_via_fiq - like svc_exit but switches to FIQ mode before exit
+	@
+	@ This macro acts in a similar manner to svc_exit but switches to FIQ
+	@ mode to restore the final part of the register state.
+	@
+	@ We cannot use the normal svc_exit procedure because that would
+	@ clobber spsr_svc (FIQ could be delivered during the first few
+	@ instructions of vector_swi meaning its contents have not been
+	@ saved anywhere).
+	@
+	@ Note that, unlike svc_exit, this macro also does not allow a caller
+	@ supplied rpsr. This is because the FIQ exceptions are not re-entrant
+	@ and the handlers cannot call into the scheduler (meaning the value
+	@ on the stack remains correct).
+	@
+	.macro  svc_exit_via_fiq
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+	.endm
+
 	.macro	restore_user_regs, fast = 0, offset = 0
 	ldr	r1, [sp, #\offset + S_PSR]	@ get calling cpsr
 	ldr	lr, [sp, #\offset + S_PC]!	@ get pc
@@ -267,6 +295,25 @@
 	rfeia	sp!
 	.endm
 
+	@
+	@ svc_exit_via_fiq - like svc_exit but switches to FIQ mode before exit
+	@
+	@ For full details see non-Thumb implementation above.
+	@
+	.macro  svc_exit_via_fiq
+	add	r0, sp, #S_R2
+	ldr	lr, [sp, #S_LR]
+	ldr	sp, [sp, #S_SP] @ abort is deadly from here onward (it will
+			        @ clobber state restored below)
+	ldmia	r0, {r2 - r12}
+	mov	r1, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	msr	cpsr_c, r1
+	sub	r0, #S_R2
+	add	r8, r0, #S_PC
+	ldmia	r0, {r0 - r1}
+	rfeia	r8
+	.endm
+
 #ifdef CONFIG_CPU_V7M
 	/*
 	 * Note we don't need to do clrex here as clearing the local monitor is
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 84db893d..c031063 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -133,6 +133,7 @@ struct stack {
 	u32 irq[3];
 	u32 abt[3];
 	u32 und[3];
+	u32 fiq[3];
 } ____cacheline_aligned;
 
 #ifndef CONFIG_CPU_V7M
@@ -470,7 +471,10 @@ void notrace cpu_init(void)
 	"msr	cpsr_c, %5\n\t"
 	"add	r14, %0, %6\n\t"
 	"mov	sp, r14\n\t"
-	"msr	cpsr_c, %7"
+	"msr	cpsr_c, %7\n\t"
+	"add	r14, %0, %8\n\t"
+	"mov	sp, r14\n\t"
+	"msr	cpsr_c, %9"
 	    :
 	    : "r" (stk),
 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
@@ -479,6 +483,8 @@ void notrace cpu_init(void)
 	      "I" (offsetof(struct stack, abt[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
 	      "I" (offsetof(struct stack, und[0])),
+	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+	      "I" (offsetof(struct stack, fiq[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
 	    : "r14");
 #endif
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index a447dcc..439138d 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -25,6 +25,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/irq.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -461,6 +462,31 @@ die_sig:
 }
 
 /*
+ * Handle FIQ similarly to NMI on x86 systems.
+ *
+ * The runtime environment for NMIs is extremely restrictive
+ * (NMIs can pre-empt critical sections meaning almost all locking is
+ * forbidden) meaning this default FIQ handling must only be used in
+ * circumstances where non-maskability improves robustness, such as
+ * watchdog or debug logic.
+ *
+ * This handler is not appropriate for general purpose use in drivers
+ * platform code and can be overrideen using set_fiq_handler.
+ */
+asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
+{
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	nmi_enter();
+
+	/* nop. FIQ handlers for special arch/arm features can be added here. */
+
+	nmi_exit();
+
+	set_irq_regs(old_regs);
+}
+
+/*
  * bad_mode handles the impossible case in the vectors.  If you see one of
  * these, then it's extremely serious, and could mean you have buggy hardware.
  * It never returns, and never tries to sync.  We hope that we can at least
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
@ 2014-09-11 11:31                               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-11 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

This patch introduces a new default FIQ handler that is structured in a
similar way to the existing ARM exception handler and result in the FIQ
being handled by C code running on the SVC stack (despite this code run
in the FIQ handler is subject to severe limitations with respect to
locking making normal interaction with the kernel impossible).

This default handler allows concepts that on x86 would be handled using
NMIs to be realized on ARM.

Credit:

    This patch is a near complete re-write of a patch originally
    provided by Anton Vorontsov. Today only a couple of small fragments
    survive, however without Anton's work to build from this patch would
    not exist.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/kernel/entry-armv.S   | 95 +++++++++++++++++++++++++++++++++++++-----
 arch/arm/kernel/entry-header.S | 47 +++++++++++++++++++++
 arch/arm/kernel/setup.c        |  8 +++-
 arch/arm/kernel/traps.c        | 26 ++++++++++++
 4 files changed, 165 insertions(+), 11 deletions(-)

diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 36276cd..0c70fee 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -146,7 +146,7 @@ ENDPROC(__und_invalid)
 #define SPFIX(code...)
 #endif
 
-	.macro	svc_entry, stack_hole=0
+	.macro	svc_entry, stack_hole=0, call_trace=1
  UNWIND(.fnstart		)
  UNWIND(.save {r0 - pc}		)
 	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
@@ -183,7 +183,9 @@ ENDPROC(__und_invalid)
 	stmia	r7, {r2 - r6}
 
 #ifdef CONFIG_TRACE_IRQFLAGS
+	.if \call_trace
 	bl	trace_hardirqs_off
+	.endif
 #endif
 	.endm
 
@@ -295,6 +297,15 @@ __pabt_svc:
 ENDPROC(__pabt_svc)
 
 	.align	5
+__fiq_svc:
+	svc_entry 0, 0
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	svc_exit_via_fiq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+	.align	5
 .LCcralign:
 	.word	cr_alignment
 #ifdef MULTI_DABORT
@@ -305,6 +316,46 @@ ENDPROC(__pabt_svc)
 	.word	fp_enter
 
 /*
+ * Abort mode handlers
+ */
+
+@
+@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode
+@ and reuses the same macros. However in abort mode we must also
+@ save/restore lr_abt and spsr_abt to make nested aborts safe.
+@
+	.align 5
+__fiq_abt:
+	svc_entry 0, 0
+
+ ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	mov	r1, lr		@ Save lr_abt
+	mrs	r2, spsr	@ Save spsr_abt, abort is now safe
+ ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	stmfd	sp!, {r1 - r2}
+
+	add	r0, sp, #8			@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+
+	ldmfd	sp!, {r1 - r2}
+ ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+	mov	lr, r1		@ Restore lr_abt, abort is unsafe
+	msr	spsr_cxsf, r2	@ Restore spsr_abt
+ ARM(	msr	cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( mov	r0, #SVC_MODE | PSR_I_BIT | PSR_F_BIT )
+ THUMB( msr	cpsr_c, r0 )
+
+	svc_exit_via_fiq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_svc)
+
+/*
  * User mode handlers
  *
  * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
@@ -683,6 +734,18 @@ ENTRY(ret_from_exception)
 ENDPROC(__pabt_usr)
 ENDPROC(ret_from_exception)
 
+	.align	5
+__fiq_usr:
+	usr_entry
+	kuser_cmpxchg_check
+	mov	r0, sp				@ struct pt_regs *regs
+	bl	handle_fiq_as_nmi
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user_from_irq
+ UNWIND(.fnend		)
+ENDPROC(__fiq_usr)
+
 /*
  * Register switch for ARMv3 and ARMv4 processors
  * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
@@ -1118,17 +1181,29 @@ vector_addrexcptn:
 	b	vector_addrexcptn
 
 /*=============================================================================
- * Undefined FIQs
+ * FIQ "NMI" handler
  *-----------------------------------------------------------------------------
- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
- * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
- * Basically to switch modes, we *HAVE* to clobber one register...  brain
- * damage alert!  I don't think that we can execute any code in here in any
- * other mode than FIQ...  Ok you can switch to another mode, but you can't
- * get out of that mode without clobbering one register.
+ * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
+ * systems.
  */
-vector_fiq:
-	subs	pc, lr, #4
+	vector_stub	fiq, FIQ_MODE, 4
+
+	.long	__fiq_usr			@  0  (USR_26 / USR_32)
+	.long	__fiq_svc			@  1  (FIQ_26 / FIQ_32)
+	.long	__fiq_svc			@  2  (IRQ_26 / IRQ_32)
+	.long	__fiq_svc			@  3  (SVC_26 / SVC_32)
+	.long	__fiq_svc			@  4
+	.long	__fiq_svc			@  5
+	.long	__fiq_svc			@  6
+	.long	__fiq_abt			@  7
+	.long	__fiq_svc			@  8
+	.long	__fiq_svc			@  9
+	.long	__fiq_svc			@  a
+	.long	__fiq_svc			@  b
+	.long	__fiq_svc			@  c
+	.long	__fiq_svc			@  d
+	.long	__fiq_svc			@  e
+	.long	__fiq_svc			@  f
 
 	.globl	vector_fiq_offset
 	.equ	vector_fiq_offset, vector_fiq
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 2fdf867..0d91ca0 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -216,6 +216,34 @@
 	ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
 	.endm
 
+	@
+	@ svc_exit_via_fiq - like svc_exit but switches to FIQ mode before exit
+	@
+	@ This macro acts in a similar manner to svc_exit but switches to FIQ
+	@ mode to restore the final part of the register state.
+	@
+	@ We cannot use the normal svc_exit procedure because that would
+	@ clobber spsr_svc (FIQ could be delivered during the first few
+	@ instructions of vector_swi meaning its contents have not been
+	@ saved anywhere).
+	@
+	@ Note that, unlike svc_exit, this macro also does not allow a caller
+	@ supplied rpsr. This is because the FIQ exceptions are not re-entrant
+	@ and the handlers cannot call into the scheduler (meaning the value
+	@ on the stack remains correct).
+	@
+	.macro  svc_exit_via_fiq
+	mov	r0, sp
+	ldmib	r0, {r1 - r14}	@ abort is deadly from here onward (it will
+				@ clobber state restored below)
+	msr	cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	add	r8, r0, #S_PC
+	ldr	r9, [r0, #S_PSR]
+	msr	spsr_cxsf, r9
+	ldr	r0, [r0, #S_R0]
+	ldmia	r8, {pc}^
+	.endm
+
 	.macro	restore_user_regs, fast = 0, offset = 0
 	ldr	r1, [sp, #\offset + S_PSR]	@ get calling cpsr
 	ldr	lr, [sp, #\offset + S_PC]!	@ get pc
@@ -267,6 +295,25 @@
 	rfeia	sp!
 	.endm
 
+	@
+	@ svc_exit_via_fiq - like svc_exit but switches to FIQ mode before exit
+	@
+	@ For full details see non-Thumb implementation above.
+	@
+	.macro  svc_exit_via_fiq
+	add	r0, sp, #S_R2
+	ldr	lr, [sp, #S_LR]
+	ldr	sp, [sp, #S_SP] @ abort is deadly from here onward (it will
+			        @ clobber state restored below)
+	ldmia	r0, {r2 - r12}
+	mov	r1, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT
+	msr	cpsr_c, r1
+	sub	r0, #S_R2
+	add	r8, r0, #S_PC
+	ldmia	r0, {r0 - r1}
+	rfeia	r8
+	.endm
+
 #ifdef CONFIG_CPU_V7M
 	/*
 	 * Note we don't need to do clrex here as clearing the local monitor is
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 84db893d..c031063 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -133,6 +133,7 @@ struct stack {
 	u32 irq[3];
 	u32 abt[3];
 	u32 und[3];
+	u32 fiq[3];
 } ____cacheline_aligned;
 
 #ifndef CONFIG_CPU_V7M
@@ -470,7 +471,10 @@ void notrace cpu_init(void)
 	"msr	cpsr_c, %5\n\t"
 	"add	r14, %0, %6\n\t"
 	"mov	sp, r14\n\t"
-	"msr	cpsr_c, %7"
+	"msr	cpsr_c, %7\n\t"
+	"add	r14, %0, %8\n\t"
+	"mov	sp, r14\n\t"
+	"msr	cpsr_c, %9"
 	    :
 	    : "r" (stk),
 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
@@ -479,6 +483,8 @@ void notrace cpu_init(void)
 	      "I" (offsetof(struct stack, abt[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
 	      "I" (offsetof(struct stack, und[0])),
+	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+	      "I" (offsetof(struct stack, fiq[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
 	    : "r14");
 #endif
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index a447dcc..439138d 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -25,6 +25,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/irq.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -461,6 +462,31 @@ die_sig:
 }
 
 /*
+ * Handle FIQ similarly to NMI on x86 systems.
+ *
+ * The runtime environment for NMIs is extremely restrictive
+ * (NMIs can pre-empt critical sections meaning almost all locking is
+ * forbidden) meaning this default FIQ handling must only be used in
+ * circumstances where non-maskability improves robustness, such as
+ * watchdog or debug logic.
+ *
+ * This handler is not appropriate for general purpose use in drivers
+ * platform code and can be overrideen using set_fiq_handler.
+ */
+asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
+{
+	struct pt_regs *old_regs = set_irq_regs(regs);
+
+	nmi_enter();
+
+	/* nop. FIQ handlers for special arch/arm features can be added here. */
+
+	nmi_exit();
+
+	set_irq_regs(old_regs);
+}
+
+/*
  * bad_mode handles the impossible case in the vectors.  If you see one of
  * these, then it's extremely serious, and could mean you have buggy hardware.
  * It never returns, and never tries to sync.  We hope that we can at least
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 3/6] arm64: Introduce dummy version of asm/fiq.h
  2014-09-11 11:31                             ` Daniel Thompson
@ 2014-09-11 11:31                               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-11 11:31 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Catalin Marinas, Will Deacon

Drivers that are shared between arm and arm64 and which employ
FIQ on arm cannot include asm/fiq.h without #ifdef'ing. This patch
introduces a dummy version of asm/fiq.h to arm64 to avoid this.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
 arch/arm64/include/asm/fiq.h | 8 ++++++++
 1 file changed, 8 insertions(+)
 create mode 100644 arch/arm64/include/asm/fiq.h

diff --git a/arch/arm64/include/asm/fiq.h b/arch/arm64/include/asm/fiq.h
new file mode 100644
index 0000000..d3776b8
--- /dev/null
+++ b/arch/arm64/include/asm/fiq.h
@@ -0,0 +1,8 @@
+/*
+ * Placeholder to reduce #ifdef'ing in shared arm/arm64 drivers. It
+ * allows code of the following form to be made unconditional.
+ *
+ * #ifdef CONFIG_FIQ
+ * #include <asm/fiq.h>
+ * #endif
+ */
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 3/6] arm64: Introduce dummy version of asm/fiq.h
@ 2014-09-11 11:31                               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-11 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

Drivers that are shared between arm and arm64 and which employ
FIQ on arm cannot include asm/fiq.h without #ifdef'ing. This patch
introduces a dummy version of asm/fiq.h to arm64 to avoid this.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
 arch/arm64/include/asm/fiq.h | 8 ++++++++
 1 file changed, 8 insertions(+)
 create mode 100644 arch/arm64/include/asm/fiq.h

diff --git a/arch/arm64/include/asm/fiq.h b/arch/arm64/include/asm/fiq.h
new file mode 100644
index 0000000..d3776b8
--- /dev/null
+++ b/arch/arm64/include/asm/fiq.h
@@ -0,0 +1,8 @@
+/*
+ * Placeholder to reduce #ifdef'ing in shared arm/arm64 drivers. It
+ * allows code of the following form to be made unconditional.
+ *
+ * #ifdef CONFIG_FIQ
+ * #include <asm/fiq.h>
+ * #endif
+ */
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 4/6] irqchip: gic: Add support for IPI FIQ
  2014-09-11 11:31                             ` Daniel Thompson
@ 2014-09-11 11:31                               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-11 11:31 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Jason Cooper

This patch provides support for arm's newly added IPI FIQ. It works
by placing all interrupt sources *except* IPI FIQ in group 1 and
then flips a configuration bit in the GIC such that group 1
interrupts use IRQ and group 0 interrupts use FIQ.

All GIC hardware except GICv1-without-TrustZone support provides a means
to group exceptions into group 0 and group 1. However the hardware
functionality is unavailable to the kernel when a secure monitor is
present because access to the grouping registers are prohibited outside
"secure world" (a feature that allows grouping to be used to allow
hardware peripherals to send interrupts into the secure world). However
when grouping is not available we can rely on the GIC's RAZ/WI semantics
and avoid conditional code.

Tested on Freescale i.MX6 (quad A9, GICv1-with-TrustZone running in
secure mode).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
---
 arch/arm/kernel/traps.c         |   5 +-
 drivers/irqchip/irq-gic.c       | 140 ++++++++++++++++++++++++++++++++++++++--
 include/linux/irqchip/arm-gic.h |   3 +
 3 files changed, 142 insertions(+), 6 deletions(-)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 439138d..92c4ea1 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/irq.h>
+#include <linux/irqchip/arm-gic.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -479,7 +480,9 @@ asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
 
 	nmi_enter();
 
-	/* nop. FIQ handlers for special arch/arm features can be added here. */
+#ifdef CONFIG_ARM_GIC
+	gic_handle_fiq_ipi();
+#endif
 
 	nmi_exit();
 
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4b959e6..0d67b0e 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,8 +39,10 @@
 #include <linux/slab.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/ratelimit.h>
 
 #include <asm/cputype.h>
+#include <asm/fiq.h>
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
@@ -48,6 +50,10 @@
 #include "irq-gic-common.h"
 #include "irqchip.h"
 
+#ifndef SMP_IPI_FIQ_MASK
+#define SMP_IPI_FIQ_MASK 0
+#endif
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -325,6 +331,94 @@ static struct irq_chip gic_chip = {
 	.irq_set_wake		= gic_set_wake,
 };
 
+/*
+ * Shift an interrupt between Group 0 and Group 1.
+ *
+ * In addition to changing the group we also modify the priority to
+ * match what "ARM strongly recommends" for a system where no Group 1
+ * interrupt must ever preempt a Group 0 interrupt.
+ *
+ * If is safe to call this function on systems which do not support
+ * grouping (it will have no effect).
+ */
+static void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				int group)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_mask = BIT(hwirq % 32);
+	u32 grp_val;
+
+	unsigned int pri_reg = (hwirq / 4) * 4;
+	u32 pri_mask = BIT(7 + ((hwirq % 4) * 8));
+	u32 pri_val;
+
+	/*
+	 * Systems which do not support grouping will have no bits
+	 * set in IGROUP[0] (and all systems which do will have set bits).
+	 */
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + 0);
+	if (!grp_val)
+		return;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(base + GIC_DIST_PRI + pri_reg);
+
+	if (group) {
+		grp_val |= grp_mask;
+		pri_val |= pri_mask;
+	} else {
+		grp_val &= ~grp_mask;
+		pri_val &= ~pri_mask;
+	}
+
+	writel_relaxed(grp_val, base + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, base + GIC_DIST_PRI + pri_reg);
+
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+/*
+ * Test which group an interrupt belongs to.
+ *
+ * Returns 0 if the controller does not support grouping.
+ */
+static int gic_get_group_irq(void __iomem *base, unsigned int hwirq)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_val;
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+
+	return (grp_val >> (hwirq % 32)) & 1;
+}
+
+/*
+ * Fully acknowledge (both ack and eoi) any outstanding FIQ-based IPI,
+ * otherwise do nothing.
+ */
+void gic_handle_fiq_ipi(void)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	unsigned long irqstat, irqnr;
+
+	if (WARN_ON(!in_nmi()))
+		return;
+
+	while ((1u << readl_relaxed(cpu_base + GIC_CPU_HIGHPRI)) &
+	       SMP_IPI_FIQ_MASK) {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		WARN_RATELIMIT(irqnr > 16,
+			       "Unexpected irqnr %lu (bad prioritization?)\n",
+			       irqnr);
+	}
+}
+
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
 	if (gic_nr >= MAX_GIC_NR)
@@ -373,7 +467,18 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 
 	gic_dist_config(base, gic_irqs, NULL);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Set all global interrupts to be group 1 (this register is
+	 * RAZ/WI if not accessible in current mode)
+	 */
+	for (i = 32; i < gic_irqs; i += 32)
+		writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	writel_relaxed(3, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -382,6 +487,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	void __iomem *base = gic_data_cpu_base(gic);
 	unsigned int cpu_mask, cpu = smp_processor_id();
 	int i;
+	unsigned long secure_irqs, secure_irq;
 
 	/*
 	 * Get what the GIC says our CPU mask is.
@@ -400,8 +506,27 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 
 	gic_cpu_config(dist_base, NULL);
 
+	/*
+	 * Set any PPI and SGI interrupts not set in SMP_IPI_FIQ_MASK
+	 * to be group 1 (this register is RAZ/WI if not accessible)
+	 */
+	writel_relaxed(~SMP_IPI_FIQ_MASK, dist_base + GIC_DIST_IGROUP + 0);
+
+	/*
+	 * Update the priority of any resulting group0 interrupts.
+	 */
+	secure_irqs = ~readl_relaxed(dist_base + GIC_DIST_IGROUP + 0);
+	for_each_set_bit(secure_irq, &secure_irqs, 16)
+		gic_set_group_irq(dist_base, i, 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+
+	/* The bottom most bit will be set for all GIC variants (and is
+	 * called Enable or EnableGrp0 depending on operating mode). The
+	 * remaining four bits (CBPR, FIQEn, AckCtl and EnableGrp1) are
+	 * RAZ/WI if not accessible.
+	 */
+	writel_relaxed(0x1f, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -485,7 +610,7 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	writel_relaxed(3, dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -542,7 +667,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -604,6 +729,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
 	unsigned long flags, map = 0;
+	unsigned long softint;
 
 	raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
@@ -618,7 +744,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+	softint = map << 16 | irq;
+	if (gic_get_group_irq(gic_data_dist_base(&gic_data[0]), irq))
+		softint |= 0x8000;
+	writel_relaxed(softint,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 45e2d8c..52a5676 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops
 {
 	gic_routable_irq_domain_ops = ops;
 }
+
+void gic_handle_fiq_ipi(void);
+
 #endif /* __ASSEMBLY */
 #endif
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 4/6] irqchip: gic: Add support for IPI FIQ
@ 2014-09-11 11:31                               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-11 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

This patch provides support for arm's newly added IPI FIQ. It works
by placing all interrupt sources *except* IPI FIQ in group 1 and
then flips a configuration bit in the GIC such that group 1
interrupts use IRQ and group 0 interrupts use FIQ.

All GIC hardware except GICv1-without-TrustZone support provides a means
to group exceptions into group 0 and group 1. However the hardware
functionality is unavailable to the kernel when a secure monitor is
present because access to the grouping registers are prohibited outside
"secure world" (a feature that allows grouping to be used to allow
hardware peripherals to send interrupts into the secure world). However
when grouping is not available we can rely on the GIC's RAZ/WI semantics
and avoid conditional code.

Tested on Freescale i.MX6 (quad A9, GICv1-with-TrustZone running in
secure mode).

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
---
 arch/arm/kernel/traps.c         |   5 +-
 drivers/irqchip/irq-gic.c       | 140 ++++++++++++++++++++++++++++++++++++++--
 include/linux/irqchip/arm-gic.h |   3 +
 3 files changed, 142 insertions(+), 6 deletions(-)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 439138d..92c4ea1 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/irq.h>
+#include <linux/irqchip/arm-gic.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -479,7 +480,9 @@ asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
 
 	nmi_enter();
 
-	/* nop. FIQ handlers for special arch/arm features can be added here. */
+#ifdef CONFIG_ARM_GIC
+	gic_handle_fiq_ipi();
+#endif
 
 	nmi_exit();
 
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4b959e6..0d67b0e 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,8 +39,10 @@
 #include <linux/slab.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/ratelimit.h>
 
 #include <asm/cputype.h>
+#include <asm/fiq.h>
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
@@ -48,6 +50,10 @@
 #include "irq-gic-common.h"
 #include "irqchip.h"
 
+#ifndef SMP_IPI_FIQ_MASK
+#define SMP_IPI_FIQ_MASK 0
+#endif
+
 union gic_base {
 	void __iomem *common_base;
 	void __percpu * __iomem *percpu_base;
@@ -325,6 +331,94 @@ static struct irq_chip gic_chip = {
 	.irq_set_wake		= gic_set_wake,
 };
 
+/*
+ * Shift an interrupt between Group 0 and Group 1.
+ *
+ * In addition to changing the group we also modify the priority to
+ * match what "ARM strongly recommends" for a system where no Group 1
+ * interrupt must ever preempt a Group 0 interrupt.
+ *
+ * If is safe to call this function on systems which do not support
+ * grouping (it will have no effect).
+ */
+static void gic_set_group_irq(void __iomem *base, unsigned int hwirq,
+				int group)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_mask = BIT(hwirq % 32);
+	u32 grp_val;
+
+	unsigned int pri_reg = (hwirq / 4) * 4;
+	u32 pri_mask = BIT(7 + ((hwirq % 4) * 8));
+	u32 pri_val;
+
+	/*
+	 * Systems which do not support grouping will have no bits
+	 * set in IGROUP[0] (and all systems which do will have set bits).
+	 */
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + 0);
+	if (!grp_val)
+		return;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+	pri_val = readl_relaxed(base + GIC_DIST_PRI + pri_reg);
+
+	if (group) {
+		grp_val |= grp_mask;
+		pri_val |= pri_mask;
+	} else {
+		grp_val &= ~grp_mask;
+		pri_val &= ~pri_mask;
+	}
+
+	writel_relaxed(grp_val, base + GIC_DIST_IGROUP + grp_reg);
+	writel_relaxed(pri_val, base + GIC_DIST_PRI + pri_reg);
+
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+/*
+ * Test which group an interrupt belongs to.
+ *
+ * Returns 0 if the controller does not support grouping.
+ */
+static int gic_get_group_irq(void __iomem *base, unsigned int hwirq)
+{
+	unsigned int grp_reg = hwirq / 32 * 4;
+	u32 grp_val;
+
+	grp_val = readl_relaxed(base + GIC_DIST_IGROUP + grp_reg);
+
+	return (grp_val >> (hwirq % 32)) & 1;
+}
+
+/*
+ * Fully acknowledge (both ack and eoi) any outstanding FIQ-based IPI,
+ * otherwise do nothing.
+ */
+void gic_handle_fiq_ipi(void)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+	unsigned long irqstat, irqnr;
+
+	if (WARN_ON(!in_nmi()))
+		return;
+
+	while ((1u << readl_relaxed(cpu_base + GIC_CPU_HIGHPRI)) &
+	       SMP_IPI_FIQ_MASK) {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+
+		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+		WARN_RATELIMIT(irqnr > 16,
+			       "Unexpected irqnr %lu (bad prioritization?)\n",
+			       irqnr);
+	}
+}
+
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
 	if (gic_nr >= MAX_GIC_NR)
@@ -373,7 +467,18 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 
 	gic_dist_config(base, gic_irqs, NULL);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Set all global interrupts to be group 1 (this register is
+	 * RAZ/WI if not accessible in current mode)
+	 */
+	for (i = 32; i < gic_irqs; i += 32)
+		writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
+
+	/*
+	 * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only,
+	 * bit 1 ignored)
+	 */
+	writel_relaxed(3, base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_init(struct gic_chip_data *gic)
@@ -382,6 +487,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 	void __iomem *base = gic_data_cpu_base(gic);
 	unsigned int cpu_mask, cpu = smp_processor_id();
 	int i;
+	unsigned long secure_irqs, secure_irq;
 
 	/*
 	 * Get what the GIC says our CPU mask is.
@@ -400,8 +506,27 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 
 	gic_cpu_config(dist_base, NULL);
 
+	/*
+	 * Set any PPI and SGI interrupts not set in SMP_IPI_FIQ_MASK
+	 * to be group 1 (this register is RAZ/WI if not accessible)
+	 */
+	writel_relaxed(~SMP_IPI_FIQ_MASK, dist_base + GIC_DIST_IGROUP + 0);
+
+	/*
+	 * Update the priority of any resulting group0 interrupts.
+	 */
+	secure_irqs = ~readl_relaxed(dist_base + GIC_DIST_IGROUP + 0);
+	for_each_set_bit(secure_irq, &secure_irqs, 16)
+		gic_set_group_irq(dist_base, i, 0);
+
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+
+	/* The bottom most bit will be set for all GIC variants (and is
+	 * called Enable or EnableGrp0 depending on operating mode). The
+	 * remaining four bits (CBPR, FIQEn, AckCtl and EnableGrp1) are
+	 * RAZ/WI if not accessible.
+	 */
+	writel_relaxed(0x1f, base + GIC_CPU_CTRL);
 }
 
 void gic_cpu_if_down(void)
@@ -485,7 +610,7 @@ static void gic_dist_restore(unsigned int gic_nr)
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	writel_relaxed(3, dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -542,7 +667,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -604,6 +729,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
 	unsigned long flags, map = 0;
+	unsigned long softint;
 
 	raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
@@ -618,7 +744,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 	dmb(ishst);
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+	softint = map << 16 | irq;
+	if (gic_get_group_irq(gic_data_dist_base(&gic_data[0]), irq))
+		softint |= 0x8000;
+	writel_relaxed(softint,
+		       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 45e2d8c..52a5676 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops
 {
 	gic_routable_irq_domain_ops = ops;
 }
+
+void gic_handle_fiq_ipi(void);
+
 #endif /* __ASSEMBLY */
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 5/6] ARM: add basic support for on-demand backtrace of other CPUs
  2014-09-11 11:31                             ` Daniel Thompson
@ 2014-09-11 11:31                               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-11 11:31 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal,
	Russell King

Add basic infrastructure for triggering a backtrace of other CPUs
via an IPI, preferably at FIQ level.  It is intended that this shall
be used for cases where we have detected that something has already
failed in the kernel.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/irq.h |  5 ++++
 arch/arm/kernel/smp.c      | 62 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+)

diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h
index 53c15de..be1d07d 100644
--- a/arch/arm/include/asm/irq.h
+++ b/arch/arm/include/asm/irq.h
@@ -35,6 +35,11 @@ extern void (*handle_arch_irq)(struct pt_regs *);
 extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
 #endif
 
+#ifdef CONFIG_SMP
+extern void arch_trigger_all_cpu_backtrace(bool);
+#define arch_trigger_all_cpu_backtrace(x) arch_trigger_all_cpu_backtrace(x)
+#endif
+
 #endif
 
 #endif
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9388a3d..94959f9 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -72,8 +72,12 @@ enum ipi_msg_type {
 	IPI_CPU_STOP,
 	IPI_IRQ_WORK,
 	IPI_COMPLETION,
+	IPI_CPU_BACKTRACE,
 };
 
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
+
 static DECLARE_COMPLETION(cpu_running);
 
 static struct smp_operations smp_ops;
@@ -539,6 +543,21 @@ static void ipi_cpu_stop(unsigned int cpu)
 		cpu_relax();
 }
 
+static void ipi_cpu_backtrace(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+
+	if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
+		static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
+
+		arch_spin_lock(&lock);
+		printk(KERN_WARNING "FIQ backtrace for cpu %d\n", cpu);
+		show_regs(regs);
+		arch_spin_unlock(&lock);
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+	}
+}
+
 static DEFINE_PER_CPU(struct completion *, cpu_completion);
 
 int register_ipi_completion(struct completion *completion, int cpu)
@@ -618,6 +637,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		irq_exit();
 		break;
 
+	case IPI_CPU_BACKTRACE:
+		irq_enter();
+		ipi_cpu_backtrace(regs);
+		irq_exit();
+		break;
+
 	default:
 		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
 		       cpu, ipinr);
@@ -712,3 +737,40 @@ static int __init register_cpufreq_notifier(void)
 core_initcall(register_cpufreq_notifier);
 
 #endif
+
+void arch_trigger_all_cpu_backtrace(bool include_self)
+{
+	static unsigned long backtrace_flag;
+	int i, cpu = get_cpu();
+
+	if (test_and_set_bit(0, &backtrace_flag)) {
+		/*
+		 * If there is already a trigger_all_cpu_backtrace() in progress
+		 * (backtrace_flag == 1), don't output double cpu dump infos.
+		 */
+		put_cpu();
+		return;
+	}
+
+	cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
+	if (!include_self)
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+
+	if (!cpumask_empty(to_cpumask(backtrace_mask))) {
+		pr_info("Sending FIQ to %s CPUs:\n",
+			(include_self ? "all" : "other"));
+		smp_cross_call(to_cpumask(backtrace_mask), IPI_CPU_BACKTRACE);
+	}
+
+	/* Wait for up to 10 seconds for all CPUs to do the backtrace */
+	for (i = 0; i < 10 * 1000; i++) {
+		if (cpumask_empty(to_cpumask(backtrace_mask)))
+			break;
+
+		mdelay(1);
+	}
+
+	clear_bit(0, &backtrace_flag);
+	smp_mb__after_atomic();
+	put_cpu();
+}
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 5/6] ARM: add basic support for on-demand backtrace of other CPUs
@ 2014-09-11 11:31                               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-11 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

Add basic infrastructure for triggering a backtrace of other CPUs
via an IPI, preferably at FIQ level.  It is intended that this shall
be used for cases where we have detected that something has already
failed in the kernel.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/irq.h |  5 ++++
 arch/arm/kernel/smp.c      | 62 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+)

diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h
index 53c15de..be1d07d 100644
--- a/arch/arm/include/asm/irq.h
+++ b/arch/arm/include/asm/irq.h
@@ -35,6 +35,11 @@ extern void (*handle_arch_irq)(struct pt_regs *);
 extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
 #endif
 
+#ifdef CONFIG_SMP
+extern void arch_trigger_all_cpu_backtrace(bool);
+#define arch_trigger_all_cpu_backtrace(x) arch_trigger_all_cpu_backtrace(x)
+#endif
+
 #endif
 
 #endif
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9388a3d..94959f9 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -72,8 +72,12 @@ enum ipi_msg_type {
 	IPI_CPU_STOP,
 	IPI_IRQ_WORK,
 	IPI_COMPLETION,
+	IPI_CPU_BACKTRACE,
 };
 
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
+
 static DECLARE_COMPLETION(cpu_running);
 
 static struct smp_operations smp_ops;
@@ -539,6 +543,21 @@ static void ipi_cpu_stop(unsigned int cpu)
 		cpu_relax();
 }
 
+static void ipi_cpu_backtrace(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+
+	if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
+		static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
+
+		arch_spin_lock(&lock);
+		printk(KERN_WARNING "FIQ backtrace for cpu %d\n", cpu);
+		show_regs(regs);
+		arch_spin_unlock(&lock);
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+	}
+}
+
 static DEFINE_PER_CPU(struct completion *, cpu_completion);
 
 int register_ipi_completion(struct completion *completion, int cpu)
@@ -618,6 +637,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		irq_exit();
 		break;
 
+	case IPI_CPU_BACKTRACE:
+		irq_enter();
+		ipi_cpu_backtrace(regs);
+		irq_exit();
+		break;
+
 	default:
 		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
 		       cpu, ipinr);
@@ -712,3 +737,40 @@ static int __init register_cpufreq_notifier(void)
 core_initcall(register_cpufreq_notifier);
 
 #endif
+
+void arch_trigger_all_cpu_backtrace(bool include_self)
+{
+	static unsigned long backtrace_flag;
+	int i, cpu = get_cpu();
+
+	if (test_and_set_bit(0, &backtrace_flag)) {
+		/*
+		 * If there is already a trigger_all_cpu_backtrace() in progress
+		 * (backtrace_flag == 1), don't output double cpu dump infos.
+		 */
+		put_cpu();
+		return;
+	}
+
+	cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
+	if (!include_self)
+		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+
+	if (!cpumask_empty(to_cpumask(backtrace_mask))) {
+		pr_info("Sending FIQ to %s CPUs:\n",
+			(include_self ? "all" : "other"));
+		smp_cross_call(to_cpumask(backtrace_mask), IPI_CPU_BACKTRACE);
+	}
+
+	/* Wait for up to 10 seconds for all CPUs to do the backtrace */
+	for (i = 0; i < 10 * 1000; i++) {
+		if (cpumask_empty(to_cpumask(backtrace_mask)))
+			break;
+
+		mdelay(1);
+	}
+
+	clear_bit(0, &backtrace_flag);
+	smp_mb__after_atomic();
+	put_cpu();
+}
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 6/6] arm: smp: Handle ipi_cpu_backtrace() using FIQ (if available)
  2014-09-11 11:31                             ` Daniel Thompson
@ 2014-09-11 11:31                               ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-11 11:31 UTC (permalink / raw)
  To: Russell King
  Cc: Daniel Thompson, linux-kernel, linux-arm-kernel, patches,
	linaro-kernel, John Stultz, Thomas Gleixner, Sumit Semwal

Previous changes have introduced a replacement default FIQ handler and
an implementation of arch_trigger_all_cpu_backtrace for ARM but these
are currently independant.

This patch plumbs together these features making it possible, on platforms
that support it, to trigger backtrace using FIQ.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/smp.h | 3 +++
 arch/arm/kernel/smp.c      | 4 +++-
 arch/arm/kernel/traps.c    | 3 +++
 3 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2ec765c..0580270 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -18,6 +18,8 @@
 # error "<asm/smp.h> included in non-SMP build"
 #endif
 
+#define SMP_IPI_FIQ_MASK 0x0100
+
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
 struct seq_file;
@@ -85,6 +87,7 @@ extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
 
+extern void ipi_cpu_backtrace(struct pt_regs *regs);
 extern int register_ipi_completion(struct completion *completion, int cpu);
 
 struct smp_operations {
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 94959f9..7a79d11 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -543,7 +543,7 @@ static void ipi_cpu_stop(unsigned int cpu)
 		cpu_relax();
 }
 
-static void ipi_cpu_backtrace(struct pt_regs *regs)
+void ipi_cpu_backtrace(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
 
@@ -584,6 +584,8 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 	unsigned int cpu = smp_processor_id();
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
+	BUILD_BUG_ON(SMP_IPI_FIQ_MASK != BIT(IPI_CPU_BACKTRACE));
+
 	if ((unsigned)ipinr < NR_IPI) {
 		trace_ipi_entry(ipi_types[ipinr]);
 		__inc_irq_stat(cpu, ipi_irqs[ipinr]);
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 92c4ea1..40b1de7 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -483,6 +483,9 @@ asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
 #ifdef CONFIG_ARM_GIC
 	gic_handle_fiq_ipi();
 #endif
+#ifdef CONFIG_SMP
+	ipi_cpu_backtrace(regs);
+#endif
 
 	nmi_exit();
 
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 6/6] arm: smp: Handle ipi_cpu_backtrace() using FIQ (if available)
@ 2014-09-11 11:31                               ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-11 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

Previous changes have introduced a replacement default FIQ handler and
an implementation of arch_trigger_all_cpu_backtrace for ARM but these
are currently independant.

This patch plumbs together these features making it possible, on platforms
that support it, to trigger backtrace using FIQ.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 arch/arm/include/asm/smp.h | 3 +++
 arch/arm/kernel/smp.c      | 4 +++-
 arch/arm/kernel/traps.c    | 3 +++
 3 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2ec765c..0580270 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -18,6 +18,8 @@
 # error "<asm/smp.h> included in non-SMP build"
 #endif
 
+#define SMP_IPI_FIQ_MASK 0x0100
+
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
 struct seq_file;
@@ -85,6 +87,7 @@ extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
 
+extern void ipi_cpu_backtrace(struct pt_regs *regs);
 extern int register_ipi_completion(struct completion *completion, int cpu);
 
 struct smp_operations {
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 94959f9..7a79d11 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -543,7 +543,7 @@ static void ipi_cpu_stop(unsigned int cpu)
 		cpu_relax();
 }
 
-static void ipi_cpu_backtrace(struct pt_regs *regs)
+void ipi_cpu_backtrace(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
 
@@ -584,6 +584,8 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 	unsigned int cpu = smp_processor_id();
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
+	BUILD_BUG_ON(SMP_IPI_FIQ_MASK != BIT(IPI_CPU_BACKTRACE));
+
 	if ((unsigned)ipinr < NR_IPI) {
 		trace_ipi_entry(ipi_types[ipinr]);
 		__inc_irq_stat(cpu, ipi_irqs[ipinr]);
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 92c4ea1..40b1de7 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -483,6 +483,9 @@ asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
 #ifdef CONFIG_ARM_GIC
 	gic_handle_fiq_ipi();
 #endif
+#ifdef CONFIG_SMP
+	ipi_cpu_backtrace(regs);
+#endif
 
 	nmi_exit();
 
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* Re: [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
  2014-09-11 11:31                               ` Daniel Thompson
@ 2014-09-12 17:03                                 ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-12 17:03 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: linux-kernel, linux-arm-kernel, patches, linaro-kernel,
	John Stultz, Thomas Gleixner, Sumit Semwal, Catalin Marinas

On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
> -	.macro	svc_entry, stack_hole=0
> +	.macro	svc_entry, stack_hole=0, call_trace=1
>   UNWIND(.fnstart		)
>   UNWIND(.save {r0 - pc}		)
>  	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
> @@ -183,7 +183,9 @@ ENDPROC(__und_invalid)
>  	stmia	r7, {r2 - r6}
>  
>  #ifdef CONFIG_TRACE_IRQFLAGS
> +	.if \call_trace
>  	bl	trace_hardirqs_off
> +	.endif
>  #endif

Good, you picked this up from my patch.  But what about the call into
lockdep from usr_entry?

Yes, it should be safe if we're entering from user mode, because by
definition, the kernel can't be holding any locks at that point.
However, I'd much prefer to keep to a set of simple rules here: avoid
lockdep in FIQ code altogether.

That's much easier to understand than "we can call into lockdep provided
we've been entered from user mode".

The other thing you miss is that /potentially/ call into the scheduler
as well from a FIQ.  Do we /really/ want to do that kind of work here?

Not happy.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
@ 2014-09-12 17:03                                 ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-12 17:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
> -	.macro	svc_entry, stack_hole=0
> +	.macro	svc_entry, stack_hole=0, call_trace=1
>   UNWIND(.fnstart		)
>   UNWIND(.save {r0 - pc}		)
>  	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
> @@ -183,7 +183,9 @@ ENDPROC(__und_invalid)
>  	stmia	r7, {r2 - r6}
>  
>  #ifdef CONFIG_TRACE_IRQFLAGS
> +	.if \call_trace
>  	bl	trace_hardirqs_off
> +	.endif
>  #endif

Good, you picked this up from my patch.  But what about the call into
lockdep from usr_entry?

Yes, it should be safe if we're entering from user mode, because by
definition, the kernel can't be holding any locks at that point.
However, I'd much prefer to keep to a set of simple rules here: avoid
lockdep in FIQ code altogether.

That's much easier to understand than "we can call into lockdep provided
we've been entered from user mode".

The other thing you miss is that /potentially/ call into the scheduler
as well from a FIQ.  Do we /really/ want to do that kind of work here?

Not happy.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
  2014-09-12 17:03                                 ` Russell King - ARM Linux
@ 2014-09-12 17:07                                   ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-12 17:07 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: linaro-kernel, patches, Catalin Marinas, linux-kernel,
	John Stultz, Thomas Gleixner, Sumit Semwal, linux-arm-kernel

On Fri, Sep 12, 2014 at 06:03:07PM +0100, Russell King - ARM Linux wrote:
> On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
> > -	.macro	svc_entry, stack_hole=0
> > +	.macro	svc_entry, stack_hole=0, call_trace=1
> >   UNWIND(.fnstart		)
> >   UNWIND(.save {r0 - pc}		)
> >  	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
> > @@ -183,7 +183,9 @@ ENDPROC(__und_invalid)
> >  	stmia	r7, {r2 - r6}
> >  
> >  #ifdef CONFIG_TRACE_IRQFLAGS
> > +	.if \call_trace
> >  	bl	trace_hardirqs_off
> > +	.endif
> >  #endif
> 
> Good, you picked this up from my patch.  But what about the call into
> lockdep from usr_entry?
> 
> Yes, it should be safe if we're entering from user mode, because by
> definition, the kernel can't be holding any locks at that point.
> However, I'd much prefer to keep to a set of simple rules here: avoid
> lockdep in FIQ code altogether.
> 
> That's much easier to understand than "we can call into lockdep provided
> we've been entered from user mode".
> 
> The other thing you miss is that /potentially/ call into the scheduler
> as well from a FIQ.  Do we /really/ want to do that kind of work here?
> 
> Not happy.

And you're also missing a .cantunwind for __fiq_usr, which means that the
Dwarf doesn't contain an explicit point to stop unwinding.

Lastly, don't thread your new patches to the old ones.  I utterly hate
that behaviour.  It makes subject lines totally pointless because all
I end up seeing is "[PAT" on the very right hand of the screen.  Far
from useful.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
@ 2014-09-12 17:07                                   ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-12 17:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Sep 12, 2014 at 06:03:07PM +0100, Russell King - ARM Linux wrote:
> On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
> > -	.macro	svc_entry, stack_hole=0
> > +	.macro	svc_entry, stack_hole=0, call_trace=1
> >   UNWIND(.fnstart		)
> >   UNWIND(.save {r0 - pc}		)
> >  	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
> > @@ -183,7 +183,9 @@ ENDPROC(__und_invalid)
> >  	stmia	r7, {r2 - r6}
> >  
> >  #ifdef CONFIG_TRACE_IRQFLAGS
> > +	.if \call_trace
> >  	bl	trace_hardirqs_off
> > +	.endif
> >  #endif
> 
> Good, you picked this up from my patch.  But what about the call into
> lockdep from usr_entry?
> 
> Yes, it should be safe if we're entering from user mode, because by
> definition, the kernel can't be holding any locks at that point.
> However, I'd much prefer to keep to a set of simple rules here: avoid
> lockdep in FIQ code altogether.
> 
> That's much easier to understand than "we can call into lockdep provided
> we've been entered from user mode".
> 
> The other thing you miss is that /potentially/ call into the scheduler
> as well from a FIQ.  Do we /really/ want to do that kind of work here?
> 
> Not happy.

And you're also missing a .cantunwind for __fiq_usr, which means that the
Dwarf doesn't contain an explicit point to stop unwinding.

Lastly, don't thread your new patches to the old ones.  I utterly hate
that behaviour.  It makes subject lines totally pointless because all
I end up seeing is "[PAT" on the very right hand of the screen.  Far
from useful.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
  2014-09-11 11:31                               ` Daniel Thompson
@ 2014-09-12 17:08                                 ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-12 17:08 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: linux-kernel, linux-arm-kernel, patches, linaro-kernel,
	John Stultz, Thomas Gleixner, Sumit Semwal, Catalin Marinas

And another thing...

On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
> +	.align 5
> +__fiq_abt:
> +	svc_entry 0, 0

Right, so this function is called __fiq_abt.
...
> +	svc_exit_via_fiq
> + UNWIND(.fnend		)
> +ENDPROC(__fiq_svc)

Or is it called __fiq_svc ?

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
@ 2014-09-12 17:08                                 ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-12 17:08 UTC (permalink / raw)
  To: linux-arm-kernel

And another thing...

On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
> +	.align 5
> +__fiq_abt:
> +	svc_entry 0, 0

Right, so this function is called __fiq_abt.
...
> +	svc_exit_via_fiq
> + UNWIND(.fnend		)
> +ENDPROC(__fiq_svc)

Or is it called __fiq_svc ?

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
  2014-09-11 11:31                               ` Daniel Thompson
@ 2014-09-12 17:14                                 ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-12 17:14 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: linux-kernel, linux-arm-kernel, patches, linaro-kernel,
	John Stultz, Thomas Gleixner, Sumit Semwal, Catalin Marinas

On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
> This patch introduces a new default FIQ handler that is structured in a
> similar way to the existing ARM exception handler and result in the FIQ
> being handled by C code running on the SVC stack (despite this code run
> in the FIQ handler is subject to severe limitations with respect to
> locking making normal interaction with the kernel impossible).
> 
> This default handler allows concepts that on x86 would be handled using
> NMIs to be realized on ARM.

Okay, lastly... I sent you my version of this change, which contained
the changes I've detailed in the previous three emails, which are absent
from your version.

However, you've taken on board the "trace" thing to svc_entry, and
renamed it to "call_trace".

Now if I add this to usr_entry, "call_trace" doesn't make any sense,
nor does the .if/.endif placement because it's not just trace_hardirqs_off
which needs to be disabled there, but also ct_user_exit as well.

I'm beginning to wonder why I tried to be nice here... it would've been
a lot faster for me to take your patch, make my own changes and commit
that instead.

Frustrated.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
@ 2014-09-12 17:14                                 ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-12 17:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
> This patch introduces a new default FIQ handler that is structured in a
> similar way to the existing ARM exception handler and result in the FIQ
> being handled by C code running on the SVC stack (despite this code run
> in the FIQ handler is subject to severe limitations with respect to
> locking making normal interaction with the kernel impossible).
> 
> This default handler allows concepts that on x86 would be handled using
> NMIs to be realized on ARM.

Okay, lastly... I sent you my version of this change, which contained
the changes I've detailed in the previous three emails, which are absent
from your version.

However, you've taken on board the "trace" thing to svc_entry, and
renamed it to "call_trace".

Now if I add this to usr_entry, "call_trace" doesn't make any sense,
nor does the .if/.endif placement because it's not just trace_hardirqs_off
which needs to be disabled there, but also ct_user_exit as well.

I'm beginning to wonder why I tried to be nice here... it would've been
a lot faster for me to take your patch, make my own changes and commit
that instead.

Frustrated.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
  2014-09-12 17:14                                 ` Russell King - ARM Linux
@ 2014-09-12 17:19                                   ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-12 17:19 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: linaro-kernel, patches, Catalin Marinas, linux-kernel,
	John Stultz, Thomas Gleixner, Sumit Semwal, linux-arm-kernel

On Fri, Sep 12, 2014 at 06:14:04PM +0100, Russell King - ARM Linux wrote:
> On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
> > This patch introduces a new default FIQ handler that is structured in a
> > similar way to the existing ARM exception handler and result in the FIQ
> > being handled by C code running on the SVC stack (despite this code run
> > in the FIQ handler is subject to severe limitations with respect to
> > locking making normal interaction with the kernel impossible).
> > 
> > This default handler allows concepts that on x86 would be handled using
> > NMIs to be realized on ARM.
> 
> Okay, lastly... I sent you my version of this change, which contained
> the changes I've detailed in the previous three emails, which are absent
> from your version.
> 
> However, you've taken on board the "trace" thing to svc_entry, and
> renamed it to "call_trace".
> 
> Now if I add this to usr_entry, "call_trace" doesn't make any sense,
> nor does the .if/.endif placement because it's not just trace_hardirqs_off
> which needs to be disabled there, but also ct_user_exit as well.
> 
> I'm beginning to wonder why I tried to be nice here... it would've been
> a lot faster for me to take your patch, make my own changes and commit
> that instead.
> 
> Frustrated.

And another thing you're missing are the updates to arch/arm/kernel/fiq.c
to ensure that the FIQ registers are preserved when we restore this new
default FIQ handler.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
@ 2014-09-12 17:19                                   ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-12 17:19 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Sep 12, 2014 at 06:14:04PM +0100, Russell King - ARM Linux wrote:
> On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
> > This patch introduces a new default FIQ handler that is structured in a
> > similar way to the existing ARM exception handler and result in the FIQ
> > being handled by C code running on the SVC stack (despite this code run
> > in the FIQ handler is subject to severe limitations with respect to
> > locking making normal interaction with the kernel impossible).
> > 
> > This default handler allows concepts that on x86 would be handled using
> > NMIs to be realized on ARM.
> 
> Okay, lastly... I sent you my version of this change, which contained
> the changes I've detailed in the previous three emails, which are absent
> from your version.
> 
> However, you've taken on board the "trace" thing to svc_entry, and
> renamed it to "call_trace".
> 
> Now if I add this to usr_entry, "call_trace" doesn't make any sense,
> nor does the .if/.endif placement because it's not just trace_hardirqs_off
> which needs to be disabled there, but also ct_user_exit as well.
> 
> I'm beginning to wonder why I tried to be nice here... it would've been
> a lot faster for me to take your patch, make my own changes and commit
> that instead.
> 
> Frustrated.

And another thing you're missing are the updates to arch/arm/kernel/fiq.c
to ensure that the FIQ registers are preserved when we restore this new
default FIQ handler.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
  2014-09-12 17:19                                   ` Russell King - ARM Linux
@ 2014-09-12 17:23                                     ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-12 17:23 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: linaro-kernel, patches, Catalin Marinas, linux-kernel,
	John Stultz, Thomas Gleixner, Sumit Semwal, linux-arm-kernel

On Fri, Sep 12, 2014 at 06:19:08PM +0100, Russell King - ARM Linux wrote:
> On Fri, Sep 12, 2014 at 06:14:04PM +0100, Russell King - ARM Linux wrote:
> > On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
> > > This patch introduces a new default FIQ handler that is structured in a
> > > similar way to the existing ARM exception handler and result in the FIQ
> > > being handled by C code running on the SVC stack (despite this code run
> > > in the FIQ handler is subject to severe limitations with respect to
> > > locking making normal interaction with the kernel impossible).
> > > 
> > > This default handler allows concepts that on x86 would be handled using
> > > NMIs to be realized on ARM.
> > 
> > Okay, lastly... I sent you my version of this change, which contained
> > the changes I've detailed in the previous three emails, which are absent
> > from your version.
> > 
> > However, you've taken on board the "trace" thing to svc_entry, and
> > renamed it to "call_trace".
> > 
> > Now if I add this to usr_entry, "call_trace" doesn't make any sense,
> > nor does the .if/.endif placement because it's not just trace_hardirqs_off
> > which needs to be disabled there, but also ct_user_exit as well.
> > 
> > I'm beginning to wonder why I tried to be nice here... it would've been
> > a lot faster for me to take your patch, make my own changes and commit
> > that instead.
> > 
> > Frustrated.
> 
> And another thing you're missing are the updates to arch/arm/kernel/fiq.c
> to ensure that the FIQ registers are preserved when we restore this new
> default FIQ handler.

Right, here's my remaining delta from your patch addressing all the points
from the last five emails.  If you have any disagreements with any of these
changes, then please discuss rather than choosing to ignore them.

107e32b0b4ef5fa4191c9fc8415ca172b886e958
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 0c70fee9a7c9..3f6293ce0f2d 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -146,7 +146,7 @@ ENDPROC(__und_invalid)
 #define SPFIX(code...)
 #endif
 
-	.macro	svc_entry, stack_hole=0, call_trace=1
+	.macro	svc_entry, stack_hole=0, trace=1
  UNWIND(.fnstart		)
  UNWIND(.save {r0 - pc}		)
 	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
@@ -182,11 +182,11 @@ ENDPROC(__und_invalid)
 	@
 	stmia	r7, {r2 - r6}
 
+	.if \trace
 #ifdef CONFIG_TRACE_IRQFLAGS
-	.if \call_trace
 	bl	trace_hardirqs_off
-	.endif
 #endif
+	.endif
 	.endm
 
 	.align	5
@@ -298,7 +298,7 @@ ENDPROC(__pabt_svc)
 
 	.align	5
 __fiq_svc:
-	svc_entry 0, 0
+	svc_entry trace=0
 	mov	r0, sp				@ struct pt_regs *regs
 	bl	handle_fiq_as_nmi
 	svc_exit_via_fiq
@@ -326,7 +326,7 @@ ENDPROC(__fiq_svc)
 @
 	.align 5
 __fiq_abt:
-	svc_entry 0, 0
+	svc_entry trace=0
 
  ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
  THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
@@ -353,7 +353,7 @@ __fiq_abt:
 
 	svc_exit_via_fiq
  UNWIND(.fnend		)
-ENDPROC(__fiq_svc)
+ENDPROC(__fiq_abt)
 
 /*
  * User mode handlers
@@ -365,7 +365,7 @@ ENDPROC(__fiq_svc)
 #error "sizeof(struct pt_regs) must be a multiple of 8"
 #endif
 
-	.macro	usr_entry
+	.macro	usr_entry, trace=1
  UNWIND(.fnstart	)
  UNWIND(.cantunwind	)	@ don't unwind the user space
 	sub	sp, sp, #S_FRAME_SIZE
@@ -402,10 +402,12 @@ ENDPROC(__fiq_svc)
 	@
 	zero_fp
 
+	.if	\trace
 #ifdef CONFIG_IRQSOFF_TRACER
 	bl	trace_hardirqs_off
 #endif
 	ct_user_exit save = 0
+	.endif
 	.endm
 
 	.macro	kuser_cmpxchg_check
@@ -736,13 +738,13 @@ ENDPROC(ret_from_exception)
 
 	.align	5
 __fiq_usr:
-	usr_entry
+	usr_entry trace=0
 	kuser_cmpxchg_check
 	mov	r0, sp				@ struct pt_regs *regs
 	bl	handle_fiq_as_nmi
 	get_thread_info tsk
-	mov	why, #0
-	b	ret_to_user_from_irq
+	restore_user_regs fast = 0, offset = 0
+ UNWIND(.cantunwind	)
  UNWIND(.fnend		)
 ENDPROC(__fiq_usr)
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d96d5d..1743049c433b 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -53,6 +53,7 @@
 	})
 
 static unsigned long no_fiq_insn;
+static struct pt_regs def_fiq_regs;
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -60,8 +61,15 @@ static unsigned long no_fiq_insn;
  */
 static int fiq_def_op(void *ref, int relinquish)
 {
-	if (!relinquish)
+	if (!relinquish) {
+		/* Restore default handler and registers */
+		local_fiq_disable();
+		set_fiq_regs(&dfl_fiq_regs);
 		set_fiq_handler(&no_fiq_insn, sizeof(no_fiq_insn));
+		local_fiq_enable();
+
+		/* FIXME: notify irq controller to standard enable FIQs */
+	}
 
 	return 0;
 }
@@ -151,5 +159,6 @@ void __init init_FIQ(int start)
 {
 	unsigned offset = FIQ_OFFSET;
 	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
+	get_fiq_regs(&dfl_fiq_regs);
 	fiq_start = start;
 }


-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
@ 2014-09-12 17:23                                     ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-12 17:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Sep 12, 2014 at 06:19:08PM +0100, Russell King - ARM Linux wrote:
> On Fri, Sep 12, 2014 at 06:14:04PM +0100, Russell King - ARM Linux wrote:
> > On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
> > > This patch introduces a new default FIQ handler that is structured in a
> > > similar way to the existing ARM exception handler and result in the FIQ
> > > being handled by C code running on the SVC stack (despite this code run
> > > in the FIQ handler is subject to severe limitations with respect to
> > > locking making normal interaction with the kernel impossible).
> > > 
> > > This default handler allows concepts that on x86 would be handled using
> > > NMIs to be realized on ARM.
> > 
> > Okay, lastly... I sent you my version of this change, which contained
> > the changes I've detailed in the previous three emails, which are absent
> > from your version.
> > 
> > However, you've taken on board the "trace" thing to svc_entry, and
> > renamed it to "call_trace".
> > 
> > Now if I add this to usr_entry, "call_trace" doesn't make any sense,
> > nor does the .if/.endif placement because it's not just trace_hardirqs_off
> > which needs to be disabled there, but also ct_user_exit as well.
> > 
> > I'm beginning to wonder why I tried to be nice here... it would've been
> > a lot faster for me to take your patch, make my own changes and commit
> > that instead.
> > 
> > Frustrated.
> 
> And another thing you're missing are the updates to arch/arm/kernel/fiq.c
> to ensure that the FIQ registers are preserved when we restore this new
> default FIQ handler.

Right, here's my remaining delta from your patch addressing all the points
from the last five emails.  If you have any disagreements with any of these
changes, then please discuss rather than choosing to ignore them.

107e32b0b4ef5fa4191c9fc8415ca172b886e958
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 0c70fee9a7c9..3f6293ce0f2d 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -146,7 +146,7 @@ ENDPROC(__und_invalid)
 #define SPFIX(code...)
 #endif
 
-	.macro	svc_entry, stack_hole=0, call_trace=1
+	.macro	svc_entry, stack_hole=0, trace=1
  UNWIND(.fnstart		)
  UNWIND(.save {r0 - pc}		)
 	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
@@ -182,11 +182,11 @@ ENDPROC(__und_invalid)
 	@
 	stmia	r7, {r2 - r6}
 
+	.if \trace
 #ifdef CONFIG_TRACE_IRQFLAGS
-	.if \call_trace
 	bl	trace_hardirqs_off
-	.endif
 #endif
+	.endif
 	.endm
 
 	.align	5
@@ -298,7 +298,7 @@ ENDPROC(__pabt_svc)
 
 	.align	5
 __fiq_svc:
-	svc_entry 0, 0
+	svc_entry trace=0
 	mov	r0, sp				@ struct pt_regs *regs
 	bl	handle_fiq_as_nmi
 	svc_exit_via_fiq
@@ -326,7 +326,7 @@ ENDPROC(__fiq_svc)
 @
 	.align 5
 __fiq_abt:
-	svc_entry 0, 0
+	svc_entry trace=0
 
  ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
  THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
@@ -353,7 +353,7 @@ __fiq_abt:
 
 	svc_exit_via_fiq
  UNWIND(.fnend		)
-ENDPROC(__fiq_svc)
+ENDPROC(__fiq_abt)
 
 /*
  * User mode handlers
@@ -365,7 +365,7 @@ ENDPROC(__fiq_svc)
 #error "sizeof(struct pt_regs) must be a multiple of 8"
 #endif
 
-	.macro	usr_entry
+	.macro	usr_entry, trace=1
  UNWIND(.fnstart	)
  UNWIND(.cantunwind	)	@ don't unwind the user space
 	sub	sp, sp, #S_FRAME_SIZE
@@ -402,10 +402,12 @@ ENDPROC(__fiq_svc)
 	@
 	zero_fp
 
+	.if	\trace
 #ifdef CONFIG_IRQSOFF_TRACER
 	bl	trace_hardirqs_off
 #endif
 	ct_user_exit save = 0
+	.endif
 	.endm
 
 	.macro	kuser_cmpxchg_check
@@ -736,13 +738,13 @@ ENDPROC(ret_from_exception)
 
 	.align	5
 __fiq_usr:
-	usr_entry
+	usr_entry trace=0
 	kuser_cmpxchg_check
 	mov	r0, sp				@ struct pt_regs *regs
 	bl	handle_fiq_as_nmi
 	get_thread_info tsk
-	mov	why, #0
-	b	ret_to_user_from_irq
+	restore_user_regs fast = 0, offset = 0
+ UNWIND(.cantunwind	)
  UNWIND(.fnend		)
 ENDPROC(__fiq_usr)
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 918875d96d5d..1743049c433b 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -53,6 +53,7 @@
 	})
 
 static unsigned long no_fiq_insn;
+static struct pt_regs def_fiq_regs;
 
 /* Default reacquire function
  * - we always relinquish FIQ control
@@ -60,8 +61,15 @@ static unsigned long no_fiq_insn;
  */
 static int fiq_def_op(void *ref, int relinquish)
 {
-	if (!relinquish)
+	if (!relinquish) {
+		/* Restore default handler and registers */
+		local_fiq_disable();
+		set_fiq_regs(&dfl_fiq_regs);
 		set_fiq_handler(&no_fiq_insn, sizeof(no_fiq_insn));
+		local_fiq_enable();
+
+		/* FIXME: notify irq controller to standard enable FIQs */
+	}
 
 	return 0;
 }
@@ -151,5 +159,6 @@ void __init init_FIQ(int start)
 {
 	unsigned offset = FIQ_OFFSET;
 	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
+	get_fiq_regs(&dfl_fiq_regs);
 	fiq_start = start;
 }


-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply related	[flat|nested] 535+ messages in thread

* Re: [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
  2014-09-12 17:03                                 ` Russell King - ARM Linux
@ 2014-09-13 12:01                                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-13 12:01 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linux-kernel, linux-arm-kernel, patches, linaro-kernel,
	John Stultz, Thomas Gleixner, Sumit Semwal, Catalin Marinas

On 12/09/14 18:03, Russell King - ARM Linux wrote:
> On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
>> -	.macro	svc_entry, stack_hole=0
>> +	.macro	svc_entry, stack_hole=0, call_trace=1
>>   UNWIND(.fnstart		)
>>   UNWIND(.save {r0 - pc}		)
>>  	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
>> @@ -183,7 +183,9 @@ ENDPROC(__und_invalid)
>>  	stmia	r7, {r2 - r6}
>>  
>>  #ifdef CONFIG_TRACE_IRQFLAGS
>> +	.if \call_trace
>>  	bl	trace_hardirqs_off
>> +	.endif
>>  #endif
> 
> Good, you picked this up from my patch.  But what about the call into
> lockdep from usr_entry?

That was writen from your review comment rather than taken from your patch.

> Yes, it should be safe if we're entering from user mode, because by
> definition, the kernel can't be holding any locks at that point.
> However, I'd much prefer to keep to a set of simple rules here: avoid
> lockdep in FIQ code altogether.

Ok. You're right that I followed the "can't be holding any locks" logic
when I didn't update usr_entry in reaction to the original review comment.

I'm also happy with the "avoid lockdep in FIQ code altogether" approach.
I'll do this.

> That's much easier to understand than "we can call into lockdep provided
> we've been entered from user mode".
> 
> The other thing you miss is that /potentially/ call into the scheduler
> as well from a FIQ.  Do we /really/ want to do that kind of work here?
> 
> Not happy.

Sorry. I will fix these.


Daniel.



^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
@ 2014-09-13 12:01                                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-13 12:01 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/09/14 18:03, Russell King - ARM Linux wrote:
> On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
>> -	.macro	svc_entry, stack_hole=0
>> +	.macro	svc_entry, stack_hole=0, call_trace=1
>>   UNWIND(.fnstart		)
>>   UNWIND(.save {r0 - pc}		)
>>  	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
>> @@ -183,7 +183,9 @@ ENDPROC(__und_invalid)
>>  	stmia	r7, {r2 - r6}
>>  
>>  #ifdef CONFIG_TRACE_IRQFLAGS
>> +	.if \call_trace
>>  	bl	trace_hardirqs_off
>> +	.endif
>>  #endif
> 
> Good, you picked this up from my patch.  But what about the call into
> lockdep from usr_entry?

That was writen from your review comment rather than taken from your patch.

> Yes, it should be safe if we're entering from user mode, because by
> definition, the kernel can't be holding any locks at that point.
> However, I'd much prefer to keep to a set of simple rules here: avoid
> lockdep in FIQ code altogether.

Ok. You're right that I followed the "can't be holding any locks" logic
when I didn't update usr_entry in reaction to the original review comment.

I'm also happy with the "avoid lockdep in FIQ code altogether" approach.
I'll do this.

> That's much easier to understand than "we can call into lockdep provided
> we've been entered from user mode".
> 
> The other thing you miss is that /potentially/ call into the scheduler
> as well from a FIQ.  Do we /really/ want to do that kind of work here?
> 
> Not happy.

Sorry. I will fix these.


Daniel.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
  2014-09-12 17:14                                 ` Russell King - ARM Linux
@ 2014-09-13 12:03                                   ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-13 12:03 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linux-kernel, linux-arm-kernel, patches, linaro-kernel,
	John Stultz, Thomas Gleixner, Sumit Semwal, Catalin Marinas

On 12/09/14 18:14, Russell King - ARM Linux wrote:
> On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
>> This patch introduces a new default FIQ handler that is structured in a
>> similar way to the existing ARM exception handler and result in the FIQ
>> being handled by C code running on the SVC stack (despite this code run
>> in the FIQ handler is subject to severe limitations with respect to
>> locking making normal interaction with the kernel impossible).
>>
>> This default handler allows concepts that on x86 would be handled using
>> NMIs to be realized on ARM.
> 
> Okay, lastly... I sent you my version of this change, which contained
> the changes I've detailed in the previous three emails, which are absent
> from your version.
> 
> However, you've taken on board the "trace" thing to svc_entry, and
> renamed it to "call_trace".
> 
> Now if I add this to usr_entry, "call_trace" doesn't make any sense,
> nor does the .if/.endif placement because it's not just trace_hardirqs_off
> which needs to be disabled there, but also ct_user_exit as well.
> 
> I'm beginning to wonder why I tried to be nice here... it would've been
> a lot faster for me to take your patch, make my own changes and commit
> that instead.

I did not do a side by side diff of your FYI patch with my current code
and hence overlooked all these changes.

Sorry. I should have done that.


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
@ 2014-09-13 12:03                                   ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-13 12:03 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/09/14 18:14, Russell King - ARM Linux wrote:
> On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
>> This patch introduces a new default FIQ handler that is structured in a
>> similar way to the existing ARM exception handler and result in the FIQ
>> being handled by C code running on the SVC stack (despite this code run
>> in the FIQ handler is subject to severe limitations with respect to
>> locking making normal interaction with the kernel impossible).
>>
>> This default handler allows concepts that on x86 would be handled using
>> NMIs to be realized on ARM.
> 
> Okay, lastly... I sent you my version of this change, which contained
> the changes I've detailed in the previous three emails, which are absent
> from your version.
> 
> However, you've taken on board the "trace" thing to svc_entry, and
> renamed it to "call_trace".
> 
> Now if I add this to usr_entry, "call_trace" doesn't make any sense,
> nor does the .if/.endif placement because it's not just trace_hardirqs_off
> which needs to be disabled there, but also ct_user_exit as well.
> 
> I'm beginning to wonder why I tried to be nice here... it would've been
> a lot faster for me to take your patch, make my own changes and commit
> that instead.

I did not do a side by side diff of your FYI patch with my current code
and hence overlooked all these changes.

Sorry. I should have done that.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
  2014-09-12 17:23                                     ` Russell King - ARM Linux
@ 2014-09-14  6:36                                       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-14  6:36 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linaro-kernel, patches, Catalin Marinas, linux-kernel,
	John Stultz, Thomas Gleixner, Sumit Semwal, linux-arm-kernel

On 12/09/14 18:23, Russell King - ARM Linux wrote:
> On Fri, Sep 12, 2014 at 06:19:08PM +0100, Russell King - ARM Linux wrote:
>> On Fri, Sep 12, 2014 at 06:14:04PM +0100, Russell King - ARM Linux wrote:
>>> On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
>>>> This patch introduces a new default FIQ handler that is structured in a
>>>> similar way to the existing ARM exception handler and result in the FIQ
>>>> being handled by C code running on the SVC stack (despite this code run
>>>> in the FIQ handler is subject to severe limitations with respect to
>>>> locking making normal interaction with the kernel impossible).
>>>>
>>>> This default handler allows concepts that on x86 would be handled using
>>>> NMIs to be realized on ARM.
>>>
>>> Okay, lastly... I sent you my version of this change, which contained
>>> the changes I've detailed in the previous three emails, which are absent
>>> from your version.
>>>
>>> However, you've taken on board the "trace" thing to svc_entry, and
>>> renamed it to "call_trace".
>>>
>>> Now if I add this to usr_entry, "call_trace" doesn't make any sense,
>>> nor does the .if/.endif placement because it's not just trace_hardirqs_off
>>> which needs to be disabled there, but also ct_user_exit as well.
>>>
>>> I'm beginning to wonder why I tried to be nice here... it would've been
>>> a lot faster for me to take your patch, make my own changes and commit
>>> that instead.
>>>
>>> Frustrated.
>>
>> And another thing you're missing are the updates to arch/arm/kernel/fiq.c
>> to ensure that the FIQ registers are preserved when we restore this new
>> default FIQ handler.
> 
> Right, here's my remaining delta from your patch addressing all the points
> from the last five emails.  If you have any disagreements with any of these
> changes, then please discuss rather than choosing to ignore them.

Thanks for the diff.


> 107e32b0b4ef5fa4191c9fc8415ca172b886e958
> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> index 0c70fee9a7c9..3f6293ce0f2d 100644
> --- a/arch/arm/kernel/entry-armv.S
> +++ b/arch/arm/kernel/entry-armv.S
> @@ -146,7 +146,7 @@ ENDPROC(__und_invalid)
>  #define SPFIX(code...)
>  #endif
>  
> -	.macro	svc_entry, stack_hole=0, call_trace=1
> +	.macro	svc_entry, stack_hole=0, trace=1
>   UNWIND(.fnstart		)
>   UNWIND(.save {r0 - pc}		)
>  	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
> @@ -182,11 +182,11 @@ ENDPROC(__und_invalid)
>  	@
>  	stmia	r7, {r2 - r6}
>  
> +	.if \trace
>  #ifdef CONFIG_TRACE_IRQFLAGS
> -	.if \call_trace
>  	bl	trace_hardirqs_off
> -	.endif
>  #endif
> +	.endif
>  	.endm
>  
>  	.align	5
> @@ -298,7 +298,7 @@ ENDPROC(__pabt_svc)
>  
>  	.align	5
>  __fiq_svc:
> -	svc_entry 0, 0
> +	svc_entry trace=0
>  	mov	r0, sp				@ struct pt_regs *regs
>  	bl	handle_fiq_as_nmi
>  	svc_exit_via_fiq
> @@ -326,7 +326,7 @@ ENDPROC(__fiq_svc)
>  @
>  	.align 5
>  __fiq_abt:
> -	svc_entry 0, 0
> +	svc_entry trace=0
>  
>   ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
>   THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
> @@ -353,7 +353,7 @@ __fiq_abt:
>  
>  	svc_exit_via_fiq
>   UNWIND(.fnend		)
> -ENDPROC(__fiq_svc)
> +ENDPROC(__fiq_abt)
>  
>  /*
>   * User mode handlers
> @@ -365,7 +365,7 @@ ENDPROC(__fiq_svc)
>  #error "sizeof(struct pt_regs) must be a multiple of 8"
>  #endif
>  
> -	.macro	usr_entry
> +	.macro	usr_entry, trace=1
>   UNWIND(.fnstart	)
>   UNWIND(.cantunwind	)	@ don't unwind the user space
>  	sub	sp, sp, #S_FRAME_SIZE
> @@ -402,10 +402,12 @@ ENDPROC(__fiq_svc)
>  	@
>  	zero_fp
>  
> +	.if	\trace
>  #ifdef CONFIG_IRQSOFF_TRACER
>  	bl	trace_hardirqs_off
>  #endif
>  	ct_user_exit save = 0
> +	.endif
>  	.endm
>  
>  	.macro	kuser_cmpxchg_check
> @@ -736,13 +738,13 @@ ENDPROC(ret_from_exception)
>  
>  	.align	5
>  __fiq_usr:
> -	usr_entry
> +	usr_entry trace=0
>  	kuser_cmpxchg_check
>  	mov	r0, sp				@ struct pt_regs *regs
>  	bl	handle_fiq_as_nmi
>  	get_thread_info tsk
> -	mov	why, #0
> -	b	ret_to_user_from_irq
> +	restore_user_regs fast = 0, offset = 0
> + UNWIND(.cantunwind	)
>   UNWIND(.fnend		)
>  ENDPROC(__fiq_usr)
>  
> diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
> index 918875d96d5d..1743049c433b 100644
> --- a/arch/arm/kernel/fiq.c
> +++ b/arch/arm/kernel/fiq.c
> @@ -53,6 +53,7 @@
>  	})
>  
>  static unsigned long no_fiq_insn;
> +static struct pt_regs def_fiq_regs;
>  
>  /* Default reacquire function
>   * - we always relinquish FIQ control
> @@ -60,8 +61,15 @@ static unsigned long no_fiq_insn;
>   */
>  static int fiq_def_op(void *ref, int relinquish)
>  {
> -	if (!relinquish)
> +	if (!relinquish) {
> +		/* Restore default handler and registers */
> +		local_fiq_disable();
> +		set_fiq_regs(&dfl_fiq_regs);

This variable was declared as def_fiq_regs .


>  		set_fiq_handler(&no_fiq_insn, sizeof(no_fiq_insn));
> +		local_fiq_enable();
> +
> +		/* FIXME: notify irq controller to standard enable FIQs */

I don't understand what we need to tell the irq controller at this point.

If we do want to mask sources of FIQ from arch code then in the case of
IPI_CPU_BACKTRACE we might be better off disabling it at point of
generation than at the interrupt controller (to avoid the long timeout).


> +	}
>  
>  	return 0;
>  }
> @@ -151,5 +159,6 @@ void __init init_FIQ(int start)
>  {
>  	unsigned offset = FIQ_OFFSET;
>  	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
> +	get_fiq_regs(&dfl_fiq_regs);
>  	fiq_start = start;
>  }
> 
> 


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
@ 2014-09-14  6:36                                       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-14  6:36 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/09/14 18:23, Russell King - ARM Linux wrote:
> On Fri, Sep 12, 2014 at 06:19:08PM +0100, Russell King - ARM Linux wrote:
>> On Fri, Sep 12, 2014 at 06:14:04PM +0100, Russell King - ARM Linux wrote:
>>> On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
>>>> This patch introduces a new default FIQ handler that is structured in a
>>>> similar way to the existing ARM exception handler and result in the FIQ
>>>> being handled by C code running on the SVC stack (despite this code run
>>>> in the FIQ handler is subject to severe limitations with respect to
>>>> locking making normal interaction with the kernel impossible).
>>>>
>>>> This default handler allows concepts that on x86 would be handled using
>>>> NMIs to be realized on ARM.
>>>
>>> Okay, lastly... I sent you my version of this change, which contained
>>> the changes I've detailed in the previous three emails, which are absent
>>> from your version.
>>>
>>> However, you've taken on board the "trace" thing to svc_entry, and
>>> renamed it to "call_trace".
>>>
>>> Now if I add this to usr_entry, "call_trace" doesn't make any sense,
>>> nor does the .if/.endif placement because it's not just trace_hardirqs_off
>>> which needs to be disabled there, but also ct_user_exit as well.
>>>
>>> I'm beginning to wonder why I tried to be nice here... it would've been
>>> a lot faster for me to take your patch, make my own changes and commit
>>> that instead.
>>>
>>> Frustrated.
>>
>> And another thing you're missing are the updates to arch/arm/kernel/fiq.c
>> to ensure that the FIQ registers are preserved when we restore this new
>> default FIQ handler.
> 
> Right, here's my remaining delta from your patch addressing all the points
> from the last five emails.  If you have any disagreements with any of these
> changes, then please discuss rather than choosing to ignore them.

Thanks for the diff.


> 107e32b0b4ef5fa4191c9fc8415ca172b886e958
> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> index 0c70fee9a7c9..3f6293ce0f2d 100644
> --- a/arch/arm/kernel/entry-armv.S
> +++ b/arch/arm/kernel/entry-armv.S
> @@ -146,7 +146,7 @@ ENDPROC(__und_invalid)
>  #define SPFIX(code...)
>  #endif
>  
> -	.macro	svc_entry, stack_hole=0, call_trace=1
> +	.macro	svc_entry, stack_hole=0, trace=1
>   UNWIND(.fnstart		)
>   UNWIND(.save {r0 - pc}		)
>  	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
> @@ -182,11 +182,11 @@ ENDPROC(__und_invalid)
>  	@
>  	stmia	r7, {r2 - r6}
>  
> +	.if \trace
>  #ifdef CONFIG_TRACE_IRQFLAGS
> -	.if \call_trace
>  	bl	trace_hardirqs_off
> -	.endif
>  #endif
> +	.endif
>  	.endm
>  
>  	.align	5
> @@ -298,7 +298,7 @@ ENDPROC(__pabt_svc)
>  
>  	.align	5
>  __fiq_svc:
> -	svc_entry 0, 0
> +	svc_entry trace=0
>  	mov	r0, sp				@ struct pt_regs *regs
>  	bl	handle_fiq_as_nmi
>  	svc_exit_via_fiq
> @@ -326,7 +326,7 @@ ENDPROC(__fiq_svc)
>  @
>  	.align 5
>  __fiq_abt:
> -	svc_entry 0, 0
> +	svc_entry trace=0
>  
>   ARM(	msr	cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
>   THUMB( mov	r0, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
> @@ -353,7 +353,7 @@ __fiq_abt:
>  
>  	svc_exit_via_fiq
>   UNWIND(.fnend		)
> -ENDPROC(__fiq_svc)
> +ENDPROC(__fiq_abt)
>  
>  /*
>   * User mode handlers
> @@ -365,7 +365,7 @@ ENDPROC(__fiq_svc)
>  #error "sizeof(struct pt_regs) must be a multiple of 8"
>  #endif
>  
> -	.macro	usr_entry
> +	.macro	usr_entry, trace=1
>   UNWIND(.fnstart	)
>   UNWIND(.cantunwind	)	@ don't unwind the user space
>  	sub	sp, sp, #S_FRAME_SIZE
> @@ -402,10 +402,12 @@ ENDPROC(__fiq_svc)
>  	@
>  	zero_fp
>  
> +	.if	\trace
>  #ifdef CONFIG_IRQSOFF_TRACER
>  	bl	trace_hardirqs_off
>  #endif
>  	ct_user_exit save = 0
> +	.endif
>  	.endm
>  
>  	.macro	kuser_cmpxchg_check
> @@ -736,13 +738,13 @@ ENDPROC(ret_from_exception)
>  
>  	.align	5
>  __fiq_usr:
> -	usr_entry
> +	usr_entry trace=0
>  	kuser_cmpxchg_check
>  	mov	r0, sp				@ struct pt_regs *regs
>  	bl	handle_fiq_as_nmi
>  	get_thread_info tsk
> -	mov	why, #0
> -	b	ret_to_user_from_irq
> +	restore_user_regs fast = 0, offset = 0
> + UNWIND(.cantunwind	)
>   UNWIND(.fnend		)
>  ENDPROC(__fiq_usr)
>  
> diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
> index 918875d96d5d..1743049c433b 100644
> --- a/arch/arm/kernel/fiq.c
> +++ b/arch/arm/kernel/fiq.c
> @@ -53,6 +53,7 @@
>  	})
>  
>  static unsigned long no_fiq_insn;
> +static struct pt_regs def_fiq_regs;
>  
>  /* Default reacquire function
>   * - we always relinquish FIQ control
> @@ -60,8 +61,15 @@ static unsigned long no_fiq_insn;
>   */
>  static int fiq_def_op(void *ref, int relinquish)
>  {
> -	if (!relinquish)
> +	if (!relinquish) {
> +		/* Restore default handler and registers */
> +		local_fiq_disable();
> +		set_fiq_regs(&dfl_fiq_regs);

This variable was declared as def_fiq_regs .


>  		set_fiq_handler(&no_fiq_insn, sizeof(no_fiq_insn));
> +		local_fiq_enable();
> +
> +		/* FIXME: notify irq controller to standard enable FIQs */

I don't understand what we need to tell the irq controller at this point.

If we do want to mask sources of FIQ from arch code then in the case of
IPI_CPU_BACKTRACE we might be better off disabling it at point of
generation than at the interrupt controller (to avoid the long timeout).


> +	}
>  
>  	return 0;
>  }
> @@ -151,5 +159,6 @@ void __init init_FIQ(int start)
>  {
>  	unsigned offset = FIQ_OFFSET;
>  	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
> +	get_fiq_regs(&dfl_fiq_regs);
>  	fiq_start = start;
>  }
> 
> 

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
  2014-09-14  6:36                                       ` Daniel Thompson
@ 2014-09-14  8:45                                         ` Russell King - ARM Linux
  -1 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-14  8:45 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: linaro-kernel, patches, Catalin Marinas, linux-kernel,
	John Stultz, Thomas Gleixner, Sumit Semwal, linux-arm-kernel

On Sun, Sep 14, 2014 at 07:36:31AM +0100, Daniel Thompson wrote:
> > -	if (!relinquish)
> > +	if (!relinquish) {
> > +		/* Restore default handler and registers */
> > +		local_fiq_disable();
> > +		set_fiq_regs(&dfl_fiq_regs);
> 
> This variable was declared as def_fiq_regs .

Yep.

> >  		set_fiq_handler(&no_fiq_insn, sizeof(no_fiq_insn));
> > +		local_fiq_enable();
> > +
> > +		/* FIXME: notify irq controller to standard enable FIQs */
> 
> I don't understand what we need to tell the irq controller at this point.
> 
> If we do want to mask sources of FIQ from arch code then in the case of
> IPI_CPU_BACKTRACE we might be better off disabling it at point of
> generation than at the interrupt controller (to avoid the long timeout).

The point is, when a platform decides that it wants to insert its own
/fast/ interrupt handler into the vector, our default one is moved out
of the way.  Those fast interrupt handlers assume that they are the
only user of FIQ (since only one fast interrupt handler routine can be
in place at any one time.)  So, it's not going to expect to receive any
other FIQs other than the one(s) it's written for.

So, when the platform gives up the FIQ vector, and we restore the
default FIQ code, we need to make sure that the FIQ sources for that
code are re-enabled.

Yes, you may not like this, and you may want to turn FIQ into a sprawling
mess with interrupt source demux and such like, but that's not really on.
The clue is in the name.  *Fast*.  On certain platforms, it gets used for
time critical activities, and it being low latency is an absolute must.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
@ 2014-09-14  8:45                                         ` Russell King - ARM Linux
  0 siblings, 0 replies; 535+ messages in thread
From: Russell King - ARM Linux @ 2014-09-14  8:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Sep 14, 2014 at 07:36:31AM +0100, Daniel Thompson wrote:
> > -	if (!relinquish)
> > +	if (!relinquish) {
> > +		/* Restore default handler and registers */
> > +		local_fiq_disable();
> > +		set_fiq_regs(&dfl_fiq_regs);
> 
> This variable was declared as def_fiq_regs .

Yep.

> >  		set_fiq_handler(&no_fiq_insn, sizeof(no_fiq_insn));
> > +		local_fiq_enable();
> > +
> > +		/* FIXME: notify irq controller to standard enable FIQs */
> 
> I don't understand what we need to tell the irq controller at this point.
> 
> If we do want to mask sources of FIQ from arch code then in the case of
> IPI_CPU_BACKTRACE we might be better off disabling it at point of
> generation than at the interrupt controller (to avoid the long timeout).

The point is, when a platform decides that it wants to insert its own
/fast/ interrupt handler into the vector, our default one is moved out
of the way.  Those fast interrupt handlers assume that they are the
only user of FIQ (since only one fast interrupt handler routine can be
in place at any one time.)  So, it's not going to expect to receive any
other FIQs other than the one(s) it's written for.

So, when the platform gives up the FIQ vector, and we restore the
default FIQ code, we need to make sure that the FIQ sources for that
code are re-enabled.

Yes, you may not like this, and you may want to turn FIQ into a sprawling
mess with interrupt source demux and such like, but that's not really on.
The clue is in the name.  *Fast*.  On certain platforms, it gets used for
time critical activities, and it being low latency is an absolute must.

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
  2014-09-12 17:23                                     ` Russell King - ARM Linux
@ 2014-09-14 11:27                                       ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-14 11:27 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linaro-kernel, patches, Catalin Marinas, linux-kernel,
	John Stultz, Thomas Gleixner, Sumit Semwal, linux-arm-kernel

On 12/09/14 18:23, Russell King - ARM Linux wrote:
> On Fri, Sep 12, 2014 at 06:19:08PM +0100, Russell King - ARM Linux wrote:
>> On Fri, Sep 12, 2014 at 06:14:04PM +0100, Russell King - ARM Linux wrote:
>>> On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
>>>> This patch introduces a new default FIQ handler that is structured in a
>>>> similar way to the existing ARM exception handler and result in the FIQ
>>>> being handled by C code running on the SVC stack (despite this code run
>>>> in the FIQ handler is subject to severe limitations with respect to
>>>> locking making normal interaction with the kernel impossible).
>>>>
>>>> This default handler allows concepts that on x86 would be handled using
>>>> NMIs to be realized on ARM.
>>>
>>> Okay, lastly... I sent you my version of this change, which contained
>>> the changes I've detailed in the previous three emails, which are absent
>>> from your version.
>>>
>>> However, you've taken on board the "trace" thing to svc_entry, and
>>> renamed it to "call_trace".
>>>
>>> Now if I add this to usr_entry, "call_trace" doesn't make any sense,
>>> nor does the .if/.endif placement because it's not just trace_hardirqs_off
>>> which needs to be disabled there, but also ct_user_exit as well.
>>>
>>> I'm beginning to wonder why I tried to be nice here... it would've been
>>> a lot faster for me to take your patch, make my own changes and commit
>>> that instead.
>>>
>>> Frustrated.
>>
>> And another thing you're missing are the updates to arch/arm/kernel/fiq.c
>> to ensure that the FIQ registers are preserved when we restore this new
>> default FIQ handler.
> 
> Right, here's my remaining delta from your patch addressing all the points
> from the last five emails.  If you have any disagreements with any of these
> changes, then please discuss rather than choosing to ignore them.
> 
> 107e32b0b4ef5fa4191c9fc8415ca172b886e958
> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> index 0c70fee9a7c9..3f6293ce0f2d 100644
> --- a/arch/arm/kernel/entry-armv.S
> +++ b/arch/arm/kernel/entry-armv.S
> <snip>
> @@ -736,13 +738,13 @@ ENDPROC(ret_from_exception)
>  
>  	.align	5
>  __fiq_usr:
> -	usr_entry
> +	usr_entry trace=0
>  	kuser_cmpxchg_check
>  	mov	r0, sp				@ struct pt_regs *regs
>  	bl	handle_fiq_as_nmi
>  	get_thread_info tsk
> -	mov	why, #0
> -	b	ret_to_user_from_irq
> +	restore_user_regs fast = 0, offset = 0
> + UNWIND(.cantunwind	)

.cantunwind is already provided by the usr_entry macro (also adding
.cantunwind here causes my assembler (2.24) to fail).


>   UNWIND(.fnend		)
>  ENDPROC(__fiq_usr)
>  
> diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
> index 918875d96d5d..1743049c433b 100644
> --- a/arch/arm/kernel/fiq.c
> +++ b/arch/arm/kernel/fiq.c
> @@ -53,6 +53,7 @@
>  	})
>  
>  static unsigned long no_fiq_insn;
> +static struct pt_regs def_fiq_regs;
>  
>  /* Default reacquire function
>   * - we always relinquish FIQ control
> @@ -60,8 +61,15 @@ static unsigned long no_fiq_insn;
>   */
>  static int fiq_def_op(void *ref, int relinquish)
>  {
> -	if (!relinquish)
> +	if (!relinquish) {
> +		/* Restore default handler and registers */
> +		local_fiq_disable();
> +		set_fiq_regs(&dfl_fiq_regs);
>  		set_fiq_handler(&no_fiq_insn, sizeof(no_fiq_insn));
> +		local_fiq_enable();
> +
> +		/* FIXME: notify irq controller to standard enable FIQs */
> +	}
>  
>  	return 0;
>  }
> @@ -151,5 +159,6 @@ void __init init_FIQ(int start)
>  {
>  	unsigned offset = FIQ_OFFSET;
>  	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
> +	get_fiq_regs(&dfl_fiq_regs);
>  	fiq_start = start;
>  }
> 
> 


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler
@ 2014-09-14 11:27                                       ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-14 11:27 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/09/14 18:23, Russell King - ARM Linux wrote:
> On Fri, Sep 12, 2014 at 06:19:08PM +0100, Russell King - ARM Linux wrote:
>> On Fri, Sep 12, 2014 at 06:14:04PM +0100, Russell King - ARM Linux wrote:
>>> On Thu, Sep 11, 2014 at 12:31:14PM +0100, Daniel Thompson wrote:
>>>> This patch introduces a new default FIQ handler that is structured in a
>>>> similar way to the existing ARM exception handler and result in the FIQ
>>>> being handled by C code running on the SVC stack (despite this code run
>>>> in the FIQ handler is subject to severe limitations with respect to
>>>> locking making normal interaction with the kernel impossible).
>>>>
>>>> This default handler allows concepts that on x86 would be handled using
>>>> NMIs to be realized on ARM.
>>>
>>> Okay, lastly... I sent you my version of this change, which contained
>>> the changes I've detailed in the previous three emails, which are absent
>>> from your version.
>>>
>>> However, you've taken on board the "trace" thing to svc_entry, and
>>> renamed it to "call_trace".
>>>
>>> Now if I add this to usr_entry, "call_trace" doesn't make any sense,
>>> nor does the .if/.endif placement because it's not just trace_hardirqs_off
>>> which needs to be disabled there, but also ct_user_exit as well.
>>>
>>> I'm beginning to wonder why I tried to be nice here... it would've been
>>> a lot faster for me to take your patch, make my own changes and commit
>>> that instead.
>>>
>>> Frustrated.
>>
>> And another thing you're missing are the updates to arch/arm/kernel/fiq.c
>> to ensure that the FIQ registers are preserved when we restore this new
>> default FIQ handler.
> 
> Right, here's my remaining delta from your patch addressing all the points
> from the last five emails.  If you have any disagreements with any of these
> changes, then please discuss rather than choosing to ignore them.
> 
> 107e32b0b4ef5fa4191c9fc8415ca172b886e958
> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> index 0c70fee9a7c9..3f6293ce0f2d 100644
> --- a/arch/arm/kernel/entry-armv.S
> +++ b/arch/arm/kernel/entry-armv.S
> <snip>
> @@ -736,13 +738,13 @@ ENDPROC(ret_from_exception)
>  
>  	.align	5
>  __fiq_usr:
> -	usr_entry
> +	usr_entry trace=0
>  	kuser_cmpxchg_check
>  	mov	r0, sp				@ struct pt_regs *regs
>  	bl	handle_fiq_as_nmi
>  	get_thread_info tsk
> -	mov	why, #0
> -	b	ret_to_user_from_irq
> +	restore_user_regs fast = 0, offset = 0
> + UNWIND(.cantunwind	)

.cantunwind is already provided by the usr_entry macro (also adding
.cantunwind here causes my assembler (2.24) to fail).


>   UNWIND(.fnend		)
>  ENDPROC(__fiq_usr)
>  
> diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
> index 918875d96d5d..1743049c433b 100644
> --- a/arch/arm/kernel/fiq.c
> +++ b/arch/arm/kernel/fiq.c
> @@ -53,6 +53,7 @@
>  	})
>  
>  static unsigned long no_fiq_insn;
> +static struct pt_regs def_fiq_regs;
>  
>  /* Default reacquire function
>   * - we always relinquish FIQ control
> @@ -60,8 +61,15 @@ static unsigned long no_fiq_insn;
>   */
>  static int fiq_def_op(void *ref, int relinquish)
>  {
> -	if (!relinquish)
> +	if (!relinquish) {
> +		/* Restore default handler and registers */
> +		local_fiq_disable();
> +		set_fiq_regs(&dfl_fiq_regs);
>  		set_fiq_handler(&no_fiq_insn, sizeof(no_fiq_insn));
> +		local_fiq_enable();
> +
> +		/* FIXME: notify irq controller to standard enable FIQs */
> +	}
>  
>  	return 0;
>  }
> @@ -151,5 +159,6 @@ void __init init_FIQ(int start)
>  {
>  	unsigned offset = FIQ_OFFSET;
>  	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
> +	get_fiq_regs(&dfl_fiq_regs);
>  	fiq_start = start;
>  }
> 
> 

^ permalink raw reply	[flat|nested] 535+ messages in thread

* Re: [PATCH v3 5/5] irqchip: gic: Add support for IPI FIQ
  2014-09-09  8:24                               ` Daniel Thompson
@ 2014-09-14 11:53                                 ` Daniel Thompson
  -1 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-14 11:53 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linux-kernel, linux-arm-kernel, patches, linaro-kernel,
	John Stultz, Thomas Gleixner, Sumit Semwal, Jason Cooper

On 09/09/14 09:24, Daniel Thompson wrote:
> On 08/09/14 17:23, Russell King - ARM Linux wrote:
>> On Mon, Sep 08, 2014 at 04:28:35PM +0100, Daniel Thompson wrote:
>>> @@ -604,8 +731,19 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
>>>  {
>>>  	int cpu;
>>>  	unsigned long flags, map = 0;
>>> +	unsigned long softint;
>>>  
>>> -	raw_spin_lock_irqsave(&irq_controller_lock, flags);
>>> +	/*
>>> +	 * The locking in this function ensures we don't use stale cpu mappings
>>> +	 * and thus we never route an IPI to the wrong physical core during a
>>> +	 * big.LITTLE switch. The switch code takes both of these locks meaning
>>> +	 * we can choose whichever lock is safe to use from our current calling
>>> +	 * context.
>>> +	 */
>>> +	if (in_nmi())
>>> +		raw_spin_lock(&fiq_safe_migration_lock);
>>> +	else
>>> +		raw_spin_lock_irqsave(&irq_controller_lock, flags);
>>
>> Firstly, why would gic_raise_softirq() be called in FIQ context?
> 
> Oops.
> 
> This code should have been removed. It *is* required for kgdb (which
> needs to send FIQ to other processors via IPI and may itself be running
> from FIQ) but it not needed for the currently targeted use case.

I'm afraid I was wrong about this. gic_raise_softitq() is called during
console unlocking inside wake_up_klogd(). This means it is required even
to support arch_trigger_all_cpu_backtrace.

I'm trying to get a (tested) refresh of the FIQ + trigger_backtrace out
today. Thus for now I plan to reinstate the code above (which I believe
to be safe because FIQ is disabled throughout a b.L switch).

Nevertheless I won't ignore this comment! I think a using a r/w lock
here can be made FIQ-safe without having to rely on in_nmi() based
conditional branches.


Daniel.


>> Secondly,
>> this doesn't save you.  If you were in the middle of gic_migrate_target()
>> when the FIQ happened that (for some reason prompted you to call this),
>> you would immediately deadlock trying to that this IRQ.
> 
> This cannot happen because gic_migrate_target() runs with FIQ disabled.
> 
> 
>> I suggest not even trying to solve this "race" which I don't think is
>> one which needs to even be considered (due to the first point.)
> 
> As mentioned above I believe it eventually needs to be addressed by some
> means but it certainly doesn't belong in the current patchset.
> 
> I will remove it.
> 


^ permalink raw reply	[flat|nested] 535+ messages in thread

* [PATCH v3 5/5] irqchip: gic: Add support for IPI FIQ
@ 2014-09-14 11:53                                 ` Daniel Thompson
  0 siblings, 0 replies; 535+ messages in thread
From: Daniel Thompson @ 2014-09-14 11:53 UTC (permalink / raw)
  To: linux-arm-kernel

On 09/09/14 09:24, Daniel Thompson wrote:
> On 08/09/14 17:23, Russell King - ARM Linux wrote:
>> On Mon, Sep 08, 2014 at 04:28:35PM +0100, Daniel Thompson wrote:
>>> @@ -604,8 +731,19 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
>>>  {
>>>  	int cpu;
>>>  	unsigned long flags, map = 0;
>>> +	unsigned long softint;
>>>  
>>> -	raw_spin_lock_irqsave(&irq_controller_lock, flags);
>>> +	/*
>>> +	 * The locking in this function ensures we don't use stale cpu mappings
>>> +	 * and thus we never route an IPI to the wrong physical core during a
>>> +	 * big.LITTLE switch. The switch code takes both of these locks meaning
>>> +	 * we can choose whichever lock is safe to use from our current calling
>>> +	 * context.
>>> +	 */
>>> +	if (in_nmi())
>>> +		raw_spin_lock(&fiq_safe_migration_lock);
>>> +	else
>>> +		raw_spin_lock_irqsave(&irq_controller_lock, flags);
>>
>> Firstly, why would gic_raise_softirq() be called in FIQ context?
> 
> Oops.
> 
> This code should have been removed. It *is* required for kgdb (which
> needs to send FIQ to other processors via IPI and may itself be running
> from FIQ) but it not needed for the currently targeted use case.

I'm afraid I was wrong about this. gic_raise_softitq() is called during
console unlocking inside wake_up_klogd(). This means it is required even
to support arch_trigger_all_cpu_backtrace.

I'm trying to get a (tested) refresh of the FIQ + trigger_backtrace out
today. Thus for now I plan to reinstate the code above (which I believe
to be safe because FIQ is disabled throughout a b.L switch).

Nevertheless I won't ignore this comment! I think a using a r/w lock
here can be made FIQ-safe without having to rely on in_nmi() based
conditional branches.


Daniel.


>> Secondly,
>> this doesn't save you.  If you were in the middle of gic_migrate_target()
>> when the FIQ happened that (for some reason prompted you to call this),
>> you would immediately deadlock trying to that this IRQ.
> 
> This cannot happen because gic_migrate_target() runs with FIQ disabled.
> 
> 
>> I suggest not even trying to solve this "race" which I don't think is
>> one which needs to even be considered (due to the first point.)
> 
> As mentioned above I believe it eventually needs to be addressed by some
> means but it certainly doesn't belong in the current patchset.
> 
> I will remove it.
> 

^ permalink raw reply	[flat|nested] 535+ messages in thread

end of thread, other threads:[~2014-09-14 11:53 UTC | newest]

Thread overview: 535+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-14 15:58 [RFC 0/8] kgdb: NMI/FIQ support for ARM Daniel Thompson
2014-05-14 15:58 ` Daniel Thompson
2014-05-14 15:58 ` [RFC 1/8] arm: fiq: Allow EOI to be communicated to the intc Daniel Thompson
2014-05-14 15:58   ` Daniel Thompson
2014-05-14 15:58 ` [RFC 2/8] irqchip: gic: Provide support for interrupt grouping Daniel Thompson
2014-05-14 15:58   ` Daniel Thompson
2014-05-14 15:58 ` [RFC 3/8] ARM: Move some macros from entry-armv to entry-header Daniel Thompson
2014-05-14 15:58   ` Daniel Thompson
2014-05-14 15:58 ` [RFC 4/8] ARM: Add KGDB/KDB FIQ debugger generic code Daniel Thompson
2014-05-14 15:58   ` Daniel Thompson
2014-05-14 15:58 ` [RFC 5/8] serial: amba-pl011: Pass on FIQ information to KGDB Daniel Thompson
2014-05-14 15:58   ` Daniel Thompson
2014-05-14 15:58 ` [RFC 6/8] serial: asc: Add support for KGDB's FIQ/NMI mode Daniel Thompson
2014-05-14 15:58   ` Daniel Thompson
2014-05-14 15:58 ` [RFC 7/8] ARM: VIC: Add vic_set_fiq function to select if an interrupt should generate an IRQ or FIQ Daniel Thompson
2014-05-14 15:58   ` Daniel Thompson
2014-05-14 15:58 ` [RFC 8/8] arm: fiq: Hack FIQ routing backdoors into GIC and VIC Daniel Thompson
2014-05-14 15:58   ` Daniel Thompson
2014-05-23 13:57 ` [RFC v2 00/10] kgdb: NMI/FIQ support for ARM Daniel Thompson
2014-05-23 13:57   ` Daniel Thompson
2014-05-23 13:57   ` [RFC v2 01/10] arm: fiq: Allow EOI to be communicated to the intc Daniel Thompson
2014-05-23 13:57     ` Daniel Thompson
2014-05-23 14:59     ` Srinivas Kandagatla
2014-05-23 14:59       ` Srinivas Kandagatla
2014-05-23 15:00     ` Russell King - ARM Linux
2014-05-23 15:00       ` Russell King - ARM Linux
2014-05-28 15:47       ` Daniel Thompson
2014-05-28 15:47         ` Daniel Thompson
2014-05-23 13:57   ` [RFC v2 02/10] irqchip: gic: Provide support for interrupt grouping Daniel Thompson
2014-05-23 13:57     ` Daniel Thompson
2014-05-23 13:57   ` [RFC v2 03/10] irqchip: gic: Introduce shadow irqs for FIQ Daniel Thompson
2014-05-23 13:57     ` Daniel Thompson
2014-05-23 13:57   ` [RFC v2 04/10] ARM: vexpress: Extend UART with FIQ support Daniel Thompson
2014-05-23 13:57     ` Daniel Thompson
2014-05-23 15:04     ` Russell King - ARM Linux
2014-05-23 15:04       ` Russell King - ARM Linux
2014-05-29 10:31       ` Daniel Thompson
2014-05-29 10:31         ` Daniel Thompson
2014-05-29 13:44         ` Rob Herring
2014-05-29 13:44           ` Rob Herring
2014-06-03 12:41           ` Daniel Thompson
2014-06-03 12:41             ` Daniel Thompson
2014-05-23 13:57   ` [RFC v2 05/10] ARM: STi: STiH41x: " Daniel Thompson
2014-05-23 13:57     ` Daniel Thompson
2014-05-23 13:57   ` [RFC v2 06/10] irqchip: vic: Introduce shadow irqs for FIQ Daniel Thompson
2014-05-23 13:57     ` Daniel Thompson
2014-05-23 13:57   ` [RFC v2 07/10] ARM: Move some macros from entry-armv to entry-header Daniel Thompson
2014-05-23 13:57     ` Daniel Thompson
2014-05-23 13:57   ` [RFC v2 08/10] ARM: Add KGDB/KDB FIQ debugger generic code Daniel Thompson
2014-05-23 13:57     ` Daniel Thompson
2014-05-23 13:57   ` [RFC v2 09/10] serial: amba-pl011: Pass on FIQ information to KGDB Daniel Thompson
2014-05-23 13:57     ` Daniel Thompson
2014-05-23 13:57   ` [RFC v2 10/10] serial: asc: Add support for KGDB's FIQ/NMI mode Daniel Thompson
2014-05-23 13:57     ` Daniel Thompson
2014-05-23 14:50     ` Srinivas Kandagatla
2014-05-23 14:50       ` Srinivas Kandagatla
2014-06-05  9:53   ` [RFC v3 0/9] kgdb: NMI/FIQ support for ARM Daniel Thompson
2014-06-05  9:53     ` Daniel Thompson
2014-06-05  9:53     ` [RFC v3 1/9] arm: fiq: arbitrary mappings from IRQ to FIQ virqs Daniel Thompson
2014-06-05  9:53       ` Daniel Thompson
2014-06-05 11:51       ` Russell King - ARM Linux
2014-06-05 11:51         ` Russell King - ARM Linux
2014-06-05 13:08         ` Daniel Thompson
2014-06-05 13:08           ` Daniel Thompson
2014-06-12  8:37       ` Linus Walleij
2014-06-12  8:37         ` Linus Walleij
2014-06-12  9:54         ` Daniel Thompson
2014-06-12  9:54           ` Daniel Thompson
2014-06-13 14:29       ` Rob Herring
2014-06-13 14:29         ` Rob Herring
2014-06-18 11:24         ` Daniel Thompson
2014-06-18 11:24           ` Daniel Thompson
2014-06-05  9:53     ` [RFC v3 2/9] arm: fiq: Allow EOI to be communicated to the intc Daniel Thompson
2014-06-05  9:53       ` Daniel Thompson
2014-06-05  9:53     ` [RFC v3 3/9] irqchip: gic: Provide support for interrupt grouping Daniel Thompson
2014-06-05  9:53       ` Daniel Thompson
2014-06-05 19:50       ` Nicolas Pitre
2014-06-05 19:50         ` Nicolas Pitre
2014-06-05  9:53     ` [RFC v3 4/9] irqchip: gic: Introduce shadow irqs for FIQ Daniel Thompson
2014-06-05  9:53       ` Daniel Thompson
2014-06-06  7:46       ` Peter De Schrijver
2014-06-06  7:46         ` Peter De Schrijver
2014-06-06  9:23         ` Daniel Thompson
2014-06-06  9:23           ` Daniel Thompson
2014-06-05  9:53     ` [RFC v3 5/9] irqchip: vic: " Daniel Thompson
2014-06-05  9:53       ` Daniel Thompson
2014-06-05  9:53     ` [RFC v3 6/9] ARM: Move some macros from entry-armv to entry-header Daniel Thompson
2014-06-05  9:53       ` Daniel Thompson
2014-06-05  9:53     ` [RFC v3 7/9] ARM: Add KGDB/KDB FIQ debugger generic code Daniel Thompson
2014-06-05  9:53       ` Daniel Thompson
2014-06-05  9:53     ` [RFC v3 8/9] serial: amba-pl011: Pass on FIQ information to KGDB Daniel Thompson
2014-06-05  9:53       ` Daniel Thompson
2014-06-05  9:53     ` [RFC v3 9/9] serial: asc: Add support for KGDB's FIQ/NMI mode Daniel Thompson
2014-06-05  9:53       ` Daniel Thompson
2014-06-19 10:38     ` [PATCH v4 00/13] kgdb: NMI/FIQ support for ARM Daniel Thompson
2014-06-19 10:38       ` Daniel Thompson
2014-06-19 10:38       ` [PATCH v4 01/13] arm: fiq: Add callbacks to manage FIQ routings Daniel Thompson
2014-06-19 10:38         ` Daniel Thompson
2014-06-19 10:38       ` [PATCH v4 02/13] arm: fiq: Allow EOI to be communicated to the intc Daniel Thompson
2014-06-19 10:38         ` Daniel Thompson
2014-06-19 10:38       ` [PATCH v4 03/13] irqchip: gic: Provide support for interrupt grouping Daniel Thompson
2014-06-19 10:38         ` Daniel Thompson
2014-06-19 10:38       ` [PATCH v4 04/13] irqchip: gic: Add support for FIQ management Daniel Thompson
2014-06-19 10:38         ` Daniel Thompson
2014-06-19 10:38       ` [PATCH v4 05/13] irqchip: gic: Remove spin locks from eoi_irq Daniel Thompson
2014-06-19 10:38         ` Daniel Thompson
2014-06-19 10:38       ` [PATCH v4 06/13] irqchip: vic: Add support for FIQ management Daniel Thompson
2014-06-19 10:38         ` Daniel Thompson
2014-06-19 10:38       ` [PATCH v4 07/13] ARM: Move some macros from entry-armv to entry-header Daniel Thompson
2014-06-19 10:38         ` Daniel Thompson
2014-06-19 10:38       ` [PATCH v4 08/13] ARM: Add KGDB/KDB FIQ debugger generic code Daniel Thompson
2014-06-19 10:38         ` Daniel Thompson
2014-06-19 10:38       ` [PATCH v4 09/13] serial: amba-pl011: Pass FIQ information to KGDB Daniel Thompson
2014-06-19 10:38         ` Daniel Thompson
2014-06-20  0:36         ` Greg Kroah-Hartman
2014-06-20  0:36           ` Greg Kroah-Hartman
2014-06-19 10:38       ` [PATCH v4 10/13] serial: asc: Add support for KGDB's FIQ/NMI mode Daniel Thompson
2014-06-19 10:38         ` Daniel Thompson
2014-06-20  0:36         ` Greg Kroah-Hartman
2014-06-20  0:36           ` Greg Kroah-Hartman
2014-06-19 10:38       ` [PATCH v4 11/13] serial: asc: Adopt readl_/writel_relaxed() Daniel Thompson
2014-06-19 10:38         ` Daniel Thompson
2014-06-19 11:29         ` Srinivas Kandagatla
2014-06-19 11:29           ` Srinivas Kandagatla
2014-06-19 11:46           ` Daniel Thompson
2014-06-19 11:46             ` Daniel Thompson
2014-06-19 11:58             ` Maxime Coquelin
2014-06-19 11:58               ` Maxime Coquelin
2014-06-19 12:01             ` Srinivas Kandagatla
2014-06-19 12:01               ` Srinivas Kandagatla
2014-06-19 13:12               ` Daniel Thompson
2014-06-19 13:12                 ` Daniel Thompson
2014-06-19 10:38       ` [PATCH v4 12/13] serial: imx: clean up imx_poll_get_char() Daniel Thompson
2014-06-19 10:38         ` Daniel Thompson
2014-06-19 10:38       ` [PATCH v4 13/13] serial: imx: Add support for KGDB's FIQ/NMI mode Daniel Thompson
2014-06-19 10:38         ` Daniel Thompson
2014-06-24 15:18       ` [PATCH v6 0/4] arm: KGDB NMI/FIQ support Daniel Thompson
2014-06-24 15:18         ` Daniel Thompson
2014-06-24 15:18         ` [PATCH v6 1/4] arm: fiq: Add callbacks to manage FIQ routings Daniel Thompson
2014-06-24 15:18           ` Daniel Thompson
2014-06-24 15:44           ` Nicolas Pitre
2014-06-24 15:44             ` Nicolas Pitre
2014-06-24 15:58             ` Daniel Thompson
2014-06-24 15:58               ` Daniel Thompson
2014-06-24 15:18         ` [PATCH v6 2/4] arm: fiq: Allow EOI to be communicated to the intc Daniel Thompson
2014-06-24 15:18           ` Daniel Thompson
2014-06-24 15:46           ` Nicolas Pitre
2014-06-24 15:46             ` Nicolas Pitre
2014-06-24 15:18         ` [PATCH v6 3/4] ARM: Move some macros from entry-armv to entry-header Daniel Thompson
2014-06-24 15:18           ` Daniel Thompson
2014-06-24 15:53           ` Nicolas Pitre
2014-06-24 15:53             ` Nicolas Pitre
2014-06-24 15:18         ` [PATCH v6 4/4] ARM: Add KGDB/KDB FIQ debugger generic code Daniel Thompson
2014-06-24 15:18           ` Daniel Thompson
2014-06-24 16:08           ` Russell King - ARM Linux
2014-06-24 16:08             ` Russell King - ARM Linux
2014-06-26  9:54             ` Daniel Thompson
2014-06-26  9:54               ` Daniel Thompson
2014-06-30 13:54               ` Daniel Thompson
2014-06-30 13:54                 ` Daniel Thompson
2014-06-24 16:22           ` Nicolas Pitre
2014-06-24 16:22             ` Nicolas Pitre
2014-06-26 12:48             ` Daniel Thompson
2014-06-26 12:48               ` Daniel Thompson
2014-06-30  8:53         ` [PATCH v7 0/4] arm: KGDB NMI/FIQ support Daniel Thompson
2014-06-30  8:53           ` Daniel Thompson
2014-06-30  8:53           ` [PATCH v7 1/4] arm: fiq: Add callbacks to manage FIQ routings Daniel Thompson
2014-06-30  8:53             ` Daniel Thompson
2014-06-30  8:53           ` [PATCH v7 2/4] arm: fiq: Allow EOI to be communicated to the intc Daniel Thompson
2014-06-30  8:53             ` Daniel Thompson
2014-06-30  8:53           ` [PATCH v7 3/4] ARM: Move some macros from entry-armv to entry-header Daniel Thompson
2014-06-30  8:53             ` Daniel Thompson
2014-06-30  8:53           ` [PATCH v7 4/4] ARM: Add KGDB/KDB FIQ debugger generic code Daniel Thompson
2014-06-30  8:53             ` Daniel Thompson
2014-07-10  8:03           ` [PATCH v8 0/4] arm: KGDB NMI/FIQ support Daniel Thompson
2014-07-10  8:03             ` Daniel Thompson
2014-07-10  8:03             ` [PATCH v8 1/4] arm: fiq: Add callbacks to manage FIQ routings Daniel Thompson
2014-07-10  8:03               ` Daniel Thompson
2014-07-10  8:03             ` [PATCH v8 2/4] arm: fiq: Allow ACK and EOI to be passed to the intc Daniel Thompson
2014-07-10  8:03               ` Daniel Thompson
2014-07-10  8:03             ` [PATCH v8 3/4] ARM: Move some macros from entry-armv to entry-header Daniel Thompson
2014-07-10  8:03               ` Daniel Thompson
2014-07-10  8:03             ` [PATCH v8 4/4] ARM: Add KGDB/KDB FIQ debugger generic code Daniel Thompson
2014-07-10  8:03               ` Daniel Thompson
2014-08-13 21:45               ` Russell King - ARM Linux
2014-08-13 21:45                 ` Russell King - ARM Linux
2014-08-14 10:48                 ` Daniel Thompson
2014-08-14 10:48                   ` Daniel Thompson
2014-08-14 11:15                   ` [RFC PATCH 0/3] arm: FIQ IPI support Daniel Thompson
2014-08-14 11:15                     ` Daniel Thompson
2014-08-14 11:15                     ` [RFC PATCH 1/3] arm: smp: Introduce a special IPI signalled using FIQ Daniel Thompson
2014-08-14 11:15                       ` Daniel Thompson
2014-08-14 11:15                     ` [RFC PATCH 2/3] arm: kgdb: Add support for IPI FIQ roundup Daniel Thompson
2014-08-14 11:15                       ` Daniel Thompson
2014-08-14 11:15                     ` [RFC PATCH 3/3] irqchip: gic: Add support for IPI FIQ Daniel Thompson
2014-08-14 11:15                       ` Daniel Thompson
2014-08-14 12:36                   ` [PATCH v8 4/4] ARM: Add KGDB/KDB FIQ debugger generic code Russell King - ARM Linux
2014-08-14 12:36                     ` Russell King - ARM Linux
2014-08-14 15:02                     ` Daniel Thompson
2014-08-14 15:02                       ` Daniel Thompson
2014-07-14 13:51             ` [PATCH v8 0/4] arm: KGDB NMI/FIQ support Harro Haan
2014-07-14 13:51               ` Harro Haan
2014-07-15  9:41               ` Daniel Thompson
2014-07-15  9:41                 ` Daniel Thompson
2014-07-15 13:04                 ` Harro Haan
2014-07-15 13:04                   ` Harro Haan
2014-07-15 14:52                   ` Daniel Thompson
2014-07-15 14:52                     ` Daniel Thompson
2014-07-15 15:59                     ` Harro Haan
2014-07-15 15:59                       ` Harro Haan
2014-07-15 17:08                       ` Daniel Thompson
2014-07-15 17:08                         ` Daniel Thompson
2014-07-16 17:15                         ` Harro Haan
2014-07-16 17:15                           ` Harro Haan
2014-07-17  9:01                           ` Daniel Thompson
2014-07-17  9:01                             ` Daniel Thompson
2014-07-15 18:45                 ` Marek Vasut
2014-07-15 18:45                   ` Marek Vasut
2014-07-16 12:54                   ` Daniel Thompson
2014-07-16 12:54                     ` Daniel Thompson
2014-07-16 17:21                     ` Harro Haan
2014-07-16 17:21                       ` Harro Haan
2014-07-17  9:20                       ` Daniel Thompson
2014-07-17  9:20                         ` Daniel Thompson
2014-08-18 13:40             ` [PATCH v9 00/16] " Daniel Thompson
2014-08-18 13:40               ` Daniel Thompson
2014-08-18 13:40               ` [PATCH v9 01/16] arm: fiq: Add callbacks to manage FIQ routings Daniel Thompson
2014-08-18 13:40                 ` Daniel Thompson
2014-08-18 13:40               ` [PATCH v9 02/16] arm: fiq: Allow ACK and EOI to be passed to the intc Daniel Thompson
2014-08-18 13:40                 ` Daniel Thompson
2014-08-18 13:40               ` [PATCH v9 03/16] arm: fiq: Replace default FIQ handler Daniel Thompson
2014-08-18 13:40                 ` Daniel Thompson
2014-08-18 13:40               ` [PATCH v9 04/16] arm: smp: Introduce a special IPI signalled using FIQ Daniel Thompson
2014-08-18 13:40                 ` Daniel Thompson
2014-08-18 13:40               ` [PATCH v9 05/16] arm: KGDB/KDB FIQ support Daniel Thompson
2014-08-18 13:40                 ` Daniel Thompson
2014-08-19 16:45               ` [PATCH v10 00/19] arm: KGDB NMI/FIQ support Daniel Thompson
2014-08-19 16:45                 ` Daniel Thompson
2014-08-19 16:45                 ` [PATCH v10 01/19] arm: fiq: Add callbacks to manage FIQ routings Daniel Thompson
2014-08-19 16:45                   ` Daniel Thompson
2014-08-19 16:45                 ` [PATCH v10 02/19] arm: fiq: Allow ACK and EOI to be passed to the intc Daniel Thompson
2014-08-19 16:45                   ` Daniel Thompson
2014-08-19 16:45                 ` [PATCH v10 03/19] arm: fiq: Replace default FIQ handler Daniel Thompson
2014-08-19 16:45                   ` Daniel Thompson
2014-08-19 17:37                   ` Russell King - ARM Linux
2014-08-19 17:37                     ` Russell King - ARM Linux
2014-08-19 18:12                     ` Daniel Thompson
2014-08-19 18:12                       ` Daniel Thompson
2014-08-28 15:01                       ` Russell King - ARM Linux
2014-08-28 15:01                         ` Russell King - ARM Linux
2014-08-28 15:43                         ` Paul E. McKenney
2014-08-28 15:43                           ` Paul E. McKenney
2014-08-28 15:54                         ` Daniel Thompson
2014-08-28 15:54                           ` Daniel Thompson
2014-08-28 16:15                           ` Paul E. McKenney
2014-08-28 16:15                             ` Paul E. McKenney
2014-09-02 11:03                             ` Daniel Thompson
2014-09-02 11:03                               ` Daniel Thompson
2014-09-02 11:36                               ` Russell King - ARM Linux
2014-09-02 11:36                                 ` Russell King - ARM Linux
2014-09-02 11:49                         ` Daniel Thompson
2014-09-02 11:49                           ` Daniel Thompson
2014-09-02 14:23                           ` Paul E. McKenney
2014-09-02 14:23                             ` Paul E. McKenney
2014-09-02 16:42                           ` Russell King - ARM Linux
2014-09-02 16:42                             ` Russell King - ARM Linux
2014-09-03 10:21                             ` Daniel Thompson
2014-09-03 10:21                               ` Daniel Thompson
2014-09-03 19:34                               ` Russell King - ARM Linux
2014-09-03 19:34                                 ` Russell King - ARM Linux
2014-09-04  9:09                                 ` Daniel Thompson
2014-09-04  9:09                                   ` Daniel Thompson
2014-09-04  9:45                                   ` Russell King - ARM Linux
2014-09-04  9:45                                     ` Russell King - ARM Linux
2014-09-04 10:04                                     ` Daniel Thompson
2014-09-04 10:04                                       ` Daniel Thompson
2014-08-19 16:45                 ` [PATCH v10 04/19] arm: smp: Introduce a special IPI signalled using FIQ Daniel Thompson
2014-08-19 16:45                   ` Daniel Thompson
2014-08-19 16:45                 ` [PATCH v10 05/19] arm: KGDB/KDB FIQ support Daniel Thompson
2014-08-19 16:45                   ` Daniel Thompson
2014-08-19 16:45                 ` [PATCH v10 06/19] irqchip: gic: Provide support for interrupt grouping Daniel Thompson
2014-08-19 16:45                   ` Daniel Thompson
2014-08-19 16:45                 ` [PATCH v10 07/19] irqchip: gic: Add support for FIQ management Daniel Thompson
2014-08-19 16:45                   ` Daniel Thompson
2014-08-19 16:45                 ` [PATCH v10 08/19] irqchip: gic: Remove spin locks from eoi_irq Daniel Thompson
2014-08-19 16:45                   ` Daniel Thompson
2014-08-19 16:45                 ` [PATCH v10 09/19] irqchip: gic: Add support for IPI FIQ Daniel Thompson
2014-08-19 16:45                   ` Daniel Thompson
2014-08-19 16:46                 ` [PATCH v10 10/19] irqchip: gic: Group 0 workaround Daniel Thompson
2014-08-19 16:46                   ` Daniel Thompson
2014-08-19 16:46                 ` [PATCH v10 11/19] irqchip: vic: Add support for FIQ management Daniel Thompson
2014-08-19 16:46                   ` Daniel Thompson
2014-08-19 16:46                   ` Daniel Thompson
2014-08-19 16:46                 ` [PATCH v10 12/19] serial: kgdb_nmi: No CON_ENABLED by default Daniel Thompson
2014-08-19 16:46                   ` Daniel Thompson
2014-08-19 16:46                 ` [PATCH v10 13/19] serial: amba-pl011: Use container_of() to get uart_amba_port Daniel Thompson
2014-08-19 16:46                   ` Daniel Thompson
2014-08-19 16:46                 ` [PATCH v10 14/19] serial: amba-pl011: Move pl011_hwinit() Daniel Thompson
2014-08-19 16:46                   ` Daniel Thompson
2014-08-19 16:46                 ` [PATCH v10 15/19] serial: amba-pl011: Pass FIQ information to KGDB Daniel Thompson
2014-08-19 16:46                   ` Daniel Thompson
2014-08-19 16:46                 ` [PATCH v10 16/19] serial: asc: Add support for KGDB's FIQ/NMI mode Daniel Thompson
2014-08-19 16:46                   ` Daniel Thompson
2014-08-19 16:46                   ` Daniel Thompson
2014-08-19 16:46                 ` [PATCH v10 17/19] serial: asc: Adopt readl_/writel_relaxed() Daniel Thompson
2014-08-19 16:46                   ` Daniel Thompson
2014-08-19 16:46                   ` Daniel Thompson
2014-08-19 16:46                 ` [PATCH v10 18/19] serial: imx: clean up imx_poll_get_char() Daniel Thompson
2014-08-19 16:46                   ` Daniel Thompson
2014-08-19 16:46                 ` [PATCH v10 19/19] serial: imx: Add support for KGDB's FIQ/NMI mode Daniel Thompson
2014-08-19 16:46                   ` Daniel Thompson
2014-09-02 13:00                 ` [PATCH v11 00/19] arm: KGDB NMI/FIQ support Daniel Thompson
2014-09-02 13:00                   ` Daniel Thompson
2014-09-02 13:00                   ` [PATCH v11 01/19] arm: fiq: Add callbacks to manage FIQ routings Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 18:51                     ` Russell King - ARM Linux
2014-09-02 18:51                       ` Russell King - ARM Linux
2014-09-03  0:03                     ` Thomas Gleixner
2014-09-03  0:03                       ` Thomas Gleixner
2014-09-03  8:27                       ` Daniel Thompson
2014-09-03  8:27                         ` Daniel Thompson
2014-09-02 13:00                   ` [PATCH v11 02/19] arm: fiq: Allow ACK and EOI to be passed to the intc Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 13:00                   ` [PATCH v11 03/19] arm: fiq: Replace default FIQ handler Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 13:00                   ` [PATCH v11 04/19] arm: smp: Introduce a special IPI signalled using FIQ Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 13:00                   ` [PATCH v11 05/19] arm: KGDB/KDB FIQ support Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 13:00                   ` [PATCH v11 06/19] irqchip: gic: Provide support for interrupt grouping Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 19:33                     ` Russell King - ARM Linux
2014-09-02 19:33                       ` Russell King - ARM Linux
2014-09-02 21:36                       ` Catalin Marinas
2014-09-02 21:36                         ` Catalin Marinas
2014-09-03  9:44                         ` Daniel Thompson
2014-09-03  9:44                           ` Daniel Thompson
2014-09-03  9:28                       ` Daniel Thompson
2014-09-03  9:28                         ` Daniel Thompson
2014-09-02 13:00                   ` [PATCH v11 07/19] irqchip: gic: Add support for FIQ management Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 19:36                     ` Russell King - ARM Linux
2014-09-02 19:36                       ` Russell King - ARM Linux
2014-09-02 13:00                   ` [PATCH v11 08/19] irqchip: gic: Remove spin locks from eoi_irq Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 13:00                   ` [PATCH v11 09/19] irqchip: gic: Add support for IPI FIQ Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 13:00                   ` [PATCH v11 10/19] irqchip: gic: Group 0 workaround Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 13:00                   ` [PATCH v11 11/19] irqchip: vic: Add support for FIQ management Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 19:40                     ` Russell King - ARM Linux
2014-09-02 19:40                       ` Russell King - ARM Linux
2014-09-02 13:00                   ` [PATCH v11 12/19] serial: kgdb_nmi: No CON_ENABLED by default Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 13:00                   ` [PATCH v11 13/19] serial: amba-pl011: Use container_of() to get uart_amba_port Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 13:00                   ` [PATCH v11 14/19] serial: amba-pl011: Move pl011_hwinit() Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 13:00                   ` [PATCH v11 15/19] serial: amba-pl011: Pass FIQ information to KGDB Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 13:00                   ` [PATCH v11 16/19] serial: asc: Add support for KGDB's FIQ/NMI mode Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 13:00                   ` [PATCH v11 17/19] serial: asc: Adopt readl_/writel_relaxed() Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 13:42                     ` [STLinux Kernel] " Peter Griffin
2014-09-02 13:42                       ` Peter Griffin
2014-09-02 13:55                     ` Maxime Coquelin
2014-09-02 13:55                       ` Maxime Coquelin
2014-09-02 13:55                       ` Maxime Coquelin
2014-09-02 13:00                   ` [PATCH v11 18/19] serial: imx: clean up imx_poll_get_char() Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 13:00                   ` [PATCH v11 19/19] serial: imx: Add support for KGDB's FIQ/NMI mode Daniel Thompson
2014-09-02 13:00                     ` Daniel Thompson
2014-09-02 23:02                   ` [PATCH v11 00/19] arm: KGDB NMI/FIQ support Thomas Gleixner
2014-09-02 23:02                     ` Thomas Gleixner
2014-09-03  9:02                     ` Daniel Thompson
2014-09-03  9:02                       ` Daniel Thompson
2014-09-03 10:06                       ` Thomas Gleixner
2014-09-03 10:06                         ` Thomas Gleixner
2014-09-03 10:30                         ` Daniel Thompson
2014-09-03 10:30                           ` Daniel Thompson
2014-09-04 16:03                   ` [PATCH v1 0/6] arm: Implement arch_trigger_all_cpu_backtrace Daniel Thompson
2014-09-04 16:03                     ` Daniel Thompson
2014-09-04 16:03                     ` [PATCH v1 1/6] arm: fiq: Replace default FIQ handler Daniel Thompson
2014-09-04 16:03                       ` Daniel Thompson
2014-09-04 18:57                       ` Nicolas Pitre
2014-09-04 18:57                         ` Nicolas Pitre
2014-09-05  9:03                         ` Daniel Thompson
2014-09-05  9:03                           ` Daniel Thompson
2014-09-05 18:04                           ` Nicolas Pitre
2014-09-05 18:04                             ` Nicolas Pitre
2014-09-08 13:22                             ` Daniel Thompson
2014-09-08 13:22                               ` Daniel Thompson
2014-09-04 16:03                     ` [PATCH v1 2/6] arm: smp: Introduce a non-maskable IPI Daniel Thompson
2014-09-04 16:03                       ` Daniel Thompson
2014-09-04 16:03                     ` [PATCH v1 3/6] arm64: Introduce dummy version of asm/fiq.h Daniel Thompson
2014-09-04 16:03                       ` Daniel Thompson
2014-09-04 16:03                     ` [PATCH v1 4/6] irqchip: gic: Add support for IPI FIQ Daniel Thompson
2014-09-04 16:03                       ` Daniel Thompson
2014-09-04 16:03                     ` [PATCH v1 5/6] irqchip: gic: Group 0 workaround Daniel Thompson
2014-09-04 16:03                       ` Daniel Thompson
2014-09-04 16:03                     ` [PATCH v1 6/6] arm: Implement arch_trigger_all_cpu_backtrace Daniel Thompson
2014-09-04 16:03                       ` Daniel Thompson
2014-09-05 15:33                     ` [PATCH v2 0/5] " Daniel Thompson
2014-09-05 15:33                       ` Daniel Thompson
2014-09-05 15:33                       ` [PATCH v2 1/5] ARM: remove unused do_unexp_fiq() function Daniel Thompson
2014-09-05 15:33                         ` Daniel Thompson
2014-09-05 15:33                       ` [PATCH v2 2/5] ARM: add basic support for on-demand backtrace of other CPUs Daniel Thompson
2014-09-05 15:33                         ` Daniel Thompson
2014-09-05 15:33                       ` [PATCH v2 3/5] arm: fiq: Replace default FIQ handler Daniel Thompson
2014-09-05 15:33                         ` Daniel Thompson
2014-09-05 15:33                       ` [PATCH v2 4/5] arm64: Introduce dummy version of asm/fiq.h Daniel Thompson
2014-09-05 15:33                         ` Daniel Thompson
2014-09-05 16:50                         ` Catalin Marinas
2014-09-05 16:50                           ` Catalin Marinas
2014-09-08 11:03                           ` Daniel Thompson
2014-09-08 11:03                             ` Daniel Thompson
2014-09-05 15:33                       ` [PATCH v2 5/5] irqchip: gic: Add support for IPI FIQ Daniel Thompson
2014-09-05 15:33                         ` Daniel Thompson
2014-09-08 15:28                       ` [PATCH v3 0/5] arm: Implement arch_trigger_all_cpu_backtrace Daniel Thompson
2014-09-08 15:28                         ` Daniel Thompson
2014-09-08 15:28                         ` [PATCH v3 1/5] ARM: remove unused do_unexp_fiq() function Daniel Thompson
2014-09-08 15:28                           ` Daniel Thompson
2014-09-08 15:28                         ` [PATCH v3 2/5] ARM: add basic support for on-demand backtrace of other CPUs Daniel Thompson
2014-09-08 15:28                           ` Daniel Thompson
2014-09-08 15:28                         ` [PATCH v3 3/5] arm: fiq: Replace default FIQ handler Daniel Thompson
2014-09-08 15:28                           ` Daniel Thompson
2014-09-08 15:49                           ` Nicolas Pitre
2014-09-08 15:49                             ` Nicolas Pitre
2014-09-08 15:57                             ` Daniel Thompson
2014-09-08 15:57                               ` Daniel Thompson
2014-09-08 15:28                         ` [PATCH v3 4/5] arm64: Introduce dummy version of asm/fiq.h Daniel Thompson
2014-09-08 15:28                           ` Daniel Thompson
2014-09-08 15:28                         ` [PATCH v3 5/5] irqchip: gic: Add support for IPI FIQ Daniel Thompson
2014-09-08 15:28                           ` Daniel Thompson
2014-09-08 16:23                           ` Russell King - ARM Linux
2014-09-08 16:23                             ` Russell King - ARM Linux
2014-09-09  8:24                             ` Daniel Thompson
2014-09-09  8:24                               ` Daniel Thompson
2014-09-14 11:53                               ` Daniel Thompson
2014-09-14 11:53                                 ` Daniel Thompson
2014-09-08 16:24                         ` [PATCH v3 0/5] arm: Implement arch_trigger_all_cpu_backtrace Russell King - ARM Linux
2014-09-08 16:24                           ` Russell King - ARM Linux
2014-09-09  8:26                           ` Daniel Thompson
2014-09-09  8:26                             ` Daniel Thompson
2014-09-09 14:15                         ` [PATCH v4 0/6] " Daniel Thompson
2014-09-09 14:15                           ` Daniel Thompson
2014-09-09 14:15                           ` [PATCH v4 1/6] ARM: remove unused do_unexp_fiq() function Daniel Thompson
2014-09-09 14:15                             ` Daniel Thompson
2014-09-09 14:15                           ` [PATCH v4 2/6] arm: fiq: Replace default FIQ handler Daniel Thompson
2014-09-09 14:15                             ` Daniel Thompson
2014-09-09 14:15                           ` [PATCH v4 3/6] arm64: Introduce dummy version of asm/fiq.h Daniel Thompson
2014-09-09 14:15                             ` Daniel Thompson
2014-09-09 14:15                           ` [PATCH v4 4/6] irqchip: gic: Add support for IPI FIQ Daniel Thompson
2014-09-09 14:15                             ` Daniel Thompson
2014-09-09 14:15                           ` [PATCH v4 5/6] ARM: add basic support for on-demand backtrace of other CPUs Daniel Thompson
2014-09-09 14:15                             ` Daniel Thompson
2014-09-09 14:15                           ` [PATCH v4 6/6] arm: smp: Handle ipi_cpu_backtrace() using FIQ (if available) Daniel Thompson
2014-09-09 14:15                             ` Daniel Thompson
2014-09-11 11:31                           ` [PATCH 3.17-rc4 v5 0/6] arm: Implement arch_trigger_all_cpu_backtrace Daniel Thompson
2014-09-11 11:31                             ` Daniel Thompson
2014-09-11 11:31                             ` [PATCH 3.17-rc4 v5 1/6] ARM: remove unused do_unexp_fiq() function Daniel Thompson
2014-09-11 11:31                               ` Daniel Thompson
2014-09-11 11:31                             ` [PATCH 3.17-rc4 v5 2/6] arm: fiq: Replace default FIQ handler Daniel Thompson
2014-09-11 11:31                               ` Daniel Thompson
2014-09-12 17:03                               ` Russell King - ARM Linux
2014-09-12 17:03                                 ` Russell King - ARM Linux
2014-09-12 17:07                                 ` Russell King - ARM Linux
2014-09-12 17:07                                   ` Russell King - ARM Linux
2014-09-13 12:01                                 ` Daniel Thompson
2014-09-13 12:01                                   ` Daniel Thompson
2014-09-12 17:08                               ` Russell King - ARM Linux
2014-09-12 17:08                                 ` Russell King - ARM Linux
2014-09-12 17:14                               ` Russell King - ARM Linux
2014-09-12 17:14                                 ` Russell King - ARM Linux
2014-09-12 17:19                                 ` Russell King - ARM Linux
2014-09-12 17:19                                   ` Russell King - ARM Linux
2014-09-12 17:23                                   ` Russell King - ARM Linux
2014-09-12 17:23                                     ` Russell King - ARM Linux
2014-09-14  6:36                                     ` Daniel Thompson
2014-09-14  6:36                                       ` Daniel Thompson
2014-09-14  8:45                                       ` Russell King - ARM Linux
2014-09-14  8:45                                         ` Russell King - ARM Linux
2014-09-14 11:27                                     ` Daniel Thompson
2014-09-14 11:27                                       ` Daniel Thompson
2014-09-13 12:03                                 ` Daniel Thompson
2014-09-13 12:03                                   ` Daniel Thompson
2014-09-11 11:31                             ` [PATCH 3.17-rc4 v5 3/6] arm64: Introduce dummy version of asm/fiq.h Daniel Thompson
2014-09-11 11:31                               ` Daniel Thompson
2014-09-11 11:31                             ` [PATCH 3.17-rc4 v5 4/6] irqchip: gic: Add support for IPI FIQ Daniel Thompson
2014-09-11 11:31                               ` Daniel Thompson
2014-09-11 11:31                             ` [PATCH 3.17-rc4 v5 5/6] ARM: add basic support for on-demand backtrace of other CPUs Daniel Thompson
2014-09-11 11:31                               ` Daniel Thompson
2014-09-11 11:31                             ` [PATCH 3.17-rc4 v5 6/6] arm: smp: Handle ipi_cpu_backtrace() using FIQ (if available) Daniel Thompson
2014-09-11 11:31                               ` Daniel Thompson
2014-08-18 14:12             ` [PATCH v9 06/16] irqchip: gic: Provide support for interrupt grouping Daniel Thompson
2014-08-18 14:12               ` Daniel Thompson
2014-08-18 14:12             ` [PATCH v9 07/16] irqchip: gic: Add support for FIQ management Daniel Thompson
2014-08-18 14:12               ` Daniel Thompson
2014-08-18 14:12             ` [PATCH v9 08/16] irqchip: gic: Remove spin locks from eoi_irq Daniel Thompson
2014-08-18 14:12               ` Daniel Thompson
2014-08-18 14:12             ` [PATCH v9 09/16] irqchip: gic: Add support for IPI FIQ Daniel Thompson
2014-08-18 14:12               ` Daniel Thompson
2014-08-18 14:12             ` [PATCH v9 10/16] irqchip: gic: Group 0 workaround Daniel Thompson
2014-08-18 14:12               ` Daniel Thompson
2014-08-18 14:12             ` [PATCH v9 11/16] irqchip: vic: Add support for FIQ management Daniel Thompson
2014-08-18 14:12               ` Daniel Thompson
2014-08-18 14:12               ` Daniel Thompson
2014-08-18 14:28             ` [PATCH v9 12/16] serial: amba-pl011: Pass FIQ information to KGDB Daniel Thompson
2014-08-18 14:28               ` Daniel Thompson
2014-08-18 18:30               ` Peter Hurley
2014-08-18 18:30                 ` Peter Hurley
2014-08-19  9:08                 ` Daniel Thompson
2014-08-19  9:08                   ` Daniel Thompson
2014-08-19 11:58                   ` Peter Hurley
2014-08-19 11:58                     ` Peter Hurley
2014-08-19 12:51                     ` Daniel Thompson
2014-08-19 12:51                       ` Daniel Thompson
2014-08-18 14:28             ` [PATCH v9 13/16] serial: asc: Add support for KGDB's FIQ/NMI mode Daniel Thompson
2014-08-18 14:28               ` Daniel Thompson
2014-08-18 14:28               ` Daniel Thompson
2014-08-18 14:28             ` [PATCH v9 14/16] serial: asc: Adopt readl_/writel_relaxed() Daniel Thompson
2014-08-18 14:28               ` Daniel Thompson
2014-08-18 14:28               ` Daniel Thompson
2014-08-18 14:28             ` [PATCH v9 15/16] serial: imx: clean up imx_poll_get_char() Daniel Thompson
2014-08-18 14:28               ` Daniel Thompson
2014-08-18 14:28             ` [PATCH v9 16/16] serial: imx: Add support for KGDB's FIQ/NMI mode Daniel Thompson
2014-08-18 14:28               ` Daniel Thompson
2014-08-18 17:32               ` Dirk Behme
2014-08-18 17:32                 ` Dirk Behme

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.