aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ibm_emac
diff options
context:
space:
mode:
authorEugene Surovegin <ebs@ebshome.net>2007-05-16 14:59:48 -0400
committerJeff Garzik <jeff@garzik.org>2007-05-17 20:43:14 -0400
commit5bb96e9f2434b49a5b8f135f2a384974aa73db51 (patch)
treed7dd01739b93f709114add365e558550f48817e6 /drivers/net/ibm_emac
parent0ec6d95053885055a50d973b3a3906905a78a8bf (diff)
ibm_emac: improved PHY support
Original patch is from Jeff Haran <jharan@brocade.com> with my minor style fixes. His comments follow: The first problem was in the function that configures the PHY for autonegotiation, genmii_setup_aneg(). The original code does a read/modify/write of the autonegotiation advertizement register (reg 4), followed by a read/modify/write of the control register (reg 0). While the original code follows the proper procedure as per reading the IEEE specs, what I found is that on at least one PHY model (National DP83843) the read of the control register comes back with the soft reset bit set (bit 15). Because of the read/modify/write operation, this causes the write to write a 1 back to the reset bit, which initiates a software reset of the PHY. This software reset causes the PHY to return to its power up state which advertizes all modes of operation, thus negating the write to the autoneg advertizement register. The modification is to spin reading the control register until the soft reset bit is clear before doing the modify/write. The second problem was in the function that configures the PHY for forced operation, genmii_setup_forced(). The original code initiates a software reset operation via a write of a 1 to bit 15 of the control register (reg 0), but then proceeds to do a second write to that same register without waiting until that reset bit is cleared by the PHY itself (which according to the IEEE specs indicates that the PHY reset is complete). This is a violation of how one is supposed to use this software reset feature of these PHYs and I believe was the cause of mysterious, difficult to reproduce link failures that we've observed on some of our systems that use this driver. The fix is to modify the function so that it spins waiting for the reset bit to clear after doing the soft reset and before doing the subsequent write. Signed-off-by: Jeff Haran <jharan@brocade.com> CC: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Eugene Surovegin <ebs@ebshome.net> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/ibm_emac')
-rw-r--r--drivers/net/ibm_emac/ibm_emac_phy.c60
1 files changed, 45 insertions, 15 deletions
diff --git a/drivers/net/ibm_emac/ibm_emac_phy.c b/drivers/net/ibm_emac/ibm_emac_phy.c
index 9074f76ee2bf..e57862b34cae 100644
--- a/drivers/net/ibm_emac/ibm_emac_phy.c
+++ b/drivers/net/ibm_emac/ibm_emac_phy.c
@@ -22,6 +22,7 @@
22 22
23#include <asm/ocp.h> 23#include <asm/ocp.h>
24 24
25#include "ibm_emac_core.h"
25#include "ibm_emac_phy.h" 26#include "ibm_emac_phy.h"
26 27
27static inline int phy_read(struct mii_phy *phy, int reg) 28static inline int phy_read(struct mii_phy *phy, int reg)
@@ -34,11 +35,39 @@ static inline void phy_write(struct mii_phy *phy, int reg, int val)
34 phy->mdio_write(phy->dev, phy->address, reg, val); 35 phy->mdio_write(phy->dev, phy->address, reg, val);
35} 36}
36 37
37int mii_reset_phy(struct mii_phy *phy) 38/*
39 * polls MII_BMCR until BMCR_RESET bit clears or operation times out.
40 *
41 * returns:
42 * >= 0 => success, value in BMCR returned to caller
43 * -EBUSY => failure, RESET bit never cleared
44 * otherwise => failure, lower level PHY read failed
45 */
46static int mii_spin_reset_complete(struct mii_phy *phy)
38{ 47{
39 int val; 48 int val;
40 int limit = 10000; 49 int limit = 10000;
41 50
51 while (limit--) {
52 val = phy_read(phy, MII_BMCR);
53 if (val >= 0 && !(val & BMCR_RESET))
54 return val; /* success */
55 udelay(10);
56 }
57 if (val & BMCR_RESET)
58 val = -EBUSY;
59
60 if (net_ratelimit())
61 printk(KERN_ERR "emac%d: PHY reset timeout (%d)\n",
62 ((struct ocp_enet_private *)phy->dev->priv)->def->index,
63 val);
64 return val;
65}
66
67int mii_reset_phy(struct mii_phy *phy)
68{
69 int val;
70
42 val = phy_read(phy, MII_BMCR); 71 val = phy_read(phy, MII_BMCR);
43 val &= ~BMCR_ISOLATE; 72 val &= ~BMCR_ISOLATE;
44 val |= BMCR_RESET; 73 val |= BMCR_RESET;
@@ -46,16 +75,11 @@ int mii_reset_phy(struct mii_phy *phy)
46 75
47 udelay(300); 76 udelay(300);
48 77
49 while (limit--) { 78 val = mii_spin_reset_complete(phy);
50 val = phy_read(phy, MII_BMCR); 79 if (val >= 0 && (val & BMCR_ISOLATE))
51 if (val >= 0 && (val & BMCR_RESET) == 0)
52 break;
53 udelay(10);
54 }
55 if ((val & BMCR_ISOLATE) && limit > 0)
56 phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE); 80 phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE);
57 81
58 return limit <= 0; 82 return val < 0;
59} 83}
60 84
61static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) 85static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
@@ -102,8 +126,14 @@ static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
102 } 126 }
103 127
104 /* Start/Restart aneg */ 128 /* Start/Restart aneg */
105 ctl = phy_read(phy, MII_BMCR); 129 /* on some PHYs (e.g. National DP83843) a write to MII_ADVERTISE
106 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); 130 * causes BMCR_RESET to be set on the next read of MII_BMCR, which
131 * if not checked for causes the PHY to be reset below */
132 ctl = mii_spin_reset_complete(phy);
133 if (ctl < 0)
134 return ctl;
135
136 ctl |= BMCR_ANENABLE | BMCR_ANRESTART;
107 phy_write(phy, MII_BMCR, ctl); 137 phy_write(phy, MII_BMCR, ctl);
108 138
109 return 0; 139 return 0;
@@ -118,13 +148,13 @@ static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
118 phy->duplex = fd; 148 phy->duplex = fd;
119 phy->pause = phy->asym_pause = 0; 149 phy->pause = phy->asym_pause = 0;
120 150
151 /* First reset the PHY */
152 mii_reset_phy(phy);
153
121 ctl = phy_read(phy, MII_BMCR); 154 ctl = phy_read(phy, MII_BMCR);
122 if (ctl < 0) 155 if (ctl < 0)
123 return ctl; 156 return ctl;
124 ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE); 157 ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE | BMCR_SPEED1000);
125
126 /* First reset the PHY */
127 phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
128 158
129 /* Select speed & duplex */ 159 /* Select speed & duplex */
130 switch (speed) { 160 switch (speed) {