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