summaryrefslogtreecommitdiff
path: root/drivers/net/sfc/mdio_10g.c
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2009-11-29 03:42:41 +0000
committerDavid S. Miller <davem@davemloft.net>2009-11-29 16:46:28 -0800
commitd3245b28ef2a45ec4e115062a38100bd06229289 (patch)
tree036133fdf01a20f36086d5eb8606728859c056de /drivers/net/sfc/mdio_10g.c
parentef2b90ee4dba7a3d9001f1f0003b860b39a4aaae (diff)
sfc: Refactor link configuration
Refactor PHY, MAC and NIC configuration operations so that the existing link configuration can be re-pushed with: efx->phy_op->reconfigure(efx); efx->mac_op->reconfigure(efx); and a new configuration with: efx->nic_op->reconfigure_port(efx); (plus locking and error-checking). We have not held the link settings in software (aside from flow control), and have relied on asking the hardware what they are. This is a problem because in some cases the hardware may no longer be in a state to tell us. In particular, if an entire multi-port board is reset through one port, the driver bindings to other ports have no chance to save settings before recovering. We only actually need to keep track of the autonegotiation settings, so add an ethtool advertising mask to struct efx_nic, initialise it in PHY init and update it as necessary. Remove now-unneeded uses of efx_phy_op::{get,set}_settings() and struct ethtool_cmd. Much of this was done by Steve Hodgson <shodgson@solarflare.com>. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sfc/mdio_10g.c')
-rw-r--r--drivers/net/sfc/mdio_10g.c41
1 files changed, 27 insertions, 14 deletions
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
index 231e580acc9a..1f62a5c002fd 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/sfc/mdio_10g.c
@@ -248,8 +248,6 @@ void efx_mdio_set_mmds_lpower(struct efx_nic *efx,
int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
{
struct ethtool_cmd prev;
- bool xnp;
- int reg;
efx->phy_op->get_settings(efx, &prev);
@@ -269,30 +267,47 @@ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
(ecmd->advertising | SUPPORTED_Autoneg) & ~prev.supported)
return -EINVAL;
- xnp = (ecmd->advertising & ADVERTISED_10000baseT_Full
- || EFX_WORKAROUND_13204(efx));
+ efx_link_set_advertising(efx, ecmd->advertising | ADVERTISED_Autoneg);
+ efx_mdio_an_reconfigure(efx);
+ return 0;
+}
+
+/**
+ * efx_mdio_an_reconfigure - Push advertising flags and restart autonegotiation
+ * @efx: Efx NIC
+ */
+void efx_mdio_an_reconfigure(struct efx_nic *efx)
+{
+ bool xnp = (efx->link_advertising & ADVERTISED_10000baseT_Full
+ || EFX_WORKAROUND_13204(efx));
+ int reg;
+
+ WARN_ON(!(efx->mdio.mmds & MDIO_DEVS_AN));
/* Set up the base page */
reg = ADVERTISE_CSMA;
- if (ecmd->advertising & ADVERTISED_10baseT_Half)
+ if (efx->link_advertising & ADVERTISED_10baseT_Half)
reg |= ADVERTISE_10HALF;
- if (ecmd->advertising & ADVERTISED_10baseT_Full)
+ if (efx->link_advertising & ADVERTISED_10baseT_Full)
reg |= ADVERTISE_10FULL;
- if (ecmd->advertising & ADVERTISED_100baseT_Half)
+ if (efx->link_advertising & ADVERTISED_100baseT_Half)
reg |= ADVERTISE_100HALF;
- if (ecmd->advertising & ADVERTISED_100baseT_Full)
+ if (efx->link_advertising & ADVERTISED_100baseT_Full)
reg |= ADVERTISE_100FULL;
if (xnp)
reg |= ADVERTISE_RESV;
- else if (ecmd->advertising & (ADVERTISED_1000baseT_Half |
- ADVERTISED_1000baseT_Full))
+ else if (efx->link_advertising & (ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full))
reg |= ADVERTISE_NPAGE;
- reg |= mii_advertise_flowctrl(efx->wanted_fc);
+ if (efx->link_advertising & ADVERTISED_Pause)
+ reg |= ADVERTISE_PAUSE_CAP;
+ if (efx->link_advertising & ADVERTISED_Asym_Pause)
+ reg |= ADVERTISE_PAUSE_ASYM;
efx_mdio_write(efx, 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);
+ efx->phy_op->set_npage_adv(efx, efx->link_advertising);
/* Enable and restart AN */
reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1);
@@ -305,8 +320,6 @@ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
else
reg &= ~MDIO_AN_CTRL1_XNP;
efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg);
-
- return 0;
}
enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx)