diff options
Diffstat (limited to 'drivers/pci/msi.c')
-rw-r--r-- | drivers/pci/msi.c | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 8312492..cda687d 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -567,6 +567,20 @@ out_unroll: return ret; } +static int msi_verify_entries(struct pci_dev *dev) +{ + struct msi_desc *entry; + + list_for_each_entry(entry, &dev->msi_list, list) { + if (!dev->no_64bit_msi || !entry->msg.address_hi) + continue; + dev_err(&dev->dev, "Device has broken 64-bit MSI but arch" + " tried to assign one above 4G\n"); + return -EIO; + } + return 0; +} + /** * msi_capability_init - configure device's MSI capability structure * @dev: pointer to the pci_dev data structure of MSI device function @@ -620,6 +634,13 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) return ret; } + ret = msi_verify_entries(dev); + if (ret) { + msi_mask_irq(entry, mask, ~mask); + free_msi_irqs(dev); + return ret; + } + ret = populate_msi_sysfs(dev); if (ret) { msi_mask_irq(entry, mask, ~mask); @@ -733,7 +754,12 @@ static int msix_capability_init(struct pci_dev *dev, ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX); if (ret) - goto error; + goto out_avail; + + /* Check if all MSI entries honor device restrictions */ + ret = msi_verify_entries(dev); + if (ret) + goto out_free; /* * Some devices require MSI-X to be enabled before we can touch the @@ -746,10 +772,8 @@ static int msix_capability_init(struct pci_dev *dev, msix_program_entries(dev, entries); ret = populate_msi_sysfs(dev); - if (ret) { - ret = 0; - goto error; - } + if (ret) + goto out_free; /* Set MSI-X enabled bits and unmask the function */ pci_intx_for_msi(dev, 0); @@ -760,7 +784,7 @@ static int msix_capability_init(struct pci_dev *dev, return 0; -error: +out_avail: if (ret < 0) { /* * If we had some success, report the number of irqs @@ -777,6 +801,7 @@ error: ret = avail; } +out_free: free_msi_irqs(dev); return ret; |