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.

DP83816 Ethernet - Transmitter Goes Idle

Other Parts Discussed in Thread: DP83816

I'm trying to solve a problem with an embedded application using the DP83816 Ethernet controller.  The transmit state machine sometimes goes idle even though there are still unsent descriptors in the ring (with the OWN bit set).

My question is about the behavior of the transmit state machine when setting the "TXE" (Transmit Enable) bit in the Command Register.  The datasheet has this statement.

"When set to a 1, and the transmit state machine is idle, then the transmit state machine becomes active.
This bit will read back as a 1 whenever the transmit state machine is active. After initial power-up,
software must insure that the transmitter has completely reset before setting this bit
"

That implies the TXE bit is ignored if the transmit state machine is not idle.  The problem is that software can set the "OWN" bit in a descriptor just after the state machine has read the descriptor.  In that case the transmitter is going to transition to the idle state.  When the software sets the "OWN" bit in the descriptor and then sets "TXE" in the Command Register, the state machine goes idle instead of re-reading the descriptor. I think that "TXE" is being ignored because the state machine has not yet transitioned to the idle state.  I'm trying to determine if that is normal behavior for the chip or I am having an unusual problem.

The transmitter stops and a "TXIDLE" interrupt occurs. The software can restart the transmitter but this introduces a delay before the frame is transmitted.  If software is polling rather than using interrupts the delay can be considerable depending on the frequency that the software polls the interrupt status.  Another possible solution that I have not tried is adding a delay between when the software sets the "OWN" bit in the descriptor and the software sets the "TXE" bit.  The delay would have to be long enough for the state machine to read the descriptor and stop completely.  I avoided that solution to the problem since the delays for the state transitions are not documented.  Also, the time required for the DMA to read the descriptor is difficult to predict.

I examined the Linux driver for the DP83816 and it simply adds an item to the ring, sets the "OWN" bit and then sets the "TXE" bit in the Command Register.  There is no handler for the "TXIDLE" interrupt. I don't see how the driver avoids this problem.  That makes me unsure if I am seeing abnormal behavior from the chip in my application.

If anyone can clarify the expected behavior of the chip or how to avoid this problem I will appreciate it.

  • Could you please provide some additional information on the descriptor arrangement ?  For example, it would help to understand the length of the descriptor ring, single/multi descriptors per packet, etc. 

  • Patrick O'Farrell said:

    Could you please provide some additional information on the descriptor arrangement ?  For example, it would help to understand the length of the descriptor ring, single/multi descriptors per packet, etc. 

    There are 128 descriptors organized as a ring.  The last descriptor points to the first descriptor.  The software does not change the link pointers. The software changes the buffer pointer in a descriptor and then sets the "OWN" bit in "cmdsts" to give the chip ownership of the descriptor. The software maintains a transmit write index and transmit read index that track which descriptors are available for use or may be owned by the chip.

    Each transmitted frame uses two descriptors.  The first descriptor points to a buffer containing the destination and source MAC address (12 bytes).  The second descriptor contains the Ethertype code and remainder of the frame.  Frames vary from 32 bytes to 1480 bytes in length.  The software typically transmits 33 frames but that varies depending on the system configuration.  The maximum configuration doesn't use more than 64 frames.

    Here is a more detailed description of how the software transmits the frames.

    1. Disable interrupts
    2. Check to make sure that there are enough unused descriptors for the packet.
      This is done by counting the number of buffers (always two) and checking the transmit write index versus read index.
      If the write index equals the read index the software checks the descriptor buffer pointer to determine if the ring is empty or full.
    3. If there are not enough available descriptors, return "ring full" status
    4. Set buffer pointer and "cmdsts" (OWN bit cleared, MORE set) for first descriptor
    5. Set buffer pointer and "cmdsts" (OWN bit set, MORE cleared) for second descriptor
    6. Set "cmdsts" (OWN bit set, MORE bit set) for first descriptor
    7. PCI I/O Output to Command Register (offset 0) with TXE bit set (0x00000001)
    8. Update transmit "write" index to indicate next available descriptor
    9. Enable interrupts

    I have tried a number of more complicated methods for starting the transmitter (step 7 above) but they all result in the transmitter sometimes going idle before all the buffers are transmitted.  The software does add buffers to the ring while transmit is in progress. Software may perform step 6 and 7 just after hardware has read the first descriptor seeing "OWN" cleared. Step 4 is not strictly necessary because the OWN bit should already be cleared in an available descriptor.  The software actually supports an arbitrary number of chained descriptors even though only two are ever used.

    The software also sets the "INTR" bit in all descriptors to cause an interrupt when any descriptor completes.  Here is the interrupt processing for transmit completion.

    1. Disable interrupts
    2. Check descriptor at transmit read index for completion (OWN bit cleared)
    3. If descriptor not complete, go to step 10
    4. Check "cmdsts" and count transmit errors
    5. Chain buffer to list of completed buffers
    6. Clear buffer pointer in completed descriptor
    7. If there is no "next" buffer, call software completion routine and clear list of completed buffers
    8. Update transmit read index
    9. Go to step 2
    10. Enable Interrupts

    The software handles the "TXIDLE" interrupt as follows.

    1. Disable interrupts
    2. PCI I/O Input from Command Register (offset 0)
    3. If "TXE" bit (0x00000001) set, go to step 12
    4. PCI I/O Input from Transmit Descriptor Pointer register (0020h)
    5. Mask unused bits of address (1 and 0)
    6. Range check address versus descriptor ring
    7. If address out of range, go to step 12
    8. Calculate ring index from descriptor address
    9. If descriptor at address has "OWN" cleared, go to step 12
    10. PCI I/O output to Transmit Descriptor Pointer register (0020h)
    11. PCI I/O Output to Command Register (offset 0) with TXE bit set (0x00000001)
    12. Enable interrupts

    The above steps were added to work around the problem with the transmitter stopping before all the frames are transmitted. For some reason it was necessary to output the address to the TXDP register in order for the transmitter to correctly finish transmitting.  I have also tried using these same steps as a way to normally start the transmitter (in place of step 7 for transmitting the frames).

    This may be the normal behavior of the chip but it isn't clear to me after reading the data sheet (manual).  If it is normal why don't other drivers have the "TXIDLE" handling to check for unprocessed descriptors?

  • I do not recall having seen any issue like this before so I would like to review your implementation more closely. 

    Could you provide a register dump so that I could review the device configuration?

    Do you have the ability to hook up a PCI bus analyzer?  That would allow you to capture on events such as the device going IDLE, accessing incorrect memory, etc.