mirror of
https://github.com/memtest86plus/memtest86plus.git
synced 2026-08-26 13:17:12 -05:00
xhci: Reposition the control ring dequeue from the enqueue state
The two-step address sequence (BLOCK SET ADDRESS pass, then real ADDRESS_DEVICE pass after reading the first 8 bytes of the device descriptor) ran three TRBs on the control ring in between. The hard-coded 'tr_dequeue_ptr += 3 * sizeof(xhci_trb_t)' had to move the dequeue pointer in the input context past them, because the second ADDRESS_DEVICE command copies the whole input context into the slot context and would otherwise reset the dequeue to the head of the ring, making the controller re-execute the three stale TRBs. That arithmetic is fragile: it silently breaks as soon as the ring wraps (the cycle bit would no longer be valid) or fewer/more TRBs are consumed. The ring already tracks its true position in ep_tr->enqueue_state, so the dequeue pointer is now computed from it with the same index/cycle decomposition used to reposition a halted endpoint in reset_endpoint.
This commit is contained in:
+14
-1
@@ -904,7 +904,20 @@ static bool assign_address(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_
|
||||
ep_context->max_packet_size = (device_speed == USB_SPEED_SUPER)
|
||||
? (1 << device->max_packet_size)
|
||||
: device->max_packet_size;
|
||||
ep_context->tr_dequeue_ptr += 3 * sizeof(xhci_trb_t);
|
||||
|
||||
// The GET_DESCRIPTOR request just completed consumed three TRBs on
|
||||
// the control ring, so the ring's enqueue state (and the hardware
|
||||
// dequeue with it) has moved on. The input context is about to be
|
||||
// copied into the slot context by the second ADDRESS_DEVICE
|
||||
// command, which would otherwise reset the control endpoint
|
||||
// dequeue pointer to the head of the ring and make the controller
|
||||
// re-execute the three stale TRBs. Reposition the dequeue pointer
|
||||
// at the current enqueue state instead of hard-coding the number
|
||||
// of TRBs consumed; the same decomposition of the enqueue state
|
||||
// into ring index and cycle is used when repositioning a halted
|
||||
// endpoint (see reset_endpoint).
|
||||
ep_context->tr_dequeue_ptr = (uintptr_t)(&ep_tr->tr[ep_tr->enqueue_state % EP_TR_SIZE])
|
||||
| (ep_tr->enqueue_state / EP_TR_SIZE);
|
||||
|
||||
fetch_length = sizeof(usb_device_desc_t);
|
||||
command_flags = 0;
|
||||
|
||||
Reference in New Issue
Block a user