aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/bnx2.c
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2007-05-03 16:23:13 -0400
committerDavid S. Miller <davem@davemloft.net>2007-05-03 16:23:13 -0400
commit605a9e20aaea23f31a5403e969bd4ab4d0405dab (patch)
tree2b3ef5ca38d7c0cb01813d3ef4cdc0a6166ab22f /drivers/net/bnx2.c
parentca58c3af99b15f729e56dffe9b74b8b2ce157e8d (diff)
[BNX2]: Re-structure the 2.5G Serdes code.
Add some common procedures to handle enabling and disabling 2.5G. Add some missing code to resolve flow control. Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bnx2.c')
-rw-r--r--drivers/net/bnx2.c147
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
901static int 901static int
902bnx2_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
923static int
924bnx2_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
942static void
943bnx2_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
963static void
964bnx2_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
981static int
902bnx2_set_link(struct bnx2 *bp) 982bnx2_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)
1026static int 1098static int
1027bnx2_setup_serdes_phy(struct bnx2 *bp) 1099bnx2_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 }