summaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/Kconfig57
-rw-r--r--drivers/usb/host/ehci-ath79.c202
-rw-r--r--drivers/usb/host/ehci-atmel.c2
-rw-r--r--drivers/usb/host/ehci-au1xxx.c12
-rw-r--r--drivers/usb/host/ehci-cns3xxx.c2
-rw-r--r--drivers/usb/host/ehci-dbg.c2
-rw-r--r--drivers/usb/host/ehci-fsl.c221
-rw-r--r--drivers/usb/host/ehci-fsl.h4
-rw-r--r--drivers/usb/host/ehci-grlib.c242
-rw-r--r--drivers/usb/host/ehci-hcd.c21
-rw-r--r--drivers/usb/host/ehci-hub.c10
-rw-r--r--drivers/usb/host/ehci-ixp4xx.c2
-rw-r--r--drivers/usb/host/ehci-msm.c2
-rw-r--r--drivers/usb/host/ehci-mxc.c2
-rw-r--r--drivers/usb/host/ehci-octeon.c2
-rw-r--r--drivers/usb/host/ehci-omap.c2
-rw-r--r--drivers/usb/host/ehci-orion.c2
-rw-r--r--drivers/usb/host/ehci-pci.c2
-rw-r--r--drivers/usb/host/ehci-pmcmsp.c2
-rw-r--r--drivers/usb/host/ehci-ppc-of.c2
-rw-r--r--drivers/usb/host/ehci-ps3.c2
-rw-r--r--drivers/usb/host/ehci-q.c5
-rw-r--r--drivers/usb/host/ehci-s5p.c202
-rw-r--r--drivers/usb/host/ehci-sched.c22
-rw-r--r--drivers/usb/host/ehci-sh.c2
-rw-r--r--drivers/usb/host/ehci-spear.c2
-rw-r--r--drivers/usb/host/ehci-tegra.c74
-rw-r--r--drivers/usb/host/ehci-vt8500.c3
-rw-r--r--drivers/usb/host/ehci-w90x900.c2
-rw-r--r--drivers/usb/host/ehci-xilinx-of.c2
-rw-r--r--drivers/usb/host/ehci.h13
-rw-r--r--drivers/usb/host/isp116x-hcd.c1
-rw-r--r--drivers/usb/host/isp1760-hcd.c1638
-rw-r--r--drivers/usb/host/isp1760-hcd.h78
-rw-r--r--drivers/usb/host/octeon2-common.c45
-rw-r--r--drivers/usb/host/ohci-ath79.c151
-rw-r--r--drivers/usb/host/ohci-hcd.c9
-rw-r--r--drivers/usb/host/ohci-pci.c12
-rw-r--r--drivers/usb/host/ohci-s3c2410.c58
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c6
-rw-r--r--drivers/usb/host/pci-quirks.c151
-rw-r--r--drivers/usb/host/sl811-hcd.c8
-rw-r--r--drivers/usb/host/u132-hcd.c3
-rw-r--r--drivers/usb/host/uhci-debug.c88
-rw-r--r--drivers/usb/host/uhci-grlib.c208
-rw-r--r--drivers/usb/host/uhci-hcd.c458
-rw-r--r--drivers/usb/host/uhci-hcd.h248
-rw-r--r--drivers/usb/host/uhci-hub.c41
-rw-r--r--drivers/usb/host/uhci-pci.c301
-rw-r--r--drivers/usb/host/uhci-q.c131
-rw-r--r--drivers/usb/host/xhci-dbg.c51
-rw-r--r--drivers/usb/host/xhci-hub.c231
-rw-r--r--drivers/usb/host/xhci-mem.c144
-rw-r--r--drivers/usb/host/xhci-pci.c1
-rw-r--r--drivers/usb/host/xhci-ring.c509
-rw-r--r--drivers/usb/host/xhci.c145
-rw-r--r--drivers/usb/host/xhci.h145
57 files changed, 4001 insertions, 1982 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index e0e0787b724b..ab085f12d570 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -106,13 +106,13 @@ config USB_EHCI_BIG_ENDIAN_MMIO
depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || \
ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
PPC_MPC512x || CPU_CAVIUM_OCTEON || \
- PMC_MSP)
+ PMC_MSP || SPARC_LEON)
default y
config USB_EHCI_BIG_ENDIAN_DESC
bool
depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
- PPC_MPC512x || PMC_MSP)
+ PPC_MPC512x || PMC_MSP || SPARC_LEON)
default y
config XPS_USB_HCD_XILINX
@@ -188,6 +188,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_S5P
+ boolean "S5P EHCI support"
+ depends on USB_EHCI_HCD && PLAT_S5P
+ help
+ Enable support for the S5P SOC's on-chip EHCI controller.
+
config USB_W90X900_EHCI
bool "W90X900(W90P910) EHCI support"
depends on USB_EHCI_HCD && ARCH_W90X900
@@ -202,6 +208,15 @@ config USB_CNS3XXX_EHCI
It is needed for high-speed (480Mbit/sec) USB 2.0 device
support.
+config USB_EHCI_ATH79
+ bool "EHCI support for AR7XXX/AR9XXX SoCs"
+ depends on USB_EHCI_HCD && (SOC_AR71XX || SOC_AR724X || SOC_AR913X)
+ select USB_EHCI_ROOT_HUB_TT
+ default y
+ ---help---
+ Enables support for the built-in EHCI controller present
+ on the Atheros AR7XXX/AR9XXX SoCs.
+
config USB_OXU210HP_HCD
tristate "OXU210HP HCD support"
depends on USB
@@ -287,6 +302,14 @@ config USB_OHCI_HCD_OMAP3
Enables support for the on-chip OHCI controller on
OMAP3 and later chips.
+config USB_OHCI_ATH79
+ bool "USB OHCI support for the Atheros AR71XX/AR7240 SoCs"
+ depends on USB_OHCI_HCD && (SOC_AR71XX || SOC_AR724X)
+ default y
+ help
+ Enables support for the built-in OHCI controller present on the
+ Atheros AR71XX/AR7240 SoCs.
+
config USB_OHCI_HCD_PPC_SOC
bool "OHCI support for on-chip PPC USB controller"
depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
@@ -373,7 +396,7 @@ config USB_OHCI_LITTLE_ENDIAN
config USB_UHCI_HCD
tristate "UHCI HCD (most Intel and VIA) support"
- depends on USB && PCI
+ depends on USB && (PCI || SPARC_LEON)
---help---
The Universal Host Controller Interface is a standard by Intel for
accessing the USB hardware in the PC (which is also called the USB
@@ -382,11 +405,27 @@ config USB_UHCI_HCD
with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX,
i810, i820) conform to this standard. Also all VIA PCI chipsets
(like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro
- 133). If unsure, say Y.
+ 133) and LEON/GRLIB SoCs with the GRUSBHC controller.
+ If unsure, say Y.
To compile this driver as a module, choose M here: the
module will be called uhci-hcd.
+config USB_UHCI_SUPPORT_NON_PCI_HC
+ bool
+ depends on USB_UHCI_HCD
+ default y if SPARC_LEON
+
+config USB_UHCI_BIG_ENDIAN_MMIO
+ bool
+ depends on USB_UHCI_SUPPORT_NON_PCI_HC && SPARC_LEON
+ default y
+
+config USB_UHCI_BIG_ENDIAN_DESC
+ bool
+ depends on USB_UHCI_SUPPORT_NON_PCI_HC && SPARC_LEON
+ default y
+
config USB_FHCI_HCD
tristate "Freescale QE USB Host Controller support"
depends on USB && OF_GPIO && QE_GPIO && QUICC_ENGINE
@@ -444,6 +483,16 @@ config USB_SL811_HCD
To compile this driver as a module, choose M here: the
module will be called sl811-hcd.
+config USB_SL811_HCD_ISO
+ bool "partial ISO support"
+ depends on USB_SL811_HCD
+ help
+ The driver doesn't support iso_frame_desc (yet), but for some simple
+ devices that just queue one ISO frame per URB, then ISO transfers
+ "should" work using the normal urb status fields.
+
+ If unsure, say N.
+
config USB_SL811_CS
tristate "CF/PCMCIA support for SL811HS HCD"
depends on USB_SL811_HCD && PCMCIA
diff --git a/drivers/usb/host/ehci-ath79.c b/drivers/usb/host/ehci-ath79.c
new file mode 100644
index 000000000000..98cc8a13169c
--- /dev/null
+++ b/drivers/usb/host/ehci-ath79.c
@@ -0,0 +1,202 @@
+/*
+ * Bus Glue for Atheros AR7XXX/AR9XXX built-in EHCI controller.
+ *
+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Parts of this file are based on Atheros' 2.6.15 BSP
+ * Copyright (C) 2007 Atheros Communications, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+
+enum {
+ EHCI_ATH79_IP_V1 = 0,
+ EHCI_ATH79_IP_V2,
+};
+
+static const struct platform_device_id ehci_ath79_id_table[] = {
+ {
+ .name = "ar71xx-ehci",
+ .driver_data = EHCI_ATH79_IP_V1,
+ },
+ {
+ .name = "ar724x-ehci",
+ .driver_data = EHCI_ATH79_IP_V2,
+ },
+ {
+ .name = "ar913x-ehci",
+ .driver_data = EHCI_ATH79_IP_V2,
+ },
+ {
+ /* terminating entry */
+ },
+};
+
+MODULE_DEVICE_TABLE(platform, ehci_ath79_id_table);
+
+static int ehci_ath79_init(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ struct platform_device *pdev = to_platform_device(hcd->self.controller);
+ const struct platform_device_id *id;
+ int hclength;
+ int ret;
+
+ id = platform_get_device_id(pdev);
+ if (!id) {
+ dev_err(hcd->self.controller, "missing device id\n");
+ return -EINVAL;
+ }
+
+ hclength = HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
+ switch (id->driver_data) {
+ case EHCI_ATH79_IP_V1:
+ ehci->has_synopsys_hc_bug = 1;
+
+ ehci->caps = hcd->regs;
+ ehci->regs = hcd->regs + hclength;
+ break;
+
+ case EHCI_ATH79_IP_V2:
+ hcd->has_tt = 1;
+
+ ehci->caps = hcd->regs + 0x100;
+ ehci->regs = hcd->regs + 0x100 + hclength;
+ break;
+
+ default:
+ BUG();
+ }
+
+ dbg_hcs_params(ehci, "reset");
+ dbg_hcc_params(ehci, "reset");
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+ ehci->sbrn = 0x20;
+
+ ehci_reset(ehci);
+
+ ret = ehci_init(hcd);
+ if (ret)
+ return ret;
+
+ ehci_port_power(ehci, 0);
+
+ return 0;
+}
+
+static const struct hc_driver ehci_ath79_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "Atheros built-in EHCI controller",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ .reset = ehci_ath79_init,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
+
+ .get_frame_number = ehci_get_frame,
+
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static int ehci_ath79_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ struct resource *res;
+ int irq;
+ int ret;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_dbg(&pdev->dev, "no IRQ specified\n");
+ return -ENODEV;
+ }
+ irq = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_dbg(&pdev->dev, "no base address specified\n");
+ return -ENODEV;
+ }
+
+ hcd = usb_create_hcd(&ehci_ath79_hc_driver, &pdev->dev,
+ dev_name(&pdev->dev));
+ if (!hcd)
+ return -ENOMEM;
+
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = res->end - res->start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ dev_dbg(&pdev->dev, "controller already in use\n");
+ ret = -EBUSY;
+ goto err_put_hcd;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ dev_dbg(&pdev->dev, "error mapping memory\n");
+ ret = -EFAULT;
+ goto err_release_region;
+ }
+
+ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ if (ret)
+ goto err_iounmap;
+
+ return 0;
+
+err_iounmap:
+ iounmap(hcd->regs);
+
+err_release_region:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_put_hcd:
+ usb_put_hcd(hcd);
+ return ret;
+}
+
+static int ehci_ath79_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+static struct platform_driver ehci_ath79_driver = {
+ .probe = ehci_ath79_probe,
+ .remove = ehci_ath79_remove,
+ .id_table = ehci_ath79_id_table,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ath79-ehci",
+ }
+};
+
+MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ath79-ehci");
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index b2ed55cb811d..a5a3ef1f0096 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -56,7 +56,7 @@ static int ehci_atmel_setup(struct usb_hcd *hcd)
/* registers start at offset 0x0 */
ehci->caps = hcd->regs;
ehci->regs = hcd->regs +
- HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index a869e3c103d3..42ae57409908 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -175,7 +175,8 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
ehci = hcd_to_ehci(hcd);
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+ ehci->regs = hcd->regs +
+ HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = readl(&ehci->caps->hcs_params);
@@ -215,10 +216,7 @@ static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
unsigned long flags;
- int rc;
-
- return 0;
- rc = 0;
+ int rc = 0;
if (time_before(jiffies, ehci->next_statechange))
msleep(10);
@@ -233,13 +231,13 @@ static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
(void)ehci_readl(ehci, &ehci->regs->intr_enable);
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
- au1xxx_stop_ehc();
spin_unlock_irqrestore(&ehci->lock, flags);
// could save FLADJ in case of Vaux power loss
// ... we'd only use it to handle clock skew
+ au1xxx_stop_ehc();
+
return rc;
}
diff --git a/drivers/usb/host/ehci-cns3xxx.c b/drivers/usb/host/ehci-cns3xxx.c
index 708a05b5d258..d41745c6f0c4 100644
--- a/drivers/usb/host/ehci-cns3xxx.c
+++ b/drivers/usb/host/ehci-cns3xxx.c
@@ -34,7 +34,7 @@ static int cns3xxx_ehci_init(struct usb_hcd *hcd)
ehci->caps = hcd->regs;
ehci->regs = hcd->regs
- + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
hcd->has_tt = 0;
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 693c29b30521..40a844c1dbb4 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -726,7 +726,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
}
/* Capability Registers */
- i = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ i = HC_VERSION(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
temp = scnprintf (next, size,
"bus %s, device %s\n"
"%s\n"
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 5c761df7fa83..f380bf97e5af 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -117,6 +117,9 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
pdata->regs = hcd->regs;
+ if (pdata->power_budget)
+ hcd->power_budget = pdata->power_budget;
+
/*
* do platform specific init: check the clock, grab/config pins, etc.
*/
@@ -134,6 +137,30 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
if (retval != 0)
goto err4;
+
+#ifdef CONFIG_USB_OTG
+ if (pdata->operating_mode == FSL_USB2_DR_OTG) {
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+ ehci->transceiver = otg_get_transceiver();
+ dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, transceiver=0x%p\n",
+ hcd, ehci, ehci->transceiver);
+
+ if (ehci->transceiver) {
+ retval = otg_set_host(ehci->transceiver,
+ &ehci_to_hcd(ehci)->self);
+ if (retval) {
+ if (ehci->transceiver)
+ put_device(ehci->transceiver->dev);
+ goto err4;
+ }
+ } else {
+ dev_err(&pdev->dev, "can't find transceiver\n");
+ retval = -ENODEV;
+ goto err4;
+ }
+ }
+#endif
return retval;
err4:
@@ -164,6 +191,12 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
struct platform_device *pdev)
{
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+ if (ehci->transceiver) {
+ otg_set_host(ehci->transceiver, NULL);
+ put_device(ehci->transceiver->dev);
+ }
usb_remove_hcd(hcd);
@@ -291,7 +324,7 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
/* EHCI registers start at offset 0x100 */
ehci->caps = hcd->regs + 0x100;
ehci->regs = hcd->regs + 0x100 +
- HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
@@ -328,6 +361,149 @@ struct ehci_fsl {
#ifdef CONFIG_PM
+#ifdef CONFIG_PPC_MPC512x
+static int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ struct fsl_usb2_platform_data *pdata = dev->platform_data;
+ u32 tmp;
+
+#ifdef DEBUG
+ u32 mode = ehci_readl(ehci, hcd->regs + FSL_SOC_USB_USBMODE);
+ mode &= USBMODE_CM_MASK;
+ tmp = ehci_readl(ehci, hcd->regs + 0x140); /* usbcmd */
+
+ dev_dbg(dev, "suspend=%d already_suspended=%d "
+ "mode=%d usbcmd %08x\n", pdata->suspended,
+ pdata->already_suspended, mode, tmp);
+#endif
+
+ /*
+ * If the controller is already suspended, then this must be a
+ * PM suspend. Remember this fact, so that we will leave the
+ * controller suspended at PM resume time.
+ */
+ if (pdata->suspended) {
+ dev_dbg(dev, "already suspended, leaving early\n");
+ pdata->already_suspended = 1;
+ return 0;
+ }
+
+ dev_dbg(dev, "suspending...\n");
+
+ hcd->state = HC_STATE_SUSPENDED;
+ dev->power.power_state = PMSG_SUSPEND;
+
+ /* ignore non-host interrupts */
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+ /* stop the controller */
+ tmp = ehci_readl(ehci, &ehci->regs->command);
+ tmp &= ~CMD_RUN;
+ ehci_writel(ehci, tmp, &ehci->regs->command);
+
+ /* save EHCI registers */
+ pdata->pm_command = ehci_readl(ehci, &ehci->regs->command);
+ pdata->pm_command &= ~CMD_RUN;
+ pdata->pm_status = ehci_readl(ehci, &ehci->regs->status);
+ pdata->pm_intr_enable = ehci_readl(ehci, &ehci->regs->intr_enable);
+ pdata->pm_frame_index = ehci_readl(ehci, &ehci->regs->frame_index);
+ pdata->pm_segment = ehci_readl(ehci, &ehci->regs->segment);
+ pdata->pm_frame_list = ehci_readl(ehci, &ehci->regs->frame_list);
+ pdata->pm_async_next = ehci_readl(ehci, &ehci->regs->async_next);
+ pdata->pm_configured_flag =
+ ehci_readl(ehci, &ehci->regs->configured_flag);
+ pdata->pm_portsc = ehci_readl(ehci, &ehci->regs->port_status[0]);
+ pdata->pm_usbgenctrl = ehci_readl(ehci,
+ hcd->regs + FSL_SOC_USB_USBGENCTRL);
+
+ /* clear the W1C bits */
+ pdata->pm_portsc &= cpu_to_hc32(ehci, ~PORT_RWC_BITS);
+
+ pdata->suspended = 1;
+
+ /* clear PP to cut power to the port */
+ tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
+ tmp &= ~PORT_POWER;
+ ehci_writel(ehci, tmp, &ehci->regs->port_status[0]);
+
+ return 0;
+}
+
+static int ehci_fsl_mpc512x_drv_resume(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ struct fsl_usb2_platform_data *pdata = dev->platform_data;
+ u32 tmp;
+
+ dev_dbg(dev, "suspend=%d already_suspended=%d\n",
+ pdata->suspended, pdata->already_suspended);
+
+ /*
+ * If the controller was already suspended at suspend time,
+ * then don't resume it now.
+ */
+ if (pdata->already_suspended) {
+ dev_dbg(dev, "already suspended, leaving early\n");
+ pdata->already_suspended = 0;
+ return 0;
+ }
+
+ if (!pdata->suspended) {
+ dev_dbg(dev, "not suspended, leaving early\n");
+ return 0;
+ }
+
+ pdata->suspended = 0;
+
+ dev_dbg(dev, "resuming...\n");
+
+ /* set host mode */
+ tmp = USBMODE_CM_HOST | (pdata->es ? USBMODE_ES : 0);
+ ehci_writel(ehci, tmp, hcd->regs + FSL_SOC_USB_USBMODE);
+
+ ehci_writel(ehci, pdata->pm_usbgenctrl,
+ hcd->regs + FSL_SOC_USB_USBGENCTRL);
+ ehci_writel(ehci, ISIPHYCTRL_PXE | ISIPHYCTRL_PHYE,
+ hcd->regs + FSL_SOC_USB_ISIPHYCTRL);
+
+ /* restore EHCI registers */
+ ehci_writel(ehci, pdata->pm_command, &ehci->regs->command);
+ ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable);
+ ehci_writel(ehci, pdata->pm_frame_index, &ehci->regs->frame_index);
+ ehci_writel(ehci, pdata->pm_segment, &ehci->regs->segment);
+ ehci_writel(ehci, pdata->pm_frame_list, &ehci->regs->frame_list);
+ ehci_writel(ehci, pdata->pm_async_next, &ehci->regs->async_next);
+ ehci_writel(ehci, pdata->pm_configured_flag,
+ &ehci->regs->configured_flag);
+ ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]);
+
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ hcd->state = HC_STATE_RUNNING;
+ dev->power.power_state = PMSG_ON;
+
+ tmp = ehci_readl(ehci, &ehci->regs->command);
+ tmp |= CMD_RUN;
+ ehci_writel(ehci, tmp, &ehci->regs->command);
+
+ usb_hcd_resume_root_hub(hcd);
+
+ return 0;
+}
+#else
+static inline int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static inline int ehci_fsl_mpc512x_drv_resume(struct device *dev)
+{
+ return 0;
+}
+#endif /* CONFIG_PPC_MPC512x */
+
static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
@@ -341,6 +517,11 @@ static int ehci_fsl_drv_suspend(struct device *dev)
struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
void __iomem *non_ehci = hcd->regs;
+ if (of_device_is_compatible(dev->parent->of_node,
+ "fsl,mpc5121-usb2-dr")) {
+ return ehci_fsl_mpc512x_drv_suspend(dev);
+ }
+
ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
device_may_wakeup(dev));
if (!fsl_deep_sleep())
@@ -357,6 +538,11 @@ static int ehci_fsl_drv_resume(struct device *dev)
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
void __iomem *non_ehci = hcd->regs;
+ if (of_device_is_compatible(dev->parent->of_node,
+ "fsl,mpc5121-usb2-dr")) {
+ return ehci_fsl_mpc512x_drv_resume(dev);
+ }
+
ehci_prepare_ports_for_controller_resume(ehci);
if (!fsl_deep_sleep())
return 0;
@@ -391,6 +577,38 @@ static struct dev_pm_ops ehci_fsl_pm_ops = {
#define EHCI_FSL_PM_OPS NULL
#endif /* CONFIG_PM */
+#ifdef CONFIG_USB_OTG
+static int ehci_start_port_reset(struct usb_hcd *hcd, unsigned port)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ u32 status;
+
+ if (!port)
+ return -EINVAL;
+
+ port--;
+
+ /* start port reset before HNP protocol time out */
+ status = readl(&ehci->regs->port_status[port]);
+ if (!(status & PORT_CONNECT))
+ return -ENODEV;
+
+ /* khubd will finish the reset later */
+ if (ehci_is_TDI(ehci)) {
+ writel(PORT_RESET |
+ (status & ~(PORT_CSC | PORT_PEC | PORT_OCC)),
+ &ehci->regs->port_status[port]);
+ } else {
+ writel(PORT_RESET, &ehci->regs->port_status[port]);
+ }
+
+ return 0;
+}
+#else
+#define ehci_start_port_reset NULL
+#endif /* CONFIG_USB_OTG */
+
+
static const struct hc_driver ehci_fsl_hc_driver = {
.description = hcd_name,
.product_desc = "Freescale On-Chip EHCI Host Controller",
@@ -430,6 +648,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
.hub_control = ehci_hub_control,
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
+ .start_port_reset = ehci_start_port_reset,
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h
index 3fabed33d940..491806221165 100644
--- a/drivers/usb/host/ehci-fsl.h
+++ b/drivers/usb/host/ehci-fsl.h
@@ -27,6 +27,10 @@
#define PORT_PTS_SERIAL (3<<30)
#define PORT_PTS_PTW (1<<28)
#define FSL_SOC_USB_PORTSC2 0x188
+#define FSL_SOC_USB_USBMODE 0x1a8
+#define USBMODE_CM_MASK (3 << 0) /* controller mode mask */
+#define USBMODE_CM_HOST (3 << 0) /* controller mode: host */
+#define USBMODE_ES (1 << 2) /* (Big) Endian Select */
#define FSL_SOC_USB_USBGENCTRL 0x200
#define USBGENCTRL_PPP (1 << 3)
diff --git a/drivers/usb/host/ehci-grlib.c b/drivers/usb/host/ehci-grlib.c
new file mode 100644
index 000000000000..93b230dc51a2
--- /dev/null
+++ b/drivers/usb/host/ehci-grlib.c
@@ -0,0 +1,242 @@
+/*
+ * Driver for Aeroflex Gaisler GRLIB GRUSBHC EHCI host controller
+ *
+ * GRUSBHC is typically found on LEON/GRLIB SoCs
+ *
+ * (c) Jan Andersson <jan@gaisler.com>
+ *
+ * Based on ehci-ppc-of.c which is:
+ * (c) Valentine Barshak <vbarshak@ru.mvista.com>
+ * and in turn based on "ehci-ppc-soc.c" by Stefan Roese <sr@denx.de>
+ * and "ohci-ppc-of.c" by Sylvain Munaut <tnt@246tNt.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/signal.h>
+
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+
+#define GRUSBHC_HCIVERSION 0x0100 /* Known value of cap. reg. HCIVERSION */
+
+/* called during probe() after chip reset completes */
+static int ehci_grlib_setup(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int retval;
+
+ retval = ehci_halt(ehci);
+ if (retval)
+ return retval;
+
+ retval = ehci_init(hcd);
+ if (retval)
+ return retval;
+
+ ehci->sbrn = 0x20;
+ ehci_port_power(ehci, 1);
+
+ return ehci_reset(ehci);
+}
+
+
+static const struct hc_driver ehci_grlib_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "GRLIB GRUSBHC EHCI",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = ehci_grlib_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 __devinit ehci_hcd_grlib_probe(struct platform_device *op)
+{
+ struct device_node *dn = op->dev.of_node;
+ struct usb_hcd *hcd;
+ struct ehci_hcd *ehci = NULL;
+ struct resource res;
+ u32 hc_capbase;
+ int irq;
+ int rv;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ dev_dbg(&op->dev, "initializing GRUSBHC EHCI USB Controller\n");
+
+ rv = of_address_to_resource(dn, 0, &res);
+ if (rv)
+ return rv;
+
+ /* usb_create_hcd requires dma_mask != NULL */
+ op->dev.dma_mask = &op->dev.coherent_dma_mask;
+ hcd = usb_create_hcd(&ehci_grlib_hc_driver, &op->dev,
+ "GRUSBHC EHCI USB");
+ if (!hcd)
+ return -ENOMEM;
+
+ hcd->rsrc_start = res.start;
+ hcd->rsrc_len = res.end - res.start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
+ rv = -EBUSY;
+ goto err_rmr;
+ }
+
+ irq = irq_of_parse_and_map(dn, 0);
+ if (irq == NO_IRQ) {
+ printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
+ rv = -EBUSY;
+ goto err_irq;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
+ rv = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ ehci = hcd_to_ehci(hcd);
+
+ ehci->caps = hcd->regs;
+
+ /* determine endianness of this implementation */
+ hc_capbase = ehci_readl(ehci, &ehci->caps->hc_capbase);
+ if (HC_VERSION(ehci, hc_capbase) != GRUSBHC_HCIVERSION) {
+ ehci->big_endian_mmio = 1;
+ ehci->big_endian_desc = 1;
+ ehci->big_endian_capbase = 1;
+ }
+
+ ehci->regs = hcd->regs +
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
+
+ /* cache this readonly data; minimize chip reads */
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+ rv = usb_add_hcd(hcd, irq, 0);
+ if (rv)
+ goto err_ehci;
+
+ return 0;
+
+err_ehci:
+ iounmap(hcd->regs);
+err_ioremap:
+ irq_dispose_mapping(irq);
+err_irq:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_rmr:
+ usb_put_hcd(hcd);
+
+ return rv;
+}
+
+
+static int ehci_hcd_grlib_remove(struct platform_device *op)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+
+ dev_set_drvdata(&op->dev, NULL);
+
+ dev_dbg(&op->dev, "stopping GRLIB GRUSBHC EHCI USB Controller\n");
+
+ usb_remove_hcd(hcd);
+
+ iounmap(hcd->regs);
+ irq_dispose_mapping(hcd->irq);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+
+static void ehci_hcd_grlib_shutdown(struct platform_device *op)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+
+ if (hcd->driver->shutdown)
+ hcd->driver->shutdown(hcd);
+}
+
+
+static const struct of_device_id ehci_hcd_grlib_of_match[] = {
+ {
+ .name = "GAISLER_EHCI",
+ },
+ {
+ .name = "01_026",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ehci_hcd_grlib_of_match);
+
+
+static struct platform_driver ehci_grlib_driver = {
+ .probe = ehci_hcd_grlib_probe,
+ .remove = ehci_hcd_grlib_remove,
+ .shutdown = ehci_hcd_grlib_shutdown,
+ .driver = {
+ .name = "grlib-ehci",
+ .owner = THIS_MODULE,
+ .of_match_table = ehci_hcd_grlib_of_match,
+ },
+};
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 78561d112c04..b435ed67dd5c 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -739,7 +739,7 @@ static int ehci_run (struct usb_hcd *hcd)
up_write(&ehci_cf_port_reset_rwsem);
ehci->last_periodic_enable = ktime_get_real();
- temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ temp = HC_VERSION(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci_info (ehci,
"USB %x.%x started, EHCI %x.%02x%s\n",
((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
@@ -777,8 +777,9 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
goto dead;
}
+ /* Shared IRQ? */
masked_status = status & INTR_MASK;
- if (!masked_status) { /* irq sharing? */
+ if (!masked_status || unlikely(hcd->state == HC_STATE_HALT)) {
spin_unlock(&ehci->lock);
return IRQ_NONE;
}
@@ -873,6 +874,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
dead:
ehci_reset(ehci);
ehci_writel(ehci, 0, &ehci->regs->configured_flag);
+ usb_hc_died(hcd);
/* generic layer kills/unlinks all urbs, then
* uses ehci_stop to clean up the rest
*/
@@ -1265,6 +1267,21 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER tegra_ehci_driver
#endif
+#ifdef CONFIG_USB_EHCI_S5P
+#include "ehci-s5p.c"
+#define PLATFORM_DRIVER s5p_ehci_driver
+#endif
+
+#ifdef CONFIG_USB_EHCI_ATH79
+#include "ehci-ath79.c"
+#define PLATFORM_DRIVER ehci_ath79_driver
+#endif
+
+#ifdef CONFIG_SPARC_LEON
+#include "ehci-grlib.c"
+#define PLATFORM_DRIVER ehci_grlib_driver
+#endif
+
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
!defined(XILINX_OF_PLATFORM_DRIVER)
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index d05ea03cfb4d..ea6184bf48d0 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -27,6 +27,7 @@
*/
/*-------------------------------------------------------------------------*/
+#include <linux/usb/otg.h>
#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
@@ -127,7 +128,7 @@ static int ehci_port_change(struct ehci_hcd *ehci)
return 0;
}
-static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
+static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
bool suspending, bool do_wakeup)
{
int port;
@@ -801,6 +802,13 @@ static int ehci_hub_control (
goto error;
if (ehci->no_selective_suspend)
break;
+#ifdef CONFIG_USB_OTG
+ if ((hcd->self.otg_port == (wIndex + 1))
+ && hcd->self.b_hnp_enable) {
+ otg_start_hnp(ehci->transceiver);
+ break;
+ }
+#endif
if (!(temp & PORT_SUSPEND))
break;
if ((temp & PORT_PE) == 0)
diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c
index 89b7c70c6ed6..50e600d26e28 100644
--- a/drivers/usb/host/ehci-ixp4xx.c
+++ b/drivers/usb/host/ehci-ixp4xx.c
@@ -23,7 +23,7 @@ static int ixp4xx_ehci_init(struct usb_hcd *hcd)
ehci->caps = hcd->regs + 0x100;
ehci->regs = hcd->regs + 0x100
- + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
hcd->has_tt = 1;
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 9ce1b0bc186d..b5a0bf649c95 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -41,7 +41,7 @@ static int ehci_msm_reset(struct usb_hcd *hcd)
ehci->caps = USB_CAPLENGTH;
ehci->regs = USB_CAPLENGTH +
- HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index 25c8c10bb689..0c058be35a38 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -208,7 +208,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
/* EHCI registers start at offset 0x100 */
ehci->caps = hcd->regs + 0x100;
ehci->regs = hcd->regs + 0x100 +
- HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
/* set up the PORTSCx register */
ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c
index a31a031178a8..ff55757ba7d8 100644
--- a/drivers/usb/host/ehci-octeon.c
+++ b/drivers/usb/host/ehci-octeon.c
@@ -151,7 +151,7 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev)
ehci->caps = hcd->regs;
ehci->regs = hcd->regs +
- HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 627f3a678759..55a57c23dd0f 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -208,7 +208,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
/* we know this is the memory we want, no need to ioremap again */
omap_ehci->caps = hcd->regs;
omap_ehci->regs = hcd->regs
- + HC_LENGTH(readl(&omap_ehci->caps->hc_capbase));
+ + HC_LENGTH(ehci, readl(&omap_ehci->caps->hc_capbase));
dbg_hcs_params(omap_ehci, "reset");
dbg_hcc_params(omap_ehci, "reset");
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
index 281e094e1c18..395bdb0248d5 100644
--- a/drivers/usb/host/ehci-orion.c
+++ b/drivers/usb/host/ehci-orion.c
@@ -251,7 +251,7 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
ehci = hcd_to_ehci(hcd);
ehci->caps = hcd->regs + 0x100;
ehci->regs = hcd->regs + 0x100 +
- HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
hcd->has_tt = 1;
ehci->sbrn = 0x20;
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index d5eaea7caf89..660b80a75cac 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -70,7 +70,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
ehci->caps = hcd->regs;
ehci->regs = hcd->regs +
- HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
diff --git a/drivers/usb/host/ehci-pmcmsp.c b/drivers/usb/host/ehci-pmcmsp.c
index a2168642175b..cd69099cda19 100644
--- a/drivers/usb/host/ehci-pmcmsp.c
+++ b/drivers/usb/host/ehci-pmcmsp.c
@@ -83,7 +83,7 @@ static int ehci_msp_setup(struct usb_hcd *hcd)
ehci->caps = hcd->regs;
ehci->regs = hcd->regs +
- HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
index 1f09f253697e..8552db6c29c9 100644
--- a/drivers/usb/host/ehci-ppc-of.c
+++ b/drivers/usb/host/ehci-ppc-of.c
@@ -179,7 +179,7 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op)
ehci->caps = hcd->regs;
ehci->regs = hcd->regs +
- HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index 1dee33b9139e..64626a777d61 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -29,7 +29,7 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
ehci->big_endian_mmio = 1;
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
+ ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
&ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 42abd0f603bf..5d6bc624c961 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -826,6 +826,7 @@ qh_make (
is_input, 0,
hb_mult(maxp) * max_packet(maxp)));
qh->start = NO_FRAME;
+ qh->stamp = ehci->periodic_stamp;
if (urb->dev->speed == USB_SPEED_HIGH) {
qh->c_usecs = 0;
@@ -1183,6 +1184,10 @@ static void end_unlink_async (struct ehci_hcd *ehci)
ehci->reclaim = NULL;
start_unlink_async (ehci, next);
}
+
+ if (ehci->has_synopsys_hc_bug)
+ ehci_writel(ehci, (u32) ehci->async->qh_dma,
+ &ehci->regs->async_next);
}
/* makes sure the async qh will become idle */
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
new file mode 100644
index 000000000000..e3374c8f7b3f
--- /dev/null
+++ b/drivers/usb/host/ehci-s5p.c
@@ -0,0 +1,202 @@
+/*
+ * SAMSUNG S5P USB HOST EHCI Controller
+ *
+ * Copyright (C) 2011 Samsung Electronics Co.Ltd
+ * Author: Jingoo Han <jg1.han@samsung.com>
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <mach/regs-pmu.h>
+#include <plat/cpu.h>
+#include <plat/ehci.h>
+#include <plat/usb-phy.h>
+
+struct s5p_ehci_hcd {
+ struct device *dev;
+ struct usb_hcd *hcd;
+ struct clk *clk;
+};
+
+static const struct hc_driver s5p_ehci_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "S5P EHCI Host Controller",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ .reset = ehci_init,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ .get_frame_number = ehci_get_frame,
+
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
+
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static int __devinit s5p_ehci_probe(struct platform_device *pdev)
+{
+ struct s5p_ehci_platdata *pdata;
+ struct s5p_ehci_hcd *s5p_ehci;
+ struct usb_hcd *hcd;
+ struct ehci_hcd *ehci;
+ struct resource *res;
+ int irq;
+ int err;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform data defined\n");
+ return -EINVAL;
+ }
+
+ s5p_ehci = kzalloc(sizeof(struct s5p_ehci_hcd), GFP_KERNEL);
+ if (!s5p_ehci)
+ return -ENOMEM;
+
+ s5p_ehci->dev = &pdev->dev;
+
+ 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");
+ err = -ENOMEM;
+ goto fail_hcd;
+ }
+
+ s5p_ehci->clk = clk_get(&pdev->dev, "usbhost");
+
+ if (IS_ERR(s5p_ehci->clk)) {
+ dev_err(&pdev->dev, "Failed to get usbhost clock\n");
+ err = PTR_ERR(s5p_ehci->clk);
+ goto fail_clk;
+ }
+
+ err = clk_enable(s5p_ehci->clk);
+ if (err)
+ goto fail_clken;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get I/O memory\n");
+ err = -ENXIO;
+ goto fail_io;
+ }
+
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+ hcd->regs = ioremap(res->start, resource_size(res));
+ if (!hcd->regs) {
+ dev_err(&pdev->dev, "Failed to remap I/O memory\n");
+ err = -ENOMEM;
+ goto fail_io;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "Failed to get IRQ\n");
+ err = -ENODEV;
+ goto fail;
+ }
+
+ if (pdata->phy_init)
+ pdata->phy_init(pdev, S5P_USB_PHY_HOST);
+
+ ehci = hcd_to_ehci(hcd);
+ ehci->caps = hcd->regs;
+ ehci->regs = hcd->regs +
+ HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
+
+ dbg_hcs_params(ehci, "reset");
+ dbg_hcc_params(ehci, "reset");
+
+ /* cache this readonly data; minimize chip reads */
+ ehci->hcs_params = readl(&ehci->caps->hcs_params);
+
+ err = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to add USB HCD\n");
+ goto fail;
+ }
+
+ platform_set_drvdata(pdev, s5p_ehci);
+
+ return 0;
+
+fail:
+ iounmap(hcd->regs);
+fail_io:
+ clk_disable(s5p_ehci->clk);
+fail_clken:
+ clk_put(s5p_ehci->clk);
+fail_clk:
+ usb_put_hcd(hcd);
+fail_hcd:
+ kfree(s5p_ehci);
+ return err;
+}
+
+static int __devexit s5p_ehci_remove(struct platform_device *pdev)
+{
+ struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
+ struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev);
+ struct usb_hcd *hcd = s5p_ehci->hcd;
+
+ usb_remove_hcd(hcd);
+
+ if (pdata && pdata->phy_exit)
+ pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
+
+ iounmap(hcd->regs);
+
+ clk_disable(s5p_ehci->clk);
+ clk_put(s5p_ehci->clk);
+
+ usb_put_hcd(hcd);
+ kfree(s5p_ehci);
+
+ return 0;
+}
+
+static void s5p_ehci_shutdown(struct platform_device *pdev)
+{
+ struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev);
+ struct usb_hcd *hcd = s5p_ehci->hcd;
+
+ if (hcd->driver->shutdown)
+ hcd->driver->shutdown(hcd);
+}
+
+static struct platform_driver s5p_ehci_driver = {
+ .probe = s5p_ehci_probe,
+ .remove = __devexit_p(s5p_ehci_remove),
+ .shutdown = s5p_ehci_shutdown,
+ .driver = {
+ .name = "s5p-ehci",
+ .owner = THIS_MODULE,
+ }
+};
+
+MODULE_ALIAS("platform:s5p-ehci");
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 1543c838b3d1..6c9fbe352f73 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -471,8 +471,10 @@ static int enable_periodic (struct ehci_hcd *ehci)
*/
status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
STS_PSS, 0, 9 * 125);
- if (status)
+ if (status) {
+ usb_hc_died(ehci_to_hcd(ehci));
return status;
+ }
cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
ehci_writel(ehci, cmd, &ehci->regs->command);
@@ -510,8 +512,10 @@ static int disable_periodic (struct ehci_hcd *ehci)
*/
status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
STS_PSS, STS_PSS, 9 * 125);
- if (status)
+ if (status) {
+ usb_hc_died(ehci_to_hcd(ehci));
return status;
+ }
cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
ehci_writel(ehci, cmd, &ehci->regs->command);
@@ -2287,6 +2291,7 @@ scan_periodic (struct ehci_hcd *ehci)
}
clock &= mod - 1;
clock_frame = clock >> 3;
+ ++ehci->periodic_stamp;
for (;;) {
union ehci_shadow q, *q_p;
@@ -2315,10 +2320,14 @@ restart:
temp.qh = qh_get (q.qh);
type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next);
q = q.qh->qh_next;
- modified = qh_completions (ehci, temp.qh);
- if (unlikely(list_empty(&temp.qh->qtd_list) ||
- temp.qh->needs_rescan))
- intr_deschedule (ehci, temp.qh);
+ if (temp.qh->stamp != ehci->periodic_stamp) {
+ modified = qh_completions(ehci, temp.qh);
+ if (!modified)
+ temp.qh->stamp = ehci->periodic_stamp;
+ if (unlikely(list_empty(&temp.qh->qtd_list) ||
+ temp.qh->needs_rescan))
+ intr_deschedule(ehci, temp.qh);
+ }
qh_put (temp.qh);
break;
case Q_TYPE_FSTN:
@@ -2460,6 +2469,7 @@ restart:
if (ehci->clock_frame != clock_frame) {
free_cached_lists(ehci);
ehci->clock_frame = clock_frame;
+ ++ehci->periodic_stamp;
}
} else {
now_uframe++;
diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c
index 595f70f42b52..86a95bb80a61 100644
--- a/drivers/usb/host/ehci-sh.c
+++ b/drivers/usb/host/ehci-sh.c
@@ -23,7 +23,7 @@ static int ehci_sh_reset(struct usb_hcd *hcd)
int ret;
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
+ ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
&ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c
index 75c00873443d..dbf1e4ef3c17 100644
--- a/drivers/usb/host/ehci-spear.c
+++ b/drivers/usb/host/ehci-spear.c
@@ -38,7 +38,7 @@ static int ehci_spear_setup(struct usb_hcd *hcd)
/* registers start at offset 0x0 */
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
+ ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
&ehci->caps->hc_capbase));
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index a516af28c29b..02b2bfd49a10 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -58,6 +58,71 @@ static void tegra_ehci_power_down(struct usb_hcd *hcd)
clk_disable(tegra->emc_clk);
}
+static int tegra_ehci_internal_port_reset(
+ struct ehci_hcd *ehci,
+ u32 __iomem *portsc_reg
+)
+{
+ u32 temp;
+ unsigned long flags;
+ int retval = 0;
+ int i, tries;
+ u32 saved_usbintr;
+
+ spin_lock_irqsave(&ehci->lock, flags);
+ saved_usbintr = ehci_readl(ehci, &ehci->regs->intr_enable);
+ /* disable USB interrupt */
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+ spin_unlock_irqrestore(&ehci->lock, flags);
+
+ /*
+ * Here we have to do Port Reset at most twice for
+ * Port Enable bit to be set.
+ */
+ for (i = 0; i < 2; i++) {
+ temp = ehci_readl(ehci, portsc_reg);
+ temp |= PORT_RESET;
+ ehci_writel(ehci, temp, portsc_reg);
+ mdelay(10);
+ temp &= ~PORT_RESET;
+ ehci_writel(ehci, temp, portsc_reg);
+ mdelay(1);
+ tries = 100;
+ do {
+ mdelay(1);
+ /*
+ * Up to this point, Port Enable bit is
+ * expected to be set after 2 ms waiting.
+ * USB1 usually takes extra 45 ms, for safety,
+ * we take 100 ms as timeout.
+ */
+ temp = ehci_readl(ehci, portsc_reg);
+ } while (!(temp & PORT_PE) && tries--);
+ if (temp & PORT_PE)
+ break;
+ }
+ if (i == 2)
+ retval = -ETIMEDOUT;
+
+ /*
+ * Clear Connect Status Change bit if it's set.
+ * We can't clear PORT_PEC. It will also cause PORT_PE to be cleared.
+ */
+ if (temp & PORT_CSC)
+ ehci_writel(ehci, PORT_CSC, portsc_reg);
+
+ /*
+ * Write to clear any interrupt status bits that might be set
+ * during port reset.
+ */
+ temp = ehci_readl(ehci, &ehci->regs->status);
+ ehci_writel(ehci, temp, &ehci->regs->status);
+
+ /* restore original interrupt enable bits */
+ ehci_writel(ehci, saved_usbintr, &ehci->regs->intr_enable);
+ return retval;
+}
+
static int tegra_ehci_hub_control(
struct usb_hcd *hcd,
u16 typeReq,
@@ -121,6 +186,13 @@ static int tegra_ehci_hub_control(
goto done;
}
+ /* For USB1 port we need to issue Port Reset twice internally */
+ if (tegra->phy->instance == 0 &&
+ (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_RESET)) {
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ return tegra_ehci_internal_port_reset(ehci, status_reg);
+ }
+
/*
* Tegra host controller will time the resume operation to clear the bit
* when the port control state switches to HS or FS Idle. This behavior
@@ -328,7 +400,7 @@ static int tegra_ehci_setup(struct usb_hcd *hcd)
/* EHCI registers start at offset 0x100 */
ehci->caps = hcd->regs + 0x100;
ehci->regs = hcd->regs + 0x100 +
- HC_LENGTH(readl(&ehci->caps->hc_capbase));
+ HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
diff --git a/drivers/usb/host/ehci-vt8500.c b/drivers/usb/host/ehci-vt8500.c
index 20168062035a..47d749631bc7 100644
--- a/drivers/usb/host/ehci-vt8500.c
+++ b/drivers/usb/host/ehci-vt8500.c
@@ -121,7 +121,8 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev)
ehci = hcd_to_ehci(hcd);
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+ ehci->regs = hcd->regs +
+ HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
diff --git a/drivers/usb/host/ehci-w90x900.c b/drivers/usb/host/ehci-w90x900.c
index 6bc35809a5c6..52a027aaa370 100644
--- a/drivers/usb/host/ehci-w90x900.c
+++ b/drivers/usb/host/ehci-w90x900.c
@@ -57,7 +57,7 @@ static int __devinit usb_w90x900_probe(const struct hc_driver *driver,
ehci = hcd_to_ehci(hcd);
ehci->caps = hcd->regs;
ehci->regs = hcd->regs +
- HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
/* enable PHY 0,1,the regs only apply to w90p910
* 0xA4,0xA8 were offsets of PHY0 and PHY1 controller of
diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c
index effc58d7af8b..a64d6d66d760 100644
--- a/drivers/usb/host/ehci-xilinx-of.c
+++ b/drivers/usb/host/ehci-xilinx-of.c
@@ -220,7 +220,7 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op)
*/
ehci->caps = hcd->regs + 0x100;
ehci->regs = hcd->regs + 0x100 +
- HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 333ddc156919..bd6ff489baf9 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -118,6 +118,7 @@ struct ehci_hcd { /* one per controller */
struct timer_list watchdog;
unsigned long actions;
unsigned stamp;
+ unsigned periodic_stamp;
unsigned random_frame;
unsigned long next_statechange;
ktime_t last_periodic_enable;
@@ -128,12 +129,14 @@ struct ehci_hcd { /* one per controller */
unsigned has_fsl_port_bug:1; /* FreeScale */
unsigned big_endian_mmio:1;
unsigned big_endian_desc:1;
+ unsigned big_endian_capbase:1;
unsigned has_amcc_usb23:1;
unsigned need_io_watchdog:1;
unsigned broken_periodic:1;
unsigned amd_pll_fix:1;
unsigned fs_i_thresh:1; /* Intel iso scheduling */
unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/
+ unsigned has_synopsys_hc_bug:1; /* Synopsys HC */
/* required for usb32 quirk */
#define OHCI_CTRL_HCFS (3 << 6)
@@ -160,6 +163,10 @@ struct ehci_hcd { /* one per controller */
#ifdef DEBUG
struct dentry *debug_dir;
#endif
+ /*
+ * OTG controllers and transceivers need software interaction
+ */
+ struct otg_transceiver *transceiver;
};
/* convert between an HCD pointer and the corresponding EHCI_HCD */
@@ -600,12 +607,18 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
* This attempts to support either format at compile time without a
* runtime penalty, or both formats with the additional overhead
* of checking a flag bit.
+ *
+ * ehci_big_endian_capbase is a special quirk for controllers that
+ * implement the HC capability registers as separate registers and not
+ * as fields of a 32-bit register.
*/
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
#define ehci_big_endian_mmio(e) ((e)->big_endian_mmio)
+#define ehci_big_endian_capbase(e) ((e)->big_endian_capbase)
#else
#define ehci_big_endian_mmio(e) 0
+#define ehci_big_endian_capbase(e) 0
#endif
/*
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index c0e22f26da19..baae4ccd16ac 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -612,6 +612,7 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd)
/* IRQ's are off, we do no DMA,
perfectly ready to die ... */
hcd->state = HC_STATE_HALT;
+ usb_hc_died(hcd);
ret = IRQ_HANDLED;
goto done;
}
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
index 7b2e69aa2e98..c9e6e454c625 100644
--- a/drivers/usb/host/isp1760-hcd.c
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -8,6 +8,8 @@
*
* (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
*
+ * (c) 2011 Arvid Brodin <arvid.brodin@enea.com>
+ *
*/
#include <linux/module.h>
#include <linux/kernel.h>
@@ -26,14 +28,18 @@
static struct kmem_cache *qtd_cachep;
static struct kmem_cache *qh_cachep;
+static struct kmem_cache *urb_listitem_cachep;
struct isp1760_hcd {
u32 hcs_params;
spinlock_t lock;
- struct inter_packet_info atl_ints[32];
- struct inter_packet_info int_ints[32];
+ struct slotinfo atl_slots[32];
+ int atl_done_map;
+ struct slotinfo int_slots[32];
+ int int_done_map;
struct memory_chunk memory_pool[BLOCKS];
- u32 atl_queued;
+ struct list_head controlqhs, bulkqhs, interruptqhs;
+ int active_ptds;
/* periodic schedule support */
#define DEFAULT_I_TDPS 1024
@@ -85,18 +91,34 @@ struct isp1760_qtd {
struct list_head qtd_list;
struct urb *urb;
size_t length;
-
- /* isp special*/
+ size_t actual_length;
+
+ /* QTD_ENQUEUED: waiting for transfer (inactive) */
+ /* QTD_PAYLOAD_ALLOC: chip mem has been allocated for payload */
+ /* QTD_XFER_STARTED: valid ptd has been written to isp176x - only
+ interrupt handler may touch this qtd! */
+ /* QTD_XFER_COMPLETE: payload has been transferred successfully */
+ /* QTD_RETIRE: transfer error/abort qtd */
+#define QTD_ENQUEUED 0
+#define QTD_PAYLOAD_ALLOC 1
+#define QTD_XFER_STARTED 2
+#define QTD_XFER_COMPLETE 3
+#define QTD_RETIRE 4
u32 status;
-#define URB_ENQUEUED (1 << 1)
};
+/* Queue head, one for each active endpoint */
struct isp1760_qh {
- /* first part defined by EHCI spec */
+ struct list_head qh_list;
struct list_head qtd_list;
-
u32 toggle;
u32 ping;
+ int slot;
+};
+
+struct urb_listitem {
+ struct list_head urb_list;
+ struct urb *urb;
};
/*
@@ -272,7 +294,7 @@ static void init_memory(struct isp1760_hcd *priv)
payload_addr += priv->memory_pool[curr + i].size;
}
- BUG_ON(payload_addr - priv->memory_pool[0].start > PAYLOAD_AREA_SIZE);
+ WARN_ON(payload_addr - priv->memory_pool[0].start > PAYLOAD_AREA_SIZE);
}
static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
@@ -280,7 +302,7 @@ static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
struct isp1760_hcd *priv = hcd_to_priv(hcd);
int i;
- BUG_ON(qtd->payload_addr);
+ WARN_ON(qtd->payload_addr);
if (!qtd->length)
return;
@@ -293,19 +315,6 @@ static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
return;
}
}
-
- dev_err(hcd->self.controller,
- "%s: Cannot allocate %zu bytes of memory\n"
- "Current memory map:\n",
- __func__, qtd->length);
- for (i = 0; i < BLOCKS; i++) {
- dev_err(hcd->self.controller, "Pool %2d size %4d status: %d\n",
- i, priv->memory_pool[i].size,
- priv->memory_pool[i].free);
- }
- /* XXX maybe -ENOMEM could be possible */
- BUG();
- return;
}
static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
@@ -318,7 +327,7 @@ static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
for (i = 0; i < BLOCKS; i++) {
if (priv->memory_pool[i].start == qtd->payload_addr) {
- BUG_ON(priv->memory_pool[i].free);
+ WARN_ON(priv->memory_pool[i].free);
priv->memory_pool[i].free = 1;
qtd->payload_addr = 0;
return;
@@ -327,19 +336,8 @@ static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
dev_err(hcd->self.controller, "%s: Invalid pointer: %08x\n",
__func__, qtd->payload_addr);
- BUG();
-}
-
-static void isp1760_init_regs(struct usb_hcd *hcd)
-{
- reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, 0);
- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
- reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
-
- reg_write32(hcd->regs, HC_ATL_PTD_DONEMAP_REG, ~NO_TRANSFER_ACTIVE);
- reg_write32(hcd->regs, HC_INT_PTD_DONEMAP_REG, ~NO_TRANSFER_ACTIVE);
- reg_write32(hcd->regs, HC_ISO_PTD_DONEMAP_REG, ~NO_TRANSFER_ACTIVE);
+ WARN_ON(1);
+ qtd->payload_addr = 0;
}
static int handshake(struct usb_hcd *hcd, u32 reg,
@@ -377,31 +375,27 @@ static int ehci_reset(struct usb_hcd *hcd)
return retval;
}
-static void qh_destroy(struct isp1760_qh *qh)
-{
- BUG_ON(!list_empty(&qh->qtd_list));
- kmem_cache_free(qh_cachep, qh);
-}
-
-static struct isp1760_qh *isp1760_qh_alloc(gfp_t flags)
+static struct isp1760_qh *qh_alloc(gfp_t flags)
{
struct isp1760_qh *qh;
qh = kmem_cache_zalloc(qh_cachep, flags);
if (!qh)
- return qh;
+ return NULL;
+ INIT_LIST_HEAD(&qh->qh_list);
INIT_LIST_HEAD(&qh->qtd_list);
+ qh->slot = -1;
+
return qh;
}
-/* magic numbers that can affect system performance */
-#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */
-#define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */
-#define EHCI_TUNE_RL_TT 0
-#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
-#define EHCI_TUNE_MULT_TT 1
-#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
+static void qh_free(struct isp1760_qh *qh)
+{
+ WARN_ON(!list_empty(&qh->qtd_list));
+ WARN_ON(qh->slot > -1);
+ kmem_cache_free(qh_cachep, qh);
+}
/* one-time init, only for memory state */
static int priv_init(struct usb_hcd *hcd)
@@ -411,6 +405,10 @@ static int priv_init(struct usb_hcd *hcd)
spin_lock_init(&priv->lock);
+ INIT_LIST_HEAD(&priv->interruptqhs);
+ INIT_LIST_HEAD(&priv->controlqhs);
+ INIT_LIST_HEAD(&priv->bulkqhs);
+
/*
* hw default: 1K periodic list heads, one per frame.
* periodic_size can shrink by USBCMD update if hcc_params allows.
@@ -468,7 +466,10 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
}
/* pre reset */
- isp1760_init_regs(hcd);
+ reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, 0);
+ reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
+ reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
+ reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
/* reset */
reg_write32(hcd->regs, HC_RESET_REG, SW_RESET_RESET_ALL);
@@ -488,12 +489,15 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
16 : 32, (priv->devflags & ISP1760_FLAG_ANALOG_OC) ?
"analog" : "digital");
+ /* This is weird: at the first plug-in of a device there seems to be
+ one packet queued that never gets returned? */
+ priv->active_ptds = -1;
+
/* ATL reset */
reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET);
mdelay(10);
reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
- reg_write32(hcd->regs, HC_INTERRUPT_REG, INTERRUPT_ENABLE_MASK);
reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, INTERRUPT_ENABLE_MASK);
/*
@@ -516,14 +520,21 @@ static void isp1760_init_maps(struct usb_hcd *hcd)
reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000);
reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000);
reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001);
+
+ reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff);
+ reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff);
+ reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff);
+
+ reg_write32(hcd->regs, HC_BUFFER_STATUS_REG,
+ ATL_BUF_FILL | INT_BUF_FILL);
}
static void isp1760_enable_interrupts(struct usb_hcd *hcd)
{
reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0);
- reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0);
+ reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff);
reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0);
- reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0);
+ reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff);
reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0);
reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff);
/* step 23 passed */
@@ -548,8 +559,7 @@ static int isp1760_run(struct usb_hcd *hcd)
command |= CMD_RUN;
reg_write32(hcd->regs, HC_USBCMD, command);
- retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN,
- 250 * 1000);
+ retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000);
if (retval)
return retval;
@@ -598,12 +608,19 @@ static int last_qtd_of_urb(struct isp1760_qtd *qtd, struct isp1760_qh *qh)
return (qtd->urb != urb);
}
-static void transform_into_atl(struct isp1760_qh *qh,
+/* magic numbers that can affect system performance */
+#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */
+#define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */
+#define EHCI_TUNE_RL_TT 0
+#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
+#define EHCI_TUNE_MULT_TT 1
+#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
+
+static void create_ptd_atl(struct isp1760_qh *qh,
struct isp1760_qtd *qtd, struct ptd *ptd)
{
u32 maxpacket;
u32 multi;
- u32 pid_code;
u32 rl = RL_COUNTER;
u32 nak = NAK_COUNTER;
@@ -616,67 +633,62 @@ static void transform_into_atl(struct isp1760_qh *qh,
maxpacket &= 0x7ff;
/* DW0 */
- ptd->dw0 = PTD_VALID;
- ptd->dw0 |= PTD_LENGTH(qtd->length);
- ptd->dw0 |= PTD_MAXPACKET(maxpacket);
- ptd->dw0 |= PTD_ENDPOINT(usb_pipeendpoint(qtd->urb->pipe));
+ ptd->dw0 = DW0_VALID_BIT;
+ ptd->dw0 |= TO_DW0_LENGTH(qtd->length);
+ ptd->dw0 |= TO_DW0_MAXPACKET(maxpacket);
+ ptd->dw0 |= TO_DW0_ENDPOINT(usb_pipeendpoint(qtd->urb->pipe));
/* DW1 */
ptd->dw1 = usb_pipeendpoint(qtd->urb->pipe) >> 1;
- ptd->dw1 |= PTD_DEVICE_ADDR(usb_pipedevice(qtd->urb->pipe));
-
- pid_code = qtd->packet_type;
- ptd->dw1 |= PTD_PID_TOKEN(pid_code);
+ ptd->dw1 |= TO_DW1_DEVICE_ADDR(usb_pipedevice(qtd->urb->pipe));
+ ptd->dw1 |= TO_DW1_PID_TOKEN(qtd->packet_type);
if (usb_pipebulk(qtd->urb->pipe))
- ptd->dw1 |= PTD_TRANS_BULK;
+ ptd->dw1 |= DW1_TRANS_BULK;
else if (usb_pipeint(qtd->urb->pipe))
- ptd->dw1 |= PTD_TRANS_INT;
+ ptd->dw1 |= DW1_TRANS_INT;
if (qtd->urb->dev->speed != USB_SPEED_HIGH) {
/* split transaction */
- ptd->dw1 |= PTD_TRANS_SPLIT;
+ ptd->dw1 |= DW1_TRANS_SPLIT;
if (qtd->urb->dev->speed == USB_SPEED_LOW)
- ptd->dw1 |= PTD_SE_USB_LOSPEED;
+ ptd->dw1 |= DW1_SE_USB_LOSPEED;
- ptd->dw1 |= PTD_PORT_NUM(qtd->urb->dev->ttport);
- ptd->dw1 |= PTD_HUB_NUM(qtd->urb->dev->tt->hub->devnum);
+ ptd->dw1 |= TO_DW1_PORT_NUM(qtd->urb->dev->ttport);
+ ptd->dw1 |= TO_DW1_HUB_NUM(qtd->urb->dev->tt->hub->devnum);
/* SE bit for Split INT transfers */
if (usb_pipeint(qtd->urb->pipe) &&
(qtd->urb->dev->speed == USB_SPEED_LOW))
ptd->dw1 |= 2 << 16;
- ptd->dw3 = 0;
rl = 0;
nak = 0;
} else {
- ptd->dw0 |= PTD_MULTI(multi);
+ ptd->dw0 |= TO_DW0_MULTI(multi);
if (usb_pipecontrol(qtd->urb->pipe) ||
usb_pipebulk(qtd->urb->pipe))
- ptd->dw3 = qh->ping;
- else
- ptd->dw3 = 0;
+ ptd->dw3 |= TO_DW3_PING(qh->ping);
}
/* DW2 */
ptd->dw2 = 0;
- ptd->dw2 |= PTD_DATA_START_ADDR(base_to_chip(qtd->payload_addr));
- ptd->dw2 |= PTD_RL_CNT(rl);
- ptd->dw3 |= PTD_NAC_CNT(nak);
+ ptd->dw2 |= TO_DW2_DATA_START_ADDR(base_to_chip(qtd->payload_addr));
+ ptd->dw2 |= TO_DW2_RL(rl);
/* DW3 */
- ptd->dw3 |= qh->toggle;
+ ptd->dw3 |= TO_DW3_NAKCOUNT(nak);
+ ptd->dw3 |= TO_DW3_DATA_TOGGLE(qh->toggle);
if (usb_pipecontrol(qtd->urb->pipe)) {
if (qtd->data_buffer == qtd->urb->setup_packet)
- ptd->dw3 &= ~PTD_DATA_TOGGLE(1);
+ ptd->dw3 &= ~TO_DW3_DATA_TOGGLE(1);
else if (last_qtd_of_urb(qtd, qh))
- ptd->dw3 |= PTD_DATA_TOGGLE(1);
+ ptd->dw3 |= TO_DW3_DATA_TOGGLE(1);
}
- ptd->dw3 |= PTD_ACTIVE;
+ ptd->dw3 |= DW3_ACTIVE_BIT;
/* Cerr */
- ptd->dw3 |= PTD_CERR(ERR_COUNTER);
+ ptd->dw3 |= TO_DW3_CERR(ERR_COUNTER);
}
static void transform_add_int(struct isp1760_qh *qh,
@@ -731,197 +743,13 @@ static void transform_add_int(struct isp1760_qh *qh,
ptd->dw4 = usof;
}
-static void transform_into_int(struct isp1760_qh *qh,
+static void create_ptd_int(struct isp1760_qh *qh,
struct isp1760_qtd *qtd, struct ptd *ptd)
{
- transform_into_atl(qh, qtd, ptd);
+ create_ptd_atl(qh, qtd, ptd);
transform_add_int(qh, qtd, ptd);
}
-static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len,
- u32 token)
-{
- int count;
-
- qtd->data_buffer = databuffer;
- qtd->packet_type = GET_QTD_TOKEN_TYPE(token);
-
- if (len > MAX_PAYLOAD_SIZE)
- count = MAX_PAYLOAD_SIZE;
- else
- count = len;
-
- qtd->length = count;
- return count;
-}
-
-static int check_error(struct usb_hcd *hcd, struct ptd *ptd)
-{
- int error = 0;
-
- if (ptd->dw3 & DW3_HALT_BIT) {
- error = -EPIPE;
-
- if (ptd->dw3 & DW3_ERROR_BIT)
- pr_err("error bit is set in DW3\n");
- }
-
- if (ptd->dw3 & DW3_QTD_ACTIVE) {
- dev_err(hcd->self.controller, "Transfer active bit is set DW3\n"
- "nak counter: %d, rl: %d\n",
- (ptd->dw3 >> 19) & 0xf, (ptd->dw2 >> 25) & 0xf);
- }
-
- return error;
-}
-
-static void check_int_err_status(struct usb_hcd *hcd, u32 dw4)
-{
- u32 i;
-
- dw4 >>= 8;
-
- for (i = 0; i < 8; i++) {
- switch (dw4 & 0x7) {
- case INT_UNDERRUN:
- dev_err(hcd->self.controller, "Underrun (%d)\n", i);
- break;
-
- case INT_EXACT:
- dev_err(hcd->self.controller,
- "Transaction error (%d)\n", i);
- break;
-
- case INT_BABBLE:
- dev_err(hcd->self.controller, "Babble error (%d)\n", i);
- break;
- }
- dw4 >>= 3;
- }
-}
-
-static void enqueue_one_qtd(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
-{
- if (qtd->length && (qtd->length <= MAX_PAYLOAD_SIZE)) {
- switch (qtd->packet_type) {
- case IN_PID:
- break;
- case OUT_PID:
- case SETUP_PID:
- mem_writes8(hcd->regs, qtd->payload_addr,
- qtd->data_buffer, qtd->length);
- }
- }
-}
-
-static void enqueue_one_atl_qtd(struct usb_hcd *hcd, struct isp1760_qh *qh,
- u32 slot, struct isp1760_qtd *qtd)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- struct ptd ptd;
-
- alloc_mem(hcd, qtd);
- transform_into_atl(qh, qtd, &ptd);
- ptd_write(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
- enqueue_one_qtd(hcd, qtd);
-
- priv->atl_ints[slot].qh = qh;
- priv->atl_ints[slot].qtd = qtd;
- qtd->status |= URB_ENQUEUED;
- qtd->status |= slot << 16;
-}
-
-static void enqueue_one_int_qtd(struct usb_hcd *hcd, struct isp1760_qh *qh,
- u32 slot, struct isp1760_qtd *qtd)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- struct ptd ptd;
-
- alloc_mem(hcd, qtd);
- transform_into_int(qh, qtd, &ptd);
- ptd_write(hcd->regs, INT_PTD_OFFSET, slot, &ptd);
- enqueue_one_qtd(hcd, qtd);
-
- priv->int_ints[slot].qh = qh;
- priv->int_ints[slot].qtd = qtd;
- qtd->status |= URB_ENQUEUED;
- qtd->status |= slot << 16;
-}
-
-static void enqueue_an_ATL_packet(struct usb_hcd *hcd, struct isp1760_qh *qh,
- struct isp1760_qtd *qtd)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 skip_map, or_map;
- u32 slot;
- u32 buffstatus;
-
- /*
- * When this function is called from the interrupt handler to enqueue
- * a follow-up packet, the SKIP register gets written and read back
- * almost immediately. With ISP1761, this register requires a delay of
- * 195ns between a write and subsequent read (see section 15.1.1.3).
- */
- mmiowb();
- ndelay(195);
- skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
-
- BUG_ON(!skip_map);
- slot = __ffs(skip_map);
-
- enqueue_one_atl_qtd(hcd, qh, slot, qtd);
-
- or_map = reg_read32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG);
- or_map |= (1 << slot);
- reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, or_map);
-
- skip_map &= ~(1 << slot);
- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
-
- priv->atl_queued++;
- if (priv->atl_queued == 2)
- reg_write32(hcd->regs, HC_INTERRUPT_ENABLE,
- INTERRUPT_ENABLE_SOT_MASK);
-
- buffstatus = reg_read32(hcd->regs, HC_BUFFER_STATUS_REG);
- buffstatus |= ATL_BUFFER;
- reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, buffstatus);
-}
-
-static void enqueue_an_INT_packet(struct usb_hcd *hcd, struct isp1760_qh *qh,
- struct isp1760_qtd *qtd)
-{
- u32 skip_map, or_map;
- u32 slot;
- u32 buffstatus;
-
- /*
- * When this function is called from the interrupt handler to enqueue
- * a follow-up packet, the SKIP register gets written and read back
- * almost immediately. With ISP1761, this register requires a delay of
- * 195ns between a write and subsequent read (see section 15.1.1.3).
- */
- mmiowb();
- ndelay(195);
- skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
-
- BUG_ON(!skip_map);
- slot = __ffs(skip_map);
-
- enqueue_one_int_qtd(hcd, qh, slot, qtd);
-
- or_map = reg_read32(hcd->regs, HC_INT_IRQ_MASK_OR_REG);
- or_map |= (1 << slot);
- reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, or_map);
-
- skip_map &= ~(1 << slot);
- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
-
- buffstatus = reg_read32(hcd->regs, HC_BUFFER_STATUS_REG);
- buffstatus |= INT_BUFFER;
- reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, buffstatus);
-}
-
static void isp1760_urb_done(struct usb_hcd *hcd, struct urb *urb)
__releases(priv->lock)
__acquires(priv->lock)
@@ -948,557 +776,654 @@ __acquires(priv->lock)
spin_lock(&priv->lock);
}
-static void isp1760_qtd_free(struct isp1760_qtd *qtd)
+static struct isp1760_qtd *qtd_alloc(gfp_t flags, struct urb *urb,
+ u8 packet_type)
{
- BUG_ON(qtd->payload_addr);
- kmem_cache_free(qtd_cachep, qtd);
+ struct isp1760_qtd *qtd;
+
+ qtd = kmem_cache_zalloc(qtd_cachep, flags);
+ if (!qtd)
+ return NULL;
+
+ INIT_LIST_HEAD(&qtd->qtd_list);
+ qtd->urb = urb;
+ qtd->packet_type = packet_type;
+ qtd->status = QTD_ENQUEUED;
+ qtd->actual_length = 0;
+
+ return qtd;
}
-static struct isp1760_qtd *clean_this_qtd(struct isp1760_qtd *qtd,
- struct isp1760_qh *qh)
+static void qtd_free(struct isp1760_qtd *qtd)
{
- struct isp1760_qtd *tmp_qtd;
-
- if (list_is_last(&qtd->qtd_list, &qh->qtd_list))
- tmp_qtd = NULL;
- else
- tmp_qtd = list_entry(qtd->qtd_list.next, struct isp1760_qtd,
- qtd_list);
- list_del(&qtd->qtd_list);
- isp1760_qtd_free(qtd);
- return tmp_qtd;
+ WARN_ON(qtd->payload_addr);
+ kmem_cache_free(qtd_cachep, qtd);
}
-/*
- * Remove this QTD from the QH list and free its memory. If this QTD
- * isn't the last one than remove also his successor(s).
- * Returns the QTD which is part of an new URB and should be enqueued.
- */
-static struct isp1760_qtd *clean_up_qtdlist(struct isp1760_qtd *qtd,
- struct isp1760_qh *qh)
+static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
+ struct slotinfo *slots, struct isp1760_qtd *qtd,
+ struct isp1760_qh *qh, struct ptd *ptd)
{
- struct urb *urb;
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int skip_map;
+
+ WARN_ON((slot < 0) || (slot > 31));
+ WARN_ON(qtd->length && !qtd->payload_addr);
+ WARN_ON(slots[slot].qtd);
+ WARN_ON(slots[slot].qh);
+ WARN_ON(qtd->status != QTD_PAYLOAD_ALLOC);
+
+ slots[slot].qtd = qtd;
+ slots[slot].qh = qh;
+ qh->slot = slot;
+ qtd->status = QTD_XFER_STARTED; /* Set this before writing ptd, since
+ interrupt routine may preempt and expects this value. */
+ ptd_write(hcd->regs, ptd_offset, slot, ptd);
+ priv->active_ptds++;
+
+ /* Make sure done map has not triggered from some unlinked transfer */
+ if (ptd_offset == ATL_PTD_OFFSET) {
+ priv->atl_done_map |= reg_read32(hcd->regs,
+ HC_ATL_PTD_DONEMAP_REG);
+ priv->atl_done_map &= ~(1 << qh->slot);
- urb = qtd->urb;
- do {
- qtd = clean_this_qtd(qtd, qh);
- } while (qtd && (qtd->urb == urb));
+ skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
+ skip_map &= ~(1 << qh->slot);
+ reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
+ } else {
+ priv->int_done_map |= reg_read32(hcd->regs,
+ HC_INT_PTD_DONEMAP_REG);
+ priv->int_done_map &= ~(1 << qh->slot);
- return qtd;
+ skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
+ skip_map &= ~(1 << qh->slot);
+ reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
+ }
}
-static void do_atl_int(struct usb_hcd *hcd)
+static int is_short_bulk(struct isp1760_qtd *qtd)
{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 done_map, skip_map;
- struct ptd ptd;
- struct urb *urb;
- u32 slot;
- u32 length;
- u32 or_map;
- u32 status = -EINVAL;
- int error;
- struct isp1760_qtd *qtd;
- struct isp1760_qh *qh;
- u32 rl;
- u32 nakcount;
+ return (usb_pipebulk(qtd->urb->pipe) &&
+ (qtd->actual_length < qtd->length));
+}
- done_map = reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG);
- skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
+static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
+ struct list_head *urb_list)
+{
+ int last_qtd;
+ struct isp1760_qtd *qtd, *qtd_next;
+ struct urb_listitem *urb_listitem;
- or_map = reg_read32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG);
- or_map &= ~done_map;
- reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, or_map);
+ list_for_each_entry_safe(qtd, qtd_next, &qh->qtd_list, qtd_list) {
+ if (qtd->status < QTD_XFER_COMPLETE)
+ break;
- while (done_map) {
- status = 0;
- priv->atl_queued--;
+ if (list_is_last(&qtd->qtd_list, &qh->qtd_list))
+ last_qtd = 1;
+ else
+ last_qtd = qtd->urb != qtd_next->urb;
+
+ if ((!last_qtd) && (qtd->status == QTD_RETIRE))
+ qtd_next->status = QTD_RETIRE;
+
+ if (qtd->status == QTD_XFER_COMPLETE) {
+ if (qtd->actual_length) {
+ switch (qtd->packet_type) {
+ case IN_PID:
+ mem_reads8(hcd->regs, qtd->payload_addr,
+ qtd->data_buffer,
+ qtd->actual_length);
+ /* Fall through (?) */
+ case OUT_PID:
+ qtd->urb->actual_length +=
+ qtd->actual_length;
+ /* Fall through ... */
+ case SETUP_PID:
+ break;
+ }
+ }
- slot = __ffs(done_map);
- done_map &= ~(1 << slot);
- skip_map |= (1 << slot);
+ if (is_short_bulk(qtd)) {
+ if (qtd->urb->transfer_flags & URB_SHORT_NOT_OK)
+ qtd->urb->status = -EREMOTEIO;
+ if (!last_qtd)
+ qtd_next->status = QTD_RETIRE;
+ }
+ }
- qtd = priv->atl_ints[slot].qtd;
- qh = priv->atl_ints[slot].qh;
+ if (qtd->payload_addr)
+ free_mem(hcd, qtd);
- if (!qh) {
- dev_err(hcd->self.controller, "qh is 0\n");
- continue;
+ if (last_qtd) {
+ if ((qtd->status == QTD_RETIRE) &&
+ (qtd->urb->status == -EINPROGRESS))
+ qtd->urb->status = -EPIPE;
+ /* Defer calling of urb_done() since it releases lock */
+ urb_listitem = kmem_cache_zalloc(urb_listitem_cachep,
+ GFP_ATOMIC);
+ if (unlikely(!urb_listitem))
+ break;
+ urb_listitem->urb = qtd->urb;
+ list_add_tail(&urb_listitem->urb_list, urb_list);
}
- ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
- rl = (ptd.dw2 >> 25) & 0x0f;
- nakcount = (ptd.dw3 >> 19) & 0xf;
-
- /* Transfer Error, *but* active and no HALT -> reload */
- if ((ptd.dw3 & DW3_ERROR_BIT) && (ptd.dw3 & DW3_QTD_ACTIVE) &&
- !(ptd.dw3 & DW3_HALT_BIT)) {
-
- /* according to ppriv code, we have to
- * reload this one if trasfered bytes != requested bytes
- * else act like everything went smooth..
- * XXX This just doesn't feel right and hasn't
- * triggered so far.
- */
+ list_del(&qtd->qtd_list);
+ qtd_free(qtd);
+ }
+}
- length = PTD_XFERRED_LENGTH(ptd.dw3);
- dev_err(hcd->self.controller,
- "Should reload now... transferred %d "
- "of %zu\n", length, qtd->length);
- BUG();
- }
+#define ENQUEUE_DEPTH 2
+static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int ptd_offset;
+ struct slotinfo *slots;
+ int curr_slot, free_slot;
+ int n;
+ struct ptd ptd;
+ struct isp1760_qtd *qtd;
- if (!nakcount && (ptd.dw3 & DW3_QTD_ACTIVE)) {
- u32 buffstatus;
+ if (unlikely(list_empty(&qh->qtd_list))) {
+ WARN_ON(1);
+ return;
+ }
- /*
- * NAKs are handled in HW by the chip. Usually if the
- * device is not able to send data fast enough.
- * This happens mostly on slower hardware.
- */
+ if (usb_pipeint(list_entry(qh->qtd_list.next, struct isp1760_qtd,
+ qtd_list)->urb->pipe)) {
+ ptd_offset = INT_PTD_OFFSET;
+ slots = priv->int_slots;
+ } else {
+ ptd_offset = ATL_PTD_OFFSET;
+ slots = priv->atl_slots;
+ }
- /* RL counter = ERR counter */
- ptd.dw3 &= ~(0xf << 19);
- ptd.dw3 |= rl << 19;
- ptd.dw3 &= ~(3 << (55 - 32));
- ptd.dw3 |= ERR_COUNTER << (55 - 32);
-
- /*
- * It is not needed to write skip map back because it
- * is unchanged. Just make sure that this entry is
- * unskipped once it gets written to the HW.
- */
- skip_map &= ~(1 << slot);
- or_map = reg_read32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG);
- or_map |= 1 << slot;
- reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, or_map);
+ free_slot = -1;
+ for (curr_slot = 0; curr_slot < 32; curr_slot++) {
+ if ((free_slot == -1) && (slots[curr_slot].qtd == NULL))
+ free_slot = curr_slot;
+ if (slots[curr_slot].qh == qh)
+ break;
+ }
- ptd.dw0 |= PTD_VALID;
- ptd_write(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
+ n = 0;
+ list_for_each_entry(qtd, &qh->qtd_list, qtd_list) {
+ if (qtd->status == QTD_ENQUEUED) {
+ WARN_ON(qtd->payload_addr);
+ alloc_mem(hcd, qtd);
+ if ((qtd->length) && (!qtd->payload_addr))
+ break;
- priv->atl_queued++;
- if (priv->atl_queued == 2)
- reg_write32(hcd->regs, HC_INTERRUPT_ENABLE,
- INTERRUPT_ENABLE_SOT_MASK);
+ if ((qtd->length) &&
+ ((qtd->packet_type == SETUP_PID) ||
+ (qtd->packet_type == OUT_PID))) {
+ mem_writes8(hcd->regs, qtd->payload_addr,
+ qtd->data_buffer, qtd->length);
+ }
- buffstatus = reg_read32(hcd->regs,
- HC_BUFFER_STATUS_REG);
- buffstatus |= ATL_BUFFER;
- reg_write32(hcd->regs, HC_BUFFER_STATUS_REG,
- buffstatus);
- continue;
+ qtd->status = QTD_PAYLOAD_ALLOC;
}
- error = check_error(hcd, &ptd);
- if (error) {
- status = error;
- priv->atl_ints[slot].qh->toggle = 0;
- priv->atl_ints[slot].qh->ping = 0;
- qtd->urb->status = -EPIPE;
-
-#if 0
- printk(KERN_ERR "Error in %s().\n", __func__);
- printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x "
- "dw3: %08x dw4: %08x dw5: %08x dw6: "
- "%08x dw7: %08x\n",
- ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3,
- ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7);
-#endif
- } else {
- priv->atl_ints[slot].qh->toggle = ptd.dw3 & (1 << 25);
- priv->atl_ints[slot].qh->ping = ptd.dw3 & (1 << 26);
- }
+ if (qtd->status == QTD_PAYLOAD_ALLOC) {
+/*
+ if ((curr_slot > 31) && (free_slot == -1))
+ dev_dbg(hcd->self.controller, "%s: No slot "
+ "available for transfer\n", __func__);
+*/
+ /* Start xfer for this endpoint if not already done */
+ if ((curr_slot > 31) && (free_slot > -1)) {
+ if (usb_pipeint(qtd->urb->pipe))
+ create_ptd_int(qh, qtd, &ptd);
+ else
+ create_ptd_atl(qh, qtd, &ptd);
+
+ start_bus_transfer(hcd, ptd_offset, free_slot,
+ slots, qtd, qh, &ptd);
+ curr_slot = free_slot;
+ }
- length = PTD_XFERRED_LENGTH(ptd.dw3);
- if (length) {
- switch (DW1_GET_PID(ptd.dw1)) {
- case IN_PID:
- mem_reads8(hcd->regs, qtd->payload_addr,
- qtd->data_buffer, length);
+ n++;
+ if (n >= ENQUEUE_DEPTH)
+ break;
+ }
+ }
+}
- case OUT_PID:
+void schedule_ptds(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv;
+ struct isp1760_qh *qh, *qh_next;
+ struct list_head *ep_queue;
+ struct usb_host_endpoint *ep;
+ LIST_HEAD(urb_list);
+ struct urb_listitem *urb_listitem, *urb_listitem_next;
+
+ if (!hcd) {
+ WARN_ON(1);
+ return;
+ }
- qtd->urb->actual_length += length;
+ priv = hcd_to_priv(hcd);
- case SETUP_PID:
- break;
+ /*
+ * check finished/retired xfers, transfer payloads, call urb_done()
+ */
+ ep_queue = &priv->interruptqhs;
+ while (ep_queue) {
+ list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list) {
+ ep = list_entry(qh->qtd_list.next, struct isp1760_qtd,
+ qtd_list)->urb->ep;
+ collect_qtds(hcd, qh, &urb_list);
+ if (list_empty(&qh->qtd_list)) {
+ list_del(&qh->qh_list);
+ if (ep->hcpriv == NULL) {
+ /* Endpoint has been disabled, so we
+ can free the associated queue head. */
+ qh_free(qh);
+ }
}
}
- priv->atl_ints[slot].qtd = NULL;
- priv->atl_ints[slot].qh = NULL;
-
- free_mem(hcd, qtd);
+ if (ep_queue == &priv->interruptqhs)
+ ep_queue = &priv->controlqhs;
+ else if (ep_queue == &priv->controlqhs)
+ ep_queue = &priv->bulkqhs;
+ else
+ ep_queue = NULL;
+ }
- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
+ list_for_each_entry_safe(urb_listitem, urb_listitem_next, &urb_list,
+ urb_list) {
+ isp1760_urb_done(hcd, urb_listitem->urb);
+ kmem_cache_free(urb_listitem_cachep, urb_listitem);
+ }
- if (qtd->urb->status == -EPIPE) {
- /* HALT was received */
+ /*
+ * Schedule packets for transfer.
+ *
+ * According to USB2.0 specification:
+ *
+ * 1st prio: interrupt xfers, up to 80 % of bandwidth
+ * 2nd prio: control xfers
+ * 3rd prio: bulk xfers
+ *
+ * ... but let's use a simpler scheme here (mostly because ISP1761 doc
+ * is very unclear on how to prioritize traffic):
+ *
+ * 1) Enqueue any queued control transfers, as long as payload chip mem
+ * and PTD ATL slots are available.
+ * 2) Enqueue any queued INT transfers, as long as payload chip mem
+ * and PTD INT slots are available.
+ * 3) Enqueue any queued bulk transfers, as long as payload chip mem
+ * and PTD ATL slots are available.
+ *
+ * Use double buffering (ENQUEUE_DEPTH==2) as a compromise between
+ * conservation of chip mem and performance.
+ *
+ * I'm sure this scheme could be improved upon!
+ */
+ ep_queue = &priv->controlqhs;
+ while (ep_queue) {
+ list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list)
+ enqueue_qtds(hcd, qh);
+
+ if (ep_queue == &priv->controlqhs)
+ ep_queue = &priv->interruptqhs;
+ else if (ep_queue == &priv->interruptqhs)
+ ep_queue = &priv->bulkqhs;
+ else
+ ep_queue = NULL;
+ }
+}
- urb = qtd->urb;
- qtd = clean_up_qtdlist(qtd, qh);
- isp1760_urb_done(hcd, urb);
+#define PTD_STATE_QTD_DONE 1
+#define PTD_STATE_QTD_RELOAD 2
+#define PTD_STATE_URB_RETIRE 3
- } else if (usb_pipebulk(qtd->urb->pipe) &&
- (length < qtd->length)) {
- /* short BULK received */
+static int check_int_transfer(struct usb_hcd *hcd, struct ptd *ptd,
+ struct urb *urb)
+{
+ __dw dw4;
+ int i;
- if (qtd->urb->transfer_flags & URB_SHORT_NOT_OK) {
- qtd->urb->status = -EREMOTEIO;
- dev_dbg(hcd->self.controller,
- "short bulk, %d instead %zu "
- "with URB_SHORT_NOT_OK flag.\n",
- length, qtd->length);
- }
+ dw4 = ptd->dw4;
+ dw4 >>= 8;
- if (qtd->urb->status == -EINPROGRESS)
- qtd->urb->status = 0;
+ /* FIXME: ISP1761 datasheet does not say what to do with these. Do we
+ need to handle these errors? Is it done in hardware? */
- urb = qtd->urb;
- qtd = clean_up_qtdlist(qtd, qh);
- isp1760_urb_done(hcd, urb);
+ if (ptd->dw3 & DW3_HALT_BIT) {
- } else if (last_qtd_of_urb(qtd, qh)) {
- /* that was the last qtd of that URB */
+ urb->status = -EPROTO; /* Default unknown error */
- if (qtd->urb->status == -EINPROGRESS)
- qtd->urb->status = 0;
+ for (i = 0; i < 8; i++) {
+ switch (dw4 & 0x7) {
+ case INT_UNDERRUN:
+ dev_dbg(hcd->self.controller, "%s: underrun "
+ "during uFrame %d\n",
+ __func__, i);
+ urb->status = -ECOMM; /* Could not write data */
+ break;
+ case INT_EXACT:
+ dev_dbg(hcd->self.controller, "%s: transaction "
+ "error during uFrame %d\n",
+ __func__, i);
+ urb->status = -EPROTO; /* timeout, bad CRC, PID
+ error etc. */
+ break;
+ case INT_BABBLE:
+ dev_dbg(hcd->self.controller, "%s: babble "
+ "error during uFrame %d\n",
+ __func__, i);
+ urb->status = -EOVERFLOW;
+ break;
+ }
+ dw4 >>= 3;
+ }
- urb = qtd->urb;
- qtd = clean_up_qtdlist(qtd, qh);
- isp1760_urb_done(hcd, urb);
+ return PTD_STATE_URB_RETIRE;
+ }
- } else {
- /* next QTD of this URB */
+ return PTD_STATE_QTD_DONE;
+}
- qtd = clean_this_qtd(qtd, qh);
- BUG_ON(!qtd);
- }
+static int check_atl_transfer(struct usb_hcd *hcd, struct ptd *ptd,
+ struct urb *urb)
+{
+ WARN_ON(!ptd);
+ if (ptd->dw3 & DW3_HALT_BIT) {
+ if (ptd->dw3 & DW3_BABBLE_BIT)
+ urb->status = -EOVERFLOW;
+ else if (FROM_DW3_CERR(ptd->dw3))
+ urb->status = -EPIPE; /* Stall */
+ else if (ptd->dw3 & DW3_ERROR_BIT)
+ urb->status = -EPROTO; /* XactErr */
+ else
+ urb->status = -EPROTO; /* Unknown */
+/*
+ dev_dbg(hcd->self.controller, "%s: ptd error:\n"
+ " dw0: %08x dw1: %08x dw2: %08x dw3: %08x\n"
+ " dw4: %08x dw5: %08x dw6: %08x dw7: %08x\n",
+ __func__,
+ ptd->dw0, ptd->dw1, ptd->dw2, ptd->dw3,
+ ptd->dw4, ptd->dw5, ptd->dw6, ptd->dw7);
+*/
+ return PTD_STATE_URB_RETIRE;
+ }
- if (qtd)
- enqueue_an_ATL_packet(hcd, qh, qtd);
+ if ((ptd->dw3 & DW3_ERROR_BIT) && (ptd->dw3 & DW3_ACTIVE_BIT)) {
+ /* Transfer Error, *but* active and no HALT -> reload */
+ dev_dbg(hcd->self.controller, "PID error; reloading ptd\n");
+ return PTD_STATE_QTD_RELOAD;
+ }
- skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
+ if (!FROM_DW3_NAKCOUNT(ptd->dw3) && (ptd->dw3 & DW3_ACTIVE_BIT)) {
+ /*
+ * NAKs are handled in HW by the chip. Usually if the
+ * device is not able to send data fast enough.
+ * This happens mostly on slower hardware.
+ */
+ return PTD_STATE_QTD_RELOAD;
}
- if (priv->atl_queued <= 1)
- reg_write32(hcd->regs, HC_INTERRUPT_ENABLE,
- INTERRUPT_ENABLE_MASK);
+
+ return PTD_STATE_QTD_DONE;
}
-static void do_intl_int(struct usb_hcd *hcd)
+static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 done_map, skip_map;
+ u32 imask;
+ irqreturn_t irqret = IRQ_NONE;
struct ptd ptd;
- struct urb *urb;
- u32 length;
- u32 or_map;
- int error;
- u32 slot;
- struct isp1760_qtd *qtd;
struct isp1760_qh *qh;
+ int slot;
+ int state;
+ struct slotinfo *slots;
+ u32 ptd_offset;
+ struct isp1760_qtd *qtd;
+ int modified;
+ static int last_active_ptds;
+ int int_skip_map, atl_skip_map;
- done_map = reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG);
- skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
-
- or_map = reg_read32(hcd->regs, HC_INT_IRQ_MASK_OR_REG);
- or_map &= ~done_map;
- reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, or_map);
-
- while (done_map) {
- slot = __ffs(done_map);
- done_map &= ~(1 << slot);
- skip_map |= (1 << slot);
-
- qtd = priv->int_ints[slot].qtd;
- qh = priv->int_ints[slot].qh;
-
- if (!qh) {
- dev_err(hcd->self.controller, "(INT) qh is 0\n");
- continue;
- }
+ spin_lock(&priv->lock);
- ptd_read(hcd->regs, INT_PTD_OFFSET, slot, &ptd);
- check_int_err_status(hcd, ptd.dw4);
-
- error = check_error(hcd, &ptd);
- if (error) {
-#if 0
- printk(KERN_ERR "Error in %s().\n", __func__);
- printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x "
- "dw3: %08x dw4: %08x dw5: %08x dw6: "
- "%08x dw7: %08x\n",
- ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3,
- ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7);
-#endif
- qtd->urb->status = -EPIPE;
- priv->int_ints[slot].qh->toggle = 0;
- priv->int_ints[slot].qh->ping = 0;
+ if (!(hcd->state & HC_STATE_RUNNING))
+ goto leave;
+ imask = reg_read32(hcd->regs, HC_INTERRUPT_REG);
+ if (unlikely(!imask))
+ goto leave;
+ reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */
+
+ int_skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
+ atl_skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
+ priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG);
+ priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG);
+ priv->int_done_map &= ~int_skip_map;
+ priv->atl_done_map &= ~atl_skip_map;
+
+ modified = priv->int_done_map | priv->atl_done_map;
+
+ while (priv->int_done_map || priv->atl_done_map) {
+ if (priv->int_done_map) {
+ /* INT ptd */
+ slot = __ffs(priv->int_done_map);
+ priv->int_done_map &= ~(1 << slot);
+ slots = priv->int_slots;
+ /* This should not trigger, and could be removed if
+ noone have any problems with it triggering: */
+ if (!slots[slot].qh) {
+ WARN_ON(1);
+ continue;
+ }
+ ptd_offset = INT_PTD_OFFSET;
+ ptd_read(hcd->regs, INT_PTD_OFFSET, slot, &ptd);
+ state = check_int_transfer(hcd, &ptd,
+ slots[slot].qtd->urb);
} else {
- priv->int_ints[slot].qh->toggle = ptd.dw3 & (1 << 25);
- priv->int_ints[slot].qh->ping = ptd.dw3 & (1 << 26);
- }
-
- if (qtd->urb->dev->speed != USB_SPEED_HIGH)
- length = PTD_XFERRED_LENGTH_LO(ptd.dw3);
- else
- length = PTD_XFERRED_LENGTH(ptd.dw3);
-
- if (length) {
- switch (DW1_GET_PID(ptd.dw1)) {
- case IN_PID:
- mem_reads8(hcd->regs, qtd->payload_addr,
- qtd->data_buffer, length);
- case OUT_PID:
-
- qtd->urb->actual_length += length;
-
- case SETUP_PID:
- break;
+ /* ATL ptd */
+ slot = __ffs(priv->atl_done_map);
+ priv->atl_done_map &= ~(1 << slot);
+ slots = priv->atl_slots;
+ /* This should not trigger, and could be removed if
+ noone have any problems with it triggering: */
+ if (!slots[slot].qh) {
+ WARN_ON(1);
+ continue;
}
+ ptd_offset = ATL_PTD_OFFSET;
+ ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
+ state = check_atl_transfer(hcd, &ptd,
+ slots[slot].qtd->urb);
}
- priv->int_ints[slot].qtd = NULL;
- priv->int_ints[slot].qh = NULL;
-
- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
- free_mem(hcd, qtd);
-
- if (qtd->urb->status == -EPIPE) {
- /* HALT received */
-
- urb = qtd->urb;
- qtd = clean_up_qtdlist(qtd, qh);
- isp1760_urb_done(hcd, urb);
-
- } else if (last_qtd_of_urb(qtd, qh)) {
-
- if (qtd->urb->status == -EINPROGRESS)
- qtd->urb->status = 0;
+ qtd = slots[slot].qtd;
+ slots[slot].qtd = NULL;
+ qh = slots[slot].qh;
+ slots[slot].qh = NULL;
+ priv->active_ptds--;
+ qh->slot = -1;
+
+ WARN_ON(qtd->status != QTD_XFER_STARTED);
+
+ switch (state) {
+ case PTD_STATE_QTD_DONE:
+ if ((usb_pipeint(qtd->urb->pipe)) &&
+ (qtd->urb->dev->speed != USB_SPEED_HIGH))
+ qtd->actual_length =
+ FROM_DW3_SCS_NRBYTESTRANSFERRED(ptd.dw3);
+ else
+ qtd->actual_length =
+ FROM_DW3_NRBYTESTRANSFERRED(ptd.dw3);
+
+ qtd->status = QTD_XFER_COMPLETE;
+ if (list_is_last(&qtd->qtd_list, &qh->qtd_list) ||
+ is_short_bulk(qtd))
+ qtd = NULL;
+ else
+ qtd = list_entry(qtd->qtd_list.next,
+ typeof(*qtd), qtd_list);
+
+ qh->toggle = FROM_DW3_DATA_TOGGLE(ptd.dw3);
+ qh->ping = FROM_DW3_PING(ptd.dw3);
+ break;
- urb = qtd->urb;
- qtd = clean_up_qtdlist(qtd, qh);
- isp1760_urb_done(hcd, urb);
+ case PTD_STATE_QTD_RELOAD: /* QTD_RETRY, for atls only */
+ qtd->status = QTD_PAYLOAD_ALLOC;
+ ptd.dw0 |= DW0_VALID_BIT;
+ /* RL counter = ERR counter */
+ ptd.dw3 &= ~TO_DW3_NAKCOUNT(0xf);
+ ptd.dw3 |= TO_DW3_NAKCOUNT(FROM_DW2_RL(ptd.dw2));
+ ptd.dw3 &= ~TO_DW3_CERR(3);
+ ptd.dw3 |= TO_DW3_CERR(ERR_COUNTER);
+ qh->toggle = FROM_DW3_DATA_TOGGLE(ptd.dw3);
+ qh->ping = FROM_DW3_PING(ptd.dw3);
+ break;
- } else {
- /* next QTD of this URB */
+ case PTD_STATE_URB_RETIRE:
+ qtd->status = QTD_RETIRE;
+ qtd = NULL;
+ qh->toggle = 0;
+ qh->ping = 0;
+ break;
- qtd = clean_this_qtd(qtd, qh);
- BUG_ON(!qtd);
+ default:
+ WARN_ON(1);
+ continue;
}
- if (qtd)
- enqueue_an_INT_packet(hcd, qh, qtd);
+ if (qtd && (qtd->status == QTD_PAYLOAD_ALLOC)) {
+ if (slots == priv->int_slots) {
+ if (state == PTD_STATE_QTD_RELOAD)
+ dev_err(hcd->self.controller,
+ "%s: PTD_STATE_QTD_RELOAD on "
+ "interrupt packet\n", __func__);
+ if (state != PTD_STATE_QTD_RELOAD)
+ create_ptd_int(qh, qtd, &ptd);
+ } else {
+ if (state != PTD_STATE_QTD_RELOAD)
+ create_ptd_atl(qh, qtd, &ptd);
+ }
- skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
+ start_bus_transfer(hcd, ptd_offset, slot, slots, qtd,
+ qh, &ptd);
+ }
}
-}
-static struct isp1760_qh *qh_make(struct usb_hcd *hcd, struct urb *urb,
- gfp_t flags)
-{
- struct isp1760_qh *qh;
- int is_input, type;
+ if (modified)
+ schedule_ptds(hcd);
- qh = isp1760_qh_alloc(flags);
- if (!qh)
- return qh;
-
- /*
- * init endpoint/device data for this QH
- */
- is_input = usb_pipein(urb->pipe);
- type = usb_pipetype(urb->pipe);
+ /* ISP1760 Errata 2 explains that interrupts may be missed (or not
+ happen?) if two USB devices are running simultaneously. Perhaps
+ this happens when a PTD is finished during interrupt handling;
+ enable SOF interrupts if PTDs are still scheduled when exiting this
+ interrupt handler, just to be safe. */
- if (!usb_pipecontrol(urb->pipe))
- usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input,
- 1);
- return qh;
-}
-
-/*
- * For control/bulk/interrupt, return QH with these TDs appended.
- * Allocates and initializes the QH if necessary.
- * Returns null if it can't allocate a QH it needs to.
- * If the QH has TDs (urbs) already, that's great.
- */
-static struct isp1760_qh *qh_append_tds(struct usb_hcd *hcd,
- struct urb *urb, struct list_head *qtd_list, int epnum,
- void **ptr)
-{
- struct isp1760_qh *qh;
-
- qh = (struct isp1760_qh *)*ptr;
- if (!qh) {
- /* can't sleep here, we have priv->lock... */
- qh = qh_make(hcd, urb, GFP_ATOMIC);
- if (!qh)
- return qh;
- *ptr = qh;
+ if (priv->active_ptds != last_active_ptds) {
+ if (priv->active_ptds > 0)
+ reg_write32(hcd->regs, HC_INTERRUPT_ENABLE,
+ INTERRUPT_ENABLE_SOT_MASK);
+ else
+ reg_write32(hcd->regs, HC_INTERRUPT_ENABLE,
+ INTERRUPT_ENABLE_MASK);
+ last_active_ptds = priv->active_ptds;
}
- list_splice(qtd_list, qh->qtd_list.prev);
+ irqret = IRQ_HANDLED;
+leave:
+ spin_unlock(&priv->lock);
- return qh;
+ return irqret;
}
-static void qtd_list_free(struct urb *urb, struct list_head *qtd_list)
+static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len)
{
- struct list_head *entry, *temp;
+ qtd->data_buffer = databuffer;
- list_for_each_safe(entry, temp, qtd_list) {
- struct isp1760_qtd *qtd;
+ if (len > MAX_PAYLOAD_SIZE)
+ len = MAX_PAYLOAD_SIZE;
+ qtd->length = len;
- qtd = list_entry(entry, struct isp1760_qtd, qtd_list);
- list_del(&qtd->qtd_list);
- isp1760_qtd_free(qtd);
- }
+ return qtd->length;
}
-static int isp1760_prepare_enqueue(struct usb_hcd *hcd, struct urb *urb,
- struct list_head *qtd_list, gfp_t mem_flags, packet_enqueue *p)
+static void qtd_list_free(struct list_head *qtd_list)
{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- struct isp1760_qtd *qtd;
- int epnum;
- unsigned long flags;
- struct isp1760_qh *qh = NULL;
- int rc;
- int qh_busy;
-
- qtd = list_entry(qtd_list->next, struct isp1760_qtd, qtd_list);
- epnum = urb->ep->desc.bEndpointAddress;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (!HCD_HW_ACCESSIBLE(hcd)) {
- rc = -ESHUTDOWN;
- goto done;
- }
- rc = usb_hcd_link_urb_to_ep(hcd, urb);
- if (rc)
- goto done;
-
- qh = urb->ep->hcpriv;
- if (qh)
- qh_busy = !list_empty(&qh->qtd_list);
- else
- qh_busy = 0;
+ struct isp1760_qtd *qtd, *qtd_next;
- qh = qh_append_tds(hcd, urb, qtd_list, epnum, &urb->ep->hcpriv);
- if (!qh) {
- usb_hcd_unlink_urb_from_ep(hcd, urb);
- rc = -ENOMEM;
- goto done;
+ list_for_each_entry_safe(qtd, qtd_next, qtd_list, qtd_list) {
+ list_del(&qtd->qtd_list);
+ qtd_free(qtd);
}
-
- if (!qh_busy)
- p(hcd, qh, qtd);
-
-done:
- spin_unlock_irqrestore(&priv->lock, flags);
- if (!qh)
- qtd_list_free(urb, qtd_list);
- return rc;
-}
-
-static struct isp1760_qtd *isp1760_qtd_alloc(gfp_t flags)
-{
- struct isp1760_qtd *qtd;
-
- qtd = kmem_cache_zalloc(qtd_cachep, flags);
- if (qtd)
- INIT_LIST_HEAD(&qtd->qtd_list);
-
- return qtd;
}
/*
- * create a list of filled qtds for this URB; won't link into qh.
+ * Packetize urb->transfer_buffer into list of packets of size wMaxPacketSize.
+ * Also calculate the PID type (SETUP/IN/OUT) for each packet.
*/
#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
-static struct list_head *qh_urb_transaction(struct usb_hcd *hcd,
+static void packetize_urb(struct usb_hcd *hcd,
struct urb *urb, struct list_head *head, gfp_t flags)
{
struct isp1760_qtd *qtd;
void *buf;
- int len, maxpacket;
- int is_input;
- u32 token;
+ int len, maxpacketsize;
+ u8 packet_type;
/*
* URBs map to sequences of QTDs: one logical transaction
*/
- qtd = isp1760_qtd_alloc(flags);
- if (!qtd)
- return NULL;
- list_add_tail(&qtd->qtd_list, head);
- qtd->urb = urb;
- urb->status = -EINPROGRESS;
+ if (!urb->transfer_buffer && urb->transfer_buffer_length) {
+ /* XXX This looks like usb storage / SCSI bug */
+ dev_err(hcd->self.controller,
+ "buf is null, dma is %08lx len is %d\n",
+ (long unsigned)urb->transfer_dma,
+ urb->transfer_buffer_length);
+ WARN_ON(1);
+ }
- token = 0;
- /* for split transactions, SplitXState initialized to zero */
+ if (usb_pipein(urb->pipe))
+ packet_type = IN_PID;
+ else
+ packet_type = OUT_PID;
- len = urb->transfer_buffer_length;
- is_input = usb_pipein(urb->pipe);
if (usb_pipecontrol(urb->pipe)) {
- /* SETUP pid */
- qtd_fill(qtd, urb->setup_packet,
- sizeof(struct usb_ctrlrequest),
- token | SETUP_PID);
-
- /* ... and always at least one more pid */
- qtd = isp1760_qtd_alloc(flags);
+ qtd = qtd_alloc(flags, urb, SETUP_PID);
if (!qtd)
goto cleanup;
- qtd->urb = urb;
+ qtd_fill(qtd, urb->setup_packet, sizeof(struct usb_ctrlrequest));
list_add_tail(&qtd->qtd_list, head);
/* for zero length DATA stages, STATUS is always IN */
- if (len == 0)
- token |= IN_PID;
+ if (urb->transfer_buffer_length == 0)
+ packet_type = IN_PID;
}
- /*
- * data transfer stage: buffer setup
- */
- buf = urb->transfer_buffer;
-
- if (is_input)
- token |= IN_PID;
- else
- token |= OUT_PID;
-
- maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input));
+ maxpacketsize = max_packet(usb_maxpacket(urb->dev, urb->pipe,
+ usb_pipeout(urb->pipe)));
/*
* buffer gets wrapped in one or more qtds;
* last one may be "short" (including zero len)
* and may serve as a control status ack
*/
+ buf = urb->transfer_buffer;
+ len = urb->transfer_buffer_length;
+
for (;;) {
int this_qtd_len;
- if (!buf && len) {
- /* XXX This looks like usb storage / SCSI bug */
- dev_err(hcd->self.controller, "buf is null, dma is %08lx len is %d\n",
- (long unsigned)urb->transfer_dma, len);
- WARN_ON(1);
- }
+ qtd = qtd_alloc(flags, urb, packet_type);
+ if (!qtd)
+ goto cleanup;
+ this_qtd_len = qtd_fill(qtd, buf, len);
+ list_add_tail(&qtd->qtd_list, head);
- this_qtd_len = qtd_fill(qtd, buf, len, token);
len -= this_qtd_len;
buf += this_qtd_len;
if (len <= 0)
break;
-
- qtd = isp1760_qtd_alloc(flags);
- if (!qtd)
- goto cleanup;
- qtd->urb = urb;
- list_add_tail(&qtd->qtd_list, head);
}
/*
@@ -1510,184 +1435,204 @@ static struct list_head *qh_urb_transaction(struct usb_hcd *hcd,
if (usb_pipecontrol(urb->pipe)) {
one_more = 1;
- /* "in" <--> "out" */
- token ^= IN_PID;
+ if (packet_type == IN_PID)
+ packet_type = OUT_PID;
+ else
+ packet_type = IN_PID;
} else if (usb_pipebulk(urb->pipe)
&& (urb->transfer_flags & URB_ZERO_PACKET)
- && !(urb->transfer_buffer_length % maxpacket)) {
+ && !(urb->transfer_buffer_length %
+ maxpacketsize)) {
one_more = 1;
}
if (one_more) {
- qtd = isp1760_qtd_alloc(flags);
+ qtd = qtd_alloc(flags, urb, packet_type);
if (!qtd)
goto cleanup;
- qtd->urb = urb;
- list_add_tail(&qtd->qtd_list, head);
/* never any data in such packets */
- qtd_fill(qtd, NULL, 0, token);
+ qtd_fill(qtd, NULL, 0);
+ list_add_tail(&qtd->qtd_list, head);
}
}
- qtd->status = 0;
- return head;
+ return;
cleanup:
- qtd_list_free(urb, head);
- return NULL;
+ qtd_list_free(head);
}
static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
gfp_t mem_flags)
{
- struct list_head qtd_list;
- packet_enqueue *pe;
-
- INIT_LIST_HEAD(&qtd_list);
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ struct list_head *ep_queue;
+ struct isp1760_qh *qh, *qhit;
+ unsigned long spinflags;
+ LIST_HEAD(new_qtds);
+ int retval;
+ int qh_in_queue;
switch (usb_pipetype(urb->pipe)) {
case PIPE_CONTROL:
+ ep_queue = &priv->controlqhs;
+ break;
case PIPE_BULK:
- if (!qh_urb_transaction(hcd, urb, &qtd_list, mem_flags))
- return -ENOMEM;
- pe = enqueue_an_ATL_packet;
+ ep_queue = &priv->bulkqhs;
break;
-
case PIPE_INTERRUPT:
- if (!qh_urb_transaction(hcd, urb, &qtd_list, mem_flags))
- return -ENOMEM;
- pe = enqueue_an_INT_packet;
+ if (urb->interval < 0)
+ return -EINVAL;
+ /* FIXME: Check bandwidth */
+ ep_queue = &priv->interruptqhs;
break;
-
case PIPE_ISOCHRONOUS:
- dev_err(hcd->self.controller, "PIPE_ISOCHRONOUS ain't supported\n");
+ dev_err(hcd->self.controller, "%s: isochronous USB packets "
+ "not yet supported\n",
+ __func__);
+ return -EPIPE;
default:
+ dev_err(hcd->self.controller, "%s: unknown pipe type\n",
+ __func__);
return -EPIPE;
}
- return isp1760_prepare_enqueue(hcd, urb, &qtd_list, mem_flags, pe);
-}
-
-static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- struct inter_packet_info *ints;
- u32 i;
- u32 reg_base, or_reg, skip_reg;
- unsigned long flags;
- struct ptd ptd;
- packet_enqueue *pe;
+ if (usb_pipein(urb->pipe))
+ urb->actual_length = 0;
- switch (usb_pipetype(urb->pipe)) {
- case PIPE_ISOCHRONOUS:
- return -EPIPE;
- break;
+ packetize_urb(hcd, urb, &new_qtds, mem_flags);
+ if (list_empty(&new_qtds))
+ return -ENOMEM;
+ urb->hcpriv = NULL; /* Used to signal unlink to interrupt handler */
- case PIPE_INTERRUPT:
- ints = priv->int_ints;
- reg_base = INT_PTD_OFFSET;
- or_reg = HC_INT_IRQ_MASK_OR_REG;
- skip_reg = HC_INT_PTD_SKIPMAP_REG;
- pe = enqueue_an_INT_packet;
- break;
+ retval = 0;
+ spin_lock_irqsave(&priv->lock, spinflags);
- default:
- ints = priv->atl_ints;
- reg_base = ATL_PTD_OFFSET;
- or_reg = HC_ATL_IRQ_MASK_OR_REG;
- skip_reg = HC_ATL_PTD_SKIPMAP_REG;
- pe = enqueue_an_ATL_packet;
- break;
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+ retval = -ESHUTDOWN;
+ goto out;
}
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval)
+ goto out;
- memset(&ptd, 0, sizeof(ptd));
- spin_lock_irqsave(&priv->lock, flags);
-
- for (i = 0; i < 32; i++) {
- if (!ints[i].qh)
- continue;
- BUG_ON(!ints[i].qtd);
+ qh = urb->ep->hcpriv;
+ if (qh) {
+ qh_in_queue = 0;
+ list_for_each_entry(qhit, ep_queue, qh_list) {
+ if (qhit == qh) {
+ qh_in_queue = 1;
+ break;
+ }
+ }
+ if (!qh_in_queue)
+ list_add_tail(&qh->qh_list, ep_queue);
+ } else {
+ qh = qh_alloc(GFP_ATOMIC);
+ if (!qh) {
+ retval = -ENOMEM;
+ goto out;
+ }
+ list_add_tail(&qh->qh_list, ep_queue);
+ urb->ep->hcpriv = qh;
+ }
- if (ints[i].qtd->urb == urb) {
- u32 skip_map;
- u32 or_map;
- struct isp1760_qtd *qtd;
- struct isp1760_qh *qh;
+ list_splice_tail(&new_qtds, &qh->qtd_list);
+ schedule_ptds(hcd);
- skip_map = reg_read32(hcd->regs, skip_reg);
- skip_map |= 1 << i;
- reg_write32(hcd->regs, skip_reg, skip_map);
+out:
+ spin_unlock_irqrestore(&priv->lock, spinflags);
+ return retval;
+}
- or_map = reg_read32(hcd->regs, or_reg);
- or_map &= ~(1 << i);
- reg_write32(hcd->regs, or_reg, or_map);
+static void kill_transfer(struct usb_hcd *hcd, struct urb *urb,
+ struct isp1760_qh *qh)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int skip_map;
- ptd_write(hcd->regs, reg_base, i, &ptd);
+ WARN_ON(qh->slot == -1);
- qtd = ints[i].qtd;
- qh = ints[i].qh;
+ /* We need to forcefully reclaim the slot since some transfers never
+ return, e.g. interrupt transfers and NAKed bulk transfers. */
+ if (usb_pipebulk(urb->pipe)) {
+ skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
+ skip_map |= (1 << qh->slot);
+ reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
+ priv->atl_slots[qh->slot].qh = NULL;
+ priv->atl_slots[qh->slot].qtd = NULL;
+ } else {
+ skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
+ skip_map |= (1 << qh->slot);
+ reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
+ priv->int_slots[qh->slot].qh = NULL;
+ priv->int_slots[qh->slot].qtd = NULL;
+ }
- free_mem(hcd, qtd);
- qtd = clean_up_qtdlist(qtd, qh);
+ qh->slot = -1;
+ priv->active_ptds--;
+}
- ints[i].qh = NULL;
- ints[i].qtd = NULL;
+static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+ int status)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ unsigned long spinflags;
+ struct isp1760_qh *qh;
+ struct isp1760_qtd *qtd;
+ int retval = 0;
- urb->status = status;
- isp1760_urb_done(hcd, urb);
- if (qtd)
- pe(hcd, qh, qtd);
- break;
+ spin_lock_irqsave(&priv->lock, spinflags);
- } else {
- struct isp1760_qtd *qtd;
-
- list_for_each_entry(qtd, &ints[i].qtd->qtd_list,
- qtd_list) {
- if (qtd->urb == urb) {
- clean_up_qtdlist(qtd, ints[i].qh);
- isp1760_urb_done(hcd, urb);
- qtd = NULL;
- break;
- }
- }
+ qh = urb->ep->hcpriv;
+ if (!qh) {
+ retval = -EINVAL;
+ goto out;
+ }
- /* We found the urb before the last slot */
- if (!qtd)
- break;
+ list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
+ if (qtd->urb == urb) {
+ if (qtd->status == QTD_XFER_STARTED)
+ kill_transfer(hcd, urb, qh);
+ qtd->status = QTD_RETIRE;
}
- }
- spin_unlock_irqrestore(&priv->lock, flags);
- return 0;
+ urb->status = status;
+ schedule_ptds(hcd);
+
+out:
+ spin_unlock_irqrestore(&priv->lock, spinflags);
+ return retval;
}
-static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
+static void isp1760_endpoint_disable(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 imask;
- irqreturn_t irqret = IRQ_NONE;
+ unsigned long spinflags;
+ struct isp1760_qh *qh;
+ struct isp1760_qtd *qtd;
- spin_lock(&priv->lock);
+ spin_lock_irqsave(&priv->lock, spinflags);
- if (!(hcd->state & HC_STATE_RUNNING))
- goto leave;
+ qh = ep->hcpriv;
+ if (!qh)
+ goto out;
- imask = reg_read32(hcd->regs, HC_INTERRUPT_REG);
- if (unlikely(!imask))
- goto leave;
+ list_for_each_entry(qtd, &qh->qtd_list, qtd_list) {
+ if (qtd->status == QTD_XFER_STARTED)
+ kill_transfer(hcd, qtd->urb, qh);
+ qtd->status = QTD_RETIRE;
+ qtd->urb->status = -ECONNRESET;
+ }
- reg_write32(hcd->regs, HC_INTERRUPT_REG, imask);
- if (imask & (HC_ATL_INT | HC_SOT_INT))
- do_atl_int(hcd);
+ ep->hcpriv = NULL;
+ /* Cannot free qh here since it will be parsed by schedule_ptds() */
- if (imask & HC_INTL_INT)
- do_intl_int(hcd);
+ schedule_ptds(hcd);
- irqret = IRQ_HANDLED;
-leave:
- spin_unlock(&priv->lock);
- return irqret;
+out:
+ spin_unlock_irqrestore(&priv->lock, spinflags);
}
static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
@@ -1778,7 +1723,7 @@ static int check_reset_complete(struct usb_hcd *hcd, int index,
/* if reset finished and it's still not enabled -- handoff */
if (!(port_status & PORT_PE)) {
- dev_err(hcd->self.controller,
+ dev_info(hcd->self.controller,
"port %d full speed --> companion\n",
index + 1);
@@ -1787,7 +1732,7 @@ static int check_reset_complete(struct usb_hcd *hcd, int index,
reg_write32(hcd->regs, HC_PORTSC1, port_status);
} else
- dev_err(hcd->self.controller, "port %d high speed\n",
+ dev_info(hcd->self.controller, "port %d high speed\n",
index + 1);
return port_status;
@@ -2059,51 +2004,6 @@ error:
return retval;
}
-static void isp1760_endpoint_disable(struct usb_hcd *hcd,
- struct usb_host_endpoint *ep)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- struct isp1760_qh *qh;
- struct isp1760_qtd *qtd;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- qh = ep->hcpriv;
- if (!qh)
- goto out;
-
- ep->hcpriv = NULL;
- do {
- /* more than entry might get removed */
- if (list_empty(&qh->qtd_list))
- break;
-
- qtd = list_first_entry(&qh->qtd_list, struct isp1760_qtd,
- qtd_list);
-
- if (qtd->status & URB_ENQUEUED) {
- spin_unlock_irqrestore(&priv->lock, flags);
- isp1760_urb_dequeue(hcd, qtd->urb, -ECONNRESET);
- spin_lock_irqsave(&priv->lock, flags);
- } else {
- struct urb *urb;
-
- urb = qtd->urb;
- clean_up_qtdlist(qtd, qh);
- urb->status = -ECONNRESET;
- isp1760_urb_done(hcd, urb);
- }
- } while (1);
-
- qh_destroy(qh);
- /* remove requests and leak them.
- * ATL are pretty fast done, INT could take a while...
- * The latter shoule be removed
- */
-out:
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
static int isp1760_get_frame(struct usb_hcd *hcd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
@@ -2165,6 +2065,13 @@ static const struct hc_driver isp1760_hc_driver = {
int __init init_kmem_once(void)
{
+ urb_listitem_cachep = kmem_cache_create("isp1760 urb_listitem",
+ sizeof(struct urb_listitem), 0, SLAB_TEMPORARY |
+ SLAB_MEM_SPREAD, NULL);
+
+ if (!urb_listitem_cachep)
+ return -ENOMEM;
+
qtd_cachep = kmem_cache_create("isp1760_qtd",
sizeof(struct isp1760_qtd), 0, SLAB_TEMPORARY |
SLAB_MEM_SPREAD, NULL);
@@ -2187,6 +2094,7 @@ void deinit_kmem_cache(void)
{
kmem_cache_destroy(qtd_cachep);
kmem_cache_destroy(qh_cachep);
+ kmem_cache_destroy(urb_listitem_cachep);
}
struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
diff --git a/drivers/usb/host/isp1760-hcd.h b/drivers/usb/host/isp1760-hcd.h
index 870507690607..014a7dfadf91 100644
--- a/drivers/usb/host/isp1760-hcd.h
+++ b/drivers/usb/host/isp1760-hcd.h
@@ -49,10 +49,9 @@ void deinit_kmem_cache(void);
#define SW_RESET_RESET_ALL (1 << 0)
#define HC_BUFFER_STATUS_REG 0x334
-#define ATL_BUFFER 0x1
-#define INT_BUFFER 0x2
-#define ISO_BUFFER 0x4
-#define BUFFER_MAP 0x7
+#define ISO_BUF_FILL (1 << 2)
+#define INT_BUF_FILL (1 << 1)
+#define ATL_BUF_FILL (1 << 0)
#define HC_MEMORY_REG 0x33c
#define ISP_BANK(x) ((x) << 16)
@@ -68,14 +67,13 @@ void deinit_kmem_cache(void);
#define HC_INTERRUPT_REG 0x310
#define HC_INTERRUPT_ENABLE 0x314
-#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT | HC_EOT_INT)
-#define INTERRUPT_ENABLE_SOT_MASK (HC_INTL_INT | HC_SOT_INT | HC_EOT_INT)
-
#define HC_ISO_INT (1 << 9)
#define HC_ATL_INT (1 << 8)
#define HC_INTL_INT (1 << 7)
#define HC_EOT_INT (1 << 3)
#define HC_SOT_INT (1 << 1)
+#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT)
+#define INTERRUPT_ENABLE_SOT_MASK (HC_SOT_INT)
#define HC_ISO_IRQ_MASK_OR_REG 0x318
#define HC_INT_IRQ_MASK_OR_REG 0x31C
@@ -106,7 +104,7 @@ struct ptd {
#define ATL_PTD_OFFSET 0x0c00
#define PAYLOAD_OFFSET 0x1000
-struct inter_packet_info {
+struct slotinfo {
struct isp1760_qh *qh;
struct isp1760_qtd *qtd;
};
@@ -156,54 +154,52 @@ struct memory_chunk {
/* ATL */
/* DW0 */
-#define PTD_VALID 1
-#define PTD_LENGTH(x) (((u32) x) << 3)
-#define PTD_MAXPACKET(x) (((u32) x) << 18)
-#define PTD_MULTI(x) (((u32) x) << 29)
-#define PTD_ENDPOINT(x) (((u32) x) << 31)
+#define DW0_VALID_BIT 1
+#define FROM_DW0_VALID(x) ((x) & 0x01)
+#define TO_DW0_LENGTH(x) (((u32) x) << 3)
+#define TO_DW0_MAXPACKET(x) (((u32) x) << 18)
+#define TO_DW0_MULTI(x) (((u32) x) << 29)
+#define TO_DW0_ENDPOINT(x) (((u32) x) << 31)
/* DW1 */
-#define PTD_DEVICE_ADDR(x) (((u32) x) << 3)
-#define PTD_PID_TOKEN(x) (((u32) x) << 10)
-#define PTD_TRANS_BULK ((u32) 2 << 12)
-#define PTD_TRANS_INT ((u32) 3 << 12)
-#define PTD_TRANS_SPLIT ((u32) 1 << 14)
-#define PTD_SE_USB_LOSPEED ((u32) 2 << 16)
-#define PTD_PORT_NUM(x) (((u32) x) << 18)
-#define PTD_HUB_NUM(x) (((u32) x) << 25)
-#define PTD_PING(x) (((u32) x) << 26)
+#define TO_DW1_DEVICE_ADDR(x) (((u32) x) << 3)
+#define TO_DW1_PID_TOKEN(x) (((u32) x) << 10)
+#define DW1_TRANS_BULK ((u32) 2 << 12)
+#define DW1_TRANS_INT ((u32) 3 << 12)
+#define DW1_TRANS_SPLIT ((u32) 1 << 14)
+#define DW1_SE_USB_LOSPEED ((u32) 2 << 16)
+#define TO_DW1_PORT_NUM(x) (((u32) x) << 18)
+#define TO_DW1_HUB_NUM(x) (((u32) x) << 25)
/* DW2 */
-#define PTD_RL_CNT(x) (((u32) x) << 25)
-#define PTD_DATA_START_ADDR(x) (((u32) x) << 8)
-#define BASE_ADDR 0x1000
+#define TO_DW2_DATA_START_ADDR(x) (((u32) x) << 8)
+#define TO_DW2_RL(x) ((x) << 25)
+#define FROM_DW2_RL(x) (((x) >> 25) & 0xf)
/* DW3 */
-#define PTD_CERR(x) (((u32) x) << 23)
-#define PTD_NAC_CNT(x) (((u32) x) << 19)
-#define PTD_ACTIVE ((u32) 1 << 31)
-#define PTD_DATA_TOGGLE(x) (((u32) x) << 25)
-
-#define DW3_HALT_BIT (1 << 30)
+#define FROM_DW3_NRBYTESTRANSFERRED(x) ((x) & 0x7fff)
+#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x) ((x) & 0x07ff)
+#define TO_DW3_NAKCOUNT(x) ((x) << 19)
+#define FROM_DW3_NAKCOUNT(x) (((x) >> 19) & 0xf)
+#define TO_DW3_CERR(x) ((x) << 23)
+#define FROM_DW3_CERR(x) (((x) >> 23) & 0x3)
+#define TO_DW3_DATA_TOGGLE(x) ((x) << 25)
+#define FROM_DW3_DATA_TOGGLE(x) (((x) >> 25) & 0x1)
+#define TO_DW3_PING(x) ((x) << 26)
+#define FROM_DW3_PING(x) (((x) >> 26) & 0x1)
#define DW3_ERROR_BIT (1 << 28)
-#define DW3_QTD_ACTIVE (1 << 31)
+#define DW3_BABBLE_BIT (1 << 29)
+#define DW3_HALT_BIT (1 << 30)
+#define DW3_ACTIVE_BIT (1 << 31)
#define INT_UNDERRUN (1 << 2)
#define INT_BABBLE (1 << 1)
#define INT_EXACT (1 << 0)
-#define DW1_GET_PID(x) (((x) >> 10) & 0x3)
-#define PTD_XFERRED_LENGTH(x) ((x) & 0x7fff)
-#define PTD_XFERRED_LENGTH_LO(x) ((x) & 0x7ff)
-
#define SETUP_PID (2)
#define IN_PID (1)
#define OUT_PID (0)
-#define GET_QTD_TOKEN_TYPE(x) ((x) & 0x3)
-
-#define DATA_TOGGLE (1 << 31)
-#define GET_DATA_TOGGLE(x) ((x) >> 31)
/* Errata 1 */
#define RL_COUNTER (0)
#define NAK_COUNTER (0)
#define ERR_COUNTER (2)
-#endif
+#endif /* _ISP1760_HCD_H_ */
diff --git a/drivers/usb/host/octeon2-common.c b/drivers/usb/host/octeon2-common.c
index 72d672cfcf39..d9df423f3d12 100644
--- a/drivers/usb/host/octeon2-common.c
+++ b/drivers/usb/host/octeon2-common.c
@@ -3,18 +3,19 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2010 Cavium Networks
+ * Copyright (C) 2010, 2011 Cavium Networks
*/
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/delay.h>
-#include <asm/atomic.h>
-
#include <asm/octeon/octeon.h>
#include <asm/octeon/cvmx-uctlx-defs.h>
-static atomic_t octeon2_usb_clock_start_cnt = ATOMIC_INIT(0);
+static DEFINE_MUTEX(octeon2_usb_clocks_mutex);
+
+static int octeon2_usb_clock_start_cnt;
void octeon2_usb_clocks_start(void)
{
@@ -26,8 +27,12 @@ void octeon2_usb_clocks_start(void)
int i;
unsigned long io_clk_64_to_ns;
- if (atomic_inc_return(&octeon2_usb_clock_start_cnt) != 1)
- return;
+
+ mutex_lock(&octeon2_usb_clocks_mutex);
+
+ octeon2_usb_clock_start_cnt++;
+ if (octeon2_usb_clock_start_cnt != 1)
+ goto exit;
io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate();
@@ -43,6 +48,13 @@ void octeon2_usb_clocks_start(void)
/* Step 3: Configure the reference clock, PHY, and HCLK */
clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0));
+
+ /*
+ * If the UCTL looks like it has already been started, skip
+ * the initialization, otherwise bus errors are obtained.
+ */
+ if (clk_rst_ctl.s.hrst)
+ goto end_clock;
/* 3a */
clk_rst_ctl.s.p_por = 1;
clk_rst_ctl.s.hrst = 0;
@@ -158,28 +170,31 @@ void octeon2_usb_clocks_start(void)
clk_rst_ctl.s.hrst = 1;
cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
+end_clock:
/* Now we can set some other registers. */
for (i = 0; i <= 1; i++) {
port_ctl_status.u64 =
cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0));
- /* Set txvreftune to 15 to obtain complient 'eye' diagram. */
+ /* Set txvreftune to 15 to obtain compliant 'eye' diagram. */
port_ctl_status.s.txvreftune = 15;
+ port_ctl_status.s.txrisetune = 1;
+ port_ctl_status.s.txpreemphasistune = 1;
cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0),
port_ctl_status.u64);
}
+
+ /* Set uSOF cycle period to 60,000 bits. */
+ cvmx_write_csr(CVMX_UCTLX_EHCI_FLA(0), 0x20ull);
+exit:
+ mutex_unlock(&octeon2_usb_clocks_mutex);
}
EXPORT_SYMBOL(octeon2_usb_clocks_start);
void octeon2_usb_clocks_stop(void)
{
- union cvmx_uctlx_if_ena if_ena;
-
- if (atomic_dec_return(&octeon2_usb_clock_start_cnt) != 0)
- return;
-
- if_ena.u64 = 0;
- if_ena.s.en = 0;
- cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64);
+ mutex_lock(&octeon2_usb_clocks_mutex);
+ octeon2_usb_clock_start_cnt--;
+ mutex_unlock(&octeon2_usb_clocks_mutex);
}
EXPORT_SYMBOL(octeon2_usb_clocks_stop);
diff --git a/drivers/usb/host/ohci-ath79.c b/drivers/usb/host/ohci-ath79.c
new file mode 100644
index 000000000000..ffea3e7cb0a8
--- /dev/null
+++ b/drivers/usb/host/ohci-ath79.c
@@ -0,0 +1,151 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * Bus Glue for Atheros AR71XX/AR724X built-in OHCI controller.
+ *
+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Parts of this file are based on Atheros' 2.6.15 BSP
+ * Copyright (C) 2007 Atheros Communications, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+
+static int __devinit ohci_ath79_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)
+ goto err;
+
+ return 0;
+
+err:
+ ohci_stop(hcd);
+ return ret;
+}
+
+static const struct hc_driver ohci_ath79_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "Atheros built-in OHCI controller",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ .start = ohci_ath79_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+
+ .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 ohci_ath79_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ struct resource *res;
+ int irq;
+ int ret;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_dbg(&pdev->dev, "no IRQ specified\n");
+ return -ENODEV;
+ }
+ irq = res->start;
+
+ hcd = usb_create_hcd(&ohci_ath79_hc_driver, &pdev->dev,
+ dev_name(&pdev->dev));
+ if (!hcd)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_dbg(&pdev->dev, "no base address specified\n");
+ ret = -ENODEV;
+ goto err_put_hcd;
+ }
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = res->end - res->start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ dev_dbg(&pdev->dev, "controller already in use\n");
+ ret = -EBUSY;
+ goto err_put_hcd;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ dev_dbg(&pdev->dev, "error mapping memory\n");
+ ret = -EFAULT;
+ goto err_release_region;
+ }
+
+ ohci_hcd_init(hcd_to_ohci(hcd));
+
+ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ if (ret)
+ goto err_stop_hcd;
+
+ return 0;
+
+err_stop_hcd:
+ iounmap(hcd->regs);
+err_release_region:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_put_hcd:
+ usb_put_hcd(hcd);
+ return ret;
+}
+
+static int ohci_ath79_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+static struct platform_driver ohci_hcd_ath79_driver = {
+ .probe = ohci_ath79_probe,
+ .remove = ohci_ath79_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .name = "ath79-ohci",
+ .owner = THIS_MODULE,
+ },
+};
+
+MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ath79-ohci");
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index d55723514860..9aa10bdf3918 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -764,6 +764,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
if (ints == ~(u32)0) {
disable (ohci);
ohci_dbg (ohci, "device removed!\n");
+ usb_hc_died(hcd);
return IRQ_HANDLED;
}
@@ -771,7 +772,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
ints &= ohci_readl(ohci, &regs->intrenable);
/* interrupt for some other device? */
- if (ints == 0)
+ if (ints == 0 || unlikely(hcd->state == HC_STATE_HALT))
return IRQ_NOTMINE;
if (ints & OHCI_INTR_UE) {
@@ -788,6 +789,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
} else {
disable (ohci);
ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
+ usb_hc_died(hcd);
}
ohci_dump (ohci, 1);
@@ -1105,6 +1107,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ohci_hcd_cns3xxx_driver
#endif
+#ifdef CONFIG_USB_OHCI_ATH79
+#include "ohci-ath79.c"
+#define PLATFORM_DRIVER ohci_hcd_ath79_driver
+#endif
+
#if !defined(PCI_DRIVER) && \
!defined(PLATFORM_DRIVER) && \
!defined(OMAP1_PLATFORM_DRIVER) && \
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index d84d6f0314f9..ad8166c681e2 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -181,10 +181,18 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd)
*/
static int ohci_quirk_nvidia_shutdown(struct usb_hcd *hcd)
{
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
- ohci->flags |= OHCI_QUIRK_SHUTDOWN;
- ohci_dbg(ohci, "enabled nVidia shutdown quirk\n");
+ /* Evidently nVidia fixed their later hardware; this is a guess at
+ * the changeover point.
+ */
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB 0x026d
+
+ if (pdev->device < PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB) {
+ ohci->flags |= OHCI_QUIRK_SHUTDOWN;
+ ohci_dbg(ohci, "enabled nVidia shutdown quirk\n");
+ }
return 0;
}
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index a68af2dd55ca..7c9a4d55526b 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -56,9 +56,8 @@ static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd)
info->hcd = hcd;
info->report_oc = s3c2410_hcd_oc;
- if (info->enable_oc != NULL) {
+ if (info->enable_oc != NULL)
(info->enable_oc)(info, 1);
- }
}
}
@@ -72,9 +71,8 @@ static void s3c2410_stop_hc(struct platform_device *dev)
info->report_oc = NULL;
info->hcd = NULL;
- if (info->enable_oc != NULL) {
+ if (info->enable_oc != NULL)
(info->enable_oc)(info, 0);
- }
}
clk_disable(clk);
@@ -88,14 +86,14 @@ static void s3c2410_stop_hc(struct platform_device *dev)
*/
static int
-ohci_s3c2410_hub_status_data (struct usb_hcd *hcd, char *buf)
+ohci_s3c2410_hub_status_data(struct usb_hcd *hcd, char *buf)
{
struct s3c2410_hcd_info *info = to_s3c2410_info(hcd);
struct s3c2410_hcd_port *port;
int orig;
int portno;
- orig = ohci_hub_status_data (hcd, buf);
+ orig = ohci_hub_status_data(hcd, buf);
if (info == NULL)
return orig;
@@ -145,7 +143,7 @@ static void s3c2410_usb_set_power(struct s3c2410_hcd_info *info,
* request.
*/
-static int ohci_s3c2410_hub_control (
+static int ohci_s3c2410_hub_control(
struct usb_hcd *hcd,
u16 typeReq,
u16 wValue,
@@ -199,9 +197,8 @@ static int ohci_s3c2410_hub_control (
dev_dbg(hcd->self.controller,
"ClearPortFeature: OVER_CURRENT\n");
- if (valid_port(wIndex)) {
+ if (valid_port(wIndex))
info->port[wIndex-1].oc_status = 0;
- }
goto out;
@@ -242,8 +239,11 @@ static int ohci_s3c2410_hub_control (
desc->wHubCharacteristics |= cpu_to_le16(0x0001);
if (info->enable_oc) {
- desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_OCPM);
- desc->wHubCharacteristics |= cpu_to_le16(0x0008|0x0001);
+ desc->wHubCharacteristics &= ~cpu_to_le16(
+ HUB_CHAR_OCPM);
+ desc->wHubCharacteristics |= cpu_to_le16(
+ 0x0008 |
+ 0x0001);
}
dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n",
@@ -257,13 +257,11 @@ static int ohci_s3c2410_hub_control (
dev_dbg(hcd->self.controller, "GetPortStatus(%d)\n", wIndex);
if (valid_port(wIndex)) {
- if (info->port[wIndex-1].oc_changed) {
+ if (info->port[wIndex-1].oc_changed)
*data |= cpu_to_le32(RH_PS_OCIC);
- }
- if (info->port[wIndex-1].oc_status) {
+ if (info->port[wIndex-1].oc_status)
*data |= cpu_to_le32(RH_PS_POCI);
- }
}
}
@@ -321,7 +319,7 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc)
*/
static void
-usb_hcd_s3c2410_remove (struct usb_hcd *hcd, struct platform_device *dev)
+usb_hcd_s3c2410_remove(struct usb_hcd *hcd, struct platform_device *dev)
{
usb_remove_hcd(hcd);
s3c2410_stop_hc(dev);
@@ -339,7 +337,7 @@ usb_hcd_s3c2410_remove (struct usb_hcd *hcd, struct platform_device *dev)
* through the hotplug entry's driver_data.
*
*/
-static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
+static int usb_hcd_s3c2410_probe(const struct hc_driver *driver,
struct platform_device *dev)
{
struct usb_hcd *hcd = NULL;
@@ -353,7 +351,7 @@ static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
return -ENOMEM;
hcd->rsrc_start = dev->resource[0].start;
- hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
+ hcd->rsrc_len = resource_size(&dev->resource[0]);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
dev_err(&dev->dev, "request_mem_region failed\n");
@@ -364,14 +362,14 @@ static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
clk = clk_get(&dev->dev, "usb-host");
if (IS_ERR(clk)) {
dev_err(&dev->dev, "cannot get usb-host clock\n");
- retval = -ENOENT;
+ retval = PTR_ERR(clk);
goto err_mem;
}
usb_clk = clk_get(&dev->dev, "usb-bus-host");
if (IS_ERR(usb_clk)) {
dev_err(&dev->dev, "cannot get usb-bus-host clock\n");
- retval = -ENOENT;
+ retval = PTR_ERR(usb_clk);
goto err_clk;
}
@@ -411,17 +409,19 @@ static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
/*-------------------------------------------------------------------------*/
static int
-ohci_s3c2410_start (struct usb_hcd *hcd)
+ohci_s3c2410_start(struct usb_hcd *hcd)
{
- struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
int ret;
- if ((ret = ohci_init(ohci)) < 0)
+ ret = ohci_init(ohci);
+ if (ret < 0)
return ret;
- if ((ret = ohci_run (ohci)) < 0) {
- err ("can't start %s", hcd->self.bus_name);
- ohci_stop (hcd);
+ ret = ohci_run(ohci);
+ if (ret < 0) {
+ err("can't start %s", hcd->self.bus_name);
+ ohci_stop(hcd);
return ret;
}
@@ -473,12 +473,12 @@ static const struct hc_driver ohci_s3c2410_hc_driver = {
/* device driver */
-static int ohci_hcd_s3c2410_drv_probe(struct platform_device *pdev)
+static int __devinit ohci_hcd_s3c2410_drv_probe(struct platform_device *pdev)
{
return usb_hcd_s3c2410_probe(&ohci_s3c2410_hc_driver, pdev);
}
-static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
+static int __devexit ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
@@ -488,7 +488,7 @@ static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
static struct platform_driver ohci_hcd_s3c2410_driver = {
.probe = ohci_hcd_s3c2410_drv_probe,
- .remove = ohci_hcd_s3c2410_drv_remove,
+ .remove = __devexit_p(ohci_hcd_s3c2410_drv_remove),
.shutdown = usb_hcd_platform_shutdown,
/*.suspend = ohci_hcd_s3c2410_drv_suspend, */
/*.resume = ohci_hcd_s3c2410_drv_resume, */
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index 4a771f6cc822..5fbe997dc6df 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -1884,6 +1884,7 @@ static int enable_periodic(struct oxu_hcd *oxu)
status = handshake(oxu, &oxu->regs->status, STS_PSS, 0, 9 * 125);
if (status != 0) {
oxu_to_hcd(oxu)->state = HC_STATE_HALT;
+ usb_hc_died(oxu_to_hcd(oxu));
return status;
}
@@ -1909,6 +1910,7 @@ static int disable_periodic(struct oxu_hcd *oxu)
status = handshake(oxu, &oxu->regs->status, STS_PSS, STS_PSS, 9 * 125);
if (status != 0) {
oxu_to_hcd(oxu)->state = HC_STATE_HALT;
+ usb_hc_died(oxu_to_hcd(oxu));
return status;
}
@@ -2449,8 +2451,9 @@ static irqreturn_t oxu210_hcd_irq(struct usb_hcd *hcd)
goto dead;
}
+ /* Shared IRQ? */
status &= INTR_MASK;
- if (!status) { /* irq sharing? */
+ if (!status || unlikely(hcd->state == HC_STATE_HALT)) {
spin_unlock(&oxu->lock);
return IRQ_NONE;
}
@@ -2516,6 +2519,7 @@ static irqreturn_t oxu210_hcd_irq(struct usb_hcd *hcd)
dead:
ehci_reset(oxu);
writel(0, &oxu->regs->configured_flag);
+ usb_hc_died(hcd);
/* generic layer kills/unlinks all urbs, then
* uses oxu_stop to clean up the rest
*/
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 9b166d70ae91..f16c59d5f487 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -14,6 +14,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/acpi.h>
+#include <linux/dmi.h>
#include "pci-quirks.h"
#include "xhci-ext-caps.h"
@@ -503,14 +504,84 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
iounmap(base);
}
+static void __devinit ehci_bios_handoff(struct pci_dev *pdev,
+ void __iomem *op_reg_base,
+ u32 cap, u8 offset)
+{
+ int try_handoff = 1, tried_handoff = 0;
+
+ /* The Pegatron Lucid (ExoPC) tablet sporadically waits for 90
+ * seconds trying the handoff on its unused controller. Skip
+ * it. */
+ if (pdev->vendor == 0x8086 && pdev->device == 0x283a) {
+ const char *dmi_bn = dmi_get_system_info(DMI_BOARD_NAME);
+ const char *dmi_bv = dmi_get_system_info(DMI_BIOS_VERSION);
+ if (dmi_bn && !strcmp(dmi_bn, "EXOPG06411") &&
+ dmi_bv && !strcmp(dmi_bv, "Lucid-CE-133"))
+ try_handoff = 0;
+ }
+
+ if (try_handoff && (cap & EHCI_USBLEGSUP_BIOS)) {
+ dev_dbg(&pdev->dev, "EHCI: BIOS handoff\n");
+
+#if 0
+/* aleksey_gorelov@phoenix.com reports that some systems need SMI forced on,
+ * but that seems dubious in general (the BIOS left it off intentionally)
+ * and is known to prevent some systems from booting. so we won't do this
+ * unless maybe we can determine when we're on a system that needs SMI forced.
+ */
+ /* BIOS workaround (?): be sure the pre-Linux code
+ * receives the SMI
+ */
+ pci_read_config_dword(pdev, offset + EHCI_USBLEGCTLSTS, &val);
+ pci_write_config_dword(pdev, offset + EHCI_USBLEGCTLSTS,
+ val | EHCI_USBLEGCTLSTS_SOOE);
+#endif
+
+ /* some systems get upset if this semaphore is
+ * set for any other reason than forcing a BIOS
+ * handoff..
+ */
+ pci_write_config_byte(pdev, offset + 3, 1);
+ }
+
+ /* if boot firmware now owns EHCI, spin till it hands it over. */
+ if (try_handoff) {
+ int msec = 1000;
+ while ((cap & EHCI_USBLEGSUP_BIOS) && (msec > 0)) {
+ tried_handoff = 1;
+ msleep(10);
+ msec -= 10;
+ pci_read_config_dword(pdev, offset, &cap);
+ }
+ }
+
+ if (cap & EHCI_USBLEGSUP_BIOS) {
+ /* well, possibly buggy BIOS... try to shut it down,
+ * and hope nothing goes too wrong
+ */
+ if (try_handoff)
+ dev_warn(&pdev->dev, "EHCI: BIOS handoff failed"
+ " (BIOS bug?) %08x\n", cap);
+ pci_write_config_byte(pdev, offset + 2, 0);
+ }
+
+ /* just in case, always disable EHCI SMIs */
+ pci_write_config_dword(pdev, offset + EHCI_USBLEGCTLSTS, 0);
+
+ /* If the BIOS ever owned the controller then we can't expect
+ * any power sessions to remain intact.
+ */
+ if (tried_handoff)
+ writel(0, op_reg_base + EHCI_CONFIGFLAG);
+}
+
static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
{
- int wait_time, delta;
void __iomem *base, *op_reg_base;
- u32 hcc_params, val;
+ u32 hcc_params, cap, val;
u8 offset, cap_length;
- int count = 256/4;
- int tried_handoff = 0;
+ int wait_time, delta, count = 256/4;
if (!mmio_resource_enabled(pdev, 0))
return;
@@ -529,77 +600,17 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
hcc_params = readl(base + EHCI_HCC_PARAMS);
offset = (hcc_params >> 8) & 0xff;
while (offset && --count) {
- u32 cap;
- int msec;
-
pci_read_config_dword(pdev, offset, &cap);
- switch (cap & 0xff) {
- case 1: /* BIOS/SMM/... handoff support */
- if ((cap & EHCI_USBLEGSUP_BIOS)) {
- dev_dbg(&pdev->dev, "EHCI: BIOS handoff\n");
-#if 0
-/* aleksey_gorelov@phoenix.com reports that some systems need SMI forced on,
- * but that seems dubious in general (the BIOS left it off intentionally)
- * and is known to prevent some systems from booting. so we won't do this
- * unless maybe we can determine when we're on a system that needs SMI forced.
- */
- /* BIOS workaround (?): be sure the
- * pre-Linux code receives the SMI
- */
- pci_read_config_dword(pdev,
- offset + EHCI_USBLEGCTLSTS,
- &val);
- pci_write_config_dword(pdev,
- offset + EHCI_USBLEGCTLSTS,
- val | EHCI_USBLEGCTLSTS_SOOE);
-#endif
-
- /* some systems get upset if this semaphore is
- * set for any other reason than forcing a BIOS
- * handoff..
- */
- pci_write_config_byte(pdev, offset + 3, 1);
- }
-
- /* if boot firmware now owns EHCI, spin till
- * it hands it over.
- */
- msec = 1000;
- while ((cap & EHCI_USBLEGSUP_BIOS) && (msec > 0)) {
- tried_handoff = 1;
- msleep(10);
- msec -= 10;
- pci_read_config_dword(pdev, offset, &cap);
- }
-
- if (cap & EHCI_USBLEGSUP_BIOS) {
- /* well, possibly buggy BIOS... try to shut
- * it down, and hope nothing goes too wrong
- */
- dev_warn(&pdev->dev, "EHCI: BIOS handoff failed"
- " (BIOS bug?) %08x\n", cap);
- pci_write_config_byte(pdev, offset + 2, 0);
- }
-
- /* just in case, always disable EHCI SMIs */
- pci_write_config_dword(pdev,
- offset + EHCI_USBLEGCTLSTS,
- 0);
-
- /* If the BIOS ever owned the controller then we
- * can't expect any power sessions to remain intact.
- */
- if (tried_handoff)
- writel(0, op_reg_base + EHCI_CONFIGFLAG);
+ switch (cap & 0xff) {
+ case 1:
+ ehci_bios_handoff(pdev, op_reg_base, cap, offset);
break;
- case 0: /* illegal reserved capability */
- cap = 0;
- /* FALLTHROUGH */
+ case 0: /* Illegal reserved cap, set cap=0 so we exit */
+ cap = 0; /* then fallthrough... */
default:
dev_warn(&pdev->dev, "EHCI: unrecognized capability "
- "%02x\n", cap & 0xff);
- break;
+ "%02x\n", cap & 0xff);
}
offset = (cap >> 8) & 0xff;
}
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index fafccc2fd331..1a996245ab98 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -72,12 +72,6 @@ MODULE_ALIAS("platform:sl811-hcd");
/* for now, use only one transfer register bank */
#undef USE_B
-/* this doesn't understand urb->iso_frame_desc[], but if you had a driver
- * that just queued one ISO frame per URB then iso transfers "should" work
- * using the normal urb status fields.
- */
-#define DISABLE_ISO
-
// #define QUIRK2
#define QUIRK3
@@ -808,7 +802,7 @@ static int sl811h_urb_enqueue(
int retval;
struct usb_host_endpoint *hep = urb->ep;
-#ifdef DISABLE_ISO
+#ifndef CONFIG_USB_SL811_HCD_ISO
if (type == PIPE_ISOCHRONOUS)
return -ENOSPC;
#endif
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index b4785934e091..533d12cca371 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -3230,8 +3230,7 @@ static int __init u132_hcd_init(void)
mutex_init(&u132_module_lock);
if (usb_disabled())
return -ENODEV;
- printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__,
- __DATE__);
+ printk(KERN_INFO "driver %s\n", hcd_name);
workqueue = create_singlethread_workqueue("u132");
retval = platform_driver_register(&u132_platform_driver);
return retval;
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index ee60cd3ea642..fc0b0daac93d 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -37,7 +37,8 @@ static void lprintk(char *buf)
}
}
-static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
+static int uhci_show_td(struct uhci_hcd *uhci, struct uhci_td *td, char *buf,
+ int len, int space)
{
char *out = buf;
char *spid;
@@ -47,8 +48,9 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
if (len < 160)
return 0;
- status = td_status(td);
- out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td, le32_to_cpu(td->link));
+ status = td_status(uhci, td);
+ out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td,
+ hc32_to_cpu(uhci, td->link));
out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
((status >> 27) & 3),
(status & TD_CTRL_SPD) ? "SPD " : "",
@@ -63,7 +65,7 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
(status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
status & 0x7ff);
- token = td_token(td);
+ token = td_token(uhci, td);
switch (uhci_packetid(token)) {
case USB_PID_SETUP:
spid = "SETUP";
@@ -86,12 +88,13 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
(token >> 8) & 127,
(token & 0xff),
spid);
- out += sprintf(out, "(buf=%08x)\n", le32_to_cpu(td->buffer));
+ out += sprintf(out, "(buf=%08x)\n", hc32_to_cpu(uhci, td->buffer));
return out - buf;
}
-static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
+static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp,
+ char *buf, int len, int space)
{
char *out = buf;
struct uhci_td *td;
@@ -130,9 +133,10 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
if (urbp->qh->type != USB_ENDPOINT_XFER_ISOC &&
(++i <= 10 || debug > 2)) {
out += sprintf(out, "%*s%d: ", space + 2, "", i);
- out += uhci_show_td(td, out, len - (out - buf), 0);
+ out += uhci_show_td(uhci, td, out,
+ len - (out - buf), 0);
} else {
- if (td_status(td) & TD_CTRL_ACTIVE)
+ if (td_status(uhci, td) & TD_CTRL_ACTIVE)
++nactive;
else
++ninactive;
@@ -151,7 +155,7 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
{
char *out = buf;
int i, nurbs;
- __le32 element = qh_element(qh);
+ __hc32 element = qh_element(qh);
char *qtype;
/* Try to make sure there's enough memory */
@@ -168,7 +172,8 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
out += sprintf(out, "%*s[%p] %s QH link (%08x) element (%08x)\n",
space, "", qh, qtype,
- le32_to_cpu(qh->link), le32_to_cpu(element));
+ hc32_to_cpu(uhci, qh->link),
+ hc32_to_cpu(uhci, element));
if (qh->type == USB_ENDPOINT_XFER_ISOC)
out += sprintf(out, "%*s period %d phase %d load %d us, "
"frame %x desc [%p]\n",
@@ -178,22 +183,22 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
out += sprintf(out, "%*s period %d phase %d load %d us\n",
space, "", qh->period, qh->phase, qh->load);
- if (element & UHCI_PTR_QH)
+ if (element & UHCI_PTR_QH(uhci))
out += sprintf(out, "%*s Element points to QH (bug?)\n", space, "");
- if (element & UHCI_PTR_DEPTH)
+ if (element & UHCI_PTR_DEPTH(uhci))
out += sprintf(out, "%*s Depth traverse\n", space, "");
- if (element & cpu_to_le32(8))
+ if (element & cpu_to_hc32(uhci, 8))
out += sprintf(out, "%*s Bit 3 set (bug?)\n", space, "");
- if (!(element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH)))
+ if (!(element & ~(UHCI_PTR_QH(uhci) | UHCI_PTR_DEPTH(uhci))))
out += sprintf(out, "%*s Element is NULL (bug?)\n", space, "");
if (list_empty(&qh->queue)) {
out += sprintf(out, "%*s queue is empty\n", space, "");
if (qh == uhci->skel_async_qh)
- out += uhci_show_td(uhci->term_td, out,
+ out += uhci_show_td(uhci, uhci->term_td, out,
len - (out - buf), 0);
} else {
struct urb_priv *urbp = list_entry(qh->queue.next,
@@ -201,13 +206,13 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
struct uhci_td *td = list_entry(urbp->td_list.next,
struct uhci_td, list);
- if (element != LINK_TO_TD(td))
+ if (element != LINK_TO_TD(uhci, td))
out += sprintf(out, "%*s Element != First TD\n",
space, "");
i = nurbs = 0;
list_for_each_entry(urbp, &qh->queue, node) {
if (++i <= 10)
- out += uhci_show_urbp(urbp, out,
+ out += uhci_show_urbp(uhci, urbp, out,
len - (out - buf), space + 2);
else
++nurbs;
@@ -219,7 +224,8 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
if (qh->dummy_td) {
out += sprintf(out, "%*s Dummy TD\n", space, "");
- out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0);
+ out += uhci_show_td(uhci, qh->dummy_td, out,
+ len - (out - buf), 0);
}
return out - buf;
@@ -285,7 +291,6 @@ static int uhci_show_root_hub_state(struct uhci_hcd *uhci, char *buf, int len)
static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
{
char *out = buf;
- unsigned long io_addr = uhci->io_addr;
unsigned short usbcmd, usbstat, usbint, usbfrnum;
unsigned int flbaseadd;
unsigned char sof;
@@ -295,14 +300,14 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
if (len < 80 * 9)
return 0;
- usbcmd = inw(io_addr + 0);
- usbstat = inw(io_addr + 2);
- usbint = inw(io_addr + 4);
- usbfrnum = inw(io_addr + 6);
- flbaseadd = inl(io_addr + 8);
- sof = inb(io_addr + 12);
- portsc1 = inw(io_addr + 16);
- portsc2 = inw(io_addr + 18);
+ 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,
@@ -347,8 +352,8 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
struct uhci_td *td;
struct list_head *tmp, *head;
int nframes, nerrs;
- __le32 link;
- __le32 fsbr_link;
+ __hc32 link;
+ __hc32 fsbr_link;
static const char * const qh_names[] = {
"unlink", "iso", "int128", "int64", "int32", "int16",
@@ -376,7 +381,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
nframes = 10;
nerrs = 0;
for (i = 0; i < UHCI_NUMFRAMES; ++i) {
- __le32 qh_dma;
+ __hc32 qh_dma;
j = 0;
td = uhci->frame_cpu[i];
@@ -386,7 +391,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
if (nframes > 0) {
out += sprintf(out, "- Frame %d -> (%08x)\n",
- i, le32_to_cpu(link));
+ i, hc32_to_cpu(uhci, link));
j = 1;
}
@@ -395,7 +400,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
do {
td = list_entry(tmp, struct uhci_td, fl_list);
tmp = tmp->next;
- if (link != LINK_TO_TD(td)) {
+ if (link != LINK_TO_TD(uhci, td)) {
if (nframes > 0)
out += sprintf(out, " link does "
"not match list entry!\n");
@@ -403,7 +408,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
++nerrs;
}
if (nframes > 0)
- out += uhci_show_td(td, out,
+ out += uhci_show_td(uhci, td, out,
len - (out - buf), 4);
link = td->link;
} while (tmp != head);
@@ -415,11 +420,12 @@ check_link:
if (!j) {
out += sprintf(out,
"- Frame %d -> (%08x)\n",
- i, le32_to_cpu(link));
+ i, hc32_to_cpu(uhci, link));
j = 1;
}
out += sprintf(out, " link does not match "
- "QH (%08x)!\n", le32_to_cpu(qh_dma));
+ "QH (%08x)!\n",
+ hc32_to_cpu(uhci, qh_dma));
} else
++nerrs;
}
@@ -440,11 +446,11 @@ check_link:
/* Last QH is the Terminating QH, it's different */
if (i == SKEL_TERM) {
- if (qh_element(qh) != LINK_TO_TD(uhci->term_td))
+ if (qh_element(qh) != LINK_TO_TD(uhci, uhci->term_td))
out += sprintf(out, " skel_term_qh element is not set to term_td!\n");
link = fsbr_link;
if (!link)
- link = LINK_TO_QH(uhci->skel_term_qh);
+ link = LINK_TO_QH(uhci, uhci->skel_term_qh);
goto check_qh_link;
}
@@ -458,20 +464,20 @@ check_link:
out += uhci_show_qh(uhci, qh, out,
len - (out - buf), 4);
if (!fsbr_link && qh->skel >= SKEL_FSBR)
- fsbr_link = LINK_TO_QH(qh);
+ fsbr_link = LINK_TO_QH(uhci, qh);
}
if ((cnt -= 10) > 0)
out += sprintf(out, " Skipped %d QHs\n", cnt);
- link = UHCI_PTR_TERM;
+ link = UHCI_PTR_TERM(uhci);
if (i <= SKEL_ISO)
;
else if (i < SKEL_ASYNC)
- link = LINK_TO_QH(uhci->skel_async_qh);
+ link = LINK_TO_QH(uhci, uhci->skel_async_qh);
else if (!uhci->fsbr_is_on)
;
else
- link = LINK_TO_QH(uhci->skel_term_qh);
+ link = LINK_TO_QH(uhci, uhci->skel_term_qh);
check_qh_link:
if (qh->link != link)
out += sprintf(out, " last QH not linked to next skeleton!\n");
diff --git a/drivers/usb/host/uhci-grlib.c b/drivers/usb/host/uhci-grlib.c
new file mode 100644
index 000000000000..d01c1e227681
--- /dev/null
+++ b/drivers/usb/host/uhci-grlib.c
@@ -0,0 +1,208 @@
+/*
+ * UHCI HCD (Host Controller Driver) for GRLIB GRUSBHC
+ *
+ * Copyright (c) 2011 Jan Andersson <jan@gaisler.com>
+ *
+ * This file is based on UHCI PCI HCD:
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu
+ */
+
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+
+static int uhci_grlib_init(struct usb_hcd *hcd)
+{
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+
+ /*
+ * Probe to determine the endianness of the controller.
+ * We know that bit 7 of the PORTSC1 register is always set
+ * and bit 15 is always clear. If uhci_readw() yields a value
+ * with bit 7 (0x80) turned on then the current little-endian
+ * setting is correct. Otherwise we assume the value was
+ * byte-swapped; hence the register interface and presumably
+ * also the descriptors are big-endian.
+ */
+ if (!(uhci_readw(uhci, USBPORTSC1) & 0x80)) {
+ uhci->big_endian_mmio = 1;
+ uhci->big_endian_desc = 1;
+ }
+
+ uhci->rh_numports = uhci_count_ports(hcd);
+
+ /* Set up pointers to to generic functions */
+ uhci->reset_hc = uhci_generic_reset_hc;
+ uhci->check_and_reset_hc = uhci_generic_check_and_reset_hc;
+ /* No special actions need to be taken for the functions below */
+ uhci->configure_hc = NULL;
+ uhci->resume_detect_interrupts_are_broken = NULL;
+ uhci->global_suspend_mode_is_broken = NULL;
+
+ /* Reset if the controller isn't already safely quiescent. */
+ check_and_reset_hc(uhci);
+ return 0;
+}
+
+static const struct hc_driver uhci_grlib_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "GRLIB GRUSBHC UHCI Host Controller",
+ .hcd_priv_size = sizeof(struct uhci_hcd),
+
+ /* Generic hardware linkage */
+ .irq = uhci_irq,
+ .flags = HCD_MEMORY | HCD_USB11,
+
+ /* Basic lifecycle operations */
+ .reset = uhci_grlib_init,
+ .start = uhci_start,
+#ifdef CONFIG_PM
+ .pci_suspend = NULL,
+ .pci_resume = NULL,
+ .bus_suspend = uhci_rh_suspend,
+ .bus_resume = uhci_rh_resume,
+#endif
+ .stop = uhci_stop,
+
+ .urb_enqueue = uhci_urb_enqueue,
+ .urb_dequeue = uhci_urb_dequeue,
+
+ .endpoint_disable = uhci_hcd_endpoint_disable,
+ .get_frame_number = uhci_hcd_get_frame_number,
+
+ .hub_status_data = uhci_hub_status_data,
+ .hub_control = uhci_hub_control,
+};
+
+
+static int __devinit uhci_hcd_grlib_probe(struct platform_device *op)
+{
+ struct device_node *dn = op->dev.of_node;
+ struct usb_hcd *hcd;
+ struct uhci_hcd *uhci = NULL;
+ struct resource res;
+ int irq;
+ int rv;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ dev_dbg(&op->dev, "initializing GRUSBHC UHCI USB Controller\n");
+
+ rv = of_address_to_resource(dn, 0, &res);
+ if (rv)
+ return rv;
+
+ /* usb_create_hcd requires dma_mask != NULL */
+ op->dev.dma_mask = &op->dev.coherent_dma_mask;
+ hcd = usb_create_hcd(&uhci_grlib_hc_driver, &op->dev,
+ "GRUSBHC UHCI USB");
+ if (!hcd)
+ return -ENOMEM;
+
+ hcd->rsrc_start = res.start;
+ hcd->rsrc_len = res.end - res.start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
+ rv = -EBUSY;
+ goto err_rmr;
+ }
+
+ irq = irq_of_parse_and_map(dn, 0);
+ if (irq == NO_IRQ) {
+ printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
+ rv = -EBUSY;
+ goto err_irq;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
+ rv = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ uhci = hcd_to_uhci(hcd);
+
+ uhci->regs = hcd->regs;
+
+ rv = usb_add_hcd(hcd, irq, 0);
+ if (rv)
+ goto err_uhci;
+
+ return 0;
+
+err_uhci:
+ iounmap(hcd->regs);
+err_ioremap:
+ irq_dispose_mapping(irq);
+err_irq:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_rmr:
+ usb_put_hcd(hcd);
+
+ return rv;
+}
+
+static int uhci_hcd_grlib_remove(struct platform_device *op)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+
+ dev_set_drvdata(&op->dev, NULL);
+
+ dev_dbg(&op->dev, "stopping GRLIB GRUSBHC UHCI USB Controller\n");
+
+ usb_remove_hcd(hcd);
+
+ iounmap(hcd->regs);
+ irq_dispose_mapping(hcd->irq);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+/* Make sure the controller is quiescent and that we're not using it
+ * any more. This is mainly for the benefit of programs which, like kexec,
+ * expect the hardware to be idle: not doing DMA or generating IRQs.
+ *
+ * This routine may be called in a damaged or failing kernel. Hence we
+ * do not acquire the spinlock before shutting down the controller.
+ */
+static void uhci_hcd_grlib_shutdown(struct platform_device *op)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+
+ uhci_hc_died(hcd_to_uhci(hcd));
+}
+
+static const struct of_device_id uhci_hcd_grlib_of_match[] = {
+ { .name = "GAISLER_UHCI", },
+ { .name = "01_027", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, uhci_hcd_grlib_of_match);
+
+
+static struct platform_driver uhci_grlib_driver = {
+ .probe = uhci_hcd_grlib_probe,
+ .remove = uhci_hcd_grlib_remove,
+ .shutdown = uhci_hcd_grlib_shutdown,
+ .driver = {
+ .name = "grlib-uhci",
+ .owner = THIS_MODULE,
+ .of_match_table = uhci_hcd_grlib_of_match,
+ },
+};
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 448b9d1f0e70..fba99b120588 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -48,7 +48,6 @@
#include <asm/system.h>
#include "uhci-hcd.h"
-#include "pci-quirks.h"
/*
* Version Information
@@ -94,7 +93,7 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
/*
* Calculate the link pointer DMA value for the first Skeleton QH in a frame.
*/
-static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
+static __hc32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
{
int skelnum;
@@ -116,7 +115,7 @@ static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES);
if (skelnum <= 1)
skelnum = 9;
- return LINK_TO_QH(uhci->skelqh[skelnum]);
+ return LINK_TO_QH(uhci, uhci->skelqh[skelnum]);
}
#include "uhci-debug.c"
@@ -135,15 +134,12 @@ static void finish_reset(struct uhci_hcd *uhci)
* We have to clear them by hand.
*/
for (port = 0; port < uhci->rh_numports; ++port)
- outw(0, uhci->io_addr + USBPORTSC1 + (port * 2));
+ uhci_writew(uhci, 0, USBPORTSC1 + (port * 2));
uhci->port_c_suspend = uhci->resuming_ports = 0;
uhci->rh_state = UHCI_RH_RESET;
uhci->is_stopped = UHCI_IS_STOPPED;
- uhci_to_hcd(uhci)->state = HC_STATE_HALT;
clear_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags);
-
- uhci->dead = 0; /* Full reset resurrects the controller */
}
/*
@@ -153,7 +149,7 @@ static void finish_reset(struct uhci_hcd *uhci)
static void uhci_hc_died(struct uhci_hcd *uhci)
{
uhci_get_current_frame_number(uhci);
- uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr);
+ uhci->reset_hc(uhci);
finish_reset(uhci);
uhci->dead = 1;
@@ -168,97 +164,118 @@ static void uhci_hc_died(struct uhci_hcd *uhci)
*/
static void check_and_reset_hc(struct uhci_hcd *uhci)
{
- if (uhci_check_and_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr))
+ if (uhci->check_and_reset_hc(uhci))
finish_reset(uhci);
}
+#if defined(CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC)
+/*
+ * The two functions below are generic reset functions that are used on systems
+ * that do not have keyboard and mouse legacy support. We assume that we are
+ * running on such a system if CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC is defined.
+ */
+
+/*
+ * Make sure the controller is completely inactive, unable to
+ * generate interrupts or do DMA.
+ */
+static void uhci_generic_reset_hc(struct uhci_hcd *uhci)
+{
+ /* Reset the HC - this will force us to get a
+ * new notification of any already connected
+ * ports due to the virtual disconnect that it
+ * implies.
+ */
+ uhci_writew(uhci, USBCMD_HCRESET, USBCMD);
+ mb();
+ udelay(5);
+ if (uhci_readw(uhci, USBCMD) & USBCMD_HCRESET)
+ dev_warn(uhci_dev(uhci), "HCRESET not completed yet!\n");
+
+ /* Just to be safe, disable interrupt requests and
+ * make sure the controller is stopped.
+ */
+ uhci_writew(uhci, 0, USBINTR);
+ uhci_writew(uhci, 0, USBCMD);
+}
+
+/*
+ * Initialize a controller that was newly discovered or has just been
+ * resumed. In either case we can't be sure of its previous state.
+ *
+ * Returns: 1 if the controller was reset, 0 otherwise.
+ */
+static int uhci_generic_check_and_reset_hc(struct uhci_hcd *uhci)
+{
+ unsigned int cmd, intr;
+
+ /*
+ * When restarting a suspended controller, we expect all the
+ * settings to be the same as we left them:
+ *
+ * Controller is stopped and configured with EGSM set;
+ * No interrupts enabled except possibly Resume Detect.
+ *
+ * If any of these conditions are violated we do a complete reset.
+ */
+
+ cmd = uhci_readw(uhci, USBCMD);
+ if ((cmd & USBCMD_RS) || !(cmd & USBCMD_CF) || !(cmd & USBCMD_EGSM)) {
+ dev_dbg(uhci_dev(uhci), "%s: cmd = 0x%04x\n",
+ __func__, cmd);
+ goto reset_needed;
+ }
+
+ intr = uhci_readw(uhci, USBINTR);
+ if (intr & (~USBINTR_RESUME)) {
+ dev_dbg(uhci_dev(uhci), "%s: intr = 0x%04x\n",
+ __func__, intr);
+ goto reset_needed;
+ }
+ return 0;
+
+reset_needed:
+ dev_dbg(uhci_dev(uhci), "Performing full reset\n");
+ uhci_generic_reset_hc(uhci);
+ return 1;
+}
+#endif /* CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC */
+
/*
* Store the basic register settings needed by the controller.
*/
static void configure_hc(struct uhci_hcd *uhci)
{
- struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci));
-
/* Set the frame length to the default: 1 ms exactly */
- outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF);
+ uhci_writeb(uhci, USBSOF_DEFAULT, USBSOF);
/* Store the frame list base address */
- outl(uhci->frame_dma_handle, uhci->io_addr + USBFLBASEADD);
+ uhci_writel(uhci, uhci->frame_dma_handle, USBFLBASEADD);
/* Set the current frame number */
- outw(uhci->frame_number & UHCI_MAX_SOF_NUMBER,
- uhci->io_addr + USBFRNUM);
-
- /* Mark controller as not halted before we enable interrupts */
- uhci_to_hcd(uhci)->state = HC_STATE_SUSPENDED;
- mb();
-
- /* Enable PIRQ */
- pci_write_config_word(pdev, USBLEGSUP, USBLEGSUP_DEFAULT);
+ uhci_writew(uhci, uhci->frame_number & UHCI_MAX_SOF_NUMBER,
+ USBFRNUM);
- /* Disable platform-specific non-PME# wakeup */
- if (pdev->vendor == PCI_VENDOR_ID_INTEL)
- pci_write_config_byte(pdev, USBRES_INTEL, 0);
+ /* perform any arch/bus specific configuration */
+ if (uhci->configure_hc)
+ uhci->configure_hc(uhci);
}
-
static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
{
- int port;
-
/* If we have to ignore overcurrent events then almost by definition
* we can't depend on resume-detect interrupts. */
if (ignore_oc)
return 1;
- switch (to_pci_dev(uhci_dev(uhci))->vendor) {
- default:
- break;
-
- case PCI_VENDOR_ID_GENESYS:
- /* Genesys Logic's GL880S controllers don't generate
- * resume-detect interrupts.
- */
- return 1;
-
- case PCI_VENDOR_ID_INTEL:
- /* Some of Intel's USB controllers have a bug that causes
- * resume-detect interrupts if any port has an over-current
- * condition. To make matters worse, some motherboards
- * hardwire unused USB ports' over-current inputs active!
- * To prevent problems, we will not enable resume-detect
- * interrupts if any ports are OC.
- */
- for (port = 0; port < uhci->rh_numports; ++port) {
- if (inw(uhci->io_addr + USBPORTSC1 + port * 2) &
- USBPORTSC_OC)
- return 1;
- }
- break;
- }
- return 0;
+ return uhci->resume_detect_interrupts_are_broken ?
+ uhci->resume_detect_interrupts_are_broken(uhci) : 0;
}
static int global_suspend_mode_is_broken(struct uhci_hcd *uhci)
{
- int port;
- const char *sys_info;
- static char bad_Asus_board[] = "A7V8X";
-
- /* One of Asus's motherboards has a bug which causes it to
- * wake up immediately from suspend-to-RAM if any of the ports
- * are connected. In such cases we will not set EGSM.
- */
- sys_info = dmi_get_system_info(DMI_BOARD_NAME);
- if (sys_info && !strcmp(sys_info, bad_Asus_board)) {
- for (port = 0; port < uhci->rh_numports; ++port) {
- if (inw(uhci->io_addr + USBPORTSC1 + port * 2) &
- USBPORTSC_CCS)
- return 1;
- }
- }
-
- return 0;
+ return uhci->global_suspend_mode_is_broken ?
+ uhci->global_suspend_mode_is_broken(uhci) : 0;
}
static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state)
@@ -321,8 +338,8 @@ __acquires(uhci->lock)
!int_enable)
uhci->RD_enable = int_enable = 0;
- outw(int_enable, uhci->io_addr + USBINTR);
- outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD);
+ uhci_writew(uhci, int_enable, USBINTR);
+ uhci_writew(uhci, egsm_enable | USBCMD_CF, USBCMD);
mb();
udelay(5);
@@ -331,7 +348,7 @@ __acquires(uhci->lock)
* controller should stop after a few microseconds. Otherwise
* we will give the controller one frame to stop.
*/
- if (!auto_stop && !(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) {
+ if (!auto_stop && !(uhci_readw(uhci, USBSTS) & USBSTS_HCH)) {
uhci->rh_state = UHCI_RH_SUSPENDING;
spin_unlock_irq(&uhci->lock);
msleep(1);
@@ -339,7 +356,7 @@ __acquires(uhci->lock)
if (uhci->dead)
return;
}
- if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH))
+ if (!(uhci_readw(uhci, USBSTS) & USBSTS_HCH))
dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n");
uhci_get_current_frame_number(uhci);
@@ -361,15 +378,14 @@ __acquires(uhci->lock)
static void start_rh(struct uhci_hcd *uhci)
{
- uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
uhci->is_stopped = 0;
/* Mark it configured and running with a 64-byte max packet.
* All interrupts are enabled, even though RESUME won't do anything.
*/
- outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, uhci->io_addr + USBCMD);
- outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
- uhci->io_addr + USBINTR);
+ uhci_writew(uhci, USBCMD_RS | USBCMD_CF | USBCMD_MAXP, USBCMD);
+ uhci_writew(uhci, USBINTR_TIMEOUT | USBINTR_RESUME |
+ USBINTR_IOC | USBINTR_SP, USBINTR);
mb();
uhci->rh_state = UHCI_RH_RUNNING;
set_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags);
@@ -392,9 +408,9 @@ __acquires(uhci->lock)
unsigned egsm;
/* Keep EGSM on if it was set before */
- egsm = inw(uhci->io_addr + USBCMD) & USBCMD_EGSM;
+ egsm = uhci_readw(uhci, USBCMD) & USBCMD_EGSM;
uhci->rh_state = UHCI_RH_RESUMING;
- outw(USBCMD_FGR | USBCMD_CF | egsm, uhci->io_addr + USBCMD);
+ uhci_writew(uhci, USBCMD_FGR | USBCMD_CF | egsm, USBCMD);
spin_unlock_irq(&uhci->lock);
msleep(20);
spin_lock_irq(&uhci->lock);
@@ -402,10 +418,10 @@ __acquires(uhci->lock)
return;
/* End Global Resume and wait for EOP to be sent */
- outw(USBCMD_CF, uhci->io_addr + USBCMD);
+ uhci_writew(uhci, USBCMD_CF, USBCMD);
mb();
udelay(4);
- if (inw(uhci->io_addr + USBCMD) & USBCMD_FGR)
+ if (uhci_readw(uhci, USBCMD) & USBCMD_FGR)
dev_warn(uhci_dev(uhci), "FGR not stopped yet!\n");
}
@@ -425,10 +441,10 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd)
* interrupt cause. Contrary to the UHCI specification, the
* "HC Halted" status bit is persistent: it is RO, not R/WC.
*/
- status = inw(uhci->io_addr + USBSTS);
+ status = uhci_readw(uhci, USBSTS);
if (!(status & ~USBSTS_HCH)) /* shared interrupt, not mine */
return IRQ_NONE;
- outw(status, uhci->io_addr + USBSTS); /* Clear it */
+ uhci_writew(uhci, status, USBSTS); /* Clear it */
if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
if (status & USBSTS_HSE)
@@ -450,6 +466,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd)
lprintk(errbuf);
}
uhci_hc_died(uhci);
+ usb_hc_died(hcd);
/* Force a callback in case there are
* pending unlinks */
@@ -483,7 +500,7 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci)
if (!uhci->is_stopped) {
unsigned delta;
- delta = (inw(uhci->io_addr + USBFRNUM) - uhci->frame_number) &
+ delta = (uhci_readw(uhci, USBFRNUM) - uhci->frame_number) &
(UHCI_NUMFRAMES - 1);
uhci->frame_number += delta;
}
@@ -520,61 +537,6 @@ static void release_uhci(struct uhci_hcd *uhci)
uhci->frame, uhci->frame_dma_handle);
}
-static int uhci_init(struct usb_hcd *hcd)
-{
- struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- unsigned io_size = (unsigned) hcd->rsrc_len;
- int port;
-
- uhci->io_addr = (unsigned long) hcd->rsrc_start;
-
- /* The UHCI spec says devices must have 2 ports, and goes on to say
- * they may have more but gives no way to determine how many there
- * are. However according to the UHCI spec, Bit 7 of the port
- * status and control register is always set to 1. So we try to
- * use this to our advantage. Another common failure mode when
- * a nonexistent register is addressed is to return all ones, so
- * we test for that also.
- */
- for (port = 0; port < (io_size - USBPORTSC1) / 2; port++) {
- unsigned int portstatus;
-
- portstatus = inw(uhci->io_addr + USBPORTSC1 + (port * 2));
- if (!(portstatus & 0x0080) || portstatus == 0xffff)
- break;
- }
- if (debug)
- dev_info(uhci_dev(uhci), "detected %d ports\n", port);
-
- /* Anything greater than 7 is weird so we'll ignore it. */
- if (port > UHCI_RH_MAXCHILD) {
- dev_info(uhci_dev(uhci), "port count misdetected? "
- "forcing to 2 ports\n");
- port = 2;
- }
- uhci->rh_numports = port;
-
- /* Kick BIOS off this hardware and reset if the controller
- * isn't already safely quiescent.
- */
- check_and_reset_hc(uhci);
- return 0;
-}
-
-/* Make sure the controller is quiescent and that we're not using it
- * any more. This is mainly for the benefit of programs which, like kexec,
- * expect the hardware to be idle: not doing DMA or generating IRQs.
- *
- * This routine may be called in a damaged or failing kernel. Hence we
- * do not acquire the spinlock before shutting down the controller.
- */
-static void uhci_shutdown(struct pci_dev *pdev)
-{
- struct usb_hcd *hcd = pci_get_drvdata(pdev);
-
- uhci_hc_died(hcd_to_uhci(hcd));
-}
-
/*
* Allocate a frame list, and then setup the skeleton
*
@@ -669,16 +631,16 @@ static int uhci_start(struct usb_hcd *hcd)
* 8 Interrupt queues; link all higher int queues to int1 = async
*/
for (i = SKEL_ISO + 1; i < SKEL_ASYNC; ++i)
- uhci->skelqh[i]->link = LINK_TO_QH(uhci->skel_async_qh);
- uhci->skel_async_qh->link = UHCI_PTR_TERM;
- uhci->skel_term_qh->link = LINK_TO_QH(uhci->skel_term_qh);
+ uhci->skelqh[i]->link = LINK_TO_QH(uhci, uhci->skel_async_qh);
+ uhci->skel_async_qh->link = UHCI_PTR_TERM(uhci);
+ uhci->skel_term_qh->link = LINK_TO_QH(uhci, uhci->skel_term_qh);
/* This dummy TD is to work around a bug in Intel PIIX controllers */
- uhci_fill_td(uhci->term_td, 0, uhci_explen(0) |
+ uhci_fill_td(uhci, uhci->term_td, 0, uhci_explen(0) |
(0x7f << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_IN, 0);
- uhci->term_td->link = UHCI_PTR_TERM;
+ uhci->term_td->link = UHCI_PTR_TERM(uhci);
uhci->skel_async_qh->element = uhci->skel_term_qh->element =
- LINK_TO_TD(uhci->term_td);
+ LINK_TO_TD(uhci, uhci->term_td);
/*
* Fill the frame list: make all entries point to the proper
@@ -791,86 +753,6 @@ static int uhci_rh_resume(struct usb_hcd *hcd)
return rc;
}
-static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
-{
- struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci));
- int rc = 0;
-
- dev_dbg(uhci_dev(uhci), "%s\n", __func__);
-
- spin_lock_irq(&uhci->lock);
- 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.
- */
- pci_write_config_word(pdev, USBLEGSUP, 0);
- clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
-
- /* Enable platform-specific non-PME# wakeup */
- if (do_wakeup) {
- if (pdev->vendor == PCI_VENDOR_ID_INTEL)
- pci_write_config_byte(pdev, USBRES_INTEL,
- USBPORT1EN | USBPORT2EN);
- }
-
-done_okay:
- clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-done:
- spin_unlock_irq(&uhci->lock);
- return rc;
-}
-
-static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
-{
- struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-
- dev_dbg(uhci_dev(uhci), "%s\n", __func__);
-
- /* Since we aren't in D3 any more, it's safe to set this flag
- * even if the controller was dead.
- */
- set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
- spin_lock_irq(&uhci->lock);
-
- /* Make sure resume from hibernation re-enumerates everything */
- if (hibernated)
- uhci_hc_died(uhci);
-
- /* The firmware or a boot kernel may have changed the controller
- * settings during a system wakeup. Check it and reconfigure
- * to avoid problems.
- */
- check_and_reset_hc(uhci);
-
- /* If the controller was dead before, it's back alive now */
- configure_hc(uhci);
-
- /* Tell the core if the controller had to be reset */
- if (uhci->rh_state == UHCI_RH_RESET)
- usb_root_hub_lost_power(hcd->self.root_hub);
-
- spin_unlock_irq(&uhci->lock);
-
- /* If interrupts don't work and remote wakeup is enabled then
- * the suspended root hub needs to be polled.
- */
- if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup)
- set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
-
- /* Does the root hub have a port wakeup pending? */
- usb_hcd_poll_rh_status(hcd);
- return 0;
-}
#endif
/* Wait until a particular device/endpoint's QH is idle, and free it */
@@ -908,67 +790,62 @@ static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
/* Minimize latency by avoiding the spinlock */
frame_number = uhci->frame_number;
barrier();
- delta = (inw(uhci->io_addr + USBFRNUM) - frame_number) &
+ delta = (uhci_readw(uhci, USBFRNUM) - frame_number) &
(UHCI_NUMFRAMES - 1);
return frame_number + delta;
}
-static const char hcd_name[] = "uhci_hcd";
-
-static const struct hc_driver uhci_driver = {
- .description = hcd_name,
- .product_desc = "UHCI Host Controller",
- .hcd_priv_size = sizeof(struct uhci_hcd),
-
- /* Generic hardware linkage */
- .irq = uhci_irq,
- .flags = HCD_USB11,
-
- /* Basic lifecycle operations */
- .reset = uhci_init,
- .start = uhci_start,
-#ifdef CONFIG_PM
- .pci_suspend = uhci_pci_suspend,
- .pci_resume = uhci_pci_resume,
- .bus_suspend = uhci_rh_suspend,
- .bus_resume = uhci_rh_resume,
-#endif
- .stop = uhci_stop,
+/* Determines number of ports on controller */
+static int uhci_count_ports(struct usb_hcd *hcd)
+{
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+ unsigned io_size = (unsigned) hcd->rsrc_len;
+ int port;
- .urb_enqueue = uhci_urb_enqueue,
- .urb_dequeue = uhci_urb_dequeue,
+ /* The UHCI spec says devices must have 2 ports, and goes on to say
+ * they may have more but gives no way to determine how many there
+ * are. However according to the UHCI spec, Bit 7 of the port
+ * status and control register is always set to 1. So we try to
+ * use this to our advantage. Another common failure mode when
+ * a nonexistent register is addressed is to return all ones, so
+ * we test for that also.
+ */
+ for (port = 0; port < (io_size - USBPORTSC1) / 2; port++) {
+ unsigned int portstatus;
- .endpoint_disable = uhci_hcd_endpoint_disable,
- .get_frame_number = uhci_hcd_get_frame_number,
+ portstatus = uhci_readw(uhci, USBPORTSC1 + (port * 2));
+ if (!(portstatus & 0x0080) || portstatus == 0xffff)
+ break;
+ }
+ if (debug)
+ dev_info(uhci_dev(uhci), "detected %d ports\n", port);
- .hub_status_data = uhci_hub_status_data,
- .hub_control = uhci_hub_control,
-};
+ /* Anything greater than 7 is weird so we'll ignore it. */
+ if (port > UHCI_RH_MAXCHILD) {
+ dev_info(uhci_dev(uhci), "port count misdetected? "
+ "forcing to 2 ports\n");
+ port = 2;
+ }
-static const struct pci_device_id uhci_pci_ids[] = { {
- /* handle any USB UHCI controller */
- PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_UHCI, ~0),
- .driver_data = (unsigned long) &uhci_driver,
- }, { /* end: all zeroes */ }
-};
+ return port;
+}
-MODULE_DEVICE_TABLE(pci, uhci_pci_ids);
+static const char hcd_name[] = "uhci_hcd";
-static struct pci_driver uhci_pci_driver = {
- .name = (char *)hcd_name,
- .id_table = uhci_pci_ids,
+#ifdef CONFIG_PCI
+#include "uhci-pci.c"
+#define PCI_DRIVER uhci_pci_driver
+#endif
- .probe = usb_hcd_pci_probe,
- .remove = usb_hcd_pci_remove,
- .shutdown = uhci_shutdown,
+#ifdef CONFIG_SPARC_LEON
+#include "uhci-grlib.c"
+#define PLATFORM_DRIVER uhci_grlib_driver
+#endif
-#ifdef CONFIG_PM_SLEEP
- .driver = {
- .pm = &usb_hcd_pci_pm_ops
- },
+#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER)
+#error "missing bus glue for uhci-hcd"
#endif
-};
-
+
static int __init uhci_hcd_init(void)
{
int retval = -ENOMEM;
@@ -994,13 +871,27 @@ static int __init uhci_hcd_init(void)
if (!uhci_up_cachep)
goto up_failed;
- retval = pci_register_driver(&uhci_pci_driver);
- if (retval)
- goto init_failed;
+#ifdef PLATFORM_DRIVER
+ retval = platform_driver_register(&PLATFORM_DRIVER);
+ if (retval < 0)
+ goto clean0;
+#endif
+
+#ifdef PCI_DRIVER
+ retval = pci_register_driver(&PCI_DRIVER);
+ if (retval < 0)
+ goto clean1;
+#endif
return 0;
-init_failed:
+#ifdef PCI_DRIVER
+clean1:
+#endif
+#ifdef PLATFORM_DRIVER
+ platform_driver_unregister(&PLATFORM_DRIVER);
+clean0:
+#endif
kmem_cache_destroy(uhci_up_cachep);
up_failed:
@@ -1017,7 +908,12 @@ errbuf_failed:
static void __exit uhci_hcd_cleanup(void)
{
- pci_unregister_driver(&uhci_pci_driver);
+#ifdef PLATFORM_DRIVER
+ platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+#ifdef PCI_DRIVER
+ pci_unregister_driver(&PCI_DRIVER);
+#endif
kmem_cache_destroy(uhci_up_cachep);
debugfs_remove(uhci_debugfs_root);
kfree(errbuf);
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 49bf2790f9c2..7af2b7052047 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -78,11 +78,11 @@
#define USBPORT1EN 0x01
#define USBPORT2EN 0x02
-#define UHCI_PTR_BITS cpu_to_le32(0x000F)
-#define UHCI_PTR_TERM cpu_to_le32(0x0001)
-#define UHCI_PTR_QH cpu_to_le32(0x0002)
-#define UHCI_PTR_DEPTH cpu_to_le32(0x0004)
-#define UHCI_PTR_BREADTH cpu_to_le32(0x0000)
+#define UHCI_PTR_BITS(uhci) cpu_to_hc32((uhci), 0x000F)
+#define UHCI_PTR_TERM(uhci) cpu_to_hc32((uhci), 0x0001)
+#define UHCI_PTR_QH(uhci) cpu_to_hc32((uhci), 0x0002)
+#define UHCI_PTR_DEPTH(uhci) cpu_to_hc32((uhci), 0x0004)
+#define UHCI_PTR_BREADTH(uhci) cpu_to_hc32((uhci), 0x0000)
#define UHCI_NUMFRAMES 1024 /* in the frame list [array] */
#define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */
@@ -99,6 +99,22 @@
/*
+ * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
+ * __leXX (normally) or __beXX (given UHCI_BIG_ENDIAN_DESC), depending on
+ * the host controller implementation.
+ *
+ * To facilitate the strongest possible byte-order checking from "sparse"
+ * and so on, we use __leXX unless that's not practical.
+ */
+#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_DESC
+typedef __u32 __bitwise __hc32;
+typedef __u16 __bitwise __hc16;
+#else
+#define __hc32 __le32
+#define __hc16 __le16
+#endif
+
+/*
* Queue Headers
*/
@@ -130,8 +146,8 @@
struct uhci_qh {
/* Hardware fields */
- __le32 link; /* Next QH in the schedule */
- __le32 element; /* Queue element (TD) pointer */
+ __hc32 link; /* Next QH in the schedule */
+ __hc32 element; /* Queue element (TD) pointer */
/* Software fields */
dma_addr_t dma_handle;
@@ -168,14 +184,10 @@ struct uhci_qh {
* We need a special accessor for the element pointer because it is
* subject to asynchronous updates by the controller.
*/
-static inline __le32 qh_element(struct uhci_qh *qh) {
- __le32 element = qh->element;
+#define qh_element(qh) ACCESS_ONCE((qh)->element)
- barrier();
- return element;
-}
-
-#define LINK_TO_QH(qh) (UHCI_PTR_QH | cpu_to_le32((qh)->dma_handle))
+#define LINK_TO_QH(uhci, qh) (UHCI_PTR_QH((uhci)) | \
+ cpu_to_hc32((uhci), (qh)->dma_handle))
/*
@@ -212,7 +224,7 @@ static inline __le32 qh_element(struct uhci_qh *qh) {
/*
* for TD <info>: (a.k.a. Token)
*/
-#define td_token(td) le32_to_cpu((td)->token)
+#define td_token(uhci, td) hc32_to_cpu((uhci), (td)->token)
#define TD_TOKEN_DEVADDR_SHIFT 8
#define TD_TOKEN_TOGGLE_SHIFT 19
#define TD_TOKEN_TOGGLE (1 << 19)
@@ -245,10 +257,10 @@ static inline __le32 qh_element(struct uhci_qh *qh) {
*/
struct uhci_td {
/* Hardware fields */
- __le32 link;
- __le32 status;
- __le32 token;
- __le32 buffer;
+ __hc32 link;
+ __hc32 status;
+ __hc32 token;
+ __hc32 buffer;
/* Software fields */
dma_addr_t dma_handle;
@@ -263,14 +275,10 @@ struct uhci_td {
* We need a special accessor for the control/status word because it is
* subject to asynchronous updates by the controller.
*/
-static inline u32 td_status(struct uhci_td *td) {
- __le32 status = td->status;
+#define td_status(uhci, td) hc32_to_cpu((uhci), \
+ ACCESS_ONCE((td)->status))
- barrier();
- return le32_to_cpu(status);
-}
-
-#define LINK_TO_TD(td) (cpu_to_le32((td)->dma_handle))
+#define LINK_TO_TD(uhci, td) (cpu_to_hc32((uhci), (td)->dma_handle))
/*
@@ -380,6 +388,9 @@ struct uhci_hcd {
/* Grabbed from PCI */
unsigned long io_addr;
+ /* Used when registers are memory mapped */
+ void __iomem *regs;
+
struct dma_pool *qh_pool;
struct dma_pool *td_pool;
@@ -390,7 +401,7 @@ struct uhci_hcd {
spinlock_t lock;
dma_addr_t frame_dma_handle; /* Hardware frame list */
- __le32 *frame;
+ __hc32 *frame;
void **frame_cpu; /* CPU's frame list */
enum uhci_rh_state rh_state;
@@ -415,6 +426,12 @@ struct uhci_hcd {
struct timer_list fsbr_timer; /* For turning off FBSR */
+ /* Silicon quirks */
+ unsigned int oc_low:1; /* OverCurrent bit active low */
+ unsigned int wait_for_hp:1; /* Wait for HP port reset */
+ unsigned int big_endian_mmio:1; /* Big endian registers */
+ unsigned int big_endian_desc:1; /* Big endian descriptors */
+
/* Support for port suspend/resume/reset */
unsigned long port_c_suspend; /* Bit-arrays of ports */
unsigned long resuming_ports;
@@ -429,6 +446,16 @@ struct uhci_hcd {
int total_load; /* Sum of array values */
short load[MAX_PHASE]; /* Periodic allocations */
+
+ /* Reset host controller */
+ void (*reset_hc) (struct uhci_hcd *uhci);
+ int (*check_and_reset_hc) (struct uhci_hcd *uhci);
+ /* configure_hc should perform arch specific settings, if needed */
+ void (*configure_hc) (struct uhci_hcd *uhci);
+ /* Check for broken resume detect interrupts */
+ int (*resume_detect_interrupts_are_broken) (struct uhci_hcd *uhci);
+ /* Check for broken global suspend */
+ int (*global_suspend_mode_is_broken) (struct uhci_hcd *uhci);
};
/* Convert between a usb_hcd pointer and the corresponding uhci_hcd */
@@ -467,4 +494,171 @@ struct urb_priv {
#define PCI_VENDOR_ID_GENESYS 0x17a0
#define PCI_DEVICE_ID_GL880S_UHCI 0x8083
+/*
+ * Functions used to access controller registers. The UCHI spec says that host
+ * controller I/O registers are mapped into PCI I/O space. For non-PCI hosts
+ * we use memory mapped registers.
+ */
+
+#ifndef CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC
+/* Support PCI only */
+static inline u32 uhci_readl(const struct uhci_hcd *uhci, int reg)
+{
+ return inl(uhci->io_addr + reg);
+}
+
+static inline void uhci_writel(const struct uhci_hcd *uhci, u32 val, int reg)
+{
+ outl(val, uhci->io_addr + reg);
+}
+
+static inline u16 uhci_readw(const struct uhci_hcd *uhci, int reg)
+{
+ return inw(uhci->io_addr + reg);
+}
+
+static inline void uhci_writew(const struct uhci_hcd *uhci, u16 val, int reg)
+{
+ outw(val, uhci->io_addr + reg);
+}
+
+static inline u8 uhci_readb(const struct uhci_hcd *uhci, int reg)
+{
+ return inb(uhci->io_addr + reg);
+}
+
+static inline void uhci_writeb(const struct uhci_hcd *uhci, u8 val, int reg)
+{
+ outb(val, uhci->io_addr + reg);
+}
+
+#else
+/* Support non-PCI host controllers */
+#ifdef CONFIG_PCI
+/* Support PCI and non-PCI host controllers */
+#define uhci_has_pci_registers(u) ((u)->io_addr != 0)
+#else
+/* Support non-PCI host controllers only */
+#define uhci_has_pci_registers(u) 0
+#endif
+
+#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
+/* Support (non-PCI) big endian host controllers */
+#define uhci_big_endian_mmio(u) ((u)->big_endian_mmio)
+#else
+#define uhci_big_endian_mmio(u) 0
+#endif
+
+static inline u32 uhci_readl(const struct uhci_hcd *uhci, int reg)
+{
+ if (uhci_has_pci_registers(uhci))
+ return inl(uhci->io_addr + reg);
+#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
+ else if (uhci_big_endian_mmio(uhci))
+ return readl_be(uhci->regs + reg);
+#endif
+ else
+ return readl(uhci->regs + reg);
+}
+
+static inline void uhci_writel(const struct uhci_hcd *uhci, u32 val, int reg)
+{
+ if (uhci_has_pci_registers(uhci))
+ outl(val, uhci->io_addr + reg);
+#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
+ else if (uhci_big_endian_mmio(uhci))
+ writel_be(val, uhci->regs + reg);
+#endif
+ else
+ writel(val, uhci->regs + reg);
+}
+
+static inline u16 uhci_readw(const struct uhci_hcd *uhci, int reg)
+{
+ if (uhci_has_pci_registers(uhci))
+ return inw(uhci->io_addr + reg);
+#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
+ else if (uhci_big_endian_mmio(uhci))
+ return readw_be(uhci->regs + reg);
+#endif
+ else
+ return readw(uhci->regs + reg);
+}
+
+static inline void uhci_writew(const struct uhci_hcd *uhci, u16 val, int reg)
+{
+ if (uhci_has_pci_registers(uhci))
+ outw(val, uhci->io_addr + reg);
+#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
+ else if (uhci_big_endian_mmio(uhci))
+ writew_be(val, uhci->regs + reg);
+#endif
+ else
+ writew(val, uhci->regs + reg);
+}
+
+static inline u8 uhci_readb(const struct uhci_hcd *uhci, int reg)
+{
+ if (uhci_has_pci_registers(uhci))
+ return inb(uhci->io_addr + reg);
+#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
+ else if (uhci_big_endian_mmio(uhci))
+ return readb_be(uhci->regs + reg);
+#endif
+ else
+ return readb(uhci->regs + reg);
+}
+
+static inline void uhci_writeb(const struct uhci_hcd *uhci, u8 val, int reg)
+{
+ if (uhci_has_pci_registers(uhci))
+ outb(val, uhci->io_addr + reg);
+#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
+ else if (uhci_big_endian_mmio(uhci))
+ writeb_be(val, uhci->regs + reg);
+#endif
+ else
+ writeb(val, uhci->regs + reg);
+}
+#endif /* CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC */
+
+/*
+ * The GRLIB GRUSBHC controller can use big endian format for its descriptors.
+ *
+ * UHCI controllers accessed through PCI work normally (little-endian
+ * everywhere), so we don't bother supporting a BE-only mode.
+ */
+#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_DESC
+#define uhci_big_endian_desc(u) ((u)->big_endian_desc)
+
+/* cpu to uhci */
+static inline __hc32 cpu_to_hc32(const struct uhci_hcd *uhci, const u32 x)
+{
+ return uhci_big_endian_desc(uhci)
+ ? (__force __hc32)cpu_to_be32(x)
+ : (__force __hc32)cpu_to_le32(x);
+}
+
+/* uhci to cpu */
+static inline u32 hc32_to_cpu(const struct uhci_hcd *uhci, const __hc32 x)
+{
+ return uhci_big_endian_desc(uhci)
+ ? be32_to_cpu((__force __be32)x)
+ : le32_to_cpu((__force __le32)x);
+}
+
+#else
+/* cpu to uhci */
+static inline __hc32 cpu_to_hc32(const struct uhci_hcd *uhci, const u32 x)
+{
+ return cpu_to_le32(x);
+}
+
+/* uhci to cpu */
+static inline u32 hc32_to_cpu(const struct uhci_hcd *uhci, const __hc32 x)
+{
+ return le32_to_cpu(x);
+}
+#endif
+
#endif
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
index 6d59c0f77f25..045cde4cbc3d 100644
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -44,7 +44,7 @@ static int any_ports_active(struct uhci_hcd *uhci)
int port;
for (port = 0; port < uhci->rh_numports; ++port) {
- if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) &
+ if ((uhci_readw(uhci, USBPORTSC1 + port * 2) &
(USBPORTSC_CCS | RWC_BITS)) ||
test_bit(port, &uhci->port_c_suspend))
return 1;
@@ -68,7 +68,7 @@ static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf)
*buf = 0;
for (port = 0; port < uhci->rh_numports; ++port) {
- if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & mask) ||
+ if ((uhci_readw(uhci, USBPORTSC1 + port * 2) & mask) ||
test_bit(port, &uhci->port_c_suspend))
*buf |= (1 << (port + 1));
}
@@ -78,17 +78,17 @@ static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf)
#define OK(x) len = (x); break
#define CLR_RH_PORTSTAT(x) \
- status = inw(port_addr); \
+ status = uhci_readw(uhci, port_addr); \
status &= ~(RWC_BITS|WZ_BITS); \
status &= ~(x); \
status |= RWC_BITS & (x); \
- outw(status, port_addr)
+ uhci_writew(uhci, status, port_addr)
#define SET_RH_PORTSTAT(x) \
- status = inw(port_addr); \
+ status = uhci_readw(uhci, port_addr); \
status |= (x); \
status &= ~(RWC_BITS|WZ_BITS); \
- outw(status, port_addr)
+ uhci_writew(uhci, status, port_addr)
/* UHCI controllers don't automatically stop resume signalling after 20 msec,
* so we have to poll and check timeouts in order to take care of it.
@@ -99,7 +99,7 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
int status;
int i;
- if (inw(port_addr) & SUSPEND_BITS) {
+ if (uhci_readw(uhci, port_addr) & SUSPEND_BITS) {
CLR_RH_PORTSTAT(SUSPEND_BITS);
if (test_bit(port, &uhci->resuming_ports))
set_bit(port, &uhci->port_c_suspend);
@@ -110,7 +110,7 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
* Experiments show that some controllers take longer, so
* we'll poll for completion. */
for (i = 0; i < 10; ++i) {
- if (!(inw(port_addr) & SUSPEND_BITS))
+ if (!(uhci_readw(uhci, port_addr) & SUSPEND_BITS))
break;
udelay(1);
}
@@ -121,12 +121,12 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
/* Wait for the UHCI controller in HP's iLO2 server management chip.
* It can take up to 250 us to finish a reset and set the CSC bit.
*/
-static void wait_for_HP(unsigned long port_addr)
+static void wait_for_HP(struct uhci_hcd *uhci, unsigned long port_addr)
{
int i;
for (i = 10; i < 250; i += 10) {
- if (inw(port_addr) & USBPORTSC_CSC)
+ if (uhci_readw(uhci, port_addr) & USBPORTSC_CSC)
return;
udelay(10);
}
@@ -140,8 +140,8 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
int status;
for (port = 0; port < uhci->rh_numports; ++port) {
- port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
- status = inw(port_addr);
+ port_addr = USBPORTSC1 + 2 * port;
+ status = uhci_readw(uhci, port_addr);
if (unlikely(status & USBPORTSC_PR)) {
if (time_after_eq(jiffies, uhci->ports_timeout)) {
CLR_RH_PORTSTAT(USBPORTSC_PR);
@@ -149,9 +149,8 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
/* HP's server management chip requires
* a longer delay. */
- if (to_pci_dev(uhci_dev(uhci))->vendor ==
- PCI_VENDOR_ID_HP)
- wait_for_HP(port_addr);
+ if (uhci->wait_for_hp)
+ wait_for_HP(uhci, port_addr);
/* If the port was enabled before, turning
* reset on caused a port enable change.
@@ -242,7 +241,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
int status, lstatus, retval = 0, len = 0;
unsigned int port = wIndex - 1;
- unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
+ unsigned long port_addr = USBPORTSC1 + 2 * port;
u16 wPortChange, wPortStatus;
unsigned long flags;
@@ -260,14 +259,13 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
goto err;
uhci_check_ports(uhci);
- status = inw(port_addr);
+ status = uhci_readw(uhci, port_addr);
/* Intel controllers report the OverCurrent bit active on.
* VIA controllers report it active off, so we'll adjust the
* bit value. (It's not standardized in the UHCI spec.)
*/
- if (to_pci_dev(hcd->self.controller)->vendor ==
- PCI_VENDOR_ID_VIA)
+ if (uhci->oc_low)
status ^= USBPORTSC_OC;
/* UHCI doesn't support C_RESET (always false) */
@@ -358,7 +356,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
CLR_RH_PORTSTAT(USBPORTSC_PEC);
OK(0);
case USB_PORT_FEAT_SUSPEND:
- if (!(inw(port_addr) & USBPORTSC_SUSP)) {
+ if (!(uhci_readw(uhci, port_addr) & USBPORTSC_SUSP)) {
/* Make certain the port isn't suspended */
uhci_finish_suspend(uhci, port, port_addr);
@@ -370,7 +368,8 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
* if the port is disabled. When this happens
* just skip the Resume signalling.
*/
- if (!(inw(port_addr) & USBPORTSC_RD))
+ if (!(uhci_readw(uhci, port_addr) &
+ USBPORTSC_RD))
uhci_finish_suspend(uhci, port,
port_addr);
else
diff --git a/drivers/usb/host/uhci-pci.c b/drivers/usb/host/uhci-pci.c
new file mode 100644
index 000000000000..c300bd2f7d1c
--- /dev/null
+++ b/drivers/usb/host/uhci-pci.c
@@ -0,0 +1,301 @@
+/*
+ * UHCI HCD (Host Controller Driver) PCI Bus Glue.
+ *
+ * Extracted from uhci-hcd.c:
+ * Maintainer: Alan Stern <stern@rowland.harvard.edu>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu
+ */
+
+#include "pci-quirks.h"
+
+/*
+ * Make sure the controller is completely inactive, unable to
+ * generate interrupts or do DMA.
+ */
+static void uhci_pci_reset_hc(struct uhci_hcd *uhci)
+{
+ uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr);
+}
+
+/*
+ * Initialize a controller that was newly discovered or has just been
+ * resumed. In either case we can't be sure of its previous state.
+ *
+ * Returns: 1 if the controller was reset, 0 otherwise.
+ */
+static int uhci_pci_check_and_reset_hc(struct uhci_hcd *uhci)
+{
+ return uhci_check_and_reset_hc(to_pci_dev(uhci_dev(uhci)),
+ uhci->io_addr);
+}
+
+/*
+ * Store the basic register settings needed by the controller.
+ * This function is called at the end of configure_hc in uhci-hcd.c.
+ */
+static void uhci_pci_configure_hc(struct uhci_hcd *uhci)
+{
+ struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci));
+
+ /* Enable PIRQ */
+ pci_write_config_word(pdev, USBLEGSUP, USBLEGSUP_DEFAULT);
+
+ /* Disable platform-specific non-PME# wakeup */
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL)
+ pci_write_config_byte(pdev, USBRES_INTEL, 0);
+}
+
+static int uhci_pci_resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
+{
+ int port;
+
+ switch (to_pci_dev(uhci_dev(uhci))->vendor) {
+ default:
+ break;
+
+ case PCI_VENDOR_ID_GENESYS:
+ /* Genesys Logic's GL880S controllers don't generate
+ * resume-detect interrupts.
+ */
+ return 1;
+
+ case PCI_VENDOR_ID_INTEL:
+ /* Some of Intel's USB controllers have a bug that causes
+ * resume-detect interrupts if any port has an over-current
+ * condition. To make matters worse, some motherboards
+ * hardwire unused USB ports' over-current inputs active!
+ * To prevent problems, we will not enable resume-detect
+ * interrupts if any ports are OC.
+ */
+ for (port = 0; port < uhci->rh_numports; ++port) {
+ if (inw(uhci->io_addr + USBPORTSC1 + port * 2) &
+ USBPORTSC_OC)
+ return 1;
+ }
+ break;
+ }
+ return 0;
+}
+
+static int uhci_pci_global_suspend_mode_is_broken(struct uhci_hcd *uhci)
+{
+ int port;
+ const char *sys_info;
+ static const char bad_Asus_board[] = "A7V8X";
+
+ /* One of Asus's motherboards has a bug which causes it to
+ * wake up immediately from suspend-to-RAM if any of the ports
+ * are connected. In such cases we will not set EGSM.
+ */
+ sys_info = dmi_get_system_info(DMI_BOARD_NAME);
+ if (sys_info && !strcmp(sys_info, bad_Asus_board)) {
+ for (port = 0; port < uhci->rh_numports; ++port) {
+ if (inw(uhci->io_addr + USBPORTSC1 + port * 2) &
+ USBPORTSC_CCS)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int uhci_pci_init(struct usb_hcd *hcd)
+{
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+
+ uhci->io_addr = (unsigned long) hcd->rsrc_start;
+
+ uhci->rh_numports = uhci_count_ports(hcd);
+
+ /* Intel controllers report the OverCurrent bit active on.
+ * VIA controllers report it active off, so we'll adjust the
+ * bit value. (It's not standardized in the UHCI spec.)
+ */
+ if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_VIA)
+ uhci->oc_low = 1;
+
+ /* HP's server management chip requires a longer port reset delay. */
+ if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_HP)
+ uhci->wait_for_hp = 1;
+
+ /* Set up pointers to PCI-specific functions */
+ uhci->reset_hc = uhci_pci_reset_hc;
+ uhci->check_and_reset_hc = uhci_pci_check_and_reset_hc;
+ uhci->configure_hc = uhci_pci_configure_hc;
+ uhci->resume_detect_interrupts_are_broken =
+ uhci_pci_resume_detect_interrupts_are_broken;
+ uhci->global_suspend_mode_is_broken =
+ uhci_pci_global_suspend_mode_is_broken;
+
+
+ /* Kick BIOS off this hardware and reset if the controller
+ * isn't already safely quiescent.
+ */
+ check_and_reset_hc(uhci);
+ return 0;
+}
+
+/* Make sure the controller is quiescent and that we're not using it
+ * any more. This is mainly for the benefit of programs which, like kexec,
+ * expect the hardware to be idle: not doing DMA or generating IRQs.
+ *
+ * This routine may be called in a damaged or failing kernel. Hence we
+ * do not acquire the spinlock before shutting down the controller.
+ */
+static void uhci_shutdown(struct pci_dev *pdev)
+{
+ struct usb_hcd *hcd = pci_get_drvdata(pdev);
+
+ uhci_hc_died(hcd_to_uhci(hcd));
+}
+
+#ifdef CONFIG_PM
+
+static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
+{
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+ struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci));
+ int rc = 0;
+
+ dev_dbg(uhci_dev(uhci), "%s\n", __func__);
+
+ spin_lock_irq(&uhci->lock);
+ 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.
+ */
+ pci_write_config_word(pdev, USBLEGSUP, 0);
+ clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+
+ /* Enable platform-specific non-PME# wakeup */
+ if (do_wakeup) {
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL)
+ pci_write_config_byte(pdev, USBRES_INTEL,
+ USBPORT1EN | USBPORT2EN);
+ }
+
+done_okay:
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+done:
+ spin_unlock_irq(&uhci->lock);
+ return rc;
+}
+
+static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
+{
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+
+ dev_dbg(uhci_dev(uhci), "%s\n", __func__);
+
+ /* Since we aren't in D3 any more, it's safe to set this flag
+ * even if the controller was dead.
+ */
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+ spin_lock_irq(&uhci->lock);
+
+ /* Make sure resume from hibernation re-enumerates everything */
+ if (hibernated) {
+ uhci->reset_hc(uhci);
+ finish_reset(uhci);
+ }
+
+ /* The firmware may have changed the controller settings during
+ * a system wakeup. Check it and reconfigure to avoid problems.
+ */
+ else {
+ check_and_reset_hc(uhci);
+ }
+ configure_hc(uhci);
+
+ /* Tell the core if the controller had to be reset */
+ if (uhci->rh_state == UHCI_RH_RESET)
+ usb_root_hub_lost_power(hcd->self.root_hub);
+
+ spin_unlock_irq(&uhci->lock);
+
+ /* If interrupts don't work and remote wakeup is enabled then
+ * the suspended root hub needs to be polled.
+ */
+ if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup)
+ set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+
+ /* Does the root hub have a port wakeup pending? */
+ usb_hcd_poll_rh_status(hcd);
+ return 0;
+}
+
+#endif
+
+static const struct hc_driver uhci_driver = {
+ .description = hcd_name,
+ .product_desc = "UHCI Host Controller",
+ .hcd_priv_size = sizeof(struct uhci_hcd),
+
+ /* Generic hardware linkage */
+ .irq = uhci_irq,
+ .flags = HCD_USB11,
+
+ /* Basic lifecycle operations */
+ .reset = uhci_pci_init,
+ .start = uhci_start,
+#ifdef CONFIG_PM
+ .pci_suspend = uhci_pci_suspend,
+ .pci_resume = uhci_pci_resume,
+ .bus_suspend = uhci_rh_suspend,
+ .bus_resume = uhci_rh_resume,
+#endif
+ .stop = uhci_stop,
+
+ .urb_enqueue = uhci_urb_enqueue,
+ .urb_dequeue = uhci_urb_dequeue,
+
+ .endpoint_disable = uhci_hcd_endpoint_disable,
+ .get_frame_number = uhci_hcd_get_frame_number,
+
+ .hub_status_data = uhci_hub_status_data,
+ .hub_control = uhci_hub_control,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(uhci_pci_ids) = { {
+ /* handle any USB UHCI controller */
+ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_UHCI, ~0),
+ .driver_data = (unsigned long) &uhci_driver,
+ }, { /* end: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE(pci, uhci_pci_ids);
+
+static struct pci_driver uhci_pci_driver = {
+ .name = (char *)hcd_name,
+ .id_table = uhci_pci_ids,
+
+ .probe = usb_hcd_pci_probe,
+ .remove = usb_hcd_pci_remove,
+ .shutdown = uhci_shutdown,
+
+#ifdef CONFIG_PM_SLEEP
+ .driver = {
+ .pm = &usb_hcd_pci_pm_ops
+ },
+#endif
+};
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index af77abb5c68b..84ed28b34f93 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -29,12 +29,12 @@ static void uhci_set_next_interrupt(struct uhci_hcd *uhci)
{
if (uhci->is_stopped)
mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
- uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC);
+ uhci->term_td->status |= cpu_to_hc32(uhci, TD_CTRL_IOC);
}
static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
{
- uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC);
+ uhci->term_td->status &= ~cpu_to_hc32(uhci, TD_CTRL_IOC);
}
@@ -53,7 +53,7 @@ static void uhci_fsbr_on(struct uhci_hcd *uhci)
uhci->fsbr_is_on = 1;
lqh = list_entry(uhci->skel_async_qh->node.prev,
struct uhci_qh, node);
- lqh->link = LINK_TO_QH(uhci->skel_term_qh);
+ lqh->link = LINK_TO_QH(uhci, uhci->skel_term_qh);
}
static void uhci_fsbr_off(struct uhci_hcd *uhci)
@@ -65,7 +65,7 @@ static void uhci_fsbr_off(struct uhci_hcd *uhci)
uhci->fsbr_is_on = 0;
lqh = list_entry(uhci->skel_async_qh->node.prev,
struct uhci_qh, node);
- lqh->link = UHCI_PTR_TERM;
+ lqh->link = UHCI_PTR_TERM(uhci);
}
static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb)
@@ -131,12 +131,12 @@ static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
dma_pool_free(uhci->td_pool, td, td->dma_handle);
}
-static inline void uhci_fill_td(struct uhci_td *td, u32 status,
- u32 token, u32 buffer)
+static inline void uhci_fill_td(struct uhci_hcd *uhci, struct uhci_td *td,
+ u32 status, u32 token, u32 buffer)
{
- td->status = cpu_to_le32(status);
- td->token = cpu_to_le32(token);
- td->buffer = cpu_to_le32(buffer);
+ td->status = cpu_to_hc32(uhci, status);
+ td->token = cpu_to_hc32(uhci, token);
+ td->buffer = cpu_to_hc32(uhci, buffer);
}
static void uhci_add_td_to_urbp(struct uhci_td *td, struct urb_priv *urbp)
@@ -170,11 +170,11 @@ static inline void uhci_insert_td_in_frame_list(struct uhci_hcd *uhci,
td->link = ltd->link;
wmb();
- ltd->link = LINK_TO_TD(td);
+ ltd->link = LINK_TO_TD(uhci, td);
} else {
td->link = uhci->frame[framenum];
wmb();
- uhci->frame[framenum] = LINK_TO_TD(td);
+ uhci->frame[framenum] = LINK_TO_TD(uhci, td);
uhci->frame_cpu[framenum] = td;
}
}
@@ -198,7 +198,7 @@ static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci,
ntd = list_entry(td->fl_list.next,
struct uhci_td,
fl_list);
- uhci->frame[td->frame] = LINK_TO_TD(ntd);
+ uhci->frame[td->frame] = LINK_TO_TD(uhci, ntd);
uhci->frame_cpu[td->frame] = ntd;
}
} else {
@@ -255,8 +255,8 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
memset(qh, 0, sizeof(*qh));
qh->dma_handle = dma_handle;
- qh->element = UHCI_PTR_TERM;
- qh->link = UHCI_PTR_TERM;
+ qh->element = UHCI_PTR_TERM(uhci);
+ qh->link = UHCI_PTR_TERM(uhci);
INIT_LIST_HEAD(&qh->queue);
INIT_LIST_HEAD(&qh->node);
@@ -348,9 +348,9 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh,
/* If the QH element pointer is UHCI_PTR_TERM then then currently
* executing URB has already been unlinked, so this one isn't it. */
- if (qh_element(qh) == UHCI_PTR_TERM)
+ if (qh_element(qh) == UHCI_PTR_TERM(uhci))
goto done;
- qh->element = UHCI_PTR_TERM;
+ qh->element = UHCI_PTR_TERM(uhci);
/* Control pipes don't have to worry about toggles */
if (qh->type == USB_ENDPOINT_XFER_CONTROL)
@@ -360,7 +360,7 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh,
WARN_ON(list_empty(&urbp->td_list));
td = list_entry(urbp->td_list.next, struct uhci_td, list);
qh->needs_fixup = 1;
- qh->initial_toggle = uhci_toggle(td_token(td));
+ qh->initial_toggle = uhci_toggle(td_token(uhci, td));
done:
return ret;
@@ -370,7 +370,8 @@ done:
* Fix up the data toggles for URBs in a queue, when one of them
* terminates early (short transfer, error, or dequeued).
*/
-static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first)
+static void uhci_fixup_toggles(struct uhci_hcd *uhci, struct uhci_qh *qh,
+ int skip_first)
{
struct urb_priv *urbp = NULL;
struct uhci_td *td;
@@ -384,7 +385,7 @@ static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first)
/* When starting with the first URB, if the QH element pointer is
* still valid then we know the URB's toggles are okay. */
- else if (qh_element(qh) != UHCI_PTR_TERM)
+ else if (qh_element(qh) != UHCI_PTR_TERM(uhci))
toggle = 2;
/* Fix up the toggle for the URBs in the queue. Normally this
@@ -396,15 +397,15 @@ static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first)
/* If the first TD has the right toggle value, we don't
* need to change any toggles in this URB */
td = list_entry(urbp->td_list.next, struct uhci_td, list);
- if (toggle > 1 || uhci_toggle(td_token(td)) == toggle) {
+ if (toggle > 1 || uhci_toggle(td_token(uhci, td)) == toggle) {
td = list_entry(urbp->td_list.prev, struct uhci_td,
list);
- toggle = uhci_toggle(td_token(td)) ^ 1;
+ toggle = uhci_toggle(td_token(uhci, td)) ^ 1;
/* Otherwise all the toggles in the URB have to be switched */
} else {
list_for_each_entry(td, &urbp->td_list, list) {
- td->token ^= cpu_to_le32(
+ td->token ^= cpu_to_hc32(uhci,
TD_TOKEN_TOGGLE);
toggle ^= 1;
}
@@ -441,7 +442,7 @@ static void link_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh)
pqh = list_entry(qh->node.prev, struct uhci_qh, node);
qh->link = pqh->link;
wmb();
- pqh->link = LINK_TO_QH(qh);
+ pqh->link = LINK_TO_QH(uhci, qh);
}
/*
@@ -451,7 +452,7 @@ static void link_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh)
static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
{
struct uhci_qh *pqh;
- __le32 link_to_new_qh;
+ __hc32 link_to_new_qh;
/* Find the predecessor QH for our new one and insert it in the list.
* The list of QHs is expected to be short, so linear search won't
@@ -465,7 +466,7 @@ static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
/* Link it into the schedule */
qh->link = pqh->link;
wmb();
- link_to_new_qh = LINK_TO_QH(qh);
+ link_to_new_qh = LINK_TO_QH(uhci, qh);
pqh->link = link_to_new_qh;
/* If this is now the first FSBR QH, link the terminating skeleton
@@ -483,13 +484,13 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
/* Set the element pointer if it isn't set already.
* This isn't needed for Isochronous queues, but it doesn't hurt. */
- if (qh_element(qh) == UHCI_PTR_TERM) {
+ if (qh_element(qh) == UHCI_PTR_TERM(uhci)) {
struct urb_priv *urbp = list_entry(qh->queue.next,
struct urb_priv, node);
struct uhci_td *td = list_entry(urbp->td_list.next,
struct uhci_td, list);
- qh->element = LINK_TO_TD(td);
+ qh->element = LINK_TO_TD(uhci, td);
}
/* Treat the queue as if it has just advanced */
@@ -533,7 +534,7 @@ static void unlink_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh)
static void unlink_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
{
struct uhci_qh *pqh;
- __le32 link_to_next_qh = qh->link;
+ __hc32 link_to_next_qh = qh->link;
pqh = list_entry(qh->node.prev, struct uhci_qh, node);
pqh->link = link_to_next_qh;
@@ -757,8 +758,8 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci,
/*
* Map status to standard result codes
*
- * <status> is (td_status(td) & 0xF60000), a.k.a.
- * uhci_status_bits(td_status(td)).
+ * <status> is (td_status(uhci, td) & 0xF60000), a.k.a.
+ * uhci_status_bits(td_status(uhci, td)).
* Note: <status> does not include the TD_CTRL_NAK bit.
* <dir_out> is True for output TDs and False for input TDs.
*/
@@ -794,7 +795,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
int len = urb->transfer_buffer_length;
dma_addr_t data = urb->transfer_dma;
- __le32 *plink;
+ __hc32 *plink;
struct urb_priv *urbp = urb->hcpriv;
int skel;
@@ -811,7 +812,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
*/
td = qh->dummy_td;
uhci_add_td_to_urbp(td, urbp);
- uhci_fill_td(td, status, destination | uhci_explen(8),
+ uhci_fill_td(uhci, td, status, destination | uhci_explen(8),
urb->setup_dma);
plink = &td->link;
status |= TD_CTRL_ACTIVE;
@@ -844,14 +845,14 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci);
if (!td)
goto nomem;
- *plink = LINK_TO_TD(td);
+ *plink = LINK_TO_TD(uhci, td);
/* Alternate Data0/1 (start with Data1) */
destination ^= TD_TOKEN_TOGGLE;
uhci_add_td_to_urbp(td, urbp);
- uhci_fill_td(td, status, destination | uhci_explen(pktsze),
- data);
+ uhci_fill_td(uhci, td, status,
+ destination | uhci_explen(pktsze), data);
plink = &td->link;
data += pktsze;
@@ -864,14 +865,14 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci);
if (!td)
goto nomem;
- *plink = LINK_TO_TD(td);
+ *plink = LINK_TO_TD(uhci, td);
/* Change direction for the status transaction */
destination ^= (USB_PID_IN ^ USB_PID_OUT);
destination |= TD_TOKEN_TOGGLE; /* End in Data1 */
uhci_add_td_to_urbp(td, urbp);
- uhci_fill_td(td, status | TD_CTRL_IOC,
+ uhci_fill_td(uhci, td, status | TD_CTRL_IOC,
destination | uhci_explen(0), 0);
plink = &td->link;
@@ -881,11 +882,11 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci);
if (!td)
goto nomem;
- *plink = LINK_TO_TD(td);
+ *plink = LINK_TO_TD(uhci, td);
- uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
+ uhci_fill_td(uhci, td, 0, USB_PID_OUT | uhci_explen(0), 0);
wmb();
- qh->dummy_td->status |= cpu_to_le32(TD_CTRL_ACTIVE);
+ qh->dummy_td->status |= cpu_to_hc32(uhci, TD_CTRL_ACTIVE);
qh->dummy_td = td;
/* Low-speed transfers get a different queue, and won't hog the bus.
@@ -921,7 +922,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
int len = urb->transfer_buffer_length;
int this_sg_len;
dma_addr_t data;
- __le32 *plink;
+ __hc32 *plink;
struct urb_priv *urbp = urb->hcpriv;
unsigned int toggle;
struct scatterlist *sg;
@@ -974,10 +975,10 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci);
if (!td)
goto nomem;
- *plink = LINK_TO_TD(td);
+ *plink = LINK_TO_TD(uhci, td);
}
uhci_add_td_to_urbp(td, urbp);
- uhci_fill_td(td, status,
+ uhci_fill_td(uhci, td, status,
destination | uhci_explen(pktsze) |
(toggle << TD_TOKEN_TOGGLE_SHIFT),
data);
@@ -1010,10 +1011,10 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci);
if (!td)
goto nomem;
- *plink = LINK_TO_TD(td);
+ *plink = LINK_TO_TD(uhci, td);
uhci_add_td_to_urbp(td, urbp);
- uhci_fill_td(td, status,
+ uhci_fill_td(uhci, td, status,
destination | uhci_explen(0) |
(toggle << TD_TOKEN_TOGGLE_SHIFT),
data);
@@ -1028,7 +1029,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
* fast side but not enough to justify delaying an interrupt
* more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT
* flag setting. */
- td->status |= cpu_to_le32(TD_CTRL_IOC);
+ td->status |= cpu_to_hc32(uhci, TD_CTRL_IOC);
/*
* Build the new dummy TD and activate the old one
@@ -1036,11 +1037,11 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci);
if (!td)
goto nomem;
- *plink = LINK_TO_TD(td);
+ *plink = LINK_TO_TD(uhci, td);
- uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
+ uhci_fill_td(uhci, td, 0, USB_PID_OUT | uhci_explen(0), 0);
wmb();
- qh->dummy_td->status |= cpu_to_le32(TD_CTRL_ACTIVE);
+ qh->dummy_td->status |= cpu_to_hc32(uhci, TD_CTRL_ACTIVE);
qh->dummy_td = td;
usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
@@ -1133,7 +1134,7 @@ static int uhci_fixup_short_transfer(struct uhci_hcd *uhci,
* the queue at the status stage transaction, which is
* the last TD. */
WARN_ON(list_empty(&urbp->td_list));
- qh->element = LINK_TO_TD(td);
+ qh->element = LINK_TO_TD(uhci, td);
tmp = td->list.prev;
ret = -EINPROGRESS;
@@ -1142,8 +1143,9 @@ static int uhci_fixup_short_transfer(struct uhci_hcd *uhci,
/* When a bulk/interrupt transfer is short, we have to
* fix up the toggles of the following URBs on the queue
* before restarting the queue at the next URB. */
- qh->initial_toggle = uhci_toggle(td_token(qh->post_td)) ^ 1;
- uhci_fixup_toggles(qh, 1);
+ qh->initial_toggle =
+ uhci_toggle(td_token(uhci, qh->post_td)) ^ 1;
+ uhci_fixup_toggles(uhci, qh, 1);
if (list_empty(&urbp->td_list))
td = qh->post_td;
@@ -1178,7 +1180,7 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
unsigned int ctrlstat;
int len;
- ctrlstat = td_status(td);
+ ctrlstat = td_status(uhci, td);
status = uhci_status_bits(ctrlstat);
if (status & TD_CTRL_ACTIVE)
return -EINPROGRESS;
@@ -1188,7 +1190,7 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
if (status) {
ret = uhci_map_status(status,
- uhci_packetout(td_token(td)));
+ uhci_packetout(td_token(uhci, td)));
if ((debug == 1 && ret != -EPIPE) || debug > 1) {
/* Some debugging code */
dev_dbg(&urb->dev->dev,
@@ -1204,7 +1206,7 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
}
/* Did we receive a short packet? */
- } else if (len < uhci_expected_length(td_token(td))) {
+ } else if (len < uhci_expected_length(td_token(uhci, td))) {
/* For control transfers, go to the status TD if
* this isn't already the last data TD */
@@ -1236,10 +1238,10 @@ err:
if (ret < 0) {
/* Note that the queue has stopped and save
* the next toggle value */
- qh->element = UHCI_PTR_TERM;
+ qh->element = UHCI_PTR_TERM(uhci);
qh->is_stopped = 1;
qh->needs_fixup = (qh->type != USB_ENDPOINT_XFER_CONTROL);
- qh->initial_toggle = uhci_toggle(td_token(td)) ^
+ qh->initial_toggle = uhci_toggle(td_token(uhci, td)) ^
(ret == -EREMOTEIO);
} else /* Short packet received */
@@ -1335,14 +1337,14 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
return -ENOMEM;
uhci_add_td_to_urbp(td, urbp);
- uhci_fill_td(td, status, destination |
+ uhci_fill_td(uhci, td, status, destination |
uhci_explen(urb->iso_frame_desc[i].length),
urb->transfer_dma +
urb->iso_frame_desc[i].offset);
}
/* Set the interrupt-on-completion flag on the last packet. */
- td->status |= cpu_to_le32(TD_CTRL_IOC);
+ td->status |= cpu_to_hc32(uhci, TD_CTRL_IOC);
/* Add the TDs to the frame list */
frame = urb->start_frame;
@@ -1378,7 +1380,7 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
uhci_remove_tds_from_frame(uhci, qh->iso_frame);
- ctrlstat = td_status(td);
+ ctrlstat = td_status(uhci, td);
if (ctrlstat & TD_CTRL_ACTIVE) {
status = -EXDEV; /* TD was added too late? */
} else {
@@ -1629,7 +1631,7 @@ restart:
* queue, the QH can now be re-activated. */
if (!list_empty(&qh->queue)) {
if (qh->needs_fixup)
- uhci_fixup_toggles(qh, 0);
+ uhci_fixup_toggles(uhci, qh, 0);
/* If the first URB on the queue wants FSBR but its time
* limit has expired, set the next TD to interrupt on
@@ -1639,7 +1641,7 @@ restart:
struct uhci_td *td = list_entry(urbp->td_list.next,
struct uhci_td, list);
- td->status |= __cpu_to_le32(TD_CTRL_IOC);
+ td->status |= cpu_to_hc32(uhci, TD_CTRL_IOC);
}
uhci_activate_qh(uhci, qh);
@@ -1686,7 +1688,7 @@ static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh)
} else {
urbp = list_entry(qh->queue.next, struct urb_priv, node);
td = list_entry(urbp->td_list.next, struct uhci_td, list);
- status = td_status(td);
+ status = td_status(uhci, td);
if (!(status & TD_CTRL_ACTIVE)) {
/* We're okay, the queue has advanced */
@@ -1704,7 +1706,8 @@ static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh)
if (time_after(jiffies, qh->advance_jiffies + QH_WAIT_TIMEOUT)) {
/* Detect the Intel bug and work around it */
- if (qh->post_td && qh_element(qh) == LINK_TO_TD(qh->post_td)) {
+ if (qh->post_td && qh_element(qh) ==
+ LINK_TO_TD(uhci, qh->post_td)) {
qh->element = qh->post_td->link;
qh->advance_jiffies = jiffies;
ret = 1;
diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c
index 0231814a97a5..2e0486178dbe 100644
--- a/drivers/usb/host/xhci-dbg.c
+++ b/drivers/usb/host/xhci-dbg.c
@@ -147,7 +147,7 @@ static void xhci_print_op_regs(struct xhci_hcd *xhci)
static void xhci_print_ports(struct xhci_hcd *xhci)
{
- u32 __iomem *addr;
+ __le32 __iomem *addr;
int i, j;
int ports;
char *names[NUM_PORT_REGS] = {
@@ -253,27 +253,27 @@ void xhci_print_trb_offsets(struct xhci_hcd *xhci, union xhci_trb *trb)
void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
{
u64 address;
- u32 type = xhci_readl(xhci, &trb->link.control) & TRB_TYPE_BITMASK;
+ u32 type = le32_to_cpu(trb->link.control) & TRB_TYPE_BITMASK;
switch (type) {
case TRB_TYPE(TRB_LINK):
xhci_dbg(xhci, "Link TRB:\n");
xhci_print_trb_offsets(xhci, trb);
- address = trb->link.segment_ptr;
+ address = le64_to_cpu(trb->link.segment_ptr);
xhci_dbg(xhci, "Next ring segment DMA address = 0x%llx\n", address);
xhci_dbg(xhci, "Interrupter target = 0x%x\n",
- GET_INTR_TARGET(trb->link.intr_target));
+ GET_INTR_TARGET(le32_to_cpu(trb->link.intr_target)));
xhci_dbg(xhci, "Cycle bit = %u\n",
- (unsigned int) (trb->link.control & TRB_CYCLE));
+ (unsigned int) (le32_to_cpu(trb->link.control) & TRB_CYCLE));
xhci_dbg(xhci, "Toggle cycle bit = %u\n",
- (unsigned int) (trb->link.control & LINK_TOGGLE));
+ (unsigned int) (le32_to_cpu(trb->link.control) & LINK_TOGGLE));
xhci_dbg(xhci, "No Snoop bit = %u\n",
- (unsigned int) (trb->link.control & TRB_NO_SNOOP));
+ (unsigned int) (le32_to_cpu(trb->link.control) & TRB_NO_SNOOP));
break;
case TRB_TYPE(TRB_TRANSFER):
- address = trb->trans_event.buffer;
+ address = le64_to_cpu(trb->trans_event.buffer);
/*
* FIXME: look at flags to figure out if it's an address or if
* the data is directly in the buffer field.
@@ -281,11 +281,12 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
xhci_dbg(xhci, "DMA address or buffer contents= %llu\n", address);
break;
case TRB_TYPE(TRB_COMPLETION):
- address = trb->event_cmd.cmd_trb;
+ address = le64_to_cpu(trb->event_cmd.cmd_trb);
xhci_dbg(xhci, "Command TRB pointer = %llu\n", address);
xhci_dbg(xhci, "Completion status = %u\n",
- (unsigned int) GET_COMP_CODE(trb->event_cmd.status));
- xhci_dbg(xhci, "Flags = 0x%x\n", (unsigned int) trb->event_cmd.flags);
+ (unsigned int) GET_COMP_CODE(le32_to_cpu(trb->event_cmd.status)));
+ xhci_dbg(xhci, "Flags = 0x%x\n",
+ (unsigned int) le32_to_cpu(trb->event_cmd.flags));
break;
default:
xhci_dbg(xhci, "Unknown TRB with TRB type ID %u\n",
@@ -311,16 +312,16 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg)
{
int i;
- u32 addr = (u32) seg->dma;
+ u64 addr = seg->dma;
union xhci_trb *trb = seg->trbs;
for (i = 0; i < TRBS_PER_SEGMENT; ++i) {
trb = &seg->trbs[i];
- xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n", addr,
- lower_32_bits(trb->link.segment_ptr),
- upper_32_bits(trb->link.segment_ptr),
- (unsigned int) trb->link.intr_target,
- (unsigned int) trb->link.control);
+ xhci_dbg(xhci, "@%016llx %08x %08x %08x %08x\n", addr,
+ (u32)lower_32_bits(le64_to_cpu(trb->link.segment_ptr)),
+ (u32)upper_32_bits(le64_to_cpu(trb->link.segment_ptr)),
+ (unsigned int) le32_to_cpu(trb->link.intr_target),
+ (unsigned int) le32_to_cpu(trb->link.control));
addr += sizeof(*trb);
}
}
@@ -391,18 +392,18 @@ void xhci_dbg_ep_rings(struct xhci_hcd *xhci,
void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
{
- u32 addr = (u32) erst->erst_dma_addr;
+ u64 addr = erst->erst_dma_addr;
int i;
struct xhci_erst_entry *entry;
for (i = 0; i < erst->num_entries; ++i) {
entry = &erst->entries[i];
- xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n",
- (unsigned int) addr,
- lower_32_bits(entry->seg_addr),
- upper_32_bits(entry->seg_addr),
- (unsigned int) entry->seg_size,
- (unsigned int) entry->rsvd);
+ xhci_dbg(xhci, "@%016llx %08x %08x %08x %08x\n",
+ addr,
+ lower_32_bits(le64_to_cpu(entry->seg_addr)),
+ upper_32_bits(le64_to_cpu(entry->seg_addr)),
+ (unsigned int) le32_to_cpu(entry->seg_size),
+ (unsigned int) le32_to_cpu(entry->rsvd));
addr += sizeof(*entry);
}
}
@@ -436,7 +437,7 @@ char *xhci_get_slot_state(struct xhci_hcd *xhci,
{
struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx);
- switch (GET_SLOT_STATE(slot_ctx->dev_state)) {
+ switch (GET_SLOT_STATE(le32_to_cpu(slot_ctx->dev_state))) {
case 0:
return "enabled/disabled";
case 1:
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 73f75d26436c..0be788cc2fdb 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -50,7 +50,7 @@ static void xhci_common_hub_descriptor(struct xhci_hcd *xhci,
temp |= 0x0008;
/* Bits 6:5 - no TTs in root ports */
/* Bit 7 - no port indicators */
- desc->wHubCharacteristics = (__force __u16) cpu_to_le16(temp);
+ desc->wHubCharacteristics = cpu_to_le16(temp);
}
/* Fill in the USB 2.0 roothub descriptor */
@@ -314,7 +314,7 @@ void xhci_ring_device(struct xhci_hcd *xhci, int slot_id)
}
static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
- u16 wIndex, u32 __iomem *addr, u32 port_status)
+ u16 wIndex, __le32 __iomem *addr, u32 port_status)
{
/* Don't allow the USB core to disable SuperSpeed ports. */
if (hcd->speed == HCD_USB3) {
@@ -331,7 +331,7 @@ static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
}
static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
- u16 wIndex, u32 __iomem *addr, u32 port_status)
+ u16 wIndex, __le32 __iomem *addr, u32 port_status)
{
char *port_change_bit;
u32 status;
@@ -341,6 +341,10 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
status = PORT_RC;
port_change_bit = "reset";
break;
+ case USB_PORT_FEAT_C_BH_PORT_RESET:
+ status = PORT_WRC;
+ port_change_bit = "warm(BH) reset";
+ break;
case USB_PORT_FEAT_C_CONNECTION:
status = PORT_CSC;
port_change_bit = "connect";
@@ -357,6 +361,10 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
status = PORT_PLC;
port_change_bit = "suspend/resume";
break;
+ case USB_PORT_FEAT_C_PORT_LINK_STATE:
+ status = PORT_PLC;
+ port_change_bit = "link state";
+ break;
default:
/* Should never happen */
return;
@@ -368,25 +376,36 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
port_change_bit, wIndex, port_status);
}
+static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array)
+{
+ int max_ports;
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+ if (hcd->speed == HCD_USB3) {
+ max_ports = xhci->num_usb3_ports;
+ *port_array = xhci->usb3_ports;
+ } else {
+ max_ports = xhci->num_usb2_ports;
+ *port_array = xhci->usb2_ports;
+ }
+
+ return max_ports;
+}
+
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- int ports;
+ int max_ports;
unsigned long flags;
u32 temp, temp1, status;
int retval = 0;
- u32 __iomem **port_array;
+ __le32 __iomem **port_array;
int slot_id;
struct xhci_bus_state *bus_state;
+ u16 link_state = 0;
- if (hcd->speed == HCD_USB3) {
- ports = xhci->num_usb3_ports;
- port_array = xhci->usb3_ports;
- } else {
- ports = xhci->num_usb2_ports;
- port_array = xhci->usb2_ports;
- }
+ max_ports = xhci_get_ports(hcd, &port_array);
bus_state = &xhci->bus_state[hcd_index(hcd)];
spin_lock_irqsave(&xhci->lock, flags);
@@ -411,7 +430,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
(struct usb_hub_descriptor *) buf);
break;
case GetPortStatus:
- if (!wIndex || wIndex > ports)
+ if (!wIndex || wIndex > max_ports)
goto error;
wIndex--;
status = 0;
@@ -422,9 +441,6 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
}
xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp);
- /* FIXME - should we return a port status value like the USB
- * 3.0 external hubs do?
- */
/* wPortChange bits */
if (temp & PORT_CSC)
status |= USB_PORT_STAT_C_CONNECTION << 16;
@@ -432,13 +448,21 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
status |= USB_PORT_STAT_C_ENABLE << 16;
if ((temp & PORT_OCC))
status |= USB_PORT_STAT_C_OVERCURRENT << 16;
- /*
- * FIXME ignoring reset and USB 2.1/3.0 specific
- * changes
- */
- if ((temp & PORT_PLS_MASK) == XDEV_U3
- && (temp & PORT_POWER))
- status |= 1 << USB_PORT_FEAT_SUSPEND;
+ if ((temp & PORT_RC))
+ status |= USB_PORT_STAT_C_RESET << 16;
+ /* USB3.0 only */
+ if (hcd->speed == HCD_USB3) {
+ if ((temp & PORT_PLC))
+ status |= USB_PORT_STAT_C_LINK_STATE << 16;
+ if ((temp & PORT_WRC))
+ status |= USB_PORT_STAT_C_BH_RESET << 16;
+ }
+
+ if (hcd->speed != HCD_USB3) {
+ if ((temp & PORT_PLS_MASK) == XDEV_U3
+ && (temp & PORT_POWER))
+ status |= USB_PORT_STAT_SUSPEND;
+ }
if ((temp & PORT_PLS_MASK) == XDEV_RESUME) {
if ((temp & PORT_RESET) || !(temp & PORT_PE))
goto error;
@@ -469,7 +493,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
&& (temp & PORT_POWER)
&& (bus_state->suspended_ports & (1 << wIndex))) {
bus_state->suspended_ports &= ~(1 << wIndex);
- bus_state->port_c_suspend |= 1 << wIndex;
+ if (hcd->speed != HCD_USB3)
+ bus_state->port_c_suspend |= 1 << wIndex;
}
if (temp & PORT_CONNECT) {
status |= USB_PORT_STAT_CONNECTION;
@@ -481,16 +506,30 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
status |= USB_PORT_STAT_OVERCURRENT;
if (temp & PORT_RESET)
status |= USB_PORT_STAT_RESET;
- if (temp & PORT_POWER)
- status |= USB_PORT_STAT_POWER;
+ if (temp & PORT_POWER) {
+ if (hcd->speed == HCD_USB3)
+ status |= USB_SS_PORT_STAT_POWER;
+ else
+ status |= USB_PORT_STAT_POWER;
+ }
+ /* Port Link State */
+ if (hcd->speed == HCD_USB3) {
+ /* resume state is a xHCI internal state.
+ * Do not report it to usb core.
+ */
+ if ((temp & PORT_PLS_MASK) != XDEV_RESUME)
+ status |= (temp & PORT_PLS_MASK);
+ }
if (bus_state->port_c_suspend & (1 << wIndex))
status |= 1 << USB_PORT_FEAT_C_SUSPEND;
xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
put_unaligned(cpu_to_le32(status), (__le32 *) buf);
break;
case SetPortFeature:
+ if (wValue == USB_PORT_FEAT_LINK_STATE)
+ link_state = (wIndex & 0xff00) >> 3;
wIndex &= 0xff;
- if (!wIndex || wIndex > ports)
+ if (!wIndex || wIndex > max_ports)
goto error;
wIndex--;
temp = xhci_readl(xhci, port_array[wIndex]);
@@ -537,6 +576,44 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp = xhci_readl(xhci, port_array[wIndex]);
bus_state->suspended_ports |= 1 << wIndex;
break;
+ case USB_PORT_FEAT_LINK_STATE:
+ temp = xhci_readl(xhci, port_array[wIndex]);
+ /* Software should not attempt to set
+ * port link state above '5' (Rx.Detect) and the port
+ * must be enabled.
+ */
+ if ((temp & PORT_PE) == 0 ||
+ (link_state > USB_SS_PORT_LS_RX_DETECT)) {
+ xhci_warn(xhci, "Cannot set link state.\n");
+ goto error;
+ }
+
+ if (link_state == USB_SS_PORT_LS_U3) {
+ slot_id = xhci_find_slot_id_by_port(hcd, xhci,
+ wIndex + 1);
+ if (slot_id) {
+ /* unlock to execute stop endpoint
+ * commands */
+ spin_unlock_irqrestore(&xhci->lock,
+ flags);
+ xhci_stop_device(xhci, slot_id, 1);
+ spin_lock_irqsave(&xhci->lock, flags);
+ }
+ }
+
+ temp = xhci_port_state_to_neutral(temp);
+ temp &= ~PORT_PLS_MASK;
+ temp |= PORT_LINK_STROBE | link_state;
+ xhci_writel(xhci, temp, port_array[wIndex]);
+
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ msleep(20); /* wait device to enter */
+ spin_lock_irqsave(&xhci->lock, flags);
+
+ temp = xhci_readl(xhci, port_array[wIndex]);
+ if (link_state == USB_SS_PORT_LS_U3)
+ bus_state->suspended_ports |= 1 << wIndex;
+ break;
case USB_PORT_FEAT_POWER:
/*
* Turn on ports, even if there isn't per-port switching.
@@ -557,6 +634,12 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp = xhci_readl(xhci, port_array[wIndex]);
xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp);
break;
+ case USB_PORT_FEAT_BH_PORT_RESET:
+ temp |= PORT_WR;
+ xhci_writel(xhci, temp, port_array[wIndex]);
+
+ temp = xhci_readl(xhci, port_array[wIndex]);
+ break;
default:
goto error;
}
@@ -564,7 +647,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp = xhci_readl(xhci, port_array[wIndex]);
break;
case ClearPortFeature:
- if (!wIndex || wIndex > ports)
+ if (!wIndex || wIndex > max_ports)
goto error;
wIndex--;
temp = xhci_readl(xhci, port_array[wIndex]);
@@ -584,35 +667,27 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
if (temp & XDEV_U3) {
if ((temp & PORT_PE) == 0)
goto error;
- if (DEV_SUPERSPEED(temp)) {
- temp = xhci_port_state_to_neutral(temp);
- temp &= ~PORT_PLS_MASK;
- temp |= PORT_LINK_STROBE | XDEV_U0;
- xhci_writel(xhci, temp,
- port_array[wIndex]);
- xhci_readl(xhci, port_array[wIndex]);
- } else {
- temp = xhci_port_state_to_neutral(temp);
- temp &= ~PORT_PLS_MASK;
- temp |= PORT_LINK_STROBE | XDEV_RESUME;
- xhci_writel(xhci, temp,
- port_array[wIndex]);
- spin_unlock_irqrestore(&xhci->lock,
- flags);
- msleep(20);
- spin_lock_irqsave(&xhci->lock, flags);
+ temp = xhci_port_state_to_neutral(temp);
+ temp &= ~PORT_PLS_MASK;
+ temp |= PORT_LINK_STROBE | XDEV_RESUME;
+ xhci_writel(xhci, temp,
+ port_array[wIndex]);
- temp = xhci_readl(xhci,
- port_array[wIndex]);
- temp = xhci_port_state_to_neutral(temp);
- temp &= ~PORT_PLS_MASK;
- temp |= PORT_LINK_STROBE | XDEV_U0;
- xhci_writel(xhci, temp,
- port_array[wIndex]);
- }
- bus_state->port_c_suspend |= 1 << wIndex;
+ spin_unlock_irqrestore(&xhci->lock,
+ flags);
+ msleep(20);
+ spin_lock_irqsave(&xhci->lock, flags);
+
+ temp = xhci_readl(xhci,
+ port_array[wIndex]);
+ temp = xhci_port_state_to_neutral(temp);
+ temp &= ~PORT_PLS_MASK;
+ temp |= PORT_LINK_STROBE | XDEV_U0;
+ xhci_writel(xhci, temp,
+ port_array[wIndex]);
}
+ bus_state->port_c_suspend |= 1 << wIndex;
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
wIndex + 1);
@@ -625,9 +700,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case USB_PORT_FEAT_C_SUSPEND:
bus_state->port_c_suspend &= ~(1 << wIndex);
case USB_PORT_FEAT_C_RESET:
+ case USB_PORT_FEAT_C_BH_PORT_RESET:
case USB_PORT_FEAT_C_CONNECTION:
case USB_PORT_FEAT_C_OVER_CURRENT:
case USB_PORT_FEAT_C_ENABLE:
+ case USB_PORT_FEAT_C_PORT_LINK_STATE:
xhci_clear_port_change_bit(xhci, wValue, wIndex,
port_array[wIndex], temp);
break;
@@ -663,29 +740,23 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
u32 mask;
int i, retval;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- int ports;
- u32 __iomem **port_array;
+ int max_ports;
+ __le32 __iomem **port_array;
struct xhci_bus_state *bus_state;
- if (hcd->speed == HCD_USB3) {
- ports = xhci->num_usb3_ports;
- port_array = xhci->usb3_ports;
- } else {
- ports = xhci->num_usb2_ports;
- port_array = xhci->usb2_ports;
- }
+ max_ports = xhci_get_ports(hcd, &port_array);
bus_state = &xhci->bus_state[hcd_index(hcd)];
/* Initial status is no changes */
- retval = (ports + 8) / 8;
+ retval = (max_ports + 8) / 8;
memset(buf, 0, retval);
status = 0;
- mask = PORT_CSC | PORT_PEC | PORT_OCC;
+ mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC;
spin_lock_irqsave(&xhci->lock, flags);
/* For each port, did anything change? If so, set that bit in buf. */
- for (i = 0; i < ports; i++) {
+ for (i = 0; i < max_ports; i++) {
temp = xhci_readl(xhci, port_array[i]);
if (temp == 0xffffffff) {
retval = -ENODEV;
@@ -709,19 +780,11 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
int max_ports, port_index;
- u32 __iomem **port_array;
+ __le32 __iomem **port_array;
struct xhci_bus_state *bus_state;
unsigned long flags;
- if (hcd->speed == HCD_USB3) {
- max_ports = xhci->num_usb3_ports;
- port_array = xhci->usb3_ports;
- xhci_dbg(xhci, "suspend USB 3.0 root hub\n");
- } else {
- max_ports = xhci->num_usb2_ports;
- port_array = xhci->usb2_ports;
- xhci_dbg(xhci, "suspend USB 2.0 root hub\n");
- }
+ max_ports = xhci_get_ports(hcd, &port_array);
bus_state = &xhci->bus_state[hcd_index(hcd)];
spin_lock_irqsave(&xhci->lock, flags);
@@ -779,7 +842,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
if (hcd->speed != HCD_USB3) {
/* enable remote wake up for USB 2.0 */
- u32 __iomem *addr;
+ __le32 __iomem *addr;
u32 tmp;
/* Add one to the port status register address to get
@@ -801,20 +864,12 @@ int xhci_bus_resume(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
int max_ports, port_index;
- u32 __iomem **port_array;
+ __le32 __iomem **port_array;
struct xhci_bus_state *bus_state;
u32 temp;
unsigned long flags;
- if (hcd->speed == HCD_USB3) {
- max_ports = xhci->num_usb3_ports;
- port_array = xhci->usb3_ports;
- xhci_dbg(xhci, "resume USB 3.0 root hub\n");
- } else {
- max_ports = xhci->num_usb2_ports;
- port_array = xhci->usb2_ports;
- xhci_dbg(xhci, "resume USB 2.0 root hub\n");
- }
+ max_ports = xhci_get_ports(hcd, &port_array);
bus_state = &xhci->bus_state[hcd_index(hcd)];
if (time_before(jiffies, bus_state->next_statechange))
@@ -890,7 +945,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
if (hcd->speed != HCD_USB3) {
/* disable remote wake up for USB 2.0 */
- u32 __iomem *addr;
+ __le32 __iomem *addr;
u32 tmp;
/* Add one to the port status register address to get
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 627f3438028c..26caba4c1950 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -89,16 +89,17 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
return;
prev->next = next;
if (link_trbs) {
- prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr = next->dma;
+ prev->trbs[TRBS_PER_SEGMENT-1].link.
+ segment_ptr = cpu_to_le64(next->dma);
/* Set the last TRB in the segment to have a TRB type ID of Link TRB */
- val = prev->trbs[TRBS_PER_SEGMENT-1].link.control;
+ val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control);
val &= ~TRB_TYPE_BITMASK;
val |= TRB_TYPE(TRB_LINK);
/* Always set the chain bit with 0.95 hardware */
if (xhci_link_trb_quirk(xhci))
val |= TRB_CHAIN;
- prev->trbs[TRBS_PER_SEGMENT-1].link.control = val;
+ prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val);
}
xhci_dbg(xhci, "Linking segment 0x%llx to segment 0x%llx (DMA)\n",
(unsigned long long)prev->dma,
@@ -186,7 +187,8 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
if (link_trbs) {
/* See section 4.9.2.1 and 6.4.4.1 */
- prev->trbs[TRBS_PER_SEGMENT-1].link.control |= (LINK_TOGGLE);
+ prev->trbs[TRBS_PER_SEGMENT-1].link.
+ control |= cpu_to_le32(LINK_TOGGLE);
xhci_dbg(xhci, "Wrote link toggle flag to"
" segment %p (virtual), 0x%llx (DMA)\n",
prev, (unsigned long long)prev->dma);
@@ -207,14 +209,13 @@ void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
rings_cached = virt_dev->num_rings_cached;
if (rings_cached < XHCI_MAX_RINGS_CACHED) {
- virt_dev->num_rings_cached++;
- rings_cached = virt_dev->num_rings_cached;
virt_dev->ring_cache[rings_cached] =
virt_dev->eps[ep_index].ring;
+ virt_dev->num_rings_cached++;
xhci_dbg(xhci, "Cached old ring, "
"%d ring%s cached\n",
- rings_cached,
- (rings_cached > 1) ? "s" : "");
+ virt_dev->num_rings_cached,
+ (virt_dev->num_rings_cached > 1) ? "s" : "");
} else {
xhci_ring_free(xhci, virt_dev->eps[ep_index].ring);
xhci_dbg(xhci, "Ring cache full (%d rings), "
@@ -548,7 +549,8 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
addr = cur_ring->first_seg->dma |
SCT_FOR_CTX(SCT_PRI_TR) |
cur_ring->cycle_state;
- stream_info->stream_ctx_array[cur_stream].stream_ring = addr;
+ stream_info->stream_ctx_array[cur_stream].
+ stream_ring = cpu_to_le64(addr);
xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n",
cur_stream, (unsigned long long) addr);
@@ -614,10 +616,10 @@ void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci,
max_primary_streams = fls(stream_info->num_stream_ctxs) - 2;
xhci_dbg(xhci, "Setting number of stream ctx array entries to %u\n",
1 << (max_primary_streams + 1));
- ep_ctx->ep_info &= ~EP_MAXPSTREAMS_MASK;
- ep_ctx->ep_info |= EP_MAXPSTREAMS(max_primary_streams);
- ep_ctx->ep_info |= EP_HAS_LSA;
- ep_ctx->deq = stream_info->ctx_array_dma;
+ ep_ctx->ep_info &= cpu_to_le32(~EP_MAXPSTREAMS_MASK);
+ ep_ctx->ep_info |= cpu_to_le32(EP_MAXPSTREAMS(max_primary_streams)
+ | EP_HAS_LSA);
+ ep_ctx->deq = cpu_to_le64(stream_info->ctx_array_dma);
}
/*
@@ -630,10 +632,9 @@ void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci,
struct xhci_virt_ep *ep)
{
dma_addr_t addr;
- ep_ctx->ep_info &= ~EP_MAXPSTREAMS_MASK;
- ep_ctx->ep_info &= ~EP_HAS_LSA;
+ ep_ctx->ep_info &= cpu_to_le32(~(EP_MAXPSTREAMS_MASK | EP_HAS_LSA));
addr = xhci_trb_virt_to_dma(ep->ring->deq_seg, ep->ring->dequeue);
- ep_ctx->deq = addr | ep->ring->cycle_state;
+ ep_ctx->deq = cpu_to_le64(addr | ep->ring->cycle_state);
}
/* Frees all stream contexts associated with the endpoint,
@@ -781,11 +782,11 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
dev->udev = udev;
/* Point to output device context in dcbaa. */
- xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx->dma;
+ xhci->dcbaa->dev_context_ptrs[slot_id] = cpu_to_le64(dev->out_ctx->dma);
xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n",
- slot_id,
- &xhci->dcbaa->dev_context_ptrs[slot_id],
- (unsigned long long) xhci->dcbaa->dev_context_ptrs[slot_id]);
+ slot_id,
+ &xhci->dcbaa->dev_context_ptrs[slot_id],
+ (unsigned long long) le64_to_cpu(xhci->dcbaa->dev_context_ptrs[slot_id]));
return 1;
fail:
@@ -810,8 +811,9 @@ void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,
* configured device has reset, so all control transfers should have
* been completed or cancelled before the reset.
*/
- ep0_ctx->deq = xhci_trb_virt_to_dma(ep_ring->enq_seg, ep_ring->enqueue);
- ep0_ctx->deq |= ep_ring->cycle_state;
+ ep0_ctx->deq = cpu_to_le64(xhci_trb_virt_to_dma(ep_ring->enq_seg,
+ ep_ring->enqueue)
+ | ep_ring->cycle_state);
}
/*
@@ -885,24 +887,22 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
slot_ctx = xhci_get_slot_ctx(xhci, dev->in_ctx);
/* 2) New slot context and endpoint 0 context are valid*/
- ctrl_ctx->add_flags = SLOT_FLAG | EP0_FLAG;
+ ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
/* 3) Only the control endpoint is valid - one endpoint context */
- slot_ctx->dev_info |= LAST_CTX(1);
-
- slot_ctx->dev_info |= (u32) udev->route;
+ slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | (u32) udev->route);
switch (udev->speed) {
case USB_SPEED_SUPER:
- slot_ctx->dev_info |= (u32) SLOT_SPEED_SS;
+ slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_SS);
break;
case USB_SPEED_HIGH:
- slot_ctx->dev_info |= (u32) SLOT_SPEED_HS;
+ slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_HS);
break;
case USB_SPEED_FULL:
- slot_ctx->dev_info |= (u32) SLOT_SPEED_FS;
+ slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_FS);
break;
case USB_SPEED_LOW:
- slot_ctx->dev_info |= (u32) SLOT_SPEED_LS;
+ slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_LS);
break;
case USB_SPEED_WIRELESS:
xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
@@ -916,7 +916,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
port_num = xhci_find_real_port_number(xhci, udev);
if (!port_num)
return -EINVAL;
- slot_ctx->dev_info2 |= (u32) ROOT_HUB_PORT(port_num);
+ slot_ctx->dev_info2 |= cpu_to_le32((u32) ROOT_HUB_PORT(port_num));
/* Set the port number in the virtual_device to the faked port number */
for (top_dev = udev; top_dev->parent && top_dev->parent->parent;
top_dev = top_dev->parent)
@@ -927,31 +927,31 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
/* Is this a LS/FS device under an external HS hub? */
if (udev->tt && udev->tt->hub->parent) {
- slot_ctx->tt_info = udev->tt->hub->slot_id;
- slot_ctx->tt_info |= udev->ttport << 8;
+ slot_ctx->tt_info = cpu_to_le32(udev->tt->hub->slot_id |
+ (udev->ttport << 8));
if (udev->tt->multi)
- slot_ctx->dev_info |= DEV_MTT;
+ slot_ctx->dev_info |= cpu_to_le32(DEV_MTT);
}
xhci_dbg(xhci, "udev->tt = %p\n", udev->tt);
xhci_dbg(xhci, "udev->ttport = 0x%x\n", udev->ttport);
/* Step 4 - ring already allocated */
/* Step 5 */
- ep0_ctx->ep_info2 = EP_TYPE(CTRL_EP);
+ ep0_ctx->ep_info2 = cpu_to_le32(EP_TYPE(CTRL_EP));
/*
* XXX: Not sure about wireless USB devices.
*/
switch (udev->speed) {
case USB_SPEED_SUPER:
- ep0_ctx->ep_info2 |= MAX_PACKET(512);
+ ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(512));
break;
case USB_SPEED_HIGH:
/* USB core guesses at a 64-byte max packet first for FS devices */
case USB_SPEED_FULL:
- ep0_ctx->ep_info2 |= MAX_PACKET(64);
+ ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(64));
break;
case USB_SPEED_LOW:
- ep0_ctx->ep_info2 |= MAX_PACKET(8);
+ ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(8));
break;
case USB_SPEED_WIRELESS:
xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
@@ -962,12 +962,10 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
BUG();
}
/* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */
- ep0_ctx->ep_info2 |= MAX_BURST(0);
- ep0_ctx->ep_info2 |= ERROR_COUNT(3);
+ ep0_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(0) | ERROR_COUNT(3));
- ep0_ctx->deq =
- dev->eps[0].ring->first_seg->dma;
- ep0_ctx->deq |= dev->eps[0].ring->cycle_state;
+ ep0_ctx->deq = cpu_to_le64(dev->eps[0].ring->first_seg->dma |
+ dev->eps[0].ring->cycle_state);
/* Steps 7 and 8 were done in xhci_alloc_virt_device() */
@@ -1046,12 +1044,12 @@ static unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
break;
case USB_SPEED_FULL:
- if (usb_endpoint_xfer_int(&ep->desc)) {
+ if (usb_endpoint_xfer_isoc(&ep->desc)) {
interval = xhci_parse_exponent_interval(udev, ep);
break;
}
/*
- * Fall through for isochronous endpoint interval decoding
+ * Fall through for interrupt endpoint interval decoding
* since it uses the same rules as low speed interrupt
* endpoints.
*/
@@ -1131,10 +1129,10 @@ static u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci,
return 0;
if (udev->speed == USB_SPEED_SUPER)
- return ep->ss_ep_comp.wBytesPerInterval;
+ return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval);
- max_packet = GET_MAX_PACKET(ep->desc.wMaxPacketSize);
- max_burst = (ep->desc.wMaxPacketSize & 0x1800) >> 11;
+ max_packet = GET_MAX_PACKET(le16_to_cpu(ep->desc.wMaxPacketSize));
+ max_burst = (le16_to_cpu(ep->desc.wMaxPacketSize) & 0x1800) >> 11;
/* A 0 in max burst means 1 transfer per ESIT */
return max_packet * (max_burst + 1);
}
@@ -1183,33 +1181,33 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
}
virt_dev->eps[ep_index].skip = false;
ep_ring = virt_dev->eps[ep_index].new_ring;
- ep_ctx->deq = ep_ring->first_seg->dma | ep_ring->cycle_state;
+ ep_ctx->deq = cpu_to_le64(ep_ring->first_seg->dma | ep_ring->cycle_state);
- ep_ctx->ep_info = xhci_get_endpoint_interval(udev, ep);
- ep_ctx->ep_info |= EP_MULT(xhci_get_endpoint_mult(udev, ep));
+ ep_ctx->ep_info = cpu_to_le32(xhci_get_endpoint_interval(udev, ep)
+ | EP_MULT(xhci_get_endpoint_mult(udev, ep)));
/* FIXME dig Mult and streams info out of ep companion desc */
/* Allow 3 retries for everything but isoc;
- * error count = 0 means infinite retries.
+ * CErr shall be set to 0 for Isoch endpoints.
*/
if (!usb_endpoint_xfer_isoc(&ep->desc))
- ep_ctx->ep_info2 = ERROR_COUNT(3);
+ ep_ctx->ep_info2 = cpu_to_le32(ERROR_COUNT(3));
else
- ep_ctx->ep_info2 = ERROR_COUNT(1);
+ ep_ctx->ep_info2 = cpu_to_le32(ERROR_COUNT(0));
- ep_ctx->ep_info2 |= xhci_get_endpoint_type(udev, ep);
+ ep_ctx->ep_info2 |= cpu_to_le32(xhci_get_endpoint_type(udev, ep));
/* Set the max packet size and max burst */
switch (udev->speed) {
case USB_SPEED_SUPER:
- max_packet = ep->desc.wMaxPacketSize;
- ep_ctx->ep_info2 |= MAX_PACKET(max_packet);
+ max_packet = le16_to_cpu(ep->desc.wMaxPacketSize);
+ ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet));
/* dig out max burst from ep companion desc */
max_packet = ep->ss_ep_comp.bMaxBurst;
if (!max_packet)
xhci_warn(xhci, "WARN no SS endpoint bMaxBurst\n");
- ep_ctx->ep_info2 |= MAX_BURST(max_packet);
+ ep_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(max_packet));
break;
case USB_SPEED_HIGH:
/* bits 11:12 specify the number of additional transaction
@@ -1217,20 +1215,21 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
*/
if (usb_endpoint_xfer_isoc(&ep->desc) ||
usb_endpoint_xfer_int(&ep->desc)) {
- max_burst = (ep->desc.wMaxPacketSize & 0x1800) >> 11;
- ep_ctx->ep_info2 |= MAX_BURST(max_burst);
+ max_burst = (le16_to_cpu(ep->desc.wMaxPacketSize)
+ & 0x1800) >> 11;
+ ep_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(max_burst));
}
/* Fall through */
case USB_SPEED_FULL:
case USB_SPEED_LOW:
- max_packet = GET_MAX_PACKET(ep->desc.wMaxPacketSize);
- ep_ctx->ep_info2 |= MAX_PACKET(max_packet);
+ max_packet = GET_MAX_PACKET(le16_to_cpu(ep->desc.wMaxPacketSize));
+ ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet));
break;
default:
BUG();
}
max_esit_payload = xhci_get_max_esit_payload(xhci, udev, ep);
- ep_ctx->tx_info = MAX_ESIT_PAYLOAD_FOR_EP(max_esit_payload);
+ ep_ctx->tx_info = cpu_to_le32(MAX_ESIT_PAYLOAD_FOR_EP(max_esit_payload));
/*
* XXX no idea how to calculate the average TRB buffer length for bulk
@@ -1246,8 +1245,15 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
* including link TRBs, No-op TRBs, and Event data TRBs. Since we don't
* use Event Data TRBs, and we don't chain in a link TRB on short
* transfers, we're basically dividing by 1.
+ *
+ * xHCI 1.0 specification indicates that the Average TRB Length should
+ * be set to 8 for control endpoints.
*/
- ep_ctx->tx_info |= AVG_TRB_LENGTH_FOR_EP(max_esit_payload);
+ if (usb_endpoint_xfer_control(&ep->desc) && xhci->hci_version == 0x100)
+ ep_ctx->tx_info |= cpu_to_le32(AVG_TRB_LENGTH_FOR_EP(8));
+ else
+ ep_ctx->tx_info |=
+ cpu_to_le32(AVG_TRB_LENGTH_FOR_EP(max_esit_payload));
/* FIXME Debug endpoint context */
return 0;
@@ -1347,7 +1353,7 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
if (!xhci->scratchpad->sp_dma_buffers)
goto fail_sp4;
- xhci->dcbaa->dev_context_ptrs[0] = xhci->scratchpad->sp_dma;
+ xhci->dcbaa->dev_context_ptrs[0] = cpu_to_le64(xhci->scratchpad->sp_dma);
for (i = 0; i < num_sp; i++) {
dma_addr_t dma;
void *buf = pci_alloc_consistent(to_pci_dev(dev),
@@ -1724,7 +1730,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
}
static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
- u32 __iomem *addr, u8 major_revision)
+ __le32 __iomem *addr, u8 major_revision)
{
u32 temp, port_offset, port_count;
int i;
@@ -1789,7 +1795,7 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
*/
static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
{
- u32 __iomem *addr;
+ __le32 __iomem *addr;
u32 offset;
unsigned int num_ports;
int i, port_index;
@@ -2042,8 +2048,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
/* set ring base address and size for each segment table entry */
for (val = 0, seg = xhci->event_ring->first_seg; val < ERST_NUM_SEGS; val++) {
struct xhci_erst_entry *entry = &xhci->erst.entries[val];
- entry->seg_addr = seg->dma;
- entry->seg_size = TRBS_PER_SEGMENT;
+ entry->seg_addr = cpu_to_le64(seg->dma);
+ entry->seg_size = cpu_to_le32(TRBS_PER_SEGMENT);
entry->rsvd = 0;
seg = seg->next;
}
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index a10494c2f3c7..cbc4d491e626 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -21,6 +21,7 @@
*/
#include <linux/pci.h>
+#include <linux/slab.h>
#include "xhci.h"
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 7437386a9a50..237a765f8d18 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -100,7 +100,7 @@ static bool last_trb_on_last_seg(struct xhci_hcd *xhci, struct xhci_ring *ring,
return (trb == &seg->trbs[TRBS_PER_SEGMENT]) &&
(seg->next == xhci->event_ring->first_seg);
else
- return trb->link.control & LINK_TOGGLE;
+ return le32_to_cpu(trb->link.control) & LINK_TOGGLE;
}
/* Is this TRB a link TRB or was the last TRB the last TRB in this event ring
@@ -113,13 +113,15 @@ static int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
if (ring == xhci->event_ring)
return trb == &seg->trbs[TRBS_PER_SEGMENT];
else
- return (trb->link.control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK);
+ return (le32_to_cpu(trb->link.control) & TRB_TYPE_BITMASK)
+ == TRB_TYPE(TRB_LINK);
}
static int enqueue_is_link_trb(struct xhci_ring *ring)
{
struct xhci_link_trb *link = &ring->enqueue->link;
- return ((link->control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK));
+ return ((le32_to_cpu(link->control) & TRB_TYPE_BITMASK) ==
+ TRB_TYPE(TRB_LINK));
}
/* Updates trb to point to the next TRB in the ring, and updates seg if the next
@@ -197,7 +199,7 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
union xhci_trb *next;
unsigned long long addr;
- chain = ring->enqueue->generic.field[3] & TRB_CHAIN;
+ chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN;
next = ++(ring->enqueue);
ring->enq_updates++;
@@ -223,12 +225,14 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
* (which may mean the chain bit is cleared).
*/
if (!xhci_link_trb_quirk(xhci)) {
- next->link.control &= ~TRB_CHAIN;
- next->link.control |= chain;
+ next->link.control &=
+ cpu_to_le32(~TRB_CHAIN);
+ next->link.control |=
+ cpu_to_le32(chain);
}
/* Give this link TRB to the hardware */
wmb();
- next->link.control ^= TRB_CYCLE;
+ next->link.control ^= cpu_to_le32(TRB_CYCLE);
}
/* Toggle the cycle bit after the last ring segment. */
if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
@@ -319,7 +323,7 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
unsigned int ep_index,
unsigned int stream_id)
{
- __u32 __iomem *db_addr = &xhci->dba->doorbell[slot_id];
+ __le32 __iomem *db_addr = &xhci->dba->doorbell[slot_id];
struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
unsigned int ep_state = ep->ep_state;
@@ -380,7 +384,7 @@ static struct xhci_segment *find_trb_seg(
while (cur_seg->trbs > trb ||
&cur_seg->trbs[TRBS_PER_SEGMENT - 1] < trb) {
generic_trb = &cur_seg->trbs[TRBS_PER_SEGMENT - 1].generic;
- if (generic_trb->field[3] & LINK_TOGGLE)
+ if (le32_to_cpu(generic_trb->field[3]) & LINK_TOGGLE)
*cycle_state ^= 0x1;
cur_seg = cur_seg->next;
if (cur_seg == start_seg)
@@ -447,6 +451,10 @@ static struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
* any link TRBs with the toggle cycle bit set.
* - Finally we move the dequeue state one TRB further, toggling the cycle bit
* if we've moved it past a link TRB with the toggle cycle bit set.
+ *
+ * Some of the uses of xhci_generic_trb are grotty, but if they're done
+ * with correct __le32 accesses they should work fine. Only users of this are
+ * in here.
*/
void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
@@ -480,7 +488,7 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
/* Dig out the cycle state saved by the xHC during the stop ep cmd */
xhci_dbg(xhci, "Finding endpoint context\n");
ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
- state->new_cycle_state = 0x1 & ep_ctx->deq;
+ state->new_cycle_state = 0x1 & le64_to_cpu(ep_ctx->deq);
state->new_deq_ptr = cur_td->last_trb;
xhci_dbg(xhci, "Finding segment containing last TRB in TD.\n");
@@ -493,8 +501,8 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
}
trb = &state->new_deq_ptr->generic;
- if ((trb->field[3] & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK) &&
- (trb->field[3] & LINK_TOGGLE))
+ if ((le32_to_cpu(trb->field[3]) & TRB_TYPE_BITMASK) ==
+ TRB_TYPE(TRB_LINK) && (le32_to_cpu(trb->field[3]) & LINK_TOGGLE))
state->new_cycle_state ^= 0x1;
next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr);
@@ -529,12 +537,12 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
for (cur_seg = cur_td->start_seg, cur_trb = cur_td->first_trb;
true;
next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) {
- if ((cur_trb->generic.field[3] & TRB_TYPE_BITMASK) ==
- TRB_TYPE(TRB_LINK)) {
+ if ((le32_to_cpu(cur_trb->generic.field[3]) & TRB_TYPE_BITMASK)
+ == TRB_TYPE(TRB_LINK)) {
/* Unchain any chained Link TRBs, but
* leave the pointers intact.
*/
- cur_trb->generic.field[3] &= ~TRB_CHAIN;
+ cur_trb->generic.field[3] &= cpu_to_le32(~TRB_CHAIN);
xhci_dbg(xhci, "Cancel (unchain) link TRB\n");
xhci_dbg(xhci, "Address = %p (0x%llx dma); "
"in seg %p (0x%llx dma)\n",
@@ -547,8 +555,9 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
cur_trb->generic.field[1] = 0;
cur_trb->generic.field[2] = 0;
/* Preserve only the cycle bit of this TRB */
- cur_trb->generic.field[3] &= TRB_CYCLE;
- cur_trb->generic.field[3] |= TRB_TYPE(TRB_TR_NOOP);
+ cur_trb->generic.field[3] &= cpu_to_le32(TRB_CYCLE);
+ cur_trb->generic.field[3] |= cpu_to_le32(
+ TRB_TYPE(TRB_TR_NOOP));
xhci_dbg(xhci, "Cancel TRB %p (0x%llx dma) "
"in seg %p (0x%llx dma)\n",
cur_trb,
@@ -662,9 +671,9 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
struct xhci_dequeue_state deq_state;
if (unlikely(TRB_TO_SUSPEND_PORT(
- xhci->cmd_ring->dequeue->generic.field[3]))) {
+ le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])))) {
slot_id = TRB_TO_SLOT_ID(
- xhci->cmd_ring->dequeue->generic.field[3]);
+ 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,
@@ -677,8 +686,8 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
}
memset(&deq_state, 0, sizeof(deq_state));
- slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
- ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
+ 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];
if (list_empty(&ep->cancelled_td_list)) {
@@ -910,9 +919,9 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,
struct xhci_ep_ctx *ep_ctx;
struct xhci_slot_ctx *slot_ctx;
- slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
- ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
- stream_id = TRB_TO_STREAM_ID(trb->generic.field[2]);
+ 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];
ep_ring = xhci_stream_id_to_ring(dev, ep_index, stream_id);
@@ -928,11 +937,11 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,
ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx);
- if (GET_COMP_CODE(event->status) != COMP_SUCCESS) {
+ if (GET_COMP_CODE(le32_to_cpu(event->status)) != COMP_SUCCESS) {
unsigned int ep_state;
unsigned int slot_state;
- switch (GET_COMP_CODE(event->status)) {
+ 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");
@@ -940,9 +949,9 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,
case COMP_CTX_STATE:
xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed due "
"to incorrect slot or ep state.\n");
- ep_state = ep_ctx->ep_info;
+ ep_state = le32_to_cpu(ep_ctx->ep_info);
ep_state &= EP_STATE_MASK;
- slot_state = slot_ctx->dev_state;
+ slot_state = le32_to_cpu(slot_ctx->dev_state);
slot_state = GET_SLOT_STATE(slot_state);
xhci_dbg(xhci, "Slot state = %u, EP state = %u\n",
slot_state, ep_state);
@@ -954,7 +963,7 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,
default:
xhci_warn(xhci, "WARN Set TR Deq Ptr cmd with unknown "
"completion code of %u.\n",
- GET_COMP_CODE(event->status));
+ GET_COMP_CODE(le32_to_cpu(event->status)));
break;
}
/* OK what do we do now? The endpoint state is hosed, and we
@@ -965,10 +974,10 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,
*/
} else {
xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq = @%08llx\n",
- ep_ctx->deq);
+ le64_to_cpu(ep_ctx->deq));
if (xhci_trb_virt_to_dma(dev->eps[ep_index].queued_deq_seg,
- dev->eps[ep_index].queued_deq_ptr) ==
- (ep_ctx->deq & ~(EP_CTX_CYCLE_MASK))) {
+ dev->eps[ep_index].queued_deq_ptr) ==
+ (le64_to_cpu(ep_ctx->deq) & ~(EP_CTX_CYCLE_MASK))) {
/* Update the ring's dequeue segment and dequeue pointer
* to reflect the new position.
*/
@@ -997,13 +1006,13 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci,
int slot_id;
unsigned int ep_index;
- slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
- ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
+ 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(xhci, "Ignoring reset ep completion code of %u\n",
- (unsigned int) GET_COMP_CODE(event->status));
+ (unsigned int) 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
@@ -1040,8 +1049,7 @@ static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
if (xhci->cmd_ring->dequeue != command->command_trb)
return 0;
- command->status =
- GET_COMP_CODE(event->status);
+ command->status = GET_COMP_CODE(le32_to_cpu(event->status));
list_del(&command->cmd_list);
if (command->completion)
complete(command->completion);
@@ -1053,7 +1061,7 @@ static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
static void handle_cmd_completion(struct xhci_hcd *xhci,
struct xhci_event_cmd *event)
{
- int slot_id = TRB_TO_SLOT_ID(event->flags);
+ int slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
u64 cmd_dma;
dma_addr_t cmd_dequeue_dma;
struct xhci_input_control_ctx *ctrl_ctx;
@@ -1062,7 +1070,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
struct xhci_ring *ep_ring;
unsigned int ep_state;
- cmd_dma = event->cmd_trb;
+ cmd_dma = le64_to_cpu(event->cmd_trb);
cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
xhci->cmd_ring->dequeue);
/* Is the command ring deq ptr out of sync with the deq seg ptr? */
@@ -1075,9 +1083,10 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
xhci->error_bitmask |= 1 << 5;
return;
}
- switch (xhci->cmd_ring->dequeue->generic.field[3] & TRB_TYPE_BITMASK) {
+ switch (le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])
+ & TRB_TYPE_BITMASK) {
case TRB_TYPE(TRB_ENABLE_SLOT):
- if (GET_COMP_CODE(event->status) == COMP_SUCCESS)
+ if (GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_SUCCESS)
xhci->slot_id = slot_id;
else
xhci->slot_id = 0;
@@ -1102,7 +1111,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
ctrl_ctx = xhci_get_input_control_ctx(xhci,
virt_dev->in_ctx);
/* Input ctx add_flags are the endpoint index plus one */
- ep_index = xhci_last_valid_endpoint(ctrl_ctx->add_flags) - 1;
+ 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
@@ -1111,8 +1120,8 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
*/
if (xhci->quirks & XHCI_RESET_EP_QUIRK &&
ep_index != (unsigned int) -1 &&
- ctrl_ctx->add_flags - SLOT_FLAG ==
- ctrl_ctx->drop_flags) {
+ 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))
@@ -1129,18 +1138,18 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
bandwidth_change:
xhci_dbg(xhci, "Completed config ep cmd\n");
xhci->devs[slot_id]->cmd_status =
- GET_COMP_CODE(event->status);
+ GET_COMP_CODE(le32_to_cpu(event->status));
complete(&xhci->devs[slot_id]->cmd_completion);
break;
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(event->status);
+ xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(le32_to_cpu(event->status));
complete(&xhci->devs[slot_id]->cmd_completion);
break;
case TRB_TYPE(TRB_ADDR_DEV):
- xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(event->status);
+ xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(le32_to_cpu(event->status));
complete(&xhci->addr_dev);
break;
case TRB_TYPE(TRB_STOP_RING):
@@ -1157,7 +1166,7 @@ bandwidth_change:
case TRB_TYPE(TRB_RESET_DEV):
xhci_dbg(xhci, "Completed reset device command.\n");
slot_id = TRB_TO_SLOT_ID(
- xhci->cmd_ring->dequeue->generic.field[3]);
+ 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);
@@ -1171,8 +1180,8 @@ bandwidth_change:
break;
}
xhci_dbg(xhci, "NEC firmware version %2x.%02x\n",
- NEC_FW_MAJOR(event->status),
- NEC_FW_MINOR(event->status));
+ 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 */
@@ -1187,7 +1196,7 @@ static void handle_vendor_event(struct xhci_hcd *xhci,
{
u32 trb_type;
- trb_type = TRB_FIELD_TO_TYPE(event->generic.field[3]);
+ trb_type = TRB_FIELD_TO_TYPE(le32_to_cpu(event->generic.field[3]));
xhci_dbg(xhci, "Vendor specific event TRB type = %u\n", trb_type);
if (trb_type == TRB_NEC_CMD_COMP && (xhci->quirks & XHCI_NEC_HOST))
handle_cmd_completion(xhci, &event->event_cmd);
@@ -1241,15 +1250,15 @@ static void handle_port_status(struct xhci_hcd *xhci,
unsigned int faked_port_index;
u8 major_revision;
struct xhci_bus_state *bus_state;
- u32 __iomem **port_array;
+ __le32 __iomem **port_array;
bool bogus_port_status = false;
/* Port status change events always have a successful completion code */
- if (GET_COMP_CODE(event->generic.field[2]) != COMP_SUCCESS) {
+ if (GET_COMP_CODE(le32_to_cpu(event->generic.field[2])) != COMP_SUCCESS) {
xhci_warn(xhci, "WARN: xHC returned failed port status event\n");
xhci->error_bitmask |= 1 << 8;
}
- port_id = GET_PORT_ID(event->generic.field[0]);
+ port_id = GET_PORT_ID(le32_to_cpu(event->generic.field[0]));
xhci_dbg(xhci, "Port Status Change Event for port %d\n", port_id);
max_ports = HCS_MAX_PORTS(xhci->hcs_params1);
@@ -1456,7 +1465,7 @@ static int xhci_requires_manual_halt_cleanup(struct xhci_hcd *xhci,
* endpoint anyway. Check if a babble halted the
* endpoint.
*/
- if ((ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_HALTED)
+ if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) == EP_STATE_HALTED)
return 1;
return 0;
@@ -1494,12 +1503,12 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
struct urb_priv *urb_priv;
u32 trb_comp_code;
- slot_id = TRB_TO_SLOT_ID(event->flags);
+ slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
xdev = xhci->devs[slot_id];
- ep_index = TRB_TO_EP_ID(event->flags) - 1;
- ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer);
+ ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1;
+ ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer));
ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
- trb_comp_code = GET_COMP_CODE(event->transfer_len);
+ trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
if (skip)
goto td_cleanup;
@@ -1602,12 +1611,12 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
struct xhci_ep_ctx *ep_ctx;
u32 trb_comp_code;
- slot_id = TRB_TO_SLOT_ID(event->flags);
+ slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
xdev = xhci->devs[slot_id];
- ep_index = TRB_TO_EP_ID(event->flags) - 1;
- ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer);
+ ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1;
+ ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer));
ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
- trb_comp_code = GET_COMP_CODE(event->transfer_len);
+ trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
xhci_debug_trb(xhci, xhci->event_ring->dequeue);
switch (trb_comp_code) {
@@ -1632,6 +1641,9 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
else
*status = 0;
break;
+ case COMP_STOP_INVAL:
+ case COMP_STOP:
+ return finish_td(xhci, td, event_trb, event, ep, status, false);
default:
if (!xhci_requires_manual_halt_cleanup(xhci,
ep_ctx, trb_comp_code))
@@ -1646,7 +1658,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
event_trb != td->last_trb)
td->urb->actual_length =
td->urb->transfer_buffer_length
- - TRB_LEN(event->transfer_len);
+ - TRB_LEN(le32_to_cpu(event->transfer_len));
else
td->urb->actual_length = 0;
@@ -1676,15 +1688,12 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
}
} else {
/* Maybe the event was for the data stage? */
- if (trb_comp_code != COMP_STOP_INVAL) {
- /* We didn't stop on a link TRB in the middle */
- td->urb->actual_length =
- td->urb->transfer_buffer_length -
- TRB_LEN(event->transfer_len);
- xhci_dbg(xhci, "Waiting for status "
- "stage event\n");
- return 0;
- }
+ td->urb->actual_length =
+ td->urb->transfer_buffer_length -
+ TRB_LEN(le32_to_cpu(event->transfer_len));
+ xhci_dbg(xhci, "Waiting for status "
+ "stage event\n");
+ return 0;
}
}
@@ -1708,8 +1717,8 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
u32 trb_comp_code;
bool skip_td = false;
- ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer);
- trb_comp_code = GET_COMP_CODE(event->transfer_len);
+ ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer));
+ trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
urb_priv = td->urb->hcpriv;
idx = urb_priv->td_cnt;
frame = &td->urb->iso_frame_desc[idx];
@@ -1752,15 +1761,14 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
for (cur_trb = ep_ring->dequeue,
cur_seg = ep_ring->deq_seg; cur_trb != event_trb;
next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) {
- if ((cur_trb->generic.field[3] &
+ if ((le32_to_cpu(cur_trb->generic.field[3]) &
TRB_TYPE_BITMASK) != TRB_TYPE(TRB_TR_NOOP) &&
- (cur_trb->generic.field[3] &
+ (le32_to_cpu(cur_trb->generic.field[3]) &
TRB_TYPE_BITMASK) != TRB_TYPE(TRB_LINK))
- len +=
- TRB_LEN(cur_trb->generic.field[2]);
+ len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2]));
}
- len += TRB_LEN(cur_trb->generic.field[2]) -
- TRB_LEN(event->transfer_len);
+ len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) -
+ TRB_LEN(le32_to_cpu(event->transfer_len));
if (trb_comp_code != COMP_STOP_INVAL) {
frame->actual_length = len;
@@ -1815,8 +1823,8 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
struct xhci_segment *cur_seg;
u32 trb_comp_code;
- ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer);
- trb_comp_code = GET_COMP_CODE(event->transfer_len);
+ ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer));
+ trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
switch (trb_comp_code) {
case COMP_SUCCESS:
@@ -1852,18 +1860,18 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
"%d bytes untransferred\n",
td->urb->ep->desc.bEndpointAddress,
td->urb->transfer_buffer_length,
- TRB_LEN(event->transfer_len));
+ TRB_LEN(le32_to_cpu(event->transfer_len)));
/* Fast path - was this the last TRB in the TD for this URB? */
if (event_trb == td->last_trb) {
- if (TRB_LEN(event->transfer_len) != 0) {
+ if (TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
td->urb->actual_length =
td->urb->transfer_buffer_length -
- TRB_LEN(event->transfer_len);
+ TRB_LEN(le32_to_cpu(event->transfer_len));
if (td->urb->transfer_buffer_length <
td->urb->actual_length) {
xhci_warn(xhci, "HC gave bad length "
"of %d bytes left\n",
- TRB_LEN(event->transfer_len));
+ TRB_LEN(le32_to_cpu(event->transfer_len)));
td->urb->actual_length = 0;
if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
*status = -EREMOTEIO;
@@ -1894,20 +1902,20 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
for (cur_trb = ep_ring->dequeue, cur_seg = ep_ring->deq_seg;
cur_trb != event_trb;
next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) {
- if ((cur_trb->generic.field[3] &
+ if ((le32_to_cpu(cur_trb->generic.field[3]) &
TRB_TYPE_BITMASK) != TRB_TYPE(TRB_TR_NOOP) &&
- (cur_trb->generic.field[3] &
+ (le32_to_cpu(cur_trb->generic.field[3]) &
TRB_TYPE_BITMASK) != TRB_TYPE(TRB_LINK))
td->urb->actual_length +=
- TRB_LEN(cur_trb->generic.field[2]);
+ TRB_LEN(le32_to_cpu(cur_trb->generic.field[2]));
}
/* If the ring didn't stop on a Link or No-op TRB, add
* in the actual bytes transferred from the Normal TRB
*/
if (trb_comp_code != COMP_STOP_INVAL)
td->urb->actual_length +=
- TRB_LEN(cur_trb->generic.field[2]) -
- TRB_LEN(event->transfer_len);
+ TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) -
+ TRB_LEN(le32_to_cpu(event->transfer_len));
}
return finish_td(xhci, td, event_trb, event, ep, status, false);
@@ -1937,7 +1945,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
u32 trb_comp_code;
int ret = 0;
- slot_id = TRB_TO_SLOT_ID(event->flags);
+ slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
xdev = xhci->devs[slot_id];
if (!xdev) {
xhci_err(xhci, "ERROR Transfer event pointed to bad slot\n");
@@ -1945,20 +1953,21 @@ static int handle_tx_event(struct xhci_hcd *xhci,
}
/* Endpoint ID is 1 based, our index is zero based */
- ep_index = TRB_TO_EP_ID(event->flags) - 1;
+ ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1;
xhci_dbg(xhci, "%s - ep index = %d\n", __func__, ep_index);
ep = &xdev->eps[ep_index];
- ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer);
+ ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer));
ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
if (!ep_ring ||
- (ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_DISABLED) {
+ (le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) ==
+ EP_STATE_DISABLED) {
xhci_err(xhci, "ERROR Transfer event for disabled endpoint "
"or incorrect stream ring\n");
return -ENODEV;
}
- event_dma = event->buffer;
- trb_comp_code = GET_COMP_CODE(event->transfer_len);
+ event_dma = le64_to_cpu(event->buffer);
+ trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
/* Look for common error cases */
switch (trb_comp_code) {
/* Skip codes that require special handling depending on
@@ -2011,14 +2020,16 @@ static int handle_tx_event(struct xhci_hcd *xhci,
if (!list_empty(&ep_ring->td_list))
xhci_dbg(xhci, "Underrun Event for slot %d ep %d "
"still with TDs queued?\n",
- TRB_TO_SLOT_ID(event->flags), ep_index);
+ TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
+ ep_index);
goto cleanup;
case COMP_OVERRUN:
xhci_dbg(xhci, "overrun event on endpoint\n");
if (!list_empty(&ep_ring->td_list))
xhci_dbg(xhci, "Overrun Event for slot %d ep %d "
"still with TDs queued?\n",
- TRB_TO_SLOT_ID(event->flags), ep_index);
+ TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
+ ep_index);
goto cleanup;
case COMP_MISSED_INT:
/*
@@ -2047,9 +2058,11 @@ static int handle_tx_event(struct xhci_hcd *xhci,
if (list_empty(&ep_ring->td_list)) {
xhci_warn(xhci, "WARN Event TRB for slot %d ep %d "
"with no TDs queued?\n",
- TRB_TO_SLOT_ID(event->flags), ep_index);
+ TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
+ ep_index);
xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
- (unsigned int) (event->flags & TRB_TYPE_BITMASK)>>10);
+ (unsigned int) (le32_to_cpu(event->flags)
+ & TRB_TYPE_BITMASK)>>10);
xhci_print_trb_offsets(xhci, (union xhci_trb *) event);
if (ep->skip) {
ep->skip = false;
@@ -2092,7 +2105,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
* corresponding TD has been cancelled. Just ignore
* the TD.
*/
- if ((event_trb->generic.field[3] & TRB_TYPE_BITMASK)
+ if ((le32_to_cpu(event_trb->generic.field[3])
+ & TRB_TYPE_BITMASK)
== TRB_TYPE(TRB_TR_NOOP)) {
xhci_dbg(xhci,
"event_trb is a no-op TRB. Skip it\n");
@@ -2157,8 +2171,10 @@ cleanup:
/*
* This function handles all OS-owned events on the event ring. It may drop
* xhci->lock between event processing (e.g. to pass up port status changes).
+ * Returns >0 for "possibly more events to process" (caller should call again),
+ * otherwise 0 if done. In future, <0 returns should indicate error code.
*/
-static void xhci_handle_event(struct xhci_hcd *xhci)
+static int xhci_handle_event(struct xhci_hcd *xhci)
{
union xhci_trb *event;
int update_ptrs = 1;
@@ -2167,20 +2183,25 @@ static void xhci_handle_event(struct xhci_hcd *xhci)
xhci_dbg(xhci, "In %s\n", __func__);
if (!xhci->event_ring || !xhci->event_ring->dequeue) {
xhci->error_bitmask |= 1 << 1;
- return;
+ return 0;
}
event = xhci->event_ring->dequeue;
/* Does the HC or OS own the TRB? */
- if ((event->event_cmd.flags & TRB_CYCLE) !=
- xhci->event_ring->cycle_state) {
+ if ((le32_to_cpu(event->event_cmd.flags) & TRB_CYCLE) !=
+ xhci->event_ring->cycle_state) {
xhci->error_bitmask |= 1 << 2;
- return;
+ return 0;
}
xhci_dbg(xhci, "%s - OS owns TRB\n", __func__);
+ /*
+ * Barrier between reading the TRB_CYCLE (valid) flag above and any
+ * speculative reads of the event's flags/data below.
+ */
+ rmb();
/* FIXME: Handle more event types. */
- switch ((event->event_cmd.flags & TRB_TYPE_BITMASK)) {
+ switch ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK)) {
case TRB_TYPE(TRB_COMPLETION):
xhci_dbg(xhci, "%s - calling handle_cmd_completion\n", __func__);
handle_cmd_completion(xhci, &event->event_cmd);
@@ -2202,7 +2223,8 @@ static void xhci_handle_event(struct xhci_hcd *xhci)
update_ptrs = 0;
break;
default:
- if ((event->event_cmd.flags & TRB_TYPE_BITMASK) >= TRB_TYPE(48))
+ if ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK) >=
+ TRB_TYPE(48))
handle_vendor_event(xhci, event);
else
xhci->error_bitmask |= 1 << 3;
@@ -2213,15 +2235,17 @@ static void xhci_handle_event(struct xhci_hcd *xhci)
if (xhci->xhc_state & XHCI_STATE_DYING) {
xhci_dbg(xhci, "xHCI host dying, returning from "
"event handler.\n");
- return;
+ return 0;
}
if (update_ptrs)
/* Update SW event ring dequeue pointer */
inc_deq(xhci, xhci->event_ring, true);
- /* Are there more items on the event ring? */
- xhci_handle_event(xhci);
+ /* Are there more items on the event ring? Caller will call us again to
+ * check.
+ */
+ return 1;
}
/*
@@ -2252,12 +2276,12 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
xhci_dbg(xhci, "op reg status = %08x\n", status);
xhci_dbg(xhci, "Event ring dequeue ptr:\n");
xhci_dbg(xhci, "@%llx %08x %08x %08x %08x\n",
- (unsigned long long)
- xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, trb),
- lower_32_bits(trb->link.segment_ptr),
- upper_32_bits(trb->link.segment_ptr),
- (unsigned int) trb->link.intr_target,
- (unsigned int) trb->link.control);
+ (unsigned long long)
+ xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, trb),
+ lower_32_bits(le64_to_cpu(trb->link.segment_ptr)),
+ upper_32_bits(le64_to_cpu(trb->link.segment_ptr)),
+ (unsigned int) le32_to_cpu(trb->link.intr_target),
+ (unsigned int) le32_to_cpu(trb->link.control));
if (status & STS_FATAL) {
xhci_warn(xhci, "WARNING: Host System Error\n");
@@ -2303,7 +2327,7 @@ hw_died:
/* FIXME this should be a delayed service routine
* that clears the EHB.
*/
- xhci_handle_event(xhci);
+ while (xhci_handle_event(xhci) > 0) {}
temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
/* If necessary, update the HW's version of the event ring deq ptr. */
@@ -2358,10 +2382,10 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
struct xhci_generic_trb *trb;
trb = &ring->enqueue->generic;
- trb->field[0] = field1;
- trb->field[1] = field2;
- trb->field[2] = field3;
- trb->field[3] = field4;
+ trb->field[0] = cpu_to_le32(field1);
+ trb->field[1] = cpu_to_le32(field2);
+ trb->field[2] = cpu_to_le32(field3);
+ trb->field[3] = cpu_to_le32(field4);
inc_enq(xhci, ring, consumer, more_trbs_coming);
}
@@ -2414,17 +2438,16 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
next = ring->enqueue;
while (last_trb(xhci, ring, ring->enq_seg, next)) {
-
/* If we're not dealing with 0.95 hardware,
* clear the chain bit.
*/
if (!xhci_link_trb_quirk(xhci))
- next->link.control &= ~TRB_CHAIN;
+ next->link.control &= cpu_to_le32(~TRB_CHAIN);
else
- next->link.control |= TRB_CHAIN;
+ next->link.control |= cpu_to_le32(TRB_CHAIN);
wmb();
- next->link.control ^= (u32) TRB_CYCLE;
+ next->link.control ^= cpu_to_le32((u32) TRB_CYCLE);
/* Toggle the cycle bit after the last ring segment. */
if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
@@ -2467,8 +2490,8 @@ static int prepare_transfer(struct xhci_hcd *xhci,
}
ret = prepare_ring(xhci, ep_ring,
- ep_ctx->ep_info & EP_STATE_MASK,
- num_trbs, mem_flags);
+ le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK,
+ num_trbs, mem_flags);
if (ret)
return ret;
@@ -2570,9 +2593,9 @@ static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id,
*/
wmb();
if (start_cycle)
- start_trb->field[3] |= start_cycle;
+ start_trb->field[3] |= cpu_to_le32(start_cycle);
else
- start_trb->field[3] &= ~0x1;
+ start_trb->field[3] &= cpu_to_le32(~TRB_CYCLE);
xhci_ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
}
@@ -2590,7 +2613,7 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
int xhci_interval;
int ep_interval;
- xhci_interval = EP_INTERVAL_TO_UFRAMES(ep_ctx->ep_info);
+ xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx->ep_info));
ep_interval = urb->interval;
/* Convert to microframes */
if (urb->dev->speed == USB_SPEED_LOW ||
@@ -2632,6 +2655,35 @@ static u32 xhci_td_remainder(unsigned int remainder)
return (remainder >> 10) << 17;
}
+/*
+ * For xHCI 1.0 host controllers, TD size is the number of packets remaining in
+ * the TD (*not* including this TRB).
+ *
+ * Total TD packet count = total_packet_count =
+ * roundup(TD size in bytes / wMaxPacketSize)
+ *
+ * Packets transferred up to and including this TRB = packets_transferred =
+ * rounddown(total bytes transferred including this TRB / wMaxPacketSize)
+ *
+ * TD size = total_packet_count - packets_transferred
+ *
+ * It must fit in bits 21:17, so it can't be bigger than 31.
+ */
+
+static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len,
+ unsigned int total_packet_count, struct urb *urb)
+{
+ int packets_transferred;
+
+ /* All the TRB queueing functions don't count the current TRB in
+ * running_total.
+ */
+ packets_transferred = (running_total + trb_buff_len) /
+ le16_to_cpu(urb->ep->desc.wMaxPacketSize);
+
+ return xhci_td_remainder(total_packet_count - packets_transferred);
+}
+
static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct urb *urb, int slot_id, unsigned int ep_index)
{
@@ -2642,6 +2694,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct scatterlist *sg;
int num_sgs;
int trb_buff_len, this_sg_len, running_total;
+ unsigned int total_packet_count;
bool first_trb;
u64 addr;
bool more_trbs_coming;
@@ -2655,6 +2708,8 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
num_trbs = count_sg_trbs_needed(xhci, urb);
num_sgs = urb->num_sgs;
+ total_packet_count = roundup(urb->transfer_buffer_length,
+ le16_to_cpu(urb->ep->desc.wMaxPacketSize));
trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id],
ep_index, urb->stream_id,
@@ -2718,6 +2773,11 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
td->last_trb = ep_ring->enqueue;
field |= TRB_IOC;
}
+
+ /* Only set interrupt on short packet for IN endpoints */
+ if (usb_urb_dir_in(urb))
+ field |= TRB_ISP;
+
xhci_dbg(xhci, " sg entry: dma = %#x, len = %#x (%d), "
"64KB boundary at %#x, end dma = %#x\n",
(unsigned int) addr, trb_buff_len, trb_buff_len,
@@ -2730,11 +2790,20 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
(unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1),
(unsigned int) addr + trb_buff_len);
}
- remainder = xhci_td_remainder(urb->transfer_buffer_length -
- running_total) ;
+
+ /* Set the TRB length, TD size, and interrupter fields. */
+ if (xhci->hci_version < 0x100) {
+ remainder = xhci_td_remainder(
+ urb->transfer_buffer_length -
+ running_total);
+ } else {
+ remainder = xhci_v1_0_td_remainder(running_total,
+ trb_buff_len, total_packet_count, urb);
+ }
length_field = TRB_LEN(trb_buff_len) |
remainder |
TRB_INTR_TARGET(0);
+
if (num_trbs > 1)
more_trbs_coming = true;
else
@@ -2743,12 +2812,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
lower_32_bits(addr),
upper_32_bits(addr),
length_field,
- /* We always want to know if the TRB was short,
- * or we won't get an event when it completes.
- * (Unless we use event data TRBs, which are a
- * waste of space and HC resources.)
- */
- field | TRB_ISP | TRB_TYPE(TRB_NORMAL));
+ field | TRB_TYPE(TRB_NORMAL));
--num_trbs;
running_total += trb_buff_len;
@@ -2796,6 +2860,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
u32 field, length_field;
int running_total, trb_buff_len, ret;
+ unsigned int total_packet_count;
u64 addr;
if (urb->num_sgs)
@@ -2850,6 +2915,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
start_cycle = ep_ring->cycle_state;
running_total = 0;
+ total_packet_count = roundup(urb->transfer_buffer_length,
+ le16_to_cpu(urb->ep->desc.wMaxPacketSize));
/* How much data is in the first TRB? */
addr = (u64) urb->transfer_dma;
trb_buff_len = TRB_MAX_BUFF_SIZE -
@@ -2882,11 +2949,24 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
td->last_trb = ep_ring->enqueue;
field |= TRB_IOC;
}
- remainder = xhci_td_remainder(urb->transfer_buffer_length -
- running_total);
+
+ /* Only set interrupt on short packet for IN endpoints */
+ if (usb_urb_dir_in(urb))
+ field |= TRB_ISP;
+
+ /* Set the TRB length, TD size, and interrupter fields. */
+ if (xhci->hci_version < 0x100) {
+ remainder = xhci_td_remainder(
+ urb->transfer_buffer_length -
+ running_total);
+ } else {
+ remainder = xhci_v1_0_td_remainder(running_total,
+ trb_buff_len, total_packet_count, urb);
+ }
length_field = TRB_LEN(trb_buff_len) |
remainder |
TRB_INTR_TARGET(0);
+
if (num_trbs > 1)
more_trbs_coming = true;
else
@@ -2895,12 +2975,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
lower_32_bits(addr),
upper_32_bits(addr),
length_field,
- /* We always want to know if the TRB was short,
- * or we won't get an event when it completes.
- * (Unless we use event data TRBs, which are a
- * waste of space and HC resources.)
- */
- field | TRB_ISP | TRB_TYPE(TRB_NORMAL));
+ field | TRB_TYPE(TRB_NORMAL));
--num_trbs;
running_total += trb_buff_len;
@@ -2978,16 +3053,31 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
field |= TRB_IDT | TRB_TYPE(TRB_SETUP);
if (start_cycle == 0)
field |= 0x1;
+
+ /* xHCI 1.0 6.4.1.2.1: Transfer Type field */
+ if (xhci->hci_version == 0x100) {
+ if (urb->transfer_buffer_length > 0) {
+ if (setup->bRequestType & USB_DIR_IN)
+ field |= TRB_TX_TYPE(TRB_DATA_IN);
+ else
+ field |= TRB_TX_TYPE(TRB_DATA_OUT);
+ }
+ }
+
queue_trb(xhci, ep_ring, false, true,
- /* FIXME endianness is probably going to bite my ass here. */
- setup->bRequestType | setup->bRequest << 8 | setup->wValue << 16,
- setup->wIndex | setup->wLength << 16,
- TRB_LEN(8) | TRB_INTR_TARGET(0),
- /* Immediate data in pointer */
- field);
+ setup->bRequestType | setup->bRequest << 8 | le16_to_cpu(setup->wValue) << 16,
+ le16_to_cpu(setup->wIndex) | le16_to_cpu(setup->wLength) << 16,
+ TRB_LEN(8) | TRB_INTR_TARGET(0),
+ /* Immediate data in pointer */
+ field);
/* If there's data, queue data TRBs */
- field = 0;
+ /* Only set interrupt on short packet for IN endpoints */
+ if (usb_urb_dir_in(urb))
+ field = TRB_ISP | TRB_TYPE(TRB_DATA);
+ else
+ field = TRB_TYPE(TRB_DATA);
+
length_field = TRB_LEN(urb->transfer_buffer_length) |
xhci_td_remainder(urb->transfer_buffer_length) |
TRB_INTR_TARGET(0);
@@ -2998,8 +3088,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
lower_32_bits(urb->transfer_dma),
upper_32_bits(urb->transfer_dma),
length_field,
- /* Event on short tx */
- field | TRB_ISP | TRB_TYPE(TRB_DATA) | ep_ring->cycle_state);
+ field | ep_ring->cycle_state);
}
/* Save the DMA address of the last TRB in the TD */
@@ -3045,6 +3134,63 @@ static int count_isoc_trbs_needed(struct xhci_hcd *xhci,
return num_trbs;
}
+/*
+ * The transfer burst count field of the isochronous TRB defines the number of
+ * bursts that are required to move all packets in this TD. Only SuperSpeed
+ * devices can burst up to bMaxBurst number of packets per service interval.
+ * This field is zero based, meaning a value of zero in the field means one
+ * burst. Basically, for everything but SuperSpeed devices, this field will be
+ * zero. Only xHCI 1.0 host controllers support this field.
+ */
+static unsigned int xhci_get_burst_count(struct xhci_hcd *xhci,
+ struct usb_device *udev,
+ struct urb *urb, unsigned int total_packet_count)
+{
+ unsigned int max_burst;
+
+ if (xhci->hci_version < 0x100 || udev->speed != USB_SPEED_SUPER)
+ return 0;
+
+ max_burst = urb->ep->ss_ep_comp.bMaxBurst;
+ return roundup(total_packet_count, max_burst + 1) - 1;
+}
+
+/*
+ * Returns the number of packets in the last "burst" of packets. This field is
+ * valid for all speeds of devices. USB 2.0 devices can only do one "burst", so
+ * the last burst packet count is equal to the total number of packets in the
+ * TD. SuperSpeed endpoints can have up to 3 bursts. All but the last burst
+ * must contain (bMaxBurst + 1) number of packets, but the last burst can
+ * contain 1 to (bMaxBurst + 1) packets.
+ */
+static unsigned int xhci_get_last_burst_packet_count(struct xhci_hcd *xhci,
+ struct usb_device *udev,
+ struct urb *urb, unsigned int total_packet_count)
+{
+ unsigned int max_burst;
+ unsigned int residue;
+
+ if (xhci->hci_version < 0x100)
+ return 0;
+
+ switch (udev->speed) {
+ case USB_SPEED_SUPER:
+ /* bMaxBurst is zero based: 0 means 1 packet per burst */
+ max_burst = urb->ep->ss_ep_comp.bMaxBurst;
+ residue = total_packet_count % (max_burst + 1);
+ /* If residue is zero, the last burst contains (max_burst + 1)
+ * number of packets, but the TLBPC field is zero-based.
+ */
+ if (residue == 0)
+ return max_burst;
+ return residue - 1;
+ default:
+ if (total_packet_count == 0)
+ return 0;
+ return total_packet_count - 1;
+ }
+}
+
/* This is for isoc transfer */
static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct urb *urb, int slot_id, unsigned int ep_index)
@@ -3085,12 +3231,22 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
/* Queue the first TRB, even if it's zero-length */
for (i = 0; i < num_tds; i++) {
- first_trb = true;
+ unsigned int total_packet_count;
+ unsigned int burst_count;
+ unsigned int residue;
+ first_trb = true;
running_total = 0;
addr = start_addr + urb->iso_frame_desc[i].offset;
td_len = urb->iso_frame_desc[i].length;
td_remain_len = td_len;
+ /* FIXME: Ignoring zero-length packets, can those happen? */
+ total_packet_count = roundup(td_len,
+ le16_to_cpu(urb->ep->desc.wMaxPacketSize));
+ burst_count = xhci_get_burst_count(xhci, urb->dev, urb,
+ total_packet_count);
+ residue = xhci_get_last_burst_packet_count(xhci,
+ urb->dev, urb, total_packet_count);
trbs_per_td = count_isoc_trbs_needed(xhci, urb, i);
@@ -3104,7 +3260,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
for (j = 0; j < trbs_per_td; j++) {
u32 remainder = 0;
- field = 0;
+ field = TRB_TBC(burst_count) | TRB_TLBPC(residue);
if (first_trb) {
/* Queue the isoc TRB */
@@ -3123,6 +3279,10 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
field |= ep_ring->cycle_state;
}
+ /* Only set interrupt on short packet for IN EPs */
+ if (usb_urb_dir_in(urb))
+ field |= TRB_ISP;
+
/* Chain all the TRBs together; clear the chain bit in
* the last TRB to indicate it's the last TRB in the
* chain.
@@ -3133,6 +3293,11 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
} else {
td->last_trb = ep_ring->enqueue;
field |= TRB_IOC;
+ if (xhci->hci_version == 0x100) {
+ /* Set BEI bit except for the last td */
+ if (i < num_tds - 1)
+ field |= TRB_BEI;
+ }
more_trbs_coming = false;
}
@@ -3142,20 +3307,24 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
if (trb_buff_len > td_remain_len)
trb_buff_len = td_remain_len;
- remainder = xhci_td_remainder(td_len - running_total);
+ /* Set the TRB length, TD size, & interrupter fields. */
+ if (xhci->hci_version < 0x100) {
+ remainder = xhci_td_remainder(
+ td_len - running_total);
+ } else {
+ remainder = xhci_v1_0_td_remainder(
+ running_total, trb_buff_len,
+ total_packet_count, urb);
+ }
length_field = TRB_LEN(trb_buff_len) |
remainder |
TRB_INTR_TARGET(0);
+
queue_trb(xhci, ep_ring, false, more_trbs_coming,
lower_32_bits(addr),
upper_32_bits(addr),
length_field,
- /* We always want to know if the TRB was short,
- * or we won't get an event when it completes.
- * (Unless we use event data TRBs, which are a
- * waste of space and HC resources.)
- */
- field | TRB_ISP);
+ field);
running_total += trb_buff_len;
addr += trb_buff_len;
@@ -3211,8 +3380,8 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
/* Check the ring to guarantee there is enough room for the whole urb.
* Do not insert any td of the urb to the ring if the check failed.
*/
- ret = prepare_ring(xhci, ep_ring, ep_ctx->ep_info & EP_STATE_MASK,
- num_trbs, mem_flags);
+ ret = prepare_ring(xhci, ep_ring, le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK,
+ num_trbs, mem_flags);
if (ret)
return ret;
@@ -3224,7 +3393,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
urb->dev->speed == USB_SPEED_FULL)
urb->start_frame >>= 3;
- xhci_interval = EP_INTERVAL_TO_UFRAMES(ep_ctx->ep_info);
+ xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx->ep_info));
ep_interval = urb->interval;
/* Convert to microframes */
if (urb->dev->speed == USB_SPEED_LOW ||
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 81b976e45880..8f2a56ece44f 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -973,8 +973,8 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
out_ctx = xhci->devs[slot_id]->out_ctx;
ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
- hw_max_packet_size = MAX_PACKET_DECODED(ep_ctx->ep_info2);
- max_packet_size = urb->dev->ep0.desc.wMaxPacketSize;
+ hw_max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2));
+ max_packet_size = le16_to_cpu(urb->dev->ep0.desc.wMaxPacketSize);
if (hw_max_packet_size != max_packet_size) {
xhci_dbg(xhci, "Max Packet Size for ep 0 changed.\n");
xhci_dbg(xhci, "Max packet size in usb_device = %d\n",
@@ -988,15 +988,15 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
xhci->devs[slot_id]->out_ctx, ep_index);
in_ctx = xhci->devs[slot_id]->in_ctx;
ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, ep_index);
- ep_ctx->ep_info2 &= ~MAX_PACKET_MASK;
- ep_ctx->ep_info2 |= MAX_PACKET(max_packet_size);
+ ep_ctx->ep_info2 &= cpu_to_le32(~MAX_PACKET_MASK);
+ ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet_size));
/* Set up the input context flags for the command */
/* FIXME: This won't work if a non-default control endpoint
* changes max packet sizes.
*/
ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
- ctrl_ctx->add_flags = EP0_FLAG;
+ ctrl_ctx->add_flags = cpu_to_le32(EP0_FLAG);
ctrl_ctx->drop_flags = 0;
xhci_dbg(xhci, "Slot %d input context\n", slot_id);
@@ -1010,7 +1010,7 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
/* Clean up the input context for later use by bandwidth
* functions.
*/
- ctrl_ctx->add_flags = SLOT_FLAG;
+ ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG);
}
return ret;
}
@@ -1331,27 +1331,30 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
/* If the HC already knows the endpoint is disabled,
* or the HCD has noted it is disabled, ignore this request
*/
- if ((ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_DISABLED ||
- ctrl_ctx->drop_flags & xhci_get_endpoint_flag(&ep->desc)) {
+ if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) ==
+ EP_STATE_DISABLED ||
+ le32_to_cpu(ctrl_ctx->drop_flags) &
+ xhci_get_endpoint_flag(&ep->desc)) {
xhci_warn(xhci, "xHCI %s called with disabled ep %p\n",
__func__, ep);
return 0;
}
- ctrl_ctx->drop_flags |= drop_flag;
- new_drop_flags = ctrl_ctx->drop_flags;
+ ctrl_ctx->drop_flags |= cpu_to_le32(drop_flag);
+ new_drop_flags = le32_to_cpu(ctrl_ctx->drop_flags);
- ctrl_ctx->add_flags &= ~drop_flag;
- new_add_flags = ctrl_ctx->add_flags;
+ ctrl_ctx->add_flags &= cpu_to_le32(~drop_flag);
+ new_add_flags = le32_to_cpu(ctrl_ctx->add_flags);
- last_ctx = xhci_last_valid_endpoint(ctrl_ctx->add_flags);
+ last_ctx = xhci_last_valid_endpoint(le32_to_cpu(ctrl_ctx->add_flags));
slot_ctx = xhci_get_slot_ctx(xhci, in_ctx);
/* Update the last valid endpoint context, if we deleted the last one */
- if ((slot_ctx->dev_info & LAST_CTX_MASK) > LAST_CTX(last_ctx)) {
- slot_ctx->dev_info &= ~LAST_CTX_MASK;
- slot_ctx->dev_info |= LAST_CTX(last_ctx);
+ if ((le32_to_cpu(slot_ctx->dev_info) & LAST_CTX_MASK) >
+ LAST_CTX(last_ctx)) {
+ slot_ctx->dev_info &= cpu_to_le32(~LAST_CTX_MASK);
+ slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(last_ctx));
}
- new_slot_info = slot_ctx->dev_info;
+ new_slot_info = le32_to_cpu(slot_ctx->dev_info);
xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep);
@@ -1419,7 +1422,8 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
/* If the HCD has already noted the endpoint is enabled,
* ignore this request.
*/
- if (ctrl_ctx->add_flags & xhci_get_endpoint_flag(&ep->desc)) {
+ if (le32_to_cpu(ctrl_ctx->add_flags) &
+ xhci_get_endpoint_flag(&ep->desc)) {
xhci_warn(xhci, "xHCI %s called with enabled ep %p\n",
__func__, ep);
return 0;
@@ -1437,8 +1441,8 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
return -ENOMEM;
}
- ctrl_ctx->add_flags |= added_ctxs;
- new_add_flags = ctrl_ctx->add_flags;
+ ctrl_ctx->add_flags |= cpu_to_le32(added_ctxs);
+ new_add_flags = le32_to_cpu(ctrl_ctx->add_flags);
/* If xhci_endpoint_disable() was called for this endpoint, but the
* xHC hasn't been notified yet through the check_bandwidth() call,
@@ -1446,15 +1450,16 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
* descriptors. We must drop and re-add this endpoint, so we leave the
* drop flags alone.
*/
- new_drop_flags = ctrl_ctx->drop_flags;
+ new_drop_flags = le32_to_cpu(ctrl_ctx->drop_flags);
slot_ctx = xhci_get_slot_ctx(xhci, in_ctx);
/* Update the last valid endpoint context, if we just added one past */
- if ((slot_ctx->dev_info & LAST_CTX_MASK) < LAST_CTX(last_ctx)) {
- slot_ctx->dev_info &= ~LAST_CTX_MASK;
- slot_ctx->dev_info |= LAST_CTX(last_ctx);
+ if ((le32_to_cpu(slot_ctx->dev_info) & LAST_CTX_MASK) <
+ LAST_CTX(last_ctx)) {
+ slot_ctx->dev_info &= cpu_to_le32(~LAST_CTX_MASK);
+ slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(last_ctx));
}
- new_slot_info = slot_ctx->dev_info;
+ new_slot_info = le32_to_cpu(slot_ctx->dev_info);
/* Store the usb_device pointer for later use */
ep->hcpriv = udev;
@@ -1484,9 +1489,9 @@ static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *vir
ctrl_ctx->drop_flags = 0;
ctrl_ctx->add_flags = 0;
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
- slot_ctx->dev_info &= ~LAST_CTX_MASK;
+ slot_ctx->dev_info &= cpu_to_le32(~LAST_CTX_MASK);
/* Endpoint 0 is always valid */
- slot_ctx->dev_info |= LAST_CTX(1);
+ slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1));
for (i = 1; i < 31; ++i) {
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, i);
ep_ctx->ep_info = 0;
@@ -1497,7 +1502,7 @@ static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *vir
}
static int xhci_configure_endpoint_result(struct xhci_hcd *xhci,
- struct usb_device *udev, int *cmd_status)
+ struct usb_device *udev, u32 *cmd_status)
{
int ret;
@@ -1535,7 +1540,7 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci,
}
static int xhci_evaluate_context_result(struct xhci_hcd *xhci,
- struct usb_device *udev, int *cmd_status)
+ struct usb_device *udev, u32 *cmd_status)
{
int ret;
struct xhci_virt_device *virt_dev = xhci->devs[udev->slot_id];
@@ -1555,6 +1560,11 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci,
xhci_dbg_ctx(xhci, virt_dev->out_ctx, 1);
ret = -EINVAL;
break;
+ case COMP_MEL_ERR:
+ /* Max Exit Latency too large error */
+ dev_warn(&udev->dev, "WARN: Max Exit Latency too large\n");
+ ret = -EINVAL;
+ break;
case COMP_SUCCESS:
dev_dbg(&udev->dev, "Successful evaluate context command\n");
ret = 0;
@@ -1581,7 +1591,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
unsigned long flags;
struct xhci_container_ctx *in_ctx;
struct completion *cmd_completion;
- int *cmd_status;
+ u32 *cmd_status;
struct xhci_virt_device *virt_dev;
spin_lock_irqsave(&xhci->lock, flags);
@@ -1595,8 +1605,8 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
/* Enqueue pointer can be left pointing to the link TRB,
* we must handle that
*/
- if ((command->command_trb->link.control & TRB_TYPE_BITMASK)
- == TRB_TYPE(TRB_LINK))
+ if ((le32_to_cpu(command->command_trb->link.control)
+ & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK))
command->command_trb =
xhci->cmd_ring->enq_seg->next->trbs;
@@ -1672,14 +1682,13 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
/* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */
ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
- ctrl_ctx->add_flags |= SLOT_FLAG;
- ctrl_ctx->add_flags &= ~EP0_FLAG;
- ctrl_ctx->drop_flags &= ~SLOT_FLAG;
- ctrl_ctx->drop_flags &= ~EP0_FLAG;
+ ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
+ ctrl_ctx->add_flags &= cpu_to_le32(~EP0_FLAG);
+ ctrl_ctx->drop_flags &= cpu_to_le32(~(SLOT_FLAG | EP0_FLAG));
xhci_dbg(xhci, "New Input Control Context:\n");
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
xhci_dbg_ctx(xhci, virt_dev->in_ctx,
- LAST_CTX_TO_EP_NUM(slot_ctx->dev_info));
+ LAST_CTX_TO_EP_NUM(le32_to_cpu(slot_ctx->dev_info)));
ret = xhci_configure_endpoint(xhci, udev, NULL,
false, false);
@@ -1690,10 +1699,19 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
xhci_dbg(xhci, "Output context after successful config ep cmd:\n");
xhci_dbg_ctx(xhci, virt_dev->out_ctx,
- LAST_CTX_TO_EP_NUM(slot_ctx->dev_info));
+ LAST_CTX_TO_EP_NUM(le32_to_cpu(slot_ctx->dev_info)));
+ /* Free any rings that were dropped, but not changed. */
+ for (i = 1; i < 31; ++i) {
+ if ((ctrl_ctx->drop_flags & (1 << (i + 1))) &&
+ !(ctrl_ctx->add_flags & (1 << (i + 1))))
+ xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
+ }
xhci_zero_in_ctx(xhci, virt_dev);
- /* Install new rings and free or cache any old rings */
+ /*
+ * Install any rings for completely new endpoints or changed endpoints,
+ * and free or cache any old rings from changed endpoints.
+ */
for (i = 1; i < 31; ++i) {
if (!virt_dev->eps[i].new_ring)
continue;
@@ -1740,10 +1758,10 @@ static void xhci_setup_input_ctx_for_config_ep(struct xhci_hcd *xhci,
{
struct xhci_input_control_ctx *ctrl_ctx;
ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
- ctrl_ctx->add_flags = add_flags;
- ctrl_ctx->drop_flags = drop_flags;
+ ctrl_ctx->add_flags = cpu_to_le32(add_flags);
+ ctrl_ctx->drop_flags = cpu_to_le32(drop_flags);
xhci_slot_copy(xhci, in_ctx, out_ctx);
- ctrl_ctx->add_flags |= SLOT_FLAG;
+ ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
xhci_dbg(xhci, "Input Context:\n");
xhci_dbg_ctx(xhci, in_ctx, xhci_last_valid_endpoint(add_flags));
@@ -1772,7 +1790,7 @@ static void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci,
deq_state->new_deq_ptr);
return;
}
- ep_ctx->deq = addr | deq_state->new_cycle_state;
+ ep_ctx->deq = cpu_to_le64(addr | deq_state->new_cycle_state);
added_ctxs = xhci_get_endpoint_flag_from_index(ep_index);
xhci_setup_input_ctx_for_config_ep(xhci, xhci->devs[slot_id]->in_ctx,
@@ -2327,8 +2345,8 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
/* Enqueue pointer can be left pointing to the link TRB,
* we must handle that
*/
- if ((reset_device_cmd->command_trb->link.control & TRB_TYPE_BITMASK)
- == TRB_TYPE(TRB_LINK))
+ if ((le32_to_cpu(reset_device_cmd->command_trb->link.control)
+ & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK))
reset_device_cmd->command_trb =
xhci->cmd_ring->enq_seg->next->trbs;
@@ -2542,6 +2560,17 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
virt_dev = xhci->devs[udev->slot_id];
+ if (WARN_ON(!virt_dev)) {
+ /*
+ * In plug/unplug torture test with an NEC controller,
+ * a zero-dereference was observed once due to virt_dev = 0.
+ * Print useful debug rather than crash if it is observed again!
+ */
+ xhci_warn(xhci, "Virt dev invalid for slot_id 0x%x!\n",
+ udev->slot_id);
+ return -EINVAL;
+ }
+
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
/*
* If this is the first Set Address since device plug-in or
@@ -2609,10 +2638,10 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
temp_64 = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
xhci_dbg(xhci, "Op regs DCBAA ptr = %#016llx\n", temp_64);
xhci_dbg(xhci, "Slot ID %d dcbaa entry @%p = %#016llx\n",
- udev->slot_id,
- &xhci->dcbaa->dev_context_ptrs[udev->slot_id],
- (unsigned long long)
- xhci->dcbaa->dev_context_ptrs[udev->slot_id]);
+ udev->slot_id,
+ &xhci->dcbaa->dev_context_ptrs[udev->slot_id],
+ (unsigned long long)
+ le64_to_cpu(xhci->dcbaa->dev_context_ptrs[udev->slot_id]));
xhci_dbg(xhci, "Output Context DMA address = %#08llx\n",
(unsigned long long)virt_dev->out_ctx->dma);
xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
@@ -2626,7 +2655,8 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
/* Use kernel assigned address for devices; store xHC assigned
* address locally. */
- virt_dev->address = (slot_ctx->dev_state & DEV_ADDR_MASK) + 1;
+ virt_dev->address = (le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK)
+ + 1;
/* Zero the input context control for later use */
ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
ctrl_ctx->add_flags = 0;
@@ -2670,24 +2700,29 @@ int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
spin_lock_irqsave(&xhci->lock, flags);
xhci_slot_copy(xhci, config_cmd->in_ctx, vdev->out_ctx);
ctrl_ctx = xhci_get_input_control_ctx(xhci, config_cmd->in_ctx);
- ctrl_ctx->add_flags |= SLOT_FLAG;
+ ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
slot_ctx = xhci_get_slot_ctx(xhci, config_cmd->in_ctx);
- slot_ctx->dev_info |= DEV_HUB;
+ slot_ctx->dev_info |= cpu_to_le32(DEV_HUB);
if (tt->multi)
- slot_ctx->dev_info |= DEV_MTT;
+ slot_ctx->dev_info |= cpu_to_le32(DEV_MTT);
if (xhci->hci_version > 0x95) {
xhci_dbg(xhci, "xHCI version %x needs hub "
"TT think time and number of ports\n",
(unsigned int) xhci->hci_version);
- slot_ctx->dev_info2 |= XHCI_MAX_PORTS(hdev->maxchild);
+ slot_ctx->dev_info2 |= cpu_to_le32(XHCI_MAX_PORTS(hdev->maxchild));
/* Set TT think time - convert from ns to FS bit times.
* 0 = 8 FS bit times, 1 = 16 FS bit times,
* 2 = 24 FS bit times, 3 = 32 FS bit times.
+ *
+ * xHCI 1.0: this field shall be 0 if the device is not a
+ * High-spped hub.
*/
think_time = tt->think_time;
if (think_time != 0)
think_time = (think_time / 666) - 1;
- slot_ctx->tt_info |= TT_THINK_TIME(think_time);
+ if (xhci->hci_version < 0x100 || hdev->speed == USB_SPEED_HIGH)
+ slot_ctx->tt_info |=
+ cpu_to_le32(TT_THINK_TIME(think_time));
} else {
xhci_dbg(xhci, "xHCI version %x doesn't need hub "
"TT think time or number of ports\n",
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index ba1be6b7cc6d..e12db7cfb9bb 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -57,13 +57,13 @@
* @run_regs_off: RTSOFF - Runtime register space offset
*/
struct xhci_cap_regs {
- u32 hc_capbase;
- u32 hcs_params1;
- u32 hcs_params2;
- u32 hcs_params3;
- u32 hcc_params;
- u32 db_off;
- u32 run_regs_off;
+ __le32 hc_capbase;
+ __le32 hcs_params1;
+ __le32 hcs_params2;
+ __le32 hcs_params3;
+ __le32 hcc_params;
+ __le32 db_off;
+ __le32 run_regs_off;
/* Reserved up to (CAPLENGTH - 0x1C) */
};
@@ -155,26 +155,26 @@ struct xhci_cap_regs {
* devices.
*/
struct xhci_op_regs {
- u32 command;
- u32 status;
- u32 page_size;
- u32 reserved1;
- u32 reserved2;
- u32 dev_notification;
- u64 cmd_ring;
+ __le32 command;
+ __le32 status;
+ __le32 page_size;
+ __le32 reserved1;
+ __le32 reserved2;
+ __le32 dev_notification;
+ __le64 cmd_ring;
/* rsvd: offset 0x20-2F */
- u32 reserved3[4];
- u64 dcbaa_ptr;
- u32 config_reg;
+ __le32 reserved3[4];
+ __le64 dcbaa_ptr;
+ __le32 config_reg;
/* rsvd: offset 0x3C-3FF */
- u32 reserved4[241];
+ __le32 reserved4[241];
/* port 1 registers, which serve as a base address for other ports */
- u32 port_status_base;
- u32 port_power_base;
- u32 port_link_base;
- u32 reserved5;
+ __le32 port_status_base;
+ __le32 port_power_base;
+ __le32 port_link_base;
+ __le32 reserved5;
/* registers for ports 2-255 */
- u32 reserved6[NUM_PORT_REGS*254];
+ __le32 reserved6[NUM_PORT_REGS*254];
};
/* USBCMD - USB command - command bitmasks */
@@ -382,12 +382,12 @@ struct xhci_op_regs {
* updates the dequeue pointer.
*/
struct xhci_intr_reg {
- u32 irq_pending;
- u32 irq_control;
- u32 erst_size;
- u32 rsvd;
- u64 erst_base;
- u64 erst_dequeue;
+ __le32 irq_pending;
+ __le32 irq_control;
+ __le32 erst_size;
+ __le32 rsvd;
+ __le64 erst_base;
+ __le64 erst_dequeue;
};
/* irq_pending bitmasks */
@@ -432,8 +432,8 @@ struct xhci_intr_reg {
* or larger accesses"
*/
struct xhci_run_regs {
- u32 microframe_index;
- u32 rsvd[7];
+ __le32 microframe_index;
+ __le32 rsvd[7];
struct xhci_intr_reg ir_set[128];
};
@@ -447,7 +447,7 @@ struct xhci_run_regs {
* Section 5.6
*/
struct xhci_doorbell_array {
- u32 doorbell[256];
+ __le32 doorbell[256];
};
#define DB_VALUE(ep, stream) ((((ep) + 1) & 0xff) | ((stream) << 16))
@@ -504,12 +504,12 @@ struct xhci_container_ctx {
* reserved at the end of the slot context for HC internal use.
*/
struct xhci_slot_ctx {
- u32 dev_info;
- u32 dev_info2;
- u32 tt_info;
- u32 dev_state;
+ __le32 dev_info;
+ __le32 dev_info2;
+ __le32 tt_info;
+ __le32 dev_state;
/* offset 0x10 to 0x1f reserved for HC internal use */
- u32 reserved[4];
+ __le32 reserved[4];
};
/* dev_info bitmasks */
@@ -580,12 +580,12 @@ struct xhci_slot_ctx {
* reserved at the end of the endpoint context for HC internal use.
*/
struct xhci_ep_ctx {
- u32 ep_info;
- u32 ep_info2;
- u64 deq;
- u32 tx_info;
+ __le32 ep_info;
+ __le32 ep_info2;
+ __le64 deq;
+ __le32 tx_info;
/* offset 0x14 - 0x1f reserved for HC internal use */
- u32 reserved[3];
+ __le32 reserved[3];
};
/* ep_info bitmasks */
@@ -660,9 +660,9 @@ struct xhci_ep_ctx {
* @add_context: set the bit of the endpoint context you want to enable
*/
struct xhci_input_control_ctx {
- u32 drop_flags;
- u32 add_flags;
- u32 rsvd2[6];
+ __le32 drop_flags;
+ __le32 add_flags;
+ __le32 rsvd2[6];
};
/* Represents everything that is needed to issue a command on the command ring.
@@ -688,9 +688,9 @@ struct xhci_command {
struct xhci_stream_ctx {
/* 64-bit stream ring address, cycle state, and stream type */
- u64 stream_ring;
+ __le64 stream_ring;
/* offset 0x14 - 0x1f reserved for HC internal use */
- u32 reserved[2];
+ __le32 reserved[2];
};
/* Stream Context Types (section 6.4.1) - bits 3:1 of stream ctx deq ptr */
@@ -803,7 +803,7 @@ struct xhci_virt_device {
*/
struct xhci_device_context_array {
/* 64-bit device addresses; we only write 32-bit addresses */
- u64 dev_context_ptrs[MAX_HC_SLOTS];
+ __le64 dev_context_ptrs[MAX_HC_SLOTS];
/* private xHCD pointers */
dma_addr_t dma;
};
@@ -816,10 +816,10 @@ struct xhci_device_context_array {
struct xhci_transfer_event {
/* 64-bit buffer address, or immediate data */
- u64 buffer;
- u32 transfer_len;
+ __le64 buffer;
+ __le32 transfer_len;
/* This field is interpreted differently based on the type of TRB */
- u32 flags;
+ __le32 flags;
};
/** Transfer Event bit fields **/
@@ -881,7 +881,9 @@ struct xhci_transfer_event {
#define COMP_STOP_INVAL 27
/* Control Abort Error - Debug Capability - control pipe aborted */
#define COMP_DBG_ABORT 28
-/* TRB type 29 and 30 reserved */
+/* Max Exit Latency Too Large Error */
+#define COMP_MEL_ERR 29
+/* TRB type 30 reserved */
/* Isoc Buffer Overrun - an isoc IN ep sent more data than could fit in TD */
#define COMP_BUFF_OVER 31
/* Event Lost Error - xHC has an "internal event overrun condition" */
@@ -898,9 +900,9 @@ struct xhci_transfer_event {
struct xhci_link_trb {
/* 64-bit segment pointer*/
- u64 segment_ptr;
- u32 intr_target;
- u32 control;
+ __le64 segment_ptr;
+ __le32 intr_target;
+ __le32 control;
};
/* control bitfields */
@@ -909,9 +911,9 @@ struct xhci_link_trb {
/* Command completion event TRB */
struct xhci_event_cmd {
/* Pointer to command TRB, or the value passed by the event data trb */
- u64 cmd_trb;
- u32 status;
- u32 flags;
+ __le64 cmd_trb;
+ __le32 status;
+ __le32 flags;
};
/* flags bitmasks */
@@ -943,6 +945,8 @@ struct xhci_event_cmd {
/* Interrupter Target - which MSI-X vector to target the completion event at */
#define TRB_INTR_TARGET(p) (((p) & 0x3ff) << 22)
#define GET_INTR_TARGET(p) (((p) >> 22) & 0x3ff)
+#define TRB_TBC(p) (((p) & 0x3) << 7)
+#define TRB_TLBPC(p) (((p) & 0xf) << 16)
/* Cycle bit - indicates TRB ownership by HC or HCD */
#define TRB_CYCLE (1<<0)
@@ -962,15 +966,20 @@ struct xhci_event_cmd {
/* The buffer pointer contains immediate data */
#define TRB_IDT (1<<6)
+/* Block Event Interrupt */
+#define TRB_BEI (1<<9)
/* Control transfer TRB specific fields */
#define TRB_DIR_IN (1<<16)
+#define TRB_TX_TYPE(p) ((p) << 16)
+#define TRB_DATA_OUT 2
+#define TRB_DATA_IN 3
/* Isochronous TRB specific fields */
#define TRB_SIA (1<<31)
struct xhci_generic_trb {
- u32 field[4];
+ __le32 field[4];
};
union xhci_trb {
@@ -1118,10 +1127,10 @@ struct xhci_ring {
struct xhci_erst_entry {
/* 64-bit event ring segment address */
- u64 seg_addr;
- u32 seg_size;
+ __le64 seg_addr;
+ __le32 seg_size;
/* Set to zero */
- u32 rsvd;
+ __le32 rsvd;
};
struct xhci_erst {
@@ -1286,10 +1295,10 @@ struct xhci_hcd {
/* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */
u8 *port_array;
/* Array of pointers to USB 3.0 PORTSC registers */
- u32 __iomem **usb3_ports;
+ __le32 __iomem **usb3_ports;
unsigned int num_usb3_ports;
/* Array of pointers to USB 2.0 PORTSC registers */
- u32 __iomem **usb2_ports;
+ __le32 __iomem **usb2_ports;
unsigned int num_usb2_ports;
};
@@ -1322,12 +1331,12 @@ static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci)
/* TODO: copied from ehci.h - can be refactored? */
/* xHCI spec says all registers are little endian */
static inline unsigned int xhci_readl(const struct xhci_hcd *xhci,
- __u32 __iomem *regs)
+ __le32 __iomem *regs)
{
return readl(regs);
}
static inline void xhci_writel(struct xhci_hcd *xhci,
- const unsigned int val, __u32 __iomem *regs)
+ const unsigned int val, __le32 __iomem *regs)
{
xhci_dbg(xhci,
"`MEM_WRITE_DWORD(3'b000, 32'h%p, 32'h%0x, 4'hf);\n",
@@ -1345,7 +1354,7 @@ static inline void xhci_writel(struct xhci_hcd *xhci,
* the high dword, and write order is irrelevant.
*/
static inline u64 xhci_read_64(const struct xhci_hcd *xhci,
- __u64 __iomem *regs)
+ __le64 __iomem *regs)
{
__u32 __iomem *ptr = (__u32 __iomem *) regs;
u64 val_lo = readl(ptr);
@@ -1353,7 +1362,7 @@ static inline u64 xhci_read_64(const struct xhci_hcd *xhci,
return val_lo + (val_hi << 32);
}
static inline void xhci_write_64(struct xhci_hcd *xhci,
- const u64 val, __u64 __iomem *regs)
+ const u64 val, __le64 __iomem *regs)
{
__u32 __iomem *ptr = (__u32 __iomem *) regs;
u32 val_lo = lower_32_bits(val);
OpenPOWER on IntegriCloud