GNU Linux-libre 4.14.332-gnu1
[releases.git] / arch / m32r / mm / mmu.S
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  *  linux/arch/m32r/mm/mmu.S
4  *
5  *  Copyright (C) 2001 by Hiroyuki Kondo
6  */
7
8 #include <linux/linkage.h>
9 #include <asm/assembler.h>
10 #include <asm/smp.h>
11
12         .text
13 #ifdef CONFIG_MMU
14
15 #include <asm/mmu_context.h>
16 #include <asm/page.h>
17 #include <asm/pgtable.h>
18 #include <asm/m32r.h>
19
20 /*
21  * TLB Miss Exception handler
22  */
23         .balign 16
24 ENTRY(tme_handler)
25         .global tlb_entry_i_dat
26         .global tlb_entry_d_dat
27
28         SWITCH_TO_KERNEL_STACK
29
30 #if defined(CONFIG_ISA_M32R2)
31         st      r0, @-sp
32         st      r1, @-sp
33         st      r2, @-sp
34         st      r3, @-sp
35
36         seth    r3, #high(MMU_REG_BASE)
37         ld      r1, @(MESTS_offset, r3) ; r1: status     (MESTS reg.)
38         ld      r0, @(MDEVP_offset, r3) ; r0: PFN + ASID (MDEVP reg.)
39         st      r1, @(MESTS_offset, r3) ; clear status   (MESTS reg.)
40         and3    r1, r1, #(MESTS_IT)
41         bnez    r1, 1f                  ; instruction TLB miss?
42
43 ;; data TLB miss
44 ;;  input
45 ;;   r0: PFN + ASID (MDEVP reg.)
46 ;;   r1 - r3: free
47 ;;  output
48 ;;   r0: PFN + ASID
49 ;;   r1: TLB entry base address
50 ;;   r2: &tlb_entry_{i|d}_dat
51 ;;   r3: free
52
53 #ifndef CONFIG_SMP
54         seth    r2, #high(tlb_entry_d_dat)
55         or3     r2, r2, #low(tlb_entry_d_dat)
56 #else   /* CONFIG_SMP */
57         ldi     r1, #-8192
58         seth    r2, #high(tlb_entry_d_dat)
59         or3     r2, r2, #low(tlb_entry_d_dat)
60         and     r1, sp
61         ld      r1, @(16, r1)           ; current_thread_info->cpu
62         slli    r1, #2
63         add     r2, r1
64 #endif  /* !CONFIG_SMP */
65         seth    r1, #high(DTLB_BASE)
66         or3     r1, r1, #low(DTLB_BASE)
67         bra     2f
68
69         .balign 16
70         .fillinsn
71 1:
72 ;; instrucntion TLB miss
73 ;;  input
74 ;;   r0: MDEVP reg. (included ASID)
75 ;;   r1 - r3: free
76 ;;  output
77 ;;   r0: PFN + ASID
78 ;;   r1: TLB entry base address
79 ;;   r2: &tlb_entry_{i|d}_dat
80 ;;   r3: free
81         ldi     r3, #-4096
82         and3    r0, r0, #(MMU_CONTEXT_ASID_MASK)
83         mvfc    r1, bpc
84         and     r1, r3
85         or      r0, r1                  ; r0: PFN + ASID
86 #ifndef CONFIG_SMP
87         seth    r2, #high(tlb_entry_i_dat)
88         or3     r2, r2, #low(tlb_entry_i_dat)
89 #else   /* CONFIG_SMP */
90         ldi     r1, #-8192
91         seth    r2, #high(tlb_entry_i_dat)
92         or3     r2, r2, #low(tlb_entry_i_dat)
93         and     r1, sp
94         ld      r1, @(16, r1)           ; current_thread_info->cpu
95         slli    r1, #2
96         add     r2, r1
97 #endif  /* !CONFIG_SMP */
98         seth    r1, #high(ITLB_BASE)
99         or3     r1, r1, #low(ITLB_BASE)
100
101         .fillinsn
102 2:
103 ;; select TLB entry
104 ;;  input
105 ;;   r0: PFN + ASID
106 ;;   r1: TLB entry base address
107 ;;   r2: &tlb_entry_{i|d}_dat
108 ;;   r3: free
109 ;;  output
110 ;;   r0: PFN + ASID
111 ;;   r1: TLB entry address
112 ;;   r2, r3: free
113 #ifdef CONFIG_ISA_DUAL_ISSUE
114         ld      r3, @r2         ||      srli    r1, #3
115 #else
116         ld      r3, @r2
117         srli    r1, #3
118 #endif
119         add     r1, r3
120         ; tlb_entry_{d|i}_dat++;
121         addi    r3, #1
122         and3    r3, r3, #(NR_TLB_ENTRIES - 1)
123 #ifdef CONFIG_ISA_DUAL_ISSUE
124         st      r3, @r2         ||      slli    r1, #3
125 #else
126         st      r3, @r2
127         slli    r1, #3
128 #endif
129
130 ;; load pte
131 ;;  input
132 ;;   r0: PFN + ASID
133 ;;   r1: TLB entry address
134 ;;   r2, r3: free
135 ;;  output
136 ;;   r0: PFN + ASID
137 ;;   r1: TLB entry address
138 ;;   r2: pte_data
139 ;;   r3: free
140         ; pgd = *(unsigned long *)MPTB;
141         ld24    r2, #(-MPTB - 1)
142         srl3    r3, r0, #22
143 #ifdef CONFIG_ISA_DUAL_ISSUE
144         not     r2, r2              ||  slli    r3, #2  ; r3: pgd offset
145 #else
146         not     r2, r2
147         slli    r3, #2
148 #endif
149         ld      r2, @r2                 ; r2: pgd base addr (MPTB reg.)
150         or      r3, r2                  ; r3: pmd addr
151
152         ; pmd = pmd_offset(pgd, address);
153         ld      r3, @r3                 ; r3: pmd data
154         beqz    r3, 3f                  ; pmd_none(*pmd) ?
155
156         and3    r2, r3, #0xfff
157         add3    r2, r2, #-355           ; _KERNPG_TABLE(=0x163)
158         bnez    r2, 3f                  ; pmd_bad(*pmd) ?
159         ldi     r2, #-4096
160
161         ; pte = pte_offset(pmd, address);
162         and     r2, r3                  ; r2: pte base addr
163         srl3    r3, r0, #10
164         and3    r3, r3, #0xffc          ; r3: pte offset
165         or      r3, r2
166         seth    r2, #0x8000
167         or      r3, r2                  ; r3: pte addr
168
169         ; pte_data = (unsigned long)pte_val(*pte);
170         ld      r2, @r3                 ; r2: pte data
171         and3    r3, r2, #2              ; _PAGE_PRESENT(=2) check
172         beqz    r3, 3f
173
174         .fillinsn
175 5:
176 ;; set tlb
177 ;;  input
178 ;;   r0: PFN + ASID
179 ;;   r1: TLB entry address
180 ;;   r2: pte_data
181 ;;   r3: free
182         st      r0, @r1                 ; set_tlb_tag(entry++, address);
183         st      r2, @+r1                ; set_tlb_data(entry, pte_data);
184
185         .fillinsn
186 6:
187         ld      r3, @sp+
188         ld      r2, @sp+
189         ld      r1, @sp+
190         ld      r0, @sp+
191         rte
192
193         .fillinsn
194 3:
195 ;; error
196 ;;  input
197 ;;   r0: PFN + ASID
198 ;;   r1: TLB entry address
199 ;;   r2, r3: free
200 ;;  output
201 ;;   r0: PFN + ASID
202 ;;   r1: TLB entry address
203 ;;   r2: pte_data
204 ;;   r3: free
205 #ifdef CONFIG_ISA_DUAL_ISSUE
206         bra     5b                  ||  ldi     r2, #2
207 #else
208         ldi     r2, #2          ; r2: pte_data = 0 | _PAGE_PRESENT(=2)
209         bra     5b
210 #endif
211
212 #elif defined (CONFIG_ISA_M32R)
213
214         st      sp, @-sp
215         st      r0, @-sp
216         st      r1, @-sp
217         st      r2, @-sp
218         st      r3, @-sp
219         st      r4, @-sp
220
221         seth    r3, #high(MMU_REG_BASE)
222         ld      r0, @(MDEVA_offset,r3)  ; r0: address  (MDEVA reg.)
223         mvfc    r2, bpc                 ; r2: bpc
224         ld      r1, @(MESTS_offset,r3)  ; r1: status   (MESTS reg.)
225         st      r1, @(MESTS_offset,r3)  ; clear status (MESTS reg.)
226         and3    r1, r1, #(MESTS_IT)
227         beqz    r1, 1f                  ; data TLB miss?
228
229 ;; instrucntion TLB miss
230         mv      r0, r2                  ; address = bpc;
231         ; entry = (unsigned long *)ITLB_BASE+tlb_entry_i*2;
232         seth    r3, #shigh(tlb_entry_i_dat)
233         ld      r4, @(low(tlb_entry_i_dat),r3)
234         sll3    r2, r4, #3
235         seth    r1, #high(ITLB_BASE)
236         or3     r1, r1, #low(ITLB_BASE)
237         add     r2, r1                  ; r2: entry
238         addi    r4, #1                  ; tlb_entry_i++;
239         and3    r4, r4, #(NR_TLB_ENTRIES-1)
240         st      r4, @(low(tlb_entry_i_dat),r3)
241         bra     2f
242         .fillinsn
243 1:
244 ;; data TLB miss
245         ; entry = (unsigned long *)DTLB_BASE+tlb_entry_d*2;
246         seth    r3, #shigh(tlb_entry_d_dat)
247         ld      r4, @(low(tlb_entry_d_dat),r3)
248         sll3    r2, r4, #3
249         seth    r1, #high(DTLB_BASE)
250         or3     r1, r1, #low(DTLB_BASE)
251         add     r2, r1                  ; r2: entry
252         addi    r4, #1                  ; tlb_entry_d++;
253         and3    r4, r4, #(NR_TLB_ENTRIES-1)
254         st      r4, @(low(tlb_entry_d_dat),r3)
255         .fillinsn
256 2:
257 ;; load pte
258 ; r0: address, r2: entry
259 ; r1,r3,r4: (free)
260         ; pgd = *(unsigned long *)MPTB;
261         ld24    r1, #(-MPTB-1)
262         not     r1, r1
263         ld      r1, @r1
264         srl3    r4, r0, #22
265         sll3    r3, r4, #2
266         add     r3, r1                  ; r3: pgd
267         ; pmd = pmd_offset(pgd, address);
268         ld      r1, @r3                 ; r1: pmd
269         beqz    r1, 3f                  ; pmd_none(*pmd) ?
270 ;
271         and3    r1, r1, #0x3ff
272         ldi     r4, #0x163              ; _KERNPG_TABLE(=0x163)
273         bne     r1, r4, 3f              ; pmd_bad(*pmd) ?
274
275         .fillinsn
276 4:
277         ; pte = pte_offset(pmd, address);
278         ld      r4, @r3                 ; r4: pte
279         ldi     r3, #-4096
280         and     r4, r3
281         srl3    r3, r0, #10
282         and3    r3, r3, #0xffc
283         add     r4, r3
284         seth    r3, #0x8000
285         add     r4, r3                  ; r4: pte
286         ; pte_data = (unsigned long)pte_val(*pte);
287         ld      r1, @r4                 ; r1: pte_data
288         and3    r3, r1, #2              ; _PAGE_PRESENT(=2) check
289         beqz    r3, 3f
290
291         .fillinsn
292 ;; set tlb
293 ; r0: address, r1: pte_data, r2: entry
294 ; r3,r4: (free)
295 5:
296         ldi     r3, #-4096              ; set_tlb_tag(entry++, address);
297         and     r3, r0
298         seth    r4, #shigh(MASID)
299         ld      r4, @(low(MASID),r4)    ; r4: MASID
300         and3    r4, r4, #(MMU_CONTEXT_ASID_MASK)
301         or      r3, r4
302         st      r3, @r2
303         st      r1, @(4,r2)             ; set_tlb_data(entry, pte_data);
304
305         ld      r4, @sp+
306         ld      r3, @sp+
307         ld      r2, @sp+
308         ld      r1, @sp+
309         ld      r0, @sp+
310         ld      sp, @sp+
311         rte
312
313         .fillinsn
314 3:
315         ldi     r1, #2                  ; r1: pte_data = 0 | _PAGE_PRESENT(=2)
316         bra     5b
317
318 #else
319 #error unknown isa configuration
320 #endif
321
322 ENTRY(init_tlb)
323 ;; Set MMU Register
324         seth    r0, #high(MMU_REG_BASE)  ; Set MMU_REG_BASE higher
325         or3     r0, r0, #low(MMU_REG_BASE)  ; Set MMU_REG_BASE lower
326         ldi     r1, #0
327         st      r1, @(MPSZ_offset,r0)   ; Set MPSZ Reg(Page size 4KB:0 16KB:1 64KB:2)
328         ldi     r1, #0
329         st      r1, @(MASID_offset,r0)  ; Set ASID Zero
330
331 ;; Set TLB
332         seth    r0, #high(ITLB_BASE)    ; Set ITLB_BASE higher
333         or3     r0, r0, #low(ITLB_BASE) ; Set ITLB_BASE lower
334         seth    r1, #high(DTLB_BASE)    ; Set DTLB_BASE higher
335         or3     r1, r1, #low(DTLB_BASE) ; Set DTLB_BASE lower
336         ldi     r2, #0
337         ldi     r3, #NR_TLB_ENTRIES
338         addi    r0, #-4
339         addi    r1, #-4
340 clear_tlb:
341         st      r2, @+r0                ; VPA <- 0
342         st      r2, @+r0                ; PPA <- 0
343         st      r2, @+r1                ; VPA <- 0
344         st      r2, @+r1                ; PPA <- 0
345         addi    r3, #-1
346         bnez    r3, clear_tlb
347 ;;
348         jmp     r14
349
350 ENTRY(m32r_itlb_entrys)
351 ENTRY(m32r_otlb_entrys)
352
353 #endif  /* CONFIG_MMU */
354
355         .end