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