xref: /openbmc/linux/arch/arm/kernel/setup.c (revision eb50439b)
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>
361da177e4SLinus Torvalds #include <asm/cpu.h>
370ba8b9b2SRussell King #include <asm/cputype.h>
381da177e4SLinus Torvalds #include <asm/elf.h>
391da177e4SLinus Torvalds #include <asm/procinfo.h>
4037efe642SRussell King #include <asm/sections.h>
411da177e4SLinus Torvalds #include <asm/setup.h>
42f00ec48fSRussell King #include <asm/smp_plat.h>
431da177e4SLinus Torvalds #include <asm/mach-types.h>
441da177e4SLinus Torvalds #include <asm/cacheflush.h>
4546097c7dSRussell King #include <asm/cachetype.h>
461da177e4SLinus Torvalds #include <asm/tlbflush.h>
472ecccf90SDave Martin #include <asm/system.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>
535cbad0ebSJason Wessel #include <asm/traps.h>
54bff595c1SCatalin Marinas #include <asm/unwind.h>
551c16d242STejun Heo #include <asm/memblock.h>
561da177e4SLinus Torvalds 
5773a65b3fSUwe Kleine-König #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
580fc1c832SBen Dooks #include "compat.h"
5973a65b3fSUwe Kleine-König #endif
604cd9d6f7SRichard Purdie #include "atags.h"
61bc581770SLinus Walleij #include "tcm.h"
620fc1c832SBen Dooks 
631da177e4SLinus Torvalds #ifndef MEM_SIZE
641da177e4SLinus Torvalds #define MEM_SIZE	(16*1024*1024)
651da177e4SLinus Torvalds #endif
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
681da177e4SLinus Torvalds char fpe_type[8];
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds static int __init fpe_setup(char *line)
711da177e4SLinus Torvalds {
721da177e4SLinus Torvalds 	memcpy(fpe_type, line, 8);
731da177e4SLinus Torvalds 	return 1;
741da177e4SLinus Torvalds }
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds __setup("fpe=", fpe_setup);
771da177e4SLinus Torvalds #endif
781da177e4SLinus Torvalds 
794b5f32ceSNicolas Pitre extern void paging_init(struct machine_desc *desc);
800371d3f7SRussell King extern void sanity_check_meminfo(void);
811da177e4SLinus Torvalds extern void reboot_setup(char *str);
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds unsigned int processor_id;
84c18f6581SKrzysztof Halasa EXPORT_SYMBOL(processor_id);
850385ebc0SRussell King unsigned int __machine_arch_type __read_mostly;
861da177e4SLinus Torvalds EXPORT_SYMBOL(__machine_arch_type);
870385ebc0SRussell King unsigned int cacheid __read_mostly;
88c0e95878SRussell King EXPORT_SYMBOL(cacheid);
891da177e4SLinus Torvalds 
909d20fdd5SBill Gatliff unsigned int __atags_pointer __initdata;
919d20fdd5SBill Gatliff 
921da177e4SLinus Torvalds unsigned int system_rev;
931da177e4SLinus Torvalds EXPORT_SYMBOL(system_rev);
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds unsigned int system_serial_low;
961da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_low);
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds unsigned int system_serial_high;
991da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_high);
1001da177e4SLinus Torvalds 
1010385ebc0SRussell King unsigned int elf_hwcap __read_mostly;
1021da177e4SLinus Torvalds EXPORT_SYMBOL(elf_hwcap);
1031da177e4SLinus Torvalds 
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds #ifdef MULTI_CPU
1060385ebc0SRussell King struct processor processor __read_mostly;
1071da177e4SLinus Torvalds #endif
1081da177e4SLinus Torvalds #ifdef MULTI_TLB
1090385ebc0SRussell King struct cpu_tlb_fns cpu_tlb __read_mostly;
1101da177e4SLinus Torvalds #endif
1111da177e4SLinus Torvalds #ifdef MULTI_USER
1120385ebc0SRussell King struct cpu_user_fns cpu_user __read_mostly;
1131da177e4SLinus Torvalds #endif
1141da177e4SLinus Torvalds #ifdef MULTI_CACHE
1150385ebc0SRussell King struct cpu_cache_fns cpu_cache __read_mostly;
1161da177e4SLinus Torvalds #endif
117953233dcSCatalin Marinas #ifdef CONFIG_OUTER_CACHE
1180385ebc0SRussell King struct outer_cache_fns outer_cache __read_mostly;
1196c09f09dSSantosh Shilimkar EXPORT_SYMBOL(outer_cache);
120953233dcSCatalin Marinas #endif
1211da177e4SLinus Torvalds 
1222ecccf90SDave Martin /*
1232ecccf90SDave Martin  * Cached cpu_architecture() result for use by assembler code.
1242ecccf90SDave Martin  * C code should use the cpu_architecture() function instead of accessing this
1252ecccf90SDave Martin  * variable directly.
1262ecccf90SDave Martin  */
1272ecccf90SDave Martin int __cpu_architecture __read_mostly = CPU_ARCH_UNKNOWN;
1282ecccf90SDave Martin 
129ccea7a19SRussell King struct stack {
130ccea7a19SRussell King 	u32 irq[3];
131ccea7a19SRussell King 	u32 abt[3];
132ccea7a19SRussell King 	u32 und[3];
133ccea7a19SRussell King } ____cacheline_aligned;
134ccea7a19SRussell King 
135ccea7a19SRussell King static struct stack stacks[NR_CPUS];
136ccea7a19SRussell King 
1371da177e4SLinus Torvalds char elf_platform[ELF_PLATFORM_SIZE];
1381da177e4SLinus Torvalds EXPORT_SYMBOL(elf_platform);
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds static const char *cpu_name;
1411da177e4SLinus Torvalds static const char *machine_name;
14248ab7e09SJeremy Kerr static char __initdata cmd_line[COMMAND_LINE_SIZE];
1438ff1443cSRussell King struct machine_desc *machine_desc __initdata;
1441da177e4SLinus Torvalds 
1451da177e4SLinus Torvalds static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
1461da177e4SLinus Torvalds static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
1471da177e4SLinus Torvalds #define ENDIANNESS ((char)endian_test.l)
1481da177e4SLinus Torvalds 
1491da177e4SLinus Torvalds DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
1501da177e4SLinus Torvalds 
1511da177e4SLinus Torvalds /*
1521da177e4SLinus Torvalds  * Standard memory resources
1531da177e4SLinus Torvalds  */
1541da177e4SLinus Torvalds static struct resource mem_res[] = {
155740e518eSGreg Kroah-Hartman 	{
156740e518eSGreg Kroah-Hartman 		.name = "Video RAM",
157740e518eSGreg Kroah-Hartman 		.start = 0,
158740e518eSGreg Kroah-Hartman 		.end = 0,
159740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
160740e518eSGreg Kroah-Hartman 	},
161740e518eSGreg Kroah-Hartman 	{
162a36d8e5bSKees Cook 		.name = "Kernel code",
163740e518eSGreg Kroah-Hartman 		.start = 0,
164740e518eSGreg Kroah-Hartman 		.end = 0,
165740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
166740e518eSGreg Kroah-Hartman 	},
167740e518eSGreg Kroah-Hartman 	{
168740e518eSGreg Kroah-Hartman 		.name = "Kernel data",
169740e518eSGreg Kroah-Hartman 		.start = 0,
170740e518eSGreg Kroah-Hartman 		.end = 0,
171740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
172740e518eSGreg Kroah-Hartman 	}
1731da177e4SLinus Torvalds };
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds #define video_ram   mem_res[0]
1761da177e4SLinus Torvalds #define kernel_code mem_res[1]
1771da177e4SLinus Torvalds #define kernel_data mem_res[2]
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds static struct resource io_res[] = {
180740e518eSGreg Kroah-Hartman 	{
181740e518eSGreg Kroah-Hartman 		.name = "reserved",
182740e518eSGreg Kroah-Hartman 		.start = 0x3bc,
183740e518eSGreg Kroah-Hartman 		.end = 0x3be,
184740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
185740e518eSGreg Kroah-Hartman 	},
186740e518eSGreg Kroah-Hartman 	{
187740e518eSGreg Kroah-Hartman 		.name = "reserved",
188740e518eSGreg Kroah-Hartman 		.start = 0x378,
189740e518eSGreg Kroah-Hartman 		.end = 0x37f,
190740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
191740e518eSGreg Kroah-Hartman 	},
192740e518eSGreg Kroah-Hartman 	{
193740e518eSGreg Kroah-Hartman 		.name = "reserved",
194740e518eSGreg Kroah-Hartman 		.start = 0x278,
195740e518eSGreg Kroah-Hartman 		.end = 0x27f,
196740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
197740e518eSGreg Kroah-Hartman 	}
1981da177e4SLinus Torvalds };
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds #define lp0 io_res[0]
2011da177e4SLinus Torvalds #define lp1 io_res[1]
2021da177e4SLinus Torvalds #define lp2 io_res[2]
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds static const char *proc_arch[] = {
2051da177e4SLinus Torvalds 	"undefined/unknown",
2061da177e4SLinus Torvalds 	"3",
2071da177e4SLinus Torvalds 	"4",
2081da177e4SLinus Torvalds 	"4T",
2091da177e4SLinus Torvalds 	"5",
2101da177e4SLinus Torvalds 	"5T",
2111da177e4SLinus Torvalds 	"5TE",
2121da177e4SLinus Torvalds 	"5TEJ",
2131da177e4SLinus Torvalds 	"6TEJ",
2146b090a25SCatalin Marinas 	"7",
2151da177e4SLinus Torvalds 	"?(11)",
2161da177e4SLinus Torvalds 	"?(12)",
2171da177e4SLinus Torvalds 	"?(13)",
2181da177e4SLinus Torvalds 	"?(14)",
2191da177e4SLinus Torvalds 	"?(15)",
2201da177e4SLinus Torvalds 	"?(16)",
2211da177e4SLinus Torvalds 	"?(17)",
2221da177e4SLinus Torvalds };
2231da177e4SLinus Torvalds 
2242ecccf90SDave Martin static int __get_cpu_architecture(void)
2251da177e4SLinus Torvalds {
2261da177e4SLinus Torvalds 	int cpu_arch;
2271da177e4SLinus Torvalds 
2280ba8b9b2SRussell King 	if ((read_cpuid_id() & 0x0008f000) == 0) {
2291da177e4SLinus Torvalds 		cpu_arch = CPU_ARCH_UNKNOWN;
2300ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
2310ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
2320ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x00080000) == 0x00000000) {
2330ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() >> 16) & 7;
2341da177e4SLinus Torvalds 		if (cpu_arch)
2351da177e4SLinus Torvalds 			cpu_arch += CPU_ARCH_ARMv3;
2360ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
237180005c4SCatalin Marinas 		unsigned int mmfr0;
238180005c4SCatalin Marinas 
239180005c4SCatalin Marinas 		/* Revised CPUID format. Read the Memory Model Feature
240180005c4SCatalin Marinas 		 * Register 0 and check for VMSAv7 or PMSAv7 */
241180005c4SCatalin Marinas 		asm("mrc	p15, 0, %0, c0, c1, 4"
242180005c4SCatalin Marinas 		    : "=r" (mmfr0));
243315cfe78SCatalin Marinas 		if ((mmfr0 & 0x0000000f) >= 0x00000003 ||
244315cfe78SCatalin Marinas 		    (mmfr0 & 0x000000f0) >= 0x00000030)
245180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv7;
246180005c4SCatalin Marinas 		else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
247180005c4SCatalin Marinas 			 (mmfr0 & 0x000000f0) == 0x00000020)
248180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv6;
249180005c4SCatalin Marinas 		else
250180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_UNKNOWN;
251180005c4SCatalin Marinas 	} else
252180005c4SCatalin Marinas 		cpu_arch = CPU_ARCH_UNKNOWN;
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds 	return cpu_arch;
2551da177e4SLinus Torvalds }
2561da177e4SLinus Torvalds 
2572ecccf90SDave Martin int __pure cpu_architecture(void)
2582ecccf90SDave Martin {
2592ecccf90SDave Martin 	BUG_ON(__cpu_architecture == CPU_ARCH_UNKNOWN);
2602ecccf90SDave Martin 
2612ecccf90SDave Martin 	return __cpu_architecture;
2622ecccf90SDave Martin }
2632ecccf90SDave Martin 
2648925ec4cSWill Deacon static int cpu_has_aliasing_icache(unsigned int arch)
2658925ec4cSWill Deacon {
2668925ec4cSWill Deacon 	int aliasing_icache;
2678925ec4cSWill Deacon 	unsigned int id_reg, num_sets, line_size;
2688925ec4cSWill Deacon 
2697f94e9ccSWill Deacon 	/* PIPT caches never alias. */
2707f94e9ccSWill Deacon 	if (icache_is_pipt())
2717f94e9ccSWill Deacon 		return 0;
2727f94e9ccSWill Deacon 
2738925ec4cSWill Deacon 	/* arch specifies the register format */
2748925ec4cSWill Deacon 	switch (arch) {
2758925ec4cSWill Deacon 	case CPU_ARCH_ARMv7:
2765fb31a96SLinus Walleij 		asm("mcr	p15, 2, %0, c0, c0, 0 @ set CSSELR"
2775fb31a96SLinus Walleij 		    : /* No output operands */
2788925ec4cSWill Deacon 		    : "r" (1));
2795fb31a96SLinus Walleij 		isb();
2805fb31a96SLinus Walleij 		asm("mrc	p15, 1, %0, c0, c0, 0 @ read CCSIDR"
2815fb31a96SLinus Walleij 		    : "=r" (id_reg));
2828925ec4cSWill Deacon 		line_size = 4 << ((id_reg & 0x7) + 2);
2838925ec4cSWill Deacon 		num_sets = ((id_reg >> 13) & 0x7fff) + 1;
2848925ec4cSWill Deacon 		aliasing_icache = (line_size * num_sets) > PAGE_SIZE;
2858925ec4cSWill Deacon 		break;
2868925ec4cSWill Deacon 	case CPU_ARCH_ARMv6:
2878925ec4cSWill Deacon 		aliasing_icache = read_cpuid_cachetype() & (1 << 11);
2888925ec4cSWill Deacon 		break;
2898925ec4cSWill Deacon 	default:
2908925ec4cSWill Deacon 		/* I-cache aliases will be handled by D-cache aliasing code */
2918925ec4cSWill Deacon 		aliasing_icache = 0;
2928925ec4cSWill Deacon 	}
2938925ec4cSWill Deacon 
2948925ec4cSWill Deacon 	return aliasing_icache;
2958925ec4cSWill Deacon }
2968925ec4cSWill Deacon 
297c0e95878SRussell King static void __init cacheid_init(void)
298c0e95878SRussell King {
299c0e95878SRussell King 	unsigned int cachetype = read_cpuid_cachetype();
300c0e95878SRussell King 	unsigned int arch = cpu_architecture();
301c0e95878SRussell King 
302b57ee99fSCatalin Marinas 	if (arch >= CPU_ARCH_ARMv6) {
303b57ee99fSCatalin Marinas 		if ((cachetype & (7 << 29)) == 4 << 29) {
304b57ee99fSCatalin Marinas 			/* ARMv7 register format */
30572dc53acSWill Deacon 			arch = CPU_ARCH_ARMv7;
306c0e95878SRussell King 			cacheid = CACHEID_VIPT_NONALIASING;
3077f94e9ccSWill Deacon 			switch (cachetype & (3 << 14)) {
3087f94e9ccSWill Deacon 			case (1 << 14):
309c0e95878SRussell King 				cacheid |= CACHEID_ASID_TAGGED;
3107f94e9ccSWill Deacon 				break;
3117f94e9ccSWill Deacon 			case (3 << 14):
3127f94e9ccSWill Deacon 				cacheid |= CACHEID_PIPT;
3137f94e9ccSWill Deacon 				break;
3147f94e9ccSWill Deacon 			}
3158925ec4cSWill Deacon 		} else {
31672dc53acSWill Deacon 			arch = CPU_ARCH_ARMv6;
31772dc53acSWill Deacon 			if (cachetype & (1 << 23))
31872dc53acSWill Deacon 				cacheid = CACHEID_VIPT_ALIASING;
31972dc53acSWill Deacon 			else
320c0e95878SRussell King 				cacheid = CACHEID_VIPT_NONALIASING;
3218925ec4cSWill Deacon 		}
32272dc53acSWill Deacon 		if (cpu_has_aliasing_icache(arch))
32372dc53acSWill Deacon 			cacheid |= CACHEID_VIPT_I_ALIASING;
324c0e95878SRussell King 	} else {
325c0e95878SRussell King 		cacheid = CACHEID_VIVT;
326c0e95878SRussell King 	}
3272b4ae1f1SRussell King 
3282b4ae1f1SRussell King 	printk("CPU: %s data cache, %s instruction cache\n",
3292b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
3302b4ae1f1SRussell King 		cache_is_vipt_aliasing() ? "VIPT aliasing" :
3317f94e9ccSWill Deacon 		cache_is_vipt_nonaliasing() ? "PIPT / VIPT nonaliasing" : "unknown",
3322b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
3332b4ae1f1SRussell King 		icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :
3348925ec4cSWill Deacon 		icache_is_vipt_aliasing() ? "VIPT aliasing" :
3357f94e9ccSWill Deacon 		icache_is_pipt() ? "PIPT" :
3362b4ae1f1SRussell King 		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");
337c0e95878SRussell King }
338c0e95878SRussell King 
3391da177e4SLinus Torvalds /*
3401da177e4SLinus Torvalds  * These functions re-use the assembly code in head.S, which
3411da177e4SLinus Torvalds  * already provide the required functionality.
3421da177e4SLinus Torvalds  */
3430f44ba1dSRussell King extern struct proc_info_list *lookup_processor_type(unsigned int);
3446fc31d54SRussell King 
34593c02ab4SGrant Likely void __init early_print(const char *str, ...)
3466fc31d54SRussell King {
3476fc31d54SRussell King 	extern void printascii(const char *);
3486fc31d54SRussell King 	char buf[256];
3496fc31d54SRussell King 	va_list ap;
3506fc31d54SRussell King 
3516fc31d54SRussell King 	va_start(ap, str);
3526fc31d54SRussell King 	vsnprintf(buf, sizeof(buf), str, ap);
3536fc31d54SRussell King 	va_end(ap);
3546fc31d54SRussell King 
3556fc31d54SRussell King #ifdef CONFIG_DEBUG_LL
3566fc31d54SRussell King 	printascii(buf);
3576fc31d54SRussell King #endif
3586fc31d54SRussell King 	printk("%s", buf);
3596fc31d54SRussell King }
3606fc31d54SRussell King 
361f159f4edSTony Lindgren static void __init feat_v6_fixup(void)
362f159f4edSTony Lindgren {
363f159f4edSTony Lindgren 	int id = read_cpuid_id();
364f159f4edSTony Lindgren 
365f159f4edSTony Lindgren 	if ((id & 0xff0f0000) != 0x41070000)
366f159f4edSTony Lindgren 		return;
367f159f4edSTony Lindgren 
368f159f4edSTony Lindgren 	/*
369f159f4edSTony Lindgren 	 * HWCAP_TLS is available only on 1136 r1p0 and later,
370f159f4edSTony Lindgren 	 * see also kuser_get_tls_init.
371f159f4edSTony Lindgren 	 */
372f159f4edSTony Lindgren 	if ((((id >> 4) & 0xfff) == 0xb36) && (((id >> 20) & 3) == 0))
373f159f4edSTony Lindgren 		elf_hwcap &= ~HWCAP_TLS;
374f159f4edSTony Lindgren }
375f159f4edSTony Lindgren 
376b69874e4SRussell King /*
377b69874e4SRussell King  * cpu_init - initialise one CPU.
378b69874e4SRussell King  *
379b69874e4SRussell King  * cpu_init sets up the per-CPU stacks.
380b69874e4SRussell King  */
381b69874e4SRussell King void cpu_init(void)
382b69874e4SRussell King {
383b69874e4SRussell King 	unsigned int cpu = smp_processor_id();
384b69874e4SRussell King 	struct stack *stk = &stacks[cpu];
385b69874e4SRussell King 
386b69874e4SRussell King 	if (cpu >= NR_CPUS) {
387b69874e4SRussell King 		printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);
388b69874e4SRussell King 		BUG();
389b69874e4SRussell King 	}
390b69874e4SRussell King 
391b69874e4SRussell King 	cpu_proc_init();
392b69874e4SRussell King 
393b69874e4SRussell King 	/*
394b69874e4SRussell King 	 * Define the placement constraint for the inline asm directive below.
395b69874e4SRussell King 	 * In Thumb-2, msr with an immediate value is not allowed.
396b69874e4SRussell King 	 */
397b69874e4SRussell King #ifdef CONFIG_THUMB2_KERNEL
398b69874e4SRussell King #define PLC	"r"
399b69874e4SRussell King #else
400b69874e4SRussell King #define PLC	"I"
401b69874e4SRussell King #endif
402b69874e4SRussell King 
403b69874e4SRussell King 	/*
404b69874e4SRussell King 	 * setup stacks for re-entrant exception handlers
405b69874e4SRussell King 	 */
406b69874e4SRussell King 	__asm__ (
407b69874e4SRussell King 	"msr	cpsr_c, %1\n\t"
408b69874e4SRussell King 	"add	r14, %0, %2\n\t"
409b69874e4SRussell King 	"mov	sp, r14\n\t"
410b69874e4SRussell King 	"msr	cpsr_c, %3\n\t"
411b69874e4SRussell King 	"add	r14, %0, %4\n\t"
412b69874e4SRussell King 	"mov	sp, r14\n\t"
413b69874e4SRussell King 	"msr	cpsr_c, %5\n\t"
414b69874e4SRussell King 	"add	r14, %0, %6\n\t"
415b69874e4SRussell King 	"mov	sp, r14\n\t"
416b69874e4SRussell King 	"msr	cpsr_c, %7"
417b69874e4SRussell King 	    :
418b69874e4SRussell King 	    : "r" (stk),
419b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
420b69874e4SRussell King 	      "I" (offsetof(struct stack, irq[0])),
421b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
422b69874e4SRussell King 	      "I" (offsetof(struct stack, abt[0])),
423b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
424b69874e4SRussell King 	      "I" (offsetof(struct stack, und[0])),
425b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
426b69874e4SRussell King 	    : "r14");
427b69874e4SRussell King }
428b69874e4SRussell King 
429eb50439bSWill Deacon int __cpu_logical_map[NR_CPUS];
430eb50439bSWill Deacon 
431eb50439bSWill Deacon void __init smp_setup_processor_id(void)
432eb50439bSWill Deacon {
433eb50439bSWill Deacon 	int i;
434eb50439bSWill Deacon 	u32 cpu = is_smp() ? read_cpuid_mpidr() & 0xff : 0;
435eb50439bSWill Deacon 
436eb50439bSWill Deacon 	cpu_logical_map(0) = cpu;
437eb50439bSWill Deacon 	for (i = 1; i < NR_CPUS; ++i)
438eb50439bSWill Deacon 		cpu_logical_map(i) = i == cpu ? 0 : i;
439eb50439bSWill Deacon 
440eb50439bSWill Deacon 	printk(KERN_INFO "Booting Linux on physical CPU %d\n", cpu);
441eb50439bSWill Deacon }
442eb50439bSWill Deacon 
4431da177e4SLinus Torvalds static void __init setup_processor(void)
4441da177e4SLinus Torvalds {
4451da177e4SLinus Torvalds 	struct proc_info_list *list;
4461da177e4SLinus Torvalds 
4471da177e4SLinus Torvalds 	/*
4481da177e4SLinus Torvalds 	 * locate processor in the list of supported processor
4491da177e4SLinus Torvalds 	 * types.  The linker builds this table for us from the
4501da177e4SLinus Torvalds 	 * entries in arch/arm/mm/proc-*.S
4511da177e4SLinus Torvalds 	 */
4520ba8b9b2SRussell King 	list = lookup_processor_type(read_cpuid_id());
4531da177e4SLinus Torvalds 	if (!list) {
4541da177e4SLinus Torvalds 		printk("CPU configuration botched (ID %08x), unable "
4550ba8b9b2SRussell King 		       "to continue.\n", read_cpuid_id());
4561da177e4SLinus Torvalds 		while (1);
4571da177e4SLinus Torvalds 	}
4581da177e4SLinus Torvalds 
4591da177e4SLinus Torvalds 	cpu_name = list->cpu_name;
4602ecccf90SDave Martin 	__cpu_architecture = __get_cpu_architecture();
4611da177e4SLinus Torvalds 
4621da177e4SLinus Torvalds #ifdef MULTI_CPU
4631da177e4SLinus Torvalds 	processor = *list->proc;
4641da177e4SLinus Torvalds #endif
4651da177e4SLinus Torvalds #ifdef MULTI_TLB
4661da177e4SLinus Torvalds 	cpu_tlb = *list->tlb;
4671da177e4SLinus Torvalds #endif
4681da177e4SLinus Torvalds #ifdef MULTI_USER
4691da177e4SLinus Torvalds 	cpu_user = *list->user;
4701da177e4SLinus Torvalds #endif
4711da177e4SLinus Torvalds #ifdef MULTI_CACHE
4721da177e4SLinus Torvalds 	cpu_cache = *list->cache;
4731da177e4SLinus Torvalds #endif
4741da177e4SLinus Torvalds 
4754e19025bSRussell King 	printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
4760ba8b9b2SRussell King 	       cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
477264edb35SRussell King 	       proc_arch[cpu_architecture()], cr_alignment);
4781da177e4SLinus Torvalds 
479a34dbfb0SWill Deacon 	snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c",
480a34dbfb0SWill Deacon 		 list->arch_name, ENDIANNESS);
481a34dbfb0SWill Deacon 	snprintf(elf_platform, ELF_PLATFORM_SIZE, "%s%c",
482a34dbfb0SWill Deacon 		 list->elf_name, ENDIANNESS);
4831da177e4SLinus Torvalds 	elf_hwcap = list->elf_hwcap;
484adeff422SCatalin Marinas #ifndef CONFIG_ARM_THUMB
485adeff422SCatalin Marinas 	elf_hwcap &= ~HWCAP_THUMB;
486adeff422SCatalin Marinas #endif
4871da177e4SLinus Torvalds 
488f159f4edSTony Lindgren 	feat_v6_fixup();
489f159f4edSTony Lindgren 
490c0e95878SRussell King 	cacheid_init();
491b69874e4SRussell King 	cpu_init();
492ccea7a19SRussell King }
493ccea7a19SRussell King 
49493c02ab4SGrant Likely void __init dump_machine_table(void)
4951da177e4SLinus Torvalds {
496dce72dd0SNicolas Pitre 	struct machine_desc *p;
4971da177e4SLinus Torvalds 
4986291319dSGrant Likely 	early_print("Available machine support:\n\nID (hex)\tNAME\n");
4996291319dSGrant Likely 	for_each_machine_desc(p)
500dce72dd0SNicolas Pitre 		early_print("%08x\t%s\n", p->nr, p->name);
501dce72dd0SNicolas Pitre 
502dce72dd0SNicolas Pitre 	early_print("\nPlease check your kernel config and/or bootloader.\n");
503dce72dd0SNicolas Pitre 
504dce72dd0SNicolas Pitre 	while (true)
505dce72dd0SNicolas Pitre 		/* can't use cpu_relax() here as it may require MMU setup */;
5061da177e4SLinus Torvalds }
5071da177e4SLinus Torvalds 
5089eb8f674SGrant Likely int __init arm_add_memory(phys_addr_t start, unsigned long size)
5093a669411SRussell King {
5104b5f32ceSNicolas Pitre 	struct membank *bank = &meminfo.bank[meminfo.nr_banks];
5114b5f32ceSNicolas Pitre 
5124b5f32ceSNicolas Pitre 	if (meminfo.nr_banks >= NR_BANKS) {
5134b5f32ceSNicolas Pitre 		printk(KERN_CRIT "NR_BANKS too low, "
51429a38193SWill Deacon 			"ignoring memory at 0x%08llx\n", (long long)start);
5154b5f32ceSNicolas Pitre 		return -EINVAL;
5164b5f32ceSNicolas Pitre 	}
51705f96ef1SRussell King 
5183a669411SRussell King 	/*
5193a669411SRussell King 	 * Ensure that start/size are aligned to a page boundary.
5203a669411SRussell King 	 * Size is appropriately rounded down, start is rounded up.
5213a669411SRussell King 	 */
5223a669411SRussell King 	size -= start & ~PAGE_MASK;
52305f96ef1SRussell King 	bank->start = PAGE_ALIGN(start);
52405f96ef1SRussell King 	bank->size  = size & PAGE_MASK;
5254b5f32ceSNicolas Pitre 
5264b5f32ceSNicolas Pitre 	/*
5274b5f32ceSNicolas Pitre 	 * Check whether this memory region has non-zero size or
5284b5f32ceSNicolas Pitre 	 * invalid node number.
5294b5f32ceSNicolas Pitre 	 */
530be370302SRussell King 	if (bank->size == 0)
5314b5f32ceSNicolas Pitre 		return -EINVAL;
5324b5f32ceSNicolas Pitre 
5334b5f32ceSNicolas Pitre 	meminfo.nr_banks++;
5344b5f32ceSNicolas Pitre 	return 0;
5353a669411SRussell King }
5363a669411SRussell King 
5371da177e4SLinus Torvalds /*
5381da177e4SLinus Torvalds  * Pick out the memory size.  We look for mem=size@start,
5391da177e4SLinus Torvalds  * where start and size are "size[KkMm]"
5401da177e4SLinus Torvalds  */
5412b0d8c25SJeremy Kerr static int __init early_mem(char *p)
5421da177e4SLinus Torvalds {
5431da177e4SLinus Torvalds 	static int usermem __initdata = 0;
544f60892d3SWill Deacon 	unsigned long size;
545f60892d3SWill Deacon 	phys_addr_t start;
5462b0d8c25SJeremy Kerr 	char *endp;
5471da177e4SLinus Torvalds 
5481da177e4SLinus Torvalds 	/*
5491da177e4SLinus Torvalds 	 * If the user specifies memory size, we
5501da177e4SLinus Torvalds 	 * blow away any automatically generated
5511da177e4SLinus Torvalds 	 * size.
5521da177e4SLinus Torvalds 	 */
5531da177e4SLinus Torvalds 	if (usermem == 0) {
5541da177e4SLinus Torvalds 		usermem = 1;
5551da177e4SLinus Torvalds 		meminfo.nr_banks = 0;
5561da177e4SLinus Torvalds 	}
5571da177e4SLinus Torvalds 
5581da177e4SLinus Torvalds 	start = PHYS_OFFSET;
5592b0d8c25SJeremy Kerr 	size  = memparse(p, &endp);
5602b0d8c25SJeremy Kerr 	if (*endp == '@')
5612b0d8c25SJeremy Kerr 		start = memparse(endp + 1, NULL);
5621da177e4SLinus Torvalds 
5631c97b73eSAndrew Morton 	arm_add_memory(start, size);
5641da177e4SLinus Torvalds 
5652b0d8c25SJeremy Kerr 	return 0;
5661da177e4SLinus Torvalds }
5672b0d8c25SJeremy Kerr early_param("mem", early_mem);
5681da177e4SLinus Torvalds 
5691da177e4SLinus Torvalds static void __init
5701da177e4SLinus Torvalds setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
5711da177e4SLinus Torvalds {
5721da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_RAM
5731da177e4SLinus Torvalds 	extern int rd_size, rd_image_start, rd_prompt, rd_doload;
5741da177e4SLinus Torvalds 
5751da177e4SLinus Torvalds 	rd_image_start = image_start;
5761da177e4SLinus Torvalds 	rd_prompt = prompt;
5771da177e4SLinus Torvalds 	rd_doload = doload;
5781da177e4SLinus Torvalds 
5791da177e4SLinus Torvalds 	if (rd_sz)
5801da177e4SLinus Torvalds 		rd_size = rd_sz;
5811da177e4SLinus Torvalds #endif
5821da177e4SLinus Torvalds }
5831da177e4SLinus Torvalds 
58411b9369cSDima Zavin static void __init request_standard_resources(struct machine_desc *mdesc)
5851da177e4SLinus Torvalds {
58611b9369cSDima Zavin 	struct memblock_region *region;
5871da177e4SLinus Torvalds 	struct resource *res;
5881da177e4SLinus Torvalds 
58937efe642SRussell King 	kernel_code.start   = virt_to_phys(_text);
59037efe642SRussell King 	kernel_code.end     = virt_to_phys(_etext - 1);
591842eab40SRussell King 	kernel_data.start   = virt_to_phys(_sdata);
59237efe642SRussell King 	kernel_data.end     = virt_to_phys(_end - 1);
5931da177e4SLinus Torvalds 
59411b9369cSDima Zavin 	for_each_memblock(memory, region) {
5951da177e4SLinus Torvalds 		res = alloc_bootmem_low(sizeof(*res));
5961da177e4SLinus Torvalds 		res->name  = "System RAM";
59711b9369cSDima Zavin 		res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
59811b9369cSDima Zavin 		res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
5991da177e4SLinus Torvalds 		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
6001da177e4SLinus Torvalds 
6011da177e4SLinus Torvalds 		request_resource(&iomem_resource, res);
6021da177e4SLinus Torvalds 
6031da177e4SLinus Torvalds 		if (kernel_code.start >= res->start &&
6041da177e4SLinus Torvalds 		    kernel_code.end <= res->end)
6051da177e4SLinus Torvalds 			request_resource(res, &kernel_code);
6061da177e4SLinus Torvalds 		if (kernel_data.start >= res->start &&
6071da177e4SLinus Torvalds 		    kernel_data.end <= res->end)
6081da177e4SLinus Torvalds 			request_resource(res, &kernel_data);
6091da177e4SLinus Torvalds 	}
6101da177e4SLinus Torvalds 
6111da177e4SLinus Torvalds 	if (mdesc->video_start) {
6121da177e4SLinus Torvalds 		video_ram.start = mdesc->video_start;
6131da177e4SLinus Torvalds 		video_ram.end   = mdesc->video_end;
6141da177e4SLinus Torvalds 		request_resource(&iomem_resource, &video_ram);
6151da177e4SLinus Torvalds 	}
6161da177e4SLinus Torvalds 
6171da177e4SLinus Torvalds 	/*
6181da177e4SLinus Torvalds 	 * Some machines don't have the possibility of ever
6191da177e4SLinus Torvalds 	 * possessing lp0, lp1 or lp2
6201da177e4SLinus Torvalds 	 */
6211da177e4SLinus Torvalds 	if (mdesc->reserve_lp0)
6221da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp0);
6231da177e4SLinus Torvalds 	if (mdesc->reserve_lp1)
6241da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp1);
6251da177e4SLinus Torvalds 	if (mdesc->reserve_lp2)
6261da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp2);
6271da177e4SLinus Torvalds }
6281da177e4SLinus Torvalds 
6291da177e4SLinus Torvalds /*
6301da177e4SLinus Torvalds  *  Tag parsing.
6311da177e4SLinus Torvalds  *
6321da177e4SLinus Torvalds  * This is the new way of passing data to the kernel at boot time.  Rather
6331da177e4SLinus Torvalds  * than passing a fixed inflexible structure to the kernel, we pass a list
6341da177e4SLinus Torvalds  * of variable-sized tags to the kernel.  The first tag must be a ATAG_CORE
6351da177e4SLinus Torvalds  * tag for the list to be recognised (to distinguish the tagged list from
6361da177e4SLinus Torvalds  * a param_struct).  The list is terminated with a zero-length tag (this tag
6371da177e4SLinus Torvalds  * is not parsed in any way).
6381da177e4SLinus Torvalds  */
6391da177e4SLinus Torvalds static int __init parse_tag_core(const struct tag *tag)
6401da177e4SLinus Torvalds {
6411da177e4SLinus Torvalds 	if (tag->hdr.size > 2) {
6421da177e4SLinus Torvalds 		if ((tag->u.core.flags & 1) == 0)
6431da177e4SLinus Torvalds 			root_mountflags &= ~MS_RDONLY;
6441da177e4SLinus Torvalds 		ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
6451da177e4SLinus Torvalds 	}
6461da177e4SLinus Torvalds 	return 0;
6471da177e4SLinus Torvalds }
6481da177e4SLinus Torvalds 
6491da177e4SLinus Torvalds __tagtable(ATAG_CORE, parse_tag_core);
6501da177e4SLinus Torvalds 
6511da177e4SLinus Torvalds static int __init parse_tag_mem32(const struct tag *tag)
6521da177e4SLinus Torvalds {
6534b5f32ceSNicolas Pitre 	return arm_add_memory(tag->u.mem.start, tag->u.mem.size);
6541da177e4SLinus Torvalds }
6551da177e4SLinus Torvalds 
6561da177e4SLinus Torvalds __tagtable(ATAG_MEM, parse_tag_mem32);
6571da177e4SLinus Torvalds 
6581da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
6591da177e4SLinus Torvalds struct screen_info screen_info = {
6601da177e4SLinus Torvalds  .orig_video_lines	= 30,
6611da177e4SLinus Torvalds  .orig_video_cols	= 80,
6621da177e4SLinus Torvalds  .orig_video_mode	= 0,
6631da177e4SLinus Torvalds  .orig_video_ega_bx	= 0,
6641da177e4SLinus Torvalds  .orig_video_isVGA	= 1,
6651da177e4SLinus Torvalds  .orig_video_points	= 8
6661da177e4SLinus Torvalds };
6671da177e4SLinus Torvalds 
6681da177e4SLinus Torvalds static int __init parse_tag_videotext(const struct tag *tag)
6691da177e4SLinus Torvalds {
6701da177e4SLinus Torvalds 	screen_info.orig_x            = tag->u.videotext.x;
6711da177e4SLinus Torvalds 	screen_info.orig_y            = tag->u.videotext.y;
6721da177e4SLinus Torvalds 	screen_info.orig_video_page   = tag->u.videotext.video_page;
6731da177e4SLinus Torvalds 	screen_info.orig_video_mode   = tag->u.videotext.video_mode;
6741da177e4SLinus Torvalds 	screen_info.orig_video_cols   = tag->u.videotext.video_cols;
6751da177e4SLinus Torvalds 	screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
6761da177e4SLinus Torvalds 	screen_info.orig_video_lines  = tag->u.videotext.video_lines;
6771da177e4SLinus Torvalds 	screen_info.orig_video_isVGA  = tag->u.videotext.video_isvga;
6781da177e4SLinus Torvalds 	screen_info.orig_video_points = tag->u.videotext.video_points;
6791da177e4SLinus Torvalds 	return 0;
6801da177e4SLinus Torvalds }
6811da177e4SLinus Torvalds 
6821da177e4SLinus Torvalds __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
6831da177e4SLinus Torvalds #endif
6841da177e4SLinus Torvalds 
6851da177e4SLinus Torvalds static int __init parse_tag_ramdisk(const struct tag *tag)
6861da177e4SLinus Torvalds {
6871da177e4SLinus Torvalds 	setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
6881da177e4SLinus Torvalds 		      (tag->u.ramdisk.flags & 2) == 0,
6891da177e4SLinus Torvalds 		      tag->u.ramdisk.start, tag->u.ramdisk.size);
6901da177e4SLinus Torvalds 	return 0;
6911da177e4SLinus Torvalds }
6921da177e4SLinus Torvalds 
6931da177e4SLinus Torvalds __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
6941da177e4SLinus Torvalds 
6951da177e4SLinus Torvalds static int __init parse_tag_serialnr(const struct tag *tag)
6961da177e4SLinus Torvalds {
6971da177e4SLinus Torvalds 	system_serial_low = tag->u.serialnr.low;
6981da177e4SLinus Torvalds 	system_serial_high = tag->u.serialnr.high;
6991da177e4SLinus Torvalds 	return 0;
7001da177e4SLinus Torvalds }
7011da177e4SLinus Torvalds 
7021da177e4SLinus Torvalds __tagtable(ATAG_SERIAL, parse_tag_serialnr);
7031da177e4SLinus Torvalds 
7041da177e4SLinus Torvalds static int __init parse_tag_revision(const struct tag *tag)
7051da177e4SLinus Torvalds {
7061da177e4SLinus Torvalds 	system_rev = tag->u.revision.rev;
7071da177e4SLinus Torvalds 	return 0;
7081da177e4SLinus Torvalds }
7091da177e4SLinus Torvalds 
7101da177e4SLinus Torvalds __tagtable(ATAG_REVISION, parse_tag_revision);
7111da177e4SLinus Torvalds 
7121da177e4SLinus Torvalds static int __init parse_tag_cmdline(const struct tag *tag)
7131da177e4SLinus Torvalds {
7144394c124SVictor Boivie #if defined(CONFIG_CMDLINE_EXTEND)
7154394c124SVictor Boivie 	strlcat(default_command_line, " ", COMMAND_LINE_SIZE);
7164394c124SVictor Boivie 	strlcat(default_command_line, tag->u.cmdline.cmdline,
7174394c124SVictor Boivie 		COMMAND_LINE_SIZE);
7184394c124SVictor Boivie #elif defined(CONFIG_CMDLINE_FORCE)
71922eeb8f6SAlexander Holler 	pr_warning("Ignoring tag cmdline (using the default kernel command line)\n");
7204394c124SVictor Boivie #else
7214394c124SVictor Boivie 	strlcpy(default_command_line, tag->u.cmdline.cmdline,
7224394c124SVictor Boivie 		COMMAND_LINE_SIZE);
7234394c124SVictor Boivie #endif
7241da177e4SLinus Torvalds 	return 0;
7251da177e4SLinus Torvalds }
7261da177e4SLinus Torvalds 
7271da177e4SLinus Torvalds __tagtable(ATAG_CMDLINE, parse_tag_cmdline);
7281da177e4SLinus Torvalds 
7291da177e4SLinus Torvalds /*
7301da177e4SLinus Torvalds  * Scan the tag table for this tag, and call its parse function.
7311da177e4SLinus Torvalds  * The tag table is built by the linker from all the __tagtable
7321da177e4SLinus Torvalds  * declarations.
7331da177e4SLinus Torvalds  */
7341da177e4SLinus Torvalds static int __init parse_tag(const struct tag *tag)
7351da177e4SLinus Torvalds {
7361da177e4SLinus Torvalds 	extern struct tagtable __tagtable_begin, __tagtable_end;
7371da177e4SLinus Torvalds 	struct tagtable *t;
7381da177e4SLinus Torvalds 
7391da177e4SLinus Torvalds 	for (t = &__tagtable_begin; t < &__tagtable_end; t++)
7401da177e4SLinus Torvalds 		if (tag->hdr.tag == t->tag) {
7411da177e4SLinus Torvalds 			t->parse(tag);
7421da177e4SLinus Torvalds 			break;
7431da177e4SLinus Torvalds 		}
7441da177e4SLinus Torvalds 
7451da177e4SLinus Torvalds 	return t < &__tagtable_end;
7461da177e4SLinus Torvalds }
7471da177e4SLinus Torvalds 
7481da177e4SLinus Torvalds /*
7491da177e4SLinus Torvalds  * Parse all tags in the list, checking both the global and architecture
7501da177e4SLinus Torvalds  * specific tag tables.
7511da177e4SLinus Torvalds  */
7521da177e4SLinus Torvalds static void __init parse_tags(const struct tag *t)
7531da177e4SLinus Torvalds {
7541da177e4SLinus Torvalds 	for (; t->hdr.size; t = tag_next(t))
7551da177e4SLinus Torvalds 		if (!parse_tag(t))
7561da177e4SLinus Torvalds 			printk(KERN_WARNING
7571da177e4SLinus Torvalds 				"Ignoring unrecognised tag 0x%08x\n",
7581da177e4SLinus Torvalds 				t->hdr.tag);
7591da177e4SLinus Torvalds }
7601da177e4SLinus Torvalds 
7611da177e4SLinus Torvalds /*
7621da177e4SLinus Torvalds  * This holds our defaults.
7631da177e4SLinus Torvalds  */
7641da177e4SLinus Torvalds static struct init_tags {
7651da177e4SLinus Torvalds 	struct tag_header hdr1;
7661da177e4SLinus Torvalds 	struct tag_core   core;
7671da177e4SLinus Torvalds 	struct tag_header hdr2;
7681da177e4SLinus Torvalds 	struct tag_mem32  mem;
7691da177e4SLinus Torvalds 	struct tag_header hdr3;
7701da177e4SLinus Torvalds } init_tags __initdata = {
7711da177e4SLinus Torvalds 	{ tag_size(tag_core), ATAG_CORE },
7721da177e4SLinus Torvalds 	{ 1, PAGE_SIZE, 0xff },
7731da177e4SLinus Torvalds 	{ tag_size(tag_mem32), ATAG_MEM },
774b75c178aSRussell King 	{ MEM_SIZE },
7751da177e4SLinus Torvalds 	{ 0, ATAG_NONE }
7761da177e4SLinus Torvalds };
7771da177e4SLinus Torvalds 
7781da177e4SLinus Torvalds static int __init customize_machine(void)
7791da177e4SLinus Torvalds {
7801da177e4SLinus Torvalds 	/* customizes platform devices, or adds new ones */
7818ff1443cSRussell King 	if (machine_desc->init_machine)
7828ff1443cSRussell King 		machine_desc->init_machine();
7831da177e4SLinus Torvalds 	return 0;
7841da177e4SLinus Torvalds }
7851da177e4SLinus Torvalds arch_initcall(customize_machine);
7861da177e4SLinus Torvalds 
7873c57fb43SMika Westerberg #ifdef CONFIG_KEXEC
7883c57fb43SMika Westerberg static inline unsigned long long get_total_mem(void)
7893c57fb43SMika Westerberg {
7903c57fb43SMika Westerberg 	unsigned long total;
7913c57fb43SMika Westerberg 
7923c57fb43SMika Westerberg 	total = max_low_pfn - min_low_pfn;
7933c57fb43SMika Westerberg 	return total << PAGE_SHIFT;
7943c57fb43SMika Westerberg }
7953c57fb43SMika Westerberg 
7963c57fb43SMika Westerberg /**
7973c57fb43SMika Westerberg  * reserve_crashkernel() - reserves memory are for crash kernel
7983c57fb43SMika Westerberg  *
7993c57fb43SMika Westerberg  * This function reserves memory area given in "crashkernel=" kernel command
8003c57fb43SMika Westerberg  * line parameter. The memory reserved is used by a dump capture kernel when
8013c57fb43SMika Westerberg  * primary kernel is crashing.
8023c57fb43SMika Westerberg  */
8033c57fb43SMika Westerberg static void __init reserve_crashkernel(void)
8043c57fb43SMika Westerberg {
8053c57fb43SMika Westerberg 	unsigned long long crash_size, crash_base;
8063c57fb43SMika Westerberg 	unsigned long long total_mem;
8073c57fb43SMika Westerberg 	int ret;
8083c57fb43SMika Westerberg 
8093c57fb43SMika Westerberg 	total_mem = get_total_mem();
8103c57fb43SMika Westerberg 	ret = parse_crashkernel(boot_command_line, total_mem,
8113c57fb43SMika Westerberg 				&crash_size, &crash_base);
8123c57fb43SMika Westerberg 	if (ret)
8133c57fb43SMika Westerberg 		return;
8143c57fb43SMika Westerberg 
8153c57fb43SMika Westerberg 	ret = reserve_bootmem(crash_base, crash_size, BOOTMEM_EXCLUSIVE);
8163c57fb43SMika Westerberg 	if (ret < 0) {
8173c57fb43SMika Westerberg 		printk(KERN_WARNING "crashkernel reservation failed - "
8183c57fb43SMika Westerberg 		       "memory is in use (0x%lx)\n", (unsigned long)crash_base);
8193c57fb43SMika Westerberg 		return;
8203c57fb43SMika Westerberg 	}
8213c57fb43SMika Westerberg 
8223c57fb43SMika Westerberg 	printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
8233c57fb43SMika Westerberg 	       "for crashkernel (System RAM: %ldMB)\n",
8243c57fb43SMika Westerberg 	       (unsigned long)(crash_size >> 20),
8253c57fb43SMika Westerberg 	       (unsigned long)(crash_base >> 20),
8263c57fb43SMika Westerberg 	       (unsigned long)(total_mem >> 20));
8273c57fb43SMika Westerberg 
8283c57fb43SMika Westerberg 	crashk_res.start = crash_base;
8293c57fb43SMika Westerberg 	crashk_res.end = crash_base + crash_size - 1;
8303c57fb43SMika Westerberg 	insert_resource(&iomem_resource, &crashk_res);
8313c57fb43SMika Westerberg }
8323c57fb43SMika Westerberg #else
8333c57fb43SMika Westerberg static inline void reserve_crashkernel(void) {}
8343c57fb43SMika Westerberg #endif /* CONFIG_KEXEC */
8353c57fb43SMika Westerberg 
83673a65b3fSUwe Kleine-König static void __init squash_mem_tags(struct tag *tag)
83773a65b3fSUwe Kleine-König {
83873a65b3fSUwe Kleine-König 	for (; tag->hdr.size; tag = tag_next(tag))
83973a65b3fSUwe Kleine-König 		if (tag->hdr.tag == ATAG_MEM)
84073a65b3fSUwe Kleine-König 			tag->hdr.tag = ATAG_NONE;
84173a65b3fSUwe Kleine-König }
84273a65b3fSUwe Kleine-König 
8436291319dSGrant Likely static struct machine_desc * __init setup_machine_tags(unsigned int nr)
8441da177e4SLinus Torvalds {
8451da177e4SLinus Torvalds 	struct tag *tags = (struct tag *)&init_tags;
8466291319dSGrant Likely 	struct machine_desc *mdesc = NULL, *p;
8471da177e4SLinus Torvalds 	char *from = default_command_line;
8481da177e4SLinus Torvalds 
849b75c178aSRussell King 	init_tags.mem.start = PHYS_OFFSET;
850b75c178aSRussell King 
8516291319dSGrant Likely 	/*
8526291319dSGrant Likely 	 * locate machine in the list of supported machines.
8536291319dSGrant Likely 	 */
8546291319dSGrant Likely 	for_each_machine_desc(p)
8556291319dSGrant Likely 		if (nr == p->nr) {
8566291319dSGrant Likely 			printk("Machine: %s\n", p->name);
8576291319dSGrant Likely 			mdesc = p;
8586291319dSGrant Likely 			break;
8596291319dSGrant Likely 		}
860bff595c1SCatalin Marinas 
8616291319dSGrant Likely 	if (!mdesc) {
8626291319dSGrant Likely 		early_print("\nError: unrecognized/unsupported machine ID"
8636291319dSGrant Likely 			" (r1 = 0x%08x).\n\n", nr);
8646291319dSGrant Likely 		dump_machine_table(); /* does not return */
8656291319dSGrant Likely 	}
8661da177e4SLinus Torvalds 
8679d20fdd5SBill Gatliff 	if (__atags_pointer)
8689d20fdd5SBill Gatliff 		tags = phys_to_virt(__atags_pointer);
8692bb9839eSNicolas Pitre 	else if (mdesc->atag_offset)
8702bb9839eSNicolas Pitre 		tags = (void *)(PAGE_OFFSET + mdesc->atag_offset);
8711da177e4SLinus Torvalds 
87273a65b3fSUwe Kleine-König #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
8731da177e4SLinus Torvalds 	/*
8741da177e4SLinus Torvalds 	 * If we have the old style parameters, convert them to
8751da177e4SLinus Torvalds 	 * a tag list.
8761da177e4SLinus Torvalds 	 */
8771da177e4SLinus Torvalds 	if (tags->hdr.tag != ATAG_CORE)
8781da177e4SLinus Torvalds 		convert_to_tag_list(tags);
87973a65b3fSUwe Kleine-König #endif
88093c02ab4SGrant Likely 
88193c02ab4SGrant Likely 	if (tags->hdr.tag != ATAG_CORE) {
88293c02ab4SGrant Likely #if defined(CONFIG_OF)
88393c02ab4SGrant Likely 		/*
88493c02ab4SGrant Likely 		 * If CONFIG_OF is set, then assume this is a reasonably
88593c02ab4SGrant Likely 		 * modern system that should pass boot parameters
88693c02ab4SGrant Likely 		 */
88793c02ab4SGrant Likely 		early_print("Warning: Neither atags nor dtb found\n");
88893c02ab4SGrant Likely #endif
8891da177e4SLinus Torvalds 		tags = (struct tag *)&init_tags;
89093c02ab4SGrant Likely 	}
8911da177e4SLinus Torvalds 
8921da177e4SLinus Torvalds 	if (mdesc->fixup)
8930744a3eeSRussell King 		mdesc->fixup(tags, &from, &meminfo);
8941da177e4SLinus Torvalds 
8951da177e4SLinus Torvalds 	if (tags->hdr.tag == ATAG_CORE) {
8961da177e4SLinus Torvalds 		if (meminfo.nr_banks != 0)
8971da177e4SLinus Torvalds 			squash_mem_tags(tags);
8984cd9d6f7SRichard Purdie 		save_atags(tags);
8991da177e4SLinus Torvalds 		parse_tags(tags);
9001da177e4SLinus Torvalds 	}
9011da177e4SLinus Torvalds 
9026291319dSGrant Likely 	/* parse_early_param needs a boot_command_line */
9036291319dSGrant Likely 	strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
9046291319dSGrant Likely 
9056291319dSGrant Likely 	return mdesc;
9066291319dSGrant Likely }
9076291319dSGrant Likely 
90827a3f0e9SNicolas Pitre static int __init meminfo_cmp(const void *_a, const void *_b)
90927a3f0e9SNicolas Pitre {
91027a3f0e9SNicolas Pitre 	const struct membank *a = _a, *b = _b;
91127a3f0e9SNicolas Pitre 	long cmp = bank_pfn_start(a) - bank_pfn_start(b);
91227a3f0e9SNicolas Pitre 	return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
91327a3f0e9SNicolas Pitre }
9146291319dSGrant Likely 
9156291319dSGrant Likely void __init setup_arch(char **cmdline_p)
9166291319dSGrant Likely {
9176291319dSGrant Likely 	struct machine_desc *mdesc;
9186291319dSGrant Likely 
9196291319dSGrant Likely 	setup_processor();
92093c02ab4SGrant Likely 	mdesc = setup_machine_fdt(__atags_pointer);
92193c02ab4SGrant Likely 	if (!mdesc)
9226291319dSGrant Likely 		mdesc = setup_machine_tags(machine_arch_type);
9236291319dSGrant Likely 	machine_desc = mdesc;
9246291319dSGrant Likely 	machine_name = mdesc->name;
9256291319dSGrant Likely 
9269811ccdfSArnaud Patard #ifdef CONFIG_ZONE_DMA
9279811ccdfSArnaud Patard 	if (mdesc->dma_zone_size) {
9289811ccdfSArnaud Patard 		extern unsigned long arm_dma_zone_size;
9299811ccdfSArnaud Patard 		arm_dma_zone_size = mdesc->dma_zone_size;
9309811ccdfSArnaud Patard 	}
9319811ccdfSArnaud Patard #endif
932b44c350dSRussell King 	if (mdesc->restart_mode)
933b44c350dSRussell King 		reboot_setup(&mdesc->restart_mode);
9346291319dSGrant Likely 
93537efe642SRussell King 	init_mm.start_code = (unsigned long) _text;
93637efe642SRussell King 	init_mm.end_code   = (unsigned long) _etext;
93737efe642SRussell King 	init_mm.end_data   = (unsigned long) _edata;
93837efe642SRussell King 	init_mm.brk	   = (unsigned long) _end;
9391da177e4SLinus Torvalds 
94048ab7e09SJeremy Kerr 	/* populate cmd_line too for later use, preserving boot_command_line */
94148ab7e09SJeremy Kerr 	strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
94248ab7e09SJeremy Kerr 	*cmdline_p = cmd_line;
9432b0d8c25SJeremy Kerr 
9442b0d8c25SJeremy Kerr 	parse_early_param();
9452b0d8c25SJeremy Kerr 
94627a3f0e9SNicolas Pitre 	sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL);
9470371d3f7SRussell King 	sanity_check_meminfo();
9488d717a52SRussell King 	arm_memblock_init(&meminfo, mdesc);
9492778f620SRussell King 
9504b5f32ceSNicolas Pitre 	paging_init(mdesc);
95111b9369cSDima Zavin 	request_standard_resources(mdesc);
9521da177e4SLinus Torvalds 
953a528721dSRussell King 	if (mdesc->restart)
954a528721dSRussell King 		arm_pm_restart = mdesc->restart;
955a528721dSRussell King 
95693c02ab4SGrant Likely 	unflatten_device_tree();
95793c02ab4SGrant Likely 
9587bbb7940SRussell King #ifdef CONFIG_SMP
959f00ec48fSRussell King 	if (is_smp())
9607bbb7940SRussell King 		smp_init_cpus();
9617bbb7940SRussell King #endif
9623c57fb43SMika Westerberg 	reserve_crashkernel();
9637bbb7940SRussell King 
964bc581770SLinus Walleij 	tcm_init();
965ccea7a19SRussell King 
96652108641Seric miao #ifdef CONFIG_MULTI_IRQ_HANDLER
96752108641Seric miao 	handle_arch_irq = mdesc->handle_irq;
96852108641Seric miao #endif
9691da177e4SLinus Torvalds 
9701da177e4SLinus Torvalds #ifdef CONFIG_VT
9711da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE)
9721da177e4SLinus Torvalds 	conswitchp = &vga_con;
9731da177e4SLinus Torvalds #elif defined(CONFIG_DUMMY_CONSOLE)
9741da177e4SLinus Torvalds 	conswitchp = &dummy_con;
9751da177e4SLinus Torvalds #endif
9761da177e4SLinus Torvalds #endif
9775cbad0ebSJason Wessel 	early_trap_init();
978dec12e62SRussell King 
979dec12e62SRussell King 	if (mdesc->init_early)
980dec12e62SRussell King 		mdesc->init_early();
9811da177e4SLinus Torvalds }
9821da177e4SLinus Torvalds 
9831da177e4SLinus Torvalds 
9841da177e4SLinus Torvalds static int __init topology_init(void)
9851da177e4SLinus Torvalds {
9861da177e4SLinus Torvalds 	int cpu;
9871da177e4SLinus Torvalds 
98866fb8bd2SRussell King 	for_each_possible_cpu(cpu) {
98966fb8bd2SRussell King 		struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu);
99066fb8bd2SRussell King 		cpuinfo->cpu.hotpluggable = 1;
99166fb8bd2SRussell King 		register_cpu(&cpuinfo->cpu, cpu);
99266fb8bd2SRussell King 	}
9931da177e4SLinus Torvalds 
9941da177e4SLinus Torvalds 	return 0;
9951da177e4SLinus Torvalds }
9961da177e4SLinus Torvalds subsys_initcall(topology_init);
9971da177e4SLinus Torvalds 
998e119bfffSRussell King #ifdef CONFIG_HAVE_PROC_CPU
999e119bfffSRussell King static int __init proc_cpu_init(void)
1000e119bfffSRussell King {
1001e119bfffSRussell King 	struct proc_dir_entry *res;
1002e119bfffSRussell King 
1003e119bfffSRussell King 	res = proc_mkdir("cpu", NULL);
1004e119bfffSRussell King 	if (!res)
1005e119bfffSRussell King 		return -ENOMEM;
1006e119bfffSRussell King 	return 0;
1007e119bfffSRussell King }
1008e119bfffSRussell King fs_initcall(proc_cpu_init);
1009e119bfffSRussell King #endif
1010e119bfffSRussell King 
10111da177e4SLinus Torvalds static const char *hwcap_str[] = {
10121da177e4SLinus Torvalds 	"swp",
10131da177e4SLinus Torvalds 	"half",
10141da177e4SLinus Torvalds 	"thumb",
10151da177e4SLinus Torvalds 	"26bit",
10161da177e4SLinus Torvalds 	"fastmult",
10171da177e4SLinus Torvalds 	"fpa",
10181da177e4SLinus Torvalds 	"vfp",
10191da177e4SLinus Torvalds 	"edsp",
10201da177e4SLinus Torvalds 	"java",
10218f7f9435SPaul Gortmaker 	"iwmmxt",
102299e4a6ddSLennert Buytenhek 	"crunch",
10234369ae16SCatalin Marinas 	"thumbee",
10242bedbdf4SCatalin Marinas 	"neon",
10257279dc3eSCatalin Marinas 	"vfpv3",
10267279dc3eSCatalin Marinas 	"vfpv3d16",
1027254cdf8eSWill Deacon 	"tls",
1028254cdf8eSWill Deacon 	"vfpv4",
1029254cdf8eSWill Deacon 	"idiva",
1030254cdf8eSWill Deacon 	"idivt",
10311da177e4SLinus Torvalds 	NULL
10321da177e4SLinus Torvalds };
10331da177e4SLinus Torvalds 
10341da177e4SLinus Torvalds static int c_show(struct seq_file *m, void *v)
10351da177e4SLinus Torvalds {
10361da177e4SLinus Torvalds 	int i;
10371da177e4SLinus Torvalds 
10381da177e4SLinus Torvalds 	seq_printf(m, "Processor\t: %s rev %d (%s)\n",
10390ba8b9b2SRussell King 		   cpu_name, read_cpuid_id() & 15, elf_platform);
10401da177e4SLinus Torvalds 
10411da177e4SLinus Torvalds #if defined(CONFIG_SMP)
10421da177e4SLinus Torvalds 	for_each_online_cpu(i) {
104315559722SRussell King 		/*
104415559722SRussell King 		 * glibc reads /proc/cpuinfo to determine the number of
104515559722SRussell King 		 * online processors, looking for lines beginning with
104615559722SRussell King 		 * "processor".  Give glibc what it expects.
104715559722SRussell King 		 */
104815559722SRussell King 		seq_printf(m, "processor\t: %d\n", i);
10491da177e4SLinus Torvalds 		seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
10501da177e4SLinus Torvalds 			   per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
10511da177e4SLinus Torvalds 			   (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
10521da177e4SLinus Torvalds 	}
10531da177e4SLinus Torvalds #else /* CONFIG_SMP */
10541da177e4SLinus Torvalds 	seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
10551da177e4SLinus Torvalds 		   loops_per_jiffy / (500000/HZ),
10561da177e4SLinus Torvalds 		   (loops_per_jiffy / (5000/HZ)) % 100);
10571da177e4SLinus Torvalds #endif
10581da177e4SLinus Torvalds 
10591da177e4SLinus Torvalds 	/* dump out the processor features */
10601da177e4SLinus Torvalds 	seq_puts(m, "Features\t: ");
10611da177e4SLinus Torvalds 
10621da177e4SLinus Torvalds 	for (i = 0; hwcap_str[i]; i++)
10631da177e4SLinus Torvalds 		if (elf_hwcap & (1 << i))
10641da177e4SLinus Torvalds 			seq_printf(m, "%s ", hwcap_str[i]);
10651da177e4SLinus Torvalds 
10660ba8b9b2SRussell King 	seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
10671da177e4SLinus Torvalds 	seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]);
10681da177e4SLinus Torvalds 
10690ba8b9b2SRussell King 	if ((read_cpuid_id() & 0x0008f000) == 0x00000000) {
10701da177e4SLinus Torvalds 		/* pre-ARM7 */
10710ba8b9b2SRussell King 		seq_printf(m, "CPU part\t: %07x\n", read_cpuid_id() >> 4);
10721da177e4SLinus Torvalds 	} else {
10730ba8b9b2SRussell King 		if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
10741da177e4SLinus Torvalds 			/* ARM7 */
10751da177e4SLinus Torvalds 			seq_printf(m, "CPU variant\t: 0x%02x\n",
10760ba8b9b2SRussell King 				   (read_cpuid_id() >> 16) & 127);
10771da177e4SLinus Torvalds 		} else {
10781da177e4SLinus Torvalds 			/* post-ARM7 */
10791da177e4SLinus Torvalds 			seq_printf(m, "CPU variant\t: 0x%x\n",
10800ba8b9b2SRussell King 				   (read_cpuid_id() >> 20) & 15);
10811da177e4SLinus Torvalds 		}
10821da177e4SLinus Torvalds 		seq_printf(m, "CPU part\t: 0x%03x\n",
10830ba8b9b2SRussell King 			   (read_cpuid_id() >> 4) & 0xfff);
10841da177e4SLinus Torvalds 	}
10850ba8b9b2SRussell King 	seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);
10861da177e4SLinus Torvalds 
10871da177e4SLinus Torvalds 	seq_puts(m, "\n");
10881da177e4SLinus Torvalds 
10891da177e4SLinus Torvalds 	seq_printf(m, "Hardware\t: %s\n", machine_name);
10901da177e4SLinus Torvalds 	seq_printf(m, "Revision\t: %04x\n", system_rev);
10911da177e4SLinus Torvalds 	seq_printf(m, "Serial\t\t: %08x%08x\n",
10921da177e4SLinus Torvalds 		   system_serial_high, system_serial_low);
10931da177e4SLinus Torvalds 
10941da177e4SLinus Torvalds 	return 0;
10951da177e4SLinus Torvalds }
10961da177e4SLinus Torvalds 
10971da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos)
10981da177e4SLinus Torvalds {
10991da177e4SLinus Torvalds 	return *pos < 1 ? (void *)1 : NULL;
11001da177e4SLinus Torvalds }
11011da177e4SLinus Torvalds 
11021da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos)
11031da177e4SLinus Torvalds {
11041da177e4SLinus Torvalds 	++*pos;
11051da177e4SLinus Torvalds 	return NULL;
11061da177e4SLinus Torvalds }
11071da177e4SLinus Torvalds 
11081da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v)
11091da177e4SLinus Torvalds {
11101da177e4SLinus Torvalds }
11111da177e4SLinus Torvalds 
11122ffd6e18SJan Engelhardt const struct seq_operations cpuinfo_op = {
11131da177e4SLinus Torvalds 	.start	= c_start,
11141da177e4SLinus Torvalds 	.next	= c_next,
11151da177e4SLinus Torvalds 	.stop	= c_stop,
11161da177e4SLinus Torvalds 	.show	= c_show
11171da177e4SLinus Torvalds };
1118