make uclibc 0.9.30.1 the default
[openwrt.git] / target / linux / s3c24xx / patches-2.6.30 / 013-fiq_c_handler.patch
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
5 @@ -8,6 +8,8 @@
6   *
7   *  FIQ support re-written by Russell King to be more generic
8   *
9 + *  FIQ handler in C supoprt written by Andy Green <andy@openmoko.com>
10 + *
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.
14 @@ -124,6 +126,83 @@
15         : "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE));
16  }
17  
18 +/* -------- FIQ handler in C ---------
19 + *
20 + * Major Caveats for using this
21 + *  ---------------------------
22 + *  *
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.
30 + *
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.
39 + *
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
50 + *
51 + * If you follow these rules, it is fantastic, an extremely powerful, solid,
52 + * genuine hard realtime feature.
53 + */
54 +
55 +static void (*current_fiq_c_isr)(void);
56 +#define FIQ_C_ISR_STACK_SIZE   256
57 +
58 +static void __attribute__((naked)) __jump_to_isr(void)
59 +{
60 +       asm __volatile__ ("mov pc, r8");
61 +}
62 +
63 +
64 +static void __attribute__((naked)) __actual_isr(void)
65 +{
66 +       asm __volatile__ (
67 +               "stmdb  sp!, {r0-r12, lr};"
68 +               "mov     fp, sp;"
69 +       );
70 +
71 +       current_fiq_c_isr();
72 +
73 +       asm __volatile__ (
74 +               "ldmia  sp!, {r0-r12, lr};"
75 +               "subs   pc, lr, #4;"
76 +       );
77 +}
78 +
79 +void set_fiq_c_handler(void (*isr)(void))
80 +{
81 +       struct pt_regs regs;
82 +
83 +       memset(&regs, 0, sizeof(regs));
84 +       regs.ARM_r8 = (unsigned long) __actual_isr;
85 +       regs.ARM_sp = 0xffff001c + FIQ_C_ISR_STACK_SIZE;
86 +
87 +       set_fiq_handler(__jump_to_isr, 4);
88 +
89 +       current_fiq_c_isr = isr;
90 +
91 +       set_fiq_regs(&regs);
92 +}
93 +/* -------- FIQ handler in C ---------*/
94 +
95  int claim_fiq(struct fiq_handler *f)
96  {
97         int ret = 0;
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
102 @@ -29,8 +29,9 @@
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);
113  
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
118 @@ -12,6 +12,7 @@
119  
120  #include <linux/io.h>
121  
122 +#include <mach/irqs.h>
123  #include <mach/hardware.h>
124  #include <mach/regs-irq.h>
125  #include <mach/regs-gpio.h>
126 @@ -31,8 +32,15 @@
127  {
128         unsigned long mask;
129         unsigned long submask;
130 +#ifdef CONFIG_S3C2440_C_FIQ
131 +       unsigned long flags;
132 +#endif
133  
134         submask = __raw_readl(S3C2410_INTSUBMSK);
135 +#ifdef CONFIG_S3C2440_C_FIQ
136 +       local_save_flags(flags);
137 +       local_fiq_disable();
138 +#endif
139         mask = __raw_readl(S3C2410_INTMSK);
140  
141         submask |= (1UL << (irqno - IRQ_S3CUART_RX0));
142 @@ -45,6 +53,9 @@
143  
144         /* write back masks */
145         __raw_writel(submask, S3C2410_INTSUBMSK);
146 +#ifdef CONFIG_S3C2440_C_FIQ
147 +       local_irq_restore(flags);
148 +#endif
149  
150  }
151  
152 @@ -53,8 +64,15 @@
153  {
154         unsigned long mask;
155         unsigned long submask;
156 +#ifdef CONFIG_S3C2440_C_FIQ
157 +       unsigned long flags;
158 +#endif
159  
160         submask = __raw_readl(S3C2410_INTSUBMSK);
161 +#ifdef CONFIG_S3C2440_C_FIQ
162 +       local_save_flags(flags);
163 +       local_fiq_disable();
164 +#endif
165         mask = __raw_readl(S3C2410_INTMSK);
166  
167         submask &= ~(1UL << (irqno - IRQ_S3CUART_RX0));
168 @@ -63,6 +81,9 @@
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);
174 +#endif
175  }
176  
177  
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
182 @@ -28,6 +28,8 @@
183  #include <asm/mach/irq.h>
184  
185  #include <plat/regs-irqtype.h>
186 +#include <mach/regs-irq.h>
187 +#include <mach/regs-gpio.h>
188  
189  #include <plat/cpu.h>
190  #include <plat/pm.h>
191 @@ -37,12 +39,20 @@
192  s3c_irq_mask(unsigned int irqno)
193  {
194         unsigned long mask;
195 -
196 +#ifdef CONFIG_S3C2440_C_FIQ
197 +       unsigned long flags;
198 +#endif
199         irqno -= IRQ_EINT0;
200 -
201 +#ifdef CONFIG_S3C2440_C_FIQ
202 +       local_save_flags(flags);
203 +       local_fiq_disable();
204 +#endif
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);
210 +#endif
211  }
212  
213  static inline void
214 @@ -59,9 +69,19 @@
215  {
216         unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
217         unsigned long mask;
218 -
219 +#ifdef CONFIG_S3C2440_C_FIQ
220 +       unsigned long flags;
221 +#endif
222 +
223 +#ifdef CONFIG_S3C2440_C_FIQ
224 +       local_save_flags(flags);
225 +       local_fiq_disable();
226 +#endif
227         mask = __raw_readl(S3C2410_INTMSK);
228         __raw_writel(mask|bitval, S3C2410_INTMSK);
229 +#ifdef CONFIG_S3C2440_C_FIQ
230 +       local_irq_restore(flags);
231 +#endif
232  
233         __raw_writel(bitval, S3C2410_SRCPND);
234         __raw_writel(bitval, S3C2410_INTPND);
235 @@ -72,15 +92,25 @@
236  s3c_irq_unmask(unsigned int irqno)
237  {
238         unsigned long mask;
239 +#ifdef CONFIG_S3C2440_C_FIQ
240 +       unsigned long flags;
241 +#endif
242  
243         if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23)
244                 irqdbf2("s3c_irq_unmask %d\n", irqno);
245  
246         irqno -= IRQ_EINT0;
247  
248 +#ifdef CONFIG_S3C2440_C_FIQ
249 +       local_save_flags(flags);
250 +       local_fiq_disable();
251 +#endif
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);
257 +#endif
258  }
259  
260  struct irq_chip s3c_irq_level_chip = {
261 @@ -523,26 +553,26 @@
262  
263         last = 0;
264         for (i = 0; i < 4; i++) {
265 -               pend = __raw_readl(S3C2410_INTPND);
266 +               pend = __raw_readl(S3C2410_SUBSRCPND);
267  
268                 if (pend == 0 || pend == last)
269                         break;
270  
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);
276                 last = pend;
277         }
278  
279         last = 0;
280         for (i = 0; i < 4; i++) {
281 -               pend = __raw_readl(S3C2410_SUBSRCPND);
282 +               pend = __raw_readl(S3C2410_INTPND);
283  
284                 if (pend == 0 || pend == last)
285                         break;
286  
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);
292                 last = pend;
293         }
294