xref: /openbmc/linux/arch/arm/kernel/setup.c (revision 8258a989)
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>
21883a106bSArnd Bergmann #include <linux/of_platform.h>
221da177e4SLinus Torvalds #include <linux/init.h>
233c57fb43SMika Westerberg #include <linux/kexec.h>
2493c02ab4SGrant Likely #include <linux/of_fdt.h>
251da177e4SLinus Torvalds #include <linux/cpu.h>
261da177e4SLinus Torvalds #include <linux/interrupt.h>
277bbb7940SRussell King #include <linux/smp.h>
28e119bfffSRussell King #include <linux/proc_fs.h>
292778f620SRussell King #include <linux/memblock.h>
302ecccf90SDave Martin #include <linux/bug.h>
312ecccf90SDave Martin #include <linux/compiler.h>
3227a3f0e9SNicolas Pitre #include <linux/sort.h>
331da177e4SLinus Torvalds 
34b86040a5SCatalin Marinas #include <asm/unified.h>
3515d07dc9SRussell King #include <asm/cp15.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>
4005774088SStefano Stabellini #include <asm/psci.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>
584588c34dSDave Martin #include <asm/virt.h>
591da177e4SLinus Torvalds 
604cd9d6f7SRichard Purdie #include "atags.h"
610fc1c832SBen Dooks 
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
641da177e4SLinus Torvalds char fpe_type[8];
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds static int __init fpe_setup(char *line)
671da177e4SLinus Torvalds {
681da177e4SLinus Torvalds 	memcpy(fpe_type, line, 8);
691da177e4SLinus Torvalds 	return 1;
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds __setup("fpe=", fpe_setup);
731da177e4SLinus Torvalds #endif
741da177e4SLinus Torvalds 
75ff69a4c8SRussell King extern void paging_init(const struct machine_desc *desc);
76a77e0c7bSSantosh Shilimkar extern void early_paging_init(const struct machine_desc *,
77a77e0c7bSSantosh Shilimkar 			      struct proc_info_list *);
780371d3f7SRussell King extern void sanity_check_meminfo(void);
7916d6d5b0SRobin Holt extern enum reboot_mode reboot_mode;
80ff69a4c8SRussell King extern void setup_dma_zone(const struct machine_desc *desc);
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds unsigned int processor_id;
83c18f6581SKrzysztof Halasa EXPORT_SYMBOL(processor_id);
840385ebc0SRussell King unsigned int __machine_arch_type __read_mostly;
851da177e4SLinus Torvalds EXPORT_SYMBOL(__machine_arch_type);
860385ebc0SRussell King unsigned int cacheid __read_mostly;
87c0e95878SRussell King EXPORT_SYMBOL(cacheid);
881da177e4SLinus Torvalds 
899d20fdd5SBill Gatliff unsigned int __atags_pointer __initdata;
909d20fdd5SBill Gatliff 
911da177e4SLinus Torvalds unsigned int system_rev;
921da177e4SLinus Torvalds EXPORT_SYMBOL(system_rev);
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds unsigned int system_serial_low;
951da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_low);
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds unsigned int system_serial_high;
981da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_high);
991da177e4SLinus Torvalds 
1000385ebc0SRussell King unsigned int elf_hwcap __read_mostly;
1011da177e4SLinus Torvalds EXPORT_SYMBOL(elf_hwcap);
1021da177e4SLinus Torvalds 
103b342ea4eSArd Biesheuvel unsigned int elf_hwcap2 __read_mostly;
104b342ea4eSArd Biesheuvel EXPORT_SYMBOL(elf_hwcap2);
105b342ea4eSArd Biesheuvel 
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds #ifdef MULTI_CPU
1080385ebc0SRussell King struct processor processor __read_mostly;
1091da177e4SLinus Torvalds #endif
1101da177e4SLinus Torvalds #ifdef MULTI_TLB
1110385ebc0SRussell King struct cpu_tlb_fns cpu_tlb __read_mostly;
1121da177e4SLinus Torvalds #endif
1131da177e4SLinus Torvalds #ifdef MULTI_USER
1140385ebc0SRussell King struct cpu_user_fns cpu_user __read_mostly;
1151da177e4SLinus Torvalds #endif
1161da177e4SLinus Torvalds #ifdef MULTI_CACHE
1170385ebc0SRussell King struct cpu_cache_fns cpu_cache __read_mostly;
1181da177e4SLinus Torvalds #endif
119953233dcSCatalin Marinas #ifdef CONFIG_OUTER_CACHE
1200385ebc0SRussell King struct outer_cache_fns outer_cache __read_mostly;
1216c09f09dSSantosh Shilimkar EXPORT_SYMBOL(outer_cache);
122953233dcSCatalin Marinas #endif
1231da177e4SLinus Torvalds 
1242ecccf90SDave Martin /*
1252ecccf90SDave Martin  * Cached cpu_architecture() result for use by assembler code.
1262ecccf90SDave Martin  * C code should use the cpu_architecture() function instead of accessing this
1272ecccf90SDave Martin  * variable directly.
1282ecccf90SDave Martin  */
1292ecccf90SDave Martin int __cpu_architecture __read_mostly = CPU_ARCH_UNKNOWN;
1302ecccf90SDave Martin 
131ccea7a19SRussell King struct stack {
132ccea7a19SRussell King 	u32 irq[3];
133ccea7a19SRussell King 	u32 abt[3];
134ccea7a19SRussell King 	u32 und[3];
135ccea7a19SRussell King } ____cacheline_aligned;
136ccea7a19SRussell King 
13755bdd694SCatalin Marinas #ifndef CONFIG_CPU_V7M
138ccea7a19SRussell King static struct stack stacks[NR_CPUS];
13955bdd694SCatalin Marinas #endif
140ccea7a19SRussell King 
1411da177e4SLinus Torvalds char elf_platform[ELF_PLATFORM_SIZE];
1421da177e4SLinus Torvalds EXPORT_SYMBOL(elf_platform);
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds static const char *cpu_name;
1451da177e4SLinus Torvalds static const char *machine_name;
14648ab7e09SJeremy Kerr static char __initdata cmd_line[COMMAND_LINE_SIZE];
147ff69a4c8SRussell King const struct machine_desc *machine_desc __initdata;
1481da177e4SLinus Torvalds 
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",
21855bdd694SCatalin Marinas 	"7M",
2191da177e4SLinus Torvalds 	"?(12)",
2201da177e4SLinus Torvalds 	"?(13)",
2211da177e4SLinus Torvalds 	"?(14)",
2221da177e4SLinus Torvalds 	"?(15)",
2231da177e4SLinus Torvalds 	"?(16)",
2241da177e4SLinus Torvalds 	"?(17)",
2251da177e4SLinus Torvalds };
2261da177e4SLinus Torvalds 
22755bdd694SCatalin Marinas #ifdef CONFIG_CPU_V7M
22855bdd694SCatalin Marinas static int __get_cpu_architecture(void)
22955bdd694SCatalin Marinas {
23055bdd694SCatalin Marinas 	return CPU_ARCH_ARMv7M;
23155bdd694SCatalin Marinas }
23255bdd694SCatalin Marinas #else
2332ecccf90SDave Martin static int __get_cpu_architecture(void)
2341da177e4SLinus Torvalds {
2351da177e4SLinus Torvalds 	int cpu_arch;
2361da177e4SLinus Torvalds 
2370ba8b9b2SRussell King 	if ((read_cpuid_id() & 0x0008f000) == 0) {
2381da177e4SLinus Torvalds 		cpu_arch = CPU_ARCH_UNKNOWN;
2390ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
2400ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
2410ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x00080000) == 0x00000000) {
2420ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() >> 16) & 7;
2431da177e4SLinus Torvalds 		if (cpu_arch)
2441da177e4SLinus Torvalds 			cpu_arch += CPU_ARCH_ARMv3;
2450ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
246180005c4SCatalin Marinas 		unsigned int mmfr0;
247180005c4SCatalin Marinas 
248180005c4SCatalin Marinas 		/* Revised CPUID format. Read the Memory Model Feature
249180005c4SCatalin Marinas 		 * Register 0 and check for VMSAv7 or PMSAv7 */
250180005c4SCatalin Marinas 		asm("mrc	p15, 0, %0, c0, c1, 4"
251180005c4SCatalin Marinas 		    : "=r" (mmfr0));
252315cfe78SCatalin Marinas 		if ((mmfr0 & 0x0000000f) >= 0x00000003 ||
253315cfe78SCatalin Marinas 		    (mmfr0 & 0x000000f0) >= 0x00000030)
254180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv7;
255180005c4SCatalin Marinas 		else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
256180005c4SCatalin Marinas 			 (mmfr0 & 0x000000f0) == 0x00000020)
257180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv6;
258180005c4SCatalin Marinas 		else
259180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_UNKNOWN;
260180005c4SCatalin Marinas 	} else
261180005c4SCatalin Marinas 		cpu_arch = CPU_ARCH_UNKNOWN;
2621da177e4SLinus Torvalds 
2631da177e4SLinus Torvalds 	return cpu_arch;
2641da177e4SLinus Torvalds }
26555bdd694SCatalin Marinas #endif
2661da177e4SLinus Torvalds 
2672ecccf90SDave Martin int __pure cpu_architecture(void)
2682ecccf90SDave Martin {
2692ecccf90SDave Martin 	BUG_ON(__cpu_architecture == CPU_ARCH_UNKNOWN);
2702ecccf90SDave Martin 
2712ecccf90SDave Martin 	return __cpu_architecture;
2722ecccf90SDave Martin }
2732ecccf90SDave Martin 
2748925ec4cSWill Deacon static int cpu_has_aliasing_icache(unsigned int arch)
2758925ec4cSWill Deacon {
2768925ec4cSWill Deacon 	int aliasing_icache;
2778925ec4cSWill Deacon 	unsigned int id_reg, num_sets, line_size;
2788925ec4cSWill Deacon 
2797f94e9ccSWill Deacon 	/* PIPT caches never alias. */
2807f94e9ccSWill Deacon 	if (icache_is_pipt())
2817f94e9ccSWill Deacon 		return 0;
2827f94e9ccSWill Deacon 
2838925ec4cSWill Deacon 	/* arch specifies the register format */
2848925ec4cSWill Deacon 	switch (arch) {
2858925ec4cSWill Deacon 	case CPU_ARCH_ARMv7:
2865fb31a96SLinus Walleij 		asm("mcr	p15, 2, %0, c0, c0, 0 @ set CSSELR"
2875fb31a96SLinus Walleij 		    : /* No output operands */
2888925ec4cSWill Deacon 		    : "r" (1));
2895fb31a96SLinus Walleij 		isb();
2905fb31a96SLinus Walleij 		asm("mrc	p15, 1, %0, c0, c0, 0 @ read CCSIDR"
2915fb31a96SLinus Walleij 		    : "=r" (id_reg));
2928925ec4cSWill Deacon 		line_size = 4 << ((id_reg & 0x7) + 2);
2938925ec4cSWill Deacon 		num_sets = ((id_reg >> 13) & 0x7fff) + 1;
2948925ec4cSWill Deacon 		aliasing_icache = (line_size * num_sets) > PAGE_SIZE;
2958925ec4cSWill Deacon 		break;
2968925ec4cSWill Deacon 	case CPU_ARCH_ARMv6:
2978925ec4cSWill Deacon 		aliasing_icache = read_cpuid_cachetype() & (1 << 11);
2988925ec4cSWill Deacon 		break;
2998925ec4cSWill Deacon 	default:
3008925ec4cSWill Deacon 		/* I-cache aliases will be handled by D-cache aliasing code */
3018925ec4cSWill Deacon 		aliasing_icache = 0;
3028925ec4cSWill Deacon 	}
3038925ec4cSWill Deacon 
3048925ec4cSWill Deacon 	return aliasing_icache;
3058925ec4cSWill Deacon }
3068925ec4cSWill Deacon 
307c0e95878SRussell King static void __init cacheid_init(void)
308c0e95878SRussell King {
309c0e95878SRussell King 	unsigned int arch = cpu_architecture();
310c0e95878SRussell King 
31155bdd694SCatalin Marinas 	if (arch == CPU_ARCH_ARMv7M) {
31255bdd694SCatalin Marinas 		cacheid = 0;
31355bdd694SCatalin Marinas 	} else if (arch >= CPU_ARCH_ARMv6) {
314ac52e83fSUwe Kleine-König 		unsigned int cachetype = read_cpuid_cachetype();
315b57ee99fSCatalin Marinas 		if ((cachetype & (7 << 29)) == 4 << 29) {
316b57ee99fSCatalin Marinas 			/* ARMv7 register format */
31772dc53acSWill Deacon 			arch = CPU_ARCH_ARMv7;
318c0e95878SRussell King 			cacheid = CACHEID_VIPT_NONALIASING;
3197f94e9ccSWill Deacon 			switch (cachetype & (3 << 14)) {
3207f94e9ccSWill Deacon 			case (1 << 14):
321c0e95878SRussell King 				cacheid |= CACHEID_ASID_TAGGED;
3227f94e9ccSWill Deacon 				break;
3237f94e9ccSWill Deacon 			case (3 << 14):
3247f94e9ccSWill Deacon 				cacheid |= CACHEID_PIPT;
3257f94e9ccSWill Deacon 				break;
3267f94e9ccSWill Deacon 			}
3278925ec4cSWill Deacon 		} else {
32872dc53acSWill Deacon 			arch = CPU_ARCH_ARMv6;
32972dc53acSWill Deacon 			if (cachetype & (1 << 23))
33072dc53acSWill Deacon 				cacheid = CACHEID_VIPT_ALIASING;
33172dc53acSWill Deacon 			else
332c0e95878SRussell King 				cacheid = CACHEID_VIPT_NONALIASING;
3338925ec4cSWill Deacon 		}
33472dc53acSWill Deacon 		if (cpu_has_aliasing_icache(arch))
33572dc53acSWill Deacon 			cacheid |= CACHEID_VIPT_I_ALIASING;
336c0e95878SRussell King 	} else {
337c0e95878SRussell King 		cacheid = CACHEID_VIVT;
338c0e95878SRussell King 	}
3392b4ae1f1SRussell King 
3401b0f6681SOlof Johansson 	pr_info("CPU: %s data cache, %s instruction cache\n",
3412b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
3422b4ae1f1SRussell King 		cache_is_vipt_aliasing() ? "VIPT aliasing" :
3437f94e9ccSWill Deacon 		cache_is_vipt_nonaliasing() ? "PIPT / VIPT nonaliasing" : "unknown",
3442b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
3452b4ae1f1SRussell King 		icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :
3468925ec4cSWill Deacon 		icache_is_vipt_aliasing() ? "VIPT aliasing" :
3477f94e9ccSWill Deacon 		icache_is_pipt() ? "PIPT" :
3482b4ae1f1SRussell King 		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");
349c0e95878SRussell King }
350c0e95878SRussell King 
3511da177e4SLinus Torvalds /*
3521da177e4SLinus Torvalds  * These functions re-use the assembly code in head.S, which
3531da177e4SLinus Torvalds  * already provide the required functionality.
3541da177e4SLinus Torvalds  */
3550f44ba1dSRussell King extern struct proc_info_list *lookup_processor_type(unsigned int);
3566fc31d54SRussell King 
35793c02ab4SGrant Likely void __init early_print(const char *str, ...)
3586fc31d54SRussell King {
3596fc31d54SRussell King 	extern void printascii(const char *);
3606fc31d54SRussell King 	char buf[256];
3616fc31d54SRussell King 	va_list ap;
3626fc31d54SRussell King 
3636fc31d54SRussell King 	va_start(ap, str);
3646fc31d54SRussell King 	vsnprintf(buf, sizeof(buf), str, ap);
3656fc31d54SRussell King 	va_end(ap);
3666fc31d54SRussell King 
3676fc31d54SRussell King #ifdef CONFIG_DEBUG_LL
3686fc31d54SRussell King 	printascii(buf);
3696fc31d54SRussell King #endif
3706fc31d54SRussell King 	printk("%s", buf);
3716fc31d54SRussell King }
3726fc31d54SRussell King 
3738164f7afSStephen Boyd static void __init cpuid_init_hwcaps(void)
3748164f7afSStephen Boyd {
375a469abd0SWill Deacon 	unsigned int divide_instrs, vmsa;
3768164f7afSStephen Boyd 
3778164f7afSStephen Boyd 	if (cpu_architecture() < CPU_ARCH_ARMv7)
3788164f7afSStephen Boyd 		return;
3798164f7afSStephen Boyd 
3808164f7afSStephen Boyd 	divide_instrs = (read_cpuid_ext(CPUID_EXT_ISAR0) & 0x0f000000) >> 24;
3818164f7afSStephen Boyd 
3828164f7afSStephen Boyd 	switch (divide_instrs) {
3838164f7afSStephen Boyd 	case 2:
3848164f7afSStephen Boyd 		elf_hwcap |= HWCAP_IDIVA;
3858164f7afSStephen Boyd 	case 1:
3868164f7afSStephen Boyd 		elf_hwcap |= HWCAP_IDIVT;
3878164f7afSStephen Boyd 	}
388a469abd0SWill Deacon 
389a469abd0SWill Deacon 	/* LPAE implies atomic ldrd/strd instructions */
390a469abd0SWill Deacon 	vmsa = (read_cpuid_ext(CPUID_EXT_MMFR0) & 0xf) >> 0;
391a469abd0SWill Deacon 	if (vmsa >= 5)
392a469abd0SWill Deacon 		elf_hwcap |= HWCAP_LPAE;
3938164f7afSStephen Boyd }
3948164f7afSStephen Boyd 
395f159f4edSTony Lindgren static void __init feat_v6_fixup(void)
396f159f4edSTony Lindgren {
397f159f4edSTony Lindgren 	int id = read_cpuid_id();
398f159f4edSTony Lindgren 
399f159f4edSTony Lindgren 	if ((id & 0xff0f0000) != 0x41070000)
400f159f4edSTony Lindgren 		return;
401f159f4edSTony Lindgren 
402f159f4edSTony Lindgren 	/*
403f159f4edSTony Lindgren 	 * HWCAP_TLS is available only on 1136 r1p0 and later,
404f159f4edSTony Lindgren 	 * see also kuser_get_tls_init.
405f159f4edSTony Lindgren 	 */
406f159f4edSTony Lindgren 	if ((((id >> 4) & 0xfff) == 0xb36) && (((id >> 20) & 3) == 0))
407f159f4edSTony Lindgren 		elf_hwcap &= ~HWCAP_TLS;
408f159f4edSTony Lindgren }
409f159f4edSTony Lindgren 
410b69874e4SRussell King /*
411b69874e4SRussell King  * cpu_init - initialise one CPU.
412b69874e4SRussell King  *
413b69874e4SRussell King  * cpu_init sets up the per-CPU stacks.
414b69874e4SRussell King  */
4151783d457SJon Medhurst void notrace cpu_init(void)
416b69874e4SRussell King {
41755bdd694SCatalin Marinas #ifndef CONFIG_CPU_V7M
418b69874e4SRussell King 	unsigned int cpu = smp_processor_id();
419b69874e4SRussell King 	struct stack *stk = &stacks[cpu];
420b69874e4SRussell King 
421b69874e4SRussell King 	if (cpu >= NR_CPUS) {
4221b0f6681SOlof Johansson 		pr_crit("CPU%u: bad primary CPU number\n", cpu);
423b69874e4SRussell King 		BUG();
424b69874e4SRussell King 	}
425b69874e4SRussell King 
42614318efbSRob Herring 	/*
42714318efbSRob Herring 	 * This only works on resume and secondary cores. For booting on the
42814318efbSRob Herring 	 * boot cpu, smp_prepare_boot_cpu is called after percpu area setup.
42914318efbSRob Herring 	 */
43014318efbSRob Herring 	set_my_cpu_offset(per_cpu_offset(cpu));
43114318efbSRob Herring 
432b69874e4SRussell King 	cpu_proc_init();
433b69874e4SRussell King 
434b69874e4SRussell King 	/*
435b69874e4SRussell King 	 * Define the placement constraint for the inline asm directive below.
436b69874e4SRussell King 	 * In Thumb-2, msr with an immediate value is not allowed.
437b69874e4SRussell King 	 */
438b69874e4SRussell King #ifdef CONFIG_THUMB2_KERNEL
439b69874e4SRussell King #define PLC	"r"
440b69874e4SRussell King #else
441b69874e4SRussell King #define PLC	"I"
442b69874e4SRussell King #endif
443b69874e4SRussell King 
444b69874e4SRussell King 	/*
445b69874e4SRussell King 	 * setup stacks for re-entrant exception handlers
446b69874e4SRussell King 	 */
447b69874e4SRussell King 	__asm__ (
448b69874e4SRussell King 	"msr	cpsr_c, %1\n\t"
449b69874e4SRussell King 	"add	r14, %0, %2\n\t"
450b69874e4SRussell King 	"mov	sp, r14\n\t"
451b69874e4SRussell King 	"msr	cpsr_c, %3\n\t"
452b69874e4SRussell King 	"add	r14, %0, %4\n\t"
453b69874e4SRussell King 	"mov	sp, r14\n\t"
454b69874e4SRussell King 	"msr	cpsr_c, %5\n\t"
455b69874e4SRussell King 	"add	r14, %0, %6\n\t"
456b69874e4SRussell King 	"mov	sp, r14\n\t"
457b69874e4SRussell King 	"msr	cpsr_c, %7"
458b69874e4SRussell King 	    :
459b69874e4SRussell King 	    : "r" (stk),
460b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
461b69874e4SRussell King 	      "I" (offsetof(struct stack, irq[0])),
462b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
463b69874e4SRussell King 	      "I" (offsetof(struct stack, abt[0])),
464b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
465b69874e4SRussell King 	      "I" (offsetof(struct stack, und[0])),
466b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
467b69874e4SRussell King 	    : "r14");
46855bdd694SCatalin Marinas #endif
469b69874e4SRussell King }
470b69874e4SRussell King 
47118d7f152SLorenzo Pieralisi u32 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = MPIDR_INVALID };
472eb50439bSWill Deacon 
473eb50439bSWill Deacon void __init smp_setup_processor_id(void)
474eb50439bSWill Deacon {
475eb50439bSWill Deacon 	int i;
476cb8cf4f8SLorenzo Pieralisi 	u32 mpidr = is_smp() ? read_cpuid_mpidr() & MPIDR_HWID_BITMASK : 0;
477cb8cf4f8SLorenzo Pieralisi 	u32 cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
478eb50439bSWill Deacon 
479eb50439bSWill Deacon 	cpu_logical_map(0) = cpu;
480cb8cf4f8SLorenzo Pieralisi 	for (i = 1; i < nr_cpu_ids; ++i)
481eb50439bSWill Deacon 		cpu_logical_map(i) = i == cpu ? 0 : i;
482eb50439bSWill Deacon 
4839394c1c6SMing Lei 	/*
4849394c1c6SMing Lei 	 * clear __my_cpu_offset on boot CPU to avoid hang caused by
4859394c1c6SMing Lei 	 * using percpu variable early, for example, lockdep will
4869394c1c6SMing Lei 	 * access percpu variable inside lock_release
4879394c1c6SMing Lei 	 */
4889394c1c6SMing Lei 	set_my_cpu_offset(0);
4899394c1c6SMing Lei 
4901b0f6681SOlof Johansson 	pr_info("Booting Linux on physical CPU 0x%x\n", mpidr);
491eb50439bSWill Deacon }
492eb50439bSWill Deacon 
4938cf72172SLorenzo Pieralisi struct mpidr_hash mpidr_hash;
4948cf72172SLorenzo Pieralisi #ifdef CONFIG_SMP
4958cf72172SLorenzo Pieralisi /**
4968cf72172SLorenzo Pieralisi  * smp_build_mpidr_hash - Pre-compute shifts required at each affinity
4978cf72172SLorenzo Pieralisi  *			  level in order to build a linear index from an
4988cf72172SLorenzo Pieralisi  *			  MPIDR value. Resulting algorithm is a collision
4998cf72172SLorenzo Pieralisi  *			  free hash carried out through shifting and ORing
5008cf72172SLorenzo Pieralisi  */
5018cf72172SLorenzo Pieralisi static void __init smp_build_mpidr_hash(void)
5028cf72172SLorenzo Pieralisi {
5038cf72172SLorenzo Pieralisi 	u32 i, affinity;
5048cf72172SLorenzo Pieralisi 	u32 fs[3], bits[3], ls, mask = 0;
5058cf72172SLorenzo Pieralisi 	/*
5068cf72172SLorenzo Pieralisi 	 * Pre-scan the list of MPIDRS and filter out bits that do
5078cf72172SLorenzo Pieralisi 	 * not contribute to affinity levels, ie they never toggle.
5088cf72172SLorenzo Pieralisi 	 */
5098cf72172SLorenzo Pieralisi 	for_each_possible_cpu(i)
5108cf72172SLorenzo Pieralisi 		mask |= (cpu_logical_map(i) ^ cpu_logical_map(0));
5118cf72172SLorenzo Pieralisi 	pr_debug("mask of set bits 0x%x\n", mask);
5128cf72172SLorenzo Pieralisi 	/*
5138cf72172SLorenzo Pieralisi 	 * Find and stash the last and first bit set at all affinity levels to
5148cf72172SLorenzo Pieralisi 	 * check how many bits are required to represent them.
5158cf72172SLorenzo Pieralisi 	 */
5168cf72172SLorenzo Pieralisi 	for (i = 0; i < 3; i++) {
5178cf72172SLorenzo Pieralisi 		affinity = MPIDR_AFFINITY_LEVEL(mask, i);
5188cf72172SLorenzo Pieralisi 		/*
5198cf72172SLorenzo Pieralisi 		 * Find the MSB bit and LSB bits position
5208cf72172SLorenzo Pieralisi 		 * to determine how many bits are required
5218cf72172SLorenzo Pieralisi 		 * to express the affinity level.
5228cf72172SLorenzo Pieralisi 		 */
5238cf72172SLorenzo Pieralisi 		ls = fls(affinity);
5248cf72172SLorenzo Pieralisi 		fs[i] = affinity ? ffs(affinity) - 1 : 0;
5258cf72172SLorenzo Pieralisi 		bits[i] = ls - fs[i];
5268cf72172SLorenzo Pieralisi 	}
5278cf72172SLorenzo Pieralisi 	/*
5288cf72172SLorenzo Pieralisi 	 * An index can be created from the MPIDR by isolating the
5298cf72172SLorenzo Pieralisi 	 * significant bits at each affinity level and by shifting
5308cf72172SLorenzo Pieralisi 	 * them in order to compress the 24 bits values space to a
5318cf72172SLorenzo Pieralisi 	 * compressed set of values. This is equivalent to hashing
5328cf72172SLorenzo Pieralisi 	 * the MPIDR through shifting and ORing. It is a collision free
5338cf72172SLorenzo Pieralisi 	 * hash though not minimal since some levels might contain a number
5348cf72172SLorenzo Pieralisi 	 * of CPUs that is not an exact power of 2 and their bit
5358cf72172SLorenzo Pieralisi 	 * representation might contain holes, eg MPIDR[7:0] = {0x2, 0x80}.
5368cf72172SLorenzo Pieralisi 	 */
5378cf72172SLorenzo Pieralisi 	mpidr_hash.shift_aff[0] = fs[0];
5388cf72172SLorenzo Pieralisi 	mpidr_hash.shift_aff[1] = MPIDR_LEVEL_BITS + fs[1] - bits[0];
5398cf72172SLorenzo Pieralisi 	mpidr_hash.shift_aff[2] = 2*MPIDR_LEVEL_BITS + fs[2] -
5408cf72172SLorenzo Pieralisi 						(bits[1] + bits[0]);
5418cf72172SLorenzo Pieralisi 	mpidr_hash.mask = mask;
5428cf72172SLorenzo Pieralisi 	mpidr_hash.bits = bits[2] + bits[1] + bits[0];
5438cf72172SLorenzo Pieralisi 	pr_debug("MPIDR hash: aff0[%u] aff1[%u] aff2[%u] mask[0x%x] bits[%u]\n",
5448cf72172SLorenzo Pieralisi 				mpidr_hash.shift_aff[0],
5458cf72172SLorenzo Pieralisi 				mpidr_hash.shift_aff[1],
5468cf72172SLorenzo Pieralisi 				mpidr_hash.shift_aff[2],
5478cf72172SLorenzo Pieralisi 				mpidr_hash.mask,
5488cf72172SLorenzo Pieralisi 				mpidr_hash.bits);
5498cf72172SLorenzo Pieralisi 	/*
5508cf72172SLorenzo Pieralisi 	 * 4x is an arbitrary value used to warn on a hash table much bigger
5518cf72172SLorenzo Pieralisi 	 * than expected on most systems.
5528cf72172SLorenzo Pieralisi 	 */
5538cf72172SLorenzo Pieralisi 	if (mpidr_hash_size() > 4 * num_possible_cpus())
5548cf72172SLorenzo Pieralisi 		pr_warn("Large number of MPIDR hash buckets detected\n");
5558cf72172SLorenzo Pieralisi 	sync_cache_w(&mpidr_hash);
5568cf72172SLorenzo Pieralisi }
5578cf72172SLorenzo Pieralisi #endif
5588cf72172SLorenzo Pieralisi 
5591da177e4SLinus Torvalds static void __init setup_processor(void)
5601da177e4SLinus Torvalds {
5611da177e4SLinus Torvalds 	struct proc_info_list *list;
5621da177e4SLinus Torvalds 
5631da177e4SLinus Torvalds 	/*
5641da177e4SLinus Torvalds 	 * locate processor in the list of supported processor
5651da177e4SLinus Torvalds 	 * types.  The linker builds this table for us from the
5661da177e4SLinus Torvalds 	 * entries in arch/arm/mm/proc-*.S
5671da177e4SLinus Torvalds 	 */
5680ba8b9b2SRussell King 	list = lookup_processor_type(read_cpuid_id());
5691da177e4SLinus Torvalds 	if (!list) {
5701b0f6681SOlof Johansson 		pr_err("CPU configuration botched (ID %08x), unable to continue.\n",
5711b0f6681SOlof Johansson 		       read_cpuid_id());
5721da177e4SLinus Torvalds 		while (1);
5731da177e4SLinus Torvalds 	}
5741da177e4SLinus Torvalds 
5751da177e4SLinus Torvalds 	cpu_name = list->cpu_name;
5762ecccf90SDave Martin 	__cpu_architecture = __get_cpu_architecture();
5771da177e4SLinus Torvalds 
5781da177e4SLinus Torvalds #ifdef MULTI_CPU
5791da177e4SLinus Torvalds 	processor = *list->proc;
5801da177e4SLinus Torvalds #endif
5811da177e4SLinus Torvalds #ifdef MULTI_TLB
5821da177e4SLinus Torvalds 	cpu_tlb = *list->tlb;
5831da177e4SLinus Torvalds #endif
5841da177e4SLinus Torvalds #ifdef MULTI_USER
5851da177e4SLinus Torvalds 	cpu_user = *list->user;
5861da177e4SLinus Torvalds #endif
5871da177e4SLinus Torvalds #ifdef MULTI_CACHE
5881da177e4SLinus Torvalds 	cpu_cache = *list->cache;
5891da177e4SLinus Torvalds #endif
5901da177e4SLinus Torvalds 
5911b0f6681SOlof Johansson 	pr_info("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
5920ba8b9b2SRussell King 		cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
593264edb35SRussell King 		proc_arch[cpu_architecture()], cr_alignment);
5941da177e4SLinus Torvalds 
595a34dbfb0SWill Deacon 	snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c",
596a34dbfb0SWill Deacon 		 list->arch_name, ENDIANNESS);
597a34dbfb0SWill Deacon 	snprintf(elf_platform, ELF_PLATFORM_SIZE, "%s%c",
598a34dbfb0SWill Deacon 		 list->elf_name, ENDIANNESS);
5991da177e4SLinus Torvalds 	elf_hwcap = list->elf_hwcap;
6008164f7afSStephen Boyd 
6018164f7afSStephen Boyd 	cpuid_init_hwcaps();
6028164f7afSStephen Boyd 
603adeff422SCatalin Marinas #ifndef CONFIG_ARM_THUMB
604c40e3641SStephen Boyd 	elf_hwcap &= ~(HWCAP_THUMB | HWCAP_IDIVT);
605adeff422SCatalin Marinas #endif
6061da177e4SLinus Torvalds 
60792871b94SRob Herring 	erratum_a15_798181_init();
60892871b94SRob Herring 
609f159f4edSTony Lindgren 	feat_v6_fixup();
610f159f4edSTony Lindgren 
611c0e95878SRussell King 	cacheid_init();
612b69874e4SRussell King 	cpu_init();
613ccea7a19SRussell King }
614ccea7a19SRussell King 
61593c02ab4SGrant Likely void __init dump_machine_table(void)
6161da177e4SLinus Torvalds {
617ff69a4c8SRussell King 	const struct machine_desc *p;
6181da177e4SLinus Torvalds 
6196291319dSGrant Likely 	early_print("Available machine support:\n\nID (hex)\tNAME\n");
6206291319dSGrant Likely 	for_each_machine_desc(p)
621dce72dd0SNicolas Pitre 		early_print("%08x\t%s\n", p->nr, p->name);
622dce72dd0SNicolas Pitre 
623dce72dd0SNicolas Pitre 	early_print("\nPlease check your kernel config and/or bootloader.\n");
624dce72dd0SNicolas Pitre 
625dce72dd0SNicolas Pitre 	while (true)
626dce72dd0SNicolas Pitre 		/* can't use cpu_relax() here as it may require MMU setup */;
6271da177e4SLinus Torvalds }
6281da177e4SLinus Torvalds 
6296a5014aaSMagnus Damm int __init arm_add_memory(u64 start, u64 size)
6303a669411SRussell King {
6314b5f32ceSNicolas Pitre 	struct membank *bank = &meminfo.bank[meminfo.nr_banks];
6326d7d5da7SMagnus Damm 	u64 aligned_start;
6334b5f32ceSNicolas Pitre 
6344b5f32ceSNicolas Pitre 	if (meminfo.nr_banks >= NR_BANKS) {
6351b0f6681SOlof Johansson 		pr_crit("NR_BANKS too low, ignoring memory at 0x%08llx\n",
6361b0f6681SOlof Johansson 			(long long)start);
6374b5f32ceSNicolas Pitre 		return -EINVAL;
6384b5f32ceSNicolas Pitre 	}
63905f96ef1SRussell King 
6403a669411SRussell King 	/*
6413a669411SRussell King 	 * Ensure that start/size are aligned to a page boundary.
6423a669411SRussell King 	 * Size is appropriately rounded down, start is rounded up.
6433a669411SRussell King 	 */
6443a669411SRussell King 	size -= start & ~PAGE_MASK;
6456d7d5da7SMagnus Damm 	aligned_start = PAGE_ALIGN(start);
646e5ab8580SWill Deacon 
6476d7d5da7SMagnus Damm #ifndef CONFIG_ARCH_PHYS_ADDR_T_64BIT
6486d7d5da7SMagnus Damm 	if (aligned_start > ULONG_MAX) {
6491b0f6681SOlof Johansson 		pr_crit("Ignoring memory at 0x%08llx outside 32-bit physical address space\n",
6501b0f6681SOlof Johansson 			(long long)start);
6516d7d5da7SMagnus Damm 		return -EINVAL;
6526d7d5da7SMagnus Damm 	}
6536d7d5da7SMagnus Damm 
6546d7d5da7SMagnus Damm 	if (aligned_start + size > ULONG_MAX) {
6551b0f6681SOlof Johansson 		pr_crit("Truncating memory at 0x%08llx to fit in 32-bit physical address space\n",
6561b0f6681SOlof Johansson 			(long long)start);
657e5ab8580SWill Deacon 		/*
658e5ab8580SWill Deacon 		 * To ensure bank->start + bank->size is representable in
659e5ab8580SWill Deacon 		 * 32 bits, we use ULONG_MAX as the upper limit rather than 4GB.
660e5ab8580SWill Deacon 		 * This means we lose a page after masking.
661e5ab8580SWill Deacon 		 */
6626d7d5da7SMagnus Damm 		size = ULONG_MAX - aligned_start;
663e5ab8580SWill Deacon 	}
664e5ab8580SWill Deacon #endif
665e5ab8580SWill Deacon 
666571b1437SRussell King 	if (aligned_start < PHYS_OFFSET) {
667571b1437SRussell King 		if (aligned_start + size <= PHYS_OFFSET) {
668571b1437SRussell King 			pr_info("Ignoring memory below PHYS_OFFSET: 0x%08llx-0x%08llx\n",
669571b1437SRussell King 				aligned_start, aligned_start + size);
670571b1437SRussell King 			return -EINVAL;
671571b1437SRussell King 		}
672571b1437SRussell King 
673571b1437SRussell King 		pr_info("Ignoring memory below PHYS_OFFSET: 0x%08llx-0x%08llx\n",
674571b1437SRussell King 			aligned_start, (u64)PHYS_OFFSET);
675571b1437SRussell King 
676571b1437SRussell King 		size -= PHYS_OFFSET - aligned_start;
677571b1437SRussell King 		aligned_start = PHYS_OFFSET;
678571b1437SRussell King 	}
679571b1437SRussell King 
6806d7d5da7SMagnus Damm 	bank->start = aligned_start;
681a5d5f7daSPeter Maydell 	bank->size = size & ~(phys_addr_t)(PAGE_SIZE - 1);
6824b5f32ceSNicolas Pitre 
6834b5f32ceSNicolas Pitre 	/*
6844b5f32ceSNicolas Pitre 	 * Check whether this memory region has non-zero size or
6854b5f32ceSNicolas Pitre 	 * invalid node number.
6864b5f32ceSNicolas Pitre 	 */
687be370302SRussell King 	if (bank->size == 0)
6884b5f32ceSNicolas Pitre 		return -EINVAL;
6894b5f32ceSNicolas Pitre 
6904b5f32ceSNicolas Pitre 	meminfo.nr_banks++;
6914b5f32ceSNicolas Pitre 	return 0;
6923a669411SRussell King }
6933a669411SRussell King 
6941da177e4SLinus Torvalds /*
6951da177e4SLinus Torvalds  * Pick out the memory size.  We look for mem=size@start,
6961da177e4SLinus Torvalds  * where start and size are "size[KkMm]"
6971da177e4SLinus Torvalds  */
6982b0d8c25SJeremy Kerr static int __init early_mem(char *p)
6991da177e4SLinus Torvalds {
7001da177e4SLinus Torvalds 	static int usermem __initdata = 0;
7016a5014aaSMagnus Damm 	u64 size;
7026a5014aaSMagnus Damm 	u64 start;
7032b0d8c25SJeremy Kerr 	char *endp;
7041da177e4SLinus Torvalds 
7051da177e4SLinus Torvalds 	/*
7061da177e4SLinus Torvalds 	 * If the user specifies memory size, we
7071da177e4SLinus Torvalds 	 * blow away any automatically generated
7081da177e4SLinus Torvalds 	 * size.
7091da177e4SLinus Torvalds 	 */
7101da177e4SLinus Torvalds 	if (usermem == 0) {
7111da177e4SLinus Torvalds 		usermem = 1;
7121da177e4SLinus Torvalds 		meminfo.nr_banks = 0;
7131da177e4SLinus Torvalds 	}
7141da177e4SLinus Torvalds 
7151da177e4SLinus Torvalds 	start = PHYS_OFFSET;
7162b0d8c25SJeremy Kerr 	size  = memparse(p, &endp);
7172b0d8c25SJeremy Kerr 	if (*endp == '@')
7182b0d8c25SJeremy Kerr 		start = memparse(endp + 1, NULL);
7191da177e4SLinus Torvalds 
7201c97b73eSAndrew Morton 	arm_add_memory(start, size);
7211da177e4SLinus Torvalds 
7222b0d8c25SJeremy Kerr 	return 0;
7231da177e4SLinus Torvalds }
7242b0d8c25SJeremy Kerr early_param("mem", early_mem);
7251da177e4SLinus Torvalds 
726ff69a4c8SRussell King static void __init request_standard_resources(const struct machine_desc *mdesc)
7271da177e4SLinus Torvalds {
72811b9369cSDima Zavin 	struct memblock_region *region;
7291da177e4SLinus Torvalds 	struct resource *res;
7301da177e4SLinus Torvalds 
73137efe642SRussell King 	kernel_code.start   = virt_to_phys(_text);
73237efe642SRussell King 	kernel_code.end     = virt_to_phys(_etext - 1);
733842eab40SRussell King 	kernel_data.start   = virt_to_phys(_sdata);
73437efe642SRussell King 	kernel_data.end     = virt_to_phys(_end - 1);
7351da177e4SLinus Torvalds 
73611b9369cSDima Zavin 	for_each_memblock(memory, region) {
737ad6492b8SYinghai Lu 		res = memblock_virt_alloc_low(sizeof(*res), 0);
7381da177e4SLinus Torvalds 		res->name  = "System RAM";
73911b9369cSDima Zavin 		res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
74011b9369cSDima Zavin 		res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
7411da177e4SLinus Torvalds 		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
7421da177e4SLinus Torvalds 
7431da177e4SLinus Torvalds 		request_resource(&iomem_resource, res);
7441da177e4SLinus Torvalds 
7451da177e4SLinus Torvalds 		if (kernel_code.start >= res->start &&
7461da177e4SLinus Torvalds 		    kernel_code.end <= res->end)
7471da177e4SLinus Torvalds 			request_resource(res, &kernel_code);
7481da177e4SLinus Torvalds 		if (kernel_data.start >= res->start &&
7491da177e4SLinus Torvalds 		    kernel_data.end <= res->end)
7501da177e4SLinus Torvalds 			request_resource(res, &kernel_data);
7511da177e4SLinus Torvalds 	}
7521da177e4SLinus Torvalds 
7531da177e4SLinus Torvalds 	if (mdesc->video_start) {
7541da177e4SLinus Torvalds 		video_ram.start = mdesc->video_start;
7551da177e4SLinus Torvalds 		video_ram.end   = mdesc->video_end;
7561da177e4SLinus Torvalds 		request_resource(&iomem_resource, &video_ram);
7571da177e4SLinus Torvalds 	}
7581da177e4SLinus Torvalds 
7591da177e4SLinus Torvalds 	/*
7601da177e4SLinus Torvalds 	 * Some machines don't have the possibility of ever
7611da177e4SLinus Torvalds 	 * possessing lp0, lp1 or lp2
7621da177e4SLinus Torvalds 	 */
7631da177e4SLinus Torvalds 	if (mdesc->reserve_lp0)
7641da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp0);
7651da177e4SLinus Torvalds 	if (mdesc->reserve_lp1)
7661da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp1);
7671da177e4SLinus Torvalds 	if (mdesc->reserve_lp2)
7681da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp2);
7691da177e4SLinus Torvalds }
7701da177e4SLinus Torvalds 
7711da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
7721da177e4SLinus Torvalds struct screen_info screen_info = {
7731da177e4SLinus Torvalds  .orig_video_lines	= 30,
7741da177e4SLinus Torvalds  .orig_video_cols	= 80,
7751da177e4SLinus Torvalds  .orig_video_mode	= 0,
7761da177e4SLinus Torvalds  .orig_video_ega_bx	= 0,
7771da177e4SLinus Torvalds  .orig_video_isVGA	= 1,
7781da177e4SLinus Torvalds  .orig_video_points	= 8
7791da177e4SLinus Torvalds };
7801da177e4SLinus Torvalds #endif
7811da177e4SLinus Torvalds 
7821da177e4SLinus Torvalds static int __init customize_machine(void)
7831da177e4SLinus Torvalds {
784883a106bSArnd Bergmann 	/*
785883a106bSArnd Bergmann 	 * customizes platform devices, or adds new ones
786883a106bSArnd Bergmann 	 * On DT based machines, we fall back to populating the
787883a106bSArnd Bergmann 	 * machine from the device tree, if no callback is provided,
788883a106bSArnd Bergmann 	 * otherwise we would always need an init_machine callback.
789883a106bSArnd Bergmann 	 */
7908ff1443cSRussell King 	if (machine_desc->init_machine)
7918ff1443cSRussell King 		machine_desc->init_machine();
792883a106bSArnd Bergmann #ifdef CONFIG_OF
793883a106bSArnd Bergmann 	else
794883a106bSArnd Bergmann 		of_platform_populate(NULL, of_default_bus_match_table,
795883a106bSArnd Bergmann 					NULL, NULL);
796883a106bSArnd Bergmann #endif
7971da177e4SLinus Torvalds 	return 0;
7981da177e4SLinus Torvalds }
7991da177e4SLinus Torvalds arch_initcall(customize_machine);
8001da177e4SLinus Torvalds 
80190de4137SShawn Guo static int __init init_machine_late(void)
80290de4137SShawn Guo {
80390de4137SShawn Guo 	if (machine_desc->init_late)
80490de4137SShawn Guo 		machine_desc->init_late();
80590de4137SShawn Guo 	return 0;
80690de4137SShawn Guo }
80790de4137SShawn Guo late_initcall(init_machine_late);
80890de4137SShawn Guo 
8093c57fb43SMika Westerberg #ifdef CONFIG_KEXEC
8103c57fb43SMika Westerberg static inline unsigned long long get_total_mem(void)
8113c57fb43SMika Westerberg {
8123c57fb43SMika Westerberg 	unsigned long total;
8133c57fb43SMika Westerberg 
8143c57fb43SMika Westerberg 	total = max_low_pfn - min_low_pfn;
8153c57fb43SMika Westerberg 	return total << PAGE_SHIFT;
8163c57fb43SMika Westerberg }
8173c57fb43SMika Westerberg 
8183c57fb43SMika Westerberg /**
8193c57fb43SMika Westerberg  * reserve_crashkernel() - reserves memory are for crash kernel
8203c57fb43SMika Westerberg  *
8213c57fb43SMika Westerberg  * This function reserves memory area given in "crashkernel=" kernel command
8223c57fb43SMika Westerberg  * line parameter. The memory reserved is used by a dump capture kernel when
8233c57fb43SMika Westerberg  * primary kernel is crashing.
8243c57fb43SMika Westerberg  */
8253c57fb43SMika Westerberg static void __init reserve_crashkernel(void)
8263c57fb43SMika Westerberg {
8273c57fb43SMika Westerberg 	unsigned long long crash_size, crash_base;
8283c57fb43SMika Westerberg 	unsigned long long total_mem;
8293c57fb43SMika Westerberg 	int ret;
8303c57fb43SMika Westerberg 
8313c57fb43SMika Westerberg 	total_mem = get_total_mem();
8323c57fb43SMika Westerberg 	ret = parse_crashkernel(boot_command_line, total_mem,
8333c57fb43SMika Westerberg 				&crash_size, &crash_base);
8343c57fb43SMika Westerberg 	if (ret)
8353c57fb43SMika Westerberg 		return;
8363c57fb43SMika Westerberg 
83784f452b1SSantosh Shilimkar 	ret = memblock_reserve(crash_base, crash_size);
8383c57fb43SMika Westerberg 	if (ret < 0) {
8391b0f6681SOlof Johansson 		pr_warn("crashkernel reservation failed - memory is in use (0x%lx)\n",
8401b0f6681SOlof Johansson 			(unsigned long)crash_base);
8413c57fb43SMika Westerberg 		return;
8423c57fb43SMika Westerberg 	}
8433c57fb43SMika Westerberg 
8441b0f6681SOlof Johansson 	pr_info("Reserving %ldMB of memory at %ldMB for crashkernel (System RAM: %ldMB)\n",
8453c57fb43SMika Westerberg 		(unsigned long)(crash_size >> 20),
8463c57fb43SMika Westerberg 		(unsigned long)(crash_base >> 20),
8473c57fb43SMika Westerberg 		(unsigned long)(total_mem >> 20));
8483c57fb43SMika Westerberg 
8493c57fb43SMika Westerberg 	crashk_res.start = crash_base;
8503c57fb43SMika Westerberg 	crashk_res.end = crash_base + crash_size - 1;
8513c57fb43SMika Westerberg 	insert_resource(&iomem_resource, &crashk_res);
8523c57fb43SMika Westerberg }
8533c57fb43SMika Westerberg #else
8543c57fb43SMika Westerberg static inline void reserve_crashkernel(void) {}
8553c57fb43SMika Westerberg #endif /* CONFIG_KEXEC */
8563c57fb43SMika Westerberg 
85727a3f0e9SNicolas Pitre static int __init meminfo_cmp(const void *_a, const void *_b)
85827a3f0e9SNicolas Pitre {
85927a3f0e9SNicolas Pitre 	const struct membank *a = _a, *b = _b;
86027a3f0e9SNicolas Pitre 	long cmp = bank_pfn_start(a) - bank_pfn_start(b);
86127a3f0e9SNicolas Pitre 	return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
86227a3f0e9SNicolas Pitre }
8636291319dSGrant Likely 
8644588c34dSDave Martin void __init hyp_mode_check(void)
8654588c34dSDave Martin {
8664588c34dSDave Martin #ifdef CONFIG_ARM_VIRT_EXT
8678fbac214SMark Rutland 	sync_boot_mode();
8688fbac214SMark Rutland 
8694588c34dSDave Martin 	if (is_hyp_mode_available()) {
8704588c34dSDave Martin 		pr_info("CPU: All CPU(s) started in HYP mode.\n");
8714588c34dSDave Martin 		pr_info("CPU: Virtualization extensions available.\n");
8724588c34dSDave Martin 	} else if (is_hyp_mode_mismatched()) {
8734588c34dSDave Martin 		pr_warn("CPU: WARNING: CPU(s) started in wrong/inconsistent modes (primary CPU mode 0x%x)\n",
8744588c34dSDave Martin 			__boot_cpu_mode & MODE_MASK);
8754588c34dSDave Martin 		pr_warn("CPU: This may indicate a broken bootloader or firmware.\n");
8764588c34dSDave Martin 	} else
8774588c34dSDave Martin 		pr_info("CPU: All CPU(s) started in SVC mode.\n");
8784588c34dSDave Martin #endif
8794588c34dSDave Martin }
8804588c34dSDave Martin 
8816291319dSGrant Likely void __init setup_arch(char **cmdline_p)
8826291319dSGrant Likely {
883ff69a4c8SRussell King 	const struct machine_desc *mdesc;
8846291319dSGrant Likely 
8856291319dSGrant Likely 	setup_processor();
88693c02ab4SGrant Likely 	mdesc = setup_machine_fdt(__atags_pointer);
88793c02ab4SGrant Likely 	if (!mdesc)
888b8b499c8SAlexander Shiyan 		mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type);
8896291319dSGrant Likely 	machine_desc = mdesc;
8906291319dSGrant Likely 	machine_name = mdesc->name;
8916291319dSGrant Likely 
89216d6d5b0SRobin Holt 	if (mdesc->reboot_mode != REBOOT_HARD)
89316d6d5b0SRobin Holt 		reboot_mode = mdesc->reboot_mode;
8946291319dSGrant Likely 
89537efe642SRussell King 	init_mm.start_code = (unsigned long) _text;
89637efe642SRussell King 	init_mm.end_code   = (unsigned long) _etext;
89737efe642SRussell King 	init_mm.end_data   = (unsigned long) _edata;
89837efe642SRussell King 	init_mm.brk	   = (unsigned long) _end;
8991da177e4SLinus Torvalds 
90048ab7e09SJeremy Kerr 	/* populate cmd_line too for later use, preserving boot_command_line */
90148ab7e09SJeremy Kerr 	strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
90248ab7e09SJeremy Kerr 	*cmdline_p = cmd_line;
9032b0d8c25SJeremy Kerr 
9042b0d8c25SJeremy Kerr 	parse_early_param();
9052b0d8c25SJeremy Kerr 
90627a3f0e9SNicolas Pitre 	sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL);
907a77e0c7bSSantosh Shilimkar 
908a77e0c7bSSantosh Shilimkar 	early_paging_init(mdesc, lookup_processor_type(read_cpuid_id()));
9097c927322SSantosh Shilimkar 	setup_dma_zone(mdesc);
9100371d3f7SRussell King 	sanity_check_meminfo();
9118d717a52SRussell King 	arm_memblock_init(&meminfo, mdesc);
9122778f620SRussell King 
9134b5f32ceSNicolas Pitre 	paging_init(mdesc);
91411b9369cSDima Zavin 	request_standard_resources(mdesc);
9151da177e4SLinus Torvalds 
916a528721dSRussell King 	if (mdesc->restart)
917a528721dSRussell King 		arm_pm_restart = mdesc->restart;
918a528721dSRussell King 
91993c02ab4SGrant Likely 	unflatten_device_tree();
92093c02ab4SGrant Likely 
9215587164eSLorenzo Pieralisi 	arm_dt_init_cpu_maps();
92205774088SStefano Stabellini 	psci_init();
9237bbb7940SRussell King #ifdef CONFIG_SMP
924abcee5fbSMarc Zyngier 	if (is_smp()) {
925b382b940SJon Medhurst 		if (!mdesc->smp_init || !mdesc->smp_init()) {
92605774088SStefano Stabellini 			if (psci_smp_available())
92705774088SStefano Stabellini 				smp_set_ops(&psci_smp_ops);
92805774088SStefano Stabellini 			else if (mdesc->smp)
929abcee5fbSMarc Zyngier 				smp_set_ops(mdesc->smp);
930b382b940SJon Medhurst 		}
9317bbb7940SRussell King 		smp_init_cpus();
9328cf72172SLorenzo Pieralisi 		smp_build_mpidr_hash();
933abcee5fbSMarc Zyngier 	}
9347bbb7940SRussell King #endif
9354588c34dSDave Martin 
9364588c34dSDave Martin 	if (!is_smp())
9374588c34dSDave Martin 		hyp_mode_check();
9384588c34dSDave Martin 
9393c57fb43SMika Westerberg 	reserve_crashkernel();
9407bbb7940SRussell King 
94152108641Seric miao #ifdef CONFIG_MULTI_IRQ_HANDLER
94252108641Seric miao 	handle_arch_irq = mdesc->handle_irq;
94352108641Seric miao #endif
9441da177e4SLinus Torvalds 
9451da177e4SLinus Torvalds #ifdef CONFIG_VT
9461da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE)
9471da177e4SLinus Torvalds 	conswitchp = &vga_con;
9481da177e4SLinus Torvalds #elif defined(CONFIG_DUMMY_CONSOLE)
9491da177e4SLinus Torvalds 	conswitchp = &dummy_con;
9501da177e4SLinus Torvalds #endif
9511da177e4SLinus Torvalds #endif
952dec12e62SRussell King 
953dec12e62SRussell King 	if (mdesc->init_early)
954dec12e62SRussell King 		mdesc->init_early();
9551da177e4SLinus Torvalds }
9561da177e4SLinus Torvalds 
9571da177e4SLinus Torvalds 
9581da177e4SLinus Torvalds static int __init topology_init(void)
9591da177e4SLinus Torvalds {
9601da177e4SLinus Torvalds 	int cpu;
9611da177e4SLinus Torvalds 
96266fb8bd2SRussell King 	for_each_possible_cpu(cpu) {
96366fb8bd2SRussell King 		struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu);
96466fb8bd2SRussell King 		cpuinfo->cpu.hotpluggable = 1;
96566fb8bd2SRussell King 		register_cpu(&cpuinfo->cpu, cpu);
96666fb8bd2SRussell King 	}
9671da177e4SLinus Torvalds 
9681da177e4SLinus Torvalds 	return 0;
9691da177e4SLinus Torvalds }
9701da177e4SLinus Torvalds subsys_initcall(topology_init);
9711da177e4SLinus Torvalds 
972e119bfffSRussell King #ifdef CONFIG_HAVE_PROC_CPU
973e119bfffSRussell King static int __init proc_cpu_init(void)
974e119bfffSRussell King {
975e119bfffSRussell King 	struct proc_dir_entry *res;
976e119bfffSRussell King 
977e119bfffSRussell King 	res = proc_mkdir("cpu", NULL);
978e119bfffSRussell King 	if (!res)
979e119bfffSRussell King 		return -ENOMEM;
980e119bfffSRussell King 	return 0;
981e119bfffSRussell King }
982e119bfffSRussell King fs_initcall(proc_cpu_init);
983e119bfffSRussell King #endif
984e119bfffSRussell King 
9851da177e4SLinus Torvalds static const char *hwcap_str[] = {
9861da177e4SLinus Torvalds 	"swp",
9871da177e4SLinus Torvalds 	"half",
9881da177e4SLinus Torvalds 	"thumb",
9891da177e4SLinus Torvalds 	"26bit",
9901da177e4SLinus Torvalds 	"fastmult",
9911da177e4SLinus Torvalds 	"fpa",
9921da177e4SLinus Torvalds 	"vfp",
9931da177e4SLinus Torvalds 	"edsp",
9941da177e4SLinus Torvalds 	"java",
9958f7f9435SPaul Gortmaker 	"iwmmxt",
99699e4a6ddSLennert Buytenhek 	"crunch",
9974369ae16SCatalin Marinas 	"thumbee",
9982bedbdf4SCatalin Marinas 	"neon",
9997279dc3eSCatalin Marinas 	"vfpv3",
10007279dc3eSCatalin Marinas 	"vfpv3d16",
1001254cdf8eSWill Deacon 	"tls",
1002254cdf8eSWill Deacon 	"vfpv4",
1003254cdf8eSWill Deacon 	"idiva",
1004254cdf8eSWill Deacon 	"idivt",
1005ab8d46c0STetsuyuki Kobayashi 	"vfpd32",
1006a469abd0SWill Deacon 	"lpae",
1007e9faebc6SSudeep KarkadaNagesha 	"evtstrm",
10081da177e4SLinus Torvalds 	NULL
10091da177e4SLinus Torvalds };
10101da177e4SLinus Torvalds 
1011b342ea4eSArd Biesheuvel static const char *hwcap2_str[] = {
10128258a989SArd Biesheuvel 	"aes",
10138258a989SArd Biesheuvel 	"pmull",
10148258a989SArd Biesheuvel 	"sha1",
10158258a989SArd Biesheuvel 	"sha2",
10168258a989SArd Biesheuvel 	"crc32",
1017b342ea4eSArd Biesheuvel 	NULL
1018b342ea4eSArd Biesheuvel };
1019b342ea4eSArd Biesheuvel 
10201da177e4SLinus Torvalds static int c_show(struct seq_file *m, void *v)
10211da177e4SLinus Torvalds {
1022b4b8f770SLorenzo Pieralisi 	int i, j;
1023b4b8f770SLorenzo Pieralisi 	u32 cpuid;
10241da177e4SLinus Torvalds 
10251da177e4SLinus Torvalds 	for_each_online_cpu(i) {
102615559722SRussell King 		/*
102715559722SRussell King 		 * glibc reads /proc/cpuinfo to determine the number of
102815559722SRussell King 		 * online processors, looking for lines beginning with
102915559722SRussell King 		 * "processor".  Give glibc what it expects.
103015559722SRussell King 		 */
103115559722SRussell King 		seq_printf(m, "processor\t: %d\n", i);
1032b4b8f770SLorenzo Pieralisi 		cpuid = is_smp() ? per_cpu(cpu_data, i).cpuid : read_cpuid_id();
1033b4b8f770SLorenzo Pieralisi 		seq_printf(m, "model name\t: %s rev %d (%s)\n",
1034b4b8f770SLorenzo Pieralisi 			   cpu_name, cpuid & 15, elf_platform);
1035b4b8f770SLorenzo Pieralisi 
10361da177e4SLinus Torvalds 		/* dump out the processor features */
10371da177e4SLinus Torvalds 		seq_puts(m, "Features\t: ");
10381da177e4SLinus Torvalds 
1039b4b8f770SLorenzo Pieralisi 		for (j = 0; hwcap_str[j]; j++)
1040b4b8f770SLorenzo Pieralisi 			if (elf_hwcap & (1 << j))
1041b4b8f770SLorenzo Pieralisi 				seq_printf(m, "%s ", hwcap_str[j]);
10421da177e4SLinus Torvalds 
1043b342ea4eSArd Biesheuvel 		for (j = 0; hwcap2_str[j]; j++)
1044b342ea4eSArd Biesheuvel 			if (elf_hwcap2 & (1 << j))
1045b342ea4eSArd Biesheuvel 				seq_printf(m, "%s ", hwcap2_str[j]);
1046b342ea4eSArd Biesheuvel 
1047b4b8f770SLorenzo Pieralisi 		seq_printf(m, "\nCPU implementer\t: 0x%02x\n", cpuid >> 24);
1048b4b8f770SLorenzo Pieralisi 		seq_printf(m, "CPU architecture: %s\n",
1049b4b8f770SLorenzo Pieralisi 			   proc_arch[cpu_architecture()]);
10501da177e4SLinus Torvalds 
1051b4b8f770SLorenzo Pieralisi 		if ((cpuid & 0x0008f000) == 0x00000000) {
10521da177e4SLinus Torvalds 			/* pre-ARM7 */
1053b4b8f770SLorenzo Pieralisi 			seq_printf(m, "CPU part\t: %07x\n", cpuid >> 4);
10541da177e4SLinus Torvalds 		} else {
1055b4b8f770SLorenzo Pieralisi 			if ((cpuid & 0x0008f000) == 0x00007000) {
10561da177e4SLinus Torvalds 				/* ARM7 */
10571da177e4SLinus Torvalds 				seq_printf(m, "CPU variant\t: 0x%02x\n",
1058b4b8f770SLorenzo Pieralisi 					   (cpuid >> 16) & 127);
10591da177e4SLinus Torvalds 			} else {
10601da177e4SLinus Torvalds 				/* post-ARM7 */
10611da177e4SLinus Torvalds 				seq_printf(m, "CPU variant\t: 0x%x\n",
1062b4b8f770SLorenzo Pieralisi 					   (cpuid >> 20) & 15);
10631da177e4SLinus Torvalds 			}
10641da177e4SLinus Torvalds 			seq_printf(m, "CPU part\t: 0x%03x\n",
1065b4b8f770SLorenzo Pieralisi 				   (cpuid >> 4) & 0xfff);
10661da177e4SLinus Torvalds 		}
1067b4b8f770SLorenzo Pieralisi 		seq_printf(m, "CPU revision\t: %d\n\n", cpuid & 15);
1068b4b8f770SLorenzo Pieralisi 	}
10691da177e4SLinus Torvalds 
10701da177e4SLinus Torvalds 	seq_printf(m, "Hardware\t: %s\n", machine_name);
10711da177e4SLinus Torvalds 	seq_printf(m, "Revision\t: %04x\n", system_rev);
10721da177e4SLinus Torvalds 	seq_printf(m, "Serial\t\t: %08x%08x\n",
10731da177e4SLinus Torvalds 		   system_serial_high, system_serial_low);
10741da177e4SLinus Torvalds 
10751da177e4SLinus Torvalds 	return 0;
10761da177e4SLinus Torvalds }
10771da177e4SLinus Torvalds 
10781da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos)
10791da177e4SLinus Torvalds {
10801da177e4SLinus Torvalds 	return *pos < 1 ? (void *)1 : NULL;
10811da177e4SLinus Torvalds }
10821da177e4SLinus Torvalds 
10831da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos)
10841da177e4SLinus Torvalds {
10851da177e4SLinus Torvalds 	++*pos;
10861da177e4SLinus Torvalds 	return NULL;
10871da177e4SLinus Torvalds }
10881da177e4SLinus Torvalds 
10891da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v)
10901da177e4SLinus Torvalds {
10911da177e4SLinus Torvalds }
10921da177e4SLinus Torvalds 
10932ffd6e18SJan Engelhardt const struct seq_operations cpuinfo_op = {
10941da177e4SLinus Torvalds 	.start	= c_start,
10951da177e4SLinus Torvalds 	.next	= c_next,
10961da177e4SLinus Torvalds 	.stop	= c_stop,
10971da177e4SLinus Torvalds 	.show	= c_show
10981da177e4SLinus Torvalds };
1099