[PATCH] PQII FCC Ethernet driver: transmit buffer leak for 2.4
Li Yang-r58472
LeoLi at freescale.com
Mon Jun 28 21:40:39 EST 2004
Hi,
When PQII FCC Ethernet runs under heavy tx load(such as using NetPIPE to
measure network performance), you may observe memory leak. Eventually
makes system crash. I digged into this problem and found that 2.6.7
don't have this problem. I pulled the fix to 2.4.x, and generated patch
(for 2.4.26, and can be easily modified for other versions). I suggest
that anyone using linux-2.4.x on PQII apply this patch. The problem is
kind of serious. And this should be merged into kernel.org tree as soon
as possible. Who can pass this to the 2.4 maintainer?
--
Leo Li
Software Engineer
Metrowerks -- Freescale
Patch
======
--- linux-2.4.26/arch/ppc/cpm2_io/fcc_enet.c 2004-04-14 21:05:27.000000000 +0800
+++ linux-2.4.26/arch/ppc/cpm2_io/fcc_enet.c.new 2004-06-28 17:02:19.060144928 +0800
@@ -304,6 +304,8 @@
struct sk_buff* tx_skbuff[TX_RING_SIZE];
ushort skb_cur;
ushort skb_dirty;
+
+ atomic_t n_pkts; /* Number of packets in tx ring */
/* CPM dual port RAM relative addresses.
*/
@@ -396,13 +398,15 @@
bdp->cbd_datlen = skb->len;
bdp->cbd_bufaddr = __pa(skb->data);
+ spin_lock_irq(&cep->lock);
+
/* Save skb pointer. */
cep->tx_skbuff[cep->skb_cur] = skb;
cep->stats.tx_bytes += skb->len;
cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK;
- spin_lock_irq(&cep->lock);
+ atomic_inc(&cep->n_pkts);
/* Send it on its way. Tell CPM its ready, interrupt when done,
* its the last BD of the frame, and to put the CRC on the end.
@@ -421,9 +425,12 @@
else
bdp++;
- if (bdp->cbd_sc & BD_ENET_TX_READY) {
- netif_stop_queue(dev);
+ /* If the tx_ring is full, stop the queue */
+ if (atomic_read(&cep->n_pkts) >= (TX_RING_SIZE-1)) {
+ if (!netif_queue_stopped(dev)) {
+ netif_stop_queue(dev);
cep->tx_full = 1;
+ }
}
cep->cur_tx = (cbd_t *)bdp;
@@ -541,6 +548,8 @@
/* Free the sk buffer associated with this last transmit. */
dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]);
cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK;
+
+ atomic_dec(&cep->n_pkts);
/* Update pointer to next buffer descriptor to be transmitted. */
if (bdp->cbd_sc & BD_ENET_TX_WRAP)
@@ -1782,6 +1791,7 @@
while (cp->cp_cpcr & CPM_CR_FLG);
cep->skb_cur = cep->skb_dirty = 0;
+ atomic_set(&cep->n_pkts, 0);
}
/* Let 'er rip.
** Sent via the linuxppc-embedded mail list. See http://lists.linuxppc.org/
More information about the Linuxppc-embedded
mailing list