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

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


Jeff Kirsher says:

====================
40GbE Intel Wired LAN Driver Updates 2017-09-29

This series contains updates to i40e and i40evf only.

Jake provides several of the changes starting with the renaming of a
variable to clarify what the value is actually calculating. Found we
were misusing the __I40E_RECOVERY_PENDING bit to determine when we
should actually request a new IRQ in i40e_setup_misc_vector(), which
lead to a design mistake, so to resolve the issue, use a separate
state bit for miscellaneous IRQ setup and fix up the design while we
are at it.  Cleaned up the old legacy PM support in the driver since
we support the newer generic PM callbacks.  Fixed a failure to
hibernate issue, where on some platforms with a large number of CPUs,
we would allocate many IRQ vectors which we would try to migrate to
CPU0 when hibernating.

Sudheer cleans up a check for unqualified module inside i40e_up_complete()
because the link state information is in flux at time, so log messages
are getting logged with incorrect link state information.  Also provided
additional log message cleanups and simplify member variable access in
the printing of the link messages.

Mariusz relaxes the firmware check since Fortville and Fort Park NICs
can and do have different firmware versions, so only warn for older
Fortville firmware.  Fixed an errata with a flow director statistic that
was not wrapping as expected, simply reset after reading.

Mitch prevents consternation by lowering the log level to debug on a
message seen regularly on VF reset or unload, which is meaningless under
normal circumstances.  Refactor the firmware version checking since
Fortville and Fort Park devices can have different firmware versions.

Alan fixes a ring to vector mapping, where the past implementation
attempted to map each Tx and Rx ring to its own vector, however we use
combined queues so we should be mapping the Tx/Rx rings together on one
vector.  Adds the ability for the VF to request a different number of
queues allocated to it.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 45c1fd61 22b96551
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@
#define i40e_default_queues_per_vmdq(pf) \
		(((pf)->hw_features & I40E_HW_RSS_AQ_CAPABLE) ? 4 : 1)
#define I40E_DEFAULT_QUEUES_PER_VF	4
#define I40E_MAX_VF_QUEUES		16
#define I40E_DEFAULT_QUEUES_PER_TC	1 /* should be a power of 2 */
#define i40e_pf_get_max_q_per_tc(pf) \
		(((pf)->hw_features & I40E_HW_128_QP_RSS_CAPABLE) ? 128 : 64)
@@ -136,6 +137,7 @@ enum i40e_state_t {
	__I40E_MDD_EVENT_PENDING,
	__I40E_VFLR_EVENT_PENDING,
	__I40E_RESET_RECOVERY_PENDING,
	__I40E_MISC_IRQ_REQUESTED,
	__I40E_RESET_INTR_RECEIVED,
	__I40E_REINIT_REQUESTED,
	__I40E_PF_RESET_REQUESTED,
+9 −1
Original line number Diff line number Diff line
@@ -34,7 +34,15 @@
 */

#define I40E_FW_API_VERSION_MAJOR	0x0001
#define I40E_FW_API_VERSION_MINOR	0x0005
#define I40E_FW_API_VERSION_MINOR_X722	0x0005
#define I40E_FW_API_VERSION_MINOR_X710	0x0007

#define I40E_FW_MINOR_VERSION(_h) ((_h)->mac.type == I40E_MAC_XL710 ? \
					I40E_FW_API_VERSION_MINOR_X710 : \
					I40E_FW_API_VERSION_MINOR_X722)

/* API version 1.7 implements additional link and PHY-specific APIs  */
#define I40E_MINOR_VER_GET_LINK_INFO_XL710 0x0007

