xref: /linux/arch/mips/sgi-ip27/ip27-memory.c (revision 617a814f14b8914271f7a70366d72c6196d17663)
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  *
1092a76f6dSAdam Buchbinder  * On SGI IP27 the ARC memory configuration data is completely 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>
159d15ffc8STejun Heo #include <linux/memblock.h>
161da177e4SLinus Torvalds #include <linux/mm.h>
171da177e4SLinus Torvalds #include <linux/mmzone.h>
1826dd3e4fSPaul Gortmaker #include <linux/export.h>
191da177e4SLinus Torvalds #include <linux/nodemask.h>
201da177e4SLinus Torvalds #include <linux/swap.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>
26f134bd1eSThomas Bogendoerfer #include <asm/sgialib.h>
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds #include <asm/sn/arch.h>
29524c4e1fSThomas Bogendoerfer #include <asm/sn/agent.h>
301da177e4SLinus Torvalds #include <asm/sn/klconfig.h>
311da177e4SLinus Torvalds 
329d0aaf98SThomas Bogendoerfer #include "ip27-common.h"
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds #define SLOT_PFNSHIFT		(SLOT_SHIFT - PAGE_SHIFT)
351da177e4SLinus Torvalds #define PFN_NASIDSHFT		(NASID_SHFT - PAGE_SHIFT)
361da177e4SLinus Torvalds 
37*bc5c8ad3SMike Rapoport (Microsoft) struct node_data *__node_data[MAX_NUMNODES];
381da177e4SLinus Torvalds EXPORT_SYMBOL(__node_data);
391da177e4SLinus Torvalds 
40524c4e1fSThomas Bogendoerfer static u64 gen_region_mask(void)
411da177e4SLinus Torvalds {
42524c4e1fSThomas Bogendoerfer 	int region_shift;
43524c4e1fSThomas Bogendoerfer 	u64 region_mask;
444bf841ebSThomas Bogendoerfer 	nasid_t nasid;
451da177e4SLinus Torvalds 
46524c4e1fSThomas Bogendoerfer 	region_shift = get_region_shift();
47524c4e1fSThomas Bogendoerfer 	region_mask = 0;
48524c4e1fSThomas Bogendoerfer 	for_each_online_node(nasid)
49524c4e1fSThomas Bogendoerfer 		region_mask |= BIT_ULL(nasid >> region_shift);
50524c4e1fSThomas Bogendoerfer 
51524c4e1fSThomas Bogendoerfer 	return region_mask;
521da177e4SLinus Torvalds }
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds #define rou_rflag	rou_flags
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds static int router_distance;
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds static void router_recurse(klrou_t *router_a, klrou_t *router_b, int depth)
591da177e4SLinus Torvalds {
601da177e4SLinus Torvalds 	klrou_t *router;
611da177e4SLinus Torvalds 	lboard_t *brd;
621da177e4SLinus Torvalds 	int	port;
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds 	if (router_a->rou_rflag == 1)
651da177e4SLinus Torvalds 		return;
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds 	if (depth >= router_distance)
681da177e4SLinus Torvalds 		return;
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds 	router_a->rou_rflag = 1;
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds 	for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
731da177e4SLinus Torvalds 		if (router_a->rou_port[port].port_nasid == INVALID_NASID)
741da177e4SLinus Torvalds 			continue;
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds 		brd = (lboard_t *)NODE_OFFSET_TO_K0(
771da177e4SLinus Torvalds 			router_a->rou_port[port].port_nasid,
781da177e4SLinus Torvalds 			router_a->rou_port[port].port_offset);
791da177e4SLinus Torvalds 
801da177e4SLinus Torvalds 		if (brd->brd_type == KLTYPE_ROUTER) {
811da177e4SLinus Torvalds 			router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
821da177e4SLinus Torvalds 			if (router == router_b) {
831da177e4SLinus Torvalds 				if (depth < router_distance)
841da177e4SLinus Torvalds 					router_distance = depth;
851da177e4SLinus Torvalds 			}
861da177e4SLinus Torvalds 			else
871da177e4SLinus Torvalds 				router_recurse(router, router_b, depth + 1);
881da177e4SLinus Torvalds 		}
891da177e4SLinus Torvalds 	}
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds 	router_a->rou_rflag = 0;
921da177e4SLinus Torvalds }
931da177e4SLinus Torvalds 
94c80b4896SThomas Bogendoerfer unsigned char __node_distances[MAX_NUMNODES][MAX_NUMNODES];
955829b0ecSJames Cowgill EXPORT_SYMBOL(__node_distances);
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds static int __init compute_node_distance(nasid_t nasid_a, nasid_t nasid_b)
981da177e4SLinus Torvalds {
991da177e4SLinus Torvalds 	klrou_t *router, *router_a = NULL, *router_b = NULL;
1001da177e4SLinus Torvalds 	lboard_t *brd, *dest_brd;
1011da177e4SLinus Torvalds 	nasid_t nasid;
1021da177e4SLinus Torvalds 	int port;
1031da177e4SLinus Torvalds 
1041da177e4SLinus Torvalds 	/* Figure out which routers nodes in question are connected to */
1054bf841ebSThomas Bogendoerfer 	for_each_online_node(nasid) {
1061da177e4SLinus Torvalds 		brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
1071da177e4SLinus Torvalds 					KLTYPE_ROUTER);
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds 		if (!brd)
1101da177e4SLinus Torvalds 			continue;
1111da177e4SLinus Torvalds 
1121da177e4SLinus Torvalds 		do {
1131da177e4SLinus Torvalds 			if (brd->brd_flags & DUPLICATE_BOARD)
1141da177e4SLinus Torvalds 				continue;
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds 			router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
1171da177e4SLinus Torvalds 			router->rou_rflag = 0;
1181da177e4SLinus Torvalds 
1191da177e4SLinus Torvalds 			for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
1201da177e4SLinus Torvalds 				if (router->rou_port[port].port_nasid == INVALID_NASID)
1211da177e4SLinus Torvalds 					continue;
1221da177e4SLinus Torvalds 
1231da177e4SLinus Torvalds 				dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
1241da177e4SLinus Torvalds 					router->rou_port[port].port_nasid,
1251da177e4SLinus Torvalds 					router->rou_port[port].port_offset);
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds 				if (dest_brd->brd_type == KLTYPE_IP27) {
1281da177e4SLinus Torvalds 					if (dest_brd->brd_nasid == nasid_a)
1291da177e4SLinus Torvalds 						router_a = router;
1301da177e4SLinus Torvalds 					if (dest_brd->brd_nasid == nasid_b)
1311da177e4SLinus Torvalds 						router_b = router;
1321da177e4SLinus Torvalds 				}
1331da177e4SLinus Torvalds 			}
1341da177e4SLinus Torvalds 
1351da177e4SLinus Torvalds 		} while ((brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)));
1361da177e4SLinus Torvalds 	}
1371da177e4SLinus Torvalds 
138a20ebc04SThomas Bogendoerfer 	if (nasid_a == nasid_b)
139a20ebc04SThomas Bogendoerfer 		return LOCAL_DISTANCE;
140a20ebc04SThomas Bogendoerfer 
141a20ebc04SThomas Bogendoerfer 	if (router_a == router_b)
142a20ebc04SThomas Bogendoerfer 		return LOCAL_DISTANCE + 1;
143a20ebc04SThomas Bogendoerfer 
1441da177e4SLinus Torvalds 	if (router_a == NULL) {
145ab68280eSThomas Bogendoerfer 		pr_info("node_distance: router_a NULL\n");
146a20ebc04SThomas Bogendoerfer 		return 255;
1471da177e4SLinus Torvalds 	}
1481da177e4SLinus Torvalds 	if (router_b == NULL) {
149ab68280eSThomas Bogendoerfer 		pr_info("node_distance: router_b NULL\n");
150a20ebc04SThomas Bogendoerfer 		return 255;
1511da177e4SLinus Torvalds 	}
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds 	router_distance = 100;
1541da177e4SLinus Torvalds 	router_recurse(router_a, router_b, 2);
1551da177e4SLinus Torvalds 
156a20ebc04SThomas Bogendoerfer 	return LOCAL_DISTANCE + router_distance;
1571da177e4SLinus Torvalds }
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds static void __init init_topology_matrix(void)
1601da177e4SLinus Torvalds {
1614bf841ebSThomas Bogendoerfer 	nasid_t row, col;
1621da177e4SLinus Torvalds 
163c80b4896SThomas Bogendoerfer 	for (row = 0; row < MAX_NUMNODES; row++)
164c80b4896SThomas Bogendoerfer 		for (col = 0; col < MAX_NUMNODES; col++)
1651da177e4SLinus Torvalds 			__node_distances[row][col] = -1;
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds 	for_each_online_node(row) {
1681da177e4SLinus Torvalds 		for_each_online_node(col) {
1691da177e4SLinus Torvalds 			__node_distances[row][col] =
1704bf841ebSThomas Bogendoerfer 				compute_node_distance(row, col);
1711da177e4SLinus Torvalds 		}
1721da177e4SLinus Torvalds 	}
1731da177e4SLinus Torvalds }
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds static void __init dump_topology(void)
1761da177e4SLinus Torvalds {
1771da177e4SLinus Torvalds 	nasid_t nasid;
1781da177e4SLinus Torvalds 	lboard_t *brd, *dest_brd;
1791da177e4SLinus Torvalds 	int port;
1801da177e4SLinus Torvalds 	int router_num = 0;
1811da177e4SLinus Torvalds 	klrou_t *router;
1824bf841ebSThomas Bogendoerfer 	nasid_t row, col;
1831da177e4SLinus Torvalds 
184ab68280eSThomas Bogendoerfer 	pr_info("************** Topology ********************\n");
1851da177e4SLinus Torvalds 
186ab68280eSThomas Bogendoerfer 	pr_info("    ");
1871da177e4SLinus Torvalds 	for_each_online_node(col)
188ab68280eSThomas Bogendoerfer 		pr_cont("%02d ", col);
189ab68280eSThomas Bogendoerfer 	pr_cont("\n");
1901da177e4SLinus Torvalds 	for_each_online_node(row) {
191ab68280eSThomas Bogendoerfer 		pr_info("%02d  ", row);
1921da177e4SLinus Torvalds 		for_each_online_node(col)
193ab68280eSThomas Bogendoerfer 			pr_cont("%2d ", node_distance(row, col));
194ab68280eSThomas Bogendoerfer 		pr_cont("\n");
1951da177e4SLinus Torvalds 	}
1961da177e4SLinus Torvalds 
1974bf841ebSThomas Bogendoerfer 	for_each_online_node(nasid) {
1981da177e4SLinus Torvalds 		brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
1991da177e4SLinus Torvalds 					KLTYPE_ROUTER);
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds 		if (!brd)
2021da177e4SLinus Torvalds 			continue;
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds 		do {
2051da177e4SLinus Torvalds 			if (brd->brd_flags & DUPLICATE_BOARD)
2061da177e4SLinus Torvalds 				continue;
207ab68280eSThomas Bogendoerfer 			pr_cont("Router %d:", router_num);
2081da177e4SLinus Torvalds 			router_num++;
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds 			router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds 			for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
2131da177e4SLinus Torvalds 				if (router->rou_port[port].port_nasid == INVALID_NASID)
2141da177e4SLinus Torvalds 					continue;
2151da177e4SLinus Torvalds 
2161da177e4SLinus Torvalds 				dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
2171da177e4SLinus Torvalds 					router->rou_port[port].port_nasid,
2181da177e4SLinus Torvalds 					router->rou_port[port].port_offset);
2191da177e4SLinus Torvalds 
2201da177e4SLinus Torvalds 				if (dest_brd->brd_type == KLTYPE_IP27)
221ab68280eSThomas Bogendoerfer 					pr_cont(" %d", dest_brd->brd_nasid);
2221da177e4SLinus Torvalds 				if (dest_brd->brd_type == KLTYPE_ROUTER)
223ab68280eSThomas Bogendoerfer 					pr_cont(" r");
2241da177e4SLinus Torvalds 			}
225ab68280eSThomas Bogendoerfer 			pr_cont("\n");
2261da177e4SLinus Torvalds 
2271da177e4SLinus Torvalds 		} while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
2281da177e4SLinus Torvalds 	}
2291da177e4SLinus Torvalds }
2301da177e4SLinus Torvalds 
2314bf841ebSThomas Bogendoerfer static unsigned long __init slot_getbasepfn(nasid_t nasid, int slot)
2321da177e4SLinus Torvalds {
233fc0460d0SRalf Baechle 	return ((unsigned long)nasid << PFN_NASIDSHFT) | (slot << SLOT_PFNSHIFT);
2341da177e4SLinus Torvalds }
2351da177e4SLinus Torvalds 
2364bf841ebSThomas Bogendoerfer static unsigned long __init slot_psize_compute(nasid_t nasid, int slot)
2371da177e4SLinus Torvalds {
2381da177e4SLinus Torvalds 	lboard_t *brd;
2391da177e4SLinus Torvalds 	klmembnk_t *banks;
2401da177e4SLinus Torvalds 	unsigned long size;
2411da177e4SLinus Torvalds 
2421da177e4SLinus Torvalds 	/* Find the node board */
2431da177e4SLinus Torvalds 	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27);
2441da177e4SLinus Torvalds 	if (!brd)
2451da177e4SLinus Torvalds 		return 0;
2461da177e4SLinus Torvalds 
2471da177e4SLinus Torvalds 	/* Get the memory bank structure */
2481da177e4SLinus Torvalds 	banks = (klmembnk_t *) find_first_component(brd, KLSTRUCT_MEMBNK);
2491da177e4SLinus Torvalds 	if (!banks)
2501da177e4SLinus Torvalds 		return 0;
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds 	/* Size in _Megabytes_ */
2531da177e4SLinus Torvalds 	size = (unsigned long)banks->membnk_bnksz[slot/4];
2541da177e4SLinus Torvalds 
2551da177e4SLinus Torvalds 	/* hack for 128 dimm banks */
2561da177e4SLinus Torvalds 	if (size <= 128) {
2571da177e4SLinus Torvalds 		if (slot % 4 == 0) {
2581da177e4SLinus Torvalds 			size <<= 20;		/* size in bytes */
259635c9907SRalf Baechle 			return size >> PAGE_SHIFT;
2601da177e4SLinus Torvalds 		} else
2611da177e4SLinus Torvalds 			return 0;
2621da177e4SLinus Torvalds 	} else {
2631da177e4SLinus Torvalds 		size /= 4;
2641da177e4SLinus Torvalds 		size <<= 20;
2651da177e4SLinus Torvalds 		return size >> PAGE_SHIFT;
2661da177e4SLinus Torvalds 	}
2671da177e4SLinus Torvalds }
2681da177e4SLinus Torvalds 
2691da177e4SLinus Torvalds static void __init mlreset(void)
2701da177e4SLinus Torvalds {
271524c4e1fSThomas Bogendoerfer 	u64 region_mask;
2724bf841ebSThomas Bogendoerfer 	nasid_t nasid;
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds 	master_nasid = get_nasid();
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds 	/*
2771da177e4SLinus Torvalds 	 * Probe for all CPUs - this creates the cpumask and sets up the
2781da177e4SLinus Torvalds 	 * mapping tables.  We need to do this as early as possible.
2791da177e4SLinus Torvalds 	 */
2801da177e4SLinus Torvalds #ifdef CONFIG_SMP
2811da177e4SLinus Torvalds 	cpu_node_probe();
2821da177e4SLinus Torvalds #endif
2831da177e4SLinus Torvalds 
2841da177e4SLinus Torvalds 	init_topology_matrix();
2851da177e4SLinus Torvalds 	dump_topology();
2861da177e4SLinus Torvalds 
287524c4e1fSThomas Bogendoerfer 	region_mask = gen_region_mask();
2881da177e4SLinus Torvalds 
2891da177e4SLinus Torvalds 	setup_replication_mask();
2901da177e4SLinus Torvalds 
2911da177e4SLinus Torvalds 	/*
2921da177e4SLinus Torvalds 	 * Set all nodes' calias sizes to 8k
2931da177e4SLinus Torvalds 	 */
2944bf841ebSThomas Bogendoerfer 	for_each_online_node(nasid) {
2951da177e4SLinus Torvalds 		/*
2961da177e4SLinus Torvalds 		 * Always have node 0 in the region mask, otherwise
2971da177e4SLinus Torvalds 		 * CALIAS accesses get exceptions since the hub
2981da177e4SLinus Torvalds 		 * thinks it is a node 0 address.
2991da177e4SLinus Torvalds 		 */
3001da177e4SLinus Torvalds 		REMOTE_HUB_S(nasid, PI_REGION_PRESENT, (region_mask | 1));
3011da177e4SLinus Torvalds 		REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_0);
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds #ifdef LATER
3041da177e4SLinus Torvalds 		/*
3051da177e4SLinus Torvalds 		 * Set up all hubs to have a big window pointing at
3061da177e4SLinus Torvalds 		 * widget 0. Memory mode, widget 0, offset 0
3071da177e4SLinus Torvalds 		 */
3081da177e4SLinus Torvalds 		REMOTE_HUB_S(nasid, IIO_ITTE(SWIN0_BIGWIN),
3091da177e4SLinus Torvalds 			((HUB_PIO_MAP_TO_MEM << IIO_ITTE_IOSP_SHIFT) |
3101da177e4SLinus Torvalds 			(0 << IIO_ITTE_WIDGET_SHIFT)));
3111da177e4SLinus Torvalds #endif
3121da177e4SLinus Torvalds 	}
3131da177e4SLinus Torvalds }
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds static void __init szmem(void)
3161da177e4SLinus Torvalds {
317fc0460d0SRalf Baechle 	unsigned long slot_psize, slot0sz = 0, nodebytes;	/* Hack to detect problem configs */
3182bf8ec2dSThomas Bogendoerfer 	int slot;
3194bf841ebSThomas Bogendoerfer 	nasid_t node;
3201da177e4SLinus Torvalds 
3211da177e4SLinus Torvalds 	for_each_online_node(node) {
3222bf8ec2dSThomas Bogendoerfer 		nodebytes = 0;
3231da177e4SLinus Torvalds 		for (slot = 0; slot < MAX_MEM_SLOTS; slot++) {
3241da177e4SLinus Torvalds 			slot_psize = slot_psize_compute(node, slot);
3251da177e4SLinus Torvalds 			if (slot == 0)
3261da177e4SLinus Torvalds 				slot0sz = slot_psize;
3271da177e4SLinus Torvalds 			/*
3281da177e4SLinus Torvalds 			 * We need to refine the hack when we have replicated
3291da177e4SLinus Torvalds 			 * kernel text.
3301da177e4SLinus Torvalds 			 */
3311da177e4SLinus Torvalds 			nodebytes += (1LL << SLOT_SHIFT);
3322bf8ec2dSThomas Bogendoerfer 
3332bf8ec2dSThomas Bogendoerfer 			if (!slot_psize)
3342bf8ec2dSThomas Bogendoerfer 				continue;
3352bf8ec2dSThomas Bogendoerfer 
3361da177e4SLinus Torvalds 			if ((nodebytes >> PAGE_SHIFT) * (sizeof(struct page)) >
3372bf8ec2dSThomas Bogendoerfer 						(slot0sz << PAGE_SHIFT)) {
338ab68280eSThomas Bogendoerfer 				pr_info("Ignoring slot %d onwards on node %d\n",
3391da177e4SLinus Torvalds 								slot, node);
3401da177e4SLinus Torvalds 				slot = MAX_MEM_SLOTS;
3411da177e4SLinus Torvalds 				continue;
3421da177e4SLinus Torvalds 			}
3439d15ffc8STejun Heo 			memblock_add_node(PFN_PHYS(slot_getbasepfn(node, slot)),
344952eea9bSDavid Hildenbrand 					  PFN_PHYS(slot_psize), node,
345952eea9bSDavid Hildenbrand 					  MEMBLOCK_NONE);
3461da177e4SLinus Torvalds 		}
3471da177e4SLinus Torvalds 	}
3481da177e4SLinus Torvalds }
3491da177e4SLinus Torvalds 
3504bf841ebSThomas Bogendoerfer static void __init node_mem_init(nasid_t node)
3511da177e4SLinus Torvalds {
352fc0460d0SRalf Baechle 	unsigned long slot_firstpfn = slot_getbasepfn(node, 0);
353fc0460d0SRalf Baechle 	unsigned long slot_freepfn = node_getfirstfree(node);
354fc0460d0SRalf Baechle 	unsigned long start_pfn, end_pfn;
3552bf8ec2dSThomas Bogendoerfer 
3562bf8ec2dSThomas Bogendoerfer 	get_pfn_range_for_nid(node, &start_pfn, &end_pfn);
3571da177e4SLinus Torvalds 
3581da177e4SLinus Torvalds 	/*
3591da177e4SLinus Torvalds 	 * Allocate the node data structures on the node first.
3601da177e4SLinus Torvalds 	 */
3611da177e4SLinus Torvalds 	__node_data[node] = __va(slot_freepfn << PAGE_SHIFT);
36293180cecSMinchan Kim 	memset(__node_data[node], 0, PAGE_SIZE);
363*bc5c8ad3SMike Rapoport (Microsoft) 	node_data[node] = &__node_data[node]->pglist;
3641da177e4SLinus Torvalds 
3652bf8ec2dSThomas Bogendoerfer 	NODE_DATA(node)->node_start_pfn = start_pfn;
3662bf8ec2dSThomas Bogendoerfer 	NODE_DATA(node)->node_spanned_pages = end_pfn - start_pfn;
3671da177e4SLinus Torvalds 
3688dd92891SRusty Russell 	cpumask_clear(&hub_data(node)->h_cpus);
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds 	slot_freepfn += PFN_UP(sizeof(struct pglist_data) +
3711da177e4SLinus Torvalds 			       sizeof(struct hub_data));
3721da177e4SLinus Torvalds 
373bcec54bfSMike Rapoport 	memblock_reserve(slot_firstpfn << PAGE_SHIFT,
374bcec54bfSMike Rapoport 			 ((slot_freepfn - slot_firstpfn) << PAGE_SHIFT));
3751da177e4SLinus Torvalds }
3761da177e4SLinus Torvalds 
3771da177e4SLinus Torvalds /*
3781da177e4SLinus Torvalds  * A node with nothing.	 We use it to avoid any special casing in
37929c337a0SRusty Russell  * cpumask_of_node
3801da177e4SLinus Torvalds  */
3811da177e4SLinus Torvalds static struct node_data null_node = {
3821da177e4SLinus Torvalds 	.hub = {
3831da177e4SLinus Torvalds 		.h_cpus = CPU_MASK_NONE
3841da177e4SLinus Torvalds 	}
3851da177e4SLinus Torvalds };
3861da177e4SLinus Torvalds 
3871da177e4SLinus Torvalds /*
3881da177e4SLinus Torvalds  * Currently, the intranode memory hole support assumes that each slot
3891da177e4SLinus Torvalds  * contains at least 32 MBytes of memory. We assume all bootmem data
3901da177e4SLinus Torvalds  * fits on the first slot.
3911da177e4SLinus Torvalds  */
3921da177e4SLinus Torvalds void __init prom_meminit(void)
3931da177e4SLinus Torvalds {
3944bf841ebSThomas Bogendoerfer 	nasid_t node;
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds 	mlreset();
3971da177e4SLinus Torvalds 	szmem();
3981229ace4SPaul Burton 	max_low_pfn = PHYS_PFN(memblock_end_of_DRAM());
3991da177e4SLinus Torvalds 
400c80b4896SThomas Bogendoerfer 	for (node = 0; node < MAX_NUMNODES; node++) {
4011da177e4SLinus Torvalds 		if (node_online(node)) {
4021da177e4SLinus Torvalds 			node_mem_init(node);
4031da177e4SLinus Torvalds 			continue;
4041da177e4SLinus Torvalds 		}
4051da177e4SLinus Torvalds 		__node_data[node] = &null_node;
4061da177e4SLinus Torvalds 	}
4071da177e4SLinus Torvalds }
4081da177e4SLinus Torvalds 
40931605922SJiang Liu extern void setup_zero_pages(void);
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds void __init paging_init(void)
4121da177e4SLinus Torvalds {
413f06a9684SChristoph Lameter 	unsigned long zones_size[MAX_NR_ZONES] = {0, };
4141da177e4SLinus Torvalds 
4151da177e4SLinus Torvalds 	pagetable_init();
4162bf8ec2dSThomas Bogendoerfer 	zones_size[ZONE_NORMAL] = max_low_pfn;
4179691a071SMike Rapoport 	free_area_init(zones_size);
4181da177e4SLinus Torvalds }
4191da177e4SLinus Torvalds 
4201da177e4SLinus Torvalds void __init mem_init(void)
4211da177e4SLinus Torvalds {
4221132137eSJiang Liu 	high_memory = (void *) __va(get_num_physpages() << PAGE_SHIFT);
423c6ffc5caSMike Rapoport 	memblock_free_all();
42431605922SJiang Liu 	setup_zero_pages();	/* This comes from node 0 */
4251da177e4SLinus Torvalds }
426