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.

am335x: usb freeze (with DMA)

Summary: Under some conditions, the system fails to receive isochronous IN transfers, when DMA is used. Only resetting the usb hardware brings it back to life.

Hardware: BeagleBone Black with a UVC camera attached to its USB host port. Tested with two cameras, one Logitech Quickcam Pro 9000, the other is an embedded camera module from a laptop. Both work fine when connected to a PC.

Kernel: 3.14.26 taken from ti-processor-sdk-linux-am335x-evm-01.00.00.00, with cppi41 dma enabled. The issue is not present with DMA disabled.
For USB trace capture, I've disabled the High-Speed USB mode in the kernel (MUSB_POWER_HSENAB), as I don't have access to a High-Speed analyzer. The problem occurs with High-Speed as well as with Full-Speed USB.

Test case:

Note: During testing, I've also experienced soft lockups related to dynamic CPU frequency scaling. In case of lockups disable cpufreq or set the governor to fixed-frequency.

With the camera attached, I run a shell script which repeatedly opens the video device and reads a few frames (using http://git.ideasonboard.org/yavta.git

while sleep 1; do yavta -s320x240 -c4 /dev/video0; done

After a few iterations (occasionally it takes several minutes), yavta freezes waiting for the first frame. After this point, no further video streaming is possible. USB trace (included below) shows that the driver fails to receive a response for the first (and only) isochronous IN token. Dumping the hardware registers shows that the RXPKTRDY bit is set for the appropriate endpoint, which would indicate that the USB hardware has received a response. But the DMA-completed interrupt never arrives.

Restarting yavta or replugging the camera have no effect. The only way to reset to a working state, apart from rebooting is resetting the driver and hardware as follows:

echo musb-hdrc.1.auto > /sys/bus/platform/drivers/musb-hdrc/unbind
echo musb-hdrc.1.auto > /sys/bus/platform/drivers/musb-hdrc/bind

My question:

How to solve this problem, or - at least - how to debug issues between the MUSB and CPPI41?

USB trace snipplet for the failing case(taken at 12Mbit):

=== SOF 241

IN addr 4 endpoint 0
NAK
...
IN addr 4 endpoint 0
NAK

=== SOF 242

IN addr 4 endpoint 0
DATA1 (0 bytes)
ACK

=== SOF 243

IN addr 4 endpoint 1
NAK

=== SOF 244

IN addr 4 endpoint 2   # MUSB sends one IN token on the isochronous endpoint
DATA0 (0 bytes) # receives a response

=== SOF 245

# no further IN tokens are sent for endpoint 2

=== SOF 246

=== SOF 247

=== SOF 248

=== SOF 249

=== SOF 250

=== SOF 251

=== SOF 252

IN addr 4 endpoint 1
NAK

Kernel function trace snipplet:

I've added some trace_printk-s to the code, and filtered the trace to include only musb_* and cppi41_* functions.

  135.623111 |   0)   4.208 us    |  musb_h_disable();
  135.623732 |   0)   2.708 us    |  musb_map_urb_for_dma();
  135.623743 |   0)               |  musb_urb_enqueue() {
  135.623749 |   0)               |  /* urb endpoint: 82 pipe: 410280 */
  135.623764 |   0)               |    musb_start_urb() {
  135.623769 |   0)   1.417 us    |      cppi41_dma_channel_allocate();
  135.623777 |   0)               |      cppi41_dma_channel_program() {
  135.623782 |   0)               |        /* dma de7e6388 status = 2 */
  135.623785 |   0)   0.916 us    |        cppi41_set_dma_mode.isra.3();
  135.623791 |   0)   1.917 us    |        cppi41_dma_prep_slave_sg();
  135.623798 |   0)   0.417 us    |        cppi41_tx_submit();
  135.623803 |   0)   1.584 us    |        cppi41_dma_issue_pending();
  135.623809 |   0) + 29.667 us   |      }
  135.623811 |   0) + 44.000 us   |    }
  135.623814 |   0) + 68.291 us   |  }
  135.623819 |   0)   0.625 us    |  musb_map_urb_for_dma();
  135.623824 |   0)               |  musb_urb_enqueue() {
  135.623828 |   0)               |  /* urb endpoint: 82 pipe: 410280 */
  135.623832 |   0)   5.750 us    |  }
  135.623837 |   0)   0.542 us    |  musb_map_urb_for_dma();
  135.623842 |   0)               |  musb_urb_enqueue() {
  135.623844 |   0)               |  /* urb endpoint: 82 pipe: 410280 */
  135.623848 |   0)   4.709 us    |  }
  135.623853 |   0)   0.541 us    |  musb_map_urb_for_dma();
  135.623858 |   0)               |  musb_urb_enqueue() {
  135.623861 |   0)               |  /* urb endpoint: 82 pipe: 410280 */
  135.623865 |   0)   4.625 us    |  }
  135.623870 |   0)   0.542 us    |  musb_map_urb_for_dma();
  135.623875 |   0)               |  musb_urb_enqueue() {
  135.623878 |   0)               |  /* urb endpoint: 82 pipe: 410280 */
  135.623882 |   0)   4.833 us    |  }

