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

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


Jeff Kirsher says:

====================
Intel Wired LAN Driver Updates

This series contains updates to i40e, i40evf, e1000e, ixgbe and ixgbevf.

Mitch adds support for the VF link state ndo which allows the PF driver
to control the virtual link state of the VF devices.  Added
support for viewing and modifying RSS hash options and RSS hash look-up
table programming through ethtool for i40evf.  Fixed complaint about
the use of min() where min_t() should be used in i40evf.

Anjali adds support for ethtool -k option for NTUPLE control for i40e.

Elizabeth cleans up and refactors i40e_open() to separate out the VSI
code into its own i40e_vsi_open().

Jesse enables the hardware feature head write back to avoid updating the
descriptor ring by marking each descriptor with a DD bit and instead
writes a memory location with an update to where the driver should clean
up to in i40e and i40evf.  Reduces context descriptors for i40e/i40evf
since we do not need context descriptors for every packet, only for
TSO or timesync.

Dan Carpenter fixes a potential array underflow in i40e_vc_process_vf_msg().

Dave fixes an e1000e hardware unit hang where the check for pending Tx work
when link is lost was mistakenly moved to be done only when link is first
detected to be lost.  Fixed a problem with poor network performance on
certain silicon in e1000e when configured for 100M HDX performance.

Carolyn adds register defines needed for time sync functions and the code
to call the updated defines.

Jacob adds the ixgbe function for writing PCI config word and checks
whether the adapter has been removed first.

Mark adds the bit __IXGBEVF_REMOVING to indicate that the module is being
removed because the __IXGBEVF_DOWN bit had been overloaded for this
purpose, but leads to trouble.  ixgbevf_down function can now prevent
multiple executions by doing test_and_set_bit on __IXGBEVF_DOWN.

v2:
- dropped patch Mitch's patch "i40evf: Support RSS option in ethtool"
  based on feedback from Ben Hutchings so that Mitch can re-work the
  patch solution

v3:
- removed unnecessary parenthesis in patch 1 based on feedback from David
  Miller
- changed a macro to get the next queue to a function in patch 2 based on
  feedback from David Miller
- added blank lines after variable declaration and code in two functions
  in patch 6 based on feedback from David Miller
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 28bdc499 5b346dc9
Loading
Loading
Loading
Loading
+32 −10
Original line number Diff line number Diff line
@@ -1090,8 +1090,14 @@ static void e1000_print_hw_hang(struct work_struct *work)
		adapter->tx_hang_recheck = true;
		return;
	}
	/* Real hang detected */
	adapter->tx_hang_recheck = false;

	if (er32(TDH(0)) == er32(TDT(0))) {
		e_dbg("false hang detected, ignoring\n");
		return;
	}

	/* Real hang detected */
	netif_stop_queue(netdev);

	e1e_rphy(hw, MII_BMSR, &phy_status);
@@ -1121,6 +1127,8 @@ static void e1000_print_hw_hang(struct work_struct *work)
	      eop, jiffies, eop_desc->upper.fields.status, er32(STATUS),
	      phy_status, phy_1000t_status, phy_ext_status, pci_status);

	e1000e_dump(adapter);

	/* Suggest workaround for known h/w issue */
	if ((hw->mac.type == e1000_pchlan) && (er32(CTRL) & E1000_CTRL_TFCE))
		e_err("Try turning off Tx pause (flow control) via ethtool\n");
@@ -2890,7 +2898,7 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
	struct e1000_hw *hw = &adapter->hw;
	struct e1000_ring *tx_ring = adapter->tx_ring;
	u64 tdba;
	u32 tdlen, tarc;
	u32 tdlen, tctl, tarc;

	/* Setup the HW Tx Head and Tail descriptor pointers */
	tdba = tx_ring->dma;
