19e953cdaSAlexandre Ghiti // SPDX-License-Identifier: GPL-2.0
29e953cdaSAlexandre Ghiti #include <linux/hugetlb.h>
39e953cdaSAlexandre Ghiti #include <linux/err.h>
49e953cdaSAlexandre Ghiti
582a1a1f3SQinglin Pan #ifdef CONFIG_RISCV_ISA_SVNAPOT
huge_ptep_get(pte_t * ptep)66966d798SAlexandre Ghiti pte_t huge_ptep_get(pte_t *ptep)
76966d798SAlexandre Ghiti {
86966d798SAlexandre Ghiti unsigned long pte_num;
96966d798SAlexandre Ghiti int i;
106966d798SAlexandre Ghiti pte_t orig_pte = ptep_get(ptep);
116966d798SAlexandre Ghiti
126966d798SAlexandre Ghiti if (!pte_present(orig_pte) || !pte_napot(orig_pte))
136966d798SAlexandre Ghiti return orig_pte;
146966d798SAlexandre Ghiti
156966d798SAlexandre Ghiti pte_num = napot_pte_num(napot_cont_order(orig_pte));
166966d798SAlexandre Ghiti
176966d798SAlexandre Ghiti for (i = 0; i < pte_num; i++, ptep++) {
186966d798SAlexandre Ghiti pte_t pte = ptep_get(ptep);
196966d798SAlexandre Ghiti
206966d798SAlexandre Ghiti if (pte_dirty(pte))
216966d798SAlexandre Ghiti orig_pte = pte_mkdirty(orig_pte);
226966d798SAlexandre Ghiti
236966d798SAlexandre Ghiti if (pte_young(pte))
246966d798SAlexandre Ghiti orig_pte = pte_mkyoung(orig_pte);
256966d798SAlexandre Ghiti }
266966d798SAlexandre Ghiti
276966d798SAlexandre Ghiti return orig_pte;
286966d798SAlexandre Ghiti }
296966d798SAlexandre Ghiti
huge_pte_alloc(struct mm_struct * mm,struct vm_area_struct * vma,unsigned long addr,unsigned long sz)3082a1a1f3SQinglin Pan pte_t *huge_pte_alloc(struct mm_struct *mm,
3182a1a1f3SQinglin Pan struct vm_area_struct *vma,
3282a1a1f3SQinglin Pan unsigned long addr,
3382a1a1f3SQinglin Pan unsigned long sz)
3482a1a1f3SQinglin Pan {
3582a1a1f3SQinglin Pan unsigned long order;
3682a1a1f3SQinglin Pan pte_t *pte = NULL;
3782a1a1f3SQinglin Pan pgd_t *pgd;
3882a1a1f3SQinglin Pan p4d_t *p4d;
3982a1a1f3SQinglin Pan pud_t *pud;
4082a1a1f3SQinglin Pan pmd_t *pmd;
4182a1a1f3SQinglin Pan
4282a1a1f3SQinglin Pan pgd = pgd_offset(mm, addr);
4382a1a1f3SQinglin Pan p4d = p4d_alloc(mm, pgd, addr);
4482a1a1f3SQinglin Pan if (!p4d)
4582a1a1f3SQinglin Pan return NULL;
4682a1a1f3SQinglin Pan
4782a1a1f3SQinglin Pan pud = pud_alloc(mm, p4d, addr);
4882a1a1f3SQinglin Pan if (!pud)
4982a1a1f3SQinglin Pan return NULL;
5082a1a1f3SQinglin Pan
5182a1a1f3SQinglin Pan if (sz == PUD_SIZE) {
5282a1a1f3SQinglin Pan pte = (pte_t *)pud;
5382a1a1f3SQinglin Pan goto out;
5482a1a1f3SQinglin Pan }
5582a1a1f3SQinglin Pan
5682a1a1f3SQinglin Pan if (sz == PMD_SIZE) {
57e0316069SAlexandre Ghiti if (want_pmd_share(vma, addr) && pud_none(pudp_get(pud)))
5882a1a1f3SQinglin Pan pte = huge_pmd_share(mm, vma, addr, pud);
5982a1a1f3SQinglin Pan else
6082a1a1f3SQinglin Pan pte = (pte_t *)pmd_alloc(mm, pud, addr);
6182a1a1f3SQinglin Pan goto out;
6282a1a1f3SQinglin Pan }
6382a1a1f3SQinglin Pan
6482a1a1f3SQinglin Pan pmd = pmd_alloc(mm, pud, addr);
6582a1a1f3SQinglin Pan if (!pmd)
6682a1a1f3SQinglin Pan return NULL;
6782a1a1f3SQinglin Pan
6882a1a1f3SQinglin Pan for_each_napot_order(order) {
6982a1a1f3SQinglin Pan if (napot_cont_size(order) == sz) {
70893f667fSHugh Dickins pte = pte_alloc_huge(mm, pmd, addr & napot_cont_mask(order));
7182a1a1f3SQinglin Pan break;
7282a1a1f3SQinglin Pan }
7382a1a1f3SQinglin Pan }
7482a1a1f3SQinglin Pan
7582a1a1f3SQinglin Pan out:
7662ba41d2SJohn Hubbard if (pte) {
7762ba41d2SJohn Hubbard pte_t pteval = ptep_get_lockless(pte);
7862ba41d2SJohn Hubbard
7962ba41d2SJohn Hubbard WARN_ON_ONCE(pte_present(pteval) && !pte_huge(pteval));
8062ba41d2SJohn Hubbard }
8182a1a1f3SQinglin Pan return pte;
8282a1a1f3SQinglin Pan }
8382a1a1f3SQinglin Pan
huge_pte_offset(struct mm_struct * mm,unsigned long addr,unsigned long sz)8482a1a1f3SQinglin Pan pte_t *huge_pte_offset(struct mm_struct *mm,
8582a1a1f3SQinglin Pan unsigned long addr,
8682a1a1f3SQinglin Pan unsigned long sz)
8782a1a1f3SQinglin Pan {
8882a1a1f3SQinglin Pan unsigned long order;
8982a1a1f3SQinglin Pan pte_t *pte = NULL;
9082a1a1f3SQinglin Pan pgd_t *pgd;
9182a1a1f3SQinglin Pan p4d_t *p4d;
9282a1a1f3SQinglin Pan pud_t *pud;
9382a1a1f3SQinglin Pan pmd_t *pmd;
9482a1a1f3SQinglin Pan
9582a1a1f3SQinglin Pan pgd = pgd_offset(mm, addr);
96e0316069SAlexandre Ghiti if (!pgd_present(pgdp_get(pgd)))
9782a1a1f3SQinglin Pan return NULL;
9882a1a1f3SQinglin Pan
9982a1a1f3SQinglin Pan p4d = p4d_offset(pgd, addr);
100e0316069SAlexandre Ghiti if (!p4d_present(p4dp_get(p4d)))
10182a1a1f3SQinglin Pan return NULL;
10282a1a1f3SQinglin Pan
10382a1a1f3SQinglin Pan pud = pud_offset(p4d, addr);
10482a1a1f3SQinglin Pan if (sz == PUD_SIZE)
10582a1a1f3SQinglin Pan /* must be pud huge, non-present or none */
10682a1a1f3SQinglin Pan return (pte_t *)pud;
10782a1a1f3SQinglin Pan
108e0316069SAlexandre Ghiti if (!pud_present(pudp_get(pud)))
10982a1a1f3SQinglin Pan return NULL;
11082a1a1f3SQinglin Pan
11182a1a1f3SQinglin Pan pmd = pmd_offset(pud, addr);
11282a1a1f3SQinglin Pan if (sz == PMD_SIZE)
11382a1a1f3SQinglin Pan /* must be pmd huge, non-present or none */
11482a1a1f3SQinglin Pan return (pte_t *)pmd;
11582a1a1f3SQinglin Pan
116e0316069SAlexandre Ghiti if (!pmd_present(pmdp_get(pmd)))
11782a1a1f3SQinglin Pan return NULL;
11882a1a1f3SQinglin Pan
11982a1a1f3SQinglin Pan for_each_napot_order(order) {
12082a1a1f3SQinglin Pan if (napot_cont_size(order) == sz) {
121893f667fSHugh Dickins pte = pte_offset_huge(pmd, addr & napot_cont_mask(order));
12282a1a1f3SQinglin Pan break;
12382a1a1f3SQinglin Pan }
12482a1a1f3SQinglin Pan }
12582a1a1f3SQinglin Pan return pte;
12682a1a1f3SQinglin Pan }
12782a1a1f3SQinglin Pan
hugetlb_mask_last_page(struct hstate * h)128d0d1f9a9SAlexandre Ghiti unsigned long hugetlb_mask_last_page(struct hstate *h)
129d0d1f9a9SAlexandre Ghiti {
130d0d1f9a9SAlexandre Ghiti unsigned long hp_size = huge_page_size(h);
131d0d1f9a9SAlexandre Ghiti
132d0d1f9a9SAlexandre Ghiti switch (hp_size) {
133d0d1f9a9SAlexandre Ghiti #ifndef __PAGETABLE_PMD_FOLDED
134d0d1f9a9SAlexandre Ghiti case PUD_SIZE:
135d0d1f9a9SAlexandre Ghiti return P4D_SIZE - PUD_SIZE;
136d0d1f9a9SAlexandre Ghiti #endif
137d0d1f9a9SAlexandre Ghiti case PMD_SIZE:
138d0d1f9a9SAlexandre Ghiti return PUD_SIZE - PMD_SIZE;
139d0d1f9a9SAlexandre Ghiti case napot_cont_size(NAPOT_CONT64KB_ORDER):
140d0d1f9a9SAlexandre Ghiti return PMD_SIZE - napot_cont_size(NAPOT_CONT64KB_ORDER);
141d0d1f9a9SAlexandre Ghiti default:
142d0d1f9a9SAlexandre Ghiti break;
143d0d1f9a9SAlexandre Ghiti }
144d0d1f9a9SAlexandre Ghiti
145d0d1f9a9SAlexandre Ghiti return 0UL;
146d0d1f9a9SAlexandre Ghiti }
147d0d1f9a9SAlexandre Ghiti
get_clear_contig(struct mm_struct * mm,unsigned long addr,pte_t * ptep,unsigned long pte_num)14882a1a1f3SQinglin Pan static pte_t get_clear_contig(struct mm_struct *mm,
14982a1a1f3SQinglin Pan unsigned long addr,
15082a1a1f3SQinglin Pan pte_t *ptep,
15182a1a1f3SQinglin Pan unsigned long pte_num)
15282a1a1f3SQinglin Pan {
15382a1a1f3SQinglin Pan pte_t orig_pte = ptep_get(ptep);
15482a1a1f3SQinglin Pan unsigned long i;
15582a1a1f3SQinglin Pan
15682a1a1f3SQinglin Pan for (i = 0; i < pte_num; i++, addr += PAGE_SIZE, ptep++) {
15782a1a1f3SQinglin Pan pte_t pte = ptep_get_and_clear(mm, addr, ptep);
15882a1a1f3SQinglin Pan
15982a1a1f3SQinglin Pan if (pte_dirty(pte))
16082a1a1f3SQinglin Pan orig_pte = pte_mkdirty(orig_pte);
16182a1a1f3SQinglin Pan
16282a1a1f3SQinglin Pan if (pte_young(pte))
16382a1a1f3SQinglin Pan orig_pte = pte_mkyoung(orig_pte);
16482a1a1f3SQinglin Pan }
16582a1a1f3SQinglin Pan
16682a1a1f3SQinglin Pan return orig_pte;
16782a1a1f3SQinglin Pan }
16882a1a1f3SQinglin Pan
get_clear_contig_flush(struct mm_struct * mm,unsigned long addr,pte_t * ptep,unsigned long pte_num)16982a1a1f3SQinglin Pan static pte_t get_clear_contig_flush(struct mm_struct *mm,
17082a1a1f3SQinglin Pan unsigned long addr,
17182a1a1f3SQinglin Pan pte_t *ptep,
17282a1a1f3SQinglin Pan unsigned long pte_num)
17382a1a1f3SQinglin Pan {
17482a1a1f3SQinglin Pan pte_t orig_pte = get_clear_contig(mm, addr, ptep, pte_num);
17582a1a1f3SQinglin Pan struct vm_area_struct vma = TLB_FLUSH_VMA(mm, 0);
17682a1a1f3SQinglin Pan bool valid = !pte_none(orig_pte);
17782a1a1f3SQinglin Pan
17882a1a1f3SQinglin Pan if (valid)
17982a1a1f3SQinglin Pan flush_tlb_range(&vma, addr, addr + (PAGE_SIZE * pte_num));
18082a1a1f3SQinglin Pan
18182a1a1f3SQinglin Pan return orig_pte;
18282a1a1f3SQinglin Pan }
18382a1a1f3SQinglin Pan
arch_make_huge_pte(pte_t entry,unsigned int shift,vm_flags_t flags)18482a1a1f3SQinglin Pan pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags)
18582a1a1f3SQinglin Pan {
18682a1a1f3SQinglin Pan unsigned long order;
18782a1a1f3SQinglin Pan
18882a1a1f3SQinglin Pan for_each_napot_order(order) {
18982a1a1f3SQinglin Pan if (shift == napot_cont_shift(order)) {
19082a1a1f3SQinglin Pan entry = pte_mknapot(entry, order);
19182a1a1f3SQinglin Pan break;
19282a1a1f3SQinglin Pan }
19382a1a1f3SQinglin Pan }
19482a1a1f3SQinglin Pan if (order == NAPOT_ORDER_MAX)
19582a1a1f3SQinglin Pan entry = pte_mkhuge(entry);
19682a1a1f3SQinglin Pan
19782a1a1f3SQinglin Pan return entry;
19882a1a1f3SQinglin Pan }
19982a1a1f3SQinglin Pan
clear_flush(struct mm_struct * mm,unsigned long addr,pte_t * ptep,unsigned long pgsize,unsigned long ncontig)20021dba4e4SAlexandre Ghiti static void clear_flush(struct mm_struct *mm,
20121dba4e4SAlexandre Ghiti unsigned long addr,
20221dba4e4SAlexandre Ghiti pte_t *ptep,
20321dba4e4SAlexandre Ghiti unsigned long pgsize,
20421dba4e4SAlexandre Ghiti unsigned long ncontig)
20521dba4e4SAlexandre Ghiti {
20621dba4e4SAlexandre Ghiti struct vm_area_struct vma = TLB_FLUSH_VMA(mm, 0);
20721dba4e4SAlexandre Ghiti unsigned long i, saddr = addr;
20821dba4e4SAlexandre Ghiti
20921dba4e4SAlexandre Ghiti for (i = 0; i < ncontig; i++, addr += pgsize, ptep++)
21021dba4e4SAlexandre Ghiti ptep_get_and_clear(mm, addr, ptep);
21121dba4e4SAlexandre Ghiti
21221dba4e4SAlexandre Ghiti flush_tlb_range(&vma, saddr, addr);
21321dba4e4SAlexandre Ghiti }
21421dba4e4SAlexandre Ghiti
21521dba4e4SAlexandre Ghiti /*
21621dba4e4SAlexandre Ghiti * When dealing with NAPOT mappings, the privileged specification indicates that
21721dba4e4SAlexandre Ghiti * "if an update needs to be made, the OS generally should first mark all of the
21821dba4e4SAlexandre Ghiti * PTEs invalid, then issue SFENCE.VMA instruction(s) covering all 4 KiB regions
21921dba4e4SAlexandre Ghiti * within the range, [...] then update the PTE(s), as described in Section
22021dba4e4SAlexandre Ghiti * 4.2.1.". That's the equivalent of the Break-Before-Make approach used by
22121dba4e4SAlexandre Ghiti * arm64.
22221dba4e4SAlexandre Ghiti */
set_huge_pte_at(struct mm_struct * mm,unsigned long addr,pte_t * ptep,pte_t pte,unsigned long sz)22382a1a1f3SQinglin Pan void set_huge_pte_at(struct mm_struct *mm,
22482a1a1f3SQinglin Pan unsigned long addr,
22582a1a1f3SQinglin Pan pte_t *ptep,
226935d4f0cSRyan Roberts pte_t pte,
227935d4f0cSRyan Roberts unsigned long sz)
22882a1a1f3SQinglin Pan {
22921dba4e4SAlexandre Ghiti unsigned long hugepage_shift, pgsize;
23082a1a1f3SQinglin Pan int i, pte_num;
23182a1a1f3SQinglin Pan
2321de195ddSAlexandre Ghiti if (sz >= PGDIR_SIZE)
2331de195ddSAlexandre Ghiti hugepage_shift = PGDIR_SHIFT;
2341de195ddSAlexandre Ghiti else if (sz >= P4D_SIZE)
2351de195ddSAlexandre Ghiti hugepage_shift = P4D_SHIFT;
2361de195ddSAlexandre Ghiti else if (sz >= PUD_SIZE)
2371de195ddSAlexandre Ghiti hugepage_shift = PUD_SHIFT;
2381de195ddSAlexandre Ghiti else if (sz >= PMD_SIZE)
2391de195ddSAlexandre Ghiti hugepage_shift = PMD_SHIFT;
2401de195ddSAlexandre Ghiti else
2411de195ddSAlexandre Ghiti hugepage_shift = PAGE_SHIFT;
24282a1a1f3SQinglin Pan
2431de195ddSAlexandre Ghiti pte_num = sz >> hugepage_shift;
24421dba4e4SAlexandre Ghiti pgsize = 1 << hugepage_shift;
24521dba4e4SAlexandre Ghiti
24621dba4e4SAlexandre Ghiti if (!pte_present(pte)) {
24721dba4e4SAlexandre Ghiti for (i = 0; i < pte_num; i++, ptep++, addr += pgsize)
24821dba4e4SAlexandre Ghiti set_ptes(mm, addr, ptep, pte, 1);
24921dba4e4SAlexandre Ghiti return;
25021dba4e4SAlexandre Ghiti }
25121dba4e4SAlexandre Ghiti
25221dba4e4SAlexandre Ghiti if (!pte_napot(pte)) {
25321dba4e4SAlexandre Ghiti set_ptes(mm, addr, ptep, pte, 1);
25421dba4e4SAlexandre Ghiti return;
25521dba4e4SAlexandre Ghiti }
25621dba4e4SAlexandre Ghiti
25721dba4e4SAlexandre Ghiti clear_flush(mm, addr, ptep, pgsize, pte_num);
25821dba4e4SAlexandre Ghiti
25921dba4e4SAlexandre Ghiti for (i = 0; i < pte_num; i++, ptep++, addr += pgsize)
26082a1a1f3SQinglin Pan set_pte_at(mm, addr, ptep, pte);
26182a1a1f3SQinglin Pan }
26282a1a1f3SQinglin Pan
huge_ptep_set_access_flags(struct vm_area_struct * vma,unsigned long addr,pte_t * ptep,pte_t pte,int dirty)26382a1a1f3SQinglin Pan int huge_ptep_set_access_flags(struct vm_area_struct *vma,
26482a1a1f3SQinglin Pan unsigned long addr,
26582a1a1f3SQinglin Pan pte_t *ptep,
26682a1a1f3SQinglin Pan pte_t pte,
26782a1a1f3SQinglin Pan int dirty)
26882a1a1f3SQinglin Pan {
26982a1a1f3SQinglin Pan struct mm_struct *mm = vma->vm_mm;
27082a1a1f3SQinglin Pan unsigned long order;
27182a1a1f3SQinglin Pan pte_t orig_pte;
27282a1a1f3SQinglin Pan int i, pte_num;
27382a1a1f3SQinglin Pan
27482a1a1f3SQinglin Pan if (!pte_napot(pte))
27582a1a1f3SQinglin Pan return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
27682a1a1f3SQinglin Pan
27782a1a1f3SQinglin Pan order = napot_cont_order(pte);
27882a1a1f3SQinglin Pan pte_num = napot_pte_num(order);
27982a1a1f3SQinglin Pan ptep = huge_pte_offset(mm, addr, napot_cont_size(order));
28082a1a1f3SQinglin Pan orig_pte = get_clear_contig_flush(mm, addr, ptep, pte_num);
28182a1a1f3SQinglin Pan
28282a1a1f3SQinglin Pan if (pte_dirty(orig_pte))
28382a1a1f3SQinglin Pan pte = pte_mkdirty(pte);
28482a1a1f3SQinglin Pan
28582a1a1f3SQinglin Pan if (pte_young(orig_pte))
28682a1a1f3SQinglin Pan pte = pte_mkyoung(pte);
28782a1a1f3SQinglin Pan
28882a1a1f3SQinglin Pan for (i = 0; i < pte_num; i++, addr += PAGE_SIZE, ptep++)
28982a1a1f3SQinglin Pan set_pte_at(mm, addr, ptep, pte);
29082a1a1f3SQinglin Pan
29182a1a1f3SQinglin Pan return true;
29282a1a1f3SQinglin Pan }
29382a1a1f3SQinglin Pan
huge_ptep_get_and_clear(struct mm_struct * mm,unsigned long addr,pte_t * ptep,unsigned long sz)29482a1a1f3SQinglin Pan pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
29582a1a1f3SQinglin Pan unsigned long addr,
296*c04035ceSRyan Roberts pte_t *ptep, unsigned long sz)
29782a1a1f3SQinglin Pan {
29882a1a1f3SQinglin Pan pte_t orig_pte = ptep_get(ptep);
29982a1a1f3SQinglin Pan int pte_num;
30082a1a1f3SQinglin Pan
30182a1a1f3SQinglin Pan if (!pte_napot(orig_pte))
30282a1a1f3SQinglin Pan return ptep_get_and_clear(mm, addr, ptep);
30382a1a1f3SQinglin Pan
30482a1a1f3SQinglin Pan pte_num = napot_pte_num(napot_cont_order(orig_pte));
30582a1a1f3SQinglin Pan
30682a1a1f3SQinglin Pan return get_clear_contig(mm, addr, ptep, pte_num);
30782a1a1f3SQinglin Pan }
30882a1a1f3SQinglin Pan
huge_ptep_set_wrprotect(struct mm_struct * mm,unsigned long addr,pte_t * ptep)30982a1a1f3SQinglin Pan void huge_ptep_set_wrprotect(struct mm_struct *mm,
31082a1a1f3SQinglin Pan unsigned long addr,
31182a1a1f3SQinglin Pan pte_t *ptep)
31282a1a1f3SQinglin Pan {
31382a1a1f3SQinglin Pan pte_t pte = ptep_get(ptep);
31482a1a1f3SQinglin Pan unsigned long order;
315835e5ac3SAlexandre Ghiti pte_t orig_pte;
31682a1a1f3SQinglin Pan int i, pte_num;
31782a1a1f3SQinglin Pan
31882a1a1f3SQinglin Pan if (!pte_napot(pte)) {
31982a1a1f3SQinglin Pan ptep_set_wrprotect(mm, addr, ptep);
32082a1a1f3SQinglin Pan return;
32182a1a1f3SQinglin Pan }
32282a1a1f3SQinglin Pan
32382a1a1f3SQinglin Pan order = napot_cont_order(pte);
32482a1a1f3SQinglin Pan pte_num = napot_pte_num(order);
32582a1a1f3SQinglin Pan ptep = huge_pte_offset(mm, addr, napot_cont_size(order));
326835e5ac3SAlexandre Ghiti orig_pte = get_clear_contig_flush(mm, addr, ptep, pte_num);
327835e5ac3SAlexandre Ghiti
328835e5ac3SAlexandre Ghiti orig_pte = pte_wrprotect(orig_pte);
32982a1a1f3SQinglin Pan
33082a1a1f3SQinglin Pan for (i = 0; i < pte_num; i++, addr += PAGE_SIZE, ptep++)
331835e5ac3SAlexandre Ghiti set_pte_at(mm, addr, ptep, orig_pte);
33282a1a1f3SQinglin Pan }
33382a1a1f3SQinglin Pan
huge_ptep_clear_flush(struct vm_area_struct * vma,unsigned long addr,pte_t * ptep)33482a1a1f3SQinglin Pan pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,
33582a1a1f3SQinglin Pan unsigned long addr,
33682a1a1f3SQinglin Pan pte_t *ptep)
33782a1a1f3SQinglin Pan {
33882a1a1f3SQinglin Pan pte_t pte = ptep_get(ptep);
33982a1a1f3SQinglin Pan int pte_num;
34082a1a1f3SQinglin Pan
34182a1a1f3SQinglin Pan if (!pte_napot(pte))
34282a1a1f3SQinglin Pan return ptep_clear_flush(vma, addr, ptep);
34382a1a1f3SQinglin Pan
34482a1a1f3SQinglin Pan pte_num = napot_pte_num(napot_cont_order(pte));
34582a1a1f3SQinglin Pan
34682a1a1f3SQinglin Pan return get_clear_contig_flush(vma->vm_mm, addr, ptep, pte_num);
34782a1a1f3SQinglin Pan }
34882a1a1f3SQinglin Pan
huge_pte_clear(struct mm_struct * mm,unsigned long addr,pte_t * ptep,unsigned long sz)34982a1a1f3SQinglin Pan void huge_pte_clear(struct mm_struct *mm,
35082a1a1f3SQinglin Pan unsigned long addr,
35182a1a1f3SQinglin Pan pte_t *ptep,
35282a1a1f3SQinglin Pan unsigned long sz)
35382a1a1f3SQinglin Pan {
354e0316069SAlexandre Ghiti pte_t pte = ptep_get(ptep);
35582a1a1f3SQinglin Pan int i, pte_num;
35682a1a1f3SQinglin Pan
35782a1a1f3SQinglin Pan if (!pte_napot(pte)) {
35882a1a1f3SQinglin Pan pte_clear(mm, addr, ptep);
35982a1a1f3SQinglin Pan return;
36082a1a1f3SQinglin Pan }
36182a1a1f3SQinglin Pan
36282a1a1f3SQinglin Pan pte_num = napot_pte_num(napot_cont_order(pte));
36382a1a1f3SQinglin Pan for (i = 0; i < pte_num; i++, addr += PAGE_SIZE, ptep++)
36482a1a1f3SQinglin Pan pte_clear(mm, addr, ptep);
36582a1a1f3SQinglin Pan }
36682a1a1f3SQinglin Pan
is_napot_size(unsigned long size)367bc401f79SAlexandre Ghiti static bool is_napot_size(unsigned long size)
36882a1a1f3SQinglin Pan {
36982a1a1f3SQinglin Pan unsigned long order;
37082a1a1f3SQinglin Pan
37182a1a1f3SQinglin Pan if (!has_svnapot())
37282a1a1f3SQinglin Pan return false;
37382a1a1f3SQinglin Pan
37482a1a1f3SQinglin Pan for_each_napot_order(order) {
37582a1a1f3SQinglin Pan if (size == napot_cont_size(order))
37682a1a1f3SQinglin Pan return true;
37782a1a1f3SQinglin Pan }
37882a1a1f3SQinglin Pan return false;
37982a1a1f3SQinglin Pan }
38082a1a1f3SQinglin Pan
napot_hugetlbpages_init(void)38182a1a1f3SQinglin Pan static __init int napot_hugetlbpages_init(void)
38282a1a1f3SQinglin Pan {
38382a1a1f3SQinglin Pan if (has_svnapot()) {
38482a1a1f3SQinglin Pan unsigned long order;
38582a1a1f3SQinglin Pan
38682a1a1f3SQinglin Pan for_each_napot_order(order)
38782a1a1f3SQinglin Pan hugetlb_add_hstate(order);
38882a1a1f3SQinglin Pan }
38982a1a1f3SQinglin Pan return 0;
39082a1a1f3SQinglin Pan }
39182a1a1f3SQinglin Pan arch_initcall(napot_hugetlbpages_init);
39282a1a1f3SQinglin Pan
39382a1a1f3SQinglin Pan #else
39482a1a1f3SQinglin Pan
is_napot_size(unsigned long size)395bc401f79SAlexandre Ghiti static bool is_napot_size(unsigned long size)
39682a1a1f3SQinglin Pan {
39782a1a1f3SQinglin Pan return false;
39882a1a1f3SQinglin Pan }
39982a1a1f3SQinglin Pan
40082a1a1f3SQinglin Pan #endif /*CONFIG_RISCV_ISA_SVNAPOT*/
40182a1a1f3SQinglin Pan
pud_huge(pud_t pud)4029e953cdaSAlexandre Ghiti int pud_huge(pud_t pud)
4039e953cdaSAlexandre Ghiti {
4043133287bSAlexandre Ghiti return pud_leaf(pud);
4059e953cdaSAlexandre Ghiti }
4069e953cdaSAlexandre Ghiti
pmd_huge(pmd_t pmd)4079e953cdaSAlexandre Ghiti int pmd_huge(pmd_t pmd)
4089e953cdaSAlexandre Ghiti {
4093133287bSAlexandre Ghiti return pmd_leaf(pmd);
4109e953cdaSAlexandre Ghiti }
4119e953cdaSAlexandre Ghiti
__hugetlb_valid_size(unsigned long size)412bc401f79SAlexandre Ghiti static bool __hugetlb_valid_size(unsigned long size)
413ae94da89SMike Kravetz {
414ae94da89SMike Kravetz if (size == HPAGE_SIZE)
415ae94da89SMike Kravetz return true;
416ae94da89SMike Kravetz else if (IS_ENABLED(CONFIG_64BIT) && size == PUD_SIZE)
417ae94da89SMike Kravetz return true;
41882a1a1f3SQinglin Pan else if (is_napot_size(size))
41982a1a1f3SQinglin Pan return true;
420ae94da89SMike Kravetz else
421ae94da89SMike Kravetz return false;
422ae94da89SMike Kravetz }
423ae94da89SMike Kravetz
arch_hugetlb_valid_size(unsigned long size)424bc401f79SAlexandre Ghiti bool __init arch_hugetlb_valid_size(unsigned long size)
425bc401f79SAlexandre Ghiti {
426bc401f79SAlexandre Ghiti return __hugetlb_valid_size(size);
427bc401f79SAlexandre Ghiti }
428bc401f79SAlexandre Ghiti
429cc698db4SAlexandre Ghiti #ifdef CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION
arch_hugetlb_migration_supported(struct hstate * h)430bc401f79SAlexandre Ghiti bool arch_hugetlb_migration_supported(struct hstate *h)
431bc401f79SAlexandre Ghiti {
432bc401f79SAlexandre Ghiti return __hugetlb_valid_size(huge_page_size(h));
433bc401f79SAlexandre Ghiti }
434cc698db4SAlexandre Ghiti #endif
435bc401f79SAlexandre Ghiti
4369e953cdaSAlexandre Ghiti #ifdef CONFIG_CONTIG_ALLOC
gigantic_pages_init(void)4379e953cdaSAlexandre Ghiti static __init int gigantic_pages_init(void)
4389e953cdaSAlexandre Ghiti {
4399e953cdaSAlexandre Ghiti /* With CONTIG_ALLOC, we can allocate gigantic pages at runtime */
44038237830SMike Kravetz if (IS_ENABLED(CONFIG_64BIT))
4419e953cdaSAlexandre Ghiti hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT);
4429e953cdaSAlexandre Ghiti return 0;
4439e953cdaSAlexandre Ghiti }
4449e953cdaSAlexandre Ghiti arch_initcall(gigantic_pages_init);
4459e953cdaSAlexandre Ghiti #endif
446