This is an automated email from the ASF dual-hosted git repository.
linguini1 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 8df855d2abb arch/arm/stm32h5: Add ethernet hardware checksum
8df855d2abb is described below
commit 8df855d2abb082204b8b586de6856641a6477133
Author: Patrick José Pereira <[email protected]>
AuthorDate: Wed May 20 10:46:02 2026 -0300
arch/arm/stm32h5: Add ethernet hardware checksum
The Ethernet MAC (57.11.4) was already configured in the code,
but it was necessary to configure the Transmit Descriptor (57.10.3)
in read format:
- Checksum Interface Control for IP, payload and pseudo-header
Add checks for Recceive Descriptor (57.10.4) in read format:
- Receive Descriptor 1 is valid from Receive Descriptor 3
- IP checksum was not bypassed
- IP header checksum error op IP payload checkerror is set
Testing with STM32 Nucleo-144 using iperf, improved transmission from
35 MBits/s to 50MBits/s.
Signed-off-by: Patrick José Pereira <[email protected]>
---
arch/arm/src/stm32h5/Kconfig | 11 ++++++
arch/arm/src/stm32h5/hardware/stm32_ethernet.h | 5 +++
arch/arm/src/stm32h5/stm32_ethernet.c | 48 +++++++++++++++++++-------
3 files changed, 52 insertions(+), 12 deletions(-)
diff --git a/arch/arm/src/stm32h5/Kconfig b/arch/arm/src/stm32h5/Kconfig
index 96a140e409e..651bbeeba08 100644
--- a/arch/arm/src/stm32h5/Kconfig
+++ b/arch/arm/src/stm32h5/Kconfig
@@ -5335,6 +5335,17 @@ config STM32H5_ETH_NTXDESC
---help---
Number of TX DMA descriptors to use.
+config STM32H5_ETH_HWCHECKSUM
+ bool "Enable ethernet hardware checksum"
+ default n
+ ---help---
+ Enable the IPv4/IPv6 header and TCP/UDP/ICMP payload checksum
offload
+ engine in the Ethernet MAC.
+ When enabled, hardware generates checksums for TX and checks RX
frames.
+ Be sure to disable software checksums (NET_TCP_CHECKSUMS,
NET_UDP_CHECKSUMS,
+ NET_ICMP_CHECKSUMS, NET_IPV4_CHECKSUMS, NET_IPV6_CHECKSUMS) to
avoid
+ redundant verification in the network stack.
+
config STM32H5_ETHFD
bool "Full duplex"
default n
diff --git a/arch/arm/src/stm32h5/hardware/stm32_ethernet.h
b/arch/arm/src/stm32h5/hardware/stm32_ethernet.h
index d49863c5602..420f624695c 100644
--- a/arch/arm/src/stm32h5/hardware/stm32_ethernet.h
+++ b/arch/arm/src/stm32h5/hardware/stm32_ethernet.h
@@ -502,6 +502,11 @@
#define ETH_TDES3_RD_CIC_TPL_SHIFT (16) /* Checksum Insertion Control or TCP
Payload Length */
#define ETH_TDES3_RD_CIC_TPL_MASK (0x3 << ETH_TDES3_RD_CIC_TPL_SHIFT)
+# define ETH_TDES3_RD_CIC_DISABLED (0x0 << ETH_TDES3_RD_CIC_TPL_SHIFT) /*
Checksum insertion disabled */
+# define ETH_TDES3_RD_CIC_IPHDR (0x1 << ETH_TDES3_RD_CIC_TPL_SHIFT) /*
Only IP header checksum calculation and insertion are enabled */
+# define ETH_TDES3_RD_CIC_IPHDR_PL (0x2 << ETH_TDES3_RD_CIC_TPL_SHIFT) /* IP
header + payload checksum and insertion, pseudo-header checksum is not
calculated in hardware. */
+# define ETH_TDES3_RD_CIC_ALL (0x3 << ETH_TDES3_RD_CIC_TPL_SHIFT) /* IP
header + payload + pseudo-header computed by hardware */
+
#define ETH_TDES3_RD_TSE (1 << 18) /* Bit 18: TCP Segmentation
Enable */
#define ETH_TDES3_RD_THL_SHIFT (19) /* TCP Header Length */
diff --git a/arch/arm/src/stm32h5/stm32_ethernet.c
b/arch/arm/src/stm32h5/stm32_ethernet.c
index 836a65483ed..48c972aa2f5 100644
--- a/arch/arm/src/stm32h5/stm32_ethernet.c
+++ b/arch/arm/src/stm32h5/stm32_ethernet.c
@@ -174,8 +174,6 @@
# warning "CONFIG_STM32H5_ETH_PTP is not yet supported"
#endif
-#undef CONFIG_STM32H5_ETH_HWCHECKSUM
-
/* Add 4 to the configured buffer size to account for the 2 byte checksum
* memory needed at the end of the maximum size packet. Buffer sizes must
* be an even multiple of 4, 8, or 16 bytes (depending on buswidth). We
@@ -498,12 +496,6 @@
#define MTLRXQOMR_SET_MASK \
((0x7 << ETH_MTLRXQOMR_RQS_SHIFT) | ETH_MTLRXQOMR_RTC_64)
-#ifdef CONFIG_STM32H5_ETH_HWCHECKSUM
-/* TODO */
-
-# error CONFIG_STM32H5_ETH_HWCHECKSUM not supported
-#endif
-
/* Clear the DMAMR bits that will be setup during MAC initialization (or that
* are cleared unconditionally). Per the reference manual, all reserved bits
* must be retained at their reset value.
@@ -1116,9 +1108,16 @@ static int stm32_transmit(struct stm32_ethmac_s *priv)
ninfo("bufcount: %d lastsize: %d\n", bufcount, lastsize);
- /* Set the first segment bit in the first TX descriptor */
+ /* Set the first segment bit in the first TX descriptor.
+ * If hardware checksum is enabled, IP header + payload +
+ * pseudo-header checksum will be computed.
+ */
+#ifdef CONFIG_STM32H5_ETH_HWCHECKSUM
+ txdesc->des3 = ETH_TDES3_RD_FD | ETH_TDES3_RD_CIC_ALL;
+#else
txdesc->des3 = ETH_TDES3_RD_FD;
+#endif
/* Set up all but the last TX descriptor */
@@ -1204,10 +1203,16 @@ static int stm32_transmit(struct stm32_ethmac_s *priv)
/* The single descriptor is both the first and last segment. */
/* Set OWN bit of the TX descriptor des3. This gives the buffer to
- * Ethernet DMA
+ * Ethernet DMA. If hardware checksum is enabled, IP header + payload +
+ * pseudo-header checksum will be computed.
*/
+#ifdef CONFIG_STM32H5_ETH_HWCHECKSUM
+ txdesc->des3 = (ETH_TDES3_RD_OWN | ETH_TDES3_RD_LD | ETH_TDES3_RD_FD |
+ ETH_TDES3_RD_CIC_ALL);
+#else
txdesc->des3 = (ETH_TDES3_RD_OWN | ETH_TDES3_RD_LD | ETH_TDES3_RD_FD);
+#endif
/* Flush the contents of the modified TX descriptor into physical
* memory.
@@ -1702,6 +1707,7 @@ static int stm32_recvframe(struct stm32_ethmac_s *priv)
else
{
+ bool err = ((rxdesc->des3 & ETH_RDES3_WB_ES) != 0);
priv->segments++;
/* Check if there is only one segment in the frame */
@@ -1718,9 +1724,27 @@ static int stm32_recvframe(struct stm32_ethmac_s *priv)
ninfo("rxhead: %p rxcurr: %p segments: %d\n",
priv->rxhead, priv->rxcurr, priv->segments);
- /* Check if any errors are reported in the frame */
+#ifdef CONFIG_STM32H5_ETH_HWCHECKSUM
+ /* Check if any errors are reported in the frame.
+ * If hardware checksum is enabled, check if:
+ * - RDES1 is valid
+ * - IP checksum was not bypassed
+ * - IP hdr checksum error or IP payload checksum error is set
+ *
+ * By the previous checks the Last Descriptor is set.
+ * RS1V is valid.
+ */
+
+ if (!err && (rxdesc->des3 & ETH_RDES3_WB_RS1V) != 0 &&
+ (rxdesc->des1 & ETH_RDES1_WB_IPCB) == 0 &&
+ (rxdesc->des1 & (ETH_RDES1_WB_IPHE |
+ ETH_RDES1_WB_IPCE)) != 0)
+ {
+ err = true;
+ }
+#endif
- if ((rxdesc->des3 & ETH_RDES3_WB_ES) == 0)
+ if (!err)
{
struct net_driver_s *dev = &priv->dev;