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++]);
+ }
}
/*