x86_64/ioapic: Allow GSI's target CPU to be configured
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Sat, 29 Oct 2011 13:13:43 +0000 (21:13 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Sat, 29 Oct 2011 14:43:23 +0000 (22:43 +0800)
- Tuneable hw.ioapic.gsi.X.cpu is added, which could be used to specify
  the GSI X's target CPU id
- If hw.ioapic.gsi.X is not set, then GSI X will be target to CPU Y,
  Y = X % ncpus

sys/dev/acpica5/acpi_sci_var.h
sys/platform/pc64/acpica5/acpi_fadt.c
sys/platform/pc64/apic/ioapic.c
sys/platform/pc64/apic/ioapic.h
sys/platform/pc64/apic/ioapic_abi.c

index 71982a8..7d41314 100644 (file)
@@ -4,5 +4,6 @@
 void   acpi_sci_config(void);
 int    acpi_sci_enabled(void);
 int    acpi_sci_pci_shariable(void);
+int    acpi_sci_irqno(void);
 
 #endif /* !_ACPI_SCI_VAR_H_ */
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 e198b0a..c3325d7 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;
 
@@ -376,7 +376,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;
@@ -441,7 +441,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
@@ -452,7 +452,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
@@ -467,13 +467,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;
@@ -529,7 +530,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 25a1d1c..b439c26 100644 (file)
@@ -57,7 +57,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 2798911..282fa7e 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,
        .intr_disable   = ioapic_abi_intr_disable,
@@ -680,7 +683,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);
@@ -705,6 +708,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();
@@ -716,7 +721,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();
 }
@@ -790,7 +795,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);
@@ -834,6 +839,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();
@@ -843,7 +850,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();
 }
@@ -856,6 +863,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)
@@ -911,8 +921,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;
 }