diff options
| author | Michael Chan <mchan@broadcom.com> | 2007-05-03 16:23:13 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2007-05-03 16:23:13 -0400 |
| commit | 605a9e20aaea23f31a5403e969bd4ab4d0405dab (patch) | |
| tree | 2b3ef5ca38d7c0cb01813d3ef4cdc0a6166ab22f /drivers/net/bnx2.c | |
| parent | ca58c3af99b15f729e56dffe9b74b8b2ce157e8d (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.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 | } |
