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;
 

Reply via email to