Skip to content

Commit 044818a

Browse files
l1kgregkh
authored andcommitted
xhci: Set DESI bits in ERDP register correctly
When using more than one Event Ring segment (ERSTSZ > 1), software shall set the DESI bits in the ERDP register to the number of the segment to which the upper ERDP bits are pointing. The xHC may use the DESI bits as a shortcut to determine whether it needs to check for an Event Ring Full condition: If it's enqueueing events in a different segment, it need not compare its internal Enqueue Pointer with the Dequeue Pointer in the upper bits of the ERDP register (sec 5.5.2.3.3). Not setting the DESI bits correctly can result in the xHC enqueueing events past the Dequeue Pointer. On Renesas uPD720201 host controllers, incorrect DESI bits cause an interrupt storm. For comparison, VIA VL805 host controllers do not exhibit such problems. Perhaps they do not take advantage of the optimization afforded by the DESI bits. To fix the issue, assign the segment number to each struct xhci_segment in xhci_segment_alloc(). When advancing the Dequeue Pointer in xhci_update_erst_dequeue(), write the segment number to the DESI bits. On driver probe, set the DESI bits to zero in xhci_set_hc_event_deq() as processing starts in segment 0. Likewise on driver teardown, clear the DESI bits to zero in xhci_free_interrupter() when clearing the upper bits of the ERDP register. Previously those functions (incorrectly) treated the DESI bits as if they're declared RsvdP. Signed-off-by: Lukas Wunner <lukas@wunner.de> Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Link: https://lore.kernel.org/r/20231019102924.2797346-5-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent e2d3ac9 commit 044818a

File tree

3 files changed

+13
-15
lines changed

3 files changed

+13
-15
lines changed

drivers/usb/host/xhci-mem.c

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
3030
unsigned int cycle_state,
3131
unsigned int max_packet,
32+
unsigned int num,
3233
gfp_t flags)
3334
{
3435
struct xhci_segment *seg;
@@ -60,6 +61,7 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
6061
for (i = 0; i < TRBS_PER_SEGMENT; i++)
6162
seg->trbs[i].link.control = cpu_to_le32(TRB_CYCLE);
6263
}
64+
seg->num = num;
6365
seg->dma = dma;
6466
seg->next = NULL;
6567

@@ -324,23 +326,25 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
324326
enum xhci_ring_type type, unsigned int max_packet, gfp_t flags)
325327
{
326328
struct xhci_segment *prev;
329+
unsigned int num = 0;
327330
bool chain_links;
328331

329332
/* Set chain bit for 0.95 hosts, and for isoc rings on AMD 0.96 host */
330333
chain_links = !!(xhci_link_trb_quirk(xhci) ||
331334
(type == TYPE_ISOC &&
332335
(xhci->quirks & XHCI_AMD_0x96_HOST)));
333336

334-
prev = xhci_segment_alloc(xhci, cycle_state, max_packet, flags);
337+
prev = xhci_segment_alloc(xhci, cycle_state, max_packet, num, flags);
335338
if (!prev)
336339
return -ENOMEM;
337-
num_segs--;
340+
num++;
338341

339342
*first = prev;
340-
while (num_segs > 0) {
343+
while (num < num_segs) {
341344
struct xhci_segment *next;
342345

343-
next = xhci_segment_alloc(xhci, cycle_state, max_packet, flags);
346+
next = xhci_segment_alloc(xhci, cycle_state, max_packet, num,
347+
flags);
344348
if (!next) {
345349
prev = *first;
346350
while (prev) {
@@ -353,7 +357,7 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
353357
xhci_link_segments(prev, next, type, chain_links);
354358

355359
prev = next;
356-
num_segs--;
360+
num++;
357361
}
358362
xhci_link_segments(prev, *first, type, chain_links);
359363
*last = prev;
@@ -1801,7 +1805,6 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
18011805
{
18021806
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
18031807
size_t erst_size;
1804-
u64 tmp64;
18051808
u32 tmp;
18061809

18071810
if (!ir)
@@ -1824,9 +1827,7 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
18241827
tmp &= ERST_SIZE_MASK;
18251828
writel(tmp, &ir->ir_set->erst_size);
18261829

1827-
tmp64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
1828-
tmp64 &= (u64) ERST_PTR_MASK;
1829-
xhci_write_64(xhci, tmp64, &ir->ir_set->erst_dequeue);
1830+
xhci_write_64(xhci, ERST_EHB, &ir->ir_set->erst_dequeue);
18301831
}
18311832

18321833
/* free interrrupter event ring */
@@ -1933,23 +1934,19 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
19331934

19341935
static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
19351936
{
1936-
u64 temp;
19371937
dma_addr_t deq;
19381938

19391939
deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg,
19401940
ir->event_ring->dequeue);
19411941
if (!deq)
19421942
xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr.\n");
19431943
/* Update HC event ring dequeue pointer */
1944-
temp = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
1945-
temp &= ERST_PTR_MASK;
19461944
/* Don't clear the EHB bit (which is RW1C) because
19471945
* there might be more events to service.
19481946
*/
1949-
temp &= ~ERST_EHB;
19501947
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
19511948
"// Write event ring dequeue pointer, preserving EHB bit");
1952-
xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp,
1949+
xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK),
19531950
&ir->ir_set->erst_dequeue);
19541951
}
19551952

drivers/usb/host/xhci-ring.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3018,7 +3018,7 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
30183018
return;
30193019

30203020
/* Update HC event ring dequeue pointer */
3021-
temp_64 &= ERST_DESI_MASK;
3021+
temp_64 = ir->event_ring->deq_seg->num & ERST_DESI_MASK;
30223022
temp_64 |= ((u64) deq & (u64) ~ERST_PTR_MASK);
30233023
}
30243024

drivers/usb/host/xhci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1518,6 +1518,7 @@ struct xhci_segment {
15181518
union xhci_trb *trbs;
15191519
/* private to HCD */
15201520
struct xhci_segment *next;
1521+
unsigned int num;
15211522
dma_addr_t dma;
15221523
/* Max packet sized bounce buffer for td-fragmant alignment */
15231524
dma_addr_t bounce_dma;

0 commit comments

Comments
 (0)