Skip to contentSkip to conversation

ARMv7: at91: Enable ICache and DCache for at91 armv7 cpu

PATCH Superseded Josh Wu 2 participants 6 messages May 16, 2014

Subsystems (3)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore

Josh Wu

author
#0 lore raw

cover ARMv7: at91: Enable ICache and DCache for at91 armv7 cpu

First, before we enable DCache. We need add dcache support for macb driver. Then enable ICache/DCache.

Tested on SAMA5D3x-EK board and AT91SAM9M10G45EK.

Josh Wu (2):
net: macb: enable dcache in macb
ARMv7: at91: enable ICache and DCache.

 arch/arm/cpu/armv7/at91/cpu.c       |    6 +++++
 board/atmel/sama5d3xek/sama5d3xek.c |    6 ++++-
 drivers/net/macb.c                  |   51 +++++++++++++++++++++++++++++++++++
 3 files changed, 62 insertions(+), 1 deletion(-)
Signature · 1 line
1.7.9.5
author
#1 lore raw

PATCH 1/2 net: macb: enable dcache in macb

Add to code to flush the dcache after we writing in DMA buffer. Also we need invalidate the dcache before we check the status in the DMA buffer.

Tested in SAMA5D3x-EK with gmac0. Tftp download speed shows in below:
Disable DCache: 1.1 MiB/s
Enable DCache: 1.6 MiB/s
Increase speed with about 40%.

The code should have no impact with the boards which are not enable_dcache().
Tested in AT91SAM9M10G45EK.

---
 drivers/net/macb.c |   51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)
drivers/net/macb.c +51 -0
index 781a272..b18f07b 100644
@@ -194,6 +194,39 @@ int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value)
 }
 #endif
 
+#define	IS_RX	1
+#define	IS_TX	0
+static inline void macb_invalidate_ring_desc(struct macb_device *macb, bool is_rx)
+{
+	if (is_rx)
+		invalidate_dcache_range(macb->rx_ring_dma, macb->rx_ring_dma +
+			CONFIG_SYS_MACB_RX_RING_SIZE * sizeof(struct macb_dma_desc));
+	else
+		invalidate_dcache_range(macb->tx_ring_dma, macb->tx_ring_dma +
+			CONFIG_SYS_MACB_TX_RING_SIZE * sizeof(struct macb_dma_desc));
+}
+
+static inline void macb_flush_ring_desc(struct macb_device *macb, bool is_rx)
+{
+	if (is_rx)
+		flush_dcache_range(macb->rx_ring_dma, macb->rx_ring_dma +
+			CONFIG_SYS_MACB_RX_RING_SIZE * sizeof(struct macb_dma_desc));
+	else
+		flush_dcache_range(macb->tx_ring_dma, macb->tx_ring_dma +
+			CONFIG_SYS_MACB_TX_RING_SIZE * sizeof(struct macb_dma_desc));
+}
+
+static inline void macb_flush_rx_buffer(struct macb_device *macb)
+{
+	flush_dcache_range(macb->rx_buffer_dma,
+		macb->rx_buffer_dma + CONFIG_SYS_MACB_RX_BUFFER_SIZE);
+}
+
+static inline void macb_invalidate_rx_buffer(struct macb_device *macb)
+{
+	invalidate_dcache_range(macb->rx_buffer_dma,
+		macb->rx_buffer_dma + CONFIG_SYS_MACB_RX_BUFFER_SIZE);
+}
 
 #if defined(CONFIG_CMD_NET)
 
@@ -217,6 +250,9 @@ static int macb_send(struct eth_device *netdev, void *packet, int length)
 	macb->tx_ring[tx_head].ctrl = ctrl;
 	macb->tx_ring[tx_head].addr = paddr;
 	barrier();
