diff options
-rw-r--r-- | drivers/net/cxgb3/ael1002.c | 46 | ||||
-rw-r--r-- | drivers/net/cxgb3/common.h | 19 | ||||
-rw-r--r-- | drivers/net/cxgb3/cxgb3_main.c | 19 | ||||
-rw-r--r-- | drivers/net/cxgb3/t3_hw.c | 41 |
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 | ||
47 | static void ael100x_txon(struct cphy *phy) | 44 | static 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 | ||
137 | static int ael1006_intr_enable(struct cphy *phy) | ||
138 | { | ||
139 | return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1); | ||
140 | } | ||
141 | |||
142 | static int ael1006_intr_disable(struct cphy *phy) | ||
143 | { | ||
144 | return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0); | ||
145 | } | ||
146 | |||
147 | static 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 | |||
154 | static 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 | |||
164 | static int ael1006_power_down(struct cphy *phy, int enable) | 134 | static 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 | ||
170 | static struct cphy_ops ael1006_ops = { | 140 | static 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 | ||
190 | static struct cphy_ops qt2045_ops = { | 160 | static 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 */ | ||
532 | enum { | ||
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, | |||
665 | int t3_phy_reset(struct cphy *phy, int mmd, int wait); | 678 | int t3_phy_reset(struct cphy *phy, int mmd, int wait); |
666 | int t3_phy_advertise(struct cphy *phy, unsigned int advert); | 679 | int t3_phy_advertise(struct cphy *phy, unsigned int advert); |
667 | int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex); | 680 | int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex); |
681 | int t3_phy_lasi_intr_enable(struct cphy *phy); | ||
682 | int t3_phy_lasi_intr_disable(struct cphy *phy); | ||
683 | int t3_phy_lasi_intr_clear(struct cphy *phy); | ||
684 | int t3_phy_lasi_intr_handler(struct cphy *phy); | ||
668 | 685 | ||
669 | void t3_intr_enable(struct adapter *adapter); | 686 | void t3_intr_enable(struct adapter *adapter); |
670 | void t3_intr_disable(struct adapter *adapter); | 687 | void 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 | ||
1517 | static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 1517 | static 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 | ||
445 | int t3_phy_lasi_intr_enable(struct cphy *phy) | ||
446 | { | ||
447 | return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1); | ||
448 | } | ||
449 | |||
450 | int t3_phy_lasi_intr_disable(struct cphy *phy) | ||
451 | { | ||
452 | return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0); | ||
453 | } | ||
454 | |||
455 | int 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 | |||
462 | int 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 | |||
445 | static const struct adapter_info t3_adap_info[] = { | 472 | static 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 { |