2 * arch/score/mm/tlb-score.c
4 * Score Processor version.
6 * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
7 * Lennox Wu <lennox.wu@sunplusct.com>
8 * Chen Liqin <liqin.chen@sunplusct.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see the file COPYING, or write
22 * to the Free Software Foundation, Inc.,
23 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 #include <linux/highmem.h>
27 #include <linux/module.h>
30 #include <asm/mmu_context.h>
35 unsigned long asid_cache
= ASID_FIRST_VERSION
;
36 EXPORT_SYMBOL(asid_cache
);
38 void local_flush_tlb_all(void)
41 unsigned long old_ASID
;
44 local_irq_save(flags
);
45 old_ASID
= pevn_get() & ASID_MASK
;
46 pectx_set(0); /* invalid */
47 entry
= tlblock_get(); /* skip locked entries*/
49 for (; entry
< TLBSIZE
; entry
++) {
56 local_irq_restore(flags
);
60 * If mm is currently active_mm, we can't really drop it. Instead,
61 * we will get a new one for it.
64 drop_mmu_context(struct mm_struct
*mm
)
68 local_irq_save(flags
);
69 get_new_mmu_context(mm
);
70 pevn_set(mm
->context
& ASID_MASK
);
71 local_irq_restore(flags
);
74 void local_flush_tlb_mm(struct mm_struct
*mm
)
80 void local_flush_tlb_range(struct vm_area_struct
*vma
, unsigned long start
,
83 struct mm_struct
*mm
= vma
->vm_mm
;
84 unsigned long vma_mm_context
= mm
->context
;
85 if (mm
->context
!= 0) {
89 local_irq_save(flags
);
90 size
= (end
- start
+ (PAGE_SIZE
- 1)) >> PAGE_SHIFT
;
91 if (size
<= TLBSIZE
) {
92 int oldpid
= pevn_get() & ASID_MASK
;
93 int newpid
= vma_mm_context
& ASID_MASK
;
96 end
+= (PAGE_SIZE
- 1);
101 pevn_set(start
| newpid
);
114 /* Bigger than TLBSIZE, get new ASID directly */
115 get_new_mmu_context(mm
);
116 if (mm
== current
->active_mm
)
117 pevn_set(vma_mm_context
& ASID_MASK
);
119 local_irq_restore(flags
);
123 void local_flush_tlb_kernel_range(unsigned long start
, unsigned long end
)
128 local_irq_save(flags
);
129 size
= (end
- start
+ (PAGE_SIZE
- 1)) >> PAGE_SHIFT
;
130 if (size
<= TLBSIZE
) {
131 int pid
= pevn_get();
134 end
+= PAGE_SIZE
- 1;
137 while (start
< end
) {
153 local_flush_tlb_all();
156 local_irq_restore(flags
);
159 void local_flush_tlb_page(struct vm_area_struct
*vma
, unsigned long page
)
161 if (!vma
|| vma
->vm_mm
->context
!= 0) {
163 int oldpid
, newpid
, idx
;
164 unsigned long vma_ASID
= vma
->vm_mm
->context
;
166 newpid
= vma_ASID
& ASID_MASK
;
168 local_irq_save(flags
);
169 oldpid
= pevn_get() & ASID_MASK
;
170 pevn_set(page
| newpid
);
176 if (idx
< 0) /* p_bit(31) - 1: miss, 0: hit*/
182 local_irq_restore(flags
);
187 * This one is only used for pages with the global bit set so we don't care
188 * much about the ASID.
190 void local_flush_tlb_one(unsigned long page
)
195 local_irq_save(flags
);
197 page
&= (PAGE_MASK
<< 1);
204 /* Make sure all entries differ. */
210 local_irq_restore(flags
);
213 void __update_tlb(struct vm_area_struct
*vma
, unsigned long address
, pte_t pte
)
219 * Handle debugger faulting in for debugee.
221 if (current
->active_mm
!= vma
->vm_mm
)
224 pid
= pevn_get() & ASID_MASK
;
226 local_irq_save(flags
);
227 address
&= PAGE_MASK
;
228 pevn_set(address
| pid
);
232 pectx_set(pte_val(pte
));
233 pevn_set(address
| pid
);
240 local_irq_restore(flags
);
243 void __cpuinit
tlb_init(void)
246 local_flush_tlb_all();
247 memcpy((void *)(EXCEPTION_VECTOR_BASE_ADDR
+ 0x100),
248 &score7_FTLB_refill_Handler
, 0xFC);
249 flush_icache_range(EXCEPTION_VECTOR_BASE_ADDR
+ 0x100,
250 EXCEPTION_VECTOR_BASE_ADDR
+ 0x1FC);