93 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			93 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From b48745c534ced06005d2ba57198b54a6a160b39d Mon Sep 17 00:00:00 2001
 | 
						|
From: John Crispin <john@phrozen.org>
 | 
						|
Date: Sat, 23 Apr 2016 09:18:28 +0200
 | 
						|
Subject: [PATCH 083/102] net-next: mediatek: fix missing free of scratch
 | 
						|
 memory
 | 
						|
 | 
						|
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>
 | 
						|
---
 | 
						|
 drivers/net/ethernet/mediatek/mtk_eth_soc.c |   18 +++++++++++++-----
 | 
						|
 drivers/net/ethernet/mediatek/mtk_eth_soc.h |    2 ++
 | 
						|
 2 files changed, 15 insertions(+), 5 deletions(-)
 | 
						|
 | 
						|
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 | 
						|
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 | 
						|
@@ -484,14 +484,14 @@ static inline void mtk_rx_get_desc(struc
 | 
						|
 /* 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,
 | 
						|
+					       ð->phy_scratch_ring,
 | 
						|
 					       GFP_ATOMIC | __GFP_ZERO);
 | 
						|
 	if (unlikely(!eth->scratch_ring))
 | 
						|
 		return -ENOMEM;
 | 
						|
@@ -508,19 +508,19 @@ static int mtk_init_fq_dma(struct mtk_et
 | 
						|
 		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);
 | 
						|
@@ -1220,6 +1220,14 @@ static void mtk_dma_free(struct mtk_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);
 | 
						|
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 | 
						|
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 | 
						|
@@ -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;
 |