Skip to content

Commit

Permalink
sfc: SFX7101/SFT9001: Fix AN advertisements
Browse files Browse the repository at this point in the history
All 10Xpress PHYs require autonegotiation all the time; enforce this
in the set_settings() method and do not treat it as a workaround.

Remove claimed support for 100M HD mode since it is not supported by
current firmware.

Do not set speed override bits when AN is enabled, and do not use
register 1.49192 for AN configuration as it can override what we set
elsewhere.

Always set the AN selector bits to 1 (802.3).

Fix confusion between Next Page and Extended Next Page.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Ben Hutchings authored and David S. Miller committed Jan 30, 2009
1 parent c9d5a53 commit af4ad9b
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 201 deletions.
3 changes: 0 additions & 3 deletions drivers/net/sfc/ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,6 @@ int efx_ethtool_set_settings(struct net_device *net_dev,
struct efx_nic *efx = netdev_priv(net_dev);
int rc;

if (EFX_WORKAROUND_13963(efx) && !ecmd->autoneg)
return -EINVAL;

/* Falcon GMAC does not support 1000Mbps HD */
if (ecmd->speed == SPEED_1000 && ecmd->duplex != DUPLEX_FULL) {
EFX_LOG(efx, "rejecting unsupported 1000Mbps HD"
Expand Down
177 changes: 79 additions & 98 deletions drivers/net/sfc/mdio_10g.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ void mdio_clause45_set_mmds_lpower(struct efx_nic *efx,
}
}

static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr, u32 xnp)
static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr)
{
int phy_id = efx->mii.phy_id;
u32 result = 0;
Expand All @@ -281,9 +281,6 @@ static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr, u32 xnp)
result |= ADVERTISED_100baseT_Half;
if (reg & ADVERTISE_100FULL)
result |= ADVERTISED_100baseT_Full;
if (reg & LPA_RESV)
result |= xnp;

return result;
}

