From: yinbo.zhu <yinbo....@nxp.com>

This issue is observed in USB 2.0 mode when the USB 3.0 host
controller is connected to a FS/LS device via a hub. The
host controller issues start-split (SSPLIT) and (CSPLIT)
tokens to accomplish a split-transaction. A
split-transaction consists of a SSPLIT token, token/data
consists of a SSPLIT token, token/data packets, CSPLIT token
and token/data/handshake packets. A SSPLIT token is issued
by the host controller to the hub followed by token/data/
handshake packets. The hub then relays the token/data/
handshake packets to the FS /LS device. Sometime later, the
host controller issues a CSPLIT token followed by the same
token/data/handshake packets to the hub to complete the
split-transaction. As an example scenario, when the xHCI
driver issues an Address device command with BSR=0, the
host controller sends SETUP(SET_ADDRESS) tokens on the USB
as part of splittransactions. If the host controller
receives a NYET response from the hub for the CSPLIT SETUP,
it means that the split-transaction has not yet been
completed or the hub is not able to handle the split
transaction. In such a case, the host controller keeps
retrying the splittransactions until such time an ACK
response is received from the hub for the CSPLIT SETUP token
. If the split-transactions do not complete in a time bound
manner, the xHCI driver may issue a Stop Endpoint Command.
The host controller does not service the Stop Endpoint
Command and eventually the xHCI driver times out waiting for
the Stop Endpoint Command to complete.

Impact: Stop Endpoint Command does not complete.
Workaround: Instead of issuing a Stop Endpoint Command,
issue a Disable Slot Command with the corresponding slot
ID. Alternately, you can issue an Address Device Command
with BSR=1.

Configs Affected:
LS1012A-R1.0, LS1012A-R2.0, LS1021-20-22A-R1.0,
LS1021-20-22A-R2.0, LS1043-23A-R1.0, LS1043-23A-R1.1,
LS1046-26A-R1.0, LS1088-48A-R1.0, LS2080-40A-R1.0,
LS2081A-R1.1, LS2085-45A-R1.0, LS2088-48A-R1.0,
LS2088-48A-R1.1, LX2160-2120-2080A-R1.0.

Signed-off-by: yinbo.zhu <yinbo....@nxp.com>
---
Change in v3:
                Adjust the commit information.
                Replace "(1<<34)" with BIT(34).
                Update the DT properity description.
                Update erratum description in code comment.
 drivers/usb/dwc3/core.c      |    2 ++
 drivers/usb/dwc3/core.h      |    2 ++
 drivers/usb/dwc3/host.c      |    3 +++
 drivers/usb/host/xhci-plat.c |    3 +++
 drivers/usb/host/xhci.c      |   12 ++++++++++++
 drivers/usb/host/xhci.h      |    1 +
 6 files changed, 23 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 863f2c0..90b097c 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1059,6 +1059,8 @@ static void dwc3_get_properties(struct dwc3 *dwc)
                                "snps,quirk_reverse_in_out");
        dwc->quirk_stop_transfer_in_block = device_property_read_bool(dev,
                                "snps,quirk_stop_transfer_in_block");
+       dwc->quirk_stop_ep_in_u1 = device_property_read_bool(dev,
+                               "snps,quirk_stop_ep_in_u1");
        device_property_read_u8(dev, "snps,tx_de_emphasis",
                                &tx_de_emphasis);
        device_property_read_string(dev, "snps,hsphy_interface",
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 6276678..b55a443 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -860,6 +860,7 @@ struct dwc3_scratchpad_array {
  * @quirk_reverse_in_out: prevent tx fifo reverse the data direction
  * @quirk_stop_transfer_in_block: prevent block transmission from being
  *                               interrupted
+ * @quirk_stop_ep_in_u1: replace stop commad with disable slot command
  * @imod_interval: set the interrupt moderation interval in 250ns
  *                 increments or 0 to disable.
  */
@@ -1014,6 +1015,7 @@ struct dwc3 {
        unsigned                tx_de_emphasis:2;
        unsigned                quirk_reverse_in_out:1;
        unsigned                quirk_stop_transfer_in_block:1;
+       unsigned                quirk_stop_ep_in_u1:1;
 
        u16                     imod_interval;
 };
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index 78cb7bb..0a34274 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -96,6 +96,9 @@ int dwc3_host_init(struct dwc3 *dwc)
        if (dwc->quirk_stop_transfer_in_block)
                props[prop_idx++].name = "quirk-stop-transfer-in-block";
 
+       if (dwc->quirk_stop_ep_in_u1)
+               props[prop_idx++].name = "quirk-stop-ep-in-u1";
+
        if (dwc->usb3_lpm_capable)
                props[prop_idx++].name = "usb3-lpm-capable";
 
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 35e0fc8..49d6cb4 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -273,6 +273,9 @@ static int xhci_plat_probe(struct platform_device *pdev)
                                "quirk-stop-transfer-in-block"))
                xhci->quirks |= XHCI_STOP_TRANSFER_IN_BLOCK;
 
+       if (device_property_read_bool(&pdev->dev, "quirk-stop-ep-in-u1"))
+               xhci->quirks |= XHCI_STOP_EP_IN_U1;
+
        if (device_property_read_bool(&pdev->dev, "quirk-broken-port-ped"))
                xhci->quirks |= XHCI_BROKEN_PORT_PED;
 
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 5141856..20c9af4 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1521,6 +1521,18 @@ static int xhci_urb_dequeue(struct usb_hcd *hcd, struct 
urb *urb, int status)
                        xhci_ring_cmd_db(xhci);
                }
 
+               /*
+                *erratum A-009668: Stop Endpoint Command does not complete.
+                *Workaround: Instead of issuing a Stop Endpoint Command,
+                *issue a Disable Slot Command with the corresponding slot ID.
+                *Alternately, you can issue an Address Device Command with
+                *BSR=1
+                */
+               if ((urb->dev->speed <= USB_SPEED_HIGH) &&
+                                       (xhci->quirks & XHCI_STOP_EP_IN_U1)) {
+                       xhci_queue_slot_control(xhci, command, TRB_DISABLE_SLOT,
+                               urb->dev->slot_id);
+               }
        }
 done:
        spin_unlock_irqrestore(&xhci->lock, flags);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index db10ee4..22ba752 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1821,6 +1821,7 @@ struct xhci_hcd {
 #define XHCI_MISSING_CAS       (1 << 24)
 #define XHCI_REVERSE_IN_OUT     BIT(32)
 #define XHCI_STOP_TRANSFER_IN_BLOCK   BIT(33)
+#define XHCI_STOP_EP_IN_U1     BIT(34)
 /* For controller with a broken Port Disable implementation */
 #define XHCI_BROKEN_PORT_PED   (1 << 25)
 #define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26)
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to