patch-2.1.116 linux/arch/alpha/kernel/setup.c

Next file: linux/arch/alpha/kernel/smp.c
Previous file: linux/arch/alpha/kernel/pyxis.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.115/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c
@@ -5,10 +5,9 @@
  */
 
 /*
- * bootup setup stuff..
+ * Bootup setup stuff.
  */
 
-#include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -24,6 +23,9 @@
 #include <linux/ioport.h>
 #include <linux/mc146818rtc.h>
 #include <linux/console.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/string.h>
 
 #ifdef CONFIG_RTC
 #include <linux/timex.h>
@@ -36,8 +38,8 @@
 #include <asm/dma.h>
 #include <asm/io.h>
 
-extern void setup_smp(void);
-extern char *smp_info(void);
+
+#include "proto.h"
 
 #if 1
 # define DBG_SRM(args)         printk args
@@ -45,19 +47,23 @@
 # define DBG_SRM(args)
 #endif
 
-struct hae hae = {
-	0,
-	(unsigned long*) HAE_ADDRESS
-};
-
-#ifdef CONFIG_ALPHA_SRM_SETUP
+struct hwrpb_struct *hwrpb;
 unsigned long srm_hae;
-#endif
 
-struct hwrpb_struct *hwrpb;
+#ifdef CONFIG_ALPHA_GENERIC
+struct alpha_machine_vector alpha_mv;
+int alpha_using_srm, alpha_use_srm_setup;
+#endif
 
 unsigned char aux_device_present = 0xaa;
 
+#define N(a) (sizeof(a)/sizeof(a[0]))
+
+static unsigned long find_end_memory(void);
+static struct alpha_machine_vector *get_sysvec(long, long, long);
+static struct alpha_machine_vector *get_sysvec_byname(const char *);
+static void get_sysnames(long, long, char **, char **);
+
 /*
  * This is setup by the secondary bootstrap loader.  Because
  * the zero page is zeroed out as soon as the vm system is
@@ -68,161 +74,241 @@
 #define COMMAND_LINE		((char*)(PARAM + 0x0000))
 #define COMMAND_LINE_SIZE	256
 
-static char command_line[COMMAND_LINE_SIZE] = { 0, };
-       char saved_command_line[COMMAND_LINE_SIZE];
+static char command_line[COMMAND_LINE_SIZE];
+char saved_command_line[COMMAND_LINE_SIZE];
+
 
 /*
  * 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 screen_info = {
-#if defined(CONFIG_ALPHA_BOOK1)
-  /* the AlphaBook1 has LCD video fixed at 800x600, 37 rows and 100 cols */
-	0, 37,			/* orig-x, orig-y */
-	{ 0, 0 },		/* unused */
-	0,			/* orig-video-page */
-	0,			/* orig-video-mode */
-        100,			/* orig-video-cols */
-	0,0,0,			/* ega_ax, ega_bx, ega_cx */
-        37,			/* orig-video-lines */
-	1,			/* orig-video-isVGA */
-	16			/* orig-video-points */
-#else
-	0, 25,			/* orig-x, orig-y */
-	0,	 		/* unused */
-	0,			/* orig-video-page */
-	0,			/* orig-video-mode */
-	80,			/* orig-video-cols */
-	0,0,0,			/* ega_ax, ega_bx, ega_cx */
-	25,			/* orig-video-lines */
-	1,			/* orig-video-isVGA */
-	16			/* orig-video-points */
-#endif
+	orig_x: 0,
+	orig_y: 25,
+	orig_video_cols: 80,
+	orig_video_lines: 25,
+	orig_video_isVGA: 1,
+	orig_video_points: 16
 };
 
+
 /*
  * Initialize Programmable Interval Timers with standard values.  Some
  * drivers depend on them being initialized (e.g., joystick driver).
  */
