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
6 * Copyright (C) 2000 by Ralf Baechle
7 * Copyright (C) 2000 by Silicon Graphics, Inc.
9 * On SGI IP27 the ARC memory configuration data is completly bogus but
10 * alternate easier to use mechanisms are available.
12 #include <linux/init.h>
13 #include <linux/config.h>
14 #include <linux/kernel.h>
16 #include <linux/bootmem.h>
17 #include <linux/swap.h>
20 #include <asm/bootinfo.h>
21 #include <asm/addrspace.h>
22 #include <asm/pgtable.h>
23 #include <asm/sn/types.h>
24 #include <asm/sn/addrs.h>
25 #include <asm/sn/klconfig.h>
26 #include <asm/sn/arch.h>
27 #include <asm/mmzone.h>
30 extern pfn_t
node_getfirstfree(cnodeid_t cnode
);
32 #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
33 #define SLOT_IGNORED 0xffff
35 short slot_lastfilled_cache
[MAX_COMPACT_NODES
];
36 unsigned short slot_psize_cache
[MAX_COMPACT_NODES
][MAX_MEM_SLOTS
];
37 static pfn_t numpages
;
39 plat_pg_data_t
*plat_node_data
[MAX_COMPACT_NODES
];
40 bootmem_data_t plat_node_bdata
[MAX_COMPACT_NODES
];
44 printk("NUMA debug\n");
50 * Return the number of pages of memory provided by the given slot
51 * on the specified node.
53 pfn_t
slot_getsize(cnodeid_t node
, int slot
)
55 return (pfn_t
) slot_psize_cache
[node
][slot
];
59 * Return highest slot filled
61 int node_getlastslot(cnodeid_t node
)
63 return (int) slot_lastfilled_cache
[node
];
67 * Return the pfn of the last free page of memory on a node.
69 pfn_t
node_getmaxclick(cnodeid_t node
)
75 * Start at the top slot. When we find a slot with memory in it,
78 for (slot
= (node_getnumslots(node
) - 1); slot
>= 0; slot
--) {
79 if ((slot_psize
= slot_getsize(node
, slot
))) {
80 if (slot_psize
== SLOT_IGNORED
)
82 /* Return the basepfn + the slot size, minus 1. */
83 return slot_getbasepfn(node
, slot
) + slot_psize
- 1;
88 * If there's no memory on the node, return 0. This is likely
94 static pfn_t
slot_psize_compute(cnodeid_t node
, int slot
)
101 nasid
= COMPACT_TO_NASID_NODEID(node
);
102 /* Find the node board */
103 brd
= find_lboard((lboard_t
*)KL_CONFIG_INFO(nasid
), KLTYPE_IP27
);
107 /* Get the memory bank structure */
108 banks
= (klmembnk_t
*)find_first_component(brd
, KLSTRUCT_MEMBNK
);
112 /* Size in _Megabytes_ */
113 size
= (unsigned long)banks
->membnk_bnksz
[slot
/4];
115 /* hack for 128 dimm banks */
118 size
<<= 20; /* size in bytes */
119 return(size
>> PAGE_SHIFT
);
126 return(size
>> PAGE_SHIFT
);
130 pfn_t
szmem(pfn_t fpage
, pfn_t maxpmem
)
134 pfn_t num_pages
= 0, slot_psize
;
135 pfn_t slot0sz
= 0, nodebytes
; /* Hack to detect problem configs */
138 for (node
= 0; node
< numnodes
; node
++) {
139 numslots
= node_getnumslots(node
);
140 ignore
= nodebytes
= 0;
141 for (slot
= 0; slot
< numslots
; slot
++) {
142 slot_psize
= slot_psize_compute(node
, slot
);
143 if (slot
== 0) slot0sz
= slot_psize
;
145 * We need to refine the hack when we have replicated
148 nodebytes
+= SLOT_SIZE
;
149 if ((nodebytes
>> PAGE_SHIFT
) * (sizeof(struct page
)) >
150 (slot0sz
<< PAGE_SHIFT
))
152 if (ignore
&& slot_psize
) {
153 printk("Ignoring slot %d onwards on node %d\n",
155 slot_psize_cache
[node
][slot
] = SLOT_IGNORED
;
159 num_pages
+= slot_psize
;
160 slot_psize_cache
[node
][slot
] =
161 (unsigned short) slot_psize
;
163 slot_lastfilled_cache
[node
] = slot
;
167 return((maxpmem
> num_pages
) ? num_pages
: maxpmem
);
173 * Currently, the intranode memory hole support assumes that each slot
174 * contains at least 32 MBytes of memory. We assume all bootmem data
175 * fits on the first slot.
177 void __init
prom_meminit(void)
179 extern void mlreset(void);
181 pfn_t slot_firstpfn
, slot_lastpfn
, slot_freepfn
;
182 unsigned long bootmap_size
;
185 node_datasz
= PFN_UP(sizeof(plat_pg_data_t
));
187 numpages
= szmem(0, 0);
188 for (node
= (numnodes
- 1); node
>= 0; node
--) {
189 slot_firstpfn
= slot_getbasepfn(node
, 0);
190 slot_lastpfn
= slot_firstpfn
+ slot_getsize(node
, 0);
191 slot_freepfn
= node_getfirstfree(node
);
192 /* Foll line hack for non discontigmem; remove once discontigmem
193 * becomes the default. */
194 max_low_pfn
= (slot_lastpfn
- slot_firstpfn
);
197 * Allocate the node data structure on the node first.
199 plat_node_data
[node
] = (plat_pg_data_t
*)(__va(slot_freepfn \
201 NODE_DATA(node
)->bdata
= plat_node_bdata
+ node
;
202 slot_freepfn
+= node_datasz
;
203 bootmap_size
= init_bootmem_node(NODE_DATA(node
), slot_freepfn
,
204 slot_firstpfn
, slot_lastpfn
);
205 free_bootmem_node(NODE_DATA(node
), slot_firstpfn
<< PAGE_SHIFT
,
206 (slot_lastpfn
- slot_firstpfn
) << PAGE_SHIFT
);
207 reserve_bootmem_node(NODE_DATA(node
), slot_firstpfn
<< PAGE_SHIFT
,
208 ((slot_freepfn
- slot_firstpfn
) << PAGE_SHIFT
) + bootmap_size
);
210 printk("Total memory probed : 0x%lx pages\n", numpages
);
213 int __init
page_is_ram(unsigned long pagenr
)
219 prom_free_prom_memory (void)
221 /* We got nothing to free here ... */
224 #ifdef CONFIG_DISCONTIGMEM
226 static pfn_t pagenr
= 0;
228 void __init
paging_init(void)
231 unsigned long zones_size
[MAX_NR_ZONES
] = {0, 0, 0};
233 /* Initialize the entire pgd. */
234 pgd_init((unsigned long)swapper_pg_dir
);
235 pmd_init((unsigned long)invalid_pmd_table
, (unsigned long)invalid_pte_table
);
236 memset((void *)invalid_pte_table
, 0, sizeof(pte_t
) * PTRS_PER_PTE
);
237 pmd_init((unsigned long)empty_bad_pmd_table
, (unsigned long)empty_bad_page_table
);
238 memset((void *)empty_bad_page_table
, 0, sizeof(pte_t
) * PTRS_PER_PTE
);
240 for (node
= 0; node
< numnodes
; node
++) {
241 pfn_t start_pfn
= slot_getbasepfn(node
, 0);
242 pfn_t end_pfn
= node_getmaxclick(node
);
244 zones_size
[ZONE_DMA
] = end_pfn
+ 1 - start_pfn
;
245 free_area_init_node(node
, NODE_DATA(node
), 0, zones_size
,
246 start_pfn
<< PAGE_SHIFT
, 0);
247 if ((PLAT_NODE_DATA_STARTNR(node
) +
248 PLAT_NODE_DATA_SIZE(node
)) > pagenr
)
249 pagenr
= PLAT_NODE_DATA_STARTNR(node
) +
250 PLAT_NODE_DATA_SIZE(node
);
254 void __init
mem_init(void)
256 extern char _stext
, _etext
, _fdata
, _edata
;
257 extern char __init_begin
, __init_end
;
258 extern unsigned long totalram_pages
;
259 extern unsigned long setup_zero_pages(void);
262 unsigned long codesize
, datasize
, initsize
;
264 struct page
*pg
, *pslot
;
267 num_physpages
= numpages
; /* memory already sized by szmem */
268 max_mapnr
= pagenr
; /* already found during paging_init */
269 high_memory
= (void *) __va(max_mapnr
<< PAGE_SHIFT
);
271 for (nid
= 0; nid
< numnodes
; nid
++) {
274 * Hack till free_area_init_core() zeroes free_pages
276 for (tmp
= 0; tmp
< MAX_NR_ZONES
; tmp
++)
277 PLAT_NODE_DATA(nid
)->gendata
.node_zones
[tmp
].free_pages
=0;
279 * This will free up the bootmem, ie, slot 0 memory.
281 totalram_pages
+= free_all_bootmem_node(NODE_DATA(nid
));
284 * We need to manually do the other slots.
286 pg
= NODE_DATA(nid
)->node_mem_map
+ slot_getsize(nid
, 0);
287 pgnr
= PLAT_NODE_DATA_STARTNR(nid
) + slot_getsize(nid
, 0);
288 numslots
= node_getlastslot(nid
);
289 for (slot
= 1; slot
<= numslots
; slot
++) {
290 pslot
= NODE_DATA(nid
)->node_mem_map
+
291 slot_getbasepfn(nid
, slot
) - slot_getbasepfn(nid
, 0);
294 * Mark holes in previous slot. May also want to
295 * free up the pages that hold the memmap entries.
302 * Free valid memory in current slot.
304 pslot
+= slot_getsize(nid
, slot
);
306 if (!page_is_ram(pgnr
))
308 ClearPageReserved(pg
);
309 atomic_set(&pg
->count
, 1);
317 totalram_pages
-= setup_zero_pages(); /* This comes from node 0 */
319 codesize
= (unsigned long) &_etext
- (unsigned long) &_stext
;
320 datasize
= (unsigned long) &_edata
- (unsigned long) &_fdata
;
321 initsize
= (unsigned long) &__init_end
- (unsigned long) &__init_begin
;
323 tmp
= (unsigned long) nr_free_pages();
324 printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, "
325 "%ldk data, %ldk init)\n",
326 tmp
<< (PAGE_SHIFT
-10),
327 num_physpages
<< (PAGE_SHIFT
-10),
329 (num_physpages
- tmp
) << (PAGE_SHIFT
-10),
334 #endif /* CONFIG_DISCONTIGMEM */