diff options
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/Kconfig | 25 | ||||
-rw-r--r-- | drivers/usb/host/Makefile | 2 | ||||
-rw-r--r-- | drivers/usb/host/ehci-fsl.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/ehci-mem.c | 3 | ||||
-rw-r--r-- | drivers/usb/host/ehci-platform.c | 55 | ||||
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 6 | ||||
-rw-r--r-- | drivers/usb/host/ehci-tegra.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/fhci-dbg.c | 26 | ||||
-rw-r--r-- | drivers/usb/host/imx21-dbg.c | 65 | ||||
-rw-r--r-- | drivers/usb/host/isp116x-hcd.c | 15 | ||||
-rw-r--r-- | drivers/usb/host/ohci-omap.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/ohci-platform.c | 56 | ||||
-rw-r--r-- | drivers/usb/host/sl811-hcd.c | 17 | ||||
-rw-r--r-- | drivers/usb/host/whci/debug.c | 48 | ||||
-rw-r--r-- | drivers/usb/host/xhci-dbgtty.c | 5 | ||||
-rw-r--r-- | drivers/usb/host/xhci-ext-caps.c | 90 | ||||
-rw-r--r-- | drivers/usb/host/xhci-ext-caps.h | 7 | ||||
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/xhci-mtk.c | 98 | ||||
-rw-r--r-- | drivers/usb/host/xhci-pci.c | 5 | ||||
-rw-r--r-- | drivers/usb/host/xhci-plat.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 27 | ||||
-rw-r--r-- | drivers/usb/host/xhci.c | 139 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 4 |
24 files changed, 270 insertions, 430 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index b85822f0c874..5d958da8e1bc 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -293,19 +293,6 @@ config USB_CNS3XXX_EHCI It is needed for high-speed (480Mbit/sec) USB 2.0 device support. -config USB_EHCI_ATH79 - bool "EHCI support for AR7XXX/AR9XXX SoCs (DEPRECATED)" - depends on (SOC_AR71XX || SOC_AR724X || SOC_AR913X || SOC_AR933X) - select USB_EHCI_ROOT_HUB_TT - select USB_EHCI_HCD_PLATFORM - default y - ---help--- - This option is deprecated now and the driver was removed, use - USB_EHCI_HCD_PLATFORM instead. - - Enables support for the built-in EHCI controller present - on the Atheros AR7XXX/AR9XXX SoCs. - config USB_EHCI_HCD_PLATFORM tristate "Generic EHCI driver for a platform device" default n @@ -490,18 +477,6 @@ config USB_OHCI_HCD_DAVINCI controller. This driver cannot currently be a loadable module because it lacks a proper PHY abstraction. -config USB_OHCI_ATH79 - bool "USB OHCI support for the Atheros AR71XX/AR7240 SoCs (DEPRECATED)" - depends on (SOC_AR71XX || SOC_AR724X) - select USB_OHCI_HCD_PLATFORM - default y - help - This option is deprecated now and the driver was removed, use - USB_OHCI_HCD_PLATFORM instead. - - Enables support for the built-in OHCI controller present on the - Atheros AR71XX/AR7240 SoCs. - config USB_OHCI_HCD_PPC_OF_BE bool "OHCI support for OF platform bus (big endian)" depends on PPC diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 4ede4ce12366..8a8cffe0b445 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -11,7 +11,7 @@ fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o -xhci-hcd-y := xhci.o xhci-mem.o +xhci-hcd-y := xhci.o xhci-mem.o xhci-ext-caps.o xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o xhci-hcd-y += xhci-trace.o diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index c5094cb88cd5..0a9fd2022acf 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -155,6 +155,8 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev) retval = -ENODEV; goto err2; } + + hcd->skip_phy_initialization = 1; } #endif return retval; diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index 21307d862af6..4c6c08b675b5 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -73,10 +73,9 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) if (!qh) goto done; qh->hw = (struct ehci_qh_hw *) - dma_pool_alloc(ehci->qh_pool, flags, &dma); + dma_pool_zalloc(ehci->qh_pool, flags, &dma); if (!qh->hw) goto fail; - memset(qh->hw, 0, sizeof *qh->hw); qh->qh_dma = dma; // INIT_LIST_HEAD (&qh->qh_list); INIT_LIST_HEAD (&qh->qtd_list); diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index b065a960adc2..4c306fb6b069 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -27,7 +27,6 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/reset.h> #include <linux/usb.h> @@ -44,8 +43,6 @@ struct ehci_platform_priv { struct clk *clks[EHCI_MAX_CLKS]; struct reset_control *rsts; - struct phy **phys; - int num_phys; bool reset_on_resume; }; @@ -80,7 +77,7 @@ static int ehci_platform_power_on(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); - int clk, ret, phy_num; + int clk, ret; for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) { ret = clk_prepare_enable(priv->clks[clk]); @@ -88,24 +85,8 @@ static int ehci_platform_power_on(struct platform_device *dev) goto err_disable_clks; } - for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { - ret = phy_init(priv->phys[phy_num]); - if (ret) - goto err_exit_phy; - ret = phy_power_on(priv->phys[phy_num]); - if (ret) { - phy_exit(priv->phys[phy_num]); - goto err_exit_phy; - } - } - return 0; -err_exit_phy: - while (--phy_num >= 0) { - phy_power_off(priv->phys[phy_num]); - phy_exit(priv->phys[phy_num]); - } err_disable_clks: while (--clk >= 0) clk_disable_unprepare(priv->clks[clk]); @@ -117,12 +98,7 @@ static void ehci_platform_power_off(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); - int clk, phy_num; - - for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { - phy_power_off(priv->phys[phy_num]); - phy_exit(priv->phys[phy_num]); - } + int clk; for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--) if (priv->clks[clk]) @@ -149,7 +125,7 @@ static int ehci_platform_probe(struct platform_device *dev) struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev); struct ehci_platform_priv *priv; struct ehci_hcd *ehci; - int err, irq, phy_num, clk = 0; + int err, irq, clk = 0; if (usb_disabled()) return -ENODEV; @@ -202,29 +178,6 @@ static int ehci_platform_probe(struct platform_device *dev) "has-transaction-translator")) hcd->has_tt = 1; - priv->num_phys = of_count_phandle_with_args(dev->dev.of_node, - "phys", "#phy-cells"); - - if (priv->num_phys > 0) { - priv->phys = devm_kcalloc(&dev->dev, priv->num_phys, - sizeof(struct phy *), GFP_KERNEL); - if (!priv->phys) - return -ENOMEM; - } else - priv->num_phys = 0; - - for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { - priv->phys[phy_num] = devm_of_phy_get_by_index( - &dev->dev, dev->dev.of_node, phy_num); - if (IS_ERR(priv->phys[phy_num])) { - err = PTR_ERR(priv->phys[phy_num]); - goto err_put_hcd; - } else if (!hcd->phy) { - /* Avoiding phy_get() in usb_add_hcd() */ - hcd->phy = priv->phys[phy_num]; - } - } - for (clk = 0; clk < EHCI_MAX_CLKS; clk++) { priv->clks[clk] = of_clk_get(dev->dev.of_node, clk); if (IS_ERR(priv->clks[clk])) { @@ -306,7 +259,7 @@ err_reset: err_put_clks: while (--clk >= 0) clk_put(priv->clks[clk]); -err_put_hcd: + if (pdata == &ehci_platform_defaults) dev->dev.platform_data = NULL; diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index e56db44708bc..28e2a338b481 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1287,7 +1287,7 @@ itd_urb_transaction( } else { alloc_itd: spin_unlock_irqrestore(&ehci->lock, flags); - itd = dma_pool_alloc(ehci->itd_pool, mem_flags, + itd = dma_pool_zalloc(ehci->itd_pool, mem_flags, &itd_dma); spin_lock_irqsave(&ehci->lock, flags); if (!itd) { @@ -1297,7 +1297,6 @@ itd_urb_transaction( } } - memset(itd, 0, sizeof(*itd)); itd->itd_dma = itd_dma; itd->frame = NO_FRAME; list_add(&itd->itd_list, &sched->td_list); @@ -2081,7 +2080,7 @@ sitd_urb_transaction( } else { alloc_sitd: spin_unlock_irqrestore(&ehci->lock, flags); - sitd = dma_pool_alloc(ehci->sitd_pool, mem_flags, + sitd = dma_pool_zalloc(ehci->sitd_pool, mem_flags, &sitd_dma); spin_lock_irqsave(&ehci->lock, flags); if (!sitd) { @@ -2091,7 +2090,6 @@ sitd_urb_transaction( } } - memset(sitd, 0, sizeof(*sitd)); sitd->sitd_dma = sitd_dma; sitd->frame = NO_FRAME; list_add(&sitd->sitd_list, &iso_sched->td_list); diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index c809f7d2f08f..a6f4389f7e88 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -461,6 +461,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) goto cleanup_clk_en; } hcd->usb_phy = u_phy; + hcd->skip_phy_initialization = 1; tegra->needs_double_reset = of_property_read_bool(pdev->dev.of_node, "nvidia,needs-double-reset"); diff --git a/drivers/usb/host/fhci-dbg.c b/drivers/usb/host/fhci-dbg.c index fafa91189e45..ebf9bb219f75 100644 --- a/drivers/usb/host/fhci-dbg.c +++ b/drivers/usb/host/fhci-dbg.c @@ -55,6 +55,7 @@ static int fhci_dfs_regs_show(struct seq_file *s, void *v) return 0; } +DEFINE_SHOW_ATTRIBUTE(fhci_dfs_regs); static int fhci_dfs_irq_stat_show(struct seq_file *s, void *v) { @@ -75,30 +76,7 @@ static int fhci_dfs_irq_stat_show(struct seq_file *s, void *v) return 0; } - -static int fhci_dfs_regs_open(struct inode *inode, struct file *file) -{ - return single_open(file, fhci_dfs_regs_show, inode->i_private); -} - -static int fhci_dfs_irq_stat_open(struct inode *inode, struct file *file) -{ - return single_open(file, fhci_dfs_irq_stat_show, inode->i_private); -} - -static const struct file_operations fhci_dfs_regs_fops = { - .open = fhci_dfs_regs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations fhci_dfs_irq_stat_fops = { - .open = fhci_dfs_irq_stat_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(fhci_dfs_irq_stat); void fhci_dfs_create(struct fhci_hcd *fhci) { diff --git a/drivers/usb/host/imx21-dbg.c b/drivers/usb/host/imx21-dbg.c index b964f9a51d87..a213ed6f07b5 100644 --- a/drivers/usb/host/imx21-dbg.c +++ b/drivers/usb/host/imx21-dbg.c @@ -245,6 +245,7 @@ static int debug_status_show(struct seq_file *s, void *v) return 0; } +DEFINE_SHOW_ATTRIBUTE(debug_status); static int debug_dmem_show(struct seq_file *s, void *v) { @@ -266,6 +267,7 @@ static int debug_dmem_show(struct seq_file *s, void *v) return 0; } +DEFINE_SHOW_ATTRIBUTE(debug_dmem); static int debug_etd_show(struct seq_file *s, void *v) { @@ -334,6 +336,7 @@ static int debug_etd_show(struct seq_file *s, void *v) return 0; } +DEFINE_SHOW_ATTRIBUTE(debug_etd); static void debug_statistics_show_one(struct seq_file *s, const char *name, struct debug_stats *stats) @@ -368,6 +371,7 @@ static int debug_statistics_show(struct seq_file *s, void *v) return 0; } +DEFINE_SHOW_ATTRIBUTE(debug_statistics); static void debug_isoc_show_one(struct seq_file *s, const char *name, int index, struct debug_isoc_trace *trace) @@ -409,66 +413,7 @@ static int debug_isoc_show(struct seq_file *s, void *v) return 0; } - -static int debug_status_open(struct inode *inode, struct file *file) -{ - return single_open(file, debug_status_show, inode->i_private); -} - -static int debug_dmem_open(struct inode *inode, struct file *file) -{ - return single_open(file, debug_dmem_show, inode->i_private); -} - -static int debug_etd_open(struct inode *inode, struct file *file) -{ - return single_open(file, debug_etd_show, inode->i_private); -} - -static int debug_statistics_open(struct inode *inode, struct file *file) -{ - return single_open(file, debug_statistics_show, inode->i_private); -} - -static int debug_isoc_open(struct inode *inode, struct file *file) -{ - return single_open(file, debug_isoc_show, inode->i_private); -} - -static const struct file_operations debug_status_fops = { - .open = debug_status_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations debug_dmem_fops = { - .open = debug_dmem_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations debug_etd_fops = { - .open = debug_etd_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations debug_statistics_fops = { - .open = debug_statistics_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations debug_isoc_fops = { - .open = debug_isoc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(debug_isoc); static void create_debug_files(struct imx21 *imx21) { diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 5f9234b9cf7b..4602ed801f0a 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1168,7 +1168,7 @@ static void dump_int(struct seq_file *s, char *label, u32 mask) mask & HCINT_SF ? " sof" : "", mask & HCINT_SO ? " so" : ""); } -static int isp116x_show_dbg(struct seq_file *s, void *unused) +static int isp116x_debug_show(struct seq_file *s, void *unused) { struct isp116x *isp116x = s->private; @@ -1196,18 +1196,7 @@ static int isp116x_show_dbg(struct seq_file *s, void *unused) return 0; } - -static int isp116x_open_seq(struct inode *inode, struct file *file) -{ - return single_open(file, isp116x_show_dbg, inode->i_private); -} - -static const struct file_operations isp116x_debug_fops = { - .open = isp116x_open_seq, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(isp116x_debug); static int create_debug_file(struct isp116x *isp116x) { diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 0201c49bc4fc..d8d35d456456 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -230,6 +230,7 @@ static int ohci_omap_reset(struct usb_hcd *hcd) } else { return -EPROBE_DEFER; } + hcd->skip_phy_initialization = 1; ohci->start_hnp = start_hnp; } #endif diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index 1e6c954f4b3f..65a1c3fdc88c 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -21,7 +21,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/err.h> -#include <linux/phy/phy.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/reset.h> @@ -38,8 +38,6 @@ struct ohci_platform_priv { struct clk *clks[OHCI_MAX_CLKS]; struct reset_control *resets; - struct phy **phys; - int num_phys; }; static const char hcd_name[] = "ohci-platform"; @@ -48,7 +46,7 @@ static int ohci_platform_power_on(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd); - int clk, ret, phy_num; + int clk, ret; for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) { ret = clk_prepare_enable(priv->clks[clk]); @@ -56,24 +54,8 @@ static int ohci_platform_power_on(struct platform_device *dev) goto err_disable_clks; } - for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { - ret = phy_init(priv->phys[phy_num]); - if (ret) - goto err_exit_phy; - ret = phy_power_on(priv->phys[phy_num]); - if (ret) { - phy_exit(priv->phys[phy_num]); - goto err_exit_phy; - } - } - return 0; -err_exit_phy: - while (--phy_num >= 0) { - phy_power_off(priv->phys[phy_num]); - phy_exit(priv->phys[phy_num]); - } err_disable_clks: while (--clk >= 0) clk_disable_unprepare(priv->clks[clk]); @@ -85,12 +67,7 @@ static void ohci_platform_power_off(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd); - int clk, phy_num; - - for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { - phy_power_off(priv->phys[phy_num]); - phy_exit(priv->phys[phy_num]); - } + int clk; for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--) if (priv->clks[clk]) @@ -117,7 +94,7 @@ static int ohci_platform_probe(struct platform_device *dev) struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev); struct ohci_platform_priv *priv; struct ohci_hcd *ohci; - int err, irq, phy_num, clk = 0; + int err, irq, clk = 0; if (usb_disabled()) return -ENODEV; @@ -169,29 +146,6 @@ static int ohci_platform_probe(struct platform_device *dev) of_property_read_u32(dev->dev.of_node, "num-ports", &ohci->num_ports); - priv->num_phys = of_count_phandle_with_args(dev->dev.of_node, - "phys", "#phy-cells"); - - if (priv->num_phys > 0) { - priv->phys = devm_kcalloc(&dev->dev, priv->num_phys, - sizeof(struct phy *), GFP_KERNEL); - if (!priv->phys) - return -ENOMEM; - } else - priv->num_phys = 0; - - for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { - priv->phys[phy_num] = devm_of_phy_get_by_index( - &dev->dev, dev->dev.of_node, phy_num); - if (IS_ERR(priv->phys[phy_num])) { - err = PTR_ERR(priv->phys[phy_num]); - goto err_put_hcd; - } else if (!hcd->phy) { - /* Avoiding phy_get() in usb_add_hcd() */ - hcd->phy = priv->phys[phy_num]; - } - } - for (clk = 0; clk < OHCI_MAX_CLKS; clk++) { priv->clks[clk] = of_clk_get(dev->dev.of_node, clk); if (IS_ERR(priv->clks[clk])) { @@ -277,7 +231,7 @@ err_reset: err_put_clks: while (--clk >= 0) clk_put(priv->clks[clk]); -err_put_hcd: + if (pdata == &ohci_platform_defaults) dev->dev.platform_data = NULL; diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index fa88a903fa2e..5b061e599948 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1381,7 +1381,7 @@ static void dump_irq(struct seq_file *s, char *label, u8 mask) (mask & SL11H_INTMASK_DP) ? " dp" : ""); } -static int sl811h_show(struct seq_file *s, void *unused) +static int sl811h_debug_show(struct seq_file *s, void *unused) { struct sl811 *sl811 = s->private; struct sl811h_ep *ep; @@ -1491,25 +1491,14 @@ static int sl811h_show(struct seq_file *s, void *unused) return 0; } - -static int sl811h_open(struct inode *inode, struct file *file) -{ - return single_open(file, sl811h_show, inode->i_private); -} - -static const struct file_operations debug_ops = { - .open = sl811h_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(sl811h_debug); /* expect just one sl811 per system */ static void create_debug_file(struct sl811 *sl811) { sl811->debug_file = debugfs_create_file("sl811h", S_IRUGO, usb_debug_root, sl811, - &debug_ops); + &sl811h_debug_fops); } static void remove_debug_file(struct sl811 *sl811) diff --git a/drivers/usb/host/whci/debug.c b/drivers/usb/host/whci/debug.c index f154e5791bfd..8ddfe3f1f693 100644 --- a/drivers/usb/host/whci/debug.c +++ b/drivers/usb/host/whci/debug.c @@ -72,7 +72,7 @@ static void qset_print(struct seq_file *s, struct whc_qset *qset) } } -static int di_print(struct seq_file *s, void *p) +static int di_show(struct seq_file *s, void *p) { struct whc *whc = s->private; int d; @@ -91,8 +91,9 @@ static int di_print(struct seq_file *s, void *p) } return 0; } +DEFINE_SHOW_ATTRIBUTE(di); -static int asl_print(struct seq_file *s, void *p) +static int asl_show(struct seq_file *s, void *p) { struct whc *whc = s->private; struct whc_qset *qset; @@ -103,8 +104,9 @@ static int asl_print(struct seq_file *s, void *p) return 0; } +DEFINE_SHOW_ATTRIBUTE(asl); -static int pzl_print(struct seq_file *s, void *p) +static int pzl_show(struct seq_file *s, void *p) { struct whc *whc = s->private; struct whc_qset *qset; @@ -118,45 +120,7 @@ static int pzl_print(struct seq_file *s, void *p) } return 0; } - -static int di_open(struct inode *inode, struct file *file) -{ - return single_open(file, di_print, inode->i_private); -} - -static int asl_open(struct inode *inode, struct file *file) -{ - return single_open(file, asl_print, inode->i_private); -} - -static int pzl_open(struct inode *inode, struct file *file) -{ - return single_open(file, pzl_print, inode->i_private); -} - -static const struct file_operations di_fops = { - .open = di_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static const struct file_operations asl_fops = { - .open = asl_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static const struct file_operations pzl_fops = { - .open = pzl_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; +DEFINE_SHOW_ATTRIBUTE(pzl); void whc_dbg_init(struct whc *whc) { diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c index 75f0b92694ba..48779c44c361 100644 --- a/drivers/usb/host/xhci-dbgtty.c +++ b/drivers/usb/host/xhci-dbgtty.c @@ -447,9 +447,10 @@ int xhci_dbc_tty_register_device(struct xhci_hcd *xhci) xhci_dbc_tty_init_port(xhci, port); tty_dev = tty_port_register_device(&port->port, dbc_tty_driver, 0, NULL); - ret = IS_ERR_OR_NULL(tty_dev); - if (ret) + if (IS_ERR(tty_dev)) { + ret = PTR_ERR(tty_dev); goto register_fail; + } ret = kfifo_alloc(&port->write_fifo, DBC_WRITE_BUF_SIZE, GFP_KERNEL); if (ret) diff --git a/drivers/usb/host/xhci-ext-caps.c b/drivers/usb/host/xhci-ext-caps.c new file mode 100644 index 000000000000..399113f9fc5c --- /dev/null +++ b/drivers/usb/host/xhci-ext-caps.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * XHCI extended capability handling + * + * Copyright (c) 2017 Hans de Goede <hdegoede@redhat.com> + */ + +#include <linux/platform_device.h> +#include "xhci.h" + +#define USB_SW_DRV_NAME "intel_xhci_usb_sw" +#define USB_SW_RESOURCE_SIZE 0x400 + +static void xhci_intel_unregister_pdev(void *arg) +{ + platform_device_unregister(arg); +} + +static int xhci_create_intel_xhci_sw_pdev(struct xhci_hcd *xhci, u32 cap_offset) +{ + struct usb_hcd *hcd = xhci_to_hcd(xhci); + struct device *dev = hcd->self.controller; + struct platform_device *pdev; + struct resource res = { 0, }; + int ret; + + pdev = platform_device_alloc(USB_SW_DRV_NAME, PLATFORM_DEVID_NONE); + if (!pdev) { + xhci_err(xhci, "couldn't allocate %s platform device\n", + USB_SW_DRV_NAME); + return -ENOMEM; + } + + res.start = hcd->rsrc_start + cap_offset; + res.end = res.start + USB_SW_RESOURCE_SIZE - 1; + res.name = USB_SW_DRV_NAME; + res.flags = IORESOURCE_MEM; + + ret = platform_device_add_resources(pdev, &res, 1); + if (ret) { + dev_err(dev, "couldn't add resources to intel_xhci_usb_sw pdev\n"); + platform_device_put(pdev); + return ret; + } + + pdev->dev.parent = dev; + + ret = platform_device_add(pdev); + if (ret) { + dev_err(dev, "couldn't register intel_xhci_usb_sw pdev\n"); + platform_device_put(pdev); + return ret; + } + + ret = devm_add_action_or_reset(dev, xhci_intel_unregister_pdev, pdev); + if (ret) { + dev_err(dev, "couldn't add unregister action for intel_xhci_usb_sw pdev\n"); + return ret; + } + + return 0; +} + +int xhci_ext_cap_init(struct xhci_hcd *xhci) +{ + void __iomem *base = &xhci->cap_regs->hc_capbase; + u32 offset, val; + int ret; + + offset = xhci_find_next_ext_cap(base, 0, 0); + + while (offset) { + val = readl(base + offset); + + switch (XHCI_EXT_CAPS_ID(val)) { + case XHCI_EXT_CAPS_VENDOR_INTEL: + if (xhci->quirks & XHCI_INTEL_USB_ROLE_SW) { + ret = xhci_create_intel_xhci_sw_pdev(xhci, + offset); + if (ret) + return ret; + } + break; + } + offset = xhci_find_next_ext_cap(base, offset, 0); + } + + return 0; +} +EXPORT_SYMBOL_GPL(xhci_ext_cap_init); diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h index bf7316e130d3..268328c20681 100644 --- a/drivers/usb/host/xhci-ext-caps.h +++ b/drivers/usb/host/xhci-ext-caps.h @@ -39,6 +39,8 @@ #define XHCI_EXT_CAPS_ROUTE 5 /* IDs 6-9 reserved */ #define XHCI_EXT_CAPS_DEBUG 10 +/* Vendor caps */ +#define XHCI_EXT_CAPS_VENDOR_INTEL 192 /* USB Legacy Support Capability - section 7.1.1 */ #define XHCI_HC_BIOS_OWNED (1 << 16) #define XHCI_HC_OS_OWNED (1 << 24) @@ -84,7 +86,8 @@ * @base PCI MMIO registers base address. * @start address at which to start looking, (0 or HCC_PARAMS to start at * beginning of list) - * @id Extended capability ID to search for. + * @id Extended capability ID to search for, or 0 for the next + * capability * * Returns the offset of the next matching extended capability structure. * Some capabilities can occur several times, e.g., the XHCI_EXT_CAPS_PROTOCOL, @@ -110,7 +113,7 @@ static inline int xhci_find_next_ext_cap(void __iomem *base, u32 start, int id) val = readl(base + offset); if (val == ~0) return 0; - if (XHCI_EXT_CAPS_ID(val) == id && offset != start) + if (offset != start && (id == 0 || XHCI_EXT_CAPS_ID(val) == id)) return offset; next = XHCI_EXT_CAPS_NEXT(val); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 332420d10be9..e5ace8995b3b 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -913,6 +913,8 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) if (dev->out_ctx) xhci_free_container_ctx(xhci, dev->out_ctx); + if (dev->udev && dev->udev->slot_id) + dev->udev->slot_id = 0; kfree(xhci->devs[slot_id]); xhci->devs[slot_id] = NULL; } diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index b0ab4d5e2751..7334da9e9779 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -14,7 +14,6 @@ #include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> @@ -352,62 +351,6 @@ static const struct xhci_driver_overrides xhci_mtk_overrides __initconst = { static struct hc_driver __read_mostly xhci_mtk_hc_driver; -static int xhci_mtk_phy_init(struct xhci_hcd_mtk *mtk) -{ - int i; - int ret; - - for (i = 0; i < mtk->num_phys; i++) { - ret = phy_init(mtk->phys[i]); - if (ret) - goto exit_phy; - } - return 0; - -exit_phy: - for (; i > 0; i--) - phy_exit(mtk->phys[i - 1]); - - return ret; -} - -static int xhci_mtk_phy_exit(struct xhci_hcd_mtk *mtk) -{ - int i; - - for (i = 0; i < mtk->num_phys; i++) - phy_exit(mtk->phys[i]); - - return 0; -} - -static int xhci_mtk_phy_power_on(struct xhci_hcd_mtk *mtk) -{ - int i; - int ret; - - for (i = 0; i < mtk->num_phys; i++) { - ret = phy_power_on(mtk->phys[i]); - if (ret) - goto power_off_phy; - } - return 0; - -power_off_phy: - for (; i > 0; i--) - phy_power_off(mtk->phys[i - 1]); - - return ret; -} - -static void xhci_mtk_phy_power_off(struct xhci_hcd_mtk *mtk) -{ - unsigned int i; - - for (i = 0; i < mtk->num_phys; i++) - phy_power_off(mtk->phys[i]); -} - static int xhci_mtk_ldos_enable(struct xhci_hcd_mtk *mtk) { int ret; @@ -488,8 +431,6 @@ static int xhci_mtk_probe(struct platform_device *pdev) struct xhci_hcd *xhci; struct resource *res; struct usb_hcd *hcd; - struct phy *phy; - int phy_num; int ret = -ENODEV; int irq; @@ -529,16 +470,6 @@ static int xhci_mtk_probe(struct platform_device *pdev) return ret; } - mtk->num_phys = of_count_phandle_with_args(node, - "phys", "#phy-cells"); - if (mtk->num_phys > 0) { - mtk->phys = devm_kcalloc(dev, mtk->num_phys, - sizeof(*mtk->phys), GFP_KERNEL); - if (!mtk->phys) - return -ENOMEM; - } else { - mtk->num_phys = 0; - } pm_runtime_enable(dev); pm_runtime_get_sync(dev); device_enable_async_suspend(dev); @@ -596,23 +527,6 @@ static int xhci_mtk_probe(struct platform_device *pdev) mtk->has_ippc = false; } - for (phy_num = 0; phy_num < mtk->num_phys; phy_num++) { - phy = devm_of_phy_get_by_index(dev, node, phy_num); - if (IS_ERR(phy)) { - ret = PTR_ERR(phy); - goto put_usb2_hcd; - } - mtk->phys[phy_num] = phy; - } - - ret = xhci_mtk_phy_init(mtk); - if (ret) - goto put_usb2_hcd; - - ret = xhci_mtk_phy_power_on(mtk); - if (ret) - goto exit_phys; - device_init_wakeup(dev, true); xhci = hcd_to_xhci(hcd); @@ -630,7 +544,7 @@ static int xhci_mtk_probe(struct platform_device *pdev) dev_name(dev), hcd); if (!xhci->shared_hcd) { ret = -ENOMEM; - goto power_off_phys; + goto disable_device_wakeup; } ret = usb_add_hcd(hcd, irq, IRQF_SHARED); @@ -653,13 +567,9 @@ put_usb3_hcd: xhci_mtk_sch_exit(mtk); usb_put_hcd(xhci->shared_hcd); -power_off_phys: - xhci_mtk_phy_power_off(mtk); +disable_device_wakeup: device_init_wakeup(dev, false); -exit_phys: - xhci_mtk_phy_exit(mtk); - put_usb2_hcd: usb_put_hcd(hcd); @@ -682,8 +592,6 @@ static int xhci_mtk_remove(struct platform_device *dev) struct xhci_hcd *xhci = hcd_to_xhci(hcd); usb_remove_hcd(xhci->shared_hcd); - xhci_mtk_phy_power_off(mtk); - xhci_mtk_phy_exit(mtk); device_init_wakeup(&dev->dev, false); usb_remove_hcd(hcd); @@ -718,7 +626,6 @@ static int __maybe_unused xhci_mtk_suspend(struct device *dev) del_timer_sync(&xhci->shared_hcd->rh_timer); xhci_mtk_host_disable(mtk); - xhci_mtk_phy_power_off(mtk); xhci_mtk_clks_disable(mtk); usb_wakeup_set(mtk, true); return 0; @@ -732,7 +639,6 @@ static int __maybe_unused xhci_mtk_resume(struct device *dev) usb_wakeup_set(mtk, false); xhci_mtk_clks_enable(mtk); - xhci_mtk_phy_power_on(mtk); xhci_mtk_host_enable(mtk); xhci_dbg(xhci, "%s: restart port polling\n", __func__); diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index d9f831b67e57..f17b7eab66cf 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -178,6 +178,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) { xhci->quirks |= XHCI_SSIC_PORT_UNUSED; + xhci->quirks |= XHCI_INTEL_USB_ROLE_SW; } if (pdev->vendor == PCI_VENDOR_ID_INTEL && (pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || @@ -311,6 +312,10 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) goto dealloc_usb2_hcd; } + retval = xhci_ext_cap_init(xhci); + if (retval) + goto put_usb3_hcd; + retval = usb_add_hcd(xhci->shared_hcd, dev->irq, IRQF_SHARED); if (retval) diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 6652e2d5bd2e..df327dcc2bac 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -284,6 +284,7 @@ static int xhci_plat_probe(struct platform_device *pdev) ret = usb_phy_init(hcd->usb_phy); if (ret) goto put_usb3_hcd; + hcd->skip_phy_initialization = 1; } ret = usb_add_hcd(hcd, irq, IRQF_SHARED); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index daa94c3aed80..91a1a824673d 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1436,7 +1436,8 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, case TRB_STOP_RING: WARN_ON(slot_id != TRB_TO_SLOT_ID( le32_to_cpu(cmd_trb->generic.field[3]))); - xhci_handle_cmd_stop_ep(xhci, slot_id, cmd_trb, event); + if (!cmd->completion) + xhci_handle_cmd_stop_ep(xhci, slot_id, cmd_trb, event); break; case TRB_SET_DEQ: WARN_ON(slot_id != TRB_TO_SLOT_ID( @@ -1815,8 +1816,7 @@ struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, - unsigned int stream_id, - struct xhci_td *td, union xhci_trb *ep_trb, + unsigned int stream_id, struct xhci_td *td, enum xhci_ep_reset_type reset_type) { struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index]; @@ -1829,9 +1829,10 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, xhci_queue_reset_ep(xhci, command, slot_id, ep_index, reset_type); - if (reset_type == EP_HARD_RESET) + if (reset_type == EP_HARD_RESET) { + ep->ep_state |= EP_HARD_CLEAR_TOGGLE; xhci_cleanup_stalled_ring(xhci, ep_index, stream_id, td); - + } xhci_ring_cmd_db(xhci); } @@ -1922,7 +1923,7 @@ static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td, } static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, - union xhci_trb *ep_trb, struct xhci_transfer_event *event, + struct xhci_transfer_event *event, struct xhci_virt_ep *ep, int *status) { struct xhci_virt_device *xdev; @@ -1957,8 +1958,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, * The class driver clears the device side halt later. */ xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index, - ep_ring->stream_id, td, ep_trb, - EP_HARD_RESET); + ep_ring->stream_id, td, EP_HARD_RESET); } else { /* Update ring dequeue pointer */ while (ep_ring->dequeue != td->last_trb) @@ -2083,7 +2083,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, td->urb->actual_length = requested; finish_td: - return finish_td(xhci, td, ep_trb, event, ep, status); + return finish_td(xhci, td, event, ep, status); } /* @@ -2170,7 +2170,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, td->urb->actual_length += frame->actual_length; - return finish_td(xhci, td, ep_trb, event, ep, status); + return finish_td(xhci, td, event, ep, status); } static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, @@ -2260,7 +2260,7 @@ finish_td: remaining); td->urb->actual_length = 0; } - return finish_td(xhci, td, ep_trb, event, ep, status); + return finish_td(xhci, td, event, ep, status); } /* @@ -2318,7 +2318,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, case COMP_INVALID_STREAM_TYPE_ERROR: case COMP_INVALID_STREAM_ID_ERROR: xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index, 0, - NULL, NULL, EP_SOFT_RESET); + NULL, EP_SOFT_RESET); goto cleanup; case COMP_RING_UNDERRUN: case COMP_RING_OVERRUN: @@ -2584,8 +2584,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index, ep_ring->stream_id, - td, ep_trb, - EP_HARD_RESET); + td, EP_HARD_RESET); goto cleanup; } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 5d37700ae4b0..9b27798ecce5 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1290,7 +1290,8 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag struct xhci_hcd *xhci = hcd_to_xhci(hcd); unsigned long flags; int ret = 0; - unsigned int slot_id, ep_index, ep_state; + unsigned int slot_id, ep_index; + unsigned int *ep_state; struct urb_priv *urb_priv; int num_tds; @@ -1300,6 +1301,7 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag slot_id = urb->dev->slot_id; ep_index = xhci_get_endpoint_index(&urb->ep->desc); + ep_state = &xhci->devs[slot_id]->eps[ep_index].ep_state; if (!HCD_HW_ACCESSIBLE(hcd)) { if (!in_interrupt()) @@ -1351,6 +1353,17 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag ret = -ESHUTDOWN; goto free_priv; } + if (*ep_state & (EP_GETTING_STREAMS | EP_GETTING_NO_STREAMS)) { + xhci_warn(xhci, "WARN: Can't enqueue URB, ep in streams transition state %x\n", + *ep_state); + ret = -EINVAL; + goto free_priv; + } + if (*ep_state & EP_SOFT_CLEAR_TOGGLE) { + xhci_warn(xhci, "Can't enqueue URB while manually clearing toggle\n"); + ret = -EINVAL; + goto free_priv; + } switch (usb_endpoint_type(&urb->ep->desc)) { @@ -1359,23 +1372,13 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag slot_id, ep_index); break; case USB_ENDPOINT_XFER_BULK: - ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state; - if (ep_state & (EP_GETTING_STREAMS | EP_GETTING_NO_STREAMS)) { - xhci_warn(xhci, "WARN: Can't enqueue URB, ep in streams transition state %x\n", - ep_state); - ret = -EINVAL; - break; - } ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); break; - - case USB_ENDPOINT_XFER_INT: ret = xhci_queue_intr_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); break; - case USB_ENDPOINT_XFER_ISOC: ret = xhci_queue_isoc_tx_prepare(xhci, GFP_ATOMIC, urb, slot_id, ep_index); @@ -2874,33 +2877,103 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, unsigned int ep_index, } } -/* Called when clearing halted device. The core should have sent the control - * message to clear the device halt condition. The host side of the halt should - * already be cleared with a reset endpoint command issued when the STALL tx - * event was received. +/* + * Called after usb core issues a clear halt control message. + * The host side of the halt should already be cleared by a reset endpoint + * command issued when the STALL event was received. * - * Context: in_interrupt + * The reset endpoint command may only be issued to endpoints in the halted + * state. For software that wishes to reset the data toggle or sequence number + * of an endpoint that isn't in the halted state this function will issue a + * configure endpoint command with the Drop and Add bits set for the target + * endpoint. Refer to the additional note in xhci spcification section 4.6.8. */ static void xhci_endpoint_reset(struct usb_hcd *hcd, - struct usb_host_endpoint *ep) + struct usb_host_endpoint *host_ep) { struct xhci_hcd *xhci; + struct usb_device *udev; + struct xhci_virt_device *vdev; + struct xhci_virt_ep *ep; + struct xhci_input_control_ctx *ctrl_ctx; + struct xhci_command *stop_cmd, *cfg_cmd; + unsigned int ep_index; + unsigned long flags; + u32 ep_flag; xhci = hcd_to_xhci(hcd); + if (!host_ep->hcpriv) + return; + udev = (struct usb_device *) host_ep->hcpriv; + vdev = xhci->devs[udev->slot_id]; + ep_index = xhci_get_endpoint_index(&host_ep->desc); + ep = &vdev->eps[ep_index]; + + /* Bail out if toggle is already being cleared by a endpoint reset */ + if (ep->ep_state & EP_HARD_CLEAR_TOGGLE) { + ep->ep_state &= ~EP_HARD_CLEAR_TOGGLE; + return; + } + /* Only interrupt and bulk ep's use data toggle, USB2 spec 5.5.4-> */ + if (usb_endpoint_xfer_control(&host_ep->desc) || + usb_endpoint_xfer_isoc(&host_ep->desc)) + return; + + ep_flag = xhci_get_endpoint_flag(&host_ep->desc); + + if (ep_flag == SLOT_FLAG || ep_flag == EP0_FLAG) + return; + + stop_cmd = xhci_alloc_command(xhci, true, GFP_NOWAIT); + if (!stop_cmd) + return; + + cfg_cmd = xhci_alloc_command_with_ctx(xhci, true, GFP_NOWAIT); + if (!cfg_cmd) + goto cleanup; + + spin_lock_irqsave(&xhci->lock, flags); + + /* block queuing new trbs and ringing ep doorbell */ + ep->ep_state |= EP_SOFT_CLEAR_TOGGLE; /* - * We might need to implement the config ep cmd in xhci 4.8.1 note: - * The Reset Endpoint Command may only be issued to endpoints in the - * Halted state. If software wishes reset the Data Toggle or Sequence - * Number of an endpoint that isn't in the Halted state, then software - * may issue a Configure Endpoint Command with the Drop and Add bits set - * for the target endpoint. that is in the Stopped state. + * Make sure endpoint ring is empty before resetting the toggle/seq. + * Driver is required to synchronously cancel all transfer request. + * Stop the endpoint to force xHC to update the output context */ - /* For now just print debug to follow the situation */ - xhci_dbg(xhci, "Endpoint 0x%x ep reset callback called\n", - ep->desc.bEndpointAddress); + if (!list_empty(&ep->ring->td_list)) { + dev_err(&udev->dev, "EP not empty, refuse reset\n"); + spin_unlock_irqrestore(&xhci->lock, flags); + goto cleanup; + } + xhci_queue_stop_endpoint(xhci, stop_cmd, udev->slot_id, ep_index, 0); + xhci_ring_cmd_db(xhci); + spin_unlock_irqrestore(&xhci->lock, flags); + + wait_for_completion(stop_cmd->completion); + + spin_lock_irqsave(&xhci->lock, flags); + + /* config ep command clears toggle if add and drop ep flags are set */ + ctrl_ctx = xhci_get_input_control_ctx(cfg_cmd->in_ctx); + xhci_setup_input_ctx_for_config_ep(xhci, cfg_cmd->in_ctx, vdev->out_ctx, + ctrl_ctx, ep_flag, ep_flag); + xhci_endpoint_copy(xhci, cfg_cmd->in_ctx, vdev->out_ctx, ep_index); + + xhci_queue_configure_endpoint(xhci, cfg_cmd, cfg_cmd->in_ctx->dma, + udev->slot_id, false); + xhci_ring_cmd_db(xhci); + spin_unlock_irqrestore(&xhci->lock, flags); + + wait_for_completion(cfg_cmd->completion); + + ep->ep_state &= ~EP_SOFT_CLEAR_TOGGLE; + xhci_free_command(xhci, cfg_cmd); +cleanup: + xhci_free_command(xhci, stop_cmd); } static int xhci_check_streams_endpoint(struct xhci_hcd *xhci, @@ -4768,6 +4841,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) * quirks */ struct device *dev = hcd->self.sysdev; + unsigned int minor_rev; int retval; /* Accept arbitrarily long scatter-gather lists */ @@ -4795,12 +4869,19 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) */ hcd->has_tt = 1; } else { - /* Some 3.1 hosts return sbrn 0x30, can't rely on sbrn alone */ - if (xhci->sbrn == 0x31 || xhci->usb3_rhub.min_rev >= 1) { - xhci_info(xhci, "Host supports USB 3.1 Enhanced SuperSpeed\n"); + /* + * Some 3.1 hosts return sbrn 0x30, use xhci supported protocol + * minor revision instead of sbrn + */ + minor_rev = xhci->usb3_rhub.min_rev; + if (minor_rev) { hcd->speed = HCD_USB31; hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS; } + xhci_info(xhci, "Host supports USB 3.%x %s SuperSpeed\n", + minor_rev, + minor_rev ? "Enhanced" : ""); + /* xHCI private pointer was set in xhci_pci_probe for the second * registered roothub. */ diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 866e141d4972..05c909b04f14 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -922,6 +922,8 @@ struct xhci_virt_ep { #define EP_HAS_STREAMS (1 << 4) /* Transitioning the endpoint to not using streams, don't enqueue URBs */ #define EP_GETTING_NO_STREAMS (1 << 5) +#define EP_HARD_CLEAR_TOGGLE (1 << 6) +#define EP_SOFT_CLEAR_TOGGLE (1 << 7) /* ---- Related to URB cancellation ---- */ struct list_head cancelled_td_list; /* Watchdog timer for stop endpoint command to cancel URBs */ @@ -1827,6 +1829,7 @@ struct xhci_hcd { #define XHCI_ASMEDIA_MODIFY_FLOWCONTROL (1 << 28) #define XHCI_HW_LPM_DISABLE (1 << 29) #define XHCI_SUSPEND_DELAY (1 << 30) +#define XHCI_INTEL_USB_ROLE_SW (1 << 31) unsigned int num_active_eps; unsigned int limit_active_eps; @@ -2022,6 +2025,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks); void xhci_init_driver(struct hc_driver *drv, const struct xhci_driver_overrides *over); int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id); +int xhci_ext_cap_init(struct xhci_hcd *xhci); int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup); int xhci_resume(struct xhci_hcd *xhci, bool hibernated); |