+	macb_flush_ring_desc(macb, IS_TX);
+	/* Do we need check paddr and length is dcache line aligned? */
+	flush_dcache_range(paddr, paddr + length);
 	macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART));
 
 	/*
@@ -225,6 +261,7 @@ static int macb_send(struct eth_device *netdev, void *packet, int length)
 	 */
 	for (i = 0; i <= CONFIG_SYS_MACB_TX_TIMEOUT; i++) {
 		barrier();
+		macb_invalidate_ring_desc(macb, IS_TX);
 		ctrl = macb->tx_ring[tx_head].ctrl;
 		if (ctrl & TXBUF_USED)
 			break;
@@ -253,6 +290,8 @@ static void reclaim_rx_buffers(struct macb_device *macb,
 	unsigned int i;
 
 	i = macb->rx_tail;
+
+	macb_invalidate_ring_desc(macb, IS_RX);
 	while (i > new_tail) {
 		macb->rx_ring[i].addr &= ~RXADDR_USED;
 		i++;
@@ -266,6 +305,7 @@ static void reclaim_rx_buffers(struct macb_device *macb,
 	}
 
 	barrier();
+	macb_flush_ring_desc(macb, IS_RX);
 	macb->rx_tail = new_tail;
 }
 
@@ -279,6 +319,8 @@ static int macb_recv(struct eth_device *netdev)
 	u32 status;
 
 	for (;;) {
+		macb_invalidate_ring_desc(macb, IS_RX);
+
 		if (!(macb->rx_ring[rx_tail].addr & RXADDR_USED))
 			return -1;
 
@@ -292,6 +334,8 @@ static int macb_recv(struct eth_device *netdev)
 		if (status & RXBUF_FRAME_END) {
 			buffer = macb->rx_buffer + 128 * macb->rx_tail;
 			length = status & RXBUF_FRMLEN_MASK;
+
+			macb_invalidate_rx_buffer(macb);
 			if (wrapped) {
 				unsigned int headlen, taillen;
 
@@ -506,6 +550,9 @@ static int macb_init(struct eth_device *netdev, bd_t *bd)
 		macb->rx_ring[i].ctrl = 0;
 		paddr += 128;
 	}
+	macb_flush_ring_desc(macb, IS_RX);
+	macb_flush_rx_buffer(macb);
+
 	for (i = 0; i < CONFIG_SYS_MACB_TX_RING_SIZE; i++) {
 		macb->tx_ring[i].addr = 0;
 		if (i == (CONFIG_SYS_MACB_TX_RING_SIZE - 1))
@@ -513,6 +560,8 @@ static int macb_init(struct eth_device *netdev, bd_t *bd)
 		else
 			macb->tx_ring[i].ctrl = TXBUF_USED;
 	}
+	macb_flush_ring_desc(macb, IS_TX);
+
 	macb->rx_tail = macb->tx_head = macb->tx_tail = 0;
 
 	macb_writel(macb, RBQP, macb->rx_ring_dma);
@@ -663,6 +712,8 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr)
 					   * sizeof(struct macb_dma_desc),
 					   &macb->tx_ring_dma);
 
+	/* TODO: we need check the rx/tx_ring_dma is dcache line aligned */
+
 	macb->regs = regs;
 	macb->phy_addr = phy_addr;
 
Signature · 1 line
1.7.9.5
author
#2 lore raw

PATCH 2/2 ARMv7: at91: enable ICache and DCache.

In reply to Josh Wu

As SAMA5D3 is a at91 ARMv7 cpu, so we should enable LCD DCache flush for SAMA5D3X-EK.

---
 arch/arm/cpu/armv7/at91/cpu.c       |    6 ++++++
 board/atmel/sama5d3xek/sama5d3xek.c |    6 +++++-
 2 files changed, 11 insertions(+), 1 deletion(-)
arch/arm/cpu/armv7/at91/cpu.c +6 -0
index 2fbf60d..6f2164f 100644
@@ -61,6 +61,12 @@ int print_cpuinfo(void)
 
 void enable_caches(void)
 {
+#ifndef CONFIG_SYS_ICACHE_OFF
+	icache_enable();
+#endif
+#ifndef CONFIG_SYS_DCACHE_OFF
+	dcache_enable();
+#endif
 }
 
 unsigned int get_chip_id(void)
board/atmel/sama5d3xek/sama5d3xek.c +5 -1
index c835c12..1fc91d9 100644
@@ -200,8 +200,12 @@ int board_init(void)
 		at91_gmac_hw_init();
 #endif
 #ifdef CONFIG_LCD
-	if (has_lcdc())
+	if (has_lcdc()) {
 		sama5d3xek_lcd_hw_init();
+
+		/* Enable flushing as we enabled dcache */
+		lcd_set_flush_dcache(1);
+	}
 #endif
 	return 0;
 }
Signature · 1 line
1.7.9.5
#3 lore raw

PATCH 2/2 ARMv7: at91: enable ICache and DCache.

Hi Josh,

Quoted 14 lines · Josh Wu

As SAMA5D3 is a at91 ARMv7 cpu, so we should enable LCD DCache flush for SAMA5D3X-EK.

---
  arch/arm/cpu/armv7/at91/cpu.c       |    6 ++++++
  board/atmel/sama5d3xek/sama5d3xek.c |    6 +++++-
  2 files changed, 11 insertions(+), 1 deletion(-)
arch/arm/cpu/armv7/at91/cpu.c +0 -0
index 2fbf60d..6f2164f 100644

arch/arm/cpu/armv7/at91/cpu.c int print_cpuinfo(void) · line 66

Quoted 6 lines
arch/arm/cpu/armv7/at91/cpu.c +3 -0
@@ -61,6 +61,12 @@ int print_cpuinfo(void)
 
  void enable_caches(void)
  {
+#ifndef CONFIG_SYS_ICACHE_OFF
+	icache_enable();
+#endif

No need this one. Ifdef CONFIG_SYS_ICACHE_OFF, it will be disabled.

Quoted 11 lines
arch/arm/cpu/armv7/at91/cpu.c +3 -0
+#ifndef CONFIG_SYS_DCACHE_OFF
+	dcache_enable();
+#endif
  }
 
  unsigned int get_chip_id(void)
board/atmel/sama5d3xek/sama5d3xek.c +0 -0
index c835c12..1fc91d9 100644

board/atmel/sama5d3xek/sama5d3xek.c int board_init(void) · line 207

Quoted 9 lines
board/atmel/sama5d3xek/sama5d3xek.c +4 -1
@@ -200,8 +200,12 @@ int board_init(void)
  		at91_gmac_hw_init();
  #endif
  #ifdef CONFIG_LCD
-	if (has_lcdc())
+	if (has_lcdc()) {
  		sama5d3xek_lcd_hw_init();
+
+		/* Enable flushing as we enabled dcache */
+		lcd_set_flush_dcache(1);

Why not implement in driver, or else, each SoC enable dcache will need add this.

board/atmel/sama5d3xek/sama5d3xek.c int board_init(void) · line 211

Quoted 5 lines
board/atmel/sama5d3xek/sama5d3xek.c +1 -0
+	}
  #endif
  	return 0;
  }

