diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-26 17:23:47 (GMT) |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-26 17:23:47 (GMT) |
commit | 9fc377799bc9bfd8d5cb35d0d1ea2e2458cbdbb3 (patch) | |
tree | fe93603b4e33dd50ff5f95ff769a0748b230cdf9 /drivers/usb/host | |
parent | 5e23ae49960d05f578a73ecd19749c45af682c2b (diff) | |
parent | e387ef5c47ddeaeaa3cbdc54424cdb7a28dae2c0 (diff) | |
download | linux-9fc377799bc9bfd8d5cb35d0d1ea2e2458cbdbb3.tar.xz |
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')
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(®s->usb_mod), in_8(®s->usb_addr), - in_8(®s->usb_comm), in_be16(®s->usb_ep[0]), - in_be16(®s->usb_event), in_be16(®s->usb_mask), - in_8(®s->usb_status), in_be16(®s->usb_sof_tmr), - in_be16(®s->usb_frame_num), + in_8(®s->usb_usmod), in_8(®s->usb_usadr), + in_8(®s->usb_uscom), in_be16(®s->usb_usep[0]), + in_be16(®s->usb_usber), in_be16(®s->usb_usbmr), + in_8(®s->usb_usbs), in_be16(®s->usb_ussft), + in_be16(®s->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); |