Skip to contentSkip to conversation

kgdb: NMI/FIQ support for ARM

RFC Superseded Daniel Thompson 17 participants 262 messages May 14, 2014 – Sep 14, 2014 Page 1 of 2

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

cover kgdb: NMI/FIQ support for ARM

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
Signature · 1 line
1.9.0
#1 lore raw

RFC 1/8 arm: fiq: Allow EOI to be communicated to the intc

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.

---
 arch/arm/include/asm/fiq.h |  1 +
 arch/arm/kernel/fiq.c      | 11 +++++++++++
 2 files changed, 12 insertions(+)
arch/arm/include/asm/fiq.h +1 -0
index d493d0b..5a2a9b9 100644
@@ -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);
arch/arm/kernel/fiq.c +11 -0
index 918875d..defbe85 100644
@@ -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)
 {
Signature · 1 line
1.9.0
#2 lore raw

RFC 2/8 irqchip: gic: Provide support for interrupt grouping

In reply to Daniel Thompson

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).

---
 drivers/irqchip/irq-gic.c       | 35 ++++++++++++++++++++++++++++++-----
 include/linux/irqchip/arm-gic.h |  3 +++
 2 files changed, 33 insertions(+), 5 deletions(-)
drivers/irqchip/irq-gic.c +30 -5
index 57d165e..aa8efe4 100644
@@ -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);
 }
include/linux/irqchip/arm-gic.h +3 -0
index 7ed92d0..919502f 100644
@@ -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
Signature · 1 line
1.9.0
#3 lore raw

RFC 3/8 ARM: Move some macros from entry-armv to entry-header

In reply to Daniel Thompson

From: Anton Vorontsov <[email protected]>

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.

---
 arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
 arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 150 deletions(-)
arch/arm/kernel/entry-armv.S +1 -150
index 1879e8d..ed95b95 100644
@@ -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:
arch/arm/kernel/entry-header.S +164 -0

167 lines not on this page · raw message

Signature · 1 line
1.9.0
#4 lore raw

RFC 4/8 ARM: Add KGDB/KDB FIQ debugger generic code

In reply to Daniel Thompson

From: Anton Vorontsov <[email protected]>

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.

---
 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
arch/arm/Kconfig +2 -0
index db3c541..419fd0a 100644
@@ -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
arch/arm/Kconfig.debug +18 -0
index 6a2bcfd..1f1bec1 100644
@@ -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
arch/arm/include/asm/kgdb.h +7 -0
index 0a9d5dd..5de21f01 100644
@@ -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__ */
 
 /*
arch/arm/kernel/Makefile +1 -0
index 040619c..251f651 100644
@@ -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
arch/arm/kernel/kgdb_fiq.c new file +117 -0

117 lines not on this page · raw message

arch/arm/kernel/kgdb_fiq_entry.S new file +87 -0

87 lines not on this page · raw message

Signature · 1 line
1.9.0
#5 lore raw

RFC 5/8 serial: amba-pl011: Pass on FIQ information to KGDB.

In reply to Daniel Thompson

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).

---
 drivers/tty/serial/amba-pl011.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)
drivers/tty/serial/amba-pl011.c +17 -1
index dacf0a0..aac817a 100644
@@ -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;
 }
Signature · 1 line
1.9.0
#6 lore raw

RFC 6/8 serial: asc: Add support for KGDB's FIQ/NMI mode

In reply to Daniel Thompson

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).

---
 drivers/tty/serial/st-asc.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)
drivers/tty/serial/st-asc.c +25 -0
index c7f61ac..e93803f 100644
@@ -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;
 }
 
Signature · 1 line
1.9.0
#7 lore raw

RFC 7/8 ARM: VIC: Add vic_set_fiq function to select if an interrupt should generate an IRQ or FIQ

In reply to Daniel Thompson

From: Arve Hj?nnev?g <[email protected]>

---
 drivers/irqchip/irq-vic.c       | 23 +++++++++++++++++++++++
 include/linux/irqchip/arm-vic.h |  1 +
 2 files changed, 24 insertions(+)
drivers/irqchip/irq-vic.c +23 -0
index 7d35287..3eaa2e4 100644
@@ -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)
 {
include/linux/irqchip/arm-vic.h +1 -0
index ba46c79..61ee4c9 100644
@@ -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
Signature · 1 line
1.9.0
#8 lore raw

RFC 8/8 arm: fiq: Hack FIQ routing backdoors into GIC and VIC

In reply to Daniel Thompson

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.

---
 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(-)
arch/arm/boot/dts/stih416.dtsi +1 -1
index 78746d2..a288898 100644
@@ -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>;
arch/arm/boot/dts/vexpress-v2m-rs1.dtsi +1 -1
index ac870fb..fab2a40 100644
@@ -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";
 			};
arch/arm/kernel/fiq.c +39 -0
index defbe85..efce321 100644
@@ -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)
drivers/irqchip/irq-gic.c +27 -0
index aa8efe4..c25632b 100644
@@ -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) {
Signature · 1 line
1.9.0
#9 lore raw

v2 cover kgdb: NMI/FIQ support for ARM

In reply to Daniel Thompson

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
Signature · 1 line
1.9.0
#10 lore raw

RFC v2 1/10 arm: fiq: Allow EOI to be communicated to the intc

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().

Cc Russell King <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Nicolas Pitre <[email protected]>
---
 arch/arm/include/asm/fiq.h |  1 +
 arch/arm/kernel/fiq.c      | 11 +++++++++++
 2 files changed, 12 insertions(+)
arch/arm/include/asm/fiq.h +1 -0
index d493d0b..5a2a9b9 100644
@@ -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);
arch/arm/kernel/fiq.c +11 -0
index 918875d..defbe85 100644
@@ -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)
 {
Signature · 1 line
1.9.0
#11 lore raw

RFC v2 1/10 arm: fiq: Allow EOI to be communicated to the intc

arch/arm/kernel/fiq.c void disable_fiq(int fiq) · line 151

Quoted 5 lines · Daniel Thompson
arch/arm/kernel/fiq.c +5 -0
+
+	if (chip->irq_eoi)
+			chip->irq_eoi(irq_data);
+}
+

Looks like an extra tab here..

#12 lore raw

RFC v2 1/10 arm: fiq: Allow EOI to be communicated to the intc

In reply to Daniel Thompson

arch/arm/kernel/fiq.c void disable_fiq(int fiq) · line 150

Quoted 8 lines · Daniel Thompson
arch/arm/kernel/fiq.c +8 -0
+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.

Signature · 2 lines
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.
#13 lore raw

RFC v2 1/10 arm: fiq: Allow EOI to be communicated to the intc

Quoted 13 lines · Russell King - ARM Linux

arch/arm/kernel/fiq.c void disable_fiq(int fiq) · line 150

Quoted 8 lines · Daniel Thompson
arch/arm/kernel/fiq.c +8 -0
+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.

#14 lore raw

RFC v2 2/10 irqchip: gic: Provide support for interrupt grouping

In reply to Daniel Thompson

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).

Cc Thomas Gleixner <[email protected]>
Cc Jason Cooper <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Christoffer Dall <[email protected]>
Cc Sricharan R <[email protected]>
---
 drivers/irqchip/irq-gic.c       | 35 ++++++++++++++++++++++++++++++-----
 include/linux/irqchip/arm-gic.h |  3 +++
 2 files changed, 33 insertions(+), 5 deletions(-)
drivers/irqchip/irq-gic.c +30 -5
index 57d165e..aa8efe4 100644
@@ -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);
 }
include/linux/irqchip/arm-gic.h +3 -0
index 7ed92d0..919502f 100644
@@ -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
Signature · 1 line
1.9.0
#15 lore raw

RFC v2 3/10 irqchip: gic: Introduce shadow irqs for FIQ

In reply to Daniel Thompson

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.

Cc : Thomas Gleixner <[email protected]>
Cc Jason Cooper <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Christoffer Dall <[email protected]>
Cc Sricharan R <[email protected]>
---
 drivers/irqchip/irq-gic.c | 46 +++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 41 insertions(+), 5 deletions(-)
drivers/irqchip/irq-gic.c +41 -5
index aa8efe4..0c259ac 100644
@@ -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))
Signature · 1 line
1.9.0
#16 lore raw

RFC v2 4/10 ARM: vexpress: Extend UART with FIQ support

In reply to Daniel Thompson

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).

Cc Rob Herring <[email protected]>
Cc Pawel Moll <[email protected]>
Cc Mark Rutland <[email protected]>
Cc Ian Campbell <[email protected]>
Cc Kumar Gala <[email protected]>
Cc Russell King <[email protected]>
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(-)
arch/arm/boot/dts/vexpress-v2m-rs1.dtsi +4 -4
index ac870fb..e86936c 100644
@@ -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";
 			};
arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts +8 -2
index 9420053..9c489fa 100644
@@ -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"
 	};
arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts +7 -1
index 15f98cb..75821d2 100644
@@ -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"
 	};
arch/arm/boot/dts/vexpress-v2p-ca5s.dts +8 -2
index c544a55..930e2ef 100644
@@ -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"
 	};
Signature · 1 line
1.9.0
#17 lore raw

RFC v2 4/10 ARM: vexpress: Extend UART with FIQ support

arch/arm/boot/dts/vexpress-v2m-rs1.dtsi line 143

Quoted 6 lines · Daniel Thompson
arch/arm/boot/dts/vexpress-v2m-rs1.dtsi +1 -1
@@ -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.

Signature · 2 lines
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.
#18 lore raw

RFC v2 4/10 ARM: vexpress: Extend UART with FIQ support

Quoted 11 lines · Russell King - ARM Linux

arch/arm/boot/dts/vexpress-v2m-rs1.dtsi line 143

Quoted 6 lines · Daniel Thompson
arch/arm/boot/dts/vexpress-v2m-rs1.dtsi +1 -1
@@ -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.

arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts line 236

Quoted 8 lines
arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts +1 -1
@@ -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.

#19 lore raw

RFC v2 4/10 ARM: vexpress: Extend UART with FIQ support

Quoted 12 lines · Daniel Thompson
Quoted 11 lines · Russell King - ARM Linux

arch/arm/boot/dts/vexpress-v2m-rs1.dtsi line 143

Quoted 6 lines · Daniel Thompson
arch/arm/boot/dts/vexpress-v2m-rs1.dtsi +1 -1
@@ -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

Quoted 7 lines

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

#20 lore raw

RFC v2 4/10 ARM: vexpress: Extend UART with FIQ support

Quoted 25 lines · Rob Herring
Quoted 12 lines · Daniel Thompson
Quoted 11 lines · Russell King - ARM Linux

arch/arm/boot/dts/vexpress-v2m-rs1.dtsi line 143

Quoted 6 lines · Daniel Thompson
arch/arm/boot/dts/vexpress-v2m-rs1.dtsi +1 -1
@@ -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

Quoted 7 lines

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).

Quoted 8 lines

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.

#21 lore raw

RFC v2 5/10 ARM: STi: STiH41x: Extend UART with FIQ support.

In reply to Daniel Thompson

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).

Cc Srinivas Kandagatla <[email protected]>
Cc Maxime Coquelin <[email protected]>
Cc Patrice Chotard <[email protected]>
Cc Rob Herring <[email protected]>
Cc Pawel Moll <[email protected]>
Cc Mark Rutland <[email protected]>
Cc Ian Campbell <[email protected]>
Cc Kumar Gala <[email protected]>
Cc Russell King <[email protected]>
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(-)
arch/arm/boot/dts/stih415.dtsi +2 -2
index d89064c..b2c9df4 100644
@@ -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>;
arch/arm/boot/dts/stih416.dtsi +2 -2
index 78746d2..fdf7b43 100644
@@ -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>;
Signature · 1 line
1.9.0
#22 lore raw

RFC v2 6/10 irqchip: vic: Introduce shadow irqs for FIQ

In reply to Daniel Thompson

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.

Cc Hartley Sweeten <[email protected]>
Cc Ryan Mallon <[email protected]>
Cc Russell King <[email protected]>
Cc Ben Dooks <[email protected]>
Cc Kukjin Kim <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Jason Cooper <[email protected]>
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(-)
arch/arm/mach-ep93xx/core.c +4 -2
index 0e571f1..aa26411 100644
@@ -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);
 }
 
 
arch/arm/mach-netx/generic.c +2 -1
index db25b0c..5398dcd 100644
@@ -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,
arch/arm/mach-s3c64xx/common.c +4 -2
index 5c45aae..b98dd48 100644
@@ -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))
arch/arm/mach-versatile/core.c +5 -4
index f2c89fb..3444ca8 100644
@@ -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 */
arch/arm/mach-versatile/include/mach/irqs.h +38 -38

