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