-static void init_pit (void)
+
+/* It is (normally) only counter 1 that presents config problems, so
+   provide this support function to do the rest of the job.  */
+
+void inline
+init_pit_rest(void)
 {
 #if 0
-    /*
-     * Leave refresh timer alone---nobody should depend on
-     * a particular value anyway.
-     */
-    outb(0x54, 0x43);	/* counter 1: refresh timer */
-    outb(0x18, 0x41);
-#endif
-
-#ifdef CONFIG_RTC /* setup interval timer if /dev/rtc is being used */
-    outb(0x34, 0x43);  /* binary, mode 2, LSB/MSB, ch 0 */
-    outb(LATCH & 0xff, 0x40); /* LSB */
-    outb(LATCH >> 8, 0x40); /* MSB */
-    request_region(0x40, 0x20, "timer"); /* reserve pit */
-#else /* RTC */
-#if !defined(CONFIG_ALPHA_RUFFIAN)
-    /* Ruffian depends on the system timer established in MILO!! */
-    outb(0x36, 0x43);	/* counter 0: system timer */
-    outb(0x00, 0x40);
-    outb(0x00, 0x40);
-#endif /* RUFFIAN */
-    request_region(0x70, 0x10, "timer"); /* reserve rtc */
-#endif /* RTC */
-
-    outb(0xb6, 0x43);	/* counter 2: speaker */
-    outb(0x31, 0x42);
-    outb(0x13, 0x42);
+	/* Leave refresh timer alone---nobody should depend on a
+	   particular value anyway. */
+	outb(0x54, 0x43);	/* counter 1: refresh timer */
+	outb(0x18, 0x41);
+#endif
+
+	outb(0xb6, 0x43);	/* counter 2: speaker */
+	outb(0x31, 0x42);
+	outb(0x13, 0x42);
+
+	if ((CMOS_READ(RTC_FREQ_SELECT) & 0x3f) != 0x26) {
+		printk("Setting RTC_FREQ to 1024 Hz\n");
+		CMOS_WRITE(0x26, RTC_FREQ_SELECT);
+	}
 }
 