Best Regards,
Bo Shen

author
#4 lore raw

PATCH 2/2 ARMv7: at91: enable ICache and DCache.

Hi, Bo

Thanks for the review ;-)

Quoted 19 lines · Bo Shen

Hi Josh,

Quoted 16 lines · Josh Wu

As SAMA5D3 is a at91 ARMv7 cpu, so we should enable LCD DCache flush for SAMA5D3X-EK.

---
  arch/arm/cpu/armv7/at91/cpu.c       |    6 ++++++
  board/atmel/sama5d3xek/sama5d3xek.c |    6 +++++-
  2 files changed, 11 insertions(+), 1 deletion(-)
arch/arm/cpu/armv7/at91/cpu.c +0 -0
index 2fbf60d..6f2164f 100644
@@ -61,6 +61,12 @@ int print_cpuinfo(void)
 
Quoted 7 lines

arch/arm/cpu/armv7/at91/cpu.c int print_cpuinfo(void) · line 66

Quoted 5 lines
arch/arm/cpu/armv7/at91/cpu.c +3 -0
  void enable_caches(void)
  {
+#ifndef CONFIG_SYS_ICACHE_OFF
+    icache_enable();
+#endif

No need this one. Ifdef CONFIG_SYS_ICACHE_OFF, it will be disabled.

ok, good. I will remove this #if.

Quoted 4 lines

arch/arm/cpu/armv7/at91/cpu.c int print_cpuinfo(void) · line 69

Quoted 4 lines
arch/arm/cpu/armv7/at91/cpu.c +3 -0
+#ifndef CONFIG_SYS_DCACHE_OFF
+    dcache_enable();
+#endif

This will be removed too.

Quoted 13 lines
Quoted 13 lines
arch/arm/cpu/armv7/at91/cpu.c +0 -0
  }
 
  unsigned int get_chip_id(void)
