diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sh/include/asm/io.h | 23 | ||||
-rw-r--r-- | arch/sh/include/asm/mmu.h | 31 | ||||
-rw-r--r-- | arch/sh/mm/ioremap.c | 70 | ||||
-rw-r--r-- | arch/sh/mm/ioremap_fixed.c | 11 | ||||
-rw-r--r-- | arch/sh/mm/pmb.c | 256 |
5 files changed, 223 insertions, 168 deletions
diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index 7dab7b23a5ec..f689554e17c1 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h | |||
@@ -291,21 +291,21 @@ unsigned long long poke_real_address_q(unsigned long long addr, | |||
291 | * doesn't exist, so everything must go through page tables. | 291 | * doesn't exist, so everything must go through page tables. |
292 | */ | 292 | */ |
293 | #ifdef CONFIG_MMU | 293 | #ifdef CONFIG_MMU |
294 | void __iomem *__ioremap_caller(unsigned long offset, unsigned long size, | 294 | void __iomem *__ioremap_caller(phys_addr_t offset, unsigned long size, |
295 | pgprot_t prot, void *caller); | 295 | pgprot_t prot, void *caller); |
296 | void __iounmap(void __iomem *addr); | 296 | void __iounmap(void __iomem *addr); |
297 | 297 | ||
298 | static inline void __iomem * | 298 | static inline void __iomem * |
299 | __ioremap(unsigned long offset, unsigned long size, pgprot_t prot) | 299 | __ioremap(phys_addr_t offset, unsigned long size, pgprot_t prot) |
300 | { | 300 | { |
301 | return __ioremap_caller(offset, size, prot, __builtin_return_address(0)); | 301 | return __ioremap_caller(offset, size, prot, __builtin_return_address(0)); |
302 | } | 302 | } |
303 | 303 | ||
304 | static inline void __iomem * | 304 | static inline void __iomem * |
305 | __ioremap_29bit(unsigned long offset, unsigned long size, pgprot_t prot) | 305 | __ioremap_29bit(phys_addr_t offset, unsigned long size, pgprot_t prot) |
306 | { | 306 | { |
307 | #ifdef CONFIG_29BIT | 307 | #ifdef CONFIG_29BIT |
308 | unsigned long last_addr = offset + size - 1; | 308 | phys_addr_t last_addr = offset + size - 1; |
309 | 309 | ||
310 | /* | 310 | /* |
311 | * For P1 and P2 space this is trivial, as everything is already | 311 | * For P1 and P2 space this is trivial, as everything is already |
@@ -329,7 +329,7 @@ __ioremap_29bit(unsigned long offset, unsigned long size, pgprot_t prot) | |||
329 | } | 329 | } |
330 | 330 | ||
331 | static inline void __iomem * | 331 | static inline void __iomem * |
332 | __ioremap_mode(unsigned long offset, unsigned long size, pgprot_t prot) | 332 | __ioremap_mode(phys_addr_t offset, unsigned long size, pgprot_t prot) |
333 | { | 333 | { |
334 | void __iomem *ret; | 334 | void __iomem *ret; |
335 | 335 | ||
@@ -349,35 +349,32 @@ __ioremap_mode(unsigned long offset, unsigned long size, pgprot_t prot) | |||
349 | #define __iounmap(addr) do { } while (0) | 349 | #define __iounmap(addr) do { } while (0) |
350 | #endif /* CONFIG_MMU */ | 350 | #endif /* CONFIG_MMU */ |
351 | 351 | ||
352 | static inline void __iomem * | 352 | static inline void __iomem *ioremap(phys_addr_t offset, unsigned long size) |
353 | ioremap(unsigned long offset, unsigned long size) | ||
354 | { | 353 | { |
355 | return __ioremap_mode(offset, size, PAGE_KERNEL_NOCACHE); | 354 | return __ioremap_mode(offset, size, PAGE_KERNEL_NOCACHE); |
356 | } | 355 | } |
357 | 356 | ||
358 | static inline void __iomem * | 357 | static inline void __iomem * |
359 | ioremap_cache(unsigned long offset, unsigned long size) | 358 | ioremap_cache(phys_addr_t offset, unsigned long size) |
360 | { | 359 | { |
361 | return __ioremap_mode(offset, size, PAGE_KERNEL); | 360 | return __ioremap_mode(offset, size, PAGE_KERNEL); |
362 | } | 361 | } |
363 | 362 | ||
364 | #ifdef CONFIG_HAVE_IOREMAP_PROT | 363 | #ifdef CONFIG_HAVE_IOREMAP_PROT |
365 | static inline void __iomem * | 364 | static inline void __iomem * |
366 | ioremap_prot(resource_size_t offset, unsigned long size, unsigned long flags) | 365 | ioremap_prot(phys_addr_t offset, unsigned long size, unsigned long flags) |
367 | { | 366 | { |
368 | return __ioremap_mode(offset, size, __pgprot(flags)); | 367 | return __ioremap_mode(offset, size, __pgprot(flags)); |
369 | } | 368 | } |
370 | #endif | 369 | #endif |
371 | 370 | ||
372 | #ifdef CONFIG_IOREMAP_FIXED | 371 | #ifdef CONFIG_IOREMAP_FIXED |
373 | extern void __iomem *ioremap_fixed(resource_size_t, unsigned long, | 372 | extern void __iomem *ioremap_fixed(phys_addr_t, unsigned long, pgprot_t); |
374 | unsigned long, pgprot_t); | ||
375 | extern int iounmap_fixed(void __iomem *); | 373 | extern int iounmap_fixed(void __iomem *); |
376 | extern void ioremap_fixed_init(void); | 374 | extern void ioremap_fixed_init(void); |
377 | #else | 375 | #else |
378 | static inline void __iomem * | 376 | static inline void __iomem * |
379 | ioremap_fixed(resource_size_t phys_addr, unsigned long offset, | 377 | ioremap_fixed(phys_addr_t phys_addr, unsigned long size, pgprot_t prot) |
380 | unsigned long size, pgprot_t prot) | ||
381 | { | 378 | { |
382 | BUG(); | 379 | BUG(); |
383 | return NULL; | 380 | return NULL; |
diff --git a/arch/sh/include/asm/mmu.h b/arch/sh/include/asm/mmu.h index 15a05b615ba7..19fe84550b49 100644 --- a/arch/sh/include/asm/mmu.h +++ b/arch/sh/include/asm/mmu.h | |||
@@ -55,19 +55,29 @@ typedef struct { | |||
55 | 55 | ||
56 | #ifdef CONFIG_PMB | 56 | #ifdef CONFIG_PMB |
57 | /* arch/sh/mm/pmb.c */ | 57 | /* arch/sh/mm/pmb.c */ |
58 | long pmb_remap(unsigned long virt, unsigned long phys, | ||
59 | unsigned long size, pgprot_t prot); | ||
60 | void pmb_unmap(unsigned long addr); | ||
61 | void pmb_init(void); | ||
62 | bool __in_29bit_mode(void); | 58 | bool __in_29bit_mode(void); |
59 | |||
60 | void pmb_init(void); | ||
61 | int pmb_bolt_mapping(unsigned long virt, phys_addr_t phys, | ||
62 | unsigned long size, pgprot_t prot); | ||
63 | void __iomem *pmb_remap_caller(phys_addr_t phys, unsigned long size, | ||
64 | pgprot_t prot, void *caller); | ||
65 | int pmb_unmap(void __iomem *addr); | ||
66 | |||
63 | #else | 67 | #else |
64 | static inline long pmb_remap(unsigned long virt, unsigned long phys, | 68 | |
65 | unsigned long size, pgprot_t prot) | 69 | static inline void __iomem * |
70 | pmb_remap_caller(phys_addr_t phys, unsigned long size, | ||
71 | pgprot_t prot, void *caller) | ||
72 | { | ||
73 | return NULL; | ||
74 | } | ||
75 | |||
76 | static inline int pmb_unmap(void __iomem *addr) | ||
66 | { | 77 | { |
67 | return -EINVAL; | 78 | return -EINVAL; |
68 | } | 79 | } |
69 | 80 | ||
70 | #define pmb_unmap(addr) do { } while (0) | ||
71 | #define pmb_init(addr) do { } while (0) | 81 | #define pmb_init(addr) do { } while (0) |
72 | 82 | ||
73 | #ifdef CONFIG_29BIT | 83 | #ifdef CONFIG_29BIT |
@@ -77,6 +87,13 @@ static inline long pmb_remap(unsigned long virt, unsigned long phys, | |||
77 | #endif | 87 | #endif |
78 | 88 | ||
79 | #endif /* CONFIG_PMB */ | 89 | #endif /* CONFIG_PMB */ |
90 | |||
91 | static inline void __iomem * | ||
92 | pmb_remap(phys_addr_t phys, unsigned long size, pgprot_t prot) | ||
93 | { | ||
94 | return pmb_remap_caller(phys, size, prot, __builtin_return_address(0)); | ||
95 | } | ||
96 | |||
80 | #endif /* __ASSEMBLY__ */ | 97 | #endif /* __ASSEMBLY__ */ |
81 | 98 | ||
82 | #endif /* __MMU_H */ | 99 | #endif /* __MMU_H */ |
diff --git a/arch/sh/mm/ioremap.c b/arch/sh/mm/ioremap.c index c68d2d7d00a9..1ab2385ecefe 100644 --- a/arch/sh/mm/ioremap.c +++ b/arch/sh/mm/ioremap.c | |||
@@ -34,11 +34,12 @@ | |||
34 | * caller shouldn't need to know that small detail. | 34 | * caller shouldn't need to know that small detail. |
35 | */ | 35 | */ |
36 | void __iomem * __init_refok | 36 | void __iomem * __init_refok |
37 | __ioremap_caller(unsigned long phys_addr, unsigned long size, | 37 | __ioremap_caller(phys_addr_t phys_addr, unsigned long size, |
38 | pgprot_t pgprot, void *caller) | 38 | pgprot_t pgprot, void *caller) |
39 | { | 39 | { |
40 | struct vm_struct *area; | 40 | struct vm_struct *area; |
41 | unsigned long offset, last_addr, addr, orig_addr; | 41 | unsigned long offset, last_addr, addr, orig_addr; |
42 | void __iomem *mapped; | ||
42 | 43 | ||
43 | /* Don't allow wraparound or zero size */ | 44 | /* Don't allow wraparound or zero size */ |
44 | last_addr = phys_addr + size - 1; | 45 | last_addr = phys_addr + size - 1; |
@@ -46,6 +47,20 @@ __ioremap_caller(unsigned long phys_addr, unsigned long size, | |||
46 | return NULL; | 47 | return NULL; |
47 | 48 | ||
48 | /* | 49 | /* |
50 | * If we can't yet use the regular approach, go the fixmap route. | ||
51 | */ | ||
52 | if (!mem_init_done) | ||
53 | return ioremap_fixed(phys_addr, size, pgprot); | ||
54 | |||
55 | /* | ||
56 | * First try to remap through the PMB. | ||
57 | * PMB entries are all pre-faulted. | ||
58 | */ | ||
59 | mapped = pmb_remap_caller(phys_addr, size, pgprot, caller); | ||
60 | if (mapped && !IS_ERR(mapped)) | ||
61 | return mapped; | ||
62 | |||
63 | /* | ||
49 | * Mappings have to be page-aligned | 64 | * Mappings have to be page-aligned |
50 | */ | 65 | */ |
51 | offset = phys_addr & ~PAGE_MASK; | 66 | offset = phys_addr & ~PAGE_MASK; |
@@ -53,12 +68,6 @@ __ioremap_caller(unsigned long phys_addr, unsigned long size, | |||
53 | size = PAGE_ALIGN(last_addr+1) - phys_addr; | 68 | size = PAGE_ALIGN(last_addr+1) - phys_addr; |
54 | 69 | ||
55 | /* | 70 | /* |
56 | * If we can't yet use the regular approach, go the fixmap route. | ||
57 | */ | ||
58 | if (!mem_init_done) | ||
59 | return ioremap_fixed(phys_addr, offset, size, pgprot); | ||
60 | |||
61 | /* | ||
62 | * Ok, go for it.. | 71 | * Ok, go for it.. |
63 | */ | 72 | */ |
64 | area = get_vm_area_caller(size, VM_IOREMAP, caller); | 73 | area = get_vm_area_caller(size, VM_IOREMAP, caller); |
@@ -67,33 +76,10 @@ __ioremap_caller(unsigned long phys_addr, unsigned long size, | |||
67 | area->phys_addr = phys_addr; | 76 | area->phys_addr = phys_addr; |
68 | orig_addr = addr = (unsigned long)area->addr; | 77 | orig_addr = addr = (unsigned long)area->addr; |
69 | 78 | ||
70 | #ifdef CONFIG_PMB | 79 | if (ioremap_page_range(addr, addr + size, phys_addr, pgprot)) { |
71 | /* | 80 | vunmap((void *)orig_addr); |
72 | * First try to remap through the PMB once a valid VMA has been | 81 | return NULL; |
73 | * established. Smaller allocations (or the rest of the size | ||
74 | * remaining after a PMB mapping due to the size not being | ||
75 | * perfectly aligned on a PMB size boundary) are then mapped | ||
76 | * through the UTLB using conventional page tables. | ||
77 | * | ||
78 | * PMB entries are all pre-faulted. | ||
79 | */ | ||
80 | if (unlikely(phys_addr >= P1SEG)) { | ||
81 | unsigned long mapped; | ||
82 | |||
83 | mapped = pmb_remap(addr, phys_addr, size, pgprot); | ||
84 | if (likely(mapped)) { | ||
85 | addr += mapped; | ||
86 | phys_addr += mapped; | ||
87 | size -= mapped; | ||
88 | } | ||
89 | } | 82 | } |
90 | #endif | ||
91 | |||
92 | if (likely(size)) | ||
93 | if (ioremap_page_range(addr, addr + size, phys_addr, pgprot)) { | ||
94 | vunmap((void *)orig_addr); | ||
95 | return NULL; | ||
96 | } | ||
97 | 83 | ||
98 | return (void __iomem *)(offset + (char *)orig_addr); | 84 | return (void __iomem *)(offset + (char *)orig_addr); |
99 | } | 85 | } |
@@ -133,23 +119,11 @@ void __iounmap(void __iomem *addr) | |||
133 | if (iounmap_fixed(addr) == 0) | 119 | if (iounmap_fixed(addr) == 0) |
134 | return; | 120 | return; |
135 | 121 | ||
136 | #ifdef CONFIG_PMB | ||
137 | /* | 122 | /* |
138 | * Purge any PMB entries that may have been established for this | 123 | * If the PMB handled it, there's nothing else to do. |
139 | * mapping, then proceed with conventional VMA teardown. | ||
140 | * | ||
141 | * XXX: Note that due to the way that remove_vm_area() does | ||
142 | * matching of the resultant VMA, we aren't able to fast-forward | ||
143 | * the address past the PMB space until the end of the VMA where | ||
144 | * the page tables reside. As such, unmap_vm_area() will be | ||
145 | * forced to linearly scan over the area until it finds the page | ||
146 | * tables where PTEs that need to be unmapped actually reside, | ||
147 | * which is far from optimal. Perhaps we need to use a separate | ||
148 | * VMA for the PMB mappings? | ||
149 | * -- PFM. | ||
150 | */ | 124 | */ |
151 | pmb_unmap(vaddr); | 125 | if (pmb_unmap(addr) == 0) |
152 | #endif | 126 | return; |
153 | 127 | ||
154 | p = remove_vm_area((void *)(vaddr & PAGE_MASK)); | 128 | p = remove_vm_area((void *)(vaddr & PAGE_MASK)); |
155 | if (!p) { | 129 | if (!p) { |
diff --git a/arch/sh/mm/ioremap_fixed.c b/arch/sh/mm/ioremap_fixed.c index 0b78b1e20ef1..7f682e5dafcf 100644 --- a/arch/sh/mm/ioremap_fixed.c +++ b/arch/sh/mm/ioremap_fixed.c | |||
@@ -45,14 +45,21 @@ void __init ioremap_fixed_init(void) | |||
45 | } | 45 | } |
46 | 46 | ||
47 | void __init __iomem * | 47 | void __init __iomem * |
48 | ioremap_fixed(resource_size_t phys_addr, unsigned long offset, | 48 | ioremap_fixed(phys_addr_t phys_addr, unsigned long size, pgprot_t prot) |
49 | unsigned long size, pgprot_t prot) | ||
50 | { | 49 | { |
51 | enum fixed_addresses idx0, idx; | 50 | enum fixed_addresses idx0, idx; |
52 | struct ioremap_map *map; | 51 | struct ioremap_map *map; |
53 | unsigned int nrpages; | 52 | unsigned int nrpages; |
53 | unsigned long offset; | ||
54 | int i, slot; | 54 | int i, slot; |
55 | 55 | ||
56 | /* | ||
57 | * Mappings have to be page-aligned | ||
58 | */ | ||
59 | offset = phys_addr & ~PAGE_MASK; | ||
60 | phys_addr &= PAGE_MASK; | ||
61 | size = PAGE_ALIGN(phys_addr + size) - phys_addr; | ||
62 | |||
56 | slot = -1; | 63 | slot = -1; |
57 | for (i = 0; i < FIX_N_IOREMAPS; i++) { | 64 | for (i = 0; i < FIX_N_IOREMAPS; i++) { |
58 | map = &ioremap_maps[i]; | 65 | map = &ioremap_maps[i]; |
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index 35b364f931ea..9a516b89839a 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/err.h> | 23 | #include <linux/err.h> |
24 | #include <linux/io.h> | 24 | #include <linux/io.h> |
25 | #include <linux/spinlock.h> | 25 | #include <linux/spinlock.h> |
26 | #include <linux/vmalloc.h> | ||
26 | #include <asm/sizes.h> | 27 | #include <asm/sizes.h> |
27 | #include <asm/system.h> | 28 | #include <asm/system.h> |
28 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
@@ -51,6 +52,16 @@ struct pmb_entry { | |||
51 | struct pmb_entry *link; | 52 | struct pmb_entry *link; |
52 | }; | 53 | }; |
53 | 54 | ||
55 | static struct { | ||
56 | unsigned long size; | ||
57 | int flag; | ||
58 | } pmb_sizes[] = { | ||
59 | { .size = SZ_512M, .flag = PMB_SZ_512M, }, | ||
60 | { .size = SZ_128M, .flag = PMB_SZ_128M, }, | ||
61 | { .size = SZ_64M, .flag = PMB_SZ_64M, }, | ||
62 | { .size = SZ_16M, .flag = PMB_SZ_16M, }, | ||
63 | }; | ||
64 | |||
54 | static void pmb_unmap_entry(struct pmb_entry *, int depth); | 65 | static void pmb_unmap_entry(struct pmb_entry *, int depth); |
55 | 66 | ||
56 | static DEFINE_RWLOCK(pmb_rwlock); | 67 | static DEFINE_RWLOCK(pmb_rwlock); |
@@ -72,6 +83,88 @@ static __always_inline unsigned long mk_pmb_data(unsigned int entry) | |||
72 | return mk_pmb_entry(entry) | PMB_DATA; | 83 | return mk_pmb_entry(entry) | PMB_DATA; |
73 | } | 84 | } |
74 | 85 | ||
86 | static __always_inline unsigned int pmb_ppn_in_range(unsigned long ppn) | ||
87 | { | ||
88 | return ppn >= __pa(memory_start) && ppn < __pa(memory_end); | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * Ensure that the PMB entries match our cache configuration. | ||
93 | * | ||
94 | * When we are in 32-bit address extended mode, CCR.CB becomes | ||
95 | * invalid, so care must be taken to manually adjust cacheable | ||
96 | * translations. | ||
97 | */ | ||
98 | static __always_inline unsigned long pmb_cache_flags(void) | ||
99 | { | ||
100 | unsigned long flags = 0; | ||
101 | |||
102 | #if defined(CONFIG_CACHE_OFF) | ||
103 | flags |= PMB_WT | PMB_UB; | ||
104 | #elif defined(CONFIG_CACHE_WRITETHROUGH) | ||
105 | flags |= PMB_C | PMB_WT | PMB_UB; | ||
106 | #elif defined(CONFIG_CACHE_WRITEBACK) | ||
107 | flags |= PMB_C; | ||
108 | #endif | ||
109 | |||
110 | return flags; | ||
111 | } | ||
112 | |||
113 | /* | ||
114 | * Convert typical pgprot value to the PMB equivalent | ||
115 | */ | ||
116 | static inline unsigned long pgprot_to_pmb_flags(pgprot_t prot) | ||
117 | { | ||
118 | unsigned long pmb_flags = 0; | ||
119 | u64 flags = pgprot_val(prot); | ||
120 | |||
121 | if (flags & _PAGE_CACHABLE) | ||
122 | pmb_flags |= PMB_C; | ||
123 | if (flags & _PAGE_WT) | ||
124 | pmb_flags |= PMB_WT | PMB_UB; | ||
125 | |||
126 | return pmb_flags; | ||
127 | } | ||
128 | |||
129 | static bool pmb_can_merge(struct pmb_entry *a, struct pmb_entry *b) | ||
130 | { | ||
131 | return (b->vpn == (a->vpn + a->size)) && | ||
132 | (b->ppn == (a->ppn + a->size)) && | ||
133 | (b->flags == a->flags); | ||
134 | } | ||
135 | |||
136 | static bool pmb_size_valid(unsigned long size) | ||
137 | { | ||
138 | int i; | ||
139 | |||
140 | for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) | ||
141 | if (pmb_sizes[i].size == size) | ||
142 | return true; | ||
143 | |||
144 | return false; | ||
145 | } | ||
146 | |||
147 | static inline bool pmb_addr_valid(unsigned long addr, unsigned long size) | ||
148 | { | ||
149 | return (addr >= P1SEG && (addr + size - 1) < P3SEG); | ||
150 | } | ||
151 | |||
152 | static inline bool pmb_prot_valid(pgprot_t prot) | ||
153 | { | ||
154 | return (pgprot_val(prot) & _PAGE_USER) == 0; | ||
155 | } | ||
156 | |||
157 | static int pmb_size_to_flags(unsigned long size) | ||
158 | { | ||
159 | int i; | ||
160 | |||
161 | for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) | ||
162 | if (pmb_sizes[i].size == size) | ||
163 | return pmb_sizes[i].flag; | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
75 | static int pmb_alloc_entry(void) | 168 | static int pmb_alloc_entry(void) |
76 | { | 169 | { |
77 | int pos; | 170 | int pos; |
@@ -139,33 +232,13 @@ static void pmb_free(struct pmb_entry *pmbe) | |||
139 | } | 232 | } |
140 | 233 | ||
141 | /* | 234 | /* |
142 | * Ensure that the PMB entries match our cache configuration. | ||
143 | * | ||
144 | * When we are in 32-bit address extended mode, CCR.CB becomes | ||
145 | * invalid, so care must be taken to manually adjust cacheable | ||
146 | * translations. | ||
147 | */ | ||
148 | static __always_inline unsigned long pmb_cache_flags(void) | ||
149 | { | ||
150 | unsigned long flags = 0; | ||
151 | |||
152 | #if defined(CONFIG_CACHE_WRITETHROUGH) | ||
153 | flags |= PMB_C | PMB_WT | PMB_UB; | ||
154 | #elif defined(CONFIG_CACHE_WRITEBACK) | ||
155 | flags |= PMB_C; | ||
156 | #endif | ||
157 | |||
158 | return flags; | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * Must be run uncached. | 235 | * Must be run uncached. |
163 | */ | 236 | */ |
164 | static void __set_pmb_entry(struct pmb_entry *pmbe) | 237 | static void __set_pmb_entry(struct pmb_entry *pmbe) |
165 | { | 238 | { |
166 | writel_uncached(pmbe->vpn | PMB_V, mk_pmb_addr(pmbe->entry)); | 239 | /* Set V-bit */ |
167 | writel_uncached(pmbe->ppn | pmbe->flags | PMB_V, | 240 | __raw_writel(pmbe->ppn | pmbe->flags | PMB_V, mk_pmb_data(pmbe->entry)); |
168 | mk_pmb_data(pmbe->entry)); | 241 | __raw_writel(pmbe->vpn | PMB_V, mk_pmb_addr(pmbe->entry)); |
169 | } | 242 | } |
170 | 243 | ||
171 | static void __clear_pmb_entry(struct pmb_entry *pmbe) | 244 | static void __clear_pmb_entry(struct pmb_entry *pmbe) |
@@ -193,39 +266,56 @@ static void set_pmb_entry(struct pmb_entry *pmbe) | |||
193 | spin_unlock_irqrestore(&pmbe->lock, flags); | 266 | spin_unlock_irqrestore(&pmbe->lock, flags); |
194 | } | 267 | } |
195 | 268 | ||
196 | static struct { | 269 | int pmb_bolt_mapping(unsigned long vaddr, phys_addr_t phys, |
197 | unsigned long size; | 270 | unsigned long size, pgprot_t prot) |
198 | int flag; | 271 | { |
199 | } pmb_sizes[] = { | 272 | return 0; |
200 | { .size = SZ_512M, .flag = PMB_SZ_512M, }, | 273 | } |
201 | { .size = SZ_128M, .flag = PMB_SZ_128M, }, | ||
202 | { .size = SZ_64M, .flag = PMB_SZ_64M, }, | ||
203 | { .size = SZ_16M, .flag = PMB_SZ_16M, }, | ||
204 | }; | ||
205 | 274 | ||
206 | long pmb_remap(unsigned long vaddr, unsigned long phys, | 275 | void __iomem *pmb_remap_caller(phys_addr_t phys, unsigned long size, |
207 | unsigned long size, pgprot_t prot) | 276 | pgprot_t prot, void *caller) |
208 | { | 277 | { |
209 | struct pmb_entry *pmbp, *pmbe; | 278 | struct pmb_entry *pmbp, *pmbe; |
210 | unsigned long wanted; | 279 | unsigned long pmb_flags; |
211 | int pmb_flags, i; | 280 | int i, mapped; |
212 | long err; | 281 | unsigned long orig_addr, vaddr; |
213 | u64 flags; | 282 | phys_addr_t offset, last_addr; |
283 | phys_addr_t align_mask; | ||
284 | unsigned long aligned; | ||
285 | struct vm_struct *area; | ||
214 | 286 | ||
215 | flags = pgprot_val(prot); | 287 | /* |
288 | * Small mappings need to go through the TLB. | ||
289 | */ | ||
290 | if (size < SZ_16M) | ||
291 | return ERR_PTR(-EINVAL); | ||
292 | if (!pmb_prot_valid(prot)) | ||
293 | return ERR_PTR(-EINVAL); | ||
216 | 294 | ||
217 | pmb_flags = PMB_WT | PMB_UB; | 295 | pmbp = NULL; |
296 | pmb_flags = pgprot_to_pmb_flags(prot); | ||
297 | mapped = 0; | ||
218 | 298 | ||
219 | /* Convert typical pgprot value to the PMB equivalent */ | 299 | for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) |
220 | if (flags & _PAGE_CACHABLE) { | 300 | if (size >= pmb_sizes[i].size) |
221 | pmb_flags |= PMB_C; | 301 | break; |
222 | 302 | ||
223 | if ((flags & _PAGE_WT) == 0) | 303 | last_addr = phys + size; |
224 | pmb_flags &= ~(PMB_WT | PMB_UB); | 304 | align_mask = ~(pmb_sizes[i].size - 1); |
225 | } | 305 | offset = phys & ~align_mask; |
306 | phys &= align_mask; | ||
307 | aligned = ALIGN(last_addr, pmb_sizes[i].size) - phys; | ||
226 | 308 | ||
227 | pmbp = NULL; | 309 | area = __get_vm_area_caller(aligned, VM_IOREMAP, uncached_end, |
228 | wanted = size; | 310 | P3SEG, caller); |
311 | if (!area) | ||
312 | return NULL; | ||
313 | |||
314 | area->phys_addr = phys; | ||
315 | orig_addr = vaddr = (unsigned long)area->addr; | ||
316 | |||
317 | if (!pmb_addr_valid(vaddr, aligned)) | ||
318 | return ERR_PTR(-EFAULT); | ||
229 | 319 | ||
230 | again: | 320 | again: |
231 | for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) { | 321 | for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) { |
@@ -237,19 +327,19 @@ again: | |||
237 | pmbe = pmb_alloc(vaddr, phys, pmb_flags | pmb_sizes[i].flag, | 327 | pmbe = pmb_alloc(vaddr, phys, pmb_flags | pmb_sizes[i].flag, |
238 | PMB_NO_ENTRY); | 328 | PMB_NO_ENTRY); |
239 | if (IS_ERR(pmbe)) { | 329 | if (IS_ERR(pmbe)) { |
240 | err = PTR_ERR(pmbe); | 330 | pmb_unmap_entry(pmbp, mapped); |
241 | goto out; | 331 | return pmbe; |
242 | } | 332 | } |
243 | 333 | ||
244 | spin_lock_irqsave(&pmbe->lock, flags); | 334 | spin_lock_irqsave(&pmbe->lock, flags); |
245 | 335 | ||
336 | pmbe->size = pmb_sizes[i].size; | ||
337 | |||
246 | __set_pmb_entry(pmbe); | 338 | __set_pmb_entry(pmbe); |
247 | 339 | ||
248 | phys += pmb_sizes[i].size; | 340 | phys += pmbe->size; |
249 | vaddr += pmb_sizes[i].size; | 341 | vaddr += pmbe->size; |
250 | size -= pmb_sizes[i].size; | 342 | size -= pmbe->size; |
251 | |||
252 | pmbe->size = pmb_sizes[i].size; | ||
253 | 343 | ||
254 | /* | 344 | /* |
255 | * Link adjacent entries that span multiple PMB entries | 345 | * Link adjacent entries that span multiple PMB entries |
@@ -269,6 +359,7 @@ again: | |||
269 | * pmb_sizes[i].size again. | 359 | * pmb_sizes[i].size again. |
270 | */ | 360 | */ |
271 | i--; | 361 | i--; |
362 | mapped++; | ||
272 | 363 | ||
273 | spin_unlock_irqrestore(&pmbe->lock, flags); | 364 | spin_unlock_irqrestore(&pmbe->lock, flags); |
274 | } | 365 | } |
@@ -276,61 +367,35 @@ again: | |||
276 | if (size >= SZ_16M) | 367 | if (size >= SZ_16M) |
277 | goto again; | 368 | goto again; |
278 | 369 | ||
279 | return wanted - size; | 370 | return (void __iomem *)(offset + (char *)orig_addr); |
280 | |||
281 | out: | ||
282 | pmb_unmap_entry(pmbp, NR_PMB_ENTRIES); | ||
283 | |||
284 | return err; | ||
285 | } | 371 | } |
286 | 372 | ||
287 | void pmb_unmap(unsigned long addr) | 373 | int pmb_unmap(void __iomem *addr) |
288 | { | 374 | { |
289 | struct pmb_entry *pmbe = NULL; | 375 | struct pmb_entry *pmbe = NULL; |
290 | int i; | 376 | unsigned long vaddr = (unsigned long __force)addr; |
377 | int i, found = 0; | ||
291 | 378 | ||
292 | read_lock(&pmb_rwlock); | 379 | read_lock(&pmb_rwlock); |
293 | 380 | ||
294 | for (i = 0; i < ARRAY_SIZE(pmb_entry_list); i++) { | 381 | for (i = 0; i < ARRAY_SIZE(pmb_entry_list); i++) { |
295 | if (test_bit(i, pmb_map)) { | 382 | if (test_bit(i, pmb_map)) { |
296 | pmbe = &pmb_entry_list[i]; | 383 | pmbe = &pmb_entry_list[i]; |
297 | if (pmbe->vpn == addr) | 384 | if (pmbe->vpn == vaddr) { |
385 | found = 1; | ||
298 | break; | 386 | break; |
387 | } | ||
299 | } | 388 | } |
300 | } | 389 | } |
301 | 390 | ||
302 | read_unlock(&pmb_rwlock); | 391 | read_unlock(&pmb_rwlock); |
303 | 392 | ||
304 | pmb_unmap_entry(pmbe, NR_PMB_ENTRIES); | 393 | if (found) { |
305 | } | 394 | pmb_unmap_entry(pmbe, NR_PMB_ENTRIES); |
306 | 395 | return 0; | |
307 | static bool pmb_can_merge(struct pmb_entry *a, struct pmb_entry *b) | 396 | } |
308 | { | ||
309 | return (b->vpn == (a->vpn + a->size)) && | ||
310 | (b->ppn == (a->ppn + a->size)) && | ||
311 | (b->flags == a->flags); | ||
312 | } | ||
313 | |||
314 | static bool pmb_size_valid(unsigned long size) | ||
315 | { | ||
316 | int i; | ||
317 | |||
318 | for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) | ||
319 | if (pmb_sizes[i].size == size) | ||
320 | return true; | ||
321 | |||
322 | return false; | ||
323 | } | ||
324 | |||
325 | static int pmb_size_to_flags(unsigned long size) | ||
326 | { | ||
327 | int i; | ||
328 | |||
329 | for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) | ||
330 | if (pmb_sizes[i].size == size) | ||
331 | return pmb_sizes[i].flag; | ||
332 | 397 | ||
333 | return 0; | 398 | return -EINVAL; |
334 | } | 399 | } |
335 | 400 | ||
336 | static void __pmb_unmap_entry(struct pmb_entry *pmbe, int depth) | 401 | static void __pmb_unmap_entry(struct pmb_entry *pmbe, int depth) |
@@ -368,11 +433,6 @@ static void pmb_unmap_entry(struct pmb_entry *pmbe, int depth) | |||
368 | write_unlock_irqrestore(&pmb_rwlock, flags); | 433 | write_unlock_irqrestore(&pmb_rwlock, flags); |
369 | } | 434 | } |
370 | 435 | ||
371 | static __always_inline unsigned int pmb_ppn_in_range(unsigned long ppn) | ||
372 | { | ||
373 | return ppn >= __pa(memory_start) && ppn < __pa(memory_end); | ||
374 | } | ||
375 | |||
376 | static void __init pmb_notify(void) | 436 | static void __init pmb_notify(void) |
377 | { | 437 | { |
378 | int i; | 438 | int i; |