pci: Utilize device_getenv_int
[dragonfly.git] / sys / bus / pci / pci.c
index 26f39eb..f752fa1 100644 (file)
@@ -28,7 +28,6 @@
  * $FreeBSD: src/sys/dev/pci/pci.c,v 1.355.2.9.2.1 2009/04/15 03:14:26 kensmith Exp $
  */
 
-#include "opt_bus.h"
 #include "opt_acpi.h"
 #include "opt_compat_oldpci.h"
 
@@ -113,6 +112,7 @@ static void         pci_setup_msix_vector(device_t dev, u_int index,
 static void            pci_mask_msix_vector(device_t dev, u_int index);
 static void            pci_unmask_msix_vector(device_t dev, u_int index);
 static void            pci_mask_msix_allvectors(device_t dev);
+static struct msix_vector *pci_find_msix_vector(device_t dev, int rid);
 static int             pci_msi_blacklisted(void);
 static void            pci_resume_msi(device_t dev);
 static void            pci_resume_msix(device_t dev);
@@ -173,8 +173,9 @@ static device_method_t pci_methods[] = {
        DEVMETHOD(pci_assign_interrupt, pci_assign_interrupt_method),
        DEVMETHOD(pci_find_extcap,      pci_find_extcap_method),
        DEVMETHOD(pci_alloc_msi,        pci_alloc_msi_method),
-       DEVMETHOD(pci_alloc_msix,       pci_alloc_msix_method),
        DEVMETHOD(pci_release_msi,      pci_release_msi_method),
+       DEVMETHOD(pci_alloc_msix_vector, pci_alloc_msix_vector_method),
+       DEVMETHOD(pci_release_msix_vector, pci_release_msix_vector_method),
        DEVMETHOD(pci_msi_count,        pci_msi_count_method),
        DEVMETHOD(pci_msix_count,       pci_msix_count_method),
 
@@ -255,6 +256,9 @@ struct pci_quirk pci_quirks[] = {
 #define        PCI_MAPMEMP     0x02    /* prefetchable memory map */
 #define        PCI_MAPPORT     0x04    /* port map */
 
+#define PCI_MSIX_RID2VEC(rid)  ((rid) - 1)     /* rid -> MSI-X vector # */
+#define PCI_MSIX_VEC2RID(vec)  ((vec) + 1)     /* MSI-X vector # -> rid */
+
 struct devlist pci_devq;
 uint32_t pci_generation;
 uint32_t pci_numdevs = 0;
@@ -291,12 +295,10 @@ TUNABLE_INT("hw.pci.enable_msi", &pci_do_msi);
 SYSCTL_INT(_hw_pci, OID_AUTO, enable_msi, CTLFLAG_RW, &pci_do_msi, 1,
     "Enable support for MSI interrupts");
 
-static int pci_do_msix = 0;
-#if 0
+static int pci_do_msix = 1;
 TUNABLE_INT("hw.pci.enable_msix", &pci_do_msix);
 SYSCTL_INT(_hw_pci, OID_AUTO, enable_msix, CTLFLAG_RW, &pci_do_msix, 1,
     "Enable support for MSI-X interrupts");
-#endif
 
 static int pci_honor_msi_blacklist = 1;
 TUNABLE_INT("hw.pci.honor_msi_blacklist", &pci_honor_msi_blacklist);
@@ -681,6 +683,8 @@ pci_read_cap_msix(device_t pcib, int ptr, int nextptr, pcicfgregs *cfg)
        msix->msix_pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK);
        msix->msix_pba_offset = val & ~PCIM_MSIX_BIR_MASK;
 
+       TAILQ_INIT(&msix->msix_vectors);
+
 #undef REG
 }
 
@@ -1372,7 +1376,7 @@ pci_setup_msix_vector(device_t dev, u_int index, uint64_t address,
        struct pcicfg_msix *msix = &dinfo->cfg.msix;
        uint32_t offset;
 
-       KASSERT(msix->msix_table_len > index, ("bogus index"));
+       KASSERT(msix->msix_msgnum > index, ("bogus index"));
        offset = msix->msix_table_offset + index * 16;
        bus_write_4(msix->msix_table_res, offset, address & 0xffffffff);
        bus_write_4(msix->msix_table_res, offset + 4, address >> 32);
@@ -1405,7 +1409,7 @@ pci_unmask_msix_vector(device_t dev, u_int index)
        struct pcicfg_msix *msix = &dinfo->cfg.msix;
        uint32_t offset, val;
 
-       KASSERT(msix->msix_table_len > index, ("bogus index"));
+       KASSERT(msix->msix_msgnum > index, ("bogus index"));
        offset = msix->msix_table_offset + index * 16 + 12;
        val = bus_read_4(msix->msix_table_res, offset);
        if (val & PCIM_MSIX_VCTRL_MASK) {
@@ -1424,7 +1428,7 @@ pci_pending_msix_vector(device_t dev, u_int index)
        KASSERT(msix->msix_table_res != NULL && msix->msix_pba_res != NULL,
            ("MSI-X is not setup yet\n"));
 
-       KASSERT(msix->msix_table_len > index, ("bogus index"));
+       KASSERT(msix->msix_msgnum > index, ("bogus index"));
        offset = msix->msix_pba_offset + (index / 32) * 4;
        bit = 1 << index % 32;
        return (bus_read_4(msix->msix_pba_res, offset) & bit);
@@ -1440,22 +1444,22 @@ pci_resume_msix(device_t dev)
 {
        struct pci_devinfo *dinfo = device_get_ivars(dev);
        struct pcicfg_msix *msix = &dinfo->cfg.msix;
-       struct msix_table_entry *mte;
-       struct msix_vector *mv;
-       int i;
 
-       if (msix->msix_alloc > 0) {
+       if (msix->msix_table_res != NULL) {
+               const struct msix_vector *mv;
+
                pci_mask_msix_allvectors(dev);
 
-               /* Program any messages with at least one handler. */
-               for (i = 0; i < msix->msix_table_len; i++) {
-                       mte = &msix->msix_table[i];
-                       if (mte->mte_vector == 0 || mte->mte_handlers == 0)
+               TAILQ_FOREACH(mv, &msix->msix_vectors, mv_link) {
+                       u_int vector;
+
+                       if (mv->mv_address == 0)
                                continue;
-                       mv = &msix->msix_vectors[mte->mte_vector - 1];
-                       pci_setup_msix_vector(dev, i, mv->mv_address,
-                           mv->mv_data);
-                       pci_unmask_msix_vector(dev, i);
+
+                       vector = PCI_MSIX_RID2VEC(mv->mv_rid);
+                       pci_setup_msix_vector(dev, vector,
+                           mv->mv_address, mv->mv_data);
+                       pci_unmask_msix_vector(dev, vector);
                }
        }
        pci_write_config(dev, msix->msix_location + PCIR_MSIX_CTRL,
@@ -1463,199 +1467,103 @@ pci_resume_msix(device_t dev)
 }
 
 /*
- * Attempt to allocate *count MSI-X messages.  The actual number allocated is
- * returned in *count.  After this function returns, each message will be
- * available to the driver as SYS_RES_IRQ resources starting at rid 1.
+ * Attempt to allocate one MSI-X message at the specified vector on cpuid.
+ *
+ * After this function returns, the MSI-X's rid will be saved in rid0.
  */
 int
-pci_alloc_msix_method(device_t dev, device_t child, int *count)
+pci_alloc_msix_vector_method(device_t dev, device_t child, u_int vector,
+    int *rid0, int cpuid)
 {
        struct pci_devinfo *dinfo = device_get_ivars(child);
-       pcicfgregs *cfg = &dinfo->cfg;
+       struct pcicfg_msix *msix = &dinfo->cfg.msix;
+       struct msix_vector *mv;
        struct resource_list_entry *rle;
-       int actual, error, i, irq, max;
-
-       /* Don't let count == 0 get us into trouble. */
-       if (*count == 0)
-               return (EINVAL);
-
-       /* If rid 0 is allocated, then fail. */
-       rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 0);
-       if (rle != NULL && rle->res != NULL)
-               return (ENXIO);
+       int error, irq, rid;
 
-       /* Already have allocated messages? */
-       if (cfg->msi.msi_alloc != 0 || cfg->msix.msix_alloc != 0)
-               return (ENXIO);
-
-       /* If MSI is blacklisted for this system, fail. */
-       if (pci_msi_blacklisted())
-               return (ENXIO);
-
-       /* MSI-X capability present? */
-       if (cfg->msix.msix_location == 0 || !pci_do_msix)
-               return (ENODEV);
-
-       /* Make sure the appropriate BARs are mapped. */
-       rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY,
-           cfg->msix.msix_table_bar);
-       if (rle == NULL || rle->res == NULL ||
-           !(rman_get_flags(rle->res) & RF_ACTIVE))
-               return (ENXIO);
-       cfg->msix.msix_table_res = rle->res;
-       if (cfg->msix.msix_pba_bar != cfg->msix.msix_table_bar) {
-               rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY,
-                   cfg->msix.msix_pba_bar);
-               if (rle == NULL || rle->res == NULL ||
-                   !(rman_get_flags(rle->res) & RF_ACTIVE))
-                       return (ENXIO);
-       }
-       cfg->msix.msix_pba_res = rle->res;
+       KASSERT(msix->msix_table_res != NULL &&
+           msix->msix_pba_res != NULL, ("MSI-X is not setup yet\n"));
+       KASSERT(cpuid >= 0 && cpuid < ncpus, ("invalid cpuid %d\n", cpuid));
+       KASSERT(vector < msix->msix_msgnum,
+           ("invalid MSI-X vector %u, total %d\n", vector, msix->msix_msgnum));
 
-       if (bootverbose)
+       if (bootverbose) {
                device_printf(child,
-                   "attempting to allocate %d MSI-X vectors (%d supported)\n",
-                   *count, cfg->msix.msix_msgnum);
-       max = min(*count, cfg->msix.msix_msgnum);
-       for (i = 0; i < max; i++) {
-               /* Allocate a message. */
-               error = PCIB_ALLOC_MSIX(device_get_parent(dev), child, &irq,
-                   -1 /* XXX */);
-               if (error)
-                       break;
-               resource_list_add(&dinfo->resources, SYS_RES_IRQ, i + 1, irq,
-                   irq, 1, -1);
+                   "attempting to allocate MSI-X #%u vector (%d supported)\n",
+                   vector, msix->msix_msgnum);
        }
-       actual = i;
 
-       if (actual == 0) {
-               if (bootverbose) {
-                       device_printf(child,
-                           "could not allocate any MSI-X vectors\n");
-               }
-               return  (ENXIO);
-       }
+       /* Set rid according to vector number */
+       rid = PCI_MSIX_VEC2RID(vector);
 
-       if (bootverbose) {
-               rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 1);
-               if (actual == 1)
-                       device_printf(child, "using IRQ %lu for MSI-X\n",
-                           rle->start);
-               else {
-                       int run;
+       /* Vector has already been allocated */
+       mv = pci_find_msix_vector(child, rid);
+       if (mv != NULL)
+               return EBUSY;
 
-                       /*
-                        * Be fancy and try to print contiguous runs of
-                        * IRQ values as ranges.  'irq' is the previous IRQ.
-                        * 'run' is true if we are in a range.
-                        */
-                       device_printf(child, "using IRQs %lu", rle->start);
-                       irq = rle->start;
-                       run = 0;
-                       for (i = 1; i < actual; i++) {
-                               rle = resource_list_find(&dinfo->resources,
-                                   SYS_RES_IRQ, i + 1);
-
-                               /* Still in a run? */
-                               if (rle->start == irq + 1) {
-                                       run = 1;
-                                       irq++;
-                                       continue;
-                               }
-
-                               /* Finish previous range. */
-                               if (run) {
-                                       kprintf("-%d", irq);
-                                       run = 0;
-                               }
-
-                               /* Start new range. */
-                               kprintf(",%lu", rle->start);
-                               irq = rle->start;
-                       }
+       /* Allocate a message. */
+       error = PCIB_ALLOC_MSIX(device_get_parent(dev), child, &irq, cpuid);
+       if (error)
+               return error;
+       resource_list_add(&dinfo->resources, SYS_RES_IRQ, rid,
+           irq, irq, 1, cpuid);
 
-                       /* Unfinished range? */
-                       if (run)
-                               kprintf("-%d", irq);
-                       kprintf(" for MSI-X\n");
-               }
+       if (bootverbose) {
+               rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, rid);
+               device_printf(child, "using IRQ %lu for MSI-X on cpu%d\n",
+                   rle->start, cpuid);
        }
 
-       /* Mask all vectors. */
-       for (i = 0; i < cfg->msix.msix_msgnum; i++)
-               pci_mask_msix_vector(child, i);
-
-       /* Allocate and initialize vector data and virtual table. */
-       cfg->msix.msix_vectors = kmalloc(sizeof(struct msix_vector) * actual,
-           M_DEVBUF, M_WAITOK | M_ZERO);
-       cfg->msix.msix_table = kmalloc(sizeof(struct msix_table_entry) * actual,
-           M_DEVBUF, M_WAITOK | M_ZERO);
-       for (i = 0; i < actual; i++) {
-               rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i + 1);
-               cfg->msix.msix_vectors[i].mv_irq = rle->start;
-               cfg->msix.msix_table[i].mte_vector = i + 1;
-       }
+       /* Update counts of alloc'd messages. */
+       msix->msix_alloc++;
 
-       /* Update control register to enable MSI-X. */
-       cfg->msix.msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE;
-       pci_write_config(child, cfg->msix.msix_location + PCIR_MSIX_CTRL,
-           cfg->msix.msix_ctrl, 2);
+       mv = kmalloc(sizeof(*mv), M_DEVBUF, M_WAITOK | M_ZERO);
+       mv->mv_rid = rid;
+       TAILQ_INSERT_TAIL(&msix->msix_vectors, mv, mv_link);
 
-       /* Update counts of alloc'd messages. */
-       cfg->msix.msix_alloc = actual;
-       cfg->msix.msix_table_len = actual;
-       *count = actual;
-       return (0);
+       *rid0 = rid;
+       return 0;
 }
 
-#ifdef notyet
-static int
-pci_release_msix(device_t dev, device_t child)
+int
+pci_release_msix_vector_method(device_t dev, device_t child, int rid)
 {
        struct pci_devinfo *dinfo = device_get_ivars(child);
        struct pcicfg_msix *msix = &dinfo->cfg.msix;
        struct resource_list_entry *rle;
-       int i;
+       struct msix_vector *mv;
+       int irq, cpuid;
 
-       /* Do we have any messages to release? */
-       if (msix->msix_alloc == 0)
-               return (ENODEV);
+       KASSERT(msix->msix_table_res != NULL &&
+           msix->msix_pba_res != NULL, ("MSI-X is not setup yet\n"));
+       KASSERT(msix->msix_alloc > 0, ("No MSI-X allocated\n"));
+       KASSERT(rid > 0, ("invalid rid %d\n", rid));
 
-       /* Make sure none of the resources are allocated. */
-       for (i = 0; i < msix->msix_table_len; i++) {
-               if (msix->msix_table[i].mte_vector == 0)
-                       continue;
-               if (msix->msix_table[i].mte_handlers > 0)
-                       return (EBUSY);
-               rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i + 1);
-               KASSERT(rle != NULL, ("missing resource"));
-               if (rle->res != NULL)
-                       return (EBUSY);
-       }
+       mv = pci_find_msix_vector(child, rid);
+       KASSERT(mv != NULL, ("MSI-X rid %d is not allocated\n", rid));
+       KASSERT(mv->mv_address == 0, ("MSI-X rid %d not teardown\n", rid));
 
-       /* Update control register to disable MSI-X. */
-       msix->msix_ctrl &= ~PCIM_MSIXCTRL_MSIX_ENABLE;
-       pci_write_config(child, msix->msix_location + PCIR_MSIX_CTRL,
-           msix->msix_ctrl, 2);
+       /* Make sure resource is no longer allocated. */
+       rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, rid);
+       KASSERT(rle != NULL, ("missing MSI-X resource, rid %d\n", rid));
+       KASSERT(rle->res == NULL,
+           ("MSI-X resource is still allocated, rid %d\n", rid));
+
+       irq = rle->start;
+       cpuid = rle->cpuid;
 
        /* Free the resource list entries. */
