aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2006-09-06 15:44:47 -0400
committerJeff Garzik <jeff@garzik.org>2006-09-13 13:27:44 -0400
commit2eaba1a280b6380f5b1238c53ce62e4381fc5f97 (patch)
tree4b161be011f0bb6adeea1c49c5fef5e84297e26d
parent6aa20a2235535605db6d6d2bd850298b2fe7f31e (diff)
[PATCH] sky2: tx pause bug fix
Fix problems with transmit pause frames. The driver was telling the GMAC to flush (not process) pause frames. Manually disabling pause wasn't working because of problems in the setup. This maybe the cause of the lockup under load. http://bugzilla.kernel.org/show_bug.cgi?id=6839 Patch against netdev-2.6 git tree Signed-off-by: Stephen Hemminger <shemminger@osdl.org> Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r--drivers/net/sky2.c123
-rw-r--r--drivers/net/sky2.h2
2 files changed, 43 insertions, 82 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 7ce0663baf45..a3a4ab26044a 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -289,7 +289,7 @@ static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port)
289static void sky2_phy_init(struct sky2_hw *hw, unsigned port) 289static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
290{ 290{
291 struct sky2_port *sky2 = netdev_priv(hw->dev[port]); 291 struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
292 u16 ctrl, ct1000, adv, pg, ledctrl, ledover; 292 u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg;
293 293
294 if (sky2->autoneg == AUTONEG_ENABLE && 294 if (sky2->autoneg == AUTONEG_ENABLE &&
295 !(hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) { 295 !(hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
@@ -358,6 +358,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
358 ctrl = 0; 358 ctrl = 0;
359 ct1000 = 0; 359 ct1000 = 0;
360 adv = PHY_AN_CSMA; 360 adv = PHY_AN_CSMA;
361 reg = 0;
361 362
362 if (sky2->autoneg == AUTONEG_ENABLE) { 363 if (sky2->autoneg == AUTONEG_ENABLE) {
363 if (hw->copper) { 364 if (hw->copper) {
@@ -390,21 +391,46 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
390 /* forced speed/duplex settings */ 391 /* forced speed/duplex settings */
391 ct1000 = PHY_M_1000C_MSE; 392 ct1000 = PHY_M_1000C_MSE;
392 393
393 if (sky2->duplex == DUPLEX_FULL) 394 /* Disable auto update for duplex flow control and speed */
394 ctrl |= PHY_CT_DUP_MD; 395 reg |= GM_GPCR_AU_ALL_DIS;
395 396
396 switch (sky2->speed) { 397 switch (sky2->speed) {
397 case SPEED_1000: 398 case SPEED_1000:
398 ctrl |= PHY_CT_SP1000; 399 ctrl |= PHY_CT_SP1000;
400 reg |= GM_GPCR_SPEED_1000;
399 break; 401 break;
400 case SPEED_100: 402 case SPEED_100:
401 ctrl |= PHY_CT_SP100; 403 ctrl |= PHY_CT_SP100;
404 reg |= GM_GPCR_SPEED_100;
402 break; 405 break;
403 } 406 }
404 407
408 if (sky2->duplex == DUPLEX_FULL) {
409 reg |= GM_GPCR_DUP_FULL;
410 ctrl |= PHY_CT_DUP_MD;
411 } else if (sky2->speed != SPEED_1000 && hw->chip_id != CHIP_ID_YUKON_EC_U) {
412 /* Turn off flow control for 10/100mbps */
413 sky2->rx_pause = 0;
414 sky2->tx_pause = 0;
415 }
416
417 if (!sky2->rx_pause)
418 reg |= GM_GPCR_FC_RX_DIS;
419
420 if (!sky2->tx_pause)
421 reg |= GM_GPCR_FC_TX_DIS;
422
423 /* Forward pause packets to GMAC? */
424 if (sky2->tx_pause || sky2->rx_pause)
425 sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
426 else
427 sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
428
405 ctrl |= PHY_CT_RESET; 429 ctrl |= PHY_CT_RESET;
406 } 430 }
407 431
432 gma_write16(hw, port, GM_GP_CTRL, reg);
433
408 if (hw->chip_id != CHIP_ID_YUKON_FE) 434 if (hw->chip_id != CHIP_ID_YUKON_FE)
409 gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000); 435 gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);
410 436
@@ -508,6 +534,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
508 gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover); 534 gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
509 535
510 } 536 }
537
511 /* Enable phy interrupt on auto-negotiation complete (or link up) */ 538 /* Enable phy interrupt on auto-negotiation complete (or link up) */
512 if (sky2->autoneg == AUTONEG_ENABLE) 539 if (sky2->autoneg == AUTONEG_ENABLE)
513 gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL); 540 gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL);
@@ -570,49 +597,11 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
570 gm_phy_read(hw, 1, PHY_MARV_INT_MASK) != 0); 597 gm_phy_read(hw, 1, PHY_MARV_INT_MASK) != 0);
571 } 598 }
572 599
573 if (sky2->autoneg == AUTONEG_DISABLE) {
574 reg = gma_read16(hw, port, GM_GP_CTRL);
575 reg |= GM_GPCR_AU_ALL_DIS;
576 gma_write16(hw, port, GM_GP_CTRL, reg);
577 gma_read16(hw, port, GM_GP_CTRL);
578
579 switch (sky2->speed) {
580 case SPEED_1000:
581 reg &= ~GM_GPCR_SPEED_100;
582 reg |= GM_GPCR_SPEED_1000;
583 break;
584 case SPEED_100:
585 reg &= ~GM_GPCR_SPEED_1000;
586 reg |= GM_GPCR_SPEED_100;
587 break;
588 case SPEED_10:
589 reg &= ~(GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100);
590 break;
591 }
592
593 if (sky2->duplex == DUPLEX_FULL)
594 reg |= GM_GPCR_DUP_FULL;
595
596 /* turn off pause in 10/100mbps half duplex */
597 else if (sky2->speed != SPEED_1000 &&
598 hw->chip_id != CHIP_ID_YUKON_EC_U)
599 sky2->tx_pause = sky2->rx_pause = 0;
600 } else
601 reg = GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100 | GM_GPCR_DUP_FULL;
602
603 if (!sky2->tx_pause && !sky2->rx_pause) {
604 sky2_write32(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
605 reg |=
606 GM_GPCR_FC_TX_DIS | GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
607 } else if (sky2->tx_pause && !sky2->rx_pause) {
608 /* disable Rx flow-control */
609 reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
610 }
611
612 gma_write16(hw, port, GM_GP_CTRL, reg);
613
614 sky2_read16(hw, SK_REG(port, GMAC_IRQ_SRC)); 600 sky2_read16(hw, SK_REG(port, GMAC_IRQ_SRC));
615 601
602 /* Enable Transmit FIFO Underrun */
603 sky2_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK);
604
616 spin_lock_bh(&sky2->phy_lock); 605 spin_lock_bh(&sky2->phy_lock);
617 sky2_phy_init(hw, port); 606 sky2_phy_init(hw, port);
618 spin_unlock_bh(&sky2->phy_lock); 607 spin_unlock_bh(&sky2->phy_lock);
@@ -1529,40 +1518,10 @@ static void sky2_link_up(struct sky2_port *sky2)
1529 unsigned port = sky2->port; 1518 unsigned port = sky2->port;
1530 u16 reg; 1519 u16 reg;
1531 1520
1532 /* Enable Transmit FIFO Underrun */
1533 sky2_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK);
1534
1535 reg = gma_read16(hw, port, GM_GP_CTRL);
1536 if (sky2->autoneg == AUTONEG_DISABLE) {
1537 reg |= GM_GPCR_AU_ALL_DIS;
1538
1539 /* Is write/read necessary? Copied from sky2_mac_init */
1540 gma_write16(hw, port, GM_GP_CTRL, reg);
1541 gma_read16(hw, port, GM_GP_CTRL);
1542
1543 switch (sky2->speed) {
1544 case SPEED_1000:
1545 reg &= ~GM_GPCR_SPEED_100;
1546 reg |= GM_GPCR_SPEED_1000;
1547 break;
1548 case SPEED_100:
1549 reg &= ~GM_GPCR_SPEED_1000;
1550 reg |= GM_GPCR_SPEED_100;
1551 break;
1552 case SPEED_10:
1553 reg &= ~(GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100);
1554 break;
1555 }
1556 } else
1557 reg &= ~GM_GPCR_AU_ALL_DIS;
1558
1559 if (sky2->duplex == DUPLEX_FULL || sky2->autoneg == AUTONEG_ENABLE)
1560 reg |= GM_GPCR_DUP_FULL;
1561
1562 /* enable Rx/Tx */ 1521 /* enable Rx/Tx */
1522 reg = gma_read16(hw, port, GM_GP_CTRL);
1563 reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA; 1523 reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA;
1564 gma_write16(hw, port, GM_GP_CTRL, reg); 1524 gma_write16(hw, port, GM_GP_CTRL, reg);
1565 gma_read16(hw, port, GM_GP_CTRL);
1566 1525
1567 gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK); 1526 gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
1568 1527
@@ -1616,7 +1575,6 @@ static void sky2_link_down(struct sky2_port *sky2)
1616 reg = gma_read16(hw, port, GM_GP_CTRL); 1575 reg = gma_read16(hw, port, GM_GP_CTRL);
1617 reg &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); 1576 reg &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
1618 gma_write16(hw, port, GM_GP_CTRL, reg); 1577 gma_write16(hw, port, GM_GP_CTRL, reg);
1619 gma_read16(hw, port, GM_GP_CTRL); /* PCI post */
1620 1578
1621 if (sky2->rx_pause && !sky2->tx_pause) { 1579 if (sky2->rx_pause && !sky2->tx_pause) {
1622 /* restore Asymmetric Pause bit */ 1580 /* restore Asymmetric Pause bit */
@@ -1633,6 +1591,7 @@ static void sky2_link_down(struct sky2_port *sky2)
1633 1591
1634 if (netif_msg_link(sky2)) 1592 if (netif_msg_link(sky2))
1635 printk(KERN_INFO PFX "%s: Link is down.\n", sky2->netdev->name); 1593 printk(KERN_INFO PFX "%s: Link is down.\n", sky2->netdev->name);
1594
1636 sky2_phy_init(hw, port); 1595 sky2_phy_init(hw, port);
1637} 1596}
1638 1597
@@ -1673,8 +1632,11 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
1673 sky2->rx_pause = (aux & PHY_M_PS_RX_P_EN) != 0; 1632 sky2->rx_pause = (aux & PHY_M_PS_RX_P_EN) != 0;
1674 sky2->tx_pause = (aux & PHY_M_PS_TX_P_EN) != 0; 1633 sky2->tx_pause = (aux & PHY_M_PS_TX_P_EN) != 0;
1675 1634
1676 if ((sky2->tx_pause || sky2->rx_pause) 1635 if (sky2->duplex == DUPLEX_HALF && sky2->speed != SPEED_1000
1677 && !(sky2->speed < SPEED_1000 && sky2->duplex == DUPLEX_HALF)) 1636 && hw->chip_id != CHIP_ID_YUKON_EC_U)
1637 sky2->rx_pause = sky2->tx_pause = 0;
1638
1639 if (sky2->rx_pause || sky2->tx_pause)
1678 sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON); 1640 sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
1679 else 1641 else
1680 sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); 1642 sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
@@ -1700,7 +1662,7 @@ static void sky2_phy_intr(struct sky2_hw *hw, unsigned port)
1700 printk(KERN_INFO PFX "%s: phy interrupt status 0x%x 0x%x\n", 1662 printk(KERN_INFO PFX "%s: phy interrupt status 0x%x 0x%x\n",
1701 sky2->netdev->name, istatus, phystat); 1663 sky2->netdev->name, istatus, phystat);
1702 1664
1703 if (istatus & PHY_M_IS_AN_COMPL) { 1665 if (sky2->autoneg == AUTONEG_ENABLE && (istatus & PHY_M_IS_AN_COMPL)) {
1704 if (sky2_autoneg_done(sky2, phystat) == 0) 1666 if (sky2_autoneg_done(sky2, phystat) == 0)
1705 sky2_link_up(sky2); 1667 sky2_link_up(sky2);
1706 goto out; 1668 goto out;
@@ -2890,7 +2852,6 @@ static int sky2_set_pauseparam(struct net_device *dev,
2890 struct ethtool_pauseparam *ecmd) 2852 struct ethtool_pauseparam *ecmd)
2891{ 2853{
2892 struct sky2_port *sky2 = netdev_priv(dev); 2854 struct sky2_port *sky2 = netdev_priv(dev);
2893 int err = 0;
2894 2855
2895 sky2->autoneg = ecmd->autoneg; 2856 sky2->autoneg = ecmd->autoneg;
2896 sky2->tx_pause = ecmd->tx_pause != 0; 2857 sky2->tx_pause = ecmd->tx_pause != 0;
@@ -2898,7 +2859,7 @@ static int sky2_set_pauseparam(struct net_device *dev,
2898 2859
2899 sky2_phy_reinit(sky2); 2860 sky2_phy_reinit(sky2);
2900 2861
2901 return err; 2862 return 0;
2902} 2863}
2903 2864
2904static int sky2_get_coalesce(struct net_device *dev, 2865static int sky2_get_coalesce(struct net_device *dev,
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index fa8af9f503e4..a27194c874fc 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -1566,7 +1566,7 @@ enum {
1566 1566
1567 GMR_FS_ANY_ERR = GMR_FS_RX_FF_OV | GMR_FS_CRC_ERR | 1567 GMR_FS_ANY_ERR = GMR_FS_RX_FF_OV | GMR_FS_CRC_ERR |
1568 GMR_FS_FRAGMENT | GMR_FS_LONG_ERR | 1568 GMR_FS_FRAGMENT | GMR_FS_LONG_ERR |
1569 GMR_FS_MII_ERR | GMR_FS_BAD_FC | GMR_FS_GOOD_FC | 1569 GMR_FS_MII_ERR | GMR_FS_BAD_FC |
1570 GMR_FS_UN_SIZE | GMR_FS_JABBER, 1570 GMR_FS_UN_SIZE | GMR_FS_JABBER,
1571}; 1571};
1572 1572