18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef _ASM_POWERPC_BOOK3S_64_HUGETLB_H
38c2ecf20Sopenharmony_ci#define _ASM_POWERPC_BOOK3S_64_HUGETLB_H
48c2ecf20Sopenharmony_ci/*
58c2ecf20Sopenharmony_ci * For radix we want generic code to handle hugetlb. But then if we want
68c2ecf20Sopenharmony_ci * both hash and radix to be enabled together we need to workaround the
78c2ecf20Sopenharmony_ci * limitations.
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_civoid radix__flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
108c2ecf20Sopenharmony_civoid radix__local_flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
118c2ecf20Sopenharmony_ciextern unsigned long
128c2ecf20Sopenharmony_ciradix__hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
138c2ecf20Sopenharmony_ci				unsigned long len, unsigned long pgoff,
148c2ecf20Sopenharmony_ci				unsigned long flags);
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ciextern void radix__huge_ptep_modify_prot_commit(struct vm_area_struct *vma,
178c2ecf20Sopenharmony_ci						unsigned long addr, pte_t *ptep,
188c2ecf20Sopenharmony_ci						pte_t old_pte, pte_t pte);
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic inline int hstate_get_psize(struct hstate *hstate)
218c2ecf20Sopenharmony_ci{
228c2ecf20Sopenharmony_ci	unsigned long shift;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	shift = huge_page_shift(hstate);
258c2ecf20Sopenharmony_ci	if (shift == mmu_psize_defs[MMU_PAGE_2M].shift)
268c2ecf20Sopenharmony_ci		return MMU_PAGE_2M;
278c2ecf20Sopenharmony_ci	else if (shift == mmu_psize_defs[MMU_PAGE_1G].shift)
288c2ecf20Sopenharmony_ci		return MMU_PAGE_1G;
298c2ecf20Sopenharmony_ci	else if (shift == mmu_psize_defs[MMU_PAGE_16M].shift)
308c2ecf20Sopenharmony_ci		return MMU_PAGE_16M;
318c2ecf20Sopenharmony_ci	else if (shift == mmu_psize_defs[MMU_PAGE_16G].shift)
328c2ecf20Sopenharmony_ci		return MMU_PAGE_16G;
338c2ecf20Sopenharmony_ci	else {
348c2ecf20Sopenharmony_ci		WARN(1, "Wrong huge page shift\n");
358c2ecf20Sopenharmony_ci		return mmu_virtual_psize;
368c2ecf20Sopenharmony_ci	}
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define __HAVE_ARCH_GIGANTIC_PAGE_RUNTIME_SUPPORTED
408c2ecf20Sopenharmony_cistatic inline bool gigantic_page_runtime_supported(void)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	/*
438c2ecf20Sopenharmony_ci	 * We used gigantic page reservation with hypervisor assist in some case.
448c2ecf20Sopenharmony_ci	 * We cannot use runtime allocation of gigantic pages in those platforms
458c2ecf20Sopenharmony_ci	 * This is hash translation mode LPARs.
468c2ecf20Sopenharmony_ci	 */
478c2ecf20Sopenharmony_ci	if (firmware_has_feature(FW_FEATURE_LPAR) && !radix_enabled())
488c2ecf20Sopenharmony_ci		return false;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	return true;
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci/* hugepd entry valid bit */
548c2ecf20Sopenharmony_ci#define HUGEPD_VAL_BITS		(0x8000000000000000UL)
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define huge_ptep_modify_prot_start huge_ptep_modify_prot_start
578c2ecf20Sopenharmony_ciextern pte_t huge_ptep_modify_prot_start(struct vm_area_struct *vma,
588c2ecf20Sopenharmony_ci					 unsigned long addr, pte_t *ptep);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#define huge_ptep_modify_prot_commit huge_ptep_modify_prot_commit
618c2ecf20Sopenharmony_ciextern void huge_ptep_modify_prot_commit(struct vm_area_struct *vma,
628c2ecf20Sopenharmony_ci					 unsigned long addr, pte_t *ptep,
638c2ecf20Sopenharmony_ci					 pte_t old_pte, pte_t new_pte);
648c2ecf20Sopenharmony_ci/*
658c2ecf20Sopenharmony_ci * This should work for other subarchs too. But right now we use the
668c2ecf20Sopenharmony_ci * new format only for 64bit book3s
678c2ecf20Sopenharmony_ci */
688c2ecf20Sopenharmony_cistatic inline pte_t *hugepd_page(hugepd_t hpd)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	BUG_ON(!hugepd_ok(hpd));
718c2ecf20Sopenharmony_ci	/*
728c2ecf20Sopenharmony_ci	 * We have only four bits to encode, MMU page size
738c2ecf20Sopenharmony_ci	 */
748c2ecf20Sopenharmony_ci	BUILD_BUG_ON((MMU_PAGE_COUNT - 1) > 0xf);
758c2ecf20Sopenharmony_ci	return __va(hpd_val(hpd) & HUGEPD_ADDR_MASK);
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic inline unsigned int hugepd_mmu_psize(hugepd_t hpd)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	return (hpd_val(hpd) & HUGEPD_SHIFT_MASK) >> 2;
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic inline unsigned int hugepd_shift(hugepd_t hpd)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	return mmu_psize_to_shift(hugepd_mmu_psize(hpd));
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_cistatic inline void flush_hugetlb_page(struct vm_area_struct *vma,
888c2ecf20Sopenharmony_ci				      unsigned long vmaddr)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	if (radix_enabled())
918c2ecf20Sopenharmony_ci		return radix__flush_hugetlb_page(vma, vmaddr);
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic inline pte_t *hugepte_offset(hugepd_t hpd, unsigned long addr,
958c2ecf20Sopenharmony_ci				    unsigned int pdshift)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	unsigned long idx = (addr & ((1UL << pdshift) - 1)) >> hugepd_shift(hpd);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	return hugepd_page(hpd) + idx;
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic inline void hugepd_populate(hugepd_t *hpdp, pte_t *new, unsigned int pshift)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	*hpdp = __hugepd(__pa(new) | HUGEPD_VAL_BITS | (shift_to_mmu_psize(pshift) << 2));
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_civoid flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic inline int check_and_get_huge_psize(int shift)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	int mmu_psize;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	if (shift > SLICE_HIGH_SHIFT)
1148c2ecf20Sopenharmony_ci		return -EINVAL;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	mmu_psize = shift_to_mmu_psize(shift);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	/*
1198c2ecf20Sopenharmony_ci	 * We need to make sure that for different page sizes reported by
1208c2ecf20Sopenharmony_ci	 * firmware we only add hugetlb support for page sizes that can be
1218c2ecf20Sopenharmony_ci	 * supported by linux page table layout.
1228c2ecf20Sopenharmony_ci	 * For now we have
1238c2ecf20Sopenharmony_ci	 * Radix: 2M and 1G
1248c2ecf20Sopenharmony_ci	 * Hash: 16M and 16G
1258c2ecf20Sopenharmony_ci	 */
1268c2ecf20Sopenharmony_ci	if (radix_enabled()) {
1278c2ecf20Sopenharmony_ci		if (mmu_psize != MMU_PAGE_2M && mmu_psize != MMU_PAGE_1G)
1288c2ecf20Sopenharmony_ci			return -EINVAL;
1298c2ecf20Sopenharmony_ci	} else {
1308c2ecf20Sopenharmony_ci		if (mmu_psize != MMU_PAGE_16M && mmu_psize != MMU_PAGE_16G)
1318c2ecf20Sopenharmony_ci			return -EINVAL;
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci	return mmu_psize;
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci#endif
137