fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / arm / kernel / setup.c
index d58a35e..bbab134 100644 (file)
@@ -7,7 +7,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <linux/config.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/stddef.h>
 #include <linux/ioport.h>
 #include <linux/console.h>
 #include <linux/bootmem.h>
 #include <linux/seq_file.h>
-#include <linux/tty.h>
+#include <linux/screen_info.h>
 #include <linux/init.h>
 #include <linux/root_dev.h>
 #include <linux/cpu.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
 
+#include <asm/cpu.h>
 #include <asm/elf.h>
-#include <asm/hardware.h>
-#include <asm/io.h>
 #include <asm/procinfo.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
@@ -33,6 +34,9 @@
 
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+
+#include "compat.h"
 
 #ifndef MEM_SIZE
 #define MEM_SIZE       (16*1024*1024)
@@ -50,21 +54,27 @@ static int __init fpe_setup(char *line)
 __setup("fpe=", fpe_setup);
 #endif
 
-extern unsigned int mem_fclk_21285;
 extern void paging_init(struct meminfo *, struct machine_desc *desc);
-extern void convert_to_tag_list(struct tag *tags);
-extern void squash_mem_tags(struct tag *tag);
-extern void bootmem_init(struct meminfo *);
 extern void reboot_setup(char *str);
 extern int root_mountflags;
-extern int _stext, _text, _etext, _edata, _end;
+extern void _stext, _text, _etext, __data_start, _edata, _end;
 
 unsigned int processor_id;
 unsigned int __machine_arch_type;
+EXPORT_SYMBOL(__machine_arch_type);
+
 unsigned int system_rev;
+EXPORT_SYMBOL(system_rev);
+
 unsigned int system_serial_low;
+EXPORT_SYMBOL(system_serial_low);
+
 unsigned int system_serial_high;
+EXPORT_SYMBOL(system_serial_high);
+
 unsigned int elf_hwcap;
+EXPORT_SYMBOL(elf_hwcap);
+
 
 #ifdef MULTI_CPU
 struct processor processor;
@@ -79,9 +89,17 @@ struct cpu_user_fns cpu_user;
 struct cpu_cache_fns cpu_cache;
 #endif
 
-unsigned char aux_device_present;
+struct stack {
+       u32 irq[3];
+       u32 abt[3];
+       u32 und[3];
+} ____cacheline_aligned;
+
+static struct stack stacks[NR_CPUS];
+
 char elf_platform[ELF_PLATFORM_SIZE];
-char saved_command_line[COMMAND_LINE_SIZE];
+EXPORT_SYMBOL(elf_platform);
+
 unsigned long phys_initrd_start __initdata = 0;
 unsigned long phys_initrd_size __initdata = 0;
 
@@ -94,13 +112,30 @@ static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
 static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
 #define ENDIANNESS ((char)endian_test.l)
 
+DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
+
 /*
  * Standard memory resources
  */
 static struct resource mem_res[] = {
-       { "Video RAM",   0,     0,     IORESOURCE_MEM                   },
-       { "Kernel code", 0,     0,     IORESOURCE_MEM                   },
-       { "Kernel data", 0,     0,     IORESOURCE_MEM                   }
+       {
+               .name = "Video RAM",
+               .start = 0,
+               .end = 0,
+               .flags = IORESOURCE_MEM
+       },
+       {
+               .name = "Kernel text",
+               .start = 0,
+               .end = 0,
+               .flags = IORESOURCE_MEM
+       },
+       {
+               .name = "Kernel data",
+               .start = 0,
+               .end = 0,
+               .flags = IORESOURCE_MEM
+       }
 };
 
 #define video_ram   mem_res[0]
