octeontx2-pf: Free pending and dropped SQEs
authorGeetha sowjanya <gakula@marvell.com>
Tue, 31 Oct 2023 11:23:45 +0000 (16:53 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 20 Nov 2023 10:52:16 +0000 (11:52 +0100)
[ Upstream commit 3423ca23e08bf285a324237abe88e7e7d9becfe6 ]

On interface down, the pending SQEs in the NIX get dropped
or drained out during SMQ flush. But skb's pointed by these
SQEs never get free or updated to the stack as respective CQE
never get added.
This patch fixes the issue by freeing all valid skb's in SQ SG list.

Fixes: b1bc8457e9d0 ("octeontx2-pf: Cleanup all receive buffers in SG descriptor")
Signed-off-by: Geetha sowjanya <gakula@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c

index c76dad78c26eb1c66ab3d62cbdebd9578d903823..0f896f606c3e66da39728bab6bf179c2f543a3dc 100644 (file)
@@ -797,7 +797,6 @@ void otx2_sqb_flush(struct otx2_nic *pfvf)
        int qidx, sqe_tail, sqe_head;
        struct otx2_snd_queue *sq;
        u64 incr, *ptr, val;
-       int timeout = 1000;
 
        ptr = (u64 *)otx2_get_regaddr(pfvf, NIX_LF_SQ_OP_STATUS);
        for (qidx = 0; qidx < otx2_get_total_tx_queues(pfvf); qidx++) {
@@ -806,15 +805,11 @@ void otx2_sqb_flush(struct otx2_nic *pfvf)
                        continue;
 
                incr = (u64)qidx << 32;
-               while (timeout) {
-                       val = otx2_atomic64_add(incr, ptr);
-                       sqe_head = (val >> 20) & 0x3F;
-                       sqe_tail = (val >> 28) & 0x3F;
-                       if (sqe_head == sqe_tail)
-                               break;
-                       usleep_range(1, 3);
-                       timeout--;
-               }
+               val = otx2_atomic64_add(incr, ptr);
+               sqe_head = (val >> 20) & 0x3F;
+               sqe_tail = (val >> 28) & 0x3F;
+               if (sqe_head != sqe_tail)
+                       usleep_range(50, 60);
        }
 }
 
index 876a7b51b8e51cc794c3bc69a78b0e110f9474b7..efd66224b3dbf83fde93f8bc44e358e0b0354529 100644 (file)
@@ -933,6 +933,7 @@ int otx2_txschq_config(struct otx2_nic *pfvf, int lvl, int prio, bool pfc_en);
 int otx2_txsch_alloc(struct otx2_nic *pfvf);
 void otx2_txschq_stop(struct otx2_nic *pfvf);
 void otx2_txschq_free_one(struct otx2_nic *pfvf, u16 lvl, u16 schq);
+void otx2_free_pending_sqe(struct otx2_nic *pfvf);
 void otx2_sqb_flush(struct otx2_nic *pfvf);
 int otx2_alloc_rbuf(struct otx2_nic *pfvf, struct otx2_pool *pool,
                    dma_addr_t *dma);
index c558c9b64f5be5ed2d681690afa43d57c783328c..c724131172f3f5c86cb8ec630e0a9983cbac6e7f 100644 (file)
@@ -1596,6 +1596,7 @@ static void otx2_free_hw_resources(struct otx2_nic *pf)
                else
                        otx2_cleanup_tx_cqes(pf, cq);
        }
+       otx2_free_pending_sqe(pf);
 
        otx2_free_sq_res(pf);
 
index d005434e1e03771aa1cbced8b95d5a8aa20c5ea7..20d801d30c732b6cc1c010f4a8185683704e82d2 100644 (file)
@@ -1224,9 +1224,11 @@ void otx2_cleanup_rx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq)
 
 void otx2_cleanup_tx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq)
 {
+       int tx_pkts = 0, tx_bytes = 0;
        struct sk_buff *skb = NULL;
        struct otx2_snd_queue *sq;
        struct nix_cqe_tx_s *cqe;
+       struct netdev_queue *txq;
        int processed_cqe = 0;
        struct sg_list *sg;
        int qidx;
@@ -1247,12 +1249,20 @@ void otx2_cleanup_tx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq)
                sg = &sq->sg[cqe->comp.sqe_id];
                skb = (struct sk_buff *)sg->skb;
                if (skb) {
+                       tx_bytes += skb->len;
+                       tx_pkts++;
                        otx2_dma_unmap_skb_frags(pfvf, sg);
                        dev_kfree_skb_any(skb);
                        sg->skb = (u64)NULL;
                }
        }
 
+       if (likely(tx_pkts)) {
+               if (qidx >= pfvf->hw.tx_queues)
+                       qidx -= pfvf->hw.xdp_queues;
+               txq = netdev_get_tx_queue(pfvf->netdev, qidx);
+               netdev_tx_completed_queue(txq, tx_pkts, tx_bytes);
+       }
        /* Free CQEs to HW */
        otx2_write64(pfvf, NIX_LF_CQ_OP_DOOR,
                     ((u64)cq->cq_idx << 32) | processed_cqe);
@@ -1279,6 +1289,38 @@ int otx2_rxtx_enable(struct otx2_nic *pfvf, bool enable)
        return err;
 }
 
+void otx2_free_pending_sqe(struct otx2_nic *pfvf)
+{
+       int tx_pkts = 0, tx_bytes = 0;
+       struct sk_buff *skb = NULL;
+       struct otx2_snd_queue *sq;
+       struct netdev_queue *txq;
+       struct sg_list *sg;
+       int sq_idx, sqe;
+
+       for (sq_idx = 0; sq_idx < pfvf->hw.tx_queues; sq_idx++) {
+               sq = &pfvf->qset.sq[sq_idx];
+               for (sqe = 0; sqe < sq->sqe_cnt; sqe++) {
+                       sg = &sq->sg[sqe];
+                       skb = (struct sk_buff *)sg->skb;
+                       if (skb) {
+                               tx_bytes += skb->len;
+                               tx_pkts++;
+                               otx2_dma_unmap_skb_frags(pfvf, sg);
+                               dev_kfree_skb_any(skb);
+                               sg->skb = (u64)NULL;
+                       }
+               }
+
+               if (!tx_pkts)
+                       continue;
+               txq = netdev_get_tx_queue(pfvf->netdev, sq_idx);
+               netdev_tx_completed_queue(txq, tx_pkts, tx_bytes);
+               tx_pkts = 0;
+               tx_bytes = 0;
+       }
+}
+
 static void otx2_xdp_sqe_add_sg(struct otx2_snd_queue *sq, u64 dma_addr,
                                int len, int *offset)
 {