@@ -2927,6 +2935,12 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
	/* erratum work around: set txdctl the same for both queues */
	ew32(TXDCTL(1), er32(TXDCTL(0)));

	/* Program the Transmit Control Register */
	tctl = er32(TCTL);
	tctl &= ~E1000_TCTL_CT;
	tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
		(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);

	if (adapter->flags & FLAG_TARC_SPEED_MODE_BIT) {
		tarc = er32(TARC(0));
		/* set the speed mode bit, we'll clear it if we're not at
@@ -2957,6 +2971,8 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
	/* enable Report Status bit */
	adapter->txd_cmd |= E1000_TXD_CMD_RS;

	ew32(TCTL, tctl);

	hw->mac.ops.config_collision_dist(hw);
}

@@ -4798,6 +4814,7 @@ static void e1000e_check_82574_phy_workaround(struct e1000_adapter *adapter)

	if (adapter->phy_hang_count > 1) {
		adapter->phy_hang_count = 0;
		e_dbg("PHY appears hung - resetting\n");
		schedule_work(&adapter->reset_task);
	}
}
@@ -4956,15 +4973,11 @@ static void e1000_watchdog_task(struct work_struct *work)
				mod_timer(&adapter->phy_info_timer,
					  round_jiffies(jiffies + 2 * HZ));

			/* The link is lost so the controller stops DMA.
			 * If there is queued Tx work that cannot be done
			 * or if on an 8000ES2LAN which requires a Rx packet
			 * buffer work-around on link down event, reset the
			 * controller to flush the Tx/Rx packet buffers.
			 * (Do the reset outside of interrupt context).
			/* 8000ES2LAN requires a Rx packet buffer work-around
			 * on link down event; reset the controller to flush
			 * the Rx packet buffer.
			 */
			if ((adapter->flags & FLAG_RX_NEEDS_RESTART) ||
			    (e1000_desc_unused(tx_ring) + 1 < tx_ring->count))
			if (adapter->flags & FLAG_RX_NEEDS_RESTART)
				adapter->flags |= FLAG_RESTART_NOW;
			else
				pm_schedule_suspend(netdev->dev.parent,
@@ -4987,6 +5000,15 @@ link_up:
	adapter->gotc_old = adapter->stats.gotc;
	spin_unlock(&adapter->stats64_lock);

	/* If the link is lost the controller stops DMA, but
	 * if there is queued Tx work it cannot be done.  So
	 * reset the controller to flush the Tx packet buffers.
	 */
	if (!netif_carrier_ok(netdev) &&
	    (e1000_desc_unused(tx_ring) + 1 < tx_ring->count))
		adapter->flags |= FLAG_RESTART_NOW;

	/* If reset is necessary, do it outside of interrupt context. */
	if (adapter->flags & FLAG_RESTART_NOW) {
		schedule_work(&adapter->reset_task);
		/* return immediately since reset is imminent */
+3 −1
Original line number Diff line number Diff line
@@ -208,7 +208,7 @@ struct i40e_pf {
	bool fc_autoneg_status;

	u16 eeprom_version;
	u16 num_vmdq_vsis;         /* num vmdq pools this pf has set up */
	u16 num_vmdq_vsis;         /* num vmdq vsis this pf has set up */
	u16 num_vmdq_qps;          /* num queue pairs per vmdq pool */
	u16 num_vmdq_msix;         /* num queue vectors per vmdq pool */
	u16 num_req_vfs;           /* num vfs requested for this vf */
@@ -558,6 +558,7 @@ int i40e_add_del_fdir(struct i40e_vsi *vsi,
		      struct i40e_fdir_filter *input, bool add);
void i40e_fdir_check_and_reenable(struct i40e_pf *pf);
int i40e_get_current_fd_count(struct i40e_pf *pf);
bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features);
void i40e_set_ethtool_ops(struct net_device *netdev);
struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
					u8 *macaddr, s16 vlan,
@@ -596,6 +597,7 @@ void i40e_irq_dynamic_enable(struct i40e_vsi *vsi, int vector);
void i40e_irq_dynamic_disable_icr0(struct i40e_pf *pf);
void i40e_irq_dynamic_enable_icr0(struct i40e_pf *pf);
int i40e_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
int i40e_vsi_open(struct i40e_vsi *vsi);
void i40e_vlan_stripping_disable(struct i40e_vsi *vsi);
int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid);
int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid);
+80 −9
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ static const char i40e_driver_string[] =

