aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sky2.c
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@linux-foundation.org>2007-02-15 19:40:32 -0500
committerJeff Garzik <jeff@garzik.org>2007-02-17 15:30:47 -0500
commitda4c1ff475d82585e3206f0270cb1ba55bcf3c74 (patch)
tree1d9c63ce3bd7dd5a0ba297303cfef6055b1a1812 /drivers/net/sky2.c
parent7a7b5181517752005fd0dc822176a6975218ec0f (diff)
sky2: flow control negotiation for Yukon-FE
The Yukon-FE chip doesn't do gigabit and has a differen PHY internally. On this chip, phy status register doesn't properly reflect the result of flow control negotiation. To workaround the problem and avoid having to have so much chip dependent code; compute the result of flow control by looking at the local and remote advertised bits. Signed-off-by: Stephen Hemmminger <shemminger@linux-foundation.org> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r--drivers/net/sky2.c42
1 files changed, 31 insertions, 11 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index e5679965501c..2c9118125b5e 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -1766,10 +1766,10 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
1766{ 1766{
1767 struct sky2_hw *hw = sky2->hw; 1767 struct sky2_hw *hw = sky2->hw;
1768 unsigned port = sky2->port; 1768 unsigned port = sky2->port;
1769 u16 lpa; 1769 u16 advert, lpa;
1770 1770
1771 advert = gm_phy_read(hw, port, PHY_MARV_AUNE_ADV);
1771 lpa = gm_phy_read(hw, port, PHY_MARV_AUNE_LP); 1772 lpa = gm_phy_read(hw, port, PHY_MARV_AUNE_LP);
1772
1773 if (lpa & PHY_M_AN_RF) { 1773 if (lpa & PHY_M_AN_RF) {
1774 printk(KERN_ERR PFX "%s: remote fault", sky2->netdev->name); 1774 printk(KERN_ERR PFX "%s: remote fault", sky2->netdev->name);
1775 return -1; 1775 return -1;
@@ -1784,20 +1784,40 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
1784 sky2->speed = sky2_phy_speed(hw, aux); 1784 sky2->speed = sky2_phy_speed(hw, aux);
1785 sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF; 1785 sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF;
1786 1786
1787 /* Pause bits are offset (9..8) */ 1787 /* Since the pause result bits seem to in different positions on
1788 if (hw->chip_id == CHIP_ID_YUKON_XL 1788 * different chips. look at registers.
1789 || hw->chip_id == CHIP_ID_YUKON_EC_U 1789 */
1790 || hw->chip_id == CHIP_ID_YUKON_EX) 1790 if (!sky2_is_copper(hw)) {
1791 aux >>= 6; 1791 /* Shift for bits in fiber PHY */
1792 1792 advert &= ~(ADVERTISE_PAUSE_CAP|ADVERTISE_PAUSE_ASYM);
1793 sky2->flow_status = sky2_flow(aux & PHY_M_PS_RX_P_EN, 1793 lpa &= ~(LPA_PAUSE_CAP|LPA_PAUSE_ASYM);
1794 aux & PHY_M_PS_TX_P_EN); 1794
1795 if (advert & ADVERTISE_1000XPAUSE)
1796 advert |= ADVERTISE_PAUSE_CAP;
1797 if (advert & ADVERTISE_1000XPSE_ASYM)
1798 advert |= ADVERTISE_PAUSE_ASYM;
1799 if (lpa & LPA_1000XPAUSE)
1800 lpa |= LPA_PAUSE_CAP;
1801 if (lpa & LPA_1000XPAUSE_ASYM)
1802 lpa |= LPA_PAUSE_ASYM;
1803 }
1804
1805 sky2->flow_status = FC_NONE;
1806 if (advert & ADVERTISE_PAUSE_CAP) {
1807 if (lpa & LPA_PAUSE_CAP)
1808 sky2->flow_status = FC_BOTH;
1809 else if (advert & ADVERTISE_PAUSE_ASYM)
1810 sky2->flow_status = FC_RX;
1811 } else if (advert & ADVERTISE_PAUSE_ASYM) {
1812 if ((lpa & LPA_PAUSE_CAP) && (lpa & LPA_PAUSE_ASYM))
1813 sky2->flow_status = FC_TX;
1814 }
1795 1815
1796 if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000 1816 if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000
1797 && !(hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)) 1817 && !(hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX))
1798 sky2->flow_status = FC_NONE; 1818 sky2->flow_status = FC_NONE;
1799 1819
1800 if (aux & PHY_M_PS_RX_P_EN) 1820 if (sky2->flow_status & FC_TX)
1801 sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON); 1821 sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
1802 else 1822 else
1803 sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); 1823 sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);