-static unsigned long find_end_memory(void)
+#ifdef CONFIG_RTC
+static inline void
+rtc_init_pit (void)
 {
-	int i;
-	unsigned long high = 0;
-	struct memclust_struct * cluster;
-	struct memdesc_struct * memdesc;
+	/* Setup interval timer if /dev/rtc is being used */
+	outb(0x34, 0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
+	outb(LATCH & 0xff, 0x40);	/* LSB */
+	outb(LATCH >> 8, 0x40);		/* MSB */
+	request_region(0x40, 0x20, "timer"); /* reserve pit */
 
-	memdesc = (struct memdesc_struct *)
-	  (INIT_HWRPB->mddt_offset + (unsigned long) INIT_HWRPB);
-	cluster = memdesc->cluster;
-	for (i = memdesc->numclusters ; i > 0; i--, cluster++) {
-		unsigned long tmp;
-		tmp = (cluster->start_pfn + cluster->numpages) << PAGE_SHIFT;
-		if (tmp > high)
-			high = tmp;
-	}
-	/* round it up to an even number of pages.. */
-	high = (high + PAGE_SIZE) & (PAGE_MASK*2);
-	return PAGE_OFFSET + high;
+	init_pit_rest();
 }
+#endif
 
-void setup_arch(char **cmdline_p,
-	unsigned long * memory_start_p, unsigned long * memory_end_p)
+void
+generic_init_pit (void)
 {
-	extern int _end;
+	outb(0x36, 0x43);	/* counter 0: system timer */
+	outb(0x00, 0x40);
+	outb(0x00, 0x40);
+	request_region(RTC_PORT(0), 0x10, "timer"); /* reserve rtc */
 
-	init_pit();
+	init_pit_rest();
+}
 
-	if ((CMOS_READ(RTC_FREQ_SELECT) & 0x3f) != 0x26) {
-	  printk("setup_arch: setting RTC_FREQ to 1024/sec\n");
-	  CMOS_WRITE(0x26, RTC_FREQ_SELECT);
-	}
+/* This probably isn't Right, but it is what the old code did.  */
+#if defined(CONFIG_RTC)
+# define init_pit	rtc_init_pit
+#else
+# define init_pit	alpha_mv.init_pit
+#endif
+
+
+/*
+ * Declare all of the machine vectors.
+ */
+
+extern struct alpha_machine_vector alcor_mv;
+extern struct alpha_machine_vector alphabook1_mv;
+extern struct alpha_machine_vector avanti_mv;
+extern struct alpha_machine_vector cabriolet_mv;
+extern struct alpha_machine_vector dp264_mv;
+extern struct alpha_machine_vector eb164_mv;
+extern struct alpha_machine_vector eb64p_mv;
+extern struct alpha_machine_vector eb66_mv;
+extern struct alpha_machine_vector eb66p_mv;
+extern struct alpha_machine_vector jensen_mv;
+extern struct alpha_machine_vector lx164_mv;
+extern struct alpha_machine_vector miata_mv;
+extern struct alpha_machine_vector mikasa_mv;
+extern struct alpha_machine_vector mikasa_primo_mv;
+extern struct alpha_machine_vector noname_mv;
+extern struct alpha_machine_vector noritake_mv;
+extern struct alpha_machine_vector noritake_primo_mv;
+extern struct alpha_machine_vector p2k_mv;
+extern struct alpha_machine_vector pc164_mv;
+extern struct alpha_machine_vector rawhide_mv;
+extern struct alpha_machine_vector ruffian_mv;
+extern struct alpha_machine_vector sable_mv;
+extern struct alpha_machine_vector sable_gamma_mv;
+extern struct alpha_machine_vector sx164_mv;
+extern struct alpha_machine_vector takara_mv;
+extern struct alpha_machine_vector xl_mv;
+extern struct alpha_machine_vector xlt_mv;
+
+
+void __init
+setup_arch(char **cmdline_p, unsigned long * memory_start_p,
+	   unsigned long * memory_end_p)
+{
+	extern char _end[];
+
+	struct alpha_machine_vector *vec = NULL;
+	struct percpu_struct *cpu;
+	char *type_name, *var_name, *p;
 
 	hwrpb = (struct hwrpb_struct*)(IDENT_ADDR + INIT_HWRPB->phys_addr);
 
-#if !defined(CONFIG_ALPHA_TSUNAMI)
-#ifdef CONFIG_ALPHA_SRM_SETUP
-	srm_hae = *hae.reg; /* save SRM setting for restoration */
-	DBG_SRM(("setup_arch: old HAE base: 0x%016lx\n", srm_hae));
-#endif /* SRM_SETUP */
-	set_hae(hae.cache);	/* sync HAE register w/hae_cache */
-#endif /* !TSUNAMI */
-
-	wrmces(0x7);		/* reset enable correctable error reports */
-
-	ROOT_DEV = to_kdev_t(0x0802);		/* sda2 */
-	command_line[COMMAND_LINE_SIZE - 1] = '\0';
-
-	/* Hack for Jensen... since we're restricted to 8 or 16 
-	 * chars for boot flags depending on the boot mode,
-	 * we need some shorthand.  This should do for 
-	 * installation.  Later we'll add other abbreviations
-	 * as well...
+	/* 
+	 * Locate the command line.
 	 */
+
+	/* Hack for Jensen... since we're restricted to 8 or 16 chars for
+	   boot flags depending on the boot mode, we need some shorthand.
+	   This should do for installation.  Later we'll add other
+	   abbreviations as well... */
 	if (strcmp(COMMAND_LINE, "INSTALL") == 0) {
 		strcpy(command_line, "root=/dev/fd0 load_ramdisk=1");
-		strcpy(saved_command_line, command_line);
 	} else {
-		strcpy(command_line, COMMAND_LINE);
-		strcpy(saved_command_line, COMMAND_LINE);
+		strncpy(command_line, COMMAND_LINE, sizeof command_line);
+		command_line[sizeof(command_line)-1] = 0;
 	}
-	printk("Command line: %s\n", command_line);
-
+	strcpy(saved_command_line, command_line);
 	*cmdline_p = command_line;
-	*memory_start_p = (unsigned long) &_end;
-	*memory_end_p = find_end_memory();
 
-#if defined(CONFIG_ALPHA_LCA)
-	*memory_start_p = lca_init(*memory_start_p, *memory_end_p);
-#elif defined(CONFIG_ALPHA_APECS)
-	*memory_start_p = apecs_init(*memory_start_p, *memory_end_p);
-#elif defined(CONFIG_ALPHA_CIA)
-	*memory_start_p = cia_init(*memory_start_p, *memory_end_p);
-#elif defined(CONFIG_ALPHA_PYXIS)
-	*memory_start_p = pyxis_init(*memory_start_p, *memory_end_p);
-#elif defined(CONFIG_ALPHA_T2)
-	*memory_start_p = t2_init(*memory_start_p, *memory_end_p);
-#elif defined(CONFIG_ALPHA_TSUNAMI)
-	*memory_start_p = tsunami_init(*memory_start_p, *memory_end_p);
-#elif defined(CONFIG_ALPHA_MCPCIA)
-	*memory_start_p = mcpcia_init(*memory_start_p, *memory_end_p);
+	/* 
+	 * Process command-line arguments.
+	 */
+
+	for (p = strtok(command_line, " \t"); p ; p = strtok(NULL, " \t")) {
+#ifndef alpha_use_srm_setup
+		/* Allow a command-line option to respect the
+		   SRM's configuration.  */
+		if (strncmp(p, "srm_setup=", 10) == 0) {
+			alpha_use_srm_setup = (p[10] != '0');
+			continue;
+		}
 #endif
 
-#ifdef __SMP__
-	setup_smp();
+		if (strncmp(p, "alpha_mv=", 9) == 0) {
+			vec = get_sysvec_byname(p+9);
+			continue;
+		}
+	}
+
+	/* Replace the command line, not that we've killed it with strtok.  */
+	strcpy(command_line, saved_command_line);
+
+	/*
+	 * Indentify and reconfigure for the current system.
+	 */
+
+	get_sysnames(hwrpb->sys_type, hwrpb->sys_variation,
+		     &type_name, &var_name);
+	if (*var_name == '0')
+		var_name = "";
+
+	if (!vec) {
+		cpu = (struct percpu_struct*)
+			((char*)hwrpb + hwrpb->processor_offset);
+		vec = get_sysvec(hwrpb->sys_type, hwrpb->sys_variation,
+				 cpu->type);
+	}
+
+#ifdef CONFIG_ALPHA_GENERIC
+	if (!vec) {
+		panic("Unsupported system type: %s%s%s (%ld %ld)\n",
+		      type_name, (*var_name ? " variation " : ""), var_name,
+		      hwrpb->sys_type, hwrpb->sys_variation);
+	}
+	alpha_mv = *vec;
+
+	/* Assume that we've booted from SRM if we havn't booted from MILO.
+	   Detect the later by looking for "MILO" in the system serial nr.  */
+	alpha_using_srm = strncmp((const char *)hwrpb->ssn, "MILO", 4) != 0;
+#else
+	/* Once we're sure we can reliably identify systems, we should
+	   simply panic as we do above.  */
+	if (vec != &alpha_mv) {
+		printk("WARNING: Not configured for system type: %s%s%s "
+		       "(%ld %ld)\nContinuing with trepidation...\n",
+		       type_name, (*var_name ? " variation " : ""), var_name,
+		       hwrpb->sys_type, hwrpb->sys_variation);
+	}
 #endif
 
+	/* 
+	 * Sync with the HAE
+	 */
+
+	/* Save the SRM's current value for restoration.  */
+	srm_hae = *alpha_mv.hae_register;
+	__set_hae(alpha_mv.hae_cache);
+
+	/* Reset enable correctable error reports.  */
+	wrmces(0x7);
+
+	/* Find our memory.  */
+	*memory_end_p = find_end_memory();
+	*memory_start_p = (unsigned long) _end;
+
+	/* Initialize the machine.  Usually has to do with setting up
+	   DMA windows and the like.  */
+	if (alpha_mv.init_arch)
+		alpha_mv.init_arch(memory_start_p, memory_end_p);
+
+	/* Initialize the timers.  */
+	init_pit();
+
+	/* Default root filesystem to sda2.  */
+	ROOT_DEV = to_kdev_t(0x0802);
+
+	/* 
+	 * Give us a default console.  TGA users will see nothing until
+	 * chr_dev_init is called, rather late in the boot sequence.
+	 */
+
 #ifdef CONFIG_VT
 #if defined(CONFIG_VGA_CONSOLE)
 	conswitchp = &vga_con;
@@ -230,81 +316,284 @@
 	conswitchp = &dummy_con;
 #endif
 #endif
-}
 
+	/* Delayed so that we've initialized the machine first.  */
+	printk("Booting on %s%s%s using machine vector %s\n",
+	       type_name, (*var_name ? " variation " : ""),
+	       var_name, alpha_mv.vector_name);
+	printk("Command line: %s\n", command_line);
 
-#define N(a) (sizeof(a)/sizeof(a[0]))
+ 	/*
+	 * Check ASN in HWRPB for validity, report if bad.
+	 * FIXME: how was this failing?  Should we trust it instead,
+	 * and copy the value into alpha_mv.max_asn?
+ 	 */
+
+ 	if (hwrpb->max_asn != MAX_ASN) {
+		printk("Max ASN from HWRPB is bad (0x%lx)\n", hwrpb->max_asn);
+ 	}
 
-/* A change was made to the HWRPB via an ECO and the following code tracks
- * a part of the ECO.  In HWRPB versions less than 5, the ECO was not
- * implemented in the console firmware.  If it's revision 5 or greater we can
- * get the name of the platform as an ASCII string from the HWRPB.  That's what
- * this function does.  It checks the revision level and if the string is in
- * the HWRPB it returns the address of the string--a pointer to the name of the
- * platform.
- *
- * Returns:
- *      - Pointer to a ASCII string if it's in the HWRPB
- *      - Pointer to a blank string if the data is not in the HWRPB.
- */
-static char *
-platform_string(void)
+	/*
+	 * Identify the flock of penguins.
+	 */
+
+#ifdef __SMP__
+	setup_smp();
+#endif
+}
+
+static unsigned long __init
+find_end_memory(void)
 {
-	struct dsr_struct *dsr;
-	static char unk_system_string[] = "N/A";
+	int i;
+	unsigned long high = 0;
+	struct memclust_struct * cluster;
+	struct memdesc_struct * memdesc;
 
-        /* Go to the console for the string pointer.
-         * If the rpb_vers is not 5 or greater the rpb
-	 * is old and does not have this data in it.
-	 */
-        if (hwrpb->revision < 5)
-		return (unk_system_string);
-	else {
-		/* The Dynamic System Recognition struct
-		 * has the system platform name starting
-		 * after the character count of the string.
-		 */
-		dsr =  ((struct dsr_struct *)
-			  ((char *)hwrpb + hwrpb->dsr_offset));
-		return ((char *)dsr + (dsr->sysname_off +
-						 sizeof(long)));
-        }
+	memdesc = (struct memdesc_struct *)
+		(INIT_HWRPB->mddt_offset + (unsigned long) INIT_HWRPB);
+	cluster = memdesc->cluster;
+
+	for (i = memdesc->numclusters ; i > 0; i--, cluster++) {
+		unsigned long tmp;
+		tmp = (cluster->start_pfn + cluster->numpages) << PAGE_SHIFT;
+		if (tmp > high)
+			high = tmp;
+	}
+
+	/* Round it up to an even number of pages. */
+	high = (high + PAGE_SIZE) & (PAGE_MASK*2);
+	return PAGE_OFFSET + high;
 }
 
