]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/ethernet/ibm/emac/core.c
Merge branch 'ufs-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[karo-tx-linux.git] / drivers / net / ethernet / ibm / emac / core.c
index 508923f39ccfe0cbc39ed23305af46860eef32c9..259e69a52ec52acde37849b9858c9953029679af 100644 (file)
@@ -343,6 +343,7 @@ static int emac_reset(struct emac_instance *dev)
 {
        struct emac_regs __iomem *p = dev->emacp;
        int n = 20;
+       bool __maybe_unused try_internal_clock = false;
 
        DBG(dev, "reset" NL);
 
@@ -355,6 +356,7 @@ static int emac_reset(struct emac_instance *dev)
        }
 
 #ifdef CONFIG_PPC_DCR_NATIVE
+do_retry:
        /*
         * PPC460EX/GT Embedded Processor Advanced User's Manual
         * section 28.10.1 Mode Register 0 (EMACx_MR0) states:
@@ -362,10 +364,19 @@ static int emac_reset(struct emac_instance *dev)
         * of the EMAC. If none is present, select the internal clock
         * (SDR0_ETH_CFG[EMACx_PHY_CLK] = 1).
         * After a soft reset, select the external clock.
+        *
+        * The AR8035-A PHY Meraki MR24 does not provide a TX Clk if the
+        * ethernet cable is not attached. This causes the reset to timeout
+        * and the PHY detection code in emac_init_phy() is unable to
+        * communicate and detect the AR8035-A PHY. As a result, the emac
+        * driver bails out early and the user has no ethernet.
+        * In order to stay compatible with existing configurations, the
+        * driver will temporarily switch to the internal clock, after
+        * the first reset fails.
         */
        if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) {
-               if (dev->phy_address == 0xffffffff &&
-                   dev->phy_map == 0xffffffff) {
+               if (try_internal_clock || (dev->phy_address == 0xffffffff &&
+                                          dev->phy_map == 0xffffffff)) {
                        /* No PHY: select internal loop clock before reset */
                        dcri_clrset(SDR0, SDR0_ETH_CFG,
                                    0, SDR0_ETH_CFG_ECS << dev->cell_index);
@@ -383,8 +394,15 @@ static int emac_reset(struct emac_instance *dev)
 
 #ifdef CONFIG_PPC_DCR_NATIVE
        if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) {
-               if (dev->phy_address == 0xffffffff &&
-                   dev->phy_map == 0xffffffff) {
+               if (!n && !try_internal_clock) {
+                       /* first attempt has timed out. */
+                       n = 20;
+                       try_internal_clock = true;
+                       goto do_retry;
+               }
+
+               if (try_internal_clock || (dev->phy_address == 0xffffffff &&
+                                          dev->phy_map == 0xffffffff)) {
                        /* No PHY: restore external clock source after reset */
                        dcri_clrset(SDR0, SDR0_ETH_CFG,
                                    SDR0_ETH_CFG_ECS << dev->cell_index, 0);
@@ -2460,20 +2478,24 @@ static int emac_mii_bus_reset(struct mii_bus *bus)
        return emac_reset(dev);
 }
 
+static int emac_mdio_phy_start_aneg(struct mii_phy *phy,
+                                   struct phy_device *phy_dev)
+{
+       phy_dev->autoneg = phy->autoneg;
+       phy_dev->speed = phy->speed;
+       phy_dev->duplex = phy->duplex;
+       phy_dev->advertising = phy->advertising;
+       return phy_start_aneg(phy_dev);
+}
+
 static int emac_mdio_setup_aneg(struct mii_phy *phy, u32 advertise)
 {
        struct net_device *ndev = phy->dev;
        struct emac_instance *dev = netdev_priv(ndev);
 
-       dev->phy.autoneg = AUTONEG_ENABLE;
-       dev->phy.speed = SPEED_1000;
-       dev->phy.duplex = DUPLEX_FULL;
-       dev->phy.advertising = advertise;
        phy->autoneg = AUTONEG_ENABLE;
-       phy->speed = dev->phy.speed;
-       phy->duplex = dev->phy.duplex;
        phy->advertising = advertise;
-       return phy_start_aneg(dev->phy_dev);
+       return emac_mdio_phy_start_aneg(phy, dev->phy_dev);
 }
 
 static int emac_mdio_setup_forced(struct mii_phy *phy, int speed, int fd)
@@ -2481,13 +2503,10 @@ static int emac_mdio_setup_forced(struct mii_phy *phy, int speed, int fd)
        struct net_device *ndev = phy->dev;
        struct emac_instance *dev = netdev_priv(ndev);
 
-       dev->phy.autoneg =  AUTONEG_DISABLE;
-       dev->phy.speed = speed;
-       dev->phy.duplex = fd;
        phy->autoneg = AUTONEG_DISABLE;
        phy->speed = speed;
        phy->duplex = fd;
-       return phy_start_aneg(dev->phy_dev);
+       return emac_mdio_phy_start_aneg(phy, dev->phy_dev);
 }
 
 static int emac_mdio_poll_link(struct mii_phy *phy)
@@ -2509,16 +2528,17 @@ static int emac_mdio_read_link(struct mii_phy *phy)
 {
        struct net_device *ndev = phy->dev;
        struct emac_instance *dev = netdev_priv(ndev);
+       struct phy_device *phy_dev = dev->phy_dev;
        int res;
 
-       res = phy_read_status(dev->phy_dev);
+       res = phy_read_status(phy_dev);
        if (res)
                return res;
 
-       dev->phy.speed = phy->speed;
-       dev->phy.duplex = phy->duplex;
-       dev->phy.pause = phy->pause;
-       dev->phy.asym_pause = phy->asym_pause;
+       phy->speed = phy_dev->speed;
+       phy->duplex = phy_dev->duplex;
+       phy->pause = phy_dev->pause;
+       phy->asym_pause = phy_dev->asym_pause;
        return 0;
 }
 
@@ -2528,13 +2548,6 @@ static int emac_mdio_init_phy(struct mii_phy *phy)
        struct emac_instance *dev = netdev_priv(ndev);
 
        phy_start(dev->phy_dev);
-       dev->phy.autoneg = phy->autoneg;
-       dev->phy.speed = phy->speed;
-       dev->phy.duplex = phy->duplex;
-       dev->phy.advertising = phy->advertising;
-       dev->phy.pause = phy->pause;
-       dev->phy.asym_pause = phy->asym_pause;
-
        return phy_init_hw(dev->phy_dev);
 }