Skip to content

Commit 3c1b210

Browse files
author
Desnes Nunes
committed
usb: xhci: remove '0' write to write-1-to-clear register
JIRA: https://issues.redhat.com/browse/RHEL-116016 commit e1db856 Author: Niklas Neronin <niklas.neronin@linux.intel.com> Date: Thu, 15 May 2025 16:56:14 +0300 xHCI specification 1.2, section 5.5.2.1. Interrupt Pending bit is RW1C (Write-1-to-clear), which means that writing '0' to is has no effect and is removed. The Interrupt Pending (IP) bit is cleared at the start of interrupt handling; xhci_clear_interrupt_pending(). This could theoretically cause a new interrupt to be issued before the xhci driver reaches the interrupter disable functions. To address this, the IP bit is read after Interrupt Enable is disabled, and a debug message is issued if the IP bit is still set. Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com> Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Link: https://lore.kernel.org/r/20250515135621.335595-18-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Desnes Nunes <desnesn@redhat.com>
1 parent ebca722 commit 3c1b210

File tree

4 files changed

+10
-9
lines changed

4 files changed

+10
-9
lines changed

drivers/usb/host/xhci-hub.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1907,7 +1907,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
19071907
* prevent port event interrupts from interfering
19081908
* with usb2 port resume process
19091909
*/
1910-
xhci_disable_interrupter(xhci->interrupters[0]);
1910+
xhci_disable_interrupter(xhci, xhci->interrupters[0]);
19111911
disabled_irq = true;
19121912
}
19131913
}

drivers/usb/host/xhci-ring.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3166,7 +3166,7 @@ void xhci_skip_sec_intr_events(struct xhci_hcd *xhci,
31663166
dma_addr_t deq;
31673167

31683168
/* disable irq, ack pending interrupt and ack all pending events */
3169-
xhci_disable_interrupter(ir);
3169+
xhci_disable_interrupter(xhci, ir);
31703170

31713171
/* last acked event trb is in erdp reg */
31723172
erdp_reg = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);

drivers/usb/host/xhci.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,6 @@ int xhci_enable_interrupter(struct xhci_interrupter *ir)
331331
return -EINVAL;
332332

333333
iman = readl(&ir->ir_set->irq_pending);
334-
iman &= ~IMAN_IP;
335334
iman |= IMAN_IE;
336335
writel(iman, &ir->ir_set->irq_pending);
337336

@@ -340,19 +339,21 @@ int xhci_enable_interrupter(struct xhci_interrupter *ir)
340339
return 0;
341340
}
342341

343-
int xhci_disable_interrupter(struct xhci_interrupter *ir)
342+
int xhci_disable_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
344343
{
345344
u32 iman;
346345

347346
if (!ir || !ir->ir_set)
348347
return -EINVAL;
349348

350349
iman = readl(&ir->ir_set->irq_pending);
351-
iman &= ~IMAN_IP;
352350
iman &= ~IMAN_IE;
353351
writel(iman, &ir->ir_set->irq_pending);
354352

355-
readl(&ir->ir_set->irq_pending);
353+
iman = readl(&ir->ir_set->irq_pending);
354+
if (iman & IMAN_IP)
355+
xhci_dbg(xhci, "%s: Interrupt pending\n", __func__);
356+
356357
return 0;
357358
}
358359

@@ -754,7 +755,7 @@ void xhci_stop(struct usb_hcd *hcd)
754755
"// Disabling event ring interrupts");
755756
temp = readl(&xhci->op_regs->status);
756757
writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
757-
xhci_disable_interrupter(ir);
758+
xhci_disable_interrupter(xhci, ir);
758759

759760
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory");
760761
xhci_mem_cleanup(xhci);
@@ -1189,7 +1190,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool power_lost, bool is_auto_resume)
11891190
xhci_dbg(xhci, "// Disabling event ring interrupts\n");
11901191
temp = readl(&xhci->op_regs->status);
11911192
writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
1192-
xhci_disable_interrupter(xhci->interrupters[0]);
1193+
xhci_disable_interrupter(xhci, xhci->interrupters[0]);
11931194

11941195
xhci_dbg(xhci, "cleaning up memory\n");
11951196
xhci_mem_cleanup(xhci);

drivers/usb/host/xhci.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1900,7 +1900,7 @@ int xhci_alloc_tt_info(struct xhci_hcd *xhci,
19001900
int xhci_set_interrupter_moderation(struct xhci_interrupter *ir,
19011901
u32 imod_interval);
19021902
int xhci_enable_interrupter(struct xhci_interrupter *ir);
1903-
int xhci_disable_interrupter(struct xhci_interrupter *ir);
1903+
int xhci_disable_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir);
19041904

19051905
/* xHCI ring, segment, TRB, and TD functions */
19061906
dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb);

0 commit comments

Comments
 (0)