1 /* SPDX-License-Identifier: GPL-2.0-only */
3 * Based on arch/arm/include/asm/tlb.h
5 * Copyright (C) 2002 Russell King
6 * Copyright (C) 2012 ARM Ltd.
11 #include <linux/pagemap.h>
12 #include <linux/swap.h>
14 static inline void __tlb_remove_table(void *_table
)
16 free_page_and_swap_cache((struct page
*)_table
);
19 #define tlb_flush tlb_flush
20 static void tlb_flush(struct mmu_gather
*tlb
);
22 #include <asm-generic/tlb.h>
25 * get the tlbi levels in arm64. Default value is TLBI_TTL_UNKNOWN if more than
26 * one of cleared_* is set or neither is set - this elides the level hinting to
29 static inline int tlb_get_level(struct mmu_gather
*tlb
)
31 /* The TTL field is only valid for the leaf entry. */
32 if (tlb
->freed_tables
)
33 return TLBI_TTL_UNKNOWN
;
35 if (tlb
->cleared_ptes
&& !(tlb
->cleared_pmds
||
40 if (tlb
->cleared_pmds
&& !(tlb
->cleared_ptes
||
45 if (tlb
->cleared_puds
&& !(tlb
->cleared_ptes
||
50 if (tlb
->cleared_p4ds
&& !(tlb
->cleared_ptes
||
55 return TLBI_TTL_UNKNOWN
;
58 static inline void tlb_flush(struct mmu_gather
*tlb
)
60 struct vm_area_struct vma
= TLB_FLUSH_VMA(tlb
->mm
, 0);
61 bool last_level
= !tlb
->freed_tables
;
62 unsigned long stride
= tlb_get_unmap_size(tlb
);
63 int tlb_level
= tlb_get_level(tlb
);
66 * If we're tearing down the address space then we only care about
67 * invalidating the walk-cache, since the ASID allocator won't
68 * reallocate our ASID without invalidating the entire TLB.
72 flush_tlb_mm(tlb
->mm
);
76 __flush_tlb_range(&vma
, tlb
->start
, tlb
->end
, stride
,
77 last_level
, tlb_level
);
80 static inline void __pte_free_tlb(struct mmu_gather
*tlb
, pgtable_t pte
,
83 struct ptdesc
*ptdesc
= page_ptdesc(pte
);
85 pagetable_pte_dtor(ptdesc
);
86 tlb_remove_ptdesc(tlb
, ptdesc
);
89 #if CONFIG_PGTABLE_LEVELS > 2
90 static inline void __pmd_free_tlb(struct mmu_gather
*tlb
, pmd_t
*pmdp
,
93 struct ptdesc
*ptdesc
= virt_to_ptdesc(pmdp
);
95 pagetable_pmd_dtor(ptdesc
);
96 tlb_remove_ptdesc(tlb
, ptdesc
);
100 #if CONFIG_PGTABLE_LEVELS > 3
101 static inline void __pud_free_tlb(struct mmu_gather
*tlb
, pud_t
*pudp
,
104 struct ptdesc
*ptdesc
= virt_to_ptdesc(pudp
);
106 if (!pgtable_l4_enabled())
109 pagetable_pud_dtor(ptdesc
);
110 tlb_remove_ptdesc(tlb
, ptdesc
);