Here yavta freezes in the "failing" case. In the "working" case, the next entry in the trace would be like this:

  132.994996 |   0)               |  cppi41_irq() {
  132.995005 |   0)               |    cppi41_dma_callback() {
  132.995010 |   0)   1.458 us    |      cppi41_dma_tx_status();
  132.995019 |   0)               |      cppi41_trans_done() {
  132.995025 |   0)               |        /* dma de7e6388 status = 1 */
  132.995029 |   0)               |        musb_dma_completion() {
  132.995032 |   0)               |          musb_host_rx() {
  132.995038 |   0)               |            /* <== hw 14 rxcsr 2200, urb actual 0 (+dma 0) */
  132.995042 |   0)               |            cppi41_dma_channel_program() {
  132.995045 |   0)               |              /* dma de7e6388 status = 2 */
  132.995047 |   0)   0.750 us    |              cppi41_set_dma_mode.isra.3();
  132.995051 |   0)   0.750 us    |              cppi41_dma_prep_slave_sg();
  132.995056 |   0)   0.458 us    |              cppi41_tx_submit();
  132.995061 |   0)   1.000 us    |              cppi41_dma_issue_pending();
  132.995066 |   0) + 21.916 us   |            }
  132.995069 |   0) + 35.042 us   |          }
  132.995070 |   0) + 39.209 us   |        }
  132.995072 |   0) + 51.166 us   |      }
  132.995075 |   0) + 67.375 us   |    }
  132.995077 |   0) + 76.333 us   |  }

  • I've seen this page before.

    8.1 refers to transmission issues
    8.2 and 8.4 refer to a scenario with a USB HUB
    8.3 - I've applied both patches, without effect
  • I have asked an USB expert to help on this.
  • Thanks for the detailed report. I will try to replicate the issue and debug it here.

    Andrzej Szombierski said:

    === SOF 244

    IN addr 4 endpoint 2   # MUSB sends one IN token on the isochronous endpoint
    DATA0 (0 bytes) # receives a response

    Do you mean in SOF244, EP2 receives 0 byte packet? EP2 is the Isoch IN EP from the camera, right? I am not sure how this would happen, based on the UVC Specs, echo packet has 12 bytes header, so the minimum UVC packet size should be 12, not 0.

    If indeed EP2 received 0-byte packet (I have never seen it happened on UVC cameras), you might hit on a sw bug while handling zero-length packet, please refer to TRM Section 16.3.9.5 for the special case. I will check on this.

  • I remembered I had issues with Yavta before. Have you tried to test with gstreamer pipeline if the same issue happens? You can run the following command on the SDK filesystem.

    # gst-launch -v v4l2src device=/dev/video0 num-buffers=5 ! 'video/x-raw-yuv,width=320,height=240' ! fakesink
  • Bin Liu said:

    Do you mean in SOF244, EP2 receives 0 byte packet? EP2 is the Isoch IN EP from the camera, right? I am not sure how this would happen, based on the UVC Specs, echo packet has 12 bytes header, so the minimum UVC packet size should be 12, not 0.

    If indeed EP2 received 0-byte packet (I have never seen it happened on UVC cameras), you might hit on a sw bug while handling zero-length packet, please refer to TRM Section 16.3.9.5 for the special case. I will check on this.

    Well, this *is* curious. I just assumed that a zero-length packet is ok unless the camera has something to say. In the "working" case, there is a long stream of zero-length packets between frames.

    Anyway, on the logitech camera the bug occurs without zero-length ISO packets. There are zero-length communications on the control endpoint, but this should not be an issue, right?

    IN addr 3 endpoint 0
    DATA1 (0 bytes)
    ACK
    SETUP addr 3 endpoint 0
    DATA0 (8 bytes)
    ACK
    IN addr 3 endpoint 0
    DATA1 (0 bytes)
    ACK

    === SOF 526

    === SOF 527

    === SOF 528

    IN addr 3 endpoint 1
    DATA0 (12 bytes)

    === SOF 529

    === SOF 530

    === SOF 531

    === SOF 532

    === SOF 533

    === SOF 534

    === SOF 535

    === SOF 536

    IN addr 3 endpoint 7
    NAK

    === SOF 537

    === SOF 538

  • The issue is not yavta-specific, GStreamer triggers the bug as well.
  • Andrzej Szombierski said:

    Well, this *is* curious. I just assumed that a zero-length packet is ok unless the camera has something to say. In the "working" case, there is a long stream of zero-length packets between frames.

    Anyway, on the logitech camera the bug occurs without zero-length ISO packets.

    Do you mean the logitech camera does not have zero-length Isoch packets, but the other camera does?

    Andrzej Szombierski said:
    There are zero-length communications on the control endpoint, but this should not be an issue, right?

    Correct, zero-length packets on control endpoint is normal.

    I am not an expert of UVC Specs, and only read it once at years ago while debugging a UVC issue. Please first let my try to replicate the issue with my pro900 and see what causes the problem.

  • Bin Liu said:

    Do you mean the logitech camera does not have zero-length Isoch packets, but the other camera does?

    Yes. The logitech camera always sends the 12-byte UVC header. The other camera sends 0-byte packets instead. Both of them trigger the same bug, or at least a bug that looks the same.

  • Did you manage to reproduce the issue?
  • Andrzej, yes, I believe I am able to see the same issue, but the debugging process has been slow, the cppi drivers in both MUSB and DMA-Engine modules do not have much debug logging facility, I have to add those in, I have also been distracted by other tasks. I will keep you posted once I have progress on debugging on this problem.

  • Andrzej,

    Please try the following patch and let me know if it fixes the issue for you.

    diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c
    index 190a3f8..40947da 100644
    --- a/drivers/usb/musb/musb_cppi41.c
    +++ b/drivers/usb/musb/musb_cppi41.c
    @@ -582,6 +582,9 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel)
            } else {
                    cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREQ_NONE);
    
    +               /* delay to drain to cppi dma pipeline for isoch */
    +               udelay(50);
    +
                    csr = musb_readw(epio, MUSB_RXCSR);
                    csr &= ~(MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_DMAENAB);
                    musb_writew(epio, MUSB_RXCSR, csr);
    
  • This patch doesn't apply cleanly on my kernel (ti-linux-kernel 3.14.31 with various patches). Which version were you using?


    I've tried to apply it manually, by adding these two lines in cppi41_dma_channel_abort, in the else branch for the first if(is_tx)

                    cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREG_NONE);
                    udelay(50);

    but the problem persists.

  • I was on SDK8.0 kernel, plus patch #8.3 in http://processors.wiki.ti.com/index.php/Sitara_Linux_MUSB_Issues.

    In your new test with your manual patch, when the problem happens, do you see the MUSB cppi dma interrupt still happen?

    # grep dma-con /proc/interrupts

  • Ok, that was the missing piece. I was missing patch #8.3 - that's why your patch couldn't be applied cleanly.
    With #8.3 and your patch the bug seems to be gone - I will leave it for an overnight stress-test just to be sure.
  • Well, it seems that I was lucky in the previous test. The bug is still there.

    I've checked with my kernel and the one from processor sdk 01. I'm not sure where to find SDK 8.0.
    In both cases I needed to manually fixup some constant names (AUTOREQ -> AUTOREG) in order to apply the patches and build the kernel.

    After the freeze the interrupt count stays fixed, even when starting/stopping yavta and (un)plugging the camera.
  • Andrzej,


    I believe the kernel in p-sdk v01 and AMSDK v8.0 is very very close if not the same. The macro name change is covered in patch #8.3.a in the wiki I mentioned. It seems you only applied #8.3.b.

    Can you please change the delay in the new patch from 50 to 250 and re-run the test? 250us was the original delay value in TI 3.2 kernel, but it seems 50us works on my camera, but it could be too aggressive.

  • Ok, with udelay(250) it works flawlessly. Tested for about 50 hours with no problems.

    Thank you.

  • Andrzej,

    Thanks for the validation and update. I will push the patch to kernel mainline.