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


Mateusz Palczewski says:

====================
40GbE Intel Wired LAN Driver Updates 2021-10-18

Use single state machine for driver initialization
and for service initialized driver. The init state
machine implemented in init_task() is merged
into the watchdog_task(). The init_task() function
is removed.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 939a6567 898ef1cb
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -177,6 +177,7 @@ enum iavf_state_t {
	__IAVF_INIT_VERSION_CHECK,	/* aq msg sent, awaiting reply */
	__IAVF_INIT_GET_RESOURCES,	/* aq msg sent, awaiting reply */
	__IAVF_INIT_SW,		/* got resources, setting up structs */
	__IAVF_INIT_FAILED,	/* init failed, restarting procedure */
	__IAVF_RESETTING,		/* in reset */
	__IAVF_COMM_FAILED,		/* communication with PF failed */
	/* Below here, watchdog is running */
@@ -225,7 +226,6 @@ struct iavf_adapter {
	struct work_struct reset_task;
	struct work_struct adminq_task;
	struct delayed_work client_task;
	struct delayed_work init_task;
	wait_queue_head_t down_waitqueue;
	struct iavf_q_vector *q_vectors;
	struct list_head vlan_filter_list;
@@ -312,6 +312,7 @@ struct iavf_adapter {
	struct iavf_hw hw; /* defined in iavf_type.h */

	enum iavf_state_t state;
	enum iavf_state_t last_state;
	unsigned long crit_section;

	struct delayed_work watchdog_task;
@@ -393,6 +394,15 @@ struct iavf_device {
extern char iavf_driver_name[];
extern struct workqueue_struct *iavf_wq;

static inline void iavf_change_state(struct iavf_adapter *adapter,
				     enum iavf_state_t state)
{
	if (adapter->state != state) {
		adapter->last_state = adapter->state;
		adapter->state = state;
	}
}

int iavf_up(struct iavf_adapter *adapter);
void iavf_down(struct iavf_adapter *adapter);
int iavf_process_config(struct iavf_adapter *adapter);
+89 −103
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
static int iavf_setup_all_tx_resources(struct iavf_adapter *adapter);
static int iavf_setup_all_rx_resources(struct iavf_adapter *adapter);
static int iavf_close(struct net_device *netdev);
static int iavf_init_get_resources(struct iavf_adapter *adapter);
static void iavf_init_get_resources(struct iavf_adapter *adapter);
static int iavf_check_reset_complete(struct iavf_hw *hw);

char iavf_driver_name[] = "iavf";
@@ -960,7 +960,7 @@ static void iavf_configure(struct iavf_adapter *adapter)
 **/
static void iavf_up_complete(struct iavf_adapter *adapter)
{
	adapter->state = __IAVF_RUNNING;
	iavf_change_state(adapter, __IAVF_RUNNING);
	clear_bit(__IAVF_VSI_DOWN, adapter->vsi.state);

	iavf_napi_enable_all(adapter);
@@ -1688,9 +1688,9 @@ static int iavf_process_aq_command(struct iavf_adapter *adapter)
 *
 * Function process __IAVF_STARTUP driver state.
 * When success the state is changed to __IAVF_INIT_VERSION_CHECK
 * when fails it returns -EAGAIN
 * when fails the state is changed to __IAVF_INIT_FAILED
 **/
static int iavf_startup(struct iavf_adapter *adapter)
static void iavf_startup(struct iavf_adapter *adapter)
{
	struct pci_dev *pdev = adapter->pdev;
	struct iavf_hw *hw = &adapter->hw;
@@ -1729,9 +1729,10 @@ static int iavf_startup(struct iavf_adapter *adapter)
		iavf_shutdown_adminq(hw);
		goto err;
	}
	adapter->state = __IAVF_INIT_VERSION_CHECK;
	iavf_change_state(adapter, __IAVF_INIT_VERSION_CHECK);
	return;
err:
	return err;
	iavf_change_state(adapter, __IAVF_INIT_FAILED);
}

/**
@@ -1740,9 +1741,9 @@ static int iavf_startup(struct iavf_adapter *adapter)
 *
 * Function process __IAVF_INIT_VERSION_CHECK driver state.
 * When success the state is changed to __IAVF_INIT_GET_RESOURCES
 * when fails it returns -EAGAIN
 * when fails the state is changed to __IAVF_INIT_FAILED
 **/
static int iavf_init_version_check(struct iavf_adapter *adapter)
static void iavf_init_version_check(struct iavf_adapter *adapter)
{
	struct pci_dev *pdev = adapter->pdev;
	struct iavf_hw *hw = &adapter->hw;
@@ -1753,7 +1754,7 @@ static int iavf_init_version_check(struct iavf_adapter *adapter)
	if (!iavf_asq_done(hw)) {
		dev_err(&pdev->dev, "Admin queue command never completed\n");
		iavf_shutdown_adminq(hw);
		adapter->state = __IAVF_STARTUP;
		iavf_change_state(adapter, __IAVF_STARTUP);
		goto err;
	}

@@ -1776,10 +1777,10 @@ static int iavf_init_version_check(struct iavf_adapter *adapter)
			err);
		goto err;
	}
	adapter->state = __IAVF_INIT_GET_RESOURCES;

	iavf_change_state(adapter, __IAVF_INIT_GET_RESOURCES);
	return;
err:
	return err;
	iavf_change_state(adapter, __IAVF_INIT_FAILED);
}

/**
@@ -1789,9 +1790,9 @@ static int iavf_init_version_check(struct iavf_adapter *adapter)
 * Function process __IAVF_INIT_GET_RESOURCES driver state and
 * finishes driver initialization procedure.
 * When success the state is changed to __IAVF_DOWN
 * when fails it returns -EAGAIN
 * when fails the state is changed to __IAVF_INIT_FAILED
 **/
static int iavf_init_get_resources(struct iavf_adapter *adapter)
static void iavf_init_get_resources(struct iavf_adapter *adapter)
{
	struct net_device *netdev = adapter->netdev;
	struct pci_dev *pdev = adapter->pdev;
@@ -1819,7 +1820,7 @@ static int iavf_init_get_resources(struct iavf_adapter *adapter)
		 */
		iavf_shutdown_adminq(hw);
		dev_err(&pdev->dev, "Unable to get VF config due to PF error condition, not retrying\n");
		return 0;
		return;
	}
	if (err) {
		dev_err(&pdev->dev, "Unable to get VF config (%d)\n", err);
@@ -1893,7 +1894,7 @@ static int iavf_init_get_resources(struct iavf_adapter *adapter)
	if (netdev->features & NETIF_F_GRO)
		dev_info(&pdev->dev, "GRO is enabled\n");

	adapter->state = __IAVF_DOWN;
	iavf_change_state(adapter, __IAVF_DOWN);
	set_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
	rtnl_unlock();

@@ -1911,7 +1912,7 @@ static int iavf_init_get_resources(struct iavf_adapter *adapter)
	else
		iavf_init_rss(adapter);

	return err;
	return;
err_mem:
	iavf_free_rss(adapter);
err_register:
@@ -1922,7 +1923,7 @@ static int iavf_init_get_resources(struct iavf_adapter *adapter)
	kfree(adapter->vf_res);
	adapter->vf_res = NULL;
err:
	return err;
	iavf_change_state(adapter, __IAVF_INIT_FAILED);
}

/**
@@ -1941,9 +1942,50 @@ static void iavf_watchdog_task(struct work_struct *work)
		goto restart_watchdog;

	if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED)
		adapter->state = __IAVF_COMM_FAILED;
		iavf_change_state(adapter, __IAVF_COMM_FAILED);

	if (adapter->flags & IAVF_FLAG_RESET_NEEDED &&
	    adapter->state != __IAVF_RESETTING) {
		iavf_change_state(adapter, __IAVF_RESETTING);
		adapter->aq_required = 0;
		adapter->current_op = VIRTCHNL_OP_UNKNOWN;
	}

	switch (adapter->state) {
	case __IAVF_STARTUP:
		iavf_startup(adapter);
		mutex_unlock(&adapter->crit_lock);
		queue_delayed_work(iavf_wq, &adapter->watchdog_task,
				   msecs_to_jiffies(30));
		return;
	case __IAVF_INIT_VERSION_CHECK:
		iavf_init_version_check(adapter);
		mutex_unlock(&adapter->crit_lock);
		queue_delayed_work(iavf_wq, &adapter->watchdog_task,
				   msecs_to_jiffies(30));
		return;
	case __IAVF_INIT_GET_RESOURCES:
		iavf_init_get_resources(adapter);
		mutex_unlock(&adapter->crit_lock);
		queue_delayed_work(iavf_wq, &adapter->watchdog_task,
				   msecs_to_jiffies(1));
		return;
	case __IAVF_INIT_FAILED:
		if (++adapter->aq_wait_count > IAVF_AQ_MAX_ERR) {
			dev_err(&adapter->pdev->dev,
				"Failed to communicate with PF; waiting before retry\n");
			adapter->flags |= IAVF_FLAG_PF_COMMS_FAILED;
			iavf_shutdown_adminq(hw);
			mutex_unlock(&adapter->crit_lock);
			queue_delayed_work(iavf_wq,
					   &adapter->watchdog_task, (5 * HZ));
			return;
		}
		/* Try again from failed step*/
		iavf_change_state(adapter, adapter->last_state);
		mutex_unlock(&adapter->crit_lock);
		queue_delayed_work(iavf_wq, &adapter->watchdog_task, HZ);
		return;
	case __IAVF_COMM_FAILED:
		reg_val = rd32(hw, IAVF_VFGEN_RSTAT) &
			  IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
@@ -1952,23 +1994,19 @@ static void iavf_watchdog_task(struct work_struct *work)
			/* A chance for redemption! */
			dev_err(&adapter->pdev->dev,
				"Hardware came out of reset. Attempting reinit.\n");
			adapter->state = __IAVF_STARTUP;
			adapter->flags &= ~IAVF_FLAG_PF_COMMS_FAILED;
			queue_delayed_work(iavf_wq, &adapter->init_task, 10);
			mutex_unlock(&adapter->crit_lock);
			/* Don't reschedule the watchdog, since we've restarted
			 * the init task. When init_task contacts the PF and
			/* When init task contacts the PF and
			 * gets everything set up again, it'll restart the
			 * watchdog for us. Down, boy. Sit. Stay. Woof.
			 */
			return;
			iavf_change_state(adapter, __IAVF_STARTUP);
			adapter->flags &= ~IAVF_FLAG_PF_COMMS_FAILED;
		}
		adapter->aq_required = 0;
		adapter->current_op = VIRTCHNL_OP_UNKNOWN;
		queue_delayed_work(iavf_wq,
				   &adapter->watchdog_task,
				   msecs_to_jiffies(10));
		goto watchdog_done;
		return;
	case __IAVF_RESETTING:
		mutex_unlock(&adapter->crit_lock);
		queue_delayed_work(iavf_wq, &adapter->watchdog_task, HZ * 2);
@@ -1991,38 +2029,40 @@ static void iavf_watchdog_task(struct work_struct *work)
			    adapter->state == __IAVF_RUNNING)
				iavf_request_stats(adapter);
		}
		if (adapter->state == __IAVF_RUNNING)
			iavf_detect_recover_hung(&adapter->vsi);
		break;
	case __IAVF_REMOVE:
		mutex_unlock(&adapter->crit_lock);
		return;
	default:
		goto restart_watchdog;
		return;
	}

	/* check for hw reset */
	reg_val = rd32(hw, IAVF_VF_ARQLEN1) & IAVF_VF_ARQLEN1_ARQENABLE_MASK;
	if (!reg_val) {
		iavf_change_state(adapter, __IAVF_RESETTING);
		adapter->flags |= IAVF_FLAG_RESET_PENDING;
		adapter->aq_required = 0;
		adapter->current_op = VIRTCHNL_OP_UNKNOWN;
		dev_err(&adapter->pdev->dev, "Hardware reset detected\n");
		queue_work(iavf_wq, &adapter->reset_task);
		goto watchdog_done;
		mutex_unlock(&adapter->crit_lock);
		queue_delayed_work(iavf_wq,
				   &adapter->watchdog_task, HZ * 2);
		return;
	}

	schedule_delayed_work(&adapter->client_task, msecs_to_jiffies(5));
watchdog_done:
	if (adapter->state == __IAVF_RUNNING ||
	    adapter->state == __IAVF_COMM_FAILED)
		iavf_detect_recover_hung(&adapter->vsi);
	mutex_unlock(&adapter->crit_lock);
restart_watchdog:
	queue_work(iavf_wq, &adapter->adminq_task);
	if (adapter->aq_required)
		queue_delayed_work(iavf_wq, &adapter->watchdog_task,
				   msecs_to_jiffies(20));
	else
		queue_delayed_work(iavf_wq, &adapter->watchdog_task, HZ * 2);
	queue_work(iavf_wq, &adapter->adminq_task);
}

static void iavf_disable_vf(struct iavf_adapter *adapter)
@@ -2081,7 +2121,7 @@ static void iavf_disable_vf(struct iavf_adapter *adapter)
	adapter->netdev->flags &= ~IFF_UP;
	mutex_unlock(&adapter->crit_lock);
	adapter->flags &= ~IAVF_FLAG_RESET_PENDING;
	adapter->state = __IAVF_DOWN;
	iavf_change_state(adapter, __IAVF_DOWN);
	wake_up(&adapter->down_waitqueue);
	dev_info(&adapter->pdev->dev, "Reset task did not complete, VF disabled\n");
}
@@ -2191,7 +2231,7 @@ static void iavf_reset_task(struct work_struct *work)
	}
	iavf_irq_disable(adapter);

	adapter->state = __IAVF_RESETTING;
	iavf_change_state(adapter, __IAVF_RESETTING);
	adapter->flags &= ~IAVF_FLAG_RESET_PENDING;

	/* free the Tx/Rx rings and descriptors, might be better to just
@@ -2291,11 +2331,14 @@ static void iavf_reset_task(struct work_struct *work)

		iavf_configure(adapter);

		/* iavf_up_complete() will switch device back
		 * to __IAVF_RUNNING
		 */
		iavf_up_complete(adapter);

		iavf_irq_enable(adapter, true);
	} else {
		adapter->state = __IAVF_DOWN;
		iavf_change_state(adapter, __IAVF_DOWN);
		wake_up(&adapter->down_waitqueue);
	}
	mutex_unlock(&adapter->client_lock);
@@ -2305,6 +2348,8 @@ static void iavf_reset_task(struct work_struct *work)
reset_err:
	mutex_unlock(&adapter->client_lock);
	mutex_unlock(&adapter->crit_lock);
	if (running)
		iavf_change_state(adapter, __IAVF_RUNNING);
	dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n");
	iavf_close(netdev);
}
@@ -3297,7 +3342,7 @@ static int iavf_close(struct net_device *netdev)
		adapter->flags |= IAVF_FLAG_CLIENT_NEEDS_CLOSE;

	iavf_down(adapter);
	adapter->state = __IAVF_DOWN_PENDING;
	iavf_change_state(adapter, __IAVF_DOWN_PENDING);
	iavf_free_traffic_irqs(adapter);

	mutex_unlock(&adapter->crit_lock);
@@ -3630,64 +3675,6 @@ int iavf_process_config(struct iavf_adapter *adapter)
	return 0;
}

/**
 * iavf_init_task - worker thread to perform delayed initialization
 * @work: pointer to work_struct containing our data
 *
 * This task completes the work that was begun in probe. Due to the nature
 * of VF-PF communications, we may need to wait tens of milliseconds to get
 * responses back from the PF. Rather than busy-wait in probe and bog down the
 * whole system, we'll do it in a task so we can sleep.
 * This task only runs during driver init. Once we've established
 * communications with the PF driver and set up our netdev, the watchdog
 * takes over.
 **/
