]> git.itanic.dy.fi Git - linux-stable/commitdiff
net: sunhme: Just restart autonegotiation if we can't bring the link up
authorSean Anderson <seanga2@gmail.com>
Fri, 24 Mar 2023 17:51:28 +0000 (13:51 -0400)
committerDavid S. Miller <davem@davemloft.net>
Mon, 27 Mar 2023 07:41:56 +0000 (08:41 +0100)
If we've tried regular autonegotiation and forcing the link mode, just
restart autonegotiation instead of reinitializing the whole NIC.

Signed-off-by: Sean Anderson <seanga2@gmail.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/sun/sunhme.c

index 7cf8210ebbec37602be91dcf7bc98e92b8394ed7..e52f2d9305bcf78239b83a095b95362fae866afb 100644 (file)
@@ -589,8 +589,6 @@ static int set_happy_link_modes(struct happy_meal *hp, void __iomem *tregs)
        return 1;
 }
 
-static int happy_meal_init(struct happy_meal *hp);
-
 static int is_lucent_phy(struct happy_meal *hp)
 {
        void __iomem *tregs = hp->tcvregs;
@@ -606,6 +604,124 @@ static int is_lucent_phy(struct happy_meal *hp)
        return ret;
 }
 
+/* hp->happy_lock must be held */
+static void
+happy_meal_begin_auto_negotiation(struct happy_meal *hp,
+                                 void __iomem *tregs,
+                                 const struct ethtool_link_ksettings *ep)
+{
+       int timeout;
+
+       /* Read all of the registers we are interested in now. */
+       hp->sw_bmsr      = happy_meal_tcvr_read(hp, tregs, MII_BMSR);
+       hp->sw_bmcr      = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
+       hp->sw_physid1   = happy_meal_tcvr_read(hp, tregs, MII_PHYSID1);
+       hp->sw_physid2   = happy_meal_tcvr_read(hp, tregs, MII_PHYSID2);
+
+       /* XXX Check BMSR_ANEGCAPABLE, should not be necessary though. */
+
+       hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, MII_ADVERTISE);
+       if (!ep || ep->base.autoneg == AUTONEG_ENABLE) {
+               /* Advertise everything we can support. */
+               if (hp->sw_bmsr & BMSR_10HALF)
+                       hp->sw_advertise |= (ADVERTISE_10HALF);
+               else
+                       hp->sw_advertise &= ~(ADVERTISE_10HALF);
+
+               if (hp->sw_bmsr & BMSR_10FULL)
+                       hp->sw_advertise |= (ADVERTISE_10FULL);
+               else
+                       hp->sw_advertise &= ~(ADVERTISE_10FULL);
+               if (hp->sw_bmsr & BMSR_100HALF)
+                       hp->sw_advertise |= (ADVERTISE_100HALF);
+               else
+                       hp->sw_advertise &= ~(ADVERTISE_100HALF);
+               if (hp->sw_bmsr & BMSR_100FULL)
+                       hp->sw_advertise |= (ADVERTISE_100FULL);
+               else
+                       hp->sw_advertise &= ~(ADVERTISE_100FULL);
+               happy_meal_tcvr_write(hp, tregs, MII_ADVERTISE, hp->sw_advertise);
+
+               /* XXX Currently no Happy Meal cards I know off support 100BaseT4,
+                * XXX and this is because the DP83840 does not support it, changes
+                * XXX would need to be made to the tx/rx logic in the driver as well
+                * XXX so I completely skip checking for it in the BMSR for now.
+                */
+
+               ASD("Advertising [ %s%s%s%s]\n",
+                   hp->sw_advertise & ADVERTISE_10HALF ? "10H " : "",
+                   hp->sw_advertise & ADVERTISE_10FULL ? "10F " : "",
+                   hp->sw_advertise & ADVERTISE_100HALF ? "100H " : "",
+                   hp->sw_advertise & ADVERTISE_100FULL ? "100F " : "");
+
+               /* Enable Auto-Negotiation, this is usually on already... */
+               hp->sw_bmcr |= BMCR_ANENABLE;
+               happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
+
+               /* Restart it to make sure it is going. */
+               hp->sw_bmcr |= BMCR_ANRESTART;
+               happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
+
+               /* BMCR_ANRESTART self clears when the process has begun. */
+
+               timeout = 64;  /* More than enough. */
+               while (--timeout) {
+                       hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
+                       if (!(hp->sw_bmcr & BMCR_ANRESTART))
+                               break; /* got it. */
+                       udelay(10);
+               }
+               if (!timeout) {
+                       netdev_err(hp->dev,
+                                  "Happy Meal would not start auto negotiation BMCR=0x%04x\n",
+                                  hp->sw_bmcr);
+                       netdev_notice(hp->dev,
+                                     "Performing force link detection.\n");
+                       goto force_link;
+               } else {
+                       hp->timer_state = arbwait;
+               }
+       } else {
+force_link:
+               /* Force the link up, trying first a particular mode.
+                * Either we are here at the request of ethtool or
+                * because the Happy Meal would not start to autoneg.
+                */
+
+               /* Disable auto-negotiation in BMCR, enable the duplex and
+                * speed setting, init the timer state machine, and fire it off.
+                */
+               if (!ep || ep->base.autoneg == AUTONEG_ENABLE) {
+                       hp->sw_bmcr = BMCR_SPEED100;
+               } else {
+                       if (ep->base.speed == SPEED_100)
+                               hp->sw_bmcr = BMCR_SPEED100;
+                       else
+                               hp->sw_bmcr = 0;
+                       if (ep->base.duplex == DUPLEX_FULL)
+                               hp->sw_bmcr |= BMCR_FULLDPLX;
+               }
+               happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
+
+               if (!is_lucent_phy(hp)) {
+                       /* OK, seems we need do disable the transceiver for the first
+                        * tick to make sure we get an accurate link state at the
+                        * second tick.
+                        */
+                       hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,
+                                                              DP83840_CSCONFIG);
+                       hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
+                       happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG,
+                                             hp->sw_csconfig);
+               }
+               hp->timer_state = ltrywait;
+       }
+
+       hp->timer_ticks = 0;
+       hp->happy_timer.expires = jiffies + (12 * HZ)/10;  /* 1.2 sec. */
+       add_timer(&hp->happy_timer);
+}
+
 static void happy_meal_timer(struct timer_list *t)
 {
        struct happy_meal *hp = from_timer(hp, t, happy_timer);
@@ -743,12 +859,7 @@ static void happy_meal_timer(struct timer_list *t)
                                        netdev_notice(hp->dev,
                                                      "Link down, cable problem?\n");
 
-                                       ret = happy_meal_init(hp);
-                                       if (ret) {
-                                               /* ho hum... */
-                                               netdev_err(hp->dev,
-                                                          "Error, cannot re-init the Happy Meal.\n");
-                                       }
+                                       happy_meal_begin_auto_negotiation(hp, tregs, NULL);
                                        goto out;
                                }
                                if (!is_lucent_phy(hp)) {
@@ -1201,124 +1312,6 @@ static void happy_meal_init_rings(struct happy_meal *hp)
        HMD("done\n");
 }
 
