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