diff options
-rw-r--r-- | drivers/net/skge.c | 129 | ||||
-rw-r--r-- | drivers/net/skge.h | 22 |
2 files changed, 95 insertions, 56 deletions
diff --git a/drivers/net/skge.c b/drivers/net/skge.c index c19f49bce7a..d844a837a8f 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); |
diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 9cc955c1250..537c0aaa1db 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 | ||
2430 | enum { | 2430 | enum 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 | |||
2439 | enum 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 | |||
2437 | struct skge_port { | 2448 | struct 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 */ |