提交 19fc190e 编写于 作者: A Arkadiusz Kubalewski 提交者: Yang Yingliang

i40e: Fix logic of disabling queues

stable inclusion
from linux-4.19.201
commit 6d51a5fb5b864b137cf1135abb526fff5afdce21

--------------------------------

[ Upstream commit 65662a8d ]

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: NAleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: NArkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Tested-by: NTony Brelinski <tonyx.brelinski@intel.com>
Signed-off-by: NTony Nguyen <anthony.l.nguyen@intel.com>
Signed-off-by: NSasha Levin <sashal@kernel.org>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 9855d5cf
...@@ -4310,11 +4310,10 @@ int i40e_control_wait_tx_q(int seid, struct i40e_pf *pf, int pf_q, ...@@ -4310,11 +4310,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 * @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; struct i40e_pf *pf = vsi->back;
int i, pf_q, ret = 0; int i, pf_q, ret = 0;
...@@ -4323,7 +4322,7 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable) ...@@ -4323,7 +4322,7 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) { for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
ret = i40e_control_wait_tx_q(vsi->seid, pf, ret = i40e_control_wait_tx_q(vsi->seid, pf,
pf_q, pf_q,
false /*is xdp*/, enable); false /*is xdp*/, true);
if (ret) if (ret)
break; break;
...@@ -4332,7 +4331,7 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable) ...@@ -4332,7 +4331,7 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
ret = i40e_control_wait_tx_q(vsi->seid, pf, ret = i40e_control_wait_tx_q(vsi->seid, pf,
pf_q + vsi->alloc_queue_pairs, pf_q + vsi->alloc_queue_pairs,
true /*is xdp*/, enable); true /*is xdp*/, true);
if (ret) if (ret)
break; break;
} }
...@@ -4430,32 +4429,25 @@ int i40e_control_wait_rx_q(struct i40e_pf *pf, int pf_q, bool enable) ...@@ -4430,32 +4429,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 * @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; struct i40e_pf *pf = vsi->back;
int i, pf_q, ret = 0; int i, pf_q, ret = 0;
pf_q = vsi->base_queue; pf_q = vsi->base_queue;
for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) { 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) { if (ret) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"VSI seid %d Rx ring %d %sable timeout\n", "VSI seid %d Rx ring %d enable timeout\n",
vsi->seid, pf_q, (enable ? "en" : "dis")); vsi->seid, pf_q);
break; 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; return ret;
} }
...@@ -4468,29 +4460,47 @@ int i40e_vsi_start_rings(struct i40e_vsi *vsi) ...@@ -4468,29 +4460,47 @@ int i40e_vsi_start_rings(struct i40e_vsi *vsi)
int ret = 0; int ret = 0;
/* do rx first for enable and last for disable */ /* do rx first for enable and last for disable */
ret = i40e_vsi_control_rx(vsi, true); ret = i40e_vsi_enable_rx(vsi);
if (ret) if (ret)
return ret; return ret;
ret = i40e_vsi_control_tx(vsi, true); ret = i40e_vsi_enable_tx(vsi);
return ret; return ret;
} }
#define I40E_DISABLE_TX_GAP_MSEC 50
/** /**
* i40e_vsi_stop_rings - Stop a VSI's rings * i40e_vsi_stop_rings - Stop a VSI's rings
* @vsi: the VSI being configured * @vsi: the VSI being configured
**/ **/
void i40e_vsi_stop_rings(struct i40e_vsi *vsi) 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 */ /* When port TX is suspended, don't wait */
if (test_bit(__I40E_PORT_SUSPENDED, vsi->back->state)) if (test_bit(__I40E_PORT_SUSPENDED, vsi->back->state))
return i40e_vsi_stop_rings_no_wait(vsi); return i40e_vsi_stop_rings_no_wait(vsi);
/* do rx first for enable and last for disable q_end = vsi->base_queue + vsi->num_queue_pairs;
* Ignore return value, we need to shutdown whatever we can for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++)
*/ i40e_pre_tx_queue_cfg(&pf->hw, (u32)pf_q, false);
i40e_vsi_control_tx(vsi, false);
i40e_vsi_control_rx(vsi, 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);
} }
/** /**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册