Module Name:    src
Committed By:   christos
Date:           Wed Aug 21 16:37:31 UTC 2013

Modified Files:
        src/sys/arch/x86/x86: mpbios.c

Log Message:
Use the default mp definition tables for ancient machines. From Felix
Deichmann.


To generate a diff of this commit:
cvs rdiff -u -r1.60 -r1.61 src/sys/arch/x86/x86/mpbios.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/x86/x86/mpbios.c
diff -u src/sys/arch/x86/x86/mpbios.c:1.60 src/sys/arch/x86/x86/mpbios.c:1.61
--- src/sys/arch/x86/x86/mpbios.c:1.60	Tue Nov 27 15:32:58 2012
+++ src/sys/arch/x86/x86/mpbios.c	Wed Aug 21 12:37:31 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: mpbios.c,v 1.60 2012/11/27 20:32:58 jakllsch Exp $	*/
+/*	$NetBSD: mpbios.c,v 1.61 2013/08/21 16:37:31 christos Exp $	*/
 
 /*-
  * Copyright (c) 2000 The NetBSD Foundation, Inc.
@@ -96,7 +96,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mpbios.c,v 1.60 2012/11/27 20:32:58 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mpbios.c,v 1.61 2013/08/21 16:37:31 christos Exp $");
 
 #include "acpica.h"
 #include "lapic.h"
@@ -147,10 +147,6 @@ int mpbios_nioapic;
 
 #include "locators.h"
 
-static struct mpbios_ioapic default_ioapic = {
-    2,0,1,IOAPICENTRY_FLAG_EN,(uint32_t)IOAPIC_BASE_DEFAULT
-};
-
 /* descriptions of MP basetable entries */
 struct mpbios_baseentry {
 	uint8_t  	type;
@@ -174,6 +170,11 @@ struct mp_map
 	int		psize;
 };
 
+struct dflt_conf_entry {
+	const char	*bus_type[2];
+	int		flags;
+};
+
 int mp_cpuprint(void *, const char *);
 int mp_ioapicprint(void *, const char *);
 static const void *mpbios_search(device_t, paddr_t, int,
@@ -194,7 +195,12 @@ static void mp_cfg_eisa_intr(const struc
 static void mp_cfg_isa_intr(const struct mpbios_int *, uint32_t *);
 static void mp_print_isa_intr(int intr);
 
-static void mpbios_cpus(device_t);
+static void mpbios_dflt_conf_cpu(device_t);
+static void mpbios_dflt_conf_bus(device_t, const struct dflt_conf_entry *);
+static void mpbios_dflt_conf_ioapic(device_t);
+static void mpbios_dflt_conf_int(device_t, const struct dflt_conf_entry *,
+                                 const int *);
+
 static void mpbios_cpu(const uint8_t *, device_t);
 static void mpbios_bus(const uint8_t *, device_t);
 static void mpbios_ioapic(const uint8_t *, device_t);
@@ -342,8 +348,6 @@ mpbios_probe(device_t self)
 
 			goto err;
 		}
-		aprint_normal_dev(self, "MP default configuration %d\n",
-		    mp_fps->mpfb1);
 		return 10;
 	}
 
@@ -476,6 +480,55 @@ static struct mp_bus nmi_bus = {
 	NULL, 0, 0, NULL, 0
 };
 
