1 Index: linux-2.6.30-rc6/arch/arm/kernel/fiq.c
2 ===================================================================
3 --- linux-2.6.30-rc6.orig/arch/arm/kernel/fiq.c 2009-05-16 06:12:57.000000000 +0200
4 +++ linux-2.6.30-rc6/arch/arm/kernel/fiq.c 2009-05-18 19:08:30.000000000 +0200
7 * FIQ support re-written by Russell King to be more generic
9 + * FIQ handler in C supoprt written by Andy Green <andy@openmoko.com>
11 * We now properly support a method by which the FIQ handlers can
12 * be stacked onto the vector. We still do not support sharing
13 * the FIQ vector itself.
15 : "r" (®s->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE));
18 +/* -------- FIQ handler in C ---------
20 + * Major Caveats for using this
21 + * ---------------------------
23 + * * 1) it CANNOT touch any vmalloc()'d memory, only memory
24 + * that was kmalloc()'d. Static allocations in the monolithic kernel
25 + * are kmalloc()'d so they are okay. You can touch memory-mapped IO, but
26 + * the pointer for it has to have been stored in kmalloc'd memory. The
27 + * reason for this is simple: every now and then Linux turns off interrupts
28 + * and reorders the paging tables. If a FIQ happens during this time, the
29 + * virtual memory space can be partly or entirely disordered or missing.
31 + * 2) Because vmalloc() is used when a module is inserted, THIS FIQ
32 + * ISR HAS TO BE IN THE MONOLITHIC KERNEL, not a module. But the way
33 + * it is set up, you can all to enable and disable it from your module
34 + * and intercommunicate with it through struct fiq_ipc
35 + * fiq_ipc which you can define in
36 + * asm/archfiq_ipc_type.h. The reason is the same as above, a
37 + * FIQ could happen while even the ISR is not present in virtual memory
38 + * space due to pagetables being changed at the time.
40 + * 3) You can't call any Linux API code except simple macros
41 + * - understand that FIQ can come in at any time, no matter what
42 + * state of undress the kernel may privately be in, thinking it
43 + * locked the door by turning off interrupts... FIQ is an
44 + * unstoppable monster force (which is its value)
45 + * - they are not vmalloc()'d memory safe
46 + * - they might do crazy stuff like sleep: FIQ pisses fire and
47 + * is not interested in 'sleep' that the weak seem to need
48 + * - calling APIs from FIQ can re-enter un-renterable things
49 + * - summary: you cannot interoperate with linux APIs directly in the FIQ ISR
51 + * If you follow these rules, it is fantastic, an extremely powerful, solid,
52 + * genuine hard realtime feature.
55 +static void (*current_fiq_c_isr)(void);
56 +#define FIQ_C_ISR_STACK_SIZE 256
58 +static void __attribute__((naked)) __jump_to_isr(void)
60 + asm __volatile__ ("mov pc, r8");
64 +static void __attribute__((naked)) __actual_isr(void)
67 + "stmdb sp!, {r0-r12, lr};"
71 + current_fiq_c_isr();
74 + "ldmia sp!, {r0-r12, lr};"
79 +void set_fiq_c_handler(void (*isr)(void))
81 + struct pt_regs regs;
83 + memset(®s, 0, sizeof(regs));
84 + regs.ARM_r8 = (unsigned long) __actual_isr;
85 + regs.ARM_sp = 0xffff001c + FIQ_C_ISR_STACK_SIZE;
87 + set_fiq_handler(__jump_to_isr, 4);
89 + current_fiq_c_isr = isr;
91 + set_fiq_regs(®s);
93 +/* -------- FIQ handler in C ---------*/
95 int claim_fiq(struct fiq_handler *f)
98 Index: linux-2.6.30-rc6/arch/arm/include/asm/fiq.h
99 ===================================================================
100 --- linux-2.6.30-rc6.orig/arch/arm/include/asm/fiq.h 2009-05-16 06:12:57.000000000 +0200
101 +++ linux-2.6.30-rc6/arch/arm/include/asm/fiq.h 2009-05-18 19:08:30.000000000 +0200
103 extern int claim_fiq(struct fiq_handler *f);
104 extern void release_fiq(struct fiq_handler *f);
105 extern void set_fiq_handler(void *start, unsigned int length);
106 -extern void set_fiq_regs(struct pt_regs *regs);
107 -extern void get_fiq_regs(struct pt_regs *regs);
108 +extern void set_fiq_c_handler(void (*handler)(void));
109 +extern void __attribute__((naked)) set_fiq_regs(struct pt_regs *regs);
110 +extern void __attribute__((naked)) get_fiq_regs(struct pt_regs *regs);
111 extern void enable_fiq(int fiq);
112 extern void disable_fiq(int fiq);
114 Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/include/plat/irq.h
115 ===================================================================
116 --- linux-2.6.30-rc6.orig/arch/arm/plat-s3c24xx/include/plat/irq.h 2009-05-16 06:12:57.000000000 +0200
117 +++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/include/plat/irq.h 2009-05-18 19:08:30.000000000 +0200
120 #include <linux/io.h>
122 +#include <mach/irqs.h>
123 #include <mach/hardware.h>
124 #include <mach/regs-irq.h>
125 #include <mach/regs-gpio.h>
129 unsigned long submask;
130 +#ifdef CONFIG_S3C2440_C_FIQ
131 + unsigned long flags;
134 submask = __raw_readl(S3C2410_INTSUBMSK);
135 +#ifdef CONFIG_S3C2440_C_FIQ
136 + local_save_flags(flags);
137 + local_fiq_disable();
139 mask = __raw_readl(S3C2410_INTMSK);
141 submask |= (1UL << (irqno - IRQ_S3CUART_RX0));
144 /* write back masks */
145 __raw_writel(submask, S3C2410_INTSUBMSK);
146 +#ifdef CONFIG_S3C2440_C_FIQ
147 + local_irq_restore(flags);
155 unsigned long submask;
156 +#ifdef CONFIG_S3C2440_C_FIQ
157 + unsigned long flags;
160 submask = __raw_readl(S3C2410_INTSUBMSK);
161 +#ifdef CONFIG_S3C2440_C_FIQ
162 + local_save_flags(flags);
163 + local_fiq_disable();
165 mask = __raw_readl(S3C2410_INTMSK);
167 submask &= ~(1UL << (irqno - IRQ_S3CUART_RX0));
169 /* write back masks */
170 __raw_writel(submask, S3C2410_INTSUBMSK);
171 __raw_writel(mask, S3C2410_INTMSK);
172 +#ifdef CONFIG_S3C2440_C_FIQ
173 + local_irq_restore(flags);
178 Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/irq.c
179 ===================================================================
180 --- linux-2.6.30-rc6.orig/arch/arm/plat-s3c24xx/irq.c 2009-05-16 06:12:57.000000000 +0200
181 +++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/irq.c 2009-05-18 19:08:30.000000000 +0200
183 #include <asm/mach/irq.h>
185 #include <plat/regs-irqtype.h>
186 +#include <mach/regs-irq.h>
187 +#include <mach/regs-gpio.h>
189 #include <plat/cpu.h>
192 s3c_irq_mask(unsigned int irqno)
196 +#ifdef CONFIG_S3C2440_C_FIQ
197 + unsigned long flags;
201 +#ifdef CONFIG_S3C2440_C_FIQ
202 + local_save_flags(flags);
203 + local_fiq_disable();
205 mask = __raw_readl(S3C2410_INTMSK);
206 mask |= 1UL << irqno;
207 __raw_writel(mask, S3C2410_INTMSK);
208 +#ifdef CONFIG_S3C2440_C_FIQ
209 + local_irq_restore(flags);
216 unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
219 +#ifdef CONFIG_S3C2440_C_FIQ
220 + unsigned long flags;
223 +#ifdef CONFIG_S3C2440_C_FIQ
224 + local_save_flags(flags);
225 + local_fiq_disable();
227 mask = __raw_readl(S3C2410_INTMSK);
228 __raw_writel(mask|bitval, S3C2410_INTMSK);
229 +#ifdef CONFIG_S3C2440_C_FIQ
230 + local_irq_restore(flags);
233 __raw_writel(bitval, S3C2410_SRCPND);
234 __raw_writel(bitval, S3C2410_INTPND);
236 s3c_irq_unmask(unsigned int irqno)
239 +#ifdef CONFIG_S3C2440_C_FIQ
240 + unsigned long flags;
243 if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23)
244 irqdbf2("s3c_irq_unmask %d\n", irqno);
248 +#ifdef CONFIG_S3C2440_C_FIQ
249 + local_save_flags(flags);
250 + local_fiq_disable();
252 mask = __raw_readl(S3C2410_INTMSK);
253 mask &= ~(1UL << irqno);
254 __raw_writel(mask, S3C2410_INTMSK);
255 +#ifdef CONFIG_S3C2440_C_FIQ
256 + local_irq_restore(flags);
260 struct irq_chip s3c_irq_level_chip = {
261 @@ -523,26 +553,26 @@
264 for (i = 0; i < 4; i++) {
265 - pend = __raw_readl(S3C2410_INTPND);
266 + pend = __raw_readl(S3C2410_SUBSRCPND);
268 if (pend == 0 || pend == last)
271 - __raw_writel(pend, S3C2410_SRCPND);
272 - __raw_writel(pend, S3C2410_INTPND);
273 - printk("irq: clearing pending status %08x\n", (int)pend);
274 + printk("irq: clearing subpending status %08x\n", (int)pend);
275 + __raw_writel(pend, S3C2410_SUBSRCPND);
280 for (i = 0; i < 4; i++) {
281 - pend = __raw_readl(S3C2410_SUBSRCPND);
282 + pend = __raw_readl(S3C2410_INTPND);
284 if (pend == 0 || pend == last)
287 - printk("irq: clearing subpending status %08x\n", (int)pend);
288 - __raw_writel(pend, S3C2410_SUBSRCPND);
289 + __raw_writel(pend, S3C2410_SRCPND);
290 + __raw_writel(pend, S3C2410_INTPND);
291 + printk("irq: clearing pending status %08x\n", (int)pend);