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.

TMS570LC4357: EMAC driver must not set TXHDP until EOQ is detected

Part Number: TMS570LC4357

The technical reference would indicate one can set the TXHDP whenever the TXHDP is 0.  Under very high send/receive rates, this will result in a MACSTATUS 0x00200000 (TXERRCODE: OWNERSHIP bit not set in SOP buffer.  

If I instead wait for the EOQ flag to be set, no MACSTATUS error is generated.

Please advise if I have misinterpreted the technical reference, or what your recommendation is for managing the transmit chains.

I've included an example project (see main.c) which demonstrates the failure.  By commenting out line 114 and enabling line 115, the failure can be demonstrated.
The demonstration runs in EMAC loopback mode, so no external harnessing is required.
  • HI,

    Thanks for the test example and look into it! The TRM says:

    32.2.6.2 Transmit and Receive Descriptor Queues

    There is a potential race condition where the EMAC may read the “next” pointer of a descriptor as NULL in
    the instant before an application appends additional descriptors to the list by patching the pointer. This
    case is handled by the software application always examining the buffer descriptor flags of all EOP
    packets, looking for a special flag called end of queue (EOQ). The EOQ flag is set by the EMAC on the
    last descriptor of a packet when the descriptor’s “next” pointer is NULL. This is the way the EMAC
    indicates to the software application that it believes it has reached the end of the list. When the software
    application sees the EOQ flag set, the application may at that time submit the new list, or the portion of
    the appended list that was missed by writing the new list pointer to the same HDP that started the
    process.

    In our example code,  https://git.ti.com/cgit/hercules_examples/hercules_examples/tree/Application/LwIP/v00.04.00/TMS570LC43x/HALCoGen-TMS570LC43x/source, HL_emac.c, we have such check inside boolean EMACTransmit(hdkif_t *hdkif, pbuf_t *pbuf)

    /* Wait for the EOQ bit is set */
    /*SAFETYMCUSW 28 D MR:NA <APPROVED> "Hardware status bit read check" */
    /*SAFETYMCUSW 134 S MR:12.2 <APPROVED> "LDRA Tool issue" */
    /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are assigned in this driver" */
    while (EMAC_BUF_DESC_EOQ != (EMACSwizzleData(curr_bd->flags_pktlen) & EMAC_BUF_DESC_EOQ))
    {
    }
    /* Don't write to TXHDP0 until it turns to zero */
    /*SAFETYMCUSW 28 D MR:NA <APPROVED> "Hardware status bit read check" */
    /*SAFETYMCUSW 134 S MR:12.2 <APPROVED> "LDRA Tool issue" */
    while (((uint32)0U != *((uint32 *)0xFCF78600U)))
    {
    }

    Regards, Eric

  • I deliberately created this demo to not use chaining to decouple the two concerns.  The demonstration simply uses one transmit descriptor (whose next pointer is always 0).

    This demo indicates is that there is another race condition- i.e. code that relies solely on TXHDP == 0 can corrupt the internal state of the EMAC.

  • Stephen Holstein said:
    I've included an example project (see main.c) which demonstrates the failure.  By commenting out line 114 and enabling line 115, the failure can be demonstrated.

    I can repeat the failure with a TMS570LC4357 Silicon Revision A device.

    Stephen Holstein said:
    The technical reference would indicate one can set the TXHDP whenever the TXHDP is 0.

    Reading SPNU563A:

    1) Section 32.2.6.4.9 End of Queue (EOQ) Flag is:

    When set, this flag indicates that the descriptor in question was the last descriptor in the transmit queue for a given transmit channel, and that the transmitter has halted. This flag is initially cleared by the software application prior to adding the descriptor to the transmit queue. This bit is set by the EMAC when the EMAC identifies that a descriptor is the last for a given packet (the EOP flag is set), and there are no more descriptors in the transmit list (next descriptor pointer is NULL).

    The software application can use this bit to detect when the EMAC transmitter for the corresponding channel has halted. This is useful when the application appends additional packet descriptors to a transmit queue list that is already owned by the EMAC. Note that this flag is valid on EOP descriptors only

    I.e. the EOQ flag is described as an indication that the transmitter has halted.

    2) The description of the Transmit Channel DMA Head Descriptor Pointer Registers and Receive Channel DMA Head Descriptor Pointer Registers contains:

    Writing to these locations when they are nonzero is an error (except at reset)

    While it is clear that TXHDP shouldn't be written to again until changes to zero, I can't find a clear description of when TXHDP changes to zero w.r.t. when the transmitter stops.

    3) Section 32.2.6.2 Transmit and Receive Descriptor Queues contains:

    The HDP must never be written to while a list is active.

    However, in that section I can't seem to find an explicit of how the software tells when a list is active.

    Stephen Holstein said:
    Please advise if I have misinterpreted the technical reference, or what your recommendation is for managing the transmit chains.

    Based upon my reading of the technical reference think that the most robust method to determine that the transmit channel has halted is to wait until both EOQ is set in the last descriptor AND TXHDP is zero.

    This is only my understanding from reading the technical reference; hopefully a TI employee cam make a more definitive statement.

  • Based upon my reading of the technical reference think that the most robust method to determine that the transmit channel has halted is to wait until both EOQ is set in the last descriptor AND TXHDP is zero.

    I modified the example to try sampling both the EOQ and RXHDP/TXHDP values and report statistics on which combinations had been seen.

    For both the transmit and receive channels the code waits until both EOQ is set and the RXHDP/RXHDP is zero.

    Sample results for the statistics when compiled for debug taken while the program was running (optimization level off):

    Sample values when compiled for release taken while the program was running (optimization level 4):

    The num_rx_starts and num_tx_starts count how many times EMAC_RXHDP and EMAC_TXHDP have been written, so can check the program is still performing an Ethernet loopback.

    The two dimensional rx_status_counts and tx_status_counts arrays count the number of combinations in which sampled:

    [0][0] = EOQ clear and HDP non-zero

    [0][1] = EOQ clear and HDP zero

    [1][0] = EOQ set and HDP non-zero

    [1][1] = EOQ set and HDP zero - which is the condition under which the code considers the channel has halted and can write another entry to the HDP.

    The results show some captures in which sampled the combinations of "EOQ clear and HDP zero" and "EOQ set and HDP non-zero", which does suggest both need to be sampled.

    3531.TMS570LC4357_emac_status.zip

  • Hi Chester,

    Thanks for looking into this to capture the occurrences of four EOQ and HDP combinations. The statistics showed that we do need to check both EOQ = 1 and HDP = 0 conditions before one can write into HDP next time.  

    Stephen,

    Hope this answered your concern.

    Regards, Eric

  • I'm hoping for an authoritative statement of how transmit chains should be handled, rather than a characterization via software.

    My concern is that there isn't anything to say that this characterization is complete- only that analyzing these two variables (TXHDP and EOQ) were sufficient for the characterization trials.  For example, what's to say that the software shouldn't be waiting out the TXCP, or the interrupt flag, etc.

    If TXHDP and EOQ are the only two required signals for synchronization with the EMAC, then can you confirm that here (and update the next Technical Reference Manual revision)?

  • Stephen,

    Thanks! I understood your concern, let me check if our EMAC driver design or IP team can comment on this.

    Regards, Eric

  • Hi,

    From our design team,

    "Transmit Operation

    After reset the host must write zeroes to all Tx DMA State head descriptor pointers. The Tx port may then be enabled. To initiate packet transmission the host constructs transmit queues in memory (one or more packets for transmission) and then writes the appropriate Tx DMA state head descriptor pointers. For each buffer added to a transmit queue, the host must initialize the Tx buffer descriptor values as follows:

    1. Write the Next Descriptor Pointer with the 32-bit aligned address of the next descriptor in the queue (zero if last descriptor)
    2. Write the Buffer Pointer with the byte aligned address of the buffer data
    3. Write the Buffer Length with the number of bytes in the buffer
    4. Write the Buffer Offset with the number of bytes in the offset to the data (nonzero with SOP only)
    5. Set the SOP, EOP, and Ownership bits as appropriate
    6. Clear the End Of Queue bit

    The port begins Tx packet transmission on a given channel when the host writes the channel’s Tx queue head descriptor pointer with the address of the first buffer descriptor in the queue (nonzero value). Each channel may have one or more queues, so each channel may have one or more head descriptor pointers. The first buffer descriptor for each Tx packet must have the Start of Packet (SOP) bit and the Ownership bit set to one by the host. The last buffer descriptor for each Tx packet must have the End of Packet (EOP) bit set to one by the host. The port will transmit packets until all queued packets have been transmitted and the queue(s) are empty.

    When each packet transmission is complete, the port will clear the Ownership bit in the packet’s SOP buffer descriptor and issue an interrupt to the host by writing the packet’s last buffer descriptor address to the queue’s Tx DMA State Completion Pointer. The interrupt is generated by the write, regardless of the value written. When the last packet in a queue has been transmitted, the port sets the End Of Queue bit in the EOP buffer descriptor, clears the Ownership bit in the SOP Descriptor, zeroes the appropriate DMA state head descriptor pointer, and then issues a Tx interrupt to the host by writing to the queue’s associated Tx completion pointer (address of the last buffer descriptor processed by the port). The port issues a maskable level interrupt (which may then be routed through external interrupt control logic to the host).

    On interrupt from the port, the host processes the buffer queue, detecting transmitted packets by the status of the Ownership bit in the SOP buffer descriptor. If the Ownership bit is cleared to zero, then the packet has been transmitted and the host may reclaim the buffers associated with the packet. The host continues queue processing until the end of the queue or until a SOP buffer descriptor is read that contains a set Ownership bit indicating that the packet transmission is not complete. The host determines that all packets in the queue have been transmitted when the last packet in the queue has a cleared Ownership bit in the SOP buffer descriptor, the End of Queue bit is set in the last packet EOP buffer descriptor, and the Next Descriptor Pointer of the last packet EOP buffer descriptor is zero. The host acknowledges an interrupt by writing the address of the last buffer descriptor to the queue’s associated Tx Completion Pointer in the Tx DMA State. If the host written buffer address value is different from the buffer address written by the port, then the level interrupt remains asserted. If the host written buffer address value is equal to the port written value, then the level interrupt is deasserted. The port write to the completion pointer actually stores the value in the state register (ram). The host written value is actually not written to the register location. The host written value is compared to the register contents (which was written by the port) and if the two values are equal, the interrupt is removed, otherwise the interrupt remains asserted. The host may process multiple packets previous to acknowledging an interrupt, or the host may acknowledge interrupts for every packet."

    As you are not concerned about chaining (A misqueued packet condition may occur when the host adds a packet to a queue for transmission as the port finishes transmitting the previous last packet in the queue): I deliberately created this demo to not use chaining to decouple the two concerns.  The demonstration simply uses one transmit descriptor (whose next pointer is always 0). So you can see how to know the transmission finished by the above highlighted sentence: EOQ = 1, TXHDP = 0 and Ownership bit  = 0.

    Regards, Eric

  • As identified in the demonstration and chester's characterization, the signals necessary to determine if the transmit channel is inactive do not change simultaneously.

    When the last packet in a queue has been transmitted, the port sets the End Of Queue bit in the EOP buffer descriptor, clears the Ownership bit in the SOP Descriptor, zeroes the appropriate DMA state head descriptor pointer, and then issues a Tx interrupt to the host by writing to the queue’s associated Tx completion pointer (address of the last buffer descriptor processed by the port).

    The "When" in the statement above is ambiguous- as there are many states changing in that single sentence, some of which are known to change at different times.  Per your last post, only EOQ, TXHDP, and Ownership need to be monitored by the host to ensure that the EMAC transmit channel is inactive.  None of the other signals identified in that sentence (EOP, SOP, interrupt state, TXCP) are necessary to ensure that the EMAC transmit channel is inactive.

    My understanding (per your last post) is that TI's authoritative statement is:

    The transmit channel is inactive when EOQ=1, TXHDP=0, and Ownership=0.  Only when this inactive condition is met, can TXHDP be written with a new head descriptor.

  • Hi,

    My understanding (per your last post) is that TI's authoritative statement is: "The transmit channel is inactive when EOQ=1, TXHDP=0, and Ownership=0.  Only when this inactive condition is met, can TXHDP be written with a new head descriptor."

    Yes, that is correct.

    Regards, Eric

  • I've found the same condition for necessary for receive channels:

    "The receive channel is inactive when EOQ=1, RXHDP=0, and Ownership=0.  Only when this inactive condition is met, can RXHDP be written with a new head descriptor."

    With these two understandings, I'm satisfied (until I find other behavior) by these assertions.