Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1598c36a authored by David S. Miller's avatar David S. Miller
Browse files


Jeff Kirsher says:

====================
Intel Wired LAN Driver Updates 2014-07-02

This series contains updates to i40e and i40evf.

Anjali fixes a possible race where we were trying to free the dummy packet
buffer in the function that created it, so cleanup the dummy packet buffer
in i40e_clean_tx_ring() instead.  Also fixes an issue where the filter
program routine was not checking if there were descriptors available for
programming a filter.

Mitch fixes unnecessary delays when sending the admin queue commands by
moving a declaration up one level so we do not dereference it out of scope.
Fixes an issue with the VF where if the admin queue interrupts get lost for
some reason, the VF communication will stall as the VFs have no way of
reaching the PF.  To alleviate this condition, go ahead and check the ARQ
every time we run the service task.  Updates i40evf to allow the watchdog
to fire vector 0 via software, which makes the driver tolerant of dropped
interrupts on that vector.

Paul fixes a shifted '1' to be unsigned to avoid shifting a signed integer.

Jesse disables TPH by default since it is currently not enabled in the
current hardware.  Also finishes the i40e implementation of get_settings
for ethtool.

Catherine adds a new variable (hw.phy.link_info.an_enabled) to track whether
auto-negotiation is enabled, along with the functionality to update the
variable.  Adds the functionality to set the requested flow control mode.
Adds i40e implementation of setpauseparam and set_settings to ethtool.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents dbaaca81 4e776381
Loading
Loading
Loading
Loading
+200 −0
Original line number Diff line number Diff line
@@ -1036,6 +1036,164 @@ void i40e_led_set(struct i40e_hw *hw, u32 mode, bool blink)

/* Admin command wrappers */

/**
 * i40e_aq_get_phy_capabilities
 * @hw: pointer to the hw struct
 * @abilities: structure for PHY capabilities to be filled
 * @qualified_modules: report Qualified Modules
 * @report_init: report init capabilities (active are default)
 * @cmd_details: pointer to command details structure or NULL
 *
 * Returns the various PHY abilities supported on the Port.
 **/
i40e_status i40e_aq_get_phy_capabilities(struct i40e_hw *hw,
			bool qualified_modules, bool report_init,
			struct i40e_aq_get_phy_abilities_resp *abilities,
			struct i40e_asq_cmd_details *cmd_details)
{
	struct i40e_aq_desc desc;
	i40e_status status;
	u16 abilities_size = sizeof(struct i40e_aq_get_phy_abilities_resp);

	if (!abilities)
		return I40E_ERR_PARAM;

	i40e_fill_default_direct_cmd_desc(&desc,
					  i40e_aqc_opc_get_phy_abilities);

	desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
	if (abilities_size > I40E_AQ_LARGE_BUF)
		desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);

	if (qualified_modules)
		desc.params.external.param0 |=
			cpu_to_le32(I40E_AQ_PHY_REPORT_QUALIFIED_MODULES);

	if (report_init)
		desc.params.external.param0 |=
			cpu_to_le32(I40E_AQ_PHY_REPORT_INITIAL_VALUES);

	status = i40e_asq_send_command(hw, &desc, abilities, abilities_size,
				       cmd_details);

	if (hw->aq.asq_last_status == I40E_AQ_RC_EIO)
		status = I40E_ERR_UNKNOWN_PHY;

	return status;
}

/**
 * i40e_aq_set_phy_config
 * @hw: pointer to the hw struct
 * @config: structure with PHY configuration to be set
 * @cmd_details: pointer to command details structure or NULL
 *
 * Set the various PHY configuration parameters
 * supported on the Port.One or more of the Set PHY config parameters may be
 * ignored in an MFP mode as the PF may not have the privilege to set some
 * of the PHY Config parameters. This status will be indicated by the
 * command response.
 **/
enum i40e_status_code i40e_aq_set_phy_config(struct i40e_hw *hw,
				struct i40e_aq_set_phy_config *config,
				struct i40e_asq_cmd_details *cmd_details)
{
	struct i40e_aq_desc desc;
	struct i40e_aq_set_phy_config *cmd =
			(struct i40e_aq_set_phy_config *)&desc.params.raw;
	enum i40e_status_code status;

	if (!config)
		return I40E_ERR_PARAM;

