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


Tony Nguyen says:

====================
40GbE Intel Wired LAN Driver Updates 2021-07-19

This series contains updates to iavf and i40e drivers.

Stefan Assmann adds locking to a path that does not acquire a spinlock
where needed for i40e. He also adjusts locking of critical sections to
help avoid races and removes overriding of the adapter state during
pending reset for iavf driver.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e4b1dc43 226d5285
Loading
Loading
Loading
Loading
+20 −3
Original line number Diff line number Diff line
@@ -1160,12 +1160,12 @@ static int i40e_quiesce_vf_pci(struct i40e_vf *vf)
}

/**
 * i40e_getnum_vf_vsi_vlan_filters
 * __i40e_getnum_vf_vsi_vlan_filters
 * @vsi: pointer to the vsi
 *
 * called to get the number of VLANs offloaded on this VF
 **/
static int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi)
static int __i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi)
{
	struct i40e_mac_filter *f;
	u16 num_vlans = 0, bkt;
@@ -1178,6 +1178,23 @@ static int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi)
	return num_vlans;
}

/**
 * i40e_getnum_vf_vsi_vlan_filters
 * @vsi: pointer to the vsi
 *
 * wrapper for __i40e_getnum_vf_vsi_vlan_filters() with spinlock held
 **/
static int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi)
{
	int num_vlans;

	spin_lock_bh(&vsi->mac_filter_hash_lock);
	num_vlans = __i40e_getnum_vf_vsi_vlan_filters(vsi);
	spin_unlock_bh(&vsi->mac_filter_hash_lock);

	return num_vlans;
}

/**
 * i40e_get_vlan_list_sync
 * @vsi: pointer to the VSI
@@ -1195,7 +1212,7 @@ static void i40e_get_vlan_list_sync(struct i40e_vsi *vsi, u16 *num_vlans,
	int bkt;

	spin_lock_bh(&vsi->mac_filter_hash_lock);
	*num_vlans = i40e_getnum_vf_vsi_vlan_filters(vsi);
	*num_vlans = __i40e_getnum_vf_vsi_vlan_filters(vsi);
	*vlan_list = kcalloc(*num_vlans, sizeof(**vlan_list), GFP_ATOMIC);
	if (!(*vlan_list))
		goto err;
+50 −8
Original line number Diff line number Diff line
@@ -131,6 +131,30 @@ enum iavf_status iavf_free_virt_mem_d(struct iavf_hw *hw,
	return 0;
}

/**
 * iavf_lock_timeout - try to set bit but give up after timeout
 * @adapter: board private structure
 * @bit: bit to set
 * @msecs: timeout in msecs
 *
 * Returns 0 on success, negative on failure
 **/
static int iavf_lock_timeout(struct iavf_adapter *adapter,
			     enum iavf_critical_section_t bit,
			     unsigned int msecs)
{
	unsigned int wait, delay = 10;

	for (wait = 0; wait < msecs; wait += delay) {
		if (!test_and_set_bit(bit, &adapter->crit_section))
			return 0;

		msleep(delay);
	}

	return -1;
}

/**
 * iavf_schedule_reset - Set the flags and schedule a reset event
 * @adapter: board private structure
@@ -1988,7 +2012,6 @@ static void iavf_watchdog_task(struct work_struct *work)
		/* check for hw reset */
	reg_val = rd32(hw, IAVF_VF_ARQLEN1) & IAVF_VF_ARQLEN1_ARQENABLE_MASK;
	if (!reg_val) {
		adapter->state = __IAVF_RESETTING;
		adapter->flags |= IAVF_FLAG_RESET_PENDING;
		adapter->aq_required = 0;
		adapter->current_op = VIRTCHNL_OP_UNKNOWN;
@@ -2102,6 +2125,10 @@ static void iavf_reset_task(struct work_struct *work)
	if (test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section))
		return;

	if (iavf_lock_timeout(adapter, __IAVF_IN_CRITICAL_TASK, 200)) {
		schedule_work(&adapter->reset_task);
		return;
	}
	while (test_and_set_bit(__IAVF_IN_CLIENT_TASK,
				&adapter->crit_section))
		usleep_range(500, 1000);
