aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/phy
diff options
context:
space:
mode:
authorAndy Fleming <afleming@freescale.com>2006-10-16 17:19:17 -0400
committerJeff Garzik <jeff@garzik.org>2006-12-02 00:12:02 -0500
commit6b655529c3d817ed1b69cf2dd29e2c3ce5148a2b (patch)
tree0217c984a2fe169634931a52b0ebde2d80ecf1ca /drivers/net/phy
parent2109f89f3483ff5a05899385ee3fb04d779e9cce (diff)
[PATCH] Fixed a number of bugs in the PHY Layer
* genphy_update_link is now exported * Added a fix from ncase@xes-inc.com which changes forcing so it only updates the link. Otherwise, it never tries the lower values, since it is always overwriting the speed/duplex values with the current ones, rather than the intended ones. * Fixed a bug where bringing up a PHY with no link caused it to timeout, and enter forcing mode. Once in forcing mode, plugging in the link didn't autonegotiate. Now the AN state detects the lack of link, and enters the NO_LINK state. AN only times out if the link is up and AN fails * Cleaned up the PHY_AN case, reducing one level of indentation for the timeout code. Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/phy')
-rw-r--r--drivers/net/phy/phy.c81
-rw-r--r--drivers/net/phy/phy_device.c1
2 files changed, 40 insertions, 42 deletions
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 95f0419ba21e..88237bdb5255 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -713,60 +713,57 @@ static void phy_timer(unsigned long data)
713 713
714 break; 714 break;
715 case PHY_AN: 715 case PHY_AN:
716 err = phy_read_status(phydev);
717
718 if (err < 0)
719 break;
720
721 /* If the link is down, give up on
722 * negotiation for now */
723 if (!phydev->link) {
724 phydev->state = PHY_NOLINK;
725 netif_carrier_off(phydev->attached_dev);
726 phydev->adjust_link(phydev->attached_dev);
727 break;
728 }
729
716 /* Check if negotiation is done. Break 730 /* Check if negotiation is done. Break
717 * if there's an error */ 731 * if there's an error */
718 err = phy_aneg_done(phydev); 732 err = phy_aneg_done(phydev);
719 if (err < 0) 733 if (err < 0)
720 break; 734 break;
721 735
722 /* If auto-negotiation is done, we change to 736 /* If AN is done, we're running */
723 * either RUNNING, or NOLINK */
724 if (err > 0) { 737 if (err > 0) {
725 err = phy_read_status(phydev); 738 phydev->state = PHY_RUNNING;
739 netif_carrier_on(phydev->attached_dev);
740 phydev->adjust_link(phydev->attached_dev);
741
742 } else if (0 == phydev->link_timeout--) {
743 int idx;
726 744
727 if (err) 745 needs_aneg = 1;
746 /* If we have the magic_aneg bit,
747 * we try again */
748 if (phydev->drv->flags & PHY_HAS_MAGICANEG)
728 break; 749 break;
729 750
730 if (phydev->link) { 751 /* The timer expired, and we still
731 phydev->state = PHY_RUNNING; 752 * don't have a setting, so we try
732 netif_carrier_on(phydev->attached_dev); 753 * forcing it until we find one that
733 } else { 754 * works, starting from the fastest speed,
734 phydev->state = PHY_NOLINK; 755 * and working our way down */
735 netif_carrier_off(phydev->attached_dev); 756 idx = phy_find_valid(0, phydev->supported);
736 }
737 757
738 phydev->adjust_link(phydev->attached_dev); 758 phydev->speed = settings[idx].speed;
759 phydev->duplex = settings[idx].duplex;
739 760
740 } else if (0 == phydev->link_timeout--) { 761 phydev->autoneg = AUTONEG_DISABLE;
741 /* The counter expired, so either we
742 * switch to forced mode, or the
743 * magic_aneg bit exists, and we try aneg
744 * again */
745 if (!(phydev->drv->flags & PHY_HAS_MAGICANEG)) {
746 int idx;
747
748 /* We'll start from the
749 * fastest speed, and work
750 * our way down */
751 idx = phy_find_valid(0,
752 phydev->supported);
753
754 phydev->speed = settings[idx].speed;
755 phydev->duplex = settings[idx].duplex;
756
757 phydev->autoneg = AUTONEG_DISABLE;
758 phydev->state = PHY_FORCING;
759 phydev->link_timeout =
760 PHY_FORCE_TIMEOUT;
761
762 pr_info("Trying %d/%s\n",
763 phydev->speed,
764 DUPLEX_FULL ==
765 phydev->duplex ?
766 "FULL" : "HALF");
767 }
768 762
769 needs_aneg = 1; 763 pr_info("Trying %d/%s\n", phydev->speed,
764 DUPLEX_FULL ==
765 phydev->duplex ?
766 "FULL" : "HALF");
770 } 767 }
771 break; 768 break;
772 case PHY_NOLINK: 769 case PHY_NOLINK:
@@ -782,7 +779,7 @@ static void phy_timer(unsigned long data)
782 } 779 }
783 break; 780 break;
784 case PHY_FORCING: 781 case PHY_FORCING:
785 err = phy_read_status(phydev); 782 err = genphy_update_link(phydev);
786 783
787 if (err) 784 if (err)
788 break; 785 break;
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 3bbd5e70c209..2a08b2b62c4c 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -427,6 +427,7 @@ int genphy_update_link(struct phy_device *phydev)
427 427
428 return 0; 428 return 0;
429} 429}
430EXPORT_SYMBOL(genphy_update_link);
430 431
431/* genphy_read_status 432/* genphy_read_status
432 * 433 *