static void iavf_init_task(struct work_struct *work)
{
	struct iavf_adapter *adapter = container_of(work,
						    struct iavf_adapter,
						    init_task.work);
	struct iavf_hw *hw = &adapter->hw;

	if (iavf_lock_timeout(&adapter->crit_lock, 5000)) {
		dev_warn(&adapter->pdev->dev, "failed to acquire crit_lock in %s\n", __FUNCTION__);
		return;
	}
	switch (adapter->state) {
	case __IAVF_STARTUP:
		if (iavf_startup(adapter) < 0)
			goto init_failed;
		break;
	case __IAVF_INIT_VERSION_CHECK:
		if (iavf_init_version_check(adapter) < 0)
			goto init_failed;
		break;
	case __IAVF_INIT_GET_RESOURCES:
		if (iavf_init_get_resources(adapter) < 0)
			goto init_failed;
		goto out;
	default:
		goto init_failed;
	}

	queue_delayed_work(iavf_wq, &adapter->init_task,
			   msecs_to_jiffies(30));
	goto out;
init_failed:
	if (++adapter->aq_wait_count > IAVF_AQ_MAX_ERR) {
		dev_err(&adapter->pdev->dev,
			"Failed to communicate with PF; waiting before retry\n");
		adapter->flags |= IAVF_FLAG_PF_COMMS_FAILED;
		iavf_shutdown_adminq(hw);
		adapter->state = __IAVF_STARTUP;
		queue_delayed_work(iavf_wq, &adapter->init_task, HZ * 5);
		goto out;
	}
	queue_delayed_work(iavf_wq, &adapter->init_task, HZ);
out:
	mutex_unlock(&adapter->crit_lock);
}

