Root/target/linux/s3c24xx/patches-2.6.30/013-fiq_c_handler.patch

1--- a/arch/arm/kernel/fiq.c
2+++ b/arch/arm/kernel/fiq.c
3@@ -8,6 +8,8 @@
4  *
5  * FIQ support re-written by Russell King to be more generic
6  *
7+ * FIQ handler in C supoprt written by Andy Green <andy@openmoko.com>
8+ *
9  * We now properly support a method by which the FIQ handlers can
10  * be stacked onto the vector. We still do not support sharing
11  * the FIQ vector itself.
12@@ -124,6 +126,83 @@ void __naked get_fiq_regs(struct pt_regs
13     : "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE));
14 }
15 
16+/* -------- FIQ handler in C ---------
17+ *
18+ * Major Caveats for using this
19+ * ---------------------------
20+ * *
21+ * * 1) it CANNOT touch any vmalloc()'d memory, only memory
22+ * that was kmalloc()'d. Static allocations in the monolithic kernel
23+ * are kmalloc()'d so they are okay. You can touch memory-mapped IO, but
24+ * the pointer for it has to have been stored in kmalloc'd memory. The
25+ * reason for this is simple: every now and then Linux turns off interrupts
26+ * and reorders the paging tables. If a FIQ happens during this time, the
27+ * virtual memory space can be partly or entirely disordered or missing.
28+ *
29+ * 2) Because vmalloc() is used when a module is inserted, THIS FIQ
30+ * ISR HAS TO BE IN THE MONOLITHIC KERNEL, not a module. But the way
31+ * it is set up, you can all to enable and disable it from your module
32+ * and intercommunicate with it through struct fiq_ipc
33+ * fiq_ipc which you can define in
34+ * asm/archfiq_ipc_type.h. The reason is the same as above, a
35+ * FIQ could happen while even the ISR is not present in virtual memory
36+ * space due to pagetables being changed at the time.
37+ *
38+ * 3) You can't call any Linux API code except simple macros
39+ * - understand that FIQ can come in at any time, no matter what
40+ * state of undress the kernel may privately be in, thinking it
41+ * locked the door by turning off interrupts... FIQ is an
42+ * unstoppable monster force (which is its value)
43+ * - they are not vmalloc()'d memory safe
44+ * - they might do crazy stuff like sleep: FIQ pisses fire and
45+ * is not interested in 'sleep' that the weak seem to need
46+ * - calling APIs from FIQ can re-enter un-renterable things
47+ * - summary: you cannot interoperate with linux APIs directly in the FIQ ISR
48+ *
49+ * If you follow these rules, it is fantastic, an extremely powerful, solid,
50+ * genuine hard realtime feature.
51+ */
52+
53+static void (*current_fiq_c_isr)(void);
54+#define FIQ_C_ISR_STACK_SIZE 256
55+
56+static void __attribute__((naked)) __jump_to_isr(void)
57+{
58+ asm __volatile__ ("mov pc, r8");
59+}
60+
61+
62+static void __attribute__((naked)) __actual_isr(void)
63+{
64+ asm __volatile__ (
65+ "stmdb sp!, {r0-r12, lr};"
66+ "mov fp, sp;"
67+ );
68+
69+ current_fiq_c_isr();
70+
71+ asm __volatile__ (
72+ "ldmia sp!, {r0-r12, lr};"
73+ "subs pc, lr, #4;"
74+ );
75+}
76+
77+void set_fiq_c_handler(void (*isr)(void))
78+{
79+ struct pt_regs regs;
80+
81+ memset(&regs, 0, sizeof(regs));
82+ regs.ARM_r8 = (unsigned long) __actual_isr;
83+ regs.ARM_sp = 0xffff001c + FIQ_C_ISR_STACK_SIZE;
84+
85+ set_fiq_handler(__jump_to_isr, 4);
86+
87+ current_fiq_c_isr = isr;
88+
89+ set_fiq_regs(&regs);
90+}
91+/* -------- FIQ handler in C ---------*/
92+
93 int claim_fiq(struct fiq_handler *f)
94 {
95     int ret = 0;
96--- a/arch/arm/include/asm/fiq.h
97+++ b/arch/arm/include/asm/fiq.h
98@@ -29,8 +29,9 @@ struct fiq_handler {
99 extern int claim_fiq(struct fiq_handler *f);
100 extern void release_fiq(struct fiq_handler *f);
101 extern void set_fiq_handler(void *start, unsigned int length);
102-extern void set_fiq_regs(struct pt_regs *regs);
103-extern void get_fiq_regs(struct pt_regs *regs);
104+extern void set_fiq_c_handler(void (*handler)(void));
105+extern void __attribute__((naked)) set_fiq_regs(struct pt_regs *regs);
106+extern void __attribute__((naked)) get_fiq_regs(struct pt_regs *regs);
107 extern void enable_fiq(int fiq);
108 extern void disable_fiq(int fiq);
109 
110--- a/arch/arm/plat-s3c24xx/include/plat/irq.h
111+++ b/arch/arm/plat-s3c24xx/include/plat/irq.h
112@@ -12,6 +12,7 @@
113 
114 #include <linux/io.h>
115 
116+#include <mach/irqs.h>
117 #include <mach/hardware.h>
118 #include <mach/regs-irq.h>
119 #include <mach/regs-gpio.h>
120@@ -31,8 +32,15 @@ s3c_irqsub_mask(unsigned int irqno, unsi
121 {
122     unsigned long mask;
123     unsigned long submask;
124+#ifdef CONFIG_S3C2440_C_FIQ
125+ unsigned long flags;
126+#endif
127 
128     submask = __raw_readl(S3C2410_INTSUBMSK);
129+#ifdef CONFIG_S3C2440_C_FIQ
130+ local_save_flags(flags);
131+ local_fiq_disable();
132+#endif
133     mask = __raw_readl(S3C2410_INTMSK);
134 
135     submask |= (1UL << (irqno - IRQ_S3CUART_RX0));
136@@ -45,6 +53,9 @@ s3c_irqsub_mask(unsigned int irqno, unsi
137 
138     /* write back masks */
139     __raw_writel(submask, S3C2410_INTSUBMSK);
140+#ifdef CONFIG_S3C2440_C_FIQ
141+ local_irq_restore(flags);
142+#endif
143 
144 }
145 
146@@ -53,8 +64,15 @@ s3c_irqsub_unmask(unsigned int irqno, un
147 {
148     unsigned long mask;
149     unsigned long submask;
150+#ifdef CONFIG_S3C2440_C_FIQ
151+ unsigned long flags;
152+#endif
153 
154     submask = __raw_readl(S3C2410_INTSUBMSK);
155+#ifdef CONFIG_S3C2440_C_FIQ
156+ local_save_flags(flags);
157+ local_fiq_disable();
158+#endif
159     mask = __raw_readl(S3C2410_INTMSK);
160 
161     submask &= ~(1UL << (irqno - IRQ_S3CUART_RX0));
162@@ -63,6 +81,9 @@ s3c_irqsub_unmask(unsigned int irqno, un
163     /* write back masks */
164     __raw_writel(submask, S3C2410_INTSUBMSK);
165     __raw_writel(mask, S3C2410_INTMSK);
166+#ifdef CONFIG_S3C2440_C_FIQ
167+ local_irq_restore(flags);
168+#endif
169 }
170 
171 
172--- a/arch/arm/plat-s3c24xx/irq.c
173+++ b/arch/arm/plat-s3c24xx/irq.c
174@@ -28,6 +28,8 @@
175 #include <asm/mach/irq.h>
176 
177 #include <plat/regs-irqtype.h>
178+#include <mach/regs-irq.h>
179+#include <mach/regs-gpio.h>
180 
181 #include <plat/cpu.h>
182 #include <plat/pm.h>
183@@ -37,12 +39,20 @@ static void
184 s3c_irq_mask(unsigned int irqno)
185 {
186     unsigned long mask;
187-
188+#ifdef CONFIG_S3C2440_C_FIQ
189+ unsigned long flags;
190+#endif
191     irqno -= IRQ_EINT0;
192-
193+#ifdef CONFIG_S3C2440_C_FIQ
194+ local_save_flags(flags);
195+ local_fiq_disable();
196+#endif
197     mask = __raw_readl(S3C2410_INTMSK);
198     mask |= 1UL << irqno;
199     __raw_writel(mask, S3C2410_INTMSK);
200+#ifdef CONFIG_S3C2440_C_FIQ
201+ local_irq_restore(flags);
202+#endif
203 }
204 
205 static inline void
206@@ -59,9 +69,19 @@ s3c_irq_maskack(unsigned int irqno)
207 {
208     unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
209     unsigned long mask;
210-
211+#ifdef CONFIG_S3C2440_C_FIQ
212+ unsigned long flags;
213+#endif
214+
215+#ifdef CONFIG_S3C2440_C_FIQ
216+ local_save_flags(flags);
217+ local_fiq_disable();
218+#endif
219     mask = __raw_readl(S3C2410_INTMSK);
220     __raw_writel(mask|bitval, S3C2410_INTMSK);
221+#ifdef CONFIG_S3C2440_C_FIQ
222+ local_irq_restore(flags);
223+#endif
224 
225     __raw_writel(bitval, S3C2410_SRCPND);
226     __raw_writel(bitval, S3C2410_INTPND);
227@@ -72,15 +92,25 @@ static void
228 s3c_irq_unmask(unsigned int irqno)
229 {
230     unsigned long mask;
231+#ifdef CONFIG_S3C2440_C_FIQ
232+ unsigned long flags;
233+#endif
234 
235     if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23)
236         irqdbf2("s3c_irq_unmask %d\n", irqno);
237 
238     irqno -= IRQ_EINT0;
239 
240+#ifdef CONFIG_S3C2440_C_FIQ
241+ local_save_flags(flags);
242+ local_fiq_disable();
243+#endif
244     mask = __raw_readl(S3C2410_INTMSK);
245     mask &= ~(1UL << irqno);
246     __raw_writel(mask, S3C2410_INTMSK);
247+#ifdef CONFIG_S3C2440_C_FIQ
248+ local_irq_restore(flags);
249+#endif
250 }
251 
252 struct irq_chip s3c_irq_level_chip = {
253@@ -523,26 +553,26 @@ void __init s3c24xx_init_irq(void)
254 
255     last = 0;
256     for (i = 0; i < 4; i++) {
257- pend = __raw_readl(S3C2410_INTPND);
258+ pend = __raw_readl(S3C2410_SUBSRCPND);
259 
260         if (pend == 0 || pend == last)
261             break;
262 
263- __raw_writel(pend, S3C2410_SRCPND);
264- __raw_writel(pend, S3C2410_INTPND);
265- printk("irq: clearing pending status %08x\n", (int)pend);
266+ printk("irq: clearing subpending status %08x\n", (int)pend);
267+ __raw_writel(pend, S3C2410_SUBSRCPND);
268         last = pend;
269     }
270 
271     last = 0;
272     for (i = 0; i < 4; i++) {
273- pend = __raw_readl(S3C2410_SUBSRCPND);
274+ pend = __raw_readl(S3C2410_INTPND);
275 
276         if (pend == 0 || pend == last)
277             break;
278 
279- printk("irq: clearing subpending status %08x\n", (int)pend);
280- __raw_writel(pend, S3C2410_SUBSRCPND);
281+ __raw_writel(pend, S3C2410_SRCPND);
282+ __raw_writel(pend, S3C2410_INTPND);
283+ printk("irq: clearing pending status %08x\n", (int)pend);
284         last = pend;
285     }
286 
287

Archive Download this file



interactive