i386/ioapic: Allow GSI's target CPU to be configured
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 11 Dec 2011 11:02:25 +0000 (19:02 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 11 Dec 2011 11:02:25 +0000 (19:02 +0800)
This merges 95874ffdec65823430464b7869d8f0acf75cc226

sys/platform/pc32/acpica5/acpi_fadt.c
sys/platform/pc32/apic/ioapic.c
sys/platform/pc32/apic/ioapic.h
sys/platform/pc32/apic/ioapic_abi.c

index d49013e..6822bea 100644 (file)
@@ -252,3 +252,9 @@ acpi_sci_pci_shariable(void)
        else
                return 0;
 }
+
+int
+acpi_sci_irqno(void)
+{
+       return acpi_sci_irq;
+}
index 1fd3461..ef62cc2 100644 (file)
@@ -73,7 +73,7 @@ static void   ioapic_gsi_setup(int);
 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;
 
@@ -379,7 +379,7 @@ ioapic_gsi_setup(int gsi)
                                 */
                                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;
@@ -444,7 +444,7 @@ void
 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
@@ -455,7 +455,7 @@ ioapic_extpin_gsi(void)
 
 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
@@ -470,13 +470,14 @@ ioapic_pin_setup(void *addr, int pin, int vec,
         * 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;
@@ -532,7 +533,7 @@ ioapic_pin_prog(void *addr, int pin, int vec,
        }
 
        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);
index d8b7dcb..c048abd 100644 (file)
@@ -56,7 +56,7 @@ void  ioapic_intsrc(int, int, enum intr_trigger, enum intr_polarity);
 void   *ioapic_gsi_ioaddr(int);
 int    ioapic_gsi_pin(int);
 void   ioapic_pin_setup(void *, int, int,
-           enum intr_trigger, enum intr_polarity);
+           enum intr_trigger, enum intr_polarity, int);
 void   ioapic_extpin_setup(void *, int, int);
 int    ioapic_extpin_gsi(void);
 int    ioapic_gsi(int, int);
index f0f66fd..6968353 100644 (file)
@@ -46,6 +46,7 @@
 #include <sys/machintr.h>
 #include <sys/interrupt.h>
 #include <sys/bus.h>
+#include <sys/thread2.h>
 
 #include <machine/smp.h>
 #include <machine/segments.h>
@@ -53,8 +54,6 @@
 #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>
@@ -63,6 +62,8 @@
 #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
@@ -490,6 +491,8 @@ static void ioapic_abi_setdefault(void);
 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,
 
@@ -683,7 +686,7 @@ ioapic_abi_set_irqmap(int irq, int gsi, enum intr_trigger trig,
        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);
@@ -708,6 +711,8 @@ ioapic_abi_set_irqmap(int irq, int gsi, enum intr_trigger trig,
        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();
@@ -719,7 +724,7 @@ ioapic_abi_set_irqmap(int irq, int gsi, enum intr_trigger trig,
                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();
 }
@@ -793,7 +798,7 @@ ioapic_abi_intr_config(int irq, enum intr_trigger trig, enum intr_polarity pola)
        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);
@@ -837,6 +842,8 @@ ioapic_abi_intr_config(int irq, enum intr_trigger trig, enum intr_polarity pola)
        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();
@@ -846,7 +853,7 @@ ioapic_abi_intr_config(int irq, enum intr_trigger trig, enum intr_polarity pola)
                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();
 }
@@ -859,6 +866,9 @@ ioapic_abi_extint_irqmap(int irq)
        void *ioaddr;
        int pin, error, vec;
 
+       /* XXX only irq0 is allowed */
+       KKASSERT(irq == 0);
+
        vec = IDT_OFFSET + irq;
 
        if (ioapic_abi_extint_irq == irq)
@@ -914,8 +924,59 @@ ioapic_abi_extint_irqmap(int 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;
 }