summaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-10-03 15:13:24 +1000
committerJiri Slaby <jslaby@suse.cz>2014-12-06 15:14:51 +0100
commit5545f8b0fca9fa9efe65d8084dbb536aebabdb61 (patch)
tree011c6e3d8c39d499a0346a432afe56ba9b6b3899 /drivers/pci
parentc50db3a5b930ef107cf6df611e729032e69de350 (diff)
downloadlinux-stable-5545f8b0fca9fa9efe65d8084dbb536aebabdb61.tar.gz
linux-stable-5545f8b0fca9fa9efe65d8084dbb536aebabdb61.tar.bz2
linux-stable-5545f8b0fca9fa9efe65d8084dbb536aebabdb61.zip
PCI/MSI: Add device flag indicating that 64-bit MSIs don't work
commit f144d1496b47e7450f41b767d0d91c724c2198bc upstream. This can be set by quirks/drivers to be used by the architecture code that assigns the MSI addresses. We additionally add verification in the core MSI code that the values assigned by the architecture do satisfy the limitation in order to fail gracefully if they don't (ie. the arch hasn't been updated to deal with that quirk yet). Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Acked-by: Bjorn Helgaas <bhelgaas@google.com> Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/msi.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index b43f391dc8b6..89237c8eab1d 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -553,6 +553,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
@@ -606,6 +620,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);
@@ -721,6 +742,11 @@ static int msix_capability_init(struct pci_dev *dev,
if (ret)
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
* MSI-X registers. We need to mask all the vectors to prevent