aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/Kconfig3
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-dbg.c15
-rw-r--r--drivers/usb/host/ehci-hcd.c74
-rw-r--r--drivers/usb/host/ehci-hub.c20
-rw-r--r--drivers/usb/host/ehci-mv.c2
-rw-r--r--drivers/usb/host/ehci-mxc.c8
-rw-r--r--drivers/usb/host/ehci-omap.c331
-rw-r--r--drivers/usb/host/ehci-orion.c4
-rw-r--r--drivers/usb/host/ehci-pci.c12
-rw-r--r--drivers/usb/host/ehci-platform.c34
-rw-r--r--drivers/usb/host/ehci-q.c241
-rw-r--r--drivers/usb/host/ehci-s5p.c11
-rw-r--r--drivers/usb/host/ehci-sched.c40
-rw-r--r--drivers/usb/host/ehci-sh.c5
-rw-r--r--drivers/usb/host/ehci-spear.c4
-rw-r--r--drivers/usb/host/ehci-timer.c72
-rw-r--r--drivers/usb/host/ehci-vt8500.c150
-rw-r--r--drivers/usb/host/ehci.h15
-rw-r--r--drivers/usb/host/ohci-hub.c6
-rw-r--r--drivers/usb/host/ohci-omap3.c24
-rw-r--r--drivers/usb/host/sl811-hcd.c2
-rw-r--r--drivers/usb/host/u132-hcd.c9
-rw-r--r--drivers/usb/host/xhci-hub.c2
-rw-r--r--drivers/usb/host/xhci.c4
25 files changed, 427 insertions, 662 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index c59a112..2f68221 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -155,8 +155,9 @@ config USB_EHCI_MXC
Variation of ARC USB block used in some Freescale chips.
config USB_EHCI_HCD_OMAP
- bool "EHCI support for OMAP3 and later chips"
+ tristate "EHCI support for OMAP3 and later chips"
depends on USB_EHCI_HCD && ARCH_OMAP
+ select NOP_USB_XCEIV
default y
---help---
Enables support for the on-chip EHCI controller on
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 001fbff..56de410 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
obj-$(CONFIG_USB_EHCI_HCD_PLATFORM) += ehci-platform.o
obj-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
+obj-$(CONFIG_USB_EHCI_HCD_OMAP) += ehci-omap.o
obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o
obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 70b496d..5429d26 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -510,14 +510,16 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf)
spin_lock_irqsave (&ehci->lock, flags);
for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh)
qh_lines (ehci, qh, &next, &size);
- if (ehci->async_unlink && size > 0) {
+ if (!list_empty(&ehci->async_unlink) && size > 0) {
temp = scnprintf(next, size, "\nunlink =\n");
size -= temp;
next += temp;
- for (qh = ehci->async_unlink; size > 0 && qh;
- qh = qh->unlink_next)
- qh_lines (ehci, qh, &next, &size);
+ list_for_each_entry(qh, &ehci->async_unlink, unlink_node) {
+ if (size <= 0)
+ break;
+ qh_lines(ehci, qh, &next, &size);
+ }
}
spin_unlock_irqrestore (&ehci->lock, flags);
@@ -814,9 +816,10 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
}
}
- if (ehci->async_unlink) {
+ if (!list_empty(&ehci->async_unlink)) {
temp = scnprintf(next, size, "async unlink qh %p\n",
- ehci->async_unlink);
+ list_first_entry(&ehci->async_unlink,
+ struct ehci_qh, unlink_node));
size -= temp;
next += temp;
}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 416a6dc..b12b97d 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -482,6 +482,9 @@ static int ehci_init(struct usb_hcd *hcd)
* periodic_size can shrink by USBCMD update if hcc_params allows.
*/
ehci->periodic_size = DEFAULT_I_TDPS;
+ INIT_LIST_HEAD(&ehci->async_unlink);
+ INIT_LIST_HEAD(&ehci->async_idle);
+ INIT_LIST_HEAD(&ehci->intr_unlink);
INIT_LIST_HEAD(&ehci->intr_qh_list);
INIT_LIST_HEAD(&ehci->cached_itd_list);
INIT_LIST_HEAD(&ehci->cached_sitd_list);
@@ -749,7 +752,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* guard against (alleged) silicon errata */
if (cmd & CMD_IAAD)
ehci_dbg(ehci, "IAA with IAAD still set?\n");
- if (ehci->async_iaa)
+ if (ehci->iaa_in_progress)
COUNT(ehci->stats.iaa);
end_unlink_async(ehci);
}
@@ -757,7 +760,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* remote wakeup [4.3.1] */
if (status & STS_PCD) {
unsigned i = HCS_N_PORTS (ehci->hcs_params);
- u32 ppcd = 0;
+ u32 ppcd = ~0;
/* kick root hub later */
pcd_status = status;
@@ -774,7 +777,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
int pstatus;
/* leverage per-port change bits feature */
- if (ehci->has_ppcd && !(ppcd & (1 << i)))
+ if (!(ppcd & (1 << i)))
continue;
pstatus = ehci_readl(ehci,
&ehci->regs->port_status[i]);
@@ -896,17 +899,24 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
if (rc)
goto done;
- switch (usb_pipetype (urb->pipe)) {
- // case PIPE_CONTROL:
- // case PIPE_BULK:
- default:
+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+ /*
+ * We don't expedite dequeue for isochronous URBs.
+ * Just wait until they complete normally or their
+ * time slot expires.
+ */
+ } else {
qh = (struct ehci_qh *) urb->hcpriv;
- if (!qh)
- break;
+ qh->exception = 1;
switch (qh->qh_state) {
case QH_STATE_LINKED:
+ if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)
+ start_unlink_intr(ehci, qh);
+ else
+ start_unlink_async(ehci, qh);
+ break;
case QH_STATE_COMPLETING:
- start_unlink_async(ehci, qh);
+ qh->dequeue_during_giveback = 1;
break;
case QH_STATE_UNLINK:
case QH_STATE_UNLINK_WAIT:
@@ -917,33 +927,6 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
qh_completions(ehci, qh);
break;
}
- break;
-
- case PIPE_INTERRUPT:
- qh = (struct ehci_qh *) urb->hcpriv;
- if (!qh)
- break;
- switch (qh->qh_state) {
- case QH_STATE_LINKED:
- case QH_STATE_COMPLETING:
- start_unlink_intr(ehci, qh);
- break;
- case QH_STATE_IDLE:
- qh_completions (ehci, qh);
- break;
- default:
- ehci_dbg (ehci, "bogus qh %p state %d\n",
- qh, qh->qh_state);
- goto done;
- }
- break;
-
- case PIPE_ISOCHRONOUS:
- // itd or sitd ...
-
- // wait till next completion, do it then.
- // completion irqs can wait up to 1024 msec,
- break;
}
done:
spin_unlock_irqrestore (&ehci->lock, flags);
@@ -984,6 +967,7 @@ rescan:
goto done;
}
+ qh->exception = 1;
if (ehci->rh_state < EHCI_RH_RUNNING)
qh->qh_state = QH_STATE_IDLE;
switch (qh->qh_state) {
@@ -1052,13 +1036,12 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
usb_settoggle(qh->dev, epnum, is_out, 0);
if (!list_empty(&qh->qtd_list)) {
WARN_ONCE(1, "clear_halt for a busy endpoint\n");
- } else if (qh->qh_state == QH_STATE_LINKED ||
- qh->qh_state == QH_STATE_COMPLETING) {
-
+ } else {
/* The toggle value in the QH can't be updated
* while the QH is active. Unlink it now;
* re-linking will call qh_refresh().
*/
+ qh->exception = 1;
if (eptype == USB_ENDPOINT_XFER_BULK)
start_unlink_async(ehci, qh);
else
@@ -1251,11 +1234,6 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_hcd_sh_driver
#endif
-#ifdef CONFIG_USB_EHCI_HCD_OMAP
-#include "ehci-omap.c"
-#define PLATFORM_DRIVER ehci_hcd_omap_driver
-#endif
-
#ifdef CONFIG_PPC_PS3
#include "ehci-ps3.c"
#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver
@@ -1291,11 +1269,6 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_octeon_driver
#endif
-#ifdef CONFIG_ARCH_VT8500
-#include "ehci-vt8500.c"
-#define PLATFORM_DRIVER vt8500_ehci_driver
-#endif
-
#ifdef CONFIG_PLAT_SPEAR
#include "ehci-spear.c"
#define PLATFORM_DRIVER spear_ehci_hcd_driver
@@ -1345,6 +1318,7 @@ MODULE_LICENSE ("GPL");
!IS_ENABLED(CONFIG_USB_EHCI_HCD_PLATFORM) && \
!IS_ENABLED(CONFIG_USB_CHIPIDEA_HOST) && \
!IS_ENABLED(CONFIG_USB_EHCI_MXC) && \
+ !IS_ENABLED(CONFIG_USB_EHCI_HCD_OMAP) && \
!defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && \
!defined(OF_PLATFORM_DRIVER) && \
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 7d06e77..7b04ca9 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -464,7 +464,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
while (i--) {
temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
if (test_bit(i, &resume_needed)) {
- temp &= ~(PORT_RWC_BITS | PORT_RESUME);
+ temp &= ~(PORT_RWC_BITS | PORT_SUSPEND | PORT_RESUME);
ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
ehci_vdbg (ehci, "resumed port %d\n", i + 1);
}
@@ -590,7 +590,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
u32 mask;
int ports, i, retval = 1;
unsigned long flags;
- u32 ppcd = 0;
+ u32 ppcd = ~0;
/* init status to no-changes */
buf [0] = 0;
@@ -628,9 +628,10 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
for (i = 0; i < ports; i++) {
/* leverage per-port change bits feature */
- if (ehci->has_ppcd && !(ppcd & (1 << i)))
- continue;
- temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
+ if (ppcd & (1 << i))
+ temp = ehci_readl(ehci, &ehci->regs->port_status[i]);
+ else
+ temp = 0;
/*
* Return status information even for ports with OWNER set.
@@ -870,10 +871,9 @@ static int ehci_hub_control (
usb_hcd_end_port_resume(&hcd->self, wIndex);
/* stop resume signaling */
- temp = ehci_readl(ehci, status_reg);
- ehci_writel(ehci,
- temp & ~(PORT_RWC_BITS | PORT_RESUME),
- status_reg);
+ temp &= ~(PORT_RWC_BITS |
+ PORT_SUSPEND | PORT_RESUME);
+ ehci_writel(ehci, temp, status_reg);
clear_bit(wIndex, &ehci->resuming_ports);
retval = handshake(ehci, status_reg,
PORT_RESUME, 0, 2000 /* 2msec */);
@@ -883,7 +883,7 @@ static int ehci_hub_control (
wIndex + 1, retval);
goto error;
}
- temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+ temp = ehci_readl(ehci, status_reg);
}
}
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c
index 3065809..5cd9f96 100644
--- a/drivers/usb/host/ehci-mv.c
+++ b/drivers/usb/host/ehci-mv.c
@@ -225,7 +225,7 @@ static int mv_ehci_probe(struct platform_device *pdev)
(void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset);
hcd->rsrc_start = r->start;
- hcd->rsrc_len = r->end - r->start + 1;
+ hcd->rsrc_len = resource_size(r);
hcd->regs = ehci_mv->op_regs;
hcd->irq = platform_get_irq(pdev, 0);
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index e9301fb..a38c8c8 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -28,11 +28,7 @@
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
-
#include <linux/platform_data/usb-ehci-mxc.h>
-
-#include <asm/mach-types.h>
-
#include "ehci.h"
#define DRIVER_DESC "Freescale On-Chip EHCI Host driver"
@@ -61,8 +57,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct ehci_hcd *ehci;
- dev_info(&pdev->dev, "initializing i.MX USB Controller\n");
-
if (!pdata) {
dev_err(dev, "No platform data given, bailing out.\n");
return -EINVAL;
@@ -178,7 +172,7 @@ err_alloc:
return ret;
}
-static int __exit ehci_mxc_drv_remove(struct platform_device *pdev)
+static int ehci_mxc_drv_remove(struct platform_device *pdev)
{
struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
struct usb_hcd *hcd = platform_get_drvdata(pdev);
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 0555ee4..5de3e43 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -4,10 +4,11 @@
* Bus Glue for the EHCI controllers in OMAP3/4
* Tested on several OMAP3 boards, and OMAP4 Pandaboard
*
- * Copyright (C) 2007-2011 Texas Instruments, Inc.
+ * Copyright (C) 2007-2013 Texas Instruments, Inc.
* Author: Vikram Pandita <vikram.pandita@ti.com>
* Author: Anand Gadiyar <gadiyar@ti.com>
* Author: Keshava Munegowda <keshava_mgowda@ti.com>
+ * Author: Roger Quadros <rogerq@ti.com>
*
* Copyright (C) 2009 Nokia Corporation
* Contact: Felipe Balbi <felipe.balbi@nokia.com>
@@ -28,21 +29,23 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * TODO (last updated Feb 27, 2010):
- * - add kernel-doc
- * - enable AUTOIDLE
- * - add suspend/resume
- * - add HSIC and TLL support
- * - convert to use hwmod and runtime PM
*/
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/usb/ulpi.h>
-#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/gpio.h>
#include <linux/clk.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/of.h>
+#include <linux/dma-mapping.h>
+
+#include "ehci.h"
#include <linux/platform_data/usb-omap.h>
@@ -57,10 +60,16 @@
#define EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT 8
#define EHCI_INSNREG05_ULPI_WRDATA_SHIFT 0
-/*-------------------------------------------------------------------------*/
+#define DRIVER_DESC "OMAP-EHCI Host Controller driver"
+
+static const char hcd_name[] = "ehci-omap";
-static const struct hc_driver ehci_omap_hc_driver;
+/*-------------------------------------------------------------------------*/
+struct omap_hcd {
+ struct usb_phy *phy[OMAP3_HS_USB_PORTS]; /* one PHY for each port */
+ int nports;
+};
static inline void ehci_write(void __iomem *base, u32 reg, u32 val)
{
@@ -72,99 +81,16 @@ static inline u32 ehci_read(void __iomem *base, u32 reg)
return __raw_readl(base + reg);
}
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
-static void omap_ehci_soft_phy_reset(struct usb_hcd *hcd, u8 port)
-{
- unsigned long timeout = jiffies + msecs_to_jiffies(1000);
- unsigned reg = 0;
-
- reg = ULPI_FUNC_CTRL_RESET
- /* FUNCTION_CTRL_SET register */
- | (ULPI_SET(ULPI_FUNC_CTRL) << EHCI_INSNREG05_ULPI_REGADD_SHIFT)
- /* Write */
- | (2 << EHCI_INSNREG05_ULPI_OPSEL_SHIFT)
- /* PORTn */
- | ((port + 1) << EHCI_INSNREG05_ULPI_PORTSEL_SHIFT)
- /* start ULPI access*/
- | (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT);
-
- ehci_write(hcd->regs, EHCI_INSNREG05_ULPI, reg);
-
- /* Wait for ULPI access completion */
- while ((ehci_read(hcd->regs, EHCI_INSNREG05_ULPI)
- & (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT))) {
- cpu_relax();
-
- if (time_after(jiffies, timeout)) {
- dev_dbg(hcd->self.controller,
- "phy reset operation timed out\n");
- break;
- }
- }
-}
-
-static int omap_ehci_init(struct usb_hcd *hcd)
-{
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- int rc;
- struct usbhs_omap_platform_data *pdata;
-
- pdata = hcd->self.controller->platform_data;
-
- /* Hold PHYs in reset while initializing EHCI controller */
- if (pdata->phy_reset) {
- if (gpio_is_valid(pdata->reset_gpio_port[0]))
- gpio_set_value_cansleep(pdata->reset_gpio_port[0], 0);
-
- if (gpio_is_valid(pdata->reset_gpio_port[1]))
- gpio_set_value_cansleep(pdata->reset_gpio_port[1], 0);
-
- /* Hold the PHY in RESET for enough time till DIR is high */
- udelay(10);
- }
-
- /* Soft reset the PHY using PHY reset command over ULPI */
- if (pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY)
- omap_ehci_soft_phy_reset(hcd, 0);
- if (pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_PHY)
- omap_ehci_soft_phy_reset(hcd, 1);
-
- /* we know this is the memory we want, no need to ioremap again */
- ehci->caps = hcd->regs;
-
- rc = ehci_setup(hcd);
-
- if (pdata->phy_reset) {
- /* Hold the PHY in RESET for enough time till
- * PHY is settled and ready
- */
- udelay(10);
-
- if (gpio_is_valid(pdata->reset_gpio_port[0]))
- gpio_set_value_cansleep(pdata->reset_gpio_port[0], 1);
-
- if (gpio_is_valid(pdata->reset_gpio_port[1]))
- gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1);
- }
-
- return rc;
-}
+static struct hc_driver __read_mostly ehci_omap_hc_driver;
-static void disable_put_regulator(
- struct usbhs_omap_platform_data *pdata)
-{
- int i;
-
- for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
- if (pdata->regulator[i]) {
- regulator_disable(pdata->regulator[i]);
- regulator_put(pdata->regulator[i]);
- }
- }
-}
+static const struct ehci_driver_overrides ehci_omap_overrides __initdata = {
+ .extra_priv_size = sizeof(struct omap_hcd),
+};
-/* configure so an HC device and id are always provided */
-/* always called with process context; sleeping is OK */
+static u64 omap_ehci_dma_mask = DMA_BIT_MASK(32);
/**
* ehci_hcd_omap_probe - initialize TI-based HCDs
@@ -175,15 +101,15 @@ static void disable_put_regulator(
*/
static int ehci_hcd_omap_probe(struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
- struct usbhs_omap_platform_data *pdata = dev->platform_data;
- struct resource *res;
- struct usb_hcd *hcd;
- void __iomem *regs;
- int ret = -ENODEV;
- int irq;
- int i;
- char supply[7];
+ struct device *dev = &pdev->dev;
+ struct usbhs_omap_platform_data *pdata = dev->platform_data;
+ struct resource *res;
+ struct usb_hcd *hcd;
+ void __iomem *regs;
+ int ret = -ENODEV;
+ int irq;
+ int i;
+ struct omap_hcd *omap;
if (usb_disabled())
return -ENODEV;
@@ -193,52 +119,74 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
return -ENODEV;
}
- irq = platform_get_irq_byname(pdev, "ehci-irq");
- if (irq < 0) {
- dev_err(dev, "EHCI irq failed\n");
- return -ENODEV;
+ /* For DT boot, get platform data from parent. i.e. usbhshost */
+ if (dev->of_node) {
+ pdata = dev->parent->platform_data;
+ dev->platform_data = pdata;
}
- res = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "ehci");
- if (!res) {
- dev_err(dev, "UHH EHCI get resource failed\n");
+ if (!pdata) {
+ dev_err(dev, "Missing platform data\n");
return -ENODEV;
}
- regs = ioremap(res->start, resource_size(res));
- if (!regs) {
- dev_err(dev, "UHH EHCI ioremap failed\n");
- return -ENOMEM;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "EHCI irq failed\n");
+ return -ENODEV;
}
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ /*
+ * Right now device-tree probed devices don't get dma_mask set.
+ * Since shared usb code relies on it, set it here for now.
+ * Once we have dma capability bindings this can go away.
+ */
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &omap_ehci_dma_mask;
+
hcd = usb_create_hcd(&ehci_omap_hc_driver, dev,
dev_name(dev));
if (!hcd) {
- dev_err(dev, "failed to create hcd with err %d\n", ret);
- ret = -ENOMEM;
- goto err_io;
+ dev_err(dev, "Failed to create HCD\n");
+ return -ENOMEM;
}
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
hcd->regs = regs;
-
- /* get ehci regulator and enable */
- for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
- if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) {
- pdata->regulator[i] = NULL;
- continue;
- }
- snprintf(supply, sizeof(supply), "hsusb%d", i);
- pdata->regulator[i] = regulator_get(dev, supply);
- if (IS_ERR(pdata->regulator[i])) {
- pdata->regulator[i] = NULL;
- dev_dbg(dev,
- "failed to get ehci port%d regulator\n", i);
- } else {
- regulator_enable(pdata->regulator[i]);
+ hcd_to_ehci(hcd)->caps = regs;
+
+ omap = (struct omap_hcd *)hcd_to_ehci(hcd)->priv;
+ omap->nports = pdata->nports;
+
+ platform_set_drvdata(pdev, hcd);
+
+ /* get the PHY devices if needed */
+ for (i = 0 ; i < omap->nports ; i++) {
+ 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);
+ if (IS_ERR(phy) || !phy) {
+ /* Don't bail out if PHY is not absolutely necessary */
+ if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY)
+ continue;
+
+ ret = IS_ERR(phy) ? PTR_ERR(phy) : -ENODEV;
+ dev_err(dev, "Can't get PHY device for port %d: %d\n",
+ i, ret);
+ goto err_phy;
}
+
+ omap->phy[i] = phy;
}
pm_runtime_enable(dev);
@@ -262,16 +210,34 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
goto err_pm_runtime;
}
+ /*
+ * Bring PHYs out of reset.
+ * Even though HSIC mode is a PHY-less mode, the reset
+ * line exists between the chips and can be modelled
+ * as a PHY device for reset control.
+ */
+ for (i = 0; i < omap->nports; i++) {
+ if (!omap->phy[i])
+ continue;
+
+ usb_phy_init(omap->phy[i]);
+ /* bring PHY out of suspend */
+ usb_phy_set_suspend(omap->phy[i], 0);
+ }
return 0;
err_pm_runtime:
- disable_put_regulator(pdata);
pm_runtime_put_sync(dev);
+
+err_phy:
+ for (i = 0; i < omap->nports; i++) {
+ if (omap->phy[i])
+ usb_phy_shutdown(omap->phy[i]);
+ }
+
usb_put_hcd(hcd);
-err_io:
- iounmap(regs);
return ret;
}
@@ -286,14 +252,19 @@ err_io:
*/
static int ehci_hcd_omap_remove(struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
- struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct device *dev = &pdev->dev;
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct omap_hcd *omap = (struct omap_hcd *)hcd_to_ehci(hcd)->priv;
+ int i;
usb_remove_hcd(hcd);
- disable_put_regulator(dev->platform_data);
- iounmap(hcd->regs);
- usb_put_hcd(hcd);
+ for (i = 0; i < omap->nports; i++) {
+ if (omap->phy[i])
+ usb_phy_shutdown(omap->phy[i]);
+ }
+
+ usb_put_hcd(hcd);
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
@@ -308,6 +279,13 @@ static void ehci_hcd_omap_shutdown(struct platform_device *pdev)
hcd->driver->shutdown(hcd);
}
+static const struct of_device_id omap_ehci_dt_ids[] = {
+ { .compatible = "ti,ehci-omap" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, omap_ehci_dt_ids);
+
static struct platform_driver ehci_hcd_omap_driver = {
.probe = ehci_hcd_omap_probe,
.remove = ehci_hcd_omap_remove,
@@ -315,56 +293,35 @@ static struct platform_driver ehci_hcd_omap_driver = {
/*.suspend = ehci_hcd_omap_suspend, */
/*.resume = ehci_hcd_omap_resume, */
.driver = {
- .name = "ehci-omap",
+ .name = hcd_name,
+ .of_match_table = of_match_ptr(omap_ehci_dt_ids),
}
};
/*-------------------------------------------------------------------------*/
-static const struct hc_driver ehci_omap_hc_driver = {
- .description = hcd_name,
- .product_desc = "OMAP-EHCI Host Controller",
- .hcd_priv_size = sizeof(struct ehci_hcd),
-
- /*
- * generic hardware linkage
- */
- .irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
-
- /*
- * basic lifecycle operations
- */
- .reset = omap_ehci_init,
- .start = ehci_run,
- .stop = ehci_stop,
- .shutdown = ehci_shutdown,
-
- /*
- * managing i/o requests and associated device resources
- */
- .urb_enqueue = ehci_urb_enqueue,
- .urb_dequeue = ehci_urb_dequeue,
- .endpoint_disable = ehci_endpoint_disable,
- .endpoint_reset = ehci_endpoint_reset,
+static int __init ehci_omap_init(void)
+{
+ if (usb_disabled())
+ return -ENODEV;
- /*
- * scheduling support
- */
- .get_frame_number = ehci_get_frame,
+ pr_info("%s: " DRIVER_DESC "\n", hcd_name);
- /*
- * root hub support
- */
- .hub_status_data = ehci_hub_status_data,
- .hub_control = ehci_hub_control,
- .bus_suspend = ehci_bus_suspend,
- .bus_resume = ehci_bus_resume,
+ ehci_init_driver(&ehci_omap_hc_driver, &ehci_omap_overrides);
+ return platform_driver_register(&ehci_hcd_omap_driver);
+}
+module_init(ehci_omap_init);
- .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
-};
+static void __exit ehci_omap_cleanup(void)
+{
+ platform_driver_unregister(&ehci_hcd_omap_driver);
+}
+module_exit(ehci_omap_cleanup);
MODULE_ALIAS("platform:ehci-omap");
MODULE_AUTHOR("Texas Instruments, Inc.");
MODULE_AUTHOR("Felipe Balbi <felipe.balbi@nokia.com>");
+MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
index 914a3ec..38c45fb 100644
--- a/drivers/usb/host/ehci-orion.c
+++ b/drivers/usb/host/ehci-orion.c
@@ -305,7 +305,7 @@ err1:
return err;
}
-static int __exit ehci_orion_drv_remove(struct platform_device *pdev)
+static int ehci_orion_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct clk *clk;
@@ -333,7 +333,7 @@ MODULE_DEVICE_TABLE(of, ehci_orion_dt_ids);
static struct platform_driver ehci_orion_driver = {
.probe = ehci_orion_drv_probe,
- .remove = __exit_p(ehci_orion_drv_remove),
+ .remove = ehci_orion_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "orion-ehci",
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 170b939..a573d5f 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -292,17 +292,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
}
}
-#ifdef CONFIG_USB_SUSPEND
- /* REVISIT: the controller works fine for wakeup iff the root hub
- * itself is "globally" suspended, but usbcore currently doesn't
- * understand such things.
- *
- * System suspend currently expects to be able to suspend the entire
- * device tree, device-at-a-time. If we failed selective suspend
- * reports, system suspend would fail; so the root hub code must claim
- * success. That's lying to usbcore, and it matters for runtime
- * PM scenarios with selective suspend and remote wakeup...
- */
+#ifdef CONFIG_PM_RUNTIME
if (ehci->no_selective_suspend && device_can_wakeup(&pdev->dev))
ehci_warn(ehci, "selective suspend/wakeup unavailable\n");
#endif
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index ca75063..cda0fa9 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -18,11 +18,13 @@
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
+#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/hrtimer.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
@@ -62,22 +64,32 @@ static const struct ehci_driver_overrides platform_overrides __initdata = {
.reset = ehci_platform_reset,
};
+static struct usb_ehci_pdata ehci_platform_defaults;
+
static int ehci_platform_probe(struct platform_device *dev)
{
struct usb_hcd *hcd;
struct resource *res_mem;
- struct usb_ehci_pdata *pdata = dev->dev.platform_data;
+ struct usb_ehci_pdata *pdata;
int irq;
int err = -ENOMEM;
- if (!pdata) {
- WARN_ON(1);
- return -ENODEV;
- }
-
if (usb_disabled())
return -ENODEV;
+ /*
+ * use reasonable defaults so platforms don't have to provide these.
+ * with DT probing on ARM, none of these are set.
+ */
+ if (!dev->dev.platform_data)
+ dev->dev.platform_data = &ehci_platform_defaults;
+ if (!dev->dev.dma_mask)
+ dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
+ if (!dev->dev.coherent_dma_mask)
+ dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+ pdata = dev->dev.platform_data;
+
irq = platform_get_irq(dev, 0);
if (irq < 0) {
dev_err(&dev->dev, "no irq provided");
@@ -139,6 +151,9 @@ static int ehci_platform_remove(struct platform_device *dev)
if (pdata->power_off)
pdata->power_off(dev);
+ if (pdata == &ehci_platform_defaults)
+ dev->dev.platform_data = NULL;
+
return 0;
}
@@ -183,6 +198,12 @@ static int ehci_platform_resume(struct device *dev)
#define ehci_platform_resume NULL
#endif /* CONFIG_PM */
+static const struct of_device_id vt8500_ehci_ids[] = {
+ { .compatible = "via,vt8500-ehci", },
+ { .compatible = "wm,prizm-ehci", },
+ {}
+};
+
static const struct platform_device_id ehci_platform_table[] = {
{ "ehci-platform", 0 },
{ }
@@ -203,6 +224,7 @@ static struct platform_driver ehci_platform_driver = {
.owner = THIS_MODULE,
.name = "ehci-platform",
.pm = &ehci_platform_pm_ops,
+ .of_match_table = of_match_ptr(vt8500_ehci_ids),
}
};
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 23d1369..d34b399 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -90,7 +90,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
struct ehci_qh_hw *hw = qh->hw;
/* writes to an active overlay are unsafe */
- BUG_ON(qh->qh_state != QH_STATE_IDLE);
+ WARN_ON(qh->qh_state != QH_STATE_IDLE);
hw->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);
hw->hw_alt_next = EHCI_LIST_END(ehci);
@@ -123,26 +123,19 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
struct ehci_qtd *qtd;
- if (list_empty (&qh->qtd_list))
- qtd = qh->dummy;
- else {
- qtd = list_entry (qh->qtd_list.next,
- struct ehci_qtd, qtd_list);
- /*
- * first qtd may already be partially processed.
- * If we come here during unlink, the QH overlay region
- * might have reference to the just unlinked qtd. The
- * qtd is updated in qh_completions(). Update the QH
- * overlay here.
- */
- if (qh->hw->hw_token & ACTIVE_BIT(ehci)) {
- qh->hw->hw_qtd_next = qtd->hw_next;
- qtd = NULL;
- }
- }
+ qtd = list_entry(qh->qtd_list.next, struct ehci_qtd, qtd_list);
- if (qtd)
- qh_update (ehci, qh, qtd);
+ /*
+ * first qtd may already be partially processed.
+ * If we come here during unlink, the QH overlay region
+ * might have reference to the just unlinked qtd. The
+ * qtd is updated in qh_completions(). Update the QH
+ * overlay here.
+ */
+ if (qh->hw->hw_token & ACTIVE_BIT(ehci))
+ qh->hw->hw_qtd_next = qtd->hw_next;
+ else
+ qh_update(ehci, qh, qtd);
}
/*-------------------------------------------------------------------------*/
@@ -299,8 +292,8 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
/*
* Process and free completed qtds for a qh, returning URBs to drivers.
- * Chases up to qh->hw_current. Returns number of completions called,
- * indicating how much "real" work we did.
+ * Chases up to qh->hw_current. Returns nonzero if the caller should
+ * unlink qh.
*/
static unsigned
qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
@@ -309,13 +302,9 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
struct list_head *entry, *tmp;
int last_status;
int stopped;
- unsigned count = 0;
u8 state;
struct ehci_qh_hw *hw = qh->hw;
- if (unlikely (list_empty (&qh->qtd_list)))
- return count;
-
/* completions (or tasks on other cpus) must never clobber HALT
* till we've gone through and cleaned everything up, even when
* they add urbs to this qh's queue or mark them for unlinking.
@@ -333,7 +322,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
rescan:
last = NULL;
last_status = -EINPROGRESS;
- qh->needs_rescan = 0;
+ qh->dequeue_during_giveback = 0;
/* remove de-activated QTDs from front of queue.
* after faults (including short reads), cleanup this urb
@@ -352,7 +341,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (last) {
if (likely (last->urb != urb)) {
ehci_urb_done(ehci, last->urb, last_status);
- count++;
last_status = -EINPROGRESS;
}
ehci_qtd_free (ehci, last);
@@ -526,23 +514,16 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* last urb's completion might still need calling */
if (likely (last != NULL)) {
ehci_urb_done(ehci, last->urb, last_status);
- count++;
ehci_qtd_free (ehci, last);
}
/* Do we need to rescan for URBs dequeued during a giveback? */
- if (unlikely(qh->needs_rescan)) {
+ if (unlikely(qh->dequeue_during_giveback)) {
/* If the QH is already unlinked, do the rescan now. */
if (state == QH_STATE_IDLE)
goto rescan;
- /* Otherwise we have to wait until the QH is fully unlinked.
- * Our caller will start an unlink if qh->needs_rescan is
- * set. But if an unlink has already started, nothing needs
- * to be done.
- */
- if (state != QH_STATE_LINKED)
- qh->needs_rescan = 0;
+ /* Otherwise the caller must unlink the QH. */
}
/* restore original state; caller must unlink or relink */
@@ -551,33 +532,23 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* be sure the hardware's done with the qh before refreshing
* it after fault cleanup, or recovering from silicon wrongly
* overlaying the dummy qtd (which reduces DMA chatter).
+ *
+ * We won't refresh a QH that's linked (after the HC
+ * stopped the queue). That avoids a race:
+ * - HC reads first part of QH;
+ * - CPU updates that first part and the token;
+ * - HC reads rest of that QH, including token
+ * Result: HC gets an inconsistent image, and then
+ * DMAs to/from the wrong memory (corrupting it).
+ *
+ * That should be rare for interrupt transfers,
+ * except maybe high bandwidth ...
*/
- if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci)) {
- switch (state) {
- case QH_STATE_IDLE:
- qh_refresh(ehci, qh);
- break;
- case QH_STATE_LINKED:
- /* We won't refresh a QH that's linked (after the HC
- * stopped the queue). That avoids a race:
- * - HC reads first part of QH;
- * - CPU updates that first part and the token;
- * - HC reads rest of that QH, including token
- * Result: HC gets an inconsistent image, and then
- * DMAs to/from the wrong memory (corrupting it).
- *
- * That should be rare for interrupt transfers,
- * except maybe high bandwidth ...
- */
+ if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci))
+ qh->exception = 1;
- /* Tell the caller to start an unlink */
- qh->needs_rescan = 1;
- break;
- /* otherwise, unlink already started */
- }
- }
-
- return count;
+ /* Let the caller know if the QH needs to be unlinked. */
+ return qh->exception;
}
/*-------------------------------------------------------------------------*/
@@ -957,14 +928,13 @@ done:
/* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */
- /* init as live, toggle clear, advance to dummy */
+ /* init as live, toggle clear */
qh->qh_state = QH_STATE_IDLE;
hw = qh->hw;
hw->hw_info1 = cpu_to_hc32(ehci, info1);
hw->hw_info2 = cpu_to_hc32(ehci, info2);
qh->is_out = !is_input;
usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
- qh_refresh (ehci, qh);
return qh;
}
@@ -988,8 +958,9 @@ static void disable_async(struct ehci_hcd *ehci)
if (--ehci->async_count)
return;
- /* The async schedule and async_unlink list are supposed to be empty */
- WARN_ON(ehci->async->qh_next.qh || ehci->async_unlink);
+ /* The async schedule and unlink lists are supposed to be empty */
+ WARN_ON(ehci->async->qh_next.qh || !list_empty(&ehci->async_unlink) ||
+ !list_empty(&ehci->async_idle));
/* Don't turn off the schedule until ASS is 1 */
ehci_poll_ASS(ehci);
@@ -1020,8 +991,9 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
head->qh_next.qh = qh;
head->hw->hw_next = dma;
- qh->xacterrs = 0;
qh->qh_state = QH_STATE_LINKED;
+ qh->xacterrs = 0;
+ qh->exception = 0;
/* qtd completions reported later by interrupt */
enable_async(ehci);
@@ -1179,11 +1151,7 @@ static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
/* Add to the end of the list of QHs waiting for the next IAAD */
qh->qh_state = QH_STATE_UNLINK_WAIT;
- if (ehci->async_unlink)
- ehci->async_unlink_last->unlink_next = qh;
- else
- ehci->async_unlink = qh;
- ehci->async_unlink_last = qh;
+ list_add_tail(&qh->unlink_node, &ehci->async_unlink);
/* Unlink it from the schedule */
prev = ehci->async;
@@ -1196,44 +1164,19 @@ static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
ehci->qh_scan_next = qh->qh_next.qh;
}
-static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested)
+static void start_iaa_cycle(struct ehci_hcd *ehci)
{
- /*
- * Do nothing if an IAA cycle is already running or
- * if one will be started shortly.
- */
- if (ehci->async_iaa || ehci->async_unlinking)
+ /* Do nothing if an IAA cycle is already running */
+ if (ehci->iaa_in_progress)
return;
+ ehci->iaa_in_progress = true;
/* If the controller isn't running, we don't have to wait for it */
if (unlikely(ehci->rh_state < EHCI_RH_RUNNING)) {
-
- /* Do all the waiting QHs */
- ehci->async_iaa = ehci->async_unlink;
- ehci->async_unlink = NULL;
-
- if (!nested) /* Avoid recursion */
- end_unlink_async(ehci);
+ end_unlink_async(ehci);
/* Otherwise start a new IAA cycle */
} else if (likely(ehci->rh_state == EHCI_RH_RUNNING)) {
- struct ehci_qh *qh;
-
- /* Do only the first waiting QH (nVidia bug?) */
- qh = ehci->async_unlink;
-
- /*
- * Intel (?) bug: The HC can write back the overlay region
- * even after the IAA interrupt occurs. In self-defense,
- * always go through two IAA cycles for each QH.
- */
- if (qh->qh_state == QH_STATE_UNLINK_WAIT) {
- qh->qh_state = QH_STATE_UNLINK;
- } else {
- ehci->async_iaa = qh;
- ehci->async_unlink = qh->unlink_next;
- qh->unlink_next = NULL;
- }
/* Make sure the unlinks are all visible to the hardware */
wmb();
@@ -1250,36 +1193,73 @@ static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested)
static void end_unlink_async(struct ehci_hcd *ehci)
{
struct ehci_qh *qh;
+ bool early_exit;
if (ehci->has_synopsys_hc_bug)
ehci_writel(ehci, (u32) ehci->async->qh_dma,
&ehci->regs->async_next);
+ /* The current IAA cycle has ended */
+ ehci->iaa_in_progress = false;
+
+ if (list_empty(&ehci->async_unlink))
+ return;
+ qh = list_first_entry(&ehci->async_unlink, struct ehci_qh,
+ unlink_node); /* QH whose IAA cycle just ended */
+
+ /*
+ * If async_unlinking is set then this routine is already running,
+ * either on the stack or on another CPU.
+ */
+ early_exit = ehci->async_unlinking;
+
+ /* If the controller isn't running, process all the waiting QHs */
+ if (ehci->rh_state < EHCI_RH_RUNNING)
+ list_splice_tail_init(&ehci->async_unlink, &ehci->async_idle);
+
+ /*
+ * Intel (?) bug: The HC can write back the overlay region even
+ * after the IAA interrupt occurs. In self-defense, always go
+ * through two IAA cycles for each QH.
+ */
+ else if (qh->qh_state == QH_STATE_UNLINK_WAIT) {
+ qh->qh_state = QH_STATE_UNLINK;
+ early_exit = true;
+ }
+
+ /* Otherwise process only the first waiting QH (NVIDIA bug?) */
+ else
+ list_move_tail(&qh->unlink_node, &ehci->async_idle);
+
+ /* Start a new IAA cycle if any QHs are waiting for it */
+ if (!list_empty(&ehci->async_unlink))
+ start_iaa_cycle(ehci);
+
+ /*
+ * Don't allow nesting or concurrent calls,
+ * or wait for the second IAA cycle for the next QH.
+ */
+ if (early_exit)
+ return;
+
/* Process the idle QHs */
- restart:
ehci->async_unlinking = true;
- while (ehci->async_iaa) {
- qh = ehci->async_iaa;
- ehci->async_iaa = qh->unlink_next;
- qh->unlink_next = NULL;
+ while (!list_empty(&ehci->async_idle)) {
+ qh = list_first_entry(&ehci->async_idle, struct ehci_qh,
+ unlink_node);
+ list_del(&qh->unlink_node);
qh->qh_state = QH_STATE_IDLE;
qh->qh_next.qh = NULL;
- qh_completions(ehci, qh);
+ if (!list_empty(&qh->qtd_list))
+ qh_completions(ehci, qh);
if (!list_empty(&qh->qtd_list) &&
ehci->rh_state == EHCI_RH_RUNNING)
qh_link_async(ehci, qh);
disable_async(ehci);
}
ehci->async_unlinking = false;
-
- /* Start a new IAA cycle if any QHs are waiting for it */
- if (ehci->async_unlink) {
- start_iaa_cycle(ehci, true);
- if (unlikely(ehci->rh_state < EHCI_RH_RUNNING))
- goto restart;
- }
}
static void start_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh);
@@ -1288,7 +1268,6 @@ static void unlink_empty_async(struct ehci_hcd *ehci)
{
struct ehci_qh *qh;
struct ehci_qh *qh_to_unlink = NULL;
- bool check_unlinks_later = false;
int count = 0;
/* Find the last async QH which has been empty for a timer cycle */
@@ -1296,15 +1275,13 @@ static void unlink_empty_async(struct ehci_hcd *ehci)
if (list_empty(&qh->qtd_list) &&
qh->qh_state == QH_STATE_LINKED) {
++count;
- if (qh->unlink_cycle == ehci->async_unlink_cycle)
- check_unlinks_later = true;
- else
+ if (qh->unlink_cycle != ehci->async_unlink_cycle)
qh_to_unlink = qh;
}
}
/* If nothing else is being unlinked, unlink the last empty QH */
- if (!ehci->async_iaa && !ehci->async_unlink && qh_to_unlink) {
+ if (list_empty(&ehci->async_unlink) && qh_to_unlink) {
start_unlink_async(ehci, qh_to_unlink);
--count;
}
@@ -1317,7 +1294,7 @@ static void unlink_empty_async(struct ehci_hcd *ehci)
}
/* The root hub is suspended; unlink all the async QHs */
-static void unlink_empty_async_suspended(struct ehci_hcd *ehci)
+static void __maybe_unused unlink_empty_async_suspended(struct ehci_hcd *ehci)
{
struct ehci_qh *qh;
@@ -1326,7 +1303,7 @@ static void unlink_empty_async_suspended(struct ehci_hcd *ehci)
WARN_ON(!list_empty(&qh->qtd_list));
single_unlink_async(ehci, qh);
}
- start_iaa_cycle(ehci, false);
+ start_iaa_cycle(ehci);
}
/* makes sure the async qh will become idle */
@@ -1334,19 +1311,12 @@ static void unlink_empty_async_suspended(struct ehci_hcd *ehci)
static void start_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- /*
- * If the QH isn't linked then there's nothing we can do
- * unless we were called during a giveback, in which case
- * qh_completions() has to deal with it.
- */
- if (qh->qh_state != QH_STATE_LINKED) {
- if (qh->qh_state == QH_STATE_COMPLETING)
- qh->needs_rescan = 1;
+ /* If the QH isn't linked then there's nothing we can do. */
+ if (qh->qh_state != QH_STATE_LINKED)
return;
- }
single_unlink_async(ehci, qh);
- start_iaa_cycle(ehci, false);
+ start_iaa_cycle(ehci);
}
/*-------------------------------------------------------------------------*/
@@ -1360,7 +1330,7 @@ static void scan_async (struct ehci_hcd *ehci)
while (ehci->qh_scan_next) {
qh = ehci->qh_scan_next;
ehci->qh_scan_next = qh->qh_next.qh;
- rescan:
+
/* clean any finished work for this qh */
if (!list_empty(&qh->qtd_list)) {
int temp;
@@ -1373,14 +1343,13 @@ static void scan_async (struct ehci_hcd *ehci)
* in single_unlink_async().
*/
temp = qh_completions(ehci, qh);
- if (qh->needs_rescan) {
+ if (unlikely(temp)) {
start_unlink_async(ehci, qh);
} else if (list_empty(&qh->qtd_list)
&& qh->qh_state == QH_STATE_LINKED) {
qh->unlink_cycle = ehci->async_unlink_cycle;
check_unlinks_later = true;
- } else if (temp != 0)
- goto rescan;
+ }
}
}
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index 20ebf6a..738490e 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -92,20 +92,21 @@ static void s5p_ehci_phy_disable(struct s5p_ehci_hcd *s5p_ehci)
static void s5p_setup_vbus_gpio(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
int err;
int gpio;
- if (!pdev->dev.of_node)
+ if (!dev->of_node)
return;
- gpio = of_get_named_gpio(pdev->dev.of_node,
- "samsung,vbus-gpio", 0);
+ gpio = of_get_named_gpio(dev->of_node, "samsung,vbus-gpio", 0);
if (!gpio_is_valid(gpio))
return;
- err = gpio_request_one(gpio, GPIOF_OUT_INIT_HIGH, "ehci_vbus_gpio");
+ err = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_HIGH,
+ "ehci_vbus_gpio");
if (err)
- dev_err(&pdev->dev, "can't request ehci vbus gpio %d", gpio);
+ dev_err(dev, "can't request ehci vbus gpio %d", gpio);
}
static u64 ehci_s5p_dma_mask = DMA_BIT_MASK(32);
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 010f686..acff5b8 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -539,6 +539,7 @@ static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
}
qh->qh_state = QH_STATE_LINKED;
qh->xacterrs = 0;
+ qh->exception = 0;
/* update per-qh bandwidth for usbfs */
ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->period
@@ -602,15 +603,9 @@ static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- /* If the QH isn't linked then there's nothing we can do
- * unless we were called during a giveback, in which case
- * qh_completions() has to deal with it.
- */
- if (qh->qh_state != QH_STATE_LINKED) {
- if (qh->qh_state == QH_STATE_COMPLETING)
- qh->needs_rescan = 1;
+ /* If the QH isn't linked then there's nothing we can do. */
+ if (qh->qh_state != QH_STATE_LINKED)
return;
- }
qh_unlink_periodic (ehci, qh);
@@ -625,17 +620,13 @@ static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
qh->unlink_cycle = ehci->intr_unlink_cycle;
/* New entries go at the end of the intr_unlink list */
- if (ehci->intr_unlink)
- ehci->intr_unlink_last->unlink_next = qh;
- else
- ehci->intr_unlink = qh;
- ehci->intr_unlink_last = qh;
+ list_add_tail(&qh->unlink_node, &ehci->intr_unlink);
if (ehci->intr_unlinking)
; /* Avoid recursive calls */
else if (ehci->rh_state < EHCI_RH_RUNNING)
ehci_handle_intr_unlinks(ehci);
- else if (ehci->intr_unlink == qh) {
+ else if (ehci->intr_unlink.next == &qh->unlink_node) {
ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true);
++ehci->intr_unlink_cycle;
}
@@ -649,7 +640,8 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
qh->qh_state = QH_STATE_IDLE;
hw->hw_next = EHCI_LIST_END(ehci);
- qh_completions(ehci, qh);
+ if (!list_empty(&qh->qtd_list))
+ qh_completions(ehci, qh);
/* reschedule QH iff another request is queued */
if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) {
@@ -792,7 +784,6 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */
struct ehci_qh_hw *hw = qh->hw;
- qh_refresh(ehci, qh);
hw->hw_next = EHCI_LIST_END(ehci);
frame = qh->start;
@@ -844,8 +835,6 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
} else
ehci_dbg (ehci, "reused qh %p schedule\n", qh);
- /* stuff into the periodic schedule */
- qh_link_periodic(ehci, qh);
done:
return status;
}
@@ -891,6 +880,12 @@ static int intr_submit (
qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
BUG_ON (qh == NULL);
+ /* stuff into the periodic schedule */
+ if (qh->qh_state == QH_STATE_IDLE) {
+ qh_refresh(ehci, qh);
+ qh_link_periodic(ehci, qh);
+ }
+
/* ... update usbfs periodic stats */
ehci_to_hcd(ehci)->self.bandwidth_int_reqs++;
@@ -911,7 +906,7 @@ static void scan_intr(struct ehci_hcd *ehci)
list_for_each_entry_safe(qh, ehci->qh_scan_next, &ehci->intr_qh_list,
intr_node) {
- rescan:
+
/* clean any finished work for this qh */
if (!list_empty(&qh->qtd_list)) {
int temp;
@@ -924,12 +919,9 @@ static void scan_intr(struct ehci_hcd *ehci)
* in qh_unlink_periodic().
*/
temp = qh_completions(ehci, qh);
- if (unlikely(qh->needs_rescan ||
- (list_empty(&qh->qtd_list) &&
- qh->qh_state == QH_STATE_LINKED)))
+ if (unlikely(temp || (list_empty(&qh->qtd_list) &&
+ qh->qh_state == QH_STATE_LINKED)))
start_unlink_intr(ehci, qh);
- else if (temp != 0)
- goto rescan;
}
}
}
diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c
index 3565a30..b44d716 100644
--- a/drivers/usb/host/ehci-sh.c
+++ b/drivers/usb/host/ehci-sh.c
@@ -77,7 +77,6 @@ static const struct hc_driver ehci_sh_hc_driver = {
static int ehci_hcd_sh_probe(struct platform_device *pdev)
{
- const struct hc_driver *driver = &ehci_sh_hc_driver;
struct resource *res;
struct ehci_sh_priv *priv;
struct ehci_sh_platdata *pdata;
@@ -170,7 +169,7 @@ fail_create_hcd:
return ret;
}
-static int __exit ehci_hcd_sh_remove(struct platform_device *pdev)
+static int ehci_hcd_sh_remove(struct platform_device *pdev)
{
struct ehci_sh_priv *priv = platform_get_drvdata(pdev);
struct usb_hcd *hcd = priv->hcd;
@@ -196,7 +195,7 @@ static void ehci_hcd_sh_shutdown(struct platform_device *pdev)
static struct platform_driver ehci_hcd_sh_driver = {
.probe = ehci_hcd_sh_probe,
- .remove = __exit_p(ehci_hcd_sh_remove),
+ .remove = ehci_hcd_sh_remove,
.shutdown = ehci_hcd_sh_shutdown,
.driver = {
.name = "sh_ehci",
diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c
index 466c1bb..210bb67 100644
--- a/drivers/usb/host/ehci-spear.c
+++ b/drivers/usb/host/ehci-spear.c
@@ -78,7 +78,7 @@ static const struct hc_driver ehci_spear_hc_driver = {
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int ehci_spear_drv_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
@@ -94,7 +94,7 @@ static int ehci_spear_drv_resume(struct device *dev)
ehci_resume(hcd, false);
return 0;
}
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend,
ehci_spear_drv_resume);
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c
index c3fa130..11e5b32 100644
--- a/drivers/usb/host/ehci-timer.c
+++ b/drivers/usb/host/ehci-timer.c
@@ -113,8 +113,8 @@ static void ehci_poll_ASS(struct ehci_hcd *ehci)
if (want != actual) {
- /* Poll again later, but give up after about 20 ms */
- if (ehci->ASS_poll_count++ < 20) {
+ /* Poll again later, but give up after about 2-4 ms */
+ if (ehci->ASS_poll_count++ < 2) {
ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true);
return;
}
@@ -159,8 +159,8 @@ static void ehci_poll_PSS(struct ehci_hcd *ehci)
if (want != actual) {
- /* Poll again later, but give up after about 20 ms */
- if (ehci->PSS_poll_count++ < 20) {
+ /* Poll again later, but give up after about 2-4 ms */
+ if (ehci->PSS_poll_count++ < 2) {
ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true);
return;
}
@@ -229,18 +229,19 @@ static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci)
* process all the QHs on the list.
*/
ehci->intr_unlinking = true;
- while (ehci->intr_unlink) {
- struct ehci_qh *qh = ehci->intr_unlink;
+ while (!list_empty(&ehci->intr_unlink)) {
+ struct ehci_qh *qh;
+ qh = list_first_entry(&ehci->intr_unlink, struct ehci_qh,
+ unlink_node);
if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle)
break;
- ehci->intr_unlink = qh->unlink_next;
- qh->unlink_next = NULL;
+ list_del(&qh->unlink_node);
end_unlink_intr(ehci, qh);
}
/* Handle remaining entries later */
- if (ehci->intr_unlink) {
+ if (!list_empty(&ehci->intr_unlink)) {
ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true);
++ehci->intr_unlink_cycle;
}
@@ -295,8 +296,7 @@ static void end_free_itds(struct ehci_hcd *ehci)
/* Handle lost (or very late) IAA interrupts */
static void ehci_iaa_watchdog(struct ehci_hcd *ehci)
{
- if (ehci->rh_state != EHCI_RH_RUNNING)
- return;
+ u32 cmd, status;
/*
* Lost IAA irqs wedge things badly; seen first with a vt8235.
@@ -304,34 +304,32 @@ static void ehci_iaa_watchdog(struct ehci_hcd *ehci)
* (a) SMP races against real IAA firing and retriggering, and
* (b) clean HC shutdown, when IAA watchdog was pending.
*/
- if (1) {
- u32 cmd, status;
-
- /* If we get here, IAA is *REALLY* late. It's barely
- * conceivable that the system is so busy that CMD_IAAD
- * is still legitimately set, so let's be sure it's
- * clear before we read STS_IAA. (The HC should clear
- * CMD_IAAD when it sets STS_IAA.)
- */
- cmd = ehci_readl(ehci, &ehci->regs->command);
-
- /*
- * If IAA is set here it either legitimately triggered
- * after the watchdog timer expired (_way_ late, so we'll
- * still count it as lost) ... or a silicon erratum:
- * - VIA seems to set IAA without triggering the IRQ;
- * - IAAD potentially cleared without setting IAA.
- */
- status = ehci_readl(ehci, &ehci->regs->status);
- if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
- COUNT(ehci->stats.lost_iaa);
- ehci_writel(ehci, STS_IAA, &ehci->regs->status);
- }
+ if (!ehci->iaa_in_progress || ehci->rh_state != EHCI_RH_RUNNING)
+ return;
+
+ /* If we get here, IAA is *REALLY* late. It's barely
+ * conceivable that the system is so busy that CMD_IAAD
+ * is still legitimately set, so let's be sure it's
+ * clear before we read STS_IAA. (The HC should clear
+ * CMD_IAAD when it sets STS_IAA.)
+ */
+ cmd = ehci_readl(ehci, &ehci->regs->command);
- ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n",
- status, cmd);
- end_unlink_async(ehci);
+ /*
+ * If IAA is set here it either legitimately triggered
+ * after the watchdog timer expired (_way_ late, so we'll
+ * still count it as lost) ... or a silicon erratum:
+ * - VIA seems to set IAA without triggering the IRQ;
+ * - IAAD potentially cleared without setting IAA.
+ */
+ status = ehci_readl(ehci, &ehci->regs->status);
+ if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
+ COUNT(ehci->stats.lost_iaa);
+ ehci_writel(ehci, STS_IAA, &ehci->regs->status);
}
+
+ ehci_dbg(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd);
+ end_unlink_async(ehci);
}
diff --git a/drivers/usb/host/ehci-vt8500.c b/drivers/usb/host/ehci-vt8500.c
deleted file mode 100644
index 7ecf709..0000000
--- a/drivers/usb/host/ehci-vt8500.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * drivers/usb/host/ehci-vt8500.c
- *
- * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
- *
- * Based on ehci-au1xxx.c
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/err.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-
-static const struct hc_driver vt8500_ehci_hc_driver = {
- .description = hcd_name,
- .product_desc = "VT8500 EHCI",
- .hcd_priv_size = sizeof(struct ehci_hcd),
-
- /*
- * generic hardware linkage
- */
- .irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
-
- /*
- * basic lifecycle operations
- */
- .reset = ehci_setup,
- .start = ehci_run,
- .stop = ehci_stop,
- .shutdown = ehci_shutdown,
-
- /*
- * managing i/o requests and associated device resources
- */
- .urb_enqueue = ehci_urb_enqueue,
- .urb_dequeue = ehci_urb_dequeue,
- .endpoint_disable = ehci_endpoint_disable,
- .endpoint_reset = ehci_endpoint_reset,
-
- /*
- * scheduling support
- */
- .get_frame_number = ehci_get_frame,
-
- /*
- * root hub support
- */
- .hub_status_data = ehci_hub_status_data,
- .hub_control = ehci_hub_control,
- .bus_suspend = ehci_bus_suspend,
- .bus_resume = ehci_bus_resume,
- .relinquish_port = ehci_relinquish_port,
- .port_handed_over = ehci_port_handed_over,
-
- .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
-};
-
-static u64 vt8500_ehci_dma_mask = DMA_BIT_MASK(32);
-
-static int vt8500_ehci_drv_probe(struct platform_device *pdev)
-{
- struct usb_hcd *hcd;
- struct ehci_hcd *ehci;
- struct resource *res;
- int ret;
-
- if (usb_disabled())
- return -ENODEV;
-
- /*
- * Right now device-tree probed devices don't get dma_mask set.
- * Since shared usb code relies on it, set it here for now.
- * Once we have dma capability bindings this can go away.
- */
- if (!pdev->dev.dma_mask)
- pdev->dev.dma_mask = &vt8500_ehci_dma_mask;
-
- if (pdev->resource[1].flags != IORESOURCE_IRQ) {
- pr_debug("resource[1] is not IORESOURCE_IRQ");
- return -ENOMEM;
- }
- hcd = usb_create_hcd(&vt8500_ehci_hc_driver, &pdev->dev, "VT8500");
- if (!hcd)
- return -ENOMEM;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
-
- hcd->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(hcd->regs)) {
- ret = PTR_ERR(hcd->regs);
- goto err1;
- }
-
- ehci = hcd_to_ehci(hcd);
- ehci->caps = hcd->regs;
-
- ret = usb_add_hcd(hcd, pdev->resource[1].start,
- IRQF_SHARED);
- if (ret == 0) {
- platform_set_drvdata(pdev, hcd);
- return ret;
- }
-
-err1:
- usb_put_hcd(hcd);
- return ret;
-}
-
-static int vt8500_ehci_drv_remove(struct platform_device *pdev)
-{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
- usb_remove_hcd(hcd);
- usb_put_hcd(hcd);
- platform_set_drvdata(pdev, NULL);
-
- return 0;
-}
-
-static const struct of_device_id vt8500_ehci_ids[] = {
- { .compatible = "via,vt8500-ehci", },
- { .compatible = "wm,prizm-ehci", },
- {}
-};
-
-static struct platform_driver vt8500_ehci_driver = {
- .probe = vt8500_ehci_drv_probe,
- .remove = vt8500_ehci_drv_remove,
- .shutdown = usb_hcd_platform_shutdown,
- .driver = {
- .name = "vt8500-ehci",
- .owner = THIS_MODULE,
- .of_match_table = of_match_ptr(vt8500_ehci_ids),
- }
-};
-
-MODULE_ALIAS("platform:vt8500-ehci");
-MODULE_DEVICE_TABLE(of, vt8500_ehci_ids);
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 36c3a82..e666999 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -121,6 +121,7 @@ struct ehci_hcd { /* one per controller */
bool scanning:1;
bool need_rescan:1;
bool intr_unlinking:1;
+ bool iaa_in_progress:1;
bool async_unlinking:1;
bool shutdown:1;
struct ehci_qh *qh_scan_next;
@@ -128,9 +129,8 @@ struct ehci_hcd { /* one per controller */
/* async schedule support */
struct ehci_qh *async;
struct ehci_qh *dummy; /* For AMD quirk use */
- struct ehci_qh *async_unlink;
- struct ehci_qh *async_unlink_last;
- struct ehci_qh *async_iaa;
+ struct list_head async_unlink;
+ struct list_head async_idle;
unsigned async_unlink_cycle;
unsigned async_count; /* async activity count */
@@ -143,8 +143,7 @@ struct ehci_hcd { /* one per controller */
unsigned i_thresh; /* uframes HC might cache */
union ehci_shadow *pshadow; /* mirror hw periodic table */
- struct ehci_qh *intr_unlink;
- struct ehci_qh *intr_unlink_last;
+ struct list_head intr_unlink;
unsigned intr_unlink_cycle;
unsigned now_frame; /* frame from HC hardware */
unsigned last_iso_frame; /* last frame scanned for iso */
@@ -380,11 +379,10 @@ struct ehci_qh {
struct list_head qtd_list; /* sw qtd list */
struct list_head intr_node; /* list of intr QHs */
struct ehci_qtd *dummy;
- struct ehci_qh *unlink_next; /* next on unlink list */
+ struct list_head unlink_node;
unsigned unlink_cycle;
- u8 needs_rescan; /* Dequeue during giveback */
u8 qh_state;
#define QH_STATE_LINKED 1 /* HC sees this */
#define QH_STATE_UNLINK 2 /* HC may still see this */
@@ -407,6 +405,9 @@ struct ehci_qh {
struct usb_device *dev; /* access to TT */
unsigned is_out:1; /* bulk or intr OUT */
unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
+ unsigned dequeue_during_giveback:1;
+ unsigned exception:1; /* got a fault, or an unlink
+ was requested */
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index db09dae..60ff422 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -580,14 +580,8 @@ static int ohci_start_port_reset (struct usb_hcd *hcd, unsigned port)
/* See usb 7.1.7.5: root hubs must issue at least 50 msec reset signaling,
* not necessarily continuous ... to guard against resume signaling.
- * The short timeout is safe for non-root hubs, and is backward-compatible
- * with earlier Linux hosts.
*/
-#ifdef CONFIG_USB_SUSPEND
#define PORT_RESET_MSEC 50
-#else
-#define PORT_RESET_MSEC 10
-#endif
/* this timer value might be vendor-specific ... */
#define PORT_RESET_HW_MSEC 10
diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c
index eb35d96..ddfc314 100644
--- a/drivers/usb/host/ohci-omap3.c
+++ b/drivers/usb/host/ohci-omap3.c
@@ -31,6 +31,8 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/dma-mapping.h>
/*-------------------------------------------------------------------------*/
@@ -112,6 +114,8 @@ static const struct hc_driver ohci_omap3_hc_driver = {
/*-------------------------------------------------------------------------*/
+static u64 omap_ohci_dma_mask = DMA_BIT_MASK(32);
+
/*
* configure so an HC device and id are always provided
* always called with process context; sleeping is OK
@@ -141,14 +145,13 @@ static int ohci_hcd_omap3_probe(struct platform_device *pdev)
return -ENODEV;
}
- irq = platform_get_irq_byname(pdev, "ohci-irq");
+ irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "OHCI irq failed\n");
return -ENODEV;
}
- res = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "ohci");
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "UHH OHCI get resource failed\n");
return -ENOMEM;
@@ -160,6 +163,13 @@ static int ohci_hcd_omap3_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ /*
+ * Right now device-tree probed devices don't get dma_mask set.
+ * Since shared usb code relies on it, set it here for now.
+ * Once we have dma capability bindings this can go away.
+ */
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &omap_ohci_dma_mask;
hcd = usb_create_hcd(&ohci_omap3_hc_driver, dev,
dev_name(dev));
@@ -229,12 +239,20 @@ static void ohci_hcd_omap3_shutdown(struct platform_device *pdev)
hcd->driver->shutdown(hcd);
}
+static const struct of_device_id omap_ohci_dt_ids[] = {
+ { .compatible = "ti,ohci-omap3" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, omap_ohci_dt_ids);
+
static struct platform_driver ohci_hcd_omap3_driver = {
.probe = ohci_hcd_omap3_probe,
.remove = ohci_hcd_omap3_remove,
.shutdown = ohci_hcd_omap3_shutdown,
.driver = {
.name = "ohci-omap3",
+ .of_match_table = of_match_ptr(omap_ohci_dt_ids),
},
};
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index d62f040..15ed7e8 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1755,7 +1755,7 @@ sl811h_probe(struct platform_device *dev)
/* for this device there's no useful distinction between the controller
* and its root hub, except that the root hub only gets direct PM calls
- * when CONFIG_USB_SUSPEND is enabled.
+ * when CONFIG_PM_RUNTIME is enabled.
*/
static int
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 5efdffe..5c124bf 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -3141,10 +3141,11 @@ static int u132_probe(struct platform_device *pdev)
#ifdef CONFIG_PM
-/* for this device there's no useful distinction between the controller
-* and its root hub, except that the root hub only gets direct PM calls
-* when CONFIG_USB_SUSPEND is enabled.
-*/
+/*
+ * for this device there's no useful distinction between the controller
+ * and its root hub, except that the root hub only gets direct PM calls
+ * when CONFIG_PM_RUNTIME is enabled.
+ */
static int u132_suspend(struct platform_device *pdev, pm_message_t state)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 6891442..187a3ec 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1075,7 +1075,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
set_bit(port_index, &bus_state->bus_suspended);
}
/* USB core sets remote wake mask for USB 3.0 hubs,
- * including the USB 3.0 roothub, but only if CONFIG_USB_SUSPEND
+ * including the USB 3.0 roothub, but only if CONFIG_PM_RUNTIME
* is enabled, so also enable remote wake here.
*/
if (hcd->self.root_hub->do_remote_wakeup) {
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 53b8f89..5156b72 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -3801,7 +3801,7 @@ int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1)
return raw_port;
}
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
/* BESL to HIRD Encoding array for USB2 LPM */
static int xhci_besl_encoding[16] = {125, 150, 200, 300, 400, 500, 1000, 2000,
@@ -4051,7 +4051,7 @@ int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
return 0;
}
-#endif /* CONFIG_USB_SUSPEND */
+#endif /* CONFIG_PM_RUNTIME */
/*---------------------- USB 3.0 Link PM functions ------------------------*/