Blackfin arch: Fix bug - make ksz8893m driver available when bfin_mac is enabled
[safe/jmp/linux-2.6] / arch / mips / mm / c-r4k.c
index 256b661..c43f4b2 100644 (file)
@@ -7,10 +7,14 @@
  * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Ralf Baechle (ralf@gnu.org)
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  */
+#include <linux/hardirq.h>
 #include <linux/init.h>
+#include <linux/highmem.h>
 #include <linux/kernel.h>
+#include <linux/linkage.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/module.h>
 #include <linux/bitops.h>
 
 #include <asm/bcache.h>
@@ -23,6 +27,7 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/r4kcache.h>
+#include <asm/sections.h>
 #include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/war.h>
  *    primary cache.
  */
 static inline void r4k_on_each_cpu(void (*func) (void *info), void *info,
-                                   int retry, int wait)
+                                   int wait)
 {
        preempt_disable();
 
 #if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC)
-       smp_call_function(func, info, retry, wait);
+       smp_call_function(func, info, wait);
 #endif
        func(info);
        preempt_enable();
 }
 
+#if defined(CONFIG_MIPS_CMP)
+#define cpu_has_safe_index_cacheops 0
+#else
+#define cpu_has_safe_index_cacheops 1
+#endif
+
 /*
  * Must die.
  */
@@ -89,7 +100,7 @@ static inline void r4k_blast_dcache_page_dc32(unsigned long addr)
        blast_dcache32_page(addr);
 }
 
