summaryrefslogtreecommitdiff
path: root/drivers/pci/dwc
diff options
context:
space:
mode:
authorRichard Zhu <hongxing.zhu@nxp.com>2018-03-02 17:24:05 +0800
committerJason Liu <jason.hui.liu@nxp.com>2019-02-12 10:30:56 +0800
commit2a273132d3643e1044d40c2d12bbbbbd66247cdf (patch)
treef59cbd124f810d8b6e23d8141143a634d08b2278 /drivers/pci/dwc
parentd6f092a89223504d0e725f8da998d51db6f28499 (diff)
MLK-17731 PCI: dwc: implement MSI-X support
The DWC MSI controller does not support different MSI-X target addresses and does not allow to route individual IRQs to different CPUs. Aside from those shortcomings it is able to support MSI-X just fine. Some devices like the Intel i210 network controller depend on MSI-X to be available to enable all hardware features, so even a feature limited implementation of MSI-X on the host side is useful. Signed-off-by: Lucas Stach <l.stach@pengutronix.de> Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
Diffstat (limited to 'drivers/pci/dwc')
-rw-r--r--drivers/pci/dwc/pcie-designware-host.c20
1 files changed, 14 insertions, 6 deletions
diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c
index eb63a7e627ee..4acd0babc248 100644
--- a/drivers/pci/dwc/pcie-designware-host.c
+++ b/drivers/pci/dwc/pcie-designware-host.c
@@ -234,9 +234,6 @@ static int dw_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev,
int irq, pos;
struct pcie_port *pp = pdev->bus->sysdata;
- if (desc->msi_attrib.is_msix)
- return -EINVAL;
-
irq = assign_irq(1, desc, &pos);
if (irq < 0)
return irq;
@@ -254,9 +251,20 @@ static int dw_msi_setup_irqs(struct msi_controller *chip, struct pci_dev *pdev,
struct msi_desc *desc;
struct pcie_port *pp = pdev->bus->sysdata;
- /* MSI-X interrupts are not supported */
- if (type == PCI_CAP_ID_MSIX)
- return -EINVAL;
+ if (type == PCI_CAP_ID_MSIX) {
+ if ((MAX_MSI_IRQS - bitmap_weight(pp->msi_irq_in_use,
+ MAX_MSI_IRQS)) < nvec)
+ return -ENOSPC;
+
+ for_each_pci_msi_entry(desc, pdev) {
+ int ret = dw_msi_setup_irq(chip, pdev, desc);
+
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+ }
WARN_ON(!list_is_singular(&pdev->dev.msi_list));
desc = list_entry(pdev->dev.msi_list.next, struct msi_desc, list);