These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / net / ethernet / broadcom / genet / bcmmii.c
index 420949c..8bdfe53 100644 (file)
@@ -47,7 +47,12 @@ static int bcmgenet_mii_read(struct mii_bus *bus, int phy_id, int location)
                           HZ / 100);
        ret = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD);
 
-       if (ret & MDIO_READ_FAIL)
+       /* Some broken devices are known not to release the line during
+        * turn-around, e.g: Broadcom BCM53125 external switches, so check for
+        * that condition here and ignore the MDIO controller read failure
+        * indication.
+        */
+       if (!(bus->phy_ignore_ta_mask & 1 << phy_id) && (ret & MDIO_READ_FAIL))
                return -EIO;
 
        return ret & 0xffff;
@@ -158,10 +163,26 @@ void bcmgenet_mii_setup(struct net_device *dev)
        phy_print_status(phydev);
 }
 
+
+static int bcmgenet_fixed_phy_link_update(struct net_device *dev,
+                                         struct fixed_phy_status *status)
+{
+       if (dev && dev->phydev && status)
+               status->link = dev->phydev->link;
+
+       return 0;
+}
+
+/* Perform a voluntary PHY software reset, since the EPHY is very finicky about
+ * not doing it and will start corrupting packets
+ */
 void bcmgenet_mii_reset(struct net_device *dev)
 {
        struct bcmgenet_priv *priv = netdev_priv(dev);
 
+       if (GENET_IS_V4(priv))
+               return;
+
        if (priv->phydev) {
                phy_init_hw(priv->phydev);
                phy_start_aneg(priv->phydev);
@@ -221,9 +242,13 @@ static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv)
        reg = bcmgenet_sys_readl(priv, SYS_PORT_CTRL);
        reg |= LED_ACT_SOURCE_MAC;
        bcmgenet_sys_writel(priv, reg, SYS_PORT_CTRL);
+
+       if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET)
+               fixed_phy_set_link_update(priv->phydev,
+                                         bcmgenet_fixed_phy_link_update);
 }
 
-int bcmgenet_mii_config(struct net_device *dev, bool init)
+int bcmgenet_mii_config(struct net_device *dev)
 {
        struct bcmgenet_priv *priv = netdev_priv(dev);
        struct phy_device *phydev = priv->phydev;
@@ -233,10 +258,10 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
        u32 port_ctrl;
        u32 reg;
 
-       priv->ext_phy = !phy_is_internal(priv->phydev) &&
+       priv->ext_phy = !priv->internal_phy &&
                        (priv->phy_interface != PHY_INTERFACE_MODE_MOCA);
 
-       if (phy_is_internal(priv->phydev))
+       if (priv->internal_phy)
                priv->phy_interface = PHY_INTERFACE_MODE_NA;
 
        switch (priv->phy_interface) {
@@ -254,7 +279,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
 
                bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL);
 
-               if (phy_is_internal(priv->phydev)) {
+               if (priv->internal_phy) {
                        phy_name = "internal PHY";
                        bcmgenet_internal_phy_setup(dev);
                } else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
@@ -316,13 +341,12 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
                bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
        }
 
-       if (init)
-               dev_info(kdev, "configuring instance for %s\n", phy_name);
+       dev_info_once(kdev, "configuring instance for %s\n", phy_name);
 
        return 0;
 }
 
