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