diff --git a/sys/i386/i386/io_apic.c b/sys/i386/i386/io_apic.c index c1e3b07da443..c00bebf17658 100644 --- a/sys/i386/i386/io_apic.c +++ b/sys/i386/i386/io_apic.c @@ -99,6 +99,7 @@ struct ioapic_intsrc { u_int io_edgetrigger:1; u_int io_masked:1; int io_dest:5; + int io_bus:4; }; struct ioapic { @@ -114,6 +115,8 @@ struct ioapic { static u_int ioapic_read(volatile ioapic_t *apic, int reg); static void ioapic_write(volatile ioapic_t *apic, int reg, u_int val); +static const char *ioapic_bus_string(int bus_type); +static void ioapic_print_vector(struct ioapic_intsrc *intpin); static void ioapic_enable_source(struct intsrc *isrc); static void ioapic_disable_source(struct intsrc *isrc); static void ioapic_eoi_source(struct intsrc *isrc); @@ -162,6 +165,45 @@ ioapic_write(volatile ioapic_t *apic, int reg, u_int val) apic->iowin = val; } +static const char * +ioapic_bus_string(int bus_type) +{ + + switch (bus_type) { + case APIC_BUS_ISA: + return ("ISA"); + case APIC_BUS_EISA: + return ("EISA"); + case APIC_BUS_PCI: + return ("PCI"); + default: + return ("unknown"); + } +} + +static void +ioapic_print_vector(struct ioapic_intsrc *intpin) +{ + + switch (intpin->io_vector) { + case VECTOR_DISABLED: + printf("disabled"); + break; + case VECTOR_EXTINT: + printf("ExtINT"); + break; + case VECTOR_NMI: + printf("NMI"); + break; + case VECTOR_SMI: + printf("SMI"); + break; + default: + printf("%s IRQ %u", ioapic_bus_string(intpin->io_bus), + intpin->io_vector); + } +} + static void ioapic_enable_source(struct intsrc *isrc) { @@ -298,10 +340,7 @@ ioapic_program_destination(struct ioapic_intsrc *intpin) if (bootverbose) { printf("ioapic%u: routing intpin %u (", io->io_id, intpin->io_intpin); - if (intpin->io_vector == VECTOR_EXTINT) - printf("ExtINT"); - else - printf("IRQ %u", intpin->io_vector); + ioapic_print_vector(intpin); printf(") to cluster %u\n", intpin->io_dest); } ioapic_program_intpin(intpin); @@ -490,44 +529,36 @@ ioapic_create(uintptr_t addr, int32_t apic_id, int intbase) intpin->io_vector = intbase + i; /* - * Assume that pin 0 on the first IO APIC is an ExtINT pin by - * default. Assume that intpins 1-15 are ISA interrupts and - * use suitable defaults for those. Assume that all other - * intpins are PCI interrupts. Enable the ExtINT pin if - * mixed mode is available and active but mask all other pins. + * Assume that pin 0 on the first I/O APIC is an ExtINT pin + * and that pins 1-15 are ISA interrupts. Assume that all + * other pins are PCI interrupts. */ - if (intpin->io_vector == 0) { - intpin->io_activehi = 1; - intpin->io_edgetrigger = 1; - intpin->io_vector = VECTOR_EXTINT; - if (mixed_mode_enabled && mixed_mode_active) - intpin->io_masked = 0; - else - intpin->io_masked = 1; - } else if (intpin->io_vector < IOAPIC_ISA_INTS) { + if (intpin->io_vector == 0) + ioapic_set_extint(io, i); + else if (intpin->io_vector < IOAPIC_ISA_INTS) { + intpin->io_bus = APIC_BUS_ISA; intpin->io_activehi = 1; intpin->io_edgetrigger = 1; intpin->io_masked = 1; } else { + intpin->io_bus = APIC_BUS_PCI; intpin->io_activehi = 0; intpin->io_edgetrigger = 0; intpin->io_masked = 1; } /* - * Start off without a logical cluster destination until - * the pin is enabled. + * Route interrupts to the BSP by default using physical + * addressing. Vectored interrupts get readdressed using + * logical IDs to CPU clusters when they are enabled. */ intpin->io_dest = DEST_NONE; - if (bootverbose) { + if (bootverbose && intpin->io_vector != VECTOR_DISABLED) { printf("ioapic%u: intpin %d -> ", io->io_id, i); - if (intpin->io_vector == VECTOR_EXTINT) - printf("ExtINT"); - else - printf("irq %u", intpin->io_vector); - printf(" (%s, active%s)\n", intpin->io_edgetrigger ? - "edge" : "level", intpin->io_activehi ? "hi" : - "lo"); + ioapic_print_vector(intpin); + printf(" (%s, %s)\n", intpin->io_edgetrigger ? + "edge" : "level", intpin->io_activehi ? "high" : + "low"); } value = ioapic_read(apic, IOAPIC_REDTBL_LO(i)); ioapic_write(apic, IOAPIC_REDTBL_LO(i), value | IOART_INTMSET); @@ -581,6 +612,25 @@ ioapic_remap_vector(void *cookie, u_int pin, int vector) return (0); } +int +ioapic_set_bus(void *cookie, u_int pin, int bus_type) +{ + struct ioapic *io; + + if (bus_type < 0 || bus_type > APIC_BUS_MAX) + return (EINVAL); + io = (struct ioapic *)cookie; + if (pin >= io->io_numintr) + return (EINVAL); + if (io->io_pins[pin].io_vector >= NUM_IO_INTS) + return (EINVAL); + io->io_pins[pin].io_bus = bus_type; + if (bootverbose) + printf("ioapic%u: intpin %d bus %s\n", io->io_id, pin, + ioapic_bus_string(bus_type)); + return (0); +} + int ioapic_set_nmi(void *cookie, u_int pin) { @@ -589,8 +639,11 @@ ioapic_set_nmi(void *cookie, u_int pin) io = (struct ioapic *)cookie; if (pin >= io->io_numintr) return (EINVAL); + if (io->io_pins[pin].io_vector == VECTOR_NMI) + return (0); if (io->io_pins[pin].io_vector >= NUM_IO_INTS) return (EINVAL); + io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN; io->io_pins[pin].io_vector = VECTOR_NMI; io->io_pins[pin].io_masked = 0; io->io_pins[pin].io_edgetrigger = 1; @@ -609,8 +662,11 @@ ioapic_set_smi(void *cookie, u_int pin) io = (struct ioapic *)cookie; if (pin >= io->io_numintr) return (EINVAL); + if (io->io_pins[pin].io_vector == VECTOR_SMI) + return (0); if (io->io_pins[pin].io_vector >= NUM_IO_INTS) return (EINVAL); + io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN; io->io_pins[pin].io_vector = VECTOR_SMI; io->io_pins[pin].io_masked = 0; io->io_pins[pin].io_edgetrigger = 1; @@ -629,10 +685,18 @@ ioapic_set_extint(void *cookie, u_int pin) io = (struct ioapic *)cookie; if (pin >= io->io_numintr) return (EINVAL); + if (io->io_pins[pin].io_vector == VECTOR_EXTINT) + return (0); if (io->io_pins[pin].io_vector >= NUM_IO_INTS) return (EINVAL); + io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN; io->io_pins[pin].io_vector = VECTOR_EXTINT; - io->io_pins[pin].io_masked = 0; + + /* Enable this pin if mixed mode is available and active. */ + if (mixed_mode_enabled && mixed_mode_active) + io->io_pins[pin].io_masked = 0; + else + io->io_pins[pin].io_masked = 1; io->io_pins[pin].io_edgetrigger = 1; io->io_pins[pin].io_activehi = 1; if (bootverbose) diff --git a/sys/i386/i386/mptable.c b/sys/i386/i386/mptable.c index 294e92f75868..262d336e261d 100644 --- a/sys/i386/i386/mptable.c +++ b/sys/i386/i386/mptable.c @@ -646,14 +646,28 @@ mptable_parse_io_int(int_entry_ptr intr) pin = intr->dst_apic_int; switch (intr->int_type) { case INTENTRY_TYPE_INT: - if (busses[intr->src_bus_id].bus_type == NOBUS) + switch (busses[intr->src_bus_id].bus_type) { + case NOBUS: panic("interrupt from missing bus"); - if (busses[intr->src_bus_id].bus_type == ISA && - intr->src_bus_irq != pin) { + case ISA: + case EISA: + if (busses[intr->src_bus_id].bus_type == ISA) + ioapic_set_bus(ioapic, pin, APIC_BUS_ISA); + else + ioapic_set_bus(ioapic, pin, APIC_BUS_EISA); + if (intr->src_bus_irq == pin) + break; ioapic_remap_vector(ioapic, pin, intr->src_bus_irq); if (ioapic_get_vector(ioapic, intr->src_bus_irq) == intr->src_bus_irq) ioapic_disable_pin(ioapic, intr->src_bus_irq); + break; + case PCI: + ioapic_set_bus(ioapic, pin, APIC_BUS_PCI); + break; + default: + ioapic_set_bus(ioapic, pin, APIC_BUS_UNKNOWN); + break; } break; case INTENTRY_TYPE_NMI: diff --git a/sys/i386/include/apicvar.h b/sys/i386/include/apicvar.h index 7bdcc7f75803..cc46fdac365d 100644 --- a/sys/i386/include/apicvar.h +++ b/sys/i386/include/apicvar.h @@ -113,6 +113,12 @@ #define APIC_IPI_DEST_ALL -2 #define APIC_IPI_DEST_OTHERS -3 +#define APIC_BUS_UNKNOWN -1 +#define APIC_BUS_ISA 0 +#define APIC_BUS_EISA 1 +#define APIC_BUS_PCI 2 +#define APIC_BUS_MAX APIC_BUS_PCI + /* * An APIC enumerator is a psuedo bus driver that enumerates APIC's including * CPU's and I/O APIC's. @@ -141,6 +147,7 @@ int ioapic_get_vector(void *cookie, u_int pin); int ioapic_next_logical_cluster(void); void ioapic_register(void *cookie); int ioapic_remap_vector(void *cookie, u_int pin, int vector); +int ioapic_set_bus(void *cookie, u_int pin, int bus_type); int ioapic_set_extint(void *cookie, u_int pin); int ioapic_set_nmi(void *cookie, u_int pin); int ioapic_set_polarity(void *cookie, u_int pin, enum intr_polarity pol);