	i40e_fill_default_direct_cmd_desc(&desc,
					  i40e_aqc_opc_set_phy_config);

	*cmd = *config;

	status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);

	return status;
}

/**
 * i40e_set_fc
 * @hw: pointer to the hw struct
 *
 * Set the requested flow control mode using set_phy_config.
 **/
enum i40e_status_code i40e_set_fc(struct i40e_hw *hw, u8 *aq_failures,
				  bool atomic_restart)
{
	enum i40e_fc_mode fc_mode = hw->fc.requested_mode;
	struct i40e_aq_get_phy_abilities_resp abilities;
	struct i40e_aq_set_phy_config config;
	enum i40e_status_code status;
	u8 pause_mask = 0x0;

	*aq_failures = 0x0;

	switch (fc_mode) {
	case I40E_FC_FULL:
		pause_mask |= I40E_AQ_PHY_FLAG_PAUSE_TX;
		pause_mask |= I40E_AQ_PHY_FLAG_PAUSE_RX;
		break;
	case I40E_FC_RX_PAUSE:
		pause_mask |= I40E_AQ_PHY_FLAG_PAUSE_RX;
		break;
	case I40E_FC_TX_PAUSE:
		pause_mask |= I40E_AQ_PHY_FLAG_PAUSE_TX;
		break;
	default:
		break;
	}

	/* Get the current phy config */
	status = i40e_aq_get_phy_capabilities(hw, false, false, &abilities,
					      NULL);
	if (status) {
		*aq_failures |= I40E_SET_FC_AQ_FAIL_GET;
		return status;
	}

	memset(&config, 0, sizeof(struct i40e_aq_set_phy_config));
	/* clear the old pause settings */
	config.abilities = abilities.abilities & ~(I40E_AQ_PHY_FLAG_PAUSE_TX) &
			   ~(I40E_AQ_PHY_FLAG_PAUSE_RX);
	/* set the new abilities */
	config.abilities |= pause_mask;
	/* If the abilities have changed, then set the new config */
	if (config.abilities != abilities.abilities) {
		/* Auto restart link so settings take effect */
		if (atomic_restart)
			config.abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
		/* Copy over all the old settings */
		config.phy_type = abilities.phy_type;
		config.link_speed = abilities.link_speed;
		config.eee_capability = abilities.eee_capability;
		config.eeer = abilities.eeer_val;
		config.low_power_ctrl = abilities.d3_lpan;
		status = i40e_aq_set_phy_config(hw, &config, NULL);

		if (status)
			*aq_failures |= I40E_SET_FC_AQ_FAIL_SET;
	}
	/* Update the link info */
	status = i40e_update_link_info(hw, true);
	if (status) {
		/* Wait a little bit (on 40G cards it sometimes takes a really
		 * long time for link to come back from the atomic reset)
		 * and try once more
		 */
		msleep(1000);
		status = i40e_update_link_info(hw, true);
	}
	if (status)
		*aq_failures |= I40E_SET_FC_AQ_FAIL_UPDATE;

	return status;
}

/**
 * i40e_aq_clear_pxe_mode
 * @hw: pointer to the hw struct
@@ -1112,6 +1270,7 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw,
		(struct i40e_aqc_get_link_status *)&desc.params.raw;
	struct i40e_link_status *hw_link_info = &hw->phy.link_info;
	i40e_status status;
	bool tx_pause, rx_pause;
	u16 command_flags;

	i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_get_link_status);
@@ -1141,6 +1300,18 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw,
	hw_link_info->max_frame_size = le16_to_cpu(resp->max_frame_size);
	hw_link_info->pacing = resp->config & I40E_AQ_CONFIG_PACING_MASK;

	/* update fc info */
	tx_pause = !!(resp->an_info & I40E_AQ_LINK_PAUSE_TX);
	rx_pause = !!(resp->an_info & I40E_AQ_LINK_PAUSE_RX);
	if (tx_pause & rx_pause)
		hw->fc.current_mode = I40E_FC_FULL;
	else if (tx_pause)
		hw->fc.current_mode = I40E_FC_TX_PAUSE;
	else if (rx_pause)
		hw->fc.current_mode = I40E_FC_RX_PAUSE;
	else
		hw->fc.current_mode = I40E_FC_NONE;

	if (resp->config & I40E_AQ_CONFIG_CRC_ENA)
		hw_link_info->crc_enable = true;
	else
