fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / sh / kernel / cpu / init.c
index a81b340..4812176 100644 (file)
@@ -4,6 +4,7 @@
  * CPU init code
  *
  * Copyright (C) 2002, 2003  Paul Mundt
+ * Copyright (C) 2003  Richard Curnow
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -13,6 +14,7 @@
 #include <linux/kernel.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
+#include <asm/page.h>
 #include <asm/system.h>
 #include <asm/cacheflush.h>
 #include <asm/cache.h>
@@ -24,13 +26,13 @@ extern void detect_cpu_and_cache_system(void);
  * Generic wrapper for command line arguments to disable on-chip
  * peripherals (nofpu, nodsp, and so forth).
  */
-#define onchip_setup(x)                        \
-static int x##_disabled __initdata = 0;        \
+#define onchip_setup(x)                                \
+static int x##_disabled __initdata = 0;                \
                                                \
 static int __init x##_setup(char *opts)                \
 {                                              \
        x##_disabled = 1;                       \
-       return 0;                               \
+       return 1;                               \
 }                                              \
 __setup("no" __stringify(x), x##_setup);
 
@@ -42,7 +44,7 @@ onchip_setup(dsp);
  */
 static void __init cache_init(void)
 {
-       unsigned long ccr, flags = 0;
+       unsigned long ccr, flags;
 
        if (cpu_data->type == CPU_SH_NONE)
                panic("Unknown CPU");
@@ -51,45 +53,65 @@ static void __init cache_init(void)
        ccr = ctrl_inl(CCR);
 
        /*
-        * If the cache is already enabled .. flush it.
+        * At this point we don't know whether the cache is enabled or not - a
+        * bootloader may have enabled it.  There are at least 2 things that
+        * could be dirty in the cache at this point:
+        * 1. kernel command line set up by boot loader
+        * 2. spilled registers from the prolog of this function
+        * => before re-initialising the cache, we must do a purge of the whole
+        * cache out to memory for safety.  As long as nothing is spilled
+        * during the loop to lines that have already been done, this is safe.
+        * - RPC
         */
        if (ccr & CCR_CACHE_ENABLE) {
-               unsigned long entries, i, j;
+               unsigned long ways, waysize, addrstart;
 
-               entries = cpu_data->dcache.sets;
+               waysize = cpu_data->dcache.sets;
 
+#ifdef CCR_CACHE_ORA
                /*
                 * If the OC is already in RAM mode, we only have
                 * half of the entries to flush..
                 */
                if (ccr & CCR_CACHE_ORA)
-                       entries >>= 1;
+                       waysize >>= 1;
+#endif
+
+               waysize <<= cpu_data->dcache.entry_shift;
 
-               for (i = 0; i < entries; i++) {
-                       for (j = 0; j < cpu_data->dcache.ways; j++) {
-                               unsigned long data, addr;
+#ifdef CCR_CACHE_EMODE
+               /* If EMODE is not set, we only have 1 way to flush. */
+               if (!(ccr & CCR_CACHE_EMODE))
+                       ways = 1;
+               else
+#endif
+                       ways = cpu_data->dcache.ways;
 
-                               addr = CACHE_OC_ADDRESS_ARRAY |
-                                       (j << cpu_data->dcache.way_shift) |
-                                       (i << cpu_data->dcache.entry_shift);
+               addrstart = CACHE_OC_ADDRESS_ARRAY;
+               do {
+                       unsigned long addr;
 
-                               data = ctrl_inl(addr);
+                       for (addr = addrstart;
+                            addr < addrstart + waysize;
+                            addr += cpu_data->dcache.linesz)
+                               ctrl_outl(0, addr);
 
-                               if ((data & (SH_CACHE_UPDATED | SH_CACHE_VALID))
-                                       == (SH_CACHE_UPDATED | SH_CACHE_VALID))
-                                       ctrl_outl(data & ~SH_CACHE_UPDATED, addr);
-                       }
-               }
+                       addrstart += cpu_data->dcache.way_incr;
+               } while (--ways);
        }
 
-       /* 
+       /*
         * Default CCR values .. enable the caches
-        * and flush them immediately..
+        * and invalidate them immediately..
         */
-       flags |= CCR_CACHE_ENABLE | CCR_CACHE_INVALIDATE;
-       
+       flags = CCR_CACHE_ENABLE | CCR_CACHE_INVALIDATE;
+
 #ifdef CCR_CACHE_EMODE
-       flags |= (ccr & CCR_CACHE_EMODE);
+       /* Force EMODE if possible */
+       if (cpu_data->dcache.ways > 1)
+               flags |= CCR_CACHE_EMODE;
+       else
+               flags &= ~CCR_CACHE_EMODE;
 #endif
 
 #ifdef CONFIG_SH_WRITETHROUGH
@@ -104,6 +126,9 @@ static void __init cache_init(void)
        /* Turn on OCRAM -- halve the OC */
        flags |= CCR_CACHE_ORA;
        cpu_data->dcache.sets >>= 1;
+
+       cpu_data->dcache.way_size = cpu_data->dcache.sets *
+                                   cpu_data->dcache.linesz;
 #endif
 
        ctrl_outl(flags, CCR);
@@ -145,14 +170,14 @@ static void __init dsp_init(void)
 
        /* If the DSP bit is still set, this CPU has a DSP */
        if (sr & SR_DSP)
-               set_bit(CPU_HAS_DSP, &(cpu_data->flags));
-       
+               cpu_data->flags |= CPU_HAS_DSP;
+
        /* Now that we've determined the DSP status, clear the DSP bit. */
        release_dsp();
 }
 #endif /* CONFIG_SH_DSP */
 
-/*
+/**
  * sh_cpu_init
  *
  * This is our initial entry point for each CPU, and is invoked on the boot
@@ -176,6 +201,10 @@ asmlinkage void __init sh_cpu_init(void)
        /* Init the cache */
        cache_init();
 
+       shm_align_mask = max_t(unsigned long,
+                              cpu_data->dcache.way_size - 1,
+                              PAGE_SIZE - 1);
+
        /* Disable the FPU */
        if (fpu_disabled) {
                printk("FPU Disabled\n");
@@ -184,15 +213,15 @@ asmlinkage void __init sh_cpu_init(void)
        }
 
        /* FPU initialization */
-       if (test_bit(CPU_HAS_FPU, &(cpu_data->flags))) {
+       if ((cpu_data->flags & CPU_HAS_FPU)) {
                clear_thread_flag(TIF_USEDFPU);
-               current->used_math = 0;
+               clear_used_math();
        }
 
 #ifdef CONFIG_SH_DSP
        /* Probe for DSP */
        dsp_init();
-       
+
        /* Disable the DSP */
        if (dsp_disabled) {
                printk("DSP Disabled\n");