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

Commit b2ab34e8 authored by Arkadiusz Kubalewski's avatar Arkadiusz Kubalewski Committed by Greg Kroah-Hartman
Browse files

i40e: Fix logic of disabling queues



[ Upstream commit 65662a8dcdd01342b71ee44234bcfd0162e195af ]

Correct the message flow between driver and firmware when disabling
queues.

Previously in case of PF reset (due to required reinit after reconfig),
the error like: "VSI seid 397 Tx ring 60 disable timeout" could show up
occasionally. The error was not a real issue of hardware or firmware,
it was caused by wrong sequence of messages invoked by the driver.

Fixes: 41c445ff ("i40e: main driver core")
Signed-off-by: default avatarAleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: default avatarArkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Tested-by: default avatarTony Brelinski <tonyx.brelinski@intel.com>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 519582e4
Loading
Loading
Loading
Loading
+34 −24
Original line number Diff line number Diff line
@@ -4403,11 +4403,10 @@ int i40e_control_wait_tx_q(int seid, struct i40e_pf *pf, int pf_q,
}

/**
 * i40e_vsi_control_tx - Start or stop a VSI's rings
 * i40e_vsi_enable_tx - Start a VSI's rings
 * @vsi: the VSI being configured
 * @enable: start or stop the rings
 **/
static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
static int i40e_vsi_enable_tx(struct i40e_vsi *vsi)
{
	struct i40e_pf *pf = vsi->back;
	int i, pf_q, ret = 0;
@@ -4416,7 +4415,7 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
	for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
		ret = i40e_control_wait_tx_q(vsi->seid, pf,
					     pf_q,
					     false /*is xdp*/, enable);
					     false /*is xdp*/, true);
		if (ret)
			break;

@@ -4425,7 +4424,7 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)

		ret = i40e_control_wait_tx_q(vsi->seid, pf,
					     pf_q + vsi->alloc_queue_pairs,
					     true /*is xdp*/, enable);
					     true /*is xdp*/, true);
		if (ret)
			break;
	}
@@ -4523,32 +4522,25 @@ int i40e_control_wait_rx_q(struct i40e_pf *pf, int pf_q, bool enable)
}

/**
 * i40e_vsi_control_rx - Start or stop a VSI's rings
 * i40e_vsi_enable_rx - Start a VSI's rings
 * @vsi: the VSI being configured
 * @enable: start or stop the rings
 **/
static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable)
static int i40e_vsi_enable_rx(struct i40e_vsi *vsi)
{
	struct i40e_pf *pf = vsi->back;
	int i, pf_q, ret = 0;

	pf_q = vsi->base_queue;
	for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
		ret = i40e_control_wait_rx_q(pf, pf_q, enable);
		ret = i40e_control_wait_rx_q(pf, pf_q, true);
		if (ret) {
			dev_info(&pf->pdev->dev,
				 "VSI seid %d Rx ring %d %sable timeout\n",
				 vsi->seid, pf_q, (enable ? "en" : "dis"));
				 "VSI seid %d Rx ring %d enable timeout\n",
				 vsi->seid, pf_q);
			break;
		}
	}

	/* Due to HW errata, on Rx disable only, the register can indicate done
	 * before it really is. Needs 50ms to be sure
	 */
	if (!enable)
		mdelay(50);

	return ret;
}

@@ -4561,29 +4553,47 @@ int i40e_vsi_start_rings(struct i40e_vsi *vsi)
	int ret = 0;

	/* do rx first for enable and last for disable */
	ret = i40e_vsi_control_rx(vsi, true);
	ret = i40e_vsi_enable_rx(vsi);
	if (ret)
		return ret;
	ret = i40e_vsi_control_tx(vsi, true);
	ret = i40e_vsi_enable_tx(vsi);

	return ret;
}

#define I40E_DISABLE_TX_GAP_MSEC	50

/**
 * i40e_vsi_stop_rings - Stop a VSI's rings
 * @vsi: the VSI being configured
 **/
void i40e_vsi_stop_rings(struct i40e_vsi *vsi)
{
	struct i40e_pf *pf = vsi->back;
	int pf_q, err, q_end;

	/* When port TX is suspended, don't wait */
	if (test_bit(__I40E_PORT_SUSPENDED, vsi->back->state))
		return i40e_vsi_stop_rings_no_wait(vsi);

	/* do rx first for enable and last for disable
	 * Ignore return value, we need to shutdown whatever we can
	 */
	i40e_vsi_control_tx(vsi, false);
	i40e_vsi_control_rx(vsi, false);
	q_end = vsi->base_queue + vsi->num_queue_pairs;
	for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++)
		i40e_pre_tx_queue_cfg(&pf->hw, (u32)pf_q, false);

	for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++) {
		err = i40e_control_wait_rx_q(pf, pf_q, false);
		if (err)
			dev_info(&pf->pdev->dev,
				 "VSI seid %d Rx ring %d dissable timeout\n",
				 vsi->seid, pf_q);
	}

	msleep(I40E_DISABLE_TX_GAP_MSEC);
	pf_q = vsi->base_queue;
	for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++)
		wr32(&pf->hw, I40E_QTX_ENA(pf_q), 0);

	i40e_vsi_wait_queues_disabled(vsi);
}

/**