X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Farm%2Fkernel%2Fsetup.c;h=bbab134cd82d3fa547d72d5d2514591da9f52d92;hb=refs%2Fheads%2Fvserver;hp=d58a35e506ef3889f37d708e54087b4cf2588414;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index d58a35e50..bbab134cd 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -7,7 +7,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include +#include #include #include #include @@ -17,14 +17,15 @@ #include #include #include -#include +#include #include #include #include +#include +#include +#include #include -#include -#include #include #include #include @@ -33,6 +34,9 @@ #include #include +#include + +#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);