18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright IBM Corporation, 2015
38c2ecf20Sopenharmony_ci * Author Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it
68c2ecf20Sopenharmony_ci * under the terms of version 2 of the GNU Lesser General Public License
78c2ecf20Sopenharmony_ci * as published by the Free Software Foundation.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * This program is distributed in the hope that it would be useful, but
108c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
118c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <linux/mm.h>
168c2ecf20Sopenharmony_ci#include <asm/machdep.h>
178c2ecf20Sopenharmony_ci#include <asm/mmu.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*
208c2ecf20Sopenharmony_ci * Return true, if the entry has a slot value which
218c2ecf20Sopenharmony_ci * the software considers as invalid.
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_cistatic inline bool hpte_soft_invalid(unsigned long hidx)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	return ((hidx & 0xfUL) == 0xfUL);
268c2ecf20Sopenharmony_ci}
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/*
298c2ecf20Sopenharmony_ci * index from 0 - 15
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_cibool __rpte_sub_valid(real_pte_t rpte, unsigned long index)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	return !(hpte_soft_invalid(__rpte_to_hidx(rpte, index)));
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ciint __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
378c2ecf20Sopenharmony_ci		   pte_t *ptep, unsigned long trap, unsigned long flags,
388c2ecf20Sopenharmony_ci		   int ssize, int subpg_prot)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	real_pte_t rpte;
418c2ecf20Sopenharmony_ci	unsigned long hpte_group;
428c2ecf20Sopenharmony_ci	unsigned int subpg_index;
438c2ecf20Sopenharmony_ci	unsigned long rflags, pa;
448c2ecf20Sopenharmony_ci	unsigned long old_pte, new_pte, subpg_pte;
458c2ecf20Sopenharmony_ci	unsigned long vpn, hash, slot, gslot;
468c2ecf20Sopenharmony_ci	unsigned long shift = mmu_psize_defs[MMU_PAGE_4K].shift;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	/*
498c2ecf20Sopenharmony_ci	 * atomically mark the linux large page PTE busy and dirty
508c2ecf20Sopenharmony_ci	 */
518c2ecf20Sopenharmony_ci	do {
528c2ecf20Sopenharmony_ci		pte_t pte = READ_ONCE(*ptep);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci		old_pte = pte_val(pte);
558c2ecf20Sopenharmony_ci		/* If PTE busy, retry the access */
568c2ecf20Sopenharmony_ci		if (unlikely(old_pte & H_PAGE_BUSY))
578c2ecf20Sopenharmony_ci			return 0;
588c2ecf20Sopenharmony_ci		/* If PTE permissions don't match, take page fault */
598c2ecf20Sopenharmony_ci		if (unlikely(!check_pte_access(access, old_pte)))
608c2ecf20Sopenharmony_ci			return 1;
618c2ecf20Sopenharmony_ci		/*
628c2ecf20Sopenharmony_ci		 * Try to lock the PTE, add ACCESSED and DIRTY if it was
638c2ecf20Sopenharmony_ci		 * a write access. Since this is 4K insert of 64K page size
648c2ecf20Sopenharmony_ci		 * also add H_PAGE_COMBO
658c2ecf20Sopenharmony_ci		 */
668c2ecf20Sopenharmony_ci		new_pte = old_pte | H_PAGE_BUSY | _PAGE_ACCESSED | H_PAGE_COMBO;
678c2ecf20Sopenharmony_ci		if (access & _PAGE_WRITE)
688c2ecf20Sopenharmony_ci			new_pte |= _PAGE_DIRTY;
698c2ecf20Sopenharmony_ci	} while (!pte_xchg(ptep, __pte(old_pte), __pte(new_pte)));
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	/*
728c2ecf20Sopenharmony_ci	 * Handle the subpage protection bits
738c2ecf20Sopenharmony_ci	 */
748c2ecf20Sopenharmony_ci	subpg_pte = new_pte & ~subpg_prot;
758c2ecf20Sopenharmony_ci	rflags = htab_convert_pte_flags(subpg_pte);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	if (cpu_has_feature(CPU_FTR_NOEXECUTE) &&
788c2ecf20Sopenharmony_ci	    !cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) {
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci		/*
818c2ecf20Sopenharmony_ci		 * No CPU has hugepages but lacks no execute, so we
828c2ecf20Sopenharmony_ci		 * don't need to worry about that case
838c2ecf20Sopenharmony_ci		 */
848c2ecf20Sopenharmony_ci		rflags = hash_page_do_lazy_icache(rflags, __pte(old_pte), trap);
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	subpg_index = (ea & (PAGE_SIZE - 1)) >> shift;
888c2ecf20Sopenharmony_ci	vpn  = hpt_vpn(ea, vsid, ssize);
898c2ecf20Sopenharmony_ci	rpte = __real_pte(__pte(old_pte), ptep, PTRS_PER_PTE);
908c2ecf20Sopenharmony_ci	/*
918c2ecf20Sopenharmony_ci	 *None of the sub 4k page is hashed
928c2ecf20Sopenharmony_ci	 */
938c2ecf20Sopenharmony_ci	if (!(old_pte & H_PAGE_HASHPTE))
948c2ecf20Sopenharmony_ci		goto htab_insert_hpte;
958c2ecf20Sopenharmony_ci	/*
968c2ecf20Sopenharmony_ci	 * Check if the pte was already inserted into the hash table
978c2ecf20Sopenharmony_ci	 * as a 64k HW page, and invalidate the 64k HPTE if so.
988c2ecf20Sopenharmony_ci	 */
998c2ecf20Sopenharmony_ci	if (!(old_pte & H_PAGE_COMBO)) {
1008c2ecf20Sopenharmony_ci		flush_hash_page(vpn, rpte, MMU_PAGE_64K, ssize, flags);
1018c2ecf20Sopenharmony_ci		/*
1028c2ecf20Sopenharmony_ci		 * clear the old slot details from the old and new pte.
1038c2ecf20Sopenharmony_ci		 * On hash insert failure we use old pte value and we don't
1048c2ecf20Sopenharmony_ci		 * want slot information there if we have a insert failure.
1058c2ecf20Sopenharmony_ci		 */
1068c2ecf20Sopenharmony_ci		old_pte &= ~H_PAGE_HASHPTE;
1078c2ecf20Sopenharmony_ci		new_pte &= ~H_PAGE_HASHPTE;
1088c2ecf20Sopenharmony_ci		goto htab_insert_hpte;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci	/*
1118c2ecf20Sopenharmony_ci	 * Check for sub page valid and update
1128c2ecf20Sopenharmony_ci	 */
1138c2ecf20Sopenharmony_ci	if (__rpte_sub_valid(rpte, subpg_index)) {
1148c2ecf20Sopenharmony_ci		int ret;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci		gslot = pte_get_hash_gslot(vpn, shift, ssize, rpte,
1178c2ecf20Sopenharmony_ci					   subpg_index);
1188c2ecf20Sopenharmony_ci		ret = mmu_hash_ops.hpte_updatepp(gslot, rflags, vpn,
1198c2ecf20Sopenharmony_ci						 MMU_PAGE_4K, MMU_PAGE_4K,
1208c2ecf20Sopenharmony_ci						 ssize, flags);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci		/*
1238c2ecf20Sopenharmony_ci		 * If we failed because typically the HPTE wasn't really here
1248c2ecf20Sopenharmony_ci		 * we try an insertion.
1258c2ecf20Sopenharmony_ci		 */
1268c2ecf20Sopenharmony_ci		if (ret == -1)
1278c2ecf20Sopenharmony_ci			goto htab_insert_hpte;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci		*ptep = __pte(new_pte & ~H_PAGE_BUSY);
1308c2ecf20Sopenharmony_ci		return 0;
1318c2ecf20Sopenharmony_ci	}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cihtab_insert_hpte:
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	/*
1368c2ecf20Sopenharmony_ci	 * Initialize all hidx entries to invalid value, the first time
1378c2ecf20Sopenharmony_ci	 * the PTE is about to allocate a 4K HPTE.
1388c2ecf20Sopenharmony_ci	 */
1398c2ecf20Sopenharmony_ci	if (!(old_pte & H_PAGE_COMBO))
1408c2ecf20Sopenharmony_ci		rpte.hidx = INVALID_RPTE_HIDX;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	/*
1438c2ecf20Sopenharmony_ci	 * handle H_PAGE_4K_PFN case
1448c2ecf20Sopenharmony_ci	 */
1458c2ecf20Sopenharmony_ci	if (old_pte & H_PAGE_4K_PFN) {
1468c2ecf20Sopenharmony_ci		/*
1478c2ecf20Sopenharmony_ci		 * All the sub 4k page have the same
1488c2ecf20Sopenharmony_ci		 * physical address.
1498c2ecf20Sopenharmony_ci		 */
1508c2ecf20Sopenharmony_ci		pa = pte_pfn(__pte(old_pte)) << HW_PAGE_SHIFT;
1518c2ecf20Sopenharmony_ci	} else {
1528c2ecf20Sopenharmony_ci		pa = pte_pfn(__pte(old_pte)) << PAGE_SHIFT;
1538c2ecf20Sopenharmony_ci		pa += (subpg_index << shift);
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci	hash = hpt_hash(vpn, shift, ssize);
1568c2ecf20Sopenharmony_cirepeat:
1578c2ecf20Sopenharmony_ci	hpte_group = (hash & htab_hash_mask) * HPTES_PER_GROUP;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	/* Insert into the hash table, primary slot */
1608c2ecf20Sopenharmony_ci	slot = mmu_hash_ops.hpte_insert(hpte_group, vpn, pa, rflags, 0,
1618c2ecf20Sopenharmony_ci					MMU_PAGE_4K, MMU_PAGE_4K, ssize);
1628c2ecf20Sopenharmony_ci	/*
1638c2ecf20Sopenharmony_ci	 * Primary is full, try the secondary
1648c2ecf20Sopenharmony_ci	 */
1658c2ecf20Sopenharmony_ci	if (unlikely(slot == -1)) {
1668c2ecf20Sopenharmony_ci		bool soft_invalid;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci		hpte_group = (~hash & htab_hash_mask) * HPTES_PER_GROUP;
1698c2ecf20Sopenharmony_ci		slot = mmu_hash_ops.hpte_insert(hpte_group, vpn, pa,
1708c2ecf20Sopenharmony_ci						rflags, HPTE_V_SECONDARY,
1718c2ecf20Sopenharmony_ci						MMU_PAGE_4K, MMU_PAGE_4K,
1728c2ecf20Sopenharmony_ci						ssize);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci		soft_invalid = hpte_soft_invalid(slot);
1758c2ecf20Sopenharmony_ci		if (unlikely(soft_invalid)) {
1768c2ecf20Sopenharmony_ci			/*
1778c2ecf20Sopenharmony_ci			 * We got a valid slot from a hardware point of view.
1788c2ecf20Sopenharmony_ci			 * but we cannot use it, because we use this special
1798c2ecf20Sopenharmony_ci			 * value; as defined by hpte_soft_invalid(), to track
1808c2ecf20Sopenharmony_ci			 * invalid slots. We cannot use it. So invalidate it.
1818c2ecf20Sopenharmony_ci			 */
1828c2ecf20Sopenharmony_ci			gslot = slot & _PTEIDX_GROUP_IX;
1838c2ecf20Sopenharmony_ci			mmu_hash_ops.hpte_invalidate(hpte_group + gslot, vpn,
1848c2ecf20Sopenharmony_ci						     MMU_PAGE_4K, MMU_PAGE_4K,
1858c2ecf20Sopenharmony_ci						     ssize, 0);
1868c2ecf20Sopenharmony_ci		}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci		if (unlikely(slot == -1 || soft_invalid)) {
1898c2ecf20Sopenharmony_ci			/*
1908c2ecf20Sopenharmony_ci			 * For soft invalid slot, let's ensure that we release a
1918c2ecf20Sopenharmony_ci			 * slot from the primary, with the hope that we will
1928c2ecf20Sopenharmony_ci			 * acquire that slot next time we try. This will ensure
1938c2ecf20Sopenharmony_ci			 * that we do not get the same soft-invalid slot.
1948c2ecf20Sopenharmony_ci			 */
1958c2ecf20Sopenharmony_ci			if (soft_invalid || (mftb() & 0x1))
1968c2ecf20Sopenharmony_ci				hpte_group = (hash & htab_hash_mask) * HPTES_PER_GROUP;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci			mmu_hash_ops.hpte_remove(hpte_group);
1998c2ecf20Sopenharmony_ci			/*
2008c2ecf20Sopenharmony_ci			 * FIXME!! Should be try the group from which we removed ?
2018c2ecf20Sopenharmony_ci			 */
2028c2ecf20Sopenharmony_ci			goto repeat;
2038c2ecf20Sopenharmony_ci		}
2048c2ecf20Sopenharmony_ci	}
2058c2ecf20Sopenharmony_ci	/*
2068c2ecf20Sopenharmony_ci	 * Hypervisor failure. Restore old pte and return -1
2078c2ecf20Sopenharmony_ci	 * similar to __hash_page_*
2088c2ecf20Sopenharmony_ci	 */
2098c2ecf20Sopenharmony_ci	if (unlikely(slot == -2)) {
2108c2ecf20Sopenharmony_ci		*ptep = __pte(old_pte);
2118c2ecf20Sopenharmony_ci		hash_failure_debug(ea, access, vsid, trap, ssize,
2128c2ecf20Sopenharmony_ci				   MMU_PAGE_4K, MMU_PAGE_4K, old_pte);
2138c2ecf20Sopenharmony_ci		return -1;
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	new_pte |= pte_set_hidx(ptep, rpte, subpg_index, slot, PTRS_PER_PTE);
2178c2ecf20Sopenharmony_ci	new_pte |= H_PAGE_HASHPTE;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	*ptep = __pte(new_pte & ~H_PAGE_BUSY);
2208c2ecf20Sopenharmony_ci	return 0;
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ciint __hash_page_64K(unsigned long ea, unsigned long access,
2248c2ecf20Sopenharmony_ci		    unsigned long vsid, pte_t *ptep, unsigned long trap,
2258c2ecf20Sopenharmony_ci		    unsigned long flags, int ssize)
2268c2ecf20Sopenharmony_ci{
2278c2ecf20Sopenharmony_ci	real_pte_t rpte;
2288c2ecf20Sopenharmony_ci	unsigned long hpte_group;
2298c2ecf20Sopenharmony_ci	unsigned long rflags, pa;
2308c2ecf20Sopenharmony_ci	unsigned long old_pte, new_pte;
2318c2ecf20Sopenharmony_ci	unsigned long vpn, hash, slot;
2328c2ecf20Sopenharmony_ci	unsigned long shift = mmu_psize_defs[MMU_PAGE_64K].shift;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	/*
2358c2ecf20Sopenharmony_ci	 * atomically mark the linux large page PTE busy and dirty
2368c2ecf20Sopenharmony_ci	 */
2378c2ecf20Sopenharmony_ci	do {
2388c2ecf20Sopenharmony_ci		pte_t pte = READ_ONCE(*ptep);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci		old_pte = pte_val(pte);
2418c2ecf20Sopenharmony_ci		/* If PTE busy, retry the access */
2428c2ecf20Sopenharmony_ci		if (unlikely(old_pte & H_PAGE_BUSY))
2438c2ecf20Sopenharmony_ci			return 0;
2448c2ecf20Sopenharmony_ci		/* If PTE permissions don't match, take page fault */
2458c2ecf20Sopenharmony_ci		if (unlikely(!check_pte_access(access, old_pte)))
2468c2ecf20Sopenharmony_ci			return 1;
2478c2ecf20Sopenharmony_ci		/*
2488c2ecf20Sopenharmony_ci		 * Check if PTE has the cache-inhibit bit set
2498c2ecf20Sopenharmony_ci		 * If so, bail out and refault as a 4k page
2508c2ecf20Sopenharmony_ci		 */
2518c2ecf20Sopenharmony_ci		if (!mmu_has_feature(MMU_FTR_CI_LARGE_PAGE) &&
2528c2ecf20Sopenharmony_ci		    unlikely(pte_ci(pte)))
2538c2ecf20Sopenharmony_ci			return 0;
2548c2ecf20Sopenharmony_ci		/*
2558c2ecf20Sopenharmony_ci		 * Try to lock the PTE, add ACCESSED and DIRTY if it was
2568c2ecf20Sopenharmony_ci		 * a write access.
2578c2ecf20Sopenharmony_ci		 */
2588c2ecf20Sopenharmony_ci		new_pte = old_pte | H_PAGE_BUSY | _PAGE_ACCESSED;
2598c2ecf20Sopenharmony_ci		if (access & _PAGE_WRITE)
2608c2ecf20Sopenharmony_ci			new_pte |= _PAGE_DIRTY;
2618c2ecf20Sopenharmony_ci	} while (!pte_xchg(ptep, __pte(old_pte), __pte(new_pte)));
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	rflags = htab_convert_pte_flags(new_pte);
2648c2ecf20Sopenharmony_ci	rpte = __real_pte(__pte(old_pte), ptep, PTRS_PER_PTE);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	if (cpu_has_feature(CPU_FTR_NOEXECUTE) &&
2678c2ecf20Sopenharmony_ci	    !cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
2688c2ecf20Sopenharmony_ci		rflags = hash_page_do_lazy_icache(rflags, __pte(old_pte), trap);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	vpn  = hpt_vpn(ea, vsid, ssize);
2718c2ecf20Sopenharmony_ci	if (unlikely(old_pte & H_PAGE_HASHPTE)) {
2728c2ecf20Sopenharmony_ci		unsigned long gslot;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci		/*
2758c2ecf20Sopenharmony_ci		 * There MIGHT be an HPTE for this pte
2768c2ecf20Sopenharmony_ci		 */
2778c2ecf20Sopenharmony_ci		gslot = pte_get_hash_gslot(vpn, shift, ssize, rpte, 0);
2788c2ecf20Sopenharmony_ci		if (mmu_hash_ops.hpte_updatepp(gslot, rflags, vpn, MMU_PAGE_64K,
2798c2ecf20Sopenharmony_ci					       MMU_PAGE_64K, ssize,
2808c2ecf20Sopenharmony_ci					       flags) == -1)
2818c2ecf20Sopenharmony_ci			old_pte &= ~_PAGE_HPTEFLAGS;
2828c2ecf20Sopenharmony_ci	}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	if (likely(!(old_pte & H_PAGE_HASHPTE))) {
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci		pa = pte_pfn(__pte(old_pte)) << PAGE_SHIFT;
2878c2ecf20Sopenharmony_ci		hash = hpt_hash(vpn, shift, ssize);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cirepeat:
2908c2ecf20Sopenharmony_ci		hpte_group = (hash & htab_hash_mask) * HPTES_PER_GROUP;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci		/* Insert into the hash table, primary slot */
2938c2ecf20Sopenharmony_ci		slot = mmu_hash_ops.hpte_insert(hpte_group, vpn, pa, rflags, 0,
2948c2ecf20Sopenharmony_ci						MMU_PAGE_64K, MMU_PAGE_64K,
2958c2ecf20Sopenharmony_ci						ssize);
2968c2ecf20Sopenharmony_ci		/*
2978c2ecf20Sopenharmony_ci		 * Primary is full, try the secondary
2988c2ecf20Sopenharmony_ci		 */
2998c2ecf20Sopenharmony_ci		if (unlikely(slot == -1)) {
3008c2ecf20Sopenharmony_ci			hpte_group = (~hash & htab_hash_mask) * HPTES_PER_GROUP;
3018c2ecf20Sopenharmony_ci			slot = mmu_hash_ops.hpte_insert(hpte_group, vpn, pa,
3028c2ecf20Sopenharmony_ci							rflags,
3038c2ecf20Sopenharmony_ci							HPTE_V_SECONDARY,
3048c2ecf20Sopenharmony_ci							MMU_PAGE_64K,
3058c2ecf20Sopenharmony_ci							MMU_PAGE_64K, ssize);
3068c2ecf20Sopenharmony_ci			if (slot == -1) {
3078c2ecf20Sopenharmony_ci				if (mftb() & 0x1)
3088c2ecf20Sopenharmony_ci					hpte_group = (hash & htab_hash_mask) *
3098c2ecf20Sopenharmony_ci							HPTES_PER_GROUP;
3108c2ecf20Sopenharmony_ci				mmu_hash_ops.hpte_remove(hpte_group);
3118c2ecf20Sopenharmony_ci				/*
3128c2ecf20Sopenharmony_ci				 * FIXME!! Should be try the group from which we removed ?
3138c2ecf20Sopenharmony_ci				 */
3148c2ecf20Sopenharmony_ci				goto repeat;
3158c2ecf20Sopenharmony_ci			}
3168c2ecf20Sopenharmony_ci		}
3178c2ecf20Sopenharmony_ci		/*
3188c2ecf20Sopenharmony_ci		 * Hypervisor failure. Restore old pte and return -1
3198c2ecf20Sopenharmony_ci		 * similar to __hash_page_*
3208c2ecf20Sopenharmony_ci		 */
3218c2ecf20Sopenharmony_ci		if (unlikely(slot == -2)) {
3228c2ecf20Sopenharmony_ci			*ptep = __pte(old_pte);
3238c2ecf20Sopenharmony_ci			hash_failure_debug(ea, access, vsid, trap, ssize,
3248c2ecf20Sopenharmony_ci					   MMU_PAGE_64K, MMU_PAGE_64K, old_pte);
3258c2ecf20Sopenharmony_ci			return -1;
3268c2ecf20Sopenharmony_ci		}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci		new_pte = (new_pte & ~_PAGE_HPTEFLAGS) | H_PAGE_HASHPTE;
3298c2ecf20Sopenharmony_ci		new_pte |= pte_set_hidx(ptep, rpte, 0, slot, PTRS_PER_PTE);
3308c2ecf20Sopenharmony_ci	}
3318c2ecf20Sopenharmony_ci	*ptep = __pte(new_pte & ~H_PAGE_BUSY);
3328c2ecf20Sopenharmony_ci	return 0;
3338c2ecf20Sopenharmony_ci}
334