xref: /openbmc/linux/arch/arm/kernel/setup.c (revision a5d5f7da)
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  */
10ecea4ab6SPaul Gortmaker #include <linux/export.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>
2393c02ab4SGrant Likely #include <linux/of_fdt.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>
312ecccf90SDave Martin #include <linux/bug.h>
322ecccf90SDave Martin #include <linux/compiler.h>
3327a3f0e9SNicolas Pitre #include <linux/sort.h>
341da177e4SLinus Torvalds 
35b86040a5SCatalin Marinas #include <asm/unified.h>
3615d07dc9SRussell King #include <asm/cp15.h>
371da177e4SLinus Torvalds #include <asm/cpu.h>
380ba8b9b2SRussell King #include <asm/cputype.h>
391da177e4SLinus Torvalds #include <asm/elf.h>
401da177e4SLinus Torvalds #include <asm/procinfo.h>
4137efe642SRussell King #include <asm/sections.h>
421da177e4SLinus Torvalds #include <asm/setup.h>
43f00ec48fSRussell King #include <asm/smp_plat.h>
441da177e4SLinus Torvalds #include <asm/mach-types.h>
451da177e4SLinus Torvalds #include <asm/cacheflush.h>
4646097c7dSRussell King #include <asm/cachetype.h>
471da177e4SLinus Torvalds #include <asm/tlbflush.h>
481da177e4SLinus Torvalds 
4993c02ab4SGrant Likely #include <asm/prom.h>
501da177e4SLinus Torvalds #include <asm/mach/arch.h>
511da177e4SLinus Torvalds #include <asm/mach/irq.h>
521da177e4SLinus Torvalds #include <asm/mach/time.h>
539f97da78SDavid Howells #include <asm/system_info.h>
549f97da78SDavid Howells #include <asm/system_misc.h>
555cbad0ebSJason Wessel #include <asm/traps.h>
56bff595c1SCatalin Marinas #include <asm/unwind.h>
571c16d242STejun Heo #include <asm/memblock.h>
581da177e4SLinus Torvalds 
5973a65b3fSUwe Kleine-König #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
600fc1c832SBen Dooks #include "compat.h"
6173a65b3fSUwe Kleine-König #endif
624cd9d6f7SRichard Purdie #include "atags.h"
63bc581770SLinus Walleij #include "tcm.h"
640fc1c832SBen Dooks 
651da177e4SLinus Torvalds #ifndef MEM_SIZE
661da177e4SLinus Torvalds #define MEM_SIZE	(16*1024*1024)
671da177e4SLinus Torvalds #endif
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
701da177e4SLinus Torvalds char fpe_type[8];
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds static int __init fpe_setup(char *line)
731da177e4SLinus Torvalds {
741da177e4SLinus Torvalds 	memcpy(fpe_type, line, 8);
751da177e4SLinus Torvalds 	return 1;
761da177e4SLinus Torvalds }
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds __setup("fpe=", fpe_setup);
791da177e4SLinus Torvalds #endif
801da177e4SLinus Torvalds 
814b5f32ceSNicolas Pitre extern void paging_init(struct machine_desc *desc);
820371d3f7SRussell King extern void sanity_check_meminfo(void);
831da177e4SLinus Torvalds extern void reboot_setup(char *str);
84c7909509SMarek Szyprowski extern void setup_dma_zone(struct machine_desc *desc);
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds unsigned int processor_id;
87c18f6581SKrzysztof Halasa EXPORT_SYMBOL(processor_id);
880385ebc0SRussell King unsigned int __machine_arch_type __read_mostly;
891da177e4SLinus Torvalds EXPORT_SYMBOL(__machine_arch_type);
900385ebc0SRussell King unsigned int cacheid __read_mostly;
91c0e95878SRussell King EXPORT_SYMBOL(cacheid);
921da177e4SLinus Torvalds 
939d20fdd5SBill Gatliff unsigned int __atags_pointer __initdata;
949d20fdd5SBill Gatliff 
951da177e4SLinus Torvalds unsigned int system_rev;
961da177e4SLinus Torvalds EXPORT_SYMBOL(system_rev);
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds unsigned int system_serial_low;
991da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_low);
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds unsigned int system_serial_high;
1021da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_high);
1031da177e4SLinus Torvalds 
1040385ebc0SRussell King unsigned int elf_hwcap __read_mostly;
1051da177e4SLinus Torvalds EXPORT_SYMBOL(elf_hwcap);
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds 
1081da177e4SLinus Torvalds #ifdef MULTI_CPU
1090385ebc0SRussell King struct processor processor __read_mostly;
1101da177e4SLinus Torvalds #endif
1111da177e4SLinus Torvalds #ifdef MULTI_TLB
1120385ebc0SRussell King struct cpu_tlb_fns cpu_tlb __read_mostly;
1131da177e4SLinus Torvalds #endif
1141da177e4SLinus Torvalds #ifdef MULTI_USER
1150385ebc0SRussell King struct cpu_user_fns cpu_user __read_mostly;
1161da177e4SLinus Torvalds #endif
1171da177e4SLinus Torvalds #ifdef MULTI_CACHE
1180385ebc0SRussell King struct cpu_cache_fns cpu_cache __read_mostly;
1191da177e4SLinus Torvalds #endif
120953233dcSCatalin Marinas #ifdef CONFIG_OUTER_CACHE
1210385ebc0SRussell King struct outer_cache_fns outer_cache __read_mostly;
1226c09f09dSSantosh Shilimkar EXPORT_SYMBOL(outer_cache);
123953233dcSCatalin Marinas #endif
1241da177e4SLinus Torvalds 
1252ecccf90SDave Martin /*
1262ecccf90SDave Martin  * Cached cpu_architecture() result for use by assembler code.
1272ecccf90SDave Martin  * C code should use the cpu_architecture() function instead of accessing this
1282ecccf90SDave Martin  * variable directly.
1292ecccf90SDave Martin  */
1302ecccf90SDave Martin int __cpu_architecture __read_mostly = CPU_ARCH_UNKNOWN;
1312ecccf90SDave Martin 
132ccea7a19SRussell King struct stack {
133ccea7a19SRussell King 	u32 irq[3];
134ccea7a19SRussell King 	u32 abt[3];
135ccea7a19SRussell King 	u32 und[3];
136ccea7a19SRussell King } ____cacheline_aligned;
137ccea7a19SRussell King 
138ccea7a19SRussell King static struct stack stacks[NR_CPUS];
139ccea7a19SRussell King 
1401da177e4SLinus Torvalds char elf_platform[ELF_PLATFORM_SIZE];
1411da177e4SLinus Torvalds EXPORT_SYMBOL(elf_platform);
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds static const char *cpu_name;
1441da177e4SLinus Torvalds static const char *machine_name;
14548ab7e09SJeremy Kerr static char __initdata cmd_line[COMMAND_LINE_SIZE];
1468ff1443cSRussell King struct machine_desc *machine_desc __initdata;
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
1491da177e4SLinus Torvalds static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
1501da177e4SLinus Torvalds #define ENDIANNESS ((char)endian_test.l)
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds /*
1551da177e4SLinus Torvalds  * Standard memory resources
1561da177e4SLinus Torvalds  */
1571da177e4SLinus Torvalds static struct resource mem_res[] = {
158740e518eSGreg Kroah-Hartman 	{
159740e518eSGreg Kroah-Hartman 		.name = "Video RAM",
160740e518eSGreg Kroah-Hartman 		.start = 0,
161740e518eSGreg Kroah-Hartman 		.end = 0,
162740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
163740e518eSGreg Kroah-Hartman 	},
164740e518eSGreg Kroah-Hartman 	{
165a36d8e5bSKees Cook 		.name = "Kernel code",
166740e518eSGreg Kroah-Hartman 		.start = 0,
167740e518eSGreg Kroah-Hartman 		.end = 0,
168740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
169740e518eSGreg Kroah-Hartman 	},
170740e518eSGreg Kroah-Hartman 	{
171740e518eSGreg Kroah-Hartman 		.name = "Kernel data",
172740e518eSGreg Kroah-Hartman 		.start = 0,
173740e518eSGreg Kroah-Hartman 		.end = 0,
174740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
175740e518eSGreg Kroah-Hartman 	}
1761da177e4SLinus Torvalds };
1771da177e4SLinus Torvalds 
1781da177e4SLinus Torvalds #define video_ram   mem_res[0]
1791da177e4SLinus Torvalds #define kernel_code mem_res[1]
1801da177e4SLinus Torvalds #define kernel_data mem_res[2]
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds static struct resource io_res[] = {
183740e518eSGreg Kroah-Hartman 	{
184740e518eSGreg Kroah-Hartman 		.name = "reserved",
185740e518eSGreg Kroah-Hartman 		.start = 0x3bc,
186740e518eSGreg Kroah-Hartman 		.end = 0x3be,
187740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
188740e518eSGreg Kroah-Hartman 	},
189740e518eSGreg Kroah-Hartman 	{
190740e518eSGreg Kroah-Hartman 		.name = "reserved",
191740e518eSGreg Kroah-Hartman 		.start = 0x378,
192740e518eSGreg Kroah-Hartman 		.end = 0x37f,
193740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
194740e518eSGreg Kroah-Hartman 	},
195740e518eSGreg Kroah-Hartman 	{
196740e518eSGreg Kroah-Hartman 		.name = "reserved",
197740e518eSGreg Kroah-Hartman 		.start = 0x278,
198740e518eSGreg Kroah-Hartman 		.end = 0x27f,
199740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
200740e518eSGreg Kroah-Hartman 	}
2011da177e4SLinus Torvalds };
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds #define lp0 io_res[0]
2041da177e4SLinus Torvalds #define lp1 io_res[1]
2051da177e4SLinus Torvalds #define lp2 io_res[2]
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds static const char *proc_arch[] = {
2081da177e4SLinus Torvalds 	"undefined/unknown",
2091da177e4SLinus Torvalds 	"3",
2101da177e4SLinus Torvalds 	"4",
2111da177e4SLinus Torvalds 	"4T",
2121da177e4SLinus Torvalds 	"5",
2131da177e4SLinus Torvalds 	"5T",
2141da177e4SLinus Torvalds 	"5TE",
2151da177e4SLinus Torvalds 	"5TEJ",
2161da177e4SLinus Torvalds 	"6TEJ",
2176b090a25SCatalin Marinas 	"7",
2181da177e4SLinus Torvalds 	"?(11)",
2191da177e4SLinus Torvalds 	"?(12)",
2201da177e4SLinus Torvalds 	"?(13)",
2211da177e4SLinus Torvalds 	"?(14)",
2221da177e4SLinus Torvalds 	"?(15)",
2231da177e4SLinus Torvalds 	"?(16)",
2241da177e4SLinus Torvalds 	"?(17)",
2251da177e4SLinus Torvalds };
2261da177e4SLinus Torvalds 
2272ecccf90SDave Martin static int __get_cpu_architecture(void)
2281da177e4SLinus Torvalds {
2291da177e4SLinus Torvalds 	int cpu_arch;
2301da177e4SLinus Torvalds 
2310ba8b9b2SRussell King 	if ((read_cpuid_id() & 0x0008f000) == 0) {
2321da177e4SLinus Torvalds 		cpu_arch = CPU_ARCH_UNKNOWN;
2330ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
2340ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
2350ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x00080000) == 0x00000000) {
2360ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() >> 16) & 7;
2371da177e4SLinus Torvalds 		if (cpu_arch)
2381da177e4SLinus Torvalds 			cpu_arch += CPU_ARCH_ARMv3;
2390ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
240180005c4SCatalin Marinas 		unsigned int mmfr0;
241180005c4SCatalin Marinas 
242180005c4SCatalin Marinas 		/* Revised CPUID format. Read the Memory Model Feature
243180005c4SCatalin Marinas 		 * Register 0 and check for VMSAv7 or PMSAv7 */
244180005c4SCatalin Marinas 		asm("mrc	p15, 0, %0, c0, c1, 4"
245180005c4SCatalin Marinas 		    : "=r" (mmfr0));
246315cfe78SCatalin Marinas 		if ((mmfr0 & 0x0000000f) >= 0x00000003 ||
247315cfe78SCatalin Marinas 		    (mmfr0 & 0x000000f0) >= 0x00000030)
248180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv7;
249180005c4SCatalin Marinas 		else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
250180005c4SCatalin Marinas 			 (mmfr0 & 0x000000f0) == 0x00000020)
251180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv6;
252180005c4SCatalin Marinas 		else
253180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_UNKNOWN;
254180005c4SCatalin Marinas 	} else
255180005c4SCatalin Marinas 		cpu_arch = CPU_ARCH_UNKNOWN;
2561da177e4SLinus Torvalds 
2571da177e4SLinus Torvalds 	return cpu_arch;
2581da177e4SLinus Torvalds }
2591da177e4SLinus Torvalds 
2602ecccf90SDave Martin int __pure cpu_architecture(void)
2612ecccf90SDave Martin {
2622ecccf90SDave Martin 	BUG_ON(__cpu_architecture == CPU_ARCH_UNKNOWN);
2632ecccf90SDave Martin 
2642ecccf90SDave Martin 	return __cpu_architecture;
2652ecccf90SDave Martin }
2662ecccf90SDave Martin 
2678925ec4cSWill Deacon static int cpu_has_aliasing_icache(unsigned int arch)
2688925ec4cSWill Deacon {
2698925ec4cSWill Deacon 	int aliasing_icache;
2708925ec4cSWill Deacon 	unsigned int id_reg, num_sets, line_size;
2718925ec4cSWill Deacon 
2727f94e9ccSWill Deacon 	/* PIPT caches never alias. */
2737f94e9ccSWill Deacon 	if (icache_is_pipt())
2747f94e9ccSWill Deacon 		return 0;
2757f94e9ccSWill Deacon 
2768925ec4cSWill Deacon 	/* arch specifies the register format */
2778925ec4cSWill Deacon 	switch (arch) {
2788925ec4cSWill Deacon 	case CPU_ARCH_ARMv7:
2795fb31a96SLinus Walleij 		asm("mcr	p15, 2, %0, c0, c0, 0 @ set CSSELR"
2805fb31a96SLinus Walleij 		    : /* No output operands */
2818925ec4cSWill Deacon 		    : "r" (1));
2825fb31a96SLinus Walleij 		isb();
2835fb31a96SLinus Walleij 		asm("mrc	p15, 1, %0, c0, c0, 0 @ read CCSIDR"
2845fb31a96SLinus Walleij 		    : "=r" (id_reg));
2858925ec4cSWill Deacon 		line_size = 4 << ((id_reg & 0x7) + 2);
2868925ec4cSWill Deacon 		num_sets = ((id_reg >> 13) & 0x7fff) + 1;
2878925ec4cSWill Deacon 		aliasing_icache = (line_size * num_sets) > PAGE_SIZE;
2888925ec4cSWill Deacon 		break;
2898925ec4cSWill Deacon 	case CPU_ARCH_ARMv6:
2908925ec4cSWill Deacon 		aliasing_icache = read_cpuid_cachetype() & (1 << 11);
2918925ec4cSWill Deacon 		break;
2928925ec4cSWill Deacon 	default:
2938925ec4cSWill Deacon 		/* I-cache aliases will be handled by D-cache aliasing code */
2948925ec4cSWill Deacon 		aliasing_icache = 0;
2958925ec4cSWill Deacon 	}
2968925ec4cSWill Deacon 
2978925ec4cSWill Deacon 	return aliasing_icache;
2988925ec4cSWill Deacon }
2998925ec4cSWill Deacon 
300c0e95878SRussell King static void __init cacheid_init(void)
301c0e95878SRussell King {
302c0e95878SRussell King 	unsigned int cachetype = read_cpuid_cachetype();
303c0e95878SRussell King 	unsigned int arch = cpu_architecture();
304c0e95878SRussell King 
305b57ee99fSCatalin Marinas 	if (arch >= CPU_ARCH_ARMv6) {
306b57ee99fSCatalin Marinas 		if ((cachetype & (7 << 29)) == 4 << 29) {
307b57ee99fSCatalin Marinas 			/* ARMv7 register format */
30872dc53acSWill Deacon 			arch = CPU_ARCH_ARMv7;
309c0e95878SRussell King 			cacheid = CACHEID_VIPT_NONALIASING;
3107f94e9ccSWill Deacon 			switch (cachetype & (3 << 14)) {
3117f94e9ccSWill Deacon 			case (1 << 14):
312c0e95878SRussell King 				cacheid |= CACHEID_ASID_TAGGED;
3137f94e9ccSWill Deacon 				break;
3147f94e9ccSWill Deacon 			case (3 << 14):
3157f94e9ccSWill Deacon 				cacheid |= CACHEID_PIPT;
3167f94e9ccSWill Deacon 				break;
3177f94e9ccSWill Deacon 			}
3188925ec4cSWill Deacon 		} else {
31972dc53acSWill Deacon 			arch = CPU_ARCH_ARMv6;
32072dc53acSWill Deacon 			if (cachetype & (1 << 23))
32172dc53acSWill Deacon 				cacheid = CACHEID_VIPT_ALIASING;
32272dc53acSWill Deacon 			else
323c0e95878SRussell King 				cacheid = CACHEID_VIPT_NONALIASING;
3248925ec4cSWill Deacon 		}
32572dc53acSWill Deacon 		if (cpu_has_aliasing_icache(arch))
32672dc53acSWill Deacon 			cacheid |= CACHEID_VIPT_I_ALIASING;
327c0e95878SRussell King 	} else {
328c0e95878SRussell King 		cacheid = CACHEID_VIVT;
329c0e95878SRussell King 	}
3302b4ae1f1SRussell King 
3312b4ae1f1SRussell King 	printk("CPU: %s data cache, %s instruction cache\n",
3322b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
3332b4ae1f1SRussell King 		cache_is_vipt_aliasing() ? "VIPT aliasing" :
3347f94e9ccSWill Deacon 		cache_is_vipt_nonaliasing() ? "PIPT / VIPT nonaliasing" : "unknown",
3352b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
3362b4ae1f1SRussell King 		icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :
3378925ec4cSWill Deacon 		icache_is_vipt_aliasing() ? "VIPT aliasing" :
3387f94e9ccSWill Deacon 		icache_is_pipt() ? "PIPT" :
3392b4ae1f1SRussell King 		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");
340c0e95878SRussell King }
341c0e95878SRussell King 
3421da177e4SLinus Torvalds /*
3431da177e4SLinus Torvalds  * These functions re-use the assembly code in head.S, which
3441da177e4SLinus Torvalds  * already provide the required functionality.
3451da177e4SLinus Torvalds  */
3460f44ba1dSRussell King extern struct proc_info_list *lookup_processor_type(unsigned int);
3476fc31d54SRussell King 
34893c02ab4SGrant Likely void __init early_print(const char *str, ...)
3496fc31d54SRussell King {
3506fc31d54SRussell King 	extern void printascii(const char *);
3516fc31d54SRussell King 	char buf[256];
3526fc31d54SRussell King 	va_list ap;
3536fc31d54SRussell King 
3546fc31d54SRussell King 	va_start(ap, str);
3556fc31d54SRussell King 	vsnprintf(buf, sizeof(buf), str, ap);
3566fc31d54SRussell King 	va_end(ap);
3576fc31d54SRussell King 
3586fc31d54SRussell King #ifdef CONFIG_DEBUG_LL
3596fc31d54SRussell King 	printascii(buf);
3606fc31d54SRussell King #endif
3616fc31d54SRussell King 	printk("%s", buf);
3626fc31d54SRussell King }
3636fc31d54SRussell King 
364f159f4edSTony Lindgren static void __init feat_v6_fixup(void)
365f159f4edSTony Lindgren {
366f159f4edSTony Lindgren 	int id = read_cpuid_id();
367f159f4edSTony Lindgren 
368f159f4edSTony Lindgren 	if ((id & 0xff0f0000) != 0x41070000)
369f159f4edSTony Lindgren 		return;
370f159f4edSTony Lindgren 
371f159f4edSTony Lindgren 	/*
372f159f4edSTony Lindgren 	 * HWCAP_TLS is available only on 1136 r1p0 and later,
373f159f4edSTony Lindgren 	 * see also kuser_get_tls_init.
374f159f4edSTony Lindgren 	 */
375f159f4edSTony Lindgren 	if ((((id >> 4) & 0xfff) == 0xb36) && (((id >> 20) & 3) == 0))
376f159f4edSTony Lindgren 		elf_hwcap &= ~HWCAP_TLS;
377f159f4edSTony Lindgren }
378f159f4edSTony Lindgren 
379b69874e4SRussell King /*
380b69874e4SRussell King  * cpu_init - initialise one CPU.
381b69874e4SRussell King  *
382b69874e4SRussell King  * cpu_init sets up the per-CPU stacks.
383b69874e4SRussell King  */
384b69874e4SRussell King void cpu_init(void)
385b69874e4SRussell King {
386b69874e4SRussell King 	unsigned int cpu = smp_processor_id();
387b69874e4SRussell King 	struct stack *stk = &stacks[cpu];
388b69874e4SRussell King 
389b69874e4SRussell King 	if (cpu >= NR_CPUS) {
390b69874e4SRussell King 		printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);
391b69874e4SRussell King 		BUG();
392b69874e4SRussell King 	}
393b69874e4SRussell King 
394b69874e4SRussell King 	cpu_proc_init();
395b69874e4SRussell King 
396b69874e4SRussell King 	/*
397b69874e4SRussell King 	 * Define the placement constraint for the inline asm directive below.
398b69874e4SRussell King 	 * In Thumb-2, msr with an immediate value is not allowed.
399b69874e4SRussell King 	 */
400b69874e4SRussell King #ifdef CONFIG_THUMB2_KERNEL
401b69874e4SRussell King #define PLC	"r"
402b69874e4SRussell King #else
403b69874e4SRussell King #define PLC	"I"
404b69874e4SRussell King #endif
405b69874e4SRussell King 
406b69874e4SRussell King 	/*
407b69874e4SRussell King 	 * setup stacks for re-entrant exception handlers
408b69874e4SRussell King 	 */
409b69874e4SRussell King 	__asm__ (
410b69874e4SRussell King 	"msr	cpsr_c, %1\n\t"
411b69874e4SRussell King 	"add	r14, %0, %2\n\t"
412b69874e4SRussell King 	"mov	sp, r14\n\t"
413b69874e4SRussell King 	"msr	cpsr_c, %3\n\t"
414b69874e4SRussell King 	"add	r14, %0, %4\n\t"
415b69874e4SRussell King 	"mov	sp, r14\n\t"
416b69874e4SRussell King 	"msr	cpsr_c, %5\n\t"
417b69874e4SRussell King 	"add	r14, %0, %6\n\t"
418b69874e4SRussell King 	"mov	sp, r14\n\t"
419b69874e4SRussell King 	"msr	cpsr_c, %7"
420b69874e4SRussell King 	    :
421b69874e4SRussell King 	    : "r" (stk),
422b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
423b69874e4SRussell King 	      "I" (offsetof(struct stack, irq[0])),
424b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
425b69874e4SRussell King 	      "I" (offsetof(struct stack, abt[0])),
426b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
427b69874e4SRussell King 	      "I" (offsetof(struct stack, und[0])),
428b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
429b69874e4SRussell King 	    : "r14");
430b69874e4SRussell King }
431b69874e4SRussell King 
432eb50439bSWill Deacon int __cpu_logical_map[NR_CPUS];
433eb50439bSWill Deacon 
434eb50439bSWill Deacon void __init smp_setup_processor_id(void)
435eb50439bSWill Deacon {
436eb50439bSWill Deacon 	int i;
437eb50439bSWill Deacon 	u32 cpu = is_smp() ? read_cpuid_mpidr() & 0xff : 0;
438eb50439bSWill Deacon 
439eb50439bSWill Deacon 	cpu_logical_map(0) = cpu;
440eb50439bSWill Deacon 	for (i = 1; i < NR_CPUS; ++i)
441eb50439bSWill Deacon 		cpu_logical_map(i) = i == cpu ? 0 : i;
442eb50439bSWill Deacon 
443eb50439bSWill Deacon 	printk(KERN_INFO "Booting Linux on physical CPU %d\n", cpu);
444eb50439bSWill Deacon }
445eb50439bSWill Deacon 
4461da177e4SLinus Torvalds static void __init setup_processor(void)
4471da177e4SLinus Torvalds {
4481da177e4SLinus Torvalds 	struct proc_info_list *list;
4491da177e4SLinus Torvalds 
4501da177e4SLinus Torvalds 	/*
4511da177e4SLinus Torvalds 	 * locate processor in the list of supported processor
4521da177e4SLinus Torvalds 	 * types.  The linker builds this table for us from the
4531da177e4SLinus Torvalds 	 * entries in arch/arm/mm/proc-*.S
4541da177e4SLinus Torvalds 	 */
4550ba8b9b2SRussell King 	list = lookup_processor_type(read_cpuid_id());
4561da177e4SLinus Torvalds 	if (!list) {
4571da177e4SLinus Torvalds 		printk("CPU configuration botched (ID %08x), unable "
4580ba8b9b2SRussell King 		       "to continue.\n", read_cpuid_id());
4591da177e4SLinus Torvalds 		while (1);
4601da177e4SLinus Torvalds 	}
4611da177e4SLinus Torvalds 
4621da177e4SLinus Torvalds 	cpu_name = list->cpu_name;
4632ecccf90SDave Martin 	__cpu_architecture = __get_cpu_architecture();
4641da177e4SLinus Torvalds 
4651da177e4SLinus Torvalds #ifdef MULTI_CPU
4661da177e4SLinus Torvalds 	processor = *list->proc;
4671da177e4SLinus Torvalds #endif
4681da177e4SLinus Torvalds #ifdef MULTI_TLB
4691da177e4SLinus Torvalds 	cpu_tlb = *list->tlb;
4701da177e4SLinus Torvalds #endif
4711da177e4SLinus Torvalds #ifdef MULTI_USER
4721da177e4SLinus Torvalds 	cpu_user = *list->user;
4731da177e4SLinus Torvalds #endif
4741da177e4SLinus Torvalds #ifdef MULTI_CACHE
4751da177e4SLinus Torvalds 	cpu_cache = *list->cache;
4761da177e4SLinus Torvalds #endif
4771da177e4SLinus Torvalds 
4784e19025bSRussell King 	printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
4790ba8b9b2SRussell King 	       cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
480264edb35SRussell King 	       proc_arch[cpu_architecture()], cr_alignment);
4811da177e4SLinus Torvalds 
482a34dbfb0SWill Deacon 	snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c",
483a34dbfb0SWill Deacon 		 list->arch_name, ENDIANNESS);
484a34dbfb0SWill Deacon 	snprintf(elf_platform, ELF_PLATFORM_SIZE, "%s%c",
485a34dbfb0SWill Deacon 		 list->elf_name, ENDIANNESS);
4861da177e4SLinus Torvalds 	elf_hwcap = list->elf_hwcap;
487adeff422SCatalin Marinas #ifndef CONFIG_ARM_THUMB
488adeff422SCatalin Marinas 	elf_hwcap &= ~HWCAP_THUMB;
489adeff422SCatalin Marinas #endif
4901da177e4SLinus Torvalds 
491f159f4edSTony Lindgren 	feat_v6_fixup();
492f159f4edSTony Lindgren 
493c0e95878SRussell King 	cacheid_init();
494b69874e4SRussell King 	cpu_init();
495ccea7a19SRussell King }
496ccea7a19SRussell King 
49793c02ab4SGrant Likely void __init dump_machine_table(void)
4981da177e4SLinus Torvalds {
499dce72dd0SNicolas Pitre 	struct machine_desc *p;
5001da177e4SLinus Torvalds 
5016291319dSGrant Likely 	early_print("Available machine support:\n\nID (hex)\tNAME\n");
5026291319dSGrant Likely 	for_each_machine_desc(p)
503dce72dd0SNicolas Pitre 		early_print("%08x\t%s\n", p->nr, p->name);
504dce72dd0SNicolas Pitre 
505dce72dd0SNicolas Pitre 	early_print("\nPlease check your kernel config and/or bootloader.\n");
506dce72dd0SNicolas Pitre 
507dce72dd0SNicolas Pitre 	while (true)
508dce72dd0SNicolas Pitre 		/* can't use cpu_relax() here as it may require MMU setup */;
5091da177e4SLinus Torvalds }
5101da177e4SLinus Torvalds 
511a5d5f7daSPeter Maydell int __init arm_add_memory(phys_addr_t start, phys_addr_t size)
5123a669411SRussell King {
5134b5f32ceSNicolas Pitre 	struct membank *bank = &meminfo.bank[meminfo.nr_banks];
5144b5f32ceSNicolas Pitre 
5154b5f32ceSNicolas Pitre 	if (meminfo.nr_banks >= NR_BANKS) {
5164b5f32ceSNicolas Pitre 		printk(KERN_CRIT "NR_BANKS too low, "
51729a38193SWill Deacon 			"ignoring memory at 0x%08llx\n", (long long)start);
5184b5f32ceSNicolas Pitre 		return -EINVAL;
5194b5f32ceSNicolas Pitre 	}
52005f96ef1SRussell King 
5213a669411SRussell King 	/*
5223a669411SRussell King 	 * Ensure that start/size are aligned to a page boundary.
5233a669411SRussell King 	 * Size is appropriately rounded down, start is rounded up.
5243a669411SRussell King 	 */
5253a669411SRussell King 	size -= start & ~PAGE_MASK;
52605f96ef1SRussell King 	bank->start = PAGE_ALIGN(start);
527e5ab8580SWill Deacon 
528e5ab8580SWill Deacon #ifndef CONFIG_LPAE
529e5ab8580SWill Deacon 	if (bank->start + size < bank->start) {
530e5ab8580SWill Deacon 		printk(KERN_CRIT "Truncating memory at 0x%08llx to fit in "
531e5ab8580SWill Deacon 			"32-bit physical address space\n", (long long)start);
532e5ab8580SWill Deacon 		/*
533e5ab8580SWill Deacon 		 * To ensure bank->start + bank->size is representable in
534e5ab8580SWill Deacon 		 * 32 bits, we use ULONG_MAX as the upper limit rather than 4GB.
535e5ab8580SWill Deacon 		 * This means we lose a page after masking.
536e5ab8580SWill Deacon 		 */
537e5ab8580SWill Deacon 		size = ULONG_MAX - bank->start;
538e5ab8580SWill Deacon 	}
539e5ab8580SWill Deacon #endif
540e5ab8580SWill Deacon 
541a5d5f7daSPeter Maydell 	bank->size = size & ~(phys_addr_t)(PAGE_SIZE - 1);
5424b5f32ceSNicolas Pitre 
5434b5f32ceSNicolas Pitre 	/*
5444b5f32ceSNicolas Pitre 	 * Check whether this memory region has non-zero size or
5454b5f32ceSNicolas Pitre 	 * invalid node number.
5464b5f32ceSNicolas Pitre 	 */
547be370302SRussell King 	if (bank->size == 0)
5484b5f32ceSNicolas Pitre 		return -EINVAL;
5494b5f32ceSNicolas Pitre 
5504b5f32ceSNicolas Pitre 	meminfo.nr_banks++;
5514b5f32ceSNicolas Pitre 	return 0;
5523a669411SRussell King }
5533a669411SRussell King 
5541da177e4SLinus Torvalds /*
5551da177e4SLinus Torvalds  * Pick out the memory size.  We look for mem=size@start,
5561da177e4SLinus Torvalds  * where start and size are "size[KkMm]"
5571da177e4SLinus Torvalds  */
5582b0d8c25SJeremy Kerr static int __init early_mem(char *p)
5591da177e4SLinus Torvalds {
5601da177e4SLinus Torvalds 	static int usermem __initdata = 0;
561a5d5f7daSPeter Maydell 	phys_addr_t size;
562f60892d3SWill Deacon 	phys_addr_t start;
5632b0d8c25SJeremy Kerr 	char *endp;
5641da177e4SLinus Torvalds 
5651da177e4SLinus Torvalds 	/*
5661da177e4SLinus Torvalds 	 * If the user specifies memory size, we
5671da177e4SLinus Torvalds 	 * blow away any automatically generated
5681da177e4SLinus Torvalds 	 * size.
5691da177e4SLinus Torvalds 	 */
5701da177e4SLinus Torvalds 	if (usermem == 0) {
5711da177e4SLinus Torvalds 		usermem = 1;
5721da177e4SLinus Torvalds 		meminfo.nr_banks = 0;
5731da177e4SLinus Torvalds 	}
5741da177e4SLinus Torvalds 
5751da177e4SLinus Torvalds 	start = PHYS_OFFSET;
5762b0d8c25SJeremy Kerr 	size  = memparse(p, &endp);
5772b0d8c25SJeremy Kerr 	if (*endp == '@')
5782b0d8c25SJeremy Kerr 		start = memparse(endp + 1, NULL);
5791da177e4SLinus Torvalds 
5801c97b73eSAndrew Morton 	arm_add_memory(start, size);
5811da177e4SLinus Torvalds 
5822b0d8c25SJeremy Kerr 	return 0;
5831da177e4SLinus Torvalds }
5842b0d8c25SJeremy Kerr early_param("mem", early_mem);
5851da177e4SLinus Torvalds 
5861da177e4SLinus Torvalds static void __init
5871da177e4SLinus Torvalds setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
5881da177e4SLinus Torvalds {
5891da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_RAM
5901da177e4SLinus Torvalds 	extern int rd_size, rd_image_start, rd_prompt, rd_doload;
5911da177e4SLinus Torvalds 
5921da177e4SLinus Torvalds 	rd_image_start = image_start;
5931da177e4SLinus Torvalds 	rd_prompt = prompt;
5941da177e4SLinus Torvalds 	rd_doload = doload;
5951da177e4SLinus Torvalds 
5961da177e4SLinus Torvalds 	if (rd_sz)
5971da177e4SLinus Torvalds 		rd_size = rd_sz;
5981da177e4SLinus Torvalds #endif
5991da177e4SLinus Torvalds }
6001da177e4SLinus Torvalds 
60111b9369cSDima Zavin static void __init request_standard_resources(struct machine_desc *mdesc)
6021da177e4SLinus Torvalds {
60311b9369cSDima Zavin 	struct memblock_region *region;
6041da177e4SLinus Torvalds 	struct resource *res;
6051da177e4SLinus Torvalds 
60637efe642SRussell King 	kernel_code.start   = virt_to_phys(_text);
60737efe642SRussell King 	kernel_code.end     = virt_to_phys(_etext - 1);
608842eab40SRussell King 	kernel_data.start   = virt_to_phys(_sdata);
60937efe642SRussell King 	kernel_data.end     = virt_to_phys(_end - 1);
6101da177e4SLinus Torvalds 
61111b9369cSDima Zavin 	for_each_memblock(memory, region) {
6121da177e4SLinus Torvalds 		res = alloc_bootmem_low(sizeof(*res));
6131da177e4SLinus Torvalds 		res->name  = "System RAM";
61411b9369cSDima Zavin 		res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
61511b9369cSDima Zavin 		res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
6161da177e4SLinus Torvalds 		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
6171da177e4SLinus Torvalds 
6181da177e4SLinus Torvalds 		request_resource(&iomem_resource, res);
6191da177e4SLinus Torvalds 
6201da177e4SLinus Torvalds 		if (kernel_code.start >= res->start &&
6211da177e4SLinus Torvalds 		    kernel_code.end <= res->end)
6221da177e4SLinus Torvalds 			request_resource(res, &kernel_code);
6231da177e4SLinus Torvalds 		if (kernel_data.start >= res->start &&
6241da177e4SLinus Torvalds 		    kernel_data.end <= res->end)
6251da177e4SLinus Torvalds 			request_resource(res, &kernel_data);
6261da177e4SLinus Torvalds 	}
6271da177e4SLinus Torvalds 
6281da177e4SLinus Torvalds 	if (mdesc->video_start) {
6291da177e4SLinus Torvalds 		video_ram.start = mdesc->video_start;
6301da177e4SLinus Torvalds 		video_ram.end   = mdesc->video_end;
6311da177e4SLinus Torvalds 		request_resource(&iomem_resource, &video_ram);
6321da177e4SLinus Torvalds 	}
6331da177e4SLinus Torvalds 
6341da177e4SLinus Torvalds 	/*
6351da177e4SLinus Torvalds 	 * Some machines don't have the possibility of ever
6361da177e4SLinus Torvalds 	 * possessing lp0, lp1 or lp2
6371da177e4SLinus Torvalds 	 */
6381da177e4SLinus Torvalds 	if (mdesc->reserve_lp0)
6391da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp0);
6401da177e4SLinus Torvalds 	if (mdesc->reserve_lp1)
6411da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp1);
6421da177e4SLinus Torvalds 	if (mdesc->reserve_lp2)
6431da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp2);
6441da177e4SLinus Torvalds }
6451da177e4SLinus Torvalds 
6461da177e4SLinus Torvalds /*
6471da177e4SLinus Torvalds  *  Tag parsing.
6481da177e4SLinus Torvalds  *
6491da177e4SLinus Torvalds  * This is the new way of passing data to the kernel at boot time.  Rather
6501da177e4SLinus Torvalds  * than passing a fixed inflexible structure to the kernel, we pass a list
6511da177e4SLinus Torvalds  * of variable-sized tags to the kernel.  The first tag must be a ATAG_CORE
6521da177e4SLinus Torvalds  * tag for the list to be recognised (to distinguish the tagged list from
6531da177e4SLinus Torvalds  * a param_struct).  The list is terminated with a zero-length tag (this tag
6541da177e4SLinus Torvalds  * is not parsed in any way).
6551da177e4SLinus Torvalds  */
6561da177e4SLinus Torvalds static int __init parse_tag_core(const struct tag *tag)
6571da177e4SLinus Torvalds {
6581da177e4SLinus Torvalds 	if (tag->hdr.size > 2) {
6591da177e4SLinus Torvalds 		if ((tag->u.core.flags & 1) == 0)
6601da177e4SLinus Torvalds 			root_mountflags &= ~MS_RDONLY;
6611da177e4SLinus Torvalds 		ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
6621da177e4SLinus Torvalds 	}
6631da177e4SLinus Torvalds 	return 0;
6641da177e4SLinus Torvalds }
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds __tagtable(ATAG_CORE, parse_tag_core);
6671da177e4SLinus Torvalds 
6681da177e4SLinus Torvalds static int __init parse_tag_mem32(const struct tag *tag)
6691da177e4SLinus Torvalds {
6704b5f32ceSNicolas Pitre 	return arm_add_memory(tag->u.mem.start, tag->u.mem.size);
6711da177e4SLinus Torvalds }
6721da177e4SLinus Torvalds 
6731da177e4SLinus Torvalds __tagtable(ATAG_MEM, parse_tag_mem32);
6741da177e4SLinus Torvalds 
6751da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
6761da177e4SLinus Torvalds struct screen_info screen_info = {
6771da177e4SLinus Torvalds  .orig_video_lines	= 30,
6781da177e4SLinus Torvalds  .orig_video_cols	= 80,
6791da177e4SLinus Torvalds  .orig_video_mode	= 0,
6801da177e4SLinus Torvalds  .orig_video_ega_bx	= 0,
6811da177e4SLinus Torvalds  .orig_video_isVGA	= 1,
6821da177e4SLinus Torvalds  .orig_video_points	= 8
6831da177e4SLinus Torvalds };
6841da177e4SLinus Torvalds 
6851da177e4SLinus Torvalds static int __init parse_tag_videotext(const struct tag *tag)
6861da177e4SLinus Torvalds {
6871da177e4SLinus Torvalds 	screen_info.orig_x            = tag->u.videotext.x;
6881da177e4SLinus Torvalds 	screen_info.orig_y            = tag->u.videotext.y;
6891da177e4SLinus Torvalds 	screen_info.orig_video_page   = tag->u.videotext.video_page;
6901da177e4SLinus Torvalds 	screen_info.orig_video_mode   = tag->u.videotext.video_mode;
6911da177e4SLinus Torvalds 	screen_info.orig_video_cols   = tag->u.videotext.video_cols;
6921da177e4SLinus Torvalds 	screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
6931da177e4SLinus Torvalds 	screen_info.orig_video_lines  = tag->u.videotext.video_lines;
6941da177e4SLinus Torvalds 	screen_info.orig_video_isVGA  = tag->u.videotext.video_isvga;
6951da177e4SLinus Torvalds 	screen_info.orig_video_points = tag->u.videotext.video_points;
6961da177e4SLinus Torvalds 	return 0;
6971da177e4SLinus Torvalds }
6981da177e4SLinus Torvalds 
6991da177e4SLinus Torvalds __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
7001da177e4SLinus Torvalds #endif
7011da177e4SLinus Torvalds 
7021da177e4SLinus Torvalds static int __init parse_tag_ramdisk(const struct tag *tag)
7031da177e4SLinus Torvalds {
7041da177e4SLinus Torvalds 	setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
7051da177e4SLinus Torvalds 		      (tag->u.ramdisk.flags & 2) == 0,
7061da177e4SLinus Torvalds 		      tag->u.ramdisk.start, tag->u.ramdisk.size);
7071da177e4SLinus Torvalds 	return 0;
7081da177e4SLinus Torvalds }
7091da177e4SLinus Torvalds 
7101da177e4SLinus Torvalds __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
7111da177e4SLinus Torvalds 
7121da177e4SLinus Torvalds static int __init parse_tag_serialnr(const struct tag *tag)
7131da177e4SLinus Torvalds {
7141da177e4SLinus Torvalds 	system_serial_low = tag->u.serialnr.low;
7151da177e4SLinus Torvalds 	system_serial_high = tag->u.serialnr.high;
7161da177e4SLinus Torvalds 	return 0;
7171da177e4SLinus Torvalds }
7181da177e4SLinus Torvalds 
7191da177e4SLinus Torvalds __tagtable(ATAG_SERIAL, parse_tag_serialnr);
7201da177e4SLinus Torvalds 
7211da177e4SLinus Torvalds static int __init parse_tag_revision(const struct tag *tag)
7221da177e4SLinus Torvalds {
7231da177e4SLinus Torvalds 	system_rev = tag->u.revision.rev;
7241da177e4SLinus Torvalds 	return 0;
7251da177e4SLinus Torvalds }
7261da177e4SLinus Torvalds 
7271da177e4SLinus Torvalds __tagtable(ATAG_REVISION, parse_tag_revision);
7281da177e4SLinus Torvalds 
7291da177e4SLinus Torvalds static int __init parse_tag_cmdline(const struct tag *tag)
7301da177e4SLinus Torvalds {
7314394c124SVictor Boivie #if defined(CONFIG_CMDLINE_EXTEND)
7324394c124SVictor Boivie 	strlcat(default_command_line, " ", COMMAND_LINE_SIZE);
7334394c124SVictor Boivie 	strlcat(default_command_line, tag->u.cmdline.cmdline,
7344394c124SVictor Boivie 		COMMAND_LINE_SIZE);
7354394c124SVictor Boivie #elif defined(CONFIG_CMDLINE_FORCE)
73622eeb8f6SAlexander Holler 	pr_warning("Ignoring tag cmdline (using the default kernel command line)\n");
7374394c124SVictor Boivie #else
7384394c124SVictor Boivie 	strlcpy(default_command_line, tag->u.cmdline.cmdline,
7394394c124SVictor Boivie 		COMMAND_LINE_SIZE);
7404394c124SVictor Boivie #endif
7411da177e4SLinus Torvalds 	return 0;
7421da177e4SLinus Torvalds }
7431da177e4SLinus Torvalds 
7441da177e4SLinus Torvalds __tagtable(ATAG_CMDLINE, parse_tag_cmdline);
7451da177e4SLinus Torvalds 
7461da177e4SLinus Torvalds /*
7471da177e4SLinus Torvalds  * Scan the tag table for this tag, and call its parse function.
7481da177e4SLinus Torvalds  * The tag table is built by the linker from all the __tagtable
7491da177e4SLinus Torvalds  * declarations.
7501da177e4SLinus Torvalds  */
7511da177e4SLinus Torvalds static int __init parse_tag(const struct tag *tag)
7521da177e4SLinus Torvalds {
7531da177e4SLinus Torvalds 	extern struct tagtable __tagtable_begin, __tagtable_end;
7541da177e4SLinus Torvalds 	struct tagtable *t;
7551da177e4SLinus Torvalds 
7561da177e4SLinus Torvalds 	for (t = &__tagtable_begin; t < &__tagtable_end; t++)
7571da177e4SLinus Torvalds 		if (tag->hdr.tag == t->tag) {
7581da177e4SLinus Torvalds 			t->parse(tag);
7591da177e4SLinus Torvalds 			break;
7601da177e4SLinus Torvalds 		}
7611da177e4SLinus Torvalds 
7621da177e4SLinus Torvalds 	return t < &__tagtable_end;
7631da177e4SLinus Torvalds }
7641da177e4SLinus Torvalds 
7651da177e4SLinus Torvalds /*
7661da177e4SLinus Torvalds  * Parse all tags in the list, checking both the global and architecture
7671da177e4SLinus Torvalds  * specific tag tables.
7681da177e4SLinus Torvalds  */
7691da177e4SLinus Torvalds static void __init parse_tags(const struct tag *t)
7701da177e4SLinus Torvalds {
7711da177e4SLinus Torvalds 	for (; t->hdr.size; t = tag_next(t))
7721da177e4SLinus Torvalds 		if (!parse_tag(t))
7731da177e4SLinus Torvalds 			printk(KERN_WARNING
7741da177e4SLinus Torvalds 				"Ignoring unrecognised tag 0x%08x\n",
7751da177e4SLinus Torvalds 				t->hdr.tag);
7761da177e4SLinus Torvalds }
7771da177e4SLinus Torvalds 
7781da177e4SLinus Torvalds /*
7791da177e4SLinus Torvalds  * This holds our defaults.
7801da177e4SLinus Torvalds  */
7811da177e4SLinus Torvalds static struct init_tags {
7821da177e4SLinus Torvalds 	struct tag_header hdr1;
7831da177e4SLinus Torvalds 	struct tag_core   core;
7841da177e4SLinus Torvalds 	struct tag_header hdr2;
7851da177e4SLinus Torvalds 	struct tag_mem32  mem;
7861da177e4SLinus Torvalds 	struct tag_header hdr3;
7871da177e4SLinus Torvalds } init_tags __initdata = {
7881da177e4SLinus Torvalds 	{ tag_size(tag_core), ATAG_CORE },
7891da177e4SLinus Torvalds 	{ 1, PAGE_SIZE, 0xff },
7901da177e4SLinus Torvalds 	{ tag_size(tag_mem32), ATAG_MEM },
791b75c178aSRussell King 	{ MEM_SIZE },
7921da177e4SLinus Torvalds 	{ 0, ATAG_NONE }
7931da177e4SLinus Torvalds };
7941da177e4SLinus Torvalds 
7951da177e4SLinus Torvalds static int __init customize_machine(void)
7961da177e4SLinus Torvalds {
7971da177e4SLinus Torvalds 	/* customizes platform devices, or adds new ones */
7988ff1443cSRussell King 	if (machine_desc->init_machine)
7998ff1443cSRussell King 		machine_desc->init_machine();
8001da177e4SLinus Torvalds 	return 0;
8011da177e4SLinus Torvalds }
8021da177e4SLinus Torvalds arch_initcall(customize_machine);
8031da177e4SLinus Torvalds 
80490de4137SShawn Guo static int __init init_machine_late(void)
80590de4137SShawn Guo {
80690de4137SShawn Guo 	if (machine_desc->init_late)
80790de4137SShawn Guo 		machine_desc->init_late();
80890de4137SShawn Guo 	return 0;
80990de4137SShawn Guo }
81090de4137SShawn Guo late_initcall(init_machine_late);
81190de4137SShawn Guo 
8123c57fb43SMika Westerberg #ifdef CONFIG_KEXEC
8133c57fb43SMika Westerberg static inline unsigned long long get_total_mem(void)
8143c57fb43SMika Westerberg {
8153c57fb43SMika Westerberg 	unsigned long total;
8163c57fb43SMika Westerberg 
8173c57fb43SMika Westerberg 	total = max_low_pfn - min_low_pfn;
8183c57fb43SMika Westerberg 	return total << PAGE_SHIFT;
8193c57fb43SMika Westerberg }
8203c57fb43SMika Westerberg 
8213c57fb43SMika Westerberg /**
8223c57fb43SMika Westerberg  * reserve_crashkernel() - reserves memory are for crash kernel
8233c57fb43SMika Westerberg  *
8243c57fb43SMika Westerberg  * This function reserves memory area given in "crashkernel=" kernel command
8253c57fb43SMika Westerberg  * line parameter. The memory reserved is used by a dump capture kernel when
8263c57fb43SMika Westerberg  * primary kernel is crashing.
8273c57fb43SMika Westerberg  */
8283c57fb43SMika Westerberg static void __init reserve_crashkernel(void)
8293c57fb43SMika Westerberg {
8303c57fb43SMika Westerberg 	unsigned long long crash_size, crash_base;
8313c57fb43SMika Westerberg 	unsigned long long total_mem;
8323c57fb43SMika Westerberg 	int ret;
8333c57fb43SMika Westerberg 
8343c57fb43SMika Westerberg 	total_mem = get_total_mem();
8353c57fb43SMika Westerberg 	ret = parse_crashkernel(boot_command_line, total_mem,
8363c57fb43SMika Westerberg 				&crash_size, &crash_base);
8373c57fb43SMika Westerberg 	if (ret)
8383c57fb43SMika Westerberg 		return;
8393c57fb43SMika Westerberg 
8403c57fb43SMika Westerberg 	ret = reserve_bootmem(crash_base, crash_size, BOOTMEM_EXCLUSIVE);
8413c57fb43SMika Westerberg 	if (ret < 0) {
8423c57fb43SMika Westerberg 		printk(KERN_WARNING "crashkernel reservation failed - "
8433c57fb43SMika Westerberg 		       "memory is in use (0x%lx)\n", (unsigned long)crash_base);
8443c57fb43SMika Westerberg 		return;
8453c57fb43SMika Westerberg 	}
8463c57fb43SMika Westerberg 
8473c57fb43SMika Westerberg 	printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
8483c57fb43SMika Westerberg 	       "for crashkernel (System RAM: %ldMB)\n",
8493c57fb43SMika Westerberg 	       (unsigned long)(crash_size >> 20),
8503c57fb43SMika Westerberg 	       (unsigned long)(crash_base >> 20),
8513c57fb43SMika Westerberg 	       (unsigned long)(total_mem >> 20));
8523c57fb43SMika Westerberg 
8533c57fb43SMika Westerberg 	crashk_res.start = crash_base;
8543c57fb43SMika Westerberg 	crashk_res.end = crash_base + crash_size - 1;
8553c57fb43SMika Westerberg 	insert_resource(&iomem_resource, &crashk_res);
8563c57fb43SMika Westerberg }
8573c57fb43SMika Westerberg #else
8583c57fb43SMika Westerberg static inline void reserve_crashkernel(void) {}
8593c57fb43SMika Westerberg #endif /* CONFIG_KEXEC */
8603c57fb43SMika Westerberg 
86173a65b3fSUwe Kleine-König static void __init squash_mem_tags(struct tag *tag)
86273a65b3fSUwe Kleine-König {
86373a65b3fSUwe Kleine-König 	for (; tag->hdr.size; tag = tag_next(tag))
86473a65b3fSUwe Kleine-König 		if (tag->hdr.tag == ATAG_MEM)
86573a65b3fSUwe Kleine-König 			tag->hdr.tag = ATAG_NONE;
86673a65b3fSUwe Kleine-König }
86773a65b3fSUwe Kleine-König 
8686291319dSGrant Likely static struct machine_desc * __init setup_machine_tags(unsigned int nr)
8691da177e4SLinus Torvalds {
8701da177e4SLinus Torvalds 	struct tag *tags = (struct tag *)&init_tags;
8716291319dSGrant Likely 	struct machine_desc *mdesc = NULL, *p;
8721da177e4SLinus Torvalds 	char *from = default_command_line;
8731da177e4SLinus Torvalds 
874b75c178aSRussell King 	init_tags.mem.start = PHYS_OFFSET;
875b75c178aSRussell King 
8766291319dSGrant Likely 	/*
8776291319dSGrant Likely 	 * locate machine in the list of supported machines.
8786291319dSGrant Likely 	 */
8796291319dSGrant Likely 	for_each_machine_desc(p)
8806291319dSGrant Likely 		if (nr == p->nr) {
8816291319dSGrant Likely 			printk("Machine: %s\n", p->name);
8826291319dSGrant Likely 			mdesc = p;
8836291319dSGrant Likely 			break;
8846291319dSGrant Likely 		}
885bff595c1SCatalin Marinas 
8866291319dSGrant Likely 	if (!mdesc) {
8876291319dSGrant Likely 		early_print("\nError: unrecognized/unsupported machine ID"
8886291319dSGrant Likely 			" (r1 = 0x%08x).\n\n", nr);
8896291319dSGrant Likely 		dump_machine_table(); /* does not return */
8906291319dSGrant Likely 	}
8911da177e4SLinus Torvalds 
8929d20fdd5SBill Gatliff 	if (__atags_pointer)
8939d20fdd5SBill Gatliff 		tags = phys_to_virt(__atags_pointer);
8942bb9839eSNicolas Pitre 	else if (mdesc->atag_offset)
8952bb9839eSNicolas Pitre 		tags = (void *)(PAGE_OFFSET + mdesc->atag_offset);
8961da177e4SLinus Torvalds 
89773a65b3fSUwe Kleine-König #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
8981da177e4SLinus Torvalds 	/*
8991da177e4SLinus Torvalds 	 * If we have the old style parameters, convert them to
9001da177e4SLinus Torvalds 	 * a tag list.
9011da177e4SLinus Torvalds 	 */
9021da177e4SLinus Torvalds 	if (tags->hdr.tag != ATAG_CORE)
9031da177e4SLinus Torvalds 		convert_to_tag_list(tags);
90473a65b3fSUwe Kleine-König #endif
90593c02ab4SGrant Likely 
90693c02ab4SGrant Likely 	if (tags->hdr.tag != ATAG_CORE) {
90793c02ab4SGrant Likely #if defined(CONFIG_OF)
90893c02ab4SGrant Likely 		/*
90993c02ab4SGrant Likely 		 * If CONFIG_OF is set, then assume this is a reasonably
91093c02ab4SGrant Likely 		 * modern system that should pass boot parameters
91193c02ab4SGrant Likely 		 */
91293c02ab4SGrant Likely 		early_print("Warning: Neither atags nor dtb found\n");
91393c02ab4SGrant Likely #endif
9141da177e4SLinus Torvalds 		tags = (struct tag *)&init_tags;
91593c02ab4SGrant Likely 	}
9161da177e4SLinus Torvalds 
9171da177e4SLinus Torvalds 	if (mdesc->fixup)
9180744a3eeSRussell King 		mdesc->fixup(tags, &from, &meminfo);
9191da177e4SLinus Torvalds 
9201da177e4SLinus Torvalds 	if (tags->hdr.tag == ATAG_CORE) {
9211da177e4SLinus Torvalds 		if (meminfo.nr_banks != 0)
9221da177e4SLinus Torvalds 			squash_mem_tags(tags);
9234cd9d6f7SRichard Purdie 		save_atags(tags);
9241da177e4SLinus Torvalds 		parse_tags(tags);
9251da177e4SLinus Torvalds 	}
9261da177e4SLinus Torvalds 
9276291319dSGrant Likely 	/* parse_early_param needs a boot_command_line */
9286291319dSGrant Likely 	strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
9296291319dSGrant Likely 
9306291319dSGrant Likely 	return mdesc;
9316291319dSGrant Likely }
9326291319dSGrant Likely 
93327a3f0e9SNicolas Pitre static int __init meminfo_cmp(const void *_a, const void *_b)
93427a3f0e9SNicolas Pitre {
93527a3f0e9SNicolas Pitre 	const struct membank *a = _a, *b = _b;
93627a3f0e9SNicolas Pitre 	long cmp = bank_pfn_start(a) - bank_pfn_start(b);
93727a3f0e9SNicolas Pitre 	return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
93827a3f0e9SNicolas Pitre }
9396291319dSGrant Likely 
9406291319dSGrant Likely void __init setup_arch(char **cmdline_p)
9416291319dSGrant Likely {
9426291319dSGrant Likely 	struct machine_desc *mdesc;
9436291319dSGrant Likely 
9446291319dSGrant Likely 	setup_processor();
94593c02ab4SGrant Likely 	mdesc = setup_machine_fdt(__atags_pointer);
94693c02ab4SGrant Likely 	if (!mdesc)
9476291319dSGrant Likely 		mdesc = setup_machine_tags(machine_arch_type);
9486291319dSGrant Likely 	machine_desc = mdesc;
9496291319dSGrant Likely 	machine_name = mdesc->name;
9506291319dSGrant Likely 
951c7909509SMarek Szyprowski 	setup_dma_zone(mdesc);
952c7909509SMarek Szyprowski 
953b44c350dSRussell King 	if (mdesc->restart_mode)
954b44c350dSRussell King 		reboot_setup(&mdesc->restart_mode);
9556291319dSGrant Likely 
95637efe642SRussell King 	init_mm.start_code = (unsigned long) _text;
95737efe642SRussell King 	init_mm.end_code   = (unsigned long) _etext;
95837efe642SRussell King 	init_mm.end_data   = (unsigned long) _edata;
95937efe642SRussell King 	init_mm.brk	   = (unsigned long) _end;
9601da177e4SLinus Torvalds 
96148ab7e09SJeremy Kerr 	/* populate cmd_line too for later use, preserving boot_command_line */
96248ab7e09SJeremy Kerr 	strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
96348ab7e09SJeremy Kerr 	*cmdline_p = cmd_line;
9642b0d8c25SJeremy Kerr 
9652b0d8c25SJeremy Kerr 	parse_early_param();
9662b0d8c25SJeremy Kerr 
96727a3f0e9SNicolas Pitre 	sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL);
9680371d3f7SRussell King 	sanity_check_meminfo();
9698d717a52SRussell King 	arm_memblock_init(&meminfo, mdesc);
9702778f620SRussell King 
9714b5f32ceSNicolas Pitre 	paging_init(mdesc);
97211b9369cSDima Zavin 	request_standard_resources(mdesc);
9731da177e4SLinus Torvalds 
974a528721dSRussell King 	if (mdesc->restart)
975a528721dSRussell King 		arm_pm_restart = mdesc->restart;
976a528721dSRussell King 
97793c02ab4SGrant Likely 	unflatten_device_tree();
97893c02ab4SGrant Likely 
9797bbb7940SRussell King #ifdef CONFIG_SMP
980f00ec48fSRussell King 	if (is_smp())
9817bbb7940SRussell King 		smp_init_cpus();
9827bbb7940SRussell King #endif
9833c57fb43SMika Westerberg 	reserve_crashkernel();
9847bbb7940SRussell King 
985bc581770SLinus Walleij 	tcm_init();
986ccea7a19SRussell King 
98752108641Seric miao #ifdef CONFIG_MULTI_IRQ_HANDLER
98852108641Seric miao 	handle_arch_irq = mdesc->handle_irq;
98952108641Seric miao #endif
9901da177e4SLinus Torvalds 
9911da177e4SLinus Torvalds #ifdef CONFIG_VT
9921da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE)
9931da177e4SLinus Torvalds 	conswitchp = &vga_con;
9941da177e4SLinus Torvalds #elif defined(CONFIG_DUMMY_CONSOLE)
9951da177e4SLinus Torvalds 	conswitchp = &dummy_con;
9961da177e4SLinus Torvalds #endif
9971da177e4SLinus Torvalds #endif
998dec12e62SRussell King 
999dec12e62SRussell King 	if (mdesc->init_early)
1000dec12e62SRussell King 		mdesc->init_early();
10011da177e4SLinus Torvalds }
10021da177e4SLinus Torvalds 
10031da177e4SLinus Torvalds 
10041da177e4SLinus Torvalds static int __init topology_init(void)
10051da177e4SLinus Torvalds {
10061da177e4SLinus Torvalds 	int cpu;
10071da177e4SLinus Torvalds 
100866fb8bd2SRussell King 	for_each_possible_cpu(cpu) {
100966fb8bd2SRussell King 		struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu);
101066fb8bd2SRussell King 		cpuinfo->cpu.hotpluggable = 1;
101166fb8bd2SRussell King 		register_cpu(&cpuinfo->cpu, cpu);
101266fb8bd2SRussell King 	}
10131da177e4SLinus Torvalds 
10141da177e4SLinus Torvalds 	return 0;
10151da177e4SLinus Torvalds }
10161da177e4SLinus Torvalds subsys_initcall(topology_init);
10171da177e4SLinus Torvalds 
1018e119bfffSRussell King #ifdef CONFIG_HAVE_PROC_CPU
1019e119bfffSRussell King static int __init proc_cpu_init(void)
1020e119bfffSRussell King {
1021e119bfffSRussell King 	struct proc_dir_entry *res;
1022e119bfffSRussell King 
1023e119bfffSRussell King 	res = proc_mkdir("cpu", NULL);
1024e119bfffSRussell King 	if (!res)
1025e119bfffSRussell King 		return -ENOMEM;
1026e119bfffSRussell King 	return 0;
1027e119bfffSRussell King }
1028e119bfffSRussell King fs_initcall(proc_cpu_init);
1029e119bfffSRussell King #endif
1030e119bfffSRussell King 
10311da177e4SLinus Torvalds static const char *hwcap_str[] = {
10321da177e4SLinus Torvalds 	"swp",
10331da177e4SLinus Torvalds 	"half",
10341da177e4SLinus Torvalds 	"thumb",
10351da177e4SLinus Torvalds 	"26bit",
10361da177e4SLinus Torvalds 	"fastmult",
10371da177e4SLinus Torvalds 	"fpa",
10381da177e4SLinus Torvalds 	"vfp",
10391da177e4SLinus Torvalds 	"edsp",
10401da177e4SLinus Torvalds 	"java",
10418f7f9435SPaul Gortmaker 	"iwmmxt",
104299e4a6ddSLennert Buytenhek 	"crunch",
10434369ae16SCatalin Marinas 	"thumbee",
10442bedbdf4SCatalin Marinas 	"neon",
10457279dc3eSCatalin Marinas 	"vfpv3",
10467279dc3eSCatalin Marinas 	"vfpv3d16",
1047254cdf8eSWill Deacon 	"tls",
1048254cdf8eSWill Deacon 	"vfpv4",
1049254cdf8eSWill Deacon 	"idiva",
1050254cdf8eSWill Deacon 	"idivt",
10511da177e4SLinus Torvalds 	NULL
10521da177e4SLinus Torvalds };
10531da177e4SLinus Torvalds 
10541da177e4SLinus Torvalds static int c_show(struct seq_file *m, void *v)
10551da177e4SLinus Torvalds {
10561da177e4SLinus Torvalds 	int i;
10571da177e4SLinus Torvalds 
10581da177e4SLinus Torvalds 	seq_printf(m, "Processor\t: %s rev %d (%s)\n",
10590ba8b9b2SRussell King 		   cpu_name, read_cpuid_id() & 15, elf_platform);
10601da177e4SLinus Torvalds 
10611da177e4SLinus Torvalds #if defined(CONFIG_SMP)
10621da177e4SLinus Torvalds 	for_each_online_cpu(i) {
106315559722SRussell King 		/*
106415559722SRussell King 		 * glibc reads /proc/cpuinfo to determine the number of
106515559722SRussell King 		 * online processors, looking for lines beginning with
106615559722SRussell King 		 * "processor".  Give glibc what it expects.
106715559722SRussell King 		 */
106815559722SRussell King 		seq_printf(m, "processor\t: %d\n", i);
10691da177e4SLinus Torvalds 		seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
10701da177e4SLinus Torvalds 			   per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
10711da177e4SLinus Torvalds 			   (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
10721da177e4SLinus Torvalds 	}
10731da177e4SLinus Torvalds #else /* CONFIG_SMP */
10741da177e4SLinus Torvalds 	seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
10751da177e4SLinus Torvalds 		   loops_per_jiffy / (500000/HZ),
10761da177e4SLinus Torvalds 		   (loops_per_jiffy / (5000/HZ)) % 100);
10771da177e4SLinus Torvalds #endif
10781da177e4SLinus Torvalds 
10791da177e4SLinus Torvalds 	/* dump out the processor features */
10801da177e4SLinus Torvalds 	seq_puts(m, "Features\t: ");
10811da177e4SLinus Torvalds 
10821da177e4SLinus Torvalds 	for (i = 0; hwcap_str[i]; i++)
10831da177e4SLinus Torvalds 		if (elf_hwcap & (1 << i))
10841da177e4SLinus Torvalds 			seq_printf(m, "%s ", hwcap_str[i]);
10851da177e4SLinus Torvalds 
10860ba8b9b2SRussell King 	seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
10871da177e4SLinus Torvalds 	seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]);
10881da177e4SLinus Torvalds 
10890ba8b9b2SRussell King 	if ((read_cpuid_id() & 0x0008f000) == 0x00000000) {
10901da177e4SLinus Torvalds 		/* pre-ARM7 */
10910ba8b9b2SRussell King 		seq_printf(m, "CPU part\t: %07x\n", read_cpuid_id() >> 4);
10921da177e4SLinus Torvalds 	} else {
10930ba8b9b2SRussell King 		if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
10941da177e4SLinus Torvalds 			/* ARM7 */
10951da177e4SLinus Torvalds 			seq_printf(m, "CPU variant\t: 0x%02x\n",
10960ba8b9b2SRussell King 				   (read_cpuid_id() >> 16) & 127);
10971da177e4SLinus Torvalds 		} else {
10981da177e4SLinus Torvalds 			/* post-ARM7 */
10991da177e4SLinus Torvalds 			seq_printf(m, "CPU variant\t: 0x%x\n",
11000ba8b9b2SRussell King 				   (read_cpuid_id() >> 20) & 15);
11011da177e4SLinus Torvalds 		}
11021da177e4SLinus Torvalds 		seq_printf(m, "CPU part\t: 0x%03x\n",
11030ba8b9b2SRussell King 			   (read_cpuid_id() >> 4) & 0xfff);
11041da177e4SLinus Torvalds 	}
11050ba8b9b2SRussell King 	seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);
11061da177e4SLinus Torvalds 
11071da177e4SLinus Torvalds 	seq_puts(m, "\n");
11081da177e4SLinus Torvalds 
11091da177e4SLinus Torvalds 	seq_printf(m, "Hardware\t: %s\n", machine_name);
11101da177e4SLinus Torvalds 	seq_printf(m, "Revision\t: %04x\n", system_rev);
11111da177e4SLinus Torvalds 	seq_printf(m, "Serial\t\t: %08x%08x\n",
11121da177e4SLinus Torvalds 		   system_serial_high, system_serial_low);
11131da177e4SLinus Torvalds 
11141da177e4SLinus Torvalds 	return 0;
11151da177e4SLinus Torvalds }
11161da177e4SLinus Torvalds 
11171da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos)
11181da177e4SLinus Torvalds {
11191da177e4SLinus Torvalds 	return *pos < 1 ? (void *)1 : NULL;
11201da177e4SLinus Torvalds }
11211da177e4SLinus Torvalds 
11221da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos)
11231da177e4SLinus Torvalds {
11241da177e4SLinus Torvalds 	++*pos;
11251da177e4SLinus Torvalds 	return NULL;
11261da177e4SLinus Torvalds }
11271da177e4SLinus Torvalds 
11281da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v)
11291da177e4SLinus Torvalds {
11301da177e4SLinus Torvalds }
11311da177e4SLinus Torvalds 
11322ffd6e18SJan Engelhardt const struct seq_operations cpuinfo_op = {
11331da177e4SLinus Torvalds 	.start	= c_start,
11341da177e4SLinus Torvalds 	.next	= c_next,
11351da177e4SLinus Torvalds 	.stop	= c_stop,
11361da177e4SLinus Torvalds 	.show	= c_show
11371da177e4SLinus Torvalds };
1138