diff options
Diffstat (limited to 'drivers/usb/host')
| -rw-r--r-- | drivers/usb/host/ehci-platform.c | 40 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-da8xx.c | 17 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-platform.c | 24 | ||||
| -rw-r--r-- | drivers/usb/host/sl811-hcd.c | 1 | ||||
| -rw-r--r-- | drivers/usb/host/uhci-hcd.h | 1 | ||||
| -rw-r--r-- | drivers/usb/host/uhci-platform.c | 28 | ||||
| -rw-r--r-- | drivers/usb/host/xen-hcd.c | 4 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-caps.h | 167 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-dbgcap.c | 23 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-dbgcap.h | 1 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-dbgtty.c | 23 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-debugfs.c | 57 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-hub.c | 125 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-mem.c | 41 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-mtk.c | 1 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-mtk.h | 10 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-pci.c | 9 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-port.h | 5 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-ring.c | 257 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-sideband.c | 102 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-tegra.c | 13 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-trace.h | 25 | ||||
| -rw-r--r-- | drivers/usb/host/xhci.c | 93 | ||||
| -rw-r--r-- | drivers/usb/host/xhci.h | 116 |
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; } |
