aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/sky2.c115
-rw-r--r--drivers/net/sky2.h11
2 files changed, 81 insertions, 45 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);
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 0a8d8210679a..3f05492da703 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -1828,6 +1828,13 @@ struct rx_ring_info {
1828 dma_addr_t frag_addr[ETH_JUMBO_MTU >> PAGE_SHIFT]; 1828 dma_addr_t frag_addr[ETH_JUMBO_MTU >> PAGE_SHIFT];
1829}; 1829};
1830 1830
1831enum flow_control {
1832 FC_NONE = 0,
1833 FC_TX = 1,
1834 FC_RX = 2,
1835 FC_BOTH = 3,
1836};
1837
1831struct sky2_port { 1838struct sky2_port {
1832 struct sky2_hw *hw; 1839 struct sky2_hw *hw;
1833 struct net_device *netdev; 1840 struct net_device *netdev;
@@ -1864,9 +1871,9 @@ struct sky2_port {
1864 u16 speed; /* SPEED_1000, SPEED_100, ... */ 1871 u16 speed; /* SPEED_1000, SPEED_100, ... */
1865 u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */ 1872 u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */
1866 u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */ 1873 u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */
1867 u8 rx_pause;
1868 u8 tx_pause;
1869 u8 rx_csum; 1874 u8 rx_csum;
1875 enum flow_control flow_mode;
1876 enum flow_control flow_status;
1870 1877
1871 struct net_device_stats net_stats; 1878 struct net_device_stats net_stats;
1872 1879