pcnet: add cache flushing & invalidation
Ensure that the view of memory from the CPU & the ethernet controller is
coherent at the various points where they exchange data. This prevents
stale data from being transmitted or received, and prevents the driver
from getting stuck waiting for the ethernet controller to update
descriptors when in reality it has but the old values are being read
from cache.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
diff --git a/drivers/net/pcnet.c b/drivers/net/pcnet.c
index 843a6fc..7b87660 100644
--- a/drivers/net/pcnet.c
+++ b/drivers/net/pcnet.c
@@ -364,6 +364,7 @@
RX_RING_LEN_BITS);
lp->init_block.rx_ring = PCI_TO_MEM_LE(dev, lp->rx_ring);
lp->init_block.tx_ring = PCI_TO_MEM_LE(dev, lp->tx_ring);
+ flush_dcache_range((unsigned long)lp, (unsigned long)&lp->rx_buf);
PCNET_DEBUG1("\ntlen_rlen=0x%x rx_ring=0x%x tx_ring=0x%x\n",
lp->init_block.tlen_rlen,
@@ -407,8 +408,13 @@
PCNET_DEBUG2("Tx%d: %d bytes from 0x%p ", lp->cur_tx, pkt_len,
packet);
+ flush_dcache_range((unsigned long)packet,
+ (unsigned long)packet + pkt_len);
+
/* Wait for completion by testing the OWN bit */
for (i = 1000; i > 0; i--) {
+ invalidate_dcache_range((unsigned long)entry,
+ (unsigned long)entry + sizeof(*entry));
status = le16_to_cpu(entry->status);
if ((status & 0x8000) == 0)
break;
@@ -431,6 +437,8 @@
entry->misc = 0x00000000;
entry->base = PCI_TO_MEM_LE(dev, packet);
entry->status = cpu_to_le16(status);
+ flush_dcache_range((unsigned long)entry,
+ (unsigned long)entry + sizeof(*entry));
/* Trigger an immediate send poll. */
pcnet_write_csr(dev, 0, 0x0008);
@@ -451,6 +459,8 @@
while (1) {
entry = &lp->rx_ring[lp->cur_rx];
+ invalidate_dcache_range((unsigned long)entry,
+ (unsigned long)entry + sizeof(*entry));
/*
* If we own the next entry, it's a new packet. Send it up.
*/
@@ -479,6 +489,10 @@
printf("%s: Rx%d: invalid packet length %d\n",
dev->name, lp->cur_rx, pkt_len);
} else {
+ invalidate_dcache_range(
+ (unsigned long)lp->rx_buf[lp->cur_rx],
+ (unsigned long)lp->rx_buf[lp->cur_rx] +
+ pkt_len);
NetReceive(lp->rx_buf[lp->cur_rx], pkt_len);
PCNET_DEBUG2("Rx%d: %d bytes from 0x%p\n",
lp->cur_rx, pkt_len,
@@ -486,6 +500,8 @@
}
}
entry->status |= cpu_to_le16(0x8000);
+ flush_dcache_range((unsigned long)entry,
+ (unsigned long)entry + sizeof(*entry));
if (++lp->cur_rx >= RX_RING_SIZE)
lp->cur_rx = 0;