@@ -1162,6 +1333,35 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw,
	return status;
}

/**
 * i40e_update_link_info
 * @hw: pointer to the hw struct
 * @enable_lse: enable/disable LinkStatusEvent reporting
 *
 * Returns the link status of the adapter
 **/
i40e_status i40e_update_link_info(struct i40e_hw *hw, bool enable_lse)
{
	struct i40e_aq_get_phy_abilities_resp abilities;
	i40e_status status;

	status = i40e_aq_get_link_info(hw, enable_lse, NULL, NULL);
	if (status)
		return status;

	status = i40e_aq_get_phy_capabilities(hw, false, false,
					      &abilities, NULL);
	if (status)
		return status;

	if (abilities.abilities & I40E_AQ_PHY_AN_ENABLED)
		hw->phy.link_info.an_enabled = true;
	else
		hw->phy.link_info.an_enabled = false;

	return status;
}

/**
 * i40e_aq_add_vsi
 * @hw: pointer to the hw struct
+380 −42
Original line number Diff line number Diff line
@@ -215,52 +215,135 @@ static int i40e_get_settings(struct net_device *netdev,
	/* hardware is either in 40G mode or 10G mode
	 * NOTE: this section initializes supported and advertising
	 */
	if (!link_up) {
		/* link is down and the driver needs to fall back on
		 * device ID to determine what kinds of info to display,
		 * it's mostly a guess that may change when link is up
		 */
		switch (hw->device_id) {
		case I40E_DEV_ID_QSFP_A:
		case I40E_DEV_ID_QSFP_B:
		case I40E_DEV_ID_QSFP_C:
			/* pluggable QSFP */
			ecmd->supported = SUPPORTED_40000baseSR4_Full |
					  SUPPORTED_40000baseCR4_Full |
					  SUPPORTED_40000baseLR4_Full;
			ecmd->advertising = ADVERTISED_40000baseSR4_Full |
					    ADVERTISED_40000baseCR4_Full |
					    ADVERTISED_40000baseLR4_Full;
			break;
		case I40E_DEV_ID_KX_B:
			/* backplane 40G */
			ecmd->supported = SUPPORTED_40000baseKR4_Full;
			ecmd->advertising = ADVERTISED_40000baseKR4_Full;
			break;
		case I40E_DEV_ID_KX_C:
			/* backplane 10G */
			ecmd->supported = SUPPORTED_10000baseKR_Full;
			ecmd->advertising = ADVERTISED_10000baseKR_Full;
			break;
		default:
			/* all the rest are 10G/1G */
			ecmd->supported = SUPPORTED_10000baseT_Full |
					  SUPPORTED_1000baseT_Full;
			ecmd->advertising = ADVERTISED_10000baseT_Full |
					    ADVERTISED_1000baseT_Full;
			break;
		}

		/* skip phy_type use as it is zero when link is down */
		goto no_valid_phy_type;
	}

	switch (hw_link_info->phy_type) {
	case I40E_PHY_TYPE_40GBASE_CR4:
	case I40E_PHY_TYPE_40GBASE_CR4_CU:
		ecmd->supported = SUPPORTED_40000baseCR4_Full;
		ecmd->advertising = ADVERTISED_40000baseCR4_Full;
		ecmd->supported = SUPPORTED_Autoneg |
				  SUPPORTED_40000baseCR4_Full;
		ecmd->advertising = ADVERTISED_Autoneg |
				    ADVERTISED_40000baseCR4_Full;
		break;
	case I40E_PHY_TYPE_40GBASE_KR4:
		ecmd->supported = SUPPORTED_40000baseKR4_Full;
		ecmd->advertising = ADVERTISED_40000baseKR4_Full;
		ecmd->supported = SUPPORTED_Autoneg |
				  SUPPORTED_40000baseKR4_Full;
		ecmd->advertising = ADVERTISED_Autoneg |
				    ADVERTISED_40000baseKR4_Full;
		break;
	case I40E_PHY_TYPE_40GBASE_SR4:
	case I40E_PHY_TYPE_XLPPI:
	case I40E_PHY_TYPE_XLAUI:
		ecmd->supported = SUPPORTED_40000baseSR4_Full;
		ecmd->advertising = ADVERTISED_40000baseSR4_Full;
		break;
	case I40E_PHY_TYPE_40GBASE_LR4:
		ecmd->supported = SUPPORTED_40000baseLR4_Full;
		ecmd->advertising = ADVERTISED_40000baseLR4_Full;
		break;
	case I40E_PHY_TYPE_10GBASE_KX4:
		ecmd->supported = SUPPORTED_10000baseKX4_Full;
		ecmd->advertising = ADVERTISED_10000baseKX4_Full;
		ecmd->supported = SUPPORTED_Autoneg |
				  SUPPORTED_10000baseKX4_Full;
		ecmd->advertising = ADVERTISED_Autoneg |
				    ADVERTISED_10000baseKX4_Full;
		break;
	case I40E_PHY_TYPE_10GBASE_KR:
		ecmd->supported = SUPPORTED_10000baseKR_Full;
		ecmd->advertising = ADVERTISED_10000baseKR_Full;
		ecmd->supported = SUPPORTED_Autoneg |
				  SUPPORTED_10000baseKR_Full;
		ecmd->advertising = ADVERTISED_Autoneg |
				    ADVERTISED_10000baseKR_Full;
		break;
	default:
		if (i40e_is_40G_device(hw->device_id)) {
			ecmd->supported = SUPPORTED_40000baseSR4_Full;
			ecmd->advertising = ADVERTISED_40000baseSR4_Full;
		} else {
	case I40E_PHY_TYPE_10GBASE_SR:
	case I40E_PHY_TYPE_10GBASE_LR:
		ecmd->supported = SUPPORTED_10000baseT_Full;
		break;
	case I40E_PHY_TYPE_10GBASE_CR1_CU:
	case I40E_PHY_TYPE_10GBASE_CR1:
	case I40E_PHY_TYPE_10GBASE_T:
		ecmd->supported = SUPPORTED_Autoneg |
				  SUPPORTED_10000baseT_Full;
		ecmd->advertising = ADVERTISED_Autoneg |
				    ADVERTISED_10000baseT_Full;
		break;
	case I40E_PHY_TYPE_XAUI:
	case I40E_PHY_TYPE_XFI:
	case I40E_PHY_TYPE_SFI:
	case I40E_PHY_TYPE_10GBASE_SFPP_CU:
		ecmd->supported = SUPPORTED_10000baseT_Full;
			ecmd->advertising = ADVERTISED_10000baseT_Full;
		}
		break;
	case I40E_PHY_TYPE_1000BASE_KX:
	case I40E_PHY_TYPE_1000BASE_T:
		ecmd->supported = SUPPORTED_Autoneg |
				  SUPPORTED_1000baseT_Full;
		ecmd->advertising = ADVERTISED_Autoneg |
				    ADVERTISED_1000baseT_Full;
		break;
	case I40E_PHY_TYPE_100BASE_TX:
		ecmd->supported = SUPPORTED_Autoneg |
				  SUPPORTED_100baseT_Full;
		ecmd->advertising = ADVERTISED_Autoneg |
				    ADVERTISED_100baseT_Full;
		break;
	case I40E_PHY_TYPE_SGMII:
		ecmd->supported = SUPPORTED_Autoneg |
				  SUPPORTED_1000baseT_Full |
				  SUPPORTED_100baseT_Full;
		ecmd->advertising = ADVERTISED_Autoneg |
				    ADVERTISED_1000baseT_Full |
				    ADVERTISED_100baseT_Full;
		break;
	default:
		/* if we got here and link is up something bad is afoot */
		WARN_ON(link_up);
	}

	ecmd->supported |= SUPPORTED_Autoneg;
	ecmd->advertising |= ADVERTISED_Autoneg;
