Skip to content

Commit

Permalink
Merge branch 'tg3_eee'
Browse files Browse the repository at this point in the history
Nithin Nayak Sujir says:

====================
This series adds support for modifying EEE settings via ethtool. Since this can
impact Link Flap Avoidance, the driver pulls the current hardware settings if
LFA is enabled. This is similar to how we do the link settings to avoid a flap.

v2: Fixes pointed out by Ben Hutchings.
 - Use MDIO_AN_EEE_LPABLE to set the lp_advertised field.
 - Check that tx_lpi_timer is within valid range.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed May 20, 2013
2 parents 1649544 + 1cbf9eb commit f6abf2b
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 56 deletions.
227 changes: 171 additions & 56 deletions drivers/net/ethernet/broadcom/tg3.c
Original file line number Diff line number Diff line change
Expand Up @@ -2320,6 +2320,46 @@ static void tg3_phy_apply_otp(struct tg3 *tp)
tg3_phy_toggle_auxctl_smdsp(tp, false);
}

static void tg3_eee_pull_config(struct tg3 *tp, struct ethtool_eee *eee)
{
u32 val;
struct ethtool_eee *dest = &tp->eee;

if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP))
return;

if (eee)
dest = eee;

if (tg3_phy_cl45_read(tp, MDIO_MMD_AN, TG3_CL45_D7_EEERES_STAT, &val))
return;

/* Pull eee_active */
if (val == TG3_CL45_D7_EEERES_STAT_LP_1000T ||
val == TG3_CL45_D7_EEERES_STAT_LP_100TX) {
dest->eee_active = 1;
} else
dest->eee_active = 0;

/* Pull lp advertised settings */
if (tg3_phy_cl45_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE, &val))
return;
dest->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(val);

/* Pull advertised and eee_enabled settings */
if (tg3_phy_cl45_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, &val))
return;
dest->eee_enabled = !!val;
dest->advertised = mmd_eee_adv_to_ethtool_adv_t(val);

/* Pull tx_lpi_enabled */
val = tr32(TG3_CPMU_EEE_MODE);
dest->tx_lpi_enabled = !!(val & TG3_CPMU_EEEMD_LPI_IN_TX);

/* Pull lpi timer value */
dest->tx_lpi_timer = tr32(TG3_CPMU_EEE_DBTMR1) & 0xffff;
}

static void tg3_phy_eee_adjust(struct tg3 *tp, bool current_link_up)
{
u32 val;
Expand All @@ -2343,11 +2383,8 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, bool current_link_up)

tw32(TG3_CPMU_EEE_CTRL, eeectl);

tg3_phy_cl45_read(tp, MDIO_MMD_AN,
TG3_CL45_D7_EEERES_STAT, &val);

if (val == TG3_CL45_D7_EEERES_STAT_LP_1000T ||
val == TG3_CL45_D7_EEERES_STAT_LP_100TX)
tg3_eee_pull_config(tp, NULL);
if (tp->eee.eee_active)
tp->setlpicnt = 2;
}

Expand Down Expand Up @@ -4249,6 +4286,16 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
/* Advertise 1000-BaseT EEE ability */
if (advertise & ADVERTISED_1000baseT_Full)
val |= MDIO_AN_EEE_ADV_1000T;

if (!tp->eee.eee_enabled) {
val = 0;
tp->eee.advertised = 0;
} else {
tp->eee.advertised = advertise &
(ADVERTISED_100baseT_Full |
ADVERTISED_1000baseT_Full);
}

err = tg3_phy_cl45_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val);
if (err)
val = 0;
Expand Down Expand Up @@ -4493,26 +4540,23 @@ static int tg3_init_5401phy_dsp(struct tg3 *tp)

static bool tg3_phy_eee_config_ok(struct tg3 *tp)
{
u32 val;
u32 tgtadv = 0;
u32 advertising = tp->link_config.advertising;
struct ethtool_eee eee;

if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP))
return true;

if (tg3_phy_cl45_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, &val))
return false;

val &= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);

tg3_eee_pull_config(tp, &eee);

if (advertising & ADVERTISED_100baseT_Full)
tgtadv |= MDIO_AN_EEE_ADV_100TX;
if (advertising & ADVERTISED_1000baseT_Full)
tgtadv |= MDIO_AN_EEE_ADV_1000T;

if (val != tgtadv)
return false;
if (tp->eee.eee_enabled) {
if (tp->eee.advertised != eee.advertised ||
tp->eee.tx_lpi_timer != eee.tx_lpi_timer ||
tp->eee.tx_lpi_enabled != eee.tx_lpi_enabled)
return false;
} else {
/* EEE is disabled but we're advertising */
if (eee.advertised)
return false;
}