struct i40e_aq_desc {
	__le16 flags;
+4 −2
Original line number Diff line number Diff line
@@ -1593,8 +1593,10 @@ i40e_status i40e_aq_get_phy_capabilities(struct i40e_hw *hw,
		status = I40E_ERR_UNKNOWN_PHY;

	if (report_init) {
		hw->phy.phy_types = le32_to_cpu(abilities->phy_type);
		hw->phy.phy_types |= ((u64)abilities->phy_type_ext << 32);
		if (hw->mac.type ==  I40E_MAC_XL710 &&
		    hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
		    hw->aq.api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_XL710)
			status = i40e_aq_get_link_info(hw, true, NULL, NULL);
	}

	return status;
+150 −99
Original line number Diff line number Diff line
@@ -599,6 +599,20 @@ static void i40e_stat_update32(struct i40e_hw *hw, u32 reg,
		*stat = (u32)((new_data + BIT_ULL(32)) - *offset);
}

/**
 * i40e_stat_update_and_clear32 - read and clear hw reg, update a 32 bit stat
 * @hw: ptr to the hardware info
 * @reg: the hw reg to read and clear
 * @stat: ptr to the stat
 **/
static void i40e_stat_update_and_clear32(struct i40e_hw *hw, u32 reg, u64 *stat)
{
	u32 new_data = rd32(hw, reg);

	wr32(hw, reg, 1); /* must write a nonzero value to clear register */
	*stat += new_data;
}

/**
 * i40e_update_eth_stats - Update VSI-specific ethernet statistics counters.
 * @vsi: the VSI to be updated
@@ -1040,18 +1054,15 @@ static void i40e_update_pf_stats(struct i40e_pf *pf)
			   &osd->rx_jabber, &nsd->rx_jabber);

	/* FDIR stats */
	i40e_stat_update32(hw,
			   I40E_GLQF_PCNT(I40E_FD_ATR_STAT_IDX(pf->hw.pf_id)),
			   pf->stat_offsets_loaded,
			   &osd->fd_atr_match, &nsd->fd_atr_match);
	i40e_stat_update32(hw,
			   I40E_GLQF_PCNT(I40E_FD_SB_STAT_IDX(pf->hw.pf_id)),
			   pf->stat_offsets_loaded,
			   &osd->fd_sb_match, &nsd->fd_sb_match);
	i40e_stat_update32(hw,
		      I40E_GLQF_PCNT(I40E_FD_ATR_TUNNEL_STAT_IDX(pf->hw.pf_id)),
		      pf->stat_offsets_loaded,
		      &osd->fd_atr_tunnel_match, &nsd->fd_atr_tunnel_match);
	i40e_stat_update_and_clear32(hw,
			I40E_GLQF_PCNT(I40E_FD_ATR_STAT_IDX(hw->pf_id)),
			&nsd->fd_atr_match);
	i40e_stat_update_and_clear32(hw,
			I40E_GLQF_PCNT(I40E_FD_SB_STAT_IDX(hw->pf_id)),
			&nsd->fd_sb_match);
	i40e_stat_update_and_clear32(hw,
			I40E_GLQF_PCNT(I40E_FD_ATR_TUNNEL_STAT_IDX(hw->pf_id)),
			&nsd->fd_atr_tunnel_match);

	val = rd32(hw, I40E_PRTPM_EEE_STAT);
	nsd->tx_lpi_status =
@@ -3593,14 +3604,20 @@ static int i40e_vsi_enable_irq(struct i40e_vsi *vsi)
}

/**
 * i40e_stop_misc_vector - Stop the vector that handles non-queue events
 * i40e_free_misc_vector - Free the vector that handles non-queue events
 * @pf: board private structure
 **/
static void i40e_stop_misc_vector(struct i40e_pf *pf)
static void i40e_free_misc_vector(struct i40e_pf *pf)
{
	/* Disable ICR 0 */
	wr32(&pf->hw, I40E_PFINT_ICR0_ENA, 0);
	i40e_flush(&pf->hw);

	if (pf->flags & I40E_FLAG_MSIX_ENABLED && pf->msix_entries) {
		synchronize_irq(pf->msix_entries[0].vector);
		free_irq(pf->msix_entries[0].vector, pf);
		clear_bit(__I40E_MISC_IRQ_REQUESTED, pf->state);
	}
}

/**
@@ -4455,11 +4472,7 @@ static void i40e_clear_interrupt_scheme(struct i40e_pf *pf)
{
	int i;

	i40e_stop_misc_vector(pf);
	if (pf->flags & I40E_FLAG_MSIX_ENABLED && pf->msix_entries) {
		synchronize_irq(pf->msix_entries[0].vector);
		free_irq(pf->msix_entries[0].vector, pf);
	}
	i40e_free_misc_vector(pf);

	i40e_put_lump(pf->irq_pile, pf->iwarp_base_vector,
		      I40E_IWARP_IRQ_PILE_ID);
@@ -5346,13 +5359,14 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf)
void i40e_print_link_message(struct i40e_vsi *vsi, bool isup)
{
	enum i40e_aq_link_speed new_speed;
	struct i40e_pf *pf = vsi->back;
	char *speed = "Unknown";
	char *fc = "Unknown";
	char *fec = "";
	char *req_fec = "";
	char *an = "";

	new_speed = vsi->back->hw.phy.link_info.link_speed;
	new_speed = pf->hw.phy.link_info.link_speed;

	if ((vsi->current_isup == isup) && (vsi->current_speed == new_speed))
		return;
@@ -5366,13 +5380,13 @@ void i40e_print_link_message(struct i40e_vsi *vsi, bool isup)
	/* Warn user if link speed on NPAR enabled partition is not at
	 * least 10GB
	 */
	if (vsi->back->hw.func_caps.npar_enable &&
	    (vsi->back->hw.phy.link_info.link_speed == I40E_LINK_SPEED_1GB ||
	     vsi->back->hw.phy.link_info.link_speed == I40E_LINK_SPEED_100MB))
	if (pf->hw.func_caps.npar_enable &&
	    (pf->hw.phy.link_info.link_speed == I40E_LINK_SPEED_1GB ||
	     pf->hw.phy.link_info.link_speed == I40E_LINK_SPEED_100MB))
		netdev_warn(vsi->netdev,
			    "The partition detected link speed that is less than 10Gbps\n");