-       for (i = 0; i < msix->msix_table_len; i++) {
-               if (msix->msix_table[i].mte_vector == 0)
-                       continue;
-               resource_list_delete(&dinfo->resources, SYS_RES_IRQ, i + 1);
-       }
-       kfree(msix->msix_table, M_DEVBUF);
-       msix->msix_table_len = 0;
-
-       /* Release the IRQs. */
-       for (i = 0; i < msix->msix_alloc; i++)
-               PCIB_RELEASE_MSIX(device_get_parent(dev), child,
-                   msix->msix_vectors[i].mv_irq, -1 /* XXX */);
-       kfree(msix->msix_vectors, M_DEVBUF);
-       msix->msix_alloc = 0;
+       resource_list_delete(&dinfo->resources, SYS_RES_IRQ, rid);
+
+       /* Release the IRQ. */
+       PCIB_RELEASE_MSIX(device_get_parent(dev), child, irq, cpuid);
+
+       TAILQ_REMOVE(&msix->msix_vectors, mv, mv_link);
+       kfree(mv, M_DEVBUF);
+
+       msix->msix_alloc--;
        return (0);
 }
-#endif
 
 /*
  * Return the max supported MSI-X messages this device supports.
@@ -1699,9 +1607,14 @@ pci_setup_msix(device_t dev)
                return (ENXIO);
 
        /* MSI-X capability present? */
