|
@@ -289,7 +289,7 @@ static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port)
|
|
static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
|
|
static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
|
|
{
|
|
{
|
|
struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
|
|
struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
|
|
- u16 ctrl, ct1000, adv, pg, ledctrl, ledover;
|
|
|
|
|
|
+ u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg;
|
|
|
|
|
|
if (sky2->autoneg == AUTONEG_ENABLE &&
|
|
if (sky2->autoneg == AUTONEG_ENABLE &&
|
|
!(hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
|
|
!(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)
|
|
ctrl = 0;
|
|
ctrl = 0;
|
|
ct1000 = 0;
|
|
ct1000 = 0;
|
|
adv = PHY_AN_CSMA;
|
|
adv = PHY_AN_CSMA;
|
|
|
|
+ reg = 0;
|
|
|
|
|
|
if (sky2->autoneg == AUTONEG_ENABLE) {
|
|
if (sky2->autoneg == AUTONEG_ENABLE) {
|
|
if (hw->copper) {
|
|
if (hw->copper) {
|
|
@@ -390,21 +391,46 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
|
|
/* forced speed/duplex settings */
|
|
/* forced speed/duplex settings */
|
|
ct1000 = PHY_M_1000C_MSE;
|
|
ct1000 = PHY_M_1000C_MSE;
|
|
|
|
|
|
- if (sky2->duplex == DUPLEX_FULL)
|
|
|
|
- ctrl |= PHY_CT_DUP_MD;
|
|
|
|
|
|
+ /* Disable auto update for duplex flow control and speed */
|
|
|
|
+ reg |= GM_GPCR_AU_ALL_DIS;
|
|
|
|
|
|
switch (sky2->speed) {
|
|
switch (sky2->speed) {
|
|
case SPEED_1000:
|
|
case SPEED_1000:
|
|
ctrl |= PHY_CT_SP1000;
|
|
ctrl |= PHY_CT_SP1000;
|
|
|
|
+ reg |= GM_GPCR_SPEED_1000;
|
|
break;
|
|
break;
|
|
case SPEED_100:
|
|
case SPEED_100:
|
|
ctrl |= PHY_CT_SP100;
|
|
ctrl |= PHY_CT_SP100;
|
|
|
|
+ reg |= GM_GPCR_SPEED_100;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (sky2->duplex == DUPLEX_FULL) {
|
|
|
|
+ reg |= GM_GPCR_DUP_FULL;
|
|
|
|
+ ctrl |= PHY_CT_DUP_MD;
|
|
|
|
+ } else if (sky2->speed != SPEED_1000 && hw->chip_id != CHIP_ID_YUKON_EC_U) {
|
|
|
|
+ /* Turn off flow control for 10/100mbps */
|
|
|
|
+ sky2->rx_pause = 0;
|
|
|
|
+ sky2->tx_pause = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!sky2->rx_pause)
|
|
|
|
+ reg |= GM_GPCR_FC_RX_DIS;
|
|
|
|
+
|
|
|
|
+ if (!sky2->tx_pause)
|
|
|
|
+ reg |= GM_GPCR_FC_TX_DIS;
|
|
|
|
+
|
|
|
|
+ /* Forward pause packets to GMAC? */
|
|
|
|
+ if (sky2->tx_pause || sky2->rx_pause)
|
|
|
|
+ sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
|
|
|
|
+ else
|
|
|
|
+ sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
|
|
|
|
+
|
|
ctrl |= PHY_CT_RESET;
|
|
ctrl |= PHY_CT_RESET;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ gma_write16(hw, port, GM_GP_CTRL, reg);
|
|
|
|
+
|
|
if (hw->chip_id != CHIP_ID_YUKON_FE)
|
|
if (hw->chip_id != CHIP_ID_YUKON_FE)
|
|
gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);
|
|
gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);
|
|
|
|
|
|
@@ -508,6 +534,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
|
|
gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
|
|
gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
|
|
|
|
|
|
}
|
|
}
|
|
|
|
+
|
|
/* Enable phy interrupt on auto-negotiation complete (or link up) */
|
|
/* Enable phy interrupt on auto-negotiation complete (or link up) */
|
|
if (sky2->autoneg == AUTONEG_ENABLE)
|
|
if (sky2->autoneg == AUTONEG_ENABLE)
|
|
gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL);
|
|
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)
|
|
gm_phy_read(hw, 1, PHY_MARV_INT_MASK) != 0);
|
|
gm_phy_read(hw, 1, PHY_MARV_INT_MASK) != 0);
|
|
}
|
|
}
|
|
|
|
|
|
- if (sky2->autoneg == AUTONEG_DISABLE) {
|
|
|
|
- reg = gma_read16(hw, port, GM_GP_CTRL);
|
|
|
|
- reg |= GM_GPCR_AU_ALL_DIS;
|
|
|
|
- gma_write16(hw, port, GM_GP_CTRL, reg);
|
|
|
|
- gma_read16(hw, port, GM_GP_CTRL);
|
|
|
|
-
|
|
|
|
- switch (sky2->speed) {
|
|
|
|
- case SPEED_1000:
|
|
|
|
- reg &= ~GM_GPCR_SPEED_100;
|
|
|
|
- reg |= GM_GPCR_SPEED_1000;
|
|
|
|
- break;
|
|
|
|
- case SPEED_100:
|
|
|
|
- reg &= ~GM_GPCR_SPEED_1000;
|
|
|
|
- reg |= GM_GPCR_SPEED_100;
|
|
|
|
- break;
|
|
|
|
- case SPEED_10:
|
|
|
|
- reg &= ~(GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (sky2->duplex == DUPLEX_FULL)
|
|
|
|
- reg |= GM_GPCR_DUP_FULL;
|
|
|
|
-
|
|
|
|
- /* turn off pause in 10/100mbps half duplex */
|
|
|
|
- else if (sky2->speed != SPEED_1000 &&
|
|
|
|
- hw->chip_id != CHIP_ID_YUKON_EC_U)
|
|
|
|
- sky2->tx_pause = sky2->rx_pause = 0;
|
|
|
|
- } else
|
|
|
|
- reg = GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100 | GM_GPCR_DUP_FULL;
|
|
|
|
-
|
|
|
|
- if (!sky2->tx_pause && !sky2->rx_pause) {
|
|
|
|
- sky2_write32(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
|
|
|
|
- reg |=
|
|
|
|
- GM_GPCR_FC_TX_DIS | GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
|
|
|
|
- } else if (sky2->tx_pause && !sky2->rx_pause) {
|
|
|
|
- /* disable Rx flow-control */
|
|
|
|
- reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- gma_write16(hw, port, GM_GP_CTRL, reg);
|
|
|
|
-
|
|
|
|
sky2_read16(hw, SK_REG(port, GMAC_IRQ_SRC));
|
|
sky2_read16(hw, SK_REG(port, GMAC_IRQ_SRC));
|
|
|
|
|
|
|
|
+ /* Enable Transmit FIFO Underrun */
|
|
|
|
+ sky2_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK);
|
|
|
|
+
|
|
spin_lock_bh(&sky2->phy_lock);
|
|
spin_lock_bh(&sky2->phy_lock);
|
|
sky2_phy_init(hw, port);
|
|
sky2_phy_init(hw, port);
|
|
spin_unlock_bh(&sky2->phy_lock);
|
|
spin_unlock_bh(&sky2->phy_lock);
|
|
@@ -1529,40 +1518,10 @@ static void sky2_link_up(struct sky2_port *sky2)
|
|
unsigned port = sky2->port;
|
|
unsigned port = sky2->port;
|
|
u16 reg;
|
|
u16 reg;
|
|
|
|
|
|
- /* Enable Transmit FIFO Underrun */
|
|
|
|
- sky2_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK);
|
|
|
|
-
|
|
|
|
- reg = gma_read16(hw, port, GM_GP_CTRL);
|
|
|
|
- if (sky2->autoneg == AUTONEG_DISABLE) {
|
|
|
|
- reg |= GM_GPCR_AU_ALL_DIS;
|
|
|
|
-
|
|
|
|
- /* Is write/read necessary? Copied from sky2_mac_init */
|
|
|
|
- gma_write16(hw, port, GM_GP_CTRL, reg);
|
|
|
|
- gma_read16(hw, port, GM_GP_CTRL);
|
|
|
|
-
|
|
|
|
- switch (sky2->speed) {
|
|
|
|
- case SPEED_1000:
|
|
|
|
- reg &= ~GM_GPCR_SPEED_100;
|
|
|
|
- reg |= GM_GPCR_SPEED_1000;
|
|
|
|
- break;
|
|
|
|
- case SPEED_100:
|
|
|
|
- reg &= ~GM_GPCR_SPEED_1000;
|
|
|
|
- reg |= GM_GPCR_SPEED_100;
|
|
|
|
- break;
|
|
|
|
- case SPEED_10:
|
|
|
|
- reg &= ~(GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- } else
|
|
|
|
- reg &= ~GM_GPCR_AU_ALL_DIS;
|
|
|
|
-
|
|
|
|
- if (sky2->duplex == DUPLEX_FULL || sky2->autoneg == AUTONEG_ENABLE)
|
|
|
|
- reg |= GM_GPCR_DUP_FULL;
|
|
|
|
-
|
|
|
|
/* enable Rx/Tx */
|
|
/* enable Rx/Tx */
|
|
|
|
+ reg = gma_read16(hw, port, GM_GP_CTRL);
|
|
reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA;
|
|
reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA;
|
|
gma_write16(hw, port, GM_GP_CTRL, reg);
|
|
gma_write16(hw, port, GM_GP_CTRL, reg);
|
|
- gma_read16(hw, port, GM_GP_CTRL);
|
|
|
|
|
|
|
|
gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
|
|
gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
|
|
|
|
|
|
@@ -1616,7 +1575,6 @@ static void sky2_link_down(struct sky2_port *sky2)
|
|
reg = gma_read16(hw, port, GM_GP_CTRL);
|
|
reg = gma_read16(hw, port, GM_GP_CTRL);
|
|
reg &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
|
|
reg &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
|
|
gma_write16(hw, port, GM_GP_CTRL, reg);
|
|
gma_write16(hw, port, GM_GP_CTRL, reg);
|
|
- gma_read16(hw, port, GM_GP_CTRL); /* PCI post */
|
|
|
|
|
|
|
|
if (sky2->rx_pause && !sky2->tx_pause) {
|
|
if (sky2->rx_pause && !sky2->tx_pause) {
|
|
/* restore Asymmetric Pause bit */
|
|
/* restore Asymmetric Pause bit */
|
|
@@ -1633,6 +1591,7 @@ static void sky2_link_down(struct sky2_port *sky2)
|
|
|
|
|
|
if (netif_msg_link(sky2))
|
|
if (netif_msg_link(sky2))
|
|
printk(KERN_INFO PFX "%s: Link is down.\n", sky2->netdev->name);
|
|
printk(KERN_INFO PFX "%s: Link is down.\n", sky2->netdev->name);
|
|
|
|
+
|
|
sky2_phy_init(hw, port);
|
|
sky2_phy_init(hw, port);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1673,8 +1632,11 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
|
|
sky2->rx_pause = (aux & PHY_M_PS_RX_P_EN) != 0;
|
|
sky2->rx_pause = (aux & PHY_M_PS_RX_P_EN) != 0;
|
|
sky2->tx_pause = (aux & PHY_M_PS_TX_P_EN) != 0;
|
|
sky2->tx_pause = (aux & PHY_M_PS_TX_P_EN) != 0;
|
|
|
|
|
|
- if ((sky2->tx_pause || sky2->rx_pause)
|
|
|
|
- && !(sky2->speed < SPEED_1000 && sky2->duplex == DUPLEX_HALF))
|
|
|
|
|
|
+ if (sky2->duplex == DUPLEX_HALF && sky2->speed != SPEED_1000
|
|
|
|
+ && hw->chip_id != CHIP_ID_YUKON_EC_U)
|
|
|
|
+ sky2->rx_pause = sky2->tx_pause = 0;
|
|
|
|
+
|
|
|
|
+ if (sky2->rx_pause || sky2->tx_pause)
|
|
sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
|
|
sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
|
|
else
|
|
else
|
|
sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
|
|
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)
|
|
printk(KERN_INFO PFX "%s: phy interrupt status 0x%x 0x%x\n",
|
|
printk(KERN_INFO PFX "%s: phy interrupt status 0x%x 0x%x\n",
|
|
sky2->netdev->name, istatus, phystat);
|
|
sky2->netdev->name, istatus, phystat);
|
|
|
|
|
|
- if (istatus & PHY_M_IS_AN_COMPL) {
|
|
|
|
|
|
+ if (sky2->autoneg == AUTONEG_ENABLE && (istatus & PHY_M_IS_AN_COMPL)) {
|
|
if (sky2_autoneg_done(sky2, phystat) == 0)
|
|
if (sky2_autoneg_done(sky2, phystat) == 0)
|
|
sky2_link_up(sky2);
|
|
sky2_link_up(sky2);
|
|
goto out;
|
|
goto out;
|
|
@@ -2890,7 +2852,6 @@ static int sky2_set_pauseparam(struct net_device *dev,
|
|
struct ethtool_pauseparam *ecmd)
|
|
struct ethtool_pauseparam *ecmd)
|
|
{
|
|
{
|
|
struct sky2_port *sky2 = netdev_priv(dev);
|
|
struct sky2_port *sky2 = netdev_priv(dev);
|
|
- int err = 0;
|
|
|
|
|
|
|
|
sky2->autoneg = ecmd->autoneg;
|
|
sky2->autoneg = ecmd->autoneg;
|
|
sky2->tx_pause = ecmd->tx_pause != 0;
|
|
sky2->tx_pause = ecmd->tx_pause != 0;
|
|
@@ -2898,7 +2859,7 @@ static int sky2_set_pauseparam(struct net_device *dev,
|
|
|
|
|
|
sky2_phy_reinit(sky2);
|
|
sky2_phy_reinit(sky2);
|
|
|
|
|
|
- return err;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static int sky2_get_coalesce(struct net_device *dev,
|
|
static int sky2_get_coalesce(struct net_device *dev,
|