Commit | Line | Data |
---|---|---|
e5083a63 JW |
1 | /* |
2 | * xtensa mmu stuff | |
3 | * | |
4 | * Extracted from init.c | |
5 | */ | |
65559100 | 6 | #include <linux/bootmem.h> |
e5083a63 JW |
7 | #include <linux/percpu.h> |
8 | #include <linux/init.h> | |
9 | #include <linux/string.h> | |
10 | #include <linux/slab.h> | |
11 | #include <linux/cache.h> | |
12 | ||
13 | #include <asm/tlb.h> | |
14 | #include <asm/tlbflush.h> | |
15 | #include <asm/mmu_context.h> | |
16 | #include <asm/page.h> | |
6cb97111 BS |
17 | #include <asm/initialize_mmu.h> |
18 | #include <asm/io.h> | |
e5083a63 | 19 | |
65559100 MF |
20 | #if defined(CONFIG_HIGHMEM) |
21 | static void * __init init_pmd(unsigned long vaddr) | |
22 | { | |
23 | pgd_t *pgd = pgd_offset_k(vaddr); | |
24 | pmd_t *pmd = pmd_offset(pgd, vaddr); | |
25 | ||
26 | if (pmd_none(*pmd)) { | |
27 | unsigned i; | |
28 | pte_t *pte = alloc_bootmem_low_pages(PAGE_SIZE); | |
29 | ||
30 | for (i = 0; i < 1024; i++) | |
31 | pte_clear(NULL, 0, pte + i); | |
32 | ||
33 | set_pmd(pmd, __pmd(((unsigned long)pte) & PAGE_MASK)); | |
34 | BUG_ON(pte != pte_offset_kernel(pmd, 0)); | |
35 | pr_debug("%s: vaddr: 0x%08lx, pmd: 0x%p, pte: 0x%p\n", | |
36 | __func__, vaddr, pmd, pte); | |
37 | return pte; | |
38 | } else { | |
39 | return pte_offset_kernel(pmd, 0); | |
40 | } | |
41 | } | |
42 | ||
43 | static void __init fixedrange_init(void) | |
44 | { | |
45 | BUILD_BUG_ON(FIXADDR_SIZE > PMD_SIZE); | |
46 | init_pmd(__fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK); | |
47 | } | |
48 | #endif | |
49 | ||
e5083a63 JW |
50 | void __init paging_init(void) |
51 | { | |
52 | memset(swapper_pg_dir, 0, PAGE_SIZE); | |
65559100 MF |
53 | #ifdef CONFIG_HIGHMEM |
54 | fixedrange_init(); | |
55 | pkmap_page_table = init_pmd(PKMAP_BASE); | |
56 | kmap_init(); | |
57 | #endif | |
e5083a63 JW |
58 | } |
59 | ||
60 | /* | |
61 | * Flush the mmu and reset associated register to default values. | |
62 | */ | |
f615136c | 63 | void init_mmu(void) |
e5083a63 | 64 | { |
e85e335f MF |
65 | #if !(XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY) |
66 | /* | |
67 | * Writing zeros to the instruction and data TLBCFG special | |
68 | * registers ensure that valid values exist in the register. | |
69 | * | |
70 | * For existing PGSZID<w> fields, zero selects the first element | |
71 | * of the page-size array. For nonexistent PGSZID<w> fields, | |
72 | * zero is the best value to write. Also, when changing PGSZID<w> | |
e5083a63 JW |
73 | * fields, the corresponding TLB must be flushed. |
74 | */ | |
75 | set_itlbcfg_register(0); | |
76 | set_dtlbcfg_register(0); | |
e85e335f | 77 | #endif |
9848e49a | 78 | #if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && defined(CONFIG_OF) |
6cb97111 BS |
79 | /* |
80 | * Update the IO area mapping in case xtensa_kio_paddr has changed | |
81 | */ | |
82 | write_dtlb_entry(__pte(xtensa_kio_paddr + CA_WRITEBACK), | |
83 | XCHAL_KIO_CACHED_VADDR + 6); | |
84 | write_itlb_entry(__pte(xtensa_kio_paddr + CA_WRITEBACK), | |
85 | XCHAL_KIO_CACHED_VADDR + 6); | |
86 | write_dtlb_entry(__pte(xtensa_kio_paddr + CA_BYPASS), | |
87 | XCHAL_KIO_BYPASS_VADDR + 6); | |
88 | write_itlb_entry(__pte(xtensa_kio_paddr + CA_BYPASS), | |
89 | XCHAL_KIO_BYPASS_VADDR + 6); | |
90 | #endif | |
91 | ||
f615136c | 92 | local_flush_tlb_all(); |
e5083a63 JW |
93 | |
94 | /* Set rasid register to a known value. */ | |
95 | ||
ec747b21 | 96 | set_rasid_register(ASID_INSERT(ASID_USER_FIRST)); |
e5083a63 JW |
97 | |
98 | /* Set PTEVADDR special register to the start of the page | |
99 | * table, which is in kernel mappable space (ie. not | |
100 | * statically mapped). This register's value is undefined on | |
101 | * reset. | |
102 | */ | |
103 | set_ptevaddr_register(PGTABLE_START); | |
104 | } |