aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--drivers/usb/host/Kconfig8
-rw-r--r--drivers/usb/host/Makefile3
-rw-r--r--drivers/usb/host/ehci-exynos.c2
-rw-r--r--drivers/usb/host/ehci-mem.c2
-rw-r--r--drivers/usb/host/ehci-msm.c2
-rw-r--r--drivers/usb/host/ehci-pci.c25
-rw-r--r--drivers/usb/host/ehci-spear.c2
-rw-r--r--drivers/usb/host/ehci-tegra.c67
-rw-r--r--drivers/usb/host/fhci-dbg.c8
-rw-r--r--drivers/usb/host/fotg210-hcd.c48
-rw-r--r--drivers/usb/host/max3421-hcd.c48
-rw-r--r--drivers/usb/host/ohci-dbg.c9
-rw-r--r--drivers/usb/host/ohci-exynos.c2
-rw-r--r--drivers/usb/host/ohci-hcd.c381
-rw-r--r--drivers/usb/host/ohci-hub.c11
-rw-r--r--drivers/usb/host/ohci-mem.c1
-rw-r--r--drivers/usb/host/ohci-q.c262
-rw-r--r--drivers/usb/host/ohci-spear.c2
-rw-r--r--drivers/usb/host/ohci.h23
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c48
-rw-r--r--drivers/usb/host/uhci-grlib.c31
-rw-r--r--drivers/usb/host/uhci-hcd.c2
-rw-r--r--drivers/usb/host/uhci-platform.c22
-rw-r--r--drivers/usb/host/xhci-pci.c8
-rw-r--r--drivers/usb/host/xhci-plat.c52
-rw-r--r--drivers/usb/host/xhci-rcar.c148
-rw-r--r--drivers/usb/host/xhci-rcar.h27
-rw-r--r--drivers/usb/host/xhci-ring.c4
-rw-r--r--drivers/usb/host/xhci.c160
-rw-r--r--drivers/usb/host/xhci.h2
30 files changed, 873 insertions, 537 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 03314f861bee..82800a775501 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -37,6 +37,14 @@ config USB_XHCI_MVEBU
Say 'Y' to enable the support for the xHCI host controller
found in Marvell Armada 375/38x ARM SOCs.
+config USB_XHCI_RCAR
+ tristate "xHCI support for Renesas R-Car SoCs"
+ select USB_XHCI_PLATFORM
+ depends on ARCH_SHMOBILE || COMPILE_TEST
+ ---help---
+ Say 'Y' to enable the support for the xHCI host controller
+ found in Renesas R-Car ARM SoCs.
+
endif # USB_XHCI_HCD
config USB_EHCI_HCD
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index af89a903d97e..144c038ef70f 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -22,6 +22,9 @@ ifneq ($(CONFIG_USB_XHCI_PLATFORM), )
ifneq ($(CONFIG_USB_XHCI_MVEBU), )
xhci-hcd-y += xhci-mvebu.o
endif
+ifneq ($(CONFIG_USB_XHCI_RCAR), )
+ xhci-hcd-y += xhci-rcar.o
+endif
endif
obj-$(CONFIG_USB_WHCI_HCD) += whci/
diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c
index d1c76216350f..cda0a2f5c467 100644
--- a/drivers/usb/host/ehci-exynos.c
+++ b/drivers/usb/host/ehci-exynos.c
@@ -88,7 +88,7 @@ static int exynos_ehci_get_phy(struct device *dev,
return -EINVAL;
}
- phy = devm_of_phy_get(dev, child, 0);
+ phy = devm_of_phy_get(dev, child, NULL);
of_node_put(child);
if (IS_ERR(phy)) {
ret = PTR_ERR(phy);
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index c0fb6a8ae6a3..b6205fac3567 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -209,7 +209,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
ehci->periodic = (__le32 *)
dma_alloc_coherent (ehci_to_hcd(ehci)->self.controller,
ehci->periodic_size * sizeof(__le32),
- &ehci->periodic_dma, 0);
+ &ehci->periodic_dma, flags);
if (ehci->periodic == NULL) {
goto fail;
}
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 982c09bebe0f..934b39d5e44a 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -190,7 +190,7 @@ static const struct dev_pm_ops ehci_msm_dev_pm_ops = {
.resume = ehci_msm_pm_resume,
};
-static struct of_device_id msm_ehci_dt_match[] = {
+static const struct of_device_id msm_ehci_dt_match[] = {
{ .compatible = "qcom,ehci-host", },
{}
};
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 3e86bf4371b3..ca7b964124af 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -35,6 +35,21 @@ static const char hcd_name[] = "ehci-pci";
#define PCI_DEVICE_ID_INTEL_CE4100_USB 0x2e70
/*-------------------------------------------------------------------------*/
+#define PCI_DEVICE_ID_INTEL_QUARK_X1000_SOC 0x0939
+static inline bool is_intel_quark_x1000(struct pci_dev *pdev)
+{
+ return pdev->vendor == PCI_VENDOR_ID_INTEL &&
+ pdev->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_SOC;
+}
+
+/*
+ * 0x84 is the offset of in/out threshold register,
+ * and it is the same offset as the register of 'hostpc'.
+ */
+#define intel_quark_x1000_insnreg01 hostpc
+
+/* Maximum usable threshold value is 0x7f dwords for both IN and OUT */
+#define INTEL_QUARK_X1000_EHCI_MAX_THRESHOLD 0x007f007f
/* called after powerup, by probe or system-pm "wakeup" */
static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
@@ -50,6 +65,16 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
if (!retval)
ehci_dbg(ehci, "MWI active\n");
+ /* Reset the threshold limit */
+ if (is_intel_quark_x1000(pdev)) {
+ /*
+ * For the Intel QUARK X1000, raise the I/O threshold to the
+ * maximum usable value in order to improve performance.
+ */
+ ehci_writel(ehci, INTEL_QUARK_X1000_EHCI_MAX_THRESHOLD,
+ ehci->regs->intel_quark_x1000_insnreg01);
+ }
+
return 0;
}
diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c
index 1d59958ad0ce..1355ff0946b9 100644
--- a/drivers/usb/host/ehci-spear.c
+++ b/drivers/usb/host/ehci-spear.c
@@ -150,7 +150,7 @@ static int spear_ehci_hcd_drv_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id spear_ehci_id_table[] = {
+static const struct of_device_id spear_ehci_id_table[] = {
{ .compatible = "st,spear600-ehci", },
{ },
};
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 6fdcb8ad2296..7aafb05e7a40 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -46,6 +46,7 @@
#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;
@@ -60,6 +61,61 @@ 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;
+
+ phy_np = of_parse_phandle(pdev->dev.of_node, "nvidia,phy", 0);
+ if (!phy_np)
+ return -ENOENT;
+
+ if (!usb1_reset_attempted) {
+ struct reset_control *usb1_reset;
+
+ usb1_reset = of_reset_control_get(phy_np, "usb");
+ 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);
+ }
+
+ reset_control_put(usb1_reset);
+ usb1_reset_attempted = true;
+ }
+
+ if (!of_property_read_bool(phy_np, "nvidia,has-utmi-pad-registers")) {
+ reset_control_assert(tegra->rst);
+ udelay(1);
+ reset_control_deassert(tegra->rst);
+ }
+
+ of_node_put(phy_np);
+
+ return 0;
+}
+
static int tegra_ehci_internal_port_reset(
struct ehci_hcd *ehci,
u32 __iomem *portsc_reg
@@ -326,7 +382,7 @@ static const struct tegra_ehci_soc_config tegra20_soc_config = {
.has_hostpc = false,
};
-static struct of_device_id tegra_ehci_of_match[] = {
+static const struct of_device_id tegra_ehci_of_match[] = {
{ .compatible = "nvidia,tegra30-ehci", .data = &tegra30_soc_config },
{ .compatible = "nvidia,tegra20-ehci", .data = &tegra20_soc_config },
{ },
@@ -389,9 +445,9 @@ static int tegra_ehci_probe(struct platform_device *pdev)
if (err)
goto cleanup_hcd_create;
- reset_control_assert(tegra->rst);
- udelay(1);
- reset_control_deassert(tegra->rst);
+ err = tegra_reset_usb_controller(pdev);
+ if (err)
+ goto cleanup_clk_en;
u_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0);
if (IS_ERR(u_phy)) {
@@ -479,10 +535,11 @@ static int tegra_ehci_remove(struct platform_device *pdev)
usb_phy_shutdown(hcd->phy);
usb_remove_hcd(hcd);
- usb_put_hcd(hcd);
clk_disable_unprepare(tegra->clk);
+ usb_put_hcd(hcd);
+
return 0;
}
diff --git a/drivers/usb/host/fhci-dbg.c b/drivers/usb/host/fhci-dbg.c
index f238cb37305c..b58e7a60913a 100644
--- a/drivers/usb/host/fhci-dbg.c
+++ b/drivers/usb/host/fhci-dbg.c
@@ -129,11 +129,7 @@ void fhci_dfs_destroy(struct fhci_hcd *fhci)
if (!fhci->dfs_root)
return;
- if (fhci->dfs_irq_stat)
- debugfs_remove(fhci->dfs_irq_stat);
-
- if (fhci->dfs_regs)
- debugfs_remove(fhci->dfs_regs);
-
+ debugfs_remove(fhci->dfs_irq_stat);
+ debugfs_remove(fhci->dfs_regs);
debugfs_remove(fhci->dfs_root);
}
diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c
index 98a89d16cc3e..adcd2050dced 100644
--- a/drivers/usb/host/fotg210-hcd.c
+++ b/drivers/usb/host/fotg210-hcd.c
@@ -5838,41 +5838,17 @@ static int fotg210_hcd_probe(struct platform_device *pdev)
goto fail_create_hcd;
}
+ hcd->has_tt = 1;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev,
- "Found HC with no register addr. Check %s setup!\n",
- dev_name(dev));
- retval = -ENODEV;
- goto fail_request_resource;
+ hcd->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(hcd->regs)) {
+ retval = PTR_ERR(hcd->regs);
+ goto failed;
}
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
- hcd->has_tt = 1;
-
- if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
- fotg210_fotg210_hc_driver.description)) {
- dev_dbg(dev, "controller already in use\n");
- retval = -EBUSY;
- goto fail_request_resource;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (!res) {
- dev_err(dev,
- "Found HC with no register addr. Check %s setup!\n",
- dev_name(dev));
- retval = -ENODEV;
- goto fail_request_resource;
- }
-
- hcd->regs = ioremap_nocache(res->start, resource_size(res));
- if (hcd->regs == NULL) {
- dev_dbg(dev, "error mapping memory\n");
- retval = -EFAULT;
- goto fail_ioremap;
- }
fotg210 = hcd_to_fotg210(hcd);
@@ -5880,24 +5856,20 @@ static int fotg210_hcd_probe(struct platform_device *pdev)
retval = fotg210_setup(hcd);
if (retval)
- goto fail_add_hcd;
+ goto failed;
fotg210_init(fotg210);
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval) {
dev_err(dev, "failed to add hcd with err %d\n", retval);
- goto fail_add_hcd;
+ goto failed;
}
device_wakeup_enable(hcd->self.controller);
return retval;
-fail_add_hcd:
- iounmap(hcd->regs);
-fail_ioremap:
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-fail_request_resource:
+failed:
usb_put_hcd(hcd);
fail_create_hcd:
dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval);
@@ -5918,8 +5890,6 @@ static int fotg210_hcd_remove(struct platform_device *pdev)
return 0;
usb_remove_hcd(hcd);
- iounmap(hcd->regs);
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
return 0;
diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c
index 858efcfda50b..6234c75da33f 100644
--- a/drivers/usb/host/max3421-hcd.c
+++ b/drivers/usb/host/max3421-hcd.c
@@ -102,6 +102,15 @@ enum scheduling_pass {
SCHED_PASS_DONE
};
+/* Bit numbers for max3421_hcd->todo: */
+enum {
+ ENABLE_IRQ = 0,
+ RESET_HCD,
+ RESET_PORT,
+ CHECK_UNLINK,
+ IOPIN_UPDATE
+};
+
struct max3421_dma_buf {
u8 data[2];
};
@@ -146,11 +155,7 @@ struct max3421_hcd {
u8 hien;
u8 mode;
u8 iopins[2];
- unsigned int do_enable_irq:1;
- unsigned int do_reset_hcd:1;
- unsigned int do_reset_port:1;
- unsigned int do_check_unlink:1;
- unsigned int do_iopin_update:1;
+ unsigned long todo;
#ifdef DEBUG
unsigned long err_stat[16];
#endif
@@ -1165,10 +1170,8 @@ max3421_irq_handler(int irq, void *dev_id)
if (max3421_hcd->spi_thread &&
max3421_hcd->spi_thread->state != TASK_RUNNING)
wake_up_process(max3421_hcd->spi_thread);
- if (!max3421_hcd->do_enable_irq) {
- max3421_hcd->do_enable_irq = 1;
+ if (!test_and_set_bit(ENABLE_IRQ, &max3421_hcd->todo))
disable_irq_nosync(spi->irq);
- }
return IRQ_HANDLED;
}
@@ -1423,10 +1426,8 @@ max3421_spi_thread(void *dev_id)
spi_wr8(hcd, MAX3421_REG_HIEN, max3421_hcd->hien);
set_current_state(TASK_INTERRUPTIBLE);
- if (max3421_hcd->do_enable_irq) {
- max3421_hcd->do_enable_irq = 0;
+ if (test_and_clear_bit(ENABLE_IRQ, &max3421_hcd->todo))
enable_irq(spi->irq);
- }
schedule();
__set_current_state(TASK_RUNNING);
}
@@ -1440,23 +1441,18 @@ max3421_spi_thread(void *dev_id)
else if (!max3421_hcd->curr_urb)
i_worked |= max3421_select_and_start_urb(hcd);
- if (max3421_hcd->do_reset_hcd) {
+ if (test_and_clear_bit(RESET_HCD, &max3421_hcd->todo))
/* reset the HCD: */
- max3421_hcd->do_reset_hcd = 0;
i_worked |= max3421_reset_hcd(hcd);
- }
- if (max3421_hcd->do_reset_port) {
+ if (test_and_clear_bit(RESET_PORT, &max3421_hcd->todo)) {
/* perform a USB bus reset: */
- max3421_hcd->do_reset_port = 0;
spi_wr8(hcd, MAX3421_REG_HCTL,
BIT(MAX3421_HCTL_BUSRST_BIT));
i_worked = 1;
}
- if (max3421_hcd->do_check_unlink) {
- max3421_hcd->do_check_unlink = 0;
+ if (test_and_clear_bit(CHECK_UNLINK, &max3421_hcd->todo))
i_worked |= max3421_check_unlink(hcd);
- }
- if (max3421_hcd->do_iopin_update) {
+ if (test_and_clear_bit(IOPIN_UPDATE, &max3421_hcd->todo)) {
/*
* IOPINS1/IOPINS2 do not auto-increment, so we can't
* use spi_wr_buf().
@@ -1469,7 +1465,6 @@ max3421_spi_thread(void *dev_id)
spi_wr8(hcd, MAX3421_REG_IOPINS1 + i, val);
max3421_hcd->iopins[i] = val;
}
- max3421_hcd->do_iopin_update = 0;
i_worked = 1;
}
}
@@ -1485,7 +1480,8 @@ max3421_reset_port(struct usb_hcd *hcd)
max3421_hcd->port_status &= ~(USB_PORT_STAT_ENABLE |
USB_PORT_STAT_LOW_SPEED);
- max3421_hcd->do_reset_port = 1;
+ max3421_hcd->port_status |= USB_PORT_STAT_RESET;
+ set_bit(RESET_PORT, &max3421_hcd->todo);
wake_up_process(max3421_hcd->spi_thread);
return 0;
}
@@ -1498,7 +1494,7 @@ max3421_reset(struct usb_hcd *hcd)
hcd->self.sg_tablesize = 0;
hcd->speed = HCD_USB2;
hcd->self.root_hub->speed = USB_SPEED_FULL;
- max3421_hcd->do_reset_hcd = 1;
+ set_bit(RESET_HCD, &max3421_hcd->todo);
wake_up_process(max3421_hcd->spi_thread);
return 0;
}
@@ -1551,7 +1547,7 @@ max3421_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
max3421_ep = urb->ep->hcpriv;
if (!max3421_ep) {
/* gets freed in max3421_endpoint_disable: */
- max3421_ep = kzalloc(sizeof(struct max3421_ep), mem_flags);
+ max3421_ep = kzalloc(sizeof(struct max3421_ep), GFP_ATOMIC);
if (!max3421_ep) {
retval = -ENOMEM;
goto out;
@@ -1590,7 +1586,7 @@ max3421_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
*/
retval = usb_hcd_check_unlink_urb(hcd, urb, status);
if (retval == 0) {
- max3421_hcd->do_check_unlink = 1;
+ set_bit(CHECK_UNLINK, &max3421_hcd->todo);
wake_up_process(max3421_hcd->spi_thread);
}
spin_unlock_irqrestore(&max3421_hcd->lock, flags);
@@ -1690,7 +1686,7 @@ max3421_gpout_set_value(struct usb_hcd *hcd, u8 pin_number, u8 value)
max3421_hcd->iopins[idx] |= mask;
else
max3421_hcd->iopins[idx] &= ~mask;
- max3421_hcd->do_iopin_update = 1;
+ set_bit(IOPIN_UPDATE, &max3421_hcd->todo);
wake_up_process(max3421_hcd->spi_thread);
}
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index 45032e933e18..04f2186939d2 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -236,7 +236,7 @@ ohci_dump_roothub (
}
}
-static void ohci_dump (struct ohci_hcd *controller, int verbose)
+static void ohci_dump(struct ohci_hcd *controller)
{
ohci_dbg (controller, "OHCI controller state\n");
@@ -464,15 +464,16 @@ show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed)
static ssize_t fill_async_buffer(struct debug_buffer *buf)
{
struct ohci_hcd *ohci;
- size_t temp;
+ size_t temp, size;
unsigned long flags;
ohci = buf->ohci;
+ size = PAGE_SIZE;
/* display control and bulk lists together, for simplicity */
spin_lock_irqsave (&ohci->lock, flags);
- temp = show_list(ohci, buf->page, buf->count, ohci->ed_controltail);
- temp += show_list(ohci, buf->page + temp, buf->count - temp,
+ temp = show_list(ohci, buf->page, size, ohci->ed_controltail);
+ temp += show_list(ohci, buf->page + temp, size - temp,
ohci->ed_bulktail);
spin_unlock_irqrestore (&ohci->lock, flags);
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index 060a6a414750..a72ab8fe8cd3 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -87,7 +87,7 @@ static int exynos_ohci_get_phy(struct device *dev,
return -EINVAL;
}
- phy = devm_of_phy_get(dev, child, 0);
+ phy = devm_of_phy_get(dev, child, NULL);
of_node_put(child);
if (IS_ERR(phy)) {
ret = PTR_ERR(phy);
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index f98d03f3144c..46987735a2e3 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -72,12 +72,14 @@
static const char hcd_name [] = "ohci_hcd";
#define STATECHANGE_DELAY msecs_to_jiffies(300)
+#define IO_WATCHDOG_DELAY msecs_to_jiffies(250)
#include "ohci.h"
#include "pci-quirks.h"
-static void ohci_dump (struct ohci_hcd *ohci, int verbose);
-static void ohci_stop (struct usb_hcd *hcd);
+static void ohci_dump(struct ohci_hcd *ohci);
+static void ohci_stop(struct usb_hcd *hcd);
+static void io_watchdog_func(unsigned long _ohci);
#include "ohci-hub.c"
#include "ohci-dbg.c"
@@ -109,6 +111,33 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake");
/*-------------------------------------------------------------------------*/
+static int number_of_tds(struct urb *urb)
+{
+ int len, i, num, this_sg_len;
+ struct scatterlist *sg;
+
+ len = urb->transfer_buffer_length;
+ i = urb->num_mapped_sgs;
+
+ if (len > 0 && i > 0) { /* Scatter-gather transfer */
+ num = 0;
+ sg = urb->sg;
+ for (;;) {
+ this_sg_len = min_t(int, sg_dma_len(sg), len);
+ num += DIV_ROUND_UP(this_sg_len, 4096);
+ len -= this_sg_len;
+ if (--i <= 0 || len <= 0)
+ break;
+ sg = sg_next(sg);
+ }
+
+ } else { /* Non-SG transfer */
+ /* one TD for every 4096 Bytes (could be up to 8K) */
+ num = DIV_ROUND_UP(len, 4096);
+ }
+ return num;
+}
+
/*
* queue up an urb for anything except the root hub
*/
@@ -142,12 +171,8 @@ static int ohci_urb_enqueue (
// case PIPE_INTERRUPT:
// case PIPE_BULK:
default:
- /* one TD for every 4096 Bytes (can be up to 8K) */
- size += urb->transfer_buffer_length / 4096;
- /* ... and for any remaining bytes ... */
- if ((urb->transfer_buffer_length % 4096) != 0)
- size++;
- /* ... and maybe a zero length packet to wrap it up */
+ size += number_of_tds(urb);
+ /* maybe a zero-length packet to wrap it up */
if (size == 0)
size++;
else if ((urb->transfer_flags & URB_ZERO_PACKET) != 0
@@ -202,6 +227,16 @@ static int ohci_urb_enqueue (
usb_hcd_unlink_urb_from_ep(hcd, urb);
goto fail;
}
+
+ /* Start up the I/O watchdog timer, if it's not running */
+ if (!timer_pending(&ohci->io_watchdog) &&
+ list_empty(&ohci->eds_in_use)) {
+ ohci->prev_frame_no = ohci_frame_no(ohci);
+ mod_timer(&ohci->io_watchdog,
+ jiffies + IO_WATCHDOG_DELAY);
+ }
+ list_add(&ed->in_use_list, &ohci->eds_in_use);
+
if (ed->type == PIPE_ISOCHRONOUS) {
u16 frame = ohci_frame_no(ohci);
@@ -277,30 +312,24 @@ static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
unsigned long flags;
int rc;
+ urb_priv_t *urb_priv;
spin_lock_irqsave (&ohci->lock, flags);
rc = usb_hcd_check_unlink_urb(hcd, urb, status);
- if (rc) {
- ; /* Do nothing */
- } else if (ohci->rh_state == OHCI_RH_RUNNING) {
- urb_priv_t *urb_priv;
+ if (rc == 0) {
/* Unless an IRQ completed the unlink while it was being
* handed to us, flag it for unlink and giveback, and force
* some upcoming INTR_SF to call finish_unlinks()
*/
urb_priv = urb->hcpriv;
- if (urb_priv) {
- if (urb_priv->ed->state == ED_OPER)
- start_ed_unlink (ohci, urb_priv->ed);
+ if (urb_priv->ed->state == ED_OPER)
+ start_ed_unlink(ohci, urb_priv->ed);
+
+ if (ohci->rh_state != OHCI_RH_RUNNING) {
+ /* With HC dead, we can clean up right away */
+ ohci_work(ohci);
}
- } else {
- /*
- * with HC dead, we won't respect hc queue pointers
- * any more ... just clean up every urb's memory.
- */
- if (urb->hcpriv)
- finish_urb(ohci, urb, status);
}
spin_unlock_irqrestore (&ohci->lock, flags);
return rc;
@@ -332,9 +361,7 @@ rescan:
if (ohci->rh_state != OHCI_RH_RUNNING) {
sanitize:
ed->state = ED_IDLE;
- if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
- ohci->eds_scheduled--;
- finish_unlinks (ohci, 0);
+ ohci_work(ohci);
}
switch (ed->state) {
@@ -342,11 +369,6 @@ sanitize:
/* major IRQ delivery trouble loses INTR_SF too... */
if (limit-- == 0) {
ohci_warn(ohci, "ED unlink timeout\n");
- if (quirk_zfmicro(ohci)) {
- ohci_warn(ohci, "Attempting ZF TD recovery\n");
- ohci->ed_to_check = ed;
- ohci->zf_delay = 2;
- }
goto sanitize;
}
spin_unlock_irqrestore (&ohci->lock, flags);
@@ -406,93 +428,7 @@ ohci_shutdown (struct usb_hcd *hcd)
udelay(10);
ohci_writel(ohci, ohci->fminterval, &ohci->regs->fminterval);
-}
-
-static int check_ed(struct ohci_hcd *ohci, struct ed *ed)
-{
- return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0
- && (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK)
- == (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK)
- && !list_empty(&ed->td_list);
-}
-
-/* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes
- * an interrupt TD but neglects to add it to the donelist. On systems with
- * this chipset, we need to periodically check the state of the queues to look
- * for such "lost" TDs.
- */
-static void unlink_watchdog_func(unsigned long _ohci)
-{
- unsigned long flags;
- unsigned max;
- unsigned seen_count = 0;
- unsigned i;
- struct ed **seen = NULL;
- struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci;
-
- spin_lock_irqsave(&ohci->lock, flags);
- max = ohci->eds_scheduled;
- if (!max)
- goto done;
-
- if (ohci->ed_to_check)
- goto out;
-
- seen = kcalloc(max, sizeof *seen, GFP_ATOMIC);
- if (!seen)
- goto out;
-
- for (i = 0; i < NUM_INTS; i++) {
- struct ed *ed = ohci->periodic[i];
-
- while (ed) {
- unsigned temp;
-
- /* scan this branch of the periodic schedule tree */
- for (temp = 0; temp < seen_count; temp++) {
- if (seen[temp] == ed) {
- /* we've checked it and what's after */
- ed = NULL;
- break;
- }
- }
- if (!ed)
- break;
- seen[seen_count++] = ed;
- if (!check_ed(ohci, ed)) {
- ed = ed->ed_next;
- continue;
- }
-
- /* HC's TD list is empty, but HCD sees at least one
- * TD that's not been sent through the donelist.
- */
- ohci->ed_to_check = ed;
- ohci->zf_delay = 2;
-
- /* The HC may wait until the next frame to report the
- * TD as done through the donelist and INTR_WDH. (We
- * just *assume* it's not a multi-TD interrupt URB;
- * those could defer the IRQ more than one frame, using
- * DI...) Check again after the next INTR_SF.
- */
- ohci_writel(ohci, OHCI_INTR_SF,
- &ohci->regs->intrstatus);
- ohci_writel(ohci, OHCI_INTR_SF,
- &ohci->regs->intrenable);
-
- /* flush those writes */
- (void) ohci_readl(ohci, &ohci->regs->control);
-
- goto out;
- }
- }
-out:
- kfree(seen);
- if (ohci->eds_scheduled)
- mod_timer(&ohci->unlink_watchdog, round_jiffies(jiffies + HZ));
-done:
- spin_unlock_irqrestore(&ohci->lock, flags);
+ ohci->rh_state = OHCI_RH_HALTED;
}
/*-------------------------------------------------------------------------*
@@ -506,6 +442,9 @@ static int ohci_init (struct ohci_hcd *ohci)
int ret;
struct usb_hcd *hcd = ohci_to_hcd(ohci);
+ /* Accept arbitrarily long scatter-gather lists */
+ hcd->self.sg_tablesize = ~0;
+
if (distrust_firmware)
ohci->flags |= OHCI_QUIRK_HUB_POWER;
@@ -558,8 +497,12 @@ static int ohci_init (struct ohci_hcd *ohci)
if (ohci->hcca)
return 0;
+ setup_timer(&ohci->io_watchdog, io_watchdog_func,
+ (unsigned long) ohci);
+ set_timer_slack(&ohci->io_watchdog, msecs_to_jiffies(20));
+
ohci->hcca = dma_alloc_coherent (hcd->self.controller,
- sizeof *ohci->hcca, &ohci->hcca_dma, 0);
+ sizeof(*ohci->hcca), &ohci->hcca_dma, GFP_KERNEL);
if (!ohci->hcca)
return -ENOMEM;
@@ -735,16 +678,7 @@ retry:
// POTPGT delay is bits 24-31, in 2 ms units.
mdelay ((val >> 23) & 0x1fe);
- if (quirk_zfmicro(ohci)) {
- /* Create timer to watch for bad queue state on ZF Micro */
- setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func,
- (unsigned long) ohci);
-
- ohci->eds_scheduled = 0;
- ohci->ed_to_check = NULL;
- }
-
- ohci_dump (ohci, 1);
+ ohci_dump(ohci);
return 0;
}
@@ -777,6 +711,142 @@ static int ohci_start(struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
+/*
+ * Some OHCI controllers are known to lose track of completed TDs. They
+ * don't add the TDs to the hardware done queue, which means we never see
+ * them as being completed.
+ *
+ * This watchdog routine checks for such problems. Without some way to
+ * tell when those TDs have completed, we would never take their EDs off
+ * the unlink list. As a result, URBs could never be dequeued and
+ * endpoints could never be released.
+ */
+static void io_watchdog_func(unsigned long _ohci)
+{
+ struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci;
+ bool takeback_all_pending = false;
+ u32 status;
+ u32 head;
+ struct ed *ed;
+ struct td *td, *td_start, *td_next;
+ unsigned frame_no;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ohci->lock, flags);
+
+ /*
+ * One way to lose track of completed TDs is if the controller
+ * never writes back the done queue head. If it hasn't been
+ * written back since the last time this function ran and if it
+ * was non-empty at that time, something is badly wrong with the
+ * hardware.
+ */
+ status = ohci_readl(ohci, &ohci->regs->intrstatus);
+ if (!(status & OHCI_INTR_WDH) && ohci->wdh_cnt == ohci->prev_wdh_cnt) {
+ if (ohci->prev_donehead) {
+ ohci_err(ohci, "HcDoneHead not written back; disabled\n");
+ died:
+ usb_hc_died(ohci_to_hcd(ohci));
+ ohci_dump(ohci);
+ ohci_shutdown(ohci_to_hcd(ohci));
+ goto done;
+ } else {
+ /* No write back because the done queue was empty */
+ takeback_all_pending = true;
+ }
+ }
+
+ /* Check every ED which might have pending TDs */
+ list_for_each_entry(ed, &ohci->eds_in_use, in_use_list) {
+ if (ed->pending_td) {
+ if (takeback_all_pending ||
+ OKAY_TO_TAKEBACK(ohci, ed)) {
+ unsigned tmp = hc32_to_cpu(ohci, ed->hwINFO);
+
+ ohci_dbg(ohci, "takeback pending TD for dev %d ep 0x%x\n",
+ 0x007f & tmp,
+ (0x000f & (tmp >> 7)) +
+ ((tmp & ED_IN) >> 5));
+ add_to_done_list(ohci, ed->pending_td);
+ }
+ }
+
+ /* Starting from the latest pending TD, */
+ td = ed->pending_td;
+
+ /* or the last TD on the done list, */
+ if (!td) {
+ list_for_each_entry(td_next, &ed->td_list, td_list) {
+ if (!td_next->next_dl_td)
+ break;
+ td = td_next;
+ }
+ }
+
+ /* find the last TD processed by the controller. */
+ head = hc32_to_cpu(ohci, ACCESS_ONCE(ed->hwHeadP)) & TD_MASK;
+ td_start = td;
+ td_next = list_prepare_entry(td, &ed->td_list, td_list);
+ list_for_each_entry_continue(td_next, &ed->td_list, td_list) {
+ if (head == (u32) td_next->td_dma)
+ break;
+ td = td_next; /* head pointer has passed this TD */
+ }
+ if (td != td_start) {
+ /*
+ * In case a WDH cycle is in progress, we will wait
+ * for the next two cycles to complete before assuming
+ * this TD will never get on the done queue.
+ */
+ ed->takeback_wdh_cnt = ohci->wdh_cnt + 2;
+ ed->pending_td = td;
+ }
+ }
+
+ ohci_work(ohci);
+
+ if (ohci->rh_state == OHCI_RH_RUNNING) {
+
+ /*
+ * Sometimes a controller just stops working. We can tell
+ * by checking that the frame counter has advanced since
+ * the last time we ran.
+ *
+ * But be careful: Some controllers violate the spec by
+ * stopping their frame counter when no ports are active.
+ */
+ frame_no = ohci_frame_no(ohci);
+ if (frame_no == ohci->prev_frame_no) {
+ int active_cnt = 0;
+ int i;
+ unsigned tmp;
+
+ for (i = 0; i < ohci->num_ports; ++i) {
+ tmp = roothub_portstatus(ohci, i);
+ /* Enabled and not suspended? */
+ if ((tmp & RH_PS_PES) && !(tmp & RH_PS_PSS))
+ ++active_cnt;
+ }
+
+ if (active_cnt > 0) {
+ ohci_err(ohci, "frame counter not updating; disabled\n");
+ goto died;
+ }
+ }
+ if (!list_empty(&ohci->eds_in_use)) {
+ ohci->prev_frame_no = frame_no;
+ ohci->prev_wdh_cnt = ohci->wdh_cnt;
+ ohci->prev_donehead = ohci_readl(ohci,
+ &ohci->regs->donehead);
+ mod_timer(&ohci->io_watchdog,
+ jiffies + IO_WATCHDOG_DELAY);
+ }
+ }
+
+ done:
+ spin_unlock_irqrestore(&ohci->lock, flags);
+}
+
/* an interrupt happens */
static irqreturn_t ohci_irq (struct usb_hcd *hcd)
@@ -825,7 +895,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
usb_hc_died(hcd);
}
- ohci_dump (ohci, 1);
+ ohci_dump(ohci);
ohci_usb_reset (ohci);
}
@@ -863,58 +933,30 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
usb_hcd_resume_root_hub(hcd);
}
- if (ints & OHCI_INTR_WDH) {
- spin_lock (&ohci->lock);
- dl_done_list (ohci);
- spin_unlock (&ohci->lock);
- }
-
- if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) {
- spin_lock(&ohci->lock);
- if (ohci->ed_to_check) {
- struct ed *ed = ohci->ed_to_check;
-
- if (check_ed(ohci, ed)) {
- /* HC thinks the TD list is empty; HCD knows
- * at least one TD is outstanding
- */
- if (--ohci->zf_delay == 0) {
- struct td *td = list_entry(
- ed->td_list.next,
- struct td, td_list);
- ohci_warn(ohci,
- "Reclaiming orphan TD %p\n",
- td);
- takeback_td(ohci, td);
- ohci->ed_to_check = NULL;
- }
- } else
- ohci->ed_to_check = NULL;
- }
- spin_unlock(&ohci->lock);
- }
+ spin_lock(&ohci->lock);
+ if (ints & OHCI_INTR_WDH)
+ update_done_list(ohci);
/* could track INTR_SO to reduce available PCI/... bandwidth */
/* handle any pending URB/ED unlinks, leaving INTR_SF enabled
* when there's still unlinking to be done (next frame).
*/
- spin_lock (&ohci->lock);
- if (ohci->ed_rm_list)
- finish_unlinks (ohci, ohci_frame_no(ohci));
- if ((ints & OHCI_INTR_SF) != 0
- && !ohci->ed_rm_list
- && !ohci->ed_to_check
+ ohci_work(ohci);
+ if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
&& ohci->rh_state == OHCI_RH_RUNNING)
ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
- spin_unlock (&ohci->lock);
if (ohci->rh_state == OHCI_RH_RUNNING) {
ohci_writel (ohci, ints, &regs->intrstatus);
+ if (ints & OHCI_INTR_WDH)
+ ++ohci->wdh_cnt;
+
ohci_writel (ohci, OHCI_INTR_MIE, &regs->intrenable);
// flush those writes
(void) ohci_readl (ohci, &ohci->regs->control);
}
+ spin_unlock(&ohci->lock);
return IRQ_HANDLED;
}
@@ -925,18 +967,17 @@ static void ohci_stop (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
- ohci_dump (ohci, 1);
+ ohci_dump(ohci);
if (quirk_nec(ohci))
flush_work(&ohci->nec_work);
+ del_timer_sync(&ohci->io_watchdog);
ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
ohci_usb_reset(ohci);
free_irq(hcd->irq, hcd);
hcd->irq = 0;
- if (quirk_zfmicro(ohci))
- del_timer(&ohci->unlink_watchdog);
if (quirk_amdiso(ohci))
usb_amd_dev_put();
@@ -993,7 +1034,7 @@ int ohci_restart(struct ohci_hcd *ohci)
if (!urb->unlinked)
urb->unlinked = -ESHUTDOWN;
}
- finish_unlinks (ohci, 0);
+ ohci_work(ohci);
spin_unlock_irq(&ohci->lock);
/* paranoia, in case that didn't work: */
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index b4940de1eba3..17d32b0ea565 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -39,8 +39,8 @@
#define OHCI_SCHED_ENABLES \
(OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
-static void dl_done_list (struct ohci_hcd *);
-static void finish_unlinks (struct ohci_hcd *, u16);
+static void update_done_list(struct ohci_hcd *);
+static void ohci_work(struct ohci_hcd *);
#ifdef CONFIG_PM
static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop)
@@ -87,8 +87,8 @@ __acquires(ohci->lock)
msleep (8);
spin_lock_irq (&ohci->lock);
}
- dl_done_list (ohci);
- finish_unlinks (ohci, ohci_frame_no(ohci));
+ update_done_list(ohci);
+ ohci_work(ohci);
/*
* Some controllers don't handle "global" suspend properly if
@@ -309,6 +309,9 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
else
rc = ohci_rh_suspend (ohci, 0);
spin_unlock_irq (&ohci->lock);
+
+ if (rc == 0)
+ del_timer_sync(&ohci->io_watchdog);
return rc;
}
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
index 2f20d3dc895b..c9e315c6808a 100644
--- a/drivers/usb/host/ohci-mem.c
+++ b/drivers/usb/host/ohci-mem.c
@@ -28,6 +28,7 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
ohci->next_statechange = jiffies;
spin_lock_init (&ohci->lock);
INIT_LIST_HEAD (&ohci->pending);
+ INIT_LIST_HEAD(&ohci->eds_in_use);
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index d4253e319428..1463c398d322 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -187,10 +187,6 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
ed->ed_prev = NULL;
ed->ed_next = NULL;
ed->hwNextED = 0;
- if (quirk_zfmicro(ohci)
- && (ed->type == PIPE_INTERRUPT)
- && !(ohci->eds_scheduled++))
- mod_timer(&ohci->unlink_watchdog, round_jiffies(jiffies + HZ));
wmb ();
/* we care about rm_list when setting CLE/BLE in case the HC was at
@@ -311,8 +307,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)
* - ED_OPER: when there's any request queued, the ED gets rescheduled
* immediately. HC should be working on them.
*
- * - ED_IDLE: when there's no TD queue. there's no reason for the HC
- * to care about this ED; safe to disable the endpoint.
+ * - ED_IDLE: when there's no TD queue or the HC isn't running.
*
* When finish_unlinks() runs later, after SOF interrupt, it will often
* complete one or more URB unlinks before making that state change.
@@ -602,6 +597,8 @@ static void td_submit_urb (
u32 info = 0;
int is_out = usb_pipeout (urb->pipe);
int periodic = 0;
+ int i, this_sg_len, n;
+ struct scatterlist *sg;
/* OHCI handles the bulk/interrupt data toggles itself. We just
* use the device toggle bits for resetting, and rely on the fact
@@ -615,10 +612,24 @@ static void td_submit_urb (
list_add (&urb_priv->pending, &ohci->pending);
- if (data_len)
- data = urb->transfer_dma;
- else
- data = 0;
+ i = urb->num_mapped_sgs;
+ if (data_len > 0 && i > 0) {
+ sg = urb->sg;
+ data = sg_dma_address(sg);
+
+ /*
+ * urb->transfer_buffer_length may be smaller than the
+ * size of the scatterlist (or vice versa)
+ */
+ this_sg_len = min_t(int, sg_dma_len(sg), data_len);
+ } else {
+ sg = NULL;
+ if (data_len)
+ data = urb->transfer_dma;
+ else
+ data = 0;
+ this_sg_len = data_len;
+ }
/* NOTE: TD_CC is set so we can tell which TDs the HC processed by
* using TD_CC_GET, as well as by seeing them on the done list.
@@ -639,17 +650,29 @@ static void td_submit_urb (
? TD_T_TOGGLE | TD_CC | TD_DP_OUT
: TD_T_TOGGLE | TD_CC | TD_DP_IN;
/* TDs _could_ transfer up to 8K each */
- while (data_len > 4096) {
- td_fill (ohci, info, data, 4096, urb, cnt);
- data += 4096;
- data_len -= 4096;
+ for (;;) {
+ n = min(this_sg_len, 4096);
+
+ /* maybe avoid ED halt on final TD short read */
+ if (n >= data_len || (i == 1 && n >= this_sg_len)) {
+ if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
+ info |= TD_R;
+ }
+ td_fill(ohci, info, data, n, urb, cnt);
+ this_sg_len -= n;
+ data_len -= n;
+ data += n;
cnt++;
+
+ if (this_sg_len <= 0) {
+ if (--i <= 0 || data_len <= 0)
+ break;
+ sg = sg_next(sg);
+ data = sg_dma_address(sg);
+ this_sg_len = min_t(int, sg_dma_len(sg),
+ data_len);
+ }
}
- /* maybe avoid ED halt on final TD short read */
- if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
- info |= TD_R;
- td_fill (ohci, info, data, data_len, urb, cnt);
- cnt++;
if ((urb->transfer_flags & URB_ZERO_PACKET)
&& cnt < urb_priv->length) {
td_fill (ohci, info, 0, 0, urb, cnt);
@@ -869,13 +892,46 @@ static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc)
}
}
-/* replies to the request have to be on a FIFO basis so
- * we unreverse the hc-reversed done-list
- */
-static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
+/* Add a TD to the done list */
+static void add_to_done_list(struct ohci_hcd *ohci, struct td *td)
+{
+ struct td *td2, *td_prev;
+ struct ed *ed;
+
+ if (td->next_dl_td)
+ return; /* Already on the list */
+
+ /* Add all the TDs going back until we reach one that's on the list */
+ ed = td->ed;
+ td2 = td_prev = td;
+ list_for_each_entry_continue_reverse(td2, &ed->td_list, td_list) {
+ if (td2->next_dl_td)
+ break;
+ td2->next_dl_td = td_prev;
+ td_prev = td2;
+ }
+
+ if (ohci->dl_end)
+ ohci->dl_end->next_dl_td = td_prev;
+ else
+ ohci->dl_start = td_prev;
+
+ /*
+ * Make td->next_dl_td point to td itself, to mark the fact
+ * that td is on the done list.
+ */
+ ohci->dl_end = td->next_dl_td = td;
+
+ /* Did we just add the latest pending TD? */
+ td2 = ed->pending_td;
+ if (td2 && td2->next_dl_td)
+ ed->pending_td = NULL;
+}
+
+/* Get the entries on the hardware done queue and put them on our list */
+static void update_done_list(struct ohci_hcd *ohci)
{
u32 td_dma;
- struct td *td_rev = NULL;
struct td *td = NULL;
td_dma = hc32_to_cpup (ohci, &ohci->hcca->done_head);
@@ -883,7 +939,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
wmb();
/* get TD from hc's singly linked list, and
- * prepend to ours. ed->td_list changes later.
+ * add to ours. ed->td_list changes later.
*/
while (td_dma) {
int cc;
@@ -905,19 +961,17 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
&& (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H)))
ed_halted(ohci, td, cc);
- td->next_dl_td = td_rev;
- td_rev = td;
td_dma = hc32_to_cpup (ohci, &td->hwNextTD);
+ add_to_done_list(ohci, td);
}
- return td_rev;
}
/*-------------------------------------------------------------------------*/
/* there are some urbs/eds to unlink; called in_irq(), with HCD locked */
-static void
-finish_unlinks (struct ohci_hcd *ohci, u16 tick)
+static void finish_unlinks(struct ohci_hcd *ohci)
{
+ unsigned tick = ohci_frame_no(ohci);
struct ed *ed, **last;
rescan_all:
@@ -926,41 +980,48 @@ rescan_all:
int completed, modified;
__hc32 *prev;
+ /* Is this ED already invisible to the hardware? */
+ if (ed->state == ED_IDLE)
+ goto ed_idle;
+
/* only take off EDs that the HC isn't using, accounting for
* frame counter wraps and EDs with partially retired TDs
*/
- if (likely(ohci->rh_state == OHCI_RH_RUNNING)) {
- if (tick_before (tick, ed->tick)) {
+ if (likely(ohci->rh_state == OHCI_RH_RUNNING) &&
+ tick_before(tick, ed->tick)) {
skip_ed:
- last = &ed->ed_next;
- continue;
- }
+ last = &ed->ed_next;
+ continue;
+ }
+ if (!list_empty(&ed->td_list)) {
+ struct td *td;
+ u32 head;
- if (!list_empty (&ed->td_list)) {
- struct td *td;
- u32 head;
-
- td = list_entry (ed->td_list.next, struct td,
- td_list);
- head = hc32_to_cpu (ohci, ed->hwHeadP) &
- TD_MASK;
-
- /* INTR_WDH may need to clean up first */
- if (td->td_dma != head) {
- if (ed == ohci->ed_to_check)
- ohci->ed_to_check = NULL;
- else
- goto skip_ed;
- }
- }
+ td = list_first_entry(&ed->td_list, struct td, td_list);
+
+ /* INTR_WDH may need to clean up first */
+ head = hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK;
+ if (td->td_dma != head &&
+ ohci->rh_state == OHCI_RH_RUNNING)
+ goto skip_ed;
+
+ /* Don't mess up anything already on the done list */
+ if (td->next_dl_td)
+ goto skip_ed;
}
+ /* ED's now officially unlinked, hc doesn't see */
+ ed->state = ED_IDLE;
+ ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
+ ed->hwNextED = 0;
+ wmb();
+ ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE);
+ed_idle:
+
/* reentrancy: if we drop the schedule lock, someone might
* have modified this list. normally it's just prepending
* entries (which we'd ignore), but paranoia won't hurt.
*/
- *last = ed->ed_next;
- ed->ed_next = NULL;
modified = 0;
/* unlink urbs as requested, but rescan the list after
@@ -1018,19 +1079,21 @@ rescan_this:
if (completed && !list_empty (&ed->td_list))
goto rescan_this;
- /* ED's now officially unlinked, hc doesn't see */
- ed->state = ED_IDLE;
- if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
- ohci->eds_scheduled--;
- ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
- ed->hwNextED = 0;
- wmb ();
- ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP | ED_DEQUEUE);
-
- /* but if there's work queued, reschedule */
- if (!list_empty (&ed->td_list)) {
- if (ohci->rh_state == OHCI_RH_RUNNING)
- ed_schedule (ohci, ed);
+ /*
+ * If no TDs are queued, take ED off the ed_rm_list.
+ * Otherwise, if the HC is running, reschedule.
+ * If not, leave it on the list for further dequeues.
+ */
+ if (list_empty(&ed->td_list)) {
+ *last = ed->ed_next;
+ ed->ed_next = NULL;
+ list_del(&ed->in_use_list);
+ } else if (ohci->rh_state == OHCI_RH_RUNNING) {
+ *last = ed->ed_next;
+ ed->ed_next = NULL;
+ ed_schedule(ohci, ed);
+ } else {
+ last = &ed->ed_next;
}
if (modified)
@@ -1082,12 +1145,7 @@ rescan_this:
/*-------------------------------------------------------------------------*/
-/*
- * Used to take back a TD from the host controller. This would normally be
- * called from within dl_done_list, however it may be called directly if the
- * HC no longer sees the TD and it has not appeared on the donelist (after
- * two frames). This bug has been observed on ZF Micro systems.
- */
+/* Take back a TD from the host controller */
static void takeback_td(struct ohci_hcd *ohci, struct td *td)
{
struct urb *urb = td->urb;
@@ -1134,37 +1192,43 @@ static void takeback_td(struct ohci_hcd *ohci, struct td *td)
*
* This is the main path for handing urbs back to drivers. The only other
* normal path is finish_unlinks(), which unlinks URBs using ed_rm_list,
- * instead of scanning the (re-reversed) donelist as this does. There's
- * an abnormal path too, handling a quirk in some Compaq silicon: URBs
- * with TDs that appear to be orphaned are directly reclaimed.
+ * instead of scanning the (re-reversed) donelist as this does.
*/
-static void
-dl_done_list (struct ohci_hcd *ohci)
+static void process_done_list(struct ohci_hcd *ohci)
{
- struct td *td = dl_reverse_done_list (ohci);
+ struct td *td;
- while (td) {
- struct td *td_next = td->next_dl_td;
- struct ed *ed = td->ed;
+ while (ohci->dl_start) {
+ td = ohci->dl_start;
+ if (td == ohci->dl_end)
+ ohci->dl_start = ohci->dl_end = NULL;
+ else
+ ohci->dl_start = td->next_dl_td;
- /*
- * Some OHCI controllers (NVIDIA for sure, maybe others)
- * occasionally forget to add TDs to the done queue. Since
- * TDs for a given endpoint are always processed in order,
- * if we find a TD on the donelist then all of its
- * predecessors must be finished as well.
- */
- for (;;) {
- struct td *td2;
+ takeback_td(ohci, td);
+ }
+}
- td2 = list_first_entry(&ed->td_list, struct td,
- td_list);
- if (td2 == td)
- break;
- takeback_td(ohci, td2);
- }
+/*
+ * TD takeback and URB giveback must be single-threaded.
+ * This routine takes care of it all.
+ */
+static void ohci_work(struct ohci_hcd *ohci)
+{
+ if (ohci->working) {
+ ohci->restart_work = 1;
+ return;
+ }
+ ohci->working = 1;
- takeback_td(ohci, td);
- td = td_next;
+ restart:
+ process_done_list(ohci);
+ if (ohci->ed_rm_list)
+ finish_unlinks(ohci);
+
+ if (ohci->restart_work) {
+ ohci->restart_work = 0;
+ goto restart;
}
+ ohci->working = 0;
}
diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c
index 8b29a0c04c23..8d5876692e7c 100644
--- a/drivers/usb/host/ohci-spear.c
+++ b/drivers/usb/host/ohci-spear.c
@@ -162,7 +162,7 @@ static int spear_ohci_hcd_drv_resume(struct platform_device *dev)
}
#endif
-static struct of_device_id spear_ohci_id_table[] = {
+static const struct of_device_id spear_ohci_id_table[] = {
{ .compatible = "st,spear600-ohci", },
{ },
};
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 05e02a709d4f..59f424567a8d 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -47,6 +47,7 @@ struct ed {
struct ed *ed_next; /* on schedule or rm_list */
struct ed *ed_prev; /* for non-interrupt EDs */
struct list_head td_list; /* "shadow list" of our TDs */
+ struct list_head in_use_list;
/* create --> IDLE --> OPER --> ... --> IDLE --> destroy
* usually: OPER --> UNLINK --> (IDLE | OPER) --> ...
@@ -66,6 +67,13 @@ struct ed {
/* HC may see EDs on rm_list until next frame (frame_no == tick) */
u16 tick;
+
+ /* Detect TDs not added to the done queue */
+ unsigned takeback_wdh_cnt;
+ struct td *pending_td;
+#define OKAY_TO_TAKEBACK(ohci, ed) \
+ ((int) (ohci->wdh_cnt - ed->takeback_wdh_cnt) >= 0)
+
} __attribute__ ((aligned(16)));
#define ED_MASK ((u32)~0x0f) /* strip hw status in low addr bits */
@@ -380,7 +388,9 @@ struct ohci_hcd {
struct dma_pool *td_cache;
struct dma_pool *ed_cache;
struct td *td_hash [TD_HASH_SIZE];
+ struct td *dl_start, *dl_end; /* the done list */
struct list_head pending;
+ struct list_head eds_in_use; /* all EDs with at least 1 TD */
/*
* driver state
@@ -392,6 +402,8 @@ struct ohci_hcd {
unsigned long next_statechange; /* suspend/resume */
u32 fminterval; /* saved register */
unsigned autostop:1; /* rh auto stopping/stopped */
+ unsigned working:1;
+ unsigned restart_work:1;
unsigned long flags; /* for HC bugs */
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
@@ -409,13 +421,12 @@ struct ohci_hcd {
// there are also chip quirks/bugs in init logic
- struct work_struct nec_work; /* Worker for NEC quirk */
+ unsigned prev_frame_no;
+ unsigned wdh_cnt, prev_wdh_cnt;
+ u32 prev_donehead;
+ struct timer_list io_watchdog;
- /* Needed for ZF Micro quirk */
- struct timer_list unlink_watchdog;
- unsigned eds_scheduled;
- struct ed *ed_to_check;
- unsigned zf_delay;
+ struct work_struct nec_work; /* Worker for NEC quirk */
struct dentry *debug_dir;
struct dentry *debug_async;
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index e07248b6ab67..da5fb0e3c363 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -3826,49 +3826,36 @@ static int oxu_drv_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "IRQ resource %d\n", irq);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "no registers address! Check %s setup!\n",
- dev_name(&pdev->dev));
- return -ENODEV;
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base)) {
+ ret = PTR_ERR(base);
+ goto error;
}
memstart = res->start;
memlen = resource_size(res);
- dev_dbg(&pdev->dev, "MEM resource %lx-%lx\n", memstart, memlen);
- if (!request_mem_region(memstart, memlen,
- oxu_hc_driver.description)) {
- dev_dbg(&pdev->dev, "memory area already in use\n");
- return -EBUSY;
- }
ret = irq_set_irq_type(irq, IRQF_TRIGGER_FALLING);
if (ret) {
dev_err(&pdev->dev, "error setting irq type\n");
ret = -EFAULT;
- goto error_set_irq_type;
- }
-
- base = ioremap(memstart, memlen);
- if (!base) {
- dev_dbg(&pdev->dev, "error mapping memory\n");
- ret = -EFAULT;
- goto error_ioremap;
+ goto error;
}
/* Allocate a driver data struct to hold useful info for both
* SPH & OTG devices
*/
- info = kzalloc(sizeof(struct oxu_info), GFP_KERNEL);
+ info = devm_kzalloc(&pdev->dev, sizeof(struct oxu_info), GFP_KERNEL);
if (!info) {
dev_dbg(&pdev->dev, "error allocating memory\n");
ret = -EFAULT;
- goto error_alloc;
+ goto error;
}
platform_set_drvdata(pdev, info);
ret = oxu_init(pdev, memstart, memlen, base, irq);
if (ret < 0) {
dev_dbg(&pdev->dev, "cannot init USB devices\n");
- goto error_init;
+ goto error;
}
dev_info(&pdev->dev, "devices enabled and running\n");
@@ -3876,16 +3863,7 @@ static int oxu_drv_probe(struct platform_device *pdev)
return 0;
-error_init:
- kfree(info);
-
-error_alloc:
- iounmap(base);
-
-error_set_irq_type:
-error_ioremap:
- release_mem_region(memstart, memlen);
-
+error:
dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), ret);
return ret;
}
@@ -3899,18 +3877,10 @@ static void oxu_remove(struct platform_device *pdev, struct usb_hcd *hcd)
static int oxu_drv_remove(struct platform_device *pdev)
{
struct oxu_info *info = platform_get_drvdata(pdev);
- unsigned long memstart = info->hcd[0]->rsrc_start,
- memlen = info->hcd[0]->rsrc_len;
- void *base = info->hcd[0]->regs;
oxu_remove(pdev, info->hcd[0]);
oxu_remove(pdev, info->hcd[1]);
- iounmap(base);
- release_mem_region(memstart, memlen);
-
- kfree(info);
-
return 0;
}
diff --git a/drivers/usb/host/uhci-grlib.c b/drivers/usb/host/uhci-grlib.c
index ab25dc397e8b..05f57ffdf9ab 100644
--- a/drivers/usb/host/uhci-grlib.c
+++ b/drivers/usb/host/uhci-grlib.c
@@ -17,6 +17,7 @@
* (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu
*/
+#include <linux/device.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
@@ -113,24 +114,17 @@ static int uhci_hcd_grlib_probe(struct platform_device *op)
hcd->rsrc_start = res.start;
hcd->rsrc_len = resource_size(&res);
- if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
- printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
- rv = -EBUSY;
- goto err_rmr;
- }
-
irq = irq_of_parse_and_map(dn, 0);
if (irq == NO_IRQ) {
printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
rv = -EBUSY;
- goto err_irq;
+ goto err_usb;
}
- hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
- if (!hcd->regs) {
- printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
- rv = -ENOMEM;
- goto err_ioremap;
+ hcd->regs = devm_ioremap_resource(&op->dev, &res);
+ if (IS_ERR(hcd->regs)) {
+ rv = PTR_ERR(hcd->regs);
+ goto err_irq;
}
uhci = hcd_to_uhci(hcd);
@@ -139,18 +133,14 @@ static int uhci_hcd_grlib_probe(struct platform_device *op)
rv = usb_add_hcd(hcd, irq, 0);
if (rv)
- goto err_uhci;
+ goto err_irq;
device_wakeup_enable(hcd->self.controller);
return 0;
-err_uhci:
- iounmap(hcd->regs);
-err_ioremap:
- irq_dispose_mapping(irq);
err_irq:
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err_rmr:
+ irq_dispose_mapping(irq);
+err_usb:
usb_put_hcd(hcd);
return rv;
@@ -164,10 +154,7 @@ static int uhci_hcd_grlib_remove(struct platform_device *op)
usb_remove_hcd(hcd);
- iounmap(hcd->regs);
irq_dispose_mapping(hcd->irq);
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-
usb_put_hcd(hcd);
return 0;
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 27f35e8f161b..a7de8e8bb458 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -591,7 +591,7 @@ static int uhci_start(struct usb_hcd *hcd)
uhci->frame = dma_alloc_coherent(uhci_dev(uhci),
UHCI_NUMFRAMES * sizeof(*uhci->frame),
- &uhci->frame_dma_handle, 0);
+ &uhci->frame_dma_handle, GFP_KERNEL);
if (!uhci->frame) {
dev_err(uhci_dev(uhci),
"unable to allocate consistent memory for frame list\n");
diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c
index 01833ab2b5c3..b987f1d10058 100644
--- a/drivers/usb/host/uhci-platform.c
+++ b/drivers/usb/host/uhci-platform.c
@@ -8,6 +8,7 @@
*/
#include <linux/of.h>
+#include <linux/device.h>
#include <linux/platform_device.h>
static int uhci_platform_init(struct usb_hcd *hcd)
@@ -88,33 +89,22 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev)
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
- if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
- pr_err("%s: request_mem_region failed\n", __func__);
- ret = -EBUSY;
+ hcd->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(hcd->regs)) {
+ ret = PTR_ERR(hcd->regs);
goto err_rmr;
}
-
- hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
- if (!hcd->regs) {
- pr_err("%s: ioremap failed\n", __func__);
- ret = -ENOMEM;
- goto err_irq;
- }
uhci = hcd_to_uhci(hcd);
uhci->regs = hcd->regs;
ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED);
if (ret)
- goto err_uhci;
+ goto err_rmr;
device_wakeup_enable(hcd->self.controller);
return 0;
-err_uhci:
- iounmap(hcd->regs);
-err_irq:
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err_rmr:
usb_put_hcd(hcd);
@@ -126,8 +116,6 @@ static int uhci_hcd_platform_remove(struct platform_device *pdev)
struct usb_hcd *hcd = platform_get_drvdata(pdev);
usb_remove_hcd(hcd);
- iounmap(hcd->regs);
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
return 0;
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index e20520f42753..687d36608155 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -33,7 +33,7 @@
#define PCI_DEVICE_ID_FRESCO_LOGIC_FL1400 0x1400
#define PCI_VENDOR_ID_ETRON 0x1b6f
-#define PCI_DEVICE_ID_ASROCK_P67 0x7023
+#define PCI_DEVICE_ID_EJ168 0x7023
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
@@ -140,9 +140,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
xhci->quirks |= XHCI_SPURIOUS_REBOOT;
}
if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
- pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
+ pdev->device == PCI_DEVICE_ID_EJ168) {
xhci->quirks |= XHCI_RESET_ON_RESUME;
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+ xhci->quirks |= XHCI_BROKEN_STREAMS;
}
if (pdev->vendor == PCI_VENDOR_ID_RENESAS &&
pdev->device == 0x0015)
@@ -230,7 +231,8 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
goto put_usb3_hcd;
/* Roothub already marked as USB 3.0 speed */
- if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
+ if (!(xhci->quirks & XHCI_BROKEN_STREAMS) &&
+ HCC_MAX_PSA(xhci->hcc_params) >= 4)
xhci->shared_hcd->can_do_streams = 1;
/* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 29d8adb5c8d1..1a0cf9f31e43 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -17,9 +17,11 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/usb/xhci_pdriver.h>
#include "xhci.h"
#include "xhci-mvebu.h"
+#include "xhci-rcar.h"
static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
{
@@ -34,11 +36,27 @@ static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
/* called during probe() after chip reset completes */
static int xhci_plat_setup(struct usb_hcd *hcd)
{
+ struct device_node *of_node = hcd->self.controller->of_node;
+ int ret;
+
+ if (of_device_is_compatible(of_node, "renesas,xhci-r8a7790") ||
+ of_device_is_compatible(of_node, "renesas,xhci-r8a7791")) {
+ ret = xhci_rcar_init_quirk(hcd);
+ if (ret)
+ return ret;
+ }
+
return xhci_gen_setup(hcd, xhci_plat_quirks);
}
static int xhci_plat_start(struct usb_hcd *hcd)
{
+ struct device_node *of_node = hcd->self.controller->of_node;
+
+ if (of_device_is_compatible(of_node, "renesas,xhci-r8a7790") ||
+ of_device_is_compatible(of_node, "renesas,xhci-r8a7791"))
+ xhci_rcar_start(hcd);
+
return xhci_run(hcd);
}
@@ -90,10 +108,15 @@ static const struct hc_driver xhci_plat_xhci_driver = {
.hub_status_data = xhci_hub_status_data,
.bus_suspend = xhci_bus_suspend,
.bus_resume = xhci_bus_resume,
+
+ .enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout,
+ .disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout,
};
static int xhci_plat_probe(struct platform_device *pdev)
{
+ struct device_node *node = pdev->dev.of_node;
+ struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev);
const struct hc_driver *driver;
struct xhci_hcd *xhci;
struct resource *res;
@@ -140,20 +163,12 @@ static int xhci_plat_probe(struct platform_device *pdev)
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
- if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
- driver->description)) {
- dev_dbg(&pdev->dev, "controller already in use\n");
- ret = -EBUSY;
+ hcd->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(hcd->regs)) {
+ ret = PTR_ERR(hcd->regs);
goto put_hcd;
}
- hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
- if (!hcd->regs) {
- dev_dbg(&pdev->dev, "error mapping memory\n");
- ret = -EFAULT;
- goto release_mem_region;
- }
-
/*
* Not all platforms have a clk so it is not an error if the
* clock does not exists.
@@ -162,7 +177,7 @@ static int xhci_plat_probe(struct platform_device *pdev)
if (!IS_ERR(clk)) {
ret = clk_prepare_enable(clk);
if (ret)
- goto unmap_registers;
+ goto put_hcd;
}
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
@@ -182,6 +197,9 @@ static int xhci_plat_probe(struct platform_device *pdev)
goto dealloc_usb2_hcd;
}
+ if ((node && of_property_read_bool(node, "usb3-lpm-capable")) ||
+ (pdata && pdata->usb3_lpm_capable))
+ xhci->quirks |= XHCI_LPM_SUPPORT;
/*
* Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset)
* is called by usb_add_hcd().
@@ -207,12 +225,6 @@ disable_clk:
if (!IS_ERR(clk))
clk_disable_unprepare(clk);
-unmap_registers:
- iounmap(hcd->regs);
-
-release_mem_region:
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-
put_hcd:
usb_put_hcd(hcd);
@@ -231,8 +243,6 @@ static int xhci_plat_remove(struct platform_device *dev)
usb_remove_hcd(hcd);
if (!IS_ERR(clk))
clk_disable_unprepare(clk);
- iounmap(hcd->regs);
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
kfree(xhci);
@@ -270,6 +280,8 @@ static const struct of_device_id usb_xhci_of_match[] = {
{ .compatible = "xhci-platform" },
{ .compatible = "marvell,armada-375-xhci"},
{ .compatible = "marvell,armada-380-xhci"},
+ { .compatible = "renesas,xhci-r8a7790"},
+ { .compatible = "renesas,xhci-r8a7791"},
{ },
};
MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c
new file mode 100644
index 000000000000..ff0d1b44ea58
--- /dev/null
+++ b/drivers/usb/host/xhci-rcar.c
@@ -0,0 +1,148 @@
+/*
+ * xHCI host controller driver for R-Car SoCs
+ *
+ * Copyright (C) 2014 Renesas Electronics Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/usb/phy.h>
+
+#include "xhci.h"
+#include "xhci-rcar.h"
+
+#define FIRMWARE_NAME "r8a779x_usb3_v1.dlmem"
+MODULE_FIRMWARE(FIRMWARE_NAME);
+
+/*** Register Offset ***/
+#define RCAR_USB3_INT_ENA 0x224 /* Interrupt Enable */
+#define RCAR_USB3_DL_CTRL 0x250 /* FW Download Control & Status */
+#define RCAR_USB3_FW_DATA0 0x258 /* FW Data0 */
+
+#define RCAR_USB3_LCLK 0xa44 /* LCLK Select */
+#define RCAR_USB3_CONF1 0xa48 /* USB3.0 Configuration1 */
+#define RCAR_USB3_CONF2 0xa5c /* USB3.0 Configuration2 */
+#define RCAR_USB3_CONF3 0xaa8 /* USB3.0 Configuration3 */
+#define RCAR_USB3_RX_POL 0xab0 /* USB3.0 RX Polarity */
+#define RCAR_USB3_TX_POL 0xab8 /* USB3.0 TX Polarity */
+
+/*** Register Settings ***/
+/* Interrupt Enable */
+#define RCAR_USB3_INT_XHC_ENA 0x00000001
+#define RCAR_USB3_INT_PME_ENA 0x00000002
+#define RCAR_USB3_INT_HSE_ENA 0x00000004
+#define RCAR_USB3_INT_ENA_VAL (RCAR_USB3_INT_XHC_ENA | \
+ RCAR_USB3_INT_PME_ENA | RCAR_USB3_INT_HSE_ENA)
+
+/* FW Download Control & Status */
+#define RCAR_USB3_DL_CTRL_ENABLE 0x00000001
+#define RCAR_USB3_DL_CTRL_FW_SUCCESS 0x00000010
+#define RCAR_USB3_DL_CTRL_FW_SET_DATA0 0x00000100
+
+/* LCLK Select */
+#define RCAR_USB3_LCLK_ENA_VAL 0x01030001
+
+/* USB3.0 Configuration */
+#define RCAR_USB3_CONF1_VAL 0x00030204
+#define RCAR_USB3_CONF2_VAL 0x00030300
+#define RCAR_USB3_CONF3_VAL 0x13802007
+
+/* USB3.0 Polarity */
+#define RCAR_USB3_RX_POL_VAL BIT(21)
+#define RCAR_USB3_TX_POL_VAL BIT(4)
+
+void xhci_rcar_start(struct usb_hcd *hcd)
+{
+ u32 temp;
+
+ if (hcd->regs != NULL) {
+ /* Interrupt Enable */
+ temp = readl(hcd->regs + RCAR_USB3_INT_ENA);
+ temp |= RCAR_USB3_INT_ENA_VAL;
+ writel(temp, hcd->regs + RCAR_USB3_INT_ENA);
+ /* LCLK Select */
+ writel(RCAR_USB3_LCLK_ENA_VAL, hcd->regs + RCAR_USB3_LCLK);
+ /* USB3.0 Configuration */
+ writel(RCAR_USB3_CONF1_VAL, hcd->regs + RCAR_USB3_CONF1);
+ writel(RCAR_USB3_CONF2_VAL, hcd->regs + RCAR_USB3_CONF2);
+ writel(RCAR_USB3_CONF3_VAL, hcd->regs + RCAR_USB3_CONF3);
+ /* USB3.0 Polarity */
+ writel(RCAR_USB3_RX_POL_VAL, hcd->regs + RCAR_USB3_RX_POL);
+ writel(RCAR_USB3_TX_POL_VAL, hcd->regs + RCAR_USB3_TX_POL);
+ }
+}
+
+static int xhci_rcar_download_firmware(struct device *dev, void __iomem *regs)
+{
+ const struct firmware *fw;
+ int retval, index, j, time;
+ int timeout = 10000;
+ u32 data, val, temp;
+
+ /* request R-Car USB3.0 firmware */
+ retval = request_firmware(&fw, FIRMWARE_NAME, dev);
+ if (retval)
+ return retval;
+
+ /* download R-Car USB3.0 firmware */
+ temp = readl(regs + RCAR_USB3_DL_CTRL);
+ temp |= RCAR_USB3_DL_CTRL_ENABLE;
+ writel(temp, regs + RCAR_USB3_DL_CTRL);
+
+ for (index = 0; index < fw->size; index += 4) {
+ /* to avoid reading beyond the end of the buffer */
+ for (data = 0, j = 3; j >= 0; j--) {
+ if ((j + index) < fw->size)
+ data |= fw->data[index + j] << (8 * j);
+ }
+ writel(data, regs + RCAR_USB3_FW_DATA0);
+ temp = readl(regs + RCAR_USB3_DL_CTRL);
+ temp |= RCAR_USB3_DL_CTRL_FW_SET_DATA0;
+ writel(temp, regs + RCAR_USB3_DL_CTRL);
+
+ for (time = 0; time < timeout; time++) {
+ val = readl(regs + RCAR_USB3_DL_CTRL);
+ if ((val & RCAR_USB3_DL_CTRL_FW_SET_DATA0) == 0)
+ break;
+ udelay(1);
+ }
+ if (time == timeout) {
+ retval = -ETIMEDOUT;
+ break;
+ }
+ }
+
+ temp = readl(regs + RCAR_USB3_DL_CTRL);
+ temp &= ~RCAR_USB3_DL_CTRL_ENABLE;
+ writel(temp, regs + RCAR_USB3_DL_CTRL);
+
+ for (time = 0; time < timeout; time++) {
+ val = readl(regs + RCAR_USB3_DL_CTRL);
+ if (val & RCAR_USB3_DL_CTRL_FW_SUCCESS) {
+ retval = 0;
+ break;
+ }
+ udelay(1);
+ }
+ if (time == timeout)
+ retval = -ETIMEDOUT;
+
+ release_firmware(fw);
+
+ return retval;
+}
+
+/* This function needs to initialize a "phy" of usb before */
+int xhci_rcar_init_quirk(struct usb_hcd *hcd)
+{
+ /* If hcd->regs is NULL, we don't just call the following function */
+ if (!hcd->regs)
+ return 0;
+
+ return xhci_rcar_download_firmware(hcd->self.controller, hcd->regs);
+}
diff --git a/drivers/usb/host/xhci-rcar.h b/drivers/usb/host/xhci-rcar.h
new file mode 100644
index 000000000000..58501256715d
--- /dev/null
+++ b/drivers/usb/host/xhci-rcar.h
@@ -0,0 +1,27 @@
+/*
+ * drivers/usb/host/xhci-rcar.h
+ *
+ * Copyright (C) 2014 Renesas Electronics Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef _XHCI_RCAR_H
+#define _XHCI_RCAR_H
+
+#if IS_ENABLED(CONFIG_USB_XHCI_RCAR)
+void xhci_rcar_start(struct usb_hcd *hcd);
+int xhci_rcar_init_quirk(struct usb_hcd *hcd);
+#else
+static inline void xhci_rcar_start(struct usb_hcd *hcd)
+{
+}
+
+static inline int xhci_rcar_init_quirk(struct usb_hcd *hcd)
+{
+ return 0;
+}
+#endif
+#endif /* _XHCI_RCAR_H */
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 749fc68eb5c1..60fb52ae864b 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1118,6 +1118,10 @@ static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id,
if (xhci->quirks & XHCI_RESET_EP_QUIRK) {
struct xhci_command *command;
command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC);
+ if (!command) {
+ xhci_warn(xhci, "WARN Cannot submit cfg ep: ENOMEM\n");
+ return;
+ }
xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
"Queueing configure endpoint command");
xhci_queue_configure_endpoint(xhci, command,
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 7436d5f5e67a..b6f21175b872 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1553,6 +1553,10 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
*/
if (!(ep->ep_state & EP_HALT_PENDING)) {
command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC);
+ if (!command) {
+ ret = -ENOMEM;
+ goto done;
+ }
ep->ep_state |= EP_HALT_PENDING;
ep->stop_cmds_pending++;
ep->stop_cmd_timer.expires = jiffies +
@@ -1586,12 +1590,10 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
struct xhci_hcd *xhci;
struct xhci_container_ctx *in_ctx, *out_ctx;
struct xhci_input_control_ctx *ctrl_ctx;
- struct xhci_slot_ctx *slot_ctx;
- unsigned int last_ctx;
unsigned int ep_index;
struct xhci_ep_ctx *ep_ctx;
u32 drop_flag;
- u32 new_add_flags, new_drop_flags, new_slot_info;
+ u32 new_add_flags, new_drop_flags;
int ret;
ret = xhci_check_args(hcd, udev, ep, 1, true, __func__);
@@ -1638,24 +1640,13 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
ctrl_ctx->add_flags &= cpu_to_le32(~drop_flag);
new_add_flags = le32_to_cpu(ctrl_ctx->add_flags);
- last_ctx = xhci_last_valid_endpoint(le32_to_cpu(ctrl_ctx->add_flags));
- slot_ctx = xhci_get_slot_ctx(xhci, in_ctx);
- /* Update the last valid endpoint context, if we deleted the last one */
- if ((le32_to_cpu(slot_ctx->dev_info) & LAST_CTX_MASK) >
- LAST_CTX(last_ctx)) {
- slot_ctx->dev_info &= cpu_to_le32(~LAST_CTX_MASK);
- slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(last_ctx));
- }
- new_slot_info = le32_to_cpu(slot_ctx->dev_info);
-
xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep);
- xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n",
+ xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n",
(unsigned int) ep->desc.bEndpointAddress,
udev->slot_id,
(unsigned int) new_drop_flags,
- (unsigned int) new_add_flags,
- (unsigned int) new_slot_info);
+ (unsigned int) new_add_flags);
return 0;
}
@@ -1678,11 +1669,9 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
struct xhci_hcd *xhci;
struct xhci_container_ctx *in_ctx, *out_ctx;
unsigned int ep_index;
- struct xhci_slot_ctx *slot_ctx;
struct xhci_input_control_ctx *ctrl_ctx;
u32 added_ctxs;
- unsigned int last_ctx;
- u32 new_add_flags, new_drop_flags, new_slot_info;
+ u32 new_add_flags, new_drop_flags;
struct xhci_virt_device *virt_dev;
int ret = 0;
@@ -1697,7 +1686,6 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
return -ENODEV;
added_ctxs = xhci_get_endpoint_flag(&ep->desc);
- last_ctx = xhci_last_valid_endpoint(added_ctxs);
if (added_ctxs == SLOT_FLAG || added_ctxs == EP0_FLAG) {
/* FIXME when we have to issue an evaluate endpoint command to
* deal with ep0 max packet size changing once we get the
@@ -1763,24 +1751,14 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
*/
new_drop_flags = le32_to_cpu(ctrl_ctx->drop_flags);
- slot_ctx = xhci_get_slot_ctx(xhci, in_ctx);
- /* Update the last valid endpoint context, if we just added one past */
- if ((le32_to_cpu(slot_ctx->dev_info) & LAST_CTX_MASK) <
- LAST_CTX(last_ctx)) {
- slot_ctx->dev_info &= cpu_to_le32(~LAST_CTX_MASK);
- slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(last_ctx));
- }
- new_slot_info = le32_to_cpu(slot_ctx->dev_info);
-
/* Store the usb_device pointer for later use */
ep->hcpriv = udev;
- xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n",
+ xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n",
(unsigned int) ep->desc.bEndpointAddress,
udev->slot_id,
(unsigned int) new_drop_flags,
- (unsigned int) new_add_flags,
- (unsigned int) new_slot_info);
+ (unsigned int) new_add_flags);
return 0;
}
@@ -1830,15 +1808,15 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci,
ret = -ETIME;
break;
case COMP_ENOMEM:
- dev_warn(&udev->dev, "Not enough host controller resources "
- "for new device state.\n");
+ dev_warn(&udev->dev,
+ "Not enough host controller resources for new device state.\n");
ret = -ENOMEM;
/* FIXME: can we allocate more resources for the HC? */
break;
case COMP_BW_ERR:
case COMP_2ND_BW_ERR:
- dev_warn(&udev->dev, "Not enough bandwidth "
- "for new device state.\n");
+ dev_warn(&udev->dev,
+ "Not enough bandwidth for new device state.\n");
ret = -ENOSPC;
/* FIXME: can we go back to the old state? */
break;
@@ -1850,8 +1828,8 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci,
ret = -EINVAL;
break;
case COMP_DEV_ERR:
- dev_warn(&udev->dev, "ERROR: Incompatible device for endpoint "
- "configure command.\n");
+ dev_warn(&udev->dev,
+ "ERROR: Incompatible device for endpoint configure command.\n");
ret = -ENODEV;
break;
case COMP_SUCCESS:
@@ -1860,8 +1838,8 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci,
ret = 0;
break;
default:
- xhci_err(xhci, "ERROR: unexpected command completion "
- "code 0x%x.\n", *cmd_status);
+ xhci_err(xhci, "ERROR: unexpected command completion code 0x%x.\n",
+ *cmd_status);
ret = -EINVAL;
break;
}
@@ -1881,24 +1859,24 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci,
ret = -ETIME;
break;
case COMP_EINVAL:
- dev_warn(&udev->dev, "WARN: xHCI driver setup invalid evaluate "
- "context command.\n");
+ dev_warn(&udev->dev,
+ "WARN: xHCI driver setup invalid evaluate context command.\n");
ret = -EINVAL;
break;
case COMP_EBADSLT:
- dev_warn(&udev->dev, "WARN: slot not enabled for"
- "evaluate context command.\n");
+ dev_warn(&udev->dev,
+ "WARN: slot not enabled for evaluate context command.\n");
ret = -EINVAL;
break;
case COMP_CTX_STATE:
- dev_warn(&udev->dev, "WARN: invalid context state for "
- "evaluate context command.\n");
+ dev_warn(&udev->dev,
+ "WARN: invalid context state for evaluate context command.\n");
xhci_dbg_ctx(xhci, virt_dev->out_ctx, 1);
ret = -EINVAL;
break;
case COMP_DEV_ERR:
- dev_warn(&udev->dev, "ERROR: Incompatible device for evaluate "
- "context command.\n");
+ dev_warn(&udev->dev,
+ "ERROR: Incompatible device for evaluate context command.\n");
ret = -ENODEV;
break;
case COMP_MEL_ERR:
@@ -1912,8 +1890,8 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci,
ret = 0;
break;
default:
- xhci_err(xhci, "ERROR: unexpected command completion "
- "code 0x%x.\n", *cmd_status);
+ xhci_err(xhci, "ERROR: unexpected command completion code 0x%x.\n",
+ *cmd_status);
ret = -EINVAL;
break;
}
@@ -2750,8 +2728,19 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
ret = 0;
goto command_cleanup;
}
- xhci_dbg(xhci, "New Input Control Context:\n");
+ /* Fix up Context Entries field. Minimum value is EP0 == BIT(1). */
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
+ for (i = 31; i >= 1; i--) {
+ __le32 le32 = cpu_to_le32(BIT(i));
+
+ if ((virt_dev->eps[i-1].ring && !(ctrl_ctx->drop_flags & le32))
+ || (ctrl_ctx->add_flags & le32) || i == 1) {
+ slot_ctx->dev_info &= cpu_to_le32(~LAST_CTX_MASK);
+ slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(i));
+ break;
+ }
+ }
+ xhci_dbg(xhci, "New Input Control Context:\n");
xhci_dbg_ctx(xhci, virt_dev->in_ctx,
LAST_CTX_TO_EP_NUM(le32_to_cpu(slot_ctx->dev_info)));
@@ -3163,7 +3152,8 @@ int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
num_streams);
/* MaxPSASize value 0 (2 streams) means streams are not supported */
- if (HCC_MAX_PSA(xhci->hcc_params) < 4) {
+ if ((xhci->quirks & XHCI_BROKEN_STREAMS) ||
+ HCC_MAX_PSA(xhci->hcc_params) < 4) {
xhci_dbg(xhci, "xHCI controller does not support streams.\n");
return -ENOSYS;
}
@@ -4303,8 +4293,7 @@ static u16 xhci_get_timeout_no_hub_lpm(struct usb_device *udev,
return USB3_LPM_DISABLED;
}
-/* Returns the hub-encoded U1 timeout value.
- * The U1 timeout should be the maximum of the following values:
+/* The U1 timeout should be the maximum of the following values:
* - For control endpoints, U1 system exit latency (SEL) * 3
* - For bulk endpoints, U1 SEL * 5
* - For interrupt endpoints:
@@ -4312,7 +4301,8 @@ static u16 xhci_get_timeout_no_hub_lpm(struct usb_device *udev,
* - Periodic EPs, max(105% of bInterval, U1 SEL * 2)
* - For isochronous endpoints, max(105% of bInterval, U1 SEL * 2)
*/
-static u16 xhci_calculate_intel_u1_timeout(struct usb_device *udev,
+static unsigned long long xhci_calculate_intel_u1_timeout(
+ struct usb_device *udev,
struct usb_endpoint_descriptor *desc)
{
unsigned long long timeout_ns;
@@ -4344,11 +4334,28 @@ static u16 xhci_calculate_intel_u1_timeout(struct usb_device *udev,
return 0;
}
- /* The U1 timeout is encoded in 1us intervals. */
- timeout_ns = DIV_ROUND_UP_ULL(timeout_ns, 1000);
- /* Don't return a timeout of zero, because that's USB3_LPM_DISABLED. */
+ return timeout_ns;
+}
+
+/* Returns the hub-encoded U1 timeout value. */
+static u16 xhci_calculate_u1_timeout(struct xhci_hcd *xhci,
+ struct usb_device *udev,
+ struct usb_endpoint_descriptor *desc)
+{
+ unsigned long long timeout_ns;
+
+ if (xhci->quirks & XHCI_INTEL_HOST)
+ timeout_ns = xhci_calculate_intel_u1_timeout(udev, desc);
+ else
+ timeout_ns = udev->u1_params.sel;
+
+ /* The U1 timeout is encoded in 1us intervals.
+ * Don't return a timeout of zero, because that's USB3_LPM_DISABLED.
+ */
if (timeout_ns == USB3_LPM_DISABLED)
- timeout_ns++;
+ timeout_ns = 1;
+ else
+ timeout_ns = DIV_ROUND_UP_ULL(timeout_ns, 1000);
/* If the necessary timeout value is bigger than what we can set in the
* USB 3.0 hub, we have to disable hub-initiated U1.
@@ -4360,14 +4367,14 @@ static u16 xhci_calculate_intel_u1_timeout(struct usb_device *udev,
return xhci_get_timeout_no_hub_lpm(udev, USB3_LPM_U1);
}
-/* Returns the hub-encoded U2 timeout value.
- * The U2 timeout should be the maximum of:
+/* The U2 timeout should be the maximum of:
* - 10 ms (to avoid the bandwidth impact on the scheduler)
* - largest bInterval of any active periodic endpoint (to avoid going
* into lower power link states between intervals).
* - the U2 Exit Latency of the device
*/
-static u16 xhci_calculate_intel_u2_timeout(struct usb_device *udev,
+static unsigned long long xhci_calculate_intel_u2_timeout(
+ struct usb_device *udev,
struct usb_endpoint_descriptor *desc)
{
unsigned long long timeout_ns;
@@ -4383,6 +4390,21 @@ static u16 xhci_calculate_intel_u2_timeout(struct usb_device *udev,
if (u2_del_ns > timeout_ns)
timeout_ns = u2_del_ns;
+ return timeout_ns;
+}
+
+/* Returns the hub-encoded U2 timeout value. */
+static u16 xhci_calculate_u2_timeout(struct xhci_hcd *xhci,
+ struct usb_device *udev,
+ struct usb_endpoint_descriptor *desc)
+{
+ unsigned long long timeout_ns;
+
+ if (xhci->quirks & XHCI_INTEL_HOST)
+ timeout_ns = xhci_calculate_intel_u2_timeout(udev, desc);
+ else
+ timeout_ns = udev->u2_params.sel;
+
/* The U2 timeout is encoded in 256us intervals */
timeout_ns = DIV_ROUND_UP_ULL(timeout_ns, 256 * 1000);
/* If the necessary timeout value is bigger than what we can set in the
@@ -4401,13 +4423,10 @@ static u16 xhci_call_host_update_timeout_for_endpoint(struct xhci_hcd *xhci,
enum usb3_link_state state,
u16 *timeout)
{
- if (state == USB3_LPM_U1) {
- if (xhci->quirks & XHCI_INTEL_HOST)
- return xhci_calculate_intel_u1_timeout(udev, desc);
- } else {
- if (xhci->quirks & XHCI_INTEL_HOST)
- return xhci_calculate_intel_u2_timeout(udev, desc);
- }
+ if (state == USB3_LPM_U1)
+ return xhci_calculate_u1_timeout(xhci, udev, desc);
+ else if (state == USB3_LPM_U2)
+ return xhci_calculate_u2_timeout(xhci, udev, desc);
return USB3_LPM_DISABLED;
}
@@ -4484,7 +4503,8 @@ static int xhci_check_tier_policy(struct xhci_hcd *xhci,
{
if (xhci->quirks & XHCI_INTEL_HOST)
return xhci_check_intel_tier_policy(udev, state);
- return -EINVAL;
+ else
+ return 0;
}
/* Returns the U1 or U2 timeout that should be enabled.
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 9ffecd56600d..dace5152e179 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1558,6 +1558,8 @@ struct xhci_hcd {
#define XHCI_PLAT (1 << 16)
#define XHCI_SLOW_SUSPEND (1 << 17)
#define XHCI_SPURIOUS_WAKEUP (1 << 18)
+/* For controllers with a broken beyond repair streams implementation */
+#define XHCI_BROKEN_STREAMS (1 << 19)
unsigned int num_active_eps;
unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */