Commit | Line | Data |
---|---|---|
5c642506 J |
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 | { | |
39263eeb | 90 | scheduler_ipi(); |
5c642506 J |
91 | } |
92 | ||
93 | /* | |
94 | * Called before going into mips code, early cpu init | |
95 | */ | |
96 | void nlm_early_init_secondary(void) | |
97 | { | |
98 | write_c0_ebase((uint32_t)nlm_common_ebase); | |
99 | /* TLB partition here later */ | |
100 | } | |
101 | ||
102 | /* | |
103 | * Code to run on secondary just after probing the CPU | |
104 | */ | |
105 | static void __cpuinit nlm_init_secondary(void) | |
106 | { | |
107 | nlm_smp_irq_init(); | |
108 | } | |
109 | ||
110 | void nlm_smp_finish(void) | |
111 | { | |
112 | #ifdef notyet | |
113 | nlm_common_msgring_cpu_init(); | |
114 | #endif | |
39263eeb | 115 | local_irq_enable(); |
5c642506 J |
116 | } |
117 | ||
118 | void nlm_cpus_done(void) | |
119 | { | |
120 | } | |
121 | ||
122 | /* | |
123 | * Boot all other cpus in the system, initialize them, and bring them into | |
124 | * the boot function | |
125 | */ | |
126 | int nlm_cpu_unblock[NR_CPUS]; | |
127 | int nlm_cpu_ready[NR_CPUS]; | |
128 | unsigned long nlm_next_gp; | |
129 | unsigned long nlm_next_sp; | |
130 | cpumask_t phys_cpu_present_map; | |
131 | ||
132 | void nlm_boot_secondary(int logical_cpu, struct task_struct *idle) | |
133 | { | |
134 | unsigned long gp = (unsigned long)task_thread_info(idle); | |
135 | unsigned long sp = (unsigned long)__KSTK_TOS(idle); | |
136 | int cpu = cpu_logical_map(logical_cpu); | |
137 | ||
138 | nlm_next_sp = sp; | |
139 | nlm_next_gp = gp; | |
140 | ||
141 | /* barrier */ | |
142 | __sync(); | |
143 | nlm_cpu_unblock[cpu] = 1; | |
144 | } | |
145 | ||
146 | void __init nlm_smp_setup(void) | |
147 | { | |
148 | unsigned int boot_cpu; | |
149 | int num_cpus, i; | |
150 | ||
151 | boot_cpu = hard_smp_processor_id(); | |
152 | cpus_clear(phys_cpu_present_map); | |
153 | ||
154 | cpu_set(boot_cpu, phys_cpu_present_map); | |
155 | __cpu_number_map[boot_cpu] = 0; | |
156 | __cpu_logical_map[0] = boot_cpu; | |
157 | cpu_set(0, cpu_possible_map); | |
158 | ||
159 | num_cpus = 1; | |
160 | for (i = 0; i < NR_CPUS; i++) { | |
b2788965 HD |
161 | /* |
162 | * BSP is not set in nlm_cpu_ready array, it is only for | |
163 | * ASPs (goto see smpboot.S) | |
164 | */ | |
5c642506 J |
165 | if (nlm_cpu_ready[i]) { |
166 | cpu_set(i, phys_cpu_present_map); | |
167 | __cpu_number_map[i] = num_cpus; | |
168 | __cpu_logical_map[num_cpus] = i; | |
169 | cpu_set(num_cpus, cpu_possible_map); | |
170 | ++num_cpus; | |
171 | } | |
172 | } | |
173 | ||
174 | pr_info("Phys CPU present map: %lx, possible map %lx\n", | |
175 | (unsigned long)phys_cpu_present_map.bits[0], | |
176 | (unsigned long)cpu_possible_map.bits[0]); | |
177 | ||
178 | pr_info("Detected %i Slave CPU(s)\n", num_cpus); | |
179 | } | |
180 | ||
181 | void nlm_prepare_cpus(unsigned int max_cpus) | |
182 | { | |
183 | } | |
184 | ||
185 | struct plat_smp_ops nlm_smp_ops = { | |
186 | .send_ipi_single = nlm_send_ipi_single, | |
187 | .send_ipi_mask = nlm_send_ipi_mask, | |
188 | .init_secondary = nlm_init_secondary, | |
189 | .smp_finish = nlm_smp_finish, | |
190 | .cpus_done = nlm_cpus_done, | |
191 | .boot_secondary = nlm_boot_secondary, | |
192 | .smp_setup = nlm_smp_setup, | |
193 | .prepare_cpus = nlm_prepare_cpus, | |
194 | }; | |
195 | ||
196 | unsigned long secondary_entry_point; | |
197 | ||
a74e3353 | 198 | int __cpuinit nlm_wakeup_secondary_cpus(u32 wakeup_mask) |
5c642506 J |
199 | { |
200 | unsigned int tid, pid, ipi, i, boot_cpu; | |
201 | void *reset_vec; | |
202 | ||
203 | secondary_entry_point = (unsigned long)prom_pre_boot_secondary_cpus; | |
204 | reset_vec = (void *)CKSEG1ADDR(0x1fc00000); | |
205 | memcpy(reset_vec, nlm_boot_smp_nmi, 0x80); | |
206 | boot_cpu = hard_smp_processor_id(); | |
207 | ||
208 | for (i = 0; i < NR_CPUS; i++) { | |
209 | if (i == boot_cpu) | |
210 | continue; | |
211 | if (wakeup_mask & (1u << i)) { | |
212 | tid = i & 0x3; | |
213 | pid = (i >> 2) & 0x7; | |
214 | ipi = (tid << 16) | (pid << 20) | (1 << 8); | |
215 | pic_send_ipi(ipi); | |
216 | } | |
217 | } | |
218 | ||
219 | return 0; | |
220 | } |