From ad4b87e24aa28f8cf0356934e32c1e1a36257aab Mon Sep 17 00:00:00 2001 From: "Sergio R. Caprile" Date: Tue, 6 Jan 2026 14:36:40 -0300 Subject: [PATCH] Synopsys driver handles STM32H7 and N6 DCACHE (proper memory placement required) --- mongoose.c | 131 +++++++++++++++++++++++++++++++++++-------- src/drivers/stm32h.c | 131 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 218 insertions(+), 44 deletions(-) diff --git a/mongoose.c b/mongoose.c index edb3c8f4..748cf757 100644 --- a/mongoose.c +++ b/mongoose.c @@ -25748,8 +25748,26 @@ struct mg_tcpip_driver mg_tcpip_driver_stm32f = { #if MG_ENABLE_TCPIP && (MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN || \ MG_ENABLE_DRIVER_STM32N) // STM32H: vendor modded single-queue Synopsys v4.2 -// STM32N, MCXNx4x: dual-queue Synopsys v5.2 with no hash table option -// RT1170 ENET_QOS: quad-queue Synopsys v5.1 +// STM32N: dual-queue GbE Synopsys v5.2 with no hash table option, 64-bit AXI +// MCXNx4x: dual-queue Synopsys v5.2 with no hash table option +// RT1170: ENET_QOS: quad-queue Synopsys v5.1 +#if MG_ENABLE_DRIVER_STM32H +#define SYNOPSYS_ENET_V5 0 +#define SYNOPSYS_ENET_SINGLEQ 1 +#define SYNOPSYS_ENET_NOHASHTABLE 0 +#define SYNOPSYS_ENET_GbE 0 +#elif MG_ENABLE_DRIVER_STM32N +#define SYNOPSYS_ENET_V5 1 +#define SYNOPSYS_ENET_SINGLEQ 0 +#define SYNOPSYS_ENET_NOHASHTABLE 1 +#define SYNOPSYS_ENET_GbE 1 +#elif MG_ENABLE_DRIVER_MCXN +#define SYNOPSYS_ENET_V5 1 +#define SYNOPSYS_ENET_SINGLEQ 0 +#define SYNOPSYS_ENET_NOHASHTABLE 1 +#define SYNOPSYS_ENET_GbE 0 +#endif + struct synopsys_enet_qos { volatile uint32_t MACCR, MACECR, MACPFR, MACWTR, MACHT0R, MACHT1R, RESERVED1[14], MACVTR, RESERVED2, MACVHTR, RESERVED3, MACVIR, MACIVIR, @@ -25782,25 +25800,84 @@ struct synopsys_enet_qos { }; #undef ETH #if MG_ENABLE_DRIVER_STM32H -#define ETH \ - ((struct synopsys_enet_qos *) (uintptr_t) (0x40000000UL + 0x00020000UL + \ - 0x8000UL)) -#elif MG_ENABLE_DRIVER_MCXN -#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x40100000UL) +#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x40028000UL) #elif MG_ENABLE_DRIVER_STM32N #define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x48036000UL) +#elif MG_ENABLE_DRIVER_MCXN +#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x40100000UL) #endif #define ETH_PKT_SIZE 1540 // Max frame size #define ETH_DESC_CNT 4 // Descriptors count #define ETH_DS 4 // Descriptor size (words) -static volatile uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM - MG_8BYTE_ALIGNED; -static volatile uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM - MG_8BYTE_ALIGNED; -static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_8BYTE_ALIGNED; -static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_8BYTE_ALIGNED; +#if MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_STM32N +#define CACHE_LINESZ 32 // must be a whole number of (d)words (see DESC_SZW) +#ifndef SCB +struct m7_scb { + volatile uint32_t CPUID, RESERVED1[4], CCR, RESERVED2[145], DCIMVAC, DCISW, + DCCMVAU, DCCMVAC, DCCSW, DCCIMVAC, DCCISW, RESERVED3[10], CACR, + RESERVED4[3]; +}; +#define SCB ((struct m7_scb *) (uintptr_t) 0xE000ED00UL) +#endif +// ending ISB is not needed because we don't cache instructions in data space +static inline void MG_CACHE_INVAL(uint8_t *addr, int32_t len) { +#if MG_ENABLE_DRIVER_STM32H + if ((SCB->CPUID & 0xfff0) != 0xc270) return; // not a Cortex-M7 => not an H7 +#endif + if ((SCB->CCR & MG_BIT(16)) == 0) return; // cache not enabled + MG_DSB(); + while (len > 0) { + SCB->DCIMVAC = (uint32_t) addr; + addr += CACHE_LINESZ; + len -= CACHE_LINESZ; + } + MG_DSB(); +} +static inline void MG_CACHE_FLUSH(uint8_t *addr, int32_t len) { +#if MG_ENABLE_DRIVER_STM32H + if ((SCB->CPUID & 0xfff0) != 0xc270) return; // not a Cortex-M7 => not an H7 +#endif + if ((SCB->CCR & MG_BIT(16)) == 0) return; // cache not enabled + MG_DSB(); + while (len > 0) { + SCB->DCCMVAC = (uint32_t) addr; + addr += CACHE_LINESZ; + len -= CACHE_LINESZ; + } + MG_DSB(); +} +#define ETH_RAM_ALIGNED MG_32BYTE_ALIGNED // depends on CACHE_LINESZ and ETH +#define CACHE_ALIGN(x) \ + ((((size_t) (x)) + CACHE_LINESZ - 1) & ~(CACHE_LINESZ - 1)) +#define DESC_SZ CACHE_ALIGN(4 * ETH_DS) // grow descriptors to fit a line +#define DESC_SZW (DESC_SZ / 4) +#define BUFF_SZ CACHE_ALIGN(ETH_PKT_SIZE) // grow buffers to fit n lines +#if MG_ENABLE_DRIVER_STM32H +#define DESC_SKIPW (DESC_SZW - ETH_DS) // tell DMA the descriptor size, words +#else +// MG_ENABLE_DRIVER_STM32N, DMA is AXI and specs skip in 64-bit double-words +#define DESC_SKIPW ((DESC_SZW - ETH_DS) / 2) +#endif +#else +#define MG_CACHE_FLUSH(a, b) +#define MG_CACHE_INVAL(a, b) +#define ETH_RAM_ALIGNED MG_8BYTE_ALIGNED // depends on ETH DMA alone +#define DESC_SZ 0 +#define DESC_SZW ETH_DS +#define BUFF_SZ ETH_PKT_SIZE +#define DESC_SKIPW 0 // no need to skip, as we're not aligning to cache lines +#endif + +// array[rows][cols] = coldata coldata ... for all rows, keeps alignment +static volatile uint32_t s_rxdesc[ETH_DESC_CNT][DESC_SZW] MG_ETH_RAM + ETH_RAM_ALIGNED; +static volatile uint32_t s_txdesc[ETH_DESC_CNT][DESC_SZW] MG_ETH_RAM + ETH_RAM_ALIGNED; +static uint8_t s_rxbuf[ETH_DESC_CNT][BUFF_SZ] MG_ETH_RAM ETH_RAM_ALIGNED; +static uint8_t s_txbuf[ETH_DESC_CNT][BUFF_SZ] MG_ETH_RAM ETH_RAM_ALIGNED; + static struct mg_tcpip_if *s_ifp; // MIP interface static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { @@ -25832,12 +25909,14 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) { s_rxdesc[i][0] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer s_rxdesc[i][3] = MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V } + MG_CACHE_FLUSH((uint8_t *) s_rxdesc, sizeof(s_rxdesc)); // Init TX descriptors memset((char *) s_txdesc, 0, sizeof(s_txdesc)); // manual init for (int i = 0; i < ETH_DESC_CNT; i++) { s_txdesc[i][0] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer } + MG_CACHE_FLUSH((uint8_t *) s_txdesc, sizeof(s_txdesc)); ETH->DMAMR |= MG_BIT(0); // Software reset for (int i = 0; i < 4; i++) @@ -25854,7 +25933,7 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) { ETH->DMASBMR |= MG_BIT(12); // AAL NOTE(scaprile): is this actually needed ETH->MACIER = 0; // Do not enable additional irq sources (reset value) ETH->MACTFCR = MG_BIT(7); // Disable zero-quanta pause -#if MG_ENABLE_DRIVER_STM32H +#if !SYNOPSYS_ENET_V5 ETH->MACPFR = MG_BIT(10); // Perfect filtering #endif struct mg_phy phy = {eth_read_phy, eth_write_phy}; @@ -25870,15 +25949,15 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) { ETH->DMACTDRLR = ETH_DESC_CNT - 1; // ring length ETH->DMACTDTPR = (uint32_t) (uintptr_t) s_txdesc; // first available descriptor address - ETH->DMACCR = 0; // DSL = 0 (contiguous descriptor table) (reset value) -#if !MG_ENABLE_DRIVER_STM32H + ETH->DMACCR = DESC_SKIPW << 18; // DSL (contiguous/sparse descriptor table) +#if SYNOPSYS_ENET_V5 MG_SET_BITS(ETH->DMACTCR, 0x3F << 16, MG_BIT(16)); MG_SET_BITS(ETH->DMACRCR, 0x3F << 16, MG_BIT(16)); #endif ETH->DMACIER = MG_BIT(6) | MG_BIT(15); // RIE, NIE ETH->MACCR = MG_BIT(0) | MG_BIT(1) | MG_BIT(13) | MG_BIT(14) | MG_BIT(15); // RE, TE, Duplex, Fast, (10/100)/Reserved -#if MG_ENABLE_DRIVER_STM32H +#if SYNOPSYS_ENET_SINGLEQ ETH->MTLTQOMR |= MG_BIT(1); // TSF ETH->MTLRQOMR |= MG_BIT(5); // RSF #else @@ -25902,18 +25981,23 @@ static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) { if (len > sizeof(s_txbuf[s_txno])) { MG_ERROR(("Frame too big, %ld", (long) len)); - len = 0; // Frame is too big - } else if ((s_txdesc[s_txno][3] & MG_BIT(31))) { + return 0; // Frame is too big + } + MG_CACHE_INVAL((uint8_t *) &s_txdesc[s_txno], DESC_SZ); + if ((s_txdesc[s_txno][3] & MG_BIT(31))) { ifp->nerr++; MG_ERROR(("No free descriptors: %u %08X %08X %08X", s_txno, s_txdesc[s_txno][3], ETH->DMACSR, ETH->DMACTCR)); + MG_CACHE_INVAL((uint8_t *) s_txdesc, sizeof(s_txdesc)); for (int i = 0; i < ETH_DESC_CNT; i++) MG_ERROR(("%08X", s_txdesc[i][3])); len = 0; // All descriptors are busy, fail } else { - memcpy(s_txbuf[s_txno], buf, len); // Copy data + memcpy(s_txbuf[s_txno], buf, len); // Copy data + MG_CACHE_FLUSH((uint8_t *) &s_txbuf[s_txno], BUFF_SZ); s_txdesc[s_txno][2] = (uint32_t) len; // Set data len s_txdesc[s_txno][3] = MG_BIT(28) | MG_BIT(29); // FD, LD s_txdesc[s_txno][3] |= MG_BIT(31); // Set OWN bit - let DMA take over + MG_CACHE_FLUSH((uint8_t *) &s_txdesc[s_txno], DESC_SZ); if (++s_txno >= ETH_DESC_CNT) s_txno = 0; } ETH->DMACSR |= MG_BIT(2) | MG_BIT(1); // Clear any prior TBU, TPS @@ -25923,7 +26007,7 @@ static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len, } static void mg_tcpip_driver_stm32h_update_hash_table(struct mg_tcpip_if *ifp) { -#if MG_ENABLE_DRIVER_MCXN || MG_ENABLE_DRIVER_STM32N +#if SYNOPSYS_ENET_NOHASHTABLE ETH->MACPFR = MG_BIT(4); // Pass Multicast (pass all multicast frames) #else // TODO(): read database, rebuild hash table @@ -25955,7 +26039,7 @@ static bool mg_tcpip_driver_stm32h_poll(struct mg_tcpip_if *ifp, bool s1) { // if(link is slow or half) set flags otherwise // reg = tmp uint32_t maccr = ETH->MACCR | MG_BIT(14) | MG_BIT(13); // 100M, Full-duplex -#if MG_ENABLE_DRIVER_STM32N +#if SYNOPSYS_ENET_GbE if (speed == MG_PHY_SPEED_1000M) maccr &= ~MG_BIT(15); // 1000M #endif if (speed == MG_PHY_SPEED_10M) maccr &= ~MG_BIT(14); // 10M @@ -25981,6 +26065,7 @@ void ETH1_IRQHandler(void) { if (ETH->DMACSR & MG_BIT(6)) { // Frame received, loop ETH->DMACSR = MG_BIT(15) | MG_BIT(6); // Clear flag for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever + MG_CACHE_INVAL((uint8_t *) &s_rxdesc[s_rxno], DESC_SZ); if (s_rxdesc[s_rxno][3] & MG_BIT(31)) break; // exit when done if (((s_rxdesc[s_rxno][3] & (MG_BIT(28) | MG_BIT(29))) == (MG_BIT(28) | MG_BIT(29))) && @@ -25988,10 +26073,12 @@ void ETH1_IRQHandler(void) { uint32_t len = s_rxdesc[s_rxno][3] & (MG_BIT(15) - 1); // MG_DEBUG(("%lx %lu %lx %08lx", s_rxno, len, s_rxdesc[s_rxno][3], // ETH->DMACSR)); + MG_CACHE_INVAL((uint8_t *) &s_rxbuf[s_rxno], BUFF_SZ); mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp); } s_rxdesc[s_rxno][3] = MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V + MG_CACHE_FLUSH((uint8_t *) &s_rxdesc[s_rxno], DESC_SZ); if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; } } diff --git a/src/drivers/stm32h.c b/src/drivers/stm32h.c index d7267e86..f5f28399 100644 --- a/src/drivers/stm32h.c +++ b/src/drivers/stm32h.c @@ -3,8 +3,26 @@ #if MG_ENABLE_TCPIP && (MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN || \ MG_ENABLE_DRIVER_STM32N) // STM32H: vendor modded single-queue Synopsys v4.2 -// STM32N, MCXNx4x: dual-queue Synopsys v5.2 with no hash table option -// RT1170 ENET_QOS: quad-queue Synopsys v5.1 +// STM32N: dual-queue GbE Synopsys v5.2 with no hash table option, 64-bit AXI +// MCXNx4x: dual-queue Synopsys v5.2 with no hash table option +// RT1170: ENET_QOS: quad-queue Synopsys v5.1 +#if MG_ENABLE_DRIVER_STM32H +#define SYNOPSYS_ENET_V5 0 +#define SYNOPSYS_ENET_SINGLEQ 1 +#define SYNOPSYS_ENET_NOHASHTABLE 0 +#define SYNOPSYS_ENET_GbE 0 +#elif MG_ENABLE_DRIVER_STM32N +#define SYNOPSYS_ENET_V5 1 +#define SYNOPSYS_ENET_SINGLEQ 0 +#define SYNOPSYS_ENET_NOHASHTABLE 1 +#define SYNOPSYS_ENET_GbE 1 +#elif MG_ENABLE_DRIVER_MCXN +#define SYNOPSYS_ENET_V5 1 +#define SYNOPSYS_ENET_SINGLEQ 0 +#define SYNOPSYS_ENET_NOHASHTABLE 1 +#define SYNOPSYS_ENET_GbE 0 +#endif + struct synopsys_enet_qos { volatile uint32_t MACCR, MACECR, MACPFR, MACWTR, MACHT0R, MACHT1R, RESERVED1[14], MACVTR, RESERVED2, MACVHTR, RESERVED3, MACVIR, MACIVIR, @@ -37,25 +55,84 @@ struct synopsys_enet_qos { }; #undef ETH #if MG_ENABLE_DRIVER_STM32H -#define ETH \ - ((struct synopsys_enet_qos *) (uintptr_t) (0x40000000UL + 0x00020000UL + \ - 0x8000UL)) -#elif MG_ENABLE_DRIVER_MCXN -#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x40100000UL) +#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x40028000UL) #elif MG_ENABLE_DRIVER_STM32N #define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x48036000UL) +#elif MG_ENABLE_DRIVER_MCXN +#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x40100000UL) #endif #define ETH_PKT_SIZE 1540 // Max frame size #define ETH_DESC_CNT 4 // Descriptors count #define ETH_DS 4 // Descriptor size (words) -static volatile uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM - MG_8BYTE_ALIGNED; -static volatile uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM - MG_8BYTE_ALIGNED; -static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_8BYTE_ALIGNED; -static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_8BYTE_ALIGNED; +#if MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_STM32N +#define CACHE_LINESZ 32 // must be a whole number of (d)words (see DESC_SZW) +#ifndef SCB +struct m7_scb { + volatile uint32_t CPUID, RESERVED1[4], CCR, RESERVED2[145], DCIMVAC, DCISW, + DCCMVAU, DCCMVAC, DCCSW, DCCIMVAC, DCCISW, RESERVED3[10], CACR, + RESERVED4[3]; +}; +#define SCB ((struct m7_scb *) (uintptr_t) 0xE000ED00UL) +#endif +// ending ISB is not needed because we don't cache instructions in data space +static inline void MG_CACHE_INVAL(uint8_t *addr, int32_t len) { +#if MG_ENABLE_DRIVER_STM32H + if ((SCB->CPUID & 0xfff0) != 0xc270) return; // not a Cortex-M7 => not an H7 +#endif + if ((SCB->CCR & MG_BIT(16)) == 0) return; // cache not enabled + MG_DSB(); + while (len > 0) { + SCB->DCIMVAC = (uint32_t) addr; + addr += CACHE_LINESZ; + len -= CACHE_LINESZ; + } + MG_DSB(); +} +static inline void MG_CACHE_FLUSH(uint8_t *addr, int32_t len) { +#if MG_ENABLE_DRIVER_STM32H + if ((SCB->CPUID & 0xfff0) != 0xc270) return; // not a Cortex-M7 => not an H7 +#endif + if ((SCB->CCR & MG_BIT(16)) == 0) return; // cache not enabled + MG_DSB(); + while (len > 0) { + SCB->DCCMVAC = (uint32_t) addr; + addr += CACHE_LINESZ; + len -= CACHE_LINESZ; + } + MG_DSB(); +} +#define ETH_RAM_ALIGNED MG_32BYTE_ALIGNED // depends on CACHE_LINESZ and ETH +#define CACHE_ALIGN(x) \ + ((((size_t) (x)) + CACHE_LINESZ - 1) & ~(CACHE_LINESZ - 1)) +#define DESC_SZ CACHE_ALIGN(4 * ETH_DS) // grow descriptors to fit a line +#define DESC_SZW (DESC_SZ / 4) +#define BUFF_SZ CACHE_ALIGN(ETH_PKT_SIZE) // grow buffers to fit n lines +#if MG_ENABLE_DRIVER_STM32H +#define DESC_SKIPW (DESC_SZW - ETH_DS) // tell DMA the descriptor size, words +#else +// MG_ENABLE_DRIVER_STM32N, DMA is AXI and specs skip in 64-bit double-words +#define DESC_SKIPW ((DESC_SZW - ETH_DS) / 2) +#endif +#else +#define MG_CACHE_FLUSH(a, b) +#define MG_CACHE_INVAL(a, b) +#define ETH_RAM_ALIGNED MG_8BYTE_ALIGNED // depends on ETH DMA alone +#define DESC_SZ 0 +#define DESC_SZW ETH_DS +#define BUFF_SZ ETH_PKT_SIZE +#define DESC_SKIPW 0 // no need to skip, as we're not aligning to cache lines +#endif + +// array[rows][cols] = coldata coldata ... for all rows, keeps alignment +static volatile uint32_t s_rxdesc[ETH_DESC_CNT][DESC_SZW] MG_ETH_RAM + ETH_RAM_ALIGNED; +static volatile uint32_t s_txdesc[ETH_DESC_CNT][DESC_SZW] MG_ETH_RAM + ETH_RAM_ALIGNED; +static uint8_t s_rxbuf[ETH_DESC_CNT][BUFF_SZ] MG_ETH_RAM ETH_RAM_ALIGNED; +static uint8_t s_txbuf[ETH_DESC_CNT][BUFF_SZ] MG_ETH_RAM ETH_RAM_ALIGNED; + static struct mg_tcpip_if *s_ifp; // MIP interface static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { @@ -87,12 +164,14 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) { s_rxdesc[i][0] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer s_rxdesc[i][3] = MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V } + MG_CACHE_FLUSH((uint8_t *) s_rxdesc, sizeof(s_rxdesc)); // Init TX descriptors memset((char *) s_txdesc, 0, sizeof(s_txdesc)); // manual init for (int i = 0; i < ETH_DESC_CNT; i++) { s_txdesc[i][0] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer } + MG_CACHE_FLUSH((uint8_t *) s_txdesc, sizeof(s_txdesc)); ETH->DMAMR |= MG_BIT(0); // Software reset for (int i = 0; i < 4; i++) @@ -109,7 +188,7 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) { ETH->DMASBMR |= MG_BIT(12); // AAL NOTE(scaprile): is this actually needed ETH->MACIER = 0; // Do not enable additional irq sources (reset value) ETH->MACTFCR = MG_BIT(7); // Disable zero-quanta pause -#if MG_ENABLE_DRIVER_STM32H +#if !SYNOPSYS_ENET_V5 ETH->MACPFR = MG_BIT(10); // Perfect filtering #endif struct mg_phy phy = {eth_read_phy, eth_write_phy}; @@ -125,15 +204,15 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) { ETH->DMACTDRLR = ETH_DESC_CNT - 1; // ring length ETH->DMACTDTPR = (uint32_t) (uintptr_t) s_txdesc; // first available descriptor address - ETH->DMACCR = 0; // DSL = 0 (contiguous descriptor table) (reset value) -#if !MG_ENABLE_DRIVER_STM32H + ETH->DMACCR = DESC_SKIPW << 18; // DSL (contiguous/sparse descriptor table) +#if SYNOPSYS_ENET_V5 MG_SET_BITS(ETH->DMACTCR, 0x3F << 16, MG_BIT(16)); MG_SET_BITS(ETH->DMACRCR, 0x3F << 16, MG_BIT(16)); #endif ETH->DMACIER = MG_BIT(6) | MG_BIT(15); // RIE, NIE ETH->MACCR = MG_BIT(0) | MG_BIT(1) | MG_BIT(13) | MG_BIT(14) | MG_BIT(15); // RE, TE, Duplex, Fast, (10/100)/Reserved -#if MG_ENABLE_DRIVER_STM32H +#if SYNOPSYS_ENET_SINGLEQ ETH->MTLTQOMR |= MG_BIT(1); // TSF ETH->MTLRQOMR |= MG_BIT(5); // RSF #else @@ -157,18 +236,23 @@ static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) { if (len > sizeof(s_txbuf[s_txno])) { MG_ERROR(("Frame too big, %ld", (long) len)); - len = 0; // Frame is too big - } else if ((s_txdesc[s_txno][3] & MG_BIT(31))) { + return 0; // Frame is too big + } + MG_CACHE_INVAL((uint8_t *) &s_txdesc[s_txno], DESC_SZ); + if ((s_txdesc[s_txno][3] & MG_BIT(31))) { ifp->nerr++; MG_ERROR(("No free descriptors: %u %08X %08X %08X", s_txno, s_txdesc[s_txno][3], ETH->DMACSR, ETH->DMACTCR)); + MG_CACHE_INVAL((uint8_t *) s_txdesc, sizeof(s_txdesc)); for (int i = 0; i < ETH_DESC_CNT; i++) MG_ERROR(("%08X", s_txdesc[i][3])); len = 0; // All descriptors are busy, fail } else { - memcpy(s_txbuf[s_txno], buf, len); // Copy data + memcpy(s_txbuf[s_txno], buf, len); // Copy data + MG_CACHE_FLUSH((uint8_t *) &s_txbuf[s_txno], BUFF_SZ); s_txdesc[s_txno][2] = (uint32_t) len; // Set data len s_txdesc[s_txno][3] = MG_BIT(28) | MG_BIT(29); // FD, LD s_txdesc[s_txno][3] |= MG_BIT(31); // Set OWN bit - let DMA take over + MG_CACHE_FLUSH((uint8_t *) &s_txdesc[s_txno], DESC_SZ); if (++s_txno >= ETH_DESC_CNT) s_txno = 0; } ETH->DMACSR |= MG_BIT(2) | MG_BIT(1); // Clear any prior TBU, TPS @@ -178,7 +262,7 @@ static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len, } static void mg_tcpip_driver_stm32h_update_hash_table(struct mg_tcpip_if *ifp) { -#if MG_ENABLE_DRIVER_MCXN || MG_ENABLE_DRIVER_STM32N +#if SYNOPSYS_ENET_NOHASHTABLE ETH->MACPFR = MG_BIT(4); // Pass Multicast (pass all multicast frames) #else // TODO(): read database, rebuild hash table @@ -210,7 +294,7 @@ static bool mg_tcpip_driver_stm32h_poll(struct mg_tcpip_if *ifp, bool s1) { // if(link is slow or half) set flags otherwise // reg = tmp uint32_t maccr = ETH->MACCR | MG_BIT(14) | MG_BIT(13); // 100M, Full-duplex -#if MG_ENABLE_DRIVER_STM32N +#if SYNOPSYS_ENET_GbE if (speed == MG_PHY_SPEED_1000M) maccr &= ~MG_BIT(15); // 1000M #endif if (speed == MG_PHY_SPEED_10M) maccr &= ~MG_BIT(14); // 10M @@ -236,6 +320,7 @@ void ETH1_IRQHandler(void) { if (ETH->DMACSR & MG_BIT(6)) { // Frame received, loop ETH->DMACSR = MG_BIT(15) | MG_BIT(6); // Clear flag for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever + MG_CACHE_INVAL((uint8_t *) &s_rxdesc[s_rxno], DESC_SZ); if (s_rxdesc[s_rxno][3] & MG_BIT(31)) break; // exit when done if (((s_rxdesc[s_rxno][3] & (MG_BIT(28) | MG_BIT(29))) == (MG_BIT(28) | MG_BIT(29))) && @@ -243,10 +328,12 @@ void ETH1_IRQHandler(void) { uint32_t len = s_rxdesc[s_rxno][3] & (MG_BIT(15) - 1); // MG_DEBUG(("%lx %lu %lx %08lx", s_rxno, len, s_rxdesc[s_rxno][3], // ETH->DMACSR)); + MG_CACHE_INVAL((uint8_t *) &s_rxbuf[s_rxno], BUFF_SZ); mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp); } s_rxdesc[s_rxno][3] = MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V + MG_CACHE_FLUSH((uint8_t *) &s_rxdesc[s_rxno], DESC_SZ); if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; } }