Expand Down Expand Up @@ -313,7 +310,7 @@ void mdio_clause45_get_settings(struct efx_nic *efx,
*/
void mdio_clause45_get_settings_ext(struct efx_nic *efx,
struct ethtool_cmd *ecmd,
u32 xnp, u32 xnp_lpa)
u32 npage_adv, u32 npage_lpa)
{
int phy_id = efx->mii.phy_id;
int reg;
Expand Down Expand Up @@ -364,8 +361,8 @@ void mdio_clause45_get_settings_ext(struct efx_nic *efx,
ecmd->autoneg = AUTONEG_ENABLE;
ecmd->advertising |=
ADVERTISED_Autoneg |
mdio_clause45_get_an(efx,
MDIO_AN_ADVERTISE, xnp);
mdio_clause45_get_an(efx, MDIO_AN_ADVERTISE) |
npage_adv;
} else
ecmd->autoneg = AUTONEG_DISABLE;
} else
Expand All @@ -374,27 +371,30 @@ void mdio_clause45_get_settings_ext(struct efx_nic *efx,
if (ecmd->autoneg) {
/* If AN is complete, report best common mode,
* otherwise report best advertised mode. */
u32 common = ecmd->advertising;
u32 modes = 0;
if (mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
MDIO_MMDREG_STAT1) &
(1 << MDIO_AN_STATUS_AN_DONE_LBN)) {
common &= mdio_clause45_get_an(efx, MDIO_AN_LPA,
xnp_lpa);
}
if (common & ADVERTISED_10000baseT_Full) {
(1 << MDIO_AN_STATUS_AN_DONE_LBN))
modes = (ecmd->advertising &
(mdio_clause45_get_an(efx, MDIO_AN_LPA) |
npage_lpa));
if (modes == 0)
modes = ecmd->advertising;

if (modes & ADVERTISED_10000baseT_Full) {
ecmd->speed = SPEED_10000;
ecmd->duplex = DUPLEX_FULL;
} else if (common & (ADVERTISED_1000baseT_Full |
ADVERTISED_1000baseT_Half)) {
} else if (modes & (ADVERTISED_1000baseT_Full |
ADVERTISED_1000baseT_Half)) {
ecmd->speed = SPEED_1000;
ecmd->duplex = !!(common & ADVERTISED_1000baseT_Full);
} else if (common & (ADVERTISED_100baseT_Full |
ADVERTISED_100baseT_Half)) {
ecmd->duplex = !!(modes & ADVERTISED_1000baseT_Full);
} else if (modes & (ADVERTISED_100baseT_Full |
ADVERTISED_100baseT_Half)) {
ecmd->speed = SPEED_100;
ecmd->duplex = !!(common & ADVERTISED_100baseT_Full);
ecmd->duplex = !!(modes & ADVERTISED_100baseT_Full);
} else {
ecmd->speed = SPEED_10;
ecmd->duplex = !!(common & ADVERTISED_10baseT_Full);
ecmd->duplex = !!(modes & ADVERTISED_10baseT_Full);
}
} else {
/* Report forced settings */
Expand All @@ -418,7 +418,7 @@ int mdio_clause45_set_settings(struct efx_nic *efx,
int phy_id = efx->mii.phy_id;
struct ethtool_cmd prev;
u32 required;
int ctrl1_bits, reg;
int reg;

efx->phy_op->get_settings(efx, &prev);

Expand All @@ -433,102 +433,83 @@ int mdio_clause45_set_settings(struct efx_nic *efx,
if (prev.port != PORT_TP || ecmd->port != PORT_TP)
return -EINVAL;

/* Check that PHY supports these settings and work out the
* basic control bits */
if (ecmd->duplex) {
/* Check that PHY supports these settings */
if (ecmd->autoneg) {
required = SUPPORTED_Autoneg;
} else if (ecmd->duplex) {
switch (ecmd->speed) {
case SPEED_10:
ctrl1_bits = BMCR_FULLDPLX;
required = SUPPORTED_10baseT_Full;
break;
case SPEED_100:
ctrl1_bits = BMCR_SPEED100 | BMCR_FULLDPLX;
required = SUPPORTED_100baseT_Full;
break;
case SPEED_1000:
ctrl1_bits = BMCR_SPEED1000 | BMCR_FULLDPLX;
required = SUPPORTED_1000baseT_Full;
break;
case SPEED_10000:
ctrl1_bits = (BMCR_SPEED1000 | BMCR_SPEED100 |
BMCR_FULLDPLX);
required = SUPPORTED_10000baseT_Full;
break;
default:
return -EINVAL;
case SPEED_10: required = SUPPORTED_10baseT_Full; break;
case SPEED_100: required = SUPPORTED_100baseT_Full; break;
default: return -EINVAL;
}
} else {
switch (ecmd->speed) {
case SPEED_10:
ctrl1_bits = 0;
required = SUPPORTED_10baseT_Half;
break;
case SPEED_100:
ctrl1_bits = BMCR_SPEED100;
required = SUPPORTED_100baseT_Half;
break;
case SPEED_1000:
ctrl1_bits = BMCR_SPEED1000;
required = SUPPORTED_1000baseT_Half;
break;
default:
return -EINVAL;
case SPEED_10: required = SUPPORTED_10baseT_Half; break;
case SPEED_100: required = SUPPORTED_100baseT_Half; break;
default: return -EINVAL;
}
}
if (ecmd->autoneg)
required |= SUPPORTED_Autoneg;
required |= ecmd->advertising;
if (required & ~prev.supported)
return -EINVAL;

/* Set the basic control bits */
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
MDIO_MMDREG_CTRL1);
reg &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX | 0x003c);
reg |= ctrl1_bits;
mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL1,
reg);

/* Set the AN registers */
if (ecmd->autoneg != prev.autoneg ||
ecmd->advertising != prev.advertising) {
bool xnp = false;

if (efx->phy_op->set_xnp_advertise)
xnp = efx->phy_op->set_xnp_advertise(efx,
ecmd->advertising);

if (ecmd->autoneg) {
reg = 0;
if (ecmd->advertising & ADVERTISED_10baseT_Half)
reg |= ADVERTISE_10HALF;
if (ecmd->advertising & ADVERTISED_10baseT_Full)
reg |= ADVERTISE_10FULL;
if (ecmd->advertising & ADVERTISED_100baseT_Half)
reg |= ADVERTISE_100HALF;
if (ecmd->advertising & ADVERTISED_100baseT_Full)
reg |= ADVERTISE_100FULL;
if (xnp)
reg |= ADVERTISE_RESV;
mdio_clause45_write(efx, phy_id, MDIO_MMD_AN,
MDIO_AN_ADVERTISE, reg);
}
if (ecmd->autoneg) {
bool xnp = (ecmd->advertising & ADVERTISED_10000baseT_Full
|| EFX_WORKAROUND_13204(efx));

/* Set up the base page */
reg = ADVERTISE_CSMA;
if (ecmd->advertising & ADVERTISED_10baseT_Half)
reg |= ADVERTISE_10HALF;
if (ecmd->advertising & ADVERTISED_10baseT_Full)
reg |= ADVERTISE_10FULL;
if (ecmd->advertising & ADVERTISED_100baseT_Half)
reg |= ADVERTISE_100HALF;
if (ecmd->advertising & ADVERTISED_100baseT_Full)
reg |= ADVERTISE_100FULL;
if (xnp)
reg |= ADVERTISE_RESV;
else if (ecmd->advertising & (ADVERTISED_1000baseT_Half |
ADVERTISED_1000baseT_Full))
reg |= ADVERTISE_NPAGE;
reg |= efx_fc_advertise(efx->wanted_fc);
mdio_clause45_write(efx, phy_id, MDIO_MMD_AN,
MDIO_AN_ADVERTISE, reg);

/* Set up the (extended) next page if necessary */
if (efx->phy_op->set_npage_adv)
efx->phy_op->set_npage_adv(efx, ecmd->advertising);

/* Enable and restart AN */
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
MDIO_MMDREG_CTRL1);
if (ecmd->autoneg)
reg |= BMCR_ANENABLE | BMCR_ANRESTART;
else
reg &= ~BMCR_ANENABLE;
if (EFX_WORKAROUND_15195(efx)
&& LOOPBACK_MASK(efx) & efx->phy_op->loopbacks)
reg &= ~BMCR_ANRESTART;
reg |= BMCR_ANENABLE;
if (!(EFX_WORKAROUND_15195(efx) &&
LOOPBACK_MASK(efx) & efx->phy_op->loopbacks))
reg |= BMCR_ANRESTART;
if (xnp)
reg |= 1 << MDIO_AN_CTRL_XNP_LBN;
else
reg &= ~(1 << MDIO_AN_CTRL_XNP_LBN);
mdio_clause45_write(efx, phy_id, MDIO_MMD_AN,
MDIO_MMDREG_CTRL1, reg);
} else {
/* Disable AN */
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_AN,
MDIO_MMDREG_CTRL1,
__ffs(BMCR_ANENABLE), false);

/* Set the basic control bits */
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
MDIO_MMDREG_CTRL1);
reg &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX |
0x003c);
if (ecmd->speed == SPEED_100)
reg |= BMCR_SPEED100;
if (ecmd->duplex)
reg |= BMCR_FULLDPLX;
mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
MDIO_MMDREG_CTRL1, reg);
}

