summaryrefslogtreecommitdiff
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/ehci-platform.c40
-rw-r--r--drivers/usb/host/ohci-da8xx.c17
-rw-r--r--drivers/usb/host/ohci-platform.c24
-rw-r--r--drivers/usb/host/sl811-hcd.c1
-rw-r--r--drivers/usb/host/uhci-hcd.h1
-rw-r--r--drivers/usb/host/uhci-platform.c28
-rw-r--r--drivers/usb/host/xen-hcd.c4
-rw-r--r--drivers/usb/host/xhci-caps.h167
-rw-r--r--drivers/usb/host/xhci-dbgcap.c23
-rw-r--r--drivers/usb/host/xhci-dbgcap.h1
-rw-r--r--drivers/usb/host/xhci-dbgtty.c23
-rw-r--r--drivers/usb/host/xhci-debugfs.c57
-rw-r--r--drivers/usb/host/xhci-hub.c125
-rw-r--r--drivers/usb/host/xhci-mem.c41
-rw-r--r--drivers/usb/host/xhci-mtk.c1
-rw-r--r--drivers/usb/host/xhci-mtk.h10
-rw-r--r--drivers/usb/host/xhci-pci.c9
-rw-r--r--drivers/usb/host/xhci-port.h5
-rw-r--r--drivers/usb/host/xhci-ring.c257
-rw-r--r--drivers/usb/host/xhci-sideband.c102
-rw-r--r--drivers/usb/host/xhci-tegra.c13
-rw-r--r--drivers/usb/host/xhci-trace.h25
-rw-r--r--drivers/usb/host/xhci.c93
-rw-r--r--drivers/usb/host/xhci.h116
24 files changed, 662 insertions, 521 deletions
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index 6aab45c8525c..f61f095cedab 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -27,6 +27,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/sys_soc.h>
@@ -111,8 +112,7 @@ static void ehci_platform_power_off(struct platform_device *dev)
int clk;
for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--)
- if (priv->clks[clk])
- clk_disable_unprepare(priv->clks[clk]);
+ clk_disable_unprepare(priv->clks[clk]);
}
static struct hc_driver __read_mostly ehci_platform_hc_driver;
@@ -239,9 +239,11 @@ static int ehci_platform_probe(struct platform_device *dev)
struct usb_hcd *hcd;
struct resource *res_mem;
struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
+ const struct of_device_id *match;
struct ehci_platform_priv *priv;
struct ehci_hcd *ehci;
int err, irq, clk = 0;
+ bool dma_mask_64;
if (usb_disabled())
return -ENODEV;
@@ -253,8 +255,13 @@ static int ehci_platform_probe(struct platform_device *dev)
if (!pdata)
pdata = &ehci_platform_defaults;
+ dma_mask_64 = pdata->dma_mask_64;
+ match = of_match_device(dev->dev.driver->of_match_table, &dev->dev);
+ if (match && match->data)
+ dma_mask_64 = true;
+
err = dma_coerce_mask_and_coherent(&dev->dev,
- pdata->dma_mask_64 ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
+ dma_mask_64 ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
if (err) {
dev_err(&dev->dev, "Error: DMA mask configuration failed\n");
return err;
@@ -298,7 +305,9 @@ static int ehci_platform_probe(struct platform_device *dev)
if (of_device_is_compatible(dev->dev.of_node,
"aspeed,ast2500-ehci") ||
of_device_is_compatible(dev->dev.of_node,
- "aspeed,ast2600-ehci"))
+ "aspeed,ast2600-ehci") ||
+ of_device_is_compatible(dev->dev.of_node,
+ "aspeed,ast2700-ehci"))
ehci->is_aspeed = 1;
if (soc_device_match(quirk_poll_match))
@@ -445,6 +454,17 @@ static int __maybe_unused ehci_platform_suspend(struct device *dev)
if (pdata->power_suspend)
pdata->power_suspend(pdev);
+ ret = reset_control_assert(priv->rsts);
+ if (ret) {
+ if (pdata->power_on)
+ pdata->power_on(pdev);
+
+ ehci_resume(hcd, false);
+
+ if (priv->quirk_poll)
+ quirk_poll_init(priv);
+ }
+
return ret;
}
@@ -455,11 +475,18 @@ static int __maybe_unused ehci_platform_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
struct device *companion_dev;
+ int err;
+
+ err = reset_control_deassert(priv->rsts);
+ if (err)
+ return err;
if (pdata->power_on) {
- int err = pdata->power_on(pdev);
- if (err < 0)
+ err = pdata->power_on(pdev);
+ if (err < 0) {
+ reset_control_assert(priv->rsts);
return err;
+ }
}
companion_dev = usb_of_get_companion_dev(hcd->self.controller);
@@ -485,6 +512,7 @@ static const struct of_device_id vt8500_ehci_ids[] = {
{ .compatible = "wm,prizm-ehci", },
{ .compatible = "generic-ehci", },
{ .compatible = "cavium,octeon-6335-ehci", },
+ { .compatible = "aspeed,ast2700-ehci", .data = (void *)1 },
{}
};
MODULE_DEVICE_TABLE(of, vt8500_ehci_ids);
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index 3c5ca2d7c92e..0938c0e7a8b6 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -18,7 +18,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
-#include <linux/platform_data/usb-davinci.h>
#include <linux/regulator/consumer.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
@@ -166,17 +165,6 @@ static int ohci_da8xx_has_oci(struct usb_hcd *hcd)
return 0;
}
-static int ohci_da8xx_has_potpgt(struct usb_hcd *hcd)
-{
- struct device *dev = hcd->self.controller;
- struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
-
- if (hub && hub->potpgt)
- return 1;
-
- return 0;
-}
-
static int ohci_da8xx_regulator_event(struct notifier_block *nb,
unsigned long event, void *data)
{
@@ -228,7 +216,6 @@ static int ohci_da8xx_register_notify(struct usb_hcd *hcd)
static int ohci_da8xx_reset(struct usb_hcd *hcd)
{
struct device *dev = hcd->self.controller;
- struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
int result;
u32 rh_a;
@@ -266,10 +253,6 @@ static int ohci_da8xx_reset(struct usb_hcd *hcd)
rh_a &= ~RH_A_NOCP;
rh_a |= RH_A_OCPM;
}
- if (ohci_da8xx_has_potpgt(hcd)) {
- rh_a &= ~RH_A_POTPGT;
- rh_a |= hub->potpgt << 24;
- }
ohci_writel(ohci, rh_a, &ohci->regs->roothub.a);
return result;
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index f47ae12cde6a..2e4bb5cc2165 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -69,8 +69,7 @@ static void ohci_platform_power_off(struct platform_device *dev)
int clk;
for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--)
- if (priv->clks[clk])
- clk_disable_unprepare(priv->clks[clk]);
+ clk_disable_unprepare(priv->clks[clk]);
}
static struct hc_driver __read_mostly ohci_platform_hc_driver;
@@ -271,6 +270,7 @@ static int ohci_platform_suspend(struct device *dev)
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct usb_ohci_pdata *pdata = dev->platform_data;
struct platform_device *pdev = to_platform_device(dev);
+ struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
bool do_wakeup = device_may_wakeup(dev);
int ret;
@@ -281,6 +281,14 @@ static int ohci_platform_suspend(struct device *dev)
if (pdata->power_suspend)
pdata->power_suspend(pdev);
+ ret = reset_control_assert(priv->resets);
+ if (ret) {
+ if (pdata->power_on)
+ pdata->power_on(pdev);
+
+ ohci_resume(hcd, false);
+ }
+
return ret;
}
@@ -289,11 +297,19 @@ static int ohci_platform_resume_common(struct device *dev, bool hibernated)
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct usb_ohci_pdata *pdata = dev_get_platdata(dev);
struct platform_device *pdev = to_platform_device(dev);
+ struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
+ int err;
+
+ err = reset_control_deassert(priv->resets);
+ if (err)
+ return err;
if (pdata->power_on) {
- int err = pdata->power_on(pdev);
- if (err < 0)
+ err = pdata->power_on(pdev);
+ if (err < 0) {
+ reset_control_assert(priv->resets);
return err;
+ }
}
ohci_resume(hcd, hibernated);
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index ea3cab99c5d4..5d6dba681e50 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1748,6 +1748,7 @@ sl811h_suspend(struct platform_device *dev, pm_message_t state)
break;
case PM_EVENT_SUSPEND:
case PM_EVENT_HIBERNATE:
+ case PM_EVENT_POWEROFF:
case PM_EVENT_PRETHAW: /* explicitly discard hw state */
port_power(sl811, 0);
break;
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 13ee2a6144b2..4326d1f3ca76 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -445,6 +445,7 @@ struct uhci_hcd {
short load[MAX_PHASE]; /* Periodic allocations */
struct clk *clk; /* (optional) clock source */
+ struct reset_control *rsts; /* (optional) clock reset */
/* Reset host controller */
void (*reset_hc) (struct uhci_hcd *uhci);
diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c
index 62318291f566..5e02f2ceafb6 100644
--- a/drivers/usb/host/uhci-platform.c
+++ b/drivers/usb/host/uhci-platform.c
@@ -11,6 +11,7 @@
#include <linux/of.h>
#include <linux/device.h>
#include <linux/platform_device.h>
+#include <linux/reset.h>
static int uhci_platform_init(struct usb_hcd *hcd)
{
@@ -67,6 +68,7 @@ static const struct hc_driver uhci_platform_hc_driver = {
static int uhci_hcd_platform_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
+ bool dma_mask_64 = false;
struct usb_hcd *hcd;
struct uhci_hcd *uhci;
struct resource *res;
@@ -80,7 +82,11 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev)
* Since shared usb code relies on it, set it here for now.
* Once we have dma capability bindings this can go away.
*/
- ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (of_device_get_match_data(&pdev->dev))
+ dma_mask_64 = true;
+
+ ret = dma_coerce_mask_and_coherent(&pdev->dev,
+ dma_mask_64 ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
if (ret)
return ret;
@@ -113,7 +119,8 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev)
}
if (of_device_is_compatible(np, "aspeed,ast2400-uhci") ||
of_device_is_compatible(np, "aspeed,ast2500-uhci") ||
- of_device_is_compatible(np, "aspeed,ast2600-uhci")) {
+ of_device_is_compatible(np, "aspeed,ast2600-uhci") ||
+ of_device_is_compatible(np, "aspeed,ast2700-uhci")) {
uhci->is_aspeed = 1;
dev_info(&pdev->dev,
"Enabled Aspeed implementation workarounds\n");
@@ -132,17 +139,28 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev)
goto err_rmr;
}
+ uhci->rsts = devm_reset_control_array_get_optional_shared(&pdev->dev);
+ if (IS_ERR(uhci->rsts)) {
+ ret = PTR_ERR(uhci->rsts);
+ goto err_clk;
+ }
+ ret = reset_control_deassert(uhci->rsts);
+ if (ret)
+ goto err_clk;
+
ret = platform_get_irq(pdev, 0);
if (ret < 0)
- goto err_clk;
+ goto err_reset;
ret = usb_add_hcd(hcd, ret, IRQF_SHARED);
if (ret)
- goto err_clk;
+ goto err_reset;
device_wakeup_enable(hcd->self.controller);
return 0;
+err_reset:
+ reset_control_assert(uhci->rsts);
err_clk:
clk_disable_unprepare(uhci->clk);
err_rmr:
@@ -156,6 +174,7 @@ static void uhci_hcd_platform_remove(struct platform_device *pdev)
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+ reset_control_assert(uhci->rsts);
clk_disable_unprepare(uhci->clk);
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
@@ -178,6 +197,7 @@ static void uhci_hcd_platform_shutdown(struct platform_device *op)
static const struct of_device_id platform_uhci_ids[] = {
{ .compatible = "generic-uhci", },
{ .compatible = "platform-uhci", },
+ { .compatible = "aspeed,ast2700-uhci", .data = (void *)1 },
{}
};
MODULE_DEVICE_TABLE(of, platform_uhci_ids);
diff --git a/drivers/usb/host/xen-hcd.c b/drivers/usb/host/xen-hcd.c
index 1c2a95fe41e5..0a94d302911a 100644
--- a/drivers/usb/host/xen-hcd.c
+++ b/drivers/usb/host/xen-hcd.c
@@ -1388,7 +1388,7 @@ static int xenhcd_get_frame(struct usb_hcd *hcd)
return 0;
}
-static struct hc_driver xenhcd_usb20_hc_driver = {
+static const struct hc_driver xenhcd_usb20_hc_driver = {
.description = "xen-hcd",
.product_desc = "Xen USB2.0 Virtual Host Controller",
.hcd_priv_size = sizeof(struct xenhcd_info),
@@ -1413,7 +1413,7 @@ static struct hc_driver xenhcd_usb20_hc_driver = {
#endif
};
-static struct hc_driver xenhcd_usb11_hc_driver = {
+static const struct hc_driver xenhcd_usb11_hc_driver = {
.description = "xen-hcd",
.product_desc = "Xen USB1.1 Virtual Host Controller",
.hcd_priv_size = sizeof(struct xenhcd_info),
diff --git a/drivers/usb/host/xhci-caps.h b/drivers/usb/host/xhci-caps.h
index 89bc83e4f1eb..2f59b6ab1e45 100644
--- a/drivers/usb/host/xhci-caps.h
+++ b/drivers/usb/host/xhci-caps.h
@@ -1,93 +1,120 @@
/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * xHCI Host Controller Capability Registers.
+ * xHCI Specification Section 5.3, Revision 1.2.
+ */
+
+#include <linux/bits.h>
-/* hc_capbase bitmasks */
-/* bits 7:0 - how long is the Capabilities register */
-#define HC_LENGTH(p) XHCI_HC_LENGTH(p)
-/* bits 31:16 */
+/* hc_capbase - bitmasks */
+/* bits 7:0 - Capability Registers Length */
+#define HC_LENGTH(p) ((p) & 0xff)
+/* bits 15:8 - Rsvd */
+/* bits 31:16 - Host Controller Interface Version Number */
#define HC_VERSION(p) (((p) >> 16) & 0xffff)
/* HCSPARAMS1 - hcs_params1 - bitmasks */
-/* bits 0:7, Max Device Slots */
+/* bits 7:0 - Number of Device Slots */
#define HCS_MAX_SLOTS(p) (((p) >> 0) & 0xff)
#define HCS_SLOTS_MASK 0xff
-/* bits 8:18, Max Interrupters */
+/* bits 18:8 - Number of Interrupters, max values is 1024 */
#define HCS_MAX_INTRS(p) (((p) >> 8) & 0x7ff)
-/* bits 24:31, Max Ports - max value is 0x7F = 127 ports */
-#define HCS_MAX_PORTS(p) (((p) >> 24) & 0x7f)
+/* bits 31:24, Max Ports - max value is 255 */
+#define HCS_MAX_PORTS(p) (((p) >> 24) & 0xff)
/* HCSPARAMS2 - hcs_params2 - bitmasks */
-/* bits 0:3, frames or uframes that SW needs to queue transactions
- * ahead of the HW to meet periodic deadlines */
-#define HCS_IST(p) (((p) >> 0) & 0xf)
-/* bits 4:7, max number of Event Ring segments */
+/*
+ * bits 3:0 - Isochronous Scheduling Threshold, frames or uframes that SW
+ * needs to queue transactions ahead of the HW to meet periodic deadlines.
+ * - Bits 2:0: Threshold value
+ * - Bit 3: Unit indicator
+ * - '1': Threshold in Frames
+ * - '0': Threshold in Microframes (uframes)
+ * Note: 1 Frame = 8 Microframes
+ * xHCI specification section 5.3.4.
+ */
+#define HCS_IST_VALUE(p) ((p) & 0x7)
+#define HCS_IST_UNIT BIT(3)
+/* bits 7:4 - Event Ring Segment Table Max, 2^(n) */
#define HCS_ERST_MAX(p) (((p) >> 4) & 0xf)
-/* bits 21:25 Hi 5 bits of Scratchpad buffers SW must allocate for the HW */
-/* bit 26 Scratchpad restore - for save/restore HW state - not used yet */
-/* bits 27:31 Lo 5 bits of Scratchpad buffers SW must allocate for the HW */
-#define HCS_MAX_SCRATCHPAD(p) ((((p) >> 16) & 0x3e0) | (((p) >> 27) & 0x1f))
+/* bits 20:8 - Rsvd */
+/* bits 25:21 - Max Scratchpad Buffers (Hi), 5 Most significant bits */
+#define HCS_MAX_SP_HI(p) (((p) >> 21) & 0x1f)
+/* bit 26 - Scratchpad restore, for save/restore HW state */
+/* bits 31:27 - Max Scratchpad Buffers (Lo), 5 Least significant bits */
+#define HCS_MAX_SP_LO(p) (((p) >> 27) & 0x1f)
+#define HCS_MAX_SCRATCHPAD(p) (HCS_MAX_SP_HI(p) << 5 | HCS_MAX_SP_LO(p))
/* HCSPARAMS3 - hcs_params3 - bitmasks */
-/* bits 0:7, Max U1 to U0 latency for the roothub ports */
+/* bits 7:0 - U1 Device Exit Latency, Max U1 to U0 latency for the roothub ports */
#define HCS_U1_LATENCY(p) (((p) >> 0) & 0xff)
-/* bits 16:31, Max U2 to U0 latency for the roothub ports */
+/* bits 15:8 - Rsvd */
+/* bits 31:16 - U2 Device Exit Latency, Max U2 to U0 latency for the roothub ports */
#define HCS_U2_LATENCY(p) (((p) >> 16) & 0xffff)
-/* HCCPARAMS - hcc_params - bitmasks */
-/* true: HC can use 64-bit address pointers */
-#define HCC_64BIT_ADDR(p) ((p) & (1 << 0))
-/* true: HC can do bandwidth negotiation */
-#define HCC_BANDWIDTH_NEG(p) ((p) & (1 << 1))
-/* true: HC uses 64-byte Device Context structures
- * FIXME 64-byte context structures aren't supported yet.
- */
-#define HCC_64BYTE_CONTEXT(p) ((p) & (1 << 2))
-/* true: HC has port power switches */
-#define HCC_PPC(p) ((p) & (1 << 3))
-/* true: HC has port indicators */
-#define HCS_INDICATOR(p) ((p) & (1 << 4))
-/* true: HC has Light HC Reset Capability */
-#define HCC_LIGHT_RESET(p) ((p) & (1 << 5))
-/* true: HC supports latency tolerance messaging */
-#define HCC_LTC(p) ((p) & (1 << 6))
-/* true: no secondary Stream ID Support */
-#define HCC_NSS(p) ((p) & (1 << 7))
-/* true: HC supports Stopped - Short Packet */
-#define HCC_SPC(p) ((p) & (1 << 9))
-/* true: HC has Contiguous Frame ID Capability */
-#define HCC_CFC(p) ((p) & (1 << 11))
-/* Max size for Primary Stream Arrays - 2^(n+1), where n is bits 12:15 */
+/* HCCPARAMS1 - hcc_params - bitmasks */
+/* bit 0 - 64-bit Addressing Capability */
+#define HCC_64BIT_ADDR BIT(0)
+/* bit 1 - BW Negotiation Capability */
+#define HCC_BANDWIDTH_NEG BIT(1)
+/* bit 2 - Context Size */
+#define HCC_64BYTE_CONTEXT BIT(2)
+#define CTX_SIZE(_hcc) (_hcc & HCC_64BYTE_CONTEXT ? 64 : 32)
+/* bit 3 - Port Power Control */
+#define HCC_PPC BIT(3)
+/* bit 4 - Port Indicators */
+#define HCS_INDICATOR BIT(4)
+/* bit 5 - Light HC Reset Capability */
+#define HCC_LIGHT_RESET BIT(5)
+/* bit 6 - Latency Tolerance Messaging Capability */
+#define HCC_LTC BIT(6)
+/* bit 7 - No Secondary Stream ID Support */
+#define HCC_NSS BIT(7)
+/* bit 8 - Parse All Event Data */
+/* bit 9 - Short Packet Capability */
+#define HCC_SPC BIT(9)
+/* bit 10 - Stopped EDTLA Capability */
+/* bit 11 - Contiguous Frame ID Capability */
+#define HCC_CFC BIT(11)
+/* bits 15:12 - Max size for Primary Stream Arrays, 2^(n+1) */
#define HCC_MAX_PSA(p) (1 << ((((p) >> 12) & 0xf) + 1))
-/* Extended Capabilities pointer from PCI base - section 5.3.6 */
-#define HCC_EXT_CAPS(p) XHCI_HCC_EXT_CAPS(p)
-
-#define CTX_SIZE(_hcc) (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32)
+/* bits 31:16 - xHCI Extended Capabilities Pointer, from PCI base: 2^(n) */
+#define HCC_EXT_CAPS(p) (((p) >> 16) & 0xffff)
-/* db_off bitmask - bits 31:2 Doorbell Array Offset */
+/* DBOFF - db_off - bitmasks */
+/* bits 1:0 - Rsvd */
+/* bits 31:2 - Doorbell Array Offset */
#define DBOFF_MASK (0xfffffffc)
-/* run_regs_off bitmask - bits 0:4 reserved */
+/* RTSOFF - run_regs_off - bitmasks */
+/* bits 4:0 - Rsvd */
+/* bits 31:5 - Runtime Register Space Offse */
#define RTSOFF_MASK (~0x1f)
/* HCCPARAMS2 - hcc_params2 - bitmasks */
-/* true: HC supports U3 entry Capability */
-#define HCC2_U3C(p) ((p) & (1 << 0))
-/* true: HC supports Configure endpoint command Max exit latency too large */
-#define HCC2_CMC(p) ((p) & (1 << 1))
-/* true: HC supports Force Save context Capability */
-#define HCC2_FSC(p) ((p) & (1 << 2))
-/* true: HC supports Compliance Transition Capability */
-#define HCC2_CTC(p) ((p) & (1 << 3))
-/* true: HC support Large ESIT payload Capability > 48k */
-#define HCC2_LEC(p) ((p) & (1 << 4))
-/* true: HC support Configuration Information Capability */
-#define HCC2_CIC(p) ((p) & (1 << 5))
-/* true: HC support Extended TBC Capability, Isoc burst count > 65535 */
-#define HCC2_ETC(p) ((p) & (1 << 6))
-/* true: HC support Extended TBC TRB Status Capability */
-#define HCC2_ETC_TSC(p) ((p) & (1 << 7))
-/* true: HC support Get/Set Extended Property Capability */
-#define HCC2_GSC(p) ((p) & (1 << 8))
-/* true: HC support Virtualization Based Trusted I/O Capability */
-#define HCC2_VTC(p) ((p) & (1 << 9))
-/* true: HC support Double BW on a eUSB2 HS ISOC EP */
-#define HCC2_EUSB2_DIC(p) ((p) & (1 << 11))
+/* bit 0 - U3 Entry Capability */
+#define HCC2_U3C BIT(0)
+/* bit 1 - Configure Endpoint Command Max Exit Latency Too Large Capability */
+#define HCC2_CMC BIT(1)
+/* bit 2 - Force Save Context Capabilitu */
+#define HCC2_FSC BIT(2)
+/* bit 3 - Compliance Transition Capability, false: compliance is enabled by default */
+#define HCC2_CTC BIT(3)
+/* bit 4 - Large ESIT Payload Capability, true: HC support ESIT payload > 48k */
+#define HCC2_LEC BIT(4)
+/* bit 5 - Configuration Information Capability */
+#define HCC2_CIC BIT(5)
+/* bit 6 - Extended TBC Capability, true: Isoc burst count > 65535 */
+#define HCC2_ETC BIT(6)
+/* bit 7 - Extended TBC TRB Status Capability */
+#define HCC2_ETC_TSC BIT(7)
+/* bit 8 - Get/Set Extended Property Capability */
+#define HCC2_GSC BIT(8)
+/* bit 9 - Virtualization Based Trusted I/O Capability */
+#define HCC2_VTC BIT(9)
+/* bit 10 - Rsvd */
+/* bit 11 - HC support Double BW on a eUSB2 HS ISOC EP */
+#define HCC2_EUSB2_DIC BIT(11)
+/* bit 12 - HC support eUSB2V2 capability */
+#define HCC2_E2V2C BIT(12)
+/* bits 31:13 - Rsvd */
diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c
index 63edf2d8f245..9da4f3b452cb 100644
--- a/drivers/usb/host/xhci-dbgcap.c
+++ b/drivers/usb/host/xhci-dbgcap.c
@@ -374,7 +374,7 @@ int dbc_ep_queue(struct dbc_request *req)
ret = dbc_ep_do_queue(req);
spin_unlock_irqrestore(&dbc->lock, flags);
- mod_delayed_work(system_wq, &dbc->event_work, 0);
+ mod_delayed_work(system_percpu_wq, &dbc->event_work, 0);
trace_xhci_dbc_queue_request(req);
@@ -677,7 +677,7 @@ static int xhci_dbc_start(struct xhci_dbc *dbc)
return ret;
}
- return mod_delayed_work(system_wq, &dbc->event_work,
+ return mod_delayed_work(system_percpu_wq, &dbc->event_work,
msecs_to_jiffies(dbc->poll_interval));
}
@@ -892,7 +892,8 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)
dev_info(dbc->dev, "DbC configured\n");
portsc = readl(&dbc->regs->portsc);
writel(portsc, &dbc->regs->portsc);
- return EVT_GSER;
+ ret = EVT_GSER;
+ break;
}
return EVT_DONE;
@@ -954,7 +955,8 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)
break;
case TRB_TYPE(TRB_TRANSFER):
dbc_handle_xfer_event(dbc, evt);
- ret = EVT_XFER_DONE;
+ if (ret != EVT_GSER)
+ ret = EVT_XFER_DONE;
break;
default:
break;
@@ -1021,7 +1023,7 @@ static void xhci_dbc_handle_events(struct work_struct *work)
return;
}
- mod_delayed_work(system_wq, &dbc->event_work,
+ mod_delayed_work(system_percpu_wq, &dbc->event_work,
msecs_to_jiffies(poll_interval));
}
@@ -1272,7 +1274,7 @@ static ssize_t dbc_poll_interval_ms_store(struct device *dev,
dbc->poll_interval = value;
- mod_delayed_work(system_wq, &dbc->event_work, 0);
+ mod_delayed_work(system_percpu_wq, &dbc->event_work, 0);
return size;
}
@@ -1390,8 +1392,15 @@ int xhci_dbc_suspend(struct xhci_hcd *xhci)
if (!dbc)
return 0;
- if (dbc->state == DS_CONFIGURED)
+ switch (dbc->state) {
+ case DS_ENABLED:
+ case DS_CONNECTED:
+ case DS_CONFIGURED:
dbc->resume_required = 1;
+ break;
+ default:
+ break;
+ }
xhci_dbc_stop(dbc);
diff --git a/drivers/usb/host/xhci-dbgcap.h b/drivers/usb/host/xhci-dbgcap.h
index 47ac72c2286d..5426c971d2d3 100644
--- a/drivers/usb/host/xhci-dbgcap.h
+++ b/drivers/usb/host/xhci-dbgcap.h
@@ -114,6 +114,7 @@ struct dbc_port {
unsigned int tx_boundary;
bool registered;
+ bool tx_running;
};
struct dbc_driver {
diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c
index d894081d8d15..57cdda4e09c8 100644
--- a/drivers/usb/host/xhci-dbgtty.c
+++ b/drivers/usb/host/xhci-dbgtty.c
@@ -47,7 +47,7 @@ dbc_kfifo_to_req(struct dbc_port *port, char *packet)
return len;
}
-static int dbc_start_tx(struct dbc_port *port)
+static int dbc_do_start_tx(struct dbc_port *port)
__releases(&port->port_lock)
__acquires(&port->port_lock)
{
@@ -57,6 +57,8 @@ static int dbc_start_tx(struct dbc_port *port)
bool do_tty_wake = false;
struct list_head *pool = &port->write_pool;
+ port->tx_running = true;
+
while (!list_empty(pool)) {
req = list_entry(pool->next, struct dbc_request, list_pool);
len = dbc_kfifo_to_req(port, req->buf);
@@ -77,12 +79,25 @@ static int dbc_start_tx(struct dbc_port *port)
}
}
+ port->tx_running = false;
+
if (do_tty_wake && port->port.tty)
tty_wakeup(port->port.tty);
return status;
}
+/* must be called with port->port_lock held */
+static int dbc_start_tx(struct dbc_port *port)
+{
+ lockdep_assert_held(&port->port_lock);
+
+ if (port->tx_running)
+ return -EBUSY;
+
+ return dbc_do_start_tx(port);
+}
+
static void dbc_start_rx(struct dbc_port *port)
__releases(&port->port_lock)
__acquires(&port->port_lock)
@@ -535,6 +550,12 @@ static void xhci_dbc_tty_unregister_device(struct xhci_dbc *dbc)
if (!port->registered)
return;
+ /*
+ * Hang up the TTY. This wakes up any blocked
+ * writers and causes subsequent writes to fail.
+ */
+ tty_vhangup(port->port.tty);
+
tty_unregister_device(dbc_tty_driver, port->minor);
xhci_dbc_tty_exit_port(port);
port->registered = false;
diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
index c6d44977193f..c1eb1036ede9 100644
--- a/drivers/usb/host/xhci-debugfs.c
+++ b/drivers/usb/host/xhci-debugfs.c
@@ -329,7 +329,7 @@ static int xhci_portsc_show(struct seq_file *s, void *unused)
u32 portsc;
char str[XHCI_MSG_MAX];
- portsc = readl(port->addr);
+ portsc = xhci_portsc_readl(port);
seq_printf(s, "%s\n", xhci_decode_portsc(str, portsc));
return 0;
@@ -355,11 +355,11 @@ static ssize_t xhci_port_write(struct file *file, const char __user *ubuf,
if (!strncmp(buf, "compliance", 10)) {
/* If CTC is clear, compliance is enabled by default */
- if (!HCC2_CTC(xhci->hcc_params2))
+ if (!(xhci->hcc_params2 & HCC2_CTC))
return count;
spin_lock_irqsave(&xhci->lock, flags);
/* compliance mode can only be enabled on ports in RxDetect */
- portsc = readl(port->addr);
+ portsc = xhci_portsc_readl(port);
if ((portsc & PORT_PLS_MASK) != XDEV_RXDETECT) {
spin_unlock_irqrestore(&xhci->lock, flags);
return -EPERM;
@@ -367,7 +367,7 @@ static ssize_t xhci_port_write(struct file *file, const char __user *ubuf,
portsc = xhci_port_state_to_neutral(portsc);
portsc &= ~PORT_PLS_MASK;
portsc |= PORT_LINK_STROBE | XDEV_COMP_MODE;
- writel(portsc, port->addr);
+ xhci_portsc_writel(port, portsc);
spin_unlock_irqrestore(&xhci->lock, flags);
} else {
return -EINVAL;
@@ -383,6 +383,39 @@ static const struct file_operations port_fops = {
.release = single_release,
};
+static int xhci_portli_show(struct seq_file *s, void *unused)
+{
+ struct xhci_port *port = s->private;
+ struct xhci_hcd *xhci = hcd_to_xhci(port->rhub->hcd);
+ u32 portli;
+
+ portli = readl(&port->port_reg->portli);
+
+ /* PORTLI fields are valid if port is a USB3 or eUSB2V2 port */
+ if (port->rhub == &xhci->usb3_rhub)
+ seq_printf(s, "0x%08x LEC=%u RLC=%u TLC=%u\n", portli,
+ PORT_LEC(portli), PORT_RX_LANES(portli), PORT_TX_LANES(portli));
+ else if (xhci->hcc_params2 & HCC2_E2V2C)
+ seq_printf(s, "0x%08x RDR=%u TDR=%u\n", portli,
+ PORTLI_RDR(portli), PORTLI_TDR(portli));
+ else
+ seq_printf(s, "0x%08x RsvdP\n", portli);
+
+ return 0;
+}
+
+static int xhci_portli_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, xhci_portli_show, inode->i_private);
+}
+
+static const struct file_operations portli_fops = {
+ .open = xhci_portli_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static void xhci_debugfs_create_files(struct xhci_hcd *xhci,
struct xhci_file_map *files,
size_t nentries, void *data,
@@ -613,28 +646,24 @@ void xhci_debugfs_remove_slot(struct xhci_hcd *xhci, int slot_id)
static void xhci_debugfs_create_ports(struct xhci_hcd *xhci,
struct dentry *parent)
{
- unsigned int num_ports;
char port_name[8];
struct xhci_port *port;
struct dentry *dir;
- num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
-
parent = debugfs_create_dir("ports", parent);
- while (num_ports--) {
- scnprintf(port_name, sizeof(port_name), "port%02d",
- num_ports + 1);
+ for (int i = 0; i < xhci->max_ports; i++) {
+ scnprintf(port_name, sizeof(port_name), "port%02d", i + 1);
dir = debugfs_create_dir(port_name, parent);
- port = &xhci->hw_ports[num_ports];
+ port = &xhci->hw_ports[i];
debugfs_create_file("portsc", 0644, dir, port, &port_fops);
+ debugfs_create_file("portli", 0444, dir, port, &portli_fops);
}
}
static int xhci_port_bw_show(struct xhci_hcd *xhci, u8 dev_speed,
struct seq_file *s)
{
- unsigned int num_ports;
unsigned int i;
int ret;
struct xhci_container_ctx *ctx;
@@ -645,8 +674,6 @@ static int xhci_port_bw_show(struct xhci_hcd *xhci, u8 dev_speed,
if (ret < 0)
return ret;
- num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
-
ctx = xhci_alloc_port_bw_ctx(xhci, 0);
if (!ctx) {
pm_runtime_put_sync(dev);
@@ -661,7 +688,7 @@ static int xhci_port_bw_show(struct xhci_hcd *xhci, u8 dev_speed,
/* print all roothub ports available bandwidth
* refer to xhci rev1_2 protocol 6.2.6 , byte 0 is reserved
*/
- for (i = 1; i < num_ports+1; i++)
+ for (i = 1; i <= xhci->max_ports; i++)
seq_printf(s, "port[%d] available bw: %d%%.\n", i,
ctx->bytes[i]);
err_out:
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index b3a59ce1b3f4..04cc3d681495 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -110,7 +110,7 @@ static int xhci_create_usb3x_bos_desc(struct xhci_hcd *xhci, char *buf,
ss_cap->bU2DevExitLat = 0; /* set later */
reg = readl(&xhci->cap_regs->hcc_params);
- if (HCC_LTC(reg))
+ if (reg & HCC_LTC)
ss_cap->bmAttributes |= USB_LTM_SUPPORT;
if ((xhci->quirks & XHCI_LPM_SUPPORT)) {
@@ -263,7 +263,7 @@ static void xhci_common_hub_descriptor(struct xhci_hcd *xhci,
desc->bNbrPorts = ports;
temp = 0;
/* Bits 1:0 - support per-port power switching, or power always on */
- if (HCC_PPC(xhci->hcc_params))
+ if (xhci->hcc_params & HCC_PPC)
temp |= HUB_CHAR_INDV_PORT_LPSM;
else
temp |= HUB_CHAR_NO_LPSM;
@@ -299,7 +299,7 @@ static void xhci_usb2_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
*/
memset(port_removable, 0, sizeof(port_removable));
for (i = 0; i < ports; i++) {
- portsc = readl(rhub->ports[i]->addr);
+ portsc = xhci_portsc_readl(rhub->ports[i]);
/* If a device is removable, PORTSC reports a 0, same as in the
* hub descriptor DeviceRemovable bits.
*/
@@ -356,7 +356,7 @@ static void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
port_removable = 0;
/* bit 0 is reserved, bit 1 is for port 1, etc. */
for (i = 0; i < ports; i++) {
- portsc = readl(rhub->ports[i]->addr);
+ portsc = xhci_portsc_readl(rhub->ports[i]);
if (portsc & PORT_DEV_REMOVE)
port_removable |= 1 << (i + 1);
}
@@ -566,19 +566,19 @@ static void xhci_disable_port(struct xhci_hcd *xhci, struct xhci_port *port)
return;
}
- portsc = readl(port->addr);
+ portsc = xhci_portsc_readl(port);
portsc = xhci_port_state_to_neutral(portsc);
/* Write 1 to disable the port */
- writel(portsc | PORT_PE, port->addr);
+ xhci_portsc_writel(port, portsc | PORT_PE);
- portsc = readl(port->addr);
+ portsc = xhci_portsc_readl(port);
xhci_dbg(xhci, "disable port %d-%d, portsc: 0x%x\n",
hcd->self.busnum, port->hcd_portnum + 1, portsc);
}
static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
- u16 wIndex, __le32 __iomem *addr, u32 port_status)
+ u16 wIndex, struct xhci_port *port, u32 port_status)
{
char *port_change_bit;
u32 status;
@@ -621,8 +621,8 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
return;
}
/* Change bits are all write 1 to clear */
- writel(port_status | status, addr);
- port_status = readl(addr);
+ xhci_portsc_writel(port, port_status | status);
+ port_status = xhci_portsc_readl(port);
xhci_dbg(xhci, "clear port%d %s change, portsc: 0x%x\n",
wIndex + 1, port_change_bit, port_status);
@@ -650,7 +650,7 @@ static void xhci_set_port_power(struct xhci_hcd *xhci, struct xhci_port *port,
u32 temp;
hcd = port->rhub->hcd;
- temp = readl(port->addr);
+ temp = xhci_portsc_readl(port);
xhci_dbg(xhci, "set port power %d-%d %s, portsc: 0x%x\n",
hcd->self.busnum, port->hcd_portnum + 1, on ? "ON" : "OFF", temp);
@@ -659,11 +659,11 @@ static void xhci_set_port_power(struct xhci_hcd *xhci, struct xhci_port *port,
if (on) {
/* Power on */
- writel(temp | PORT_POWER, port->addr);
- readl(port->addr);
+ xhci_portsc_writel(port, temp | PORT_POWER);
+ xhci_portsc_readl(port);
} else {
/* Power off */
- writel(temp & ~PORT_POWER, port->addr);
+ xhci_portsc_writel(port, temp & ~PORT_POWER);
}
spin_unlock_irqrestore(&xhci->lock, *flags);
@@ -683,9 +683,9 @@ static void xhci_port_set_test_mode(struct xhci_hcd *xhci,
/* xhci only supports test mode for usb2 ports */
port = xhci->usb2_rhub.ports[wIndex];
- temp = readl(port->addr + PORTPMSC);
+ temp = readl(&port->port_reg->portpmsc);
temp |= test_mode << PORT_TEST_MODE_SHIFT;
- writel(temp, port->addr + PORTPMSC);
+ writel(temp, &port->port_reg->portpmsc);
xhci->test_mode = test_mode;
if (test_mode == USB_TEST_FORCE_ENABLE)
xhci_start(xhci);
@@ -700,7 +700,7 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci,
/* Disable all Device Slots */
xhci_dbg(xhci, "Disable all slots\n");
spin_unlock_irqrestore(&xhci->lock, *flags);
- for (i = 1; i <= HCS_MAX_SLOTS(xhci->hcs_params1); i++) {
+ for (i = 1; i <= xhci->max_slots; i++) {
if (!xhci->devs[i])
continue;
@@ -801,11 +801,11 @@ void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,
u32 temp;
u32 portsc;
- portsc = readl(port->addr);
+ portsc = xhci_portsc_readl(port);
temp = xhci_port_state_to_neutral(portsc);
temp &= ~PORT_PLS_MASK;
temp |= PORT_LINK_STROBE | link_state;
- writel(temp, port->addr);
+ xhci_portsc_writel(port, temp);
xhci_dbg(xhci, "Set port %d-%d link state, portsc: 0x%x, write 0x%x",
port->rhub->hcd->self.busnum, port->hcd_portnum + 1,
@@ -817,7 +817,7 @@ static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
{
u32 temp;
- temp = readl(port->addr);
+ temp = xhci_portsc_readl(port);
temp = xhci_port_state_to_neutral(temp);
if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_CONNECT)
@@ -835,7 +835,7 @@ static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
else
temp &= ~PORT_WKOC_E;
- writel(temp, port->addr);
+ xhci_portsc_writel(port, temp);
}
/* Test and clear port RWC bit */
@@ -844,11 +844,11 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, struct xhci_port *port,
{
u32 temp;
- temp = readl(port->addr);
+ temp = xhci_portsc_readl(port);
if (temp & port_bit) {
temp = xhci_port_state_to_neutral(temp);
temp |= port_bit;
- writel(temp, port->addr);
+ xhci_portsc_writel(port, temp);
}
}
@@ -1002,7 +1002,7 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
}
xhci_ring_device(xhci, port->slot_id);
} else {
- int port_status = readl(port->addr);
+ int port_status = xhci_portsc_readl(port);
xhci_warn(xhci, "Port resume timed out, port %d-%d: 0x%x\n",
hcd->self.busnum, wIndex + 1, port_status);
@@ -1263,7 +1263,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
wIndex--;
port = ports[portnum1 - 1];
- temp = readl(port->addr);
+ temp = xhci_portsc_readl(port);
if (temp == ~(u32)0) {
xhci_hc_died(xhci);
retval = -ENODEV;
@@ -1288,7 +1288,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
retval = -EINVAL;
break;
}
- port_li = readl(port->addr + PORTLI);
+ port_li = readl(&port->port_reg->portli);
status = xhci_get_ext_port_status(temp, port_li);
put_unaligned_le32(status, &buf[4]);
}
@@ -1309,7 +1309,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
port = ports[portnum1 - 1];
wIndex--;
- temp = readl(port->addr);
+ temp = xhci_portsc_readl(port);
if (temp == ~(u32)0) {
xhci_hc_died(xhci);
retval = -ENODEV;
@@ -1319,7 +1319,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
/* FIXME: What new port features do we need to support? */
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
- temp = readl(port->addr);
+ temp = xhci_portsc_readl(port);
if ((temp & PORT_PLS_MASK) != XDEV_U0) {
/* Resume the port to U0 first */
xhci_set_link_state(xhci, port, XDEV_U0);
@@ -1331,7 +1331,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
* a port unless the port reports that it is in the
* enabled (PED = ‘1’,PLS < ‘3’) state.
*/
- temp = readl(port->addr);
+ temp = xhci_portsc_readl(port);
if ((temp & PORT_PE) == 0 || (temp & PORT_RESET)
|| (temp & PORT_PLS_MASK) >= XDEV_U3) {
xhci_warn(xhci, "USB core suspending port %d-%d not in U0/U1/U2\n",
@@ -1354,11 +1354,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
msleep(10); /* wait device to enter */
spin_lock_irqsave(&xhci->lock, flags);
- temp = readl(port->addr);
+ temp = xhci_portsc_readl(port);
bus_state->suspended_ports |= 1 << wIndex;
break;
case USB_PORT_FEAT_LINK_STATE:
- temp = readl(port->addr);
+ temp = xhci_portsc_readl(port);
/* Disable port */
if (link_state == USB_SS_PORT_LS_SS_DISABLED) {
xhci_dbg(xhci, "Disable port %d-%d\n",
@@ -1371,8 +1371,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp |= PORT_CSC | PORT_PEC | PORT_WRC |
PORT_OCC | PORT_RC | PORT_PLC |
PORT_CEC;
- writel(temp | PORT_PE, port->addr);
- temp = readl(port->addr);
+ xhci_portsc_writel(port, temp | PORT_PE);
+ temp = xhci_portsc_readl(port);
break;
}
@@ -1381,7 +1381,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_dbg(xhci, "Enable port %d-%d\n",
hcd->self.busnum, portnum1);
xhci_set_link_state(xhci, port, link_state);
- temp = readl(port->addr);
+ temp = xhci_portsc_readl(port);
break;
}
@@ -1400,7 +1400,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
* automatically entered as on 1.0 and prior.
*/
if (link_state == USB_SS_PORT_LS_COMP_MOD) {
- if (!HCC2_CTC(xhci->hcc_params2)) {
+ if (!(xhci->hcc_params2 & HCC2_CTC)) {
xhci_dbg(xhci, "CTC flag is 0, port already supports entering compliance mode\n");
break;
}
@@ -1414,7 +1414,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
hcd->self.busnum, portnum1);
xhci_set_link_state(xhci, port, link_state);
- temp = readl(port->addr);
+ temp = xhci_portsc_readl(port);
break;
}
/* Port must be enabled */
@@ -1462,7 +1462,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_dbg(xhci, "missing U0 port change event for port %d-%d\n",
hcd->self.busnum, portnum1);
spin_lock_irqsave(&xhci->lock, flags);
- temp = readl(port->addr);
+ temp = xhci_portsc_readl(port);
break;
}
@@ -1480,12 +1480,12 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
spin_unlock_irqrestore(&xhci->lock, flags);
while (retries--) {
usleep_range(4000, 8000);
- temp = readl(port->addr);
+ temp = xhci_portsc_readl(port);
if ((temp & PORT_PLS_MASK) == XDEV_U3)
break;
}
spin_lock_irqsave(&xhci->lock, flags);
- temp = readl(port->addr);
+ temp = xhci_portsc_readl(port);
bus_state->suspended_ports |= 1 << wIndex;
}
break;
@@ -1500,38 +1500,38 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
break;
case USB_PORT_FEAT_RESET:
temp = (temp | PORT_RESET);
- writel(temp, port->addr);
+ xhci_portsc_writel(port, temp);
- temp = readl(port->addr);
+ temp = xhci_portsc_readl(port);
xhci_dbg(xhci, "set port reset, actual port %d-%d status = 0x%x\n",
hcd->self.busnum, portnum1, temp);
break;
case USB_PORT_FEAT_REMOTE_WAKE_MASK:
xhci_set_remote_wake_mask(xhci, port, wake_mask);
- temp = readl(port->addr);
+ temp = xhci_portsc_readl(port);
xhci_dbg(xhci, "set port remote wake mask, actual port %d-%d status = 0x%x\n",
hcd->self.busnum, portnum1, temp);
break;
case USB_PORT_FEAT_BH_PORT_RESET:
temp |= PORT_WR;
- writel(temp, port->addr);
- temp = readl(port->addr);
+ xhci_portsc_writel(port, temp);
+ temp = xhci_portsc_readl(port);
break;
case USB_PORT_FEAT_U1_TIMEOUT:
if (hcd->speed < HCD_USB3)
goto error;
- temp = readl(port->addr + PORTPMSC);
+ temp = readl(&port->port_reg->portpmsc);
temp &= ~PORT_U1_TIMEOUT_MASK;
temp |= PORT_U1_TIMEOUT(timeout);
- writel(temp, port->addr + PORTPMSC);
+ writel(temp, &port->port_reg->portpmsc);
break;
case USB_PORT_FEAT_U2_TIMEOUT:
if (hcd->speed < HCD_USB3)
goto error;
- temp = readl(port->addr + PORTPMSC);
+ temp = readl(&port->port_reg->portpmsc);
temp &= ~PORT_U2_TIMEOUT_MASK;
temp |= PORT_U2_TIMEOUT(timeout);
- writel(temp, port->addr + PORTPMSC);
+ writel(temp, &port->port_reg->portpmsc);
break;
case USB_PORT_FEAT_TEST:
/* 4.19.6 Port Test Modes (USB2 Test Mode) */
@@ -1547,7 +1547,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
goto error;
}
/* unblock any posted writes */
- temp = readl(port->addr);
+ temp = xhci_portsc_readl(port);
break;
case ClearPortFeature:
if (!portnum1 || portnum1 > max_ports)
@@ -1556,7 +1556,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
port = ports[portnum1 - 1];
wIndex--;
- temp = readl(port->addr);
+ temp = xhci_portsc_readl(port);
if (temp == ~(u32)0) {
xhci_hc_died(xhci);
retval = -ENODEV;
@@ -1566,7 +1566,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp = xhci_port_state_to_neutral(temp);
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
- temp = readl(port->addr);
+ temp = xhci_portsc_readl(port);
xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n");
xhci_dbg(xhci, "PORTSC %04x\n", temp);
if (temp & PORT_RESET)
@@ -1603,8 +1603,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case USB_PORT_FEAT_C_ENABLE:
case USB_PORT_FEAT_C_PORT_LINK_STATE:
case USB_PORT_FEAT_C_PORT_CONFIG_ERROR:
- xhci_clear_port_change_bit(xhci, wValue, wIndex,
- port->addr, temp);
+ xhci_clear_port_change_bit(xhci, wValue, wIndex, port, temp);
break;
case USB_PORT_FEAT_ENABLE:
xhci_disable_port(xhci, port);
@@ -1671,7 +1670,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
* SS devices are only visible to roothub after link training completes.
* Keep polling roothubs for a grace period after xHC start
*/
- if (xhci->run_graceperiod) {
+ if (hcd->speed >= HCD_USB3 && xhci->run_graceperiod) {
if (time_before(jiffies, xhci->run_graceperiod))
status = 1;
else
@@ -1682,7 +1681,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
/* For each port, did anything change? If so, set that bit in buf. */
for (i = 0; i < max_ports; i++) {
- temp = readl(ports[i]->addr);
+ temp = xhci_portsc_readl(ports[i]);
if (temp == ~(u32)0) {
xhci_hc_died(xhci);
retval = -ENODEV;
@@ -1751,7 +1750,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
u32 t1, t2;
int retries = 10;
retry:
- t1 = readl(ports[port_index]->addr);
+ t1 = xhci_portsc_readl(ports[port_index]);
t2 = xhci_port_state_to_neutral(t1);
portsc_buf[port_index] = 0;
@@ -1829,7 +1828,7 @@ retry:
spin_lock_irqsave(&xhci->lock, flags);
}
}
- writel(portsc_buf[port_index], ports[port_index]->addr);
+ xhci_portsc_writel(ports[port_index], portsc_buf[port_index]);
}
hcd->state = HC_STATE_SUSPENDED;
bus_state->next_statechange = jiffies + msecs_to_jiffies(10);
@@ -1850,7 +1849,7 @@ static bool xhci_port_missing_cas_quirk(struct xhci_port *port)
{
u32 portsc;
- portsc = readl(port->addr);
+ portsc = xhci_portsc_readl(port);
/* if any of these are set we are not stuck */
if (portsc & (PORT_CONNECT | PORT_CAS))
@@ -1863,9 +1862,9 @@ static bool xhci_port_missing_cas_quirk(struct xhci_port *port)
/* clear wakeup/change bits, and do a warm port reset */
portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
portsc |= PORT_WR;
- writel(portsc, port->addr);
+ xhci_portsc_writel(port, portsc);
/* flush write */
- readl(port->addr);
+ xhci_portsc_readl(port);
return true;
}
@@ -1912,7 +1911,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
}
port_index = max_ports;
while (port_index--) {
- portsc = readl(ports[port_index]->addr);
+ portsc = xhci_portsc_readl(ports[port_index]);
/* warm reset CAS limited ports stuck in polling/compliance */
if ((xhci->quirks & XHCI_MISSING_CAS) &&
@@ -1942,7 +1941,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
}
/* disable wake for all ports, write new link state if needed */
portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
- writel(portsc, ports[port_index]->addr);
+ xhci_portsc_writel(ports[port_index], portsc);
}
/* USB2 specific resume signaling delay and U0 link state transition */
@@ -1963,7 +1962,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
/* poll for U0 link state complete, both USB2 and USB3 */
for_each_set_bit(port_index, &bus_state->bus_suspended, BITS_PER_LONG) {
- sret = xhci_handshake(ports[port_index]->addr, PORT_PLC,
+ sret = xhci_handshake(&ports[port_index]->port_reg->portsc, PORT_PLC,
PORT_PLC, 10 * 1000);
if (sret) {
xhci_warn(xhci, "port %d-%d resume PLC timeout\n",
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 6e5b6057de79..c708bdd69f16 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -463,7 +463,7 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
return NULL;
ctx->type = type;
- ctx->size = HCC_64BYTE_CONTEXT(xhci->hcc_params) ? 2048 : 1024;
+ ctx->size = xhci->hcc_params & HCC_64BYTE_CONTEXT ? 2048 : 1024;
if (type == XHCI_CTX_TYPE_INPUT)
ctx->size += CTX_SIZE(xhci->hcc_params);
@@ -951,7 +951,7 @@ static void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_i
/* is this a hub device that added a tt_info to the tts list */
if (tt_info->slot_id == slot_id) {
/* are any devices using this tt_info? */
- for (i = 1; i < HCS_MAX_SLOTS(xhci->hcs_params1); i++) {
+ for (i = 1; i < xhci->max_slots; i++) {
vdev = xhci->devs[i];
if (vdev && (vdev->tt_info == tt_info))
xhci_free_virt_devices_depth_first(
@@ -1344,7 +1344,7 @@ static u32 xhci_get_endpoint_mult(struct xhci_hcd *xhci,
bool lec;
/* xHCI 1.1 with LEC set does not use mult field, except intel eUSB2 */
- lec = xhci->hci_version > 0x100 && HCC2_LEC(xhci->hcc_params2);
+ lec = xhci->hci_version > 0x100 && (xhci->hcc_params2 & HCC2_LEC);
/* eUSB2 double isoc bw devices are the only USB2 devices using mult */
if (usb_endpoint_is_hs_isoc_double(udev, ep) &&
@@ -1433,8 +1433,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
ring_type = usb_endpoint_type(&ep->desc);
/* Ensure host supports double isoc bandwidth for eUSB2 devices */
- if (usb_endpoint_is_hs_isoc_double(udev, ep) &&
- !HCC2_EUSB2_DIC(xhci->hcc_params2)) {
+ if (usb_endpoint_is_hs_isoc_double(udev, ep) && !(xhci->hcc_params2 & HCC2_EUSB2_DIC)) {
dev_dbg(&udev->dev, "Double Isoc Bandwidth not supported by xhci\n");
return -EINVAL;
}
@@ -1899,7 +1898,7 @@ EXPORT_SYMBOL_GPL(xhci_remove_secondary_interrupter);
void xhci_mem_cleanup(struct xhci_hcd *xhci)
{
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
- int i, j, num_ports;
+ int i, j;
cancel_delayed_work_sync(&xhci->cmd_timer);
@@ -1918,8 +1917,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed command ring");
xhci_cleanup_command_queue(xhci);
- num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
- for (i = 0; i < num_ports && xhci->rh_bw; i++) {
+ for (i = 0; i < xhci->max_ports && xhci->rh_bw; i++) {
struct xhci_interval_bw_table *bwt = &xhci->rh_bw[i].bw_table;
for (j = 0; j < XHCI_MAX_INTERVAL; j++) {
struct list_head *ep = &bwt->interval_bw[j].endpoints;
@@ -1928,7 +1926,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
}
}
- for (i = HCS_MAX_SLOTS(xhci->hcs_params1); i > 0; i--)
+ for (i = xhci->max_slots; i > 0; i--)
xhci_free_virt_devices_depth_first(xhci, i);
dma_pool_destroy(xhci->segment_pool);
@@ -1964,7 +1962,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
if (!xhci->rh_bw)
goto no_bw;
- for (i = 0; i < num_ports; i++) {
+ for (i = 0; i < xhci->max_ports; i++) {
struct xhci_tt_bw_info *tt, *n;
list_for_each_entry_safe(tt, n, &xhci->rh_bw[i].tts, tt_list) {
list_del(&tt->tt_list);
@@ -2165,7 +2163,7 @@ static void xhci_create_rhub_port_array(struct xhci_hcd *xhci,
if (!rhub->ports)
return;
- for (i = 0; i < HCS_MAX_PORTS(xhci->hcs_params1); i++) {
+ for (i = 0; i < xhci->max_ports; i++) {
if (xhci->hw_ports[i].rhub != rhub ||
xhci->hw_ports[i].hcd_portnum == DUPLICATE_ENTRY)
continue;
@@ -2188,32 +2186,28 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
{
void __iomem *base;
u32 offset;
- unsigned int num_ports;
int i, j;
int cap_count = 0;
u32 cap_start;
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
- num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
- xhci->hw_ports = kcalloc_node(num_ports, sizeof(*xhci->hw_ports),
- flags, dev_to_node(dev));
+ xhci->hw_ports = kcalloc_node(xhci->max_ports, sizeof(*xhci->hw_ports),
+ flags, dev_to_node(dev));
if (!xhci->hw_ports)
return -ENOMEM;
- for (i = 0; i < num_ports; i++) {
- xhci->hw_ports[i].addr = &xhci->op_regs->port_status_base +
- NUM_PORT_REGS * i;
+ for (i = 0; i < xhci->max_ports; i++) {
+ xhci->hw_ports[i].port_reg = &xhci->op_regs->port_regs[i];
xhci->hw_ports[i].hw_portnum = i;
init_completion(&xhci->hw_ports[i].rexit_done);
init_completion(&xhci->hw_ports[i].u3exit_done);
}
- xhci->rh_bw = kcalloc_node(num_ports, sizeof(*xhci->rh_bw), flags,
- dev_to_node(dev));
+ xhci->rh_bw = kcalloc_node(xhci->max_ports, sizeof(*xhci->rh_bw), flags, dev_to_node(dev));
if (!xhci->rh_bw)
return -ENOMEM;
- for (i = 0; i < num_ports; i++) {
+ for (i = 0; i < xhci->max_ports; i++) {
struct xhci_interval_bw_table *bw_table;
INIT_LIST_HEAD(&xhci->rh_bw[i].tts);
@@ -2245,9 +2239,8 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
offset = cap_start;
while (offset) {
- xhci_add_in_port(xhci, num_ports, base + offset, cap_count);
- if (xhci->usb2_rhub.num_ports + xhci->usb3_rhub.num_ports ==
- num_ports)
+ xhci_add_in_port(xhci, xhci->max_ports, base + offset, cap_count);
+ if (xhci->usb2_rhub.num_ports + xhci->usb3_rhub.num_ports == xhci->max_ports)
break;
offset = xhci_find_next_ext_cap(base, offset,
XHCI_EXT_CAPS_PROTOCOL);
diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
index 208558cf822d..06043c7c3100 100644
--- a/drivers/usb/host/xhci-mtk.c
+++ b/drivers/usb/host/xhci-mtk.c
@@ -670,7 +670,6 @@ static int xhci_mtk_probe(struct platform_device *pdev)
}
device_enable_async_suspend(dev);
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
pm_runtime_forbid(dev);
diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h
index f5e2bd66bb1b..2274f5995171 100644
--- a/drivers/usb/host/xhci-mtk.h
+++ b/drivers/usb/host/xhci-mtk.h
@@ -21,7 +21,7 @@
/* support at most 64 ep, use 32 size hash table */
#define SCH_EP_HASH_BITS 5
-/**
+/*
* To simplify scheduler algorithm, set a upper limit for ESIT,
* if a synchromous ep's ESIT is larger than @XHCI_MTK_MAX_ESIT,
* round down to the limit value, that means allocating more
@@ -34,6 +34,7 @@
#define XHCI_MTK_FRAMES_CNT (XHCI_MTK_MAX_ESIT / UFRAMES_PER_FRAME)
/**
+ * struct mu3h_sch_tt - TT scheduling data
* @fs_bus_bw_out: save bandwidth used by FS/LS OUT eps in each uframes
* @fs_bus_bw_in: save bandwidth used by FS/LS IN eps in each uframes
* @ls_bus_bw: save bandwidth used by LS eps in each uframes
@@ -51,7 +52,7 @@ struct mu3h_sch_tt {
};
/**
- * struct mu3h_sch_bw_info: schedule information for bandwidth domain
+ * struct mu3h_sch_bw_info - schedule information for bandwidth domain
*
* @bus_bw: array to keep track of bandwidth already used at each uframes
*
@@ -63,7 +64,7 @@ struct mu3h_sch_bw_info {
};
/**
- * struct mu3h_sch_ep_info: schedule information for endpoint
+ * struct mu3h_sch_ep_info - schedule information for endpoint
*
* @esit: unit is 125us, equal to 2 << Interval field in ep-context
* @num_esit: number of @esit in a period
@@ -77,6 +78,7 @@ struct mu3h_sch_bw_info {
* @ep_type: endpoint type
* @maxpkt: max packet size of endpoint
* @ep: address of usb_host_endpoint struct
+ * @speed: usb device speed
* @allocated: the bandwidth is aready allocated from bus_bw
* @offset: which uframe of the interval that transfer should be
* scheduled first time within the interval
@@ -125,7 +127,7 @@ struct mu3h_sch_ep_info {
#define MU3C_U2_PORT_MAX 5
/**
- * struct mu3c_ippc_regs: MTK ssusb ip port control registers
+ * struct mu3c_ippc_regs - MTK ssusb ip port control registers
* @ip_pw_ctr0~3: ip power and clock control registers
* @ip_pw_sts1~2: ip power and clock status registers
* @ip_xhci_cap: ip xHCI capability register
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 5c8ab519f497..585b2f3117b0 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -582,6 +582,8 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
if (!usb_hcd_is_primary_hcd(hcd))
return 0;
+ xhci->allow_single_roothub = 1;
+
if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
xhci_pme_acpi_rtd3_enable(pdev);
@@ -637,7 +639,6 @@ int xhci_pci_common_probe(struct pci_dev *dev, const struct pci_device_id *id)
xhci = hcd_to_xhci(hcd);
xhci->reset = reset;
- xhci->allow_single_roothub = 1;
if (!xhci_has_one_roothub(xhci)) {
xhci->shared_hcd = usb_create_shared_hcd(&xhci_pci_hc_driver, &dev->dev,
pci_name(dev), hcd);
@@ -895,9 +896,9 @@ static int xhci_pci_poweroff_late(struct usb_hcd *hcd, bool do_wakeup)
if (!(xhci->quirks & XHCI_RESET_TO_DEFAULT))
return 0;
- for (i = 0; i < HCS_MAX_PORTS(xhci->hcs_params1); i++) {
+ for (i = 0; i < xhci->max_ports; i++) {
port = &xhci->hw_ports[i];
- portsc = readl(port->addr);
+ portsc = xhci_portsc_readl(port);
if ((portsc & PORT_PLS_MASK) != XDEV_U3)
continue;
@@ -918,7 +919,7 @@ static int xhci_pci_poweroff_late(struct usb_hcd *hcd, bool do_wakeup)
xhci_dbg(xhci, "port %d-%d in U3 without wakeup, disable it\n",
port->rhub->hcd->self.busnum, port->hcd_portnum + 1);
portsc = xhci_port_state_to_neutral(portsc);
- writel(portsc | PORT_PE, port->addr);
+ xhci_portsc_writel(port, portsc | PORT_PE);
}
return 0;
diff --git a/drivers/usb/host/xhci-port.h b/drivers/usb/host/xhci-port.h
index f19efb966d18..889b5fb0fcd8 100644
--- a/drivers/usb/host/xhci-port.h
+++ b/drivers/usb/host/xhci-port.h
@@ -144,9 +144,14 @@
#define PORT_TEST_MODE_SHIFT 28
/* USB3 Protocol PORTLI Port Link Information */
+#define PORT_LEC(p) ((p) & 0xffff)
#define PORT_RX_LANES(p) (((p) >> 16) & 0xf)
#define PORT_TX_LANES(p) (((p) >> 20) & 0xf)
+/* eUSB2v2 protocol PORTLI Port Link information, RsvdP for normal USB2 */
+#define PORTLI_RDR(p) ((p) & 0xf)
+#define PORTLI_TDR(p) (((p) >> 4) & 0xf)
+
/* USB2 Protocol PORTHLPMC */
#define PORT_HIRDM(p)((p) & 3)
#define PORT_L1_TIMEOUT(p)(((p) & 0xff) << 2)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 8e209aa33ea7..9315ba18310d 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -82,6 +82,23 @@ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg,
return seg->dma + (segment_offset * sizeof(*trb));
}
+static union xhci_trb *xhci_dma_to_trb(struct xhci_segment *start_seg,
+ dma_addr_t dma,
+ struct xhci_segment **match_seg)
+{
+ struct xhci_segment *seg;
+
+ xhci_for_each_ring_seg(start_seg, seg) {
+ if (in_range(dma, seg->dma, TRB_SEGMENT_SIZE)) {
+ if (match_seg)
+ *match_seg = seg;
+ return &seg->trbs[(dma - seg->dma) / sizeof(union xhci_trb)];
+ }
+ }
+
+ return NULL;
+}
+
static bool trb_is_noop(union xhci_trb *trb)
{
return TRB_TYPE_NOOP_LE32(trb->generic.field[3]);
@@ -128,11 +145,11 @@ static void inc_td_cnt(struct urb *urb)
urb_priv->num_tds_done++;
}
-static void trb_to_noop(union xhci_trb *trb, u32 noop_type)
+static void trb_to_noop(union xhci_trb *trb, u32 noop_type, bool unchain_links)
{
if (trb_is_link(trb)) {
- /* unchain chained link TRBs */
- trb->link.control &= cpu_to_le32(~TRB_CHAIN);
+ if (unchain_links)
+ trb->link.control &= cpu_to_le32(~TRB_CHAIN);
} else {
trb->generic.field[0] = 0;
trb->generic.field[1] = 0;
@@ -143,6 +160,11 @@ static void trb_to_noop(union xhci_trb *trb, u32 noop_type)
}
}
+static unsigned int trb_to_pos(struct xhci_segment *seg, union xhci_trb *trb)
+{
+ return seg->num * TRBS_PER_SEGMENT + (trb - seg->trbs);
+}
+
/* Updates trb to point to the next TRB in the ring, and updates seg if the next
* TRB is in a new segment. This does not skip over link TRBs, and it does not
* effect the ring dequeue or enqueue pointers.
@@ -282,55 +304,34 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
inc_enq_past_link(xhci, ring, chain);
}
-/*
- * If the suspect DMA address is a TRB in this TD, this function returns that
- * TRB's segment. Otherwise it returns 0.
- */
-static struct xhci_segment *trb_in_td(struct xhci_td *td, dma_addr_t suspect_dma)
+static bool dma_in_range(dma_addr_t dma,
+ struct xhci_segment *start_seg, union xhci_trb *start_trb,
+ struct xhci_segment *end_seg, union xhci_trb *end_trb)
{
- dma_addr_t start_dma;
- dma_addr_t end_seg_dma;
- dma_addr_t end_trb_dma;
- struct xhci_segment *cur_seg;
+ unsigned int pos, start, end;
+ struct xhci_segment *pos_seg;
+ union xhci_trb *pos_trb = xhci_dma_to_trb(start_seg, dma, &pos_seg);
- start_dma = xhci_trb_virt_to_dma(td->start_seg, td->start_trb);
- cur_seg = td->start_seg;
+ /* Is the trb dma address even part of the whole ring? */
+ if (!pos_trb)
+ return false;
- do {
- if (start_dma == 0)
- return NULL;
- /* We may get an event for a Link TRB in the middle of a TD */
- end_seg_dma = xhci_trb_virt_to_dma(cur_seg,
- &cur_seg->trbs[TRBS_PER_SEGMENT - 1]);
- /* If the end TRB isn't in this segment, this is set to 0 */
- end_trb_dma = xhci_trb_virt_to_dma(cur_seg, td->end_trb);
-
- if (end_trb_dma > 0) {
- /* The end TRB is in this segment, so suspect should be here */
- if (start_dma <= end_trb_dma) {
- if (suspect_dma >= start_dma && suspect_dma <= end_trb_dma)
- return cur_seg;
- } else {
- /* Case for one segment with
- * a TD wrapped around to the top
- */
- if ((suspect_dma >= start_dma &&
- suspect_dma <= end_seg_dma) ||
- (suspect_dma >= cur_seg->dma &&
- suspect_dma <= end_trb_dma))
- return cur_seg;
- }
- return NULL;
- }
- /* Might still be somewhere in this segment */
- if (suspect_dma >= start_dma && suspect_dma <= end_seg_dma)
- return cur_seg;
+ pos = trb_to_pos(pos_seg, pos_trb);
+ start = trb_to_pos(start_seg, start_trb);
+ end = trb_to_pos(end_seg, end_trb);
- cur_seg = cur_seg->next;
- start_dma = xhci_trb_virt_to_dma(cur_seg, &cur_seg->trbs[0]);
- } while (cur_seg != td->start_seg);
+ /* end position is smaller than start, search range wraps around */
+ if (end < start)
+ return !(pos > end && pos < start);
- return NULL;
+ return (pos >= start && pos <= end);
+}
+
+/* If the suspect DMA address is a TRB in this TD, this function returns true */
+static bool trb_in_td(struct xhci_td *td, dma_addr_t suspect_dma)
+{
+ return dma_in_range(suspect_dma, td->start_seg, td->start_trb,
+ td->end_seg, td->end_trb);
}
/*
@@ -434,7 +435,7 @@ void xhci_ring_cmd_db(struct xhci_hcd *xhci)
static bool xhci_mod_cmd_timer(struct xhci_hcd *xhci)
{
- return mod_delayed_work(system_wq, &xhci->cmd_timer,
+ return mod_delayed_work(system_percpu_wq, &xhci->cmd_timer,
msecs_to_jiffies(xhci->current_cmd->timeout_ms));
}
@@ -465,7 +466,7 @@ static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci,
xhci_dbg(xhci, "Turn aborted command %p to no-op\n",
i_cmd->command_trb);
- trb_to_noop(i_cmd->command_trb, TRB_CMD_NOOP);
+ trb_to_noop(i_cmd->command_trb, TRB_CMD_NOOP, false);
/*
* caller waiting for completion is called when command
@@ -797,13 +798,18 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci,
* (The last TRB actually points to the ring enqueue pointer, which is not part
* of this TD.) This is used to remove partially enqueued isoc TDs from a ring.
*/
-static void td_to_noop(struct xhci_td *td, bool flip_cycle)
+static void td_to_noop(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
+ struct xhci_td *td, bool flip_cycle)
{
+ bool unchain_links;
struct xhci_segment *seg = td->start_seg;
union xhci_trb *trb = td->start_trb;
+ /* link TRBs should now be unchained, but some old HCs expect otherwise */
+ unchain_links = !xhci_link_chain_quirk(xhci, ep->ring ? ep->ring->type : TYPE_STREAM);
+
while (1) {
- trb_to_noop(trb, TRB_TR_NOOP);
+ trb_to_noop(trb, TRB_TR_NOOP, unchain_links);
/* flip cycle if asked to */
if (flip_cycle && trb != td->start_trb && trb != td->end_trb)
@@ -1091,16 +1097,16 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep)
"Found multiple active URBs %p and %p in stream %u?\n",
td->urb, cached_td->urb,
td->urb->stream_id);
- td_to_noop(cached_td, false);
+ td_to_noop(xhci, ep, cached_td, false);
cached_td->cancel_status = TD_CLEARED;
}
- td_to_noop(td, false);
+ td_to_noop(xhci, ep, td, false);
td->cancel_status = TD_CLEARING_CACHE;
cached_td = td;
break;
}
} else {
- td_to_noop(td, false);
+ td_to_noop(xhci, ep, td, false);
td->cancel_status = TD_CLEARED;
}
}
@@ -1125,7 +1131,7 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep)
continue;
xhci_warn(xhci, "Failed to clear cancelled cached URB %p, mark clear anyway\n",
td->urb);
- td_to_noop(td, false);
+ td_to_noop(xhci, ep, td, false);
td->cancel_status = TD_CLEARED;
}
}
@@ -1388,7 +1394,7 @@ void xhci_hc_died(struct xhci_hcd *xhci)
xhci_cleanup_command_queue(xhci);
/* return any pending urbs, remove may be waiting for them */
- for (i = 0; i <= HCS_MAX_SLOTS(xhci->hcs_params1); i++) {
+ for (i = 0; i <= xhci->max_slots; i++) {
if (!xhci->devs[i])
continue;
for (j = 0; j < 31; j++)
@@ -1985,10 +1991,10 @@ static void xhci_cavium_reset_phy_quirk(struct xhci_hcd *xhci)
static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event)
{
+ struct xhci_virt_device *vdev = NULL;
struct usb_hcd *hcd;
u32 port_id;
u32 portsc, cmd_reg;
- int max_ports;
unsigned int hcd_portnum;
struct xhci_bus_state *bus_state;
bool bogus_port_status = false;
@@ -2000,9 +2006,8 @@ static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event)
"WARN: xHC returned failed port status event\n");
port_id = GET_PORT_ID(le32_to_cpu(event->generic.field[0]));
- max_ports = HCS_MAX_PORTS(xhci->hcs_params1);
- if ((port_id <= 0) || (port_id > max_ports)) {
+ if ((port_id <= 0) || (port_id > xhci->max_ports)) {
xhci_warn(xhci, "Port change event with invalid port ID %d\n",
port_id);
return;
@@ -2016,6 +2021,9 @@ static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event)
goto cleanup;
}
+ if (port->slot_id)
+ vdev = xhci->devs[port->slot_id];
+
/* We might get interrupts after shared_hcd is removed */
if (port->rhub == &xhci->usb3_rhub && xhci->shared_hcd == NULL) {
xhci_dbg(xhci, "ignore port event for removed USB3 hcd\n");
@@ -2026,7 +2034,7 @@ static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event)
hcd = port->rhub->hcd;
bus_state = &port->rhub->bus_state;
hcd_portnum = port->hcd_portnum;
- portsc = readl(port->addr);
+ portsc = xhci_portsc_readl(port);
xhci_dbg(xhci, "Port change event, %d-%d, id %d, portsc: 0x%x\n",
hcd->self.busnum, hcd_portnum + 1, port_id, portsc);
@@ -2038,10 +2046,11 @@ static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event)
usb_hcd_resume_root_hub(hcd);
}
- if (hcd->speed >= HCD_USB3 &&
- (portsc & PORT_PLS_MASK) == XDEV_INACTIVE) {
- if (port->slot_id && xhci->devs[port->slot_id])
- xhci->devs[port->slot_id]->flags |= VDEV_PORT_ERROR;
+ if (vdev && (portsc & PORT_PLS_MASK) == XDEV_INACTIVE) {
+ if (!(portsc & PORT_RESET))
+ vdev->flags |= VDEV_PORT_ERROR;
+ } else if (vdev && portsc & PORT_RC) {
+ vdev->flags &= ~VDEV_PORT_ERROR;
}
if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) {
@@ -2099,7 +2108,7 @@ static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event)
* so the roothub behavior is consistent with external
* USB 3.0 hub behavior.
*/
- if (port->slot_id && xhci->devs[port->slot_id])
+ if (vdev)
xhci_ring_device(xhci, port->slot_id);
if (bus_state->port_remote_wakeup & (1 << hcd_portnum)) {
xhci_test_and_clear_bit(xhci, port, PORT_PLC);
@@ -2179,24 +2188,31 @@ static void xhci_clear_hub_tt_buffer(struct xhci_hcd *xhci, struct xhci_td *td,
* External device side is also halted in functional stall cases. Class driver
* will clear the device halt with a CLEAR_FEATURE(ENDPOINT_HALT) request later.
*/
-static bool xhci_halted_host_endpoint(struct xhci_ep_ctx *ep_ctx, unsigned int comp_code)
+static bool xhci_halted_host_endpoint(struct xhci_hcd *xhci, struct xhci_ep_ctx *ep_ctx,
+ unsigned int comp_code)
{
- /* Stall halts both internal and device side endpoint */
- if (comp_code == COMP_STALL_ERROR)
- return true;
+ int ep_type = CTX_TO_EP_TYPE(le32_to_cpu(ep_ctx->ep_info2));
- /* TRB completion codes that may require internal halt cleanup */
- if (comp_code == COMP_USB_TRANSACTION_ERROR ||
- comp_code == COMP_BABBLE_DETECTED_ERROR ||
- comp_code == COMP_SPLIT_TRANSACTION_ERROR)
+ switch (comp_code) {
+ case COMP_STALL_ERROR:
+ /* on xHCI this always halts, including protocol stall */
+ return true;
+ case COMP_BABBLE_DETECTED_ERROR:
/*
* The 0.95 spec says a babbling control endpoint is not halted.
* The 0.96 spec says it is. Some HW claims to be 0.95
* compliant, but it halts the control endpoint anyway.
* Check endpoint context if endpoint is halted.
*/
- if (GET_EP_CTX_STATE(ep_ctx) == EP_STATE_HALTED)
- return true;
+ if (xhci->hci_version <= 0x95 && ep_type == CTRL_EP)
+ return GET_EP_CTX_STATE(ep_ctx) == EP_STATE_HALTED;
+
+ fallthrough;
+ case COMP_USB_TRANSACTION_ERROR:
+ case COMP_SPLIT_TRANSACTION_ERROR:
+ /* these errors halt all non-isochronous endpoints */
+ return ep_type != ISOC_IN_EP && ep_type != ISOC_OUT_EP;
+ }
return false;
}
@@ -2233,41 +2249,9 @@ static void finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
* the ring dequeue pointer or take this TD off any lists yet.
*/
return;
- case COMP_USB_TRANSACTION_ERROR:
- case COMP_BABBLE_DETECTED_ERROR:
- case COMP_SPLIT_TRANSACTION_ERROR:
- /*
- * If endpoint context state is not halted we might be
- * racing with a reset endpoint command issued by a unsuccessful
- * stop endpoint completion (context error). In that case the
- * td should be on the cancelled list, and EP_HALTED flag set.
- *
- * Or then it's not halted due to the 0.95 spec stating that a
- * babbling control endpoint should not halt. The 0.96 spec
- * again says it should. Some HW claims to be 0.95 compliant,
- * but it halts the control endpoint anyway.
- */
- if (GET_EP_CTX_STATE(ep_ctx) != EP_STATE_HALTED) {
- /*
- * If EP_HALTED is set and TD is on the cancelled list
- * the TD and dequeue pointer will be handled by reset
- * ep command completion
- */
- if ((ep->ep_state & EP_HALTED) &&
- !list_empty(&td->cancelled_td_list)) {
- xhci_dbg(xhci, "Already resolving halted ep for 0x%llx\n",
- (unsigned long long)xhci_trb_virt_to_dma(
- td->start_seg, td->start_trb));
- return;
- }
- /* endpoint not halted, don't reset it */
- break;
- }
- /* Almost same procedure as for STALL_ERROR below */
- xhci_clear_hub_tt_buffer(xhci, td, ep);
- xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET);
- return;
- case COMP_STALL_ERROR:
+ }
+
+ if (xhci_halted_host_endpoint(xhci, ep_ctx, trb_comp_code)) {
/*
* xhci internal endpoint state will go to a "halt" state for
* any stall, including default control pipe protocol stall.
@@ -2278,14 +2262,12 @@ static void finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
* stall later. Hub TT buffer should only be cleared for FS/LS
* devices behind HS hubs for functional stalls.
*/
- if (ep->ep_index != 0)
+ if (!(ep->ep_index == 0 && trb_comp_code == COMP_STALL_ERROR))
xhci_clear_hub_tt_buffer(xhci, td, ep);
xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET);
return; /* xhci_handle_halted_endpoint marked td cancelled */
- default:
- break;
}
xhci_dequeue_td(xhci, td, ep_ring, td->status);
@@ -2362,7 +2344,7 @@ static void process_ctrl_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
case COMP_STOPPED_LENGTH_INVALID:
goto finish_td;
default:
- if (!xhci_halted_host_endpoint(ep_ctx, trb_comp_code))
+ if (!xhci_halted_host_endpoint(xhci, ep_ctx, trb_comp_code))
break;
xhci_dbg(xhci, "TRB error %u, halted endpoint index = %u\n",
trb_comp_code, ep->ep_index);
@@ -2658,7 +2640,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
int ep_index;
struct xhci_td *td = NULL;
dma_addr_t ep_trb_dma;
- struct xhci_segment *ep_seg;
union xhci_trb *ep_trb;
int status = -EINPROGRESS;
struct xhci_ep_ctx *ep_ctx;
@@ -2689,6 +2670,9 @@ static int handle_tx_event(struct xhci_hcd *xhci,
if (!ep_ring)
return handle_transferless_tx_event(xhci, ep, trb_comp_code);
+ /* find the transfer trb this events points to */
+ ep_trb = xhci_dma_to_trb(ep_ring->deq_seg, ep_trb_dma, NULL);
+
/* Look for common error cases */
switch (trb_comp_code) {
/* Skip codes that require special handling depending on
@@ -2862,10 +2846,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
td = list_first_entry(&ep_ring->td_list, struct xhci_td,
td_list);
- /* Is this a TRB in the currently executing TD? */
- ep_seg = trb_in_td(td, ep_trb_dma);
-
- if (!ep_seg) {
+ /* Is this TRB not part of the currently executing TD? */
+ if (!trb_in_td(td, ep_trb_dma)) {
if (ep->skip && usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
/* this event is unlikely to match any TD, don't skip them all */
@@ -2948,7 +2930,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
if (ring_xrun_event)
return 0;
- ep_trb = &ep_seg->trbs[(ep_trb_dma - ep_seg->dma) / sizeof(*ep_trb)];
trace_xhci_handle_transfer(ep_ring, (struct xhci_generic_trb *) ep_trb, ep_trb_dma);
/*
@@ -2973,7 +2954,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
return 0;
check_endpoint_halted:
- if (xhci_halted_host_endpoint(ep_ctx, trb_comp_code))
+ if (xhci_halted_host_endpoint(xhci, ep_ctx, trb_comp_code))
xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET);
return 0;
@@ -3985,6 +3966,16 @@ static unsigned int xhci_get_last_burst_packet_count(struct xhci_hcd *xhci,
return total_packet_count - 1;
}
+/* Returns the Isochronous Scheduling Threshold in Microframes. 1 Frame is 8 Microframes. */
+static int xhci_ist_microframes(struct xhci_hcd *xhci)
+{
+ int ist = HCS_IST_VALUE(xhci->hcs_params2);
+
+ if (xhci->hcs_params2 & HCS_IST_UNIT)
+ ist *= 8;
+ return ist;
+}
+
/*
* Calculates Frame ID field of the isochronous TRB identifies the
* target frame that the Interval associated with this Isochronous
@@ -4004,17 +3995,7 @@ static int xhci_get_isoc_frame_id(struct xhci_hcd *xhci,
else
start_frame = (urb->start_frame + index * urb->interval) >> 3;
- /* Isochronous Scheduling Threshold (IST, bits 0~3 in HCSPARAMS2):
- *
- * If bit [3] of IST is cleared to '0', software can add a TRB no
- * later than IST[2:0] Microframes before that TRB is scheduled to
- * be executed.
- * If bit [3] of IST is set to '1', software can add a TRB no later
- * than IST[2:0] Frames before that TRB is scheduled to be executed.
- */
- ist = HCS_IST(xhci->hcs_params2) & 0x7;
- if (HCS_IST(xhci->hcs_params2) & (1 << 3))
- ist <<= 3;
+ ist = xhci_ist_microframes(xhci);
/* Software shall not schedule an Isoch TD with a Frame ID value that
* is less than the Start Frame ID or greater than the End Frame ID,
@@ -4159,7 +4140,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
/* use SIA as default, if frame id is used overwrite it */
sia_frame_id = TRB_SIA;
if (!(urb->transfer_flags & URB_ISO_ASAP) &&
- HCC_CFC(xhci->hcc_params)) {
+ (xhci->hcc_params & HCC_CFC)) {
frame_id = xhci_get_isoc_frame_id(xhci, urb, i);
if (frame_id >= 0)
sia_frame_id = TRB_FRAME_ID(frame_id);
@@ -4243,7 +4224,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
}
/* store the next frame id */
- if (HCC_CFC(xhci->hcc_params))
+ if (xhci->hcc_params & HCC_CFC)
xep->next_frame_id = urb->start_frame + num_tds * urb->interval;
if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs == 0) {
@@ -4268,7 +4249,7 @@ cleanup:
*/
urb_priv->td[0].end_trb = ep_ring->enqueue;
/* Every TRB except the first & last will have its cycle bit flipped. */
- td_to_noop(&urb_priv->td[0], true);
+ td_to_noop(xhci, xep, &urb_priv->td[0], true);
/* Reset the ring enqueue back to the first TRB and its cycle bit. */
ep_ring->enqueue = urb_priv->td[0].start_trb;
@@ -4322,7 +4303,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
check_interval(urb, ep_ctx);
/* Calculate the start frame and put it in urb->start_frame. */
- if (HCC_CFC(xhci->hcc_params) && !list_empty(&ep_ring->td_list)) {
+ if ((xhci->hcc_params & HCC_CFC) && !list_empty(&ep_ring->td_list)) {
if (GET_EP_CTX_STATE(ep_ctx) == EP_STATE_RUNNING) {
urb->start_frame = xep->next_frame_id;
goto skip_start_over;
@@ -4335,9 +4316,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
* Round up to the next frame and consider the time before trb really
* gets scheduled by hardare.
*/
- ist = HCS_IST(xhci->hcs_params2) & 0x7;
- if (HCS_IST(xhci->hcs_params2) & (1 << 3))
- ist <<= 3;
+ ist = xhci_ist_microframes(xhci);
start_frame += ist + XHCI_CFC_DELAY;
start_frame = roundup(start_frame, 8);
diff --git a/drivers/usb/host/xhci-sideband.c b/drivers/usb/host/xhci-sideband.c
index e771a476fef2..a85f62a73313 100644
--- a/drivers/usb/host/xhci-sideband.c
+++ b/drivers/usb/host/xhci-sideband.c
@@ -73,9 +73,12 @@ err:
return NULL;
}
+/* Caller must hold sb->mutex */
static void
__xhci_sideband_remove_endpoint(struct xhci_sideband *sb, struct xhci_virt_ep *ep)
{
+ lockdep_assert_held(&sb->mutex);
+
/*
* Issue a stop endpoint command when an endpoint is removed.
* The stop ep cmd handler will handle the ring cleanup.
@@ -86,6 +89,25 @@ __xhci_sideband_remove_endpoint(struct xhci_sideband *sb, struct xhci_virt_ep *e
sb->eps[ep->ep_index] = NULL;
}
+/* Caller must hold sb->mutex */
+static void
+__xhci_sideband_remove_interrupter(struct xhci_sideband *sb)
+{
+ struct usb_device *udev;
+
+ lockdep_assert_held(&sb->mutex);
+
+ if (!sb->ir)
+ return;
+
+ xhci_remove_secondary_interrupter(xhci_to_hcd(sb->xhci), sb->ir);
+ sb->ir = NULL;
+ udev = sb->vdev->udev;
+
+ if (udev->state != USB_STATE_NOTATTACHED)
+ usb_offload_put(udev);
+}
+
/* sideband api functions */
/**
@@ -131,14 +153,16 @@ xhci_sideband_add_endpoint(struct xhci_sideband *sb,
struct xhci_virt_ep *ep;
unsigned int ep_index;
- mutex_lock(&sb->mutex);
+ guard(mutex)(&sb->mutex);
+
+ if (!sb->vdev)
+ return -ENODEV;
+
ep_index = xhci_get_endpoint_index(&host_ep->desc);
ep = &sb->vdev->eps[ep_index];
- if (ep->ep_state & EP_HAS_STREAMS) {
- mutex_unlock(&sb->mutex);
+ if (ep->ep_state & EP_HAS_STREAMS)
return -EINVAL;
- }
/*
* Note, we don't know the DMA mask of the audio DSP device, if its
@@ -148,14 +172,11 @@ xhci_sideband_add_endpoint(struct xhci_sideband *sb,
* and let this function add the endpoint and allocate the ring buffer
* with the smallest common DMA mask
*/
- if (sb->eps[ep_index] || ep->sideband) {
- mutex_unlock(&sb->mutex);
+ if (sb->eps[ep_index] || ep->sideband)
return -EBUSY;
- }
ep->sideband = sb;
sb->eps[ep_index] = ep;
- mutex_unlock(&sb->mutex);
return 0;
}
@@ -180,18 +201,16 @@ xhci_sideband_remove_endpoint(struct xhci_sideband *sb,
struct xhci_virt_ep *ep;
unsigned int ep_index;
- mutex_lock(&sb->mutex);
+ guard(mutex)(&sb->mutex);
+
ep_index = xhci_get_endpoint_index(&host_ep->desc);
ep = sb->eps[ep_index];
- if (!ep || !ep->sideband || ep->sideband != sb) {
- mutex_unlock(&sb->mutex);
+ if (!ep || !ep->sideband || ep->sideband != sb)
return -ENODEV;
- }
__xhci_sideband_remove_endpoint(sb, ep);
xhci_initialize_ring_info(ep->ring);
- mutex_unlock(&sb->mutex);
return 0;
}
@@ -316,28 +335,25 @@ xhci_sideband_create_interrupter(struct xhci_sideband *sb, int num_seg,
if (!sb || !sb->xhci)
return -ENODEV;
- mutex_lock(&sb->mutex);
- if (sb->ir) {
- ret = -EBUSY;
- goto out;
- }
+ guard(mutex)(&sb->mutex);
+
+ if (!sb->vdev)
+ return -ENODEV;
+
+ if (sb->ir)
+ return -EBUSY;
sb->ir = xhci_create_secondary_interrupter(xhci_to_hcd(sb->xhci),
num_seg, imod_interval,
intr_num);
- if (!sb->ir) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!sb->ir)
+ return -ENOMEM;
udev = sb->vdev->udev;
ret = usb_offload_get(udev);
sb->ir->ip_autoclear = ip_autoclear;
-out:
- mutex_unlock(&sb->mutex);
-
return ret;
}
EXPORT_SYMBOL_GPL(xhci_sideband_create_interrupter);
@@ -352,21 +368,12 @@ EXPORT_SYMBOL_GPL(xhci_sideband_create_interrupter);
void
xhci_sideband_remove_interrupter(struct xhci_sideband *sb)
{
- struct usb_device *udev;
-
- if (!sb || !sb->ir)
+ if (!sb)
return;
- mutex_lock(&sb->mutex);
- xhci_remove_secondary_interrupter(xhci_to_hcd(sb->xhci), sb->ir);
-
- sb->ir = NULL;
- udev = sb->vdev->udev;
+ guard(mutex)(&sb->mutex);
- if (udev->state != USB_STATE_NOTATTACHED)
- usb_offload_put(udev);
-
- mutex_unlock(&sb->mutex);
+ __xhci_sideband_remove_interrupter(sb);
}
EXPORT_SYMBOL_GPL(xhci_sideband_remove_interrupter);
@@ -465,6 +472,7 @@ EXPORT_SYMBOL_GPL(xhci_sideband_register);
void
xhci_sideband_unregister(struct xhci_sideband *sb)
{
+ struct xhci_virt_device *vdev;
struct xhci_hcd *xhci;
int i;
@@ -473,17 +481,23 @@ xhci_sideband_unregister(struct xhci_sideband *sb)
xhci = sb->xhci;
- mutex_lock(&sb->mutex);
- for (i = 0; i < EP_CTX_PER_DEV; i++)
- if (sb->eps[i])
- __xhci_sideband_remove_endpoint(sb, sb->eps[i]);
- mutex_unlock(&sb->mutex);
+ scoped_guard(mutex, &sb->mutex) {
+ vdev = sb->vdev;
+ if (!vdev)
+ return;
+
+ for (i = 0; i < EP_CTX_PER_DEV; i++)
+ if (sb->eps[i])
+ __xhci_sideband_remove_endpoint(sb, sb->eps[i]);
- xhci_sideband_remove_interrupter(sb);
+ __xhci_sideband_remove_interrupter(sb);
+
+ sb->vdev = NULL;
+ }
spin_lock_irq(&xhci->lock);
sb->xhci = NULL;
- sb->vdev->sideband = NULL;
+ vdev->sideband = NULL;
spin_unlock_irq(&xhci->lock);
kfree(sb);
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
index 5255b1002893..31ccced5125e 100644
--- a/drivers/usb/host/xhci-tegra.c
+++ b/drivers/usb/host/xhci-tegra.c
@@ -1399,7 +1399,6 @@ static void tegra_xhci_id_work(struct work_struct *work)
}
tegra_xhci_set_port_power(tegra, true, true);
- pm_runtime_mark_last_busy(tegra->dev);
} else {
if (tegra->otg_usb3_port >= 0)
@@ -2036,7 +2035,7 @@ static bool xhci_hub_ports_suspended(struct xhci_hub *hub)
u32 value;
for (i = 0; i < hub->num_ports; i++) {
- value = readl(hub->ports[i]->addr);
+ value = xhci_portsc_readl(hub->ports[i]);
if ((value & PORT_PE) == 0)
continue;
@@ -2162,7 +2161,7 @@ static void tegra_xhci_enable_phy_sleepwalk_wake(struct tegra_xusb *tegra)
if (!is_host_mode_phy(tegra, i, j))
continue;
- portsc = readl(rhub->ports[index]->addr);
+ portsc = xhci_portsc_readl(rhub->ports[index]);
speed = tegra_xhci_portsc_to_speed(tegra, portsc);
tegra_xusb_padctl_enable_phy_sleepwalk(padctl, phy, speed);
tegra_xusb_padctl_enable_phy_wake(padctl, phy);
@@ -2257,7 +2256,7 @@ static int tegra_xusb_enter_elpg(struct tegra_xusb *tegra, bool is_auto_resume)
for (i = 0; i < xhci->usb2_rhub.num_ports; i++) {
if (!xhci->usb2_rhub.ports[i])
continue;
- portsc = readl(xhci->usb2_rhub.ports[i]->addr);
+ portsc = xhci_portsc_readl(xhci->usb2_rhub.ports[i]);
tegra->lp0_utmi_pad_mask &= ~BIT(i);
if (((portsc & PORT_PLS_MASK) == XDEV_U3) || ((portsc & DEV_SPEED_MASK) == XDEV_FS))
tegra->lp0_utmi_pad_mask |= BIT(i);
@@ -2790,7 +2789,7 @@ static int tegra_xhci_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value,
while (i--) {
if (!test_bit(i, &bus_state->resuming_ports))
continue;
- portsc = readl(ports[i]->addr);
+ portsc = xhci_portsc_readl(ports[i]);
if ((portsc & PORT_PLS_MASK) == XDEV_RESUME)
tegra_phy_xusb_utmi_pad_power_on(
tegra_xusb_get_phy(tegra, "usb2", (int) i));
@@ -2808,7 +2807,7 @@ static int tegra_xhci_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value,
if (!index || index > rhub->num_ports)
return -EPIPE;
ports = rhub->ports;
- portsc = readl(ports[port]->addr);
+ portsc = xhci_portsc_readl(ports[port]);
if (portsc & PORT_CONNECT)
tegra_phy_xusb_utmi_pad_power_on(phy);
}
@@ -2827,7 +2826,7 @@ static int tegra_xhci_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value,
if ((type_req == ClearPortFeature) && (value == USB_PORT_FEAT_C_CONNECTION)) {
ports = rhub->ports;
- portsc = readl(ports[port]->addr);
+ portsc = xhci_portsc_readl(ports[port]);
if (!(portsc & PORT_CONNECT)) {
/* We don't suspend the PAD while HNP role swap happens on the OTG
* port
diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h
index 9abc904f1749..724cba2dbb78 100644
--- a/drivers/usb/host/xhci-trace.h
+++ b/drivers/usb/host/xhci-trace.h
@@ -71,29 +71,20 @@ DEFINE_EVENT(xhci_log_msg, xhci_dbg_ring_expansion,
);
DECLARE_EVENT_CLASS(xhci_log_ctx,
- TP_PROTO(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx,
- unsigned int ep_num),
- TP_ARGS(xhci, ctx, ep_num),
+ TP_PROTO(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx),
+ TP_ARGS(xhci, ctx),
TP_STRUCT__entry(
__field(int, ctx_64)
__field(unsigned, ctx_type)
__field(dma_addr_t, ctx_dma)
__field(u8 *, ctx_va)
- __field(unsigned, ctx_ep_num)
- __dynamic_array(u32, ctx_data,
- ((HCC_64BYTE_CONTEXT(xhci->hcc_params) + 1) * 8) *
- ((ctx->type == XHCI_CTX_TYPE_INPUT) + ep_num + 1))
),
TP_fast_assign(
- __entry->ctx_64 = HCC_64BYTE_CONTEXT(xhci->hcc_params);
+ __entry->ctx_64 = xhci->hcc_params & HCC_64BYTE_CONTEXT;
__entry->ctx_type = ctx->type;
__entry->ctx_dma = ctx->dma;
__entry->ctx_va = ctx->bytes;
- __entry->ctx_ep_num = ep_num;
- memcpy(__get_dynamic_array(ctx_data), ctx->bytes,
- ((HCC_64BYTE_CONTEXT(xhci->hcc_params) + 1) * 32) *
- ((ctx->type == XHCI_CTX_TYPE_INPUT) + ep_num + 1));
),
TP_printk("ctx_64=%d, ctx_type=%u, ctx_dma=@%llx, ctx_va=@%p",
__entry->ctx_64, __entry->ctx_type,
@@ -102,9 +93,8 @@ DECLARE_EVENT_CLASS(xhci_log_ctx,
);
DEFINE_EVENT(xhci_log_ctx, xhci_address_ctx,
- TP_PROTO(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx,
- unsigned int ep_num),
- TP_ARGS(xhci, ctx, ep_num)
+ TP_PROTO(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx),
+ TP_ARGS(xhci, ctx)
);
DECLARE_EVENT_CLASS(xhci_log_trb,
@@ -575,6 +565,11 @@ DEFINE_EVENT(xhci_log_portsc, xhci_hub_status_data,
TP_ARGS(port, portsc)
);
+DEFINE_EVENT(xhci_log_portsc, xhci_portsc_writel,
+ TP_PROTO(struct xhci_port *port, u32 portsc),
+ TP_ARGS(port, portsc)
+);
+
DECLARE_EVENT_CLASS(xhci_log_doorbell,
TP_PROTO(u32 slot, u32 doorbell),
TP_ARGS(slot, doorbell),
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 0cb45b95e4f5..02c9bfe21ae2 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -41,6 +41,19 @@ static unsigned long long quirks;
module_param(quirks, ullong, S_IRUGO);
MODULE_PARM_DESC(quirks, "Bit flags for quirks to be enabled as default");
+void xhci_portsc_writel(struct xhci_port *port, u32 val)
+{
+ trace_xhci_portsc_writel(port, val);
+ writel(val, &port->port_reg->portsc);
+}
+EXPORT_SYMBOL_GPL(xhci_portsc_writel);
+
+u32 xhci_portsc_readl(struct xhci_port *port)
+{
+ return readl(&port->port_reg->portsc);
+}
+EXPORT_SYMBOL_GPL(xhci_portsc_readl);
+
static bool td_on_ring(struct xhci_td *td, struct xhci_ring *ring)
{
struct xhci_segment *seg;
@@ -237,7 +250,6 @@ static void xhci_zero_64b_regs(struct xhci_hcd *xhci)
struct iommu_domain *domain;
int err, i;
u64 val;
- u32 intrs;
/*
* Some Renesas controllers get into a weird state if they are
@@ -278,10 +290,7 @@ static void xhci_zero_64b_regs(struct xhci_hcd *xhci)
if (upper_32_bits(val))
xhci_write_64(xhci, 0, &xhci->op_regs->cmd_ring);
- intrs = min_t(u32, HCS_MAX_INTRS(xhci->hcs_params1),
- ARRAY_SIZE(xhci->run_regs->ir_set));
-
- for (i = 0; i < intrs; i++) {
+ for (i = 0; i < xhci->max_interrupters; i++) {
struct xhci_intr_reg __iomem *ir;
ir = &xhci->run_regs->ir_set[i];
@@ -373,7 +382,7 @@ static void compliance_mode_recovery(struct timer_list *t)
return;
for (i = 0; i < rhub->num_ports; i++) {
- temp = readl(rhub->ports[i]->addr);
+ temp = xhci_portsc_readl(rhub->ports[i]);
if ((temp & PORT_PLS_MASK) == USB_SS_PORT_LS_COMP_MOD) {
/*
* Compliance Mode Detected. Letting USB Core
@@ -471,15 +480,13 @@ static void xhci_hcd_page_size(struct xhci_hcd *xhci)
static void xhci_enable_max_dev_slots(struct xhci_hcd *xhci)
{
u32 config_reg;
- u32 max_slots;
- max_slots = HCS_MAX_SLOTS(xhci->hcs_params1);
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xHC can handle at most %d device slots",
- max_slots);
+ xhci->max_slots);
config_reg = readl(&xhci->op_regs->config_reg);
config_reg &= ~HCS_SLOTS_MASK;
- config_reg |= max_slots;
+ config_reg |= xhci->max_slots;
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Setting Max device slots reg = 0x%x",
config_reg);
@@ -896,7 +903,7 @@ static void xhci_disable_hub_port_wake(struct xhci_hcd *xhci,
spin_lock_irqsave(&xhci->lock, flags);
for (i = 0; i < rhub->num_ports; i++) {
- portsc = readl(rhub->ports[i]->addr);
+ portsc = xhci_portsc_readl(rhub->ports[i]);
t1 = xhci_port_state_to_neutral(portsc);
t2 = t1;
@@ -909,7 +916,7 @@ static void xhci_disable_hub_port_wake(struct xhci_hcd *xhci,
t2 |= PORT_CSC;
if (t1 != t2) {
- writel(t2, rhub->ports[i]->addr);
+ xhci_portsc_writel(rhub->ports[i], t2);
xhci_dbg(xhci, "config port %d-%d wake bits, portsc: 0x%x, write: 0x%x\n",
rhub->hcd->self.busnum, i + 1, portsc, t2);
}
@@ -936,7 +943,7 @@ static bool xhci_pending_portevent(struct xhci_hcd *xhci)
port_index = xhci->usb2_rhub.num_ports;
ports = xhci->usb2_rhub.ports;
while (port_index--) {
- portsc = readl(ports[port_index]->addr);
+ portsc = xhci_portsc_readl(ports[port_index]);
if (portsc & PORT_CHANGE_MASK ||
(portsc & PORT_PLS_MASK) == XDEV_RESUME)
return true;
@@ -944,7 +951,7 @@ static bool xhci_pending_portevent(struct xhci_hcd *xhci)
port_index = xhci->usb3_rhub.num_ports;
ports = xhci->usb3_rhub.ports;
while (port_index--) {
- portsc = readl(ports[port_index]->addr);
+ portsc = xhci_portsc_readl(ports[port_index]);
if (portsc & (PORT_CHANGE_MASK | PORT_CAS) ||
(portsc & PORT_PLS_MASK) == XDEV_RESUME)
return true;
@@ -4007,6 +4014,7 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
xhci_get_slot_state(xhci, virt_dev->out_ctx));
xhci_dbg(xhci, "Not freeing device rings.\n");
/* Don't treat this as an error. May change my mind later. */
+ virt_dev->flags = 0;
ret = 0;
goto command_cleanup;
case COMP_SUCCESS:
@@ -4222,8 +4230,7 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
xhci_err(xhci, "Error while assigning device slot ID: %s\n",
xhci_trb_comp_code_string(command->status));
xhci_err(xhci, "Max number of devices this xHCI host supports is %u.\n",
- HCS_MAX_SLOTS(
- readl(&xhci->cap_regs->hcs_params1)));
+ xhci->max_slots);
xhci_free_command(xhci, command);
return 0;
}
@@ -4366,8 +4373,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
ctrl_ctx->drop_flags = 0;
- trace_xhci_address_ctx(xhci, virt_dev->in_ctx,
- le32_to_cpu(slot_ctx->dev_info) >> 27);
+ trace_xhci_address_ctx(xhci, virt_dev->in_ctx);
trace_xhci_address_ctrl_ctx(ctrl_ctx);
spin_lock_irqsave(&xhci->lock, flags);
@@ -4427,7 +4433,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
xhci_err(xhci,
"ERROR: unexpected setup %s command completion code 0x%x.\n",
act, command->status);
- trace_xhci_address_ctx(xhci, virt_dev->out_ctx, 1);
+ trace_xhci_address_ctx(xhci, virt_dev->out_ctx);
ret = -EINVAL;
break;
}
@@ -4445,14 +4451,12 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
xhci_dbg_trace(xhci, trace_xhci_dbg_address,
"Output Context DMA address = %#08llx",
(unsigned long long)virt_dev->out_ctx->dma);
- trace_xhci_address_ctx(xhci, virt_dev->in_ctx,
- le32_to_cpu(slot_ctx->dev_info) >> 27);
+ trace_xhci_address_ctx(xhci, virt_dev->in_ctx);
/*
* USB core uses address 1 for the roothubs, so we add one to the
* address given back to us by the HC.
*/
- trace_xhci_address_ctx(xhci, virt_dev->out_ctx,
- le32_to_cpu(slot_ctx->dev_info) >> 27);
+ trace_xhci_address_ctx(xhci, virt_dev->out_ctx);
/* Zero the input context control for later use */
ctrl_ctx->add_flags = 0;
ctrl_ctx->drop_flags = 0;
@@ -4636,7 +4640,7 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct xhci_port **ports;
- __le32 __iomem *pm_addr, *hlpm_addr;
+ struct xhci_port_regs __iomem *port_reg;
u32 pm_val, hlpm_val, field;
unsigned int port_num;
unsigned long flags;
@@ -4661,9 +4665,8 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
ports = xhci->usb2_rhub.ports;
port_num = udev->portnum - 1;
- pm_addr = ports[port_num]->addr + PORTPMSC;
- pm_val = readl(pm_addr);
- hlpm_addr = ports[port_num]->addr + PORTHLPMC;
+ port_reg = ports[port_num]->port_reg;
+ pm_val = readl(&port_reg->portpmsc);
xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n",
str_enable_disable(enable), port_num + 1);
@@ -4692,30 +4695,30 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
spin_lock_irqsave(&xhci->lock, flags);
hlpm_val = xhci_calculate_usb2_hw_lpm_params(udev);
- writel(hlpm_val, hlpm_addr);
+ writel(hlpm_val, &port_reg->porthlmpc);
/* flush write */
- readl(hlpm_addr);
+ readl(&port_reg->porthlmpc);
} else {
hird = xhci_calculate_hird_besl(xhci, udev);
}
pm_val &= ~PORT_HIRD_MASK;
pm_val |= PORT_HIRD(hird) | PORT_RWE | PORT_L1DS(udev->slot_id);
- writel(pm_val, pm_addr);
- pm_val = readl(pm_addr);
+ writel(pm_val, &port_reg->portpmsc);
+ pm_val = readl(&port_reg->portpmsc);
pm_val |= PORT_HLE;
- writel(pm_val, pm_addr);
+ writel(pm_val, &port_reg->portpmsc);
/* flush write */
- readl(pm_addr);
+ readl(&port_reg->portpmsc);
} else {
pm_val &= ~(PORT_HLE | PORT_RWE | PORT_HIRD_MASK | PORT_L1DS_MASK);
- writel(pm_val, pm_addr);
+ writel(pm_val, &port_reg->portpmsc);
/* flush write */
- readl(pm_addr);
+ readl(&port_reg->portpmsc);
if (udev->usb2_hw_lpm_besl_capable) {
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_change_max_exit_latency(xhci, udev, 0);
- readl_poll_timeout(ports[port_num]->addr, pm_val,
+ readl_poll_timeout(&ports[port_num]->port_reg->portsc, pm_val,
(pm_val & PORT_PLS_MASK) == XDEV_U0,
100, 10000);
return 0;
@@ -5408,6 +5411,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
*/
struct device *dev = hcd->self.sysdev;
int retval;
+ u32 hcs_params1;
/* Accept arbitrarily long scatter-gather lists */
hcd->self.sg_tablesize = ~0;
@@ -5433,7 +5437,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
xhci->run_regs = hcd->regs +
(readl(&xhci->cap_regs->run_regs_off) & RTSOFF_MASK);
/* Cache read-only capability registers */
- xhci->hcs_params1 = readl(&xhci->cap_regs->hcs_params1);
+ hcs_params1 = readl(&xhci->cap_regs->hcs_params1);
xhci->hcs_params2 = readl(&xhci->cap_regs->hcs_params2);
xhci->hcs_params3 = readl(&xhci->cap_regs->hcs_params3);
xhci->hci_version = HC_VERSION(readl(&xhci->cap_regs->hc_capbase));
@@ -5441,10 +5445,13 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
if (xhci->hci_version > 0x100)
xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2);
+ xhci->max_slots = HCS_MAX_SLOTS(hcs_params1);
+ xhci->max_ports = min(HCS_MAX_PORTS(hcs_params1), MAX_HC_PORTS);
/* xhci-plat or xhci-pci might have set max_interrupters already */
- if ((!xhci->max_interrupters) ||
- xhci->max_interrupters > HCS_MAX_INTRS(xhci->hcs_params1))
- xhci->max_interrupters = HCS_MAX_INTRS(xhci->hcs_params1);
+ if (!xhci->max_interrupters)
+ xhci->max_interrupters = min(HCS_MAX_INTRS(hcs_params1), MAX_HC_INTRS);
+ else if (xhci->max_interrupters > HCS_MAX_INTRS(hcs_params1))
+ xhci->max_interrupters = HCS_MAX_INTRS(hcs_params1);
xhci->quirks |= quirks;
@@ -5489,7 +5496,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
/* Set dma_mask and coherent_dma_mask to 64-bits,
* if xHC supports 64-bit addressing */
- if (HCC_64BIT_ADDR(xhci->hcc_params) &&
+ if ((xhci->hcc_params & HCC_64BIT_ADDR) &&
!dma_set_mask(dev, DMA_BIT_MASK(64))) {
xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
@@ -5663,8 +5670,8 @@ static int __init xhci_hcd_init(void)
BUILD_BUG_ON(sizeof(struct xhci_erst_entry) != 4*32/8);
BUILD_BUG_ON(sizeof(struct xhci_cap_regs) != 8*32/8);
BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8);
- /* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */
- BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
+ /* xhci_run_regs has eight fields and embeds 1024 xhci_intr_regs */
+ BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*1024)*32/8);
if (usb_disabled())
return -ENODEV;
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 58a51f09cceb..2b0796f6d00e 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -34,8 +34,16 @@
/* Max number of USB devices for any host controller - limit in section 6.1 */
#define MAX_HC_SLOTS 256
-/* Section 5.3.3 - MaxPorts */
+/*
+ * Max Number of Ports. xHCI specification section 5.3.3
+ * Valid values are in the range of 1 to 255.
+ */
#define MAX_HC_PORTS 127
+/*
+ * Max number of Interrupter Register Sets. xHCI specification section 5.3.3
+ * Valid values are in the range of 1 to 1024.
+ */
+#define MAX_HC_INTRS 128
/*
* xHCI register interface.
@@ -66,13 +74,19 @@ struct xhci_cap_regs {
/* Reserved up to (CAPLENGTH - 0x1C) */
};
-/* Number of registers per port */
-#define NUM_PORT_REGS 4
-
-#define PORTSC 0
-#define PORTPMSC 1
-#define PORTLI 2
-#define PORTHLPMC 3
+/*
+ * struct xhci_port_regs - Host Controller USB Port Register Set. xHCI spec 5.4.8
+ * @portsc: Port Status and Control
+ * @portpmsc: Port Power Management Status and Control
+ * @portli: Port Link Info
+ * @porthlmpc: Port Hardware LPM Control
+ */
+struct xhci_port_regs {
+ __le32 portsc;
+ __le32 portpmsc;
+ __le32 portli;
+ __le32 porthlmpc;
+};
/**
* struct xhci_op_regs - xHCI Host Controller Operational Registers.
@@ -85,16 +99,7 @@ struct xhci_cap_regs {
* @cmd_ring: CRP - 64-bit Command Ring Pointer
* @dcbaa_ptr: DCBAAP - 64-bit Device Context Base Address Array Pointer
* @config_reg: CONFIG - Configure Register
- * @port_status_base: PORTSCn - base address for Port Status and Control
- * Each port has a Port Status and Control register,
- * followed by a Port Power Management Status and Control
- * register, a Port Link Info register, and a reserved
- * register.
- * @port_power_base: PORTPMSCn - base address for
- * Port Power Management Status and Control
- * @port_link_base: PORTLIn - base address for Port Link Info (current
- * Link PM state and control) for USB 2.1 and USB 3.0
- * devices.
+ * @port_regs: Port Register Sets, from 1 to MaxPorts (defined by HCSPARAMS1).
*/
struct xhci_op_regs {
__le32 command;
@@ -110,13 +115,7 @@ struct xhci_op_regs {
__le32 config_reg;
/* rsvd: offset 0x3C-3FF */
__le32 reserved4[241];
- /* port 1 registers, which serve as a base address for other ports */
- __le32 port_status_base;
- __le32 port_power_base;
- __le32 port_link_base;
- __le32 reserved5;
- /* registers for ports 2-255 */
- __le32 reserved6[NUM_PORT_REGS*254];
+ struct xhci_port_regs port_regs[];
};
/* USBCMD - USB command - command bitmasks */
@@ -284,7 +283,7 @@ struct xhci_intr_reg {
struct xhci_run_regs {
__le32 microframe_index;
__le32 rsvd[7];
- struct xhci_intr_reg ir_set[128];
+ struct xhci_intr_reg ir_set[1024];
};
/**
@@ -800,7 +799,6 @@ struct xhci_device_context_array {
/* private xHCD pointers */
dma_addr_t dma;
};
-/* TODO: write function to set the 64-bit device DMA address */
/*
* TODO: change this to be dynamically sized at HC mem init time since the HC
* might not be able to handle the maximum number of devices possible.
@@ -1474,7 +1472,7 @@ struct xhci_port_cap {
};
struct xhci_port {
- __le32 __iomem *addr;
+ struct xhci_port_regs __iomem *port_reg;
int hw_portnum;
int hcd_portnum;
struct xhci_hub *rhub;
@@ -1510,7 +1508,6 @@ struct xhci_hcd {
struct xhci_doorbell_array __iomem *dba;
/* Cached register copies of read-only HC data */
- __u32 hcs_params1;
__u32 hcs_params2;
__u32 hcs_params3;
__u32 hcc_params;
@@ -1521,6 +1518,8 @@ struct xhci_hcd {
/* packed release number */
u16 hci_version;
u16 max_interrupters;
+ u8 max_slots;
+ u8 max_ports;
/* imod_interval in ns (I * 250ns) */
u32 imod_interval;
u32 page_size;
@@ -1961,6 +1960,8 @@ void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
void xhci_add_interrupter(struct xhci_hcd *xhci, unsigned int intr_num);
int xhci_usb_endpoint_maxp(struct usb_device *udev,
struct usb_host_endpoint *host_ep);
+void xhci_portsc_writel(struct xhci_port *port, u32 val);
+u32 xhci_portsc_readl(struct xhci_port *port);
/* xHCI roothub code */
void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,
@@ -2399,25 +2400,48 @@ static inline const char *xhci_decode_portsc(char *str, u32 portsc)
if (portsc == ~(u32)0)
return str;
- ret += sprintf(str + ret, "%s %s %s Link:%s PortSpeed:%d ",
- portsc & PORT_POWER ? "Powered" : "Powered-off",
- portsc & PORT_CONNECT ? "Connected" : "Not-connected",
- portsc & PORT_PE ? "Enabled" : "Disabled",
- xhci_portsc_link_state_string(portsc),
- DEV_PORT_SPEED(portsc));
+ ret += sprintf(str + ret, "Speed=%d ", DEV_PORT_SPEED(portsc));
+ ret += sprintf(str + ret, "Link=%s ", xhci_portsc_link_state_string(portsc));
+ /* RO/ROS: Read-only */
+ if (portsc & PORT_CONNECT)
+ ret += sprintf(str + ret, "CCS ");
if (portsc & PORT_OC)
- ret += sprintf(str + ret, "OverCurrent ");
+ ret += sprintf(str + ret, "OCA "); /* No set for USB2 ports */
+ if (portsc & PORT_CAS)
+ ret += sprintf(str + ret, "CAS ");
+ if (portsc & PORT_DEV_REMOVE)
+ ret += sprintf(str + ret, "DR ");
+
+ /* RWS; writing 1 sets the bit, writing 0 clears the bit. */
+ if (portsc & PORT_POWER)
+ ret += sprintf(str + ret, "PP ");
+ if (portsc & PORT_WKCONN_E)
+ ret += sprintf(str + ret, "WCE ");
+ if (portsc & PORT_WKDISC_E)
+ ret += sprintf(str + ret, "WDE ");
+ if (portsc & PORT_WKOC_E)
+ ret += sprintf(str + ret, "WOE ");
+
+ /* RW; writing 1 sets the bit, writing 0 clears the bit */
+ if (portsc & PORT_LINK_STROBE)
+ ret += sprintf(str + ret, "LWS "); /* LWS 0 write is ignored */
+
+ /* RW1S; writing 1 sets the bit, writing 0 has no effect */
if (portsc & PORT_RESET)
- ret += sprintf(str + ret, "In-Reset ");
+ ret += sprintf(str + ret, "PR ");
+ if (portsc & PORT_WR)
+ ret += sprintf(str + ret, "WPR "); /* RsvdZ for USB2 ports */
- ret += sprintf(str + ret, "Change: ");
+ /* RW1CS; writing 1 clears the bit, writing 0 has no effect. */
+ if (portsc & PORT_PE)
+ ret += sprintf(str + ret, "PED ");
if (portsc & PORT_CSC)
ret += sprintf(str + ret, "CSC ");
if (portsc & PORT_PEC)
- ret += sprintf(str + ret, "PEC ");
+ ret += sprintf(str + ret, "PEC "); /* No set for USB3 ports */
if (portsc & PORT_WRC)
- ret += sprintf(str + ret, "WRC ");
+ ret += sprintf(str + ret, "WRC "); /* RsvdZ for USB2 ports */
if (portsc & PORT_OCC)
ret += sprintf(str + ret, "OCC ");
if (portsc & PORT_RC)
@@ -2425,17 +2449,7 @@ static inline const char *xhci_decode_portsc(char *str, u32 portsc)
if (portsc & PORT_PLC)
ret += sprintf(str + ret, "PLC ");
if (portsc & PORT_CEC)
- ret += sprintf(str + ret, "CEC ");
- if (portsc & PORT_CAS)
- ret += sprintf(str + ret, "CAS ");
-
- ret += sprintf(str + ret, "Wake: ");
- if (portsc & PORT_WKCONN_E)
- ret += sprintf(str + ret, "WCE ");
- if (portsc & PORT_WKDISC_E)
- ret += sprintf(str + ret, "WDE ");
- if (portsc & PORT_WKOC_E)
- ret += sprintf(str + ret, "WOE ");
+ ret += sprintf(str + ret, "CEC "); /* RsvdZ for USB2 ports */
return str;
}