This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C EMAC Check Sum off loading impacts LWIP (tcp_write) Stack copy with TDES0_CRC_ALL_CHKSUMS.

Guru 56418 points

QS-IOT project LWIP1.4.1 (lwipopt.h) Checksum testing is disabled and configuration in (lwiplib.c) offloads IP Chksum and CRC to the EMAC.

Questions: Why is checksum during Stack writes disabled and to enable any LWIP checksums during (tcp_write) copy_data_flag the CHKSUM_GEN_TCP must be enabled?

Seemingly off loading CRC Chksum to EMAC0 is good idea until (tcp_write) performs a copy larger than the remaining stack space.

9.30.15 That was the assumption made from reading text describing LWIP function details. Seems author left out a word in the sentence (TCP) stack. After all from all the issues involved around the PBUF heap pool is seemed plausible a checksum on writes to SRAM stack space (who knew).

ASSERT_DEBUG last_unsent->oversize_left >= oversize_used line:639  C:/lwip-1.4.1/src/core/tcp_out.c
ASSERT_DEBUG unsent_oversize mismatch (pcb vs. last_unsent) line:445  C:/lwip-1.4.1/src/core/tcp_out.c

#if TCP_OVERSIZE //(MSS= 850 bytes)
  u16_t oversize = 0;
  u16_t oversize_used = 0;
#endif /* TCP_OVERSIZE */
#if TCP_CHECKSUM_ON_COPY
  u16_t concat_chksum = 0;
  u8_t concat_chksum_swapped = 0;
  u16_t concat_chksummed = 0;
#endif /* TCP_CHECKSUM_ON_COPY */
/* don't allocate segments bigger than half the maximum window we ever received */
u16_t mss_local = LWIP_MIN(pcb->mss, pcb->snd_wnd_max/2); 

Disabling all LWIP Chksum often ends badly in random crash dumps with a full TCP stack regiment. We found the minimal set works 
best to protect the Stack during (tcp_write) and the Heap PBUF appears to benefit from the Chksum test during copy packet data.
Likewise when RX CRC off-loading: The receive checksum feature can be enabled by setting the IPC bit of the Ethernet MAC
Configuration (EMACCFG) register. EMAC_CONFIG_CHECKSUM_OFFLOAD

Below minimal project Stack protection is enabled for (tcp_write):
//*****************************************************************************
//
// ---------- checksum options ----------
//
//*****************************************************************************
#define CHECKSUM_GEN_IP                 0
#define CHECKSUM_GEN_ICMP               0
#define CHECKSUM_GEN_UDP                0
#define CHECKSUM_GEN_TCP                0
#define CHECKSUM_CHECK_IP               0
#define CHECKSUM_CHECK_UDP              0
#define CHECKSUM_CHECK_TCP              0
#define LWIP_CHECKSUM_ON_COPY           1


 (tcp_impl.h) /** Don't generate checksum on copy if CHECKSUM_GEN_TCP is disabled */
#define TCP_CHECKSUM_ON_COPY  (LWIP_CHECKSUM_ON_COPY)// && CHECKSUM_GEN_TCP
20.3.8.1 Transmit Checksum Offload Engine
The checksum for TCP, UDP, or ICMP is calculated over a complete frame, and then inserted into
its corresponding header field. Because of this requirement this function is enabled only when the
TX FIFO is configured for the store-and-forward mode (the TSF bit is set in the EMACDMAOPMODE
register).

Note: The TX FIFO must be deep enough to store a complete frame before the frame is transferred
to the MAC when the checksum offload is being used. If space is not available to accept
the programmed burst length of data, the TX/RX Controller starts reading to avoid deadlock.
When reading starts, the checksum offload fails and the consequently all succeeding frames
may be corrupted because of improper recovery. Therefore, checksum insertion must only
be enabled in frames that are less than [2048-((PBL+3)*4)] bytes in size, where PBL is the
Programmable Burst Length field in the EMACDMABUSMOD register

  • > Why is checksum during Stack writes turned off in (lwipopts.h) to stack copy CHKSUM_GEN_TCP must be enabled?

    CRC is performed in the EMAC and this feature can be disabled separately from checksum off loading. Easy to confuse the two as I first did in this post.

    Appears LWIP1.4.1 is not Default configured for Checksum off loading in the http header unless we disable existing older configuration in LWIP. Otherwise we loose checksum protection during Stack copy required with every (tcp_write()). LWIP also adds the checksum into the http header prior to TX packets and EMAC0 does the same Off load - a bit redundant with perhaps hidden consequences.

    Opinion LWIP1.4.1 Third party TCP stack needs a full compatibility scrubbing for use with TM4C advanced processors.

    (tcp_impl.c) /** Don't generate checksum on copy if CHECKSUM_GEN_TCP is disabled */

    #define TCP_CHECKSUM_ON_COPY  (LWIP_CHECKSUM_ON_COPY) // && CHECKSUM_GEN_TCP

    #if TCP_CHECKSUM_ON_COPY
      u16_t chksum;
      u8_t  chksum_swapped;
    #endif /* TCP_CHECKSUM_ON_COPY */
      u8_t  flags;
    #define TF_SEG_OPTS_MSS         (u8_t)0x01U /* Include MSS option. */
    #define TF_SEG_OPTS_TS          (u8_t)0x02U /* Include timestamp option. */
    #define TF_SEG_DATA_CHECKSUMMED (u8_t)0x04U /* ALL data (not the header) is
                                                   checksummed into 'chksum' */
      struct tcp_hdr *tcphdr;  /* the TCP header */
    };
    
    
       * Phase 2: concat_p can be concatenated onto last_unsent->p
       */
      if (concat_p != NULL) {
        LWIP_ASSERT("tcp_write: cannot concatenate when pcb->unsent is empty",
          (last_unsent != NULL));
        pbuf_cat(last_unsent->p, concat_p);
        last_unsent->len += concat_p->tot_len;
    #if TCP_CHECKSUM_ON_COPY
        if (concat_chksummed) {
          tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum,
            &last_unsent->chksum_swapped);
          last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED;
        }
    #endif /* TCP_CHECKSUM_ON_COPY */

  • In line checksum (ip.c) being enable in LWIP seems a redundant overkill as checksum off load is typically being set (llwiplib.c).

    MAP_EMACConfigSet(EMAC0_BASE, EMAC_CONFIG_ CHECKSUM_OFFLOAD);

    That configuration infers the EMAC hardware is doing (http_hdr) header checksum and it should be disable in (ip.c).

    [LWIP_INLINE_IP_CHKSUM  ==  0]

    /** Set this to 0 in the rare case of wanting to call an extra function to
     * generate (or offload) the IP checksum (in contrast to calculating it on-the-fly). */
    #ifndef LWIP_INLINE_IP_CHKSUM
    #define LWIP_INLINE_IP_CHKSUM   0
    #endif
    #if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP
    #define CHECKSUM_GEN_IP_INLINE  1
    #else
    #define CHECKSUM_GEN_IP_INLINE  0
    #endif

     

  • Seems that checksum on TCP copy only adds (tcp_write) data checksum into the segment and does not do a checksum on data copied to what was believed to infer the MCU stack memory not the TCP stack itself. There is no checksum during the copy of data into heap memory blocks. From LWIP project point of view the stack is always the TCP stack.

    Likewise the inline checksum adds the checksum into the header yet assigns 0 value by default.

    * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the (TCP) stack.

    Will the real stack please stand up?

    The trouble with corrupted data during write copy flag (tcp_write) appears to be more of a LWIP local client timer speed related issue.