-static void
-get_sysnames(long type, long variation,
-	     char **type_name, char **variation_name)
+
+static char sys_unknown[] = "Unknown";
+static char systype_names[][16] = {
+	"0",
+	"ADU", "Cobra", "Ruby", "Flamingo", "Mannequin", "Jensen",
+	"Pelican", "Morgan", "Sable", "Medulla", "Noname",
+	"Turbolaser", "Avanti", "Mustang", "Alcor", "Tradewind",
+	"Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1",
+	"Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake",
+	"Cortex", "29", "Miata", "XXM", "Takara", "Yukon",
+	"Tsunami", "Wildfire", "CUSCO"
+};
+
+static char unofficial_names[][8] = {"100", "Ruffian"};
+
+static char eb164_names[][8] = {"EB164", "PC164", "LX164", "SX164"};
+static int eb164_indices[] = {0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3};
+
+static char alcor_names[][16] = {"Alcor", "Maverick", "Bret"};
+static int alcor_indices[] = {0,0,0,1,1,1,0,0,0,0,0,0,2,2,2,2,2,2};
+
+static char eb64p_names[][16] = {"EB64+", "Cabriolet", "AlphaPCI64"};
+static int eb64p_indices[] = {0,0,1,2};
+
+static char eb66_names[][8] = {"EB66", "EB66+"};
+static int eb66_indices[] = {0,0,1};
+
+static char rawhide_names[][16] = {
+	"Dodge", "Wrangler", "Durango", "Tincup", "DaVinci"
+};
+static int rawhide_indices[] = {0,0,0,1,1,2,2,3,3,4,4};
+
+
+static struct alpha_machine_vector * __init
+get_sysvec(long type, long variation, long cpu)
 {
-	static char *sys_unknown = "Unknown";
-	static char *systype_names[] = {
-		"0",
-		"ADU", "Cobra", "Ruby", "Flamingo", "Mannequin", "Jensen",
-		"Pelican", "Morgan", "Sable", "Medulla", "Noname",
-		"Turbolaser", "Avanti", "Mustang", "Alcor", "Tradewind",
-		"Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1",
-		"Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake",
-		"Cortex", "29", "Miata", "XXM", "Takara", "Yukon",
-		"Tsunami", "Wildfire", "CUSCO"
+#ifdef CONFIG_ALPHA_GENERIC
+	static struct alpha_machine_vector *systype_vecs[] __initlocaldata =
+	{
+		NULL,		/* 0 */
+		NULL,		/* ADU */
+		NULL,		/* Cobra */
+		NULL,		/* Ruby */
+		NULL,		/* Flamingo */
+		NULL,		/* Mannequin */
+		&jensen_mv,
+		NULL, 		/* Pelican */
+		NULL,		/* Morgan */
+		NULL,		/* Sable -- see below.  */
+		NULL,		/* Medulla */
+		&noname_mv,
+		NULL,		/* Turbolaser */
+		&avanti_mv,
+		NULL,		/* Mustang */
+		&alcor_mv,	/* Alcor, Bret, Maverick.  */
+		NULL,		/* Tradewind */
+		NULL,		/* Mikasa -- see below.  */
+		NULL,		/* EB64 */
+		NULL,		/* EB66 -- see variation.  */
+		NULL,		/* EB64+ -- see variation.  */
+		&alphabook1_mv,
+		&rawhide_mv,
+		NULL,		/* K2 */
+		NULL,		/* Lynx */
+		&xl_mv,
+		NULL,		/* EB164 -- see variation.  */
+		NULL,		/* Noritake -- see below.  */
+		NULL,		/* Cortex */
+		NULL,		/* 29 */
+		&miata_mv,
+		NULL,		/* XXM */
+		&takara_mv,
+		NULL,		/* Yukon */
+		&dp264_mv,
+		NULL,		/* Wildfire */
+		NULL,		/* CUSCO */
 	};
 
-	static char *unofficial_names[] = {"100", "Ruffian"};
+	static struct alpha_machine_vector *unofficial_vecs[] __initlocaldata =
+	{
+		NULL,		/* 100 */
+		&ruffian_mv,
+	};
 
-	static char * eb164_names[] = {"EB164", "PC164", "LX164", "SX164"};
-	static int eb164_indices[] = {0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3};
+	static struct alpha_machine_vector *alcor_vecs[] __initlocaldata = 
+	{
+		&alcor_mv, &xlt_mv, &xlt_mv
+	};
 
-	static char * alcor_names[] = {"Alcor", "Maverick", "Bret"};
-	static int alcor_indices[] = {0,0,0,1,1,1,0,0,0,0,0,0,2,2,2,2,2,2};
+	static struct alpha_machine_vector *eb164_vecs[] __initlocaldata =
+	{
+		&eb164_mv, &pc164_mv, &lx164_mv, &sx164_mv
+	};
 
-	static char * eb64p_names[] = {"EB64+", "Cabriolet", "AlphaPCI64"};
-	static int eb64p_indices[] = {0,0,1,2};
+	static struct alpha_machine_vector *eb64p_vecs[] __initlocaldata =
+	{
+		&eb64p_mv,
+		&cabriolet_mv,
+		NULL		/* AlphaPCI64 */
+	};
 
-	static char * eb66_names[] = {"EB66", "EB66+"};
-	static int eb66_indices[] = {0,0,1};
+	static struct alpha_machine_vector *eb66_vecs[] __initlocaldata =
+	{
+		&eb66_mv,
+		&eb66p_mv
+	};
+
+	/* ??? Do we need to distinguish between Rawhides?  */
 
-	static char * rawhide_names[] = {"Dodge", "Wrangler", "Durango",
-					 "Tincup", "DaVinci"};
-	static int rawhide_indices[] = {0,0,0,1,1,2,2,3,3,4,4};
+	struct alpha_machine_vector *vec;
 
+	/* Restore real CABRIO and EB66+ family names, ie EB64+ and EB66 */
+	if (type < 0)
+		type = -type;
+
+	/* Search the system tables first... */
+	vec = NULL;
+	if (type < N(systype_vecs)) {
+		vec = systype_vecs[type];
+	} else if ((type > ST_UNOFFICIAL_BIAS) &&
+		   (type - ST_UNOFFICIAL_BIAS) < N(unofficial_vecs)) {
+		vec = unofficial_vecs[type - ST_UNOFFICIAL_BIAS];
+	}
+
+	/* If we've not found one, try for a variation.  */
+
+	if (!vec) {
+		/* Member ID is a bit-field. */
+		long member = (variation >> 10) & 0x3f;
+
+		switch (type) {
+		case ST_DEC_ALCOR:
+			if (member < N(alcor_indices))
+				vec = alcor_vecs[alcor_indices[member]];
+			break;
+		case ST_DEC_EB164:
+			if (member < N(eb164_indices))
+				vec = eb164_vecs[eb164_indices[member]];
+			break;
+		case ST_DEC_EB64P:
+			if (member < N(eb64p_indices))
+				vec = eb64p_vecs[eb64p_indices[member]];
+			break;
+		case ST_DEC_EB66:
+			if (member < N(eb66_indices))
+				vec = eb66_vecs[eb66_indices[member]];
+			break;
+		case ST_DEC_1000:
+			if (cpu == EV5_CPU)
+				vec = &mikasa_primo_mv;
+			else
+				vec = &mikasa_mv;
+			break;
+		case ST_DEC_NORITAKE:
+			if (cpu == EV5_CPU)
+				vec = &noritake_primo_mv;
+			else
+				vec = &noritake_mv;
+			break;
+		case ST_DEC_2100_A500:
+			if (cpu == EV5_CPU)
+				vec = &sable_gamma_mv;
+			else
+				vec = &sable_mv;
+			break;
+		}
+	}
+	return vec;
+#else
+	/* TODO: verify that the system is of the type for which we
+	   were configured.  For now, cop out and return success.  */
+	return &alpha_mv;
+#endif /* GENERIC */
+}
+
+static struct alpha_machine_vector * __init
+get_sysvec_byname(const char *name)
+{
+#ifdef CONFIG_ALPHA_GENERIC
+	static struct alpha_machine_vector *all_vecs[] __initlocaldata =
+	{
+		&alcor_mv,
+		&alphabook1_mv,
+		&avanti_mv,
+		&cabriolet_mv,
+		&dp264_mv,
+		&eb164_mv,
+		&eb64p_mv,
+		&eb66_mv,
+		&eb66p_mv,
+		&jensen_mv,
+		&lx164_mv,
+		&miata_mv,
+		&mikasa_mv,
+		&mikasa_primo_mv,
+		&noname_mv,
+		&noritake_mv,
+		&noritake_primo_mv,
+		&p2k_mv,
+		&pc164_mv,
+		&rawhide_mv,
+		&ruffian_mv,
+		&sable_mv,
+		&sable_gamma_mv,
+		&sx164_mv,
+		&takara_mv,
+		&xl_mv,
+		&xlt_mv
+	};
+
+	int i, n = sizeof(all_vecs)/sizeof(*all_vecs);
+	for (i = 0; i < n; ++i) {
+		struct alpha_machine_vector *mv = all_vecs[i];
+		if (strcasecmp(mv->vector_name, name) == 0)
+			return mv;
+	}
+	return NULL;
+#else
+	if (strcasecmp(alpha_mv.vector_name, name) == 0)
+		return &alpha_mv;
+	return NULL;
+#endif
+}
+
+static void
+get_sysnames(long type, long variation,
+	     char **type_name, char **variation_name)
+{
 	long member;
 
 	/* Restore real CABRIO and EB66+ family names, ie EB64+ and EB66 */
@@ -353,9 +642,47 @@
 		break;
 	case ST_DEC_RAWHIDE:
 		if (member < N(rawhide_indices))
-		  *variation_name = rawhide_names[rawhide_indices[member]];
+			*variation_name = rawhide_names[rawhide_indices[member]];
 		break;
-	} /* end family switch */
+	}
+}
+
+/*
+ * A change was made to the HWRPB via an ECO and the following code
+ * tracks a part of the ECO.  In HWRPB versions less than 5, the ECO
+ * was not implemented in the console firmware.  If it's revision 5 or
+ * greater we can get the name of the platform as an ASCII string from
+ * the HWRPB.  That's what this function does.  It checks the revision
+ * level and if the string is in the HWRPB it returns the address of
+ * the string--a pointer to the name of the platform.
+ *
+ * Returns:
+ *      - Pointer to a ASCII string if it's in the HWRPB
+ *      - Pointer to a blank string if the data is not in the HWRPB.
+ */
+
+static char *
+platform_string(void)
+{
+	struct dsr_struct *dsr;
+	static char unk_system_string[] = "N/A";
+
+	/* Go to the console for the string pointer.
+	 * If the rpb_vers is not 5 or greater the rpb
+	 * is old and does not have this data in it.
+	 */
+	if (hwrpb->revision < 5)
+		return (unk_system_string);
+	else {
+		/* The Dynamic System Recognition struct
+		 * has the system platform name starting
+		 * after the character count of the string.
+		 */
+		dsr =  ((struct dsr_struct *)
+			((char *)hwrpb + hwrpb->dsr_offset));
+		return ((char *)dsr + (dsr->sysname_off +
+				       sizeof(long)));
+	}
 }
 
 /*
@@ -363,20 +690,21 @@
  */
 int get_cpuinfo(char *buffer)
 {
-	static char *cpu_names[] = {
-		"EV3", "EV4", "Unknown", "LCA4", "EV5", "EV45", "EV56",
-		"EV6", "PCA56", "PCA57"
-	};
-
 	extern struct unaligned_stat {
 		unsigned long count, va, pc;
 	} unaligned[2];
 
+	static char cpu_names[][8] = {
+		"EV3", "EV4", "Unknown", "LCA4", "EV5", "EV45", "EV56",
+		"EV6", "PCA56", "PCA57"
+	};
+
 	struct percpu_struct *cpu;
 	unsigned int cpu_index;
 	char *cpu_name;
 	char *systype_name;
 	char *sysvariation_name;
+	int len;
 
 	cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset);
 	cpu_index = (unsigned) (cpu->type - 1);
