diff options
author | Lendacky, Thomas <Thomas.Lendacky@amd.com> | 2014-09-03 13:14:16 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-09-05 18:11:20 -0400 |
commit | e3eec4e79322957d9408dc4e2cf7276c558999d7 (patch) | |
tree | eb0e1341d18259b468ed491580e4b0d8cbb99529 | |
parent | e4cf0b756c78e252b989b86e281ecc12d40bd2f6 (diff) |
amd-xgbe-phy: Check device for current speed mode (KR/KX)
Since device resets can change the current mode it's possible to think
the device is in a different mode than it actually is. Rather than
trying to determine every place that is needed to set/save the current
mode, be safe and check the devices actual mode when needed rather than
trying to track it.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/phy/amd-xgbe-phy.c | 135 |
1 files changed, 72 insertions, 63 deletions
diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c index f3230eef41fd..b3cef20637c0 100644 --- a/drivers/net/phy/amd-xgbe-phy.c +++ b/drivers/net/phy/amd-xgbe-phy.c | |||
@@ -331,7 +331,6 @@ struct amd_xgbe_phy_priv { | |||
331 | 331 | ||
332 | /* Maintain link status for re-starting auto-negotiation */ | 332 | /* Maintain link status for re-starting auto-negotiation */ |
333 | unsigned int link; | 333 | unsigned int link; |
334 | enum amd_xgbe_phy_mode mode; | ||
335 | unsigned int speed_set; | 334 | unsigned int speed_set; |
336 | 335 | ||
337 | /* Auto-negotiation state machine support */ | 336 | /* Auto-negotiation state machine support */ |
@@ -468,8 +467,6 @@ static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev) | |||
468 | 467 | ||
469 | amd_xgbe_phy_serdes_complete_ratechange(phydev); | 468 | amd_xgbe_phy_serdes_complete_ratechange(phydev); |
470 | 469 | ||
471 | priv->mode = AMD_XGBE_MODE_KR; | ||
472 | |||
473 | return 0; | 470 | return 0; |
474 | } | 471 | } |
475 | 472 | ||
@@ -518,8 +515,6 @@ static int amd_xgbe_phy_gmii_2500_mode(struct phy_device *phydev) | |||
518 | 515 | ||
519 | amd_xgbe_phy_serdes_complete_ratechange(phydev); | 516 | amd_xgbe_phy_serdes_complete_ratechange(phydev); |
520 | 517 | ||
521 | priv->mode = AMD_XGBE_MODE_KX; | ||
522 | |||
523 | return 0; | 518 | return 0; |
524 | } | 519 | } |
525 | 520 | ||
@@ -568,18 +563,43 @@ static int amd_xgbe_phy_gmii_mode(struct phy_device *phydev) | |||
568 | 563 | ||
569 | amd_xgbe_phy_serdes_complete_ratechange(phydev); | 564 | amd_xgbe_phy_serdes_complete_ratechange(phydev); |
570 | 565 | ||
571 | priv->mode = AMD_XGBE_MODE_KX; | 566 | return 0; |
567 | } | ||
568 | |||
569 | static int amd_xgbe_phy_cur_mode(struct phy_device *phydev, | ||
570 | enum amd_xgbe_phy_mode *mode) | ||
571 | { | ||
572 | int ret; | ||
573 | |||
574 | ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); | ||
575 | if (ret < 0) | ||
576 | return ret; | ||
577 | |||
578 | if ((ret & MDIO_PCS_CTRL2_TYPE) == MDIO_PCS_CTRL2_10GBR) | ||
579 | *mode = AMD_XGBE_MODE_KR; | ||
580 | else | ||
581 | *mode = AMD_XGBE_MODE_KX; | ||
572 | 582 | ||
573 | return 0; | 583 | return 0; |
574 | } | 584 | } |
575 | 585 | ||
586 | static bool amd_xgbe_phy_in_kr_mode(struct phy_device *phydev) | ||
587 | { | ||
588 | enum amd_xgbe_phy_mode mode; | ||
589 | |||
590 | if (amd_xgbe_phy_cur_mode(phydev, &mode)) | ||
591 | return false; | ||
592 | |||
593 | return (mode == AMD_XGBE_MODE_KR); | ||
594 | } | ||
595 | |||
576 | static int amd_xgbe_phy_switch_mode(struct phy_device *phydev) | 596 | static int amd_xgbe_phy_switch_mode(struct phy_device *phydev) |
577 | { | 597 | { |
578 | struct amd_xgbe_phy_priv *priv = phydev->priv; | 598 | struct amd_xgbe_phy_priv *priv = phydev->priv; |
579 | int ret; | 599 | int ret; |
580 | 600 | ||
581 | /* If we are in KR switch to KX, and vice-versa */ | 601 | /* If we are in KR switch to KX, and vice-versa */ |
582 | if (priv->mode == AMD_XGBE_MODE_KR) { | 602 | if (amd_xgbe_phy_in_kr_mode(phydev)) { |
583 | if (priv->speed_set == AMD_XGBE_PHY_SPEEDSET_1000_10000) | 603 | if (priv->speed_set == AMD_XGBE_PHY_SPEEDSET_1000_10000) |
584 | ret = amd_xgbe_phy_gmii_mode(phydev); | 604 | ret = amd_xgbe_phy_gmii_mode(phydev); |
585 | else | 605 | else |
@@ -591,27 +611,31 @@ static int amd_xgbe_phy_switch_mode(struct phy_device *phydev) | |||
591 | return ret; | 611 | return ret; |
592 | } | 612 | } |
593 | 613 | ||
594 | static enum amd_xgbe_phy_an amd_xgbe_an_switch_mode(struct phy_device *phydev) | 614 | static int amd_xgbe_phy_set_mode(struct phy_device *phydev, |
615 | enum amd_xgbe_phy_mode mode) | ||
595 | { | 616 | { |
617 | enum amd_xgbe_phy_mode cur_mode; | ||
596 | int ret; | 618 | int ret; |
597 | 619 | ||
598 | ret = amd_xgbe_phy_switch_mode(phydev); | 620 | ret = amd_xgbe_phy_cur_mode(phydev, &cur_mode); |
599 | if (ret < 0) | 621 | if (ret) |
600 | return AMD_XGBE_AN_ERROR; | 622 | return ret; |
601 | 623 | ||
602 | return AMD_XGBE_AN_START; | 624 | if (mode != cur_mode) |
625 | ret = amd_xgbe_phy_switch_mode(phydev); | ||
626 | |||
627 | return ret; | ||
603 | } | 628 | } |
604 | 629 | ||
605 | static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, | 630 | static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, |
606 | enum amd_xgbe_phy_rx *state) | 631 | enum amd_xgbe_phy_rx *state) |
607 | { | 632 | { |
608 | struct amd_xgbe_phy_priv *priv = phydev->priv; | ||
609 | int ad_reg, lp_reg, ret; | 633 | int ad_reg, lp_reg, ret; |
610 | 634 | ||
611 | *state = AMD_XGBE_RX_COMPLETE; | 635 | *state = AMD_XGBE_RX_COMPLETE; |
612 | 636 | ||
613 | /* If we're in KX mode then we're done */ | 637 | /* If we're not in KR mode then we're done */ |
614 | if (priv->mode == AMD_XGBE_MODE_KX) | 638 | if (!amd_xgbe_phy_in_kr_mode(phydev)) |
615 | return AMD_XGBE_AN_EVENT; | 639 | return AMD_XGBE_AN_EVENT; |
616 | 640 | ||
617 | /* Enable/Disable FEC */ | 641 | /* Enable/Disable FEC */ |
@@ -669,7 +693,6 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_xnp(struct phy_device *phydev, | |||
669 | static enum amd_xgbe_phy_an amd_xgbe_an_rx_bpa(struct phy_device *phydev, | 693 | static enum amd_xgbe_phy_an amd_xgbe_an_rx_bpa(struct phy_device *phydev, |
670 | enum amd_xgbe_phy_rx *state) | 694 | enum amd_xgbe_phy_rx *state) |
671 | { | 695 | { |
672 | struct amd_xgbe_phy_priv *priv = phydev->priv; | ||
673 | unsigned int link_support; | 696 | unsigned int link_support; |
674 | int ret, ad_reg, lp_reg; | 697 | int ret, ad_reg, lp_reg; |
675 | 698 | ||
@@ -679,9 +702,9 @@ static enum amd_xgbe_phy_an amd_xgbe_an_rx_bpa(struct phy_device *phydev, | |||
679 | return AMD_XGBE_AN_ERROR; | 702 | return AMD_XGBE_AN_ERROR; |
680 | 703 | ||
681 | /* Check for a supported mode, otherwise restart in a different one */ | 704 | /* Check for a supported mode, otherwise restart in a different one */ |
682 | link_support = (priv->mode == AMD_XGBE_MODE_KR) ? 0x80 : 0x20; | 705 | link_support = amd_xgbe_phy_in_kr_mode(phydev) ? 0x80 : 0x20; |
683 | if (!(ret & link_support)) | 706 | if (!(ret & link_support)) |
684 | return amd_xgbe_an_switch_mode(phydev); | 707 | return AMD_XGBE_AN_INCOMPAT_LINK; |
685 | 708 | ||
686 | /* Check Extended Next Page support */ | 709 | /* Check Extended Next Page support */ |
687 | ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); | 710 | ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); |
@@ -722,7 +745,7 @@ static enum amd_xgbe_phy_an amd_xgbe_an_start(struct phy_device *phydev) | |||
722 | int ret; | 745 | int ret; |
723 | 746 | ||
724 | /* Be sure we aren't looping trying to negotiate */ | 747 | /* Be sure we aren't looping trying to negotiate */ |
725 | if (priv->mode == AMD_XGBE_MODE_KR) { | 748 | if (amd_xgbe_phy_in_kr_mode(phydev)) { |
726 | if (priv->kr_state != AMD_XGBE_RX_READY) | 749 | if (priv->kr_state != AMD_XGBE_RX_READY) |
727 | return AMD_XGBE_AN_NO_LINK; | 750 | return AMD_XGBE_AN_NO_LINK; |
728 | priv->kr_state = AMD_XGBE_RX_BPA; | 751 | priv->kr_state = AMD_XGBE_RX_BPA; |
@@ -825,8 +848,8 @@ static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev) | |||
825 | enum amd_xgbe_phy_rx *state; | 848 | enum amd_xgbe_phy_rx *state; |
826 | int ret; | 849 | int ret; |
827 | 850 | ||
828 | state = (priv->mode == AMD_XGBE_MODE_KR) ? &priv->kr_state | 851 | state = amd_xgbe_phy_in_kr_mode(phydev) ? &priv->kr_state |
829 | : &priv->kx_state; | 852 | : &priv->kx_state; |
830 | 853 | ||
831 | switch (*state) { | 854 | switch (*state) { |
832 | case AMD_XGBE_RX_BPA: | 855 | case AMD_XGBE_RX_BPA: |
@@ -846,7 +869,13 @@ static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev) | |||
846 | 869 | ||
847 | static enum amd_xgbe_phy_an amd_xgbe_an_incompat_link(struct phy_device *phydev) | 870 | static enum amd_xgbe_phy_an amd_xgbe_an_incompat_link(struct phy_device *phydev) |
848 | { | 871 | { |
849 | return amd_xgbe_an_switch_mode(phydev); | 872 | int ret; |
873 | |||
874 | ret = amd_xgbe_phy_switch_mode(phydev); | ||
875 | if (ret) | ||
876 | return AMD_XGBE_AN_ERROR; | ||
877 | |||
878 | return AMD_XGBE_AN_START; | ||
850 | } | 879 | } |
851 | 880 | ||
852 | static void amd_xgbe_an_state_machine(struct work_struct *work) | 881 | static void amd_xgbe_an_state_machine(struct work_struct *work) |
@@ -1018,7 +1047,6 @@ static int amd_xgbe_phy_config_aneg(struct phy_device *phydev) | |||
1018 | { | 1047 | { |
1019 | struct amd_xgbe_phy_priv *priv = phydev->priv; | 1048 | struct amd_xgbe_phy_priv *priv = phydev->priv; |
1020 | u32 mmd_mask = phydev->c45_ids.devices_in_package; | 1049 | u32 mmd_mask = phydev->c45_ids.devices_in_package; |
1021 | int ret; | ||
1022 | 1050 | ||
1023 | if (phydev->autoneg != AUTONEG_ENABLE) | 1051 | if (phydev->autoneg != AUTONEG_ENABLE) |
1024 | return amd_xgbe_phy_setup_forced(phydev); | 1052 | return amd_xgbe_phy_setup_forced(phydev); |
@@ -1027,11 +1055,6 @@ static int amd_xgbe_phy_config_aneg(struct phy_device *phydev) | |||
1027 | if (!(mmd_mask & MDIO_DEVS_AN)) | 1055 | if (!(mmd_mask & MDIO_DEVS_AN)) |
1028 | return -EINVAL; | 1056 | return -EINVAL; |
1029 | 1057 | ||
1030 | /* Get the current speed mode */ | ||
1031 | ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); | ||
1032 | if (ret < 0) | ||
1033 | return ret; | ||
1034 | |||
1035 | /* Start/Restart the auto-negotiation state machine */ | 1058 | /* Start/Restart the auto-negotiation state machine */ |
1036 | mutex_lock(&priv->an_mutex); | 1059 | mutex_lock(&priv->an_mutex); |
1037 | priv->an_result = AMD_XGBE_AN_READY; | 1060 | priv->an_result = AMD_XGBE_AN_READY; |
@@ -1121,17 +1144,12 @@ static int amd_xgbe_phy_read_status(struct phy_device *phydev) | |||
1121 | { | 1144 | { |
1122 | struct amd_xgbe_phy_priv *priv = phydev->priv; | 1145 | struct amd_xgbe_phy_priv *priv = phydev->priv; |
1123 | u32 mmd_mask = phydev->c45_ids.devices_in_package; | 1146 | u32 mmd_mask = phydev->c45_ids.devices_in_package; |
1124 | int ret, mode, ad_ret, lp_ret; | 1147 | int ret, ad_ret, lp_ret; |
1125 | 1148 | ||
1126 | ret = amd_xgbe_phy_update_link(phydev); | 1149 | ret = amd_xgbe_phy_update_link(phydev); |
1127 | if (ret) | 1150 | if (ret) |
1128 | return ret; | 1151 | return ret; |
1129 | 1152 | ||
1130 | mode = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); | ||
1131 | if (mode < 0) | ||
1132 | return mode; | ||
1133 | mode &= MDIO_PCS_CTRL2_TYPE; | ||
1134 | |||
1135 | if (phydev->autoneg == AUTONEG_ENABLE) { | 1153 | if (phydev->autoneg == AUTONEG_ENABLE) { |
1136 | if (!(mmd_mask & MDIO_DEVS_AN)) | 1154 | if (!(mmd_mask & MDIO_DEVS_AN)) |
1137 | return -EINVAL; | 1155 | return -EINVAL; |
@@ -1163,40 +1181,39 @@ static int amd_xgbe_phy_read_status(struct phy_device *phydev) | |||
1163 | ad_ret &= lp_ret; | 1181 | ad_ret &= lp_ret; |
1164 | if (ad_ret & 0x80) { | 1182 | if (ad_ret & 0x80) { |
1165 | phydev->speed = SPEED_10000; | 1183 | phydev->speed = SPEED_10000; |
1166 | if (mode != MDIO_PCS_CTRL2_10GBR) { | 1184 | ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KR); |
1167 | ret = amd_xgbe_phy_xgmii_mode(phydev); | 1185 | if (ret) |
1168 | if (ret < 0) | 1186 | return ret; |
1169 | return ret; | ||
1170 | } | ||
1171 | } else { | 1187 | } else { |
1172 | int (*mode_fcn)(struct phy_device *); | 1188 | switch (priv->speed_set) { |
1173 | 1189 | case AMD_XGBE_PHY_SPEEDSET_1000_10000: | |
1174 | if (priv->speed_set == | ||
1175 | AMD_XGBE_PHY_SPEEDSET_1000_10000) { | ||
1176 | phydev->speed = SPEED_1000; | 1190 | phydev->speed = SPEED_1000; |
1177 | mode_fcn = amd_xgbe_phy_gmii_mode; | 1191 | break; |
1178 | } else { | 1192 | |
1193 | case AMD_XGBE_PHY_SPEEDSET_2500_10000: | ||
1179 | phydev->speed = SPEED_2500; | 1194 | phydev->speed = SPEED_2500; |
1180 | mode_fcn = amd_xgbe_phy_gmii_2500_mode; | 1195 | break; |
1181 | } | 1196 | } |
1182 | 1197 | ||
1183 | if (mode == MDIO_PCS_CTRL2_10GBR) { | 1198 | ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX); |
1184 | ret = mode_fcn(phydev); | 1199 | if (ret) |
1185 | if (ret < 0) | 1200 | return ret; |
1186 | return ret; | ||
1187 | } | ||
1188 | } | 1201 | } |
1189 | 1202 | ||
1190 | phydev->duplex = DUPLEX_FULL; | 1203 | phydev->duplex = DUPLEX_FULL; |
1191 | } else { | 1204 | } else { |
1192 | if (mode == MDIO_PCS_CTRL2_10GBR) { | 1205 | if (amd_xgbe_phy_in_kr_mode(phydev)) { |
1193 | phydev->speed = SPEED_10000; | 1206 | phydev->speed = SPEED_10000; |
1194 | } else { | 1207 | } else { |
1195 | if (priv->speed_set == | 1208 | switch (priv->speed_set) { |
1196 | AMD_XGBE_PHY_SPEEDSET_1000_10000) | 1209 | case AMD_XGBE_PHY_SPEEDSET_1000_10000: |
1197 | phydev->speed = SPEED_1000; | 1210 | phydev->speed = SPEED_1000; |
1198 | else | 1211 | break; |
1212 | |||
1213 | case AMD_XGBE_PHY_SPEEDSET_2500_10000: | ||
1199 | phydev->speed = SPEED_2500; | 1214 | phydev->speed = SPEED_2500; |
1215 | break; | ||
1216 | } | ||
1200 | } | 1217 | } |
1201 | phydev->duplex = DUPLEX_FULL; | 1218 | phydev->duplex = DUPLEX_FULL; |
1202 | phydev->pause = 0; | 1219 | phydev->pause = 0; |
@@ -1329,14 +1346,6 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) | |||
1329 | 1346 | ||
1330 | priv->link = 1; | 1347 | priv->link = 1; |
1331 | 1348 | ||
1332 | ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); | ||
1333 | if (ret < 0) | ||
1334 | goto err_sir1; | ||
1335 | if ((ret & MDIO_PCS_CTRL2_TYPE) == MDIO_PCS_CTRL2_10GBR) | ||
1336 | priv->mode = AMD_XGBE_MODE_KR; | ||
1337 | else | ||
1338 | priv->mode = AMD_XGBE_MODE_KX; | ||
1339 | |||
1340 | mutex_init(&priv->an_mutex); | 1349 | mutex_init(&priv->an_mutex); |
1341 | INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine); | 1350 | INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine); |
1342 | priv->an_workqueue = create_singlethread_workqueue(wq_name); | 1351 | priv->an_workqueue = create_singlethread_workqueue(wq_name); |