18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Based on arch/arm/include/asm/tlb.h 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2002 Russell King 68c2ecf20Sopenharmony_ci * Copyright (C) 2012 ARM Ltd. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#ifndef __ASM_TLB_H 98c2ecf20Sopenharmony_ci#define __ASM_TLB_H 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 128c2ecf20Sopenharmony_ci#include <linux/swap.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic inline void __tlb_remove_table(void *_table) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci free_page_and_swap_cache((struct page *)_table); 178c2ecf20Sopenharmony_ci} 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define tlb_flush tlb_flush 208c2ecf20Sopenharmony_cistatic void tlb_flush(struct mmu_gather *tlb); 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <asm-generic/tlb.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* 258c2ecf20Sopenharmony_ci * get the tlbi levels in arm64. Default value is 0 if more than one 268c2ecf20Sopenharmony_ci * of cleared_* is set or neither is set. 278c2ecf20Sopenharmony_ci * Arm64 doesn't support p4ds now. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_cistatic inline int tlb_get_level(struct mmu_gather *tlb) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci /* The TTL field is only valid for the leaf entry. */ 328c2ecf20Sopenharmony_ci if (tlb->freed_tables) 338c2ecf20Sopenharmony_ci return 0; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci if (tlb->cleared_ptes && !(tlb->cleared_pmds || 368c2ecf20Sopenharmony_ci tlb->cleared_puds || 378c2ecf20Sopenharmony_ci tlb->cleared_p4ds)) 388c2ecf20Sopenharmony_ci return 3; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci if (tlb->cleared_pmds && !(tlb->cleared_ptes || 418c2ecf20Sopenharmony_ci tlb->cleared_puds || 428c2ecf20Sopenharmony_ci tlb->cleared_p4ds)) 438c2ecf20Sopenharmony_ci return 2; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci if (tlb->cleared_puds && !(tlb->cleared_ptes || 468c2ecf20Sopenharmony_ci tlb->cleared_pmds || 478c2ecf20Sopenharmony_ci tlb->cleared_p4ds)) 488c2ecf20Sopenharmony_ci return 1; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci return 0; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic inline void tlb_flush(struct mmu_gather *tlb) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct vm_area_struct vma = TLB_FLUSH_VMA(tlb->mm, 0); 568c2ecf20Sopenharmony_ci bool last_level = !tlb->freed_tables; 578c2ecf20Sopenharmony_ci unsigned long stride = tlb_get_unmap_size(tlb); 588c2ecf20Sopenharmony_ci int tlb_level = tlb_get_level(tlb); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* 618c2ecf20Sopenharmony_ci * If we're tearing down the address space then we only care about 628c2ecf20Sopenharmony_ci * invalidating the walk-cache, since the ASID allocator won't 638c2ecf20Sopenharmony_ci * reallocate our ASID without invalidating the entire TLB. 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_ci if (tlb->fullmm) { 668c2ecf20Sopenharmony_ci if (!last_level) 678c2ecf20Sopenharmony_ci flush_tlb_mm(tlb->mm); 688c2ecf20Sopenharmony_ci return; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci __flush_tlb_range(&vma, tlb->start, tlb->end, stride, 728c2ecf20Sopenharmony_ci last_level, tlb_level); 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte, 768c2ecf20Sopenharmony_ci unsigned long addr) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci pgtable_pte_page_dtor(pte); 798c2ecf20Sopenharmony_ci tlb_remove_table(tlb, pte); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS > 2 838c2ecf20Sopenharmony_cistatic inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp, 848c2ecf20Sopenharmony_ci unsigned long addr) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct page *page = virt_to_page(pmdp); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci pgtable_pmd_page_dtor(page); 898c2ecf20Sopenharmony_ci tlb_remove_table(tlb, page); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci#endif 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS > 3 948c2ecf20Sopenharmony_cistatic inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pudp, 958c2ecf20Sopenharmony_ci unsigned long addr) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci tlb_remove_table(tlb, virt_to_page(pudp)); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci#endif 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci#endif 102