1132 lines · 26.1 KB · C
RawDownload
/* *  linux/arch/arm/kernel/setup.c * *  Copyright (C) 1995-2001 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <linux/export.h>#include <linux/kernel.h>#include <linux/stddef.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/utsname.h>#include <linux/initrd.h>#include <linux/console.h>#include <linux/bootmem.h>#include <linux/seq_file.h>#include <linux/screen_info.h>#include <linux/init.h>#include <linux/kexec.h>#include <linux/of_fdt.h>#include <linux/root_dev.h>#include <linux/cpu.h>#include <linux/interrupt.h>#include <linux/smp.h>#include <linux/fs.h>#include <linux/proc_fs.h>#include <linux/memblock.h>#include <linux/bug.h>#include <linux/compiler.h>#include <linux/sort.h> #include <asm/unified.h>#include <asm/cp15.h>#include <asm/cpu.h>#include <asm/cputype.h>#include <asm/elf.h>#include <asm/procinfo.h>#include <asm/sections.h>#include <asm/setup.h>#include <asm/smp_plat.h>#include <asm/mach-types.h>#include <asm/cacheflush.h>#include <asm/cachetype.h>#include <asm/tlbflush.h> #include <asm/prom.h>#include <asm/mach/arch.h>#include <asm/mach/irq.h>#include <asm/mach/time.h>#include <asm/system_info.h>#include <asm/system_misc.h>#include <asm/traps.h>#include <asm/unwind.h>#include <asm/memblock.h> #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)#include "compat.h"#endif#include "atags.h"#include "tcm.h" #ifndef MEM_SIZE#define MEM_SIZE	(16*1024*1024)#endif #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)char fpe_type[8]; static int __init fpe_setup(char *line){	memcpy(fpe_type, line, 8);	return 1;} __setup("fpe=", fpe_setup);#endif extern void paging_init(struct machine_desc *desc);extern void sanity_check_meminfo(void);extern void reboot_setup(char *str); unsigned int processor_id;EXPORT_SYMBOL(processor_id);unsigned int __machine_arch_type __read_mostly;EXPORT_SYMBOL(__machine_arch_type);unsigned int cacheid __read_mostly;EXPORT_SYMBOL(cacheid); unsigned int __atags_pointer __initdata; unsigned int system_rev;EXPORT_SYMBOL(system_rev); unsigned int system_serial_low;EXPORT_SYMBOL(system_serial_low); unsigned int system_serial_high;EXPORT_SYMBOL(system_serial_high); unsigned int elf_hwcap __read_mostly;EXPORT_SYMBOL(elf_hwcap);  #ifdef MULTI_CPUstruct processor processor __read_mostly;#endif#ifdef MULTI_TLBstruct cpu_tlb_fns cpu_tlb __read_mostly;#endif#ifdef MULTI_USERstruct cpu_user_fns cpu_user __read_mostly;#endif#ifdef MULTI_CACHEstruct cpu_cache_fns cpu_cache __read_mostly;#endif#ifdef CONFIG_OUTER_CACHEstruct outer_cache_fns outer_cache __read_mostly;EXPORT_SYMBOL(outer_cache);#endif /* * Cached cpu_architecture() result for use by assembler code. * C code should use the cpu_architecture() function instead of accessing this * variable directly. */int __cpu_architecture __read_mostly = CPU_ARCH_UNKNOWN; struct stack {	u32 irq[3];	u32 abt[3];	u32 und[3];} ____cacheline_aligned; static struct stack stacks[NR_CPUS]; char elf_platform[ELF_PLATFORM_SIZE];EXPORT_SYMBOL(elf_platform); static const char *cpu_name;static const char *machine_name;static char __initdata cmd_line[COMMAND_LINE_SIZE];struct machine_desc *machine_desc __initdata; static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };#define ENDIANNESS ((char)endian_test.l) DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data); /* * Standard memory resources */static struct resource mem_res[] = {	{		.name = "Video RAM",		.start = 0,		.end = 0,		.flags = IORESOURCE_MEM	},	{		.name = "Kernel code",		.start = 0,		.end = 0,		.flags = IORESOURCE_MEM	},	{		.name = "Kernel data",		.start = 0,		.end = 0,		.flags = IORESOURCE_MEM	}}; #define video_ram   mem_res[0]#define kernel_code mem_res[1]#define kernel_data mem_res[2] static struct resource io_res[] = {	{		.name = "reserved",		.start = 0x3bc,		.end = 0x3be,		.flags = IORESOURCE_IO | IORESOURCE_BUSY	},	{		.name = "reserved",		.start = 0x378,		.end = 0x37f,		.flags = IORESOURCE_IO | IORESOURCE_BUSY	},	{		.name = "reserved",		.start = 0x278,		.end = 0x27f,		.flags = IORESOURCE_IO | IORESOURCE_BUSY	}}; #define lp0 io_res[0]#define lp1 io_res[1]#define lp2 io_res[2] static const char *proc_arch[] = {	"undefined/unknown",	"3",	"4",	"4T",	"5",	"5T",	"5TE",	"5TEJ",	"6TEJ",	"7",	"?(11)",	"?(12)",	"?(13)",	"?(14)",	"?(15)",	"?(16)",	"?(17)",}; static int __get_cpu_architecture(void){	int cpu_arch; 	if ((read_cpuid_id() & 0x0008f000) == 0) {		cpu_arch = CPU_ARCH_UNKNOWN;	} else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {		cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;	} else if ((read_cpuid_id() & 0x00080000) == 0x00000000) {		cpu_arch = (read_cpuid_id() >> 16) & 7;		if (cpu_arch)			cpu_arch += CPU_ARCH_ARMv3;	} else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {		unsigned int mmfr0; 		/* Revised CPUID format. Read the Memory Model Feature		 * Register 0 and check for VMSAv7 or PMSAv7 */		asm("mrc	p15, 0, %0, c0, c1, 4"		    : "=r" (mmfr0));		if ((mmfr0 & 0x0000000f) >= 0x00000003 ||		    (mmfr0 & 0x000000f0) >= 0x00000030)			cpu_arch = CPU_ARCH_ARMv7;		else if ((mmfr0 & 0x0000000f) == 0x00000002 ||			 (mmfr0 & 0x000000f0) == 0x00000020)			cpu_arch = CPU_ARCH_ARMv6;		else			cpu_arch = CPU_ARCH_UNKNOWN;	} else		cpu_arch = CPU_ARCH_UNKNOWN; 	return cpu_arch;} int __pure cpu_architecture(void){	BUG_ON(__cpu_architecture == CPU_ARCH_UNKNOWN); 	return __cpu_architecture;} static int cpu_has_aliasing_icache(unsigned int arch){	int aliasing_icache;	unsigned int id_reg, num_sets, line_size; 	/* PIPT caches never alias. */	if (icache_is_pipt())		return 0; 	/* arch specifies the register format */	switch (arch) {	case CPU_ARCH_ARMv7:		asm("mcr	p15, 2, %0, c0, c0, 0 @ set CSSELR"		    : /* No output operands */		    : "r" (1));		isb();		asm("mrc	p15, 1, %0, c0, c0, 0 @ read CCSIDR"		    : "=r" (id_reg));		line_size = 4 << ((id_reg & 0x7) + 2);		num_sets = ((id_reg >> 13) & 0x7fff) + 1;		aliasing_icache = (line_size * num_sets) > PAGE_SIZE;		break;	case CPU_ARCH_ARMv6:		aliasing_icache = read_cpuid_cachetype() & (1 << 11);		break;	default:		/* I-cache aliases will be handled by D-cache aliasing code */		aliasing_icache = 0;	} 	return aliasing_icache;} static void __init cacheid_init(void){	unsigned int cachetype = read_cpuid_cachetype();	unsigned int arch = cpu_architecture(); 	if (arch >= CPU_ARCH_ARMv6) {		if ((cachetype & (7 << 29)) == 4 << 29) {			/* ARMv7 register format */			arch = CPU_ARCH_ARMv7;			cacheid = CACHEID_VIPT_NONALIASING;			switch (cachetype & (3 << 14)) {			case (1 << 14):				cacheid |= CACHEID_ASID_TAGGED;				break;			case (3 << 14):				cacheid |= CACHEID_PIPT;				break;			}		} else {			arch = CPU_ARCH_ARMv6;			if (cachetype & (1 << 23))				cacheid = CACHEID_VIPT_ALIASING;			else				cacheid = CACHEID_VIPT_NONALIASING;		}		if (cpu_has_aliasing_icache(arch))			cacheid |= CACHEID_VIPT_I_ALIASING;	} else {		cacheid = CACHEID_VIVT;	} 	printk("CPU: %s data cache, %s instruction cache\n",		cache_is_vivt() ? "VIVT" :		cache_is_vipt_aliasing() ? "VIPT aliasing" :		cache_is_vipt_nonaliasing() ? "PIPT / VIPT nonaliasing" : "unknown",		cache_is_vivt() ? "VIVT" :		icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :		icache_is_vipt_aliasing() ? "VIPT aliasing" :		icache_is_pipt() ? "PIPT" :		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");} /* * These functions re-use the assembly code in head.S, which * already provide the required functionality. */extern struct proc_info_list *lookup_processor_type(unsigned int); void __init early_print(const char *str, ...){	extern void printascii(const char *);	char buf[256];	va_list ap; 	va_start(ap, str);	vsnprintf(buf, sizeof(buf), str, ap);	va_end(ap); #ifdef CONFIG_DEBUG_LL	printascii(buf);#endif	printk("%s", buf);} static void __init feat_v6_fixup(void){	int id = read_cpuid_id(); 	if ((id & 0xff0f0000) != 0x41070000)		return; 	/*	 * HWCAP_TLS is available only on 1136 r1p0 and later,	 * see also kuser_get_tls_init.	 */	if ((((id >> 4) & 0xfff) == 0xb36) && (((id >> 20) & 3) == 0))		elf_hwcap &= ~HWCAP_TLS;} /* * cpu_init - initialise one CPU. * * cpu_init sets up the per-CPU stacks. */void cpu_init(void){	unsigned int cpu = smp_processor_id();	struct stack *stk = &stacks[cpu]; 	if (cpu >= NR_CPUS) {		printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);		BUG();	} 	cpu_proc_init(); 	/*	 * Define the placement constraint for the inline asm directive below.	 * In Thumb-2, msr with an immediate value is not allowed.	 */#ifdef CONFIG_THUMB2_KERNEL#define PLC	"r"#else#define PLC	"I"#endif 	/*	 * setup stacks for re-entrant exception handlers	 */	__asm__ (	"msr	cpsr_c, %1\n\t"	"add	r14, %0, %2\n\t"	"mov	sp, r14\n\t"	"msr	cpsr_c, %3\n\t"	"add	r14, %0, %4\n\t"	"mov	sp, r14\n\t"	"msr	cpsr_c, %5\n\t"	"add	r14, %0, %6\n\t"	"mov	sp, r14\n\t"	"msr	cpsr_c, %7"	    :	    : "r" (stk),	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),	      "I" (offsetof(struct stack, irq[0])),	      PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),	      "I" (offsetof(struct stack, abt[0])),	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),	      "I" (offsetof(struct stack, und[0])),	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)	    : "r14");} int __cpu_logical_map[NR_CPUS]; void __init smp_setup_processor_id(void){	int i;	u32 cpu = is_smp() ? read_cpuid_mpidr() & 0xff : 0; 	cpu_logical_map(0) = cpu;	for (i = 1; i < NR_CPUS; ++i)		cpu_logical_map(i) = i == cpu ? 0 : i; 	printk(KERN_INFO "Booting Linux on physical CPU %d\n", cpu);} static void __init setup_processor(void){	struct proc_info_list *list; 	/*	 * locate processor in the list of supported processor	 * types.  The linker builds this table for us from the	 * entries in arch/arm/mm/proc-*.S	 */	list = lookup_processor_type(read_cpuid_id());	if (!list) {		printk("CPU configuration botched (ID %08x), unable "		       "to continue.\n", read_cpuid_id());		while (1);	} 	cpu_name = list->cpu_name;	__cpu_architecture = __get_cpu_architecture(); #ifdef MULTI_CPU	processor = *list->proc;#endif#ifdef MULTI_TLB	cpu_tlb = *list->tlb;#endif#ifdef MULTI_USER	cpu_user = *list->user;#endif#ifdef MULTI_CACHE	cpu_cache = *list->cache;#endif 	printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",	       cpu_name, read_cpuid_id(), read_cpuid_id() & 15,	       proc_arch[cpu_architecture()], cr_alignment); 	snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c",		 list->arch_name, ENDIANNESS);	snprintf(elf_platform, ELF_PLATFORM_SIZE, "%s%c",		 list->elf_name, ENDIANNESS);	elf_hwcap = list->elf_hwcap;#ifndef CONFIG_ARM_THUMB	elf_hwcap &= ~HWCAP_THUMB;#endif 	feat_v6_fixup(); 	cacheid_init();	cpu_init();} void __init dump_machine_table(void){	struct machine_desc *p; 	early_print("Available machine support:\n\nID (hex)\tNAME\n");

Lines 1–500 of 1132.