return true;
}
Expand Down Expand Up @@ -4613,6 +4657,42 @@ static void tg3_clear_mac_status(struct tg3 *tp)
udelay(40);
}

static void tg3_setup_eee(struct tg3 *tp)
{
u32 val;

val = TG3_CPMU_EEE_LNKIDL_PCIE_NL0 |
TG3_CPMU_EEE_LNKIDL_UART_IDL;
if (tg3_chip_rev_id(tp) == CHIPREV_ID_57765_A0)
val |= TG3_CPMU_EEE_LNKIDL_APE_TX_MT;

tw32_f(TG3_CPMU_EEE_LNKIDL_CTRL, val);

tw32_f(TG3_CPMU_EEE_CTRL,
TG3_CPMU_EEE_CTRL_EXIT_20_1_US);

val = TG3_CPMU_EEEMD_ERLY_L1_XIT_DET |
(tp->eee.tx_lpi_enabled ? TG3_CPMU_EEEMD_LPI_IN_TX : 0) |
TG3_CPMU_EEEMD_LPI_IN_RX |
TG3_CPMU_EEEMD_EEE_ENABLE;

if (tg3_asic_rev(tp) != ASIC_REV_5717)
val |= TG3_CPMU_EEEMD_SND_IDX_DET_EN;

if (tg3_flag(tp, ENABLE_APE))
val |= TG3_CPMU_EEEMD_APE_TX_DET_EN;

tw32_f(TG3_CPMU_EEE_MODE, tp->eee.eee_enabled ? val : 0);

tw32_f(TG3_CPMU_EEE_DBTMR1,
TG3_CPMU_DBTMR1_PCIEXIT_2047US |
(tp->eee.tx_lpi_timer & 0xffff));

tw32_f(TG3_CPMU_EEE_DBTMR2,
TG3_CPMU_DBTMR2_APE_TX_2047US |
TG3_CPMU_DBTMR2_TXIDXEQ_2047US);
}

static int tg3_setup_copper_phy(struct tg3 *tp, bool force_reset)
{
bool current_link_up;
Expand Down Expand Up @@ -4779,8 +4859,10 @@ static int tg3_setup_copper_phy(struct tg3 *tp, bool force_reset)
*/
if (!eee_config_ok &&
(tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN) &&
!force_reset)
!force_reset) {
tg3_setup_eee(tp);
tg3_phy_reset(tp);
}
} else {
if (!(bmcr & BMCR_ANENABLE) &&
tp->link_config.speed == current_speed &&
Expand Down Expand Up @@ -9447,46 +9529,17 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy)
if (tg3_flag(tp, INIT_COMPLETE))
tg3_abort_hw(tp, 1);

/* Enable MAC control of LPI */
if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) {
val = TG3_CPMU_EEE_LNKIDL_PCIE_NL0 |
TG3_CPMU_EEE_LNKIDL_UART_IDL;
if (tg3_chip_rev_id(tp) == CHIPREV_ID_57765_A0)
val |= TG3_CPMU_EEE_LNKIDL_APE_TX_MT;

tw32_f(TG3_CPMU_EEE_LNKIDL_CTRL, val);

tw32_f(TG3_CPMU_EEE_CTRL,
TG3_CPMU_EEE_CTRL_EXIT_20_1_US);

val = TG3_CPMU_EEEMD_ERLY_L1_XIT_DET |
TG3_CPMU_EEEMD_LPI_IN_TX |
TG3_CPMU_EEEMD_LPI_IN_RX |
TG3_CPMU_EEEMD_EEE_ENABLE;

if (tg3_asic_rev(tp) != ASIC_REV_5717)
val |= TG3_CPMU_EEEMD_SND_IDX_DET_EN;

if (tg3_flag(tp, ENABLE_APE))
val |= TG3_CPMU_EEEMD_APE_TX_DET_EN;

tw32_f(TG3_CPMU_EEE_MODE, val);

tw32_f(TG3_CPMU_EEE_DBTMR1,
TG3_CPMU_DBTMR1_PCIEXIT_2047US |
TG3_CPMU_DBTMR1_LNKIDLE_2047US);

tw32_f(TG3_CPMU_EEE_DBTMR2,
TG3_CPMU_DBTMR2_APE_TX_2047US |
TG3_CPMU_DBTMR2_TXIDXEQ_2047US);
}

