From 0628019c2cb08dce06a128eef162bbe3e9ba0c8b Mon Sep 17 00:00:00 2001 From: David Sidrane Date: Wed, 13 Jul 2022 11:01:49 -0700 Subject: [PATCH] imxrt:Enet ensure proper dcache for Writeback mode Use aligned_data added proper handeling for Writeback --- arch/arm/src/imxrt/imxrt_enet.c | 112 +++++++++++++++++--------------- 1 file changed, 58 insertions(+), 54 deletions(-) diff --git a/arch/arm/src/imxrt/imxrt_enet.c b/arch/arm/src/imxrt/imxrt_enet.c index f9d3838939..07f52752a2 100644 --- a/arch/arm/src/imxrt/imxrt_enet.c +++ b/arch/arm/src/imxrt/imxrt_enet.c @@ -154,28 +154,6 @@ # error "Need at least one RX buffer" #endif -#define NENET_NBUFFERS \ - (CONFIG_IMXRT_ENET_NTXBUFFERS + CONFIG_IMXRT_ENET_NRXBUFFERS) - -/* Normally you would clean the cache after writing new values to the DMA - * memory so assure that the dirty cache lines are flushed to memory - * before the DMA occurs. And you would invalid the cache after a data is - * received via DMA so that you fetch the actual content of the data from - * the cache. - * - * These conditions are not fully supported here. If the write-throuch - * D-Cache is enabled, however, then many of these issues go away: The - * cache clean operation does nothing (because there are not dirty cache - * lines) and the cache invalid operation is innocuous (because there are - * never dirty cache lines to be lost; valid data will always be reloaded). - * - * At present, we simply insist that write through cache be enabled. - */ - -#if defined(CONFIG_ARMV7M_DCACHE) && !defined(CONFIG_ARMV7M_DCACHE_WRITETHROUGH) -# error Write back D-Cache not yet supported -#endif - /* Align assuming that the D-Cache is enabled (probably 32-bytes). * * REVISIT: The size of descriptors and buffers must also be in even units @@ -190,6 +168,14 @@ #define ENET_ALIGN_MASK (ENET_ALIGN - 1) #define ENET_ALIGN_UP(n) (((n) + ENET_ALIGN_MASK) & ~ENET_ALIGN_MASK) +#define DESC_SIZE sizeof(struct enet_desc_s) +#define DESC_PADSIZE ENET_ALIGN_UP(DESC_SIZE) + +#define ALIGNED_BUFSIZE ENET_ALIGN_UP(CONFIG_NET_ETH_PKTSIZE + \ + CONFIG_NET_GUARDSIZE) +#define NENET_NBUFFERS \ + (CONFIG_IMXRT_ENET_NTXBUFFERS + CONFIG_IMXRT_ENET_NRXBUFFERS) + /* TX timeout = 1 minute */ #define IMXRT_TXTIMEOUT (60 * CLK_TCK) @@ -300,9 +286,6 @@ #define BUF ((struct eth_hdr_s *)priv->dev.d_buf) -#define IMXRT_BUF_SIZE ENET_ALIGN_UP(CONFIG_NET_ETH_PKTSIZE + \ - CONFIG_NET_GUARDSIZE) - /**************************************************************************** * Private Types ****************************************************************************/ @@ -331,27 +314,31 @@ struct imxrt_driver_s struct net_driver_s dev; /* Interface understood by the network */ }; +/* This union type forces the allocated size of TX&RX descriptors to be + * padded to a exact multiple of the Cortex-M7 D-Cache line size. + */ + +union enet_desc_u +{ + uint8_t pad[DESC_PADSIZE]; + struct enet_desc_s desc; +}; + /**************************************************************************** * Private Data ****************************************************************************/ static struct imxrt_driver_s g_enet[CONFIG_IMXRT_ENET_NETHIFS]; -/* The DMA descriptors. A unaligned uint8_t is used to allocate the - * memory; 16 is added to assure that we can meet the descriptor alignment - * requirements. - */ +/* The DMA descriptors */ -static uint8_t g_desc_pool[NENET_NBUFFERS * sizeof(struct enet_desc_s)] - aligned_data(ENET_ALIGN); +static union enet_desc_u g_desc_pool[NENET_NBUFFERS] + aligned_data(ENET_ALIGN); -/* The DMA buffers. Again, A unaligned uint8_t is used to allocate the - * memory; 16 is added to assure that we can meet the descriptor alignment - * requirements. - */ +/* The DMA buffers */ -static uint8_t g_buffer_pool[NENET_NBUFFERS * IMXRT_BUF_SIZE] - aligned_data(ENET_ALIGN); +static uint8_t g_buffer_pool[NENET_NBUFFERS][ALIGNED_BUFSIZE] + aligned_data(ENET_ALIGN); /**************************************************************************** * Private Function Prototypes @@ -359,12 +346,12 @@ static uint8_t g_buffer_pool[NENET_NBUFFERS * IMXRT_BUF_SIZE] /* Utility functions */ -static inline uint32_t imxrt_enet_getreg32(FAR struct imxrt_driver_s *priv, +static inline uint32_t imxrt_enet_getreg32(struct imxrt_driver_s *priv, uint32_t offset); -static inline void imxrt_enet_putreg32(FAR struct imxrt_driver_s *priv, +static inline void imxrt_enet_putreg32(struct imxrt_driver_s *priv, uint32_t value, uint32_t offset); -static inline void imxrt_enet_modifyreg32(FAR struct imxrt_driver_s *priv, +static inline void imxrt_enet_modifyreg32(struct imxrt_driver_s *priv, unsigned int offset, uint32_t clearbits, uint32_t setbits); @@ -461,8 +448,8 @@ static void imxrt_reset(struct imxrt_driver_s *priv); * ****************************************************************************/ -static inline uint32_t -imxrt_enet_getreg32(FAR struct imxrt_driver_s *priv, uint32_t offset) +static inline uint32_t imxrt_enet_getreg32(struct imxrt_driver_s *priv, + uint32_t offset) { return getreg32(priv->base + offset); } @@ -484,7 +471,7 @@ imxrt_enet_getreg32(FAR struct imxrt_driver_s *priv, uint32_t offset) * ****************************************************************************/ -static inline void imxrt_enet_modifyreg32(FAR struct imxrt_driver_s *priv, +static inline void imxrt_enet_modifyreg32(struct imxrt_driver_s *priv, unsigned int offset, uint32_t clearbits, uint32_t setbits) @@ -508,7 +495,7 @@ static inline void imxrt_enet_modifyreg32(FAR struct imxrt_driver_s *priv, * ****************************************************************************/ -static inline void imxrt_enet_putreg32(FAR struct imxrt_driver_s *priv, +static inline void imxrt_enet_putreg32(struct imxrt_driver_s *priv, uint32_t value, uint32_t offset) { putreg32(value, priv->base + offset); @@ -666,18 +653,31 @@ static int imxrt_transmit(struct imxrt_driver_s *priv) buf = (uint8_t *)imxrt_swap32((uint32_t)priv->dev.d_buf); + struct enet_desc_s *rxdesc = &priv->rxdesc[priv->rxtail]; + + up_invalidate_dcache((uintptr_t)rxdesc, + (uintptr_t)rxdesc + sizeof(struct enet_desc_s)); + + if (rxdesc->data == buf) + { /* Data was written into the RX buffer, so swap the TX and RX buffers */ DEBUGASSERT((rxdesc->status1 & RXDESC_E) == 0); rxdesc->data = txdesc->data; txdesc->data = buf; + up_clean_dcache((uintptr_t)rxdesc, + (uintptr_t)rxdesc + sizeof(struct enet_desc_s)); } else { DEBUGASSERT(txdesc->data == buf); } - /* Make the following operations atomic */ + up_clean_dcache((uintptr_t)txdesc, + (uintptr_t)txdesc + sizeof(struct enet_desc_s)); + + up_clean_dcache((uintptr_t)priv->dev.d_buf, + (uintptr_t)priv->dev.d_buf + priv->dev.d_len); /* Start the TX transfer (if it was not already waiting for buffers) */ @@ -989,6 +989,9 @@ static void imxrt_receive(struct imxrt_driver_s *priv) imxrt_swap32((uint32_t)priv->txdesc[priv->txhead].data); rxdesc->status1 |= RXDESC_E; + up_clean_dcache((uintptr_t)rxdesc, + (uintptr_t)rxdesc + sizeof(struct enet_desc_s)); + /* Update the index to the next descriptor */ priv->rxtail++; @@ -1223,8 +1226,8 @@ static void imxrt_enet_interrupt_work(void *arg) static int imxrt_enet_interrupt(int irq, void *context, void *arg) { - register FAR struct imxrt_driver_s *priv = - (FAR struct imxrt_driver_s *) arg; + register struct imxrt_driver_s *priv = + (struct imxrt_driver_s *)arg; /* Disable further Ethernet interrupts. Because Ethernet interrupts are * also disabled if the TX timeout event occurs, there can be no race @@ -1393,7 +1396,7 @@ static int imxrt_ifup_action(struct net_driver_s *dev, bool resetphy) /* Set the RX buffer size */ - imxrt_enet_putreg32(priv, IMXRT_BUF_SIZE, IMXRT_ENET_MRBR_OFFSET); + imxrt_enet_putreg32(priv, ALIGNED_BUFSIZE, IMXRT_ENET_MRBR_OFFSET); /* Point to the start of the circular RX buffer descriptor queue */ @@ -2419,13 +2422,11 @@ static void imxrt_initbuffers(struct imxrt_driver_s *priv) /* Get an aligned TX descriptor (array) address */ - addr = (uintptr_t)g_desc_pool; - priv->txdesc = (struct enet_desc_s *)addr; + priv->txdesc = &g_desc_pool[0].desc; /* Get an aligned RX descriptor (array) address */ - addr += CONFIG_IMXRT_ENET_NTXBUFFERS * sizeof(struct enet_desc_s); - priv->rxdesc = (struct enet_desc_s *)addr; + priv->rxdesc = &g_desc_pool[CONFIG_IMXRT_ENET_NTXBUFFERS].desc; /* Get the beginning of the first aligned buffer */ @@ -2441,7 +2442,7 @@ static void imxrt_initbuffers(struct imxrt_driver_s *priv) #ifdef CONFIG_IMXRT_ENETENHANCEDBD priv->txdesc[i].status2 = TXDESC_IINS | TXDESC_PINS; #endif - addr += IMXRT_BUF_SIZE; + addr += ALIGNED_BUFSIZE; } /* Then fill in the RX descriptors */ @@ -2455,7 +2456,7 @@ static void imxrt_initbuffers(struct imxrt_driver_s *priv) priv->rxdesc[i].bdu = 0; priv->rxdesc[i].status2 = RXDESC_INT; #endif - addr += IMXRT_BUF_SIZE; + addr += ALIGNED_BUFSIZE; } /* Set the wrap bit in the last descriptors to form a ring */ @@ -2463,6 +2464,9 @@ static void imxrt_initbuffers(struct imxrt_driver_s *priv) priv->txdesc[CONFIG_IMXRT_ENET_NTXBUFFERS - 1].status1 |= TXDESC_W; priv->rxdesc[CONFIG_IMXRT_ENET_NRXBUFFERS - 1].status1 |= RXDESC_W; + up_clean_dcache((uintptr_t)g_desc_pool, + (uintptr_t)g_desc_pool + sizeof(g_desc_pool)); + /* We start with RX descriptor 0 and with no TX descriptors in use */ priv->txtail = 0;