static const struct ioapic_info *
ioapic_gsi_search(int);
static void ioapic_pin_prog(void *, int, int,
- enum intr_trigger, enum intr_polarity, uint32_t);
+ enum intr_trigger, enum intr_polarity, uint32_t, int);
static struct ioapic_conf ioapic_conf;
*/
ioapic_pin_setup(ioapic_gsi_ioaddr(gsi),
ioapic_gsi_pin(gsi), 0,
- INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH);
+ INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH, 0);
return;
}
trig = INTR_TRIGGER_EDGE;
ioapic_extpin_setup(void *addr, int pin, int vec)
{
ioapic_pin_prog(addr, pin, vec,
- INTR_TRIGGER_CONFORM, INTR_POLARITY_CONFORM, IOART_DELEXINT);
+ INTR_TRIGGER_CONFORM, INTR_POLARITY_CONFORM, IOART_DELEXINT, 0);
}
int
void
ioapic_pin_setup(void *addr, int pin, int vec,
- enum intr_trigger trig, enum intr_polarity pola)
+ enum intr_trigger trig, enum intr_polarity pola, int cpuid)
{
/*
* Always clear an I/O APIC pin before [re]programming it. This is
* interrupt.
*/
ioapic_pin_prog(addr, pin, vec, INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH,
- IOART_DELFIXED);
- ioapic_pin_prog(addr, pin, vec, trig, pola, IOART_DELFIXED);
+ IOART_DELFIXED, cpuid);
+ ioapic_pin_prog(addr, pin, vec, trig, pola, IOART_DELFIXED, cpuid);
}
static void
ioapic_pin_prog(void *addr, int pin, int vec,
- enum intr_trigger trig, enum intr_polarity pola, uint32_t del_mode)
+ enum intr_trigger trig, enum intr_polarity pola,
+ uint32_t del_mode, int cpuid)
{
uint32_t flags, target;
int select;
}
target = ioapic_read(addr, select + 1) & IOART_HI_DEST_RESV;
- target |= (CPUID_TO_APICID(0) << IOART_HI_DEST_SHIFT) &
+ target |= (CPUID_TO_APICID(cpuid) << IOART_HI_DEST_SHIFT) &
IOART_HI_DEST_MASK;
ioapic_write(addr, select, flags | vec);
#include <sys/machintr.h>
#include <sys/interrupt.h>
#include <sys/bus.h>
+#include <sys/thread2.h>
#include <machine/smp.h>
#include <machine/segments.h>
#include <machine/intr_machdep.h>
#include <machine/globaldata.h>
-#include <sys/thread2.h>
-
#include <machine_base/isa/isa_intr.h>
#include <machine_base/icu/icu.h>
#include <machine_base/icu/icu_var.h>
#include <machine_base/apic/ioapic_ipl.h>
#include <machine_base/apic/apicreg.h>
+#include <dev/acpica5/acpi_sci_var.h>
+
#define IOAPIC_HWI_VECTORS IDT_HWI_VECTORS
extern inthand_t
static void ioapic_abi_stabilize(void);
static void ioapic_abi_initmap(void);
+static int ioapic_abi_gsi_cpuid(int, int);
+
struct machintr_abi MachIntrABI_IOAPIC = {
MACHINTR_IOAPIC,
struct ioapic_irqinfo *info;
struct ioapic_irqmap *map;
void *ioaddr;
- int pin;
+ int pin, cpuid;
KKASSERT(trig == INTR_TRIGGER_EDGE || trig == INTR_TRIGGER_LEVEL);
KKASSERT(pola == INTR_POLARITY_HIGH || pola == INTR_POLARITY_LOW);
pin = ioapic_gsi_pin(map->im_gsi);
ioaddr = ioapic_gsi_ioaddr(map->im_gsi);
+ cpuid = ioapic_abi_gsi_cpuid(irq, map->im_gsi);
+
info = &ioapic_irqs[irq];
imen_lock();
info->io_flags |= IOAPIC_IRQI_FLAG_LEVEL;
ioapic_pin_setup(ioaddr, pin, IDT_OFFSET + irq,
- map->im_trig, map->im_pola);
+ map->im_trig, map->im_pola, cpuid);
imen_unlock();
}
struct ioapic_irqinfo *info;
struct ioapic_irqmap *map;
void *ioaddr;
- int pin;
+ int pin, cpuid;
KKASSERT(trig == INTR_TRIGGER_EDGE || trig == INTR_TRIGGER_LEVEL);
KKASSERT(pola == INTR_POLARITY_HIGH || pola == INTR_POLARITY_LOW);
pin = ioapic_gsi_pin(map->im_gsi);
ioaddr = ioapic_gsi_ioaddr(map->im_gsi);
+ cpuid = ioapic_abi_gsi_cpuid(irq, map->im_gsi);
+
info = &ioapic_irqs[irq];
imen_lock();
info->io_flags |= IOAPIC_IRQI_FLAG_LEVEL;
ioapic_pin_setup(ioaddr, pin, IDT_OFFSET + irq,
- map->im_trig, map->im_pola);
+ map->im_trig, map->im_pola, cpuid);
imen_unlock();
}
void *ioaddr;
int pin, error, vec;
+ /* XXX only irq0 is allowed */
+ KKASSERT(irq == 0);
+
vec = IDT_OFFSET + irq;
if (ioapic_abi_extint_irq == irq)
}
static int
-ioapic_abi_intr_cpuid(int irq __unused)
+ioapic_abi_intr_cpuid(int irq)
{
- /* TODO */
- return 0;
+ const struct ioapic_irqmap *map;
+
+ KKASSERT(irq >= 0 && irq < IOAPIC_HWI_VECTORS);
+ map = &ioapic_irqmaps[irq];
+
+ if (map->im_type == IOAPIC_IMT_RESERVED) {
+ /* XXX some drivers tries to peek at IRQ 2 */
+ return 0;
+ }
+
+ KASSERT(map->im_type == IOAPIC_IMT_LINE,
+ ("invalid irq %d, type %d\n", irq, map->im_type));
+ KKASSERT(map->im_gsi >= 0);
+
+ return ioapic_abi_gsi_cpuid(irq, map->im_gsi);
+}
+
+static int
+ioapic_abi_gsi_cpuid(int irq, int gsi)
+{
+ char envpath[32];
+ int cpuid = -1;
+
+ KKASSERT(gsi >= 0);
+
+ if (irq == 0 || gsi == 0) {
+ if (bootverbose)
+ kprintf("GSI %d -> CPU 0 (0)\n", gsi);
+ return 0;
+ }
+
+ if (irq == acpi_sci_irqno()) {
+ if (bootverbose)
+ kprintf("GSI %d -> CPU 0 (sci)\n", gsi);
+ return 0;
+ }
+
+ ksnprintf(envpath, sizeof(envpath), "hw.ioapic.gsi.%d.cpu", gsi);
+ kgetenv_int(envpath, &cpuid);
+
+ if (cpuid < 0) {
+ cpuid = gsi % ncpus;
+ if (bootverbose)
+ kprintf("GSI %d -> CPU %d (auto)\n", gsi, cpuid);
+ } else if (cpuid >= ncpus) {
+ cpuid = ncpus - 1;
+ if (bootverbose)
+ kprintf("GSI %d -> CPU %d (fixup)\n", gsi, cpuid);
+ } else {
+ if (bootverbose)
+ kprintf("GSI %d -> CPU %d (user)\n", gsi, cpuid);
+ }
+ return cpuid;
}