diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/net/sfc/mdio_10g.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/net/sfc/mdio_10g.c')
-rw-r--r-- | drivers/net/sfc/mdio_10g.c | 168 |
1 files changed, 89 insertions, 79 deletions
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 6c33459f9ea9..0548fcbbdcd0 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /**************************************************************************** | 1 | /**************************************************************************** |
2 | * Driver for Solarflare Solarstorm network controllers and boards | 2 | * Driver for Solarflare Solarstorm network controllers and boards |
3 | * Copyright 2006-2008 Solarflare Communications Inc. | 3 | * Copyright 2006-2009 Solarflare Communications Inc. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 as published | 6 | * under the terms of the GNU General Public License version 2 as published |
@@ -14,8 +14,8 @@ | |||
14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
15 | #include "net_driver.h" | 15 | #include "net_driver.h" |
16 | #include "mdio_10g.h" | 16 | #include "mdio_10g.h" |
17 | #include "boards.h" | ||
18 | #include "workarounds.h" | 17 | #include "workarounds.h" |
18 | #include "nic.h" | ||
19 | 19 | ||
20 | unsigned efx_mdio_id_oui(u32 id) | 20 | unsigned efx_mdio_id_oui(u32 id) |
21 | { | 21 | { |
@@ -174,7 +174,7 @@ bool efx_mdio_links_ok(struct efx_nic *efx, unsigned int mmd_mask) | |||
174 | * of mmd's */ | 174 | * of mmd's */ |
175 | if (LOOPBACK_INTERNAL(efx)) | 175 | if (LOOPBACK_INTERNAL(efx)) |
176 | return true; | 176 | return true; |
177 | else if (efx->loopback_mode == LOOPBACK_NETWORK) | 177 | else if (LOOPBACK_MASK(efx) & LOOPBACKS_WS) |
178 | return false; | 178 | return false; |
179 | else if (efx_phy_mode_disabled(efx->phy_mode)) | 179 | else if (efx_phy_mode_disabled(efx->phy_mode)) |
180 | return false; | 180 | return false; |
@@ -211,7 +211,7 @@ void efx_mdio_phy_reconfigure(struct efx_nic *efx) | |||
211 | efx->loopback_mode == LOOPBACK_PCS); | 211 | efx->loopback_mode == LOOPBACK_PCS); |
212 | efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, | 212 | efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, |
213 | MDIO_CTRL1, MDIO_PHYXS_CTRL1_LOOPBACK, | 213 | MDIO_CTRL1, MDIO_PHYXS_CTRL1_LOOPBACK, |
214 | efx->loopback_mode == LOOPBACK_NETWORK); | 214 | efx->loopback_mode == LOOPBACK_PHYXS_WS); |
215 | } | 215 | } |
216 | 216 | ||
217 | static void efx_mdio_set_mmd_lpower(struct efx_nic *efx, | 217 | static void efx_mdio_set_mmd_lpower(struct efx_nic *efx, |
@@ -249,8 +249,6 @@ void efx_mdio_set_mmds_lpower(struct efx_nic *efx, | |||
249 | int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) | 249 | int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) |
250 | { | 250 | { |
251 | struct ethtool_cmd prev; | 251 | struct ethtool_cmd prev; |
252 | u32 required; | ||
253 | int reg; | ||
254 | 252 | ||
255 | efx->phy_op->get_settings(efx, &prev); | 253 | efx->phy_op->get_settings(efx, &prev); |
256 | 254 | ||
@@ -266,86 +264,98 @@ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) | |||
266 | return -EINVAL; | 264 | return -EINVAL; |
267 | 265 | ||
268 | /* Check that PHY supports these settings */ | 266 | /* Check that PHY supports these settings */ |
269 | if (ecmd->autoneg) { | 267 | if (!ecmd->autoneg || |
270 | required = SUPPORTED_Autoneg; | 268 | (ecmd->advertising | SUPPORTED_Autoneg) & ~prev.supported) |
271 | } else if (ecmd->duplex) { | ||
272 | switch (ecmd->speed) { | ||
273 | case SPEED_10: required = SUPPORTED_10baseT_Full; break; | ||
274 | case SPEED_100: required = SUPPORTED_100baseT_Full; break; | ||
275 | default: return -EINVAL; | ||
276 | } | ||
277 | } else { | ||
278 | switch (ecmd->speed) { | ||
279 | case SPEED_10: required = SUPPORTED_10baseT_Half; break; | ||
280 | case SPEED_100: required = SUPPORTED_100baseT_Half; break; | ||
281 | default: return -EINVAL; | ||
282 | } | ||
283 | } | ||
284 | required |= ecmd->advertising; | ||
285 | if (required & ~prev.supported) | ||
286 | return -EINVAL; | 269 | return -EINVAL; |
287 | 270 | ||
288 | if (ecmd->autoneg) { | 271 | efx_link_set_advertising(efx, ecmd->advertising | ADVERTISED_Autoneg); |
289 | bool xnp = (ecmd->advertising & ADVERTISED_10000baseT_Full | 272 | efx_mdio_an_reconfigure(efx); |
290 | || EFX_WORKAROUND_13204(efx)); | ||
291 | |||
292 | /* Set up the base page */ | ||
293 | reg = ADVERTISE_CSMA; | ||
294 | if (ecmd->advertising & ADVERTISED_10baseT_Half) | ||
295 | reg |= ADVERTISE_10HALF; | ||
296 | if (ecmd->advertising & ADVERTISED_10baseT_Full) | ||
297 | reg |= ADVERTISE_10FULL; | ||
298 | if (ecmd->advertising & ADVERTISED_100baseT_Half) | ||
299 | reg |= ADVERTISE_100HALF; | ||
300 | if (ecmd->advertising & ADVERTISED_100baseT_Full) | ||
301 | reg |= ADVERTISE_100FULL; | ||
302 | if (xnp) | ||
303 | reg |= ADVERTISE_RESV; | ||
304 | else if (ecmd->advertising & (ADVERTISED_1000baseT_Half | | ||
305 | ADVERTISED_1000baseT_Full)) | ||
306 | reg |= ADVERTISE_NPAGE; | ||
307 | reg |= mii_advertise_flowctrl(efx->wanted_fc); | ||
308 | efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); | ||
309 | |||
310 | /* Set up the (extended) next page if necessary */ | ||
311 | if (efx->phy_op->set_npage_adv) | ||
312 | efx->phy_op->set_npage_adv(efx, ecmd->advertising); | ||
313 | |||
314 | /* Enable and restart AN */ | ||
315 | reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1); | ||
316 | reg |= MDIO_AN_CTRL1_ENABLE; | ||
317 | if (!(EFX_WORKAROUND_15195(efx) && | ||
318 | LOOPBACK_MASK(efx) & efx->phy_op->loopbacks)) | ||
319 | reg |= MDIO_AN_CTRL1_RESTART; | ||
320 | if (xnp) | ||
321 | reg |= MDIO_AN_CTRL1_XNP; | ||
322 | else | ||
323 | reg &= ~MDIO_AN_CTRL1_XNP; | ||
324 | efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg); | ||
325 | } else { | ||
326 | /* Disable AN */ | ||
327 | efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_CTRL1, | ||
328 | MDIO_AN_CTRL1_ENABLE, false); | ||
329 | |||
330 | /* Set the basic control bits */ | ||
331 | reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1); | ||
332 | reg &= ~(MDIO_CTRL1_SPEEDSEL | MDIO_CTRL1_FULLDPLX); | ||
333 | if (ecmd->speed == SPEED_100) | ||
334 | reg |= MDIO_PMA_CTRL1_SPEED100; | ||
335 | if (ecmd->duplex) | ||
336 | reg |= MDIO_CTRL1_FULLDPLX; | ||
337 | efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1, reg); | ||
338 | } | ||
339 | |||
340 | return 0; | 273 | return 0; |
341 | } | 274 | } |
342 | 275 | ||
276 | /** | ||
277 | * efx_mdio_an_reconfigure - Push advertising flags and restart autonegotiation | ||
278 | * @efx: Efx NIC | ||
279 | */ | ||
280 | void efx_mdio_an_reconfigure(struct efx_nic *efx) | ||
281 | { | ||
282 | bool xnp = (efx->link_advertising & ADVERTISED_10000baseT_Full | ||
283 | || EFX_WORKAROUND_13204(efx)); | ||
284 | int reg; | ||
285 | |||
286 | WARN_ON(!(efx->mdio.mmds & MDIO_DEVS_AN)); | ||
287 | |||
288 | /* Set up the base page */ | ||
289 | reg = ADVERTISE_CSMA; | ||
290 | if (efx->link_advertising & ADVERTISED_10baseT_Half) | ||
291 | reg |= ADVERTISE_10HALF; | ||
292 | if (efx->link_advertising & ADVERTISED_10baseT_Full) | ||
293 | reg |= ADVERTISE_10FULL; | ||
294 | if (efx->link_advertising & ADVERTISED_100baseT_Half) | ||
295 | reg |= ADVERTISE_100HALF; | ||
296 | if (efx->link_advertising & ADVERTISED_100baseT_Full) | ||
297 | reg |= ADVERTISE_100FULL; | ||
298 | if (xnp) | ||
299 | reg |= ADVERTISE_RESV; | ||
300 | else if (efx->link_advertising & (ADVERTISED_1000baseT_Half | | ||
301 | ADVERTISED_1000baseT_Full)) | ||
302 | reg |= ADVERTISE_NPAGE; | ||
303 | if (efx->link_advertising & ADVERTISED_Pause) | ||
304 | reg |= ADVERTISE_PAUSE_CAP; | ||
305 | if (efx->link_advertising & ADVERTISED_Asym_Pause) | ||
306 | reg |= ADVERTISE_PAUSE_ASYM; | ||
307 | efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); | ||
308 | |||
309 | /* Set up the (extended) next page if necessary */ | ||
310 | if (efx->phy_op->set_npage_adv) | ||
311 | efx->phy_op->set_npage_adv(efx, efx->link_advertising); | ||
312 | |||
313 | /* Enable and restart AN */ | ||
314 | reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1); | ||
315 | reg |= MDIO_AN_CTRL1_ENABLE; | ||
316 | if (!(EFX_WORKAROUND_15195(efx) && LOOPBACK_EXTERNAL(efx))) | ||
317 | reg |= MDIO_AN_CTRL1_RESTART; | ||
318 | if (xnp) | ||
319 | reg |= MDIO_AN_CTRL1_XNP; | ||
320 | else | ||
321 | reg &= ~MDIO_AN_CTRL1_XNP; | ||
322 | efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg); | ||
323 | } | ||
324 | |||
343 | enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx) | 325 | enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx) |
344 | { | 326 | { |
345 | int lpa; | 327 | BUILD_BUG_ON(EFX_FC_AUTO & (EFX_FC_RX | EFX_FC_TX)); |
346 | 328 | ||
347 | if (!(efx->phy_op->mmds & MDIO_DEVS_AN)) | 329 | if (!(efx->wanted_fc & EFX_FC_AUTO)) |
348 | return efx->wanted_fc; | 330 | return efx->wanted_fc; |
349 | lpa = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_LPA); | 331 | |
350 | return efx_fc_resolve(efx->wanted_fc, lpa); | 332 | WARN_ON(!(efx->mdio.mmds & MDIO_DEVS_AN)); |
333 | |||
334 | return mii_resolve_flowctrl_fdx( | ||
335 | mii_advertise_flowctrl(efx->wanted_fc), | ||
336 | efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_LPA)); | ||
337 | } | ||
338 | |||
339 | int efx_mdio_test_alive(struct efx_nic *efx) | ||
340 | { | ||
341 | int rc; | ||
342 | int devad = __ffs(efx->mdio.mmds); | ||
343 | u16 physid1, physid2; | ||
344 | |||
345 | mutex_lock(&efx->mac_lock); | ||
346 | |||
347 | physid1 = efx_mdio_read(efx, devad, MDIO_DEVID1); | ||
348 | physid2 = efx_mdio_read(efx, devad, MDIO_DEVID2); | ||
349 | |||
350 | if ((physid1 == 0x0000) || (physid1 == 0xffff) || | ||
351 | (physid2 == 0x0000) || (physid2 == 0xffff)) { | ||
352 | EFX_ERR(efx, "no MDIO PHY present with ID %d\n", | ||
353 | efx->mdio.prtad); | ||
354 | rc = -EINVAL; | ||
355 | } else { | ||
356 | rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0); | ||
357 | } | ||
358 | |||
359 | mutex_unlock(&efx->mac_lock); | ||
360 | return rc; | ||
351 | } | 361 | } |