diff options
author | Catherine Sullivan <catherine.sullivan@intel.com> | 2014-06-04 04:45:28 -0400 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2014-07-02 22:02:22 -0400 |
commit | bf9c71417f721abf6853d0ae56be8cf228f92888 (patch) | |
tree | 1f6c87c14820a9148daa424d2ac7012a623d8fe7 | |
parent | 2becc35aa74cbaf9c84e6ae166faab7a321d25ca (diff) |
i40e: Implement set_settings for ethtool
Implement set_settings for ethtool in i40e.
Change-ID: Ie3c3fe18e8ff86c3f25b842844b3d9aabc9bba57
Signed-off-by: Catherine Sullivan <catherine.sullivan@intel.com>
Tested-by: Jim Young <jamesx.m.young@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index fc86761950d0..3abd3cbab75f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c | |||
@@ -412,6 +412,163 @@ no_valid_phy_type: | |||
412 | return 0; | 412 | return 0; |
413 | } | 413 | } |
414 | 414 | ||
415 | /** | ||
416 | * i40e_set_settings - Set Speed and Duplex | ||
417 | * @netdev: network interface device structure | ||
418 | * @ecmd: ethtool command | ||
419 | * | ||
420 | * Set speed/duplex per media_types advertised/forced | ||
421 | **/ | ||
422 | static int i40e_set_settings(struct net_device *netdev, | ||
423 | struct ethtool_cmd *ecmd) | ||
424 | { | ||
425 | struct i40e_netdev_priv *np = netdev_priv(netdev); | ||
426 | struct i40e_aq_get_phy_abilities_resp abilities; | ||
427 | struct i40e_aq_set_phy_config config; | ||
428 | struct i40e_pf *pf = np->vsi->back; | ||
429 | struct i40e_vsi *vsi = np->vsi; | ||
430 | struct i40e_hw *hw = &pf->hw; | ||
431 | struct ethtool_cmd safe_ecmd; | ||
432 | i40e_status status = 0; | ||
433 | bool change = false; | ||
434 | int err = 0; | ||
435 | u8 autoneg; | ||
436 | u32 advertise; | ||
437 | |||
438 | if (vsi != pf->vsi[pf->lan_vsi]) | ||
439 | return -EOPNOTSUPP; | ||
440 | |||
441 | if (hw->phy.media_type != I40E_MEDIA_TYPE_BASET && | ||
442 | hw->phy.media_type != I40E_MEDIA_TYPE_FIBER && | ||
443 | hw->phy.media_type != I40E_MEDIA_TYPE_BACKPLANE) | ||
444 | return -EOPNOTSUPP; | ||
445 | |||
446 | /* get our own copy of the bits to check against */ | ||
447 | memset(&safe_ecmd, 0, sizeof(struct ethtool_cmd)); | ||
448 | i40e_get_settings(netdev, &safe_ecmd); | ||
449 | |||
450 | /* save autoneg and speed out of ecmd */ | ||
451 | autoneg = ecmd->autoneg; | ||
452 | advertise = ecmd->advertising; | ||
453 | |||
454 | /* set autoneg and speed back to what they currently are */ | ||
455 | ecmd->autoneg = safe_ecmd.autoneg; | ||
456 | ecmd->advertising = safe_ecmd.advertising; | ||
457 | |||
458 | ecmd->cmd = safe_ecmd.cmd; | ||
459 | /* If ecmd and safe_ecmd are not the same now, then they are | ||
460 | * trying to set something that we do not support | ||
461 | */ | ||
462 | if (memcmp(ecmd, &safe_ecmd, sizeof(struct ethtool_cmd))) | ||
463 | return -EOPNOTSUPP; | ||
464 | |||
465 | while (test_bit(__I40E_CONFIG_BUSY, &vsi->state)) | ||
466 | usleep_range(1000, 2000); | ||
467 | |||
468 | /* Get the current phy config */ | ||
469 | status = i40e_aq_get_phy_capabilities(hw, false, false, &abilities, | ||
470 | NULL); | ||
471 | if (status) | ||
472 | return -EAGAIN; | ||
473 | |||
474 | /* Copy link_speed and abilities to config in case they are not | ||
475 | * set below | ||
476 | */ | ||
477 | memset(&config, 0, sizeof(struct i40e_aq_set_phy_config)); | ||
478 | config.link_speed = abilities.link_speed; | ||
479 | config.abilities = abilities.abilities; | ||
480 | |||
481 | /* Check autoneg */ | ||
482 | if (autoneg == AUTONEG_ENABLE) { | ||
483 | /* If autoneg is not supported, return error */ | ||
484 | if (!(safe_ecmd.supported & SUPPORTED_Autoneg)) { | ||
485 | netdev_info(netdev, "Autoneg not supported on this phy\n"); | ||
486 | return -EINVAL; | ||
487 | } | ||
488 | /* If autoneg was not already enabled */ | ||
489 | if (!(hw->phy.link_info.an_info & I40E_AQ_AN_COMPLETED)) { | ||
490 | config.abilities = abilities.abilities | | ||
491 | I40E_AQ_PHY_ENABLE_AN; | ||
492 | change = true; | ||
493 | } | ||
494 | } else { | ||
495 | /* If autoneg is supported 10GBASE_T is the only phy that | ||
496 | * can disable it, so otherwise return error | ||
497 | */ | ||
498 | if (safe_ecmd.supported & SUPPORTED_Autoneg && | ||
499 | hw->phy.link_info.phy_type != I40E_PHY_TYPE_10GBASE_T) { | ||
500 | netdev_info(netdev, "Autoneg cannot be disabled on this phy\n"); | ||
501 | return -EINVAL; | ||
502 | } | ||
503 | /* If autoneg is currently enabled */ | ||
504 | if (hw->phy.link_info.an_info & I40E_AQ_AN_COMPLETED) { | ||
505 | config.abilities = abilities.abilities | | ||
506 | ~I40E_AQ_PHY_ENABLE_AN; | ||
507 | change = true; | ||
508 | } | ||
509 | } | ||
510 | |||
511 | if (advertise & ~safe_ecmd.supported) | ||
512 | return -EINVAL; | ||
513 | |||
514 | if (advertise & ADVERTISED_100baseT_Full) | ||
515 | if (!(abilities.link_speed & I40E_LINK_SPEED_100MB)) { | ||
516 | config.link_speed |= I40E_LINK_SPEED_100MB; | ||
517 | change = true; | ||
518 | } | ||
519 | if (advertise & ADVERTISED_1000baseT_Full || | ||
520 | advertise & ADVERTISED_1000baseKX_Full) | ||
521 | if (!(abilities.link_speed & I40E_LINK_SPEED_1GB)) { | ||
522 | config.link_speed |= I40E_LINK_SPEED_1GB; | ||
523 | change = true; | ||
524 | } | ||
525 | if (advertise & ADVERTISED_10000baseT_Full || | ||
526 | advertise & ADVERTISED_10000baseKX4_Full || | ||
527 | advertise & ADVERTISED_10000baseKR_Full) | ||
528 | if (!(abilities.link_speed & I40E_LINK_SPEED_10GB)) { | ||
529 | config.link_speed |= I40E_LINK_SPEED_10GB; | ||
530 | change = true; | ||
531 | } | ||
532 | if (advertise & ADVERTISED_40000baseKR4_Full || | ||
533 | advertise & ADVERTISED_40000baseCR4_Full || | ||
534 | advertise & ADVERTISED_40000baseSR4_Full || | ||
535 | advertise & ADVERTISED_40000baseLR4_Full) | ||
536 | if (!(abilities.link_speed & I40E_LINK_SPEED_40GB)) { | ||
537 | config.link_speed |= I40E_LINK_SPEED_40GB; | ||
538 | change = true; | ||
539 | } | ||
540 | |||
541 | if (change) { | ||
542 | /* copy over the rest of the abilities */ | ||
543 | config.phy_type = abilities.phy_type; | ||
544 | config.eee_capability = abilities.eee_capability; | ||
545 | config.eeer = abilities.eeer_val; | ||
546 | config.low_power_ctrl = abilities.d3_lpan; | ||
547 | |||
548 | /* If link is up set link and an so changes take effect */ | ||
549 | if (hw->phy.link_info.link_info & I40E_AQ_LINK_UP) | ||
550 | config.abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK; | ||
551 | |||
552 | /* make the aq call */ | ||
553 | status = i40e_aq_set_phy_config(hw, &config, NULL); | ||
554 | if (status) { | ||
555 | netdev_info(netdev, "Set phy config failed with error %d.\n", | ||
556 | status); | ||
557 | return -EAGAIN; | ||
558 | } | ||
559 | |||
560 | status = i40e_update_link_info(hw, true); | ||
561 | if (status) | ||
562 | netdev_info(netdev, "Updating link info failed with error %d\n", | ||
563 | status); | ||
564 | |||
565 | } else { | ||
566 | netdev_info(netdev, "Nothing changed, exiting without setting anything.\n"); | ||
567 | } | ||
568 | |||
569 | return err; | ||
570 | } | ||
571 | |||
415 | static int i40e_nway_reset(struct net_device *netdev) | 572 | static int i40e_nway_reset(struct net_device *netdev) |
416 | { | 573 | { |
417 | /* restart autonegotiation */ | 574 | /* restart autonegotiation */ |
@@ -1929,6 +2086,7 @@ static int i40e_set_channels(struct net_device *dev, | |||
1929 | 2086 | ||
1930 | static const struct ethtool_ops i40e_ethtool_ops = { | 2087 | static const struct ethtool_ops i40e_ethtool_ops = { |
1931 | .get_settings = i40e_get_settings, | 2088 | .get_settings = i40e_get_settings, |
2089 | .set_settings = i40e_set_settings, | ||
1932 | .get_drvinfo = i40e_get_drvinfo, | 2090 | .get_drvinfo = i40e_get_drvinfo, |
1933 | .get_regs_len = i40e_get_regs_len, | 2091 | .get_regs_len = i40e_get_regs_len, |
1934 | .get_regs = i40e_get_regs, | 2092 | .get_regs = i40e_get_regs, |