summaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/Kconfig11
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-dbg.c30
-rw-r--r--drivers/usb/host/ehci-hcd.c5
-rw-r--r--drivers/usb/host/ehci-omap.c5
-rw-r--r--drivers/usb/host/ehci-tegra.c87
-rw-r--r--drivers/usb/host/fhci-dbg.c23
-rw-r--r--drivers/usb/host/fhci.h2
-rw-r--r--drivers/usb/host/fotg210-hcd.c34
-rw-r--r--drivers/usb/host/imx21-dbg.c44
-rw-r--r--drivers/usb/host/isp116x-hcd.c17
-rw-r--r--drivers/usb/host/ohci-at91.c2
-rw-r--r--drivers/usb/host/ohci-dbg.c45
-rw-r--r--drivers/usb/host/ohci-hcd.c5
-rw-r--r--drivers/usb/host/ohci.h3
-rw-r--r--drivers/usb/host/pci-quirks.c20
-rw-r--r--drivers/usb/host/pci-quirks.h1
-rw-r--r--drivers/usb/host/uhci-hcd.c15
-rw-r--r--drivers/usb/host/xhci-dbgcap.c1
-rw-r--r--drivers/usb/host/xhci-dbgcap.h2
-rw-r--r--drivers/usb/host/xhci-dbgtty.c1
-rw-r--r--drivers/usb/host/xhci-debugfs.c85
-rw-r--r--drivers/usb/host/xhci-histb.c410
-rw-r--r--drivers/usb/host/xhci-hub.c244
-rw-r--r--drivers/usb/host/xhci-mem.c193
-rw-r--r--drivers/usb/host/xhci-mtk-sch.c4
-rw-r--r--drivers/usb/host/xhci-pci.c15
-rw-r--r--drivers/usb/host/xhci-ring.c126
-rw-r--r--drivers/usb/host/xhci-tegra.c176
-rw-r--r--drivers/usb/host/xhci.c123
-rw-r--r--drivers/usb/host/xhci.h106
31 files changed, 1116 insertions, 720 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 5d958da..6e64d3a 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -52,6 +52,13 @@ config USB_XHCI_PLATFORM
If unsure, say N.
+config USB_XHCI_HISTB
+ tristate "xHCI support for HiSilicon STB SoCs"
+ depends on USB_XHCI_PLATFORM && (ARCH_HISI || COMPILE_TEST)
+ help
+ Say 'Y' to enable the support for the xHCI host controller
+ found in HiSilicon STB SoCs.
+
config USB_XHCI_MTK
tristate "xHCI support for MediaTek SoCs"
select MFD_SYSCON
@@ -234,9 +241,7 @@ config USB_EHCI_TEGRA
tristate "NVIDIA Tegra HCD support"
depends on ARCH_TEGRA
select USB_EHCI_ROOT_HUB_TT
- select USB_PHY
- select USB_ULPI
- select USB_ULPI_VIEWPORT
+ select USB_TEGRA_PHY
help
This driver enables support for the internal USB Host Controllers
found in NVIDIA Tegra SoCs. The controllers are EHCI compliant.
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 8a8cffe..9b669c9 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -74,6 +74,7 @@ obj-$(CONFIG_USB_FHCI_HCD) += fhci.o
obj-$(CONFIG_USB_XHCI_HCD) += xhci-hcd.o
obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o
obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o
+obj-$(CONFIG_USB_XHCI_HISTB) += xhci-histb.o
obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk.o
obj-$(CONFIG_USB_XHCI_TEGRA) += xhci-tegra.o
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 3ed75aa..7619cfb 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -1028,29 +1028,15 @@ static inline void create_debug_files(struct ehci_hcd *ehci)
struct usb_bus *bus = &ehci_to_hcd(ehci)->self;
ehci->debug_dir = debugfs_create_dir(bus->bus_name, ehci_debug_root);
- if (!ehci->debug_dir)
- return;
- if (!debugfs_create_file("async", S_IRUGO, ehci->debug_dir, bus,
- &debug_async_fops))
- goto file_error;
-
- if (!debugfs_create_file("bandwidth", S_IRUGO, ehci->debug_dir, bus,
- &debug_bandwidth_fops))
- goto file_error;
-
- if (!debugfs_create_file("periodic", S_IRUGO, ehci->debug_dir, bus,
- &debug_periodic_fops))
- goto file_error;
-
- if (!debugfs_create_file("registers", S_IRUGO, ehci->debug_dir, bus,
- &debug_registers_fops))
- goto file_error;
-
- return;
-
-file_error:
- debugfs_remove_recursive(ehci->debug_dir);
+ debugfs_create_file("async", S_IRUGO, ehci->debug_dir, bus,
+ &debug_async_fops);
+ debugfs_create_file("bandwidth", S_IRUGO, ehci->debug_dir, bus,
+ &debug_bandwidth_fops);
+ debugfs_create_file("periodic", S_IRUGO, ehci->debug_dir, bus,
+ &debug_periodic_fops);
+ debugfs_create_file("registers", S_IRUGO, ehci->debug_dir, bus,
+ &debug_registers_fops);
}
static inline void remove_debug_files(struct ehci_hcd *ehci)
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index d927adf..89c47ae 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1311,10 +1311,6 @@ static int __init ehci_hcd_init(void)
#ifdef CONFIG_DYNAMIC_DEBUG
ehci_debug_root = debugfs_create_dir("ehci", usb_debug_root);
- if (!ehci_debug_root) {
- retval = -ENOENT;
- goto err_debug;
- }
#endif
#ifdef PLATFORM_DRIVER
@@ -1361,7 +1357,6 @@ clean0:
#ifdef CONFIG_DYNAMIC_DEBUG
debugfs_remove(ehci_debug_root);
ehci_debug_root = NULL;
-err_debug:
#endif
clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
return retval;
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 8d8bafc..7e4c1334 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -157,10 +157,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
struct usb_phy *phy;
/* get the PHY device */
- if (dev->of_node)
- phy = devm_usb_get_phy_by_phandle(dev, "phys", i);
- else
- phy = devm_usb_get_phy_dev(dev, i);
+ phy = devm_usb_get_phy_by_phandle(dev, "phys", i);
if (IS_ERR(phy)) {
/* Don't bail out if PHY is not absolutely necessary */
if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY)
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index a6f4389..4d2cdec 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -36,7 +36,6 @@
#define DRV_NAME "tegra-ehci"
static struct hc_driver __read_mostly tegra_ehci_hc_driver;
-static bool usb1_reset_attempted;
struct tegra_ehci_soc_config {
bool has_hostpc;
@@ -51,67 +50,54 @@ struct tegra_ehci_hcd {
enum tegra_usb_phy_port_speed port_speed;
};
-/*
- * The 1st USB controller contains some UTMI pad registers that are global for
- * all the controllers on the chip. Those registers are also cleared when
- * reset is asserted to the 1st controller. This means that the 1st controller
- * can only be reset when no other controlled has finished probing. So we'll
- * reset the 1st controller before doing any other setup on any of the
- * controllers, and then never again.
- *
- * Since this is a PHY issue, the Tegra PHY driver should probably be doing
- * the resetting of the USB controllers. But to keep compatibility with old
- * device trees that don't have reset phandles in the PHYs, do it here.
- * Those old DTs will be vulnerable to total USB breakage if the 1st EHCI
- * device isn't the first one to finish probing, so warn them.
- */
static int tegra_reset_usb_controller(struct platform_device *pdev)
{
struct device_node *phy_np;
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct tegra_ehci_hcd *tegra =
(struct tegra_ehci_hcd *)hcd_to_ehci(hcd)->priv;
- bool has_utmi_pad_registers = false;
+ struct reset_control *rst;
+ int err;
phy_np = of_parse_phandle(pdev->dev.of_node, "nvidia,phy", 0);
if (!phy_np)
return -ENOENT;
- if (of_property_read_bool(phy_np, "nvidia,has-utmi-pad-registers"))
- has_utmi_pad_registers = true;
+ /*
+ * The 1st USB controller contains some UTMI pad registers that are
+ * global for all the controllers on the chip. Those registers are
+ * also cleared when reset is asserted to the 1st controller.
+ */
+ rst = of_reset_control_get_shared(phy_np, "utmi-pads");
+ if (IS_ERR(rst)) {
+ dev_warn(&pdev->dev,
+ "can't get utmi-pads reset from the PHY\n");
+ dev_warn(&pdev->dev,
+ "continuing, but please update your DT\n");
+ } else {
+ /*
+ * PHY driver performs UTMI-pads reset in a case of
+ * non-legacy DT.
+ */
+ reset_control_put(rst);
+ }
- if (!usb1_reset_attempted) {
- struct reset_control *usb1_reset;
+ of_node_put(phy_np);
- if (!has_utmi_pad_registers)
- usb1_reset = of_reset_control_get(phy_np, "utmi-pads");
- else
- usb1_reset = tegra->rst;
-
- if (IS_ERR(usb1_reset)) {
- dev_warn(&pdev->dev,
- "can't get utmi-pads reset from the PHY\n");
- dev_warn(&pdev->dev,
- "continuing, but please update your DT\n");
- } else {
- reset_control_assert(usb1_reset);
- udelay(1);
- reset_control_deassert(usb1_reset);
-
- if (!has_utmi_pad_registers)
- reset_control_put(usb1_reset);
- }
+ /* reset control is shared, hence initialize it first */
+ err = reset_control_deassert(tegra->rst);
+ if (err)
+ return err;
- usb1_reset_attempted = true;
- }
+ err = reset_control_assert(tegra->rst);
+ if (err)
+ return err;
- if (!has_utmi_pad_registers) {
- reset_control_assert(tegra->rst);
- udelay(1);
- reset_control_deassert(tegra->rst);
- }
+ udelay(1);
- of_node_put(phy_np);
+ err = reset_control_deassert(tegra->rst);
+ if (err)
+ return err;
return 0;
}
@@ -440,7 +426,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
goto cleanup_hcd_create;
}
- tegra->rst = devm_reset_control_get(&pdev->dev, "usb");
+ tegra->rst = devm_reset_control_get_shared(&pdev->dev, "usb");
if (IS_ERR(tegra->rst)) {
dev_err(&pdev->dev, "Can't get ehci reset\n");
err = PTR_ERR(tegra->rst);
@@ -452,8 +438,10 @@ static int tegra_ehci_probe(struct platform_device *pdev)
goto cleanup_hcd_create;
err = tegra_reset_usb_controller(pdev);
- if (err)
+ if (err) {
+ dev_err(&pdev->dev, "Failed to reset controller\n");
goto cleanup_clk_en;
+ }
u_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0);
if (IS_ERR(u_phy)) {
@@ -538,6 +526,9 @@ static int tegra_ehci_remove(struct platform_device *pdev)
usb_phy_shutdown(hcd->usb_phy);
usb_remove_hcd(hcd);
+ reset_control_assert(tegra->rst);
+ udelay(1);
+
clk_disable_unprepare(tegra->clk);
usb_put_hcd(hcd);
diff --git a/drivers/usb/host/fhci-dbg.c b/drivers/usb/host/fhci-dbg.c
index ebf9bb2..100048b 100644
--- a/drivers/usb/host/fhci-dbg.c
+++ b/drivers/usb/host/fhci-dbg.c
@@ -83,27 +83,14 @@ void fhci_dfs_create(struct fhci_hcd *fhci)
struct device *dev = fhci_to_hcd(fhci)->self.controller;
fhci->dfs_root = debugfs_create_dir(dev_name(dev), usb_debug_root);
- if (!fhci->dfs_root) {
- WARN_ON(1);
- return;
- }
-
- fhci->dfs_regs = debugfs_create_file("regs", S_IFREG | S_IRUGO,
- fhci->dfs_root, fhci, &fhci_dfs_regs_fops);
- fhci->dfs_irq_stat = debugfs_create_file("irq_stat",
- S_IFREG | S_IRUGO, fhci->dfs_root, fhci,
- &fhci_dfs_irq_stat_fops);
-
- WARN_ON(!fhci->dfs_regs || !fhci->dfs_irq_stat);
+ debugfs_create_file("regs", S_IFREG | S_IRUGO, fhci->dfs_root, fhci,
+ &fhci_dfs_regs_fops);
+ debugfs_create_file("irq_stat", S_IFREG | S_IRUGO, fhci->dfs_root, fhci,
+ &fhci_dfs_irq_stat_fops);
}
void fhci_dfs_destroy(struct fhci_hcd *fhci)
{
- if (!fhci->dfs_root)
- return;
-
- debugfs_remove(fhci->dfs_irq_stat);
- debugfs_remove(fhci->dfs_regs);
- debugfs_remove(fhci->dfs_root);
+ debugfs_remove_recursive(fhci->dfs_root);
}
diff --git a/drivers/usb/host/fhci.h b/drivers/usb/host/fhci.h
index e7ec41d6..2ce5031 100644
--- a/drivers/usb/host/fhci.h
+++ b/drivers/usb/host/fhci.h
@@ -262,8 +262,6 @@ struct fhci_hcd {
#ifdef CONFIG_FHCI_DEBUG
int usb_irq_stat[13];
struct dentry *dfs_root;
- struct dentry *dfs_regs;
- struct dentry *dfs_irq_stat;
#endif
};
diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c
index d8abf40..e64eb47 100644
--- a/drivers/usb/host/fotg210-hcd.c
+++ b/drivers/usb/host/fotg210-hcd.c
@@ -844,28 +844,16 @@ static int debug_registers_open(struct inode *inode, struct file *file)
static inline void create_debug_files(struct fotg210_hcd *fotg210)
{
struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self;
+ struct dentry *root;
- fotg210->debug_dir = debugfs_create_dir(bus->bus_name,
- fotg210_debug_root);
- if (!fotg210->debug_dir)
- return;
-
- if (!debugfs_create_file("async", S_IRUGO, fotg210->debug_dir, bus,
- &debug_async_fops))
- goto file_error;
-
- if (!debugfs_create_file("periodic", S_IRUGO, fotg210->debug_dir, bus,
- &debug_periodic_fops))
- goto file_error;
+ root = debugfs_create_dir(bus->bus_name, fotg210_debug_root);
+ fotg210->debug_dir = root;
- if (!debugfs_create_file("registers", S_IRUGO, fotg210->debug_dir, bus,
- &debug_registers_fops))
- goto file_error;
-
- return;
-
-file_error:
- debugfs_remove_recursive(fotg210->debug_dir);
+ debugfs_create_file("async", S_IRUGO, root, bus, &debug_async_fops);
+ debugfs_create_file("periodic", S_IRUGO, root, bus,
+ &debug_periodic_fops);
+ debugfs_create_file("registers", S_IRUGO, root, bus,
+ &debug_registers_fops);
}
static inline void remove_debug_files(struct fotg210_hcd *fotg210)
@@ -5686,10 +5674,6 @@ static int __init fotg210_hcd_init(void)
sizeof(struct fotg210_itd));
fotg210_debug_root = debugfs_create_dir("fotg210", usb_debug_root);
- if (!fotg210_debug_root) {
- retval = -ENOENT;
- goto err_debug;
- }
retval = platform_driver_register(&fotg210_hcd_driver);
if (retval < 0)
@@ -5699,7 +5683,7 @@ static int __init fotg210_hcd_init(void)
clean:
debugfs_remove(fotg210_debug_root);
fotg210_debug_root = NULL;
-err_debug:
+
clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
return retval;
}
diff --git a/drivers/usb/host/imx21-dbg.c b/drivers/usb/host/imx21-dbg.c
index a213ed6..7fcf1d9 100644
--- a/drivers/usb/host/imx21-dbg.c
+++ b/drivers/usb/host/imx21-dbg.c
@@ -417,46 +417,22 @@ DEFINE_SHOW_ATTRIBUTE(debug_isoc);
static void create_debug_files(struct imx21 *imx21)
{
- imx21->debug_root = debugfs_create_dir(dev_name(imx21->dev), NULL);
- if (!imx21->debug_root)
- goto failed_create_rootdir;
+ struct dentry *root;
- if (!debugfs_create_file("status", S_IRUGO,
- imx21->debug_root, imx21, &debug_status_fops))
- goto failed_create;
+ root = debugfs_create_dir(dev_name(imx21->dev), NULL);
+ imx21->debug_root = root;
- if (!debugfs_create_file("dmem", S_IRUGO,
- imx21->debug_root, imx21, &debug_dmem_fops))
- goto failed_create;
-
- if (!debugfs_create_file("etd", S_IRUGO,
- imx21->debug_root, imx21, &debug_etd_fops))
- goto failed_create;
-
- if (!debugfs_create_file("statistics", S_IRUGO,
- imx21->debug_root, imx21, &debug_statistics_fops))
- goto failed_create;
-
- if (!debugfs_create_file("isoc", S_IRUGO,
- imx21->debug_root, imx21, &debug_isoc_fops))
- goto failed_create;
-
- return;
-
-failed_create:
- debugfs_remove_recursive(imx21->debug_root);
-
-failed_create_rootdir:
- imx21->debug_root = NULL;
+ debugfs_create_file("status", S_IRUGO, root, imx21, &debug_status_fops);
+ debugfs_create_file("dmem", S_IRUGO, root, imx21, &debug_dmem_fops);
+ debugfs_create_file("etd", S_IRUGO, root, imx21, &debug_etd_fops);
+ debugfs_create_file("statistics", S_IRUGO, root, imx21,
+ &debug_statistics_fops);
+ debugfs_create_file("isoc", S_IRUGO, root, imx21, &debug_isoc_fops);
}
-
static void remove_debug_files(struct imx21 *imx21)
{
- if (imx21->debug_root) {
- debugfs_remove_recursive(imx21->debug_root);
- imx21->debug_root = NULL;
- }
+ debugfs_remove_recursive(imx21->debug_root);
}
#endif
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 4602ed8..74da136 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -1198,14 +1198,11 @@ static int isp116x_debug_show(struct seq_file *s, void *unused)
}
DEFINE_SHOW_ATTRIBUTE(isp116x_debug);
-static int create_debug_file(struct isp116x *isp116x)
+static void create_debug_file(struct isp116x *isp116x)
{
isp116x->dentry = debugfs_create_file(hcd_name,
S_IRUGO, NULL, isp116x,
&isp116x_debug_fops);
- if (!isp116x->dentry)
- return -ENOMEM;
- return 0;
}
static void remove_debug_file(struct isp116x *isp116x)
@@ -1215,8 +1212,8 @@ static void remove_debug_file(struct isp116x *isp116x)
#else
-#define create_debug_file(d) 0
-#define remove_debug_file(d) do{}while(0)
+static inline void create_debug_file(struct isp116x *isp116x) { }
+static inline void remove_debug_file(struct isp116x *isp116x) { }
#endif /* CONFIG_DEBUG_FS */
@@ -1643,16 +1640,10 @@ static int isp116x_probe(struct platform_device *pdev)
device_wakeup_enable(hcd->self.controller);
- ret = create_debug_file(isp116x);
- if (ret) {
- ERR("Couldn't create debugfs entry\n");
- goto err7;
- }
+ create_debug_file(isp116x);
return 0;
- err7:
- usb_remove_hcd(hcd);
err6:
usb_put_hcd(hcd);
err5:
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 5ad9e9b..e986739 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -212,7 +212,7 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
ohci_at91->sfr_regmap = at91_dt_syscon_sfr();
if (!ohci_at91->sfr_regmap)
- dev_warn(dev, "failed to find sfr node\n");
+ dev_dbg(dev, "failed to find sfr node\n");
board = hcd->self.controller->platform_data;
ohci = hcd_to_ohci(hcd);
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index ac7d4ac..d3ee1f52a 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -762,50 +762,23 @@ static int debug_registers_open(struct inode *inode, struct file *file)
static inline void create_debug_files (struct ohci_hcd *ohci)
{
struct usb_bus *bus = &ohci_to_hcd(ohci)->self;
+ struct dentry *root;
- ohci->debug_dir = debugfs_create_dir(bus->bus_name, ohci_debug_root);
- if (!ohci->debug_dir)
- goto dir_error;
+ root = debugfs_create_dir(bus->bus_name, ohci_debug_root);
+ ohci->debug_dir = root;
- ohci->debug_async = debugfs_create_file("async", S_IRUGO,
- ohci->debug_dir, ohci,
- &debug_async_fops);
- if (!ohci->debug_async)
- goto async_error;
-
- ohci->debug_periodic = debugfs_create_file("periodic", S_IRUGO,
- ohci->debug_dir, ohci,
- &debug_periodic_fops);
- if (!ohci->debug_periodic)
- goto periodic_error;
-
- ohci->debug_registers = debugfs_create_file("registers", S_IRUGO,
- ohci->debug_dir, ohci,
- &debug_registers_fops);
- if (!ohci->debug_registers)
- goto registers_error;
+ debugfs_create_file("async", S_IRUGO, root, ohci, &debug_async_fops);
+ debugfs_create_file("periodic", S_IRUGO, root, ohci,
+ &debug_periodic_fops);
+ debugfs_create_file("registers", S_IRUGO, root, ohci,
+ &debug_registers_fops);
ohci_dbg (ohci, "created debug files\n");
- return;
-
-registers_error:
- debugfs_remove(ohci->debug_periodic);
-periodic_error:
- debugfs_remove(ohci->debug_async);
-async_error:
- debugfs_remove(ohci->debug_dir);
-dir_error:
- ohci->debug_periodic = NULL;
- ohci->debug_async = NULL;
- ohci->debug_dir = NULL;
}
static inline void remove_debug_files (struct ohci_hcd *ohci)
{
- debugfs_remove(ohci->debug_registers);
- debugfs_remove(ohci->debug_periodic);
- debugfs_remove(ohci->debug_async);
- debugfs_remove(ohci->debug_dir);
+ debugfs_remove_recursive(ohci->debug_dir);
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 4806e0f..210181f 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1258,10 +1258,6 @@ static int __init ohci_hcd_mod_init(void)
set_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
ohci_debug_root = debugfs_create_dir("ohci", usb_debug_root);
- if (!ohci_debug_root) {
- retval = -ENOENT;
- goto error_debug;
- }
#ifdef PS3_SYSTEM_BUS_DRIVER
retval = ps3_ohci_driver_register(&PS3_SYSTEM_BUS_DRIVER);
@@ -1318,7 +1314,6 @@ static int __init ohci_hcd_mod_init(void)
#endif
debugfs_remove(ohci_debug_root);
ohci_debug_root = NULL;
- error_debug:
clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
return retval;
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 508a803..ef4813b 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -431,9 +431,6 @@ struct ohci_hcd {
struct work_struct nec_work; /* Worker for NEC quirk */
struct dentry *debug_dir;
- struct dentry *debug_async;
- struct dentry *debug_periodic;
- struct dentry *debug_registers;
/* platform-specific data -- must come last */
unsigned long priv[0] __aligned(sizeof(s64));
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 67ad4bb..3625a5c 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -1268,23 +1268,3 @@ static void quirk_usb_early_handoff(struct pci_dev *pdev)
}
DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff);
-
-bool usb_xhci_needs_pci_reset(struct pci_dev *pdev)
-{
- /*
- * Our dear uPD72020{1,2} friend only partially resets when
- * asked to via the XHCI interface, and may end up doing DMA
- * at the wrong addresses, as it keeps the top 32bit of some
- * addresses from its previous programming under obscure
- * circumstances.
- * Give it a good wack at probe time. Unfortunately, this
- * needs to happen before we've had a chance to discover any
- * quirk, or the system will be in a rather bad state.
- */
- if (pdev->vendor == PCI_VENDOR_ID_RENESAS &&
- (pdev->device == 0x0014 || pdev->device == 0x0015))
- return true;
-
- return false;
-}
-EXPORT_SYMBOL_GPL(usb_xhci_needs_pci_reset);
diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h
index 4ca0d9b..63c63307 100644
--- a/drivers/usb/host/pci-quirks.h
+++ b/drivers/usb/host/pci-quirks.h
@@ -16,7 +16,6 @@ void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev);
void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev);
void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
void sb800_prefetch(struct device *dev, int on);
-bool usb_xhci_needs_pci_reset(struct pci_dev *pdev);
bool usb_amd_pt_check_port(struct device *device, int port);
#else
struct pci_dev;
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index f9c3947..6218bfe 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -590,14 +590,10 @@ static int uhci_start(struct usb_hcd *hcd)
init_waitqueue_head(&uhci->waitqh);
#ifdef UHCI_DEBUG_OPS
- dentry = debugfs_create_file(hcd->self.bus_name,
- S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root,
- uhci, &uhci_debug_operations);
- if (!dentry) {
- dev_err(uhci_dev(uhci), "couldn't create uhci debugfs entry\n");
- return -ENOMEM;
- }
- uhci->dentry = dentry;
+ uhci->dentry = debugfs_create_file(hcd->self.bus_name,
+ S_IFREG|S_IRUGO|S_IWUSR,
+ uhci_debugfs_root, uhci,
+ &uhci_debug_operations);
#endif
uhci->frame = dma_zalloc_coherent(uhci_dev(uhci),
@@ -882,8 +878,6 @@ static int __init uhci_hcd_init(void)
if (!errbuf)
goto errbuf_failed;
uhci_debugfs_root = debugfs_create_dir("uhci", usb_debug_root);
- if (!uhci_debugfs_root)
- goto debug_failed;
#endif
uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
@@ -918,7 +912,6 @@ up_failed:
#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
debugfs_remove(uhci_debugfs_root);
-debug_failed:
kfree(errbuf);
errbuf_failed:
diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c
index c359bae..1fbfd89 100644
--- a/drivers/usb/host/xhci-dbgcap.c
+++ b/drivers/usb/host/xhci-dbgcap.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/**
* xhci-dbgcap.c - xHCI debug capability support
*
diff --git a/drivers/usb/host/xhci-dbgcap.h b/drivers/usb/host/xhci-dbgcap.h
index e66ea07..ce0c607 100644
--- a/drivers/usb/host/xhci-dbgcap.h
+++ b/drivers/usb/host/xhci-dbgcap.h
@@ -1,4 +1,4 @@
-
+/* SPDX-License-Identifier: GPL-2.0 */
/**
* xhci-dbgcap.h - xHCI debug capability support
*
diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c
index eb494ec5..aff79ff 100644
--- a/drivers/usb/host/xhci-dbgtty.c
+++ b/drivers/usb/host/xhci-dbgtty.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/**
* xhci-dbgtty.c - tty glue for xHCI debug capability
*
diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
index 5851052..cadc013 100644
--- a/drivers/usb/host/xhci-debugfs.c
+++ b/drivers/usb/host/xhci-debugfs.c
@@ -8,6 +8,7 @@
*/
#include <linux/slab.h>
+#include <linux/uaccess.h>
#include "xhci.h"
#include "xhci-debugfs.h"
@@ -333,6 +334,67 @@ static const struct file_operations xhci_context_fops = {
.release = single_release,
};
+
+
+static int xhci_portsc_show(struct seq_file *s, void *unused)
+{
+ struct xhci_port *port = s->private;
+ u32 portsc;
+
+ portsc = readl(port->addr);
+ seq_printf(s, "%s\n", xhci_decode_portsc(portsc));
+
+ return 0;
+}
+
+static int xhci_port_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, xhci_portsc_show, inode->i_private);
+}
+
+static ssize_t xhci_port_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct seq_file *s = file->private_data;
+ struct xhci_port *port = s->private;
+ struct xhci_hcd *xhci = hcd_to_xhci(port->rhub->hcd);
+ char buf[32];
+ u32 portsc;
+ unsigned long flags;
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ if (!strncmp(buf, "compliance", 10)) {
+ /* If CTC is clear, compliance is enabled by default */
+ if (!HCC2_CTC(xhci->hcc_params2))
+ return count;
+ spin_lock_irqsave(&xhci->lock, flags);
+ /* compliance mode can only be enabled on ports in RxDetect */
+ portsc = readl(port->addr);
+ if ((portsc & PORT_PLS_MASK) != XDEV_RXDETECT) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ return -EPERM;
+ }
+ portsc = xhci_port_state_to_neutral(portsc);
+ portsc &= ~PORT_PLS_MASK;
+ portsc |= PORT_LINK_STROBE | XDEV_COMP_MODE;
+ writel(portsc, port->addr);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ } else {
+ return -EINVAL;
+ }
+ return count;
+}
+
+static const struct file_operations port_fops = {
+ .open = xhci_port_open,
+ .write = xhci_port_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static void xhci_debugfs_create_files(struct xhci_hcd *xhci,
struct xhci_file_map *files,
size_t nentries, void *data,
@@ -449,6 +511,27 @@ void xhci_debugfs_remove_slot(struct xhci_hcd *xhci, int slot_id)
dev->debugfs_private = NULL;
}
+static void xhci_debugfs_create_ports(struct xhci_hcd *xhci,
+ struct dentry *parent)
+{
+ unsigned int num_ports;
+ char port_name[8];
+ struct xhci_port *port;
+ struct dentry *dir;
+
+ num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
+
+ parent = debugfs_create_dir("ports", parent);
+
+ while (num_ports--) {
+ scnprintf(port_name, sizeof(port_name), "port%02d",
+ num_ports + 1);
+ dir = debugfs_create_dir(port_name, parent);
+ port = &xhci->hw_ports[num_ports];
+ debugfs_create_file("portsc", 0644, dir, port, &port_fops);
+ }
+}
+
void xhci_debugfs_init(struct xhci_hcd *xhci)
{
struct device *dev = xhci_to_hcd(xhci)->self.controller;
@@ -497,6 +580,8 @@ void xhci_debugfs_init(struct xhci_hcd *xhci)
xhci->debugfs_root);
xhci->debugfs_slots = debugfs_create_dir("devices", xhci->debugfs_root);
+
+ xhci_debugfs_create_ports(xhci, xhci->debugfs_root);
}
void xhci_debugfs_exit(struct xhci_hcd *xhci)
diff --git a/drivers/usb/host/xhci-histb.c b/drivers/usb/host/xhci-histb.c
new file mode 100644
index 0000000..27f0016
--- /dev/null
+++ b/drivers/usb/host/xhci-histb.c
@@ -0,0 +1,410 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * xHCI host controller driver for HiSilicon STB SoCs
+ *
+ * Copyright (C) 2017-2018 HiSilicon Co., Ltd. http://www.hisilicon.com
+ *
+ * Authors: Jianguo Sun <sunjianguo1@huawei.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include "xhci.h"
+
+#define GTXTHRCFG 0xc108
+#define GRXTHRCFG 0xc10c
+#define REG_GUSB2PHYCFG0 0xc200
+#define BIT_UTMI_8_16 BIT(3)
+#define BIT_UTMI_ULPI BIT(4)
+#define BIT_FREECLK_EXIST BIT(30)
+
+#define REG_GUSB3PIPECTL0 0xc2c0
+#define USB3_DEEMPHASIS_MASK GENMASK(2, 1)
+#define USB3_DEEMPHASIS0 BIT(1)
+#define USB3_TX_MARGIN1 BIT(4)
+
+struct xhci_hcd_histb {
+ struct device *dev;
+ struct usb_hcd *hcd;
+ void __iomem *ctrl;
+ struct clk *bus_clk;
+ struct clk *utmi_clk;
+ struct clk *pipe_clk;
+ struct clk *suspend_clk;
+ struct reset_control *soft_reset;
+};
+
+static inline struct xhci_hcd_histb *hcd_to_histb(struct usb_hcd *hcd)
+{
+ return dev_get_drvdata(hcd->self.controller);
+}
+
+static int xhci_histb_config(struct xhci_hcd_histb *histb)
+{
+ struct device_node *np = histb->dev->of_node;
+ u32 regval;
+
+ if (of_property_match_string(np, "phys-names", "inno") >= 0) {
+ /* USB2 PHY chose ulpi 8bit interface */
+ regval = readl(histb->ctrl + REG_GUSB2PHYCFG0);
+ regval &= ~BIT_UTMI_ULPI;
+ regval &= ~(BIT_UTMI_8_16);
+ regval &= ~BIT_FREECLK_EXIST;
+ writel(regval, histb->ctrl + REG_GUSB2PHYCFG0);
+ }
+
+ if (of_property_match_string(np, "phys-names", "combo") >= 0) {
+ /*
+ * write 0x010c0012 to GUSB3PIPECTL0
+ * GUSB3PIPECTL0[5:3] = 010 : Tx Margin = 900mV ,
+ * decrease TX voltage
+ * GUSB3PIPECTL0[2:1] = 01 : Tx Deemphasis = -3.5dB,
+ * refer to xHCI spec
+ */
+ regval = readl(histb->ctrl + REG_GUSB3PIPECTL0);
+ regval &= ~USB3_DEEMPHASIS_MASK;
+ regval |= USB3_DEEMPHASIS0;
+ regval |= USB3_TX_MARGIN1;
+ writel(regval, histb->ctrl + REG_GUSB3PIPECTL0);
+ }
+
+ writel(0x23100000, histb->ctrl + GTXTHRCFG);
+ writel(0x23100000, histb->ctrl + GRXTHRCFG);
+
+ return 0;
+}
+
+static int xhci_histb_clks_get(struct xhci_hcd_histb *histb)
+{
+ struct device *dev = histb->dev;
+
+ histb->bus_clk = devm_clk_get(dev, "bus");
+ if (IS_ERR(histb->bus_clk)) {
+ dev_err(dev, "fail to get bus clk\n");
+ return PTR_ERR(histb->bus_clk);
+ }
+
+ histb->utmi_clk = devm_clk_get(dev, "utmi");
+ if (IS_ERR(histb->utmi_clk)) {
+ dev_err(dev, "fail to get utmi clk\n");
+ return PTR_ERR(histb->utmi_clk);
+ }
+
+ histb->pipe_clk = devm_clk_get(dev, "pipe");
+ if (IS_ERR(histb->pipe_clk)) {
+ dev_err(dev, "fail to get pipe clk\n");
+ return PTR_ERR(histb->pipe_clk);
+ }
+
+ histb->suspend_clk = devm_clk_get(dev, "suspend");
+ if (IS_ERR(histb->suspend_clk)) {
+ dev_err(dev, "fail to get suspend clk\n");
+ return PTR_ERR(histb->suspend_clk);
+ }
+
+ return 0;
+}
+
+static int xhci_histb_host_enable(struct xhci_hcd_histb *histb)
+{
+ int ret;
+
+ ret = clk_prepare_enable(histb->bus_clk);
+ if (ret) {
+ dev_err(histb->dev, "failed to enable bus clk\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(histb->utmi_clk);
+ if (ret) {
+ dev_err(histb->dev, "failed to enable utmi clk\n");
+ goto err_utmi_clk;
+ }
+
+ ret = clk_prepare_enable(histb->pipe_clk);
+ if (ret) {
+ dev_err(histb->dev, "failed to enable pipe clk\n");
+ goto err_pipe_clk;
+ }
+
+ ret = clk_prepare_enable(histb->suspend_clk);
+ if (ret) {
+ dev_err(histb->dev, "failed to enable suspend clk\n");
+ goto err_suspend_clk;
+ }
+
+ reset_control_deassert(histb->soft_reset);
+
+ return 0;
+
+err_suspend_clk:
+ clk_disable_unprepare(histb->pipe_clk);
+err_pipe_clk:
+ clk_disable_unprepare(histb->utmi_clk);
+err_utmi_clk:
+ clk_disable_unprepare(histb->bus_clk);
+
+ return ret;
+}
+
+static void xhci_histb_host_disable(struct xhci_hcd_histb *histb)
+{
+ reset_control_assert(histb->soft_reset);
+
+ clk_disable_unprepare(histb->suspend_clk);
+ clk_disable_unprepare(histb->pipe_clk);
+ clk_disable_unprepare(histb->utmi_clk);
+ clk_disable_unprepare(histb->bus_clk);
+}
+
+static void xhci_histb_quirks(struct device *dev, struct xhci_hcd *xhci)
+{
+ /*
+ * As of now platform drivers don't provide MSI support so we ensure
+ * here that the generic code does not try to make a pci_dev from our
+ * dev struct in order to setup MSI
+ */
+ xhci->quirks |= XHCI_PLAT;
+}
+
+/* called during probe() after chip reset completes */
+static int xhci_histb_setup(struct usb_hcd *hcd)
+{
+ struct xhci_hcd_histb *histb = hcd_to_histb(hcd);
+ int ret;
+
+ if (usb_hcd_is_primary_hcd(hcd)) {
+ ret = xhci_histb_config(histb);
+ if (ret)
+ return ret;
+ }
+
+ return xhci_gen_setup(hcd, xhci_histb_quirks);
+}
+
+static const struct xhci_driver_overrides xhci_histb_overrides __initconst = {
+ .reset = xhci_histb_setup,
+};
+
+static struct hc_driver __read_mostly xhci_histb_hc_driver;
+static int xhci_histb_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct xhci_hcd_histb *histb;
+ const struct hc_driver *driver;
+ struct usb_hcd *hcd;
+ struct xhci_hcd *xhci;
+ struct resource *res;
+ int irq;
+ int ret = -ENODEV;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ driver = &xhci_histb_hc_driver;
+ histb = devm_kzalloc(dev, sizeof(*histb), GFP_KERNEL);
+ if (!histb)
+ return -ENOMEM;
+
+ histb->dev = dev;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ histb->ctrl = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(histb->ctrl))
+ return PTR_ERR(histb->ctrl);
+
+ ret = xhci_histb_clks_get(histb);
+ if (ret)
+ return ret;
+
+ histb->soft_reset = devm_reset_control_get(dev, "soft");
+ if (IS_ERR(histb->soft_reset)) {
+ dev_err(dev, "failed to get soft reset\n");
+ return PTR_ERR(histb->soft_reset);
+ }
+
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+ device_enable_async_suspend(dev);
+
+ /* Initialize dma_mask and coherent_dma_mask to 32-bits */
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ hcd = usb_create_hcd(driver, dev, dev_name(dev));
+ if (!hcd) {
+ ret = -ENOMEM;
+ goto disable_pm;
+ }
+
+ hcd->regs = histb->ctrl;
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+
+ histb->hcd = hcd;
+ dev_set_drvdata(hcd->self.controller, histb);
+
+ ret = xhci_histb_host_enable(histb);
+ if (ret)
+ goto put_hcd;
+
+ xhci = hcd_to_xhci(hcd);
+
+ device_wakeup_enable(hcd->self.controller);
+
+ xhci->main_hcd = hcd;
+ xhci->shared_hcd = usb_create_shared_hcd(driver, dev, dev_name(dev),
+ hcd);
+ if (!xhci->shared_hcd) {
+ ret = -ENOMEM;
+ goto disable_host;
+ }
+
+ if (device_property_read_bool(dev, "usb2-lpm-disable"))
+ xhci->quirks |= XHCI_HW_LPM_DISABLE;
+
+ if (device_property_read_bool(dev, "usb3-lpm-capable"))
+ xhci->quirks |= XHCI_LPM_SUPPORT;
+
+ /* imod_interval is the interrupt moderation value in nanoseconds. */
+ xhci->imod_interval = 40000;
+ device_property_read_u32(dev, "imod-interval-ns",
+ &xhci->imod_interval);
+
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ if (ret)
+ goto put_usb3_hcd;
+
+ if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
+ xhci->shared_hcd->can_do_streams = 1;
+
+ ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+ if (ret)
+ goto dealloc_usb2_hcd;
+
+ device_enable_async_suspend(dev);
+ pm_runtime_put_noidle(dev);
+
+ /*
+ * Prevent runtime pm from being on as default, users should enable
+ * runtime pm using power/control in sysfs.
+ */
+ pm_runtime_forbid(dev);
+
+ return 0;
+
+dealloc_usb2_hcd:
+ usb_remove_hcd(hcd);
+put_usb3_hcd:
+ usb_put_hcd(xhci->shared_hcd);
+disable_host:
+ xhci_histb_host_disable(histb);
+put_hcd:
+ usb_put_hcd(hcd);
+disable_pm:
+ pm_runtime_put_sync(dev);
+ pm_runtime_disable(dev);
+
+ return ret;
+}
+
+static int xhci_histb_remove(struct platform_device *dev)
+{
+ struct xhci_hcd_histb *histb = platform_get_drvdata(dev);
+ struct usb_hcd *hcd = histb->hcd;
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+ xhci->xhc_state |= XHCI_STATE_REMOVING;
+
+ usb_remove_hcd(xhci->shared_hcd);
+ device_wakeup_disable(&dev->dev);
+
+ usb_remove_hcd(hcd);
+ usb_put_hcd(xhci->shared_hcd);
+
+ xhci_histb_host_disable(histb);
+ usb_put_hcd(hcd);
+ pm_runtime_put_sync(&dev->dev);
+ pm_runtime_disable(&dev->dev);
+
+ return 0;
+}
+
+static int __maybe_unused xhci_histb_suspend(struct device *dev)
+{
+ struct xhci_hcd_histb *histb = dev_get_drvdata(dev);
+ struct usb_hcd *hcd = histb->hcd;
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ int ret;
+
+ ret = xhci_suspend(xhci, device_may_wakeup(dev));
+
+ if (!device_may_wakeup(dev))
+ xhci_histb_host_disable(histb);
+
+ return ret;
+}
+
+static int __maybe_unused xhci_histb_resume(struct device *dev)
+{
+ struct xhci_hcd_histb *histb = dev_get_drvdata(dev);
+ struct usb_hcd *hcd = histb->hcd;
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+ if (!device_may_wakeup(dev))
+ xhci_histb_host_enable(histb);
+
+ return xhci_resume(xhci, 0);
+}
+
+static const struct dev_pm_ops xhci_histb_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(xhci_histb_suspend, xhci_histb_resume)
+};
+#define DEV_PM_OPS (IS_ENABLED(CONFIG_PM) ? &xhci_histb_pm_ops : NULL)
+
+#ifdef CONFIG_OF
+static const struct of_device_id histb_xhci_of_match[] = {
+ { .compatible = "hisilicon,hi3798cv200-xhci"},
+ { },
+};
+MODULE_DEVICE_TABLE(of, histb_xhci_of_match);
+#endif
+
+static struct platform_driver histb_xhci_driver = {
+ .probe = xhci_histb_probe,
+ .remove = xhci_histb_remove,
+ .driver = {
+ .name = "xhci-histb",
+ .pm = DEV_PM_OPS,
+ .of_match_table = of_match_ptr(histb_xhci_of_match),
+ },
+};
+MODULE_ALIAS("platform:xhci-histb");
+
+static int __init xhci_histb_init(void)
+{
+ xhci_init_driver(&xhci_histb_hc_driver, &xhci_histb_overrides);
+ return platform_driver_register(&histb_xhci_driver);
+}
+module_init(xhci_histb_init);
+
+static void __exit xhci_histb_exit(void)
+{
+ platform_driver_unregister(&histb_xhci_driver);
+}
+module_exit(xhci_histb_exit);
+
+MODULE_DESCRIPTION("HiSilicon STB xHCI Host Controller Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 32cd52c..a4b95d0 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -189,9 +189,10 @@ static void xhci_usb2_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
__u8 port_removable[(USB_MAXCHILDREN + 1 + 7) / 8];
u32 portsc;
unsigned int i;
+ struct xhci_hub *rhub;
- ports = xhci->num_usb2_ports;
-
+ rhub = &xhci->usb2_rhub;
+ ports = rhub->num_ports;
xhci_common_hub_descriptor(xhci, desc, ports);
desc->bDescriptorType = USB_DT_HUB;
temp = 1 + (ports / 8);
@@ -202,7 +203,7 @@ static void xhci_usb2_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
*/
memset(port_removable, 0, sizeof(port_removable));
for (i = 0; i < ports; i++) {
- portsc = readl(xhci->usb2_ports[i]);
+ portsc = readl(rhub->ports[i]->addr);
/* If a device is removable, PORTSC reports a 0, same as in the
* hub descriptor DeviceRemovable bits.
*/
@@ -241,8 +242,10 @@ static void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
u16 port_removable;
u32 portsc;
unsigned int i;
+ struct xhci_hub *rhub;
- ports = xhci->num_usb3_ports;
+ rhub = &xhci->usb3_rhub;
+ ports = rhub->num_ports;
xhci_common_hub_descriptor(xhci, desc, ports);
desc->bDescriptorType = USB_DT_SS_HUB;
desc->bDescLength = USB_DT_SS_HUB_SIZE;
@@ -256,7 +259,7 @@ static void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
port_removable = 0;
/* bit 0 is reserved, bit 1 is for port 1, etc. */
for (i = 0; i < ports; i++) {
- portsc = readl(xhci->usb3_ports[i]);
+ portsc = readl(rhub->ports[i]->addr);
if (portsc & PORT_DEV_REMOVE)
port_removable |= 1 << (i + 1);
}
@@ -538,28 +541,13 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
port_change_bit, wIndex, port_status);
}
-static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array)
+struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd)
{
- int max_ports;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- if (hcd->speed >= HCD_USB3) {
- max_ports = xhci->num_usb3_ports;
- *port_array = xhci->usb3_ports;
- } else {
- max_ports = xhci->num_usb2_ports;
- *port_array = xhci->usb2_ports;
- }
-
- return max_ports;
-}
-
-static __le32 __iomem *xhci_get_port_io_addr(struct usb_hcd *hcd, int index)
-{
- __le32 __iomem **port_array;
-
- xhci_get_ports(hcd, &port_array);
- return port_array[index];
+ if (hcd->speed >= HCD_USB3)
+ return &xhci->usb3_rhub;
+ return &xhci->usb2_rhub;
}
/*
@@ -570,21 +558,23 @@ static __le32 __iomem *xhci_get_port_io_addr(struct usb_hcd *hcd, int index)
static void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd,
u16 index, bool on, unsigned long *flags)
{
- __le32 __iomem *addr;
+ struct xhci_hub *rhub;
+ struct xhci_port *port;
u32 temp;
- addr = xhci_get_port_io_addr(hcd, index);
- temp = readl(addr);
+ rhub = xhci_get_rhub(hcd);
+ port = rhub->ports[index];
+ temp = readl(port->addr);
temp = xhci_port_state_to_neutral(temp);
if (on) {
/* Power on */
- writel(temp | PORT_POWER, addr);
- temp = readl(addr);
+ writel(temp | PORT_POWER, port->addr);
+ temp = readl(port->addr);
xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n",
index, temp);
} else {
/* Power off */
- writel(temp & ~PORT_POWER, addr);
+ writel(temp & ~PORT_POWER, port->addr);
}
spin_unlock_irqrestore(&xhci->lock, *flags);
@@ -600,13 +590,13 @@ static void xhci_port_set_test_mode(struct xhci_hcd *xhci,
u16 test_mode, u16 wIndex)
{
u32 temp;
- __le32 __iomem *addr;
+ struct xhci_port *port;
- /* xhci only supports test mode for usb2 ports, i.e. xhci->main_hcd */
- addr = xhci_get_port_io_addr(xhci->main_hcd, wIndex);
- temp = readl(addr + PORTPMSC);
+ /* xhci only supports test mode for usb2 ports */
+ port = xhci->usb2_rhub.ports[wIndex];
+ temp = readl(port->addr + PORTPMSC);
temp |= test_mode << PORT_TEST_MODE_SHIFT;
- writel(temp, addr + PORTPMSC);
+ writel(temp, port->addr + PORTPMSC);
xhci->test_mode = test_mode;
if (test_mode == TEST_FORCE_EN)
xhci_start(xhci);
@@ -633,10 +623,10 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci,
/* Put all ports to the Disable state by clear PP */
xhci_dbg(xhci, "Disable all port (PP = 0)\n");
/* Power off USB3 ports*/
- for (i = 0; i < xhci->num_usb3_ports; i++)
+ for (i = 0; i < xhci->usb3_rhub.num_ports; i++)
xhci_set_port_power(xhci, xhci->shared_hcd, i, false, flags);
/* Power off USB2 ports*/
- for (i = 0; i < xhci->num_usb2_ports; i++)
+ for (i = 0; i < xhci->usb2_rhub.num_ports; i++)
xhci_set_port_power(xhci, xhci->main_hcd, i, false, flags);
/* Stop the controller */
xhci_dbg(xhci, "Stop controller\n");
@@ -672,24 +662,24 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci)
return xhci_reset(xhci);
}
-void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
- int port_id, u32 link_state)
+void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,
+ u32 link_state)
{
u32 temp;
- temp = readl(port_array[port_id]);
+ temp = readl(port->addr);
temp = xhci_port_state_to_neutral(temp);
temp &= ~PORT_PLS_MASK;
temp |= PORT_LINK_STROBE | link_state;
- writel(temp, port_array[port_id]);
+ writel(temp, port->addr);
}
static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
- __le32 __iomem **port_array, int port_id, u16 wake_mask)
+ struct xhci_port *port, u16 wake_mask)
{
u32 temp;
- temp = readl(port_array[port_id]);
+ temp = readl(port->addr);
temp = xhci_port_state_to_neutral(temp);
if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_CONNECT)
@@ -707,20 +697,20 @@ static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
else
temp &= ~PORT_WKOC_E;
- writel(temp, port_array[port_id]);
+ writel(temp, port->addr);
}
/* Test and clear port RWC bit */
-void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
- int port_id, u32 port_bit)
+void xhci_test_and_clear_bit(struct xhci_hcd *xhci, struct xhci_port *port,
+ u32 port_bit)
{
u32 temp;
- temp = readl(port_array[port_id]);
+ temp = readl(port->addr);
if (temp & port_bit) {
temp = xhci_port_state_to_neutral(temp);
temp |= port_bit;
- writel(temp, port_array[port_id]);
+ writel(temp, port->addr);
}
}
@@ -794,7 +784,7 @@ static void xhci_hub_report_usb3_link_state(struct xhci_hcd *xhci,
static void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status,
u16 wIndex)
{
- u32 all_ports_seen_u0 = ((1 << xhci->num_usb3_ports)-1);
+ u32 all_ports_seen_u0 = ((1 << xhci->usb3_rhub.num_ports) - 1);
bool port_in_u0 = ((status & PORT_PLS_MASK) == XDEV_U0);
if (!(xhci->quirks & XHCI_COMP_MODE_QUIRK))
@@ -840,8 +830,7 @@ static u32 xhci_get_ext_port_status(u32 raw_port_status, u32 port_li)
*/
static u32 xhci_get_port_status(struct usb_hcd *hcd,
struct xhci_bus_state *bus_state,
- __le32 __iomem **port_array,
- u16 wIndex, u32 raw_port_status,
+ u16 wIndex, u32 raw_port_status,
unsigned long flags)
__releases(&xhci->lock)
__acquires(&xhci->lock)
@@ -849,6 +838,11 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
u32 status = 0;
int slot_id;
+ struct xhci_hub *rhub;
+ struct xhci_port *port;
+
+ rhub = xhci_get_rhub(hcd);
+ port = rhub->ports[wIndex];
/* wPortChange bits */
if (raw_port_status & PORT_CSC)
@@ -919,10 +913,8 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
set_bit(wIndex, &bus_state->rexit_ports);
- xhci_test_and_clear_bit(xhci, port_array, wIndex,
- PORT_PLC);
- xhci_set_link_state(xhci, port_array, wIndex,
- XDEV_U0);
+ xhci_test_and_clear_bit(xhci, port, PORT_PLC);
+ xhci_set_link_state(xhci, port, XDEV_U0);
spin_unlock_irqrestore(&xhci->lock, flags);
time_left = wait_for_completion_timeout(
@@ -940,7 +932,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
}
xhci_ring_device(xhci, slot_id);
} else {
- int port_status = readl(port_array[wIndex]);
+ int port_status = readl(port->addr);
xhci_warn(xhci, "Port resume took longer than %i msec, port status = 0x%x\n",
XHCI_MAX_REXIT_TIMEOUT,
port_status);
@@ -1024,15 +1016,18 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
unsigned long flags;
u32 temp, status;
int retval = 0;
- __le32 __iomem **port_array;
int slot_id;
struct xhci_bus_state *bus_state;
u16 link_state = 0;
u16 wake_mask = 0;
u16 timeout = 0;
u16 test_mode = 0;
+ struct xhci_hub *rhub;
+ struct xhci_port **ports;
- max_ports = xhci_get_ports(hcd, &port_array);
+ rhub = xhci_get_rhub(hcd);
+ ports = rhub->ports;
+ max_ports = rhub->num_ports;
bus_state = &xhci->bus_state[hcd_index(hcd)];
spin_lock_irqsave(&xhci->lock, flags);
@@ -1070,15 +1065,15 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
if (!wIndex || wIndex > max_ports)
goto error;
wIndex--;
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
if (temp == ~(u32)0) {
xhci_hc_died(xhci);
retval = -ENODEV;
break;
}
trace_xhci_get_port_status(wIndex, temp);
- status = xhci_get_port_status(hcd, bus_state, port_array,
- wIndex, temp, flags);
+ status = xhci_get_port_status(hcd, bus_state, wIndex, temp,
+ flags);
if (status == 0xffffffff)
goto error;
@@ -1096,7 +1091,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
retval = -EINVAL;
break;
}
- port_li = readl(port_array[wIndex] + PORTLI);
+ port_li = readl(ports[wIndex]->addr + PORTLI);
status = xhci_get_ext_port_status(temp, port_li);
put_unaligned_le32(cpu_to_le32(status), &buf[4]);
}
@@ -1114,7 +1109,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
if (!wIndex || wIndex > max_ports)
goto error;
wIndex--;
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
if (temp == ~(u32)0) {
xhci_hc_died(xhci);
retval = -ENODEV;
@@ -1124,10 +1119,10 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
/* FIXME: What new port features do we need to support? */
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
if ((temp & PORT_PLS_MASK) != XDEV_U0) {
/* Resume the port to U0 first */
- xhci_set_link_state(xhci, port_array, wIndex,
+ xhci_set_link_state(xhci, ports[wIndex],
XDEV_U0);
spin_unlock_irqrestore(&xhci->lock, flags);
msleep(10);
@@ -1137,7 +1132,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
* a port unless the port reports that it is in the
* enabled (PED = ‘1’,PLS < ‘3’) state.
*/
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
if ((temp & PORT_PE) == 0 || (temp & PORT_RESET)
|| (temp & PORT_PLS_MASK) >= XDEV_U3) {
xhci_warn(xhci, "USB core suspending device not in U0/U1/U2.\n");
@@ -1155,18 +1150,17 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_stop_device(xhci, slot_id, 1);
spin_lock_irqsave(&xhci->lock, flags);
- xhci_set_link_state(xhci, port_array, wIndex, XDEV_U3);
+ xhci_set_link_state(xhci, ports[wIndex], XDEV_U3);
spin_unlock_irqrestore(&xhci->lock, flags);
msleep(10); /* wait device to enter */
spin_lock_irqsave(&xhci->lock, flags);
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
bus_state->suspended_ports |= 1 << wIndex;
break;
case USB_PORT_FEAT_LINK_STATE:
- temp = readl(port_array[wIndex]);
-
+ temp = readl(ports[wIndex]->addr);
/* Disable port */
if (link_state == USB_SS_PORT_LS_SS_DISABLED) {
xhci_dbg(xhci, "Disable port %d\n", wIndex);
@@ -1178,17 +1172,17 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp |= PORT_CSC | PORT_PEC | PORT_WRC |
PORT_OCC | PORT_RC | PORT_PLC |
PORT_CEC;
- writel(temp | PORT_PE, port_array[wIndex]);
- temp = readl(port_array[wIndex]);
+ writel(temp | PORT_PE, ports[wIndex]->addr);
+ temp = readl(ports[wIndex]->addr);
break;
}
/* Put link in RxDetect (enable port) */
if (link_state == USB_SS_PORT_LS_RX_DETECT) {
xhci_dbg(xhci, "Enable port %d\n", wIndex);
- xhci_set_link_state(xhci, port_array, wIndex,
- link_state);
- temp = readl(port_array[wIndex]);
+ xhci_set_link_state(xhci, ports[wIndex],
+ link_state);
+ temp = readl(ports[wIndex]->addr);
break;
}
@@ -1219,9 +1213,10 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_dbg(xhci, "Enable compliance mode transition for port %d\n",
wIndex);
- xhci_set_link_state(xhci, port_array, wIndex,
+ xhci_set_link_state(xhci, ports[wIndex],
link_state);
- temp = readl(port_array[wIndex]);
+
+ temp = readl(ports[wIndex]->addr);
break;
}
/* Port must be enabled */
@@ -1248,14 +1243,13 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
}
}
- xhci_set_link_state(xhci, port_array, wIndex,
- link_state);
+ xhci_set_link_state(xhci, ports[wIndex], link_state);
spin_unlock_irqrestore(&xhci->lock, flags);
msleep(20); /* wait device to enter */
spin_lock_irqsave(&xhci->lock, flags);
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
if (link_state == USB_SS_PORT_LS_U3)
bus_state->suspended_ports |= 1 << wIndex;
break;
@@ -1270,40 +1264,39 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
break;
case USB_PORT_FEAT_RESET:
temp = (temp | PORT_RESET);
- writel(temp, port_array[wIndex]);
+ writel(temp, ports[wIndex]->addr);
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp);
break;
case USB_PORT_FEAT_REMOTE_WAKE_MASK:
- xhci_set_remote_wake_mask(xhci, port_array,
- wIndex, wake_mask);
- temp = readl(port_array[wIndex]);
+ xhci_set_remote_wake_mask(xhci, ports[wIndex],
+ wake_mask);
+ temp = readl(ports[wIndex]->addr);
xhci_dbg(xhci, "set port remote wake mask, "
"actual port %d status = 0x%x\n",
wIndex, temp);
break;
case USB_PORT_FEAT_BH_PORT_RESET:
temp |= PORT_WR;
- writel(temp, port_array[wIndex]);
-
- temp = readl(port_array[wIndex]);
+ writel(temp, ports[wIndex]->addr);
+ temp = readl(ports[wIndex]->addr);
break;
case USB_PORT_FEAT_U1_TIMEOUT:
if (hcd->speed < HCD_USB3)
goto error;
- temp = readl(port_array[wIndex] + PORTPMSC);
+ temp = readl(ports[wIndex]->addr + PORTPMSC);
temp &= ~PORT_U1_TIMEOUT_MASK;
temp |= PORT_U1_TIMEOUT(timeout);
- writel(temp, port_array[wIndex] + PORTPMSC);
+ writel(temp, ports[wIndex]->addr + PORTPMSC);
break;
case USB_PORT_FEAT_U2_TIMEOUT:
if (hcd->speed < HCD_USB3)
goto error;
- temp = readl(port_array[wIndex] + PORTPMSC);
+ temp = readl(ports[wIndex]->addr + PORTPMSC);
temp &= ~PORT_U2_TIMEOUT_MASK;
temp |= PORT_U2_TIMEOUT(timeout);
- writel(temp, port_array[wIndex] + PORTPMSC);
+ writel(temp, ports[wIndex]->addr + PORTPMSC);
break;
case USB_PORT_FEAT_TEST:
/* 4.19.6 Port Test Modes (USB2 Test Mode) */
@@ -1318,13 +1311,13 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
goto error;
}
/* unblock any posted writes */
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
break;
case ClearPortFeature:
if (!wIndex || wIndex > max_ports)
goto error;
wIndex--;
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
if (temp == ~(u32)0) {
xhci_hc_died(xhci);
retval = -ENODEV;
@@ -1334,7 +1327,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp = xhci_port_state_to_neutral(temp);
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n");
xhci_dbg(xhci, "PORTSC %04x\n", temp);
if (temp & PORT_RESET)
@@ -1344,12 +1337,12 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
goto error;
set_bit(wIndex, &bus_state->resuming_ports);
- xhci_set_link_state(xhci, port_array, wIndex,
- XDEV_RESUME);
+ xhci_set_link_state(xhci, ports[wIndex],
+ XDEV_RESUME);
spin_unlock_irqrestore(&xhci->lock, flags);
msleep(USB_RESUME_TIMEOUT);
spin_lock_irqsave(&xhci->lock, flags);
- xhci_set_link_state(xhci, port_array, wIndex,
+ xhci_set_link_state(xhci, ports[wIndex],
XDEV_U0);
clear_bit(wIndex, &bus_state->resuming_ports);
}
@@ -1374,11 +1367,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case USB_PORT_FEAT_C_PORT_LINK_STATE:
case USB_PORT_FEAT_C_PORT_CONFIG_ERROR:
xhci_clear_port_change_bit(xhci, wValue, wIndex,
- port_array[wIndex], temp);
+ ports[wIndex]->addr, temp);
break;
case USB_PORT_FEAT_ENABLE:
xhci_disable_port(hcd, xhci, wIndex,
- port_array[wIndex], temp);
+ ports[wIndex]->addr, temp);
break;
case USB_PORT_FEAT_POWER:
xhci_set_port_power(xhci, hcd, wIndex, false, &flags);
@@ -1415,11 +1408,14 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
int i, retval;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
int max_ports;
- __le32 __iomem **port_array;
struct xhci_bus_state *bus_state;
bool reset_change = false;
+ struct xhci_hub *rhub;
+ struct xhci_port **ports;
- max_ports = xhci_get_ports(hcd, &port_array);
+ rhub = xhci_get_rhub(hcd);
+ ports = rhub->ports;
+ max_ports = rhub->num_ports;
bus_state = &xhci->bus_state[hcd_index(hcd)];
/* Initial status is no changes */
@@ -1437,7 +1433,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
spin_lock_irqsave(&xhci->lock, flags);
/* For each port, did anything change? If so, set that bit in buf. */
for (i = 0; i < max_ports; i++) {
- temp = readl(port_array[i]);
+ temp = readl(ports[i]->addr);
if (temp == ~(u32)0) {
xhci_hc_died(xhci);
retval = -ENODEV;
@@ -1469,11 +1465,14 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
int max_ports, port_index;
- __le32 __iomem **port_array;
struct xhci_bus_state *bus_state;
unsigned long flags;
+ struct xhci_hub *rhub;
+ struct xhci_port **ports;
- max_ports = xhci_get_ports(hcd, &port_array);
+ rhub = xhci_get_rhub(hcd);
+ ports = rhub->ports;
+ max_ports = rhub->num_ports;
bus_state = &xhci->bus_state[hcd_index(hcd)];
spin_lock_irqsave(&xhci->lock, flags);
@@ -1494,7 +1493,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
u32 t1, t2;
int slot_id;
- t1 = readl(port_array[port_index]);
+ t1 = readl(ports[port_index]->addr);
t2 = xhci_port_state_to_neutral(t1);
if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) {
@@ -1534,7 +1533,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
t1 = xhci_port_state_to_neutral(t1);
if (t1 != t2)
- writel(t2, port_array[port_index]);
+ writel(t2, ports[port_index]->addr);
}
hcd->state = HC_STATE_SUSPENDED;
bus_state->next_statechange = jiffies + msecs_to_jiffies(10);
@@ -1547,12 +1546,11 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
* warm reset a USB3 device stuck in polling or compliance mode after resume.
* See Intel 100/c230 series PCH specification update Doc #332692-006 Errata #8
*/
-static bool xhci_port_missing_cas_quirk(int port_index,
- __le32 __iomem **port_array)
+static bool xhci_port_missing_cas_quirk(struct xhci_port *port)
{
u32 portsc;
- portsc = readl(port_array[port_index]);
+ portsc = readl(port->addr);
/* if any of these are set we are not stuck */
if (portsc & (PORT_CONNECT | PORT_CAS))
@@ -1565,9 +1563,9 @@ static bool xhci_port_missing_cas_quirk(int port_index,
/* clear wakeup/change bits, and do a warm port reset */
portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
portsc |= PORT_WR;
- writel(portsc, port_array[port_index]);
+ writel(portsc, port->addr);
/* flush write */
- readl(port_array[port_index]);
+ readl(port->addr);
return true;
}
@@ -1575,15 +1573,18 @@ int xhci_bus_resume(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct xhci_bus_state *bus_state;
- __le32 __iomem **port_array;
unsigned long flags;
int max_ports, port_index;
int slot_id;
int sret;
u32 next_state;
u32 temp, portsc;
+ struct xhci_hub *rhub;
+ struct xhci_port **ports;
- max_ports = xhci_get_ports(hcd, &port_array);
+ rhub = xhci_get_rhub(hcd);
+ ports = rhub->ports;
+ max_ports = rhub->num_ports;
bus_state = &xhci->bus_state[hcd_index(hcd)];
if (time_before(jiffies, bus_state->next_statechange))
@@ -1608,12 +1609,12 @@ int xhci_bus_resume(struct usb_hcd *hcd)
port_index = max_ports;
while (port_index--) {
- portsc = readl(port_array[port_index]);
+ portsc = readl(ports[port_index]->addr);
/* warm reset CAS limited ports stuck in polling/compliance */
if ((xhci->quirks & XHCI_MISSING_CAS) &&
(hcd->speed >= HCD_USB3) &&
- xhci_port_missing_cas_quirk(port_index, port_array)) {
+ xhci_port_missing_cas_quirk(ports[port_index])) {
xhci_dbg(xhci, "reset stuck port %d\n", port_index);
clear_bit(port_index, &bus_state->bus_suspended);
continue;
@@ -1637,7 +1638,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
}
/* disable wake for all ports, write new link state if needed */
portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
- writel(portsc, port_array[port_index]);
+ writel(portsc, ports[port_index]->addr);
}
/* USB2 specific resume signaling delay and U0 link state transition */
@@ -1650,23 +1651,22 @@ int xhci_bus_resume(struct usb_hcd *hcd)
for_each_set_bit(port_index, &bus_state->bus_suspended,
BITS_PER_LONG) {
/* Clear PLC to poll it later for U0 transition */
- xhci_test_and_clear_bit(xhci, port_array, port_index,
+ xhci_test_and_clear_bit(xhci, ports[port_index],
PORT_PLC);
- xhci_set_link_state(xhci, port_array, port_index,
- XDEV_U0);
+ xhci_set_link_state(xhci, ports[port_index], XDEV_U0);
}
}
/* poll for U0 link state complete, both USB2 and USB3 */
for_each_set_bit(port_index, &bus_state->bus_suspended, BITS_PER_LONG) {
- sret = xhci_handshake(port_array[port_index], PORT_PLC,
+ sret = xhci_handshake(ports[port_index]->addr, PORT_PLC,
PORT_PLC, 10 * 1000);
if (sret) {
xhci_warn(xhci, "port %d resume PLC timeout\n",
port_index);
continue;
}
- xhci_test_and_clear_bit(xhci, port_array, port_index, PORT_PLC);
+ xhci_test_and_clear_bit(xhci, ports[port_index], PORT_PLC);
slot_id = xhci_find_slot_id_by_port(hcd, xhci, port_index + 1);
if (slot_id)
xhci_ring_device(xhci, slot_id);
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index e5ace89..4fe7471 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -33,8 +33,9 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
struct xhci_segment *seg;
dma_addr_t dma;
int i;
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
- seg = kzalloc(sizeof *seg, flags);
+ seg = kzalloc_node(sizeof(*seg), flags, dev_to_node(dev));
if (!seg)
return NULL;
@@ -45,7 +46,8 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
}
if (max_packet) {
- seg->bounce_buf = kzalloc(max_packet, flags);
+ seg->bounce_buf = kzalloc_node(max_packet, flags,
+ dev_to_node(dev));
if (!seg->bounce_buf) {
dma_pool_free(xhci->segment_pool, seg->trbs, dma);
kfree(seg);
@@ -363,8 +365,9 @@ struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
{
struct xhci_ring *ring;
int ret;
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
- ring = kzalloc(sizeof *(ring), flags);
+ ring = kzalloc_node(sizeof(*ring), flags, dev_to_node(dev));
if (!ring)
return NULL;
@@ -458,11 +461,12 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
int type, gfp_t flags)
{
struct xhci_container_ctx *ctx;
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
if ((type != XHCI_CTX_TYPE_DEVICE) && (type != XHCI_CTX_TYPE_INPUT))
return NULL;
- ctx = kzalloc(sizeof(*ctx), flags);
+ ctx = kzalloc_node(sizeof(*ctx), flags, dev_to_node(dev));
if (!ctx)
return NULL;
@@ -615,6 +619,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
struct xhci_ring *cur_ring;
u64 addr;
int ret;
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
xhci_dbg(xhci, "Allocating %u streams and %u "
"stream context array entries.\n",
@@ -625,7 +630,8 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
}
xhci->cmd_ring_reserved_trbs++;
- stream_info = kzalloc(sizeof(struct xhci_stream_info), mem_flags);
+ stream_info = kzalloc_node(sizeof(*stream_info), mem_flags,
+ dev_to_node(dev));
if (!stream_info)
goto cleanup_trbs;
@@ -633,9 +639,9 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
stream_info->num_stream_ctxs = num_stream_ctxs;
/* Initialize the array of virtual pointers to stream rings. */
- stream_info->stream_rings = kzalloc(
- sizeof(struct xhci_ring *)*num_streams,
- mem_flags);
+ stream_info->stream_rings = kcalloc_node(
+ num_streams, sizeof(struct xhci_ring *), mem_flags,
+ dev_to_node(dev));
if (!stream_info->stream_rings)
goto cleanup_info;
@@ -831,6 +837,7 @@ int xhci_alloc_tt_info(struct xhci_hcd *xhci,
struct xhci_tt_bw_info *tt_info;
unsigned int num_ports;
int i, j;
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
if (!tt->multi)
num_ports = 1;
@@ -840,7 +847,8 @@ int xhci_alloc_tt_info(struct xhci_hcd *xhci,
for (i = 0; i < num_ports; i++, tt_info++) {
struct xhci_interval_bw_table *bw_table;
- tt_info = kzalloc(sizeof(*tt_info), mem_flags);
+ tt_info = kzalloc_node(sizeof(*tt_info), mem_flags,
+ dev_to_node(dev));
if (!tt_info)
goto free_tts;
INIT_LIST_HEAD(&tt_info->tt_list);
@@ -1054,8 +1062,7 @@ void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,
/*
* The xHCI roothub may have ports of differing speeds in any order in the port
- * status registers. xhci->port_array provides an array of the port speed for
- * each offset into the port status registers.
+ * status registers.
*
* The xHCI hardware wants to know the roothub port number that the USB device
* is attached to (or the roothub port its ancestor hub is attached to). All we
@@ -1642,7 +1649,8 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
if (!num_sp)
return 0;
- xhci->scratchpad = kzalloc(sizeof(*xhci->scratchpad), flags);
+ xhci->scratchpad = kzalloc_node(sizeof(*xhci->scratchpad), flags,
+ dev_to_node(dev));
if (!xhci->scratchpad)
goto fail_sp;
@@ -1652,7 +1660,8 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
if (!xhci->scratchpad->sp_array)
goto fail_sp2;
- xhci->scratchpad->sp_buffers = kzalloc(sizeof(void *) * num_sp, flags);
+ xhci->scratchpad->sp_buffers = kcalloc_node(num_sp, sizeof(void *),
+ flags, dev_to_node(dev));
if (!xhci->scratchpad->sp_buffers)
goto fail_sp3;
@@ -1720,14 +1729,16 @@ struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
bool allocate_completion, gfp_t mem_flags)
{
struct xhci_command *command;
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
- command = kzalloc(sizeof(*command), mem_flags);
+ command = kzalloc_node(sizeof(*command), mem_flags, dev_to_node(dev));
if (!command)
return NULL;
if (allocate_completion) {
command->completion =
- kzalloc(sizeof(struct completion), mem_flags);
+ kzalloc_node(sizeof(struct completion), mem_flags,
+ dev_to_node(dev));
if (!command->completion) {
kfree(command);
return NULL;
@@ -1890,18 +1901,18 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
no_bw:
xhci->cmd_ring_reserved_trbs = 0;
- xhci->num_usb2_ports = 0;
- xhci->num_usb3_ports = 0;
+ xhci->usb2_rhub.num_ports = 0;
+ xhci->usb3_rhub.num_ports = 0;
xhci->num_active_eps = 0;
- kfree(xhci->usb2_ports);
- kfree(xhci->usb3_ports);
- kfree(xhci->port_array);
+ kfree(xhci->usb2_rhub.ports);
+ kfree(xhci->usb3_rhub.ports);
+ kfree(xhci->hw_ports);
kfree(xhci->rh_bw);
kfree(xhci->ext_caps);
- xhci->usb2_ports = NULL;
- xhci->usb3_ports = NULL;
- xhci->port_array = NULL;
+ xhci->usb2_rhub.ports = NULL;
+ xhci->usb3_rhub.ports = NULL;
+ xhci->hw_ports = NULL;
xhci->rh_bw = NULL;
xhci->ext_caps = NULL;
@@ -2100,6 +2111,7 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
int i;
u8 major_revision, minor_revision;
struct xhci_hub *rhub;
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
temp = readl(addr);
major_revision = XHCI_EXT_PORT_MAJOR(temp);
@@ -2136,8 +2148,8 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
rhub->psi_count = XHCI_EXT_PORT_PSIC(temp);
if (rhub->psi_count) {
- rhub->psi = kcalloc(rhub->psi_count, sizeof(*rhub->psi),
- GFP_KERNEL);
+ rhub->psi = kcalloc_node(rhub->psi_count, sizeof(*rhub->psi),
+ GFP_KERNEL, dev_to_node(dev));
if (!rhub->psi)
rhub->psi_count = 0;
@@ -2186,36 +2198,53 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
port_offset--;
for (i = port_offset; i < (port_offset + port_count); i++) {
+ struct xhci_port *hw_port = &xhci->hw_ports[i];
/* Duplicate entry. Ignore the port if the revisions differ. */
- if (xhci->port_array[i] != 0) {
+ if (hw_port->rhub) {
xhci_warn(xhci, "Duplicate port entry, Ext Cap %p,"
" port %u\n", addr, i);
xhci_warn(xhci, "Port was marked as USB %u, "
"duplicated as USB %u\n",
- xhci->port_array[i], major_revision);
+ hw_port->rhub->maj_rev, major_revision);
/* Only adjust the roothub port counts if we haven't
* found a similar duplicate.
*/
- if (xhci->port_array[i] != major_revision &&
- xhci->port_array[i] != DUPLICATE_ENTRY) {
- if (xhci->port_array[i] == 0x03)
- xhci->num_usb3_ports--;
- else
- xhci->num_usb2_ports--;
- xhci->port_array[i] = DUPLICATE_ENTRY;
+ if (hw_port->rhub != rhub &&
+ hw_port->hcd_portnum != DUPLICATE_ENTRY) {
+ hw_port->rhub->num_ports--;
+ hw_port->hcd_portnum = DUPLICATE_ENTRY;
}
- /* FIXME: Should we disable the port? */
continue;
}
- xhci->port_array[i] = major_revision;
- if (major_revision == 0x03)
- xhci->num_usb3_ports++;
- else
- xhci->num_usb2_ports++;
+ hw_port->rhub = rhub;
+ rhub->num_ports++;
}
/* FIXME: Should we disable ports not in the Extended Capabilities? */
}
+static void xhci_create_rhub_port_array(struct xhci_hcd *xhci,
+ struct xhci_hub *rhub, gfp_t flags)
+{
+ int port_index = 0;
+ int i;
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
+
+ if (!rhub->num_ports)
+ return;
+ rhub->ports = kcalloc_node(rhub->num_ports, sizeof(rhub->ports), flags,
+ dev_to_node(dev));
+ for (i = 0; i < HCS_MAX_PORTS(xhci->hcs_params1); i++) {
+ if (xhci->hw_ports[i].rhub != rhub ||
+ xhci->hw_ports[i].hcd_portnum == DUPLICATE_ENTRY)
+ continue;
+ xhci->hw_ports[i].hcd_portnum = port_index;
+ rhub->ports[port_index] = &xhci->hw_ports[i];
+ port_index++;
+ if (port_index == rhub->num_ports)
+ break;
+ }
+}
+
/*
* Scan the Extended Capabilities for the "Supported Protocol Capabilities" that
* specify what speeds each port is supposed to be. We can't count on the port
@@ -2228,16 +2257,25 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
void __iomem *base;
u32 offset;
unsigned int num_ports;
- int i, j, port_index;
+ int i, j;
int cap_count = 0;
u32 cap_start;
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
- xhci->port_array = kzalloc(sizeof(*xhci->port_array)*num_ports, flags);
- if (!xhci->port_array)
+ xhci->hw_ports = kcalloc_node(num_ports, sizeof(*xhci->hw_ports),
+ flags, dev_to_node(dev));
+ if (!xhci->hw_ports)
return -ENOMEM;
- xhci->rh_bw = kzalloc(sizeof(*xhci->rh_bw)*num_ports, flags);
+ for (i = 0; i < num_ports; i++) {
+ xhci->hw_ports[i].addr = &xhci->op_regs->port_status_base +
+ NUM_PORT_REGS * i;
+ xhci->hw_ports[i].hw_portnum = i;
+ }
+
+ xhci->rh_bw = kzalloc_node(sizeof(*xhci->rh_bw)*num_ports, flags,
+ dev_to_node(dev));
if (!xhci->rh_bw)
return -ENOMEM;
for (i = 0; i < num_ports; i++) {
@@ -2264,7 +2302,8 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
XHCI_EXT_CAPS_PROTOCOL);
}
- xhci->ext_caps = kzalloc(sizeof(*xhci->ext_caps) * cap_count, flags);
+ xhci->ext_caps = kcalloc_node(cap_count, sizeof(*xhci->ext_caps),
+ flags, dev_to_node(dev));
if (!xhci->ext_caps)
return -ENOMEM;
@@ -2272,86 +2311,44 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
while (offset) {
xhci_add_in_port(xhci, num_ports, base + offset, cap_count);
- if (xhci->num_usb2_ports + xhci->num_usb3_ports == num_ports)
+ if (xhci->usb2_rhub.num_ports + xhci->usb3_rhub.num_ports ==
+ num_ports)
break;
offset = xhci_find_next_ext_cap(base, offset,
XHCI_EXT_CAPS_PROTOCOL);
}
-
- if (xhci->num_usb2_ports == 0 && xhci->num_usb3_ports == 0) {
+ if (xhci->usb2_rhub.num_ports == 0 && xhci->usb3_rhub.num_ports == 0) {
xhci_warn(xhci, "No ports on the roothubs?\n");
return -ENODEV;
}
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "Found %u USB 2.0 ports and %u USB 3.0 ports.",
- xhci->num_usb2_ports, xhci->num_usb3_ports);
+ "Found %u USB 2.0 ports and %u USB 3.0 ports.",
+ xhci->usb2_rhub.num_ports, xhci->usb3_rhub.num_ports);
/* Place limits on the number of roothub ports so that the hub
* descriptors aren't longer than the USB core will allocate.
*/
- if (xhci->num_usb3_ports > USB_SS_MAXPORTS) {
+ if (xhci->usb3_rhub.num_ports > USB_SS_MAXPORTS) {
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Limiting USB 3.0 roothub ports to %u.",
USB_SS_MAXPORTS);
- xhci->num_usb3_ports = USB_SS_MAXPORTS;
+ xhci->usb3_rhub.num_ports = USB_SS_MAXPORTS;
}
- if (xhci->num_usb2_ports > USB_MAXCHILDREN) {
+ if (xhci->usb2_rhub.num_ports > USB_MAXCHILDREN) {
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Limiting USB 2.0 roothub ports to %u.",
USB_MAXCHILDREN);
- xhci->num_usb2_ports = USB_MAXCHILDREN;
+ xhci->usb2_rhub.num_ports = USB_MAXCHILDREN;
}
/*
* Note we could have all USB 3.0 ports, or all USB 2.0 ports.
* Not sure how the USB core will handle a hub with no ports...
*/
- if (xhci->num_usb2_ports) {
- xhci->usb2_ports = kmalloc(sizeof(*xhci->usb2_ports)*
- xhci->num_usb2_ports, flags);
- if (!xhci->usb2_ports)
- return -ENOMEM;
-
- port_index = 0;
- for (i = 0; i < num_ports; i++) {
- if (xhci->port_array[i] == 0x03 ||
- xhci->port_array[i] == 0 ||
- xhci->port_array[i] == DUPLICATE_ENTRY)
- continue;
- xhci->usb2_ports[port_index] =
- &xhci->op_regs->port_status_base +
- NUM_PORT_REGS*i;
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "USB 2.0 port at index %u, "
- "addr = %p", i,
- xhci->usb2_ports[port_index]);
- port_index++;
- if (port_index == xhci->num_usb2_ports)
- break;
- }
- }
- if (xhci->num_usb3_ports) {
- xhci->usb3_ports = kmalloc(sizeof(*xhci->usb3_ports)*
- xhci->num_usb3_ports, flags);
- if (!xhci->usb3_ports)
- return -ENOMEM;
+ xhci_create_rhub_port_array(xhci, &xhci->usb2_rhub, flags);
+ xhci_create_rhub_port_array(xhci, &xhci->usb3_rhub, flags);
- port_index = 0;
- for (i = 0; i < num_ports; i++)
- if (xhci->port_array[i] == 0x03) {
- xhci->usb3_ports[port_index] =
- &xhci->op_regs->port_status_base +
- NUM_PORT_REGS*i;
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "USB 3.0 port at index %u, "
- "addr = %p", i,
- xhci->usb3_ports[port_index]);
- port_index++;
- if (port_index == xhci->num_usb3_ports)
- break;
- }
- }
return 0;
}
diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index eea7360..fa33d6e 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -58,7 +58,7 @@ static int get_bw_index(struct xhci_hcd *xhci, struct usb_device *udev,
bw_index = (virt_dev->real_port - 1) * 2 + 1;
} else {
/* add one more for each SS port */
- bw_index = virt_dev->real_port + xhci->num_usb3_ports - 1;
+ bw_index = virt_dev->real_port + xhci->usb3_rhub.num_ports - 1;
}
return bw_index;
@@ -284,7 +284,7 @@ int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk)
int i;
/* ss IN and OUT are separated */
- num_usb_bus = xhci->num_usb3_ports * 2 + xhci->num_usb2_ports;
+ num_usb_bus = xhci->usb3_rhub.num_ports * 2 + xhci->usb2_rhub.num_ports;
sch_array = kcalloc(num_usb_bus, sizeof(*sch_array), GFP_KERNEL);
if (sch_array == NULL)
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 85ffda8..6372edf 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -196,11 +196,15 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
xhci->quirks |= XHCI_BROKEN_STREAMS;
}
if (pdev->vendor == PCI_VENDOR_ID_RENESAS &&
- pdev->device == 0x0014)
+ pdev->device == 0x0014) {
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+ xhci->quirks |= XHCI_ZERO_64B_REGS;
+ }
if (pdev->vendor == PCI_VENDOR_ID_RENESAS &&
- pdev->device == 0x0015)
+ pdev->device == 0x0015) {
xhci->quirks |= XHCI_RESET_ON_RESUME;
+ xhci->quirks |= XHCI_ZERO_64B_REGS;
+ }
if (pdev->vendor == PCI_VENDOR_ID_VIA)
xhci->quirks |= XHCI_RESET_ON_RESUME;
@@ -284,13 +288,6 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
driver = (struct hc_driver *)id->driver_data;
- /* For some HW implementation, a XHCI reset is just not enough... */
- if (usb_xhci_needs_pci_reset(dev)) {
- dev_info(&dev->dev, "Resetting\n");
- if (pci_reset_function_locked(dev))
- dev_warn(&dev->dev, "Reset failed");
- }
-
/* Prevent runtime suspending between USB-2 and USB-3 initialization */
pm_runtime_get_noresume(&dev->dev);
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 91a1a82..f0a99aa 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1497,44 +1497,6 @@ static void handle_vendor_event(struct xhci_hcd *xhci,
handle_cmd_completion(xhci, &event->event_cmd);
}
-/* @port_id: the one-based port ID from the hardware (indexed from array of all
- * port registers -- USB 3.0 and USB 2.0).
- *
- * Returns a zero-based port number, which is suitable for indexing into each of
- * the split roothubs' port arrays and bus state arrays.
- * Add one to it in order to call xhci_find_slot_id_by_port.
- */
-static unsigned int find_faked_portnum_from_hw_portnum(struct usb_hcd *hcd,
- struct xhci_hcd *xhci, u32 port_id)
-{
- unsigned int i;
- unsigned int num_similar_speed_ports = 0;
-
- /* port_id from the hardware is 1-based, but port_array[], usb3_ports[],
- * and usb2_ports are 0-based indexes. Count the number of similar
- * speed ports, up to 1 port before this port.
- */
- for (i = 0; i < (port_id - 1); i++) {
- u8 port_speed = xhci->port_array[i];
-
- /*
- * Skip ports that don't have known speeds, or have duplicate
- * Extended Capabilities port speed entries.
- */
- if (port_speed == 0 || port_speed == DUPLICATE_ENTRY)
- continue;
-
- /*
- * USB 3.0 ports are always under a USB 3.0 hub. USB 2.0 and
- * 1.1 ports are under the USB 2.0 hub. If the port speed
- * matches the device speed, it's a similar speed port.
- */
- if ((port_speed == 0x03) == (hcd->speed >= HCD_USB3))
- num_similar_speed_ports++;
- }
- return num_similar_speed_ports;
-}
-
static void handle_device_notification(struct xhci_hcd *xhci,
union xhci_trb *event)
{
@@ -1563,11 +1525,10 @@ static void handle_port_status(struct xhci_hcd *xhci,
u32 portsc, cmd_reg;
int max_ports;
int slot_id;
- unsigned int faked_port_index;
- u8 major_revision;
+ unsigned int hcd_portnum;
struct xhci_bus_state *bus_state;
- __le32 __iomem **port_array;
bool bogus_port_status = false;
+ struct xhci_port *port;
/* Port status change events always have a successful completion code */
if (GET_COMP_CODE(le32_to_cpu(event->generic.field[2])) != COMP_SUCCESS)
@@ -1584,49 +1545,19 @@ static void handle_port_status(struct xhci_hcd *xhci,
return;
}
- /* Figure out which usb_hcd this port is attached to:
- * is it a USB 3.0 port or a USB 2.0/1.1 port?
- */
- major_revision = xhci->port_array[port_id - 1];
-
- /* Find the right roothub. */
- hcd = xhci_to_hcd(xhci);
- if ((major_revision == 0x03) != (hcd->speed >= HCD_USB3))
- hcd = xhci->shared_hcd;
-
- if (major_revision == 0) {
- xhci_warn(xhci, "Event for port %u not in "
- "Extended Capabilities, ignoring.\n",
- port_id);
- bogus_port_status = true;
- goto cleanup;
- }
- if (major_revision == DUPLICATE_ENTRY) {
- xhci_warn(xhci, "Event for port %u duplicated in"
- "Extended Capabilities, ignoring.\n",
- port_id);
+ port = &xhci->hw_ports[port_id - 1];
+ if (!port || !port->rhub || port->hcd_portnum == DUPLICATE_ENTRY) {
+ xhci_warn(xhci, "Event for invalid port %u\n", port_id);
bogus_port_status = true;
goto cleanup;
}
- /*
- * Hardware port IDs reported by a Port Status Change Event include USB
- * 3.0 and USB 2.0 ports. We want to check if the port has reported a
- * resume event, but we first need to translate the hardware port ID
- * into the index into the ports on the correct split roothub, and the
- * correct bus_state structure.
- */
+ hcd = port->rhub->hcd;
bus_state = &xhci->bus_state[hcd_index(hcd)];
- if (hcd->speed >= HCD_USB3)
- port_array = xhci->usb3_ports;
- else
- port_array = xhci->usb2_ports;
- /* Find the faked port hub number */
- faked_port_index = find_faked_portnum_from_hw_portnum(hcd, xhci,
- port_id);
- portsc = readl(port_array[faked_port_index]);
+ hcd_portnum = port->hcd_portnum;
+ portsc = readl(port->addr);
- trace_xhci_handle_port_status(faked_port_index, portsc);
+ trace_xhci_handle_port_status(hcd_portnum, portsc);
if (hcd->state == HC_STATE_SUSPENDED) {
xhci_dbg(xhci, "resume root hub\n");
@@ -1634,7 +1565,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
}
if (hcd->speed >= HCD_USB3 && (portsc & PORT_PLS_MASK) == XDEV_INACTIVE)
- bus_state->port_remote_wakeup &= ~(1 << faked_port_index);
+ bus_state->port_remote_wakeup &= ~(1 << hcd_portnum);
if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) {
xhci_dbg(xhci, "port resume event for port %d\n", port_id);
@@ -1651,29 +1582,26 @@ static void handle_port_status(struct xhci_hcd *xhci,
* so we can tell the difference between the end of
* device and host initiated resume.
*/
- bus_state->port_remote_wakeup |= 1 << faked_port_index;
- xhci_test_and_clear_bit(xhci, port_array,
- faked_port_index, PORT_PLC);
- xhci_set_link_state(xhci, port_array, faked_port_index,
- XDEV_U0);
+ bus_state->port_remote_wakeup |= 1 << hcd_portnum;
+ xhci_test_and_clear_bit(xhci, port, PORT_PLC);
+ xhci_set_link_state(xhci, port, XDEV_U0);
/* Need to wait until the next link state change
* indicates the device is actually in U0.
*/
bogus_port_status = true;
goto cleanup;
- } else if (!test_bit(faked_port_index,
- &bus_state->resuming_ports)) {
+ } else if (!test_bit(hcd_portnum, &bus_state->resuming_ports)) {
xhci_dbg(xhci, "resume HS port %d\n", port_id);
- bus_state->resume_done[faked_port_index] = jiffies +
+ bus_state->resume_done[hcd_portnum] = jiffies +
msecs_to_jiffies(USB_RESUME_TIMEOUT);
- set_bit(faked_port_index, &bus_state->resuming_ports);
+ set_bit(hcd_portnum, &bus_state->resuming_ports);
/* Do the rest in GetPortStatus after resume time delay.
* Avoid polling roothub status before that so that a
* usb device auto-resume latency around ~40ms.
*/
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
mod_timer(&hcd->rh_timer,
- bus_state->resume_done[faked_port_index]);
+ bus_state->resume_done[hcd_portnum]);
bogus_port_status = true;
}
}
@@ -1688,17 +1616,14 @@ static void handle_port_status(struct xhci_hcd *xhci,
* so the roothub behavior is consistent with external
* USB 3.0 hub behavior.
*/
- slot_id = xhci_find_slot_id_by_port(hcd, xhci,
- faked_port_index + 1);
+ slot_id = xhci_find_slot_id_by_port(hcd, xhci, hcd_portnum + 1);
if (slot_id && xhci->devs[slot_id])
xhci_ring_device(xhci, slot_id);
- if (bus_state->port_remote_wakeup & (1 << faked_port_index)) {
- bus_state->port_remote_wakeup &=
- ~(1 << faked_port_index);
- xhci_test_and_clear_bit(xhci, port_array,
- faked_port_index, PORT_PLC);
+ if (bus_state->port_remote_wakeup & (1 << hcd_portnum)) {
+ bus_state->port_remote_wakeup &= ~(1 << hcd_portnum);
+ xhci_test_and_clear_bit(xhci, port, PORT_PLC);
usb_wakeup_notification(hcd->self.root_hub,
- faked_port_index + 1);
+ hcd_portnum + 1);
bogus_port_status = true;
goto cleanup;
}
@@ -1710,16 +1635,15 @@ static void handle_port_status(struct xhci_hcd *xhci,
* out of the RExit state.
*/
if (!DEV_SUPERSPEED_ANY(portsc) &&
- test_and_clear_bit(faked_port_index,
+ test_and_clear_bit(hcd_portnum,
&bus_state->rexit_ports)) {
- complete(&bus_state->rexit_done[faked_port_index]);
+ complete(&bus_state->rexit_done[hcd_portnum]);
bogus_port_status = true;
goto cleanup;
}
if (hcd->speed < HCD_USB3)
- xhci_test_and_clear_bit(xhci, port_array, faked_port_index,
- PORT_PLC);
+ xhci_test_and_clear_bit(xhci, port, PORT_PLC);
cleanup:
/* Update event ring dequeue pointer before dropping the lock */
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
index 2c076ea..a8c1d07 100644
--- a/drivers/usb/host/xhci-tegra.c
+++ b/drivers/usb/host/xhci-tegra.c
@@ -18,9 +18,11 @@
#include <linux/phy/tegra/xusb.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
+#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>
+#include <soc/tegra/pmc.h>
#include "xhci.h"
@@ -761,6 +763,49 @@ static void tegra_xusb_phy_disable(struct tegra_xusb *tegra)
}
}
+static int tegra_xusb_runtime_suspend(struct device *dev)
+{
+ struct tegra_xusb *tegra = dev_get_drvdata(dev);
+
+ tegra_xusb_phy_disable(tegra);
+ regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
+ tegra_xusb_clk_disable(tegra);
+
+ return 0;
+}
+
+static int tegra_xusb_runtime_resume(struct device *dev)
+{
+ struct tegra_xusb *tegra = dev_get_drvdata(dev);
+ int err;
+
+ err = tegra_xusb_clk_enable(tegra);
+ if (err) {
+ dev_err(dev, "failed to enable clocks: %d\n", err);
+ return err;
+ }
+
+ err = regulator_bulk_enable(tegra->soc->num_supplies, tegra->supplies);
+ if (err) {
+ dev_err(dev, "failed to enable regulators: %d\n", err);
+ goto disable_clk;
+ }
+
+ err = tegra_xusb_phy_enable(tegra);
+ if (err < 0) {
+ dev_err(dev, "failed to enable PHYs: %d\n", err);
+ goto disable_regulator;
+ }
+
+ return 0;
+
+disable_regulator:
+ regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
+disable_clk:
+ tegra_xusb_clk_disable(tegra);
+ return err;
+}
+
static int tegra_xusb_load_firmware(struct tegra_xusb *tegra)
{
unsigned int code_tag_blocks, code_size_blocks, code_blocks;
@@ -930,20 +975,6 @@ static int tegra_xusb_probe(struct platform_device *pdev)
if (IS_ERR(tegra->padctl))
return PTR_ERR(tegra->padctl);
- tegra->host_rst = devm_reset_control_get(&pdev->dev, "xusb_host");
- if (IS_ERR(tegra->host_rst)) {
- err = PTR_ERR(tegra->host_rst);
- dev_err(&pdev->dev, "failed to get xusb_host reset: %d\n", err);
- goto put_padctl;
- }
-
- tegra->ss_rst = devm_reset_control_get(&pdev->dev, "xusb_ss");
- if (IS_ERR(tegra->ss_rst)) {
- err = PTR_ERR(tegra->ss_rst);
- dev_err(&pdev->dev, "failed to get xusb_ss reset: %d\n", err);
- goto put_padctl;
- }
-
tegra->host_clk = devm_clk_get(&pdev->dev, "xusb_host");
if (IS_ERR(tegra->host_clk)) {
err = PTR_ERR(tegra->host_clk);
@@ -1007,11 +1038,48 @@ static int tegra_xusb_probe(struct platform_device *pdev)
goto put_padctl;
}
+ if (!pdev->dev.pm_domain) {
+ tegra->host_rst = devm_reset_control_get(&pdev->dev,
+ "xusb_host");
+ if (IS_ERR(tegra->host_rst)) {
+ err = PTR_ERR(tegra->host_rst);
+ dev_err(&pdev->dev,
+ "failed to get xusb_host reset: %d\n", err);
+ goto put_padctl;
+ }
+
+ tegra->ss_rst = devm_reset_control_get(&pdev->dev, "xusb_ss");
+ if (IS_ERR(tegra->ss_rst)) {
+ err = PTR_ERR(tegra->ss_rst);
+ dev_err(&pdev->dev, "failed to get xusb_ss reset: %d\n",
+ err);
+ goto put_padctl;
+ }
+
+ err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_XUSBA,
+ tegra->ss_clk,
+ tegra->ss_rst);
+ if (err) {
+ dev_err(&pdev->dev,
+ "failed to enable XUSBA domain: %d\n", err);
+ goto put_padctl;
+ }
+
+ err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_XUSBC,
+ tegra->host_clk,
+ tegra->host_rst);
+ if (err) {
+ dev_err(&pdev->dev,
+ "failed to enable XUSBC domain: %d\n", err);
+ goto disable_xusba;
+ }
+ }
+
tegra->supplies = devm_kcalloc(&pdev->dev, tegra->soc->num_supplies,
sizeof(*tegra->supplies), GFP_KERNEL);
if (!tegra->supplies) {
err = -ENOMEM;
- goto put_padctl;
+ goto disable_xusbc;
}
for (i = 0; i < tegra->soc->num_supplies; i++)
@@ -1021,7 +1089,7 @@ static int tegra_xusb_probe(struct platform_device *pdev)
tegra->supplies);
if (err) {
dev_err(&pdev->dev, "failed to get regulators: %d\n", err);
- goto put_padctl;
+ goto disable_xusbc;
}
for (i = 0; i < tegra->soc->num_types; i++)
@@ -1031,7 +1099,7 @@ static int tegra_xusb_probe(struct platform_device *pdev)
sizeof(*tegra->phys), GFP_KERNEL);
if (!tegra->phys) {
err = -ENOMEM;
- goto put_padctl;
+ goto disable_xusbc;
}
for (i = 0, k = 0; i < tegra->soc->num_types; i++) {
@@ -1047,29 +1115,35 @@ static int tegra_xusb_probe(struct platform_device *pdev)
"failed to get PHY %s: %ld\n", prop,
PTR_ERR(phy));
err = PTR_ERR(phy);
- goto put_padctl;
+ goto disable_xusbc;
}
tegra->phys[k++] = phy;
}
}
- err = tegra_xusb_clk_enable(tegra);
- if (err) {
- dev_err(&pdev->dev, "failed to enable clocks: %d\n", err);
- goto put_padctl;
+ tegra->hcd = usb_create_hcd(&tegra_xhci_hc_driver, &pdev->dev,
+ dev_name(&pdev->dev));
+ if (!tegra->hcd) {
+ err = -ENOMEM;
+ goto disable_xusbc;
}
- err = regulator_bulk_enable(tegra->soc->num_supplies, tegra->supplies);
- if (err) {
- dev_err(&pdev->dev, "failed to enable regulators: %d\n", err);
- goto disable_clk;
- }
+ /*
+ * This must happen after usb_create_hcd(), because usb_create_hcd()
+ * will overwrite the drvdata of the device with the hcd it creates.
+ */
+ platform_set_drvdata(pdev, tegra);
+
+ pm_runtime_enable(&pdev->dev);
+ if (pm_runtime_enabled(&pdev->dev))
+ err = pm_runtime_get_sync(&pdev->dev);
+ else
+ err = tegra_xusb_runtime_resume(&pdev->dev);
- err = tegra_xusb_phy_enable(tegra);
if (err < 0) {
- dev_err(&pdev->dev, "failed to enable PHYs: %d\n", err);
- goto disable_regulator;
+ dev_err(&pdev->dev, "failed to enable device: %d\n", err);
+ goto disable_rpm;
}
tegra_xusb_ipfs_config(tegra, regs);
@@ -1077,22 +1151,9 @@ static int tegra_xusb_probe(struct platform_device *pdev)
err = tegra_xusb_load_firmware(tegra);
if (err < 0) {
dev_err(&pdev->dev, "failed to load firmware: %d\n", err);
- goto disable_phy;
- }
-
- tegra->hcd = usb_create_hcd(&tegra_xhci_hc_driver, &pdev->dev,
- dev_name(&pdev->dev));
- if (!tegra->hcd) {
- err = -ENOMEM;
- goto disable_phy;
+ goto put_rpm;
}
- /*
- * This must happen after usb_create_hcd(), because usb_create_hcd()
- * will overwrite the drvdata of the device with the hcd it creates.
- */
- platform_set_drvdata(pdev, tegra);
-
tegra->hcd->regs = tegra->regs;
tegra->hcd->rsrc_start = regs->start;
tegra->hcd->rsrc_len = resource_size(regs);
@@ -1100,7 +1161,7 @@ static int tegra_xusb_probe(struct platform_device *pdev)
err = usb_add_hcd(tegra->hcd, tegra->xhci_irq, IRQF_SHARED);
if (err < 0) {
dev_err(&pdev->dev, "failed to add USB HCD: %d\n", err);
- goto put_usb2;
+ goto put_rpm;
}
device_wakeup_enable(tegra->hcd->self.controller);
@@ -1155,14 +1216,18 @@ put_usb3:
usb_put_hcd(xhci->shared_hcd);
remove_usb2:
usb_remove_hcd(tegra->hcd);
-put_usb2:
+put_rpm:
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ tegra_xusb_runtime_suspend(&pdev->dev);
+disable_rpm:
+ pm_runtime_disable(&pdev->dev);
usb_put_hcd(tegra->hcd);
-disable_phy:
- tegra_xusb_phy_disable(tegra);
-disable_regulator:
- regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
-disable_clk:
- tegra_xusb_clk_disable(tegra);
+disable_xusbc:
+ if (!&pdev->dev.pm_domain)
+ tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC);
+disable_xusba:
+ if (!&pdev->dev.pm_domain)
+ tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA);
put_padctl:
tegra_xusb_padctl_put(tegra->padctl);
return err;
@@ -1181,9 +1246,8 @@ static int tegra_xusb_remove(struct platform_device *pdev)
dma_free_coherent(&pdev->dev, tegra->fw.size, tegra->fw.virt,
tegra->fw.phys);
- tegra_xusb_phy_disable(tegra);
- regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
- tegra_xusb_clk_disable(tegra);
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
tegra_xusb_padctl_put(tegra->padctl);
@@ -1211,6 +1275,8 @@ static int tegra_xusb_resume(struct device *dev)
#endif
static const struct dev_pm_ops tegra_xusb_pm_ops = {
+ SET_RUNTIME_PM_OPS(tegra_xusb_runtime_suspend,
+ tegra_xusb_runtime_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(tegra_xusb_suspend, tegra_xusb_resume)
};
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 711da33..8c8da2d 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -33,8 +33,8 @@ static int link_quirk;
module_param(link_quirk, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(link_quirk, "Don't clear the chain bit on a link TRB");
-static unsigned int quirks;
-module_param(quirks, uint, S_IRUGO);
+static unsigned long long quirks;
+module_param(quirks, ullong, S_IRUGO);
MODULE_PARM_DESC(quirks, "Bit flags for quirks to be enabled as default");
/* TODO: copied from ehci-hcd.c - can this be refactored? */
@@ -209,6 +209,68 @@ int xhci_reset(struct xhci_hcd *xhci)
return ret;
}
+static void xhci_zero_64b_regs(struct xhci_hcd *xhci)
+{
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
+ int err, i;
+ u64 val;
+
+ /*
+ * Some Renesas controllers get into a weird state if they are
+ * reset while programmed with 64bit addresses (they will preserve
+ * the top half of the address in internal, non visible
+ * registers). You end up with half the address coming from the
+ * kernel, and the other half coming from the firmware. Also,
+ * changing the programming leads to extra accesses even if the
+ * controller is supposed to be halted. The controller ends up with
+ * a fatal fault, and is then ripe for being properly reset.
+ *
+ * Special care is taken to only apply this if the device is behind
+ * an iommu. Doing anything when there is no iommu is definitely
+ * unsafe...
+ */
+ if (!(xhci->quirks & XHCI_ZERO_64B_REGS) || !dev->iommu_group)
+ return;
+
+ xhci_info(xhci, "Zeroing 64bit base registers, expecting fault\n");
+
+ /* Clear HSEIE so that faults do not get signaled */
+ val = readl(&xhci->op_regs->command);
+ val &= ~CMD_HSEIE;
+ writel(val, &xhci->op_regs->command);
+
+ /* Clear HSE (aka FATAL) */
+ val = readl(&xhci->op_regs->status);
+ val |= STS_FATAL;
+ writel(val, &xhci->op_regs->status);
+
+ /* Now zero the registers, and brace for impact */
+ val = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
+ if (upper_32_bits(val))
+ xhci_write_64(xhci, 0, &xhci->op_regs->dcbaa_ptr);
+ val = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
+ if (upper_32_bits(val))
+ xhci_write_64(xhci, 0, &xhci->op_regs->cmd_ring);
+
+ for (i = 0; i < HCS_MAX_INTRS(xhci->hcs_params1); i++) {
+ struct xhci_intr_reg __iomem *ir;
+
+ ir = &xhci->run_regs->ir_set[i];
+ val = xhci_read_64(xhci, &ir->erst_base);
+ if (upper_32_bits(val))
+ xhci_write_64(xhci, 0, &ir->erst_base);
+ val= xhci_read_64(xhci, &ir->erst_dequeue);
+ if (upper_32_bits(val))
+ xhci_write_64(xhci, 0, &ir->erst_dequeue);
+ }
+
+ /* Wait for the fault to appear. It will be cleared on reset */
+ err = xhci_handshake(&xhci->op_regs->status,
+ STS_FATAL, STS_FATAL,
+ XHCI_MAX_HALT_USEC);
+ if (!err)
+ xhci_info(xhci, "Fault detected\n");
+}
#ifdef CONFIG_USB_PCI
/*
@@ -400,13 +462,15 @@ static void compliance_mode_recovery(struct timer_list *t)
{
struct xhci_hcd *xhci;
struct usb_hcd *hcd;
+ struct xhci_hub *rhub;
u32 temp;
int i;
xhci = from_timer(xhci, t, comp_mode_recovery_timer);
+ rhub = &xhci->usb3_rhub;
- for (i = 0; i < xhci->num_usb3_ports; i++) {
- temp = readl(xhci->usb3_ports[i]);
+ for (i = 0; i < rhub->num_ports; i++) {
+ temp = readl(rhub->ports[i]->addr);
if ((temp & PORT_PLS_MASK) == USB_SS_PORT_LS_COMP_MOD) {
/*
* Compliance Mode Detected. Letting USB Core
@@ -426,7 +490,7 @@ static void compliance_mode_recovery(struct timer_list *t)
}
}
- if (xhci->port_status_u0 != ((1 << xhci->num_usb3_ports)-1))
+ if (xhci->port_status_u0 != ((1 << rhub->num_ports) - 1))
mod_timer(&xhci->comp_mode_recovery_timer,
jiffies + msecs_to_jiffies(COMP_MODE_RCVRY_MSECS));
}
@@ -483,7 +547,7 @@ static bool xhci_compliance_mode_recovery_timer_quirk_check(void)
static int xhci_all_ports_seen_u0(struct xhci_hcd *xhci)
{
- return (xhci->port_status_u0 == ((1 << xhci->num_usb3_ports)-1));
+ return (xhci->port_status_u0 == ((1 << xhci->usb3_rhub.num_ports) - 1));
}
@@ -812,33 +876,33 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci)
static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci)
{
+ struct xhci_port **ports;
int port_index;
- __le32 __iomem **port_array;
unsigned long flags;
u32 t1, t2;
spin_lock_irqsave(&xhci->lock, flags);
/* disable usb3 ports Wake bits */
- port_index = xhci->num_usb3_ports;
- port_array = xhci->usb3_ports;
+ port_index = xhci->usb3_rhub.num_ports;
+ ports = xhci->usb3_rhub.ports;
while (port_index--) {
- t1 = readl(port_array[port_index]);
+ t1 = readl(ports[port_index]->addr);
t1 = xhci_port_state_to_neutral(t1);
t2 = t1 & ~PORT_WAKE_BITS;
if (t1 != t2)
- writel(t2, port_array[port_index]);
+ writel(t2, ports[port_index]->addr);
}
/* disable usb2 ports Wake bits */
- port_index = xhci->num_usb2_ports;
- port_array = xhci->usb2_ports;
+ port_index = xhci->usb2_rhub.num_ports;
+ ports = xhci->usb2_rhub.ports;
while (port_index--) {
- t1 = readl(port_array[port_index]);
+ t1 = readl(ports[port_index]->addr);
t1 = xhci_port_state_to_neutral(t1);
t2 = t1 & ~PORT_WAKE_BITS;
if (t1 != t2)
- writel(t2, port_array[port_index]);
+ writel(t2, ports[port_index]->addr);
}
spin_unlock_irqrestore(&xhci->lock, flags);
@@ -1004,6 +1068,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
xhci_dbg(xhci, "Stop HCD\n");
xhci_halt(xhci);
+ xhci_zero_64b_regs(xhci);
xhci_reset(xhci);
spin_unlock_irq(&xhci->lock);
xhci_cleanup_msix(xhci);
@@ -3976,18 +4041,10 @@ static int xhci_enable_device(struct usb_hcd *hcd, struct usb_device *udev)
*/
int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1)
{
- struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- __le32 __iomem *base_addr = &xhci->op_regs->port_status_base;
- __le32 __iomem *addr;
- int raw_port;
+ struct xhci_hub *rhub;
- if (hcd->speed < HCD_USB3)
- addr = xhci->usb2_ports[port1 - 1];
- else
- addr = xhci->usb3_ports[port1 - 1];
-
- raw_port = (addr - base_addr)/NUM_PORT_REGS + 1;
- return raw_port;
+ rhub = xhci_get_rhub(hcd);
+ return rhub->ports[port1 - 1]->hw_portnum + 1;
}
/*
@@ -4120,7 +4177,7 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
struct usb_device *udev, int enable)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- __le32 __iomem **port_array;
+ struct xhci_port **ports;
__le32 __iomem *pm_addr, *hlpm_addr;
u32 pm_val, hlpm_val, field;
unsigned int port_num;
@@ -4141,11 +4198,11 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
spin_lock_irqsave(&xhci->lock, flags);
- port_array = xhci->usb2_ports;
+ ports = xhci->usb2_rhub.ports;
port_num = udev->portnum - 1;
- pm_addr = port_array[port_num] + PORTPMSC;
+ pm_addr = ports[port_num]->addr + PORTPMSC;
pm_val = readl(pm_addr);
- hlpm_addr = port_array[port_num] + PORTHLPMC;
+ hlpm_addr = ports[port_num]->addr + PORTHLPMC;
field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);
xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n",
@@ -4858,6 +4915,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
if (usb_hcd_is_primary_hcd(hcd)) {
xhci->main_hcd = hcd;
+ xhci->usb2_rhub.hcd = hcd;
/* Mark the first roothub as being USB 2.0.
* The xHCI driver will register the USB 3.0 roothub.
*/
@@ -4883,6 +4941,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
minor_rev,
minor_rev ? "Enhanced" : "");
+ xhci->usb3_rhub.hcd = hcd;
/* xHCI private pointer was set in xhci_pci_probe for the second
* registered roothub.
*/
@@ -4921,6 +4980,8 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
if (retval)
return retval;
+ xhci_zero_64b_regs(xhci);
+
xhci_dbg(xhci, "Resetting HCD\n");
/* Reset the internal HC memory state and registers. */
retval = xhci_reset(xhci);
@@ -4963,7 +5024,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
return retval;
xhci_dbg(xhci, "Called HCD init\n");
- xhci_info(xhci, "hcc params 0x%08x hci version 0x%x quirks 0x%08x\n",
+ xhci_info(xhci, "hcc params 0x%08x hci version 0x%x quirks 0x%016llx\n",
xhci->hcc_params, xhci->hci_version, xhci->quirks);
return 0;
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 6dfc486..939e2f86 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1683,13 +1683,23 @@ static inline unsigned int hcd_index(struct usb_hcd *hcd)
else
return 1;
}
+struct xhci_port {
+ __le32 __iomem *addr;
+ int hw_portnum;
+ int hcd_portnum;
+ struct xhci_hub *rhub;
+};
struct xhci_hub {
- u8 maj_rev;
- u8 min_rev;
- u32 *psi; /* array of protocol speed ID entries */
- u8 psi_count;
- u8 psi_uid_count;
+ struct xhci_port **ports;
+ unsigned int num_ports;
+ struct usb_hcd *hcd;
+ /* supported prococol extended capabiliy values */
+ u8 maj_rev;
+ u8 min_rev;
+ u32 *psi; /* array of protocol speed ID entries */
+ u8 psi_count;
+ u8 psi_uid_count;
};
/* There is one xhci_hcd structure per controller */
@@ -1787,12 +1797,12 @@ struct xhci_hcd {
#define XHCI_STATE_DYING (1 << 0)
#define XHCI_STATE_HALTED (1 << 1)
#define XHCI_STATE_REMOVING (1 << 2)
- unsigned int quirks;
-#define XHCI_LINK_TRB_QUIRK (1 << 0)
-#define XHCI_RESET_EP_QUIRK (1 << 1)
-#define XHCI_NEC_HOST (1 << 2)
-#define XHCI_AMD_PLL_FIX (1 << 3)
-#define XHCI_SPURIOUS_SUCCESS (1 << 4)
+ unsigned long long quirks;
+#define XHCI_LINK_TRB_QUIRK BIT_ULL(0)
+#define XHCI_RESET_EP_QUIRK BIT_ULL(1)
+#define XHCI_NEC_HOST BIT_ULL(2)
+#define XHCI_AMD_PLL_FIX BIT_ULL(3)
+#define XHCI_SPURIOUS_SUCCESS BIT_ULL(4)
/*
* Certain Intel host controllers have a limit to the number of endpoint
* contexts they can handle. Ideally, they would signal that they can't handle
@@ -1802,50 +1812,44 @@ struct xhci_hcd {
* commands, reset device commands, disable slot commands, and address device
* commands.
*/
-#define XHCI_EP_LIMIT_QUIRK (1 << 5)
-#define XHCI_BROKEN_MSI (1 << 6)
-#define XHCI_RESET_ON_RESUME (1 << 7)
-#define XHCI_SW_BW_CHECKING (1 << 8)
-#define XHCI_AMD_0x96_HOST (1 << 9)
-#define XHCI_TRUST_TX_LENGTH (1 << 10)
-#define XHCI_LPM_SUPPORT (1 << 11)
-#define XHCI_INTEL_HOST (1 << 12)
-#define XHCI_SPURIOUS_REBOOT (1 << 13)
-#define XHCI_COMP_MODE_QUIRK (1 << 14)
-#define XHCI_AVOID_BEI (1 << 15)
-#define XHCI_PLAT (1 << 16)
-#define XHCI_SLOW_SUSPEND (1 << 17)
-#define XHCI_SPURIOUS_WAKEUP (1 << 18)
+#define XHCI_EP_LIMIT_QUIRK BIT_ULL(5)
+#define XHCI_BROKEN_MSI BIT_ULL(6)
+#define XHCI_RESET_ON_RESUME BIT_ULL(7)
+#define XHCI_SW_BW_CHECKING BIT_ULL(8)
+#define XHCI_AMD_0x96_HOST BIT_ULL(9)
+#define XHCI_TRUST_TX_LENGTH BIT_ULL(10)
+#define XHCI_LPM_SUPPORT BIT_ULL(11)
+#define XHCI_INTEL_HOST BIT_ULL(12)
+#define XHCI_SPURIOUS_REBOOT BIT_ULL(13)
+#define XHCI_COMP_MODE_QUIRK BIT_ULL(14)
+#define XHCI_AVOID_BEI BIT_ULL(15)
+#define XHCI_PLAT BIT_ULL(16)
+#define XHCI_SLOW_SUSPEND BIT_ULL(17)
+#define XHCI_SPURIOUS_WAKEUP BIT_ULL(18)
/* For controllers with a broken beyond repair streams implementation */
-#define XHCI_BROKEN_STREAMS (1 << 19)
-#define XHCI_PME_STUCK_QUIRK (1 << 20)
-#define XHCI_MTK_HOST (1 << 21)
-#define XHCI_SSIC_PORT_UNUSED (1 << 22)
-#define XHCI_NO_64BIT_SUPPORT (1 << 23)
-#define XHCI_MISSING_CAS (1 << 24)
+#define XHCI_BROKEN_STREAMS BIT_ULL(19)
+#define XHCI_PME_STUCK_QUIRK BIT_ULL(20)
+#define XHCI_MTK_HOST BIT_ULL(21)
+#define XHCI_SSIC_PORT_UNUSED BIT_ULL(22)
+#define XHCI_NO_64BIT_SUPPORT BIT_ULL(23)
+#define XHCI_MISSING_CAS BIT_ULL(24)
/* For controller with a broken Port Disable implementation */
-#define XHCI_BROKEN_PORT_PED (1 << 25)
-#define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26)
-#define XHCI_U2_DISABLE_WAKE (1 << 27)
-#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)
+#define XHCI_BROKEN_PORT_PED BIT_ULL(25)
+#define XHCI_LIMIT_ENDPOINT_INTERVAL_7 BIT_ULL(26)
+#define XHCI_U2_DISABLE_WAKE BIT_ULL(27)
+#define XHCI_ASMEDIA_MODIFY_FLOWCONTROL BIT_ULL(28)
+#define XHCI_HW_LPM_DISABLE BIT_ULL(29)
+#define XHCI_SUSPEND_DELAY BIT_ULL(30)
+#define XHCI_INTEL_USB_ROLE_SW BIT_ULL(31)
+#define XHCI_ZERO_64B_REGS BIT_ULL(32)
unsigned int num_active_eps;
unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */
struct xhci_bus_state bus_state[2];
- /* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */
- u8 *port_array;
- /* Array of pointers to USB 3.0 PORTSC registers */
- __le32 __iomem **usb3_ports;
- unsigned int num_usb3_ports;
- /* Array of pointers to USB 2.0 PORTSC registers */
- __le32 __iomem **usb2_ports;
+ struct xhci_port *hw_ports;
struct xhci_hub usb2_rhub;
struct xhci_hub usb3_rhub;
- unsigned int num_usb2_ports;
/* support xHCI 0.96 spec USB2 software LPM */
unsigned sw_lpm_support:1;
/* support xHCI 1.0 spec USB2 hardware LPM */
@@ -2091,14 +2095,16 @@ void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring);
unsigned int count_trbs(u64 addr, u64 len);
/* xHCI roothub code */
-void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
- int port_id, u32 link_state);
-void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
- int port_id, u32 port_bit);
+void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,
+ u32 link_state);
+void xhci_test_and_clear_bit(struct xhci_hcd *xhci, struct xhci_port *port,
+ u32 port_bit);
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
char *buf, u16 wLength);
int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1);
+struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd);
+
void xhci_hc_died(struct xhci_hcd *xhci);
#ifdef CONFIG_PM
OpenPOWER on IntegriCloud