summaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/Kconfig1
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-atmel.c29
-rw-r--r--drivers/usb/host/ehci-core.h12
-rw-r--r--drivers/usb/host/ehci-hcd.c61
-rw-r--r--drivers/usb/host/ehci-omap.c16
-rw-r--r--drivers/usb/host/ehci.h12
-rw-r--r--drivers/usb/host/ohci-at91.c33
-rw-r--r--drivers/usb/host/ohci-hcd.c29
-rw-r--r--drivers/usb/host/ohci.h1
-rw-r--r--drivers/usb/host/xhci-mem.c105
-rw-r--r--drivers/usb/host/xhci-ring.c222
-rw-r--r--drivers/usb/host/xhci.c99
-rw-r--r--drivers/usb/host/xhci.h34
14 files changed, 364 insertions, 291 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 891523c4d2..d38b4dcac4 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config USB_EHCI
bool "EHCI driver"
depends on HAS_DMA
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index e7a6cf213e..e55dff4580 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_USB_EHCI) += ehci-hcd.o
obj-$(CONFIG_USB_EHCI_OMAP) += ehci-omap.o
obj-$(CONFIG_USB_EHCI_ATMEL) += ehci-atmel.o
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index c3f8ab7ad5..f176babfa7 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -1,16 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* (C) Copyright 2010 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.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; version 2 of
- * the License.
- *
- * 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.
- *
*/
#include <common.h>
@@ -18,9 +8,9 @@
#include <linux/err.h>
#include <driver.h>
#include <init.h>
-#include <usb/usb.h>
-#include <usb/usb_defs.h>
-#include <usb/ehci.h>
+#include <linux/usb/usb.h>
+#include <linux/usb/usb_defs.h>
+#include <linux/usb/ehci.h>
#include <errno.h>
#include <io.h>
@@ -28,7 +18,7 @@
struct atmel_ehci_priv {
struct ehci_host *ehci;
- struct device_d *dev;
+ struct device *dev;
struct clk *iclk;
struct clk *uclk;
};
@@ -57,7 +47,7 @@ static void atmel_stop_clock(struct atmel_ehci_priv *atehci)
clk_disable(atehci->uclk);
}
-static int atmel_ehci_probe(struct device_d *dev)
+static int atmel_ehci_probe(struct device *dev)
{
int ret;
struct resource *iores;
@@ -66,7 +56,7 @@ static int atmel_ehci_probe(struct device_d *dev)
const char *uclk_name;
struct ehci_host *ehci;
- uclk_name = (dev->device_node) ? "usb_clk" : "uhpck";
+ uclk_name = (dev->of_node) ? "usb_clk" : "uhpck";
atehci = xzalloc(sizeof(*atehci));
atehci->dev = dev;
@@ -107,7 +97,7 @@ static int atmel_ehci_probe(struct device_d *dev)
return 0;
}
-static void atmel_ehci_remove(struct device_d *dev)
+static void atmel_ehci_remove(struct device *dev)
{
struct atmel_ehci_priv *atehci = dev->priv;
@@ -123,8 +113,9 @@ static const struct of_device_id atmel_ehci_dt_ids[] = {
{ .compatible = "atmel,at91sam9g45-ehci" },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids);
-static struct driver_d atmel_ehci_driver = {
+static struct driver atmel_ehci_driver = {
.name = "atmel-ehci",
.probe = atmel_ehci_probe,
.remove = atmel_ehci_remove,
diff --git a/drivers/usb/host/ehci-core.h b/drivers/usb/host/ehci-core.h
index 584dd541ad..8f43783f7e 100644
--- a/drivers/usb/host/ehci-core.h
+++ b/drivers/usb/host/ehci-core.h
@@ -1,18 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*-
* Copyright (c) 2007-2008, Juniper Networks, Inc.
* Copyright (c) 2008, Excito Elektronik i Skåne AB
* All rights reserved.
- *
- * 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 version 2 of
- * the License.
- *
- * 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.
- *
*/
#ifndef USB_EHCI_CORE_H
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 30a16103eb..7ae3a285a0 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1,26 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*-
* Copyright (c) 2007-2008, Juniper Networks, Inc.
* Copyright (c) 2008, Excito Elektronik i Skåne AB
* Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
*
* All rights reserved.
- *
- * 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 version 2 of
- * the License.
- *
- * 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.
- *
*/
/*#define DEBUG */
#include <common.h>
#include <dma.h>
#include <asm/byteorder.h>
-#include <usb/usb.h>
+#include <linux/usb/usb.h>
#include <io.h>
#include <malloc.h>
#include <driver.h>
@@ -29,7 +19,7 @@
#include <clock.h>
#include <errno.h>
#include <of.h>
-#include <usb/ehci.h>
+#include <linux/usb/ehci.h>
#include <linux/err.h>
#include <linux/sizes.h>
#include <linux/clk.h>
@@ -39,7 +29,7 @@
struct ehci_host {
int rootdev;
- struct device_d *dev;
+ struct device *dev;
struct ehci_hccr *hccr;
struct ehci_hcor *hcor;
struct usb_host host;
@@ -252,7 +242,7 @@ static int ehci_td_buffer(struct qTD *td, dma_addr_t addr, size_t sz)
return 0;
}
-static int ehci_prepare_qtd(struct device_d *dev,
+static int ehci_prepare_qtd(struct device *dev,
struct qTD *td, uint32_t token,
void *buffer, size_t length,
dma_addr_t *buffer_dma,
@@ -520,7 +510,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
}
#if defined(CONFIG_MACH_EFIKA_MX_SMARTBOOK) && defined(CONFIG_USB_ULPI)
-#include <usb/ulpi.h>
+#include <linux/usb/ulpi.h>
/*
* Add support for setting CHRGVBUS to workaround a hardware bug on efika mx/sb
* boards.
@@ -1351,7 +1341,7 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
return result;
}
-struct ehci_host *ehci_register(struct device_d *dev, struct ehci_data *data)
+struct ehci_host *ehci_register(struct device *dev, struct ehci_data *data)
{
struct usb_host *host;
struct ehci_host *ehci;
@@ -1408,12 +1398,12 @@ void ehci_unregister(struct ehci_host *ehci)
free(ehci);
}
-static int ehci_probe(struct device_d *dev)
+static int ehci_probe(struct device *dev)
{
struct resource *iores;
struct ehci_data data = {};
struct ehci_platform_data *pdata = dev->platform_data;
- struct device_node *dn = dev->device_node;
+ struct device_node *dn = dev->of_node;
struct ehci_host *ehci;
struct clk_bulk_data *clks;
int num_clocks, ret;
@@ -1431,20 +1421,6 @@ static int ehci_probe(struct device_d *dev)
*/
data.flags = EHCI_HAS_TT;
- iores = dev_request_mem_resource(dev, 0);
- if (IS_ERR(iores))
- return PTR_ERR(iores);
- data.hccr = IOMEM(iores->start);
-
- if (dev->num_resources > 1) {
- iores = dev_request_mem_resource(dev, 1);
- if (IS_ERR(iores))
- return PTR_ERR(iores);
- data.hcor = IOMEM(iores->start);
- }
- else
- data.hcor = NULL;
-
usb2_generic_phy = phy_optional_get(dev, "usb");
if (IS_ERR(usb2_generic_phy))
return PTR_ERR(usb2_generic_phy);
@@ -1466,6 +1442,20 @@ static int ehci_probe(struct device_d *dev)
if (ret)
return ret;
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ data.hccr = IOMEM(iores->start);
+
+ if (dev->num_resources > 1) {
+ iores = dev_request_mem_resource(dev, 1);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ data.hcor = IOMEM(iores->start);
+ }
+ else
+ data.hcor = NULL;
+
ehci = ehci_register(dev, &data);
if (IS_ERR(ehci))
return PTR_ERR(ehci);
@@ -1475,7 +1465,7 @@ static int ehci_probe(struct device_d *dev)
return 0;
}
-static void ehci_remove(struct device_d *dev)
+static void ehci_remove(struct device *dev)
{
struct ehci_host *ehci = dev->priv;
@@ -1489,8 +1479,9 @@ static __maybe_unused struct of_device_id ehci_platform_dt_ids[] = {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, ehci_platform_dt_ids);
-static struct driver_d ehci_driver = {
+static struct driver ehci_driver = {
.name = "ehci",
.probe = ehci_probe,
.remove = ehci_remove,
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index fc5a54f671..e364796a1a 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -1,8 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2010 Michael Grzeschik <mgr@pengutronix.de>
- *
- * This file is released under the GPLv2
- *
*/
/*
@@ -12,16 +10,16 @@
/*-------------------------------------------------------------------------*/
#include <mfd/twl4030.h>
-#include <usb/twl4030.h>
-#include <mach/ehci.h>
+#include <linux/usb/twl4030.h>
+#include <mach/omap/ehci.h>
#include <common.h>
#include <io.h>
#include <clock.h>
#include <gpio.h>
-#include <mach/omap3-silicon.h>
-#include <mach/omap3-clock.h>
-#include <mach/cm-regbits-34xx.h>
-#include <mach/sys_info.h>
+#include <mach/omap/omap3-silicon.h>
+#include <mach/omap/omap3-clock.h>
+#include <mach/omap/cm-regbits-34xx.h>
+#include <mach/omap/sys_info.h>
void omap_usb_utmi_init(struct omap_hcd *omap, u8 tll_channel_mask)
{
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 4b9092d1fe..49196bfc7d 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -1,18 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*-
* Copyright (c) 2007-2008, Juniper Networks, Inc.
* Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
* All rights reserved.
- *
- * 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 version 2 of
- * the License.
- *
- * 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.
- *
*/
#ifndef USB_EHCI_H
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 05ed2876c6..867c0977be 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -1,30 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* (C) Copyright 2010 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.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; version 2 of
- * the License.
- *
- * 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.
- *
*/
#include <common.h>
#include <linux/clk.h>
#include <driver.h>
#include <init.h>
-#include <usb/usb.h>
-#include <usb/usb_defs.h>
+#include <linux/usb/usb.h>
+#include <linux/usb/usb_defs.h>
#include <errno.h>
#include <gpio.h>
#include <of_gpio.h>
#include <io.h>
-#include <mach/board.h>
+#include <mach/at91/board.h>
#include "ohci.h"
@@ -33,7 +23,7 @@
struct ohci_at91_priv {
- struct device_d *dev;
+ struct device *dev;
struct clk *iclk;
struct clk *fclk;
struct ohci_regs __iomem *regs;
@@ -64,13 +54,13 @@ static void at91_stop_clock(struct ohci_at91_priv *ohci_at91)
clk_disable(ohci_at91->iclk);
}
-static int at91_ohci_probe_dt(struct device_d *dev)
+static int at91_ohci_probe_dt(struct device *dev)
{
u32 ports;
int i, ret, gpio;
enum of_gpio_flags flags;
struct at91_usbh_data *pdata;
- struct device_node *np = dev->device_node;
+ struct device_node *np = dev->of_node;
pdata = xzalloc(sizeof(*pdata));
dev->platform_data = pdata;
@@ -117,7 +107,7 @@ static int at91_ohci_probe_dt(struct device_d *dev)
return 0;
}
-static int at91_ohci_probe(struct device_d *dev)
+static int at91_ohci_probe(struct device *dev)
{
int ret;
struct resource *io;
@@ -126,7 +116,7 @@ static int at91_ohci_probe(struct device_d *dev)
dev->priv = ohci_at91;
ohci_at91->dev = dev;
- if (dev->device_node) {
+ if (dev->of_node) {
ret = at91_ohci_probe_dt(dev);
if (ret < 0)
return ret;
@@ -169,7 +159,7 @@ static int at91_ohci_probe(struct device_d *dev)
return 0;
}
-static void at91_ohci_remove(struct device_d *dev)
+static void at91_ohci_remove(struct device *dev)
{
struct at91_usbh_data *pdata = dev->platform_data;
struct ohci_at91_priv *ohci_at91 = dev->priv;
@@ -204,8 +194,9 @@ static const struct of_device_id at91_ohci_dt_ids[] = {
{ .compatible = "atmel,at91rm9200-ohci" },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, at91_ohci_dt_ids);
-static struct driver_d at91_ohci_driver = {
+static struct driver at91_ohci_driver = {
.name = "at91_ohci",
.probe = at91_ohci_probe,
.remove = at91_ohci_remove,
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index a28c48b4c8..ae4c34e818 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* URB OHCI HCD (Host Controller Driver) for USB on the AT91RM9200 and PCI bus.
*
@@ -16,18 +17,6 @@
*
* Modified for the MP2USB by (C) Copyright 2005 Eric Benard
* ebenard@eukrea.com - based on s3c24x0's driver
- *
- * 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.
- *
- *
*/
/*
* IMPORTANT NOTES
@@ -38,12 +27,11 @@
* to activate workaround for bug #41 or this driver will NOT work!
*/
#include <common.h>
-#include <dma.h>
#include <clock.h>
#include <dma.h>
#include <malloc.h>
-#include <usb/usb.h>
-#include <usb/usb_defs.h>
+#include <linux/usb/usb.h>
+#include <linux/usb/usb_defs.h>
#include <init.h>
#include <errno.h>
#include <linux/err.h>
@@ -854,7 +842,8 @@ static void td_fill(struct ohci *ohci, unsigned int info,
td->hwNextTD = virt_to_phys((void *)m32_swap((unsigned long)td_pt));
- dma_sync_single_for_device((unsigned long)data, len, DMA_BIDIRECTIONAL);
+ dma_sync_single_for_device(ohci->host.hw_dev, (unsigned long)data,
+ len, DMA_BIDIRECTIONAL);
/* append to queue */
td->ed->hwTailP = td->hwNextTD;
@@ -1090,7 +1079,7 @@ static int dl_done_list(struct ohci *ohci)
unsigned long ptdphys = virt_to_phys(ptd);
struct td *td_list;
- dma_sync_single_for_device((unsigned long)ptdphys,
+ dma_sync_single_for_device(ohci->host.hw_dev, (unsigned long)ptdphys,
sizeof(struct td) * NUM_TD, DMA_BIDIRECTIONAL);
td_list = dl_reverse_done_list(ohci);
@@ -1527,7 +1516,7 @@ static int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *b
dev->status = stat;
dev->act_len = urb->actual_length;
- dma_sync_single_for_cpu((unsigned long)buffer, transfer_len,
+ dma_sync_single_for_cpu(host->hw_dev, (unsigned long)buffer, transfer_len,
DMA_BIDIRECTIONAL);
pkt_print(urb, dev, pipe, buffer, transfer_len,
@@ -1787,7 +1776,7 @@ static int ohci_init(struct usb_host *host)
return 0;
}
-static int ohci_probe(struct device_d *dev)
+static int ohci_probe(struct device *dev)
{
struct resource *iores;
struct usb_host *host;
@@ -1822,7 +1811,7 @@ static int ohci_probe(struct device_d *dev)
return 0;
}
-static struct driver_d ohci_driver = {
+static struct driver ohci_driver = {
.name = "ohci",
.probe = ohci_probe,
};
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 9c9b8375ce..7d70bcb719 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* URB OHCI HCD (Host Controller Driver) for USB.
*
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index f66dadef12..e962bfde3f 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* USB HOST XHCI Controller stack
*
@@ -20,8 +20,8 @@
#include <io.h>
#include <linux/err.h>
#include <linux/sizes.h>
-#include <usb/usb.h>
-#include <usb/xhci.h>
+#include <linux/usb/usb.h>
+#include <linux/usb/xhci.h>
#include <asm/unaligned.h>
#include "xhci.h"
@@ -82,11 +82,11 @@ static void xhci_free(struct xhci_ctrl *ctrl, void *ptr)
* @param size size of memory to be allocated
* @return allocates the memory and returns the aligned pointer
*/
-static void *xhci_malloc(struct xhci_ctrl *ctrl, unsigned int size)
+static void *xhci_malloc(struct xhci_ctrl *ctrl, unsigned int size, dma_addr_t *dma_addr)
{
void *ptr;
- ptr = dma_alloc_coherent(size, DMA_ADDRESS_BROKEN);
+ ptr = dma_alloc_coherent(size, dma_addr);
if (!ptr)
return NULL;
@@ -145,7 +145,7 @@ static void xhci_scratchpad_free(struct xhci_ctrl *ctrl)
ctrl->dcbaa->dev_context_ptrs[0] = 0;
- xhci_free(ctrl, (void *)(uintptr_t)ctrl->scratchpad->sp_array[0]);
+ xhci_free(ctrl, ctrl->scratchpad->scratchpad);
xhci_free(ctrl, ctrl->scratchpad->sp_array);
free(ctrl->scratchpad);
ctrl->scratchpad = NULL;
@@ -234,14 +234,13 @@ static void xhci_link_segments(struct xhci_segment *prev,
struct xhci_segment *next, bool link_trbs)
{
u32 val;
- u64 val_64 = 0;
if (!prev || !next)
return;
prev->next = next;
if (link_trbs) {
- val_64 = (uintptr_t)next->trbs;
- prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr = val_64;
+ prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr =
+ cpu_to_le64(next->dma);
/*
* Set the last TRB in the segment to
@@ -249,8 +248,7 @@ static void xhci_link_segments(struct xhci_segment *prev,
*/
val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control);
val &= ~TRB_TYPE_BITMASK;
- val |= (TRB_LINK << TRB_TYPE_SHIFT);
-
+ val |= TRB_TYPE(TRB_LINK);
prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val);
}
}
@@ -295,7 +293,7 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_ctrl *ctrl)
seg = xzalloc(sizeof(*seg));
- seg->trbs = xhci_malloc(ctrl, SEGMENT_SIZE);
+ seg->trbs = xhci_malloc(ctrl, SEGMENT_SIZE, &seg->dma);
return seg;
}
@@ -365,6 +363,7 @@ static int xhci_scratchpad_alloc(struct xhci_ctrl *ctrl)
struct xhci_hccr *hccr = ctrl->hccr;
struct xhci_hcor *hcor = ctrl->hcor;
struct xhci_scratchpad *scratchpad;
+ dma_addr_t val_64;
int num_sp;
uint32_t page_size;
void *buf;
@@ -379,11 +378,11 @@ static int xhci_scratchpad_alloc(struct xhci_ctrl *ctrl)
goto fail_sp;
ctrl->scratchpad = scratchpad;
- scratchpad->sp_array = xhci_malloc(ctrl, num_sp * sizeof(u64));
+ scratchpad->sp_array = xhci_malloc(ctrl, num_sp * sizeof(u64), &val_64);
if (!scratchpad->sp_array)
goto fail_sp2;
- ctrl->dcbaa->dev_context_ptrs[0] =
- cpu_to_le64((uintptr_t)scratchpad->sp_array);
+
+ ctrl->dcbaa->dev_context_ptrs[0] = cpu_to_le64(val_64);
xhci_flush_cache((uintptr_t)&ctrl->dcbaa->dev_context_ptrs[0],
sizeof(ctrl->dcbaa->dev_context_ptrs[0]));
@@ -397,17 +396,21 @@ static int xhci_scratchpad_alloc(struct xhci_ctrl *ctrl)
BUG_ON(i == 16);
page_size = 1 << (i + 12);
- buf = xhci_malloc(ctrl, num_sp * page_size);
+ buf = xhci_malloc(ctrl, num_sp * page_size, &val_64);
if (!buf)
goto fail_sp3;
xhci_flush_cache((uintptr_t)buf, num_sp * page_size);
+ scratchpad->scratchpad = buf;
for (i = 0; i < num_sp; i++) {
- uintptr_t ptr = (uintptr_t)buf + i * page_size;
- scratchpad->sp_array[i] = cpu_to_le64(ptr);
+ scratchpad->sp_array[i] = cpu_to_le64(val_64);
+ val_64 += page_size;
}
+ xhci_flush_cache((uintptr_t)scratchpad->sp_array,
+ sizeof(u64) * num_sp);
+
return 0;
fail_sp3:
@@ -438,11 +441,11 @@ static struct xhci_container_ctx
BUG_ON((type != XHCI_CTX_TYPE_DEVICE) && (type != XHCI_CTX_TYPE_INPUT));
ctx->type = type;
ctx->size = (MAX_EP_CTX_NUM + 1) *
- CTX_SIZE(readl(&ctrl->hccr->cr_hccparams));
+ CTX_SIZE(xhci_readl(&ctrl->hccr->cr_hccparams));
if (type == XHCI_CTX_TYPE_INPUT)
- ctx->size += CTX_SIZE(readl(&ctrl->hccr->cr_hccparams));
+ ctx->size += CTX_SIZE(xhci_readl(&ctrl->hccr->cr_hccparams));
- ctx->bytes = xhci_malloc(ctrl, ctx->size);
+ ctx->bytes = xhci_malloc(ctrl, ctx->size, &ctx->dma);
return ctx;
}
@@ -464,8 +467,7 @@ int xhci_alloc_virt_device(struct xhci_ctrl *ctrl, unsigned int slot_id)
return -EEXIST;
}
- ctrl->devs[slot_id] = (struct xhci_virt_device *)
- malloc(sizeof(struct xhci_virt_device));
+ ctrl->devs[slot_id] = malloc(sizeof(struct xhci_virt_device));
if (!ctrl->devs[slot_id]) {
dev_err(ctrl->dev, "Failed to allocate virtual device\n");
@@ -494,10 +496,10 @@ int xhci_alloc_virt_device(struct xhci_ctrl *ctrl, unsigned int slot_id)
/* Allocate endpoint 0 ring */
virt_dev->eps[0].ring = xhci_ring_alloc(ctrl, 1, true);
- byte_64 = (uintptr_t)(virt_dev->out_ctx->bytes);
+ byte_64 = virt_dev->out_ctx->dma;
/* Point to output device context in dcbaa. */
- ctrl->dcbaa->dev_context_ptrs[slot_id] = byte_64;
+ ctrl->dcbaa->dev_context_ptrs[slot_id] = cpu_to_le64(byte_64);
xhci_flush_cache((uintptr_t)&ctrl->dcbaa->dev_context_ptrs[slot_id],
sizeof(__le64));
@@ -516,29 +518,27 @@ int xhci_alloc_virt_device(struct xhci_ctrl *ctrl, unsigned int slot_id)
int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
struct xhci_hcor *hcor)
{
+ dma_addr_t dma;
uint64_t val_64;
uint64_t trb_64;
uint32_t val;
- unsigned long deq;
+ uint64_t deq;
int i;
struct xhci_segment *seg;
/* DCBAA initialization */
- ctrl->dcbaa = xhci_malloc(ctrl, sizeof(*ctrl->dcbaa));
- if (!ctrl->dcbaa) {
- dev_err(ctrl->dev, "unable to allocate DCBA\n");
- return -ENOMEM;
- }
+ ctrl->dcbaa = xhci_malloc(ctrl, sizeof(struct xhci_device_context_array),
+ &dma);
+ ctrl->dcbaa->dma = dma;
- val_64 = (uintptr_t)ctrl->dcbaa;
/* Set the pointer in DCBAA register */
- xhci_writeq(&hcor->or_dcbaap, val_64);
+ xhci_writeq(&hcor->or_dcbaap, dma);
/* Command ring control pointer register initialization */
ctrl->cmd_ring = xhci_ring_alloc(ctrl, 1, true);
/* Set the address in the Command Ring Control register */
- trb_64 = (uintptr_t)ctrl->cmd_ring->first_seg->trbs;
+ trb_64 = ctrl->cmd_ring->first_seg->dma;
val_64 = xhci_readq(&hcor->or_crcr);
val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
(trb_64 & (u64) ~CMD_RING_RSVD_BITS) |
@@ -560,8 +560,8 @@ int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
/* Event ring does not maintain link TRB */
ctrl->event_ring = xhci_ring_alloc(ctrl, ERST_NUM_SEGS, false);
- ctrl->erst.entries =
- xhci_malloc(ctrl, sizeof(struct xhci_erst_entry) * ERST_NUM_SEGS);
+ ctrl->erst.entries = xhci_malloc(ctrl, sizeof(struct xhci_erst_entry) *
+ ERST_NUM_SEGS, &ctrl->erst.erst_dma_addr);
ctrl->erst.num_entries = ERST_NUM_SEGS;
@@ -570,9 +570,8 @@ int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
val++) {
struct xhci_erst_entry *entry = &ctrl->erst.entries[val];
- trb_64 = 0;
- trb_64 = (uintptr_t)seg->trbs;
- xhci_writeq(&entry->seg_addr, trb_64);
+ trb_64 = seg->dma;
+ entry->seg_addr = cpu_to_le64(trb_64);
entry->seg_size = cpu_to_le32(TRBS_PER_SEGMENT);
entry->rsvd = 0;
seg = seg->next;
@@ -580,7 +579,8 @@ int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
xhci_flush_cache((uintptr_t)ctrl->erst.entries,
ERST_NUM_SEGS * sizeof(struct xhci_erst_entry));
- deq = (unsigned long)ctrl->event_ring->dequeue;
+ deq = xhci_trb_virt_to_dma(ctrl->event_ring->deq_seg,
+ ctrl->event_ring->dequeue);
/* Update HC event ring dequeue pointer */
xhci_writeq(&ctrl->ir_set->erst_dequeue,
@@ -595,7 +595,7 @@ int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
/* this is the event ring segment table pointer */
val_64 = xhci_readq(&ctrl->ir_set->erst_base);
val_64 &= ERST_PTR_MASK;
- val_64 |= ((uintptr_t)(ctrl->erst.entries) & ~ERST_PTR_MASK);
+ val_64 |= ctrl->erst.erst_dma_addr & ~ERST_PTR_MASK;
xhci_writeq(&ctrl->ir_set->erst_base, val_64);
@@ -645,7 +645,7 @@ struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_ctrl *ctrl,
return (struct xhci_slot_ctx *)ctx->bytes;
return (struct xhci_slot_ctx *)
- (ctx->bytes + CTX_SIZE(readl(&ctrl->hccr->cr_hccparams)));
+ (ctx->bytes + CTX_SIZE(xhci_readl(&ctrl->hccr->cr_hccparams)));
}
/**
@@ -667,7 +667,7 @@ struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_ctrl *ctrl,
return (struct xhci_ep_ctx *)
(ctx->bytes +
- (ep_index * CTX_SIZE(readl(&ctrl->hccr->cr_hccparams))));
+ (ep_index * CTX_SIZE(xhci_readl(&ctrl->hccr->cr_hccparams))));
}
/**
@@ -776,7 +776,7 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl,
dev_dbg(&udev->dev, "route string 0x%x\n", route);
- slot_ctx->dev_info |= route;
+ slot_ctx->dev_info |= cpu_to_le32(route);
switch (speed) {
case USB_SPEED_SUPER:
@@ -824,25 +824,22 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl,
/* Step 4 - ring already allocated */
/* Step 5 */
- ep0_ctx->ep_info2 = cpu_to_le32(CTRL_EP << EP_TYPE_SHIFT);
+ ep0_ctx->ep_info2 = cpu_to_le32(EP_TYPE(CTRL_EP));
dev_dbg(&udev->dev, "SPEED = %d\n", speed);
switch (speed) {
case USB_SPEED_SUPER:
- ep0_ctx->ep_info2 |= cpu_to_le32(((512 & MAX_PACKET_MASK) <<
- MAX_PACKET_SHIFT));
+ ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(512));
dev_dbg(&udev->dev, "Setting Packet size = 512bytes\n");
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 |= cpu_to_le32(((64 & MAX_PACKET_MASK) <<
- MAX_PACKET_SHIFT));
+ ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(64));
dev_dbg(&udev->dev, "Setting Packet size = 64bytes\n");
break;
case USB_SPEED_LOW:
- ep0_ctx->ep_info2 |= cpu_to_le32(((8 & MAX_PACKET_MASK) <<
- MAX_PACKET_SHIFT));
+ ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(8));
dev_dbg(&udev->dev, "Setting Packet size = 8bytes\n");
break;
default:
@@ -851,11 +848,9 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl,
}
/* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */
- ep0_ctx->ep_info2 |=
- cpu_to_le32(((0 & MAX_BURST_MASK) << MAX_BURST_SHIFT) |
- ((3 & ERROR_COUNT_MASK) << ERROR_COUNT_SHIFT));
+ ep0_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(0) | ERROR_COUNT(3));
- trb_64 = (uintptr_t)virt_dev->eps[0].ring->first_seg->trbs;
+ trb_64 = virt_dev->eps[0].ring->first_seg->dma;
ep0_ctx->deq = cpu_to_le64(trb_64 | virt_dev->eps[0].ring->cycle_state);
/*
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 61b1b55a27..691d9c7463 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* USB HOST XHCI Controller stack
*
@@ -19,12 +19,30 @@
#include <io.h>
#include <linux/err.h>
#include <linux/sizes.h>
-#include <usb/usb.h>
-#include <usb/xhci.h>
+#include <linux/usb/usb.h>
+#include <linux/usb/xhci.h>
#include <asm/unaligned.h>
#include "xhci.h"
+/*
+ * Returns zero if the TRB isn't in this segment, otherwise it returns the DMA
+ * address of the TRB.
+ */
+dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg,
+ union xhci_trb *trb)
+{
+ unsigned long segment_offset;
+
+ BUG_ON(!seg || !trb || trb < seg->trbs);
+
+ /* offset in TRBs */
+ segment_offset = trb - seg->trbs;
+ BUG_ON(segment_offset >= TRBS_PER_SEGMENT);
+
+ return seg->dma + (segment_offset * sizeof(*trb));
+}
+
/**
* Is this TRB a link TRB or was the last TRB the last TRB in this event ring
* segment? I.e. would the updated event TRB pointer step off the end of the
@@ -181,12 +199,11 @@ static void inc_deq(struct xhci_ctrl *ctrl, struct xhci_ring *ring)
* @param trb_fields pointer to trb field array containing TRB contents
* @return pointer to the enqueued trb
*/
-static struct xhci_generic_trb *queue_trb(struct xhci_ctrl *ctrl,
- struct xhci_ring *ring,
- bool more_trbs_coming,
- unsigned int *trb_fields)
+static dma_addr_t queue_trb(struct xhci_ctrl *ctrl, struct xhci_ring *ring,
+ bool more_trbs_coming, unsigned int *trb_fields)
{
struct xhci_generic_trb *trb;
+ dma_addr_t addr;
int i;
trb = &ring->enqueue->generic;
@@ -196,9 +213,11 @@ static struct xhci_generic_trb *queue_trb(struct xhci_ctrl *ctrl,
xhci_flush_cache((uintptr_t)trb, sizeof(struct xhci_generic_trb));
+ addr = xhci_trb_virt_to_dma(ring->enq_seg, (union xhci_trb *)trb);
+
inc_enq(ctrl, ring, more_trbs_coming);
- return trb;
+ return addr;
}
/**
@@ -273,16 +292,15 @@ static int prepare_ring(struct xhci_ctrl *ctrl, struct xhci_ring *ep_ring,
* @param cmd Command type to enqueue
* @return none
*/
-void xhci_queue_command(struct xhci_ctrl *ctrl, u8 *ptr, u32 slot_id,
+void xhci_queue_command(struct xhci_ctrl *ctrl, dma_addr_t addr, u32 slot_id,
u32 ep_index, trb_type cmd)
{
u32 fields[4];
- u64 val_64 = (uintptr_t)ptr;
BUG_ON(prepare_ring(ctrl, ctrl->cmd_ring, EP_STATE_RUNNING));
- fields[0] = lower_32_bits(val_64);
- fields[1] = upper_32_bits(val_64);
+ fields[0] = lower_32_bits(addr);
+ fields[1] = upper_32_bits(addr);
fields[2] = 0;
fields[3] = TRB_TYPE(cmd) | SLOT_ID_FOR_TRB(slot_id) |
ctrl->cmd_ring->cycle_state;
@@ -396,12 +414,15 @@ static void giveback_first_trb(struct usb_device *udev, int ep_index,
*/
void xhci_acknowledge_event(struct xhci_ctrl *ctrl)
{
+ dma_addr_t deq;
+
/* Advance our dequeue pointer to the next event */
inc_deq(ctrl, ctrl->event_ring);
/* Inform the hardware */
- xhci_writeq(&ctrl->ir_set->erst_dequeue,
- (uintptr_t)ctrl->event_ring->dequeue | ERST_EHB);
+ deq = xhci_trb_virt_to_dma(ctrl->event_ring->deq_seg,
+ ctrl->event_ring->dequeue);
+ xhci_writeq(&ctrl->ir_set->erst_dequeue, deq | ERST_EHB);
}
/**
@@ -436,7 +457,8 @@ static int event_ready(struct xhci_ctrl *ctrl)
* @param expected TRB type expected from Event TRB
* @return pointer to event trb
*/
-union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected)
+union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected,
+ unsigned int timeout_ms)
{
trb_type type;
uint64_t start = get_time_ns();
@@ -448,7 +470,8 @@ union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected)
continue;
type = TRB_FIELD_TO_TYPE(le32_to_cpu(event->event_cmd.flags));
- if (type == expected)
+ if (type == expected ||
+ (expected == TRB_NONE && type != TRB_PORT_STATUS))
return event;
if (type == TRB_PORT_STATUS)
@@ -461,7 +484,7 @@ union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected)
le32_to_cpu(event->generic.field[2])) !=
COMP_SUCCESS);
else
- dev_err(ctrl->dev, "Unexpected XHCI event TRB, skipping... "
+ dev_dbg(ctrl->dev, "Unexpected XHCI event TRB, skipping... "
"(%08x %08x %08x %08x)\n",
le32_to_cpu(event->generic.field[0]),
le32_to_cpu(event->generic.field[1]),
@@ -469,13 +492,50 @@ union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected)
le32_to_cpu(event->generic.field[3]));
xhci_acknowledge_event(ctrl);
- } while (!is_timeout_non_interruptible(start, 5 * SECOND));
+ } while (!is_timeout_non_interruptible(start, timeout_ms * MSECOND));
if (expected == TRB_TRANSFER)
return NULL;
- dev_err(ctrl->dev, "XHCI timeout on event type %d... cannot recover.\n", expected);
- BUG();
+ dev_warn(ctrl->dev, "XHCI timeout on event type %d...\n", expected);
+
+ return NULL;
+}
+
+/*
+ * Send reset endpoint command for given endpoint. This recovers from a
+ * halted endpoint (e.g. due to a stall error).
+ */
+static void reset_ep(struct usb_device *udev, int ep_index, unsigned int timeout_ms)
+{
+ struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
+ struct xhci_ring *ring = ctrl->devs[udev->slot_id]->eps[ep_index].ring;
+ union xhci_trb *event;
+ u64 addr;
+ u32 field;
+
+ dev_info(&udev->dev, "Resetting EP %d...\n", ep_index);
+
+ xhci_queue_command(ctrl, 0, udev->slot_id, ep_index, TRB_RESET_EP);
+ event = xhci_wait_for_event(ctrl, TRB_COMPLETION, timeout_ms);
+ if (!event)
+ return;
+
+ field = le32_to_cpu(event->trans_event.flags);
+ BUG_ON(TRB_TO_SLOT_ID(field) != udev->slot_id);
+ xhci_acknowledge_event(ctrl);
+
+ addr = xhci_trb_virt_to_dma(ring->enq_seg,
+ (void *)((uintptr_t)ring->enqueue | ring->cycle_state));
+ xhci_queue_command(ctrl, addr, udev->slot_id, ep_index, TRB_SET_DEQ);
+ event = xhci_wait_for_event(ctrl, TRB_COMPLETION, timeout_ms);
+ if (!event)
+ return;
+
+ BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
+ != udev->slot_id || GET_COMP_CODE(le32_to_cpu(
+ event->event_cmd.status)) != COMP_SUCCESS);
+ xhci_acknowledge_event(ctrl);
}
/*
@@ -491,27 +551,49 @@ static void abort_td(struct usb_device *udev, int ep_index)
struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
struct xhci_ring *ring = ctrl->devs[udev->slot_id]->eps[ep_index].ring;
union xhci_trb *event;
+ xhci_comp_code comp;
+ trb_type type;
+ dma_addr_t addr;
u32 field;
- xhci_queue_command(ctrl, NULL, udev->slot_id, ep_index, TRB_STOP_RING);
+ xhci_queue_command(ctrl, 0, udev->slot_id, ep_index, TRB_STOP_RING);
- event = xhci_wait_for_event(ctrl, TRB_TRANSFER);
- field = le32_to_cpu(event->trans_event.flags);
- BUG_ON(TRB_TO_SLOT_ID(field) != udev->slot_id);
- BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
- BUG_ON(GET_COMP_CODE(le32_to_cpu(event->trans_event.transfer_len
- != COMP_STOP)));
- xhci_acknowledge_event(ctrl);
+ event = xhci_wait_for_event(ctrl, TRB_NONE, XHCI_TIMEOUT_DEFAULT);
+ if (!event)
+ return;
- event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
- BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
- != udev->slot_id || GET_COMP_CODE(le32_to_cpu(
- event->event_cmd.status)) != COMP_SUCCESS);
+ type = TRB_FIELD_TO_TYPE(le32_to_cpu(event->event_cmd.flags));
+ if (type == TRB_TRANSFER) {
+ field = le32_to_cpu(event->trans_event.flags);
+ BUG_ON(TRB_TO_SLOT_ID(field) != udev->slot_id);
+ BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
+ BUG_ON(GET_COMP_CODE(le32_to_cpu(event->trans_event.transfer_len
+ != COMP_STOP)));
+ xhci_acknowledge_event(ctrl);
+
+ event = xhci_wait_for_event(ctrl, TRB_COMPLETION, XHCI_TIMEOUT_DEFAULT);
+ if (!event)
+ return;
+ type = TRB_FIELD_TO_TYPE(le32_to_cpu(event->event_cmd.flags));
+
+ } else {
+ dev_warn(ctrl->dev, "abort_td: Expected a TRB_TRANSFER TRB first\n");
+ }
+
+ comp = GET_COMP_CODE(le32_to_cpu(event->event_cmd.status));
+ BUG_ON(type != TRB_COMPLETION ||
+ TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
+ != udev->slot_id || (comp != COMP_SUCCESS && comp
+ != COMP_CTX_STATE));
xhci_acknowledge_event(ctrl);
- xhci_queue_command(ctrl, (void *)((uintptr_t)ring->enqueue |
- ring->cycle_state), udev->slot_id, ep_index, TRB_SET_DEQ);
- event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+ addr = xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue);
+ addr |= ring->cycle_state;
+ xhci_queue_command(ctrl, addr, udev->slot_id, ep_index, TRB_SET_DEQ);
+ event = xhci_wait_for_event(ctrl, TRB_COMPLETION, XHCI_TIMEOUT_DEFAULT);
+ if (!event)
+ return;
+
BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
!= udev->slot_id || GET_COMP_CODE(le32_to_cpu(
event->event_cmd.status)) != COMP_SUCCESS);
@@ -557,7 +639,7 @@ static void record_transfer_result(struct usb_device *udev,
* @return returns 0 if successful else -1 on failure
*/
int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
- int length, void *buffer)
+ int length, void *buffer, unsigned int timeout_ms)
{
int num_trbs = 0;
struct xhci_generic_trb *start_trb;
@@ -601,7 +683,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
memcpy(bounce, buffer, length);
}
- map = addr = dma_map_single(ctrl->dev, bounce, length, direction);
+ map = addr = dma_map_single(ctrl->host.hw_dev, bounce, length, direction);
dev_dbg(&udev->dev, "pipe=0x%lx, buffer=%p, length=%d\n",
pipe, buffer, length);
@@ -614,6 +696,14 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
ep_ctx = xhci_get_ep_ctx(ctrl, virt_dev->out_ctx, ep_index);
+ /*
+ * If the endpoint was halted due to a prior error, resume it before
+ * the next transfer. It is the responsibility of the upper layer to
+ * have dealt with whatever caused the error.
+ */
+ if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) == EP_STATE_HALTED)
+ reset_ep(udev, ep_index, timeout_ms);
+
ring = virt_dev->eps[ep_index].ring;
/*
* How much data is (potentially) left before the 64KB boundary?
@@ -646,8 +736,10 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
*/
ret = prepare_ring(ctrl, ring,
le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK);
- if (ret < 0)
+ if (ret < 0) {
+ dma_unmap_single(ctrl->host.hw_dev, map, length, direction);
return ret;
+ }
/*
* Don't give the first TRB to the hardware (by toggling the cycle bit)
@@ -667,6 +759,9 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
first_trb = true;
+ /* flush the buffer before use */
+ xhci_flush_cache((uintptr_t)buffer, length);
+
/* Queue the first TRB, even if it's zero-length */
do {
u32 remainder = 0;
@@ -703,15 +798,14 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
maxpacketsize,
num_trbs - 1);
- length_field = ((trb_buff_len & TRB_LEN_MASK) |
+ length_field = (TRB_LEN(trb_buff_len) |
remainder |
- ((0 & TRB_INTR_TARGET_MASK) <<
- TRB_INTR_TARGET_SHIFT));
+ TRB_INTR_TARGET(0));
trb_fields[0] = lower_32_bits(addr);
trb_fields[1] = upper_32_bits(addr);
trb_fields[2] = length_field;
- trb_fields[3] = field | (TRB_NORMAL << TRB_TYPE_SHIFT);
+ trb_fields[3] = field | TRB_TYPE(TRB_NORMAL);
queue_trb(ctrl, ring, (num_trbs > 1), trb_fields);
@@ -726,12 +820,13 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
giveback_first_trb(udev, ep_index, start_cycle, start_trb);
- event = xhci_wait_for_event(ctrl, TRB_TRANSFER);
+ event = xhci_wait_for_event(ctrl, TRB_TRANSFER, timeout_ms);
if (!event) {
dev_dbg(&udev->dev, "XHCI bulk transfer timed out, aborting...\n");
abort_td(udev, ep_index);
udev->status = USB_ST_NAK_REC; /* closest thing to a timeout */
udev->act_len = 0;
+ dma_unmap_single(ctrl->host.hw_dev, map, length, direction);
return -ETIMEDOUT;
}
field = le32_to_cpu(event->trans_event.flags);
@@ -747,7 +842,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
record_transfer_result(udev, event, length);
xhci_acknowledge_event(ctrl);
- dma_unmap_single(ctrl->dev, map, length, direction);
+ dma_unmap_single(ctrl->host.hw_dev, map, length, direction);
if (usb_pipein(pipe))
memcpy(buffer, bounce, length);
@@ -767,7 +862,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
*/
int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
struct devrequest *req, int length,
- void *buffer)
+ void *buffer, unsigned int timeout_ms)
{
int ret;
int start_cycle;
@@ -846,7 +941,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
/* Queue setup TRB - see section 6.4.1.2.1 */
/* FIXME better way to translate setup_packet into two u32 fields? */
field = 0;
- field |= TRB_IDT | (TRB_SETUP << TRB_TYPE_SHIFT);
+ field |= TRB_IDT | TRB_TYPE(TRB_SETUP);
if (start_cycle == 0)
field |= 0x1;
@@ -854,9 +949,9 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
if (HC_VERSION(xhci_readl(&ctrl->hccr->cr_capbase)) >= 0x100) {
if (length > 0) {
if (req->requesttype & USB_DIR_IN)
- field |= (TRB_DATA_IN << TRB_TX_TYPE_SHIFT);
+ field |= TRB_TX_TYPE(TRB_DATA_IN);
else
- field |= (TRB_DATA_OUT << TRB_TX_TYPE_SHIFT);
+ field |= TRB_TX_TYPE(TRB_DATA_OUT);
}
}
@@ -872,8 +967,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
trb_fields[1] = le16_to_cpu(req->index) |
le16_to_cpu(req->length) << 16;
/* TRB_LEN | (TRB_INTR_TARGET) */
- trb_fields[2] = (8 | ((0 & TRB_INTR_TARGET_MASK) <<
- TRB_INTR_TARGET_SHIFT));
+ trb_fields[2] = (TRB_LEN(8) | TRB_INTR_TARGET(0));
/* Immediate data in pointer */
trb_fields[3] = field;
queue_trb(ctrl, ep_ring, true, trb_fields);
@@ -883,15 +977,15 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
/* If there's data, queue data TRBs */
/* Only set interrupt on short packet for IN endpoints */
if (usb_pipein(pipe))
- field = TRB_ISP | (TRB_DATA << TRB_TYPE_SHIFT);
+ field = TRB_ISP | TRB_TYPE(TRB_DATA);
else
- field = (TRB_DATA << TRB_TYPE_SHIFT);
+ field = TRB_TYPE(TRB_DATA);
- length_field = (length & TRB_LEN_MASK) | xhci_td_remainder(length) |
+ length_field = TRB_LEN(length) | xhci_td_remainder(length) |
((0 & TRB_INTR_TARGET_MASK) << TRB_INTR_TARGET_SHIFT);
dev_dbg(&udev->dev, "length_field = %d, length = %d,"
"xhci_td_remainder(length) = %d , TRB_INTR_TARGET(0) = %d\n",
- length_field, (length & TRB_LEN_MASK),
+ length_field, TRB_LEN(length),
xhci_td_remainder(length), 0);
if (req->requesttype & USB_DIR_IN)
@@ -902,13 +996,14 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
if (length > 0) {
if (req->requesttype & USB_DIR_IN)
field |= TRB_DIR_IN;
- map = buf_64 = dma_map_single(ctrl->dev, buffer, length, direction);
+ map = buf_64 = dma_map_single(ctrl->host.hw_dev, buffer, length, direction);
trb_fields[0] = lower_32_bits(buf_64);
trb_fields[1] = upper_32_bits(buf_64);
trb_fields[2] = length_field;
trb_fields[3] = field | ep_ring->cycle_state;
+ xhci_flush_cache((uintptr_t)buffer, length);
queue_trb(ctrl, ep_ring, true, trb_fields);
}
@@ -926,17 +1021,16 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
trb_fields[0] = 0;
trb_fields[1] = 0;
- trb_fields[2] = ((0 & TRB_INTR_TARGET_MASK) << TRB_INTR_TARGET_SHIFT);
+ trb_fields[2] = TRB_INTR_TARGET(0);
/* Event on completion */
trb_fields[3] = field | TRB_IOC |
- (TRB_STATUS << TRB_TYPE_SHIFT) |
- ep_ring->cycle_state;
+ TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state;
queue_trb(ctrl, ep_ring, false, trb_fields);
giveback_first_trb(udev, ep_index, start_cycle, start_trb);
- event = xhci_wait_for_event(ctrl, TRB_TRANSFER);
+ event = xhci_wait_for_event(ctrl, TRB_TRANSFER, timeout_ms);
if (!event)
goto abort;
field = le32_to_cpu(event->trans_event.flags);
@@ -954,12 +1048,17 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
/* Invalidate buffer to make it available to usb-core */
if (length > 0)
- dma_unmap_single(ctrl->dev, map, length, direction);
+ dma_unmap_single(ctrl->host.hw_dev, map, length, direction);
+
+ if (udev->status == USB_ST_STALLED) {
+ reset_ep(udev, ep_index, timeout_ms);
+ return -EPIPE;
+ }
if (GET_COMP_CODE(le32_to_cpu(event->trans_event.transfer_len))
== COMP_SHORT_TX) {
/* Short data stage, clear up additional status stage event */
- event = xhci_wait_for_event(ctrl, TRB_TRANSFER);
+ event = xhci_wait_for_event(ctrl, TRB_TRANSFER, timeout_ms);
if (!event)
goto abort;
BUG_ON(TRB_TO_SLOT_ID(field) != slot_id);
@@ -974,5 +1073,6 @@ abort:
abort_td(udev, ep_index);
udev->status = USB_ST_NAK_REC;
udev->act_len = 0;
+ dma_unmap_single(ctrl->host.hw_dev, map, length, direction);
return -ETIMEDOUT;
}
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index caab2400d8..e7b8344181 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* USB HOST XHCI Controller stack
*
@@ -24,13 +24,13 @@
#include <init.h>
#include <io.h>
#include <linux/err.h>
-#include <usb/usb.h>
-#include <usb/xhci.h>
+#include <linux/usb/usb.h>
+#include <linux/usb/xhci.h>
#include <asm/unaligned.h>
#include "xhci.h"
-static struct descriptor {
+static const struct descriptor {
struct usb_hub_descriptor hub;
struct usb_device_descriptor device;
struct usb_config_descriptor config;
@@ -151,6 +151,8 @@ static int xhci_start(struct xhci_ctrl *ctrl)
u32 temp;
int ret;
+ dev_dbg(ctrl->dev, "Starting the controller\n");
+
temp = xhci_readl(&hcor->or_usbcmd);
temp |= (CMD_RUN);
xhci_writel(&hcor->or_usbcmd, temp);
@@ -441,9 +443,12 @@ static int xhci_configure_endpoints(struct usb_device *udev, bool ctx_change)
in_ctx = virt_dev->in_ctx;
xhci_flush_cache((uintptr_t)in_ctx->bytes, in_ctx->size);
- xhci_queue_command(ctrl, in_ctx->bytes, udev->slot_id, 0,
+ xhci_queue_command(ctrl, in_ctx->dma, udev->slot_id, 0,
ctx_change ? TRB_EVAL_CONTEXT : TRB_CONFIG_EP);
- event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+ event = xhci_wait_for_event(ctrl, TRB_COMPLETION, XHCI_TIMEOUT_DEFAULT);
+ if (!event)
+ return -ETIMEDOUT;
+
BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
!= udev->slot_id);
@@ -566,8 +571,7 @@ static int xhci_set_configuration(struct usb_device *udev)
cpu_to_le32(EP_MAX_ESIT_PAYLOAD_HI(max_esit_payload) |
EP_INTERVAL(interval) | EP_MULT(mult));
- ep_ctx[ep_index]->ep_info2 =
- cpu_to_le32(ep_type << EP_TYPE_SHIFT);
+ ep_ctx[ep_index]->ep_info2 = cpu_to_le32(EP_TYPE(ep_type));
ep_ctx[ep_index]->ep_info2 |=
cpu_to_le32(MAX_PACKET
(get_unaligned(&endpt_desc->wMaxPacketSize)));
@@ -579,8 +583,8 @@ static int xhci_set_configuration(struct usb_device *udev)
cpu_to_le32(MAX_BURST(max_burst) |
ERROR_COUNT(err_count));
- trb_64 = (uintptr_t)
- virt_dev->eps[ep_index].ring->enqueue;
+ trb_64 = xhci_trb_virt_to_dma(virt_dev->eps[ep_index].ring->enq_seg,
+ virt_dev->eps[ep_index].ring->enqueue);
ep_ctx[ep_index]->deq = cpu_to_le64(trb_64 |
virt_dev->eps[ep_index].ring->cycle_state);
@@ -628,8 +632,12 @@ static int xhci_address_device(struct usb_device *udev, int root_portnr)
ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
ctrl_ctx->drop_flags = 0;
- xhci_queue_command(ctrl, (void *)ctrl_ctx, slot_id, 0, TRB_ADDR_DEV);
- event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+ xhci_queue_command(ctrl, virt_dev->in_ctx->dma,
+ slot_id, 0, TRB_ADDR_DEV);
+ event = xhci_wait_for_event(ctrl, TRB_COMPLETION, XHCI_TIMEOUT_DEFAULT);
+ if (!event)
+ return -ETIMEDOUT;
+
BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags)) != slot_id);
switch (GET_COMP_CODE(le32_to_cpu(event->event_cmd.status))) {
@@ -703,8 +711,11 @@ static int _xhci_alloc_device(struct usb_device *udev)
return 0;
}
- xhci_queue_command(ctrl, NULL, 0, 0, TRB_ENABLE_SLOT);
- event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+ xhci_queue_command(ctrl, 0, 0, 0, TRB_ENABLE_SLOT);
+ event = xhci_wait_for_event(ctrl, TRB_COMPLETION, XHCI_TIMEOUT_DEFAULT);
+ if (!event)
+ return -ETIMEDOUT;
+
BUG_ON(GET_COMP_CODE(le32_to_cpu(event->event_cmd.status))
!= COMP_SUCCESS);
@@ -764,8 +775,7 @@ int xhci_check_maxpacket(struct usb_device *udev)
ctrl->devs[slot_id]->out_ctx, ep_index);
in_ctx = ctrl->devs[slot_id]->in_ctx;
ep_ctx = xhci_get_ep_ctx(ctrl, in_ctx, ep_index);
- ep_ctx->ep_info2 &= cpu_to_le32(~((0xffff & MAX_PACKET_MASK)
- << MAX_PACKET_SHIFT));
+ ep_ctx->ep_info2 &= cpu_to_le32(~MAX_PACKET(MAX_PACKET_MASK));
ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet_size));
/*
@@ -860,7 +870,7 @@ static int xhci_submit_root(struct usb_device *udev, unsigned long pipe,
{
uint8_t tmpbuf[4];
u16 typeReq;
- void *srcptr = NULL;
+ const void *srcptr = NULL;
int len, srclen;
uint32_t reg;
volatile uint32_t *status_reg;
@@ -928,7 +938,7 @@ static int xhci_submit_root(struct usb_device *udev, unsigned long pipe,
case USB_DT_HUB:
case USB_DT_SS_HUB:
dev_dbg(&udev->dev, "USB_DT_HUB config\n");
- srcptr = &descriptor.hub;
+ srcptr = &ctrl->hub_desc;
srclen = 0x8;
break;
default:
@@ -1088,8 +1098,10 @@ unknown:
static int _xhci_submit_int_msg(struct usb_device *udev, unsigned long pipe,
void *buffer, int length, int interval)
{
- if (usb_pipetype(pipe) != PIPE_INTERRUPT)
+ if (usb_pipetype(pipe) != PIPE_INTERRUPT) {
+ dev_err(&udev->dev, "non-interrupt pipe (type=%lu)", usb_pipetype(pipe));
return -EINVAL;
+ }
/*
* xHCI uses normal TRBs for both bulk and interrupt. When the
@@ -1097,7 +1109,7 @@ static int _xhci_submit_int_msg(struct usb_device *udev, unsigned long pipe,
* (at most) one TD. A TD (comprised of sg list entries) can
* take several service intervals to transmit.
*/
- return xhci_bulk_tx(udev, pipe, length, buffer);
+ return xhci_bulk_tx(udev, pipe, length, buffer, 0);
}
/**
@@ -1112,10 +1124,12 @@ static int _xhci_submit_int_msg(struct usb_device *udev, unsigned long pipe,
static int _xhci_submit_bulk_msg(struct usb_device *udev, unsigned long pipe,
void *buffer, int length, int timeout_ms)
{
- if (usb_pipetype(pipe) != PIPE_BULK)
+ if (usb_pipetype(pipe) != PIPE_BULK) {
+ dev_err(&udev->dev, "non-bulk pipe (type=%lu)", usb_pipetype(pipe));
return -EINVAL;
+ }
- return xhci_bulk_tx(udev, pipe, length, buffer);
+ return xhci_bulk_tx(udev, pipe, length, buffer, timeout_ms);
}
/**
@@ -1131,13 +1145,16 @@ static int _xhci_submit_bulk_msg(struct usb_device *udev, unsigned long pipe,
*/
static int _xhci_submit_control_msg(struct usb_device *udev, unsigned long pipe,
void *buffer, int length,
- struct devrequest *setup, int root_portnr)
+ struct devrequest *setup, int root_portnr,
+ unsigned int timeout_ms)
{
struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
int ret = 0;
- if (usb_pipetype(pipe) != PIPE_CONTROL)
+ if (usb_pipetype(pipe) != PIPE_CONTROL) {
+ dev_err(&udev->dev, "non-control pipe (type=%lu)", usb_pipetype(pipe));
return -EINVAL;
+ }
if (usb_pipedevice(pipe) == ctrl->rootdev)
return xhci_submit_root(udev, pipe, buffer, setup);
@@ -1155,7 +1172,7 @@ static int _xhci_submit_control_msg(struct usb_device *udev, unsigned long pipe,
}
}
- return xhci_ctrl_tx(udev, pipe, setup, length, buffer);
+ return xhci_ctrl_tx(udev, pipe, setup, length, buffer, timeout_ms);
}
static int xhci_lowlevel_init(struct xhci_ctrl *ctrl)
@@ -1180,21 +1197,23 @@ static int xhci_lowlevel_init(struct xhci_ctrl *ctrl)
/* initializing xhci data structures */
if (xhci_mem_init(ctrl, hccr, hcor) < 0)
return -ENOMEM;
+ ctrl->hub_desc = descriptor.hub;
reg = xhci_readl(&hccr->cr_hcsparams1);
- descriptor.hub.bNbrPorts = ((reg & HCS_MAX_PORTS_MASK) >>
- HCS_MAX_PORTS_SHIFT);
+ ctrl->hub_desc.bNbrPorts = HCS_MAX_PORTS(reg);
+
+ dev_dbg(ctrl->dev, "Register 0x%x NbrPorts %d\n", reg, ctrl->hub_desc.bNbrPorts);
/* Port Indicators */
reg = xhci_readl(&hccr->cr_hccparams);
if (HCS_INDICATOR(reg))
- put_unaligned(get_unaligned(&descriptor.hub.wHubCharacteristics)
- | 0x80, &descriptor.hub.wHubCharacteristics);
+ put_unaligned(get_unaligned(&ctrl->hub_desc.wHubCharacteristics)
+ | 0x80, &ctrl->hub_desc.wHubCharacteristics);
/* Port Power Control */
if (HCC_PPC(reg))
- put_unaligned(get_unaligned(&descriptor.hub.wHubCharacteristics)
- | 0x01, &descriptor.hub.wHubCharacteristics);
+ put_unaligned(get_unaligned(&ctrl->hub_desc.wHubCharacteristics)
+ | 0x01, &ctrl->hub_desc.wHubCharacteristics);
if (xhci_start(ctrl)) {
xhci_reset(ctrl);
@@ -1217,6 +1236,8 @@ static int xhci_lowlevel_stop(struct xhci_ctrl *ctrl)
xhci_reset(ctrl);
+ dev_dbg(ctrl->dev, "Disabling event ring interrupts\n");
+
temp = xhci_readl(&ctrl->hcor->or_usbsts);
xhci_writel(&ctrl->hcor->or_usbsts, temp & ~STS_EINT);
temp = xhci_readl(&ctrl->ir_set->irq_pending);
@@ -1239,7 +1260,7 @@ static int xhci_submit_control_msg(struct usb_device *udev,
}
return _xhci_submit_control_msg(udev, pipe, buffer, length, setup,
- root_portnr);
+ root_portnr, timeout_ms);
}
static int xhci_submit_bulk_msg(struct usb_device *udev,
@@ -1343,7 +1364,7 @@ static __maybe_unused int xhci_get_max_xfer_size(size_t *size)
int xhci_register(struct xhci_ctrl *ctrl)
{
struct usb_host *host;
- struct device_d *dev = ctrl->dev;
+ struct device *dev = ctrl->dev;
int ret;
dev_dbg(dev, "%s: hccr=%p, hcor=%p\n", __func__, ctrl->hccr, ctrl->hcor);
@@ -1358,7 +1379,11 @@ int xhci_register(struct xhci_ctrl *ctrl)
*/
host->no_desc_before_addr = true;
- host->hw_dev = dev;
+ /*
+ * If xHCI doesn't have its own DT node, it'll be a child of a
+ * physical USB host controller device that should be used for DMA
+ */
+ host->hw_dev = dev_of_node(dev) ? dev : dev->parent;
host->submit_int_msg = xhci_submit_int_msg;
host->submit_control_msg = xhci_submit_control_msg;
host->submit_bulk_msg = xhci_submit_bulk_msg;
@@ -1393,7 +1418,7 @@ int xhci_deregister(struct xhci_ctrl *ctrl)
* xHCI platform driver
*/
-static int xhci_probe(struct device_d *dev)
+static int xhci_probe(struct device *dev)
{
struct resource *iores;
struct xhci_ctrl *ctrl;
@@ -1414,14 +1439,14 @@ static int xhci_probe(struct device_d *dev)
return xhci_register(ctrl);
}
-static void xhci_remove(struct device_d *dev)
+static void xhci_remove(struct device *dev)
{
struct xhci_ctrl *ctrl = dev->priv;
xhci_deregister(ctrl);
}
-static struct driver_d xhci_driver = {
+static struct driver xhci_driver = {
.name = "xHCI",
.probe = xhci_probe,
.remove = xhci_remove,
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 9ffbb103d5..37e8cee843 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* USB HOST XHCI Controller
*
@@ -16,7 +16,7 @@
#ifndef HOST_XHCI_H_
#define HOST_XHCI_H_
-#include <asm/types.h>
+#include <linux/types.h>
#include <io.h>
#include <io-64-nonatomic-lo-hi.h>
#include <linux/list.h>
@@ -30,8 +30,8 @@
/* Section 5.3.3 - MaxPorts */
#define MAX_HC_PORTS 255
-/* Up to 16 ms to halt an HC */
-#define XHCI_MAX_HALT_USEC (16*1000)
+/* Up to 32 ms to halt an HC */
+#define XHCI_MAX_HALT_USEC (32*1000)
#define XHCI_MAX_RESET_USEC (250*1000)
@@ -490,6 +490,7 @@ struct xhci_container_ctx {
int size;
u8 *bytes;
+ dma_addr_t dma;
};
/**
@@ -691,6 +692,8 @@ struct xhci_input_control_ctx {
struct xhci_device_context_array {
/* 64-bit device addresses; we only write 32-bit addresses */
__le64 dev_context_ptrs[MAX_HC_SLOTS];
+ /* private xHCD pointers */
+ dma_addr_t dma;
};
/* TODO: write function to set the 64-bit device DMA address */
/*
@@ -903,6 +906,8 @@ union xhci_trb {
/* TRB type IDs */
typedef enum {
+ /* reserved, used as a software sentinel */
+ TRB_NONE = 0,
/* bulk, interrupt, isoc scatter/gather, and control data stage */
TRB_NORMAL = 1,
/* setup stage for control transfers */
@@ -1003,6 +1008,7 @@ struct xhci_segment {
union xhci_trb *trbs;
/* private to HCD */
struct xhci_segment *next;
+ dma_addr_t dma;
};
struct xhci_ring {
@@ -1031,11 +1037,14 @@ struct xhci_erst_entry {
struct xhci_erst {
struct xhci_erst_entry *entries;
unsigned int num_entries;
+ /* xhci->event_ring keeps track of segment dma addresses */
+ dma_addr_t erst_dma_addr;
/* Num entries the ERST can contain */
unsigned int erst_size;
};
struct xhci_scratchpad {
+ void *scratchpad;
u64 *sp_array;
};
@@ -1134,8 +1143,6 @@ void xhci_hcd_stop(int index);
/*************************************************************
EXTENDED CAPABILITY DEFINITIONS
*************************************************************/
-/* Up to 16 ms to halt an HC */
-#define XHCI_MAX_HALT_USEC (16*1000)
/* HC not running - set to 1 when run/stop bit is cleared. */
#define XHCI_STS_HALT (1 << 0)
@@ -1203,7 +1210,7 @@ void xhci_hcd_stop(int index);
struct xhci_ctrl {
struct usb_host host;
- struct device_d *dev;
+ struct device *dev;
struct xhci_hccr *hccr; /* R/O registers, not need for volatile */
struct xhci_hcor *hcor;
struct xhci_doorbell_array *dba;
@@ -1218,6 +1225,7 @@ struct xhci_ctrl {
struct xhci_erst_entry entry[ERST_NUM_SEGS];
struct xhci_scratchpad *scratchpad;
struct xhci_virt_device *devs[MAX_HC_SLOTS];
+ struct usb_hub_descriptor hub_desc;
void *bounce_buffer;
int rootdev;
};
@@ -1227,7 +1235,7 @@ static inline struct xhci_ctrl *to_xhci(struct usb_host *host)
return container_of(host, struct xhci_ctrl, host);
}
-unsigned long trb_addr(struct xhci_segment *seg, union xhci_trb *trb);
+dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb);
struct xhci_input_control_ctx
*xhci_get_input_control_ctx(struct xhci_container_ctx *ctx);
struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_ctrl *ctrl,
@@ -1244,14 +1252,16 @@ void xhci_slot_copy(struct xhci_ctrl *ctrl,
struct xhci_container_ctx *out_ctx);
void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl,
struct usb_device *udev, int hop_portnr);
-void xhci_queue_command(struct xhci_ctrl *ctrl, u8 *ptr,
+void xhci_queue_command(struct xhci_ctrl *ctrl, dma_addr_t addr,
u32 slot_id, u32 ep_index, trb_type cmd);
void xhci_acknowledge_event(struct xhci_ctrl *ctrl);
-union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected);
+#define XHCI_TIMEOUT_DEFAULT 5000
+union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected,
+ unsigned int timeout_ms);
int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
- int length, void *buffer);
+ int length, void *buffer, unsigned int timeout_ms);
int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
- struct devrequest *req, int length, void *buffer);
+ struct devrequest *req, int length, void *buffer, unsigned int timeout_ms);
int xhci_check_maxpacket(struct usb_device *udev);
void xhci_flush_cache(uintptr_t addr, u32 type_len);
void xhci_inval_cache(uintptr_t addr, u32 type_len);