tlb-r3k.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:6k
- /*
- * 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/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=%dn",
- (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 %8xn, pagemask %8xn",
- 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);
- }