[U-Boot] [PATCH 8/9] net: rtl8169: Use non-cached memory if available

Thierry Reding thierry.reding at gmail.com
Mon Aug 18 10:00:51 CEST 2014


From: Thierry Reding <treding at nvidia.com>

To work around potential issues with explicit cache maintenance of the
RX and TX descriptor rings, allocate them from a pool of uncached memory
if the architecture supports it.

Signed-off-by: Thierry Reding <treding at nvidia.com>
---
 drivers/net/rtl8169.c | 43 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c
index c53666134e06..1c04946d7691 100644
--- a/drivers/net/rtl8169.c
+++ b/drivers/net/rtl8169.c
@@ -283,11 +283,31 @@ struct RxDesc {
 #  define RTL8169_ALIGN 256
 #endif
 
+/*
+ * TX and RX descriptors are 16 bytes. This causes problems with the cache
+ * maintenance on CPUs where the cache-line size exceeds the size of these
+ * descriptors. What will happen is that when the driver receives a packet
+ * it will be immediately requeued for the hardware to reuse. The CPU will
+ * therefore need to flush the cache-line containing the descriptor, which
+ * will cause all other descriptors in the same cache-line to be flushed
+ * along with it. If one of those descriptors had been written to by the
+ * device those changes (and the associated packet) will be lost.
+ *
+ * To work around this, we make use of non-cached memory if available. If
+ * descriptors are mapped uncached there's no need to manually flush them
+ * or invalidate them.
+ *
+ * Note that this only applies to descriptors. The packet data buffers do
+ * not have the same constraints since they are 1536 bytes large, so they
+ * are unlikely to share cache-lines.
+ */
+#ifndef CONFIG_SYS_NONCACHED_MEMORY
 /* Define the TX Descriptor */
 DEFINE_ALIGN_BUFFER(struct TxDesc, tx_ring, NUM_TX_DESC, RTL8169_ALIGN);
 
 /* Define the RX Descriptor */
 DEFINE_ALIGN_BUFFER(struct RxDesc, rx_ring, NUM_RX_DESC, RTL8169_ALIGN);
+#endif
 
 /*
  * Create a static buffer of size RX_BUF_SZ for each TX Descriptor. All
@@ -412,28 +432,36 @@ match:
 
 static void rtl_inval_rx_desc(struct RxDesc *desc)
 {
+#ifndef CONFIG_SYS_NONCACHED_MEMORY
 	unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1);
 	unsigned long end = ALIGN(start + sizeof(*desc), ARCH_DMA_MINALIGN);
 
 	invalidate_dcache_range(start, end);
+#endif
 }
 
 static void rtl_flush_rx_desc(struct RxDesc *desc)
 {
+#ifndef CONFIG_SYS_NONCACHED_MEMORY
 	flush_cache((unsigned long)desc, sizeof(*desc));
+#endif
 }
 
 static void rtl_inval_tx_desc(struct TxDesc *desc)
 {
+#ifndef CONFIG_SYS_NONCACHED_MEMORY
 	unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1);
 	unsigned long end = ALIGN(start + sizeof(*desc), ARCH_DMA_MINALIGN);
 
 	invalidate_dcache_range(start, end);
+#endif
 }
 
 static void rtl_flush_tx_desc(struct TxDesc *desc)
 {
+#ifndef CONFIG_SYS_NONCACHED_MEMORY
 	flush_cache((unsigned long)desc, sizeof(*desc));
+#endif
 }
 
 static void rtl_inval_buffer(void *buf, size_t size)
@@ -769,6 +797,9 @@ INIT - Look for an adapter, this routine's visible to the outside
 static int rtl_init(struct eth_device *dev, bd_t *bis)
 {
 	static int board_idx = -1;
+#ifdef CONFIG_SYS_NONCACHED_MEMORY
+	size_t size;
+#endif
 	int i, rc;
 	int option = -1, Cap10_100 = 0, Cap1000 = 0;
 
@@ -899,6 +930,7 @@ static int rtl_init(struct eth_device *dev, bd_t *bis)
 #endif
 	}
 
+#ifndef CONFIG_SYS_NONCACHED_MEMORY
 	/*
 	 * Warn if the cache-line size is larger than the descriptor size. In
 	 * such cases the driver will likely fail because the CPU needs to
@@ -910,6 +942,17 @@ static int rtl_init(struct eth_device *dev, bd_t *bis)
 
 	tpc->TxDescArray = tx_ring;
 	tpc->RxDescArray = rx_ring;
+#else
+	/*
+	 * When non-cached memory is available, allocate the descriptors from
+	 * an uncached memory region to avoid any problems caused by caching.
+	 */
+	size = NUM_TX_DESC * sizeof(struct TxDesc);
+	tpc->TxDescArray = (struct TxDesc *)noncached_alloc(size, 256);
+
+	size = NUM_RX_DESC * sizeof(struct RxDesc);
+	tpc->RxDescArray = (struct RxDesc *)noncached_alloc(size, 256);
+#endif
 
 	return 1;
 }
-- 
2.0.4



More information about the U-Boot mailing list