blob: 4e2f71e0abc8a18595533fbd8e9fc898d7cb5c7a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $Id: init.c,v 1.209 2002/02/09 19:49:31 davem Exp $
2 * arch/sparc64/mm/init.c
3 *
4 * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
5 * Copyright (C) 1997-1999 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
6 */
7
8#include <linux/config.h>
9#include <linux/kernel.h>
10#include <linux/sched.h>
11#include <linux/string.h>
12#include <linux/init.h>
13#include <linux/bootmem.h>
14#include <linux/mm.h>
15#include <linux/hugetlb.h>
16#include <linux/slab.h>
17#include <linux/initrd.h>
18#include <linux/swap.h>
19#include <linux/pagemap.h>
20#include <linux/fs.h>
21#include <linux/seq_file.h>
Prasanna S Panchamukhi05e14cb2005-09-06 15:19:30 -070022#include <linux/kprobes.h>
David S. Miller1ac4f5e2005-09-21 21:49:32 -070023#include <linux/cache.h>
David S. Miller13edad72005-09-29 17:58:26 -070024#include <linux/sort.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
26#include <asm/head.h>
27#include <asm/system.h>
28#include <asm/page.h>
29#include <asm/pgalloc.h>
30#include <asm/pgtable.h>
31#include <asm/oplib.h>
32#include <asm/iommu.h>
33#include <asm/io.h>
34#include <asm/uaccess.h>
35#include <asm/mmu_context.h>
36#include <asm/tlbflush.h>
37#include <asm/dma.h>
38#include <asm/starfire.h>
39#include <asm/tlb.h>
40#include <asm/spitfire.h>
41#include <asm/sections.h>
42
43extern void device_scan(void);
44
David S. Miller13edad72005-09-29 17:58:26 -070045#define MAX_BANKS 32
David S. Miller10147572005-09-28 21:46:43 -070046
David S. Miller13edad72005-09-29 17:58:26 -070047static struct linux_prom64_registers pavail[MAX_BANKS] __initdata;
48static struct linux_prom64_registers pavail_rescan[MAX_BANKS] __initdata;
49static int pavail_ents __initdata;
50static int pavail_rescan_ents __initdata;
David S. Miller10147572005-09-28 21:46:43 -070051
David S. Miller13edad72005-09-29 17:58:26 -070052static int cmp_p64(const void *a, const void *b)
53{
54 const struct linux_prom64_registers *x = a, *y = b;
55
56 if (x->phys_addr > y->phys_addr)
57 return 1;
58 if (x->phys_addr < y->phys_addr)
59 return -1;
60 return 0;
61}
62
63static void __init read_obp_memory(const char *property,
64 struct linux_prom64_registers *regs,
65 int *num_ents)
66{
67 int node = prom_finddevice("/memory");
68 int prop_size = prom_getproplen(node, property);
69 int ents, ret, i;
70
71 ents = prop_size / sizeof(struct linux_prom64_registers);
72 if (ents > MAX_BANKS) {
73 prom_printf("The machine has more %s property entries than "
74 "this kernel can support (%d).\n",
75 property, MAX_BANKS);
76 prom_halt();
77 }
78
79 ret = prom_getproperty(node, property, (char *) regs, prop_size);
80 if (ret == -1) {
81 prom_printf("Couldn't get %s property from /memory.\n");
82 prom_halt();
83 }
84
85 *num_ents = ents;
86
87 /* Sanitize what we got from the firmware, by page aligning
88 * everything.
89 */
90 for (i = 0; i < ents; i++) {
91 unsigned long base, size;
92
93 base = regs[i].phys_addr;
94 size = regs[i].reg_size;
95
96 size &= PAGE_MASK;
97 if (base & ~PAGE_MASK) {
98 unsigned long new_base = PAGE_ALIGN(base);
99
100 size -= new_base - base;
101 if ((long) size < 0L)
102 size = 0UL;
103 base = new_base;
104 }
105 regs[i].phys_addr = base;
106 regs[i].reg_size = size;
107 }
108 sort(regs, ents, sizeof(struct linux_prom64_registers),
109 cmp_p64, NULL);
110}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
David S. Miller2bdb3cb2005-09-22 01:08:57 -0700112unsigned long *sparc64_valid_addr_bitmap __read_mostly;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
114/* Ugly, but necessary... -DaveM */
David S. Miller1ac4f5e2005-09-21 21:49:32 -0700115unsigned long phys_base __read_mostly;
116unsigned long kern_base __read_mostly;
117unsigned long kern_size __read_mostly;
118unsigned long pfn_base __read_mostly;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120/* get_new_mmu_context() uses "cache + 1". */
121DEFINE_SPINLOCK(ctx_alloc_lock);
122unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1;
123#define CTX_BMAP_SLOTS (1UL << (CTX_NR_BITS - 6))
124unsigned long mmu_context_bmap[CTX_BMAP_SLOTS];
125
126/* References to special section boundaries */
127extern char _start[], _end[];
128
129/* Initial ramdisk setup */
130extern unsigned long sparc_ramdisk_image64;
131extern unsigned int sparc_ramdisk_image;
132extern unsigned int sparc_ramdisk_size;
133
David S. Miller1ac4f5e2005-09-21 21:49:32 -0700134struct page *mem_map_zero __read_mostly;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135
David S. Miller0835ae02005-10-04 15:23:20 -0700136unsigned int sparc64_highest_unlocked_tlb_ent __read_mostly;
137
138unsigned long sparc64_kern_pri_context __read_mostly;
139unsigned long sparc64_kern_pri_nuc_bits __read_mostly;
140unsigned long sparc64_kern_sec_context __read_mostly;
141
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142int bigkernel = 0;
143
144/* XXX Tune this... */
145#define PGT_CACHE_LOW 25
146#define PGT_CACHE_HIGH 50
147
148void check_pgt_cache(void)
149{
150 preempt_disable();
151 if (pgtable_cache_size > PGT_CACHE_HIGH) {
152 do {
153 if (pgd_quicklist)
154 free_pgd_slow(get_pgd_fast());
155 if (pte_quicklist[0])
156 free_pte_slow(pte_alloc_one_fast(NULL, 0));
157 if (pte_quicklist[1])
158 free_pte_slow(pte_alloc_one_fast(NULL, 1 << (PAGE_SHIFT + 10)));
159 } while (pgtable_cache_size > PGT_CACHE_LOW);
160 }
161 preempt_enable();
162}
163
164#ifdef CONFIG_DEBUG_DCFLUSH
165atomic_t dcpage_flushes = ATOMIC_INIT(0);
166#ifdef CONFIG_SMP
167atomic_t dcpage_flushes_xcall = ATOMIC_INIT(0);
168#endif
169#endif
170
171__inline__ void flush_dcache_page_impl(struct page *page)
172{
173#ifdef CONFIG_DEBUG_DCFLUSH
174 atomic_inc(&dcpage_flushes);
175#endif
176
177#ifdef DCACHE_ALIASING_POSSIBLE
178 __flush_dcache_page(page_address(page),
179 ((tlb_type == spitfire) &&
180 page_mapping(page) != NULL));
181#else
182 if (page_mapping(page) != NULL &&
183 tlb_type == spitfire)
184 __flush_icache_page(__pa(page_address(page)));
185#endif
186}
187
188#define PG_dcache_dirty PG_arch_1
David S. Miller48b0e542005-07-27 16:08:44 -0700189#define PG_dcache_cpu_shift 24
190#define PG_dcache_cpu_mask (256 - 1)
191
192#if NR_CPUS > 256
193#error D-cache dirty tracking and thread_info->cpu need fixing for > 256 cpus
194#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196#define dcache_dirty_cpu(page) \
David S. Miller48b0e542005-07-27 16:08:44 -0700197 (((page)->flags >> PG_dcache_cpu_shift) & PG_dcache_cpu_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
199static __inline__ void set_dcache_dirty(struct page *page, int this_cpu)
200{
201 unsigned long mask = this_cpu;
David S. Miller48b0e542005-07-27 16:08:44 -0700202 unsigned long non_cpu_bits;
203
204 non_cpu_bits = ~(PG_dcache_cpu_mask << PG_dcache_cpu_shift);
205 mask = (mask << PG_dcache_cpu_shift) | (1UL << PG_dcache_dirty);
206
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 __asm__ __volatile__("1:\n\t"
208 "ldx [%2], %%g7\n\t"
209 "and %%g7, %1, %%g1\n\t"
210 "or %%g1, %0, %%g1\n\t"
211 "casx [%2], %%g7, %%g1\n\t"
212 "cmp %%g7, %%g1\n\t"
David S. Millerb445e262005-06-27 15:42:04 -0700213 "membar #StoreLoad | #StoreStore\n\t"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 "bne,pn %%xcc, 1b\n\t"
David S. Millerb445e262005-06-27 15:42:04 -0700215 " nop"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 : /* no outputs */
217 : "r" (mask), "r" (non_cpu_bits), "r" (&page->flags)
218 : "g1", "g7");
219}
220
221static __inline__ void clear_dcache_dirty_cpu(struct page *page, unsigned long cpu)
222{
223 unsigned long mask = (1UL << PG_dcache_dirty);
224
225 __asm__ __volatile__("! test_and_clear_dcache_dirty\n"
226 "1:\n\t"
227 "ldx [%2], %%g7\n\t"
David S. Miller48b0e542005-07-27 16:08:44 -0700228 "srlx %%g7, %4, %%g1\n\t"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 "and %%g1, %3, %%g1\n\t"
230 "cmp %%g1, %0\n\t"
231 "bne,pn %%icc, 2f\n\t"
232 " andn %%g7, %1, %%g1\n\t"
233 "casx [%2], %%g7, %%g1\n\t"
234 "cmp %%g7, %%g1\n\t"
David S. Millerb445e262005-06-27 15:42:04 -0700235 "membar #StoreLoad | #StoreStore\n\t"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 "bne,pn %%xcc, 1b\n\t"
David S. Millerb445e262005-06-27 15:42:04 -0700237 " nop\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 "2:"
239 : /* no outputs */
240 : "r" (cpu), "r" (mask), "r" (&page->flags),
David S. Miller48b0e542005-07-27 16:08:44 -0700241 "i" (PG_dcache_cpu_mask),
242 "i" (PG_dcache_cpu_shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 : "g1", "g7");
244}
245
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
247{
248 struct page *page;
249 unsigned long pfn;
250 unsigned long pg_flags;
251
252 pfn = pte_pfn(pte);
253 if (pfn_valid(pfn) &&
254 (page = pfn_to_page(pfn), page_mapping(page)) &&
255 ((pg_flags = page->flags) & (1UL << PG_dcache_dirty))) {
David S. Miller48b0e542005-07-27 16:08:44 -0700256 int cpu = ((pg_flags >> PG_dcache_cpu_shift) &
257 PG_dcache_cpu_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 int this_cpu = get_cpu();
259
260 /* This is just to optimize away some function calls
261 * in the SMP case.
262 */
263 if (cpu == this_cpu)
264 flush_dcache_page_impl(page);
265 else
266 smp_flush_dcache_page_impl(page, cpu);
267
268 clear_dcache_dirty_cpu(page, cpu);
269
270 put_cpu();
271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272}
273
274void flush_dcache_page(struct page *page)
275{
David S. Millera9546f52005-04-17 18:03:09 -0700276 struct address_space *mapping;
277 int this_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
David S. Millera9546f52005-04-17 18:03:09 -0700279 /* Do not bother with the expensive D-cache flush if it
280 * is merely the zero page. The 'bigcore' testcase in GDB
281 * causes this case to run millions of times.
282 */
283 if (page == ZERO_PAGE(0))
284 return;
285
286 this_cpu = get_cpu();
287
288 mapping = page_mapping(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 if (mapping && !mapping_mapped(mapping)) {
David S. Millera9546f52005-04-17 18:03:09 -0700290 int dirty = test_bit(PG_dcache_dirty, &page->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 if (dirty) {
David S. Millera9546f52005-04-17 18:03:09 -0700292 int dirty_cpu = dcache_dirty_cpu(page);
293
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 if (dirty_cpu == this_cpu)
295 goto out;
296 smp_flush_dcache_page_impl(page, dirty_cpu);
297 }
298 set_dcache_dirty(page, this_cpu);
299 } else {
300 /* We could delay the flush for the !page_mapping
301 * case too. But that case is for exec env/arg
302 * pages and those are %99 certainly going to get
303 * faulted into the tlb (and thus flushed) anyways.
304 */
305 flush_dcache_page_impl(page);
306 }
307
308out:
309 put_cpu();
310}
311
Prasanna S Panchamukhi05e14cb2005-09-06 15:19:30 -0700312void __kprobes flush_icache_range(unsigned long start, unsigned long end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313{
314 /* Cheetah has coherent I-cache. */
315 if (tlb_type == spitfire) {
316 unsigned long kaddr;
317
318 for (kaddr = start; kaddr < end; kaddr += PAGE_SIZE)
319 __flush_icache_page(__get_phys(kaddr));
320 }
321}
322
323unsigned long page_to_pfn(struct page *page)
324{
325 return (unsigned long) ((page - mem_map) + pfn_base);
326}
327
328struct page *pfn_to_page(unsigned long pfn)
329{
330 return (mem_map + (pfn - pfn_base));
331}
332
333void show_mem(void)
334{
335 printk("Mem-info:\n");
336 show_free_areas();
337 printk("Free swap: %6ldkB\n",
338 nr_swap_pages << (PAGE_SHIFT-10));
339 printk("%ld pages of RAM\n", num_physpages);
340 printk("%d free pages\n", nr_free_pages());
341 printk("%d pages in page table cache\n",pgtable_cache_size);
342}
343
344void mmu_info(struct seq_file *m)
345{
346 if (tlb_type == cheetah)
347 seq_printf(m, "MMU Type\t: Cheetah\n");
348 else if (tlb_type == cheetah_plus)
349 seq_printf(m, "MMU Type\t: Cheetah+\n");
350 else if (tlb_type == spitfire)
351 seq_printf(m, "MMU Type\t: Spitfire\n");
352 else
353 seq_printf(m, "MMU Type\t: ???\n");
354
355#ifdef CONFIG_DEBUG_DCFLUSH
356 seq_printf(m, "DCPageFlushes\t: %d\n",
357 atomic_read(&dcpage_flushes));
358#ifdef CONFIG_SMP
359 seq_printf(m, "DCPageFlushesXC\t: %d\n",
360 atomic_read(&dcpage_flushes_xcall));
361#endif /* CONFIG_SMP */
362#endif /* CONFIG_DEBUG_DCFLUSH */
363}
364
365struct linux_prom_translation {
366 unsigned long virt;
367 unsigned long size;
368 unsigned long data;
369};
David S. Millerb206fc42005-09-21 22:31:13 -0700370static struct linux_prom_translation prom_trans[512] __initdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
372extern unsigned long prom_boot_page;
373extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle);
374extern int prom_get_mmu_ihandle(void);
375extern void register_prom_callbacks(void);
376
377/* Exported for SMP bootup purposes. */
378unsigned long kern_locked_tte_data;
379
David S. Miller1ac4f5e2005-09-21 21:49:32 -0700380/* Exported for kernel TLB miss handling in ktlb.S */
381unsigned long prom_pmd_phys __read_mostly;
382unsigned int swapper_pgd_zero __read_mostly;
383
David S. Miller5085b4a2005-09-22 00:45:41 -0700384/* Allocate power-of-2 aligned chunks from the end of the
385 * kernel image. Return physical address.
386 */
387static inline unsigned long early_alloc_phys(unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388{
David S. Miller5085b4a2005-09-22 00:45:41 -0700389 unsigned long base;
390
391 BUILD_BUG_ON(size & (size - 1));
392
393 kern_size = (kern_size + (size - 1)) & ~(size - 1);
394 base = kern_base + kern_size;
395 kern_size += size;
396
397 return base;
398}
399
400static inline unsigned long load_phys32(unsigned long pa)
401{
402 unsigned long val;
403
404 __asm__ __volatile__("lduwa [%1] %2, %0"
405 : "=&r" (val)
406 : "r" (pa), "i" (ASI_PHYS_USE_EC));
407
408 return val;
409}
410
411static inline unsigned long load_phys64(unsigned long pa)
412{
413 unsigned long val;
414
415 __asm__ __volatile__("ldxa [%1] %2, %0"
416 : "=&r" (val)
417 : "r" (pa), "i" (ASI_PHYS_USE_EC));
418
419 return val;
420}
421
422static inline void store_phys32(unsigned long pa, unsigned long val)
423{
424 __asm__ __volatile__("stwa %0, [%1] %2"
425 : /* no outputs */
426 : "r" (val), "r" (pa), "i" (ASI_PHYS_USE_EC));
427}
428
429static inline void store_phys64(unsigned long pa, unsigned long val)
430{
431 __asm__ __volatile__("stxa %0, [%1] %2"
432 : /* no outputs */
433 : "r" (val), "r" (pa), "i" (ASI_PHYS_USE_EC));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434}
435
436#define BASE_PAGE_SIZE 8192
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
438/*
439 * Translate PROM's mapping we capture at boot time into physical address.
440 * The second parameter is only set from prom_callback() invocations.
441 */
442unsigned long prom_virt_to_phys(unsigned long promva, int *error)
443{
David S. Miller5085b4a2005-09-22 00:45:41 -0700444 unsigned long pmd_phys = (prom_pmd_phys +
445 ((promva >> 23) & 0x7ff) * sizeof(pmd_t));
446 unsigned long pte_phys;
447 pmd_t pmd_ent;
448 pte_t pte_ent;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 unsigned long base;
450
David S. Miller5085b4a2005-09-22 00:45:41 -0700451 pmd_val(pmd_ent) = load_phys32(pmd_phys);
452 if (pmd_none(pmd_ent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 if (error)
454 *error = 1;
David S. Miller5085b4a2005-09-22 00:45:41 -0700455 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 }
David S. Miller5085b4a2005-09-22 00:45:41 -0700457
458 pte_phys = (unsigned long)pmd_val(pmd_ent) << 11UL;
459 pte_phys += ((promva >> 13) & 0x3ff) * sizeof(pte_t);
460 pte_val(pte_ent) = load_phys64(pte_phys);
461 if (!pte_present(pte_ent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 if (error)
463 *error = 1;
David S. Miller5085b4a2005-09-22 00:45:41 -0700464 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 }
466 if (error) {
467 *error = 0;
David S. Miller5085b4a2005-09-22 00:45:41 -0700468 return pte_val(pte_ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 }
David S. Miller5085b4a2005-09-22 00:45:41 -0700470 base = pte_val(pte_ent) & _PAGE_PADDR;
471 return (base + (promva & (BASE_PAGE_SIZE - 1)));
David S. Miller405599b2005-09-22 00:12:35 -0700472}
473
474/* The obp translations are saved based on 8k pagesize, since obp can
475 * use a mixture of pagesizes. Misses to the LOW_OBP_ADDRESS ->
476 * HI_OBP_ADDRESS range are handled in entry.S and do not use the vpte
477 * scheme (also, see rant in inherit_locked_prom_mappings()).
478 */
David S. Miller898cf0e2005-09-23 11:59:44 -0700479static void __init build_obp_range(unsigned long start, unsigned long end, unsigned long data)
David S. Miller405599b2005-09-22 00:12:35 -0700480{
481 unsigned long vaddr;
482
483 for (vaddr = start; vaddr < end; vaddr += BASE_PAGE_SIZE) {
David S. Miller5085b4a2005-09-22 00:45:41 -0700484 unsigned long val, pte_phys, pmd_phys;
485 pmd_t pmd_ent;
486 int i;
David S. Miller405599b2005-09-22 00:12:35 -0700487
David S. Miller5085b4a2005-09-22 00:45:41 -0700488 pmd_phys = (prom_pmd_phys +
489 (((vaddr >> 23) & 0x7ff) * sizeof(pmd_t)));
490 pmd_val(pmd_ent) = load_phys32(pmd_phys);
491 if (pmd_none(pmd_ent)) {
492 pte_phys = early_alloc_phys(BASE_PAGE_SIZE);
493
494 for (i = 0; i < BASE_PAGE_SIZE / sizeof(pte_t); i++)
495 store_phys64(pte_phys+i*sizeof(pte_t),0);
496
497 pmd_val(pmd_ent) = pte_phys >> 11UL;
498 store_phys32(pmd_phys, pmd_val(pmd_ent));
David S. Miller405599b2005-09-22 00:12:35 -0700499 }
David S. Miller5085b4a2005-09-22 00:45:41 -0700500
501 pte_phys = (unsigned long)pmd_val(pmd_ent) << 11UL;
502 pte_phys += (((vaddr >> 13) & 0x3ff) * sizeof(pte_t));
David S. Miller405599b2005-09-22 00:12:35 -0700503
504 val = data;
505
506 /* Clear diag TTE bits. */
507 if (tlb_type == spitfire)
508 val &= ~0x0003fe0000000000UL;
509
David S. Miller5085b4a2005-09-22 00:45:41 -0700510 store_phys64(pte_phys, val | _PAGE_MODIFIED);
511
David S. Miller405599b2005-09-22 00:12:35 -0700512 data += BASE_PAGE_SIZE;
513 }
514}
515
David S. Miller5085b4a2005-09-22 00:45:41 -0700516static inline int in_obp_range(unsigned long vaddr)
517{
518 return (vaddr >= LOW_OBP_ADDRESS &&
519 vaddr < HI_OBP_ADDRESS);
520}
521
David S. Miller405599b2005-09-22 00:12:35 -0700522#define OBP_PMD_SIZE 2048
David S. Miller898cf0e2005-09-23 11:59:44 -0700523static void __init build_obp_pgtable(int prom_trans_ents)
David S. Miller405599b2005-09-22 00:12:35 -0700524{
David S. Miller5085b4a2005-09-22 00:45:41 -0700525 unsigned long i;
David S. Miller405599b2005-09-22 00:12:35 -0700526
David S. Miller5085b4a2005-09-22 00:45:41 -0700527 prom_pmd_phys = early_alloc_phys(OBP_PMD_SIZE);
528 for (i = 0; i < OBP_PMD_SIZE; i += 4)
529 store_phys32(prom_pmd_phys + i, 0);
530
David S. Miller405599b2005-09-22 00:12:35 -0700531 for (i = 0; i < prom_trans_ents; i++) {
532 unsigned long start, end;
533
534 if (!in_obp_range(prom_trans[i].virt))
535 continue;
536
537 start = prom_trans[i].virt;
538 end = start + prom_trans[i].size;
539 if (end > HI_OBP_ADDRESS)
540 end = HI_OBP_ADDRESS;
541
542 build_obp_range(start, end, prom_trans[i].data);
543 }
David S. Miller405599b2005-09-22 00:12:35 -0700544}
545
546/* Read OBP translations property into 'prom_trans[]'.
547 * Return the number of entries.
548 */
David S. Miller898cf0e2005-09-23 11:59:44 -0700549static int __init read_obp_translations(void)
David S. Miller405599b2005-09-22 00:12:35 -0700550{
551 int n, node;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
553 node = prom_finddevice("/virtual-memory");
554 n = prom_getproplen(node, "translations");
David S. Miller405599b2005-09-22 00:12:35 -0700555 if (unlikely(n == 0 || n == -1)) {
David S. Millerb206fc42005-09-21 22:31:13 -0700556 prom_printf("prom_mappings: Couldn't get size.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 prom_halt();
558 }
David S. Miller405599b2005-09-22 00:12:35 -0700559 if (unlikely(n > sizeof(prom_trans))) {
560 prom_printf("prom_mappings: Size %Zd is too big.\n", n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 prom_halt();
562 }
David S. Miller405599b2005-09-22 00:12:35 -0700563
David S. Millerb206fc42005-09-21 22:31:13 -0700564 if ((n = prom_getproperty(node, "translations",
David S. Miller405599b2005-09-22 00:12:35 -0700565 (char *)&prom_trans[0],
566 sizeof(prom_trans))) == -1) {
David S. Millerb206fc42005-09-21 22:31:13 -0700567 prom_printf("prom_mappings: Couldn't get property.\n");
568 prom_halt();
569 }
570 n = n / sizeof(struct linux_prom_translation);
David S. Miller405599b2005-09-22 00:12:35 -0700571 return n;
572}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573
David S. Miller898cf0e2005-09-23 11:59:44 -0700574static void __init remap_kernel(void)
David S. Miller405599b2005-09-22 00:12:35 -0700575{
576 unsigned long phys_page, tte_vaddr, tte_data;
David S. Miller405599b2005-09-22 00:12:35 -0700577 int tlb_ent = sparc64_highest_locked_tlbent();
578
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 tte_vaddr = (unsigned long) KERNBASE;
David S. Millerbff06d52005-09-22 20:11:33 -0700580 phys_page = (prom_boot_mapping_phys_low >> 22UL) << 22UL;
581 tte_data = (phys_page | (_PAGE_VALID | _PAGE_SZ4MB |
582 _PAGE_CP | _PAGE_CV | _PAGE_P |
583 _PAGE_L | _PAGE_W));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584
585 kern_locked_tte_data = tte_data;
586
David S. Millerbff06d52005-09-22 20:11:33 -0700587 /* Now lock us into the TLBs via OBP. */
David S. Miller405599b2005-09-22 00:12:35 -0700588 prom_dtlb_load(tlb_ent, tte_data, tte_vaddr);
589 prom_itlb_load(tlb_ent, tte_data, tte_vaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 if (bigkernel) {
David S. Miller0835ae02005-10-04 15:23:20 -0700591 tlb_ent -= 1;
592 prom_dtlb_load(tlb_ent,
David S. Miller405599b2005-09-22 00:12:35 -0700593 tte_data + 0x400000,
594 tte_vaddr + 0x400000);
David S. Miller0835ae02005-10-04 15:23:20 -0700595 prom_itlb_load(tlb_ent,
David S. Miller405599b2005-09-22 00:12:35 -0700596 tte_data + 0x400000,
597 tte_vaddr + 0x400000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 }
David S. Miller0835ae02005-10-04 15:23:20 -0700599 sparc64_highest_unlocked_tlb_ent = tlb_ent - 1;
600 if (tlb_type == cheetah_plus) {
601 sparc64_kern_pri_context = (CTX_CHEETAH_PLUS_CTX0 |
602 CTX_CHEETAH_PLUS_NUC);
603 sparc64_kern_pri_nuc_bits = CTX_CHEETAH_PLUS_NUC;
604 sparc64_kern_sec_context = CTX_CHEETAH_PLUS_CTX0;
605 }
David S. Miller405599b2005-09-22 00:12:35 -0700606}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
David S. Miller898cf0e2005-09-23 11:59:44 -0700608static void __init inherit_prom_mappings(void)
David S. Miller405599b2005-09-22 00:12:35 -0700609{
610 int n;
611
612 n = read_obp_translations();
613 build_obp_pgtable(n);
614
615 /* Now fixup OBP's idea about where we really are mapped. */
616 prom_printf("Remapping the kernel... ");
617 remap_kernel();
618
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 prom_printf("done.\n");
620
621 register_prom_callbacks();
622}
623
624/* The OBP specifications for sun4u mark 0xfffffffc00000000 and
625 * upwards as reserved for use by the firmware (I wonder if this
626 * will be the same on Cheetah...). We use this virtual address
627 * range for the VPTE table mappings of the nucleus so we need
628 * to zap them when we enter the PROM. -DaveM
629 */
630static void __flush_nucleus_vptes(void)
631{
632 unsigned long prom_reserved_base = 0xfffffffc00000000UL;
633 int i;
634
635 /* Only DTLB must be checked for VPTE entries. */
636 if (tlb_type == spitfire) {
637 for (i = 0; i < 63; i++) {
638 unsigned long tag;
639
640 /* Spitfire Errata #32 workaround */
641 /* NOTE: Always runs on spitfire, so no cheetah+
642 * page size encodings.
643 */
644 __asm__ __volatile__("stxa %0, [%1] %2\n\t"
645 "flush %%g6"
646 : /* No outputs */
647 : "r" (0),
648 "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
649
650 tag = spitfire_get_dtlb_tag(i);
651 if (((tag & ~(PAGE_MASK)) == 0) &&
652 ((tag & (PAGE_MASK)) >= prom_reserved_base)) {
653 __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
654 "membar #Sync"
655 : /* no outputs */
656 : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
657 spitfire_put_dtlb_data(i, 0x0UL);
658 }
659 }
660 } else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
661 for (i = 0; i < 512; i++) {
662 unsigned long tag = cheetah_get_dtlb_tag(i, 2);
663
664 if ((tag & ~PAGE_MASK) == 0 &&
665 (tag & PAGE_MASK) >= prom_reserved_base) {
666 __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
667 "membar #Sync"
668 : /* no outputs */
669 : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
670 cheetah_put_dtlb_data(i, 0x0UL, 2);
671 }
672
673 if (tlb_type != cheetah_plus)
674 continue;
675
676 tag = cheetah_get_dtlb_tag(i, 3);
677
678 if ((tag & ~PAGE_MASK) == 0 &&
679 (tag & PAGE_MASK) >= prom_reserved_base) {
680 __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
681 "membar #Sync"
682 : /* no outputs */
683 : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
684 cheetah_put_dtlb_data(i, 0x0UL, 3);
685 }
686 }
687 } else {
688 /* Implement me :-) */
689 BUG();
690 }
691}
692
693static int prom_ditlb_set;
694struct prom_tlb_entry {
695 int tlb_ent;
696 unsigned long tlb_tag;
697 unsigned long tlb_data;
698};
699struct prom_tlb_entry prom_itlb[16], prom_dtlb[16];
700
701void prom_world(int enter)
702{
703 unsigned long pstate;
704 int i;
705
706 if (!enter)
707 set_fs((mm_segment_t) { get_thread_current_ds() });
708
709 if (!prom_ditlb_set)
710 return;
711
712 /* Make sure the following runs atomically. */
713 __asm__ __volatile__("flushw\n\t"
714 "rdpr %%pstate, %0\n\t"
715 "wrpr %0, %1, %%pstate"
716 : "=r" (pstate)
717 : "i" (PSTATE_IE));
718
719 if (enter) {
720 /* Kick out nucleus VPTEs. */
721 __flush_nucleus_vptes();
722
723 /* Install PROM world. */
724 for (i = 0; i < 16; i++) {
725 if (prom_dtlb[i].tlb_ent != -1) {
726 __asm__ __volatile__("stxa %0, [%1] %2\n\t"
727 "membar #Sync"
728 : : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
729 "i" (ASI_DMMU));
730 if (tlb_type == spitfire)
731 spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
732 prom_dtlb[i].tlb_data);
733 else if (tlb_type == cheetah || tlb_type == cheetah_plus)
734 cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent,
735 prom_dtlb[i].tlb_data);
736 }
737 if (prom_itlb[i].tlb_ent != -1) {
738 __asm__ __volatile__("stxa %0, [%1] %2\n\t"
739 "membar #Sync"
740 : : "r" (prom_itlb[i].tlb_tag),
741 "r" (TLB_TAG_ACCESS),
742 "i" (ASI_IMMU));
743 if (tlb_type == spitfire)
744 spitfire_put_itlb_data(prom_itlb[i].tlb_ent,
745 prom_itlb[i].tlb_data);
746 else if (tlb_type == cheetah || tlb_type == cheetah_plus)
747 cheetah_put_litlb_data(prom_itlb[i].tlb_ent,
748 prom_itlb[i].tlb_data);
749 }
750 }
751 } else {
752 for (i = 0; i < 16; i++) {
753 if (prom_dtlb[i].tlb_ent != -1) {
754 __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
755 "membar #Sync"
756 : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
757 if (tlb_type == spitfire)
758 spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, 0x0UL);
759 else
760 cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent, 0x0UL);
761 }
762 if (prom_itlb[i].tlb_ent != -1) {
763 __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
764 "membar #Sync"
765 : : "r" (TLB_TAG_ACCESS),
766 "i" (ASI_IMMU));
767 if (tlb_type == spitfire)
768 spitfire_put_itlb_data(prom_itlb[i].tlb_ent, 0x0UL);
769 else
770 cheetah_put_litlb_data(prom_itlb[i].tlb_ent, 0x0UL);
771 }
772 }
773 }
774 __asm__ __volatile__("wrpr %0, 0, %%pstate"
775 : : "r" (pstate));
776}
777
778void inherit_locked_prom_mappings(int save_p)
779{
780 int i;
781 int dtlb_seen = 0;
782 int itlb_seen = 0;
783
784 /* Fucking losing PROM has more mappings in the TLB, but
785 * it (conveniently) fails to mention any of these in the
786 * translations property. The only ones that matter are
787 * the locked PROM tlb entries, so we impose the following
788 * irrecovable rule on the PROM, it is allowed 8 locked
789 * entries in the ITLB and 8 in the DTLB.
790 *
791 * Supposedly the upper 16GB of the address space is
792 * reserved for OBP, BUT I WISH THIS WAS DOCUMENTED
793 * SOMEWHERE!!!!!!!!!!!!!!!!! Furthermore the entire interface
794 * used between the client program and the firmware on sun5
795 * systems to coordinate mmu mappings is also COMPLETELY
796 * UNDOCUMENTED!!!!!! Thanks S(t)un!
797 */
798 if (save_p) {
799 for (i = 0; i < 16; i++) {
800 prom_itlb[i].tlb_ent = -1;
801 prom_dtlb[i].tlb_ent = -1;
802 }
803 }
804 if (tlb_type == spitfire) {
David S. Miller0835ae02005-10-04 15:23:20 -0700805 int high = sparc64_highest_unlocked_tlb_ent;
806 for (i = 0; i <= high; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 unsigned long data;
808
809 /* Spitfire Errata #32 workaround */
810 /* NOTE: Always runs on spitfire, so no cheetah+
811 * page size encodings.
812 */
813 __asm__ __volatile__("stxa %0, [%1] %2\n\t"
814 "flush %%g6"
815 : /* No outputs */
816 : "r" (0),
817 "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
818
819 data = spitfire_get_dtlb_data(i);
820 if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
821 unsigned long tag;
822
823 /* Spitfire Errata #32 workaround */
824 /* NOTE: Always runs on spitfire, so no
825 * cheetah+ page size encodings.
826 */
827 __asm__ __volatile__("stxa %0, [%1] %2\n\t"
828 "flush %%g6"
829 : /* No outputs */
830 : "r" (0),
831 "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
832
833 tag = spitfire_get_dtlb_tag(i);
834 if (save_p) {
835 prom_dtlb[dtlb_seen].tlb_ent = i;
836 prom_dtlb[dtlb_seen].tlb_tag = tag;
837 prom_dtlb[dtlb_seen].tlb_data = data;
838 }
839 __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
840 "membar #Sync"
841 : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
842 spitfire_put_dtlb_data(i, 0x0UL);
843
844 dtlb_seen++;
845 if (dtlb_seen > 15)
846 break;
847 }
848 }
849
850 for (i = 0; i < high; i++) {
851 unsigned long data;
852
853 /* Spitfire Errata #32 workaround */
854 /* NOTE: Always runs on spitfire, so no
855 * cheetah+ page size encodings.
856 */
857 __asm__ __volatile__("stxa %0, [%1] %2\n\t"
858 "flush %%g6"
859 : /* No outputs */
860 : "r" (0),
861 "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
862
863 data = spitfire_get_itlb_data(i);
864 if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
865 unsigned long tag;
866
867 /* Spitfire Errata #32 workaround */
868 /* NOTE: Always runs on spitfire, so no
869 * cheetah+ page size encodings.
870 */
871 __asm__ __volatile__("stxa %0, [%1] %2\n\t"
872 "flush %%g6"
873 : /* No outputs */
874 : "r" (0),
875 "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
876
877 tag = spitfire_get_itlb_tag(i);
878 if (save_p) {
879 prom_itlb[itlb_seen].tlb_ent = i;
880 prom_itlb[itlb_seen].tlb_tag = tag;
881 prom_itlb[itlb_seen].tlb_data = data;
882 }
883 __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
884 "membar #Sync"
885 : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
886 spitfire_put_itlb_data(i, 0x0UL);
887
888 itlb_seen++;
889 if (itlb_seen > 15)
890 break;
891 }
892 }
893 } else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
David S. Miller0835ae02005-10-04 15:23:20 -0700894 int high = sparc64_highest_unlocked_tlb_ent;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895
David S. Miller0835ae02005-10-04 15:23:20 -0700896 for (i = 0; i <= high; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 unsigned long data;
898
899 data = cheetah_get_ldtlb_data(i);
900 if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
901 unsigned long tag;
902
903 tag = cheetah_get_ldtlb_tag(i);
904 if (save_p) {
905 prom_dtlb[dtlb_seen].tlb_ent = i;
906 prom_dtlb[dtlb_seen].tlb_tag = tag;
907 prom_dtlb[dtlb_seen].tlb_data = data;
908 }
909 __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
910 "membar #Sync"
911 : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
912 cheetah_put_ldtlb_data(i, 0x0UL);
913
914 dtlb_seen++;
915 if (dtlb_seen > 15)
916 break;
917 }
918 }
919
920 for (i = 0; i < high; i++) {
921 unsigned long data;
922
923 data = cheetah_get_litlb_data(i);
924 if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
925 unsigned long tag;
926
927 tag = cheetah_get_litlb_tag(i);
928 if (save_p) {
929 prom_itlb[itlb_seen].tlb_ent = i;
930 prom_itlb[itlb_seen].tlb_tag = tag;
931 prom_itlb[itlb_seen].tlb_data = data;
932 }
933 __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
934 "membar #Sync"
935 : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
936 cheetah_put_litlb_data(i, 0x0UL);
937
938 itlb_seen++;
939 if (itlb_seen > 15)
940 break;
941 }
942 }
943 } else {
944 /* Implement me :-) */
945 BUG();
946 }
947 if (save_p)
948 prom_ditlb_set = 1;
949}
950
951/* Give PROM back his world, done during reboots... */
952void prom_reload_locked(void)
953{
954 int i;
955
956 for (i = 0; i < 16; i++) {
957 if (prom_dtlb[i].tlb_ent != -1) {
958 __asm__ __volatile__("stxa %0, [%1] %2\n\t"
959 "membar #Sync"
960 : : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
961 "i" (ASI_DMMU));
962 if (tlb_type == spitfire)
963 spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
964 prom_dtlb[i].tlb_data);
965 else if (tlb_type == cheetah || tlb_type == cheetah_plus)
966 cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent,
967 prom_dtlb[i].tlb_data);
968 }
969
970 if (prom_itlb[i].tlb_ent != -1) {
971 __asm__ __volatile__("stxa %0, [%1] %2\n\t"
972 "membar #Sync"
973 : : "r" (prom_itlb[i].tlb_tag),
974 "r" (TLB_TAG_ACCESS),
975 "i" (ASI_IMMU));
976 if (tlb_type == spitfire)
977 spitfire_put_itlb_data(prom_itlb[i].tlb_ent,
978 prom_itlb[i].tlb_data);
979 else
980 cheetah_put_litlb_data(prom_itlb[i].tlb_ent,
981 prom_itlb[i].tlb_data);
982 }
983 }
984}
985
986#ifdef DCACHE_ALIASING_POSSIBLE
987void __flush_dcache_range(unsigned long start, unsigned long end)
988{
989 unsigned long va;
990
991 if (tlb_type == spitfire) {
992 int n = 0;
993
994 for (va = start; va < end; va += 32) {
995 spitfire_put_dcache_tag(va & 0x3fe0, 0x0);
996 if (++n >= 512)
997 break;
998 }
999 } else {
1000 start = __pa(start);
1001 end = __pa(end);
1002 for (va = start; va < end; va += 32)
1003 __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
1004 "membar #Sync"
1005 : /* no outputs */
1006 : "r" (va),
1007 "i" (ASI_DCACHE_INVALIDATE));
1008 }
1009}
1010#endif /* DCACHE_ALIASING_POSSIBLE */
1011
1012/* If not locked, zap it. */
1013void __flush_tlb_all(void)
1014{
1015 unsigned long pstate;
1016 int i;
1017
1018 __asm__ __volatile__("flushw\n\t"
1019 "rdpr %%pstate, %0\n\t"
1020 "wrpr %0, %1, %%pstate"
1021 : "=r" (pstate)
1022 : "i" (PSTATE_IE));
1023 if (tlb_type == spitfire) {
1024 for (i = 0; i < 64; i++) {
1025 /* Spitfire Errata #32 workaround */
1026 /* NOTE: Always runs on spitfire, so no
1027 * cheetah+ page size encodings.
1028 */
1029 __asm__ __volatile__("stxa %0, [%1] %2\n\t"
1030 "flush %%g6"
1031 : /* No outputs */
1032 : "r" (0),
1033 "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
1034
1035 if (!(spitfire_get_dtlb_data(i) & _PAGE_L)) {
1036 __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
1037 "membar #Sync"
1038 : /* no outputs */
1039 : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
1040 spitfire_put_dtlb_data(i, 0x0UL);
1041 }
1042
1043 /* Spitfire Errata #32 workaround */
1044 /* NOTE: Always runs on spitfire, so no
1045 * cheetah+ page size encodings.
1046 */
1047 __asm__ __volatile__("stxa %0, [%1] %2\n\t"
1048 "flush %%g6"
1049 : /* No outputs */
1050 : "r" (0),
1051 "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
1052
1053 if (!(spitfire_get_itlb_data(i) & _PAGE_L)) {
1054 __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
1055 "membar #Sync"
1056 : /* no outputs */
1057 : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
1058 spitfire_put_itlb_data(i, 0x0UL);
1059 }
1060 }
1061 } else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
1062 cheetah_flush_dtlb_all();
1063 cheetah_flush_itlb_all();
1064 }
1065 __asm__ __volatile__("wrpr %0, 0, %%pstate"
1066 : : "r" (pstate));
1067}
1068
1069/* Caller does TLB context flushing on local CPU if necessary.
1070 * The caller also ensures that CTX_VALID(mm->context) is false.
1071 *
1072 * We must be careful about boundary cases so that we never
1073 * let the user have CTX 0 (nucleus) or we ever use a CTX
1074 * version of zero (and thus NO_CONTEXT would not be caught
1075 * by version mis-match tests in mmu_context.h).
1076 */
1077void get_new_mmu_context(struct mm_struct *mm)
1078{
1079 unsigned long ctx, new_ctx;
1080 unsigned long orig_pgsz_bits;
1081
1082
1083 spin_lock(&ctx_alloc_lock);
1084 orig_pgsz_bits = (mm->context.sparc64_ctx_val & CTX_PGSZ_MASK);
1085 ctx = (tlb_context_cache + 1) & CTX_NR_MASK;
1086 new_ctx = find_next_zero_bit(mmu_context_bmap, 1 << CTX_NR_BITS, ctx);
1087 if (new_ctx >= (1 << CTX_NR_BITS)) {
1088 new_ctx = find_next_zero_bit(mmu_context_bmap, ctx, 1);
1089 if (new_ctx >= ctx) {
1090 int i;
1091 new_ctx = (tlb_context_cache & CTX_VERSION_MASK) +
1092 CTX_FIRST_VERSION;
1093 if (new_ctx == 1)
1094 new_ctx = CTX_FIRST_VERSION;
1095
1096 /* Don't call memset, for 16 entries that's just
1097 * plain silly...
1098 */
1099 mmu_context_bmap[0] = 3;
1100 mmu_context_bmap[1] = 0;
1101 mmu_context_bmap[2] = 0;
1102 mmu_context_bmap[3] = 0;
1103 for (i = 4; i < CTX_BMAP_SLOTS; i += 4) {
1104 mmu_context_bmap[i + 0] = 0;
1105 mmu_context_bmap[i + 1] = 0;
1106 mmu_context_bmap[i + 2] = 0;
1107 mmu_context_bmap[i + 3] = 0;
1108 }
1109 goto out;
1110 }
1111 }
1112 mmu_context_bmap[new_ctx>>6] |= (1UL << (new_ctx & 63));
1113 new_ctx |= (tlb_context_cache & CTX_VERSION_MASK);
1114out:
1115 tlb_context_cache = new_ctx;
1116 mm->context.sparc64_ctx_val = new_ctx | orig_pgsz_bits;
1117 spin_unlock(&ctx_alloc_lock);
1118}
1119
1120#ifndef CONFIG_SMP
1121struct pgtable_cache_struct pgt_quicklists;
1122#endif
1123
1124/* OK, we have to color these pages. The page tables are accessed
1125 * by non-Dcache enabled mapping in the VPTE area by the dtlb_backend.S
1126 * code, as well as by PAGE_OFFSET range direct-mapped addresses by
1127 * other parts of the kernel. By coloring, we make sure that the tlbmiss
1128 * fast handlers do not get data from old/garbage dcache lines that
1129 * correspond to an old/stale virtual address (user/kernel) that
1130 * previously mapped the pagetable page while accessing vpte range
1131 * addresses. The idea is that if the vpte color and PAGE_OFFSET range
1132 * color is the same, then when the kernel initializes the pagetable
1133 * using the later address range, accesses with the first address
1134 * range will see the newly initialized data rather than the garbage.
1135 */
1136#ifdef DCACHE_ALIASING_POSSIBLE
1137#define DC_ALIAS_SHIFT 1
1138#else
1139#define DC_ALIAS_SHIFT 0
1140#endif
Christoph Hellwig8edf72e2005-05-05 14:27:56 -07001141pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142{
1143 struct page *page;
1144 unsigned long color;
1145
1146 {
1147 pte_t *ptep = pte_alloc_one_fast(mm, address);
1148
1149 if (ptep)
1150 return ptep;
1151 }
1152
1153 color = VPTE_COLOR(address);
1154 page = alloc_pages(GFP_KERNEL|__GFP_REPEAT, DC_ALIAS_SHIFT);
1155 if (page) {
1156 unsigned long *to_free;
1157 unsigned long paddr;
1158 pte_t *pte;
1159
1160#ifdef DCACHE_ALIASING_POSSIBLE
1161 set_page_count(page, 1);
1162 ClearPageCompound(page);
1163
1164 set_page_count((page + 1), 1);
1165 ClearPageCompound(page + 1);
1166#endif
1167 paddr = (unsigned long) page_address(page);
1168 memset((char *)paddr, 0, (PAGE_SIZE << DC_ALIAS_SHIFT));
1169
1170 if (!color) {
1171 pte = (pte_t *) paddr;
1172 to_free = (unsigned long *) (paddr + PAGE_SIZE);
1173 } else {
1174 pte = (pte_t *) (paddr + PAGE_SIZE);
1175 to_free = (unsigned long *) paddr;
1176 }
1177
1178#ifdef DCACHE_ALIASING_POSSIBLE
1179 /* Now free the other one up, adjust cache size. */
1180 preempt_disable();
1181 *to_free = (unsigned long) pte_quicklist[color ^ 0x1];
1182 pte_quicklist[color ^ 0x1] = to_free;
1183 pgtable_cache_size++;
1184 preempt_enable();
1185#endif
1186
1187 return pte;
1188 }
1189 return NULL;
1190}
1191
1192void sparc_ultra_dump_itlb(void)
1193{
1194 int slot;
1195
1196 if (tlb_type == spitfire) {
1197 printk ("Contents of itlb: ");
1198 for (slot = 0; slot < 14; slot++) printk (" ");
1199 printk ("%2x:%016lx,%016lx\n",
1200 0,
1201 spitfire_get_itlb_tag(0), spitfire_get_itlb_data(0));
1202 for (slot = 1; slot < 64; slot+=3) {
1203 printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n",
1204 slot,
1205 spitfire_get_itlb_tag(slot), spitfire_get_itlb_data(slot),
1206 slot+1,
1207 spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1),
1208 slot+2,
1209 spitfire_get_itlb_tag(slot+2), spitfire_get_itlb_data(slot+2));
1210 }
1211 } else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
1212 printk ("Contents of itlb0:\n");
1213 for (slot = 0; slot < 16; slot+=2) {
1214 printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
1215 slot,
1216 cheetah_get_litlb_tag(slot), cheetah_get_litlb_data(slot),
1217 slot+1,
1218 cheetah_get_litlb_tag(slot+1), cheetah_get_litlb_data(slot+1));
1219 }
1220 printk ("Contents of itlb2:\n");
1221 for (slot = 0; slot < 128; slot+=2) {
1222 printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
1223 slot,
1224 cheetah_get_itlb_tag(slot), cheetah_get_itlb_data(slot),
1225 slot+1,
1226 cheetah_get_itlb_tag(slot+1), cheetah_get_itlb_data(slot+1));
1227 }
1228 }
1229}
1230
1231void sparc_ultra_dump_dtlb(void)
1232{
1233 int slot;
1234
1235 if (tlb_type == spitfire) {
1236 printk ("Contents of dtlb: ");
1237 for (slot = 0; slot < 14; slot++) printk (" ");
1238 printk ("%2x:%016lx,%016lx\n", 0,
1239 spitfire_get_dtlb_tag(0), spitfire_get_dtlb_data(0));
1240 for (slot = 1; slot < 64; slot+=3) {
1241 printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n",
1242 slot,
1243 spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot),
1244 slot+1,
1245 spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1),
1246 slot+2,
1247 spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2));
1248 }
1249 } else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
1250 printk ("Contents of dtlb0:\n");
1251 for (slot = 0; slot < 16; slot+=2) {
1252 printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
1253 slot,
1254 cheetah_get_ldtlb_tag(slot), cheetah_get_ldtlb_data(slot),
1255 slot+1,
1256 cheetah_get_ldtlb_tag(slot+1), cheetah_get_ldtlb_data(slot+1));
1257 }
1258 printk ("Contents of dtlb2:\n");
1259 for (slot = 0; slot < 512; slot+=2) {
1260 printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
1261 slot,
1262 cheetah_get_dtlb_tag(slot, 2), cheetah_get_dtlb_data(slot, 2),
1263 slot+1,
1264 cheetah_get_dtlb_tag(slot+1, 2), cheetah_get_dtlb_data(slot+1, 2));
1265 }
1266 if (tlb_type == cheetah_plus) {
1267 printk ("Contents of dtlb3:\n");
1268 for (slot = 0; slot < 512; slot+=2) {
1269 printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
1270 slot,
1271 cheetah_get_dtlb_tag(slot, 3), cheetah_get_dtlb_data(slot, 3),
1272 slot+1,
1273 cheetah_get_dtlb_tag(slot+1, 3), cheetah_get_dtlb_data(slot+1, 3));
1274 }
1275 }
1276 }
1277}
1278
1279extern unsigned long cmdline_memory_size;
1280
1281unsigned long __init bootmem_init(unsigned long *pages_avail)
1282{
1283 unsigned long bootmap_size, start_pfn, end_pfn;
1284 unsigned long end_of_phys_memory = 0UL;
1285 unsigned long bootmap_pfn, bytes_avail, size;
1286 int i;
1287
1288#ifdef CONFIG_DEBUG_BOOTMEM
David S. Miller13edad72005-09-29 17:58:26 -07001289 prom_printf("bootmem_init: Scan pavail, ");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290#endif
1291
1292 bytes_avail = 0UL;
David S. Miller13edad72005-09-29 17:58:26 -07001293 for (i = 0; i < pavail_ents; i++) {
1294 end_of_phys_memory = pavail[i].phys_addr +
1295 pavail[i].reg_size;
1296 bytes_avail += pavail[i].reg_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 if (cmdline_memory_size) {
1298 if (bytes_avail > cmdline_memory_size) {
1299 unsigned long slack = bytes_avail - cmdline_memory_size;
1300
1301 bytes_avail -= slack;
1302 end_of_phys_memory -= slack;
1303
David S. Miller13edad72005-09-29 17:58:26 -07001304 pavail[i].reg_size -= slack;
1305 if ((long)pavail[i].reg_size <= 0L) {
1306 pavail[i].phys_addr = 0xdeadbeefUL;
1307 pavail[i].reg_size = 0UL;
1308 pavail_ents = i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 } else {
David S. Miller13edad72005-09-29 17:58:26 -07001310 pavail[i+1].reg_size = 0Ul;
1311 pavail[i+1].phys_addr = 0xdeadbeefUL;
1312 pavail_ents = i + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 }
1314 break;
1315 }
1316 }
1317 }
1318
1319 *pages_avail = bytes_avail >> PAGE_SHIFT;
1320
1321 /* Start with page aligned address of last symbol in kernel
1322 * image. The kernel is hard mapped below PAGE_OFFSET in a
1323 * 4MB locked TLB translation.
1324 */
1325 start_pfn = PAGE_ALIGN(kern_base + kern_size) >> PAGE_SHIFT;
1326
1327 bootmap_pfn = start_pfn;
1328
1329 end_pfn = end_of_phys_memory >> PAGE_SHIFT;
1330
1331#ifdef CONFIG_BLK_DEV_INITRD
1332 /* Now have to check initial ramdisk, so that bootmap does not overwrite it */
1333 if (sparc_ramdisk_image || sparc_ramdisk_image64) {
1334 unsigned long ramdisk_image = sparc_ramdisk_image ?
1335 sparc_ramdisk_image : sparc_ramdisk_image64;
1336 if (ramdisk_image >= (unsigned long)_end - 2 * PAGE_SIZE)
1337 ramdisk_image -= KERNBASE;
1338 initrd_start = ramdisk_image + phys_base;
1339 initrd_end = initrd_start + sparc_ramdisk_size;
1340 if (initrd_end > end_of_phys_memory) {
1341 printk(KERN_CRIT "initrd extends beyond end of memory "
1342 "(0x%016lx > 0x%016lx)\ndisabling initrd\n",
1343 initrd_end, end_of_phys_memory);
1344 initrd_start = 0;
1345 }
1346 if (initrd_start) {
1347 if (initrd_start >= (start_pfn << PAGE_SHIFT) &&
1348 initrd_start < (start_pfn << PAGE_SHIFT) + 2 * PAGE_SIZE)
1349 bootmap_pfn = PAGE_ALIGN (initrd_end) >> PAGE_SHIFT;
1350 }
1351 }
1352#endif
1353 /* Initialize the boot-time allocator. */
1354 max_pfn = max_low_pfn = end_pfn;
1355 min_low_pfn = pfn_base;
1356
1357#ifdef CONFIG_DEBUG_BOOTMEM
1358 prom_printf("init_bootmem(min[%lx], bootmap[%lx], max[%lx])\n",
1359 min_low_pfn, bootmap_pfn, max_low_pfn);
1360#endif
1361 bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap_pfn, pfn_base, end_pfn);
1362
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 /* Now register the available physical memory with the
1364 * allocator.
1365 */
David S. Miller13edad72005-09-29 17:58:26 -07001366 for (i = 0; i < pavail_ents; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367#ifdef CONFIG_DEBUG_BOOTMEM
David S. Miller13edad72005-09-29 17:58:26 -07001368 prom_printf("free_bootmem(pavail:%d): base[%lx] size[%lx]\n",
1369 i, pavail[i].phys_addr, pavail[i].reg_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370#endif
David S. Miller13edad72005-09-29 17:58:26 -07001371 free_bootmem(pavail[i].phys_addr, pavail[i].reg_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 }
1373
1374#ifdef CONFIG_BLK_DEV_INITRD
1375 if (initrd_start) {
1376 size = initrd_end - initrd_start;
1377
1378 /* Resert the initrd image area. */
1379#ifdef CONFIG_DEBUG_BOOTMEM
1380 prom_printf("reserve_bootmem(initrd): base[%llx] size[%lx]\n",
1381 initrd_start, initrd_end);
1382#endif
1383 reserve_bootmem(initrd_start, size);
1384 *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
1385
1386 initrd_start += PAGE_OFFSET;
1387 initrd_end += PAGE_OFFSET;
1388 }
1389#endif
1390 /* Reserve the kernel text/data/bss. */
1391#ifdef CONFIG_DEBUG_BOOTMEM
1392 prom_printf("reserve_bootmem(kernel): base[%lx] size[%lx]\n", kern_base, kern_size);
1393#endif
1394 reserve_bootmem(kern_base, kern_size);
1395 *pages_avail -= PAGE_ALIGN(kern_size) >> PAGE_SHIFT;
1396
1397 /* Reserve the bootmem map. We do not account for it
1398 * in pages_avail because we will release that memory
1399 * in free_all_bootmem.
1400 */
1401 size = bootmap_size;
1402#ifdef CONFIG_DEBUG_BOOTMEM
1403 prom_printf("reserve_bootmem(bootmap): base[%lx] size[%lx]\n",
1404 (bootmap_pfn << PAGE_SHIFT), size);
1405#endif
1406 reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size);
1407 *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
1408
1409 return end_pfn;
1410}
1411
David S. Miller56425302005-09-25 16:46:57 -07001412#ifdef CONFIG_DEBUG_PAGEALLOC
1413static unsigned long kernel_map_range(unsigned long pstart, unsigned long pend, pgprot_t prot)
1414{
1415 unsigned long vstart = PAGE_OFFSET + pstart;
1416 unsigned long vend = PAGE_OFFSET + pend;
1417 unsigned long alloc_bytes = 0UL;
1418
1419 if ((vstart & ~PAGE_MASK) || (vend & ~PAGE_MASK)) {
David S. Miller13edad72005-09-29 17:58:26 -07001420 prom_printf("kernel_map: Unaligned physmem[%lx:%lx]\n",
David S. Miller56425302005-09-25 16:46:57 -07001421 vstart, vend);
1422 prom_halt();
1423 }
1424
1425 while (vstart < vend) {
1426 unsigned long this_end, paddr = __pa(vstart);
1427 pgd_t *pgd = pgd_offset_k(vstart);
1428 pud_t *pud;
1429 pmd_t *pmd;
1430 pte_t *pte;
1431
1432 pud = pud_offset(pgd, vstart);
1433 if (pud_none(*pud)) {
1434 pmd_t *new;
1435
1436 new = __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
1437 alloc_bytes += PAGE_SIZE;
1438 pud_populate(&init_mm, pud, new);
1439 }
1440
1441 pmd = pmd_offset(pud, vstart);
1442 if (!pmd_present(*pmd)) {
1443 pte_t *new;
1444
1445 new = __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
1446 alloc_bytes += PAGE_SIZE;
1447 pmd_populate_kernel(&init_mm, pmd, new);
1448 }
1449
1450 pte = pte_offset_kernel(pmd, vstart);
1451 this_end = (vstart + PMD_SIZE) & PMD_MASK;
1452 if (this_end > vend)
1453 this_end = vend;
1454
1455 while (vstart < this_end) {
1456 pte_val(*pte) = (paddr | pgprot_val(prot));
1457
1458 vstart += PAGE_SIZE;
1459 paddr += PAGE_SIZE;
1460 pte++;
1461 }
1462 }
1463
1464 return alloc_bytes;
1465}
1466
David S. Miller13edad72005-09-29 17:58:26 -07001467static struct linux_prom64_registers pall[MAX_BANKS] __initdata;
1468static int pall_ents __initdata;
1469
David S. Miller56425302005-09-25 16:46:57 -07001470extern unsigned int kvmap_linear_patch[1];
1471
1472static void __init kernel_physical_mapping_init(void)
1473{
David S. Miller13edad72005-09-29 17:58:26 -07001474 unsigned long i, mem_alloced = 0UL;
David S. Miller56425302005-09-25 16:46:57 -07001475
David S. Miller13edad72005-09-29 17:58:26 -07001476 read_obp_memory("reg", &pall[0], &pall_ents);
1477
1478 for (i = 0; i < pall_ents; i++) {
David S. Miller56425302005-09-25 16:46:57 -07001479 unsigned long phys_start, phys_end;
1480
David S. Miller13edad72005-09-29 17:58:26 -07001481 phys_start = pall[i].phys_addr;
1482 phys_end = phys_start + pall[i].reg_size;
David S. Miller56425302005-09-25 16:46:57 -07001483 mem_alloced += kernel_map_range(phys_start, phys_end,
1484 PAGE_KERNEL);
David S. Miller56425302005-09-25 16:46:57 -07001485 }
1486
1487 printk("Allocated %ld bytes for kernel page tables.\n",
1488 mem_alloced);
1489
1490 kvmap_linear_patch[0] = 0x01000000; /* nop */
1491 flushi(&kvmap_linear_patch[0]);
1492
1493 __flush_tlb_all();
1494}
1495
1496void kernel_map_pages(struct page *page, int numpages, int enable)
1497{
1498 unsigned long phys_start = page_to_pfn(page) << PAGE_SHIFT;
1499 unsigned long phys_end = phys_start + (numpages * PAGE_SIZE);
1500
1501 kernel_map_range(phys_start, phys_end,
1502 (enable ? PAGE_KERNEL : __pgprot(0)));
1503
1504 /* we should perform an IPI and flush all tlbs,
1505 * but that can deadlock->flush only current cpu.
1506 */
1507 __flush_tlb_kernel_range(PAGE_OFFSET + phys_start,
1508 PAGE_OFFSET + phys_end);
1509}
1510#endif
1511
David S. Miller10147572005-09-28 21:46:43 -07001512unsigned long __init find_ecache_flush_span(unsigned long size)
1513{
David S. Miller13edad72005-09-29 17:58:26 -07001514 int i;
David S. Miller10147572005-09-28 21:46:43 -07001515
David S. Miller13edad72005-09-29 17:58:26 -07001516 for (i = 0; i < pavail_ents; i++) {
1517 if (pavail[i].reg_size >= size)
1518 return pavail[i].phys_addr;
David S. Miller10147572005-09-28 21:46:43 -07001519 }
1520
1521 return ~0UL;
1522}
1523
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524/* paging_init() sets up the page tables */
1525
1526extern void cheetah_ecache_flush_init(void);
1527
1528static unsigned long last_valid_pfn;
David S. Miller56425302005-09-25 16:46:57 -07001529pgd_t swapper_pg_dir[2048];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530
1531void __init paging_init(void)
1532{
David S. Miller2bdb3cb2005-09-22 01:08:57 -07001533 unsigned long end_pfn, pages_avail, shift;
David S. Miller0836a0e2005-09-28 21:38:08 -07001534 unsigned long real_end, i;
1535
David S. Miller13edad72005-09-29 17:58:26 -07001536 /* Find available physical memory... */
1537 read_obp_memory("available", &pavail[0], &pavail_ents);
David S. Miller0836a0e2005-09-28 21:38:08 -07001538
1539 phys_base = 0xffffffffffffffffUL;
David S. Miller13edad72005-09-29 17:58:26 -07001540 for (i = 0; i < pavail_ents; i++)
1541 phys_base = min(phys_base, pavail[i].phys_addr);
David S. Miller0836a0e2005-09-28 21:38:08 -07001542
David S. Miller0836a0e2005-09-28 21:38:08 -07001543 pfn_base = phys_base >> PAGE_SHIFT;
1544
1545 kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL;
1546 kern_size = (unsigned long)&_end - (unsigned long)KERNBASE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547
1548 set_bit(0, mmu_context_bmap);
1549
David S. Miller2bdb3cb2005-09-22 01:08:57 -07001550 shift = kern_base + PAGE_OFFSET - ((unsigned long)KERNBASE);
1551
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 real_end = (unsigned long)_end;
1553 if ((real_end > ((unsigned long)KERNBASE + 0x400000)))
1554 bigkernel = 1;
David S. Miller2bdb3cb2005-09-22 01:08:57 -07001555 if ((real_end > ((unsigned long)KERNBASE + 0x800000))) {
1556 prom_printf("paging_init: Kernel > 8MB, too large.\n");
1557 prom_halt();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 }
David S. Miller2bdb3cb2005-09-22 01:08:57 -07001559
1560 /* Set kernel pgd to upper alias so physical page computations
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 * work.
1562 */
1563 init_mm.pgd += ((shift) / (sizeof(pgd_t)));
1564
David S. Miller56425302005-09-25 16:46:57 -07001565 memset(swapper_low_pmd_dir, 0, sizeof(swapper_low_pmd_dir));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566
1567 /* Now can init the kernel/bad page tables. */
1568 pud_set(pud_offset(&swapper_pg_dir[0], 0),
David S. Miller56425302005-09-25 16:46:57 -07001569 swapper_low_pmd_dir + (shift / sizeof(pgd_t)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570
David S. Miller2bdb3cb2005-09-22 01:08:57 -07001571 swapper_pgd_zero = pgd_val(swapper_pg_dir[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
David S. Miller5085b4a2005-09-22 00:45:41 -07001573 /* Inherit non-locked OBP mappings. */
1574 inherit_prom_mappings();
1575
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 /* Ok, we can use our TLB miss and window trap handlers safely.
1577 * We need to do a quick peek here to see if we are on StarFire
1578 * or not, so setup_tba can setup the IRQ globals correctly (it
1579 * needs to get the hard smp processor id correctly).
1580 */
1581 {
1582 extern void setup_tba(int);
1583 setup_tba(this_is_starfire);
1584 }
1585
1586 inherit_locked_prom_mappings(1);
1587
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 __flush_tlb_all();
1589
David S. Miller2bdb3cb2005-09-22 01:08:57 -07001590 /* Setup bootmem... */
1591 pages_avail = 0;
1592 last_valid_pfn = end_pfn = bootmem_init(&pages_avail);
1593
David S. Miller56425302005-09-25 16:46:57 -07001594#ifdef CONFIG_DEBUG_PAGEALLOC
1595 kernel_physical_mapping_init();
1596#endif
1597
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 {
1599 unsigned long zones_size[MAX_NR_ZONES];
1600 unsigned long zholes_size[MAX_NR_ZONES];
1601 unsigned long npages;
1602 int znum;
1603
1604 for (znum = 0; znum < MAX_NR_ZONES; znum++)
1605 zones_size[znum] = zholes_size[znum] = 0;
1606
1607 npages = end_pfn - pfn_base;
1608 zones_size[ZONE_DMA] = npages;
1609 zholes_size[ZONE_DMA] = npages - pages_avail;
1610
1611 free_area_init_node(0, &contig_page_data, zones_size,
1612 phys_base >> PAGE_SHIFT, zholes_size);
1613 }
1614
1615 device_scan();
1616}
1617
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618static void __init taint_real_pages(void)
1619{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 int i;
1621
David S. Miller13edad72005-09-29 17:58:26 -07001622 read_obp_memory("available", &pavail_rescan[0], &pavail_rescan_ents);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623
David S. Miller13edad72005-09-29 17:58:26 -07001624 /* Find changes discovered in the physmem available rescan and
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 * reserve the lost portions in the bootmem maps.
1626 */
David S. Miller13edad72005-09-29 17:58:26 -07001627 for (i = 0; i < pavail_ents; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 unsigned long old_start, old_end;
1629
David S. Miller13edad72005-09-29 17:58:26 -07001630 old_start = pavail[i].phys_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 old_end = old_start +
David S. Miller13edad72005-09-29 17:58:26 -07001632 pavail[i].reg_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 while (old_start < old_end) {
1634 int n;
1635
David S. Miller13edad72005-09-29 17:58:26 -07001636 for (n = 0; pavail_rescan_ents; n++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 unsigned long new_start, new_end;
1638
David S. Miller13edad72005-09-29 17:58:26 -07001639 new_start = pavail_rescan[n].phys_addr;
1640 new_end = new_start +
1641 pavail_rescan[n].reg_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642
1643 if (new_start <= old_start &&
1644 new_end >= (old_start + PAGE_SIZE)) {
David S. Miller13edad72005-09-29 17:58:26 -07001645 set_bit(old_start >> 22,
1646 sparc64_valid_addr_bitmap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 goto do_next_page;
1648 }
1649 }
1650 reserve_bootmem(old_start, PAGE_SIZE);
1651
1652 do_next_page:
1653 old_start += PAGE_SIZE;
1654 }
1655 }
1656}
1657
1658void __init mem_init(void)
1659{
1660 unsigned long codepages, datapages, initpages;
1661 unsigned long addr, last;
1662 int i;
1663
1664 i = last_valid_pfn >> ((22 - PAGE_SHIFT) + 6);
1665 i += 1;
David S. Miller2bdb3cb2005-09-22 01:08:57 -07001666 sparc64_valid_addr_bitmap = (unsigned long *) alloc_bootmem(i << 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 if (sparc64_valid_addr_bitmap == NULL) {
1668 prom_printf("mem_init: Cannot alloc valid_addr_bitmap.\n");
1669 prom_halt();
1670 }
1671 memset(sparc64_valid_addr_bitmap, 0, i << 3);
1672
1673 addr = PAGE_OFFSET + kern_base;
1674 last = PAGE_ALIGN(kern_size) + addr;
1675 while (addr < last) {
1676 set_bit(__pa(addr) >> 22, sparc64_valid_addr_bitmap);
1677 addr += PAGE_SIZE;
1678 }
1679
1680 taint_real_pages();
1681
1682 max_mapnr = last_valid_pfn - pfn_base;
1683 high_memory = __va(last_valid_pfn << PAGE_SHIFT);
1684
1685#ifdef CONFIG_DEBUG_BOOTMEM
1686 prom_printf("mem_init: Calling free_all_bootmem().\n");
1687#endif
1688 totalram_pages = num_physpages = free_all_bootmem() - 1;
1689
1690 /*
1691 * Set up the zero page, mark it reserved, so that page count
1692 * is not manipulated when freeing the page from user ptes.
1693 */
1694 mem_map_zero = alloc_pages(GFP_KERNEL|__GFP_ZERO, 0);
1695 if (mem_map_zero == NULL) {
1696 prom_printf("paging_init: Cannot alloc zero page.\n");
1697 prom_halt();
1698 }
1699 SetPageReserved(mem_map_zero);
1700
1701 codepages = (((unsigned long) _etext) - ((unsigned long) _start));
1702 codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT;
1703 datapages = (((unsigned long) _edata) - ((unsigned long) _etext));
1704 datapages = PAGE_ALIGN(datapages) >> PAGE_SHIFT;
1705 initpages = (((unsigned long) __init_end) - ((unsigned long) __init_begin));
1706 initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT;
1707
1708 printk("Memory: %uk available (%ldk kernel code, %ldk data, %ldk init) [%016lx,%016lx]\n",
1709 nr_free_pages() << (PAGE_SHIFT-10),
1710 codepages << (PAGE_SHIFT-10),
1711 datapages << (PAGE_SHIFT-10),
1712 initpages << (PAGE_SHIFT-10),
1713 PAGE_OFFSET, (last_valid_pfn << PAGE_SHIFT));
1714
1715 if (tlb_type == cheetah || tlb_type == cheetah_plus)
1716 cheetah_ecache_flush_init();
1717}
1718
David S. Miller898cf0e2005-09-23 11:59:44 -07001719void free_initmem(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720{
1721 unsigned long addr, initend;
1722
1723 /*
1724 * The init section is aligned to 8k in vmlinux.lds. Page align for >8k pagesizes.
1725 */
1726 addr = PAGE_ALIGN((unsigned long)(__init_begin));
1727 initend = (unsigned long)(__init_end) & PAGE_MASK;
1728 for (; addr < initend; addr += PAGE_SIZE) {
1729 unsigned long page;
1730 struct page *p;
1731
1732 page = (addr +
1733 ((unsigned long) __va(kern_base)) -
1734 ((unsigned long) KERNBASE));
1735 memset((void *)addr, 0xcc, PAGE_SIZE);
1736 p = virt_to_page(page);
1737
1738 ClearPageReserved(p);
1739 set_page_count(p, 1);
1740 __free_page(p);
1741 num_physpages++;
1742 totalram_pages++;
1743 }
1744}
1745
1746#ifdef CONFIG_BLK_DEV_INITRD
1747void free_initrd_mem(unsigned long start, unsigned long end)
1748{
1749 if (start < end)
1750 printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
1751 for (; start < end; start += PAGE_SIZE) {
1752 struct page *p = virt_to_page(start);
1753
1754 ClearPageReserved(p);
1755 set_page_count(p, 1);
1756 __free_page(p);
1757 num_physpages++;
1758 totalram_pages++;
1759 }
1760}
1761#endif