Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

xhci: update event ring dequeue pointer position to controller correctly

The event ring dequeue pointer field (ERDP) in xHC hardware is used to
inform controller how far the driver has processed events on the event
ring.

In the case all events are handled and event ring is empty then the
address of the TRB after the last processed one should be written.
This TRB is both the enqueue and dequeue pointer.

But in case we are writing the ERDP in the middle of processing
several events then ERDP field should be written with the "up to and
including" address of the last handled event TRB.

Currenly each ERDP write by driver is done as if all events are handled
and ring is empty.

Fix this by adjusting the order when software dequeue "inc_deq()"
is called and hardware dequeue "xhci_update_erst_dequeue()" is updated.

Details in xhci 1.2 specification section 4.9.4:

"System software shall write the Event Ring Dequeue Pointer (ERDP)
register to inform the xHC that it has completed the processing of Event
TRBs up to and including the Event TRB referenced by the ERDP.

The detection of a Cycle bit mismatch in an Event TRB processed by
software indicates the location of the xHC Event Ring Enqueue Pointer
and that the Event Ring is empty. Software shall write the ERDP with
the address of this TRB to indicate that it has processed all Events
in the ring"

This change depends on fixes made to relocate inc_deq() calls captured
in the below commits:

commit 3321f84bfae0 ("xhci: simplify event ring dequeue tracking for
transfer events")

commit d1830364e963 ("xhci: Simplify event ring dequeue pointer update
for port change events")

Fixes: dc0ffbea5729 ("usb: host: xhci: update event ring dequeue pointer on purpose")
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Wesley Cheng <quic_wcheng@quicinc.com>
Link: https://lore.kernel.org/r/20240217001017.29969-6-quic_wcheng@quicinc.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Mathias Nyman and committed by
Greg Kroah-Hartman
e30e9ad9 143e64df

+13 -10
+13 -10
drivers/usb/host/xhci-ring.c
··· 3016 3016 return 0; 3017 3017 } 3018 3018 3019 - /* Update SW event ring dequeue pointer */ 3020 - inc_deq(xhci, ir->event_ring); 3021 - 3022 3019 /* Are there more items on the event ring? Caller will call us again to 3023 3020 * check. 3024 3021 */ ··· 3138 3141 * that clears the EHB. 3139 3142 */ 3140 3143 while (xhci_handle_event(xhci, ir) > 0) { 3141 - if (event_loop++ < TRBS_PER_SEGMENT / 2) 3142 - continue; 3143 - xhci_update_erst_dequeue(xhci, ir, false); 3144 + /* 3145 + * If half a segment of events have been handled in one go then 3146 + * update ERDP, and force isoc trbs to interrupt more often 3147 + */ 3148 + if (event_loop++ > TRBS_PER_SEGMENT / 2) { 3149 + xhci_update_erst_dequeue(xhci, ir, false); 3144 3150 3145 - /* ring is half-full, force isoc trbs to interrupt more often */ 3146 - if (ir->isoc_bei_interval > AVOID_BEI_INTERVAL_MIN) 3147 - ir->isoc_bei_interval = ir->isoc_bei_interval / 2; 3151 + if (ir->isoc_bei_interval > AVOID_BEI_INTERVAL_MIN) 3152 + ir->isoc_bei_interval = ir->isoc_bei_interval / 2; 3148 3153 3149 - event_loop = 0; 3154 + event_loop = 0; 3155 + } 3156 + 3157 + /* Update SW event ring dequeue pointer */ 3158 + inc_deq(xhci, ir->event_ring); 3150 3159 } 3151 3160 3152 3161 xhci_update_erst_dequeue(xhci, ir, true);