Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[linux-2.6-microblaze.git] / drivers / net / ethernet / xscale / ixp4xx_eth.c
index 9defaa2..cb89323 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/kernel.h>
 #include <linux/net_tstamp.h>
 #include <linux/of.h>
+#include <linux/of_mdio.h>
 #include <linux/phy.h>
 #include <linux/platform_data/eth_ixp4xx.h>
 #include <linux/platform_device.h>
@@ -165,7 +166,6 @@ struct eth_regs {
 };
 
 struct port {
-       struct resource *mem_res;
        struct eth_regs __iomem *regs;
        struct npe *npe;
        struct net_device *netdev;
@@ -250,6 +250,7 @@ static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt)
 static DEFINE_SPINLOCK(mdio_lock);
 static struct eth_regs __iomem *mdio_regs; /* mdio command and status only */
 static struct mii_bus *mdio_bus;
+static struct device_node *mdio_bus_np;
 static int ports_open;
 static struct port *npe_port_tab[MAX_NPES];
 static struct dma_pool *dma_pool;
@@ -533,7 +534,8 @@ static int ixp4xx_mdio_register(struct eth_regs __iomem *regs)
        mdio_bus->write = &ixp4xx_mdio_write;
        snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "ixp4xx-eth-0");
 
-       if ((err = mdiobus_register(mdio_bus)))
+       err = of_mdiobus_register(mdio_bus, mdio_bus_np);
+       if (err)
                mdiobus_free(mdio_bus);
        return err;
 }
@@ -1358,19 +1360,118 @@ static const struct net_device_ops ixp4xx_netdev_ops = {
        .ndo_validate_addr = eth_validate_addr,
 };
 
+#ifdef CONFIG_OF
+static struct eth_plat_info *ixp4xx_of_get_platdata(struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       struct of_phandle_args queue_spec;
+       struct of_phandle_args npe_spec;
+       struct device_node *mdio_np;
+       struct eth_plat_info *plat;
+       int ret;
+
+       plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL);
+       if (!plat)
+               return NULL;
+
+       ret = of_parse_phandle_with_fixed_args(np, "intel,npe-handle", 1, 0,
+                                              &npe_spec);
+       if (ret) {
+               dev_err(dev, "no NPE engine specified\n");
+               return NULL;
+       }
+       /* NPE ID 0x00, 0x10, 0x20... */
+       plat->npe = (npe_spec.args[0] << 4);
+
+       /* Check if this device has an MDIO bus */
+       mdio_np = of_get_child_by_name(np, "mdio");
+       if (mdio_np) {
+               plat->has_mdio = true;
+               mdio_bus_np = mdio_np;
+               /* DO NOT put the mdio_np, it will be used */
+       }
+
+       /* Get the rx queue as a resource from queue manager */
+       ret = of_parse_phandle_with_fixed_args(np, "queue-rx", 1, 0,
+                                              &queue_spec);
+       if (ret) {
+               dev_err(dev, "no rx queue phandle\n");
+               return NULL;
+       }
+       plat->rxq = queue_spec.args[0];
+
+       /* Get the txready queue as resource from queue manager */
+       ret = of_parse_phandle_with_fixed_args(np, "queue-txready", 1, 0,
+                                              &queue_spec);
+       if (ret) {
+               dev_err(dev, "no txready queue phandle\n");
+               return NULL;
+       }
+       plat->txreadyq = queue_spec.args[0];
+
+       return plat;
+}
+#else
+static struct eth_plat_info *ixp4xx_of_get_platdata(struct device *dev)
+{
+       return NULL;
+}
+#endif
+
 static int ixp4xx_eth_probe(struct platform_device *pdev)
 {
-       char phy_id[MII_BUS_ID_SIZE + 3];
        struct phy_device *phydev = NULL;
        struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
        struct eth_plat_info *plat;
-       resource_size_t regs_phys;
        struct net_device *ndev;
        struct resource *res;
        struct port *port;
        int err;
 
-       plat = dev_get_platdata(dev);
+       if (np) {
+               plat = ixp4xx_of_get_platdata(dev);
+               if (!plat)
+                       return -ENODEV;
+       } else {
+               plat = dev_get_platdata(dev);
+               if (!plat)
+                       return -ENODEV;
+               plat->npe = pdev->id;
+               switch (plat->npe) {
+               case IXP4XX_ETH_NPEA:
+                       /* If the MDIO bus is not up yet, defer probe */
+                       break;
+               case IXP4XX_ETH_NPEB:
+                       /* On all except IXP43x, NPE-B is used for the MDIO bus.
+                        * If there is no NPE-B in the feature set, bail out,
+                        * else we have the MDIO bus here.
+                        */
+                       if (!cpu_is_ixp43x()) {
+                               if (!(ixp4xx_read_feature_bits() &
+                                     IXP4XX_FEATURE_NPEB_ETH0))
+                                       return -ENODEV;
+                               /* Else register the MDIO bus on NPE-B */
+                               plat->has_mdio = true;
+                       }
+                       break;
+               case IXP4XX_ETH_NPEC:
+                       /* IXP43x lacks NPE-B and uses NPE-C for the MDIO bus
+                        * access, if there is no NPE-C, no bus, nothing works,
+                        * so bail out.
+                        */
+                       if (cpu_is_ixp43x()) {
+                               if (!(ixp4xx_read_feature_bits() &
+                                     IXP4XX_FEATURE_NPEC_ETH))
+                                       return -ENODEV;
+                               /* Else register the MDIO bus on NPE-B */
+                               plat->has_mdio = true;
+                       }
+                       break;
+               default:
+                       return -ENODEV;
+               }
+       }
 
        if (!(ndev = devm_alloc_etherdev(dev, sizeof(struct port))))
                return -ENOMEM;
@@ -1378,59 +1479,29 @@ static int ixp4xx_eth_probe(struct platform_device *pdev)
        SET_NETDEV_DEV(ndev, dev);
        port = netdev_priv(ndev);
        port->netdev = ndev;
-       port->id = pdev->id;
+       port->id = plat->npe;
 
        /* Get the port resource and remap */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res)
                return -ENODEV;
