| From f144d1496b47e7450f41b767d0d91c724c2198bc Mon Sep 17 00:00:00 2001 |
| From: Benjamin Herrenschmidt <benh@kernel.crashing.org> |
| Date: Fri, 3 Oct 2014 15:13:24 +1000 |
| Subject: PCI/MSI: Add device flag indicating that 64-bit MSIs don't work |
| |
| From: Benjamin Herrenschmidt <benh@kernel.crashing.org> |
| |
| 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: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/pci/msi.c | 26 ++++++++++++++++++++++++++ |
| include/linux/pci.h | 1 + |
| 2 files changed, 27 insertions(+) |
| |
| --- a/drivers/pci/msi.c |
| +++ b/drivers/pci/msi.c |
| @@ -599,6 +599,20 @@ error_attrs: |
| 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 |
| @@ -652,6 +666,13 @@ static int msi_capability_init(struct pc |
| 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); |
| @@ -767,6 +788,11 @@ static int msix_capability_init(struct p |
| 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 |
| --- a/include/linux/pci.h |
| +++ b/include/linux/pci.h |
| @@ -324,6 +324,7 @@ struct pci_dev { |
| unsigned int is_added:1; |
| unsigned int is_busmaster:1; /* device is busmaster */ |
| unsigned int no_msi:1; /* device may not use msi */ |
| + unsigned int no_64bit_msi:1; /* device may only use 32-bit MSIs */ |
| unsigned int block_cfg_access:1; /* config space access is blocked */ |
| unsigned int broken_parity_status:1; /* Device generates false positive parity */ |
| unsigned int irq_reroute_variant:2; /* device needs IRQ rerouting variant */ |