File: /usr/src/linux/arch/m68k/mm/motorola.c

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