+/*
+ * MP default configuration tables (acc. MP Specification Version 1.4)
+ */
+
+/*
+ * Default configurations always feature two processors and the local APIC IDs
+ * are assigned consecutively by hardware starting from zero (sec. 5). We set
+ * I/O APIC ID to 2.
+ */
+#define DFLT_IOAPIC_ID	2
+
+#define ELCR_INV	0x1
+#define MCA_INV		0x2
+#define IRQ_VAR		0x4
+#define INTIN0_NC	0x8
+
+static const struct dflt_conf_entry dflt_conf_tab[7] = {
+	/*
+	 * Assume all systems with EISA and (modern) PCI chipsets have ELCRs
+	 * (to control external interrupt-level inverters). MCA systems must
+	 * use fixed inverters for INTIN1-INTIN15 (table 5-1; sec. 5.3.2).
+	 */
+	{{"ISA   ", NULL    }, 0                  },	/* default config 1 */
+	{{"EISA  ", NULL    }, ELCR_INV | IRQ_VAR },	/* default config 2 */
+	{{"EISA  ", NULL    }, ELCR_INV           },	/* default config 3 */
+	{{"MCA   ", NULL    }, MCA_INV            },	/* default config 4 */
+	{{"ISA   ", "PCI   "}, ELCR_INV           },	/* default config 5 */
+	{{"EISA  ", "PCI   "}, ELCR_INV           },	/* default config 6 */
+	{{"MCA   ", "PCI   "}, MCA_INV | INTIN0_NC}	/* default config 7 */
+};
+
+#define _ (-1) /* INTINx not connected (to a bus interrupt) */
+
+static const int dflt_bus_irq_tab[2][16] = {
+	/* Default configs 1,3-7 connect INTIN1-INTIN15 to bus interrupts. */
+	{_, 1, 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+	/*
+	 * Default config 2 connects neither timer IRQ0 nor DMA chaining to
+	 * INTIN2 and INTIN13 (sec. 5.3).
+	 */
+	{_, 1, _, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,  _, 14, 15}
+};
+
+#undef _
+
+static const uint8_t dflt_lint_tab[2] = {
+	MPS_INTTYPE_ExtINT, MPS_INTTYPE_NMI
+};
+
 
 /*
  * 1st pass on BIOS's Intel MP specification table.
@@ -495,10 +548,13 @@ void
 mpbios_scan(device_t self, int *ncpup)
 {
 	const uint8_t 	*position, *end;
+	size_t          i;
 	int		count;
 	int		type;
 	int		intr_cnt, cur_intr;
 	paddr_t		lapic_base;
+	const struct dflt_conf_entry *dflt_conf;
+	const int *dflt_bus_irq;
 	const struct mpbios_int *iep;
 	struct mpbios_int ie;
 
@@ -538,30 +594,65 @@ mpbios_scan(device_t self, int *ncpup)
 	/* check for use of 'default' configuration */
 	if (mp_fps->mpfb1 != 0) {
 
+		if (mp_fps->mpfb1 > __arraycount(dflt_conf_tab))
+			panic("Unsupported MP default configuration %d\n",
+			      mp_fps->mpfb1);
+
 		aprint_normal("\n");
 		aprint_normal_dev(self, "MP default configuration %d\n",
 		    mp_fps->mpfb1);
+
+		dflt_conf = &dflt_conf_tab[mp_fps->mpfb1 - 1];
+		dflt_bus_irq =
+		    dflt_bus_irq_tab[(dflt_conf->flags & IRQ_VAR) != 0];
+
 #if NACPICA > 0
 		if (mpacpi_ncpu == 0)
 #endif
-			mpbios_cpus(self);
+			mpbios_dflt_conf_cpu(self);
 
 #if NACPICA > 0
 		if (mpacpi_nioapic == 0)
 #endif
-			mpbios_ioapic((uint8_t *)&default_ioapic, self);
+			mpbios_dflt_conf_ioapic(self);
 
-		/* XXX */
-		aprint_verbose_dev(self, "WARNING: interrupts not configured\n");
+		/*
+		 * Walk the table once, counting items.
+		 */
+		mp_nbus = 0;
+		for (i = 0; i < __arraycount(dflt_conf->bus_type); i++) {
+			if (dflt_conf->bus_type[i] != NULL)
+				mp_nbus++;
+		}
+		KASSERT(mp_nbus != 0);
+
+		mp_busses = kmem_zalloc(sizeof(struct mp_bus) * mp_nbus,
+		                        KM_SLEEP);
+		KASSERT(mp_busses != NULL);
+
+		/* INTIN0 */
+		intr_cnt = (dflt_conf->flags & INTIN0_NC) ? 0 : 1;
+		/* INTINx */
+		for (i = 0; i < __arraycount(dflt_bus_irq_tab[0]); i++) {
+			if (dflt_bus_irq[i] >= 0)
+				intr_cnt++;
+		}
+		KASSERT(intr_cnt != 0);
+
+		/* LINTINx */
+		for (i = 0; i < __arraycount(dflt_lint_tab); i++)
+			intr_cnt++;
+
+		mp_intrs = kmem_zalloc(sizeof(struct mp_intr_map) * intr_cnt,
+		                       KM_SLEEP);
+		KASSERT(mp_intrs != NULL);
+		mp_nintr = intr_cnt;
 
 		/*
-		 * XXX rpaulo: I have a machine that can boot, so I
-		 * commented this (for now).
+		 * Re-walk the table, recording info of interest.
 		 */
-#if 0
-		panic("lazy bum");
-		return;
-#endif
+		mpbios_dflt_conf_bus(self, dflt_conf);
+		mpbios_dflt_conf_int(self, dflt_conf, dflt_bus_irq);
 	} else {
 		/*
 		 * should not happen; mp_probe returns 0 in this case,
@@ -727,19 +818,142 @@ mpbios_cpu(const uint8_t *ent, device_t 
 }
 
 static void
-mpbios_cpus(device_t self)
+mpbios_dflt_conf_cpu(device_t self)
 {
-	struct mpbios_proc pe;
-	/* use default addresses */
-	pe.apic_id = lapic_cpu_number();
-	pe.cpu_flags = PROCENTRY_FLAG_EN|PROCENTRY_FLAG_BP;
+	struct mpbios_proc mpp;
 
-	mpbios_cpu((uint8_t *)&pe, self);
+	/* mpp.type and mpp.apic_version are irrelevant for mpbios_cpu(). */
+	/*
+	 * Default configurations always feature two processors and the local
+	 * APIC IDs are assigned consecutively by hardware starting from zero
+	 * (sec. 5). Just determine the BSP (APIC ID).
+	 */
+	mpp.apic_id = cpu_info_primary.ci_cpuid;
+	mpp.cpu_flags = PROCENTRY_FLAG_EN | PROCENTRY_FLAG_BP;
+	mpbios_cpu((uint8_t *)&mpp, self);
+
+	mpp.apic_id = 1 - cpu_info_primary.ci_cpuid;
+	mpp.cpu_flags = PROCENTRY_FLAG_EN;
+	mpbios_cpu((uint8_t *)&mpp, self);
+}
 
-	pe.apic_id = 1 - lapic_cpu_number();
-	pe.cpu_flags = PROCENTRY_FLAG_EN;
+static void
+mpbios_dflt_conf_bus(device_t self, const struct dflt_conf_entry *dflt_conf)
+{
+	struct mpbios_bus mpb;
+	size_t i;
 
-	mpbios_cpu((uint8_t *)&pe, self);
+	/* mpb.type is irrelevant for mpbios_bus(). */
+	mpb.bus_id = 0;
+	for (i = 0; i < __arraycount(dflt_conf->bus_type); i++) {
+		if (dflt_conf->bus_type[i] != NULL) {
+			memcpy(mpb.bus_type, dflt_conf->bus_type[i], 6);
+			mpbios_bus((u_int8_t *)&mpb, self);
+			mpb.bus_id++;
+		}
+	}
+}
+
+static void
+mpbios_dflt_conf_ioapic(device_t self)
+{
+	struct mpbios_ioapic mpio;
+
+	/* mpio.type is irrelevant for mpbios_ioapic(). */
+	mpio.apic_id = DFLT_IOAPIC_ID;
+	/* XXX Let ioapic driver read real APIC version... */
+	mpio.apic_version = 0;
+	mpio.apic_flags = IOAPICENTRY_FLAG_EN;
+	mpio.apic_address = (uint32_t)IOAPIC_BASE_DEFAULT;
+	mpbios_ioapic((uint8_t *)&mpio, self);
+}
+
+static void
+mpbios_dflt_conf_int(device_t self, const struct dflt_conf_entry *dflt_conf,
+                     const int *dflt_bus_irq)
+{
+	struct   mpbios_int mpi;
+	size_t   i;
+	int      cur_intr;
+	uint16_t level_inv;
+
+	cur_intr = 0;
+	/*
+	 * INTIN0
+	 */
+	/*
+	 * 8259A INTR is connected to INTIN0 for default configs 1-6, but not
+	 * for default config 7 (sec. 5.3).
+	 */
+	if ((dflt_conf->flags & INTIN0_NC) == 0) {
+		/* mpi.type is irrelevant for mpbios_int(). */
+		mpi.int_type = MPS_INTTYPE_ExtINT;
+		mpi.int_flags = 0;
+		mpi.src_bus_id = 0;
+		mpi.src_bus_irq = 0;
+		mpi.dst_apic_id = DFLT_IOAPIC_ID;
+		mpi.dst_apic_int = 0;
+		mpbios_int((u_int8_t *)&mpi, MPS_MCT_IOINT,
+		           &mp_intrs[cur_intr++]);
+	}
+
+	/*
+	 * INTINx
+	 */
+	/* mpi.type is irrelevant for mpbios_int(). */
+	mpi.int_type = MPS_INTTYPE_INT;
+	/*
+	 * PCI interrupt lines appear as (E)ISA interrupt lines/on bus 0
+	 * (sec. 5.2).
+	 */
+	mpi.src_bus_id = 0;
+	mpi.dst_apic_id = DFLT_IOAPIC_ID;
+	/*
+	 * Compliant systems must convert active-low, level-triggered interrupts
+	 * to active-high by external inverters before INTINx (table 5-1;
+	 * sec. 5.3.2).
+	 */
+	if (dflt_conf->flags & ELCR_INV) {
+#ifdef X86_MPBIOS_SUPPORT_EISA
+		/* Systems with ELCRs use them to control the inverters. */
+		level_inv = ((uint16_t)inb(ELCR1) << 8) | inb(ELCR0);
+#else
+		level_inv = 0;
+#endif
+	} else if (dflt_conf->flags & MCA_INV) {
+		/* MCA systems have fixed inverters. */
+		level_inv = 0xffffU;
+	} else {
+		level_inv = 0;
+	}
+	for (i = 0; i < __arraycount(dflt_bus_irq_tab[0]); i++) {
+		if (dflt_bus_irq[i] >= 0) {
+			mpi.src_bus_irq = (uint8_t)dflt_bus_irq[i];
+			if (level_inv & (1U << mpi.src_bus_irq))
+				mpi.int_flags = (MPS_INTTR_LEVEL << 2)
+				                | MPS_INTPO_ACTHI;
+			else
+				mpi.int_flags = 0; /* conforms to bus spec. */
+			mpi.dst_apic_int = (uint8_t)i;
+			mpbios_int((u_int8_t *)&mpi, MPS_MCT_IOINT,
+			           &mp_intrs[cur_intr++]);
+		}
+	}
+
+	/*
+	 * LINTINx
+	 */
+	/* mpi.type is irrelevant for mpbios_int(). */
+	mpi.int_flags = 0;
+	mpi.src_bus_id = 0;
+	mpi.src_bus_irq = 0;
+	mpi.dst_apic_id = MPS_ALL_APICS;
+	for (i = 0; i < __arraycount(dflt_lint_tab); i++) {
+		mpi.int_type = dflt_lint_tab[i];
+		mpi.dst_apic_int = (uint8_t)i;
+		mpbios_int((u_int8_t *)&mpi, MPS_MCT_LINT,
+		           &mp_intrs[cur_intr++]);
+	}
 }
 
 /*

Reply via email to