diff options
Diffstat (limited to 'arch/ia64/sn/kernel/setup.c')
-rw-r--r-- | arch/ia64/sn/kernel/setup.c | 621 |
1 files changed, 621 insertions, 0 deletions
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c new file mode 100644 index 000000000000..f0306b516afb --- /dev/null +++ b/arch/ia64/sn/kernel/setup.c | |||
@@ -0,0 +1,621 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 1999,2001-2004 Silicon Graphics, Inc. All rights reserved. | ||
7 | */ | ||
8 | |||
9 | #include <linux/config.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/delay.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/kdev_t.h> | ||
15 | #include <linux/string.h> | ||
16 | #include <linux/tty.h> | ||
17 | #include <linux/console.h> | ||
18 | #include <linux/timex.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/ioport.h> | ||
21 | #include <linux/mm.h> | ||
22 | #include <linux/serial.h> | ||
23 | #include <linux/irq.h> | ||
24 | #include <linux/bootmem.h> | ||
25 | #include <linux/mmzone.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/acpi.h> | ||
28 | #include <linux/compiler.h> | ||
29 | #include <linux/sched.h> | ||
30 | #include <linux/root_dev.h> | ||
31 | #include <linux/nodemask.h> | ||
32 | |||
33 | #include <asm/io.h> | ||
34 | #include <asm/sal.h> | ||
35 | #include <asm/machvec.h> | ||
36 | #include <asm/system.h> | ||
37 | #include <asm/processor.h> | ||
38 | #include <asm/sn/arch.h> | ||
39 | #include <asm/sn/addrs.h> | ||
40 | #include <asm/sn/pda.h> | ||
41 | #include <asm/sn/nodepda.h> | ||
42 | #include <asm/sn/sn_cpuid.h> | ||
43 | #include <asm/sn/simulator.h> | ||
44 | #include <asm/sn/leds.h> | ||
45 | #include <asm/sn/bte.h> | ||
46 | #include <asm/sn/shub_mmr.h> | ||
47 | #include <asm/sn/clksupport.h> | ||
48 | #include <asm/sn/sn_sal.h> | ||
49 | #include <asm/sn/geo.h> | ||
50 | #include "xtalk/xwidgetdev.h" | ||
51 | #include "xtalk/hubdev.h" | ||
52 | #include <asm/sn/klconfig.h> | ||
53 | |||
54 | |||
55 | DEFINE_PER_CPU(struct pda_s, pda_percpu); | ||
56 | |||
57 | #define MAX_PHYS_MEMORY (1UL << 49) /* 1 TB */ | ||
58 | |||
59 | lboard_t *root_lboard[MAX_COMPACT_NODES]; | ||
60 | |||
61 | extern void bte_init_node(nodepda_t *, cnodeid_t); | ||
62 | |||
63 | extern void sn_timer_init(void); | ||
64 | extern unsigned long last_time_offset; | ||
65 | extern void (*ia64_mark_idle) (int); | ||
66 | extern void snidle(int); | ||
67 | extern unsigned char acpi_kbd_controller_present; | ||
68 | |||
69 | unsigned long sn_rtc_cycles_per_second; | ||
70 | EXPORT_SYMBOL(sn_rtc_cycles_per_second); | ||
71 | |||
72 | DEFINE_PER_CPU(struct sn_hub_info_s, __sn_hub_info); | ||
73 | EXPORT_PER_CPU_SYMBOL(__sn_hub_info); | ||
74 | |||
75 | partid_t sn_partid = -1; | ||
76 | EXPORT_SYMBOL(sn_partid); | ||
77 | char sn_system_serial_number_string[128]; | ||
78 | EXPORT_SYMBOL(sn_system_serial_number_string); | ||
79 | u64 sn_partition_serial_number; | ||
80 | EXPORT_SYMBOL(sn_partition_serial_number); | ||
81 | u8 sn_partition_id; | ||
82 | EXPORT_SYMBOL(sn_partition_id); | ||
83 | u8 sn_system_size; | ||
84 | EXPORT_SYMBOL(sn_system_size); | ||
85 | u8 sn_sharing_domain_size; | ||
86 | EXPORT_SYMBOL(sn_sharing_domain_size); | ||
87 | u8 sn_coherency_id; | ||
88 | EXPORT_SYMBOL(sn_coherency_id); | ||
89 | u8 sn_region_size; | ||
90 | EXPORT_SYMBOL(sn_region_size); | ||
91 | |||
92 | short physical_node_map[MAX_PHYSNODE_ID]; | ||
93 | |||
94 | EXPORT_SYMBOL(physical_node_map); | ||
95 | |||
96 | int numionodes; | ||
97 | |||
98 | static void sn_init_pdas(char **); | ||
99 | static void scan_for_ionodes(void); | ||
100 | |||
101 | static nodepda_t *nodepdaindr[MAX_COMPACT_NODES]; | ||
102 | |||
103 | /* | ||
104 | * The format of "screen_info" is strange, and due to early i386-setup | ||
105 | * code. This is just enough to make the console code think we're on a | ||
106 | * VGA color display. | ||
107 | */ | ||
108 | struct screen_info sn_screen_info = { | ||
109 | .orig_x = 0, | ||
110 | .orig_y = 0, | ||
111 | .orig_video_mode = 3, | ||
112 | .orig_video_cols = 80, | ||
113 | .orig_video_ega_bx = 3, | ||
114 | .orig_video_lines = 25, | ||
115 | .orig_video_isVGA = 1, | ||
116 | .orig_video_points = 16 | ||
117 | }; | ||
118 | |||
119 | /* | ||
120 | * This is here so we can use the CMOS detection in ide-probe.c to | ||
121 | * determine what drives are present. In theory, we don't need this | ||
122 | * as the auto-detection could be done via ide-probe.c:do_probe() but | ||
123 | * in practice that would be much slower, which is painful when | ||
124 | * running in the simulator. Note that passing zeroes in DRIVE_INFO | ||
125 | * is sufficient (the IDE driver will autodetect the drive geometry). | ||
126 | */ | ||
127 | #ifdef CONFIG_IA64_GENERIC | ||
128 | extern char drive_info[4 * 16]; | ||
129 | #else | ||
130 | char drive_info[4 * 16]; | ||
131 | #endif | ||
132 | |||
133 | /* | ||
134 | * Get nasid of current cpu early in boot before nodepda is initialized | ||
135 | */ | ||
136 | static int | ||
137 | boot_get_nasid(void) | ||
138 | { | ||
139 | int nasid; | ||
140 | |||
141 | if (ia64_sn_get_sapic_info(get_sapicid(), &nasid, NULL, NULL)) | ||
142 | BUG(); | ||
143 | return nasid; | ||
144 | } | ||
145 | |||
146 | /* | ||
147 | * This routine can only be used during init, since | ||
148 | * smp_boot_data is an init data structure. | ||
149 | * We have to use smp_boot_data.cpu_phys_id to find | ||
150 | * the physical id of the processor because the normal | ||
151 | * cpu_physical_id() relies on data structures that | ||
152 | * may not be initialized yet. | ||
153 | */ | ||
154 | |||
155 | static int __init pxm_to_nasid(int pxm) | ||
156 | { | ||
157 | int i; | ||
158 | int nid; | ||
159 | |||
160 | nid = pxm_to_nid_map[pxm]; | ||
161 | for (i = 0; i < num_node_memblks; i++) { | ||
162 | if (node_memblk[i].nid == nid) { | ||
163 | return NASID_GET(node_memblk[i].start_paddr); | ||
164 | } | ||
165 | } | ||
166 | return -1; | ||
167 | } | ||
168 | |||
169 | /** | ||
170 | * early_sn_setup - early setup routine for SN platforms | ||
171 | * | ||
172 | * Sets up an initial console to aid debugging. Intended primarily | ||
173 | * for bringup. See start_kernel() in init/main.c. | ||
174 | */ | ||
175 | |||
176 | void __init early_sn_setup(void) | ||
177 | { | ||
178 | efi_system_table_t *efi_systab; | ||
179 | efi_config_table_t *config_tables; | ||
180 | struct ia64_sal_systab *sal_systab; | ||
181 | struct ia64_sal_desc_entry_point *ep; | ||
182 | char *p; | ||
183 | int i, j; | ||
184 | |||
185 | /* | ||
186 | * Parse enough of the SAL tables to locate the SAL entry point. Since, console | ||
187 | * IO on SN2 is done via SAL calls, early_printk won't work without this. | ||
188 | * | ||
189 | * This code duplicates some of the ACPI table parsing that is in efi.c & sal.c. | ||
190 | * Any changes to those file may have to be made hereas well. | ||
191 | */ | ||
192 | efi_systab = (efi_system_table_t *) __va(ia64_boot_param->efi_systab); | ||
193 | config_tables = __va(efi_systab->tables); | ||
194 | for (i = 0; i < efi_systab->nr_tables; i++) { | ||
195 | if (efi_guidcmp(config_tables[i].guid, SAL_SYSTEM_TABLE_GUID) == | ||
196 | 0) { | ||
197 | sal_systab = __va(config_tables[i].table); | ||
198 | p = (char *)(sal_systab + 1); | ||
199 | for (j = 0; j < sal_systab->entry_count; j++) { | ||
200 | if (*p == SAL_DESC_ENTRY_POINT) { | ||
201 | ep = (struct ia64_sal_desc_entry_point | ||
202 | *)p; | ||
203 | ia64_sal_handler_init(__va | ||
204 | (ep->sal_proc), | ||
205 | __va(ep->gp)); | ||
206 | return; | ||
207 | } | ||
208 | p += SAL_DESC_SIZE(*p); | ||
209 | } | ||
210 | } | ||
211 | } | ||
212 | /* Uh-oh, SAL not available?? */ | ||
213 | printk(KERN_ERR "failed to find SAL entry point\n"); | ||
214 | } | ||
215 | |||
216 | extern int platform_intr_list[]; | ||
217 | extern nasid_t master_nasid; | ||
218 | static int shub_1_1_found __initdata; | ||
219 | |||
220 | /* | ||
221 | * sn_check_for_wars | ||
222 | * | ||
223 | * Set flag for enabling shub specific wars | ||
224 | */ | ||
225 | |||
226 | static inline int __init is_shub_1_1(int nasid) | ||
227 | { | ||
228 | unsigned long id; | ||
229 | int rev; | ||
230 | |||
231 | if (is_shub2()) | ||
232 | return 0; | ||
233 | id = REMOTE_HUB_L(nasid, SH1_SHUB_ID); | ||
234 | rev = (id & SH1_SHUB_ID_REVISION_MASK) >> SH1_SHUB_ID_REVISION_SHFT; | ||
235 | return rev <= 2; | ||
236 | } | ||
237 | |||
238 | static void __init sn_check_for_wars(void) | ||
239 | { | ||
240 | int cnode; | ||
241 | |||
242 | if (is_shub2()) { | ||
243 | /* none yet */ | ||
244 | } else { | ||
245 | for_each_online_node(cnode) { | ||
246 | if (is_shub_1_1(cnodeid_to_nasid(cnode))) | ||
247 | sn_hub_info->shub_1_1_found = 1; | ||
248 | } | ||
249 | } | ||
250 | } | ||
251 | |||
252 | /** | ||
253 | * sn_setup - SN platform setup routine | ||
254 | * @cmdline_p: kernel command line | ||
255 | * | ||
256 | * Handles platform setup for SN machines. This includes determining | ||
257 | * the RTC frequency (via a SAL call), initializing secondary CPUs, and | ||
258 | * setting up per-node data areas. The console is also initialized here. | ||
259 | */ | ||
260 | void __init sn_setup(char **cmdline_p) | ||
261 | { | ||
262 | long status, ticks_per_sec, drift; | ||
263 | int pxm; | ||
264 | int major = sn_sal_rev_major(), minor = sn_sal_rev_minor(); | ||
265 | extern void sn_cpu_init(void); | ||
266 | |||
267 | /* | ||
268 | * If the generic code has enabled vga console support - lets | ||
269 | * get rid of it again. This is a kludge for the fact that ACPI | ||
270 | * currtently has no way of informing us if legacy VGA is available | ||
271 | * or not. | ||
272 | */ | ||
273 | #if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) | ||
274 | if (conswitchp == &vga_con) { | ||
275 | printk(KERN_DEBUG "SGI: Disabling VGA console\n"); | ||
276 | #ifdef CONFIG_DUMMY_CONSOLE | ||
277 | conswitchp = &dummy_con; | ||
278 | #else | ||
279 | conswitchp = NULL; | ||
280 | #endif /* CONFIG_DUMMY_CONSOLE */ | ||
281 | } | ||
282 | #endif /* def(CONFIG_VT) && def(CONFIG_VGA_CONSOLE) */ | ||
283 | |||
284 | MAX_DMA_ADDRESS = PAGE_OFFSET + MAX_PHYS_MEMORY; | ||
285 | |||
286 | memset(physical_node_map, -1, sizeof(physical_node_map)); | ||
287 | for (pxm = 0; pxm < MAX_PXM_DOMAINS; pxm++) | ||
288 | if (pxm_to_nid_map[pxm] != -1) | ||
289 | physical_node_map[pxm_to_nasid(pxm)] = | ||
290 | pxm_to_nid_map[pxm]; | ||
291 | |||
292 | /* | ||
293 | * Old PROMs do not provide an ACPI FADT. Disable legacy keyboard | ||
294 | * support here so we don't have to listen to failed keyboard probe | ||
295 | * messages. | ||
296 | */ | ||
297 | if ((major < 2 || (major == 2 && minor <= 9)) && | ||
298 | acpi_kbd_controller_present) { | ||
299 | printk(KERN_INFO "Disabling legacy keyboard support as prom " | ||
300 | "is too old and doesn't provide FADT\n"); | ||
301 | acpi_kbd_controller_present = 0; | ||
302 | } | ||
303 | |||
304 | printk("SGI SAL version %x.%02x\n", major, minor); | ||
305 | |||
306 | /* | ||
307 | * Confirm the SAL we're running on is recent enough... | ||
308 | */ | ||
309 | if ((major < SN_SAL_MIN_MAJOR) || (major == SN_SAL_MIN_MAJOR && | ||
310 | minor < SN_SAL_MIN_MINOR)) { | ||
311 | printk(KERN_ERR "This kernel needs SGI SAL version >= " | ||
312 | "%x.%02x\n", SN_SAL_MIN_MAJOR, SN_SAL_MIN_MINOR); | ||
313 | panic("PROM version too old\n"); | ||
314 | } | ||
315 | |||
316 | master_nasid = boot_get_nasid(); | ||
317 | |||
318 | status = | ||
319 | ia64_sal_freq_base(SAL_FREQ_BASE_REALTIME_CLOCK, &ticks_per_sec, | ||
320 | &drift); | ||
321 | if (status != 0 || ticks_per_sec < 100000) { | ||
322 | printk(KERN_WARNING | ||
323 | "unable to determine platform RTC clock frequency, guessing.\n"); | ||
324 | /* PROM gives wrong value for clock freq. so guess */ | ||
325 | sn_rtc_cycles_per_second = 1000000000000UL / 30000UL; | ||
326 | } else | ||
327 | sn_rtc_cycles_per_second = ticks_per_sec; | ||
328 | |||
329 | platform_intr_list[ACPI_INTERRUPT_CPEI] = IA64_CPE_VECTOR; | ||
330 | |||
331 | /* | ||
332 | * we set the default root device to /dev/hda | ||
333 | * to make simulation easy | ||
334 | */ | ||
335 | ROOT_DEV = Root_HDA1; | ||
336 | |||
337 | /* | ||
338 | * Create the PDAs and NODEPDAs for all the cpus. | ||
339 | */ | ||
340 | sn_init_pdas(cmdline_p); | ||
341 | |||
342 | ia64_mark_idle = &snidle; | ||
343 | |||
344 | /* | ||
345 | * For the bootcpu, we do this here. All other cpus will make the | ||
346 | * call as part of cpu_init in slave cpu initialization. | ||
347 | */ | ||
348 | sn_cpu_init(); | ||
349 | |||
350 | #ifdef CONFIG_SMP | ||
351 | init_smp_config(); | ||
352 | #endif | ||
353 | screen_info = sn_screen_info; | ||
354 | |||
355 | sn_timer_init(); | ||
356 | } | ||
357 | |||
358 | /** | ||
359 | * sn_init_pdas - setup node data areas | ||
360 | * | ||
361 | * One time setup for Node Data Area. Called by sn_setup(). | ||
362 | */ | ||
363 | static void __init sn_init_pdas(char **cmdline_p) | ||
364 | { | ||
365 | cnodeid_t cnode; | ||
366 | |||
367 | memset(pda->cnodeid_to_nasid_table, -1, | ||
368 | sizeof(pda->cnodeid_to_nasid_table)); | ||
369 | for_each_online_node(cnode) | ||
370 | pda->cnodeid_to_nasid_table[cnode] = | ||
371 | pxm_to_nasid(nid_to_pxm_map[cnode]); | ||
372 | |||
373 | numionodes = num_online_nodes(); | ||
374 | scan_for_ionodes(); | ||
375 | |||
376 | /* | ||
377 | * Allocate & initalize the nodepda for each node. | ||
378 | */ | ||
379 | for_each_online_node(cnode) { | ||
380 | nodepdaindr[cnode] = | ||
381 | alloc_bootmem_node(NODE_DATA(cnode), sizeof(nodepda_t)); | ||
382 | memset(nodepdaindr[cnode], 0, sizeof(nodepda_t)); | ||
383 | memset(nodepdaindr[cnode]->phys_cpuid, -1, | ||
384 | sizeof(nodepdaindr[cnode]->phys_cpuid)); | ||
385 | } | ||
386 | |||
387 | /* | ||
388 | * Allocate & initialize nodepda for TIOs. For now, put them on node 0. | ||
389 | */ | ||
390 | for (cnode = num_online_nodes(); cnode < numionodes; cnode++) { | ||
391 | nodepdaindr[cnode] = | ||
392 | alloc_bootmem_node(NODE_DATA(0), sizeof(nodepda_t)); | ||
393 | memset(nodepdaindr[cnode], 0, sizeof(nodepda_t)); | ||
394 | } | ||
395 | |||
396 | /* | ||
397 | * Now copy the array of nodepda pointers to each nodepda. | ||
398 | */ | ||
399 | for (cnode = 0; cnode < numionodes; cnode++) | ||
400 | memcpy(nodepdaindr[cnode]->pernode_pdaindr, nodepdaindr, | ||
401 | sizeof(nodepdaindr)); | ||
402 | |||
403 | /* | ||
404 | * Set up IO related platform-dependent nodepda fields. | ||
405 | * The following routine actually sets up the hubinfo struct | ||
406 | * in nodepda. | ||
407 | */ | ||
408 | for_each_online_node(cnode) { | ||
409 | bte_init_node(nodepdaindr[cnode], cnode); | ||
410 | } | ||
411 | |||
412 | /* | ||
413 | * Initialize the per node hubdev. This includes IO Nodes and | ||
414 | * headless/memless nodes. | ||
415 | */ | ||
416 | for (cnode = 0; cnode < numionodes; cnode++) { | ||
417 | hubdev_init_node(nodepdaindr[cnode], cnode); | ||
418 | } | ||
419 | } | ||
420 | |||
421 | /** | ||
422 | * sn_cpu_init - initialize per-cpu data areas | ||
423 | * @cpuid: cpuid of the caller | ||
424 | * | ||
425 | * Called during cpu initialization on each cpu as it starts. | ||
426 | * Currently, initializes the per-cpu data area for SNIA. | ||
427 | * Also sets up a few fields in the nodepda. Also known as | ||
428 | * platform_cpu_init() by the ia64 machvec code. | ||
429 | */ | ||
430 | void __init sn_cpu_init(void) | ||
431 | { | ||
432 | int cpuid; | ||
433 | int cpuphyid; | ||
434 | int nasid; | ||
435 | int subnode; | ||
436 | int slice; | ||
437 | int cnode; | ||
438 | int i; | ||
439 | static int wars_have_been_checked; | ||
440 | |||
441 | memset(pda, 0, sizeof(pda)); | ||
442 | if (ia64_sn_get_sn_info(0, &sn_hub_info->shub2, &sn_hub_info->nasid_bitmask, &sn_hub_info->nasid_shift, | ||
443 | &sn_system_size, &sn_sharing_domain_size, &sn_partition_id, | ||
444 | &sn_coherency_id, &sn_region_size)) | ||
445 | BUG(); | ||
446 | sn_hub_info->as_shift = sn_hub_info->nasid_shift - 2; | ||
447 | |||
448 | /* | ||
449 | * The boot cpu makes this call again after platform initialization is | ||
450 | * complete. | ||
451 | */ | ||
452 | if (nodepdaindr[0] == NULL) | ||
453 | return; | ||
454 | |||
455 | cpuid = smp_processor_id(); | ||
456 | cpuphyid = get_sapicid(); | ||
457 | |||
458 | if (ia64_sn_get_sapic_info(cpuphyid, &nasid, &subnode, &slice)) | ||
459 | BUG(); | ||
460 | |||
461 | for (i=0; i < MAX_NUMNODES; i++) { | ||
462 | if (nodepdaindr[i]) { | ||
463 | nodepdaindr[i]->phys_cpuid[cpuid].nasid = nasid; | ||
464 | nodepdaindr[i]->phys_cpuid[cpuid].slice = slice; | ||
465 | nodepdaindr[i]->phys_cpuid[cpuid].subnode = subnode; | ||
466 | } | ||
467 | } | ||
468 | |||
469 | cnode = nasid_to_cnodeid(nasid); | ||
470 | |||
471 | pda->p_nodepda = nodepdaindr[cnode]; | ||
472 | pda->led_address = | ||
473 | (typeof(pda->led_address)) (LED0 + (slice << LED_CPU_SHIFT)); | ||
474 | pda->led_state = LED_ALWAYS_SET; | ||
475 | pda->hb_count = HZ / 2; | ||
476 | pda->hb_state = 0; | ||
477 | pda->idle_flag = 0; | ||
478 | |||
479 | if (cpuid != 0) { | ||
480 | memcpy(pda->cnodeid_to_nasid_table, | ||
481 | pdacpu(0)->cnodeid_to_nasid_table, | ||
482 | sizeof(pda->cnodeid_to_nasid_table)); | ||
483 | } | ||
484 | |||
485 | /* | ||
486 | * Check for WARs. | ||
487 | * Only needs to be done once, on BSP. | ||
488 | * Has to be done after loop above, because it uses pda.cnodeid_to_nasid_table[i]. | ||
489 | * Has to be done before assignment below. | ||
490 | */ | ||
491 | if (!wars_have_been_checked) { | ||
492 | sn_check_for_wars(); | ||
493 | wars_have_been_checked = 1; | ||
494 | } | ||
495 | sn_hub_info->shub_1_1_found = shub_1_1_found; | ||
496 | |||
497 | /* | ||
498 | * Set up addresses of PIO/MEM write status registers. | ||
499 | */ | ||
500 | { | ||
501 | u64 pio1[] = {SH1_PIO_WRITE_STATUS_0, 0, SH1_PIO_WRITE_STATUS_1, 0}; | ||
502 | u64 pio2[] = {SH2_PIO_WRITE_STATUS_0, SH2_PIO_WRITE_STATUS_1, | ||
503 | SH2_PIO_WRITE_STATUS_2, SH2_PIO_WRITE_STATUS_3}; | ||
504 | u64 *pio; | ||
505 | pio = is_shub1() ? pio1 : pio2; | ||
506 | pda->pio_write_status_addr = (volatile unsigned long *) LOCAL_MMR_ADDR(pio[slice]); | ||
507 | pda->pio_write_status_val = is_shub1() ? SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK : 0; | ||
508 | } | ||
509 | |||
510 | /* | ||
511 | * WAR addresses for SHUB 1.x. | ||
512 | */ | ||
513 | if (local_node_data->active_cpu_count++ == 0 && is_shub1()) { | ||
514 | int buddy_nasid; | ||
515 | buddy_nasid = | ||
516 | cnodeid_to_nasid(numa_node_id() == | ||
517 | num_online_nodes() - 1 ? 0 : numa_node_id() + 1); | ||
518 | pda->pio_shub_war_cam_addr = | ||
519 | (volatile unsigned long *)GLOBAL_MMR_ADDR(nasid, | ||
520 | SH1_PI_CAM_CONTROL); | ||
521 | } | ||
522 | } | ||
523 | |||
524 | /* | ||
525 | * Scan klconfig for ionodes. Add the nasids to the | ||
526 | * physical_node_map and the pda and increment numionodes. | ||
527 | */ | ||
528 | |||
529 | static void __init scan_for_ionodes(void) | ||
530 | { | ||
531 | int nasid = 0; | ||
532 | lboard_t *brd; | ||
533 | |||
534 | /* Setup ionodes with memory */ | ||
535 | for (nasid = 0; nasid < MAX_PHYSNODE_ID; nasid += 2) { | ||
536 | char *klgraph_header; | ||
537 | cnodeid_t cnodeid; | ||
538 | |||
539 | if (physical_node_map[nasid] == -1) | ||
540 | continue; | ||
541 | |||
542 | cnodeid = -1; | ||
543 | klgraph_header = __va(ia64_sn_get_klconfig_addr(nasid)); | ||
544 | if (!klgraph_header) { | ||
545 | if (IS_RUNNING_ON_SIMULATOR()) | ||
546 | continue; | ||
547 | BUG(); /* All nodes must have klconfig tables! */ | ||
548 | } | ||
549 | cnodeid = nasid_to_cnodeid(nasid); | ||
550 | root_lboard[cnodeid] = (lboard_t *) | ||
551 | NODE_OFFSET_TO_LBOARD((nasid), | ||
552 | ((kl_config_hdr_t | ||
553 | *) (klgraph_header))-> | ||
554 | ch_board_info); | ||
555 | } | ||
556 | |||
557 | /* Scan headless/memless IO Nodes. */ | ||
558 | for (nasid = 0; nasid < MAX_PHYSNODE_ID; nasid += 2) { | ||
559 | /* if there's no nasid, don't try to read the klconfig on the node */ | ||
560 | if (physical_node_map[nasid] == -1) | ||
561 | continue; | ||
562 | brd = find_lboard_any((lboard_t *) | ||
563 | root_lboard[nasid_to_cnodeid(nasid)], | ||
564 | KLTYPE_SNIA); | ||
565 | if (brd) { | ||
566 | brd = KLCF_NEXT_ANY(brd); /* Skip this node's lboard */ | ||
567 | if (!brd) | ||
568 | continue; | ||
569 | } | ||
570 | |||
571 | brd = find_lboard_any(brd, KLTYPE_SNIA); | ||
572 | |||
573 | while (brd) { | ||
574 | pda->cnodeid_to_nasid_table[numionodes] = | ||
575 | brd->brd_nasid; | ||
576 | physical_node_map[brd->brd_nasid] = numionodes; | ||
577 | root_lboard[numionodes] = brd; | ||
578 | numionodes++; | ||
579 | brd = KLCF_NEXT_ANY(brd); | ||
580 | if (!brd) | ||
581 | break; | ||
582 | |||
583 | brd = find_lboard_any(brd, KLTYPE_SNIA); | ||
584 | } | ||
585 | } | ||
586 | |||
587 | /* Scan for TIO nodes. */ | ||
588 | for (nasid = 0; nasid < MAX_PHYSNODE_ID; nasid += 2) { | ||
589 | /* if there's no nasid, don't try to read the klconfig on the node */ | ||
590 | if (physical_node_map[nasid] == -1) | ||
591 | continue; | ||
592 | brd = find_lboard_any((lboard_t *) | ||
593 | root_lboard[nasid_to_cnodeid(nasid)], | ||
594 | KLTYPE_TIO); | ||
595 | while (brd) { | ||
596 | pda->cnodeid_to_nasid_table[numionodes] = | ||
597 | brd->brd_nasid; | ||
598 | physical_node_map[brd->brd_nasid] = numionodes; | ||
599 | root_lboard[numionodes] = brd; | ||
600 | numionodes++; | ||
601 | brd = KLCF_NEXT_ANY(brd); | ||
602 | if (!brd) | ||
603 | break; | ||
604 | |||
605 | brd = find_lboard_any(brd, KLTYPE_TIO); | ||
606 | } | ||
607 | } | ||
608 | |||
609 | } | ||
610 | |||
611 | int | ||
612 | nasid_slice_to_cpuid(int nasid, int slice) | ||
613 | { | ||
614 | long cpu; | ||
615 | |||
616 | for (cpu=0; cpu < NR_CPUS; cpu++) | ||
617 | if (nodepda->phys_cpuid[cpu].nasid == nasid && nodepda->phys_cpuid[cpu].slice == slice) | ||
618 | return cpu; | ||
619 | |||
620 | return -1; | ||
621 | } | ||