Merge tag 'block-5.14-2021-08-07' of git://git.kernel.dk/linux-block
[linux-2.6-microblaze.git] / arch / csky / mm / tlb.c
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
3
4 #include <linux/init.h>
5 #include <linux/mm.h>
6 #include <linux/module.h>
7 #include <linux/sched.h>
8
9 #include <asm/mmu_context.h>
10 #include <asm/setup.h>
11
12 /*
13  * One C-SKY MMU TLB entry contain two PFN/page entry, ie:
14  * 1VPN -> 2PFN
15  */
16 #define TLB_ENTRY_SIZE          (PAGE_SIZE * 2)
17 #define TLB_ENTRY_SIZE_MASK     (PAGE_MASK << 1)
18
19 void flush_tlb_all(void)
20 {
21         tlb_invalid_all();
22 }
23
24 void flush_tlb_mm(struct mm_struct *mm)
25 {
26 #ifdef CONFIG_CPU_HAS_TLBI
27         sync_is();
28         asm volatile(
29                 "tlbi.asids %0  \n"
30                 "sync.i         \n"
31                 :
32                 : "r" (cpu_asid(mm))
33                 : "memory");
34 #else
35         tlb_invalid_all();
36 #endif
37 }
38
39 /*
40  * MMU operation regs only could invalid tlb entry in jtlb and we
41  * need change asid field to invalid I-utlb & D-utlb.
42  */
43 #ifndef CONFIG_CPU_HAS_TLBI
44 #define restore_asid_inv_utlb(oldpid, newpid) \
45 do { \
46         if (oldpid == newpid) \
47                 write_mmu_entryhi(oldpid + 1); \
48         write_mmu_entryhi(oldpid); \
49 } while (0)
50 #endif
51
52 void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
53                         unsigned long end)
54 {
55         unsigned long newpid = cpu_asid(vma->vm_mm);
56
57         start &= TLB_ENTRY_SIZE_MASK;
58         end   += TLB_ENTRY_SIZE - 1;
59         end   &= TLB_ENTRY_SIZE_MASK;
60
61 #ifdef CONFIG_CPU_HAS_TLBI
62         sync_is();
63         while (start < end) {
64                 asm volatile(
65                         "tlbi.vas %0    \n"
66                         :
67                         : "r" (start | newpid)
68                         : "memory");
69
70                 start += 2*PAGE_SIZE;
71         }
72         asm volatile("sync.i\n");
73 #else
74         {
75         unsigned long flags, oldpid;
76
77         local_irq_save(flags);
78         oldpid = read_mmu_entryhi() & ASID_MASK;
79         while (start < end) {
80                 int idx;
81
82                 write_mmu_entryhi(start | newpid);
83                 start += 2*PAGE_SIZE;
84                 tlb_probe();
85                 idx = read_mmu_index();
86                 if (idx >= 0)
87                         tlb_invalid_indexed();
88         }
89         restore_asid_inv_utlb(oldpid, newpid);
90         local_irq_restore(flags);
91         }
92 #endif
93 }
94
95 void flush_tlb_kernel_range(unsigned long start, unsigned long end)
96 {
97         start &= TLB_ENTRY_SIZE_MASK;
98         end   += TLB_ENTRY_SIZE - 1;
99         end   &= TLB_ENTRY_SIZE_MASK;
100
101 #ifdef CONFIG_CPU_HAS_TLBI
102         sync_is();
103         while (start < end) {
104                 asm volatile(
105                         "tlbi.vaas %0   \n"
106                         :
107                         : "r" (start)
108                         : "memory");
109
110                 start += 2*PAGE_SIZE;
111         }
112         asm volatile("sync.i\n");
113 #else
114         {
115         unsigned long flags, oldpid;
116
117         local_irq_save(flags);
118         oldpid = read_mmu_entryhi() & ASID_MASK;
119         while (start < end) {
120                 int idx;
121
122                 write_mmu_entryhi(start | oldpid);
123                 start += 2*PAGE_SIZE;
124                 tlb_probe();
125                 idx = read_mmu_index();
126                 if (idx >= 0)
127                         tlb_invalid_indexed();
128         }
129         restore_asid_inv_utlb(oldpid, oldpid);
130         local_irq_restore(flags);
131         }
132 #endif
133 }
134
135 void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
136 {
137         int newpid = cpu_asid(vma->vm_mm);
138
139         addr &= TLB_ENTRY_SIZE_MASK;
140
141 #ifdef CONFIG_CPU_HAS_TLBI
142         sync_is();
143         asm volatile(
144                 "tlbi.vas %0    \n"
145                 "sync.i         \n"
146                 :
147                 : "r" (addr | newpid)
148                 : "memory");
149 #else
150         {
151         int oldpid, idx;
152         unsigned long flags;
153
154         local_irq_save(flags);
155         oldpid = read_mmu_entryhi() & ASID_MASK;
156         write_mmu_entryhi(addr | newpid);
157         tlb_probe();
158         idx = read_mmu_index();
159         if (idx >= 0)
160                 tlb_invalid_indexed();
161
162         restore_asid_inv_utlb(oldpid, newpid);
163         local_irq_restore(flags);
164         }
165 #endif
166 }
167
168 void flush_tlb_one(unsigned long addr)
169 {
170         addr &= TLB_ENTRY_SIZE_MASK;
171
172 #ifdef CONFIG_CPU_HAS_TLBI
173         sync_is();
174         asm volatile(
175                 "tlbi.vaas %0   \n"
176                 "sync.i         \n"
177                 :
178                 : "r" (addr)
179                 : "memory");
180 #else
181         {
182         int oldpid, idx;
183         unsigned long flags;
184
185         local_irq_save(flags);
186         oldpid = read_mmu_entryhi() & ASID_MASK;
187         write_mmu_entryhi(addr | oldpid);
188         tlb_probe();
189         idx = read_mmu_index();
190         if (idx >= 0)
191                 tlb_invalid_indexed();
192
193         restore_asid_inv_utlb(oldpid, oldpid);
194         local_irq_restore(flags);
195         }
196 #endif
197 }
198 EXPORT_SYMBOL(flush_tlb_one);