Commit 0583bc77 authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman

USB: dwc2: write HCINT with INTMASK applied

dwc2_hc_n_intr() writes back INTMASK as read but evaluates it
with intmask applied. In stress testing this causes spurious
interrupts like this:

[Mon Aug 14 10:51:07 2023] dwc2 3f980000.usb: dwc2_hc_chhltd_intr_dma: Channel 7 - ChHltd set, but reason is unknown
[Mon Aug 14 10:51:07 2023] dwc2 3f980000.usb: hcint 0x00000002, intsts 0x04600001
[Mon Aug 14 10:51:08 2023] dwc2 3f980000.usb: dwc2_hc_chhltd_intr_dma: Channel 0 - ChHltd set, but reason is unknown
[Mon Aug 14 10:51:08 2023] dwc2 3f980000.usb: hcint 0x00000002, intsts 0x04600001
[Mon Aug 14 10:51:08 2023] dwc2 3f980000.usb: dwc2_hc_chhltd_intr_dma: Channel 4 - ChHltd set, but reason is unknown
[Mon Aug 14 10:51:08 2023] dwc2 3f980000.usb: hcint 0x00000002, intsts 0x04600001
[Mon Aug 14 10:51:08 2023] dwc2 3f980000.usb: dwc2_update_urb_state_abn(): trimming xfer length

Applying INTMASK prevents this. The issue exists in all versions of the
driver.
Signed-off-by: default avatarOliver Neukum <oneukum@suse.com>
Tested-by: default avatarIvan Ivanov <ivan.ivanov@suse.com>
Tested-by: default avatarAndrea della Porta <andrea.porta@suse.com>
Link: https://lore.kernel.org/r/20231115144514.15248-1-oneukum@suse.com
Cc: stable <stable@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 30ce1c03
...@@ -2015,15 +2015,17 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum) ...@@ -2015,15 +2015,17 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
{ {
struct dwc2_qtd *qtd; struct dwc2_qtd *qtd;
struct dwc2_host_chan *chan; struct dwc2_host_chan *chan;
u32 hcint, hcintmsk; u32 hcint, hcintraw, hcintmsk;
chan = hsotg->hc_ptr_array[chnum]; chan = hsotg->hc_ptr_array[chnum];
hcint = dwc2_readl(hsotg, HCINT(chnum)); hcintraw = dwc2_readl(hsotg, HCINT(chnum));
hcintmsk = dwc2_readl(hsotg, HCINTMSK(chnum)); hcintmsk = dwc2_readl(hsotg, HCINTMSK(chnum));
hcint = hcintraw & hcintmsk;
dwc2_writel(hsotg, hcint, HCINT(chnum));
if (!chan) { if (!chan) {
dev_err(hsotg->dev, "## hc_ptr_array for channel is NULL ##\n"); dev_err(hsotg->dev, "## hc_ptr_array for channel is NULL ##\n");
dwc2_writel(hsotg, hcint, HCINT(chnum));
return; return;
} }
...@@ -2032,11 +2034,9 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum) ...@@ -2032,11 +2034,9 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
chnum); chnum);
dev_vdbg(hsotg->dev, dev_vdbg(hsotg->dev,
" hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n", " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
hcint, hcintmsk, hcint & hcintmsk); hcintraw, hcintmsk, hcint);
} }
dwc2_writel(hsotg, hcint, HCINT(chnum));
/* /*
* If we got an interrupt after someone called * If we got an interrupt after someone called
* dwc2_hcd_endpoint_disable() we don't want to crash below * dwc2_hcd_endpoint_disable() we don't want to crash below
...@@ -2046,8 +2046,7 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum) ...@@ -2046,8 +2046,7 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
return; return;
} }
chan->hcint = hcint; chan->hcint = hcintraw;
hcint &= hcintmsk;
/* /*
* If the channel was halted due to a dequeue, the qtd list might * If the channel was halted due to a dequeue, the qtd list might
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment