The access patterns inside the driver assume uncached memory
but the memory returned by netdev_priv is cached.
The bug manifests itself in packets taking a long time to be
sent or received because the owner flag in the DMA descriptor
is still in the cache.

Signed-off-by: Daniel Glöckner <daniel...@gmx.net>
---
 drivers/net/jz_eth.c |   39 ++++++++++++++++++++++++++++++---------
 1 files changed, 30 insertions(+), 9 deletions(-)

diff --git a/drivers/net/jz_eth.c b/drivers/net/jz_eth.c
index e81e6da..1f4cec4 100644
--- a/drivers/net/jz_eth.c
+++ b/drivers/net/jz_eth.c
@@ -1262,12 +1262,12 @@ static int __init jz_eth_init(void)
 {
        struct net_device *dev;
        struct jz_eth_private *np;
-       int err;
+       int err = -ENOMEM;
 
        dev = alloc_etherdev(sizeof(struct jz_eth_private));
        if (!dev) {
                printk(KERN_ERR "%s: alloc_etherdev failed\n", DRV_NAME);
-               return -ENOMEM;
+               goto err_out;
        }
        
        netdev = dev;
@@ -1279,13 +1279,20 @@ static int __init jz_eth_init(void)
 
        if (!np->vaddr_rx_buf) {
                printk(KERN_ERR "%s: Cannot alloc dma buffers\n", DRV_NAME);
-               unregister_netdev(dev);
-               free_netdev(dev);
-               return -ENOMEM;
+               goto err_free_netdev;
        }
 
-       np->dma_rx_ring = virt_to_bus(np->rx_ring);
-       np->dma_tx_ring = virt_to_bus(np->tx_ring);
+       np->tx_ring = dma_alloc_coherent(NULL, (NUM_TX_DESCS + NUM_RX_DESCS)
+                                               * sizeof(jz_desc_t),
+                                        &np->dma_tx_ring, GFP_KERNEL);
+
+       if (!np->tx_ring) {
+               printk(KERN_ERR "%s: Cannot alloc dma descriptors\n", DRV_NAME);
+               goto err_free_buf;
+       }
+
+       np->rx_ring = np->tx_ring + NUM_TX_DESCS;
+       np->dma_rx_ring = np->dma_tx_ring + sizeof(jz_desc_t) * NUM_TX_DESCS;
        np->full_duplex = 1;
        np->link_state = 1;
 
@@ -1301,8 +1308,7 @@ static int __init jz_eth_init(void)
        if ((err = register_netdev(dev)) != 0) {
                printk(KERN_ERR "%s: Cannot register net device, error %d\n",
                                DRV_NAME, err);
-               free_netdev(dev);
-               return -ENOMEM;
+               goto err_free_descs;
        }
 
 //#ifdef 0 //CONFIG_PM
@@ -1312,6 +1318,18 @@ static int __init jz_eth_init(void)
 //#endif
 
        return 0;
+
+err_free_descs:
+       dma_free_coherent(NULL, (NUM_TX_DESCS + NUM_RX_DESCS)
+                                * sizeof(jz_desc_t),
+                         np->tx_ring, np->dma_tx_ring);
+err_free_buf:
+       dma_free_noncoherent(NULL, NUM_RX_DESCS * RX_BUF_SIZE,
+                            (void *)np->vaddr_rx_buf, np->dma_rx_buf);
+err_free_netdev:
+       free_netdev(dev);
+err_out:
+       return err;
 }
 
 static void __exit jz_eth_exit(void)
@@ -1320,6 +1338,9 @@ static void __exit jz_eth_exit(void)
        struct jz_eth_private *np = netdev_priv(dev);
 
        unregister_netdev(dev);
+       dma_free_coherent(NULL, (NUM_TX_DESCS + NUM_RX_DESCS)
+                                * sizeof(jz_desc_t),
+                         np->tx_ring, np->dma_tx_ring);
        dma_free_noncoherent(NULL, NUM_RX_DESCS * RX_BUF_SIZE,
                             (void *)np->vaddr_rx_buf, np->dma_rx_buf);
        free_netdev(dev);
-- 
1.7.0.5


_______________________________________________
Mipsbook-devel mailing list
Mipsbook-devel@linuxtogo.org
http://lists.linuxtogo.org/cgi-bin/mailman/listinfo/mipsbook-devel

Reply via email to