xref: /linux/arch/mips/sgi-ip27/ip27-memory.c (revision 2bf8ec2d8137e66998435ddf6d4060a558e2f727)
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(&region_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