blob: afb57eeafdcb191c68a22058db46a6ba9044686e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/m68k/motorola.c
3 *
4 * Routines specific to the Motorola MMU, originally from:
5 * linux/arch/m68k/init.c
6 * which are Copyright (C) 1995 Hamish Macdonald
7 *
8 * Moved 8/20/1999 Sam Creasey
9 */
10
11#include <linux/config.h>
12#include <linux/module.h>
13#include <linux/signal.h>
14#include <linux/sched.h>
15#include <linux/mm.h>
16#include <linux/swap.h>
17#include <linux/kernel.h>
18#include <linux/string.h>
19#include <linux/types.h>
20#include <linux/init.h>
21#include <linux/bootmem.h>
22
23#include <asm/setup.h>
24#include <asm/uaccess.h>
25#include <asm/page.h>
26#include <asm/pgalloc.h>
27#include <asm/system.h>
28#include <asm/machdep.h>
29#include <asm/io.h>
30#include <asm/dma.h>
31#ifdef CONFIG_ATARI
32#include <asm/atari_stram.h>
33#endif
34
35#undef DEBUG
36
37#ifndef mm_cachebits
38/*
39 * Bits to add to page descriptors for "normal" caching mode.
40 * For 68020/030 this is 0.
41 * For 68040, this is _PAGE_CACHE040 (cachable, copyback)
42 */
43unsigned long mm_cachebits;
44EXPORT_SYMBOL(mm_cachebits);
45#endif
46
47static pte_t * __init kernel_page_table(void)
48{
49 pte_t *ptablep;
50
51 ptablep = (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE);
52
53 clear_page(ptablep);
54 __flush_page_to_ram(ptablep);
55 flush_tlb_kernel_page(ptablep);
56 nocache_page(ptablep);
57
58 return ptablep;
59}
60
61static pmd_t *last_pgtable __initdata = NULL;
62pmd_t *zero_pgtable __initdata = NULL;
63
64static pmd_t * __init kernel_ptr_table(void)
65{
66 if (!last_pgtable) {
67 unsigned long pmd, last;
68 int i;
69
70 /* Find the last ptr table that was used in head.S and
71 * reuse the remaining space in that page for further
72 * ptr tables.
73 */
74 last = (unsigned long)kernel_pg_dir;
75 for (i = 0; i < PTRS_PER_PGD; i++) {
76 if (!pgd_present(kernel_pg_dir[i]))
77 continue;
78 pmd = __pgd_page(kernel_pg_dir[i]);
79 if (pmd > last)
80 last = pmd;
81 }
82
83 last_pgtable = (pmd_t *)last;
84#ifdef DEBUG
85 printk("kernel_ptr_init: %p\n", last_pgtable);
86#endif
87 }
88
89 last_pgtable += PTRS_PER_PMD;
90 if (((unsigned long)last_pgtable & ~PAGE_MASK) == 0) {
91 last_pgtable = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
92
93 clear_page(last_pgtable);
94 __flush_page_to_ram(last_pgtable);
95 flush_tlb_kernel_page(last_pgtable);
96 nocache_page(last_pgtable);
97 }
98
99 return last_pgtable;
100}
101
102static unsigned long __init
103map_chunk (unsigned long addr, long size)
104{
105#define PTRTREESIZE (256*1024)
106#define ROOTTREESIZE (32*1024*1024)
107 static unsigned long virtaddr = PAGE_OFFSET;
108 unsigned long physaddr;
109 pgd_t *pgd_dir;
110 pmd_t *pmd_dir;
111 pte_t *pte_dir;
112
113 physaddr = (addr | m68k_supervisor_cachemode |
114 _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
115 if (CPU_IS_040_OR_060)
116 physaddr |= _PAGE_GLOBAL040;
117
118 while (size > 0) {
119#ifdef DEBUG
120 if (!(virtaddr & (PTRTREESIZE-1)))
121 printk ("\npa=%#lx va=%#lx ", physaddr & PAGE_MASK,
122 virtaddr);
123#endif
124 pgd_dir = pgd_offset_k(virtaddr);
125 if (virtaddr && CPU_IS_020_OR_030) {
126 if (!(virtaddr & (ROOTTREESIZE-1)) &&
127 size >= ROOTTREESIZE) {
128#ifdef DEBUG
129 printk ("[very early term]");
130#endif
131 pgd_val(*pgd_dir) = physaddr;
132 size -= ROOTTREESIZE;
133 virtaddr += ROOTTREESIZE;
134 physaddr += ROOTTREESIZE;
135 continue;
136 }
137 }
138 if (!pgd_present(*pgd_dir)) {
139 pmd_dir = kernel_ptr_table();
140#ifdef DEBUG
141 printk ("[new pointer %p]", pmd_dir);
142#endif
143 pgd_set(pgd_dir, pmd_dir);
144 } else
145 pmd_dir = pmd_offset(pgd_dir, virtaddr);
146
147 if (CPU_IS_020_OR_030) {
148 if (virtaddr) {
149#ifdef DEBUG
150 printk ("[early term]");
151#endif
152 pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
153 physaddr += PTRTREESIZE;
154 } else {
155 int i;
156#ifdef DEBUG
157 printk ("[zero map]");
158#endif
159 zero_pgtable = kernel_ptr_table();
160 pte_dir = (pte_t *)zero_pgtable;
161 pmd_dir->pmd[0] = virt_to_phys(pte_dir) |
162 _PAGE_TABLE | _PAGE_ACCESSED;
163 pte_val(*pte_dir++) = 0;
164 physaddr += PAGE_SIZE;
165 for (i = 1; i < 64; physaddr += PAGE_SIZE, i++)
166 pte_val(*pte_dir++) = physaddr;
167 }
168 size -= PTRTREESIZE;
169 virtaddr += PTRTREESIZE;
170 } else {
171 if (!pmd_present(*pmd_dir)) {
172#ifdef DEBUG
173 printk ("[new table]");
174#endif
175 pte_dir = kernel_page_table();
176 pmd_set(pmd_dir, pte_dir);
177 }
178 pte_dir = pte_offset_kernel(pmd_dir, virtaddr);
179
180 if (virtaddr) {
181 if (!pte_present(*pte_dir))
182 pte_val(*pte_dir) = physaddr;
183 } else
184 pte_val(*pte_dir) = 0;
185 size -= PAGE_SIZE;
186 virtaddr += PAGE_SIZE;
187 physaddr += PAGE_SIZE;
188 }
189
190 }
191#ifdef DEBUG
192 printk("\n");
193#endif
194
195 return virtaddr;
196}
197
198/*
199 * paging_init() continues the virtual memory environment setup which
200 * was begun by the code in arch/head.S.
201 */
202void __init paging_init(void)
203{
204 int chunk;
205 unsigned long mem_avail = 0;
206 unsigned long zones_size[3] = { 0, };
207
208#ifdef DEBUG
209 {
210 extern unsigned long availmem;
211 printk ("start of paging_init (%p, %lx, %lx, %lx)\n",
212 kernel_pg_dir, availmem, start_mem, end_mem);
213 }
214#endif
215
216 /* Fix the cache mode in the page descriptors for the 680[46]0. */
217 if (CPU_IS_040_OR_060) {
218 int i;
219#ifndef mm_cachebits
220 mm_cachebits = _PAGE_CACHE040;
221#endif
222 for (i = 0; i < 16; i++)
223 pgprot_val(protection_map[i]) |= _PAGE_CACHE040;
224 }
225
226 /*
227 * Map the physical memory available into the kernel virtual
228 * address space. It may allocate some memory for page
229 * tables and thus modify availmem.
230 */
231
232 for (chunk = 0; chunk < m68k_num_memory; chunk++) {
233 mem_avail = map_chunk (m68k_memory[chunk].addr,
234 m68k_memory[chunk].size);
235
236 }
237
238 flush_tlb_all();
239#ifdef DEBUG
240 printk ("memory available is %ldKB\n", mem_avail >> 10);
241 printk ("start_mem is %#lx\nvirtual_end is %#lx\n",
242 start_mem, end_mem);
243#endif
244
245 /*
246 * initialize the bad page table and bad page to point
247 * to a couple of allocated pages
248 */
249 empty_zero_page = alloc_bootmem_pages(PAGE_SIZE);
250 memset(empty_zero_page, 0, PAGE_SIZE);
251
252 /*
253 * Set up SFC/DFC registers
254 */
255 set_fs(KERNEL_DS);
256
257#ifdef DEBUG
258 printk ("before free_area_init\n");
259#endif
260 zones_size[0] = (mach_max_dma_address < (unsigned long)high_memory ?
261 (mach_max_dma_address+1) : (unsigned long)high_memory);
262 zones_size[1] = (unsigned long)high_memory - zones_size[0];
263
264 zones_size[0] = (zones_size[0] - PAGE_OFFSET) >> PAGE_SHIFT;
265 zones_size[1] >>= PAGE_SHIFT;
266
267 free_area_init(zones_size);
268}
269
270extern char __init_begin, __init_end;
271
272void free_initmem(void)
273{
274 unsigned long addr;
275
276 addr = (unsigned long)&__init_begin;
277 for (; addr < (unsigned long)&__init_end; addr += PAGE_SIZE) {
278 virt_to_page(addr)->flags &= ~(1 << PG_reserved);
Nick Piggin7835e982006-03-22 00:08:40 -0800279 init_page_count(virt_to_page(addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 free_page(addr);
281 totalram_pages++;
282 }
283}
284
285