85 lines not on this page · raw message

arch/arm/plat-samsung/s5p-irq.c +2 -1
index ddfaca9..ddb1138 100644
@@ -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
 }
drivers/irqchip/irq-vic.c +71 -16

196 lines not on this page · raw message

include/linux/irqchip/arm-vic.h +6 -2
index ba46c79..fae480d 100644
@@ -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);
 
Signature · 1 line
1.9.0
#23 lore raw

RFC v2 7/10 ARM: Move some macros from entry-armv to entry-header

In reply to Daniel Thompson

From: Anton Vorontsov <[email protected]>

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.

Cc Russell King <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc Frederic Weisbecker <[email protected]>
---
 arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
 arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 150 deletions(-)
arch/arm/kernel/entry-armv.S +1 -150
index 1879e8d..ed95b95 100644
@@ -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:
arch/arm/kernel/entry-header.S +164 -0

167 lines not on this page · raw message

Signature · 1 line
1.9.0
#24 lore raw

RFC v2 8/10 ARM: Add KGDB/KDB FIQ debugger generic code

In reply to Daniel Thompson

From: Anton Vorontsov <[email protected]>

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.

---
 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
arch/arm/Kconfig +2 -0
index db3c541..419fd0a 100644
@@ -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
arch/arm/Kconfig.debug +18 -0
index 6a2bcfd..1f1bec1 100644
@@ -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
arch/arm/include/asm/kgdb.h +7 -0
index 0a9d5dd..5de21f01 100644
@@ -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__ */
 
 /*
arch/arm/kernel/Makefile +1 -0
index 040619c..251f651 100644
@@ -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
arch/arm/kernel/kgdb_fiq.c new file +117 -0

117 lines not on this page · raw message

arch/arm/kernel/kgdb_fiq_entry.S new file +87 -0

87 lines not on this page · raw message

Signature · 1 line
1.9.0
#25 lore raw

RFC v2 9/10 serial: amba-pl011: Pass on FIQ information to KGDB.

In reply to Daniel Thompson

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).

Cc Russell King <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Jiri Slaby <[email protected]>
Cc linux-serial at vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 101 ++++++++++++++++++++++++----------------
 1 file changed, 60 insertions(+), 41 deletions(-)
drivers/tty/serial/amba-pl011.c +60 -41
index dacf0a0..d34c72c 100644
@@ -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;
 }
Signature · 1 line
1.9.0
#26 lore raw

RFC v2 10/10 serial: asc: Add support for KGDB's FIQ/NMI mode

In reply to Daniel Thompson

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 .

Cc Srinivas Kandagatla <[email protected]>
Cc Maxime Coquelin <[email protected]>
Cc Patrice Chotard <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Jiri Slaby <[email protected]>
Cc kernel at stlinux.com
Cc linux-serial at vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
drivers/tty/serial/st-asc.c +27 -0
index c7f61ac..328720f 100644
@@ -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);
Signature · 1 line
1.9.0
#27 lore raw

RFC v2 10/10 serial: asc: Add support for KGDB's FIQ/NMI mode

Hi Dan,

Quoted 20 lines · Daniel Thompson

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 .

Cc Srinivas Kandagatla <[email protected]>
Cc Maxime Coquelin <[email protected]>
Cc Patrice Chotard <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Jiri Slaby <[email protected]>
Cc kernel at stlinux.com
Cc linux-serial at vger.kernel.org
Quoted 4 lines
---
  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.

Quoted 20 lines
drivers/tty/serial/st-asc.c +2 -0
index c7f61ac..328720f 100644
@@ -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;
  };

...

drivers/tty/serial/st-asc.c static struct uart_ops asc_uart_ops = { · line 689

Quoted 10 lines
  #ifdef CONFIG_CONSOLE_POLL
drivers/tty/serial/st-asc.c +4 -0
+#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.

drivers/tty/serial/st-asc.c static int asc_init_port(struct asc_port *ascport, · line 703

Quoted 9 lines

static int asc_init_port(struct asc_port *ascport,
struct platform_device *pdev)
{

drivers/tty/serial/st-asc.c +1 -0
@@ -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

Quoted 3 lines
drivers/tty/serial/st-asc.c +0 -0
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	port->membase = devm_ioremap_resource(&pdev->dev, res);
#28 lore raw

v3 cover kgdb: NMI/FIQ support for ARM

In reply to Daniel Thompson

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
Signature · 1 line
1.9.0
#29 lore raw

RFC v3 1/9 arm: fiq: arbitrary mappings from IRQ to FIQ virqs

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.

Cc Russell King <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Nicolas Pitre <[email protected]>
---
 arch/arm/include/asm/fiq.h |  2 ++
 arch/arm/kernel/fiq.c      | 57 +++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 53 insertions(+), 6 deletions(-)
arch/arm/include/asm/fiq.h +2 -0
index d493d0b..75d98c6 100644
@@ -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);
arch/arm/kernel/fiq.c +51 -6

99 lines not on this page · raw message

Signature · 1 line
1.9.0
#30 lore raw

RFC v3 1/9 arm: fiq: arbitrary mappings from IRQ to FIQ virqs

Quoted 8 lines · Daniel Thompson

static int fiq_def_op(void *ref, int relinquish)
{

arch/arm/kernel/fiq.c +4 -1
-	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));
+	}

...

arch/arm/kernel/fiq.c EXPORT_SYMBOL(__set_fiq_regs); /* defined in fiqasm.S */ · line 200

Quoted 6 lines

void __init init_FIQ(int start)
{

arch/arm/kernel/fiq.c +0 -2
-	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.

Signature · 2 lines
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.
#31 lore raw

RFC v3 1/9 arm: fiq: arbitrary mappings from IRQ to FIQ virqs

Quoted 10 lines · Russell King - ARM Linux
Quoted 8 lines · Daniel Thompson

static int fiq_def_op(void *ref, int relinquish)
{

arch/arm/kernel/fiq.c +4 -1
-	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));
+	}

...

Quoted 11 lines

arch/arm/kernel/fiq.c EXPORT_SYMBOL(__set_fiq_regs); /* defined in fiqasm.S */ · line 200

Quoted 6 lines

void __init init_FIQ(int start)
{

arch/arm/kernel/fiq.c +0 -2
-	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.

#32 lore raw

RFC v3 1/9 arm: fiq: arbitrary mappings from IRQ to FIQ virqs

In reply to Daniel Thompson
Quoted 8 lines · Daniel Thompson

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

#33 lore raw

RFC v3 1/9 arm: fiq: arbitrary mappings from IRQ to FIQ virqs

Quoted 7 lines · Linus Walleij
Quoted 4 lines · Daniel Thompson

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.

Quoted 7 lines
Quoted 4 lines

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.

Quoted 14 lines

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.

Quoted 8 lines

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?

#34 lore raw

RFC v3 1/9 arm: fiq: arbitrary mappings from IRQ to FIQ virqs

In reply to Daniel Thompson
Quoted 8 lines · Daniel Thompson

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

#35 lore raw

RFC v3 1/9 arm: fiq: arbitrary mappings from IRQ to FIQ virqs

Quoted 11 lines · Rob Herring
Quoted 8 lines · Daniel Thompson

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.

Quoted 4 lines

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.

#36 lore raw

RFC v3 2/9 arm: fiq: Allow EOI to be communicated to the intc

In reply to Daniel Thompson

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.

Cc Russell King <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Nicolas Pitre <[email protected]>
---
 arch/arm/include/asm/fiq.h |  2 ++
 arch/arm/kernel/fiq.c      | 28 ++++++++++++++++++++++++++++
 2 files changed, 30 insertions(+)
arch/arm/include/asm/fiq.h +2 -0
index 75d98c6..10d22eb 100644
@@ -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: */
arch/arm/kernel/fiq.c +28 -0
index 177939c..ed01162 100644
@@ -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;
Signature · 1 line
1.9.0
#37 lore raw

RFC v3 3/9 irqchip: gic: Provide support for interrupt grouping

In reply to Daniel Thompson

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).

