NetBSD-Bugs archive

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

kern/51199: XHCI driver flushes wrong memory during ring put



>Number:         51199
>Category:       kern
>Synopsis:       XHCI driver flushes wrong memory during ring put
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon May 30 21:30:00 +0000 2016
>Originator:     Sprow
>Release:        
>Organization:
>Environment:
>Description:
When putting a ring of TRBs into memory, xhci_ring_put() takes care to do it backwards to avoid confusing controllers. However, when the first TRB is written out (last) the offset passed to usb_syncmem() is the offset after the final TRB rather than the 0th TRB as required.

This is easiest to see when considering the initial call with just 1 TRB. ie. xr_ep = 0, and ntrbs = 1.
The function reduces to:

	ri = xr->xr_ep;
	ri++; /* <-- ie. 1, required since the for loop starts at 1 and post increments ri */

	/* Write any subsequent TRB first */
	for (i = 1; i < ntrbs; i++) { /* <-- ntrbs = 0, so this loop is skipped */
		usb_syncmem(&xr->xr_dma, XHCI_TRB_SIZE * ri, XHCI_TRB_SIZE * 1,
		    BUS_DMASYNC_PREWRITE);
		ri++;
	}

	/* Write the first TRB last */
	i = 0;
	usb_syncmem(&xr->xr_dma, XHCI_TRB_SIZE * ri, XHCI_TRB_SIZE * 1,
	    BUS_DMASYNC_PREWRITE); /* <-- oops, flushes the 1st TRB not the 0th */

	xr->xr_ep = ri;

obviously more complex cases (xr_ep != 0, ntrbs != 1) are similarly affected.
>How-To-Repeat:

>Fix:
--- xhci-1_46.c	2016-05-30 20:51:36 +0100
+++ xhci.c	2016-05-30 20:51:20 +0100
@@ -2559,7 +2559,7 @@
 	}
 
 	xhci_trb_put(&xr->xr_trb[xr->xr_ep], parameter, status, control);
-	usb_syncmem(&xr->xr_dma, XHCI_TRB_SIZE * ri, XHCI_TRB_SIZE * 1,
+	usb_syncmem(&xr->xr_dma, XHCI_TRB_SIZE * xr->xr_ep, XHCI_TRB_SIZE * 1,
 	    BUS_DMASYNC_PREWRITE);
 	xr->xr_cookies[xr->xr_ep] = cookie;



Home | Main Index | Thread Index | Old Index