summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/i386/i386/intr_machdep.c11
-rw-r--r--sys/i386/i386/io_apic.c40
-rw-r--r--sys/i386/i386/nexus.c10
-rw-r--r--sys/i386/include/intr_machdep.h4
-rw-r--r--sys/i386/isa/atpic.c61
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)
{
OpenPOWER on IntegriCloud