/* * If mm is currently active_mm, we can't really drop it. Instead, * we will get a new one for it. */ static inline void drop_mmu_context(struct mm_struct *mm) { unsigned long flags; local_irq_save(flags); get_new_mmu_context(mm); pevn_set(mm->context & ASID_MASK); local_irq_restore(flags); }
void local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { if (CPU_CONTEXT(smp_processor_id(), mm) != 0) { unsigned long flags; int size; #ifdef DEBUG_TLB printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff), start, end); #endif __save_and_cli(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; size = (size + 1) >> 1; if(size <= mips_cpu.tlbsize/2) { int oldpid = (get_entryhi() & 0xff); int newpid = (CPU_CONTEXT(smp_processor_id(), mm) & 0xff); start &= (PAGE_MASK << 1); end += ((PAGE_SIZE << 1) - 1); end &= (PAGE_MASK << 1); while(start < end) { int idx; set_entryhi(start | newpid); start += (PAGE_SIZE << 1); BARRIER; tlb_probe(); BARRIER; idx = get_index(); set_entrylo0(0); set_entrylo1(0); if(idx < 0) continue; /* Make sure all entries differ. */ set_entryhi(KSEG0+idx*0x2000); BARRIER; tlb_write_indexed(); BARRIER; } set_entryhi(oldpid); } else { get_new_mmu_context(mm, smp_processor_id()); if (mm == current->active_mm) set_entryhi(CPU_CONTEXT(smp_processor_id(), mm) & 0xff); } __restore_flags(flags); }
void local_flush_tlb_mm(struct mm_struct *mm) { if (mm->context != 0) { unsigned long flags; #ifdef DEBUG_TLB printk("[tlbmm<%d>]", mm->context); #endif __save_and_cli(flags); get_new_mmu_context(mm, smp_processor_id()); if (mm == current->active_mm) set_entryhi(mm->context & 0xff); __restore_flags(flags); } }
void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { struct mm_struct *mm = vma->vm_mm; unsigned long vma_mm_context = mm->context; if (mm->context != 0) { unsigned long flags; int size; local_irq_save(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; if (size <= TLBSIZE) { int oldpid = pevn_get() & ASID_MASK; int newpid = vma_mm_context & ASID_MASK; start &= PAGE_MASK; end += (PAGE_SIZE - 1); end &= PAGE_MASK; while (start < end) { int idx; pevn_set(start | newpid); start += PAGE_SIZE; barrier(); tlb_probe(); idx = tlbpt_get(); pectx_set(0); pevn_set(KSEG1); if (idx < 0) continue; tlb_write_indexed(); } pevn_set(oldpid); } else { /* Bigger than TLBSIZE, get new ASID directly */ get_new_mmu_context(mm); if (mm == current->active_mm) pevn_set(vma_mm_context & ASID_MASK); } local_irq_restore(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); }
/* * Flush the entrie MM for userland. The fastest way is to move to Next ASID */ noinline void local_flush_tlb_mm(struct mm_struct *mm) { /* * Small optimisation courtesy IA64 * flush_mm called during fork,exit,munmap etc, multiple times as well. * Only for fork( ) do we need to move parent to a new MMU ctxt, * all other cases are NOPs, hence this check. */ if (atomic_read(&mm->mm_users) == 0) return; /* * - Move to a new ASID, but only if the mm is still wired in * (Android Binder ended up calling this for vma->mm != tsk->mm, * causing h/w - s/w ASID to get out of sync) * - Also get_new_mmu_context() new implementation allocates a new * ASID only if it is not allocated already - so unallocate first */ destroy_context(mm); if (current->mm == mm) get_new_mmu_context(mm); }
/* * Select a new ASN and reload the context. This is * not inlined as this expands to a pretty large * function. */ void get_new_asn_and_reload(struct task_struct *tsk, struct mm_struct *mm) { get_new_mmu_context(tsk, mm, asn_cache); reload_context(tsk); }