162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/hugetlb.h>
362306a36Sopenharmony_ci#include <linux/err.h>
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#ifdef CONFIG_RISCV_ISA_SVNAPOT
662306a36Sopenharmony_cipte_t huge_ptep_get(pte_t *ptep)
762306a36Sopenharmony_ci{
862306a36Sopenharmony_ci	unsigned long pte_num;
962306a36Sopenharmony_ci	int i;
1062306a36Sopenharmony_ci	pte_t orig_pte = ptep_get(ptep);
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci	if (!pte_present(orig_pte) || !pte_napot(orig_pte))
1362306a36Sopenharmony_ci		return orig_pte;
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci	pte_num = napot_pte_num(napot_cont_order(orig_pte));
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci	for (i = 0; i < pte_num; i++, ptep++) {
1862306a36Sopenharmony_ci		pte_t pte = ptep_get(ptep);
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci		if (pte_dirty(pte))
2162306a36Sopenharmony_ci			orig_pte = pte_mkdirty(orig_pte);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci		if (pte_young(pte))
2462306a36Sopenharmony_ci			orig_pte = pte_mkyoung(orig_pte);
2562306a36Sopenharmony_ci	}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	return orig_pte;
2862306a36Sopenharmony_ci}
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cipte_t *huge_pte_alloc(struct mm_struct *mm,
3162306a36Sopenharmony_ci		      struct vm_area_struct *vma,
3262306a36Sopenharmony_ci		      unsigned long addr,
3362306a36Sopenharmony_ci		      unsigned long sz)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	unsigned long order;
3662306a36Sopenharmony_ci	pte_t *pte = NULL;
3762306a36Sopenharmony_ci	pgd_t *pgd;
3862306a36Sopenharmony_ci	p4d_t *p4d;
3962306a36Sopenharmony_ci	pud_t *pud;
4062306a36Sopenharmony_ci	pmd_t *pmd;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	pgd = pgd_offset(mm, addr);
4362306a36Sopenharmony_ci	p4d = p4d_alloc(mm, pgd, addr);
4462306a36Sopenharmony_ci	if (!p4d)
4562306a36Sopenharmony_ci		return NULL;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	pud = pud_alloc(mm, p4d, addr);
4862306a36Sopenharmony_ci	if (!pud)
4962306a36Sopenharmony_ci		return NULL;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	if (sz == PUD_SIZE) {
5262306a36Sopenharmony_ci		pte = (pte_t *)pud;
5362306a36Sopenharmony_ci		goto out;
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	if (sz == PMD_SIZE) {
5762306a36Sopenharmony_ci		if (want_pmd_share(vma, addr) && pud_none(*pud))
5862306a36Sopenharmony_ci			pte = huge_pmd_share(mm, vma, addr, pud);
5962306a36Sopenharmony_ci		else
6062306a36Sopenharmony_ci			pte = (pte_t *)pmd_alloc(mm, pud, addr);
6162306a36Sopenharmony_ci		goto out;
6262306a36Sopenharmony_ci	}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	pmd = pmd_alloc(mm, pud, addr);
6562306a36Sopenharmony_ci	if (!pmd)
6662306a36Sopenharmony_ci		return NULL;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	for_each_napot_order(order) {
6962306a36Sopenharmony_ci		if (napot_cont_size(order) == sz) {
7062306a36Sopenharmony_ci			pte = pte_alloc_huge(mm, pmd, addr & napot_cont_mask(order));
7162306a36Sopenharmony_ci			break;
7262306a36Sopenharmony_ci		}
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ciout:
7662306a36Sopenharmony_ci	if (pte) {
7762306a36Sopenharmony_ci		pte_t pteval = ptep_get_lockless(pte);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci		WARN_ON_ONCE(pte_present(pteval) && !pte_huge(pteval));
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci	return pte;
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cipte_t *huge_pte_offset(struct mm_struct *mm,
8562306a36Sopenharmony_ci		       unsigned long addr,
8662306a36Sopenharmony_ci		       unsigned long sz)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	unsigned long order;
8962306a36Sopenharmony_ci	pte_t *pte = NULL;
9062306a36Sopenharmony_ci	pgd_t *pgd;
9162306a36Sopenharmony_ci	p4d_t *p4d;
9262306a36Sopenharmony_ci	pud_t *pud;
9362306a36Sopenharmony_ci	pmd_t *pmd;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	pgd = pgd_offset(mm, addr);
9662306a36Sopenharmony_ci	if (!pgd_present(*pgd))
9762306a36Sopenharmony_ci		return NULL;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	p4d = p4d_offset(pgd, addr);
10062306a36Sopenharmony_ci	if (!p4d_present(*p4d))
10162306a36Sopenharmony_ci		return NULL;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	pud = pud_offset(p4d, addr);
10462306a36Sopenharmony_ci	if (sz == PUD_SIZE)
10562306a36Sopenharmony_ci		/* must be pud huge, non-present or none */
10662306a36Sopenharmony_ci		return (pte_t *)pud;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (!pud_present(*pud))
10962306a36Sopenharmony_ci		return NULL;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	pmd = pmd_offset(pud, addr);
11262306a36Sopenharmony_ci	if (sz == PMD_SIZE)
11362306a36Sopenharmony_ci		/* must be pmd huge, non-present or none */
11462306a36Sopenharmony_ci		return (pte_t *)pmd;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if (!pmd_present(*pmd))
11762306a36Sopenharmony_ci		return NULL;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	for_each_napot_order(order) {
12062306a36Sopenharmony_ci		if (napot_cont_size(order) == sz) {
12162306a36Sopenharmony_ci			pte = pte_offset_huge(pmd, addr & napot_cont_mask(order));
12262306a36Sopenharmony_ci			break;
12362306a36Sopenharmony_ci		}
12462306a36Sopenharmony_ci	}
12562306a36Sopenharmony_ci	return pte;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ciunsigned long hugetlb_mask_last_page(struct hstate *h)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	unsigned long hp_size = huge_page_size(h);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	switch (hp_size) {
13362306a36Sopenharmony_ci#ifndef __PAGETABLE_PMD_FOLDED
13462306a36Sopenharmony_ci	case PUD_SIZE:
13562306a36Sopenharmony_ci		return P4D_SIZE - PUD_SIZE;
13662306a36Sopenharmony_ci#endif
13762306a36Sopenharmony_ci	case PMD_SIZE:
13862306a36Sopenharmony_ci		return PUD_SIZE - PMD_SIZE;
13962306a36Sopenharmony_ci	case napot_cont_size(NAPOT_CONT64KB_ORDER):
14062306a36Sopenharmony_ci		return PMD_SIZE - napot_cont_size(NAPOT_CONT64KB_ORDER);
14162306a36Sopenharmony_ci	default:
14262306a36Sopenharmony_ci		break;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	return 0UL;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic pte_t get_clear_contig(struct mm_struct *mm,
14962306a36Sopenharmony_ci			      unsigned long addr,
15062306a36Sopenharmony_ci			      pte_t *ptep,
15162306a36Sopenharmony_ci			      unsigned long pte_num)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	pte_t orig_pte = ptep_get(ptep);
15462306a36Sopenharmony_ci	unsigned long i;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	for (i = 0; i < pte_num; i++, addr += PAGE_SIZE, ptep++) {
15762306a36Sopenharmony_ci		pte_t pte = ptep_get_and_clear(mm, addr, ptep);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci		if (pte_dirty(pte))
16062306a36Sopenharmony_ci			orig_pte = pte_mkdirty(orig_pte);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci		if (pte_young(pte))
16362306a36Sopenharmony_ci			orig_pte = pte_mkyoung(orig_pte);
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	return orig_pte;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic pte_t get_clear_contig_flush(struct mm_struct *mm,
17062306a36Sopenharmony_ci				    unsigned long addr,
17162306a36Sopenharmony_ci				    pte_t *ptep,
17262306a36Sopenharmony_ci				    unsigned long pte_num)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	pte_t orig_pte = get_clear_contig(mm, addr, ptep, pte_num);
17562306a36Sopenharmony_ci	struct vm_area_struct vma = TLB_FLUSH_VMA(mm, 0);
17662306a36Sopenharmony_ci	bool valid = !pte_none(orig_pte);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	if (valid)
17962306a36Sopenharmony_ci		flush_tlb_range(&vma, addr, addr + (PAGE_SIZE * pte_num));
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	return orig_pte;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cipte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	unsigned long order;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	for_each_napot_order(order) {
18962306a36Sopenharmony_ci		if (shift == napot_cont_shift(order)) {
19062306a36Sopenharmony_ci			entry = pte_mknapot(entry, order);
19162306a36Sopenharmony_ci			break;
19262306a36Sopenharmony_ci		}
19362306a36Sopenharmony_ci	}
19462306a36Sopenharmony_ci	if (order == NAPOT_ORDER_MAX)
19562306a36Sopenharmony_ci		entry = pte_mkhuge(entry);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	return entry;
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic void clear_flush(struct mm_struct *mm,
20162306a36Sopenharmony_ci			unsigned long addr,
20262306a36Sopenharmony_ci			pte_t *ptep,
20362306a36Sopenharmony_ci			unsigned long pgsize,
20462306a36Sopenharmony_ci			unsigned long ncontig)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	struct vm_area_struct vma = TLB_FLUSH_VMA(mm, 0);
20762306a36Sopenharmony_ci	unsigned long i, saddr = addr;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	for (i = 0; i < ncontig; i++, addr += pgsize, ptep++)
21062306a36Sopenharmony_ci		ptep_get_and_clear(mm, addr, ptep);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	flush_tlb_range(&vma, saddr, addr);
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci/*
21662306a36Sopenharmony_ci * When dealing with NAPOT mappings, the privileged specification indicates that
21762306a36Sopenharmony_ci * "if an update needs to be made, the OS generally should first mark all of the
21862306a36Sopenharmony_ci * PTEs invalid, then issue SFENCE.VMA instruction(s) covering all 4 KiB regions
21962306a36Sopenharmony_ci * within the range, [...] then update the PTE(s), as described in Section
22062306a36Sopenharmony_ci * 4.2.1.". That's the equivalent of the Break-Before-Make approach used by
22162306a36Sopenharmony_ci * arm64.
22262306a36Sopenharmony_ci */
22362306a36Sopenharmony_civoid set_huge_pte_at(struct mm_struct *mm,
22462306a36Sopenharmony_ci		     unsigned long addr,
22562306a36Sopenharmony_ci		     pte_t *ptep,
22662306a36Sopenharmony_ci		     pte_t pte,
22762306a36Sopenharmony_ci		     unsigned long sz)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	unsigned long hugepage_shift, pgsize;
23062306a36Sopenharmony_ci	int i, pte_num;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	if (sz >= PGDIR_SIZE)
23362306a36Sopenharmony_ci		hugepage_shift = PGDIR_SHIFT;
23462306a36Sopenharmony_ci	else if (sz >= P4D_SIZE)
23562306a36Sopenharmony_ci		hugepage_shift = P4D_SHIFT;
23662306a36Sopenharmony_ci	else if (sz >= PUD_SIZE)
23762306a36Sopenharmony_ci		hugepage_shift = PUD_SHIFT;
23862306a36Sopenharmony_ci	else if (sz >= PMD_SIZE)
23962306a36Sopenharmony_ci		hugepage_shift = PMD_SHIFT;
24062306a36Sopenharmony_ci	else
24162306a36Sopenharmony_ci		hugepage_shift = PAGE_SHIFT;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	pte_num = sz >> hugepage_shift;
24462306a36Sopenharmony_ci	pgsize = 1 << hugepage_shift;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	if (!pte_present(pte)) {
24762306a36Sopenharmony_ci		for (i = 0; i < pte_num; i++, ptep++, addr += pgsize)
24862306a36Sopenharmony_ci			set_ptes(mm, addr, ptep, pte, 1);
24962306a36Sopenharmony_ci		return;
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	if (!pte_napot(pte)) {
25362306a36Sopenharmony_ci		set_ptes(mm, addr, ptep, pte, 1);
25462306a36Sopenharmony_ci		return;
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	clear_flush(mm, addr, ptep, pgsize, pte_num);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	for (i = 0; i < pte_num; i++, ptep++, addr += pgsize)
26062306a36Sopenharmony_ci		set_pte_at(mm, addr, ptep, pte);
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ciint huge_ptep_set_access_flags(struct vm_area_struct *vma,
26462306a36Sopenharmony_ci			       unsigned long addr,
26562306a36Sopenharmony_ci			       pte_t *ptep,
26662306a36Sopenharmony_ci			       pte_t pte,
26762306a36Sopenharmony_ci			       int dirty)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	struct mm_struct *mm = vma->vm_mm;
27062306a36Sopenharmony_ci	unsigned long order;
27162306a36Sopenharmony_ci	pte_t orig_pte;
27262306a36Sopenharmony_ci	int i, pte_num;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	if (!pte_napot(pte))
27562306a36Sopenharmony_ci		return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	order = napot_cont_order(pte);
27862306a36Sopenharmony_ci	pte_num = napot_pte_num(order);
27962306a36Sopenharmony_ci	ptep = huge_pte_offset(mm, addr, napot_cont_size(order));
28062306a36Sopenharmony_ci	orig_pte = get_clear_contig_flush(mm, addr, ptep, pte_num);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	if (pte_dirty(orig_pte))
28362306a36Sopenharmony_ci		pte = pte_mkdirty(pte);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if (pte_young(orig_pte))
28662306a36Sopenharmony_ci		pte = pte_mkyoung(pte);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	for (i = 0; i < pte_num; i++, addr += PAGE_SIZE, ptep++)
28962306a36Sopenharmony_ci		set_pte_at(mm, addr, ptep, pte);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	return true;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cipte_t huge_ptep_get_and_clear(struct mm_struct *mm,
29562306a36Sopenharmony_ci			      unsigned long addr,
29662306a36Sopenharmony_ci			      pte_t *ptep)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	pte_t orig_pte = ptep_get(ptep);
29962306a36Sopenharmony_ci	int pte_num;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (!pte_napot(orig_pte))
30262306a36Sopenharmony_ci		return ptep_get_and_clear(mm, addr, ptep);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	pte_num = napot_pte_num(napot_cont_order(orig_pte));
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	return get_clear_contig(mm, addr, ptep, pte_num);
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_civoid huge_ptep_set_wrprotect(struct mm_struct *mm,
31062306a36Sopenharmony_ci			     unsigned long addr,
31162306a36Sopenharmony_ci			     pte_t *ptep)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	pte_t pte = ptep_get(ptep);
31462306a36Sopenharmony_ci	unsigned long order;
31562306a36Sopenharmony_ci	pte_t orig_pte;
31662306a36Sopenharmony_ci	int i, pte_num;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	if (!pte_napot(pte)) {
31962306a36Sopenharmony_ci		ptep_set_wrprotect(mm, addr, ptep);
32062306a36Sopenharmony_ci		return;
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	order = napot_cont_order(pte);
32462306a36Sopenharmony_ci	pte_num = napot_pte_num(order);
32562306a36Sopenharmony_ci	ptep = huge_pte_offset(mm, addr, napot_cont_size(order));
32662306a36Sopenharmony_ci	orig_pte = get_clear_contig_flush(mm, addr, ptep, pte_num);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	orig_pte = pte_wrprotect(orig_pte);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	for (i = 0; i < pte_num; i++, addr += PAGE_SIZE, ptep++)
33162306a36Sopenharmony_ci		set_pte_at(mm, addr, ptep, orig_pte);
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cipte_t huge_ptep_clear_flush(struct vm_area_struct *vma,
33562306a36Sopenharmony_ci			    unsigned long addr,
33662306a36Sopenharmony_ci			    pte_t *ptep)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	pte_t pte = ptep_get(ptep);
33962306a36Sopenharmony_ci	int pte_num;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	if (!pte_napot(pte))
34262306a36Sopenharmony_ci		return ptep_clear_flush(vma, addr, ptep);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	pte_num = napot_pte_num(napot_cont_order(pte));
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	return get_clear_contig_flush(vma->vm_mm, addr, ptep, pte_num);
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_civoid huge_pte_clear(struct mm_struct *mm,
35062306a36Sopenharmony_ci		    unsigned long addr,
35162306a36Sopenharmony_ci		    pte_t *ptep,
35262306a36Sopenharmony_ci		    unsigned long sz)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	pte_t pte = READ_ONCE(*ptep);
35562306a36Sopenharmony_ci	int i, pte_num;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	if (!pte_napot(pte)) {
35862306a36Sopenharmony_ci		pte_clear(mm, addr, ptep);
35962306a36Sopenharmony_ci		return;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	pte_num = napot_pte_num(napot_cont_order(pte));
36362306a36Sopenharmony_ci	for (i = 0; i < pte_num; i++, addr += PAGE_SIZE, ptep++)
36462306a36Sopenharmony_ci		pte_clear(mm, addr, ptep);
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic bool is_napot_size(unsigned long size)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	unsigned long order;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (!has_svnapot())
37262306a36Sopenharmony_ci		return false;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	for_each_napot_order(order) {
37562306a36Sopenharmony_ci		if (size == napot_cont_size(order))
37662306a36Sopenharmony_ci			return true;
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci	return false;
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic __init int napot_hugetlbpages_init(void)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	if (has_svnapot()) {
38462306a36Sopenharmony_ci		unsigned long order;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci		for_each_napot_order(order)
38762306a36Sopenharmony_ci			hugetlb_add_hstate(order);
38862306a36Sopenharmony_ci	}
38962306a36Sopenharmony_ci	return 0;
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ciarch_initcall(napot_hugetlbpages_init);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci#else
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_cistatic bool is_napot_size(unsigned long size)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	return false;
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci#endif /*CONFIG_RISCV_ISA_SVNAPOT*/
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ciint pud_huge(pud_t pud)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	return pud_leaf(pud);
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ciint pmd_huge(pmd_t pmd)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	return pmd_leaf(pmd);
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_cistatic bool __hugetlb_valid_size(unsigned long size)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	if (size == HPAGE_SIZE)
41562306a36Sopenharmony_ci		return true;
41662306a36Sopenharmony_ci	else if (IS_ENABLED(CONFIG_64BIT) && size == PUD_SIZE)
41762306a36Sopenharmony_ci		return true;
41862306a36Sopenharmony_ci	else if (is_napot_size(size))
41962306a36Sopenharmony_ci		return true;
42062306a36Sopenharmony_ci	else
42162306a36Sopenharmony_ci		return false;
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cibool __init arch_hugetlb_valid_size(unsigned long size)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	return __hugetlb_valid_size(size);
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci#ifdef CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION
43062306a36Sopenharmony_cibool arch_hugetlb_migration_supported(struct hstate *h)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	return __hugetlb_valid_size(huge_page_size(h));
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci#endif
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci#ifdef CONFIG_CONTIG_ALLOC
43762306a36Sopenharmony_cistatic __init int gigantic_pages_init(void)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	/* With CONTIG_ALLOC, we can allocate gigantic pages at runtime */
44062306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_64BIT))
44162306a36Sopenharmony_ci		hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT);
44262306a36Sopenharmony_ci	return 0;
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ciarch_initcall(gigantic_pages_init);
44562306a36Sopenharmony_ci#endif
446