[U-Boot] [PATCH] net/designware: make driver compatible with data cache

Alexey Brodkin Alexey.Brodkin at synopsys.com
Tue Dec 24 12:46:55 CET 2013


Up until now this driver only worked with data cache disabled.
To make it work with enabled data cache following changes were required:

 * Implement all accesses to shared structures between CPU and GMAC via
uncached reads/writes ("readl"/"writel").
 * Flush cache for data passed from CPU to GMAC
 * Invalidate cache for data passed from GMAC to CPU

I tried to implement items above keeping as much code unchanged as
possible. So logic of operation is kept as it is.

Signed-off-by: Alexey Brodkin <abrodkin at synopsys.com>

Cc: Joe Hershberger <joe.hershberger at ni.com>
Cc: Vipin Kumar <vipin.kumar at st.com>
Cc: Stefan Roese <sr at denx.de>
Cc: Mischa Jonker <mjonker at synopsys.com>
---
 drivers/net/designware.c | 91 ++++++++++++++++++++++++++++++------------------
 1 file changed, 58 insertions(+), 33 deletions(-)

diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 22155b4..04ae02c 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -30,26 +30,30 @@ static void tx_descs_init(struct eth_device *dev)
 
 	for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) {
 		desc_p = &desc_table_p[idx];
-		desc_p->dmamac_addr = &txbuffs[idx * CONFIG_ETH_BUFSIZE];
-		desc_p->dmamac_next = &desc_table_p[idx + 1];
+		writel(&txbuffs[idx * CONFIG_ETH_BUFSIZE],
+		       &desc_p->dmamac_addr);
+		writel(&desc_table_p[idx + 1], &desc_p->dmamac_next);
 
 #if defined(CONFIG_DW_ALTDESCRIPTOR)
-		desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST |
-				DESC_TXSTS_TXFIRST | DESC_TXSTS_TXCRCDIS | \
-				DESC_TXSTS_TXCHECKINSCTRL | \
-				DESC_TXSTS_TXRINGEND | DESC_TXSTS_TXPADDIS);
-
-		desc_p->txrx_status |= DESC_TXSTS_TXCHAIN;
-		desc_p->dmamac_cntl = 0;
-		desc_p->txrx_status &= ~(DESC_TXSTS_MSK | DESC_TXSTS_OWNBYDMA);
+		writel(readl(&desc_p->txrx_status) & ~(DESC_TXSTS_TXINT |
+		       DESC_TXSTS_TXLAST | DESC_TXSTS_TXFIRST |
+		       DESC_TXSTS_TXCRCDIS | DESC_TXSTS_TXCHECKINSCTRL |
+		       DESC_TXSTS_TXRINGEND | DESC_TXSTS_TXPADDIS),
+		       &desc_p->txrx_status);
+
+		writel(readl(&desc_p->txrx_status) | DESC_TXSTS_TXCHAIN,
+		       &desc_p->txrx_status);
+		writel(0, &desc_p->dmamac_cntl);
+		writel(readl(&desc_p->txrx_status) & ~(DESC_TXSTS_MSK |
+		       DESC_TXSTS_OWNBYDMA), &desc_p->txrx_status);
 #else
-		desc_p->dmamac_cntl = DESC_TXCTRL_TXCHAIN;
-		desc_p->txrx_status = 0;
+		writel(DESC_TXCTRL_TXCHAIN, &desc_p->dmamac_cntl);
+		writel(0, &desc_p->txrx_status);
 #endif
 	}
 
 	/* Correcting the last pointer of the chain */
-	desc_p->dmamac_next = &desc_table_p[0];
+	writel(&desc_table_p[0], &desc_p->dmamac_next);
 
 	writel((ulong)&desc_table_p[0], &dma_p->txdesclistaddr);
 }
@@ -63,20 +67,30 @@ static void rx_descs_init(struct eth_device *dev)
 	struct dmamacdescr *desc_p;
 	u32 idx;
 
+	/* Before passing buffers to GMAC we need to make sure zeros
+	 * written there right after "priv" structure allocation were
+	 * flushed into RAM.
+	 * Otherwise there's a chance to get some of them flushed in RAM when
+	 * GMAC is already pushing data to RAM via DMA. This way incoming from
+	 * GMAC data will be corrupted. */
+	flush_dcache_range((unsigned int)rxbuffs, (unsigned int)rxbuffs +
+			   RX_TOTAL_BUFSIZE);
+
 	for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) {
 		desc_p = &desc_table_p[idx];
-		desc_p->dmamac_addr = &rxbuffs[idx * CONFIG_ETH_BUFSIZE];
-		desc_p->dmamac_next = &desc_table_p[idx + 1];
 
-		desc_p->dmamac_cntl =
-			(MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) | \
-				      DESC_RXCTRL_RXCHAIN;
+		writel(&rxbuffs[idx * CONFIG_ETH_BUFSIZE],
+		       &desc_p->dmamac_addr);
+		writel(&desc_table_p[idx + 1], &desc_p->dmamac_next);
+
+		writel((MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) |
+		       DESC_RXCTRL_RXCHAIN, &desc_p->dmamac_cntl);
 
-		desc_p->txrx_status = DESC_RXSTS_OWNBYDMA;
+		writel(DESC_RXSTS_OWNBYDMA, &desc_p->txrx_status);
 	}
 
 	/* Correcting the last pointer of the chain */
