[U-Boot] [PATCH 4/8] davinci_emac: fix for running with dcache enabled

Ilya Yanok yanok at emcraft.com
Thu Oct 13 23:11:48 CEST 2011


DaVinci EMAC is present on TI AM35xx SoCs (ARMv7) which run with D-Cache
enabled by default. So we have to take care and flush/invalidate the
cache before/after the DMA operations.

Please note that the receive buffer alignment to 32 byte boundary comes
from the old driver version I don't know if it is really needed or
alignment to cache line size is enough.

!!!NOTE!!! This actually breaks builds for all DaVinci boards that use
this driver (as there is no {invalidate,flush}_dcache_range for
ARM926EJS).

Signed-off-by: Ilya Yanok <yanok at emcraft.com>
---
 drivers/net/davinci_emac.c |   41 +++++++++++++++++++++++++++++++++++++++--
 drivers/net/davinci_emac.h |    5 +++--
 2 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
index d413478..4318a39 100644
--- a/drivers/net/davinci_emac.c
+++ b/drivers/net/davinci_emac.c
@@ -41,6 +41,7 @@
 #include <net.h>
 #include <miiphy.h>
 #include <malloc.h>
+#include <linux/compiler.h>
 #include <asm/arch/emac_defs.h>
 #include <asm/io.h>
 #include "davinci_emac.h"
@@ -100,13 +101,34 @@ static volatile emac_desc	*emac_rx_active_tail = 0;
 static int			emac_rx_queue_active = 0;
 
 /* Receive packet buffers */
-static unsigned char		emac_rx_buffers[EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)];
+static unsigned char emac_rx_buffers[EMAC_MAX_RX_BUFFERS * EMAC_RXBUF_SIZE]
+				__aligned(CONFIG_SYS_CACHELINE_SIZE);
 
 /* PHY address for a discovered PHY (0xff - not found) */
 static volatile u_int8_t	active_phy_addr = 0xff;
 
 phy_t				phy;
 
+static inline void davinci_flush_rx_descs(void)
+{
+	/* flush the whole RX descs area */
+	flush_dcache_range(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE,
+			EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE);
+}
+
+static inline void davinci_invalidate_rx_descs(void)
+{
+	/* invalidate the whole RX descs area */
+	invalidate_dcache_range(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE,
+			EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE);
+}
+
+static inline void davinci_flush_desc(emac_desc *desc)
+{
+	flush_dcache_range((unsigned long)desc,
+			(unsigned long)desc + sizeof(*desc));
+}
+
 static int davinci_eth_set_mac_addr(struct eth_device *dev)
 {
 	unsigned long		mac_hi;
@@ -411,7 +433,7 @@ static int davinci_eth_open(struct eth_device *dev, bd_t *bis)
 	emac_rx_active_head = emac_rx_desc;
 	for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) {
 		rx_desc->next = BD_TO_HW((u_int32_t)(rx_desc + 1));
-		rx_desc->buffer = &emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)];
+		rx_desc->buffer = &emac_rx_buffers[cnt * EMAC_RXBUF_SIZE];
 		rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
 		rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
 		rx_desc++;
@@ -423,6 +445,8 @@ static int davinci_eth_open(struct eth_device *dev, bd_t *bis)
 	emac_rx_active_tail = rx_desc;
 	emac_rx_queue_active = 1;
 
+	davinci_flush_rx_descs();
+
 	/* Enable TX/RX */
 	writel(EMAC_MAX_ETHERNET_PKT_SIZE, &adap_emac->RXMAXLEN);
 	writel(0, &adap_emac->RXBUFFEROFFSET);
@@ -579,6 +603,11 @@ static int davinci_eth_send_packet (struct eth_device *dev,
 				      EMAC_CPPI_SOP_BIT |
 				      EMAC_CPPI_OWNERSHIP_BIT |
 				      EMAC_CPPI_EOP_BIT);
+
+	flush_dcache_range((unsigned long)packet,
+			(unsigned long)packet + length);
+	davinci_flush_desc(emac_tx_desc);
+
 	/* Send the packet */
 	writel(BD_TO_HW((unsigned long)emac_tx_desc), &adap_emac->TX0HDP);
 
@@ -611,6 +640,8 @@ static int davinci_eth_rcv_packet (struct eth_device *dev)
 	volatile emac_desc *tail_desc;
 	int status, ret = -1;
 
+	davinci_invalidate_rx_descs();
+
 	rx_curr_desc = emac_rx_active_head;
 	status = rx_curr_desc->pkt_flag_len;
 	if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) {
@@ -618,6 +649,9 @@ static int davinci_eth_rcv_packet (struct eth_device *dev)
 			/* Error in packet - discard it and requeue desc */
 			printf ("WARN: emac_rcv_pkt: Error in packet\n");
 		} else {
+			unsigned long tmp = (unsigned long)rx_curr_desc->buffer;
+
+			invalidate_dcache_range(tmp, tmp + EMAC_RXBUF_SIZE);
 			NetReceive (rx_curr_desc->buffer,
 				    (rx_curr_desc->buff_off_len & 0xffff));
 			ret = rx_curr_desc->buff_off_len & 0xffff;
@@ -643,6 +677,7 @@ static int davinci_eth_rcv_packet (struct eth_device *dev)
 		rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
 		rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
 		rx_curr_desc->next = 0;
+		davinci_flush_desc(rx_curr_desc);
 
 		if (emac_rx_active_head == 0) {
 			printf ("INFO: emac_rcv_pkt: active queue head = 0\n");
@@ -660,11 +695,13 @@ static int davinci_eth_rcv_packet (struct eth_device *dev)
 			tail_desc->next = BD_TO_HW((ulong) curr_desc);
 			status = tail_desc->pkt_flag_len;
 			if (status & EMAC_CPPI_EOQ_BIT) {
+				davinci_flush_desc(tail_desc);
 				writel(BD_TO_HW((ulong)curr_desc),
 				       &adap_emac->RX0HDP);
 				status &= ~EMAC_CPPI_EOQ_BIT;
 				tail_desc->pkt_flag_len = status;
 			}
+			davinci_flush_desc(tail_desc);
 		}
 		return (ret);
 	}
diff --git a/drivers/net/davinci_emac.h b/drivers/net/davinci_emac.h
index a0d82ff..9d47303 100644
--- a/drivers/net/davinci_emac.h
+++ b/drivers/net/davinci_emac.h
@@ -28,8 +28,9 @@
 /* Ethernet Min/Max packet size */
 #define EMAC_MIN_ETHERNET_PKT_SIZE	60
 #define EMAC_MAX_ETHERNET_PKT_SIZE	1518
-/* 1518 + 18 = 1536 (packet aligned on 32 byte boundry) */
-#define EMAC_PKT_ALIGN			18
+/* Buffer size (should be aligned on 32 byte and cache line) */
+#define EMAC_RXBUF_SIZE	ALIGN(ALIGN(EMAC_MAX_ETHERNET_PKT_SIZE, 32),\
+				CONFIG_SYS_CACHELINE_SIZE)
 
 /* Number of RX packet buffers
  * NOTE: Only 1 buffer supported as of now
-- 
1.7.6.2



More information about the U-Boot mailing list