diff options
-rw-r--r-- | drivers/net/sky2.c | 115 | ||||
-rw-r--r-- | drivers/net/sky2.h | 11 |
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 */ | ||
288 | static 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 */ | ||
296 | static 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 */ | ||
304 | static 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 | |||
287 | static void sky2_phy_init(struct sky2_hw *hw, unsigned port) | 312 | static 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 | ||
1655 | static void sky2_link_down(struct sky2_port *sky2) | 1664 | static 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 | ||
1695 | static 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 | |||
1686 | static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) | 1703 | static 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 | ||
1831 | enum flow_control { | ||
1832 | FC_NONE = 0, | ||
1833 | FC_TX = 1, | ||
1834 | FC_RX = 2, | ||
1835 | FC_BOTH = 3, | ||
1836 | }; | ||
1837 | |||
1831 | struct sky2_port { | 1838 | struct 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 | ||