109cfefb7SHuacai Chen // SPDX-License-Identifier: GPL-2.0
209cfefb7SHuacai Chen /*
309cfefb7SHuacai Chen * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
409cfefb7SHuacai Chen */
509cfefb7SHuacai Chen
609cfefb7SHuacai Chen #include <linux/fs.h>
709cfefb7SHuacai Chen #include <linux/mm.h>
809cfefb7SHuacai Chen #include <linux/hugetlb.h>
909cfefb7SHuacai Chen #include <linux/pagemap.h>
1009cfefb7SHuacai Chen #include <linux/err.h>
1109cfefb7SHuacai Chen #include <linux/sysctl.h>
1209cfefb7SHuacai Chen #include <asm/mman.h>
1309cfefb7SHuacai Chen #include <asm/tlb.h>
1409cfefb7SHuacai Chen #include <asm/tlbflush.h>
1509cfefb7SHuacai Chen
huge_pte_alloc(struct mm_struct * mm,struct vm_area_struct * vma,unsigned long addr,unsigned long sz)1609cfefb7SHuacai Chen pte_t *huge_pte_alloc(struct mm_struct *mm, struct vm_area_struct *vma,
1709cfefb7SHuacai Chen unsigned long addr, unsigned long sz)
1809cfefb7SHuacai Chen {
1909cfefb7SHuacai Chen pgd_t *pgd;
2009cfefb7SHuacai Chen p4d_t *p4d;
2109cfefb7SHuacai Chen pud_t *pud;
2209cfefb7SHuacai Chen pte_t *pte = NULL;
2309cfefb7SHuacai Chen
2409cfefb7SHuacai Chen pgd = pgd_offset(mm, addr);
2509cfefb7SHuacai Chen p4d = p4d_alloc(mm, pgd, addr);
2609cfefb7SHuacai Chen pud = pud_alloc(mm, p4d, addr);
2709cfefb7SHuacai Chen if (pud)
2809cfefb7SHuacai Chen pte = (pte_t *)pmd_alloc(mm, pud, addr);
2909cfefb7SHuacai Chen
3009cfefb7SHuacai Chen return pte;
3109cfefb7SHuacai Chen }
3209cfefb7SHuacai Chen
huge_pte_offset(struct mm_struct * mm,unsigned long addr,unsigned long sz)3309cfefb7SHuacai Chen pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr,
3409cfefb7SHuacai Chen unsigned long sz)
3509cfefb7SHuacai Chen {
3609cfefb7SHuacai Chen pgd_t *pgd;
3709cfefb7SHuacai Chen p4d_t *p4d;
3809cfefb7SHuacai Chen pud_t *pud;
3909cfefb7SHuacai Chen pmd_t *pmd = NULL;
4009cfefb7SHuacai Chen
4109cfefb7SHuacai Chen pgd = pgd_offset(mm, addr);
424574815aSHuacai Chen if (pgd_present(pgdp_get(pgd))) {
4309cfefb7SHuacai Chen p4d = p4d_offset(pgd, addr);
444574815aSHuacai Chen if (p4d_present(p4dp_get(p4d))) {
4509cfefb7SHuacai Chen pud = pud_offset(p4d, addr);
464574815aSHuacai Chen if (pud_present(pudp_get(pud)))
4709cfefb7SHuacai Chen pmd = pmd_offset(pud, addr);
4809cfefb7SHuacai Chen }
4909cfefb7SHuacai Chen }
50*ee084fa9STianyang Zhang
51*ee084fa9STianyang Zhang return (!pmd || pmd_none(pmdp_get(pmd))) ? NULL : (pte_t *) pmd;
5209cfefb7SHuacai Chen }
5309cfefb7SHuacai Chen
pmd_to_entrylo(unsigned long pmd_val)5409cfefb7SHuacai Chen uint64_t pmd_to_entrylo(unsigned long pmd_val)
5509cfefb7SHuacai Chen {
5609cfefb7SHuacai Chen uint64_t val;
5709cfefb7SHuacai Chen /* PMD as PTE. Must be huge page */
581965e933SPeter Xu if (!pmd_leaf(__pmd(pmd_val)))
5909cfefb7SHuacai Chen panic("%s", __func__);
6009cfefb7SHuacai Chen
6109cfefb7SHuacai Chen val = pmd_val ^ _PAGE_HUGE;
6209cfefb7SHuacai Chen val |= ((val & _PAGE_HGLOBAL) >>
6309cfefb7SHuacai Chen (_PAGE_HGLOBAL_SHIFT - _PAGE_GLOBAL_SHIFT));
6409cfefb7SHuacai Chen
6509cfefb7SHuacai Chen return val;
6609cfefb7SHuacai Chen }
67