board/atmel/sama5d3xek/sama5d3xek.c +0 -1
index c835c12..1fc91d9 100644
@@ -200,8 +200,12 @@ int board_init(void)
          at91_gmac_hw_init();
  #endif
  #ifdef CONFIG_LCD
-    if (has_lcdc())
Quoted 8 lines

board/atmel/sama5d3xek/sama5d3xek.c int board_init(void) · line 207

Quoted 5 lines
board/atmel/sama5d3xek/sama5d3xek.c +4 -0
+    if (has_lcdc()) {
          sama5d3xek_lcd_hw_init();
+
+        /* Enable flushing as we enabled dcache */
+        lcd_set_flush_dcache(1);

Why not implement in driver, or else, each SoC enable dcache will need add this.

hmm, the thing is some at91 board, for example at91sam9x5ek board, not defined CONFIG_SYS_DCACHE_OFF, that means DCache is enabled. But actually it doesn't implement dcache_enable().
In above situation, if we implement it in driver, I can't tell whether dcache is really enabled or not.
For this reason, I manually call lcd_set_flush_dcache(1) in the board file. In the future if all boards (use hlcd driver) enabled dcache I will move this function to hlcd driver.

Best Regards,
Josh Wu

Quoted 10 lines

board/atmel/sama5d3xek/sama5d3xek.c int board_init(void) · line 211

Quoted 6 lines
board/atmel/sama5d3xek/sama5d3xek.c +1 -0
+    }
  #endif
      return 0;
  }

Best Regards,
Bo Shen

#5 lore raw

PATCH 2/2 ARMv7: at91: enable ICache and DCache.

Hi Josh,

Quoted 19 lines · Josh Wu
Quoted 10 lines
Quoted 10 lines
board/atmel/sama5d3xek/sama5d3xek.c +0 -1
index c835c12..1fc91d9 100644
@@ -200,8 +200,12 @@ int board_init(void)
          at91_gmac_hw_init();
  #endif
  #ifdef CONFIG_LCD
-    if (has_lcdc())
Quoted 8 lines

board/atmel/sama5d3xek/sama5d3xek.c int board_init(void) · line 207

Quoted 5 lines
board/atmel/sama5d3xek/sama5d3xek.c +4 -0
+    if (has_lcdc()) {
          sama5d3xek_lcd_hw_init();
+
+        /* Enable flushing as we enabled dcache */
+        lcd_set_flush_dcache(1);

Why not implement in driver, or else, each SoC enable dcache will need add this.

Quoted 8 lines

hmm, the thing is some at91 board, for example at91sam9x5ek board, not defined CONFIG_SYS_DCACHE_OFF, that means DCache is enabled. But actually it doesn't implement dcache_enable().
In above situation, if we implement it in driver, I can't tell whether dcache is really enabled or not.
For this reason, I manually call lcd_set_flush_dcache(1) in the board file. In the future if all boards (use hlcd driver) enabled dcache I will move this function to hlcd driver.

I don't see any issue to implement this in driver, may be I am wrong? Can you figure out what issue you met?

Btw, if there is really have issues, can make this condition with CONFIG_SYS_DCACHE_OFF?

Quoted 2 lines

Best Regards,
Josh Wu

Best Regards,
Bo Shen