* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * r4xx0.c: R4000 processor variant specific MMU/Cache routines.
- *
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
* Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle ralf@gnu.org
- *
- * To do:
- *
- * - this code is a overbloated pig
- * - many of the bug workarounds are not efficient at all, but at
- * least they are functional ...
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2002 MIPS Technologies, Inc. All rights reserved.
*/
+#include <linux/config.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/pgtable.h>
#include <asm/system.h>
-#undef DEBUG_TLB
-#undef DEBUG_TLBUPDATE
-
-extern char except_vec0_nevada, except_vec0_r4000, except_vec0_r4600;
+extern void except_vec0_nevada(void);
+extern void except_vec0_r4000(void);
+extern void except_vec0_r4600(void);
+extern void except_vec1_r4k(void);
/* CP0 hazard avoidance. */
#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \
unsigned long old_ctx;
int entry;
-#ifdef DEBUG_TLB
- printk("[tlball]");
-#endif
-
local_irq_save(flags);
/* Save old context and create impossible VPN2 value */
- old_ctx = (read_c0_entryhi() & ASID_MASK);
+ old_ctx = read_c0_entryhi() & ASID_MASK;
write_c0_entrylo0(0);
write_c0_entrylo1(0);
BARRIER;
* Make sure all entries differ. If they're not different
* MIPS32 will take revenge ...
*/
- write_c0_entryhi(KSEG0 + entry*0x2000);
+ write_c0_entryhi(KSEG0 + entry * 0x2000);
write_c0_index(entry);
BARRIER;
tlb_write_indexed();
{
int cpu = smp_processor_id();
- if (cpu_context(cpu, mm) != 0) {
-#ifdef DEBUG_TLB
- printk("[tlbmm<%d>]", cpu_context(cpu, mm));
-#endif
+ if (cpu_context(cpu, mm) != 0)
drop_mmu_context(mm,cpu);
- }
}
void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
unsigned long flags;
int size;
-#ifdef DEBUG_TLB
- printk("[tlbrange<%02x,%08lx,%08lx>]", cpu_context(cpu, mm) & ASID_MASK,
- start, end);
-#endif
local_irq_save(flags);
size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
size = (size + 1) >> 1;
if (size <= current_cpu_data.tlbsize/2) {
int oldpid = read_c0_entryhi() & ASID_MASK;
- int newpid = cpu_context(cpu, mm) & ASID_MASK;
+ int newpid = cpu_asid(cpu, mm);
start &= (PAGE_MASK << 1);
end += ((PAGE_SIZE << 1) - 1);
if (idx < 0)
continue;
/* Make sure all entries differ. */
- write_c0_entryhi(KSEG0 + idx*0x2000);
+ write_c0_entryhi(KSEG0 + idx * 0x2000);
BARRIER;
tlb_write_indexed();
BARRIER;
unsigned long flags;
int size;
-#ifdef DEBUG_TLB
- printk("[tlbkernelrange<%02x,%08lx,%08lx>]", start, end);
-#endif
local_irq_save(flags);
size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
size = (size + 1) >> 1;
if (idx < 0)
continue;
/* Make sure all entries differ. */
- write_c0_entryhi(KSEG0 + idx*0x2000);
+ write_c0_entryhi(KSEG0 + idx * 0x2000);
BARRIER;
tlb_write_indexed();
BARRIER;
{
int cpu = smp_processor_id();
- if (!vma || cpu_context(cpu, vma->vm_mm) != 0) {
+ if (cpu_context(cpu, vma->vm_mm) != 0) {
unsigned long flags;
int oldpid, newpid, idx;
-#ifdef DEBUG_TLB
- printk("[tlbpage<%d,%08lx>]", cpu_context(cpu, vma->vm_mm),
- page);
-#endif
- newpid = (cpu_context(cpu, vma->vm_mm) & ASID_MASK);
+ newpid = cpu_asid(cpu, vma->vm_mm);
page &= (PAGE_MASK << 1);
local_irq_save(flags);
- oldpid = (read_c0_entryhi() & ASID_MASK);
+ oldpid = read_c0_entryhi() & ASID_MASK;
write_c0_entryhi(page | newpid);
BARRIER;
tlb_probe();
idx = read_c0_index();
write_c0_entrylo0(0);
write_c0_entrylo1(0);
- if(idx < 0)
+ if (idx < 0)
goto finish;
/* Make sure all entries differ. */
- write_c0_entryhi(KSEG0+idx*0x2000);
+ write_c0_entryhi(KSEG0 + idx * 0x2000);
BARRIER;
tlb_write_indexed();
local_irq_restore(flags);
}
-/* We will need multiple versions of update_mmu_cache(), one that just
+/*
+ * We will need multiple versions of update_mmu_cache(), one that just
* updates the TLB with the new pte(s), and another which also checks
* for the R4k "end of page" hardware bug and does the needy.
*/
pid = read_c0_entryhi() & ASID_MASK;
-#ifdef DEBUG_TLB
- if ((pid != cpu_context(cpu, vma->vm_mm) & ASID_MASK) ||
- (cpu_context(vma->vm_mm) == 0)) {
- printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d "
- "tlbpid=%d\n",
- (int) (cpu_context(cpu, vma->vm_mm) & ASID_MASK), pid);
- }
-#endif
-
local_irq_save(flags);
address &= (PAGE_MASK << 1);
write_c0_entryhi(address | pid);
#endif
void __init add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
- unsigned long entryhi, unsigned long pagemask)
+ unsigned long entryhi, unsigned long pagemask)
{
unsigned long flags;
unsigned long wired;
prid = read_c0_prid() & ASID_MASK;
if (prid == PRID_IMP_RM7000 || !(config & (1 << 31)))
/*
- * Not a MIPS32 complianant CPU. Config 1 register not
+ * Not a MIPS32/MIPS64 CPU.. Config 1 register not
* supported, we assume R4k style. Cpu probing already figured
* out the number of tlb entries.
*/
return;
-#if defined(CONFIG_CPU_MIPS32) || defined (CONFIG_CPU_MIPS64)
config1 = read_c0_config1();
if (!((config >> 7) & 3))
panic("No MMU present");
else
current_cpu_data.tlbsize = ((config1 >> 25) & 0x3f) + 1;
-#endif
}
void __init r4k_tlb_init(void)
{
- u32 config = read_c0_config();
+ unsigned int config = read_c0_config();
/*
* You should never change this register:
temp_tlb_entry = current_cpu_data.tlbsize - 1;
local_flush_tlb_all();
- if (cpu_has_4kex && cpu_has_4ktlb) {
- if (current_cpu_data.cputype == CPU_NEVADA)
- memcpy((void *)KSEG0, &except_vec0_nevada, 0x80);
- else if (current_cpu_data.cputype == CPU_R4600)
- memcpy((void *)KSEG0, &except_vec0_r4600, 0x80);
- else
- memcpy((void *)KSEG0, &except_vec0_r4000, 0x80);
- flush_icache_range(KSEG0, KSEG0 + 0x80);
- }
+#ifdef CONFIG_MIPS32
+ if (current_cpu_data.cputype == CPU_NEVADA)
+ memcpy((void *)KSEG0, &except_vec0_nevada, 0x80);
+ else if (current_cpu_data.cputype == CPU_R4600)
+ memcpy((void *)KSEG0, &except_vec0_r4600, 0x80);
+ else
+ memcpy((void *)KSEG0, &except_vec0_r4000, 0x80);
+ flush_icache_range(KSEG0, KSEG0 + 0x80);
+#endif
+#ifdef CONFIG_MIPS64
+ memcpy((void *)(KSEG0 + 0x80), except_vec1_r4k, 0x80);
+ flush_icache_range(KSEG0 + 0x80, KSEG0 + 0x100);
+#endif
}