]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[xhci] Consume event TRB before reporting completion to USB core
authorMichael Brown <mcb30@ipxe.org>
Mon, 19 Feb 2018 18:59:45 +0000 (18:59 +0000)
committerMichael Brown <mcb30@ipxe.org>
Mon, 19 Feb 2018 18:59:45 +0000 (18:59 +0000)
Reporting a completion via usb_complete() will pass control outside
the scope of xhci.c, and could potentially result in a further call to
xhci_event_poll() before returning from usb_complete().  Since we
currently update the event consumer counter only after calling
usb_complete(), this can result in duplicate completions and
consequent corruption of the submission TRB ring structures.

Fix by updating the event ring consumer counter before passing control
to usb_complete().

Reported-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Tested-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/drivers/usb/xhci.c

index 8bf3ca776d0a9742c4919cd8d2c1207d88403076..ecf8bf4d5e6e9f65b328d53422ef5d5dd2b0dcf1 100644 (file)
@@ -1711,6 +1711,9 @@ static void xhci_event_poll ( struct xhci_device *xhci ) {
                           ( event->cons >> shift ) ) & XHCI_TRB_C ) )
                        break;
 
+               /* Consume this TRB */
+               event->cons++;
+
                /* Handle TRB */
                type = ( trb->common.type & XHCI_TRB_TYPE_MASK );
                switch ( type ) {
@@ -1733,14 +1736,11 @@ static void xhci_event_poll ( struct xhci_device *xhci ) {
 
                default:
                        DBGC ( xhci, "XHCI %s unrecognised event %#x\n:",
-                              xhci->name, event->cons );
+                              xhci->name, ( event->cons - 1 ) );
                        DBGC_HDA ( xhci, virt_to_phys ( trb ),
                                   trb, sizeof ( *trb ) );
                        break;
                }
-
-               /* Consume this TRB */
-               event->cons++;
        }
 
        /* Update dequeue pointer if applicable */