Commit | Line | Data |
---|---|---|
45890f6d VG |
1 | /* |
2 | * Copyright (C) 2015 Synopsys, Inc. (www.synopsys.com) | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License version 2 as | |
6 | * published by the Free Software Foundation. | |
7 | * | |
8 | */ | |
9 | ||
10 | #include <linux/bootmem.h> | |
11 | #include <linux/export.h> | |
12 | #include <linux/highmem.h> | |
13 | #include <asm/processor.h> | |
14 | #include <asm/pgtable.h> | |
15 | #include <asm/pgalloc.h> | |
16 | #include <asm/tlbflush.h> | |
17 | ||
18 | /* | |
19 | * HIGHMEM API: | |
20 | * | |
7423cc0c | 21 | * kmap() API provides sleep semantics hence referred to as "permanent maps" |
45890f6d VG |
22 | * It allows mapping LAST_PKMAP pages, using @last_pkmap_nr as the cursor |
23 | * for book-keeping | |
24 | * | |
25 | * kmap_atomic() can't sleep (calls pagefault_disable()), thus it provides | |
26 | * shortlived ala "temporary mappings" which historically were implemented as | |
27 | * fixmaps (compile time addr etc). Their book-keeping is done per cpu. | |
28 | * | |
29 | * Both these facts combined (preemption disabled and per-cpu allocation) | |
30 | * means the total number of concurrent fixmaps will be limited to max | |
31 | * such allocations in a single control path. Thus KM_TYPE_NR (another | |
32 | * historic relic) is a small'ish number which caps max percpu fixmaps | |
33 | * | |
34 | * ARC HIGHMEM Details | |
35 | * | |
36 | * - the kernel vaddr space from 0x7z to 0x8z (currently used by vmalloc/module) | |
37 | * is now shared between vmalloc and kmap (non overlapping though) | |
38 | * | |
39 | * - Both fixmap/pkmap use a dedicated page table each, hooked up to swapper PGD | |
40 | * This means each only has 1 PGDIR_SIZE worth of kvaddr mappings, which means | |
41 | * 2M of kvaddr space for typical config (8K page and 11:8:13 traversal split) | |
42 | * | |
43 | * - fixmap anyhow needs a limited number of mappings. So 2M kvaddr == 256 PTE | |
44 | * slots across NR_CPUS would be more than sufficient (generic code defines | |
45 | * KM_TYPE_NR as 20). | |
46 | * | |
47 | * - pkmap being preemptible, in theory could do with more than 256 concurrent | |
48 | * mappings. However, generic pkmap code: map_new_virtual(), doesn't traverse | |
49 | * the PGD and only works with a single page table @pkmap_page_table, hence | |
50 | * sets the limit | |
51 | */ | |
52 | ||
53 | extern pte_t * pkmap_page_table; | |
54 | static pte_t * fixmap_page_table; | |
55 | ||
56 | void *kmap(struct page *page) | |
57 | { | |
58 | BUG_ON(in_interrupt()); | |
59 | if (!PageHighMem(page)) | |
60 | return page_address(page); | |
61 | ||
62 | return kmap_high(page); | |
63 | } | |
64 | ||
65 | void *kmap_atomic(struct page *page) | |
66 | { | |
67 | int idx, cpu_idx; | |
68 | unsigned long vaddr; | |
69 | ||
70 | preempt_disable(); | |
71 | pagefault_disable(); | |
72 | if (!PageHighMem(page)) | |
73 | return page_address(page); | |
74 | ||
75 | cpu_idx = kmap_atomic_idx_push(); | |
76 | idx = cpu_idx + KM_TYPE_NR * smp_processor_id(); | |
77 | vaddr = FIXMAP_ADDR(idx); | |
78 | ||
79 | set_pte_at(&init_mm, vaddr, fixmap_page_table + idx, | |
80 | mk_pte(page, kmap_prot)); | |
81 | ||
82 | return (void *)vaddr; | |
83 | } | |
84 | EXPORT_SYMBOL(kmap_atomic); | |
85 | ||
86 | void __kunmap_atomic(void *kv) | |
87 | { | |
88 | unsigned long kvaddr = (unsigned long)kv; | |
89 | ||
90 | if (kvaddr >= FIXMAP_BASE && kvaddr < (FIXMAP_BASE + FIXMAP_SIZE)) { | |
91 | ||
92 | /* | |
93 | * Because preemption is disabled, this vaddr can be associated | |
94 | * with the current allocated index. | |
95 | * But in case of multiple live kmap_atomic(), it still relies on | |
96 | * callers to unmap in right order. | |
97 | */ | |
98 | int cpu_idx = kmap_atomic_idx(); | |
99 | int idx = cpu_idx + KM_TYPE_NR * smp_processor_id(); | |
100 | ||
101 | WARN_ON(kvaddr != FIXMAP_ADDR(idx)); | |
102 | ||
103 | pte_clear(&init_mm, kvaddr, fixmap_page_table + idx); | |
104 | local_flush_tlb_kernel_range(kvaddr, kvaddr + PAGE_SIZE); | |
105 | ||
106 | kmap_atomic_idx_pop(); | |
107 | } | |
108 | ||
109 | pagefault_enable(); | |
110 | preempt_enable(); | |
111 | } | |
112 | EXPORT_SYMBOL(__kunmap_atomic); | |
113 | ||
899cfd2b | 114 | static noinline pte_t * __init alloc_kmap_pgtable(unsigned long kvaddr) |
45890f6d VG |
115 | { |
116 | pgd_t *pgd_k; | |
117 | pud_t *pud_k; | |
118 | pmd_t *pmd_k; | |
119 | pte_t *pte_k; | |
120 | ||
121 | pgd_k = pgd_offset_k(kvaddr); | |
122 | pud_k = pud_offset(pgd_k, kvaddr); | |
123 | pmd_k = pmd_offset(pud_k, kvaddr); | |
124 | ||
125 | pte_k = (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE); | |
126 | pmd_populate_kernel(&init_mm, pmd_k, pte_k); | |
127 | return pte_k; | |
128 | } | |
129 | ||
899cfd2b | 130 | void __init kmap_init(void) |
45890f6d VG |
131 | { |
132 | /* Due to recursive include hell, we can't do this in processor.h */ | |
133 | BUILD_BUG_ON(PAGE_OFFSET < (VMALLOC_END + FIXMAP_SIZE + PKMAP_SIZE)); | |
134 | ||
135 | BUILD_BUG_ON(KM_TYPE_NR > PTRS_PER_PTE); | |
136 | pkmap_page_table = alloc_kmap_pgtable(PKMAP_BASE); | |
137 | ||
138 | BUILD_BUG_ON(LAST_PKMAP > PTRS_PER_PTE); | |
139 | fixmap_page_table = alloc_kmap_pgtable(FIXMAP_BASE); | |
140 | } |