v2 : fix coding format

When USB Ethernet is plugged in ASMEDIA ASM1042A xHCI host, bad
performance was manifesting in Web browser use (like download
large file such as ISO image). It is known limitation of
ASM1042A that is not compatible with driver scheduling,
As a workaround we can modify flow control handling of ASM1042A.

Signed-off-by: Jiahau Chang <lars_ch...@asmedia.com.tw>
---
 drivers/usb/host/pci-quirks.c | 62 +++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/host/pci-quirks.h |  1 +
 drivers/usb/host/xhci-pci.c   |  5 ++++
 drivers/usb/host/xhci.c       |  3 +++
 drivers/usb/host/xhci.h       |  1 +
 5 files changed, 72 insertions(+)

diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index a9a1e4c..bdeaf75 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -77,6 +77,12 @@
 #define USB_INTEL_USB3_PSSEN   0xD8
 #define USB_INTEL_USB3PRM      0xDC
 
+/*ASMEDIA quirk use*/
+#define ASMT_DATA_WRITE0_REG   0xF8
+#define ASMT_DATA_WRITE1_REG   0xFC
+#define ASMT_CONTROL_REG       0xE0
+#define ASMT_CONTROL_WRITE_BIT 0x02
+
 /*
  * amd_chipset_gen values represent AMD different chipset generations
  */
@@ -412,6 +418,62 @@ void usb_amd_quirk_pll_disable(void)
 }
 EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_disable);
 
+void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev)
+{
+       u32 value_low, value_high;
+       unsigned char value;
+       unsigned long wait_time_count;
+
+       wait_time_count = 1000;
+       while (wait_time_count) {
+               pci_read_config_byte(pdev, ASMT_CONTROL_REG, &value);
+               if (value == 0xff) {
+                       dev_dbg(&pdev->dev, "%s: wait_write_ready IO_ERROR, 
value=%x\n",
+                               __func__, value);
+                       goto err_exit;
+               } else if ((value & ASMT_CONTROL_WRITE_BIT) == 0) {
+                       break;
+               }
+               wait_time_count--;
+               udelay(50);
+       }
+       if (wait_time_count == 0) {
+               dev_dbg(&pdev->dev, "%s: wait_write_ready timeout\n",
+                       __func__);
+               goto err_exit;
+       }
+       value_low = 0x00010423;
+       value_high = 0xFA30;
+       pci_write_config_dword(pdev, ASMT_DATA_WRITE0_REG, value_low);
+       pci_write_config_dword(pdev, ASMT_DATA_WRITE1_REG, value_high);
+       pci_write_config_byte(pdev, ASMT_CONTROL_REG, ASMT_CONTROL_WRITE_BIT);
+       wait_time_count = 1000;
+       while (wait_time_count) {
+               pci_read_config_byte(pdev, ASMT_CONTROL_REG, &value);
+               if (value == 0xff) {
+                       dev_dbg(&pdev->dev, "%s: wait_write_ready IO_ERROR, 
value=%x\n",
+                               __func__, value);
+               goto err_exit;
+               } else if ((value & ASMT_CONTROL_WRITE_BIT) == 0) {
+                       break;
+               }
+               wait_time_count--;
+               udelay(50);
+       }
+       if (wait_time_count == 0) {
+               dev_dbg(&pdev->dev, "%s: wait_write_ready timeout\n",
+                       __func__);
+               goto err_exit;
+       }
+       pci_write_config_dword(pdev, ASMT_DATA_WRITE0_REG, 0xBA);
+       pci_write_config_dword(pdev, ASMT_DATA_WRITE1_REG, 0);
+       pci_write_config_byte(pdev, ASMT_CONTROL_REG, ASMT_CONTROL_WRITE_BIT);
+
+err_exit:
+               return;
+}
+EXPORT_SYMBOL_GPL(usb_asmedia_modifyflowcontrol);
+
 void usb_amd_quirk_pll_enable(void)
 {
        usb_amd_quirk_pll(0);
diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h
index 0222195..6ce1df1 100644
--- a/drivers/usb/host/pci-quirks.h
+++ b/drivers/usb/host/pci-quirks.h
@@ -11,6 +11,7 @@ bool usb_amd_prefetch_quirk(void);
 void usb_amd_dev_put(void);
 void usb_amd_quirk_pll_disable(void);
 void usb_amd_quirk_pll_enable(void);
+void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev);
 void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev);
 void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
 void sb800_prefetch(struct device *dev, int on);
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index fcf1f3f..fba52f0 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -53,6 +53,7 @@
 #define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI             0x1aa8
 #define PCI_DEVICE_ID_INTEL_APL_XHCI                   0x5aa8
 #define PCI_DEVICE_ID_INTEL_DNV_XHCI                   0x19d0
+#define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI               0x1142
 
 static const char hcd_name[] = "xhci_hcd";
 
@@ -202,6 +203,10 @@ static void xhci_pci_quirks(struct device *dev, struct 
xhci_hcd *xhci)
                        pdev->device == 0x1042)
                xhci->quirks |= XHCI_BROKEN_STREAMS;
 
+       if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
+               pdev->device == PCI_DEVICE_ID_ASMEDIA_1042A_XHCI)
+               xhci->quirks |= XHCI_ASMEDIA_MODIFY_FLOWCONTROL;
+
        if (pdev->vendor == PCI_VENDOR_ID_TI && pdev->device == 0x8241)
                xhci->quirks |= XHCI_LIMIT_ENDPOINT_INTERVAL_7;
 
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 30f47d9..dcc310d 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -625,6 +625,9 @@ int xhci_run(struct usb_hcd *hcd)
                xhci_queue_vendor_command(xhci, command, 0, 0, 0,
                                TRB_TYPE(TRB_NEC_GET_FW));
        }
+       if (xhci->quirks & XHCI_ASMEDIA_MODIFY_FLOWCONTROL)
+               usb_asmedia_modifyflowcontrol(to_pci_dev(hcd->self.controller));
+
        xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                        "Finished xhci_run for USB2 roothub");
        return 0;
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 73a28a9..ed58f87 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1819,6 +1819,7 @@ struct xhci_hcd {
 /* For controller with a broken Port Disable implementation */
 #define XHCI_BROKEN_PORT_PED   (1 << 25)
 #define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26)
+#define XHCI_ASMEDIA_MODIFY_FLOWCONTROL        (1<<27)
 
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;
-- 
2.7.4

--
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