Cc Thomas Gleixner <[email protected]>
Cc Jason Cooper <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Christoffer Dall <[email protected]>
Cc Sricharan R <[email protected]>
---
 drivers/irqchip/irq-gic.c       | 35 ++++++++++++++++++++++++++++++-----
 include/linux/irqchip/arm-gic.h |  3 +++
 2 files changed, 33 insertions(+), 5 deletions(-)
drivers/irqchip/irq-gic.c +30 -5
index 57d165e..aa8efe4 100644
@@ -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);
 }
include/linux/irqchip/arm-gic.h +3 -0
index 7ed92d0..919502f 100644
@@ -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
Signature · 1 line
1.9.0
#38 lore raw

RFC v3 3/9 irqchip: gic: Provide support for interrupt grouping

Quoted 20 lines · Daniel Thompson
drivers/irqchip/irq-gic.c +9 -0
index 57d165e..aa8efe4 100644
@@ -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.
 	 */

drivers/irqchip/irq-gic.c static void __init gic_dist_init(struct gic_chip_data *gic) · line 431

Quoted 10 lines
drivers/irqchip/irq-gic.c +6 -1
 	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

#39 lore raw

RFC v3 4/9 irqchip: gic: Introduce shadow irqs for FIQ

In reply to Daniel Thompson

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.

Cc Thomas Gleixner <[email protected]>
Cc Jason Cooper <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Christoffer Dall <[email protected]>
Cc Sricharan R <[email protected]>
---
 drivers/irqchip/irq-gic.c | 62 ++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 56 insertions(+), 6 deletions(-)
drivers/irqchip/irq-gic.c +56 -6
index aa8efe4..9a4712d 100644
@@ -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);
Signature · 1 line
1.9.0
#40 lore raw

RFC v3 4/9 irqchip: gic: Introduce shadow irqs for FIQ

Quoted 149 lines · Daniel Thompson

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.

Cc Thomas Gleixner <[email protected]>
Cc Jason Cooper <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Christoffer Dall <[email protected]>
Cc Sricharan R <[email protected]>
---
 drivers/irqchip/irq-gic.c | 62 ++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 56 insertions(+), 6 deletions(-)
drivers/irqchip/irq-gic.c +45 -6
index aa8efe4..9a4712d 100644
@@ -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;
 

drivers/irqchip/irq-gic.c void __init gic_init_bases(unsigned int gic_nr, int irq_start, · line 1099

Quoted 10 lines
drivers/irqchip/irq-gic.c +10 -0
+#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.

#41 lore raw

RFC v3 4/9 irqchip: gic: Introduce shadow irqs for FIQ

Quoted 20 lines · Peter De Schrijver
Quoted 20 lines
drivers/irqchip/irq-gic.c +5 -5
@@ -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;
 
Quoted 14 lines

drivers/irqchip/irq-gic.c void __init gic_init_bases(unsigned int gic_nr, int irq_start, · line 1099

Quoted 10 lines
drivers/irqchip/irq-gic.c +10 -0
+#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

#42 lore raw

RFC v3 5/9 irqchip: vic: Introduce shadow irqs for FIQ

In reply to Daniel Thompson

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.

Cc Hartley Sweeten <[email protected]>
Cc Ryan Mallon <[email protected]>
Cc Russell King <[email protected]>
Cc Ben Dooks <[email protected]>
Cc Kukjin Kim <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Jason Cooper <[email protected]>
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(-)
arch/arm/mach-ep93xx/core.c +4 -2
index 0e571f1..aa26411 100644
@@ -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);
 }
 
 
arch/arm/mach-netx/generic.c +2 -1
index db25b0c..5398dcd 100644
@@ -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,
arch/arm/mach-s3c64xx/common.c +4 -2
index 5c45aae..b98dd48 100644
@@ -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))
arch/arm/mach-versatile/core.c +5 -4
index f2c89fb..3444ca8 100644
@@ -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 */
arch/arm/mach-versatile/include/mach/irqs.h +4 -1
index 0fd771c..68171d9 100644
@@ -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)
arch/arm/plat-samsung/s5p-irq.c +2 -1
index ddfaca9..ddb1138 100644
@@ -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
 }
drivers/irqchip/irq-vic.c +86 -16

223 lines not on this page · raw message

include/linux/irqchip/arm-vic.h +6 -2
index ba46c79..fae480d 100644
@@ -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);
 
Signature · 1 line
1.9.0
#43 lore raw

RFC v3 6/9 ARM: Move some macros from entry-armv to entry-header

In reply to Daniel Thompson

From: Anton Vorontsov <[email protected]>

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.

Cc Russell King <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc Frederic Weisbecker <[email protected]>
---
 arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
 arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 150 deletions(-)
arch/arm/kernel/entry-armv.S +1 -150
index 1879e8d..ed95b95 100644
@@ -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:
arch/arm/kernel/entry-header.S +164 -0

167 lines not on this page · raw message

Signature · 1 line
1.9.0
#44 lore raw

RFC v3 7/9 ARM: Add KGDB/KDB FIQ debugger generic code

In reply to Daniel Thompson

From: Anton Vorontsov <[email protected]>

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.

---
 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
arch/arm/Kconfig +2 -0
index db3c541..419fd0a 100644
@@ -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
arch/arm/Kconfig.debug +18 -0
index 6a2bcfd..1f1bec1 100644
@@ -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
arch/arm/include/asm/kgdb.h +7 -0
index 0a9d5dd..5de21f01 100644
@@ -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__ */
 
 /*
arch/arm/kernel/Makefile +1 -0
index 040619c..251f651 100644
@@ -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
arch/arm/kernel/kgdb_fiq.c new file +124 -0

124 lines not on this page · raw message

arch/arm/kernel/kgdb_fiq_entry.S new file +87 -0

87 lines not on this page · raw message

Signature · 1 line
1.9.0
#45 lore raw

RFC v3 8/9 serial: amba-pl011: Pass on FIQ information to KGDB.

In reply to Daniel Thompson

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).

Cc Russell King <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Jiri Slaby <[email protected]>
Cc linux-serial at vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 99 ++++++++++++++++++++++++-----------------
 1 file changed, 58 insertions(+), 41 deletions(-)
drivers/tty/serial/amba-pl011.c +58 -41
index dacf0a0..778fd38 100644
@@ -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;
 }
Signature · 1 line
1.9.0
#46 lore raw

RFC v3 9/9 serial: asc: Add support for KGDB's FIQ/NMI mode

In reply to Daniel Thompson

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 .

Cc Srinivas Kandagatla <[email protected]>
Cc Maxime Coquelin <[email protected]>
Cc Patrice Chotard <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Jiri Slaby <[email protected]>
Cc kernel at stlinux.com
Cc linux-serial at vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
drivers/tty/serial/st-asc.c +23 -0
index c7f61ac..4f376d8 100644
@@ -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 */
Signature · 1 line
1.9.0
#47 lore raw

v4 cover kgdb: NMI/FIQ support for ARM

In reply to Daniel Thompson

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
Signature · 1 line
1.9.3
#48 lore raw

PATCH v4 1/13 arm: fiq: Add callbacks to manage FIQ routings

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.

Cc Russell King <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Nicolas Pitre <[email protected]>
---
 arch/arm/include/asm/fiq.h |   7 +++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 108 insertions(+), 2 deletions(-)
arch/arm/include/asm/fiq.h +7 -0
index d493d0b..a7806ef 100644
@@ -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);
arch/arm/kernel/fiq.c +101 -2

141 lines not on this page · raw message

Signature · 1 line
1.9.3
#49 lore raw

PATCH v4 2/13 arm: fiq: Allow EOI to be communicated to the intc

In reply to Daniel Thompson

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.

Cc Russell King <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Nicolas Pitre <[email protected]>
---
 arch/arm/include/asm/fiq.h | 6 ++++++
 arch/arm/kernel/fiq.c      | 9 +++++++++
 2 files changed, 15 insertions(+)
arch/arm/include/asm/fiq.h +6 -0
index a7806ef..e5d9458 100644
@@ -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);
 
arch/arm/kernel/fiq.c +9 -0
index 567f8fd..edde332 100644
@@ -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);
Signature · 1 line
1.9.3
#50 lore raw

PATCH v4 3/13 irqchip: gic: Provide support for interrupt grouping

In reply to Daniel Thompson

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.

Cc Thomas Gleixner <[email protected]>
Cc Jason Cooper <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Christoffer Dall <[email protected]>
Cc Sricharan R <[email protected]>
---
 drivers/irqchip/irq-gic.c | 99 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 94 insertions(+), 5 deletions(-)
drivers/irqchip/irq-gic.c +94 -5
index 7e11c9d..bbffca3 100644
@@ -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,
Signature · 1 line
1.9.3
#51 lore raw

PATCH v4 4/13 irqchip: gic: Add support for FIQ management

In reply to Daniel Thompson

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.

Cc Thomas Gleixner <[email protected]>
Cc Jason Cooper <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Christoffer Dall <[email protected]>
Cc Sricharan R <[email protected]>
---
 drivers/irqchip/irq-gic.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)
drivers/irqchip/irq-gic.c +58 -0
index bbffca3..0300c08 100644
@@ -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,
Signature · 1 line
1.9.3
#52 lore raw

PATCH v4 5/13 irqchip: gic: Remove spin locks from eoi_irq

In reply to Daniel Thompson

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.

Cc Thomas Gleixner <[email protected]>
Cc Jason Cooper <[email protected]>
Cc Peter De Schrijver <[email protected]>
---
 drivers/irqchip/irq-gic.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)
drivers/irqchip/irq-gic.c +1 -11
index 0300c08..1cbff1d 100644
@@ -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
Signature · 1 line
1.9.3
#53 lore raw

PATCH v4 6/13 irqchip: vic: Add support for FIQ management

In reply to Daniel Thompson

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).

Cc Hartley Sweeten <[email protected]>
Cc Ryan Mallon <[email protected]>
Cc Russell King <[email protected]>
Cc Ben Dooks <[email protected]>
Cc Kukjin Kim <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Jason Cooper <[email protected]>
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(-)
arch/arm/mach-versatile/core.c +1 -1
index be83ba2..1abf360 100644
@@ -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);
 
drivers/irqchip/irq-vic.c +73 -19

173 lines not on this page · raw message

include/linux/irqchip/arm-vic.h +4 -2
index ba46c79..30ab39f 100644
@@ -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);
 
Signature · 1 line
1.9.3
#54 lore raw

PATCH v4 7/13 ARM: Move some macros from entry-armv to entry-header

In reply to Daniel Thompson

From: Anton Vorontsov <[email protected]>

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.

Cc Russell King <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc Frederic Weisbecker <[email protected]>
---
 arch/arm/kernel/entry-armv.S   | 151 +-----------------
 arch/arm/kernel/entry-header.S | 350 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 351 insertions(+), 150 deletions(-)
arch/arm/kernel/entry-armv.S +1 -150
index 52a949a..4172cd6 100644
@@ -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:
arch/arm/kernel/entry-header.S +350 -0

353 lines not on this page · raw message

Signature · 1 line
1.9.3
#55 lore raw

PATCH v4 8/13 ARM: Add KGDB/KDB FIQ debugger generic code

In reply to Daniel Thompson

From: Anton Vorontsov <[email protected]>

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.

---
 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
arch/arm/Kconfig +2 -0
index 87b63fd..32795c2 100644
@@ -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
arch/arm/Kconfig.debug +18 -0
index 26536f7..c7342b6 100644
@@ -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
arch/arm/include/asm/kgdb.h +7 -0
index 0a9d5dd..5de21f01 100644
@@ -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__ */
 
 /*
arch/arm/kernel/Makefile +1 -0
index 38ddd9f..30ee8f3 100644
@@ -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
arch/arm/kernel/entry-header.S +0 -186

192 lines not on this page · raw message

arch/arm/kernel/kgdb_fiq.c new file +124 -0

124 lines not on this page · raw message

arch/arm/kernel/kgdb_fiq_entry.S new file +87 -0

87 lines not on this page · raw message

Signature · 1 line
1.9.3
#56 lore raw

PATCH v4 9/13 serial: amba-pl011: Pass FIQ information to KGDB.

In reply to Daniel Thompson

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).

Cc Russell King <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Jiri Slaby <[email protected]>
Cc linux-serial at vger.kernel.org
---
 drivers/tty/serial/amba-pl011.c | 99 ++++++++++++++++++++++++-----------------
 1 file changed, 58 insertions(+), 41 deletions(-)
drivers/tty/serial/amba-pl011.c +58 -41
index 908a6e3..00ba4b6 100644
@@ -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;
 }
Signature · 1 line
1.9.3
#57 lore raw

PATCH v4 9/13 serial: amba-pl011: Pass FIQ information to KGDB.

Quoted 11 lines · Daniel Thompson

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).

Quoted 6 lines
Cc Russell King <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Jiri Slaby <[email protected]>
Cc linux-serial at vger.kernel.org

---

#58 lore raw

PATCH v4 10/13 serial: asc: Add support for KGDB's FIQ/NMI mode

In reply to Daniel Thompson

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 .

Cc Srinivas Kandagatla <[email protected]>
Cc Maxime Coquelin <[email protected]>
Cc Patrice Chotard <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Jiri Slaby <[email protected]>
Cc kernel at stlinux.com
Cc linux-serial at vger.kernel.org
---
 drivers/tty/serial/st-asc.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
drivers/tty/serial/st-asc.c +23 -0
index c7f61ac..4f376d8 100644
@@ -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 */
Signature · 1 line
1.9.3
#59 lore raw

PATCH v4 10/13 serial: asc: Add support for KGDB's FIQ/NMI mode

Quoted 18 lines · Daniel Thompson

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 .

Cc Srinivas Kandagatla <[email protected]>
Cc Maxime Coquelin <[email protected]>
Cc Patrice Chotard <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Jiri Slaby <[email protected]>
Cc kernel at stlinux.com
Cc linux-serial at vger.kernel.org
Quoted 1 line

---

#60 lore raw

PATCH v4 11/13 serial: asc: Adopt readl_/writel_relaxed()

In reply to Daniel Thompson

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.

