162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef _ASM_POWERPC_BOOK3S_64_MMU_H_ 362306a36Sopenharmony_ci#define _ASM_POWERPC_BOOK3S_64_MMU_H_ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <asm/page.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#ifndef __ASSEMBLY__ 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci * Page size definition 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * shift : is the "PAGE_SHIFT" value for that page size 1262306a36Sopenharmony_ci * sllp : is a bit mask with the value of SLB L || LP to be or'ed 1362306a36Sopenharmony_ci * directly to a slbmte "vsid" value 1462306a36Sopenharmony_ci * penc : is the HPTE encoding mask for the "LP" field: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_cistruct mmu_psize_def { 1862306a36Sopenharmony_ci unsigned int shift; /* number of bits */ 1962306a36Sopenharmony_ci int penc[MMU_PAGE_COUNT]; /* HPTE encoding */ 2062306a36Sopenharmony_ci unsigned int tlbiel; /* tlbiel supported for that page size */ 2162306a36Sopenharmony_ci unsigned long avpnm; /* bits to mask out in AVPN in the HPTE */ 2262306a36Sopenharmony_ci unsigned long h_rpt_pgsize; /* H_RPT_INVALIDATE page size encoding */ 2362306a36Sopenharmony_ci union { 2462306a36Sopenharmony_ci unsigned long sllp; /* SLB L||LP (exact mask to use in slbmte) */ 2562306a36Sopenharmony_ci unsigned long ap; /* Ap encoding used by PowerISA 3.0 */ 2662306a36Sopenharmony_ci }; 2762306a36Sopenharmony_ci}; 2862306a36Sopenharmony_ciextern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT]; 2962306a36Sopenharmony_ci#endif /* __ASSEMBLY__ */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* 64-bit classic hash table MMU */ 3262306a36Sopenharmony_ci#include <asm/book3s/64/mmu-hash.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#ifndef __ASSEMBLY__ 3562306a36Sopenharmony_ci/* 3662306a36Sopenharmony_ci * ISA 3.0 partition and process table entry format 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_cistruct prtb_entry { 3962306a36Sopenharmony_ci __be64 prtb0; 4062306a36Sopenharmony_ci __be64 prtb1; 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ciextern struct prtb_entry *process_tb; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistruct patb_entry { 4562306a36Sopenharmony_ci __be64 patb0; 4662306a36Sopenharmony_ci __be64 patb1; 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ciextern struct patb_entry *partition_tb; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* Bits in patb0 field */ 5162306a36Sopenharmony_ci#define PATB_HR (1UL << 63) 5262306a36Sopenharmony_ci#define RPDB_MASK 0x0fffffffffffff00UL 5362306a36Sopenharmony_ci#define RPDB_SHIFT (1UL << 8) 5462306a36Sopenharmony_ci#define RTS1_SHIFT 61 /* top 2 bits of radix tree size */ 5562306a36Sopenharmony_ci#define RTS1_MASK (3UL << RTS1_SHIFT) 5662306a36Sopenharmony_ci#define RTS2_SHIFT 5 /* bottom 3 bits of radix tree size */ 5762306a36Sopenharmony_ci#define RTS2_MASK (7UL << RTS2_SHIFT) 5862306a36Sopenharmony_ci#define RPDS_MASK 0x1f /* root page dir. size field */ 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* Bits in patb1 field */ 6162306a36Sopenharmony_ci#define PATB_GR (1UL << 63) /* guest uses radix; must match HR */ 6262306a36Sopenharmony_ci#define PRTS_MASK 0x1f /* process table size field */ 6362306a36Sopenharmony_ci#define PRTB_MASK 0x0ffffffffffff000UL 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* Number of supported LPID bits */ 6662306a36Sopenharmony_ciextern unsigned int mmu_lpid_bits; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* Number of supported PID bits */ 6962306a36Sopenharmony_ciextern unsigned int mmu_pid_bits; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* Base PID to allocate from */ 7262306a36Sopenharmony_ciextern unsigned int mmu_base_pid; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ciextern unsigned long __ro_after_init memory_block_size; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define PRTB_SIZE_SHIFT (mmu_pid_bits + 4) 7762306a36Sopenharmony_ci#define PRTB_ENTRIES (1ul << mmu_pid_bits) 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#define PATB_SIZE_SHIFT (mmu_lpid_bits + 4) 8062306a36Sopenharmony_ci#define PATB_ENTRIES (1ul << mmu_lpid_bits) 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_citypedef unsigned long mm_context_id_t; 8362306a36Sopenharmony_cistruct spinlock; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* Maximum possible number of NPUs in a system. */ 8662306a36Sopenharmony_ci#define NV_MAX_NPUS 8 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_citypedef struct { 8962306a36Sopenharmony_ci union { 9062306a36Sopenharmony_ci /* 9162306a36Sopenharmony_ci * We use id as the PIDR content for radix. On hash we can use 9262306a36Sopenharmony_ci * more than one id. The extended ids are used when we start 9362306a36Sopenharmony_ci * having address above 512TB. We allocate one extended id 9462306a36Sopenharmony_ci * for each 512TB. The new id is then used with the 49 bit 9562306a36Sopenharmony_ci * EA to build a new VA. We always use ESID_BITS_1T_MASK bits 9662306a36Sopenharmony_ci * from EA and new context ids to build the new VAs. 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_ci mm_context_id_t id; 9962306a36Sopenharmony_ci#ifdef CONFIG_PPC_64S_HASH_MMU 10062306a36Sopenharmony_ci mm_context_id_t extended_id[TASK_SIZE_USER64/TASK_CONTEXT_SIZE]; 10162306a36Sopenharmony_ci#endif 10262306a36Sopenharmony_ci }; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci /* Number of bits in the mm_cpumask */ 10562306a36Sopenharmony_ci atomic_t active_cpus; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* Number of users of the external (Nest) MMU */ 10862306a36Sopenharmony_ci atomic_t copros; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* Number of user space windows opened in process mm_context */ 11162306a36Sopenharmony_ci atomic_t vas_windows; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci#ifdef CONFIG_PPC_64S_HASH_MMU 11462306a36Sopenharmony_ci struct hash_mm_context *hash_context; 11562306a36Sopenharmony_ci#endif 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci void __user *vdso; 11862306a36Sopenharmony_ci /* 11962306a36Sopenharmony_ci * pagetable fragment support 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_ci void *pte_frag; 12262306a36Sopenharmony_ci void *pmd_frag; 12362306a36Sopenharmony_ci#ifdef CONFIG_SPAPR_TCE_IOMMU 12462306a36Sopenharmony_ci struct list_head iommu_group_mem_list; 12562306a36Sopenharmony_ci#endif 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci#ifdef CONFIG_PPC_MEM_KEYS 12862306a36Sopenharmony_ci /* 12962306a36Sopenharmony_ci * Each bit represents one protection key. 13062306a36Sopenharmony_ci * bit set -> key allocated 13162306a36Sopenharmony_ci * bit unset -> key available for allocation 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_ci u32 pkey_allocation_map; 13462306a36Sopenharmony_ci s16 execute_only_pkey; /* key holding execute-only protection */ 13562306a36Sopenharmony_ci#endif 13662306a36Sopenharmony_ci} mm_context_t; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci#ifdef CONFIG_PPC_64S_HASH_MMU 13962306a36Sopenharmony_cistatic inline u16 mm_ctx_user_psize(mm_context_t *ctx) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci return ctx->hash_context->user_psize; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic inline void mm_ctx_set_user_psize(mm_context_t *ctx, u16 user_psize) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci ctx->hash_context->user_psize = user_psize; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic inline unsigned char *mm_ctx_low_slices(mm_context_t *ctx) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci return ctx->hash_context->low_slices_psize; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic inline unsigned char *mm_ctx_high_slices(mm_context_t *ctx) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci return ctx->hash_context->high_slices_psize; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic inline unsigned long mm_ctx_slb_addr_limit(mm_context_t *ctx) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci return ctx->hash_context->slb_addr_limit; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic inline void mm_ctx_set_slb_addr_limit(mm_context_t *ctx, unsigned long limit) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci ctx->hash_context->slb_addr_limit = limit; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic inline struct slice_mask *slice_mask_for_size(mm_context_t *ctx, int psize) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES 17262306a36Sopenharmony_ci if (psize == MMU_PAGE_64K) 17362306a36Sopenharmony_ci return &ctx->hash_context->mask_64k; 17462306a36Sopenharmony_ci#endif 17562306a36Sopenharmony_ci#ifdef CONFIG_HUGETLB_PAGE 17662306a36Sopenharmony_ci if (psize == MMU_PAGE_16M) 17762306a36Sopenharmony_ci return &ctx->hash_context->mask_16m; 17862306a36Sopenharmony_ci if (psize == MMU_PAGE_16G) 17962306a36Sopenharmony_ci return &ctx->hash_context->mask_16g; 18062306a36Sopenharmony_ci#endif 18162306a36Sopenharmony_ci BUG_ON(psize != MMU_PAGE_4K); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci return &ctx->hash_context->mask_4k; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci#ifdef CONFIG_PPC_SUBPAGE_PROT 18762306a36Sopenharmony_cistatic inline struct subpage_prot_table *mm_ctx_subpage_prot(mm_context_t *ctx) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci return ctx->hash_context->spt; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci#endif 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/* 19462306a36Sopenharmony_ci * The current system page and segment sizes 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_ciextern int mmu_virtual_psize; 19762306a36Sopenharmony_ciextern int mmu_vmalloc_psize; 19862306a36Sopenharmony_ciextern int mmu_io_psize; 19962306a36Sopenharmony_ci#else /* CONFIG_PPC_64S_HASH_MMU */ 20062306a36Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES 20162306a36Sopenharmony_ci#define mmu_virtual_psize MMU_PAGE_64K 20262306a36Sopenharmony_ci#else 20362306a36Sopenharmony_ci#define mmu_virtual_psize MMU_PAGE_4K 20462306a36Sopenharmony_ci#endif 20562306a36Sopenharmony_ci#endif 20662306a36Sopenharmony_ciextern int mmu_linear_psize; 20762306a36Sopenharmony_ciextern int mmu_vmemmap_psize; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci/* MMU initialization */ 21062306a36Sopenharmony_civoid mmu_early_init_devtree(void); 21162306a36Sopenharmony_civoid hash__early_init_devtree(void); 21262306a36Sopenharmony_civoid radix__early_init_devtree(void); 21362306a36Sopenharmony_ci#ifdef CONFIG_PPC_PKEY 21462306a36Sopenharmony_civoid pkey_early_init_devtree(void); 21562306a36Sopenharmony_ci#else 21662306a36Sopenharmony_cistatic inline void pkey_early_init_devtree(void) {} 21762306a36Sopenharmony_ci#endif 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ciextern void hash__early_init_mmu(void); 22062306a36Sopenharmony_ciextern void radix__early_init_mmu(void); 22162306a36Sopenharmony_cistatic inline void __init early_init_mmu(void) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci if (radix_enabled()) 22462306a36Sopenharmony_ci return radix__early_init_mmu(); 22562306a36Sopenharmony_ci return hash__early_init_mmu(); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ciextern void hash__early_init_mmu_secondary(void); 22862306a36Sopenharmony_ciextern void radix__early_init_mmu_secondary(void); 22962306a36Sopenharmony_cistatic inline void early_init_mmu_secondary(void) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci if (radix_enabled()) 23262306a36Sopenharmony_ci return radix__early_init_mmu_secondary(); 23362306a36Sopenharmony_ci return hash__early_init_mmu_secondary(); 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ciextern void hash__setup_initial_memory_limit(phys_addr_t first_memblock_base, 23762306a36Sopenharmony_ci phys_addr_t first_memblock_size); 23862306a36Sopenharmony_cistatic inline void setup_initial_memory_limit(phys_addr_t first_memblock_base, 23962306a36Sopenharmony_ci phys_addr_t first_memblock_size) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci /* 24262306a36Sopenharmony_ci * Hash has more strict restrictions. At this point we don't 24362306a36Sopenharmony_ci * know which translations we will pick. Hence go with hash 24462306a36Sopenharmony_ci * restrictions. 24562306a36Sopenharmony_ci */ 24662306a36Sopenharmony_ci if (!early_radix_enabled()) 24762306a36Sopenharmony_ci hash__setup_initial_memory_limit(first_memblock_base, 24862306a36Sopenharmony_ci first_memblock_size); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci#ifdef CONFIG_PPC_PSERIES 25262306a36Sopenharmony_civoid __init radix_init_pseries(void); 25362306a36Sopenharmony_ci#else 25462306a36Sopenharmony_cistatic inline void radix_init_pseries(void) { } 25562306a36Sopenharmony_ci#endif 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU 25862306a36Sopenharmony_ci#define arch_clear_mm_cpumask_cpu(cpu, mm) \ 25962306a36Sopenharmony_ci do { \ 26062306a36Sopenharmony_ci if (cpumask_test_cpu(cpu, mm_cpumask(mm))) { \ 26162306a36Sopenharmony_ci dec_mm_active_cpus(mm); \ 26262306a36Sopenharmony_ci cpumask_clear_cpu(cpu, mm_cpumask(mm)); \ 26362306a36Sopenharmony_ci } \ 26462306a36Sopenharmony_ci } while (0) 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_civoid cleanup_cpu_mmu_context(void); 26762306a36Sopenharmony_ci#endif 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci#ifdef CONFIG_PPC_64S_HASH_MMU 27062306a36Sopenharmony_cistatic inline int get_user_context(mm_context_t *ctx, unsigned long ea) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci int index = ea >> MAX_EA_BITS_PER_CONTEXT; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (likely(index < ARRAY_SIZE(ctx->extended_id))) 27562306a36Sopenharmony_ci return ctx->extended_id[index]; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* should never happen */ 27862306a36Sopenharmony_ci WARN_ON(1); 27962306a36Sopenharmony_ci return 0; 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistatic inline unsigned long get_user_vsid(mm_context_t *ctx, 28362306a36Sopenharmony_ci unsigned long ea, int ssize) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci unsigned long context = get_user_context(ctx, ea); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci return get_vsid(context, ea, ssize); 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci#endif 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci#endif /* __ASSEMBLY__ */ 29262306a36Sopenharmony_ci#endif /* _ASM_POWERPC_BOOK3S_64_MMU_H_ */ 293