/**
 * iavf_shutdown - Shutdown the device in preparation for a reboot
 * @pdev: pci device structure
@@ -3705,7 +3692,7 @@ static void iavf_shutdown(struct pci_dev *pdev)
	if (iavf_lock_timeout(&adapter->crit_lock, 5000))
		dev_warn(&adapter->pdev->dev, "failed to acquire crit_lock in %s\n", __FUNCTION__);
	/* Prevent the watchdog from running. */
	adapter->state = __IAVF_REMOVE;
	iavf_change_state(adapter, __IAVF_REMOVE);
	adapter->aq_required = 0;
	mutex_unlock(&adapter->crit_lock);

@@ -3778,7 +3765,7 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
	hw->back = adapter;

	adapter->msg_enable = BIT(DEFAULT_DEBUG_LEVEL_SHIFT) - 1;
	adapter->state = __IAVF_STARTUP;
	iavf_change_state(adapter, __IAVF_STARTUP);

	/* Call save state here because it relies on the adapter struct. */
	pci_save_state(pdev);
@@ -3822,8 +3809,7 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
	INIT_WORK(&adapter->adminq_task, iavf_adminq_task);
	INIT_DELAYED_WORK(&adapter->watchdog_task, iavf_watchdog_task);
	INIT_DELAYED_WORK(&adapter->client_task, iavf_client_task);
	INIT_DELAYED_WORK(&adapter->init_task, iavf_init_task);
	queue_delayed_work(iavf_wq, &adapter->init_task,
	queue_delayed_work(iavf_wq, &adapter->watchdog_task,
			   msecs_to_jiffies(5 * (pdev->devfn & 0x07)));

	/* Setup the wait queue for indicating transition to down status */
@@ -3929,8 +3915,8 @@ static void iavf_remove(struct pci_dev *pdev)
	int err;
	/* Indicate we are in remove and not to run reset_task */
	mutex_lock(&adapter->remove_lock);
	cancel_delayed_work_sync(&adapter->init_task);
	cancel_work_sync(&adapter->reset_task);
	cancel_delayed_work_sync(&adapter->watchdog_task);
	cancel_delayed_work_sync(&adapter->client_task);
	if (adapter->netdev_registered) {
		unregister_netdev(netdev);
@@ -3954,7 +3940,7 @@ static void iavf_remove(struct pci_dev *pdev)
		dev_warn(&adapter->pdev->dev, "failed to acquire crit_lock in %s\n", __FUNCTION__);

	/* Shut down all the garbage mashers on the detention level */
	adapter->state = __IAVF_REMOVE;
	iavf_change_state(adapter, __IAVF_REMOVE);
	adapter->aq_required = 0;
	adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
	iavf_free_all_tx_resources(adapter);
+1 −1
Original line number Diff line number Diff line
@@ -1735,7 +1735,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
		iavf_free_all_tx_resources(adapter);
		iavf_free_all_rx_resources(adapter);
		if (adapter->state == __IAVF_DOWN_PENDING) {
			adapter->state = __IAVF_DOWN;
			iavf_change_state(adapter, __IAVF_DOWN);
			wake_up(&adapter->down_waitqueue);
		}
		break;