xref: /openbmc/linux/arch/arm/kernel/setup.c (revision 8925ec4c)
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