753 lines · 19.9 KB · C
RawDownload
/* *  * Common boot and setup code. * * Copyright (C) 2001 PPC64 Team, IBM Corp * *      This program is free software; you can redistribute it and/or *      modify it under the terms of the GNU General Public License *      as published by the Free Software Foundation; either version *      2 of the License, or (at your option) any later version. */ #define DEBUG #include <linux/export.h>#include <linux/string.h>#include <linux/sched.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/reboot.h>#include <linux/delay.h>#include <linux/initrd.h>#include <linux/seq_file.h>#include <linux/ioport.h>#include <linux/console.h>#include <linux/utsname.h>#include <linux/tty.h>#include <linux/root_dev.h>#include <linux/notifier.h>#include <linux/cpu.h>#include <linux/unistd.h>#include <linux/serial.h>#include <linux/serial_8250.h>#include <linux/bootmem.h>#include <linux/pci.h>#include <linux/lockdep.h>#include <linux/memblock.h>#include <linux/memory.h>#include <linux/nmi.h> #include <asm/io.h>#include <asm/kdump.h>#include <asm/prom.h>#include <asm/processor.h>#include <asm/pgtable.h>#include <asm/smp.h>#include <asm/elf.h>#include <asm/machdep.h>#include <asm/paca.h>#include <asm/time.h>#include <asm/cputable.h>#include <asm/dt_cpu_ftrs.h>#include <asm/sections.h>#include <asm/btext.h>#include <asm/nvram.h>#include <asm/setup.h>#include <asm/rtas.h>#include <asm/iommu.h>#include <asm/serial.h>#include <asm/cache.h>#include <asm/page.h>#include <asm/mmu.h>#include <asm/firmware.h>#include <asm/xmon.h>#include <asm/udbg.h>#include <asm/kexec.h>#include <asm/code-patching.h>#include <asm/livepatch.h>#include <asm/opal.h>#include <asm/cputhreads.h> #ifdef DEBUG#define DBG(fmt...) udbg_printf(fmt)#else#define DBG(fmt...)#endif int spinning_secondaries;u64 ppc64_pft_size; struct ppc64_caches ppc64_caches = {	.l1d = {		.block_size = 0x40,		.log_block_size = 6,	},	.l1i = {		.block_size = 0x40,		.log_block_size = 6	},};EXPORT_SYMBOL_GPL(ppc64_caches); #if defined(CONFIG_PPC_BOOK3E) && defined(CONFIG_SMP)void __init setup_tlb_core_data(void){	int cpu; 	BUILD_BUG_ON(offsetof(struct tlb_core_data, lock) != 0); 	for_each_possible_cpu(cpu) {		int first = cpu_first_thread_sibling(cpu); 		/*		 * If we boot via kdump on a non-primary thread,		 * make sure we point at the thread that actually		 * set up this TLB.		 */		if (cpu_first_thread_sibling(boot_cpuid) == first)			first = boot_cpuid; 		paca[cpu].tcd_ptr = &paca[first].tcd; 		/*		 * If we have threads, we need either tlbsrx.		 * or e6500 tablewalk mode, or else TLB handlers		 * will be racy and could produce duplicate entries.		 * Should we panic instead?		 */		WARN_ONCE(smt_enabled_at_boot >= 2 &&			  !mmu_has_feature(MMU_FTR_USE_TLBRSRV) &&			  book3e_htw_mode != PPC_HTW_E6500,			  "%s: unsupported MMU configuration\n", __func__);	}}#endif #ifdef CONFIG_SMP static char *smt_enabled_cmdline; /* Look for ibm,smt-enabled OF option */void __init check_smt_enabled(void){	struct device_node *dn;	const char *smt_option; 	/* Default to enabling all threads */	smt_enabled_at_boot = threads_per_core; 	/* Allow the command line to overrule the OF option */	if (smt_enabled_cmdline) {		if (!strcmp(smt_enabled_cmdline, "on"))			smt_enabled_at_boot = threads_per_core;		else if (!strcmp(smt_enabled_cmdline, "off"))			smt_enabled_at_boot = 0;		else {			int smt;			int rc; 			rc = kstrtoint(smt_enabled_cmdline, 10, &smt);			if (!rc)				smt_enabled_at_boot =					min(threads_per_core, smt);		}	} else {		dn = of_find_node_by_path("/options");		if (dn) {			smt_option = of_get_property(dn, "ibm,smt-enabled",						     NULL); 			if (smt_option) {				if (!strcmp(smt_option, "on"))					smt_enabled_at_boot = threads_per_core;				else if (!strcmp(smt_option, "off"))					smt_enabled_at_boot = 0;			} 			of_node_put(dn);		}	}} /* Look for smt-enabled= cmdline option */static int __init early_smt_enabled(char *p){	smt_enabled_cmdline = p;	return 0;}early_param("smt-enabled", early_smt_enabled); #endif /* CONFIG_SMP */ /** Fix up paca fields required for the boot cpu */static void __init fixup_boot_paca(void){	/* The boot cpu is started */	get_paca()->cpu_start = 1;	/* Allow percpu accesses to work until we setup percpu data */	get_paca()->data_offset = 0;} static void __init configure_exceptions(void){	/*	 * Setup the trampolines from the lowmem exception vectors	 * to the kdump kernel when not using a relocatable kernel.	 */	setup_kdump_trampoline(); 	/* Under a PAPR hypervisor, we need hypercalls */	if (firmware_has_feature(FW_FEATURE_SET_MODE)) {		/* Enable AIL if possible */		pseries_enable_reloc_on_exc(); 		/*		 * Tell the hypervisor that we want our exceptions to		 * be taken in little endian mode.		 *		 * We don't call this for big endian as our calling convention		 * makes us always enter in BE, and the call may fail under		 * some circumstances with kdump.		 */#ifdef __LITTLE_ENDIAN__		pseries_little_endian_exceptions();#endif	} else {		/* Set endian mode using OPAL */		if (firmware_has_feature(FW_FEATURE_OPAL))			opal_configure_cores(); 		/* AIL on native is done in cpu_ready_for_interrupts() */	}} static void cpu_ready_for_interrupts(void){	/*	 * Enable AIL if supported, and we are in hypervisor mode. This	 * is called once for every processor.	 *	 * If we are not in hypervisor mode the job is done once for	 * the whole partition in configure_exceptions().	 */	if (cpu_has_feature(CPU_FTR_HVMODE) &&	    cpu_has_feature(CPU_FTR_ARCH_207S)) {		unsigned long lpcr = mfspr(SPRN_LPCR);		mtspr(SPRN_LPCR, lpcr | LPCR_AIL_3);	} 	/*	 * Fixup HFSCR:TM based on CPU features. The bit is set by our	 * early asm init because at that point we haven't updated our	 * CPU features from firmware and device-tree. Here we have,	 * so let's do it.	 */	if (cpu_has_feature(CPU_FTR_HVMODE) && !cpu_has_feature(CPU_FTR_TM_COMP))		mtspr(SPRN_HFSCR, mfspr(SPRN_HFSCR) & ~HFSCR_TM); 	/* Set IR and DR in PACA MSR */	get_paca()->kernel_msr = MSR_KERNEL;} /* * Early initialization entry point. This is called by head.S * with MMU translation disabled. We rely on the "feature" of * the CPU that ignores the top 2 bits of the address in real * mode so we can access kernel globals normally provided we * only toy with things in the RMO region. From here, we do * some early parsing of the device-tree to setup out MEMBLOCK * data structures, and allocate & initialize the hash table * and segment tables so we can start running with translation * enabled. * * It is this function which will call the probe() callback of * the various platform types and copy the matching one to the * global ppc_md structure. Your platform can eventually do * some very early initializations from the probe() routine, but * this is not recommended, be very careful as, for example, the * device-tree is not accessible via normal means at this point. */ void __init early_setup(unsigned long dt_ptr){	static __initdata struct paca_struct boot_paca; 	/* -------- printk is _NOT_ safe to use here ! ------- */ 	/* Try new device tree based feature discovery ... */	if (!dt_cpu_ftrs_init(__va(dt_ptr)))		/* Otherwise use the old style CPU table */		identify_cpu(0, mfspr(SPRN_PVR)); 	/* Assume we're on cpu 0 for now. Don't write to the paca yet! */	initialise_paca(&boot_paca, 0);	setup_paca(&boot_paca);	fixup_boot_paca(); 	/* -------- printk is now safe to use ------- */ 	/* Enable early debugging if any specified (see udbg.h) */	udbg_early_init();  	DBG(" -> early_setup(), dt_ptr: 0x%lx\n", dt_ptr); 	/*	 * Do early initialization using the flattened device	 * tree, such as retrieving the physical memory map or	 * calculating/retrieving the hash table size.	 */	early_init_devtree(__va(dt_ptr)); 	/* Now we know the logical id of our boot cpu, setup the paca. */	setup_paca(&paca[boot_cpuid]);	fixup_boot_paca(); 	/*	 * Configure exception handlers. This include setting up trampolines	 * if needed, setting exception endian mode, etc...	 */	configure_exceptions(); 	/* Apply all the dynamic patching */	apply_feature_fixups();	setup_feature_keys(); 	/* Initialize the hash table or TLB handling */	early_init_mmu(); 	/*	 * At this point, we can let interrupts switch to virtual mode	 * (the MMU has been setup), so adjust the MSR in the PACA to	 * have IR and DR set and enable AIL if it exists	 */	cpu_ready_for_interrupts(); 	DBG(" <- early_setup()\n"); #ifdef CONFIG_PPC_EARLY_DEBUG_BOOTX	/*	 * This needs to be done *last* (after the above DBG() even)	 *	 * Right after we return from this function, we turn on the MMU	 * which means the real-mode access trick that btext does will	 * no longer work, it needs to switch to using a real MMU	 * mapping. This call will ensure that it does	 */	btext_map();#endif /* CONFIG_PPC_EARLY_DEBUG_BOOTX */} #ifdef CONFIG_SMPvoid early_setup_secondary(void){	/* Mark interrupts disabled in PACA */	get_paca()->soft_enabled = 0; 	/* Initialize the hash table or TLB handling */	early_init_mmu_secondary(); 	/*	 * At this point, we can let interrupts switch to virtual mode	 * (the MMU has been setup), so adjust the MSR in the PACA to	 * have IR and DR set.	 */	cpu_ready_for_interrupts();} #endif /* CONFIG_SMP */ #if defined(CONFIG_SMP) || defined(CONFIG_KEXEC_CORE)static bool use_spinloop(void){	if (!IS_ENABLED(CONFIG_PPC_BOOK3E))		return true; 	/*	 * When book3e boots from kexec, the ePAPR spin table does	 * not get used.	 */	return of_property_read_bool(of_chosen, "linux,booted-from-kexec");} void smp_release_cpus(void){	unsigned long *ptr;	int i; 	if (!use_spinloop())		return; 	DBG(" -> smp_release_cpus()\n"); 	/* All secondary cpus are spinning on a common spinloop, release them	 * all now so they can start to spin on their individual paca	 * spinloops. For non SMP kernels, the secondary cpus never get out	 * of the common spinloop.	 */ 	ptr  = (unsigned long *)((unsigned long)&__secondary_hold_spinloop			- PHYSICAL_START);	*ptr = ppc_function_entry(generic_secondary_smp_init); 	/* And wait a bit for them to catch up */	for (i = 0; i < 100000; i++) {		mb();		HMT_low();		if (spinning_secondaries == 0)			break;		udelay(1);	}	DBG("spinning_secondaries = %d\n", spinning_secondaries); 	DBG(" <- smp_release_cpus()\n");}#endif /* CONFIG_SMP || CONFIG_KEXEC_CORE */ /* * Initialize some remaining members of the ppc64_caches and systemcfg * structures * (at least until we get rid of them completely). This is mostly some * cache informations about the CPU that will be used by cache flush * routines and/or provided to userland */ static void init_cache_info(struct ppc_cache_info *info, u32 size, u32 lsize,			    u32 bsize, u32 sets){	info->size = size;	info->sets = sets;	info->line_size = lsize;	info->block_size = bsize;	info->log_block_size = __ilog2(bsize);	if (bsize)		info->blocks_per_page = PAGE_SIZE / bsize;	else		info->blocks_per_page = 0; 	if (sets == 0)		info->assoc = 0xffff;	else		info->assoc = size / (sets * lsize);} static bool __init parse_cache_info(struct device_node *np,				    bool icache,				    struct ppc_cache_info *info){	static const char *ipropnames[] __initdata = {		"i-cache-size",		"i-cache-sets",		"i-cache-block-size",		"i-cache-line-size",	};	static const char *dpropnames[] __initdata = {		"d-cache-size",		"d-cache-sets",		"d-cache-block-size",		"d-cache-line-size",	};	const char **propnames = icache ? ipropnames : dpropnames;	const __be32 *sizep, *lsizep, *bsizep, *setsp;	u32 size, lsize, bsize, sets;	bool success = true; 	size = 0;	sets = -1u;	lsize = bsize = cur_cpu_spec->dcache_bsize;	sizep = of_get_property(np, propnames[0], NULL);	if (sizep != NULL)		size = be32_to_cpu(*sizep);	setsp = of_get_property(np, propnames[1], NULL);	if (setsp != NULL)		sets = be32_to_cpu(*setsp);	bsizep = of_get_property(np, propnames[2], NULL);	lsizep = of_get_property(np, propnames[3], NULL);	if (bsizep == NULL)		bsizep = lsizep;	if (lsizep != NULL)		lsize = be32_to_cpu(*lsizep);	if (bsizep != NULL)		bsize = be32_to_cpu(*bsizep);	if (sizep == NULL || bsizep == NULL || lsizep == NULL)		success = false; 	/*	 * OF is weird .. it represents fully associative caches	 * as "1 way" which doesn't make much sense and doesn't	 * leave room for direct mapped. We'll assume that 0	 * in OF means direct mapped for that reason.	 */	if (sets == 1)		sets = 0;	else if (sets == 0)		sets = 1; 	init_cache_info(info, size, lsize, bsize, sets); 	return success;} void __init initialize_cache_info(void){	struct device_node *cpu = NULL, *l2, *l3 = NULL;	u32 pvr; 	DBG(" -> initialize_cache_info()\n"); 	/*	 * All shipping POWER8 machines have a firmware bug that	 * puts incorrect information in the device-tree. This will

Lines 1–500 of 753.