aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sfc/mdio_10g.c
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2009-11-28 22:42:41 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-29 19:46:28 -0500
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,
248int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) 248int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
249{ 249{
250 struct ethtool_cmd prev; 250 struct ethtool_cmd prev;
251 bool xnp;
252 int reg;
253 251
254 efx->phy_op->get_settings(efx, &prev); 252 efx->phy_op->get_settings(efx, &prev);
255 253
@@ -269,30 +267,47 @@ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
269 (ecmd->advertising | SUPPORTED_Autoneg) & ~prev.supported) 267 (ecmd->advertising | SUPPORTED_Autoneg) & ~prev.supported)
270 return -EINVAL; 268 return -EINVAL;
271 269
272 xnp = (ecmd->advertising & ADVERTISED_10000baseT_Full 270 efx_link_set_advertising(efx, ecmd->advertising | ADVERTISED_Autoneg);
273 || EFX_WORKAROUND_13204(efx)); 271 efx_mdio_an_reconfigure(efx);
272 return 0;
273}
274
275/**
276 * efx_mdio_an_reconfigure - Push advertising flags and restart autonegotiation
277 * @efx: Efx NIC
278 */
279void efx_mdio_an_reconfigure(struct efx_nic *efx)
280{
281 bool xnp = (efx->link_advertising & ADVERTISED_10000baseT_Full
282 || EFX_WORKAROUND_13204(efx));
283 int reg;
284
285 WARN_ON(!(efx->mdio.mmds & MDIO_DEVS_AN));
274 286
275 /* Set up the base page */ 287 /* Set up the base page */
276 reg = ADVERTISE_CSMA; 288 reg = ADVERTISE_CSMA;
277 if (ecmd->advertising & ADVERTISED_10baseT_Half) 289 if (efx->link_advertising & ADVERTISED_10baseT_Half)
278 reg |= ADVERTISE_10HALF; 290 reg |= ADVERTISE_10HALF;
279 if (ecmd->advertising & ADVERTISED_10baseT_Full) 291 if (efx->link_advertising & ADVERTISED_10baseT_Full)
280 reg |= ADVERTISE_10FULL; 292 reg |= ADVERTISE_10FULL;
281 if (ecmd->advertising & ADVERTISED_100baseT_Half) 293 if (efx->link_advertising & ADVERTISED_100baseT_Half)
282 reg |= ADVERTISE_100HALF; 294 reg |= ADVERTISE_100HALF;
283 if (ecmd->advertising & ADVERTISED_100baseT_Full) 295 if (efx->link_advertising & ADVERTISED_100baseT_Full)
284 reg |= ADVERTISE_100FULL; 296 reg |= ADVERTISE_100FULL;
285 if (xnp) 297 if (xnp)
286 reg |= ADVERTISE_RESV; 298 reg |= ADVERTISE_RESV;
287 else if (ecmd->advertising & (ADVERTISED_1000baseT_Half | 299 else if (efx->link_advertising & (ADVERTISED_1000baseT_Half |
288 ADVERTISED_1000baseT_Full)) 300 ADVERTISED_1000baseT_Full))
289 reg |= ADVERTISE_NPAGE; 301 reg |= ADVERTISE_NPAGE;
290 reg |= mii_advertise_flowctrl(efx->wanted_fc); 302 if (efx->link_advertising & ADVERTISED_Pause)
303 reg |= ADVERTISE_PAUSE_CAP;
304 if (efx->link_advertising & ADVERTISED_Asym_Pause)
305 reg |= ADVERTISE_PAUSE_ASYM;
291 efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); 306 efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
292 307
293 /* Set up the (extended) next page if necessary */ 308 /* Set up the (extended) next page if necessary */
294 if (efx->phy_op->set_npage_adv) 309 if (efx->phy_op->set_npage_adv)
295 efx->phy_op->set_npage_adv(efx, ecmd->advertising); 310 efx->phy_op->set_npage_adv(efx, efx->link_advertising);
296 311
297 /* Enable and restart AN */ 312 /* Enable and restart AN */
298 reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1); 313 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)
305 else 320 else
306 reg &= ~MDIO_AN_CTRL1_XNP; 321 reg &= ~MDIO_AN_CTRL1_XNP;
307 efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg); 322 efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg);
308
309 return 0;
310} 323}
311 324
312enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx) 325enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx)