USB: fix handle NAK for IN/OUT SSPLIT/CSPLIT transfers.
authorwlf <wulf@rock-chips.com>
Mon, 29 Sep 2014 09:03:50 +0000 (17:03 +0800)
committerwlf <wulf@rock-chips.com>
Mon, 29 Sep 2014 09:03:50 +0000 (17:03 +0800)
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.

drivers/usb/dwc_otg_310/dwc_otg_cil.h
drivers/usb/dwc_otg_310/dwc_otg_hcd.c
drivers/usb/dwc_otg_310/dwc_otg_hcd_intr.c

index d25a72ed87424ca95ad108bb94f6c399b97b2fb1..10f8cf07a1202d54845c891587db9188774f1c0d 100755 (executable)
@@ -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 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 */
        uint8_t hub_addr;                  /**< Address of high speed hub */
 
        uint8_t port_addr;                 /**< Port of the low/full speed device */
index cc5198bb4e750f95c09e297ea7704d7358006698..1ad27556227caf31b4669e36be9979609617518c 100755 (executable)
@@ -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;
         * 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;
        if (qh->do_split) {
                uint32_t hub_addr, port_addr;
                hc->do_split = 1;
index c803e39a22d6359b3ded67589ab529cecf8905cd..33018f4f285fdc011967c3348ca6469d6e124cca 100755 (executable)
@@ -832,6 +832,7 @@ static void release_channel(dwc_otg_hcd_t *hcd,
 {
        dwc_otg_transaction_type_e tr_type;
        int free_qtd;
 {
        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);
 
        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.
                 */
                 * 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;
                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;
        }
 
                break;
        }
 
+       if (hc->csplit_nak) {
+               continue_trans = 0;
+               hc->csplit_nak = 0;
+       }
        deactivate_qh(hcd, hc->qh, free_qtd);
 
 cleanup:
        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. */
        }
 
        /* 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;
                }
                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;
                qtd->complete_split = 0;
                halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
                goto handle_nak_done;