-static int bcmgenet_mii_probe(struct net_device *dev)
+int bcmgenet_mii_probe(struct net_device *dev)
 {
        struct bcmgenet_priv *priv = netdev_priv(dev);
        struct device_node *dn = priv->pdev->dev.of_node;
@@ -340,22 +364,6 @@ static int bcmgenet_mii_probe(struct net_device *dev)
        priv->old_pause = -1;
 
        if (dn) {
-               if (priv->phydev) {
-                       pr_info("PHY already attached\n");
-                       return 0;
-               }
-
-               /* In the case of a fixed PHY, the DT node associated
-                * to the PHY is the Ethernet MAC DT node.
-                */
-               if (!priv->phy_dn && of_phy_is_fixed_link(dn)) {
-                       ret = of_phy_register_fixed_link(dn);
-                       if (ret)
-                               return ret;
-
-                       priv->phy_dn = of_node_get(dn);
-               }
-
                phydev = of_phy_connect(dev, priv->phy_dn, bcmgenet_mii_setup,
                                        phy_flags, priv->phy_interface);
                if (!phydev) {
@@ -381,7 +389,7 @@ static int bcmgenet_mii_probe(struct net_device *dev)
         * PHY speed which is needed for bcmgenet_mii_config() to configure
         * things appropriately.
         */
-       ret = bcmgenet_mii_config(dev, true);
+       ret = bcmgenet_mii_config(dev);
        if (ret) {
                phy_disconnect(priv->phydev);
                return ret;
@@ -392,13 +400,56 @@ static int bcmgenet_mii_probe(struct net_device *dev)
        /* The internal PHY has its link interrupts routed to the
         * Ethernet MAC ISRs
         */
-       if (phy_is_internal(priv->phydev))
+       if (priv->internal_phy)
                priv->mii_bus->irq[phydev->addr] = PHY_IGNORE_INTERRUPT;
        else
                priv->mii_bus->irq[phydev->addr] = PHY_POLL;
 
-       pr_info("attached PHY at address %d [%s]\n",
-               phydev->addr, phydev->drv->name);
+       return 0;
+}
+
+/* Workaround for integrated BCM7xxx Gigabit PHYs which have a problem with
+ * their internal MDIO management controller making them fail to successfully
+ * be read from or written to for the first transaction.  We insert a dummy
+ * BMSR read here to make sure that phy_get_device() and get_phy_id() can
+ * correctly read the PHY MII_PHYSID1/2 registers and successfully register a
+ * PHY device for this peripheral.
+ *
+ * Once the PHY driver is registered, we can workaround subsequent reads from
+ * there (e.g: during system-wide power management).
+ *
+ * bus->reset is invoked before mdiobus_scan during mdiobus_register and is
+ * therefore the right location to stick that workaround. Since we do not want
+ * to read from non-existing PHYs, we either use bus->phy_mask or do a manual
+ * Device Tree scan to limit the search area.
+ */
+static int bcmgenet_mii_bus_reset(struct mii_bus *bus)
+{
+       struct net_device *dev = bus->priv;
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       struct device_node *np = priv->mdio_dn;
+       struct device_node *child = NULL;
+       u32 read_mask = 0;
+       int addr = 0;
+
+       if (!np) {
+               read_mask = 1 << priv->phy_addr;
+       } else {
+               for_each_available_child_of_node(np, child) {
+                       addr = of_mdio_parse_addr(&dev->dev, child);
+                       if (addr < 0)
+                               continue;
+
+                       read_mask |= 1 << addr;
+               }
+       }
+
+       for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
+               if (read_mask & 1 << addr) {
+                       dev_dbg(&dev->dev, "Workaround for PHY @ %d\n", addr);
+                       mdiobus_read(bus, addr, MII_BMSR);
+               }
+       }
 
        return 0;
 }
@@ -422,6 +473,7 @@ static int bcmgenet_mii_alloc(struct bcmgenet_priv *priv)
        bus->parent = &priv->pdev->dev;
        bus->read = bcmgenet_mii_read;
        bus->write = bcmgenet_mii_write;
+       bus->reset = bcmgenet_mii_bus_reset;
        snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d",
                 priv->pdev->name, priv->pdev->id);
 
@@ -438,22 +490,24 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv)
 {
        struct device_node *dn = priv->pdev->dev.of_node;
        struct device *kdev = &priv->pdev->dev;
-       struct device_node *mdio_dn;
+       const char *phy_mode_str = NULL;
+       struct phy_device *phydev = NULL;
        char *compat;
+       int phy_mode;
        int ret;
 
        compat = kasprintf(GFP_KERNEL, "brcm,genet-mdio-v%d", priv->version);
        if (!compat)
                return -ENOMEM;
 
-       mdio_dn = of_find_compatible_node(dn, NULL, compat);
+       priv->mdio_dn = of_find_compatible_node(dn, NULL, compat);
        kfree(compat);
-       if (!mdio_dn) {
+       if (!priv->mdio_dn) {
                dev_err(kdev, "unable to find MDIO bus node\n");
                return -ENODEV;
        }
 
-       ret = of_mdiobus_register(priv->mii_bus, mdio_dn);
+       ret = of_mdiobus_register(priv->mii_bus, priv->mdio_dn);
        if (ret) {
                dev_err(kdev, "failed to register MDIO bus\n");
                return ret;
@@ -462,17 +516,43 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv)
        /* Fetch the PHY phandle */
        priv->phy_dn = of_parse_phandle(dn, "phy-handle", 0);
 
+       /* In the case of a fixed PHY, the DT node associated
+        * to the PHY is the Ethernet MAC DT node.
+        */
+       if (!priv->phy_dn && of_phy_is_fixed_link(dn)) {
+               ret = of_phy_register_fixed_link(dn);
+               if (ret)
+                       return ret;
+
+               priv->phy_dn = of_node_get(dn);
+       }
+
        /* Get the link mode */
-       priv->phy_interface = of_get_phy_mode(dn);
+       phy_mode = of_get_phy_mode(dn);
+       priv->phy_interface = phy_mode;
 
-       return 0;
-}
+       /* We need to specifically look up whether this PHY interface is internal
+        * or not *before* we even try to probe the PHY driver over MDIO as we
+        * may have shut down the internal PHY for power saving purposes.
+        */
+       if (phy_mode < 0) {
+               ret = of_property_read_string(dn, "phy-mode", &phy_mode_str);
+               if (ret < 0) {
+                       dev_err(kdev, "invalid PHY mode property\n");
+                       return ret;
+               }
 
-static int bcmgenet_fixed_phy_link_update(struct net_device *dev,
-                                         struct fixed_phy_status *status)
-{
-       if (dev && dev->phydev && status)
-               status->link = dev->phydev->link;
+               priv->phy_interface = PHY_INTERFACE_MODE_NA;
+               if (!strcasecmp(phy_mode_str, "internal"))
+                       priv->internal_phy = true;
+       }
+
+       /* Make sure we initialize MoCA PHYs with a link down */
+       if (phy_mode == PHY_INTERFACE_MODE_MOCA) {
+               phydev = of_phy_find_device(dn);
+               if (phydev)
+                       phydev->link = 0;
+       }
 
        return 0;
 }
@@ -523,18 +603,15 @@ static int bcmgenet_mii_pd_init(struct bcmgenet_priv *priv)
                        .asym_pause = 0,
                };
 
