diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2008-12-13 00:50:46 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-12-13 00:58:17 -0500 |
commit | 04cc8cacb01c09fba2297faf1477cd570ba43f0b (patch) | |
tree | f17dbd584b072d14f1500c6f6d659be993ae35c7 /drivers/net/sfc/mdio_10g.c | |
parent | 177dfcd80f28f8fbc3e22c2d8b24d21cb86f1d97 (diff) |
sfc: Implement auto-negotiation
Add infrastructure for auto-negotiation of speed, duplex and flow
control.
When using 10Xpress, auto-negotiate flow control. While we're
at it, clean up the code to warn when partner is not 10GBASE-T
capable.
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.c | 348 |
1 files changed, 277 insertions, 71 deletions
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 8d91131aa5ab..037601e0b9d7 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c | |||
@@ -47,13 +47,16 @@ static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd, | |||
47 | if (LOOPBACK_INTERNAL(efx)) | 47 | if (LOOPBACK_INTERNAL(efx)) |
48 | return 0; | 48 | return 0; |
49 | 49 | ||
50 | /* Read MMD STATUS2 to check it is responding. */ | 50 | if (mmd != MDIO_MMD_AN) { |
51 | status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT2); | 51 | /* Read MMD STATUS2 to check it is responding. */ |
52 | if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) & | 52 | status = mdio_clause45_read(efx, phy_id, mmd, |
53 | ((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) != | 53 | MDIO_MMDREG_STAT2); |
54 | MDIO_MMDREG_STAT2_PRESENT_VAL) { | 54 | if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) & |
55 | EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd); | 55 | ((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) != |
56 | return -EIO; | 56 | MDIO_MMDREG_STAT2_PRESENT_VAL) { |
57 | EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd); | ||
58 | return -EIO; | ||
59 | } | ||
57 | } | 60 | } |
58 | 61 | ||
59 | /* Read MMD STATUS 1 to check for fault. */ | 62 | /* Read MMD STATUS 1 to check for fault. */ |
@@ -179,12 +182,15 @@ bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) | |||
179 | else if (efx->loopback_mode == LOOPBACK_PHYXS) | 182 | else if (efx->loopback_mode == LOOPBACK_PHYXS) |
180 | mmd_mask &= ~(MDIO_MMDREG_DEVS_PHYXS | | 183 | mmd_mask &= ~(MDIO_MMDREG_DEVS_PHYXS | |
181 | MDIO_MMDREG_DEVS_PCS | | 184 | MDIO_MMDREG_DEVS_PCS | |
182 | MDIO_MMDREG_DEVS_PMAPMD); | 185 | MDIO_MMDREG_DEVS_PMAPMD | |
186 | MDIO_MMDREG_DEVS_AN); | ||
183 | else if (efx->loopback_mode == LOOPBACK_PCS) | 187 | else if (efx->loopback_mode == LOOPBACK_PCS) |
184 | mmd_mask &= ~(MDIO_MMDREG_DEVS_PCS | | 188 | mmd_mask &= ~(MDIO_MMDREG_DEVS_PCS | |
185 | MDIO_MMDREG_DEVS_PMAPMD); | 189 | MDIO_MMDREG_DEVS_PMAPMD | |
190 | MDIO_MMDREG_DEVS_AN); | ||
186 | else if (efx->loopback_mode == LOOPBACK_PMAPMD) | 191 | else if (efx->loopback_mode == LOOPBACK_PMAPMD) |
187 | mmd_mask &= ~MDIO_MMDREG_DEVS_PMAPMD; | 192 | mmd_mask &= ~(MDIO_MMDREG_DEVS_PMAPMD | |
193 | MDIO_MMDREG_DEVS_AN); | ||
188 | 194 | ||
189 | while (mmd_mask) { | 195 | while (mmd_mask) { |
190 | if (mmd_mask & 1) { | 196 | if (mmd_mask & 1) { |
@@ -244,6 +250,7 @@ void mdio_clause45_set_mmds_lpower(struct efx_nic *efx, | |||
244 | int low_power, unsigned int mmd_mask) | 250 | int low_power, unsigned int mmd_mask) |
245 | { | 251 | { |
246 | int mmd = 0; | 252 | int mmd = 0; |
253 | mmd_mask &= ~MDIO_MMDREG_DEVS_AN; | ||
247 | while (mmd_mask) { | 254 | while (mmd_mask) { |
248 | if (mmd_mask & 1) | 255 | if (mmd_mask & 1) |
249 | mdio_clause45_set_mmd_lpower(efx, low_power, mmd); | 256 | mdio_clause45_set_mmd_lpower(efx, low_power, mmd); |
@@ -252,103 +259,302 @@ void mdio_clause45_set_mmds_lpower(struct efx_nic *efx, | |||
252 | } | 259 | } |
253 | } | 260 | } |
254 | 261 | ||
262 | static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr, u32 xnp) | ||
263 | { | ||
264 | int phy_id = efx->mii.phy_id; | ||
265 | u32 result = 0; | ||
266 | int reg; | ||
267 | |||
268 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, addr); | ||
269 | if (reg & ADVERTISE_10HALF) | ||
270 | result |= ADVERTISED_10baseT_Half; | ||
271 | if (reg & ADVERTISE_10FULL) | ||
272 | result |= ADVERTISED_10baseT_Full; | ||
273 | if (reg & ADVERTISE_100HALF) | ||
274 | result |= ADVERTISED_100baseT_Half; | ||
275 | if (reg & ADVERTISE_100FULL) | ||
276 | result |= ADVERTISED_100baseT_Full; | ||
277 | if (reg & LPA_RESV) | ||
278 | result |= xnp; | ||
279 | |||
280 | return result; | ||
281 | } | ||
282 | |||
255 | /** | 283 | /** |
256 | * mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO. | 284 | * mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO. |
257 | * @efx: Efx NIC | 285 | * @efx: Efx NIC |
258 | * @ecmd: Buffer for settings | 286 | * @ecmd: Buffer for settings |
259 | * | 287 | * |
260 | * On return the 'port', 'speed', 'supported' and 'advertising' fields of | 288 | * On return the 'port', 'speed', 'supported' and 'advertising' fields of |
261 | * ecmd have been filled out based on the PMA type. | 289 | * ecmd have been filled out. |
262 | */ | 290 | */ |
263 | void mdio_clause45_get_settings(struct efx_nic *efx, | 291 | void mdio_clause45_get_settings(struct efx_nic *efx, |
264 | struct ethtool_cmd *ecmd) | 292 | struct ethtool_cmd *ecmd) |
265 | { | 293 | { |
266 | int pma_type; | 294 | mdio_clause45_get_settings_ext(efx, ecmd, 0, 0); |
295 | } | ||
267 | 296 | ||
268 | /* If no PMA is present we are presumably talking something XAUI-ish | 297 | /** |
269 | * like CX4. Which we report as FIBRE (see below) */ | 298 | * mdio_clause45_get_settings_ext - Read (some of) the PHY settings over MDIO. |
270 | if ((efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)) == 0) { | 299 | * @efx: Efx NIC |
271 | ecmd->speed = SPEED_10000; | 300 | * @ecmd: Buffer for settings |
272 | ecmd->port = PORT_FIBRE; | 301 | * @xnp: Advertised Extended Next Page state |
273 | ecmd->supported = SUPPORTED_FIBRE; | 302 | * @xnp_lpa: Link Partner's advertised XNP state |
274 | ecmd->advertising = ADVERTISED_FIBRE; | 303 | * |
275 | return; | 304 | * On return the 'port', 'speed', 'supported' and 'advertising' fields of |
276 | } | 305 | * ecmd have been filled out. |
306 | */ | ||
307 | void mdio_clause45_get_settings_ext(struct efx_nic *efx, | ||
308 | struct ethtool_cmd *ecmd, | ||
309 | u32 xnp, u32 xnp_lpa) | ||
310 | { | ||
311 | int phy_id = efx->mii.phy_id; | ||
312 | int reg; | ||
277 | 313 | ||
278 | pma_type = mdio_clause45_read(efx, efx->mii.phy_id, | 314 | ecmd->transceiver = XCVR_INTERNAL; |
279 | MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL2); | 315 | ecmd->phy_address = phy_id; |
280 | pma_type &= MDIO_PMAPMD_CTRL2_TYPE_MASK; | ||
281 | 316 | ||
282 | switch (pma_type) { | 317 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, |
283 | /* We represent CX4 as fibre in the absence of anything | 318 | MDIO_MMDREG_CTRL2); |
284 | better. */ | 319 | switch (reg & MDIO_PMAPMD_CTRL2_TYPE_MASK) { |
285 | case MDIO_PMAPMD_CTRL2_10G_CX4: | ||
286 | ecmd->speed = SPEED_10000; | ||
287 | ecmd->port = PORT_FIBRE; | ||
288 | ecmd->supported = SUPPORTED_FIBRE; | ||
289 | ecmd->advertising = ADVERTISED_FIBRE; | ||
290 | break; | ||
291 | /* 10G Base-T */ | ||
292 | case MDIO_PMAPMD_CTRL2_10G_BT: | 320 | case MDIO_PMAPMD_CTRL2_10G_BT: |
293 | ecmd->speed = SPEED_10000; | ||
294 | ecmd->port = PORT_TP; | ||
295 | ecmd->supported = SUPPORTED_TP | SUPPORTED_10000baseT_Full; | ||
296 | ecmd->advertising = (ADVERTISED_FIBRE | ||
297 | | ADVERTISED_10000baseT_Full); | ||
298 | break; | ||
299 | case MDIO_PMAPMD_CTRL2_1G_BT: | 321 | case MDIO_PMAPMD_CTRL2_1G_BT: |
300 | ecmd->speed = SPEED_1000; | ||
301 | ecmd->port = PORT_TP; | ||
302 | ecmd->supported = SUPPORTED_TP | SUPPORTED_1000baseT_Full; | ||
303 | ecmd->advertising = (ADVERTISED_FIBRE | ||
304 | | ADVERTISED_1000baseT_Full); | ||
305 | break; | ||
306 | case MDIO_PMAPMD_CTRL2_100_BT: | 322 | case MDIO_PMAPMD_CTRL2_100_BT: |
307 | ecmd->speed = SPEED_100; | ||
308 | ecmd->port = PORT_TP; | ||
309 | ecmd->supported = SUPPORTED_TP | SUPPORTED_100baseT_Full; | ||
310 | ecmd->advertising = (ADVERTISED_FIBRE | ||
311 | | ADVERTISED_100baseT_Full); | ||
312 | break; | ||
313 | case MDIO_PMAPMD_CTRL2_10_BT: | 323 | case MDIO_PMAPMD_CTRL2_10_BT: |
314 | ecmd->speed = SPEED_10; | ||
315 | ecmd->port = PORT_TP; | 324 | ecmd->port = PORT_TP; |
316 | ecmd->supported = SUPPORTED_TP | SUPPORTED_10baseT_Full; | 325 | ecmd->supported = SUPPORTED_TP; |
317 | ecmd->advertising = ADVERTISED_FIBRE | ADVERTISED_10baseT_Full; | 326 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, |
327 | MDIO_MMDREG_SPEED); | ||
328 | if (reg & (1 << MDIO_MMDREG_SPEED_10G_LBN)) | ||
329 | ecmd->supported |= SUPPORTED_10000baseT_Full; | ||
330 | if (reg & (1 << MDIO_MMDREG_SPEED_1000M_LBN)) | ||
331 | ecmd->supported |= (SUPPORTED_1000baseT_Full | | ||
332 | SUPPORTED_1000baseT_Half); | ||
333 | if (reg & (1 << MDIO_MMDREG_SPEED_100M_LBN)) | ||
334 | ecmd->supported |= (SUPPORTED_100baseT_Full | | ||
335 | SUPPORTED_100baseT_Half); | ||
336 | if (reg & (1 << MDIO_MMDREG_SPEED_10M_LBN)) | ||
337 | ecmd->supported |= (SUPPORTED_10baseT_Full | | ||
338 | SUPPORTED_10baseT_Half); | ||
339 | ecmd->advertising = ADVERTISED_TP; | ||
318 | break; | 340 | break; |
319 | /* All the other defined modes are flavours of | 341 | |
320 | * 10G optical */ | 342 | /* We represent CX4 as fibre in the absence of anything better */ |
343 | case MDIO_PMAPMD_CTRL2_10G_CX4: | ||
344 | /* All the other defined modes are flavours of optical */ | ||
321 | default: | 345 | default: |
322 | ecmd->speed = SPEED_10000; | ||
323 | ecmd->port = PORT_FIBRE; | 346 | ecmd->port = PORT_FIBRE; |
324 | ecmd->supported = SUPPORTED_FIBRE; | 347 | ecmd->supported = SUPPORTED_FIBRE; |
325 | ecmd->advertising = ADVERTISED_FIBRE; | 348 | ecmd->advertising = ADVERTISED_FIBRE; |
326 | break; | 349 | break; |
327 | } | 350 | } |
351 | |||
352 | if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) { | ||
353 | ecmd->supported |= SUPPORTED_Autoneg; | ||
354 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, | ||
355 | MDIO_MMDREG_CTRL1); | ||
356 | if (reg & BMCR_ANENABLE) { | ||
357 | ecmd->autoneg = AUTONEG_ENABLE; | ||
358 | ecmd->advertising |= | ||
359 | ADVERTISED_Autoneg | | ||
360 | mdio_clause45_get_an(efx, | ||
361 | MDIO_AN_ADVERTISE, xnp); | ||
362 | } else | ||
363 | ecmd->autoneg = AUTONEG_DISABLE; | ||
364 | } else | ||
365 | ecmd->autoneg = AUTONEG_DISABLE; | ||
366 | |||
367 | /* If AN is enabled and complete, report best common mode */ | ||
368 | if (ecmd->autoneg && | ||
369 | (mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, MDIO_MMDREG_STAT1) & | ||
370 | (1 << MDIO_AN_STATUS_AN_DONE_LBN))) { | ||
371 | u32 common, lpa; | ||
372 | lpa = mdio_clause45_get_an(efx, MDIO_AN_LPA, xnp_lpa); | ||
373 | common = ecmd->advertising & lpa; | ||
374 | if (common & ADVERTISED_10000baseT_Full) { | ||
375 | ecmd->speed = SPEED_10000; | ||
376 | ecmd->duplex = DUPLEX_FULL; | ||
377 | } else if (common & (ADVERTISED_1000baseT_Full | | ||
378 | ADVERTISED_1000baseT_Half)) { | ||
379 | ecmd->speed = SPEED_1000; | ||
380 | ecmd->duplex = !!(common & ADVERTISED_1000baseT_Full); | ||
381 | } else if (common & (ADVERTISED_100baseT_Full | | ||
382 | ADVERTISED_100baseT_Half)) { | ||
383 | ecmd->speed = SPEED_100; | ||
384 | ecmd->duplex = !!(common & ADVERTISED_100baseT_Full); | ||
385 | } else { | ||
386 | ecmd->speed = SPEED_10; | ||
387 | ecmd->duplex = !!(common & ADVERTISED_10baseT_Full); | ||
388 | } | ||
389 | } else { | ||
390 | /* Report forced settings */ | ||
391 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, | ||
392 | MDIO_MMDREG_CTRL1); | ||
393 | ecmd->speed = (((reg & BMCR_SPEED1000) ? 100 : 1) * | ||
394 | ((reg & BMCR_SPEED100) ? 100 : 10)); | ||
395 | ecmd->duplex = (reg & BMCR_FULLDPLX || | ||
396 | ecmd->speed == SPEED_10000); | ||
397 | } | ||
328 | } | 398 | } |
329 | 399 | ||
330 | /** | 400 | /** |
331 | * mdio_clause45_set_settings - Set (some of) the PHY settings over MDIO. | 401 | * mdio_clause45_set_settings - Set (some of) the PHY settings over MDIO. |
332 | * @efx: Efx NIC | 402 | * @efx: Efx NIC |
333 | * @ecmd: New settings | 403 | * @ecmd: New settings |
334 | * | ||
335 | * Currently this just enforces that we are _not_ changing the | ||
336 | * 'port', 'speed', 'supported' or 'advertising' settings as these | ||
337 | * cannot be changed on any currently supported PHY. | ||
338 | */ | 404 | */ |
339 | int mdio_clause45_set_settings(struct efx_nic *efx, | 405 | int mdio_clause45_set_settings(struct efx_nic *efx, |
340 | struct ethtool_cmd *ecmd) | 406 | struct ethtool_cmd *ecmd) |
341 | { | 407 | { |
342 | struct ethtool_cmd tmpcmd; | 408 | int phy_id = efx->mii.phy_id; |
343 | mdio_clause45_get_settings(efx, &tmpcmd); | 409 | struct ethtool_cmd prev; |
344 | /* None of the current PHYs support more than one mode | 410 | u32 required; |
345 | * of operation (and only 10GBT ever will), so keep things | 411 | int ctrl1_bits, reg; |
346 | * simple for now */ | 412 | |
347 | if ((ecmd->speed == tmpcmd.speed) && (ecmd->port == tmpcmd.port) && | 413 | efx->phy_op->get_settings(efx, &prev); |
348 | (ecmd->supported == tmpcmd.supported) && | 414 | |
349 | (ecmd->advertising == tmpcmd.advertising)) | 415 | if (ecmd->advertising == prev.advertising && |
416 | ecmd->speed == prev.speed && | ||
417 | ecmd->duplex == prev.duplex && | ||
418 | ecmd->port == prev.port && | ||
419 | ecmd->autoneg == prev.autoneg) | ||
350 | return 0; | 420 | return 0; |
351 | return -EOPNOTSUPP; | 421 | |
422 | /* We can only change these settings for -T PHYs */ | ||
423 | if (prev.port != PORT_TP || ecmd->port != PORT_TP) | ||
424 | return -EINVAL; | ||
425 | |||
426 | /* Check that PHY supports these settings and work out the | ||
427 | * basic control bits */ | ||
428 | if (ecmd->duplex) { | ||
429 | switch (ecmd->speed) { | ||
430 | case SPEED_10: | ||
431 | ctrl1_bits = BMCR_FULLDPLX; | ||
432 | required = SUPPORTED_10baseT_Full; | ||
433 | break; | ||
434 | case SPEED_100: | ||
435 | ctrl1_bits = BMCR_SPEED100 | BMCR_FULLDPLX; | ||
436 | required = SUPPORTED_100baseT_Full; | ||
437 | break; | ||
438 | case SPEED_1000: | ||
439 | ctrl1_bits = BMCR_SPEED1000 | BMCR_FULLDPLX; | ||
440 | required = SUPPORTED_1000baseT_Full; | ||
441 | break; | ||
442 | case SPEED_10000: | ||
443 | ctrl1_bits = (BMCR_SPEED1000 | BMCR_SPEED100 | | ||
444 | BMCR_FULLDPLX); | ||
445 | required = SUPPORTED_10000baseT_Full; | ||
446 | break; | ||
447 | default: | ||
448 | return -EINVAL; | ||
449 | } | ||
450 | } else { | ||
451 | switch (ecmd->speed) { | ||
452 | case SPEED_10: | ||
453 | ctrl1_bits = 0; | ||
454 | required = SUPPORTED_10baseT_Half; | ||
455 | break; | ||
456 | case SPEED_100: | ||
457 | ctrl1_bits = BMCR_SPEED100; | ||
458 | required = SUPPORTED_100baseT_Half; | ||
459 | break; | ||
460 | case SPEED_1000: | ||
461 | ctrl1_bits = BMCR_SPEED1000; | ||
462 | required = SUPPORTED_1000baseT_Half; | ||
463 | break; | ||
464 | default: | ||
465 | return -EINVAL; | ||
466 | } | ||
467 | } | ||
468 | if (ecmd->autoneg) | ||
469 | required |= SUPPORTED_Autoneg; | ||
470 | required |= ecmd->advertising; | ||
471 | if (required & ~prev.supported) | ||
472 | return -EINVAL; | ||
473 | |||
474 | /* Set the basic control bits */ | ||
475 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, | ||
476 | MDIO_MMDREG_CTRL1); | ||
477 | reg &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX | 0x003c); | ||
478 | reg |= ctrl1_bits; | ||
479 | mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL1, | ||
480 | reg); | ||
481 | |||
482 | /* Set the AN registers */ | ||
483 | if (ecmd->autoneg != prev.autoneg || | ||
484 | ecmd->advertising != prev.advertising) { | ||
485 | bool xnp = false; | ||
486 | |||
487 | if (efx->phy_op->set_xnp_advertise) | ||
488 | xnp = efx->phy_op->set_xnp_advertise(efx, | ||
489 | ecmd->advertising); | ||
490 | |||
491 | if (ecmd->autoneg) { | ||
492 | reg = 0; | ||
493 | if (ecmd->advertising & ADVERTISED_10baseT_Half) | ||
494 | reg |= ADVERTISE_10HALF; | ||
495 | if (ecmd->advertising & ADVERTISED_10baseT_Full) | ||
496 | reg |= ADVERTISE_10FULL; | ||
497 | if (ecmd->advertising & ADVERTISED_100baseT_Half) | ||
498 | reg |= ADVERTISE_100HALF; | ||
499 | if (ecmd->advertising & ADVERTISED_100baseT_Full) | ||
500 | reg |= ADVERTISE_100FULL; | ||
501 | if (xnp) | ||
502 | reg |= ADVERTISE_RESV; | ||
503 | mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, | ||
504 | MDIO_AN_ADVERTISE, reg); | ||
505 | } | ||
506 | |||
507 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, | ||
508 | MDIO_MMDREG_CTRL1); | ||
509 | if (ecmd->autoneg) | ||
510 | reg |= BMCR_ANENABLE | BMCR_ANRESTART; | ||
511 | else | ||
512 | reg &= ~BMCR_ANENABLE; | ||
513 | if (xnp) | ||
514 | reg |= 1 << MDIO_AN_CTRL_XNP_LBN; | ||
515 | else | ||
516 | reg &= ~(1 << MDIO_AN_CTRL_XNP_LBN); | ||
517 | mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, | ||
518 | MDIO_MMDREG_CTRL1, reg); | ||
519 | } | ||
520 | |||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | void mdio_clause45_set_pause(struct efx_nic *efx) | ||
525 | { | ||
526 | int phy_id = efx->mii.phy_id; | ||
527 | int reg; | ||
528 | |||
529 | if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) { | ||
530 | /* Set pause capability advertising */ | ||
531 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, | ||
532 | MDIO_AN_ADVERTISE); | ||
533 | reg &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); | ||
534 | reg |= efx_fc_advertise(efx->wanted_fc); | ||
535 | mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, | ||
536 | MDIO_AN_ADVERTISE, reg); | ||
537 | |||
538 | /* Restart auto-negotiation */ | ||
539 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, | ||
540 | MDIO_MMDREG_CTRL1); | ||
541 | if (reg & BMCR_ANENABLE) { | ||
542 | reg |= BMCR_ANRESTART; | ||
543 | mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, | ||
544 | MDIO_MMDREG_CTRL1, reg); | ||
545 | } | ||
546 | } | ||
547 | } | ||
548 | |||
549 | enum efx_fc_type mdio_clause45_get_pause(struct efx_nic *efx) | ||
550 | { | ||
551 | int phy_id = efx->mii.phy_id; | ||
552 | int lpa; | ||
553 | |||
554 | if (!(efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN))) | ||
555 | return efx->wanted_fc; | ||
556 | lpa = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, MDIO_AN_LPA); | ||
557 | return efx_fc_resolve(efx->wanted_fc, lpa); | ||
352 | } | 558 | } |
353 | 559 | ||
354 | void mdio_clause45_set_flag(struct efx_nic *efx, u8 prt, u8 dev, | 560 | void mdio_clause45_set_flag(struct efx_nic *efx, u8 prt, u8 dev, |