diff options
-rw-r--r-- | sys/i386/i386/intr_machdep.c | 11 | ||||
-rw-r--r-- | sys/i386/i386/io_apic.c | 40 | ||||
-rw-r--r-- | sys/i386/i386/nexus.c | 10 | ||||
-rw-r--r-- | sys/i386/include/intr_machdep.h | 4 | ||||
-rw-r--r-- | sys/i386/isa/atpic.c | 61 |
5 files changed, 124 insertions, 2 deletions
diff --git a/sys/i386/i386/intr_machdep.c b/sys/i386/i386/intr_machdep.c index d023a86..f7f51c0 100644 --- a/sys/i386/i386/intr_machdep.c +++ b/sys/i386/i386/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/i386/i386/io_apic.c b/sys/i386/i386/io_apic.c index b3e760e..272ebae 100644 --- a/sys/i386/i386/io_apic.c +++ b/sys/i386/i386/io_apic.c @@ -127,6 +127,8 @@ 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); @@ -137,7 +139,8 @@ static void ioapic_setup_mixed_mode(struct ioapic_intsrc *intpin); 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; @@ -290,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) { diff --git a/sys/i386/i386/nexus.c b/sys/i386/i386/nexus.c index ecfd035..818da86 100644 --- a/sys/i386/i386/nexus.c +++ b/sys/i386/i386/nexus.c @@ -88,6 +88,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, @@ -120,6 +122,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), @@ -491,6 +494,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/i386/include/intr_machdep.h b/sys/i386/include/intr_machdep.h index 6794751..d8256c9 100644 --- a/sys/i386/include/intr_machdep.h +++ b/sys/i386/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); }; /* @@ -84,6 +86,8 @@ 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/i386/isa/atpic.c b/sys/i386/isa/atpic.c index 470783a..7567c91 100644 --- a/sys/i386/isa/atpic.c +++ b/sys/i386/isa/atpic.c @@ -115,7 +115,8 @@ inthand_t #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 }, IDTVEC(atpic_intr ## irq ), \ @@ -146,6 +147,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[] = { @@ -271,6 +274,62 @@ atpic_resume(struct intsrc *isrc) } } +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 i8259_init(struct atpic *pic, int slave) { |