[RFC][PATCH v2 2/5] omap1: Amstrad Delta: add a handler for processing interrupts generated by the FIQ routine

Janusz Krzysztofik jkrzyszt at tis.icnet.pl
Mon Mar 29 10:26:16 EDT 2010


This patch introduces an IRQ handler used for processing interrupts generated
by the FIQ handler when it decides there are data ready for processing.

The handler further invokes device specific interrupt routines based on an
interrupt source as passed from the FIQ handler.

It can be registered by the board as a handler for the otherwise unused 32k
timer interrupt.

Applies on top of patch 1/5 from this series: 
	omap1: Amstrad Delta: add FIQ handler for serial keyboard port interrupt processing

Created and tested against linux-2.6.34-rc2.

Signed-off-by: Janusz Krzysztofik <jkrzyszt at tis.icnet.pl>
---
v2 changes:
- add fiq_buffer[] declaration missing from the header file,
- refresh against 2.6.34-rc2.

 arch/arm/mach-omap1/Makefile                     |    2
 arch/arm/mach-omap1/ams-delta-fiq.c              |  175 +++++++++++++++++++++++
 arch/arm/mach-omap1/include/mach/ams-delta-fiq.h |   57 +++++++
 3 files changed, 233 insertions(+), 1 deletion(-)

diff -uprN git.orig/arch/arm/mach-omap1/Makefile git/arch/arm/mach-omap1/Makefile
--- git.orig/arch/arm/mach-omap1/Makefile	2010-03-28 23:35:25.000000000 +0200
+++ git/arch/arm/mach-omap1/Makefile	2010-03-28 23:34:38.000000000 +0200
@@ -37,7 +37,7 @@ obj-$(CONFIG_MACH_OMAP_PALMZ71)		+= boar
 obj-$(CONFIG_MACH_OMAP_PALMTT)		+= board-palmtt.o
 obj-$(CONFIG_MACH_NOKIA770)		+= board-nokia770.o
 obj-$(CONFIG_MACH_AMS_DELTA)		+= board-ams-delta.o
-obj-$(CONFIG_AMS_DELTA_FIQ)		+= ams-delta-fiq-handler.o
+obj-$(CONFIG_AMS_DELTA_FIQ)		+= ams-delta-fiq.o ams-delta-fiq-handler.o
 obj-$(CONFIG_MACH_SX1)			+= board-sx1.o board-sx1-mmc.o
 obj-$(CONFIG_MACH_HERALD)		+= board-htcherald.o
 
