hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/arch/arm64/include/asm/tlb.h
....@@ -1,20 +1,9 @@
1
+/* SPDX-License-Identifier: GPL-2.0-only */
12 /*
23 * Based on arch/arm/include/asm/tlb.h
34 *
45 * Copyright (C) 2002 Russell King
56 * Copyright (C) 2012 ARM Ltd.
6
- *
7
- * This program is free software; you can redistribute it and/or modify
8
- * it under the terms of the GNU General Public License version 2 as
9
- * published by the Free Software Foundation.
10
- *
11
- * This program is distributed in the hope that it will be useful,
12
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- * GNU General Public License for more details.
15
- *
16
- * You should have received a copy of the GNU General Public License
17
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
187 */
198 #ifndef __ASM_TLB_H
209 #define __ASM_TLB_H
....@@ -22,54 +11,82 @@
2211 #include <linux/pagemap.h>
2312 #include <linux/swap.h>
2413
25
-#ifdef CONFIG_HAVE_RCU_TABLE_FREE
26
-
27
-#define tlb_remove_entry(tlb, entry) tlb_remove_table(tlb, entry)
2814 static inline void __tlb_remove_table(void *_table)
2915 {
3016 free_page_and_swap_cache((struct page *)_table);
3117 }
32
-#else
33
-#define tlb_remove_entry(tlb, entry) tlb_remove_page(tlb, entry)
34
-#endif /* CONFIG_HAVE_RCU_TABLE_FREE */
3518
19
+#define tlb_flush tlb_flush
3620 static void tlb_flush(struct mmu_gather *tlb);
3721
3822 #include <asm-generic/tlb.h>
3923
24
+/*
25
+ * get the tlbi levels in arm64. Default value is 0 if more than one
26
+ * of cleared_* is set or neither is set.
27
+ * Arm64 doesn't support p4ds now.
28
+ */
29
+static inline int tlb_get_level(struct mmu_gather *tlb)
30
+{
31
+ /* The TTL field is only valid for the leaf entry. */
32
+ if (tlb->freed_tables)
33
+ return 0;
34
+
35
+ if (tlb->cleared_ptes && !(tlb->cleared_pmds ||
36
+ tlb->cleared_puds ||
37
+ tlb->cleared_p4ds))
38
+ return 3;
39
+
40
+ if (tlb->cleared_pmds && !(tlb->cleared_ptes ||
41
+ tlb->cleared_puds ||
42
+ tlb->cleared_p4ds))
43
+ return 2;
44
+
45
+ if (tlb->cleared_puds && !(tlb->cleared_ptes ||
46
+ tlb->cleared_pmds ||
47
+ tlb->cleared_p4ds))
48
+ return 1;
49
+
50
+ return 0;
51
+}
52
+
4053 static inline void tlb_flush(struct mmu_gather *tlb)
4154 {
4255 struct vm_area_struct vma = TLB_FLUSH_VMA(tlb->mm, 0);
56
+ bool last_level = !tlb->freed_tables;
57
+ unsigned long stride = tlb_get_unmap_size(tlb);
58
+ int tlb_level = tlb_get_level(tlb);
4359
4460 /*
45
- * The ASID allocator will either invalidate the ASID or mark
46
- * it as used.
61
+ * If we're tearing down the address space then we only care about
62
+ * invalidating the walk-cache, since the ASID allocator won't
63
+ * reallocate our ASID without invalidating the entire TLB.
4764 */
48
- if (tlb->fullmm)
65
+ if (tlb->fullmm) {
66
+ if (!last_level)
67
+ flush_tlb_mm(tlb->mm);
4968 return;
69
+ }
5070
51
- /*
52
- * The intermediate page table levels are already handled by
53
- * the __(pte|pmd|pud)_free_tlb() functions, so last level
54
- * TLBI is sufficient here.
55
- */
56
- __flush_tlb_range(&vma, tlb->start, tlb->end, true);
71
+ __flush_tlb_range(&vma, tlb->start, tlb->end, stride,
72
+ last_level, tlb_level);
5773 }
5874
5975 static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
6076 unsigned long addr)
6177 {
62
- __flush_tlb_pgtable(tlb->mm, addr);
63
- pgtable_page_dtor(pte);
64
- tlb_remove_entry(tlb, pte);
78
+ pgtable_pte_page_dtor(pte);
79
+ tlb_remove_table(tlb, pte);
6580 }
6681
6782 #if CONFIG_PGTABLE_LEVELS > 2
6883 static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
6984 unsigned long addr)
7085 {
71
- __flush_tlb_pgtable(tlb->mm, addr);
72
- tlb_remove_entry(tlb, virt_to_page(pmdp));
86
+ struct page *page = virt_to_page(pmdp);
87
+
88
+ pgtable_pmd_page_dtor(page);
89
+ tlb_remove_table(tlb, page);
7390 }
7491 #endif
7592
....@@ -77,8 +94,7 @@
7794 static inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pudp,
7895 unsigned long addr)
7996 {
80
- __flush_tlb_pgtable(tlb->mm, addr);
81
- tlb_remove_entry(tlb, virt_to_page(pudp));
97
+ tlb_remove_table(tlb, virt_to_page(pudp));
8298 }
8399 #endif
84100