raspberrypi / linux

Kernel source tree for Raspberry Pi-provided kernel builds. Issues unrelated to the linux kernel should be posted on the community forum at https://forums.raspberrypi.com/
Other
11.11k stars 4.98k forks source link

Losing data on USB bulk pipes with MIDI keyboard after data toggle error #4986

Closed rsta2 closed 2 years ago

rsta2 commented 2 years ago

Describe the bug

When I attach a M-AUDIO Keystation Mini 32 MK3 USB MIDI keyboard to a Raspberry Pi 3 Model B and continuously press the MOD (modulation) button, from time to time a MIDI event is not received by the USB host, and is missing in the row of modulation events. Because the USB MIDI transfer takes place via an USB bulk pipe, this is an error. Bulk pipes are normally safe by definition.

I was able to reproduce with a debug kernel, that this data loss happens, when a USB data toggle error occurs.

Steps to reproduce the behaviour

  1. Build the attached small C-program.
  2. Attach a M-AUDIO Keystation Mini 32 MK3
  3. Run usb-midi-mod-test < /dev/midi1 (may be midi2 instead)
  4. Press the MOD button for one second
  5. Release the MOD button and wait one second
  6. Go to 4.

The program checks the received MIDI MOD messages and reports, when a message with the wrong index has been received, like that: 23??. This happens after some time.

usb-midi-mod-test.zip

Device (s)

Raspberry Pi 3 Mod. B

System

pi@raspberrypi-rene:~ $ cat /etc/rpi-issue 
Raspberry Pi reference 2021-10-30
Generated using pi-gen, https://github.com/RPi-Distro/pi-gen, 288b21fc27e128ea6b330777aca68e0061ebf4fe, stage4
pi@raspberrypi-rene:~ $ vcgencmd version
Mar 24 2022 13:20:54 
Copyright (c) 2012 Broadcom
version e5a963efa66a1974127860b42e913d2374139ff5 (clean) (release) (start)
pi@raspberrypi-rene:~ $ uname -a
Linux raspberrypi-rene 5.15.32-v7+ #1538 SMP Thu Mar 31 19:38:48 BST 2022 armv7l GNU/Linux

Logs

pi@raspberrypi-rene:~ $ sudo lsusb -t
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/5p, 480M
        |__ Port 1: Dev 3, If 0, Class=Vendor Specific Class, Driver=smsc95xx, 480M
        |__ Port 2: Dev 4, If 0, Class=Audio, Driver=snd-usb-audio, 12M
        |__ Port 2: Dev 4, If 1, Class=Audio, Driver=snd-usb-audio, 12M
        |__ Port 4: Dev 5, If 1, Class=Human Interface Device, Driver=usbhid, 1.5M
        |__ Port 4: Dev 5, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M
pi@raspberrypi-rene:~ $ sudo lsusb -v -s 4

Bus 001 Device 004: ID 0763:3111 M-Audio Keystation Mini 32 MK3
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.11
  bDeviceClass            0 
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0         8
  idVendor           0x0763 M-Audio
  idProduct          0x3111 
  bcdDevice            1.11
  iManufacturer           1 M-Audio
  iProduct                2 Keystation Mini 32 MK3
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x0065
    bNumInterfaces          2
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0x80
      (Bus Powered)
    MaxPower               64mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           0
      bInterfaceClass         1 Audio
      bInterfaceSubClass      1 Control Device
      bInterfaceProtocol      0 
      iInterface              0 
      AudioControl Interface Descriptor:
        bLength                 9
        bDescriptorType        36
        bDescriptorSubtype      1 (HEADER)
        bcdADC               1.00
        wTotalLength       0x0009
        bInCollection           1
        baInterfaceNr(0)        1
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         1 Audio
      bInterfaceSubClass      3 MIDI Streaming
      bInterfaceProtocol      0 
      iInterface              0 
      MIDIStreaming Interface Descriptor:
        bLength                 7
        bDescriptorType        36
        bDescriptorSubtype      1 (HEADER)
        bcdADC               1.00
        wTotalLength       0x0041
      MIDIStreaming Interface Descriptor:
        bLength                 6
        bDescriptorType        36
        bDescriptorSubtype      2 (MIDI_IN_JACK)
        bJackType               1 Embedded
        bJackID                 1
        iJack                   0 
      MIDIStreaming Interface Descriptor:
        bLength                 6
        bDescriptorType        36
        bDescriptorSubtype      2 (MIDI_IN_JACK)
        bJackType               2 External
        bJackID                 2
        iJack                   0 
      MIDIStreaming Interface Descriptor:
        bLength                 9
        bDescriptorType        36
        bDescriptorSubtype      3 (MIDI_OUT_JACK)
        bJackType               1 Embedded
        bJackID                 9
        bNrInputPins            1
        baSourceID( 0)          2
        BaSourcePin( 0)         1
        iJack                   0 
      MIDIStreaming Interface Descriptor:
        bLength                 9
        bDescriptorType        36
        bDescriptorSubtype      3 (MIDI_OUT_JACK)
        bJackType               2 External
        bJackID                10
        bNrInputPins            1
        baSourceID( 0)          1
        BaSourcePin( 0)         1
        iJack                   0 
      Endpoint Descriptor:
        bLength                 9
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
        bRefresh                0
        bSynchAddress           0
        MIDIStreaming Endpoint Descriptor:
          bLength                 5
          bDescriptorType        37
          bDescriptorSubtype      1 (GENERAL)
          bNumEmbMIDIJack         1
          baAssocJackID( 0)       9
      Endpoint Descriptor:
        bLength                 9
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
        bRefresh                0
        bSynchAddress           0
        MIDIStreaming Endpoint Descriptor:
          bLength                 5
          bDescriptorType        37
          bDescriptorSubtype      1 (GENERAL)
          bNumEmbMIDIJack         1
          baAssocJackID( 0)       1
can't get debug descriptor: Resource temporarily unavailable
Device Status:     0x0000
  (Bus Powered)

Additional context

No response

P33M commented 2 years ago

What happens if you add dwc_otg.nak_holdoff=0 to /boot/cmdline.txt (and reboot)?

rsta2 commented 2 years ago

With dwc_otg.nak_holdoff=0 no problems any more. Thanks. For interest, what does this do?

P33M commented 2 years ago

By default, the dwc_otg code will ignore any FS control or bulk endpoint transfer that completes with a NAK (no data available) for a set period of time, defaulting to 1ms (8x125us microframes). This avoids high interrupt loads for devices that sit for ages before returning data in response to a request, as is usual for usb-serial dongles or devices that take ages to initialise.

The vast majority of devices have no issue with an extended polling interval, so on Pi 0 / 1 / 2 / 3 the relaxed polling interval frees up significant CPU time for other purposes. This device probably has very small endpoint buffers (or only single-buffers packets).

Edit: if the resulting increase in interrupt loading on your Pi 3 setup causes issues, nak_holdoff can be set to 1 or 2 to provide a compromise between available CPU and keeping the keyboard happy.

rsta2 commented 2 years ago

Thanks for explaining this!

rsta2 commented 2 years ago

OK, 1 does work too, 2 does not work. Thanks.