.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * PowerPC version |
---|
3 | 4 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) |
---|
.. | .. |
---|
9 | 10 | * |
---|
10 | 11 | * Derived from "arch/i386/mm/init.c" |
---|
11 | 12 | * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds |
---|
12 | | - * |
---|
13 | | - * This program is free software; you can redistribute it and/or |
---|
14 | | - * modify it under the terms of the GNU General Public License |
---|
15 | | - * as published by the Free Software Foundation; either version |
---|
16 | | - * 2 of the License, or (at your option) any later version. |
---|
17 | | - * |
---|
18 | 13 | */ |
---|
19 | 14 | |
---|
20 | 15 | #include <linux/export.h> |
---|
.. | .. |
---|
27 | 22 | #include <linux/mm.h> |
---|
28 | 23 | #include <linux/stddef.h> |
---|
29 | 24 | #include <linux/init.h> |
---|
30 | | -#include <linux/bootmem.h> |
---|
| 25 | +#include <linux/memblock.h> |
---|
31 | 26 | #include <linux/highmem.h> |
---|
32 | 27 | #include <linux/initrd.h> |
---|
33 | 28 | #include <linux/pagemap.h> |
---|
34 | 29 | #include <linux/suspend.h> |
---|
35 | | -#include <linux/memblock.h> |
---|
36 | 30 | #include <linux/hugetlb.h> |
---|
37 | 31 | #include <linux/slab.h> |
---|
38 | 32 | #include <linux/vmalloc.h> |
---|
39 | 33 | #include <linux/memremap.h> |
---|
| 34 | +#include <linux/dma-direct.h> |
---|
| 35 | +#include <linux/kprobes.h> |
---|
40 | 36 | |
---|
41 | | -#include <asm/pgalloc.h> |
---|
42 | 37 | #include <asm/prom.h> |
---|
43 | 38 | #include <asm/io.h> |
---|
44 | 39 | #include <asm/mmu_context.h> |
---|
45 | | -#include <asm/pgtable.h> |
---|
46 | 40 | #include <asm/mmu.h> |
---|
47 | 41 | #include <asm/smp.h> |
---|
48 | 42 | #include <asm/machdep.h> |
---|
.. | .. |
---|
54 | 48 | #include <asm/fixmap.h> |
---|
55 | 49 | #include <asm/swiotlb.h> |
---|
56 | 50 | #include <asm/rtas.h> |
---|
| 51 | +#include <asm/kasan.h> |
---|
| 52 | +#include <asm/svm.h> |
---|
| 53 | +#include <asm/mmzone.h> |
---|
| 54 | +#include <asm/ftrace.h> |
---|
57 | 55 | |
---|
58 | | -#include "mmu_decl.h" |
---|
| 56 | +#include <mm/mmu_decl.h> |
---|
59 | 57 | |
---|
60 | 58 | #ifndef CPU_FTR_COHERENT_ICACHE |
---|
61 | 59 | #define CPU_FTR_COHERENT_ICACHE 0 /* XXX for now */ |
---|
.. | .. |
---|
68 | 66 | #ifdef CONFIG_HIGHMEM |
---|
69 | 67 | pte_t *kmap_pte; |
---|
70 | 68 | EXPORT_SYMBOL(kmap_pte); |
---|
71 | | -pgprot_t kmap_prot; |
---|
72 | | -EXPORT_SYMBOL(kmap_prot); |
---|
73 | | -#define TOP_ZONE ZONE_HIGHMEM |
---|
74 | | - |
---|
75 | | -static inline pte_t *virt_to_kpte(unsigned long vaddr) |
---|
76 | | -{ |
---|
77 | | - return pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), |
---|
78 | | - vaddr), vaddr), vaddr); |
---|
79 | | -} |
---|
80 | | -#else |
---|
81 | | -#define TOP_ZONE ZONE_NORMAL |
---|
82 | 69 | #endif |
---|
83 | | - |
---|
84 | | -int page_is_ram(unsigned long pfn) |
---|
85 | | -{ |
---|
86 | | - return memblock_is_memory(__pfn_to_phys(pfn)); |
---|
87 | | -} |
---|
88 | 70 | |
---|
89 | 71 | pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, |
---|
90 | 72 | unsigned long size, pgprot_t vma_prot) |
---|
.. | .. |
---|
108 | 90 | } |
---|
109 | 91 | #endif |
---|
110 | 92 | |
---|
111 | | -int __weak create_section_mapping(unsigned long start, unsigned long end, int nid) |
---|
| 93 | +int __weak create_section_mapping(unsigned long start, unsigned long end, |
---|
| 94 | + int nid, pgprot_t prot) |
---|
112 | 95 | { |
---|
113 | 96 | return -ENODEV; |
---|
114 | 97 | } |
---|
.. | .. |
---|
118 | 101 | return -ENODEV; |
---|
119 | 102 | } |
---|
120 | 103 | |
---|
121 | | -int __ref arch_add_memory(int nid, u64 start, u64 size, struct vmem_altmap *altmap, |
---|
122 | | - bool want_memblock) |
---|
| 104 | +#define FLUSH_CHUNK_SIZE SZ_1G |
---|
| 105 | +/** |
---|
| 106 | + * flush_dcache_range_chunked(): Write any modified data cache blocks out to |
---|
| 107 | + * memory and invalidate them, in chunks of up to FLUSH_CHUNK_SIZE |
---|
| 108 | + * Does not invalidate the corresponding instruction cache blocks. |
---|
| 109 | + * |
---|
| 110 | + * @start: the start address |
---|
| 111 | + * @stop: the stop address (exclusive) |
---|
| 112 | + * @chunk: the max size of the chunks |
---|
| 113 | + */ |
---|
| 114 | +static void flush_dcache_range_chunked(unsigned long start, unsigned long stop, |
---|
| 115 | + unsigned long chunk) |
---|
| 116 | +{ |
---|
| 117 | + unsigned long i; |
---|
| 118 | + |
---|
| 119 | + for (i = start; i < stop; i += chunk) { |
---|
| 120 | + flush_dcache_range(i, min(stop, i + chunk)); |
---|
| 121 | + cond_resched(); |
---|
| 122 | + } |
---|
| 123 | +} |
---|
| 124 | + |
---|
| 125 | +int __ref arch_add_memory(int nid, u64 start, u64 size, |
---|
| 126 | + struct mhp_params *params) |
---|
123 | 127 | { |
---|
124 | 128 | unsigned long start_pfn = start >> PAGE_SHIFT; |
---|
125 | 129 | unsigned long nr_pages = size >> PAGE_SHIFT; |
---|
126 | 130 | int rc; |
---|
127 | 131 | |
---|
128 | | - resize_hpt_for_hotplug(memblock_phys_mem_size()); |
---|
129 | | - |
---|
130 | 132 | start = (unsigned long)__va(start); |
---|
131 | | - rc = create_section_mapping(start, start + size, nid); |
---|
| 133 | + rc = create_section_mapping(start, start + size, nid, |
---|
| 134 | + params->pgprot); |
---|
132 | 135 | if (rc) { |
---|
133 | 136 | pr_warn("Unable to create mapping for hot added memory 0x%llx..0x%llx: %d\n", |
---|
134 | 137 | start, start + size, rc); |
---|
135 | 138 | return -EFAULT; |
---|
136 | 139 | } |
---|
137 | | - flush_inval_dcache_range(start, start + size); |
---|
138 | 140 | |
---|
139 | | - return __add_pages(nid, start_pfn, nr_pages, altmap, want_memblock); |
---|
| 141 | + return __add_pages(nid, start_pfn, nr_pages, params); |
---|
140 | 142 | } |
---|
141 | 143 | |
---|
142 | 144 | void __ref arch_remove_memory(int nid, u64 start, u64 size, |
---|
.. | .. |
---|
150 | 152 | |
---|
151 | 153 | /* Remove htab bolted mappings for this section of memory */ |
---|
152 | 154 | start = (unsigned long)__va(start); |
---|
153 | | - flush_inval_dcache_range(start, start + size); |
---|
| 155 | + flush_dcache_range_chunked(start, start + size, FLUSH_CHUNK_SIZE); |
---|
| 156 | + |
---|
154 | 157 | ret = remove_section_mapping(start, start + size); |
---|
155 | 158 | WARN_ON_ONCE(ret); |
---|
156 | 159 | |
---|
.. | .. |
---|
158 | 161 | * hit that section of memory |
---|
159 | 162 | */ |
---|
160 | 163 | vm_unmap_aliases(); |
---|
161 | | - |
---|
162 | | - resize_hpt_for_hotplug(memblock_phys_mem_size()); |
---|
163 | 164 | } |
---|
164 | 165 | #endif |
---|
165 | | - |
---|
166 | | -/* |
---|
167 | | - * walk_memory_resource() needs to make sure there is no holes in a given |
---|
168 | | - * memory range. PPC64 does not maintain the memory layout in /proc/iomem. |
---|
169 | | - * Instead it maintains it in memblock.memory structures. Walk through the |
---|
170 | | - * memory regions, find holes and callback for contiguous regions. |
---|
171 | | - */ |
---|
172 | | -int |
---|
173 | | -walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages, |
---|
174 | | - void *arg, int (*func)(unsigned long, unsigned long, void *)) |
---|
175 | | -{ |
---|
176 | | - struct memblock_region *reg; |
---|
177 | | - unsigned long end_pfn = start_pfn + nr_pages; |
---|
178 | | - unsigned long tstart, tend; |
---|
179 | | - int ret = -1; |
---|
180 | | - |
---|
181 | | - for_each_memblock(memory, reg) { |
---|
182 | | - tstart = max(start_pfn, memblock_region_memory_base_pfn(reg)); |
---|
183 | | - tend = min(end_pfn, memblock_region_memory_end_pfn(reg)); |
---|
184 | | - if (tstart >= tend) |
---|
185 | | - continue; |
---|
186 | | - ret = (*func)(tstart, tend - tstart, arg); |
---|
187 | | - if (ret) |
---|
188 | | - break; |
---|
189 | | - } |
---|
190 | | - return ret; |
---|
191 | | -} |
---|
192 | | -EXPORT_SYMBOL_GPL(walk_system_ram_range); |
---|
193 | 166 | |
---|
194 | 167 | #ifndef CONFIG_NEED_MULTIPLE_NODES |
---|
195 | 168 | void __init mem_topology_setup(void) |
---|
.. | .. |
---|
208 | 181 | |
---|
209 | 182 | void __init initmem_init(void) |
---|
210 | 183 | { |
---|
211 | | - /* XXX need to clip this if using highmem? */ |
---|
212 | | - sparse_memory_present_with_active_regions(0); |
---|
213 | 184 | sparse_init(); |
---|
214 | 185 | } |
---|
215 | 186 | |
---|
216 | 187 | /* mark pages that don't exist as nosave */ |
---|
217 | 188 | static int __init mark_nonram_nosave(void) |
---|
218 | 189 | { |
---|
219 | | - struct memblock_region *reg, *prev = NULL; |
---|
| 190 | + unsigned long spfn, epfn, prev = 0; |
---|
| 191 | + int i; |
---|
220 | 192 | |
---|
221 | | - for_each_memblock(memory, reg) { |
---|
222 | | - if (prev && |
---|
223 | | - memblock_region_memory_end_pfn(prev) < memblock_region_memory_base_pfn(reg)) |
---|
224 | | - register_nosave_region(memblock_region_memory_end_pfn(prev), |
---|
225 | | - memblock_region_memory_base_pfn(reg)); |
---|
226 | | - prev = reg; |
---|
| 193 | + for_each_mem_pfn_range(i, MAX_NUMNODES, &spfn, &epfn, NULL) { |
---|
| 194 | + if (prev && prev < spfn) |
---|
| 195 | + register_nosave_region(prev, spfn); |
---|
| 196 | + |
---|
| 197 | + prev = epfn; |
---|
227 | 198 | } |
---|
| 199 | + |
---|
228 | 200 | return 0; |
---|
229 | 201 | } |
---|
230 | 202 | #else /* CONFIG_NEED_MULTIPLE_NODES */ |
---|
.. | .. |
---|
234 | 206 | } |
---|
235 | 207 | #endif |
---|
236 | 208 | |
---|
237 | | -static bool zone_limits_final; |
---|
238 | | - |
---|
239 | 209 | /* |
---|
240 | | - * The memory zones past TOP_ZONE are managed by generic mm code. |
---|
241 | | - * These should be set to zero since that's what every other |
---|
242 | | - * architecture does. |
---|
243 | | - */ |
---|
244 | | -static unsigned long max_zone_pfns[MAX_NR_ZONES] = { |
---|
245 | | - [0 ... TOP_ZONE ] = ~0UL, |
---|
246 | | - [TOP_ZONE + 1 ... MAX_NR_ZONES - 1] = 0 |
---|
247 | | -}; |
---|
248 | | - |
---|
249 | | -/* |
---|
250 | | - * Restrict the specified zone and all more restrictive zones |
---|
251 | | - * to be below the specified pfn. May not be called after |
---|
252 | | - * paging_init(). |
---|
253 | | - */ |
---|
254 | | -void __init limit_zone_pfn(enum zone_type zone, unsigned long pfn_limit) |
---|
255 | | -{ |
---|
256 | | - int i; |
---|
257 | | - |
---|
258 | | - if (WARN_ON(zone_limits_final)) |
---|
259 | | - return; |
---|
260 | | - |
---|
261 | | - for (i = zone; i >= 0; i--) { |
---|
262 | | - if (max_zone_pfns[i] > pfn_limit) |
---|
263 | | - max_zone_pfns[i] = pfn_limit; |
---|
264 | | - } |
---|
265 | | -} |
---|
266 | | - |
---|
267 | | -/* |
---|
268 | | - * Find the least restrictive zone that is entirely below the |
---|
269 | | - * specified pfn limit. Returns < 0 if no suitable zone is found. |
---|
| 210 | + * Zones usage: |
---|
270 | 211 | * |
---|
271 | | - * pfn_limit must be u64 because it can exceed 32 bits even on 32-bit |
---|
272 | | - * systems -- the DMA limit can be higher than any possible real pfn. |
---|
| 212 | + * We setup ZONE_DMA to be 31-bits on all platforms and ZONE_NORMAL to be |
---|
| 213 | + * everything else. GFP_DMA32 page allocations automatically fall back to |
---|
| 214 | + * ZONE_DMA. |
---|
| 215 | + * |
---|
| 216 | + * By using 31-bit unconditionally, we can exploit zone_dma_bits to inform the |
---|
| 217 | + * generic DMA mapping code. 32-bit only devices (if not handled by an IOMMU |
---|
| 218 | + * anyway) will take a first dip into ZONE_NORMAL and get otherwise served by |
---|
| 219 | + * ZONE_DMA. |
---|
273 | 220 | */ |
---|
274 | | -int dma_pfn_limit_to_zone(u64 pfn_limit) |
---|
275 | | -{ |
---|
276 | | - int i; |
---|
277 | | - |
---|
278 | | - for (i = TOP_ZONE; i >= 0; i--) { |
---|
279 | | - if (max_zone_pfns[i] <= pfn_limit) |
---|
280 | | - return i; |
---|
281 | | - } |
---|
282 | | - |
---|
283 | | - return -EPERM; |
---|
284 | | -} |
---|
| 221 | +static unsigned long max_zone_pfns[MAX_NR_ZONES]; |
---|
285 | 222 | |
---|
286 | 223 | /* |
---|
287 | 224 | * paging_init() sets up the page tables - in fact we've already done this. |
---|
.. | .. |
---|
291 | 228 | unsigned long long total_ram = memblock_phys_mem_size(); |
---|
292 | 229 | phys_addr_t top_of_ram = memblock_end_of_DRAM(); |
---|
293 | 230 | |
---|
294 | | -#ifdef CONFIG_PPC32 |
---|
295 | | - unsigned long v = __fix_to_virt(__end_of_fixed_addresses - 1); |
---|
296 | | - unsigned long end = __fix_to_virt(FIX_HOLE); |
---|
| 231 | +#ifdef CONFIG_HIGHMEM |
---|
| 232 | + unsigned long v = __fix_to_virt(FIX_KMAP_END); |
---|
| 233 | + unsigned long end = __fix_to_virt(FIX_KMAP_BEGIN); |
---|
297 | 234 | |
---|
298 | 235 | for (; v < end; v += PAGE_SIZE) |
---|
299 | | - map_kernel_page(v, 0, 0); /* XXX gross */ |
---|
300 | | -#endif |
---|
| 236 | + map_kernel_page(v, 0, __pgprot(0)); /* XXX gross */ |
---|
301 | 237 | |
---|
302 | | -#ifdef CONFIG_HIGHMEM |
---|
303 | | - map_kernel_page(PKMAP_BASE, 0, 0); /* XXX gross */ |
---|
| 238 | + map_kernel_page(PKMAP_BASE, 0, __pgprot(0)); /* XXX gross */ |
---|
304 | 239 | pkmap_page_table = virt_to_kpte(PKMAP_BASE); |
---|
305 | 240 | |
---|
306 | 241 | kmap_pte = virt_to_kpte(__fix_to_virt(FIX_KMAP_BEGIN)); |
---|
307 | | - kmap_prot = PAGE_KERNEL; |
---|
308 | 242 | #endif /* CONFIG_HIGHMEM */ |
---|
309 | 243 | |
---|
310 | 244 | printk(KERN_DEBUG "Top of RAM: 0x%llx, Total RAM: 0x%llx\n", |
---|
.. | .. |
---|
312 | 246 | printk(KERN_DEBUG "Memory hole size: %ldMB\n", |
---|
313 | 247 | (long int)((top_of_ram - total_ram) >> 20)); |
---|
314 | 248 | |
---|
315 | | -#ifdef CONFIG_HIGHMEM |
---|
316 | | - limit_zone_pfn(ZONE_NORMAL, lowmem_end_addr >> PAGE_SHIFT); |
---|
| 249 | + /* |
---|
| 250 | + * Allow 30-bit DMA for very limited Broadcom wifi chips on many |
---|
| 251 | + * powerbooks. |
---|
| 252 | + */ |
---|
| 253 | + if (IS_ENABLED(CONFIG_PPC32)) |
---|
| 254 | + zone_dma_bits = 30; |
---|
| 255 | + else |
---|
| 256 | + zone_dma_bits = 31; |
---|
| 257 | + |
---|
| 258 | +#ifdef CONFIG_ZONE_DMA |
---|
| 259 | + max_zone_pfns[ZONE_DMA] = min(max_low_pfn, |
---|
| 260 | + 1UL << (zone_dma_bits - PAGE_SHIFT)); |
---|
317 | 261 | #endif |
---|
318 | | - limit_zone_pfn(TOP_ZONE, top_of_ram >> PAGE_SHIFT); |
---|
319 | | - zone_limits_final = true; |
---|
320 | | - free_area_init_nodes(max_zone_pfns); |
---|
| 262 | + max_zone_pfns[ZONE_NORMAL] = max_low_pfn; |
---|
| 263 | +#ifdef CONFIG_HIGHMEM |
---|
| 264 | + max_zone_pfns[ZONE_HIGHMEM] = max_pfn; |
---|
| 265 | +#endif |
---|
| 266 | + |
---|
| 267 | + free_area_init(max_zone_pfns); |
---|
321 | 268 | |
---|
322 | 269 | mark_nonram_nosave(); |
---|
323 | 270 | } |
---|
.. | .. |
---|
339 | 286 | * back to to-down. |
---|
340 | 287 | */ |
---|
341 | 288 | memblock_set_bottom_up(true); |
---|
342 | | - swiotlb_init(0); |
---|
| 289 | + if (is_secure_guest()) |
---|
| 290 | + svm_swiotlb_init(); |
---|
| 291 | + else |
---|
| 292 | + swiotlb_init(0); |
---|
343 | 293 | #endif |
---|
344 | 294 | |
---|
345 | 295 | high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); |
---|
346 | 296 | set_max_mapnr(max_pfn); |
---|
347 | | - free_all_bootmem(); |
---|
| 297 | + |
---|
| 298 | + kasan_late_init(); |
---|
| 299 | + |
---|
| 300 | + memblock_free_all(); |
---|
348 | 301 | |
---|
349 | 302 | #ifdef CONFIG_HIGHMEM |
---|
350 | 303 | { |
---|
.. | .. |
---|
372 | 325 | mem_init_print_info(NULL); |
---|
373 | 326 | #ifdef CONFIG_PPC32 |
---|
374 | 327 | pr_info("Kernel virtual memory layout:\n"); |
---|
| 328 | +#ifdef CONFIG_KASAN |
---|
| 329 | + pr_info(" * 0x%08lx..0x%08lx : kasan shadow mem\n", |
---|
| 330 | + KASAN_SHADOW_START, KASAN_SHADOW_END); |
---|
| 331 | +#endif |
---|
375 | 332 | pr_info(" * 0x%08lx..0x%08lx : fixmap\n", FIXADDR_START, FIXADDR_TOP); |
---|
376 | 333 | #ifdef CONFIG_HIGHMEM |
---|
377 | 334 | pr_info(" * 0x%08lx..0x%08lx : highmem PTEs\n", |
---|
378 | 335 | PKMAP_BASE, PKMAP_ADDR(LAST_PKMAP)); |
---|
379 | 336 | #endif /* CONFIG_HIGHMEM */ |
---|
380 | | -#ifdef CONFIG_NOT_COHERENT_CACHE |
---|
381 | | - pr_info(" * 0x%08lx..0x%08lx : consistent mem\n", |
---|
382 | | - IOREMAP_TOP, IOREMAP_TOP + CONFIG_CONSISTENT_SIZE); |
---|
383 | | -#endif /* CONFIG_NOT_COHERENT_CACHE */ |
---|
384 | | - pr_info(" * 0x%08lx..0x%08lx : early ioremap\n", |
---|
385 | | - ioremap_bot, IOREMAP_TOP); |
---|
| 337 | + if (ioremap_bot != IOREMAP_TOP) |
---|
| 338 | + pr_info(" * 0x%08lx..0x%08lx : early ioremap\n", |
---|
| 339 | + ioremap_bot, IOREMAP_TOP); |
---|
386 | 340 | pr_info(" * 0x%08lx..0x%08lx : vmalloc & ioremap\n", |
---|
387 | 341 | VMALLOC_START, VMALLOC_END); |
---|
388 | 342 | #endif /* CONFIG_PPC32 */ |
---|
.. | .. |
---|
394 | 348 | mark_initmem_nx(); |
---|
395 | 349 | init_mem_is_free = true; |
---|
396 | 350 | free_initmem_default(POISON_FREE_INITMEM); |
---|
| 351 | + ftrace_free_init_tramp(); |
---|
397 | 352 | } |
---|
398 | 353 | |
---|
399 | | -#ifdef CONFIG_BLK_DEV_INITRD |
---|
400 | | -void __init free_initrd_mem(unsigned long start, unsigned long end) |
---|
| 354 | +/** |
---|
| 355 | + * flush_coherent_icache() - if a CPU has a coherent icache, flush it |
---|
| 356 | + * @addr: The base address to use (can be any valid address, the whole cache will be flushed) |
---|
| 357 | + * Return true if the cache was flushed, false otherwise |
---|
| 358 | + */ |
---|
| 359 | +static inline bool flush_coherent_icache(unsigned long addr) |
---|
401 | 360 | { |
---|
402 | | - free_reserved_area((void *)start, (void *)end, -1, "initrd"); |
---|
| 361 | + /* |
---|
| 362 | + * For a snooping icache, we still need a dummy icbi to purge all the |
---|
| 363 | + * prefetched instructions from the ifetch buffers. We also need a sync |
---|
| 364 | + * before the icbi to order the the actual stores to memory that might |
---|
| 365 | + * have modified instructions with the icbi. |
---|
| 366 | + */ |
---|
| 367 | + if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) { |
---|
| 368 | + mb(); /* sync */ |
---|
| 369 | + allow_read_from_user((const void __user *)addr, L1_CACHE_BYTES); |
---|
| 370 | + icbi((void *)addr); |
---|
| 371 | + prevent_read_from_user((const void __user *)addr, L1_CACHE_BYTES); |
---|
| 372 | + mb(); /* sync */ |
---|
| 373 | + isync(); |
---|
| 374 | + return true; |
---|
| 375 | + } |
---|
| 376 | + |
---|
| 377 | + return false; |
---|
403 | 378 | } |
---|
404 | | -#endif |
---|
| 379 | + |
---|
| 380 | +/** |
---|
| 381 | + * invalidate_icache_range() - Flush the icache by issuing icbi across an address range |
---|
| 382 | + * @start: the start address |
---|
| 383 | + * @stop: the stop address (exclusive) |
---|
| 384 | + */ |
---|
| 385 | +static void invalidate_icache_range(unsigned long start, unsigned long stop) |
---|
| 386 | +{ |
---|
| 387 | + unsigned long shift = l1_icache_shift(); |
---|
| 388 | + unsigned long bytes = l1_icache_bytes(); |
---|
| 389 | + char *addr = (char *)(start & ~(bytes - 1)); |
---|
| 390 | + unsigned long size = stop - (unsigned long)addr + (bytes - 1); |
---|
| 391 | + unsigned long i; |
---|
| 392 | + |
---|
| 393 | + for (i = 0; i < size >> shift; i++, addr += bytes) |
---|
| 394 | + icbi(addr); |
---|
| 395 | + |
---|
| 396 | + mb(); /* sync */ |
---|
| 397 | + isync(); |
---|
| 398 | +} |
---|
| 399 | + |
---|
| 400 | +/** |
---|
| 401 | + * flush_icache_range: Write any modified data cache blocks out to memory |
---|
| 402 | + * and invalidate the corresponding blocks in the instruction cache |
---|
| 403 | + * |
---|
| 404 | + * Generic code will call this after writing memory, before executing from it. |
---|
| 405 | + * |
---|
| 406 | + * @start: the start address |
---|
| 407 | + * @stop: the stop address (exclusive) |
---|
| 408 | + */ |
---|
| 409 | +void flush_icache_range(unsigned long start, unsigned long stop) |
---|
| 410 | +{ |
---|
| 411 | + if (flush_coherent_icache(start)) |
---|
| 412 | + return; |
---|
| 413 | + |
---|
| 414 | + clean_dcache_range(start, stop); |
---|
| 415 | + |
---|
| 416 | + if (IS_ENABLED(CONFIG_44x)) { |
---|
| 417 | + /* |
---|
| 418 | + * Flash invalidate on 44x because we are passed kmapped |
---|
| 419 | + * addresses and this doesn't work for userspace pages due to |
---|
| 420 | + * the virtually tagged icache. |
---|
| 421 | + */ |
---|
| 422 | + iccci((void *)start); |
---|
| 423 | + mb(); /* sync */ |
---|
| 424 | + isync(); |
---|
| 425 | + } else |
---|
| 426 | + invalidate_icache_range(start, stop); |
---|
| 427 | +} |
---|
| 428 | +EXPORT_SYMBOL(flush_icache_range); |
---|
| 429 | + |
---|
| 430 | +#if !defined(CONFIG_PPC_8xx) && !defined(CONFIG_PPC64) |
---|
| 431 | +/** |
---|
| 432 | + * flush_dcache_icache_phys() - Flush a page by it's physical address |
---|
| 433 | + * @physaddr: the physical address of the page |
---|
| 434 | + */ |
---|
| 435 | +static void flush_dcache_icache_phys(unsigned long physaddr) |
---|
| 436 | +{ |
---|
| 437 | + unsigned long bytes = l1_dcache_bytes(); |
---|
| 438 | + unsigned long nb = PAGE_SIZE / bytes; |
---|
| 439 | + unsigned long addr = physaddr & PAGE_MASK; |
---|
| 440 | + unsigned long msr, msr0; |
---|
| 441 | + unsigned long loop1 = addr, loop2 = addr; |
---|
| 442 | + |
---|
| 443 | + msr0 = mfmsr(); |
---|
| 444 | + msr = msr0 & ~MSR_DR; |
---|
| 445 | + /* |
---|
| 446 | + * This must remain as ASM to prevent potential memory accesses |
---|
| 447 | + * while the data MMU is disabled |
---|
| 448 | + */ |
---|
| 449 | + asm volatile( |
---|
| 450 | + " mtctr %2;\n" |
---|
| 451 | + " mtmsr %3;\n" |
---|
| 452 | + " isync;\n" |
---|
| 453 | + "0: dcbst 0, %0;\n" |
---|
| 454 | + " addi %0, %0, %4;\n" |
---|
| 455 | + " bdnz 0b;\n" |
---|
| 456 | + " sync;\n" |
---|
| 457 | + " mtctr %2;\n" |
---|
| 458 | + "1: icbi 0, %1;\n" |
---|
| 459 | + " addi %1, %1, %4;\n" |
---|
| 460 | + " bdnz 1b;\n" |
---|
| 461 | + " sync;\n" |
---|
| 462 | + " mtmsr %5;\n" |
---|
| 463 | + " isync;\n" |
---|
| 464 | + : "+&r" (loop1), "+&r" (loop2) |
---|
| 465 | + : "r" (nb), "r" (msr), "i" (bytes), "r" (msr0) |
---|
| 466 | + : "ctr", "memory"); |
---|
| 467 | +} |
---|
| 468 | +NOKPROBE_SYMBOL(flush_dcache_icache_phys) |
---|
| 469 | +#endif // !defined(CONFIG_PPC_8xx) && !defined(CONFIG_PPC64) |
---|
405 | 470 | |
---|
406 | 471 | /* |
---|
407 | 472 | * This is called when a page has been modified by the kernel. |
---|
.. | .. |
---|
435 | 500 | __flush_dcache_icache(start); |
---|
436 | 501 | kunmap_atomic(start); |
---|
437 | 502 | } else { |
---|
438 | | - __flush_dcache_icache_phys(page_to_pfn(page) << PAGE_SHIFT); |
---|
| 503 | + unsigned long addr = page_to_pfn(page) << PAGE_SHIFT; |
---|
| 504 | + |
---|
| 505 | + if (flush_coherent_icache(addr)) |
---|
| 506 | + return; |
---|
| 507 | + flush_dcache_icache_phys(addr); |
---|
439 | 508 | } |
---|
440 | 509 | #endif |
---|
441 | 510 | } |
---|
442 | 511 | EXPORT_SYMBOL(flush_dcache_icache_page); |
---|
| 512 | + |
---|
| 513 | +/** |
---|
| 514 | + * __flush_dcache_icache(): Flush a particular page from the data cache to RAM. |
---|
| 515 | + * Note: this is necessary because the instruction cache does *not* |
---|
| 516 | + * snoop from the data cache. |
---|
| 517 | + * |
---|
| 518 | + * @page: the address of the page to flush |
---|
| 519 | + */ |
---|
| 520 | +void __flush_dcache_icache(void *p) |
---|
| 521 | +{ |
---|
| 522 | + unsigned long addr = (unsigned long)p; |
---|
| 523 | + |
---|
| 524 | + if (flush_coherent_icache(addr)) |
---|
| 525 | + return; |
---|
| 526 | + |
---|
| 527 | + clean_dcache_range(addr, addr + PAGE_SIZE); |
---|
| 528 | + |
---|
| 529 | + /* |
---|
| 530 | + * We don't flush the icache on 44x. Those have a virtual icache and we |
---|
| 531 | + * don't have access to the virtual address here (it's not the page |
---|
| 532 | + * vaddr but where it's mapped in user space). The flushing of the |
---|
| 533 | + * icache on these is handled elsewhere, when a change in the address |
---|
| 534 | + * space occurs, before returning to user space. |
---|
| 535 | + */ |
---|
| 536 | + |
---|
| 537 | + if (mmu_has_feature(MMU_FTR_TYPE_44x)) |
---|
| 538 | + return; |
---|
| 539 | + |
---|
| 540 | + invalidate_icache_range(addr, addr + PAGE_SIZE); |
---|
| 541 | +} |
---|
443 | 542 | |
---|
444 | 543 | void clear_user_page(void *page, unsigned long vaddr, struct page *pg) |
---|
445 | 544 | { |
---|
.. | .. |
---|
477 | 576 | flush_dcache_page(pg); |
---|
478 | 577 | } |
---|
479 | 578 | |
---|
480 | | -void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, |
---|
| 579 | +void flush_icache_user_page(struct vm_area_struct *vma, struct page *page, |
---|
481 | 580 | unsigned long addr, int len) |
---|
482 | 581 | { |
---|
483 | 582 | unsigned long maddr; |
---|
.. | .. |
---|
486 | 585 | flush_icache_range(maddr, maddr + len); |
---|
487 | 586 | kunmap(page); |
---|
488 | 587 | } |
---|
489 | | -EXPORT_SYMBOL(flush_icache_user_range); |
---|
490 | | - |
---|
491 | | -/* |
---|
492 | | - * This is called at the end of handling a user page fault, when the |
---|
493 | | - * fault has been handled by updating a PTE in the linux page tables. |
---|
494 | | - * We use it to preload an HPTE into the hash table corresponding to |
---|
495 | | - * the updated linux PTE. |
---|
496 | | - * |
---|
497 | | - * This must always be called with the pte lock held. |
---|
498 | | - */ |
---|
499 | | -void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, |
---|
500 | | - pte_t *ptep) |
---|
501 | | -{ |
---|
502 | | -#ifdef CONFIG_PPC_STD_MMU |
---|
503 | | - /* |
---|
504 | | - * We don't need to worry about _PAGE_PRESENT here because we are |
---|
505 | | - * called with either mm->page_table_lock held or ptl lock held |
---|
506 | | - */ |
---|
507 | | - unsigned long access, trap; |
---|
508 | | - |
---|
509 | | - if (radix_enabled()) { |
---|
510 | | - prefetch((void *)address); |
---|
511 | | - return; |
---|
512 | | - } |
---|
513 | | - |
---|
514 | | - /* We only want HPTEs for linux PTEs that have _PAGE_ACCESSED set */ |
---|
515 | | - if (!pte_young(*ptep) || address >= TASK_SIZE) |
---|
516 | | - return; |
---|
517 | | - |
---|
518 | | - /* We try to figure out if we are coming from an instruction |
---|
519 | | - * access fault and pass that down to __hash_page so we avoid |
---|
520 | | - * double-faulting on execution of fresh text. We have to test |
---|
521 | | - * for regs NULL since init will get here first thing at boot |
---|
522 | | - * |
---|
523 | | - * We also avoid filling the hash if not coming from a fault |
---|
524 | | - */ |
---|
525 | | - |
---|
526 | | - trap = current->thread.regs ? TRAP(current->thread.regs) : 0UL; |
---|
527 | | - switch (trap) { |
---|
528 | | - case 0x300: |
---|
529 | | - access = 0UL; |
---|
530 | | - break; |
---|
531 | | - case 0x400: |
---|
532 | | - access = _PAGE_EXEC; |
---|
533 | | - break; |
---|
534 | | - default: |
---|
535 | | - return; |
---|
536 | | - } |
---|
537 | | - |
---|
538 | | - hash_preload(vma->vm_mm, address, access, trap); |
---|
539 | | -#endif /* CONFIG_PPC_STD_MMU */ |
---|
540 | | -#if (defined(CONFIG_PPC_BOOK3E_64) || defined(CONFIG_PPC_FSL_BOOK3E)) \ |
---|
541 | | - && defined(CONFIG_HUGETLB_PAGE) |
---|
542 | | - if (is_vm_hugetlb_page(vma)) |
---|
543 | | - book3e_hugetlb_preload(vma, address, *ptep); |
---|
544 | | -#endif |
---|
545 | | -} |
---|
546 | 588 | |
---|
547 | 589 | /* |
---|
548 | 590 | * System memory should not be in /proc/iomem but various tools expect it |
---|
.. | .. |
---|
550 | 592 | */ |
---|
551 | 593 | static int __init add_system_ram_resources(void) |
---|
552 | 594 | { |
---|
553 | | - struct memblock_region *reg; |
---|
| 595 | + phys_addr_t start, end; |
---|
| 596 | + u64 i; |
---|
554 | 597 | |
---|
555 | | - for_each_memblock(memory, reg) { |
---|
| 598 | + for_each_mem_range(i, &start, &end) { |
---|
556 | 599 | struct resource *res; |
---|
557 | | - unsigned long base = reg->base; |
---|
558 | | - unsigned long size = reg->size; |
---|
559 | 600 | |
---|
560 | 601 | res = kzalloc(sizeof(struct resource), GFP_KERNEL); |
---|
561 | 602 | WARN_ON(!res); |
---|
562 | 603 | |
---|
563 | 604 | if (res) { |
---|
564 | 605 | res->name = "System RAM"; |
---|
565 | | - res->start = base; |
---|
566 | | - res->end = base + size - 1; |
---|
| 606 | + res->start = start; |
---|
| 607 | + /* |
---|
| 608 | + * In memblock, end points to the first byte after |
---|
| 609 | + * the range while in resourses, end points to the |
---|
| 610 | + * last byte in the range. |
---|
| 611 | + */ |
---|
| 612 | + res->end = end - 1; |
---|
567 | 613 | res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; |
---|
568 | 614 | WARN_ON(request_resource(&iomem_resource, res) < 0); |
---|
569 | 615 | } |
---|
.. | .. |
---|
592 | 638 | return 0; |
---|
593 | 639 | } |
---|
594 | 640 | #endif /* CONFIG_STRICT_DEVMEM */ |
---|
| 641 | + |
---|
| 642 | +/* |
---|
| 643 | + * This is defined in kernel/resource.c but only powerpc needs to export it, for |
---|
| 644 | + * the EHEA driver. Drop this when drivers/net/ethernet/ibm/ehea is removed. |
---|
| 645 | + */ |
---|
| 646 | +EXPORT_SYMBOL_GPL(walk_system_ram_range); |
---|