diff options
author | Richard Zhu <hongxing.zhu@nxp.com> | 2018-03-02 17:24:05 +0800 |
---|---|---|
committer | Jason Liu <jason.hui.liu@nxp.com> | 2019-02-12 10:30:56 +0800 |
commit | 2a273132d3643e1044d40c2d12bbbbbd66247cdf (patch) | |
tree | f59cbd124f810d8b6e23d8141143a634d08b2278 /drivers/pci | |
parent | d6f092a89223504d0e725f8da998d51db6f28499 (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')
-rw-r--r-- | drivers/pci/dwc/pcie-designware-host.c | 20 |
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); |