5b1cd7cd9654f98cacf07015d3f3534adb099c52
[openwrt.git] / target / linux / cns3xxx / patches-3.3 / 460-cns3xxx_fiq_support.patch
1 --- a/arch/arm/Kconfig
2 +++ b/arch/arm/Kconfig
3 @@ -375,6 +375,7 @@ config ARCH_CNS3XXX
4         select PCI_DOMAINS if PCI
5         select HAVE_ARM_TWD
6         select HAVE_SMP
7 +       select FIQ
8         help
9           Support for Cavium Networks CNS3XXX platform.
10  
11 --- a/arch/arm/kernel/fiq.c
12 +++ b/arch/arm/kernel/fiq.c
13 @@ -49,6 +49,8 @@
14  
15  static unsigned long no_fiq_insn;
16  
17 +unsigned int fiq_number[2] = {0, 0};
18 +
19  /* Default reacquire function
20   * - we always relinquish FIQ control
21   * - we always reacquire FIQ control
22 @@ -70,9 +72,12 @@ static struct fiq_handler *current_fiq =
23  
24  int show_fiq_list(struct seq_file *p, int prec)
25  {
26 -       if (current_fiq != &default_owner)
27 -               seq_printf(p, "%*s:              %s\n", prec, "FIQ",
28 -                       current_fiq->name);
29 +       if (current_fiq != &default_owner) {
30 +               seq_printf(p, "%*s: ", prec, "FIQ");
31 +               seq_printf(p, "%10u ", fiq_number[0]);
32 +               seq_printf(p, "%10u ", fiq_number[1]);
33 +               seq_printf(p, "      %s\n", current_fiq->name);
34 +       }
35  
36         return 0;
37  }
38 --- a/arch/arm/kernel/smp.c
39 +++ b/arch/arm/kernel/smp.c
40 @@ -400,13 +400,13 @@ void show_ipi_list(struct seq_file *p, i
41         unsigned int cpu, i;
42  
43         for (i = 0; i < NR_IPI; i++) {
44 -               seq_printf(p, "%*s%u: ", prec - 1, "IPI", i);
45 +               seq_printf(p, "%*s%u:", prec - 1, "IPI", i);
46  
47                 for_each_present_cpu(cpu)
48                         seq_printf(p, "%10u ",
49                                    __get_irq_stat(cpu, ipi_irqs[i]));
50  
51 -               seq_printf(p, " %s\n", ipi_types[i]);
52 +               seq_printf(p, "      %s\n", ipi_types[i]);
53         }
54  }
55  
56 --- a/arch/arm/mach-cns3xxx/Makefile
57 +++ b/arch/arm/mach-cns3xxx/Makefile
58 @@ -2,6 +2,6 @@ obj-$(CONFIG_ARCH_CNS3XXX)              += core.o pm
59  obj-$(CONFIG_PCI)                      += pcie.o
60  obj-$(CONFIG_MACH_CNS3420VB)           += cns3420vb.o
61  obj-$(CONFIG_MACH_GW2388)              += laguna.o
62 -obj-$(CONFIG_SMP)                      += platsmp.o headsmp.o
63 +obj-$(CONFIG_SMP)                      += platsmp.o headsmp.o cns3xxx_fiq.o
64  obj-$(CONFIG_HOTPLUG_CPU)              += hotplug.o
65  obj-$(CONFIG_LOCAL_TIMERS)             += localtimer.o
66 --- /dev/null
67 +++ b/arch/arm/mach-cns3xxx/cns3xxx_fiq.S
68 @@ -0,0 +1,97 @@
69 +/*
70 + *  linux/arch/arm/lib/floppydma.S
71 + *
72 + *  Copyright (C) 1995, 1996 Russell King
73 + *
74 + * This program is free software; you can redistribute it and/or modify
75 + * it under the terms of the GNU General Public License version 2 as
76 + * published by the Free Software Foundation.
77 + */
78 +#include <linux/linkage.h>
79 +#include <asm/assembler.h>
80 +#include <asm/asm-offsets.h>
81 +
82 +#define D_CACHE_LINE_SIZE 32
83 +
84 +       .text
85 +
86 +/*
87 + * R8  - DMA Start Address
88 + * R9  - DMA Length
89 + * R10 - DMA Direction
90 + * R11 - DMA type
91 + * R12 - fiq_buffer Address
92 + * R13 - DMA type Address
93 +*/
94 +
95 +       .global cns3xxx_fiq_end
96 +ENTRY(cns3xxx_fiq_start)
97 +       mov r8, #0
98 +       str r8, [r13]
99 +
100 +       ldr r9, [r12]
101 +       ldr r8, [r9]
102 +       add r8, r8, #1
103 +       str r8, [r9]
104 +
105 +       ldmib r12, {r8, r9, r10}
106 +       and r11, r10, #0x3000000
107 +       and r10, r10, #0xff
108 +
109 +       teq r11, #0x1000000
110 +       beq cns3xxx_dma_map_area
111 +       teq r11, #0x2000000
112 +       beq cns3xxx_dma_unmap_area
113 +       b cns3xxx_dma_flush_range
114 +
115 +cns3xxx_fiq_exit:
116 +       mov r8, #0
117 +       str r8, [r12, #12]
118 +       mcr p15, 0, r8, c7, c10, 4    @ drain write buffer
119 +       subs pc, lr, #4
120 +
121 +cns3xxx_dma_map_area:
122 +       add r9, r9, r8
123 +       teq r10, #DMA_FROM_DEVICE
124 +       beq cns3xxx_dma_inv_range
125 +       b cns3xxx_dma_clean_range
126 +
127 +cns3xxx_dma_unmap_area:
128 +       add r9, r9, r8
129 +       teq r10, #DMA_TO_DEVICE
130 +       bne cns3xxx_dma_inv_range
131 +       b cns3xxx_fiq_exit
132 +
133 +cns3xxx_dma_flush_range:
134 +       bic r8, r8, #D_CACHE_LINE_SIZE - 1
135 +1:
136 +       mcr p15, 0, r8, c7, c14, 1   @ clean & invalidate D line
137 +       add r8, r8, #D_CACHE_LINE_SIZE
138 +       cmp r8, r9
139 +       blo 1b
140 +       b cns3xxx_fiq_exit
141 +
142 +cns3xxx_dma_clean_range:
143 +       bic r8, r8, #D_CACHE_LINE_SIZE - 1
144 +1:
145 +       mcr p15, 0, r8, c7, c10, 1    @ clean D line
146 +       add r8, r8, #D_CACHE_LINE_SIZE
147 +       cmp r8, r9
148 +       blo 1b
149 +       b cns3xxx_fiq_exit
150 +
151 +cns3xxx_dma_inv_range:
152 +       tst r8, #D_CACHE_LINE_SIZE - 1
153 +       bic r8, r8, #D_CACHE_LINE_SIZE - 1
154 +       mcrne p15, 0, r8, c7, c10, 1    @ clean D line
155 +       tst r9, #D_CACHE_LINE_SIZE - 1
156 +       bic r9, r9, #D_CACHE_LINE_SIZE - 1
157 +       mcrne p15, 0, r9, c7, c14, 1    @ clean & invalidate D line
158 +1:
159 +       mcr p15, 0, r8, c7, c6, 1   @ invalidate D line
160 +       add r8, r8, #D_CACHE_LINE_SIZE
161 +       cmp r8, r9
162 +       blo 1b
163 +       b cns3xxx_fiq_exit
164 +
165 +cns3xxx_fiq_end:
166 --- a/arch/arm/mach-cns3xxx/include/mach/cns3xxx.h
167 +++ b/arch/arm/mach-cns3xxx/include/mach/cns3xxx.h
168 @@ -294,6 +294,7 @@
169  #define MISC_PCIE_INT_MASK(x)                  MISC_MEM_MAP(0x978 + (x) * 0x100)
170  #define MISC_PCIE_INT_STATUS(x)                        MISC_MEM_MAP(0x97C + (x) * 0x100)
171  
172 +#define MISC_FIQ_CPU(x)                                MISC_MEM_MAP(0xA58 - (x) * 0x4)
173  /*
174   * Power management and clock control
175   */
176 --- a/arch/arm/mach-cns3xxx/include/mach/irqs.h
177 +++ b/arch/arm/mach-cns3xxx/include/mach/irqs.h
178 @@ -14,6 +14,7 @@
179  #define IRQ_LOCALTIMER         29
180  #define IRQ_LOCALWDOG          30
181  #define IRQ_TC11MP_GIC_START   32
182 +#define FIQ_START 0
183  
184  #include <mach/cns3xxx.h>
185  
186 --- /dev/null
187 +++ b/arch/arm/mach-cns3xxx/include/mach/smp.h
188 @@ -0,0 +1,8 @@
189 +#ifndef __MACH_SMP_H
190 +#define __MACH_SMP_H
191 +
192 +extern void smp_dma_map_area(const void *, size_t, int);
193 +extern void smp_dma_unmap_area(const void *, size_t, int);
194 +extern void smp_dma_flush_range(const void *, const void *);
195 +
196 +#endif
197 --- a/arch/arm/mach-cns3xxx/platsmp.c
198 +++ b/arch/arm/mach-cns3xxx/platsmp.c
199 @@ -24,10 +24,27 @@
200  #include <asm/hardware/gic.h>
201  #include <asm/smp_scu.h>
202  #include <asm/unified.h>
203 -
204 +#include <asm/fiq.h>
205 +#include <mach/smp.h>
206  #include <mach/cns3xxx.h>
207  
208 +static struct fiq_handler fh = {
209 +       .name = "cns3xxx-fiq"
210 +};
211 +
212 +static unsigned int fiq_buffer[8];
213 +
214 +#define FIQ_ENABLED         0x80000000
215 +#define FIQ_GENERATE                           0x00010000
216 +#define CNS3XXX_MAP_AREA    0x01000000
217 +#define CNS3XXX_UNMAP_AREA  0x02000000
218 +#define CNS3XXX_FLUSH_RANGE 0x03000000
219 +
220  extern void cns3xxx_secondary_startup(void);
221 +extern unsigned char cns3xxx_fiq_start, cns3xxx_fiq_end;
222 +extern unsigned int fiq_number[2];
223 +extern struct cpu_cache_fns cpu_cache;
224 +struct cpu_cache_fns cpu_cache_save;
225  
226  #define SCU_CPU_STATUS 0x08
227  static void __iomem *scu_base;
228 @@ -38,12 +55,50 @@ static void __iomem *scu_base;
229   */
230  volatile int __cpuinitdata pen_release = -1;
231  
232 +static void __init cns3xxx_set_fiq_regs(void)
233 +{
234 +       struct pt_regs FIQ_regs;
235 +       unsigned int cpu = smp_processor_id();
236 +
237 +       if (cpu) {
238 +               FIQ_regs.ARM_ip = (unsigned int)&fiq_buffer[4];
239 +               FIQ_regs.ARM_sp = (unsigned int)MISC_FIQ_CPU(0);
240 +       } else {
241 +               FIQ_regs.ARM_ip = (unsigned int)&fiq_buffer[0];
242 +               FIQ_regs.ARM_sp = (unsigned int)MISC_FIQ_CPU(1);
243 +       }
244 +       set_fiq_regs(&FIQ_regs);
245 +}
246 +
247 +static void __init cns3xxx_init_fiq(void)
248 +{
249 +       void *fiqhandler_start;
250 +       unsigned int fiqhandler_length;
251 +       int ret;
252 +
253 +       fiqhandler_start = &cns3xxx_fiq_start;
254 +       fiqhandler_length = &cns3xxx_fiq_end - &cns3xxx_fiq_start;
255 +
256 +       ret = claim_fiq(&fh);
257 +
258 +       if (ret) {
259 +               return;
260 +       }
261 +
262 +       set_fiq_handler(fiqhandler_start, fiqhandler_length);
263 +       fiq_buffer[0] = (unsigned int)&fiq_number[0];
264 +       fiq_buffer[3] = 0;
265 +       fiq_buffer[4] = (unsigned int)&fiq_number[1];
266 +       fiq_buffer[7] = 0;
267 +}
268 +
269 +
270  /*
271   * Write pen_release in a way that is guaranteed to be visible to all
272   * observers, irrespective of whether they're taking part in coherency
273   * or not.  This is necessary for the hotplug code to work reliably.
274   */
275 -static void write_pen_release(int val)
276 +static void __cpuinit write_pen_release(int val)
277  {
278         pen_release = val;
279         smp_wmb();
280 @@ -63,12 +118,25 @@ void __cpuinit platform_secondary_init(u
281         gic_secondary_init(0);
282  
283         /*
284 +        * Setup Secondary Core FIQ regs
285 +        */
286 +       cns3xxx_set_fiq_regs();
287 +
288 +       /*
289          * let the primary processor know we're out of the
290          * pen, then head off into the C entry point
291          */
292         write_pen_release(-1);
293  
294         /*
295 +        * Fixup DMA Operations
296 +        *
297 +        */
298 +       cpu_cache.dma_map_area = (void *)smp_dma_map_area;
299 +       cpu_cache.dma_unmap_area = (void *)smp_dma_unmap_area;
300 +       cpu_cache.dma_flush_range = (void *)smp_dma_flush_range;
301 +       
302 +       /*
303          * Synchronise with the boot thread.
304          */
305         spin_lock(&boot_lock);
306 @@ -171,4 +239,112 @@ void __init platform_smp_prepare_cpus(un
307          */
308         __raw_writel(virt_to_phys(cns3xxx_secondary_startup),
309                         (void __iomem *)(CNS3XXX_MISC_BASE_VIRT + 0x0600));
310 +
311 +       /*
312 +        * Setup FIQ's for main cpu
313 +        */
314 +       cns3xxx_init_fiq();
315 +       cns3xxx_set_fiq_regs();
316 +       memcpy((void *)&cpu_cache_save, (void *)&cpu_cache, sizeof(struct cpu_cache_fns));
317 +}
318 +
319 +
320 +static inline unsigned long cns3xxx_cpu_id(void)
321 +{
322 +       unsigned long cpu;
323 +
324 +       asm volatile(
325 +               " mrc p15, 0, %0, c0, c0, 5  @ cns3xxx_cpu_id\n"
326 +               : "=r" (cpu) : : "memory", "cc");
327 +       return (cpu & 0xf);
328 +}
329 +
330 +void smp_dma_map_area(const void *addr, size_t size, int dir)
331 +{
332 +       unsigned int cpu;
333 +       unsigned long flags;
334 +       raw_local_irq_save(flags);
335 +       cpu = cns3xxx_cpu_id();
336 +       if (cpu) {
337 +               fiq_buffer[1] = (unsigned int)addr;
338 +               fiq_buffer[2] = size;
339 +               fiq_buffer[3] = dir | CNS3XXX_MAP_AREA | FIQ_ENABLED;
340 +               smp_mb();
341 +               __raw_writel(FIQ_GENERATE, MISC_FIQ_CPU(1));
342 +
343 +               cpu_cache_save.dma_map_area(addr, size, dir);
344 +               while ((fiq_buffer[3]) & FIQ_ENABLED) { barrier(); }
345 +       } else {
346 +
347 +               fiq_buffer[5] = (unsigned int)addr;
348 +               fiq_buffer[6] = size;
349 +               fiq_buffer[7] = dir | CNS3XXX_MAP_AREA | FIQ_ENABLED;
350 +               smp_mb();
351 +               __raw_writel(FIQ_GENERATE, MISC_FIQ_CPU(0));
352 +
353 +               cpu_cache_save.dma_map_area(addr, size, dir);
354 +               while ((fiq_buffer[7]) & FIQ_ENABLED) { barrier(); }
355 +       }
356 +       raw_local_irq_restore(flags);
357 +}
358 +
359 +void smp_dma_unmap_area(const void *addr, size_t size, int dir)
360 +{
361 +       unsigned int cpu;
362 +       unsigned long flags;
363 +
364 +       raw_local_irq_save(flags);
365 +       cpu = cns3xxx_cpu_id();
366 +       if (cpu) {
367 +
368 +               fiq_buffer[1] = (unsigned int)addr;
369 +               fiq_buffer[2] = size;
370 +               fiq_buffer[3] = dir | CNS3XXX_UNMAP_AREA | FIQ_ENABLED;
371 +               smp_mb();
372 +               __raw_writel(FIQ_GENERATE, MISC_FIQ_CPU(1));
373 +
374 +               cpu_cache_save.dma_unmap_area(addr, size, dir);
375 +               while ((fiq_buffer[3]) & FIQ_ENABLED) { barrier(); }
376 +       } else {
377 +
378 +               fiq_buffer[5] = (unsigned int)addr;
379 +               fiq_buffer[6] = size;
380 +               fiq_buffer[7] = dir | CNS3XXX_UNMAP_AREA | FIQ_ENABLED;
381 +               smp_mb();
382 +               __raw_writel(FIQ_GENERATE, MISC_FIQ_CPU(0));
383 +
384 +               cpu_cache_save.dma_unmap_area(addr, size, dir);
385 +               while ((fiq_buffer[7]) & FIQ_ENABLED) { barrier(); }
386 +       }
387 +       raw_local_irq_restore(flags);
388 +}
389 +
390 +void smp_dma_flush_range(const void *start, const void *end)
391 +{
392 +       unsigned int cpu;
393 +       unsigned long flags;
394 +       raw_local_irq_save(flags);
395 +       cpu = cns3xxx_cpu_id();
396 +       if (cpu) {
397 +
398 +               fiq_buffer[1] = (unsigned int)start;
399 +               fiq_buffer[2] = (unsigned int)end;
400 +               fiq_buffer[3] = CNS3XXX_FLUSH_RANGE | FIQ_ENABLED;
401 +               smp_mb();
402 +               __raw_writel(FIQ_GENERATE, MISC_FIQ_CPU(1));
403 +
404 +               cpu_cache_save.dma_flush_range(start, end);
405 +               while ((fiq_buffer[3]) & FIQ_ENABLED) { barrier(); }
406 +       } else {
407 +
408 +               fiq_buffer[5] = (unsigned int)start;
409 +               fiq_buffer[6] = (unsigned int)end;
410 +               fiq_buffer[7] = CNS3XXX_FLUSH_RANGE | FIQ_ENABLED;
411 +               smp_mb();
412 +               __raw_writel(FIQ_GENERATE, MISC_FIQ_CPU(0));
413 +
414 +               cpu_cache_save.dma_flush_range(start, end);
415 +               while ((fiq_buffer[7]) & FIQ_ENABLED) { barrier(); }
416 +       }
417 +       raw_local_irq_restore(flags);
418  }
419 --- a/arch/arm/mm/Kconfig
420 +++ b/arch/arm/mm/Kconfig
421 @@ -793,7 +793,7 @@ config NEEDS_SYSCALL_FOR_CMPXCHG
422  
423  config DMA_CACHE_RWFO
424         bool "Enable read/write for ownership DMA cache maintenance"
425 -       depends on CPU_V6K && SMP
426 +       depends on CPU_V6K && SMP && !ARCH_CNS3XXX
427         default y
428         help
429           The Snoop Control Unit on ARM11MPCore does not detect the