]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General | |
3 | * Public License. See the file "COPYING" in the main directory of this | |
4 | * archive for more details. | |
5 | * | |
6 | * Copyright (C) 2000 - 2001 by Kanoj Sarcar (kanoj@sgi.com) | |
7 | * Copyright (C) 2000 - 2001 by Silicon Graphics, Inc. | |
8 | */ | |
9 | #include <linux/init.h> | |
10 | #include <linux/sched.h> | |
ee6a3d19 | 11 | #include <linux/topology.h> |
1da177e4 LT |
12 | #include <linux/nodemask.h> |
13 | #include <asm/page.h> | |
14 | #include <asm/processor.h> | |
15 | #include <asm/sn/arch.h> | |
16 | #include <asm/sn/gda.h> | |
17 | #include <asm/sn/intr.h> | |
18 | #include <asm/sn/klconfig.h> | |
19 | #include <asm/sn/launch.h> | |
20 | #include <asm/sn/mapped_kernel.h> | |
21 | #include <asm/sn/sn_private.h> | |
22 | #include <asm/sn/types.h> | |
23 | #include <asm/sn/sn0/hubpi.h> | |
24 | #include <asm/sn/sn0/hubio.h> | |
25 | #include <asm/sn/sn0/ip27.h> | |
26 | ||
27 | /* | |
28 | * Takes as first input the PROM assigned cpu id, and the kernel | |
29 | * assigned cpu id as the second. | |
30 | */ | |
31 | static void alloc_cpupda(cpuid_t cpu, int cpunum) | |
32 | { | |
33 | cnodeid_t node = get_cpu_cnode(cpu); | |
34 | nasid_t nasid = COMPACT_TO_NASID_NODEID(node); | |
35 | ||
36 | cputonasid(cpunum) = nasid; | |
cc6e8e08 | 37 | sn_cpu_info[cpunum].p_nodeid = node; |
1da177e4 LT |
38 | cputoslice(cpunum) = get_cpu_slice(cpu); |
39 | } | |
40 | ||
41 | static nasid_t get_actual_nasid(lboard_t *brd) | |
42 | { | |
43 | klhub_t *hub; | |
44 | ||
45 | if (!brd) | |
46 | return INVALID_NASID; | |
47 | ||
48 | /* find out if we are a completely disabled brd. */ | |
49 | hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); | |
50 | if (!hub) | |
51 | return INVALID_NASID; | |
52 | if (!(hub->hub_info.flags & KLINFO_ENABLE)) /* disabled node brd */ | |
53 | return hub->hub_info.physid; | |
54 | else | |
55 | return brd->brd_nasid; | |
56 | } | |
57 | ||
58 | static int do_cpumask(cnodeid_t cnode, nasid_t nasid, int highest) | |
59 | { | |
60 | static int tot_cpus_found = 0; | |
61 | lboard_t *brd; | |
62 | klcpu_t *acpu; | |
63 | int cpus_found = 0; | |
64 | cpuid_t cpuid; | |
65 | ||
66 | brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27); | |
67 | ||
68 | do { | |
69 | acpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU); | |
70 | while (acpu) { | |
71 | cpuid = acpu->cpu_info.virtid; | |
72 | /* cnode is not valid for completely disabled brds */ | |
73 | if (get_actual_nasid(brd) == brd->brd_nasid) | |
74 | cpuid_to_compact_node[cpuid] = cnode; | |
75 | if (cpuid > highest) | |
76 | highest = cpuid; | |
77 | /* Only let it join in if it's marked enabled */ | |
78 | if ((acpu->cpu_info.flags & KLINFO_ENABLE) && | |
79 | (tot_cpus_found != NR_CPUS)) { | |
0b5f9c00 | 80 | set_cpu_possible(cpuid, true); |
1da177e4 LT |
81 | alloc_cpupda(cpuid, tot_cpus_found); |
82 | cpus_found++; | |
83 | tot_cpus_found++; | |
84 | } | |
85 | acpu = (klcpu_t *)find_component(brd, (klinfo_t *)acpu, | |
86 | KLSTRUCT_CPU); | |
87 | } | |
88 | brd = KLCF_NEXT(brd); | |
89 | if (!brd) | |
90 | break; | |
91 | ||
92 | brd = find_lboard(brd, KLTYPE_IP27); | |
93 | } while (brd); | |
94 | ||
95 | return highest; | |
96 | } | |
97 | ||
98 | void cpu_node_probe(void) | |
99 | { | |
100 | int i, highest = 0; | |
101 | gda_t *gdap = GDA; | |
102 | ||
103 | /* | |
104 | * Initialize the arrays to invalid nodeid (-1) | |
105 | */ | |
106 | for (i = 0; i < MAX_COMPACT_NODES; i++) | |
107 | compact_to_nasid_node[i] = INVALID_NASID; | |
108 | for (i = 0; i < MAX_NASIDS; i++) | |
109 | nasid_to_compact_node[i] = INVALID_CNODEID; | |
110 | for (i = 0; i < MAXCPUS; i++) | |
111 | cpuid_to_compact_node[i] = INVALID_CNODEID; | |
112 | ||
113 | /* | |
114 | * MCD - this whole "compact node" stuff can probably be dropped, | |
115 | * as we can handle sparse numbering now | |
116 | */ | |
117 | nodes_clear(node_online_map); | |
118 | for (i = 0; i < MAX_COMPACT_NODES; i++) { | |
119 | nasid_t nasid = gdap->g_nasidtable[i]; | |
120 | if (nasid == INVALID_NASID) | |
121 | break; | |
122 | compact_to_nasid_node[i] = nasid; | |
123 | nasid_to_compact_node[nasid] = i; | |
124 | node_set_online(num_online_nodes()); | |
125 | highest = do_cpumask(i, nasid, highest); | |
126 | } | |
127 | ||
128 | printk("Discovered %d cpus on %d nodes\n", highest + 1, num_online_nodes()); | |
129 | } | |
130 | ||
39408c6a | 131 | static __init void intr_clear_all(nasid_t nasid) |
1da177e4 | 132 | { |
1da177e4 LT |
133 | int i; |
134 | ||
1da177e4 LT |
135 | REMOTE_HUB_S(nasid, PI_INT_MASK0_A, 0); |
136 | REMOTE_HUB_S(nasid, PI_INT_MASK0_B, 0); | |
137 | REMOTE_HUB_S(nasid, PI_INT_MASK1_A, 0); | |
138 | REMOTE_HUB_S(nasid, PI_INT_MASK1_B, 0); | |
39408c6a RB |
139 | |
140 | for (i = 0; i < 128; i++) | |
141 | REMOTE_HUB_CLR_INTR(nasid, i); | |
1da177e4 LT |
142 | } |
143 | ||
87353d8a | 144 | static void ip27_send_ipi_single(int destid, unsigned int action) |
1da177e4 | 145 | { |
87353d8a | 146 | int irq; |
1da177e4 | 147 | |
87353d8a RB |
148 | switch (action) { |
149 | case SMP_RESCHEDULE_YOURSELF: | |
150 | irq = CPU_RESCHED_A_IRQ; | |
151 | break; | |
152 | case SMP_CALL_FUNCTION: | |
153 | irq = CPU_CALL_A_IRQ; | |
154 | break; | |
155 | default: | |
156 | panic("sendintr"); | |
de1db6ff | 157 | } |
1da177e4 | 158 | |
87353d8a | 159 | irq += cputoslice(destid); |
1da177e4 LT |
160 | |
161 | /* | |
87353d8a RB |
162 | * Convert the compact hub number to the NASID to get the correct |
163 | * part of the address space. Then set the interrupt bit associated | |
164 | * with the CPU we want to send the interrupt to. | |
1da177e4 | 165 | */ |
87353d8a | 166 | REMOTE_HUB_SEND_INTR(COMPACT_TO_NASID_NODEID(cpu_to_node(destid)), irq); |
1da177e4 LT |
167 | } |
168 | ||
b533e652 | 169 | static void ip27_send_ipi_mask(const struct cpumask *mask, unsigned int action) |
87353d8a RB |
170 | { |
171 | unsigned int i; | |
172 | ||
48a048fe | 173 | for_each_cpu(i, mask) |
87353d8a RB |
174 | ip27_send_ipi_single(i, action); |
175 | } | |
176 | ||
078a55fc | 177 | static void ip27_init_secondary(void) |
87353d8a RB |
178 | { |
179 | per_cpu_init(); | |
87353d8a RB |
180 | } |
181 | ||
078a55fc | 182 | static void ip27_smp_finish(void) |
87353d8a | 183 | { |
b32bb803 TB |
184 | extern void hub_rt_clock_event_init(void); |
185 | ||
186 | hub_rt_clock_event_init(); | |
187 | local_irq_enable(); | |
87353d8a RB |
188 | } |
189 | ||
1da177e4 | 190 | /* |
70342287 | 191 | * Launch a slave into smp_bootstrap(). It doesn't take an argument, and we |
1da177e4 LT |
192 | * set sp to the kernel stack of the newly created idle process, gp to the proc |
193 | * struct so that current_thread_info() will work. | |
194 | */ | |
078a55fc | 195 | static void ip27_boot_secondary(int cpu, struct task_struct *idle) |
1da177e4 | 196 | { |
dc8f6029 AV |
197 | unsigned long gp = (unsigned long)task_thread_info(idle); |
198 | unsigned long sp = __KSTK_TOS(idle); | |
1da177e4 | 199 | |
21a151d8 | 200 | LAUNCH_SLAVE(cputonasid(cpu), cputoslice(cpu), |
1da177e4 LT |
201 | (launch_proc_t)MAPPED_KERN_RW_TO_K0(smp_bootstrap), |
202 | 0, (void *) sp, (void *) gp); | |
203 | } | |
204 | ||
87353d8a | 205 | static void __init ip27_smp_setup(void) |
1da177e4 | 206 | { |
87353d8a | 207 | cnodeid_t cnode; |
1da177e4 | 208 | |
87353d8a RB |
209 | for_each_online_node(cnode) { |
210 | if (cnode == 0) | |
211 | continue; | |
212 | intr_clear_all(COMPACT_TO_NASID_NODEID(cnode)); | |
1da177e4 LT |
213 | } |
214 | ||
87353d8a | 215 | replicate_kernel_text(); |
1da177e4 LT |
216 | |
217 | /* | |
87353d8a | 218 | * Assumption to be fixed: we're always booted on logical / physical |
70342287 | 219 | * processor 0. While we're always running on logical processor 0 |
87353d8a | 220 | * this still means this is physical processor zero; it might for |
877d0310 | 221 | * example be disabled in the firmware. |
1da177e4 | 222 | */ |
87353d8a | 223 | alloc_cpupda(0, 0); |
1da177e4 | 224 | } |
87353d8a RB |
225 | |
226 | static void __init ip27_prepare_cpus(unsigned int max_cpus) | |
227 | { | |
228 | /* We already did everything necessary earlier */ | |
229 | } | |
230 | ||
231 | struct plat_smp_ops ip27_smp_ops = { | |
232 | .send_ipi_single = ip27_send_ipi_single, | |
233 | .send_ipi_mask = ip27_send_ipi_mask, | |
234 | .init_secondary = ip27_init_secondary, | |
235 | .smp_finish = ip27_smp_finish, | |
87353d8a RB |
236 | .boot_secondary = ip27_boot_secondary, |
237 | .smp_setup = ip27_smp_setup, | |
238 | .prepare_cpus = ip27_prepare_cpus, | |
239 | }; |