diff options
Diffstat (limited to 'arch/mips/netlogic/xlr/smp.c')
-rw-r--r-- | arch/mips/netlogic/xlr/smp.c | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/arch/mips/netlogic/xlr/smp.c b/arch/mips/netlogic/xlr/smp.c new file mode 100644 index 000000000000..b495a7f1433b --- /dev/null +++ b/arch/mips/netlogic/xlr/smp.c | |||
@@ -0,0 +1,225 @@ | |||
1 | /* | ||
2 | * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights | ||
3 | * reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the NetLogic | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/delay.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/smp.h> | ||
39 | #include <linux/irq.h> | ||
40 | |||
41 | #include <asm/mmu_context.h> | ||
42 | |||
43 | #include <asm/netlogic/interrupt.h> | ||
44 | #include <asm/netlogic/mips-extns.h> | ||
45 | |||
46 | #include <asm/netlogic/xlr/iomap.h> | ||
47 | #include <asm/netlogic/xlr/pic.h> | ||
48 | #include <asm/netlogic/xlr/xlr.h> | ||
49 | |||
50 | void core_send_ipi(int logical_cpu, unsigned int action) | ||
51 | { | ||
52 | int cpu = cpu_logical_map(logical_cpu); | ||
53 | u32 tid = cpu & 0x3; | ||
54 | u32 pid = (cpu >> 2) & 0x07; | ||
55 | u32 ipi = (tid << 16) | (pid << 20); | ||
56 | |||
57 | if (action & SMP_CALL_FUNCTION) | ||
58 | ipi |= IRQ_IPI_SMP_FUNCTION; | ||
59 | else if (action & SMP_RESCHEDULE_YOURSELF) | ||
60 | ipi |= IRQ_IPI_SMP_RESCHEDULE; | ||
61 | else | ||
62 | return; | ||
63 | |||
64 | pic_send_ipi(ipi); | ||
65 | } | ||
66 | |||
67 | void nlm_send_ipi_single(int cpu, unsigned int action) | ||
68 | { | ||
69 | core_send_ipi(cpu, action); | ||
70 | } | ||
71 | |||
72 | void nlm_send_ipi_mask(const struct cpumask *mask, unsigned int action) | ||
73 | { | ||
74 | int cpu; | ||
75 | |||
76 | for_each_cpu(cpu, mask) { | ||
77 | core_send_ipi(cpu, action); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | /* IRQ_IPI_SMP_FUNCTION Handler */ | ||
82 | void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc) | ||
83 | { | ||
84 | smp_call_function_interrupt(); | ||
85 | } | ||
86 | |||
87 | /* IRQ_IPI_SMP_RESCHEDULE handler */ | ||
88 | void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc) | ||
89 | { | ||
90 | set_need_resched(); | ||
91 | } | ||
92 | |||
93 | void nlm_common_ipi_handler(int irq, struct pt_regs *regs) | ||
94 | { | ||
95 | if (irq == IRQ_IPI_SMP_FUNCTION) { | ||
96 | smp_call_function_interrupt(); | ||
97 | } else { | ||
98 | /* Announce that we are for reschduling */ | ||
99 | set_need_resched(); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | * Called before going into mips code, early cpu init | ||
105 | */ | ||
106 | void nlm_early_init_secondary(void) | ||
107 | { | ||
108 | write_c0_ebase((uint32_t)nlm_common_ebase); | ||
109 | /* TLB partition here later */ | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | * Code to run on secondary just after probing the CPU | ||
114 | */ | ||
115 | static void __cpuinit nlm_init_secondary(void) | ||
116 | { | ||
117 | nlm_smp_irq_init(); | ||
118 | } | ||
119 | |||
120 | void nlm_smp_finish(void) | ||
121 | { | ||
122 | #ifdef notyet | ||
123 | nlm_common_msgring_cpu_init(); | ||
124 | #endif | ||
125 | } | ||
126 | |||
127 | void nlm_cpus_done(void) | ||
128 | { | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | * Boot all other cpus in the system, initialize them, and bring them into | ||
133 | * the boot function | ||
134 | */ | ||
135 | int nlm_cpu_unblock[NR_CPUS]; | ||
136 | int nlm_cpu_ready[NR_CPUS]; | ||
137 | unsigned long nlm_next_gp; | ||
138 | unsigned long nlm_next_sp; | ||
139 | cpumask_t phys_cpu_present_map; | ||
140 | |||
141 | void nlm_boot_secondary(int logical_cpu, struct task_struct *idle) | ||
142 | { | ||
143 | unsigned long gp = (unsigned long)task_thread_info(idle); | ||
144 | unsigned long sp = (unsigned long)__KSTK_TOS(idle); | ||
145 | int cpu = cpu_logical_map(logical_cpu); | ||
146 | |||
147 | nlm_next_sp = sp; | ||
148 | nlm_next_gp = gp; | ||
149 | |||
150 | /* barrier */ | ||
151 | __sync(); | ||
152 | nlm_cpu_unblock[cpu] = 1; | ||
153 | } | ||
154 | |||
155 | void __init nlm_smp_setup(void) | ||
156 | { | ||
157 | unsigned int boot_cpu; | ||
158 | int num_cpus, i; | ||
159 | |||
160 | boot_cpu = hard_smp_processor_id(); | ||
161 | cpus_clear(phys_cpu_present_map); | ||
162 | |||
163 | cpu_set(boot_cpu, phys_cpu_present_map); | ||
164 | __cpu_number_map[boot_cpu] = 0; | ||
165 | __cpu_logical_map[0] = boot_cpu; | ||
166 | cpu_set(0, cpu_possible_map); | ||
167 | |||
168 | num_cpus = 1; | ||
169 | for (i = 0; i < NR_CPUS; i++) { | ||
170 | if (nlm_cpu_ready[i]) { | ||
171 | cpu_set(i, phys_cpu_present_map); | ||
172 | __cpu_number_map[i] = num_cpus; | ||
173 | __cpu_logical_map[num_cpus] = i; | ||
174 | cpu_set(num_cpus, cpu_possible_map); | ||
175 | ++num_cpus; | ||
176 | } | ||
177 | } | ||
178 | |||
179 | pr_info("Phys CPU present map: %lx, possible map %lx\n", | ||
180 | (unsigned long)phys_cpu_present_map.bits[0], | ||
181 | (unsigned long)cpu_possible_map.bits[0]); | ||
182 | |||
183 | pr_info("Detected %i Slave CPU(s)\n", num_cpus); | ||
184 | } | ||
185 | |||
186 | void nlm_prepare_cpus(unsigned int max_cpus) | ||
187 | { | ||
188 | } | ||
189 | |||
190 | struct plat_smp_ops nlm_smp_ops = { | ||
191 | .send_ipi_single = nlm_send_ipi_single, | ||
192 | .send_ipi_mask = nlm_send_ipi_mask, | ||
193 | .init_secondary = nlm_init_secondary, | ||
194 | .smp_finish = nlm_smp_finish, | ||
195 | .cpus_done = nlm_cpus_done, | ||
196 | .boot_secondary = nlm_boot_secondary, | ||
197 | .smp_setup = nlm_smp_setup, | ||
198 | .prepare_cpus = nlm_prepare_cpus, | ||
199 | }; | ||
200 | |||
201 | unsigned long secondary_entry_point; | ||
202 | |||
203 | int nlm_wakeup_secondary_cpus(u32 wakeup_mask) | ||
204 | { | ||
205 | unsigned int tid, pid, ipi, i, boot_cpu; | ||
206 | void *reset_vec; | ||
207 | |||
208 | secondary_entry_point = (unsigned long)prom_pre_boot_secondary_cpus; | ||
209 | reset_vec = (void *)CKSEG1ADDR(0x1fc00000); | ||
210 | memcpy(reset_vec, nlm_boot_smp_nmi, 0x80); | ||
211 | boot_cpu = hard_smp_processor_id(); | ||
212 | |||
213 | for (i = 0; i < NR_CPUS; i++) { | ||
214 | if (i == boot_cpu) | ||
215 | continue; | ||
216 | if (wakeup_mask & (1u << i)) { | ||
217 | tid = i & 0x3; | ||
218 | pid = (i >> 2) & 0x7; | ||
219 | ipi = (tid << 16) | (pid << 20) | (1 << 8); | ||
220 | pic_send_ipi(ipi); | ||
221 | } | ||
222 | } | ||
223 | |||
224 | return 0; | ||
225 | } | ||