aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sfc/mdio_10g.c
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
commitada47b5fe13d89735805b566185f4885f5a3f750 (patch)
tree644b88f8a71896307d71438e9b3af49126ffb22b /drivers/net/sfc/mdio_10g.c
parent43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff)
parent3280f21d43ee541f97f8cda5792150d2dbec20d5 (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.c168
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
20unsigned efx_mdio_id_oui(u32 id) 20unsigned 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
217static void efx_mdio_set_mmd_lpower(struct efx_nic *efx, 217static void efx_mdio_set_mmd_lpower(struct efx_nic *efx,
@@ -249,8 +249,6 @@ void efx_mdio_set_mmds_lpower(struct efx_nic *efx,
249int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) 249int 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 */
280void 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
343enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx) 325enum 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
339int 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}