-               phydev = fixed_phy_register(PHY_POLL, &fphy_status, NULL);
+               phydev = fixed_phy_register(PHY_POLL, &fphy_status, -1, NULL);
                if (!phydev || IS_ERR(phydev)) {
                        dev_err(kdev, "failed to register fixed PHY device\n");
                        return -ENODEV;
                }
 
-               if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET) {
-                       ret = fixed_phy_set_link_update(
-                               phydev, bcmgenet_fixed_phy_link_update);
-                       if (!ret)
-                               phydev->link = 0;
-               }
+               /* Make sure we initialize MoCA PHYs with a link down */
+               phydev->link = 0;
+
        }
 
        priv->phydev = phydev;
@@ -563,10 +640,6 @@ int bcmgenet_mii_init(struct net_device *dev)
                return ret;
 
        ret = bcmgenet_mii_bus_init(priv);
-       if (ret)
-               goto out_free;
-
-       ret = bcmgenet_mii_probe(dev);
        if (ret)
                goto out;
 
@@ -575,7 +648,6 @@ int bcmgenet_mii_init(struct net_device *dev)
 out:
        of_node_put(priv->phy_dn);
        mdiobus_unregister(priv->mii_bus);
-out_free:
        kfree(priv->mii_bus->irq);
        mdiobus_free(priv->mii_bus);
        return ret;