Blackfin arch: SMP supporting patchset: Blackfin kernel and memory management code
[safe/jmp/linux-2.6] / arch / blackfin / mm / init.c
1 /*
2  * File:         arch/blackfin/mm/init.c
3  * Based on:
4  * Author:
5  *
6  * Created:
7  * Description:
8  *
9  * Modified:
10  *               Copyright 2004-2007 Analog Devices Inc.
11  *
12  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, see the file COPYING, or write
26  * to the Free Software Foundation, Inc.,
27  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
28  */
29
30 #include <linux/swap.h>
31 #include <linux/bootmem.h>
32 #include <linux/uaccess.h>
33 #include <asm/bfin-global.h>
34 #include <asm/pda.h>
35 #include <asm/cplbinit.h>
36 #include "blackfin_sram.h"
37
38 /*
39  * BAD_PAGE is the page that is used for page faults when linux
40  * is out-of-memory. Older versions of linux just did a
41  * do_exit(), but using this instead means there is less risk
42  * for a process dying in kernel mode, possibly leaving a inode
43  * unused etc..
44  *
45  * BAD_PAGETABLE is the accompanying page-table: it is initialized
46  * to point to BAD_PAGE entries.
47  *
48  * ZERO_PAGE is a special page that is used for zero-initialized
49  * data and COW.
50  */
51 static unsigned long empty_bad_page_table;
52
53 static unsigned long empty_bad_page;
54
55 unsigned long empty_zero_page;
56
57 extern unsigned long exception_stack[NR_CPUS][1024];
58
59 struct blackfin_pda cpu_pda[NR_CPUS];
60 EXPORT_SYMBOL(cpu_pda);
61
62 /*
63  * paging_init() continues the virtual memory environment setup which
64  * was begun by the code in arch/head.S.
65  * The parameters are pointers to where to stick the starting and ending
66  * addresses  of available kernel virtual memory.
67  */
68 void __init paging_init(void)
69 {
70         /*
71          * make sure start_mem is page aligned,  otherwise bootmem and
72          * page_alloc get different views og the world
73          */
74         unsigned long end_mem = memory_end & PAGE_MASK;
75
76         pr_debug("start_mem is %#lx   virtual_end is %#lx\n", PAGE_ALIGN(memory_start), end_mem);
77
78         /*
79          * initialize the bad page table and bad page to point
80          * to a couple of allocated pages
81          */
82         empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
83         empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
84         empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
85         memset((void *)empty_zero_page, 0, PAGE_SIZE);
86
87         /*
88          * Set up SFC/DFC registers (user data space)
89          */
90         set_fs(KERNEL_DS);
91
92         pr_debug("free_area_init -> start_mem is %#lx   virtual_end is %#lx\n",
93                 PAGE_ALIGN(memory_start), end_mem);
94
95         {
96                 unsigned long zones_size[MAX_NR_ZONES] = { 0, };
97
98                 zones_size[ZONE_DMA] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
99                 zones_size[ZONE_NORMAL] = 0;
100 #ifdef CONFIG_HIGHMEM
101                 zones_size[ZONE_HIGHMEM] = 0;
102 #endif
103                 free_area_init(zones_size);
104         }
105 }
106
107 asmlinkage void init_pda(void)
108 {
109         unsigned int cpu = raw_smp_processor_id();
110
111         /* Initialize the PDA fields holding references to other parts
112            of the memory. The content of such memory is still
113            undefined at the time of the call, we are only setting up
114            valid pointers to it. */
115         memset(&cpu_pda[cpu], 0, sizeof(cpu_pda[cpu]));
116
117         cpu_pda[0].next = &cpu_pda[1];
118         cpu_pda[1].next = &cpu_pda[0];
119
120         cpu_pda[cpu].ex_stack = exception_stack[cpu + 1];
121
122 #ifdef CONFIG_MPU
123 #else
124         cpu_pda[cpu].ipdt = ipdt_tables[cpu];
125         cpu_pda[cpu].dpdt = dpdt_tables[cpu];
126 #ifdef CONFIG_CPLB_INFO
127         cpu_pda[cpu].ipdt_swapcount = ipdt_swapcount_tables[cpu];
128         cpu_pda[cpu].dpdt_swapcount = dpdt_swapcount_tables[cpu];
129 #endif
130 #endif
131
132 #ifdef CONFIG_SMP
133         cpu_pda[cpu].imask = 0x1f;
134 #endif
135 }
136
137 void __cpuinit reserve_pda(void)
138 {
139         printk(KERN_INFO "PDA for CPU%u reserved at %p\n", smp_processor_id(),
140                                         &cpu_pda[smp_processor_id()]);
141 }
142
143 void __init mem_init(void)
144 {
145         unsigned int codek = 0, datak = 0, initk = 0;
146         unsigned int reservedpages = 0, freepages = 0;
147         unsigned long tmp;
148         unsigned long start_mem = memory_start;
149         unsigned long end_mem = memory_end;
150
151         end_mem &= PAGE_MASK;
152         high_memory = (void *)end_mem;
153
154         start_mem = PAGE_ALIGN(start_mem);
155         max_mapnr = num_physpages = MAP_NR(high_memory);
156         printk(KERN_DEBUG "Kernel managed physical pages: %lu\n", num_physpages);
157
158         /* This will put all memory onto the freelists. */
159         totalram_pages = free_all_bootmem();
160
161         reservedpages = 0;
162         for (tmp = 0; tmp < max_mapnr; tmp++)
163                 if (PageReserved(pfn_to_page(tmp)))
164                         reservedpages++;
165         freepages =  max_mapnr - reservedpages;
166
167         /* do not count in kernel image between _rambase and _ramstart */
168         reservedpages -= (_ramstart - _rambase) >> PAGE_SHIFT;
169 #if (defined(CONFIG_BFIN_ICACHE) && ANOMALY_05000263)
170         reservedpages += (_ramend - memory_end - DMA_UNCACHED_REGION) >> PAGE_SHIFT;
171 #endif
172
173         codek = (_etext - _stext) >> 10;
174         initk = (__init_end - __init_begin) >> 10;
175         datak = ((_ramstart - _rambase) >> 10) - codek - initk;
176
177         printk(KERN_INFO
178              "Memory available: %luk/%luk RAM, "
179                 "(%uk init code, %uk kernel code, %uk data, %uk dma, %uk reserved)\n",
180                 (unsigned long) freepages << (PAGE_SHIFT-10), _ramend >> 10,
181                 initk, codek, datak, DMA_UNCACHED_REGION >> 10, (reservedpages << (PAGE_SHIFT-10)));
182 }
183
184 static int __init sram_init(void)
185 {
186         /* Initialize the blackfin L1 Memory. */
187         bfin_sram_init();
188
189         /* Reserve the PDA space for the boot CPU right after we
190          * initialized the scratch memory allocator.
191          */
192         reserve_pda();
193         return 0;
194 }
195 pure_initcall(sram_init);
196
197 static void __init free_init_pages(const char *what, unsigned long begin, unsigned long end)
198 {
199         unsigned long addr;
200         /* next to check that the page we free is not a partial page */
201         for (addr = begin; addr + PAGE_SIZE <= end; addr += PAGE_SIZE) {
202                 ClearPageReserved(virt_to_page(addr));
203                 init_page_count(virt_to_page(addr));
204                 free_page(addr);
205                 totalram_pages++;
206         }
207         printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
208 }
209
210 #ifdef CONFIG_BLK_DEV_INITRD
211 void __init free_initrd_mem(unsigned long start, unsigned long end)
212 {
213 #ifndef CONFIG_MPU
214         free_init_pages("initrd memory", start, end);
215 #endif
216 }
217 #endif
218
219 void __init_refok free_initmem(void)
220 {
221 #if defined CONFIG_RAMKERNEL && !defined CONFIG_MPU
222         free_init_pages("unused kernel memory",
223                         (unsigned long)(&__init_begin),
224                         (unsigned long)(&__init_end));
225 #endif
226 }