11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/arch/arm/kernel/setup.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 1995-2001 Russell King 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 71da177e4SLinus Torvalds * it under the terms of the GNU General Public License version 2 as 81da177e4SLinus Torvalds * published by the Free Software Foundation. 91da177e4SLinus Torvalds */ 101da177e4SLinus Torvalds #include <linux/module.h> 111da177e4SLinus Torvalds #include <linux/kernel.h> 121da177e4SLinus Torvalds #include <linux/stddef.h> 131da177e4SLinus Torvalds #include <linux/ioport.h> 141da177e4SLinus Torvalds #include <linux/delay.h> 151da177e4SLinus Torvalds #include <linux/utsname.h> 161da177e4SLinus Torvalds #include <linux/initrd.h> 171da177e4SLinus Torvalds #include <linux/console.h> 181da177e4SLinus Torvalds #include <linux/bootmem.h> 191da177e4SLinus Torvalds #include <linux/seq_file.h> 20894673eeSJon Smirl #include <linux/screen_info.h> 211da177e4SLinus Torvalds #include <linux/init.h> 223c57fb43SMika Westerberg #include <linux/kexec.h> 23cea0bb1bSMika Westerberg #include <linux/crash_dump.h> 241da177e4SLinus Torvalds #include <linux/root_dev.h> 251da177e4SLinus Torvalds #include <linux/cpu.h> 261da177e4SLinus Torvalds #include <linux/interrupt.h> 277bbb7940SRussell King #include <linux/smp.h> 284e950f6fSAlexey Dobriyan #include <linux/fs.h> 29e119bfffSRussell King #include <linux/proc_fs.h> 302778f620SRussell King #include <linux/memblock.h> 311da177e4SLinus Torvalds 32b86040a5SCatalin Marinas #include <asm/unified.h> 331da177e4SLinus Torvalds #include <asm/cpu.h> 340ba8b9b2SRussell King #include <asm/cputype.h> 351da177e4SLinus Torvalds #include <asm/elf.h> 361da177e4SLinus Torvalds #include <asm/procinfo.h> 3737efe642SRussell King #include <asm/sections.h> 381da177e4SLinus Torvalds #include <asm/setup.h> 391da177e4SLinus Torvalds #include <asm/mach-types.h> 401da177e4SLinus Torvalds #include <asm/cacheflush.h> 4146097c7dSRussell King #include <asm/cachetype.h> 421da177e4SLinus Torvalds #include <asm/tlbflush.h> 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds #include <asm/mach/arch.h> 451da177e4SLinus Torvalds #include <asm/mach/irq.h> 461da177e4SLinus Torvalds #include <asm/mach/time.h> 475cbad0ebSJason Wessel #include <asm/traps.h> 48bff595c1SCatalin Marinas #include <asm/unwind.h> 491da177e4SLinus Torvalds 5073a65b3fSUwe Kleine-König #if defined(CONFIG_DEPRECATED_PARAM_STRUCT) 510fc1c832SBen Dooks #include "compat.h" 5273a65b3fSUwe Kleine-König #endif 534cd9d6f7SRichard Purdie #include "atags.h" 54bc581770SLinus Walleij #include "tcm.h" 550fc1c832SBen Dooks 561da177e4SLinus Torvalds #ifndef MEM_SIZE 571da177e4SLinus Torvalds #define MEM_SIZE (16*1024*1024) 581da177e4SLinus Torvalds #endif 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE) 611da177e4SLinus Torvalds char fpe_type[8]; 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds static int __init fpe_setup(char *line) 641da177e4SLinus Torvalds { 651da177e4SLinus Torvalds memcpy(fpe_type, line, 8); 661da177e4SLinus Torvalds return 1; 671da177e4SLinus Torvalds } 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds __setup("fpe=", fpe_setup); 701da177e4SLinus Torvalds #endif 711da177e4SLinus Torvalds 724b5f32ceSNicolas Pitre extern void paging_init(struct machine_desc *desc); 731da177e4SLinus Torvalds extern void reboot_setup(char *str); 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds unsigned int processor_id; 76c18f6581SKrzysztof Halasa EXPORT_SYMBOL(processor_id); 771da177e4SLinus Torvalds unsigned int __machine_arch_type; 781da177e4SLinus Torvalds EXPORT_SYMBOL(__machine_arch_type); 79c0e95878SRussell King unsigned int cacheid; 80c0e95878SRussell King EXPORT_SYMBOL(cacheid); 811da177e4SLinus Torvalds 829d20fdd5SBill Gatliff unsigned int __atags_pointer __initdata; 839d20fdd5SBill Gatliff 841da177e4SLinus Torvalds unsigned int system_rev; 851da177e4SLinus Torvalds EXPORT_SYMBOL(system_rev); 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds unsigned int system_serial_low; 881da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_low); 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds unsigned int system_serial_high; 911da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_high); 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds unsigned int elf_hwcap; 941da177e4SLinus Torvalds EXPORT_SYMBOL(elf_hwcap); 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds #ifdef MULTI_CPU 981da177e4SLinus Torvalds struct processor processor; 991da177e4SLinus Torvalds #endif 1001da177e4SLinus Torvalds #ifdef MULTI_TLB 1011da177e4SLinus Torvalds struct cpu_tlb_fns cpu_tlb; 1021da177e4SLinus Torvalds #endif 1031da177e4SLinus Torvalds #ifdef MULTI_USER 1041da177e4SLinus Torvalds struct cpu_user_fns cpu_user; 1051da177e4SLinus Torvalds #endif 1061da177e4SLinus Torvalds #ifdef MULTI_CACHE 1071da177e4SLinus Torvalds struct cpu_cache_fns cpu_cache; 1081da177e4SLinus Torvalds #endif 109953233dcSCatalin Marinas #ifdef CONFIG_OUTER_CACHE 110953233dcSCatalin Marinas struct outer_cache_fns outer_cache; 1116c09f09dSSantosh Shilimkar EXPORT_SYMBOL(outer_cache); 112953233dcSCatalin Marinas #endif 1131da177e4SLinus Torvalds 114ccea7a19SRussell King struct stack { 115ccea7a19SRussell King u32 irq[3]; 116ccea7a19SRussell King u32 abt[3]; 117ccea7a19SRussell King u32 und[3]; 118ccea7a19SRussell King } ____cacheline_aligned; 119ccea7a19SRussell King 120ccea7a19SRussell King static struct stack stacks[NR_CPUS]; 121ccea7a19SRussell King 1221da177e4SLinus Torvalds char elf_platform[ELF_PLATFORM_SIZE]; 1231da177e4SLinus Torvalds EXPORT_SYMBOL(elf_platform); 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds static const char *cpu_name; 1261da177e4SLinus Torvalds static const char *machine_name; 12748ab7e09SJeremy Kerr static char __initdata cmd_line[COMMAND_LINE_SIZE]; 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; 1301da177e4SLinus Torvalds static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; 1311da177e4SLinus Torvalds #define ENDIANNESS ((char)endian_test.l) 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data); 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds /* 1361da177e4SLinus Torvalds * Standard memory resources 1371da177e4SLinus Torvalds */ 1381da177e4SLinus Torvalds static struct resource mem_res[] = { 139740e518eSGreg Kroah-Hartman { 140740e518eSGreg Kroah-Hartman .name = "Video RAM", 141740e518eSGreg Kroah-Hartman .start = 0, 142740e518eSGreg Kroah-Hartman .end = 0, 143740e518eSGreg Kroah-Hartman .flags = IORESOURCE_MEM 144740e518eSGreg Kroah-Hartman }, 145740e518eSGreg Kroah-Hartman { 146740e518eSGreg Kroah-Hartman .name = "Kernel text", 147740e518eSGreg Kroah-Hartman .start = 0, 148740e518eSGreg Kroah-Hartman .end = 0, 149740e518eSGreg Kroah-Hartman .flags = IORESOURCE_MEM 150740e518eSGreg Kroah-Hartman }, 151740e518eSGreg Kroah-Hartman { 152740e518eSGreg Kroah-Hartman .name = "Kernel data", 153740e518eSGreg Kroah-Hartman .start = 0, 154740e518eSGreg Kroah-Hartman .end = 0, 155740e518eSGreg Kroah-Hartman .flags = IORESOURCE_MEM 156740e518eSGreg Kroah-Hartman } 1571da177e4SLinus Torvalds }; 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds #define video_ram mem_res[0] 1601da177e4SLinus Torvalds #define kernel_code mem_res[1] 1611da177e4SLinus Torvalds #define kernel_data mem_res[2] 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds static struct resource io_res[] = { 164740e518eSGreg Kroah-Hartman { 165740e518eSGreg Kroah-Hartman .name = "reserved", 166740e518eSGreg Kroah-Hartman .start = 0x3bc, 167740e518eSGreg Kroah-Hartman .end = 0x3be, 168740e518eSGreg Kroah-Hartman .flags = IORESOURCE_IO | IORESOURCE_BUSY 169740e518eSGreg Kroah-Hartman }, 170740e518eSGreg Kroah-Hartman { 171740e518eSGreg Kroah-Hartman .name = "reserved", 172740e518eSGreg Kroah-Hartman .start = 0x378, 173740e518eSGreg Kroah-Hartman .end = 0x37f, 174740e518eSGreg Kroah-Hartman .flags = IORESOURCE_IO | IORESOURCE_BUSY 175740e518eSGreg Kroah-Hartman }, 176740e518eSGreg Kroah-Hartman { 177740e518eSGreg Kroah-Hartman .name = "reserved", 178740e518eSGreg Kroah-Hartman .start = 0x278, 179740e518eSGreg Kroah-Hartman .end = 0x27f, 180740e518eSGreg Kroah-Hartman .flags = IORESOURCE_IO | IORESOURCE_BUSY 181740e518eSGreg Kroah-Hartman } 1821da177e4SLinus Torvalds }; 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds #define lp0 io_res[0] 1851da177e4SLinus Torvalds #define lp1 io_res[1] 1861da177e4SLinus Torvalds #define lp2 io_res[2] 1871da177e4SLinus Torvalds 1881da177e4SLinus Torvalds static const char *proc_arch[] = { 1891da177e4SLinus Torvalds "undefined/unknown", 1901da177e4SLinus Torvalds "3", 1911da177e4SLinus Torvalds "4", 1921da177e4SLinus Torvalds "4T", 1931da177e4SLinus Torvalds "5", 1941da177e4SLinus Torvalds "5T", 1951da177e4SLinus Torvalds "5TE", 1961da177e4SLinus Torvalds "5TEJ", 1971da177e4SLinus Torvalds "6TEJ", 1986b090a25SCatalin Marinas "7", 1991da177e4SLinus Torvalds "?(11)", 2001da177e4SLinus Torvalds "?(12)", 2011da177e4SLinus Torvalds "?(13)", 2021da177e4SLinus Torvalds "?(14)", 2031da177e4SLinus Torvalds "?(15)", 2041da177e4SLinus Torvalds "?(16)", 2051da177e4SLinus Torvalds "?(17)", 2061da177e4SLinus Torvalds }; 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds int cpu_architecture(void) 2091da177e4SLinus Torvalds { 2101da177e4SLinus Torvalds int cpu_arch; 2111da177e4SLinus Torvalds 2120ba8b9b2SRussell King if ((read_cpuid_id() & 0x0008f000) == 0) { 2131da177e4SLinus Torvalds cpu_arch = CPU_ARCH_UNKNOWN; 2140ba8b9b2SRussell King } else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) { 2150ba8b9b2SRussell King cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3; 2160ba8b9b2SRussell King } else if ((read_cpuid_id() & 0x00080000) == 0x00000000) { 2170ba8b9b2SRussell King cpu_arch = (read_cpuid_id() >> 16) & 7; 2181da177e4SLinus Torvalds if (cpu_arch) 2191da177e4SLinus Torvalds cpu_arch += CPU_ARCH_ARMv3; 2200ba8b9b2SRussell King } else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) { 221180005c4SCatalin Marinas unsigned int mmfr0; 222180005c4SCatalin Marinas 223180005c4SCatalin Marinas /* Revised CPUID format. Read the Memory Model Feature 224180005c4SCatalin Marinas * Register 0 and check for VMSAv7 or PMSAv7 */ 225180005c4SCatalin Marinas asm("mrc p15, 0, %0, c0, c1, 4" 226180005c4SCatalin Marinas : "=r" (mmfr0)); 227180005c4SCatalin Marinas if ((mmfr0 & 0x0000000f) == 0x00000003 || 228180005c4SCatalin Marinas (mmfr0 & 0x000000f0) == 0x00000030) 229180005c4SCatalin Marinas cpu_arch = CPU_ARCH_ARMv7; 230180005c4SCatalin Marinas else if ((mmfr0 & 0x0000000f) == 0x00000002 || 231180005c4SCatalin Marinas (mmfr0 & 0x000000f0) == 0x00000020) 232180005c4SCatalin Marinas cpu_arch = CPU_ARCH_ARMv6; 233180005c4SCatalin Marinas else 234180005c4SCatalin Marinas cpu_arch = CPU_ARCH_UNKNOWN; 235180005c4SCatalin Marinas } else 236180005c4SCatalin Marinas cpu_arch = CPU_ARCH_UNKNOWN; 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds return cpu_arch; 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds 2418925ec4cSWill Deacon static int cpu_has_aliasing_icache(unsigned int arch) 2428925ec4cSWill Deacon { 2438925ec4cSWill Deacon int aliasing_icache; 2448925ec4cSWill Deacon unsigned int id_reg, num_sets, line_size; 2458925ec4cSWill Deacon 2468925ec4cSWill Deacon /* arch specifies the register format */ 2478925ec4cSWill Deacon switch (arch) { 2488925ec4cSWill Deacon case CPU_ARCH_ARMv7: 2498925ec4cSWill Deacon asm("mcr p15, 2, %1, c0, c0, 0 @ set CSSELR\n" 2508925ec4cSWill Deacon "isb\n" 2518925ec4cSWill Deacon "mrc p15, 1, %0, c0, c0, 0 @ read CCSIDR" 2528925ec4cSWill Deacon : "=r" (id_reg) 2538925ec4cSWill Deacon : "r" (1)); 2548925ec4cSWill Deacon line_size = 4 << ((id_reg & 0x7) + 2); 2558925ec4cSWill Deacon num_sets = ((id_reg >> 13) & 0x7fff) + 1; 2568925ec4cSWill Deacon aliasing_icache = (line_size * num_sets) > PAGE_SIZE; 2578925ec4cSWill Deacon break; 2588925ec4cSWill Deacon case CPU_ARCH_ARMv6: 2598925ec4cSWill Deacon aliasing_icache = read_cpuid_cachetype() & (1 << 11); 2608925ec4cSWill Deacon break; 2618925ec4cSWill Deacon default: 2628925ec4cSWill Deacon /* I-cache aliases will be handled by D-cache aliasing code */ 2638925ec4cSWill Deacon aliasing_icache = 0; 2648925ec4cSWill Deacon } 2658925ec4cSWill Deacon 2668925ec4cSWill Deacon return aliasing_icache; 2678925ec4cSWill Deacon } 2688925ec4cSWill Deacon 269c0e95878SRussell King static void __init cacheid_init(void) 270c0e95878SRussell King { 271c0e95878SRussell King unsigned int cachetype = read_cpuid_cachetype(); 272c0e95878SRussell King unsigned int arch = cpu_architecture(); 273c0e95878SRussell King 274b57ee99fSCatalin Marinas if (arch >= CPU_ARCH_ARMv6) { 275b57ee99fSCatalin Marinas if ((cachetype & (7 << 29)) == 4 << 29) { 276b57ee99fSCatalin Marinas /* ARMv7 register format */ 277c0e95878SRussell King cacheid = CACHEID_VIPT_NONALIASING; 278c0e95878SRussell King if ((cachetype & (3 << 14)) == 1 << 14) 279c0e95878SRussell King cacheid |= CACHEID_ASID_TAGGED; 2808925ec4cSWill Deacon else if (cpu_has_aliasing_icache(CPU_ARCH_ARMv7)) 2818925ec4cSWill Deacon cacheid |= CACHEID_VIPT_I_ALIASING; 2828925ec4cSWill Deacon } else if (cachetype & (1 << 23)) { 283c0e95878SRussell King cacheid = CACHEID_VIPT_ALIASING; 2848925ec4cSWill Deacon } else { 285c0e95878SRussell King cacheid = CACHEID_VIPT_NONALIASING; 2868925ec4cSWill Deacon if (cpu_has_aliasing_icache(CPU_ARCH_ARMv6)) 2878925ec4cSWill Deacon cacheid |= CACHEID_VIPT_I_ALIASING; 2888925ec4cSWill Deacon } 289c0e95878SRussell King } else { 290c0e95878SRussell King cacheid = CACHEID_VIVT; 291c0e95878SRussell King } 2922b4ae1f1SRussell King 2932b4ae1f1SRussell King printk("CPU: %s data cache, %s instruction cache\n", 2942b4ae1f1SRussell King cache_is_vivt() ? "VIVT" : 2952b4ae1f1SRussell King cache_is_vipt_aliasing() ? "VIPT aliasing" : 2962b4ae1f1SRussell King cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown", 2972b4ae1f1SRussell King cache_is_vivt() ? "VIVT" : 2982b4ae1f1SRussell King icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" : 2998925ec4cSWill Deacon icache_is_vipt_aliasing() ? "VIPT aliasing" : 3002b4ae1f1SRussell King cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown"); 301c0e95878SRussell King } 302c0e95878SRussell King 3031da177e4SLinus Torvalds /* 3041da177e4SLinus Torvalds * These functions re-use the assembly code in head.S, which 3051da177e4SLinus Torvalds * already provide the required functionality. 3061da177e4SLinus Torvalds */ 3070f44ba1dSRussell King extern struct proc_info_list *lookup_processor_type(unsigned int); 3081da177e4SLinus Torvalds extern struct machine_desc *lookup_machine_type(unsigned int); 3091da177e4SLinus Torvalds 310f159f4edSTony Lindgren static void __init feat_v6_fixup(void) 311f159f4edSTony Lindgren { 312f159f4edSTony Lindgren int id = read_cpuid_id(); 313f159f4edSTony Lindgren 314f159f4edSTony Lindgren if ((id & 0xff0f0000) != 0x41070000) 315f159f4edSTony Lindgren return; 316f159f4edSTony Lindgren 317f159f4edSTony Lindgren /* 318f159f4edSTony Lindgren * HWCAP_TLS is available only on 1136 r1p0 and later, 319f159f4edSTony Lindgren * see also kuser_get_tls_init. 320f159f4edSTony Lindgren */ 321f159f4edSTony Lindgren if ((((id >> 4) & 0xfff) == 0xb36) && (((id >> 20) & 3) == 0)) 322f159f4edSTony Lindgren elf_hwcap &= ~HWCAP_TLS; 323f159f4edSTony Lindgren } 324f159f4edSTony Lindgren 3251da177e4SLinus Torvalds static void __init setup_processor(void) 3261da177e4SLinus Torvalds { 3271da177e4SLinus Torvalds struct proc_info_list *list; 3281da177e4SLinus Torvalds 3291da177e4SLinus Torvalds /* 3301da177e4SLinus Torvalds * locate processor in the list of supported processor 3311da177e4SLinus Torvalds * types. The linker builds this table for us from the 3321da177e4SLinus Torvalds * entries in arch/arm/mm/proc-*.S 3331da177e4SLinus Torvalds */ 3340ba8b9b2SRussell King list = lookup_processor_type(read_cpuid_id()); 3351da177e4SLinus Torvalds if (!list) { 3361da177e4SLinus Torvalds printk("CPU configuration botched (ID %08x), unable " 3370ba8b9b2SRussell King "to continue.\n", read_cpuid_id()); 3381da177e4SLinus Torvalds while (1); 3391da177e4SLinus Torvalds } 3401da177e4SLinus Torvalds 3411da177e4SLinus Torvalds cpu_name = list->cpu_name; 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds #ifdef MULTI_CPU 3441da177e4SLinus Torvalds processor = *list->proc; 3451da177e4SLinus Torvalds #endif 3461da177e4SLinus Torvalds #ifdef MULTI_TLB 3471da177e4SLinus Torvalds cpu_tlb = *list->tlb; 3481da177e4SLinus Torvalds #endif 3491da177e4SLinus Torvalds #ifdef MULTI_USER 3501da177e4SLinus Torvalds cpu_user = *list->user; 3511da177e4SLinus Torvalds #endif 3521da177e4SLinus Torvalds #ifdef MULTI_CACHE 3531da177e4SLinus Torvalds cpu_cache = *list->cache; 3541da177e4SLinus Torvalds #endif 3551da177e4SLinus Torvalds 3564e19025bSRussell King printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n", 3570ba8b9b2SRussell King cpu_name, read_cpuid_id(), read_cpuid_id() & 15, 358264edb35SRussell King proc_arch[cpu_architecture()], cr_alignment); 3591da177e4SLinus Torvalds 36096b644bdSSerge E. Hallyn sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS); 3611da177e4SLinus Torvalds sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); 3621da177e4SLinus Torvalds elf_hwcap = list->elf_hwcap; 363adeff422SCatalin Marinas #ifndef CONFIG_ARM_THUMB 364adeff422SCatalin Marinas elf_hwcap &= ~HWCAP_THUMB; 365adeff422SCatalin Marinas #endif 3661da177e4SLinus Torvalds 367f159f4edSTony Lindgren feat_v6_fixup(); 368f159f4edSTony Lindgren 369c0e95878SRussell King cacheid_init(); 3701da177e4SLinus Torvalds cpu_proc_init(); 3711da177e4SLinus Torvalds } 3721da177e4SLinus Torvalds 373ccea7a19SRussell King /* 374ccea7a19SRussell King * cpu_init - initialise one CPU. 375ccea7a19SRussell King * 37690f1e084SRussell King * cpu_init sets up the per-CPU stacks. 377ccea7a19SRussell King */ 37836c5ed23SRussell King void cpu_init(void) 379ccea7a19SRussell King { 380ccea7a19SRussell King unsigned int cpu = smp_processor_id(); 381ccea7a19SRussell King struct stack *stk = &stacks[cpu]; 382ccea7a19SRussell King 383ccea7a19SRussell King if (cpu >= NR_CPUS) { 384ccea7a19SRussell King printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu); 385ccea7a19SRussell King BUG(); 386ccea7a19SRussell King } 387ccea7a19SRussell King 388ccea7a19SRussell King /* 389b86040a5SCatalin Marinas * Define the placement constraint for the inline asm directive below. 390b86040a5SCatalin Marinas * In Thumb-2, msr with an immediate value is not allowed. 391b86040a5SCatalin Marinas */ 392b86040a5SCatalin Marinas #ifdef CONFIG_THUMB2_KERNEL 393b86040a5SCatalin Marinas #define PLC "r" 394b86040a5SCatalin Marinas #else 395b86040a5SCatalin Marinas #define PLC "I" 396b86040a5SCatalin Marinas #endif 397b86040a5SCatalin Marinas 398b86040a5SCatalin Marinas /* 399ccea7a19SRussell King * setup stacks for re-entrant exception handlers 400ccea7a19SRussell King */ 401ccea7a19SRussell King __asm__ ( 402ccea7a19SRussell King "msr cpsr_c, %1\n\t" 403b86040a5SCatalin Marinas "add r14, %0, %2\n\t" 404b86040a5SCatalin Marinas "mov sp, r14\n\t" 405ccea7a19SRussell King "msr cpsr_c, %3\n\t" 406b86040a5SCatalin Marinas "add r14, %0, %4\n\t" 407b86040a5SCatalin Marinas "mov sp, r14\n\t" 408ccea7a19SRussell King "msr cpsr_c, %5\n\t" 409b86040a5SCatalin Marinas "add r14, %0, %6\n\t" 410b86040a5SCatalin Marinas "mov sp, r14\n\t" 411ccea7a19SRussell King "msr cpsr_c, %7" 412ccea7a19SRussell King : 413ccea7a19SRussell King : "r" (stk), 414b86040a5SCatalin Marinas PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE), 415ccea7a19SRussell King "I" (offsetof(struct stack, irq[0])), 416b86040a5SCatalin Marinas PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE), 417ccea7a19SRussell King "I" (offsetof(struct stack, abt[0])), 418b86040a5SCatalin Marinas PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE), 419ccea7a19SRussell King "I" (offsetof(struct stack, und[0])), 420b86040a5SCatalin Marinas PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE) 421aaaa3f9eSCatalin Marinas : "r14"); 422ccea7a19SRussell King } 423ccea7a19SRussell King 4241da177e4SLinus Torvalds static struct machine_desc * __init setup_machine(unsigned int nr) 4251da177e4SLinus Torvalds { 4261da177e4SLinus Torvalds struct machine_desc *list; 4271da177e4SLinus Torvalds 4281da177e4SLinus Torvalds /* 4291da177e4SLinus Torvalds * locate machine in the list of supported machines. 4301da177e4SLinus Torvalds */ 4311da177e4SLinus Torvalds list = lookup_machine_type(nr); 4321da177e4SLinus Torvalds if (!list) { 4331da177e4SLinus Torvalds printk("Machine configuration botched (nr %d), unable " 4341da177e4SLinus Torvalds "to continue.\n", nr); 4351da177e4SLinus Torvalds while (1); 4361da177e4SLinus Torvalds } 4371da177e4SLinus Torvalds 4381da177e4SLinus Torvalds printk("Machine: %s\n", list->name); 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds return list; 4411da177e4SLinus Torvalds } 4421da177e4SLinus Torvalds 4434b5f32ceSNicolas Pitre static int __init arm_add_memory(unsigned long start, unsigned long size) 4443a669411SRussell King { 4454b5f32ceSNicolas Pitre struct membank *bank = &meminfo.bank[meminfo.nr_banks]; 4464b5f32ceSNicolas Pitre 4474b5f32ceSNicolas Pitre if (meminfo.nr_banks >= NR_BANKS) { 4484b5f32ceSNicolas Pitre printk(KERN_CRIT "NR_BANKS too low, " 4494b5f32ceSNicolas Pitre "ignoring memory at %#lx\n", start); 4504b5f32ceSNicolas Pitre return -EINVAL; 4514b5f32ceSNicolas Pitre } 45205f96ef1SRussell King 4533a669411SRussell King /* 4543a669411SRussell King * Ensure that start/size are aligned to a page boundary. 4553a669411SRussell King * Size is appropriately rounded down, start is rounded up. 4563a669411SRussell King */ 4573a669411SRussell King size -= start & ~PAGE_MASK; 45805f96ef1SRussell King bank->start = PAGE_ALIGN(start); 45905f96ef1SRussell King bank->size = size & PAGE_MASK; 4604b5f32ceSNicolas Pitre 4614b5f32ceSNicolas Pitre /* 4624b5f32ceSNicolas Pitre * Check whether this memory region has non-zero size or 4634b5f32ceSNicolas Pitre * invalid node number. 4644b5f32ceSNicolas Pitre */ 465be370302SRussell King if (bank->size == 0) 4664b5f32ceSNicolas Pitre return -EINVAL; 4674b5f32ceSNicolas Pitre 4684b5f32ceSNicolas Pitre meminfo.nr_banks++; 4694b5f32ceSNicolas Pitre return 0; 4703a669411SRussell King } 4713a669411SRussell King 4721da177e4SLinus Torvalds /* 4731da177e4SLinus Torvalds * Pick out the memory size. We look for mem=size@start, 4741da177e4SLinus Torvalds * where start and size are "size[KkMm]" 4751da177e4SLinus Torvalds */ 4762b0d8c25SJeremy Kerr static int __init early_mem(char *p) 4771da177e4SLinus Torvalds { 4781da177e4SLinus Torvalds static int usermem __initdata = 0; 4791da177e4SLinus Torvalds unsigned long size, start; 4802b0d8c25SJeremy Kerr char *endp; 4811da177e4SLinus Torvalds 4821da177e4SLinus Torvalds /* 4831da177e4SLinus Torvalds * If the user specifies memory size, we 4841da177e4SLinus Torvalds * blow away any automatically generated 4851da177e4SLinus Torvalds * size. 4861da177e4SLinus Torvalds */ 4871da177e4SLinus Torvalds if (usermem == 0) { 4881da177e4SLinus Torvalds usermem = 1; 4891da177e4SLinus Torvalds meminfo.nr_banks = 0; 4901da177e4SLinus Torvalds } 4911da177e4SLinus Torvalds 4921da177e4SLinus Torvalds start = PHYS_OFFSET; 4932b0d8c25SJeremy Kerr size = memparse(p, &endp); 4942b0d8c25SJeremy Kerr if (*endp == '@') 4952b0d8c25SJeremy Kerr start = memparse(endp + 1, NULL); 4961da177e4SLinus Torvalds 4971c97b73eSAndrew Morton arm_add_memory(start, size); 4981da177e4SLinus Torvalds 4992b0d8c25SJeremy Kerr return 0; 5001da177e4SLinus Torvalds } 5012b0d8c25SJeremy Kerr early_param("mem", early_mem); 5021da177e4SLinus Torvalds 5031da177e4SLinus Torvalds static void __init 5041da177e4SLinus Torvalds setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz) 5051da177e4SLinus Torvalds { 5061da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_RAM 5071da177e4SLinus Torvalds extern int rd_size, rd_image_start, rd_prompt, rd_doload; 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds rd_image_start = image_start; 5101da177e4SLinus Torvalds rd_prompt = prompt; 5111da177e4SLinus Torvalds rd_doload = doload; 5121da177e4SLinus Torvalds 5131da177e4SLinus Torvalds if (rd_sz) 5141da177e4SLinus Torvalds rd_size = rd_sz; 5151da177e4SLinus Torvalds #endif 5161da177e4SLinus Torvalds } 5171da177e4SLinus Torvalds 5181da177e4SLinus Torvalds static void __init 5191da177e4SLinus Torvalds request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc) 5201da177e4SLinus Torvalds { 5211da177e4SLinus Torvalds struct resource *res; 5221da177e4SLinus Torvalds int i; 5231da177e4SLinus Torvalds 52437efe642SRussell King kernel_code.start = virt_to_phys(_text); 52537efe642SRussell King kernel_code.end = virt_to_phys(_etext - 1); 52637efe642SRussell King kernel_data.start = virt_to_phys(_data); 52737efe642SRussell King kernel_data.end = virt_to_phys(_end - 1); 5281da177e4SLinus Torvalds 5291da177e4SLinus Torvalds for (i = 0; i < mi->nr_banks; i++) { 5301da177e4SLinus Torvalds if (mi->bank[i].size == 0) 5311da177e4SLinus Torvalds continue; 5321da177e4SLinus Torvalds 5331da177e4SLinus Torvalds res = alloc_bootmem_low(sizeof(*res)); 5341da177e4SLinus Torvalds res->name = "System RAM"; 5353319f5e5SNicolas Pitre res->start = mi->bank[i].start; 5363319f5e5SNicolas Pitre res->end = mi->bank[i].start + mi->bank[i].size - 1; 5371da177e4SLinus Torvalds res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; 5381da177e4SLinus Torvalds 5391da177e4SLinus Torvalds request_resource(&iomem_resource, res); 5401da177e4SLinus Torvalds 5411da177e4SLinus Torvalds if (kernel_code.start >= res->start && 5421da177e4SLinus Torvalds kernel_code.end <= res->end) 5431da177e4SLinus Torvalds request_resource(res, &kernel_code); 5441da177e4SLinus Torvalds if (kernel_data.start >= res->start && 5451da177e4SLinus Torvalds kernel_data.end <= res->end) 5461da177e4SLinus Torvalds request_resource(res, &kernel_data); 5471da177e4SLinus Torvalds } 5481da177e4SLinus Torvalds 5491da177e4SLinus Torvalds if (mdesc->video_start) { 5501da177e4SLinus Torvalds video_ram.start = mdesc->video_start; 5511da177e4SLinus Torvalds video_ram.end = mdesc->video_end; 5521da177e4SLinus Torvalds request_resource(&iomem_resource, &video_ram); 5531da177e4SLinus Torvalds } 5541da177e4SLinus Torvalds 5551da177e4SLinus Torvalds /* 5561da177e4SLinus Torvalds * Some machines don't have the possibility of ever 5571da177e4SLinus Torvalds * possessing lp0, lp1 or lp2 5581da177e4SLinus Torvalds */ 5591da177e4SLinus Torvalds if (mdesc->reserve_lp0) 5601da177e4SLinus Torvalds request_resource(&ioport_resource, &lp0); 5611da177e4SLinus Torvalds if (mdesc->reserve_lp1) 5621da177e4SLinus Torvalds request_resource(&ioport_resource, &lp1); 5631da177e4SLinus Torvalds if (mdesc->reserve_lp2) 5641da177e4SLinus Torvalds request_resource(&ioport_resource, &lp2); 5651da177e4SLinus Torvalds } 5661da177e4SLinus Torvalds 5671da177e4SLinus Torvalds /* 5681da177e4SLinus Torvalds * Tag parsing. 5691da177e4SLinus Torvalds * 5701da177e4SLinus Torvalds * This is the new way of passing data to the kernel at boot time. Rather 5711da177e4SLinus Torvalds * than passing a fixed inflexible structure to the kernel, we pass a list 5721da177e4SLinus Torvalds * of variable-sized tags to the kernel. The first tag must be a ATAG_CORE 5731da177e4SLinus Torvalds * tag for the list to be recognised (to distinguish the tagged list from 5741da177e4SLinus Torvalds * a param_struct). The list is terminated with a zero-length tag (this tag 5751da177e4SLinus Torvalds * is not parsed in any way). 5761da177e4SLinus Torvalds */ 5771da177e4SLinus Torvalds static int __init parse_tag_core(const struct tag *tag) 5781da177e4SLinus Torvalds { 5791da177e4SLinus Torvalds if (tag->hdr.size > 2) { 5801da177e4SLinus Torvalds if ((tag->u.core.flags & 1) == 0) 5811da177e4SLinus Torvalds root_mountflags &= ~MS_RDONLY; 5821da177e4SLinus Torvalds ROOT_DEV = old_decode_dev(tag->u.core.rootdev); 5831da177e4SLinus Torvalds } 5841da177e4SLinus Torvalds return 0; 5851da177e4SLinus Torvalds } 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds __tagtable(ATAG_CORE, parse_tag_core); 5881da177e4SLinus Torvalds 5891da177e4SLinus Torvalds static int __init parse_tag_mem32(const struct tag *tag) 5901da177e4SLinus Torvalds { 5914b5f32ceSNicolas Pitre return arm_add_memory(tag->u.mem.start, tag->u.mem.size); 5921da177e4SLinus Torvalds } 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds __tagtable(ATAG_MEM, parse_tag_mem32); 5951da177e4SLinus Torvalds 5961da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) 5971da177e4SLinus Torvalds struct screen_info screen_info = { 5981da177e4SLinus Torvalds .orig_video_lines = 30, 5991da177e4SLinus Torvalds .orig_video_cols = 80, 6001da177e4SLinus Torvalds .orig_video_mode = 0, 6011da177e4SLinus Torvalds .orig_video_ega_bx = 0, 6021da177e4SLinus Torvalds .orig_video_isVGA = 1, 6031da177e4SLinus Torvalds .orig_video_points = 8 6041da177e4SLinus Torvalds }; 6051da177e4SLinus Torvalds 6061da177e4SLinus Torvalds static int __init parse_tag_videotext(const struct tag *tag) 6071da177e4SLinus Torvalds { 6081da177e4SLinus Torvalds screen_info.orig_x = tag->u.videotext.x; 6091da177e4SLinus Torvalds screen_info.orig_y = tag->u.videotext.y; 6101da177e4SLinus Torvalds screen_info.orig_video_page = tag->u.videotext.video_page; 6111da177e4SLinus Torvalds screen_info.orig_video_mode = tag->u.videotext.video_mode; 6121da177e4SLinus Torvalds screen_info.orig_video_cols = tag->u.videotext.video_cols; 6131da177e4SLinus Torvalds screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx; 6141da177e4SLinus Torvalds screen_info.orig_video_lines = tag->u.videotext.video_lines; 6151da177e4SLinus Torvalds screen_info.orig_video_isVGA = tag->u.videotext.video_isvga; 6161da177e4SLinus Torvalds screen_info.orig_video_points = tag->u.videotext.video_points; 6171da177e4SLinus Torvalds return 0; 6181da177e4SLinus Torvalds } 6191da177e4SLinus Torvalds 6201da177e4SLinus Torvalds __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext); 6211da177e4SLinus Torvalds #endif 6221da177e4SLinus Torvalds 6231da177e4SLinus Torvalds static int __init parse_tag_ramdisk(const struct tag *tag) 6241da177e4SLinus Torvalds { 6251da177e4SLinus Torvalds setup_ramdisk((tag->u.ramdisk.flags & 1) == 0, 6261da177e4SLinus Torvalds (tag->u.ramdisk.flags & 2) == 0, 6271da177e4SLinus Torvalds tag->u.ramdisk.start, tag->u.ramdisk.size); 6281da177e4SLinus Torvalds return 0; 6291da177e4SLinus Torvalds } 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds __tagtable(ATAG_RAMDISK, parse_tag_ramdisk); 6321da177e4SLinus Torvalds 6331da177e4SLinus Torvalds static int __init parse_tag_serialnr(const struct tag *tag) 6341da177e4SLinus Torvalds { 6351da177e4SLinus Torvalds system_serial_low = tag->u.serialnr.low; 6361da177e4SLinus Torvalds system_serial_high = tag->u.serialnr.high; 6371da177e4SLinus Torvalds return 0; 6381da177e4SLinus Torvalds } 6391da177e4SLinus Torvalds 6401da177e4SLinus Torvalds __tagtable(ATAG_SERIAL, parse_tag_serialnr); 6411da177e4SLinus Torvalds 6421da177e4SLinus Torvalds static int __init parse_tag_revision(const struct tag *tag) 6431da177e4SLinus Torvalds { 6441da177e4SLinus Torvalds system_rev = tag->u.revision.rev; 6451da177e4SLinus Torvalds return 0; 6461da177e4SLinus Torvalds } 6471da177e4SLinus Torvalds 6481da177e4SLinus Torvalds __tagtable(ATAG_REVISION, parse_tag_revision); 6491da177e4SLinus Torvalds 65092d2040dSAlexander Holler #ifndef CONFIG_CMDLINE_FORCE 6511da177e4SLinus Torvalds static int __init parse_tag_cmdline(const struct tag *tag) 6521da177e4SLinus Torvalds { 6531da177e4SLinus Torvalds strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE); 6541da177e4SLinus Torvalds return 0; 6551da177e4SLinus Torvalds } 6561da177e4SLinus Torvalds 6571da177e4SLinus Torvalds __tagtable(ATAG_CMDLINE, parse_tag_cmdline); 65892d2040dSAlexander Holler #endif /* CONFIG_CMDLINE_FORCE */ 6591da177e4SLinus Torvalds 6601da177e4SLinus Torvalds /* 6611da177e4SLinus Torvalds * Scan the tag table for this tag, and call its parse function. 6621da177e4SLinus Torvalds * The tag table is built by the linker from all the __tagtable 6631da177e4SLinus Torvalds * declarations. 6641da177e4SLinus Torvalds */ 6651da177e4SLinus Torvalds static int __init parse_tag(const struct tag *tag) 6661da177e4SLinus Torvalds { 6671da177e4SLinus Torvalds extern struct tagtable __tagtable_begin, __tagtable_end; 6681da177e4SLinus Torvalds struct tagtable *t; 6691da177e4SLinus Torvalds 6701da177e4SLinus Torvalds for (t = &__tagtable_begin; t < &__tagtable_end; t++) 6711da177e4SLinus Torvalds if (tag->hdr.tag == t->tag) { 6721da177e4SLinus Torvalds t->parse(tag); 6731da177e4SLinus Torvalds break; 6741da177e4SLinus Torvalds } 6751da177e4SLinus Torvalds 6761da177e4SLinus Torvalds return t < &__tagtable_end; 6771da177e4SLinus Torvalds } 6781da177e4SLinus Torvalds 6791da177e4SLinus Torvalds /* 6801da177e4SLinus Torvalds * Parse all tags in the list, checking both the global and architecture 6811da177e4SLinus Torvalds * specific tag tables. 6821da177e4SLinus Torvalds */ 6831da177e4SLinus Torvalds static void __init parse_tags(const struct tag *t) 6841da177e4SLinus Torvalds { 6851da177e4SLinus Torvalds for (; t->hdr.size; t = tag_next(t)) 6861da177e4SLinus Torvalds if (!parse_tag(t)) 6871da177e4SLinus Torvalds printk(KERN_WARNING 6881da177e4SLinus Torvalds "Ignoring unrecognised tag 0x%08x\n", 6891da177e4SLinus Torvalds t->hdr.tag); 6901da177e4SLinus Torvalds } 6911da177e4SLinus Torvalds 6921da177e4SLinus Torvalds /* 6931da177e4SLinus Torvalds * This holds our defaults. 6941da177e4SLinus Torvalds */ 6951da177e4SLinus Torvalds static struct init_tags { 6961da177e4SLinus Torvalds struct tag_header hdr1; 6971da177e4SLinus Torvalds struct tag_core core; 6981da177e4SLinus Torvalds struct tag_header hdr2; 6991da177e4SLinus Torvalds struct tag_mem32 mem; 7001da177e4SLinus Torvalds struct tag_header hdr3; 7011da177e4SLinus Torvalds } init_tags __initdata = { 7021da177e4SLinus Torvalds { tag_size(tag_core), ATAG_CORE }, 7031da177e4SLinus Torvalds { 1, PAGE_SIZE, 0xff }, 7041da177e4SLinus Torvalds { tag_size(tag_mem32), ATAG_MEM }, 7051da177e4SLinus Torvalds { MEM_SIZE, PHYS_OFFSET }, 7061da177e4SLinus Torvalds { 0, ATAG_NONE } 7071da177e4SLinus Torvalds }; 7081da177e4SLinus Torvalds 7091da177e4SLinus Torvalds static void (*init_machine)(void) __initdata; 7101da177e4SLinus Torvalds 7111da177e4SLinus Torvalds static int __init customize_machine(void) 7121da177e4SLinus Torvalds { 7131da177e4SLinus Torvalds /* customizes platform devices, or adds new ones */ 7141da177e4SLinus Torvalds if (init_machine) 7151da177e4SLinus Torvalds init_machine(); 7161da177e4SLinus Torvalds return 0; 7171da177e4SLinus Torvalds } 7181da177e4SLinus Torvalds arch_initcall(customize_machine); 7191da177e4SLinus Torvalds 7203c57fb43SMika Westerberg #ifdef CONFIG_KEXEC 7213c57fb43SMika Westerberg static inline unsigned long long get_total_mem(void) 7223c57fb43SMika Westerberg { 7233c57fb43SMika Westerberg unsigned long total; 7243c57fb43SMika Westerberg 7253c57fb43SMika Westerberg total = max_low_pfn - min_low_pfn; 7263c57fb43SMika Westerberg return total << PAGE_SHIFT; 7273c57fb43SMika Westerberg } 7283c57fb43SMika Westerberg 7293c57fb43SMika Westerberg /** 7303c57fb43SMika Westerberg * reserve_crashkernel() - reserves memory are for crash kernel 7313c57fb43SMika Westerberg * 7323c57fb43SMika Westerberg * This function reserves memory area given in "crashkernel=" kernel command 7333c57fb43SMika Westerberg * line parameter. The memory reserved is used by a dump capture kernel when 7343c57fb43SMika Westerberg * primary kernel is crashing. 7353c57fb43SMika Westerberg */ 7363c57fb43SMika Westerberg static void __init reserve_crashkernel(void) 7373c57fb43SMika Westerberg { 7383c57fb43SMika Westerberg unsigned long long crash_size, crash_base; 7393c57fb43SMika Westerberg unsigned long long total_mem; 7403c57fb43SMika Westerberg int ret; 7413c57fb43SMika Westerberg 7423c57fb43SMika Westerberg total_mem = get_total_mem(); 7433c57fb43SMika Westerberg ret = parse_crashkernel(boot_command_line, total_mem, 7443c57fb43SMika Westerberg &crash_size, &crash_base); 7453c57fb43SMika Westerberg if (ret) 7463c57fb43SMika Westerberg return; 7473c57fb43SMika Westerberg 7483c57fb43SMika Westerberg ret = reserve_bootmem(crash_base, crash_size, BOOTMEM_EXCLUSIVE); 7493c57fb43SMika Westerberg if (ret < 0) { 7503c57fb43SMika Westerberg printk(KERN_WARNING "crashkernel reservation failed - " 7513c57fb43SMika Westerberg "memory is in use (0x%lx)\n", (unsigned long)crash_base); 7523c57fb43SMika Westerberg return; 7533c57fb43SMika Westerberg } 7543c57fb43SMika Westerberg 7553c57fb43SMika Westerberg printk(KERN_INFO "Reserving %ldMB of memory at %ldMB " 7563c57fb43SMika Westerberg "for crashkernel (System RAM: %ldMB)\n", 7573c57fb43SMika Westerberg (unsigned long)(crash_size >> 20), 7583c57fb43SMika Westerberg (unsigned long)(crash_base >> 20), 7593c57fb43SMika Westerberg (unsigned long)(total_mem >> 20)); 7603c57fb43SMika Westerberg 7613c57fb43SMika Westerberg crashk_res.start = crash_base; 7623c57fb43SMika Westerberg crashk_res.end = crash_base + crash_size - 1; 7633c57fb43SMika Westerberg insert_resource(&iomem_resource, &crashk_res); 7643c57fb43SMika Westerberg } 7653c57fb43SMika Westerberg #else 7663c57fb43SMika Westerberg static inline void reserve_crashkernel(void) {} 7673c57fb43SMika Westerberg #endif /* CONFIG_KEXEC */ 7683c57fb43SMika Westerberg 769cea0bb1bSMika Westerberg /* 770cea0bb1bSMika Westerberg * Note: elfcorehdr_addr is not just limited to vmcore. It is also used by 771cea0bb1bSMika Westerberg * is_kdump_kernel() to determine if we are booting after a panic. Hence 772cea0bb1bSMika Westerberg * ifdef it under CONFIG_CRASH_DUMP and not CONFIG_PROC_VMCORE. 773cea0bb1bSMika Westerberg */ 774cea0bb1bSMika Westerberg 775cea0bb1bSMika Westerberg #ifdef CONFIG_CRASH_DUMP 776cea0bb1bSMika Westerberg /* 777cea0bb1bSMika Westerberg * elfcorehdr= specifies the location of elf core header stored by the crashed 778cea0bb1bSMika Westerberg * kernel. This option will be passed by kexec loader to the capture kernel. 779cea0bb1bSMika Westerberg */ 780cea0bb1bSMika Westerberg static int __init setup_elfcorehdr(char *arg) 781cea0bb1bSMika Westerberg { 782cea0bb1bSMika Westerberg char *end; 783cea0bb1bSMika Westerberg 784cea0bb1bSMika Westerberg if (!arg) 785cea0bb1bSMika Westerberg return -EINVAL; 786cea0bb1bSMika Westerberg 787cea0bb1bSMika Westerberg elfcorehdr_addr = memparse(arg, &end); 788cea0bb1bSMika Westerberg return end > arg ? 0 : -EINVAL; 789cea0bb1bSMika Westerberg } 790cea0bb1bSMika Westerberg early_param("elfcorehdr", setup_elfcorehdr); 791cea0bb1bSMika Westerberg #endif /* CONFIG_CRASH_DUMP */ 792cea0bb1bSMika Westerberg 79373a65b3fSUwe Kleine-König static void __init squash_mem_tags(struct tag *tag) 79473a65b3fSUwe Kleine-König { 79573a65b3fSUwe Kleine-König for (; tag->hdr.size; tag = tag_next(tag)) 79673a65b3fSUwe Kleine-König if (tag->hdr.tag == ATAG_MEM) 79773a65b3fSUwe Kleine-König tag->hdr.tag = ATAG_NONE; 79873a65b3fSUwe Kleine-König } 79973a65b3fSUwe Kleine-König 8001da177e4SLinus Torvalds void __init setup_arch(char **cmdline_p) 8011da177e4SLinus Torvalds { 8021da177e4SLinus Torvalds struct tag *tags = (struct tag *)&init_tags; 8031da177e4SLinus Torvalds struct machine_desc *mdesc; 8041da177e4SLinus Torvalds char *from = default_command_line; 8051da177e4SLinus Torvalds 806bff595c1SCatalin Marinas unwind_init(); 807bff595c1SCatalin Marinas 8081da177e4SLinus Torvalds setup_processor(); 8091da177e4SLinus Torvalds mdesc = setup_machine(machine_arch_type); 8101da177e4SLinus Torvalds machine_name = mdesc->name; 8111da177e4SLinus Torvalds 8121da177e4SLinus Torvalds if (mdesc->soft_reboot) 8131da177e4SLinus Torvalds reboot_setup("s"); 8141da177e4SLinus Torvalds 8159d20fdd5SBill Gatliff if (__atags_pointer) 8169d20fdd5SBill Gatliff tags = phys_to_virt(__atags_pointer); 8179d20fdd5SBill Gatliff else if (mdesc->boot_params) 818f9bd6ea4SRussell King tags = phys_to_virt(mdesc->boot_params); 8191da177e4SLinus Torvalds 82073a65b3fSUwe Kleine-König #if defined(CONFIG_DEPRECATED_PARAM_STRUCT) 8211da177e4SLinus Torvalds /* 8221da177e4SLinus Torvalds * If we have the old style parameters, convert them to 8231da177e4SLinus Torvalds * a tag list. 8241da177e4SLinus Torvalds */ 8251da177e4SLinus Torvalds if (tags->hdr.tag != ATAG_CORE) 8261da177e4SLinus Torvalds convert_to_tag_list(tags); 82773a65b3fSUwe Kleine-König #endif 8281da177e4SLinus Torvalds if (tags->hdr.tag != ATAG_CORE) 8291da177e4SLinus Torvalds tags = (struct tag *)&init_tags; 8301da177e4SLinus Torvalds 8311da177e4SLinus Torvalds if (mdesc->fixup) 8321da177e4SLinus Torvalds mdesc->fixup(mdesc, tags, &from, &meminfo); 8331da177e4SLinus Torvalds 8341da177e4SLinus Torvalds if (tags->hdr.tag == ATAG_CORE) { 8351da177e4SLinus Torvalds if (meminfo.nr_banks != 0) 8361da177e4SLinus Torvalds squash_mem_tags(tags); 8374cd9d6f7SRichard Purdie save_atags(tags); 8381da177e4SLinus Torvalds parse_tags(tags); 8391da177e4SLinus Torvalds } 8401da177e4SLinus Torvalds 84137efe642SRussell King init_mm.start_code = (unsigned long) _text; 84237efe642SRussell King init_mm.end_code = (unsigned long) _etext; 84337efe642SRussell King init_mm.end_data = (unsigned long) _edata; 84437efe642SRussell King init_mm.brk = (unsigned long) _end; 8451da177e4SLinus Torvalds 8462b0d8c25SJeremy Kerr /* parse_early_param needs a boot_command_line */ 8472b0d8c25SJeremy Kerr strlcpy(boot_command_line, from, COMMAND_LINE_SIZE); 8482b0d8c25SJeremy Kerr 84948ab7e09SJeremy Kerr /* populate cmd_line too for later use, preserving boot_command_line */ 85048ab7e09SJeremy Kerr strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); 85148ab7e09SJeremy Kerr *cmdline_p = cmd_line; 8522b0d8c25SJeremy Kerr 8532b0d8c25SJeremy Kerr parse_early_param(); 8542b0d8c25SJeremy Kerr 8558d717a52SRussell King arm_memblock_init(&meminfo, mdesc); 8562778f620SRussell King 8574b5f32ceSNicolas Pitre paging_init(mdesc); 8581da177e4SLinus Torvalds request_standard_resources(&meminfo, mdesc); 8591da177e4SLinus Torvalds 8607bbb7940SRussell King #ifdef CONFIG_SMP 8617bbb7940SRussell King smp_init_cpus(); 8627bbb7940SRussell King #endif 8633c57fb43SMika Westerberg reserve_crashkernel(); 8647bbb7940SRussell King 865ccea7a19SRussell King cpu_init(); 866bc581770SLinus Walleij tcm_init(); 867ccea7a19SRussell King 8681da177e4SLinus Torvalds /* 8691da177e4SLinus Torvalds * Set up various architecture-specific pointers 8701da177e4SLinus Torvalds */ 871354e6f72Seric miao arch_nr_irqs = mdesc->nr_irqs; 8721da177e4SLinus Torvalds init_arch_irq = mdesc->init_irq; 8731da177e4SLinus Torvalds system_timer = mdesc->timer; 8741da177e4SLinus Torvalds init_machine = mdesc->init_machine; 8751da177e4SLinus Torvalds 8761da177e4SLinus Torvalds #ifdef CONFIG_VT 8771da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) 8781da177e4SLinus Torvalds conswitchp = &vga_con; 8791da177e4SLinus Torvalds #elif defined(CONFIG_DUMMY_CONSOLE) 8801da177e4SLinus Torvalds conswitchp = &dummy_con; 8811da177e4SLinus Torvalds #endif 8821da177e4SLinus Torvalds #endif 8835cbad0ebSJason Wessel early_trap_init(); 8841da177e4SLinus Torvalds } 8851da177e4SLinus Torvalds 8861da177e4SLinus Torvalds 8871da177e4SLinus Torvalds static int __init topology_init(void) 8881da177e4SLinus Torvalds { 8891da177e4SLinus Torvalds int cpu; 8901da177e4SLinus Torvalds 89166fb8bd2SRussell King for_each_possible_cpu(cpu) { 89266fb8bd2SRussell King struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu); 89366fb8bd2SRussell King cpuinfo->cpu.hotpluggable = 1; 89466fb8bd2SRussell King register_cpu(&cpuinfo->cpu, cpu); 89566fb8bd2SRussell King } 8961da177e4SLinus Torvalds 8971da177e4SLinus Torvalds return 0; 8981da177e4SLinus Torvalds } 8991da177e4SLinus Torvalds subsys_initcall(topology_init); 9001da177e4SLinus Torvalds 901e119bfffSRussell King #ifdef CONFIG_HAVE_PROC_CPU 902e119bfffSRussell King static int __init proc_cpu_init(void) 903e119bfffSRussell King { 904e119bfffSRussell King struct proc_dir_entry *res; 905e119bfffSRussell King 906e119bfffSRussell King res = proc_mkdir("cpu", NULL); 907e119bfffSRussell King if (!res) 908e119bfffSRussell King return -ENOMEM; 909e119bfffSRussell King return 0; 910e119bfffSRussell King } 911e119bfffSRussell King fs_initcall(proc_cpu_init); 912e119bfffSRussell King #endif 913e119bfffSRussell King 9141da177e4SLinus Torvalds static const char *hwcap_str[] = { 9151da177e4SLinus Torvalds "swp", 9161da177e4SLinus Torvalds "half", 9171da177e4SLinus Torvalds "thumb", 9181da177e4SLinus Torvalds "26bit", 9191da177e4SLinus Torvalds "fastmult", 9201da177e4SLinus Torvalds "fpa", 9211da177e4SLinus Torvalds "vfp", 9221da177e4SLinus Torvalds "edsp", 9231da177e4SLinus Torvalds "java", 9248f7f9435SPaul Gortmaker "iwmmxt", 92599e4a6ddSLennert Buytenhek "crunch", 9264369ae16SCatalin Marinas "thumbee", 9272bedbdf4SCatalin Marinas "neon", 9287279dc3eSCatalin Marinas "vfpv3", 9297279dc3eSCatalin Marinas "vfpv3d16", 9301da177e4SLinus Torvalds NULL 9311da177e4SLinus Torvalds }; 9321da177e4SLinus Torvalds 9331da177e4SLinus Torvalds static int c_show(struct seq_file *m, void *v) 9341da177e4SLinus Torvalds { 9351da177e4SLinus Torvalds int i; 9361da177e4SLinus Torvalds 9371da177e4SLinus Torvalds seq_printf(m, "Processor\t: %s rev %d (%s)\n", 9380ba8b9b2SRussell King cpu_name, read_cpuid_id() & 15, elf_platform); 9391da177e4SLinus Torvalds 9401da177e4SLinus Torvalds #if defined(CONFIG_SMP) 9411da177e4SLinus Torvalds for_each_online_cpu(i) { 94215559722SRussell King /* 94315559722SRussell King * glibc reads /proc/cpuinfo to determine the number of 94415559722SRussell King * online processors, looking for lines beginning with 94515559722SRussell King * "processor". Give glibc what it expects. 94615559722SRussell King */ 94715559722SRussell King seq_printf(m, "processor\t: %d\n", i); 9481da177e4SLinus Torvalds seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n", 9491da177e4SLinus Torvalds per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ), 9501da177e4SLinus Torvalds (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100); 9511da177e4SLinus Torvalds } 9521da177e4SLinus Torvalds #else /* CONFIG_SMP */ 9531da177e4SLinus Torvalds seq_printf(m, "BogoMIPS\t: %lu.%02lu\n", 9541da177e4SLinus Torvalds loops_per_jiffy / (500000/HZ), 9551da177e4SLinus Torvalds (loops_per_jiffy / (5000/HZ)) % 100); 9561da177e4SLinus Torvalds #endif 9571da177e4SLinus Torvalds 9581da177e4SLinus Torvalds /* dump out the processor features */ 9591da177e4SLinus Torvalds seq_puts(m, "Features\t: "); 9601da177e4SLinus Torvalds 9611da177e4SLinus Torvalds for (i = 0; hwcap_str[i]; i++) 9621da177e4SLinus Torvalds if (elf_hwcap & (1 << i)) 9631da177e4SLinus Torvalds seq_printf(m, "%s ", hwcap_str[i]); 9641da177e4SLinus Torvalds 9650ba8b9b2SRussell King seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24); 9661da177e4SLinus Torvalds seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]); 9671da177e4SLinus Torvalds 9680ba8b9b2SRussell King if ((read_cpuid_id() & 0x0008f000) == 0x00000000) { 9691da177e4SLinus Torvalds /* pre-ARM7 */ 9700ba8b9b2SRussell King seq_printf(m, "CPU part\t: %07x\n", read_cpuid_id() >> 4); 9711da177e4SLinus Torvalds } else { 9720ba8b9b2SRussell King if ((read_cpuid_id() & 0x0008f000) == 0x00007000) { 9731da177e4SLinus Torvalds /* ARM7 */ 9741da177e4SLinus Torvalds seq_printf(m, "CPU variant\t: 0x%02x\n", 9750ba8b9b2SRussell King (read_cpuid_id() >> 16) & 127); 9761da177e4SLinus Torvalds } else { 9771da177e4SLinus Torvalds /* post-ARM7 */ 9781da177e4SLinus Torvalds seq_printf(m, "CPU variant\t: 0x%x\n", 9790ba8b9b2SRussell King (read_cpuid_id() >> 20) & 15); 9801da177e4SLinus Torvalds } 9811da177e4SLinus Torvalds seq_printf(m, "CPU part\t: 0x%03x\n", 9820ba8b9b2SRussell King (read_cpuid_id() >> 4) & 0xfff); 9831da177e4SLinus Torvalds } 9840ba8b9b2SRussell King seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15); 9851da177e4SLinus Torvalds 9861da177e4SLinus Torvalds seq_puts(m, "\n"); 9871da177e4SLinus Torvalds 9881da177e4SLinus Torvalds seq_printf(m, "Hardware\t: %s\n", machine_name); 9891da177e4SLinus Torvalds seq_printf(m, "Revision\t: %04x\n", system_rev); 9901da177e4SLinus Torvalds seq_printf(m, "Serial\t\t: %08x%08x\n", 9911da177e4SLinus Torvalds system_serial_high, system_serial_low); 9921da177e4SLinus Torvalds 9931da177e4SLinus Torvalds return 0; 9941da177e4SLinus Torvalds } 9951da177e4SLinus Torvalds 9961da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos) 9971da177e4SLinus Torvalds { 9981da177e4SLinus Torvalds return *pos < 1 ? (void *)1 : NULL; 9991da177e4SLinus Torvalds } 10001da177e4SLinus Torvalds 10011da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos) 10021da177e4SLinus Torvalds { 10031da177e4SLinus Torvalds ++*pos; 10041da177e4SLinus Torvalds return NULL; 10051da177e4SLinus Torvalds } 10061da177e4SLinus Torvalds 10071da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v) 10081da177e4SLinus Torvalds { 10091da177e4SLinus Torvalds } 10101da177e4SLinus Torvalds 10112ffd6e18SJan Engelhardt const struct seq_operations cpuinfo_op = { 10121da177e4SLinus Torvalds .start = c_start, 10131da177e4SLinus Torvalds .next = c_next, 10141da177e4SLinus Torvalds .stop = c_stop, 10151da177e4SLinus Torvalds .show = c_show 10161da177e4SLinus Torvalds }; 1017