net: thunderx: Fix memory leak and other issues upon interface toggle
authorSunil Goutham <sgoutham@cavium.com>
Tue, 15 Nov 2016 12:08:29 +0000 (17:38 +0530)
committerDavid S. Miller <davem@davemloft.net>
Wed, 16 Nov 2016 18:28:33 +0000 (13:28 -0500)
This patch fixes the following
1. When interface is being teardown and queues are being cleaned up,
   free pending SKBs that are in SQ which are either not transmitted
   or freed as NAPI is disabled by that time.
2. While interface initialization, delay CFG_DONE notification till
   the end to avoid corner cases where TXQs are enabled but CQ
   interrupts are not which results blocking transmission and kicking
   off watchdog.
3. Check for IFF_UP while re-enabling RBDR interrupts from tasklet.

Signed-off-by: Sunil Goutham <sgoutham@cavium.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/cavium/thunder/nicvf_main.c
drivers/net/ethernet/cavium/thunder/nicvf_queues.c

index 9dc79c0578d8a614046b019f9aafea47dad015a3..8a37012c9c89637560fc3ae7554718b0f96163e4 100644 (file)
@@ -473,9 +473,6 @@ int nicvf_set_real_num_queues(struct net_device *netdev,
 static int nicvf_init_resources(struct nicvf *nic)
 {
        int err;
-       union nic_mbx mbx = {};
-
-       mbx.msg.msg = NIC_MBOX_MSG_CFG_DONE;
 
        /* Enable Qset */
        nicvf_qset_config(nic, true);
@@ -488,9 +485,6 @@ static int nicvf_init_resources(struct nicvf *nic)
                return err;
        }
 
-       /* Send VF config done msg to PF */
-       nicvf_write_to_mbx(nic, &mbx);
-
        return 0;
 }
 
@@ -1184,6 +1178,7 @@ int nicvf_open(struct net_device *netdev)
        struct nicvf *nic = netdev_priv(netdev);
        struct queue_set *qs = nic->qs;
        struct nicvf_cq_poll *cq_poll = NULL;
+       union nic_mbx mbx = {};
 
        netif_carrier_off(netdev);
 
@@ -1271,6 +1266,10 @@ int nicvf_open(struct net_device *netdev)
        for (qidx = 0; qidx < qs->rbdr_cnt; qidx++)
                nicvf_enable_intr(nic, NICVF_INTR_RBDR, qidx);
 
+       /* Send VF config done msg to PF */
+       mbx.msg.msg = NIC_MBOX_MSG_CFG_DONE;
+       nicvf_write_to_mbx(nic, &mbx);
+
        return 0;
 cleanup:
        nicvf_disable_intr(nic, NICVF_INTR_MBOX, 0);
index bdce5915baae42daec2036491fba6826a67adc20..747ef08829763db89b8fb1802eab9b47a0eef6b0 100644 (file)
@@ -271,7 +271,8 @@ refill:
                              rbdr_idx, new_rb);
 next_rbdr:
        /* Re-enable RBDR interrupts only if buffer allocation is success */
-       if (!nic->rb_alloc_fail && rbdr->enable)
+       if (!nic->rb_alloc_fail && rbdr->enable &&
+           netif_running(nic->pnicvf->netdev))
                nicvf_enable_intr(nic, NICVF_INTR_RBDR, rbdr_idx);
 
        if (rbdr_idx)
@@ -362,6 +363,8 @@ static int nicvf_init_snd_queue(struct nicvf *nic,
 
 static void nicvf_free_snd_queue(struct nicvf *nic, struct snd_queue *sq)
 {
+       struct sk_buff *skb;
+
        if (!sq)
                return;
        if (!sq->dmem.base)
@@ -372,6 +375,15 @@ static void nicvf_free_snd_queue(struct nicvf *nic, struct snd_queue *sq)
                                  sq->dmem.q_len * TSO_HEADER_SIZE,
                                  sq->tso_hdrs, sq->tso_hdrs_phys);
 
+       /* Free pending skbs in the queue */
+       smp_rmb();
+       while (sq->head != sq->tail) {
+               skb = (struct sk_buff *)sq->skbuff[sq->head];
+               if (skb)
+                       dev_kfree_skb_any(skb);
+               sq->head++;
+               sq->head &= (sq->dmem.q_len - 1);
+       }
        kfree(sq->skbuff);
        nicvf_free_q_desc_mem(nic, &sq->dmem);
 }