diff -uprN git.orig/arch/arm/mach-omap1/ams-delta-fiq.c git/arch/arm/mach-omap1/ams-delta-fiq.c
--- git.orig/arch/arm/mach-omap1/ams-delta-fiq.c	1970-01-01 01:00:00.000000000 +0100
+++ git/arch/arm/mach-omap1/ams-delta-fiq.c	2010-03-28 23:34:38.000000000 +0200
@@ -0,0 +1,175 @@
+/*
+ *  Amstrad E3 FIQ handling
+ *
+ *  Copyright (C) 2009 Janusz Krzysztofik
+ *  Copyright (c) 2006 Matt Callow
+ *  Copyright (c) 2004 Amstrad Plc
+ *  Copyright (C) 2001 RidgeRun, Inc.
+ *
+ * Parts of this code are taken from linux/arch/arm/mach-omap/irq.c
+ * in the MontaVista 2.4 kernel (and the Amstrad changes therein)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/gpio.h>
+#include <asm/fiq.h>
+#include <mach/ams-delta-fiq.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <plat/board-ams-delta.h>
+#include <plat/mux.h>
+#include <plat/board.h>
+#include <plat/common.h>
+
+static struct fiq_handler fh = {
+	.name	= "ams-delta-fiq"
+};
+
+/*
+ * This buffer is shared between FIQ and IRQ contexts.
+ * The FIQ and IRQ isrs can both read and write it.
+ * It is structured as a header section several 32bit slots,
+ * followed by the circular buffer where the FIQ isr stores
+ * characters received from the qwerty keyboard.
+ * See ams-delta-fiq.h for details of offsets.
+ */
+unsigned int fiq_buffer[1024];
+EXPORT_SYMBOL(fiq_buffer);
+
+static unsigned int fiq_buffer_irq[FIQ_CIRC_BUFF];
+
+static irqreturn_t deferred_fiq(int irq, void *dev_id,
+		struct pt_regs *regs)
+{
+	int list_index, buffer_offset;
+	int irq_num;
+	const unsigned int cpu = smp_processor_id();
+
+	/*
+	 * Call the interrupt handler for each GPIO interrupt
+	 * where the FIQ interrupt counter > the IRQ counter
+	 */
+	for (buffer_offset = FIQ_CNT_INT_04;
+			buffer_offset >= FIQ_CNT_INT_CHAR; buffer_offset--) {
+		while (fiq_buffer[buffer_offset] >
+				fiq_buffer_irq[buffer_offset]) {
+
+			list_index = buffer_offset - FIQ_CNT_INT_00;
+			irq_num = list_index + IH_GPIO_BASE;
+
+			if (irq_desc[irq_num].action->handler != NULL) {
+				irq_desc[irq_num].action->handler(irq_num,
+					    irq_desc[irq_num].action->dev_id);
+				/* keep /proc/interrupts up to date */
+				kstat_cpu(cpu).softirqs[irq_num]++;
+
+				/*
+				 * Increment the IRQ count to ensure one IRQ
+				 * call per FIQ. There is a corresponding
+				 * increment in the FIQ handler having and
+				 * IRQ & FIQ level counters avoids any races.
+				 * There is a possibility that two calls to this
+				 * handler occur when keyboard and modem
+				 * interrupts are close together. Although both
+				 * interrupts will be serviced during the first
+				 * one. This should have no serious effect apart
+				 * from an unecessary call through here on
+				 * occasion, but that's better than missing one.
+				 */
+				fiq_buffer_irq[buffer_offset]++;
+			} else {
+				printk(KERN_WARNING
+						"!!! NULL HANDLER for[%d]!!!\n",
+						irq_num);
+				fiq_buffer_irq[buffer_offset]++;
+			}
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+void __init ams_delta_init_fiq(void)
+{
+	int retval;
+	void *fiqhandler_start;
+	unsigned int fiqhandler_length;
+	struct pt_regs FIQ_regs;
+	unsigned long val, offset;
+	int i;
+
+	fiqhandler_start = &qwerty_fiqin_start;
+	fiqhandler_length = &qwerty_fiqin_end - &qwerty_fiqin_start;
+	printk(KERN_INFO "Installing fiq handler from %p, length 0x%x\r\n",
+			fiqhandler_start, fiqhandler_length);
+
+	retval = claim_fiq(&fh);
+	if (retval) {
+		printk(KERN_ERR "ams_delta_init_fiq(): couldn't claim FIQ."
+				" ret = %d\n\r", retval);
+		return;
+	}
+
+	if (request_irq(INT_OS_TIMER, deferred_fiq, 0, "deferred_fiq", 0) < 0) {
+		printk(KERN_ERR "Failed to get OS_TIMER\r\n");
+		release_fiq(&fh);
+		return;
+	}
+
+	set_fiq_handler(fiqhandler_start, fiqhandler_length);
+
+	/*
+	 * Initialise the buffer which is shared
+	 * between FIQ mode and IRQ mode
+	 */
+	fiq_buffer[FIQ_GPIO_INT_MASK]	= 0;
+	fiq_buffer[FIQ_MASK]		= 0;
+	fiq_buffer[FIQ_STATE]		= 0;
+	fiq_buffer[FIQ_CHAR]		= 0;
+	fiq_buffer[FIQ_CHAR_CNT]	= 0;
+	fiq_buffer[FIQ_CHAR_HICNT]	= 0;
+	fiq_buffer[FIQ_FRNT_OFFSET]	= 0;
+	fiq_buffer[FIQ_BACK_OFFSET]	= 0;
+	fiq_buffer[FIQ_BUF_LEN]		= 256;
+	fiq_buffer[FIQ_MISSED_CHARS]	= 0;
+	fiq_buffer[FIQ_BUFFER_START]	=
+				(unsigned int) &fiq_buffer[FIQ_CIRC_BUFF];
+
+	for (i = FIQ_CNT_INT_00; i <= FIQ_CNT_INT_15; i++) {
+		fiq_buffer[i] = 0;
+		fiq_buffer_irq[i] = 0;
+	}
+
+	/*
+	 * FIQ mode r9 always points to the fiq_buffer, becauses the FIQ isr
+	 * will run in an unpredictable context. The fiq_buffer is the FIQ isr's
+	 * only means of communication with the IRQ level and other kernel
+	 * context code.
+	 */
+	FIQ_regs.ARM_r9 = (unsigned int)fiq_buffer;
+	FIQ_regs.ARM_r10 = 0;
+	FIQ_regs.ARM_sp = 0;
+
+	set_fiq_regs(&FIQ_regs);
+
+	printk(KERN_INFO "request_fiq(): fiq_buffer = %p\n", fiq_buffer);
+
+	/*
+	 * Set FIQ, priority 0, tigger rising on the GPIO INT
+	 * It would be nice to use omap_irq_set_cfg() here, but it's static
+	 */
+	val = 1 | ((IRQ_TYPE_EDGE_RISING & 0x1) << 1);
+	offset = IRQ_ILR0_REG_OFFSET + INT_GPIO_BANK1 * 0x4;
+	omap_writel(val, OMAP_IH1_BASE + offset);
+}
diff -uprN git.orig/arch/arm/mach-omap1/include/mach/ams-delta-fiq.h git/arch/arm/mach-omap1/include/mach/ams-delta-fiq.h
--- git.orig/arch/arm/mach-omap1/include/mach/ams-delta-fiq.h	1970-01-01 01:00:00.000000000 +0100
+++ git/arch/arm/mach-omap1/include/mach/ams-delta-fiq.h	2010-03-28 23:34:38.000000000 +0200
@@ -0,0 +1,57 @@
+/*
+ * arch/arm/mach-omap1/include/ams-delta-fiq.h
+ *
+ * Taken from the original Amstrad modifications to fiq.h
+ *
+ * Copyright (c) 2004 Amstrad Plc
+ * Copyright (c) 2006 Matt Callow
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * These are the offsets from the begining of the fiq_buffer. They are here
+ * as the buffer and header need to be accessed by drivers servicing devices
+ * which generate GPIO interrupts - e.g. qwerty, modem, smartcard
+ */
+
+#define FIQ_MASK		 0
+#define FIQ_STATE		 1
+#define FIQ_CHAR_CNT		 2
+#define FIQ_FRNT_OFFSET		 3
+#define FIQ_BACK_OFFSET		 4
+#define FIQ_BUF_LEN		 5
+#define FIQ_CHAR		 6
+#define FIQ_MISSED_CHARS	 7
+#define FIQ_BUFFER_START	 8
+#define FIQ_GPIO_INT_MASK	 9
+#define FIQ_CHAR_HICNT		10
+#define FIQ_IRQ_PEND		11
+#define FIQ_SIR_CODE_L1		12
+#define IRQ_SIR_CODE_L2		13
+
+#define FIQ_CNT_INT_00		14
+#define FIQ_CNT_INT_CHAR	15
+#define FIQ_CNT_INT_MDM		16
+#define FIQ_CNT_INT_FIQ		17
+#define FIQ_CNT_INT_04		18
+#define FIQ_CNT_INT_05		19
+#define FIQ_CNT_INT_KBD		20
+#define FIQ_CNT_INT_07		21
+#define FIQ_CNT_INT_08		22
+#define FIQ_CNT_INT_09		23
+#define FIQ_CNT_INT_10		24
+#define FIQ_CNT_INT_11		25
+#define FIQ_CNT_INT_12		26
+#define FIQ_CNT_INT_13		27
+#define FIQ_CNT_INT_14		28
+#define FIQ_CNT_INT_15		29
+
+#define FIQ_CIRC_BUFF		30      /*Start of circular buffer */
+
+extern unsigned int fiq_buffer[];
+extern unsigned char qwerty_fiqin_start, qwerty_fiqin_end;
+
+extern void __init ams_delta_init_fiq(void);



More information about the linux-arm-kernel mailing list