162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PowerPC64 port by Mike Corrigan and Dave Engebretsen
462306a36Sopenharmony_ci *   {mikejc|engebret}@us.ibm.com
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *    Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * SMP scalability work:
962306a36Sopenharmony_ci *    Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci *    Module name: htab.c
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci *    Description:
1462306a36Sopenharmony_ci *      PowerPC Hashed Page Table functions
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#undef DEBUG
1862306a36Sopenharmony_ci#undef DEBUG_LOW
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define pr_fmt(fmt) "hash-mmu: " fmt
2162306a36Sopenharmony_ci#include <linux/spinlock.h>
2262306a36Sopenharmony_ci#include <linux/errno.h>
2362306a36Sopenharmony_ci#include <linux/sched/mm.h>
2462306a36Sopenharmony_ci#include <linux/proc_fs.h>
2562306a36Sopenharmony_ci#include <linux/stat.h>
2662306a36Sopenharmony_ci#include <linux/sysctl.h>
2762306a36Sopenharmony_ci#include <linux/export.h>
2862306a36Sopenharmony_ci#include <linux/ctype.h>
2962306a36Sopenharmony_ci#include <linux/cache.h>
3062306a36Sopenharmony_ci#include <linux/init.h>
3162306a36Sopenharmony_ci#include <linux/signal.h>
3262306a36Sopenharmony_ci#include <linux/memblock.h>
3362306a36Sopenharmony_ci#include <linux/context_tracking.h>
3462306a36Sopenharmony_ci#include <linux/libfdt.h>
3562306a36Sopenharmony_ci#include <linux/pkeys.h>
3662306a36Sopenharmony_ci#include <linux/hugetlb.h>
3762306a36Sopenharmony_ci#include <linux/cpu.h>
3862306a36Sopenharmony_ci#include <linux/pgtable.h>
3962306a36Sopenharmony_ci#include <linux/debugfs.h>
4062306a36Sopenharmony_ci#include <linux/random.h>
4162306a36Sopenharmony_ci#include <linux/elf-randomize.h>
4262306a36Sopenharmony_ci#include <linux/of_fdt.h>
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#include <asm/interrupt.h>
4562306a36Sopenharmony_ci#include <asm/processor.h>
4662306a36Sopenharmony_ci#include <asm/mmu.h>
4762306a36Sopenharmony_ci#include <asm/mmu_context.h>
4862306a36Sopenharmony_ci#include <asm/page.h>
4962306a36Sopenharmony_ci#include <asm/types.h>
5062306a36Sopenharmony_ci#include <linux/uaccess.h>
5162306a36Sopenharmony_ci#include <asm/machdep.h>
5262306a36Sopenharmony_ci#include <asm/io.h>
5362306a36Sopenharmony_ci#include <asm/eeh.h>
5462306a36Sopenharmony_ci#include <asm/tlb.h>
5562306a36Sopenharmony_ci#include <asm/cacheflush.h>
5662306a36Sopenharmony_ci#include <asm/cputable.h>
5762306a36Sopenharmony_ci#include <asm/sections.h>
5862306a36Sopenharmony_ci#include <asm/copro.h>
5962306a36Sopenharmony_ci#include <asm/udbg.h>
6062306a36Sopenharmony_ci#include <asm/code-patching.h>
6162306a36Sopenharmony_ci#include <asm/fadump.h>
6262306a36Sopenharmony_ci#include <asm/firmware.h>
6362306a36Sopenharmony_ci#include <asm/tm.h>
6462306a36Sopenharmony_ci#include <asm/trace.h>
6562306a36Sopenharmony_ci#include <asm/ps3.h>
6662306a36Sopenharmony_ci#include <asm/pte-walk.h>
6762306a36Sopenharmony_ci#include <asm/asm-prototypes.h>
6862306a36Sopenharmony_ci#include <asm/ultravisor.h>
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#include <mm/mmu_decl.h>
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#include "internal.h"
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci#ifdef DEBUG
7662306a36Sopenharmony_ci#define DBG(fmt...) udbg_printf(fmt)
7762306a36Sopenharmony_ci#else
7862306a36Sopenharmony_ci#define DBG(fmt...)
7962306a36Sopenharmony_ci#endif
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#ifdef DEBUG_LOW
8262306a36Sopenharmony_ci#define DBG_LOW(fmt...) udbg_printf(fmt)
8362306a36Sopenharmony_ci#else
8462306a36Sopenharmony_ci#define DBG_LOW(fmt...)
8562306a36Sopenharmony_ci#endif
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci#define KB (1024)
8862306a36Sopenharmony_ci#define MB (1024*KB)
8962306a36Sopenharmony_ci#define GB (1024L*MB)
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/*
9262306a36Sopenharmony_ci * Note:  pte   --> Linux PTE
9362306a36Sopenharmony_ci *        HPTE  --> PowerPC Hashed Page Table Entry
9462306a36Sopenharmony_ci *
9562306a36Sopenharmony_ci * Execution context:
9662306a36Sopenharmony_ci *   htab_initialize is called with the MMU off (of course), but
9762306a36Sopenharmony_ci *   the kernel has been copied down to zero so it can directly
9862306a36Sopenharmony_ci *   reference global data.  At this point it is very difficult
9962306a36Sopenharmony_ci *   to print debug info.
10062306a36Sopenharmony_ci *
10162306a36Sopenharmony_ci */
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic unsigned long _SDR1;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ciu8 hpte_page_sizes[1 << LP_BITS];
10662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hpte_page_sizes);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistruct hash_pte *htab_address;
10962306a36Sopenharmony_ciunsigned long htab_size_bytes;
11062306a36Sopenharmony_ciunsigned long htab_hash_mask;
11162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(htab_hash_mask);
11262306a36Sopenharmony_ciint mmu_linear_psize = MMU_PAGE_4K;
11362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mmu_linear_psize);
11462306a36Sopenharmony_ciint mmu_virtual_psize = MMU_PAGE_4K;
11562306a36Sopenharmony_ciint mmu_vmalloc_psize = MMU_PAGE_4K;
11662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mmu_vmalloc_psize);
11762306a36Sopenharmony_ciint mmu_io_psize = MMU_PAGE_4K;
11862306a36Sopenharmony_ciint mmu_kernel_ssize = MMU_SEGSIZE_256M;
11962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mmu_kernel_ssize);
12062306a36Sopenharmony_ciint mmu_highuser_ssize = MMU_SEGSIZE_256M;
12162306a36Sopenharmony_ciu16 mmu_slb_size = 64;
12262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mmu_slb_size);
12362306a36Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES
12462306a36Sopenharmony_ciint mmu_ci_restrictions;
12562306a36Sopenharmony_ci#endif
12662306a36Sopenharmony_cistatic u8 *linear_map_hash_slots;
12762306a36Sopenharmony_cistatic unsigned long linear_map_hash_count;
12862306a36Sopenharmony_cistruct mmu_hash_ops mmu_hash_ops;
12962306a36Sopenharmony_ciEXPORT_SYMBOL(mmu_hash_ops);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci/*
13262306a36Sopenharmony_ci * These are definitions of page sizes arrays to be used when none
13362306a36Sopenharmony_ci * is provided by the firmware.
13462306a36Sopenharmony_ci */
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci/*
13762306a36Sopenharmony_ci * Fallback (4k pages only)
13862306a36Sopenharmony_ci */
13962306a36Sopenharmony_cistatic struct mmu_psize_def mmu_psize_defaults[] = {
14062306a36Sopenharmony_ci	[MMU_PAGE_4K] = {
14162306a36Sopenharmony_ci		.shift	= 12,
14262306a36Sopenharmony_ci		.sllp	= 0,
14362306a36Sopenharmony_ci		.penc   = {[MMU_PAGE_4K] = 0, [1 ... MMU_PAGE_COUNT - 1] = -1},
14462306a36Sopenharmony_ci		.avpnm	= 0,
14562306a36Sopenharmony_ci		.tlbiel = 0,
14662306a36Sopenharmony_ci	},
14762306a36Sopenharmony_ci};
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci/*
15062306a36Sopenharmony_ci * POWER4, GPUL, POWER5
15162306a36Sopenharmony_ci *
15262306a36Sopenharmony_ci * Support for 16Mb large pages
15362306a36Sopenharmony_ci */
15462306a36Sopenharmony_cistatic struct mmu_psize_def mmu_psize_defaults_gp[] = {
15562306a36Sopenharmony_ci	[MMU_PAGE_4K] = {
15662306a36Sopenharmony_ci		.shift	= 12,
15762306a36Sopenharmony_ci		.sllp	= 0,
15862306a36Sopenharmony_ci		.penc   = {[MMU_PAGE_4K] = 0, [1 ... MMU_PAGE_COUNT - 1] = -1},
15962306a36Sopenharmony_ci		.avpnm	= 0,
16062306a36Sopenharmony_ci		.tlbiel = 1,
16162306a36Sopenharmony_ci	},
16262306a36Sopenharmony_ci	[MMU_PAGE_16M] = {
16362306a36Sopenharmony_ci		.shift	= 24,
16462306a36Sopenharmony_ci		.sllp	= SLB_VSID_L,
16562306a36Sopenharmony_ci		.penc   = {[0 ... MMU_PAGE_16M - 1] = -1, [MMU_PAGE_16M] = 0,
16662306a36Sopenharmony_ci			    [MMU_PAGE_16M + 1 ... MMU_PAGE_COUNT - 1] = -1 },
16762306a36Sopenharmony_ci		.avpnm	= 0x1UL,
16862306a36Sopenharmony_ci		.tlbiel = 0,
16962306a36Sopenharmony_ci	},
17062306a36Sopenharmony_ci};
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic inline void tlbiel_hash_set_isa206(unsigned int set, unsigned int is)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	unsigned long rb;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	rb = (set << PPC_BITLSHIFT(51)) | (is << PPC_BITLSHIFT(53));
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	asm volatile("tlbiel %0" : : "r" (rb));
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci/*
18262306a36Sopenharmony_ci * tlbiel instruction for hash, set invalidation
18362306a36Sopenharmony_ci * i.e., r=1 and is=01 or is=10 or is=11
18462306a36Sopenharmony_ci */
18562306a36Sopenharmony_cistatic __always_inline void tlbiel_hash_set_isa300(unsigned int set, unsigned int is,
18662306a36Sopenharmony_ci					unsigned int pid,
18762306a36Sopenharmony_ci					unsigned int ric, unsigned int prs)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	unsigned long rb;
19062306a36Sopenharmony_ci	unsigned long rs;
19162306a36Sopenharmony_ci	unsigned int r = 0; /* hash format */
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	rb = (set << PPC_BITLSHIFT(51)) | (is << PPC_BITLSHIFT(53));
19462306a36Sopenharmony_ci	rs = ((unsigned long)pid << PPC_BITLSHIFT(31));
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	asm volatile(PPC_TLBIEL(%0, %1, %2, %3, %4)
19762306a36Sopenharmony_ci		     : : "r"(rb), "r"(rs), "i"(ric), "i"(prs), "i"(r)
19862306a36Sopenharmony_ci		     : "memory");
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic void tlbiel_all_isa206(unsigned int num_sets, unsigned int is)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	unsigned int set;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	asm volatile("ptesync": : :"memory");
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	for (set = 0; set < num_sets; set++)
20962306a36Sopenharmony_ci		tlbiel_hash_set_isa206(set, is);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	ppc_after_tlbiel_barrier();
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistatic void tlbiel_all_isa300(unsigned int num_sets, unsigned int is)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	unsigned int set;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	asm volatile("ptesync": : :"memory");
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	/*
22162306a36Sopenharmony_ci	 * Flush the partition table cache if this is HV mode.
22262306a36Sopenharmony_ci	 */
22362306a36Sopenharmony_ci	if (early_cpu_has_feature(CPU_FTR_HVMODE))
22462306a36Sopenharmony_ci		tlbiel_hash_set_isa300(0, is, 0, 2, 0);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	/*
22762306a36Sopenharmony_ci	 * Now invalidate the process table cache. UPRT=0 HPT modes (what
22862306a36Sopenharmony_ci	 * current hardware implements) do not use the process table, but
22962306a36Sopenharmony_ci	 * add the flushes anyway.
23062306a36Sopenharmony_ci	 *
23162306a36Sopenharmony_ci	 * From ISA v3.0B p. 1078:
23262306a36Sopenharmony_ci	 *     The following forms are invalid.
23362306a36Sopenharmony_ci	 *      * PRS=1, R=0, and RIC!=2 (The only process-scoped
23462306a36Sopenharmony_ci	 *        HPT caching is of the Process Table.)
23562306a36Sopenharmony_ci	 */
23662306a36Sopenharmony_ci	tlbiel_hash_set_isa300(0, is, 0, 2, 1);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	/*
23962306a36Sopenharmony_ci	 * Then flush the sets of the TLB proper. Hash mode uses
24062306a36Sopenharmony_ci	 * partition scoped TLB translations, which may be flushed
24162306a36Sopenharmony_ci	 * in !HV mode.
24262306a36Sopenharmony_ci	 */
24362306a36Sopenharmony_ci	for (set = 0; set < num_sets; set++)
24462306a36Sopenharmony_ci		tlbiel_hash_set_isa300(set, is, 0, 0, 0);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	ppc_after_tlbiel_barrier();
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	asm volatile(PPC_ISA_3_0_INVALIDATE_ERAT "; isync" : : :"memory");
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_civoid hash__tlbiel_all(unsigned int action)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	unsigned int is;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	switch (action) {
25662306a36Sopenharmony_ci	case TLB_INVAL_SCOPE_GLOBAL:
25762306a36Sopenharmony_ci		is = 3;
25862306a36Sopenharmony_ci		break;
25962306a36Sopenharmony_ci	case TLB_INVAL_SCOPE_LPID:
26062306a36Sopenharmony_ci		is = 2;
26162306a36Sopenharmony_ci		break;
26262306a36Sopenharmony_ci	default:
26362306a36Sopenharmony_ci		BUG();
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	if (early_cpu_has_feature(CPU_FTR_ARCH_300))
26762306a36Sopenharmony_ci		tlbiel_all_isa300(POWER9_TLB_SETS_HASH, is);
26862306a36Sopenharmony_ci	else if (early_cpu_has_feature(CPU_FTR_ARCH_207S))
26962306a36Sopenharmony_ci		tlbiel_all_isa206(POWER8_TLB_SETS, is);
27062306a36Sopenharmony_ci	else if (early_cpu_has_feature(CPU_FTR_ARCH_206))
27162306a36Sopenharmony_ci		tlbiel_all_isa206(POWER7_TLB_SETS, is);
27262306a36Sopenharmony_ci	else
27362306a36Sopenharmony_ci		WARN(1, "%s called on pre-POWER7 CPU\n", __func__);
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci/*
27762306a36Sopenharmony_ci * 'R' and 'C' update notes:
27862306a36Sopenharmony_ci *  - Under pHyp or KVM, the updatepp path will not set C, thus it *will*
27962306a36Sopenharmony_ci *     create writeable HPTEs without C set, because the hcall H_PROTECT
28062306a36Sopenharmony_ci *     that we use in that case will not update C
28162306a36Sopenharmony_ci *  - The above is however not a problem, because we also don't do that
28262306a36Sopenharmony_ci *     fancy "no flush" variant of eviction and we use H_REMOVE which will
28362306a36Sopenharmony_ci *     do the right thing and thus we don't have the race I described earlier
28462306a36Sopenharmony_ci *
28562306a36Sopenharmony_ci *    - Under bare metal,  we do have the race, so we need R and C set
28662306a36Sopenharmony_ci *    - We make sure R is always set and never lost
28762306a36Sopenharmony_ci *    - C is _PAGE_DIRTY, and *should* always be set for a writeable mapping
28862306a36Sopenharmony_ci */
28962306a36Sopenharmony_ciunsigned long htab_convert_pte_flags(unsigned long pteflags, unsigned long flags)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	unsigned long rflags = 0;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	/* _PAGE_EXEC -> NOEXEC */
29462306a36Sopenharmony_ci	if ((pteflags & _PAGE_EXEC) == 0)
29562306a36Sopenharmony_ci		rflags |= HPTE_R_N;
29662306a36Sopenharmony_ci	/*
29762306a36Sopenharmony_ci	 * PPP bits:
29862306a36Sopenharmony_ci	 * Linux uses slb key 0 for kernel and 1 for user.
29962306a36Sopenharmony_ci	 * kernel RW areas are mapped with PPP=0b000
30062306a36Sopenharmony_ci	 * User area is mapped with PPP=0b010 for read/write
30162306a36Sopenharmony_ci	 * or PPP=0b011 for read-only (including writeable but clean pages).
30262306a36Sopenharmony_ci	 */
30362306a36Sopenharmony_ci	if (pteflags & _PAGE_PRIVILEGED) {
30462306a36Sopenharmony_ci		/*
30562306a36Sopenharmony_ci		 * Kernel read only mapped with ppp bits 0b110
30662306a36Sopenharmony_ci		 */
30762306a36Sopenharmony_ci		if (!(pteflags & _PAGE_WRITE)) {
30862306a36Sopenharmony_ci			if (mmu_has_feature(MMU_FTR_KERNEL_RO))
30962306a36Sopenharmony_ci				rflags |= (HPTE_R_PP0 | 0x2);
31062306a36Sopenharmony_ci			else
31162306a36Sopenharmony_ci				rflags |= 0x3;
31262306a36Sopenharmony_ci		}
31362306a36Sopenharmony_ci	} else {
31462306a36Sopenharmony_ci		if (pteflags & _PAGE_RWX)
31562306a36Sopenharmony_ci			rflags |= 0x2;
31662306a36Sopenharmony_ci		if (!((pteflags & _PAGE_WRITE) && (pteflags & _PAGE_DIRTY)))
31762306a36Sopenharmony_ci			rflags |= 0x1;
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci	/*
32062306a36Sopenharmony_ci	 * We can't allow hardware to update hpte bits. Hence always
32162306a36Sopenharmony_ci	 * set 'R' bit and set 'C' if it is a write fault
32262306a36Sopenharmony_ci	 */
32362306a36Sopenharmony_ci	rflags |=  HPTE_R_R;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	if (pteflags & _PAGE_DIRTY)
32662306a36Sopenharmony_ci		rflags |= HPTE_R_C;
32762306a36Sopenharmony_ci	/*
32862306a36Sopenharmony_ci	 * Add in WIG bits
32962306a36Sopenharmony_ci	 */
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	if ((pteflags & _PAGE_CACHE_CTL) == _PAGE_TOLERANT)
33262306a36Sopenharmony_ci		rflags |= HPTE_R_I;
33362306a36Sopenharmony_ci	else if ((pteflags & _PAGE_CACHE_CTL) == _PAGE_NON_IDEMPOTENT)
33462306a36Sopenharmony_ci		rflags |= (HPTE_R_I | HPTE_R_G);
33562306a36Sopenharmony_ci	else if ((pteflags & _PAGE_CACHE_CTL) == _PAGE_SAO)
33662306a36Sopenharmony_ci		rflags |= (HPTE_R_W | HPTE_R_I | HPTE_R_M);
33762306a36Sopenharmony_ci	else
33862306a36Sopenharmony_ci		/*
33962306a36Sopenharmony_ci		 * Add memory coherence if cache inhibited is not set
34062306a36Sopenharmony_ci		 */
34162306a36Sopenharmony_ci		rflags |= HPTE_R_M;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	rflags |= pte_to_hpte_pkey_bits(pteflags, flags);
34462306a36Sopenharmony_ci	return rflags;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ciint htab_bolt_mapping(unsigned long vstart, unsigned long vend,
34862306a36Sopenharmony_ci		      unsigned long pstart, unsigned long prot,
34962306a36Sopenharmony_ci		      int psize, int ssize)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	unsigned long vaddr, paddr;
35262306a36Sopenharmony_ci	unsigned int step, shift;
35362306a36Sopenharmony_ci	int ret = 0;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	shift = mmu_psize_defs[psize].shift;
35662306a36Sopenharmony_ci	step = 1 << shift;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	prot = htab_convert_pte_flags(prot, HPTE_USE_KERNEL_KEY);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	DBG("htab_bolt_mapping(%lx..%lx -> %lx (%lx,%d,%d)\n",
36162306a36Sopenharmony_ci	    vstart, vend, pstart, prot, psize, ssize);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	/* Carefully map only the possible range */
36462306a36Sopenharmony_ci	vaddr = ALIGN(vstart, step);
36562306a36Sopenharmony_ci	paddr = ALIGN(pstart, step);
36662306a36Sopenharmony_ci	vend  = ALIGN_DOWN(vend, step);
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	for (; vaddr < vend; vaddr += step, paddr += step) {
36962306a36Sopenharmony_ci		unsigned long hash, hpteg;
37062306a36Sopenharmony_ci		unsigned long vsid = get_kernel_vsid(vaddr, ssize);
37162306a36Sopenharmony_ci		unsigned long vpn  = hpt_vpn(vaddr, vsid, ssize);
37262306a36Sopenharmony_ci		unsigned long tprot = prot;
37362306a36Sopenharmony_ci		bool secondary_hash = false;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci		/*
37662306a36Sopenharmony_ci		 * If we hit a bad address return error.
37762306a36Sopenharmony_ci		 */
37862306a36Sopenharmony_ci		if (!vsid)
37962306a36Sopenharmony_ci			return -1;
38062306a36Sopenharmony_ci		/* Make kernel text executable */
38162306a36Sopenharmony_ci		if (overlaps_kernel_text(vaddr, vaddr + step))
38262306a36Sopenharmony_ci			tprot &= ~HPTE_R_N;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci		/*
38562306a36Sopenharmony_ci		 * If relocatable, check if it overlaps interrupt vectors that
38662306a36Sopenharmony_ci		 * are copied down to real 0. For relocatable kernel
38762306a36Sopenharmony_ci		 * (e.g. kdump case) we copy interrupt vectors down to real
38862306a36Sopenharmony_ci		 * address 0. Mark that region as executable. This is
38962306a36Sopenharmony_ci		 * because on p8 system with relocation on exception feature
39062306a36Sopenharmony_ci		 * enabled, exceptions are raised with MMU (IR=DR=1) ON. Hence
39162306a36Sopenharmony_ci		 * in order to execute the interrupt handlers in virtual
39262306a36Sopenharmony_ci		 * mode the vector region need to be marked as executable.
39362306a36Sopenharmony_ci		 */
39462306a36Sopenharmony_ci		if ((PHYSICAL_START > MEMORY_START) &&
39562306a36Sopenharmony_ci			overlaps_interrupt_vector_text(vaddr, vaddr + step))
39662306a36Sopenharmony_ci				tprot &= ~HPTE_R_N;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci		hash = hpt_hash(vpn, shift, ssize);
39962306a36Sopenharmony_ci		hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci		BUG_ON(!mmu_hash_ops.hpte_insert);
40262306a36Sopenharmony_cirepeat:
40362306a36Sopenharmony_ci		ret = mmu_hash_ops.hpte_insert(hpteg, vpn, paddr, tprot,
40462306a36Sopenharmony_ci					       HPTE_V_BOLTED, psize, psize,
40562306a36Sopenharmony_ci					       ssize);
40662306a36Sopenharmony_ci		if (ret == -1) {
40762306a36Sopenharmony_ci			/*
40862306a36Sopenharmony_ci			 * Try to keep bolted entries in primary.
40962306a36Sopenharmony_ci			 * Remove non bolted entries and try insert again
41062306a36Sopenharmony_ci			 */
41162306a36Sopenharmony_ci			ret = mmu_hash_ops.hpte_remove(hpteg);
41262306a36Sopenharmony_ci			if (ret != -1)
41362306a36Sopenharmony_ci				ret = mmu_hash_ops.hpte_insert(hpteg, vpn, paddr, tprot,
41462306a36Sopenharmony_ci							       HPTE_V_BOLTED, psize, psize,
41562306a36Sopenharmony_ci							       ssize);
41662306a36Sopenharmony_ci			if (ret == -1 && !secondary_hash) {
41762306a36Sopenharmony_ci				secondary_hash = true;
41862306a36Sopenharmony_ci				hpteg = ((~hash & htab_hash_mask) * HPTES_PER_GROUP);
41962306a36Sopenharmony_ci				goto repeat;
42062306a36Sopenharmony_ci			}
42162306a36Sopenharmony_ci		}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci		if (ret < 0)
42462306a36Sopenharmony_ci			break;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci		cond_resched();
42762306a36Sopenharmony_ci		if (debug_pagealloc_enabled_or_kfence() &&
42862306a36Sopenharmony_ci			(paddr >> PAGE_SHIFT) < linear_map_hash_count)
42962306a36Sopenharmony_ci			linear_map_hash_slots[paddr >> PAGE_SHIFT] = ret | 0x80;
43062306a36Sopenharmony_ci	}
43162306a36Sopenharmony_ci	return ret < 0 ? ret : 0;
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ciint htab_remove_mapping(unsigned long vstart, unsigned long vend,
43562306a36Sopenharmony_ci		      int psize, int ssize)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	unsigned long vaddr, time_limit;
43862306a36Sopenharmony_ci	unsigned int step, shift;
43962306a36Sopenharmony_ci	int rc;
44062306a36Sopenharmony_ci	int ret = 0;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	shift = mmu_psize_defs[psize].shift;
44362306a36Sopenharmony_ci	step = 1 << shift;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	if (!mmu_hash_ops.hpte_removebolted)
44662306a36Sopenharmony_ci		return -ENODEV;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	/* Unmap the full range specificied */
44962306a36Sopenharmony_ci	vaddr = ALIGN_DOWN(vstart, step);
45062306a36Sopenharmony_ci	time_limit = jiffies + HZ;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	for (;vaddr < vend; vaddr += step) {
45362306a36Sopenharmony_ci		rc = mmu_hash_ops.hpte_removebolted(vaddr, psize, ssize);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci		/*
45662306a36Sopenharmony_ci		 * For large number of mappings introduce a cond_resched()
45762306a36Sopenharmony_ci		 * to prevent softlockup warnings.
45862306a36Sopenharmony_ci		 */
45962306a36Sopenharmony_ci		if (time_after(jiffies, time_limit)) {
46062306a36Sopenharmony_ci			cond_resched();
46162306a36Sopenharmony_ci			time_limit = jiffies + HZ;
46262306a36Sopenharmony_ci		}
46362306a36Sopenharmony_ci		if (rc == -ENOENT) {
46462306a36Sopenharmony_ci			ret = -ENOENT;
46562306a36Sopenharmony_ci			continue;
46662306a36Sopenharmony_ci		}
46762306a36Sopenharmony_ci		if (rc < 0)
46862306a36Sopenharmony_ci			return rc;
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	return ret;
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistatic bool disable_1tb_segments __ro_after_init;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_cistatic int __init parse_disable_1tb_segments(char *p)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	disable_1tb_segments = true;
47962306a36Sopenharmony_ci	return 0;
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ciearly_param("disable_1tb_segments", parse_disable_1tb_segments);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cibool stress_hpt_enabled __initdata;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistatic int __init parse_stress_hpt(char *p)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	stress_hpt_enabled = true;
48862306a36Sopenharmony_ci	return 0;
48962306a36Sopenharmony_ci}
49062306a36Sopenharmony_ciearly_param("stress_hpt", parse_stress_hpt);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci__ro_after_init DEFINE_STATIC_KEY_FALSE(stress_hpt_key);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci/*
49562306a36Sopenharmony_ci * per-CPU array allocated if we enable stress_hpt.
49662306a36Sopenharmony_ci */
49762306a36Sopenharmony_ci#define STRESS_MAX_GROUPS 16
49862306a36Sopenharmony_cistruct stress_hpt_struct {
49962306a36Sopenharmony_ci	unsigned long last_group[STRESS_MAX_GROUPS];
50062306a36Sopenharmony_ci};
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_cistatic inline int stress_nr_groups(void)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	/*
50562306a36Sopenharmony_ci	 * LPAR H_REMOVE flushes TLB, so need some number > 1 of entries
50662306a36Sopenharmony_ci	 * to allow practical forward progress. Bare metal returns 1, which
50762306a36Sopenharmony_ci	 * seems to help uncover more bugs.
50862306a36Sopenharmony_ci	 */
50962306a36Sopenharmony_ci	if (firmware_has_feature(FW_FEATURE_LPAR))
51062306a36Sopenharmony_ci		return STRESS_MAX_GROUPS;
51162306a36Sopenharmony_ci	else
51262306a36Sopenharmony_ci		return 1;
51362306a36Sopenharmony_ci}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_cistatic struct stress_hpt_struct *stress_hpt_struct;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cistatic int __init htab_dt_scan_seg_sizes(unsigned long node,
51862306a36Sopenharmony_ci					 const char *uname, int depth,
51962306a36Sopenharmony_ci					 void *data)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
52262306a36Sopenharmony_ci	const __be32 *prop;
52362306a36Sopenharmony_ci	int size = 0;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	/* We are scanning "cpu" nodes only */
52662306a36Sopenharmony_ci	if (type == NULL || strcmp(type, "cpu") != 0)
52762306a36Sopenharmony_ci		return 0;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	prop = of_get_flat_dt_prop(node, "ibm,processor-segment-sizes", &size);
53062306a36Sopenharmony_ci	if (prop == NULL)
53162306a36Sopenharmony_ci		return 0;
53262306a36Sopenharmony_ci	for (; size >= 4; size -= 4, ++prop) {
53362306a36Sopenharmony_ci		if (be32_to_cpu(prop[0]) == 40) {
53462306a36Sopenharmony_ci			DBG("1T segment support detected\n");
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci			if (disable_1tb_segments) {
53762306a36Sopenharmony_ci				DBG("1T segments disabled by command line\n");
53862306a36Sopenharmony_ci				break;
53962306a36Sopenharmony_ci			}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci			cur_cpu_spec->mmu_features |= MMU_FTR_1T_SEGMENT;
54262306a36Sopenharmony_ci			return 1;
54362306a36Sopenharmony_ci		}
54462306a36Sopenharmony_ci	}
54562306a36Sopenharmony_ci	cur_cpu_spec->mmu_features &= ~MMU_FTR_NO_SLBIE_B;
54662306a36Sopenharmony_ci	return 0;
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_cistatic int __init get_idx_from_shift(unsigned int shift)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	int idx = -1;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	switch (shift) {
55462306a36Sopenharmony_ci	case 0xc:
55562306a36Sopenharmony_ci		idx = MMU_PAGE_4K;
55662306a36Sopenharmony_ci		break;
55762306a36Sopenharmony_ci	case 0x10:
55862306a36Sopenharmony_ci		idx = MMU_PAGE_64K;
55962306a36Sopenharmony_ci		break;
56062306a36Sopenharmony_ci	case 0x14:
56162306a36Sopenharmony_ci		idx = MMU_PAGE_1M;
56262306a36Sopenharmony_ci		break;
56362306a36Sopenharmony_ci	case 0x18:
56462306a36Sopenharmony_ci		idx = MMU_PAGE_16M;
56562306a36Sopenharmony_ci		break;
56662306a36Sopenharmony_ci	case 0x22:
56762306a36Sopenharmony_ci		idx = MMU_PAGE_16G;
56862306a36Sopenharmony_ci		break;
56962306a36Sopenharmony_ci	}
57062306a36Sopenharmony_ci	return idx;
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic int __init htab_dt_scan_page_sizes(unsigned long node,
57462306a36Sopenharmony_ci					  const char *uname, int depth,
57562306a36Sopenharmony_ci					  void *data)
57662306a36Sopenharmony_ci{
57762306a36Sopenharmony_ci	const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
57862306a36Sopenharmony_ci	const __be32 *prop;
57962306a36Sopenharmony_ci	int size = 0;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	/* We are scanning "cpu" nodes only */
58262306a36Sopenharmony_ci	if (type == NULL || strcmp(type, "cpu") != 0)
58362306a36Sopenharmony_ci		return 0;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	prop = of_get_flat_dt_prop(node, "ibm,segment-page-sizes", &size);
58662306a36Sopenharmony_ci	if (!prop)
58762306a36Sopenharmony_ci		return 0;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	pr_info("Page sizes from device-tree:\n");
59062306a36Sopenharmony_ci	size /= 4;
59162306a36Sopenharmony_ci	cur_cpu_spec->mmu_features &= ~(MMU_FTR_16M_PAGE);
59262306a36Sopenharmony_ci	while(size > 0) {
59362306a36Sopenharmony_ci		unsigned int base_shift = be32_to_cpu(prop[0]);
59462306a36Sopenharmony_ci		unsigned int slbenc = be32_to_cpu(prop[1]);
59562306a36Sopenharmony_ci		unsigned int lpnum = be32_to_cpu(prop[2]);
59662306a36Sopenharmony_ci		struct mmu_psize_def *def;
59762306a36Sopenharmony_ci		int idx, base_idx;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci		size -= 3; prop += 3;
60062306a36Sopenharmony_ci		base_idx = get_idx_from_shift(base_shift);
60162306a36Sopenharmony_ci		if (base_idx < 0) {
60262306a36Sopenharmony_ci			/* skip the pte encoding also */
60362306a36Sopenharmony_ci			prop += lpnum * 2; size -= lpnum * 2;
60462306a36Sopenharmony_ci			continue;
60562306a36Sopenharmony_ci		}
60662306a36Sopenharmony_ci		def = &mmu_psize_defs[base_idx];
60762306a36Sopenharmony_ci		if (base_idx == MMU_PAGE_16M)
60862306a36Sopenharmony_ci			cur_cpu_spec->mmu_features |= MMU_FTR_16M_PAGE;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci		def->shift = base_shift;
61162306a36Sopenharmony_ci		if (base_shift <= 23)
61262306a36Sopenharmony_ci			def->avpnm = 0;
61362306a36Sopenharmony_ci		else
61462306a36Sopenharmony_ci			def->avpnm = (1 << (base_shift - 23)) - 1;
61562306a36Sopenharmony_ci		def->sllp = slbenc;
61662306a36Sopenharmony_ci		/*
61762306a36Sopenharmony_ci		 * We don't know for sure what's up with tlbiel, so
61862306a36Sopenharmony_ci		 * for now we only set it for 4K and 64K pages
61962306a36Sopenharmony_ci		 */
62062306a36Sopenharmony_ci		if (base_idx == MMU_PAGE_4K || base_idx == MMU_PAGE_64K)
62162306a36Sopenharmony_ci			def->tlbiel = 1;
62262306a36Sopenharmony_ci		else
62362306a36Sopenharmony_ci			def->tlbiel = 0;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci		while (size > 0 && lpnum) {
62662306a36Sopenharmony_ci			unsigned int shift = be32_to_cpu(prop[0]);
62762306a36Sopenharmony_ci			int penc  = be32_to_cpu(prop[1]);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci			prop += 2; size -= 2;
63062306a36Sopenharmony_ci			lpnum--;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci			idx = get_idx_from_shift(shift);
63362306a36Sopenharmony_ci			if (idx < 0)
63462306a36Sopenharmony_ci				continue;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci			if (penc == -1)
63762306a36Sopenharmony_ci				pr_err("Invalid penc for base_shift=%d "
63862306a36Sopenharmony_ci				       "shift=%d\n", base_shift, shift);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci			def->penc[idx] = penc;
64162306a36Sopenharmony_ci			pr_info("base_shift=%d: shift=%d, sllp=0x%04lx,"
64262306a36Sopenharmony_ci				" avpnm=0x%08lx, tlbiel=%d, penc=%d\n",
64362306a36Sopenharmony_ci				base_shift, shift, def->sllp,
64462306a36Sopenharmony_ci				def->avpnm, def->tlbiel, def->penc[idx]);
64562306a36Sopenharmony_ci		}
64662306a36Sopenharmony_ci	}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	return 1;
64962306a36Sopenharmony_ci}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci#ifdef CONFIG_HUGETLB_PAGE
65262306a36Sopenharmony_ci/*
65362306a36Sopenharmony_ci * Scan for 16G memory blocks that have been set aside for huge pages
65462306a36Sopenharmony_ci * and reserve those blocks for 16G huge pages.
65562306a36Sopenharmony_ci */
65662306a36Sopenharmony_cistatic int __init htab_dt_scan_hugepage_blocks(unsigned long node,
65762306a36Sopenharmony_ci					const char *uname, int depth,
65862306a36Sopenharmony_ci					void *data) {
65962306a36Sopenharmony_ci	const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
66062306a36Sopenharmony_ci	const __be64 *addr_prop;
66162306a36Sopenharmony_ci	const __be32 *page_count_prop;
66262306a36Sopenharmony_ci	unsigned int expected_pages;
66362306a36Sopenharmony_ci	long unsigned int phys_addr;
66462306a36Sopenharmony_ci	long unsigned int block_size;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	/* We are scanning "memory" nodes only */
66762306a36Sopenharmony_ci	if (type == NULL || strcmp(type, "memory") != 0)
66862306a36Sopenharmony_ci		return 0;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	/*
67162306a36Sopenharmony_ci	 * This property is the log base 2 of the number of virtual pages that
67262306a36Sopenharmony_ci	 * will represent this memory block.
67362306a36Sopenharmony_ci	 */
67462306a36Sopenharmony_ci	page_count_prop = of_get_flat_dt_prop(node, "ibm,expected#pages", NULL);
67562306a36Sopenharmony_ci	if (page_count_prop == NULL)
67662306a36Sopenharmony_ci		return 0;
67762306a36Sopenharmony_ci	expected_pages = (1 << be32_to_cpu(page_count_prop[0]));
67862306a36Sopenharmony_ci	addr_prop = of_get_flat_dt_prop(node, "reg", NULL);
67962306a36Sopenharmony_ci	if (addr_prop == NULL)
68062306a36Sopenharmony_ci		return 0;
68162306a36Sopenharmony_ci	phys_addr = be64_to_cpu(addr_prop[0]);
68262306a36Sopenharmony_ci	block_size = be64_to_cpu(addr_prop[1]);
68362306a36Sopenharmony_ci	if (block_size != (16 * GB))
68462306a36Sopenharmony_ci		return 0;
68562306a36Sopenharmony_ci	printk(KERN_INFO "Huge page(16GB) memory: "
68662306a36Sopenharmony_ci			"addr = 0x%lX size = 0x%lX pages = %d\n",
68762306a36Sopenharmony_ci			phys_addr, block_size, expected_pages);
68862306a36Sopenharmony_ci	if (phys_addr + block_size * expected_pages <= memblock_end_of_DRAM()) {
68962306a36Sopenharmony_ci		memblock_reserve(phys_addr, block_size * expected_pages);
69062306a36Sopenharmony_ci		pseries_add_gpage(phys_addr, block_size, expected_pages);
69162306a36Sopenharmony_ci	}
69262306a36Sopenharmony_ci	return 0;
69362306a36Sopenharmony_ci}
69462306a36Sopenharmony_ci#endif /* CONFIG_HUGETLB_PAGE */
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_cistatic void __init mmu_psize_set_default_penc(void)
69762306a36Sopenharmony_ci{
69862306a36Sopenharmony_ci	int bpsize, apsize;
69962306a36Sopenharmony_ci	for (bpsize = 0; bpsize < MMU_PAGE_COUNT; bpsize++)
70062306a36Sopenharmony_ci		for (apsize = 0; apsize < MMU_PAGE_COUNT; apsize++)
70162306a36Sopenharmony_ci			mmu_psize_defs[bpsize].penc[apsize] = -1;
70262306a36Sopenharmony_ci}
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_cistatic bool __init might_have_hea(void)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	/*
70962306a36Sopenharmony_ci	 * The HEA ethernet adapter requires awareness of the
71062306a36Sopenharmony_ci	 * GX bus. Without that awareness we can easily assume
71162306a36Sopenharmony_ci	 * we will never see an HEA ethernet device.
71262306a36Sopenharmony_ci	 */
71362306a36Sopenharmony_ci#ifdef CONFIG_IBMEBUS
71462306a36Sopenharmony_ci	return !cpu_has_feature(CPU_FTR_ARCH_207S) &&
71562306a36Sopenharmony_ci		firmware_has_feature(FW_FEATURE_SPLPAR);
71662306a36Sopenharmony_ci#else
71762306a36Sopenharmony_ci	return false;
71862306a36Sopenharmony_ci#endif
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci#endif /* #ifdef CONFIG_PPC_64K_PAGES */
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_cistatic void __init htab_scan_page_sizes(void)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	int rc;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	/* se the invalid penc to -1 */
72862306a36Sopenharmony_ci	mmu_psize_set_default_penc();
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	/* Default to 4K pages only */
73162306a36Sopenharmony_ci	memcpy(mmu_psize_defs, mmu_psize_defaults,
73262306a36Sopenharmony_ci	       sizeof(mmu_psize_defaults));
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	/*
73562306a36Sopenharmony_ci	 * Try to find the available page sizes in the device-tree
73662306a36Sopenharmony_ci	 */
73762306a36Sopenharmony_ci	rc = of_scan_flat_dt(htab_dt_scan_page_sizes, NULL);
73862306a36Sopenharmony_ci	if (rc == 0 && early_mmu_has_feature(MMU_FTR_16M_PAGE)) {
73962306a36Sopenharmony_ci		/*
74062306a36Sopenharmony_ci		 * Nothing in the device-tree, but the CPU supports 16M pages,
74162306a36Sopenharmony_ci		 * so let's fallback on a known size list for 16M capable CPUs.
74262306a36Sopenharmony_ci		 */
74362306a36Sopenharmony_ci		memcpy(mmu_psize_defs, mmu_psize_defaults_gp,
74462306a36Sopenharmony_ci		       sizeof(mmu_psize_defaults_gp));
74562306a36Sopenharmony_ci	}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci#ifdef CONFIG_HUGETLB_PAGE
74862306a36Sopenharmony_ci	if (!hugetlb_disabled && !early_radix_enabled() ) {
74962306a36Sopenharmony_ci		/* Reserve 16G huge page memory sections for huge pages */
75062306a36Sopenharmony_ci		of_scan_flat_dt(htab_dt_scan_hugepage_blocks, NULL);
75162306a36Sopenharmony_ci	}
75262306a36Sopenharmony_ci#endif /* CONFIG_HUGETLB_PAGE */
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci/*
75662306a36Sopenharmony_ci * Fill in the hpte_page_sizes[] array.
75762306a36Sopenharmony_ci * We go through the mmu_psize_defs[] array looking for all the
75862306a36Sopenharmony_ci * supported base/actual page size combinations.  Each combination
75962306a36Sopenharmony_ci * has a unique pagesize encoding (penc) value in the low bits of
76062306a36Sopenharmony_ci * the LP field of the HPTE.  For actual page sizes less than 1MB,
76162306a36Sopenharmony_ci * some of the upper LP bits are used for RPN bits, meaning that
76262306a36Sopenharmony_ci * we need to fill in several entries in hpte_page_sizes[].
76362306a36Sopenharmony_ci *
76462306a36Sopenharmony_ci * In diagrammatic form, with r = RPN bits and z = page size bits:
76562306a36Sopenharmony_ci *        PTE LP     actual page size
76662306a36Sopenharmony_ci *    rrrr rrrz		>=8KB
76762306a36Sopenharmony_ci *    rrrr rrzz		>=16KB
76862306a36Sopenharmony_ci *    rrrr rzzz		>=32KB
76962306a36Sopenharmony_ci *    rrrr zzzz		>=64KB
77062306a36Sopenharmony_ci *    ...
77162306a36Sopenharmony_ci *
77262306a36Sopenharmony_ci * The zzzz bits are implementation-specific but are chosen so that
77362306a36Sopenharmony_ci * no encoding for a larger page size uses the same value in its
77462306a36Sopenharmony_ci * low-order N bits as the encoding for the 2^(12+N) byte page size
77562306a36Sopenharmony_ci * (if it exists).
77662306a36Sopenharmony_ci */
77762306a36Sopenharmony_cistatic void __init init_hpte_page_sizes(void)
77862306a36Sopenharmony_ci{
77962306a36Sopenharmony_ci	long int ap, bp;
78062306a36Sopenharmony_ci	long int shift, penc;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	for (bp = 0; bp < MMU_PAGE_COUNT; ++bp) {
78362306a36Sopenharmony_ci		if (!mmu_psize_defs[bp].shift)
78462306a36Sopenharmony_ci			continue;	/* not a supported page size */
78562306a36Sopenharmony_ci		for (ap = bp; ap < MMU_PAGE_COUNT; ++ap) {
78662306a36Sopenharmony_ci			penc = mmu_psize_defs[bp].penc[ap];
78762306a36Sopenharmony_ci			if (penc == -1 || !mmu_psize_defs[ap].shift)
78862306a36Sopenharmony_ci				continue;
78962306a36Sopenharmony_ci			shift = mmu_psize_defs[ap].shift - LP_SHIFT;
79062306a36Sopenharmony_ci			if (shift <= 0)
79162306a36Sopenharmony_ci				continue;	/* should never happen */
79262306a36Sopenharmony_ci			/*
79362306a36Sopenharmony_ci			 * For page sizes less than 1MB, this loop
79462306a36Sopenharmony_ci			 * replicates the entry for all possible values
79562306a36Sopenharmony_ci			 * of the rrrr bits.
79662306a36Sopenharmony_ci			 */
79762306a36Sopenharmony_ci			while (penc < (1 << LP_BITS)) {
79862306a36Sopenharmony_ci				hpte_page_sizes[penc] = (ap << 4) | bp;
79962306a36Sopenharmony_ci				penc += 1 << shift;
80062306a36Sopenharmony_ci			}
80162306a36Sopenharmony_ci		}
80262306a36Sopenharmony_ci	}
80362306a36Sopenharmony_ci}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_cistatic void __init htab_init_page_sizes(void)
80662306a36Sopenharmony_ci{
80762306a36Sopenharmony_ci	bool aligned = true;
80862306a36Sopenharmony_ci	init_hpte_page_sizes();
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	if (!debug_pagealloc_enabled_or_kfence()) {
81162306a36Sopenharmony_ci		/*
81262306a36Sopenharmony_ci		 * Pick a size for the linear mapping. Currently, we only
81362306a36Sopenharmony_ci		 * support 16M, 1M and 4K which is the default
81462306a36Sopenharmony_ci		 */
81562306a36Sopenharmony_ci		if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX) &&
81662306a36Sopenharmony_ci		    (unsigned long)_stext % 0x1000000) {
81762306a36Sopenharmony_ci			if (mmu_psize_defs[MMU_PAGE_16M].shift)
81862306a36Sopenharmony_ci				pr_warn("Kernel not 16M aligned, disabling 16M linear map alignment\n");
81962306a36Sopenharmony_ci			aligned = false;
82062306a36Sopenharmony_ci		}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci		if (mmu_psize_defs[MMU_PAGE_16M].shift && aligned)
82362306a36Sopenharmony_ci			mmu_linear_psize = MMU_PAGE_16M;
82462306a36Sopenharmony_ci		else if (mmu_psize_defs[MMU_PAGE_1M].shift)
82562306a36Sopenharmony_ci			mmu_linear_psize = MMU_PAGE_1M;
82662306a36Sopenharmony_ci	}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES
82962306a36Sopenharmony_ci	/*
83062306a36Sopenharmony_ci	 * Pick a size for the ordinary pages. Default is 4K, we support
83162306a36Sopenharmony_ci	 * 64K for user mappings and vmalloc if supported by the processor.
83262306a36Sopenharmony_ci	 * We only use 64k for ioremap if the processor
83362306a36Sopenharmony_ci	 * (and firmware) support cache-inhibited large pages.
83462306a36Sopenharmony_ci	 * If not, we use 4k and set mmu_ci_restrictions so that
83562306a36Sopenharmony_ci	 * hash_page knows to switch processes that use cache-inhibited
83662306a36Sopenharmony_ci	 * mappings to 4k pages.
83762306a36Sopenharmony_ci	 */
83862306a36Sopenharmony_ci	if (mmu_psize_defs[MMU_PAGE_64K].shift) {
83962306a36Sopenharmony_ci		mmu_virtual_psize = MMU_PAGE_64K;
84062306a36Sopenharmony_ci		mmu_vmalloc_psize = MMU_PAGE_64K;
84162306a36Sopenharmony_ci		if (mmu_linear_psize == MMU_PAGE_4K)
84262306a36Sopenharmony_ci			mmu_linear_psize = MMU_PAGE_64K;
84362306a36Sopenharmony_ci		if (mmu_has_feature(MMU_FTR_CI_LARGE_PAGE)) {
84462306a36Sopenharmony_ci			/*
84562306a36Sopenharmony_ci			 * When running on pSeries using 64k pages for ioremap
84662306a36Sopenharmony_ci			 * would stop us accessing the HEA ethernet. So if we
84762306a36Sopenharmony_ci			 * have the chance of ever seeing one, stay at 4k.
84862306a36Sopenharmony_ci			 */
84962306a36Sopenharmony_ci			if (!might_have_hea())
85062306a36Sopenharmony_ci				mmu_io_psize = MMU_PAGE_64K;
85162306a36Sopenharmony_ci		} else
85262306a36Sopenharmony_ci			mmu_ci_restrictions = 1;
85362306a36Sopenharmony_ci	}
85462306a36Sopenharmony_ci#endif /* CONFIG_PPC_64K_PAGES */
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci#ifdef CONFIG_SPARSEMEM_VMEMMAP
85762306a36Sopenharmony_ci	/*
85862306a36Sopenharmony_ci	 * We try to use 16M pages for vmemmap if that is supported
85962306a36Sopenharmony_ci	 * and we have at least 1G of RAM at boot
86062306a36Sopenharmony_ci	 */
86162306a36Sopenharmony_ci	if (mmu_psize_defs[MMU_PAGE_16M].shift &&
86262306a36Sopenharmony_ci	    memblock_phys_mem_size() >= 0x40000000)
86362306a36Sopenharmony_ci		mmu_vmemmap_psize = MMU_PAGE_16M;
86462306a36Sopenharmony_ci	else
86562306a36Sopenharmony_ci		mmu_vmemmap_psize = mmu_virtual_psize;
86662306a36Sopenharmony_ci#endif /* CONFIG_SPARSEMEM_VMEMMAP */
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	printk(KERN_DEBUG "Page orders: linear mapping = %d, "
86962306a36Sopenharmony_ci	       "virtual = %d, io = %d"
87062306a36Sopenharmony_ci#ifdef CONFIG_SPARSEMEM_VMEMMAP
87162306a36Sopenharmony_ci	       ", vmemmap = %d"
87262306a36Sopenharmony_ci#endif
87362306a36Sopenharmony_ci	       "\n",
87462306a36Sopenharmony_ci	       mmu_psize_defs[mmu_linear_psize].shift,
87562306a36Sopenharmony_ci	       mmu_psize_defs[mmu_virtual_psize].shift,
87662306a36Sopenharmony_ci	       mmu_psize_defs[mmu_io_psize].shift
87762306a36Sopenharmony_ci#ifdef CONFIG_SPARSEMEM_VMEMMAP
87862306a36Sopenharmony_ci	       ,mmu_psize_defs[mmu_vmemmap_psize].shift
87962306a36Sopenharmony_ci#endif
88062306a36Sopenharmony_ci	       );
88162306a36Sopenharmony_ci}
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_cistatic int __init htab_dt_scan_pftsize(unsigned long node,
88462306a36Sopenharmony_ci				       const char *uname, int depth,
88562306a36Sopenharmony_ci				       void *data)
88662306a36Sopenharmony_ci{
88762306a36Sopenharmony_ci	const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
88862306a36Sopenharmony_ci	const __be32 *prop;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	/* We are scanning "cpu" nodes only */
89162306a36Sopenharmony_ci	if (type == NULL || strcmp(type, "cpu") != 0)
89262306a36Sopenharmony_ci		return 0;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	prop = of_get_flat_dt_prop(node, "ibm,pft-size", NULL);
89562306a36Sopenharmony_ci	if (prop != NULL) {
89662306a36Sopenharmony_ci		/* pft_size[0] is the NUMA CEC cookie */
89762306a36Sopenharmony_ci		ppc64_pft_size = be32_to_cpu(prop[1]);
89862306a36Sopenharmony_ci		return 1;
89962306a36Sopenharmony_ci	}
90062306a36Sopenharmony_ci	return 0;
90162306a36Sopenharmony_ci}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ciunsigned htab_shift_for_mem_size(unsigned long mem_size)
90462306a36Sopenharmony_ci{
90562306a36Sopenharmony_ci	unsigned memshift = __ilog2(mem_size);
90662306a36Sopenharmony_ci	unsigned pshift = mmu_psize_defs[mmu_virtual_psize].shift;
90762306a36Sopenharmony_ci	unsigned pteg_shift;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	/* round mem_size up to next power of 2 */
91062306a36Sopenharmony_ci	if ((1UL << memshift) < mem_size)
91162306a36Sopenharmony_ci		memshift += 1;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	/* aim for 2 pages / pteg */
91462306a36Sopenharmony_ci	pteg_shift = memshift - (pshift + 1);
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	/*
91762306a36Sopenharmony_ci	 * 2^11 PTEGS of 128 bytes each, ie. 2^18 bytes is the minimum htab
91862306a36Sopenharmony_ci	 * size permitted by the architecture.
91962306a36Sopenharmony_ci	 */
92062306a36Sopenharmony_ci	return max(pteg_shift + 7, 18U);
92162306a36Sopenharmony_ci}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_cistatic unsigned long __init htab_get_table_size(void)
92462306a36Sopenharmony_ci{
92562306a36Sopenharmony_ci	/*
92662306a36Sopenharmony_ci	 * If hash size isn't already provided by the platform, we try to
92762306a36Sopenharmony_ci	 * retrieve it from the device-tree. If it's not there neither, we
92862306a36Sopenharmony_ci	 * calculate it now based on the total RAM size
92962306a36Sopenharmony_ci	 */
93062306a36Sopenharmony_ci	if (ppc64_pft_size == 0)
93162306a36Sopenharmony_ci		of_scan_flat_dt(htab_dt_scan_pftsize, NULL);
93262306a36Sopenharmony_ci	if (ppc64_pft_size)
93362306a36Sopenharmony_ci		return 1UL << ppc64_pft_size;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	return 1UL << htab_shift_for_mem_size(memblock_phys_mem_size());
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci#ifdef CONFIG_MEMORY_HOTPLUG
93962306a36Sopenharmony_cistatic int resize_hpt_for_hotplug(unsigned long new_mem_size)
94062306a36Sopenharmony_ci{
94162306a36Sopenharmony_ci	unsigned target_hpt_shift;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	if (!mmu_hash_ops.resize_hpt)
94462306a36Sopenharmony_ci		return 0;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	target_hpt_shift = htab_shift_for_mem_size(new_mem_size);
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	/*
94962306a36Sopenharmony_ci	 * To avoid lots of HPT resizes if memory size is fluctuating
95062306a36Sopenharmony_ci	 * across a boundary, we deliberately have some hysterisis
95162306a36Sopenharmony_ci	 * here: we immediately increase the HPT size if the target
95262306a36Sopenharmony_ci	 * shift exceeds the current shift, but we won't attempt to
95362306a36Sopenharmony_ci	 * reduce unless the target shift is at least 2 below the
95462306a36Sopenharmony_ci	 * current shift
95562306a36Sopenharmony_ci	 */
95662306a36Sopenharmony_ci	if (target_hpt_shift > ppc64_pft_size ||
95762306a36Sopenharmony_ci	    target_hpt_shift < ppc64_pft_size - 1)
95862306a36Sopenharmony_ci		return mmu_hash_ops.resize_hpt(target_hpt_shift);
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	return 0;
96162306a36Sopenharmony_ci}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ciint hash__create_section_mapping(unsigned long start, unsigned long end,
96462306a36Sopenharmony_ci				 int nid, pgprot_t prot)
96562306a36Sopenharmony_ci{
96662306a36Sopenharmony_ci	int rc;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	if (end >= H_VMALLOC_START) {
96962306a36Sopenharmony_ci		pr_warn("Outside the supported range\n");
97062306a36Sopenharmony_ci		return -1;
97162306a36Sopenharmony_ci	}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	resize_hpt_for_hotplug(memblock_phys_mem_size());
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	rc = htab_bolt_mapping(start, end, __pa(start),
97662306a36Sopenharmony_ci			       pgprot_val(prot), mmu_linear_psize,
97762306a36Sopenharmony_ci			       mmu_kernel_ssize);
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	if (rc < 0) {
98062306a36Sopenharmony_ci		int rc2 = htab_remove_mapping(start, end, mmu_linear_psize,
98162306a36Sopenharmony_ci					      mmu_kernel_ssize);
98262306a36Sopenharmony_ci		BUG_ON(rc2 && (rc2 != -ENOENT));
98362306a36Sopenharmony_ci	}
98462306a36Sopenharmony_ci	return rc;
98562306a36Sopenharmony_ci}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ciint hash__remove_section_mapping(unsigned long start, unsigned long end)
98862306a36Sopenharmony_ci{
98962306a36Sopenharmony_ci	int rc = htab_remove_mapping(start, end, mmu_linear_psize,
99062306a36Sopenharmony_ci				     mmu_kernel_ssize);
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	if (resize_hpt_for_hotplug(memblock_phys_mem_size()) == -ENOSPC)
99362306a36Sopenharmony_ci		pr_warn("Hash collision while resizing HPT\n");
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	return rc;
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci#endif /* CONFIG_MEMORY_HOTPLUG */
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_cistatic void __init hash_init_partition_table(phys_addr_t hash_table,
100062306a36Sopenharmony_ci					     unsigned long htab_size)
100162306a36Sopenharmony_ci{
100262306a36Sopenharmony_ci	mmu_partition_table_init();
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	/*
100562306a36Sopenharmony_ci	 * PS field (VRMA page size) is not used for LPID 0, hence set to 0.
100662306a36Sopenharmony_ci	 * For now, UPRT is 0 and we have no segment table.
100762306a36Sopenharmony_ci	 */
100862306a36Sopenharmony_ci	htab_size =  __ilog2(htab_size) - 18;
100962306a36Sopenharmony_ci	mmu_partition_table_set_entry(0, hash_table | htab_size, 0, false);
101062306a36Sopenharmony_ci	pr_info("Partition table %p\n", partition_tb);
101162306a36Sopenharmony_ci}
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_civoid hpt_clear_stress(void);
101462306a36Sopenharmony_cistatic struct timer_list stress_hpt_timer;
101562306a36Sopenharmony_cistatic void stress_hpt_timer_fn(struct timer_list *timer)
101662306a36Sopenharmony_ci{
101762306a36Sopenharmony_ci	int next_cpu;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	hpt_clear_stress();
102062306a36Sopenharmony_ci	if (!firmware_has_feature(FW_FEATURE_LPAR))
102162306a36Sopenharmony_ci		tlbiel_all();
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	next_cpu = cpumask_next(raw_smp_processor_id(), cpu_online_mask);
102462306a36Sopenharmony_ci	if (next_cpu >= nr_cpu_ids)
102562306a36Sopenharmony_ci		next_cpu = cpumask_first(cpu_online_mask);
102662306a36Sopenharmony_ci	stress_hpt_timer.expires = jiffies + msecs_to_jiffies(10);
102762306a36Sopenharmony_ci	add_timer_on(&stress_hpt_timer, next_cpu);
102862306a36Sopenharmony_ci}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_cistatic void __init htab_initialize(void)
103162306a36Sopenharmony_ci{
103262306a36Sopenharmony_ci	unsigned long table;
103362306a36Sopenharmony_ci	unsigned long pteg_count;
103462306a36Sopenharmony_ci	unsigned long prot;
103562306a36Sopenharmony_ci	phys_addr_t base = 0, size = 0, end;
103662306a36Sopenharmony_ci	u64 i;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	DBG(" -> htab_initialize()\n");
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) {
104162306a36Sopenharmony_ci		mmu_kernel_ssize = MMU_SEGSIZE_1T;
104262306a36Sopenharmony_ci		mmu_highuser_ssize = MMU_SEGSIZE_1T;
104362306a36Sopenharmony_ci		printk(KERN_INFO "Using 1TB segments\n");
104462306a36Sopenharmony_ci	}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	if (stress_slb_enabled)
104762306a36Sopenharmony_ci		static_branch_enable(&stress_slb_key);
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	if (stress_hpt_enabled) {
105062306a36Sopenharmony_ci		unsigned long tmp;
105162306a36Sopenharmony_ci		static_branch_enable(&stress_hpt_key);
105262306a36Sopenharmony_ci		// Too early to use nr_cpu_ids, so use NR_CPUS
105362306a36Sopenharmony_ci		tmp = memblock_phys_alloc_range(sizeof(struct stress_hpt_struct) * NR_CPUS,
105462306a36Sopenharmony_ci						__alignof__(struct stress_hpt_struct),
105562306a36Sopenharmony_ci						0, MEMBLOCK_ALLOC_ANYWHERE);
105662306a36Sopenharmony_ci		memset((void *)tmp, 0xff, sizeof(struct stress_hpt_struct) * NR_CPUS);
105762306a36Sopenharmony_ci		stress_hpt_struct = __va(tmp);
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci		timer_setup(&stress_hpt_timer, stress_hpt_timer_fn, 0);
106062306a36Sopenharmony_ci		stress_hpt_timer.expires = jiffies + msecs_to_jiffies(10);
106162306a36Sopenharmony_ci		add_timer(&stress_hpt_timer);
106262306a36Sopenharmony_ci	}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	/*
106562306a36Sopenharmony_ci	 * Calculate the required size of the htab.  We want the number of
106662306a36Sopenharmony_ci	 * PTEGs to equal one half the number of real pages.
106762306a36Sopenharmony_ci	 */
106862306a36Sopenharmony_ci	htab_size_bytes = htab_get_table_size();
106962306a36Sopenharmony_ci	pteg_count = htab_size_bytes >> 7;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	htab_hash_mask = pteg_count - 1;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	if (firmware_has_feature(FW_FEATURE_LPAR) ||
107462306a36Sopenharmony_ci	    firmware_has_feature(FW_FEATURE_PS3_LV1)) {
107562306a36Sopenharmony_ci		/* Using a hypervisor which owns the htab */
107662306a36Sopenharmony_ci		htab_address = NULL;
107762306a36Sopenharmony_ci		_SDR1 = 0;
107862306a36Sopenharmony_ci#ifdef CONFIG_FA_DUMP
107962306a36Sopenharmony_ci		/*
108062306a36Sopenharmony_ci		 * If firmware assisted dump is active firmware preserves
108162306a36Sopenharmony_ci		 * the contents of htab along with entire partition memory.
108262306a36Sopenharmony_ci		 * Clear the htab if firmware assisted dump is active so
108362306a36Sopenharmony_ci		 * that we dont end up using old mappings.
108462306a36Sopenharmony_ci		 */
108562306a36Sopenharmony_ci		if (is_fadump_active() && mmu_hash_ops.hpte_clear_all)
108662306a36Sopenharmony_ci			mmu_hash_ops.hpte_clear_all();
108762306a36Sopenharmony_ci#endif
108862306a36Sopenharmony_ci	} else {
108962306a36Sopenharmony_ci		unsigned long limit = MEMBLOCK_ALLOC_ANYWHERE;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci#ifdef CONFIG_PPC_CELL
109262306a36Sopenharmony_ci		/*
109362306a36Sopenharmony_ci		 * Cell may require the hash table down low when using the
109462306a36Sopenharmony_ci		 * Axon IOMMU in order to fit the dynamic region over it, see
109562306a36Sopenharmony_ci		 * comments in cell/iommu.c
109662306a36Sopenharmony_ci		 */
109762306a36Sopenharmony_ci		if (fdt_subnode_offset(initial_boot_params, 0, "axon") > 0) {
109862306a36Sopenharmony_ci			limit = 0x80000000;
109962306a36Sopenharmony_ci			pr_info("Hash table forced below 2G for Axon IOMMU\n");
110062306a36Sopenharmony_ci		}
110162306a36Sopenharmony_ci#endif /* CONFIG_PPC_CELL */
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci		table = memblock_phys_alloc_range(htab_size_bytes,
110462306a36Sopenharmony_ci						  htab_size_bytes,
110562306a36Sopenharmony_ci						  0, limit);
110662306a36Sopenharmony_ci		if (!table)
110762306a36Sopenharmony_ci			panic("ERROR: Failed to allocate %pa bytes below %pa\n",
110862306a36Sopenharmony_ci			      &htab_size_bytes, &limit);
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci		DBG("Hash table allocated at %lx, size: %lx\n", table,
111162306a36Sopenharmony_ci		    htab_size_bytes);
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci		htab_address = __va(table);
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci		/* htab absolute addr + encoded htabsize */
111662306a36Sopenharmony_ci		_SDR1 = table + __ilog2(htab_size_bytes) - 18;
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci		/* Initialize the HPT with no entries */
111962306a36Sopenharmony_ci		memset((void *)table, 0, htab_size_bytes);
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci		if (!cpu_has_feature(CPU_FTR_ARCH_300))
112262306a36Sopenharmony_ci			/* Set SDR1 */
112362306a36Sopenharmony_ci			mtspr(SPRN_SDR1, _SDR1);
112462306a36Sopenharmony_ci		else
112562306a36Sopenharmony_ci			hash_init_partition_table(table, htab_size_bytes);
112662306a36Sopenharmony_ci	}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	prot = pgprot_val(PAGE_KERNEL);
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	if (debug_pagealloc_enabled_or_kfence()) {
113162306a36Sopenharmony_ci		linear_map_hash_count = memblock_end_of_DRAM() >> PAGE_SHIFT;
113262306a36Sopenharmony_ci		linear_map_hash_slots = memblock_alloc_try_nid(
113362306a36Sopenharmony_ci				linear_map_hash_count, 1, MEMBLOCK_LOW_LIMIT,
113462306a36Sopenharmony_ci				ppc64_rma_size,	NUMA_NO_NODE);
113562306a36Sopenharmony_ci		if (!linear_map_hash_slots)
113662306a36Sopenharmony_ci			panic("%s: Failed to allocate %lu bytes max_addr=%pa\n",
113762306a36Sopenharmony_ci			      __func__, linear_map_hash_count, &ppc64_rma_size);
113862306a36Sopenharmony_ci	}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	/* create bolted the linear mapping in the hash table */
114162306a36Sopenharmony_ci	for_each_mem_range(i, &base, &end) {
114262306a36Sopenharmony_ci		size = end - base;
114362306a36Sopenharmony_ci		base = (unsigned long)__va(base);
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci		DBG("creating mapping for region: %lx..%lx (prot: %lx)\n",
114662306a36Sopenharmony_ci		    base, size, prot);
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci		if ((base + size) >= H_VMALLOC_START) {
114962306a36Sopenharmony_ci			pr_warn("Outside the supported range\n");
115062306a36Sopenharmony_ci			continue;
115162306a36Sopenharmony_ci		}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci		BUG_ON(htab_bolt_mapping(base, base + size, __pa(base),
115462306a36Sopenharmony_ci				prot, mmu_linear_psize, mmu_kernel_ssize));
115562306a36Sopenharmony_ci	}
115662306a36Sopenharmony_ci	memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE);
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	/*
115962306a36Sopenharmony_ci	 * If we have a memory_limit and we've allocated TCEs then we need to
116062306a36Sopenharmony_ci	 * explicitly map the TCE area at the top of RAM. We also cope with the
116162306a36Sopenharmony_ci	 * case that the TCEs start below memory_limit.
116262306a36Sopenharmony_ci	 * tce_alloc_start/end are 16MB aligned so the mapping should work
116362306a36Sopenharmony_ci	 * for either 4K or 16MB pages.
116462306a36Sopenharmony_ci	 */
116562306a36Sopenharmony_ci	if (tce_alloc_start) {
116662306a36Sopenharmony_ci		tce_alloc_start = (unsigned long)__va(tce_alloc_start);
116762306a36Sopenharmony_ci		tce_alloc_end = (unsigned long)__va(tce_alloc_end);
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci		if (base + size >= tce_alloc_start)
117062306a36Sopenharmony_ci			tce_alloc_start = base + size + 1;
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci		BUG_ON(htab_bolt_mapping(tce_alloc_start, tce_alloc_end,
117362306a36Sopenharmony_ci					 __pa(tce_alloc_start), prot,
117462306a36Sopenharmony_ci					 mmu_linear_psize, mmu_kernel_ssize));
117562306a36Sopenharmony_ci	}
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	DBG(" <- htab_initialize()\n");
117962306a36Sopenharmony_ci}
118062306a36Sopenharmony_ci#undef KB
118162306a36Sopenharmony_ci#undef MB
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_civoid __init hash__early_init_devtree(void)
118462306a36Sopenharmony_ci{
118562306a36Sopenharmony_ci	/* Initialize segment sizes */
118662306a36Sopenharmony_ci	of_scan_flat_dt(htab_dt_scan_seg_sizes, NULL);
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	/* Initialize page sizes */
118962306a36Sopenharmony_ci	htab_scan_page_sizes();
119062306a36Sopenharmony_ci}
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_cistatic struct hash_mm_context init_hash_mm_context;
119362306a36Sopenharmony_civoid __init hash__early_init_mmu(void)
119462306a36Sopenharmony_ci{
119562306a36Sopenharmony_ci#ifndef CONFIG_PPC_64K_PAGES
119662306a36Sopenharmony_ci	/*
119762306a36Sopenharmony_ci	 * We have code in __hash_page_4K() and elsewhere, which assumes it can
119862306a36Sopenharmony_ci	 * do the following:
119962306a36Sopenharmony_ci	 *   new_pte |= (slot << H_PAGE_F_GIX_SHIFT) & (H_PAGE_F_SECOND | H_PAGE_F_GIX);
120062306a36Sopenharmony_ci	 *
120162306a36Sopenharmony_ci	 * Where the slot number is between 0-15, and values of 8-15 indicate
120262306a36Sopenharmony_ci	 * the secondary bucket. For that code to work H_PAGE_F_SECOND and
120362306a36Sopenharmony_ci	 * H_PAGE_F_GIX must occupy four contiguous bits in the PTE, and
120462306a36Sopenharmony_ci	 * H_PAGE_F_SECOND must be placed above H_PAGE_F_GIX. Assert that here
120562306a36Sopenharmony_ci	 * with a BUILD_BUG_ON().
120662306a36Sopenharmony_ci	 */
120762306a36Sopenharmony_ci	BUILD_BUG_ON(H_PAGE_F_SECOND != (1ul  << (H_PAGE_F_GIX_SHIFT + 3)));
120862306a36Sopenharmony_ci#endif /* CONFIG_PPC_64K_PAGES */
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	htab_init_page_sizes();
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	/*
121362306a36Sopenharmony_ci	 * initialize page table size
121462306a36Sopenharmony_ci	 */
121562306a36Sopenharmony_ci	__pte_frag_nr = H_PTE_FRAG_NR;
121662306a36Sopenharmony_ci	__pte_frag_size_shift = H_PTE_FRAG_SIZE_SHIFT;
121762306a36Sopenharmony_ci	__pmd_frag_nr = H_PMD_FRAG_NR;
121862306a36Sopenharmony_ci	__pmd_frag_size_shift = H_PMD_FRAG_SIZE_SHIFT;
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	__pte_index_size = H_PTE_INDEX_SIZE;
122162306a36Sopenharmony_ci	__pmd_index_size = H_PMD_INDEX_SIZE;
122262306a36Sopenharmony_ci	__pud_index_size = H_PUD_INDEX_SIZE;
122362306a36Sopenharmony_ci	__pgd_index_size = H_PGD_INDEX_SIZE;
122462306a36Sopenharmony_ci	__pud_cache_index = H_PUD_CACHE_INDEX;
122562306a36Sopenharmony_ci	__pte_table_size = H_PTE_TABLE_SIZE;
122662306a36Sopenharmony_ci	__pmd_table_size = H_PMD_TABLE_SIZE;
122762306a36Sopenharmony_ci	__pud_table_size = H_PUD_TABLE_SIZE;
122862306a36Sopenharmony_ci	__pgd_table_size = H_PGD_TABLE_SIZE;
122962306a36Sopenharmony_ci	/*
123062306a36Sopenharmony_ci	 * 4k use hugepd format, so for hash set then to
123162306a36Sopenharmony_ci	 * zero
123262306a36Sopenharmony_ci	 */
123362306a36Sopenharmony_ci	__pmd_val_bits = HASH_PMD_VAL_BITS;
123462306a36Sopenharmony_ci	__pud_val_bits = HASH_PUD_VAL_BITS;
123562306a36Sopenharmony_ci	__pgd_val_bits = HASH_PGD_VAL_BITS;
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	__kernel_virt_start = H_KERN_VIRT_START;
123862306a36Sopenharmony_ci	__vmalloc_start = H_VMALLOC_START;
123962306a36Sopenharmony_ci	__vmalloc_end = H_VMALLOC_END;
124062306a36Sopenharmony_ci	__kernel_io_start = H_KERN_IO_START;
124162306a36Sopenharmony_ci	__kernel_io_end = H_KERN_IO_END;
124262306a36Sopenharmony_ci	vmemmap = (struct page *)H_VMEMMAP_START;
124362306a36Sopenharmony_ci	ioremap_bot = IOREMAP_BASE;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci#ifdef CONFIG_PCI
124662306a36Sopenharmony_ci	pci_io_base = ISA_IO_BASE;
124762306a36Sopenharmony_ci#endif
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	/* Select appropriate backend */
125062306a36Sopenharmony_ci	if (firmware_has_feature(FW_FEATURE_PS3_LV1))
125162306a36Sopenharmony_ci		ps3_early_mm_init();
125262306a36Sopenharmony_ci	else if (firmware_has_feature(FW_FEATURE_LPAR))
125362306a36Sopenharmony_ci		hpte_init_pseries();
125462306a36Sopenharmony_ci	else if (IS_ENABLED(CONFIG_PPC_HASH_MMU_NATIVE))
125562306a36Sopenharmony_ci		hpte_init_native();
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	if (!mmu_hash_ops.hpte_insert)
125862306a36Sopenharmony_ci		panic("hash__early_init_mmu: No MMU hash ops defined!\n");
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	/*
126162306a36Sopenharmony_ci	 * Initialize the MMU Hash table and create the linear mapping
126262306a36Sopenharmony_ci	 * of memory. Has to be done before SLB initialization as this is
126362306a36Sopenharmony_ci	 * currently where the page size encoding is obtained.
126462306a36Sopenharmony_ci	 */
126562306a36Sopenharmony_ci	htab_initialize();
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	init_mm.context.hash_context = &init_hash_mm_context;
126862306a36Sopenharmony_ci	mm_ctx_set_slb_addr_limit(&init_mm.context, SLB_ADDR_LIMIT_DEFAULT);
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	pr_info("Initializing hash mmu with SLB\n");
127162306a36Sopenharmony_ci	/* Initialize SLB management */
127262306a36Sopenharmony_ci	slb_initialize();
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	if (cpu_has_feature(CPU_FTR_ARCH_206)
127562306a36Sopenharmony_ci			&& cpu_has_feature(CPU_FTR_HVMODE))
127662306a36Sopenharmony_ci		tlbiel_all();
127762306a36Sopenharmony_ci}
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci#ifdef CONFIG_SMP
128062306a36Sopenharmony_civoid hash__early_init_mmu_secondary(void)
128162306a36Sopenharmony_ci{
128262306a36Sopenharmony_ci	/* Initialize hash table for that CPU */
128362306a36Sopenharmony_ci	if (!firmware_has_feature(FW_FEATURE_LPAR)) {
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci		if (!cpu_has_feature(CPU_FTR_ARCH_300))
128662306a36Sopenharmony_ci			mtspr(SPRN_SDR1, _SDR1);
128762306a36Sopenharmony_ci		else
128862306a36Sopenharmony_ci			set_ptcr_when_no_uv(__pa(partition_tb) |
128962306a36Sopenharmony_ci					    (PATB_SIZE_SHIFT - 12));
129062306a36Sopenharmony_ci	}
129162306a36Sopenharmony_ci	/* Initialize SLB */
129262306a36Sopenharmony_ci	slb_initialize();
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	if (cpu_has_feature(CPU_FTR_ARCH_206)
129562306a36Sopenharmony_ci			&& cpu_has_feature(CPU_FTR_HVMODE))
129662306a36Sopenharmony_ci		tlbiel_all();
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci#ifdef CONFIG_PPC_MEM_KEYS
129962306a36Sopenharmony_ci	if (mmu_has_feature(MMU_FTR_PKEY))
130062306a36Sopenharmony_ci		mtspr(SPRN_UAMOR, default_uamor);
130162306a36Sopenharmony_ci#endif
130262306a36Sopenharmony_ci}
130362306a36Sopenharmony_ci#endif /* CONFIG_SMP */
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci/*
130662306a36Sopenharmony_ci * Called by asm hashtable.S for doing lazy icache flush
130762306a36Sopenharmony_ci */
130862306a36Sopenharmony_ciunsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap)
130962306a36Sopenharmony_ci{
131062306a36Sopenharmony_ci	struct folio *folio;
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	if (!pfn_valid(pte_pfn(pte)))
131362306a36Sopenharmony_ci		return pp;
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	folio = page_folio(pte_page(pte));
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	/* page is dirty */
131862306a36Sopenharmony_ci	if (!test_bit(PG_dcache_clean, &folio->flags) &&
131962306a36Sopenharmony_ci	    !folio_test_reserved(folio)) {
132062306a36Sopenharmony_ci		if (trap == INTERRUPT_INST_STORAGE) {
132162306a36Sopenharmony_ci			flush_dcache_icache_folio(folio);
132262306a36Sopenharmony_ci			set_bit(PG_dcache_clean, &folio->flags);
132362306a36Sopenharmony_ci		} else
132462306a36Sopenharmony_ci			pp |= HPTE_R_N;
132562306a36Sopenharmony_ci	}
132662306a36Sopenharmony_ci	return pp;
132762306a36Sopenharmony_ci}
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_cistatic unsigned int get_paca_psize(unsigned long addr)
133062306a36Sopenharmony_ci{
133162306a36Sopenharmony_ci	unsigned char *psizes;
133262306a36Sopenharmony_ci	unsigned long index, mask_index;
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	if (addr < SLICE_LOW_TOP) {
133562306a36Sopenharmony_ci		psizes = get_paca()->mm_ctx_low_slices_psize;
133662306a36Sopenharmony_ci		index = GET_LOW_SLICE_INDEX(addr);
133762306a36Sopenharmony_ci	} else {
133862306a36Sopenharmony_ci		psizes = get_paca()->mm_ctx_high_slices_psize;
133962306a36Sopenharmony_ci		index = GET_HIGH_SLICE_INDEX(addr);
134062306a36Sopenharmony_ci	}
134162306a36Sopenharmony_ci	mask_index = index & 0x1;
134262306a36Sopenharmony_ci	return (psizes[index >> 1] >> (mask_index * 4)) & 0xF;
134362306a36Sopenharmony_ci}
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci/*
134762306a36Sopenharmony_ci * Demote a segment to using 4k pages.
134862306a36Sopenharmony_ci * For now this makes the whole process use 4k pages.
134962306a36Sopenharmony_ci */
135062306a36Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES
135162306a36Sopenharmony_civoid demote_segment_4k(struct mm_struct *mm, unsigned long addr)
135262306a36Sopenharmony_ci{
135362306a36Sopenharmony_ci	if (get_slice_psize(mm, addr) == MMU_PAGE_4K)
135462306a36Sopenharmony_ci		return;
135562306a36Sopenharmony_ci	slice_set_range_psize(mm, addr, 1, MMU_PAGE_4K);
135662306a36Sopenharmony_ci	copro_flush_all_slbs(mm);
135762306a36Sopenharmony_ci	if ((get_paca_psize(addr) != MMU_PAGE_4K) && (current->mm == mm)) {
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci		copy_mm_to_paca(mm);
136062306a36Sopenharmony_ci		slb_flush_and_restore_bolted();
136162306a36Sopenharmony_ci	}
136262306a36Sopenharmony_ci}
136362306a36Sopenharmony_ci#endif /* CONFIG_PPC_64K_PAGES */
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci#ifdef CONFIG_PPC_SUBPAGE_PROT
136662306a36Sopenharmony_ci/*
136762306a36Sopenharmony_ci * This looks up a 2-bit protection code for a 4k subpage of a 64k page.
136862306a36Sopenharmony_ci * Userspace sets the subpage permissions using the subpage_prot system call.
136962306a36Sopenharmony_ci *
137062306a36Sopenharmony_ci * Result is 0: full permissions, _PAGE_RW: read-only,
137162306a36Sopenharmony_ci * _PAGE_RWX: no access.
137262306a36Sopenharmony_ci */
137362306a36Sopenharmony_cistatic int subpage_protection(struct mm_struct *mm, unsigned long ea)
137462306a36Sopenharmony_ci{
137562306a36Sopenharmony_ci	struct subpage_prot_table *spt = mm_ctx_subpage_prot(&mm->context);
137662306a36Sopenharmony_ci	u32 spp = 0;
137762306a36Sopenharmony_ci	u32 **sbpm, *sbpp;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	if (!spt)
138062306a36Sopenharmony_ci		return 0;
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	if (ea >= spt->maxaddr)
138362306a36Sopenharmony_ci		return 0;
138462306a36Sopenharmony_ci	if (ea < 0x100000000UL) {
138562306a36Sopenharmony_ci		/* addresses below 4GB use spt->low_prot */
138662306a36Sopenharmony_ci		sbpm = spt->low_prot;
138762306a36Sopenharmony_ci	} else {
138862306a36Sopenharmony_ci		sbpm = spt->protptrs[ea >> SBP_L3_SHIFT];
138962306a36Sopenharmony_ci		if (!sbpm)
139062306a36Sopenharmony_ci			return 0;
139162306a36Sopenharmony_ci	}
139262306a36Sopenharmony_ci	sbpp = sbpm[(ea >> SBP_L2_SHIFT) & (SBP_L2_COUNT - 1)];
139362306a36Sopenharmony_ci	if (!sbpp)
139462306a36Sopenharmony_ci		return 0;
139562306a36Sopenharmony_ci	spp = sbpp[(ea >> PAGE_SHIFT) & (SBP_L1_COUNT - 1)];
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	/* extract 2-bit bitfield for this 4k subpage */
139862306a36Sopenharmony_ci	spp >>= 30 - 2 * ((ea >> 12) & 0xf);
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	/*
140162306a36Sopenharmony_ci	 * 0 -> full permission
140262306a36Sopenharmony_ci	 * 1 -> Read only
140362306a36Sopenharmony_ci	 * 2 -> no access.
140462306a36Sopenharmony_ci	 * We return the flag that need to be cleared.
140562306a36Sopenharmony_ci	 */
140662306a36Sopenharmony_ci	spp = ((spp & 2) ? _PAGE_RWX : 0) | ((spp & 1) ? _PAGE_WRITE : 0);
140762306a36Sopenharmony_ci	return spp;
140862306a36Sopenharmony_ci}
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci#else /* CONFIG_PPC_SUBPAGE_PROT */
141162306a36Sopenharmony_cistatic inline int subpage_protection(struct mm_struct *mm, unsigned long ea)
141262306a36Sopenharmony_ci{
141362306a36Sopenharmony_ci	return 0;
141462306a36Sopenharmony_ci}
141562306a36Sopenharmony_ci#endif
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_civoid hash_failure_debug(unsigned long ea, unsigned long access,
141862306a36Sopenharmony_ci			unsigned long vsid, unsigned long trap,
141962306a36Sopenharmony_ci			int ssize, int psize, int lpsize, unsigned long pte)
142062306a36Sopenharmony_ci{
142162306a36Sopenharmony_ci	if (!printk_ratelimit())
142262306a36Sopenharmony_ci		return;
142362306a36Sopenharmony_ci	pr_info("mm: Hashing failure ! EA=0x%lx access=0x%lx current=%s\n",
142462306a36Sopenharmony_ci		ea, access, current->comm);
142562306a36Sopenharmony_ci	pr_info("    trap=0x%lx vsid=0x%lx ssize=%d base psize=%d psize %d pte=0x%lx\n",
142662306a36Sopenharmony_ci		trap, vsid, ssize, psize, lpsize, pte);
142762306a36Sopenharmony_ci}
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_cistatic void check_paca_psize(unsigned long ea, struct mm_struct *mm,
143062306a36Sopenharmony_ci			     int psize, bool user_region)
143162306a36Sopenharmony_ci{
143262306a36Sopenharmony_ci	if (user_region) {
143362306a36Sopenharmony_ci		if (psize != get_paca_psize(ea)) {
143462306a36Sopenharmony_ci			copy_mm_to_paca(mm);
143562306a36Sopenharmony_ci			slb_flush_and_restore_bolted();
143662306a36Sopenharmony_ci		}
143762306a36Sopenharmony_ci	} else if (get_paca()->vmalloc_sllp !=
143862306a36Sopenharmony_ci		   mmu_psize_defs[mmu_vmalloc_psize].sllp) {
143962306a36Sopenharmony_ci		get_paca()->vmalloc_sllp =
144062306a36Sopenharmony_ci			mmu_psize_defs[mmu_vmalloc_psize].sllp;
144162306a36Sopenharmony_ci		slb_vmalloc_update();
144262306a36Sopenharmony_ci	}
144362306a36Sopenharmony_ci}
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci/*
144662306a36Sopenharmony_ci * Result code is:
144762306a36Sopenharmony_ci *  0 - handled
144862306a36Sopenharmony_ci *  1 - normal page fault
144962306a36Sopenharmony_ci * -1 - critical hash insertion error
145062306a36Sopenharmony_ci * -2 - access not permitted by subpage protection mechanism
145162306a36Sopenharmony_ci */
145262306a36Sopenharmony_ciint hash_page_mm(struct mm_struct *mm, unsigned long ea,
145362306a36Sopenharmony_ci		 unsigned long access, unsigned long trap,
145462306a36Sopenharmony_ci		 unsigned long flags)
145562306a36Sopenharmony_ci{
145662306a36Sopenharmony_ci	bool is_thp;
145762306a36Sopenharmony_ci	pgd_t *pgdir;
145862306a36Sopenharmony_ci	unsigned long vsid;
145962306a36Sopenharmony_ci	pte_t *ptep;
146062306a36Sopenharmony_ci	unsigned hugeshift;
146162306a36Sopenharmony_ci	int rc, user_region = 0;
146262306a36Sopenharmony_ci	int psize, ssize;
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	DBG_LOW("hash_page(ea=%016lx, access=%lx, trap=%lx\n",
146562306a36Sopenharmony_ci		ea, access, trap);
146662306a36Sopenharmony_ci	trace_hash_fault(ea, access, trap);
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	/* Get region & vsid */
146962306a36Sopenharmony_ci	switch (get_region_id(ea)) {
147062306a36Sopenharmony_ci	case USER_REGION_ID:
147162306a36Sopenharmony_ci		user_region = 1;
147262306a36Sopenharmony_ci		if (! mm) {
147362306a36Sopenharmony_ci			DBG_LOW(" user region with no mm !\n");
147462306a36Sopenharmony_ci			rc = 1;
147562306a36Sopenharmony_ci			goto bail;
147662306a36Sopenharmony_ci		}
147762306a36Sopenharmony_ci		psize = get_slice_psize(mm, ea);
147862306a36Sopenharmony_ci		ssize = user_segment_size(ea);
147962306a36Sopenharmony_ci		vsid = get_user_vsid(&mm->context, ea, ssize);
148062306a36Sopenharmony_ci		break;
148162306a36Sopenharmony_ci	case VMALLOC_REGION_ID:
148262306a36Sopenharmony_ci		vsid = get_kernel_vsid(ea, mmu_kernel_ssize);
148362306a36Sopenharmony_ci		psize = mmu_vmalloc_psize;
148462306a36Sopenharmony_ci		ssize = mmu_kernel_ssize;
148562306a36Sopenharmony_ci		flags |= HPTE_USE_KERNEL_KEY;
148662306a36Sopenharmony_ci		break;
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	case IO_REGION_ID:
148962306a36Sopenharmony_ci		vsid = get_kernel_vsid(ea, mmu_kernel_ssize);
149062306a36Sopenharmony_ci		psize = mmu_io_psize;
149162306a36Sopenharmony_ci		ssize = mmu_kernel_ssize;
149262306a36Sopenharmony_ci		flags |= HPTE_USE_KERNEL_KEY;
149362306a36Sopenharmony_ci		break;
149462306a36Sopenharmony_ci	default:
149562306a36Sopenharmony_ci		/*
149662306a36Sopenharmony_ci		 * Not a valid range
149762306a36Sopenharmony_ci		 * Send the problem up to do_page_fault()
149862306a36Sopenharmony_ci		 */
149962306a36Sopenharmony_ci		rc = 1;
150062306a36Sopenharmony_ci		goto bail;
150162306a36Sopenharmony_ci	}
150262306a36Sopenharmony_ci	DBG_LOW(" mm=%p, mm->pgdir=%p, vsid=%016lx\n", mm, mm->pgd, vsid);
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	/* Bad address. */
150562306a36Sopenharmony_ci	if (!vsid) {
150662306a36Sopenharmony_ci		DBG_LOW("Bad address!\n");
150762306a36Sopenharmony_ci		rc = 1;
150862306a36Sopenharmony_ci		goto bail;
150962306a36Sopenharmony_ci	}
151062306a36Sopenharmony_ci	/* Get pgdir */
151162306a36Sopenharmony_ci	pgdir = mm->pgd;
151262306a36Sopenharmony_ci	if (pgdir == NULL) {
151362306a36Sopenharmony_ci		rc = 1;
151462306a36Sopenharmony_ci		goto bail;
151562306a36Sopenharmony_ci	}
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	/* Check CPU locality */
151862306a36Sopenharmony_ci	if (user_region && mm_is_thread_local(mm))
151962306a36Sopenharmony_ci		flags |= HPTE_LOCAL_UPDATE;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci#ifndef CONFIG_PPC_64K_PAGES
152262306a36Sopenharmony_ci	/*
152362306a36Sopenharmony_ci	 * If we use 4K pages and our psize is not 4K, then we might
152462306a36Sopenharmony_ci	 * be hitting a special driver mapping, and need to align the
152562306a36Sopenharmony_ci	 * address before we fetch the PTE.
152662306a36Sopenharmony_ci	 *
152762306a36Sopenharmony_ci	 * It could also be a hugepage mapping, in which case this is
152862306a36Sopenharmony_ci	 * not necessary, but it's not harmful, either.
152962306a36Sopenharmony_ci	 */
153062306a36Sopenharmony_ci	if (psize != MMU_PAGE_4K)
153162306a36Sopenharmony_ci		ea &= ~((1ul << mmu_psize_defs[psize].shift) - 1);
153262306a36Sopenharmony_ci#endif /* CONFIG_PPC_64K_PAGES */
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	/* Get PTE and page size from page tables */
153562306a36Sopenharmony_ci	ptep = find_linux_pte(pgdir, ea, &is_thp, &hugeshift);
153662306a36Sopenharmony_ci	if (ptep == NULL || !pte_present(*ptep)) {
153762306a36Sopenharmony_ci		DBG_LOW(" no PTE !\n");
153862306a36Sopenharmony_ci		rc = 1;
153962306a36Sopenharmony_ci		goto bail;
154062306a36Sopenharmony_ci	}
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	/*
154362306a36Sopenharmony_ci	 * Add _PAGE_PRESENT to the required access perm. If there are parallel
154462306a36Sopenharmony_ci	 * updates to the pte that can possibly clear _PAGE_PTE, catch that too.
154562306a36Sopenharmony_ci	 *
154662306a36Sopenharmony_ci	 * We can safely use the return pte address in rest of the function
154762306a36Sopenharmony_ci	 * because we do set H_PAGE_BUSY which prevents further updates to pte
154862306a36Sopenharmony_ci	 * from generic code.
154962306a36Sopenharmony_ci	 */
155062306a36Sopenharmony_ci	access |= _PAGE_PRESENT | _PAGE_PTE;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	/*
155362306a36Sopenharmony_ci	 * Pre-check access permissions (will be re-checked atomically
155462306a36Sopenharmony_ci	 * in __hash_page_XX but this pre-check is a fast path
155562306a36Sopenharmony_ci	 */
155662306a36Sopenharmony_ci	if (!check_pte_access(access, pte_val(*ptep))) {
155762306a36Sopenharmony_ci		DBG_LOW(" no access !\n");
155862306a36Sopenharmony_ci		rc = 1;
155962306a36Sopenharmony_ci		goto bail;
156062306a36Sopenharmony_ci	}
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	if (hugeshift) {
156362306a36Sopenharmony_ci		if (is_thp)
156462306a36Sopenharmony_ci			rc = __hash_page_thp(ea, access, vsid, (pmd_t *)ptep,
156562306a36Sopenharmony_ci					     trap, flags, ssize, psize);
156662306a36Sopenharmony_ci#ifdef CONFIG_HUGETLB_PAGE
156762306a36Sopenharmony_ci		else
156862306a36Sopenharmony_ci			rc = __hash_page_huge(ea, access, vsid, ptep, trap,
156962306a36Sopenharmony_ci					      flags, ssize, hugeshift, psize);
157062306a36Sopenharmony_ci#else
157162306a36Sopenharmony_ci		else {
157262306a36Sopenharmony_ci			/*
157362306a36Sopenharmony_ci			 * if we have hugeshift, and is not transhuge with
157462306a36Sopenharmony_ci			 * hugetlb disabled, something is really wrong.
157562306a36Sopenharmony_ci			 */
157662306a36Sopenharmony_ci			rc = 1;
157762306a36Sopenharmony_ci			WARN_ON(1);
157862306a36Sopenharmony_ci		}
157962306a36Sopenharmony_ci#endif
158062306a36Sopenharmony_ci		if (current->mm == mm)
158162306a36Sopenharmony_ci			check_paca_psize(ea, mm, psize, user_region);
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci		goto bail;
158462306a36Sopenharmony_ci	}
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci#ifndef CONFIG_PPC_64K_PAGES
158762306a36Sopenharmony_ci	DBG_LOW(" i-pte: %016lx\n", pte_val(*ptep));
158862306a36Sopenharmony_ci#else
158962306a36Sopenharmony_ci	DBG_LOW(" i-pte: %016lx %016lx\n", pte_val(*ptep),
159062306a36Sopenharmony_ci		pte_val(*(ptep + PTRS_PER_PTE)));
159162306a36Sopenharmony_ci#endif
159262306a36Sopenharmony_ci	/* Do actual hashing */
159362306a36Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES
159462306a36Sopenharmony_ci	/* If H_PAGE_4K_PFN is set, make sure this is a 4k segment */
159562306a36Sopenharmony_ci	if ((pte_val(*ptep) & H_PAGE_4K_PFN) && psize == MMU_PAGE_64K) {
159662306a36Sopenharmony_ci		demote_segment_4k(mm, ea);
159762306a36Sopenharmony_ci		psize = MMU_PAGE_4K;
159862306a36Sopenharmony_ci	}
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	/*
160162306a36Sopenharmony_ci	 * If this PTE is non-cacheable and we have restrictions on
160262306a36Sopenharmony_ci	 * using non cacheable large pages, then we switch to 4k
160362306a36Sopenharmony_ci	 */
160462306a36Sopenharmony_ci	if (mmu_ci_restrictions && psize == MMU_PAGE_64K && pte_ci(*ptep)) {
160562306a36Sopenharmony_ci		if (user_region) {
160662306a36Sopenharmony_ci			demote_segment_4k(mm, ea);
160762306a36Sopenharmony_ci			psize = MMU_PAGE_4K;
160862306a36Sopenharmony_ci		} else if (ea < VMALLOC_END) {
160962306a36Sopenharmony_ci			/*
161062306a36Sopenharmony_ci			 * some driver did a non-cacheable mapping
161162306a36Sopenharmony_ci			 * in vmalloc space, so switch vmalloc
161262306a36Sopenharmony_ci			 * to 4k pages
161362306a36Sopenharmony_ci			 */
161462306a36Sopenharmony_ci			printk(KERN_ALERT "Reducing vmalloc segment "
161562306a36Sopenharmony_ci			       "to 4kB pages because of "
161662306a36Sopenharmony_ci			       "non-cacheable mapping\n");
161762306a36Sopenharmony_ci			psize = mmu_vmalloc_psize = MMU_PAGE_4K;
161862306a36Sopenharmony_ci			copro_flush_all_slbs(mm);
161962306a36Sopenharmony_ci		}
162062306a36Sopenharmony_ci	}
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci#endif /* CONFIG_PPC_64K_PAGES */
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	if (current->mm == mm)
162562306a36Sopenharmony_ci		check_paca_psize(ea, mm, psize, user_region);
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES
162862306a36Sopenharmony_ci	if (psize == MMU_PAGE_64K)
162962306a36Sopenharmony_ci		rc = __hash_page_64K(ea, access, vsid, ptep, trap,
163062306a36Sopenharmony_ci				     flags, ssize);
163162306a36Sopenharmony_ci	else
163262306a36Sopenharmony_ci#endif /* CONFIG_PPC_64K_PAGES */
163362306a36Sopenharmony_ci	{
163462306a36Sopenharmony_ci		int spp = subpage_protection(mm, ea);
163562306a36Sopenharmony_ci		if (access & spp)
163662306a36Sopenharmony_ci			rc = -2;
163762306a36Sopenharmony_ci		else
163862306a36Sopenharmony_ci			rc = __hash_page_4K(ea, access, vsid, ptep, trap,
163962306a36Sopenharmony_ci					    flags, ssize, spp);
164062306a36Sopenharmony_ci	}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	/*
164362306a36Sopenharmony_ci	 * Dump some info in case of hash insertion failure, they should
164462306a36Sopenharmony_ci	 * never happen so it is really useful to know if/when they do
164562306a36Sopenharmony_ci	 */
164662306a36Sopenharmony_ci	if (rc == -1)
164762306a36Sopenharmony_ci		hash_failure_debug(ea, access, vsid, trap, ssize, psize,
164862306a36Sopenharmony_ci				   psize, pte_val(*ptep));
164962306a36Sopenharmony_ci#ifndef CONFIG_PPC_64K_PAGES
165062306a36Sopenharmony_ci	DBG_LOW(" o-pte: %016lx\n", pte_val(*ptep));
165162306a36Sopenharmony_ci#else
165262306a36Sopenharmony_ci	DBG_LOW(" o-pte: %016lx %016lx\n", pte_val(*ptep),
165362306a36Sopenharmony_ci		pte_val(*(ptep + PTRS_PER_PTE)));
165462306a36Sopenharmony_ci#endif
165562306a36Sopenharmony_ci	DBG_LOW(" -> rc=%d\n", rc);
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_cibail:
165862306a36Sopenharmony_ci	return rc;
165962306a36Sopenharmony_ci}
166062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hash_page_mm);
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ciint hash_page(unsigned long ea, unsigned long access, unsigned long trap,
166362306a36Sopenharmony_ci	      unsigned long dsisr)
166462306a36Sopenharmony_ci{
166562306a36Sopenharmony_ci	unsigned long flags = 0;
166662306a36Sopenharmony_ci	struct mm_struct *mm = current->mm;
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	if ((get_region_id(ea) == VMALLOC_REGION_ID) ||
166962306a36Sopenharmony_ci	    (get_region_id(ea) == IO_REGION_ID))
167062306a36Sopenharmony_ci		mm = &init_mm;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	if (dsisr & DSISR_NOHPTE)
167362306a36Sopenharmony_ci		flags |= HPTE_NOHPTE_UPDATE;
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	return hash_page_mm(mm, ea, access, trap, flags);
167662306a36Sopenharmony_ci}
167762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hash_page);
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ciDEFINE_INTERRUPT_HANDLER(do_hash_fault)
168062306a36Sopenharmony_ci{
168162306a36Sopenharmony_ci	unsigned long ea = regs->dar;
168262306a36Sopenharmony_ci	unsigned long dsisr = regs->dsisr;
168362306a36Sopenharmony_ci	unsigned long access = _PAGE_PRESENT | _PAGE_READ;
168462306a36Sopenharmony_ci	unsigned long flags = 0;
168562306a36Sopenharmony_ci	struct mm_struct *mm;
168662306a36Sopenharmony_ci	unsigned int region_id;
168762306a36Sopenharmony_ci	long err;
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	if (unlikely(dsisr & (DSISR_BAD_FAULT_64S | DSISR_KEYFAULT))) {
169062306a36Sopenharmony_ci		hash__do_page_fault(regs);
169162306a36Sopenharmony_ci		return;
169262306a36Sopenharmony_ci	}
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci	region_id = get_region_id(ea);
169562306a36Sopenharmony_ci	if ((region_id == VMALLOC_REGION_ID) || (region_id == IO_REGION_ID))
169662306a36Sopenharmony_ci		mm = &init_mm;
169762306a36Sopenharmony_ci	else
169862306a36Sopenharmony_ci		mm = current->mm;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	if (dsisr & DSISR_NOHPTE)
170162306a36Sopenharmony_ci		flags |= HPTE_NOHPTE_UPDATE;
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ci	if (dsisr & DSISR_ISSTORE)
170462306a36Sopenharmony_ci		access |= _PAGE_WRITE;
170562306a36Sopenharmony_ci	/*
170662306a36Sopenharmony_ci	 * We set _PAGE_PRIVILEGED only when
170762306a36Sopenharmony_ci	 * kernel mode access kernel space.
170862306a36Sopenharmony_ci	 *
170962306a36Sopenharmony_ci	 * _PAGE_PRIVILEGED is NOT set
171062306a36Sopenharmony_ci	 * 1) when kernel mode access user space
171162306a36Sopenharmony_ci	 * 2) user space access kernel space.
171262306a36Sopenharmony_ci	 */
171362306a36Sopenharmony_ci	access |= _PAGE_PRIVILEGED;
171462306a36Sopenharmony_ci	if (user_mode(regs) || (region_id == USER_REGION_ID))
171562306a36Sopenharmony_ci		access &= ~_PAGE_PRIVILEGED;
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	if (TRAP(regs) == INTERRUPT_INST_STORAGE)
171862306a36Sopenharmony_ci		access |= _PAGE_EXEC;
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	err = hash_page_mm(mm, ea, access, TRAP(regs), flags);
172162306a36Sopenharmony_ci	if (unlikely(err < 0)) {
172262306a36Sopenharmony_ci		// failed to insert a hash PTE due to an hypervisor error
172362306a36Sopenharmony_ci		if (user_mode(regs)) {
172462306a36Sopenharmony_ci			if (IS_ENABLED(CONFIG_PPC_SUBPAGE_PROT) && err == -2)
172562306a36Sopenharmony_ci				_exception(SIGSEGV, regs, SEGV_ACCERR, ea);
172662306a36Sopenharmony_ci			else
172762306a36Sopenharmony_ci				_exception(SIGBUS, regs, BUS_ADRERR, ea);
172862306a36Sopenharmony_ci		} else {
172962306a36Sopenharmony_ci			bad_page_fault(regs, SIGBUS);
173062306a36Sopenharmony_ci		}
173162306a36Sopenharmony_ci		err = 0;
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	} else if (err) {
173462306a36Sopenharmony_ci		hash__do_page_fault(regs);
173562306a36Sopenharmony_ci	}
173662306a36Sopenharmony_ci}
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_cistatic bool should_hash_preload(struct mm_struct *mm, unsigned long ea)
173962306a36Sopenharmony_ci{
174062306a36Sopenharmony_ci	int psize = get_slice_psize(mm, ea);
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	/* We only prefault standard pages for now */
174362306a36Sopenharmony_ci	if (unlikely(psize != mm_ctx_user_psize(&mm->context)))
174462306a36Sopenharmony_ci		return false;
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	/*
174762306a36Sopenharmony_ci	 * Don't prefault if subpage protection is enabled for the EA.
174862306a36Sopenharmony_ci	 */
174962306a36Sopenharmony_ci	if (unlikely((psize == MMU_PAGE_4K) && subpage_protection(mm, ea)))
175062306a36Sopenharmony_ci		return false;
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci	return true;
175362306a36Sopenharmony_ci}
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_cistatic void hash_preload(struct mm_struct *mm, pte_t *ptep, unsigned long ea,
175662306a36Sopenharmony_ci			 bool is_exec, unsigned long trap)
175762306a36Sopenharmony_ci{
175862306a36Sopenharmony_ci	unsigned long vsid;
175962306a36Sopenharmony_ci	pgd_t *pgdir;
176062306a36Sopenharmony_ci	int rc, ssize, update_flags = 0;
176162306a36Sopenharmony_ci	unsigned long access = _PAGE_PRESENT | _PAGE_READ | (is_exec ? _PAGE_EXEC : 0);
176262306a36Sopenharmony_ci	unsigned long flags;
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	BUG_ON(get_region_id(ea) != USER_REGION_ID);
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci	if (!should_hash_preload(mm, ea))
176762306a36Sopenharmony_ci		return;
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	DBG_LOW("hash_preload(mm=%p, mm->pgdir=%p, ea=%016lx, access=%lx,"
177062306a36Sopenharmony_ci		" trap=%lx\n", mm, mm->pgd, ea, access, trap);
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	/* Get Linux PTE if available */
177362306a36Sopenharmony_ci	pgdir = mm->pgd;
177462306a36Sopenharmony_ci	if (pgdir == NULL)
177562306a36Sopenharmony_ci		return;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	/* Get VSID */
177862306a36Sopenharmony_ci	ssize = user_segment_size(ea);
177962306a36Sopenharmony_ci	vsid = get_user_vsid(&mm->context, ea, ssize);
178062306a36Sopenharmony_ci	if (!vsid)
178162306a36Sopenharmony_ci		return;
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES
178462306a36Sopenharmony_ci	/* If either H_PAGE_4K_PFN or cache inhibited is set (and we are on
178562306a36Sopenharmony_ci	 * a 64K kernel), then we don't preload, hash_page() will take
178662306a36Sopenharmony_ci	 * care of it once we actually try to access the page.
178762306a36Sopenharmony_ci	 * That way we don't have to duplicate all of the logic for segment
178862306a36Sopenharmony_ci	 * page size demotion here
178962306a36Sopenharmony_ci	 * Called with  PTL held, hence can be sure the value won't change in
179062306a36Sopenharmony_ci	 * between.
179162306a36Sopenharmony_ci	 */
179262306a36Sopenharmony_ci	if ((pte_val(*ptep) & H_PAGE_4K_PFN) || pte_ci(*ptep))
179362306a36Sopenharmony_ci		return;
179462306a36Sopenharmony_ci#endif /* CONFIG_PPC_64K_PAGES */
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci	/*
179762306a36Sopenharmony_ci	 * __hash_page_* must run with interrupts off, including PMI interrupts
179862306a36Sopenharmony_ci	 * off, as it sets the H_PAGE_BUSY bit.
179962306a36Sopenharmony_ci	 *
180062306a36Sopenharmony_ci	 * It's otherwise possible for perf interrupts to hit at any time and
180162306a36Sopenharmony_ci	 * may take a hash fault reading the user stack, which could take a
180262306a36Sopenharmony_ci	 * hash miss and deadlock on the same H_PAGE_BUSY bit.
180362306a36Sopenharmony_ci	 *
180462306a36Sopenharmony_ci	 * Interrupts must also be off for the duration of the
180562306a36Sopenharmony_ci	 * mm_is_thread_local test and update, to prevent preempt running the
180662306a36Sopenharmony_ci	 * mm on another CPU (XXX: this may be racy vs kthread_use_mm).
180762306a36Sopenharmony_ci	 */
180862306a36Sopenharmony_ci	powerpc_local_irq_pmu_save(flags);
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	/* Is that local to this CPU ? */
181162306a36Sopenharmony_ci	if (mm_is_thread_local(mm))
181262306a36Sopenharmony_ci		update_flags |= HPTE_LOCAL_UPDATE;
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	/* Hash it in */
181562306a36Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES
181662306a36Sopenharmony_ci	if (mm_ctx_user_psize(&mm->context) == MMU_PAGE_64K)
181762306a36Sopenharmony_ci		rc = __hash_page_64K(ea, access, vsid, ptep, trap,
181862306a36Sopenharmony_ci				     update_flags, ssize);
181962306a36Sopenharmony_ci	else
182062306a36Sopenharmony_ci#endif /* CONFIG_PPC_64K_PAGES */
182162306a36Sopenharmony_ci		rc = __hash_page_4K(ea, access, vsid, ptep, trap, update_flags,
182262306a36Sopenharmony_ci				    ssize, subpage_protection(mm, ea));
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	/* Dump some info in case of hash insertion failure, they should
182562306a36Sopenharmony_ci	 * never happen so it is really useful to know if/when they do
182662306a36Sopenharmony_ci	 */
182762306a36Sopenharmony_ci	if (rc == -1)
182862306a36Sopenharmony_ci		hash_failure_debug(ea, access, vsid, trap, ssize,
182962306a36Sopenharmony_ci				   mm_ctx_user_psize(&mm->context),
183062306a36Sopenharmony_ci				   mm_ctx_user_psize(&mm->context),
183162306a36Sopenharmony_ci				   pte_val(*ptep));
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci	powerpc_local_irq_pmu_restore(flags);
183462306a36Sopenharmony_ci}
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci/*
183762306a36Sopenharmony_ci * This is called at the end of handling a user page fault, when the
183862306a36Sopenharmony_ci * fault has been handled by updating a PTE in the linux page tables.
183962306a36Sopenharmony_ci * We use it to preload an HPTE into the hash table corresponding to
184062306a36Sopenharmony_ci * the updated linux PTE.
184162306a36Sopenharmony_ci *
184262306a36Sopenharmony_ci * This must always be called with the pte lock held.
184362306a36Sopenharmony_ci */
184462306a36Sopenharmony_civoid __update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
184562306a36Sopenharmony_ci		      pte_t *ptep)
184662306a36Sopenharmony_ci{
184762306a36Sopenharmony_ci	/*
184862306a36Sopenharmony_ci	 * We don't need to worry about _PAGE_PRESENT here because we are
184962306a36Sopenharmony_ci	 * called with either mm->page_table_lock held or ptl lock held
185062306a36Sopenharmony_ci	 */
185162306a36Sopenharmony_ci	unsigned long trap;
185262306a36Sopenharmony_ci	bool is_exec;
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	/* We only want HPTEs for linux PTEs that have _PAGE_ACCESSED set */
185562306a36Sopenharmony_ci	if (!pte_young(*ptep) || address >= TASK_SIZE)
185662306a36Sopenharmony_ci		return;
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	/*
185962306a36Sopenharmony_ci	 * We try to figure out if we are coming from an instruction
186062306a36Sopenharmony_ci	 * access fault and pass that down to __hash_page so we avoid
186162306a36Sopenharmony_ci	 * double-faulting on execution of fresh text. We have to test
186262306a36Sopenharmony_ci	 * for regs NULL since init will get here first thing at boot.
186362306a36Sopenharmony_ci	 *
186462306a36Sopenharmony_ci	 * We also avoid filling the hash if not coming from a fault.
186562306a36Sopenharmony_ci	 */
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	trap = current->thread.regs ? TRAP(current->thread.regs) : 0UL;
186862306a36Sopenharmony_ci	switch (trap) {
186962306a36Sopenharmony_ci	case 0x300:
187062306a36Sopenharmony_ci		is_exec = false;
187162306a36Sopenharmony_ci		break;
187262306a36Sopenharmony_ci	case 0x400:
187362306a36Sopenharmony_ci		is_exec = true;
187462306a36Sopenharmony_ci		break;
187562306a36Sopenharmony_ci	default:
187662306a36Sopenharmony_ci		return;
187762306a36Sopenharmony_ci	}
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	hash_preload(vma->vm_mm, ptep, address, is_exec, trap);
188062306a36Sopenharmony_ci}
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
188362306a36Sopenharmony_cistatic inline void tm_flush_hash_page(int local)
188462306a36Sopenharmony_ci{
188562306a36Sopenharmony_ci	/*
188662306a36Sopenharmony_ci	 * Transactions are not aborted by tlbiel, only tlbie. Without, syncing a
188762306a36Sopenharmony_ci	 * page back to a block device w/PIO could pick up transactional data
188862306a36Sopenharmony_ci	 * (bad!) so we force an abort here. Before the sync the page will be
188962306a36Sopenharmony_ci	 * made read-only, which will flush_hash_page. BIG ISSUE here: if the
189062306a36Sopenharmony_ci	 * kernel uses a page from userspace without unmapping it first, it may
189162306a36Sopenharmony_ci	 * see the speculated version.
189262306a36Sopenharmony_ci	 */
189362306a36Sopenharmony_ci	if (local && cpu_has_feature(CPU_FTR_TM) && current->thread.regs &&
189462306a36Sopenharmony_ci	    MSR_TM_ACTIVE(current->thread.regs->msr)) {
189562306a36Sopenharmony_ci		tm_enable();
189662306a36Sopenharmony_ci		tm_abort(TM_CAUSE_TLBI);
189762306a36Sopenharmony_ci	}
189862306a36Sopenharmony_ci}
189962306a36Sopenharmony_ci#else
190062306a36Sopenharmony_cistatic inline void tm_flush_hash_page(int local)
190162306a36Sopenharmony_ci{
190262306a36Sopenharmony_ci}
190362306a36Sopenharmony_ci#endif
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci/*
190662306a36Sopenharmony_ci * Return the global hash slot, corresponding to the given PTE, which contains
190762306a36Sopenharmony_ci * the HPTE.
190862306a36Sopenharmony_ci */
190962306a36Sopenharmony_ciunsigned long pte_get_hash_gslot(unsigned long vpn, unsigned long shift,
191062306a36Sopenharmony_ci		int ssize, real_pte_t rpte, unsigned int subpg_index)
191162306a36Sopenharmony_ci{
191262306a36Sopenharmony_ci	unsigned long hash, gslot, hidx;
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci	hash = hpt_hash(vpn, shift, ssize);
191562306a36Sopenharmony_ci	hidx = __rpte_to_hidx(rpte, subpg_index);
191662306a36Sopenharmony_ci	if (hidx & _PTEIDX_SECONDARY)
191762306a36Sopenharmony_ci		hash = ~hash;
191862306a36Sopenharmony_ci	gslot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
191962306a36Sopenharmony_ci	gslot += hidx & _PTEIDX_GROUP_IX;
192062306a36Sopenharmony_ci	return gslot;
192162306a36Sopenharmony_ci}
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_civoid flush_hash_page(unsigned long vpn, real_pte_t pte, int psize, int ssize,
192462306a36Sopenharmony_ci		     unsigned long flags)
192562306a36Sopenharmony_ci{
192662306a36Sopenharmony_ci	unsigned long index, shift, gslot;
192762306a36Sopenharmony_ci	int local = flags & HPTE_LOCAL_UPDATE;
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci	DBG_LOW("flush_hash_page(vpn=%016lx)\n", vpn);
193062306a36Sopenharmony_ci	pte_iterate_hashed_subpages(pte, psize, vpn, index, shift) {
193162306a36Sopenharmony_ci		gslot = pte_get_hash_gslot(vpn, shift, ssize, pte, index);
193262306a36Sopenharmony_ci		DBG_LOW(" sub %ld: gslot=%lx\n", index, gslot);
193362306a36Sopenharmony_ci		/*
193462306a36Sopenharmony_ci		 * We use same base page size and actual psize, because we don't
193562306a36Sopenharmony_ci		 * use these functions for hugepage
193662306a36Sopenharmony_ci		 */
193762306a36Sopenharmony_ci		mmu_hash_ops.hpte_invalidate(gslot, vpn, psize, psize,
193862306a36Sopenharmony_ci					     ssize, local);
193962306a36Sopenharmony_ci	} pte_iterate_hashed_end();
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	tm_flush_hash_page(local);
194262306a36Sopenharmony_ci}
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE
194562306a36Sopenharmony_civoid flush_hash_hugepage(unsigned long vsid, unsigned long addr,
194662306a36Sopenharmony_ci			 pmd_t *pmdp, unsigned int psize, int ssize,
194762306a36Sopenharmony_ci			 unsigned long flags)
194862306a36Sopenharmony_ci{
194962306a36Sopenharmony_ci	int i, max_hpte_count, valid;
195062306a36Sopenharmony_ci	unsigned long s_addr;
195162306a36Sopenharmony_ci	unsigned char *hpte_slot_array;
195262306a36Sopenharmony_ci	unsigned long hidx, shift, vpn, hash, slot;
195362306a36Sopenharmony_ci	int local = flags & HPTE_LOCAL_UPDATE;
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	s_addr = addr & HPAGE_PMD_MASK;
195662306a36Sopenharmony_ci	hpte_slot_array = get_hpte_slot_array(pmdp);
195762306a36Sopenharmony_ci	/*
195862306a36Sopenharmony_ci	 * IF we try to do a HUGE PTE update after a withdraw is done.
195962306a36Sopenharmony_ci	 * we will find the below NULL. This happens when we do
196062306a36Sopenharmony_ci	 * split_huge_pmd
196162306a36Sopenharmony_ci	 */
196262306a36Sopenharmony_ci	if (!hpte_slot_array)
196362306a36Sopenharmony_ci		return;
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	if (mmu_hash_ops.hugepage_invalidate) {
196662306a36Sopenharmony_ci		mmu_hash_ops.hugepage_invalidate(vsid, s_addr, hpte_slot_array,
196762306a36Sopenharmony_ci						 psize, ssize, local);
196862306a36Sopenharmony_ci		goto tm_abort;
196962306a36Sopenharmony_ci	}
197062306a36Sopenharmony_ci	/*
197162306a36Sopenharmony_ci	 * No bluk hpte removal support, invalidate each entry
197262306a36Sopenharmony_ci	 */
197362306a36Sopenharmony_ci	shift = mmu_psize_defs[psize].shift;
197462306a36Sopenharmony_ci	max_hpte_count = HPAGE_PMD_SIZE >> shift;
197562306a36Sopenharmony_ci	for (i = 0; i < max_hpte_count; i++) {
197662306a36Sopenharmony_ci		/*
197762306a36Sopenharmony_ci		 * 8 bits per each hpte entries
197862306a36Sopenharmony_ci		 * 000| [ secondary group (one bit) | hidx (3 bits) | valid bit]
197962306a36Sopenharmony_ci		 */
198062306a36Sopenharmony_ci		valid = hpte_valid(hpte_slot_array, i);
198162306a36Sopenharmony_ci		if (!valid)
198262306a36Sopenharmony_ci			continue;
198362306a36Sopenharmony_ci		hidx =  hpte_hash_index(hpte_slot_array, i);
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci		/* get the vpn */
198662306a36Sopenharmony_ci		addr = s_addr + (i * (1ul << shift));
198762306a36Sopenharmony_ci		vpn = hpt_vpn(addr, vsid, ssize);
198862306a36Sopenharmony_ci		hash = hpt_hash(vpn, shift, ssize);
198962306a36Sopenharmony_ci		if (hidx & _PTEIDX_SECONDARY)
199062306a36Sopenharmony_ci			hash = ~hash;
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci		slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
199362306a36Sopenharmony_ci		slot += hidx & _PTEIDX_GROUP_IX;
199462306a36Sopenharmony_ci		mmu_hash_ops.hpte_invalidate(slot, vpn, psize,
199562306a36Sopenharmony_ci					     MMU_PAGE_16M, ssize, local);
199662306a36Sopenharmony_ci	}
199762306a36Sopenharmony_citm_abort:
199862306a36Sopenharmony_ci	tm_flush_hash_page(local);
199962306a36Sopenharmony_ci}
200062306a36Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_civoid flush_hash_range(unsigned long number, int local)
200362306a36Sopenharmony_ci{
200462306a36Sopenharmony_ci	if (mmu_hash_ops.flush_hash_range)
200562306a36Sopenharmony_ci		mmu_hash_ops.flush_hash_range(number, local);
200662306a36Sopenharmony_ci	else {
200762306a36Sopenharmony_ci		int i;
200862306a36Sopenharmony_ci		struct ppc64_tlb_batch *batch =
200962306a36Sopenharmony_ci			this_cpu_ptr(&ppc64_tlb_batch);
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci		for (i = 0; i < number; i++)
201262306a36Sopenharmony_ci			flush_hash_page(batch->vpn[i], batch->pte[i],
201362306a36Sopenharmony_ci					batch->psize, batch->ssize, local);
201462306a36Sopenharmony_ci	}
201562306a36Sopenharmony_ci}
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_cilong hpte_insert_repeating(unsigned long hash, unsigned long vpn,
201862306a36Sopenharmony_ci			   unsigned long pa, unsigned long rflags,
201962306a36Sopenharmony_ci			   unsigned long vflags, int psize, int ssize)
202062306a36Sopenharmony_ci{
202162306a36Sopenharmony_ci	unsigned long hpte_group;
202262306a36Sopenharmony_ci	long slot;
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_cirepeat:
202562306a36Sopenharmony_ci	hpte_group = (hash & htab_hash_mask) * HPTES_PER_GROUP;
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci	/* Insert into the hash table, primary slot */
202862306a36Sopenharmony_ci	slot = mmu_hash_ops.hpte_insert(hpte_group, vpn, pa, rflags, vflags,
202962306a36Sopenharmony_ci					psize, psize, ssize);
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	/* Primary is full, try the secondary */
203262306a36Sopenharmony_ci	if (unlikely(slot == -1)) {
203362306a36Sopenharmony_ci		hpte_group = (~hash & htab_hash_mask) * HPTES_PER_GROUP;
203462306a36Sopenharmony_ci		slot = mmu_hash_ops.hpte_insert(hpte_group, vpn, pa, rflags,
203562306a36Sopenharmony_ci						vflags | HPTE_V_SECONDARY,
203662306a36Sopenharmony_ci						psize, psize, ssize);
203762306a36Sopenharmony_ci		if (slot == -1) {
203862306a36Sopenharmony_ci			if (mftb() & 0x1)
203962306a36Sopenharmony_ci				hpte_group = (hash & htab_hash_mask) *
204062306a36Sopenharmony_ci						HPTES_PER_GROUP;
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci			mmu_hash_ops.hpte_remove(hpte_group);
204362306a36Sopenharmony_ci			goto repeat;
204462306a36Sopenharmony_ci		}
204562306a36Sopenharmony_ci	}
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci	return slot;
204862306a36Sopenharmony_ci}
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_civoid hpt_clear_stress(void)
205162306a36Sopenharmony_ci{
205262306a36Sopenharmony_ci	int cpu = raw_smp_processor_id();
205362306a36Sopenharmony_ci	int g;
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	for (g = 0; g < stress_nr_groups(); g++) {
205662306a36Sopenharmony_ci		unsigned long last_group;
205762306a36Sopenharmony_ci		last_group = stress_hpt_struct[cpu].last_group[g];
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci		if (last_group != -1UL) {
206062306a36Sopenharmony_ci			int i;
206162306a36Sopenharmony_ci			for (i = 0; i < HPTES_PER_GROUP; i++) {
206262306a36Sopenharmony_ci				if (mmu_hash_ops.hpte_remove(last_group) == -1)
206362306a36Sopenharmony_ci					break;
206462306a36Sopenharmony_ci			}
206562306a36Sopenharmony_ci			stress_hpt_struct[cpu].last_group[g] = -1;
206662306a36Sopenharmony_ci		}
206762306a36Sopenharmony_ci	}
206862306a36Sopenharmony_ci}
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_civoid hpt_do_stress(unsigned long ea, unsigned long hpte_group)
207162306a36Sopenharmony_ci{
207262306a36Sopenharmony_ci	unsigned long last_group;
207362306a36Sopenharmony_ci	int cpu = raw_smp_processor_id();
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci	last_group = stress_hpt_struct[cpu].last_group[stress_nr_groups() - 1];
207662306a36Sopenharmony_ci	if (hpte_group == last_group)
207762306a36Sopenharmony_ci		return;
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci	if (last_group != -1UL) {
208062306a36Sopenharmony_ci		int i;
208162306a36Sopenharmony_ci		/*
208262306a36Sopenharmony_ci		 * Concurrent CPUs might be inserting into this group, so
208362306a36Sopenharmony_ci		 * give up after a number of iterations, to prevent a live
208462306a36Sopenharmony_ci		 * lock.
208562306a36Sopenharmony_ci		 */
208662306a36Sopenharmony_ci		for (i = 0; i < HPTES_PER_GROUP; i++) {
208762306a36Sopenharmony_ci			if (mmu_hash_ops.hpte_remove(last_group) == -1)
208862306a36Sopenharmony_ci				break;
208962306a36Sopenharmony_ci		}
209062306a36Sopenharmony_ci		stress_hpt_struct[cpu].last_group[stress_nr_groups() - 1] = -1;
209162306a36Sopenharmony_ci	}
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	if (ea >= PAGE_OFFSET) {
209462306a36Sopenharmony_ci		/*
209562306a36Sopenharmony_ci		 * We would really like to prefetch to get the TLB loaded, then
209662306a36Sopenharmony_ci		 * remove the PTE before returning from fault interrupt, to
209762306a36Sopenharmony_ci		 * increase the hash fault rate.
209862306a36Sopenharmony_ci		 *
209962306a36Sopenharmony_ci		 * Unfortunately QEMU TCG does not model the TLB in a way that
210062306a36Sopenharmony_ci		 * makes this possible, and systemsim (mambo) emulator does not
210162306a36Sopenharmony_ci		 * bring in TLBs with prefetches (although loads/stores do
210262306a36Sopenharmony_ci		 * work for non-CI PTEs).
210362306a36Sopenharmony_ci		 *
210462306a36Sopenharmony_ci		 * So remember this PTE and clear it on the next hash fault.
210562306a36Sopenharmony_ci		 */
210662306a36Sopenharmony_ci		memmove(&stress_hpt_struct[cpu].last_group[1],
210762306a36Sopenharmony_ci			&stress_hpt_struct[cpu].last_group[0],
210862306a36Sopenharmony_ci			(stress_nr_groups() - 1) * sizeof(unsigned long));
210962306a36Sopenharmony_ci		stress_hpt_struct[cpu].last_group[0] = hpte_group;
211062306a36Sopenharmony_ci	}
211162306a36Sopenharmony_ci}
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KFENCE)
211462306a36Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(linear_map_hash_lock);
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_cistatic void kernel_map_linear_page(unsigned long vaddr, unsigned long lmi)
211762306a36Sopenharmony_ci{
211862306a36Sopenharmony_ci	unsigned long hash;
211962306a36Sopenharmony_ci	unsigned long vsid = get_kernel_vsid(vaddr, mmu_kernel_ssize);
212062306a36Sopenharmony_ci	unsigned long vpn = hpt_vpn(vaddr, vsid, mmu_kernel_ssize);
212162306a36Sopenharmony_ci	unsigned long mode = htab_convert_pte_flags(pgprot_val(PAGE_KERNEL), HPTE_USE_KERNEL_KEY);
212262306a36Sopenharmony_ci	long ret;
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	hash = hpt_hash(vpn, PAGE_SHIFT, mmu_kernel_ssize);
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	/* Don't create HPTE entries for bad address */
212762306a36Sopenharmony_ci	if (!vsid)
212862306a36Sopenharmony_ci		return;
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci	if (linear_map_hash_slots[lmi] & 0x80)
213162306a36Sopenharmony_ci		return;
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci	ret = hpte_insert_repeating(hash, vpn, __pa(vaddr), mode,
213462306a36Sopenharmony_ci				    HPTE_V_BOLTED,
213562306a36Sopenharmony_ci				    mmu_linear_psize, mmu_kernel_ssize);
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	BUG_ON (ret < 0);
213862306a36Sopenharmony_ci	raw_spin_lock(&linear_map_hash_lock);
213962306a36Sopenharmony_ci	BUG_ON(linear_map_hash_slots[lmi] & 0x80);
214062306a36Sopenharmony_ci	linear_map_hash_slots[lmi] = ret | 0x80;
214162306a36Sopenharmony_ci	raw_spin_unlock(&linear_map_hash_lock);
214262306a36Sopenharmony_ci}
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_cistatic void kernel_unmap_linear_page(unsigned long vaddr, unsigned long lmi)
214562306a36Sopenharmony_ci{
214662306a36Sopenharmony_ci	unsigned long hash, hidx, slot;
214762306a36Sopenharmony_ci	unsigned long vsid = get_kernel_vsid(vaddr, mmu_kernel_ssize);
214862306a36Sopenharmony_ci	unsigned long vpn = hpt_vpn(vaddr, vsid, mmu_kernel_ssize);
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	hash = hpt_hash(vpn, PAGE_SHIFT, mmu_kernel_ssize);
215162306a36Sopenharmony_ci	raw_spin_lock(&linear_map_hash_lock);
215262306a36Sopenharmony_ci	if (!(linear_map_hash_slots[lmi] & 0x80)) {
215362306a36Sopenharmony_ci		raw_spin_unlock(&linear_map_hash_lock);
215462306a36Sopenharmony_ci		return;
215562306a36Sopenharmony_ci	}
215662306a36Sopenharmony_ci	hidx = linear_map_hash_slots[lmi] & 0x7f;
215762306a36Sopenharmony_ci	linear_map_hash_slots[lmi] = 0;
215862306a36Sopenharmony_ci	raw_spin_unlock(&linear_map_hash_lock);
215962306a36Sopenharmony_ci	if (hidx & _PTEIDX_SECONDARY)
216062306a36Sopenharmony_ci		hash = ~hash;
216162306a36Sopenharmony_ci	slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
216262306a36Sopenharmony_ci	slot += hidx & _PTEIDX_GROUP_IX;
216362306a36Sopenharmony_ci	mmu_hash_ops.hpte_invalidate(slot, vpn, mmu_linear_psize,
216462306a36Sopenharmony_ci				     mmu_linear_psize,
216562306a36Sopenharmony_ci				     mmu_kernel_ssize, 0);
216662306a36Sopenharmony_ci}
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_civoid hash__kernel_map_pages(struct page *page, int numpages, int enable)
216962306a36Sopenharmony_ci{
217062306a36Sopenharmony_ci	unsigned long flags, vaddr, lmi;
217162306a36Sopenharmony_ci	int i;
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	local_irq_save(flags);
217462306a36Sopenharmony_ci	for (i = 0; i < numpages; i++, page++) {
217562306a36Sopenharmony_ci		vaddr = (unsigned long)page_address(page);
217662306a36Sopenharmony_ci		lmi = __pa(vaddr) >> PAGE_SHIFT;
217762306a36Sopenharmony_ci		if (lmi >= linear_map_hash_count)
217862306a36Sopenharmony_ci			continue;
217962306a36Sopenharmony_ci		if (enable)
218062306a36Sopenharmony_ci			kernel_map_linear_page(vaddr, lmi);
218162306a36Sopenharmony_ci		else
218262306a36Sopenharmony_ci			kernel_unmap_linear_page(vaddr, lmi);
218362306a36Sopenharmony_ci	}
218462306a36Sopenharmony_ci	local_irq_restore(flags);
218562306a36Sopenharmony_ci}
218662306a36Sopenharmony_ci#endif /* CONFIG_DEBUG_PAGEALLOC || CONFIG_KFENCE */
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_civoid hash__setup_initial_memory_limit(phys_addr_t first_memblock_base,
218962306a36Sopenharmony_ci				phys_addr_t first_memblock_size)
219062306a36Sopenharmony_ci{
219162306a36Sopenharmony_ci	/*
219262306a36Sopenharmony_ci	 * We don't currently support the first MEMBLOCK not mapping 0
219362306a36Sopenharmony_ci	 * physical on those processors
219462306a36Sopenharmony_ci	 */
219562306a36Sopenharmony_ci	BUG_ON(first_memblock_base != 0);
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci	/*
219862306a36Sopenharmony_ci	 * On virtualized systems the first entry is our RMA region aka VRMA,
219962306a36Sopenharmony_ci	 * non-virtualized 64-bit hash MMU systems don't have a limitation
220062306a36Sopenharmony_ci	 * on real mode access.
220162306a36Sopenharmony_ci	 *
220262306a36Sopenharmony_ci	 * For guests on platforms before POWER9, we clamp the it limit to 1G
220362306a36Sopenharmony_ci	 * to avoid some funky things such as RTAS bugs etc...
220462306a36Sopenharmony_ci	 *
220562306a36Sopenharmony_ci	 * On POWER9 we limit to 1TB in case the host erroneously told us that
220662306a36Sopenharmony_ci	 * the RMA was >1TB. Effective address bits 0:23 are treated as zero
220762306a36Sopenharmony_ci	 * (meaning the access is aliased to zero i.e. addr = addr % 1TB)
220862306a36Sopenharmony_ci	 * for virtual real mode addressing and so it doesn't make sense to
220962306a36Sopenharmony_ci	 * have an area larger than 1TB as it can't be addressed.
221062306a36Sopenharmony_ci	 */
221162306a36Sopenharmony_ci	if (!early_cpu_has_feature(CPU_FTR_HVMODE)) {
221262306a36Sopenharmony_ci		ppc64_rma_size = first_memblock_size;
221362306a36Sopenharmony_ci		if (!early_cpu_has_feature(CPU_FTR_ARCH_300))
221462306a36Sopenharmony_ci			ppc64_rma_size = min_t(u64, ppc64_rma_size, 0x40000000);
221562306a36Sopenharmony_ci		else
221662306a36Sopenharmony_ci			ppc64_rma_size = min_t(u64, ppc64_rma_size,
221762306a36Sopenharmony_ci					       1UL << SID_SHIFT_1T);
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci		/* Finally limit subsequent allocations */
222062306a36Sopenharmony_ci		memblock_set_current_limit(ppc64_rma_size);
222162306a36Sopenharmony_ci	} else {
222262306a36Sopenharmony_ci		ppc64_rma_size = ULONG_MAX;
222362306a36Sopenharmony_ci	}
222462306a36Sopenharmony_ci}
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_cistatic int hpt_order_get(void *data, u64 *val)
222962306a36Sopenharmony_ci{
223062306a36Sopenharmony_ci	*val = ppc64_pft_size;
223162306a36Sopenharmony_ci	return 0;
223262306a36Sopenharmony_ci}
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_cistatic int hpt_order_set(void *data, u64 val)
223562306a36Sopenharmony_ci{
223662306a36Sopenharmony_ci	int ret;
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci	if (!mmu_hash_ops.resize_hpt)
223962306a36Sopenharmony_ci		return -ENODEV;
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci	cpus_read_lock();
224262306a36Sopenharmony_ci	ret = mmu_hash_ops.resize_hpt(val);
224362306a36Sopenharmony_ci	cpus_read_unlock();
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	return ret;
224662306a36Sopenharmony_ci}
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_hpt_order, hpt_order_get, hpt_order_set, "%llu\n");
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_cistatic int __init hash64_debugfs(void)
225162306a36Sopenharmony_ci{
225262306a36Sopenharmony_ci	debugfs_create_file("hpt_order", 0600, arch_debugfs_dir, NULL,
225362306a36Sopenharmony_ci			    &fops_hpt_order);
225462306a36Sopenharmony_ci	return 0;
225562306a36Sopenharmony_ci}
225662306a36Sopenharmony_cimachine_device_initcall(pseries, hash64_debugfs);
225762306a36Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_civoid __init print_system_hash_info(void)
226062306a36Sopenharmony_ci{
226162306a36Sopenharmony_ci	pr_info("ppc64_pft_size    = 0x%llx\n", ppc64_pft_size);
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci	if (htab_hash_mask)
226462306a36Sopenharmony_ci		pr_info("htab_hash_mask    = 0x%lx\n", htab_hash_mask);
226562306a36Sopenharmony_ci}
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ciunsigned long arch_randomize_brk(struct mm_struct *mm)
226862306a36Sopenharmony_ci{
226962306a36Sopenharmony_ci	/*
227062306a36Sopenharmony_ci	 * If we are using 1TB segments and we are allowed to randomise
227162306a36Sopenharmony_ci	 * the heap, we can put it above 1TB so it is backed by a 1TB
227262306a36Sopenharmony_ci	 * segment. Otherwise the heap will be in the bottom 1TB
227362306a36Sopenharmony_ci	 * which always uses 256MB segments and this may result in a
227462306a36Sopenharmony_ci	 * performance penalty.
227562306a36Sopenharmony_ci	 */
227662306a36Sopenharmony_ci	if (is_32bit_task())
227762306a36Sopenharmony_ci		return randomize_page(mm->brk, SZ_32M);
227862306a36Sopenharmony_ci	else if (!radix_enabled() && mmu_highuser_ssize == MMU_SEGSIZE_1T)
227962306a36Sopenharmony_ci		return randomize_page(max_t(unsigned long, mm->brk, SZ_1T), SZ_1G);
228062306a36Sopenharmony_ci	else
228162306a36Sopenharmony_ci		return randomize_page(mm->brk, SZ_1G);
228262306a36Sopenharmony_ci}
2283