11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public 31da177e4SLinus Torvalds * License. See the file "COPYING" in the main directory of this archive 41da177e4SLinus Torvalds * for more details. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (C) 2000, 05 by Ralf Baechle (ralf@linux-mips.org) 71da177e4SLinus Torvalds * Copyright (C) 2000 by Silicon Graphics, Inc. 81da177e4SLinus Torvalds * Copyright (C) 2004 by Christoph Hellwig 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * On SGI IP27 the ARC memory configuration data is completly bogus but 111da177e4SLinus Torvalds * alternate easier to use mechanisms are available. 121da177e4SLinus Torvalds */ 131da177e4SLinus Torvalds #include <linux/init.h> 141da177e4SLinus Torvalds #include <linux/kernel.h> 151da177e4SLinus Torvalds #include <linux/mm.h> 161da177e4SLinus Torvalds #include <linux/mmzone.h> 171da177e4SLinus Torvalds #include <linux/module.h> 181da177e4SLinus Torvalds #include <linux/nodemask.h> 191da177e4SLinus Torvalds #include <linux/swap.h> 201da177e4SLinus Torvalds #include <linux/bootmem.h> 2122a9835cSDave Hansen #include <linux/pfn.h> 22c1f60a5aSChristoph Lameter #include <linux/highmem.h> 231da177e4SLinus Torvalds #include <asm/page.h> 246a1e5529SAtsushi Nemoto #include <asm/pgalloc.h> 251da177e4SLinus Torvalds #include <asm/sections.h> 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds #include <asm/sn/arch.h> 281da177e4SLinus Torvalds #include <asm/sn/hub.h> 291da177e4SLinus Torvalds #include <asm/sn/klconfig.h> 301da177e4SLinus Torvalds #include <asm/sn/sn_private.h> 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds #define SLOT_PFNSHIFT (SLOT_SHIFT - PAGE_SHIFT) 341da177e4SLinus Torvalds #define PFN_NASIDSHFT (NASID_SHFT - PAGE_SHIFT) 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds static struct bootmem_data __initdata plat_node_bdata[MAX_COMPACT_NODES]; 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds struct node_data *__node_data[MAX_COMPACT_NODES]; 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds EXPORT_SYMBOL(__node_data); 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds static int fine_mode; 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds static int is_fine_dirmode(void) 451da177e4SLinus Torvalds { 461da177e4SLinus Torvalds return (((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_REGIONSIZE_MASK) 471da177e4SLinus Torvalds >> NSRI_REGIONSIZE_SHFT) & REGIONSIZE_FINE); 481da177e4SLinus Torvalds } 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds static hubreg_t get_region(cnodeid_t cnode) 511da177e4SLinus Torvalds { 521da177e4SLinus Torvalds if (fine_mode) 531da177e4SLinus Torvalds return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_FINEREG_SHFT; 541da177e4SLinus Torvalds else 551da177e4SLinus Torvalds return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_COARSEREG_SHFT; 561da177e4SLinus Torvalds } 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds static hubreg_t region_mask; 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds static void gen_region_mask(hubreg_t *region_mask) 611da177e4SLinus Torvalds { 621da177e4SLinus Torvalds cnodeid_t cnode; 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds (*region_mask) = 0; 651da177e4SLinus Torvalds for_each_online_node(cnode) { 661da177e4SLinus Torvalds (*region_mask) |= 1ULL << get_region(cnode); 671da177e4SLinus Torvalds } 681da177e4SLinus Torvalds } 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds #define rou_rflag rou_flags 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds static int router_distance; 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds static void router_recurse(klrou_t *router_a, klrou_t *router_b, int depth) 751da177e4SLinus Torvalds { 761da177e4SLinus Torvalds klrou_t *router; 771da177e4SLinus Torvalds lboard_t *brd; 781da177e4SLinus Torvalds int port; 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds if (router_a->rou_rflag == 1) 811da177e4SLinus Torvalds return; 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds if (depth >= router_distance) 841da177e4SLinus Torvalds return; 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds router_a->rou_rflag = 1; 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds for (port = 1; port <= MAX_ROUTER_PORTS; port++) { 891da177e4SLinus Torvalds if (router_a->rou_port[port].port_nasid == INVALID_NASID) 901da177e4SLinus Torvalds continue; 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds brd = (lboard_t *)NODE_OFFSET_TO_K0( 931da177e4SLinus Torvalds router_a->rou_port[port].port_nasid, 941da177e4SLinus Torvalds router_a->rou_port[port].port_offset); 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds if (brd->brd_type == KLTYPE_ROUTER) { 971da177e4SLinus Torvalds router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]); 981da177e4SLinus Torvalds if (router == router_b) { 991da177e4SLinus Torvalds if (depth < router_distance) 1001da177e4SLinus Torvalds router_distance = depth; 1011da177e4SLinus Torvalds } 1021da177e4SLinus Torvalds else 1031da177e4SLinus Torvalds router_recurse(router, router_b, depth + 1); 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds router_a->rou_rflag = 0; 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES]; 1111da177e4SLinus Torvalds 1121da177e4SLinus Torvalds static int __init compute_node_distance(nasid_t nasid_a, nasid_t nasid_b) 1131da177e4SLinus Torvalds { 1141da177e4SLinus Torvalds klrou_t *router, *router_a = NULL, *router_b = NULL; 1151da177e4SLinus Torvalds lboard_t *brd, *dest_brd; 1161da177e4SLinus Torvalds cnodeid_t cnode; 1171da177e4SLinus Torvalds nasid_t nasid; 1181da177e4SLinus Torvalds int port; 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds /* Figure out which routers nodes in question are connected to */ 1211da177e4SLinus Torvalds for_each_online_node(cnode) { 1221da177e4SLinus Torvalds nasid = COMPACT_TO_NASID_NODEID(cnode); 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds if (nasid == -1) continue; 1251da177e4SLinus Torvalds 1261da177e4SLinus Torvalds brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid), 1271da177e4SLinus Torvalds KLTYPE_ROUTER); 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds if (!brd) 1301da177e4SLinus Torvalds continue; 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds do { 1331da177e4SLinus Torvalds if (brd->brd_flags & DUPLICATE_BOARD) 1341da177e4SLinus Torvalds continue; 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]); 1371da177e4SLinus Torvalds router->rou_rflag = 0; 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds for (port = 1; port <= MAX_ROUTER_PORTS; port++) { 1401da177e4SLinus Torvalds if (router->rou_port[port].port_nasid == INVALID_NASID) 1411da177e4SLinus Torvalds continue; 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( 1441da177e4SLinus Torvalds router->rou_port[port].port_nasid, 1451da177e4SLinus Torvalds router->rou_port[port].port_offset); 1461da177e4SLinus Torvalds 1471da177e4SLinus Torvalds if (dest_brd->brd_type == KLTYPE_IP27) { 1481da177e4SLinus Torvalds if (dest_brd->brd_nasid == nasid_a) 1491da177e4SLinus Torvalds router_a = router; 1501da177e4SLinus Torvalds if (dest_brd->brd_nasid == nasid_b) 1511da177e4SLinus Torvalds router_b = router; 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds } 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds } while ((brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER))); 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds if (router_a == NULL) { 1591da177e4SLinus Torvalds printk("node_distance: router_a NULL\n"); 1601da177e4SLinus Torvalds return -1; 1611da177e4SLinus Torvalds } 1621da177e4SLinus Torvalds if (router_b == NULL) { 1631da177e4SLinus Torvalds printk("node_distance: router_b NULL\n"); 1641da177e4SLinus Torvalds return -1; 1651da177e4SLinus Torvalds } 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds if (nasid_a == nasid_b) 1681da177e4SLinus Torvalds return 0; 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds if (router_a == router_b) 1711da177e4SLinus Torvalds return 1; 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds router_distance = 100; 1741da177e4SLinus Torvalds router_recurse(router_a, router_b, 2); 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds return router_distance; 1771da177e4SLinus Torvalds } 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds static void __init init_topology_matrix(void) 1801da177e4SLinus Torvalds { 1811da177e4SLinus Torvalds nasid_t nasid, nasid2; 1821da177e4SLinus Torvalds cnodeid_t row, col; 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds for (row = 0; row < MAX_COMPACT_NODES; row++) 1851da177e4SLinus Torvalds for (col = 0; col < MAX_COMPACT_NODES; col++) 1861da177e4SLinus Torvalds __node_distances[row][col] = -1; 1871da177e4SLinus Torvalds 1881da177e4SLinus Torvalds for_each_online_node(row) { 1891da177e4SLinus Torvalds nasid = COMPACT_TO_NASID_NODEID(row); 1901da177e4SLinus Torvalds for_each_online_node(col) { 1911da177e4SLinus Torvalds nasid2 = COMPACT_TO_NASID_NODEID(col); 1921da177e4SLinus Torvalds __node_distances[row][col] = 1931da177e4SLinus Torvalds compute_node_distance(nasid, nasid2); 1941da177e4SLinus Torvalds } 1951da177e4SLinus Torvalds } 1961da177e4SLinus Torvalds } 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds static void __init dump_topology(void) 1991da177e4SLinus Torvalds { 2001da177e4SLinus Torvalds nasid_t nasid; 2011da177e4SLinus Torvalds cnodeid_t cnode; 2021da177e4SLinus Torvalds lboard_t *brd, *dest_brd; 2031da177e4SLinus Torvalds int port; 2041da177e4SLinus Torvalds int router_num = 0; 2051da177e4SLinus Torvalds klrou_t *router; 2061da177e4SLinus Torvalds cnodeid_t row, col; 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds printk("************** Topology ********************\n"); 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds printk(" "); 2111da177e4SLinus Torvalds for_each_online_node(col) 2121da177e4SLinus Torvalds printk("%02d ", col); 2131da177e4SLinus Torvalds printk("\n"); 2141da177e4SLinus Torvalds for_each_online_node(row) { 2151da177e4SLinus Torvalds printk("%02d ", row); 2161da177e4SLinus Torvalds for_each_online_node(col) 2171da177e4SLinus Torvalds printk("%2d ", node_distance(row, col)); 2181da177e4SLinus Torvalds printk("\n"); 2191da177e4SLinus Torvalds } 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds for_each_online_node(cnode) { 2221da177e4SLinus Torvalds nasid = COMPACT_TO_NASID_NODEID(cnode); 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds if (nasid == -1) continue; 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid), 2271da177e4SLinus Torvalds KLTYPE_ROUTER); 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds if (!brd) 2301da177e4SLinus Torvalds continue; 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds do { 2331da177e4SLinus Torvalds if (brd->brd_flags & DUPLICATE_BOARD) 2341da177e4SLinus Torvalds continue; 2351da177e4SLinus Torvalds printk("Router %d:", router_num); 2361da177e4SLinus Torvalds router_num++; 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]); 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds for (port = 1; port <= MAX_ROUTER_PORTS; port++) { 2411da177e4SLinus Torvalds if (router->rou_port[port].port_nasid == INVALID_NASID) 2421da177e4SLinus Torvalds continue; 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( 2451da177e4SLinus Torvalds router->rou_port[port].port_nasid, 2461da177e4SLinus Torvalds router->rou_port[port].port_offset); 2471da177e4SLinus Torvalds 2481da177e4SLinus Torvalds if (dest_brd->brd_type == KLTYPE_IP27) 2491da177e4SLinus Torvalds printk(" %d", dest_brd->brd_nasid); 2501da177e4SLinus Torvalds if (dest_brd->brd_type == KLTYPE_ROUTER) 2511da177e4SLinus Torvalds printk(" r"); 2521da177e4SLinus Torvalds } 2531da177e4SLinus Torvalds printk("\n"); 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds } while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) ); 2561da177e4SLinus Torvalds } 2571da177e4SLinus Torvalds } 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds static pfn_t __init slot_getbasepfn(cnodeid_t cnode, int slot) 2601da177e4SLinus Torvalds { 2611da177e4SLinus Torvalds nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode); 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds return ((pfn_t)nasid << PFN_NASIDSHFT) | (slot << SLOT_PFNSHIFT); 2641da177e4SLinus Torvalds } 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds static pfn_t __init slot_psize_compute(cnodeid_t node, int slot) 2671da177e4SLinus Torvalds { 2681da177e4SLinus Torvalds nasid_t nasid; 2691da177e4SLinus Torvalds lboard_t *brd; 2701da177e4SLinus Torvalds klmembnk_t *banks; 2711da177e4SLinus Torvalds unsigned long size; 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds nasid = COMPACT_TO_NASID_NODEID(node); 2741da177e4SLinus Torvalds /* Find the node board */ 2751da177e4SLinus Torvalds brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27); 2761da177e4SLinus Torvalds if (!brd) 2771da177e4SLinus Torvalds return 0; 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds /* Get the memory bank structure */ 2801da177e4SLinus Torvalds banks = (klmembnk_t *) find_first_component(brd, KLSTRUCT_MEMBNK); 2811da177e4SLinus Torvalds if (!banks) 2821da177e4SLinus Torvalds return 0; 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds /* Size in _Megabytes_ */ 2851da177e4SLinus Torvalds size = (unsigned long)banks->membnk_bnksz[slot/4]; 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds /* hack for 128 dimm banks */ 2881da177e4SLinus Torvalds if (size <= 128) { 2891da177e4SLinus Torvalds if (slot % 4 == 0) { 2901da177e4SLinus Torvalds size <<= 20; /* size in bytes */ 2911da177e4SLinus Torvalds return(size >> PAGE_SHIFT); 2921da177e4SLinus Torvalds } else 2931da177e4SLinus Torvalds return 0; 2941da177e4SLinus Torvalds } else { 2951da177e4SLinus Torvalds size /= 4; 2961da177e4SLinus Torvalds size <<= 20; 2971da177e4SLinus Torvalds return size >> PAGE_SHIFT; 2981da177e4SLinus Torvalds } 2991da177e4SLinus Torvalds } 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds static void __init mlreset(void) 3021da177e4SLinus Torvalds { 3031da177e4SLinus Torvalds int i; 3041da177e4SLinus Torvalds 3051da177e4SLinus Torvalds master_nasid = get_nasid(); 3061da177e4SLinus Torvalds fine_mode = is_fine_dirmode(); 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds /* 3091da177e4SLinus Torvalds * Probe for all CPUs - this creates the cpumask and sets up the 3101da177e4SLinus Torvalds * mapping tables. We need to do this as early as possible. 3111da177e4SLinus Torvalds */ 3121da177e4SLinus Torvalds #ifdef CONFIG_SMP 3131da177e4SLinus Torvalds cpu_node_probe(); 3141da177e4SLinus Torvalds #endif 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds init_topology_matrix(); 3171da177e4SLinus Torvalds dump_topology(); 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds gen_region_mask(®ion_mask); 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds setup_replication_mask(); 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds /* 3241da177e4SLinus Torvalds * Set all nodes' calias sizes to 8k 3251da177e4SLinus Torvalds */ 3261da177e4SLinus Torvalds for_each_online_node(i) { 3271da177e4SLinus Torvalds nasid_t nasid; 3281da177e4SLinus Torvalds 3291da177e4SLinus Torvalds nasid = COMPACT_TO_NASID_NODEID(i); 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds /* 3321da177e4SLinus Torvalds * Always have node 0 in the region mask, otherwise 3331da177e4SLinus Torvalds * CALIAS accesses get exceptions since the hub 3341da177e4SLinus Torvalds * thinks it is a node 0 address. 3351da177e4SLinus Torvalds */ 3361da177e4SLinus Torvalds REMOTE_HUB_S(nasid, PI_REGION_PRESENT, (region_mask | 1)); 3371da177e4SLinus Torvalds #ifdef CONFIG_REPLICATE_EXHANDLERS 3381da177e4SLinus Torvalds REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_8K); 3391da177e4SLinus Torvalds #else 3401da177e4SLinus Torvalds REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_0); 3411da177e4SLinus Torvalds #endif 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds #ifdef LATER 3441da177e4SLinus Torvalds /* 3451da177e4SLinus Torvalds * Set up all hubs to have a big window pointing at 3461da177e4SLinus Torvalds * widget 0. Memory mode, widget 0, offset 0 3471da177e4SLinus Torvalds */ 3481da177e4SLinus Torvalds REMOTE_HUB_S(nasid, IIO_ITTE(SWIN0_BIGWIN), 3491da177e4SLinus Torvalds ((HUB_PIO_MAP_TO_MEM << IIO_ITTE_IOSP_SHIFT) | 3501da177e4SLinus Torvalds (0 << IIO_ITTE_WIDGET_SHIFT))); 3511da177e4SLinus Torvalds #endif 3521da177e4SLinus Torvalds } 3531da177e4SLinus Torvalds } 3541da177e4SLinus Torvalds 3551da177e4SLinus Torvalds static void __init szmem(void) 3561da177e4SLinus Torvalds { 3571da177e4SLinus Torvalds pfn_t slot_psize, slot0sz = 0, nodebytes; /* Hack to detect problem configs */ 358*2bf8ec2dSThomas Bogendoerfer int slot; 3591da177e4SLinus Torvalds cnodeid_t node; 3601da177e4SLinus Torvalds 3611da177e4SLinus Torvalds num_physpages = 0; 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds for_each_online_node(node) { 364*2bf8ec2dSThomas Bogendoerfer nodebytes = 0; 3651da177e4SLinus Torvalds for (slot = 0; slot < MAX_MEM_SLOTS; slot++) { 3661da177e4SLinus Torvalds slot_psize = slot_psize_compute(node, slot); 3671da177e4SLinus Torvalds if (slot == 0) 3681da177e4SLinus Torvalds slot0sz = slot_psize; 3691da177e4SLinus Torvalds /* 3701da177e4SLinus Torvalds * We need to refine the hack when we have replicated 3711da177e4SLinus Torvalds * kernel text. 3721da177e4SLinus Torvalds */ 3731da177e4SLinus Torvalds nodebytes += (1LL << SLOT_SHIFT); 374*2bf8ec2dSThomas Bogendoerfer 375*2bf8ec2dSThomas Bogendoerfer if (!slot_psize) 376*2bf8ec2dSThomas Bogendoerfer continue; 377*2bf8ec2dSThomas Bogendoerfer 3781da177e4SLinus Torvalds if ((nodebytes >> PAGE_SHIFT) * (sizeof(struct page)) > 379*2bf8ec2dSThomas Bogendoerfer (slot0sz << PAGE_SHIFT)) { 3801da177e4SLinus Torvalds printk("Ignoring slot %d onwards on node %d\n", 3811da177e4SLinus Torvalds slot, node); 3821da177e4SLinus Torvalds slot = MAX_MEM_SLOTS; 3831da177e4SLinus Torvalds continue; 3841da177e4SLinus Torvalds } 3851da177e4SLinus Torvalds num_physpages += slot_psize; 386*2bf8ec2dSThomas Bogendoerfer add_active_range(node, slot_getbasepfn(node, slot), 387*2bf8ec2dSThomas Bogendoerfer slot_getbasepfn(node, slot) + slot_psize); 3881da177e4SLinus Torvalds } 3891da177e4SLinus Torvalds } 3901da177e4SLinus Torvalds } 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds static void __init node_mem_init(cnodeid_t node) 3931da177e4SLinus Torvalds { 3941da177e4SLinus Torvalds pfn_t slot_firstpfn = slot_getbasepfn(node, 0); 3951da177e4SLinus Torvalds pfn_t slot_freepfn = node_getfirstfree(node); 3961da177e4SLinus Torvalds unsigned long bootmap_size; 397*2bf8ec2dSThomas Bogendoerfer pfn_t start_pfn, end_pfn; 398*2bf8ec2dSThomas Bogendoerfer 399*2bf8ec2dSThomas Bogendoerfer get_pfn_range_for_nid(node, &start_pfn, &end_pfn); 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds /* 4021da177e4SLinus Torvalds * Allocate the node data structures on the node first. 4031da177e4SLinus Torvalds */ 4041da177e4SLinus Torvalds __node_data[node] = __va(slot_freepfn << PAGE_SHIFT); 4051da177e4SLinus Torvalds 406*2bf8ec2dSThomas Bogendoerfer NODE_DATA(node)->bdata = &plat_node_bdata[node]; 407*2bf8ec2dSThomas Bogendoerfer NODE_DATA(node)->node_start_pfn = start_pfn; 408*2bf8ec2dSThomas Bogendoerfer NODE_DATA(node)->node_spanned_pages = end_pfn - start_pfn; 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds cpus_clear(hub_data(node)->h_cpus); 4111da177e4SLinus Torvalds 4121da177e4SLinus Torvalds slot_freepfn += PFN_UP(sizeof(struct pglist_data) + 4131da177e4SLinus Torvalds sizeof(struct hub_data)); 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds bootmap_size = init_bootmem_node(NODE_DATA(node), slot_freepfn, 416*2bf8ec2dSThomas Bogendoerfer start_pfn, end_pfn); 417*2bf8ec2dSThomas Bogendoerfer free_bootmem_with_active_regions(node, end_pfn); 4181da177e4SLinus Torvalds reserve_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT, 41972a7fe39SBernhard Walle ((slot_freepfn - slot_firstpfn) << PAGE_SHIFT) + bootmap_size, 42072a7fe39SBernhard Walle BOOTMEM_DEFAULT); 421*2bf8ec2dSThomas Bogendoerfer sparse_memory_present_with_active_regions(node); 4221da177e4SLinus Torvalds } 4231da177e4SLinus Torvalds 4241da177e4SLinus Torvalds /* 4251da177e4SLinus Torvalds * A node with nothing. We use it to avoid any special casing in 4261da177e4SLinus Torvalds * node_to_cpumask 4271da177e4SLinus Torvalds */ 4281da177e4SLinus Torvalds static struct node_data null_node = { 4291da177e4SLinus Torvalds .hub = { 4301da177e4SLinus Torvalds .h_cpus = CPU_MASK_NONE 4311da177e4SLinus Torvalds } 4321da177e4SLinus Torvalds }; 4331da177e4SLinus Torvalds 4341da177e4SLinus Torvalds /* 4351da177e4SLinus Torvalds * Currently, the intranode memory hole support assumes that each slot 4361da177e4SLinus Torvalds * contains at least 32 MBytes of memory. We assume all bootmem data 4371da177e4SLinus Torvalds * fits on the first slot. 4381da177e4SLinus Torvalds */ 4391da177e4SLinus Torvalds void __init prom_meminit(void) 4401da177e4SLinus Torvalds { 4411da177e4SLinus Torvalds cnodeid_t node; 4421da177e4SLinus Torvalds 4431da177e4SLinus Torvalds mlreset(); 4441da177e4SLinus Torvalds szmem(); 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds for (node = 0; node < MAX_COMPACT_NODES; node++) { 4471da177e4SLinus Torvalds if (node_online(node)) { 4481da177e4SLinus Torvalds node_mem_init(node); 4491da177e4SLinus Torvalds continue; 4501da177e4SLinus Torvalds } 4511da177e4SLinus Torvalds __node_data[node] = &null_node; 4521da177e4SLinus Torvalds } 4531da177e4SLinus Torvalds } 4541da177e4SLinus Torvalds 455c44e8d5eSAtsushi Nemoto void __init prom_free_prom_memory(void) 4561da177e4SLinus Torvalds { 4571da177e4SLinus Torvalds /* We got nothing to free here ... */ 4581da177e4SLinus Torvalds } 4591da177e4SLinus Torvalds 4601da177e4SLinus Torvalds extern unsigned long setup_zero_pages(void); 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds void __init paging_init(void) 4631da177e4SLinus Torvalds { 464f06a9684SChristoph Lameter unsigned long zones_size[MAX_NR_ZONES] = {0, }; 4651da177e4SLinus Torvalds unsigned node; 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds pagetable_init(); 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds for_each_online_node(node) { 470*2bf8ec2dSThomas Bogendoerfer pfn_t start_pfn, end_pfn; 4711da177e4SLinus Torvalds 472*2bf8ec2dSThomas Bogendoerfer get_pfn_range_for_nid(node, &start_pfn, &end_pfn); 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds if (end_pfn > max_low_pfn) 4751da177e4SLinus Torvalds max_low_pfn = end_pfn; 4761da177e4SLinus Torvalds } 477*2bf8ec2dSThomas Bogendoerfer zones_size[ZONE_NORMAL] = max_low_pfn; 478*2bf8ec2dSThomas Bogendoerfer free_area_init_nodes(zones_size); 4791da177e4SLinus Torvalds } 4801da177e4SLinus Torvalds 4811da177e4SLinus Torvalds void __init mem_init(void) 4821da177e4SLinus Torvalds { 4831da177e4SLinus Torvalds unsigned long codesize, datasize, initsize, tmp; 4841da177e4SLinus Torvalds unsigned node; 4851da177e4SLinus Torvalds 4861da177e4SLinus Torvalds high_memory = (void *) __va(num_physpages << PAGE_SHIFT); 4871da177e4SLinus Torvalds 4881da177e4SLinus Torvalds for_each_online_node(node) { 4891da177e4SLinus Torvalds /* 4901da177e4SLinus Torvalds * This will free up the bootmem, ie, slot 0 memory. 4911da177e4SLinus Torvalds */ 4921da177e4SLinus Torvalds totalram_pages += free_all_bootmem_node(NODE_DATA(node)); 4931da177e4SLinus Torvalds } 4941da177e4SLinus Torvalds 4951da177e4SLinus Torvalds totalram_pages -= setup_zero_pages(); /* This comes from node 0 */ 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds codesize = (unsigned long) &_etext - (unsigned long) &_text; 4981da177e4SLinus Torvalds datasize = (unsigned long) &_edata - (unsigned long) &_etext; 4991da177e4SLinus Torvalds initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; 5001da177e4SLinus Torvalds 5011da177e4SLinus Torvalds tmp = nr_free_pages(); 5021da177e4SLinus Torvalds printk(KERN_INFO "Memory: %luk/%luk available (%ldk kernel code, " 5031da177e4SLinus Torvalds "%ldk reserved, %ldk data, %ldk init, %ldk highmem)\n", 5041da177e4SLinus Torvalds tmp << (PAGE_SHIFT-10), 5051da177e4SLinus Torvalds num_physpages << (PAGE_SHIFT-10), 5061da177e4SLinus Torvalds codesize >> 10, 5071da177e4SLinus Torvalds (num_physpages - tmp) << (PAGE_SHIFT-10), 5081da177e4SLinus Torvalds datasize >> 10, 5091da177e4SLinus Torvalds initsize >> 10, 5101da177e4SLinus Torvalds (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))); 5111da177e4SLinus Torvalds } 512