net: mediatek: fix missing free of scratch memory
authorJohn Crispin <john@phrozen.org>
Fri, 10 Jun 2016 11:27:59 +0000 (13:27 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sat, 11 Jun 2016 06:29:28 +0000 (23:29 -0700)
Scratch memory gets allocated in mtk_init_fq_dma() but the corresponding
code to free it is missing inside mtk_dma_free() causing a memory leak.
With this patch applied, we can run ifconfig up/down several thousand
times without any problems.

Signed-off-by: John Crispin <john@phrozen.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mediatek/mtk_eth_soc.c
drivers/net/ethernet/mediatek/mtk_eth_soc.h

index 11cd7304e4977138136709a84e21db6ddd66e199..fb8b17db7fa2b1e9bcd6aeaeaf136770a636a4be 100644 (file)
@@ -481,14 +481,14 @@ static inline void mtk_rx_get_desc(struct mtk_rx_dma *rxd,
 /* the qdma core needs scratch memory to be setup */
 static int mtk_init_fq_dma(struct mtk_eth *eth)
 {
-       dma_addr_t phy_ring_head, phy_ring_tail;
+       dma_addr_t phy_ring_tail;
        int cnt = MTK_DMA_SIZE;
        dma_addr_t dma_addr;
        int i;
 
        eth->scratch_ring = dma_alloc_coherent(eth->dev,
                                               cnt * sizeof(struct mtk_tx_dma),
-                                              &phy_ring_head,
+                                              &eth->phy_scratch_ring,
                                               GFP_ATOMIC | __GFP_ZERO);
        if (unlikely(!eth->scratch_ring))
                return -ENOMEM;
@@ -505,19 +505,19 @@ static int mtk_init_fq_dma(struct mtk_eth *eth)
                return -ENOMEM;
 
        memset(eth->scratch_ring, 0x0, sizeof(struct mtk_tx_dma) * cnt);
-       phy_ring_tail = phy_ring_head +
+       phy_ring_tail = eth->phy_scratch_ring +
                        (sizeof(struct mtk_tx_dma) * (cnt - 1));
 
        for (i = 0; i < cnt; i++) {
                eth->scratch_ring[i].txd1 =
                                        (dma_addr + (i * MTK_QDMA_PAGE_SIZE));
                if (i < cnt - 1)
-                       eth->scratch_ring[i].txd2 = (phy_ring_head +
+                       eth->scratch_ring[i].txd2 = (eth->phy_scratch_ring +
                                ((i + 1) * sizeof(struct mtk_tx_dma)));
                eth->scratch_ring[i].txd3 = TX_DMA_SDL(MTK_QDMA_PAGE_SIZE);
        }
 
-       mtk_w32(eth, phy_ring_head, MTK_QDMA_FQ_HEAD);
+       mtk_w32(eth, eth->phy_scratch_ring, MTK_QDMA_FQ_HEAD);
        mtk_w32(eth, phy_ring_tail, MTK_QDMA_FQ_TAIL);
        mtk_w32(eth, (cnt << 16) | cnt, MTK_QDMA_FQ_CNT);
        mtk_w32(eth, MTK_QDMA_PAGE_SIZE << 16, MTK_QDMA_FQ_BLEN);
@@ -1210,6 +1210,14 @@ static void mtk_dma_free(struct mtk_eth *eth)
        for (i = 0; i < MTK_MAC_COUNT; i++)
                if (eth->netdev[i])
                        netdev_reset_queue(eth->netdev[i]);
+       if (eth->scratch_ring) {
+               dma_free_coherent(eth->dev,
+                                 MTK_DMA_SIZE * sizeof(struct mtk_tx_dma),
+                                 eth->scratch_ring,
+                                 eth->phy_scratch_ring);
+               eth->scratch_ring = NULL;
+               eth->phy_scratch_ring = 0;
+       }
        mtk_tx_clean(eth);
        mtk_rx_clean(eth);
        kfree(eth->scratch_head);
index eed626d56ea4f1d3df5f2ed3aacbd8bded28cead..57f7e8a3dbe29a1945fbeb7a928825d999c4166b 100644 (file)
@@ -357,6 +357,7 @@ struct mtk_rx_ring {
  * @rx_ring:           Pointer to the memore holding info about the RX ring
  * @rx_napi:           The NAPI struct
  * @scratch_ring:      Newer SoCs need memory for a second HW managed TX ring
+ * @phy_scratch_ring:  physical address of scratch_ring
  * @scratch_head:      The scratch memory that scratch_ring points to.
  * @clk_ethif:         The ethif clock
  * @clk_esw:           The switch clock
@@ -384,6 +385,7 @@ struct mtk_eth {
        struct mtk_rx_ring              rx_ring;
        struct napi_struct              rx_napi;
        struct mtk_tx_dma               *scratch_ring;
+       dma_addr_t                      phy_scratch_ring;
        void                            *scratch_head;
        struct clk                      *clk_ethif;
        struct clk                      *clk_esw;