diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-10-15 09:51:18 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-10-15 09:51:18 -0700 |
commit | c6dbef7307629cce855aa6b482b60cbf7777ed88 (patch) | |
tree | d8d13630bd57090173ad9f0c5f8e3bfb392964c9 /drivers/usb/host | |
parent | ade7afe3e606f9f6ff0e6deefce140157f75540b (diff) | |
parent | 93578a25d4e21603518daf27a5f9caa4bf79de68 (diff) |
Merge tag 'usb-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB/PHY/Thunderbolt driver updates from Greg KH:
"Here is the big set of USB, PHY, and Thunderbolt driver updates for
5.10-rc1.
Lots of tiny different things for these subsystems are in here,
including:
- phy driver updates
- thunderbolt / USB 4 updates and additions
- USB gadget driver updates
- xhci fixes and updates
- typec driver additions and updates
- api conversions to various drivers for core kernel api changes
- new USB control message functions to make it harder to get wrong,
as found by syzbot (took 2 tries to get it right)
- lots of tiny USB driver fixes and updates all over the place
All of these have been in linux-next for a while, with the exception
of the last "obviously correct" patch that updated a FALLTHROUGH
comment that got merged last weekend"
* tag 'usb-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (374 commits)
usb: musb: gadget: Use fallthrough pseudo-keyword
usb: typec: Add QCOM PMIC typec detection driver
USB: serial: option: add Cellient MPL200 card
usb: typec: tcpci_maxim: Add support for Sink FRS
usb: typec: tcpci: Implement callbacks for FRS
usb: typec: tcpm: Add support for Sink Fast Role SWAP(FRS)
usb: typec: tcpci_maxim: Chip level TCPC driver
usb: typec: tcpci: Add set_vbus tcpci callback
usb: typec: tcpci: Add a getter method to retrieve tcpm_port reference
usbip: vhci_hcd: fix calling usb_hcd_giveback_urb() with irqs enabled
usb: cdc-acm: add quirk to blacklist ETAS ES58X devices
USB: serial: ftdi_sio: use cur_altsetting for consistency
USB: serial: option: Add Telit FT980-KS composition
USB: core: remove polling for /sys/kernel/debug/usb/devices
usb: typec: add support for STUSB160x Type-C controller family
usb: typec: add typec_find_pwr_opmode
usb: typec: hd3ss3220: Use OF graph API to get the connector fwnode
dt-bindings: usb: renesas,usb3-peri: Document HS and SS data bus
dt-bindings: usb: convert ti,hd3ss3220 bindings to json-schema
usb: dwc2: Fix INTR OUT transfers in DDMA mode.
...
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/bcma-hcd.c | 13 | ||||
-rw-r--r-- | drivers/usb/host/ehci-npcm7xx.c | 8 | ||||
-rw-r--r-- | drivers/usb/host/ehci-platform.c | 16 | ||||
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 20 | ||||
-rw-r--r-- | drivers/usb/host/ehci-spear.c | 8 | ||||
-rw-r--r-- | drivers/usb/host/fotg210-hcd.c | 20 | ||||
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 18 | ||||
-rw-r--r-- | drivers/usb/host/oxu210hp-hcd.c | 21 | ||||
-rw-r--r-- | drivers/usb/host/pci-quirks.c | 35 | ||||
-rw-r--r-- | drivers/usb/host/xhci-dbgtty.c | 6 | ||||
-rw-r--r-- | drivers/usb/host/xhci-debugfs.c | 109 | ||||
-rw-r--r-- | drivers/usb/host/xhci-debugfs.h | 10 | ||||
-rw-r--r-- | drivers/usb/host/xhci-mtk.c | 6 | ||||
-rw-r--r-- | drivers/usb/host/xhci-pci.c | 10 | ||||
-rw-r--r-- | drivers/usb/host/xhci-plat.c | 44 | ||||
-rw-r--r-- | drivers/usb/host/xhci-plat.h | 1 | ||||
-rw-r--r-- | drivers/usb/host/xhci-rcar.c | 43 | ||||
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 23 | ||||
-rw-r--r-- | drivers/usb/host/xhci-tegra.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/xhci.c | 11 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 3 |
21 files changed, 273 insertions, 153 deletions
diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index b1b777f33521..337b425dd4b0 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -498,15 +498,4 @@ static struct bcma_driver bcma_hcd_driver = { .suspend = bcma_hcd_suspend, .resume = bcma_hcd_resume, }; - -static int __init bcma_hcd_init(void) -{ - return bcma_driver_register(&bcma_hcd_driver); -} -module_init(bcma_hcd_init); - -static void __exit bcma_hcd_exit(void) -{ - bcma_driver_unregister(&bcma_hcd_driver); -} -module_exit(bcma_hcd_exit); +module_bcma_driver(bcma_hcd_driver); diff --git a/drivers/usb/host/ehci-npcm7xx.c b/drivers/usb/host/ehci-npcm7xx.c index adaf8fb4b459..6b5a7a873e01 100644 --- a/drivers/usb/host/ehci-npcm7xx.c +++ b/drivers/usb/host/ehci-npcm7xx.c @@ -37,8 +37,7 @@ static const char hcd_name[] = "npcm7xx-ehci"; static struct hc_driver __read_mostly ehci_npcm7xx_hc_driver; -#ifdef CONFIG_PM_SLEEP -static int ehci_npcm7xx_drv_suspend(struct device *dev) +static int __maybe_unused ehci_npcm7xx_drv_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); bool do_wakeup = device_may_wakeup(dev); @@ -46,14 +45,13 @@ static int ehci_npcm7xx_drv_suspend(struct device *dev) return ehci_suspend(hcd, do_wakeup); } -static int ehci_npcm7xx_drv_resume(struct device *dev) +static int __maybe_unused ehci_npcm7xx_drv_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); ehci_resume(hcd, false); return 0; } -#endif /* CONFIG_PM_SLEEP */ static SIMPLE_DEV_PM_OPS(ehci_npcm7xx_pm_ops, ehci_npcm7xx_drv_suspend, ehci_npcm7xx_drv_resume); @@ -183,7 +181,7 @@ static struct platform_driver npcm7xx_ehci_hcd_driver = { .driver = { .name = "npcm7xx-ehci", .bus = &platform_bus_type, - .pm = &ehci_npcm7xx_pm_ops, + .pm = pm_ptr(&ehci_npcm7xx_pm_ops), .of_match_table = npcm7xx_ehci_id_table, } }; diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 006c4f6188a5..a48dd3fac153 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -42,6 +42,9 @@ #define EHCI_MAX_CLKS 4 #define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv) +#define BCM_USB_FIFO_THRESHOLD 0x00800040 +#define bcm_iproc_insnreg01 hostpc[0] + struct ehci_platform_priv { struct clk *clks[EHCI_MAX_CLKS]; struct reset_control *rsts; @@ -75,6 +78,11 @@ static int ehci_platform_reset(struct usb_hcd *hcd) if (pdata->no_io_watchdog) ehci->need_io_watchdog = 0; + + if (of_device_is_compatible(pdev->dev.of_node, "brcm,xgs-iproc-ehci")) + ehci_writel(ehci, BCM_USB_FIFO_THRESHOLD, + &ehci->regs->bcm_iproc_insnreg01); + return 0; } @@ -410,8 +418,7 @@ static int ehci_platform_remove(struct platform_device *dev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int ehci_platform_suspend(struct device *dev) +static int __maybe_unused ehci_platform_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct usb_ehci_pdata *pdata = dev_get_platdata(dev); @@ -433,7 +440,7 @@ static int ehci_platform_suspend(struct device *dev) return ret; } -static int ehci_platform_resume(struct device *dev) +static int __maybe_unused ehci_platform_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct usb_ehci_pdata *pdata = dev_get_platdata(dev); @@ -464,7 +471,6 @@ static int ehci_platform_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM_SLEEP */ static const struct of_device_id vt8500_ehci_ids[] = { { .compatible = "via,vt8500-ehci", }, @@ -499,7 +505,7 @@ static struct platform_driver ehci_platform_driver = { .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "ehci-platform", - .pm = &ehci_platform_pm_ops, + .pm = pm_ptr(&ehci_platform_pm_ops), .of_match_table = vt8500_ehci_ids, .acpi_match_table = ACPI_PTR(ehci_acpi_match), } diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 847979f265b1..6dfb242f9a4b 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -307,26 +307,6 @@ static int __maybe_unused same_tt(struct usb_device *dev1, #ifdef CONFIG_USB_EHCI_TT_NEWSCHED -/* Which uframe does the low/fullspeed transfer start in? - * - * The parameter is the mask of ssplits in "H-frame" terms - * and this returns the transfer start uframe in "B-frame" terms, - * which allows both to match, e.g. a ssplit in "H-frame" uframe 0 - * will cause a transfer in "B-frame" uframe 0. "B-frames" lag - * "H-frames" by 1 uframe. See the EHCI spec sec 4.5 and figure 4.7. - */ -static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __hc32 mask) -{ - unsigned char smask = hc32_to_cpu(ehci, mask) & QH_SMASK; - - if (!smask) { - ehci_err(ehci, "invalid empty smask!\n"); - /* uframe 7 can't have bw so this will indicate failure */ - return 7; - } - return ffs(smask) - 1; -} - static const unsigned char max_tt_usecs[] = { 125, 125, 125, 125, 125, 125, 30, 0 }; diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c index add796c78561..3694e450a11a 100644 --- a/drivers/usb/host/ehci-spear.c +++ b/drivers/usb/host/ehci-spear.c @@ -34,8 +34,7 @@ struct spear_ehci { static struct hc_driver __read_mostly ehci_spear_hc_driver; -#ifdef CONFIG_PM_SLEEP -static int ehci_spear_drv_suspend(struct device *dev) +static int __maybe_unused ehci_spear_drv_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); bool do_wakeup = device_may_wakeup(dev); @@ -43,14 +42,13 @@ static int ehci_spear_drv_suspend(struct device *dev) return ehci_suspend(hcd, do_wakeup); } -static int ehci_spear_drv_resume(struct device *dev) +static int __maybe_unused ehci_spear_drv_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); ehci_resume(hcd, false); return 0; } -#endif /* CONFIG_PM_SLEEP */ static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend, ehci_spear_drv_resume); @@ -155,7 +153,7 @@ static struct platform_driver spear_ehci_hcd_driver = { .driver = { .name = "spear-ehci", .bus = &platform_bus_type, - .pm = &ehci_spear_pm_ops, + .pm = pm_ptr(&ehci_spear_pm_ops), .of_match_table = spear_ehci_id_table, } }; diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index 194df8282471..1d94fcfac2c2 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -32,6 +32,7 @@ #include <linux/uaccess.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/clk.h> #include <asm/byteorder.h> @@ -883,18 +884,15 @@ static int handshake(struct fotg210_hcd *fotg210, void __iomem *ptr, u32 mask, u32 done, int usec) { u32 result; + int ret; - do { - result = fotg210_readl(fotg210, ptr); - if (result == ~(u32)0) /* card removed */ - return -ENODEV; - result &= mask; - if (result == done) - return 0; - udelay(1); - usec--; - } while (usec > 0); - return -ETIMEDOUT; + ret = readl_poll_timeout_atomic(ptr, result, + ((result & mask) == done || + result == U32_MAX), 1, usec); + if (result == U32_MAX) /* card removed */ + return -ENODEV; + + return ret; } /* Force HC to halt state from unknown (EHCI spec section 2.3). diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index dd37e77dae00..73e13e7c2b46 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -102,7 +102,7 @@ static void io_watchdog_func(struct timer_list *t); /* Some boards misreport power switching/overcurrent */ -static bool distrust_firmware = true; +static bool distrust_firmware; module_param (distrust_firmware, bool, 0); MODULE_PARM_DESC (distrust_firmware, "true to distrust firmware power/overcurrent setup"); @@ -673,20 +673,24 @@ retry: /* handle root hub init quirks ... */ val = roothub_a (ohci); - val &= ~(RH_A_PSM | RH_A_OCPM); + /* Configure for per-port over-current protection by default */ + val &= ~RH_A_NOCP; + val |= RH_A_OCPM; if (ohci->flags & OHCI_QUIRK_SUPERIO) { - /* NSC 87560 and maybe others */ + /* NSC 87560 and maybe others. + * Ganged power switching, no over-current protection. + */ val |= RH_A_NOCP; - val &= ~(RH_A_POTPGT | RH_A_NPS); - ohci_writel (ohci, val, &ohci->regs->roothub.a); + val &= ~(RH_A_POTPGT | RH_A_NPS | RH_A_PSM | RH_A_OCPM); } else if ((ohci->flags & OHCI_QUIRK_AMD756) || (ohci->flags & OHCI_QUIRK_HUB_POWER)) { /* hub power always on; required for AMD-756 and some - * Mac platforms. ganged overcurrent reporting, if any. + * Mac platforms. */ val |= RH_A_NPS; - ohci_writel (ohci, val, &ohci->regs->roothub.a); } + ohci_writel(ohci, val, &ohci->regs->roothub.a); + ohci_writel (ohci, RH_HS_LPSC, &ohci->regs->roothub.status); ohci_writel (ohci, (val & RH_A_NPS) ? 0 : RH_B_PPCM, &ohci->regs->roothub.b); diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index cfa7dd2cc7d3..27dbbe1b28b1 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -24,6 +24,7 @@ #include <linux/moduleparam.h> #include <linux/dma-mapping.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <asm/irq.h> #include <asm/unaligned.h> @@ -748,18 +749,16 @@ static int handshake(struct oxu_hcd *oxu, void __iomem *ptr, u32 mask, u32 done, int usec) { u32 result; + int ret; - do { - result = readl(ptr); - if (result == ~(u32)0) /* card removed */ - return -ENODEV; - result &= mask; - if (result == done) - return 0; - udelay(1); - usec--; - } while (usec > 0); - return -ETIMEDOUT; + ret = readl_poll_timeout_atomic(ptr, result, + ((result & mask) == done || + result == U32_MAX), + 1, usec); + if (result == U32_MAX) /* card removed */ + return -ENODEV; + + return ret; } /* Force HC to halt state from unknown (EHCI spec section 2.3) */ diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 8c1bbac6d136..ef08d68b9714 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -16,8 +16,8 @@ #include <linux/export.h> #include <linux/acpi.h> #include <linux/dmi.h> - -#include <soc/bcm2835/raspberrypi-firmware.h> +#include <linux/of.h> +#include <linux/iopoll.h> #include "pci-quirks.h" #include "xhci-ext-caps.h" @@ -1013,15 +1013,9 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done, { u32 result; - do { - result = readl(ptr); - result &= mask; - if (result == done) - return 0; - udelay(delay_usec); - wait_usec -= delay_usec; - } while (wait_usec > 0); - return -ETIMEDOUT; + return readl_poll_timeout_atomic(ptr, result, + ((result & mask) == done), + delay_usec, wait_usec); } /* @@ -1247,7 +1241,8 @@ iounmap: static void quirk_usb_early_handoff(struct pci_dev *pdev) { - int ret; + struct device_node *parent; + bool is_rpi; /* Skip Netlogic mips SoC's internal PCI USB controller. * This device does not need/support EHCI/OHCI handoff @@ -1255,14 +1250,16 @@ static void quirk_usb_early_handoff(struct pci_dev *pdev) if (pdev->vendor == 0x184e) /* vendor Netlogic */ return; + /* + * Bypass the Raspberry Pi 4 controller xHCI controller, things are + * taken care of by the board's co-processor. + */ if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483) { - ret = rpi_firmware_init_vl805(pdev); - if (ret) { - /* Firmware might be outdated, or something failed */ - dev_warn(&pdev->dev, - "Failed to load VL805's firmware: %d. Will continue to attempt to work, but bad things might happen. You should fix this...\n", - ret); - } + parent = of_get_parent(pdev->bus->dev.of_node); + is_rpi = of_device_is_compatible(parent, "brcm,bcm2711-pcie"); + of_node_put(parent); + if (is_rpi) + return; } if (pdev->class != PCI_CLASS_SERIAL_USB_UHCI && diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c index b8918f73a432..ae4e4ab638b5 100644 --- a/drivers/usb/host/xhci-dbgtty.c +++ b/drivers/usb/host/xhci-dbgtty.c @@ -288,14 +288,14 @@ static const struct tty_operations dbc_tty_ops = { .unthrottle = dbc_tty_unthrottle, }; -static void dbc_rx_push(unsigned long _port) +static void dbc_rx_push(struct tasklet_struct *t) { struct dbc_request *req; struct tty_struct *tty; unsigned long flags; bool do_push = false; bool disconnect = false; - struct dbc_port *port = (void *)_port; + struct dbc_port *port = from_tasklet(port, t, push); struct list_head *queue = &port->read_queue; spin_lock_irqsave(&port->port_lock, flags); @@ -382,7 +382,7 @@ xhci_dbc_tty_init_port(struct xhci_dbc *dbc, struct dbc_port *port) { tty_port_init(&port->port); spin_lock_init(&port->port_lock); - tasklet_init(&port->push, dbc_rx_push, (unsigned long)port); + tasklet_setup(&port->push, dbc_rx_push); INIT_LIST_HEAD(&port->read_pool); INIT_LIST_HEAD(&port->read_queue); INIT_LIST_HEAD(&port->write_pool); diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c index c88bffd68742..2c0fda57869e 100644 --- a/drivers/usb/host/xhci-debugfs.c +++ b/drivers/usb/host/xhci-debugfs.c @@ -451,9 +451,11 @@ void xhci_debugfs_create_endpoint(struct xhci_hcd *xhci, if (!epriv) return; + epriv->show_ring = dev->eps[ep_index].ring; + snprintf(epriv->name, sizeof(epriv->name), "ep%02d", ep_index); epriv->root = xhci_debugfs_create_ring_dir(xhci, - &dev->eps[ep_index].ring, + &epriv->show_ring, epriv->name, spriv->root); spriv->eps[ep_index] = epriv; @@ -475,6 +477,111 @@ void xhci_debugfs_remove_endpoint(struct xhci_hcd *xhci, kfree(epriv); } +static int xhci_stream_id_show(struct seq_file *s, void *unused) +{ + struct xhci_ep_priv *epriv = s->private; + + if (!epriv->stream_info) + return -EPERM; + + seq_printf(s, "Show stream ID %d trb ring, supported [1 - %d]\n", + epriv->stream_id, epriv->stream_info->num_streams - 1); + + return 0; +} + +static int xhci_stream_id_open(struct inode *inode, struct file *file) +{ + return single_open(file, xhci_stream_id_show, inode->i_private); +} + +static ssize_t xhci_stream_id_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct xhci_ep_priv *epriv = s->private; + int ret; + u16 stream_id; /* MaxPStreams + 1 <= 16 */ + + if (!epriv->stream_info) + return -EPERM; + + /* Decimal number */ + ret = kstrtou16_from_user(ubuf, count, 10, &stream_id); + if (ret) + return ret; + + if (stream_id == 0 || stream_id >= epriv->stream_info->num_streams) + return -EINVAL; + + epriv->stream_id = stream_id; + epriv->show_ring = epriv->stream_info->stream_rings[stream_id]; + + return count; +} + +static const struct file_operations stream_id_fops = { + .open = xhci_stream_id_open, + .write = xhci_stream_id_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int xhci_stream_context_array_show(struct seq_file *s, void *unused) +{ + struct xhci_ep_priv *epriv = s->private; + struct xhci_stream_ctx *stream_ctx; + dma_addr_t dma; + int id; + + if (!epriv->stream_info) + return -EPERM; + + seq_printf(s, "Allocated %d streams and %d stream context array entries\n", + epriv->stream_info->num_streams, + epriv->stream_info->num_stream_ctxs); + + for (id = 0; id < epriv->stream_info->num_stream_ctxs; id++) { + stream_ctx = epriv->stream_info->stream_ctx_array + id; + dma = epriv->stream_info->ctx_array_dma + id * 16; + if (id < epriv->stream_info->num_streams) + seq_printf(s, "%pad stream id %d deq %016llx\n", &dma, + id, le64_to_cpu(stream_ctx->stream_ring)); + else + seq_printf(s, "%pad stream context entry not used deq %016llx\n", + &dma, le64_to_cpu(stream_ctx->stream_ring)); + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(xhci_stream_context_array); + +void xhci_debugfs_create_stream_files(struct xhci_hcd *xhci, + struct xhci_virt_device *dev, + int ep_index) +{ + struct xhci_slot_priv *spriv = dev->debugfs_private; + struct xhci_ep_priv *epriv; + + if (!spriv || !spriv->eps[ep_index] || + !dev->eps[ep_index].stream_info) + return; + + epriv = spriv->eps[ep_index]; + epriv->stream_info = dev->eps[ep_index].stream_info; + + /* Show trb ring of stream ID 1 by default */ + epriv->stream_id = 1; + epriv->show_ring = epriv->stream_info->stream_rings[1]; + debugfs_create_file("stream_id", 0644, + epriv->root, epriv, + &stream_id_fops); + debugfs_create_file("stream_context_array", 0444, + epriv->root, epriv, + &xhci_stream_context_array_fops); +} + void xhci_debugfs_create_slot(struct xhci_hcd *xhci, int slot_id) { struct xhci_slot_priv *priv; diff --git a/drivers/usb/host/xhci-debugfs.h b/drivers/usb/host/xhci-debugfs.h index 56db635fcd6e..7c074b4be819 100644 --- a/drivers/usb/host/xhci-debugfs.h +++ b/drivers/usb/host/xhci-debugfs.h @@ -91,6 +91,9 @@ struct xhci_file_map { struct xhci_ep_priv { char name[DEBUGFS_NAMELEN]; struct dentry *root; + struct xhci_stream_info *stream_info; + struct xhci_ring *show_ring; + unsigned int stream_id; }; struct xhci_slot_priv { @@ -113,6 +116,9 @@ void xhci_debugfs_create_endpoint(struct xhci_hcd *xhci, void xhci_debugfs_remove_endpoint(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, int ep_index); +void xhci_debugfs_create_stream_files(struct xhci_hcd *xhci, + struct xhci_virt_device *virt_dev, + int ep_index); #else static inline void xhci_debugfs_init(struct xhci_hcd *xhci) { } static inline void xhci_debugfs_exit(struct xhci_hcd *xhci) { } @@ -128,6 +134,10 @@ static inline void xhci_debugfs_remove_endpoint(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, int ep_index) { } +static inline void +xhci_debugfs_create_stream_files(struct xhci_hcd *xhci, + struct xhci_virt_device *virt_dev, + int ep_index) { } #endif /* CONFIG_DEBUG_FS */ #endif /* __LINUX_XHCI_DEBUGFS_H */ diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index 4311d4c9b68d..8f321f39ab96 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -77,7 +77,7 @@ static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk) { struct mu3c_ippc_regs __iomem *ippc = mtk->ippc_regs; u32 value, check_val; - int u3_ports_disabed = 0; + int u3_ports_disabled = 0; int ret; int i; @@ -92,7 +92,7 @@ static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk) /* power on and enable u3 ports except skipped ones */ for (i = 0; i < mtk->num_u3_ports; i++) { if ((0x1 << i) & mtk->u3p_dis_msk) { - u3_ports_disabed++; + u3_ports_disabled++; continue; } @@ -117,7 +117,7 @@ static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk) check_val = STS1_SYSPLL_STABLE | STS1_REF_RST | STS1_SYS125_RST | STS1_XHCI_RST; - if (mtk->num_u3_ports > u3_ports_disabed) + if (mtk->num_u3_ports > u3_ports_disabled) check_val |= STS1_U3_MAC_RST; ret = readl_poll_timeout(&ippc->ip_pw_sts1, value, diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 3feaafebfe58..c26c06e5c88c 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -12,6 +12,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/acpi.h> +#include <linux/reset.h> #include "xhci.h" #include "xhci-trace.h" @@ -346,6 +347,7 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) struct xhci_hcd *xhci; struct usb_hcd *hcd; struct xhci_driver_data *driver_data; + struct reset_control *reset; driver_data = (struct xhci_driver_data *)id->driver_data; if (driver_data && driver_data->quirks & XHCI_RENESAS_FW_QUIRK) { @@ -354,6 +356,11 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) return retval; } + reset = devm_reset_control_get_optional_exclusive(&dev->dev, NULL); + if (IS_ERR(reset)) + return PTR_ERR(reset); + reset_control_reset(reset); + /* Prevent runtime suspending between USB-2 and USB-3 initialization */ pm_runtime_get_noresume(&dev->dev); @@ -371,6 +378,7 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) /* USB 2.0 roothub is stored in the PCI device now. */ hcd = dev_get_drvdata(&dev->dev); xhci = hcd_to_xhci(hcd); + xhci->reset = reset; xhci->shared_hcd = usb_create_shared_hcd(&xhci_pci_hc_driver, &dev->dev, pci_name(dev), hcd); if (!xhci->shared_hcd) { @@ -522,6 +530,8 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) struct pci_dev *pdev = to_pci_dev(hcd->self.controller); int retval = 0; + reset_control_reset(xhci->reset); + /* The BIOS on systems with the Intel Panther Point chipset may or may * not support xHCI natively. That means that during system resume, it * may switch the ports back to EHCI so that users can use their diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 3057cfc76d6a..aa2d35f98200 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -54,6 +54,16 @@ static int xhci_priv_init_quirk(struct usb_hcd *hcd) return priv->init_quirk(hcd); } +static int xhci_priv_suspend_quirk(struct usb_hcd *hcd) +{ + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); + + if (!priv->suspend_quirk) + return 0; + + return priv->suspend_quirk(hcd); +} + static int xhci_priv_resume_quirk(struct usb_hcd *hcd) { struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); @@ -173,6 +183,8 @@ static int xhci_plat_probe(struct platform_device *pdev) struct usb_hcd *hcd; int ret; int irq; + struct xhci_plat_priv *priv = NULL; + if (usb_disabled()) return -ENODEV; @@ -264,16 +276,18 @@ static int xhci_plat_probe(struct platform_device *pdev) if (ret) goto disable_reg_clk; - priv_match = of_device_get_match_data(&pdev->dev); - if (priv_match) { - struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); + if (pdev->dev.of_node) + priv_match = of_device_get_match_data(&pdev->dev); + else + priv_match = dev_get_platdata(&pdev->dev); + if (priv_match) { + priv = hcd_to_xhci_priv(hcd); /* Just copy data for now */ - if (priv_match) - *priv = *priv_match; + *priv = *priv_match; } - device_wakeup_enable(hcd->self.controller); + device_set_wakeup_capable(&pdev->dev, true); xhci->main_hcd = hcd; xhci->shared_hcd = __usb_create_hcd(driver, sysdev, &pdev->dev, @@ -316,6 +330,9 @@ static int xhci_plat_probe(struct platform_device *pdev) hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node); xhci->shared_hcd->tpl_support = hcd->tpl_support; + if (priv && (priv->quirks & XHCI_SKIP_PHY_INIT)) + hcd->skip_phy_initialization = 1; + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret) goto disable_usb_phy; @@ -397,14 +414,14 @@ static int __maybe_unused xhci_plat_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct xhci_hcd *xhci = hcd_to_xhci(hcd); + int ret; + ret = xhci_priv_suspend_quirk(hcd); + if (ret) + return ret; /* * xhci_suspend() needs `do_wakeup` to know whether host is allowed - * to do wakeup during suspend. Since xhci_plat_suspend is currently - * only designed for system suspend, device_may_wakeup() is enough - * to dertermine whether host is allowed to do wakeup. Need to - * reconsider this when xhci_plat_suspend enlarges its scope, e.g., - * also applies to runtime suspend. + * to do wakeup during suspend. */ return xhci_suspend(xhci, device_may_wakeup(dev)); } @@ -434,6 +451,11 @@ static int __maybe_unused xhci_plat_runtime_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct xhci_hcd *xhci = hcd_to_xhci(hcd); + int ret; + + ret = xhci_priv_suspend_quirk(hcd); + if (ret) + return ret; return xhci_suspend(xhci, true); } diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h index b49f6447bd3a..1fb149d1fbce 100644 --- a/drivers/usb/host/xhci-plat.h +++ b/drivers/usb/host/xhci-plat.h @@ -15,6 +15,7 @@ struct xhci_plat_priv { unsigned long long quirks; void (*plat_start)(struct usb_hcd *); int (*init_quirk)(struct usb_hcd *); + int (*suspend_quirk)(struct usb_hcd *); int (*resume_quirk)(struct usb_hcd *); }; diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index c1025d321a41..1bc4fe7b8c75 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -6,6 +6,7 @@ */ #include <linux/firmware.h> +#include <linux/iopoll.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/of.h> @@ -127,8 +128,7 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd) void __iomem *regs = hcd->regs; struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); const struct firmware *fw; - int retval, index, j, time; - int timeout = 10000; + int retval, index, j; u32 data, val, temp; u32 quirks = 0; const struct soc_device_attribute *attr; @@ -166,32 +166,19 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd) temp |= RCAR_USB3_DL_CTRL_FW_SET_DATA0; writel(temp, regs + RCAR_USB3_DL_CTRL); - for (time = 0; time < timeout; time++) { - val = readl(regs + RCAR_USB3_DL_CTRL); - if ((val & RCAR_USB3_DL_CTRL_FW_SET_DATA0) == 0) - break; - udelay(1); - } - if (time == timeout) { - retval = -ETIMEDOUT; + retval = readl_poll_timeout_atomic(regs + RCAR_USB3_DL_CTRL, + val, !(val & RCAR_USB3_DL_CTRL_FW_SET_DATA0), + 1, 10000); + if (retval < 0) break; - } } temp = readl(regs + RCAR_USB3_DL_CTRL); temp &= ~RCAR_USB3_DL_CTRL_ENABLE; writel(temp, regs + RCAR_USB3_DL_CTRL); - for (time = 0; time < timeout; time++) { - val = readl(regs + RCAR_USB3_DL_CTRL); - if (val & RCAR_USB3_DL_CTRL_FW_SUCCESS) { - retval = 0; - break; - } - udelay(1); - } - if (time == timeout) - retval = -ETIMEDOUT; + retval = readl_poll_timeout_atomic((regs + RCAR_USB3_DL_CTRL), + val, val & RCAR_USB3_DL_CTRL_FW_SUCCESS, 1, 10000); release_firmware(fw); @@ -200,18 +187,12 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd) static bool xhci_rcar_wait_for_pll_active(struct usb_hcd *hcd) { - int timeout = 1000; + int retval; u32 val, mask = RCAR_USB3_AXH_STA_PLL_ACTIVE_MASK; - while (timeout > 0) { - val = readl(hcd->regs + RCAR_USB3_AXH_STA); - if ((val & mask) == mask) - return true; - udelay(1); - timeout--; - } - - return false; + retval = readl_poll_timeout_atomic(hcd->regs + RCAR_USB3_AXH_STA, + val, (val & mask) == mask, 1, 1000); + return !retval; } /* This function needs to initialize a "phy" of usb before */ diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index a741a38a4c69..167dae117f73 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3736,6 +3736,24 @@ static int xhci_get_isoc_frame_id(struct xhci_hcd *xhci, return start_frame; } +/* Check if we should generate event interrupt for a TD in an isoc URB */ +static bool trb_block_event_intr(struct xhci_hcd *xhci, int num_tds, int i) +{ + if (xhci->hci_version < 0x100) + return false; + /* always generate an event interrupt for the last TD */ + if (i == num_tds - 1) + return false; + /* + * If AVOID_BEI is set the host handles full event rings poorly, + * generate an event at least every 8th TD to clear the event ring + */ + if (i && xhci->quirks & XHCI_AVOID_BEI) + return !!(i % 8); + + return true; +} + /* This is for isoc transfer */ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index) @@ -3843,10 +3861,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, more_trbs_coming = false; td->last_trb = ep_ring->enqueue; field |= TRB_IOC; - /* set BEI, except for the last TD */ - if (xhci->hci_version >= 0x100 && - !(xhci->quirks & XHCI_AVOID_BEI) && - i < num_tds - 1) + if (trb_block_event_intr(xhci, num_tds, i)) field |= TRB_BEI; } /* Calculate TRB length */ diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 190923d8b246..934be1686352 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -1866,7 +1866,6 @@ static const struct tegra_xusb_phy_type tegra124_phy_types[] = { static const unsigned int tegra124_xusb_context_ipfs[] = { IPFS_XUSB_HOST_MSI_BAR_SZ_0, - IPFS_XUSB_HOST_MSI_BAR_SZ_0, IPFS_XUSB_HOST_MSI_AXI_BAR_ST_0, IPFS_XUSB_HOST_MSI_FPCI_BAR_ST_0, IPFS_XUSB_HOST_MSI_VEC0_0, diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index f4cedcaee14b..482fe8c5e3b4 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -982,12 +982,15 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) xhci->shared_hcd->state != HC_STATE_SUSPENDED) return -EINVAL; - xhci_dbc_suspend(xhci); - /* Clear root port wake on bits if wakeup not allowed. */ if (!do_wakeup) xhci_disable_port_wake_on_bits(xhci); + if (!HCD_HW_ACCESSIBLE(hcd)) + return 0; + + xhci_dbc_suspend(xhci); + /* Don't poll the roothubs on bus suspend. */ xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); @@ -1915,8 +1918,6 @@ static int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); trace_xhci_add_endpoint(ep_ctx); - xhci_debugfs_create_endpoint(xhci, virt_dev, ep_index); - xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n", (unsigned int) ep->desc.bEndpointAddress, udev->slot_id, @@ -2949,6 +2950,7 @@ static int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) xhci_check_bw_drop_ep_streams(xhci, virt_dev, i); virt_dev->eps[i].ring = virt_dev->eps[i].new_ring; virt_dev->eps[i].new_ring = NULL; + xhci_debugfs_create_endpoint(xhci, virt_dev, i); } command_cleanup: kfree(command->completion); @@ -3531,6 +3533,7 @@ static int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, xhci_dbg(xhci, "Slot %u ep ctx %u now has streams.\n", udev->slot_id, ep_index); vdev->eps[ep_index].ep_state |= EP_HAS_STREAMS; + xhci_debugfs_create_stream_files(xhci, vdev, ep_index); } xhci_free_command(xhci, config_cmd); spin_unlock_irqrestore(&xhci->lock, flags); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index ea1754f185a2..8be88379c0fb 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1770,6 +1770,8 @@ struct xhci_hcd { /* optional clocks */ struct clk *clk; struct clk *reg_clk; + /* optional reset controller */ + struct reset_control *reset; /* data structures */ struct xhci_device_context_array *dcbaa; struct xhci_ring *cmd_ring; @@ -1874,6 +1876,7 @@ struct xhci_hcd { #define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34) #define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35) #define XHCI_RENESAS_FW_QUIRK BIT_ULL(36) +#define XHCI_SKIP_PHY_INIT BIT_ULL(37) unsigned int num_active_eps; unsigned int limit_active_eps; |