1035 lines · 24.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/module.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/crash_dump.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 <asm/unified.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/mach/arch.h>#include <asm/mach/irq.h>#include <asm/mach/time.h>#include <asm/traps.h>#include <asm/unwind.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 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 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 text",		.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)",}; int 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;} static int cpu_has_aliasing_icache(unsigned int arch){	int aliasing_icache;	unsigned int id_reg, num_sets, line_size; 	/* 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 */			cacheid = CACHEID_VIPT_NONALIASING;			if ((cachetype & (3 << 14)) == 1 << 14)				cacheid |= CACHEID_ASID_TAGGED;			else if (cpu_has_aliasing_icache(CPU_ARCH_ARMv7))				cacheid |= CACHEID_VIPT_I_ALIASING;		} else if (cachetype & (1 << 23)) {			cacheid = CACHEID_VIPT_ALIASING;		} else {			cacheid = CACHEID_VIPT_NONALIASING;			if (cpu_has_aliasing_icache(CPU_ARCH_ARMv6))				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() ? "VIPT nonaliasing" : "unknown",		cache_is_vivt() ? "VIVT" :		icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :		icache_is_vipt_aliasing() ? "VIPT aliasing" :		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); static 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;} 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; #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); 	sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS);	sprintf(elf_platform, "%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_proc_init();} /* * 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();	} 	/*	 * 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");} static struct machine_desc * __init setup_machine(unsigned int nr){	extern struct machine_desc __arch_info_begin[], __arch_info_end[];	struct machine_desc *p; 	/*	 * locate machine in the list of supported machines.	 */	for (p = __arch_info_begin; p < __arch_info_end; p++)		if (nr == p->nr) {			printk("Machine: %s\n", p->name);			return p;		} 	early_print("\n"		"Error: unrecognized/unsupported machine ID (r1 = 0x%08x).\n\n"		"Available machine support:\n\nID (hex)\tNAME\n", nr); 	for (p = __arch_info_begin; p < __arch_info_end; p++)		early_print("%08x\t%s\n", p->nr, p->name); 	early_print("\nPlease check your kernel config and/or bootloader.\n"); 	while (true)		/* can't use cpu_relax() here as it may require MMU setup */;} static int __init arm_add_memory(phys_addr_t start, unsigned long size){	struct membank *bank = &meminfo.bank[meminfo.nr_banks]; 	if (meminfo.nr_banks >= NR_BANKS) {		printk(KERN_CRIT "NR_BANKS too low, "			"ignoring memory at 0x%08llx\n", (long long)start);		return -EINVAL;	} 	/*	 * Ensure that start/size are aligned to a page boundary.	 * Size is appropriately rounded down, start is rounded up.	 */	size -= start & ~PAGE_MASK;	bank->start = PAGE_ALIGN(start);	bank->size  = size & PAGE_MASK; 	/*	 * Check whether this memory region has non-zero size or	 * invalid node number.	 */	if (bank->size == 0)		return -EINVAL; 	meminfo.nr_banks++;	return 0;} /* * Pick out the memory size.  We look for mem=size@start, * where start and size are "size[KkMm]"

Lines 1–500 of 1035.