x86/PCI: read maximum MSI vector count early
authorJan Beulich <jbeulich@suse.com>
Wed, 25 Sep 2019 14:01:31 +0000 (16:01 +0200)
committerJan Beulich <jbeulich@suse.com>
Wed, 25 Sep 2019 14:01:31 +0000 (16:01 +0200)
Rather than doing this every time we set up interrupts for a device
anew (and then in several places) fill this invariant field right after
allocating struct pci_dev.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Paul Durrant <paul.durrant@citrix.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
xen/arch/x86/msi.c
xen/drivers/passthrough/pci.c
xen/drivers/vpci/msi.c
xen/include/xen/pci.h
xen/include/xen/vpci.h

index 529705993676b6979d512a7daf25e323b59484da..76d4034c4f5db44b3c76470618732685fbd10303 100644 (file)
@@ -664,7 +664,7 @@ static int msi_capability_init(struct pci_dev *dev,
 {
     struct msi_desc *entry;
     int pos;
-    unsigned int i, maxvec, mpos;
+    unsigned int i, mpos;
     u16 control, seg = dev->seg;
     u8 bus = dev->bus;
     u8 slot = PCI_SLOT(dev->devfn);
@@ -675,9 +675,8 @@ static int msi_capability_init(struct pci_dev *dev,
     if ( !pos )
         return -ENODEV;
     control = pci_conf_read16(dev->sbdf, msi_control_reg(pos));
-    maxvec = multi_msi_capable(control);
-    if ( nvec > maxvec )
-        return maxvec;
+    if ( nvec > dev->msi_maxvec )
+        return dev->msi_maxvec;
     control &= ~PCI_MSI_FLAGS_QSIZE;
     multi_msi_enable(control, nvec);
 
@@ -711,7 +710,7 @@ static int msi_capability_init(struct pci_dev *dev,
 
         /* All MSIs are unmasked by default, Mask them all */
         maskbits = pci_conf_read32(dev->sbdf, mpos);
-        maskbits |= ~(u32)0 >> (32 - maxvec);
+        maskbits |= ~(uint32_t)0 >> (32 - dev->msi_maxvec);
         pci_conf_write32(dev->sbdf, mpos, maskbits);
     }
     list_add_tail(&entry->list, &dev->msi_list);
@@ -1284,7 +1283,6 @@ int pci_msi_conf_write_intercept(struct pci_dev *pdev, unsigned int reg,
     entry = find_msi_entry(pdev, -1, PCI_CAP_ID_MSI);
     if ( entry && entry->msi_attrib.maskbit )
     {
-        uint16_t cntl;
         uint32_t unused;
         unsigned int nvec = entry->msi.nvec;
 
@@ -1297,8 +1295,7 @@ int pci_msi_conf_write_intercept(struct pci_dev *pdev, unsigned int reg,
         if ( reg < entry->msi.mpos || reg >= entry->msi.mpos + 4 || size != 4 )
             return -EACCES;
 
-        cntl = pci_conf_read16(pdev->sbdf, msi_control_reg(pos));
-        unused = ~(uint32_t)0 >> (32 - multi_msi_capable(cntl));
+        unused = ~(uint32_t)0 >> (32 - pdev->msi_maxvec);
         for ( pos = 0; pos < nvec; ++pos, ++entry )
         {
             entry->msi_attrib.guest_masked =
index d28f17af7525fc0e5a21c4dc0374ac9faec513e6..b3c4c9166afc8d7e2ffb13a4398e56d6c8c885f2 100644 (file)
@@ -340,6 +340,15 @@ static struct pci_dev *alloc_pdev(struct pci_seg *pseg, u8 bus, u8 devfn)
     pdev->domain = NULL;
     INIT_LIST_HEAD(&pdev->msi_list);
 
+    pos = pci_find_cap_offset(pseg->nr, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                              PCI_CAP_ID_MSI);
+    if ( pos )
+    {
+        uint16_t ctrl = pci_conf_read16(pdev->sbdf, msi_control_reg(pos));
+
+        pdev->msi_maxvec = multi_msi_capable(ctrl);
+    }
+
     pos = pci_find_cap_offset(pseg->nr, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
                               PCI_CAP_ID_MSIX);
     if ( pos )
index 5b6602f3c2babcea1e8e8fd47155da81096f374e..75010762ed6dab1629a3327de9bf138b07040d27 100644 (file)
@@ -27,7 +27,7 @@ static uint32_t control_read(const struct pci_dev *pdev, unsigned int reg,
 {
     const struct vpci_msi *msi = data;
 
-    return MASK_INSR(fls(msi->max_vectors) - 1, PCI_MSI_FLAGS_QMASK) |
+    return MASK_INSR(fls(pdev->msi_maxvec) - 1, PCI_MSI_FLAGS_QMASK) |
            MASK_INSR(fls(msi->vectors) - 1, PCI_MSI_FLAGS_QSIZE) |
            (msi->enabled ? PCI_MSI_FLAGS_ENABLE : 0) |
            (msi->masking ? PCI_MSI_FLAGS_MASKBIT : 0) |
@@ -40,7 +40,7 @@ static void control_write(const struct pci_dev *pdev, unsigned int reg,
     struct vpci_msi *msi = data;
     unsigned int vectors = min_t(uint8_t,
                                  1u << MASK_EXTR(val, PCI_MSI_FLAGS_QSIZE),
-                                 msi->max_vectors);
+                                 pdev->msi_maxvec);
     bool new_enabled = val & PCI_MSI_FLAGS_ENABLE;
 
     /*
@@ -215,8 +215,7 @@ static int init_msi(struct pci_dev *pdev)
      * FIXME: I've only been able to test this code with devices using a single
      * MSI interrupt and no mask register.
      */
-    pdev->vpci->msi->max_vectors = multi_msi_capable(control);
-    ASSERT(pdev->vpci->msi->max_vectors <= 32);
+    ASSERT(pdev->msi_maxvec <= 32);
 
     /* The multiple message enable is 0 after reset (1 message enabled). */
     pdev->vpci->msi->vectors = 1;
@@ -298,7 +297,7 @@ void vpci_dump_msi(void)
                 if ( msi->masking )
                     printk(" mask=%08x", msi->mask);
                 printk(" vectors max: %u enabled: %u\n",
-                       msi->max_vectors, msi->vectors);
+                       pdev->msi_maxvec, msi->vectors);
 
                 vpci_msi_arch_print(msi);
             }
index 8148f5b2e77393844a839023689bfa23390b614c..393cb45de347cd74748c1346f419b8bff44c7b69 100644 (file)
@@ -94,7 +94,8 @@ struct pci_dev {
         pci_sbdf_t sbdf;
     };
 
-    u8 phantom_stride;
+    uint8_t msi_maxvec;
+    uint8_t phantom_stride;
 
     nodeid_t node; /* NUMA node */
 
index 4cf233c77983e7f303342d060e7e748d864b715a..5295d4c9907b9ce7f96b03db6e506434aa05a2a4 100644 (file)
@@ -99,14 +99,12 @@ struct vpci {
         uint32_t mask;
         /* Data. */
         uint16_t data;
-        /* Maximum number of vectors supported by the device. */
-        uint8_t max_vectors : 6;
+        /* Number of vectors configured. */
+        uint8_t vectors     : 6;
         /* Supports per-vector masking? */
         bool masking        : 1;
         /* 64-bit address capable? */
         bool address64      : 1;
-        /* Number of vectors configured. */
-        uint8_t vectors     : 6;
         /* Enabled? */
         bool enabled        : 1;
         /* Arch-specific data. */