From: wlf Date: Mon, 29 Sep 2014 09:03:50 +0000 (+0800) Subject: USB: fix handle NAK for IN/OUT SSPLIT/CSPLIT transfers. X-Git-Tag: firefly_0821_release~4628 X-Git-Url: http://plrg.eecs.uci.edu/git/?p=firefly-linux-kernel-4.4.55.git;a=commitdiff_plain;h=c1906ff58fd7d1af957de1bd2491e5c338228616 USB: fix handle NAK for IN/OUT SSPLIT/CSPLIT transfers. 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. --- diff --git a/drivers/usb/dwc_otg_310/dwc_otg_cil.h b/drivers/usb/dwc_otg_310/dwc_otg_cil.h index d25a72ed8742..10f8cf07a120 100755 --- a/drivers/usb/dwc_otg_310/dwc_otg_cil.h +++ b/drivers/usb/dwc_otg_310/dwc_otg_cil.h @@ -377,6 +377,7 @@ typedef struct dwc_hc { */ uint8_t do_split; /**< Enable split for the channel */ uint8_t complete_split; /**< Enable complete split */ + uint8_t csplit_nak; uint8_t hub_addr; /**< Address of high speed hub */ uint8_t port_addr; /**< Port of the low/full speed device */ diff --git a/drivers/usb/dwc_otg_310/dwc_otg_hcd.c b/drivers/usb/dwc_otg_310/dwc_otg_hcd.c index cc5198bb4e75..1ad27556227c 100755 --- a/drivers/usb/dwc_otg_310/dwc_otg_hcd.c +++ b/drivers/usb/dwc_otg_310/dwc_otg_hcd.c @@ -1071,6 +1071,7 @@ static int assign_and_init_hc(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh) * Set the split attributes */ hc->do_split = 0; + hc->csplit_nak = 0; if (qh->do_split) { uint32_t hub_addr, port_addr; hc->do_split = 1; diff --git a/drivers/usb/dwc_otg_310/dwc_otg_hcd_intr.c b/drivers/usb/dwc_otg_310/dwc_otg_hcd_intr.c index c803e39a22d6..33018f4f285f 100755 --- a/drivers/usb/dwc_otg_310/dwc_otg_hcd_intr.c +++ b/drivers/usb/dwc_otg_310/dwc_otg_hcd_intr.c @@ -832,6 +832,7 @@ static void release_channel(dwc_otg_hcd_t *hcd, { dwc_otg_transaction_type_e tr_type; int free_qtd; + int continue_trans = 1; DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d\n", __func__, hc->hc_num, halt_status); @@ -883,6 +884,7 @@ static void release_channel(dwc_otg_hcd_t *hcd, * deactivated. Don't want to do anything except release the * host channel and try to queue more transfers. */ + continue_trans = 0; goto cleanup; case DWC_OTG_HC_XFER_NO_HALT_STATUS: free_qtd = 0; @@ -898,6 +900,10 @@ static void release_channel(dwc_otg_hcd_t *hcd, break; } + if (hc->csplit_nak) { + continue_trans = 0; + hc->csplit_nak = 0; + } deactivate_qh(hcd, hc->qh, free_qtd); cleanup: @@ -925,9 +931,10 @@ cleanup: } /* Try to queue more transfers now that there's a free channel. */ - tr_type = dwc_otg_hcd_select_transactions(hcd); - if (tr_type != DWC_OTG_TRANSACTION_NONE) { - dwc_otg_hcd_queue_transactions(hcd, tr_type); + if (continue_trans) { + tr_type = dwc_otg_hcd_select_transactions(hcd); + if (tr_type != DWC_OTG_TRANSACTION_NONE) + dwc_otg_hcd_queue_transactions(hcd, tr_type); } } @@ -1364,6 +1371,7 @@ static int32_t handle_hc_nak_intr(dwc_otg_hcd_t *hcd, if (hc->complete_split) { qtd->error_count = 0; } + hc->csplit_nak = 1; qtd->complete_split = 0; halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK); goto handle_nak_done;