]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
xhci: Bad Ethernet performance plugged in ASM1042A host
authorJiahau Chang <jiahau@gmail.com>
Wed, 19 Jul 2017 07:44:36 +0000 (15:44 +0800)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Wed, 9 Aug 2017 14:38:27 +0000 (16:38 +0200)
BugLink: https://bugs.launchpad.net/bugs/1667750
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.
The register we modify is changes the behavior

[use quirk bit 28 instead, usleep_range 40-60us -Mathias]
Cc: <stable@vger.kernel.org>
Signed-off-by: Jiahau Chang <Lars_chang@asmedia.com.tw>
Signed-off-by: Ian Pilcher <arequipeno@gmail.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
(backported from commit 9da5a1092b13468839b1a864b126cacfb72ad016)
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Acked-by: Seth Forshee <seth.forshee@canonical.com>
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
drivers/usb/host/pci-quirks.c
drivers/usb/host/pci-quirks.h
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h

index a9a1e4c40480cf2c5c7c7995aa5d337d3ef3ee87..c8989c62a2621b88cf8b9d0c3001a37a31d5e151 100644 (file)
 #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
+#define ASMT_WRITEREG_CMD      0x10423
+#define ASMT_FLOWCTL_ADDR      0xFA30
+#define ASMT_FLOWCTL_DATA      0xBA
+#define ASMT_PSEUDO_DATA       0
+
 /*
  * amd_chipset_gen values represent AMD different chipset generations
  */
@@ -412,6 +422,50 @@ void usb_amd_quirk_pll_disable(void)
 }
 EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_disable);
 
+static int usb_asmedia_wait_write(struct pci_dev *pdev)
+{
+       unsigned long retry_count;
+       unsigned char value;
+
+       for (retry_count = 1000; retry_count > 0; --retry_count) {
+
+               pci_read_config_byte(pdev, ASMT_CONTROL_REG, &value);
+
+               if (value == 0xff) {
+                       dev_err(&pdev->dev, "%s: check_ready ERROR", __func__);
+                       return -EIO;
+               }
+
+               if ((value & ASMT_CONTROL_WRITE_BIT) == 0)
+                       return 0;
+
+               usleep_range(40, 60);
+       }
+
+       dev_warn(&pdev->dev, "%s: check_write_ready timeout", __func__);
+       return -ETIMEDOUT;
+}
+
+void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev)
+{
+       if (usb_asmedia_wait_write(pdev) != 0)
+               return;
+
+       /* send command and address to device */
+       pci_write_config_dword(pdev, ASMT_DATA_WRITE0_REG, ASMT_WRITEREG_CMD);
+       pci_write_config_dword(pdev, ASMT_DATA_WRITE1_REG, ASMT_FLOWCTL_ADDR);
+       pci_write_config_byte(pdev, ASMT_CONTROL_REG, ASMT_CONTROL_WRITE_BIT);
+
+       if (usb_asmedia_wait_write(pdev) != 0)
+               return;
+
+       /* send data to device */
+       pci_write_config_dword(pdev, ASMT_DATA_WRITE0_REG, ASMT_FLOWCTL_DATA);
+       pci_write_config_dword(pdev, ASMT_DATA_WRITE1_REG, ASMT_PSEUDO_DATA);
+       pci_write_config_byte(pdev, ASMT_CONTROL_REG, ASMT_CONTROL_WRITE_BIT);
+}
+EXPORT_SYMBOL_GPL(usb_asmedia_modifyflowcontrol);
+
 void usb_amd_quirk_pll_enable(void)
 {
        usb_amd_quirk_pll(0);
index c622ddf21c94e61f6c8089cdc493088f33973599..c78a0dc42d1025de469254da82ebba58c8836901 100644 (file)
@@ -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);
index 93f566cb968b1764983f04cd34c45ed40bd6c8fd..f16c817fdba945d5e8c0e097d74d2662f9890262 100644 (file)
@@ -53,6 +53,8 @@
 #define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI             0x1aa8
 #define PCI_DEVICE_ID_INTEL_APL_XHCI                   0x5aa8
 
+#define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI               0x1142
+
 static const char hcd_name[] = "xhci_hcd";
 
 static struct hc_driver __read_mostly xhci_pci_hc_driver;
@@ -199,6 +201,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;
 
index 9a0ec116654acd27740d497c76ba1a6bb6ab6dd9..c182e764bb78bc659cf29c8f8b582d58860de2d9 100644 (file)
@@ -198,6 +198,9 @@ int xhci_reset(struct xhci_hcd *xhci)
        if (ret)
                return ret;
 
+       if (xhci->quirks & XHCI_ASMEDIA_MODIFY_FLOWCONTROL)
+               usb_asmedia_modifyflowcontrol(to_pci_dev(xhci_to_hcd(xhci)->self.controller));
+
        xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                         "Wait for controller to be ready for doorbell rings");
        /*
@@ -1127,6 +1130,9 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
        if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && !comp_timer_running)
                compliance_mode_recovery_timer_init(xhci);
 
+       if (xhci->quirks & XHCI_ASMEDIA_MODIFY_FLOWCONTROL)
+               usb_asmedia_modifyflowcontrol(to_pci_dev(hcd->self.controller));
+
        /* Re-enable port polling. */
        xhci_dbg(xhci, "%s: starting port polling.\n", __func__);
        set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
index 98eb5d50e03db5c14cf49959dbb8326319dce241..5cf2e6dac933a8bff61c6afecf2ae108953a6de9 100644 (file)
@@ -1653,6 +1653,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 << 28)
 
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;