1*09cfefb7SHuacai Chen // SPDX-License-Identifier: GPL-2.0
2*09cfefb7SHuacai Chen /*
3*09cfefb7SHuacai Chen * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
4*09cfefb7SHuacai Chen */
5*09cfefb7SHuacai Chen
6*09cfefb7SHuacai Chen #include <linux/fs.h>
7*09cfefb7SHuacai Chen #include <linux/mm.h>
8*09cfefb7SHuacai Chen #include <linux/hugetlb.h>
9*09cfefb7SHuacai Chen #include <linux/pagemap.h>
10*09cfefb7SHuacai Chen #include <linux/err.h>
11*09cfefb7SHuacai Chen #include <linux/sysctl.h>
12*09cfefb7SHuacai Chen #include <asm/mman.h>
13*09cfefb7SHuacai Chen #include <asm/tlb.h>
14*09cfefb7SHuacai Chen #include <asm/tlbflush.h>
15*09cfefb7SHuacai Chen
huge_pte_alloc(struct mm_struct * mm,struct vm_area_struct * vma,unsigned long addr,unsigned long sz)16*09cfefb7SHuacai Chen pte_t *huge_pte_alloc(struct mm_struct *mm, struct vm_area_struct *vma,
17*09cfefb7SHuacai Chen unsigned long addr, unsigned long sz)
18*09cfefb7SHuacai Chen {
19*09cfefb7SHuacai Chen pgd_t *pgd;
20*09cfefb7SHuacai Chen p4d_t *p4d;
21*09cfefb7SHuacai Chen pud_t *pud;
22*09cfefb7SHuacai Chen pte_t *pte = NULL;
23*09cfefb7SHuacai Chen
24*09cfefb7SHuacai Chen pgd = pgd_offset(mm, addr);
25*09cfefb7SHuacai Chen p4d = p4d_alloc(mm, pgd, addr);
26*09cfefb7SHuacai Chen pud = pud_alloc(mm, p4d, addr);
27*09cfefb7SHuacai Chen if (pud)
28*09cfefb7SHuacai Chen pte = (pte_t *)pmd_alloc(mm, pud, addr);
29*09cfefb7SHuacai Chen
30*09cfefb7SHuacai Chen return pte;
31*09cfefb7SHuacai Chen }
32*09cfefb7SHuacai Chen
huge_pte_offset(struct mm_struct * mm,unsigned long addr,unsigned long sz)33*09cfefb7SHuacai Chen pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr,
34*09cfefb7SHuacai Chen unsigned long sz)
35*09cfefb7SHuacai Chen {
36*09cfefb7SHuacai Chen pgd_t *pgd;
37*09cfefb7SHuacai Chen p4d_t *p4d;
38*09cfefb7SHuacai Chen pud_t *pud;
39*09cfefb7SHuacai Chen pmd_t *pmd = NULL;
40*09cfefb7SHuacai Chen
41*09cfefb7SHuacai Chen pgd = pgd_offset(mm, addr);
42*09cfefb7SHuacai Chen if (pgd_present(*pgd)) {
43*09cfefb7SHuacai Chen p4d = p4d_offset(pgd, addr);
44*09cfefb7SHuacai Chen if (p4d_present(*p4d)) {
45*09cfefb7SHuacai Chen pud = pud_offset(p4d, addr);
46*09cfefb7SHuacai Chen if (pud_present(*pud))
47*09cfefb7SHuacai Chen pmd = pmd_offset(pud, addr);
48*09cfefb7SHuacai Chen }
49*09cfefb7SHuacai Chen }
50*09cfefb7SHuacai Chen return (pte_t *) pmd;
51*09cfefb7SHuacai Chen }
52*09cfefb7SHuacai Chen
pmd_huge(pmd_t pmd)53*09cfefb7SHuacai Chen int pmd_huge(pmd_t pmd)
54*09cfefb7SHuacai Chen {
55*09cfefb7SHuacai Chen return (pmd_val(pmd) & _PAGE_HUGE) != 0;
56*09cfefb7SHuacai Chen }
57*09cfefb7SHuacai Chen
pud_huge(pud_t pud)58*09cfefb7SHuacai Chen int pud_huge(pud_t pud)
59*09cfefb7SHuacai Chen {
60*09cfefb7SHuacai Chen return (pud_val(pud) & _PAGE_HUGE) != 0;
61*09cfefb7SHuacai Chen }
62*09cfefb7SHuacai Chen
pmd_to_entrylo(unsigned long pmd_val)63*09cfefb7SHuacai Chen uint64_t pmd_to_entrylo(unsigned long pmd_val)
64*09cfefb7SHuacai Chen {
65*09cfefb7SHuacai Chen uint64_t val;
66*09cfefb7SHuacai Chen /* PMD as PTE. Must be huge page */
67*09cfefb7SHuacai Chen if (!pmd_huge(__pmd(pmd_val)))
68*09cfefb7SHuacai Chen panic("%s", __func__);
69*09cfefb7SHuacai Chen
70*09cfefb7SHuacai Chen val = pmd_val ^ _PAGE_HUGE;
71*09cfefb7SHuacai Chen val |= ((val & _PAGE_HGLOBAL) >>
72*09cfefb7SHuacai Chen (_PAGE_HGLOBAL_SHIFT - _PAGE_GLOBAL_SHIFT));
73*09cfefb7SHuacai Chen
74*09cfefb7SHuacai Chen return val;
75*09cfefb7SHuacai Chen }
76