-/* hp->happy_lock must be held */
-static void
-happy_meal_begin_auto_negotiation(struct happy_meal *hp,
-                                 void __iomem *tregs,
-                                 const struct ethtool_link_ksettings *ep)
-{
-       int timeout;
-
-       /* Read all of the registers we are interested in now. */
-       hp->sw_bmsr      = happy_meal_tcvr_read(hp, tregs, MII_BMSR);
-       hp->sw_bmcr      = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
-       hp->sw_physid1   = happy_meal_tcvr_read(hp, tregs, MII_PHYSID1);
-       hp->sw_physid2   = happy_meal_tcvr_read(hp, tregs, MII_PHYSID2);
-
-       /* XXX Check BMSR_ANEGCAPABLE, should not be necessary though. */
-
-       hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, MII_ADVERTISE);
-       if (!ep || ep->base.autoneg == AUTONEG_ENABLE) {
-               /* Advertise everything we can support. */
-               if (hp->sw_bmsr & BMSR_10HALF)
-                       hp->sw_advertise |= (ADVERTISE_10HALF);
-               else
-                       hp->sw_advertise &= ~(ADVERTISE_10HALF);
-
-               if (hp->sw_bmsr & BMSR_10FULL)
-                       hp->sw_advertise |= (ADVERTISE_10FULL);
-               else
-                       hp->sw_advertise &= ~(ADVERTISE_10FULL);
-               if (hp->sw_bmsr & BMSR_100HALF)
-                       hp->sw_advertise |= (ADVERTISE_100HALF);
-               else
-                       hp->sw_advertise &= ~(ADVERTISE_100HALF);
-               if (hp->sw_bmsr & BMSR_100FULL)
-                       hp->sw_advertise |= (ADVERTISE_100FULL);
-               else
-                       hp->sw_advertise &= ~(ADVERTISE_100FULL);
-               happy_meal_tcvr_write(hp, tregs, MII_ADVERTISE, hp->sw_advertise);
-
-               /* XXX Currently no Happy Meal cards I know off support 100BaseT4,
-                * XXX and this is because the DP83840 does not support it, changes
-                * XXX would need to be made to the tx/rx logic in the driver as well
-                * XXX so I completely skip checking for it in the BMSR for now.
-                */
-
-               ASD("Advertising [ %s%s%s%s]\n",
-                   hp->sw_advertise & ADVERTISE_10HALF ? "10H " : "",
-                   hp->sw_advertise & ADVERTISE_10FULL ? "10F " : "",
-                   hp->sw_advertise & ADVERTISE_100HALF ? "100H " : "",
-                   hp->sw_advertise & ADVERTISE_100FULL ? "100F " : "");
-
-               /* Enable Auto-Negotiation, this is usually on already... */
-               hp->sw_bmcr |= BMCR_ANENABLE;
-               happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
-
-               /* Restart it to make sure it is going. */
-               hp->sw_bmcr |= BMCR_ANRESTART;
-               happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
-
-               /* BMCR_ANRESTART self clears when the process has begun. */
-
-               timeout = 64;  /* More than enough. */
-               while (--timeout) {
-                       hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
-                       if (!(hp->sw_bmcr & BMCR_ANRESTART))
-                               break; /* got it. */
-                       udelay(10);
-               }
-               if (!timeout) {
-                       netdev_err(hp->dev,
-                                  "Happy Meal would not start auto negotiation BMCR=0x%04x\n",
-                                  hp->sw_bmcr);
-                       netdev_notice(hp->dev,
-                                     "Performing force link detection.\n");
-                       goto force_link;
-               } else {
-                       hp->timer_state = arbwait;
-               }
-       } else {
-force_link:
-               /* Force the link up, trying first a particular mode.
-                * Either we are here at the request of ethtool or
-                * because the Happy Meal would not start to autoneg.
-                */
-
-               /* Disable auto-negotiation in BMCR, enable the duplex and
-                * speed setting, init the timer state machine, and fire it off.
-                */
-               if (!ep || ep->base.autoneg == AUTONEG_ENABLE) {
-                       hp->sw_bmcr = BMCR_SPEED100;
-               } else {
-                       if (ep->base.speed == SPEED_100)
-                               hp->sw_bmcr = BMCR_SPEED100;
-                       else
-                               hp->sw_bmcr = 0;
-                       if (ep->base.duplex == DUPLEX_FULL)
-                               hp->sw_bmcr |= BMCR_FULLDPLX;
-               }
-               happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
-
-               if (!is_lucent_phy(hp)) {
-                       /* OK, seems we need do disable the transceiver for the first
-                        * tick to make sure we get an accurate link state at the
-                        * second tick.
-                        */
-                       hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,
-                                                              DP83840_CSCONFIG);
-                       hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
-                       happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG,
-                                             hp->sw_csconfig);
-               }
-               hp->timer_state = ltrywait;
-       }
-
-       hp->timer_ticks = 0;
-       hp->happy_timer.expires = jiffies + (12 * HZ)/10;  /* 1.2 sec. */
-       add_timer(&hp->happy_timer);
-}
-
 /* hp->happy_lock must be held */
 static int happy_meal_init(struct happy_meal *hp)
 {