Cc Srinivas Kandagatla <[email protected]>
Cc Maxime Coquelin <[email protected]>
Cc Patrice Chotard <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Jiri Slaby <[email protected]>
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(-)
drivers/tty/serial/st-asc.c +10 -1
index 4f376d8..58aa1c6 100644
@@ -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
 }
 
 /*
Signature · 1 line
1.9.3
#61 lore raw

PATCH v4 11/13 serial: asc: Adopt readl_/writel_relaxed()

Hi Dan,

Quoted 10 lines · Daniel Thompson

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.

Quoted 6 lines

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

Quoted 40 lines
Cc Srinivas Kandagatla <[email protected]>
Cc Maxime Coquelin <[email protected]>
Cc Patrice Chotard <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Jiri Slaby <[email protected]>
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(-)
drivers/tty/serial/st-asc.c +10 -1
index 4f376d8..58aa1c6 100644
@@ -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
  }
 
  /*
#62 lore raw

PATCH v4 11/13 serial: asc: Adopt readl_/writel_relaxed()

Quoted 19 lines · Srinivas Kandagatla

Hi Dan,

Quoted 10 lines · Daniel Thompson

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.

Quoted 6 lines

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.

Quoted 5 lines

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).

Quoted 2 lines

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.

Quoted 46 lines

--srini

Quoted 42 lines
Cc Srinivas Kandagatla <[email protected]>
Cc Maxime Coquelin <[email protected]>
Cc Patrice Chotard <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Jiri Slaby <[email protected]>
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(-)
drivers/tty/serial/st-asc.c +10 -1
index 4f376d8..58aa1c6 100644
@@ -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
  }

/*

#63 lore raw

PATCH v4 11/13 serial: asc: Adopt readl_/writel_relaxed()

Hi Daniel,

Quoted 27 lines · Daniel Thompson
Quoted 20 lines · Srinivas Kandagatla

Hi Dan,

Quoted 11 lines · Daniel Thompson

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.

Quoted 6 lines

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.

Quoted 5 lines

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.

Quoted 5 lines

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

Quoted 50 lines
Quoted 4 lines

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.

Quoted 31 lines

--srini

Quoted 27 lines

Srinivas Kandagatla <[email protected]> Cc: Maxime Coquelin <[email protected]> Cc: Patrice Chotard <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Cc: Jiri Slaby <[email protected]>
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(-)

(quoted diff) +0 -0

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 }

/*

#64 lore raw

PATCH v4 11/13 serial: asc: Adopt readl_/writel_relaxed()

In reply to Daniel Thompson
Quoted 26 lines · Daniel Thompson
Quoted 19 lines · Srinivas Kandagatla

Hi Dan,

Quoted 10 lines · Daniel Thompson

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.

Quoted 6 lines

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.

Quoted 5 lines

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.

Quoted 5 lines

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?

Quoted 1 line

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.

Quoted 8 lines
Quoted 3 lines

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.

Quoted 3 lines

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

Quoted 52 lines

Don't feel that strongly though. Can easily change it if you're unconvinced.

Quoted 46 lines

--srini

Quoted 42 lines
Cc Srinivas Kandagatla <[email protected]>
Cc Maxime Coquelin <[email protected]>
Cc Patrice Chotard <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Jiri Slaby <[email protected]>
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(-)
drivers/tty/serial/st-asc.c +10 -1
index 4f376d8..58aa1c6 100644
@@ -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
   }
   /*
#65 lore raw

PATCH v4 11/13 serial: asc: Adopt readl_/writel_relaxed()

Quoted 6 lines · Srinivas Kandagatla
Quoted 6 lines
Quoted 5 lines

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.

Quoted 8 lines
Quoted 5 lines

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.

Quoted 8 lines
Quoted 7 lines
Quoted 2 lines

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)?

Quoted 9 lines
Quoted 3 lines

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.

#66 lore raw

PATCH v4 12/13 serial: imx: clean up imx_poll_get_char()

In reply to Daniel Thompson

From: Dirk Behme <[email protected]>

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>
Cc Greg Kroah-Hartman <[email protected]>
Cc Jiri Slaby <[email protected]>
Cc linux-serial at vger.kernel.org
---
 drivers/tty/serial/imx.c | 29 ++++-------------------------
 1 file changed, 4 insertions(+), 25 deletions(-)
drivers/tty/serial/imx.c +4 -25
index e2f9387..25ed1d2 100644
@@ -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)
Signature · 1 line
1.9.3
#67 lore raw

PATCH v4 13/13 serial: imx: Add support for KGDB's FIQ/NMI mode

In reply to Daniel Thompson

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).

Cc Greg Kroah-Hartman <[email protected]>
Cc Jiri Slaby <[email protected]>
Cc linux-serial at vger.kernel.org
---
 drivers/tty/serial/imx.c | 71 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 52 insertions(+), 19 deletions(-)
drivers/tty/serial/imx.c +52 -19
index 25ed1d2..a2baf7e 100644
@@ -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
Signature · 1 line
1.9.3
#68 lore raw

v6 cover arm: KGDB NMI/FIQ support

In reply to Daniel Thompson

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

#69 lore raw

PATCH v6 1/4 arm: fiq: Add callbacks to manage FIQ routings

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.

Cc Russell King <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Nicolas Pitre <[email protected]>
---
 arch/arm/include/asm/fiq.h |   7 +++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 108 insertions(+), 2 deletions(-)
arch/arm/include/asm/fiq.h +7 -0
index d493d0b..a7806ef 100644
@@ -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);
arch/arm/kernel/fiq.c +101 -2

141 lines not on this page · raw message

Signature · 1 line
1.9.3
Acked-by on v6 1/4
#70 lore raw

Re: [PATCH v6 1/4] arm: fiq: Add callbacks to manage FIQ routings

Quoted 17 lines · Daniel Thompson

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.

Cc Russell King <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Nicolas Pitre <[email protected]>
---
 arch/arm/include/asm/fiq.h |   7 +++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 108 insertions(+), 2 deletions(-)

[...]

arch/arm/kernel/fiq.c void release_fiq(struct fiq_handler *f) · line 196

Quoted 11 lines
arch/arm/kernel/fiq.c +11 -0
+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...

Nicolas

#71 lore raw

Re: [PATCH v6 1/4] arm: fiq: Add callbacks to manage FIQ routings

Quoted 22 lines · Nicolas Pitre
Quoted 17 lines · Daniel Thompson

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.

Cc Russell King <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Nicolas Pitre <[email protected]>
---
 arch/arm/include/asm/fiq.h |   7 +++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 108 insertions(+), 2 deletions(-)

[...]

Quoted 13 lines

arch/arm/kernel/fiq.c void release_fiq(struct fiq_handler *f) · line 196

Quoted 11 lines
arch/arm/kernel/fiq.c +11 -0
+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.

#72 lore raw

PATCH v6 2/4 arm: fiq: Allow EOI to be communicated to the intc

In reply to Daniel Thompson

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.

Cc Russell King <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Nicolas Pitre <[email protected]>
---
 arch/arm/include/asm/fiq.h | 6 ++++++
 arch/arm/kernel/fiq.c      | 9 +++++++++
 2 files changed, 15 insertions(+)
arch/arm/include/asm/fiq.h +6 -0
index a7806ef..e5d9458 100644
@@ -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);
 
arch/arm/kernel/fiq.c +9 -0
index 567f8fd..edde332 100644
@@ -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);
Signature · 1 line
1.9.3
Acked-by on v6 2/4
#73 lore raw

Re: [PATCH v6 2/4] arm: fiq: Allow EOI to be communicated to the intc

Quoted 9 lines · Daniel Thompson

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.

Cc Russell King <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Nicolas Pitre <[email protected]>
Quoted 52 lines
---
 arch/arm/include/asm/fiq.h | 6 ++++++
 arch/arm/kernel/fiq.c      | 9 +++++++++
 2 files changed, 15 insertions(+)
arch/arm/include/asm/fiq.h +6 -0
index a7806ef..e5d9458 100644
@@ -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);
 
arch/arm/kernel/fiq.c +9 -0
index 567f8fd..edde332 100644
@@ -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);
Signature · 1 line
1.9.3
#74 lore raw

PATCH v6 3/4 ARM: Move some macros from entry-armv to entry-header

In reply to Daniel Thompson

From: Anton Vorontsov <[email protected]>

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.

Cc Russell King <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc Frederic Weisbecker <[email protected]>
---
 arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
 arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 150 deletions(-)
arch/arm/kernel/entry-armv.S +1 -150
index 52a949a..4172cd6 100644
@@ -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:
arch/arm/kernel/entry-header.S +164 -0

167 lines not on this page · raw message

Signature · 1 line
1.9.3
Acked-by on v6 3/4
#75 lore raw

Re: [PATCH v6 3/4] ARM: Move some macros from entry-armv to entry-header

Quoted 15 lines · Daniel Thompson

From: Anton Vorontsov <[email protected]>

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.

Quoted 7 lines
Cc Russell King <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Quoted 365 lines
---
 arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
 arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 150 deletions(-)
arch/arm/kernel/entry-armv.S +1 -150
index 52a949a..4172cd6 100644
@@ -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:
arch/arm/kernel/entry-header.S +164 -0
index 5d702f8..eb2c426 100644
@@ -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
+
+
Signature · 1 line
1.9.3
#76 lore raw

PATCH v6 4/4 ARM: Add KGDB/KDB FIQ debugger generic code

In reply to Daniel Thompson

From: Anton Vorontsov <[email protected]>

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.

---
 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
arch/arm/Kconfig +2 -0
index 245058b..f385b27 100644
@@ -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
arch/arm/Kconfig.debug +18 -0
index 26536f7..c7342b6 100644
@@ -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
arch/arm/include/asm/kgdb.h +7 -0
index 0a9d5dd..5de21f01 100644
@@ -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__ */
 
 /*
arch/arm/kernel/Makefile +1 -0
index 38ddd9f..30ee8f3 100644
@@ -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
arch/arm/kernel/kgdb_fiq.c new file +124 -0

124 lines not on this page · raw message

arch/arm/kernel/kgdb_fiq_entry.S new file +87 -0

87 lines not on this page · raw message

Signature · 1 line
1.9.3
#77 lore raw

Re: [PATCH v6 4/4] ARM: Add KGDB/KDB FIQ debugger generic code

arch/arm/kernel/kgdb_fiq_entry.S line 37

Quoted 3 lines · Daniel Thompson
arch/arm/kernel/kgdb_fiq_entry.S new file +3 -0
+	.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?

arch/arm/kernel/kgdb_fiq_entry.S line 40

Quoted 3 lines
arch/arm/kernel/kgdb_fiq_entry.S new file +3 -0
+	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).

arch/arm/kernel/kgdb_fiq_entry.S line 41

Quoted 1 line
arch/arm/kernel/kgdb_fiq_entry.S new file +1 -0
+	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.

arch/arm/kernel/kgdb_fiq_entry.S line 44

Quoted 3 lines
arch/arm/kernel/kgdb_fiq_entry.S new file +3 -0
+	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...

arch/arm/kernel/kgdb_fiq_entry.S line 45

Quoted 1 line
arch/arm/kernel/kgdb_fiq_entry.S new file +1 -0
+	ldr	r0, [r0, #S_R0]

Load the calling mode's R0 value.

arch/arm/kernel/kgdb_fiq_entry.S line 46

Quoted 1 line
arch/arm/kernel/kgdb_fiq_entry.S new file +1 -0
+	ldmia	r8, {pc}^

And return (restoring CPSR from SPSR_fiq).

This looks pretty good except for the niggles...

Signature · 2 lines
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.
#78 lore raw

Re: [PATCH v6 4/4] ARM: Add KGDB/KDB FIQ debugger generic code

Quoted 8 lines · Russell King - ARM Linux

arch/arm/kernel/kgdb_fiq_entry.S line 37

Quoted 3 lines · Daniel Thompson
arch/arm/kernel/kgdb_fiq_entry.S new file +3 -0
+	.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.

Quoted 2 lines

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.

Quoted 7 lines

arch/arm/kernel/kgdb_fiq_entry.S line 40

Quoted 3 lines
arch/arm/kernel/kgdb_fiq_entry.S new file +3 -0
+	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.

Quoted 4 lines

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.

Quoted 8 lines

arch/arm/kernel/kgdb_fiq_entry.S line 41

Quoted 1 line
arch/arm/kernel/kgdb_fiq_entry.S new file +1 -0
+	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.

Quoted 11 lines

arch/arm/kernel/kgdb_fiq_entry.S line 44

Quoted 3 lines
arch/arm/kernel/kgdb_fiq_entry.S new file +3 -0
+	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...

arch/arm/kernel/kgdb_fiq_entry.S line 45

Quoted 1 line
arch/arm/kernel/kgdb_fiq_entry.S new file +1 -0
+	ldr	r0, [r0, #S_R0]

Load the calling mode's R0 value.

Quoted 5 lines

arch/arm/kernel/kgdb_fiq_entry.S line 46

Quoted 1 line
arch/arm/kernel/kgdb_fiq_entry.S new file +1 -0
+	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.

#79 lore raw

Re: [PATCH v6 4/4] ARM: Add KGDB/KDB FIQ debugger generic code

Quoted 6 lines · Daniel Thompson
Quoted 2 lines

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.

Quoted 9 lines
Quoted 8 lines

arch/arm/kernel/kgdb_fiq_entry.S line 41

Quoted 1 line
arch/arm/kernel/kgdb_fiq_entry.S new file +1 -0
+	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.

Quoted 5 lines

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.

Quoted 3 lines

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.

Quoted 1 line

2. Add a paired up trace_hardirqs_on() (and review more deeply).

Done.

Quoted 1 line

3. Add comments explaining hazards w.r.t. data abort,

Done.

Quoted 1 line

4. Correctly manage T bit during transition back to FIQ mode.

Not applicable.

Quoted 1 line

Do I miss anything?

I hope not!

Daniel.

Acked-by on v6 4/4
#80 lore raw

Re: [PATCH v6 4/4] ARM: Add KGDB/KDB FIQ debugger generic code

In reply to Daniel Thompson
Quoted 25 lines · Daniel Thompson

From: Anton Vorontsov <[email protected]>

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.

---
 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

[...]

arch/arm/kernel/kgdb_fiq.c line 54

Quoted 7 lines
arch/arm/kernel/kgdb_fiq.c new file +7 -0
+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?

Quoted 21 lines
arch/arm/kernel/kgdb_fiq.c new file +21 -0
+
+	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;
+

arch/arm/kernel/kgdb_fiq.c line 85

Quoted 10 lines
arch/arm/kernel/kgdb_fiq.c new file +10 -0
+	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...

Nicolas

#81 lore raw

Re: [PATCH v6 4/4] ARM: Add KGDB/KDB FIQ debugger generic code

Quoted 30 lines · Nicolas Pitre
Quoted 25 lines · Daniel Thompson

From: Anton Vorontsov <[email protected]>

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.

---
 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

[...]

Quoted 10 lines

arch/arm/kernel/kgdb_fiq.c line 54

Quoted 7 lines
arch/arm/kernel/kgdb_fiq.c new file +7 -0
+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).

Quoted 34 lines
Quoted 21 lines
arch/arm/kernel/kgdb_fiq.c new file +21 -0
+
+	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;
+

arch/arm/kernel/kgdb_fiq.c line 85

Quoted 10 lines
arch/arm/kernel/kgdb_fiq.c new file +10 -0
+	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:

Quoted 7 lines
	/*
	 * 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.

Quoted 3 lines

Other than that...

Thanks for review.

#82 lore raw

v7 cover arm: KGDB NMI/FIQ support

In reply to Daniel Thompson

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

#83 lore raw

PATCH v7 1/4 arm: fiq: Add callbacks to manage FIQ routings

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.

---
 arch/arm/include/asm/fiq.h |   8 ++++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 2 deletions(-)
arch/arm/include/asm/fiq.h +8 -0
index d493d0b..ed44528 100644
@@ -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);
arch/arm/kernel/fiq.c +101 -2

141 lines not on this page · raw message

Signature · 1 line
1.9.3
#84 lore raw

PATCH v7 2/4 arm: fiq: Allow EOI to be communicated to the intc

In reply to Daniel Thompson

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.

---
 arch/arm/include/asm/fiq.h | 6 ++++++
 arch/arm/kernel/fiq.c      | 9 +++++++++
 2 files changed, 15 insertions(+)
arch/arm/include/asm/fiq.h +6 -0
index ed44528..fbc0df1 100644
@@ -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);
 
arch/arm/kernel/fiq.c +9 -0
index 5d831cf..c35fd6a 100644
@@ -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);
Signature · 1 line
1.9.3
#85 lore raw

PATCH v7 3/4 ARM: Move some macros from entry-armv to entry-header

In reply to Daniel Thompson

From: Anton Vorontsov <[email protected]>

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.

---
 arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
 arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 150 deletions(-)
arch/arm/kernel/entry-armv.S +1 -150
index 52a949a..4172cd6 100644
@@ -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:
arch/arm/kernel/entry-header.S +164 -0

167 lines not on this page · raw message

Signature · 1 line
1.9.3
#86 lore raw

PATCH v7 4/4 ARM: Add KGDB/KDB FIQ debugger generic code

In reply to Daniel Thompson

From: Anton Vorontsov <[email protected]>

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.

[daniel.thompson at linaro.org: Added __fiq_abt, rewrote stack init]
Cc Russell King <[email protected]>
Cc Ben Dooks <[email protected]>
Cc Dave Martin <[email protected]>
---
 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
arch/arm/Kconfig +2 -0
index 245058b..f385b27 100644
@@ -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
arch/arm/Kconfig.debug +18 -0
index 26536f7..c7342b6 100644
@@ -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
arch/arm/include/asm/kgdb.h +7 -0
index 0a9d5dd..5de21f01 100644
@@ -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__ */
 
 /*
arch/arm/kernel/Makefile +1 -0
index 38ddd9f..30ee8f3 100644
@@ -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
arch/arm/kernel/kgdb_fiq.c new file +127 -0

127 lines not on this page · raw message

arch/arm/kernel/kgdb_fiq_entry.S new file +130 -0

130 lines not on this page · raw message

Signature · 1 line
1.9.3
#87 lore raw

v8 cover arm: KGDB NMI/FIQ support

In reply to Daniel Thompson

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

#88 lore raw

PATCH v8 1/4 arm: fiq: Add callbacks to manage FIQ routings

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.

---
 arch/arm/include/asm/fiq.h |   8 ++++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 2 deletions(-)
arch/arm/include/asm/fiq.h +8 -0
index d493d0b..ed44528 100644
@@ -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);
arch/arm/kernel/fiq.c +101 -2

141 lines not on this page · raw message

Signature · 1 line
1.9.3
#89 lore raw

PATCH v8 2/4 arm: fiq: Allow ACK and EOI to be passed to the intc

In reply to Daniel Thompson

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.

---
 arch/arm/include/asm/fiq.h |  9 +++++++++
 arch/arm/kernel/fiq.c      | 19 +++++++++++++++++++
 2 files changed, 28 insertions(+)
arch/arm/include/asm/fiq.h +9 -0
index ed44528..a25c952 100644
@@ -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);
 
arch/arm/kernel/fiq.c +19 -0
index 5d831cf..3ccaa8c 100644
@@ -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);
Signature · 1 line
1.9.3
#90 lore raw

PATCH v8 3/4 ARM: Move some macros from entry-armv to entry-header

In reply to Daniel Thompson

From: Anton Vorontsov <[email protected]>

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.

---
 arch/arm/kernel/entry-armv.S   | 151 +------------------------------------
 arch/arm/kernel/entry-header.S | 164 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 150 deletions(-)
arch/arm/kernel/entry-armv.S +1 -150
index 52a949a..4172cd6 100644
@@ -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:
arch/arm/kernel/entry-header.S +164 -0

167 lines not on this page · raw message

Signature · 1 line
1.9.3
#91 lore raw

PATCH v8 4/4 ARM: Add KGDB/KDB FIQ debugger generic code

In reply to Daniel Thompson

From: Anton Vorontsov <[email protected]>

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.

[daniel.thompson at linaro.org: Added __fiq_abt, rewrote stack init]
Cc Russell King <[email protected]>
Cc Ben Dooks <[email protected]>
Cc Dave Martin <[email protected]>
---
 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
arch/arm/Kconfig +2 -0
index 245058b..f385b27 100644
@@ -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
arch/arm/Kconfig.debug +18 -0
index 26536f7..c7342b6 100644
@@ -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
arch/arm/include/asm/kgdb.h +7 -0
index 0a9d5dd..5de21f01 100644
@@ -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__ */
 
 /*
arch/arm/kernel/Makefile +1 -0
index 38ddd9f..30ee8f3 100644
@@ -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
arch/arm/kernel/kgdb_fiq.c new file +132 -0

132 lines not on this page · raw message

arch/arm/kernel/kgdb_fiq_entry.S new file +130 -0

130 lines not on this page · raw message

Signature · 1 line
1.9.3
#92 lore raw

Re: [PATCH v8 4/4] ARM: Add KGDB/KDB FIQ debugger generic code

Quoted 8 lines · Daniel Thompson

From: Anton Vorontsov <[email protected]>

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.)

Signature · 2 lines
FTTC broadband for 0.8mile line: [email protected] down 400kbps up
according to speedtest.net.
#93 lore raw

Re: [PATCH v8 4/4] ARM: Add KGDB/KDB FIQ debugger generic code

Quoted 49 lines · Russell King - ARM Linux
Quoted 8 lines · Daniel Thompson

From: Anton Vorontsov <[email protected]>

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()

(quoted diff) +8 -0
+       /*
+        * 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()

Review

Quoted 4 lines
(quoted diff) +4 -0
+       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() )

Quoted 82 lines

arch/arm/kernel/smp.c:

(quoted diff) +59 -0
+/* 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:

(quoted diff) +2 -0
+static unsigned int fiq_stack[4][1024];
+
...

cpu_init()

(quoted diff) +5 -1
-       "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:

arch/arm/kernel/kgdb_fiq_entry.S new file +3 -0
+       .macro  fiq_handler
+       bl      __fiq_handle
+       .endm
Quoted 7 lines

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.

Quoted 11 lines

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?

Quoted 9 lines

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.

Quoted 3 lines

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.

#94 lore raw

cover arm: FIQ IPI support

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

#95 lore raw

RFC PATCH 1/3 arm: smp: Introduce a special IPI signalled using FIQ

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.

---
 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(-)
arch/arm/include/asm/hardirq.h +1 -1
index fe3ea77..5df33e3 100644
@@ -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;
arch/arm/include/asm/smp.h +11 -0
index 2ec765c..6a969f8 100644
@@ -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
 	/*
arch/arm/kernel/smp.c +44 -0

68 lines not on this page · raw message

Signature · 1 line
1.9.3
#96 lore raw

RFC PATCH 2/3 arm: kgdb: Add support for IPI FIQ roundup

In reply to Daniel Thompson

Rounding up the other CPUs using FIQ improves debugger robustness.

---
 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(-)
arch/arm/include/asm/kgdb.h +1 -0
index 5de21f01..ceb466f 100644
@@ -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);
arch/arm/kernel/kgdb.c +16 -4
index a74b53c..e5c3ec0 100644
@@ -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)
arch/arm/kernel/kgdb_fiq.c +6 -1
index a894dde..f7a2c3d 100644
@@ -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);
Signature · 1 line
1.9.3
#97 lore raw

RFC PATCH 3/3 irqchip: gic: Add support for IPI FIQ

In reply to Daniel Thompson

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.

---
 drivers/irqchip/irq-gic.c | 126 +++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 107 insertions(+), 19 deletions(-)
drivers/irqchip/irq-gic.c +107 -19
index d928912..240cc87 100644
@@ -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);
 	}
Signature · 1 line
1.9.3
#98 lore raw

Re: [PATCH v8 4/4] ARM: Add KGDB/KDB FIQ debugger generic code

In reply to Daniel Thompson
Quoted 10 lines · Daniel Thompson

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);
Quoted 10 lines
Quoted 3 lines

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.

Quoted 3 lines

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.

Quoted 3 lines

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.

Quoted 3 lines

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.

Signature · 2 lines
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.
#99 lore raw

Re: [PATCH v8 4/4] ARM: Add KGDB/KDB FIQ debugger generic code

Quoted 22 lines · Russell King - ARM Linux
Quoted 10 lines · Daniel Thompson

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

Quoted 9 lines
   -> 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.

Quoted 6 lines
Quoted 6 lines
Quoted 3 lines

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.

Quoted 8 lines
Quoted 4 lines

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.

Quoted 8 lines
Quoted 3 lines

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).

Quoted 9 lines
Quoted 3 lines

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.

Quoted 5 lines

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.

Quoted 11 lines
Quoted 3 lines

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.

Quoted 2 lines

Given that fiq.c doesn't work with SMP, this isn't something I want to encourage.

Makes sense.

Quoted 3 lines

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).

#100 lore raw

Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support

In reply to Daniel Thompson
Quoted 11 lines · Daniel Thompson

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.

Quoted 6 lines

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
Quoted 1 line

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

#101 lore raw

Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support

Quoted 57 lines · Harro Haan
Quoted 11 lines · Daniel Thompson

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.

Quoted 6 lines

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
Quoted 3 lines

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.

Quoted 8 lines

I can reduce the number of occurrences (not prevent it) by adding the following hack to irq-gic.c

(quoted diff) +0 -0
@@ -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);

Quoted 6 lines

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)

drivers/irqchip/irq-gic.c +0 -0
index 73ae896..309bf2c 100644
@@ -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);

#102 lore raw

Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support

Quoted 76 lines · Daniel Thompson
Quoted 57 lines · Harro Haan
Quoted 11 lines · Daniel Thompson

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.

Quoted 6 lines

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
Quoted 3 lines

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.

Quoted 8 lines

I can reduce the number of occurrences (not prevent it) by adding the following hack to irq-gic.c

(quoted diff) +0 -0
@@ -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);

Quoted 9 lines
Quoted 6 lines

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.

Quoted 20 lines
drivers/irqchip/irq-gic.c +9 -0
index 73ae896..309bf2c 100644
@@ -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;
+

drivers/irqchip/irq-gic.c static int gic_set_wake(struct irq_data *d, · line 326

Quoted 10 lines
drivers/irqchip/irq-gic.c +10 -0
+       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.

drivers/irqchip/irq-gic.c static void __exception_irq_entry · line 336

Quoted 12 lines
drivers/irqchip/irq-gic.c +3 -0
+       return 1023;
+}
+
 static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
        u32 irqstat, irqnr;
drivers/irqchip/irq-gic.c +1 -0
@@ -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

Quoted 7 lines
drivers/irqchip/irq-gic.c +2 -1
                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

#103 lore raw

Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support

Quoted 60 lines · Harro Haan
Quoted 14 lines

Makes sense.

Avoiding this problem on GICv2 is easy (thanks to the aliased intack register) but on iMX.6 we have only a GICv1.

Quoted 8 lines

I can reduce the number of occurrences (not prevent it) by adding the following hack to irq-gic.c

(quoted diff) +0 -0
@@ -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);

Quoted 9 lines
Quoted 6 lines

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.

Quoted 20 lines
drivers/irqchip/irq-gic.c +9 -0
index 73ae896..309bf2c 100644
@@ -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;
+

drivers/irqchip/irq-gic.c static int gic_set_wake(struct irq_data *d, · line 326

Quoted 10 lines
drivers/irqchip/irq-gic.c +10 -0
+       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"

Quoted 8 lines

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?).

Quoted 10 lines
Quoted 10 lines
drivers/irqchip/irq-gic.c +3 -0
+       return 1023;
+}
+
 static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
        u32 irqstat, irqnr;
drivers/irqchip/irq-gic.c +0 -0
@@ -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);
 
Quoted 6 lines

drivers/irqchip/irq-gic.c static void __exception_irq_entry · line 336

Quoted 2 lines
drivers/irqchip/irq-gic.c +1 -0
        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.

Quoted 48 lines
Quoted 7 lines
drivers/irqchip/irq-gic.c +2 -1
                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:

(quoted diff) +30 -0
@@ -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.

Review static int gic_set_wake(struct irq_data *d, · line 335

Quoted 10 lines
(quoted diff) +10 -0
+ * - 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).

#104 lore raw

Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support

Quoted 70 lines · Daniel Thompson
Quoted 60 lines · Harro Haan
Quoted 14 lines

Makes sense.

Avoiding this problem on GICv2 is easy (thanks to the aliased intack register) but on iMX.6 we have only a GICv1.

Quoted 8 lines

I can reduce the number of occurrences (not prevent it) by adding the following hack to irq-gic.c

(quoted diff) +0 -0
@@ -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);

Quoted 9 lines
Quoted 6 lines

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.

Quoted 20 lines
drivers/irqchip/irq-gic.c +9 -0
index 73ae896..309bf2c 100644
@@ -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;
+

drivers/irqchip/irq-gic.c static int gic_set_wake(struct irq_data *d, · line 326

Quoted 10 lines
drivers/irqchip/irq-gic.c +10 -0
+       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"

Quoted 8 lines

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.

Quoted 5 lines

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.

Quoted 1 line

From page 56:

PPI[0], [2],and[3]:b11
interrupt is rising-edge sensitive.

Quoted 96 lines

A level triggered interrupt that hasn't been serviced should return the pending state (shouldn't it?).

Quoted 10 lines
Quoted 10 lines
drivers/irqchip/irq-gic.c +3 -0
+       return 1023;
+}
+
 static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
        u32 irqstat, irqnr;
drivers/irqchip/irq-gic.c +0 -0
@@ -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);
 
Quoted 6 lines

drivers/irqchip/irq-gic.c static void __exception_irq_entry · line 336

Quoted 2 lines
drivers/irqchip/irq-gic.c +1 -0
        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.

Quoted 48 lines
Quoted 7 lines
drivers/irqchip/irq-gic.c +2 -1
                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:

(quoted diff) +30 -0
@@ -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.

Review static int gic_set_wake(struct irq_data *d, · line 335

Quoted 10 lines
(quoted diff) +10 -0
+ * - 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:

Quoted 8 lines

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.

#105 lore raw

Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support

Quoted 75 lines · Harro Haan
Quoted 70 lines · Daniel Thompson
Quoted 60 lines · Harro Haan
Quoted 14 lines

Makes sense.

Avoiding this problem on GICv2 is easy (thanks to the aliased intack register) but on iMX.6 we have only a GICv1.

Quoted 8 lines

I can reduce the number of occurrences (not prevent it) by adding the following hack to irq-gic.c

(quoted diff) +0 -0
@@ -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);

Quoted 9 lines
Quoted 6 lines

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.

Quoted 20 lines
drivers/irqchip/irq-gic.c +9 -0
index 73ae896..309bf2c 100644
@@ -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;
+

drivers/irqchip/irq-gic.c static int gic_set_wake(struct irq_data *d, · line 326

Quoted 10 lines
drivers/irqchip/irq-gic.c +10 -0
+       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"

Quoted 8 lines

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.

Quoted 3 lines

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.

Quoted 8 lines

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.

Quoted 7 lines
Quoted 7 lines

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.

Quoted 6 lines
Quoted 3 lines

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).

---
 drivers/irqchip/irq-gic.c | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)
drivers/irqchip/irq-gic.c +0 -0
index 73ae896..88f92e6 100644
@@ -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);

Signature · 1 line
1.9.3
#106 lore raw

Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support

Quoted 174 lines · Daniel Thompson
Quoted 75 lines · Harro Haan
Quoted 70 lines · Daniel Thompson
Quoted 60 lines · Harro Haan
Quoted 14 lines

Makes sense.

Avoiding this problem on GICv2 is easy (thanks to the aliased intack register) but on iMX.6 we have only a GICv1.

Quoted 8 lines

I can reduce the number of occurrences (not prevent it) by adding the following hack to irq-gic.c

(quoted diff) +0 -0
@@ -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);

Quoted 9 lines
Quoted 6 lines

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.

Quoted 20 lines
drivers/irqchip/irq-gic.c +9 -0
index 73ae896..309bf2c 100644
@@ -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;
+

drivers/irqchip/irq-gic.c static int gic_set_wake(struct irq_data *d, · line 326

Quoted 10 lines
drivers/irqchip/irq-gic.c +10 -0
+       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"

Quoted 8 lines

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.

Quoted 3 lines

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.

Quoted 8 lines

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.

Quoted 7 lines
Quoted 7 lines

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.

Quoted 6 lines
Quoted 3 lines

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).

---
 drivers/irqchip/irq-gic.c | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)
drivers/irqchip/irq-gic.c +1 -0
index 73ae896..88f92e6 100644
@@ -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)

drivers/irqchip/irq-gic.c +26 -1
+{
+       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);
Quoted 5 lines

--
1.9.3

I just tested the above code. This approach also works as expected for edge sensitive interrupts.

#107 lore raw

Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support

Quoted 63 lines · Harro Haan
Quoted 63 lines

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).

---
 drivers/irqchip/irq-gic.c | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)
drivers/irqchip/irq-gic.c +1 -0
index 73ae896..88f92e6 100644
@@ -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)

drivers/irqchip/irq-gic.c +26 -1
+{
+       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();
 
Quoted 10 lines
Quoted 7 lines
drivers/irqchip/irq-gic.c +0 -0
                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!

#108 lore raw

Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support

In reply to Daniel Thompson
Quoted 60 lines · Daniel Thompson
Quoted 59 lines · Harro Haan
Quoted 10 lines · Daniel Thompson

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.

Quoted 5 lines

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

Quoted 8 lines
Quoted 3 lines

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.

Quoted 15 lines
Quoted 15 lines

I can reduce the number of occurrences (not prevent it) by adding the following hack to irq-gic.c

(quoted diff) +0 -0
@@ -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");

Quoted 5 lines
Quoted 2 lines
  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

#109 lore raw

Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support

Quoted 21 lines · Marek Vasut
Quoted 15 lines
Quoted 15 lines

I can reduce the number of occurrences (not prevent it) by adding the following hack to irq-gic.c

(quoted diff) +0 -0
@@ -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");

Quoted 5 lines
Quoted 2 lines
  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)

Quoted 7 lines

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.

#110 lore raw

Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support

Quoted 30 lines · Daniel Thompson
Quoted 21 lines · Marek Vasut
Quoted 15 lines
Quoted 15 lines

I can reduce the number of occurrences (not prevent it) by adding the following hack to irq-gic.c

(quoted diff) +0 -0
@@ -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");

Quoted 5 lines
Quoted 2 lines
  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)

Quoted 7 lines

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.

Quoted 4 lines

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.

Quoted 4 lines

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.

#111 lore raw

Re: [PATCH v8 0/4] arm: KGDB NMI/FIQ support

Quoted 61 lines · Harro Haan
Quoted 30 lines · Daniel Thompson
Quoted 21 lines · Marek Vasut
Quoted 15 lines
Quoted 15 lines

I can reduce the number of occurrences (not prevent it) by adding the following hack to irq-gic.c

(quoted diff) +0 -0
@@ -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");

Quoted 5 lines
Quoted 2 lines
  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)

Quoted 7 lines

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.

Quoted 4 lines

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.

Quoted 4 lines

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)

Quoted 1 line

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).

#112 lore raw

v9 cover arm: KGDB NMI/FIQ support

In reply to Daniel Thompson

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

#113 lore raw

PATCH v9 1/16 arm: fiq: Add callbacks to manage FIQ routings

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.

---
 arch/arm/include/asm/fiq.h |   8 ++++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 2 deletions(-)
arch/arm/include/asm/fiq.h +8 -0
index d493d0b..ed44528 100644
@@ -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);
arch/arm/kernel/fiq.c +101 -2

141 lines not on this page · raw message

Signature · 1 line
1.9.3
#114 lore raw

PATCH v9 2/16 arm: fiq: Allow ACK and EOI to be passed to the intc

In reply to Daniel Thompson

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.

---
 arch/arm/include/asm/fiq.h |  9 +++++++++
 arch/arm/kernel/fiq.c      | 19 +++++++++++++++++++
 2 files changed, 28 insertions(+)
arch/arm/include/asm/fiq.h +9 -0
index ed44528..a25c952 100644
@@ -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);
 
arch/arm/kernel/fiq.c +19 -0
index 5d831cf..3ccaa8c 100644
@@ -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);
Signature · 1 line
1.9.3
#115 lore raw

PATCH v9 3/16 arm: fiq: Replace default FIQ handler

In reply to Daniel Thompson

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.

Cc Russell King <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Catalin Marinas <[email protected]>
---
 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(-)
arch/arm/include/asm/fiq.h +1 -0
index a25c952..175bfed 100644
@@ -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: */
arch/arm/kernel/entry-armv.S +115 -10

