diff options
author | Scott Wood <scottwood@freescale.com> | 2014-04-07 23:49:35 (GMT) |
---|---|---|
committer | Scott Wood <scottwood@freescale.com> | 2014-04-07 23:49:35 (GMT) |
commit | 62b8c978ee6b8d135d9e7953221de58000dba986 (patch) | |
tree | 683b04b2e627f6710c22c151b23c8cc9a165315e /drivers/usb/host | |
parent | 78fd82238d0e5716578c326404184a27ba67fd6e (diff) | |
download | linux-fsl-qoriq-62b8c978ee6b8d135d9e7953221de58000dba986.tar.xz |
Rewind v3.13-rc3+ (78fd82238d0e5716) to v3.12
Diffstat (limited to 'drivers/usb/host')
68 files changed, 2257 insertions, 2152 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index a9707da..b3f20d7 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -54,7 +54,7 @@ config USB_EHCI_HCD config USB_EHCI_ROOT_HUB_TT bool "Root Hub Transaction Translators" - depends on USB_EHCI_HCD + depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST ---help--- Some EHCI chips have vendor-specific extensions to integrate transaction translators, so that no OHCI or UHCI companion @@ -66,7 +66,7 @@ config USB_EHCI_ROOT_HUB_TT config USB_EHCI_TT_NEWSCHED bool "Improved Transaction Translator scheduling" - depends on USB_EHCI_HCD + depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST default y ---help--- This changes the periodic scheduling code to fill more of the low @@ -203,11 +203,12 @@ config USB_EHCI_SH Enables support for the on-chip EHCI controller on the SuperH. If you use the PCI EHCI controller, this option is not necessary. -config USB_EHCI_EXYNOS +config USB_EHCI_S5P tristate "EHCI support for Samsung S5P/EXYNOS SoC Series" depends on PLAT_S5P || ARCH_EXYNOS help - Enable support for the Samsung Exynos SOC's on-chip EHCI controller. + Enable support for the Samsung S5Pxxxx and Exynos3/4/5 SOC's + on-chip EHCI controller. config USB_EHCI_MV bool "EHCI support for Marvell PXA/MMP USB controller" @@ -223,7 +224,7 @@ config USB_EHCI_MV on-chip EHCI USB controller" for those. config USB_W90X900_EHCI - tristate "W90X900(W90P910) EHCI support" + bool "W90X900(W90P910) EHCI support" depends on ARCH_W90X900 ---help--- Enables support for the W90X900 USB controller @@ -366,54 +367,14 @@ config USB_OHCI_HCD if USB_OHCI_HCD config USB_OHCI_HCD_OMAP1 - tristate "OHCI support for OMAP1/2 chips" + bool "OHCI support for OMAP1/2 chips" depends on ARCH_OMAP1 default y ---help--- Enables support for the OHCI controller on OMAP1/2 chips. -config USB_OHCI_HCD_SPEAR - tristate "Support for ST SPEAr on-chip OHCI USB controller" - depends on USB_OHCI_HCD && PLAT_SPEAR - default y - ---help--- - Enables support for the on-chip OHCI controller on - ST SPEAr chips. - -config USB_OHCI_HCD_S3C2410 - tristate "OHCI support for Samsung S3C24xx/S3C64xx SoC series" - depends on USB_OHCI_HCD && (ARCH_S3C24XX || ARCH_S3C64XX) - default y - ---help--- - Enables support for the on-chip OHCI controller on - S3C24xx/S3C64xx chips. - -config USB_OHCI_HCD_LPC32XX - tristate "Support for LPC on-chip OHCI USB controller" - depends on USB_OHCI_HCD && ARCH_LPC32XX - default y - ---help--- - Enables support for the on-chip OHCI controller on - NXP chips. - -config USB_OHCI_HCD_PXA27X - tristate "Support for PXA27X/PXA3XX on-chip OHCI USB controller" - depends on USB_OHCI_HCD && (PXA27x || PXA3xx) - default y - ---help--- - Enables support for the on-chip OHCI controller on - PXA27x/PXA3xx chips. - -config USB_OHCI_HCD_AT91 - tristate "Support for Atmel on-chip OHCI USB controller" - depends on USB_OHCI_HCD && ARCH_AT91 - default y - ---help--- - Enables support for the on-chip OHCI controller on - Atmel chips. - config USB_OHCI_HCD_OMAP3 - tristate "OHCI support for OMAP3 and later chips" + bool "OHCI support for OMAP3 and later chips" depends on (ARCH_OMAP3 || ARCH_OMAP4) default y ---help--- @@ -493,8 +454,8 @@ config USB_OHCI_SH If you use the PCI OHCI controller, this option is not necessary. config USB_OHCI_EXYNOS - tristate "OHCI support for Samsung S5P/EXYNOS SoC Series" - depends on PLAT_S5P || ARCH_EXYNOS + boolean "OHCI support for Samsung EXYNOS SoC Series" + depends on ARCH_EXYNOS help Enable support for the Samsung Exynos SOC's on-chip OHCI controller. diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 01e879e..50b0041 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -34,11 +34,10 @@ obj-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o obj-$(CONFIG_USB_EHCI_HCD_OMAP) += ehci-omap.o obj-$(CONFIG_USB_EHCI_HCD_ORION) += ehci-orion.o obj-$(CONFIG_USB_EHCI_HCD_SPEAR) += ehci-spear.o -obj-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o +obj-$(CONFIG_USB_EHCI_S5P) += ehci-s5p.o obj-$(CONFIG_USB_EHCI_HCD_AT91) += ehci-atmel.o obj-$(CONFIG_USB_EHCI_MSM) += ehci-msm.o obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o -obj-$(CONFIG_USB_W90X900_EHCI) += ehci-w90x900.o obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o @@ -47,14 +46,6 @@ obj-$(CONFIG_USB_ISP1362_HCD) += isp1362-hcd.o obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o obj-$(CONFIG_USB_OHCI_HCD_PCI) += ohci-pci.o obj-$(CONFIG_USB_OHCI_HCD_PLATFORM) += ohci-platform.o -obj-$(CONFIG_USB_OHCI_EXYNOS) += ohci-exynos.o -obj-$(CONFIG_USB_OHCI_HCD_OMAP1) += ohci-omap.o -obj-$(CONFIG_USB_OHCI_HCD_OMAP3) += ohci-omap3.o -obj-$(CONFIG_USB_OHCI_HCD_SPEAR) += ohci-spear.o -obj-$(CONFIG_USB_OHCI_HCD_AT91) += ohci-at91.o -obj-$(CONFIG_USB_OHCI_HCD_S3C2410) += ohci-s3c2410.o -obj-$(CONFIG_USB_OHCI_HCD_LPC32XX) += ohci-nxp.o -obj-$(CONFIG_USB_OHCI_HCD_PXA27X) += ohci-pxa27x.o obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o obj-$(CONFIG_USB_FHCI_HCD) += fhci.o diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 205f4a3..df13d42 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -227,7 +227,8 @@ static int bcma_hcd_probe(struct bcma_device *dev) /* TODO: Probably need checks here; is the core connected? */ - if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32))) + if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) || + dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32))) return -EOPNOTSUPP; usb_dev = kzalloc(sizeof(struct bcma_hcd_device), GFP_KERNEL); diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c index 284f841..3b645ff 100644 --- a/drivers/usb/host/ehci-atmel.c +++ b/drivers/usb/host/ehci-atmel.c @@ -30,17 +30,13 @@ static const char hcd_name[] = "ehci-atmel"; static struct hc_driver __read_mostly ehci_atmel_hc_driver; /* interface and function clocks */ -static struct clk *iclk, *fclk, *uclk; +static struct clk *iclk, *fclk; static int clocked; /*-------------------------------------------------------------------------*/ static void atmel_start_clock(void) { - if (IS_ENABLED(CONFIG_COMMON_CLK)) { - clk_set_rate(uclk, 48000000); - clk_prepare_enable(uclk); - } clk_prepare_enable(iclk); clk_prepare_enable(fclk); clocked = 1; @@ -50,8 +46,6 @@ static void atmel_stop_clock(void) { clk_disable_unprepare(fclk); clk_disable_unprepare(iclk); - if (IS_ENABLED(CONFIG_COMMON_CLK)) - clk_disable_unprepare(uclk); clocked = 0; } @@ -96,9 +90,10 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev) * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away. */ - retval = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (retval) - goto fail_create_hcd; + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { @@ -135,14 +130,6 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev) retval = -ENOENT; goto fail_request_resource; } - if (IS_ENABLED(CONFIG_COMMON_CLK)) { - uclk = devm_clk_get(&pdev->dev, "usb_clk"); - if (IS_ERR(uclk)) { - dev_err(&pdev->dev, "failed to get uclk\n"); - retval = PTR_ERR(uclk); - goto fail_request_resource; - } - } ehci = hcd_to_ehci(hcd); /* registers start at offset 0x0 */ diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 4a9c2ed..aa5b603 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -334,7 +334,6 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { } /* troubleshooting help: expose state in debugfs */ static int debug_async_open(struct inode *, struct file *); -static int debug_bandwidth_open(struct inode *, struct file *); static int debug_periodic_open(struct inode *, struct file *); static int debug_registers_open(struct inode *, struct file *); @@ -348,13 +347,6 @@ static const struct file_operations debug_async_fops = { .release = debug_close, .llseek = default_llseek, }; -static const struct file_operations debug_bandwidth_fops = { - .owner = THIS_MODULE, - .open = debug_bandwidth_open, - .read = debug_output, - .release = debug_close, - .llseek = default_llseek, -}; static const struct file_operations debug_periodic_fops = { .owner = THIS_MODULE, .open = debug_periodic_open, @@ -387,7 +379,7 @@ struct debug_buffer { case QH_LOW_SPEED: tmp = 'l'; break; \ case QH_HIGH_SPEED: tmp = 'h'; break; \ default: tmp = '?'; break; \ - } tmp; }) + }; tmp; }) static inline char token_mark(struct ehci_hcd *ehci, __hc32 token) { @@ -533,89 +525,6 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf) return strlen(buf->output_buf); } -static ssize_t fill_bandwidth_buffer(struct debug_buffer *buf) -{ - struct ehci_hcd *ehci; - struct ehci_tt *tt; - struct ehci_per_sched *ps; - unsigned temp, size; - char *next; - unsigned i; - u8 *bw; - u16 *bf; - u8 budget[EHCI_BANDWIDTH_SIZE]; - - ehci = hcd_to_ehci(bus_to_hcd(buf->bus)); - next = buf->output_buf; - size = buf->alloc_size; - - *next = 0; - - spin_lock_irq(&ehci->lock); - - /* Dump the HS bandwidth table */ - temp = scnprintf(next, size, - "HS bandwidth allocation (us per microframe)\n"); - size -= temp; - next += temp; - for (i = 0; i < EHCI_BANDWIDTH_SIZE; i += 8) { - bw = &ehci->bandwidth[i]; - temp = scnprintf(next, size, - "%2u: %4u%4u%4u%4u%4u%4u%4u%4u\n", - i, bw[0], bw[1], bw[2], bw[3], - bw[4], bw[5], bw[6], bw[7]); - size -= temp; - next += temp; - } - - /* Dump all the FS/LS tables */ - list_for_each_entry(tt, &ehci->tt_list, tt_list) { - temp = scnprintf(next, size, - "\nTT %s port %d FS/LS bandwidth allocation (us per frame)\n", - dev_name(&tt->usb_tt->hub->dev), - tt->tt_port + !!tt->usb_tt->multi); - size -= temp; - next += temp; - - bf = tt->bandwidth; - temp = scnprintf(next, size, - " %5u%5u%5u%5u%5u%5u%5u%5u\n", - bf[0], bf[1], bf[2], bf[3], - bf[4], bf[5], bf[6], bf[7]); - size -= temp; - next += temp; - - temp = scnprintf(next, size, - "FS/LS budget (us per microframe)\n"); - size -= temp; - next += temp; - compute_tt_budget(budget, tt); - for (i = 0; i < EHCI_BANDWIDTH_SIZE; i += 8) { - bw = &budget[i]; - temp = scnprintf(next, size, - "%2u: %4u%4u%4u%4u%4u%4u%4u%4u\n", - i, bw[0], bw[1], bw[2], bw[3], - bw[4], bw[5], bw[6], bw[7]); - size -= temp; - next += temp; - } - list_for_each_entry(ps, &tt->ps_list, ps_list) { - temp = scnprintf(next, size, - "%s ep %02x: %4u @ %2u.%u+%u mask %04x\n", - dev_name(&ps->udev->dev), - ps->ep->desc.bEndpointAddress, - ps->tt_usecs, - ps->bw_phase, ps->phase_uf, - ps->bw_period, ps->cs_mask); - size -= temp; - next += temp; - } - } - spin_unlock_irq(&ehci->lock); - - return next - buf->output_buf; -} - #define DBG_SCHED_LIMIT 64 static ssize_t fill_periodic_buffer(struct debug_buffer *buf) { @@ -662,7 +571,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf) case Q_TYPE_QH: hw = p.qh->hw; temp = scnprintf (next, size, " qh%d-%04x/%p", - p.qh->ps.period, + p.qh->period, hc32_to_cpup(ehci, &hw->hw_info2) /* uframe masks */ @@ -709,8 +618,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf) speed_char (scratch), scratch & 0x007f, (scratch >> 8) & 0x000f, type, - p.qh->ps.usecs, - p.qh->ps.c_usecs, + p.qh->usecs, p.qh->c_usecs, temp, 0x7ff & (scratch >> 16)); @@ -737,7 +645,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf) case Q_TYPE_SITD: temp = scnprintf (next, size, " sitd%d-%04x/%p", - p.sitd->stream->ps.period, + p.sitd->stream->interval, hc32_to_cpup(ehci, &p.sitd->hw_uframe) & 0x0000ffff, p.sitd); @@ -1010,7 +918,6 @@ static int debug_close(struct inode *inode, struct file *file) return 0; } - static int debug_async_open(struct inode *inode, struct file *file) { file->private_data = alloc_buffer(inode->i_private, fill_async_buffer); @@ -1018,14 +925,6 @@ static int debug_async_open(struct inode *inode, struct file *file) return file->private_data ? 0 : -ENOMEM; } -static int debug_bandwidth_open(struct inode *inode, struct file *file) -{ - file->private_data = alloc_buffer(inode->i_private, - fill_bandwidth_buffer); - - return file->private_data ? 0 : -ENOMEM; -} - static int debug_periodic_open(struct inode *inode, struct file *file) { struct debug_buffer *buf; @@ -1058,10 +957,6 @@ static inline void create_debug_files (struct ehci_hcd *ehci) &debug_async_fops)) goto file_error; - if (!debugfs_create_file("bandwidth", S_IRUGO, ehci->debug_dir, bus, - &debug_bandwidth_fops)) - goto file_error; - if (!debugfs_create_file("periodic", S_IRUGO, ehci->debug_dir, bus, &debug_periodic_fops)) goto file_error; diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index a06d501..f2407b2 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -57,7 +57,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, pr_debug("initializing FSL-SOC USB Controller\n"); /* Need platform data for setup */ - pdata = dev_get_platdata(&pdev->dev); + pdata = (struct fsl_usb2_platform_data *)dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(&pdev->dev, "No platform data for %s.\n", dev_name(&pdev->dev)); @@ -664,7 +664,7 @@ static const struct hc_driver ehci_fsl_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_USB2 | HCD_MEMORY | HCD_BH, + .flags = HCD_USB2 | HCD_MEMORY, /* * basic lifecycle operations diff --git a/drivers/usb/host/ehci-grlib.c b/drivers/usb/host/ehci-grlib.c index b52a66c..83ab51a 100644 --- a/drivers/usb/host/ehci-grlib.c +++ b/drivers/usb/host/ehci-grlib.c @@ -43,7 +43,7 @@ static const struct hc_driver ehci_grlib_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, + .flags = HCD_MEMORY | HCD_USB2, /* * basic lifecycle operations diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index e8ba4c4..86ab9fd 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -110,9 +110,6 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications"); #include "ehci.h" #include "pci-quirks.h" -static void compute_tt_budget(u8 budget_table[EHCI_BANDWIDTH_SIZE], - struct ehci_tt *tt); - /* * The MosChip MCS9990 controller updates its microframe counter * a little before the frame counter, and occasionally we will read @@ -487,7 +484,6 @@ static int ehci_init(struct usb_hcd *hcd) INIT_LIST_HEAD(&ehci->intr_qh_list); INIT_LIST_HEAD(&ehci->cached_itd_list); INIT_LIST_HEAD(&ehci->cached_sitd_list); - INIT_LIST_HEAD(&ehci->tt_list); if (HCC_PGM_FRAMELISTLEN(hcc_params)) { /* periodic schedule size can be smaller than default */ @@ -960,7 +956,6 @@ rescan: goto idle_timeout; /* BUG_ON(!list_empty(&stream->free_list)); */ - reserve_release_iso_bandwidth(ehci, stream, -1); kfree(stream); goto done; } @@ -987,8 +982,6 @@ idle_timeout: if (qh->clearing_tt) goto idle_timeout; if (list_empty (&qh->qtd_list)) { - if (qh->ps.bw_uperiod) - reserve_release_intr_bandwidth(ehci, qh, -1); qh_destroy(ehci, qh); break; } @@ -1029,6 +1022,7 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep) * the toggle bit in the QH. */ if (qh) { + usb_settoggle(qh->dev, epnum, is_out, 0); if (!list_empty(&qh->qtd_list)) { WARN_ONCE(1, "clear_halt for a busy endpoint\n"); } else { @@ -1036,7 +1030,6 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep) * while the QH is active. Unlink it now; * re-linking will call qh_refresh(). */ - usb_settoggle(qh->ps.udev, epnum, is_out, 0); qh->exception = 1; if (eptype == USB_ENDPOINT_XFER_BULK) start_unlink_async(ehci, qh); @@ -1055,19 +1048,6 @@ static int ehci_get_frame (struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ -/* Device addition and removal */ - -static void ehci_remove_device(struct usb_hcd *hcd, struct usb_device *udev) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - spin_lock_irq(&ehci->lock); - drop_tt(udev); - spin_unlock_irq(&ehci->lock); -} - -/*-------------------------------------------------------------------------*/ - #ifdef CONFIG_PM /* suspend/resume, section 4.3 */ @@ -1095,14 +1075,6 @@ int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup) clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); spin_unlock_irq(&ehci->lock); - synchronize_irq(hcd->irq); - - /* Check for race with a wakeup request */ - if (do_wakeup && HCD_WAKEUP_PENDING(hcd)) { - ehci_resume(hcd, false); - return -EBUSY; - } - return 0; } EXPORT_SYMBOL_GPL(ehci_suspend); @@ -1186,7 +1158,7 @@ static const struct hc_driver ehci_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, + .flags = HCD_MEMORY | HCD_USB2, /* * basic lifecycle operations @@ -1219,11 +1191,6 @@ static const struct hc_driver ehci_hc_driver = { .bus_resume = ehci_bus_resume, .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, - - /* - * device support - */ - .free_dev = ehci_remove_device, }; void ehci_init_driver(struct hc_driver *drv, @@ -1271,6 +1238,11 @@ MODULE_LICENSE ("GPL"); #define XILINX_OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver #endif +#ifdef CONFIG_USB_W90X900_EHCI +#include "ehci-w90x900.c" +#define PLATFORM_DRIVER ehci_hcd_w90x900_driver +#endif + #ifdef CONFIG_USB_OCTEON_EHCI #include "ehci-octeon.c" #define PLATFORM_DRIVER ehci_octeon_driver diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index c0fb6a8..52a7773 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -224,11 +224,11 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags) hw->hw_next = EHCI_LIST_END(ehci); hw->hw_qtd_next = EHCI_LIST_END(ehci); hw->hw_alt_next = EHCI_LIST_END(ehci); + hw->hw_token &= ~QTD_STS_ACTIVE; ehci->dummy->hw = hw; for (i = 0; i < ehci->periodic_size; i++) - ehci->periodic[i] = cpu_to_hc32(ehci, - ehci->dummy->qh_dma); + ehci->periodic[i] = ehci->dummy->qh_dma; } else { for (i = 0; i < ehci->periodic_size; i++) ehci->periodic[i] = EHCI_LIST_END(ehci); diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index f341651..0f717dc 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -42,6 +42,7 @@ static const char hcd_name[] = "ehci-msm"; static struct hc_driver __read_mostly msm_hc_driver; +static struct usb_phy *phy; static int ehci_msm_reset(struct usb_hcd *hcd) { @@ -69,7 +70,6 @@ static int ehci_msm_probe(struct platform_device *pdev) { struct usb_hcd *hcd; struct resource *res; - struct usb_phy *phy; int ret; dev_dbg(&pdev->dev, "ehci_msm proble\n"); @@ -108,14 +108,10 @@ static int ehci_msm_probe(struct platform_device *pdev) * powering up VBUS, mapping of registers address space and power * management. */ - if (pdev->dev.of_node) - phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); - else - phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); - + phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); if (IS_ERR(phy)) { dev_err(&pdev->dev, "unable to find transceiver\n"); - ret = -EPROBE_DEFER; + ret = -ENODEV; goto put_hcd; } @@ -125,7 +121,6 @@ static int ehci_msm_probe(struct platform_device *pdev) goto put_hcd; } - hcd->phy = phy; device_init_wakeup(&pdev->dev, 1); /* * OTG device parent of HCD takes care of putting @@ -152,7 +147,7 @@ static int ehci_msm_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); - otg_set_host(hcd->phy->otg, NULL); + otg_set_host(phy->otg, NULL); /* FIXME: need to call usb_remove_hcd() here? */ @@ -191,19 +186,12 @@ static const struct dev_pm_ops ehci_msm_dev_pm_ops = { .resume = ehci_msm_pm_resume, }; -static struct of_device_id msm_ehci_dt_match[] = { - { .compatible = "qcom,ehci-host", }, - {} -}; -MODULE_DEVICE_TABLE(of, msm_ehci_dt_match); - static struct platform_driver ehci_msm_driver = { .probe = ehci_msm_probe, .remove = ehci_msm_remove, .driver = { .name = "msm_hsusb_host", .pm = &ehci_msm_dev_pm_ops, - .of_match_table = msm_ehci_dt_match, }, }; diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index 417c10d..35cdbd8 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -96,7 +96,7 @@ static const struct hc_driver mv_ehci_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, + .flags = HCD_MEMORY | HCD_USB2, /* * basic lifecycle operations diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c index 4c528b2..45cc001 100644 --- a/drivers/usb/host/ehci-octeon.c +++ b/drivers/usb/host/ehci-octeon.c @@ -51,7 +51,7 @@ static const struct hc_driver ehci_octeon_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, + .flags = HCD_MEMORY | HCD_USB2, /* * basic lifecycle operations @@ -116,10 +116,8 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev) * We can DMA from anywhere. But the descriptors must be in * the lower 4GB. */ + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); pdev->dev.dma_mask = &ehci_octeon_dma_mask; - ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; hcd = usb_create_hcd(&ehci_octeon_hc_driver, &pdev->dev, "octeon"); if (!hcd) diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 6fa82d6..78b01fa 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -104,7 +104,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) struct resource *res; struct usb_hcd *hcd; void __iomem *regs; - int ret; + int ret = -ENODEV; int irq; int i; struct omap_hcd *omap; @@ -144,11 +144,11 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away. */ - ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); - if (ret) - return ret; + if (!dev->dma_mask) + dev->dma_mask = &dev->coherent_dma_mask; + if (!dev->coherent_dma_mask) + dev->coherent_dma_mask = DMA_BIT_MASK(32); - ret = -ENODEV; hcd = usb_create_hcd(&ehci_omap_hc_driver, dev, dev_name(dev)); if (!hcd) { diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 2ba7673..d1dfb9d 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -180,9 +180,10 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) * set. Since shared usb code relies on it, set it here for * now. Once we have dma capability bindings this can go away. */ - err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (err) - goto err1; + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); if (!request_mem_region(res->start, resource_size(res), ehci_orion_hc_driver.description)) { diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 3e86bf4..854c2ec 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -58,6 +58,8 @@ static int ehci_pci_setup(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + struct pci_dev *p_smbus; + u8 rev; u32 temp; int retval; @@ -173,12 +175,22 @@ static int ehci_pci_setup(struct usb_hcd *hcd) /* SB600 and old version of SB700 have a bug in EHCI controller, * which causes usb devices lose response in some cases. */ - if ((pdev->device == 0x4386 || pdev->device == 0x4396) && - usb_amd_hang_symptom_quirk()) { - u8 tmp; - ehci_info(ehci, "applying AMD SB600/SB700 USB freeze workaround\n"); - pci_read_config_byte(pdev, 0x53, &tmp); - pci_write_config_byte(pdev, 0x53, tmp | (1<<3)); + if ((pdev->device == 0x4386) || (pdev->device == 0x4396)) { + p_smbus = pci_get_device(PCI_VENDOR_ID_ATI, + PCI_DEVICE_ID_ATI_SBX00_SMBUS, + NULL); + if (!p_smbus) + break; + rev = p_smbus->revision; + if ((pdev->device == 0x4386) || (rev == 0x3a) + || (rev == 0x3b)) { + u8 tmp; + ehci_info(ehci, "applying AMD SB600/SB700 USB " + "freeze workaround\n"); + pci_read_config_byte(pdev, 0x53, &tmp); + pci_write_config_byte(pdev, 0x53, tmp | (1<<3)); + } + pci_dev_put(p_smbus); } break; case PCI_VENDOR_ID_NETMOS: diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 7f30b71..f6b790c 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -78,7 +78,7 @@ static int ehci_platform_probe(struct platform_device *dev) struct resource *res_mem; struct usb_ehci_pdata *pdata; int irq; - int err; + int err = -ENOMEM; if (usb_disabled()) return -ENODEV; @@ -89,10 +89,10 @@ static int ehci_platform_probe(struct platform_device *dev) */ if (!dev_get_platdata(&dev->dev)) dev->dev.platform_data = &ehci_platform_defaults; - - err = dma_coerce_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)); - if (err) - return err; + if (!dev->dev.dma_mask) + dev->dev.dma_mask = &dev->dev.coherent_dma_mask; + if (!dev->dev.coherent_dma_mask) + dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); pdata = dev_get_platdata(&dev->dev); diff --git a/drivers/usb/host/ehci-pmcmsp.c b/drivers/usb/host/ehci-pmcmsp.c index 893b707..601e208 100644 --- a/drivers/usb/host/ehci-pmcmsp.c +++ b/drivers/usb/host/ehci-pmcmsp.c @@ -286,7 +286,7 @@ static const struct hc_driver ehci_msp_hc_driver = { #else .irq = ehci_irq, #endif - .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, + .flags = HCD_MEMORY | HCD_USB2, /* * basic lifecycle operations diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c index 875d2fc..932293f 100644 --- a/drivers/usb/host/ehci-ppc-of.c +++ b/drivers/usb/host/ehci-ppc-of.c @@ -16,8 +16,6 @@ #include <linux/signal.h> #include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> #include <linux/of_platform.h> @@ -30,7 +28,7 @@ static const struct hc_driver ehci_ppc_of_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, + .flags = HCD_MEMORY | HCD_USB2, /* * basic lifecycle operations diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 8188542..fd98377 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -71,7 +71,7 @@ static const struct hc_driver ps3_ehci_hc_driver = { .product_desc = "PS3 EHCI Host Controller", .hcd_priv_size = sizeof(struct ehci_hcd), .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, + .flags = HCD_MEMORY | HCD_USB2, .reset = ps3_ehci_hc_reset, .start = ehci_run, .stop = ehci_stop, diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index db05bd8..a7f776a 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -105,9 +105,9 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) is_out = qh->is_out; epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f; - if (unlikely(!usb_gettoggle(qh->ps.udev, epnum, is_out))) { + if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); - usb_settoggle(qh->ps.udev, epnum, is_out, 1); + usb_settoggle (qh->dev, epnum, is_out, 1); } } @@ -247,6 +247,8 @@ static int qtd_copy_status ( static void ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status) +__releases(ehci->lock) +__acquires(ehci->lock) { if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { /* ... update hc-wide periodic stats */ @@ -272,8 +274,11 @@ ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status) urb->actual_length, urb->transfer_buffer_length); #endif + /* complete() can reenter this HCD */ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); + spin_unlock (&ehci->lock); usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status); + spin_lock (&ehci->lock); } static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh); @@ -797,35 +802,26 @@ qh_make ( * For control/bulk requests, the HC or TT handles these. */ if (type == PIPE_INTERRUPT) { - unsigned tmp; - - qh->ps.usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH, + qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH, is_input, 0, hb_mult(maxp) * max_packet(maxp))); - qh->ps.phase = NO_FRAME; + qh->start = NO_FRAME; if (urb->dev->speed == USB_SPEED_HIGH) { - qh->ps.c_usecs = 0; + qh->c_usecs = 0; qh->gap_uf = 0; - if (urb->interval > 1 && urb->interval < 8) { + qh->period = urb->interval >> 3; + if (qh->period == 0 && urb->interval != 1) { /* NOTE interval 2 or 4 uframes could work. * But interval 1 scheduling is simpler, and * includes high bandwidth. */ urb->interval = 1; - } else if (urb->interval > ehci->periodic_size << 3) { - urb->interval = ehci->periodic_size << 3; + } else if (qh->period > ehci->periodic_size) { + qh->period = ehci->periodic_size; + urb->interval = qh->period << 3; } - qh->ps.period = urb->interval >> 3; - - /* period for bandwidth allocation */ - tmp = min_t(unsigned, EHCI_BANDWIDTH_SIZE, - 1 << (urb->ep->desc.bInterval - 1)); - - /* Allow urb->interval to override */ - qh->ps.bw_uperiod = min_t(unsigned, tmp, urb->interval); - qh->ps.bw_period = qh->ps.bw_uperiod >> 3; } else { int think_time; @@ -835,35 +831,27 @@ qh_make ( /* FIXME this just approximates SPLIT/CSPLIT times */ if (is_input) { // SPLIT, gap, CSPLIT+DATA - qh->ps.c_usecs = qh->ps.usecs + HS_USECS(0); - qh->ps.usecs = HS_USECS(1); + qh->c_usecs = qh->usecs + HS_USECS (0); + qh->usecs = HS_USECS (1); } else { // SPLIT+DATA, gap, CSPLIT - qh->ps.usecs += HS_USECS(1); - qh->ps.c_usecs = HS_USECS(0); + qh->usecs += HS_USECS (1); + qh->c_usecs = HS_USECS (0); } think_time = tt ? tt->think_time : 0; - qh->ps.tt_usecs = NS_TO_US(think_time + + qh->tt_usecs = NS_TO_US (think_time + usb_calc_bus_time (urb->dev->speed, is_input, 0, max_packet (maxp))); - if (urb->interval > ehci->periodic_size) - urb->interval = ehci->periodic_size; - qh->ps.period = urb->interval; - - /* period for bandwidth allocation */ - tmp = min_t(unsigned, EHCI_BANDWIDTH_FRAMES, - urb->ep->desc.bInterval); - tmp = rounddown_pow_of_two(tmp); - - /* Allow urb->interval to override */ - qh->ps.bw_period = min_t(unsigned, tmp, urb->interval); - qh->ps.bw_uperiod = qh->ps.bw_period << 3; + qh->period = urb->interval; + if (qh->period > ehci->periodic_size) { + qh->period = ehci->periodic_size; + urb->interval = qh->period; + } } } /* support for tt scheduling, and access to toggles */ - qh->ps.udev = urb->dev; - qh->ps.ep = urb->ep; + qh->dev = urb->dev; /* using TT? */ switch (urb->dev->speed) { diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-s5p.c index e97c198..7c3de95 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-s5p.c @@ -1,5 +1,5 @@ /* - * SAMSUNG EXYNOS USB HOST EHCI Controller + * SAMSUNG S5P USB HOST EHCI Controller * * Copyright (C) 2011 Samsung Electronics Co.Ltd * Author: Jingoo Han <jg1.han@samsung.com> @@ -20,6 +20,7 @@ #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/platform_device.h> +#include <linux/platform_data/usb-ehci-s5p.h> #include <linux/usb/phy.h> #include <linux/usb/samsung_usb_phy.h> #include <linux/usb.h> @@ -28,7 +29,7 @@ #include "ehci.h" -#define DRIVER_DESC "EHCI EXYNOS driver" +#define DRIVER_DESC "EHCI s5p driver" #define EHCI_INSNREG00(base) (base + 0x90) #define EHCI_INSNREG00_ENA_INCR16 (0x1 << 25) @@ -39,18 +40,21 @@ (EHCI_INSNREG00_ENA_INCR16 | EHCI_INSNREG00_ENA_INCR8 | \ EHCI_INSNREG00_ENA_INCR4 | EHCI_INSNREG00_ENA_INCRX_ALIGN) -static const char hcd_name[] = "ehci-exynos"; -static struct hc_driver __read_mostly exynos_ehci_hc_driver; +static const char hcd_name[] = "ehci-s5p"; +static struct hc_driver __read_mostly s5p_ehci_hc_driver; -struct exynos_ehci_hcd { +struct s5p_ehci_hcd { struct clk *clk; struct usb_phy *phy; struct usb_otg *otg; + struct s5p_ehci_platdata *pdata; }; -#define to_exynos_ehci(hcd) (struct exynos_ehci_hcd *)(hcd_to_ehci(hcd)->priv) +static struct s5p_ehci_platdata empty_platdata; -static void exynos_setup_vbus_gpio(struct platform_device *pdev) +#define to_s5p_ehci(hcd) (struct s5p_ehci_hcd *)(hcd_to_ehci(hcd)->priv) + +static void s5p_setup_vbus_gpio(struct platform_device *pdev) { struct device *dev = &pdev->dev; int err; @@ -69,9 +73,10 @@ static void exynos_setup_vbus_gpio(struct platform_device *pdev) dev_err(dev, "can't request ehci vbus gpio %d", gpio); } -static int exynos_ehci_probe(struct platform_device *pdev) +static int s5p_ehci_probe(struct platform_device *pdev) { - struct exynos_ehci_hcd *exynos_ehci; + struct s5p_ehci_platdata *pdata = dev_get_platdata(&pdev->dev); + struct s5p_ehci_hcd *s5p_ehci; struct usb_hcd *hcd; struct ehci_hcd *ehci; struct resource *res; @@ -84,45 +89,53 @@ static int exynos_ehci_probe(struct platform_device *pdev) * Since shared usb code relies on it, set it here for now. * Once we move to full device tree support this will vanish off. */ - err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (err) - return err; + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - exynos_setup_vbus_gpio(pdev); + s5p_setup_vbus_gpio(pdev); - hcd = usb_create_hcd(&exynos_ehci_hc_driver, + hcd = usb_create_hcd(&s5p_ehci_hc_driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { dev_err(&pdev->dev, "Unable to create HCD\n"); return -ENOMEM; } - exynos_ehci = to_exynos_ehci(hcd); + s5p_ehci = to_s5p_ehci(hcd); if (of_device_is_compatible(pdev->dev.of_node, - "samsung,exynos5440-ehci")) + "samsung,exynos5440-ehci")) { + s5p_ehci->pdata = &empty_platdata; goto skip_phy; + } phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); if (IS_ERR(phy)) { - usb_put_hcd(hcd); - dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); - return -EPROBE_DEFER; + /* Fallback to pdata */ + if (!pdata) { + usb_put_hcd(hcd); + dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); + return -EPROBE_DEFER; + } else { + s5p_ehci->pdata = pdata; + } } else { - exynos_ehci->phy = phy; - exynos_ehci->otg = phy->otg; + s5p_ehci->phy = phy; + s5p_ehci->otg = phy->otg; } skip_phy: - exynos_ehci->clk = devm_clk_get(&pdev->dev, "usbhost"); + s5p_ehci->clk = devm_clk_get(&pdev->dev, "usbhost"); - if (IS_ERR(exynos_ehci->clk)) { + if (IS_ERR(s5p_ehci->clk)) { dev_err(&pdev->dev, "Failed to get usbhost clock\n"); - err = PTR_ERR(exynos_ehci->clk); + err = PTR_ERR(s5p_ehci->clk); goto fail_clk; } - err = clk_prepare_enable(exynos_ehci->clk); + err = clk_prepare_enable(s5p_ehci->clk); if (err) goto fail_clk; @@ -149,11 +162,13 @@ skip_phy: goto fail_io; } - if (exynos_ehci->otg) - exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self); + if (s5p_ehci->otg) + s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self); - if (exynos_ehci->phy) - usb_phy_init(exynos_ehci->phy); + if (s5p_ehci->phy) + usb_phy_init(s5p_ehci->phy); + else if (s5p_ehci->pdata->phy_init) + s5p_ehci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST); ehci = hcd_to_ehci(hcd); ehci->caps = hcd->regs; @@ -172,29 +187,33 @@ skip_phy: return 0; fail_add_hcd: - if (exynos_ehci->phy) - usb_phy_shutdown(exynos_ehci->phy); + if (s5p_ehci->phy) + usb_phy_shutdown(s5p_ehci->phy); + else if (s5p_ehci->pdata->phy_exit) + s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); fail_io: - clk_disable_unprepare(exynos_ehci->clk); + clk_disable_unprepare(s5p_ehci->clk); fail_clk: usb_put_hcd(hcd); return err; } -static int exynos_ehci_remove(struct platform_device *pdev) +static int s5p_ehci_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd); + struct s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd); usb_remove_hcd(hcd); - if (exynos_ehci->otg) - exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self); + if (s5p_ehci->otg) + s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self); - if (exynos_ehci->phy) - usb_phy_shutdown(exynos_ehci->phy); + if (s5p_ehci->phy) + usb_phy_shutdown(s5p_ehci->phy); + else if (s5p_ehci->pdata->phy_exit) + s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); - clk_disable_unprepare(exynos_ehci->clk); + clk_disable_unprepare(s5p_ehci->clk); usb_put_hcd(hcd); @@ -202,39 +221,45 @@ static int exynos_ehci_remove(struct platform_device *pdev) } #ifdef CONFIG_PM -static int exynos_ehci_suspend(struct device *dev) +static int s5p_ehci_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); - struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd); + struct s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd); + struct platform_device *pdev = to_platform_device(dev); bool do_wakeup = device_may_wakeup(dev); int rc; rc = ehci_suspend(hcd, do_wakeup); - if (exynos_ehci->otg) - exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self); + if (s5p_ehci->otg) + s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self); - if (exynos_ehci->phy) - usb_phy_shutdown(exynos_ehci->phy); + if (s5p_ehci->phy) + usb_phy_shutdown(s5p_ehci->phy); + else if (s5p_ehci->pdata->phy_exit) + s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); - clk_disable_unprepare(exynos_ehci->clk); + clk_disable_unprepare(s5p_ehci->clk); return rc; } -static int exynos_ehci_resume(struct device *dev) +static int s5p_ehci_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); - struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd); + struct s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd); + struct platform_device *pdev = to_platform_device(dev); - clk_prepare_enable(exynos_ehci->clk); + clk_prepare_enable(s5p_ehci->clk); - if (exynos_ehci->otg) - exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self); + if (s5p_ehci->otg) + s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self); - if (exynos_ehci->phy) - usb_phy_init(exynos_ehci->phy); + if (s5p_ehci->phy) + usb_phy_init(s5p_ehci->phy); + else if (s5p_ehci->pdata->phy_init) + s5p_ehci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST); /* DMA burst Enable */ writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); @@ -243,13 +268,13 @@ static int exynos_ehci_resume(struct device *dev) return 0; } #else -#define exynos_ehci_suspend NULL -#define exynos_ehci_resume NULL +#define s5p_ehci_suspend NULL +#define s5p_ehci_resume NULL #endif -static const struct dev_pm_ops exynos_ehci_pm_ops = { - .suspend = exynos_ehci_suspend, - .resume = exynos_ehci_resume, +static const struct dev_pm_ops s5p_ehci_pm_ops = { + .suspend = s5p_ehci_suspend, + .resume = s5p_ehci_resume, }; #ifdef CONFIG_OF @@ -261,40 +286,40 @@ static const struct of_device_id exynos_ehci_match[] = { MODULE_DEVICE_TABLE(of, exynos_ehci_match); #endif -static struct platform_driver exynos_ehci_driver = { - .probe = exynos_ehci_probe, - .remove = exynos_ehci_remove, +static struct platform_driver s5p_ehci_driver = { + .probe = s5p_ehci_probe, + .remove = s5p_ehci_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { - .name = "exynos-ehci", + .name = "s5p-ehci", .owner = THIS_MODULE, - .pm = &exynos_ehci_pm_ops, + .pm = &s5p_ehci_pm_ops, .of_match_table = of_match_ptr(exynos_ehci_match), } }; -static const struct ehci_driver_overrides exynos_overrides __initdata = { - .extra_priv_size = sizeof(struct exynos_ehci_hcd), +static const struct ehci_driver_overrides s5p_overrides __initdata = { + .extra_priv_size = sizeof(struct s5p_ehci_hcd), }; -static int __init ehci_exynos_init(void) +static int __init ehci_s5p_init(void) { if (usb_disabled()) return -ENODEV; pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ehci_init_driver(&exynos_ehci_hc_driver, &exynos_overrides); - return platform_driver_register(&exynos_ehci_driver); + ehci_init_driver(&s5p_ehci_hc_driver, &s5p_overrides); + return platform_driver_register(&s5p_ehci_driver); } -module_init(ehci_exynos_init); +module_init(ehci_s5p_init); -static void __exit ehci_exynos_cleanup(void) +static void __exit ehci_s5p_cleanup(void) { - platform_driver_unregister(&exynos_ehci_driver); + platform_driver_unregister(&s5p_ehci_driver); } -module_exit(ehci_exynos_cleanup); +module_exit(ehci_s5p_cleanup); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_ALIAS("platform:exynos-ehci"); +MODULE_ALIAS("platform:s5p-ehci"); MODULE_AUTHOR("Jingoo Han"); MODULE_AUTHOR("Joonyoung Shim"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index e113fd7..85dd24e 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -103,210 +103,83 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) *hw_p = *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p)); else - *hw_p = cpu_to_hc32(ehci, ehci->dummy->qh_dma); + *hw_p = ehci->dummy->qh_dma; } -/*-------------------------------------------------------------------------*/ - -/* Bandwidth and TT management */ - -/* Find the TT data structure for this device; create it if necessary */ -static struct ehci_tt *find_tt(struct usb_device *udev) +/* how many of the uframe's 125 usecs are allocated? */ +static unsigned short +periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) { - struct usb_tt *utt = udev->tt; - struct ehci_tt *tt, **tt_index, **ptt; - unsigned port; - bool allocated_index = false; - - if (!utt) - return NULL; /* Not below a TT */ - - /* - * Find/create our data structure. - * For hubs with a single TT, we get it directly. - * For hubs with multiple TTs, there's an extra level of pointers. - */ - tt_index = NULL; - if (utt->multi) { - tt_index = utt->hcpriv; - if (!tt_index) { /* Create the index array */ - tt_index = kzalloc(utt->hub->maxchild * - sizeof(*tt_index), GFP_ATOMIC); - if (!tt_index) - return ERR_PTR(-ENOMEM); - utt->hcpriv = tt_index; - allocated_index = true; - } - port = udev->ttport - 1; - ptt = &tt_index[port]; - } else { - port = 0; - ptt = (struct ehci_tt **) &utt->hcpriv; - } - - tt = *ptt; - if (!tt) { /* Create the ehci_tt */ - struct ehci_hcd *ehci = - hcd_to_ehci(bus_to_hcd(udev->bus)); - - tt = kzalloc(sizeof(*tt), GFP_ATOMIC); - if (!tt) { - if (allocated_index) { - utt->hcpriv = NULL; - kfree(tt_index); + __hc32 *hw_p = &ehci->periodic [frame]; + union ehci_shadow *q = &ehci->pshadow [frame]; + unsigned usecs = 0; + struct ehci_qh_hw *hw; + + while (q->ptr) { + switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) { + case Q_TYPE_QH: + hw = q->qh->hw; + /* is it in the S-mask? */ + if (hw->hw_info2 & cpu_to_hc32(ehci, 1 << uframe)) + usecs += q->qh->usecs; + /* ... or C-mask? */ + if (hw->hw_info2 & cpu_to_hc32(ehci, + 1 << (8 + uframe))) + usecs += q->qh->c_usecs; + hw_p = &hw->hw_next; + q = &q->qh->qh_next; + break; + // case Q_TYPE_FSTN: + default: + /* for "save place" FSTNs, count the relevant INTR + * bandwidth from the previous frame + */ + if (q->fstn->hw_prev != EHCI_LIST_END(ehci)) { + ehci_dbg (ehci, "ignoring FSTN cost ...\n"); } - return ERR_PTR(-ENOMEM); - } - list_add_tail(&tt->tt_list, &ehci->tt_list); - INIT_LIST_HEAD(&tt->ps_list); - tt->usb_tt = utt; - tt->tt_port = port; - *ptt = tt; - } - - return tt; -} - -/* Release the TT above udev, if it's not in use */ -static void drop_tt(struct usb_device *udev) -{ - struct usb_tt *utt = udev->tt; - struct ehci_tt *tt, **tt_index, **ptt; - int cnt, i; - - if (!utt || !utt->hcpriv) - return; /* Not below a TT, or never allocated */ - - cnt = 0; - if (utt->multi) { - tt_index = utt->hcpriv; - ptt = &tt_index[udev->ttport - 1]; - - /* How many entries are left in tt_index? */ - for (i = 0; i < utt->hub->maxchild; ++i) - cnt += !!tt_index[i]; - } else { - tt_index = NULL; - ptt = (struct ehci_tt **) &utt->hcpriv; - } - - tt = *ptt; - if (!tt || !list_empty(&tt->ps_list)) - return; /* never allocated, or still in use */ - - list_del(&tt->tt_list); - *ptt = NULL; - kfree(tt); - if (cnt == 1) { - utt->hcpriv = NULL; - kfree(tt_index); - } -} - -static void bandwidth_dbg(struct ehci_hcd *ehci, int sign, char *type, - struct ehci_per_sched *ps) -{ - dev_dbg(&ps->udev->dev, - "ep %02x: %s %s @ %u+%u (%u.%u+%u) [%u/%u us] mask %04x\n", - ps->ep->desc.bEndpointAddress, - (sign >= 0 ? "reserve" : "release"), type, - (ps->bw_phase << 3) + ps->phase_uf, ps->bw_uperiod, - ps->phase, ps->phase_uf, ps->period, - ps->usecs, ps->c_usecs, ps->cs_mask); -} - -static void reserve_release_intr_bandwidth(struct ehci_hcd *ehci, - struct ehci_qh *qh, int sign) -{ - unsigned start_uf; - unsigned i, j, m; - int usecs = qh->ps.usecs; - int c_usecs = qh->ps.c_usecs; - int tt_usecs = qh->ps.tt_usecs; - struct ehci_tt *tt; - - if (qh->ps.phase == NO_FRAME) /* Bandwidth wasn't reserved */ - return; - start_uf = qh->ps.bw_phase << 3; - - bandwidth_dbg(ehci, sign, "intr", &qh->ps); - - if (sign < 0) { /* Release bandwidth */ - usecs = -usecs; - c_usecs = -c_usecs; - tt_usecs = -tt_usecs; - } - - /* Entire transaction (high speed) or start-split (full/low speed) */ - for (i = start_uf + qh->ps.phase_uf; i < EHCI_BANDWIDTH_SIZE; - i += qh->ps.bw_uperiod) - ehci->bandwidth[i] += usecs; - - /* Complete-split (full/low speed) */ - if (qh->ps.c_usecs) { - /* NOTE: adjustments needed for FSTN */ - for (i = start_uf; i < EHCI_BANDWIDTH_SIZE; - i += qh->ps.bw_uperiod) { - for ((j = 2, m = 1 << (j+8)); j < 8; (++j, m <<= 1)) { - if (qh->ps.cs_mask & m) - ehci->bandwidth[i+j] += c_usecs; + hw_p = &q->fstn->hw_next; + q = &q->fstn->fstn_next; + break; + case Q_TYPE_ITD: + if (q->itd->hw_transaction[uframe]) + usecs += q->itd->stream->usecs; + hw_p = &q->itd->hw_next; + q = &q->itd->itd_next; + break; + case Q_TYPE_SITD: + /* is it in the S-mask? (count SPLIT, DATA) */ + if (q->sitd->hw_uframe & cpu_to_hc32(ehci, + 1 << uframe)) { + if (q->sitd->hw_fullspeed_ep & + cpu_to_hc32(ehci, 1<<31)) + usecs += q->sitd->stream->usecs; + else /* worst case for OUT start-split */ + usecs += HS_USECS_ISO (188); } - } - } - /* FS/LS bus bandwidth */ - if (tt_usecs) { - tt = find_tt(qh->ps.udev); - if (sign > 0) - list_add_tail(&qh->ps.ps_list, &tt->ps_list); - else - list_del(&qh->ps.ps_list); + /* ... C-mask? (count CSPLIT, DATA) */ + if (q->sitd->hw_uframe & + cpu_to_hc32(ehci, 1 << (8 + uframe))) { + /* worst case for IN complete-split */ + usecs += q->sitd->stream->c_usecs; + } - for (i = start_uf >> 3; i < EHCI_BANDWIDTH_FRAMES; - i += qh->ps.bw_period) - tt->bandwidth[i] += tt_usecs; + hw_p = &q->sitd->hw_next; + q = &q->sitd->sitd_next; + break; + } } +#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) + if (usecs > ehci->uframe_periodic_max) + ehci_err (ehci, "uframe %d sched overrun: %d usecs\n", + frame * 8 + uframe, usecs); +#endif + return usecs; } /*-------------------------------------------------------------------------*/ -static void compute_tt_budget(u8 budget_table[EHCI_BANDWIDTH_SIZE], - struct ehci_tt *tt) -{ - struct ehci_per_sched *ps; - unsigned uframe, uf, x; - u8 *budget_line; - - if (!tt) - return; - memset(budget_table, 0, EHCI_BANDWIDTH_SIZE); - - /* Add up the contributions from all the endpoints using this TT */ - list_for_each_entry(ps, &tt->ps_list, ps_list) { - for (uframe = ps->bw_phase << 3; uframe < EHCI_BANDWIDTH_SIZE; - uframe += ps->bw_uperiod) { - budget_line = &budget_table[uframe]; - x = ps->tt_usecs; - - /* propagate the time forward */ - for (uf = ps->phase_uf; uf < 8; ++uf) { - x += budget_line[uf]; - - /* Each microframe lasts 125 us */ - if (x <= 125) { - budget_line[uf] = x; - break; - } else { - budget_line[uf] = 125; - x -= 125; - } - } - } - } -} - -static int __maybe_unused same_tt(struct usb_device *dev1, - struct usb_device *dev2) +static int same_tt (struct usb_device *dev1, struct usb_device *dev2) { if (!dev1->tt || !dev2->tt) return 0; @@ -354,6 +227,68 @@ static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8]) } } +/* How many of the tt's periodic downstream 1000 usecs are allocated? + * + * While this measures the bandwidth in terms of usecs/uframe, + * the low/fullspeed bus has no notion of uframes, so any particular + * low/fullspeed transfer can "carry over" from one uframe to the next, + * since the TT just performs downstream transfers in sequence. + * + * For example two separate 100 usec transfers can start in the same uframe, + * and the second one would "carry over" 75 usecs into the next uframe. + */ +static void +periodic_tt_usecs ( + struct ehci_hcd *ehci, + struct usb_device *dev, + unsigned frame, + unsigned short tt_usecs[8] +) +{ + __hc32 *hw_p = &ehci->periodic [frame]; + union ehci_shadow *q = &ehci->pshadow [frame]; + unsigned char uf; + + memset(tt_usecs, 0, 16); + + while (q->ptr) { + switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) { + case Q_TYPE_ITD: + hw_p = &q->itd->hw_next; + q = &q->itd->itd_next; + continue; + case Q_TYPE_QH: + if (same_tt(dev, q->qh->dev)) { + uf = tt_start_uframe(ehci, q->qh->hw->hw_info2); + tt_usecs[uf] += q->qh->tt_usecs; + } + hw_p = &q->qh->hw->hw_next; + q = &q->qh->qh_next; + continue; + case Q_TYPE_SITD: + if (same_tt(dev, q->sitd->urb->dev)) { + uf = tt_start_uframe(ehci, q->sitd->hw_uframe); + tt_usecs[uf] += q->sitd->stream->tt_usecs; + } + hw_p = &q->sitd->hw_next; + q = &q->sitd->sitd_next; + continue; + // case Q_TYPE_FSTN: + default: + ehci_dbg(ehci, "ignoring periodic frame %d FSTN\n", + frame); + hw_p = &q->fstn->hw_next; + q = &q->fstn->fstn_next; + } + } + + carryover_tt_bandwidth(tt_usecs); + + if (max_tt_usecs[7] < tt_usecs[7]) + ehci_err(ehci, "frame %d tt sched overrun: %d usecs\n", + frame, tt_usecs[7] - max_tt_usecs[7]); +} + /* * Return true if the device's tt's downstream bus is available for a * periodic transfer of the specified length (usecs), starting at the @@ -377,29 +312,20 @@ static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8]) */ static int tt_available ( struct ehci_hcd *ehci, - struct ehci_per_sched *ps, - struct ehci_tt *tt, + unsigned period, + struct usb_device *dev, unsigned frame, - unsigned uframe + unsigned uframe, + u16 usecs ) { - unsigned period = ps->bw_period; - unsigned usecs = ps->tt_usecs; - if ((period == 0) || (uframe >= 7)) /* error */ return 0; - for (frame &= period - 1; frame < EHCI_BANDWIDTH_FRAMES; - frame += period) { - unsigned i, uf; - unsigned short tt_usecs[8]; - - if (tt->bandwidth[frame] + usecs > 900) - return 0; + for (; frame < ehci->periodic_size; frame += period) { + unsigned short tt_usecs[8]; - uf = frame << 3; - for (i = 0; i < 8; (++i, ++uf)) - tt_usecs[i] = ehci->tt_budget[uf]; + periodic_tt_usecs (ehci, dev, frame, tt_usecs); if (max_tt_usecs[uframe] <= tt_usecs[uframe]) return 0; @@ -411,7 +337,7 @@ static int tt_available ( */ if (125 < usecs) { int ufs = (usecs / 125); - + int i; for (i = uframe; i < (uframe + ufs) && i < 8; i++) if (0 < tt_usecs[i]) return 0; @@ -465,7 +391,7 @@ static int tt_no_collision ( continue; case Q_TYPE_QH: hw = here.qh->hw; - if (same_tt(dev, here.qh->ps.udev)) { + if (same_tt (dev, here.qh->dev)) { u32 mask; mask = hc32_to_cpu(ehci, @@ -545,19 +471,19 @@ static void disable_periodic(struct ehci_hcd *ehci) static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) { unsigned i; - unsigned period = qh->ps.period; + unsigned period = qh->period; - dev_dbg(&qh->ps.udev->dev, + dev_dbg (&qh->dev->dev, "link qh%d-%04x/%p start %d [%d/%d us]\n", period, hc32_to_cpup(ehci, &qh->hw->hw_info2) & (QH_CMASK | QH_SMASK), - qh, qh->ps.phase, qh->ps.usecs, qh->ps.c_usecs); + qh, qh->start, qh->usecs, qh->c_usecs); /* high bandwidth, or otherwise every microframe */ if (period == 0) period = 1; - for (i = qh->ps.phase; i < ehci->periodic_size; i += period) { + for (i = qh->start; i < ehci->periodic_size; i += period) { union ehci_shadow *prev = &ehci->pshadow[i]; __hc32 *hw_p = &ehci->periodic[i]; union ehci_shadow here = *prev; @@ -577,7 +503,7 @@ static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) * enables sharing interior tree nodes */ while (here.ptr && qh != here.qh) { - if (qh->ps.period > here.qh->ps.period) + if (qh->period > here.qh->period) break; prev = &here.qh->qh_next; hw_p = &here.qh->hw->hw_next; @@ -597,10 +523,10 @@ static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) qh->xacterrs = 0; qh->exception = 0; - /* update per-qh bandwidth for debugfs */ - ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->ps.bw_period - ? ((qh->ps.usecs + qh->ps.c_usecs) / qh->ps.bw_period) - : (qh->ps.usecs * 8); + /* 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); @@ -630,21 +556,22 @@ static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) */ /* high bandwidth, or otherwise part of every microframe */ - period = qh->ps.period ? : 1; + if ((period = qh->period) == 0) + period = 1; - for (i = qh->ps.phase; i < ehci->periodic_size; i += period) + for (i = qh->start; i < ehci->periodic_size; i += period) periodic_unlink (ehci, i, qh); - /* update per-qh bandwidth for debugfs */ - ehci_to_hcd(ehci)->self.bandwidth_allocated -= qh->ps.bw_period - ? ((qh->ps.usecs + qh->ps.c_usecs) / qh->ps.bw_period) - : (qh->ps.usecs * 8); + /* 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); - dev_dbg(&qh->ps.udev->dev, + dev_dbg (&qh->dev->dev, "unlink qh%d-%04x/%p start %d [%d/%d us]\n", - qh->ps.period, + qh->period, hc32_to_cpup(ehci, &qh->hw->hw_info2) & (QH_CMASK | QH_SMASK), - qh, qh->ps.phase, qh->ps.usecs, qh->ps.c_usecs); + qh, qh->start, qh->usecs, qh->c_usecs); /* qh->qh_next still "live" to HC */ qh->qh_state = QH_STATE_UNLINK; @@ -767,9 +694,11 @@ static int check_period ( struct ehci_hcd *ehci, unsigned frame, unsigned uframe, - unsigned uperiod, + unsigned period, unsigned usecs ) { + int claimed; + /* complete split running into next frame? * given FSTN support, we could sometimes check... */ @@ -779,10 +708,25 @@ static int check_period ( /* convert "usecs we need" to "max already claimed" */ usecs = ehci->uframe_periodic_max - usecs; - for (uframe += frame << 3; uframe < EHCI_BANDWIDTH_SIZE; - uframe += uperiod) { - if (ehci->bandwidth[uframe] > usecs) - return 0; + /* we "know" 2 and 4 uframe intervals were rejected; so + * for period 0, check _every_ microframe in the schedule. + */ + if (unlikely (period == 0)) { + do { + for (uframe = 0; uframe < 7; uframe++) { + claimed = periodic_usecs (ehci, frame, uframe); + if (claimed > usecs) + return 0; + } + } while ((frame += 1) < ehci->periodic_size); + + /* just check the specified uframe, at that period */ + } else { + do { + claimed = periodic_usecs (ehci, frame, uframe); + if (claimed > usecs) + return 0; + } while ((frame += period) < ehci->periodic_size); } // success! @@ -793,40 +737,40 @@ static int check_intr_schedule ( struct ehci_hcd *ehci, unsigned frame, unsigned uframe, - struct ehci_qh *qh, - unsigned *c_maskp, - struct ehci_tt *tt + const struct ehci_qh *qh, + __hc32 *c_maskp ) { int retval = -ENOSPC; u8 mask = 0; - if (qh->ps.c_usecs && uframe >= 6) /* FSTN territory? */ + if (qh->c_usecs && uframe >= 6) /* FSTN territory? */ goto done; - if (!check_period(ehci, frame, uframe, qh->ps.bw_uperiod, qh->ps.usecs)) + if (!check_period (ehci, frame, uframe, qh->period, qh->usecs)) goto done; - if (!qh->ps.c_usecs) { + if (!qh->c_usecs) { retval = 0; *c_maskp = 0; goto done; } #ifdef CONFIG_USB_EHCI_TT_NEWSCHED - if (tt_available(ehci, &qh->ps, tt, frame, uframe)) { + if (tt_available (ehci, qh->period, qh->dev, frame, uframe, + qh->tt_usecs)) { unsigned i; /* TODO : this may need FSTN for SSPLIT in uframe 5. */ - for (i = uframe+2; i < 8 && i <= uframe+4; i++) - if (!check_period(ehci, frame, i, - qh->ps.bw_uperiod, qh->ps.c_usecs)) + for (i=uframe+1; i<8 && i<uframe+4; i++) + if (!check_period (ehci, frame, i, + qh->period, qh->c_usecs)) goto done; else mask |= 1 << i; retval = 0; - *c_maskp = mask; + *c_maskp = cpu_to_hc32(ehci, mask << 8); } #else /* Make sure this tt's buffer is also available for CSPLITs. @@ -837,15 +781,15 @@ static int check_intr_schedule ( * one smart pass... */ mask = 0x03 << (uframe + qh->gap_uf); - *c_maskp = mask; + *c_maskp = cpu_to_hc32(ehci, mask << 8); mask |= 1 << uframe; - if (tt_no_collision(ehci, qh->ps.bw_period, qh->ps.udev, frame, mask)) { - if (!check_period(ehci, frame, uframe + qh->gap_uf + 1, - qh->ps.bw_uperiod, qh->ps.c_usecs)) + if (tt_no_collision (ehci, qh->period, qh->dev, frame, mask)) { + if (!check_period (ehci, frame, uframe + qh->gap_uf + 1, + qh->period, qh->c_usecs)) goto done; - if (!check_period(ehci, frame, uframe + qh->gap_uf, - qh->ps.bw_uperiod, qh->ps.c_usecs)) + if (!check_period (ehci, frame, uframe + qh->gap_uf, + qh->period, qh->c_usecs)) goto done; retval = 0; } @@ -859,67 +803,62 @@ done: */ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh) { - int status = 0; + int status; unsigned uframe; - unsigned c_mask; + __hc32 c_mask; + unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ struct ehci_qh_hw *hw = qh->hw; - struct ehci_tt *tt; hw->hw_next = EHCI_LIST_END(ehci); + frame = qh->start; /* reuse the previous schedule slots, if we can */ - if (qh->ps.phase != NO_FRAME) { - ehci_dbg(ehci, "reused qh %p schedule\n", qh); - return 0; - } - - uframe = 0; - c_mask = 0; - tt = find_tt(qh->ps.udev); - if (IS_ERR(tt)) { - status = PTR_ERR(tt); - goto done; + if (frame < qh->period) { + uframe = ffs(hc32_to_cpup(ehci, &hw->hw_info2) & QH_SMASK); + status = check_intr_schedule (ehci, frame, --uframe, + qh, &c_mask); + } else { + uframe = 0; + c_mask = 0; + status = -ENOSPC; } - compute_tt_budget(ehci->tt_budget, tt); /* else scan the schedule to find a group of slots such that all * uframes have enough periodic bandwidth available. */ - /* "normal" case, uframing flexible except with splits */ - if (qh->ps.bw_period) { - int i; - unsigned frame; - - for (i = qh->ps.bw_period; i > 0; --i) { - frame = ++ehci->random_frame & (qh->ps.bw_period - 1); - for (uframe = 0; uframe < 8; uframe++) { - status = check_intr_schedule(ehci, - frame, uframe, qh, &c_mask, tt); - if (status == 0) - goto got_it; + if (status) { + /* "normal" case, uframing flexible except with splits */ + if (qh->period) { + int i; + + for (i = qh->period; status && i > 0; --i) { + frame = ++ehci->random_frame % qh->period; + for (uframe = 0; uframe < 8; uframe++) { + status = check_intr_schedule (ehci, + frame, uframe, qh, + &c_mask); + if (status == 0) + break; + } } - } - - /* qh->ps.bw_period == 0 means every uframe */ - } else { - status = check_intr_schedule(ehci, 0, 0, qh, &c_mask, tt); - } - if (status) - goto done; - got_it: - qh->ps.phase = (qh->ps.period ? ehci->random_frame & - (qh->ps.period - 1) : 0); - qh->ps.bw_phase = qh->ps.phase & (qh->ps.bw_period - 1); - qh->ps.phase_uf = uframe; - qh->ps.cs_mask = qh->ps.period ? - (c_mask << 8) | (1 << uframe) : - QH_SMASK; + /* qh->period == 0 means every uframe */ + } else { + frame = 0; + status = check_intr_schedule (ehci, 0, 0, qh, &c_mask); + } + if (status) + goto done; + qh->start = frame; - /* reset S-frame and (maybe) C-frame masks */ - hw->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK)); - hw->hw_info2 |= cpu_to_hc32(ehci, qh->ps.cs_mask); - reserve_release_intr_bandwidth(ehci, qh, 1); + /* reset S-frame and (maybe) C-frame masks */ + hw->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK)); + hw->hw_info2 |= qh->period + ? cpu_to_hc32(ehci, 1 << uframe) + : cpu_to_hc32(ehci, QH_SMASK); + hw->hw_info2 |= c_mask; + } else + ehci_dbg (ehci, "reused qh %p schedule\n", qh); done: return status; @@ -1030,8 +969,7 @@ iso_stream_alloc (gfp_t mem_flags) if (likely (stream != NULL)) { INIT_LIST_HEAD(&stream->td_list); INIT_LIST_HEAD(&stream->free_list); - stream->next_uframe = NO_FRAME; - stream->ps.phase = NO_FRAME; + stream->next_uframe = -1; } return stream; } @@ -1040,24 +978,25 @@ static void iso_stream_init ( struct ehci_hcd *ehci, struct ehci_iso_stream *stream, - struct urb *urb + struct usb_device *dev, + int pipe, + unsigned interval ) { static const u8 smask_out [] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f }; - struct usb_device *dev = urb->dev; u32 buf1; unsigned epnum, maxp; int is_input; - unsigned tmp; + long bandwidth; /* * this might be a "high bandwidth" highspeed endpoint, * as encoded in the ep descriptor's wMaxPacket field */ - epnum = usb_pipeendpoint(urb->pipe); - is_input = usb_pipein(urb->pipe) ? USB_DIR_IN : 0; - maxp = usb_endpoint_maxp(&urb->ep->desc); + epnum = usb_pipeendpoint (pipe); + is_input = usb_pipein (pipe) ? USB_DIR_IN : 0; + maxp = usb_maxpacket(dev, pipe, !is_input); if (is_input) { buf1 = (1 << 11); } else { @@ -1081,19 +1020,9 @@ iso_stream_init ( /* usbfs wants to report the average usecs per frame tied up * when transfers on this endpoint are scheduled ... */ - stream->ps.usecs = HS_USECS_ISO(maxp); - - /* period for bandwidth allocation */ - tmp = min_t(unsigned, EHCI_BANDWIDTH_SIZE, - 1 << (urb->ep->desc.bInterval - 1)); - - /* Allow urb->interval to override */ - stream->ps.bw_uperiod = min_t(unsigned, tmp, urb->interval); - - stream->uperiod = urb->interval; - stream->ps.period = urb->interval >> 3; - stream->bandwidth = stream->ps.usecs * 8 / - stream->ps.bw_uperiod; + stream->usecs = HS_USECS_ISO (maxp); + bandwidth = stream->usecs * 8; + bandwidth /= interval; } else { u32 addr; @@ -1107,46 +1036,36 @@ iso_stream_init ( addr |= dev->tt->hub->devnum << 16; addr |= epnum << 8; addr |= dev->devnum; - stream->ps.usecs = HS_USECS_ISO(maxp); + stream->usecs = HS_USECS_ISO (maxp); think_time = dev->tt ? dev->tt->think_time : 0; - stream->ps.tt_usecs = NS_TO_US(think_time + usb_calc_bus_time( + stream->tt_usecs = NS_TO_US (think_time + usb_calc_bus_time ( dev->speed, is_input, 1, maxp)); hs_transfers = max (1u, (maxp + 187) / 188); if (is_input) { u32 tmp; addr |= 1 << 31; - stream->ps.c_usecs = stream->ps.usecs; - stream->ps.usecs = HS_USECS_ISO(1); - stream->ps.cs_mask = 1; + stream->c_usecs = stream->usecs; + stream->usecs = HS_USECS_ISO (1); + stream->raw_mask = 1; /* c-mask as specified in USB 2.0 11.18.4 3.c */ tmp = (1 << (hs_transfers + 2)) - 1; - stream->ps.cs_mask |= tmp << (8 + 2); + stream->raw_mask |= tmp << (8 + 2); } else - stream->ps.cs_mask = smask_out[hs_transfers - 1]; - - /* period for bandwidth allocation */ - tmp = min_t(unsigned, EHCI_BANDWIDTH_FRAMES, - 1 << (urb->ep->desc.bInterval - 1)); - - /* Allow urb->interval to override */ - stream->ps.bw_period = min_t(unsigned, tmp, urb->interval); - stream->ps.bw_uperiod = stream->ps.bw_period << 3; + stream->raw_mask = smask_out [hs_transfers - 1]; + bandwidth = stream->usecs + stream->c_usecs; + bandwidth /= interval << 3; - stream->ps.period = urb->interval; - stream->uperiod = urb->interval << 3; - stream->bandwidth = (stream->ps.usecs + stream->ps.c_usecs) / - stream->ps.bw_period; - - /* stream->splits gets created from cs_mask later */ + /* stream->splits gets created from raw_mask later */ stream->address = cpu_to_hc32(ehci, addr); } + stream->bandwidth = bandwidth; - stream->ps.udev = dev; - stream->ps.ep = urb->ep; + stream->udev = dev; stream->bEndpointAddress = is_input | epnum; + stream->interval = interval; stream->maxp = maxp; } @@ -1171,7 +1090,9 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb) stream = iso_stream_alloc(GFP_ATOMIC); if (likely (stream != NULL)) { ep->hcpriv = stream; - iso_stream_init(ehci, stream, urb); + stream->ep = ep; + iso_stream_init(ehci, stream, urb->dev, urb->pipe, + urb->interval); } /* if dev->ep [epnum] is a QH, hw is set */ @@ -1216,7 +1137,7 @@ itd_sched_init( dma_addr_t dma = urb->transfer_dma; /* how many uframes are needed for these transfers */ - iso_sched->span = urb->number_of_packets * stream->uperiod; + iso_sched->span = urb->number_of_packets * stream->interval; /* figure out per-uframe itd fields that we'll need later * when we fit new itds into the schedule. @@ -1315,7 +1236,7 @@ itd_urb_transaction ( memset (itd, 0, sizeof *itd); itd->itd_dma = itd_dma; - itd->frame = NO_FRAME; + itd->frame = 9999; /* an invalid value */ list_add (&itd->itd_list, &sched->td_list); } spin_unlock_irqrestore (&ehci->lock, flags); @@ -1328,106 +1249,49 @@ itd_urb_transaction ( /*-------------------------------------------------------------------------*/ -static void reserve_release_iso_bandwidth(struct ehci_hcd *ehci, - struct ehci_iso_stream *stream, int sign) -{ - unsigned uframe; - unsigned i, j; - unsigned s_mask, c_mask, m; - int usecs = stream->ps.usecs; - int c_usecs = stream->ps.c_usecs; - int tt_usecs = stream->ps.tt_usecs; - struct ehci_tt *tt; - - if (stream->ps.phase == NO_FRAME) /* Bandwidth wasn't reserved */ - return; - uframe = stream->ps.bw_phase << 3; - - bandwidth_dbg(ehci, sign, "iso", &stream->ps); - - if (sign < 0) { /* Release bandwidth */ - usecs = -usecs; - c_usecs = -c_usecs; - tt_usecs = -tt_usecs; - } - - if (!stream->splits) { /* High speed */ - for (i = uframe + stream->ps.phase_uf; i < EHCI_BANDWIDTH_SIZE; - i += stream->ps.bw_uperiod) - ehci->bandwidth[i] += usecs; - - } else { /* Full speed */ - s_mask = stream->ps.cs_mask; - c_mask = s_mask >> 8; - - /* NOTE: adjustment needed for frame overflow */ - for (i = uframe; i < EHCI_BANDWIDTH_SIZE; - i += stream->ps.bw_uperiod) { - for ((j = stream->ps.phase_uf, m = 1 << j); j < 8; - (++j, m <<= 1)) { - if (s_mask & m) - ehci->bandwidth[i+j] += usecs; - else if (c_mask & m) - ehci->bandwidth[i+j] += c_usecs; - } - } - - tt = find_tt(stream->ps.udev); - if (sign > 0) - list_add_tail(&stream->ps.ps_list, &tt->ps_list); - else - list_del(&stream->ps.ps_list); - - for (i = uframe >> 3; i < EHCI_BANDWIDTH_FRAMES; - i += stream->ps.bw_period) - tt->bandwidth[i] += tt_usecs; - } -} - static inline int itd_slot_ok ( struct ehci_hcd *ehci, - struct ehci_iso_stream *stream, - unsigned uframe + u32 mod, + u32 uframe, + u8 usecs, + u32 period ) { - unsigned usecs; - - /* convert "usecs we need" to "max already claimed" */ - usecs = ehci->uframe_periodic_max - stream->ps.usecs; - - for (uframe &= stream->ps.bw_uperiod - 1; uframe < EHCI_BANDWIDTH_SIZE; - uframe += stream->ps.bw_uperiod) { - if (ehci->bandwidth[uframe] > usecs) + uframe %= period; + do { + /* can't commit more than uframe_periodic_max usec */ + if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7) + > (ehci->uframe_periodic_max - usecs)) return 0; - } + + /* we know urb->interval is 2^N uframes */ + uframe += period; + } while (uframe < mod); return 1; } static inline int sitd_slot_ok ( struct ehci_hcd *ehci, + u32 mod, struct ehci_iso_stream *stream, - unsigned uframe, + u32 uframe, struct ehci_iso_sched *sched, - struct ehci_tt *tt + u32 period_uframes ) { - unsigned mask, tmp; - unsigned frame, uf; - - mask = stream->ps.cs_mask << (uframe & 7); + u32 mask, tmp; + u32 frame, uf; - /* for OUT, don't wrap SSPLIT into H-microframe 7 */ - if (((stream->ps.cs_mask & 0xff) << (uframe & 7)) >= (1 << 7)) - return 0; + mask = stream->raw_mask << (uframe & 7); /* for IN, don't wrap CSPLIT into the next frame */ if (mask & ~0xffff) return 0; /* check bandwidth */ - uframe &= stream->ps.bw_uperiod - 1; + uframe %= period_uframes; frame = uframe >> 3; #ifdef CONFIG_USB_EHCI_TT_NEWSCHED @@ -1435,48 +1299,54 @@ sitd_slot_ok ( * tt_available scheduling guarantees 10+% for control/bulk. */ uf = uframe & 7; - if (!tt_available(ehci, &stream->ps, tt, frame, uf)) + if (!tt_available(ehci, period_uframes >> 3, + stream->udev, frame, uf, stream->tt_usecs)) return 0; #else /* tt must be idle for start(s), any gap, and csplit. * assume scheduling slop leaves 10+% for control/bulk. */ - if (!tt_no_collision(ehci, stream->ps.bw_period, - stream->ps.udev, frame, mask)) + if (!tt_no_collision(ehci, period_uframes >> 3, + stream->udev, frame, mask)) return 0; #endif + /* this multi-pass logic is simple, but performance may + * suffer when the schedule data isn't cached. + */ do { - unsigned max_used; - unsigned i; + u32 max_used; + + frame = uframe >> 3; + uf = uframe & 7; /* check starts (OUT uses more than one) */ - uf = uframe; - max_used = ehci->uframe_periodic_max - stream->ps.usecs; - for (tmp = stream->ps.cs_mask & 0xff; tmp; tmp >>= 1, uf++) { - if (ehci->bandwidth[uf] > max_used) + max_used = ehci->uframe_periodic_max - stream->usecs; + for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) { + if (periodic_usecs (ehci, frame, uf) > max_used) return 0; } /* for IN, check CSPLIT */ - if (stream->ps.c_usecs) { - max_used = ehci->uframe_periodic_max - - stream->ps.c_usecs; - uf = uframe & ~7; - tmp = 1 << (2+8); - for (i = (uframe & 7) + 2; i < 8; (++i, tmp <<= 1)) { - if ((stream->ps.cs_mask & tmp) == 0) + if (stream->c_usecs) { + uf = uframe & 7; + max_used = ehci->uframe_periodic_max - stream->c_usecs; + do { + tmp = 1 << uf; + tmp <<= 8; + if ((stream->raw_mask & tmp) == 0) continue; - if (ehci->bandwidth[uf+i] > max_used) + if (periodic_usecs (ehci, frame, uf) + > max_used) return 0; - } + } while (++uf < 8); } - uframe += stream->ps.bw_uperiod; - } while (uframe < EHCI_BANDWIDTH_SIZE); + /* we know urb->interval is 2^N uframes */ + uframe += period_uframes; + } while (uframe < mod); - stream->ps.cs_mask <<= uframe & 7; - stream->splits = cpu_to_hc32(ehci, stream->ps.cs_mask); + stream->splits = cpu_to_hc32(ehci, stream->raw_mask << (uframe & 7)); return 1; } @@ -1491,6 +1361,8 @@ sitd_slot_ok ( * given EHCI_TUNE_FLS and the slop). Or, write a smarter scheduler! */ +#define SCHEDULING_DELAY 40 /* microframes */ + static int iso_stream_schedule ( struct ehci_hcd *ehci, @@ -1498,184 +1370,134 @@ iso_stream_schedule ( struct ehci_iso_stream *stream ) { - u32 now, base, next, start, period, span, now2; - u32 wrap = 0, skip = 0; - int status = 0; + u32 now, base, next, start, period, span; + int status; unsigned mod = ehci->periodic_size << 3; struct ehci_iso_sched *sched = urb->hcpriv; - bool empty = list_empty(&stream->td_list); - bool new_stream = false; - period = stream->uperiod; + period = urb->interval; span = sched->span; - if (!stream->highspeed) + if (!stream->highspeed) { + period <<= 3; span <<= 3; - - /* Start a new isochronous stream? */ - if (unlikely(empty && !hcd_periodic_completion_in_progress( - ehci_to_hcd(ehci), urb->ep))) { - - /* Schedule the endpoint */ - if (stream->ps.phase == NO_FRAME) { - int done = 0; - struct ehci_tt *tt = find_tt(stream->ps.udev); - - if (IS_ERR(tt)) { - status = PTR_ERR(tt); - goto fail; - } - compute_tt_budget(ehci->tt_budget, tt); - - start = ((-(++ehci->random_frame)) << 3) & (period - 1); - - /* find a uframe slot with enough bandwidth. - * Early uframes are more precious because full-speed - * iso IN transfers can't use late uframes, - * and therefore they should be allocated last. - */ - next = start; - start += period; - do { - start--; - /* check schedule: enough space? */ - if (stream->highspeed) { - if (itd_slot_ok(ehci, stream, start)) - done = 1; - } else { - if ((start % 8) >= 6) - continue; - if (sitd_slot_ok(ehci, stream, start, - sched, tt)) - done = 1; - } - } while (start > next && !done); - - /* no room in the schedule */ - if (!done) { - ehci_dbg(ehci, "iso sched full %p", urb); - status = -ENOSPC; - goto fail; - } - stream->ps.phase = (start >> 3) & - (stream->ps.period - 1); - stream->ps.bw_phase = stream->ps.phase & - (stream->ps.bw_period - 1); - stream->ps.phase_uf = start & 7; - reserve_release_iso_bandwidth(ehci, stream, 1); - } - - /* New stream is already scheduled; use the upcoming slot */ - else { - start = (stream->ps.phase << 3) + stream->ps.phase_uf; - } - - stream->next_uframe = start; - new_stream = true; } now = ehci_read_frame_index(ehci) & (mod - 1); - /* Take the isochronous scheduling threshold into account */ - if (ehci->i_thresh) - next = now + ehci->i_thresh; /* uframe cache */ - else - next = (now + 2 + 7) & ~0x07; /* full frame cache */ - - /* - * Use ehci->last_iso_frame as the base. There can't be any - * TDs scheduled for earlier than that. - */ - base = ehci->last_iso_frame << 3; - next = (next - base) & (mod - 1); - start = (stream->next_uframe - base) & (mod - 1); - - if (unlikely(new_stream)) - goto do_ASAP; - - /* - * Typical case: reuse current schedule, stream may still be active. + /* Typical case: reuse current schedule, stream is still active. * Hopefully there are no gaps from the host falling behind * (irq delays etc). If there are, the behavior depends on * whether URB_ISO_ASAP is set. */ - now2 = (now - base) & (mod - 1); + if (likely (!list_empty (&stream->td_list))) { - /* Is the schedule already full? */ - if (unlikely(!empty && start < period)) { - ehci_dbg(ehci, "iso sched full %p (%u-%u < %u mod %u)\n", - urb, stream->next_uframe, base, period, mod); - status = -ENOSPC; - goto fail; - } + /* Take the isochronous scheduling threshold into account */ + if (ehci->i_thresh) + next = now + ehci->i_thresh; /* uframe cache */ + else + next = (now + 2 + 7) & ~0x07; /* full frame cache */ - /* Is the next packet scheduled after the base time? */ - if (likely(!empty || start <= now2 + period)) { + /* + * Use ehci->last_iso_frame as the base. There can't be any + * TDs scheduled for earlier than that. + */ + base = ehci->last_iso_frame << 3; + next = (next - base) & (mod - 1); + start = (stream->next_uframe - base) & (mod - 1); + + /* Is the schedule already full? */ + if (unlikely(start < period)) { + ehci_dbg(ehci, "iso sched full %p (%u-%u < %u mod %u)\n", + urb, stream->next_uframe, base, + period, mod); + status = -ENOSPC; + goto fail; + } - /* URB_ISO_ASAP: make sure that start >= next */ - if (unlikely(start < next && - (urb->transfer_flags & URB_ISO_ASAP))) - goto do_ASAP; + /* Behind the scheduling threshold? */ + if (unlikely(start < next)) { + unsigned now2 = (now - base) & (mod - 1); - /* Otherwise use start, if it's not in the past */ - if (likely(start >= now2)) - goto use_start; + /* USB_ISO_ASAP: Round up to the first available slot */ + if (urb->transfer_flags & URB_ISO_ASAP) + start += (next - start + period - 1) & -period; - /* Otherwise we got an underrun while the queue was empty */ - } else { - if (urb->transfer_flags & URB_ISO_ASAP) - goto do_ASAP; - wrap = mod; - now2 += mod; + /* + * Not ASAP: Use the next slot in the stream, + * no matter what. + */ + else if (start + span - period < now2) { + ehci_dbg(ehci, "iso underrun %p (%u+%u < %u)\n", + urb, start + base, + span - period, now2 + base); + } + } + + start += base; } - /* How many uframes and packets do we need to skip? */ - skip = (now2 - start + period - 1) & -period; - if (skip >= span) { /* Entirely in the past? */ - ehci_dbg(ehci, "iso underrun %p (%u+%u < %u) [%u]\n", - urb, start + base, span - period, now2 + base, - base); - - /* Try to keep the last TD intact for scanning later */ - skip = span - period; - - /* Will it come before the current scan position? */ - if (empty) { - skip = span; /* Skip the entire URB */ - status = 1; /* and give it back immediately */ - iso_sched_free(stream, sched); - sched = NULL; + /* need to schedule; when's the next (u)frame we could start? + * this is bigger than ehci->i_thresh allows; scheduling itself + * isn't free, the delay should handle reasonably slow cpus. it + * can also help high bandwidth if the dma and irq loads don't + * jump until after the queue is primed. + */ + else { + int done = 0; + + base = now & ~0x07; + start = base + SCHEDULING_DELAY; + + /* find a uframe slot with enough bandwidth. + * Early uframes are more precious because full-speed + * iso IN transfers can't use late uframes, + * and therefore they should be allocated last. + */ + next = start; + start += period; + do { + start--; + /* check schedule: enough space? */ + if (stream->highspeed) { + if (itd_slot_ok(ehci, mod, start, + stream->usecs, period)) + done = 1; + } else { + if ((start % 8) >= 6) + continue; + if (sitd_slot_ok(ehci, mod, stream, + start, sched, period)) + done = 1; + } + } while (start > next && !done); + + /* no room in the schedule */ + if (!done) { + ehci_dbg(ehci, "iso sched full %p", urb); + status = -ENOSPC; + goto fail; } } - urb->error_count = skip / period; - if (sched) - sched->first_packet = urb->error_count; - goto use_start; - do_ASAP: - /* Use the first slot after "next" */ - start = next + ((start - next) & (period - 1)); - - use_start: /* Tried to schedule too far into the future? */ - if (unlikely(start + span - period >= mod + wrap)) { + if (unlikely(start - base + span - period >= mod)) { ehci_dbg(ehci, "request %p would overflow (%u+%u >= %u)\n", - urb, start, span - period, mod + wrap); + urb, start - base, span - period, mod); status = -EFBIG; goto fail; } - start += base; - stream->next_uframe = (start + skip) & (mod - 1); + stream->next_uframe = start & (mod - 1); /* report high speed start in uframes; full speed, in frames */ - urb->start_frame = start & (mod - 1); + 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->last_iso_frame = now >> 3; - return status; + return 0; fail: iso_sched_free(stream, sched); @@ -1788,8 +1610,7 @@ static void itd_link_urb( ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; /* fill iTDs uframe by uframe */ - for (packet = iso_sched->first_packet, itd = NULL; - packet < urb->number_of_packets;) { + for (packet = 0, itd = NULL; packet < urb->number_of_packets; ) { if (itd == NULL) { /* ASSERT: we have all necessary itds */ // BUG_ON (list_empty (&iso_sched->td_list)); @@ -1809,7 +1630,7 @@ static void itd_link_urb( itd_patch(ehci, itd, iso_sched, packet, uframe); - next_uframe += stream->uperiod; + next_uframe += stream->interval; next_uframe &= mod - 1; packet++; @@ -1949,9 +1770,9 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, ehci_dbg (ehci, "can't get iso stream\n"); return -ENOMEM; } - if (unlikely(urb->interval != stream->uperiod)) { + if (unlikely (urb->interval != stream->interval)) { ehci_dbg (ehci, "can't change iso interval %d --> %d\n", - stream->uperiod, urb->interval); + stream->interval, urb->interval); goto done; } @@ -1983,14 +1804,10 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, if (unlikely(status)) goto done_not_linked; status = iso_stream_schedule(ehci, urb, stream); - if (likely(status == 0)) { + if (likely (status == 0)) itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); - } else if (status > 0) { - status = 0; - ehci_urb_done(ehci, urb, 0); - } else { + else usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); - } done_not_linked: spin_unlock_irqrestore (&ehci->lock, flags); done: @@ -2016,7 +1833,7 @@ sitd_sched_init( dma_addr_t dma = urb->transfer_dma; /* how many frames are needed for these transfers */ - iso_sched->span = urb->number_of_packets * stream->ps.period; + iso_sched->span = urb->number_of_packets * stream->interval; /* figure out per-frame sitd fields that we'll need later * when we fit new sitds into the schedule. @@ -2108,7 +1925,7 @@ sitd_urb_transaction ( memset (sitd, 0, sizeof *sitd); sitd->sitd_dma = sitd_dma; - sitd->frame = NO_FRAME; + sitd->frame = 9999; /* an invalid value */ list_add (&sitd->sitd_list, &iso_sched->td_list); } @@ -2191,7 +2008,7 @@ static void sitd_link_urb( ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; /* fill sITDs frame by frame */ - for (packet = sched->first_packet, sitd = NULL; + for (packet = 0, sitd = NULL; packet < urb->number_of_packets; packet++) { @@ -2210,7 +2027,7 @@ static void sitd_link_urb( sitd_link(ehci, (next_uframe >> 3) & (ehci->periodic_size - 1), sitd); - next_uframe += stream->uperiod; + next_uframe += stream->interval << 3; } stream->next_uframe = next_uframe & (mod - 1); @@ -2329,9 +2146,9 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, ehci_dbg (ehci, "can't get iso stream\n"); return -ENOMEM; } - if (urb->interval != stream->ps.period) { + if (urb->interval != stream->interval) { ehci_dbg (ehci, "can't change iso interval %d --> %d\n", - stream->ps.period, urb->interval); + stream->interval, urb->interval); goto done; } @@ -2361,14 +2178,10 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, if (unlikely(status)) goto done_not_linked; status = iso_stream_schedule(ehci, urb, stream); - if (likely(status == 0)) { + if (status == 0) sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); - } else if (status > 0) { - status = 0; - ehci_urb_done(ehci, urb, 0); - } else { + else usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); - } done_not_linked: spin_unlock_irqrestore (&ehci->lock, flags); done: @@ -2446,8 +2259,7 @@ restart: q.itd->hw_next != EHCI_LIST_END(ehci)) *hw_p = q.itd->hw_next; else - *hw_p = cpu_to_hc32(ehci, - ehci->dummy->qh_dma); + *hw_p = ehci->dummy->qh_dma; type = Q_NEXT_TYPE(ehci, q.itd->hw_next); wmb(); modified = itd_complete (ehci, q.itd); @@ -2482,8 +2294,7 @@ restart: q.sitd->hw_next != EHCI_LIST_END(ehci)) *hw_p = q.sitd->hw_next; else - *hw_p = cpu_to_hc32(ehci, - ehci->dummy->qh_dma); + *hw_p = ehci->dummy->qh_dma; type = Q_NEXT_TYPE(ehci, q.sitd->hw_next); wmb(); modified = sitd_complete (ehci, q.sitd); diff --git a/drivers/usb/host/ehci-sead3.c b/drivers/usb/host/ehci-sead3.c index 8a73449..b2de52d 100644 --- a/drivers/usb/host/ehci-sead3.c +++ b/drivers/usb/host/ehci-sead3.c @@ -55,7 +55,7 @@ const struct hc_driver ehci_sead3_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, + .flags = HCD_MEMORY | HCD_USB2, /* * basic lifecycle operations diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c index dc899eb..93e59a1 100644 --- a/drivers/usb/host/ehci-sh.c +++ b/drivers/usb/host/ehci-sh.c @@ -36,7 +36,7 @@ static const struct hc_driver ehci_sh_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_USB2 | HCD_MEMORY | HCD_BH, + .flags = HCD_USB2 | HCD_MEMORY, /* * basic lifecycle operations diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c index ee6f9ff..1cf0adb 100644 --- a/drivers/usb/host/ehci-spear.c +++ b/drivers/usb/host/ehci-spear.c @@ -81,9 +81,10 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev) * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away. */ - retval = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (retval) - goto fail; + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); usbh_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(usbh_clk)) { diff --git a/drivers/usb/host/ehci-sysfs.c b/drivers/usb/host/ehci-sysfs.c index f6459df..14ced00 100644 --- a/drivers/usb/host/ehci-sysfs.c +++ b/drivers/usb/host/ehci-sysfs.c @@ -97,7 +97,8 @@ static ssize_t store_uframe_periodic_max(struct device *dev, { struct ehci_hcd *ehci; unsigned uframe_periodic_max; - unsigned uframe; + unsigned frame, uframe; + unsigned short allocated_max; unsigned long flags; ssize_t ret; @@ -121,14 +122,16 @@ static ssize_t store_uframe_periodic_max(struct device *dev, /* * for request to decrease max periodic bandwidth, we have to check - * to see whether the decrease is possible. + * every microframe in the schedule to see whether the decrease is + * possible. */ if (uframe_periodic_max < ehci->uframe_periodic_max) { - u8 allocated_max = 0; + allocated_max = 0; - for (uframe = 0; uframe < EHCI_BANDWIDTH_SIZE; ++uframe) - allocated_max = max(allocated_max, - ehci->bandwidth[uframe]); + for (frame = 0; frame < ehci->periodic_size; ++frame) + for (uframe = 0; uframe < 7; ++uframe) + allocated_max = max(allocated_max, + periodic_usecs (ehci, frame, uframe)); if (allocated_max > uframe_periodic_max) { ehci_info(ehci, diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index b9fd039..78fa76d 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -362,9 +362,10 @@ static int tegra_ehci_probe(struct platform_device *pdev) * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away. */ - err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (err) - return err; + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev, dev_name(&pdev->dev)); @@ -387,7 +388,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) err = clk_prepare_enable(tegra->clk); if (err) - goto cleanup_hcd_create; + goto cleanup_clk_get; tegra_periph_reset_assert(tegra->clk); udelay(1); @@ -464,6 +465,8 @@ cleanup_phy: usb_phy_shutdown(hcd->phy); cleanup_clk_en: clk_disable_unprepare(tegra->clk); +cleanup_clk_get: + clk_put(tegra->clk); cleanup_hcd_create: usb_put_hcd(hcd); return err; diff --git a/drivers/usb/host/ehci-tilegx.c b/drivers/usb/host/ehci-tilegx.c index 67026ff..cca4be9 100644 --- a/drivers/usb/host/ehci-tilegx.c +++ b/drivers/usb/host/ehci-tilegx.c @@ -61,7 +61,7 @@ static const struct hc_driver ehci_tilegx_hc_driver = { * Generic hardware linkage. */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, + .flags = HCD_MEMORY | HCD_USB2, /* * Basic lifecycle operations. diff --git a/drivers/usb/host/ehci-w90x900.c b/drivers/usb/host/ehci-w90x900.c index cdad843..59e0e24 100644 --- a/drivers/usb/host/ehci-w90x900.c +++ b/drivers/usb/host/ehci-w90x900.c @@ -11,28 +11,13 @@ * */ -#include <linux/dma-mapping.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/of.h> #include <linux/platform_device.h> -#include <linux/usb.h> -#include <linux/usb/hcd.h> - -#include "ehci.h" /* enable phy0 and phy1 for w90p910 */ #define ENPHY (0x01<<8) #define PHY0_CTR (0xA4) #define PHY1_CTR (0xA8) -#define DRIVER_DESC "EHCI w90x900 driver" - -static const char hcd_name[] = "ehci-w90x900 "; - -static struct hc_driver __read_mostly ehci_w90x900_hc_driver; - static int usb_w90x900_probe(const struct hc_driver *driver, struct platform_device *pdev) { @@ -105,8 +90,8 @@ err1: return retval; } -static void usb_w90x900_remove(struct usb_hcd *hcd, - struct platform_device *pdev) +static +void usb_w90x900_remove(struct usb_hcd *hcd, struct platform_device *pdev) { usb_remove_hcd(hcd); iounmap(hcd->regs); @@ -114,6 +99,54 @@ static void usb_w90x900_remove(struct usb_hcd *hcd, usb_put_hcd(hcd); } +static const struct hc_driver ehci_w90x900_hc_driver = { + .description = hcd_name, + .product_desc = "Nuvoton w90x900 EHCI Host Controller", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_USB2|HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .reset = ehci_setup, + .start = ehci_run, + + .stop = ehci_stop, + .shutdown = ehci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, +#ifdef CONFIG_PM + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, +#endif + .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, + + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, +}; + static int ehci_w90x900_probe(struct platform_device *pdev) { if (usb_disabled()) @@ -140,25 +173,7 @@ static struct platform_driver ehci_hcd_w90x900_driver = { }, }; -static int __init ehci_w90X900_init(void) -{ - if (usb_disabled()) - return -ENODEV; - - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - - ehci_init_driver(&ehci_w90x900_hc_driver, NULL); - return platform_driver_register(&ehci_hcd_w90x900_driver); -} -module_init(ehci_w90X900_init); - -static void __exit ehci_w90X900_cleanup(void) -{ - platform_driver_unregister(&ehci_hcd_w90x900_driver); -} -module_exit(ehci_w90X900_cleanup); - -MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); +MODULE_DESCRIPTION("w90p910 usb ehci driver!"); +MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:w90p910-ehci"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c index 95979f9..eba962e 100644 --- a/drivers/usb/host/ehci-xilinx-of.c +++ b/drivers/usb/host/ehci-xilinx-of.c @@ -79,7 +79,7 @@ static const struct hc_driver ehci_xilinx_of_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, + .flags = HCD_MEMORY | HCD_USB2, /* * basic lifecycle operations diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index e8f41c5..291db7d 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -54,28 +54,6 @@ struct ehci_stats { unsigned long unlink; }; -/* - * Scheduling and budgeting information for periodic transfers, for both - * high-speed devices and full/low-speed devices lying behind a TT. - */ -struct ehci_per_sched { - struct usb_device *udev; /* access to the TT */ - struct usb_host_endpoint *ep; - struct list_head ps_list; /* node on ehci_tt's ps_list */ - u16 tt_usecs; /* time on the FS/LS bus */ - u16 cs_mask; /* C-mask and S-mask bytes */ - u16 period; /* actual period in frames */ - u16 phase; /* actual phase, frame part */ - u8 bw_phase; /* same, for bandwidth - reservation */ - u8 phase_uf; /* uframe part of the phase */ - u8 usecs, c_usecs; /* times on the HS bus */ - u8 bw_uperiod; /* period in microframes, for - bandwidth reservation */ - u8 bw_period; /* same, in frames */ -}; -#define NO_FRAME 29999 /* frame not assigned yet */ - /* ehci_hcd->lock guards shared data against other CPUs: * ehci_hcd: async, unlink, periodic (and shadow), ... * usb_host_endpoint: hcpriv @@ -252,15 +230,6 @@ struct ehci_hcd { /* one per controller */ struct dentry *debug_dir; #endif - /* bandwidth usage */ -#define EHCI_BANDWIDTH_SIZE 64 -#define EHCI_BANDWIDTH_FRAMES (EHCI_BANDWIDTH_SIZE >> 3) - u8 bandwidth[EHCI_BANDWIDTH_SIZE]; - /* us allocated per uframe */ - u8 tt_budget[EHCI_BANDWIDTH_SIZE]; - /* us budgeted per uframe */ - struct list_head tt_list; - /* platform-specific data -- must come last */ unsigned long priv[0] __aligned(sizeof(s64)); }; @@ -416,7 +385,6 @@ struct ehci_qh { struct list_head intr_node; /* list of intr QHs */ struct ehci_qtd *dummy; struct list_head unlink_node; - struct ehci_per_sched ps; /* scheduling info */ unsigned unlink_cycle; @@ -430,8 +398,16 @@ struct ehci_qh { u8 xacterrs; /* XactErr retry counter */ #define QH_XACTERR_MAX 32 /* XactErr retry limit */ + /* periodic schedule info */ + u8 usecs; /* intr bandwidth */ u8 gap_uf; /* uframes split/csplit gap */ + u8 c_usecs; /* ... split completion bw */ + u16 tt_usecs; /* tt downstream bandwidth */ + unsigned short period; /* polling interval */ + unsigned short start; /* where polling starts */ +#define NO_FRAME ((unsigned short)~0) /* pick new start */ + struct usb_device *dev; /* access to TT */ unsigned is_out:1; /* bulk or intr OUT */ unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ unsigned dequeue_during_giveback:1; @@ -458,7 +434,6 @@ struct ehci_iso_packet { struct ehci_iso_sched { struct list_head td_list; unsigned span; - unsigned first_packet; struct ehci_iso_packet packet [0]; }; @@ -474,17 +449,22 @@ struct ehci_iso_stream { u8 highspeed; struct list_head td_list; /* queued itds/sitds */ struct list_head free_list; /* list of unused itds/sitds */ + struct usb_device *udev; + struct usb_host_endpoint *ep; /* output of (re)scheduling */ - struct ehci_per_sched ps; /* scheduling info */ - unsigned next_uframe; + int next_uframe; __hc32 splits; /* the rest is derived from the endpoint descriptor, + * trusting urb->interval == f(epdesc->bInterval) and * including the extra info for hw_bufp[0..2] */ - u16 uperiod; /* period in uframes */ + u8 usecs, c_usecs; + u16 interval; + u16 tt_usecs; u16 maxp; + u16 raw_mask; unsigned bandwidth; /* This is used to initialize iTD's hw_bufp fields */ @@ -599,35 +579,6 @@ struct ehci_fstn { /*-------------------------------------------------------------------------*/ -/* - * USB-2.0 Specification Sections 11.14 and 11.18 - * Scheduling and budgeting split transactions using TTs - * - * A hub can have a single TT for all its ports, or multiple TTs (one for each - * port). The bandwidth and budgeting information for the full/low-speed bus - * below each TT is self-contained and independent of the other TTs or the - * high-speed bus. - * - * "Bandwidth" refers to the number of microseconds on the FS/LS bus allocated - * to an interrupt or isochronous endpoint for each frame. "Budget" refers to - * the best-case estimate of the number of full-speed bytes allocated to an - * endpoint for each microframe within an allocated frame. - * - * Removal of an endpoint invalidates a TT's budget. Instead of trying to - * keep an up-to-date record, we recompute the budget when it is needed. - */ - -struct ehci_tt { - u16 bandwidth[EHCI_BANDWIDTH_FRAMES]; - - struct list_head tt_list; /* List of all ehci_tt's */ - struct list_head ps_list; /* Items using this TT */ - struct usb_tt *usb_tt; - int tt_port; /* TT port number */ -}; - -/*-------------------------------------------------------------------------*/ - /* Prepare the PORTSC wakeup flags during controller suspend/resume */ #define ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup) \ diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c index 0551c0a..0b4654259 100644 --- a/drivers/usb/host/fhci-hcd.c +++ b/drivers/usb/host/fhci-hcd.c @@ -26,8 +26,6 @@ #include <linux/io.h> #include <linux/usb.h> #include <linux/usb/hcd.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/of_gpio.h> #include <linux/slab.h> diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index 55486bd..fce13bc 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -412,7 +412,7 @@ struct debug_buffer { tmp = 'h'; break; \ default: \ tmp = '?'; break; \ - } tmp; }) + }; tmp; }) static inline char token_mark(struct fotg210_hcd *fotg210, __hc32 token) { diff --git a/drivers/usb/host/fusbh200-hcd.c b/drivers/usb/host/fusbh200-hcd.c index e1c6d85..299253c 100644 --- a/drivers/usb/host/fusbh200-hcd.c +++ b/drivers/usb/host/fusbh200-hcd.c @@ -402,7 +402,7 @@ struct debug_buffer { case QH_LOW_SPEED: tmp = 'l'; break; \ case QH_HIGH_SPEED: tmp = 'h'; break; \ default: tmp = '?'; break; \ - } tmp; }) + }; tmp; }) static inline char token_mark(struct fusbh200_hcd *fusbh200, __hc32 token) { diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c index ada0a52..5b86ffb 100644 --- a/drivers/usb/host/hwa-hc.c +++ b/drivers/usb/host/hwa-hc.c @@ -199,14 +199,10 @@ static int hwahc_op_get_frame_number(struct usb_hcd *usb_hcd) { struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - struct wahc *wa = &hwahc->wa; - /* - * We cannot query the HWA for the WUSB time since that requires sending - * a synchronous URB and this function can be called in_interrupt. - * Instead, query the USB frame number for our parent and use that. - */ - return usb_get_current_frame_number(wa->usb_dev); + dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__, + usb_hcd, hwahc); + return -ENOSYS; } static int hwahc_op_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb, @@ -570,10 +566,14 @@ found: goto error; } wa->wa_descr = wa_descr = (struct usb_wa_descriptor *) hdr; - if (le16_to_cpu(wa_descr->bcdWAVersion) > 0x0100) + /* Make LE fields CPU order */ + wa_descr->bcdWAVersion = le16_to_cpu(wa_descr->bcdWAVersion); + wa_descr->wNumRPipes = le16_to_cpu(wa_descr->wNumRPipes); + wa_descr->wRPipeMaxBlock = le16_to_cpu(wa_descr->wRPipeMaxBlock); + if (wa_descr->bcdWAVersion > 0x0100) dev_warn(dev, "Wire Adapter v%d.%d newer than groked v1.0\n", - le16_to_cpu(wa_descr->bcdWAVersion) & 0xff00 >> 8, - le16_to_cpu(wa_descr->bcdWAVersion) & 0x00ff); + wa_descr->bcdWAVersion & 0xff00 >> 8, + wa_descr->bcdWAVersion & 0x00ff); result = 0; error: return result; @@ -679,8 +679,7 @@ static void hwahc_security_release(struct hwahc *hwahc) /* nothing to do here so far... */ } -static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface, - kernel_ulong_t quirks) +static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface) { int result; struct device *dev = &iface->dev; @@ -725,7 +724,7 @@ static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface, dev_err(dev, "Can't create WUSB HC structures: %d\n", result); goto error_wusbhc_create; } - result = wa_create(&hwahc->wa, iface, quirks); + result = wa_create(&hwahc->wa, iface); if (result < 0) goto error_wa_create; return 0; @@ -781,7 +780,7 @@ static int hwahc_probe(struct usb_interface *usb_iface, wusbhc = usb_hcd_to_wusbhc(usb_hcd); hwahc = container_of(wusbhc, struct hwahc, wusbhc); hwahc_init(hwahc); - result = hwahc_create(hwahc, usb_iface, id->driver_info); + result = hwahc_create(hwahc, usb_iface); if (result < 0) { dev_err(dev, "Cannot initialize internals: %d\n", result); goto error_hwahc_create; @@ -825,12 +824,6 @@ static void hwahc_disconnect(struct usb_interface *usb_iface) } static struct usb_device_id hwahc_id_table[] = { - /* Alereon 5310 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5310, 0xe0, 0x02, 0x01), - .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC }, - /* Alereon 5611 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5611, 0xe0, 0x02, 0x01), - .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC }, /* FIXME: use class labels for this */ { USB_INTERFACE_INFO(0xe0, 0x02, 0x01), }, {}, diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index 935a2dd..6f29aba 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -2108,7 +2108,7 @@ static int isp1362_show(struct seq_file *s, void *unused) default: s = "?"; break; - } + }; s;}), ep->maxpacket) ; list_for_each_entry(urb, &ep->hep->urb_list, urb_list) { seq_printf(s, " urb%p, %d/%d\n", urb, diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 418444e..caa3764 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -13,24 +13,19 @@ */ #include <linux/clk.h> -#include <linux/dma-mapping.h> +#include <linux/platform_device.h> #include <linux/of_platform.h> #include <linux/of_gpio.h> -#include <linux/platform_device.h> #include <linux/platform_data/atmel.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/usb/hcd.h> #include <mach/hardware.h> #include <asm/gpio.h> #include <mach/cpu.h> - -#include "ohci.h" +#ifndef CONFIG_ARCH_AT91 +#error "CONFIG_ARCH_AT91 must be defined." +#endif #define valid_port(index) ((index) >= 0 && (index) < AT91_MAX_USBH_PORTS) #define at91_for_each_port(index) \ @@ -38,17 +33,7 @@ /* interface, function and usb clocks; sometimes also an AHB clock */ static struct clk *iclk, *fclk, *uclk, *hclk; -/* interface and function clocks; sometimes also an AHB clock */ - -#define DRIVER_DESC "OHCI Atmel driver" - -static const char hcd_name[] = "ohci-atmel"; - -static struct hc_driver __read_mostly ohci_at91_hc_driver; static int clocked; -static int (*orig_ohci_hub_control)(struct usb_hcd *hcd, u16 typeReq, - u16 wValue, u16 wIndex, char *buf, u16 wLength); -static int (*orig_ohci_hub_status_data)(struct usb_hcd *hcd, char *buf); extern int usb_disabled(void); @@ -132,8 +117,6 @@ static void usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *); static int usb_hcd_at91_probe(const struct hc_driver *driver, struct platform_device *pdev) { - struct at91_usbh_data *board; - struct ohci_hcd *ohci; int retval; struct usb_hcd *hcd = NULL; @@ -194,10 +177,8 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, } } - board = hcd->self.controller->platform_data; - ohci = hcd_to_ohci(hcd); - ohci->num_ports = board->ports; at91_start_hc(pdev); + ohci_hcd_init(hcd_to_ohci(hcd)); retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED); if (retval == 0) @@ -257,6 +238,36 @@ static void usb_hcd_at91_remove(struct usb_hcd *hcd, } /*-------------------------------------------------------------------------*/ + +static int +ohci_at91_reset (struct usb_hcd *hcd) +{ + struct at91_usbh_data *board = dev_get_platdata(hcd->self.controller); + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret; + + if ((ret = ohci_init(ohci)) < 0) + return ret; + + ohci->num_ports = board->ports; + return 0; +} + +static int +ohci_at91_start (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret; + + if ((ret = ohci_run(ohci)) < 0) { + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); + ohci_stop(hcd); + return ret; + } + return 0; +} + static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int enable) { if (!valid_port(port)) @@ -286,8 +297,8 @@ static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port) */ static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf) { - struct at91_usbh_data *pdata = hcd->self.controller->platform_data; - int length = orig_ohci_hub_status_data(hcd, buf); + struct at91_usbh_data *pdata = dev_get_platdata(hcd->self.controller); + int length = ohci_hub_status_data(hcd, buf); int port; at91_for_each_port(port) { @@ -365,8 +376,7 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, break; } - ret = orig_ohci_hub_control(hcd, typeReq, wValue, wIndex + 1, - buf, wLength); + ret = ohci_hub_control(hcd, typeReq, wValue, wIndex + 1, buf, wLength); if (ret) goto out; @@ -420,6 +430,51 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /*-------------------------------------------------------------------------*/ +static const struct hc_driver ohci_at91_hc_driver = { + .description = hcd_name, + .product_desc = "AT91 OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .reset = ohci_at91_reset, + .start = ohci_at91_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_at91_hub_status_data, + .hub_control = ohci_at91_hub_control, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + +/*-------------------------------------------------------------------------*/ + static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) { struct platform_device *pdev = data; @@ -469,7 +524,7 @@ MODULE_DEVICE_TABLE(of, at91_ohci_dt_ids); static int ohci_at91_of_init(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - int i, gpio, ret; + int i, gpio; enum of_gpio_flags flags; struct at91_usbh_data *pdata; u32 ports; @@ -481,9 +536,10 @@ static int ohci_at91_of_init(struct platform_device *pdev) * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away. */ - ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -647,11 +703,7 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg) * REVISIT: some boards will be able to turn VBUS off... */ if (at91_suspend_entering_slow_clock()) { - ohci->hc_control = ohci_readl(ohci, &ohci->regs->control); - ohci->hc_control &= OHCI_CTRL_RWC; - ohci_writel(ohci, ohci->hc_control, &ohci->regs->control); - ohci->rh_state = OHCI_RH_HALTED; - + ohci_usb_reset (ohci); /* flush the writes */ (void) ohci_readl (ohci, &ohci->regs->control); at91_stop_clock(); @@ -678,6 +730,8 @@ static int ohci_hcd_at91_drv_resume(struct platform_device *pdev) #define ohci_hcd_at91_drv_resume NULL #endif +MODULE_ALIAS("platform:at91_ohci"); + static struct platform_driver ohci_hcd_at91_driver = { .probe = ohci_hcd_at91_drv_probe, .remove = ohci_hcd_at91_drv_remove, @@ -690,40 +744,3 @@ static struct platform_driver ohci_hcd_at91_driver = { .of_match_table = of_match_ptr(at91_ohci_dt_ids), }, }; - -static int __init ohci_at91_init(void) -{ - if (usb_disabled()) - return -ENODEV; - - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ohci_init_driver(&ohci_at91_hc_driver, NULL); - - /* - * The Atmel HW has some unusual quirks, which require Atmel-specific - * workarounds. We override certain hc_driver functions here to - * achieve that. We explicitly do not enhance ohci_driver_overrides to - * allow this more easily, since this is an unusual case, and we don't - * want to encourage others to override these functions by making it - * too easy. - */ - - orig_ohci_hub_control = ohci_at91_hc_driver.hub_control; - orig_ohci_hub_status_data = ohci_at91_hc_driver.hub_status_data; - - ohci_at91_hc_driver.hub_status_data = ohci_at91_hub_status_data; - ohci_at91_hc_driver.hub_control = ohci_at91_hub_control; - - return platform_driver_register(&ohci_hcd_at91_driver); -} -module_init(ohci_at91_init); - -static void __exit ohci_at91_cleanup(void) -{ - platform_driver_unregister(&ohci_hcd_at91_driver); -} -module_exit(ohci_at91_cleanup); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:at91_ohci"); diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index 3fca52e..31b81f9 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -17,7 +17,7 @@ case PIPE_BULK: temp = "bulk"; break; \ case PIPE_INTERRUPT: temp = "intr"; break; \ default: temp = "isoc"; break; \ - } temp;}) + }; temp;}) #define pipestring(pipe) edstring(usb_pipetype(pipe)) /* debug| print the main components of an URB diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c new file mode 100644 index 0000000..84a20d5 --- /dev/null +++ b/drivers/usb/host/ohci-ep93xx.c @@ -0,0 +1,184 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> + * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> + * (C) Copyright 2002 Hewlett-Packard Company + * + * Bus Glue for ep93xx. + * + * Written by Christopher Hoover <ch@hpl.hp.com> + * Based on fragments of previous driver by Russell King et al. + * + * Modified for LH7A404 from ohci-sa1111.c + * by Durgesh Pattamatta <pattamattad@sharpsec.com> + * + * Modified for pxa27x from ohci-lh7a404.c + * by Nick Bane <nick@cecomputing.co.uk> 26-8-2004 + * + * Modified for ep93xx from ohci-pxa27x.c + * by Lennert Buytenhek <buytenh@wantstofly.org> 28-2-2006 + * Based on an earlier driver by Ray Lehtiniemi + * + * This file is licenced under the GPL. + */ + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/signal.h> +#include <linux/platform_device.h> + +static struct clk *usb_host_clock; + +static int ohci_ep93xx_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + if ((ret = ohci_init(ohci)) < 0) + return ret; + + if ((ret = ohci_run(ohci)) < 0) { + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); + ohci_stop(hcd); + return ret; + } + + return 0; +} + +static struct hc_driver ohci_ep93xx_hc_driver = { + .description = hcd_name, + .product_desc = "EP93xx OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + .start = ohci_ep93xx_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + .get_frame_number = ohci_get_frame, + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + +static int ohci_hcd_ep93xx_drv_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd; + struct resource *res; + int irq; + int ret; + + if (usb_disabled()) + return -ENODEV; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENXIO; + + hcd = usb_create_hcd(&ohci_ep93xx_hc_driver, &pdev->dev, "ep93xx"); + if (!hcd) + return -ENOMEM; + + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + + hcd->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hcd->regs)) { + ret = PTR_ERR(hcd->regs); + goto err_put_hcd; + } + + usb_host_clock = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(usb_host_clock)) { + ret = PTR_ERR(usb_host_clock); + goto err_put_hcd; + } + + clk_enable(usb_host_clock); + + ohci_hcd_init(hcd_to_ohci(hcd)); + + ret = usb_add_hcd(hcd, irq, 0); + if (ret) + goto err_clk_disable; + + return 0; + +err_clk_disable: + clk_disable(usb_host_clock); +err_put_hcd: + usb_put_hcd(hcd); + + return ret; +} + +static int ohci_hcd_ep93xx_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_remove_hcd(hcd); + clk_disable(usb_host_clock); + usb_put_hcd(hcd); + + return 0; +} + +#ifdef CONFIG_PM +static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; + + clk_disable(usb_host_clock); + return 0; +} + +static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; + + clk_enable(usb_host_clock); + + ohci_resume(hcd, false); + return 0; +} +#endif + + +static struct platform_driver ohci_hcd_ep93xx_driver = { + .probe = ohci_hcd_ep93xx_drv_probe, + .remove = ohci_hcd_ep93xx_drv_remove, + .shutdown = usb_hcd_platform_shutdown, +#ifdef CONFIG_PM + .suspend = ohci_hcd_ep93xx_drv_suspend, + .resume = ohci_hcd_ep93xx_drv_resume, +#endif + .driver = { + .name = "ep93xx-ohci", + .owner = THIS_MODULE, + }, +}; + +MODULE_ALIAS("platform:ep93xx-ohci"); diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index 91ec9b2..dc6ee9a 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -12,55 +12,98 @@ */ #include <linux/clk.h> -#include <linux/dma-mapping.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/platform_data/usb-ohci-exynos.h> #include <linux/usb/phy.h> #include <linux/usb/samsung_usb_phy.h> -#include <linux/usb.h> -#include <linux/usb/hcd.h> -#include <linux/usb/otg.h> - -#include "ohci.h" - -#define DRIVER_DESC "OHCI EXYNOS driver" - -static const char hcd_name[] = "ohci-exynos"; -static struct hc_driver __read_mostly exynos_ohci_hc_driver; - -#define to_exynos_ohci(hcd) (struct exynos_ohci_hcd *)(hcd_to_ohci(hcd)->priv) struct exynos_ohci_hcd { + struct device *dev; + struct usb_hcd *hcd; struct clk *clk; struct usb_phy *phy; struct usb_otg *otg; + struct exynos4_ohci_platdata *pdata; }; -static void exynos_ohci_phy_enable(struct platform_device *pdev) +static void exynos_ohci_phy_enable(struct exynos_ohci_hcd *exynos_ohci) { - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd); + struct platform_device *pdev = to_platform_device(exynos_ohci->dev); if (exynos_ohci->phy) usb_phy_init(exynos_ohci->phy); + else if (exynos_ohci->pdata && exynos_ohci->pdata->phy_init) + exynos_ohci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST); } -static void exynos_ohci_phy_disable(struct platform_device *pdev) +static void exynos_ohci_phy_disable(struct exynos_ohci_hcd *exynos_ohci) { - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd); + struct platform_device *pdev = to_platform_device(exynos_ohci->dev); if (exynos_ohci->phy) usb_phy_shutdown(exynos_ohci->phy); + else if (exynos_ohci->pdata && exynos_ohci->pdata->phy_exit) + exynos_ohci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); +} + +static int ohci_exynos_reset(struct usb_hcd *hcd) +{ + return ohci_init(hcd_to_ohci(hcd)); +} + +static int ohci_exynos_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + ohci_dbg(ohci, "ohci_exynos_start, ohci:%p", ohci); + + ret = ohci_run(ohci); + if (ret < 0) { + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); + ohci_stop(hcd); + return ret; + } + + return 0; } +static const struct hc_driver exynos_ohci_hc_driver = { + .description = hcd_name, + .product_desc = "EXYNOS OHCI Host Controller", + .hcd_priv_size = sizeof(struct ohci_hcd), + + .irq = ohci_irq, + .flags = HCD_MEMORY|HCD_USB11, + + .reset = ohci_exynos_reset, + .start = ohci_exynos_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + + .get_frame_number = ohci_get_frame, + + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + static int exynos_ohci_probe(struct platform_device *pdev) { + struct exynos4_ohci_platdata *pdata = dev_get_platdata(&pdev->dev); struct exynos_ohci_hcd *exynos_ohci; struct usb_hcd *hcd; + struct ohci_hcd *ohci; struct resource *res; struct usb_phy *phy; int irq; @@ -71,18 +114,15 @@ static int exynos_ohci_probe(struct platform_device *pdev) * Since shared usb code relies on it, set it here for now. * Once we move to full device tree support this will vanish off. */ - err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (err) - return err; - - hcd = usb_create_hcd(&exynos_ohci_hc_driver, - &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - dev_err(&pdev->dev, "Unable to create HCD\n"); + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_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; - } - - exynos_ohci = to_exynos_ohci(hcd); if (of_device_is_compatible(pdev->dev.of_node, "samsung,exynos5440-ohci")) @@ -90,15 +130,30 @@ static int exynos_ohci_probe(struct platform_device *pdev) phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); if (IS_ERR(phy)) { - usb_put_hcd(hcd); - dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); - return -EPROBE_DEFER; + /* Fallback to pdata */ + if (!pdata) { + dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); + return -EPROBE_DEFER; + } else { + exynos_ohci->pdata = pdata; + } } else { exynos_ohci->phy = phy; exynos_ohci->otg = phy->otg; } skip_phy: + + exynos_ohci->dev = &pdev->dev; + + hcd = usb_create_hcd(&exynos_ohci_hc_driver, &pdev->dev, + dev_name(&pdev->dev)); + if (!hcd) { + dev_err(&pdev->dev, "Unable to create HCD\n"); + return -ENOMEM; + } + + exynos_ohci->hcd = hcd; exynos_ohci->clk = devm_clk_get(&pdev->dev, "usbhost"); if (IS_ERR(exynos_ohci->clk)) { @@ -135,21 +190,26 @@ skip_phy: } if (exynos_ohci->otg) - exynos_ohci->otg->set_host(exynos_ohci->otg, &hcd->self); + exynos_ohci->otg->set_host(exynos_ohci->otg, + &exynos_ohci->hcd->self); - platform_set_drvdata(pdev, hcd); + exynos_ohci_phy_enable(exynos_ohci); - exynos_ohci_phy_enable(pdev); + ohci = hcd_to_ohci(hcd); + ohci_hcd_init(ohci); err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) { dev_err(&pdev->dev, "Failed to add USB HCD\n"); goto fail_add_hcd; } + + platform_set_drvdata(pdev, exynos_ohci); + return 0; fail_add_hcd: - exynos_ohci_phy_disable(pdev); + exynos_ohci_phy_disable(exynos_ohci); fail_io: clk_disable_unprepare(exynos_ohci->clk); fail_clk: @@ -159,15 +219,16 @@ fail_clk: static int exynos_ohci_remove(struct platform_device *pdev) { - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd); + struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev); + struct usb_hcd *hcd = exynos_ohci->hcd; usb_remove_hcd(hcd); if (exynos_ohci->otg) - exynos_ohci->otg->set_host(exynos_ohci->otg, &hcd->self); + exynos_ohci->otg->set_host(exynos_ohci->otg, + &exynos_ohci->hcd->self); - exynos_ohci_phy_disable(pdev); + exynos_ohci_phy_disable(exynos_ohci); clk_disable_unprepare(exynos_ohci->clk); @@ -178,7 +239,8 @@ static int exynos_ohci_remove(struct platform_device *pdev) static void exynos_ohci_shutdown(struct platform_device *pdev) { - struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev); + struct usb_hcd *hcd = exynos_ohci->hcd; if (hcd->driver->shutdown) hcd->driver->shutdown(hcd); @@ -187,10 +249,9 @@ static void exynos_ohci_shutdown(struct platform_device *pdev) #ifdef CONFIG_PM static int exynos_ohci_suspend(struct device *dev) { - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd); + struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); + struct usb_hcd *hcd = exynos_ohci->hcd; struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct platform_device *pdev = to_platform_device(dev); unsigned long flags; int rc = 0; @@ -210,9 +271,10 @@ static int exynos_ohci_suspend(struct device *dev) clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); if (exynos_ohci->otg) - exynos_ohci->otg->set_host(exynos_ohci->otg, &hcd->self); + exynos_ohci->otg->set_host(exynos_ohci->otg, + &exynos_ohci->hcd->self); - exynos_ohci_phy_disable(pdev); + exynos_ohci_phy_disable(exynos_ohci); clk_disable_unprepare(exynos_ohci->clk); @@ -224,16 +286,16 @@ fail: static int exynos_ohci_resume(struct device *dev) { - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd); - struct platform_device *pdev = to_platform_device(dev); + struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); + struct usb_hcd *hcd = exynos_ohci->hcd; clk_prepare_enable(exynos_ohci->clk); if (exynos_ohci->otg) - exynos_ohci->otg->set_host(exynos_ohci->otg, &hcd->self); + exynos_ohci->otg->set_host(exynos_ohci->otg, + &exynos_ohci->hcd->self); - exynos_ohci_phy_enable(pdev); + exynos_ohci_phy_enable(exynos_ohci); ohci_resume(hcd, false); @@ -244,10 +306,6 @@ static int exynos_ohci_resume(struct device *dev) #define exynos_ohci_resume NULL #endif -static const struct ohci_driver_overrides exynos_overrides __initconst = { - .extra_priv_size = sizeof(struct exynos_ohci_hcd), -}; - static const struct dev_pm_ops exynos_ohci_pm_ops = { .suspend = exynos_ohci_suspend, .resume = exynos_ohci_resume, @@ -273,23 +331,6 @@ static struct platform_driver exynos_ohci_driver = { .of_match_table = of_match_ptr(exynos_ohci_match), } }; -static int __init ohci_exynos_init(void) -{ - if (usb_disabled()) - return -ENODEV; - - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ohci_init_driver(&exynos_ohci_hc_driver, &exynos_overrides); - return platform_driver_register(&exynos_ohci_driver); -} -module_init(ohci_exynos_init); - -static void __exit ohci_exynos_cleanup(void) -{ - platform_driver_unregister(&exynos_ohci_driver); -} -module_exit(ohci_exynos_cleanup); MODULE_ALIAS("platform:exynos-ohci"); MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 8ada13f..604cad1 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1161,12 +1161,10 @@ void ohci_init_driver(struct hc_driver *drv, /* Copy the generic table to drv and then apply the overrides */ *drv = ohci_hc_driver; - if (over) { - drv->product_desc = over->product_desc; - drv->hcd_priv_size += over->extra_priv_size; - if (over->reset) - drv->reset = over->reset; - } + drv->product_desc = over->product_desc; + drv->hcd_priv_size += over->extra_priv_size; + if (over->reset) + drv->reset = over->reset; } EXPORT_SYMBOL_GPL(ohci_init_driver); @@ -1181,6 +1179,46 @@ MODULE_LICENSE ("GPL"); #define SA1111_DRIVER ohci_hcd_sa1111_driver #endif +#if defined(CONFIG_ARCH_S3C24XX) || defined(CONFIG_ARCH_S3C64XX) +#include "ohci-s3c2410.c" +#define S3C2410_PLATFORM_DRIVER ohci_hcd_s3c2410_driver +#endif + +#ifdef CONFIG_USB_OHCI_EXYNOS +#include "ohci-exynos.c" +#define EXYNOS_PLATFORM_DRIVER exynos_ohci_driver +#endif + +#ifdef CONFIG_USB_OHCI_HCD_OMAP1 +#include "ohci-omap.c" +#define OMAP1_PLATFORM_DRIVER ohci_hcd_omap_driver +#endif + +#ifdef CONFIG_USB_OHCI_HCD_OMAP3 +#include "ohci-omap3.c" +#define OMAP3_PLATFORM_DRIVER ohci_hcd_omap3_driver +#endif + +#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) +#include "ohci-pxa27x.c" +#define PLATFORM_DRIVER ohci_hcd_pxa27x_driver +#endif + +#ifdef CONFIG_ARCH_EP93XX +#include "ohci-ep93xx.c" +#define EP93XX_PLATFORM_DRIVER ohci_hcd_ep93xx_driver +#endif + +#ifdef CONFIG_ARCH_AT91 +#include "ohci-at91.c" +#define AT91_PLATFORM_DRIVER ohci_hcd_at91_driver +#endif + +#ifdef CONFIG_ARCH_LPC32XX +#include "ohci-nxp.c" +#define NXP_PLATFORM_DRIVER usb_hcd_nxp_driver +#endif + #ifdef CONFIG_ARCH_DAVINCI_DA8XX #include "ohci-da8xx.c" #define DAVINCI_PLATFORM_DRIVER ohci_hcd_da8xx_driver @@ -1191,6 +1229,11 @@ MODULE_LICENSE ("GPL"); #define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver #endif +#ifdef CONFIG_PLAT_SPEAR +#include "ohci-spear.c" +#define SPEAR_PLATFORM_DRIVER spear_ohci_hcd_driver +#endif + #ifdef CONFIG_PPC_PS3 #include "ohci-ps3.c" #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver @@ -1253,6 +1296,18 @@ static int __init ohci_hcd_mod_init(void) goto error_platform; #endif +#ifdef OMAP1_PLATFORM_DRIVER + retval = platform_driver_register(&OMAP1_PLATFORM_DRIVER); + if (retval < 0) + goto error_omap1_platform; +#endif + +#ifdef OMAP3_PLATFORM_DRIVER + retval = platform_driver_register(&OMAP3_PLATFORM_DRIVER); + if (retval < 0) + goto error_omap3_platform; +#endif + #ifdef OF_PLATFORM_DRIVER retval = platform_driver_register(&OF_PLATFORM_DRIVER); if (retval < 0) @@ -1277,19 +1332,79 @@ static int __init ohci_hcd_mod_init(void) goto error_tmio; #endif +#ifdef S3C2410_PLATFORM_DRIVER + retval = platform_driver_register(&S3C2410_PLATFORM_DRIVER); + if (retval < 0) + goto error_s3c2410; +#endif + +#ifdef EXYNOS_PLATFORM_DRIVER + retval = platform_driver_register(&EXYNOS_PLATFORM_DRIVER); + if (retval < 0) + goto error_exynos; +#endif + +#ifdef EP93XX_PLATFORM_DRIVER + retval = platform_driver_register(&EP93XX_PLATFORM_DRIVER); + if (retval < 0) + goto error_ep93xx; +#endif + +#ifdef AT91_PLATFORM_DRIVER + retval = platform_driver_register(&AT91_PLATFORM_DRIVER); + if (retval < 0) + goto error_at91; +#endif + +#ifdef NXP_PLATFORM_DRIVER + retval = platform_driver_register(&NXP_PLATFORM_DRIVER); + if (retval < 0) + goto error_nxp; +#endif + #ifdef DAVINCI_PLATFORM_DRIVER retval = platform_driver_register(&DAVINCI_PLATFORM_DRIVER); if (retval < 0) goto error_davinci; #endif +#ifdef SPEAR_PLATFORM_DRIVER + retval = platform_driver_register(&SPEAR_PLATFORM_DRIVER); + if (retval < 0) + goto error_spear; +#endif + return retval; /* Error path */ +#ifdef SPEAR_PLATFORM_DRIVER + platform_driver_unregister(&SPEAR_PLATFORM_DRIVER); + error_spear: +#endif #ifdef DAVINCI_PLATFORM_DRIVER platform_driver_unregister(&DAVINCI_PLATFORM_DRIVER); error_davinci: #endif +#ifdef NXP_PLATFORM_DRIVER + platform_driver_unregister(&NXP_PLATFORM_DRIVER); + error_nxp: +#endif +#ifdef AT91_PLATFORM_DRIVER + platform_driver_unregister(&AT91_PLATFORM_DRIVER); + error_at91: +#endif +#ifdef EP93XX_PLATFORM_DRIVER + platform_driver_unregister(&EP93XX_PLATFORM_DRIVER); + error_ep93xx: +#endif +#ifdef EXYNOS_PLATFORM_DRIVER + platform_driver_unregister(&EXYNOS_PLATFORM_DRIVER); + error_exynos: +#endif +#ifdef S3C2410_PLATFORM_DRIVER + platform_driver_unregister(&S3C2410_PLATFORM_DRIVER); + error_s3c2410: +#endif #ifdef TMIO_OHCI_DRIVER platform_driver_unregister(&TMIO_OHCI_DRIVER); error_tmio: @@ -1306,6 +1421,14 @@ static int __init ohci_hcd_mod_init(void) platform_driver_unregister(&OF_PLATFORM_DRIVER); error_of_platform: #endif +#ifdef OMAP3_PLATFORM_DRIVER + platform_driver_unregister(&OMAP3_PLATFORM_DRIVER); + error_omap3_platform: +#endif +#ifdef OMAP1_PLATFORM_DRIVER + platform_driver_unregister(&OMAP1_PLATFORM_DRIVER); + error_omap1_platform: +#endif #ifdef PLATFORM_DRIVER platform_driver_unregister(&PLATFORM_DRIVER); error_platform: @@ -1327,9 +1450,27 @@ module_init(ohci_hcd_mod_init); static void __exit ohci_hcd_mod_exit(void) { +#ifdef SPEAR_PLATFORM_DRIVER + platform_driver_unregister(&SPEAR_PLATFORM_DRIVER); +#endif #ifdef DAVINCI_PLATFORM_DRIVER platform_driver_unregister(&DAVINCI_PLATFORM_DRIVER); #endif +#ifdef NXP_PLATFORM_DRIVER + platform_driver_unregister(&NXP_PLATFORM_DRIVER); +#endif +#ifdef AT91_PLATFORM_DRIVER + platform_driver_unregister(&AT91_PLATFORM_DRIVER); +#endif +#ifdef EP93XX_PLATFORM_DRIVER + platform_driver_unregister(&EP93XX_PLATFORM_DRIVER); +#endif +#ifdef EXYNOS_PLATFORM_DRIVER + platform_driver_unregister(&EXYNOS_PLATFORM_DRIVER); +#endif +#ifdef S3C2410_PLATFORM_DRIVER + platform_driver_unregister(&S3C2410_PLATFORM_DRIVER); +#endif #ifdef TMIO_OHCI_DRIVER platform_driver_unregister(&TMIO_OHCI_DRIVER); #endif @@ -1342,6 +1483,12 @@ static void __exit ohci_hcd_mod_exit(void) #ifdef OF_PLATFORM_DRIVER platform_driver_unregister(&OF_PLATFORM_DRIVER); #endif +#ifdef OMAP3_PLATFORM_DRIVER + platform_driver_unregister(&OMAP3_PLATFORM_DRIVER); +#endif +#ifdef OMAP1_PLATFORM_DRIVER + platform_driver_unregister(&OMAP1_PLATFORM_DRIVER); +#endif #ifdef PLATFORM_DRIVER platform_driver_unregister(&PLATFORM_DRIVER); #endif diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 61705a7..2347ab8 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -212,11 +212,10 @@ __acquires(ohci->lock) /* Sometimes PCI D3 suspend trashes frame timings ... */ periodic_reinit (ohci); - /* - * The following code is executed with ohci->lock held and - * irqs disabled if and only if autostopped is true. This - * will cause sparse to warn about a "context imbalance". + /* the following code is executed with ohci->lock held and + * irqs disabled if and only if autostopped is true */ + skip_resume: /* interrupts might have been disabled */ ohci_writel (ohci, OHCI_INTR_INIT, &ohci->regs->intrenable); @@ -532,7 +531,7 @@ ohci_hub_descriptor ( temp |= 0x0010; else if (rh & RH_A_OCPM) /* per-port overcurrent reporting? */ temp |= 0x0008; - desc->wHubCharacteristics = cpu_to_le16(temp); + desc->wHubCharacteristics = (__force __u16)cpu_to_hc16(ohci, temp); /* ports removable, and usb 1.0 legacy PortPwrCtrlMask */ rh = roothub_b (ohci); diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c index e99db8a..7d7d507 100644 --- a/drivers/usb/host/ohci-nxp.c +++ b/drivers/usb/host/ohci-nxp.c @@ -19,19 +19,10 @@ * or implied. */ #include <linux/clk.h> -#include <linux/dma-mapping.h> -#include <linux/io.h> +#include <linux/platform_device.h> #include <linux/i2c.h> -#include <linux/kernel.h> -#include <linux/module.h> #include <linux/of.h> -#include <linux/platform_device.h> #include <linux/usb/isp1301.h> -#include <linux/usb.h> -#include <linux/usb/hcd.h> - -#include "ohci.h" - #include <mach/hardware.h> #include <asm/mach-types.h> @@ -66,11 +57,6 @@ #define start_int_umask(irq) #endif -#define DRIVER_DESC "OHCI NXP driver" - -static const char hcd_name[] = "ohci-nxp"; -static struct hc_driver __read_mostly ohci_nxp_hc_driver; - static struct i2c_client *isp1301_i2c_client; extern int usb_disabled(void); @@ -146,14 +132,14 @@ static inline void isp1301_vbus_off(void) OTG1_VBUS_DRV); } -static void ohci_nxp_start_hc(void) +static void nxp_start_hc(void) { unsigned long tmp = __raw_readl(USB_OTG_STAT_CONTROL) | HOST_EN; __raw_writel(tmp, USB_OTG_STAT_CONTROL); isp1301_vbus_on(); } -static void ohci_nxp_stop_hc(void) +static void nxp_stop_hc(void) { unsigned long tmp; isp1301_vbus_off(); @@ -161,9 +147,68 @@ static void ohci_nxp_stop_hc(void) __raw_writel(tmp, USB_OTG_STAT_CONTROL); } -static int ohci_hcd_nxp_probe(struct platform_device *pdev) +static int ohci_nxp_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + if ((ret = ohci_init(ohci)) < 0) + return ret; + + if ((ret = ohci_run(ohci)) < 0) { + dev_err(hcd->self.controller, "can't start\n"); + ohci_stop(hcd); + return ret; + } + return 0; +} + +static const struct hc_driver ohci_nxp_hc_driver = { + .description = hcd_name, + .product_desc = "nxp OHCI", + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + .hcd_priv_size = sizeof(struct ohci_hcd), + /* + * basic lifecycle operations + */ + .start = ohci_nxp_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + +static int usb_hcd_nxp_probe(struct platform_device *pdev) { struct usb_hcd *hcd = 0; + struct ohci_hcd *ohci; const struct hc_driver *driver = &ohci_nxp_hc_driver; struct resource *res; int ret = 0, irq; @@ -181,9 +226,8 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev) return -EPROBE_DEFER; } - ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) - goto fail_disable; + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name); if (usb_disabled()) { @@ -269,15 +313,17 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev) goto fail_resource; } - ohci_nxp_start_hc(); + nxp_start_hc(); platform_set_drvdata(pdev, hcd); + ohci = hcd_to_ohci(hcd); + ohci_hcd_init(ohci); dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq); ret = usb_add_hcd(hcd, irq, 0); if (ret == 0) return ret; - ohci_nxp_stop_hc(); + nxp_stop_hc(); fail_resource: usb_put_hcd(hcd); fail_hcd: @@ -299,12 +345,12 @@ fail_disable: return ret; } -static int ohci_hcd_nxp_remove(struct platform_device *pdev) +static int usb_hcd_nxp_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); usb_remove_hcd(hcd); - ohci_nxp_stop_hc(); + nxp_stop_hc(); usb_put_hcd(hcd); clk_disable(usb_pll_clk); clk_put(usb_pll_clk); @@ -320,40 +366,20 @@ static int ohci_hcd_nxp_remove(struct platform_device *pdev) MODULE_ALIAS("platform:usb-ohci"); #ifdef CONFIG_OF -static const struct of_device_id ohci_hcd_nxp_match[] = { +static const struct of_device_id usb_hcd_nxp_match[] = { { .compatible = "nxp,ohci-nxp" }, {}, }; -MODULE_DEVICE_TABLE(of, ohci_hcd_nxp_match); +MODULE_DEVICE_TABLE(of, usb_hcd_nxp_match); #endif -static struct platform_driver ohci_hcd_nxp_driver = { +static struct platform_driver usb_hcd_nxp_driver = { .driver = { .name = "usb-ohci", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(ohci_hcd_nxp_match), + .of_match_table = of_match_ptr(usb_hcd_nxp_match), }, - .probe = ohci_hcd_nxp_probe, - .remove = ohci_hcd_nxp_remove, + .probe = usb_hcd_nxp_probe, + .remove = usb_hcd_nxp_remove, }; -static int __init ohci_nxp_init(void) -{ - if (usb_disabled()) - return -ENODEV; - - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - - ohci_init_driver(&ohci_nxp_hc_driver, NULL); - return platform_driver_register(&ohci_hcd_nxp_driver); -} -module_init(ohci_nxp_init); - -static void __exit ohci_nxp_cleanup(void) -{ - platform_driver_unregister(&ohci_hcd_nxp_driver); -} -module_exit(ohci_nxp_cleanup); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/ohci-octeon.c b/drivers/usb/host/ohci-octeon.c index 6c16dce..342dc7e 100644 --- a/drivers/usb/host/ohci-octeon.c +++ b/drivers/usb/host/ohci-octeon.c @@ -127,9 +127,8 @@ static int ohci_octeon_drv_probe(struct platform_device *pdev) } /* Ohci is a 32-bit device. */ - ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; hcd = usb_create_hcd(&ohci_octeon_hc_driver, &pdev->dev, "octeon"); if (!hcd) diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index f253214..31d3a12 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -14,21 +14,12 @@ * This file is licenced under the GPL. */ +#include <linux/signal.h> +#include <linux/jiffies.h> +#include <linux/platform_device.h> #include <linux/clk.h> -#include <linux/dma-mapping.h> #include <linux/err.h> #include <linux/gpio.h> -#include <linux/io.h> -#include <linux/jiffies.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/usb/otg.h> -#include <linux/platform_device.h> -#include <linux/signal.h> -#include <linux/usb.h> -#include <linux/usb/hcd.h> - -#include "ohci.h" #include <asm/io.h> #include <asm/mach-types.h> @@ -51,7 +42,10 @@ #define OMAP1510_LB_MMU_RAM_H 0xfffec234 #define OMAP1510_LB_MMU_RAM_L 0xfffec238 -#define DRIVER_DESC "OHCI OMAP driver" + +#ifndef CONFIG_ARCH_OMAP +#error "This file is OMAP bus glue. CONFIG_OMAP must be defined." +#endif #ifdef CONFIG_TPS65010 #include <linux/i2c/tps65010.h> @@ -74,9 +68,8 @@ extern int ocpi_enable(void); static struct clk *usb_host_ck; static struct clk *usb_dc_ck; - -static const char hcd_name[] = "ohci-omap"; -static struct hc_driver __read_mostly ohci_omap_hc_driver; +static int host_enabled; +static int host_initialized; static void omap_ohci_clock_power(int on) { @@ -195,7 +188,7 @@ static void start_hnp(struct ohci_hcd *ohci) /*-------------------------------------------------------------------------*/ -static int ohci_omap_reset(struct usb_hcd *hcd) +static int ohci_omap_init(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); struct omap_usb_config *config = dev_get_platdata(hcd->self.controller); @@ -205,9 +198,9 @@ static int ohci_omap_reset(struct usb_hcd *hcd) dev_dbg(hcd->self.controller, "starting USB Controller\n"); if (config->otg) { - hcd->self.otg_port = config->otg; + ohci_to_hcd(ohci)->self.otg_port = config->otg; /* default/minimum OTG power budget: 8 mA */ - hcd->power_budget = 8; + ohci_to_hcd(ohci)->power_budget = 8; } /* boards can use OTG transceivers in non-OTG modes */ @@ -245,15 +238,9 @@ static int ohci_omap_reset(struct usb_hcd *hcd) omap_1510_local_bus_init(); } - ret = ohci_setup(hcd); - if (ret < 0) + if ((ret = ohci_init(ohci)) < 0) return ret; - if (config->otg || config->rwc) { - ohci->hc_control = OHCI_CTRL_RWC; - writel(OHCI_CTRL_RWC, &ohci->regs->control); - } - /* board-specific power switching and overcurrent support */ if (machine_is_omap_osk() || machine_is_omap_innovator()) { u32 rh = roothub_a (ohci); @@ -294,6 +281,14 @@ static int ohci_omap_reset(struct usb_hcd *hcd) return 0; } +static void ohci_omap_stop(struct usb_hcd *hcd) +{ + dev_dbg(hcd->self.controller, "stopping USB Controller\n"); + ohci_stop(hcd); + omap_ohci_clock_power(0); +} + + /*-------------------------------------------------------------------------*/ /** @@ -309,6 +304,7 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver, { int retval, irq; struct usb_hcd *hcd = 0; + struct ohci_hcd *ohci; if (pdev->num_resources != 2) { printk(KERN_ERR "hcd probe: invalid num_resources: %i\n", @@ -358,6 +354,12 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver, goto err2; } + ohci = hcd_to_ohci(hcd); + ohci_hcd_init(ohci); + + host_initialized = 0; + host_enabled = 1; + irq = platform_get_irq(pdev, 0); if (irq < 0) { retval = -ENXIO; @@ -367,6 +369,11 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver, if (retval) goto err3; + host_initialized = 1; + + if (!host_enabled) + omap_ohci_clock_power(0); + return 0; err3: iounmap(hcd->regs); @@ -395,9 +402,7 @@ err0: static inline void usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev) { - dev_dbg(hcd->self.controller, "stopping USB Controller\n"); usb_remove_hcd(hcd); - omap_ohci_clock_power(0); if (!IS_ERR_OR_NULL(hcd->phy)) { (void) otg_set_host(hcd->phy->otg, 0); usb_put_phy(hcd->phy); @@ -413,6 +418,76 @@ usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev) /*-------------------------------------------------------------------------*/ +static int +ohci_omap_start (struct usb_hcd *hcd) +{ + struct omap_usb_config *config; + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret; + + if (!host_enabled) + return 0; + config = dev_get_platdata(hcd->self.controller); + if (config->otg || config->rwc) { + ohci->hc_control = OHCI_CTRL_RWC; + writel(OHCI_CTRL_RWC, &ohci->regs->control); + } + + if ((ret = ohci_run (ohci)) < 0) { + dev_err(hcd->self.controller, "can't start\n"); + ohci_stop (hcd); + return ret; + } + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static const struct hc_driver ohci_omap_hc_driver = { + .description = hcd_name, + .product_desc = "OMAP OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .reset = ohci_omap_init, + .start = ohci_omap_start, + .stop = ohci_omap_stop, + .shutdown = ohci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + +/*-------------------------------------------------------------------------*/ + static int ohci_hcd_omap_drv_probe(struct platform_device *dev) { return usb_hcd_omap_probe(&ohci_omap_hc_driver, dev); @@ -431,23 +506,16 @@ static int ohci_hcd_omap_drv_remove(struct platform_device *dev) #ifdef CONFIG_PM -static int ohci_omap_suspend(struct platform_device *pdev, pm_message_t message) +static int ohci_omap_suspend(struct platform_device *dev, pm_message_t message) { - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - bool do_wakeup = device_may_wakeup(&pdev->dev); - int ret; + struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(dev)); if (time_before(jiffies, ohci->next_statechange)) msleep(5); ohci->next_statechange = jiffies; - ret = ohci_suspend(hcd, do_wakeup); - if (ret) - return ret; - omap_ohci_clock_power(0); - return ret; + return 0; } static int ohci_omap_resume(struct platform_device *dev) @@ -485,29 +553,4 @@ static struct platform_driver ohci_hcd_omap_driver = { }, }; -static const struct ohci_driver_overrides omap_overrides __initconst = { - .product_desc = "OMAP OHCI", - .reset = ohci_omap_reset -}; - -static int __init ohci_omap_init(void) -{ - if (usb_disabled()) - return -ENODEV; - - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - - ohci_init_driver(&ohci_omap_hc_driver, &omap_overrides); - return platform_driver_register(&ohci_hcd_omap_driver); -} -module_init(ohci_omap_init); - -static void __exit ohci_omap_cleanup(void) -{ - platform_driver_unregister(&ohci_hcd_omap_driver); -} -module_exit(ohci_omap_cleanup); - -MODULE_DESCRIPTION(DRIVER_DESC); MODULE_ALIAS("platform:ohci"); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c index 2145741..a09af26 100644 --- a/drivers/usb/host/ohci-omap3.c +++ b/drivers/usb/host/ohci-omap3.c @@ -29,22 +29,90 @@ * - add kernel-doc */ -#include <linux/dma-mapping.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/usb/otg.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <linux/usb.h> -#include <linux/usb/hcd.h> +#include <linux/of.h> +#include <linux/dma-mapping.h> + +/*-------------------------------------------------------------------------*/ + +static int ohci_omap3_init(struct usb_hcd *hcd) +{ + dev_dbg(hcd->self.controller, "starting OHCI controller\n"); + + return ohci_init(hcd_to_ohci(hcd)); +} + +/*-------------------------------------------------------------------------*/ + +static int ohci_omap3_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + /* + * RemoteWakeupConnected has to be set explicitly before + * calling ohci_run. The reset value of RWC is 0. + */ + ohci->hc_control = OHCI_CTRL_RWC; + writel(OHCI_CTRL_RWC, &ohci->regs->control); + + ret = ohci_run(ohci); + + if (ret < 0) { + dev_err(hcd->self.controller, "can't start\n"); + ohci_stop(hcd); + } + + return ret; +} + +/*-------------------------------------------------------------------------*/ + +static const struct hc_driver ohci_omap3_hc_driver = { + .description = hcd_name, + .product_desc = "OMAP3 OHCI Host Controller", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .reset = ohci_omap3_init, + .start = ohci_omap3_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, -#include "ohci.h" + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, -#define DRIVER_DESC "OHCI OMAP3 driver" + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; -static const char hcd_name[] = "ohci-omap3"; -static struct hc_driver __read_mostly ohci_omap3_hc_driver; +/*-------------------------------------------------------------------------*/ /* * configure so an HC device and id are always provided @@ -61,11 +129,10 @@ static struct hc_driver __read_mostly ohci_omap3_hc_driver; static int ohci_hcd_omap3_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct ohci_hcd *ohci; struct usb_hcd *hcd = NULL; void __iomem *regs = NULL; struct resource *res; - int ret; + int ret = -ENODEV; int irq; if (usb_disabled()) @@ -99,11 +166,11 @@ static int ohci_hcd_omap3_probe(struct platform_device *pdev) * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away. */ - ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); - if (ret) - goto err_io; + if (!dev->dma_mask) + dev->dma_mask = &dev->coherent_dma_mask; + if (!dev->coherent_dma_mask) + dev->coherent_dma_mask = DMA_BIT_MASK(32); - ret = -ENODEV; hcd = usb_create_hcd(&ohci_omap3_hc_driver, dev, dev_name(dev)); if (!hcd) { @@ -118,12 +185,7 @@ static int ohci_hcd_omap3_probe(struct platform_device *pdev) pm_runtime_enable(dev); pm_runtime_get_sync(dev); - ohci = hcd_to_ohci(hcd); - /* - * RemoteWakeupConnected has to be set explicitly before - * calling ohci_run. The reset value of RWC is 0. - */ - ohci->hc_control = OHCI_CTRL_RWC; + ohci_hcd_init(hcd_to_ohci(hcd)); ret = usb_add_hcd(hcd, irq, 0); if (ret) { @@ -186,25 +248,5 @@ static struct platform_driver ohci_hcd_omap3_driver = { }, }; -static int __init ohci_omap3_init(void) -{ - if (usb_disabled()) - return -ENODEV; - - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - - ohci_init_driver(&ohci_omap3_hc_driver, NULL); - return platform_driver_register(&ohci_hcd_omap3_driver); -} -module_init(ohci_omap3_init); - -static void __exit ohci_omap3_cleanup(void) -{ - platform_driver_unregister(&ohci_hcd_omap3_driver); -} -module_exit(ohci_omap3_cleanup); - -MODULE_DESCRIPTION(DRIVER_DESC); MODULE_ALIAS("platform:ohci-omap3"); MODULE_AUTHOR("Anand Gadiyar <gadiyar@ti.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 90879e9..ec337c2 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -150,16 +150,28 @@ static int ohci_quirk_nec(struct usb_hcd *hcd) static int ohci_quirk_amd700(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); + struct pci_dev *amd_smbus_dev; + u8 rev; if (usb_amd_find_chipset_info()) ohci->flags |= OHCI_QUIRK_AMD_PLL; + amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, + PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL); + if (!amd_smbus_dev) + return 0; + + rev = amd_smbus_dev->revision; + /* SB800 needs pre-fetch fix */ - if (usb_amd_prefetch_quirk()) { + if ((rev >= 0x40) && (rev <= 0x4f)) { ohci->flags |= OHCI_QUIRK_AMD_PREFETCH; ohci_dbg(ohci, "enabled AMD prefetch quirk\n"); } + pci_dev_put(amd_smbus_dev); + amd_smbus_dev = NULL; + return 0; } @@ -311,4 +323,3 @@ module_exit(ohci_pci_cleanup); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_SOFTDEP("pre: ehci_pci"); diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index f351ff5..a4c6410 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -139,21 +139,14 @@ static int ohci_platform_remove(struct platform_device *dev) static int ohci_platform_suspend(struct device *dev) { - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct usb_ohci_pdata *pdata = dev->platform_data; + struct usb_ohci_pdata *pdata = dev_get_platdata(dev); struct platform_device *pdev = container_of(dev, struct platform_device, dev); - bool do_wakeup = device_may_wakeup(dev); - int ret; - - ret = ohci_suspend(hcd, do_wakeup); - if (ret) - return ret; if (pdata->power_suspend) pdata->power_suspend(pdev); - return ret; + return 0; } static int ohci_platform_resume(struct device *dev) diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c index 81f3eba..75f5a1e 100644 --- a/drivers/usb/host/ohci-ppc-of.c +++ b/drivers/usb/host/ohci-ppc-of.c @@ -14,8 +14,6 @@ */ #include <linux/signal.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> #include <linux/of_platform.h> #include <asm/prom.h> diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 9b7435f..93371a2 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -19,27 +19,15 @@ * This file is licenced under the GPL. */ -#include <linux/clk.h> #include <linux/device.h> -#include <linux/dma-mapping.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/module.h> +#include <linux/signal.h> +#include <linux/platform_device.h> +#include <linux/clk.h> #include <linux/of_platform.h> #include <linux/of_gpio.h> +#include <mach/hardware.h> #include <linux/platform_data/usb-ohci-pxa27x.h> #include <linux/platform_data/usb-pxa3xx-ulpi.h> -#include <linux/platform_device.h> -#include <linux/signal.h> -#include <linux/usb.h> -#include <linux/usb/hcd.h> -#include <linux/usb/otg.h> - -#include <mach/hardware.h> - -#include "ohci.h" - -#define DRIVER_DESC "OHCI PXA27x/PXA3x driver" /* * UHC: USB Host Controller (OHCI-like) register definitions @@ -113,16 +101,16 @@ #define PXA_UHC_MAX_PORTNUM 3 -static const char hcd_name[] = "ohci-pxa27x"; - -static struct hc_driver __read_mostly ohci_pxa27x_hc_driver; - struct pxa27x_ohci { + /* must be 1st member here for hcd_to_ohci() to work */ + struct ohci_hcd ohci; + + struct device *dev; struct clk *clk; void __iomem *mmio_base; }; -#define to_pxa27x_ohci(hcd) (struct pxa27x_ohci *)(hcd_to_ohci(hcd)->priv) +#define to_pxa27x_ohci(hcd) (struct pxa27x_ohci *)hcd_to_ohci(hcd) /* PMM_NPS_MODE -- PMM Non-power switching mode @@ -134,10 +122,10 @@ struct pxa27x_ohci { PMM_PERPORT_MODE -- PMM per port switching mode Ports are powered individually. */ -static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *pxa_ohci, int mode) +static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *ohci, int mode) { - uint32_t uhcrhda = __raw_readl(pxa_ohci->mmio_base + UHCRHDA); - uint32_t uhcrhdb = __raw_readl(pxa_ohci->mmio_base + UHCRHDB); + uint32_t uhcrhda = __raw_readl(ohci->mmio_base + UHCRHDA); + uint32_t uhcrhdb = __raw_readl(ohci->mmio_base + UHCRHDB); switch (mode) { case PMM_NPS_MODE: @@ -161,18 +149,20 @@ static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *pxa_ohci, int mode) uhcrhda |= RH_A_NPS; } - __raw_writel(uhcrhda, pxa_ohci->mmio_base + UHCRHDA); - __raw_writel(uhcrhdb, pxa_ohci->mmio_base + UHCRHDB); + __raw_writel(uhcrhda, ohci->mmio_base + UHCRHDA); + __raw_writel(uhcrhdb, ohci->mmio_base + UHCRHDB); return 0; } +extern int usb_disabled(void); + /*-------------------------------------------------------------------------*/ -static inline void pxa27x_setup_hc(struct pxa27x_ohci *pxa_ohci, +static inline void pxa27x_setup_hc(struct pxa27x_ohci *ohci, struct pxaohci_platform_data *inf) { - uint32_t uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR); - uint32_t uhcrhda = __raw_readl(pxa_ohci->mmio_base + UHCRHDA); + uint32_t uhchr = __raw_readl(ohci->mmio_base + UHCHR); + uint32_t uhcrhda = __raw_readl(ohci->mmio_base + UHCRHDA); if (inf->flags & ENABLE_PORT1) uhchr &= ~UHCHR_SSEP1; @@ -204,17 +194,17 @@ static inline void pxa27x_setup_hc(struct pxa27x_ohci *pxa_ohci, uhcrhda |= UHCRHDA_POTPGT(inf->power_on_delay / 2); } - __raw_writel(uhchr, pxa_ohci->mmio_base + UHCHR); - __raw_writel(uhcrhda, pxa_ohci->mmio_base + UHCRHDA); + __raw_writel(uhchr, ohci->mmio_base + UHCHR); + __raw_writel(uhcrhda, ohci->mmio_base + UHCRHDA); } -static inline void pxa27x_reset_hc(struct pxa27x_ohci *pxa_ohci) +static inline void pxa27x_reset_hc(struct pxa27x_ohci *ohci) { - uint32_t uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR); + uint32_t uhchr = __raw_readl(ohci->mmio_base + UHCHR); - __raw_writel(uhchr | UHCHR_FHR, pxa_ohci->mmio_base + UHCHR); + __raw_writel(uhchr | UHCHR_FHR, ohci->mmio_base + UHCHR); udelay(11); - __raw_writel(uhchr & ~UHCHR_FHR, pxa_ohci->mmio_base + UHCHR); + __raw_writel(uhchr & ~UHCHR_FHR, ohci->mmio_base + UHCHR); } #ifdef CONFIG_PXA27x @@ -223,26 +213,25 @@ extern void pxa27x_clear_otgph(void); #define pxa27x_clear_otgph() do {} while (0) #endif -static int pxa27x_start_hc(struct pxa27x_ohci *pxa_ohci, struct device *dev) +static int pxa27x_start_hc(struct pxa27x_ohci *ohci, struct device *dev) { int retval = 0; struct pxaohci_platform_data *inf; uint32_t uhchr; - struct usb_hcd *hcd = dev_get_drvdata(dev); inf = dev_get_platdata(dev); - clk_prepare_enable(pxa_ohci->clk); + clk_prepare_enable(ohci->clk); - pxa27x_reset_hc(pxa_ohci); + pxa27x_reset_hc(ohci); - uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR) | UHCHR_FSBIR; - __raw_writel(uhchr, pxa_ohci->mmio_base + UHCHR); + uhchr = __raw_readl(ohci->mmio_base + UHCHR) | UHCHR_FSBIR; + __raw_writel(uhchr, ohci->mmio_base + UHCHR); - while (__raw_readl(pxa_ohci->mmio_base + UHCHR) & UHCHR_FSBIR) + while (__raw_readl(ohci->mmio_base + UHCHR) & UHCHR_FSBIR) cpu_relax(); - pxa27x_setup_hc(pxa_ohci, inf); + pxa27x_setup_hc(ohci, inf); if (inf->init) retval = inf->init(dev); @@ -251,39 +240,38 @@ static int pxa27x_start_hc(struct pxa27x_ohci *pxa_ohci, struct device *dev) return retval; if (cpu_is_pxa3xx()) - pxa3xx_u2d_start_hc(&hcd->self); + pxa3xx_u2d_start_hc(&ohci_to_hcd(&ohci->ohci)->self); - uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR) & ~UHCHR_SSE; - __raw_writel(uhchr, pxa_ohci->mmio_base + UHCHR); - __raw_writel(UHCHIE_UPRIE | UHCHIE_RWIE, pxa_ohci->mmio_base + UHCHIE); + uhchr = __raw_readl(ohci->mmio_base + UHCHR) & ~UHCHR_SSE; + __raw_writel(uhchr, ohci->mmio_base + UHCHR); + __raw_writel(UHCHIE_UPRIE | UHCHIE_RWIE, ohci->mmio_base + UHCHIE); /* Clear any OTG Pin Hold */ pxa27x_clear_otgph(); return 0; } -static void pxa27x_stop_hc(struct pxa27x_ohci *pxa_ohci, struct device *dev) +static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, struct device *dev) { struct pxaohci_platform_data *inf; - struct usb_hcd *hcd = dev_get_drvdata(dev); uint32_t uhccoms; inf = dev_get_platdata(dev); if (cpu_is_pxa3xx()) - pxa3xx_u2d_stop_hc(&hcd->self); + pxa3xx_u2d_stop_hc(&ohci_to_hcd(&ohci->ohci)->self); if (inf->exit) inf->exit(dev); - pxa27x_reset_hc(pxa_ohci); + pxa27x_reset_hc(ohci); /* Host Controller Reset */ - uhccoms = __raw_readl(pxa_ohci->mmio_base + UHCCOMS) | 0x01; - __raw_writel(uhccoms, pxa_ohci->mmio_base + UHCCOMS); + uhccoms = __raw_readl(ohci->mmio_base + UHCCOMS) | 0x01; + __raw_writel(uhccoms, ohci->mmio_base + UHCCOMS); udelay(10); - clk_disable_unprepare(pxa_ohci->clk); + clk_disable_unprepare(ohci->clk); } #ifdef CONFIG_OF @@ -299,7 +287,6 @@ static int ohci_pxa_of_init(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct pxaohci_platform_data *pdata; u32 tmp; - int ret; if (!np) return 0; @@ -308,9 +295,10 @@ static int ohci_pxa_of_init(struct platform_device *pdev) * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away. */ - ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -368,8 +356,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device int retval, irq; struct usb_hcd *hcd; struct pxaohci_platform_data *inf; - struct pxa27x_ohci *pxa_ohci; - struct ohci_hcd *ohci; + struct pxa27x_ohci *ohci; struct resource *r; struct clk *usb_clk; @@ -422,31 +409,29 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device } /* initialize "struct pxa27x_ohci" */ - pxa_ohci = to_pxa27x_ohci(hcd); - pxa_ohci->clk = usb_clk; - pxa_ohci->mmio_base = (void __iomem *)hcd->regs; + ohci = (struct pxa27x_ohci *)hcd_to_ohci(hcd); + ohci->dev = &pdev->dev; + ohci->clk = usb_clk; + ohci->mmio_base = (void __iomem *)hcd->regs; - retval = pxa27x_start_hc(pxa_ohci, &pdev->dev); - if (retval < 0) { + if ((retval = pxa27x_start_hc(ohci, &pdev->dev)) < 0) { pr_debug("pxa27x_start_hc failed"); goto err3; } /* Select Power Management Mode */ - pxa27x_ohci_select_pmm(pxa_ohci, inf->port_mode); + pxa27x_ohci_select_pmm(ohci, inf->port_mode); if (inf->power_budget) hcd->power_budget = inf->power_budget; - /* The value of NDP in roothub_a is incorrect on this hardware */ - ohci = hcd_to_ohci(hcd); - ohci->num_ports = 3; + ohci_hcd_init(hcd_to_ohci(hcd)); retval = usb_add_hcd(hcd, irq, 0); if (retval == 0) return retval; - pxa27x_stop_hc(pxa_ohci, &pdev->dev); + pxa27x_stop_hc(ohci, &pdev->dev); err3: iounmap(hcd->regs); err2: @@ -474,18 +459,88 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device */ void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev) { - struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd); + struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd); usb_remove_hcd(hcd); - pxa27x_stop_hc(pxa_ohci, &pdev->dev); + pxa27x_stop_hc(ohci, &pdev->dev); iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - clk_put(pxa_ohci->clk); usb_put_hcd(hcd); + clk_put(ohci->clk); } /*-------------------------------------------------------------------------*/ +static int +ohci_pxa27x_start (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret; + + ohci_dbg (ohci, "ohci_pxa27x_start, ohci:%p", ohci); + + /* The value of NDP in roothub_a is incorrect on this hardware */ + ohci->num_ports = 3; + + if ((ret = ohci_init(ohci)) < 0) + return ret; + + if ((ret = ohci_run (ohci)) < 0) { + dev_err(hcd->self.controller, "can't start %s", + hcd->self.bus_name); + ohci_stop (hcd); + return ret; + } + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static const struct hc_driver ohci_pxa27x_hc_driver = { + .description = hcd_name, + .product_desc = "PXA27x OHCI", + .hcd_priv_size = sizeof(struct pxa27x_ohci), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .start = ohci_pxa27x_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + +/*-------------------------------------------------------------------------*/ + static int ohci_hcd_pxa27x_drv_probe(struct platform_device *pdev) { pr_debug ("In ohci_hcd_pxa27x_drv_probe"); @@ -508,42 +563,32 @@ static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev) static int ohci_hcd_pxa27x_drv_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); - struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - bool do_wakeup = device_may_wakeup(dev); - int ret; - + struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd); - if (time_before(jiffies, ohci->next_statechange)) + if (time_before(jiffies, ohci->ohci.next_statechange)) msleep(5); - ohci->next_statechange = jiffies; + ohci->ohci.next_statechange = jiffies; - ret = ohci_suspend(hcd, do_wakeup); - if (ret) - return ret; - - pxa27x_stop_hc(pxa_ohci, dev); - return ret; + pxa27x_stop_hc(ohci, dev); + return 0; } static int ohci_hcd_pxa27x_drv_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); - struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd); + struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd); struct pxaohci_platform_data *inf = dev_get_platdata(dev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); int status; - if (time_before(jiffies, ohci->next_statechange)) + if (time_before(jiffies, ohci->ohci.next_statechange)) msleep(5); - ohci->next_statechange = jiffies; + ohci->ohci.next_statechange = jiffies; - status = pxa27x_start_hc(pxa_ohci, dev); - if (status < 0) + if ((status = pxa27x_start_hc(ohci, dev)) < 0) return status; /* Select Power Management Mode */ - pxa27x_ohci_select_pmm(pxa_ohci, inf->port_mode); + pxa27x_ohci_select_pmm(ohci, inf->port_mode); ohci_resume(hcd, false); return 0; @@ -555,6 +600,9 @@ static const struct dev_pm_ops ohci_hcd_pxa27x_pm_ops = { }; #endif +/* work with hotplug and coldplug */ +MODULE_ALIAS("platform:pxa27x-ohci"); + static struct platform_driver ohci_hcd_pxa27x_driver = { .probe = ohci_hcd_pxa27x_drv_probe, .remove = ohci_hcd_pxa27x_drv_remove, @@ -569,27 +617,3 @@ static struct platform_driver ohci_hcd_pxa27x_driver = { }, }; -static const struct ohci_driver_overrides pxa27x_overrides __initconst = { - .extra_priv_size = sizeof(struct pxa27x_ohci), -}; - -static int __init ohci_pxa27x_init(void) -{ - if (usb_disabled()) - return -ENODEV; - - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ohci_init_driver(&ohci_pxa27x_hc_driver, &pxa27x_overrides); - return platform_driver_register(&ohci_hcd_pxa27x_driver); -} -module_init(ohci_pxa27x_init); - -static void __exit ohci_pxa27x_cleanup(void) -{ - platform_driver_unregister(&ohci_hcd_pxa27x_driver); -} -module_exit(ohci_pxa27x_cleanup); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pxa27x-ohci"); diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index f90101b..4919afa 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -19,36 +19,19 @@ * This file is licenced under the GPL. */ -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/module.h> #include <linux/platform_device.h> +#include <linux/clk.h> #include <linux/platform_data/usb-ohci-s3c2410.h> -#include <linux/usb.h> -#include <linux/usb/hcd.h> - -#include "ohci.h" - #define valid_port(idx) ((idx) == 1 || (idx) == 2) /* clock device associated with the hcd */ - -#define DRIVER_DESC "OHCI S3C2410 driver" - -static const char hcd_name[] = "ohci-s3c2410"; - static struct clk *clk; static struct clk *usb_clk; /* forward definitions */ -static int (*orig_ohci_hub_control)(struct usb_hcd *hcd, u16 typeReq, - u16 wValue, u16 wIndex, char *buf, u16 wLength); -static int (*orig_ohci_hub_status_data)(struct usb_hcd *hcd, char *buf); - static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc); /* conversion functions */ @@ -64,10 +47,10 @@ static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd) dev_dbg(&dev->dev, "s3c2410_start_hc:\n"); - clk_prepare_enable(usb_clk); + clk_enable(usb_clk); mdelay(2); /* let the bus clock stabilise */ - clk_prepare_enable(clk); + clk_enable(clk); if (info != NULL) { info->hcd = hcd; @@ -92,8 +75,8 @@ static void s3c2410_stop_hc(struct platform_device *dev) (info->enable_oc)(info, 0); } - clk_disable_unprepare(clk); - clk_disable_unprepare(usb_clk); + clk_disable(clk); + clk_disable(usb_clk); } /* ohci_s3c2410_hub_status_data @@ -110,7 +93,7 @@ ohci_s3c2410_hub_status_data(struct usb_hcd *hcd, char *buf) int orig; int portno; - orig = orig_ohci_hub_status_data(hcd, buf); + orig = ohci_hub_status_data(hcd, buf); if (info == NULL) return orig; @@ -181,7 +164,7 @@ static int ohci_s3c2410_hub_control( * process the request straight away and exit */ if (info == NULL) { - ret = orig_ohci_hub_control(hcd, typeReq, wValue, + ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); goto out; } @@ -231,7 +214,7 @@ static int ohci_s3c2410_hub_control( break; } - ret = orig_ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); + ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); if (ret) goto out; @@ -391,6 +374,8 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver, s3c2410_start_hc(dev, hcd); + ohci_hcd_init(hcd_to_ohci(hcd)); + retval = usb_add_hcd(hcd, dev->resource[1].start, 0); if (retval != 0) goto err_ioremap; @@ -407,7 +392,71 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver, /*-------------------------------------------------------------------------*/ -static struct hc_driver __read_mostly ohci_s3c2410_hc_driver; +static int +ohci_s3c2410_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + ret = ohci_init(ohci); + if (ret < 0) + return ret; + + ret = ohci_run(ohci); + if (ret < 0) { + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); + ohci_stop(hcd); + return ret; + } + + return 0; +} + + +static const struct hc_driver ohci_s3c2410_hc_driver = { + .description = hcd_name, + .product_desc = "S3C24XX OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .start = ohci_s3c2410_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_s3c2410_hub_status_data, + .hub_control = ohci_s3c2410_hub_control, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + +/* device driver */ static int ohci_hcd_s3c2410_drv_probe(struct platform_device *pdev) { @@ -484,39 +533,4 @@ static struct platform_driver ohci_hcd_s3c2410_driver = { }, }; -static int __init ohci_s3c2410_init(void) -{ - if (usb_disabled()) - return -ENODEV; - - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ohci_init_driver(&ohci_s3c2410_hc_driver, NULL); - - /* - * The Samsung HW has some unusual quirks, which require - * Sumsung-specific workarounds. We override certain hc_driver - * functions here to achieve that. We explicitly do not enhance - * ohci_driver_overrides to allow this more easily, since this - * is an unusual case, and we don't want to encourage others to - * override these functions by making it too easy. - */ - - orig_ohci_hub_control = ohci_s3c2410_hc_driver.hub_control; - orig_ohci_hub_status_data = ohci_s3c2410_hc_driver.hub_status_data; - - ohci_s3c2410_hc_driver.hub_status_data = ohci_s3c2410_hub_status_data; - ohci_s3c2410_hc_driver.hub_control = ohci_s3c2410_hub_control; - - return platform_driver_register(&ohci_hcd_s3c2410_driver); -} -module_init(ohci_s3c2410_init); - -static void __exit ohci_s3c2410_cleanup(void) -{ - platform_driver_unregister(&ohci_hcd_s3c2410_driver); -} -module_exit(ohci_s3c2410_cleanup); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:s3c2410-ohci"); diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index aa9e127..17b2a7d 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -185,12 +185,6 @@ static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev) if (usb_disabled()) return -ENODEV; - /* - * We don't call dma_set_mask_and_coherent() here because the - * DMA mask has already been appropraitely setup by the core - * SA-1111 bus code (which includes bug workarounds.) - */ - hcd = usb_create_hcd(&ohci_sa1111_hc_driver, &dev->dev, "sa1111"); if (!hcd) return -ENOMEM; diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c index 2a5de5f..d479d5d 100644 --- a/drivers/usb/host/ohci-sm501.c +++ b/drivers/usb/host/ohci-sm501.c @@ -216,21 +216,14 @@ static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev) static int ohci_sm501_suspend(struct platform_device *pdev, pm_message_t msg) { struct device *dev = &pdev->dev; - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - bool do_wakeup = device_may_wakeup(dev); - int ret; + struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(pdev)); if (time_before(jiffies, ohci->next_statechange)) msleep(5); ohci->next_statechange = jiffies; - ret = ohci_suspend(hcd, do_wakeup); - if (ret) - return ret; - sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 0); - return ret; + return 0; } static int ohci_sm501_resume(struct platform_device *pdev) diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c index 6b02107..cc9dd9e 100644 --- a/drivers/usb/host/ohci-spear.c +++ b/drivers/usb/host/ohci-spear.c @@ -11,37 +11,92 @@ * warranty of any kind, whether express or implied. */ +#include <linux/signal.h> +#include <linux/platform_device.h> #include <linux/clk.h> -#include <linux/dma-mapping.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/module.h> #include <linux/of.h> -#include <linux/platform_device.h> -#include <linux/signal.h> -#include <linux/usb.h> -#include <linux/usb/hcd.h> - -#include "ohci.h" -#define DRIVER_DESC "OHCI SPEAr driver" - -static const char hcd_name[] = "SPEAr-ohci"; struct spear_ohci { + struct ohci_hcd ohci; struct clk *clk; }; -#define to_spear_ohci(hcd) (struct spear_ohci *)(hcd_to_ohci(hcd)->priv) +#define to_spear_ohci(hcd) (struct spear_ohci *)hcd_to_ohci(hcd) + +static void spear_start_ohci(struct spear_ohci *ohci) +{ + clk_prepare_enable(ohci->clk); +} + +static void spear_stop_ohci(struct spear_ohci *ohci) +{ + clk_disable_unprepare(ohci->clk); +} + +static int ohci_spear_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + ret = ohci_init(ohci); + if (ret < 0) + return ret; + ohci->regs = hcd->regs; + + ret = ohci_run(ohci); + if (ret < 0) { + dev_err(hcd->self.controller, "can't start\n"); + ohci_stop(hcd); + return ret; + } -static struct hc_driver __read_mostly ohci_spear_hc_driver; + create_debug_files(ohci); + +#ifdef DEBUG + ohci_dump(ohci, 1); +#endif + return 0; +} + +static const struct hc_driver ohci_spear_hc_driver = { + .description = hcd_name, + .product_desc = "SPEAr OHCI", + .hcd_priv_size = sizeof(struct spear_ohci), + + /* generic hardware linkage */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + /* basic lifecycle operations */ + .start = ohci_spear_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + + /* managing i/o requests and associated device resources */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* scheduling support */ + .get_frame_number = ohci_get_frame, + + /* root hub support */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + + .start_port_reset = ohci_start_port_reset, +}; static int spear_ohci_hcd_drv_probe(struct platform_device *pdev) { const struct hc_driver *driver = &ohci_spear_hc_driver; - struct ohci_hcd *ohci; struct usb_hcd *hcd = NULL; struct clk *usbh_clk; - struct spear_ohci *sohci_p; + struct spear_ohci *ohci_p; struct resource *res; int retval, irq; @@ -56,9 +111,10 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev) * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away. */ - retval = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (retval) - goto fail; + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); usbh_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(usbh_clk)) { @@ -95,18 +151,16 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev) goto err_put_hcd; } - sohci_p = to_spear_ohci(hcd); - sohci_p->clk = usbh_clk; - - clk_prepare_enable(sohci_p->clk); - - ohci = hcd_to_ohci(hcd); + ohci_p = (struct spear_ohci *)hcd_to_ohci(hcd); + ohci_p->clk = usbh_clk; + spear_start_ohci(ohci_p); + ohci_hcd_init(hcd_to_ohci(hcd)); retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), 0); if (retval == 0) return retval; - clk_disable_unprepare(sohci_p->clk); + spear_stop_ohci(ohci_p); err_put_hcd: usb_put_hcd(hcd); fail: @@ -118,11 +172,11 @@ fail: static int spear_ohci_hcd_drv_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct spear_ohci *sohci_p = to_spear_ohci(hcd); + struct spear_ohci *ohci_p = to_spear_ohci(hcd); usb_remove_hcd(hcd); - if (sohci_p->clk) - clk_disable_unprepare(sohci_p->clk); + if (ohci_p->clk) + spear_stop_ohci(ohci_p); usb_put_hcd(hcd); return 0; @@ -134,14 +188,13 @@ static int spear_ohci_hcd_drv_suspend(struct platform_device *dev, { struct usb_hcd *hcd = platform_get_drvdata(dev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct spear_ohci *sohci_p = to_spear_ohci(hcd); + struct spear_ohci *ohci_p = to_spear_ohci(hcd); if (time_before(jiffies, ohci->next_statechange)) msleep(5); ohci->next_statechange = jiffies; - clk_disable_unprepare(sohci_p->clk); - + spear_stop_ohci(ohci_p); return 0; } @@ -149,13 +202,13 @@ static int spear_ohci_hcd_drv_resume(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct spear_ohci *sohci_p = to_spear_ohci(hcd); + struct spear_ohci *ohci_p = to_spear_ohci(hcd); if (time_before(jiffies, ohci->next_statechange)) msleep(5); ohci->next_statechange = jiffies; - clk_prepare_enable(sohci_p->clk); + spear_start_ohci(ohci_p); ohci_resume(hcd, false); return 0; } @@ -181,28 +234,4 @@ static struct platform_driver spear_ohci_hcd_driver = { }, }; -static const struct ohci_driver_overrides spear_overrides __initconst = { - .extra_priv_size = sizeof(struct spear_ohci), -}; -static int __init ohci_spear_init(void) -{ - if (usb_disabled()) - return -ENODEV; - - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - - ohci_init_driver(&ohci_spear_hc_driver, &spear_overrides); - return platform_driver_register(&spear_ohci_hcd_driver); -} -module_init(ohci_spear_init); - -static void __exit ohci_spear_cleanup(void) -{ - platform_driver_unregister(&spear_ohci_hcd_driver); -} -module_exit(ohci_spear_cleanup); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Deepak Sikri"); -MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:spear-ohci"); diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index dfbdd3a..08ef282 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -79,30 +79,11 @@ #define USB_INTEL_USB3_PSSEN 0xD8 #define USB_INTEL_USB3PRM 0xDC -/* - * amd_chipset_gen values represent AMD different chipset generations - */ -enum amd_chipset_gen { - NOT_AMD_CHIPSET = 0, - AMD_CHIPSET_SB600, - AMD_CHIPSET_SB700, - AMD_CHIPSET_SB800, - AMD_CHIPSET_HUDSON2, - AMD_CHIPSET_BOLTON, - AMD_CHIPSET_YANGTZE, - AMD_CHIPSET_UNKNOWN, -}; - -struct amd_chipset_type { - enum amd_chipset_gen gen; - u8 rev; -}; - static struct amd_chipset_info { struct pci_dev *nb_dev; struct pci_dev *smbus_dev; int nb_type; - struct amd_chipset_type sb_type; + int sb_type; int isoc_reqs; int probe_count; int probe_result; @@ -110,51 +91,6 @@ static struct amd_chipset_info { static DEFINE_SPINLOCK(amd_lock); -/* - * amd_chipset_sb_type_init - initialize amd chipset southbridge type - * - * AMD FCH/SB generation and revision is identified by SMBus controller - * vendor, device and revision IDs. - * - * Returns: 1 if it is an AMD chipset, 0 otherwise. - */ -static int amd_chipset_sb_type_init(struct amd_chipset_info *pinfo) -{ - u8 rev = 0; - pinfo->sb_type.gen = AMD_CHIPSET_UNKNOWN; - - pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, - PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL); - if (pinfo->smbus_dev) { - rev = pinfo->smbus_dev->revision; - if (rev >= 0x10 && rev <= 0x1f) - pinfo->sb_type.gen = AMD_CHIPSET_SB600; - else if (rev >= 0x30 && rev <= 0x3f) - pinfo->sb_type.gen = AMD_CHIPSET_SB700; - else if (rev >= 0x40 && rev <= 0x4f) - pinfo->sb_type.gen = AMD_CHIPSET_SB800; - } else { - pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, - PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL); - - if (!pinfo->smbus_dev) { - pinfo->sb_type.gen = NOT_AMD_CHIPSET; - return 0; - } - - rev = pinfo->smbus_dev->revision; - if (rev >= 0x11 && rev <= 0x14) - pinfo->sb_type.gen = AMD_CHIPSET_HUDSON2; - else if (rev >= 0x15 && rev <= 0x18) - pinfo->sb_type.gen = AMD_CHIPSET_BOLTON; - else if (rev >= 0x39 && rev <= 0x3a) - pinfo->sb_type.gen = AMD_CHIPSET_YANGTZE; - } - - pinfo->sb_type.rev = rev; - return 1; -} - void sb800_prefetch(struct device *dev, int on) { u16 misc; @@ -170,6 +106,7 @@ EXPORT_SYMBOL_GPL(sb800_prefetch); int usb_amd_find_chipset_info(void) { + u8 rev = 0; unsigned long flags; struct amd_chipset_info info; int ret; @@ -185,17 +122,27 @@ int usb_amd_find_chipset_info(void) memset(&info, 0, sizeof(info)); spin_unlock_irqrestore(&amd_lock, flags); - if (!amd_chipset_sb_type_init(&info)) { - ret = 0; - goto commit; + info.smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL); + if (info.smbus_dev) { + rev = info.smbus_dev->revision; + if (rev >= 0x40) + info.sb_type = 1; + else if (rev >= 0x30 && rev <= 0x3b) + info.sb_type = 3; + } else { + info.smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, + 0x780b, NULL); + if (!info.smbus_dev) { + ret = 0; + goto commit; + } + + rev = info.smbus_dev->revision; + if (rev >= 0x11 && rev <= 0x18) + info.sb_type = 2; } - /* Below chipset generations needn't enable AMD PLL quirk */ - if (info.sb_type.gen == AMD_CHIPSET_UNKNOWN || - info.sb_type.gen == AMD_CHIPSET_SB600 || - info.sb_type.gen == AMD_CHIPSET_YANGTZE || - (info.sb_type.gen == AMD_CHIPSET_SB700 && - info.sb_type.rev > 0x3b)) { + if (info.sb_type == 0) { if (info.smbus_dev) { pci_dev_put(info.smbus_dev); info.smbus_dev = NULL; @@ -250,39 +197,6 @@ commit: } EXPORT_SYMBOL_GPL(usb_amd_find_chipset_info); -int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev) -{ - /* Make sure amd chipset type has already been initialized */ - usb_amd_find_chipset_info(); - if (amd_chipset.sb_type.gen != AMD_CHIPSET_YANGTZE) - return 0; - - dev_dbg(&pdev->dev, "QUIRK: Enable AMD remote wakeup fix\n"); - return 1; -} -EXPORT_SYMBOL_GPL(usb_hcd_amd_remote_wakeup_quirk); - -bool usb_amd_hang_symptom_quirk(void) -{ - u8 rev; - - usb_amd_find_chipset_info(); - rev = amd_chipset.sb_type.rev; - /* SB600 and old version of SB700 have hang symptom bug */ - return amd_chipset.sb_type.gen == AMD_CHIPSET_SB600 || - (amd_chipset.sb_type.gen == AMD_CHIPSET_SB700 && - rev >= 0x3a && rev <= 0x3b); -} -EXPORT_SYMBOL_GPL(usb_amd_hang_symptom_quirk); - -bool usb_amd_prefetch_quirk(void) -{ - usb_amd_find_chipset_info(); - /* SB800 needs pre-fetch fix */ - return amd_chipset.sb_type.gen == AMD_CHIPSET_SB800; -} -EXPORT_SYMBOL_GPL(usb_amd_prefetch_quirk); - /* * The hardware normally enables the A-link power management feature, which * lets the system lower the power consumption in idle states. @@ -315,9 +229,7 @@ static void usb_amd_quirk_pll(int disable) } } - if (amd_chipset.sb_type.gen == AMD_CHIPSET_SB800 || - amd_chipset.sb_type.gen == AMD_CHIPSET_HUDSON2 || - amd_chipset.sb_type.gen == AMD_CHIPSET_BOLTON) { + if (amd_chipset.sb_type == 1 || amd_chipset.sb_type == 2) { outb_p(AB_REG_BAR_LOW, 0xcd6); addr_low = inb_p(0xcd7); outb_p(AB_REG_BAR_HIGH, 0xcd6); @@ -328,8 +240,7 @@ static void usb_amd_quirk_pll(int disable) outl_p(0x40, AB_DATA(addr)); outl_p(0x34, AB_INDX(addr)); val = inl_p(AB_DATA(addr)); - } else if (amd_chipset.sb_type.gen == AMD_CHIPSET_SB700 && - amd_chipset.sb_type.rev <= 0x3b) { + } else if (amd_chipset.sb_type == 3) { pci_read_config_dword(amd_chipset.smbus_dev, AB_REG_BAR_SB700, &addr); outl(AX_INDXC, AB_INDX(addr)); @@ -442,7 +353,7 @@ void usb_amd_dev_put(void) amd_chipset.nb_dev = NULL; amd_chipset.smbus_dev = NULL; amd_chipset.nb_type = 0; - memset(&amd_chipset.sb_type, 0, sizeof(amd_chipset.sb_type)); + amd_chipset.sb_type = 0; amd_chipset.isoc_reqs = 0; amd_chipset.probe_result = 0; diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h index 638e88f..ed6700d 100644 --- a/drivers/usb/host/pci-quirks.h +++ b/drivers/usb/host/pci-quirks.h @@ -5,8 +5,6 @@ void uhci_reset_hc(struct pci_dev *pdev, unsigned long base); int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base); int usb_amd_find_chipset_info(void); -bool usb_amd_hang_symptom_quirk(void); -bool usb_amd_prefetch_quirk(void); void usb_amd_dev_put(void); void usb_amd_quirk_pll_disable(void); void usb_amd_quirk_pll_enable(void); diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 79620c3..5477bf5 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1413,7 +1413,7 @@ static int sl811h_show(struct seq_file *s, void *unused) case SL11H_CTL1MASK_SE0: s = " se0/reset"; break; case SL11H_CTL1MASK_K: s = " k/resume"; break; default: s = "j"; break; - } s; }), + }; s; }), (t & SL11H_CTL1MASK_LSPD) ? " lowspeed" : "", (t & SL11H_CTL1MASK_SUSPEND) ? " suspend" : ""); @@ -1446,7 +1446,7 @@ static int sl811h_show(struct seq_file *s, void *unused) case USB_PID_SETUP: s = "setup"; break; case USB_PID_ACK: s = "status"; break; default: s = "?"; break; - } s;}), + }; s;}), ep->maxpacket, ep->nak_count, ep->error_count); list_for_each_entry (urb, &ep->hep->urb_list, urb_list) { diff --git a/drivers/usb/host/ssb-hcd.c b/drivers/usb/host/ssb-hcd.c index 0196f76..74af2c6 100644 --- a/drivers/usb/host/ssb-hcd.c +++ b/drivers/usb/host/ssb-hcd.c @@ -163,7 +163,8 @@ static int ssb_hcd_probe(struct ssb_device *dev, /* TODO: Probably need checks here; is the core connected? */ - if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32))) + if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) || + dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32))) return -EOPNOTSUPP; usb_dev = kzalloc(sizeof(struct ssb_hcd_device), GFP_KERNEL); diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 8e239cd..4557375 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -310,14 +310,14 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len) unsigned short portsc1, portsc2; - usbcmd = uhci_readw(uhci, USBCMD); - usbstat = uhci_readw(uhci, USBSTS); - usbint = uhci_readw(uhci, USBINTR); - usbfrnum = uhci_readw(uhci, USBFRNUM); - flbaseadd = uhci_readl(uhci, USBFLBASEADD); - sof = uhci_readb(uhci, USBSOF); - portsc1 = uhci_readw(uhci, USBPORTSC1); - portsc2 = uhci_readw(uhci, USBPORTSC2); + usbcmd = uhci_readw(uhci, 0); + usbstat = uhci_readw(uhci, 2); + usbint = uhci_readw(uhci, 4); + usbfrnum = uhci_readw(uhci, 6); + flbaseadd = uhci_readl(uhci, 8); + sof = uhci_readb(uhci, 12); + portsc1 = uhci_readw(uhci, 16); + portsc2 = uhci_readw(uhci, 18); out += sprintf(out, " usbcmd = %04x %s%s%s%s%s%s%s%s\n", usbcmd, diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index 93e17b1..9189bc9 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -75,6 +75,8 @@ static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf) return !!*buf; } +#define OK(x) len = (x); break + #define CLR_RH_PORTSTAT(x) \ status = uhci_readw(uhci, port_addr); \ status &= ~(RWC_BITS|WZ_BITS); \ @@ -242,7 +244,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - int status, lstatus, retval = 0; + int status, lstatus, retval = 0, len = 0; unsigned int port = wIndex - 1; unsigned long port_addr = USBPORTSC1 + 2 * port; u16 wPortChange, wPortStatus; @@ -256,8 +258,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case GetHubStatus: *(__le32 *)buf = cpu_to_le32(0); - retval = 4; /* hub power */ - break; + OK(4); /* hub power */ case GetPortStatus: if (port >= uhci->rh_numports) goto err; @@ -310,14 +311,13 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, *(__le16 *)buf = cpu_to_le16(wPortStatus); *(__le16 *)(buf + 2) = cpu_to_le16(wPortChange); - retval = 4; - break; + OK(4); case SetHubFeature: /* We don't implement these */ case ClearHubFeature: switch (wValue) { case C_HUB_OVER_CURRENT: case C_HUB_LOCAL_POWER: - break; + OK(0); default: goto err; } @@ -329,7 +329,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, switch (wValue) { case USB_PORT_FEAT_SUSPEND: SET_RH_PORTSTAT(USBPORTSC_SUSP); - break; + OK(0); case USB_PORT_FEAT_RESET: SET_RH_PORTSTAT(USBPORTSC_PR); @@ -338,10 +338,10 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /* USB v2.0 7.1.7.5 */ uhci->ports_timeout = jiffies + msecs_to_jiffies(50); - break; + OK(0); case USB_PORT_FEAT_POWER: /* UHCI has no power switching */ - break; + OK(0); default: goto err; } @@ -356,10 +356,10 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /* Disable terminates Resume signalling */ uhci_finish_suspend(uhci, port, port_addr); - break; + OK(0); case USB_PORT_FEAT_C_ENABLE: CLR_RH_PORTSTAT(USBPORTSC_PEC); - break; + OK(0); case USB_PORT_FEAT_SUSPEND: if (!(uhci_readw(uhci, port_addr) & USBPORTSC_SUSP)) { @@ -382,32 +382,32 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, uhci->ports_timeout = jiffies + msecs_to_jiffies(20); } - break; + OK(0); case USB_PORT_FEAT_C_SUSPEND: clear_bit(port, &uhci->port_c_suspend); - break; + OK(0); case USB_PORT_FEAT_POWER: /* UHCI has no power switching */ goto err; case USB_PORT_FEAT_C_CONNECTION: CLR_RH_PORTSTAT(USBPORTSC_CSC); - break; + OK(0); case USB_PORT_FEAT_C_OVER_CURRENT: CLR_RH_PORTSTAT(USBPORTSC_OCC); - break; + OK(0); case USB_PORT_FEAT_C_RESET: /* this driver won't report these */ - break; + OK(0); default: goto err; } break; case GetHubDescriptor: - retval = min_t(unsigned int, sizeof(root_hub_hub_des), wLength); - memcpy(buf, root_hub_hub_des, retval); - if (retval > 2) + len = min_t(unsigned int, sizeof(root_hub_hub_des), wLength); + memcpy(buf, root_hub_hub_des, len); + if (len > 2) buf[2] = uhci->rh_numports; - break; + OK(len); default: err: retval = -EPIPE; diff --git a/drivers/usb/host/uhci-pci.c b/drivers/usb/host/uhci-pci.c index 4cd7988..0f228c4 100644 --- a/drivers/usb/host/uhci-pci.c +++ b/drivers/usb/host/uhci-pci.c @@ -162,8 +162,6 @@ static void uhci_shutdown(struct pci_dev *pdev) #ifdef CONFIG_PM -static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated); - static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); @@ -176,6 +174,12 @@ static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) if (!HCD_HW_ACCESSIBLE(hcd) || uhci->dead) goto done_okay; /* Already suspended or dead */ + if (uhci->rh_state > UHCI_RH_SUSPENDED) { + dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n"); + rc = -EBUSY; + goto done; + }; + /* All PCI host controllers are required to disable IRQ generation * at the source, so we must turn off PIRQ. */ @@ -191,15 +195,8 @@ static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) done_okay: clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); +done: spin_unlock_irq(&uhci->lock); - - synchronize_irq(hcd->irq); - - /* Check for race with a wakeup request */ - if (do_wakeup && HCD_WAKEUP_PENDING(hcd)) { - uhci_pci_resume(hcd, false); - rc = -EBUSY; - } return rc; } @@ -302,5 +299,3 @@ static struct pci_driver uhci_pci_driver = { }, #endif }; - -MODULE_SOFTDEP("pre: ehci_pci"); diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c index 3003fef..d033a0e 100644 --- a/drivers/usb/host/uhci-platform.c +++ b/drivers/usb/host/uhci-platform.c @@ -75,9 +75,10 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev) * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away. */ - ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); hcd = usb_create_hcd(&uhci_platform_hc_driver, &pdev->dev, pdev->name); @@ -104,7 +105,8 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev) uhci->regs = hcd->regs; - ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED); + ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED | + IRQF_SHARED); if (ret) goto err_uhci; diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c index 1b0888f..ecc88db 100644 --- a/drivers/usb/host/whci/hcd.c +++ b/drivers/usb/host/whci/hcd.c @@ -134,7 +134,7 @@ static int whc_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb, default: ret = asl_urb_enqueue(whc, urb, mem_flags); break; - } + }; return ret; } @@ -160,7 +160,7 @@ static int whc_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb, int status) default: ret = asl_urb_dequeue(whc, urb, status); break; - } + }; return ret; } diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 805f234..e8b4c56 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -296,7 +296,7 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) /* Wait for last stop endpoint command to finish */ timeleft = wait_for_completion_interruptible_timeout( cmd->completion, - XHCI_CMD_DEFAULT_TIMEOUT); + USB_CTRL_SET_TIMEOUT); if (timeleft <= 0) { xhci_warn(xhci, "%s while waiting for stop endpoint command\n", timeleft == 0 ? "Timeout" : "Signal"); @@ -524,8 +524,7 @@ static void xhci_hub_report_usb3_link_state(u32 *status, u32 status_reg) * the compliance mode timer is deleted. A port won't enter * compliance mode if it has previously entered U0. */ -static void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, - u16 wIndex) +void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex) { u32 all_ports_seen_u0 = ((1 << xhci->num_usb3_ports)-1); bool port_in_u0 = ((status & PORT_PLS_MASK) == XDEV_U0); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 49b8bd0..83bcd13 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1693,7 +1693,9 @@ void xhci_free_command(struct xhci_hcd *xhci, void xhci_mem_cleanup(struct xhci_hcd *xhci) { struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + struct dev_info *dev_info, *next; struct xhci_cd *cur_cd, *next_cd; + unsigned long flags; int size; int i, j, num_ports; @@ -1754,6 +1756,13 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) scratchpad_free(xhci); + spin_lock_irqsave(&xhci->lock, flags); + list_for_each_entry_safe(dev_info, next, &xhci->lpm_failed_devs, list) { + list_del(&dev_info->list); + kfree(dev_info); + } + spin_unlock_irqrestore(&xhci->lock, flags); + if (!xhci->rh_bw) goto no_bw; @@ -2222,6 +2231,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) u32 page_size, temp; int i; + INIT_LIST_HEAD(&xhci->lpm_failed_devs); INIT_LIST_HEAD(&xhci->cancel_cmd_list); page_size = xhci_readl(xhci, &xhci->op_regs->page_size); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 53c2e29..6bfbd80 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -178,7 +178,7 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring) if (ring->type == TYPE_EVENT && last_trb_on_last_seg(xhci, ring, ring->deq_seg, ring->dequeue)) { - ring->cycle_state ^= 1; + ring->cycle_state = (ring->cycle_state ? 0 : 1); } ring->deq_seg = ring->deq_seg->next; ring->dequeue = ring->deq_seg->trbs; @@ -726,7 +726,7 @@ static void xhci_stop_watchdog_timer_in_irq(struct xhci_hcd *xhci, /* Must be called with xhci->lock held in interrupt context */ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci, - struct xhci_td *cur_td, int status) + struct xhci_td *cur_td, int status, char *adjective) { struct usb_hcd *hcd; struct urb *urb; @@ -765,9 +765,10 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci, * 2. Otherwise, we turn all the TRBs in the TD into No-op TRBs (with the chain * bit cleared) so that the HW will skip over them. */ -static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, +static void handle_stopped_endpoint(struct xhci_hcd *xhci, union xhci_trb *trb, struct xhci_event_cmd *event) { + unsigned int slot_id; unsigned int ep_index; struct xhci_virt_device *virt_dev; struct xhci_ring *ep_ring; @@ -778,7 +779,10 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, struct xhci_dequeue_state deq_state; - if (unlikely(TRB_TO_SUSPEND_PORT(le32_to_cpu(trb->generic.field[3])))) { + if (unlikely(TRB_TO_SUSPEND_PORT( + le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])))) { + slot_id = TRB_TO_SLOT_ID( + le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])); virt_dev = xhci->devs[slot_id]; if (virt_dev) handle_cmd_in_cmd_wait_list(xhci, virt_dev, @@ -791,6 +795,7 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, } memset(&deq_state, 0, sizeof(deq_state)); + slot_id = TRB_TO_SLOT_ID(le32_to_cpu(trb->generic.field[3])); ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3])); ep = &xhci->devs[slot_id]->eps[ep_index]; @@ -886,7 +891,7 @@ remove_finished_td: /* Doesn't matter what we pass for status, since the core will * just overwrite it (because the URB has been unlinked). */ - xhci_giveback_urb_in_irq(xhci, cur_td, 0); + xhci_giveback_urb_in_irq(xhci, cur_td, 0, "cancelled"); /* Stop processing the cancelled list if the watchdog timer is * running. @@ -996,7 +1001,7 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) if (!list_empty(&cur_td->cancelled_td_list)) list_del_init(&cur_td->cancelled_td_list); xhci_giveback_urb_in_irq(xhci, cur_td, - -ESHUTDOWN); + -ESHUTDOWN, "killed"); } while (!list_empty(&temp_ep->cancelled_td_list)) { cur_td = list_first_entry( @@ -1005,7 +1010,7 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) cancelled_td_list); list_del_init(&cur_td->cancelled_td_list); xhci_giveback_urb_in_irq(xhci, cur_td, - -ESHUTDOWN); + -ESHUTDOWN, "killed"); } } } @@ -1072,9 +1077,11 @@ static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci, * endpoint doorbell to restart the ring, but only if there aren't more * cancellations pending. */ -static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, - union xhci_trb *trb, u32 cmd_comp_code) +static void handle_set_deq_completion(struct xhci_hcd *xhci, + struct xhci_event_cmd *event, + union xhci_trb *trb) { + unsigned int slot_id; unsigned int ep_index; unsigned int stream_id; struct xhci_ring *ep_ring; @@ -1082,6 +1089,7 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, struct xhci_ep_ctx *ep_ctx; struct xhci_slot_ctx *slot_ctx; + slot_id = TRB_TO_SLOT_ID(le32_to_cpu(trb->generic.field[3])); ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3])); stream_id = TRB_TO_STREAM_ID(le32_to_cpu(trb->generic.field[2])); dev = xhci->devs[slot_id]; @@ -1099,11 +1107,11 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx); - if (cmd_comp_code != COMP_SUCCESS) { + if (GET_COMP_CODE(le32_to_cpu(event->status)) != COMP_SUCCESS) { unsigned int ep_state; unsigned int slot_state; - switch (cmd_comp_code) { + switch (GET_COMP_CODE(le32_to_cpu(event->status))) { case COMP_TRB_ERR: xhci_warn(xhci, "WARN Set TR Deq Ptr cmd invalid because " "of stream ID configuration\n"); @@ -1126,7 +1134,7 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, default: xhci_warn(xhci, "WARN Set TR Deq Ptr cmd with unknown " "completion code of %u.\n", - cmd_comp_code); + GET_COMP_CODE(le32_to_cpu(event->status))); break; } /* OK what do we do now? The endpoint state is hosed, and we @@ -1163,17 +1171,21 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, ring_doorbell_for_active_rings(xhci, slot_id, ep_index); } -static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id, - union xhci_trb *trb, u32 cmd_comp_code) +static void handle_reset_ep_completion(struct xhci_hcd *xhci, + struct xhci_event_cmd *event, + union xhci_trb *trb) { + int slot_id; unsigned int ep_index; + slot_id = TRB_TO_SLOT_ID(le32_to_cpu(trb->generic.field[3])); ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3])); /* This command will only fail if the endpoint wasn't halted, * but we don't care. */ xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep, - "Ignoring reset ep completion code of %u", cmd_comp_code); + "Ignoring reset ep completion code of %u", + GET_COMP_CODE(le32_to_cpu(event->status))); /* HW with the reset endpoint quirk needs to have a configure endpoint * command complete before the endpoint can be used. Queue that here @@ -1374,149 +1386,21 @@ static int handle_stopped_cmd_ring(struct xhci_hcd *xhci, return cur_trb_is_good; } -static void xhci_handle_cmd_enable_slot(struct xhci_hcd *xhci, int slot_id, - u32 cmd_comp_code) -{ - if (cmd_comp_code == COMP_SUCCESS) - xhci->slot_id = slot_id; - else - xhci->slot_id = 0; - complete(&xhci->addr_dev); -} - -static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id) -{ - struct xhci_virt_device *virt_dev; - - virt_dev = xhci->devs[slot_id]; - if (!virt_dev) - return; - if (xhci->quirks & XHCI_EP_LIMIT_QUIRK) - /* Delete default control endpoint resources */ - xhci_free_device_endpoint_resources(xhci, virt_dev, true); - xhci_free_virt_device(xhci, slot_id); -} - -static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id, - struct xhci_event_cmd *event, u32 cmd_comp_code) -{ - struct xhci_virt_device *virt_dev; - struct xhci_input_control_ctx *ctrl_ctx; - unsigned int ep_index; - unsigned int ep_state; - u32 add_flags, drop_flags; - - virt_dev = xhci->devs[slot_id]; - if (handle_cmd_in_cmd_wait_list(xhci, virt_dev, event)) - return; - /* - * Configure endpoint commands can come from the USB core - * configuration or alt setting changes, or because the HW - * needed an extra configure endpoint command after a reset - * endpoint command or streams were being configured. - * If the command was for a halted endpoint, the xHCI driver - * is not waiting on the configure endpoint command. - */ - ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); - if (!ctrl_ctx) { - xhci_warn(xhci, "Could not get input context, bad type.\n"); - return; - } - - add_flags = le32_to_cpu(ctrl_ctx->add_flags); - drop_flags = le32_to_cpu(ctrl_ctx->drop_flags); - /* Input ctx add_flags are the endpoint index plus one */ - ep_index = xhci_last_valid_endpoint(add_flags) - 1; - - /* A usb_set_interface() call directly after clearing a halted - * condition may race on this quirky hardware. Not worth - * worrying about, since this is prototype hardware. Not sure - * if this will work for streams, but streams support was - * untested on this prototype. - */ - if (xhci->quirks & XHCI_RESET_EP_QUIRK && - ep_index != (unsigned int) -1 && - add_flags - SLOT_FLAG == drop_flags) { - ep_state = virt_dev->eps[ep_index].ep_state; - if (!(ep_state & EP_HALTED)) - goto bandwidth_change; - xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, - "Completed config ep cmd - " - "last ep index = %d, state = %d", - ep_index, ep_state); - /* Clear internal halted state and restart ring(s) */ - virt_dev->eps[ep_index].ep_state &= ~EP_HALTED; - ring_doorbell_for_active_rings(xhci, slot_id, ep_index); - return; - } -bandwidth_change: - xhci_dbg_trace(xhci, trace_xhci_dbg_context_change, - "Completed config ep cmd"); - virt_dev->cmd_status = cmd_comp_code; - complete(&virt_dev->cmd_completion); - return; -} - -static void xhci_handle_cmd_eval_ctx(struct xhci_hcd *xhci, int slot_id, - struct xhci_event_cmd *event, u32 cmd_comp_code) -{ - struct xhci_virt_device *virt_dev; - - virt_dev = xhci->devs[slot_id]; - if (handle_cmd_in_cmd_wait_list(xhci, virt_dev, event)) - return; - virt_dev->cmd_status = cmd_comp_code; - complete(&virt_dev->cmd_completion); -} - -static void xhci_handle_cmd_addr_dev(struct xhci_hcd *xhci, int slot_id, - u32 cmd_comp_code) -{ - xhci->devs[slot_id]->cmd_status = cmd_comp_code; - complete(&xhci->addr_dev); -} - -static void xhci_handle_cmd_reset_dev(struct xhci_hcd *xhci, int slot_id, - struct xhci_event_cmd *event) -{ - struct xhci_virt_device *virt_dev; - - xhci_dbg(xhci, "Completed reset device command.\n"); - virt_dev = xhci->devs[slot_id]; - if (virt_dev) - handle_cmd_in_cmd_wait_list(xhci, virt_dev, event); - else - xhci_warn(xhci, "Reset device command completion " - "for disabled slot %u\n", slot_id); -} - -static void xhci_handle_cmd_nec_get_fw(struct xhci_hcd *xhci, - struct xhci_event_cmd *event) -{ - if (!(xhci->quirks & XHCI_NEC_HOST)) { - xhci->error_bitmask |= 1 << 6; - return; - } - xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, - "NEC firmware version %2x.%02x", - NEC_FW_MAJOR(le32_to_cpu(event->status)), - NEC_FW_MINOR(le32_to_cpu(event->status))); -} - static void handle_cmd_completion(struct xhci_hcd *xhci, struct xhci_event_cmd *event) { int slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); u64 cmd_dma; dma_addr_t cmd_dequeue_dma; - u32 cmd_comp_code; - union xhci_trb *cmd_trb; - u32 cmd_type; + struct xhci_input_control_ctx *ctrl_ctx; + struct xhci_virt_device *virt_dev; + unsigned int ep_index; + struct xhci_ring *ep_ring; + unsigned int ep_state; cmd_dma = le64_to_cpu(event->cmd_trb); - cmd_trb = xhci->cmd_ring->dequeue; cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, - cmd_trb); + xhci->cmd_ring->dequeue); /* Is the command ring deq ptr out of sync with the deq seg ptr? */ if (cmd_dequeue_dma == 0) { xhci->error_bitmask |= 1 << 4; @@ -1528,17 +1412,19 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, return; } - trace_xhci_cmd_completion(cmd_trb, (struct xhci_generic_trb *) event); + trace_xhci_cmd_completion(&xhci->cmd_ring->dequeue->generic, + (struct xhci_generic_trb *) event); - cmd_comp_code = GET_COMP_CODE(le32_to_cpu(event->status)); - if (cmd_comp_code == COMP_CMD_ABORT || cmd_comp_code == COMP_CMD_STOP) { + if ((GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_ABORT) || + (GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_STOP)) { /* If the return value is 0, we think the trb pointed by * command ring dequeue pointer is a good trb. The good * trb means we don't want to cancel the trb, but it have * been stopped by host. So we should handle it normally. * Otherwise, driver should invoke inc_deq() and return. */ - if (handle_stopped_cmd_ring(xhci, cmd_comp_code)) { + if (handle_stopped_cmd_ring(xhci, + GET_COMP_CODE(le32_to_cpu(event->status)))) { inc_deq(xhci, xhci->cmd_ring); return; } @@ -1550,47 +1436,117 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, return; } - cmd_type = TRB_FIELD_TO_TYPE(le32_to_cpu(cmd_trb->generic.field[3])); - switch (cmd_type) { - case TRB_ENABLE_SLOT: - xhci_handle_cmd_enable_slot(xhci, slot_id, cmd_comp_code); + switch (le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3]) + & TRB_TYPE_BITMASK) { + case TRB_TYPE(TRB_ENABLE_SLOT): + if (GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_SUCCESS) + xhci->slot_id = slot_id; + else + xhci->slot_id = 0; + complete(&xhci->addr_dev); break; - case TRB_DISABLE_SLOT: - xhci_handle_cmd_disable_slot(xhci, slot_id); + case TRB_TYPE(TRB_DISABLE_SLOT): + if (xhci->devs[slot_id]) { + if (xhci->quirks & XHCI_EP_LIMIT_QUIRK) + /* Delete default control endpoint resources */ + xhci_free_device_endpoint_resources(xhci, + xhci->devs[slot_id], true); + xhci_free_virt_device(xhci, slot_id); + } break; - case TRB_CONFIG_EP: - xhci_handle_cmd_config_ep(xhci, slot_id, event, cmd_comp_code); + case TRB_TYPE(TRB_CONFIG_EP): + virt_dev = xhci->devs[slot_id]; + if (handle_cmd_in_cmd_wait_list(xhci, virt_dev, event)) + break; + /* + * Configure endpoint commands can come from the USB core + * configuration or alt setting changes, or because the HW + * needed an extra configure endpoint command after a reset + * endpoint command or streams were being configured. + * If the command was for a halted endpoint, the xHCI driver + * is not waiting on the configure endpoint command. + */ + ctrl_ctx = xhci_get_input_control_ctx(xhci, + virt_dev->in_ctx); + if (!ctrl_ctx) { + xhci_warn(xhci, "Could not get input context, bad type.\n"); + break; + } + /* Input ctx add_flags are the endpoint index plus one */ + ep_index = xhci_last_valid_endpoint(le32_to_cpu(ctrl_ctx->add_flags)) - 1; + /* A usb_set_interface() call directly after clearing a halted + * condition may race on this quirky hardware. Not worth + * worrying about, since this is prototype hardware. Not sure + * if this will work for streams, but streams support was + * untested on this prototype. + */ + if (xhci->quirks & XHCI_RESET_EP_QUIRK && + ep_index != (unsigned int) -1 && + le32_to_cpu(ctrl_ctx->add_flags) - SLOT_FLAG == + le32_to_cpu(ctrl_ctx->drop_flags)) { + ep_ring = xhci->devs[slot_id]->eps[ep_index].ring; + ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state; + if (!(ep_state & EP_HALTED)) + goto bandwidth_change; + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "Completed config ep cmd - " + "last ep index = %d, state = %d", + ep_index, ep_state); + /* Clear internal halted state and restart ring(s) */ + xhci->devs[slot_id]->eps[ep_index].ep_state &= + ~EP_HALTED; + ring_doorbell_for_active_rings(xhci, slot_id, ep_index); + break; + } +bandwidth_change: + xhci_dbg_trace(xhci, trace_xhci_dbg_context_change, + "Completed config ep cmd"); + xhci->devs[slot_id]->cmd_status = + GET_COMP_CODE(le32_to_cpu(event->status)); + complete(&xhci->devs[slot_id]->cmd_completion); break; - case TRB_EVAL_CONTEXT: - xhci_handle_cmd_eval_ctx(xhci, slot_id, event, cmd_comp_code); + case TRB_TYPE(TRB_EVAL_CONTEXT): + virt_dev = xhci->devs[slot_id]; + if (handle_cmd_in_cmd_wait_list(xhci, virt_dev, event)) + break; + xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(le32_to_cpu(event->status)); + complete(&xhci->devs[slot_id]->cmd_completion); break; - case TRB_ADDR_DEV: - xhci_handle_cmd_addr_dev(xhci, slot_id, cmd_comp_code); + case TRB_TYPE(TRB_ADDR_DEV): + xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(le32_to_cpu(event->status)); + complete(&xhci->addr_dev); break; - case TRB_STOP_RING: - WARN_ON(slot_id != TRB_TO_SLOT_ID( - le32_to_cpu(cmd_trb->generic.field[3]))); - xhci_handle_cmd_stop_ep(xhci, slot_id, cmd_trb, event); + case TRB_TYPE(TRB_STOP_RING): + handle_stopped_endpoint(xhci, xhci->cmd_ring->dequeue, event); break; - case TRB_SET_DEQ: - WARN_ON(slot_id != TRB_TO_SLOT_ID( - le32_to_cpu(cmd_trb->generic.field[3]))); - xhci_handle_cmd_set_deq(xhci, slot_id, cmd_trb, cmd_comp_code); + case TRB_TYPE(TRB_SET_DEQ): + handle_set_deq_completion(xhci, event, xhci->cmd_ring->dequeue); break; - case TRB_CMD_NOOP: + case TRB_TYPE(TRB_CMD_NOOP): break; - case TRB_RESET_EP: - WARN_ON(slot_id != TRB_TO_SLOT_ID( - le32_to_cpu(cmd_trb->generic.field[3]))); - xhci_handle_cmd_reset_ep(xhci, slot_id, cmd_trb, cmd_comp_code); + case TRB_TYPE(TRB_RESET_EP): + handle_reset_ep_completion(xhci, event, xhci->cmd_ring->dequeue); break; - case TRB_RESET_DEV: - WARN_ON(slot_id != TRB_TO_SLOT_ID( - le32_to_cpu(cmd_trb->generic.field[3]))); - xhci_handle_cmd_reset_dev(xhci, slot_id, event); + case TRB_TYPE(TRB_RESET_DEV): + xhci_dbg(xhci, "Completed reset device command.\n"); + slot_id = TRB_TO_SLOT_ID( + le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])); + virt_dev = xhci->devs[slot_id]; + if (virt_dev) + handle_cmd_in_cmd_wait_list(xhci, virt_dev, event); + else + xhci_warn(xhci, "Reset device command completion " + "for disabled slot %u\n", slot_id); break; - case TRB_NEC_GET_FW: - xhci_handle_cmd_nec_get_fw(xhci, event); + case TRB_TYPE(TRB_NEC_GET_FW): + if (!(xhci->quirks & XHCI_NEC_HOST)) { + xhci->error_bitmask |= 1 << 6; + break; + } + xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, + "NEC firmware version %2x.%02x", + NEC_FW_MAJOR(le32_to_cpu(event->status)), + NEC_FW_MINOR(le32_to_cpu(event->status))); break; default: /* Skip over unknown commands on the event ring */ @@ -2973,58 +2929,8 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, } while (1) { - if (room_on_ring(xhci, ep_ring, num_trbs)) { - union xhci_trb *trb = ep_ring->enqueue; - unsigned int usable = ep_ring->enq_seg->trbs + - TRBS_PER_SEGMENT - 1 - trb; - u32 nop_cmd; - - /* - * Section 4.11.7.1 TD Fragments states that a link - * TRB must only occur at the boundary between - * data bursts (eg 512 bytes for 480M). - * While it is possible to split a large fragment - * we don't know the size yet. - * Simplest solution is to fill the trb before the - * LINK with nop commands. - */ - if (num_trbs == 1 || num_trbs <= usable || usable == 0) - break; - - if (ep_ring->type != TYPE_BULK) - /* - * While isoc transfers might have a buffer that - * crosses a 64k boundary it is unlikely. - * Since we can't add NOPs without generating - * gaps in the traffic just hope it never - * happens at the end of the ring. - * This could be fixed by writing a LINK TRB - * instead of the first NOP - however the - * TRB_TYPE_LINK_LE32() calls would all need - * changing to check the ring length. - */ - break; - - if (num_trbs >= TRBS_PER_SEGMENT) { - xhci_err(xhci, "Too many fragments %d, max %d\n", - num_trbs, TRBS_PER_SEGMENT - 1); - return -ENOMEM; - } - - nop_cmd = cpu_to_le32(TRB_TYPE(TRB_TR_NOOP) | - ep_ring->cycle_state); - ep_ring->num_trbs_free -= usable; - do { - trb->generic.field[0] = 0; - trb->generic.field[1] = 0; - trb->generic.field[2] = 0; - trb->generic.field[3] = nop_cmd; - trb++; - } while (--usable); - ep_ring->enqueue = trb; - if (room_on_ring(xhci, ep_ring, num_trbs)) - break; - } + if (room_on_ring(xhci, ep_ring, num_trbs)) + break; if (ep_ring == xhci->cmd_ring) { xhci_err(xhci, "Do not support expand command ring\n"); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 4265b48..6e0d886 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3459,7 +3459,7 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) /* Wait for the Reset Device command to finish */ timeleft = wait_for_completion_interruptible_timeout( reset_device_cmd->completion, - XHCI_CMD_DEFAULT_TIMEOUT); + USB_CTRL_SET_TIMEOUT); if (timeleft <= 0) { xhci_warn(xhci, "%s while waiting for reset device command\n", timeleft == 0 ? "Timeout" : "Signal"); @@ -3583,6 +3583,11 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) del_timer_sync(&virt_dev->eps[i].stop_cmd_timer); } + if (udev->usb2_hw_lpm_enabled) { + xhci_set_usb2_hardware_lpm(hcd, udev, 0); + udev->usb2_hw_lpm_enabled = 0; + } + spin_lock_irqsave(&xhci->lock, flags); /* Don't disable the slot if the host controller is dead. */ state = xhci_readl(xhci, &xhci->op_regs->status); @@ -3716,6 +3721,9 @@ disable_slot: * the device). * We should be protected by the usb_address0_mutex in khubd's hub_port_init, so * we should only issue and wait on one address command at the same time. + * + * We add one to the device address issued by the hardware because the USB core + * uses address 1 for the root hubs (even though they're not really devices). */ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) { @@ -3860,13 +3868,16 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx); trace_xhci_address_ctx(xhci, virt_dev->out_ctx, slot_ctx->dev_info >> 27); + /* Use kernel assigned address for devices; store xHC assigned + * address locally. */ + virt_dev->address = (le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK) + + 1; /* Zero the input context control for later use */ ctrl_ctx->add_flags = 0; ctrl_ctx->drop_flags = 0; xhci_dbg_trace(xhci, trace_xhci_dbg_address, - "Internal device address = %d", - le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK); + "Internal device address = %d", virt_dev->address); return 0; } @@ -4014,6 +4025,133 @@ static int xhci_calculate_usb2_hw_lpm_params(struct usb_device *udev) return PORT_BESLD(besld) | PORT_L1_TIMEOUT(l1) | PORT_HIRDM(hirdm); } +static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd, + struct usb_device *udev) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct dev_info *dev_info; + __le32 __iomem **port_array; + __le32 __iomem *addr, *pm_addr; + u32 temp, dev_id; + unsigned int port_num; + unsigned long flags; + int hird; + int ret; + + if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support || + !udev->lpm_capable) + return -EINVAL; + + /* we only support lpm for non-hub device connected to root hub yet */ + if (!udev->parent || udev->parent->parent || + udev->descriptor.bDeviceClass == USB_CLASS_HUB) + return -EINVAL; + + spin_lock_irqsave(&xhci->lock, flags); + + /* Look for devices in lpm_failed_devs list */ + dev_id = le16_to_cpu(udev->descriptor.idVendor) << 16 | + le16_to_cpu(udev->descriptor.idProduct); + list_for_each_entry(dev_info, &xhci->lpm_failed_devs, list) { + if (dev_info->dev_id == dev_id) { + ret = -EINVAL; + goto finish; + } + } + + port_array = xhci->usb2_ports; + port_num = udev->portnum - 1; + + if (port_num > HCS_MAX_PORTS(xhci->hcs_params1)) { + xhci_dbg(xhci, "invalid port number %d\n", udev->portnum); + ret = -EINVAL; + goto finish; + } + + /* + * Test USB 2.0 software LPM. + * FIXME: some xHCI 1.0 hosts may implement a new register to set up + * hardware-controlled USB 2.0 LPM. See section 5.4.11 and 4.23.5.1.1.1 + * in the June 2011 errata release. + */ + xhci_dbg(xhci, "test port %d software LPM\n", port_num); + /* + * Set L1 Device Slot and HIRD/BESL. + * Check device's USB 2.0 extension descriptor to determine whether + * HIRD or BESL shoule be used. See USB2.0 LPM errata. + */ + pm_addr = port_array[port_num] + PORTPMSC; + hird = xhci_calculate_hird_besl(xhci, udev); + temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird); + xhci_writel(xhci, temp, pm_addr); + + /* Set port link state to U2(L1) */ + addr = port_array[port_num]; + xhci_set_link_state(xhci, port_array, port_num, XDEV_U2); + + /* wait for ACK */ + spin_unlock_irqrestore(&xhci->lock, flags); + msleep(10); + spin_lock_irqsave(&xhci->lock, flags); + + /* Check L1 Status */ + ret = xhci_handshake(xhci, pm_addr, + PORT_L1S_MASK, PORT_L1S_SUCCESS, 125); + if (ret != -ETIMEDOUT) { + /* enter L1 successfully */ + temp = xhci_readl(xhci, addr); + xhci_dbg(xhci, "port %d entered L1 state, port status 0x%x\n", + port_num, temp); + ret = 0; + } else { + temp = xhci_readl(xhci, pm_addr); + xhci_dbg(xhci, "port %d software lpm failed, L1 status %d\n", + port_num, temp & PORT_L1S_MASK); + ret = -EINVAL; + } + + /* Resume the port */ + xhci_set_link_state(xhci, port_array, port_num, XDEV_U0); + + spin_unlock_irqrestore(&xhci->lock, flags); + msleep(10); + spin_lock_irqsave(&xhci->lock, flags); + + /* Clear PLC */ + xhci_test_and_clear_bit(xhci, port_array, port_num, PORT_PLC); + + /* Check PORTSC to make sure the device is in the right state */ + if (!ret) { + temp = xhci_readl(xhci, addr); + xhci_dbg(xhci, "resumed port %d status 0x%x\n", port_num, temp); + if (!(temp & PORT_CONNECT) || !(temp & PORT_PE) || + (temp & PORT_PLS_MASK) != XDEV_U0) { + xhci_dbg(xhci, "port L1 resume fail\n"); + ret = -EINVAL; + } + } + + if (ret) { + /* Insert dev to lpm_failed_devs list */ + xhci_warn(xhci, "device LPM test failed, may disconnect and " + "re-enumerate\n"); + dev_info = kzalloc(sizeof(struct dev_info), GFP_ATOMIC); + if (!dev_info) { + ret = -ENOMEM; + goto finish; + } + dev_info->dev_id = dev_id; + INIT_LIST_HEAD(&dev_info->list); + list_add(&dev_info->list, &xhci->lpm_failed_devs); + } else { + xhci_ring_device(xhci, udev->slot_id); + } + +finish: + spin_unlock_irqrestore(&xhci->lock, flags); + return ret; +} + int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, struct usb_device *udev, int enable) { @@ -4090,7 +4228,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, } pm_val &= ~PORT_HIRD_MASK; - pm_val |= PORT_HIRD(hird) | PORT_RWE | PORT_L1DS(udev->slot_id); + pm_val |= PORT_HIRD(hird) | PORT_RWE; xhci_writel(xhci, pm_val, pm_addr); pm_val = xhci_readl(xhci, pm_addr); pm_val |= PORT_HLE; @@ -4098,7 +4236,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, /* flush write */ xhci_readl(xhci, pm_addr); } else { - pm_val &= ~(PORT_HLE | PORT_RWE | PORT_HIRD_MASK | PORT_L1DS_MASK); + pm_val &= ~(PORT_HLE | PORT_RWE | PORT_HIRD_MASK); xhci_writel(xhci, pm_val, pm_addr); /* flush write */ xhci_readl(xhci, pm_addr); @@ -4141,26 +4279,24 @@ static int xhci_check_usb2_port_capability(struct xhci_hcd *xhci, int port, int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); + int ret; int portnum = udev->portnum - 1; - if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support || - !udev->lpm_capable) - return 0; - - /* we only support lpm for non-hub device connected to root hub yet */ - if (!udev->parent || udev->parent->parent || - udev->descriptor.bDeviceClass == USB_CLASS_HUB) - return 0; - - if (xhci->hw_lpm_support == 1 && - xhci_check_usb2_port_capability( - xhci, portnum, XHCI_HLC)) { - udev->usb2_hw_lpm_capable = 1; - udev->l1_params.timeout = XHCI_L1_TIMEOUT; - udev->l1_params.besl = XHCI_DEFAULT_BESL; - if (xhci_check_usb2_port_capability(xhci, portnum, - XHCI_BLC)) - udev->usb2_hw_lpm_besl_capable = 1; + ret = xhci_usb2_software_lpm_test(hcd, udev); + if (!ret) { + xhci_dbg(xhci, "software LPM test succeed\n"); + if (xhci->hw_lpm_support == 1 && + xhci_check_usb2_port_capability(xhci, portnum, XHCI_HLC)) { + udev->usb2_hw_lpm_capable = 1; + udev->l1_params.timeout = XHCI_L1_TIMEOUT; + udev->l1_params.besl = XHCI_DEFAULT_BESL; + if (xhci_check_usb2_port_capability(xhci, portnum, + XHCI_BLC)) + udev->usb2_hw_lpm_besl_capable = 1; + ret = xhci_set_usb2_hardware_lpm(hcd, udev, 1); + if (!ret) + udev->usb2_hw_lpm_enabled = 1; + } } return 0; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 03c74b7..941d5f5 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -383,7 +383,6 @@ struct xhci_op_regs { #define PORT_RWE (1 << 3) #define PORT_HIRD(p) (((p) & 0xf) << 4) #define PORT_HIRD_MASK (0xf << 4) -#define PORT_L1DS_MASK (0xff << 8) #define PORT_L1DS(p) (((p) & 0xff) << 8) #define PORT_HLE (1 << 16) @@ -935,6 +934,8 @@ struct xhci_virt_device { /* Rings saved to ensure old alt settings can be re-instated */ struct xhci_ring **ring_cache; int num_rings_cached; + /* Store xHC assigned device address */ + int address; #define XHCI_MAX_RINGS_CACHED 31 struct xhci_virt_ep eps[31]; struct completion cmd_completion; |