PCI: vmd: Fix config addressing when using bus offsets
authorJon Derrick <jonathan.derrick@intel.com>
Mon, 16 Sep 2019 13:54:34 +0000 (07:54 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 17 Oct 2019 20:45:44 +0000 (13:45 -0700)
commit e3dffa4f6c3612dea337c9c59191bd418afc941b upstream.

VMD maps child device config spaces to the VMD Config BAR linearly
regardless of the starting bus offset. Because of this, the config
address decode must ignore starting bus offsets when mapping the BDF to
the config space address.

Fixes: 2a5a9c9a20f9 ("PCI: vmd: Add offset to bus numbers if necessary")
Signed-off-by: Jon Derrick <jonathan.derrick@intel.com>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: stable@vger.kernel.org # v5.2+
Signed-off-by: Sushma Kalakota <sushmax.kalakota@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/pci/controller/vmd.c

index 52d4fa4161dcebdb5d61355f916c6b24dc8210ec..65eaa6b61868585d3258f17d178f326eaf1bf4ad 100644 (file)
@@ -97,6 +97,7 @@ struct vmd_dev {
        struct resource         resources[3];
        struct irq_domain       *irq_domain;
        struct pci_bus          *bus;
+       u8                      busn_start;
 
 #ifdef CONFIG_X86_DEV_DMA_OPS
        struct dma_map_ops      dma_ops;
@@ -468,7 +469,8 @@ static char __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus,
                                  unsigned int devfn, int reg, int len)
 {
        char __iomem *addr = vmd->cfgbar +
-                            (bus->number << 20) + (devfn << 12) + reg;
+                            ((bus->number - vmd->busn_start) << 20) +
+                            (devfn << 12) + reg;
 
        if ((addr - vmd->cfgbar) + len >=
            resource_size(&vmd->dev->resource[VMD_CFGBAR]))
@@ -591,7 +593,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
        unsigned long flags;
        LIST_HEAD(resources);
        resource_size_t offset[2] = {0};
-       resource_size_t membar2_offset = 0x2000, busn_start = 0;
+       resource_size_t membar2_offset = 0x2000;
 
        /*
         * Shadow registers may exist in certain VMD device ids which allow
@@ -633,14 +635,14 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
                pci_read_config_dword(vmd->dev, PCI_REG_VMCONFIG, &vmconfig);
                if (BUS_RESTRICT_CAP(vmcap) &&
                    (BUS_RESTRICT_CFG(vmconfig) == 0x1))
-                       busn_start = 128;
+                       vmd->busn_start = 128;
        }
 
        res = &vmd->dev->resource[VMD_CFGBAR];
        vmd->resources[0] = (struct resource) {
                .name  = "VMD CFGBAR",
-               .start = busn_start,
-               .end   = busn_start + (resource_size(res) >> 20) - 1,
+               .start = vmd->busn_start,
+               .end   = vmd->busn_start + (resource_size(res) >> 20) - 1,
                .flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED,
        };
 
@@ -708,8 +710,8 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
        pci_add_resource_offset(&resources, &vmd->resources[1], offset[0]);
        pci_add_resource_offset(&resources, &vmd->resources[2], offset[1]);
 
-       vmd->bus = pci_create_root_bus(&vmd->dev->dev, busn_start, &vmd_ops,
-                                      sd, &resources);
+       vmd->bus = pci_create_root_bus(&vmd->dev->dev, vmd->busn_start,
+                                       &vmd_ops, sd, &resources);
        if (!vmd->bus) {
                pci_free_resource_list(&resources);
                irq_domain_remove(vmd->irq_domain);