18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef _ASM_POWERPC_BOOK3S_64_MMU_H_ 38c2ecf20Sopenharmony_ci#define _ASM_POWERPC_BOOK3S_64_MMU_H_ 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <asm/page.h> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__ 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci * Page size definition 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * shift : is the "PAGE_SHIFT" value for that page size 128c2ecf20Sopenharmony_ci * sllp : is a bit mask with the value of SLB L || LP to be or'ed 138c2ecf20Sopenharmony_ci * directly to a slbmte "vsid" value 148c2ecf20Sopenharmony_ci * penc : is the HPTE encoding mask for the "LP" field: 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_cistruct mmu_psize_def { 188c2ecf20Sopenharmony_ci unsigned int shift; /* number of bits */ 198c2ecf20Sopenharmony_ci int penc[MMU_PAGE_COUNT]; /* HPTE encoding */ 208c2ecf20Sopenharmony_ci unsigned int tlbiel; /* tlbiel supported for that page size */ 218c2ecf20Sopenharmony_ci unsigned long avpnm; /* bits to mask out in AVPN in the HPTE */ 228c2ecf20Sopenharmony_ci union { 238c2ecf20Sopenharmony_ci unsigned long sllp; /* SLB L||LP (exact mask to use in slbmte) */ 248c2ecf20Sopenharmony_ci unsigned long ap; /* Ap encoding used by PowerISA 3.0 */ 258c2ecf20Sopenharmony_ci }; 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ciextern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT]; 288c2ecf20Sopenharmony_ci#endif /* __ASSEMBLY__ */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* 64-bit classic hash table MMU */ 318c2ecf20Sopenharmony_ci#include <asm/book3s/64/mmu-hash.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__ 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci * ISA 3.0 partition and process table entry format 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_cistruct prtb_entry { 388c2ecf20Sopenharmony_ci __be64 prtb0; 398c2ecf20Sopenharmony_ci __be64 prtb1; 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ciextern struct prtb_entry *process_tb; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct patb_entry { 448c2ecf20Sopenharmony_ci __be64 patb0; 458c2ecf20Sopenharmony_ci __be64 patb1; 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ciextern struct patb_entry *partition_tb; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* Bits in patb0 field */ 508c2ecf20Sopenharmony_ci#define PATB_HR (1UL << 63) 518c2ecf20Sopenharmony_ci#define RPDB_MASK 0x0fffffffffffff00UL 528c2ecf20Sopenharmony_ci#define RPDB_SHIFT (1UL << 8) 538c2ecf20Sopenharmony_ci#define RTS1_SHIFT 61 /* top 2 bits of radix tree size */ 548c2ecf20Sopenharmony_ci#define RTS1_MASK (3UL << RTS1_SHIFT) 558c2ecf20Sopenharmony_ci#define RTS2_SHIFT 5 /* bottom 3 bits of radix tree size */ 568c2ecf20Sopenharmony_ci#define RTS2_MASK (7UL << RTS2_SHIFT) 578c2ecf20Sopenharmony_ci#define RPDS_MASK 0x1f /* root page dir. size field */ 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* Bits in patb1 field */ 608c2ecf20Sopenharmony_ci#define PATB_GR (1UL << 63) /* guest uses radix; must match HR */ 618c2ecf20Sopenharmony_ci#define PRTS_MASK 0x1f /* process table size field */ 628c2ecf20Sopenharmony_ci#define PRTB_MASK 0x0ffffffffffff000UL 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* Number of supported PID bits */ 658c2ecf20Sopenharmony_ciextern unsigned int mmu_pid_bits; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* Base PID to allocate from */ 688c2ecf20Sopenharmony_ciextern unsigned int mmu_base_pid; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* 718c2ecf20Sopenharmony_ci * memory block size used with radix translation. 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_ciextern unsigned long __ro_after_init radix_mem_block_size; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#define PRTB_SIZE_SHIFT (mmu_pid_bits + 4) 768c2ecf20Sopenharmony_ci#define PRTB_ENTRIES (1ul << mmu_pid_bits) 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* 798c2ecf20Sopenharmony_ci * Power9 currently only support 64K partition table size. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ci#define PATB_SIZE_SHIFT 16 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_citypedef unsigned long mm_context_id_t; 848c2ecf20Sopenharmony_cistruct spinlock; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* Maximum possible number of NPUs in a system. */ 878c2ecf20Sopenharmony_ci#define NV_MAX_NPUS 8 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_citypedef struct { 908c2ecf20Sopenharmony_ci union { 918c2ecf20Sopenharmony_ci /* 928c2ecf20Sopenharmony_ci * We use id as the PIDR content for radix. On hash we can use 938c2ecf20Sopenharmony_ci * more than one id. The extended ids are used when we start 948c2ecf20Sopenharmony_ci * having address above 512TB. We allocate one extended id 958c2ecf20Sopenharmony_ci * for each 512TB. The new id is then used with the 49 bit 968c2ecf20Sopenharmony_ci * EA to build a new VA. We always use ESID_BITS_1T_MASK bits 978c2ecf20Sopenharmony_ci * from EA and new context ids to build the new VAs. 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ci mm_context_id_t id; 1008c2ecf20Sopenharmony_ci mm_context_id_t extended_id[TASK_SIZE_USER64/TASK_CONTEXT_SIZE]; 1018c2ecf20Sopenharmony_ci }; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci /* Number of bits in the mm_cpumask */ 1048c2ecf20Sopenharmony_ci atomic_t active_cpus; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* Number of users of the external (Nest) MMU */ 1078c2ecf20Sopenharmony_ci atomic_t copros; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* Number of user space windows opened in process mm_context */ 1108c2ecf20Sopenharmony_ci atomic_t vas_windows; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci struct hash_mm_context *hash_context; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci unsigned long vdso_base; 1158c2ecf20Sopenharmony_ci /* 1168c2ecf20Sopenharmony_ci * pagetable fragment support 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_ci void *pte_frag; 1198c2ecf20Sopenharmony_ci void *pmd_frag; 1208c2ecf20Sopenharmony_ci#ifdef CONFIG_SPAPR_TCE_IOMMU 1218c2ecf20Sopenharmony_ci struct list_head iommu_group_mem_list; 1228c2ecf20Sopenharmony_ci#endif 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_MEM_KEYS 1258c2ecf20Sopenharmony_ci /* 1268c2ecf20Sopenharmony_ci * Each bit represents one protection key. 1278c2ecf20Sopenharmony_ci * bit set -> key allocated 1288c2ecf20Sopenharmony_ci * bit unset -> key available for allocation 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ci u32 pkey_allocation_map; 1318c2ecf20Sopenharmony_ci s16 execute_only_pkey; /* key holding execute-only protection */ 1328c2ecf20Sopenharmony_ci#endif 1338c2ecf20Sopenharmony_ci} mm_context_t; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic inline u16 mm_ctx_user_psize(mm_context_t *ctx) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci return ctx->hash_context->user_psize; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic inline void mm_ctx_set_user_psize(mm_context_t *ctx, u16 user_psize) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci ctx->hash_context->user_psize = user_psize; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic inline unsigned char *mm_ctx_low_slices(mm_context_t *ctx) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci return ctx->hash_context->low_slices_psize; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic inline unsigned char *mm_ctx_high_slices(mm_context_t *ctx) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci return ctx->hash_context->high_slices_psize; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic inline unsigned long mm_ctx_slb_addr_limit(mm_context_t *ctx) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci return ctx->hash_context->slb_addr_limit; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic inline void mm_ctx_set_slb_addr_limit(mm_context_t *ctx, unsigned long limit) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci ctx->hash_context->slb_addr_limit = limit; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic inline struct slice_mask *slice_mask_for_size(mm_context_t *ctx, int psize) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES 1688c2ecf20Sopenharmony_ci if (psize == MMU_PAGE_64K) 1698c2ecf20Sopenharmony_ci return &ctx->hash_context->mask_64k; 1708c2ecf20Sopenharmony_ci#endif 1718c2ecf20Sopenharmony_ci#ifdef CONFIG_HUGETLB_PAGE 1728c2ecf20Sopenharmony_ci if (psize == MMU_PAGE_16M) 1738c2ecf20Sopenharmony_ci return &ctx->hash_context->mask_16m; 1748c2ecf20Sopenharmony_ci if (psize == MMU_PAGE_16G) 1758c2ecf20Sopenharmony_ci return &ctx->hash_context->mask_16g; 1768c2ecf20Sopenharmony_ci#endif 1778c2ecf20Sopenharmony_ci BUG_ON(psize != MMU_PAGE_4K); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci return &ctx->hash_context->mask_4k; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_SUBPAGE_PROT 1838c2ecf20Sopenharmony_cistatic inline struct subpage_prot_table *mm_ctx_subpage_prot(mm_context_t *ctx) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci return ctx->hash_context->spt; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci#endif 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci/* 1908c2ecf20Sopenharmony_ci * The current system page and segment sizes 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_ciextern int mmu_linear_psize; 1938c2ecf20Sopenharmony_ciextern int mmu_virtual_psize; 1948c2ecf20Sopenharmony_ciextern int mmu_vmalloc_psize; 1958c2ecf20Sopenharmony_ciextern int mmu_vmemmap_psize; 1968c2ecf20Sopenharmony_ciextern int mmu_io_psize; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/* MMU initialization */ 1998c2ecf20Sopenharmony_civoid mmu_early_init_devtree(void); 2008c2ecf20Sopenharmony_civoid hash__early_init_devtree(void); 2018c2ecf20Sopenharmony_civoid radix__early_init_devtree(void); 2028c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_MEM_KEYS 2038c2ecf20Sopenharmony_civoid pkey_early_init_devtree(void); 2048c2ecf20Sopenharmony_ci#else 2058c2ecf20Sopenharmony_cistatic inline void pkey_early_init_devtree(void) {} 2068c2ecf20Sopenharmony_ci#endif 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ciextern void hash__early_init_mmu(void); 2098c2ecf20Sopenharmony_ciextern void radix__early_init_mmu(void); 2108c2ecf20Sopenharmony_cistatic inline void __init early_init_mmu(void) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci if (radix_enabled()) 2138c2ecf20Sopenharmony_ci return radix__early_init_mmu(); 2148c2ecf20Sopenharmony_ci return hash__early_init_mmu(); 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ciextern void hash__early_init_mmu_secondary(void); 2178c2ecf20Sopenharmony_ciextern void radix__early_init_mmu_secondary(void); 2188c2ecf20Sopenharmony_cistatic inline void early_init_mmu_secondary(void) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci if (radix_enabled()) 2218c2ecf20Sopenharmony_ci return radix__early_init_mmu_secondary(); 2228c2ecf20Sopenharmony_ci return hash__early_init_mmu_secondary(); 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ciextern void hash__setup_initial_memory_limit(phys_addr_t first_memblock_base, 2268c2ecf20Sopenharmony_ci phys_addr_t first_memblock_size); 2278c2ecf20Sopenharmony_cistatic inline void setup_initial_memory_limit(phys_addr_t first_memblock_base, 2288c2ecf20Sopenharmony_ci phys_addr_t first_memblock_size) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci /* 2318c2ecf20Sopenharmony_ci * Hash has more strict restrictions. At this point we don't 2328c2ecf20Sopenharmony_ci * know which translations we will pick. Hence go with hash 2338c2ecf20Sopenharmony_ci * restrictions. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci return hash__setup_initial_memory_limit(first_memblock_base, 2368c2ecf20Sopenharmony_ci first_memblock_size); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_PSERIES 2408c2ecf20Sopenharmony_ciextern void radix_init_pseries(void); 2418c2ecf20Sopenharmony_ci#else 2428c2ecf20Sopenharmony_cistatic inline void radix_init_pseries(void) { }; 2438c2ecf20Sopenharmony_ci#endif 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU 2468c2ecf20Sopenharmony_ci#define arch_clear_mm_cpumask_cpu(cpu, mm) \ 2478c2ecf20Sopenharmony_ci do { \ 2488c2ecf20Sopenharmony_ci if (cpumask_test_cpu(cpu, mm_cpumask(mm))) { \ 2498c2ecf20Sopenharmony_ci atomic_dec(&(mm)->context.active_cpus); \ 2508c2ecf20Sopenharmony_ci cpumask_clear_cpu(cpu, mm_cpumask(mm)); \ 2518c2ecf20Sopenharmony_ci } \ 2528c2ecf20Sopenharmony_ci } while (0) 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_civoid cleanup_cpu_mmu_context(void); 2558c2ecf20Sopenharmony_ci#endif 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic inline int get_user_context(mm_context_t *ctx, unsigned long ea) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci int index = ea >> MAX_EA_BITS_PER_CONTEXT; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (likely(index < ARRAY_SIZE(ctx->extended_id))) 2628c2ecf20Sopenharmony_ci return ctx->extended_id[index]; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* should never happen */ 2658c2ecf20Sopenharmony_ci WARN_ON(1); 2668c2ecf20Sopenharmony_ci return 0; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic inline unsigned long get_user_vsid(mm_context_t *ctx, 2708c2ecf20Sopenharmony_ci unsigned long ea, int ssize) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci unsigned long context = get_user_context(ctx, ea); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci return get_vsid(context, ea, ssize); 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci#endif /* __ASSEMBLY__ */ 2788c2ecf20Sopenharmony_ci#endif /* _ASM_POWERPC_BOOK3S_64_MMU_H_ */ 279