173 lines not on this page · raw message

arch/arm/kernel/fiq.c +17 -0
index 3ccaa8c..b2bd1c7 100644
@@ -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 */
arch/arm/kernel/setup.c +7 -1
index 84db893d..c031063 100644
@@ -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
Signature · 1 line
1.9.3
#116 lore raw

PATCH v9 4/16 arm: smp: Introduce a special IPI signalled using FIQ

In reply to Daniel Thompson

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.

---
 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(-)
arch/arm/include/asm/hardirq.h +1 -1
index fe3ea77..5df33e3 100644
@@ -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;
arch/arm/include/asm/smp.h +7 -0
index 2ec765c..215c927 100644
@@ -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
 	/*
arch/arm/kernel/smp.c +15 -0
index 9388a3d..d386c32 100644
@@ -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);
Signature · 1 line
1.9.3
#117 lore raw

PATCH v9 5/16 arm: KGDB/KDB FIQ support

In reply to Daniel Thompson

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.

Cc Russell King <[email protected]>
Cc Ben Dooks <[email protected]>
Cc Omar Sandoval <[email protected]>
---
 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(-)
arch/arm/Kconfig +2 -0
index c49a775..e6380b3 100644
@@ -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
arch/arm/Kconfig.debug +19 -0
index f304694..a99f8d2 100644
@@ -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
arch/arm/include/asm/kgdb.h +4 -0
index 0a9d5dd..6563da0 100644
@@ -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__ */
 
 /*
arch/arm/kernel/kgdb.c +109 -6

145 lines not on this page · raw message

Signature · 1 line
1.9.3
#118 lore raw

v10 cover arm: KGDB NMI/FIQ support

In reply to Daniel Thompson

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

#119 lore raw

PATCH v10 1/19 arm: fiq: Add callbacks to manage FIQ routings

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.

---
 arch/arm/include/asm/fiq.h |   8 ++++
 arch/arm/kernel/fiq.c      | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 2 deletions(-)
arch/arm/include/asm/fiq.h +8 -0
index d493d0b..ed44528 100644
@@ -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);
arch/arm/kernel/fiq.c +101 -2

141 lines not on this page · raw message

Signature · 1 line
1.9.3
#120 lore raw

PATCH v10 2/19 arm: fiq: Allow ACK and EOI to be passed to the intc

In reply to Daniel Thompson

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.

---
 arch/arm/include/asm/fiq.h |  9 +++++++++
 arch/arm/kernel/fiq.c      | 19 +++++++++++++++++++
 2 files changed, 28 insertions(+)
arch/arm/include/asm/fiq.h +9 -0
index ed44528..a25c952 100644
@@ -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);
 
arch/arm/kernel/fiq.c +19 -0
index 5d831cf..3ccaa8c 100644
@@ -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);
Signature · 1 line
1.9.3
#121 lore raw

PATCH v10 3/19 arm: fiq: Replace default FIQ handler

In reply to Daniel Thompson

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.

Cc Russell King <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Catalin Marinas <[email protected]>
---
 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(-)
arch/arm/include/asm/fiq.h +1 -0
index a25c952..175bfed 100644
@@ -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: */
arch/arm/kernel/entry-armv.S +119 -10

