diff options
author | Matt Carlson <mcarlson@broadcom.com> | 2007-12-20 23:08:00 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:59:31 -0500 |
commit | ba4d07a8483e6ec0de3194960f8aca862711454c (patch) | |
tree | 9f69fc77c1d3768cfd88575a42a38715a2e48011 | |
parent | 95937268b7c4c334a3d98f7177c7d5a00b74b2e7 (diff) |
[TG3]: Add 1000T & 1000X flowctl adv helpers
This patch adds two functions designed to convert abstract TX & RX
flow control parameters to 1000-BaseT and 1000-BaseX autonegotiation
advertisements. Code that uses standard definitions which statically
advertises TX & RX flow control has been replaced with code that
configures the advertisements based on administrator dictated
preferences.
Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/tg3.c | 62 |
1 files changed, 48 insertions, 14 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b571b20ce6e..5b83a542660 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c | |||
@@ -1612,6 +1612,38 @@ static void tg3_link_report(struct tg3 *tp) | |||
1612 | } | 1612 | } |
1613 | } | 1613 | } |
1614 | 1614 | ||
1615 | static u16 tg3_advert_flowctrl_1000T(u8 flow_ctrl) | ||
1616 | { | ||
1617 | u16 miireg; | ||
1618 | |||
1619 | if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX)) | ||
1620 | miireg = ADVERTISE_PAUSE_CAP; | ||
1621 | else if (flow_ctrl & TG3_FLOW_CTRL_TX) | ||
1622 | miireg = ADVERTISE_PAUSE_ASYM; | ||
1623 | else if (flow_ctrl & TG3_FLOW_CTRL_RX) | ||
1624 | miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; | ||
1625 | else | ||
1626 | miireg = 0; | ||
1627 | |||
1628 | return miireg; | ||
1629 | } | ||
1630 | |||
1631 | static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl) | ||
1632 | { | ||
1633 | u16 miireg; | ||
1634 | |||
1635 | if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX)) | ||
1636 | miireg = ADVERTISE_1000XPAUSE; | ||
1637 | else if (flow_ctrl & TG3_FLOW_CTRL_TX) | ||
1638 | miireg = ADVERTISE_1000XPSE_ASYM; | ||
1639 | else if (flow_ctrl & TG3_FLOW_CTRL_RX) | ||
1640 | miireg = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM; | ||
1641 | else | ||
1642 | miireg = 0; | ||
1643 | |||
1644 | return miireg; | ||
1645 | } | ||
1646 | |||
1615 | static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv) | 1647 | static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv) |
1616 | { | 1648 | { |
1617 | u8 cap = 0; | 1649 | u8 cap = 0; |
@@ -1764,7 +1796,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp) | |||
1764 | ~(ADVERTISED_1000baseT_Half | | 1796 | ~(ADVERTISED_1000baseT_Half | |
1765 | ADVERTISED_1000baseT_Full); | 1797 | ADVERTISED_1000baseT_Full); |
1766 | 1798 | ||
1767 | new_adv = (ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); | 1799 | new_adv = ADVERTISE_CSMA; |
1768 | if (tp->link_config.advertising & ADVERTISED_10baseT_Half) | 1800 | if (tp->link_config.advertising & ADVERTISED_10baseT_Half) |
1769 | new_adv |= ADVERTISE_10HALF; | 1801 | new_adv |= ADVERTISE_10HALF; |
1770 | if (tp->link_config.advertising & ADVERTISED_10baseT_Full) | 1802 | if (tp->link_config.advertising & ADVERTISED_10baseT_Full) |
@@ -1773,6 +1805,9 @@ static void tg3_phy_copper_begin(struct tg3 *tp) | |||
1773 | new_adv |= ADVERTISE_100HALF; | 1805 | new_adv |= ADVERTISE_100HALF; |
1774 | if (tp->link_config.advertising & ADVERTISED_100baseT_Full) | 1806 | if (tp->link_config.advertising & ADVERTISED_100baseT_Full) |
1775 | new_adv |= ADVERTISE_100FULL; | 1807 | new_adv |= ADVERTISE_100FULL; |
1808 | |||
1809 | new_adv |= tg3_advert_flowctrl_1000T(tp->link_config.flowctrl); | ||
1810 | |||
1776 | tg3_writephy(tp, MII_ADVERTISE, new_adv); | 1811 | tg3_writephy(tp, MII_ADVERTISE, new_adv); |
1777 | 1812 | ||
1778 | if (tp->link_config.advertising & | 1813 | if (tp->link_config.advertising & |
@@ -1792,9 +1827,11 @@ static void tg3_phy_copper_begin(struct tg3 *tp) | |||
1792 | tg3_writephy(tp, MII_TG3_CTRL, 0); | 1827 | tg3_writephy(tp, MII_TG3_CTRL, 0); |
1793 | } | 1828 | } |
1794 | } else { | 1829 | } else { |
1830 | new_adv = tg3_advert_flowctrl_1000T(tp->link_config.flowctrl); | ||
1831 | new_adv |= ADVERTISE_CSMA; | ||
1832 | |||
1795 | /* Asking for a specific link mode. */ | 1833 | /* Asking for a specific link mode. */ |
1796 | if (tp->link_config.speed == SPEED_1000) { | 1834 | if (tp->link_config.speed == SPEED_1000) { |
1797 | new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP; | ||
1798 | tg3_writephy(tp, MII_ADVERTISE, new_adv); | 1835 | tg3_writephy(tp, MII_ADVERTISE, new_adv); |
1799 | 1836 | ||
1800 | if (tp->link_config.duplex == DUPLEX_FULL) | 1837 | if (tp->link_config.duplex == DUPLEX_FULL) |
@@ -1805,11 +1842,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp) | |||
1805 | tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) | 1842 | tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) |
1806 | new_adv |= (MII_TG3_CTRL_AS_MASTER | | 1843 | new_adv |= (MII_TG3_CTRL_AS_MASTER | |
1807 | MII_TG3_CTRL_ENABLE_AS_MASTER); | 1844 | MII_TG3_CTRL_ENABLE_AS_MASTER); |
1808 | tg3_writephy(tp, MII_TG3_CTRL, new_adv); | ||
1809 | } else { | 1845 | } else { |
1810 | tg3_writephy(tp, MII_TG3_CTRL, 0); | ||
1811 | |||
1812 | new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP; | ||
1813 | if (tp->link_config.speed == SPEED_100) { | 1846 | if (tp->link_config.speed == SPEED_100) { |
1814 | if (tp->link_config.duplex == DUPLEX_FULL) | 1847 | if (tp->link_config.duplex == DUPLEX_FULL) |
1815 | new_adv |= ADVERTISE_100FULL; | 1848 | new_adv |= ADVERTISE_100FULL; |
@@ -1822,7 +1855,11 @@ static void tg3_phy_copper_begin(struct tg3 *tp) | |||
1822 | new_adv |= ADVERTISE_10HALF; | 1855 | new_adv |= ADVERTISE_10HALF; |
1823 | } | 1856 | } |
1824 | tg3_writephy(tp, MII_ADVERTISE, new_adv); | 1857 | tg3_writephy(tp, MII_ADVERTISE, new_adv); |
1858 | |||
1859 | new_adv = 0; | ||
1825 | } | 1860 | } |
1861 | |||
1862 | tg3_writephy(tp, MII_TG3_CTRL, new_adv); | ||
1826 | } | 1863 | } |
1827 | 1864 | ||
1828 | if (tp->link_config.autoneg == AUTONEG_DISABLE && | 1865 | if (tp->link_config.autoneg == AUTONEG_DISABLE && |
@@ -2118,17 +2155,15 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) | |||
2118 | 2155 | ||
2119 | if (tg3_readphy(tp, MII_ADVERTISE, &local_adv)) | 2156 | if (tg3_readphy(tp, MII_ADVERTISE, &local_adv)) |
2120 | local_adv = 0; | 2157 | local_adv = 0; |
2121 | local_adv &= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); | ||
2122 | 2158 | ||
2123 | if (tg3_readphy(tp, MII_LPA, &remote_adv)) | 2159 | if (tg3_readphy(tp, MII_LPA, &remote_adv)) |
2124 | remote_adv = 0; | 2160 | remote_adv = 0; |
2125 | 2161 | ||
2126 | remote_adv &= (LPA_PAUSE_CAP | LPA_PAUSE_ASYM); | 2162 | /* If we are not advertising what has been requested, |
2127 | 2163 | * bring the link down and reconfigure. | |
2128 | /* If we are not advertising full pause capability, | ||
2129 | * something is wrong. Bring the link down and reconfigure. | ||
2130 | */ | 2164 | */ |
2131 | if (local_adv != ADVERTISE_PAUSE_CAP) { | 2165 | if (local_adv != |
2166 | tg3_advert_flowctrl_1000T(tp->link_config.flowctrl)) { | ||
2132 | current_link_up = 0; | 2167 | current_link_up = 0; |
2133 | } else { | 2168 | } else { |
2134 | tg3_setup_flow_control(tp, local_adv, remote_adv); | 2169 | tg3_setup_flow_control(tp, local_adv, remote_adv); |
@@ -2973,8 +3008,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset) | |||
2973 | ADVERTISE_1000XPSE_ASYM | | 3008 | ADVERTISE_1000XPSE_ASYM | |
2974 | ADVERTISE_SLCT); | 3009 | ADVERTISE_SLCT); |
2975 | 3010 | ||
2976 | /* Always advertise symmetric PAUSE just like copper */ | 3011 | new_adv |= tg3_advert_flowctrl_1000X(tp->link_config.flowctrl); |
2977 | new_adv |= ADVERTISE_1000XPAUSE; | ||
2978 | 3012 | ||
2979 | if (tp->link_config.advertising & ADVERTISED_1000baseT_Half) | 3013 | if (tp->link_config.advertising & ADVERTISED_1000baseT_Half) |
2980 | new_adv |= ADVERTISE_1000XHALF; | 3014 | new_adv |= ADVERTISE_1000XHALF; |