-       if (cfg->msix.msix_location == 0 || !pci_do_msix)
+       if (cfg->msix.msix_location == 0 || cfg->msix.msix_msgnum == 0 ||
+           !pci_do_msix)
                return (ENODEV);
 
+       KASSERT(cfg->msix.msix_alloc == 0 &&
+           TAILQ_EMPTY(&cfg->msix.msix_vectors),
+           ("MSI-X vector has been allocated\n"));
+
        /* Make sure the appropriate BARs are mapped. */
        rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY,
            cfg->msix.msix_table_bar);
@@ -1734,6 +1647,8 @@ pci_teardown_msix(device_t dev)
 
        KASSERT(msix->msix_table_res != NULL &&
            msix->msix_pba_res != NULL, ("MSI-X is not setup yet\n"));
+       KASSERT(msix->msix_alloc == 0 && TAILQ_EMPTY(&msix->msix_vectors),
+           ("MSI-X vector is still allocated\n"));
 
        pci_mask_msix_allvectors(dev);
 
@@ -1741,6 +1656,39 @@ pci_teardown_msix(device_t dev)
        msix->msix_pba_res = NULL;
 }
 
+void
+pci_enable_msix(device_t dev)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(dev);
+       struct pcicfg_msix *msix = &dinfo->cfg.msix;
+
+       KASSERT(msix->msix_table_res != NULL &&
+           msix->msix_pba_res != NULL, ("MSI-X is not setup yet\n"));
+
+       /* Update control register to enable MSI-X. */
+       msix->msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE;
+       pci_write_config(dev, msix->msix_location + PCIR_MSIX_CTRL,
+           msix->msix_ctrl, 2);
+}
+
+void
+pci_disable_msix(device_t dev)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(dev);
+       struct pcicfg_msix *msix = &dinfo->cfg.msix;
+
+       KASSERT(msix->msix_table_res != NULL &&
+           msix->msix_pba_res != NULL, ("MSI-X is not setup yet\n"));
+
+       /* Disable MSI -> HT mapping. */
+       pci_ht_map_msi(dev, 0);
+
+       /* Update control register to disable MSI-X. */
+       msix->msix_ctrl &= ~PCIM_MSIXCTRL_MSIX_ENABLE;
+       pci_write_config(dev, msix->msix_location + PCIR_MSIX_CTRL,
+           msix->msix_ctrl, 2);
+}
+
 static void
 pci_mask_msix_allvectors(device_t dev)
 {
@@ -1751,6 +1699,20 @@ pci_mask_msix_allvectors(device_t dev)
                pci_mask_msix_vector(dev, i);
 }
 