@@ -108,9 +143,24 @@ static struct resource mem_res[] = {
 #define kernel_data mem_res[2]
 
 static struct resource io_res[] = {
-       { "reserved",    0x3bc, 0x3be, IORESOURCE_IO | IORESOURCE_BUSY },
-       { "reserved",    0x378, 0x37f, IORESOURCE_IO | IORESOURCE_BUSY },
-       { "reserved",    0x278, 0x27f, IORESOURCE_IO | IORESOURCE_BUSY }
+       {
+               .name = "reserved",
+               .start = 0x3bc,
+               .end = 0x3be,
+               .flags = IORESOURCE_IO | IORESOURCE_BUSY
+       },
+       {
+               .name = "reserved",
+               .start = 0x378,
+               .end = 0x37f,
+               .flags = IORESOURCE_IO | IORESOURCE_BUSY
+       },
+       {
+               .name = "reserved",
+               .start = 0x278,
+               .end = 0x27f,
+               .flags = IORESOURCE_IO | IORESOURCE_BUSY
+       }
 };
 
 #define lp0 io_res[0]
@@ -118,21 +168,21 @@ static struct resource io_res[] = {
 #define lp2 io_res[2]
 
 static const char *cache_types[16] = {
-       "VIVT write-through",
-       "VIVT write-back",
-       "VIVT write-back",
+       "write-through",
+       "write-back",
+       "write-back",
        "undefined 3",
        "undefined 4",
        "undefined 5",
-       "VIVT write-back",
-       "VIVT write-back",
+       "write-back",
+       "write-back",
        "undefined 8",
        "undefined 9",
        "undefined 10",
        "undefined 11",
        "undefined 12",
        "undefined 13",
-       "VIPT write-back",
+       "write-back",
        "undefined 15",
 };
 
@@ -184,7 +234,7 @@ static const char *proc_arch[] = {
        "5TE",
        "5TEJ",
        "6TEJ",
-       "?(10)",
+       "7",
        "?(11)",
        "?(12)",
        "?(13)",
@@ -204,12 +254,12 @@ static const char *proc_arch[] = {
 #define CACHE_M(y)     ((y) & (1 << 2))
 #define CACHE_LINE(y)  ((y) & 3)
 
-static inline void dump_cache(const char *prefix, unsigned int cache)
+static inline void dump_cache(const char *prefix, int cpu, unsigned int cache)
 {
        unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
 
-       printk("%s: %d bytes, associativity %d, %d byte lines, %d sets\n",
-               prefix,
+       printk("CPU%u: %s: %d bytes, associativity %d, %d byte lines, %d sets\n",
+               cpu, prefix,
                mult << (8 + CACHE_SIZE(cache)),
                (mult << CACHE_ASSOC(cache)) >> 1,
                8 << CACHE_LINE(cache),
@@ -217,41 +267,54 @@ static inline void dump_cache(const char *prefix, unsigned int cache)
                        CACHE_LINE(cache)));
 }
 
-static void __init dump_cpu_info(void)
+static void __init dump_cpu_info(int cpu)
 {
        unsigned int info = read_cpuid(CPUID_CACHETYPE);
 
        if (info != processor_id) {
-               printk("CPU: D %s cache\n", cache_types[CACHE_TYPE(info)]);
+               printk("CPU%u: D %s %s cache\n", cpu, cache_is_vivt() ? "VIVT" : "VIPT",
+                      cache_types[CACHE_TYPE(info)]);
                if (CACHE_S(info)) {
-                       dump_cache("CPU: I cache", CACHE_ISIZE(info));
-                       dump_cache("CPU: D cache", CACHE_DSIZE(info));
+                       dump_cache("I cache", cpu, CACHE_ISIZE(info));
+                       dump_cache("D cache", cpu, CACHE_DSIZE(info));
                } else {
-                       dump_cache("CPU: cache", CACHE_ISIZE(info));
+                       dump_cache("cache", cpu, CACHE_ISIZE(info));
                }
        }
+
+       if (arch_is_coherent())
+               printk("Cache coherency enabled\n");
 }
 
 int cpu_architecture(void)
 {
        int cpu_arch;
 
-       if ((processor_id & 0x0000f000) == 0) {
+       if ((processor_id & 0x0008f000) == 0) {
                cpu_arch = CPU_ARCH_UNKNOWN;
-       } else if ((processor_id & 0x0000f000) == 0x00007000) {
+       } else if ((processor_id & 0x0008f000) == 0x00007000) {
                cpu_arch = (processor_id & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
-       } else {
-               cpu_arch = (processor_id >> 16) & 15;
+       } else if ((processor_id & 0x00080000) == 0x00000000) {
+               cpu_arch = (processor_id >> 16) & 7;
                if (cpu_arch)
                        cpu_arch += CPU_ARCH_ARMv3;
+       } else {
+               /* the revised CPUID */
+               cpu_arch = ((processor_id >> 12) & 0xf) - 0xb + CPU_ARCH_ARMv6;
        }
 
        return cpu_arch;
 }
 
+/*
+ * These functions re-use the assembly code in head.S, which
+ * already provide the required functionality.
+ */
+extern struct proc_info_list *lookup_processor_type(unsigned int);
+extern struct machine_desc *lookup_machine_type(unsigned int);
+
 static void __init setup_processor(void)
 {
-       extern struct proc_info_list __proc_info_begin, __proc_info_end;
        struct proc_info_list *list;
 
        /*
@@ -259,15 +322,8 @@ static void __init setup_processor(void)
         * types.  The linker builds this table for us from the
         * entries in arch/arm/mm/proc-*.S
         */
-       for (list = &__proc_info_begin; list < &__proc_info_end ; list++)
-               if ((processor_id & list->cpu_mask) == list->cpu_val)
-                       break;
-
-       /*
-        * If processor type is unrecognised, then we
-        * can do nothing...
-        */
-       if (list >= &__proc_info_end) {
+       list = lookup_processor_type(processor_id);
+       if (!list) {
                printk("CPU configuration botched (ID %08x), unable "
                       "to continue.\n", processor_id);
                while (1);
@@ -288,37 +344,72 @@ static void __init setup_processor(void)
        cpu_cache = *list->cache;
 #endif
 
-       printk("CPU: %s [%08x] revision %d (ARMv%s)\n",
+       printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
               cpu_name, processor_id, (int)processor_id & 15,
-              proc_arch[cpu_architecture()]);
+              proc_arch[cpu_architecture()], cr_alignment);
 
-       dump_cpu_info();
-
-       sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS);
+       sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS);
        sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
        elf_hwcap = list->elf_hwcap;
+#ifndef CONFIG_ARM_THUMB
+       elf_hwcap &= ~HWCAP_THUMB;
+#endif
 
        cpu_proc_init();
 }
 
-static struct machine_desc * __init setup_machine(unsigned int nr)
+/*
+ * cpu_init - initialise one CPU.
+ *
+ * cpu_init dumps the cache information, initialises SMP specific
+ * information, and sets up the per-CPU stacks.
+ */
+void cpu_init(void)
 {
-       extern struct machine_desc __arch_info_begin, __arch_info_end;
-       struct machine_desc *list;
+       unsigned int cpu = smp_processor_id();
+       struct stack *stk = &stacks[cpu];
+
+       if (cpu >= NR_CPUS) {
+               printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);
+               BUG();
+       }
+
+       if (system_state == SYSTEM_BOOTING)
+               dump_cpu_info(cpu);
 
        /*
-        * locate architecture in the list of supported architectures.
+        * setup stacks for re-entrant exception handlers
         */
-       for (list = &__arch_info_begin; list < &__arch_info_end; list++)
-               if (list->nr == nr)
-                       break;
+       __asm__ (
+       "msr    cpsr_c, %1\n\t"
+       "add    sp, %0, %2\n\t"
+       "msr    cpsr_c, %3\n\t"
+       "add    sp, %0, %4\n\t"
+       "msr    cpsr_c, %5\n\t"
+       "add    sp, %0, %6\n\t"
+       "msr    cpsr_c, %7"
+           :
+           : "r" (stk),
+             "I" (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
+             "I" (offsetof(struct stack, irq[0])),
+             "I" (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
+             "I" (offsetof(struct stack, abt[0])),
+             "I" (PSR_F_BIT | PSR_I_BIT | UND_MODE),
+             "I" (offsetof(struct stack, und[0])),
+             "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
+           : "r14");
+}
+
+static struct machine_desc * __init setup_machine(unsigned int nr)
+{
+       struct machine_desc *list;
 
        /*
-        * If the architecture type is not recognised, then we
-        * can co nothing...
+        * locate machine in the list of supported machines.
         */
-       if (list >= &__arch_info_end) {
-               printk("Architecture configuration botched (nr %d), unable "
+       list = lookup_machine_type(nr);
+       if (!list) {
+               printk("Machine configuration botched (nr %d), unable "
                       "to continue.\n", nr);
                while (1);
        }
@@ -342,6 +433,23 @@ static void __init early_initrd(char **p)
 }
 __early_param("initrd=", early_initrd);
 
+static void __init arm_add_memory(unsigned long start, unsigned long size)
+{
+       struct membank *bank;
+
+       /*
+        * Ensure that start/size are aligned to a page boundary.
+        * Size is appropriately rounded down, start is rounded up.
+        */
+       size -= start & ~PAGE_MASK;
+
+       bank = &meminfo.bank[meminfo.nr_banks++];
+
+       bank->start = PAGE_ALIGN(start);
+       bank->size  = size & PAGE_MASK;
+       bank->node  = PHYS_TO_NID(start);
+}
+
 /*
  * Pick out the memory size.  We look for mem=size@start,
  * where start and size are "size[KkMm]"
@@ -366,10 +474,7 @@ static void __init early_mem(char **p)
        if (**p == '@')
                start = memparse(*p + 1, p);
 
-       meminfo.bank[meminfo.nr_banks].start = start;
-       meminfo.bank[meminfo.nr_banks].size  = size;
-       meminfo.bank[meminfo.nr_banks].node  = PHYS_TO_NID(start);
-       meminfo.nr_banks += 1;
+       arm_add_memory(start, size);
 }
 __early_param("mem=", early_mem);
 
@@ -433,10 +538,10 @@ request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
        struct resource *res;
        int i;
 
-       kernel_code.start  = __virt_to_phys(init_mm.start_code);
-       kernel_code.end    = __virt_to_phys(init_mm.end_code - 1);
-       kernel_data.start  = __virt_to_phys(init_mm.end_code);
-       kernel_data.end    = __virt_to_phys(init_mm.brk - 1);
+       kernel_code.start   = virt_to_phys(&_text);
+       kernel_code.end     = virt_to_phys(&_etext - 1);
+       kernel_data.start   = virt_to_phys(&__data_start);
+       kernel_data.end     = virt_to_phys(&_end - 1);
 
        for (i = 0; i < mi->nr_banks; i++) {
                unsigned long virt_start, virt_end;
@@ -511,11 +616,7 @@ static int __init parse_tag_mem32(const struct tag *tag)
                        tag->u.mem.start, tag->u.mem.size / 1024);
                return -EINVAL;
        }
-       meminfo.bank[meminfo.nr_banks].start = tag->u.mem.start;
-       meminfo.bank[meminfo.nr_banks].size  = tag->u.mem.size;
-       meminfo.bank[meminfo.nr_banks].node  = PHYS_TO_NID(tag->u.mem.start);
-       meminfo.nr_banks += 1;
-
+       arm_add_memory(tag->u.mem.start, tag->u.mem.size);
        return 0;
 }
 
@@ -676,8 +777,8 @@ void __init setup_arch(char **cmdline_p)
        if (mdesc->soft_reboot)
                reboot_setup("s");
 
-       if (mdesc->param_offset)
-               tags = phys_to_virt(mdesc->param_offset);
+       if (mdesc->boot_params)
+               tags = phys_to_virt(mdesc->boot_params);
 
        /*
         * If we have the old style parameters, convert them to
@@ -705,14 +806,20 @@ void __init setup_arch(char **cmdline_p)
        memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
        saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
        parse_cmdline(cmdline_p, from);
-       bootmem_init(&meminfo);
        paging_init(&meminfo, mdesc);
        request_standard_resources(&meminfo, mdesc);
 
+#ifdef CONFIG_SMP
+       smp_init_cpus();
+#endif
+
+       cpu_init();
+
        /*
         * Set up various architecture-specific pointers
         */
        init_arch_irq = mdesc->init_irq;
+       system_timer = mdesc->timer;
        init_machine = mdesc->init_machine;
 
 #ifdef CONFIG_VT
@@ -724,11 +831,15 @@ void __init setup_arch(char **cmdline_p)
 #endif
 }
 
-static struct cpu cpu[1];
 
 static int __init topology_init(void)
 {
-       return register_cpu(cpu, 0, NULL);
+       int cpu;
+
+       for_each_possible_cpu(cpu)
+               register_cpu(&per_cpu(cpu_data, cpu).cpu, cpu);
+
+       return 0;
 }
 
 subsys_initcall(topology_init);
@@ -742,6 +853,9 @@ static const char *hwcap_str[] = {
        "fpa",
        "vfp",
        "edsp",
+       "java",
+       "iwmmxt",
+       "crunch",
        NULL
 };
 
@@ -768,9 +882,23 @@ static int c_show(struct seq_file *m, void *v)
        seq_printf(m, "Processor\t: %s rev %d (%s)\n",
                   cpu_name, (int)processor_id & 15, elf_platform);
 
+#if defined(CONFIG_SMP)
+       for_each_online_cpu(i) {
+               /*
+                * glibc reads /proc/cpuinfo to determine the number of
+                * online processors, looking for lines beginning with
+                * "processor".  Give glibc what it expects.
+                */
+               seq_printf(m, "processor\t: %d\n", i);
+               seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
+                          per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
+                          (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
+       }
+#else /* CONFIG_SMP */
        seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
                   loops_per_jiffy / (500000/HZ),
                   (loops_per_jiffy / (5000/HZ)) % 100);
+#endif
 
        /* dump out the processor features */
        seq_puts(m, "Features\t: ");
@@ -782,11 +910,11 @@ static int c_show(struct seq_file *m, void *v)
        seq_printf(m, "\nCPU implementer\t: 0x%02x\n", processor_id >> 24);
        seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]);
 
-       if ((processor_id & 0x0000f000) == 0x00000000) {
+       if ((processor_id & 0x0008f000) == 0x00000000) {
                /* pre-ARM7 */
                seq_printf(m, "CPU part\t\t: %07x\n", processor_id >> 4);
        } else {
-               if ((processor_id & 0x0000f000) == 0x00007000) {
+               if ((processor_id & 0x0008f000) == 0x00007000) {
                        /* ARM7 */
                        seq_printf(m, "CPU variant\t: 0x%02x\n",
                                   (processor_id >> 16) & 127);