#define DRV_VERSION_MAJOR 0
#define DRV_VERSION_MINOR 3
#define DRV_VERSION_BUILD 34
#define DRV_VERSION_BUILD 36
#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
	     __stringify(DRV_VERSION_MINOR) "." \
	     __stringify(DRV_VERSION_BUILD)    DRV_KERN
@@ -2181,6 +2181,11 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
	tx_ctx.fd_ena = !!(vsi->back->flags & (I40E_FLAG_FD_SB_ENABLED |
					       I40E_FLAG_FD_ATR_ENABLED));
	tx_ctx.timesync_ena = !!(vsi->back->flags & I40E_FLAG_PTP);
	/* FDIR VSI tx ring can still use RS bit and writebacks */
	if (vsi->type != I40E_VSI_FDIR)
		tx_ctx.head_wb_ena = 1;
	tx_ctx.head_wb_addr = ring->dma +
			      (ring->count * sizeof(struct i40e_tx_desc));

	/* As part of VSI creation/update, FW allocates certain
	 * Tx arbitration queue sets for each TC enabled for
@@ -4235,7 +4240,6 @@ static int i40e_open(struct net_device *netdev)
	struct i40e_netdev_priv *np = netdev_priv(netdev);
	struct i40e_vsi *vsi = np->vsi;
	struct i40e_pf *pf = vsi->back;
	char int_name[IFNAMSIZ];
	int err;

	/* disallow open during test */
@@ -4244,6 +4248,31 @@ static int i40e_open(struct net_device *netdev)

	netif_carrier_off(netdev);

	err = i40e_vsi_open(vsi);
	if (err)
		return err;

#ifdef CONFIG_I40E_VXLAN
	vxlan_get_rx_port(netdev);
#endif

	return 0;
}

/**
 * i40e_vsi_open -
 * @vsi: the VSI to open
 *
 * Finish initialization of the VSI.
 *
 * Returns 0 on success, negative value on failure
 **/
int i40e_vsi_open(struct i40e_vsi *vsi)
{
	struct i40e_pf *pf = vsi->back;
	char int_name[IFNAMSIZ];
	int err;

	/* allocate descriptors */
	err = i40e_vsi_setup_tx_resources(vsi);
	if (err)
@@ -4256,18 +4285,22 @@ static int i40e_open(struct net_device *netdev)
	if (err)
		goto err_setup_rx;

	if (!vsi->netdev) {
		err = EINVAL;
		goto err_setup_rx;
	}
	snprintf(int_name, sizeof(int_name) - 1, "%s-%s",
		 dev_driver_string(&pf->pdev->dev), netdev->name);
		 dev_driver_string(&pf->pdev->dev), vsi->netdev->name);
	err = i40e_vsi_request_irq(vsi, int_name);
	if (err)
		goto err_setup_rx;

	/* Notify the stack of the actual queue counts. */
	err = netif_set_real_num_tx_queues(netdev, vsi->num_queue_pairs);
	err = netif_set_real_num_tx_queues(vsi->netdev, vsi->num_queue_pairs);
	if (err)
		goto err_set_queues;

	err = netif_set_real_num_rx_queues(netdev, vsi->num_queue_pairs);
	err = netif_set_real_num_rx_queues(vsi->netdev, vsi->num_queue_pairs);
	if (err)
		goto err_set_queues;

@@ -4275,10 +4308,6 @@ static int i40e_open(struct net_device *netdev)
	if (err)
		goto err_up_complete;

#ifdef CONFIG_I40E_VXLAN
	vxlan_get_rx_port(netdev);
#endif

	return 0;

err_up_complete:
@@ -6408,6 +6437,39 @@ sw_init_done:
	return err;
}

