ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / ia64 / sn / fakeprom / fpmem.c
1 /* 
2  *
3  * This file is subject to the terms and conditions of the GNU General Public
4  * License.  See the file "COPYING" in the main directory of this archive
5  * for more details.
6  *
7  * Copyright (C) 2000-2003 Silicon Graphics, Inc.  All rights reserved.
8  */
9
10
11
12 /*
13  * FPROM EFI memory descriptor build routines
14  *
15  *      - Routines to build the EFI memory descriptor map
16  *      - Should also be usable by the SGI prom to convert
17  *        klconfig to efi_memmap
18  */
19
20 #include <linux/config.h>
21 #include <linux/efi.h>
22 #include "fpmem.h"
23
24 /*
25  * args points to a layout in memory like this
26  *
27  *              32 bit          32 bit
28  *
29  *              numnodes        numcpus
30  *
31  *              16 bit   16 bit            32 bit
32  *              nasid0  cpuconf         membankdesc0
33  *              nasid1  cpuconf         membankdesc1
34  *                         .
35  *                         .
36  *                         .
37  *                         .
38  *                         .
39  */
40
41 sn_memmap_t     *sn_memmap ;
42 sn_config_t     *sn_config ;
43
44 /*
45  * There is a hole in the node 0 address space. Dont put it
46  * in the memory map
47  */
48 #define NODE0_HOLE_SIZE         (20*MB)
49 #define NODE0_HOLE_END          (4UL*GB)
50
51 #define MB                      (1024*1024)
52 #define GB                      (1024*MB)
53 #define KERNEL_SIZE             (4*MB)
54 #define PROMRESERVED_SIZE       (1*MB)
55
56 #ifdef SGI_SN2
57 #define PHYS_ADDRESS(_n, _x)            (((long)_n<<38) | (long)_x | 0x3000000000UL)
58 #define MD_BANK_SHFT 34
59 #endif
60
61 /*
62  * For SN, this may not take an arg and gets the numnodes from 
63  * the prom variable or by traversing klcfg or promcfg
64  */
65 int
66 GetNumNodes(void)
67 {
68         return sn_config->nodes;
69 }
70
71 int
72 GetNumCpus(void)
73 {
74         return sn_config->cpus;
75 }
76
77 /* For SN, get the index th nasid */
78
79 int
80 GetNasid(int index)
81 {
82         return sn_memmap[index].nasid ;
83 }
84
85 node_memmap_t
86 GetMemBankInfo(int index)
87 {
88         return sn_memmap[index].node_memmap ;
89 }
90
91 int
92 IsCpuPresent(int cnode, int cpu)
93 {
94         return  sn_memmap[cnode].cpuconfig & (1UL<<cpu);
95 }
96
97
98 /*
99  * Made this into an explicit case statement so that
100  * we can assign specific properties to banks like bank0
101  * actually disabled etc.
102  */
103
104 #ifdef SGI_SN2
105 int
106 IsBankPresent(int index, node_memmap_t nmemmap)
107 {
108         switch (index) {
109                 case 0:return BankPresent(nmemmap.b0size);
110                 case 1:return BankPresent(nmemmap.b1size);
111                 case 2:return BankPresent(nmemmap.b2size);
112                 case 3:return BankPresent(nmemmap.b3size);
113                 default:return -1 ;
114         }
115 }
116
117 int
118 GetBankSize(int index, node_memmap_t nmemmap)
119 {
120         /*
121          * Add 2 because there are 4 dimms per bank.
122          */
123         switch (index) {
124                 case 0:return 2 + ((long)nmemmap.b0size + nmemmap.b0dou);
125                 case 1:return 2 + ((long)nmemmap.b1size + nmemmap.b1dou);
126                 case 2:return 2 + ((long)nmemmap.b2size + nmemmap.b2dou);
127                 case 3:return 2 + ((long)nmemmap.b3size + nmemmap.b3dou);
128                 default:return -1 ;
129         }
130 }
131
132 #endif
133
134 void
135 build_mem_desc(efi_memory_desc_t *md, int type, long paddr, long numbytes, long attr)
136 {
137         md->type = type;
138         md->phys_addr = paddr;
139         md->virt_addr = 0;
140         md->num_pages = numbytes >> 12;
141         md->attribute = attr;
142 }
143
144 int
145 build_efi_memmap(void *md, int mdsize)
146 {
147         int             numnodes = GetNumNodes() ;
148         int             cnode,bank ;
149         int             nasid ;
150         node_memmap_t   membank_info ;
151         int             bsize;
152         int             count = 0 ;
153         long            paddr, hole, numbytes;
154
155
156         for (cnode=0;cnode<numnodes;cnode++) {
157                 nasid = GetNasid(cnode) ;
158                 membank_info = GetMemBankInfo(cnode) ;
159                 for (bank=0;bank<MD_BANKS_PER_NODE;bank++) {
160                         if (IsBankPresent(bank, membank_info)) {
161                                 bsize = GetBankSize(bank, membank_info) ;
162                                 paddr = PHYS_ADDRESS(nasid, (long)bank<<MD_BANK_SHFT);
163                                 numbytes = BankSizeBytes(bsize);
164 #ifdef SGI_SN2
165                                 /* 
166                                  * Ignore directory.
167                                  * Shorten memory chunk by 1 page - makes a better
168                                  * testcase & is more like the real PROM.
169                                  */
170                                 numbytes = numbytes * 31 / 32;
171 #endif
172                                 /*
173                                  * Only emulate the memory prom grabs
174                                  * if we have lots of memory, to allow
175                                  * us to simulate smaller memory configs than
176                                  * we can actually run on h/w.  Otherwise,
177                                  * linux throws away a whole "granule".
178                                  */
179                                 if (cnode == 0 && bank == 0 &&
180                                     numbytes > 128*1024*1024) {
181                                         numbytes -= 1000;
182                                 }
183
184                                 /*
185                                  * Check for the node 0 hole. Since banks cant
186                                  * span the hole, we only need to check if the end of
187                                  * the range is the end of the hole.
188                                  */
189                                 if (paddr+numbytes == NODE0_HOLE_END)
190                                         numbytes -= NODE0_HOLE_SIZE;
191                                 /*
192                                  * UGLY hack - we must skip overr the kernel and
193                                  * PROM runtime services but we dont exactly where it is.
194                                  * So lets just reserve:
195                                  *      node 0
196                                  *              0-1MB for PAL
197                                  *              1-4MB for SAL
198                                  *      node 1-N
199                                  *              0-1 for SAL
200                                  */
201                                 if (bank == 0) {
202                                         if (cnode == 0) {
203                                                 hole = 2*1024*1024;
204                                                 build_mem_desc(md, EFI_PAL_CODE, paddr, hole, EFI_MEMORY_WB|EFI_MEMORY_WB);
205                                                 numbytes -= hole;
206                                                 paddr += hole;
207                                                 count++ ;
208                                                 md += mdsize;
209                                                 hole = 1*1024*1024;
210                                                 build_mem_desc(md, EFI_CONVENTIONAL_MEMORY, paddr, hole, EFI_MEMORY_UC);
211                                                 numbytes -= hole;
212                                                 paddr += hole;
213                                                 count++ ;
214                                                 md += mdsize;
215                                                 hole = 1*1024*1024;
216                                                 build_mem_desc(md, EFI_RUNTIME_SERVICES_DATA, paddr, hole, EFI_MEMORY_WB|EFI_MEMORY_WB);
217                                                 numbytes -= hole;
218                                                 paddr += hole;
219                                                 count++ ;
220                                                 md += mdsize;
221                                         } else {
222                                                 hole = 2*1024*1024;
223                                                 build_mem_desc(md, EFI_RUNTIME_SERVICES_DATA, paddr, hole, EFI_MEMORY_WB|EFI_MEMORY_WB);
224                                                 numbytes -= hole;
225                                                 paddr += hole;
226                                                 count++ ;
227                                                 md += mdsize;
228                                                 hole = 2*1024*1024;
229                                                 build_mem_desc(md, EFI_RUNTIME_SERVICES_DATA, paddr, hole, EFI_MEMORY_UC);
230                                                 numbytes -= hole;
231                                                 paddr += hole;
232                                                 count++ ;
233                                                 md += mdsize;
234                                         }
235                                 }
236                                 build_mem_desc(md, EFI_CONVENTIONAL_MEMORY, paddr, numbytes, EFI_MEMORY_WB|EFI_MEMORY_WB);
237
238                                 md += mdsize ;
239                                 count++ ;
240                         }
241                 }
242         }
243         return count ;
244 }
245
246 void
247 build_init(unsigned long args)
248 {
249         sn_config = (sn_config_t *) (args);     
250         sn_memmap = (sn_memmap_t *)(args + 8) ; /* SN equiv for this is */
251                                                 /* init to klconfig start */
252 }