summaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-07-26 10:23:47 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2012-07-26 10:23:47 -0700
commit9fc377799bc9bfd8d5cb35d0d1ea2e2458cbdbb3 (patch)
treefe93603b4e33dd50ff5f95ff769a0748b230cdf9 /drivers/usb/host
parent5e23ae49960d05f578a73ecd19749c45af682c2b (diff)
parente387ef5c47ddeaeaa3cbdc54424cdb7a28dae2c0 (diff)
downloadop-kernel-dev-9fc377799bc9bfd8d5cb35d0d1ea2e2458cbdbb3.zip
op-kernel-dev-9fc377799bc9bfd8d5cb35d0d1ea2e2458cbdbb3.tar.gz
Merge tag 'usb-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB patches from Greg Kroah-Hartman: "Here's the big USB patch set for the 3.6-rc1 merge window. Lots of little changes in here, primarily for gadget controllers and drivers. There's some scsi changes that I think also went in through the scsi tree, but they merge just fine. All of these patches have been in the linux-next tree for a while now. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>" Fix up trivial conflicts in include/scsi/scsi_device.h (same libata conflict that Jeff had already encountered) * tag 'usb-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (207 commits) usb: Add USB_QUIRK_RESET_RESUME for all Logitech UVC webcams usb: Add quirk detection based on interface information usb: s3c-hsotg: Add header file protection macros in s3c-hsotg.h USB: ehci-s5p: Add vbus setup function to the s5p ehci glue layer USB: add USB_VENDOR_AND_INTERFACE_INFO() macro USB: notify phy when root hub port connect change USB: remove 8 bytes of padding from usb_host_interface on 64 bit builds USB: option: add ZTE MF821D USB: sierra: QMI mode MC7710 moved to qcserial USB: qcserial: adding Sierra Wireless devices USB: qcserial: support generic Qualcomm serial ports USB: qcserial: make probe more flexible USB: qcserial: centralize probe exit path USB: qcserial: consolidate usb_set_interface calls USB: ehci-s5p: Add support for device tree USB: ohci-exynos: Add support for device tree USB: ehci-omap: fix compile failure(v1) usb: host: tegra: pass correct pointer in ehci_setup() USB: ehci-fsl: Update ifdef check to work on 64-bit ppc USB: serial: keyspan: Removed unrequired parentheses. ...
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/Kconfig4
-rw-r--r--drivers/usb/host/ehci-atmel.c19
-rw-r--r--drivers/usb/host/ehci-au1xxx.c87
-rw-r--r--drivers/usb/host/ehci-cns3xxx.c6
-rw-r--r--drivers/usb/host/ehci-dbg.c24
-rw-r--r--drivers/usb/host/ehci-fsl.c42
-rw-r--r--drivers/usb/host/ehci-grlib.c15
-rw-r--r--drivers/usb/host/ehci-hcd.c512
-rw-r--r--drivers/usb/host/ehci-hub.c129
-rw-r--r--drivers/usb/host/ehci-ixp4xx.c6
-rw-r--r--drivers/usb/host/ehci-mem.c25
-rw-r--r--drivers/usb/host/ehci-msm.c27
-rw-r--r--drivers/usb/host/ehci-mv.c36
-rw-r--r--drivers/usb/host/ehci-mxc.c17
-rw-r--r--drivers/usb/host/ehci-octeon.c8
-rw-r--r--drivers/usb/host/ehci-omap.c114
-rw-r--r--drivers/usb/host/ehci-orion.c17
-rw-r--r--drivers/usb/host/ehci-pci.c238
-rw-r--r--drivers/usb/host/ehci-platform.c7
-rw-r--r--drivers/usb/host/ehci-pmcmsp.c17
-rw-r--r--drivers/usb/host/ehci-ppc-of.c25
-rw-r--r--drivers/usb/host/ehci-ps3.c18
-rw-r--r--drivers/usb/host/ehci-q.c311
-rw-r--r--drivers/usb/host/ehci-s5p.c135
-rw-r--r--drivers/usb/host/ehci-sched.c552
-rw-r--r--drivers/usb/host/ehci-sead3.c74
-rw-r--r--drivers/usb/host/ehci-sh.c16
-rw-r--r--drivers/usb/host/ehci-spear.c71
-rw-r--r--drivers/usb/host/ehci-tegra.c36
-rw-r--r--drivers/usb/host/ehci-timer.c401
-rw-r--r--drivers/usb/host/ehci-vt8500.c14
-rw-r--r--drivers/usb/host/ehci-w90x900.c9
-rw-r--r--drivers/usb/host/ehci-xilinx-of.c31
-rw-r--r--drivers/usb/host/ehci-xls.c21
-rw-r--r--drivers/usb/host/ehci.h138
-rw-r--r--drivers/usb/host/fhci-dbg.c12
-rw-r--r--drivers/usb/host/fhci-hcd.c32
-rw-r--r--drivers/usb/host/fhci-hub.c16
-rw-r--r--drivers/usb/host/fhci-sched.c30
-rw-r--r--drivers/usb/host/fhci-tds.c14
-rw-r--r--drivers/usb/host/fhci.h22
-rw-r--r--drivers/usb/host/imx21-hcd.c6
-rw-r--r--drivers/usb/host/ohci-exynos.c46
-rw-r--r--drivers/usb/host/ohci-nxp.c88
-rw-r--r--drivers/usb/host/ohci-omap.c28
-rw-r--r--drivers/usb/host/ohci.h5
-rw-r--r--drivers/usb/host/xhci-hub.c6
-rw-r--r--drivers/usb/host/xhci.c2
48 files changed, 1604 insertions, 1905 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index dcfaaa9..075d2ec 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -652,7 +652,7 @@ config USB_HCD_BCMA
select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
help
- Enbale support for the EHCI and OCHI host controller on an bcma bus.
+ Enable support for the EHCI and OCHI host controller on an bcma bus.
It converts the bcma driver into two platform device drivers
for ehci and ohci.
@@ -664,7 +664,7 @@ config USB_HCD_SSB
select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
help
- Enbale support for the EHCI and OCHI host controller on an bcma bus.
+ Enable support for the EHCI and OCHI host controller on an bcma bus.
It converts the bcma driver into two platform device drivers
for ehci and ohci.
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index cf14c95..a47e2cf 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -53,30 +53,15 @@ static void atmel_stop_ehci(struct platform_device *pdev)
static int ehci_atmel_setup(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- int retval = 0;
+ int retval;
/* registers start at offset 0x0 */
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs +
- HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
- dbg_hcs_params(ehci, "reset");
- dbg_hcc_params(ehci, "reset");
-
- /* cache this readonly data; minimize chip reads */
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-
- retval = ehci_halt(ehci);
- if (retval)
- return retval;
- /* data structure init */
- retval = ehci_init(hcd);
+ retval = ehci_setup(hcd);
if (retval)
return retval;
- ehci->sbrn = 0x20;
-
- ehci_reset(ehci);
ehci_port_power(ehci, 0);
return retval;
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index bf7441a..cba10d6 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -20,10 +20,12 @@ extern int usb_disabled(void);
static int au1xxx_ehci_setup(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- int ret = ehci_init(hcd);
+ int ret;
+
+ ehci->caps = hcd->regs;
+ ret = ehci_setup(hcd);
ehci->need_io_watchdog = 0;
- ehci_reset(ehci);
return ret;
}
@@ -78,7 +80,6 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
- struct ehci_hcd *ehci;
struct resource *res;
int ret;
@@ -116,13 +117,6 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
goto err3;
}
- ehci = hcd_to_ehci(hcd);
- ehci->caps = hcd->regs;
- ehci->regs = hcd->regs +
- HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
- /* cache this readonly data; minimize chip reads */
- ehci->hcs_params = readl(&ehci->caps->hcs_params);
-
ret = usb_add_hcd(hcd, pdev->resource[1].start,
IRQF_SHARED);
if (ret == 0) {
@@ -158,28 +152,10 @@ static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- unsigned long flags;
- int rc = 0;
-
- if (time_before(jiffies, ehci->next_statechange))
- msleep(10);
-
- /* Root hub was already suspended. Disable irq emission and
- * mark HW unaccessible. The PM and USB cores make sure that
- * the root hub is either suspended or stopped.
- */
- ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
- spin_lock_irqsave(&ehci->lock, flags);
- ehci_writel(ehci, 0, &ehci->regs->intr_enable);
- (void)ehci_readl(ehci, &ehci->regs->intr_enable);
-
- clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- spin_unlock_irqrestore(&ehci->lock, flags);
-
- // could save FLADJ in case of Vaux power loss
- // ... we'd only use it to handle clock skew
+ bool do_wakeup = device_may_wakeup(dev);
+ int rc;
+ rc = ehci_suspend(hcd, do_wakeup);
alchemy_usb_control(ALCHEMY_USB_EHCI0, 0);
return rc;
@@ -188,56 +164,9 @@ static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
alchemy_usb_control(ALCHEMY_USB_EHCI0, 1);
-
- // maybe restore FLADJ
-
- if (time_before(jiffies, ehci->next_statechange))
- msleep(100);
-
- /* Mark hardware accessible again as we are out of D3 state by now */
- set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
- /* If CF is still set, we maintained PCI Vaux power.
- * Just undo the effect of ehci_pci_suspend().
- */
- if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
- int mask = INTR_MASK;
-
- ehci_prepare_ports_for_controller_resume(ehci);
- if (!hcd->self.root_hub->do_remote_wakeup)
- mask &= ~STS_PCD;
- ehci_writel(ehci, mask, &ehci->regs->intr_enable);
- ehci_readl(ehci, &ehci->regs->intr_enable);
- return 0;
- }
-
- ehci_dbg(ehci, "lost power, restarting\n");
- usb_root_hub_lost_power(hcd->self.root_hub);
-
- /* Else reset, to cope with power loss or flush-to-storage
- * style "resume" having let BIOS kick in during reboot.
- */
- (void) ehci_halt(ehci);
- (void) ehci_reset(ehci);
-
- /* emptying the schedule aborts any urbs */
- spin_lock_irq(&ehci->lock);
- if (ehci->reclaim)
- end_unlink_async(ehci);
- ehci_work(ehci);
- spin_unlock_irq(&ehci->lock);
-
- ehci_writel(ehci, ehci->command, &ehci->regs->command);
- ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
- ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
-
- /* here we "know" root ports should always stay powered */
- ehci_port_power(ehci, 1);
-
- ehci->rh_state = EHCI_RH_SUSPENDED;
+ ehci_resume(hcd, false);
return 0;
}
diff --git a/drivers/usb/host/ehci-cns3xxx.c b/drivers/usb/host/ehci-cns3xxx.c
index 6536abd..caaa3e5 100644
--- a/drivers/usb/host/ehci-cns3xxx.c
+++ b/drivers/usb/host/ehci-cns3xxx.c
@@ -33,14 +33,10 @@ static int cns3xxx_ehci_init(struct usb_hcd *hcd)
}
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs
- + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
hcd->has_tt = 0;
- ehci_reset(ehci);
- retval = ehci_init(hcd);
+ retval = ehci_setup(hcd);
if (retval)
return retval;
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 7561966..f0c00de 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -404,9 +404,9 @@ struct debug_buffer {
#define speed_char(info1) ({ char tmp; \
switch (info1 & (3 << 12)) { \
- case 0 << 12: tmp = 'f'; break; \
- case 1 << 12: tmp = 'l'; break; \
- case 2 << 12: tmp = 'h'; break; \
+ case QH_FULL_SPEED: tmp = 'f'; break; \
+ case QH_LOW_SPEED: tmp = 'l'; break; \
+ case QH_HIGH_SPEED: tmp = 'h'; break; \
default: tmp = '?'; break; \
}; tmp; })
@@ -538,12 +538,13 @@ 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->reclaim && size > 0) {
- temp = scnprintf (next, size, "\nreclaim =\n");
+ if (ehci->async_unlink && size > 0) {
+ temp = scnprintf(next, size, "\nunlink =\n");
size -= temp;
next += temp;
- for (qh = ehci->reclaim; size > 0 && qh; qh = qh->reclaim)
+ for (qh = ehci->async_unlink; size > 0 && qh;
+ qh = qh->unlink_next)
qh_lines (ehci, qh, &next, &size);
}
spin_unlock_irqrestore (&ehci->lock, flags);
@@ -705,6 +706,8 @@ static const char *rh_state_string(struct ehci_hcd *ehci)
return "suspended";
case EHCI_RH_RUNNING:
return "running";
+ case EHCI_RH_STOPPING:
+ return "stopping";
}
return "?";
}
@@ -841,16 +844,17 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
}
}
- if (ehci->reclaim) {
- temp = scnprintf(next, size, "reclaim qh %p\n", ehci->reclaim);
+ if (ehci->async_unlink) {
+ temp = scnprintf(next, size, "async unlink qh %p\n",
+ ehci->async_unlink);
size -= temp;
next += temp;
}
#ifdef EHCI_STATS
temp = scnprintf (next, size,
- "irq normal %ld err %ld reclaim %ld (lost %ld)\n",
- ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,
+ "irq normal %ld err %ld iaa %ld (lost %ld)\n",
+ ehci->stats.normal, ehci->stats.error, ehci->stats.iaa,
ehci->stats.lost_iaa);
size -= temp;
next += temp;
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 4336257..b7451b2 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -27,6 +27,7 @@
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/pm.h>
+#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/fsl_devices.h>
@@ -142,19 +143,19 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
if (pdata->operating_mode == FSL_USB2_DR_OTG) {
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- ehci->transceiver = usb_get_transceiver();
- dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, transceiver=0x%p\n",
- hcd, ehci, ehci->transceiver);
+ hcd->phy = usb_get_phy(USB_PHY_TYPE_USB2);
+ dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, phy=0x%p\n",
+ hcd, ehci, hcd->phy);
- if (ehci->transceiver) {
- retval = otg_set_host(ehci->transceiver->otg,
+ if (!IS_ERR_OR_NULL(hcd->phy)) {
+ retval = otg_set_host(hcd->phy->otg,
&ehci_to_hcd(ehci)->self);
if (retval) {
- usb_put_transceiver(ehci->transceiver);
+ usb_put_phy(hcd->phy);
goto err4;
}
} else {
- dev_err(&pdev->dev, "can't find transceiver\n");
+ dev_err(&pdev->dev, "can't find phy\n");
retval = -ENODEV;
goto err4;
}
@@ -190,11 +191,10 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
struct platform_device *pdev)
{
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- if (ehci->transceiver) {
- otg_set_host(ehci->transceiver->otg, NULL);
- usb_put_transceiver(ehci->transceiver);
+ if (!IS_ERR_OR_NULL(hcd->phy)) {
+ otg_set_host(hcd->phy->otg, NULL);
+ usb_put_phy(hcd->phy);
}
usb_remove_hcd(hcd);
@@ -313,7 +313,7 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
}
if (pdata->have_sysif_regs) {
-#ifdef CONFIG_PPC_85xx
+#ifdef CONFIG_FSL_SOC_BOOKE
out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008);
out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080);
#else
@@ -348,29 +348,13 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
/* EHCI registers start at offset 0x100 */
ehci->caps = hcd->regs + 0x100;
- ehci->regs = hcd->regs + 0x100 +
- HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
- dbg_hcs_params(ehci, "reset");
- dbg_hcc_params(ehci, "reset");
-
- /* cache this readonly data; minimize chip reads */
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
hcd->has_tt = 1;
- retval = ehci_halt(ehci);
- if (retval)
- return retval;
-
- /* data structure init */
- retval = ehci_init(hcd);
+ retval = ehci_setup(hcd);
if (retval)
return retval;
- ehci->sbrn = 0x20;
-
- ehci_reset(ehci);
-
if (of_device_is_compatible(dev->parent->of_node,
"fsl,mpc5121-usb2-dr")) {
/*
diff --git a/drivers/usb/host/ehci-grlib.c b/drivers/usb/host/ehci-grlib.c
index fdfd8c5..22ca45c 100644
--- a/drivers/usb/host/ehci-grlib.c
+++ b/drivers/usb/host/ehci-grlib.c
@@ -40,18 +40,13 @@ static int ehci_grlib_setup(struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int retval;
- retval = ehci_halt(ehci);
+ retval = ehci_setup(hcd);
if (retval)
return retval;
- retval = ehci_init(hcd);
- if (retval)
- return retval;
-
- ehci->sbrn = 0x20;
ehci_port_power(ehci, 1);
- return ehci_reset(ehci);
+ return retval;
}
@@ -164,12 +159,6 @@ static int __devinit ehci_hcd_grlib_probe(struct platform_device *op)
ehci->big_endian_capbase = 1;
}
- ehci->regs = hcd->regs +
- HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-
- /* cache this readonly data; minimize chip reads */
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-
rv = usb_add_hcd(hcd, irq, 0);
if (rv)
goto err_ehci;
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 1d9401e..b05c686 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -30,8 +30,7 @@
#include <linux/vmalloc.h>
#include <linux/errno.h>
#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/ktime.h>
+#include <linux/hrtimer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/usb.h>
@@ -94,12 +93,6 @@ static const char hcd_name [] = "ehci_hcd";
*/
#define EHCI_TUNE_FLS 1 /* (medium) 512-frame schedule */
-#define EHCI_IAA_MSECS 10 /* arbitrary */
-#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
-#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
-#define EHCI_SHRINK_JIFFIES (DIV_ROUND_UP(HZ, 200) + 1)
- /* 5-ms async qh unlink delay */
-
/* Initial IRQ latency: faster than hw default */
static int log2_irq_thresh = 0; // 0 to 6
module_param (log2_irq_thresh, int, S_IRUGO);
@@ -130,41 +123,6 @@ MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us");
/*-------------------------------------------------------------------------*/
-static void
-timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action)
-{
- /* Don't override timeouts which shrink or (later) disable
- * the async ring; just the I/O watchdog. Note that if a
- * SHRINK were pending, OFF would never be requested.
- */
- if (timer_pending(&ehci->watchdog)
- && ((BIT(TIMER_ASYNC_SHRINK) | BIT(TIMER_ASYNC_OFF))
- & ehci->actions))
- return;
-
- if (!test_and_set_bit(action, &ehci->actions)) {
- unsigned long t;
-
- switch (action) {
- case TIMER_IO_WATCHDOG:
- if (!ehci->need_io_watchdog)
- return;
- t = EHCI_IO_JIFFIES;
- break;
- case TIMER_ASYNC_OFF:
- t = EHCI_ASYNC_JIFFIES;
- break;
- /* case TIMER_ASYNC_SHRINK: */
- default:
- t = EHCI_SHRINK_JIFFIES;
- break;
- }
- mod_timer(&ehci->watchdog, t + jiffies);
- }
-}
-
-/*-------------------------------------------------------------------------*/
-
/*
* handshake - spin reading hc until handshake completes or fails
* @ptr: address of hc register to be read
@@ -203,29 +161,30 @@ static int handshake (struct ehci_hcd *ehci, void __iomem *ptr,
/* check TDI/ARC silicon is in host mode */
static int tdi_in_host_mode (struct ehci_hcd *ehci)
{
- u32 __iomem *reg_ptr;
u32 tmp;
- reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + USBMODE);
- tmp = ehci_readl(ehci, reg_ptr);
+ tmp = ehci_readl(ehci, &ehci->regs->usbmode);
return (tmp & 3) == USBMODE_CM_HC;
}
-/* force HC to halt state from unknown (EHCI spec section 2.3) */
+/*
+ * Force HC to halt state from unknown (EHCI spec section 2.3).
+ * Must be called with interrupts enabled and the lock not held.
+ */
static int ehci_halt (struct ehci_hcd *ehci)
{
- u32 temp = ehci_readl(ehci, &ehci->regs->status);
+ u32 temp;
+
+ spin_lock_irq(&ehci->lock);
/* disable any irqs left enabled by previous code */
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
- if (ehci_is_TDI(ehci) && tdi_in_host_mode(ehci) == 0) {
+ if (ehci_is_TDI(ehci) && !tdi_in_host_mode(ehci)) {
+ spin_unlock_irq(&ehci->lock);
return 0;
}
- if ((temp & STS_HALT) != 0)
- return 0;
-
/*
* This routine gets called during probe before ehci->command
* has been initialized, so we can't rely on its value.
@@ -234,80 +193,20 @@ static int ehci_halt (struct ehci_hcd *ehci)
temp = ehci_readl(ehci, &ehci->regs->command);
temp &= ~(CMD_RUN | CMD_IAAD);
ehci_writel(ehci, temp, &ehci->regs->command);
- return handshake (ehci, &ehci->regs->status,
- STS_HALT, STS_HALT, 16 * 125);
-}
-
-#if defined(CONFIG_USB_SUSPEND) && defined(CONFIG_PPC_PS3)
-
-/*
- * The EHCI controller of the Cell Super Companion Chip used in the
- * PS3 will stop the root hub after all root hub ports are suspended.
- * When in this condition handshake will return -ETIMEDOUT. The
- * STS_HLT bit will not be set, so inspection of the frame index is
- * used here to test for the condition. If the condition is found
- * return success to allow the USB suspend to complete.
- */
-
-static int handshake_for_broken_root_hub(struct ehci_hcd *ehci,
- void __iomem *ptr, u32 mask, u32 done,
- int usec)
-{
- unsigned int old_index;
- int error;
-
- if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
- return -ETIMEDOUT;
-
- old_index = ehci_read_frame_index(ehci);
-
- error = handshake(ehci, ptr, mask, done, usec);
-
- if (error == -ETIMEDOUT && ehci_read_frame_index(ehci) == old_index)
- return 0;
-
- return error;
-}
-
-#else
-
-static int handshake_for_broken_root_hub(struct ehci_hcd *ehci,
- void __iomem *ptr, u32 mask, u32 done,
- int usec)
-{
- return -ETIMEDOUT;
-}
-
-#endif
-static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
- u32 mask, u32 done, int usec)
-{
- int error;
-
- error = handshake(ehci, ptr, mask, done, usec);
- if (error == -ETIMEDOUT)
- error = handshake_for_broken_root_hub(ehci, ptr, mask, done,
- usec);
-
- if (error) {
- ehci_halt(ehci);
- ehci->rh_state = EHCI_RH_HALTED;
- ehci_err(ehci, "force halt; handshake %p %08x %08x -> %d\n",
- ptr, mask, done, error);
- }
+ spin_unlock_irq(&ehci->lock);
+ synchronize_irq(ehci_to_hcd(ehci)->irq);
- return error;
+ return handshake(ehci, &ehci->regs->status,
+ STS_HALT, STS_HALT, 16 * 125);
}
/* put TDI/ARC silicon into EHCI mode */
static void tdi_reset (struct ehci_hcd *ehci)
{
- u32 __iomem *reg_ptr;
u32 tmp;
- reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + USBMODE);
- tmp = ehci_readl(ehci, reg_ptr);
+ tmp = ehci_readl(ehci, &ehci->regs->usbmode);
tmp |= USBMODE_CM_HC;
/* The default byte access to MMR space is LE after
* controller reset. Set the required endian mode
@@ -315,10 +214,13 @@ static void tdi_reset (struct ehci_hcd *ehci)
*/
if (ehci_big_endian_mmio(ehci))
tmp |= USBMODE_BE;
- ehci_writel(ehci, tmp, reg_ptr);
+ ehci_writel(ehci, tmp, &ehci->regs->usbmode);
}
-/* reset a non-running (STS_HALT == 1) controller */
+/*
+ * Reset a non-running (STS_HALT == 1) controller.
+ * Must be called with interrupts enabled and the lock not held.
+ */
static int ehci_reset (struct ehci_hcd *ehci)
{
int retval;
@@ -339,9 +241,8 @@ static int ehci_reset (struct ehci_hcd *ehci)
if (ehci->has_hostpc) {
ehci_writel(ehci, USBMODE_EX_HC | USBMODE_EX_VBPS,
- (u32 __iomem *)(((u8 *)ehci->regs) + USBMODE_EX));
- ehci_writel(ehci, TXFIFO_DEFAULT,
- (u32 __iomem *)(((u8 *)ehci->regs) + TXFILLTUNING));
+ &ehci->regs->usbmode_ex);
+ ehci_writel(ehci, TXFIFO_DEFAULT, &ehci->regs->txfill_tuning);
}
if (retval)
return retval;
@@ -357,36 +258,40 @@ static int ehci_reset (struct ehci_hcd *ehci)
return retval;
}
-/* idle the controller (from running) */
+/*
+ * Idle the controller (turn off the schedules).
+ * Must be called with interrupts enabled and the lock not held.
+ */
static void ehci_quiesce (struct ehci_hcd *ehci)
{
u32 temp;
-#ifdef DEBUG
if (ehci->rh_state != EHCI_RH_RUNNING)
- BUG ();
-#endif
+ return;
/* wait for any schedule enables/disables to take effect */
temp = (ehci->command << 10) & (STS_ASS | STS_PSS);
- if (handshake_on_error_set_halt(ehci, &ehci->regs->status,
- STS_ASS | STS_PSS, temp, 16 * 125))
- return;
+ handshake(ehci, &ehci->regs->status, STS_ASS | STS_PSS, temp, 16 * 125);
/* then disable anything that's still active */
+ spin_lock_irq(&ehci->lock);
ehci->command &= ~(CMD_ASE | CMD_PSE);
ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ spin_unlock_irq(&ehci->lock);
/* hardware can take 16 microframes to turn off ... */
- handshake_on_error_set_halt(ehci, &ehci->regs->status,
- STS_ASS | STS_PSS, 0, 16 * 125);
+ handshake(ehci, &ehci->regs->status, STS_ASS | STS_PSS, 0, 16 * 125);
}
/*-------------------------------------------------------------------------*/
static void end_unlink_async(struct ehci_hcd *ehci);
+static void unlink_empty_async(struct ehci_hcd *ehci);
static void ehci_work(struct ehci_hcd *ehci);
+static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh);
+static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh);
+#include "ehci-timer.c"
#include "ehci-hub.c"
#include "ehci-lpm.c"
#include "ehci-mem.c"
@@ -396,68 +301,6 @@ static void ehci_work(struct ehci_hcd *ehci);
/*-------------------------------------------------------------------------*/
-static void ehci_iaa_watchdog(unsigned long param)
-{
- struct ehci_hcd *ehci = (struct ehci_hcd *) param;
- unsigned long flags;
-
- spin_lock_irqsave (&ehci->lock, flags);
-
- /* Lost IAA irqs wedge things badly; seen first with a vt8235.
- * So we need this watchdog, but must protect it against both
- * (a) SMP races against real IAA firing and retriggering, and
- * (b) clean HC shutdown, when IAA watchdog was pending.
- */
- if (ehci->reclaim
- && !timer_pending(&ehci->iaa_watchdog)
- && ehci->rh_state == EHCI_RH_RUNNING) {
- 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
- * before we cleared IAAD above (but _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_vdbg(ehci, "IAA watchdog: status %x cmd %x\n",
- status, cmd);
- end_unlink_async(ehci);
- }
-
- spin_unlock_irqrestore(&ehci->lock, flags);
-}
-
-static void ehci_watchdog(unsigned long param)
-{
- struct ehci_hcd *ehci = (struct ehci_hcd *) param;
- unsigned long flags;
-
- spin_lock_irqsave(&ehci->lock, flags);
-
- /* stop async processing after it's idled a bit */
- if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
- start_unlink_async (ehci, ehci->async);
-
- /* ehci could run by timer, without IRQs ... */
- ehci_work (ehci);
-
- spin_unlock_irqrestore (&ehci->lock, flags);
-}
-
/* On some systems, leaving remote wakeup enabled prevents system shutdown.
* The firmware seems to think that powering off is a wakeup event!
* This routine turns off remote wakeup and everything else, on all ports.
@@ -473,11 +316,14 @@ static void ehci_turn_off_all_ports(struct ehci_hcd *ehci)
/*
* Halt HC, turn off all ports, and let the BIOS use the companion controllers.
- * Should be called with ehci->lock held.
+ * Must be called with interrupts enabled and the lock not held.
*/
static void ehci_silence_controller(struct ehci_hcd *ehci)
{
ehci_halt(ehci);
+
+ spin_lock_irq(&ehci->lock);
+ ehci->rh_state = EHCI_RH_HALTED;
ehci_turn_off_all_ports(ehci);
/* make BIOS/etc use companion controller during reboot */
@@ -485,6 +331,7 @@ static void ehci_silence_controller(struct ehci_hcd *ehci)
/* unblock posted writes */
ehci_readl(ehci, &ehci->regs->configured_flag);
+ spin_unlock_irq(&ehci->lock);
}
/* ehci_shutdown kick in for silicon on any bus (not just pci, etc).
@@ -495,12 +342,15 @@ static void ehci_shutdown(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- del_timer_sync(&ehci->watchdog);
- del_timer_sync(&ehci->iaa_watchdog);
-
spin_lock_irq(&ehci->lock);
- ehci_silence_controller(ehci);
+ ehci->shutdown = true;
+ ehci->rh_state = EHCI_RH_STOPPING;
+ ehci->enabled_hrtimer_events = 0;
spin_unlock_irq(&ehci->lock);
+
+ ehci_silence_controller(ehci);
+
+ hrtimer_cancel(&ehci->hrtimer);
}
static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
@@ -529,28 +379,33 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
*/
static void ehci_work (struct ehci_hcd *ehci)
{
- timer_action_done (ehci, TIMER_IO_WATCHDOG);
-
/* another CPU may drop ehci->lock during a schedule scan while
* it reports urb completions. this flag guards against bogus
* attempts at re-entrant schedule scanning.
*/
- if (ehci->scanning)
+ if (ehci->scanning) {
+ ehci->need_rescan = true;
return;
- ehci->scanning = 1;
- scan_async (ehci);
- if (ehci->next_uframe != -1)
- scan_periodic (ehci);
- ehci->scanning = 0;
+ }
+ ehci->scanning = true;
+
+ rescan:
+ ehci->need_rescan = false;
+ if (ehci->async_count)
+ scan_async(ehci);
+ if (ehci->intr_count > 0)
+ scan_intr(ehci);
+ if (ehci->isoc_count > 0)
+ scan_isoc(ehci);
+ if (ehci->need_rescan)
+ goto rescan;
+ ehci->scanning = false;
/* the IO watchdog guards against hardware or driver bugs that
* misplace IRQs, and should let us run completely without IRQs.
* such lossage has been observed on both VT6202 and VT8235.
*/
- if (ehci->rh_state == EHCI_RH_RUNNING &&
- (ehci->async->qh_next.ptr != NULL ||
- ehci->periodic_sched != 0))
- timer_action (ehci, TIMER_IO_WATCHDOG);
+ turn_on_io_watchdog(ehci);
}
/*
@@ -563,24 +418,22 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci_dbg (ehci, "stop\n");
/* no more interrupts ... */
- del_timer_sync (&ehci->watchdog);
- del_timer_sync(&ehci->iaa_watchdog);
spin_lock_irq(&ehci->lock);
- if (ehci->rh_state == EHCI_RH_RUNNING)
- ehci_quiesce (ehci);
+ ehci->enabled_hrtimer_events = 0;
+ spin_unlock_irq(&ehci->lock);
+ ehci_quiesce(ehci);
ehci_silence_controller(ehci);
ehci_reset (ehci);
- spin_unlock_irq(&ehci->lock);
+ hrtimer_cancel(&ehci->hrtimer);
remove_sysfs_files(ehci);
remove_debug_files (ehci);
/* root hub is shut down separately (first, when possible) */
spin_lock_irq (&ehci->lock);
- if (ehci->async)
- ehci_work (ehci);
+ end_free_itds(ehci);
spin_unlock_irq (&ehci->lock);
ehci_mem_cleanup (ehci);
@@ -588,8 +441,8 @@ static void ehci_stop (struct usb_hcd *hcd)
usb_amd_dev_put();
#ifdef EHCI_STATS
- ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n",
- ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,
+ ehci_dbg(ehci, "irq normal %ld err %ld iaa %ld (lost %ld)\n",
+ ehci->stats.normal, ehci->stats.error, ehci->stats.iaa,
ehci->stats.lost_iaa);
ehci_dbg (ehci, "complete %ld unlink %ld\n",
ehci->stats.complete, ehci->stats.unlink);
@@ -614,13 +467,10 @@ static int ehci_init(struct usb_hcd *hcd)
* keep io watchdog by default, those good HCDs could turn off it later
*/
ehci->need_io_watchdog = 1;
- init_timer(&ehci->watchdog);
- ehci->watchdog.function = ehci_watchdog;
- ehci->watchdog.data = (unsigned long) ehci;
- init_timer(&ehci->iaa_watchdog);
- ehci->iaa_watchdog.function = ehci_iaa_watchdog;
- ehci->iaa_watchdog.data = (unsigned long) ehci;
+ hrtimer_init(&ehci->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ ehci->hrtimer.function = ehci_hrtimer_func;
+ ehci->next_hrtimer_event = EHCI_HRTIMER_NO_EVENT;
hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
@@ -635,6 +485,7 @@ 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->intr_qh_list);
INIT_LIST_HEAD(&ehci->cached_itd_list);
INIT_LIST_HEAD(&ehci->cached_sitd_list);
@@ -656,10 +507,6 @@ static int ehci_init(struct usb_hcd *hcd)
else // N microframes cached
ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
- ehci->reclaim = NULL;
- ehci->next_uframe = -1;
- ehci->clock_frame = -1;
-
/*
* dedicate a qh for the async ring head, since we couldn't unlink
* a 'real' qh without stopping the async schedule [4.8]. use it
@@ -672,7 +519,7 @@ static int ehci_init(struct usb_hcd *hcd)
hw->hw_next = QH_NEXT(ehci, ehci->async->qh_dma);
hw->hw_info1 = cpu_to_hc32(ehci, QH_HEAD);
#if defined(CONFIG_PPC_PS3)
- hw->hw_info1 |= cpu_to_hc32(ehci, (1 << 7)); /* I = 1 */
+ hw->hw_info1 |= cpu_to_hc32(ehci, QH_INACTIVATE);
#endif
hw->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
hw->hw_qtd_next = EHCI_LIST_END(ehci);
@@ -813,7 +660,7 @@ static int ehci_run (struct usb_hcd *hcd)
return 0;
}
-static int __maybe_unused ehci_setup (struct usb_hcd *hcd)
+static int ehci_setup(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int retval;
@@ -828,15 +675,18 @@ static int __maybe_unused ehci_setup (struct usb_hcd *hcd)
ehci->sbrn = HCD_USB2;
- retval = ehci_halt(ehci);
+ /* data structure init */
+ retval = ehci_init(hcd);
if (retval)
return retval;
- /* data structure init */
- retval = ehci_init(hcd);
+ retval = ehci_halt(ehci);
if (retval)
return retval;
+ if (ehci_is_TDI(ehci))
+ tdi_reset(ehci);
+
ehci_reset(ehci);
return 0;
@@ -895,14 +745,28 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* complete the unlinking of some qh [4.15.2.3] */
if (status & STS_IAA) {
+
+ /* Turn off the IAA watchdog */
+ ehci->enabled_hrtimer_events &= ~BIT(EHCI_HRTIMER_IAA_WATCHDOG);
+
+ /*
+ * Mild optimization: Allow another IAAD to reset the
+ * hrtimer, if one occurs before the next expiration.
+ * In theory we could always cancel the hrtimer, but
+ * tests show that about half the time it will be reset
+ * for some other event anyway.
+ */
+ if (ehci->next_hrtimer_event == EHCI_HRTIMER_IAA_WATCHDOG)
+ ++ehci->next_hrtimer_event;
+
/* guard against (alleged) silicon errata */
if (cmd & CMD_IAAD)
ehci_dbg(ehci, "IAA with IAAD still set?\n");
- if (ehci->reclaim) {
- COUNT(ehci->stats.reclaim);
+ if (ehci->async_iaa) {
+ COUNT(ehci->stats.iaa);
end_unlink_async(ehci);
} else
- ehci_dbg(ehci, "IAA with nothing to reclaim?\n");
+ ehci_dbg(ehci, "IAA with nothing unlinked?\n");
}
/* remote wakeup [4.3.1] */
@@ -956,15 +820,19 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
ehci_err(ehci, "fatal error\n");
dbg_cmd(ehci, "fatal", cmd);
dbg_status(ehci, "fatal", status);
- ehci_halt(ehci);
dead:
- ehci_reset(ehci);
- ehci_writel(ehci, 0, &ehci->regs->configured_flag);
usb_hc_died(hcd);
- /* generic layer kills/unlinks all urbs, then
- * uses ehci_stop to clean up the rest
- */
- bh = 1;
+
+ /* Don't let the controller do anything more */
+ ehci->shutdown = true;
+ ehci->rh_state = EHCI_RH_STOPPING;
+ ehci->command &= ~(CMD_RUN | CMD_ASE | CMD_PSE);
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+ ehci_handle_controller_death(ehci);
+
+ /* Handle completions when the controller stops */
+ bh = 0;
}
if (bh)
@@ -1026,38 +894,6 @@ static int ehci_urb_enqueue (
}
}
-static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
-{
- /* failfast */
- if (ehci->rh_state != EHCI_RH_RUNNING && ehci->reclaim)
- end_unlink_async(ehci);
-
- /* 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;
- return;
- }
-
- /* defer till later if busy */
- if (ehci->reclaim) {
- struct ehci_qh *last;
-
- for (last = ehci->reclaim;
- last->reclaim;
- last = last->reclaim)
- continue;
- qh->qh_state = QH_STATE_UNLINK_WAIT;
- last->reclaim = qh;
-
- /* start IAA cycle */
- } else
- start_unlink_async (ehci, qh);
-}
-
/* remove from hardware lists
* completions normally happen asynchronously
*/
@@ -1084,7 +920,7 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
switch (qh->qh_state) {
case QH_STATE_LINKED:
case QH_STATE_COMPLETING:
- unlink_async(ehci, qh);
+ start_unlink_async(ehci, qh);
break;
case QH_STATE_UNLINK:
case QH_STATE_UNLINK_WAIT:
@@ -1104,7 +940,7 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
switch (qh->qh_state) {
case QH_STATE_LINKED:
case QH_STATE_COMPLETING:
- intr_deschedule (ehci, qh);
+ start_unlink_intr(ehci, qh);
break;
case QH_STATE_IDLE:
qh_completions (ehci, qh);
@@ -1152,11 +988,17 @@ rescan:
* accelerate iso completions ... so spin a while.
*/
if (qh->hw == NULL) {
- ehci_vdbg (ehci, "iso delay\n");
- goto idle_timeout;
+ struct ehci_iso_stream *stream = ep->hcpriv;
+
+ if (!list_empty(&stream->td_list))
+ goto idle_timeout;
+
+ /* BUG_ON(!list_empty(&stream->free_list)); */
+ kfree(stream);
+ goto done;
}
- if (ehci->rh_state != EHCI_RH_RUNNING)
+ if (ehci->rh_state < EHCI_RH_RUNNING)
qh->qh_state = QH_STATE_IDLE;
switch (qh->qh_state) {
case QH_STATE_LINKED:
@@ -1169,7 +1011,7 @@ rescan:
* may already be unlinked.
*/
if (tmp)
- unlink_async(ehci, qh);
+ start_unlink_async(ehci, qh);
/* FALL THROUGH */
case QH_STATE_UNLINK: /* wait for hw to finish? */
case QH_STATE_UNLINK_WAIT:
@@ -1181,7 +1023,7 @@ idle_timeout:
if (qh->clearing_tt)
goto idle_timeout;
if (list_empty (&qh->qtd_list)) {
- qh_put (qh);
+ qh_destroy(ehci, qh);
break;
}
/* else FALL THROUGH */
@@ -1194,8 +1036,8 @@ idle_timeout:
list_empty (&qh->qtd_list) ? "" : "(has tds)");
break;
}
+ done:
ep->hcpriv = NULL;
-done:
spin_unlock_irqrestore (&ehci->lock, flags);
}
@@ -1232,9 +1074,9 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
* re-linking will call qh_refresh().
*/
if (eptype == USB_ENDPOINT_XFER_BULK)
- unlink_async(ehci, qh);
+ start_unlink_async(ehci, qh);
else
- intr_deschedule(ehci, qh);
+ start_unlink_intr(ehci, qh);
}
}
spin_unlock_irqrestore(&ehci->lock, flags);
@@ -1247,6 +1089,104 @@ static int ehci_get_frame (struct usb_hcd *hcd)
}
/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_PM
+
+/* suspend/resume, section 4.3 */
+
+/* These routines handle the generic parts of controller suspend/resume */
+
+static int __maybe_unused ehci_suspend(struct usb_hcd *hcd, bool do_wakeup)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+ if (time_before(jiffies, ehci->next_statechange))
+ msleep(10);
+
+ /*
+ * Root hub was already suspended. Disable IRQ emission and
+ * mark HW unaccessible. The PM and USB cores make sure that
+ * the root hub is either suspended or stopped.
+ */
+ ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup);
+
+ spin_lock_irq(&ehci->lock);
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+ (void) ehci_readl(ehci, &ehci->regs->intr_enable);
+
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ spin_unlock_irq(&ehci->lock);
+
+ return 0;
+}
+
+/* Returns 0 if power was preserved, 1 if power was lost */
+static int __maybe_unused ehci_resume(struct usb_hcd *hcd, bool hibernated)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+ if (time_before(jiffies, ehci->next_statechange))
+ msleep(100);
+
+ /* Mark hardware accessible again as we are back to full power by now */
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+ if (ehci->shutdown)
+ return 0; /* Controller is dead */
+
+ /*
+ * If CF is still set and we aren't resuming from hibernation
+ * then we maintained suspend power.
+ * Just undo the effect of ehci_suspend().
+ */
+ if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
+ !hibernated) {
+ int mask = INTR_MASK;
+
+ ehci_prepare_ports_for_controller_resume(ehci);
+
+ spin_lock_irq(&ehci->lock);
+ if (ehci->shutdown)
+ goto skip;
+
+ if (!hcd->self.root_hub->do_remote_wakeup)
+ mask &= ~STS_PCD;
+ ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+ ehci_readl(ehci, &ehci->regs->intr_enable);
+ skip:
+ spin_unlock_irq(&ehci->lock);
+ return 0;
+ }
+
+ /*
+ * Else reset, to cope with power loss or resume from hibernation
+ * having let the firmware kick in during reboot.
+ */
+ usb_root_hub_lost_power(hcd->self.root_hub);
+ (void) ehci_halt(ehci);
+ (void) ehci_reset(ehci);
+
+ spin_lock_irq(&ehci->lock);
+ if (ehci->shutdown)
+ goto skip;
+
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
+
+ ehci->rh_state = EHCI_RH_SUSPENDED;
+ spin_unlock_irq(&ehci->lock);
+
+ /* here we "know" root ports should always stay powered */
+ ehci_port_power(ehci, 1);
+
+ return 1;
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
/*
* The EHCI in ChipIdea HDRC cannot be a separate module or device,
* because its registers (and irq) are shared between host/gadget/otg
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index fc9e7cc..c788022 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -59,6 +59,7 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
/* Give the connections some time to appear */
msleep(20);
+ spin_lock_irq(&ehci->lock);
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
if (test_bit(port, &ehci->owned_ports)) {
@@ -70,23 +71,30 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
clear_bit(port, &ehci->owned_ports);
else if (test_bit(port, &ehci->companion_ports))
ehci_writel(ehci, status & ~PORT_PE, reg);
- else
+ else {
+ spin_unlock_irq(&ehci->lock);
ehci_hub_control(hcd, SetPortFeature,
USB_PORT_FEAT_RESET, port + 1,
NULL, 0);
+ spin_lock_irq(&ehci->lock);
+ }
}
}
+ spin_unlock_irq(&ehci->lock);
if (!ehci->owned_ports)
return;
msleep(90); /* Wait for resets to complete */
+ spin_lock_irq(&ehci->lock);
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
if (test_bit(port, &ehci->owned_ports)) {
+ spin_unlock_irq(&ehci->lock);
ehci_hub_control(hcd, GetPortStatus,
0, port + 1,
(char *) &buf, sizeof(buf));
+ spin_lock_irq(&ehci->lock);
/* The companion should now own the port,
* but if something went wrong the port must not
@@ -105,9 +113,10 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
}
ehci->owned_ports = 0;
+ spin_unlock_irq(&ehci->lock);
}
-static int __maybe_unused ehci_port_change(struct ehci_hcd *ehci)
+static int ehci_port_change(struct ehci_hcd *ehci)
{
int i = HCS_N_PORTS(ehci->hcs_params);
@@ -128,12 +137,11 @@ static int __maybe_unused ehci_port_change(struct ehci_hcd *ehci)
return 0;
}
-static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
+static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
bool suspending, bool do_wakeup)
{
int port;
u32 temp;
- unsigned long flags;
/* If remote wakeup is enabled for the root hub but disabled
* for the controller, we must adjust all the port wakeup flags
@@ -143,22 +151,20 @@ static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup)
return;
- spin_lock_irqsave(&ehci->lock, flags);
+ spin_lock_irq(&ehci->lock);
/* clear phy low-power mode before changing wakeup flags */
if (ehci->has_hostpc) {
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
- u32 __iomem *hostpc_reg;
+ u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port];
- hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
- + HOSTPC0 + 4 * port);
temp = ehci_readl(ehci, hostpc_reg);
ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg);
}
- spin_unlock_irqrestore(&ehci->lock, flags);
+ spin_unlock_irq(&ehci->lock);
msleep(5);
- spin_lock_irqsave(&ehci->lock, flags);
+ spin_lock_irq(&ehci->lock);
}
port = HCS_N_PORTS(ehci->hcs_params);
@@ -185,10 +191,8 @@ static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
if (ehci->has_hostpc) {
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
- u32 __iomem *hostpc_reg;
+ u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port];
- hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
- + HOSTPC0 + 4 * port);
temp = ehci_readl(ehci, hostpc_reg);
ehci_writel(ehci, temp | HOSTPC_PHCD, hostpc_reg);
}
@@ -198,7 +202,7 @@ static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
if (!suspending && ehci_port_change(ehci))
usb_hcd_resume_root_hub(ehci_to_hcd(ehci));
- spin_unlock_irqrestore(&ehci->lock, flags);
+ spin_unlock_irq(&ehci->lock);
}
static int ehci_bus_suspend (struct usb_hcd *hcd)
@@ -212,10 +216,13 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
if (time_before (jiffies, ehci->next_statechange))
msleep(5);
- del_timer_sync(&ehci->watchdog);
- del_timer_sync(&ehci->iaa_watchdog);
+
+ /* stop the schedules */
+ ehci_quiesce(ehci);
spin_lock_irq (&ehci->lock);
+ if (ehci->rh_state < EHCI_RH_RUNNING)
+ goto done;
/* Once the controller is stopped, port resumes that are already
* in progress won't complete. Hence if remote wakeup is enabled
@@ -230,11 +237,6 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
}
}
- /* stop schedules, clean any completed work */
- if (ehci->rh_state == EHCI_RH_RUNNING)
- ehci_quiesce (ehci);
- ehci_work(ehci);
-
/* Unlike other USB host controller types, EHCI doesn't have
* any notion of "global" or bus-wide suspend. The driver has
* to manually suspend all the active unsuspended ports, and
@@ -285,11 +287,9 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
- u32 __iomem *hostpc_reg;
+ u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port];
u32 t3;
- hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
- + HOSTPC0 + 4 * port);
t3 = ehci_readl(ehci, hostpc_reg);
ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
t3 = ehci_readl(ehci, hostpc_reg);
@@ -298,6 +298,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
"succeeded" : "failed");
}
}
+ spin_unlock_irq(&ehci->lock);
/* Apparently some devices need a >= 1-uframe delay here */
if (ehci->bus_suspended)
@@ -305,10 +306,18 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
/* turn off now-idle HC */
ehci_halt (ehci);
+
+ spin_lock_irq(&ehci->lock);
+ if (ehci->enabled_hrtimer_events & BIT(EHCI_HRTIMER_POLL_DEAD))
+ ehci_handle_controller_death(ehci);
+ if (ehci->rh_state != EHCI_RH_RUNNING)
+ goto done;
ehci->rh_state = EHCI_RH_SUSPENDED;
- if (ehci->reclaim)
- end_unlink_async(ehci);
+ end_unlink_async(ehci);
+ unlink_empty_async(ehci);
+ ehci_handle_intr_unlinks(ehci);
+ end_free_itds(ehci);
/* allow remote wakeup */
mask = INTR_MASK;
@@ -317,13 +326,13 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
ehci_writel(ehci, mask, &ehci->regs->intr_enable);
ehci_readl(ehci, &ehci->regs->intr_enable);
+ done:
ehci->next_statechange = jiffies + msecs_to_jiffies(10);
+ ehci->enabled_hrtimer_events = 0;
+ ehci->next_hrtimer_event = EHCI_HRTIMER_NO_EVENT;
spin_unlock_irq (&ehci->lock);
- /* ehci_work() may have re-enabled the watchdog timer, which we do not
- * want, and so we must delete any pending watchdog timer events.
- */
- del_timer_sync(&ehci->watchdog);
+ hrtimer_cancel(&ehci->hrtimer);
return 0;
}
@@ -340,10 +349,8 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
if (time_before (jiffies, ehci->next_statechange))
msleep(5);
spin_lock_irq (&ehci->lock);
- if (!HCD_HW_ACCESSIBLE(hcd)) {
- spin_unlock_irq(&ehci->lock);
- return -ESHUTDOWN;
- }
+ if (!HCD_HW_ACCESSIBLE(hcd) || ehci->shutdown)
+ goto shutdown;
if (unlikely(ehci->debug)) {
if (!dbgp_reset_prep())
@@ -382,16 +389,17 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
spin_unlock_irq(&ehci->lock);
msleep(8);
spin_lock_irq(&ehci->lock);
+ if (ehci->shutdown)
+ goto shutdown;
/* clear phy low-power mode before resume */
if (ehci->bus_suspended && ehci->has_hostpc) {
i = HCS_N_PORTS(ehci->hcs_params);
while (i--) {
if (test_bit(i, &ehci->bus_suspended)) {
- u32 __iomem *hostpc_reg;
+ u32 __iomem *hostpc_reg =
+ &ehci->regs->hostpc[i];
- hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
- + HOSTPC0 + 4 * i);
temp = ehci_readl(ehci, hostpc_reg);
ehci_writel(ehci, temp & ~HOSTPC_PHCD,
hostpc_reg);
@@ -400,6 +408,8 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
spin_unlock_irq(&ehci->lock);
msleep(5);
spin_lock_irq(&ehci->lock);
+ if (ehci->shutdown)
+ goto shutdown;
}
/* manually resume the ports we suspended during bus_suspend() */
@@ -420,6 +430,8 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
spin_unlock_irq(&ehci->lock);
msleep(20);
spin_lock_irq(&ehci->lock);
+ if (ehci->shutdown)
+ goto shutdown;
}
i = HCS_N_PORTS (ehci->hcs_params);
@@ -431,27 +443,25 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
ehci_vdbg (ehci, "resumed port %d\n", i + 1);
}
}
- (void) ehci_readl(ehci, &ehci->regs->command);
-
- /* maybe re-activate the schedule(s) */
- temp = 0;
- if (ehci->async->qh_next.qh)
- temp |= CMD_ASE;
- if (ehci->periodic_sched)
- temp |= CMD_PSE;
- if (temp) {
- ehci->command |= temp;
- ehci_writel(ehci, ehci->command, &ehci->regs->command);
- }
ehci->next_statechange = jiffies + msecs_to_jiffies(5);
+ spin_unlock_irq(&ehci->lock);
+
+ ehci_handover_companion_ports(ehci);
/* Now we can safely re-enable irqs */
+ spin_lock_irq(&ehci->lock);
+ if (ehci->shutdown)
+ goto shutdown;
ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
+ (void) ehci_readl(ehci, &ehci->regs->intr_enable);
+ spin_unlock_irq(&ehci->lock);
- spin_unlock_irq (&ehci->lock);
- ehci_handover_companion_ports(ehci);
return 0;
+
+ shutdown:
+ spin_unlock_irq(&ehci->lock);
+ return -ESHUTDOWN;
}
#else
@@ -667,7 +677,7 @@ static int ehci_hub_control (
int ports = HCS_N_PORTS (ehci->hcs_params);
u32 __iomem *status_reg = &ehci->regs->port_status[
(wIndex & 0xff) - 1];
- u32 __iomem *hostpc_reg = NULL;
+ u32 __iomem *hostpc_reg = &ehci->regs->hostpc[(wIndex & 0xff) - 1];
u32 temp, temp1, status;
unsigned long flags;
int retval = 0;
@@ -680,9 +690,6 @@ static int ehci_hub_control (
* power, "this is the one", etc. EHCI spec supports this.
*/
- if (ehci->has_hostpc)
- hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
- + HOSTPC0 + 4 * ((wIndex & 0xff) - 1));
spin_lock_irqsave (&ehci->lock, flags);
switch (typeReq) {
case ClearHubFeature:
@@ -724,7 +731,7 @@ static int ehci_hub_control (
#ifdef CONFIG_USB_OTG
if ((hcd->self.otg_port == (wIndex + 1))
&& hcd->self.b_hnp_enable) {
- otg_start_hnp(ehci->transceiver->otg);
+ otg_start_hnp(hcd->phy->otg);
break;
}
#endif
@@ -734,7 +741,7 @@ static int ehci_hub_control (
goto error;
/* clear phy low-power mode before resume */
- if (hostpc_reg) {
+ if (ehci->has_hostpc) {
temp1 = ehci_readl(ehci, hostpc_reg);
ehci_writel(ehci, temp1 & ~HOSTPC_PHCD,
hostpc_reg);
@@ -984,7 +991,7 @@ static int ehci_hub_control (
temp &= ~PORT_WKCONN_E;
temp |= PORT_WKDISC_E | PORT_WKOC_E;
ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
- if (hostpc_reg) {
+ if (ehci->has_hostpc) {
spin_unlock_irqrestore(&ehci->lock, flags);
msleep(5);/* 5ms for HCD enter low pwr mode */
spin_lock_irqsave(&ehci->lock, flags);
@@ -1041,7 +1048,9 @@ static int ehci_hub_control (
case USB_PORT_FEAT_TEST:
if (!selector || selector > 5)
goto error;
+ spin_unlock_irqrestore(&ehci->lock, flags);
ehci_quiesce(ehci);
+ spin_lock_irqsave(&ehci->lock, flags);
/* Put all enabled ports into suspend */
while (ports--) {
@@ -1053,7 +1062,11 @@ static int ehci_hub_control (
ehci_writel(ehci, temp | PORT_SUSPEND,
sreg);
}
+
+ spin_unlock_irqrestore(&ehci->lock, flags);
ehci_halt(ehci);
+ spin_lock_irqsave(&ehci->lock, flags);
+
temp = ehci_readl(ehci, status_reg);
temp |= selector << 16;
ehci_writel(ehci, temp, status_reg);
diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c
index c4460f3..488d401 100644
--- a/drivers/usb/host/ehci-ixp4xx.c
+++ b/drivers/usb/host/ehci-ixp4xx.c
@@ -22,14 +22,10 @@ static int ixp4xx_ehci_init(struct usb_hcd *hcd)
ehci->big_endian_mmio = 1;
ehci->caps = hcd->regs + 0x100;
- ehci->regs = hcd->regs + 0x100
- + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
hcd->has_tt = 1;
- ehci_reset(ehci);
- retval = ehci_init(hcd);
+ retval = ehci_setup(hcd);
if (retval)
return retval;
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index 12f70c3..ef2c3a1 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -64,10 +64,8 @@ static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
}
-static void qh_destroy(struct ehci_qh *qh)
+static void qh_destroy(struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- struct ehci_hcd *ehci = qh->ehci;
-
/* clean qtds first, and know this is not linked */
if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
ehci_dbg (ehci, "unused qh not empty!\n");
@@ -92,8 +90,6 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
if (!qh->hw)
goto fail;
memset(qh->hw, 0, sizeof *qh->hw);
- qh->refcount = 1;
- qh->ehci = ehci;
qh->qh_dma = dma;
// INIT_LIST_HEAD (&qh->qh_list);
INIT_LIST_HEAD (&qh->qtd_list);
@@ -113,20 +109,6 @@ fail:
return NULL;
}
-/* to share a qh (cpu threads, or hc) */
-static inline struct ehci_qh *qh_get (struct ehci_qh *qh)
-{
- WARN_ON(!qh->refcount);
- qh->refcount++;
- return qh;
-}
-
-static inline void qh_put (struct ehci_qh *qh)
-{
- if (!--qh->refcount)
- qh_destroy(qh);
-}
-
/*-------------------------------------------------------------------------*/
/* The queue heads and transfer descriptors are managed from pools tied
@@ -136,13 +118,12 @@ static inline void qh_put (struct ehci_qh *qh)
static void ehci_mem_cleanup (struct ehci_hcd *ehci)
{
- free_cached_lists(ehci);
if (ehci->async)
- qh_put (ehci->async);
+ qh_destroy(ehci, ehci->async);
ehci->async = NULL;
if (ehci->dummy)
- qh_put(ehci->dummy);
+ qh_destroy(ehci, ehci->dummy);
ehci->dummy = NULL;
/* DMA consistent memory and pools */
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 9803a55..17dd9e9 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -145,8 +145,8 @@ static int ehci_msm_probe(struct platform_device *pdev)
* powering up VBUS, mapping of registers address space and power
* management.
*/
- phy = usb_get_transceiver();
- if (!phy) {
+ phy = usb_get_phy(USB_PHY_TYPE_USB2);
+ if (IS_ERR_OR_NULL(phy)) {
dev_err(&pdev->dev, "unable to find transceiver\n");
ret = -ENODEV;
goto unmap;
@@ -169,7 +169,7 @@ static int ehci_msm_probe(struct platform_device *pdev)
return 0;
put_transceiver:
- usb_put_transceiver(phy);
+ usb_put_phy(phy);
unmap:
iounmap(hcd->regs);
put_hcd:
@@ -187,7 +187,7 @@ static int __devexit ehci_msm_remove(struct platform_device *pdev)
pm_runtime_set_suspended(&pdev->dev);
otg_set_host(phy->otg, NULL);
- usb_put_transceiver(phy);
+ usb_put_phy(phy);
usb_put_hcd(hcd);
@@ -198,24 +198,11 @@ static int __devexit ehci_msm_remove(struct platform_device *pdev)
static int ehci_msm_pm_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
- bool wakeup = device_may_wakeup(dev);
+ bool do_wakeup = device_may_wakeup(dev);
dev_dbg(dev, "ehci-msm PM suspend\n");
- /*
- * EHCI helper function has also the same check before manipulating
- * port wakeup flags. We do check here the same condition before
- * calling the same helper function to avoid bringing hardware
- * from Low power mode when there is no need for adjusting port
- * wakeup flags.
- */
- if (hcd->self.root_hub->do_remote_wakeup && !wakeup) {
- pm_runtime_resume(dev);
- ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
- wakeup);
- }
-
- return 0;
+ return ehci_suspend(hcd, do_wakeup);
}
static int ehci_msm_pm_resume(struct device *dev)
@@ -223,7 +210,7 @@ static int ehci_msm_pm_resume(struct device *dev)
struct usb_hcd *hcd = dev_get_drvdata(dev);
dev_dbg(dev, "ehci-msm PM resume\n");
- ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
+ ehci_resume(hcd, false);
return 0;
}
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c
index a936bbc..f6df1cc 100644
--- a/drivers/usb/host/ehci-mv.c
+++ b/drivers/usb/host/ehci-mv.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/err.h>
#include <linux/usb/otg.h>
#include <linux/platform_data/mv_usb.h>
@@ -76,7 +77,6 @@ static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv)
static int mv_ehci_reset(struct usb_hcd *hcd)
{
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct device *dev = hcd->self.controller;
struct ehci_hcd_mv *ehci_mv = dev_get_drvdata(dev);
int retval;
@@ -86,25 +86,13 @@ static int mv_ehci_reset(struct usb_hcd *hcd)
return -ENODEV;
}
- /*
- * data structure init
- */
- retval = ehci_init(hcd);
- if (retval) {
- dev_err(dev, "ehci_init failed %d\n", retval);
- return retval;
- }
-
hcd->has_tt = 1;
- ehci->sbrn = 0x20;
- retval = ehci_reset(ehci);
- if (retval) {
- dev_err(dev, "ehci_reset failed %d\n", retval);
- return retval;
- }
+ retval = ehci_setup(hcd);
+ if (retval)
+ dev_err(dev, "ehci_setup failed %d\n", retval);
- return 0;
+ return retval;
}
static const struct hc_driver mv_ehci_hc_driver = {
@@ -247,14 +235,12 @@ static int mv_ehci_probe(struct platform_device *pdev)
ehci = hcd_to_ehci(hcd);
ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs;
- ehci->regs = (struct ehci_regs *) ehci_mv->op_regs;
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
ehci_mv->mode = pdata->mode;
if (ehci_mv->mode == MV_USB_MODE_OTG) {
#ifdef CONFIG_USB_OTG_UTILS
- ehci_mv->otg = usb_get_transceiver();
- if (!ehci_mv->otg) {
+ ehci_mv->otg = usb_get_phy(USB_PHY_TYPE_USB2);
+ if (IS_ERR_OR_NULL(ehci_mv->otg)) {
dev_err(&pdev->dev,
"unable to find transceiver\n");
retval = -ENODEV;
@@ -302,8 +288,8 @@ err_set_vbus:
pdata->set_vbus(0);
#ifdef CONFIG_USB_OTG_UTILS
err_put_transceiver:
- if (ehci_mv->otg)
- usb_put_transceiver(ehci_mv->otg);
+ if (!IS_ERR_OR_NULL(ehci_mv->otg))
+ usb_put_phy(ehci_mv->otg);
#endif
err_disable_clk:
mv_ehci_disable(ehci_mv);
@@ -331,9 +317,9 @@ static int mv_ehci_remove(struct platform_device *pdev)
if (hcd->rh_registered)
usb_remove_hcd(hcd);
- if (ehci_mv->otg) {
+ if (!IS_ERR_OR_NULL(ehci_mv->otg)) {
otg_set_host(ehci_mv->otg->otg, NULL);
- usb_put_transceiver(ehci_mv->otg);
+ usb_put_phy(ehci_mv->otg);
}
if (ehci_mv->mode == MV_USB_MODE_HOST) {
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index c778ffe..3420137 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -42,27 +42,12 @@ static int ehci_mxc_setup(struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int retval;
- dbg_hcs_params(ehci, "reset");
- dbg_hcc_params(ehci, "reset");
-
- /* cache this readonly data; minimize chip reads */
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-
hcd->has_tt = 1;
- retval = ehci_halt(ehci);
+ retval = ehci_setup(hcd);
if (retval)
return retval;
- /* data structure init */
- retval = ehci_init(hcd);
- if (retval)
- return retval;
-
- ehci->sbrn = 0x20;
-
- ehci_reset(ehci);
-
ehci_port_power(ehci, 0);
return 0;
}
diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c
index c010488..ba26957a 100644
--- a/drivers/usb/host/ehci-octeon.c
+++ b/drivers/usb/host/ehci-octeon.c
@@ -56,7 +56,7 @@ static const struct hc_driver ehci_octeon_hc_driver = {
/*
* basic lifecycle operations
*/
- .reset = ehci_init,
+ .reset = ehci_setup,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
@@ -150,12 +150,6 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev)
#endif
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs +
- HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
- /* cache this readonly data; minimize chip reads */
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-
- ehci_reset(ehci);
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret) {
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index c304354..ec21f4a 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -115,9 +115,8 @@ static void omap_ehci_erratum_i693(struct ehci_hcd *ehci)
clk_disable(usbhost_p2_fck);
}
-static void omap_ehci_soft_phy_reset(struct platform_device *pdev, u8 port)
+static void omap_ehci_soft_phy_reset(struct usb_hcd *hcd, u8 port)
{
- struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev);
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
unsigned reg = 0;
@@ -139,12 +138,63 @@ static void omap_ehci_soft_phy_reset(struct platform_device *pdev, u8 port)
cpu_relax();
if (time_after(jiffies, timeout)) {
- dev_dbg(&pdev->dev, "phy reset operation timed out\n");
+ 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 ehci_hcd_omap_platform_data *pdata;
+
+ pdata = hcd->self.controller->platform_data;
+ if (pdata->phy_reset) {
+ if (gpio_is_valid(pdata->reset_gpio_port[0]))
+ gpio_request_one(pdata->reset_gpio_port[0],
+ GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
+
+ if (gpio_is_valid(pdata->reset_gpio_port[1]))
+ gpio_request_one(pdata->reset_gpio_port[1],
+ GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
+
+ /* 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);
+ }
+
+ /* root ports should always stay powered */
+ ehci_port_power(ehci, 1);
+
+ return rc;
+}
+
static int omap_ehci_hub_control(
struct usb_hcd *hcd,
u16 typeReq,
@@ -219,7 +269,6 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
struct resource *res;
struct usb_hcd *hcd;
void __iomem *regs;
- struct ehci_hcd *omap_ehci;
int ret = -ENODEV;
int irq;
int i;
@@ -281,18 +330,6 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
}
}
- /* 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);
- }
-
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
@@ -308,49 +345,12 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
ehci_write(regs, EHCI_INSNREG04,
EHCI_INSNREG04_DISABLE_UNSUSPEND);
- /* 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(pdev, 0);
- if (pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_PHY)
- omap_ehci_soft_phy_reset(pdev, 1);
-
- omap_ehci = hcd_to_ehci(hcd);
- omap_ehci->sbrn = 0x20;
-
- /* we know this is the memory we want, no need to ioremap again */
- omap_ehci->caps = hcd->regs;
- omap_ehci->regs = hcd->regs
- + HC_LENGTH(ehci, readl(&omap_ehci->caps->hc_capbase));
-
- dbg_hcs_params(omap_ehci, "reset");
- dbg_hcc_params(omap_ehci, "reset");
-
- /* cache this readonly data; minimize chip reads */
- omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params);
-
- ehci_reset(omap_ehci);
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret) {
dev_err(dev, "failed to add hcd with err %d\n", ret);
- goto err_add_hcd;
+ goto err_pm_runtime;
}
- 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);
- }
-
- /* root ports should always stay powered */
- ehci_port_power(omap_ehci, 1);
-
/* get clocks */
utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
if (IS_ERR(utmi_p1_fck)) {
@@ -422,8 +422,12 @@ err_utmi_p1_fck:
clk_put(utmi_p1_fck);
err_add_hcd:
+ usb_remove_hcd(hcd);
+
+err_pm_runtime:
disable_put_regulator(pdata);
pm_runtime_put_sync(dev);
+ usb_put_hcd(hcd);
err_io:
iounmap(regs);
@@ -506,7 +510,7 @@ static const struct hc_driver ehci_omap_hc_driver = {
/*
* basic lifecycle operations
*/
- .reset = ehci_init,
+ .reset = omap_ehci_init,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
index 82de107..9408da8 100644
--- a/drivers/usb/host/ehci-orion.c
+++ b/drivers/usb/host/ehci-orion.c
@@ -106,21 +106,10 @@ static int ehci_orion_setup(struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int retval;
- hcd->has_tt = 1;
-
- retval = ehci_halt(ehci);
- if (retval)
- return retval;
-
- /*
- * data structure init
- */
- retval = ehci_init(hcd);
+ retval = ehci_setup(hcd);
if (retval)
return retval;
- ehci_reset(ehci);
-
ehci_port_power(ehci, 0);
return retval;
@@ -261,11 +250,7 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
ehci = hcd_to_ehci(hcd);
ehci->caps = hcd->regs + 0x100;
- ehci->regs = hcd->regs + 0x100 +
- HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
hcd->has_tt = 1;
- ehci->sbrn = 0x20;
/*
* (Re-)program MBUS remapping windows if we are asked to.
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 1234817..2cb7d37 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -54,6 +54,17 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
u32 temp;
int retval;
+ ehci->caps = hcd->regs;
+
+ /*
+ * ehci_init() causes memory for DMA transfers to be
+ * allocated. Thus, any vendor-specific workarounds based on
+ * limiting the type of memory used for DMA transfers must
+ * happen before ehci_setup() is called.
+ *
+ * Most other workarounds can be done either before or after
+ * init and reset; they are located here too.
+ */
switch (pdev->vendor) {
case PCI_VENDOR_ID_TOSHIBA_2:
/* celleb's companion chip */
@@ -66,20 +77,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
#endif
}
break;
- }
-
- ehci->caps = hcd->regs;
- ehci->regs = hcd->regs +
- HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-
- dbg_hcs_params(ehci, "reset");
- dbg_hcc_params(ehci, "reset");
-
- /* ehci_init() causes memory for DMA transfers to be
- * allocated. Thus, any vendor-specific workarounds based on
- * limiting the type of memory used for DMA transfers must
- * happen before ehci_init() is called. */
- switch (pdev->vendor) {
case PCI_VENDOR_ID_NVIDIA:
/* NVidia reports that certain chips don't handle
* QH, ITD, or SITD addresses above 2GB. (But TD,
@@ -95,61 +92,24 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
ehci_warn(ehci, "can't enable NVidia "
"workaround for >2GB RAM\n");
break;
- }
- break;
- }
-
- /* cache this readonly data; minimize chip reads */
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-
- retval = ehci_halt(ehci);
- if (retval)
- return retval;
- if ((pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x7808) ||
- (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x4396)) {
- /* EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may
- * read/write memory space which does not belong to it when
- * there is NULL pointer with T-bit set to 1 in the frame list
- * table. To avoid the issue, the frame list link pointer
- * should always contain a valid pointer to a inactive qh.
+ /* Some NForce2 chips have problems with selective suspend;
+ * fixed in newer silicon.
*/
- ehci->use_dummy_qh = 1;
- ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI "
- "dummy qh workaround\n");
- }
-
- /* data structure init */
- retval = ehci_init(hcd);
- if (retval)
- return retval;
-
- switch (pdev->vendor) {
- case PCI_VENDOR_ID_NEC:
- ehci->need_io_watchdog = 0;
+ case 0x0068:
+ if (pdev->revision < 0xa4)
+ ehci->no_selective_suspend = 1;
+ break;
+ }
break;
case PCI_VENDOR_ID_INTEL:
- ehci->need_io_watchdog = 0;
ehci->fs_i_thresh = 1;
- if (pdev->device == 0x27cc) {
- ehci->broken_periodic = 1;
- ehci_info(ehci, "using broken periodic workaround\n");
- }
- if (pdev->device == 0x0806 || pdev->device == 0x0811
- || pdev->device == 0x0829) {
- ehci_info(ehci, "disable lpm for langwell/penwell\n");
- ehci->has_lpm = 0;
- }
- if (pdev->device == PCI_DEVICE_ID_INTEL_CE4100_USB) {
+ if (pdev->device == PCI_DEVICE_ID_INTEL_CE4100_USB)
hcd->has_tt = 1;
- tdi_reset(ehci);
- }
break;
case PCI_VENDOR_ID_TDI:
- if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
+ if (pdev->device == PCI_DEVICE_ID_TDI_EHCI)
hcd->has_tt = 1;
- tdi_reset(ehci);
- }
break;
case PCI_VENDOR_ID_AMD:
/* AMD PLL quirk */
@@ -161,28 +121,17 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
retval = -EIO;
goto done;
}
- break;
- case PCI_VENDOR_ID_NVIDIA:
- switch (pdev->device) {
- /* Some NForce2 chips have problems with selective suspend;
- * fixed in newer silicon.
- */
- case 0x0068:
- if (pdev->revision < 0xa4)
- ehci->no_selective_suspend = 1;
- break;
- /* MCP89 chips on the MacBookAir3,1 give EPROTO when
- * fetching device descriptors unless LPM is disabled.
- * There are also intermittent problems enumerating
- * devices with PPCD enabled.
+ /*
+ * EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may
+ * read/write memory space which does not belong to it when
+ * there is NULL pointer with T-bit set to 1 in the frame list
+ * table. To avoid the issue, the frame list link pointer
+ * should always contain a valid pointer to a inactive qh.
*/
- case 0x0d9d:
- ehci_info(ehci, "disable lpm/ppcd for nvidia mcp89");
- ehci->has_lpm = 0;
- ehci->has_ppcd = 0;
- ehci->command &= ~CMD_PPCEE;
- break;
+ if (pdev->device == 0x7808) {
+ ehci->use_dummy_qh = 1;
+ ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI dummy qh workaround\n");
}
break;
case PCI_VENDOR_ID_VIA:
@@ -203,6 +152,18 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
/* AMD PLL quirk */
if (usb_amd_find_chipset_info())
ehci->amd_pll_fix = 1;
+
+ /*
+ * EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may
+ * read/write memory space which does not belong to it when
+ * there is NULL pointer with T-bit set to 1 in the frame list
+ * table. To avoid the issue, the frame list link pointer
+ * should always contain a valid pointer to a inactive qh.
+ */
+ if (pdev->device == 0x4396) {
+ ehci->use_dummy_qh = 1;
+ ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI dummy qh workaround\n");
+ }
/* SB600 and old version of SB700 have a bug in EHCI controller,
* which causes usb devices lose response in some cases.
*/
@@ -231,6 +192,40 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
break;
}
+ retval = ehci_setup(hcd);
+ if (retval)
+ return retval;
+
+ /* These workarounds need to be applied after ehci_setup() */
+ switch (pdev->vendor) {
+ case PCI_VENDOR_ID_NEC:
+ ehci->need_io_watchdog = 0;
+ break;
+ case PCI_VENDOR_ID_INTEL:
+ ehci->need_io_watchdog = 0;
+ if (pdev->device == 0x0806 || pdev->device == 0x0811
+ || pdev->device == 0x0829) {
+ ehci_info(ehci, "disable lpm for langwell/penwell\n");
+ ehci->has_lpm = 0;
+ }
+ break;
+ case PCI_VENDOR_ID_NVIDIA:
+ switch (pdev->device) {
+ /* MCP89 chips on the MacBookAir3,1 give EPROTO when
+ * fetching device descriptors unless LPM is disabled.
+ * There are also intermittent problems enumerating
+ * devices with PPCD enabled.
+ */
+ case 0x0d9d:
+ ehci_info(ehci, "disable lpm/ppcd for nvidia mcp89");
+ ehci->has_lpm = 0;
+ ehci->has_ppcd = 0;
+ ehci->command &= ~CMD_PPCEE;
+ break;
+ }
+ break;
+ }
+
/* optional debug port, normally in the first BAR */
temp = pci_find_capability(pdev, 0x0a);
if (temp) {
@@ -238,7 +233,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
temp >>= 16;
if ((temp & (3 << 13)) == (1 << 13)) {
temp &= 0x1fff;
- ehci->debug = ehci_to_hcd(ehci)->regs + temp;
+ ehci->debug = hcd->regs + temp;
temp = ehci_readl(ehci, &ehci->debug->control);
ehci_info(ehci, "debug port %d%s\n",
HCS_DEBUG_PORT(ehci->hcs_params),
@@ -250,8 +245,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
}
}
- ehci_reset(ehci);
-
/* at least the Genesys GL880S needs fixup here */
temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
temp &= 0x0f;
@@ -275,10 +268,11 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
}
/* Serial Bus Release Number is at PCI 0x60 offset */
- pci_read_config_byte(pdev, 0x60, &ehci->sbrn);
if (pdev->vendor == PCI_VENDOR_ID_STMICRO
&& pdev->device == PCI_DEVICE_ID_STMICRO_USB_HOST)
- ehci->sbrn = 0x20; /* ConneXT has no sbrn register */
+ ; /* ConneXT has no sbrn register */
+ else
+ pci_read_config_byte(pdev, 0x60, &ehci->sbrn);
/* Keep this around for a while just in case some EHCI
* implementation uses legacy PCI PM support. This test
@@ -331,29 +325,7 @@ done:
static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
{
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- unsigned long flags;
- int rc = 0;
-
- if (time_before(jiffies, ehci->next_statechange))
- msleep(10);
-
- /* Root hub was already suspended. Disable irq emission and
- * mark HW unaccessible. The PM and USB cores make sure that
- * the root hub is either suspended or stopped.
- */
- ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup);
- spin_lock_irqsave (&ehci->lock, flags);
- ehci_writel(ehci, 0, &ehci->regs->intr_enable);
- (void)ehci_readl(ehci, &ehci->regs->intr_enable);
-
- clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- spin_unlock_irqrestore (&ehci->lock, flags);
-
- // could save FLADJ in case of Vaux power loss
- // ... we'd only use it to handle clock skew
-
- return rc;
+ return ehci_suspend(hcd, do_wakeup);
}
static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev)
@@ -402,54 +374,8 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
if (usb_is_intel_switchable_ehci(pdev))
ehci_enable_xhci_companion();
- // maybe restore FLADJ
-
- if (time_before(jiffies, ehci->next_statechange))
- msleep(100);
-
- /* Mark hardware accessible again as we are out of D3 state by now */
- set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
- /* If CF is still set and we aren't resuming from hibernation
- * then we maintained PCI Vaux power.
- * Just undo the effect of ehci_pci_suspend().
- */
- if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
- !hibernated) {
- int mask = INTR_MASK;
-
- ehci_prepare_ports_for_controller_resume(ehci);
- if (!hcd->self.root_hub->do_remote_wakeup)
- mask &= ~STS_PCD;
- ehci_writel(ehci, mask, &ehci->regs->intr_enable);
- ehci_readl(ehci, &ehci->regs->intr_enable);
- return 0;
- }
-
- usb_root_hub_lost_power(hcd->self.root_hub);
-
- /* Else reset, to cope with power loss or flush-to-storage
- * style "resume" having let BIOS kick in during reboot.
- */
- (void) ehci_halt(ehci);
- (void) ehci_reset(ehci);
- (void) ehci_pci_reinit(ehci, pdev);
-
- /* emptying the schedule aborts any urbs */
- spin_lock_irq(&ehci->lock);
- if (ehci->reclaim)
- end_unlink_async(ehci);
- ehci_work(ehci);
- spin_unlock_irq(&ehci->lock);
-
- ehci_writel(ehci, ehci->command, &ehci->regs->command);
- ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
- ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
-
- /* here we "know" root ports should always stay powered */
- ehci_port_power(ehci, 1);
-
- ehci->rh_state = EHCI_RH_SUSPENDED;
+ if (ehci_resume(hcd, hibernated) != 0)
+ (void) ehci_pci_reinit(ehci, pdev);
return 0;
}
#endif
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index dfe881a..4b1d896 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -153,17 +153,16 @@ static int __devexit ehci_platform_remove(struct platform_device *dev)
static int ehci_platform_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
- bool wakeup = device_may_wakeup(dev);
+ bool do_wakeup = device_may_wakeup(dev);
- ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd), wakeup);
- return 0;
+ return ehci_suspend(hcd, do_wakeup);
}
static int ehci_platform_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
- ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
+ ehci_resume(hcd, false);
return 0;
}
diff --git a/drivers/usb/host/ehci-pmcmsp.c b/drivers/usb/host/ehci-pmcmsp.c
index e8d54de..087aee2 100644
--- a/drivers/usb/host/ehci-pmcmsp.c
+++ b/drivers/usb/host/ehci-pmcmsp.c
@@ -78,27 +78,14 @@ static int ehci_msp_setup(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int retval;
+
ehci->big_endian_mmio = 1;
ehci->big_endian_desc = 1;
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs +
- HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
- dbg_hcs_params(ehci, "reset");
- dbg_hcc_params(ehci, "reset");
-
- /* cache this readonly data; minimize chip reads */
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
hcd->has_tt = 1;
- retval = ehci_halt(ehci);
- if (retval)
- return retval;
-
- ehci_reset(ehci);
-
- /* data structure init */
- retval = ehci_init(hcd);
+ retval = ehci_setup(hcd);
if (retval)
return retval;
diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
index 41d11fe..bbbe89d 100644
--- a/drivers/usb/host/ehci-ppc-of.c
+++ b/drivers/usb/host/ehci-ppc-of.c
@@ -17,24 +17,6 @@
#include <linux/of.h>
#include <linux/of_platform.h>
-/* called during probe() after chip reset completes */
-static int ehci_ppc_of_setup(struct usb_hcd *hcd)
-{
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- int retval;
-
- retval = ehci_halt(ehci);
- if (retval)
- return retval;
-
- retval = ehci_init(hcd);
- if (retval)
- return retval;
-
- ehci->sbrn = 0x20;
- return ehci_reset(ehci);
-}
-
static const struct hc_driver ehci_ppc_of_hc_driver = {
.description = hcd_name,
@@ -50,7 +32,7 @@ static const struct hc_driver ehci_ppc_of_hc_driver = {
/*
* basic lifecycle operations
*/
- .reset = ehci_ppc_of_setup,
+ .reset = ehci_setup,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
@@ -178,11 +160,6 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op)
ehci->big_endian_desc = 1;
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs +
- HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-
- /* cache this readonly data; minimize chip reads */
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
if (of_device_is_compatible(dn, "ibm,usb-ehci-440epx")) {
rv = ppc44x_enable_bmt(dn);
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index a20e496..45a356e 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -55,28 +55,12 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
ehci->big_endian_mmio = 1;
-
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
- &ehci->caps->hc_capbase));
-
- dbg_hcs_params(ehci, "reset");
- dbg_hcc_params(ehci, "reset");
-
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-
- result = ehci_halt(ehci);
+ result = ehci_setup(hcd);
if (result)
return result;
- result = ehci_init(hcd);
-
- if (result)
- return result;
-
- ehci_reset(ehci);
-
ps3_ehci_setup_insnreg(ehci);
return result;
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 4378bf7..9bc39ca 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -100,7 +100,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
* and set the pseudo-toggle in udev. Only usb_clear_halt() will
* ever clear it.
*/
- if (!(hw->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
+ if (!(hw->hw_info1 & cpu_to_hc32(ehci, QH_TOGGLE_CTL))) {
unsigned is_out, epnum;
is_out = qh->is_out;
@@ -265,7 +265,6 @@ __acquires(ehci->lock)
/* ... update hc-wide periodic stats (for usbfs) */
ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
}
- qh_put (qh);
}
if (unlikely(urb->unlinked)) {
@@ -294,9 +293,6 @@ __acquires(ehci->lock)
spin_lock (&ehci->lock);
}
-static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
-static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
-
static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
/*
@@ -326,7 +322,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
*
* It's a bug for qh->qh_state to be anything other than
* QH_STATE_IDLE, unless our caller is scan_async() or
- * scan_periodic().
+ * scan_intr().
*/
state = qh->qh_state;
qh->qh_state = QH_STATE_COMPLETING;
@@ -434,7 +430,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* stop scanning when we reach qtds the hc is using */
} else if (likely (!stopped
- && ehci->rh_state == EHCI_RH_RUNNING)) {
+ && ehci->rh_state >= EHCI_RH_RUNNING)) {
break;
/* scan the whole queue for unlinks whenever it stops */
@@ -442,7 +438,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
stopped = 1;
/* cancel everything if we halt, suspend, etc */
- if (ehci->rh_state != EHCI_RH_RUNNING)
+ if (ehci->rh_state < EHCI_RH_RUNNING)
last_status = -ESHUTDOWN;
/* this qtd is active; skip it unless a previous qtd
@@ -836,7 +832,6 @@ qh_make (
is_input, 0,
hb_mult(maxp) * max_packet(maxp)));
qh->start = NO_FRAME;
- qh->stamp = ehci->periodic_stamp;
if (urb->dev->speed == USB_SPEED_HIGH) {
qh->c_usecs = 0;
@@ -887,7 +882,7 @@ qh_make (
/* using TT? */
switch (urb->dev->speed) {
case USB_SPEED_LOW:
- info1 |= (1 << 12); /* EPS "low" */
+ info1 |= QH_LOW_SPEED;
/* FALL THROUGH */
case USB_SPEED_FULL:
@@ -895,8 +890,8 @@ qh_make (
if (type != PIPE_INTERRUPT)
info1 |= (EHCI_TUNE_RL_TT << 28);
if (type == PIPE_CONTROL) {
- info1 |= (1 << 27); /* for TT */
- info1 |= 1 << 14; /* toggle from qtd */
+ info1 |= QH_CONTROL_EP; /* for TT */
+ info1 |= QH_TOGGLE_CTL; /* toggle from qtd */
}
info1 |= maxp << 16;
@@ -921,11 +916,11 @@ qh_make (
break;
case USB_SPEED_HIGH: /* no TT involved */
- info1 |= (2 << 12); /* EPS "high" */
+ info1 |= QH_HIGH_SPEED;
if (type == PIPE_CONTROL) {
info1 |= (EHCI_TUNE_RL_HS << 28);
info1 |= 64 << 16; /* usb2 fixed maxpacket */
- info1 |= 1 << 14; /* toggle from qtd */
+ info1 |= QH_TOGGLE_CTL; /* toggle from qtd */
info2 |= (EHCI_TUNE_MULT_HS << 30);
} else if (type == PIPE_BULK) {
info1 |= (EHCI_TUNE_RL_HS << 28);
@@ -946,7 +941,7 @@ qh_make (
ehci_dbg(ehci, "bogus dev %p speed %d\n", urb->dev,
urb->dev->speed);
done:
- qh_put (qh);
+ qh_destroy(ehci, qh);
return NULL;
}
@@ -965,6 +960,31 @@ done:
/*-------------------------------------------------------------------------*/
+static void enable_async(struct ehci_hcd *ehci)
+{
+ if (ehci->async_count++)
+ return;
+
+ /* Stop waiting to turn off the async schedule */
+ ehci->enabled_hrtimer_events &= ~BIT(EHCI_HRTIMER_DISABLE_ASYNC);
+
+ /* Don't start the schedule until ASS is 0 */
+ ehci_poll_ASS(ehci);
+ turn_on_io_watchdog(ehci);
+}
+
+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);
+
+ /* Don't turn off the schedule until ASS is 1 */
+ ehci_poll_ASS(ehci);
+}
+
/* move qh (and its qtds) onto async queue; maybe enable queue. */
static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
@@ -978,24 +998,11 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
WARN_ON(qh->qh_state != QH_STATE_IDLE);
- /* (re)start the async schedule? */
- head = ehci->async;
- timer_action_done (ehci, TIMER_ASYNC_OFF);
- if (!head->qh_next.qh) {
- if (!(ehci->command & CMD_ASE)) {
- /* in case a clear of CMD_ASE didn't take yet */
- (void)handshake(ehci, &ehci->regs->status,
- STS_ASS, 0, 150);
- ehci->command |= CMD_ASE;
- ehci_writel(ehci, ehci->command, &ehci->regs->command);
- /* posted write need not be known to HC yet ... */
- }
- }
-
/* clear halt and/or toggle; and maybe recover from silicon quirk */
qh_refresh(ehci, qh);
/* splice right after start */
+ head = ehci->async;
qh->qh_next = head->qh_next;
qh->hw->hw_next = head->hw->hw_next;
wmb ();
@@ -1003,10 +1010,11 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
head->qh_next.qh = qh;
head->hw->hw_next = dma;
- qh_get(qh);
qh->xacterrs = 0;
qh->qh_state = QH_STATE_LINKED;
/* qtd completions reported later by interrupt */
+
+ enable_async(ehci);
}
/*-------------------------------------------------------------------------*/
@@ -1090,7 +1098,7 @@ static struct ehci_qh *qh_append_tds (
wmb ();
dummy->hw_token = token;
- urb->hcpriv = qh_get (qh);
+ urb->hcpriv = qh;
}
}
return qh;
@@ -1155,117 +1163,155 @@ submit_async (
/*-------------------------------------------------------------------------*/
-/* the async qh for the qtds being reclaimed are now unlinked from the HC */
-
-static void end_unlink_async (struct ehci_hcd *ehci)
+static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- struct ehci_qh *qh = ehci->reclaim;
- struct ehci_qh *next;
+ struct ehci_qh *prev;
- iaa_watchdog_done(ehci);
+ /* Add to the end of the list of QHs waiting for the next IAAD */
+ qh->qh_state = QH_STATE_UNLINK;
+ if (ehci->async_unlink)
+ ehci->async_unlink_last->unlink_next = qh;
+ else
+ ehci->async_unlink = qh;
+ ehci->async_unlink_last = qh;
- // qh->hw_next = cpu_to_hc32(qh->qh_dma);
- qh->qh_state = QH_STATE_IDLE;
- qh->qh_next.qh = NULL;
- qh_put (qh); // refcount from reclaim
+ /* Unlink it from the schedule */
+ prev = ehci->async;
+ while (prev->qh_next.qh != qh)
+ prev = prev->qh_next.qh;
- /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
- next = qh->reclaim;
- ehci->reclaim = next;
- qh->reclaim = NULL;
+ prev->hw->hw_next = qh->hw->hw_next;
+ prev->qh_next = qh->qh_next;
+ if (ehci->qh_scan_next == qh)
+ ehci->qh_scan_next = qh->qh_next.qh;
+}
- qh_completions (ehci, qh);
+static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested)
+{
+ /*
+ * Do nothing if an IAA cycle is already running or
+ * if one will be started shortly.
+ */
+ if (ehci->async_iaa || ehci->async_unlinking)
+ return;
- if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) {
- qh_link_async (ehci, qh);
- } else {
- /* it's not free to turn the async schedule on/off; leave it
- * active but idle for a while once it empties.
- */
- if (ehci->rh_state == EHCI_RH_RUNNING
- && ehci->async->qh_next.qh == NULL)
- timer_action (ehci, TIMER_ASYNC_OFF);
- }
- qh_put(qh); /* refcount from async list */
+ /* Do all the waiting QHs at once */
+ ehci->async_iaa = ehci->async_unlink;
+ ehci->async_unlink = NULL;
- if (next) {
- ehci->reclaim = NULL;
- start_unlink_async (ehci, next);
+ /* If the controller isn't running, we don't have to wait for it */
+ if (unlikely(ehci->rh_state < EHCI_RH_RUNNING)) {
+ if (!nested) /* Avoid recursion */
+ end_unlink_async(ehci);
+
+ /* Otherwise start a new IAA cycle */
+ } else if (likely(ehci->rh_state == EHCI_RH_RUNNING)) {
+ /* Make sure the unlinks are all visible to the hardware */
+ wmb();
+
+ ehci_writel(ehci, ehci->command | CMD_IAAD,
+ &ehci->regs->command);
+ ehci_readl(ehci, &ehci->regs->command);
+ ehci_enable_event(ehci, EHCI_HRTIMER_IAA_WATCHDOG, true);
}
+}
+
+/* the async qh for the qtds being unlinked are now gone from the HC */
+
+static void end_unlink_async(struct ehci_hcd *ehci)
+{
+ struct ehci_qh *qh;
if (ehci->has_synopsys_hc_bug)
ehci_writel(ehci, (u32) ehci->async->qh_dma,
&ehci->regs->async_next);
-}
-
-/* makes sure the async qh will become idle */
-/* caller must own ehci->lock */
-static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
-{
- struct ehci_qh *prev;
+ /* 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;
+
+ qh->qh_state = QH_STATE_IDLE;
+ qh->qh_next.qh = NULL;
+
+ 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;
-#ifdef DEBUG
- assert_spin_locked(&ehci->lock);
- if (ehci->reclaim
- || (qh->qh_state != QH_STATE_LINKED
- && qh->qh_state != QH_STATE_UNLINK_WAIT)
- )
- BUG ();
-#endif
+ /* 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;
+ }
+}
- /* stop async schedule right now? */
- if (unlikely (qh == ehci->async)) {
- /* can't get here without STS_ASS set */
- if (ehci->rh_state != EHCI_RH_HALTED
- && !ehci->reclaim) {
- /* ... and CMD_IAAD clear */
- ehci->command &= ~CMD_ASE;
- ehci_writel(ehci, ehci->command, &ehci->regs->command);
- wmb ();
- // handshake later, if we need to
- timer_action_done (ehci, TIMER_ASYNC_OFF);
+static void unlink_empty_async(struct ehci_hcd *ehci)
+{
+ struct ehci_qh *qh, *next;
+ bool stopped = (ehci->rh_state < EHCI_RH_RUNNING);
+ bool check_unlinks_later = false;
+
+ /* Unlink all the async QHs that have been empty for a timer cycle */
+ next = ehci->async->qh_next.qh;
+ while (next) {
+ qh = next;
+ next = qh->qh_next.qh;
+
+ if (list_empty(&qh->qtd_list) &&
+ qh->qh_state == QH_STATE_LINKED) {
+ if (!stopped && qh->unlink_cycle ==
+ ehci->async_unlink_cycle)
+ check_unlinks_later = true;
+ else
+ single_unlink_async(ehci, qh);
}
- return;
}
- qh->qh_state = QH_STATE_UNLINK;
- ehci->reclaim = qh = qh_get (qh);
+ /* Start a new IAA cycle if any QHs are waiting for it */
+ if (ehci->async_unlink)
+ start_iaa_cycle(ehci, false);
- prev = ehci->async;
- while (prev->qh_next.qh != qh)
- prev = prev->qh_next.qh;
+ /* QHs that haven't been empty for long enough will be handled later */
+ if (check_unlinks_later) {
+ ehci_enable_event(ehci, EHCI_HRTIMER_ASYNC_UNLINKS, true);
+ ++ehci->async_unlink_cycle;
+ }
+}
- prev->hw->hw_next = qh->hw->hw_next;
- prev->qh_next = qh->qh_next;
- if (ehci->qh_scan_next == qh)
- ehci->qh_scan_next = qh->qh_next.qh;
- wmb ();
+/* makes sure the async qh will become idle */
+/* caller must own ehci->lock */
- /* If the controller isn't running, we don't have to wait for it */
- if (unlikely(ehci->rh_state != EHCI_RH_RUNNING)) {
- /* if (unlikely (qh->reclaim != 0))
- * this will recurse, probably not much
- */
- end_unlink_async (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;
return;
}
- ehci_writel(ehci, ehci->command | CMD_IAAD, &ehci->regs->command);
- (void)ehci_readl(ehci, &ehci->regs->command);
- iaa_watchdog_start(ehci);
+ single_unlink_async(ehci, qh);
+ start_iaa_cycle(ehci, false);
}
/*-------------------------------------------------------------------------*/
static void scan_async (struct ehci_hcd *ehci)
{
- bool stopped;
struct ehci_qh *qh;
- enum ehci_timer_action action = TIMER_IO_WATCHDOG;
-
- timer_action_done (ehci, TIMER_ASYNC_SHRINK);
- stopped = (ehci->rh_state != EHCI_RH_RUNNING);
+ bool check_unlinks_later = false;
ehci->qh_scan_next = ehci->async->qh_next.qh;
while (ehci->qh_scan_next) {
@@ -1281,33 +1327,30 @@ static void scan_async (struct ehci_hcd *ehci)
* drops the lock. That's why ehci->qh_scan_next
* always holds the next qh to scan; if the next qh
* gets unlinked then ehci->qh_scan_next is adjusted
- * in start_unlink_async().
+ * in single_unlink_async().
*/
- qh = qh_get(qh);
temp = qh_completions(ehci, qh);
- if (qh->needs_rescan)
- unlink_async(ehci, qh);
- qh->unlink_time = jiffies + EHCI_SHRINK_JIFFIES;
- qh_put(qh);
- if (temp != 0)
+ if (qh->needs_rescan) {
+ 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;
}
+ }
- /* unlink idle entries, reducing DMA usage as well
- * as HCD schedule-scanning costs. delay for any qh
- * we just scanned, there's a not-unusual case that it
- * doesn't stay idle for long.
- * (plus, avoids some kind of re-activation race.)
- */
- if (list_empty(&qh->qtd_list)
- && qh->qh_state == QH_STATE_LINKED) {
- if (!ehci->reclaim && (stopped ||
- time_after_eq(jiffies, qh->unlink_time)))
- start_unlink_async(ehci, qh);
- else
- action = TIMER_ASYNC_SHRINK;
- }
+ /*
+ * Unlink empty entries, reducing DMA usage as well
+ * as HCD schedule-scanning costs. Delay for any qh
+ * we just scanned, there's a not-unusual case that it
+ * doesn't stay idle for long.
+ */
+ if (check_unlinks_later && ehci->rh_state == EHCI_RH_RUNNING &&
+ !(ehci->enabled_hrtimer_events &
+ BIT(EHCI_HRTIMER_ASYNC_UNLINKS))) {
+ ehci_enable_event(ehci, EHCI_HRTIMER_ASYNC_UNLINKS, true);
+ ++ehci->async_unlink_cycle;
}
- if (action == TIMER_ASYNC_SHRINK)
- timer_action (ehci, TIMER_ASYNC_SHRINK);
}
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index c474cec..9d8f1dd 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -13,7 +13,9 @@
*/
#include <linux/clk.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/of_gpio.h>
#include <plat/ehci.h>
#include <plat/usb-phy.h>
@@ -40,7 +42,7 @@ static const struct hc_driver s5p_ehci_hc_driver = {
.irq = ehci_irq,
.flags = HCD_MEMORY | HCD_USB2,
- .reset = ehci_init,
+ .reset = ehci_setup,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
@@ -63,6 +65,26 @@ static const struct hc_driver s5p_ehci_hc_driver = {
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
+static void s5p_setup_vbus_gpio(struct platform_device *pdev)
+{
+ int err;
+ int gpio;
+
+ if (!pdev->dev.of_node)
+ return;
+
+ gpio = of_get_named_gpio(pdev->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");
+ if (err)
+ dev_err(&pdev->dev, "can't request ehci vbus gpio %d", gpio);
+}
+
+static u64 ehci_s5p_dma_mask = DMA_BIT_MASK(32);
+
static int __devinit s5p_ehci_probe(struct platform_device *pdev)
{
struct s5p_ehci_platdata *pdata;
@@ -79,7 +101,20 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
return -EINVAL;
}
- s5p_ehci = kzalloc(sizeof(struct s5p_ehci_hcd), GFP_KERNEL);
+ /*
+ * 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 move to full device tree support this will vanish off.
+ */
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &ehci_s5p_dma_mask;
+ if (!pdev->dev.coherent_dma_mask)
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+ s5p_setup_vbus_gpio(pdev);
+
+ s5p_ehci = devm_kzalloc(&pdev->dev, sizeof(struct s5p_ehci_hcd),
+ GFP_KERNEL);
if (!s5p_ehci)
return -ENOMEM;
@@ -89,8 +124,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
dev_name(&pdev->dev));
if (!hcd) {
dev_err(&pdev->dev, "Unable to create HCD\n");
- err = -ENOMEM;
- goto fail_hcd;
+ return -ENOMEM;
}
s5p_ehci->hcd = hcd;
@@ -115,7 +149,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
- hcd->regs = ioremap(res->start, resource_size(res));
+ hcd->regs = devm_ioremap(&pdev->dev, res->start, hcd->rsrc_len);
if (!hcd->regs) {
dev_err(&pdev->dev, "Failed to remap I/O memory\n");
err = -ENOMEM;
@@ -126,7 +160,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
if (!irq) {
dev_err(&pdev->dev, "Failed to get IRQ\n");
err = -ENODEV;
- goto fail;
+ goto fail_io;
}
if (pdata->phy_init)
@@ -134,40 +168,26 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
ehci = hcd_to_ehci(hcd);
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs +
- HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
/* DMA burst Enable */
writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
- dbg_hcs_params(ehci, "reset");
- dbg_hcc_params(ehci, "reset");
-
- /* cache this readonly data; minimize chip reads */
- ehci->hcs_params = readl(&ehci->caps->hcs_params);
-
- ehci_reset(ehci);
-
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err) {
dev_err(&pdev->dev, "Failed to add USB HCD\n");
- goto fail;
+ goto fail_io;
}
platform_set_drvdata(pdev, s5p_ehci);
return 0;
-fail:
- iounmap(hcd->regs);
fail_io:
clk_disable(s5p_ehci->clk);
fail_clken:
clk_put(s5p_ehci->clk);
fail_clk:
usb_put_hcd(hcd);
-fail_hcd:
- kfree(s5p_ehci);
return err;
}
@@ -182,13 +202,10 @@ static int __devexit s5p_ehci_remove(struct platform_device *pdev)
if (pdata && pdata->phy_exit)
pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
- iounmap(hcd->regs);
-
clk_disable(s5p_ehci->clk);
clk_put(s5p_ehci->clk);
usb_put_hcd(hcd);
- kfree(s5p_ehci);
return 0;
}
@@ -207,27 +224,12 @@ static int s5p_ehci_suspend(struct device *dev)
{
struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
struct usb_hcd *hcd = s5p_ehci->hcd;
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ bool do_wakeup = device_may_wakeup(dev);
struct platform_device *pdev = to_platform_device(dev);
struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
- unsigned long flags;
- int rc = 0;
-
- if (time_before(jiffies, ehci->next_statechange))
- msleep(20);
-
- /*
- * Root hub was already suspended. Disable irq emission and
- * mark HW unaccessible. The PM and USB cores make sure that
- * the root hub is either suspended or stopped.
- */
- ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
- spin_lock_irqsave(&ehci->lock, flags);
- ehci_writel(ehci, 0, &ehci->regs->intr_enable);
- (void)ehci_readl(ehci, &ehci->regs->intr_enable);
+ int rc;
- clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- spin_unlock_irqrestore(&ehci->lock, flags);
+ rc = ehci_suspend(hcd, do_wakeup);
if (pdata && pdata->phy_exit)
pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
@@ -241,7 +243,6 @@ static int s5p_ehci_resume(struct device *dev)
{
struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
struct usb_hcd *hcd = s5p_ehci->hcd;
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct platform_device *pdev = to_platform_device(dev);
struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
@@ -253,44 +254,7 @@ static int s5p_ehci_resume(struct device *dev)
/* DMA burst Enable */
writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
- if (time_before(jiffies, ehci->next_statechange))
- msleep(100);
-
- /* Mark hardware accessible again as we are out of D3 state by now */
- set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
- if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
- int mask = INTR_MASK;
-
- ehci_prepare_ports_for_controller_resume(ehci);
- if (!hcd->self.root_hub->do_remote_wakeup)
- mask &= ~STS_PCD;
- ehci_writel(ehci, mask, &ehci->regs->intr_enable);
- ehci_readl(ehci, &ehci->regs->intr_enable);
- return 0;
- }
-
- usb_root_hub_lost_power(hcd->self.root_hub);
-
- (void) ehci_halt(ehci);
- (void) ehci_reset(ehci);
-
- /* emptying the schedule aborts any urbs */
- spin_lock_irq(&ehci->lock);
- if (ehci->reclaim)
- end_unlink_async(ehci);
- ehci_work(ehci);
- spin_unlock_irq(&ehci->lock);
-
- ehci_writel(ehci, ehci->command, &ehci->regs->command);
- ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
- ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
-
- /* here we "know" root ports should always stay powered */
- ehci_port_power(ehci, 1);
-
- ehci->rh_state = EHCI_RH_SUSPENDED;
-
+ ehci_resume(hcd, false);
return 0;
}
#else
@@ -303,6 +267,14 @@ static const struct dev_pm_ops s5p_ehci_pm_ops = {
.resume = s5p_ehci_resume,
};
+#ifdef CONFIG_OF
+static const struct of_device_id exynos_ehci_match[] = {
+ { .compatible = "samsung,exynos-ehci" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, exynos_ehci_match);
+#endif
+
static struct platform_driver s5p_ehci_driver = {
.probe = s5p_ehci_probe,
.remove = __devexit_p(s5p_ehci_remove),
@@ -311,6 +283,7 @@ static struct platform_driver s5p_ehci_driver = {
.name = "s5p-ehci",
.owner = THIS_MODULE,
.pm = &s5p_ehci_pm_ops,
+ .of_match_table = of_match_ptr(exynos_ehci_match),
}
};
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 33182c6..7cf3da7 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -479,70 +479,26 @@ static int tt_no_collision (
/*-------------------------------------------------------------------------*/
-static int enable_periodic (struct ehci_hcd *ehci)
+static void enable_periodic(struct ehci_hcd *ehci)
{
- int status;
-
- if (ehci->periodic_sched++)
- return 0;
-
- /* did clearing PSE did take effect yet?
- * takes effect only at frame boundaries...
- */
- status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
- STS_PSS, 0, 9 * 125);
- if (status) {
- usb_hc_died(ehci_to_hcd(ehci));
- return status;
- }
+ if (ehci->periodic_count++)
+ return;
- ehci->command |= CMD_PSE;
- ehci_writel(ehci, ehci->command, &ehci->regs->command);
- /* posted write ... PSS happens later */
+ /* Stop waiting to turn off the periodic schedule */
+ ehci->enabled_hrtimer_events &= ~BIT(EHCI_HRTIMER_DISABLE_PERIODIC);
- /* make sure ehci_work scans these */
- ehci->next_uframe = ehci_read_frame_index(ehci)
- % (ehci->periodic_size << 3);
- if (unlikely(ehci->broken_periodic))
- ehci->last_periodic_enable = ktime_get_real();
- return 0;
+ /* Don't start the schedule until PSS is 0 */
+ ehci_poll_PSS(ehci);
+ turn_on_io_watchdog(ehci);
}
-static int disable_periodic (struct ehci_hcd *ehci)
+static void disable_periodic(struct ehci_hcd *ehci)
{
- int status;
-
- if (--ehci->periodic_sched)
- return 0;
-
- if (unlikely(ehci->broken_periodic)) {
- /* delay experimentally determined */
- ktime_t safe = ktime_add_us(ehci->last_periodic_enable, 1000);
- ktime_t now = ktime_get_real();
- s64 delay = ktime_us_delta(safe, now);
-
- if (unlikely(delay > 0))
- udelay(delay);
- }
-
- /* did setting PSE not take effect yet?
- * takes effect only at frame boundaries...
- */
- status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
- STS_PSS, STS_PSS, 9 * 125);
- if (status) {
- usb_hc_died(ehci_to_hcd(ehci));
- return status;
- }
-
- ehci->command &= ~CMD_PSE;
- ehci_writel(ehci, ehci->command, &ehci->regs->command);
- /* posted write ... */
-
- free_cached_lists(ehci);
+ if (--ehci->periodic_count)
+ return;
- ehci->next_uframe = -1;
- return 0;
+ /* Don't turn off the schedule until PSS is 1 */
+ ehci_poll_PSS(ehci);
}
/*-------------------------------------------------------------------------*/
@@ -553,7 +509,7 @@ static int disable_periodic (struct ehci_hcd *ehci)
* this just links in a qh; caller guarantees uframe masks are set right.
* no FSTN support (yet; ehci 0.96+)
*/
-static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
+static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
{
unsigned i;
unsigned period = qh->period;
@@ -606,28 +562,38 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
}
qh->qh_state = QH_STATE_LINKED;
qh->xacterrs = 0;
- qh_get (qh);
/* update per-qh bandwidth for usbfs */
ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->period
? ((qh->usecs + qh->c_usecs) / qh->period)
: (qh->usecs * 8);
+ list_add(&qh->intr_node, &ehci->intr_qh_list);
+
/* maybe enable periodic schedule processing */
- return enable_periodic(ehci);
+ ++ehci->intr_count;
+ enable_periodic(ehci);
}
-static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
+static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
{
unsigned i;
unsigned period;
- // FIXME:
- // IF this isn't high speed
- // and this qh is active in the current uframe
- // (and overlay token SplitXstate is false?)
- // THEN
- // qh->hw_info1 |= cpu_to_hc32(1 << 7 /* "ignore" */);
+ /*
+ * If qh is for a low/full-speed device, simply unlinking it
+ * could interfere with an ongoing split transaction. To unlink
+ * it safely would require setting the QH_INACTIVATE bit and
+ * waiting at least one frame, as described in EHCI 4.12.2.5.
+ *
+ * We won't bother with any of this. Instead, we assume that the
+ * only reason for unlinking an interrupt QH while the current URB
+ * is still active is to dequeue all the URBs (flush the whole
+ * endpoint queue).
+ *
+ * If rebalancing the periodic schedule is ever implemented, this
+ * approach will no longer be valid.
+ */
/* high bandwidth, or otherwise part of every microframe */
if ((period = qh->period) == 0)
@@ -650,18 +616,15 @@ static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
/* qh->qh_next still "live" to HC */
qh->qh_state = QH_STATE_UNLINK;
qh->qh_next.ptr = NULL;
- qh_put (qh);
- /* maybe turn off periodic schedule */
- return disable_periodic(ehci);
+ if (ehci->qh_scan_next == qh)
+ ehci->qh_scan_next = list_entry(qh->intr_node.next,
+ struct ehci_qh, intr_node);
+ list_del(&qh->intr_node);
}
-static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
+static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- unsigned wait;
- struct ehci_qh_hw *hw = qh->hw;
- int rc;
-
/* 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.
@@ -674,28 +637,45 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
qh_unlink_periodic (ehci, qh);
- /* simple/paranoid: always delay, expecting the HC needs to read
- * qh->hw_next or finish a writeback after SPLIT/CSPLIT ... and
- * expect khubd to clean up after any CSPLITs we won't issue.
- * active high speed queues may need bigger delays...
+ /* Make sure the unlinks are visible before starting the timer */
+ wmb();
+
+ /*
+ * The EHCI spec doesn't say how long it takes the controller to
+ * stop accessing an unlinked interrupt QH. The timer delay is
+ * 9 uframes; presumably that will be long enough.
*/
- if (list_empty (&qh->qtd_list)
- || (cpu_to_hc32(ehci, QH_CMASK)
- & hw->hw_info2) != 0)
- wait = 2;
+ 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
- wait = 55; /* worst case: 3 * 1024 */
+ ehci->intr_unlink = qh;
+ ehci->intr_unlink_last = qh;
+
+ 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) {
+ ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true);
+ ++ehci->intr_unlink_cycle;
+ }
+}
+
+static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+ struct ehci_qh_hw *hw = qh->hw;
+ int rc;
- udelay (wait);
qh->qh_state = QH_STATE_IDLE;
hw->hw_next = EHCI_LIST_END(ehci);
- wmb ();
qh_completions(ehci, qh);
/* reschedule QH iff another request is queued */
- if (!list_empty(&qh->qtd_list) &&
- ehci->rh_state == EHCI_RH_RUNNING) {
+ if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) {
rc = qh_schedule(ehci, qh);
/* An error here likely indicates handshake failure
@@ -708,6 +688,10 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
ehci_err(ehci, "can't reschedule qh %p, err %d\n",
qh, rc);
}
+
+ /* maybe turn off periodic schedule */
+ --ehci->intr_count;
+ disable_periodic(ehci);
}
/*-------------------------------------------------------------------------*/
@@ -884,7 +868,7 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
ehci_dbg (ehci, "reused qh %p schedule\n", qh);
/* stuff into the periodic schedule */
- status = qh_link_periodic (ehci, qh);
+ qh_link_periodic(ehci, qh);
done:
return status;
}
@@ -944,6 +928,35 @@ done_not_linked:
return status;
}
+static void scan_intr(struct ehci_hcd *ehci)
+{
+ struct ehci_qh *qh;
+
+ 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;
+
+ /*
+ * Unlinks could happen here; completion reporting
+ * drops the lock. That's why ehci->qh_scan_next
+ * always holds the next qh to scan; if the next qh
+ * gets unlinked then ehci->qh_scan_next is adjusted
+ * 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)))
+ start_unlink_intr(ehci, qh);
+ else if (temp != 0)
+ goto rescan;
+ }
+ }
+}
+
/*-------------------------------------------------------------------------*/
/* ehci_iso_stream ops work with both ITD and SITD */
@@ -958,7 +971,6 @@ iso_stream_alloc (gfp_t mem_flags)
INIT_LIST_HEAD(&stream->td_list);
INIT_LIST_HEAD(&stream->free_list);
stream->next_uframe = -1;
- stream->refcount = 1;
}
return stream;
}
@@ -1058,57 +1070,6 @@ iso_stream_init (
stream->maxp = maxp;
}
-static void
-iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream)
-{
- stream->refcount--;
-
- /* free whenever just a dev->ep reference remains.
- * not like a QH -- no persistent state (toggle, halt)
- */
- if (stream->refcount == 1) {
- // BUG_ON (!list_empty(&stream->td_list));
-
- while (!list_empty (&stream->free_list)) {
- struct list_head *entry;
-
- entry = stream->free_list.next;
- list_del (entry);
-
- /* knows about ITD vs SITD */
- if (stream->highspeed) {
- struct ehci_itd *itd;
-
- itd = list_entry (entry, struct ehci_itd,
- itd_list);
- dma_pool_free (ehci->itd_pool, itd,
- itd->itd_dma);
- } else {
- struct ehci_sitd *sitd;
-
- sitd = list_entry (entry, struct ehci_sitd,
- sitd_list);
- dma_pool_free (ehci->sitd_pool, sitd,
- sitd->sitd_dma);
- }
- }
-
- stream->bEndpointAddress &= 0x0f;
- if (stream->ep)
- stream->ep->hcpriv = NULL;
-
- kfree(stream);
- }
-}
-
-static inline struct ehci_iso_stream *
-iso_stream_get (struct ehci_iso_stream *stream)
-{
- if (likely (stream != NULL))
- stream->refcount++;
- return stream;
-}
-
static struct ehci_iso_stream *
iso_stream_find (struct ehci_hcd *ehci, struct urb *urb)
{
@@ -1129,7 +1090,6 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb)
if (unlikely (stream == NULL)) {
stream = iso_stream_alloc(GFP_ATOMIC);
if (likely (stream != NULL)) {
- /* dev->ep owns the initial refcount */
ep->hcpriv = stream;
stream->ep = ep;
iso_stream_init(ehci, stream, urb->dev, urb->pipe,
@@ -1144,9 +1104,6 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb)
stream = NULL;
}
- /* caller guarantees an eventual matching iso_stream_put */
- stream = iso_stream_get (stream);
-
spin_unlock_irqrestore (&ehci->lock, flags);
return stream;
}
@@ -1254,17 +1211,19 @@ itd_urb_transaction (
spin_lock_irqsave (&ehci->lock, flags);
for (i = 0; i < num_itds; i++) {
- /* free_list.next might be cache-hot ... but maybe
- * the HC caches it too. avoid that issue for now.
+ /*
+ * Use iTDs from the free list, but not iTDs that may
+ * still be in use by the hardware.
*/
-
- /* prefer previously-allocated itds */
- if (likely (!list_empty(&stream->free_list))) {
- itd = list_entry (stream->free_list.prev,
+ if (likely(!list_empty(&stream->free_list))) {
+ itd = list_first_entry(&stream->free_list,
struct ehci_itd, itd_list);
+ if (itd->frame == ehci->now_frame)
+ goto alloc_itd;
list_del (&itd->itd_list);
itd_dma = itd->itd_dma;
} else {
+ alloc_itd:
spin_unlock_irqrestore (&ehci->lock, flags);
itd = dma_pool_alloc (ehci->itd_pool, mem_flags,
&itd_dma);
@@ -1528,6 +1487,10 @@ iso_stream_schedule (
urb->start_frame = stream->next_uframe;
if (!stream->highspeed)
urb->start_frame >>= 3;
+
+ /* Make sure scan_isoc() sees these */
+ if (ehci->isoc_count == 0)
+ ehci->next_frame = now >> 3;
return 0;
fail:
@@ -1615,8 +1578,7 @@ itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
}
/* fit urb's itds into the selected schedule slot; activate as needed */
-static int
-itd_link_urb (
+static void itd_link_urb(
struct ehci_hcd *ehci,
struct urb *urb,
unsigned mod,
@@ -1659,7 +1621,7 @@ itd_link_urb (
itd = list_entry (iso_sched->td_list.next,
struct ehci_itd, itd_list);
list_move_tail (&itd->itd_list, &stream->td_list);
- itd->stream = iso_stream_get (stream);
+ itd->stream = stream;
itd->urb = urb;
itd_init (ehci, stream, itd);
}
@@ -1686,8 +1648,8 @@ itd_link_urb (
iso_sched_free (stream, iso_sched);
urb->hcpriv = NULL;
- timer_action (ehci, TIMER_IO_WATCHDOG);
- return enable_periodic(ehci);
+ ++ehci->isoc_count;
+ enable_periodic(ehci);
}
#define ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
@@ -1702,11 +1664,8 @@ itd_link_urb (
* (b) only this endpoint's completions submit URBs. It seems some silicon
* corrupts things if you reuse completed descriptors very quickly...
*/
-static unsigned
-itd_complete (
- struct ehci_hcd *ehci,
- struct ehci_itd *itd
-) {
+static bool itd_complete(struct ehci_hcd *ehci, struct ehci_itd *itd)
+{
struct urb *urb = itd->urb;
struct usb_iso_packet_descriptor *desc;
u32 t;
@@ -1714,7 +1673,7 @@ itd_complete (
int urb_index = -1;
struct ehci_iso_stream *stream = itd->stream;
struct usb_device *dev;
- unsigned retval = false;
+ bool retval = false;
/* for each uframe with a packet */
for (uframe = 0; uframe < 8; uframe++) {
@@ -1767,9 +1726,11 @@ itd_complete (
ehci_urb_done(ehci, urb, 0);
retval = true;
urb = NULL;
- (void) disable_periodic(ehci);
- ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
+ --ehci->isoc_count;
+ disable_periodic(ehci);
+
+ ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
if (ehci->amd_pll_fix == 1)
usb_amd_quirk_pll_enable();
@@ -1783,28 +1744,20 @@ itd_complete (
dev->devpath, stream->bEndpointAddress & 0x0f,
(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
}
- iso_stream_put (ehci, stream);
done:
itd->urb = NULL;
- if (ehci->clock_frame != itd->frame || itd->index[7] != -1) {
- /* OK to recycle this ITD now. */
- itd->stream = NULL;
- list_move(&itd->itd_list, &stream->free_list);
- iso_stream_put(ehci, stream);
- } else {
- /* HW might remember this ITD, so we can't recycle it yet.
- * Move it to a safe place until a new frame starts.
- */
- list_move(&itd->itd_list, &ehci->cached_itd_list);
- if (stream->refcount == 2) {
- /* If iso_stream_put() were called here, stream
- * would be freed. Instead, just prevent reuse.
- */
- stream->ep->hcpriv = NULL;
- stream->ep = NULL;
- }
+
+ /* Add to the end of the free list for later reuse */
+ list_move_tail(&itd->itd_list, &stream->free_list);
+
+ /* Recycle the iTDs when the pipeline is empty (ep no longer in use) */
+ if (list_empty(&stream->td_list)) {
+ list_splice_tail_init(&stream->free_list,
+ &ehci->cached_itd_list);
+ start_free_itds(ehci);
}
+
return retval;
}
@@ -1861,12 +1814,9 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
else
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
-done_not_linked:
+ done_not_linked:
spin_unlock_irqrestore (&ehci->lock, flags);
-
-done:
- if (unlikely (status < 0))
- iso_stream_put (ehci, stream);
+ done:
return status;
}
@@ -1955,17 +1905,19 @@ sitd_urb_transaction (
* means we never need two sitds for full speed packets.
*/
- /* free_list.next might be cache-hot ... but maybe
- * the HC caches it too. avoid that issue for now.
+ /*
+ * Use siTDs from the free list, but not siTDs that may
+ * still be in use by the hardware.
*/
-
- /* prefer previously-allocated sitds */
- if (!list_empty(&stream->free_list)) {
- sitd = list_entry (stream->free_list.prev,
+ if (likely(!list_empty(&stream->free_list))) {
+ sitd = list_first_entry(&stream->free_list,
struct ehci_sitd, sitd_list);
+ if (sitd->frame == ehci->now_frame)
+ goto alloc_sitd;
list_del (&sitd->sitd_list);
sitd_dma = sitd->sitd_dma;
} else {
+ alloc_sitd:
spin_unlock_irqrestore (&ehci->lock, flags);
sitd = dma_pool_alloc (ehci->sitd_pool, mem_flags,
&sitd_dma);
@@ -2034,8 +1986,7 @@ sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
}
/* fit urb's sitds into the selected schedule slot; activate as needed */
-static int
-sitd_link_urb (
+static void sitd_link_urb(
struct ehci_hcd *ehci,
struct urb *urb,
unsigned mod,
@@ -2081,7 +2032,7 @@ sitd_link_urb (
sitd = list_entry (sched->td_list.next,
struct ehci_sitd, sitd_list);
list_move_tail (&sitd->sitd_list, &stream->td_list);
- sitd->stream = iso_stream_get (stream);
+ sitd->stream = stream;
sitd->urb = urb;
sitd_patch(ehci, stream, sitd, sched, packet);
@@ -2096,8 +2047,8 @@ sitd_link_urb (
iso_sched_free (stream, sched);
urb->hcpriv = NULL;
- timer_action (ehci, TIMER_IO_WATCHDOG);
- return enable_periodic(ehci);
+ ++ehci->isoc_count;
+ enable_periodic(ehci);
}
/*-------------------------------------------------------------------------*/
@@ -2115,18 +2066,15 @@ sitd_link_urb (
* (b) only this endpoint's completions submit URBs. It seems some silicon
* corrupts things if you reuse completed descriptors very quickly...
*/
-static unsigned
-sitd_complete (
- struct ehci_hcd *ehci,
- struct ehci_sitd *sitd
-) {
+static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd)
+{
struct urb *urb = sitd->urb;
struct usb_iso_packet_descriptor *desc;
u32 t;
int urb_index = -1;
struct ehci_iso_stream *stream = sitd->stream;
struct usb_device *dev;
- unsigned retval = false;
+ bool retval = false;
urb_index = sitd->index;
desc = &urb->iso_frame_desc [urb_index];
@@ -2163,9 +2111,11 @@ sitd_complete (
ehci_urb_done(ehci, urb, 0);
retval = true;
urb = NULL;
- (void) disable_periodic(ehci);
- ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
+ --ehci->isoc_count;
+ disable_periodic(ehci);
+
+ ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
if (ehci->amd_pll_fix == 1)
usb_amd_quirk_pll_enable();
@@ -2179,28 +2129,20 @@ sitd_complete (
dev->devpath, stream->bEndpointAddress & 0x0f,
(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
}
- iso_stream_put (ehci, stream);
done:
sitd->urb = NULL;
- if (ehci->clock_frame != sitd->frame) {
- /* OK to recycle this SITD now. */
- sitd->stream = NULL;
- list_move(&sitd->sitd_list, &stream->free_list);
- iso_stream_put(ehci, stream);
- } else {
- /* HW might remember this SITD, so we can't recycle it yet.
- * Move it to a safe place until a new frame starts.
- */
- list_move(&sitd->sitd_list, &ehci->cached_sitd_list);
- if (stream->refcount == 2) {
- /* If iso_stream_put() were called here, stream
- * would be freed. Instead, just prevent reuse.
- */
- stream->ep->hcpriv = NULL;
- stream->ep = NULL;
- }
+
+ /* Add to the end of the free list for later reuse */
+ list_move_tail(&sitd->sitd_list, &stream->free_list);
+
+ /* Recycle the siTDs when the pipeline is empty (ep no longer in use) */
+ if (list_empty(&stream->td_list)) {
+ list_splice_tail_init(&stream->free_list,
+ &ehci->cached_sitd_list);
+ start_free_itds(ehci);
}
+
return retval;
}
@@ -2254,74 +2196,39 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
else
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
-done_not_linked:
+ done_not_linked:
spin_unlock_irqrestore (&ehci->lock, flags);
-
-done:
- if (status < 0)
- iso_stream_put (ehci, stream);
+ done:
return status;
}
/*-------------------------------------------------------------------------*/
-static void free_cached_lists(struct ehci_hcd *ehci)
+static void scan_isoc(struct ehci_hcd *ehci)
{
- struct ehci_itd *itd, *n;
- struct ehci_sitd *sitd, *sn;
-
- list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) {
- struct ehci_iso_stream *stream = itd->stream;
- itd->stream = NULL;
- list_move(&itd->itd_list, &stream->free_list);
- iso_stream_put(ehci, stream);
- }
-
- list_for_each_entry_safe(sitd, sn, &ehci->cached_sitd_list, sitd_list) {
- struct ehci_iso_stream *stream = sitd->stream;
- sitd->stream = NULL;
- list_move(&sitd->sitd_list, &stream->free_list);
- iso_stream_put(ehci, stream);
- }
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void
-scan_periodic (struct ehci_hcd *ehci)
-{
- unsigned now_uframe, frame, clock, clock_frame, mod;
- unsigned modified;
-
- mod = ehci->periodic_size << 3;
+ unsigned uf, now_frame, frame;
+ unsigned fmask = ehci->periodic_size - 1;
+ bool modified, live;
/*
* When running, scan from last scan point up to "now"
* else clean up by scanning everything that's left.
* Touches as few pages as possible: cache-friendly.
*/
- now_uframe = ehci->next_uframe;
- if (ehci->rh_state == EHCI_RH_RUNNING) {
- clock = ehci_read_frame_index(ehci);
- clock_frame = (clock >> 3) & (ehci->periodic_size - 1);
+ if (ehci->rh_state >= EHCI_RH_RUNNING) {
+ uf = ehci_read_frame_index(ehci);
+ now_frame = (uf >> 3) & fmask;
+ live = true;
} else {
- clock = now_uframe + mod - 1;
- clock_frame = -1;
+ now_frame = (ehci->next_frame - 1) & fmask;
+ live = false;
}
- if (ehci->clock_frame != clock_frame) {
- free_cached_lists(ehci);
- ehci->clock_frame = clock_frame;
- }
- clock &= mod - 1;
- clock_frame = clock >> 3;
- ++ehci->periodic_stamp;
+ ehci->now_frame = now_frame;
+ frame = ehci->next_frame;
for (;;) {
union ehci_shadow q, *q_p;
__hc32 type, *hw_p;
- unsigned incomplete = false;
-
- frame = now_uframe >> 3;
restart:
/* scan each element in frame's queue for completions */
@@ -2329,48 +2236,17 @@ restart:
hw_p = &ehci->periodic [frame];
q.ptr = q_p->ptr;
type = Q_NEXT_TYPE(ehci, *hw_p);
- modified = 0;
+ modified = false;
while (q.ptr != NULL) {
- unsigned uf;
- union ehci_shadow temp;
- int live;
-
- live = (ehci->rh_state == EHCI_RH_RUNNING);
switch (hc32_to_cpu(ehci, type)) {
- case Q_TYPE_QH:
- /* handle any completions */
- temp.qh = qh_get (q.qh);
- type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next);
- q = q.qh->qh_next;
- if (temp.qh->stamp != ehci->periodic_stamp) {
- modified = qh_completions(ehci, temp.qh);
- if (!modified)
- temp.qh->stamp = ehci->periodic_stamp;
- if (unlikely(list_empty(&temp.qh->qtd_list) ||
- temp.qh->needs_rescan))
- intr_deschedule(ehci, temp.qh);
- }
- qh_put (temp.qh);
- break;
- case Q_TYPE_FSTN:
- /* for "save place" FSTNs, look at QH entries
- * in the previous frame for completions.
- */
- if (q.fstn->hw_prev != EHCI_LIST_END(ehci)) {
- ehci_dbg(ehci,
- "ignoring completions from FSTNs\n");
- }
- type = Q_NEXT_TYPE(ehci, q.fstn->hw_next);
- q = q.fstn->fstn_next;
- break;
case Q_TYPE_ITD:
/* If this ITD is still active, leave it for
* later processing ... check the next entry.
* No need to check for activity unless the
* frame is current.
*/
- if (frame == clock_frame && live) {
+ if (frame == now_frame && live) {
rmb();
for (uf = 0; uf < 8; uf++) {
if (q.itd->hw_transaction[uf] &
@@ -2378,7 +2254,6 @@ restart:
break;
}
if (uf < 8) {
- incomplete = true;
q_p = &q.itd->itd_next;
hw_p = &q.itd->hw_next;
type = Q_NEXT_TYPE(ehci,
@@ -2410,14 +2285,12 @@ restart:
* No need to check for activity unless the
* frame is current.
*/
- if (((frame == clock_frame) ||
- (((frame + 1) & (ehci->periodic_size - 1))
- == clock_frame))
+ if (((frame == now_frame) ||
+ (((frame + 1) & fmask) == now_frame))
&& live
&& (q.sitd->hw_results &
SITD_ACTIVE(ehci))) {
- incomplete = true;
q_p = &q.sitd->sitd_next;
hw_p = &q.sitd->hw_next;
type = Q_NEXT_TYPE(ehci,
@@ -2445,58 +2318,23 @@ restart:
ehci_dbg(ehci, "corrupt type %d frame %d shadow %p\n",
type, frame, q.ptr);
// BUG ();
+ /* FALL THROUGH */
+ case Q_TYPE_QH:
+ case Q_TYPE_FSTN:
+ /* End of the iTDs and siTDs */
q.ptr = NULL;
+ break;
}
/* assume completion callbacks modify the queue */
- if (unlikely (modified)) {
- if (likely(ehci->periodic_sched > 0))
- goto restart;
- /* short-circuit this scan */
- now_uframe = clock;
- break;
- }
+ if (unlikely(modified && ehci->isoc_count > 0))
+ goto restart;
}
- /* If we can tell we caught up to the hardware, stop now.
- * We can't advance our scan without collecting the ISO
- * transfers that are still pending in this frame.
- */
- if (incomplete && ehci->rh_state == EHCI_RH_RUNNING) {
- ehci->next_uframe = now_uframe;
+ /* Stop when we have reached the current frame */
+ if (frame == now_frame)
break;
- }
-
- // FIXME: this assumes we won't get lapped when
- // latencies climb; that should be rare, but...
- // detect it, and just go all the way around.
- // FLR might help detect this case, so long as latencies
- // don't exceed periodic_size msec (default 1.024 sec).
-
- // FIXME: likewise assumes HC doesn't halt mid-scan
-
- if (now_uframe == clock) {
- unsigned now;
-
- if (ehci->rh_state != EHCI_RH_RUNNING
- || ehci->periodic_sched == 0)
- break;
- ehci->next_uframe = now_uframe;
- now = ehci_read_frame_index(ehci) & (mod - 1);
- if (now_uframe == now)
- break;
-
- /* rescan the rest of this frame, then ... */
- clock = now;
- clock_frame = clock >> 3;
- if (ehci->clock_frame != clock_frame) {
- free_cached_lists(ehci);
- ehci->clock_frame = clock_frame;
- ++ehci->periodic_stamp;
- }
- } else {
- now_uframe++;
- now_uframe &= mod - 1;
- }
+ frame = (frame + 1) & fmask;
}
+ ehci->next_frame = now_frame;
}
diff --git a/drivers/usb/host/ehci-sead3.c b/drivers/usb/host/ehci-sead3.c
index cc199e8..58c96bd 100644
--- a/drivers/usb/host/ehci-sead3.c
+++ b/drivers/usb/host/ehci-sead3.c
@@ -160,84 +160,16 @@ static int ehci_hcd_sead3_drv_remove(struct platform_device *pdev)
static int ehci_hcd_sead3_drv_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- unsigned long flags;
- int rc = 0;
-
- if (time_before(jiffies, ehci->next_statechange))
- msleep(20);
-
- /* Root hub was already suspended. Disable irq emission and
- * mark HW unaccessible. The PM and USB cores make sure that
- * the root hub is either suspended or stopped.
- */
- ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
- spin_lock_irqsave(&ehci->lock, flags);
- ehci_writel(ehci, 0, &ehci->regs->intr_enable);
- (void)ehci_readl(ehci, &ehci->regs->intr_enable);
-
- clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- spin_unlock_irqrestore(&ehci->lock, flags);
+ bool do_wakeup = device_may_wakeup(dev);
- /* could save FLADJ in case of Vaux power loss
- * ... we'd only use it to handle clock skew
- */
-
- return rc;
+ return ehci_suspend(hcd, do_wakeup);
}
static int ehci_hcd_sead3_drv_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-
- /* maybe restore FLADJ. */
-
- if (time_before(jiffies, ehci->next_statechange))
- msleep(100);
-
- /* Mark hardware accessible again as we are out of D3 state by now */
- set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
- /* If CF is still set, we maintained PCI Vaux power.
- * Just undo the effect of ehci_pci_suspend().
- */
- if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
- int mask = INTR_MASK;
-
- ehci_prepare_ports_for_controller_resume(ehci);
- if (!hcd->self.root_hub->do_remote_wakeup)
- mask &= ~STS_PCD;
- ehci_writel(ehci, mask, &ehci->regs->intr_enable);
- ehci_readl(ehci, &ehci->regs->intr_enable);
- return 0;
- }
-
- ehci_dbg(ehci, "lost power, restarting\n");
- usb_root_hub_lost_power(hcd->self.root_hub);
-
- /* Else reset, to cope with power loss or flush-to-storage
- * style "resume" having let BIOS kick in during reboot.
- */
- (void) ehci_halt(ehci);
- (void) ehci_reset(ehci);
-
- /* emptying the schedule aborts any urbs */
- spin_lock_irq(&ehci->lock);
- if (ehci->reclaim)
- end_unlink_async(ehci);
- ehci_work(ehci);
- spin_unlock_irq(&ehci->lock);
-
- ehci_writel(ehci, ehci->command, &ehci->regs->command);
- ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
- ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
-
- /* here we "know" root ports should always stay powered */
- ehci_port_power(ehci, 1);
-
- ehci->rh_state = EHCI_RH_SUSPENDED;
+ ehci_resume(hcd, false);
return 0;
}
diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c
index e7cb392..b3f1e36 100644
--- a/drivers/usb/host/ehci-sh.c
+++ b/drivers/usb/host/ehci-sh.c
@@ -24,25 +24,11 @@ static int ehci_sh_reset(struct usb_hcd *hcd)
int ret;
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
- &ehci->caps->hc_capbase));
- dbg_hcs_params(ehci, "reset");
- dbg_hcc_params(ehci, "reset");
-
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-
- ret = ehci_halt(ehci);
- if (unlikely(ret))
- return ret;
-
- ret = ehci_init(hcd);
+ ret = ehci_setup(hcd);
if (unlikely(ret))
return ret;
- ehci->sbrn = 0x20;
-
- ehci_reset(ehci);
ehci_port_power(ehci, 0);
return ret;
diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c
index 37ba8c8..c718a06 100644
--- a/drivers/usb/host/ehci-spear.c
+++ b/drivers/usb/host/ehci-spear.c
@@ -41,19 +41,11 @@ static int ehci_spear_setup(struct usb_hcd *hcd)
/* registers start at offset 0x0 */
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
- &ehci->caps->hc_capbase));
- /* cache this readonly data; minimize chip reads */
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
- retval = ehci_halt(ehci);
- if (retval)
- return retval;
- retval = ehci_init(hcd);
+ retval = ehci_setup(hcd);
if (retval)
return retval;
- ehci_reset(ehci);
ehci_port_power(ehci, 0);
return retval;
@@ -97,71 +89,16 @@ static const struct hc_driver ehci_spear_hc_driver = {
static int ehci_spear_drv_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- unsigned long flags;
- int rc = 0;
+ bool do_wakeup = device_may_wakeup(dev);
- if (time_before(jiffies, ehci->next_statechange))
- msleep(10);
-
- /*
- * Root hub was already suspended. Disable irq emission and mark HW
- * unaccessible. The PM and USB cores make sure that the root hub is
- * either suspended or stopped.
- */
- spin_lock_irqsave(&ehci->lock, flags);
- ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
- ehci_writel(ehci, 0, &ehci->regs->intr_enable);
- ehci_readl(ehci, &ehci->regs->intr_enable);
- spin_unlock_irqrestore(&ehci->lock, flags);
-
- return rc;
+ return ehci_suspend(hcd, do_wakeup);
}
static int ehci_spear_drv_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-
- if (time_before(jiffies, ehci->next_statechange))
- msleep(100);
-
- if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
- int mask = INTR_MASK;
-
- ehci_prepare_ports_for_controller_resume(ehci);
-
- if (!hcd->self.root_hub->do_remote_wakeup)
- mask &= ~STS_PCD;
-
- ehci_writel(ehci, mask, &ehci->regs->intr_enable);
- ehci_readl(ehci, &ehci->regs->intr_enable);
- return 0;
- }
-
- usb_root_hub_lost_power(hcd->self.root_hub);
-
- /*
- * Else reset, to cope with power loss or flush-to-storage style
- * "resume" having let BIOS kick in during reboot.
- */
- ehci_halt(ehci);
- ehci_reset(ehci);
-
- /* emptying the schedule aborts any urbs */
- spin_lock_irq(&ehci->lock);
- if (ehci->reclaim)
- end_unlink_async(ehci);
-
- ehci_work(ehci);
- spin_unlock_irq(&ehci->lock);
-
- ehci_writel(ehci, ehci->command, &ehci->regs->command);
- ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
- ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
- /* here we "know" root ports should always stay powered */
- ehci_port_power(ehci, 1);
+ ehci_resume(hcd, false);
return 0;
}
#endif /* CONFIG_PM */
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index ab8a3bf..950e95e 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -17,6 +17,7 @@
*/
#include <linux/clk.h>
+#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/platform_data/tegra_usb.h>
#include <linux/irq.h>
@@ -280,30 +281,14 @@ static int tegra_ehci_setup(struct usb_hcd *hcd)
/* EHCI registers start at offset 0x100 */
ehci->caps = hcd->regs + 0x100;
- ehci->regs = hcd->regs + 0x100 +
- HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
-
- dbg_hcs_params(ehci, "reset");
- dbg_hcc_params(ehci, "reset");
-
- /* cache this readonly data; minimize chip reads */
- ehci->hcs_params = readl(&ehci->caps->hcs_params);
/* switch to host mode */
hcd->has_tt = 1;
- ehci_reset(ehci);
-
- retval = ehci_halt(ehci);
- if (retval)
- return retval;
- /* data structure init */
- retval = ehci_init(hcd);
+ retval = ehci_setup(hcd);
if (retval)
return retval;
- ehci->sbrn = 0x20;
-
ehci_port_power(ehci, 1);
return retval;
}
@@ -460,12 +445,11 @@ static int controller_suspend(struct device *dev)
if (time_before(jiffies, ehci->next_statechange))
msleep(10);
- spin_lock_irqsave(&ehci->lock, flags);
+ ehci_halt(ehci);
+ spin_lock_irqsave(&ehci->lock, flags);
tegra->port_speed = (readl(&hw->port_status[0]) >> 26) & 0x3;
- ehci_halt(ehci);
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
spin_unlock_irqrestore(&ehci->lock, flags);
tegra_ehci_power_down(hcd);
@@ -749,8 +733,8 @@ static int tegra_ehci_probe(struct platform_device *pdev)
#ifdef CONFIG_USB_OTG_UTILS
if (pdata->operating_mode == TEGRA_USB_OTG) {
- tegra->transceiver = usb_get_transceiver();
- if (tegra->transceiver)
+ tegra->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+ if (!IS_ERR_OR_NULL(tegra->transceiver))
otg_set_host(tegra->transceiver->otg, &hcd->self);
}
#endif
@@ -773,9 +757,9 @@ static int tegra_ehci_probe(struct platform_device *pdev)
fail:
#ifdef CONFIG_USB_OTG_UTILS
- if (tegra->transceiver) {
+ if (!IS_ERR_OR_NULL(tegra->transceiver)) {
otg_set_host(tegra->transceiver->otg, NULL);
- usb_put_transceiver(tegra->transceiver);
+ usb_put_phy(tegra->transceiver);
}
#endif
tegra_usb_phy_close(tegra->phy);
@@ -808,9 +792,9 @@ static int tegra_ehci_remove(struct platform_device *pdev)
pm_runtime_put_noidle(&pdev->dev);
#ifdef CONFIG_USB_OTG_UTILS
- if (tegra->transceiver) {
+ if (!IS_ERR_OR_NULL(tegra->transceiver)) {
otg_set_host(tegra->transceiver->otg, NULL);
- usb_put_transceiver(tegra->transceiver);
+ usb_put_phy(tegra->transceiver);
}
#endif
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c
new file mode 100644
index 0000000..eb896a2
--- /dev/null
+++ b/drivers/usb/host/ehci-timer.c
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2012 by Alan Stern
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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.
+ */
+
+/* This file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/* Set a bit in the USBCMD register */
+static void ehci_set_command_bit(struct ehci_hcd *ehci, u32 bit)
+{
+ ehci->command |= bit;
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
+
+ /* unblock posted write */
+ ehci_readl(ehci, &ehci->regs->command);
+}
+
+/* Clear a bit in the USBCMD register */
+static void ehci_clear_command_bit(struct ehci_hcd *ehci, u32 bit)
+{
+ ehci->command &= ~bit;
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
+
+ /* unblock posted write */
+ ehci_readl(ehci, &ehci->regs->command);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI timer support... Now using hrtimers.
+ *
+ * Lots of different events are triggered from ehci->hrtimer. Whenever
+ * the timer routine runs, it checks each possible event; events that are
+ * currently enabled and whose expiration time has passed get handled.
+ * The set of enabled events is stored as a collection of bitflags in
+ * ehci->enabled_hrtimer_events, and they are numbered in order of
+ * increasing delay values (ranging between 1 ms and 100 ms).
+ *
+ * Rather than implementing a sorted list or tree of all pending events,
+ * we keep track only of the lowest-numbered pending event, in
+ * ehci->next_hrtimer_event. Whenever ehci->hrtimer gets restarted, its
+ * expiration time is set to the timeout value for this event.
+ *
+ * As a result, events might not get handled right away; the actual delay
+ * could be anywhere up to twice the requested delay. This doesn't
+ * matter, because none of the events are especially time-critical. The
+ * ones that matter most all have a delay of 1 ms, so they will be
+ * handled after 2 ms at most, which is okay. In addition to this, we
+ * allow for an expiration range of 1 ms.
+ */
+
+/*
+ * Delay lengths for the hrtimer event types.
+ * Keep this list sorted by delay length, in the same order as
+ * the event types indexed by enum ehci_hrtimer_event in ehci.h.
+ */
+static unsigned event_delays_ns[] = {
+ 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_ASS */
+ 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_PSS */
+ 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */
+ 1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */
+ 2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_FREE_ITDS */
+ 6 * NSEC_PER_MSEC, /* EHCI_HRTIMER_ASYNC_UNLINKS */
+ 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */
+ 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */
+ 15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */
+ 100 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IO_WATCHDOG */
+};
+
+/* Enable a pending hrtimer event */
+static void ehci_enable_event(struct ehci_hcd *ehci, unsigned event,
+ bool resched)
+{
+ ktime_t *timeout = &ehci->hr_timeouts[event];
+
+ if (resched)
+ *timeout = ktime_add(ktime_get(),
+ ktime_set(0, event_delays_ns[event]));
+ ehci->enabled_hrtimer_events |= (1 << event);
+
+ /* Track only the lowest-numbered pending event */
+ if (event < ehci->next_hrtimer_event) {
+ ehci->next_hrtimer_event = event;
+ hrtimer_start_range_ns(&ehci->hrtimer, *timeout,
+ NSEC_PER_MSEC, HRTIMER_MODE_ABS);
+ }
+}
+
+
+/* Poll the STS_ASS status bit; see when it agrees with CMD_ASE */
+static void ehci_poll_ASS(struct ehci_hcd *ehci)
+{
+ unsigned actual, want;
+
+ /* Don't enable anything if the controller isn't running (e.g., died) */
+ if (ehci->rh_state != EHCI_RH_RUNNING)
+ return;
+
+ want = (ehci->command & CMD_ASE) ? STS_ASS : 0;
+ actual = ehci_readl(ehci, &ehci->regs->status) & STS_ASS;
+
+ if (want != actual) {
+
+ /* Poll again later, but give up after about 20 ms */
+ if (ehci->ASS_poll_count++ < 20) {
+ ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true);
+ return;
+ }
+ ehci_warn(ehci, "Waited too long for the async schedule status, giving up\n");
+ }
+ ehci->ASS_poll_count = 0;
+
+ /* The status is up-to-date; restart or stop the schedule as needed */
+ if (want == 0) { /* Stopped */
+ if (ehci->async_count > 0)
+ ehci_set_command_bit(ehci, CMD_ASE);
+
+ } else { /* Running */
+ if (ehci->async_count == 0) {
+
+ /* Turn off the schedule after a while */
+ ehci_enable_event(ehci, EHCI_HRTIMER_DISABLE_ASYNC,
+ true);
+ }
+ }
+}
+
+/* Turn off the async schedule after a brief delay */
+static void ehci_disable_ASE(struct ehci_hcd *ehci)
+{
+ ehci_clear_command_bit(ehci, CMD_ASE);
+}
+
+
+/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */
+static void ehci_poll_PSS(struct ehci_hcd *ehci)
+{
+ unsigned actual, want;
+
+ /* Don't do anything if the controller isn't running (e.g., died) */
+ if (ehci->rh_state != EHCI_RH_RUNNING)
+ return;
+
+ want = (ehci->command & CMD_PSE) ? STS_PSS : 0;
+ actual = ehci_readl(ehci, &ehci->regs->status) & STS_PSS;
+
+ if (want != actual) {
+
+ /* Poll again later, but give up after about 20 ms */
+ if (ehci->PSS_poll_count++ < 20) {
+ ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true);
+ return;
+ }
+ ehci_warn(ehci, "Waited too long for the periodic schedule status, giving up\n");
+ }
+ ehci->PSS_poll_count = 0;
+
+ /* The status is up-to-date; restart or stop the schedule as needed */
+ if (want == 0) { /* Stopped */
+ if (ehci->periodic_count > 0)
+ ehci_set_command_bit(ehci, CMD_PSE);
+
+ } else { /* Running */
+ if (ehci->periodic_count == 0) {
+
+ /* Turn off the schedule after a while */
+ ehci_enable_event(ehci, EHCI_HRTIMER_DISABLE_PERIODIC,
+ true);
+ }
+ }
+}
+
+/* Turn off the periodic schedule after a brief delay */
+static void ehci_disable_PSE(struct ehci_hcd *ehci)
+{
+ ehci_clear_command_bit(ehci, CMD_PSE);
+}
+
+
+/* Poll the STS_HALT status bit; see when a dead controller stops */
+static void ehci_handle_controller_death(struct ehci_hcd *ehci)
+{
+ if (!(ehci_readl(ehci, &ehci->regs->status) & STS_HALT)) {
+
+ /* Give up after a few milliseconds */
+ if (ehci->died_poll_count++ < 5) {
+ /* Try again later */
+ ehci_enable_event(ehci, EHCI_HRTIMER_POLL_DEAD, true);
+ return;
+ }
+ ehci_warn(ehci, "Waited too long for the controller to stop, giving up\n");
+ }
+
+ /* Clean up the mess */
+ ehci->rh_state = EHCI_RH_HALTED;
+ ehci_writel(ehci, 0, &ehci->regs->configured_flag);
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+ ehci_work(ehci);
+ end_unlink_async(ehci);
+
+ /* Not in process context, so don't try to reset the controller */
+}
+
+
+/* Handle unlinked interrupt QHs once they are gone from the hardware */
+static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci)
+{
+ bool stopped = (ehci->rh_state < EHCI_RH_RUNNING);
+
+ /*
+ * Process all the QHs on the intr_unlink list that were added
+ * before the current unlink cycle began. The list is in
+ * temporal order, so stop when we reach the first entry in the
+ * current cycle. But if the root hub isn't running then
+ * process all the QHs on the list.
+ */
+ ehci->intr_unlinking = true;
+ while (ehci->intr_unlink) {
+ struct ehci_qh *qh = ehci->intr_unlink;
+
+ if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle)
+ break;
+ ehci->intr_unlink = qh->unlink_next;
+ qh->unlink_next = NULL;
+ end_unlink_intr(ehci, qh);
+ }
+
+ /* Handle remaining entries later */
+ if (ehci->intr_unlink) {
+ ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true);
+ ++ehci->intr_unlink_cycle;
+ }
+ ehci->intr_unlinking = false;
+}
+
+
+/* Start another free-iTDs/siTDs cycle */
+static void start_free_itds(struct ehci_hcd *ehci)
+{
+ if (!(ehci->enabled_hrtimer_events & BIT(EHCI_HRTIMER_FREE_ITDS))) {
+ ehci->last_itd_to_free = list_entry(
+ ehci->cached_itd_list.prev,
+ struct ehci_itd, itd_list);
+ ehci->last_sitd_to_free = list_entry(
+ ehci->cached_sitd_list.prev,
+ struct ehci_sitd, sitd_list);
+ ehci_enable_event(ehci, EHCI_HRTIMER_FREE_ITDS, true);
+ }
+}
+
+/* Wait for controller to stop using old iTDs and siTDs */
+static void end_free_itds(struct ehci_hcd *ehci)
+{
+ struct ehci_itd *itd, *n;
+ struct ehci_sitd *sitd, *sn;
+
+ if (ehci->rh_state < EHCI_RH_RUNNING) {
+ ehci->last_itd_to_free = NULL;
+ ehci->last_sitd_to_free = NULL;
+ }
+
+ list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) {
+ list_del(&itd->itd_list);
+ dma_pool_free(ehci->itd_pool, itd, itd->itd_dma);
+ if (itd == ehci->last_itd_to_free)
+ break;
+ }
+ list_for_each_entry_safe(sitd, sn, &ehci->cached_sitd_list, sitd_list) {
+ list_del(&sitd->sitd_list);
+ dma_pool_free(ehci->sitd_pool, sitd, sitd->sitd_dma);
+ if (sitd == ehci->last_sitd_to_free)
+ break;
+ }
+
+ if (!list_empty(&ehci->cached_itd_list) ||
+ !list_empty(&ehci->cached_sitd_list))
+ start_free_itds(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;
+
+ /*
+ * Lost IAA irqs wedge things badly; seen first with a vt8235.
+ * So we need this watchdog, but must protect it against both
+ * (a) SMP races against real IAA firing and retriggering, and
+ * (b) clean HC shutdown, when IAA watchdog was pending.
+ */
+ if (ehci->async_iaa) {
+ 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);
+ }
+
+ ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n",
+ status, cmd);
+ end_unlink_async(ehci);
+ }
+}
+
+
+/* Enable the I/O watchdog, if appropriate */
+static void turn_on_io_watchdog(struct ehci_hcd *ehci)
+{
+ /* Not needed if the controller isn't running or it's already enabled */
+ if (ehci->rh_state != EHCI_RH_RUNNING ||
+ (ehci->enabled_hrtimer_events &
+ BIT(EHCI_HRTIMER_IO_WATCHDOG)))
+ return;
+
+ /*
+ * Isochronous transfers always need the watchdog.
+ * For other sorts we use it only if the flag is set.
+ */
+ if (ehci->isoc_count > 0 || (ehci->need_io_watchdog &&
+ ehci->async_count + ehci->intr_count > 0))
+ ehci_enable_event(ehci, EHCI_HRTIMER_IO_WATCHDOG, true);
+}
+
+
+/*
+ * Handler functions for the hrtimer event types.
+ * Keep this array in the same order as the event types indexed by
+ * enum ehci_hrtimer_event in ehci.h.
+ */
+static void (*event_handlers[])(struct ehci_hcd *) = {
+ ehci_poll_ASS, /* EHCI_HRTIMER_POLL_ASS */
+ ehci_poll_PSS, /* EHCI_HRTIMER_POLL_PSS */
+ ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */
+ ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */
+ end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */
+ unlink_empty_async, /* EHCI_HRTIMER_ASYNC_UNLINKS */
+ ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */
+ ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */
+ ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */
+ ehci_work, /* EHCI_HRTIMER_IO_WATCHDOG */
+};
+
+static enum hrtimer_restart ehci_hrtimer_func(struct hrtimer *t)
+{
+ struct ehci_hcd *ehci = container_of(t, struct ehci_hcd, hrtimer);
+ ktime_t now;
+ unsigned long events;
+ unsigned long flags;
+ unsigned e;
+
+ spin_lock_irqsave(&ehci->lock, flags);
+
+ events = ehci->enabled_hrtimer_events;
+ ehci->enabled_hrtimer_events = 0;
+ ehci->next_hrtimer_event = EHCI_HRTIMER_NO_EVENT;
+
+ /*
+ * Check each pending event. If its time has expired, handle
+ * the event; otherwise re-enable it.
+ */
+ now = ktime_get();
+ for_each_set_bit(e, &events, EHCI_HRTIMER_NUM_EVENTS) {
+ if (now.tv64 >= ehci->hr_timeouts[e].tv64)
+ event_handlers[e](ehci);
+ else
+ ehci_enable_event(ehci, e, false);
+ }
+
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ return HRTIMER_NORESTART;
+}
diff --git a/drivers/usb/host/ehci-vt8500.c b/drivers/usb/host/ehci-vt8500.c
index c1eda73..4d147c4 100644
--- a/drivers/usb/host/ehci-vt8500.c
+++ b/drivers/usb/host/ehci-vt8500.c
@@ -48,7 +48,7 @@ static const struct hc_driver vt8500_ehci_hc_driver = {
/*
* basic lifecycle operations
*/
- .reset = ehci_init,
+ .reset = ehci_setup,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
@@ -121,18 +121,6 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev)
ehci = hcd_to_ehci(hcd);
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs +
- HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
-
- dbg_hcs_params(ehci, "reset");
- dbg_hcc_params(ehci, "reset");
-
- /* cache this readonly data; minimize chip reads */
- ehci->hcs_params = readl(&ehci->caps->hcs_params);
-
- ehci_port_power(ehci, 1);
-
- ehci_reset(ehci);
ret = usb_add_hcd(hcd, pdev->resource[1].start,
IRQF_SHARED);
diff --git a/drivers/usb/host/ehci-w90x900.c b/drivers/usb/host/ehci-w90x900.c
index 3d2e26c..ec59808 100644
--- a/drivers/usb/host/ehci-w90x900.c
+++ b/drivers/usb/host/ehci-w90x900.c
@@ -71,21 +71,14 @@ static int __devinit usb_w90x900_probe(const struct hc_driver *driver,
val |= ENPHY;
__raw_writel(val, ehci->regs+PHY1_CTR);
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
- ehci->sbrn = 0x20;
-
irq = platform_get_irq(pdev, 0);
if (irq < 0)
goto err4;
- ehci_reset(ehci);
-
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval != 0)
goto err4;
- ehci_writel(ehci, 1, &ehci->regs->configured_flag);
-
return retval;
err4:
iounmap(hcd->regs);
@@ -120,7 +113,7 @@ static const struct hc_driver ehci_w90x900_hc_driver = {
/*
* basic lifecycle operations
*/
- .reset = ehci_init,
+ .reset = ehci_setup,
.start = ehci_run,
.stop = ehci_stop,
diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c
index e9713d5..39f24fa 100644
--- a/drivers/usb/host/ehci-xilinx-of.c
+++ b/drivers/usb/host/ehci-xilinx-of.c
@@ -32,30 +32,6 @@
#include <linux/of_address.h>
/**
- * ehci_xilinx_of_setup - Initialize the device for ehci_reset()
- * @hcd: Pointer to the usb_hcd device to which the host controller bound
- *
- * called during probe() after chip reset completes.
- */
-static int ehci_xilinx_of_setup(struct usb_hcd *hcd)
-{
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- int retval;
-
- retval = ehci_halt(ehci);
- if (retval)
- return retval;
-
- retval = ehci_init(hcd);
- if (retval)
- return retval;
-
- ehci->sbrn = 0x20;
-
- return ehci_reset(ehci);
-}
-
-/**
* ehci_xilinx_port_handed_over - hand the port out if failed to enable it
* @hcd: Pointer to the usb_hcd device to which the host controller bound
* @portnum:Port number to which the device is attached.
@@ -107,7 +83,7 @@ static const struct hc_driver ehci_xilinx_of_hc_driver = {
/*
* basic lifecycle operations
*/
- .reset = ehci_xilinx_of_setup,
+ .reset = ehci_setup,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
@@ -219,11 +195,6 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op)
/* Debug registers are at the first 0x100 region
*/
ehci->caps = hcd->regs + 0x100;
- ehci->regs = hcd->regs + 0x100 +
- HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-
- /* cache this readonly data; minimize chip reads */
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
rv = usb_add_hcd(hcd, irq, 0);
if (rv == 0)
diff --git a/drivers/usb/host/ehci-xls.c b/drivers/usb/host/ehci-xls.c
index 72f0819..8dc6a22 100644
--- a/drivers/usb/host/ehci-xls.c
+++ b/drivers/usb/host/ehci-xls.c
@@ -14,30 +14,11 @@
static int ehci_xls_setup(struct usb_hcd *hcd)
{
- int retval;
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs +
- HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
- dbg_hcs_params(ehci, "reset");
- dbg_hcc_params(ehci, "reset");
- /* cache this readonly data; minimize chip reads */
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-
- retval = ehci_halt(ehci);
- if (retval)
- return retval;
-
- /* data structure init */
- retval = ehci_init(hcd);
- if (retval)
- return retval;
-
- ehci_reset(ehci);
-
- return retval;
+ return ehci_setup(hcd);
}
int ehci_xls_probe_internal(const struct hc_driver *driver,
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 2694ed6..da07d98 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -42,7 +42,7 @@ struct ehci_stats {
/* irq usage */
unsigned long normal;
unsigned long error;
- unsigned long reclaim;
+ unsigned long iaa;
unsigned long lost_iaa;
/* termination of urbs from core */
@@ -51,7 +51,7 @@ struct ehci_stats {
};
/* ehci_hcd->lock guards shared data against other CPUs:
- * ehci_hcd: async, reclaim, periodic (and shadow), ...
+ * ehci_hcd: async, unlink, periodic (and shadow), ...
* usb_host_endpoint: hcpriv
* ehci_qh: qh_next, qtd_list
* ehci_qtd: qtd_list
@@ -62,13 +62,48 @@ struct ehci_stats {
#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */
+/*
+ * ehci_rh_state values of EHCI_RH_RUNNING or above mean that the
+ * controller may be doing DMA. Lower values mean there's no DMA.
+ */
enum ehci_rh_state {
EHCI_RH_HALTED,
EHCI_RH_SUSPENDED,
- EHCI_RH_RUNNING
+ EHCI_RH_RUNNING,
+ EHCI_RH_STOPPING
};
+/*
+ * Timer events, ordered by increasing delay length.
+ * Always update event_delays_ns[] and event_handlers[] (defined in
+ * ehci-timer.c) in parallel with this list.
+ */
+enum ehci_hrtimer_event {
+ EHCI_HRTIMER_POLL_ASS, /* Poll for async schedule off */
+ EHCI_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */
+ EHCI_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */
+ EHCI_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */
+ EHCI_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */
+ EHCI_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */
+ EHCI_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */
+ EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */
+ EHCI_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */
+ EHCI_HRTIMER_IO_WATCHDOG, /* Check for missing IRQs */
+ EHCI_HRTIMER_NUM_EVENTS /* Must come last */
+};
+#define EHCI_HRTIMER_NO_EVENT 99
+
struct ehci_hcd { /* one per controller */
+ /* timing support */
+ enum ehci_hrtimer_event next_hrtimer_event;
+ unsigned enabled_hrtimer_events;
+ ktime_t hr_timeouts[EHCI_HRTIMER_NUM_EVENTS];
+ struct hrtimer hrtimer;
+
+ int PSS_poll_count;
+ int ASS_poll_count;
+ int died_poll_count;
+
/* glue to PCI and HCD framework */
struct ehci_caps __iomem *caps;
struct ehci_regs __iomem *regs;
@@ -78,30 +113,48 @@ struct ehci_hcd { /* one per controller */
spinlock_t lock;
enum ehci_rh_state rh_state;
+ /* general schedule support */
+ bool scanning:1;
+ bool need_rescan:1;
+ bool intr_unlinking:1;
+ bool async_unlinking:1;
+ bool shutdown:1;
+ struct ehci_qh *qh_scan_next;
+
/* async schedule support */
struct ehci_qh *async;
struct ehci_qh *dummy; /* For AMD quirk use */
- struct ehci_qh *reclaim;
- struct ehci_qh *qh_scan_next;
- unsigned scanning : 1;
+ struct ehci_qh *async_unlink;
+ struct ehci_qh *async_unlink_last;
+ struct ehci_qh *async_iaa;
+ unsigned async_unlink_cycle;
+ unsigned async_count; /* async activity count */
/* periodic schedule support */
#define DEFAULT_I_TDPS 1024 /* some HCs can do less */
unsigned periodic_size;
__hc32 *periodic; /* hw periodic table */
dma_addr_t periodic_dma;
+ struct list_head intr_qh_list;
unsigned i_thresh; /* uframes HC might cache */
union ehci_shadow *pshadow; /* mirror hw periodic table */
- int next_uframe; /* scan periodic, start here */
- unsigned periodic_sched; /* periodic activity count */
+ struct ehci_qh *intr_unlink;
+ struct ehci_qh *intr_unlink_last;
+ unsigned intr_unlink_cycle;
+ unsigned now_frame; /* frame from HC hardware */
+ unsigned next_frame; /* scan periodic, start here */
+ unsigned intr_count; /* intr activity count */
+ unsigned isoc_count; /* isoc activity count */
+ unsigned periodic_count; /* periodic activity count */
unsigned uframe_periodic_max; /* max periodic time per uframe */
- /* list of itds & sitds completed while clock_frame was still active */
+ /* list of itds & sitds completed while now_frame was still active */
struct list_head cached_itd_list;
+ struct ehci_itd *last_itd_to_free;
struct list_head cached_sitd_list;
- unsigned clock_frame;
+ struct ehci_sitd *last_sitd_to_free;
/* per root hub port */
unsigned long reset_done [EHCI_MAX_ROOT_PORTS];
@@ -126,10 +179,6 @@ struct ehci_hcd { /* one per controller */
struct dma_pool *itd_pool; /* itd per iso urb */
struct dma_pool *sitd_pool; /* sitd per split iso urb */
- struct timer_list iaa_watchdog;
- struct timer_list watchdog;
- unsigned long actions;
- unsigned periodic_stamp;
unsigned random_frame;
unsigned long next_statechange;
ktime_t last_periodic_enable;
@@ -143,7 +192,6 @@ struct ehci_hcd { /* one per controller */
unsigned big_endian_capbase:1;
unsigned has_amcc_usb23:1;
unsigned need_io_watchdog:1;
- unsigned broken_periodic:1;
unsigned amd_pll_fix:1;
unsigned fs_i_thresh:1; /* Intel iso scheduling */
unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/
@@ -175,10 +223,6 @@ struct ehci_hcd { /* one per controller */
#ifdef DEBUG
struct dentry *debug_dir;
#endif
- /*
- * OTG controllers and transceivers need software interaction
- */
- struct usb_phy *transceiver;
};
/* convert between an HCD pointer and the corresponding EHCI_HCD */
@@ -191,34 +235,6 @@ static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci)
return container_of ((void *) ehci, struct usb_hcd, hcd_priv);
}
-
-static inline void
-iaa_watchdog_start(struct ehci_hcd *ehci)
-{
- WARN_ON(timer_pending(&ehci->iaa_watchdog));
- mod_timer(&ehci->iaa_watchdog,
- jiffies + msecs_to_jiffies(EHCI_IAA_MSECS));
-}
-
-static inline void iaa_watchdog_done(struct ehci_hcd *ehci)
-{
- del_timer(&ehci->iaa_watchdog);
-}
-
-enum ehci_timer_action {
- TIMER_IO_WATCHDOG,
- TIMER_ASYNC_SHRINK,
- TIMER_ASYNC_OFF,
-};
-
-static inline void
-timer_action_done (struct ehci_hcd *ehci, enum ehci_timer_action action)
-{
- clear_bit (action, &ehci->actions);
-}
-
-static void free_cached_lists(struct ehci_hcd *ehci);
-
/*-------------------------------------------------------------------------*/
#include <linux/usb/ehci_def.h>
@@ -328,7 +344,13 @@ union ehci_shadow {
struct ehci_qh_hw {
__hc32 hw_next; /* see EHCI 3.6.1 */
__hc32 hw_info1; /* see EHCI 3.6.2 */
-#define QH_HEAD 0x00008000
+#define QH_CONTROL_EP (1 << 27) /* FS/LS control endpoint */
+#define QH_HEAD (1 << 15) /* Head of async reclamation list */
+#define QH_TOGGLE_CTL (1 << 14) /* Data toggle control */
+#define QH_HIGH_SPEED (2 << 12) /* Endpoint speed */
+#define QH_LOW_SPEED (1 << 12)
+#define QH_FULL_SPEED (0 << 12)
+#define QH_INACTIVATE (1 << 7) /* Inactivate on next transaction */
__hc32 hw_info2; /* see EHCI 3.6.2 */
#define QH_SMASK 0x000000ff
#define QH_CMASK 0x0000ff00
@@ -346,32 +368,23 @@ struct ehci_qh_hw {
} __attribute__ ((aligned(32)));
struct ehci_qh {
- struct ehci_qh_hw *hw;
+ struct ehci_qh_hw *hw; /* Must come first */
/* the rest is HCD-private */
dma_addr_t qh_dma; /* address of qh */
union ehci_shadow qh_next; /* ptr to qh; or periodic */
struct list_head qtd_list; /* sw qtd list */
+ struct list_head intr_node; /* list of intr QHs */
struct ehci_qtd *dummy;
- struct ehci_qh *reclaim; /* next to reclaim */
-
- struct ehci_hcd *ehci;
- unsigned long unlink_time;
+ struct ehci_qh *unlink_next; /* next on unlink list */
- /*
- * Do NOT use atomic operations for QH refcounting. On some CPUs
- * (PPC7448 for example), atomic operations cannot be performed on
- * memory that is cache-inhibited (i.e. being used for DMA).
- * Spinlocks are used to protect all QH fields.
- */
- u32 refcount;
- unsigned stamp;
+ 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 */
#define QH_STATE_IDLE 3 /* HC doesn't see this */
-#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on reclaim q */
+#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on unlink q */
#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */
u8 xacterrs; /* XactErr retry counter */
@@ -421,7 +434,6 @@ struct ehci_iso_stream {
/* first field matches ehci_hq, but is NULL */
struct ehci_qh_hw *hw;
- u32 refcount;
u8 bEndpointAddress;
u8 highspeed;
struct list_head td_list; /* queued itds/sitds */
diff --git a/drivers/usb/host/fhci-dbg.c b/drivers/usb/host/fhci-dbg.c
index 6fe5500..f238cb3 100644
--- a/drivers/usb/host/fhci-dbg.c
+++ b/drivers/usb/host/fhci-dbg.c
@@ -41,7 +41,7 @@ void fhci_dbg_isr(struct fhci_hcd *fhci, int usb_er)
static int fhci_dfs_regs_show(struct seq_file *s, void *v)
{
struct fhci_hcd *fhci = s->private;
- struct fhci_regs __iomem *regs = fhci->regs;
+ struct qe_usb_ctlr __iomem *regs = fhci->regs;
seq_printf(s,
"mode: 0x%x\n" "addr: 0x%x\n"
@@ -50,11 +50,11 @@ static int fhci_dfs_regs_show(struct seq_file *s, void *v)
"status: 0x%x\n" "SOF timer: %d\n"
"frame number: %d\n"
"lines status: 0x%x\n",
- in_8(&regs->usb_mod), in_8(&regs->usb_addr),
- in_8(&regs->usb_comm), in_be16(&regs->usb_ep[0]),
- in_be16(&regs->usb_event), in_be16(&regs->usb_mask),
- in_8(&regs->usb_status), in_be16(&regs->usb_sof_tmr),
- in_be16(&regs->usb_frame_num),
+ in_8(&regs->usb_usmod), in_8(&regs->usb_usadr),
+ in_8(&regs->usb_uscom), in_be16(&regs->usb_usep[0]),
+ in_be16(&regs->usb_usber), in_be16(&regs->usb_usbmr),
+ in_8(&regs->usb_usbs), in_be16(&regs->usb_ussft),
+ in_be16(&regs->usb_usfrn),
fhci_ioports_check_bus_state(fhci));
return 0;
diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c
index d262374..7da1a26 100644
--- a/drivers/usb/host/fhci-hcd.c
+++ b/drivers/usb/host/fhci-hcd.c
@@ -40,8 +40,8 @@ void fhci_start_sof_timer(struct fhci_hcd *fhci)
/* clear frame_n */
out_be16(&fhci->pram->frame_num, 0);
- out_be16(&fhci->regs->usb_sof_tmr, 0);
- setbits8(&fhci->regs->usb_mod, USB_MODE_SFTE);
+ out_be16(&fhci->regs->usb_ussft, 0);
+ setbits8(&fhci->regs->usb_usmod, USB_MODE_SFTE);
fhci_dbg(fhci, "<- %s\n", __func__);
}
@@ -50,7 +50,7 @@ void fhci_stop_sof_timer(struct fhci_hcd *fhci)
{
fhci_dbg(fhci, "-> %s\n", __func__);
- clrbits8(&fhci->regs->usb_mod, USB_MODE_SFTE);
+ clrbits8(&fhci->regs->usb_usmod, USB_MODE_SFTE);
gtm_stop_timer16(fhci->timer);
fhci_dbg(fhci, "<- %s\n", __func__);
@@ -58,7 +58,7 @@ void fhci_stop_sof_timer(struct fhci_hcd *fhci)
u16 fhci_get_sof_timer_count(struct fhci_usb *usb)
{
- return be16_to_cpu(in_be16(&usb->fhci->regs->usb_sof_tmr) / 12);
+ return be16_to_cpu(in_be16(&usb->fhci->regs->usb_ussft) / 12);
}
/* initialize the endpoint zero */
@@ -88,8 +88,8 @@ void fhci_usb_enable_interrupt(struct fhci_usb *usb)
enable_irq(fhci_to_hcd(fhci)->irq);
/* initialize the event register and mask register */
- out_be16(&usb->fhci->regs->usb_event, 0xffff);
- out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);
+ out_be16(&usb->fhci->regs->usb_usber, 0xffff);
+ out_be16(&usb->fhci->regs->usb_usbmr, usb->saved_msk);
/* enable the timer interrupts */
enable_irq(fhci->timer->irq);
@@ -109,7 +109,7 @@ void fhci_usb_disable_interrupt(struct fhci_usb *usb)
/* disable the usb interrupt */
disable_irq_nosync(fhci_to_hcd(fhci)->irq);
- out_be16(&usb->fhci->regs->usb_mask, 0);
+ out_be16(&usb->fhci->regs->usb_usbmr, 0);
}
usb->intr_nesting_cnt++;
}
@@ -119,9 +119,9 @@ static u32 fhci_usb_enable(struct fhci_hcd *fhci)
{
struct fhci_usb *usb = fhci->usb_lld;
- out_be16(&usb->fhci->regs->usb_event, 0xffff);
- out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);
- setbits8(&usb->fhci->regs->usb_mod, USB_MODE_EN);
+ out_be16(&usb->fhci->regs->usb_usber, 0xffff);
+ out_be16(&usb->fhci->regs->usb_usbmr, usb->saved_msk);
+ setbits8(&usb->fhci->regs->usb_usmod, USB_MODE_EN);
mdelay(100);
@@ -141,7 +141,7 @@ static u32 fhci_usb_disable(struct fhci_hcd *fhci)
usb->port_status == FHCI_PORT_LOW)
fhci_device_disconnected_interrupt(fhci);
- clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_EN);
+ clrbits8(&usb->fhci->regs->usb_usmod, USB_MODE_EN);
return 0;
}
@@ -285,13 +285,13 @@ static int fhci_usb_init(struct fhci_hcd *fhci)
USB_E_IDLE_MASK |
USB_E_RESET_MASK | USB_E_SFT_MASK | USB_E_MSF_MASK);
- out_8(&usb->fhci->regs->usb_mod, USB_MODE_HOST | USB_MODE_EN);
+ out_8(&usb->fhci->regs->usb_usmod, USB_MODE_HOST | USB_MODE_EN);
/* clearing the mask register */
- out_be16(&usb->fhci->regs->usb_mask, 0);
+ out_be16(&usb->fhci->regs->usb_usbmr, 0);
/* initialing the event register */
- out_be16(&usb->fhci->regs->usb_event, 0xffff);
+ out_be16(&usb->fhci->regs->usb_usber, 0xffff);
if (endpoint_zero_init(usb, DEFAULT_DATA_MEM, DEFAULT_RING_LEN) != 0) {
fhci_usb_free(usb);
@@ -745,8 +745,8 @@ static int __devinit of_fhci_probe(struct platform_device *ofdev)
}
/* Clear and disable any pending interrupts. */
- out_be16(&fhci->regs->usb_event, 0xffff);
- out_be16(&fhci->regs->usb_mask, 0);
+ out_be16(&fhci->regs->usb_usber, 0xffff);
+ out_be16(&fhci->regs->usb_usbmr, 0);
ret = usb_add_hcd(hcd, usb_irq, 0);
if (ret < 0)
diff --git a/drivers/usb/host/fhci-hub.c b/drivers/usb/host/fhci-hub.c
index 348fe62..6af2512 100644
--- a/drivers/usb/host/fhci-hub.c
+++ b/drivers/usb/host/fhci-hub.c
@@ -97,7 +97,7 @@ void fhci_port_disable(struct fhci_hcd *fhci)
/* Enable IDLE since we want to know if something comes along */
usb->saved_msk |= USB_E_IDLE_MASK;
- out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);
+ out_be16(&usb->fhci->regs->usb_usbmr, usb->saved_msk);
/* check if during the disconnection process attached new device */
if (port_status == FHCI_PORT_WAITING)
@@ -158,21 +158,21 @@ void fhci_port_reset(void *lld)
fhci_stop_sof_timer(fhci);
/* disable the USB controller */
- mode = in_8(&fhci->regs->usb_mod);
- out_8(&fhci->regs->usb_mod, mode & (~USB_MODE_EN));
+ mode = in_8(&fhci->regs->usb_usmod);
+ out_8(&fhci->regs->usb_usmod, mode & (~USB_MODE_EN));
/* disable idle interrupts */
- mask = in_be16(&fhci->regs->usb_mask);
- out_be16(&fhci->regs->usb_mask, mask & (~USB_E_IDLE_MASK));
+ mask = in_be16(&fhci->regs->usb_usbmr);
+ out_be16(&fhci->regs->usb_usbmr, mask & (~USB_E_IDLE_MASK));
fhci_io_port_generate_reset(fhci);
/* enable interrupt on this endpoint */
- out_be16(&fhci->regs->usb_mask, mask);
+ out_be16(&fhci->regs->usb_usbmr, mask);
/* enable the USB controller */
- mode = in_8(&fhci->regs->usb_mod);
- out_8(&fhci->regs->usb_mod, mode | USB_MODE_EN);
+ mode = in_8(&fhci->regs->usb_usmod);
+ out_8(&fhci->regs->usb_usmod, mode | USB_MODE_EN);
fhci_start_sof_timer(fhci);
fhci_dbg(fhci, "<- %s\n", __func__);
diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c
index 2df851b..2dc8a40 100644
--- a/drivers/usb/host/fhci-sched.c
+++ b/drivers/usb/host/fhci-sched.c
@@ -132,8 +132,8 @@ void fhci_flush_all_transmissions(struct fhci_usb *usb)
u8 mode;
struct td *td;
- mode = in_8(&usb->fhci->regs->usb_mod);
- clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_EN);
+ mode = in_8(&usb->fhci->regs->usb_usmod);
+ clrbits8(&usb->fhci->regs->usb_usmod, USB_MODE_EN);
fhci_flush_bds(usb);
@@ -147,9 +147,9 @@ void fhci_flush_all_transmissions(struct fhci_usb *usb)
usb->actual_frame->frame_status = FRAME_END_TRANSMISSION;
/* reset the event register */
- out_be16(&usb->fhci->regs->usb_event, 0xffff);
+ out_be16(&usb->fhci->regs->usb_usber, 0xffff);
/* enable the USB controller */
- out_8(&usb->fhci->regs->usb_mod, mode | USB_MODE_EN);
+ out_8(&usb->fhci->regs->usb_usmod, mode | USB_MODE_EN);
}
/*
@@ -414,7 +414,7 @@ static void sof_interrupt(struct fhci_hcd *fhci)
usb->port_status = FHCI_PORT_FULL;
/* Disable IDLE */
usb->saved_msk &= ~USB_E_IDLE_MASK;
- out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);
+ out_be16(&usb->fhci->regs->usb_usbmr, usb->saved_msk);
}
gtm_set_exact_timer16(fhci->timer, usb->max_frame_usage, false);
@@ -433,14 +433,14 @@ void fhci_device_disconnected_interrupt(struct fhci_hcd *fhci)
fhci_dbg(fhci, "-> %s\n", __func__);
fhci_usb_disable_interrupt(usb);
- clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_LSS);
+ clrbits8(&usb->fhci->regs->usb_usmod, USB_MODE_LSS);
usb->port_status = FHCI_PORT_DISABLED;
fhci_stop_sof_timer(fhci);
/* Enable IDLE since we want to know if something comes along */
usb->saved_msk |= USB_E_IDLE_MASK;
- out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);
+ out_be16(&usb->fhci->regs->usb_usbmr, usb->saved_msk);
usb->vroot_hub->port.wPortStatus &= ~USB_PORT_STAT_CONNECTION;
usb->vroot_hub->port.wPortChange |= USB_PORT_STAT_C_CONNECTION;
@@ -473,7 +473,7 @@ void fhci_device_connected_interrupt(struct fhci_hcd *fhci)
}
usb->port_status = FHCI_PORT_LOW;
- setbits8(&usb->fhci->regs->usb_mod, USB_MODE_LSS);
+ setbits8(&usb->fhci->regs->usb_usmod, USB_MODE_LSS);
usb->vroot_hub->port.wPortStatus |=
(USB_PORT_STAT_LOW_SPEED |
USB_PORT_STAT_CONNECTION);
@@ -491,7 +491,7 @@ void fhci_device_connected_interrupt(struct fhci_hcd *fhci)
}
usb->port_status = FHCI_PORT_FULL;
- clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_LSS);
+ clrbits8(&usb->fhci->regs->usb_usmod, USB_MODE_LSS);
usb->vroot_hub->port.wPortStatus &=
~USB_PORT_STAT_LOW_SPEED;
usb->vroot_hub->port.wPortStatus |=
@@ -535,7 +535,7 @@ static void abort_transmission(struct fhci_usb *usb)
/* issue stop Tx command */
qe_issue_cmd(QE_USB_STOP_TX, QE_CR_SUBBLOCK_USB, EP_ZERO, 0);
/* flush Tx FIFOs */
- out_8(&usb->fhci->regs->usb_comm, USB_CMD_FLUSH_FIFO | EP_ZERO);
+ out_8(&usb->fhci->regs->usb_uscom, USB_CMD_FLUSH_FIFO | EP_ZERO);
udelay(1000);
/* reset Tx BDs */
fhci_flush_bds(usb);
@@ -555,11 +555,11 @@ irqreturn_t fhci_irq(struct usb_hcd *hcd)
usb = fhci->usb_lld;
- usb_er |= in_be16(&usb->fhci->regs->usb_event) &
- in_be16(&usb->fhci->regs->usb_mask);
+ usb_er |= in_be16(&usb->fhci->regs->usb_usber) &
+ in_be16(&usb->fhci->regs->usb_usbmr);
/* clear event bits for next time */
- out_be16(&usb->fhci->regs->usb_event, usb_er);
+ out_be16(&usb->fhci->regs->usb_usber, usb_er);
fhci_dbg_isr(fhci, usb_er);
@@ -573,7 +573,7 @@ irqreturn_t fhci_irq(struct usb_hcd *hcd)
/* Turn on IDLE since we want to disconnect */
usb->saved_msk |= USB_E_IDLE_MASK;
- out_be16(&usb->fhci->regs->usb_event,
+ out_be16(&usb->fhci->regs->usb_usber,
usb->saved_msk);
} else if (usb->port_status == FHCI_PORT_DISABLED) {
if (fhci_ioports_check_bus_state(fhci) == 1)
@@ -611,7 +611,7 @@ irqreturn_t fhci_irq(struct usb_hcd *hcd)
/* XXX usb->port_status = FHCI_PORT_WAITING; */
/* Disable IDLE */
usb->saved_msk &= ~USB_E_IDLE_MASK;
- out_be16(&usb->fhci->regs->usb_mask,
+ out_be16(&usb->fhci->regs->usb_usbmr,
usb->saved_msk);
} else {
fhci_dbg_isr(fhci, -1);
diff --git a/drivers/usb/host/fhci-tds.c b/drivers/usb/host/fhci-tds.c
index c5ed881..1498061 100644
--- a/drivers/usb/host/fhci-tds.c
+++ b/drivers/usb/host/fhci-tds.c
@@ -249,7 +249,7 @@ void fhci_init_ep_registers(struct fhci_usb *usb, struct endpoint *ep,
u8 rt;
/* set the endpoint registers according to the endpoint */
- out_be16(&usb->fhci->regs->usb_ep[0],
+ out_be16(&usb->fhci->regs->usb_usep[0],
USB_TRANS_CTR | USB_EP_MF | USB_EP_RTE);
out_be16(&usb->fhci->pram->ep_ptr[0],
cpm_muram_offset(ep->ep_pram_ptr));
@@ -463,7 +463,7 @@ u32 fhci_host_transaction(struct fhci_usb *usb,
cq_put(&ep->conf_frame_Q, pkt);
if (cq_howmany(&ep->conf_frame_Q) == 1)
- out_8(&usb->fhci->regs->usb_comm, USB_CMD_STR_FIFO);
+ out_8(&usb->fhci->regs->usb_uscom, USB_CMD_STR_FIFO);
return 0;
}
@@ -535,8 +535,8 @@ void fhci_flush_actual_frame(struct fhci_usb *usb)
struct endpoint *ep = usb->ep0;
/* disable the USB controller */
- mode = in_8(&usb->fhci->regs->usb_mod);
- out_8(&usb->fhci->regs->usb_mod, mode & ~USB_MODE_EN);
+ mode = in_8(&usb->fhci->regs->usb_usmod);
+ out_8(&usb->fhci->regs->usb_usmod, mode & ~USB_MODE_EN);
tb_ptr = in_be16(&ep->ep_pram_ptr->tx_bd_ptr);
td = cpm_muram_addr(tb_ptr);
@@ -571,9 +571,9 @@ void fhci_flush_actual_frame(struct fhci_usb *usb)
usb->actual_frame->frame_status = FRAME_TIMER_END_TRANSMISSION;
/* reset the event register */
- out_be16(&usb->fhci->regs->usb_event, 0xffff);
+ out_be16(&usb->fhci->regs->usb_usber, 0xffff);
/* enable the USB controller */
- out_8(&usb->fhci->regs->usb_mod, mode | USB_MODE_EN);
+ out_8(&usb->fhci->regs->usb_usmod, mode | USB_MODE_EN);
}
/* handles Tx confirm and Tx error interrupt */
@@ -613,7 +613,7 @@ void fhci_host_transmit_actual_frame(struct fhci_usb *usb)
/* start transmit only if we have something in the TDs */
if (in_be16(&td->status) & TD_R)
- out_8(&usb->fhci->regs->usb_comm, USB_CMD_STR_FIFO);
+ out_8(&usb->fhci->regs->usb_uscom, USB_CMD_STR_FIFO);
if (in_be32(&ep->conf_td->buf_ptr) == DUMMY_BD_BUFFER) {
out_be32(&old_td->buf_ptr, 0);
diff --git a/drivers/usb/host/fhci.h b/drivers/usb/host/fhci.h
index dc6939a..7cc1c32 100644
--- a/drivers/usb/host/fhci.h
+++ b/drivers/usb/host/fhci.h
@@ -28,6 +28,7 @@
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <asm/qe.h>
+#include <asm/immap_qe.h>
#define USB_CLOCK 48000000
@@ -173,25 +174,6 @@
#define USB_E_TXB_MASK 0x0002
#define USB_E_RXB_MASK 0x0001
-/* Freescale USB Host controller registers */
-struct fhci_regs {
- u8 usb_mod; /* mode register */
- u8 usb_addr; /* address register */
- u8 usb_comm; /* command register */
- u8 reserved1[1];
- __be16 usb_ep[4]; /* endpoint register */
- u8 reserved2[4];
- __be16 usb_event; /* event register */
- u8 reserved3[2];
- __be16 usb_mask; /* mask register */
- u8 reserved4[1];
- u8 usb_status; /* status register */
- __be16 usb_sof_tmr; /* Start Of Frame timer */
- u8 reserved5[2];
- __be16 usb_frame_num; /* frame number register */
- u8 reserved6[1];
-};
-
/* Freescale USB HOST */
struct fhci_pram {
__be16 ep_ptr[4]; /* Endpoint porter reg */
@@ -267,7 +249,7 @@ struct fhci_hcd {
int gpios[NUM_GPIOS];
bool alow_gpios[NUM_GPIOS];
- struct fhci_regs __iomem *regs; /* I/O memory used to communicate */
+ struct qe_usb_ctlr __iomem *regs; /* I/O memory used to communicate */
struct fhci_pram __iomem *pram; /* Parameter RAM */
struct gtm_timer *timer;
diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c
index ff471c1..f19e269 100644
--- a/drivers/usb/host/imx21-hcd.c
+++ b/drivers/usb/host/imx21-hcd.c
@@ -1811,7 +1811,7 @@ static int imx21_remove(struct platform_device *pdev)
usb_remove_hcd(hcd);
if (res != NULL) {
- clk_disable(imx21->clk);
+ clk_disable_unprepare(imx21->clk);
clk_put(imx21->clk);
iounmap(imx21->regs);
release_mem_region(res->start, resource_size(res));
@@ -1884,7 +1884,7 @@ static int imx21_probe(struct platform_device *pdev)
ret = clk_set_rate(imx21->clk, clk_round_rate(imx21->clk, 48000000));
if (ret)
goto failed_clock_set;
- ret = clk_enable(imx21->clk);
+ ret = clk_prepare_enable(imx21->clk);
if (ret)
goto failed_clock_enable;
@@ -1900,7 +1900,7 @@ static int imx21_probe(struct platform_device *pdev)
return 0;
failed_add_hcd:
- clk_disable(imx21->clk);
+ clk_disable_unprepare(imx21->clk);
failed_clock_enable:
failed_clock_set:
clk_put(imx21->clk);
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index 2909621..fc3091b 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -12,6 +12,7 @@
*/
#include <linux/clk.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <mach/ohci.h>
#include <plat/usb-phy.h>
@@ -71,6 +72,8 @@ static const struct hc_driver exynos_ohci_hc_driver = {
.start_port_reset = ohci_start_port_reset,
};
+static u64 ohci_exynos_dma_mask = DMA_BIT_MASK(32);
+
static int __devinit exynos_ohci_probe(struct platform_device *pdev)
{
struct exynos4_ohci_platdata *pdata;
@@ -87,7 +90,18 @@ static int __devinit exynos_ohci_probe(struct platform_device *pdev)
return -EINVAL;
}
- exynos_ohci = kzalloc(sizeof(struct exynos_ohci_hcd), GFP_KERNEL);
+ /*
+ * 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 move to full device tree support this will vanish off.
+ */
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &ohci_exynos_dma_mask;
+ if (!pdev->dev.coherent_dma_mask)
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+ exynos_ohci = devm_kzalloc(&pdev->dev, sizeof(struct exynos_ohci_hcd),
+ GFP_KERNEL);
if (!exynos_ohci)
return -ENOMEM;
@@ -97,8 +111,7 @@ static int __devinit exynos_ohci_probe(struct platform_device *pdev)
dev_name(&pdev->dev));
if (!hcd) {
dev_err(&pdev->dev, "Unable to create HCD\n");
- err = -ENOMEM;
- goto fail_hcd;
+ return -ENOMEM;
}
exynos_ohci->hcd = hcd;
@@ -123,7 +136,7 @@ static int __devinit exynos_ohci_probe(struct platform_device *pdev)
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
- hcd->regs = ioremap(res->start, resource_size(res));
+ hcd->regs = devm_ioremap(&pdev->dev, res->start, hcd->rsrc_len);
if (!hcd->regs) {
dev_err(&pdev->dev, "Failed to remap I/O memory\n");
err = -ENOMEM;
@@ -134,7 +147,7 @@ static int __devinit exynos_ohci_probe(struct platform_device *pdev)
if (!irq) {
dev_err(&pdev->dev, "Failed to get IRQ\n");
err = -ENODEV;
- goto fail;
+ goto fail_io;
}
if (pdata->phy_init)
@@ -146,23 +159,19 @@ static int __devinit exynos_ohci_probe(struct platform_device *pdev)
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err) {
dev_err(&pdev->dev, "Failed to add USB HCD\n");
- goto fail;
+ goto fail_io;
}
platform_set_drvdata(pdev, exynos_ohci);
return 0;
-fail:
- iounmap(hcd->regs);
fail_io:
clk_disable(exynos_ohci->clk);
fail_clken:
clk_put(exynos_ohci->clk);
fail_clk:
usb_put_hcd(hcd);
-fail_hcd:
- kfree(exynos_ohci);
return err;
}
@@ -177,13 +186,10 @@ static int __devexit exynos_ohci_remove(struct platform_device *pdev)
if (pdata && pdata->phy_exit)
pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
- iounmap(hcd->regs);
-
clk_disable(exynos_ohci->clk);
clk_put(exynos_ohci->clk);
usb_put_hcd(hcd);
- kfree(exynos_ohci);
return 0;
}
@@ -225,6 +231,9 @@ static int exynos_ohci_suspend(struct device *dev)
if (pdata && pdata->phy_exit)
pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
+
+ clk_disable(exynos_ohci->clk);
+
fail:
spin_unlock_irqrestore(&ohci->lock, flags);
@@ -238,6 +247,8 @@ static int exynos_ohci_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
+ clk_enable(exynos_ohci->clk);
+
if (pdata && pdata->phy_init)
pdata->phy_init(pdev, S5P_USB_PHY_HOST);
@@ -258,6 +269,14 @@ static const struct dev_pm_ops exynos_ohci_pm_ops = {
.resume = exynos_ohci_resume,
};
+#ifdef CONFIG_OF
+static const struct of_device_id exynos_ohci_match[] = {
+ { .compatible = "samsung,exynos-ohci" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, exynos_ohci_match);
+#endif
+
static struct platform_driver exynos_ohci_driver = {
.probe = exynos_ohci_probe,
.remove = __devexit_p(exynos_ohci_remove),
@@ -266,6 +285,7 @@ static struct platform_driver exynos_ohci_driver = {
.name = "exynos-ohci",
.owner = THIS_MODULE,
.pm = &exynos_ohci_pm_ops,
+ .of_match_table = of_match_ptr(exynos_ohci_match),
}
};
diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c
index 1e364ec..a446386 100644
--- a/drivers/usb/host/ohci-nxp.c
+++ b/drivers/usb/host/ohci-nxp.c
@@ -43,16 +43,6 @@
#define USB_HOST_NEED_CLK_EN (1 << 21)
#define PAD_CONTROL_LAST_DRIVEN (1 << 19)
-#define USB_OTG_CLK_CTRL IO_ADDRESS(USB_CONFIG_BASE + 0xFF4)
-#define USB_OTG_CLK_STAT IO_ADDRESS(USB_CONFIG_BASE + 0xFF8)
-
-/* USB_OTG_CLK_CTRL bit defines */
-#define AHB_M_CLOCK_ON (1 << 4)
-#define OTG_CLOCK_ON (1 << 3)
-#define I2C_CLOCK_ON (1 << 2)
-#define DEV_CLOCK_ON (1 << 1)
-#define HOST_CLOCK_ON (1 << 0)
-
#define USB_OTG_STAT_CONTROL IO_ADDRESS(USB_CONFIG_BASE + 0x110)
/* USB_OTG_STAT_CONTROL bit defines */
@@ -72,7 +62,9 @@ static struct i2c_client *isp1301_i2c_client;
extern int usb_disabled(void);
-static struct clk *usb_clk;
+static struct clk *usb_pll_clk;
+static struct clk *usb_dev_clk;
+static struct clk *usb_otg_clk;
static void isp1301_configure_pnx4008(void)
{
@@ -249,8 +241,6 @@ static const struct hc_driver ohci_nxp_hc_driver = {
.start_port_reset = ohci_start_port_reset,
};
-#define USB_CLOCK_MASK (AHB_M_CLOCK_ON| OTG_CLOCK_ON | HOST_CLOCK_ON | I2C_CLOCK_ON)
-
static void nxp_set_usb_bits(void)
{
if (machine_is_pnx4008()) {
@@ -327,41 +317,63 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
/* Enable AHB slave USB clock, needed for further USB clock control */
__raw_writel(USB_SLAVE_HCLK_EN | PAD_CONTROL_LAST_DRIVEN, USB_CTRL);
- isp1301_configure();
-
/* Enable USB PLL */
- usb_clk = clk_get(&pdev->dev, "ck_pll5");
- if (IS_ERR(usb_clk)) {
+ usb_pll_clk = clk_get(&pdev->dev, "ck_pll5");
+ if (IS_ERR(usb_pll_clk)) {
dev_err(&pdev->dev, "failed to acquire USB PLL\n");
- ret = PTR_ERR(usb_clk);
+ ret = PTR_ERR(usb_pll_clk);
goto out1;
}
- ret = clk_enable(usb_clk);
+ ret = clk_enable(usb_pll_clk);
if (ret < 0) {
dev_err(&pdev->dev, "failed to start USB PLL\n");
goto out2;
}
- ret = clk_set_rate(usb_clk, 48000);
+ ret = clk_set_rate(usb_pll_clk, 48000);
if (ret < 0) {
dev_err(&pdev->dev, "failed to set USB clock rate\n");
goto out3;
}
+ /* Enable USB device clock */
+ usb_dev_clk = clk_get(&pdev->dev, "ck_usbd");
+ if (IS_ERR(usb_dev_clk)) {
+ dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n");
+ ret = PTR_ERR(usb_dev_clk);
+ goto out4;
+ }
+
+ ret = clk_enable(usb_dev_clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to start USB DEV Clock\n");
+ goto out5;
+ }
+
+ /* Enable USB otg clocks */
+ usb_otg_clk = clk_get(&pdev->dev, "ck_usb_otg");
+ if (IS_ERR(usb_otg_clk)) {
+ dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n");
+ ret = PTR_ERR(usb_dev_clk);
+ goto out6;
+ }
+
__raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL);
- /* Set to enable all needed USB clocks */
- __raw_writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL);
+ ret = clk_enable(usb_otg_clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to start USB DEV Clock\n");
+ goto out7;
+ }
- while ((__raw_readl(USB_OTG_CLK_STAT) & USB_CLOCK_MASK) !=
- USB_CLOCK_MASK) ;
+ isp1301_configure();
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) {
dev_err(&pdev->dev, "Failed to allocate HC buffer\n");
ret = -ENOMEM;
- goto out3;
+ goto out8;
}
/* Set all USB bits in the Start Enable register */
@@ -371,14 +383,14 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
if (!res) {
dev_err(&pdev->dev, "Failed to get MEM resource\n");
ret = -ENOMEM;
- goto out4;
+ goto out8;
}
hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
if (!hcd->regs) {
dev_err(&pdev->dev, "Failed to devm_request_and_ioremap\n");
ret = -ENOMEM;
- goto out4;
+ goto out8;
}
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
@@ -386,7 +398,7 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = -ENXIO;
- goto out4;
+ goto out8;
}
nxp_start_hc();
@@ -400,13 +412,21 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
return ret;
nxp_stop_hc();
-out4:
+out8:
nxp_unset_usb_bits();
usb_put_hcd(hcd);
+out7:
+ clk_disable(usb_otg_clk);
+out6:
+ clk_put(usb_otg_clk);
+out5:
+ clk_disable(usb_dev_clk);
+out4:
+ clk_put(usb_dev_clk);
out3:
- clk_disable(usb_clk);
+ clk_disable(usb_pll_clk);
out2:
- clk_put(usb_clk);
+ clk_put(usb_pll_clk);
out1:
isp1301_i2c_client = NULL;
out:
@@ -422,8 +442,10 @@ static int usb_hcd_nxp_remove(struct platform_device *pdev)
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
nxp_unset_usb_bits();
- clk_disable(usb_clk);
- clk_put(usb_clk);
+ clk_disable(usb_pll_clk);
+ clk_put(usb_pll_clk);
+ clk_disable(usb_dev_clk);
+ clk_put(usb_dev_clk);
i2c_unregister_device(isp1301_i2c_client);
isp1301_i2c_client = NULL;
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index b02c344..e7d75d2 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -18,6 +18,7 @@
#include <linux/jiffies.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/err.h>
#include <linux/gpio.h>
#include <asm/io.h>
@@ -168,14 +169,15 @@ static int omap_1510_local_bus_init(void)
static void start_hnp(struct ohci_hcd *ohci)
{
- const unsigned port = ohci_to_hcd(ohci)->self.otg_port - 1;
+ struct usb_hcd *hcd = ohci_to_hcd(ohci);
+ const unsigned port = hcd->self.otg_port - 1;
unsigned long flags;
u32 l;
- otg_start_hnp(ohci->transceiver->otg);
+ otg_start_hnp(hcd->phy->otg);
local_irq_save(flags);
- ohci->transceiver->state = OTG_STATE_A_SUSPEND;
+ hcd->phy->state = OTG_STATE_A_SUSPEND;
writel (RH_PS_PSS, &ohci->regs->roothub.portstatus [port]);
l = omap_readl(OTG_CTRL);
l &= ~OTG_A_BUSREQ;
@@ -212,18 +214,18 @@ static int ohci_omap_init(struct usb_hcd *hcd)
#ifdef CONFIG_USB_OTG
if (need_transceiver) {
- ohci->transceiver = usb_get_transceiver();
- if (ohci->transceiver) {
- int status = otg_set_host(ohci->transceiver->otg,
+ hcd->phy = usb_get_phy(USB_PHY_TYPE_USB2);
+ if (!IS_ERR_OR_NULL(hcd->phy)) {
+ int status = otg_set_host(hcd->phy->otg,
&ohci_to_hcd(ohci)->self);
- dev_dbg(hcd->self.controller, "init %s transceiver, status %d\n",
- ohci->transceiver->label, status);
+ dev_dbg(hcd->self.controller, "init %s phy, status %d\n",
+ hcd->phy->label, status);
if (status) {
- usb_put_transceiver(ohci->transceiver);
+ usb_put_phy(hcd->phy);
return status;
}
} else {
- dev_err(hcd->self.controller, "can't find transceiver\n");
+ dev_err(hcd->self.controller, "can't find phy\n");
return -ENODEV;
}
ohci->start_hnp = start_hnp;
@@ -404,9 +406,9 @@ usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
usb_remove_hcd(hcd);
- if (ohci->transceiver) {
- (void) otg_set_host(ohci->transceiver->otg, 0);
- usb_put_transceiver(ohci->transceiver);
+ if (!IS_ERR_OR_NULL(hcd->phy)) {
+ (void) otg_set_host(hcd->phy->otg, 0);
+ usb_put_phy(hcd->phy);
}
if (machine_is_omap_osk())
gpio_free(9);
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 1b19aea..d329914 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -372,11 +372,6 @@ struct ohci_hcd {
struct ed *ed_controltail; /* last in ctrl list */
struct ed *periodic [NUM_INTS]; /* shadow int_table */
- /*
- * OTG controllers and transceivers need software interaction;
- * other external transceivers should be software-transparent
- */
- struct usb_phy *transceiver;
void (*start_hnp)(struct ohci_hcd *ohci);
/*
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 7b01094..74bfc86 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -544,12 +544,18 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
if (hcd->speed != HCD_USB3)
goto error;
+ /* Set the U1 and U2 exit latencies. */
memcpy(buf, &usb_bos_descriptor,
USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE);
temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3);
buf[12] = HCS_U1_LATENCY(temp);
put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]);
+ /* Indicate whether the host has LTM support. */
+ temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
+ if (HCC_LTC(temp))
+ buf[8] |= USB_LTM_SUPPORT;
+
spin_unlock_irqrestore(&xhci->lock, flags);
return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE;
case GetPortStatus:
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index a979cd0..7648b2d 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -4450,6 +4450,8 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
/* Accept arbitrarily long scatter-gather lists */
hcd->self.sg_tablesize = ~0;
+ /* XHCI controllers don't stop the ep queue on short packets :| */
+ hcd->self.no_stop_on_short = 1;
if (usb_hcd_is_primary_hcd(hcd)) {
xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL);
OpenPOWER on IntegriCloud