18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PowerPC64 port by Mike Corrigan and Dave Engebretsen 48c2ecf20Sopenharmony_ci * {mikejc|engebret}@us.ibm.com 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * SMP scalability work: 98c2ecf20Sopenharmony_ci * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Module name: htab.c 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Description: 148c2ecf20Sopenharmony_ci * PowerPC Hashed Page Table functions 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#undef DEBUG 188c2ecf20Sopenharmony_ci#undef DEBUG_LOW 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "hash-mmu: " fmt 218c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 228c2ecf20Sopenharmony_ci#include <linux/errno.h> 238c2ecf20Sopenharmony_ci#include <linux/sched/mm.h> 248c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 258c2ecf20Sopenharmony_ci#include <linux/stat.h> 268c2ecf20Sopenharmony_ci#include <linux/sysctl.h> 278c2ecf20Sopenharmony_ci#include <linux/export.h> 288c2ecf20Sopenharmony_ci#include <linux/ctype.h> 298c2ecf20Sopenharmony_ci#include <linux/cache.h> 308c2ecf20Sopenharmony_ci#include <linux/init.h> 318c2ecf20Sopenharmony_ci#include <linux/signal.h> 328c2ecf20Sopenharmony_ci#include <linux/memblock.h> 338c2ecf20Sopenharmony_ci#include <linux/context_tracking.h> 348c2ecf20Sopenharmony_ci#include <linux/libfdt.h> 358c2ecf20Sopenharmony_ci#include <linux/pkeys.h> 368c2ecf20Sopenharmony_ci#include <linux/hugetlb.h> 378c2ecf20Sopenharmony_ci#include <linux/cpu.h> 388c2ecf20Sopenharmony_ci#include <linux/pgtable.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include <asm/debugfs.h> 418c2ecf20Sopenharmony_ci#include <asm/processor.h> 428c2ecf20Sopenharmony_ci#include <asm/mmu.h> 438c2ecf20Sopenharmony_ci#include <asm/mmu_context.h> 448c2ecf20Sopenharmony_ci#include <asm/page.h> 458c2ecf20Sopenharmony_ci#include <asm/types.h> 468c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 478c2ecf20Sopenharmony_ci#include <asm/machdep.h> 488c2ecf20Sopenharmony_ci#include <asm/prom.h> 498c2ecf20Sopenharmony_ci#include <asm/io.h> 508c2ecf20Sopenharmony_ci#include <asm/eeh.h> 518c2ecf20Sopenharmony_ci#include <asm/tlb.h> 528c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 538c2ecf20Sopenharmony_ci#include <asm/cputable.h> 548c2ecf20Sopenharmony_ci#include <asm/sections.h> 558c2ecf20Sopenharmony_ci#include <asm/copro.h> 568c2ecf20Sopenharmony_ci#include <asm/udbg.h> 578c2ecf20Sopenharmony_ci#include <asm/code-patching.h> 588c2ecf20Sopenharmony_ci#include <asm/fadump.h> 598c2ecf20Sopenharmony_ci#include <asm/firmware.h> 608c2ecf20Sopenharmony_ci#include <asm/tm.h> 618c2ecf20Sopenharmony_ci#include <asm/trace.h> 628c2ecf20Sopenharmony_ci#include <asm/ps3.h> 638c2ecf20Sopenharmony_ci#include <asm/pte-walk.h> 648c2ecf20Sopenharmony_ci#include <asm/asm-prototypes.h> 658c2ecf20Sopenharmony_ci#include <asm/ultravisor.h> 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#include <mm/mmu_decl.h> 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#include "internal.h" 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#ifdef DEBUG 738c2ecf20Sopenharmony_ci#define DBG(fmt...) udbg_printf(fmt) 748c2ecf20Sopenharmony_ci#else 758c2ecf20Sopenharmony_ci#define DBG(fmt...) 768c2ecf20Sopenharmony_ci#endif 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#ifdef DEBUG_LOW 798c2ecf20Sopenharmony_ci#define DBG_LOW(fmt...) udbg_printf(fmt) 808c2ecf20Sopenharmony_ci#else 818c2ecf20Sopenharmony_ci#define DBG_LOW(fmt...) 828c2ecf20Sopenharmony_ci#endif 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#define KB (1024) 858c2ecf20Sopenharmony_ci#define MB (1024*KB) 868c2ecf20Sopenharmony_ci#define GB (1024L*MB) 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* 898c2ecf20Sopenharmony_ci * Note: pte --> Linux PTE 908c2ecf20Sopenharmony_ci * HPTE --> PowerPC Hashed Page Table Entry 918c2ecf20Sopenharmony_ci * 928c2ecf20Sopenharmony_ci * Execution context: 938c2ecf20Sopenharmony_ci * htab_initialize is called with the MMU off (of course), but 948c2ecf20Sopenharmony_ci * the kernel has been copied down to zero so it can directly 958c2ecf20Sopenharmony_ci * reference global data. At this point it is very difficult 968c2ecf20Sopenharmony_ci * to print debug info. 978c2ecf20Sopenharmony_ci * 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic unsigned long _SDR1; 1018c2ecf20Sopenharmony_cistruct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT]; 1028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mmu_psize_defs); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ciu8 hpte_page_sizes[1 << LP_BITS]; 1058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hpte_page_sizes); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistruct hash_pte *htab_address; 1088c2ecf20Sopenharmony_ciunsigned long htab_size_bytes; 1098c2ecf20Sopenharmony_ciunsigned long htab_hash_mask; 1108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(htab_hash_mask); 1118c2ecf20Sopenharmony_ciint mmu_linear_psize = MMU_PAGE_4K; 1128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mmu_linear_psize); 1138c2ecf20Sopenharmony_ciint mmu_virtual_psize = MMU_PAGE_4K; 1148c2ecf20Sopenharmony_ciint mmu_vmalloc_psize = MMU_PAGE_4K; 1158c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARSEMEM_VMEMMAP 1168c2ecf20Sopenharmony_ciint mmu_vmemmap_psize = MMU_PAGE_4K; 1178c2ecf20Sopenharmony_ci#endif 1188c2ecf20Sopenharmony_ciint mmu_io_psize = MMU_PAGE_4K; 1198c2ecf20Sopenharmony_ciint mmu_kernel_ssize = MMU_SEGSIZE_256M; 1208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mmu_kernel_ssize); 1218c2ecf20Sopenharmony_ciint mmu_highuser_ssize = MMU_SEGSIZE_256M; 1228c2ecf20Sopenharmony_ciu16 mmu_slb_size = 64; 1238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mmu_slb_size); 1248c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES 1258c2ecf20Sopenharmony_ciint mmu_ci_restrictions; 1268c2ecf20Sopenharmony_ci#endif 1278c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_PAGEALLOC 1288c2ecf20Sopenharmony_cistatic u8 *linear_map_hash_slots; 1298c2ecf20Sopenharmony_cistatic unsigned long linear_map_hash_count; 1308c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(linear_map_hash_lock); 1318c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_PAGEALLOC */ 1328c2ecf20Sopenharmony_cistruct mmu_hash_ops mmu_hash_ops; 1338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mmu_hash_ops); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci/* 1368c2ecf20Sopenharmony_ci * These are definitions of page sizes arrays to be used when none 1378c2ecf20Sopenharmony_ci * is provided by the firmware. 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* 1418c2ecf20Sopenharmony_ci * Fallback (4k pages only) 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_cistatic struct mmu_psize_def mmu_psize_defaults[] = { 1448c2ecf20Sopenharmony_ci [MMU_PAGE_4K] = { 1458c2ecf20Sopenharmony_ci .shift = 12, 1468c2ecf20Sopenharmony_ci .sllp = 0, 1478c2ecf20Sopenharmony_ci .penc = {[MMU_PAGE_4K] = 0, [1 ... MMU_PAGE_COUNT - 1] = -1}, 1488c2ecf20Sopenharmony_ci .avpnm = 0, 1498c2ecf20Sopenharmony_ci .tlbiel = 0, 1508c2ecf20Sopenharmony_ci }, 1518c2ecf20Sopenharmony_ci}; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci/* 1548c2ecf20Sopenharmony_ci * POWER4, GPUL, POWER5 1558c2ecf20Sopenharmony_ci * 1568c2ecf20Sopenharmony_ci * Support for 16Mb large pages 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_cistatic struct mmu_psize_def mmu_psize_defaults_gp[] = { 1598c2ecf20Sopenharmony_ci [MMU_PAGE_4K] = { 1608c2ecf20Sopenharmony_ci .shift = 12, 1618c2ecf20Sopenharmony_ci .sllp = 0, 1628c2ecf20Sopenharmony_ci .penc = {[MMU_PAGE_4K] = 0, [1 ... MMU_PAGE_COUNT - 1] = -1}, 1638c2ecf20Sopenharmony_ci .avpnm = 0, 1648c2ecf20Sopenharmony_ci .tlbiel = 1, 1658c2ecf20Sopenharmony_ci }, 1668c2ecf20Sopenharmony_ci [MMU_PAGE_16M] = { 1678c2ecf20Sopenharmony_ci .shift = 24, 1688c2ecf20Sopenharmony_ci .sllp = SLB_VSID_L, 1698c2ecf20Sopenharmony_ci .penc = {[0 ... MMU_PAGE_16M - 1] = -1, [MMU_PAGE_16M] = 0, 1708c2ecf20Sopenharmony_ci [MMU_PAGE_16M + 1 ... MMU_PAGE_COUNT - 1] = -1 }, 1718c2ecf20Sopenharmony_ci .avpnm = 0x1UL, 1728c2ecf20Sopenharmony_ci .tlbiel = 0, 1738c2ecf20Sopenharmony_ci }, 1748c2ecf20Sopenharmony_ci}; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci/* 1778c2ecf20Sopenharmony_ci * 'R' and 'C' update notes: 1788c2ecf20Sopenharmony_ci * - Under pHyp or KVM, the updatepp path will not set C, thus it *will* 1798c2ecf20Sopenharmony_ci * create writeable HPTEs without C set, because the hcall H_PROTECT 1808c2ecf20Sopenharmony_ci * that we use in that case will not update C 1818c2ecf20Sopenharmony_ci * - The above is however not a problem, because we also don't do that 1828c2ecf20Sopenharmony_ci * fancy "no flush" variant of eviction and we use H_REMOVE which will 1838c2ecf20Sopenharmony_ci * do the right thing and thus we don't have the race I described earlier 1848c2ecf20Sopenharmony_ci * 1858c2ecf20Sopenharmony_ci * - Under bare metal, we do have the race, so we need R and C set 1868c2ecf20Sopenharmony_ci * - We make sure R is always set and never lost 1878c2ecf20Sopenharmony_ci * - C is _PAGE_DIRTY, and *should* always be set for a writeable mapping 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_ciunsigned long htab_convert_pte_flags(unsigned long pteflags) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci unsigned long rflags = 0; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* _PAGE_EXEC -> NOEXEC */ 1948c2ecf20Sopenharmony_ci if ((pteflags & _PAGE_EXEC) == 0) 1958c2ecf20Sopenharmony_ci rflags |= HPTE_R_N; 1968c2ecf20Sopenharmony_ci /* 1978c2ecf20Sopenharmony_ci * PPP bits: 1988c2ecf20Sopenharmony_ci * Linux uses slb key 0 for kernel and 1 for user. 1998c2ecf20Sopenharmony_ci * kernel RW areas are mapped with PPP=0b000 2008c2ecf20Sopenharmony_ci * User area is mapped with PPP=0b010 for read/write 2018c2ecf20Sopenharmony_ci * or PPP=0b011 for read-only (including writeable but clean pages). 2028c2ecf20Sopenharmony_ci */ 2038c2ecf20Sopenharmony_ci if (pteflags & _PAGE_PRIVILEGED) { 2048c2ecf20Sopenharmony_ci /* 2058c2ecf20Sopenharmony_ci * Kernel read only mapped with ppp bits 0b110 2068c2ecf20Sopenharmony_ci */ 2078c2ecf20Sopenharmony_ci if (!(pteflags & _PAGE_WRITE)) { 2088c2ecf20Sopenharmony_ci if (mmu_has_feature(MMU_FTR_KERNEL_RO)) 2098c2ecf20Sopenharmony_ci rflags |= (HPTE_R_PP0 | 0x2); 2108c2ecf20Sopenharmony_ci else 2118c2ecf20Sopenharmony_ci rflags |= 0x3; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci } else { 2148c2ecf20Sopenharmony_ci if (pteflags & _PAGE_RWX) 2158c2ecf20Sopenharmony_ci rflags |= 0x2; 2168c2ecf20Sopenharmony_ci if (!((pteflags & _PAGE_WRITE) && (pteflags & _PAGE_DIRTY))) 2178c2ecf20Sopenharmony_ci rflags |= 0x1; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci /* 2208c2ecf20Sopenharmony_ci * We can't allow hardware to update hpte bits. Hence always 2218c2ecf20Sopenharmony_ci * set 'R' bit and set 'C' if it is a write fault 2228c2ecf20Sopenharmony_ci */ 2238c2ecf20Sopenharmony_ci rflags |= HPTE_R_R; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (pteflags & _PAGE_DIRTY) 2268c2ecf20Sopenharmony_ci rflags |= HPTE_R_C; 2278c2ecf20Sopenharmony_ci /* 2288c2ecf20Sopenharmony_ci * Add in WIG bits 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if ((pteflags & _PAGE_CACHE_CTL) == _PAGE_TOLERANT) 2328c2ecf20Sopenharmony_ci rflags |= HPTE_R_I; 2338c2ecf20Sopenharmony_ci else if ((pteflags & _PAGE_CACHE_CTL) == _PAGE_NON_IDEMPOTENT) 2348c2ecf20Sopenharmony_ci rflags |= (HPTE_R_I | HPTE_R_G); 2358c2ecf20Sopenharmony_ci else if ((pteflags & _PAGE_CACHE_CTL) == _PAGE_SAO) 2368c2ecf20Sopenharmony_ci rflags |= (HPTE_R_W | HPTE_R_I | HPTE_R_M); 2378c2ecf20Sopenharmony_ci else 2388c2ecf20Sopenharmony_ci /* 2398c2ecf20Sopenharmony_ci * Add memory coherence if cache inhibited is not set 2408c2ecf20Sopenharmony_ci */ 2418c2ecf20Sopenharmony_ci rflags |= HPTE_R_M; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci rflags |= pte_to_hpte_pkey_bits(pteflags); 2448c2ecf20Sopenharmony_ci return rflags; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ciint htab_bolt_mapping(unsigned long vstart, unsigned long vend, 2488c2ecf20Sopenharmony_ci unsigned long pstart, unsigned long prot, 2498c2ecf20Sopenharmony_ci int psize, int ssize) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci unsigned long vaddr, paddr; 2528c2ecf20Sopenharmony_ci unsigned int step, shift; 2538c2ecf20Sopenharmony_ci int ret = 0; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci shift = mmu_psize_defs[psize].shift; 2568c2ecf20Sopenharmony_ci step = 1 << shift; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci prot = htab_convert_pte_flags(prot); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci DBG("htab_bolt_mapping(%lx..%lx -> %lx (%lx,%d,%d)\n", 2618c2ecf20Sopenharmony_ci vstart, vend, pstart, prot, psize, ssize); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* Carefully map only the possible range */ 2648c2ecf20Sopenharmony_ci vaddr = ALIGN(vstart, step); 2658c2ecf20Sopenharmony_ci paddr = ALIGN(pstart, step); 2668c2ecf20Sopenharmony_ci vend = ALIGN_DOWN(vend, step); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci for (; vaddr < vend; vaddr += step, paddr += step) { 2698c2ecf20Sopenharmony_ci unsigned long hash, hpteg; 2708c2ecf20Sopenharmony_ci unsigned long vsid = get_kernel_vsid(vaddr, ssize); 2718c2ecf20Sopenharmony_ci unsigned long vpn = hpt_vpn(vaddr, vsid, ssize); 2728c2ecf20Sopenharmony_ci unsigned long tprot = prot; 2738c2ecf20Sopenharmony_ci bool secondary_hash = false; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* 2768c2ecf20Sopenharmony_ci * If we hit a bad address return error. 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_ci if (!vsid) 2798c2ecf20Sopenharmony_ci return -1; 2808c2ecf20Sopenharmony_ci /* Make kernel text executable */ 2818c2ecf20Sopenharmony_ci if (overlaps_kernel_text(vaddr, vaddr + step)) 2828c2ecf20Sopenharmony_ci tprot &= ~HPTE_R_N; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* 2858c2ecf20Sopenharmony_ci * If relocatable, check if it overlaps interrupt vectors that 2868c2ecf20Sopenharmony_ci * are copied down to real 0. For relocatable kernel 2878c2ecf20Sopenharmony_ci * (e.g. kdump case) we copy interrupt vectors down to real 2888c2ecf20Sopenharmony_ci * address 0. Mark that region as executable. This is 2898c2ecf20Sopenharmony_ci * because on p8 system with relocation on exception feature 2908c2ecf20Sopenharmony_ci * enabled, exceptions are raised with MMU (IR=DR=1) ON. Hence 2918c2ecf20Sopenharmony_ci * in order to execute the interrupt handlers in virtual 2928c2ecf20Sopenharmony_ci * mode the vector region need to be marked as executable. 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_ci if ((PHYSICAL_START > MEMORY_START) && 2958c2ecf20Sopenharmony_ci overlaps_interrupt_vector_text(vaddr, vaddr + step)) 2968c2ecf20Sopenharmony_ci tprot &= ~HPTE_R_N; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci hash = hpt_hash(vpn, shift, ssize); 2998c2ecf20Sopenharmony_ci hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci BUG_ON(!mmu_hash_ops.hpte_insert); 3028c2ecf20Sopenharmony_cirepeat: 3038c2ecf20Sopenharmony_ci ret = mmu_hash_ops.hpte_insert(hpteg, vpn, paddr, tprot, 3048c2ecf20Sopenharmony_ci HPTE_V_BOLTED, psize, psize, 3058c2ecf20Sopenharmony_ci ssize); 3068c2ecf20Sopenharmony_ci if (ret == -1) { 3078c2ecf20Sopenharmony_ci /* 3088c2ecf20Sopenharmony_ci * Try to to keep bolted entries in primary. 3098c2ecf20Sopenharmony_ci * Remove non bolted entries and try insert again 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_ci ret = mmu_hash_ops.hpte_remove(hpteg); 3128c2ecf20Sopenharmony_ci if (ret != -1) 3138c2ecf20Sopenharmony_ci ret = mmu_hash_ops.hpte_insert(hpteg, vpn, paddr, tprot, 3148c2ecf20Sopenharmony_ci HPTE_V_BOLTED, psize, psize, 3158c2ecf20Sopenharmony_ci ssize); 3168c2ecf20Sopenharmony_ci if (ret == -1 && !secondary_hash) { 3178c2ecf20Sopenharmony_ci secondary_hash = true; 3188c2ecf20Sopenharmony_ci hpteg = ((~hash & htab_hash_mask) * HPTES_PER_GROUP); 3198c2ecf20Sopenharmony_ci goto repeat; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (ret < 0) 3248c2ecf20Sopenharmony_ci break; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci cond_resched(); 3278c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_PAGEALLOC 3288c2ecf20Sopenharmony_ci if (debug_pagealloc_enabled() && 3298c2ecf20Sopenharmony_ci (paddr >> PAGE_SHIFT) < linear_map_hash_count) 3308c2ecf20Sopenharmony_ci linear_map_hash_slots[paddr >> PAGE_SHIFT] = ret | 0x80; 3318c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_PAGEALLOC */ 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci return ret < 0 ? ret : 0; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ciint htab_remove_mapping(unsigned long vstart, unsigned long vend, 3378c2ecf20Sopenharmony_ci int psize, int ssize) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci unsigned long vaddr, time_limit; 3408c2ecf20Sopenharmony_ci unsigned int step, shift; 3418c2ecf20Sopenharmony_ci int rc; 3428c2ecf20Sopenharmony_ci int ret = 0; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci shift = mmu_psize_defs[psize].shift; 3458c2ecf20Sopenharmony_ci step = 1 << shift; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (!mmu_hash_ops.hpte_removebolted) 3488c2ecf20Sopenharmony_ci return -ENODEV; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* Unmap the full range specificied */ 3518c2ecf20Sopenharmony_ci vaddr = ALIGN_DOWN(vstart, step); 3528c2ecf20Sopenharmony_ci time_limit = jiffies + HZ; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci for (;vaddr < vend; vaddr += step) { 3558c2ecf20Sopenharmony_ci rc = mmu_hash_ops.hpte_removebolted(vaddr, psize, ssize); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* 3588c2ecf20Sopenharmony_ci * For large number of mappings introduce a cond_resched() 3598c2ecf20Sopenharmony_ci * to prevent softlockup warnings. 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_ci if (time_after(jiffies, time_limit)) { 3628c2ecf20Sopenharmony_ci cond_resched(); 3638c2ecf20Sopenharmony_ci time_limit = jiffies + HZ; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci if (rc == -ENOENT) { 3668c2ecf20Sopenharmony_ci ret = -ENOENT; 3678c2ecf20Sopenharmony_ci continue; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci if (rc < 0) 3708c2ecf20Sopenharmony_ci return rc; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci return ret; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic bool disable_1tb_segments = false; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic int __init parse_disable_1tb_segments(char *p) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci disable_1tb_segments = true; 3818c2ecf20Sopenharmony_ci return 0; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ciearly_param("disable_1tb_segments", parse_disable_1tb_segments); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic int __init htab_dt_scan_seg_sizes(unsigned long node, 3868c2ecf20Sopenharmony_ci const char *uname, int depth, 3878c2ecf20Sopenharmony_ci void *data) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci const char *type = of_get_flat_dt_prop(node, "device_type", NULL); 3908c2ecf20Sopenharmony_ci const __be32 *prop; 3918c2ecf20Sopenharmony_ci int size = 0; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* We are scanning "cpu" nodes only */ 3948c2ecf20Sopenharmony_ci if (type == NULL || strcmp(type, "cpu") != 0) 3958c2ecf20Sopenharmony_ci return 0; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci prop = of_get_flat_dt_prop(node, "ibm,processor-segment-sizes", &size); 3988c2ecf20Sopenharmony_ci if (prop == NULL) 3998c2ecf20Sopenharmony_ci return 0; 4008c2ecf20Sopenharmony_ci for (; size >= 4; size -= 4, ++prop) { 4018c2ecf20Sopenharmony_ci if (be32_to_cpu(prop[0]) == 40) { 4028c2ecf20Sopenharmony_ci DBG("1T segment support detected\n"); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (disable_1tb_segments) { 4058c2ecf20Sopenharmony_ci DBG("1T segments disabled by command line\n"); 4068c2ecf20Sopenharmony_ci break; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci cur_cpu_spec->mmu_features |= MMU_FTR_1T_SEGMENT; 4108c2ecf20Sopenharmony_ci return 1; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci cur_cpu_spec->mmu_features &= ~MMU_FTR_NO_SLBIE_B; 4148c2ecf20Sopenharmony_ci return 0; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic int __init get_idx_from_shift(unsigned int shift) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci int idx = -1; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci switch (shift) { 4228c2ecf20Sopenharmony_ci case 0xc: 4238c2ecf20Sopenharmony_ci idx = MMU_PAGE_4K; 4248c2ecf20Sopenharmony_ci break; 4258c2ecf20Sopenharmony_ci case 0x10: 4268c2ecf20Sopenharmony_ci idx = MMU_PAGE_64K; 4278c2ecf20Sopenharmony_ci break; 4288c2ecf20Sopenharmony_ci case 0x14: 4298c2ecf20Sopenharmony_ci idx = MMU_PAGE_1M; 4308c2ecf20Sopenharmony_ci break; 4318c2ecf20Sopenharmony_ci case 0x18: 4328c2ecf20Sopenharmony_ci idx = MMU_PAGE_16M; 4338c2ecf20Sopenharmony_ci break; 4348c2ecf20Sopenharmony_ci case 0x22: 4358c2ecf20Sopenharmony_ci idx = MMU_PAGE_16G; 4368c2ecf20Sopenharmony_ci break; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci return idx; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic int __init htab_dt_scan_page_sizes(unsigned long node, 4428c2ecf20Sopenharmony_ci const char *uname, int depth, 4438c2ecf20Sopenharmony_ci void *data) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci const char *type = of_get_flat_dt_prop(node, "device_type", NULL); 4468c2ecf20Sopenharmony_ci const __be32 *prop; 4478c2ecf20Sopenharmony_ci int size = 0; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* We are scanning "cpu" nodes only */ 4508c2ecf20Sopenharmony_ci if (type == NULL || strcmp(type, "cpu") != 0) 4518c2ecf20Sopenharmony_ci return 0; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci prop = of_get_flat_dt_prop(node, "ibm,segment-page-sizes", &size); 4548c2ecf20Sopenharmony_ci if (!prop) 4558c2ecf20Sopenharmony_ci return 0; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci pr_info("Page sizes from device-tree:\n"); 4588c2ecf20Sopenharmony_ci size /= 4; 4598c2ecf20Sopenharmony_ci cur_cpu_spec->mmu_features &= ~(MMU_FTR_16M_PAGE); 4608c2ecf20Sopenharmony_ci while(size > 0) { 4618c2ecf20Sopenharmony_ci unsigned int base_shift = be32_to_cpu(prop[0]); 4628c2ecf20Sopenharmony_ci unsigned int slbenc = be32_to_cpu(prop[1]); 4638c2ecf20Sopenharmony_ci unsigned int lpnum = be32_to_cpu(prop[2]); 4648c2ecf20Sopenharmony_ci struct mmu_psize_def *def; 4658c2ecf20Sopenharmony_ci int idx, base_idx; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci size -= 3; prop += 3; 4688c2ecf20Sopenharmony_ci base_idx = get_idx_from_shift(base_shift); 4698c2ecf20Sopenharmony_ci if (base_idx < 0) { 4708c2ecf20Sopenharmony_ci /* skip the pte encoding also */ 4718c2ecf20Sopenharmony_ci prop += lpnum * 2; size -= lpnum * 2; 4728c2ecf20Sopenharmony_ci continue; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci def = &mmu_psize_defs[base_idx]; 4758c2ecf20Sopenharmony_ci if (base_idx == MMU_PAGE_16M) 4768c2ecf20Sopenharmony_ci cur_cpu_spec->mmu_features |= MMU_FTR_16M_PAGE; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci def->shift = base_shift; 4798c2ecf20Sopenharmony_ci if (base_shift <= 23) 4808c2ecf20Sopenharmony_ci def->avpnm = 0; 4818c2ecf20Sopenharmony_ci else 4828c2ecf20Sopenharmony_ci def->avpnm = (1 << (base_shift - 23)) - 1; 4838c2ecf20Sopenharmony_ci def->sllp = slbenc; 4848c2ecf20Sopenharmony_ci /* 4858c2ecf20Sopenharmony_ci * We don't know for sure what's up with tlbiel, so 4868c2ecf20Sopenharmony_ci * for now we only set it for 4K and 64K pages 4878c2ecf20Sopenharmony_ci */ 4888c2ecf20Sopenharmony_ci if (base_idx == MMU_PAGE_4K || base_idx == MMU_PAGE_64K) 4898c2ecf20Sopenharmony_ci def->tlbiel = 1; 4908c2ecf20Sopenharmony_ci else 4918c2ecf20Sopenharmony_ci def->tlbiel = 0; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci while (size > 0 && lpnum) { 4948c2ecf20Sopenharmony_ci unsigned int shift = be32_to_cpu(prop[0]); 4958c2ecf20Sopenharmony_ci int penc = be32_to_cpu(prop[1]); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci prop += 2; size -= 2; 4988c2ecf20Sopenharmony_ci lpnum--; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci idx = get_idx_from_shift(shift); 5018c2ecf20Sopenharmony_ci if (idx < 0) 5028c2ecf20Sopenharmony_ci continue; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (penc == -1) 5058c2ecf20Sopenharmony_ci pr_err("Invalid penc for base_shift=%d " 5068c2ecf20Sopenharmony_ci "shift=%d\n", base_shift, shift); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci def->penc[idx] = penc; 5098c2ecf20Sopenharmony_ci pr_info("base_shift=%d: shift=%d, sllp=0x%04lx," 5108c2ecf20Sopenharmony_ci " avpnm=0x%08lx, tlbiel=%d, penc=%d\n", 5118c2ecf20Sopenharmony_ci base_shift, shift, def->sllp, 5128c2ecf20Sopenharmony_ci def->avpnm, def->tlbiel, def->penc[idx]); 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return 1; 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci#ifdef CONFIG_HUGETLB_PAGE 5208c2ecf20Sopenharmony_ci/* 5218c2ecf20Sopenharmony_ci * Scan for 16G memory blocks that have been set aside for huge pages 5228c2ecf20Sopenharmony_ci * and reserve those blocks for 16G huge pages. 5238c2ecf20Sopenharmony_ci */ 5248c2ecf20Sopenharmony_cistatic int __init htab_dt_scan_hugepage_blocks(unsigned long node, 5258c2ecf20Sopenharmony_ci const char *uname, int depth, 5268c2ecf20Sopenharmony_ci void *data) { 5278c2ecf20Sopenharmony_ci const char *type = of_get_flat_dt_prop(node, "device_type", NULL); 5288c2ecf20Sopenharmony_ci const __be64 *addr_prop; 5298c2ecf20Sopenharmony_ci const __be32 *page_count_prop; 5308c2ecf20Sopenharmony_ci unsigned int expected_pages; 5318c2ecf20Sopenharmony_ci long unsigned int phys_addr; 5328c2ecf20Sopenharmony_ci long unsigned int block_size; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci /* We are scanning "memory" nodes only */ 5358c2ecf20Sopenharmony_ci if (type == NULL || strcmp(type, "memory") != 0) 5368c2ecf20Sopenharmony_ci return 0; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci /* 5398c2ecf20Sopenharmony_ci * This property is the log base 2 of the number of virtual pages that 5408c2ecf20Sopenharmony_ci * will represent this memory block. 5418c2ecf20Sopenharmony_ci */ 5428c2ecf20Sopenharmony_ci page_count_prop = of_get_flat_dt_prop(node, "ibm,expected#pages", NULL); 5438c2ecf20Sopenharmony_ci if (page_count_prop == NULL) 5448c2ecf20Sopenharmony_ci return 0; 5458c2ecf20Sopenharmony_ci expected_pages = (1 << be32_to_cpu(page_count_prop[0])); 5468c2ecf20Sopenharmony_ci addr_prop = of_get_flat_dt_prop(node, "reg", NULL); 5478c2ecf20Sopenharmony_ci if (addr_prop == NULL) 5488c2ecf20Sopenharmony_ci return 0; 5498c2ecf20Sopenharmony_ci phys_addr = be64_to_cpu(addr_prop[0]); 5508c2ecf20Sopenharmony_ci block_size = be64_to_cpu(addr_prop[1]); 5518c2ecf20Sopenharmony_ci if (block_size != (16 * GB)) 5528c2ecf20Sopenharmony_ci return 0; 5538c2ecf20Sopenharmony_ci printk(KERN_INFO "Huge page(16GB) memory: " 5548c2ecf20Sopenharmony_ci "addr = 0x%lX size = 0x%lX pages = %d\n", 5558c2ecf20Sopenharmony_ci phys_addr, block_size, expected_pages); 5568c2ecf20Sopenharmony_ci if (phys_addr + block_size * expected_pages <= memblock_end_of_DRAM()) { 5578c2ecf20Sopenharmony_ci memblock_reserve(phys_addr, block_size * expected_pages); 5588c2ecf20Sopenharmony_ci pseries_add_gpage(phys_addr, block_size, expected_pages); 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci return 0; 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci#endif /* CONFIG_HUGETLB_PAGE */ 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic void mmu_psize_set_default_penc(void) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci int bpsize, apsize; 5678c2ecf20Sopenharmony_ci for (bpsize = 0; bpsize < MMU_PAGE_COUNT; bpsize++) 5688c2ecf20Sopenharmony_ci for (apsize = 0; apsize < MMU_PAGE_COUNT; apsize++) 5698c2ecf20Sopenharmony_ci mmu_psize_defs[bpsize].penc[apsize] = -1; 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic bool might_have_hea(void) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci /* 5778c2ecf20Sopenharmony_ci * The HEA ethernet adapter requires awareness of the 5788c2ecf20Sopenharmony_ci * GX bus. Without that awareness we can easily assume 5798c2ecf20Sopenharmony_ci * we will never see an HEA ethernet device. 5808c2ecf20Sopenharmony_ci */ 5818c2ecf20Sopenharmony_ci#ifdef CONFIG_IBMEBUS 5828c2ecf20Sopenharmony_ci return !cpu_has_feature(CPU_FTR_ARCH_207S) && 5838c2ecf20Sopenharmony_ci firmware_has_feature(FW_FEATURE_SPLPAR); 5848c2ecf20Sopenharmony_ci#else 5858c2ecf20Sopenharmony_ci return false; 5868c2ecf20Sopenharmony_ci#endif 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci#endif /* #ifdef CONFIG_PPC_64K_PAGES */ 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic void __init htab_scan_page_sizes(void) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci int rc; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci /* se the invalid penc to -1 */ 5968c2ecf20Sopenharmony_ci mmu_psize_set_default_penc(); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci /* Default to 4K pages only */ 5998c2ecf20Sopenharmony_ci memcpy(mmu_psize_defs, mmu_psize_defaults, 6008c2ecf20Sopenharmony_ci sizeof(mmu_psize_defaults)); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci /* 6038c2ecf20Sopenharmony_ci * Try to find the available page sizes in the device-tree 6048c2ecf20Sopenharmony_ci */ 6058c2ecf20Sopenharmony_ci rc = of_scan_flat_dt(htab_dt_scan_page_sizes, NULL); 6068c2ecf20Sopenharmony_ci if (rc == 0 && early_mmu_has_feature(MMU_FTR_16M_PAGE)) { 6078c2ecf20Sopenharmony_ci /* 6088c2ecf20Sopenharmony_ci * Nothing in the device-tree, but the CPU supports 16M pages, 6098c2ecf20Sopenharmony_ci * so let's fallback on a known size list for 16M capable CPUs. 6108c2ecf20Sopenharmony_ci */ 6118c2ecf20Sopenharmony_ci memcpy(mmu_psize_defs, mmu_psize_defaults_gp, 6128c2ecf20Sopenharmony_ci sizeof(mmu_psize_defaults_gp)); 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci#ifdef CONFIG_HUGETLB_PAGE 6168c2ecf20Sopenharmony_ci if (!hugetlb_disabled && !early_radix_enabled() ) { 6178c2ecf20Sopenharmony_ci /* Reserve 16G huge page memory sections for huge pages */ 6188c2ecf20Sopenharmony_ci of_scan_flat_dt(htab_dt_scan_hugepage_blocks, NULL); 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci#endif /* CONFIG_HUGETLB_PAGE */ 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci/* 6248c2ecf20Sopenharmony_ci * Fill in the hpte_page_sizes[] array. 6258c2ecf20Sopenharmony_ci * We go through the mmu_psize_defs[] array looking for all the 6268c2ecf20Sopenharmony_ci * supported base/actual page size combinations. Each combination 6278c2ecf20Sopenharmony_ci * has a unique pagesize encoding (penc) value in the low bits of 6288c2ecf20Sopenharmony_ci * the LP field of the HPTE. For actual page sizes less than 1MB, 6298c2ecf20Sopenharmony_ci * some of the upper LP bits are used for RPN bits, meaning that 6308c2ecf20Sopenharmony_ci * we need to fill in several entries in hpte_page_sizes[]. 6318c2ecf20Sopenharmony_ci * 6328c2ecf20Sopenharmony_ci * In diagrammatic form, with r = RPN bits and z = page size bits: 6338c2ecf20Sopenharmony_ci * PTE LP actual page size 6348c2ecf20Sopenharmony_ci * rrrr rrrz >=8KB 6358c2ecf20Sopenharmony_ci * rrrr rrzz >=16KB 6368c2ecf20Sopenharmony_ci * rrrr rzzz >=32KB 6378c2ecf20Sopenharmony_ci * rrrr zzzz >=64KB 6388c2ecf20Sopenharmony_ci * ... 6398c2ecf20Sopenharmony_ci * 6408c2ecf20Sopenharmony_ci * The zzzz bits are implementation-specific but are chosen so that 6418c2ecf20Sopenharmony_ci * no encoding for a larger page size uses the same value in its 6428c2ecf20Sopenharmony_ci * low-order N bits as the encoding for the 2^(12+N) byte page size 6438c2ecf20Sopenharmony_ci * (if it exists). 6448c2ecf20Sopenharmony_ci */ 6458c2ecf20Sopenharmony_cistatic void init_hpte_page_sizes(void) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci long int ap, bp; 6488c2ecf20Sopenharmony_ci long int shift, penc; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci for (bp = 0; bp < MMU_PAGE_COUNT; ++bp) { 6518c2ecf20Sopenharmony_ci if (!mmu_psize_defs[bp].shift) 6528c2ecf20Sopenharmony_ci continue; /* not a supported page size */ 6538c2ecf20Sopenharmony_ci for (ap = bp; ap < MMU_PAGE_COUNT; ++ap) { 6548c2ecf20Sopenharmony_ci penc = mmu_psize_defs[bp].penc[ap]; 6558c2ecf20Sopenharmony_ci if (penc == -1 || !mmu_psize_defs[ap].shift) 6568c2ecf20Sopenharmony_ci continue; 6578c2ecf20Sopenharmony_ci shift = mmu_psize_defs[ap].shift - LP_SHIFT; 6588c2ecf20Sopenharmony_ci if (shift <= 0) 6598c2ecf20Sopenharmony_ci continue; /* should never happen */ 6608c2ecf20Sopenharmony_ci /* 6618c2ecf20Sopenharmony_ci * For page sizes less than 1MB, this loop 6628c2ecf20Sopenharmony_ci * replicates the entry for all possible values 6638c2ecf20Sopenharmony_ci * of the rrrr bits. 6648c2ecf20Sopenharmony_ci */ 6658c2ecf20Sopenharmony_ci while (penc < (1 << LP_BITS)) { 6668c2ecf20Sopenharmony_ci hpte_page_sizes[penc] = (ap << 4) | bp; 6678c2ecf20Sopenharmony_ci penc += 1 << shift; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic void __init htab_init_page_sizes(void) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci bool aligned = true; 6768c2ecf20Sopenharmony_ci init_hpte_page_sizes(); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci if (!debug_pagealloc_enabled()) { 6798c2ecf20Sopenharmony_ci /* 6808c2ecf20Sopenharmony_ci * Pick a size for the linear mapping. Currently, we only 6818c2ecf20Sopenharmony_ci * support 16M, 1M and 4K which is the default 6828c2ecf20Sopenharmony_ci */ 6838c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX) && 6848c2ecf20Sopenharmony_ci (unsigned long)_stext % 0x1000000) { 6858c2ecf20Sopenharmony_ci if (mmu_psize_defs[MMU_PAGE_16M].shift) 6868c2ecf20Sopenharmony_ci pr_warn("Kernel not 16M aligned, disabling 16M linear map alignment\n"); 6878c2ecf20Sopenharmony_ci aligned = false; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci if (mmu_psize_defs[MMU_PAGE_16M].shift && aligned) 6918c2ecf20Sopenharmony_ci mmu_linear_psize = MMU_PAGE_16M; 6928c2ecf20Sopenharmony_ci else if (mmu_psize_defs[MMU_PAGE_1M].shift) 6938c2ecf20Sopenharmony_ci mmu_linear_psize = MMU_PAGE_1M; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES 6978c2ecf20Sopenharmony_ci /* 6988c2ecf20Sopenharmony_ci * Pick a size for the ordinary pages. Default is 4K, we support 6998c2ecf20Sopenharmony_ci * 64K for user mappings and vmalloc if supported by the processor. 7008c2ecf20Sopenharmony_ci * We only use 64k for ioremap if the processor 7018c2ecf20Sopenharmony_ci * (and firmware) support cache-inhibited large pages. 7028c2ecf20Sopenharmony_ci * If not, we use 4k and set mmu_ci_restrictions so that 7038c2ecf20Sopenharmony_ci * hash_page knows to switch processes that use cache-inhibited 7048c2ecf20Sopenharmony_ci * mappings to 4k pages. 7058c2ecf20Sopenharmony_ci */ 7068c2ecf20Sopenharmony_ci if (mmu_psize_defs[MMU_PAGE_64K].shift) { 7078c2ecf20Sopenharmony_ci mmu_virtual_psize = MMU_PAGE_64K; 7088c2ecf20Sopenharmony_ci mmu_vmalloc_psize = MMU_PAGE_64K; 7098c2ecf20Sopenharmony_ci if (mmu_linear_psize == MMU_PAGE_4K) 7108c2ecf20Sopenharmony_ci mmu_linear_psize = MMU_PAGE_64K; 7118c2ecf20Sopenharmony_ci if (mmu_has_feature(MMU_FTR_CI_LARGE_PAGE)) { 7128c2ecf20Sopenharmony_ci /* 7138c2ecf20Sopenharmony_ci * When running on pSeries using 64k pages for ioremap 7148c2ecf20Sopenharmony_ci * would stop us accessing the HEA ethernet. So if we 7158c2ecf20Sopenharmony_ci * have the chance of ever seeing one, stay at 4k. 7168c2ecf20Sopenharmony_ci */ 7178c2ecf20Sopenharmony_ci if (!might_have_hea()) 7188c2ecf20Sopenharmony_ci mmu_io_psize = MMU_PAGE_64K; 7198c2ecf20Sopenharmony_ci } else 7208c2ecf20Sopenharmony_ci mmu_ci_restrictions = 1; 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_64K_PAGES */ 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARSEMEM_VMEMMAP 7258c2ecf20Sopenharmony_ci /* 7268c2ecf20Sopenharmony_ci * We try to use 16M pages for vmemmap if that is supported 7278c2ecf20Sopenharmony_ci * and we have at least 1G of RAM at boot 7288c2ecf20Sopenharmony_ci */ 7298c2ecf20Sopenharmony_ci if (mmu_psize_defs[MMU_PAGE_16M].shift && 7308c2ecf20Sopenharmony_ci memblock_phys_mem_size() >= 0x40000000) 7318c2ecf20Sopenharmony_ci mmu_vmemmap_psize = MMU_PAGE_16M; 7328c2ecf20Sopenharmony_ci else 7338c2ecf20Sopenharmony_ci mmu_vmemmap_psize = mmu_virtual_psize; 7348c2ecf20Sopenharmony_ci#endif /* CONFIG_SPARSEMEM_VMEMMAP */ 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Page orders: linear mapping = %d, " 7378c2ecf20Sopenharmony_ci "virtual = %d, io = %d" 7388c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARSEMEM_VMEMMAP 7398c2ecf20Sopenharmony_ci ", vmemmap = %d" 7408c2ecf20Sopenharmony_ci#endif 7418c2ecf20Sopenharmony_ci "\n", 7428c2ecf20Sopenharmony_ci mmu_psize_defs[mmu_linear_psize].shift, 7438c2ecf20Sopenharmony_ci mmu_psize_defs[mmu_virtual_psize].shift, 7448c2ecf20Sopenharmony_ci mmu_psize_defs[mmu_io_psize].shift 7458c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARSEMEM_VMEMMAP 7468c2ecf20Sopenharmony_ci ,mmu_psize_defs[mmu_vmemmap_psize].shift 7478c2ecf20Sopenharmony_ci#endif 7488c2ecf20Sopenharmony_ci ); 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic int __init htab_dt_scan_pftsize(unsigned long node, 7528c2ecf20Sopenharmony_ci const char *uname, int depth, 7538c2ecf20Sopenharmony_ci void *data) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci const char *type = of_get_flat_dt_prop(node, "device_type", NULL); 7568c2ecf20Sopenharmony_ci const __be32 *prop; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci /* We are scanning "cpu" nodes only */ 7598c2ecf20Sopenharmony_ci if (type == NULL || strcmp(type, "cpu") != 0) 7608c2ecf20Sopenharmony_ci return 0; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci prop = of_get_flat_dt_prop(node, "ibm,pft-size", NULL); 7638c2ecf20Sopenharmony_ci if (prop != NULL) { 7648c2ecf20Sopenharmony_ci /* pft_size[0] is the NUMA CEC cookie */ 7658c2ecf20Sopenharmony_ci ppc64_pft_size = be32_to_cpu(prop[1]); 7668c2ecf20Sopenharmony_ci return 1; 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci return 0; 7698c2ecf20Sopenharmony_ci} 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ciunsigned htab_shift_for_mem_size(unsigned long mem_size) 7728c2ecf20Sopenharmony_ci{ 7738c2ecf20Sopenharmony_ci unsigned memshift = __ilog2(mem_size); 7748c2ecf20Sopenharmony_ci unsigned pshift = mmu_psize_defs[mmu_virtual_psize].shift; 7758c2ecf20Sopenharmony_ci unsigned pteg_shift; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci /* round mem_size up to next power of 2 */ 7788c2ecf20Sopenharmony_ci if ((1UL << memshift) < mem_size) 7798c2ecf20Sopenharmony_ci memshift += 1; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci /* aim for 2 pages / pteg */ 7828c2ecf20Sopenharmony_ci pteg_shift = memshift - (pshift + 1); 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci /* 7858c2ecf20Sopenharmony_ci * 2^11 PTEGS of 128 bytes each, ie. 2^18 bytes is the minimum htab 7868c2ecf20Sopenharmony_ci * size permitted by the architecture. 7878c2ecf20Sopenharmony_ci */ 7888c2ecf20Sopenharmony_ci return max(pteg_shift + 7, 18U); 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_cistatic unsigned long __init htab_get_table_size(void) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci /* 7948c2ecf20Sopenharmony_ci * If hash size isn't already provided by the platform, we try to 7958c2ecf20Sopenharmony_ci * retrieve it from the device-tree. If it's not there neither, we 7968c2ecf20Sopenharmony_ci * calculate it now based on the total RAM size 7978c2ecf20Sopenharmony_ci */ 7988c2ecf20Sopenharmony_ci if (ppc64_pft_size == 0) 7998c2ecf20Sopenharmony_ci of_scan_flat_dt(htab_dt_scan_pftsize, NULL); 8008c2ecf20Sopenharmony_ci if (ppc64_pft_size) 8018c2ecf20Sopenharmony_ci return 1UL << ppc64_pft_size; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci return 1UL << htab_shift_for_mem_size(memblock_phys_mem_size()); 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci#ifdef CONFIG_MEMORY_HOTPLUG 8078c2ecf20Sopenharmony_cistatic int resize_hpt_for_hotplug(unsigned long new_mem_size) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci unsigned target_hpt_shift; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci if (!mmu_hash_ops.resize_hpt) 8128c2ecf20Sopenharmony_ci return 0; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci target_hpt_shift = htab_shift_for_mem_size(new_mem_size); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci /* 8178c2ecf20Sopenharmony_ci * To avoid lots of HPT resizes if memory size is fluctuating 8188c2ecf20Sopenharmony_ci * across a boundary, we deliberately have some hysterisis 8198c2ecf20Sopenharmony_ci * here: we immediately increase the HPT size if the target 8208c2ecf20Sopenharmony_ci * shift exceeds the current shift, but we won't attempt to 8218c2ecf20Sopenharmony_ci * reduce unless the target shift is at least 2 below the 8228c2ecf20Sopenharmony_ci * current shift 8238c2ecf20Sopenharmony_ci */ 8248c2ecf20Sopenharmony_ci if (target_hpt_shift > ppc64_pft_size || 8258c2ecf20Sopenharmony_ci target_hpt_shift < ppc64_pft_size - 1) 8268c2ecf20Sopenharmony_ci return mmu_hash_ops.resize_hpt(target_hpt_shift); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci return 0; 8298c2ecf20Sopenharmony_ci} 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ciint hash__create_section_mapping(unsigned long start, unsigned long end, 8328c2ecf20Sopenharmony_ci int nid, pgprot_t prot) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci int rc; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci if (end >= H_VMALLOC_START) { 8378c2ecf20Sopenharmony_ci pr_warn("Outside the supported range\n"); 8388c2ecf20Sopenharmony_ci return -1; 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci resize_hpt_for_hotplug(memblock_phys_mem_size()); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci rc = htab_bolt_mapping(start, end, __pa(start), 8448c2ecf20Sopenharmony_ci pgprot_val(prot), mmu_linear_psize, 8458c2ecf20Sopenharmony_ci mmu_kernel_ssize); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (rc < 0) { 8488c2ecf20Sopenharmony_ci int rc2 = htab_remove_mapping(start, end, mmu_linear_psize, 8498c2ecf20Sopenharmony_ci mmu_kernel_ssize); 8508c2ecf20Sopenharmony_ci BUG_ON(rc2 && (rc2 != -ENOENT)); 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci return rc; 8538c2ecf20Sopenharmony_ci} 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ciint hash__remove_section_mapping(unsigned long start, unsigned long end) 8568c2ecf20Sopenharmony_ci{ 8578c2ecf20Sopenharmony_ci int rc = htab_remove_mapping(start, end, mmu_linear_psize, 8588c2ecf20Sopenharmony_ci mmu_kernel_ssize); 8598c2ecf20Sopenharmony_ci WARN_ON(rc < 0); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci if (resize_hpt_for_hotplug(memblock_phys_mem_size()) == -ENOSPC) 8628c2ecf20Sopenharmony_ci pr_warn("Hash collision while resizing HPT\n"); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci return rc; 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci#endif /* CONFIG_MEMORY_HOTPLUG */ 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_cistatic void __init hash_init_partition_table(phys_addr_t hash_table, 8698c2ecf20Sopenharmony_ci unsigned long htab_size) 8708c2ecf20Sopenharmony_ci{ 8718c2ecf20Sopenharmony_ci mmu_partition_table_init(); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci /* 8748c2ecf20Sopenharmony_ci * PS field (VRMA page size) is not used for LPID 0, hence set to 0. 8758c2ecf20Sopenharmony_ci * For now, UPRT is 0 and we have no segment table. 8768c2ecf20Sopenharmony_ci */ 8778c2ecf20Sopenharmony_ci htab_size = __ilog2(htab_size) - 18; 8788c2ecf20Sopenharmony_ci mmu_partition_table_set_entry(0, hash_table | htab_size, 0, false); 8798c2ecf20Sopenharmony_ci pr_info("Partition table %p\n", partition_tb); 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cistatic void __init htab_initialize(void) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci unsigned long table; 8858c2ecf20Sopenharmony_ci unsigned long pteg_count; 8868c2ecf20Sopenharmony_ci unsigned long prot; 8878c2ecf20Sopenharmony_ci phys_addr_t base = 0, size = 0, end; 8888c2ecf20Sopenharmony_ci u64 i; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci DBG(" -> htab_initialize()\n"); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) { 8938c2ecf20Sopenharmony_ci mmu_kernel_ssize = MMU_SEGSIZE_1T; 8948c2ecf20Sopenharmony_ci mmu_highuser_ssize = MMU_SEGSIZE_1T; 8958c2ecf20Sopenharmony_ci printk(KERN_INFO "Using 1TB segments\n"); 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci if (stress_slb_enabled) 8998c2ecf20Sopenharmony_ci static_branch_enable(&stress_slb_key); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci /* 9028c2ecf20Sopenharmony_ci * Calculate the required size of the htab. We want the number of 9038c2ecf20Sopenharmony_ci * PTEGs to equal one half the number of real pages. 9048c2ecf20Sopenharmony_ci */ 9058c2ecf20Sopenharmony_ci htab_size_bytes = htab_get_table_size(); 9068c2ecf20Sopenharmony_ci pteg_count = htab_size_bytes >> 7; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci htab_hash_mask = pteg_count - 1; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci if (firmware_has_feature(FW_FEATURE_LPAR) || 9118c2ecf20Sopenharmony_ci firmware_has_feature(FW_FEATURE_PS3_LV1)) { 9128c2ecf20Sopenharmony_ci /* Using a hypervisor which owns the htab */ 9138c2ecf20Sopenharmony_ci htab_address = NULL; 9148c2ecf20Sopenharmony_ci _SDR1 = 0; 9158c2ecf20Sopenharmony_ci#ifdef CONFIG_FA_DUMP 9168c2ecf20Sopenharmony_ci /* 9178c2ecf20Sopenharmony_ci * If firmware assisted dump is active firmware preserves 9188c2ecf20Sopenharmony_ci * the contents of htab along with entire partition memory. 9198c2ecf20Sopenharmony_ci * Clear the htab if firmware assisted dump is active so 9208c2ecf20Sopenharmony_ci * that we dont end up using old mappings. 9218c2ecf20Sopenharmony_ci */ 9228c2ecf20Sopenharmony_ci if (is_fadump_active() && mmu_hash_ops.hpte_clear_all) 9238c2ecf20Sopenharmony_ci mmu_hash_ops.hpte_clear_all(); 9248c2ecf20Sopenharmony_ci#endif 9258c2ecf20Sopenharmony_ci } else { 9268c2ecf20Sopenharmony_ci unsigned long limit = MEMBLOCK_ALLOC_ANYWHERE; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_CELL 9298c2ecf20Sopenharmony_ci /* 9308c2ecf20Sopenharmony_ci * Cell may require the hash table down low when using the 9318c2ecf20Sopenharmony_ci * Axon IOMMU in order to fit the dynamic region over it, see 9328c2ecf20Sopenharmony_ci * comments in cell/iommu.c 9338c2ecf20Sopenharmony_ci */ 9348c2ecf20Sopenharmony_ci if (fdt_subnode_offset(initial_boot_params, 0, "axon") > 0) { 9358c2ecf20Sopenharmony_ci limit = 0x80000000; 9368c2ecf20Sopenharmony_ci pr_info("Hash table forced below 2G for Axon IOMMU\n"); 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_CELL */ 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci table = memblock_phys_alloc_range(htab_size_bytes, 9418c2ecf20Sopenharmony_ci htab_size_bytes, 9428c2ecf20Sopenharmony_ci 0, limit); 9438c2ecf20Sopenharmony_ci if (!table) 9448c2ecf20Sopenharmony_ci panic("ERROR: Failed to allocate %pa bytes below %pa\n", 9458c2ecf20Sopenharmony_ci &htab_size_bytes, &limit); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci DBG("Hash table allocated at %lx, size: %lx\n", table, 9488c2ecf20Sopenharmony_ci htab_size_bytes); 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci htab_address = __va(table); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci /* htab absolute addr + encoded htabsize */ 9538c2ecf20Sopenharmony_ci _SDR1 = table + __ilog2(htab_size_bytes) - 18; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci /* Initialize the HPT with no entries */ 9568c2ecf20Sopenharmony_ci memset((void *)table, 0, htab_size_bytes); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_ARCH_300)) 9598c2ecf20Sopenharmony_ci /* Set SDR1 */ 9608c2ecf20Sopenharmony_ci mtspr(SPRN_SDR1, _SDR1); 9618c2ecf20Sopenharmony_ci else 9628c2ecf20Sopenharmony_ci hash_init_partition_table(table, htab_size_bytes); 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci prot = pgprot_val(PAGE_KERNEL); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_PAGEALLOC 9688c2ecf20Sopenharmony_ci if (debug_pagealloc_enabled()) { 9698c2ecf20Sopenharmony_ci linear_map_hash_count = memblock_end_of_DRAM() >> PAGE_SHIFT; 9708c2ecf20Sopenharmony_ci linear_map_hash_slots = memblock_alloc_try_nid( 9718c2ecf20Sopenharmony_ci linear_map_hash_count, 1, MEMBLOCK_LOW_LIMIT, 9728c2ecf20Sopenharmony_ci ppc64_rma_size, NUMA_NO_NODE); 9738c2ecf20Sopenharmony_ci if (!linear_map_hash_slots) 9748c2ecf20Sopenharmony_ci panic("%s: Failed to allocate %lu bytes max_addr=%pa\n", 9758c2ecf20Sopenharmony_ci __func__, linear_map_hash_count, &ppc64_rma_size); 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_PAGEALLOC */ 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci /* create bolted the linear mapping in the hash table */ 9808c2ecf20Sopenharmony_ci for_each_mem_range(i, &base, &end) { 9818c2ecf20Sopenharmony_ci size = end - base; 9828c2ecf20Sopenharmony_ci base = (unsigned long)__va(base); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci DBG("creating mapping for region: %lx..%lx (prot: %lx)\n", 9858c2ecf20Sopenharmony_ci base, size, prot); 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci if ((base + size) >= H_VMALLOC_START) { 9888c2ecf20Sopenharmony_ci pr_warn("Outside the supported range\n"); 9898c2ecf20Sopenharmony_ci continue; 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci BUG_ON(htab_bolt_mapping(base, base + size, __pa(base), 9938c2ecf20Sopenharmony_ci prot, mmu_linear_psize, mmu_kernel_ssize)); 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE); 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci /* 9988c2ecf20Sopenharmony_ci * If we have a memory_limit and we've allocated TCEs then we need to 9998c2ecf20Sopenharmony_ci * explicitly map the TCE area at the top of RAM. We also cope with the 10008c2ecf20Sopenharmony_ci * case that the TCEs start below memory_limit. 10018c2ecf20Sopenharmony_ci * tce_alloc_start/end are 16MB aligned so the mapping should work 10028c2ecf20Sopenharmony_ci * for either 4K or 16MB pages. 10038c2ecf20Sopenharmony_ci */ 10048c2ecf20Sopenharmony_ci if (tce_alloc_start) { 10058c2ecf20Sopenharmony_ci tce_alloc_start = (unsigned long)__va(tce_alloc_start); 10068c2ecf20Sopenharmony_ci tce_alloc_end = (unsigned long)__va(tce_alloc_end); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci if (base + size >= tce_alloc_start) 10098c2ecf20Sopenharmony_ci tce_alloc_start = base + size + 1; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci BUG_ON(htab_bolt_mapping(tce_alloc_start, tce_alloc_end, 10128c2ecf20Sopenharmony_ci __pa(tce_alloc_start), prot, 10138c2ecf20Sopenharmony_ci mmu_linear_psize, mmu_kernel_ssize)); 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci DBG(" <- htab_initialize()\n"); 10188c2ecf20Sopenharmony_ci} 10198c2ecf20Sopenharmony_ci#undef KB 10208c2ecf20Sopenharmony_ci#undef MB 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_civoid __init hash__early_init_devtree(void) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci /* Initialize segment sizes */ 10258c2ecf20Sopenharmony_ci of_scan_flat_dt(htab_dt_scan_seg_sizes, NULL); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci /* Initialize page sizes */ 10288c2ecf20Sopenharmony_ci htab_scan_page_sizes(); 10298c2ecf20Sopenharmony_ci} 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_cistatic struct hash_mm_context init_hash_mm_context; 10328c2ecf20Sopenharmony_civoid __init hash__early_init_mmu(void) 10338c2ecf20Sopenharmony_ci{ 10348c2ecf20Sopenharmony_ci#ifndef CONFIG_PPC_64K_PAGES 10358c2ecf20Sopenharmony_ci /* 10368c2ecf20Sopenharmony_ci * We have code in __hash_page_4K() and elsewhere, which assumes it can 10378c2ecf20Sopenharmony_ci * do the following: 10388c2ecf20Sopenharmony_ci * new_pte |= (slot << H_PAGE_F_GIX_SHIFT) & (H_PAGE_F_SECOND | H_PAGE_F_GIX); 10398c2ecf20Sopenharmony_ci * 10408c2ecf20Sopenharmony_ci * Where the slot number is between 0-15, and values of 8-15 indicate 10418c2ecf20Sopenharmony_ci * the secondary bucket. For that code to work H_PAGE_F_SECOND and 10428c2ecf20Sopenharmony_ci * H_PAGE_F_GIX must occupy four contiguous bits in the PTE, and 10438c2ecf20Sopenharmony_ci * H_PAGE_F_SECOND must be placed above H_PAGE_F_GIX. Assert that here 10448c2ecf20Sopenharmony_ci * with a BUILD_BUG_ON(). 10458c2ecf20Sopenharmony_ci */ 10468c2ecf20Sopenharmony_ci BUILD_BUG_ON(H_PAGE_F_SECOND != (1ul << (H_PAGE_F_GIX_SHIFT + 3))); 10478c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_64K_PAGES */ 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci htab_init_page_sizes(); 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci /* 10528c2ecf20Sopenharmony_ci * initialize page table size 10538c2ecf20Sopenharmony_ci */ 10548c2ecf20Sopenharmony_ci __pte_frag_nr = H_PTE_FRAG_NR; 10558c2ecf20Sopenharmony_ci __pte_frag_size_shift = H_PTE_FRAG_SIZE_SHIFT; 10568c2ecf20Sopenharmony_ci __pmd_frag_nr = H_PMD_FRAG_NR; 10578c2ecf20Sopenharmony_ci __pmd_frag_size_shift = H_PMD_FRAG_SIZE_SHIFT; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci __pte_index_size = H_PTE_INDEX_SIZE; 10608c2ecf20Sopenharmony_ci __pmd_index_size = H_PMD_INDEX_SIZE; 10618c2ecf20Sopenharmony_ci __pud_index_size = H_PUD_INDEX_SIZE; 10628c2ecf20Sopenharmony_ci __pgd_index_size = H_PGD_INDEX_SIZE; 10638c2ecf20Sopenharmony_ci __pud_cache_index = H_PUD_CACHE_INDEX; 10648c2ecf20Sopenharmony_ci __pte_table_size = H_PTE_TABLE_SIZE; 10658c2ecf20Sopenharmony_ci __pmd_table_size = H_PMD_TABLE_SIZE; 10668c2ecf20Sopenharmony_ci __pud_table_size = H_PUD_TABLE_SIZE; 10678c2ecf20Sopenharmony_ci __pgd_table_size = H_PGD_TABLE_SIZE; 10688c2ecf20Sopenharmony_ci /* 10698c2ecf20Sopenharmony_ci * 4k use hugepd format, so for hash set then to 10708c2ecf20Sopenharmony_ci * zero 10718c2ecf20Sopenharmony_ci */ 10728c2ecf20Sopenharmony_ci __pmd_val_bits = HASH_PMD_VAL_BITS; 10738c2ecf20Sopenharmony_ci __pud_val_bits = HASH_PUD_VAL_BITS; 10748c2ecf20Sopenharmony_ci __pgd_val_bits = HASH_PGD_VAL_BITS; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci __kernel_virt_start = H_KERN_VIRT_START; 10778c2ecf20Sopenharmony_ci __vmalloc_start = H_VMALLOC_START; 10788c2ecf20Sopenharmony_ci __vmalloc_end = H_VMALLOC_END; 10798c2ecf20Sopenharmony_ci __kernel_io_start = H_KERN_IO_START; 10808c2ecf20Sopenharmony_ci __kernel_io_end = H_KERN_IO_END; 10818c2ecf20Sopenharmony_ci vmemmap = (struct page *)H_VMEMMAP_START; 10828c2ecf20Sopenharmony_ci ioremap_bot = IOREMAP_BASE; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 10858c2ecf20Sopenharmony_ci pci_io_base = ISA_IO_BASE; 10868c2ecf20Sopenharmony_ci#endif 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci /* Select appropriate backend */ 10898c2ecf20Sopenharmony_ci if (firmware_has_feature(FW_FEATURE_PS3_LV1)) 10908c2ecf20Sopenharmony_ci ps3_early_mm_init(); 10918c2ecf20Sopenharmony_ci else if (firmware_has_feature(FW_FEATURE_LPAR)) 10928c2ecf20Sopenharmony_ci hpte_init_pseries(); 10938c2ecf20Sopenharmony_ci else if (IS_ENABLED(CONFIG_PPC_NATIVE)) 10948c2ecf20Sopenharmony_ci hpte_init_native(); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci if (!mmu_hash_ops.hpte_insert) 10978c2ecf20Sopenharmony_ci panic("hash__early_init_mmu: No MMU hash ops defined!\n"); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci /* 11008c2ecf20Sopenharmony_ci * Initialize the MMU Hash table and create the linear mapping 11018c2ecf20Sopenharmony_ci * of memory. Has to be done before SLB initialization as this is 11028c2ecf20Sopenharmony_ci * currently where the page size encoding is obtained. 11038c2ecf20Sopenharmony_ci */ 11048c2ecf20Sopenharmony_ci htab_initialize(); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci init_mm.context.hash_context = &init_hash_mm_context; 11078c2ecf20Sopenharmony_ci mm_ctx_set_slb_addr_limit(&init_mm.context, SLB_ADDR_LIMIT_DEFAULT); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci pr_info("Initializing hash mmu with SLB\n"); 11108c2ecf20Sopenharmony_ci /* Initialize SLB management */ 11118c2ecf20Sopenharmony_ci slb_initialize(); 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_ARCH_206) 11148c2ecf20Sopenharmony_ci && cpu_has_feature(CPU_FTR_HVMODE)) 11158c2ecf20Sopenharmony_ci tlbiel_all(); 11168c2ecf20Sopenharmony_ci} 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP 11198c2ecf20Sopenharmony_civoid hash__early_init_mmu_secondary(void) 11208c2ecf20Sopenharmony_ci{ 11218c2ecf20Sopenharmony_ci /* Initialize hash table for that CPU */ 11228c2ecf20Sopenharmony_ci if (!firmware_has_feature(FW_FEATURE_LPAR)) { 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_ARCH_300)) 11258c2ecf20Sopenharmony_ci mtspr(SPRN_SDR1, _SDR1); 11268c2ecf20Sopenharmony_ci else 11278c2ecf20Sopenharmony_ci set_ptcr_when_no_uv(__pa(partition_tb) | 11288c2ecf20Sopenharmony_ci (PATB_SIZE_SHIFT - 12)); 11298c2ecf20Sopenharmony_ci } 11308c2ecf20Sopenharmony_ci /* Initialize SLB */ 11318c2ecf20Sopenharmony_ci slb_initialize(); 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_ARCH_206) 11348c2ecf20Sopenharmony_ci && cpu_has_feature(CPU_FTR_HVMODE)) 11358c2ecf20Sopenharmony_ci tlbiel_all(); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_MEM_KEYS 11388c2ecf20Sopenharmony_ci if (mmu_has_feature(MMU_FTR_PKEY)) 11398c2ecf20Sopenharmony_ci mtspr(SPRN_UAMOR, default_uamor); 11408c2ecf20Sopenharmony_ci#endif 11418c2ecf20Sopenharmony_ci} 11428c2ecf20Sopenharmony_ci#endif /* CONFIG_SMP */ 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci/* 11458c2ecf20Sopenharmony_ci * Called by asm hashtable.S for doing lazy icache flush 11468c2ecf20Sopenharmony_ci */ 11478c2ecf20Sopenharmony_ciunsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap) 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci struct page *page; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci if (!pfn_valid(pte_pfn(pte))) 11528c2ecf20Sopenharmony_ci return pp; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci page = pte_page(pte); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci /* page is dirty */ 11578c2ecf20Sopenharmony_ci if (!test_bit(PG_arch_1, &page->flags) && !PageReserved(page)) { 11588c2ecf20Sopenharmony_ci if (trap == 0x400) { 11598c2ecf20Sopenharmony_ci flush_dcache_icache_page(page); 11608c2ecf20Sopenharmony_ci set_bit(PG_arch_1, &page->flags); 11618c2ecf20Sopenharmony_ci } else 11628c2ecf20Sopenharmony_ci pp |= HPTE_R_N; 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci return pp; 11658c2ecf20Sopenharmony_ci} 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_MM_SLICES 11688c2ecf20Sopenharmony_cistatic unsigned int get_paca_psize(unsigned long addr) 11698c2ecf20Sopenharmony_ci{ 11708c2ecf20Sopenharmony_ci unsigned char *psizes; 11718c2ecf20Sopenharmony_ci unsigned long index, mask_index; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci if (addr < SLICE_LOW_TOP) { 11748c2ecf20Sopenharmony_ci psizes = get_paca()->mm_ctx_low_slices_psize; 11758c2ecf20Sopenharmony_ci index = GET_LOW_SLICE_INDEX(addr); 11768c2ecf20Sopenharmony_ci } else { 11778c2ecf20Sopenharmony_ci psizes = get_paca()->mm_ctx_high_slices_psize; 11788c2ecf20Sopenharmony_ci index = GET_HIGH_SLICE_INDEX(addr); 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci mask_index = index & 0x1; 11818c2ecf20Sopenharmony_ci return (psizes[index >> 1] >> (mask_index * 4)) & 0xF; 11828c2ecf20Sopenharmony_ci} 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci#else 11858c2ecf20Sopenharmony_ciunsigned int get_paca_psize(unsigned long addr) 11868c2ecf20Sopenharmony_ci{ 11878c2ecf20Sopenharmony_ci return get_paca()->mm_ctx_user_psize; 11888c2ecf20Sopenharmony_ci} 11898c2ecf20Sopenharmony_ci#endif 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci/* 11928c2ecf20Sopenharmony_ci * Demote a segment to using 4k pages. 11938c2ecf20Sopenharmony_ci * For now this makes the whole process use 4k pages. 11948c2ecf20Sopenharmony_ci */ 11958c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES 11968c2ecf20Sopenharmony_civoid demote_segment_4k(struct mm_struct *mm, unsigned long addr) 11978c2ecf20Sopenharmony_ci{ 11988c2ecf20Sopenharmony_ci if (get_slice_psize(mm, addr) == MMU_PAGE_4K) 11998c2ecf20Sopenharmony_ci return; 12008c2ecf20Sopenharmony_ci slice_set_range_psize(mm, addr, 1, MMU_PAGE_4K); 12018c2ecf20Sopenharmony_ci copro_flush_all_slbs(mm); 12028c2ecf20Sopenharmony_ci if ((get_paca_psize(addr) != MMU_PAGE_4K) && (current->mm == mm)) { 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci copy_mm_to_paca(mm); 12058c2ecf20Sopenharmony_ci slb_flush_and_restore_bolted(); 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci} 12088c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_64K_PAGES */ 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_SUBPAGE_PROT 12118c2ecf20Sopenharmony_ci/* 12128c2ecf20Sopenharmony_ci * This looks up a 2-bit protection code for a 4k subpage of a 64k page. 12138c2ecf20Sopenharmony_ci * Userspace sets the subpage permissions using the subpage_prot system call. 12148c2ecf20Sopenharmony_ci * 12158c2ecf20Sopenharmony_ci * Result is 0: full permissions, _PAGE_RW: read-only, 12168c2ecf20Sopenharmony_ci * _PAGE_RWX: no access. 12178c2ecf20Sopenharmony_ci */ 12188c2ecf20Sopenharmony_cistatic int subpage_protection(struct mm_struct *mm, unsigned long ea) 12198c2ecf20Sopenharmony_ci{ 12208c2ecf20Sopenharmony_ci struct subpage_prot_table *spt = mm_ctx_subpage_prot(&mm->context); 12218c2ecf20Sopenharmony_ci u32 spp = 0; 12228c2ecf20Sopenharmony_ci u32 **sbpm, *sbpp; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci if (!spt) 12258c2ecf20Sopenharmony_ci return 0; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci if (ea >= spt->maxaddr) 12288c2ecf20Sopenharmony_ci return 0; 12298c2ecf20Sopenharmony_ci if (ea < 0x100000000UL) { 12308c2ecf20Sopenharmony_ci /* addresses below 4GB use spt->low_prot */ 12318c2ecf20Sopenharmony_ci sbpm = spt->low_prot; 12328c2ecf20Sopenharmony_ci } else { 12338c2ecf20Sopenharmony_ci sbpm = spt->protptrs[ea >> SBP_L3_SHIFT]; 12348c2ecf20Sopenharmony_ci if (!sbpm) 12358c2ecf20Sopenharmony_ci return 0; 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci sbpp = sbpm[(ea >> SBP_L2_SHIFT) & (SBP_L2_COUNT - 1)]; 12388c2ecf20Sopenharmony_ci if (!sbpp) 12398c2ecf20Sopenharmony_ci return 0; 12408c2ecf20Sopenharmony_ci spp = sbpp[(ea >> PAGE_SHIFT) & (SBP_L1_COUNT - 1)]; 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci /* extract 2-bit bitfield for this 4k subpage */ 12438c2ecf20Sopenharmony_ci spp >>= 30 - 2 * ((ea >> 12) & 0xf); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci /* 12468c2ecf20Sopenharmony_ci * 0 -> full premission 12478c2ecf20Sopenharmony_ci * 1 -> Read only 12488c2ecf20Sopenharmony_ci * 2 -> no access. 12498c2ecf20Sopenharmony_ci * We return the flag that need to be cleared. 12508c2ecf20Sopenharmony_ci */ 12518c2ecf20Sopenharmony_ci spp = ((spp & 2) ? _PAGE_RWX : 0) | ((spp & 1) ? _PAGE_WRITE : 0); 12528c2ecf20Sopenharmony_ci return spp; 12538c2ecf20Sopenharmony_ci} 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci#else /* CONFIG_PPC_SUBPAGE_PROT */ 12568c2ecf20Sopenharmony_cistatic inline int subpage_protection(struct mm_struct *mm, unsigned long ea) 12578c2ecf20Sopenharmony_ci{ 12588c2ecf20Sopenharmony_ci return 0; 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci#endif 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_civoid hash_failure_debug(unsigned long ea, unsigned long access, 12638c2ecf20Sopenharmony_ci unsigned long vsid, unsigned long trap, 12648c2ecf20Sopenharmony_ci int ssize, int psize, int lpsize, unsigned long pte) 12658c2ecf20Sopenharmony_ci{ 12668c2ecf20Sopenharmony_ci if (!printk_ratelimit()) 12678c2ecf20Sopenharmony_ci return; 12688c2ecf20Sopenharmony_ci pr_info("mm: Hashing failure ! EA=0x%lx access=0x%lx current=%s\n", 12698c2ecf20Sopenharmony_ci ea, access, current->comm); 12708c2ecf20Sopenharmony_ci pr_info(" trap=0x%lx vsid=0x%lx ssize=%d base psize=%d psize %d pte=0x%lx\n", 12718c2ecf20Sopenharmony_ci trap, vsid, ssize, psize, lpsize, pte); 12728c2ecf20Sopenharmony_ci} 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_cistatic void check_paca_psize(unsigned long ea, struct mm_struct *mm, 12758c2ecf20Sopenharmony_ci int psize, bool user_region) 12768c2ecf20Sopenharmony_ci{ 12778c2ecf20Sopenharmony_ci if (user_region) { 12788c2ecf20Sopenharmony_ci if (psize != get_paca_psize(ea)) { 12798c2ecf20Sopenharmony_ci copy_mm_to_paca(mm); 12808c2ecf20Sopenharmony_ci slb_flush_and_restore_bolted(); 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci } else if (get_paca()->vmalloc_sllp != 12838c2ecf20Sopenharmony_ci mmu_psize_defs[mmu_vmalloc_psize].sllp) { 12848c2ecf20Sopenharmony_ci get_paca()->vmalloc_sllp = 12858c2ecf20Sopenharmony_ci mmu_psize_defs[mmu_vmalloc_psize].sllp; 12868c2ecf20Sopenharmony_ci slb_vmalloc_update(); 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci} 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci/* 12918c2ecf20Sopenharmony_ci * Result code is: 12928c2ecf20Sopenharmony_ci * 0 - handled 12938c2ecf20Sopenharmony_ci * 1 - normal page fault 12948c2ecf20Sopenharmony_ci * -1 - critical hash insertion error 12958c2ecf20Sopenharmony_ci * -2 - access not permitted by subpage protection mechanism 12968c2ecf20Sopenharmony_ci */ 12978c2ecf20Sopenharmony_ciint hash_page_mm(struct mm_struct *mm, unsigned long ea, 12988c2ecf20Sopenharmony_ci unsigned long access, unsigned long trap, 12998c2ecf20Sopenharmony_ci unsigned long flags) 13008c2ecf20Sopenharmony_ci{ 13018c2ecf20Sopenharmony_ci bool is_thp; 13028c2ecf20Sopenharmony_ci enum ctx_state prev_state = exception_enter(); 13038c2ecf20Sopenharmony_ci pgd_t *pgdir; 13048c2ecf20Sopenharmony_ci unsigned long vsid; 13058c2ecf20Sopenharmony_ci pte_t *ptep; 13068c2ecf20Sopenharmony_ci unsigned hugeshift; 13078c2ecf20Sopenharmony_ci int rc, user_region = 0; 13088c2ecf20Sopenharmony_ci int psize, ssize; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci DBG_LOW("hash_page(ea=%016lx, access=%lx, trap=%lx\n", 13118c2ecf20Sopenharmony_ci ea, access, trap); 13128c2ecf20Sopenharmony_ci trace_hash_fault(ea, access, trap); 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci /* Get region & vsid */ 13158c2ecf20Sopenharmony_ci switch (get_region_id(ea)) { 13168c2ecf20Sopenharmony_ci case USER_REGION_ID: 13178c2ecf20Sopenharmony_ci user_region = 1; 13188c2ecf20Sopenharmony_ci if (! mm) { 13198c2ecf20Sopenharmony_ci DBG_LOW(" user region with no mm !\n"); 13208c2ecf20Sopenharmony_ci rc = 1; 13218c2ecf20Sopenharmony_ci goto bail; 13228c2ecf20Sopenharmony_ci } 13238c2ecf20Sopenharmony_ci psize = get_slice_psize(mm, ea); 13248c2ecf20Sopenharmony_ci ssize = user_segment_size(ea); 13258c2ecf20Sopenharmony_ci vsid = get_user_vsid(&mm->context, ea, ssize); 13268c2ecf20Sopenharmony_ci break; 13278c2ecf20Sopenharmony_ci case VMALLOC_REGION_ID: 13288c2ecf20Sopenharmony_ci vsid = get_kernel_vsid(ea, mmu_kernel_ssize); 13298c2ecf20Sopenharmony_ci psize = mmu_vmalloc_psize; 13308c2ecf20Sopenharmony_ci ssize = mmu_kernel_ssize; 13318c2ecf20Sopenharmony_ci break; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci case IO_REGION_ID: 13348c2ecf20Sopenharmony_ci vsid = get_kernel_vsid(ea, mmu_kernel_ssize); 13358c2ecf20Sopenharmony_ci psize = mmu_io_psize; 13368c2ecf20Sopenharmony_ci ssize = mmu_kernel_ssize; 13378c2ecf20Sopenharmony_ci break; 13388c2ecf20Sopenharmony_ci default: 13398c2ecf20Sopenharmony_ci /* 13408c2ecf20Sopenharmony_ci * Not a valid range 13418c2ecf20Sopenharmony_ci * Send the problem up to do_page_fault() 13428c2ecf20Sopenharmony_ci */ 13438c2ecf20Sopenharmony_ci rc = 1; 13448c2ecf20Sopenharmony_ci goto bail; 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci DBG_LOW(" mm=%p, mm->pgdir=%p, vsid=%016lx\n", mm, mm->pgd, vsid); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci /* Bad address. */ 13498c2ecf20Sopenharmony_ci if (!vsid) { 13508c2ecf20Sopenharmony_ci DBG_LOW("Bad address!\n"); 13518c2ecf20Sopenharmony_ci rc = 1; 13528c2ecf20Sopenharmony_ci goto bail; 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci /* Get pgdir */ 13558c2ecf20Sopenharmony_ci pgdir = mm->pgd; 13568c2ecf20Sopenharmony_ci if (pgdir == NULL) { 13578c2ecf20Sopenharmony_ci rc = 1; 13588c2ecf20Sopenharmony_ci goto bail; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci /* Check CPU locality */ 13628c2ecf20Sopenharmony_ci if (user_region && mm_is_thread_local(mm)) 13638c2ecf20Sopenharmony_ci flags |= HPTE_LOCAL_UPDATE; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci#ifndef CONFIG_PPC_64K_PAGES 13668c2ecf20Sopenharmony_ci /* 13678c2ecf20Sopenharmony_ci * If we use 4K pages and our psize is not 4K, then we might 13688c2ecf20Sopenharmony_ci * be hitting a special driver mapping, and need to align the 13698c2ecf20Sopenharmony_ci * address before we fetch the PTE. 13708c2ecf20Sopenharmony_ci * 13718c2ecf20Sopenharmony_ci * It could also be a hugepage mapping, in which case this is 13728c2ecf20Sopenharmony_ci * not necessary, but it's not harmful, either. 13738c2ecf20Sopenharmony_ci */ 13748c2ecf20Sopenharmony_ci if (psize != MMU_PAGE_4K) 13758c2ecf20Sopenharmony_ci ea &= ~((1ul << mmu_psize_defs[psize].shift) - 1); 13768c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_64K_PAGES */ 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci /* Get PTE and page size from page tables */ 13798c2ecf20Sopenharmony_ci ptep = find_linux_pte(pgdir, ea, &is_thp, &hugeshift); 13808c2ecf20Sopenharmony_ci if (ptep == NULL || !pte_present(*ptep)) { 13818c2ecf20Sopenharmony_ci DBG_LOW(" no PTE !\n"); 13828c2ecf20Sopenharmony_ci rc = 1; 13838c2ecf20Sopenharmony_ci goto bail; 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci /* 13878c2ecf20Sopenharmony_ci * Add _PAGE_PRESENT to the required access perm. If there are parallel 13888c2ecf20Sopenharmony_ci * updates to the pte that can possibly clear _PAGE_PTE, catch that too. 13898c2ecf20Sopenharmony_ci * 13908c2ecf20Sopenharmony_ci * We can safely use the return pte address in rest of the function 13918c2ecf20Sopenharmony_ci * because we do set H_PAGE_BUSY which prevents further updates to pte 13928c2ecf20Sopenharmony_ci * from generic code. 13938c2ecf20Sopenharmony_ci */ 13948c2ecf20Sopenharmony_ci access |= _PAGE_PRESENT | _PAGE_PTE; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci /* 13978c2ecf20Sopenharmony_ci * Pre-check access permissions (will be re-checked atomically 13988c2ecf20Sopenharmony_ci * in __hash_page_XX but this pre-check is a fast path 13998c2ecf20Sopenharmony_ci */ 14008c2ecf20Sopenharmony_ci if (!check_pte_access(access, pte_val(*ptep))) { 14018c2ecf20Sopenharmony_ci DBG_LOW(" no access !\n"); 14028c2ecf20Sopenharmony_ci rc = 1; 14038c2ecf20Sopenharmony_ci goto bail; 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci if (hugeshift) { 14078c2ecf20Sopenharmony_ci if (is_thp) 14088c2ecf20Sopenharmony_ci rc = __hash_page_thp(ea, access, vsid, (pmd_t *)ptep, 14098c2ecf20Sopenharmony_ci trap, flags, ssize, psize); 14108c2ecf20Sopenharmony_ci#ifdef CONFIG_HUGETLB_PAGE 14118c2ecf20Sopenharmony_ci else 14128c2ecf20Sopenharmony_ci rc = __hash_page_huge(ea, access, vsid, ptep, trap, 14138c2ecf20Sopenharmony_ci flags, ssize, hugeshift, psize); 14148c2ecf20Sopenharmony_ci#else 14158c2ecf20Sopenharmony_ci else { 14168c2ecf20Sopenharmony_ci /* 14178c2ecf20Sopenharmony_ci * if we have hugeshift, and is not transhuge with 14188c2ecf20Sopenharmony_ci * hugetlb disabled, something is really wrong. 14198c2ecf20Sopenharmony_ci */ 14208c2ecf20Sopenharmony_ci rc = 1; 14218c2ecf20Sopenharmony_ci WARN_ON(1); 14228c2ecf20Sopenharmony_ci } 14238c2ecf20Sopenharmony_ci#endif 14248c2ecf20Sopenharmony_ci if (current->mm == mm) 14258c2ecf20Sopenharmony_ci check_paca_psize(ea, mm, psize, user_region); 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci goto bail; 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci#ifndef CONFIG_PPC_64K_PAGES 14318c2ecf20Sopenharmony_ci DBG_LOW(" i-pte: %016lx\n", pte_val(*ptep)); 14328c2ecf20Sopenharmony_ci#else 14338c2ecf20Sopenharmony_ci DBG_LOW(" i-pte: %016lx %016lx\n", pte_val(*ptep), 14348c2ecf20Sopenharmony_ci pte_val(*(ptep + PTRS_PER_PTE))); 14358c2ecf20Sopenharmony_ci#endif 14368c2ecf20Sopenharmony_ci /* Do actual hashing */ 14378c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES 14388c2ecf20Sopenharmony_ci /* If H_PAGE_4K_PFN is set, make sure this is a 4k segment */ 14398c2ecf20Sopenharmony_ci if ((pte_val(*ptep) & H_PAGE_4K_PFN) && psize == MMU_PAGE_64K) { 14408c2ecf20Sopenharmony_ci demote_segment_4k(mm, ea); 14418c2ecf20Sopenharmony_ci psize = MMU_PAGE_4K; 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci /* 14458c2ecf20Sopenharmony_ci * If this PTE is non-cacheable and we have restrictions on 14468c2ecf20Sopenharmony_ci * using non cacheable large pages, then we switch to 4k 14478c2ecf20Sopenharmony_ci */ 14488c2ecf20Sopenharmony_ci if (mmu_ci_restrictions && psize == MMU_PAGE_64K && pte_ci(*ptep)) { 14498c2ecf20Sopenharmony_ci if (user_region) { 14508c2ecf20Sopenharmony_ci demote_segment_4k(mm, ea); 14518c2ecf20Sopenharmony_ci psize = MMU_PAGE_4K; 14528c2ecf20Sopenharmony_ci } else if (ea < VMALLOC_END) { 14538c2ecf20Sopenharmony_ci /* 14548c2ecf20Sopenharmony_ci * some driver did a non-cacheable mapping 14558c2ecf20Sopenharmony_ci * in vmalloc space, so switch vmalloc 14568c2ecf20Sopenharmony_ci * to 4k pages 14578c2ecf20Sopenharmony_ci */ 14588c2ecf20Sopenharmony_ci printk(KERN_ALERT "Reducing vmalloc segment " 14598c2ecf20Sopenharmony_ci "to 4kB pages because of " 14608c2ecf20Sopenharmony_ci "non-cacheable mapping\n"); 14618c2ecf20Sopenharmony_ci psize = mmu_vmalloc_psize = MMU_PAGE_4K; 14628c2ecf20Sopenharmony_ci copro_flush_all_slbs(mm); 14638c2ecf20Sopenharmony_ci } 14648c2ecf20Sopenharmony_ci } 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_64K_PAGES */ 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci if (current->mm == mm) 14698c2ecf20Sopenharmony_ci check_paca_psize(ea, mm, psize, user_region); 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES 14728c2ecf20Sopenharmony_ci if (psize == MMU_PAGE_64K) 14738c2ecf20Sopenharmony_ci rc = __hash_page_64K(ea, access, vsid, ptep, trap, 14748c2ecf20Sopenharmony_ci flags, ssize); 14758c2ecf20Sopenharmony_ci else 14768c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_64K_PAGES */ 14778c2ecf20Sopenharmony_ci { 14788c2ecf20Sopenharmony_ci int spp = subpage_protection(mm, ea); 14798c2ecf20Sopenharmony_ci if (access & spp) 14808c2ecf20Sopenharmony_ci rc = -2; 14818c2ecf20Sopenharmony_ci else 14828c2ecf20Sopenharmony_ci rc = __hash_page_4K(ea, access, vsid, ptep, trap, 14838c2ecf20Sopenharmony_ci flags, ssize, spp); 14848c2ecf20Sopenharmony_ci } 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci /* 14878c2ecf20Sopenharmony_ci * Dump some info in case of hash insertion failure, they should 14888c2ecf20Sopenharmony_ci * never happen so it is really useful to know if/when they do 14898c2ecf20Sopenharmony_ci */ 14908c2ecf20Sopenharmony_ci if (rc == -1) 14918c2ecf20Sopenharmony_ci hash_failure_debug(ea, access, vsid, trap, ssize, psize, 14928c2ecf20Sopenharmony_ci psize, pte_val(*ptep)); 14938c2ecf20Sopenharmony_ci#ifndef CONFIG_PPC_64K_PAGES 14948c2ecf20Sopenharmony_ci DBG_LOW(" o-pte: %016lx\n", pte_val(*ptep)); 14958c2ecf20Sopenharmony_ci#else 14968c2ecf20Sopenharmony_ci DBG_LOW(" o-pte: %016lx %016lx\n", pte_val(*ptep), 14978c2ecf20Sopenharmony_ci pte_val(*(ptep + PTRS_PER_PTE))); 14988c2ecf20Sopenharmony_ci#endif 14998c2ecf20Sopenharmony_ci DBG_LOW(" -> rc=%d\n", rc); 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_cibail: 15028c2ecf20Sopenharmony_ci exception_exit(prev_state); 15038c2ecf20Sopenharmony_ci return rc; 15048c2ecf20Sopenharmony_ci} 15058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hash_page_mm); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ciint hash_page(unsigned long ea, unsigned long access, unsigned long trap, 15088c2ecf20Sopenharmony_ci unsigned long dsisr) 15098c2ecf20Sopenharmony_ci{ 15108c2ecf20Sopenharmony_ci unsigned long flags = 0; 15118c2ecf20Sopenharmony_ci struct mm_struct *mm = current->mm; 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci if ((get_region_id(ea) == VMALLOC_REGION_ID) || 15148c2ecf20Sopenharmony_ci (get_region_id(ea) == IO_REGION_ID)) 15158c2ecf20Sopenharmony_ci mm = &init_mm; 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci if (dsisr & DSISR_NOHPTE) 15188c2ecf20Sopenharmony_ci flags |= HPTE_NOHPTE_UPDATE; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci return hash_page_mm(mm, ea, access, trap, flags); 15218c2ecf20Sopenharmony_ci} 15228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hash_page); 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ciint __hash_page(unsigned long trap, unsigned long ea, unsigned long dsisr, 15258c2ecf20Sopenharmony_ci unsigned long msr) 15268c2ecf20Sopenharmony_ci{ 15278c2ecf20Sopenharmony_ci unsigned long access = _PAGE_PRESENT | _PAGE_READ; 15288c2ecf20Sopenharmony_ci unsigned long flags = 0; 15298c2ecf20Sopenharmony_ci struct mm_struct *mm = current->mm; 15308c2ecf20Sopenharmony_ci unsigned int region_id = get_region_id(ea); 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci if ((region_id == VMALLOC_REGION_ID) || (region_id == IO_REGION_ID)) 15338c2ecf20Sopenharmony_ci mm = &init_mm; 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci if (dsisr & DSISR_NOHPTE) 15368c2ecf20Sopenharmony_ci flags |= HPTE_NOHPTE_UPDATE; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci if (dsisr & DSISR_ISSTORE) 15398c2ecf20Sopenharmony_ci access |= _PAGE_WRITE; 15408c2ecf20Sopenharmony_ci /* 15418c2ecf20Sopenharmony_ci * We set _PAGE_PRIVILEGED only when 15428c2ecf20Sopenharmony_ci * kernel mode access kernel space. 15438c2ecf20Sopenharmony_ci * 15448c2ecf20Sopenharmony_ci * _PAGE_PRIVILEGED is NOT set 15458c2ecf20Sopenharmony_ci * 1) when kernel mode access user space 15468c2ecf20Sopenharmony_ci * 2) user space access kernel space. 15478c2ecf20Sopenharmony_ci */ 15488c2ecf20Sopenharmony_ci access |= _PAGE_PRIVILEGED; 15498c2ecf20Sopenharmony_ci if ((msr & MSR_PR) || (region_id == USER_REGION_ID)) 15508c2ecf20Sopenharmony_ci access &= ~_PAGE_PRIVILEGED; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci if (trap == 0x400) 15538c2ecf20Sopenharmony_ci access |= _PAGE_EXEC; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci return hash_page_mm(mm, ea, access, trap, flags); 15568c2ecf20Sopenharmony_ci} 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_MM_SLICES 15598c2ecf20Sopenharmony_cistatic bool should_hash_preload(struct mm_struct *mm, unsigned long ea) 15608c2ecf20Sopenharmony_ci{ 15618c2ecf20Sopenharmony_ci int psize = get_slice_psize(mm, ea); 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci /* We only prefault standard pages for now */ 15648c2ecf20Sopenharmony_ci if (unlikely(psize != mm_ctx_user_psize(&mm->context))) 15658c2ecf20Sopenharmony_ci return false; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci /* 15688c2ecf20Sopenharmony_ci * Don't prefault if subpage protection is enabled for the EA. 15698c2ecf20Sopenharmony_ci */ 15708c2ecf20Sopenharmony_ci if (unlikely((psize == MMU_PAGE_4K) && subpage_protection(mm, ea))) 15718c2ecf20Sopenharmony_ci return false; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci return true; 15748c2ecf20Sopenharmony_ci} 15758c2ecf20Sopenharmony_ci#else 15768c2ecf20Sopenharmony_cistatic bool should_hash_preload(struct mm_struct *mm, unsigned long ea) 15778c2ecf20Sopenharmony_ci{ 15788c2ecf20Sopenharmony_ci return true; 15798c2ecf20Sopenharmony_ci} 15808c2ecf20Sopenharmony_ci#endif 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_cistatic void hash_preload(struct mm_struct *mm, pte_t *ptep, unsigned long ea, 15838c2ecf20Sopenharmony_ci bool is_exec, unsigned long trap) 15848c2ecf20Sopenharmony_ci{ 15858c2ecf20Sopenharmony_ci unsigned long vsid; 15868c2ecf20Sopenharmony_ci pgd_t *pgdir; 15878c2ecf20Sopenharmony_ci int rc, ssize, update_flags = 0; 15888c2ecf20Sopenharmony_ci unsigned long access = _PAGE_PRESENT | _PAGE_READ | (is_exec ? _PAGE_EXEC : 0); 15898c2ecf20Sopenharmony_ci unsigned long flags; 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci BUG_ON(get_region_id(ea) != USER_REGION_ID); 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (!should_hash_preload(mm, ea)) 15948c2ecf20Sopenharmony_ci return; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci DBG_LOW("hash_preload(mm=%p, mm->pgdir=%p, ea=%016lx, access=%lx," 15978c2ecf20Sopenharmony_ci " trap=%lx\n", mm, mm->pgd, ea, access, trap); 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci /* Get Linux PTE if available */ 16008c2ecf20Sopenharmony_ci pgdir = mm->pgd; 16018c2ecf20Sopenharmony_ci if (pgdir == NULL) 16028c2ecf20Sopenharmony_ci return; 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci /* Get VSID */ 16058c2ecf20Sopenharmony_ci ssize = user_segment_size(ea); 16068c2ecf20Sopenharmony_ci vsid = get_user_vsid(&mm->context, ea, ssize); 16078c2ecf20Sopenharmony_ci if (!vsid) 16088c2ecf20Sopenharmony_ci return; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES 16118c2ecf20Sopenharmony_ci /* If either H_PAGE_4K_PFN or cache inhibited is set (and we are on 16128c2ecf20Sopenharmony_ci * a 64K kernel), then we don't preload, hash_page() will take 16138c2ecf20Sopenharmony_ci * care of it once we actually try to access the page. 16148c2ecf20Sopenharmony_ci * That way we don't have to duplicate all of the logic for segment 16158c2ecf20Sopenharmony_ci * page size demotion here 16168c2ecf20Sopenharmony_ci * Called with PTL held, hence can be sure the value won't change in 16178c2ecf20Sopenharmony_ci * between. 16188c2ecf20Sopenharmony_ci */ 16198c2ecf20Sopenharmony_ci if ((pte_val(*ptep) & H_PAGE_4K_PFN) || pte_ci(*ptep)) 16208c2ecf20Sopenharmony_ci return; 16218c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_64K_PAGES */ 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci /* 16248c2ecf20Sopenharmony_ci * __hash_page_* must run with interrupts off, as it sets the 16258c2ecf20Sopenharmony_ci * H_PAGE_BUSY bit. It's possible for perf interrupts to hit at any 16268c2ecf20Sopenharmony_ci * time and may take a hash fault reading the user stack, see 16278c2ecf20Sopenharmony_ci * read_user_stack_slow() in the powerpc/perf code. 16288c2ecf20Sopenharmony_ci * 16298c2ecf20Sopenharmony_ci * If that takes a hash fault on the same page as we lock here, it 16308c2ecf20Sopenharmony_ci * will bail out when seeing H_PAGE_BUSY set, and retry the access 16318c2ecf20Sopenharmony_ci * leading to an infinite loop. 16328c2ecf20Sopenharmony_ci * 16338c2ecf20Sopenharmony_ci * Disabling interrupts here does not prevent perf interrupts, but it 16348c2ecf20Sopenharmony_ci * will prevent them taking hash faults (see the NMI test in 16358c2ecf20Sopenharmony_ci * do_hash_page), then read_user_stack's copy_from_user_nofault will 16368c2ecf20Sopenharmony_ci * fail and perf will fall back to read_user_stack_slow(), which 16378c2ecf20Sopenharmony_ci * walks the Linux page tables. 16388c2ecf20Sopenharmony_ci * 16398c2ecf20Sopenharmony_ci * Interrupts must also be off for the duration of the 16408c2ecf20Sopenharmony_ci * mm_is_thread_local test and update, to prevent preempt running the 16418c2ecf20Sopenharmony_ci * mm on another CPU (XXX: this may be racy vs kthread_use_mm). 16428c2ecf20Sopenharmony_ci */ 16438c2ecf20Sopenharmony_ci local_irq_save(flags); 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci /* Is that local to this CPU ? */ 16468c2ecf20Sopenharmony_ci if (mm_is_thread_local(mm)) 16478c2ecf20Sopenharmony_ci update_flags |= HPTE_LOCAL_UPDATE; 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci /* Hash it in */ 16508c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES 16518c2ecf20Sopenharmony_ci if (mm_ctx_user_psize(&mm->context) == MMU_PAGE_64K) 16528c2ecf20Sopenharmony_ci rc = __hash_page_64K(ea, access, vsid, ptep, trap, 16538c2ecf20Sopenharmony_ci update_flags, ssize); 16548c2ecf20Sopenharmony_ci else 16558c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_64K_PAGES */ 16568c2ecf20Sopenharmony_ci rc = __hash_page_4K(ea, access, vsid, ptep, trap, update_flags, 16578c2ecf20Sopenharmony_ci ssize, subpage_protection(mm, ea)); 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci /* Dump some info in case of hash insertion failure, they should 16608c2ecf20Sopenharmony_ci * never happen so it is really useful to know if/when they do 16618c2ecf20Sopenharmony_ci */ 16628c2ecf20Sopenharmony_ci if (rc == -1) 16638c2ecf20Sopenharmony_ci hash_failure_debug(ea, access, vsid, trap, ssize, 16648c2ecf20Sopenharmony_ci mm_ctx_user_psize(&mm->context), 16658c2ecf20Sopenharmony_ci mm_ctx_user_psize(&mm->context), 16668c2ecf20Sopenharmony_ci pte_val(*ptep)); 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci local_irq_restore(flags); 16698c2ecf20Sopenharmony_ci} 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci/* 16728c2ecf20Sopenharmony_ci * This is called at the end of handling a user page fault, when the 16738c2ecf20Sopenharmony_ci * fault has been handled by updating a PTE in the linux page tables. 16748c2ecf20Sopenharmony_ci * We use it to preload an HPTE into the hash table corresponding to 16758c2ecf20Sopenharmony_ci * the updated linux PTE. 16768c2ecf20Sopenharmony_ci * 16778c2ecf20Sopenharmony_ci * This must always be called with the pte lock held. 16788c2ecf20Sopenharmony_ci */ 16798c2ecf20Sopenharmony_civoid update_mmu_cache(struct vm_area_struct *vma, unsigned long address, 16808c2ecf20Sopenharmony_ci pte_t *ptep) 16818c2ecf20Sopenharmony_ci{ 16828c2ecf20Sopenharmony_ci /* 16838c2ecf20Sopenharmony_ci * We don't need to worry about _PAGE_PRESENT here because we are 16848c2ecf20Sopenharmony_ci * called with either mm->page_table_lock held or ptl lock held 16858c2ecf20Sopenharmony_ci */ 16868c2ecf20Sopenharmony_ci unsigned long trap; 16878c2ecf20Sopenharmony_ci bool is_exec; 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci if (radix_enabled()) 16908c2ecf20Sopenharmony_ci return; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci /* We only want HPTEs for linux PTEs that have _PAGE_ACCESSED set */ 16938c2ecf20Sopenharmony_ci if (!pte_young(*ptep) || address >= TASK_SIZE) 16948c2ecf20Sopenharmony_ci return; 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci /* 16978c2ecf20Sopenharmony_ci * We try to figure out if we are coming from an instruction 16988c2ecf20Sopenharmony_ci * access fault and pass that down to __hash_page so we avoid 16998c2ecf20Sopenharmony_ci * double-faulting on execution of fresh text. We have to test 17008c2ecf20Sopenharmony_ci * for regs NULL since init will get here first thing at boot. 17018c2ecf20Sopenharmony_ci * 17028c2ecf20Sopenharmony_ci * We also avoid filling the hash if not coming from a fault. 17038c2ecf20Sopenharmony_ci */ 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci trap = current->thread.regs ? TRAP(current->thread.regs) : 0UL; 17068c2ecf20Sopenharmony_ci switch (trap) { 17078c2ecf20Sopenharmony_ci case 0x300: 17088c2ecf20Sopenharmony_ci is_exec = false; 17098c2ecf20Sopenharmony_ci break; 17108c2ecf20Sopenharmony_ci case 0x400: 17118c2ecf20Sopenharmony_ci is_exec = true; 17128c2ecf20Sopenharmony_ci break; 17138c2ecf20Sopenharmony_ci default: 17148c2ecf20Sopenharmony_ci return; 17158c2ecf20Sopenharmony_ci } 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci hash_preload(vma->vm_mm, ptep, address, is_exec, trap); 17188c2ecf20Sopenharmony_ci} 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_TRANSACTIONAL_MEM 17218c2ecf20Sopenharmony_cistatic inline void tm_flush_hash_page(int local) 17228c2ecf20Sopenharmony_ci{ 17238c2ecf20Sopenharmony_ci /* 17248c2ecf20Sopenharmony_ci * Transactions are not aborted by tlbiel, only tlbie. Without, syncing a 17258c2ecf20Sopenharmony_ci * page back to a block device w/PIO could pick up transactional data 17268c2ecf20Sopenharmony_ci * (bad!) so we force an abort here. Before the sync the page will be 17278c2ecf20Sopenharmony_ci * made read-only, which will flush_hash_page. BIG ISSUE here: if the 17288c2ecf20Sopenharmony_ci * kernel uses a page from userspace without unmapping it first, it may 17298c2ecf20Sopenharmony_ci * see the speculated version. 17308c2ecf20Sopenharmony_ci */ 17318c2ecf20Sopenharmony_ci if (local && cpu_has_feature(CPU_FTR_TM) && current->thread.regs && 17328c2ecf20Sopenharmony_ci MSR_TM_ACTIVE(current->thread.regs->msr)) { 17338c2ecf20Sopenharmony_ci tm_enable(); 17348c2ecf20Sopenharmony_ci tm_abort(TM_CAUSE_TLBI); 17358c2ecf20Sopenharmony_ci } 17368c2ecf20Sopenharmony_ci} 17378c2ecf20Sopenharmony_ci#else 17388c2ecf20Sopenharmony_cistatic inline void tm_flush_hash_page(int local) 17398c2ecf20Sopenharmony_ci{ 17408c2ecf20Sopenharmony_ci} 17418c2ecf20Sopenharmony_ci#endif 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci/* 17448c2ecf20Sopenharmony_ci * Return the global hash slot, corresponding to the given PTE, which contains 17458c2ecf20Sopenharmony_ci * the HPTE. 17468c2ecf20Sopenharmony_ci */ 17478c2ecf20Sopenharmony_ciunsigned long pte_get_hash_gslot(unsigned long vpn, unsigned long shift, 17488c2ecf20Sopenharmony_ci int ssize, real_pte_t rpte, unsigned int subpg_index) 17498c2ecf20Sopenharmony_ci{ 17508c2ecf20Sopenharmony_ci unsigned long hash, gslot, hidx; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci hash = hpt_hash(vpn, shift, ssize); 17538c2ecf20Sopenharmony_ci hidx = __rpte_to_hidx(rpte, subpg_index); 17548c2ecf20Sopenharmony_ci if (hidx & _PTEIDX_SECONDARY) 17558c2ecf20Sopenharmony_ci hash = ~hash; 17568c2ecf20Sopenharmony_ci gslot = (hash & htab_hash_mask) * HPTES_PER_GROUP; 17578c2ecf20Sopenharmony_ci gslot += hidx & _PTEIDX_GROUP_IX; 17588c2ecf20Sopenharmony_ci return gslot; 17598c2ecf20Sopenharmony_ci} 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_civoid flush_hash_page(unsigned long vpn, real_pte_t pte, int psize, int ssize, 17628c2ecf20Sopenharmony_ci unsigned long flags) 17638c2ecf20Sopenharmony_ci{ 17648c2ecf20Sopenharmony_ci unsigned long index, shift, gslot; 17658c2ecf20Sopenharmony_ci int local = flags & HPTE_LOCAL_UPDATE; 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci DBG_LOW("flush_hash_page(vpn=%016lx)\n", vpn); 17688c2ecf20Sopenharmony_ci pte_iterate_hashed_subpages(pte, psize, vpn, index, shift) { 17698c2ecf20Sopenharmony_ci gslot = pte_get_hash_gslot(vpn, shift, ssize, pte, index); 17708c2ecf20Sopenharmony_ci DBG_LOW(" sub %ld: gslot=%lx\n", index, gslot); 17718c2ecf20Sopenharmony_ci /* 17728c2ecf20Sopenharmony_ci * We use same base page size and actual psize, because we don't 17738c2ecf20Sopenharmony_ci * use these functions for hugepage 17748c2ecf20Sopenharmony_ci */ 17758c2ecf20Sopenharmony_ci mmu_hash_ops.hpte_invalidate(gslot, vpn, psize, psize, 17768c2ecf20Sopenharmony_ci ssize, local); 17778c2ecf20Sopenharmony_ci } pte_iterate_hashed_end(); 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci tm_flush_hash_page(local); 17808c2ecf20Sopenharmony_ci} 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 17838c2ecf20Sopenharmony_civoid flush_hash_hugepage(unsigned long vsid, unsigned long addr, 17848c2ecf20Sopenharmony_ci pmd_t *pmdp, unsigned int psize, int ssize, 17858c2ecf20Sopenharmony_ci unsigned long flags) 17868c2ecf20Sopenharmony_ci{ 17878c2ecf20Sopenharmony_ci int i, max_hpte_count, valid; 17888c2ecf20Sopenharmony_ci unsigned long s_addr; 17898c2ecf20Sopenharmony_ci unsigned char *hpte_slot_array; 17908c2ecf20Sopenharmony_ci unsigned long hidx, shift, vpn, hash, slot; 17918c2ecf20Sopenharmony_ci int local = flags & HPTE_LOCAL_UPDATE; 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci s_addr = addr & HPAGE_PMD_MASK; 17948c2ecf20Sopenharmony_ci hpte_slot_array = get_hpte_slot_array(pmdp); 17958c2ecf20Sopenharmony_ci /* 17968c2ecf20Sopenharmony_ci * IF we try to do a HUGE PTE update after a withdraw is done. 17978c2ecf20Sopenharmony_ci * we will find the below NULL. This happens when we do 17988c2ecf20Sopenharmony_ci * split_huge_pmd 17998c2ecf20Sopenharmony_ci */ 18008c2ecf20Sopenharmony_ci if (!hpte_slot_array) 18018c2ecf20Sopenharmony_ci return; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci if (mmu_hash_ops.hugepage_invalidate) { 18048c2ecf20Sopenharmony_ci mmu_hash_ops.hugepage_invalidate(vsid, s_addr, hpte_slot_array, 18058c2ecf20Sopenharmony_ci psize, ssize, local); 18068c2ecf20Sopenharmony_ci goto tm_abort; 18078c2ecf20Sopenharmony_ci } 18088c2ecf20Sopenharmony_ci /* 18098c2ecf20Sopenharmony_ci * No bluk hpte removal support, invalidate each entry 18108c2ecf20Sopenharmony_ci */ 18118c2ecf20Sopenharmony_ci shift = mmu_psize_defs[psize].shift; 18128c2ecf20Sopenharmony_ci max_hpte_count = HPAGE_PMD_SIZE >> shift; 18138c2ecf20Sopenharmony_ci for (i = 0; i < max_hpte_count; i++) { 18148c2ecf20Sopenharmony_ci /* 18158c2ecf20Sopenharmony_ci * 8 bits per each hpte entries 18168c2ecf20Sopenharmony_ci * 000| [ secondary group (one bit) | hidx (3 bits) | valid bit] 18178c2ecf20Sopenharmony_ci */ 18188c2ecf20Sopenharmony_ci valid = hpte_valid(hpte_slot_array, i); 18198c2ecf20Sopenharmony_ci if (!valid) 18208c2ecf20Sopenharmony_ci continue; 18218c2ecf20Sopenharmony_ci hidx = hpte_hash_index(hpte_slot_array, i); 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci /* get the vpn */ 18248c2ecf20Sopenharmony_ci addr = s_addr + (i * (1ul << shift)); 18258c2ecf20Sopenharmony_ci vpn = hpt_vpn(addr, vsid, ssize); 18268c2ecf20Sopenharmony_ci hash = hpt_hash(vpn, shift, ssize); 18278c2ecf20Sopenharmony_ci if (hidx & _PTEIDX_SECONDARY) 18288c2ecf20Sopenharmony_ci hash = ~hash; 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; 18318c2ecf20Sopenharmony_ci slot += hidx & _PTEIDX_GROUP_IX; 18328c2ecf20Sopenharmony_ci mmu_hash_ops.hpte_invalidate(slot, vpn, psize, 18338c2ecf20Sopenharmony_ci MMU_PAGE_16M, ssize, local); 18348c2ecf20Sopenharmony_ci } 18358c2ecf20Sopenharmony_citm_abort: 18368c2ecf20Sopenharmony_ci tm_flush_hash_page(local); 18378c2ecf20Sopenharmony_ci} 18388c2ecf20Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_civoid flush_hash_range(unsigned long number, int local) 18418c2ecf20Sopenharmony_ci{ 18428c2ecf20Sopenharmony_ci if (mmu_hash_ops.flush_hash_range) 18438c2ecf20Sopenharmony_ci mmu_hash_ops.flush_hash_range(number, local); 18448c2ecf20Sopenharmony_ci else { 18458c2ecf20Sopenharmony_ci int i; 18468c2ecf20Sopenharmony_ci struct ppc64_tlb_batch *batch = 18478c2ecf20Sopenharmony_ci this_cpu_ptr(&ppc64_tlb_batch); 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci for (i = 0; i < number; i++) 18508c2ecf20Sopenharmony_ci flush_hash_page(batch->vpn[i], batch->pte[i], 18518c2ecf20Sopenharmony_ci batch->psize, batch->ssize, local); 18528c2ecf20Sopenharmony_ci } 18538c2ecf20Sopenharmony_ci} 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci/* 18568c2ecf20Sopenharmony_ci * low_hash_fault is called when we the low level hash code failed 18578c2ecf20Sopenharmony_ci * to instert a PTE due to an hypervisor error 18588c2ecf20Sopenharmony_ci */ 18598c2ecf20Sopenharmony_civoid low_hash_fault(struct pt_regs *regs, unsigned long address, int rc) 18608c2ecf20Sopenharmony_ci{ 18618c2ecf20Sopenharmony_ci enum ctx_state prev_state = exception_enter(); 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci if (user_mode(regs)) { 18648c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_SUBPAGE_PROT 18658c2ecf20Sopenharmony_ci if (rc == -2) 18668c2ecf20Sopenharmony_ci _exception(SIGSEGV, regs, SEGV_ACCERR, address); 18678c2ecf20Sopenharmony_ci else 18688c2ecf20Sopenharmony_ci#endif 18698c2ecf20Sopenharmony_ci _exception(SIGBUS, regs, BUS_ADRERR, address); 18708c2ecf20Sopenharmony_ci } else 18718c2ecf20Sopenharmony_ci bad_page_fault(regs, address, SIGBUS); 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci exception_exit(prev_state); 18748c2ecf20Sopenharmony_ci} 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_cilong hpte_insert_repeating(unsigned long hash, unsigned long vpn, 18778c2ecf20Sopenharmony_ci unsigned long pa, unsigned long rflags, 18788c2ecf20Sopenharmony_ci unsigned long vflags, int psize, int ssize) 18798c2ecf20Sopenharmony_ci{ 18808c2ecf20Sopenharmony_ci unsigned long hpte_group; 18818c2ecf20Sopenharmony_ci long slot; 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_cirepeat: 18848c2ecf20Sopenharmony_ci hpte_group = (hash & htab_hash_mask) * HPTES_PER_GROUP; 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci /* Insert into the hash table, primary slot */ 18878c2ecf20Sopenharmony_ci slot = mmu_hash_ops.hpte_insert(hpte_group, vpn, pa, rflags, vflags, 18888c2ecf20Sopenharmony_ci psize, psize, ssize); 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci /* Primary is full, try the secondary */ 18918c2ecf20Sopenharmony_ci if (unlikely(slot == -1)) { 18928c2ecf20Sopenharmony_ci hpte_group = (~hash & htab_hash_mask) * HPTES_PER_GROUP; 18938c2ecf20Sopenharmony_ci slot = mmu_hash_ops.hpte_insert(hpte_group, vpn, pa, rflags, 18948c2ecf20Sopenharmony_ci vflags | HPTE_V_SECONDARY, 18958c2ecf20Sopenharmony_ci psize, psize, ssize); 18968c2ecf20Sopenharmony_ci if (slot == -1) { 18978c2ecf20Sopenharmony_ci if (mftb() & 0x1) 18988c2ecf20Sopenharmony_ci hpte_group = (hash & htab_hash_mask) * 18998c2ecf20Sopenharmony_ci HPTES_PER_GROUP; 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci mmu_hash_ops.hpte_remove(hpte_group); 19028c2ecf20Sopenharmony_ci goto repeat; 19038c2ecf20Sopenharmony_ci } 19048c2ecf20Sopenharmony_ci } 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci return slot; 19078c2ecf20Sopenharmony_ci} 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_PAGEALLOC 19108c2ecf20Sopenharmony_cistatic void kernel_map_linear_page(unsigned long vaddr, unsigned long lmi) 19118c2ecf20Sopenharmony_ci{ 19128c2ecf20Sopenharmony_ci unsigned long hash; 19138c2ecf20Sopenharmony_ci unsigned long vsid = get_kernel_vsid(vaddr, mmu_kernel_ssize); 19148c2ecf20Sopenharmony_ci unsigned long vpn = hpt_vpn(vaddr, vsid, mmu_kernel_ssize); 19158c2ecf20Sopenharmony_ci unsigned long mode = htab_convert_pte_flags(pgprot_val(PAGE_KERNEL)); 19168c2ecf20Sopenharmony_ci long ret; 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_ci hash = hpt_hash(vpn, PAGE_SHIFT, mmu_kernel_ssize); 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci /* Don't create HPTE entries for bad address */ 19218c2ecf20Sopenharmony_ci if (!vsid) 19228c2ecf20Sopenharmony_ci return; 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci ret = hpte_insert_repeating(hash, vpn, __pa(vaddr), mode, 19258c2ecf20Sopenharmony_ci HPTE_V_BOLTED, 19268c2ecf20Sopenharmony_ci mmu_linear_psize, mmu_kernel_ssize); 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci BUG_ON (ret < 0); 19298c2ecf20Sopenharmony_ci spin_lock(&linear_map_hash_lock); 19308c2ecf20Sopenharmony_ci BUG_ON(linear_map_hash_slots[lmi] & 0x80); 19318c2ecf20Sopenharmony_ci linear_map_hash_slots[lmi] = ret | 0x80; 19328c2ecf20Sopenharmony_ci spin_unlock(&linear_map_hash_lock); 19338c2ecf20Sopenharmony_ci} 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_cistatic void kernel_unmap_linear_page(unsigned long vaddr, unsigned long lmi) 19368c2ecf20Sopenharmony_ci{ 19378c2ecf20Sopenharmony_ci unsigned long hash, hidx, slot; 19388c2ecf20Sopenharmony_ci unsigned long vsid = get_kernel_vsid(vaddr, mmu_kernel_ssize); 19398c2ecf20Sopenharmony_ci unsigned long vpn = hpt_vpn(vaddr, vsid, mmu_kernel_ssize); 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci hash = hpt_hash(vpn, PAGE_SHIFT, mmu_kernel_ssize); 19428c2ecf20Sopenharmony_ci spin_lock(&linear_map_hash_lock); 19438c2ecf20Sopenharmony_ci BUG_ON(!(linear_map_hash_slots[lmi] & 0x80)); 19448c2ecf20Sopenharmony_ci hidx = linear_map_hash_slots[lmi] & 0x7f; 19458c2ecf20Sopenharmony_ci linear_map_hash_slots[lmi] = 0; 19468c2ecf20Sopenharmony_ci spin_unlock(&linear_map_hash_lock); 19478c2ecf20Sopenharmony_ci if (hidx & _PTEIDX_SECONDARY) 19488c2ecf20Sopenharmony_ci hash = ~hash; 19498c2ecf20Sopenharmony_ci slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; 19508c2ecf20Sopenharmony_ci slot += hidx & _PTEIDX_GROUP_IX; 19518c2ecf20Sopenharmony_ci mmu_hash_ops.hpte_invalidate(slot, vpn, mmu_linear_psize, 19528c2ecf20Sopenharmony_ci mmu_linear_psize, 19538c2ecf20Sopenharmony_ci mmu_kernel_ssize, 0); 19548c2ecf20Sopenharmony_ci} 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_civoid __kernel_map_pages(struct page *page, int numpages, int enable) 19578c2ecf20Sopenharmony_ci{ 19588c2ecf20Sopenharmony_ci unsigned long flags, vaddr, lmi; 19598c2ecf20Sopenharmony_ci int i; 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci local_irq_save(flags); 19628c2ecf20Sopenharmony_ci for (i = 0; i < numpages; i++, page++) { 19638c2ecf20Sopenharmony_ci vaddr = (unsigned long)page_address(page); 19648c2ecf20Sopenharmony_ci lmi = __pa(vaddr) >> PAGE_SHIFT; 19658c2ecf20Sopenharmony_ci if (lmi >= linear_map_hash_count) 19668c2ecf20Sopenharmony_ci continue; 19678c2ecf20Sopenharmony_ci if (enable) 19688c2ecf20Sopenharmony_ci kernel_map_linear_page(vaddr, lmi); 19698c2ecf20Sopenharmony_ci else 19708c2ecf20Sopenharmony_ci kernel_unmap_linear_page(vaddr, lmi); 19718c2ecf20Sopenharmony_ci } 19728c2ecf20Sopenharmony_ci local_irq_restore(flags); 19738c2ecf20Sopenharmony_ci} 19748c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_PAGEALLOC */ 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_civoid hash__setup_initial_memory_limit(phys_addr_t first_memblock_base, 19778c2ecf20Sopenharmony_ci phys_addr_t first_memblock_size) 19788c2ecf20Sopenharmony_ci{ 19798c2ecf20Sopenharmony_ci /* 19808c2ecf20Sopenharmony_ci * We don't currently support the first MEMBLOCK not mapping 0 19818c2ecf20Sopenharmony_ci * physical on those processors 19828c2ecf20Sopenharmony_ci */ 19838c2ecf20Sopenharmony_ci BUG_ON(first_memblock_base != 0); 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci /* 19868c2ecf20Sopenharmony_ci * On virtualized systems the first entry is our RMA region aka VRMA, 19878c2ecf20Sopenharmony_ci * non-virtualized 64-bit hash MMU systems don't have a limitation 19888c2ecf20Sopenharmony_ci * on real mode access. 19898c2ecf20Sopenharmony_ci * 19908c2ecf20Sopenharmony_ci * For guests on platforms before POWER9, we clamp the it limit to 1G 19918c2ecf20Sopenharmony_ci * to avoid some funky things such as RTAS bugs etc... 19928c2ecf20Sopenharmony_ci * 19938c2ecf20Sopenharmony_ci * On POWER9 we limit to 1TB in case the host erroneously told us that 19948c2ecf20Sopenharmony_ci * the RMA was >1TB. Effective address bits 0:23 are treated as zero 19958c2ecf20Sopenharmony_ci * (meaning the access is aliased to zero i.e. addr = addr % 1TB) 19968c2ecf20Sopenharmony_ci * for virtual real mode addressing and so it doesn't make sense to 19978c2ecf20Sopenharmony_ci * have an area larger than 1TB as it can't be addressed. 19988c2ecf20Sopenharmony_ci */ 19998c2ecf20Sopenharmony_ci if (!early_cpu_has_feature(CPU_FTR_HVMODE)) { 20008c2ecf20Sopenharmony_ci ppc64_rma_size = first_memblock_size; 20018c2ecf20Sopenharmony_ci if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) 20028c2ecf20Sopenharmony_ci ppc64_rma_size = min_t(u64, ppc64_rma_size, 0x40000000); 20038c2ecf20Sopenharmony_ci else 20048c2ecf20Sopenharmony_ci ppc64_rma_size = min_t(u64, ppc64_rma_size, 20058c2ecf20Sopenharmony_ci 1UL << SID_SHIFT_1T); 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci /* Finally limit subsequent allocations */ 20088c2ecf20Sopenharmony_ci memblock_set_current_limit(ppc64_rma_size); 20098c2ecf20Sopenharmony_ci } else { 20108c2ecf20Sopenharmony_ci ppc64_rma_size = ULONG_MAX; 20118c2ecf20Sopenharmony_ci } 20128c2ecf20Sopenharmony_ci} 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_cistatic int hpt_order_get(void *data, u64 *val) 20178c2ecf20Sopenharmony_ci{ 20188c2ecf20Sopenharmony_ci *val = ppc64_pft_size; 20198c2ecf20Sopenharmony_ci return 0; 20208c2ecf20Sopenharmony_ci} 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_cistatic int hpt_order_set(void *data, u64 val) 20238c2ecf20Sopenharmony_ci{ 20248c2ecf20Sopenharmony_ci int ret; 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci if (!mmu_hash_ops.resize_hpt) 20278c2ecf20Sopenharmony_ci return -ENODEV; 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci cpus_read_lock(); 20308c2ecf20Sopenharmony_ci ret = mmu_hash_ops.resize_hpt(val); 20318c2ecf20Sopenharmony_ci cpus_read_unlock(); 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci return ret; 20348c2ecf20Sopenharmony_ci} 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_hpt_order, hpt_order_get, hpt_order_set, "%llu\n"); 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_cistatic int __init hash64_debugfs(void) 20398c2ecf20Sopenharmony_ci{ 20408c2ecf20Sopenharmony_ci debugfs_create_file("hpt_order", 0600, powerpc_debugfs_root, NULL, 20418c2ecf20Sopenharmony_ci &fops_hpt_order); 20428c2ecf20Sopenharmony_ci return 0; 20438c2ecf20Sopenharmony_ci} 20448c2ecf20Sopenharmony_cimachine_device_initcall(pseries, hash64_debugfs); 20458c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */ 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_civoid __init print_system_hash_info(void) 20488c2ecf20Sopenharmony_ci{ 20498c2ecf20Sopenharmony_ci pr_info("ppc64_pft_size = 0x%llx\n", ppc64_pft_size); 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci if (htab_hash_mask) 20528c2ecf20Sopenharmony_ci pr_info("htab_hash_mask = 0x%lx\n", htab_hash_mask); 20538c2ecf20Sopenharmony_ci} 2054