diff options
Diffstat (limited to 'drivers/net/bnx2.c')
-rw-r--r-- | drivers/net/bnx2.c | 147 |
1 files changed, 108 insertions, 39 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index a63431526ce4..944f547a7406 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c | |||
@@ -899,6 +899,86 @@ bnx2_set_mac_link(struct bnx2 *bp) | |||
899 | } | 899 | } |
900 | 900 | ||
901 | static int | 901 | static int |
902 | bnx2_test_and_enable_2g5(struct bnx2 *bp) | ||
903 | { | ||
904 | u32 up1; | ||
905 | int ret = 1; | ||
906 | |||
907 | if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) | ||
908 | return 0; | ||
909 | |||
910 | if (bp->autoneg & AUTONEG_SPEED) | ||
911 | bp->advertising |= ADVERTISED_2500baseX_Full; | ||
912 | |||
913 | bnx2_read_phy(bp, bp->mii_up1, &up1); | ||
914 | if (!(up1 & BCM5708S_UP1_2G5)) { | ||
915 | up1 |= BCM5708S_UP1_2G5; | ||
916 | bnx2_write_phy(bp, bp->mii_up1, up1); | ||
917 | ret = 0; | ||
918 | } | ||
919 | |||
920 | return ret; | ||
921 | } | ||
922 | |||
923 | static int | ||
924 | bnx2_test_and_disable_2g5(struct bnx2 *bp) | ||
925 | { | ||
926 | u32 up1; | ||
927 | int ret = 0; | ||
928 | |||
929 | if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) | ||
930 | return 0; | ||
931 | |||
932 | bnx2_read_phy(bp, bp->mii_up1, &up1); | ||
933 | if (up1 & BCM5708S_UP1_2G5) { | ||
934 | up1 &= ~BCM5708S_UP1_2G5; | ||
935 | bnx2_write_phy(bp, bp->mii_up1, up1); | ||
936 | ret = 1; | ||
937 | } | ||
938 | |||
939 | return ret; | ||
940 | } | ||
941 | |||
942 | static void | ||
943 | bnx2_enable_forced_2g5(struct bnx2 *bp) | ||
944 | { | ||
945 | u32 bmcr; | ||
946 | |||
947 | if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) | ||
948 | return; | ||
949 | |||
950 | if (CHIP_NUM(bp) == CHIP_NUM_5708) { | ||
951 | bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); | ||
952 | bmcr |= BCM5708S_BMCR_FORCE_2500; | ||
953 | } | ||
954 | |||
955 | if (bp->autoneg & AUTONEG_SPEED) { | ||
956 | bmcr &= ~BMCR_ANENABLE; | ||
957 | if (bp->req_duplex == DUPLEX_FULL) | ||
958 | bmcr |= BMCR_FULLDPLX; | ||
959 | } | ||
960 | bnx2_write_phy(bp, bp->mii_bmcr, bmcr); | ||
961 | } | ||
962 | |||
963 | static void | ||
964 | bnx2_disable_forced_2g5(struct bnx2 *bp) | ||
965 | { | ||
966 | u32 bmcr; | ||
967 | |||
968 | if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) | ||
969 | return; | ||
970 | |||
971 | if (CHIP_NUM(bp) == CHIP_NUM_5708) { | ||
972 | bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); | ||
973 | bmcr &= ~BCM5708S_BMCR_FORCE_2500; | ||
974 | } | ||
975 | |||
976 | if (bp->autoneg & AUTONEG_SPEED) | ||
977 | bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART; | ||
978 | bnx2_write_phy(bp, bp->mii_bmcr, bmcr); | ||
979 | } | ||
980 | |||
981 | static int | ||
902 | bnx2_set_link(struct bnx2 *bp) | 982 | bnx2_set_link(struct bnx2 *bp) |
903 | { | 983 | { |
904 | u32 bmsr; | 984 | u32 bmsr; |
@@ -941,17 +1021,9 @@ bnx2_set_link(struct bnx2 *bp) | |||
941 | } | 1021 | } |
942 | else { | 1022 | else { |
943 | if ((bp->phy_flags & PHY_SERDES_FLAG) && | 1023 | if ((bp->phy_flags & PHY_SERDES_FLAG) && |
944 | (bp->autoneg & AUTONEG_SPEED)) { | 1024 | (bp->autoneg & AUTONEG_SPEED)) |
1025 | bnx2_disable_forced_2g5(bp); | ||
945 | 1026 | ||
946 | u32 bmcr; | ||
947 | |||
948 | bnx2_read_phy(bp, MII_BMCR, &bmcr); | ||
949 | bmcr &= ~BCM5708S_BMCR_FORCE_2500; | ||
950 | if (!(bmcr & BMCR_ANENABLE)) { | ||
951 | bnx2_write_phy(bp, MII_BMCR, bmcr | | ||
952 | BMCR_ANENABLE); | ||
953 | } | ||
954 | } | ||
955 | bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG; | 1027 | bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG; |
956 | bp->link_up = 0; | 1028 | bp->link_up = 0; |
957 | } | 1029 | } |
@@ -1026,34 +1098,32 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp) | |||
1026 | static int | 1098 | static int |
1027 | bnx2_setup_serdes_phy(struct bnx2 *bp) | 1099 | bnx2_setup_serdes_phy(struct bnx2 *bp) |
1028 | { | 1100 | { |
1029 | u32 adv, bmcr, up1; | 1101 | u32 adv, bmcr; |
1030 | u32 new_adv = 0; | 1102 | u32 new_adv = 0; |
1031 | 1103 | ||
1032 | if (!(bp->autoneg & AUTONEG_SPEED)) { | 1104 | if (!(bp->autoneg & AUTONEG_SPEED)) { |
1033 | u32 new_bmcr; | 1105 | u32 new_bmcr; |
1034 | int force_link_down = 0; | 1106 | int force_link_down = 0; |
1035 | 1107 | ||
1108 | if (bp->req_line_speed == SPEED_2500) { | ||
1109 | if (!bnx2_test_and_enable_2g5(bp)) | ||
1110 | force_link_down = 1; | ||
1111 | } else if (bp->req_line_speed == SPEED_1000) { | ||
1112 | if (bnx2_test_and_disable_2g5(bp)) | ||
1113 | force_link_down = 1; | ||
1114 | } | ||
1036 | bnx2_read_phy(bp, bp->mii_adv, &adv); | 1115 | bnx2_read_phy(bp, bp->mii_adv, &adv); |
1037 | adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF); | 1116 | adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF); |
1038 | 1117 | ||
1039 | bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); | 1118 | bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); |
1040 | new_bmcr = bmcr & ~(BMCR_ANENABLE | BCM5708S_BMCR_FORCE_2500); | 1119 | new_bmcr = bmcr & ~BMCR_ANENABLE; |
1041 | new_bmcr |= BMCR_SPEED1000; | 1120 | new_bmcr |= BMCR_SPEED1000; |
1042 | if (bp->req_line_speed == SPEED_2500) { | 1121 | |
1043 | new_bmcr |= BCM5708S_BMCR_FORCE_2500; | 1122 | if (CHIP_NUM(bp) == CHIP_NUM_5708) { |
1044 | bnx2_read_phy(bp, BCM5708S_UP1, &up1); | 1123 | if (bp->req_line_speed == SPEED_2500) |
1045 | if (!(up1 & BCM5708S_UP1_2G5)) { | 1124 | new_bmcr |= BCM5708S_BMCR_FORCE_2500; |
1046 | up1 |= BCM5708S_UP1_2G5; | 1125 | else |
1047 | bnx2_write_phy(bp, BCM5708S_UP1, up1); | 1126 | new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500; |
1048 | force_link_down = 1; | ||
1049 | } | ||
1050 | } else if (CHIP_NUM(bp) == CHIP_NUM_5708) { | ||
1051 | bnx2_read_phy(bp, BCM5708S_UP1, &up1); | ||
1052 | if (up1 & BCM5708S_UP1_2G5) { | ||
1053 | up1 &= ~BCM5708S_UP1_2G5; | ||
1054 | bnx2_write_phy(bp, BCM5708S_UP1, up1); | ||
1055 | force_link_down = 1; | ||
1056 | } | ||
1057 | } | 1127 | } |
1058 | 1128 | ||
1059 | if (bp->req_duplex == DUPLEX_FULL) { | 1129 | if (bp->req_duplex == DUPLEX_FULL) { |
@@ -1080,15 +1150,14 @@ bnx2_setup_serdes_phy(struct bnx2 *bp) | |||
1080 | } | 1150 | } |
1081 | bnx2_write_phy(bp, bp->mii_adv, adv); | 1151 | bnx2_write_phy(bp, bp->mii_adv, adv); |
1082 | bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr); | 1152 | bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr); |
1153 | } else { | ||
1154 | bnx2_resolve_flow_ctrl(bp); | ||
1155 | bnx2_set_mac_link(bp); | ||
1083 | } | 1156 | } |
1084 | return 0; | 1157 | return 0; |
1085 | } | 1158 | } |
1086 | 1159 | ||
1087 | if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) { | 1160 | bnx2_test_and_enable_2g5(bp); |
1088 | bnx2_read_phy(bp, BCM5708S_UP1, &up1); | ||
1089 | up1 |= BCM5708S_UP1_2G5; | ||
1090 | bnx2_write_phy(bp, BCM5708S_UP1, up1); | ||
1091 | } | ||
1092 | 1161 | ||
1093 | if (bp->advertising & ADVERTISED_1000baseT_Full) | 1162 | if (bp->advertising & ADVERTISED_1000baseT_Full) |
1094 | new_adv |= ADVERTISE_1000XFULL; | 1163 | new_adv |= ADVERTISE_1000XFULL; |
@@ -1122,6 +1191,9 @@ bnx2_setup_serdes_phy(struct bnx2 *bp) | |||
1122 | bp->current_interval = SERDES_AN_TIMEOUT; | 1191 | bp->current_interval = SERDES_AN_TIMEOUT; |
1123 | bp->serdes_an_pending = 1; | 1192 | bp->serdes_an_pending = 1; |
1124 | mod_timer(&bp->timer, jiffies + bp->current_interval); | 1193 | mod_timer(&bp->timer, jiffies + bp->current_interval); |
1194 | } else { | ||
1195 | bnx2_resolve_flow_ctrl(bp); | ||
1196 | bnx2_set_mac_link(bp); | ||
1125 | } | 1197 | } |
1126 | 1198 | ||
1127 | return 0; | 1199 | return 0; |
@@ -4300,16 +4372,11 @@ bnx2_5708_serdes_timer(struct bnx2 *bp) | |||
4300 | u32 bmcr; | 4372 | u32 bmcr; |
4301 | 4373 | ||
4302 | bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); | 4374 | bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); |
4303 | |||
4304 | if (bmcr & BMCR_ANENABLE) { | 4375 | if (bmcr & BMCR_ANENABLE) { |
4305 | bmcr &= ~BMCR_ANENABLE; | 4376 | bnx2_enable_forced_2g5(bp); |
4306 | bmcr |= BMCR_FULLDPLX | BCM5708S_BMCR_FORCE_2500; | ||
4307 | bnx2_write_phy(bp, MII_BMCR, bmcr); | ||
4308 | bp->current_interval = SERDES_FORCED_TIMEOUT; | 4377 | bp->current_interval = SERDES_FORCED_TIMEOUT; |
4309 | } else { | 4378 | } else { |
4310 | bmcr &= ~(BMCR_FULLDPLX | BCM5708S_BMCR_FORCE_2500); | 4379 | bnx2_disable_forced_2g5(bp); |
4311 | bmcr |= BMCR_ANENABLE; | ||
4312 | bnx2_write_phy(bp, MII_BMCR, bmcr); | ||
4313 | bp->serdes_an_pending = 2; | 4380 | bp->serdes_an_pending = 2; |
4314 | bp->current_interval = bp->timer_interval; | 4381 | bp->current_interval = bp->timer_interval; |
4315 | } | 4382 | } |
@@ -4778,6 +4845,8 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
4778 | if (bp->phy_flags & PHY_SERDES_FLAG) { | 4845 | if (bp->phy_flags & PHY_SERDES_FLAG) { |
4779 | cmd->supported |= SUPPORTED_1000baseT_Full | | 4846 | cmd->supported |= SUPPORTED_1000baseT_Full | |
4780 | SUPPORTED_FIBRE; | 4847 | SUPPORTED_FIBRE; |
4848 | if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) | ||
4849 | cmd->supported |= SUPPORTED_2500baseX_Full; | ||
4781 | 4850 | ||
4782 | cmd->port = PORT_FIBRE; | 4851 | cmd->port = PORT_FIBRE; |
4783 | } | 4852 | } |