PCI: pci-host-generic: add MSI support
Add the required code to probe for a "msi-parent" node in
the FDT, and assign the corresponding msi_chip to the PCI
bus. This relies on the msi_chip having been registered
as a "msi-controller".
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
[will: moved phandle parsing to avoid having to put the ref on error]
Signed-off-by: Will Deacon <will.deacon@arm.com>
diff --git a/Documentation/devicetree/bindings/pci/host-generic-pci.txt b/Documentation/devicetree/bindings/pci/host-generic-pci.txt
index f0b0436..22cc401 100644
--- a/Documentation/devicetree/bindings/pci/host-generic-pci.txt
+++ b/Documentation/devicetree/bindings/pci/host-generic-pci.txt
@@ -69,6 +69,9 @@
- interrupt-map-mask : <see aforementioned specification>
+MSI support is provided by a separate optional property:
+
+- msi-parent : phandle to the device implementing the MSI doorbell
Example:
@@ -97,4 +100,6 @@
// PCI_DEVICE(3) INT#(1)
interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+
+ msi-parent = <&its>
}
diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c
index 0fb464a..8052ae0 100644
--- a/drivers/pci/host/pci-host-generic.c
+++ b/drivers/pci/host/pci-host-generic.c
@@ -21,6 +21,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/msi.h>
#include <linux/of_address.h>
#include <linux/of_pci.h>
#include <linux/platform_device.h>
@@ -42,6 +43,7 @@
struct pci_host_bridge host;
struct gen_pci_cfg_windows cfg;
struct list_head resources;
+ struct msi_chip *msi;
};
static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus,
@@ -317,6 +319,26 @@
return 1;
}
+static void gen_pci_add_bus(struct pci_bus *bus)
+{
+ struct pci_sys_data *sys = bus->sysdata;
+ struct gen_pci *pci = sys->private_data;
+
+ bus->msi = pci->msi;
+}
+
+static void gen_pci_get_msi_parent(struct gen_pci *pci)
+{
+ struct device_node *msi_node;
+
+ msi_node = of_parse_phandle(pci->host.dev.parent->of_node,
+ "msi-parent", 0);
+ if (!msi_node)
+ return;
+
+ pci->msi = of_pci_find_msi_chip_by_node(msi_node);
+}
+
static int gen_pci_probe(struct platform_device *pdev)
{
int err;
@@ -334,6 +356,7 @@
.map_irq = of_irq_parse_and_map_pci,
#endif
.ops = &gen_pci_ops,
+ .add_bus = gen_pci_add_bus,
};
if (!pci)
@@ -371,6 +394,7 @@
return err;
}
+ gen_pci_get_msi_parent(pci);
pci_common_init_dev(dev, &hw);
return 0;
}