]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/mips/mm/c-r4k.c
x86, ptrace: rlimit BTS buffer allocation
[linux-2.6-omap-h63xx.git] / arch / mips / mm / c-r4k.c
index bad571971bf69f99bb8a64824309505fd479da84..02bd180f0e02748354383af23352900da6d1b02b 100644 (file)
@@ -7,8 +7,11 @@
  * 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/bitops.h>
@@ -162,12 +165,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)
@@ -193,12 +196,12 @@ 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);
@@ -317,23 +320,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)
@@ -343,7 +329,7 @@ static inline void local_r4k___flush_cache_all(void * args)
        r4k_blast_dcache();
        r4k_blast_icache();
 
-       switch (current_cpu_data.cputype) {
+       switch (current_cpu_type()) {
        case CPU_R4000SC:
        case CPU_R4000MC:
        case CPU_R4400SC:
@@ -360,11 +346,26 @@ static void r4k___flush_cache_all(void)
        r4k_on_each_cpu(local_r4k___flush_cache_all, NULL, 1, 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 inline void local_r4k_flush_cache_range(void * args)
 {
        struct vm_area_struct *vma = args;
 
-       if (!(cpu_context(smp_processor_id(), vma->vm_mm)))
+       if (!(has_valid_asid(vma->vm_mm)))
                return;
 
        r4k_blast_dcache();
@@ -383,7 +384,7 @@ 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;
 
        /*
@@ -392,10 +393,10 @@ static inline void local_r4k_flush_cache_mm(void * args)
         * 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;
        }
@@ -422,19 +423,20 @@ 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
         * this page into the cache.
         */
-       if (cpu_context(smp_processor_id(), mm) == 0)
+       if (!has_valid_asid(mm))
                return;
 
        addr &= PAGE_MASK;
@@ -447,46 +449,41 @@ 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.
+                */
+               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) {
-               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);
        }
 }
 
@@ -509,7 +506,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, 1);
 }
 
 struct flush_icache_range_args {
@@ -530,13 +531,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)
@@ -595,7 +589,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
                if (size >= scache_size)
                        r4k_blast_scache();
                else
-                       blast_scache_range(addr, addr + size);
+                       blast_inv_scache_range(addr, addr + size);
                return;
        }
 
@@ -603,7 +597,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
                r4k_blast_dcache();
        } else {
                R4600_HIT_CACHEOP_WAR_IMPL;
-               blast_dcache_range(addr, addr + size);
+               blast_inv_dcache_range(addr, addr + size);
        }
 
        bc_inv(addr, size);
@@ -948,12 +942,16 @@ 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:
@@ -982,6 +980,8 @@ 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;
        }
@@ -996,11 +996,15 @@ static void __init probe_pcache(void)
 
        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);
 }
 
 /*
@@ -1210,7 +1214,7 @@ static void __init 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:
@@ -1235,11 +1239,20 @@ void __init 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();
@@ -1265,7 +1278,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;