18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2020 Loongson Technology Corporation Limited 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/fs.h> 78c2ecf20Sopenharmony_ci#include <linux/mm.h> 88c2ecf20Sopenharmony_ci#include <linux/hugetlb.h> 98c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 108c2ecf20Sopenharmony_ci#include <linux/err.h> 118c2ecf20Sopenharmony_ci#include <linux/sysctl.h> 128c2ecf20Sopenharmony_ci#include <asm/mman.h> 138c2ecf20Sopenharmony_ci#include <asm/tlb.h> 148c2ecf20Sopenharmony_ci#include <asm/tlbflush.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cipte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr, 178c2ecf20Sopenharmony_ci unsigned long sz) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci pgd_t *pgd; 208c2ecf20Sopenharmony_ci p4d_t *p4d; 218c2ecf20Sopenharmony_ci pud_t *pud; 228c2ecf20Sopenharmony_ci pte_t *pte = NULL; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci pgd = pgd_offset(mm, addr); 258c2ecf20Sopenharmony_ci p4d = p4d_alloc(mm, pgd, addr); 268c2ecf20Sopenharmony_ci pud = pud_alloc(mm, p4d, addr); 278c2ecf20Sopenharmony_ci if (pud) 288c2ecf20Sopenharmony_ci pte = (pte_t *)pmd_alloc(mm, pud, addr); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci return pte; 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cipte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr, 348c2ecf20Sopenharmony_ci unsigned long sz) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci pgd_t *pgd; 378c2ecf20Sopenharmony_ci p4d_t *p4d; 388c2ecf20Sopenharmony_ci pud_t *pud; 398c2ecf20Sopenharmony_ci pmd_t *pmd = NULL; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci pgd = pgd_offset(mm, addr); 428c2ecf20Sopenharmony_ci if (pgd_present(*pgd)) { 438c2ecf20Sopenharmony_ci p4d = p4d_offset(pgd, addr); 448c2ecf20Sopenharmony_ci if (p4d_present(*p4d)) { 458c2ecf20Sopenharmony_ci pud = pud_offset(p4d, addr); 468c2ecf20Sopenharmony_ci if (pud_present(*pud)) 478c2ecf20Sopenharmony_ci pmd = pmd_offset(pud, addr); 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci return (pte_t *) pmd; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ciint pmd_huge(pmd_t pmd) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci return (pmd_val(pmd) & _PAGE_HUGE) != 0; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pmd_huge); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ciint pud_huge(pud_t pud) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci return (pud_val(pud) & _PAGE_HUGE) != 0; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pud_huge); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ciuint64_t pmd_to_entrylo(unsigned long pmd_val) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci uint64_t val; 688c2ecf20Sopenharmony_ci /* PMD as PTE. Must be huge page */ 698c2ecf20Sopenharmony_ci if (!pmd_huge(__pmd(pmd_val))) 708c2ecf20Sopenharmony_ci panic("%s", __func__); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci val = pmd_val ^ _PAGE_HUGE; 738c2ecf20Sopenharmony_ci val |= ((val & _PAGE_HGLOBAL) >> 748c2ecf20Sopenharmony_ci (_PAGE_HGLOBAL_SHIFT - _PAGE_GLOBAL_SHIFT)); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci return val; 778c2ecf20Sopenharmony_ci} 78