return 0;
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/sfc/mdio_10g.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@
#define MDIO_AN_XNP 22
#define MDIO_AN_LPA_XNP 25

#define MDIO_AN_10GBT_ADVERTISE 32
#define MDIO_AN_10GBT_CTRL 32
#define MDIO_AN_10GBT_CTRL_ADV_10G_LBN 12
#define MDIO_AN_10GBT_STATUS (33)
#define MDIO_AN_10GBT_STATUS_MS_FLT_LBN (15) /* MASTER/SLAVE config fault */
#define MDIO_AN_10GBT_STATUS_MS_LBN (14) /* MASTER/SLAVE config */
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/sfc/net_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ struct efx_mac_operations {
* @poll: Poll for hardware state. Serialised by the mac_lock.
* @get_settings: Get ethtool settings. Serialised by the mac_lock.
* @set_settings: Set ethtool settings. Serialised by the mac_lock.
* @set_xnp_advertise: Set abilities advertised in Extended Next Page
* @set_npage_adv: Set abilities advertised in (Extended) Next Page
* (only needed where AN bit is set in mmds)
* @num_tests: Number of PHY-specific tests/results
* @test_names: Names of the tests/results
Expand All @@ -586,7 +586,7 @@ struct efx_phy_operations {
struct ethtool_cmd *ecmd);
int (*set_settings) (struct efx_nic *efx,
struct ethtool_cmd *ecmd);
bool (*set_xnp_advertise) (struct efx_nic *efx, u32);
void (*set_npage_adv) (struct efx_nic *efx, u32);
u32 num_tests;
const char *const *test_names;
int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags);
Expand Down
Loading

0 comments on commit af4ad9b

Please sign in to comment.