+static struct msix_vector *
+pci_find_msix_vector(device_t dev, int rid)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(dev);
+       struct pcicfg_msix *msix = &dinfo->cfg.msix;
+       struct msix_vector *mv;
+
+       TAILQ_FOREACH(mv, &msix->msix_vectors, mv_link) {
+               if (mv->mv_rid == rid)
+                       return mv;
+       }
+       return NULL;
+}
+
 /*
  * HyperTransport MSI mapping control
  */
@@ -1771,7 +1733,7 @@ pci_ht_map_msi(device_t dev, uint64_t addr)
                    ht->ht_msictrl, 2);
        }
 
-       if (!addr && ht->ht_msictrl & PCIM_HTCMD_MSI_ENABLE) {
+       if (!addr && (ht->ht_msictrl & PCIM_HTCMD_MSI_ENABLE)) {
                /* Disable MSI -> HT mapping. */
                ht->ht_msictrl &= ~PCIM_HTCMD_MSI_ENABLE;
                pci_write_config(dev, ht->ht_msimap + PCIR_HT_COMMAND,
@@ -1940,7 +1902,7 @@ pci_alloc_msi_method(device_t dev, device_t child, int *rid, int count,
                return (ENXIO);
 
        /* Already have allocated messages? */
-       if (cfg->msi.msi_alloc != 0 || cfg->msix.msix_alloc != 0)
+       if (cfg->msi.msi_alloc != 0 || cfg->msix.msix_table_res != NULL)
                return (ENXIO);
 
        /* If MSI is blacklisted for this system, fail. */
@@ -1948,7 +1910,8 @@ pci_alloc_msi_method(device_t dev, device_t child, int *rid, int count,
                return (ENXIO);
 
        /* MSI capability present? */
-       if (cfg->msi.msi_location == 0 || !pci_do_msi)
+       if (cfg->msi.msi_location == 0 || cfg->msi.msi_msgnum == 0 ||
+           !pci_do_msi)
                return (ENODEV);
 
        KASSERT(count <= cfg->msi.msi_msgnum, ("large MSI count %d, max %d\n",
@@ -1956,8 +1919,8 @@ pci_alloc_msi_method(device_t dev, device_t child, int *rid, int count,
 
        if (bootverbose) {
                device_printf(child,
-                   "attempting to allocate %d MSI vectors (%d supported)\n",
-                   count, cfg->msi.msi_msgnum);
+                   "attempting to allocate %d MSI vector%s (%d supported)\n",
+                   count, count > 1 ? "s" : "", cfg->msi.msi_msgnum);
        }
 
        if (start_cpuid < 0)
@@ -2726,10 +2689,16 @@ pci_assign_interrupt(device_t bus, device_t dev, int force_route)
        /* Let the user override the IRQ with a tunable. */
        irq = PCI_INVALID_IRQ;
        ksnprintf(tunable_name, sizeof(tunable_name),
-           "hw.pci%d.%d.%d.INT%c.irq",
-           cfg->domain, cfg->bus, cfg->slot, cfg->intpin + 'A' - 1);
-       if (TUNABLE_INT_FETCH(tunable_name, &irq) && (irq >= 255 || irq <= 0))
-               irq = PCI_INVALID_IRQ;
+           "hw.pci%d.%d.%d.%d.INT%c.irq",
+           cfg->domain, cfg->bus, cfg->slot, cfg->func, cfg->intpin + 'A' - 1);
+       if (TUNABLE_INT_FETCH(tunable_name, &irq)) {
+               if (irq >= 255 || irq <= 0) {
+                       irq = PCI_INVALID_IRQ;
+               } else {
+                       BUS_CONFIG_INTR(bus, dev, irq,
+                           INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
+               }
+       }
 
        /*
         * If we didn't get an IRQ via the tunable, then we either use the
@@ -3022,18 +2991,14 @@ pci_child_detached(device_t parent __unused, device_t child)
 
 int
 pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags,
-    driver_intr_t *intr, void *arg, void **cookiep, lwkt_serialize_t serializer)
+    driver_intr_t *intr, void *arg, void **cookiep,
+    lwkt_serialize_t serializer, const char *desc)
 {
-       struct pci_devinfo *dinfo;
-       struct msix_table_entry *mte;
-       struct msix_vector *mv;
-       uint64_t addr;
-       uint32_t data;
        int rid, error;
        void *cookie;
 
        error = bus_generic_setup_intr(dev, child, irq, flags, intr,
-           arg, &cookie, serializer);
+           arg, &cookie, serializer, desc);
        if (error)
                return (error);
 
@@ -3048,6 +3013,10 @@ pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags,
                /* Make sure that INTx is enabled */
                pci_clear_command_bit(dev, child, PCIM_CMD_INTxDIS);
        } else {
+               struct pci_devinfo *dinfo = device_get_ivars(child);
+               uint64_t addr;
+               uint32_t data;
+
                /*
                 * Check to see if the interrupt is MSI or MSI-X.
                 * Ask our parent to map the MSI and give
@@ -3055,48 +3024,47 @@ pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags,
                 * If we fail for some reason, teardown the
                 * interrupt handler.
                 */
-               dinfo = device_get_ivars(child);
                if (dinfo->cfg.msi.msi_alloc > 0) {
-                       if (dinfo->cfg.msi.msi_addr == 0) {
-                               KASSERT(dinfo->cfg.msi.msi_handlers == 0,
+                       struct pcicfg_msi *msi = &dinfo->cfg.msi;
+
+                       if (msi->msi_addr == 0) {
+                               KASSERT(msi->msi_handlers == 0,
                            ("MSI has handlers, but vectors not mapped"));
                                error = PCIB_MAP_MSI(device_get_parent(dev),
                                    child, rman_get_start(irq), &addr, &data,
                                    rman_get_cpuid(irq));
                                if (error)
                                        goto bad;
-                               dinfo->cfg.msi.msi_addr = addr;
-                               dinfo->cfg.msi.msi_data = data;
+                               msi->msi_addr = addr;
+                               msi->msi_data = data;
                                pci_enable_msi(child, addr, data);
                        }
-                       dinfo->cfg.msi.msi_handlers++;
+                       msi->msi_handlers++;
                } else {
+                       struct msix_vector *mv;
+                       u_int vector;
+
                        KASSERT(dinfo->cfg.msix.msix_alloc > 0,
-                           ("No MSI or MSI-X interrupts allocated"));
-                       KASSERT(rid <= dinfo->cfg.msix.msix_table_len,
-                           ("MSI-X index too high"));
-                       mte = &dinfo->cfg.msix.msix_table[rid - 1];
-                       KASSERT(mte->mte_vector != 0, ("no message vector"));
-                       mv = &dinfo->cfg.msix.msix_vectors[mte->mte_vector - 1];
-                       KASSERT(mv->mv_irq == rman_get_start(irq),
-                           ("IRQ mismatch"));
-                       if (mv->mv_address == 0) {
-                               KASSERT(mte->mte_handlers == 0,
-                   ("MSI-X table entry has handlers, but vector not mapped"));
-                               error = PCIB_MAP_MSI(device_get_parent(dev),
-                                   child, rman_get_start(irq), &addr, &data,
-                                   rman_get_cpuid(irq));
-                               if (error)
-                                       goto bad;
-                               mv->mv_address = addr;
-                               mv->mv_data = data;
-                       }
-                       if (mte->mte_handlers == 0) {
-                               pci_setup_msix_vector(child, rid - 1,
-                                   mv->mv_address, mv->mv_data);
-                               pci_unmask_msix_vector(child, rid - 1);
-                       }
-                       mte->mte_handlers++;
+                           ("No MSI-X or MSI rid %d allocated\n", rid));
+
+                       mv = pci_find_msix_vector(child, rid);
+                       KASSERT(mv != NULL,
+                           ("MSI-X rid %d is not allocated\n", rid));
+                       KASSERT(mv->mv_address == 0,
+                           ("MSI-X rid %d has been setup\n", rid));
+
+                       error = PCIB_MAP_MSI(device_get_parent(dev),
+                           child, rman_get_start(irq), &addr, &data,
+                           rman_get_cpuid(irq));
+                       if (error)
+                               goto bad;
+                       mv->mv_address = addr;
+                       mv->mv_data = data;
+
+                       vector = PCI_MSIX_RID2VEC(rid);
+                       pci_setup_msix_vector(child, vector,
+                           mv->mv_address, mv->mv_data);
+                       pci_unmask_msix_vector(child, vector);
                }
 
                /* Make sure that INTx is disabled if we are using MSI/MSIX */
@@ -3116,9 +3084,6 @@ int
 pci_teardown_intr(device_t dev, device_t child, struct resource *irq,
     void *cookie)
 {
-       struct msix_table_entry *mte;
-       struct resource_list_entry *rle;
-       struct pci_devinfo *dinfo;
        int rid, error;
 
        if (irq == NULL || !(rman_get_flags(irq) & RF_ACTIVE))
@@ -3133,35 +3098,40 @@ pci_teardown_intr(device_t dev, device_t child, struct resource *irq,
                /* Mask INTx */
                pci_set_command_bit(dev, child, PCIM_CMD_INTxDIS);
        } else {
+               struct pci_devinfo *dinfo = device_get_ivars(child);
+
                /*
                 * Check to see if the interrupt is MSI or MSI-X.  If so,
                 * decrement the appropriate handlers count and mask the
                 * MSI-X message, or disable MSI messages if the count
                 * drops to 0.
                 */
-               dinfo = device_get_ivars(child);
-               rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, rid);
-               if (rle->res != irq)
-                       return (EINVAL);
                if (dinfo->cfg.msi.msi_alloc > 0) {
-                       KASSERT(rid <= dinfo->cfg.msi.msi_alloc,
-                           ("MSI-X index too high"));
-                       if (dinfo->cfg.msi.msi_handlers == 0)
-                               return (EINVAL);
-                       dinfo->cfg.msi.msi_handlers--;
-                       if (dinfo->cfg.msi.msi_handlers == 0)
+                       struct pcicfg_msi *msi = &dinfo->cfg.msi;
+
+                       KASSERT(rid <= msi->msi_alloc,
+                           ("MSI-X index too high\n"));
+                       KASSERT(msi->msi_handlers > 0,
+                           ("MSI rid %d is not setup\n", rid));
+
+                       msi->msi_handlers--;
+                       if (msi->msi_handlers == 0)
                                pci_disable_msi(child);
                } else {
+                       struct msix_vector *mv;
+
                        KASSERT(dinfo->cfg.msix.msix_alloc > 0,
-                           ("No MSI or MSI-X interrupts allocated"));
-                       KASSERT(rid <= dinfo->cfg.msix.msix_table_len,
-                           ("MSI-X index too high"));
-                       mte = &dinfo->cfg.msix.msix_table[rid - 1];
-                       if (mte->mte_handlers == 0)
-                               return (EINVAL);
-                       mte->mte_handlers--;
-                       if (mte->mte_handlers == 0)
-                               pci_mask_msix_vector(child, rid - 1);
+                           ("No MSI or MSI-X rid %d allocated", rid));
+
+                       mv = pci_find_msix_vector(child, rid);
+                       KASSERT(mv != NULL,
+                           ("MSI-X rid %d is not allocated\n", rid));
+                       KASSERT(mv->mv_address != 0,
+                           ("MSI-X rid %d has not been setup\n", rid));
+
+                       pci_mask_msix_vector(child, PCI_MSIX_RID2VEC(rid));
+                       mv->mv_address = 0;
+                       mv->mv_data = 0;
                }
        }
        error = bus_generic_teardown_intr(dev, child, irq, cookie);
@@ -4128,22 +4098,16 @@ pci_alloc_1intr(device_t dev, int msi_enable, int *rid0, u_int *flags0)
 {
        int rid, type;
        u_int flags;
-       char env[64];
 
        rid = 0;
        type = PCI_INTR_TYPE_LEGACY;
        flags = RF_SHAREABLE | RF_ACTIVE;
 
-       ksnprintf(env, sizeof(env), "hw.%s.msi.enable",
-           device_get_nameunit(dev));
-       kgetenv_int(env, &msi_enable);
-
+       device_getenv_int(dev, "msi.enable", &msi_enable);
        if (msi_enable) {
                int cpu = -1;
 
-               ksnprintf(env, sizeof(env), "hw.%s.msi.cpu",
-                   device_get_nameunit(dev));
-               kgetenv_int(env, &cpu);
+               device_getenv_int(dev, "msi.cpu", &cpu);
                if (cpu >= ncpus)
                        cpu = ncpus - 1;