-static inline void r4k_blast_dcache_page_setup(void)
+static void __cpuinit r4k_blast_dcache_page_setup(void)
 {
        unsigned long  dc_lsize = cpu_dcache_line_size();
 
@@ -103,7 +114,7 @@ static inline void r4k_blast_dcache_page_setup(void)
 
 static void (* r4k_blast_dcache_page_indexed)(unsigned long addr);
 
-static inline void r4k_blast_dcache_page_indexed_setup(void)
+static void __cpuinit r4k_blast_dcache_page_indexed_setup(void)
 {
        unsigned long dc_lsize = cpu_dcache_line_size();
 
@@ -117,7 +128,7 @@ static inline void r4k_blast_dcache_page_indexed_setup(void)
 
 static void (* r4k_blast_dcache)(void);
 
-static inline void r4k_blast_dcache_setup(void)
+static void __cpuinit r4k_blast_dcache_setup(void)
 {
        unsigned long dc_lsize = cpu_dcache_line_size();
 
@@ -161,12 +172,12 @@ static inline void tx49_blast_icache32(void)
        /* I'm in even chunk.  blast odd chunks */
        for (ws = 0; ws < ws_end; ws += ws_inc)
                for (addr = start + 0x400; addr < end; addr += 0x400 * 2)
-                       cache32_unroll32(addr|ws,Index_Invalidate_I);
+                       cache32_unroll32(addr|ws, Index_Invalidate_I);
        CACHE32_UNROLL32_ALIGN;
        /* I'm in odd chunk.  blast even chunks */
        for (ws = 0; ws < ws_end; ws += ws_inc)
                for (addr = start; addr < end; addr += 0x400 * 2)
-                       cache32_unroll32(addr|ws,Index_Invalidate_I);
+                       cache32_unroll32(addr|ws, Index_Invalidate_I);
 }
 
 static inline void blast_icache32_r4600_v1_page_indexed(unsigned long page)
@@ -192,17 +203,17 @@ static inline void tx49_blast_icache32_page_indexed(unsigned long page)
        /* I'm in even chunk.  blast odd chunks */
        for (ws = 0; ws < ws_end; ws += ws_inc)
                for (addr = start + 0x400; addr < end; addr += 0x400 * 2)
-                       cache32_unroll32(addr|ws,Index_Invalidate_I);
+                       cache32_unroll32(addr|ws, Index_Invalidate_I);
        CACHE32_UNROLL32_ALIGN;
        /* I'm in odd chunk.  blast even chunks */
        for (ws = 0; ws < ws_end; ws += ws_inc)
                for (addr = start; addr < end; addr += 0x400 * 2)
-                       cache32_unroll32(addr|ws,Index_Invalidate_I);
+                       cache32_unroll32(addr|ws, Index_Invalidate_I);
 }
 
 static void (* r4k_blast_icache_page)(unsigned long addr);
 
-static inline void r4k_blast_icache_page_setup(void)
+static void __cpuinit r4k_blast_icache_page_setup(void)
 {
        unsigned long ic_lsize = cpu_icache_line_size();
 
@@ -219,7 +230,7 @@ static inline void r4k_blast_icache_page_setup(void)
 
 static void (* r4k_blast_icache_page_indexed)(unsigned long addr);
 
-static inline void r4k_blast_icache_page_indexed_setup(void)
+static void __cpuinit r4k_blast_icache_page_indexed_setup(void)
 {
        unsigned long ic_lsize = cpu_icache_line_size();
 
@@ -243,7 +254,7 @@ static inline void r4k_blast_icache_page_indexed_setup(void)
 
 static void (* r4k_blast_icache)(void);
 
-static inline void r4k_blast_icache_setup(void)
+static void __cpuinit r4k_blast_icache_setup(void)
 {
        unsigned long ic_lsize = cpu_icache_line_size();
 
@@ -264,7 +275,7 @@ static inline void r4k_blast_icache_setup(void)
 
 static void (* r4k_blast_scache_page)(unsigned long addr);
 
-static inline void r4k_blast_scache_page_setup(void)
+static void __cpuinit r4k_blast_scache_page_setup(void)
 {
        unsigned long sc_lsize = cpu_scache_line_size();
 
@@ -282,7 +293,7 @@ static inline void r4k_blast_scache_page_setup(void)
 
 static void (* r4k_blast_scache_page_indexed)(unsigned long addr);
 
-static inline void r4k_blast_scache_page_indexed_setup(void)
+static void __cpuinit r4k_blast_scache_page_indexed_setup(void)
 {
        unsigned long sc_lsize = cpu_scache_line_size();
 
@@ -300,7 +311,7 @@ static inline void r4k_blast_scache_page_indexed_setup(void)
 
 static void (* r4k_blast_scache)(void);
 
-static inline void r4k_blast_scache_setup(void)
+static void __cpuinit r4k_blast_scache_setup(void)
 {
        unsigned long sc_lsize = cpu_scache_line_size();
 
@@ -316,30 +327,16 @@ static inline void 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();
-       r4k_blast_icache();
-}
-
-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)
+       r4k_blast_scache();
+       return;
+#endif
        r4k_blast_dcache();
        r4k_blast_icache();
 
-       switch (current_cpu_data.cputype) {
+       switch (current_cpu_type()) {
        case CPU_R4000SC:
        case CPU_R4000MC:
        case CPU_R4400SC:
@@ -353,20 +350,43 @@ static inline void local_r4k___flush_cache_all(void * args)
 
 static void r4k___flush_cache_all(void)
 {
-       r4k_on_each_cpu(local_r4k___flush_cache_all, NULL, 1, 1);
+       r4k_on_each_cpu(local_r4k___flush_cache_all, NULL, 1);
+}
+
+static inline int has_valid_asid(const struct mm_struct *mm)
+{
+#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC)
+       int i;
+
+       for_each_online_cpu(i)
+               if (cpu_context(i, mm))
+                       return 1;
+
+       return 0;
+#else
+       return cpu_context(smp_processor_id(), mm);
+#endif
+}
+
+static void r4k__flush_cache_vmap(void)
+{
+       r4k_blast_dcache();
+}
+
+static void r4k__flush_cache_vunmap(void)
+{
+       r4k_blast_dcache();
 }
 
 static inline void local_r4k_flush_cache_range(void * args)
 {
        struct vm_area_struct *vma = args;
-       int exec;
+       int exec = vma->vm_flags & VM_EXEC;
 
-       if (!(cpu_context(smp_processor_id(), vma->vm_mm)))
+       if (!(has_valid_asid(vma->vm_mm)))
                return;
 
-       exec = vma->vm_flags & VM_EXEC;
-       if (cpu_has_dc_aliases || exec)
-               r4k_blast_dcache();
+       r4k_blast_dcache();
        if (exec)
                r4k_blast_icache();
 }
@@ -374,28 +394,34 @@ static inline void local_r4k_flush_cache_range(void * args)
 static void r4k_flush_cache_range(struct vm_area_struct *vma,
        unsigned long start, unsigned long end)
 {
-       r4k_on_each_cpu(local_r4k_flush_cache_range, vma, 1, 1);
+       int exec = vma->vm_flags & VM_EXEC;
+
+       if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc))
+               r4k_on_each_cpu(local_r4k_flush_cache_range, vma, 1);
 }
 
 static inline void local_r4k_flush_cache_mm(void * args)
 {
        struct mm_struct *mm = args;
 
-       if (!cpu_context(smp_processor_id(), mm))
+       if (!has_valid_asid(mm))
                return;
 
-       r4k_blast_dcache();
-       r4k_blast_icache();
-
        /*
         * Kludge alert.  For obscure reasons R4000SC and R4400SC go nuts if we
         * only flush the primary caches but R10000 and R12000 behave sane ...
+        * R4000SC and R4400SC indexed S-cache ops also invalidate primary
+        * caches, so we can bail out early.
         */
-       if (current_cpu_data.cputype == CPU_R4000SC ||
-           current_cpu_data.cputype == CPU_R4000MC ||
-           current_cpu_data.cputype == CPU_R4400SC ||
-           current_cpu_data.cputype == CPU_R4400MC)
+       if (current_cpu_type() == CPU_R4000SC ||
+           current_cpu_type() == CPU_R4000MC ||
+           current_cpu_type() == CPU_R4400SC ||
+           current_cpu_type() == CPU_R4400MC) {
                r4k_blast_scache();
+               return;
+       }
+
+       r4k_blast_dcache();
 }
 
 static void r4k_flush_cache_mm(struct mm_struct *mm)
@@ -403,7 +429,7 @@ static void r4k_flush_cache_mm(struct mm_struct *mm)
        if (!cpu_has_dc_aliases)
                return;
 
-       r4k_on_each_cpu(local_r4k_flush_cache_mm, mm, 1, 1);
+       r4k_on_each_cpu(local_r4k_flush_cache_mm, mm, 1);
 }
 
 struct flush_cache_page_args {
@@ -417,19 +443,21 @@ 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;
+       int map_coherent = 0;
        pgd_t *pgdp;
        pud_t *pudp;
        pmd_t *pmdp;
        pte_t *ptep;
+       void *vaddr;
 
        /*
         * If ownes no valid ASID yet, cannot possibly have gotten
         * this page into the cache.
         */
-       if (cpu_context(smp_processor_id(), mm) == 0)
+       if (!has_valid_asid(mm))
                return;
 
        addr &= PAGE_MASK;
@@ -442,46 +470,45 @@ static inline void local_r4k_flush_cache_page(void *args)
         * If the page isn't marked valid, the page cannot possibly be
         * in the cache.
         */
-       if (!(pte_val(*ptep) & _PAGE_PRESENT))
+       if (!(pte_present(*ptep)))
                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.
+                */
+               map_coherent = (cpu_has_dc_aliases &&
+                               page_mapped(page) && !Page_dcache_dirty(page));
+               if (map_coherent)
+                       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) {
+               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 (map_coherent)
+                       kunmap_coherent();
+               else
+                       kunmap_atomic(vaddr, KM_USER0);
        }
 }
 
@@ -494,7 +521,7 @@ static void r4k_flush_cache_page(struct vm_area_struct *vma,
        args.addr = addr;
        args.pfn = pfn;
 
-       r4k_on_each_cpu(local_r4k_flush_cache_page, &args, 1, 1);
+       r4k_on_each_cpu(local_r4k_flush_cache_page, &args, 1);
 }
 
 static inline void local_r4k_flush_data_cache_page(void * addr)
@@ -504,7 +531,11 @@ static inline void local_r4k_flush_data_cache_page(void * addr)
 
 static void r4k_flush_data_cache_page(unsigned long addr)
 {
-       r4k_on_each_cpu(local_r4k_flush_data_cache_page, (void *) addr, 1, 1);
+       if (in_atomic())
+               local_r4k_flush_data_cache_page((void *)addr);
+       else
+               r4k_on_each_cpu(local_r4k_flush_data_cache_page, (void *) addr,
+                               1);
 }
 
 struct flush_icache_range_args {
@@ -512,12 +543,8 @@ struct flush_icache_range_args {
        unsigned long end;
 };
 
-static inline void local_r4k_flush_icache_range(void *args)
+static inline void local_r4k_flush_icache_range(unsigned long start, unsigned long end)
 {
-       struct flush_icache_range_args *fir_args = args;
-       unsigned long start = fir_args->start;
-       unsigned long end = fir_args->end;
-
        if (!cpu_has_ic_fills_f_dc) {
                if (end - start >= dcache_size) {
                        r4k_blast_dcache();
@@ -525,13 +552,6 @@ static inline void local_r4k_flush_icache_range(void *args)
                        R4600_HIT_CACHEOP_WAR_IMPL;
                        protected_blast_dcache_range(start, end);
                }
-
-               if (!cpu_icache_snoops_remote_store && scache_size) {
-                       if (end - start > scache_size)
-                               r4k_blast_scache();
-                       else
-                               protected_blast_scache_range(start, end);
-               }
        }
 
        if (end - start > icache_size)
@@ -540,6 +560,15 @@ static inline void local_r4k_flush_icache_range(void *args)
                protected_blast_icache_range(start, end);
 }
 
+static inline void local_r4k_flush_icache_range_ipi(void *args)
+{
+       struct flush_icache_range_args *fir_args = args;
+       unsigned long start = fir_args->start;
+       unsigned long end = fir_args->end;
+
+       local_r4k_flush_icache_range(start, end);
+}
+
 static void r4k_flush_icache_range(unsigned long start, unsigned long end)
 {
        struct flush_icache_range_args args;
@@ -547,86 +576,10 @@ static void r4k_flush_icache_range(unsigned long start, unsigned long end)
        args.start = start;
        args.end = end;
 
-       r4k_on_each_cpu(local_r4k_flush_icache_range, &args, 1, 1);
+       r4k_on_each_cpu(local_r4k_flush_icache_range_ipi, &args, 1);
        instruction_hazard();
 }
 
-/*
- * Ok, this seriously sucks.  We use them to flush a user page but don't
- * know the virtual address, so we have to blast away the whole icache
- * which is significantly more expensive than the real thing.  Otoh we at
- * least know the kernel address of the page so we can flush it
- * selectivly.
- */
-
-struct flush_icache_page_args {
-       struct vm_area_struct *vma;
-       struct page *page;
-};
-
-static inline void local_r4k_flush_icache_page(void *args)
-{
-       struct flush_icache_page_args *fip_args = args;
-       struct vm_area_struct *vma = fip_args->vma;
-       struct page *page = fip_args->page;
-
-       /*
-        * Tricky ...  Because we don't know the virtual address we've got the
-        * choice of either invalidating the entire primary and secondary
-        * caches or invalidating the secondary caches also.  With the subset
-        * enforcment on R4000SC, R4400SC, R10000 and R12000 invalidating the
-        * secondary cache will result in any entries in the primary caches
-        * also getting invalidated which hopefully is a bit more economical.
-        */
-       if (cpu_has_inclusive_pcaches) {
-               unsigned long addr = (unsigned long) page_address(page);
-
-               r4k_blast_scache_page(addr);
-               ClearPageDcacheDirty(page);
-
-               return;
-       }
-
-       if (!cpu_has_ic_fills_f_dc) {
-               unsigned long addr = (unsigned long) page_address(page);
-               r4k_blast_dcache_page(addr);
-               if (!cpu_icache_snoops_remote_store)
-                       r4k_blast_scache_page(addr);
-               ClearPageDcacheDirty(page);
-       }
-
-       /*
-        * We're not sure of the virtual address(es) involved here, so
-        * we have to flush the entire I-cache.
-        */
-       if (cpu_has_vtag_icache) {
-               int cpu = smp_processor_id();
-
-               if (cpu_context(cpu, vma->vm_mm) != 0)
-                       drop_mmu_context(vma->vm_mm, cpu);
-       } else
-               r4k_blast_icache();
-}
-
-static void r4k_flush_icache_page(struct vm_area_struct *vma,
-       struct page *page)
-{
-       struct flush_icache_page_args args;
-
-       /*
-        * If there's no context yet, or the page isn't executable, no I-cache
-        * flush is needed.
-        */
-       if (!(vma->vm_flags & VM_EXEC))
-               return;
-
-       args.vma = vma;
-       args.page = page;
-
-       r4k_on_each_cpu(local_r4k_flush_icache_page, &args, 1, 1);
-}
-
-
 #ifdef CONFIG_DMA_NONCOHERENT
 
 static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
@@ -647,7 +600,7 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
         * subset property so we have to flush the primary caches
         * explicitly
         */
-       if (size >= dcache_size) {
+       if (cpu_has_safe_index_cacheops && size >= dcache_size) {
                r4k_blast_dcache();
        } else {
                R4600_HIT_CACHEOP_WAR_IMPL;
@@ -665,16 +618,36 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
        if (cpu_has_inclusive_pcaches) {
                if (size >= scache_size)
                        r4k_blast_scache();
-               else
-                       blast_scache_range(addr, addr + size);
+               else {
+                       unsigned long lsize = cpu_scache_line_size();
+                       unsigned long almask = ~(lsize - 1);
+
+                       /*
+                        * There is no clearly documented alignment requirement
+                        * for the cache instruction on MIPS processors and
+                        * some processors, among them the RM5200 and RM7000
+                        * QED processors will throw an address error for cache
+                        * hit ops with insufficient alignment.  Solved by
+                        * aligning the address to cache line size.
+                        */
+                       cache_op(Hit_Writeback_Inv_SD, addr & almask);
+                       cache_op(Hit_Writeback_Inv_SD,
+                                (addr + size - 1) & almask);
+                       blast_inv_scache_range(addr, addr + size);
+               }
                return;
        }
 
-       if (size >= dcache_size) {
+       if (cpu_has_safe_index_cacheops && size >= dcache_size) {
                r4k_blast_dcache();
        } else {
+               unsigned long lsize = cpu_dcache_line_size();
+               unsigned long almask = ~(lsize - 1);
+
                R4600_HIT_CACHEOP_WAR_IMPL;
-               blast_dcache_range(addr, addr + size);
+               cache_op(Hit_Writeback_Inv_D, addr & almask);
+               cache_op(Hit_Writeback_Inv_D, (addr + size - 1)  & almask);
+               blast_inv_dcache_range(addr, addr + size);
        }
 
        bc_inv(addr, size);
@@ -724,7 +697,7 @@ static void local_r4k_flush_cache_sigtramp(void * arg)
 
 static void r4k_flush_cache_sigtramp(unsigned long addr)
 {
-       r4k_on_each_cpu(local_r4k_flush_cache_sigtramp, (void *) addr, 1, 1);
+       r4k_on_each_cpu(local_r4k_flush_cache_sigtramp, (void *) addr, 1);
 }
 
 static void r4k_flush_icache_all(void)
@@ -765,11 +738,11 @@ static inline void rm7k_erratum31(void)
        }
 }
 
-static char *way_string[] __initdata = { NULL, "direct mapped", "2-way",
+static char *way_string[] __cpuinitdata = { NULL, "direct mapped", "2-way",
        "3-way", "4-way", "5-way", "6-way", "7-way", "8-way"
 };
 
-static void __init probe_pcache(void)
+static void __cpuinit probe_pcache(void)
 {
        struct cpuinfo_mips *c = &current_cpu_data;
        unsigned int config = read_c0_config();
@@ -862,17 +835,18 @@ static void __init probe_pcache(void)
                break;
 
        case CPU_VR4133:
-               write_c0_config(config & ~CONF_EB);
+               write_c0_config(config & ~VR41_CONF_P4K);
        case CPU_VR4131:
                /* Workaround for cache instruction bug of VR4131 */
                if (c->processor_id == 0x0c80U || c->processor_id == 0x0c81U ||
                    c->processor_id == 0x0c82U) {
-                       config &= ~0x00000030U;
                        config |= 0x00400000U;
                        if (c->processor_id == 0x0c80U)
                                config |= VR41_CONF_BP;
                        write_c0_config(config);
-               }
+               } else
+                       c->options |= MIPS_CPU_CACHE_CDEX_P;
+
                icache_size = 1 << (10 + ((config & CONF_IC) >> 9));
                c->icache.linesz = 16 << ((config & CONF_IB) >> 5);
                c->icache.ways = 2;
@@ -882,8 +856,6 @@ static void __init probe_pcache(void)
                c->dcache.linesz = 16 << ((config & CONF_DB) >> 4);
                c->dcache.ways = 2;
                c->dcache.waybit = __ffs(dcache_size/2);
-
-               c->options |= MIPS_CPU_CACHE_CDEX_P;
                break;
 
        case CPU_VR41XX:
@@ -925,6 +897,24 @@ static void __init probe_pcache(void)
                c->options |= MIPS_CPU_PREFETCH;
                break;
 
+       case CPU_LOONGSON2:
+               icache_size = 1 << (12 + ((config & CONF_IC) >> 9));
+               c->icache.linesz = 16 << ((config & CONF_IB) >> 5);
+               if (prid & 0x3)
+                       c->icache.ways = 4;
+               else
+                       c->icache.ways = 2;
+               c->icache.waybit = 0;
+
+               dcache_size = 1 << (12 + ((config & CONF_DC) >> 6));
+               c->dcache.linesz = 16 << ((config & CONF_DB) >> 4);
+               if (prid & 0x3)
+                       c->dcache.ways = 4;
+               else
+                       c->dcache.ways = 2;
+               c->dcache.waybit = 0;
+               break;
+
        default:
                if (!(config & MIPS_CONF_M))
                        panic("Don't know how to probe P-caches on this cpu.");
@@ -1002,15 +992,20 @@ static void __init probe_pcache(void)
        switch (c->cputype) {
        case CPU_20KC:
        case CPU_25KF:
+       case CPU_SB1:
+       case CPU_SB1A:
                c->dcache.flags |= MIPS_CACHE_PINDEX;
+               break;
+
        case CPU_R10000:
        case CPU_R12000:
        case CPU_R14000:
-       case CPU_SB1:
                break;
+
        case CPU_24K:
        case CPU_34K:
        case CPU_74K:
+       case CPU_1004K:
                if ((read_c0_config7() & (1 << 16))) {
                        /* effectively physically indexed dcache,
                           thus no virtual aliases. */
@@ -1036,17 +1031,31 @@ static void __init probe_pcache(void)
        case CPU_AU1100:
        case CPU_AU1550:
        case CPU_AU1200:
+       case CPU_AU1210:
+       case CPU_AU1250:
                c->icache.flags |= MIPS_CACHE_IC_F_DC;
                break;
        }
 
+#ifdef  CONFIG_CPU_LOONGSON2
+       /*
+        * LOONGSON2 has 4 way icache, but when using indexed cache op,
+        * one op will act on all 4 ways
+        */
+       c->icache.ways = 1;
+#endif
+
        printk("Primary instruction cache %ldkB, %s, %s, linesize %d bytes.\n",
               icache_size >> 10,
-              cpu_has_vtag_icache ? "virtually tagged" : "physically tagged",
+              cpu_has_vtag_icache ? "VIVT" : "VIPT",
               way_string[c->icache.ways], c->icache.linesz);
 
-       printk("Primary data cache %ldkB, %s, linesize %d bytes.\n",
-              dcache_size >> 10, way_string[c->dcache.ways], c->dcache.linesz);
+       printk("Primary data cache %ldkB, %s, %s, %s, linesize %d bytes\n",
+              dcache_size >> 10, way_string[c->dcache.ways],
+              (c->dcache.flags & MIPS_CACHE_PINDEX) ? "PIPT" : "VIPT",
+              (c->dcache.flags & MIPS_CACHE_ALIASES) ?
+                       "cache aliases" : "no aliases",
+              c->dcache.linesz);
 }
 
 /*
@@ -1055,9 +1064,8 @@ static void __init probe_pcache(void)
  * executes in KSEG1 space or else you will crash and burn badly.  You have
  * been warned.
  */
-static int __init probe_scache(void)
+static int __cpuinit probe_scache(void)
 {
-       extern unsigned long stext;
        unsigned long flags, addr, begin, end, pow2;
        unsigned int config = read_c0_config();
        struct cpuinfo_mips *c = &current_cpu_data;
@@ -1066,7 +1074,7 @@ static int __init probe_scache(void)
        if (config & CONF_SC)
                return 0;
 
-       begin = (unsigned long) &stext;
+       begin = (unsigned long) &_stext;
        begin &= ~((4 * 1024 * 1024) - 1);
        end = begin + (4 * 1024 * 1024);
 
@@ -1113,11 +1121,29 @@ static int __init probe_scache(void)
        return 1;
 }
 
+#if defined(CONFIG_CPU_LOONGSON2)
+static void __init loongson2_sc_init(void)
+{
+       struct cpuinfo_mips *c = &current_cpu_data;
+
+       scache_size = 512*1024;
+       c->scache.linesz = 32;
+       c->scache.ways = 4;
+       c->scache.waybit = 0;
+       c->scache.waysize = scache_size / (c->scache.ways);
+       c->scache.sets = scache_size / (c->scache.linesz * c->scache.ways);
+       pr_info("Unified secondary cache %ldkB %s, linesize %d bytes.\n",
+              scache_size >> 10, way_string[c->scache.ways], c->scache.linesz);
+
+       c->options |= MIPS_CPU_INCLUSIVE_CACHES;
+}
+#endif
+
 extern int r5k_sc_init(void);
 extern int rm7k_sc_init(void);
 extern int mips_sc_init(void);
 
-static void __init setup_scache(void)
+static void __cpuinit setup_scache(void)
 {
        struct cpuinfo_mips *c = &current_cpu_data;
        unsigned int config = read_c0_config();
@@ -1126,7 +1152,7 @@ static void __init setup_scache(void)
        /*
         * Do the probing thing on R4000SC and R4400SC processors.  Other
         * processors don't have a S-cache that would be relevant to the
-        * Linux memory managment.
+        * Linux memory management.
         */
        switch (c->cputype) {
        case CPU_R4000SC:
@@ -1162,6 +1188,12 @@ static void __init setup_scache(void)
 #endif
                return;
 
+#if defined(CONFIG_CPU_LOONGSON2)
+       case CPU_LOONGSON2:
+               loongson2_sc_init();
+               return;
+#endif
+
        default:
                if (c->isa_level == MIPS_CPU_ISA_M32R1 ||
                    c->isa_level == MIPS_CPU_ISA_M32R2 ||
@@ -1222,9 +1254,47 @@ void au1x00_fixup_config_od(void)
        }
 }
 
-static inline void coherency_setup(void)
+/* CP0 hazard avoidance. */
+#define NXP_BARRIER()                                                  \
+        __asm__ __volatile__(                                          \
+       ".set noreorder\n\t"                                            \
+       "nop; nop; nop; nop; nop; nop;\n\t"                             \
+       ".set reorder\n\t")
+
+static void nxp_pr4450_fixup_config(void)
+{
+       unsigned long config0;
+
+       config0 = read_c0_config();
+
+       /* clear all three cache coherency fields */
+       config0 &= ~(0x7 | (7 << 25) | (7 << 28));
+       config0 |= (((_page_cachable_default >> _CACHE_SHIFT) <<  0) |
+                   ((_page_cachable_default >> _CACHE_SHIFT) << 25) |
+                   ((_page_cachable_default >> _CACHE_SHIFT) << 28));
+       write_c0_config(config0);
+       NXP_BARRIER();
+}
+
+static int __cpuinitdata cca = -1;
+
+static int __init cca_setup(char *str)
+{
+       get_option(&str, &cca);
+
+       return 1;
+}
+
+__setup("cca=", cca_setup);
+
+static void __cpuinit coherency_setup(void)
 {
-       change_c0_config(CONF_CM_CMASK, CONF_CM_DEFAULT);
+       if (cca < 0 || cca > 7)
+               cca = read_c0_config() & CONF_CM_CMASK;
+       _page_cachable_default = cca << _CACHE_SHIFT;
+
+       pr_debug("Using cache attribute %d\n", cca);
+       change_c0_config(CONF_CM_CMASK, cca);
 
        /*
         * c0_status.cu=0 specifies that updates by the sc instruction use
@@ -1233,7 +1303,7 @@ static inline void coherency_setup(void)
         * this bit and; some wire it to zero, others like Toshiba had the
         * silly idea of putting something else there ...
         */
-       switch (current_cpu_data.cputype) {
+       switch (current_cpu_type()) {
        case CPU_R4000PC:
        case CPU_R4000SC:
        case CPU_R4000MC:
@@ -1243,7 +1313,7 @@ static inline void coherency_setup(void)
                clear_c0_config(CONF_CU);
                break;
        /*
-        * We need to catch the ealry Alchemy SOCs with
+        * We need to catch the early Alchemy SOCs with
         * the write-only co_config.od bit and set it back to one...
         */
        case CPU_AU1000: /* rev. DA, HA, HB */
@@ -1251,18 +1321,45 @@ static inline void coherency_setup(void)
        case CPU_AU1500: /* rev. AB */
                au1x00_fixup_config_od();
                break;
+
+       case PRID_IMP_PR4450:
+               nxp_pr4450_fixup_config();
+               break;
        }
 }
 
-void __init r4k_cache_init(void)
+#if defined(CONFIG_DMA_NONCOHERENT)
+
+static int __cpuinitdata coherentio;
+
+static int __init setcoherentio(char *str)
+{
+       coherentio = 1;
+
+       return 1;
+}
+
+__setup("coherentio", setcoherentio);
+#endif
+
+void __cpuinit r4k_cache_init(void)
 {
        extern void build_clear_page(void);
        extern void build_copy_page(void);
-       extern char except_vec2_generic;
+       extern char __weak except_vec2_generic;
+       extern char __weak except_vec2_sb1;
        struct cpuinfo_mips *c = &current_cpu_data;
 
-       /* Default cache error handler for R4000 and R5000 family */
-       set_uncached_handler (0x100, &except_vec2_generic, 0x80);
+       switch (c->cputype) {
+       case CPU_SB1:
+       case CPU_SB1A:
+               set_uncached_handler(0x100, &except_vec2_sb1, 0x80);
+               break;
+
+       default:
+               set_uncached_handler(0x100, &except_vec2_generic, 0x80);
+               break;
+       }
 
        probe_pcache();
        setup_scache();
@@ -1288,11 +1385,14 @@ 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_vmap      = r4k__flush_cache_vmap;
+       __flush_cache_vunmap    = r4k__flush_cache_vunmap;
+
+       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;
-       flush_icache_page       = r4k_flush_icache_page;
        flush_cache_range       = r4k_flush_cache_range;
 
        flush_cache_sigtramp    = r4k_flush_cache_sigtramp;
@@ -1300,15 +1400,24 @@ void __init r4k_cache_init(void)
        local_flush_data_cache_page     = local_r4k_flush_data_cache_page;
        flush_data_cache_page   = r4k_flush_data_cache_page;
        flush_icache_range      = r4k_flush_icache_range;
+       local_flush_icache_range        = local_r4k_flush_icache_range;
 
-#ifdef CONFIG_DMA_NONCOHERENT
-       _dma_cache_wback_inv    = r4k_dma_cache_wback_inv;
-       _dma_cache_wback        = r4k_dma_cache_wback_inv;
-       _dma_cache_inv          = r4k_dma_cache_inv;
+#if defined(CONFIG_DMA_NONCOHERENT)
+       if (coherentio) {
+               _dma_cache_wback_inv    = (void *)cache_noop;
+               _dma_cache_wback        = (void *)cache_noop;
+               _dma_cache_inv          = (void *)cache_noop;
+       } else {
+               _dma_cache_wback_inv    = r4k_dma_cache_wback_inv;
+               _dma_cache_wback        = r4k_dma_cache_wback_inv;
+               _dma_cache_inv          = r4k_dma_cache_inv;
+       }
 #endif
 
        build_clear_page();
        build_copy_page();
+#if !defined(CONFIG_MIPS_CMP)
        local_r4k___flush_cache_all(NULL);
+#endif
        coherency_setup();
 }