NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: port-evbarm/54696: Kernel panic in bus_dma.c on Raspberry Pi 3B/3B+



On 2019/11/14 08:39, Tetsuya Isaki wrote:
> At Wed, 13 Nov 2019 21:05:01 +0000 (UTC),
> Michael van Elst wrote:
>>  >[   153.534940] panic: kernel diagnostic assertion "len > 0 && offset + len <= map->dm_mapsize" failed: file "/usr/src/sys/arch/arm/arm32/bus_dma.c", line 1058 len 0 offset 0 mapsize 8192
>>  
>>  A zero length transfer. In that case it would be a uaudio (or audio?) bug.
>>  
>>  No idea why that should be aarch64-specific.
> 
> I think it's dwc2's issue.

Seconded.

> 
> According to report, calling usb_syncmem() with len == 0 in
> dwc2_device_start() caused a panic.
> 
>  sys/external/bsd/dwc2/dwc2.c:
>   929 dwc2_device_start(struct usbd_xfer *xfer)
>   930 {
>   :
>   966     if (xfertype == UE_CONTROL) {
>   :
>   990     } else {
>   :
>   995         len = xfer->ux_length;
>   996     }
>   :
>  1027     if (!(xfertype == UE_CONTROL && len == 0)) {
>  1028         dwc2_urb->usbdma = &xfer->ux_dmabuf;
>  1029         dwc2_urb->buf = KERNADDR(dwc2_urb->usbdma, 0);
>  1030         dwc2_urb->dma = DMAADDR(dwc2_urb->usbdma, 0);
>  1031
>  1032         usb_syncmem(&xfer->ux_dmabuf, 0, len,
>  1033             dir == UE_DIR_IN ?
>  1034             BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 
> 
> Here len passed to usb_syncmem() is xfer->ux_length.
> 
> According to reported backtrace,
> - dwc2_device_start(xfer) is called from dwc2_device_isoc_transfer(xfer).
> - dwc2_device_isoc_transfer(xfer) is called from usbd_transfer(xfer) as
>   up_methods->upm_transfer.
> - usbd_transfer(xfer) seems be called from uaudio_chan_rtransfer(ch)
>   and uaudio_chan_rtransfer(ch) seems be inline-expanded in
>   uaudio_trigger_input().
> 
>  sys/dev/usb/uaudio.c:
>  2838 uaudio_chan_rtransfer(struct chan *ch)
>  2839 {
>  :
>  2874     usbd_setup_isoc_xfer(cb->xfer, cb, cb->sizes, UAUDIO_NFRAMES, 0,
>  2875         uaudio_chan_rintr);
>  2876
>  2877     (void)usbd_transfer(cb->xfer);
>  2878 }
> 
> usbd_setup_isoc_xfer() initializes ux_length == 0.
> 
>   592 usbd_setup_isoc_xfer(struct usbd_xfer *xfer, void *priv, uint16_t
>       *frlengths,
>   593     uint32_t nframes, uint16_t flags, usbd_callback callback)
>   594 {
>   595     xfer->ux_priv = priv;
>   596     xfer->ux_buffer = NULL;
>   597     xfer->ux_length = 0;
>  
> And then see also similar (the same?) PR port-arm/54615,
> sc.dying%gmail.com@localhost wrote:
>>  At line 1032 of sys/external/bsd/dwc2/dwc2.c usb_syncmem is called.
>>
>>> 		usb_syncmem(&xfer->ux_dmabuf, 0, len,
>>> 		    dir == UE_DIR_IN ?
>>> 			BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
>>
>> len = xfer->ux_length, however, ux_length is always 0 for isoc transfers.
> 
> I just read source code and I have no environment.  But if my
> understanding is correct, I think that dwc2_device_start() needs
> to handle length == 0 properly.

This bug can be solved by wrapping above usb_syncmem with if (len != 0) {}
or by changing arm/arm32/bus_dma.c accept zero length sync like x86 does.

But the transfer length of isoc xfer is sum of xfer->ux_frlengths[i]
where i = 0.. xfer->ux_nframes - 1, not zero.
dwc2 should do this usb_syncmem if xfertype == UE_{INTERRUPT,BULK},
UE_CONTROL that has data phase (that is, len != 0), or if xfertype ==
UE_ISOCHRONOUS, should do usb_syncmem for each chunk of ux_frlengths.

However, the uaudio works with dwc2 even if avobe usb_syncmem is ignored.
I think dwc2 does usb_syncmem for isoc data buf somewhere else, but
I'm not sure where it is.

> 
> Thanks,
> ---
> Tetsuya Isaki <isaki%pastel-flower.jp@localhost / isaki%NetBSD.org@localhost>
> 


Home | Main Index | Thread Index | Old Index