	switch (vsi->back->hw.phy.link_info.link_speed) {
	switch (pf->hw.phy.link_info.link_speed) {
	case I40E_LINK_SPEED_40GB:
		speed = "40 G";
		break;
@@ -5395,7 +5409,7 @@ void i40e_print_link_message(struct i40e_vsi *vsi, bool isup)
		break;
	}

	switch (vsi->back->hw.fc.current_mode) {
	switch (pf->hw.fc.current_mode) {
	case I40E_FC_FULL:
		fc = "RX/TX";
		break;
@@ -5410,18 +5424,18 @@ void i40e_print_link_message(struct i40e_vsi *vsi, bool isup)
		break;
	}

	if (vsi->back->hw.phy.link_info.link_speed == I40E_LINK_SPEED_25GB) {
	if (pf->hw.phy.link_info.link_speed == I40E_LINK_SPEED_25GB) {
		req_fec = ", Requested FEC: None";
		fec = ", FEC: None";
		an = ", Autoneg: False";

		if (vsi->back->hw.phy.link_info.an_info & I40E_AQ_AN_COMPLETED)
		if (pf->hw.phy.link_info.an_info & I40E_AQ_AN_COMPLETED)
			an = ", Autoneg: True";

		if (vsi->back->hw.phy.link_info.fec_info &
		if (pf->hw.phy.link_info.fec_info &
		    I40E_AQ_CONFIG_FEC_KR_ENA)
			fec = ", FEC: CL74 FC-FEC/BASE-R";
		else if (vsi->back->hw.phy.link_info.fec_info &
		else if (pf->hw.phy.link_info.fec_info &
			 I40E_AQ_CONFIG_FEC_RS_ENA)
			fec = ", FEC: CL108 RS-FEC";

@@ -5470,15 +5484,6 @@ static int i40e_up_complete(struct i40e_vsi *vsi)
		i40e_print_link_message(vsi, true);
		netif_tx_start_all_queues(vsi->netdev);
		netif_carrier_on(vsi->netdev);
	} else if (vsi->netdev) {
		i40e_print_link_message(vsi, false);
		/* need to check for qualified module here*/
		if ((pf->hw.phy.link_info.link_info &
			I40E_AQ_MEDIA_AVAILABLE) &&
		    (!(pf->hw.phy.link_info.an_info &
			I40E_AQ_QUALIFIED_MODULE)))
			netdev_err(vsi->netdev,
				   "the driver failed to link because an unqualified module was detected.");
	}

	/* replay FDIR SB filters */
@@ -6429,7 +6434,6 @@ static void i40e_link_event(struct i40e_pf *pf)
	     new_link == netif_carrier_ok(vsi->netdev)))
		return;

	if (!test_bit(__I40E_VSI_DOWN, vsi->state))
	i40e_print_link_message(vsi, new_link);

	/* Notify the base of the switch tree connected to
@@ -8350,6 +8354,57 @@ static int i40e_init_interrupt_scheme(struct i40e_pf *pf)
	return 0;
}

#ifdef CONFIG_PM
/**
 * i40e_restore_interrupt_scheme - Restore the interrupt scheme
 * @pf: private board data structure
 *
 * Restore the interrupt scheme that was cleared when we suspended the
 * device. This should be called during resume to re-allocate the q_vectors
 * and reacquire IRQs.
 */
static int i40e_restore_interrupt_scheme(struct i40e_pf *pf)
{
	int err, i;

	/* We cleared the MSI and MSI-X flags when disabling the old interrupt
	 * scheme. We need to re-enabled them here in order to attempt to
	 * re-acquire the MSI or MSI-X vectors
	 */
	pf->flags |= (I40E_FLAG_MSIX_ENABLED | I40E_FLAG_MSI_ENABLED);

	err = i40e_init_interrupt_scheme(pf);
	if (err)
		return err;

	/* Now that we've re-acquired IRQs, we need to remap the vectors and
	 * rings together again.
	 */
	for (i = 0; i < pf->num_alloc_vsi; i++) {
		if (pf->vsi[i]) {
			err = i40e_vsi_alloc_q_vectors(pf->vsi[i]);
			if (err)
				goto err_unwind;
			i40e_vsi_map_rings_to_vectors(pf->vsi[i]);
		}
	}

	err = i40e_setup_misc_vector(pf);
	if (err)
		goto err_unwind;

	return 0;

err_unwind:
	while (i--) {
		if (pf->vsi[i])
			i40e_vsi_free_q_vectors(pf->vsi[i]);
	}

	return err;
}
#endif /* CONFIG_PM */

/**
 * i40e_setup_misc_vector - Setup the misc vector to handle non queue events
 * @pf: board private structure
@@ -8363,13 +8418,12 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf)
	struct i40e_hw *hw = &pf->hw;
	int err = 0;

	/* Only request the irq if this is the first time through, and
	 * not when we're rebuilding after a Reset
	 */
	if (!test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state)) {
	/* Only request the IRQ once, the first time through. */
	if (!test_and_set_bit(__I40E_MISC_IRQ_REQUESTED, pf->state)) {
		err = request_irq(pf->msix_entries[0].vector,
				  i40e_intr, 0, pf->int_name, pf);
		if (err) {
			clear_bit(__I40E_MISC_IRQ_REQUESTED, pf->state);
			dev_info(&pf->pdev->dev,
				 "request_irq for %s failed: %d\n",
				 pf->int_name, err);
@@ -11380,11 +11434,10 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
		 i40e_nvm_version_str(hw));

	if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
	    hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR)
	    hw->aq.api_min_ver > I40E_FW_MINOR_VERSION(hw))
		dev_info(&pdev->dev,
			 "The driver for the device detected a newer version of the NVM image than expected. Please install the most recent version of the network driver.\n");
	else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR ||
		 hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1))
	else if (hw->aq.api_maj_ver == 1 && hw->aq.api_min_ver < 4)
		dev_info(&pdev->dev,
			 "The driver for the device detected an older version of the NVM image than expected. Please update the NVM image.\n");

@@ -12048,18 +12101,25 @@ static void i40e_shutdown(struct pci_dev *pdev)

#ifdef CONFIG_PM
/**
 * i40e_suspend - PCI callback for moving to D3
 * @pdev: PCI device information struct
 * i40e_suspend - PM callback for moving to D3
 * @dev: generic device information structure
 **/
static int i40e_suspend(struct pci_dev *pdev, pm_message_t state)
static int i40e_suspend(struct device *dev)
{
	struct pci_dev *pdev = to_pci_dev(dev);
	struct i40e_pf *pf = pci_get_drvdata(pdev);
	struct i40e_hw *hw = &pf->hw;
	int retval = 0;

	set_bit(__I40E_SUSPENDED, pf->state);
	/* If we're already suspended, then there is nothing to do */
	if (test_and_set_bit(__I40E_SUSPENDED, pf->state))
		return 0;

	set_bit(__I40E_DOWN, pf->state);

	/* Ensure service task will not be running */
	del_timer_sync(&pf->service_timer);
	cancel_work_sync(&pf->service_task);

	if (pf->wol_en && (pf->hw_features & I40E_HW_WOL_MC_MAGIC_PKT_WAKE))
		i40e_enable_mc_magic_wake(pf);

@@ -12068,81 +12128,72 @@ static int i40e_suspend(struct pci_dev *pdev, pm_message_t state)
	wr32(hw, I40E_PFPM_APM, (pf->wol_en ? I40E_PFPM_APM_APME_MASK : 0));
	wr32(hw, I40E_PFPM_WUFC, (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0));

	i40e_stop_misc_vector(pf);
	if (pf->msix_entries) {
		synchronize_irq(pf->msix_entries[0].vector);
		free_irq(pf->msix_entries[0].vector, pf);
	}
	retval = pci_save_state(pdev);
	if (retval)
		return retval;

	pci_wake_from_d3(pdev, pf->wol_en);
	pci_set_power_state(pdev, PCI_D3hot);
	/* Clear the interrupt scheme and release our IRQs so that the system
	 * can safely hibernate even when there are a large number of CPUs.
	 * Otherwise hibernation might fail when mapping all the vectors back
	 * to CPU0.
	 */
	i40e_clear_interrupt_scheme(pf);

	return retval;
	return 0;
}

/**
 * i40e_resume - PCI callback for waking up from D3
 * @pdev: PCI device information struct
 * i40e_resume - PM callback for waking up from D3
 * @dev: generic device information structure
 **/
static int i40e_resume(struct pci_dev *pdev)
static int i40e_resume(struct device *dev)
{
	struct pci_dev *pdev = to_pci_dev(dev);
	struct i40e_pf *pf = pci_get_drvdata(pdev);
	u32 err;
	int err;

	pci_set_power_state(pdev, PCI_D0);
	pci_restore_state(pdev);
	/* pci_restore_state() clears dev->state_saves, so
	 * call pci_save_state() again to restore it.
	 */
	pci_save_state(pdev);
	/* If we're not suspended, then there is nothing to do */
	if (!test_bit(__I40E_SUSPENDED, pf->state))
		return 0;

	err = pci_enable_device_mem(pdev);
	/* We cleared the interrupt scheme when we suspended, so we need to
	 * restore it now to resume device functionality.
	 */
	err = i40e_restore_interrupt_scheme(pf);
	if (err) {
		dev_err(&pdev->dev, "Cannot enable PCI device from suspend\n");
		return err;
		dev_err(&pdev->dev, "Cannot restore interrupt scheme: %d\n",
			err);
	}
	pci_set_master(pdev);

	/* no wakeup events while running */
	pci_wake_from_d3(pdev, false);

	/* handling the reset will rebuild the device state */
	if (test_and_clear_bit(__I40E_SUSPENDED, pf->state)) {
	clear_bit(__I40E_DOWN, pf->state);
		if (pf->msix_entries) {
			err = request_irq(pf->msix_entries[0].vector,
					  i40e_intr, 0, pf->int_name, pf);
			if (err) {
				dev_err(&pf->pdev->dev,
					"request_irq for %s failed: %d\n",
					pf->int_name, err);
			}
		}
	i40e_reset_and_rebuild(pf, false, false);
	}

	/* Clear suspended state last after everything is recovered */
	clear_bit(__I40E_SUSPENDED, pf->state);

	/* Restart the service task */
	mod_timer(&pf->service_timer,
		  round_jiffies(jiffies + pf->service_timer_period));

	return 0;
}

#endif
#endif /* CONFIG_PM */

static const struct pci_error_handlers i40e_err_handler = {
	.error_detected = i40e_pci_error_detected,
	.slot_reset = i40e_pci_error_slot_reset,
	.resume = i40e_pci_error_resume,
};

static SIMPLE_DEV_PM_OPS(i40e_pm_ops, i40e_suspend, i40e_resume);

static struct pci_driver i40e_driver = {
	.name     = i40e_driver_name,
	.id_table = i40e_pci_tbl,
	.probe    = i40e_probe,
	.remove   = i40e_remove,
#ifdef CONFIG_PM
	.suspend  = i40e_suspend,
	.resume   = i40e_resume,
#endif
	.driver   = {
		.pm = &i40e_pm_ops,
	},
#endif /* CONFIG_PM */
	.shutdown = i40e_shutdown,
	.err_handler = &i40e_err_handler,
	.sriov_configure = i40e_pci_sriov_configure,
+6 −6
Original line number Diff line number Diff line
@@ -960,14 +960,14 @@ static bool i40e_set_new_dynamic_itr(struct i40e_ring_container *rc)
{
	enum i40e_latency_range new_latency_range = rc->latency_range;
	u32 new_itr = rc->itr;
	int bytes_per_int;
	int bytes_per_usec;
	unsigned int usecs, estimated_usecs;

	if (rc->total_packets == 0 || !rc->itr)
		return false;

	usecs = (rc->itr << 1) * ITR_COUNTDOWN_START;
	bytes_per_int = rc->total_bytes / usecs;
	bytes_per_usec = rc->total_bytes / usecs;

	/* The calculations in this algorithm depend on interrupts actually
	 * firing at the ITR rate. This may not happen if the packet rate is
@@ -993,18 +993,18 @@ static bool i40e_set_new_dynamic_itr(struct i40e_ring_container *rc)
	 */
	switch (new_latency_range) {
	case I40E_LOWEST_LATENCY:
		if (bytes_per_int > 10)
		if (bytes_per_usec > 10)
			new_latency_range = I40E_LOW_LATENCY;
		break;
	case I40E_LOW_LATENCY:
		if (bytes_per_int > 20)
		if (bytes_per_usec > 20)
			new_latency_range = I40E_BULK_LATENCY;
		else if (bytes_per_int <= 10)
		else if (bytes_per_usec <= 10)
			new_latency_range = I40E_LOWEST_LATENCY;
		break;
	case I40E_BULK_LATENCY:
	default:
		if (bytes_per_int <= 20)
		if (bytes_per_usec <= 20)
			new_latency_range = I40E_LOW_LATENCY;
		break;
	}
Loading