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