--- mpbios_rev_1_60.c 2013-05-29 20:18:24.000000000 +0200 +++ mpbios.c 2013-05-29 20:18:23.000000000 +0200 @@ -147,10 +147,6 @@ #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 @@ 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_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 @@ goto err; } - aprint_normal_dev(self, "MP default configuration %d\n", - mp_fps->mpfb1); return 10; } @@ -476,6 +480,55 @@ 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 @@ 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 @@ /* 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); + + /* + * 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); - /* XXX */ - aprint_verbose_dev(self, "WARNING: interrupts not configured\n"); + /* 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,138 @@ } static void -mpbios_cpus(device_t self) +mpbios_dflt_conf_cpu(device_t self) +{ + struct mpbios_proc mpp; + + /* 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); +} + +static void +mpbios_dflt_conf_bus(device_t self, const struct dflt_conf_entry *dflt_conf) +{ + struct mpbios_bus mpb; + size_t i; + + /* 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_proc pe; - /* use default addresses */ - pe.apic_id = lapic_cpu_number(); - pe.cpu_flags = PROCENTRY_FLAG_EN|PROCENTRY_FLAG_BP; + struct mpbios_int mpi; + size_t i; + int cur_intr; + uint16_t level_inv; - mpbios_cpu((uint8_t *)&pe, self); + 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++]); + } - pe.apic_id = 1 - lapic_cpu_number(); - pe.cpu_flags = PROCENTRY_FLAG_EN; + /* + * 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) { + /* Systems with ELCRs use them to control the inverters. */ + level_inv = ((uint16_t)inb(ELCR1) << 8) | inb(ELCR0); + } 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++]); + } + } - mpbios_cpu((uint8_t *)&pe, self); + /* + * 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++]); + } } /*