From 870a8cc271cdcca0b45382ac6888c8005c0e93f3 Mon Sep 17 00:00:00 2001 From: tzuwen_chang Date: Thu, 13 Aug 2020 06:24:51 +0000 Subject: [PATCH] usb: dwc2: host: fix channel halt with unknown reason Channel halt with unknown reason happens in the following case: DWC2 + USB 2.0 HUB + HS Device + FS Device The HS Device is an optical fingerprint: usb 1-1.4: USB disconnect, device number 5 usb 1-1.4: new high-speed USB device number 6 using dwc2 usb 1-1.4: New USB device found, idVendor=28ed, idProduct=7000 usb 1-1.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3 usb 1-1.4: Product: Aratek Capture Device usb 1-1.4: Manufacturer: Aratek The FS Device is an ID card identification module: usb 1-1.3: new full-speed USB device number 9 using dwc2 usb 1-1.3: New USB device found, idVendor=0400, idProduct=c35a usb 1-1.3: New USB device strings: Mfr=0, Product=0, SerialNumber=0 When the issuse occurs, it always dump the error log: dwc2 ff540000.usb: dwc2_hc_chhltd_intr_dma: Channel 13 - ChHltd set, but reason is unknown dwc2 ff540000.usb: hcint 0x00000002, intsts 0x04000021 dwc2 ff540000.usb: dwc2_update_urb_state_abn(): trimming xfer length ------------[ cut here ]------------ WARNING: CPU: 0 PID: 0 at drivers/usb/dwc2/hcd.c:2796 dwc2_assign_and_init_hc+0x554/0x8e4() Modules linked in: bcmdhd CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.4.143 #3 Hardware name: Generic DT based system [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0x7c/0x9c) [] (dump_stack) from [] (warn_slowpath_common+0x88/0xb4) [] (warn_slowpath_common) from [] (warn_slowpath_null+0x18/0x20) [] (warn_slowpath_null) from [] (dwc2_assign_and_init_hc+0x554/0x8e4) [] (dwc2_assign_and_init_hc) from [] (dwc2_hcd_select_transactions+0xe4/0x178) [] (dwc2_hcd_select_transactions) from [] (dwc2_release_channel+0x1b8/0x1cc) [] (dwc2_release_channel) from [] (dwc2_hc_n_intr+0x4a0/0x728) [] (dwc2_hc_n_intr) from [] (dwc2_handle_hcd_intr+0x4ac/0x4d8) [] (dwc2_handle_hcd_intr) from [] (usb_hcd_irq+0x24/0x38) [] (usb_hcd_irq) from [] (handle_irq_event_percpu+0xa8/0x28c) [] (handle_irq_event_percpu) from [] (handle_irq_event+0x38/0x5c) [] (handle_irq_event) from [] (handle_fasteoi_irq+0xa8/0x124) [] (handle_fasteoi_irq) from [] (generic_handle_irq+0x18/0x28) [] (generic_handle_irq) from [] (__handle_domain_irq+0x88/0xb0) [] (__handle_domain_irq) from [] (gic_handle_irq+0x44/0x74) [] (gic_handle_irq) from [] (__irq_svc+0x54/0x90) This patch only clears the unmask interrupts to avoid trigger unknown Channel Halted interrupt. However, if the Channel Halted interrupt happens unexpected, we need to check if the urb->length is 4-byte alignment in dwc2_update_urb_state_abn(), this can help to avoid the above warning. Change-Id: I51f829458be032fbc75f745ddfe0c465bf634b3e --- drivers/usb/dwc2/hcd_intr.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c index bbc2e077fad8..e49846e2ea89 100644 --- a/drivers/usb/dwc2/hcd_intr.c +++ b/drivers/usb/dwc2/hcd_intr.c @@ -1175,7 +1175,10 @@ static void dwc2_update_urb_state_abn(struct dwc2_hsotg *hsotg, if (urb->actual_length + xfer_length > urb->length) { dev_warn(hsotg->dev, "%s(): trimming xfer length\n", __func__); - xfer_length = urb->length - urb->actual_length; + if (urb->length & 0x3) + xfer_length = 0; + else + xfer_length = urb->length - urb->actual_length; } urb->actual_length += xfer_length; @@ -2039,8 +2042,6 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum) hcint, hcintmsk, hcint & hcintmsk); } - dwc2_writel(hcint, hsotg->regs + HCINT(chnum)); - /* * If we got an interrupt after someone called * dwc2_hcd_endpoint_disable() we don't want to crash below @@ -2053,6 +2054,8 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum) chan->hcint = hcint; hcint &= hcintmsk; + dwc2_writel(hcint, hsotg->regs + HCINT(chnum)); + /* * If the channel was halted due to a dequeue, the qtd list might * be empty or at least the first entry will not be the active qtd.