-	desc_p->dmamac_next = &desc_table_p[0];
+	writel(&desc_table_p[0], &desc_p->dmamac_next);
 
 	writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr);
 }
@@ -198,26 +212,32 @@ static int dw_eth_send(struct eth_device *dev, void *packet, int length)
 	struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num];
 
 	/* Check if the descriptor is owned by CPU */
-	if (desc_p->txrx_status & DESC_TXSTS_OWNBYDMA) {
+	if (readl(&desc_p->txrx_status) & DESC_TXSTS_OWNBYDMA) {
 		printf("CPU not owner of tx frame\n");
 		return -1;
 	}
 
 	memcpy((void *)desc_p->dmamac_addr, packet, length);
 
-#if defined(CONFIG_DW_ALTDESCRIPTOR)
-	desc_p->txrx_status |= DESC_TXSTS_TXFIRST | DESC_TXSTS_TXLAST;
-	desc_p->dmamac_cntl |= (length << DESC_TXCTRL_SIZE1SHFT) & \
-			       DESC_TXCTRL_SIZE1MASK;
+	flush_dcache_range((unsigned long)desc_p->dmamac_addr,
+			   (unsigned long)desc_p->dmamac_addr + length);
 
-	desc_p->txrx_status &= ~(DESC_TXSTS_MSK);
-	desc_p->txrx_status |= DESC_TXSTS_OWNBYDMA;
+#if defined(CONFIG_DW_ALTDESCRIPTOR)
+	writel(readl(&desc_p->txrx_status) | DESC_TXSTS_TXFIRST |
+	       DESC_TXSTS_TXLAST, &desc_p->txrx_status);
+	writel(readl(&desc_p->dmamac_cntl) | (length << DESC_TXCTRL_SIZE1SHFT) &
+	       DESC_TXCTRL_SIZE1MASK, &desc_p->dmamac_cntl);
+
+	writel(readl(&desc_p->txrx_status) & ~DESC_TXSTS_MSK,
+	       &desc_p->txrx_status);
+	writel(readl(&desc_p->txrx_status) | DESC_TXSTS_OWNBYDMA,
+	       &desc_p->txrx_status);
 #else
-	desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) & \
-			       DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST | \
-			       DESC_TXCTRL_TXFIRST;
+	writel(readl(&desc_p->dmamac_cntl) |
+	       ((length << DESC_TXCTRL_SIZE1SHFT) & DESC_TXCTRL_SIZE1MASK) |
+	       DESC_TXCTRL_TXLAST | DESC_TXCTRL_TXFIRST, &desc_p->dmamac_cntl);
 
-	desc_p->txrx_status = DESC_TXSTS_OWNBYDMA;
+	writel(DESC_TXSTS_OWNBYDMA, &desc_p->txrx_status);
 #endif
 
 	/* Test the wrap-around condition. */
@@ -238,7 +258,7 @@ static int dw_eth_recv(struct eth_device *dev)
 	u32 desc_num = priv->rx_currdescnum;
 	struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
 
-	u32 status = desc_p->txrx_status;
+	u32 status = readl(&desc_p->txrx_status);
 	int length = 0;
 
 	/* Check  if the owner is the CPU */
@@ -247,13 +267,18 @@ static int dw_eth_recv(struct eth_device *dev)
 		length = (status & DESC_RXSTS_FRMLENMSK) >> \
 			 DESC_RXSTS_FRMLENSHFT;
 
+		invalidate_dcache_range((unsigned long)desc_p->dmamac_addr,
+					(unsigned long)desc_p->dmamac_addr +
+					length);
+
 		NetReceive(desc_p->dmamac_addr, length);
 
 		/*
 		 * Make the current descriptor valid again and go to
 		 * the next one
 		 */
-		desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA;
+		writel(readl(&desc_p->txrx_status) | DESC_RXSTS_OWNBYDMA,
+		       &desc_p->txrx_status);
 
 		/* Test the wrap-around condition. */
 		if (++desc_num >= CONFIG_RX_DESCR_NUM)
-- 
1.8.4.2



More information about the U-Boot mailing list