@@ -2308,6 +2335,8 @@ static void iavf_adminq_task(struct work_struct *work)
	if (!event.msg_buf)
		goto out;

	if (iavf_lock_timeout(adapter, __IAVF_IN_CRITICAL_TASK, 200))
		goto freedom;
	do {
		ret = iavf_clean_arq_element(hw, &event, &pending);
		v_op = (enum virtchnl_ops)le32_to_cpu(event.desc.cookie_high);
@@ -2321,6 +2350,7 @@ static void iavf_adminq_task(struct work_struct *work)
		if (pending != 0)
			memset(event.msg_buf, 0, IAVF_MAX_AQ_BUF_SIZE);
	} while (pending);
	clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);

	if ((adapter->flags &
	     (IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED)) ||
@@ -3625,6 +3655,10 @@ static void iavf_init_task(struct work_struct *work)
						    init_task.work);
	struct iavf_hw *hw = &adapter->hw;

	if (iavf_lock_timeout(adapter, __IAVF_IN_CRITICAL_TASK, 5000)) {
		dev_warn(&adapter->pdev->dev, "failed to set __IAVF_IN_CRITICAL_TASK in %s\n", __FUNCTION__);
		return;
	}
	switch (adapter->state) {
	case __IAVF_STARTUP:
		if (iavf_startup(adapter) < 0)
@@ -3637,14 +3671,14 @@ static void iavf_init_task(struct work_struct *work)
	case __IAVF_INIT_GET_RESOURCES:
		if (iavf_init_get_resources(adapter) < 0)
			goto init_failed;
		return;
		goto out;
	default:
		goto init_failed;
	}

	queue_delayed_work(iavf_wq, &adapter->init_task,
			   msecs_to_jiffies(30));
	return;
	goto out;
init_failed:
	if (++adapter->aq_wait_count > IAVF_AQ_MAX_ERR) {
		dev_err(&adapter->pdev->dev,
@@ -3653,9 +3687,11 @@ static void iavf_init_task(struct work_struct *work)
		iavf_shutdown_adminq(hw);
		adapter->state = __IAVF_STARTUP;
		queue_delayed_work(iavf_wq, &adapter->init_task, HZ * 5);
		return;
		goto out;
	}
	queue_delayed_work(iavf_wq, &adapter->init_task, HZ);
out:
	clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
}

/**
@@ -3672,9 +3708,12 @@ static void iavf_shutdown(struct pci_dev *pdev)
	if (netif_running(netdev))
		iavf_close(netdev);

	if (iavf_lock_timeout(adapter, __IAVF_IN_CRITICAL_TASK, 5000))
		dev_warn(&adapter->pdev->dev, "failed to set __IAVF_IN_CRITICAL_TASK in %s\n", __FUNCTION__);
	/* Prevent the watchdog from running. */
	adapter->state = __IAVF_REMOVE;
	adapter->aq_required = 0;
	clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);

#ifdef CONFIG_PM
	pci_save_state(pdev);
@@ -3908,10 +3947,6 @@ static void iavf_remove(struct pci_dev *pdev)
				 err);
	}

	/* Shut down all the garbage mashers on the detention level */
	adapter->state = __IAVF_REMOVE;
	adapter->aq_required = 0;
	adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
	iavf_request_reset(adapter);
	msleep(50);
	/* If the FW isn't responding, kick it once, but only once. */
@@ -3919,6 +3954,13 @@ static void iavf_remove(struct pci_dev *pdev)
		iavf_request_reset(adapter);
		msleep(50);
	}
	if (iavf_lock_timeout(adapter, __IAVF_IN_CRITICAL_TASK, 5000))
		dev_warn(&adapter->pdev->dev, "failed to set __IAVF_IN_CRITICAL_TASK in %s\n", __FUNCTION__);

	/* Shut down all the garbage mashers on the detention level */
	adapter->state = __IAVF_REMOVE;
	adapter->aq_required = 0;
	adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
	iavf_free_all_tx_resources(adapter);
	iavf_free_all_rx_resources(adapter);
	iavf_misc_irq_disable(adapter);
+3 −5
Original line number Diff line number Diff line
@@ -326,11 +326,9 @@ static irqreturn_t dp83822_handle_interrupt(struct phy_device *phydev)

static int dp8382x_disable_wol(struct phy_device *phydev)
{
	int value = DP83822_WOL_EN | DP83822_WOL_MAGIC_EN |
		    DP83822_WOL_SECURE_ON;

	return phy_clear_bits_mmd(phydev, DP83822_DEVADDR,
				  MII_DP83822_WOL_CFG, value);
	return phy_clear_bits_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG,
				  DP83822_WOL_EN | DP83822_WOL_MAGIC_EN |
				  DP83822_WOL_SECURE_ON);
}

static int dp83822_read_status(struct phy_device *phydev)