diff options
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/kernel/smp.c | 17 | ||||
-rw-r--r-- | arch/mips/mm/c-r4k.c | 4 |
2 files changed, 19 insertions, 2 deletions
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index f9d01e953acb..0c98b4a313be 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -512,10 +512,17 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned l smp_on_other_tlbs(flush_tlb_range_ipi, &fd); } else { unsigned int cpu; + int exec = vma->vm_flags & VM_EXEC; for_each_online_cpu(cpu) { + /* + * flush_cache_range() will only fully flush icache if + * the VMA is executable, otherwise we must invalidate + * ASID without it appearing to has_valid_asid() as if + * mm has been completely unused by that CPU. + */ if (cpu != smp_processor_id() && cpu_context(cpu, mm)) - cpu_context(cpu, mm) = 0; + cpu_context(cpu, mm) = !exec; } } local_flush_tlb_range(vma, start, end); @@ -560,8 +567,14 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) unsigned int cpu; for_each_online_cpu(cpu) { + /* + * flush_cache_page() only does partial flushes, so + * invalidate ASID without it appearing to + * has_valid_asid() as if mm has been completely unused + * by that CPU. + */ if (cpu != smp_processor_id() && cpu_context(cpu, vma->vm_mm)) - cpu_context(cpu, vma->vm_mm) = 0; + cpu_context(cpu, vma->vm_mm) = 1; } } local_flush_tlb_page(vma, page); diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 645c69c95c9c..9204d4e4f02f 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -484,6 +484,10 @@ static void r4k__flush_cache_vunmap(void) r4k_blast_dcache(); } +/* + * Note: flush_tlb_range() assumes flush_cache_range() sufficiently flushes + * whole caches when vma is executable. + */ static inline void local_r4k_flush_cache_range(void * args) { struct vm_area_struct *vma = args; |