]> Pileus Git - ~andy/linux/blobdiff - drivers/pci/host/pci-mvebu.c
PCI: mvebu: increment nports only for registered ports
[~andy/linux] / drivers / pci / host / pci-mvebu.c
index 729d5a101d621ece6d36b425ad213a48a57a859f..87aaed591c802290a09a70972cc0234f7728231b 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/clk.h>
 #include <linux/module.h>
 #include <linux/mbus.h>
+#include <linux/msi.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <linux/of_address.h>
@@ -103,6 +104,7 @@ struct mvebu_pcie_port;
 struct mvebu_pcie {
        struct platform_device *pdev;
        struct mvebu_pcie_port *ports;
+       struct msi_chip *msi;
        struct resource io;
        struct resource realio;
        struct resource mem;
@@ -673,6 +675,12 @@ static struct pci_bus *mvebu_pcie_scan_bus(int nr, struct pci_sys_data *sys)
        return bus;
 }
 
+void mvebu_pcie_add_bus(struct pci_bus *bus)
+{
+       struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata);
+       bus->msi = pcie->msi;
+}
+
 resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev,
                                          const struct resource *res,
                                          resource_size_t start,
@@ -709,6 +717,7 @@ static void __init mvebu_pcie_enable(struct mvebu_pcie *pcie)
        hw.map_irq        = mvebu_pcie_map_irq;
        hw.ops            = &mvebu_pcie_ops;
        hw.align_resource = mvebu_pcie_align_resource;
+       hw.add_bus        = mvebu_pcie_add_bus;
 
        pci_common_init(&hw);
 }
@@ -777,6 +786,21 @@ static int mvebu_get_tgt_attr(struct device_node *np, int devfn,
        return -ENOENT;
 }
 
+static void __init mvebu_pcie_msi_enable(struct mvebu_pcie *pcie)
+{
+       struct device_node *msi_node;
+
+       msi_node = of_parse_phandle(pcie->pdev->dev.of_node,
+                                   "msi-parent", 0);
+       if (!msi_node)
+               return;
+
+       pcie->msi = of_pci_find_msi_chip_by_node(msi_node);
+
+       if (pcie->msi)
+               pcie->msi->dev = &pcie->pdev->dev;
+}
+
 static int __init mvebu_pcie_probe(struct platform_device *pdev)
 {
        struct mvebu_pcie *pcie;
@@ -818,13 +842,14 @@ static int __init mvebu_pcie_probe(struct platform_device *pdev)
                return ret;
        }
 
+       i = 0;
        for_each_child_of_node(pdev->dev.of_node, child) {
                if (!of_device_is_available(child))
                        continue;
-               pcie->nports++;
+               i++;
        }
 
-       pcie->ports = devm_kzalloc(&pdev->dev, pcie->nports *
+       pcie->ports = devm_kzalloc(&pdev->dev, i *
                                   sizeof(struct mvebu_pcie_port),
                                   GFP_KERNEL);
        if (!pcie->ports)
@@ -873,11 +898,23 @@ static int __init mvebu_pcie_probe(struct platform_device *pdev)
                        continue;
                }
 
+               port->clk = of_clk_get_by_name(child, NULL);
+               if (IS_ERR(port->clk)) {
+                       dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n",
+                              port->port, port->lane);
+                       continue;
+               }
+
+               ret = clk_prepare_enable(port->clk);
+               if (ret)
+                       continue;
+
                port->base = mvebu_pcie_map_registers(pdev, child, port);
                if (IS_ERR(port->base)) {
                        dev_err(&pdev->dev, "PCIe%d.%d: cannot map registers\n",
                                port->port, port->lane);
                        port->base = NULL;
+                       clk_disable_unprepare(port->clk);
                        continue;
                }
 
@@ -893,25 +930,14 @@ static int __init mvebu_pcie_probe(struct platform_device *pdev)
                                 port->port, port->lane);
                }
 
-               port->clk = of_clk_get_by_name(child, NULL);
-               if (IS_ERR(port->clk)) {
-                       dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n",
-                              port->port, port->lane);
-                       iounmap(port->base);
-                       port->haslink = 0;
-                       continue;
-               }
-
                port->dn = child;
-
-               clk_prepare_enable(port->clk);
                spin_lock_init(&port->conf_lock);
-
                mvebu_sw_pci_bridge_init(port);
-
                i++;
        }
 
+       pcie->nports = i;
+       mvebu_pcie_msi_enable(pcie);
        mvebu_pcie_enable(pcie);
 
        return 0;