-       regs_phys = res->start;
        port->regs = devm_ioremap_resource(dev, res);
        if (IS_ERR(port->regs))
                return PTR_ERR(port->regs);
 
-       switch (port->id) {
-       case IXP4XX_ETH_NPEA:
-               /* If the MDIO bus is not up yet, defer probe */
-               if (!mdio_bus)
-                       return -EPROBE_DEFER;
-               break;
-       case IXP4XX_ETH_NPEB:
-               /*
-                * On all except IXP43x, NPE-B is used for the MDIO bus.
-                * If there is no NPE-B in the feature set, bail out, else
-                * register the MDIO bus.
-                */
-               if (!cpu_is_ixp43x()) {
-                       if (!(ixp4xx_read_feature_bits() &
-                             IXP4XX_FEATURE_NPEB_ETH0))
-                               return -ENODEV;
-                       /* Else register the MDIO bus on NPE-B */
-                       if ((err = ixp4xx_mdio_register(port->regs)))
-                               return err;
-               }
-               if (!mdio_bus)
-                       return -EPROBE_DEFER;
-               break;
-       case IXP4XX_ETH_NPEC:
-               /*
-                * IXP43x lacks NPE-B and uses NPE-C for the MDIO bus access,
-                * of there is no NPE-C, no bus, nothing works, so bail out.
-                */
-               if (cpu_is_ixp43x()) {
-                       if (!(ixp4xx_read_feature_bits() &
-                             IXP4XX_FEATURE_NPEC_ETH))
-                               return -ENODEV;
-                       /* Else register the MDIO bus on NPE-C */
-                       if ((err = ixp4xx_mdio_register(port->regs)))
-                               return err;
+       /* Register the MDIO bus if we have it */
+       if (plat->has_mdio) {
+               err = ixp4xx_mdio_register(port->regs);
+               if (err) {
+                       dev_err(dev, "failed to register MDIO bus\n");
+                       return err;
                }
-               if (!mdio_bus)
-                       return -EPROBE_DEFER;
-               break;
-       default:
-               return -ENODEV;
        }
+       /* If the instance with the MDIO bus has not yet appeared,
+        * defer probing until it gets probed.
+        */
+       if (!mdio_bus)
+               return -EPROBE_DEFER;
 
        ndev->netdev_ops = &ixp4xx_netdev_ops;
        ndev->ethtool_ops = &ixp4xx_ethtool_ops;
@@ -1444,12 +1515,6 @@ static int ixp4xx_eth_probe(struct platform_device *pdev)
        if (!(port->npe = npe_request(NPE_ID(port->id))))
                return -EIO;
 
-       port->mem_res = request_mem_region(regs_phys, REGS_SIZE, ndev->name);
-       if (!port->mem_res) {
-               err = -EBUSY;
-               goto err_npe_rel;
-       }
-
        port->plat = plat;
        npe_port_tab[NPE_ID(port->id)] = port;
        memcpy(ndev->dev_addr, plat->hwaddr, ETH_ALEN);
@@ -1462,12 +1527,24 @@ static int ixp4xx_eth_probe(struct platform_device *pdev)
        __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
        udelay(50);
 
-       snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT,
-               mdio_bus->id, plat->phy);
-       phydev = phy_connect(ndev, phy_id, &ixp4xx_adjust_link,
-                            PHY_INTERFACE_MODE_MII);
-       if (IS_ERR(phydev)) {
-               err = PTR_ERR(phydev);
+       if (np) {
+               phydev = of_phy_get_and_connect(ndev, np, ixp4xx_adjust_link);
+       } else {
+               phydev = mdiobus_get_phy(mdio_bus, plat->phy);
+               if (IS_ERR(phydev)) {
+                       err = PTR_ERR(phydev);
+                       dev_err(dev, "could not connect phydev (%d)\n", err);
+                       goto err_free_mem;
+               }
+               err = phy_connect_direct(ndev, phydev, ixp4xx_adjust_link,
+                                        PHY_INTERFACE_MODE_MII);
+               if (err)
+                       goto err_free_mem;
+
+       }
+       if (!phydev) {
+               err = -ENODEV;
+               dev_err(dev, "no phydev\n");
                goto err_free_mem;
        }
 
@@ -1485,8 +1562,6 @@ err_phy_dis:
        phy_disconnect(phydev);
 err_free_mem:
        npe_port_tab[NPE_ID(port->id)] = NULL;
-       release_resource(port->mem_res);
-err_npe_rel:
        npe_release(port->npe);
        return err;
 }
@@ -1502,12 +1577,21 @@ static int ixp4xx_eth_remove(struct platform_device *pdev)
        ixp4xx_mdio_remove();
        npe_port_tab[NPE_ID(port->id)] = NULL;
        npe_release(port->npe);
-       release_resource(port->mem_res);
        return 0;
 }
 
+static const struct of_device_id ixp4xx_eth_of_match[] = {
+       {
+               .compatible = "intel,ixp4xx-ethernet",
+       },
+       { },
+};
+
 static struct platform_driver ixp4xx_eth_driver = {
-       .driver.name    = DRV_NAME,
+       .driver = {
+               .name = DRV_NAME,
+               .of_match_table = of_match_ptr(ixp4xx_eth_of_match),
+       },
        .probe          = ixp4xx_eth_probe,
        .remove         = ixp4xx_eth_remove,
 };