On Sat, Apr 18, 2020 at 02:01:14PM +0200, Patrick Wildt wrote:
> On Tue, Apr 14, 2020 at 06:42:53PM +0000, Mikolaj Kucharski wrote:
> > On Tue, Apr 14, 2020 at 11:06:00AM +0200, Patrick Wildt wrote:
> > > On Mon, Apr 13, 2020 at 09:36:04PM +0200, Mark Kettenis wrote:
> > > > Can you print the status (full 32 bits) of that particular QTD?
> > >
> > > Yeah, I wish I could see the status field for each sqtd in that
> > > chain.
> >
> > XXX #1# ehci_idone: len=4 actlen=4294951308, xf_actlen=0, status=0x8d00,
> > sqtd_count=3
> > XXX #2# ehci_idone: x_actlen=4294951304, sqtd_len=8, ehci_qtd_len=16000,
> > status=0xbe808d00, qtd_status=0xbe808d00, sqtd_count=1
> > XXX #2# ehci_idone: x_actlen=4294951308, sqtd_len=4, ehci_qtd_len=0,
> > status=0xc00, qtd_status=0xc00, sqtd_count=2
> > XXX #2# ehci_idone: x_actlen=4294951308, sqtd_len=0, ehci_qtd_len=0,
> > status=0x8d00, qtd_status=0x8d00, sqtd_count=3
> > panic: _dmamap_sync: ran off map!
>
> Thanks for the information! I'll try and see if I can find what's
> happening. But yeah, that's good information. This is a control
> transfers, which has 3 transfer descriptors.
>
> The three TDs should be: SETUP, DATA (because of len=4), and STATUS.
>
> As you can see, the middle one, DATA, has a len of 4, and the BYTES
> field in the status is 0, indicating that the transfer completed.
>
> Then we have STATUS, which has no len, looks just fine as well.
>
> But the first one, the SETUP, is weird. The len is fine, 8 bytes,
> but ehci_qtd_len looks completely off, the BYTES field also says
> "lots of bytes remaining". This is where we fuck up, I suppose.
>
> What's weird is that we actually account it, because we have this
> check:
>
> if (EHCI_QTD_GET_PID(status) != EHCI_QTD_PID_SETUP)
> actlen += sqtd->len - EHCI_QTD_GET_BYTES(status);
>
> But it looks like the status field on the SETUP descriptor does
> not say PID_SETUP, but PID_IN. Did the DMA controller change the
> bit? Or did someone else overwrite it?
>
> Patrick
I'm kinda stuck with this. I added KASSERT()s in places where I think
condtions should be checked and otherwise kernel should panic. Obviously
as I can trigger bogus condition I ended up with following ddb trace:
urtwn0: SCAN -> INIT
XXX S1 ehci_idone: actlen=4, sqtd_len=0, ehci_qtd_len=16000, status=0x3e808d00
XXX S2 ehci_idone: actlen=-15996, sqtd_len=0, ehci_qtd_len=16000,
status=0x3e808d00
panic: kernel diagnostic assertion "sqtd_len >= ehci_qtd_len" failed: file
"/home/mkucharski/src/sys/dev/usb/ehci.c", line 915
...
db_enter() at panic+0x14c
panic() at ehci_idone+0x264
ehci_isoc_idone() at ehci_softintr+0x158
ehci_softintr() at softintr_biglock_wrap+0x1c
softintr_biglock_wrap() at softintr_dispatch+0x9c
softintr_dispatch() at arm_do_pending_intr+0xa8
arm_do_pending_intr() at ampintc_irq_handler+0x178
This is retyped by hand from a glass console, be aware of typos.
I don't understand why ehci_idone() goes to ehci_isoc_idone() in above
ddb trace output.
Index: sys/dev/usb/ehci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ehci.c,v
retrieving revision 1.210
diff -u -p -u -r1.210 ehci.c
--- sys/dev/usb/ehci.c 3 Apr 2020 20:11:47 -0000 1.210
+++ sys/dev/usb/ehci.c 1 Jun 2020 06:19:27 -0000
@@ -870,6 +870,7 @@ ehci_idone(struct usbd_xfer *xfer)
struct ehci_soft_qtd *sqtd;
u_int32_t status = 0, nstatus = 0;
int actlen, cerr;
+ u_int32_t sqtd_len, ehci_qtd_len;
#ifdef DIAGNOSTIC
{
@@ -899,8 +900,20 @@ ehci_idone(struct usbd_xfer *xfer)
if (sqtd->qtd.qtd_next == htole32(EHCI_LINK_TERMINATE) &&
EHCI_QTD_GET_BYTES(status) == 0)
status &= ~EHCI_QTD_HALTED;
- if (EHCI_QTD_GET_PID(status) != EHCI_QTD_PID_SETUP)
- actlen += sqtd->len - EHCI_QTD_GET_BYTES(status);
+ if (EHCI_QTD_GET_PID(status) != EHCI_QTD_PID_SETUP) {
+ sqtd_len = sqtd->len;
+ ehci_qtd_len = EHCI_QTD_GET_BYTES(status);
+ if (ehci_qtd_len > sqtd_len) {
+ printf("XXX S1 %s: actlen=%d, sqtd_len=%u,
ehci_qtd_len=%u, status=0x%x\n",
+ __func__, actlen, sqtd_len,
ehci_qtd_len, status);
+ }
+ actlen += sqtd_len - ehci_qtd_len;
+ if (ehci_qtd_len > sqtd_len) {
+ printf("XXX S2 %s: actlen=%d, sqtd_len=%u,
ehci_qtd_len=%u, status=0x%x\n",
+ __func__, actlen, sqtd_len,
ehci_qtd_len, status);
+ }
+ KASSERT(sqtd_len >= ehci_qtd_len);
+ }
}
cerr = EHCI_QTD_GET_CERR(status);
Index: sys/dev/usb/usbdi.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbdi.c,v
retrieving revision 1.106
diff -u -p -u -r1.106 usbdi.c
--- sys/dev/usb/usbdi.c 3 Apr 2020 20:11:47 -0000 1.106
+++ sys/dev/usb/usbdi.c 1 Jun 2020 06:19:49 -0000
@@ -735,13 +735,12 @@ usb_transfer_complete(struct usbd_xfer *
if (polling)
pipe->running = 0;
-#ifdef DIAGNOSTIC
if (xfer->actlen > xfer->length) {
printf("%s: actlen > len %u > %u\n", __func__, xfer->actlen,
xfer->length);
+ KASSERT(xfer->actlen <= xfer->length);
xfer->actlen = xfer->length;
}
-#endif
if (usbd_xfer_isread(xfer) && xfer->actlen != 0 &&
(xfer->flags & USBD_NO_COPY) == 0)
--
Regards,
Mikolaj