patch-2.4.19 linux-2.4.19/arch/mips/mm/tlb-r3k.c
Next file: linux-2.4.19/arch/mips/mm/tlb-r4k.c
Previous file: linux-2.4.19/arch/mips/mm/sb1.c
Back to the patch index
Back to the overall index
- Lines: 258
- Date:
Fri Aug 2 17:39:43 2002
- Orig file:
linux-2.4.18/arch/mips/mm/tlb-r3k.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -urN linux-2.4.18/arch/mips/mm/tlb-r3k.c linux-2.4.19/arch/mips/mm/tlb-r3k.c
@@ -0,0 +1,257 @@
+/*
+ * r2300.c: R2000 and R3000 specific mmu/cache code.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * with a lot of changes to make this thing work for R3000s
+ * Tx39XX R4k style caches added. HK
+ * Copyright (C) 1998, 1999, 2000 Harald Koerfgen
+ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/mmu_context.h>
+#include <asm/system.h>
+#include <asm/isadep.h>
+#include <asm/io.h>
+#include <asm/wbflush.h>
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
+
+extern char except_vec0_r2300;
+
+#undef DEBUG_TLB
+
+int r3k_have_wired_reg = 0; /* should be in mips_cpu? */
+
+/* TLB operations. */
+void local_flush_tlb_all(void)
+{
+ unsigned long flags;
+ unsigned long old_ctx;
+ int entry;
+
+#ifdef DEBUG_TLB
+ printk("[tlball]");
+#endif
+
+ save_and_cli(flags);
+ old_ctx = (get_entryhi() & 0xfc0);
+ write_32bit_cp0_register(CP0_ENTRYLO0, 0);
+#ifdef CONFIG_CPU_TX39XX
+ entry = r3k_have_wired_reg ? get_wired() : 8;
+#else
+ entry = 8;
+#endif
+ for (; entry < mips_cpu.tlbsize; entry++) {
+ write_32bit_cp0_register(CP0_INDEX, entry << 8);
+ write_32bit_cp0_register(CP0_ENTRYHI, ((entry | 0x80000) << 12));
+ __asm__ __volatile__("tlbwi");
+ }
+ set_entryhi(old_ctx);
+ restore_flags(flags);
+}
+
+void local_flush_tlb_mm(struct mm_struct *mm)
+{
+ if (mm->context != 0) {
+ unsigned long flags;
+
+#ifdef DEBUG_TLB
+ printk("[tlbmm<%lu>]", (unsigned long) mm->context);
+#endif
+ save_and_cli(flags);
+ get_new_mmu_context(mm, smp_processor_id());
+ if (mm == current->active_mm)
+ set_entryhi(mm->context & 0xfc0);
+ restore_flags(flags);
+ }
+}
+
+void local_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+ unsigned long end)
+{
+ if (mm->context != 0) {
+ unsigned long flags;
+ int size;
+
+#ifdef DEBUG_TLB
+ printk("[tlbrange<%lu,0x%08lx,0x%08lx>]",
+ (mm->context & 0xfc0), start, end);
+#endif
+ save_and_cli(flags);
+ size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ if (size <= mips_cpu.tlbsize) {
+ int oldpid = (get_entryhi() & 0xfc0);
+ int newpid = (mm->context & 0xfc0);
+
+ start &= PAGE_MASK;
+ end += (PAGE_SIZE - 1);
+ end &= PAGE_MASK;
+ while (start < end) {
+ int idx;
+
+ set_entryhi(start | newpid);
+ start += PAGE_SIZE;
+ tlb_probe();
+ idx = get_index();
+ set_entrylo0(0);
+ set_entryhi(KSEG0);
+ if (idx < 0)
+ continue;
+ tlb_write_indexed();
+ }
+ set_entryhi(oldpid);
+ } else {
+ get_new_mmu_context(mm, smp_processor_id());
+ if (mm == current->active_mm)
+ set_entryhi(mm->context & 0xfc0);
+ }
+ restore_flags(flags);
+ }
+}
+
+void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+ if (!vma || vma->vm_mm->context != 0) {
+ unsigned long flags;
+ int oldpid, newpid, idx;
+
+#ifdef DEBUG_TLB
+ printk("[tlbpage<%lu,0x%08lx>]", vma->vm_mm->context, page);
+#endif
+ newpid = (vma->vm_mm->context & 0xfc0);
+ page &= PAGE_MASK;
+ save_and_cli(flags);
+ oldpid = (get_entryhi() & 0xfc0);
+ set_entryhi(page | newpid);
+ tlb_probe();
+ idx = get_index();
+ set_entrylo0(0);
+ set_entryhi(KSEG0);
+ if (idx < 0)
+ goto finish;
+ tlb_write_indexed();
+
+finish:
+ set_entryhi(oldpid);
+ restore_flags(flags);
+ }
+}
+
+void update_mmu_cache(struct vm_area_struct * vma, unsigned long address,
+ pte_t pte)
+{
+ unsigned long flags;
+ pgd_t *pgdp;
+ pmd_t *pmdp;
+ pte_t *ptep;
+ int idx, pid;
+
+ /*
+ * Handle debugger faulting in for debugee.
+ */
+ if (current->active_mm != vma->vm_mm)
+ return;
+
+ pid = get_entryhi() & 0xfc0;
+
+#ifdef DEBUG_TLB
+ if ((pid != (vma->vm_mm->context & 0xfc0)) || (vma->vm_mm->context == 0)) {
+ printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%lu tlbpid=%d\n",
+ (vma->vm_mm->context & 0xfc0), pid);
+ }
+#endif
+
+ save_and_cli(flags);
+ address &= PAGE_MASK;
+ set_entryhi(address | (pid));
+ pgdp = pgd_offset(vma->vm_mm, address);
+ tlb_probe();
+ pmdp = pmd_offset(pgdp, address);
+ idx = get_index();
+ ptep = pte_offset(pmdp, address);
+ set_entrylo0(pte_val(*ptep));
+ set_entryhi(address | (pid));
+ if (idx < 0) {
+ tlb_write_random();
+#if 0
+ printk("[MISS]");
+#endif
+ } else {
+ tlb_write_indexed();
+#if 0
+ printk("[HIT]");
+#endif
+ }
+ set_entryhi(pid);
+ restore_flags(flags);
+}
+
+void __init add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+ unsigned long entryhi, unsigned long pagemask)
+{
+ unsigned long flags;
+ unsigned long old_ctx;
+ static unsigned long wired = 0;
+
+#ifdef CONFIG_CPU_TX39XX
+ if (r3k_have_wired_reg) {
+ unsigned long old_pagemask;
+ unsigned long w;
+
+#ifdef DEBUG_TLB
+ printk("[tlbwired]");
+ printk("ently lo0 %8x, hi %8x\n, pagemask %8x\n",
+ entrylo0, entryhi, pagemask);
+#endif
+ save_and_cli(flags);
+ /* Save old context and create impossible VPN2 value */
+ old_ctx = (get_entryhi() & 0xff);
+ old_pagemask = get_pagemask();
+ w = get_wired();
+ set_wired (w + 1);
+ if (get_wired() != w + 1) {
+ printk("[tlbwired] No WIRED reg?\n");
+ return;
+ }
+ set_index (w << 8);
+ set_pagemask (pagemask);
+ set_entryhi(entryhi);
+ set_entrylo0(entrylo0);
+ tlb_write_indexed();
+
+ set_entryhi(old_ctx);
+ set_pagemask (old_pagemask);
+ local_flush_tlb_all();
+ restore_flags(flags);
+ return;
+ }
+#endif
+
+ if (wired < 8) {
+ __save_and_cli(flags);
+ old_ctx = get_entryhi() & 0xfc0;
+ set_entrylo0(entrylo0);
+ set_entryhi(entryhi);
+ set_index(wired);
+ wired++;
+ tlb_write_indexed();
+ set_entryhi(old_ctx);
+ local_flush_tlb_all();
+ __restore_flags(flags);
+ }
+}
+
+void __init r3k_tlb_init(void)
+{
+ local_flush_tlb_all();
+ memcpy((void *)KSEG0, &except_vec0_r2300, 0x80);
+ flush_icache_range(KSEG0, KSEG0 + 0x80);
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)