177 lines not on this page · raw message

arch/arm/kernel/fiq.c +17 -0
index 3ccaa8c..b2bd1c7 100644
@@ -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 */
arch/arm/kernel/setup.c +7 -1
index 84db893d..c031063 100644
@@ -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
Signature · 1 line
1.9.3
#122 lore raw

Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler

Quoted 4 lines · Daniel Thompson
arch/arm/kernel/fiq.c +4 -0
+int register_fiq_nmi_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
+}

arch/arm/kernel/fiq.c bool has_fiq(int fiq) · line 234

Quoted 10 lines
arch/arm/kernel/fiq.c +10 -0
+
+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.

Signature · 2 lines
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.
#123 lore raw

Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler

Quoted 11 lines · Russell King - ARM Linux
Quoted 10 lines · Daniel Thompson
arch/arm/kernel/fiq.c +10 -0
+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();
Quoted 8 lines

arch/arm/kernel/fiq.c bool has_fiq(int fiq) · line 234

Quoted 4 lines
arch/arm/kernel/fiq.c +4 -0
+	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.

Quoted 12 lines

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.
Quoted 6 lines

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.

Quoted 6 lines

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.

#124 lore raw

Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler

Quoted 21 lines · Daniel Thompson
Quoted 11 lines · Russell King - ARM Linux
Quoted 10 lines · Daniel Thompson
arch/arm/kernel/fiq.c +10 -0
+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();
Quoted 8 lines

