diff options
-rw-r--r-- | sys/amd64/acpica/madt.c | 163 | ||||
-rw-r--r-- | sys/amd64/amd64/intr_machdep.c | 11 | ||||
-rw-r--r-- | sys/amd64/amd64/io_apic.c | 111 | ||||
-rw-r--r-- | sys/amd64/amd64/legacy.c | 72 | ||||
-rw-r--r-- | sys/amd64/amd64/local_apic.c | 22 | ||||
-rw-r--r-- | sys/amd64/amd64/mptable.c | 64 | ||||
-rw-r--r-- | sys/amd64/amd64/mptable_pci.c | 10 | ||||
-rw-r--r-- | sys/amd64/amd64/nexus.c | 10 | ||||
-rw-r--r-- | sys/amd64/include/apicvar.h | 12 | ||||
-rw-r--r-- | sys/amd64/include/intr_machdep.h | 9 | ||||
-rw-r--r-- | sys/amd64/include/legacyvar.h | 1 | ||||
-rw-r--r-- | sys/amd64/include/pmap.h | 1 | ||||
-rw-r--r-- | sys/amd64/isa/atpic.c | 158 | ||||
-rw-r--r-- | sys/amd64/isa/atpic_vector.S | 2 | ||||
-rw-r--r-- | sys/amd64/isa/clock.c | 11 | ||||
-rw-r--r-- | sys/amd64/isa/icu.h | 30 | ||||
-rw-r--r-- | sys/amd64/isa/nmi.c | 8 | ||||
-rw-r--r-- | sys/amd64/pci/pci_bus.c | 2 | ||||
-rw-r--r-- | sys/conf/files.amd64 | 1 |
19 files changed, 506 insertions, 192 deletions
diff --git a/sys/amd64/acpica/madt.c b/sys/amd64/acpica/madt.c index d8d6437..575e916 100644 --- a/sys/amd64/acpica/madt.c +++ b/sys/amd64/acpica/madt.c @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include <machine/specialreg.h> #include "acpi.h" +#include <contrib/dev/acpica/actables.h> #include <dev/acpica/acpivar.h> #include <dev/pci/pcivar.h> @@ -69,14 +70,15 @@ struct lapic_info { u_int la_apic_id:8; } lapics[NLAPICS + 1]; +static int madt_found_sci_override; static MULTIPLE_APIC_TABLE *madt; static vm_paddr_t madt_physaddr; static vm_offset_t madt_length; MALLOC_DEFINE(M_MADT, "MADT Table", "ACPI MADT Table Items"); -static u_char interrupt_polarity(UINT16 Polarity); -static u_char interrupt_trigger(UINT16 TriggerMode); +static enum intr_polarity interrupt_polarity(UINT16 Polarity, UINT8 Source); +static enum intr_trigger interrupt_trigger(UINT16 TriggerMode, UINT8 Source); static int madt_find_cpu(u_int acpi_id, u_int *apic_id); static int madt_find_interrupt(int intr, void **apic, u_int *pin); static void *madt_map(vm_paddr_t pa, int offset, vm_offset_t length); @@ -157,6 +159,7 @@ madt_map_table(vm_paddr_t pa, int offset, const char *sig) { ACPI_TABLE_HEADER *header; vm_offset_t length; + void *table; header = madt_map(pa, offset, sizeof(ACPI_TABLE_HEADER)); if (strncmp(header->Signature, sig, 4) != 0) { @@ -165,7 +168,14 @@ madt_map_table(vm_paddr_t pa, int offset, const char *sig) } length = header->Length; madt_unmap(header, sizeof(ACPI_TABLE_HEADER)); - return (madt_map(pa, offset, length)); + table = madt_map(pa, offset, length); + if (ACPI_FAILURE(AcpiTbVerifyTableChecksum(table))) { + if (bootverbose) + printf("MADT: Failed checksum for table %s\n", sig); + madt_unmap(table, length); + return (NULL); + } + return (table); } static void @@ -215,6 +225,16 @@ madt_probe(void) * Page 0 is used to map in the headers of candidate ACPI tables. */ if (rsdp->Revision >= 2) { + /* + * AcpiOsGetRootPointer only verifies the checksum for + * the version 1.0 portion of the RSDP. Version 2.0 has + * an additional checksum that we verify first. + */ + if (AcpiTbChecksum(rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0) { + if (bootverbose) + printf("MADT: RSDP failed extended checksum\n"); + return (ENXIO); + } xsdt = madt_map_table(rsdp->XsdtPhysicalAddress, 1, XSDT_SIG); if (xsdt == NULL) { if (bootverbose) @@ -251,6 +271,16 @@ madt_probe(void) printf("MADT: Found table at 0x%jx\n", (uintmax_t)madt_physaddr); + /* + * Verify that we can map the full table and that its checksum is + * correct, etc. + */ + madt = madt_map_table(madt_physaddr, 0, APIC_SIG); + if (madt == NULL) + return (ENXIO); + madt_unmap_table(madt); + madt = NULL; + return (0); } @@ -273,7 +303,6 @@ madt_probe_table(vm_paddr_t address) printf("Table '%.4s' at 0x%jx\n", table->Signature, (uintmax_t)address); - /* XXX: Verify checksum? */ if (strncmp(table->Signature, APIC_SIG, 4) != 0) { madt_unmap(table, sizeof(ACPI_TABLE_HEADER)); return (0); @@ -325,6 +354,8 @@ madt_setup_local(void) static int madt_setup_io(void) { + void *ioapic; + u_int pin; int i; /* Try to initialize ACPI so that we can access the FADT. */ @@ -337,11 +368,30 @@ madt_setup_io(void) } /* First, we run through adding I/O APIC's. */ + if (madt->PCATCompat) + ioapic_enable_mixed_mode(); madt_walk_table(madt_parse_apics, NULL); /* Second, we run through the table tweaking interrupt sources. */ madt_walk_table(madt_parse_ints, NULL); + /* + * If there was not an explicit override entry for the SCI, + * force it to use level trigger and active-low polarity. + */ + if (!madt_found_sci_override) { + if (madt_find_interrupt(AcpiGbl_FADT->SciInt, &ioapic, &pin) + != 0) + printf("MADT: Could not find APIC for SCI IRQ %d\n", + AcpiGbl_FADT->SciInt); + else { + printf( + "MADT: Forcing active-low polarity and level trigger for SCI\n"); + ioapic_set_polarity(ioapic, pin, INTR_POLARITY_LOW); + ioapic_set_triggermode(ioapic, pin, INTR_TRIGGER_LEVEL); + } + } + /* Third, we register all the I/O APIC's. */ for (i = 0; i < NIOAPICS; i++) if (ioapics[i].io_apic != NULL) @@ -446,35 +496,44 @@ madt_parse_apics(APIC_HEADER *entry, void *arg __unused) } /* - * Determine properties of an interrupt source. Note that for ACPI, - * these are only used for ISA interrupts, so we assume ISA bus values - * (Active Hi, Edge Triggered) for conforming values. + * Determine properties of an interrupt source. Note that for ACPI these + * functions are only used for ISA interrupts, so we assume ISA bus values + * (Active Hi, Edge Triggered) for conforming values except for the ACPI + * SCI for which we use Active Lo, Level Triggered. */ -static u_char -interrupt_polarity(UINT16 Polarity) +static enum intr_polarity +interrupt_polarity(UINT16 Polarity, UINT8 Source) { switch (Polarity) { case POLARITY_CONFORMS: + if (Source == AcpiGbl_FADT->SciInt) + return (INTR_POLARITY_LOW); + else + return (INTR_POLARITY_HIGH); case POLARITY_ACTIVE_HIGH: - return (1); + return (INTR_POLARITY_HIGH); case POLARITY_ACTIVE_LOW: - return (0); + return (INTR_POLARITY_LOW); default: panic("Bogus Interrupt Polarity"); } } -static u_char -interrupt_trigger(UINT16 TriggerMode) +static enum intr_trigger +interrupt_trigger(UINT16 TriggerMode, UINT8 Source) { switch (TriggerMode) { case TRIGGER_CONFORMS: + if (Source == AcpiGbl_FADT->SciInt) + return (INTR_TRIGGER_LEVEL); + else + return (INTR_TRIGGER_EDGE); case TRIGGER_EDGE: - return (1); + return (INTR_TRIGGER_EDGE); case TRIGGER_LEVEL: - return (0); + return (INTR_TRIGGER_LEVEL); default: panic("Bogus Interrupt Trigger Mode"); } @@ -532,7 +591,9 @@ madt_parse_interrupt_override(MADT_INTERRUPT_OVERRIDE *intr) { void *new_ioapic, *old_ioapic; u_int new_pin, old_pin; - int force_lo; + enum intr_trigger trig; + enum intr_polarity pol; + char buf[64]; if (bootverbose) printf("MADT: intr override: source %u, irq %u\n", @@ -546,18 +607,46 @@ madt_parse_interrupt_override(MADT_INTERRUPT_OVERRIDE *intr) } /* - * If the SCI is remapped to a non-ISA global interrupt, - * force it to level trigger and active-lo polarity. + * Lookup the appropriate trigger and polarity modes for this + * entry. + */ + trig = interrupt_trigger(intr->TriggerMode, intr->Source); + pol = interrupt_polarity(intr->Polarity, intr->Source); + + /* * If the SCI is identity mapped but has edge trigger and - * active-hi polarity, also force it to use level/lo. + * active-hi polarity or the force_sci_lo tunable is set, + * force it to use level/lo. */ - force_lo = 0; - if (intr->Source == AcpiGbl_FADT->SciInt) - if (intr->Interrupt > 15 || (intr->Interrupt == intr->Source && - intr->TriggerMode == TRIGGER_EDGE && - intr->Polarity == POLARITY_ACTIVE_HIGH)) - force_lo = 1; + if (intr->Source == AcpiGbl_FADT->SciInt) { + madt_found_sci_override = 1; + if (getenv_string("hw.acpi.sci.trigger", buf, sizeof(buf))) { + if (tolower(buf[0]) == 'e') + trig = INTR_TRIGGER_EDGE; + else if (tolower(buf[0]) == 'l') + trig = INTR_TRIGGER_LEVEL; + else + panic( + "Invalid trigger %s: must be 'edge' or 'level'", + buf); + printf("MADT: Forcing SCI to %s trigger\n", + trig == INTR_TRIGGER_EDGE ? "edge" : "level"); + } + if (getenv_string("hw.acpi.sci.polarity", buf, sizeof(buf))) { + if (tolower(buf[0]) == 'h') + pol = INTR_POLARITY_HIGH; + else if (tolower(buf[0]) == 'l') + pol = INTR_POLARITY_LOW; + else + panic( + "Invalid polarity %s: must be 'high' or 'low'", + buf); + printf("MADT: Forcing SCI to active %s polarity\n", + pol == INTR_POLARITY_HIGH ? "high" : "low"); + } + } + /* Remap the IRQ if it is mapped to a different interrupt vector. */ if (intr->Source != intr->Interrupt) { /* * If the SCI is remapped to a non-ISA global interrupt, @@ -577,18 +666,10 @@ madt_parse_interrupt_override(MADT_INTERRUPT_OVERRIDE *intr) intr->Source) ioapic_disable_pin(old_ioapic, old_pin); } - if (force_lo) { - printf( - "MADT: Forcing active-lo polarity and level trigger for IRQ %d\n", - intr->Source); - ioapic_set_polarity(new_ioapic, new_pin, 0); - ioapic_set_triggermode(new_ioapic, new_pin, 0); - } else { - ioapic_set_polarity(new_ioapic, new_pin, - interrupt_polarity(intr->Polarity)); - ioapic_set_triggermode(new_ioapic, new_pin, - interrupt_trigger(intr->TriggerMode)); - } + + /* Program the polarity and trigger mode. */ + ioapic_set_triggermode(new_ioapic, new_pin, trig); + ioapic_set_polarity(new_ioapic, new_pin, pol); } /* @@ -609,10 +690,10 @@ madt_parse_nmi(MADT_NMI_SOURCE *nmi) ioapic_set_nmi(ioapic, pin); if (nmi->TriggerMode != TRIGGER_CONFORMS) ioapic_set_triggermode(ioapic, pin, - interrupt_trigger(nmi->TriggerMode)); + interrupt_trigger(nmi->TriggerMode, 0)); if (nmi->Polarity != TRIGGER_CONFORMS) ioapic_set_polarity(ioapic, pin, - interrupt_polarity(nmi->Polarity)); + interrupt_polarity(nmi->Polarity, 0)); } /* @@ -638,10 +719,10 @@ madt_parse_local_nmi(MADT_LOCAL_APIC_NMI *nmi) lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_NMI); if (nmi->TriggerMode != TRIGGER_CONFORMS) lapic_set_lvt_triggermode(apic_id, pin, - interrupt_trigger(nmi->TriggerMode)); + interrupt_trigger(nmi->TriggerMode, 0)); if (nmi->Polarity != POLARITY_CONFORMS) lapic_set_lvt_polarity(apic_id, pin, - interrupt_polarity(nmi->Polarity)); + interrupt_polarity(nmi->Polarity, 0)); } /* diff --git a/sys/amd64/amd64/intr_machdep.c b/sys/amd64/amd64/intr_machdep.c index d023a86..f7f51c0 100644 --- a/sys/amd64/amd64/intr_machdep.c +++ b/sys/amd64/amd64/intr_machdep.c @@ -138,6 +138,17 @@ intr_remove_handler(void *cookie) return (error); } +int +intr_config_intr(int vector, enum intr_trigger trig, enum intr_polarity pol) +{ + struct intsrc *isrc; + + isrc = intr_lookup_source(vector); + if (isrc == NULL) + return (EINVAL); + return (isrc->is_pic->pic_config_intr(isrc, trig, pol)); +} + void intr_execute_handlers(struct intsrc *isrc, struct intrframe *iframe) { diff --git a/sys/amd64/amd64/io_apic.c b/sys/amd64/amd64/io_apic.c index b620440..b662e50 100644 --- a/sys/amd64/amd64/io_apic.c +++ b/sys/amd64/amd64/io_apic.c @@ -51,10 +51,6 @@ __FBSDID("$FreeBSD$"); #include <machine/apicvar.h> #include <machine/segments.h> -#if defined(DEV_ISA) && defined(DEV_ATPIC) && !defined(NO_MIXED_MODE) -#define MIXED_MODE -#endif - #define IOAPIC_ISA_INTS 16 #define IOAPIC_MEM_REGION 32 #define IOAPIC_REDTBL_LO(i) (IOAPIC_REDTBL + (i) * 2) @@ -117,9 +113,6 @@ struct ioapic { struct ioapic_intsrc io_pins[0]; }; -static STAILQ_HEAD(,ioapic) ioapic_list = STAILQ_HEAD_INITIALIZER(ioapic_list); -static u_int next_id, program_logical_dest; - 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 void ioapic_enable_source(struct intsrc *isrc); @@ -128,19 +121,28 @@ static void ioapic_eoi_source(struct intsrc *isrc); static void ioapic_enable_intr(struct intsrc *isrc); static int ioapic_vector(struct intsrc *isrc); static int ioapic_source_pending(struct intsrc *isrc); +static int ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig, + enum intr_polarity pol); static void ioapic_suspend(struct intsrc *isrc); static void ioapic_resume(struct intsrc *isrc); static void ioapic_program_destination(struct ioapic_intsrc *intpin); -#ifdef MIXED_MODE static void ioapic_setup_mixed_mode(struct ioapic_intsrc *intpin); -#endif +static STAILQ_HEAD(,ioapic) ioapic_list = STAILQ_HEAD_INITIALIZER(ioapic_list); struct pic ioapic_template = { ioapic_enable_source, ioapic_disable_source, ioapic_eoi_source, ioapic_enable_intr, ioapic_vector, ioapic_source_pending, - ioapic_suspend, ioapic_resume }; + ioapic_suspend, ioapic_resume, + ioapic_config_intr }; -static int next_ioapic_base, logical_clusters, current_cluster; +static int current_cluster, logical_clusters, next_ioapic_base; +static u_int mixed_mode_enabled, next_id, program_logical_dest; +#if defined(NO_MIXED_MODE) || !defined(DEV_ATPIC) +static int mixed_mode_active = 0; +#else +static int mixed_mode_active = 1; +#endif +TUNABLE_INT("hw.apic.mixed_mode", &mixed_mode_active); static u_int ioapic_read(volatile ioapic_t *apic, int reg) @@ -291,6 +293,41 @@ ioapic_source_pending(struct intsrc *isrc) return (lapic_intr_pending(intpin->io_vector)); } +static int +ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig, + enum intr_polarity pol) +{ + struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc; + struct ioapic *io = (struct ioapic *)isrc->is_pic; + + KASSERT(!(trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM), + ("%s: Conforming trigger or polarity\n", __func__)); + + /* + * For now we ignore any requests but do output any changes that + * would be made to the console it bootverbose is enabled. The only + * known causes of these messages so far is a bug in acpi(4) that + * causes the ISA IRQs used for PCI interrupts in PIC mode to be + * set to level/low when they aren't being used. There are possibly + * legitimate requests, so at some point when the acpi(4) driver is + * fixed this code can be changed to actually change the intpin as + * requested. + */ + if (!bootverbose) + return (0); + if (intpin->io_edgetrigger != (trig == INTR_TRIGGER_EDGE)) + printf( + "ioapic%u: Request to change trigger for pin %u to %s ignored\n", + io->io_id, intpin->io_intpin, trig == INTR_TRIGGER_EDGE ? + "edge" : "level"); + if (intpin->io_activehi != (pol == INTR_POLARITY_HIGH)) + printf( + "ioapic%u: Request to change polarity for pin %u to %s ignored\n", + io->io_id, intpin->io_intpin, pol == INTR_POLARITY_HIGH ? + "high" : "low"); + return (0); +} + static void ioapic_suspend(struct intsrc *isrc) { @@ -306,6 +343,17 @@ ioapic_resume(struct intsrc *isrc) } /* + * APIC enumerators call this function to indicate that the 8259A AT PICs + * are available and that mixed mode can be used. + */ +void +ioapic_enable_mixed_mode(void) +{ + + mixed_mode_enabled = 1; +} + +/* * Allocate and return a logical cluster ID. Note that the first time * this is called, it returns cluster 0. ioapic_enable_intr() treats * the two cases of logical_clusters == 0 and logical_clusters == 1 the @@ -380,14 +428,17 @@ ioapic_create(uintptr_t addr, int32_t apic_id, int intbase) * 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 by - * default but mask all other pins. + * intpins are PCI interrupts. Enable the ExtINT pin if + * mixed mode is available and active but mask all other pins. */ if (intpin->io_vector == 0) { intpin->io_activehi = 1; intpin->io_edgetrigger = 1; intpin->io_vector = VECTOR_EXTINT; - intpin->io_masked = 0; + if (mixed_mode_enabled && mixed_mode_active) + intpin->io_masked = 0; + else + intpin->io_masked = 1; } else if (intpin->io_vector < IOAPIC_ISA_INTS) { intpin->io_activehi = 1; intpin->io_edgetrigger = 1; @@ -526,36 +577,36 @@ ioapic_set_extint(void *cookie, u_int pin) } int -ioapic_set_polarity(void *cookie, u_int pin, char activehi) +ioapic_set_polarity(void *cookie, u_int pin, enum intr_polarity pol) { struct ioapic *io; io = (struct ioapic *)cookie; - if (pin >= io->io_numintr) + if (pin >= io->io_numintr || pol == INTR_POLARITY_CONFORM) return (EINVAL); if (io->io_pins[pin].io_vector >= NUM_IO_INTS) return (EINVAL); - io->io_pins[pin].io_activehi = activehi; + io->io_pins[pin].io_activehi = (pol == INTR_POLARITY_HIGH); if (bootverbose) printf("ioapic%u: intpin %d polarity: %s\n", io->io_id, pin, - activehi ? "active-hi" : "active-lo"); + pol == INTR_POLARITY_HIGH ? "high" : "low"); return (0); } int -ioapic_set_triggermode(void *cookie, u_int pin, char edgetrigger) +ioapic_set_triggermode(void *cookie, u_int pin, enum intr_trigger trigger) { struct ioapic *io; io = (struct ioapic *)cookie; - if (pin >= io->io_numintr) + if (pin >= io->io_numintr || trigger == INTR_TRIGGER_CONFORM) return (EINVAL); if (io->io_pins[pin].io_vector >= NUM_IO_INTS) return (EINVAL); - io->io_pins[pin].io_edgetrigger = edgetrigger; + io->io_pins[pin].io_edgetrigger = (trigger == INTR_TRIGGER_EDGE); if (bootverbose) printf("ioapic%u: intpin %d trigger: %s\n", io->io_id, pin, - edgetrigger ? "edge" : "level"); + trigger == INTR_TRIGGER_EDGE ? "edge" : "level"); return (0); } @@ -632,12 +683,15 @@ ioapic_register(void *cookie) ioapic_write(apic, IOAPIC_REDTBL_HI(i), flags); mtx_unlock_spin(&icu_lock); if (pin->io_vector < NUM_IO_INTS) { -#ifdef MIXED_MODE - /* Route IRQ0 via the 8259A using mixed mode. */ - if (pin->io_vector == 0) + + /* + * Route IRQ0 via the 8259A using mixed mode if + * mixed mode is available and turned on. + */ + if (pin->io_vector == 0 && mixed_mode_active && + mixed_mode_enabled) ioapic_setup_mixed_mode(pin); else -#endif intr_register_source(&pin->io_intsrc); } @@ -664,7 +718,6 @@ ioapic_set_logical_destinations(void *arg __unused) SYSINIT(ioapic_destinations, SI_SUB_SMP, SI_ORDER_SECOND, ioapic_set_logical_destinations, NULL) -#ifdef MIXED_MODE /* * Support for mixed-mode interrupt sources. These sources route an ISA * IRQ through the 8259A's via the ExtINT on pin 0 of the I/O APIC that @@ -673,7 +726,7 @@ SYSINIT(ioapic_destinations, SI_SUB_SMP, SI_ORDER_SECOND, * that IRQ instead. */ -void +static void ioapic_setup_mixed_mode(struct ioapic_intsrc *intpin) { struct ioapic_intsrc *extint; @@ -693,5 +746,3 @@ ioapic_setup_mixed_mode(struct ioapic_intsrc *intpin) ioapic_assign_cluster(extint); #endif } - -#endif /* MIXED_MODE */ diff --git a/sys/amd64/amd64/legacy.c b/sys/amd64/amd64/legacy.c index 0acea92..44a1229 100644 --- a/sys/amd64/amd64/legacy.c +++ b/sys/amd64/amd64/legacy.c @@ -41,7 +41,9 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/malloc.h> #include <machine/bus.h> +#include <sys/pcpu.h> #include <sys/rman.h> +#include <sys/smp.h> #include <machine/legacyvar.h> #include <machine/resource.h> @@ -138,7 +140,9 @@ legacy_probe(device_t dev) static int legacy_attach(device_t dev) { - device_t child; + device_t child; + int i; + struct pcpu *pc; /* * First, let our child driver's identify any child devices that @@ -148,6 +152,21 @@ legacy_attach(device_t dev) bus_generic_probe(dev); bus_generic_attach(dev); + /* Attach CPU pseudo-driver. */ + if (!devclass_get_device(devclass_find("cpu"), 0)) { + for (i = 0; i <= mp_maxid; i++) + if (!CPU_ABSENT(i)) { + pc = pcpu_find(i); + KASSERT(pc != NULL, ("pcpu_find failed")); + child = BUS_ADD_CHILD(dev, 0, "cpu", i); + if (child == NULL) + panic("legacy_attach cpu"); + device_probe_and_attach(child); + pc->pc_device = child; + device_set_ivars(child, pc); + } + } + /* * If we didn't see ISA on a pci bridge, create some * connection points now so it shows up "on motherboard". @@ -305,3 +324,54 @@ legacy_delete_resource(device_t dev, device_t child, int type, int rid) resource_list_delete(rl, type, rid); } + +/* + * Legacy CPU attachment when ACPI is not available. Drivers like + * cpufreq(4) hang off this. + */ +static int cpu_read_ivar(device_t dev, device_t child, int index, + uintptr_t *result); + +static device_method_t cpu_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, bus_generic_probe), + DEVMETHOD(device_attach, bus_generic_attach), + DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* Bus interface */ + DEVMETHOD(bus_read_ivar, cpu_read_ivar), + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + { 0, 0 } +}; + +static driver_t cpu_driver = { + "cpu", + cpu_methods, + 1, /* no softc */ +}; +static devclass_t cpu_devclass; +DRIVER_MODULE(cpu, legacy, cpu_driver, cpu_devclass, 0, 0); + +static int +cpu_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) +{ + struct pcpu *pc; + + if (index != 0) + return (ENOENT); + pc = device_get_ivars(child); + if (pc == NULL) + return (ENOENT); + *result = (uintptr_t)pc; + return (0); +} diff --git a/sys/amd64/amd64/local_apic.c b/sys/amd64/amd64/local_apic.c index 54efeea..839cb03 100644 --- a/sys/amd64/amd64/local_apic.c +++ b/sys/amd64/amd64/local_apic.c @@ -422,50 +422,52 @@ lapic_set_lvt_mode(u_int apic_id, u_int pin, u_int32_t mode) } int -lapic_set_lvt_polarity(u_int apic_id, u_int pin, u_char activehi) +lapic_set_lvt_polarity(u_int apic_id, u_int pin, enum intr_polarity pol) { - if (pin > LVT_MAX) + if (pin > LVT_MAX || pol == INTR_POLARITY_CONFORM) return (EINVAL); if (apic_id == APIC_ID_ALL) { - lvts[pin].lvt_activehi = activehi; + lvts[pin].lvt_activehi = (pol == INTR_POLARITY_HIGH); if (bootverbose) printf("lapic:"); } else { KASSERT(lapics[apic_id].la_present, ("%s: missing APIC %u", __func__, apic_id)); lapics[apic_id].la_lvts[pin].lvt_active = 1; - lapics[apic_id].la_lvts[pin].lvt_activehi = activehi; + lapics[apic_id].la_lvts[pin].lvt_activehi = + (pol == INTR_POLARITY_HIGH); if (bootverbose) printf("lapic%u:", apic_id); } if (bootverbose) printf(" LINT%u polarity: active-%s\n", pin, - activehi ? "hi" : "lo"); + pol == INTR_POLARITY_HIGH ? "high" : "low"); return (0); } int -lapic_set_lvt_triggermode(u_int apic_id, u_int pin, u_char edgetrigger) +lapic_set_lvt_triggermode(u_int apic_id, u_int pin, enum intr_trigger trigger) { - if (pin > LVT_MAX) + if (pin > LVT_MAX || trigger == INTR_TRIGGER_CONFORM) return (EINVAL); if (apic_id == APIC_ID_ALL) { - lvts[pin].lvt_edgetrigger = edgetrigger; + lvts[pin].lvt_edgetrigger = (trigger == INTR_TRIGGER_EDGE); if (bootverbose) printf("lapic:"); } else { KASSERT(lapics[apic_id].la_present, ("%s: missing APIC %u", __func__, apic_id)); - lapics[apic_id].la_lvts[pin].lvt_edgetrigger = edgetrigger; + lapics[apic_id].la_lvts[pin].lvt_edgetrigger = + (trigger == INTR_TRIGGER_EDGE); lapics[apic_id].la_lvts[pin].lvt_active = 1; if (bootverbose) printf("lapic%u:", apic_id); } if (bootverbose) printf(" LINT%u trigger: %s\n", pin, - edgetrigger ? "edge" : "level"); + trigger == INTR_TRIGGER_EDGE ? "edge" : "level"); return (0); } diff --git a/sys/amd64/amd64/mptable.c b/sys/amd64/amd64/mptable.c index a65ca0f..c422f36 100644 --- a/sys/amd64/amd64/mptable.c +++ b/sys/amd64/amd64/mptable.c @@ -47,10 +47,6 @@ __FBSDID("$FreeBSD$"); #include <dev/pci/pcivar.h> -/* EISA Edge/Level trigger control registers */ -#define ELCR0 0x4d0 /* eisa irq 0-7 */ -#define ELCR1 0x4d1 /* eisa irq 8-15 */ - /* string defined by the Intel MP Spec as identifying the MP table */ #define MP_SIG 0x5f504d5f /* _MP_ */ @@ -147,10 +143,11 @@ static int pci0 = -1; MALLOC_DEFINE(M_MPTABLE, "MP Table", "MP Table Items"); -static u_char conforming_polarity(u_char src_bus); -static u_char conforming_trigger(u_char src_bus, u_char src_bus_irq); -static u_char intentry_polarity(int_entry_ptr intr); -static u_char intentry_trigger(int_entry_ptr intr); +static enum intr_polarity conforming_polarity(u_char src_bus, + u_char src_bus_irq); +static enum intr_trigger conforming_trigger(u_char src_bus, u_char src_bus_irq); +static enum intr_polarity intentry_polarity(int_entry_ptr intr); +static enum intr_trigger intentry_trigger(int_entry_ptr intr); static int lookup_bus_type(char *name); static void mptable_count_items(void); static void mptable_count_items_handler(u_char *entry, void *arg); @@ -340,6 +337,7 @@ mptable_setup_io(void) busses[i].bus_type = NOBUS; /* Second, we run through adding I/O APIC's and busses. */ + ioapic_enable_mixed_mode(); mptable_parse_apics_and_busses(); /* Third, we run through the table tweaking interrupt sources. */ @@ -539,19 +537,22 @@ mptable_parse_apics_and_busses(void) /* * Determine conforming polarity for a given bus type. */ -static u_char -conforming_polarity(u_char src_bus) +static enum intr_polarity +conforming_polarity(u_char src_bus, u_char src_bus_irq) { KASSERT(src_bus <= mptable_maxbusid, ("bus id %d too large", src_bus)); switch (busses[src_bus].bus_type) { case ISA: - case EISA: - /* Active Hi */ - return (1); + return (INTR_POLARITY_HIGH); case PCI: - /* Active Lo */ - return (0); + return (INTR_POLARITY_LOW); + case EISA: + KASSERT(src_bus_irq < 16, ("Invalid EISA IRQ %d", src_bus_irq)); + if (elcr_read_trigger(src_bus_irq) == INTR_TRIGGER_LEVEL) + return (INTR_POLARITY_LOW); + else + return (INTR_POLARITY_HIGH); default: panic("%s: unknown bus type %d", __func__, busses[src_bus].bus_type); @@ -561,52 +562,43 @@ conforming_polarity(u_char src_bus) /* * Determine conforming trigger for a given bus type. */ -static u_char +static enum intr_trigger conforming_trigger(u_char src_bus, u_char src_bus_irq) { - static int eisa_int_control = -1; KASSERT(src_bus <= mptable_maxbusid, ("bus id %d too large", src_bus)); switch (busses[src_bus].bus_type) { case ISA: - /* Edge Triggered */ - return (1); + return (INTR_TRIGGER_EDGE); case PCI: - /* Level Triggered */ - return (0); + return (INTR_TRIGGER_LEVEL); case EISA: KASSERT(src_bus_irq < 16, ("Invalid EISA IRQ %d", src_bus_irq)); - if (eisa_int_control == -1) - eisa_int_control = inb(ELCR1) << 8 | inb(ELCR0); - if (eisa_int_control & (1 << src_bus_irq)) - /* Level Triggered */ - return (0); - else - /* Edge Triggered */ - return (1); + return (elcr_read_trigger(src_bus_irq)); default: panic("%s: unknown bus type %d", __func__, busses[src_bus].bus_type); } } -static u_char +static enum intr_polarity intentry_polarity(int_entry_ptr intr) { switch (intr->int_flags & INTENTRY_FLAGS_POLARITY) { case INTENTRY_FLAGS_POLARITY_CONFORM: - return (conforming_polarity(intr->src_bus_id)); + return (conforming_polarity(intr->src_bus_id, + intr->src_bus_irq)); case INTENTRY_FLAGS_POLARITY_ACTIVEHI: - return (1); + return (INTR_POLARITY_HIGH); case INTENTRY_FLAGS_POLARITY_ACTIVELO: - return (0); + return (INTR_POLARITY_LOW); default: panic("Bogus interrupt flags"); } } -static u_char +static enum intr_trigger intentry_trigger(int_entry_ptr intr) { @@ -615,9 +607,9 @@ intentry_trigger(int_entry_ptr intr) return (conforming_trigger(intr->src_bus_id, intr->src_bus_irq)); case INTENTRY_FLAGS_TRIGGER_EDGE: - return (1); + return (INTR_TRIGGER_EDGE); case INTENTRY_FLAGS_TRIGGER_LEVEL: - return (0); + return (INTR_TRIGGER_LEVEL); default: panic("Bogus interrupt flags"); } diff --git a/sys/amd64/amd64/mptable_pci.c b/sys/amd64/amd64/mptable_pci.c index 5aa0b69..660ced6 100644 --- a/sys/amd64/amd64/mptable_pci.c +++ b/sys/amd64/amd64/mptable_pci.c @@ -64,10 +64,18 @@ mptable_hostb_probe(device_t dev) return (0); } +static int +mptable_hostb_attach(device_t dev) +{ + + device_add_child(dev, "pci", pcib_get_bus(dev)); + return (bus_generic_attach(dev)); +} + static device_method_t mptable_hostb_methods[] = { /* Device interface */ DEVMETHOD(device_probe, mptable_hostb_probe), - DEVMETHOD(device_attach, legacy_pcib_attach), + DEVMETHOD(device_attach, mptable_hostb_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), diff --git a/sys/amd64/amd64/nexus.c b/sys/amd64/amd64/nexus.c index b6762f2..1ac0c67 100644 --- a/sys/amd64/amd64/nexus.c +++ b/sys/amd64/amd64/nexus.c @@ -84,6 +84,8 @@ static device_t nexus_add_child(device_t bus, int order, const char *name, int unit); static struct resource *nexus_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); +static int nexus_config_intr(device_t, int, enum intr_trigger, + enum intr_polarity); static int nexus_activate_resource(device_t, device_t, int, int, struct resource *); static int nexus_deactivate_resource(device_t, device_t, int, int, @@ -116,6 +118,7 @@ static device_method_t nexus_methods[] = { DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource), DEVMETHOD(bus_setup_intr, nexus_setup_intr), DEVMETHOD(bus_teardown_intr, nexus_teardown_intr), + DEVMETHOD(bus_config_intr, nexus_config_intr), DEVMETHOD(bus_set_resource, nexus_set_resource), DEVMETHOD(bus_get_resource, nexus_get_resource), DEVMETHOD(bus_delete_resource, nexus_delete_resource), @@ -453,6 +456,13 @@ nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih) } static int +nexus_config_intr(device_t dev, int irq, enum intr_trigger trig, + enum intr_polarity pol) +{ + return (intr_config_intr(irq, trig, pol)); +} + +static int nexus_set_resource(device_t dev, device_t child, int type, int rid, u_long start, u_long count) { struct nexus_device *ndev = DEVTONX(child); diff --git a/sys/amd64/include/apicvar.h b/sys/amd64/include/apicvar.h index 4dea040..f467bc7 100644 --- a/sys/amd64/include/apicvar.h +++ b/sys/amd64/include/apicvar.h @@ -138,14 +138,16 @@ u_int apic_idt_to_irq(u_int vector); void apic_register_enumerator(struct apic_enumerator *enumerator); void *ioapic_create(uintptr_t addr, int32_t id, int intbase); int ioapic_disable_pin(void *cookie, u_int pin); +void ioapic_enable_mixed_mode(void); 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_extint(void *cookie, u_int pin); int ioapic_set_nmi(void *cookie, u_int pin); -int ioapic_set_polarity(void *cookie, u_int pin, char activehi); -int ioapic_set_triggermode(void *cookie, u_int pin, char edgetrigger); +int ioapic_set_polarity(void *cookie, u_int pin, enum intr_polarity pol); +int ioapic_set_triggermode(void *cookie, u_int pin, + enum intr_trigger trigger); int ioapic_set_smi(void *cookie, u_int pin); void lapic_create(u_int apic_id, int boot_cpu); void lapic_disable(void); @@ -162,8 +164,10 @@ void lapic_handle_intr(void *cookie, struct intrframe frame); void lapic_set_logical_id(u_int apic_id, u_int cluster, u_int cluster_id); int lapic_set_lvt_mask(u_int apic_id, u_int lvt, u_char masked); int lapic_set_lvt_mode(u_int apic_id, u_int lvt, u_int32_t mode); -int lapic_set_lvt_polarity(u_int apic_id, u_int lvt, u_char activehi); -int lapic_set_lvt_triggermode(u_int apic_id, u_int lvt, u_char edgetrigger); +int lapic_set_lvt_polarity(u_int apic_id, u_int lvt, + enum intr_polarity pol); +int lapic_set_lvt_triggermode(u_int apic_id, u_int lvt, + enum intr_trigger trigger); void lapic_setup(void); #endif /* !LOCORE */ diff --git a/sys/amd64/include/intr_machdep.h b/sys/amd64/include/intr_machdep.h index 0aacd91..d8256c9 100644 --- a/sys/amd64/include/intr_machdep.h +++ b/sys/amd64/include/intr_machdep.h @@ -57,6 +57,8 @@ struct pic { int (*pic_source_pending)(struct intsrc *); void (*pic_suspend)(struct intsrc *); void (*pic_resume)(struct intsrc *); + int (*pic_config_intr)(struct intsrc *, enum intr_trigger, + enum intr_polarity); }; /* @@ -77,8 +79,15 @@ struct intrframe; extern struct mtx icu_lock; +/* XXX: The elcr_* prototypes probably belong somewhere else. */ +int elcr_probe(void); +enum intr_trigger elcr_read_trigger(u_int irq); +void elcr_resume(void); +void elcr_write_trigger(u_int irq, enum intr_trigger trigger); int intr_add_handler(const char *name, int vector, driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep); +int intr_config_intr(int vector, enum intr_trigger trig, + enum intr_polarity pol); void intr_execute_handlers(struct intsrc *isrc, struct intrframe *iframe); struct intsrc *intr_lookup_source(int vector); int intr_register_source(struct intsrc *isrc); diff --git a/sys/amd64/include/legacyvar.h b/sys/amd64/include/legacyvar.h index 2fcb142..a3d28420 100644 --- a/sys/amd64/include/legacyvar.h +++ b/sys/amd64/include/legacyvar.h @@ -40,7 +40,6 @@ LEGACY_ACCESSOR(pcibus, PCIBUS, u_int32_t) #undef LEGACY_ACCESSOR -int legacy_pcib_attach(device_t dev); int legacy_pcib_maxslots(device_t dev); u_int32_t legacy_pcib_read_config(device_t dev, int bus, int slot, int func, int reg, int bytes); diff --git a/sys/amd64/include/pmap.h b/sys/amd64/include/pmap.h index 4463db3..0974f48 100644 --- a/sys/amd64/include/pmap.h +++ b/sys/amd64/include/pmap.h @@ -257,7 +257,6 @@ extern struct ppro_vmtrr PPro_vmtrr[NPPROVMTRR]; extern caddr_t CADDR1; extern pt_entry_t *CMAP1; extern vm_paddr_t avail_end; -extern vm_paddr_t avail_start; extern vm_paddr_t phys_avail[]; extern vm_offset_t virtual_avail; extern vm_offset_t virtual_end; diff --git a/sys/amd64/isa/atpic.c b/sys/amd64/isa/atpic.c index 6d726eb..98276b7 100644 --- a/sys/amd64/isa/atpic.c +++ b/sys/amd64/isa/atpic.c @@ -63,6 +63,16 @@ __FBSDID("$FreeBSD$"); #define SLAVE 1 /* + * PC-98 machines wire the slave 8259A to pin 7 on the master PIC, and + * PC-AT machines wire the slave PIC to pin 2 on the master PIC. + */ +#ifdef PC98 +#define ICU_SLAVEID 7 +#else +#define ICU_SLAVEID 2 +#endif + +/* * Determine the base master and slave modes not including auto EOI support. * All machines that FreeBSD supports use 8086 mode. */ @@ -81,9 +91,15 @@ __FBSDID("$FreeBSD$"); #define SLAVE_MODE BASE_SLAVE_MODE #endif +#define IRQ_MASK(irq) (1 << (irq)) +#define IMEN_MASK(ai) (IRQ_MASK((ai)->at_irq)) + +#define NUM_ISA_IRQS 16 + static void atpic_init(void *dummy); unsigned int imen; /* XXX */ +static int using_elcr; inthand_t IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2), @@ -95,14 +111,15 @@ inthand_t #define IRQ(ap, ai) ((ap)->at_irqbase + (ai)->at_irq) -#define ATPIC(io, base, eoi, imenptr) \ +#define ATPIC(io, base, eoi, imenptr) \ { { atpic_enable_source, atpic_disable_source, (eoi), \ atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \ - atpic_resume }, (io), (base), IDT_IO_INTS + (base), (imenptr) } + atpic_resume, atpic_config_intr }, (io), (base), \ + IDT_IO_INTS + (base), (imenptr) } #define INTSRC(irq) \ - { { &atpics[(irq) / 8].at_pic }, (irq) % 8, \ - IDTVEC(atpic_intr ## irq ) } + { { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \ + (irq) % 8 } struct atpic { struct pic at_pic; @@ -114,8 +131,9 @@ struct atpic { struct atpic_intsrc { struct intsrc at_intsrc; - int at_irq; /* Relative to PIC base. */ inthand_t *at_intr; + int at_irq; /* Relative to PIC base. */ + enum intr_trigger at_trigger; u_long at_count; u_long at_straycount; }; @@ -128,6 +146,8 @@ static void atpic_enable_intr(struct intsrc *isrc); static int atpic_vector(struct intsrc *isrc); static void atpic_resume(struct intsrc *isrc); static int atpic_source_pending(struct intsrc *isrc); +static int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, + enum intr_polarity pol); static void i8259_init(struct atpic *pic, int slave); static struct atpic atpics[] = { @@ -154,6 +174,8 @@ static struct atpic_intsrc atintrs[] = { INTSRC(15), }; +CTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS); + static void atpic_enable_source(struct intsrc *isrc) { @@ -161,8 +183,10 @@ atpic_enable_source(struct intsrc *isrc) struct atpic *ap = (struct atpic *)isrc->is_pic; mtx_lock_spin(&icu_lock); - *ap->at_imen &= ~(1 << ai->at_irq); - outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); + if (*ap->at_imen & IMEN_MASK(ai)) { + *ap->at_imen &= ~IMEN_MASK(ai); + outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); + } mtx_unlock_spin(&icu_lock); } @@ -172,8 +196,10 @@ atpic_disable_source(struct intsrc *isrc) struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; struct atpic *ap = (struct atpic *)isrc->is_pic; + if (ai->at_trigger == INTR_TRIGGER_EDGE) + return; mtx_lock_spin(&icu_lock); - *ap->at_imen |= (1 << ai->at_irq); + *ap->at_imen |= IMEN_MASK(ai); outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); mtx_unlock_spin(&icu_lock); } @@ -186,7 +212,7 @@ atpic_eoi_master(struct intsrc *isrc) ("%s: mismatched pic", __func__)); #ifndef AUTO_EOI_1 mtx_lock_spin(&icu_lock); - outb(atpics[MASTER].at_ioaddr, ICU_EOI); + outb(atpics[MASTER].at_ioaddr, OCW2_EOI); mtx_unlock_spin(&icu_lock); #endif } @@ -203,9 +229,9 @@ atpic_eoi_slave(struct intsrc *isrc) ("%s: mismatched pic", __func__)); #ifndef AUTO_EOI_2 mtx_lock_spin(&icu_lock); - outb(atpics[SLAVE].at_ioaddr, ICU_EOI); + outb(atpics[SLAVE].at_ioaddr, OCW2_EOI); #ifndef AUTO_EOI_1 - outb(atpics[MASTER].at_ioaddr, ICU_EOI); + outb(atpics[MASTER].at_ioaddr, OCW2_EOI); #endif mtx_unlock_spin(&icu_lock); #endif @@ -231,7 +257,7 @@ atpic_source_pending(struct intsrc *isrc) struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; struct atpic *ap = (struct atpic *)isrc->is_pic; - return (inb(ap->at_ioaddr) & (1 << ai->at_irq)); + return (inb(ap->at_ioaddr) & IMEN_MASK(ai)); } static void @@ -240,8 +266,67 @@ atpic_resume(struct intsrc *isrc) struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; struct atpic *ap = (struct atpic *)isrc->is_pic; - if (ai->at_irq == 0) + if (ai->at_irq == 0) { i8259_init(ap, ap == &atpics[SLAVE]); + if (ap == &atpics[SLAVE] && using_elcr) + elcr_resume(); + } +} + +static int +atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, + enum intr_polarity pol) +{ + struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; + u_int vector; + + /* Map conforming values to edge/hi and sanity check the values. */ + if (trig == INTR_TRIGGER_CONFORM) + trig = INTR_TRIGGER_EDGE; + if (pol == INTR_POLARITY_CONFORM) + pol = INTR_POLARITY_HIGH; + vector = atpic_vector(isrc); + if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) || + (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) { + printf( + "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n", + vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level", + pol == INTR_POLARITY_HIGH ? "high" : "low"); + return (EINVAL); + } + + /* If there is no change, just return. */ + if (ai->at_trigger == trig) + return (0); + + /* + * Certain IRQs can never be level/lo, so don't try to set them + * that way if asked. At least some ELCR registers ignore setting + * these bits as well. + */ + if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) && + trig == INTR_TRIGGER_LEVEL) { + if (bootverbose) + printf( + "atpic: Ignoring invalid level/low configuration for IRQ%u\n", + vector); + return (EINVAL); + } + if (!using_elcr) { + if (bootverbose) + printf("atpic: No ELCR to configure IRQ%u as %s\n", + vector, trig == INTR_TRIGGER_EDGE ? "edge/high" : + "level/low"); + return (ENXIO); + } + if (bootverbose) + printf("atpic: Programming IRQ%u as %s\n", vector, + trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low"); + mtx_lock_spin(&icu_lock); + elcr_write_trigger(atpic_vector(isrc), trig); + ai->at_trigger = trig; + mtx_unlock_spin(&icu_lock); + return (0); } static void @@ -263,9 +348,9 @@ i8259_init(struct atpic *pic, int slave) * which line on the master we are connected to. */ if (slave) - outb(imr_addr, ICU_SLAVEID); /* my slave id is 7 */ + outb(imr_addr, ICU_SLAVEID); else - outb(imr_addr, IRQ_SLAVE); /* slave on line 7 */ + outb(imr_addr, IRQ_MASK(ICU_SLAVEID)); /* Set mode. */ if (slave) @@ -298,27 +383,58 @@ atpic_startup(void) atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]); /* Install low-level interrupt handlers for all of our IRQs. */ - for (i = 0; i < sizeof(atintrs) / sizeof(struct atpic_intsrc); i++) { + for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { if (i == ICU_SLAVEID) continue; - ai = &atintrs[i]; ai->at_intsrc.is_count = &ai->at_count; ai->at_intsrc.is_straycount = &ai->at_straycount; setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase + ai->at_irq, ai->at_intr, SDT_SYSIGT, SEL_KPL, 0); } + + /* + * Look for an ELCR. If we find one, update the trigger modes. + * If we don't find one, assume that IRQs 0, 1, 2, and 13 are + * edge triggered and that everything else is level triggered. + * We only use the trigger information to reprogram the ELCR if + * we have one and as an optimization to avoid masking edge + * triggered interrupts. For the case that we don't have an ELCR, + * it doesn't hurt to mask an edge triggered interrupt, so we + * assume level trigger for any interrupt that we aren't sure is + * edge triggered. + */ + if (elcr_probe() == 0) { + using_elcr = 1; + for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) + ai->at_trigger = elcr_read_trigger(i); + } else { + for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) + switch (i) { + case 0: + case 1: + case 2: + case 8: + case 13: + ai->at_trigger = INTR_TRIGGER_EDGE; + break; + default: + ai->at_trigger = INTR_TRIGGER_LEVEL; + break; + } + } } static void atpic_init(void *dummy __unused) { + struct atpic_intsrc *ai; int i; /* Loop through all interrupt sources and add them. */ - for (i = 0; i < sizeof(atintrs) / sizeof(struct atpic_intsrc); i++) { + for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { if (i == ICU_SLAVEID) continue; - intr_register_source(&atintrs[i].at_intsrc); + intr_register_source(&ai->at_intsrc); } } SYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL) @@ -329,7 +445,7 @@ atpic_handle_intr(void *cookie, struct intrframe iframe) struct intsrc *isrc; int vec = (uintptr_t)cookie; - KASSERT(vec < ICU_LEN, ("unknown int %d\n", vec)); + KASSERT(vec < NUM_ISA_IRQS, ("unknown int %d\n", vec)); isrc = &atintrs[vec].at_intsrc; /* @@ -349,7 +465,7 @@ atpic_handle_intr(void *cookie, struct intrframe iframe) isr = inb(port); outb(port, OCW3_SEL | OCW3_RR); mtx_unlock_spin(&icu_lock); - if ((isr & IRQ7) == 0) + if ((isr & IRQ_MASK(7)) == 0) return; } intr_execute_handlers(isrc, &iframe); diff --git a/sys/amd64/isa/atpic_vector.S b/sys/amd64/isa/atpic_vector.S index a8e0d83..72f3bed 100644 --- a/sys/amd64/isa/atpic_vector.S +++ b/sys/amd64/isa/atpic_vector.S @@ -37,8 +37,6 @@ */ #include <machine/asmacros.h> -#include <amd64/isa/icu.h> -#include <amd64/isa/isa.h> #include "assym.s" diff --git a/sys/amd64/isa/clock.c b/sys/amd64/isa/clock.c index 47ae6da..fca9127 100644 --- a/sys/amd64/isa/clock.c +++ b/sys/amd64/isa/clock.c @@ -73,7 +73,6 @@ __FBSDID("$FreeBSD$"); #endif #include <machine/specialreg.h> -#include <amd64/isa/icu.h> #include <amd64/isa/isa.h> #include <isa/rtc.h> #ifdef DEV_ISA @@ -107,10 +106,11 @@ struct mtx clock_lock; static int beeping = 0; static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31}; static u_int hardclock_max_count; +static struct intsrc *i8254_intsrc; static u_int32_t i8254_lastcount; static u_int32_t i8254_offset; +static int (*i8254_pending)(struct intsrc *); static int i8254_ticked; -static struct intsrc *i8254_intsrc; static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; static u_char rtc_statusb = RTCSB_24HR | RTCSB_PINTR; @@ -741,6 +741,9 @@ cpu_initclocks() /* Finish initializing 8254 timer 0. */ intr_add_handler("clk", 0, (driver_intr_t *)clkintr, NULL, INTR_TYPE_CLK | INTR_FAST, NULL); + i8254_intsrc = intr_lookup_source(0); + if (i8254_intsrc != NULL) + i8254_pending = i8254_intsrc->is_pic->pic_source_pending; /* Initialize RTC. */ writertc(RTC_STATUSA, rtc_statusa); @@ -754,7 +757,6 @@ cpu_initclocks() intr_add_handler("rtc", 8, (driver_intr_t *)rtcintr, NULL, INTR_TYPE_CLK | INTR_FAST, NULL); - i8254_intsrc = intr_lookup_source(8); writertc(RTC_STATUSB, rtc_statusb); } @@ -821,8 +823,7 @@ i8254_get_timecount(struct timecounter *tc) if (count < i8254_lastcount || (!i8254_ticked && (clkintr_pending || ((count < 20 || (!(rflags & PSL_I) && count < timer0_max_count / 2u)) && - i8254_intsrc != NULL && - i8254_intsrc->is_pic->pic_source_pending(i8254_intsrc))))) { + i8254_intsrc != NULL && i8254_pending(i8254_intsrc))))) { i8254_ticked = 1; i8254_offset += timer0_max_count; } diff --git a/sys/amd64/isa/icu.h b/sys/amd64/isa/icu.h index 17d6931..f25fac6 100644 --- a/sys/amd64/isa/icu.h +++ b/sys/amd64/isa/icu.h @@ -41,39 +41,9 @@ #ifndef _AMD64_ISA_ICU_H_ #define _AMD64_ISA_ICU_H_ -/* - * Interrupt enable bits - in normal order of priority (which we change) - */ -#define IRQ0 0x0001 /* highest priority - timer */ -#define IRQ1 0x0002 -#define IRQ_SLAVE 0x0004 -#define IRQ8 0x0100 -#define IRQ9 0x0200 -#define IRQ2 IRQ9 -#define IRQ10 0x0400 -#define IRQ11 0x0800 -#define IRQ12 0x1000 -#define IRQ13 0x2000 -#define IRQ14 0x4000 -#define IRQ15 0x8000 -#define IRQ3 0x0008 /* this is highest after rotation */ -#define IRQ4 0x0010 -#define IRQ5 0x0020 -#define IRQ6 0x0040 -#define IRQ7 0x0080 /* lowest - parallel printer */ - -/* - * Interrupt Control offset into Interrupt descriptor table (IDT) - */ -#define ICU_OFFSET 32 /* 0-31 are processor exceptions */ -#define ICU_LEN 16 /* 32-47 are ISA interrupts */ #define ICU_IMR_OFFSET 1 -#define ICU_SLAVEID 2 -#define ICU_EOI (OCW2_EOI) /* non-specific EOI */ -#ifndef LOCORE void atpic_handle_intr(void *cookie, struct intrframe iframe); void atpic_startup(void); -#endif #endif /* !_AMD64_ISA_ICU_H_ */ diff --git a/sys/amd64/isa/nmi.c b/sys/amd64/isa/nmi.c index db5550c..887879a 100644 --- a/sys/amd64/isa/nmi.c +++ b/sys/amd64/isa/nmi.c @@ -43,10 +43,6 @@ __FBSDID("$FreeBSD$"); #include <machine/md_var.h> -#ifdef DEV_MCA -#include <i386/bios/mca_machdep.h> -#endif - #define NMI_PARITY (1 << 7) #define NMI_IOCHAN (1 << 6) #define ENMI_WATCHDOG (1 << 7) @@ -65,10 +61,6 @@ isa_nmi(int cd) int eisa_port = inb(0x461); log(LOG_CRIT, "NMI ISA %x, EISA %x\n", isa_port, eisa_port); -#ifdef DEV_MCA - if (MCA_system && mca_bus_nmi()) - return(0); -#endif if (isa_port & NMI_PARITY) { log(LOG_CRIT, "RAM parity error, likely hardware failure."); diff --git a/sys/amd64/pci/pci_bus.c b/sys/amd64/pci/pci_bus.c index 0feff0f..4ee9c68 100644 --- a/sys/amd64/pci/pci_bus.c +++ b/sys/amd64/pci/pci_bus.c @@ -225,7 +225,7 @@ legacy_pcib_probe(device_t dev) return -100; } -int +static int legacy_pcib_attach(device_t dev) { int bus; diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 index b24d28c..a2f0c2e 100644 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -81,6 +81,7 @@ amd64/amd64/vm_machdep.c standard amd64/isa/atpic.c optional atpic isa amd64/isa/atpic_vector.S optional atpic isa amd64/isa/clock.c standard +amd64/isa/elcr.c standard amd64/isa/isa.c standard amd64/isa/isa_dma.c standard amd64/isa/nmi.c standard |