diff options
Diffstat (limited to 'drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c')
| -rw-r--r-- | drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 274 | 
1 files changed, 195 insertions, 79 deletions
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 60ef6458741..0ee9bd4819f 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -263,6 +263,8 @@ cont_loop:  	tx_ring->total_bytes += total_bytes;  	tx_ring->total_packets += total_packets;  	u64_stats_update_end(&tx_ring->syncp); +	q_vector->tx.total_bytes += total_bytes; +	q_vector->tx.total_packets += total_packets;  	return count < tx_ring->count;  } @@ -272,12 +274,10 @@ cont_loop:   * @q_vector: structure containing interrupt and ring information   * @skb: packet to send up   * @status: hardware indication of status of receive - * @rx_ring: rx descriptor ring (for a specific queue) to setup   * @rx_desc: rx descriptor   **/  static void ixgbevf_receive_skb(struct ixgbevf_q_vector *q_vector,  				struct sk_buff *skb, u8 status, -				struct ixgbevf_ring *ring,  				union ixgbe_adv_rx_desc *rx_desc)  {  	struct ixgbevf_adapter *adapter = q_vector->adapter; @@ -433,11 +433,21 @@ static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,  		if (!(staterr & IXGBE_RXD_STAT_EOP)) {  			skb->next = next_buffer->skb; -			skb->next->prev = skb; +			IXGBE_CB(skb->next)->prev = skb;  			adapter->non_eop_descs++;  			goto next_desc;  		} +		/* we should not be chaining buffers, if we did drop the skb */ +		if (IXGBE_CB(skb)->prev) { +			do { +				struct sk_buff *this = skb; +				skb = IXGBE_CB(skb)->prev; +				dev_kfree_skb(this); +			} while (skb); +			goto next_desc; +		} +  		/* ERR_MASK will only have valid bits if EOP set */  		if (unlikely(staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK)) {  			dev_kfree_skb_irq(skb); @@ -461,7 +471,7 @@ static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,  		}  		skb->protocol = eth_type_trans(skb, rx_ring->netdev); -		ixgbevf_receive_skb(q_vector, skb, staterr, rx_ring, rx_desc); +		ixgbevf_receive_skb(q_vector, skb, staterr, rx_desc);  next_desc:  		rx_desc->wb.upper.status_error = 0; @@ -490,6 +500,8 @@ next_desc:  	rx_ring->total_packets += total_rx_packets;  	rx_ring->total_bytes += total_rx_bytes;  	u64_stats_update_end(&rx_ring->syncp); +	q_vector->rx.total_packets += total_rx_packets; +	q_vector->rx.total_bytes += total_rx_bytes;  	return !!budget;  } @@ -716,40 +728,15 @@ static void ixgbevf_set_itr(struct ixgbevf_q_vector *q_vector)  	}  } -static irqreturn_t ixgbevf_msix_mbx(int irq, void *data) +static irqreturn_t ixgbevf_msix_other(int irq, void *data)  {  	struct ixgbevf_adapter *adapter = data;  	struct ixgbe_hw *hw = &adapter->hw; -	u32 msg; -	bool got_ack = false; - -	if (!hw->mbx.ops.check_for_ack(hw)) -		got_ack = true; -	if (!hw->mbx.ops.check_for_msg(hw)) { -		hw->mbx.ops.read(hw, &msg, 1); +	hw->mac.get_link_status = 1; -		if ((msg & IXGBE_MBVFICR_VFREQ_MASK) == IXGBE_PF_CONTROL_MSG) -			mod_timer(&adapter->watchdog_timer, -				  round_jiffies(jiffies + 1)); - -		if (msg & IXGBE_VT_MSGTYPE_NACK) -			pr_warn("Last Request of type %2.2x to PF Nacked\n", -				msg & 0xFF); -		/* -		 * Restore the PFSTS bit in case someone is polling for a -		 * return message from the PF -		 */ -		hw->mbx.v2p_mailbox |= IXGBE_VFMAILBOX_PFSTS; -	} - -	/* -	 * checking for the ack clears the PFACK bit.  Place -	 * it back in the v2p_mailbox cache so that anyone -	 * polling for an ack will not miss it -	 */ -	if (got_ack) -		hw->mbx.v2p_mailbox |= IXGBE_VFMAILBOX_PFACK; +	if (!test_bit(__IXGBEVF_DOWN, &adapter->state)) +		mod_timer(&adapter->watchdog_timer, jiffies);  	IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, adapter->eims_other); @@ -899,10 +886,10 @@ static int ixgbevf_request_msix_irqs(struct ixgbevf_adapter *adapter)  	}  	err = request_irq(adapter->msix_entries[vector].vector, -			  &ixgbevf_msix_mbx, 0, netdev->name, adapter); +			  &ixgbevf_msix_other, 0, netdev->name, adapter);  	if (err) {  		hw_dbg(&adapter->hw, -		       "request_irq for msix_mbx failed: %d\n", err); +		       "request_irq for msix_other failed: %d\n", err);  		goto free_queue_irqs;  	} @@ -1057,15 +1044,46 @@ static void ixgbevf_configure_srrctl(struct ixgbevf_adapter *adapter, int index)  	srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; -	if (rx_ring->rx_buf_len == MAXIMUM_ETHERNET_VLAN_SIZE) -		srrctl |= IXGBEVF_RXBUFFER_2048 >> -			IXGBE_SRRCTL_BSIZEPKT_SHIFT; -	else -		srrctl |= rx_ring->rx_buf_len >> -			IXGBE_SRRCTL_BSIZEPKT_SHIFT; +	srrctl |= ALIGN(rx_ring->rx_buf_len, 1024) >> +		  IXGBE_SRRCTL_BSIZEPKT_SHIFT; +  	IXGBE_WRITE_REG(hw, IXGBE_VFSRRCTL(index), srrctl);  } +static void ixgbevf_set_rx_buffer_len(struct ixgbevf_adapter *adapter) +{ +	struct ixgbe_hw *hw = &adapter->hw; +	struct net_device *netdev = adapter->netdev; +	int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; +	int i; +	u16 rx_buf_len; + +	/* notify the PF of our intent to use this size of frame */ +	ixgbevf_rlpml_set_vf(hw, max_frame); + +	/* PF will allow an extra 4 bytes past for vlan tagged frames */ +	max_frame += VLAN_HLEN; + +	/* +	 * Make best use of allocation by using all but 1K of a +	 * power of 2 allocation that will be used for skb->head. +	 */ +	if ((hw->mac.type == ixgbe_mac_X540_vf) && +	    (max_frame <= MAXIMUM_ETHERNET_VLAN_SIZE)) +		rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE; +	else if (max_frame <= IXGBEVF_RXBUFFER_3K) +		rx_buf_len = IXGBEVF_RXBUFFER_3K; +	else if (max_frame <= IXGBEVF_RXBUFFER_7K) +		rx_buf_len = IXGBEVF_RXBUFFER_7K; +	else if (max_frame <= IXGBEVF_RXBUFFER_15K) +		rx_buf_len = IXGBEVF_RXBUFFER_15K; +	else +		rx_buf_len = IXGBEVF_MAX_RXBUFFER; + +	for (i = 0; i < adapter->num_rx_queues; i++) +		adapter->rx_ring[i].rx_buf_len = rx_buf_len; +} +  /**   * ixgbevf_configure_rx - Configure 82599 VF Receive Unit after Reset   * @adapter: board private structure @@ -1076,18 +1094,14 @@ static void ixgbevf_configure_rx(struct ixgbevf_adapter *adapter)  {  	u64 rdba;  	struct ixgbe_hw *hw = &adapter->hw; -	struct net_device *netdev = adapter->netdev; -	int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;  	int i, j;  	u32 rdlen; -	int rx_buf_len;  	/* PSRTYPE must be initialized in 82599 */  	IXGBE_WRITE_REG(hw, IXGBE_VFPSRTYPE, 0); -	if (netdev->mtu <= ETH_DATA_LEN) -		rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE; -	else -		rx_buf_len = ALIGN(max_frame, 1024); + +	/* set_rx_buffer_len must be called before ring initialization */ +	ixgbevf_set_rx_buffer_len(adapter);  	rdlen = adapter->rx_ring[0].count * sizeof(union ixgbe_adv_rx_desc);  	/* Setup the HW Rx Head and Tail Descriptor Pointers and @@ -1103,7 +1117,6 @@ static void ixgbevf_configure_rx(struct ixgbevf_adapter *adapter)  		IXGBE_WRITE_REG(hw, IXGBE_VFRDT(j), 0);  		adapter->rx_ring[i].head = IXGBE_VFRDH(j);  		adapter->rx_ring[i].tail = IXGBE_VFRDT(j); -		adapter->rx_ring[i].rx_buf_len = rx_buf_len;  		ixgbevf_configure_srrctl(adapter, j);  	} @@ -1113,36 +1126,47 @@ static int ixgbevf_vlan_rx_add_vid(struct net_device *netdev, u16 vid)  {  	struct ixgbevf_adapter *adapter = netdev_priv(netdev);  	struct ixgbe_hw *hw = &adapter->hw; +	int err; + +	if (!hw->mac.ops.set_vfta) +		return -EOPNOTSUPP;  	spin_lock(&adapter->mbx_lock);  	/* add VID to filter table */ -	if (hw->mac.ops.set_vfta) -		hw->mac.ops.set_vfta(hw, vid, 0, true); +	err = hw->mac.ops.set_vfta(hw, vid, 0, true);  	spin_unlock(&adapter->mbx_lock); +	/* translate error return types so error makes sense */ +	if (err == IXGBE_ERR_MBX) +		return -EIO; + +	if (err == IXGBE_ERR_INVALID_ARGUMENT) +		return -EACCES; +  	set_bit(vid, adapter->active_vlans); -	return 0; +	return err;  }  static int ixgbevf_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)  {  	struct ixgbevf_adapter *adapter = netdev_priv(netdev);  	struct ixgbe_hw *hw = &adapter->hw; +	int err = -EOPNOTSUPP;  	spin_lock(&adapter->mbx_lock);  	/* remove VID from filter table */  	if (hw->mac.ops.set_vfta) -		hw->mac.ops.set_vfta(hw, vid, 0, false); +		err = hw->mac.ops.set_vfta(hw, vid, 0, false);  	spin_unlock(&adapter->mbx_lock);  	clear_bit(vid, adapter->active_vlans); -	return 0; +	return err;  }  static void ixgbevf_restore_vlan(struct ixgbevf_adapter *adapter) @@ -1308,6 +1332,25 @@ static void ixgbevf_init_last_counter_stats(struct ixgbevf_adapter *adapter)  	adapter->stats.base_vfmprc = adapter->stats.last_vfmprc;  } +static void ixgbevf_negotiate_api(struct ixgbevf_adapter *adapter) +{ +	struct ixgbe_hw *hw = &adapter->hw; +	int api[] = { ixgbe_mbox_api_10, +		      ixgbe_mbox_api_unknown }; +	int err = 0, idx = 0; + +	spin_lock(&adapter->mbx_lock); + +	while (api[idx] != ixgbe_mbox_api_unknown) { +		err = ixgbevf_negotiate_api_version(hw, api[idx]); +		if (!err) +			break; +		idx++; +	} + +	spin_unlock(&adapter->mbx_lock); +} +  static void ixgbevf_up_complete(struct ixgbevf_adapter *adapter)  {  	struct net_device *netdev = adapter->netdev; @@ -1315,7 +1358,6 @@ static void ixgbevf_up_complete(struct ixgbevf_adapter *adapter)  	int i, j = 0;  	int num_rx_rings = adapter->num_rx_queues;  	u32 txdctl, rxdctl; -	u32 msg[2];  	for (i = 0; i < adapter->num_tx_queues; i++) {  		j = adapter->tx_ring[i].reg_idx; @@ -1356,10 +1398,6 @@ static void ixgbevf_up_complete(struct ixgbevf_adapter *adapter)  			hw->mac.ops.set_rar(hw, 0, hw->mac.perm_addr, 0);  	} -	msg[0] = IXGBE_VF_SET_LPE; -	msg[1] = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; -	hw->mbx.ops.write_posted(hw, msg, 2); -  	spin_unlock(&adapter->mbx_lock);  	clear_bit(__IXGBEVF_DOWN, &adapter->state); @@ -1371,6 +1409,7 @@ static void ixgbevf_up_complete(struct ixgbevf_adapter *adapter)  	ixgbevf_save_reset_stats(adapter);  	ixgbevf_init_last_counter_stats(adapter); +	hw->mac.get_link_status = 1;  	mod_timer(&adapter->watchdog_timer, jiffies);  } @@ -1378,6 +1417,8 @@ void ixgbevf_up(struct ixgbevf_adapter *adapter)  {  	struct ixgbe_hw *hw = &adapter->hw; +	ixgbevf_negotiate_api(adapter); +  	ixgbevf_configure(adapter);  	ixgbevf_up_complete(adapter); @@ -1419,7 +1460,7 @@ static void ixgbevf_clean_rx_ring(struct ixgbevf_adapter *adapter,  			rx_buffer_info->skb = NULL;  			do {  				struct sk_buff *this = skb; -				skb = skb->prev; +				skb = IXGBE_CB(skb)->prev;  				dev_kfree_skb(this);  			} while (skb);  		} @@ -1547,8 +1588,6 @@ void ixgbevf_down(struct ixgbevf_adapter *adapter)  void ixgbevf_reinit_locked(struct ixgbevf_adapter *adapter)  { -	struct ixgbe_hw *hw = &adapter->hw; -  	WARN_ON(in_interrupt());  	while (test_and_set_bit(__IXGBEVF_RESETTING, &adapter->state)) @@ -1561,10 +1600,8 @@ void ixgbevf_reinit_locked(struct ixgbevf_adapter *adapter)  	 * watchdog task will continue to schedule reset tasks until  	 * the PF is up and running.  	 */ -	if (!hw->mac.ops.reset_hw(hw)) { -		ixgbevf_down(adapter); -		ixgbevf_up(adapter); -	} +	ixgbevf_down(adapter); +	ixgbevf_up(adapter);  	clear_bit(__IXGBEVF_RESETTING, &adapter->state);  } @@ -1867,6 +1904,22 @@ err_set_interrupt:  }  /** + * ixgbevf_clear_interrupt_scheme - Clear the current interrupt scheme settings + * @adapter: board private structure to clear interrupt scheme on + * + * We go through and clear interrupt specific resources and reset the structure + * to pre-load conditions + **/ +static void ixgbevf_clear_interrupt_scheme(struct ixgbevf_adapter *adapter) +{ +	adapter->num_tx_queues = 0; +	adapter->num_rx_queues = 0; + +	ixgbevf_free_q_vectors(adapter); +	ixgbevf_reset_interrupt_capability(adapter); +} + +/**   * ixgbevf_sw_init - Initialize general software structures   * (struct ixgbevf_adapter)   * @adapter: board private structure to initialize @@ -2351,6 +2404,8 @@ static int ixgbevf_open(struct net_device *netdev)  		}  	} +	ixgbevf_negotiate_api(adapter); +  	/* allocate transmit descriptors */  	err = ixgbevf_setup_all_tx_resources(adapter);  	if (err) @@ -2860,10 +2915,8 @@ static int ixgbevf_set_mac(struct net_device *netdev, void *p)  static int ixgbevf_change_mtu(struct net_device *netdev, int new_mtu)  {  	struct ixgbevf_adapter *adapter = netdev_priv(netdev); -	struct ixgbe_hw *hw = &adapter->hw;  	int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;  	int max_possible_frame = MAXIMUM_ETHERNET_VLAN_SIZE; -	u32 msg[2];  	if (adapter->hw.mac.type == ixgbe_mac_X540_vf)  		max_possible_frame = IXGBE_MAX_JUMBO_FRAME_SIZE; @@ -2877,35 +2930,91 @@ static int ixgbevf_change_mtu(struct net_device *netdev, int new_mtu)  	/* must set new MTU before calling down or up */  	netdev->mtu = new_mtu; -	if (!netif_running(netdev)) { -		msg[0] = IXGBE_VF_SET_LPE; -		msg[1] = max_frame; -		hw->mbx.ops.write_posted(hw, msg, 2); -	} -  	if (netif_running(netdev))  		ixgbevf_reinit_locked(adapter);  	return 0;  } -static void ixgbevf_shutdown(struct pci_dev *pdev) +static int ixgbevf_suspend(struct pci_dev *pdev, pm_message_t state)  {  	struct net_device *netdev = pci_get_drvdata(pdev);  	struct ixgbevf_adapter *adapter = netdev_priv(netdev); +#ifdef CONFIG_PM +	int retval = 0; +#endif  	netif_device_detach(netdev);  	if (netif_running(netdev)) { +		rtnl_lock();  		ixgbevf_down(adapter);  		ixgbevf_free_irq(adapter);  		ixgbevf_free_all_tx_resources(adapter);  		ixgbevf_free_all_rx_resources(adapter); +		rtnl_unlock();  	} -	pci_save_state(pdev); +	ixgbevf_clear_interrupt_scheme(adapter); +#ifdef CONFIG_PM +	retval = pci_save_state(pdev); +	if (retval) +		return retval; + +#endif  	pci_disable_device(pdev); + +	return 0; +} + +#ifdef CONFIG_PM +static int ixgbevf_resume(struct pci_dev *pdev) +{ +	struct ixgbevf_adapter *adapter = pci_get_drvdata(pdev); +	struct net_device *netdev = adapter->netdev; +	u32 err; + +	pci_set_power_state(pdev, PCI_D0); +	pci_restore_state(pdev); +	/* +	 * pci_restore_state clears dev->state_saved so call +	 * pci_save_state to restore it. +	 */ +	pci_save_state(pdev); + +	err = pci_enable_device_mem(pdev); +	if (err) { +		dev_err(&pdev->dev, "Cannot enable PCI device from suspend\n"); +		return err; +	} +	pci_set_master(pdev); + +	rtnl_lock(); +	err = ixgbevf_init_interrupt_scheme(adapter); +	rtnl_unlock(); +	if (err) { +		dev_err(&pdev->dev, "Cannot initialize interrupts\n"); +		return err; +	} + +	ixgbevf_reset(adapter); + +	if (netif_running(netdev)) { +		err = ixgbevf_open(netdev); +		if (err) +			return err; +	} + +	netif_device_attach(netdev); + +	return err; +} + +#endif /* CONFIG_PM */ +static void ixgbevf_shutdown(struct pci_dev *pdev) +{ +	ixgbevf_suspend(pdev, PMSG_SUSPEND);  }  static struct rtnl_link_stats64 *ixgbevf_get_stats(struct net_device *netdev, @@ -2946,7 +3055,7 @@ static struct rtnl_link_stats64 *ixgbevf_get_stats(struct net_device *netdev,  	return stats;  } -static const struct net_device_ops ixgbe_netdev_ops = { +static const struct net_device_ops ixgbevf_netdev_ops = {  	.ndo_open		= ixgbevf_open,  	.ndo_stop		= ixgbevf_close,  	.ndo_start_xmit		= ixgbevf_xmit_frame, @@ -2962,7 +3071,7 @@ static const struct net_device_ops ixgbe_netdev_ops = {  static void ixgbevf_assign_netdev_ops(struct net_device *dev)  { -	dev->netdev_ops = &ixgbe_netdev_ops; +	dev->netdev_ops = &ixgbevf_netdev_ops;  	ixgbevf_set_ethtool_ops(dev);  	dev->watchdog_timeo = 5 * HZ;  } @@ -3131,6 +3240,7 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,  	return 0;  err_register: +	ixgbevf_clear_interrupt_scheme(adapter);  err_sw_init:  	ixgbevf_reset_interrupt_capability(adapter);  	iounmap(hw->hw_addr); @@ -3168,6 +3278,7 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)  	if (netdev->reg_state == NETREG_REGISTERED)  		unregister_netdev(netdev); +	ixgbevf_clear_interrupt_scheme(adapter);  	ixgbevf_reset_interrupt_capability(adapter);  	iounmap(adapter->hw.hw_addr); @@ -3256,7 +3367,7 @@ static void ixgbevf_io_resume(struct pci_dev *pdev)  }  /* PCI Error Recovery (ERS) */ -static struct pci_error_handlers ixgbevf_err_handler = { +static const struct pci_error_handlers ixgbevf_err_handler = {  	.error_detected = ixgbevf_io_error_detected,  	.slot_reset = ixgbevf_io_slot_reset,  	.resume = ixgbevf_io_resume, @@ -3267,6 +3378,11 @@ static struct pci_driver ixgbevf_driver = {  	.id_table = ixgbevf_pci_tbl,  	.probe    = ixgbevf_probe,  	.remove   = __devexit_p(ixgbevf_remove), +#ifdef CONFIG_PM +	/* Power Management Hooks */ +	.suspend  = ixgbevf_suspend, +	.resume   = ixgbevf_resume, +#endif  	.shutdown = ixgbevf_shutdown,  	.err_handler = &ixgbevf_err_handler  };  |