aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sky2.c
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2006-10-17 13:24:13 -0400
committerStephen Hemminger <shemminger@osdl.org>2006-10-17 13:24:13 -0400
commit16ad91e1c686734aaa5664cd08af0b5e9bf3af61 (patch)
tree2e4c5d3e4932c66d2c00eddee81b2df0667970fe /drivers/net/sky2.c
parent7800fddcd05a7dc89276389b96664af4f7890ea7 (diff)
sky2: flow control setting fixes
The result of flow control negotiation should not limit the next negotiatition. If board is plugged into an old half duplex 10Mbit port, without pause, then replugged into a gigabit port, it should negotiate what is desired, not inherit that last negotiation. Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r--drivers/net/sky2.c115
1 files changed, 72 insertions, 43 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 20a8c34e6d53..b8f202169a75 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -284,6 +284,31 @@ static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port)
284 gma_write16(hw, port, GM_RX_CTRL, reg); 284 gma_write16(hw, port, GM_RX_CTRL, reg);
285} 285}
286 286
287/* flow control to advertise bits */
288static const u16 copper_fc_adv[] = {
289 [FC_NONE] = 0,
290 [FC_TX] = PHY_M_AN_ASP,
291 [FC_RX] = PHY_M_AN_PC,
292 [FC_BOTH] = PHY_M_AN_PC | PHY_M_AN_ASP,
293};
294
295/* flow control to advertise bits when using 1000BaseX */
296static const u16 fiber_fc_adv[] = {
297 [FC_BOTH] = PHY_M_P_BOTH_MD_X,
298 [FC_TX] = PHY_M_P_ASYM_MD_X,
299 [FC_RX] = PHY_M_P_SYM_MD_X,
300 [FC_NONE] = PHY_M_P_NO_PAUSE_X,
301};
302
303/* flow control to GMA disable bits */
304static const u16 gm_fc_disable[] = {
305 [FC_NONE] = GM_GPCR_FC_RX_DIS | GM_GPCR_FC_TX_DIS,
306 [FC_TX] = GM_GPCR_FC_RX_DIS,
307 [FC_RX] = GM_GPCR_FC_TX_DIS,
308 [FC_BOTH] = 0,
309};
310
311
287static void sky2_phy_init(struct sky2_hw *hw, unsigned port) 312static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
288{ 313{
289 struct sky2_port *sky2 = netdev_priv(hw->dev[port]); 314 struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
@@ -376,29 +401,14 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
376 if (sky2->advertising & ADVERTISED_10baseT_Half) 401 if (sky2->advertising & ADVERTISED_10baseT_Half)
377 adv |= PHY_M_AN_10_HD; 402 adv |= PHY_M_AN_10_HD;
378 403
379 /* desired flow control */ 404 adv |= copper_fc_adv[sky2->flow_mode];
380 if (sky2->tx_pause && sky2->rx_pause) /* both */
381 adv |= PHY_M_AN_PC | PHY_M_AN_ASP;
382 else if (sky2->tx_pause)
383 adv |= PHY_M_AN_ASP;
384 else if (sky2->rx_pause)
385 adv |= PHY_M_AN_PC;
386
387
388 } else { /* special defines for FIBER (88E1040S only) */ 405 } else { /* special defines for FIBER (88E1040S only) */
389 if (sky2->advertising & ADVERTISED_1000baseT_Full) 406 if (sky2->advertising & ADVERTISED_1000baseT_Full)
390 adv |= PHY_M_AN_1000X_AFD; 407 adv |= PHY_M_AN_1000X_AFD;
391 if (sky2->advertising & ADVERTISED_1000baseT_Half) 408 if (sky2->advertising & ADVERTISED_1000baseT_Half)
392 adv |= PHY_M_AN_1000X_AHD; 409 adv |= PHY_M_AN_1000X_AHD;
393 410
394 if (sky2->tx_pause && sky2->rx_pause) /* both */ 411 adv |= fiber_fc_adv[sky2->flow_mode];
395 adv |= PHY_M_P_BOTH_MD_X;
396 else if (sky2->tx_pause)
397 adv |= PHY_M_P_ASYM_MD_X;
398 else if (sky2->rx_pause)
399 adv |= PHY_M_P_SYM_MD_X;
400 else
401 adv |= PHY_M_P_NO_PAUSE_X;
402 } 412 }
403 413
404 /* Restart Auto-negotiation */ 414 /* Restart Auto-negotiation */
@@ -424,20 +434,14 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
424 if (sky2->duplex == DUPLEX_FULL) { 434 if (sky2->duplex == DUPLEX_FULL) {
425 reg |= GM_GPCR_DUP_FULL; 435 reg |= GM_GPCR_DUP_FULL;
426 ctrl |= PHY_CT_DUP_MD; 436 ctrl |= PHY_CT_DUP_MD;
427 } else if (sky2->speed != SPEED_1000 && hw->chip_id != CHIP_ID_YUKON_EC_U) { 437 } else if (sky2->speed < SPEED_1000)
428 /* Turn off flow control for 10/100mbps */ 438 sky2->flow_mode = FC_NONE;
429 sky2->rx_pause = 0;
430 sky2->tx_pause = 0;
431 }
432 439
433 if (!sky2->rx_pause)
434 reg |= GM_GPCR_FC_RX_DIS;
435 440
436 if (!sky2->tx_pause) 441 reg |= gm_fc_disable[sky2->flow_mode];
437 reg |= GM_GPCR_FC_TX_DIS;
438 442
439 /* Forward pause packets to GMAC? */ 443 /* Forward pause packets to GMAC? */
440 if (sky2->tx_pause || sky2->rx_pause) 444 if (sky2->flow_mode & FC_RX)
441 sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON); 445 sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
442 else 446 else
443 sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); 447 sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
@@ -1605,6 +1609,12 @@ static void sky2_link_up(struct sky2_port *sky2)
1605 struct sky2_hw *hw = sky2->hw; 1609 struct sky2_hw *hw = sky2->hw;
1606 unsigned port = sky2->port; 1610 unsigned port = sky2->port;
1607 u16 reg; 1611 u16 reg;
1612 static const char *fc_name[] = {
1613 [FC_NONE] = "none",
1614 [FC_TX] = "tx",
1615 [FC_RX] = "rx",
1616 [FC_BOTH] = "both",
1617 };
1608 1618
1609 /* enable Rx/Tx */ 1619 /* enable Rx/Tx */
1610 reg = gma_read16(hw, port, GM_GP_CTRL); 1620 reg = gma_read16(hw, port, GM_GP_CTRL);
@@ -1648,8 +1658,7 @@ static void sky2_link_up(struct sky2_port *sky2)
1648 "%s: Link is up at %d Mbps, %s duplex, flow control %s\n", 1658 "%s: Link is up at %d Mbps, %s duplex, flow control %s\n",
1649 sky2->netdev->name, sky2->speed, 1659 sky2->netdev->name, sky2->speed,
1650 sky2->duplex == DUPLEX_FULL ? "full" : "half", 1660 sky2->duplex == DUPLEX_FULL ? "full" : "half",
1651 (sky2->tx_pause && sky2->rx_pause) ? "both" : 1661 fc_name[sky2->flow_status]);
1652 sky2->tx_pause ? "tx" : sky2->rx_pause ? "rx" : "none");
1653} 1662}
1654 1663
1655static void sky2_link_down(struct sky2_port *sky2) 1664static void sky2_link_down(struct sky2_port *sky2)
@@ -1664,7 +1673,7 @@ static void sky2_link_down(struct sky2_port *sky2)
1664 reg &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); 1673 reg &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
1665 gma_write16(hw, port, GM_GP_CTRL, reg); 1674 gma_write16(hw, port, GM_GP_CTRL, reg);
1666 1675
1667 if (sky2->rx_pause && !sky2->tx_pause) { 1676 if (sky2->flow_status == FC_RX) {
1668 /* restore Asymmetric Pause bit */ 1677 /* restore Asymmetric Pause bit */
1669 gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, 1678 gm_phy_write(hw, port, PHY_MARV_AUNE_ADV,
1670 gm_phy_read(hw, port, PHY_MARV_AUNE_ADV) 1679 gm_phy_read(hw, port, PHY_MARV_AUNE_ADV)
@@ -1683,6 +1692,14 @@ static void sky2_link_down(struct sky2_port *sky2)
1683 sky2_phy_init(hw, port); 1692 sky2_phy_init(hw, port);
1684} 1693}
1685 1694
1695static enum flow_control sky2_flow(int rx, int tx)
1696{
1697 if (rx)
1698 return tx ? FC_BOTH : FC_RX;
1699 else
1700 return tx ? FC_TX : FC_NONE;
1701}
1702
1686static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) 1703static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
1687{ 1704{
1688 struct sky2_hw *hw = sky2->hw; 1705 struct sky2_hw *hw = sky2->hw;
@@ -1709,14 +1726,14 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
1709 if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) 1726 if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)
1710 aux >>= 6; 1727 aux >>= 6;
1711 1728
1712 sky2->rx_pause = (aux & PHY_M_PS_RX_P_EN) != 0; 1729 sky2->flow_status = sky2_flow(aux & PHY_M_PS_RX_P_EN,
1713 sky2->tx_pause = (aux & PHY_M_PS_TX_P_EN) != 0; 1730 aux & PHY_M_PS_TX_P_EN);
1714 1731
1715 if (sky2->duplex == DUPLEX_HALF && sky2->speed != SPEED_1000 1732 if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000
1716 && hw->chip_id != CHIP_ID_YUKON_EC_U) 1733 && hw->chip_id != CHIP_ID_YUKON_EC_U)
1717 sky2->rx_pause = sky2->tx_pause = 0; 1734 sky2->flow_status = FC_NONE;
1718 1735
1719 if (sky2->rx_pause || sky2->tx_pause) 1736 if (aux & PHY_M_PS_RX_P_EN)
1720 sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON); 1737 sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
1721 else 1738 else
1722 sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); 1739 sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
@@ -2729,7 +2746,7 @@ static int sky2_nway_reset(struct net_device *dev)
2729{ 2746{
2730 struct sky2_port *sky2 = netdev_priv(dev); 2747 struct sky2_port *sky2 = netdev_priv(dev);
2731 2748
2732 if (sky2->autoneg != AUTONEG_ENABLE) 2749 if (!netif_running(dev) || sky2->autoneg != AUTONEG_ENABLE)
2733 return -EINVAL; 2750 return -EINVAL;
2734 2751
2735 sky2_phy_reinit(sky2); 2752 sky2_phy_reinit(sky2);
@@ -2971,8 +2988,20 @@ static void sky2_get_pauseparam(struct net_device *dev,
2971{ 2988{
2972 struct sky2_port *sky2 = netdev_priv(dev); 2989 struct sky2_port *sky2 = netdev_priv(dev);
2973 2990
2974 ecmd->tx_pause = sky2->tx_pause; 2991 switch (sky2->flow_mode) {
2975 ecmd->rx_pause = sky2->rx_pause; 2992 case FC_NONE:
2993 ecmd->tx_pause = ecmd->rx_pause = 0;
2994 break;
2995 case FC_TX:
2996 ecmd->tx_pause = 1, ecmd->rx_pause = 0;
2997 break;
2998 case FC_RX:
2999 ecmd->tx_pause = 0, ecmd->rx_pause = 1;
3000 break;
3001 case FC_BOTH:
3002 ecmd->tx_pause = ecmd->rx_pause = 1;
3003 }
3004
2976 ecmd->autoneg = sky2->autoneg; 3005 ecmd->autoneg = sky2->autoneg;
2977} 3006}
2978 3007
@@ -2982,10 +3011,10 @@ static int sky2_set_pauseparam(struct net_device *dev,
2982 struct sky2_port *sky2 = netdev_priv(dev); 3011 struct sky2_port *sky2 = netdev_priv(dev);
2983 3012
2984 sky2->autoneg = ecmd->autoneg; 3013 sky2->autoneg = ecmd->autoneg;
2985 sky2->tx_pause = ecmd->tx_pause != 0; 3014 sky2->flow_mode = sky2_flow(ecmd->rx_pause, ecmd->tx_pause);
2986 sky2->rx_pause = ecmd->rx_pause != 0;
2987 3015
2988 sky2_phy_reinit(sky2); 3016 if (netif_running(dev))
3017 sky2_phy_reinit(sky2);
2989 3018
2990 return 0; 3019 return 0;
2991} 3020}
@@ -3215,8 +3244,8 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
3215 3244
3216 /* Auto speed and flow control */ 3245 /* Auto speed and flow control */
3217 sky2->autoneg = AUTONEG_ENABLE; 3246 sky2->autoneg = AUTONEG_ENABLE;
3218 sky2->tx_pause = 1; 3247 sky2->flow_mode = FC_BOTH;
3219 sky2->rx_pause = 1; 3248
3220 sky2->duplex = -1; 3249 sky2->duplex = -1;
3221 sky2->speed = -1; 3250 sky2->speed = -1;
3222 sky2->advertising = sky2_supported_modes(hw); 3251 sky2->advertising = sky2_supported_modes(hw);