Merge git://git.kernel.org/pub/scm/linux/kernel/git/sam/kbuild-fixes
[linux-2.6] / arch / mips / cavium-octeon / smp.c
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2004-2008 Cavium Networks
7  */
8 #include <linux/init.h>
9 #include <linux/delay.h>
10 #include <linux/smp.h>
11 #include <linux/interrupt.h>
12 #include <linux/kernel_stat.h>
13 #include <linux/sched.h>
14 #include <linux/module.h>
15
16 #include <asm/mmu_context.h>
17 #include <asm/system.h>
18 #include <asm/time.h>
19
20 #include <asm/octeon/octeon.h>
21
22 volatile unsigned long octeon_processor_boot = 0xff;
23 volatile unsigned long octeon_processor_sp;
24 volatile unsigned long octeon_processor_gp;
25
26 static irqreturn_t mailbox_interrupt(int irq, void *dev_id)
27 {
28         const int coreid = cvmx_get_core_num();
29         uint64_t action;
30
31         /* Load the mailbox register to figure out what we're supposed to do */
32         action = cvmx_read_csr(CVMX_CIU_MBOX_CLRX(coreid));
33
34         /* Clear the mailbox to clear the interrupt */
35         cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), action);
36
37         if (action & SMP_CALL_FUNCTION)
38                 smp_call_function_interrupt();
39
40         /* Check if we've been told to flush the icache */
41         if (action & SMP_ICACHE_FLUSH)
42                 asm volatile ("synci 0($0)\n");
43         return IRQ_HANDLED;
44 }
45
46 /**
47  * Cause the function described by call_data to be executed on the passed
48  * cpu.  When the function has finished, increment the finished field of
49  * call_data.
50  */
51 void octeon_send_ipi_single(int cpu, unsigned int action)
52 {
53         int coreid = cpu_logical_map(cpu);
54         /*
55         pr_info("SMP: Mailbox send cpu=%d, coreid=%d, action=%u\n", cpu,
56                coreid, action);
57         */
58         cvmx_write_csr(CVMX_CIU_MBOX_SETX(coreid), action);
59 }
60
61 static inline void octeon_send_ipi_mask(cpumask_t mask, unsigned int action)
62 {
63         unsigned int i;
64
65         for_each_cpu_mask(i, mask)
66                 octeon_send_ipi_single(i, action);
67 }
68
69 /**
70  * Detect available CPUs, populate phys_cpu_present_map
71  */
72 static void octeon_smp_setup(void)
73 {
74         const int coreid = cvmx_get_core_num();
75         int cpus;
76         int id;
77
78         int core_mask = octeon_get_boot_coremask();
79
80         cpus_clear(cpu_possible_map);
81         __cpu_number_map[coreid] = 0;
82         __cpu_logical_map[0] = coreid;
83         cpu_set(0, cpu_possible_map);
84
85         cpus = 1;
86         for (id = 0; id < 16; id++) {
87                 if ((id != coreid) && (core_mask & (1 << id))) {
88                         cpu_set(cpus, cpu_possible_map);
89                         __cpu_number_map[id] = cpus;
90                         __cpu_logical_map[cpus] = id;
91                         cpus++;
92                 }
93         }
94 }
95
96 /**
97  * Firmware CPU startup hook
98  *
99  */
100 static void octeon_boot_secondary(int cpu, struct task_struct *idle)
101 {
102         int count;
103
104         pr_info("SMP: Booting CPU%02d (CoreId %2d)...\n", cpu,
105                 cpu_logical_map(cpu));
106
107         octeon_processor_sp = __KSTK_TOS(idle);
108         octeon_processor_gp = (unsigned long)(task_thread_info(idle));
109         octeon_processor_boot = cpu_logical_map(cpu);
110         mb();
111
112         count = 10000;
113         while (octeon_processor_sp && count) {
114                 /* Waiting for processor to get the SP and GP */
115                 udelay(1);
116                 count--;
117         }
118         if (count == 0)
119                 pr_err("Secondary boot timeout\n");
120 }
121
122 /**
123  * After we've done initial boot, this function is called to allow the
124  * board code to clean up state, if needed
125  */
126 static void octeon_init_secondary(void)
127 {
128         const int coreid = cvmx_get_core_num();
129         union cvmx_ciu_intx_sum0 interrupt_enable;
130
131         octeon_check_cpu_bist();
132         octeon_init_cvmcount();
133         /*
134         pr_info("SMP: CPU%d (CoreId %lu) started\n", cpu, coreid);
135         */
136         /* Enable Mailbox interrupts to this core. These are the only
137            interrupts allowed on line 3 */
138         cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), 0xffffffff);
139         interrupt_enable.u64 = 0;
140         interrupt_enable.s.mbox = 0x3;
141         cvmx_write_csr(CVMX_CIU_INTX_EN0((coreid * 2)), interrupt_enable.u64);
142         cvmx_write_csr(CVMX_CIU_INTX_EN0((coreid * 2 + 1)), 0);
143         cvmx_write_csr(CVMX_CIU_INTX_EN1((coreid * 2)), 0);
144         cvmx_write_csr(CVMX_CIU_INTX_EN1((coreid * 2 + 1)), 0);
145         /* Enable core interrupt processing for 2,3 and 7 */
146         set_c0_status(0x8c01);
147 }
148
149 /**
150  * Callout to firmware before smp_init
151  *
152  */
153 void octeon_prepare_cpus(unsigned int max_cpus)
154 {
155         cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), 0xffffffff);
156         if (request_irq(OCTEON_IRQ_MBOX0, mailbox_interrupt, IRQF_SHARED,
157                         "mailbox0", mailbox_interrupt)) {
158                 panic("Cannot request_irq(OCTEON_IRQ_MBOX0)\n");
159         }
160         if (request_irq(OCTEON_IRQ_MBOX1, mailbox_interrupt, IRQF_SHARED,
161                         "mailbox1", mailbox_interrupt)) {
162                 panic("Cannot request_irq(OCTEON_IRQ_MBOX1)\n");
163         }
164 }
165
166 /**
167  * Last chance for the board code to finish SMP initialization before
168  * the CPU is "online".
169  */
170 static void octeon_smp_finish(void)
171 {
172 #ifdef CONFIG_CAVIUM_GDB
173         unsigned long tmp;
174         /* Pulse MCD0 signal on Ctrl-C to stop all the cores. Also set the MCD0
175            to be not masked by this core so we know the signal is received by
176            someone */
177         asm volatile ("dmfc0 %0, $22\n"
178                       "ori   %0, %0, 0x9100\n" "dmtc0 %0, $22\n" : "=r" (tmp));
179 #endif
180
181         octeon_user_io_init();
182
183         /* to generate the first CPU timer interrupt */
184         write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ);
185 }
186
187 /**
188  * Hook for after all CPUs are online
189  */
190 static void octeon_cpus_done(void)
191 {
192 #ifdef CONFIG_CAVIUM_GDB
193         unsigned long tmp;
194         /* Pulse MCD0 signal on Ctrl-C to stop all the cores. Also set the MCD0
195            to be not masked by this core so we know the signal is received by
196            someone */
197         asm volatile ("dmfc0 %0, $22\n"
198                       "ori   %0, %0, 0x9100\n" "dmtc0 %0, $22\n" : "=r" (tmp));
199 #endif
200 }
201
202 struct plat_smp_ops octeon_smp_ops = {
203         .send_ipi_single        = octeon_send_ipi_single,
204         .send_ipi_mask          = octeon_send_ipi_mask,
205         .init_secondary         = octeon_init_secondary,
206         .smp_finish             = octeon_smp_finish,
207         .cpus_done              = octeon_cpus_done,
208         .boot_secondary         = octeon_boot_secondary,
209         .smp_setup              = octeon_smp_setup,
210         .prepare_cpus           = octeon_prepare_cpus,
211 };