- Add a new pic method pic_config_intr() to set the trigger mode and
polarity for a specified IRQ. The intr_config_intr() function wraps this pic method hiding the IRQ to interrupt source lookup. - Add a config_intr() method to the atpic(4) driver that reconfigures the interrupt using the ELCR if possible and returns an error otherwise. - Add a config_intr() method to the apic(4) driver that just logs any requests that would change the existing programming under bootverbose. Currently, the only changes the apic(4) driver receives are due to bugs in the acpi(4) driver and its handling of link devices, hence the reason for such requests currently being ignored. - Have the nexus(4) driver on i386 implement the bus_config_intr() function by calling intr_config_intr().
This commit is contained in:
parent
e077495344
commit
415131cd6d
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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),
|
||||
@ -490,6 +493,13 @@ nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih)
|
||||
return (intr_remove_handler(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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user