rfkill config cleanup
[15.05/openwrt.git] / 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