summaryrefslogtreecommitdiff
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/Kconfig25
-rw-r--r--drivers/usb/host/Makefile2
-rw-r--r--drivers/usb/host/ehci-fsl.c2
-rw-r--r--drivers/usb/host/ehci-mem.c3
-rw-r--r--drivers/usb/host/ehci-platform.c55
-rw-r--r--drivers/usb/host/ehci-sched.c6
-rw-r--r--drivers/usb/host/ehci-tegra.c1
-rw-r--r--drivers/usb/host/fhci-dbg.c26
-rw-r--r--drivers/usb/host/imx21-dbg.c65
-rw-r--r--drivers/usb/host/isp116x-hcd.c15
-rw-r--r--drivers/usb/host/ohci-omap.c1
-rw-r--r--drivers/usb/host/ohci-platform.c56
-rw-r--r--drivers/usb/host/sl811-hcd.c17
-rw-r--r--drivers/usb/host/whci/debug.c48
-rw-r--r--drivers/usb/host/xhci-dbgtty.c5
-rw-r--r--drivers/usb/host/xhci-ext-caps.c90
-rw-r--r--drivers/usb/host/xhci-ext-caps.h7
-rw-r--r--drivers/usb/host/xhci-mem.c2
-rw-r--r--drivers/usb/host/xhci-mtk.c98
-rw-r--r--drivers/usb/host/xhci-pci.c5
-rw-r--r--drivers/usb/host/xhci-plat.c1
-rw-r--r--drivers/usb/host/xhci-ring.c27
-rw-r--r--drivers/usb/host/xhci.c139
-rw-r--r--drivers/usb/host/xhci.h4
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);