/**
 * i40e_set_ntuple - set the ntuple feature flag and take action
 * @pf: board private structure to initialize
 * @features: the feature set that the stack is suggesting
 *
 * returns a bool to indicate if reset needs to happen
 **/
bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)
{
	bool need_reset = false;

	/* Check if Flow Director n-tuple support was enabled or disabled.  If
	 * the state changed, we need to reset.
	 */
	if (features & NETIF_F_NTUPLE) {
		/* Enable filters and mark for reset */
		if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
			need_reset = true;
		pf->flags |= I40E_FLAG_FD_SB_ENABLED;
	} else {
		/* turn off filters, mark for reset and clear SW filter list */
		if (pf->flags & I40E_FLAG_FD_SB_ENABLED) {
			need_reset = true;
			i40e_fdir_filter_exit(pf);
		}
		pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
		/* if ATR was disabled it can be re-enabled. */
		if (!(pf->flags & I40E_FLAG_FD_ATR_ENABLED))
			pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
	}
	return need_reset;
}

/**
 * i40e_set_features - set the netdev feature flags
 * @netdev: ptr to the netdev being adjusted
@@ -6418,12 +6480,19 @@ static int i40e_set_features(struct net_device *netdev,
{
	struct i40e_netdev_priv *np = netdev_priv(netdev);
	struct i40e_vsi *vsi = np->vsi;
	struct i40e_pf *pf = vsi->back;
	bool need_reset;

	if (features & NETIF_F_HW_VLAN_CTAG_RX)
		i40e_vlan_stripping_enable(vsi);
	else
		i40e_vlan_stripping_disable(vsi);

	need_reset = i40e_set_ntuple(pf, features);

	if (need_reset)
		i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED));

	return 0;
}

@@ -6547,6 +6616,7 @@ static const struct net_device_ops i40e_netdev_ops = {
	.ndo_set_vf_vlan	= i40e_ndo_set_vf_port_vlan,
	.ndo_set_vf_tx_rate	= i40e_ndo_set_vf_bw,
	.ndo_get_vf_config	= i40e_ndo_get_vf_config,
	.ndo_set_vf_link_state	= i40e_ndo_set_vf_link_state,
#ifdef CONFIG_I40E_VXLAN
	.ndo_add_vxlan_port	= i40e_add_vxlan_port,
	.ndo_del_vxlan_port	= i40e_del_vxlan_port,
@@ -6594,6 +6664,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
			   NETIF_F_TSO		       |
			   NETIF_F_TSO6		       |
			   NETIF_F_RXCSUM	       |
			   NETIF_F_NTUPLE	       |
			   NETIF_F_RXHASH	       |
			   0;

+42 −7
Original line number Diff line number Diff line
@@ -618,6 +618,20 @@ static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
	return ret;
}

/**
 * i40e_get_head - Retrieve head from head writeback
 * @tx_ring:  tx ring to fetch head of
 *
 * Returns value of Tx ring head based on value stored
 * in head write-back location
 **/
static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
{
	void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;

	return le32_to_cpu(*(volatile __le32 *)head);
}

/**
 * i40e_clean_tx_irq - Reclaim resources after transmit completes
 * @tx_ring:  tx ring to clean
@@ -629,6 +643,7 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
{
	u16 i = tx_ring->next_to_clean;
	struct i40e_tx_buffer *tx_buf;
	struct i40e_tx_desc *tx_head;
	struct i40e_tx_desc *tx_desc;
	unsigned int total_packets = 0;
	unsigned int total_bytes = 0;
@@ -637,6 +652,8 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
	tx_desc = I40E_TX_DESC(tx_ring, i);
	i -= tx_ring->count;

	tx_head = I40E_TX_DESC(tx_ring, i40e_get_head(tx_ring));

	do {
		struct i40e_tx_desc *eop_desc = tx_buf->next_to_watch;

@@ -647,9 +664,8 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
		/* prevent any other reads prior to eop_desc */
		read_barrier_depends();

		/* if the descriptor isn't done, no work yet to do */
		if (!(eop_desc->cmd_type_offset_bsz &
		      cpu_to_le64(I40E_TX_DESC_DTYPE_DESC_DONE)))
		/* we have caught up to head, no work left to do */
		if (tx_head == tx_desc)
			break;

		/* clear next_to_watch to prevent false hangs */
