# BRCM_VERSION=3
[bcm963xx.git] / kernel / linux / arch / mips / sgi-ip27 / ip27-memory.c
1 /*
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
4  * for more details.
5  *
6  * Copyright (C) 2000 by Ralf Baechle
7  * Copyright (C) 2000 by Silicon Graphics, Inc.
8  * Copyright (C) 2004 by Christoph Hellwig
9  *
10  * On SGI IP27 the ARC memory configuration data is completly bogus but
11  * alternate easier to use mechanisms are available.
12  */
13 #include <linux/init.h>
14 #include <linux/kernel.h>
15 #include <linux/mm.h>
16 #include <linux/mmzone.h>
17 #include <linux/module.h>
18 #include <linux/swap.h>
19 #include <linux/bootmem.h>
20 #include <asm/page.h>
21 #include <asm/sections.h>
22
23 #include <asm/sn/arch.h>
24 #include <asm/sn/hub.h>
25 #include <asm/sn/klconfig.h>
26 #include <asm/sn/sn_private.h>
27
28
29 #define PFN_UP(x)               (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
30
31 #define SLOT_PFNSHIFT           (SLOT_SHIFT - PAGE_SHIFT)
32 #define PFN_NASIDSHFT           (NASID_SHFT - PAGE_SHIFT)
33
34 #define SLOT_IGNORED            0xffff
35
36 static short __initdata slot_lastfilled_cache[MAX_COMPACT_NODES];
37 static unsigned short __initdata slot_psize_cache[MAX_COMPACT_NODES][MAX_MEM_SLOTS];
38 static struct bootmem_data __initdata plat_node_bdata[MAX_COMPACT_NODES];
39
40 struct pglist_data *node_data[MAX_COMPACT_NODES];
41 struct hub_data *hub_data[MAX_COMPACT_NODES];
42
43 EXPORT_SYMBOL(node_data);
44
45 static pfn_t __init slot_getbasepfn(cnodeid_t cnode, int slot)
46 {
47         nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode);
48
49         return ((pfn_t)nasid << PFN_NASIDSHFT) | (slot << SLOT_PFNSHIFT);
50 }
51
52 /*
53  * Return the number of pages of memory provided by the given slot
54  * on the specified node.
55  */
56 static pfn_t __init slot_getsize(cnodeid_t node, int slot)
57 {
58         return (pfn_t) slot_psize_cache[node][slot];
59 }
60
61 /*
62  * Return highest slot filled
63  */
64 static int __init node_getlastslot(cnodeid_t node)
65 {
66         return (int) slot_lastfilled_cache[node];
67 }
68
69 /*
70  * Return the pfn of the last free page of memory on a node.
71  */
72 static pfn_t __init node_getmaxclick(cnodeid_t node)
73 {
74         pfn_t   slot_psize;
75         int     slot;
76
77         /*
78          * Start at the top slot. When we find a slot with memory in it,
79          * that's the winner.
80          */
81         for (slot = (MAX_MEM_SLOTS - 1); slot >= 0; slot--) {
82                 if ((slot_psize = slot_getsize(node, slot))) {
83                         if (slot_psize == SLOT_IGNORED)
84                                 continue;
85                         /* Return the basepfn + the slot size, minus 1. */
86                         return slot_getbasepfn(node, slot) + slot_psize - 1;
87                 }
88         }
89
90         /*
91          * If there's no memory on the node, return 0. This is likely
92          * to cause problems.
93          */
94         return 0;
95 }
96
97 static pfn_t __init slot_psize_compute(cnodeid_t node, int slot)
98 {
99         nasid_t nasid;
100         lboard_t *brd;
101         klmembnk_t *banks;
102         unsigned long size;
103
104         nasid = COMPACT_TO_NASID_NODEID(node);
105         /* Find the node board */
106         brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27);
107         if (!brd)
108                 return 0;
109
110         /* Get the memory bank structure */
111         banks = (klmembnk_t *) find_first_component(brd, KLSTRUCT_MEMBNK);
112         if (!banks)
113                 return 0;
114
115         /* Size in _Megabytes_ */
116         size = (unsigned long)banks->membnk_bnksz[slot/4];
117
118         /* hack for 128 dimm banks */
119         if (size <= 128) {
120                 if (slot % 4 == 0) {
121                         size <<= 20;            /* size in bytes */
122                         return(size >> PAGE_SHIFT);
123                 } else
124                         return 0;
125         } else {
126                 size /= 4;
127                 size <<= 20;
128                 return size >> PAGE_SHIFT;
129         }
130 }
131
132 static void __init szmem(void)
133 {
134         pfn_t slot_psize, slot0sz = 0, nodebytes;       /* Hack to detect problem configs */
135         int slot, ignore;
136         cnodeid_t node;
137
138         num_physpages = 0;
139
140         for (node = 0; node < numnodes; node++) {
141                 ignore = nodebytes = 0;
142                 for (slot = 0; slot < MAX_MEM_SLOTS; slot++) {
143                         slot_psize = slot_psize_compute(node, slot);
144                         if (slot == 0)
145                                 slot0sz = slot_psize;
146                         /*
147                          * We need to refine the hack when we have replicated
148                          * kernel text.
149                          */
150                         nodebytes += (1LL << SLOT_SHIFT);
151                         if ((nodebytes >> PAGE_SHIFT) * (sizeof(struct page)) >
152                                                 (slot0sz << PAGE_SHIFT))
153                                 ignore = 1;
154                         if (ignore && slot_psize) {
155                                 printk("Ignoring slot %d onwards on node %d\n",
156                                                                 slot, node);
157                                 slot_psize_cache[node][slot] = SLOT_IGNORED;
158                                 slot = MAX_MEM_SLOTS;
159                                 continue;
160                         }
161                         num_physpages += slot_psize;
162                         slot_psize_cache[node][slot] =
163                                         (unsigned short) slot_psize;
164                         if (slot_psize)
165                                 slot_lastfilled_cache[node] = slot;
166                 }
167         }
168 }
169
170 /*
171  * Currently, the intranode memory hole support assumes that each slot
172  * contains at least 32 MBytes of memory. We assume all bootmem data
173  * fits on the first slot.
174  */
175 void __init prom_meminit(void)
176 {
177         cnodeid_t node;
178
179         mlreset();
180         szmem();
181
182         for (node = 0; node < numnodes; node++) {
183                 pfn_t slot_firstpfn = slot_getbasepfn(node, 0);
184                 pfn_t slot_lastpfn = slot_firstpfn + slot_getsize(node, 0);
185                 pfn_t slot_freepfn = node_getfirstfree(node);
186                 unsigned long bootmap_size;
187
188                 /*
189                  * Allocate the node data structures on the node first.
190                  */
191                 node_data[node] = __va(slot_freepfn << PAGE_SHIFT);
192                 node_data[node]->bdata = &plat_node_bdata[node];
193
194                 hub_data[node] = (struct hub_data *)(node_data[node] + 1);
195
196                 cpus_clear(hub_data[node]->h_cpus);
197
198                 slot_freepfn += PFN_UP(sizeof(struct pglist_data) +
199                                        sizeof(struct hub_data));
200         
201                 bootmap_size = init_bootmem_node(NODE_DATA(node), slot_freepfn,
202                                                 slot_firstpfn, slot_lastpfn);
203                 free_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT,
204                                 (slot_lastpfn - slot_firstpfn) << PAGE_SHIFT);
205                 reserve_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT,
206                   ((slot_freepfn - slot_firstpfn) << PAGE_SHIFT) + bootmap_size);
207         }
208 }
209
210 unsigned long __init prom_free_prom_memory(void)
211 {
212         /* We got nothing to free here ...  */
213         return 0;
214 }
215
216 extern void pagetable_init(void);
217 extern unsigned long setup_zero_pages(void);
218
219 void __init paging_init(void)
220 {
221         unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
222         unsigned node;
223
224         pagetable_init();
225
226         for (node = 0; node < numnodes; node++) {
227                 pfn_t start_pfn = slot_getbasepfn(node, 0);
228                 pfn_t end_pfn = node_getmaxclick(node) + 1;
229
230                 zones_size[ZONE_DMA] = end_pfn - start_pfn;
231                 free_area_init_node(node, NODE_DATA(node), NULL,
232                                 zones_size, start_pfn, NULL);
233
234                 if (end_pfn > max_low_pfn)
235                         max_low_pfn = end_pfn;
236         }
237 }
238
239 void __init mem_init(void)
240 {
241         unsigned long codesize, datasize, initsize, tmp;
242         unsigned node;
243
244         high_memory = (void *) __va(num_physpages << PAGE_SHIFT);
245
246         for (node = 0; node < numnodes; node++) {
247                 unsigned slot, numslots;
248                 struct page *end, *p;
249         
250                 /*
251                  * This will free up the bootmem, ie, slot 0 memory.
252                  */
253                 totalram_pages += free_all_bootmem_node(NODE_DATA(node));
254
255                 /*
256                  * We need to manually do the other slots.
257                  */
258                 numslots = node_getlastslot(node);
259                 for (slot = 1; slot <= numslots; slot++) {
260                         p = NODE_DATA(node)->node_mem_map +
261                                 (slot_getbasepfn(node, slot) -
262                                  slot_getbasepfn(node, 0));
263
264                         /*
265                          * Free valid memory in current slot.
266                          */
267                         for (end = p + slot_getsize(node, slot); p < end; p++) {
268                                 /* if (!page_is_ram(pgnr)) continue; */
269                                 /* commented out until page_is_ram works */
270                                 ClearPageReserved(p);
271                                 set_page_count(p, 1);
272                                 __free_page(p);
273                                 totalram_pages++;
274                         }
275                 }
276         }
277
278         totalram_pages -= setup_zero_pages();   /* This comes from node 0 */
279
280         codesize =  (unsigned long) &_etext - (unsigned long) &_text;
281         datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
282         initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
283
284         tmp = nr_free_pages();
285         printk(KERN_INFO "Memory: %luk/%luk available (%ldk kernel code, "
286                "%ldk reserved, %ldk data, %ldk init, %ldk highmem)\n",
287                tmp << (PAGE_SHIFT-10),
288                num_physpages << (PAGE_SHIFT-10),
289                codesize >> 10,
290                (num_physpages - tmp) << (PAGE_SHIFT-10),
291                datasize >> 10,
292                initsize >> 10,
293                (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)));
294 }