2 * Copyright (c) 2000, 2003 Silicon Graphics, Inc. All rights reserved.
3 * Copyright (c) 2001 Intel Corp.
4 * Copyright (c) 2001 Tony Luck <tony.luck@intel.com>
5 * Copyright (c) 2002 NEC Corp.
6 * Copyright (c) 2002 Kimio Suganuma <k-suganuma@da.jp.nec.com>
10 * Platform initialization for Discontig Memory
13 #include <linux/kernel.h>
15 #include <linux/bootmem.h>
16 #include <linux/mmzone.h>
17 #include <linux/acpi.h>
18 #include <linux/efi.h>
19 #include <asm/pgalloc.h>
24 * Round an address upward to the next multiple of GRANULE size.
26 #define GRANULEROUNDDOWN(n) ((n) & ~(IA64_GRANULE_SIZE-1))
27 #define GRANULEROUNDUP(n) (((n)+IA64_GRANULE_SIZE-1) & ~(IA64_GRANULE_SIZE-1))
30 * Used to locate BOOT_DATA prior to initializing the node data area.
32 #define BOOT_NODE_DATA(node) pg_data_ptr[node]
35 * To prevent cache aliasing effects, align per-node structures so that they
36 * start at addresses that are strided by node number.
38 #define NODEDATA_ALIGN(addr, node) ((((addr) + 1024*1024-1) & ~(1024*1024-1)) + (node)*PAGE_SIZE)
41 static struct ia64_node_data *boot_node_data[NR_NODES] __initdata;
42 static pg_data_t *pg_data_ptr[NR_NODES] __initdata;
43 static bootmem_data_t bdata[NR_NODES] __initdata;
44 static unsigned long boot_pernode[NR_NODES] __initdata;
45 static unsigned long boot_pernodesize[NR_NODES] __initdata;
47 extern int filter_rsvd_memory (unsigned long start, unsigned long end, void *arg);
48 extern struct cpuinfo_ia64 *_cpu_data[NR_CPUS];
53 * We allocate one of the bootmem_data_t structs for each piece of memory
54 * that we wish to treat as a contiguous block. Each such block must start
55 * on a GRANULE boundary. Multiple banks per node is not supported.
56 * (Note: on SN2, all memory on a node is trated as a single bank.
57 * Holes within the bank are supported. This works because memory
58 * from different banks is not interleaved. The bootmap bitmap
59 * for the node is somewhat large but not too large).
62 build_maps(unsigned long start, unsigned long end, int node)
65 unsigned long cstart, epfn;
68 epfn = GRANULEROUNDUP(__pa(end)) >> PAGE_SHIFT;
69 cstart = GRANULEROUNDDOWN(__pa(start));
71 if (!bdp->node_low_pfn) {
72 bdp->node_boot_start = cstart;
73 bdp->node_low_pfn = epfn;
75 bdp->node_boot_start = min(cstart, bdp->node_boot_start);
76 bdp->node_low_pfn = max(epfn, bdp->node_low_pfn);
79 min_low_pfn = min(min_low_pfn, bdp->node_boot_start>>PAGE_SHIFT);
80 max_low_pfn = max(max_low_pfn, bdp->node_low_pfn);
87 * Count the number of cpus on the node
94 for (cpu=0; cpu < NR_CPUS; cpu++)
95 if (node == node_cpuid[cpu].nid)
102 * Find space on each node for the bootmem map & other per-node data structures.
104 * Called by efi_memmap_walk to find boot memory on each node. Note that
105 * only blocks that are free are passed to this routine (currently filtered by
106 * free_available_memory).
109 find_pernode_space(unsigned long start, unsigned long end, int node)
111 unsigned long mapsize, pages, epfn, map=0, cpu, cpus;
112 unsigned long pernodesize=0, pernode;
113 unsigned long cpu_data, mmu_gathers;
114 unsigned long pstart, length;
117 pstart = __pa(start);
118 length = end - start;
119 epfn = (pstart + length) >> PAGE_SHIFT;
122 if (pstart < bdp->node_boot_start || epfn > bdp->node_low_pfn)
125 if (!boot_pernode[node]) {
126 cpus = count_cpus(node);
127 pernodesize += PAGE_ALIGN(sizeof(struct cpuinfo_ia64)) * cpus;
128 pernodesize += L1_CACHE_ALIGN(sizeof(mmu_gather_t)) * cpus;
129 pernodesize += L1_CACHE_ALIGN(sizeof(pg_data_t));
130 pernodesize += L1_CACHE_ALIGN(sizeof(struct ia64_node_data));
131 pernodesize = PAGE_ALIGN(pernodesize);
132 pernode = NODEDATA_ALIGN(pstart, node);
134 if (pstart + length > (pernode + pernodesize)) {
135 boot_pernode[node] = pernode;
136 boot_pernodesize[node] = pernodesize;
137 memset(__va(pernode), 0, pernodesize);
140 pernode += PAGE_ALIGN(sizeof(struct cpuinfo_ia64)) * cpus;
142 mmu_gathers = pernode;
143 pernode += L1_CACHE_ALIGN(sizeof(mmu_gather_t)) * cpus;
145 pg_data_ptr[node] = __va(pernode);
146 pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));
148 boot_node_data[node] = __va(pernode);
149 pernode += L1_CACHE_ALIGN(sizeof(struct ia64_node_data));
151 pg_data_ptr[node]->bdata = &bdata[node];
152 pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));
154 for (cpu=0; cpu < NR_CPUS; cpu++) {
155 if (node == node_cpuid[cpu].nid) {
156 _cpu_data[cpu] = __va(cpu_data);
157 _cpu_data[cpu]->node_data = boot_node_data[node];
158 _cpu_data[cpu]->nodeid = node;
159 _cpu_data[cpu]->mmu_gathers = __va(mmu_gathers);
160 cpu_data += PAGE_ALIGN(sizeof(struct cpuinfo_ia64));
161 mmu_gathers += L1_CACHE_ALIGN(sizeof(mmu_gather_t));
168 pernode = boot_pernode[node];
169 pernodesize = boot_pernodesize[node];
170 if (pernode && !bdp->node_bootmem_map) {
171 pages = bdp->node_low_pfn - (bdp->node_boot_start>>PAGE_SHIFT);
172 mapsize = bootmem_bootmap_pages(pages) << PAGE_SHIFT;
174 if (pernode - pstart > mapsize)
176 else if (pstart + length - pernode - pernodesize > mapsize)
177 map = pernode + pernodesize;
181 BOOT_NODE_DATA(node),
183 bdp->node_boot_start>>PAGE_SHIFT,
194 * Free available memory to the bootmem allocator.
196 * Note that only blocks that are free are passed to this routine (currently
197 * filtered by free_available_memory).
201 discontig_free_bootmem_node(unsigned long start, unsigned long end, int node)
203 free_bootmem_node(BOOT_NODE_DATA(node), __pa(start), end - start);
210 * Reserve the space used by the bootmem maps.
213 discontig_reserve_bootmem(void)
216 unsigned long base, size, pages;
219 for (node = 0; node < numnodes; node++) {
220 bdp = BOOT_NODE_DATA(node)->bdata;
222 pages = bdp->node_low_pfn - (bdp->node_boot_start>>PAGE_SHIFT);
223 size = bootmem_bootmap_pages(pages) << PAGE_SHIFT;
224 base = __pa(bdp->node_bootmem_map);
225 reserve_bootmem_node(BOOT_NODE_DATA(node), base, size);
227 size = boot_pernodesize[node];
228 base = __pa(boot_pernode[node]);
229 reserve_bootmem_node(BOOT_NODE_DATA(node), base, size);
234 * Initialize per-node data
236 * Finish setting up the node data for this node, then copy it to the other nodes.
240 initialize_pernode_data(void)
244 memcpy(boot_node_data[0]->pg_data_ptrs, pg_data_ptr, sizeof(pg_data_ptr));
245 memcpy(boot_node_data[0]->node_data_ptrs, boot_node_data, sizeof(boot_node_data));
247 for (node=1; node < numnodes; node++) {
248 memcpy(boot_node_data[node], boot_node_data[0], sizeof(struct ia64_node_data));
249 boot_node_data[node]->node = node;
252 for (cpu=0; cpu < NR_CPUS; cpu++) {
253 node = node_cpuid[cpu].nid;
254 _cpu_data[cpu]->node_data = boot_node_data[node];
255 _cpu_data[cpu]->nodeid = node;
261 * Called early in boot to setup the boot memory allocator, and to
262 * allocate the node-local pg_data & node-directory data structures..
265 discontig_mem_init(void)
268 printk("node info missing!\n");
275 efi_memmap_walk(filter_rsvd_memory, build_maps);
276 efi_memmap_walk(filter_rsvd_memory, find_pernode_space);
277 efi_memmap_walk(filter_rsvd_memory, discontig_free_bootmem_node);
279 discontig_reserve_bootmem();
280 initialize_pernode_data();