/* Initialize the wired register and all tlb entries to * known good state. */ void __init early_tlb_init(void) { unsigned long index; struct cpuinfo_mips *c = ¤t_cpu_data; tmp_tlb_ent = c->tlbsize; /* printk(KERN_ALERT "%s: tlb size %ld\n", __FUNCTION__, c->tlbsize); */ /* * initialize entire TLB to uniqe virtual addresses * but with the PAGE_VALID bit not set */ write_c0_pagemask(PM_DEFAULT_MASK); write_c0_wired(0); write_c0_entrylo0(0); /* not _PAGE_VALID */ write_c0_entrylo1(0); for (index = 0; index < c->tlbsize; index++) { /* Make sure all entries differ. */ write_c0_entryhi(UNIQUE_ENTRYHI(index+32)); write_c0_index(index); mtc0_tlbw_hazard(); tlb_write_indexed(); } tlbw_use_hazard(); }
void local_flush_tlb_all(void) { unsigned long flags; unsigned long old_ctx; int entry; ENTER_CRITICAL(flags); /* Save old context and create impossible VPN2 value */ old_ctx = read_c0_entryhi(); write_c0_entrylo0(0); write_c0_entrylo1(0); entry = read_c0_wired(); /* Blast 'em all away. */ while (entry < current_cpu_data.tlbsize) { /* Make sure all entries differ. */ write_c0_entryhi(UNIQUE_ENTRYHI(entry)); write_c0_index(entry); mtc0_tlbw_hazard(); tlb_write_indexed(); entry++; } tlbw_use_hazard(); write_c0_entryhi(old_ctx); FLUSH_ITLB; EXIT_CRITICAL(flags); }
void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { struct mm_struct *mm = vma->vm_mm; int cpu = smp_processor_id(); if (cpu_context(cpu, mm) != 0) { unsigned long size, flags; unsigned long config6_flags; ENTER_CRITICAL(flags); disable_pgwalker(config6_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(); int newpid = cpu_asid(cpu, mm); start &= (PAGE_MASK << 1); end += ((PAGE_SIZE << 1) - 1); end &= (PAGE_MASK << 1); while (start < end) { int idx; write_c0_entryhi(start | newpid); start += (PAGE_SIZE << 1); mtc0_tlbw_hazard(); tlb_probe(); tlb_probe_hazard(); idx = read_c0_index(); write_c0_entrylo0(0); write_c0_entrylo1(0); if (idx < 0) continue; /* Make sure all entries differ. */ #ifndef CONFIG_NLM_VMIPS write_c0_entryhi(UNIQUE_ENTRYHI(idx)); #else __write_64bit_c0_register($10, 0, (UNIQUE_VMIPS_ENTRYHI(idx))); #endif mtc0_tlbw_hazard(); tlb_write_indexed(); } tlbw_use_hazard(); write_c0_entryhi(oldpid); } else { drop_mmu_context(mm, cpu); } FLUSH_ITLB; enable_pgwalker(config6_flags); EXIT_CRITICAL(flags); }
void local_flush_tlb_all(void) { unsigned long flags; unsigned long old_ctx; int entry, ftlbhighset; local_irq_save(flags); /* Save old context and create impossible VPN2 value */ old_ctx = read_c0_entryhi(); htw_stop(); write_c0_entrylo0(0); write_c0_entrylo1(0); entry = read_c0_wired(); /* * Blast 'em all away. * If there are any wired entries, fall back to iterating */ if (cpu_has_tlbinv && !entry) { if (current_cpu_data.tlbsizevtlb) { write_c0_index(0); mtc0_tlbw_hazard(); tlbinvf(); /* invalidate VTLB */ } ftlbhighset = current_cpu_data.tlbsizevtlb + current_cpu_data.tlbsizeftlbsets; for (entry = current_cpu_data.tlbsizevtlb; entry < ftlbhighset; entry++) { write_c0_index(entry); mtc0_tlbw_hazard(); tlbinvf(); /* invalidate one FTLB set */ } } else { while (entry < current_cpu_data.tlbsize) { /* Make sure all entries differ. */ write_c0_entryhi(UNIQUE_ENTRYHI(entry)); write_c0_index(entry); mtc0_tlbw_hazard(); tlb_write_indexed(); entry++; } } tlbw_use_hazard(); write_c0_entryhi(old_ctx); htw_start(); flush_micro_tlb(); local_irq_restore(flags); }
void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { struct mm_struct *mm = vma->vm_mm; int cpu = smp_processor_id(); if (cpu_context(cpu, mm) != 0) { unsigned long size, flags; local_irq_save(flags); start = round_down(start, PAGE_SIZE << 1); end = round_up(end, PAGE_SIZE << 1); size = (end - start) >> (PAGE_SHIFT + 1); if (size <= (current_cpu_data.tlbsizeftlbsets ? current_cpu_data.tlbsize / 8 : current_cpu_data.tlbsize / 2)) { int oldpid = read_c0_entryhi(); int newpid = cpu_asid(cpu, mm); htw_stop(); while (start < end) { int idx; write_c0_entryhi(start | newpid); start += (PAGE_SIZE << 1); mtc0_tlbw_hazard(); tlb_probe(); tlb_probe_hazard(); idx = read_c0_index(); write_c0_entrylo0(0); write_c0_entrylo1(0); if (idx < 0) continue; /* Make sure all entries differ. */ write_c0_entryhi(UNIQUE_ENTRYHI(idx)); mtc0_tlbw_hazard(); tlb_write_indexed(); } tlbw_use_hazard(); write_c0_entryhi(oldpid); htw_start(); } else { drop_mmu_context(mm, cpu); } flush_micro_tlb(); local_irq_restore(flags); }
void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { struct mm_struct *mm = vma->vm_mm; int cpu = smp_processor_id(); if (cpu_context(cpu, mm) != 0) { unsigned long flags; int size; ENTER_CRITICAL(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; size = (size + 1) >> 1; local_irq_save(flags); if (size <= current_cpu_data.tlbsize/2) { int oldpid = read_c0_entryhi(); int newpid = cpu_asid(cpu, mm); start &= (PAGE_MASK << 1); end += ((PAGE_SIZE << 1) - 1); end &= (PAGE_MASK << 1); while (start < end) { int idx; write_c0_entryhi(start | newpid); start += (PAGE_SIZE << 1); mtc0_tlbw_hazard(); tlb_probe(); tlb_probe_hazard(); idx = read_c0_index(); write_c0_entrylo0(0); write_c0_entrylo1(0); if (idx < 0) continue; /* Make sure all entries differ. */ write_c0_entryhi(UNIQUE_ENTRYHI(idx)); mtc0_tlbw_hazard(); tlb_write_indexed(); } tlbw_use_hazard(); write_c0_entryhi(oldpid); } else { drop_mmu_context(mm, cpu); } EXIT_CRITICAL(flags); }
/** @brief Flush memory range If the memory range is too big, we flush all entries with this ASID */ void local_flush_tlb_range(unsigned int asid, unsigned long start, unsigned long end) { unsigned long size, flags; ENTER_CRITICAL(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(); int newpid = asid; start &= (PAGE_MASK << 1); end += ((PAGE_SIZE << 1) - 1); end &= (PAGE_MASK << 1); while (start < end) { int idx; write_c0_entryhi(start | newpid); start += (PAGE_SIZE << 1); mtc0_tlbw_hazard(); tlb_probe(); tlb_probe_hazard(); idx = read_c0_index(); write_c0_entrylo0(0); write_c0_entrylo1(0); if (idx < 0) continue; /* Make sure all entries differ. */ write_c0_entryhi(UNIQUE_ENTRYHI(idx)); mtc0_tlbw_hazard(); tlb_write_indexed(); } tlbw_use_hazard(); write_c0_entryhi(oldpid); } else local_flush_asid(asid); FLUSH_ITLB; EXIT_CRITICAL(flags); }
void local_flush_tlb_all(void) { unsigned long flags, config6_flags; unsigned long old_ctx; int entry; ENTER_CRITICAL(flags); disable_pgwalker(config6_flags); /* Save old context and create impossible VPN2 value */ old_ctx = read_c0_entryhi(); write_c0_entrylo0(0); write_c0_entrylo1(0); entry = read_c0_wired(); #if defined(CONFIG_MAPPED_KERNEL) if (!entry) printk("[%s] flushing entry=%d in MAPPED_KERNEL mode!\n", __FUNCTION__, entry); #endif /* Blast 'em all away. */ while (entry < current_cpu_data.tlbsize) { /* Make sure all entries differ. */ #ifndef CONFIG_NLM_VMIPS write_c0_entryhi(UNIQUE_ENTRYHI(entry)); #else __write_64bit_c0_register($10, 0, (UNIQUE_VMIPS_ENTRYHI(entry))); #endif write_c0_index(entry); mtc0_tlbw_hazard(); tlb_write_indexed(); entry++; } tlbw_use_hazard(); write_c0_entryhi(old_ctx); FLUSH_ITLB; enable_pgwalker(config6_flags); EXIT_CRITICAL(flags); }