diff options
Diffstat (limited to 'arch/x86/kernel/genx2apic_uv_x.c')
-rw-r--r-- | arch/x86/kernel/genx2apic_uv_x.c | 214 |
1 files changed, 171 insertions, 43 deletions
diff --git a/arch/x86/kernel/genx2apic_uv_x.c b/arch/x86/kernel/genx2apic_uv_x.c index ebf13908a743..711f11c30b06 100644 --- a/arch/x86/kernel/genx2apic_uv_x.c +++ b/arch/x86/kernel/genx2apic_uv_x.c | |||
@@ -5,9 +5,10 @@ | |||
5 | * | 5 | * |
6 | * SGI UV APIC functions (note: not an Intel compatible APIC) | 6 | * SGI UV APIC functions (note: not an Intel compatible APIC) |
7 | * | 7 | * |
8 | * Copyright (C) 2007 Silicon Graphics, Inc. All rights reserved. | 8 | * Copyright (C) 2007-2008 Silicon Graphics, Inc. All rights reserved. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/kernel.h> | ||
11 | #include <linux/threads.h> | 12 | #include <linux/threads.h> |
12 | #include <linux/cpumask.h> | 13 | #include <linux/cpumask.h> |
13 | #include <linux/string.h> | 14 | #include <linux/string.h> |
@@ -20,6 +21,7 @@ | |||
20 | #include <asm/smp.h> | 21 | #include <asm/smp.h> |
21 | #include <asm/ipi.h> | 22 | #include <asm/ipi.h> |
22 | #include <asm/genapic.h> | 23 | #include <asm/genapic.h> |
24 | #include <asm/pgtable.h> | ||
23 | #include <asm/uv/uv_mmrs.h> | 25 | #include <asm/uv/uv_mmrs.h> |
24 | #include <asm/uv/uv_hub.h> | 26 | #include <asm/uv/uv_hub.h> |
25 | 27 | ||
@@ -55,37 +57,37 @@ static cpumask_t uv_vector_allocation_domain(int cpu) | |||
55 | int uv_wakeup_secondary(int phys_apicid, unsigned int start_rip) | 57 | int uv_wakeup_secondary(int phys_apicid, unsigned int start_rip) |
56 | { | 58 | { |
57 | unsigned long val; | 59 | unsigned long val; |
58 | int nasid; | 60 | int pnode; |
59 | 61 | ||
60 | nasid = uv_apicid_to_nasid(phys_apicid); | 62 | pnode = uv_apicid_to_pnode(phys_apicid); |
61 | val = (1UL << UVH_IPI_INT_SEND_SHFT) | | 63 | val = (1UL << UVH_IPI_INT_SEND_SHFT) | |
62 | (phys_apicid << UVH_IPI_INT_APIC_ID_SHFT) | | 64 | (phys_apicid << UVH_IPI_INT_APIC_ID_SHFT) | |
63 | (((long)start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) | | 65 | (((long)start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) | |
64 | APIC_DM_INIT; | 66 | APIC_DM_INIT; |
65 | uv_write_global_mmr64(nasid, UVH_IPI_INT, val); | 67 | uv_write_global_mmr64(pnode, UVH_IPI_INT, val); |
66 | mdelay(10); | 68 | mdelay(10); |
67 | 69 | ||
68 | val = (1UL << UVH_IPI_INT_SEND_SHFT) | | 70 | val = (1UL << UVH_IPI_INT_SEND_SHFT) | |
69 | (phys_apicid << UVH_IPI_INT_APIC_ID_SHFT) | | 71 | (phys_apicid << UVH_IPI_INT_APIC_ID_SHFT) | |
70 | (((long)start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) | | 72 | (((long)start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) | |
71 | APIC_DM_STARTUP; | 73 | APIC_DM_STARTUP; |
72 | uv_write_global_mmr64(nasid, UVH_IPI_INT, val); | 74 | uv_write_global_mmr64(pnode, UVH_IPI_INT, val); |
73 | return 0; | 75 | return 0; |
74 | } | 76 | } |
75 | 77 | ||
76 | static void uv_send_IPI_one(int cpu, int vector) | 78 | static void uv_send_IPI_one(int cpu, int vector) |
77 | { | 79 | { |
78 | unsigned long val, apicid, lapicid; | 80 | unsigned long val, apicid, lapicid; |
79 | int nasid; | 81 | int pnode; |
80 | 82 | ||
81 | apicid = per_cpu(x86_cpu_to_apicid, cpu); /* ZZZ - cache node-local ? */ | 83 | apicid = per_cpu(x86_cpu_to_apicid, cpu); /* ZZZ - cache node-local ? */ |
82 | lapicid = apicid & 0x3f; /* ZZZ macro needed */ | 84 | lapicid = apicid & 0x3f; /* ZZZ macro needed */ |
83 | nasid = uv_apicid_to_nasid(apicid); | 85 | pnode = uv_apicid_to_pnode(apicid); |
84 | val = | 86 | val = |
85 | (1UL << UVH_IPI_INT_SEND_SHFT) | (lapicid << | 87 | (1UL << UVH_IPI_INT_SEND_SHFT) | (lapicid << |
86 | UVH_IPI_INT_APIC_ID_SHFT) | | 88 | UVH_IPI_INT_APIC_ID_SHFT) | |
87 | (vector << UVH_IPI_INT_VECTOR_SHFT); | 89 | (vector << UVH_IPI_INT_VECTOR_SHFT); |
88 | uv_write_global_mmr64(nasid, UVH_IPI_INT, val); | 90 | uv_write_global_mmr64(pnode, UVH_IPI_INT, val); |
89 | } | 91 | } |
90 | 92 | ||
91 | static void uv_send_IPI_mask(cpumask_t mask, int vector) | 93 | static void uv_send_IPI_mask(cpumask_t mask, int vector) |
@@ -159,39 +161,146 @@ struct genapic apic_x2apic_uv_x = { | |||
159 | .phys_pkg_id = phys_pkg_id, /* Fixme ZZZ */ | 161 | .phys_pkg_id = phys_pkg_id, /* Fixme ZZZ */ |
160 | }; | 162 | }; |
161 | 163 | ||
162 | static __cpuinit void set_x2apic_extra_bits(int nasid) | 164 | static __cpuinit void set_x2apic_extra_bits(int pnode) |
163 | { | 165 | { |
164 | __get_cpu_var(x2apic_extra_bits) = ((nasid >> 1) << 6); | 166 | __get_cpu_var(x2apic_extra_bits) = (pnode << 6); |
165 | } | 167 | } |
166 | 168 | ||
167 | /* | 169 | /* |
168 | * Called on boot cpu. | 170 | * Called on boot cpu. |
169 | */ | 171 | */ |
172 | static __init int boot_pnode_to_blade(int pnode) | ||
173 | { | ||
174 | int blade; | ||
175 | |||
176 | for (blade = 0; blade < uv_num_possible_blades(); blade++) | ||
177 | if (pnode == uv_blade_info[blade].pnode) | ||
178 | return blade; | ||
179 | BUG(); | ||
180 | } | ||
181 | |||
182 | struct redir_addr { | ||
183 | unsigned long redirect; | ||
184 | unsigned long alias; | ||
185 | }; | ||
186 | |||
187 | #define DEST_SHIFT UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_SHFT | ||
188 | |||
189 | static __initdata struct redir_addr redir_addrs[] = { | ||
190 | {UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR, UVH_SI_ALIAS0_OVERLAY_CONFIG}, | ||
191 | {UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR, UVH_SI_ALIAS1_OVERLAY_CONFIG}, | ||
192 | {UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR, UVH_SI_ALIAS2_OVERLAY_CONFIG}, | ||
193 | }; | ||
194 | |||
195 | static __init void get_lowmem_redirect(unsigned long *base, unsigned long *size) | ||
196 | { | ||
197 | union uvh_si_alias0_overlay_config_u alias; | ||
198 | union uvh_rh_gam_alias210_redirect_config_2_mmr_u redirect; | ||
199 | int i; | ||
200 | |||
201 | for (i = 0; i < ARRAY_SIZE(redir_addrs); i++) { | ||
202 | alias.v = uv_read_local_mmr(redir_addrs[i].alias); | ||
203 | if (alias.s.base == 0) { | ||
204 | *size = (1UL << alias.s.m_alias); | ||
205 | redirect.v = uv_read_local_mmr(redir_addrs[i].redirect); | ||
206 | *base = (unsigned long)redirect.s.dest_base << DEST_SHIFT; | ||
207 | return; | ||
208 | } | ||
209 | } | ||
210 | BUG(); | ||
211 | } | ||
212 | |||
213 | static __init void map_low_mmrs(void) | ||
214 | { | ||
215 | init_extra_mapping_uc(UV_GLOBAL_MMR32_BASE, UV_GLOBAL_MMR32_SIZE); | ||
216 | init_extra_mapping_uc(UV_LOCAL_MMR_BASE, UV_LOCAL_MMR_SIZE); | ||
217 | } | ||
218 | |||
219 | enum map_type {map_wb, map_uc}; | ||
220 | |||
221 | static void map_high(char *id, unsigned long base, int shift, enum map_type map_type) | ||
222 | { | ||
223 | unsigned long bytes, paddr; | ||
224 | |||
225 | paddr = base << shift; | ||
226 | bytes = (1UL << shift); | ||
227 | printk(KERN_INFO "UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr, | ||
228 | paddr + bytes); | ||
229 | if (map_type == map_uc) | ||
230 | init_extra_mapping_uc(paddr, bytes); | ||
231 | else | ||
232 | init_extra_mapping_wb(paddr, bytes); | ||
233 | |||
234 | } | ||
235 | static __init void map_gru_high(int max_pnode) | ||
236 | { | ||
237 | union uvh_rh_gam_gru_overlay_config_mmr_u gru; | ||
238 | int shift = UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT; | ||
239 | |||
240 | gru.v = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR); | ||
241 | if (gru.s.enable) | ||
242 | map_high("GRU", gru.s.base, shift, map_wb); | ||
243 | } | ||
244 | |||
245 | static __init void map_config_high(int max_pnode) | ||
246 | { | ||
247 | union uvh_rh_gam_cfg_overlay_config_mmr_u cfg; | ||
248 | int shift = UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR_BASE_SHFT; | ||
249 | |||
250 | cfg.v = uv_read_local_mmr(UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR); | ||
251 | if (cfg.s.enable) | ||
252 | map_high("CONFIG", cfg.s.base, shift, map_uc); | ||
253 | } | ||
254 | |||
255 | static __init void map_mmr_high(int max_pnode) | ||
256 | { | ||
257 | union uvh_rh_gam_mmr_overlay_config_mmr_u mmr; | ||
258 | int shift = UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT; | ||
259 | |||
260 | mmr.v = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR); | ||
261 | if (mmr.s.enable) | ||
262 | map_high("MMR", mmr.s.base, shift, map_uc); | ||
263 | } | ||
264 | |||
265 | static __init void map_mmioh_high(int max_pnode) | ||
266 | { | ||
267 | union uvh_rh_gam_mmioh_overlay_config_mmr_u mmioh; | ||
268 | int shift = UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT; | ||
269 | |||
270 | mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR); | ||
271 | if (mmioh.s.enable) | ||
272 | map_high("MMIOH", mmioh.s.base, shift, map_uc); | ||
273 | } | ||
274 | |||
170 | static __init void uv_system_init(void) | 275 | static __init void uv_system_init(void) |
171 | { | 276 | { |
172 | union uvh_si_addr_map_config_u m_n_config; | 277 | union uvh_si_addr_map_config_u m_n_config; |
173 | int bytes, nid, cpu, lcpu, nasid, last_nasid, blade; | 278 | union uvh_node_id_u node_id; |
174 | unsigned long mmr_base; | 279 | unsigned long gnode_upper, lowmem_redir_base, lowmem_redir_size; |
280 | int bytes, nid, cpu, lcpu, pnode, blade, i, j, m_val, n_val; | ||
281 | int max_pnode = 0; | ||
282 | unsigned long mmr_base, present; | ||
283 | |||
284 | map_low_mmrs(); | ||
175 | 285 | ||
176 | m_n_config.v = uv_read_local_mmr(UVH_SI_ADDR_MAP_CONFIG); | 286 | m_n_config.v = uv_read_local_mmr(UVH_SI_ADDR_MAP_CONFIG); |
287 | m_val = m_n_config.s.m_skt; | ||
288 | n_val = m_n_config.s.n_skt; | ||
177 | mmr_base = | 289 | mmr_base = |
178 | uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) & | 290 | uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) & |
179 | ~UV_MMR_ENABLE; | 291 | ~UV_MMR_ENABLE; |
180 | printk(KERN_DEBUG "UV: global MMR base 0x%lx\n", mmr_base); | 292 | printk(KERN_DEBUG "UV: global MMR base 0x%lx\n", mmr_base); |
181 | 293 | ||
182 | last_nasid = -1; | 294 | for(i = 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++) |
183 | for_each_possible_cpu(cpu) { | 295 | uv_possible_blades += |
184 | nid = cpu_to_node(cpu); | 296 | hweight64(uv_read_local_mmr( UVH_NODE_PRESENT_TABLE + i * 8)); |
185 | nasid = uv_apicid_to_nasid(per_cpu(x86_cpu_to_apicid, cpu)); | ||
186 | if (nasid != last_nasid) | ||
187 | uv_possible_blades++; | ||
188 | last_nasid = nasid; | ||
189 | } | ||
190 | printk(KERN_DEBUG "UV: Found %d blades\n", uv_num_possible_blades()); | 297 | printk(KERN_DEBUG "UV: Found %d blades\n", uv_num_possible_blades()); |
191 | 298 | ||
192 | bytes = sizeof(struct uv_blade_info) * uv_num_possible_blades(); | 299 | bytes = sizeof(struct uv_blade_info) * uv_num_possible_blades(); |
193 | uv_blade_info = alloc_bootmem_pages(bytes); | 300 | uv_blade_info = alloc_bootmem_pages(bytes); |
194 | 301 | ||
302 | get_lowmem_redirect(&lowmem_redir_base, &lowmem_redir_size); | ||
303 | |||
195 | bytes = sizeof(uv_node_to_blade[0]) * num_possible_nodes(); | 304 | bytes = sizeof(uv_node_to_blade[0]) * num_possible_nodes(); |
196 | uv_node_to_blade = alloc_bootmem_pages(bytes); | 305 | uv_node_to_blade = alloc_bootmem_pages(bytes); |
197 | memset(uv_node_to_blade, 255, bytes); | 306 | memset(uv_node_to_blade, 255, bytes); |
@@ -200,43 +309,62 @@ static __init void uv_system_init(void) | |||
200 | uv_cpu_to_blade = alloc_bootmem_pages(bytes); | 309 | uv_cpu_to_blade = alloc_bootmem_pages(bytes); |
201 | memset(uv_cpu_to_blade, 255, bytes); | 310 | memset(uv_cpu_to_blade, 255, bytes); |
202 | 311 | ||
203 | last_nasid = -1; | 312 | blade = 0; |
204 | blade = -1; | 313 | for (i = 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++) { |
205 | lcpu = -1; | 314 | present = uv_read_local_mmr(UVH_NODE_PRESENT_TABLE + i * 8); |
206 | for_each_possible_cpu(cpu) { | 315 | for (j = 0; j < 64; j++) { |
207 | nid = cpu_to_node(cpu); | 316 | if (!test_bit(j, &present)) |
208 | nasid = uv_apicid_to_nasid(per_cpu(x86_cpu_to_apicid, cpu)); | 317 | continue; |
209 | if (nasid != last_nasid) { | 318 | uv_blade_info[blade].pnode = (i * 64 + j); |
210 | blade++; | 319 | uv_blade_info[blade].nr_possible_cpus = 0; |
211 | lcpu = -1; | ||
212 | uv_blade_info[blade].nr_posible_cpus = 0; | ||
213 | uv_blade_info[blade].nr_online_cpus = 0; | 320 | uv_blade_info[blade].nr_online_cpus = 0; |
321 | blade++; | ||
214 | } | 322 | } |
215 | last_nasid = nasid; | 323 | } |
216 | lcpu++; | ||
217 | 324 | ||
218 | uv_cpu_hub_info(cpu)->m_val = m_n_config.s.m_skt; | 325 | node_id.v = uv_read_local_mmr(UVH_NODE_ID); |
219 | uv_cpu_hub_info(cpu)->n_val = m_n_config.s.n_skt; | 326 | gnode_upper = (((unsigned long)node_id.s.node_id) & |
327 | ~((1 << n_val) - 1)) << m_val; | ||
328 | |||
329 | for_each_present_cpu(cpu) { | ||
330 | nid = cpu_to_node(cpu); | ||
331 | pnode = uv_apicid_to_pnode(per_cpu(x86_cpu_to_apicid, cpu)); | ||
332 | blade = boot_pnode_to_blade(pnode); | ||
333 | lcpu = uv_blade_info[blade].nr_possible_cpus; | ||
334 | uv_blade_info[blade].nr_possible_cpus++; | ||
335 | |||
336 | uv_cpu_hub_info(cpu)->lowmem_remap_base = lowmem_redir_base; | ||
337 | uv_cpu_hub_info(cpu)->lowmem_remap_top = | ||
338 | lowmem_redir_base + lowmem_redir_size; | ||
339 | uv_cpu_hub_info(cpu)->m_val = m_val; | ||
340 | uv_cpu_hub_info(cpu)->n_val = m_val; | ||
220 | uv_cpu_hub_info(cpu)->numa_blade_id = blade; | 341 | uv_cpu_hub_info(cpu)->numa_blade_id = blade; |
221 | uv_cpu_hub_info(cpu)->blade_processor_id = lcpu; | 342 | uv_cpu_hub_info(cpu)->blade_processor_id = lcpu; |
222 | uv_cpu_hub_info(cpu)->local_nasid = nasid; | 343 | uv_cpu_hub_info(cpu)->pnode = pnode; |
223 | uv_cpu_hub_info(cpu)->gnode_upper = | 344 | uv_cpu_hub_info(cpu)->pnode_mask = (1 << n_val) - 1; |
224 | nasid & ~((1 << uv_hub_info->n_val) - 1); | 345 | uv_cpu_hub_info(cpu)->gpa_mask = (1 << (m_val + n_val)) - 1; |
346 | uv_cpu_hub_info(cpu)->gnode_upper = gnode_upper; | ||
225 | uv_cpu_hub_info(cpu)->global_mmr_base = mmr_base; | 347 | uv_cpu_hub_info(cpu)->global_mmr_base = mmr_base; |
226 | uv_cpu_hub_info(cpu)->coherency_domain_number = 0;/* ZZZ */ | 348 | uv_cpu_hub_info(cpu)->coherency_domain_number = 0;/* ZZZ */ |
227 | uv_blade_info[blade].nasid = nasid; | ||
228 | uv_blade_info[blade].nr_posible_cpus++; | ||
229 | uv_node_to_blade[nid] = blade; | 349 | uv_node_to_blade[nid] = blade; |
230 | uv_cpu_to_blade[cpu] = blade; | 350 | uv_cpu_to_blade[cpu] = blade; |
351 | max_pnode = max(pnode, max_pnode); | ||
231 | 352 | ||
232 | printk(KERN_DEBUG "UV cpu %d, apicid 0x%x, nasid %d, nid %d\n", | 353 | printk(KERN_DEBUG "UV: cpu %d, apicid 0x%x, pnode %d, nid %d, " |
233 | cpu, per_cpu(x86_cpu_to_apicid, cpu), nasid, nid); | 354 | "lcpu %d, blade %d\n", |
234 | printk(KERN_DEBUG "UV lcpu %d, blade %d\n", lcpu, blade); | 355 | cpu, per_cpu(x86_cpu_to_apicid, cpu), pnode, nid, |
356 | lcpu, blade); | ||
235 | } | 357 | } |
358 | |||
359 | map_gru_high(max_pnode); | ||
360 | map_mmr_high(max_pnode); | ||
361 | map_config_high(max_pnode); | ||
362 | map_mmioh_high(max_pnode); | ||
236 | } | 363 | } |
237 | 364 | ||
238 | /* | 365 | /* |
239 | * Called on each cpu to initialize the per_cpu UV data area. | 366 | * Called on each cpu to initialize the per_cpu UV data area. |
367 | * ZZZ hotplug not supported yet | ||
240 | */ | 368 | */ |
241 | void __cpuinit uv_cpu_init(void) | 369 | void __cpuinit uv_cpu_init(void) |
242 | { | 370 | { |
@@ -246,5 +374,5 @@ void __cpuinit uv_cpu_init(void) | |||
246 | uv_blade_info[uv_numa_blade_id()].nr_online_cpus++; | 374 | uv_blade_info[uv_numa_blade_id()].nr_online_cpus++; |
247 | 375 | ||
248 | if (get_uv_system_type() == UV_NON_UNIQUE_APIC) | 376 | if (get_uv_system_type() == UV_NON_UNIQUE_APIC) |
249 | set_x2apic_extra_bits(uv_hub_info->local_nasid); | 377 | set_x2apic_extra_bits(uv_hub_info->pnode); |
250 | } | 378 | } |