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