@@ -387,30 +715,25 @@
 	get_sysnames(hwrpb->sys_type, hwrpb->sys_variation,
 		     &systype_name, &sysvariation_name);
 
-	return sprintf(buffer,
-		       "cpu\t\t\t: Alpha\n"
-		       "cpu model\t\t: %s\n"
-		       "cpu variation\t\t: %ld\n"
-		       "cpu revision\t\t: %ld\n"
-		       "cpu serial number\t: %s\n"
-		       "system type\t\t: %s\n"
-		       "system variation\t: %s\n"
-		       "system revision\t\t: %ld\n"
-		       "system serial number\t: %s\n"
-		       "cycle frequency [Hz]\t: %lu\n"
-		       "timer frequency [Hz]\t: %lu.%02lu\n"
-		       "page size [bytes]\t: %ld\n"
-		       "phys. address bits\t: %ld\n"
-		       "max. addr. space #\t: %ld\n"
-		       "BogoMIPS\t\t: %lu.%02lu\n"
-		       "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
-		       "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
-		       "platform string\t\t: %s\n"
-#ifdef __SMP__
-		       "%s"
-#endif
-		       ,
-
+	len = sprintf(buffer,
+		      "cpu\t\t\t: Alpha\n"
+		      "cpu model\t\t: %s\n"
+		      "cpu variation\t\t: %ld\n"
+		      "cpu revision\t\t: %ld\n"
+		      "cpu serial number\t: %s\n"
+		      "system type\t\t: %s\n"
+		      "system variation\t: %s\n"
+		      "system revision\t\t: %ld\n"
+		      "system serial number\t: %s\n"
+		      "cycle frequency [Hz]\t: %lu\n"
+		      "timer frequency [Hz]\t: %lu.%02lu\n"
+		      "page size [bytes]\t: %ld\n"
+		      "phys. address bits\t: %ld\n"
+		      "max. addr. space #\t: %ld\n"
+		      "BogoMIPS\t\t: %lu.%02lu\n"
+		      "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
+		      "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
+		      "platform string\t\t: %s\n",
 		       cpu_name, cpu->variation, cpu->revision,
 		       (char*)cpu->serial_no,
 		       systype_name, sysvariation_name, hwrpb->sys_revision,
@@ -424,9 +747,11 @@
 		       loops_per_sec / 500000, (loops_per_sec / 5000) % 100,
 		       unaligned[0].count, unaligned[0].pc, unaligned[0].va,
 		       unaligned[1].count, unaligned[1].pc, unaligned[1].va,
-		       platform_string()
+		       platform_string());
+
 #ifdef __SMP__
-		       , smp_info()
+	return len + smp_info(buffer+len);
+#else
+	return len;
 #endif
-		       );
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov