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