@@ -905,6 +921,10 @@ int i40e_setup_tx_descriptors(struct i40e_ring *tx_ring)

	/* round up to nearest 4K */
	tx_ring->size = tx_ring->count * sizeof(struct i40e_tx_desc);
	/* add u32 for head writeback, align after this takes care of
	 * guaranteeing this is at least one cache line in size
	 */
	tx_ring->size += sizeof(u32);
	tx_ring->size = ALIGN(tx_ring->size, 4096);
	tx_ring->desc = dma_alloc_coherent(dev, tx_ring->size,
					   &tx_ring->dma, GFP_KERNEL);
@@ -1931,7 +1951,8 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring,
	struct i40e_tx_context_desc *context_desc;
	int i = tx_ring->next_to_use;

	if (!cd_type_cmd_tso_mss && !cd_tunneling && !cd_l2tag2)
	if ((cd_type_cmd_tso_mss == I40E_TX_DESC_DTYPE_CONTEXT) &&
	    !cd_tunneling && !cd_l2tag2)
		return;

	/* grab the next descriptor */
@@ -2042,9 +2063,23 @@ static void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
		tx_bi = &tx_ring->tx_bi[i];
	}

	/* Place RS bit on last descriptor of any packet that spans across the
	 * 4th descriptor (WB_STRIDE aka 0x3) in a 64B cacheline.
	 */
