netdev: octeon_mgmt: Fix race condition freeing TX buffers.
authorDavid Daney <ddaney@caviumnetworks.com>
Wed, 5 May 2010 13:03:09 +0000 (13:03 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 6 May 2010 04:22:33 +0000 (21:22 -0700)
Under heavy load the TX cleanup tasklet and xmit threads would race
and try to free too many buffers.

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/octeon/octeon_mgmt.c

index bbbd737210f9d0a1c541c0974ddadcee7c93d554..b975a2fad9530ff8dad979213d36d8e924fb49f0 100644 (file)
@@ -189,12 +189,19 @@ static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p)
 
        mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port));
        while (mix_orcnt.s.orcnt) {
+               spin_lock_irqsave(&p->tx_list.lock, flags);
+
+               mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port));
+
+               if (mix_orcnt.s.orcnt == 0) {
+                       spin_unlock_irqrestore(&p->tx_list.lock, flags);
+                       break;
+               }
+
                dma_sync_single_for_cpu(p->dev, p->tx_ring_handle,
                                        ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE),
                                        DMA_BIDIRECTIONAL);
 
-               spin_lock_irqsave(&p->tx_list.lock, flags);
-
                re.d64 = p->tx_ring[p->tx_next_clean];
                p->tx_next_clean =
                        (p->tx_next_clean + 1) % OCTEON_MGMT_TX_RING_SIZE;