diff options
author | Stephen Hemminger <shemminger@osdl.org> | 2006-10-05 18:49:52 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-10-11 04:06:09 -0400 |
commit | 5d5c8e03786691d0d083142b922edce8609c0fd5 (patch) | |
tree | a821bad020b3a961e9af512803aca9804169fcd1 /drivers/net/skge.c | |
parent | 4b67be999ed5bfb1bfe4cc502d37d59b4f6b6b7f (diff) |
[PATCH] skge: better flow control negotiation
Do flow control negotiation properly. Don't let auto negotiation
status limit renegotiation. Separate desired pause values from
the result of auto negotiation.
Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/skge.c')
-rw-r--r-- | drivers/net/skge.c | 129 |
1 files changed, 78 insertions, 51 deletions
diff --git a/drivers/net/skge.c b/drivers/net/skge.c index c19f49bce7af..d844a837a8f2 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c | |||
@@ -487,31 +487,37 @@ static void skge_get_pauseparam(struct net_device *dev, | |||
487 | { | 487 | { |
488 | struct skge_port *skge = netdev_priv(dev); | 488 | struct skge_port *skge = netdev_priv(dev); |
489 | 489 | ||
490 | ecmd->tx_pause = (skge->flow_control == FLOW_MODE_LOC_SEND) | 490 | ecmd->rx_pause = (skge->flow_control == FLOW_MODE_SYMMETRIC) |
491 | || (skge->flow_control == FLOW_MODE_SYMMETRIC); | 491 | || (skge->flow_control == FLOW_MODE_SYM_OR_REM); |
492 | ecmd->rx_pause = (skge->flow_control == FLOW_MODE_REM_SEND) | 492 | ecmd->tx_pause = ecmd->rx_pause || (skge->flow_control == FLOW_MODE_LOC_SEND); |
493 | || (skge->flow_control == FLOW_MODE_SYMMETRIC); | ||
494 | 493 | ||
495 | ecmd->autoneg = skge->autoneg; | 494 | ecmd->autoneg = ecmd->rx_pause || ecmd->tx_pause; |
496 | } | 495 | } |
497 | 496 | ||
498 | static int skge_set_pauseparam(struct net_device *dev, | 497 | static int skge_set_pauseparam(struct net_device *dev, |
499 | struct ethtool_pauseparam *ecmd) | 498 | struct ethtool_pauseparam *ecmd) |
500 | { | 499 | { |
501 | struct skge_port *skge = netdev_priv(dev); | 500 | struct skge_port *skge = netdev_priv(dev); |
501 | struct ethtool_pauseparam old; | ||
502 | 502 | ||
503 | skge->autoneg = ecmd->autoneg; | 503 | skge_get_pauseparam(dev, &old); |
504 | if (ecmd->rx_pause && ecmd->tx_pause) | 504 | |
505 | skge->flow_control = FLOW_MODE_SYMMETRIC; | 505 | if (ecmd->autoneg != old.autoneg) |
506 | else if (ecmd->rx_pause && !ecmd->tx_pause) | 506 | skge->flow_control = ecmd->autoneg ? FLOW_MODE_NONE : FLOW_MODE_SYMMETRIC; |
507 | skge->flow_control = FLOW_MODE_REM_SEND; | 507 | else { |
508 | else if (!ecmd->rx_pause && ecmd->tx_pause) | 508 | if (ecmd->rx_pause && ecmd->tx_pause) |
509 | skge->flow_control = FLOW_MODE_LOC_SEND; | 509 | skge->flow_control = FLOW_MODE_SYMMETRIC; |
510 | else | 510 | else if (ecmd->rx_pause && !ecmd->tx_pause) |
511 | skge->flow_control = FLOW_MODE_NONE; | 511 | skge->flow_control = FLOW_MODE_SYM_OR_REM; |
512 | else if (!ecmd->rx_pause && ecmd->tx_pause) | ||
513 | skge->flow_control = FLOW_MODE_LOC_SEND; | ||
514 | else | ||
515 | skge->flow_control = FLOW_MODE_NONE; | ||
516 | } | ||
512 | 517 | ||
513 | if (netif_running(dev)) | 518 | if (netif_running(dev)) |
514 | skge_phy_reset(skge); | 519 | skge_phy_reset(skge); |
520 | |||
515 | return 0; | 521 | return 0; |
516 | } | 522 | } |
517 | 523 | ||
@@ -854,6 +860,23 @@ static int skge_rx_fill(struct net_device *dev) | |||
854 | return 0; | 860 | return 0; |
855 | } | 861 | } |
856 | 862 | ||
863 | static const char *skge_pause(enum pause_status status) | ||
864 | { | ||
865 | switch(status) { | ||
866 | case FLOW_STAT_NONE: | ||
867 | return "none"; | ||
868 | case FLOW_STAT_REM_SEND: | ||
869 | return "rx only"; | ||
870 | case FLOW_STAT_LOC_SEND: | ||
871 | return "tx_only"; | ||
872 | case FLOW_STAT_SYMMETRIC: /* Both station may send PAUSE */ | ||
873 | return "both"; | ||
874 | default: | ||
875 | return "indeterminated"; | ||
876 | } | ||
877 | } | ||
878 | |||
879 | |||
857 | static void skge_link_up(struct skge_port *skge) | 880 | static void skge_link_up(struct skge_port *skge) |
858 | { | 881 | { |
859 | skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), | 882 | skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), |
@@ -862,16 +885,13 @@ static void skge_link_up(struct skge_port *skge) | |||
862 | netif_carrier_on(skge->netdev); | 885 | netif_carrier_on(skge->netdev); |
863 | netif_wake_queue(skge->netdev); | 886 | netif_wake_queue(skge->netdev); |
864 | 887 | ||
865 | if (netif_msg_link(skge)) | 888 | if (netif_msg_link(skge)) { |
866 | printk(KERN_INFO PFX | 889 | printk(KERN_INFO PFX |
867 | "%s: Link is up at %d Mbps, %s duplex, flow control %s\n", | 890 | "%s: Link is up at %d Mbps, %s duplex, flow control %s\n", |
868 | skge->netdev->name, skge->speed, | 891 | skge->netdev->name, skge->speed, |
869 | skge->duplex == DUPLEX_FULL ? "full" : "half", | 892 | skge->duplex == DUPLEX_FULL ? "full" : "half", |
870 | (skge->flow_control == FLOW_MODE_NONE) ? "none" : | 893 | skge_pause(skge->flow_status)); |
871 | (skge->flow_control == FLOW_MODE_LOC_SEND) ? "tx only" : | 894 | } |
872 | (skge->flow_control == FLOW_MODE_REM_SEND) ? "rx only" : | ||
873 | (skge->flow_control == FLOW_MODE_SYMMETRIC) ? "tx and rx" : | ||
874 | "unknown"); | ||
875 | } | 895 | } |
876 | 896 | ||
877 | static void skge_link_down(struct skge_port *skge) | 897 | static void skge_link_down(struct skge_port *skge) |
@@ -1015,7 +1035,7 @@ static const u16 phy_pause_map[] = { | |||
1015 | [FLOW_MODE_NONE] = 0, | 1035 | [FLOW_MODE_NONE] = 0, |
1016 | [FLOW_MODE_LOC_SEND] = PHY_AN_PAUSE_ASYM, | 1036 | [FLOW_MODE_LOC_SEND] = PHY_AN_PAUSE_ASYM, |
1017 | [FLOW_MODE_SYMMETRIC] = PHY_AN_PAUSE_CAP, | 1037 | [FLOW_MODE_SYMMETRIC] = PHY_AN_PAUSE_CAP, |
1018 | [FLOW_MODE_REM_SEND] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM, | 1038 | [FLOW_MODE_SYM_OR_REM] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM, |
1019 | }; | 1039 | }; |
1020 | 1040 | ||
1021 | /* special defines for FIBER (88E1011S only) */ | 1041 | /* special defines for FIBER (88E1011S only) */ |
@@ -1023,7 +1043,7 @@ static const u16 fiber_pause_map[] = { | |||
1023 | [FLOW_MODE_NONE] = PHY_X_P_NO_PAUSE, | 1043 | [FLOW_MODE_NONE] = PHY_X_P_NO_PAUSE, |
1024 | [FLOW_MODE_LOC_SEND] = PHY_X_P_ASYM_MD, | 1044 | [FLOW_MODE_LOC_SEND] = PHY_X_P_ASYM_MD, |
1025 | [FLOW_MODE_SYMMETRIC] = PHY_X_P_SYM_MD, | 1045 | [FLOW_MODE_SYMMETRIC] = PHY_X_P_SYM_MD, |
1026 | [FLOW_MODE_REM_SEND] = PHY_X_P_BOTH_MD, | 1046 | [FLOW_MODE_SYM_OR_REM] = PHY_X_P_BOTH_MD, |
1027 | }; | 1047 | }; |
1028 | 1048 | ||
1029 | 1049 | ||
@@ -1072,20 +1092,19 @@ static void bcom_check_link(struct skge_hw *hw, int port) | |||
1072 | return; | 1092 | return; |
1073 | } | 1093 | } |
1074 | 1094 | ||
1075 | |||
1076 | /* We are using IEEE 802.3z/D5.0 Table 37-4 */ | 1095 | /* We are using IEEE 802.3z/D5.0 Table 37-4 */ |
1077 | switch (aux & PHY_B_AS_PAUSE_MSK) { | 1096 | switch (aux & PHY_B_AS_PAUSE_MSK) { |
1078 | case PHY_B_AS_PAUSE_MSK: | 1097 | case PHY_B_AS_PAUSE_MSK: |
1079 | skge->flow_control = FLOW_MODE_SYMMETRIC; | 1098 | skge->flow_status = FLOW_STAT_SYMMETRIC; |
1080 | break; | 1099 | break; |
1081 | case PHY_B_AS_PRR: | 1100 | case PHY_B_AS_PRR: |
1082 | skge->flow_control = FLOW_MODE_REM_SEND; | 1101 | skge->flow_status = FLOW_STAT_REM_SEND; |
1083 | break; | 1102 | break; |
1084 | case PHY_B_AS_PRT: | 1103 | case PHY_B_AS_PRT: |
1085 | skge->flow_control = FLOW_MODE_LOC_SEND; | 1104 | skge->flow_status = FLOW_STAT_LOC_SEND; |
1086 | break; | 1105 | break; |
1087 | default: | 1106 | default: |
1088 | skge->flow_control = FLOW_MODE_NONE; | 1107 | skge->flow_status = FLOW_STAT_NONE; |
1089 | } | 1108 | } |
1090 | skge->speed = SPEED_1000; | 1109 | skge->speed = SPEED_1000; |
1091 | } | 1110 | } |
@@ -1283,15 +1302,20 @@ static void xm_check_link(struct net_device *dev) | |||
1283 | } | 1302 | } |
1284 | 1303 | ||
1285 | /* We are using IEEE 802.3z/D5.0 Table 37-4 */ | 1304 | /* We are using IEEE 802.3z/D5.0 Table 37-4 */ |
1286 | if (lpa & PHY_X_P_SYM_MD) | 1305 | if ((skge->flow_control == FLOW_MODE_SYMMETRIC || |
1287 | skge->flow_control = FLOW_MODE_SYMMETRIC; | 1306 | skge->flow_control == FLOW_MODE_SYM_OR_REM) && |
1288 | else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) | 1307 | (lpa & PHY_X_P_SYM_MD)) |
1289 | skge->flow_control = FLOW_MODE_REM_SEND; | 1308 | skge->flow_status = FLOW_STAT_SYMMETRIC; |
1290 | else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) | 1309 | else if (skge->flow_control == FLOW_MODE_SYM_OR_REM && |
1291 | skge->flow_control = FLOW_MODE_LOC_SEND; | 1310 | (lpa & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) |
1311 | /* Enable PAUSE receive, disable PAUSE transmit */ | ||
1312 | skge->flow_status = FLOW_STAT_REM_SEND; | ||
1313 | else if (skge->flow_control == FLOW_MODE_LOC_SEND && | ||
1314 | (lpa & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) | ||
1315 | /* Disable PAUSE receive, enable PAUSE transmit */ | ||
1316 | skge->flow_status = FLOW_STAT_LOC_SEND; | ||
1292 | else | 1317 | else |
1293 | skge->flow_control = FLOW_MODE_NONE; | 1318 | skge->flow_status = FLOW_STAT_NONE; |
1294 | |||
1295 | 1319 | ||
1296 | skge->speed = SPEED_1000; | 1320 | skge->speed = SPEED_1000; |
1297 | } | 1321 | } |
@@ -1602,8 +1626,8 @@ static void genesis_link_up(struct skge_port *skge) | |||
1602 | * enabling pause frame reception is required for 1000BT | 1626 | * enabling pause frame reception is required for 1000BT |
1603 | * because the XMAC is not reset if the link is going down | 1627 | * because the XMAC is not reset if the link is going down |
1604 | */ | 1628 | */ |
1605 | if (skge->flow_control == FLOW_MODE_NONE || | 1629 | if (skge->flow_status == FLOW_STAT_NONE || |
1606 | skge->flow_control == FLOW_MODE_LOC_SEND) | 1630 | skge->flow_status == FLOW_STAT_LOC_SEND) |
1607 | /* Disable Pause Frame Reception */ | 1631 | /* Disable Pause Frame Reception */ |
1608 | cmd |= XM_MMU_IGN_PF; | 1632 | cmd |= XM_MMU_IGN_PF; |
1609 | else | 1633 | else |
@@ -1613,8 +1637,8 @@ static void genesis_link_up(struct skge_port *skge) | |||
1613 | xm_write16(hw, port, XM_MMU_CMD, cmd); | 1637 | xm_write16(hw, port, XM_MMU_CMD, cmd); |
1614 | 1638 | ||
1615 | mode = xm_read32(hw, port, XM_MODE); | 1639 | mode = xm_read32(hw, port, XM_MODE); |
1616 | if (skge->flow_control == FLOW_MODE_SYMMETRIC || | 1640 | if (skge->flow_status== FLOW_STAT_SYMMETRIC || |
1617 | skge->flow_control == FLOW_MODE_LOC_SEND) { | 1641 | skge->flow_status == FLOW_STAT_LOC_SEND) { |
1618 | /* | 1642 | /* |
1619 | * Configure Pause Frame Generation | 1643 | * Configure Pause Frame Generation |
1620 | * Use internal and external Pause Frame Generation. | 1644 | * Use internal and external Pause Frame Generation. |
@@ -1938,6 +1962,11 @@ static void yukon_mac_init(struct skge_hw *hw, int port) | |||
1938 | case FLOW_MODE_LOC_SEND: | 1962 | case FLOW_MODE_LOC_SEND: |
1939 | /* disable Rx flow-control */ | 1963 | /* disable Rx flow-control */ |
1940 | reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS; | 1964 | reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS; |
1965 | break; | ||
1966 | case FLOW_MODE_SYMMETRIC: | ||
1967 | case FLOW_MODE_SYM_OR_REM: | ||
1968 | /* enable Tx & Rx flow-control */ | ||
1969 | break; | ||
1941 | } | 1970 | } |
1942 | 1971 | ||
1943 | gma_write16(hw, port, GM_GP_CTRL, reg); | 1972 | gma_write16(hw, port, GM_GP_CTRL, reg); |
@@ -2132,13 +2161,11 @@ static void yukon_link_down(struct skge_port *skge) | |||
2132 | ctrl &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); | 2161 | ctrl &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); |
2133 | gma_write16(hw, port, GM_GP_CTRL, ctrl); | 2162 | gma_write16(hw, port, GM_GP_CTRL, ctrl); |
2134 | 2163 | ||
2135 | if (skge->flow_control == FLOW_MODE_REM_SEND) { | 2164 | if (skge->flow_status == FLOW_STAT_REM_SEND) { |
2165 | ctrl = gm_phy_read(hw, port, PHY_MARV_AUNE_ADV); | ||
2166 | ctrl |= PHY_M_AN_ASP; | ||
2136 | /* restore Asymmetric Pause bit */ | 2167 | /* restore Asymmetric Pause bit */ |
2137 | gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, | 2168 | gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, ctrl); |
2138 | gm_phy_read(hw, port, | ||
2139 | PHY_MARV_AUNE_ADV) | ||
2140 | | PHY_M_AN_ASP); | ||
2141 | |||
2142 | } | 2169 | } |
2143 | 2170 | ||
2144 | yukon_reset(hw, port); | 2171 | yukon_reset(hw, port); |
@@ -2185,19 +2212,19 @@ static void yukon_phy_intr(struct skge_port *skge) | |||
2185 | /* We are using IEEE 802.3z/D5.0 Table 37-4 */ | 2212 | /* We are using IEEE 802.3z/D5.0 Table 37-4 */ |
2186 | switch (phystat & PHY_M_PS_PAUSE_MSK) { | 2213 | switch (phystat & PHY_M_PS_PAUSE_MSK) { |
2187 | case PHY_M_PS_PAUSE_MSK: | 2214 | case PHY_M_PS_PAUSE_MSK: |
2188 | skge->flow_control = FLOW_MODE_SYMMETRIC; | 2215 | skge->flow_status = FLOW_STAT_SYMMETRIC; |
2189 | break; | 2216 | break; |
2190 | case PHY_M_PS_RX_P_EN: | 2217 | case PHY_M_PS_RX_P_EN: |
2191 | skge->flow_control = FLOW_MODE_REM_SEND; | 2218 | skge->flow_status = FLOW_STAT_REM_SEND; |
2192 | break; | 2219 | break; |
2193 | case PHY_M_PS_TX_P_EN: | 2220 | case PHY_M_PS_TX_P_EN: |
2194 | skge->flow_control = FLOW_MODE_LOC_SEND; | 2221 | skge->flow_status = FLOW_STAT_LOC_SEND; |
2195 | break; | 2222 | break; |
2196 | default: | 2223 | default: |
2197 | skge->flow_control = FLOW_MODE_NONE; | 2224 | skge->flow_status = FLOW_STAT_NONE; |
2198 | } | 2225 | } |
2199 | 2226 | ||
2200 | if (skge->flow_control == FLOW_MODE_NONE || | 2227 | if (skge->flow_status == FLOW_STAT_NONE || |
2201 | (skge->speed < SPEED_1000 && skge->duplex == DUPLEX_HALF)) | 2228 | (skge->speed < SPEED_1000 && skge->duplex == DUPLEX_HALF)) |
2202 | skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); | 2229 | skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); |
2203 | else | 2230 | else |
@@ -3420,7 +3447,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, | |||
3420 | 3447 | ||
3421 | /* Auto speed and flow control */ | 3448 | /* Auto speed and flow control */ |
3422 | skge->autoneg = AUTONEG_ENABLE; | 3449 | skge->autoneg = AUTONEG_ENABLE; |
3423 | skge->flow_control = FLOW_MODE_SYMMETRIC; | 3450 | skge->flow_control = FLOW_MODE_SYM_OR_REM; |
3424 | skge->duplex = -1; | 3451 | skge->duplex = -1; |
3425 | skge->speed = -1; | 3452 | skge->speed = -1; |
3426 | skge->advertising = skge_supported_modes(hw); | 3453 | skge->advertising = skge_supported_modes(hw); |