From cfe2329be3af16b324a2e338ad29484f36e753ab Mon Sep 17 00:00:00 2001 From: Bin Yang Date: Wed, 29 Mar 2017 17:43:23 +0800 Subject: [PATCH] USB: fix handle NAK for IN/OUT SSPLIT/CSPLIT transfers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IN SSPLIT/CSPLIT transfers, NAK packet will cause DWC_OTG ctrl to generate lots of SSPLIT/CSPLIT transfer interrupts, and seriously affect the performance of the system. So need to stop queue transactions after receive SSPLIT/CSPLIT NAK. Change-Id: Ie1b1e9e6971c6546a4239a10b06fba7360978ce0 Signed-off-by: Wu Liang feng Reviewed-on: https://tp-biosrd-v02/gerrit/80149 Reviewed-by: Scorpio Chang(張志賢) Tested-by: Scorpio Chang(張志賢) --- drivers/usb/dwc2/hcd.c | 2 ++ drivers/usb/dwc2/hcd.h | 1 + drivers/usb/dwc2/hcd_intr.c | 19 ++++++++++++++----- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 3ed5d3398831..7bca8ffe9146 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -2700,6 +2700,8 @@ static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) chan->xfer_len = urb->length - urb->actual_length; chan->xfer_count = 0; + chan->csplit_nak = 0; + /* Set the split attributes if required */ if (qh->do_split) dwc2_hc_init_split(hsotg, chan, qtd, urb); diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h index 7758bfb644ff..91091d9009ef 100755 --- a/drivers/usb/dwc2/hcd.h +++ b/drivers/usb/dwc2/hcd.h @@ -142,6 +142,7 @@ struct dwc2_host_chan { u8 halt_pending; u8 do_split; u8 complete_split; + u8 csplit_nak; u8 hub_addr; u8 hub_port; u8 xact_pos; diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c index 906f223542ee..d0ee6fb3d088 100644 --- a/drivers/usb/dwc2/hcd_intr.c +++ b/drivers/usb/dwc2/hcd_intr.c @@ -691,6 +691,7 @@ static void dwc2_release_channel(struct dwc2_hsotg *hsotg, enum dwc2_transaction_type tr_type; u32 haintmsk; int free_qtd = 0; + int continue_trans = 1; if (dbg_hc(chan)) dev_vdbg(hsotg->dev, " %s: channel %d, halt_status %d\n", @@ -719,6 +720,7 @@ static void dwc2_release_channel(struct dwc2_hsotg *hsotg, * deactivated. Don't want to do anything except release the * host channel and try to queue more transfers. */ + continue_trans = 0; goto cleanup; case DWC2_HC_XFER_PERIODIC_INCOMPLETE: dev_vdbg(hsotg->dev, " Complete URB with I/O error\n"); @@ -730,6 +732,10 @@ static void dwc2_release_channel(struct dwc2_hsotg *hsotg, break; } + if (chan->csplit_nak) { + continue_trans = 0; + chan->csplit_nak = 0; + } dwc2_deactivate_qh(hsotg, chan->qh, free_qtd); cleanup: @@ -767,11 +773,13 @@ static void dwc2_release_channel(struct dwc2_hsotg *hsotg, dwc2_writel(haintmsk, hsotg->regs + HAINTMSK); /* Try to queue more transfers now that there's a free channel */ - tr_type = dwc2_hcd_select_transactions(hsotg); - if (tr_type != DWC2_TRANSACTION_NONE) - dwc2_hcd_queue_transactions(hsotg, tr_type); -} - + if (continue_trans) { + tr_type = dwc2_hcd_select_transactions(hsotg); + if (tr_type != DWC2_TRANSACTION_NONE) + dwc2_hcd_queue_transactions(hsotg, tr_type); + } + } + /* * Halts a host channel. If the channel cannot be halted immediately because * the request queue is full, this function ensures that the FIFO empty @@ -1199,6 +1207,7 @@ static void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg, if (chan->do_split) { if (chan->complete_split) qtd->error_count = 0; + chan->csplit_nak = 1; qtd->complete_split = 0; dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK); goto handle_nak_done;