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