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) 2000, 05 by Ralf Baechle (ralf@linux-mips.org) 7 * Copyright (C) 2000 by Silicon Graphics, Inc. 8 * Copyright (C) 2004 by Christoph Hellwig 9 * 10 * On SGI IP27 the ARC memory configuration data is completly bogus but 11 * alternate easier to use mechanisms are available. 12 */ 13 #include <linux/init.h> 14 #include <linux/kernel.h> 15 #include <linux/memblock.h> 16 #include <linux/mm.h> 17 #include <linux/mmzone.h> 18 #include <linux/module.h> 19 #include <linux/nodemask.h> 20 #include <linux/swap.h> 21 #include <linux/bootmem.h> 22 #include <linux/pfn.h> 23 #include <linux/highmem.h> 24 #include <asm/page.h> 25 #include <asm/pgalloc.h> 26 #include <asm/sections.h> 27 28 #include <asm/sn/arch.h> 29 #include <asm/sn/hub.h> 30 #include <asm/sn/klconfig.h> 31 #include <asm/sn/sn_private.h> 32 33 34 #define SLOT_PFNSHIFT (SLOT_SHIFT - PAGE_SHIFT) 35 #define PFN_NASIDSHFT (NASID_SHFT - PAGE_SHIFT) 36 37 struct node_data *__node_data[MAX_COMPACT_NODES]; 38 39 EXPORT_SYMBOL(__node_data); 40 41 static int fine_mode; 42 43 static int is_fine_dirmode(void) 44 { 45 return (((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_REGIONSIZE_MASK) 46 >> NSRI_REGIONSIZE_SHFT) & REGIONSIZE_FINE); 47 } 48 49 static hubreg_t get_region(cnodeid_t cnode) 50 { 51 if (fine_mode) 52 return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_FINEREG_SHFT; 53 else 54 return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_COARSEREG_SHFT; 55 } 56 57 static hubreg_t region_mask; 58 59 static void gen_region_mask(hubreg_t *region_mask) 60 { 61 cnodeid_t cnode; 62 63 (*region_mask) = 0; 64 for_each_online_node(cnode) { 65 (*region_mask) |= 1ULL << get_region(cnode); 66 } 67 } 68 69 #define rou_rflag rou_flags 70 71 static int router_distance; 72 73 static void router_recurse(klrou_t *router_a, klrou_t *router_b, int depth) 74 { 75 klrou_t *router; 76 lboard_t *brd; 77 int port; 78 79 if (router_a->rou_rflag == 1) 80 return; 81 82 if (depth >= router_distance) 83 return; 84 85 router_a->rou_rflag = 1; 86 87 for (port = 1; port <= MAX_ROUTER_PORTS; port++) { 88 if (router_a->rou_port[port].port_nasid == INVALID_NASID) 89 continue; 90 91 brd = (lboard_t *)NODE_OFFSET_TO_K0( 92 router_a->rou_port[port].port_nasid, 93 router_a->rou_port[port].port_offset); 94 95 if (brd->brd_type == KLTYPE_ROUTER) { 96 router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]); 97 if (router == router_b) { 98 if (depth < router_distance) 99 router_distance = depth; 100 } 101 else 102 router_recurse(router, router_b, depth + 1); 103 } 104 } 105 106 router_a->rou_rflag = 0; 107 } 108 109 unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES]; 110 EXPORT_SYMBOL(__node_distances); 111 112 static int __init compute_node_distance(nasid_t nasid_a, nasid_t nasid_b) 113 { 114 klrou_t *router, *router_a = NULL, *router_b = NULL; 115 lboard_t *brd, *dest_brd; 116 cnodeid_t cnode; 117 nasid_t nasid; 118 int port; 119 120 /* Figure out which routers nodes in question are connected to */ 121 for_each_online_node(cnode) { 122 nasid = COMPACT_TO_NASID_NODEID(cnode); 123 124 if (nasid == -1) continue; 125 126 brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid), 127 KLTYPE_ROUTER); 128 129 if (!brd) 130 continue; 131 132 do { 133 if (brd->brd_flags & DUPLICATE_BOARD) 134 continue; 135 136 router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]); 137 router->rou_rflag = 0; 138 139 for (port = 1; port <= MAX_ROUTER_PORTS; port++) { 140 if (router->rou_port[port].port_nasid == INVALID_NASID) 141 continue; 142 143 dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( 144 router->rou_port[port].port_nasid, 145 router->rou_port[port].port_offset); 146 147 if (dest_brd->brd_type == KLTYPE_IP27) { 148 if (dest_brd->brd_nasid == nasid_a) 149 router_a = router; 150 if (dest_brd->brd_nasid == nasid_b) 151 router_b = router; 152 } 153 } 154 155 } while ((brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER))); 156 } 157 158 if (router_a == NULL) { 159 printk("node_distance: router_a NULL\n"); 160 return -1; 161 } 162 if (router_b == NULL) { 163 printk("node_distance: router_b NULL\n"); 164 return -1; 165 } 166 167 if (nasid_a == nasid_b) 168 return 0; 169 170 if (router_a == router_b) 171 return 1; 172 173 router_distance = 100; 174 router_recurse(router_a, router_b, 2); 175 176 return router_distance; 177 } 178 179 static void __init init_topology_matrix(void) 180 { 181 nasid_t nasid, nasid2; 182 cnodeid_t row, col; 183 184 for (row = 0; row < MAX_COMPACT_NODES; row++) 185 for (col = 0; col < MAX_COMPACT_NODES; col++) 186 __node_distances[row][col] = -1; 187 188 for_each_online_node(row) { 189 nasid = COMPACT_TO_NASID_NODEID(row); 190 for_each_online_node(col) { 191 nasid2 = COMPACT_TO_NASID_NODEID(col); 192 __node_distances[row][col] = 193 compute_node_distance(nasid, nasid2); 194 } 195 } 196 } 197 198 static void __init dump_topology(void) 199 { 200 nasid_t nasid; 201 cnodeid_t cnode; 202 lboard_t *brd, *dest_brd; 203 int port; 204 int router_num = 0; 205 klrou_t *router; 206 cnodeid_t row, col; 207 208 printk("************** Topology ********************\n"); 209 210 printk(" "); 211 for_each_online_node(col) 212 printk("%02d ", col); 213 printk("\n"); 214 for_each_online_node(row) { 215 printk("%02d ", row); 216 for_each_online_node(col) 217 printk("%2d ", node_distance(row, col)); 218 printk("\n"); 219 } 220 221 for_each_online_node(cnode) { 222 nasid = COMPACT_TO_NASID_NODEID(cnode); 223 224 if (nasid == -1) continue; 225 226 brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid), 227 KLTYPE_ROUTER); 228 229 if (!brd) 230 continue; 231 232 do { 233 if (brd->brd_flags & DUPLICATE_BOARD) 234 continue; 235 printk("Router %d:", router_num); 236 router_num++; 237 238 router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]); 239 240 for (port = 1; port <= MAX_ROUTER_PORTS; port++) { 241 if (router->rou_port[port].port_nasid == INVALID_NASID) 242 continue; 243 244 dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( 245 router->rou_port[port].port_nasid, 246 router->rou_port[port].port_offset); 247 248 if (dest_brd->brd_type == KLTYPE_IP27) 249 printk(" %d", dest_brd->brd_nasid); 250 if (dest_brd->brd_type == KLTYPE_ROUTER) 251 printk(" r"); 252 } 253 printk("\n"); 254 255 } while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) ); 256 } 257 } 258 259 static unsigned long __init slot_getbasepfn(cnodeid_t cnode, int slot) 260 { 261 nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode); 262 263 return ((unsigned long)nasid << PFN_NASIDSHFT) | (slot << SLOT_PFNSHIFT); 264 } 265 266 static unsigned long __init slot_psize_compute(cnodeid_t node, int slot) 267 { 268 nasid_t nasid; 269 lboard_t *brd; 270 klmembnk_t *banks; 271 unsigned long size; 272 273 nasid = COMPACT_TO_NASID_NODEID(node); 274 /* Find the node board */ 275 brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27); 276 if (!brd) 277 return 0; 278 279 /* Get the memory bank structure */ 280 banks = (klmembnk_t *) find_first_component(brd, KLSTRUCT_MEMBNK); 281 if (!banks) 282 return 0; 283 284 /* Size in _Megabytes_ */ 285 size = (unsigned long)banks->membnk_bnksz[slot/4]; 286 287 /* hack for 128 dimm banks */ 288 if (size <= 128) { 289 if (slot % 4 == 0) { 290 size <<= 20; /* size in bytes */ 291 return(size >> PAGE_SHIFT); 292 } else 293 return 0; 294 } else { 295 size /= 4; 296 size <<= 20; 297 return size >> PAGE_SHIFT; 298 } 299 } 300 301 static void __init mlreset(void) 302 { 303 int i; 304 305 master_nasid = get_nasid(); 306 fine_mode = is_fine_dirmode(); 307 308 /* 309 * Probe for all CPUs - this creates the cpumask and sets up the 310 * mapping tables. We need to do this as early as possible. 311 */ 312 #ifdef CONFIG_SMP 313 cpu_node_probe(); 314 #endif 315 316 init_topology_matrix(); 317 dump_topology(); 318 319 gen_region_mask(®ion_mask); 320 321 setup_replication_mask(); 322 323 /* 324 * Set all nodes' calias sizes to 8k 325 */ 326 for_each_online_node(i) { 327 nasid_t nasid; 328 329 nasid = COMPACT_TO_NASID_NODEID(i); 330 331 /* 332 * Always have node 0 in the region mask, otherwise 333 * CALIAS accesses get exceptions since the hub 334 * thinks it is a node 0 address. 335 */ 336 REMOTE_HUB_S(nasid, PI_REGION_PRESENT, (region_mask | 1)); 337 #ifdef CONFIG_REPLICATE_EXHANDLERS 338 REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_8K); 339 #else 340 REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_0); 341 #endif 342 343 #ifdef LATER 344 /* 345 * Set up all hubs to have a big window pointing at 346 * widget 0. Memory mode, widget 0, offset 0 347 */ 348 REMOTE_HUB_S(nasid, IIO_ITTE(SWIN0_BIGWIN), 349 ((HUB_PIO_MAP_TO_MEM << IIO_ITTE_IOSP_SHIFT) | 350 (0 << IIO_ITTE_WIDGET_SHIFT))); 351 #endif 352 } 353 } 354 355 static void __init szmem(void) 356 { 357 unsigned long slot_psize, slot0sz = 0, nodebytes; /* Hack to detect problem configs */ 358 int slot; 359 cnodeid_t node; 360 361 for_each_online_node(node) { 362 nodebytes = 0; 363 for (slot = 0; slot < MAX_MEM_SLOTS; slot++) { 364 slot_psize = slot_psize_compute(node, slot); 365 if (slot == 0) 366 slot0sz = slot_psize; 367 /* 368 * We need to refine the hack when we have replicated 369 * kernel text. 370 */ 371 nodebytes += (1LL << SLOT_SHIFT); 372 373 if (!slot_psize) 374 continue; 375 376 if ((nodebytes >> PAGE_SHIFT) * (sizeof(struct page)) > 377 (slot0sz << PAGE_SHIFT)) { 378 printk("Ignoring slot %d onwards on node %d\n", 379 slot, node); 380 slot = MAX_MEM_SLOTS; 381 continue; 382 } 383 memblock_add_node(PFN_PHYS(slot_getbasepfn(node, slot)), 384 PFN_PHYS(slot_psize), node); 385 } 386 } 387 } 388 389 static void __init node_mem_init(cnodeid_t node) 390 { 391 unsigned long slot_firstpfn = slot_getbasepfn(node, 0); 392 unsigned long slot_freepfn = node_getfirstfree(node); 393 unsigned long bootmap_size; 394 unsigned long start_pfn, end_pfn; 395 396 get_pfn_range_for_nid(node, &start_pfn, &end_pfn); 397 398 /* 399 * Allocate the node data structures on the node first. 400 */ 401 __node_data[node] = __va(slot_freepfn << PAGE_SHIFT); 402 memset(__node_data[node], 0, PAGE_SIZE); 403 404 NODE_DATA(node)->bdata = &bootmem_node_data[node]; 405 NODE_DATA(node)->node_start_pfn = start_pfn; 406 NODE_DATA(node)->node_spanned_pages = end_pfn - start_pfn; 407 408 cpus_clear(hub_data(node)->h_cpus); 409 410 slot_freepfn += PFN_UP(sizeof(struct pglist_data) + 411 sizeof(struct hub_data)); 412 413 bootmap_size = init_bootmem_node(NODE_DATA(node), slot_freepfn, 414 start_pfn, end_pfn); 415 free_bootmem_with_active_regions(node, end_pfn); 416 reserve_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT, 417 ((slot_freepfn - slot_firstpfn) << PAGE_SHIFT) + bootmap_size, 418 BOOTMEM_DEFAULT); 419 sparse_memory_present_with_active_regions(node); 420 } 421 422 /* 423 * A node with nothing. We use it to avoid any special casing in 424 * cpumask_of_node 425 */ 426 static struct node_data null_node = { 427 .hub = { 428 .h_cpus = CPU_MASK_NONE 429 } 430 }; 431 432 /* 433 * Currently, the intranode memory hole support assumes that each slot 434 * contains at least 32 MBytes of memory. We assume all bootmem data 435 * fits on the first slot. 436 */ 437 void __init prom_meminit(void) 438 { 439 cnodeid_t node; 440 441 mlreset(); 442 szmem(); 443 444 for (node = 0; node < MAX_COMPACT_NODES; node++) { 445 if (node_online(node)) { 446 node_mem_init(node); 447 continue; 448 } 449 __node_data[node] = &null_node; 450 } 451 } 452 453 void __init prom_free_prom_memory(void) 454 { 455 /* We got nothing to free here ... */ 456 } 457 458 extern void setup_zero_pages(void); 459 460 void __init paging_init(void) 461 { 462 unsigned long zones_size[MAX_NR_ZONES] = {0, }; 463 unsigned node; 464 465 pagetable_init(); 466 467 for_each_online_node(node) { 468 unsigned long start_pfn, end_pfn; 469 470 get_pfn_range_for_nid(node, &start_pfn, &end_pfn); 471 472 if (end_pfn > max_low_pfn) 473 max_low_pfn = end_pfn; 474 } 475 zones_size[ZONE_NORMAL] = max_low_pfn; 476 free_area_init_nodes(zones_size); 477 } 478 479 void __init mem_init(void) 480 { 481 high_memory = (void *) __va(get_num_physpages() << PAGE_SHIFT); 482 free_all_bootmem(); 483 setup_zero_pages(); /* This comes from node 0 */ 484 mem_init_print_info(NULL); 485 } 486