#define WB_STRIDE 0x3
	if (((i & WB_STRIDE) != WB_STRIDE) &&
	    (first <= &tx_ring->tx_bi[i]) &&
	    (first >= &tx_ring->tx_bi[i & ~WB_STRIDE])) {
		tx_desc->cmd_type_offset_bsz =
			build_ctob(td_cmd, td_offset, size, td_tag) |
		cpu_to_le64((u64)I40E_TXD_CMD << I40E_TXD_QW1_CMD_SHIFT);
			cpu_to_le64((u64)I40E_TX_DESC_CMD_EOP <<
					 I40E_TXD_QW1_CMD_SHIFT);
	} else {
		tx_desc->cmd_type_offset_bsz =
			build_ctob(td_cmd, td_offset, size, td_tag) |
			cpu_to_le64((u64)I40E_TXD_CMD <<
					 I40E_TXD_QW1_CMD_SHIFT);
	}

	netdev_tx_sent_queue(netdev_get_tx_queue(tx_ring->netdev,
						 tx_ring->queue_index),
+84 −7
Original line number Diff line number Diff line
@@ -230,6 +230,9 @@ static int i40e_config_vsi_tx_queue(struct i40e_vf *vf, u16 vsi_idx,
	tx_ctx.qlen = info->ring_len;
	tx_ctx.rdylist = le16_to_cpu(pf->vsi[vsi_idx]->info.qs_handle[0]);
	tx_ctx.rdylist_act = 0;
	tx_ctx.head_wb_ena = 1;
	tx_ctx.head_wb_addr = info->dma_ring_addr +
			      (info->ring_len * sizeof(struct i40e_tx_desc));

	/* clear the context in the HMC */
	ret = i40e_clear_lan_tx_queue_context(hw, pf_queue_id);
@@ -1771,7 +1774,7 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, u16 vf_id, u32 v_opcode,
			   u32 v_retval, u8 *msg, u16 msglen)
{
	struct i40e_hw *hw = &pf->hw;
	int local_vf_id = vf_id - hw->func_caps.vf_base_id;
	unsigned int local_vf_id = vf_id - hw->func_caps.vf_base_id;
	struct i40e_vf *vf;
	int ret;

@@ -1920,15 +1923,28 @@ static void i40e_vc_vf_broadcast(struct i40e_pf *pf,
void i40e_vc_notify_link_state(struct i40e_pf *pf)
{
	struct i40e_virtchnl_pf_event pfe;
	struct i40e_hw *hw = &pf->hw;
	struct i40e_vf *vf = pf->vf;
	struct i40e_link_status *ls = &pf->hw.phy.link_info;
	int i;

	pfe.event = I40E_VIRTCHNL_EVENT_LINK_CHANGE;
	pfe.severity = I40E_PF_EVENT_SEVERITY_INFO;
	for (i = 0; i < pf->num_alloc_vfs; i++) {
		if (vf->link_forced) {
			pfe.event_data.link_event.link_status = vf->link_up;
			pfe.event_data.link_event.link_speed =
				(vf->link_up ? I40E_LINK_SPEED_40GB : 0);
		} else {
			pfe.event_data.link_event.link_status =
	    pf->hw.phy.link_info.link_info & I40E_AQ_LINK_UP;
	pfe.event_data.link_event.link_speed = pf->hw.phy.link_info.link_speed;

	i40e_vc_vf_broadcast(pf, I40E_VIRTCHNL_OP_EVENT, I40E_SUCCESS,
			     (u8 *)&pfe, sizeof(struct i40e_virtchnl_pf_event));
				ls->link_info & I40E_AQ_LINK_UP;
			pfe.event_data.link_event.link_speed = ls->link_speed;
		}
		i40e_aq_send_msg_to_vf(hw, vf->vf_id, I40E_VIRTCHNL_OP_EVENT,
				       0, (u8 *)&pfe, sizeof(pfe),
				       NULL);
		vf++;
	}
}

/**
@@ -2193,3 +2209,64 @@ int i40e_ndo_get_vf_config(struct net_device *netdev,
error_param:
	return ret;
}

/**
 * i40e_ndo_set_vf_link_state
 * @netdev: network interface device structure
 * @vf_id: vf identifier
 * @link: required link state
 *
 * Set the link state of a specified VF, regardless of physical link state
 **/
int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link)
{
	struct i40e_netdev_priv *np = netdev_priv(netdev);
	struct i40e_pf *pf = np->vsi->back;
	struct i40e_virtchnl_pf_event pfe;
	struct i40e_hw *hw = &pf->hw;
	struct i40e_vf *vf;
	int ret = 0;

	/* validate the request */
	if (vf_id >= pf->num_alloc_vfs) {
		dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id);
		ret = -EINVAL;
		goto error_out;
	}

	vf = &pf->vf[vf_id];

	pfe.event = I40E_VIRTCHNL_EVENT_LINK_CHANGE;
	pfe.severity = I40E_PF_EVENT_SEVERITY_INFO;

	switch (link) {
	case IFLA_VF_LINK_STATE_AUTO:
		vf->link_forced = false;
		pfe.event_data.link_event.link_status =
			pf->hw.phy.link_info.link_info & I40E_AQ_LINK_UP;
		pfe.event_data.link_event.link_speed =
			pf->hw.phy.link_info.link_speed;
		break;
	case IFLA_VF_LINK_STATE_ENABLE:
		vf->link_forced = true;
		vf->link_up = true;
		pfe.event_data.link_event.link_status = true;
		pfe.event_data.link_event.link_speed = I40E_LINK_SPEED_40GB;
		break;
	case IFLA_VF_LINK_STATE_DISABLE:
		vf->link_forced = true;
		vf->link_up = false;
		pfe.event_data.link_event.link_status = false;
		pfe.event_data.link_event.link_speed = 0;
		break;
	default:
		ret = -EINVAL;
		goto error_out;
	}
	/* Notify the VF of its new link state */
	i40e_aq_send_msg_to_vf(hw, vf->vf_id, I40E_VIRTCHNL_OP_EVENT,
			       0, (u8 *)&pfe, sizeof(pfe), NULL);

error_out:
	return ret;
}
Loading