arch/arm/kernel/fiq.c bool has_fiq(int fiq) · line 234

Quoted 4 lines
arch/arm/kernel/fiq.c +4 -0
+	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() ?

Quoted 1 line

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.

Signature · 2 lines
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.
#125 lore raw

Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler

Quoted 40 lines · Russell King - ARM Linux
Quoted 21 lines · Daniel Thompson
Quoted 11 lines · Russell King - ARM Linux
Quoted 10 lines · Daniel Thompson
arch/arm/kernel/fiq.c +10 -0
+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();
Quoted 8 lines

arch/arm/kernel/fiq.c bool has_fiq(int fiq) · line 234

Quoted 4 lines
arch/arm/kernel/fiq.c +4 -0
+	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() ?

Quoted 1 line

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.

Quoted 6 lines

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

#126 lore raw

Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler

In reply to Russell King - ARM Linux
Quoted 22 lines · Russell King - ARM Linux
Quoted 21 lines · Daniel Thompson
Quoted 19 lines · Russell King - ARM Linux
Quoted 4 lines · Daniel Thompson
arch/arm/kernel/fiq.c +4 -0
+int register_fiq_nmi_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
+}

arch/arm/kernel/fiq.c bool has_fiq(int fiq) · line 234

Quoted 10 lines
arch/arm/kernel/fiq.c +10 -0
+
+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() ?

Quoted 5 lines
Quoted 1 line

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.

Quoted 3 lines

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.

Quoted 14 lines

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.

#127 lore raw

Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler

Quoted 42 lines · Daniel Thompson
Quoted 22 lines · Russell King - ARM Linux
Quoted 21 lines · Daniel Thompson
Quoted 19 lines · Russell King - ARM Linux
Quoted 4 lines · Daniel Thompson
arch/arm/kernel/fiq.c +4 -0
+int register_fiq_nmi_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
+}

arch/arm/kernel/fiq.c bool has_fiq(int fiq) · line 234

Quoted 10 lines
arch/arm/kernel/fiq.c +10 -0
+
+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() ?

Quoted 5 lines
Quoted 1 line

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.

Quoted 7 lines
Quoted 3 lines

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

Quoted 17 lines
Quoted 14 lines

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.

#128 lore raw

Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler

Quoted 47 lines · Paul E. McKenney
Quoted 46 lines · Daniel Thompson
Quoted 22 lines · Russell King - ARM Linux
Quoted 21 lines · Daniel Thompson
Quoted 19 lines · Russell King - ARM Linux
Quoted 4 lines · Daniel Thompson
(quoted diff) +4 -0
+int register_fiq_nmi_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&fiq_nmi_chain, nb);
+}

Review

Quoted 10 lines
(quoted diff) +10 -0
+
+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() ?

Quoted 5 lines
Quoted 1 line

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.

Quoted 3 lines

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.

Quoted 23 lines
Quoted 3 lines

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

Quoted 14 lines
Quoted 14 lines

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.

arch/arm/include/asm/fiq.h +0 -1
index 175bfed..a25c952 100644
@@ -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: */
arch/arm/include/asm/kgdb.h +1 -0
index 6563da0..cb5ccd6 100644
@@ -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__ */
 
arch/arm/kernel/fiq.c +10 -7
index b2bd1c7..7422b58 100644
@@ -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);
 }
arch/arm/kernel/kgdb.c +4 -9
index b77b885..630a3ef 100644
@@ -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;
 }
drivers/irqchip/irq-gic.c +7 -14
index bda5a91..8821160 100644
@@ -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);
 	}
include/linux/irqchip/arm-gic.h +3 -0
index 45e2d8c..52a5676 100644
@@ -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
#129 lore raw

Re: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler

Quoted 14 lines · Daniel Thompson
Quoted 13 lines · Paul E. McKenney
Quoted 12 lines · Daniel Thompson
Quoted 11 lines · Russell King - ARM Linux

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.

Quoted 8 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

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.

Signature · 2 lines
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.