aboutsummaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorBalaji Rao <balajirrao@openmoko.org>2009-02-22 04:39:41 +0000
committerAndy Green <agreen@octopus.localdomain>2009-02-22 04:39:41 +0000
commitd7617452eb27c1054ff67c4c9db4b63053d20125 (patch)
treef539a049eb98a76e570379202669aac2c8d170d9 /arch
parent699298c9ccf37cd116e485523c15c184781e5063 (diff)
fiq_handler_in_c.patch
The code for creating FIQ handlers in C is moved to arch/arm/kerne/fiq.c Signed-off-by: Balaji Rao <balajirrao@openmoko.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/include/asm/fiq.h1
-rw-r--r--arch/arm/kernel/fiq.c79
2 files changed, 80 insertions, 0 deletions
diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index a0cc0c084b8..7ade2b8445d 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -29,6 +29,7 @@ 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 void set_fiq_c_handler(void (*handler)(void));
extern void __attribute__((naked)) set_fiq_regs(struct pt_regs *regs);
extern void __attribute__((naked)) get_fiq_regs(struct pt_regs *regs);
extern void enable_fiq(int fiq);
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 36f81d96797..1307c0fbe66 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -8,6 +8,8 @@
*
* FIQ support re-written by Russell King to be more generic
*
+ * FIQ handler in C supoprt written by Andy Green <andy@openmoko.com>
+ *
* We now properly support a method by which the FIQ handlers can
* be stacked onto the vector. We still do not support sharing
* the FIQ vector itself.
@@ -124,6 +126,83 @@ void __attribute__((naked)) get_fiq_regs(struct pt_regs *regs)
: "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE));
}
+/* -------- FIQ handler in C ---------
+ *
+ * Major Caveats for using this
+ * ---------------------------
+ * *
+ * * 1) it CANNOT touch any vmalloc()'d memory, only memory
+ * that was kmalloc()'d. Static allocations in the monolithic kernel
+ * are kmalloc()'d so they are okay. You can touch memory-mapped IO, but
+ * the pointer for it has to have been stored in kmalloc'd memory. The
+ * reason for this is simple: every now and then Linux turns off interrupts
+ * and reorders the paging tables. If a FIQ happens during this time, the
+ * virtual memory space can be partly or entirely disordered or missing.
+ *
+ * 2) Because vmalloc() is used when a module is inserted, THIS FIQ
+ * ISR HAS TO BE IN THE MONOLITHIC KERNEL, not a module. But the way
+ * it is set up, you can all to enable and disable it from your module
+ * and intercommunicate with it through struct fiq_ipc
+ * fiq_ipc which you can define in
+ * asm/archfiq_ipc_type.h. The reason is the same as above, a
+ * FIQ could happen while even the ISR is not present in virtual memory
+ * space due to pagetables being changed at the time.
+ *
+ * 3) You can't call any Linux API code except simple macros
+ * - understand that FIQ can come in at any time, no matter what
+ * state of undress the kernel may privately be in, thinking it
+ * locked the door by turning off interrupts... FIQ is an
+ * unstoppable monster force (which is its value)
+ * - they are not vmalloc()'d memory safe
+ * - they might do crazy stuff like sleep: FIQ pisses fire and
+ * is not interested in 'sleep' that the weak seem to need
+ * - calling APIs from FIQ can re-enter un-renterable things
+ * - summary: you cannot interoperate with linux APIs directly in the FIQ ISR
+ *
+ * If you follow these rules, it is fantastic, an extremely powerful, solid,
+ * genuine hard realtime feature.
+ */
+
+static void (*current_fiq_c_isr)(void);
+#define FIQ_C_ISR_STACK_SIZE 256
+
+static void __attribute__((naked)) __jump_to_isr(void)
+{
+ asm __volatile__ ("mov pc, r8");
+}
+
+
+static void __attribute__((naked)) __actual_isr(void)
+{
+ asm __volatile__ (
+ "stmdb sp!, {r0-r12, lr};"
+ "mov fp, sp;"
+ );
+
+ current_fiq_c_isr();
+
+ asm __volatile__ (
+ "ldmia sp!, {r0-r12, lr};"
+ "subs pc, lr, #4;"
+ );
+}
+
+void set_fiq_c_handler(void (*isr)(void))
+{
+ struct pt_regs regs;
+
+ memset(&regs, 0, sizeof(regs));
+ regs.ARM_r8 = (unsigned long) __actual_isr;
+ regs.ARM_sp = 0xffff001c + FIQ_C_ISR_STACK_SIZE;
+
+ set_fiq_handler(__jump_to_isr, 4);
+
+ current_fiq_c_isr = isr;
+
+ set_fiq_regs(&regs);
+}
+/* -------- FIQ handler in C ---------*/
+
int claim_fiq(struct fiq_handler *f)
{
int ret = 0;