aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYijing Wang <wangyijing@huawei.com>2015-01-27 20:52:17 -0500
committerBjorn Helgaas <bhelgaas@google.com>2015-01-28 10:25:57 -0500
commit6a878e5085fe97bd1e222b7883a1b815fcbbe4ed (patch)
tree2ffcc34c8799f2c387c46c3441aa8c1072000e03
parent97bf6af1f928216fd6c5a66e8a57bfa95a659672 (diff)
PCI: Fail MSI-X mappings if there's no space assigned to MSI-X BAR
Unlike MSI, which is configured via registers in the MSI capability in Configuration Space, MSI-X is configured via tables in Memory Space. These MSI-X tables are mapped by a device BAR, and if no Memory Space has been assigned to the BAR, MSI-X cannot be used. Fail MSI-X setup if no space has been assigned for the BAR. Previously, we ioremapped the MSI-X table even if the resource hadn't been assigned. In this case, the resource address is undefined (and is often zero), which may lead to warnings or oopses in this path: pci_enable_msix msix_capability_init msix_map_region ioremap_nocache The PCI core sets resource flags to zero when it can't assign space for the resource (see reset_resource()). There are also some cases where it sets the IORESOURCE_UNSET flag, e.g., pci_reassigndev_resource_alignment(), pci_assign_resource(), etc. So we must check for both cases. [bhelgaas: changelog] Reported-by: Zhang Jukuo <zhangjukuo@huawei.com> Tested-by: Zhang Jukuo <zhangjukuo@huawei.com> Signed-off-by: Yijing Wang <wangyijing@huawei.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
-rw-r--r--arch/x86/pci/xen.c4
-rw-r--r--drivers/pci/msi.c5
2 files changed, 9 insertions, 0 deletions
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
index c489ef2c1a39..34fc4189ebf0 100644
--- a/arch/x86/pci/xen.c
+++ b/arch/x86/pci/xen.c
@@ -298,12 +298,16 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
298 map_irq.entry_nr = nvec; 298 map_irq.entry_nr = nvec;
299 } else if (type == PCI_CAP_ID_MSIX) { 299 } else if (type == PCI_CAP_ID_MSIX) {
300 int pos; 300 int pos;
301 unsigned long flags;
301 u32 table_offset, bir; 302 u32 table_offset, bir;
302 303
303 pos = dev->msix_cap; 304 pos = dev->msix_cap;
304 pci_read_config_dword(dev, pos + PCI_MSIX_TABLE, 305 pci_read_config_dword(dev, pos + PCI_MSIX_TABLE,
305 &table_offset); 306 &table_offset);
306 bir = (u8)(table_offset & PCI_MSIX_TABLE_BIR); 307 bir = (u8)(table_offset & PCI_MSIX_TABLE_BIR);
308 flags = pci_resource_flags(dev, bir);
309 if (!flags || (flags & IORESOURCE_UNSET))
310 return -EINVAL;
307 311
308 map_irq.table_base = pci_resource_start(dev, bir); 312 map_irq.table_base = pci_resource_start(dev, bir);
309 map_irq.entry_nr = msidesc->msi_attrib.entry_nr; 313 map_irq.entry_nr = msidesc->msi_attrib.entry_nr;
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index fd60806d3fd0..c3e7dfcf9ff5 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -694,11 +694,16 @@ static void __iomem *msix_map_region(struct pci_dev *dev, unsigned nr_entries)
694{ 694{
695 resource_size_t phys_addr; 695 resource_size_t phys_addr;
696 u32 table_offset; 696 u32 table_offset;
697 unsigned long flags;
697 u8 bir; 698 u8 bir;
698 699
699 pci_read_config_dword(dev, dev->msix_cap + PCI_MSIX_TABLE, 700 pci_read_config_dword(dev, dev->msix_cap + PCI_MSIX_TABLE,
700 &table_offset); 701 &table_offset);
701 bir = (u8)(table_offset & PCI_MSIX_TABLE_BIR); 702 bir = (u8)(table_offset & PCI_MSIX_TABLE_BIR);
703 flags = pci_resource_flags(dev, bir);
704 if (!flags || (flags & IORESOURCE_UNSET))
705 return NULL;
706
702 table_offset &= PCI_MSIX_TABLE_OFFSET; 707 table_offset &= PCI_MSIX_TABLE_OFFSET;
703 phys_addr = pci_resource_start(dev, bir) + table_offset; 708 phys_addr = pci_resource_start(dev, bir) + table_offset;
704 709