summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/mips/mm/c-r4k.c74
1 files changed, 28 insertions, 46 deletions
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 738b89803a44..cf48371e5690 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -8,6 +8,7 @@
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
*/
#include <linux/init.h>
+#include <linux/highmem.h>
#include <linux/kernel.h>
#include <linux/linkage.h>
#include <linux/sched.h>
@@ -318,23 +319,6 @@ static void __init r4k_blast_scache_setup(void)
r4k_blast_scache = blast_scache128;
}
-/*
- * This is former mm's flush_cache_all() which really should be
- * flush_cache_vunmap these days ...
- */
-static inline void local_r4k_flush_cache_all(void * args)
-{
- r4k_blast_dcache();
-}
-
-static void r4k_flush_cache_all(void)
-{
- if (!cpu_has_dc_aliases)
- return;
-
- r4k_on_each_cpu(local_r4k_flush_cache_all, NULL, 1, 1);
-}
-
static inline void local_r4k___flush_cache_all(void * args)
{
#if defined(CONFIG_CPU_LOONGSON2)
@@ -423,13 +407,14 @@ static inline void local_r4k_flush_cache_page(void *args)
struct flush_cache_page_args *fcp_args = args;
struct vm_area_struct *vma = fcp_args->vma;
unsigned long addr = fcp_args->addr;
- unsigned long paddr = fcp_args->pfn << PAGE_SHIFT;
+ struct page *page = pfn_to_page(fcp_args->pfn);
int exec = vma->vm_flags & VM_EXEC;
struct mm_struct *mm = vma->vm_mm;
pgd_t *pgdp;
pud_t *pudp;
pmd_t *pmdp;
pte_t *ptep;
+ void *vaddr;
/*
* If ownes no valid ASID yet, cannot possibly have gotten
@@ -451,43 +436,40 @@ static inline void local_r4k_flush_cache_page(void *args)
if (!(pte_val(*ptep) & _PAGE_PRESENT))
return;
- /*
- * Doing flushes for another ASID than the current one is
- * too difficult since stupid R4k caches do a TLB translation
- * for every cache flush operation. So we do indexed flushes
- * in that case, which doesn't overly flush the cache too much.
- */
- if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) {
- if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) {
- r4k_blast_dcache_page(addr);
- if (exec && !cpu_icache_snoops_remote_store)
- r4k_blast_scache_page(addr);
- }
- if (exec)
- r4k_blast_icache_page(addr);
-
- return;
+ if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID))
+ vaddr = NULL;
+ else {
+ /*
+ * Use kmap_coherent or kmap_atomic to do flushes for
+ * another ASID than the current one.
+ */
+ if (cpu_has_dc_aliases)
+ vaddr = kmap_coherent(page, addr);
+ else
+ vaddr = kmap_atomic(page, KM_USER0);
+ addr = (unsigned long)vaddr;
}
- /*
- * Do indexed flush, too much work to get the (possible) TLB refills
- * to work correctly.
- */
if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) {
- r4k_blast_dcache_page_indexed(cpu_has_pindexed_dcache ?
- paddr : addr);
- if (exec && !cpu_icache_snoops_remote_store) {
- r4k_blast_scache_page_indexed(paddr);
- }
+ r4k_blast_dcache_page(addr);
+ if (exec && !cpu_icache_snoops_remote_store)
+ r4k_blast_scache_page(addr);
}
if (exec) {
- if (cpu_has_vtag_icache && mm == current->active_mm) {
+ if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) {
int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0)
drop_mmu_context(mm, cpu);
} else
- r4k_blast_icache_page_indexed(addr);
+ r4k_blast_icache_page(addr);
+ }
+
+ if (vaddr) {
+ if (cpu_has_dc_aliases)
+ kunmap_coherent();
+ else
+ kunmap_atomic(vaddr, KM_USER0);
}
}
@@ -1279,7 +1261,7 @@ void __init r4k_cache_init(void)
PAGE_SIZE - 1);
else
shm_align_mask = PAGE_SIZE-1;
- flush_cache_all = r4k_flush_cache_all;
+ flush_cache_all = cache_noop;
__flush_cache_all = r4k___flush_cache_all;
flush_cache_mm = r4k_flush_cache_mm;
flush_cache_page = r4k_flush_cache_page;