no_valid_phy_type:
	/* this is if autoneg is enabled or disabled */
	ecmd->autoneg = ((hw_link_info->an_info & I40E_AQ_AN_COMPLETED) ?
			  AUTONEG_ENABLE : AUTONEG_DISABLE);

	switch (hw->phy.media_type) {
	case I40E_MEDIA_TYPE_BACKPLANE:
		ecmd->supported |= SUPPORTED_Backplane;
		ecmd->advertising |= ADVERTISED_Backplane;
		ecmd->supported |= SUPPORTED_Autoneg |
				   SUPPORTED_Backplane;
		ecmd->advertising |= ADVERTISED_Autoneg |
				     ADVERTISED_Backplane;
		ecmd->port = PORT_NONE;
		break;
	case I40E_MEDIA_TYPE_BASET:
@@ -276,7 +359,6 @@ static int i40e_get_settings(struct net_device *netdev,
		break;
	case I40E_MEDIA_TYPE_FIBER:
		ecmd->supported |= SUPPORTED_FIBRE;
		ecmd->advertising |= ADVERTISED_FIBRE;
		ecmd->port = PORT_FIBRE;
		break;
	case I40E_MEDIA_TYPE_UNKNOWN:
@@ -287,6 +369,25 @@ static int i40e_get_settings(struct net_device *netdev,

	ecmd->transceiver = XCVR_EXTERNAL;

	ecmd->supported |= SUPPORTED_Pause;

	switch (hw->fc.current_mode) {
	case I40E_FC_FULL:
		ecmd->advertising |= ADVERTISED_Pause;
		break;
	case I40E_FC_TX_PAUSE:
		ecmd->advertising |= ADVERTISED_Asym_Pause;
		break;
	case I40E_FC_RX_PAUSE:
		ecmd->advertising |= (ADVERTISED_Pause |
				      ADVERTISED_Asym_Pause);
		break;
	default:
		ecmd->advertising &= ~(ADVERTISED_Pause |
				       ADVERTISED_Asym_Pause);
		break;
	}

	if (link_up) {
		switch (link_speed) {
		case I40E_LINK_SPEED_40GB:
@@ -296,6 +397,9 @@ static int i40e_get_settings(struct net_device *netdev,
		case I40E_LINK_SPEED_10GB:
			ethtool_cmd_speed_set(ecmd, SPEED_10000);
			break;
		case I40E_LINK_SPEED_1GB:
			ethtool_cmd_speed_set(ecmd, SPEED_1000);
			break;
		default:
			break;
		}
@@ -308,6 +412,182 @@ static int i40e_get_settings(struct net_device *netdev,
	return 0;
}

/**
 * i40e_set_settings - Set Speed and Duplex
 * @netdev: network interface device structure
 * @ecmd: ethtool command
 *
 * Set speed/duplex per media_types advertised/forced
 **/
static int i40e_set_settings(struct net_device *netdev,
			     struct ethtool_cmd *ecmd)
{
	struct i40e_netdev_priv *np = netdev_priv(netdev);
	struct i40e_aq_get_phy_abilities_resp abilities;
	struct i40e_aq_set_phy_config config;
	struct i40e_pf *pf = np->vsi->back;
	struct i40e_vsi *vsi = np->vsi;
	struct i40e_hw *hw = &pf->hw;
	struct ethtool_cmd safe_ecmd;
	i40e_status status = 0;
	bool change = false;
	int err = 0;
	u8 autoneg;
	u32 advertise;

	if (vsi != pf->vsi[pf->lan_vsi])
		return -EOPNOTSUPP;

	if (hw->phy.media_type != I40E_MEDIA_TYPE_BASET &&
	    hw->phy.media_type != I40E_MEDIA_TYPE_FIBER &&
	    hw->phy.media_type != I40E_MEDIA_TYPE_BACKPLANE)
		return -EOPNOTSUPP;

	/* get our own copy of the bits to check against */
	memset(&safe_ecmd, 0, sizeof(struct ethtool_cmd));
	i40e_get_settings(netdev, &safe_ecmd);

	/* save autoneg and speed out of ecmd */
	autoneg = ecmd->autoneg;
	advertise = ecmd->advertising;

	/* set autoneg and speed back to what they currently are */
	ecmd->autoneg = safe_ecmd.autoneg;
	ecmd->advertising = safe_ecmd.advertising;

	ecmd->cmd = safe_ecmd.cmd;
	/* If ecmd and safe_ecmd are not the same now, then they are
	 * trying to set something that we do not support
	 */
	if (memcmp(ecmd, &safe_ecmd, sizeof(struct ethtool_cmd)))
		return -EOPNOTSUPP;

	while (test_bit(__I40E_CONFIG_BUSY, &vsi->state))
		usleep_range(1000, 2000);

	/* Get the current phy config */
	status = i40e_aq_get_phy_capabilities(hw, false, false, &abilities,
					      NULL);
	if (status)
		return -EAGAIN;

	/* Copy link_speed and abilities to config in case they are not
	 * set below
	 */
	memset(&config, 0, sizeof(struct i40e_aq_set_phy_config));
	config.link_speed = abilities.link_speed;
	config.abilities = abilities.abilities;

	/* Check autoneg */
	if (autoneg == AUTONEG_ENABLE) {
		/* If autoneg is not supported, return error */
		if (!(safe_ecmd.supported & SUPPORTED_Autoneg)) {
			netdev_info(netdev, "Autoneg not supported on this phy\n");
			return -EINVAL;
		}
		/* If autoneg was not already enabled */
		if (!(hw->phy.link_info.an_info & I40E_AQ_AN_COMPLETED)) {
			config.abilities = abilities.abilities |
					   I40E_AQ_PHY_ENABLE_AN;
			change = true;
		}
	} else {
		/* If autoneg is supported 10GBASE_T is the only phy that
		 * can disable it, so otherwise return error
		 */
		if (safe_ecmd.supported & SUPPORTED_Autoneg &&
		    hw->phy.link_info.phy_type != I40E_PHY_TYPE_10GBASE_T) {
			netdev_info(netdev, "Autoneg cannot be disabled on this phy\n");
			return -EINVAL;
		}
		/* If autoneg is currently enabled */
		if (hw->phy.link_info.an_info & I40E_AQ_AN_COMPLETED) {
			config.abilities = abilities.abilities |
					   ~I40E_AQ_PHY_ENABLE_AN;
			change = true;
		}
	}

	if (advertise & ~safe_ecmd.supported)
		return -EINVAL;

	if (advertise & ADVERTISED_100baseT_Full)
		if (!(abilities.link_speed & I40E_LINK_SPEED_100MB)) {
			config.link_speed |= I40E_LINK_SPEED_100MB;
			change = true;
		}
	if (advertise & ADVERTISED_1000baseT_Full ||
	    advertise & ADVERTISED_1000baseKX_Full)
		if (!(abilities.link_speed & I40E_LINK_SPEED_1GB)) {
			config.link_speed |= I40E_LINK_SPEED_1GB;
			change = true;
		}
	if (advertise & ADVERTISED_10000baseT_Full ||
	    advertise & ADVERTISED_10000baseKX4_Full ||
	    advertise & ADVERTISED_10000baseKR_Full)
		if (!(abilities.link_speed & I40E_LINK_SPEED_10GB)) {
			config.link_speed |= I40E_LINK_SPEED_10GB;
			change = true;
		}
	if (advertise & ADVERTISED_40000baseKR4_Full ||
	    advertise & ADVERTISED_40000baseCR4_Full ||
	    advertise & ADVERTISED_40000baseSR4_Full ||
	    advertise & ADVERTISED_40000baseLR4_Full)
		if (!(abilities.link_speed & I40E_LINK_SPEED_40GB)) {
			config.link_speed |= I40E_LINK_SPEED_40GB;
			change = true;
		}

	if (change) {
		/* copy over the rest of the abilities */
		config.phy_type = abilities.phy_type;
		config.eee_capability = abilities.eee_capability;
		config.eeer = abilities.eeer_val;
		config.low_power_ctrl = abilities.d3_lpan;

		/* If link is up set link and an so changes take effect */
		if (hw->phy.link_info.link_info & I40E_AQ_LINK_UP)
			config.abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK;

		/* make the aq call */
		status = i40e_aq_set_phy_config(hw, &config, NULL);
		if (status) {
			netdev_info(netdev, "Set phy config failed with error %d.\n",
				    status);
			return -EAGAIN;
		}

		status = i40e_update_link_info(hw, true);
		if (status)
			netdev_info(netdev, "Updating link info failed with error %d\n",
				    status);

	} else {
		netdev_info(netdev, "Nothing changed, exiting without setting anything.\n");
	}

	return err;
}

static int i40e_nway_reset(struct net_device *netdev)
{
	/* restart autonegotiation */
	struct i40e_netdev_priv *np = netdev_priv(netdev);
	struct i40e_pf *pf = np->vsi->back;
	struct i40e_hw *hw = &pf->hw;
	bool link_up = hw->phy.link_info.link_info & I40E_AQ_LINK_UP;
	i40e_status ret = 0;

	ret = i40e_aq_set_link_restart_an(hw, link_up, NULL);
	if (ret) {
		netdev_info(netdev, "link restart failed, aq_err=%d\n",
			    pf->hw.aq.asq_last_status);
		return -EIO;
	}

	return 0;
}

/**
 * i40e_get_pauseparam -  Get Flow Control status
 * Return tx/rx-pause status
@@ -334,6 +614,81 @@ static void i40e_get_pauseparam(struct net_device *netdev,
	}
}

/**
 * i40e_set_pauseparam - Set Flow Control parameter
 * @netdev: network interface device structure
 * @pause: return tx/rx flow control status
 **/
static int i40e_set_pauseparam(struct net_device *netdev,
			       struct ethtool_pauseparam *pause)
{
	struct i40e_netdev_priv *np = netdev_priv(netdev);
	struct i40e_pf *pf = np->vsi->back;
	struct i40e_vsi *vsi = np->vsi;
	struct i40e_hw *hw = &pf->hw;
	struct i40e_link_status *hw_link_info = &hw->phy.link_info;
	bool link_up = hw_link_info->link_info & I40E_AQ_LINK_UP;
	i40e_status status;
	u8 aq_failures;
	int err;

	if (vsi != pf->vsi[pf->lan_vsi])
		return -EOPNOTSUPP;

	if (pause->autoneg != ((hw_link_info->an_info & I40E_AQ_AN_COMPLETED) ?
	    AUTONEG_ENABLE : AUTONEG_DISABLE)) {
		netdev_info(netdev, "To change autoneg please use: ethtool -s <dev> autoneg <on|off>\n");
		return -EOPNOTSUPP;
	}

	/* If we have link and don't have autoneg */
	if (!test_bit(__I40E_DOWN, &pf->state) &&
	    !(hw_link_info->an_info & I40E_AQ_AN_COMPLETED)) {
		/* Send message that it might not necessarily work*/
		netdev_info(netdev, "Autoneg did not complete so changing settings may not result in an actual change.\n");
	}

	if (hw->fc.current_mode == I40E_FC_PFC) {
		netdev_info(netdev, "Priority flow control enabled. Cannot set link flow control.\n");
		return -EOPNOTSUPP;
	}

	if (pause->rx_pause && pause->tx_pause)
		hw->fc.requested_mode = I40E_FC_FULL;
	else if (pause->rx_pause && !pause->tx_pause)
		hw->fc.requested_mode = I40E_FC_RX_PAUSE;
	else if (!pause->rx_pause && pause->tx_pause)
		hw->fc.requested_mode = I40E_FC_TX_PAUSE;
	else if (!pause->rx_pause && !pause->tx_pause)
		hw->fc.requested_mode = I40E_FC_NONE;
	else
		 return -EINVAL;

	/* Set the fc mode and only restart an if link is up*/
	status = i40e_set_fc(hw, &aq_failures, link_up);

	if (aq_failures & I40E_SET_FC_AQ_FAIL_GET) {
		netdev_info(netdev, "Set fc failed on the get_phy_capabilities call with error %d and status %d\n",
			    status, hw->aq.asq_last_status);
		err = -EAGAIN;
	}
	if (aq_failures & I40E_SET_FC_AQ_FAIL_SET) {
		netdev_info(netdev, "Set fc failed on the set_phy_config call with error %d and status %d\n",
			    status, hw->aq.asq_last_status);
		err = -EAGAIN;
	}
	if (aq_failures & I40E_SET_FC_AQ_FAIL_UPDATE) {
		netdev_info(netdev, "Set fc failed on the update_link_info call with error %d and status %d\n",
			    status, hw->aq.asq_last_status);
		err = -EAGAIN;
	}

	if (!test_bit(__I40E_DOWN, &pf->state))
		return i40e_nway_reset(netdev);

	return err;
}

static u32 i40e_get_msglevel(struct net_device *netdev)
{
	struct i40e_netdev_priv *np = netdev_priv(netdev);
@@ -1021,25 +1376,6 @@ static int i40e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
	return 0;
}

static int i40e_nway_reset(struct net_device *netdev)
{
	/* restart autonegotiation */
	struct i40e_netdev_priv *np = netdev_priv(netdev);
	struct i40e_pf *pf = np->vsi->back;
	struct i40e_hw *hw = &pf->hw;
	bool link_up = hw->phy.link_info.link_info & I40E_AQ_LINK_UP;
	i40e_status ret = 0;

	ret = i40e_aq_set_link_restart_an(hw, link_up, NULL);
	if (ret) {
		netdev_info(netdev, "link restart failed, aq_err=%d\n",
			    pf->hw.aq.asq_last_status);
		return -EIO;
	}

	return 0;
}

static int i40e_set_phys_id(struct net_device *netdev,
			    enum ethtool_phys_id_state state)
{
@@ -1750,6 +2086,7 @@ static int i40e_set_channels(struct net_device *dev,

static const struct ethtool_ops i40e_ethtool_ops = {
	.get_settings		= i40e_get_settings,
	.set_settings		= i40e_set_settings,
	.get_drvinfo		= i40e_get_drvinfo,
	.get_regs_len		= i40e_get_regs_len,
	.get_regs		= i40e_get_regs,
@@ -1762,6 +2099,7 @@ static const struct ethtool_ops i40e_ethtool_ops = {
	.get_ringparam		= i40e_get_ringparam,
	.set_ringparam		= i40e_set_ringparam,
	.get_pauseparam		= i40e_get_pauseparam,
	.set_pauseparam		= i40e_set_pauseparam,
	.get_msglevel		= i40e_get_msglevel,
	.set_msglevel		= i40e_set_msglevel,
	.get_rxnfc		= i40e_get_rxnfc,
+2 −2
Original line number Diff line number Diff line
@@ -127,7 +127,7 @@ struct i40e_hmc_info {
		((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) <<		\
		I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) |			\
		(1 << I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT);		\
	val3 = (sd_index) | (1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT);	\
	val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT);	\
	wr32((hw), I40E_PFHMC_SDDATAHIGH, val1);			\
	wr32((hw), I40E_PFHMC_SDDATALOW, val2);				\
	wr32((hw), I40E_PFHMC_SDCMD, val3);				\
@@ -146,7 +146,7 @@ struct i40e_hmc_info {
		I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) |		\
		((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) <<		\
		I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT);			\
	val3 = (sd_index) | (1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT);	\
	val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT);	\
	wr32((hw), I40E_PFHMC_SDDATAHIGH, 0);				\
	wr32((hw), I40E_PFHMC_SDDATALOW, val2);				\
	wr32((hw), I40E_PFHMC_SDCMD, val3);				\
+33 −74

File changed.

Preview size limit exceeded, changes collapsed.

+10 −0
Original line number Diff line number Diff line
@@ -74,6 +74,15 @@ i40e_status i40e_aq_set_phy_debug(struct i40e_hw *hw, u8 cmd_flags,
				struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_default_vsi(struct i40e_hw *hw, u16 vsi_id,
				struct i40e_asq_cmd_details *cmd_details);
enum i40e_status_code i40e_aq_get_phy_capabilities(struct i40e_hw *hw,
			bool qualified_modules, bool report_init,
			struct i40e_aq_get_phy_abilities_resp *abilities,
			struct i40e_asq_cmd_details *cmd_details);
enum i40e_status_code i40e_aq_set_phy_config(struct i40e_hw *hw,
				struct i40e_aq_set_phy_config *config,
				struct i40e_asq_cmd_details *cmd_details);
enum i40e_status_code i40e_set_fc(struct i40e_hw *hw, u8 *aq_failures,
				  bool atomic_reset);
i40e_status i40e_aq_clear_pxe_mode(struct i40e_hw *hw,
				struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_link_restart_an(struct i40e_hw *hw,
@@ -82,6 +91,7 @@ i40e_status i40e_aq_set_link_restart_an(struct i40e_hw *hw,
i40e_status i40e_aq_get_link_info(struct i40e_hw *hw,
				bool enable_lse, struct i40e_link_status *link,
				struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_update_link_info(struct i40e_hw *hw, bool enable_lse);
i40e_status i40e_aq_set_local_advt_reg(struct i40e_hw *hw,
				u64 advt_reg,
				struct i40e_asq_cmd_details *cmd_details);
Loading