1373 lines · 34.7 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* *  linux/arch/alpha/kernel/setup.c * *  Copyright (C) 1995  Linus Torvalds */ /* 2.3.x bootmem, 1999 Andrea Arcangeli <andrea@suse.de> */ /* * Bootup setup stuff. */ #include <linux/sched.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/stddef.h>#include <linux/unistd.h>#include <linux/ptrace.h>#include <linux/slab.h>#include <linux/user.h>#include <linux/screen_info.h>#include <linux/delay.h>#include <linux/mc146818rtc.h>#include <linux/console.h>#include <linux/cpu.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/string.h>#include <linux/ioport.h>#include <linux/panic_notifier.h>#include <linux/platform_device.h>#include <linux/memblock.h>#include <linux/pci.h>#include <linux/seq_file.h>#include <linux/root_dev.h>#include <linux/initrd.h>#include <linux/eisa.h>#include <linux/pfn.h>#ifdef CONFIG_MAGIC_SYSRQ#include <linux/sysrq.h>#include <linux/reboot.h>#endif#include <linux/notifier.h>#include <asm/setup.h>#include <asm/io.h>#include <linux/log2.h>#include <linux/export.h> static int alpha_panic_event(struct notifier_block *, unsigned long, void *);static struct notifier_block alpha_panic_block = {	alpha_panic_event,        NULL,        INT_MAX /* try to do it first */}; #include <linux/uaccess.h>#include <asm/hwrpb.h>#include <asm/dma.h>#include <asm/mmu_context.h>#include <asm/console.h> #include "proto.h"#include "pci_impl.h"  struct hwrpb_struct *hwrpb;EXPORT_SYMBOL(hwrpb);unsigned long srm_hae; int alpha_l1i_cacheshape;int alpha_l1d_cacheshape;int alpha_l2_cacheshape;int alpha_l3_cacheshape; #ifdef CONFIG_VERBOSE_MCHECK/* 0=minimum, 1=verbose, 2=all *//* These can be overridden via the command line, ie "verbose_mcheck=2") */unsigned long alpha_verbose_mcheck = CONFIG_VERBOSE_MCHECK_ON;#endif /* Which processor we booted from.  */int boot_cpuid; /* * Using SRM callbacks for initial console output. This works from * setup_arch() time through the end of time_init(), as those places * are under our (Alpha) control.  * "srmcons" specified in the boot command arguments allows us to * see kernel messages during the period of time before the true * console device is "registered" during console_init().  * As of this version (2.5.59), console_init() will call * disable_early_printk() as the last action before initializing * the console drivers. That's the last possible time srmcons can be  * unregistered without interfering with console behavior. * * By default, OFF; set it with a bootcommand arg of "srmcons" or  * "console=srm". The meaning of these two args is: *     "srmcons"     - early callback prints  *     "console=srm" - full callback based console, including early prints */int srmcons_output = 0; /* Enforce a memory size limit; useful for testing. By default, none. */unsigned long mem_size_limit = 0; /* Set AGP GART window size (0 means disabled). */unsigned long alpha_agpgart_size = DEFAULT_AGP_APER_SIZE; #ifdef CONFIG_ALPHA_GENERICstruct alpha_machine_vector alpha_mv;EXPORT_SYMBOL(alpha_mv);#endif #ifndef alpha_using_srmint alpha_using_srm;EXPORT_SYMBOL(alpha_using_srm);#endif #ifndef alpha_using_qemuint alpha_using_qemu;#endif static struct alpha_machine_vector *get_sysvec(unsigned long, unsigned long,					       unsigned long);static struct alpha_machine_vector *get_sysvec_byname(const char *);static void get_sysnames(unsigned long, unsigned long, unsigned long,			 char **, char **);static void determine_cpu_caches (unsigned int); static char __initdata command_line[COMMAND_LINE_SIZE]; #ifdef CONFIG_VGA_CONSOLE/* * The format of "screen_info" is strange, and due to early * i386-setup code. This is just enough to make the console * code think we're on a VGA color display. */ struct screen_info vgacon_screen_info = {	.orig_x = 0,	.orig_y = 25,	.orig_video_cols = 80,	.orig_video_lines = 25,	.orig_video_isVGA = 1,	.orig_video_points = 16};#endif /* * The direct map I/O window, if any.  This should be the same * for all busses, since it's used by virt_to_bus. */ unsigned long __direct_map_base;unsigned long __direct_map_size;EXPORT_SYMBOL(__direct_map_base);EXPORT_SYMBOL(__direct_map_size); /* * Declare all of the machine vectors. */ /* GCC 2.7.2 (on alpha at least) is lame.  It does not support either    __attribute__((weak)) or #pragma weak.  Bypass it and talk directly   to the assembler.  */ #define WEAK(X) \	extern struct alpha_machine_vector X; \	asm(".weak "#X) WEAK(alcor_mv);WEAK(clipper_mv);WEAK(dp264_mv);WEAK(eb164_mv);WEAK(eiger_mv);WEAK(lx164_mv);WEAK(marvel_ev7_mv);WEAK(miata_mv);WEAK(mikasa_primo_mv);WEAK(monet_mv);WEAK(nautilus_mv);WEAK(noritake_primo_mv);WEAK(pc164_mv);WEAK(privateer_mv);WEAK(rawhide_mv);WEAK(ruffian_mv);WEAK(rx164_mv);WEAK(sable_gamma_mv);WEAK(shark_mv);WEAK(sx164_mv);WEAK(takara_mv);WEAK(titan_mv);WEAK(webbrick_mv);WEAK(wildfire_mv);WEAK(xlt_mv); #undef WEAK /* * I/O resources inherited from PeeCees.  Except for perhaps the * turbochannel alphas, everyone has these on some sort of SuperIO chip. * * ??? If this becomes less standard, move the struct out into the * machine vector. */ static void __initreserve_std_resources(void){	static struct resource standard_io_resources[] = {		{ .name = "rtc", .start = 0x70, .end =  0x7f},        	{ .name = "dma1", .start = 0x00, .end = 0x1f },        	{ .name = "pic1", .start = 0x20, .end = 0x3f },        	{ .name = "timer", .start = 0x40, .end = 0x5f },        	{ .name = "keyboard", .start = 0x60, .end = 0x6f },        	{ .name = "dma page reg", .start = 0x80, .end = 0x8f },        	{ .name = "pic2", .start = 0xa0, .end = 0xbf },        	{ .name = "dma2", .start = 0xc0, .end = 0xdf },	}; 	struct resource *io = &ioport_resource;	size_t i; 	if (hose_head) {		struct pci_controller *hose;		for (hose = hose_head; hose; hose = hose->next)			if (hose->index == 0) {				io = hose->io_space;				break;			}	} 	for (i = 0; i < ARRAY_SIZE(standard_io_resources); ++i)		request_resource(io, standard_io_resources+i);} #define PFN_MAX		PFN_DOWN(0x80000000)#define for_each_mem_cluster(memdesc, _cluster, i)		\	for ((_cluster) = (memdesc)->cluster, (i) = 0;		\	     (i) < (memdesc)->numclusters; (i)++, (_cluster)++) static unsigned long __initget_mem_size_limit(char *s){        unsigned long end = 0;        char *from = s;         end = simple_strtoul(from, &from, 0);        if ( *from == 'K' || *from == 'k' ) {                end = end << 10;                from++;        } else if ( *from == 'M' || *from == 'm' ) {                end = end << 20;                from++;        } else if ( *from == 'G' || *from == 'g' ) {                end = end << 30;                from++;        }        return end >> PAGE_SHIFT; /* Return the PFN of the limit. */} #ifdef CONFIG_BLK_DEV_INITRDvoid * __initmove_initrd(unsigned long mem_limit){	void *start;	unsigned long size; 	size = initrd_end - initrd_start;	start = memblock_alloc(PAGE_ALIGN(size), PAGE_SIZE);	if (!start || __pa(start) + size > mem_limit) {		initrd_start = initrd_end = 0;		return NULL;	}	memmove(start, (void *)initrd_start, size);	initrd_start = (unsigned long)start;	initrd_end = initrd_start + size;	printk("initrd moved to %p\n", start);	return start;}#endif static void __initsetup_memory(void *kernel_end){	struct memclust_struct * cluster;	struct memdesc_struct * memdesc;	unsigned long kernel_size;	unsigned long i; 	/* Find free clusters, and init and free the bootmem accordingly.  */	memdesc = (struct memdesc_struct *)	  (hwrpb->mddt_offset + (unsigned long) hwrpb); 	for_each_mem_cluster(memdesc, cluster, i) {		unsigned long end; 		printk("memcluster %lu, usage %01lx, start %8lu, end %8lu\n",		       i, cluster->usage, cluster->start_pfn,		       cluster->start_pfn + cluster->numpages); 		end = cluster->start_pfn + cluster->numpages;		if (end > max_low_pfn)			max_low_pfn = end; 		memblock_add(PFN_PHYS(cluster->start_pfn),			     cluster->numpages << PAGE_SHIFT); 		/* Bit 0 is console/PALcode reserved.  Bit 1 is		   non-volatile memory -- we might want to mark		   this for later.  */		if (cluster->usage & 3)			memblock_reserve(PFN_PHYS(cluster->start_pfn),				         cluster->numpages << PAGE_SHIFT);	} 	/*	 * Except for the NUMA systems (wildfire, marvel) all of the 	 * Alpha systems we run on support 32GB of memory or less.	 * Since the NUMA systems introduce large holes in memory addressing,	 * we can get into a situation where there is not enough contiguous	 * memory for the memory map. 	 *	 * Limit memory to the first 32GB to limit the NUMA systems to 	 * memory on their first node (wildfire) or 2 (marvel) to avoid 	 * not being able to produce the memory map. In order to access 	 * all of the memory on the NUMA systems, build with discontiguous	 * memory support.	 *	 * If the user specified a memory limit, let that memory limit stand.	 */	if (!mem_size_limit) 		mem_size_limit = (32ul * 1024 * 1024 * 1024) >> PAGE_SHIFT; 	if (mem_size_limit && max_low_pfn >= mem_size_limit)	{		printk("setup: forcing memory size to %ldK (from %ldK).\n",		       mem_size_limit << (PAGE_SHIFT - 10),		       max_low_pfn    << (PAGE_SHIFT - 10));		max_low_pfn = mem_size_limit;	} 	/* Reserve the kernel memory. */	kernel_size = virt_to_phys(kernel_end) - KERNEL_START_PHYS;	memblock_reserve(KERNEL_START_PHYS, kernel_size); #ifdef CONFIG_BLK_DEV_INITRD	initrd_start = INITRD_START;	if (initrd_start) {		initrd_end = initrd_start+INITRD_SIZE;		printk("Initial ramdisk at: 0x%p (%lu bytes)\n",		       (void *) initrd_start, INITRD_SIZE); 		if ((void *)initrd_end > phys_to_virt(PFN_PHYS(max_low_pfn))) {			if (!move_initrd(PFN_PHYS(max_low_pfn)))				printk("initrd extends beyond end of memory "				       "(0x%08lx > 0x%p)\ndisabling initrd\n",				       initrd_end,				       phys_to_virt(PFN_PHYS(max_low_pfn)));		} else {			memblock_reserve(virt_to_phys((void *)initrd_start),					INITRD_SIZE);		}	}#endif /* CONFIG_BLK_DEV_INITRD */} int page_is_ram(unsigned long pfn){	struct memclust_struct * cluster;	struct memdesc_struct * memdesc;	unsigned long i; 	memdesc = (struct memdesc_struct *)		(hwrpb->mddt_offset + (unsigned long) hwrpb);	for_each_mem_cluster(memdesc, cluster, i)	{		if (pfn >= cluster->start_pfn  &&		    pfn < cluster->start_pfn + cluster->numpages) {			return (cluster->usage & 3) ? 0 : 1;		}	} 	return 0;} static int __initregister_cpus(void){	int i; 	for_each_possible_cpu(i) {		struct cpu *p = kzalloc_obj(*p);		if (!p)			return -ENOMEM;		register_cpu(p, i);	}	return 0;} arch_initcall(register_cpus); #ifdef CONFIG_MAGIC_SYSRQstatic void sysrq_reboot_handler(u8 unused){	machine_halt();} static const struct sysrq_key_op srm_sysrq_reboot_op = {	.handler	= sysrq_reboot_handler,	.help_msg       = "reboot(b)",	.action_msg     = "Resetting",	.enable_mask    = SYSRQ_ENABLE_BOOT,};#endif void __initsetup_arch(char **cmdline_p){	extern char _end[]; 	struct alpha_machine_vector *vec = NULL;	struct percpu_struct *cpu;	char *type_name, *var_name, *p;	void *kernel_end = _end; /* end of kernel */	char *args = command_line; 	hwrpb = (struct hwrpb_struct*) __va(INIT_HWRPB->phys_addr);	boot_cpuid = hard_smp_processor_id();         /*	 * Pre-process the system type to make sure it will be valid.	 *	 * This may restore real CABRIO and EB66+ family names, ie	 * EB64+ and EB66.	 *	 * Oh, and "white box" AS800 (aka DIGITAL Server 3000 series)	 * and AS1200 (DIGITAL Server 5000 series) have the type as	 * the negative of the real one.	 */        if ((long)hwrpb->sys_type < 0) {		hwrpb->sys_type = -((long)hwrpb->sys_type);		hwrpb_update_checksum(hwrpb);	} 	/* Register a call for panic conditions. */	atomic_notifier_chain_register(&panic_notifier_list,			&alpha_panic_block); #ifndef alpha_using_srm	/* Assume that we've booted from SRM if we haven't booted from MILO.	   Detect the later by looking for "MILO" in the system serial nr.  */	alpha_using_srm = !str_has_prefix((const char *)hwrpb->ssn, "MILO");#endif#ifndef alpha_using_qemu	/* Similarly, look for QEMU.  */	alpha_using_qemu = strstr((const char *)hwrpb->ssn, "QEMU") != 0;#endif 	/* If we are using SRM, we want to allow callbacks	   as early as possible, so do this NOW, and then	   they should work immediately thereafter.	*/	kernel_end = callback_init(kernel_end); 	/* 	 * Locate the command line.	 */	strscpy(command_line, COMMAND_LINE, sizeof(command_line));	strcpy(boot_command_line, command_line);	*cmdline_p = command_line; 	/* 	 * Process command-line arguments.	 */	while ((p = strsep(&args, " \t")) != NULL) {		if (!*p) continue;		if (strncmp(p, "alpha_mv=", 9) == 0) {			vec = get_sysvec_byname(p+9);			continue;		}		if (strncmp(p, "cycle=", 6) == 0) {			est_cycle_freq = simple_strtol(p+6, NULL, 0);			continue;		}		if (strncmp(p, "mem=", 4) == 0) {			mem_size_limit = get_mem_size_limit(p+4);			continue;		}		if (strncmp(p, "srmcons", 7) == 0) {			srmcons_output |= 1;			continue;		}		if (strncmp(p, "console=srm", 11) == 0) {			srmcons_output |= 2;			continue;		}		if (strncmp(p, "gartsize=", 9) == 0) {

Lines 1–500 of 1373.