Commit 69422a7e authored by Rahul Lakkireddy's avatar Rahul Lakkireddy Committed by David S. Miller

cxgb4: fix EOTID leak when disabling TC-MQPRIO offload

Under heavy load, the EOTID termination FLOWC request fails to get
enqueued to the end of the Tx ring due to lack of credits. This
results in EOTID leak.

When disabling TC-MQPRIO offload, the link is already brought down
to cleanup EOTIDs. So, flush any pending enqueued skbs that can't be
sent outside the wire, to make room for FLOWC request. Also, move the
FLOWC descriptor consumption logic closer to when the FLOWC request is
actually posted to hardware.

Fixes: 0e395b3c ("cxgb4: add FLOWC based QoS offload")
Signed-off-by: default avatarRahul Lakkireddy <rahul.lakkireddy@chelsio.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ab1c637c
......@@ -2207,6 +2207,9 @@ static void ethofld_hard_xmit(struct net_device *dev,
if (unlikely(skip_eotx_wr)) {
start = (u64 *)wr;
eosw_txq->state = next_state;
eosw_txq->cred -= wrlen16;
eosw_txq->ncompl++;
eosw_txq->last_compl = 0;
goto write_wr_headers;
}
......@@ -2365,6 +2368,34 @@ netdev_tx_t t4_start_xmit(struct sk_buff *skb, struct net_device *dev)
return cxgb4_eth_xmit(skb, dev);
}
static void eosw_txq_flush_pending_skbs(struct sge_eosw_txq *eosw_txq)
{
int pktcount = eosw_txq->pidx - eosw_txq->last_pidx;
int pidx = eosw_txq->pidx;
struct sk_buff *skb;
if (!pktcount)
return;
if (pktcount < 0)
pktcount += eosw_txq->ndesc;
while (pktcount--) {
pidx--;
if (pidx < 0)
pidx += eosw_txq->ndesc;
skb = eosw_txq->desc[pidx].skb;
if (skb) {
dev_consume_skb_any(skb);
eosw_txq->desc[pidx].skb = NULL;
eosw_txq->inuse--;
}
}
eosw_txq->pidx = eosw_txq->last_pidx + 1;
}
/**
* cxgb4_ethofld_send_flowc - Send ETHOFLD flowc request to bind eotid to tc.
* @dev - netdevice
......@@ -2440,9 +2471,11 @@ int cxgb4_ethofld_send_flowc(struct net_device *dev, u32 eotid, u32 tc)
FW_FLOWC_MNEM_EOSTATE_CLOSING :
FW_FLOWC_MNEM_EOSTATE_ESTABLISHED);
eosw_txq->cred -= len16;
eosw_txq->ncompl++;
eosw_txq->last_compl = 0;
/* Free up any pending skbs to ensure there's room for
* termination FLOWC.
*/
if (tc == FW_SCHED_CLS_NONE)
eosw_txq_flush_pending_skbs(eosw_txq);
ret = eosw_txq_enqueue(eosw_txq, skb);
if (ret) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment