summaryrefslogtreecommitdiff
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
committerScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
commit62b8c978ee6b8d135d9e7953221de58000dba986 (patch)
tree683b04b2e627f6710c22c151b23c8cc9a165315e /drivers/usb/host
parent78fd82238d0e5716578c326404184a27ba67fd6e (diff)
downloadlinux-fsl-qoriq-62b8c978ee6b8d135d9e7953221de58000dba986.tar.xz
Rewind v3.13-rc3+ (78fd82238d0e5716) to v3.12
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/Kconfig59
-rw-r--r--drivers/usb/host/Makefile11
-rw-r--r--drivers/usb/host/bcma-hcd.c3
-rw-r--r--drivers/usb/host/ehci-atmel.c23
-rw-r--r--drivers/usb/host/ehci-dbg.c113
-rw-r--r--drivers/usb/host/ehci-fsl.c4
-rw-r--r--drivers/usb/host/ehci-grlib.c2
-rw-r--r--drivers/usb/host/ehci-hcd.c42
-rw-r--r--drivers/usb/host/ehci-mem.c4
-rw-r--r--drivers/usb/host/ehci-msm.c20
-rw-r--r--drivers/usb/host/ehci-mv.c2
-rw-r--r--drivers/usb/host/ehci-octeon.c6
-rw-r--r--drivers/usb/host/ehci-omap.c10
-rw-r--r--drivers/usb/host/ehci-orion.c7
-rw-r--r--drivers/usb/host/ehci-pci.c24
-rw-r--r--drivers/usb/host/ehci-platform.c10
-rw-r--r--drivers/usb/host/ehci-pmcmsp.c2
-rw-r--r--drivers/usb/host/ehci-ppc-of.c4
-rw-r--r--drivers/usb/host/ehci-ps3.c2
-rw-r--r--drivers/usb/host/ehci-q.c64
-rw-r--r--drivers/usb/host/ehci-s5p.c (renamed from drivers/usb/host/ehci-exynos.c)171
-rw-r--r--drivers/usb/host/ehci-sched.c1033
-rw-r--r--drivers/usb/host/ehci-sead3.c2
-rw-r--r--drivers/usb/host/ehci-sh.c2
-rw-r--r--drivers/usb/host/ehci-spear.c7
-rw-r--r--drivers/usb/host/ehci-sysfs.c15
-rw-r--r--drivers/usb/host/ehci-tegra.c11
-rw-r--r--drivers/usb/host/ehci-tilegx.c2
-rw-r--r--drivers/usb/host/ehci-w90x900.c89
-rw-r--r--drivers/usb/host/ehci-xilinx-of.c2
-rw-r--r--drivers/usb/host/ehci.h81
-rw-r--r--drivers/usb/host/fhci-hcd.c2
-rw-r--r--drivers/usb/host/fotg210-hcd.c2
-rw-r--r--drivers/usb/host/fusbh200-hcd.c2
-rw-r--r--drivers/usb/host/hwa-hc.c33
-rw-r--r--drivers/usb/host/isp1362-hcd.c2
-rw-r--r--drivers/usb/host/ohci-at91.c165
-rw-r--r--drivers/usb/host/ohci-dbg.c2
-rw-r--r--drivers/usb/host/ohci-ep93xx.c184
-rw-r--r--drivers/usb/host/ohci-exynos.c193
-rw-r--r--drivers/usb/host/ohci-hcd.c159
-rw-r--r--drivers/usb/host/ohci-hub.c9
-rw-r--r--drivers/usb/host/ohci-nxp.c128
-rw-r--r--drivers/usb/host/ohci-octeon.c5
-rw-r--r--drivers/usb/host/ohci-omap.c169
-rw-r--r--drivers/usb/host/ohci-omap3.c128
-rw-r--r--drivers/usb/host/ohci-pci.c15
-rw-r--r--drivers/usb/host/ohci-platform.c11
-rw-r--r--drivers/usb/host/ohci-ppc-of.c2
-rw-r--r--drivers/usb/host/ohci-pxa27x.c258
-rw-r--r--drivers/usb/host/ohci-s3c2410.c136
-rw-r--r--drivers/usb/host/ohci-sa1111.c6
-rw-r--r--drivers/usb/host/ohci-sm501.c11
-rw-r--r--drivers/usb/host/ohci-spear.c147
-rw-r--r--drivers/usb/host/pci-quirks.c137
-rw-r--r--drivers/usb/host/pci-quirks.h2
-rw-r--r--drivers/usb/host/sl811-hcd.c4
-rw-r--r--drivers/usb/host/ssb-hcd.c3
-rw-r--r--drivers/usb/host/uhci-debug.c16
-rw-r--r--drivers/usb/host/uhci-hub.c40
-rw-r--r--drivers/usb/host/uhci-pci.c19
-rw-r--r--drivers/usb/host/uhci-platform.c10
-rw-r--r--drivers/usb/host/whci/hcd.c4
-rw-r--r--drivers/usb/host/xhci-hub.c5
-rw-r--r--drivers/usb/host/xhci-mem.c10
-rw-r--r--drivers/usb/host/xhci-ring.c378
-rw-r--r--drivers/usb/host/xhci.c182
-rw-r--r--drivers/usb/host/xhci.h3
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;