disable IMQ on 2.6.28 as well -- people should use IFB..
[openwrt.git] / target / linux / s3c24xx / patches / 0045-introduce-fiq-basis.patch.patch
1 From 6a2c7de90f47b7eb74f3cb2d181f950ece22b3fb Mon Sep 17 00:00:00 2001
2 From: mokopatches <mokopatches@openmoko.org>
3 Date: Fri, 25 Jul 2008 22:21:22 +0100
4 Subject: [PATCH] introduce-fiq-basis.patch
5  Adds a C-based FIQ ISR which is very convenient (and unusual --
6  normally you have to do FIQ ISR in assembler only).
7  Based on my article:
8
9 http://warmcat.com/_wp/2007/09/17/at91rm9200-fiq-faq-and-simple-example-code-patch/
10
11 Implemented as a platform device and driver.
12
13 Suspend / resume is tested and works.
14
15 Signed-off-by: Andy Green <andy@warmcat.com>
16 ---
17  arch/arm/mach-s3c2440/Kconfig                |    7 +
18  arch/arm/mach-s3c2440/Makefile               |    1 +
19  arch/arm/mach-s3c2440/fiq_c_isr.c            |  250 ++++++++++++++++++++++++++
20  arch/arm/mach-s3c2440/fiq_c_isr.h            |   64 +++++++
21  arch/arm/mach-s3c2440/mach-gta02.c           |   22 +++
22  arch/arm/plat-s3c24xx/irq.c                  |   32 +++-
23  include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h |   28 +++
24  include/asm-arm/plat-s3c24xx/irq.h           |   20 ++
25  8 files changed, 422 insertions(+), 2 deletions(-)
26  create mode 100644 arch/arm/mach-s3c2440/fiq_c_isr.c
27  create mode 100644 arch/arm/mach-s3c2440/fiq_c_isr.h
28  create mode 100644 include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h
29
30 diff --git a/arch/arm/mach-s3c2440/Kconfig b/arch/arm/mach-s3c2440/Kconfig
31 index 6b317d1..3015aaf 100644
32 --- a/arch/arm/mach-s3c2440/Kconfig
33 +++ b/arch/arm/mach-s3c2440/Kconfig
34 @@ -22,6 +22,13 @@ config S3C2440_DMA
35         help
36           Support for S3C2440 specific DMA code5A
37  
38 +config S3C2440_C_FIQ
39 +       bool "FIQ ISR support in C"
40 +       depends on ARCH_S3C2410
41 +       select FIQ
42 +       help
43 +         Support for S3C2440 FIQ support in C -- see
44 +         ./arch/arm/macs3c2440/fiq_c_isr.c
45  
46  menu "S3C2440 Machines"
47  
48 diff --git a/arch/arm/mach-s3c2440/Makefile b/arch/arm/mach-s3c2440/Makefile
49 index 1a4defd..4932232 100644
50 --- a/arch/arm/mach-s3c2440/Makefile
51 +++ b/arch/arm/mach-s3c2440/Makefile
52 @@ -13,6 +13,7 @@ obj-$(CONFIG_CPU_S3C2440)     += s3c2440.o dsc.o
53  obj-$(CONFIG_CPU_S3C2440)      += irq.o
54  obj-$(CONFIG_CPU_S3C2440)      += clock.o
55  obj-$(CONFIG_S3C2440_DMA)      += dma.o
56 +obj-$(CONFIG_S3C2440_C_FIQ)    += fiq_c_isr.o
57  
58  # Machine support
59  
60 diff --git a/arch/arm/mach-s3c2440/fiq_c_isr.c b/arch/arm/mach-s3c2440/fiq_c_isr.c
61 new file mode 100644
62 index 0000000..12f4527
63 --- /dev/null
64 +++ b/arch/arm/mach-s3c2440/fiq_c_isr.c
65 @@ -0,0 +1,250 @@
66 +/*
67 + * Copyright 2007  Andy Green <andy@warmcat.com>
68 + * S3C modfifications
69 + * Copyright 2008 Andy Green <andy@openmoko.com>
70 + */
71 +
72 +#include <linux/module.h>
73 +#include <linux/kernel.h>
74 +#include <asm/hardware.h>
75 +#include <asm/fiq.h>
76 +#include "fiq_c_isr.h"
77 +#include <linux/sysfs.h>
78 +#include <linux/device.h>
79 +#include <linux/platform_device.h>
80 +
81 +#include <asm/io.h>
82 +
83 +#include <asm/plat-s3c24xx/cpu.h>
84 +#include <asm/plat-s3c24xx/irq.h>
85 +
86 +/*
87 + * Major Caveats for using FIQ
88 + * ---------------------------
89 + *
90 + * 1) it CANNOT touch any vmalloc()'d memory, only memory
91 + *    that was kmalloc()'d.  Static allocations in the monolithic kernel
92 + *    are kmalloc()'d so they are okay.  You can touch memory-mapped IO, but
93 + *    the pointer for it has to have been stored in kmalloc'd memory.  The
94 + *    reason for this is simple: every now and then Linux turns off interrupts
95 + *    and reorders the paging tables.  If a FIQ happens during this time, the
96 + *    virtual memory space can be partly or entirely disordered or missing.
97 + *
98 + * 2) Because vmalloc() is used when a module is inserted, THIS FIQ
99 + *    ISR HAS TO BE IN THE MONOLITHIC KERNEL, not a module.  But the way
100 + *    it is set up, you can all to enable and disable it from your module
101 + *    and intercommunicate with it through struct fiq_ipc
102 + *    fiq_ipc which you can define in
103 + *    asm/archfiq_ipc_type.h.  The reason is the same as above, a
104 + *    FIQ could happen while even the ISR is not present in virtual memory
105 + *    space due to pagetables being changed at the time.
106 + *
107 + * 3) You can't call any Linux API code except simple macros
108 + *    - understand that FIQ can come in at any time, no matter what
109 + *      state of undress the kernel may privately be in, thinking it
110 + *      locked the door by turning off interrupts... FIQ is an
111 + *      unstoppable monster force (which is its value)
112 + *    - they are not vmalloc()'d memory safe
113 + *    - they might do crazy stuff like sleep: FIQ pisses fire and
114 + *      is not interested in 'sleep' that the weak seem to need
115 + *    - calling APIs from FIQ can re-enter un-renterable things
116 + *    - summary: you cannot interoperate with linux APIs directly in the FIQ ISR
117 + *
118 + * If you follow these rules, it is fantastic, an extremely powerful, solid,
119 + * genuine hard realtime feature.
120 + *
121 + */
122 +
123 +/* more than enough to cover our jump instruction to the isr */
124 +#define SIZEOF_FIQ_JUMP 8
125 +/* more than enough to cover s3c2440_fiq_isr() in 4K blocks */
126 +#define SIZEOF_FIQ_ISR 0x2000
127 +/* increase the size of the stack that is active during FIQ as needed */
128 +static u8 u8aFiqStack[4096];
129 +
130 +/* only one FIQ ISR possible, okay to do these here */
131 +u32 _fiq_ack_mask; /* used by isr exit define */
132 +unsigned long _fiq_count_fiqs; /* used by isr exit define */
133 +static int _fiq_irq; /* private ; irq index we were started with, or 0 */
134 +
135 +/* this function must live in the monolithic kernel somewhere!  A module is
136 + * NOT good enough!
137 + */
138 +extern void __attribute__ ((naked)) s3c2440_fiq_isr(void);
139 +
140 +/* this is copied into the hard FIQ vector during init */
141 +
142 +static void __attribute__ ((naked)) s3c2440_FIQ_Branch(void)
143 +{
144 +       asm __volatile__ (
145 +               "mov pc, r8 ; "
146 +       );
147 +}
148 +
149 +/* sysfs */
150 +
151 +static ssize_t show_count(struct device *dev, struct device_attribute *attr,
152 +                        char *buf)
153 +{
154 +       return sprintf(buf, "%ld\n", _fiq_count_fiqs);
155 +}
156 +
157 +static DEVICE_ATTR(count, 0444, show_count, NULL);
158 +
159 +static struct attribute *s3c2440_fiq_sysfs_entries[] = {
160 +       &dev_attr_count.attr,
161 +       NULL
162 +};
163 +
164 +static struct attribute_group s3c2440_fiq_attr_group = {
165 +       .name   = "fiq",
166 +       .attrs  = s3c2440_fiq_sysfs_entries,
167 +};
168 +
169 +/*
170 + * call this from your kernel module to set up the FIQ ISR to service FIQs,
171 + * You need to have configured your FIQ input pin before anything will happen
172 + *
173 + * call it with, eg, IRQ_TIMER3 from asm-arm/arch-s3c2410/irqs.h
174 + *
175 + * you still need to clear the source interrupt in S3C2410_INTMSK to get
176 + * anything good happening
177 + */
178 +static void fiq_init_irq_source(int irq_index_fiq)
179 +{
180 +       if (!irq_index_fiq) /* no interrupt */
181 +               return;
182 +
183 +       printk(KERN_INFO"Enabling FIQ using int idx %d\n",
184 +              irq_index_fiq - S3C2410_CPUIRQ_OFFSET);
185 +       local_fiq_disable();
186 +
187 +       _fiq_irq = irq_index_fiq;
188 +       _fiq_ack_mask = 1 << (irq_index_fiq - S3C2410_CPUIRQ_OFFSET);
189 +
190 +       /* let our selected interrupt be a magic FIQ interrupt */
191 +       __raw_writel(_fiq_ack_mask, S3C2410_INTMOD);
192 +
193 +       /* it's ready to go as soon as we unmask the source in S3C2410_INTMSK */
194 +       local_fiq_enable();
195 +}
196 +
197 +
198 +/* call this from your kernel module to disable generation of FIQ actions */
199 +static void fiq_disable_irq_source(void)
200 +{
201 +       /* nothing makes FIQ any more */
202 +       __raw_writel(0, S3C2410_INTMOD);
203 +       local_fiq_disable();
204 +       _fiq_irq = 0; /* no active source interrupt now either */
205 +}
206 +
207 +/* this starts FIQ timer events... they continue until the FIQ ISR sees that
208 + * its work is done and it turns off the timer.  After setting up the fiq_ipc
209 + * struct with new work, you call this to start FIQ timer actions up again.
210 + * Only the FIQ ISR decides when it is done and controls turning off the
211 + * timer events.
212 + */
213 +void fiq_kick(void)
214 +{
215 +       unsigned long flags;
216 +
217 +       /* we have to take care about FIQ because this modification is
218 +        * non-atomic, FIQ could come in after the read and before the
219 +        * writeback and its changes to the register would be lost
220 +        * (platform INTMSK mod code is taken care of already)
221 +        */
222 +       local_save_flags(flags);
223 +       local_fiq_disable();
224 +       __raw_writel(__raw_readl(S3C2410_INTMSK) &
225 +                    ~(1 << (_fiq_irq - S3C2410_CPUIRQ_OFFSET)),
226 +                    S3C2410_INTMSK);
227 +       local_irq_restore(flags);
228 +}
229 +EXPORT_SYMBOL_GPL(fiq_kick);
230 +
231 +
232 +
233 +static int __init sc32440_fiq_probe(struct platform_device *pdev)
234 +{
235 +       struct resource *r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
236 +
237 +       if (!r)
238 +               return -EIO;
239 +       /* configure for the interrupt we are meant to use */
240 +       fiq_init_irq_source(r->start);
241 +
242 +       return sysfs_create_group(&pdev->dev.kobj, &s3c2440_fiq_attr_group);
243 +}
244 +
245 +static int sc32440_fiq_remove(struct platform_device *pdev)
246 +{
247 +       fiq_disable_irq_source();
248 +       sysfs_remove_group(&pdev->dev.kobj, &s3c2440_fiq_attr_group);
249 +       return 0;
250 +}
251 +
252 +static void fiq_set_vector_and_regs(void)
253 +{
254 +       struct pt_regs regs;
255 +
256 +       /* prep the special FIQ mode regs */
257 +       memset(&regs, 0, sizeof(regs));
258 +       regs.ARM_r8 = (unsigned long)s3c2440_fiq_isr;
259 +       regs.ARM_sp = (unsigned long)u8aFiqStack + sizeof(u8aFiqStack) - 4;
260 +       /* set up the special FIQ-mode-only registers from our regs */
261 +       set_fiq_regs(&regs);
262 +       /* copy our jump to the real ISR into the hard vector address */
263 +       set_fiq_handler(s3c2440_FIQ_Branch, SIZEOF_FIQ_JUMP);
264 +}
265 +
266 +#ifdef CONFIG_PM
267 +static int sc32440_fiq_suspend(struct platform_device *pdev, pm_message_t state)
268 +{
269 +       /* nothing makes FIQ any more */
270 +       __raw_writel(0, S3C2410_INTMOD);
271 +       local_fiq_disable();
272 +
273 +       return 0;
274 +}
275 +
276 +static int sc32440_fiq_resume(struct platform_device *pdev)
277 +{
278 +       fiq_set_vector_and_regs();
279 +       fiq_init_irq_source(_fiq_irq);
280 +       return 0;
281 +}
282 +#else
283 +#define sc32440_fiq_suspend    NULL
284 +#define sc32440_fiq_resume     NULL
285 +#endif
286 +
287 +static struct platform_driver sc32440_fiq_driver = {
288 +       .driver = {
289 +               .name   = "sc32440_fiq",
290 +               .owner  = THIS_MODULE,
291 +       },
292 +
293 +       .probe   = sc32440_fiq_probe,
294 +       .remove  = __devexit_p(sc32440_fiq_remove),
295 +       .suspend = sc32440_fiq_suspend,
296 +       .resume  = sc32440_fiq_resume,
297 +};
298 +
299 +static int __init sc32440_fiq_init(void)
300 +{
301 +       fiq_set_vector_and_regs();
302 +
303 +       return platform_driver_register(&sc32440_fiq_driver);
304 +}
305 +
306 +static void __exit sc32440_fiq_exit(void)
307 +{
308 +       fiq_disable_irq_source();
309 +}
310 +
311 +MODULE_AUTHOR("Andy Green <andy@openmoko.com>");
312 +MODULE_LICENSE("GPL");
313 +
314 +module_init(sc32440_fiq_init);
315 +module_exit(sc32440_fiq_exit);
316 diff --git a/arch/arm/mach-s3c2440/fiq_c_isr.h b/arch/arm/mach-s3c2440/fiq_c_isr.h
317 new file mode 100644
318 index 0000000..f08740e
319 --- /dev/null
320 +++ b/arch/arm/mach-s3c2440/fiq_c_isr.h
321 @@ -0,0 +1,64 @@
322 +#ifndef _LINUX_FIQ_C_ISR_H
323 +#define _LINUX_FIQ_C_ISR_H
324 +
325 +#include <asm/arch-s3c2410/regs-irq.h>
326 +
327 +extern unsigned long _fiq_count_fiqs;
328 +extern u32 _fiq_ack_mask;
329 +
330 +/* This CANNOT be implemented in a module -- it has to be used in code
331 + * included in the monolithic kernel
332 + */
333 +
334 +#define FIQ_HANDLER_START() \
335 +void __attribute__ ((naked)) s3c2440_fiq_isr(void) \
336 +{\
337 +       /*\
338 +        * you can declare local vars here, take care to set the frame size\
339 +        *  below accordingly if there are more than a few dozen bytes of them\
340 +        */\
341 +
342 +/* stick your locals here :-)
343 + * Do NOT initialize them here!  define them and initialize them after
344 + * FIQ_HANDLER_ENTRY() is done.
345 + */
346 +
347 +#define FIQ_HANDLER_ENTRY(LOCALS, FRAME) \
348 +       const int _FIQ_FRAME_SIZE = FRAME; \
349 +       /* entry takes care to store registers we will be treading on here */\
350 +       asm __volatile__ (\
351 +               "mov     ip, sp ;"\
352 +               /* stash FIQ and r0-r8 normal regs */\
353 +               "stmdb  sp!, {r0-r12, lr};"\
354 +               /* allow SP to get some space */\
355 +               "sub     sp, sp, %1 ;"\
356 +               /* !! THIS SETS THE FRAME, adjust to > sizeof locals */\
357 +               "sub     fp, sp, %0 ;"\
358 +               :\
359 +               : "rI" (LOCALS), "rI" (FRAME)\
360 +               :"r9"\
361 +       );
362 +
363 +/* stick your ISR code here and then end with... */
364 +
365 +#define FIQ_HANDLER_END() \
366 +       _fiq_count_fiqs++;\
367 +       __raw_writel(_fiq_ack_mask, S3C2410_SRCPND);\
368 +\
369 +       /* exit back to normal mode restoring everything */\
370 +       asm __volatile__ (\
371 +               /* pop our allocation */\
372 +               "add     sp, sp, %0 ;"\
373 +               /* return FIQ regs back to pristine state\
374 +                * and get normal regs back\
375 +                */\
376 +               "ldmia  sp!, {r0-r12, lr};"\
377 +\
378 +               /* return */\
379 +               "subs   pc, lr, #4;"\
380 +               : \
381 +               : "rI" (_FIQ_FRAME_SIZE) \
382 +       );\
383 +}
384 +
385 +#endif /* _LINUX_FIQ_C_ISR_H */
386 diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
387 index 46acede..0bdd0e0 100644
388 --- a/arch/arm/mach-s3c2440/mach-gta02.c
389 +++ b/arch/arm/mach-s3c2440/mach-gta02.c
390 @@ -78,9 +78,31 @@
391  
392  #include <linux/glamofb.h>
393  
394 +#include <asm/arch/fiq_ipc_gta02.h>
395 +#include "fiq_c_isr.h"
396 +
397  /* arbitrates which sensor IRQ owns the shared SPI bus */
398  static spinlock_t motion_irq_lock;
399  
400 +/* define FIQ IPC struct */
401 +/*
402 + * contains stuff FIQ ISR modifies and normal kernel code can see and use
403 + * this is defined in <asm/arch/fiq_ipc_gta02.h>, you should customize
404 + * the definition in there and include the same definition in your kernel
405 + * module that wants to interoperate with your FIQ code.
406 + */
407 +struct fiq_ipc fiq_ipc;
408 +EXPORT_SYMBOL(fiq_ipc);
409 +
410 +/* define FIQ ISR */
411 +
412 +FIQ_HANDLER_START()
413 +/* define your locals here -- no initializers though */
414 +FIQ_HANDLER_ENTRY(256, 512)
415 +/* Your ISR here :-) */
416 +FIQ_HANDLER_END()
417 +
418 +
419  static struct map_desc gta02_iodesc[] __initdata = {
420         {
421                 .virtual        = 0xe0000000,
422 diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
423 index ae2c5d7..9887db1 100644
424 --- a/arch/arm/plat-s3c24xx/irq.c
425 +++ b/arch/arm/plat-s3c24xx/irq.c
426 @@ -133,12 +133,20 @@ static void
427  s3c_irq_mask(unsigned int irqno)
428  {
429         unsigned long mask;
430 -
431 +#ifdef CONFIG_S3C2440_C_FIQ
432 +       unsigned long flags;
433 +#endif
434         irqno -= IRQ_EINT0;
435 -
436 +#ifdef CONFIG_S3C2440_C_FIQ
437 +       local_save_flags(flags);
438 +       local_fiq_disable();
439 +#endif
440         mask = __raw_readl(S3C2410_INTMSK);
441         mask |= 1UL << irqno;
442         __raw_writel(mask, S3C2410_INTMSK);
443 +#ifdef CONFIG_S3C2440_C_FIQ
444 +       local_irq_restore(flags);
445 +#endif
446  }
447  
448  static inline void
449 @@ -155,9 +163,19 @@ s3c_irq_maskack(unsigned int irqno)
450  {
451         unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
452         unsigned long mask;
453 +#ifdef CONFIG_S3C2440_C_FIQ
454 +       unsigned long flags;
455 +#endif
456  
457 +#ifdef CONFIG_S3C2440_C_FIQ
458 +       local_save_flags(flags);
459 +       local_fiq_disable();
460 +#endif
461         mask = __raw_readl(S3C2410_INTMSK);
462         __raw_writel(mask|bitval, S3C2410_INTMSK);
463 +#ifdef CONFIG_S3C2440_C_FIQ
464 +       local_irq_restore(flags);
465 +#endif
466  
467         __raw_writel(bitval, S3C2410_SRCPND);
468         __raw_writel(bitval, S3C2410_INTPND);
469 @@ -168,15 +186,25 @@ static void
470  s3c_irq_unmask(unsigned int irqno)
471  {
472         unsigned long mask;
473 +#ifdef CONFIG_S3C2440_C_FIQ
474 +       unsigned long flags;
475 +#endif
476  
477         if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23)
478                 irqdbf2("s3c_irq_unmask %d\n", irqno);
479  
480         irqno -= IRQ_EINT0;
481  
482 +#ifdef CONFIG_S3C2440_C_FIQ
483 +       local_save_flags(flags);
484 +       local_fiq_disable();
485 +#endif
486         mask = __raw_readl(S3C2410_INTMSK);
487         mask &= ~(1UL << irqno);
488         __raw_writel(mask, S3C2410_INTMSK);
489 +#ifdef CONFIG_S3C2440_C_FIQ
490 +       local_irq_restore(flags);
491 +#endif
492  }
493  
494  struct irq_chip s3c_irq_level_chip = {
495 diff --git a/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h b/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h
496 new file mode 100644
497 index 0000000..341f2bb
498 --- /dev/null
499 +++ b/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h
500 @@ -0,0 +1,28 @@
501 +#ifndef _LINUX_FIQ_IPC_H
502 +#define _LINUX_FIQ_IPC_H
503 +
504 +/*
505 + * this defines the struct which is used to communicate between the FIQ
506 + * world and the normal linux kernel world.  One of these structs is
507 + * statically defined for you in the monolithic kernel so the FIQ ISR code
508 + * can safely touch it any any time.
509 + *
510 + * You also want to include this file in your kernel module that wants to
511 + * communicate with your FIQ code.  Add any kinds of vars that are used by
512 + * the FIQ ISR and the module in here.
513 + *
514 + * To get you started there is just an int that is incremented every FIQ
515 + * you can remove this when you are ready to customize, but it is useful
516 + * for testing
517 + */
518 +
519 +struct fiq_ipc {
520 +       u8 u8a[0]; /* placeholder */
521 +};
522 +
523 +/* actual definition lives in arch/arm/mach-s3c2440/fiq_c_isr.c */
524 +extern struct fiq_ipc fiq_ipc;
525 +
526 +extern void fiq_kick(void);  /* provoke a FIQ "immediately" */
527 +
528 +#endif /* _LINUX_FIQ_IPC_H */
529 diff --git a/include/asm-arm/plat-s3c24xx/irq.h b/include/asm-arm/plat-s3c24xx/irq.h
530 index 45746a9..bf15e1c 100644
531 --- a/include/asm-arm/plat-s3c24xx/irq.h
532 +++ b/include/asm-arm/plat-s3c24xx/irq.h
533 @@ -25,8 +25,15 @@ s3c_irqsub_mask(unsigned int irqno, unsigned int parentbit,
534  {
535         unsigned long mask;
536         unsigned long submask;
537 +#ifdef CONFIG_S3C2440_C_FIQ
538 +       unsigned long flags;
539 +#endif
540  
541         submask = __raw_readl(S3C2410_INTSUBMSK);
542 +#ifdef CONFIG_S3C2440_C_FIQ
543 +       local_save_flags(flags);
544 +       local_fiq_disable();
545 +#endif
546         mask = __raw_readl(S3C2410_INTMSK);
547  
548         submask |= (1UL << (irqno - IRQ_S3CUART_RX0));
549 @@ -39,6 +46,9 @@ s3c_irqsub_mask(unsigned int irqno, unsigned int parentbit,
550  
551         /* write back masks */
552         __raw_writel(submask, S3C2410_INTSUBMSK);
553 +#ifdef CONFIG_S3C2440_C_FIQ
554 +       local_irq_restore(flags);
555 +#endif
556  
557  }
558  
559 @@ -47,8 +57,15 @@ s3c_irqsub_unmask(unsigned int irqno, unsigned int parentbit)
560  {
561         unsigned long mask;
562         unsigned long submask;
563 +#ifdef CONFIG_S3C2440_C_FIQ
564 +       unsigned long flags;
565 +#endif
566  
567         submask = __raw_readl(S3C2410_INTSUBMSK);
568 +#ifdef CONFIG_S3C2440_C_FIQ
569 +       local_save_flags(flags);
570 +       local_fiq_disable();
571 +#endif
572         mask = __raw_readl(S3C2410_INTMSK);
573  
574         submask &= ~(1UL << (irqno - IRQ_S3CUART_RX0));
575 @@ -57,6 +74,9 @@ s3c_irqsub_unmask(unsigned int irqno, unsigned int parentbit)
576         /* write back masks */
577         __raw_writel(submask, S3C2410_INTSUBMSK);
578         __raw_writel(mask, S3C2410_INTMSK);
579 +#ifdef CONFIG_S3C2440_C_FIQ
580 +       local_irq_restore(flags);
581 +#endif
582  }
583  
584  
585 -- 
586 1.5.6.3
587