aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2006-10-05 18:49:52 -0400
committerJeff Garzik <jeff@garzik.org>2006-10-11 04:06:09 -0400
commit5d5c8e03786691d0d083142b922edce8609c0fd5 (patch)
treea821bad020b3a961e9af512803aca9804169fcd1 /drivers
parent4b67be999ed5bfb1bfe4cc502d37d59b4f6b6b7f (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')
-rw-r--r--drivers/net/skge.c129
-rw-r--r--drivers/net/skge.h22
2 files changed, 95 insertions, 56 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
498static int skge_set_pauseparam(struct net_device *dev, 497static 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
863static 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
857static void skge_link_up(struct skge_port *skge) 880static 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
877static void skge_link_down(struct skge_port *skge) 897static 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);
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index 9cc955c12503..537c0aaa1db8 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -2427,13 +2427,24 @@ struct skge_hw {
2427 struct mutex phy_mutex; 2427 struct mutex phy_mutex;
2428}; 2428};
2429 2429
2430enum { 2430enum pause_control {
2431 FLOW_MODE_NONE = 0, /* No Flow-Control */ 2431 FLOW_MODE_NONE = 1, /* No Flow-Control */
2432 FLOW_MODE_LOC_SEND = 1, /* Local station sends PAUSE */ 2432 FLOW_MODE_LOC_SEND = 2, /* Local station sends PAUSE */
2433 FLOW_MODE_REM_SEND = 2, /* Symmetric or just remote */
2434 FLOW_MODE_SYMMETRIC = 3, /* Both stations may send PAUSE */ 2433 FLOW_MODE_SYMMETRIC = 3, /* Both stations may send PAUSE */
2434 FLOW_MODE_SYM_OR_REM = 4, /* Both stations may send PAUSE or
2435 * just the remote station may send PAUSE
2436 */
2437};
2438
2439enum pause_status {
2440 FLOW_STAT_INDETERMINATED=0, /* indeterminated */
2441 FLOW_STAT_NONE, /* No Flow Control */
2442 FLOW_STAT_REM_SEND, /* Remote Station sends PAUSE */
2443 FLOW_STAT_LOC_SEND, /* Local station sends PAUSE */
2444 FLOW_STAT_SYMMETRIC, /* Both station may send PAUSE */
2435}; 2445};
2436 2446
2447
2437struct skge_port { 2448struct skge_port {
2438 u32 msg_enable; 2449 u32 msg_enable;
2439 struct skge_hw *hw; 2450 struct skge_hw *hw;
@@ -2446,9 +2457,10 @@ struct skge_port {
2446 struct net_device_stats net_stats; 2457 struct net_device_stats net_stats;
2447 2458
2448 struct work_struct link_thread; 2459 struct work_struct link_thread;
2460 enum pause_control flow_control;
2461 enum pause_status flow_status;
2449 u8 rx_csum; 2462 u8 rx_csum;
2450 u8 blink_on; 2463 u8 blink_on;
2451 u8 flow_control;
2452 u8 wol; 2464 u8 wol;
2453 u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */ 2465 u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */
2454 u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */ 2466 u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */