aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDivy Le Ray <divy@chelsio.com>2008-10-08 20:39:31 -0400
committerDavid S. Miller <davem@davemloft.net>2008-10-08 20:39:31 -0400
commit9b1e36566c5fafbcc732c971acfcf8580332931a (patch)
tree2c779d712f07f0b097ad1a2041779597b7ca9bbc
parentf231e0a5a2d01da40515c24f1daa689fe8cfd8d7 (diff)
cxgb3: commnonize LASI phy code
Add generic code to manage interrupt driven PHYs. Do not reset the phy after link parameters update, the new values might get lost. Return early from link change notification when the link parameters remain unchanged. Signed-off-by: Divy Le Ray <divy@chelsio.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/cxgb3/ael1002.c46
-rw-r--r--drivers/net/cxgb3/common.h19
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c19
-rw-r--r--drivers/net/cxgb3/t3_hw.c41
4 files changed, 77 insertions, 48 deletions
diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c
index f4e046e32fc6..f6e575fa7468 100644
--- a/drivers/net/cxgb3/ael1002.c
+++ b/drivers/net/cxgb3/ael1002.c
@@ -39,9 +39,6 @@ enum {
39 AEL1002_PWR_DOWN_LO = 0xc012, 39 AEL1002_PWR_DOWN_LO = 0xc012,
40 AEL1002_XFI_EQL = 0xc015, 40 AEL1002_XFI_EQL = 0xc015,
41 AEL1002_LB_EN = 0xc017, 41 AEL1002_LB_EN = 0xc017,
42
43 LASI_CTRL = 0x9002,
44 LASI_STAT = 0x9005
45}; 42};
46 43
47static void ael100x_txon(struct cphy *phy) 44static void ael100x_txon(struct cphy *phy)
@@ -134,33 +131,6 @@ static int ael1006_reset(struct cphy *phy, int wait)
134 return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait); 131 return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
135} 132}
136 133
137static int ael1006_intr_enable(struct cphy *phy)
138{
139 return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
140}
141
142static int ael1006_intr_disable(struct cphy *phy)
143{
144 return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
145}
146
147static int ael1006_intr_clear(struct cphy *phy)
148{
149 u32 val;
150
151 return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
152}
153
154static int ael1006_intr_handler(struct cphy *phy)
155{
156 unsigned int status;
157 int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
158
159 if (err)
160 return err;
161 return (status & 1) ? cphy_cause_link_change : 0;
162}
163
164static int ael1006_power_down(struct cphy *phy, int enable) 134static int ael1006_power_down(struct cphy *phy, int enable)
165{ 135{
166 return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, 136 return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
@@ -169,10 +139,10 @@ static int ael1006_power_down(struct cphy *phy, int enable)
169 139
170static struct cphy_ops ael1006_ops = { 140static struct cphy_ops ael1006_ops = {
171 .reset = ael1006_reset, 141 .reset = ael1006_reset,
172 .intr_enable = ael1006_intr_enable, 142 .intr_enable = t3_phy_lasi_intr_enable,
173 .intr_disable = ael1006_intr_disable, 143 .intr_disable = t3_phy_lasi_intr_disable,
174 .intr_clear = ael1006_intr_clear, 144 .intr_clear = t3_phy_lasi_intr_clear,
175 .intr_handler = ael1006_intr_handler, 145 .intr_handler = t3_phy_lasi_intr_handler,
176 .get_link_status = ael100x_get_link_status, 146 .get_link_status = ael100x_get_link_status,
177 .power_down = ael1006_power_down, 147 .power_down = ael1006_power_down,
178}; 148};
@@ -189,10 +159,10 @@ int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
189 159
190static struct cphy_ops qt2045_ops = { 160static struct cphy_ops qt2045_ops = {
191 .reset = ael1006_reset, 161 .reset = ael1006_reset,
192 .intr_enable = ael1006_intr_enable, 162 .intr_enable = t3_phy_lasi_intr_enable,
193 .intr_disable = ael1006_intr_disable, 163 .intr_disable = t3_phy_lasi_intr_disable,
194 .intr_clear = ael1006_intr_clear, 164 .intr_clear = t3_phy_lasi_intr_clear,
195 .intr_handler = ael1006_intr_handler, 165 .intr_handler = t3_phy_lasi_intr_handler,
196 .get_link_status = ael100x_get_link_status, 166 .get_link_status = ael100x_get_link_status,
197 .power_down = ael1006_power_down, 167 .power_down = ael1006_power_down,
198}; 168};
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index 75b5ee61f45c..d1b6b1e62f41 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -522,7 +522,20 @@ enum {
522 MDIO_DEV_PMA_PMD = 1, 522 MDIO_DEV_PMA_PMD = 1,
523 MDIO_DEV_WIS = 2, 523 MDIO_DEV_WIS = 2,
524 MDIO_DEV_PCS = 3, 524 MDIO_DEV_PCS = 3,
525 MDIO_DEV_XGXS = 4 525 MDIO_DEV_XGXS = 4,
526 MDIO_DEV_ANEG = 7,
527 MDIO_DEV_VEND1 = 30,
528 MDIO_DEV_VEND2 = 31
529};
530
531/* LASI control and status registers */
532enum {
533 RX_ALARM_CTRL = 0x9000,
534 TX_ALARM_CTRL = 0x9001,
535 LASI_CTRL = 0x9002,
536 RX_ALARM_STAT = 0x9003,
537 TX_ALARM_STAT = 0x9004,
538 LASI_STAT = 0x9005
526}; 539};
527 540
528/* PHY loopback direction */ 541/* PHY loopback direction */
@@ -665,6 +678,10 @@ int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear,
665int t3_phy_reset(struct cphy *phy, int mmd, int wait); 678int t3_phy_reset(struct cphy *phy, int mmd, int wait);
666int t3_phy_advertise(struct cphy *phy, unsigned int advert); 679int t3_phy_advertise(struct cphy *phy, unsigned int advert);
667int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex); 680int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex);
681int t3_phy_lasi_intr_enable(struct cphy *phy);
682int t3_phy_lasi_intr_disable(struct cphy *phy);
683int t3_phy_lasi_intr_clear(struct cphy *phy);
684int t3_phy_lasi_intr_handler(struct cphy *phy);
668 685
669void t3_intr_enable(struct adapter *adapter); 686void t3_intr_enable(struct adapter *adapter);
670void t3_intr_disable(struct adapter *adapter); 687void t3_intr_disable(struct adapter *adapter);
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 5b8251decbdc..bddcf945d6bb 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -1516,11 +1516,22 @@ static int speed_duplex_to_caps(int speed, int duplex)
1516 1516
1517static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) 1517static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1518{ 1518{
1519 int cap;
1519 struct port_info *p = netdev_priv(dev); 1520 struct port_info *p = netdev_priv(dev);
1520 struct link_config *lc = &p->link_config; 1521 struct link_config *lc = &p->link_config;
1521 1522
1522 if (!(lc->supported & SUPPORTED_Autoneg)) 1523 if (!(lc->supported & SUPPORTED_Autoneg)) {
1523 return -EOPNOTSUPP; /* can't change speed/duplex */ 1524 /*
1525 * PHY offers a single speed/duplex. See if that's what's
1526 * being requested.
1527 */
1528 if (cmd->autoneg == AUTONEG_DISABLE) {
1529 cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
1530 if (lc->supported & cap)
1531 return 0;
1532 }
1533 return -EINVAL;
1534 }
1524 1535
1525 if (cmd->autoneg == AUTONEG_DISABLE) { 1536 if (cmd->autoneg == AUTONEG_DISABLE) {
1526 int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex); 1537 int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
@@ -2195,7 +2206,7 @@ static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
2195 mmd = data->phy_id >> 8; 2206 mmd = data->phy_id >> 8;
2196 if (!mmd) 2207 if (!mmd)
2197 mmd = MDIO_DEV_PCS; 2208 mmd = MDIO_DEV_PCS;
2198 else if (mmd > MDIO_DEV_XGXS) 2209 else if (mmd > MDIO_DEV_VEND2)
2199 return -EINVAL; 2210 return -EINVAL;
2200 2211
2201 ret = 2212 ret =
@@ -2221,7 +2232,7 @@ static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
2221 mmd = data->phy_id >> 8; 2232 mmd = data->phy_id >> 8;
2222 if (!mmd) 2233 if (!mmd)
2223 mmd = MDIO_DEV_PCS; 2234 mmd = MDIO_DEV_PCS;
2224 else if (mmd > MDIO_DEV_XGXS) 2235 else if (mmd > MDIO_DEV_VEND2)
2225 return -EINVAL; 2236 return -EINVAL;
2226 2237
2227 ret = 2238 ret =
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index bfce761156a1..58a3097579f9 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -442,6 +442,33 @@ int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex)
442 return mdio_write(phy, 0, MII_BMCR, ctl); 442 return mdio_write(phy, 0, MII_BMCR, ctl);
443} 443}
444 444
445int t3_phy_lasi_intr_enable(struct cphy *phy)
446{
447 return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
448}
449
450int t3_phy_lasi_intr_disable(struct cphy *phy)
451{
452 return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
453}
454
455int t3_phy_lasi_intr_clear(struct cphy *phy)
456{
457 u32 val;
458
459 return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
460}
461
462int t3_phy_lasi_intr_handler(struct cphy *phy)
463{
464 unsigned int status;
465 int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
466
467 if (err)
468 return err;
469 return (status & 1) ? cphy_cause_link_change : 0;
470}
471
445static const struct adapter_info t3_adap_info[] = { 472static const struct adapter_info t3_adap_info[] = {
446 {2, 0, 473 {2, 0,
447 F_GPIO2_OEN | F_GPIO4_OEN | 474 F_GPIO2_OEN | F_GPIO4_OEN |
@@ -1132,6 +1159,15 @@ void t3_link_changed(struct adapter *adapter, int port_id)
1132 1159
1133 phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc); 1160 phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
1134 1161
1162 if (lc->requested_fc & PAUSE_AUTONEG)
1163 fc &= lc->requested_fc;
1164 else
1165 fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1166
1167 if (link_ok == lc->link_ok && speed == lc->speed &&
1168 duplex == lc->duplex && fc == lc->fc)
1169 return; /* nothing changed */
1170
1135 if (link_ok != lc->link_ok && adapter->params.rev > 0 && 1171 if (link_ok != lc->link_ok && adapter->params.rev > 0 &&
1136 uses_xaui(adapter)) { 1172 uses_xaui(adapter)) {
1137 if (link_ok) 1173 if (link_ok)
@@ -1142,10 +1178,6 @@ void t3_link_changed(struct adapter *adapter, int port_id)
1142 lc->link_ok = link_ok; 1178 lc->link_ok = link_ok;
1143 lc->speed = speed < 0 ? SPEED_INVALID : speed; 1179 lc->speed = speed < 0 ? SPEED_INVALID : speed;
1144 lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex; 1180 lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
1145 if (lc->requested_fc & PAUSE_AUTONEG)
1146 fc &= lc->requested_fc;
1147 else
1148 fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1149 1181
1150 if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) { 1182 if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) {
1151 /* Set MAC speed, duplex, and flow control to match PHY. */ 1183 /* Set MAC speed, duplex, and flow control to match PHY. */
@@ -1191,7 +1223,6 @@ int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
1191 fc); 1223 fc);
1192 /* Also disables autoneg */ 1224 /* Also disables autoneg */
1193 phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex); 1225 phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex);
1194 phy->ops->reset(phy, 0);
1195 } else 1226 } else
1196 phy->ops->autoneg_enable(phy); 1227 phy->ops->autoneg_enable(phy);
1197 } else { 1228 } else {