diff options
Diffstat (limited to 'drivers/usb/host')
34 files changed, 1158 insertions, 738 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 5d958da8e1bc..6e64d3a64dbb 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 8a8cffe0b445..9b669c9f9a48 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 3ed75aaa09d9..7619cfb06883 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 d927adf3afcd..89c47ae5c7d3 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-mem.c b/drivers/usb/host/ehci-mem.c index 4c6c08b675b5..21307d862af6 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -73,9 +73,10 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) if (!qh) goto done; qh->hw = (struct ehci_qh_hw *) - dma_pool_zalloc(ehci->qh_pool, flags, &dma); + dma_pool_alloc(ehci->qh_pool, flags, &dma); if (!qh->hw) goto fail; + memset(qh->hw, 0, sizeof *qh->hw); qh->qh_dma = dma; // INIT_LIST_HEAD (&qh->qh_list); INIT_LIST_HEAD (&qh->qtd_list); diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 8d8bafc70c1f..7e4c13346a1e 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-sched.c b/drivers/usb/host/ehci-sched.c index 28e2a338b481..e56db44708bc 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1287,7 +1287,7 @@ itd_urb_transaction( } else { alloc_itd: spin_unlock_irqrestore(&ehci->lock, flags); - itd = dma_pool_zalloc(ehci->itd_pool, mem_flags, + itd = dma_pool_alloc(ehci->itd_pool, mem_flags, &itd_dma); spin_lock_irqsave(&ehci->lock, flags); if (!itd) { @@ -1297,6 +1297,7 @@ itd_urb_transaction( } } + memset(itd, 0, sizeof(*itd)); itd->itd_dma = itd_dma; itd->frame = NO_FRAME; list_add(&itd->itd_list, &sched->td_list); @@ -2080,7 +2081,7 @@ sitd_urb_transaction( } else { alloc_sitd: spin_unlock_irqrestore(&ehci->lock, flags); - sitd = dma_pool_zalloc(ehci->sitd_pool, mem_flags, + sitd = dma_pool_alloc(ehci->sitd_pool, mem_flags, &sitd_dma); spin_lock_irqsave(&ehci->lock, flags); if (!sitd) { @@ -2090,6 +2091,7 @@ sitd_urb_transaction( } } + memset(sitd, 0, sizeof(*sitd)); sitd->sitd_dma = sitd_dma; sitd->frame = NO_FRAME; list_add(&sitd->sitd_list, &iso_sched->td_list); diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index a6f4389f7e88..4d2cdec4cb78 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 ebf9bb219f75..100048b3bd17 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 e7ec41d62410..2ce5031d866d 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 d8abf401918a..e64eb47770c8 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 a213ed6f07b5..7fcf1d9dd7f3 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 4602ed801f0a..74da136d322a 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 5ad9e9bdc8ee..e98673954020 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 ac7d4ac34b02..d3ee1f52aaab 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 4806e0f9e8d4..210181fd98d2 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 508a803139dd..ef4813bfc5bf 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 67ad4bb6919a..3625a5c1a41b 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 4ca0d9b7e463..63c633077d9e 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 f9c3947577fc..6218bfe54f52 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 c359bae7b754..1fbfd89d0a0f 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 e66ea0748ba3..ce0c6072bd48 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 48779c44c361..aff79ff5aba4 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 * @@ -320,9 +321,11 @@ int xhci_dbc_tty_register_driver(struct xhci_hcd *xhci) void xhci_dbc_tty_unregister_driver(void) { - tty_unregister_driver(dbc_tty_driver); - put_tty_driver(dbc_tty_driver); - dbc_tty_driver = NULL; + if (dbc_tty_driver) { + tty_unregister_driver(dbc_tty_driver); + put_tty_driver(dbc_tty_driver); + dbc_tty_driver = NULL; + } } static void dbc_rx_push(unsigned long _port) diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c index 5851052d4668..cadc01336bf8 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 000000000000..27f00160332e --- /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 72ebbc908e19..a4b95d019f84 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); } @@ -354,7 +357,7 @@ int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci, slot_id = 0; for (i = 0; i < MAX_HC_SLOTS; i++) { - if (!xhci->devs[i]) + if (!xhci->devs[i] || !xhci->devs[i]->udev) continue; speed = xhci->devs[i]->udev->speed; if (((speed >= USB_SPEED_SUPER) == (hcd->speed >= HCD_USB3)) @@ -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 e5ace8995b3b..4fe74711938e 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 eea7360a18fc..fa33d6e5b1cb 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 f17b7eab66cf..6372edf339d9 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -126,7 +126,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info()) xhci->quirks |= XHCI_AMD_PLL_FIX; - if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x43bb) + if (pdev->vendor == PCI_VENDOR_ID_AMD && + (pdev->device == 0x15e0 || + pdev->device == 0x15e1 || + pdev->device == 0x43bb)) xhci->quirks |= XHCI_SUSPEND_DELAY; if (pdev->vendor == PCI_VENDOR_ID_AMD) @@ -193,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; @@ -281,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-plat.c b/drivers/usb/host/xhci-plat.c index df327dcc2bac..c1b22fc64e38 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -157,6 +157,7 @@ static int xhci_plat_probe(struct platform_device *pdev) struct resource *res; struct usb_hcd *hcd; struct clk *clk; + struct clk *reg_clk; int ret; int irq; @@ -226,17 +227,27 @@ static int xhci_plat_probe(struct platform_device *pdev) hcd->rsrc_len = resource_size(res); /* - * Not all platforms have a clk so it is not an error if the - * clock does not exists. + * Not all platforms have clks so it is not an error if the + * clock do not exist. */ + reg_clk = devm_clk_get(&pdev->dev, "reg"); + if (!IS_ERR(reg_clk)) { + ret = clk_prepare_enable(reg_clk); + if (ret) + goto put_hcd; + } else if (PTR_ERR(reg_clk) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto put_hcd; + } + clk = devm_clk_get(&pdev->dev, NULL); if (!IS_ERR(clk)) { ret = clk_prepare_enable(clk); if (ret) - goto put_hcd; + goto disable_reg_clk; } else if (PTR_ERR(clk) == -EPROBE_DEFER) { ret = -EPROBE_DEFER; - goto put_hcd; + goto disable_reg_clk; } xhci = hcd_to_xhci(hcd); @@ -252,6 +263,7 @@ static int xhci_plat_probe(struct platform_device *pdev) device_wakeup_enable(hcd->self.controller); xhci->clk = clk; + xhci->reg_clk = reg_clk; xhci->main_hcd = hcd; xhci->shared_hcd = __usb_create_hcd(driver, sysdev, &pdev->dev, dev_name(&pdev->dev), hcd); @@ -320,8 +332,10 @@ put_usb3_hcd: usb_put_hcd(xhci->shared_hcd); disable_clk: - if (!IS_ERR(clk)) - clk_disable_unprepare(clk); + clk_disable_unprepare(clk); + +disable_reg_clk: + clk_disable_unprepare(reg_clk); put_hcd: usb_put_hcd(hcd); @@ -338,6 +352,7 @@ static int xhci_plat_remove(struct platform_device *dev) struct usb_hcd *hcd = platform_get_drvdata(dev); struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct clk *clk = xhci->clk; + struct clk *reg_clk = xhci->reg_clk; xhci->xhc_state |= XHCI_STATE_REMOVING; @@ -347,8 +362,8 @@ static int xhci_plat_remove(struct platform_device *dev) usb_remove_hcd(hcd); usb_put_hcd(xhci->shared_hcd); - if (!IS_ERR(clk)) - clk_disable_unprepare(clk); + clk_disable_unprepare(clk); + clk_disable_unprepare(reg_clk); usb_put_hcd(hcd); pm_runtime_set_suspended(&dev->dev); @@ -420,7 +435,6 @@ MODULE_DEVICE_TABLE(acpi, usb_xhci_acpi_match); static struct platform_driver usb_xhci_driver = { .probe = xhci_plat_probe, .remove = xhci_plat_remove, - .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "xhci-hcd", .pm = &xhci_plat_pm_ops, diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 91a1a824673d..f0a99aa0ac58 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 2c076ea80522..a8c1d073cba0 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 9b27798ecce5..8c8da2d657fa 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); @@ -3621,6 +3686,7 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) del_timer_sync(&virt_dev->eps[i].stop_cmd_timer); } xhci_debugfs_remove_slot(xhci, udev->slot_id); + virt_dev->udev = NULL; ret = xhci_disable_slot(xhci, udev->slot_id); if (ret) xhci_free_virt_device(xhci, udev->slot_id); @@ -3975,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; } /* @@ -4119,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; @@ -4140,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", @@ -4857,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. */ @@ -4882,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. */ @@ -4920,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); @@ -4962,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 05c909b04f14..939e2f86b595 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 */ @@ -1729,8 +1739,9 @@ struct xhci_hcd { int page_shift; /* msi-x vectors */ int msix_count; - /* optional clock */ + /* optional clocks */ struct clk *clk; + struct clk *reg_clk; /* data structures */ struct xhci_device_context_array *dcbaa; struct xhci_ring *cmd_ring; @@ -1786,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 @@ -1801,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 */ @@ -2090,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 |