if ((tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN) &&
!(tp->phy_flags & TG3_PHYFLG_USER_CONFIGURED)) {
tg3_phy_pull_config(tp);
tg3_eee_pull_config(tp, NULL);
tp->phy_flags |= TG3_PHYFLG_USER_CONFIGURED;
}

/* Enable MAC control of LPI */
if (tp->phy_flags & TG3_PHYFLG_EEE_CAP)
tg3_setup_eee(tp);

if (reset_phy)
tg3_phy_reset(tp);

Expand Down Expand Up @@ -13565,6 +13618,57 @@ static int tg3_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec)
return 0;
}

static int tg3_set_eee(struct net_device *dev, struct ethtool_eee *edata)
{
struct tg3 *tp = netdev_priv(dev);

if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP)) {
netdev_warn(tp->dev, "Board does not support EEE!\n");
return -EOPNOTSUPP;
}

if (edata->advertised != tp->eee.advertised) {
netdev_warn(tp->dev,
"Direct manipulation of EEE advertisement is not supported\n");
return -EINVAL;
}

if (edata->tx_lpi_timer > TG3_CPMU_DBTMR1_LNKIDLE_MAX) {
netdev_warn(tp->dev,
"Maximal Tx Lpi timer supported is %#x(u)\n",
TG3_CPMU_DBTMR1_LNKIDLE_MAX);
return -EINVAL;
}

tp->eee = *edata;

tp->phy_flags |= TG3_PHYFLG_USER_CONFIGURED;
tg3_warn_mgmt_link_flap(tp);

if (netif_running(tp->dev)) {
tg3_full_lock(tp, 0);
tg3_setup_eee(tp);
tg3_phy_reset(tp);
tg3_full_unlock(tp);
}

return 0;
}

static int tg3_get_eee(struct net_device *dev, struct ethtool_eee *edata)
{
struct tg3 *tp = netdev_priv(dev);

if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP)) {
netdev_warn(tp->dev,
"Board does not support EEE!\n");
return -EOPNOTSUPP;
}

*edata = tp->eee;
return 0;
}

static const struct ethtool_ops tg3_ethtool_ops = {
.get_settings = tg3_get_settings,
.set_settings = tg3_set_settings,
Expand Down Expand Up @@ -13598,6 +13702,8 @@ static const struct ethtool_ops tg3_ethtool_ops = {
.get_channels = tg3_get_channels,
.set_channels = tg3_set_channels,
.get_ts_info = tg3_get_ts_info,
.get_eee = tg3_get_eee,
.set_eee = tg3_set_eee,
};

static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
Expand Down Expand Up @@ -14946,9 +15052,18 @@ static int tg3_phy_probe(struct tg3 *tp)
(tg3_asic_rev(tp) == ASIC_REV_5717 &&
tg3_chip_rev_id(tp) != CHIPREV_ID_5717_A0) ||
(tg3_asic_rev(tp) == ASIC_REV_57765 &&
tg3_chip_rev_id(tp) != CHIPREV_ID_57765_A0)))
tg3_chip_rev_id(tp) != CHIPREV_ID_57765_A0))) {
tp->phy_flags |= TG3_PHYFLG_EEE_CAP;

tp->eee.supported = SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full;
tp->eee.advertised = ADVERTISED_100baseT_Full |
ADVERTISED_1000baseT_Full;
tp->eee.eee_enabled = 1;
tp->eee.tx_lpi_enabled = 1;
tp->eee.tx_lpi_timer = TG3_CPMU_DBTMR1_LNKIDLE_2047US;
}

tg3_phy_init_link_config(tp);

if (!(tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN) &&
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/ethernet/broadcom/tg3.h
Original file line number Diff line number Diff line change
Expand Up @@ -1175,6 +1175,7 @@
#define TG3_CPMU_EEE_DBTMR1 0x000036b4
#define TG3_CPMU_DBTMR1_PCIEXIT_2047US 0x07ff0000
#define TG3_CPMU_DBTMR1_LNKIDLE_2047US 0x000007ff
#define TG3_CPMU_DBTMR1_LNKIDLE_MAX 0x0000ffff
#define TG3_CPMU_EEE_DBTMR2 0x000036b8
#define TG3_CPMU_DBTMR2_APE_TX_2047US 0x07ff0000
#define TG3_CPMU_DBTMR2_TXIDXEQ_2047US 0x000007ff
Expand Down Expand Up @@ -3371,6 +3372,7 @@ struct tg3 {
unsigned int irq_cnt;

struct ethtool_coalesce coal;
struct ethtool_eee eee;

/* firmware info */
const char *fw_needed;
Expand Down

0 comments on commit f6abf2b

Please sign in to comment.