Hi,
Dne 10. 01. 20 v 8:29 Pavel Hofman napsal(a):
Hi,
Together with dwc2 maintainer Minas Harutyunyan we have been
troubleshooting various issues of dwc2 on RPi4. We hit a problem where
the g_audio in capture (EP OUT, playback from USB host) requests req->
length larger than maxpacket*mc.
As a workaround we removed the check in dwc2/gadget.c, however that is
not a proper solution. Minas with his team decided to add a patch where
dwc2 will rejecting this type of wrong requests in dwc2_hsotg_ep_queue()
function, to not process these request at all. The f_uac2 + g_audio
gadget should restrain from sending such requests.
Steps to reproduce:
* Changing fs_epout_desc.bInterval in f_uac2.c from 4 (1ms) to 1 (125us)
- the goal is to maximize available throughput of the audio gadget
* Loading the g_audio module with c_srate=48000, c_ssize=2, c_chmask=2 -
i.e. standard 48kHz/16bit/2ch USB playback -> alsa capture
This combination produces mps=24 and mc=1 for EP OUT. Yet the audio
function driver sometimes queues request with req->length 192.
IMO the problem is here
https://github.com/torvalds/linux/blob/master/drivers/usb/gadget/function/f_uac2.c#L675
:
First wMaxPacketSize is correctly calculated for HS and FS. In my setup
it yields (confirmed by an added debug in set_ep_max_packet_size):
FS: ep_desc->wMaxPacketSize 192
HS: ep_desc->wMaxPacketSize 24
However, a few lines later the agdev->out_ep_maxpsize is set as maximum
from these two values
https://github.com/torvalds/linux/blob/master/drivers/usb/gadget/function/f_uac2.c#L700
:
agdev->out_ep_maxpsize = max_t(u16,
le16_to_cpu(fs_epout_desc.wMaxPacketSize),
le16_to_cpu(hs_epout_desc.wMaxPacketSize));
In g_audio_setup this value is used for max_psize
https://github.com/torvalds/linux/blob/master/drivers/usb/gadget/function/u_audio.c#L519
:
prm->max_psize = g_audio->out_ep_maxpsize;
And max_psize is used as req->length in u_audio_start_capture
https://github.com/torvalds/linux/blob/master/drivers/usb/gadget/function/u_audio.c#L379
:
req_len = prm->max_psize;
...
req->length = req_len;
192bytes (the value for FS) will be assigned here, instead of the
correct 24 bytes for HS. The reason it has worked so far is the original
bInterval=4 for HS which yields the same 192bytes as the original for
FS. But lowering the fs_epout_desc.bInterval reduces the packets, yet
the maximum of the two values is being used.
IMO the very same problem will be on u_audio playback side, the
preceeding line:
agdev->in_ep_maxpsize = max_t(u16,
le16_to_cpu(fs_epin_desc.wMaxPacketSize),
le16_to_cpu(hs_epin_desc.wMaxPacketSize));
Unfortunately I do not know the reason for selection of the maximum
value from FS and HS, I cannot create a patch. Very likely there is more
hidden know-how which I do not know.
Thanks a lot for looking at the issue.
With regards,
Pavel.