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;
 }