diff options
| author | Yijing Wang <wangyijing@huawei.com> | 2015-01-27 20:52:17 -0500 |
|---|---|---|
| committer | Bjorn Helgaas <bhelgaas@google.com> | 2015-01-28 10:25:57 -0500 |
| commit | 6a878e5085fe97bd1e222b7883a1b815fcbbe4ed (patch) | |
| tree | 2ffcc34c8799f2c387c46c3441aa8c1072000e03 | |
| parent | 97bf6af1f928216fd6c5a66e8a57bfa95a659672 (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.c | 4 | ||||
| -rw-r--r-- | drivers/pci/msi.c | 5 |
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 | ||
