summaryrefslogtreecommitdiff
path: root/drivers/pci/host/pci-xgene.c
diff options
context:
space:
mode:
authorDuc Dang <dhdang@apm.com>2015-06-05 20:56:34 (GMT)
committerBjorn Helgaas <bhelgaas@google.com>2015-06-05 20:56:34 (GMT)
commitdcd19de36775b689df602139f3e40bfb114d5d12 (patch)
treecd10fb434431da064a0816ed582989fb7f522569 /drivers/pci/host/pci-xgene.c
parent5ebe6afaf0057ac3eaeb98defd5456894b446d22 (diff)
downloadlinux-dcd19de36775b689df602139f3e40bfb114d5d12.tar.xz
PCI: xgene: Add APM X-Gene v1 PCIe MSI/MSIX termination driver
APM X-Gene v1 SoC supports its own implementation of MSI, which is not compliant to GIC V2M specification for MSI Termination. There is a single MSI block in X-Gene v1 SOC which serves all 5 PCIe ports. This MSI block supports 2048 MSI termination ports coalesced into 16 physical HW IRQ lines and shared across all 5 PCIe ports. As there are only 16 HW IRQs to serve 2048 MSI vectors, to support set_affinity correctly for each MSI vectors, the 16 HW IRQs are statically allocated to 8 X-Gene v1 cores (2 HW IRQs for each cores). To steer MSI interrupt to target CPU, MSI vector is moved around these HW IRQs lines. With this approach, the total MSI vectors this driver supports is reduced to 256. [bhelgaas: squash doc, driver, maintainer update] Signed-off-by: Duc Dang <dhdang@apm.com> Signed-off-by: Tanmay Inamdar <tinamdar@apm.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'drivers/pci/host/pci-xgene.c')
-rw-r--r--drivers/pci/host/pci-xgene.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c
index ee082c0..3e5a636 100644
--- a/drivers/pci/host/pci-xgene.c
+++ b/drivers/pci/host/pci-xgene.c
@@ -468,6 +468,23 @@ static int xgene_pcie_setup(struct xgene_pcie_port *port,
return 0;
}
+static int xgene_pcie_msi_enable(struct pci_bus *bus)
+{
+ struct device_node *msi_node;
+
+ msi_node = of_parse_phandle(bus->dev.of_node,
+ "msi-parent", 0);
+ if (!msi_node)
+ return -ENODEV;
+
+ bus->msi = of_pci_find_msi_chip_by_node(msi_node);
+ if (!bus->msi)
+ return -ENODEV;
+
+ bus->msi->dev = &bus->dev;
+ return 0;
+}
+
static int xgene_pcie_probe_bridge(struct platform_device *pdev)
{
struct device_node *dn = pdev->dev.of_node;
@@ -504,6 +521,10 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev)
if (!bus)
return -ENOMEM;
+ if (IS_ENABLED(CONFIG_PCI_MSI))
+ if (xgene_pcie_msi_enable(bus))
+ dev_info(port->dev, "failed to enable MSI\n");
+
pci_scan_child_bus(bus);
pci_assign_unassigned_bus_resources(bus);
pci_bus_add_devices(bus);