Update Linux to v5.4.2
Change-Id: Idf6911045d9d382da2cfe01b1edff026404ac8fd
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 1a4ea98..79b2e79 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
#
# USB Host Controller Drivers
#
@@ -69,13 +70,13 @@
If unsure, say N.
config USB_XHCI_MVEBU
- tristate "xHCI support for Marvell Armada 375/38x"
+ tristate "xHCI support for Marvell Armada 375/38x/37xx"
select USB_XHCI_PLATFORM
depends on HAS_IOMEM
depends on ARCH_MVEBU || COMPILE_TEST
---help---
Say 'Y' to enable the support for the xHCI host controller
- found in Marvell Armada 375/38x ARM SOCs.
+ found in Marvell Armada 375/38x/37xx ARM SOCs.
config USB_XHCI_RCAR
tristate "xHCI support for Renesas R-Car SoCs"
@@ -113,7 +114,7 @@
Controller Driver or UHCI (for Via motherboards) Host Controller
Driver too.
- You may want to read <file:Documentation/usb/ehci.txt>.
+ You may want to read <file:Documentation/usb/ehci.rst>.
To compile this driver as a module, choose M here: the
module will be called ehci-hcd.
@@ -160,7 +161,6 @@
config USB_EHCI_HCD_PMC_MSP
tristate "EHCI support for on-chip PMC MSP71xx USB controller"
depends on MSP_HAS_USB
- default n
select USB_EHCI_BIG_ENDIAN_DESC
select USB_EHCI_BIG_ENDIAN_MMIO
---help---
@@ -179,8 +179,7 @@
devices only.
config USB_EHCI_FSL
- tristate "Support for Freescale PPC on-chip EHCI USB controller"
- depends on FSL_SOC
+ tristate "Support for Freescale on-chip EHCI USB controller"
select USB_EHCI_ROOT_HUB_TT
---help---
Variation of ARC USB block used in some Freescale chips.
@@ -276,7 +275,7 @@
Enable support for the Samsung Exynos SOC's on-chip EHCI controller.
config USB_EHCI_MV
- bool "EHCI support for Marvell PXA/MMP USB controller"
+ tristate "EHCI support for Marvell PXA/MMP USB controller"
depends on (ARCH_PXA || ARCH_MMP)
select USB_EHCI_ROOT_HUB_TT
---help---
@@ -288,12 +287,6 @@
Dova, Armada 370 and Armada XP. See "Support for Marvell EBU
on-chip EHCI USB controller" for those.
-config USB_W90X900_EHCI
- tristate "W90X900(W90P910) EHCI support"
- depends on ARCH_W90X900
- ---help---
- Enables support for the W90X900 USB controller
-
config USB_CNS3XXX_EHCI
bool "Cavium CNS3XXX EHCI Module (DEPRECATED)"
depends on ARCH_CNS3XXX
@@ -308,7 +301,6 @@
config USB_EHCI_HCD_PLATFORM
tristate "Generic EHCI driver for a platform device"
- default n
---help---
Adds an EHCI host driver for a generic platform device, which
provides a memory space and an irq.
@@ -318,7 +310,6 @@
config USB_OCTEON_EHCI
bool "Octeon on-chip EHCI support (DEPRECATED)"
depends on CAVIUM_OCTEON_SOC
- default n
select USB_EHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
select USB_EHCI_HCD_PLATFORM
help
@@ -444,7 +435,8 @@
config USB_OHCI_HCD_LPC32XX
tristate "Support for LPC on-chip OHCI USB controller"
- depends on USB_OHCI_HCD && ARCH_LPC32XX
+ depends on USB_OHCI_HCD
+ depends on ARCH_LPC32XX || COMPILE_TEST
depends on USB_ISP1301
default y
---help---
@@ -526,7 +518,6 @@
depends on (SSB = y || SSB = USB_OHCI_HCD)
select USB_HCD_SSB
select USB_OHCI_HCD_PLATFORM
- default n
---help---
This option is deprecated now and the driver was removed, use
USB_HCD_SSB and USB_OHCI_HCD_PLATFORM instead.
@@ -569,7 +560,6 @@
config USB_OHCI_HCD_PLATFORM
tristate "Generic OHCI driver for a platform device"
- default n
---help---
Adds an OHCI host driver for a generic platform device, which
provides a memory space and an irq.
@@ -722,32 +712,6 @@
To compile this driver as a module, choose M here: the
module will be called renesas-usbhs.
-config USB_WHCI_HCD
- tristate "Wireless USB Host Controller Interface (WHCI) driver"
- depends on USB_PCI && USB && UWB
- select USB_WUSB
- select UWB_WHCI
- help
- A driver for PCI-based Wireless USB Host Controllers that are
- compliant with the WHCI specification.
-
- To compile this driver a module, choose M here: the module
- will be called "whci-hcd".
-
-config USB_HWA_HCD
- tristate "Host Wire Adapter (HWA) driver"
- depends on USB && UWB
- select USB_WUSB
- select UWB_HWA
- help
- This driver enables you to connect Wireless USB devices to
- your system using a Host Wire Adaptor USB dongle. This is an
- UWB Radio Controller and WUSB Host Controller connected to
- your machine via USB (specified in WUSB1.0).
-
- To compile this driver a module, choose M here: the module
- will be called "hwa-hc".
-
config USB_IMX21_HCD
tristate "i.MX21 HCD support"
depends on ARM && ARCH_MXC
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index e623526..b191361 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -35,8 +35,6 @@
xhci-hcd-y += xhci-debugfs.o
endif
-obj-$(CONFIG_USB_WHCI_HCD) += whci/
-
obj-$(CONFIG_USB_PCI) += pci-quirks.o
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
@@ -51,7 +49,6 @@
obj-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o
obj-$(CONFIG_USB_EHCI_HCD_AT91) += ehci-atmel.o
obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o
-obj-$(CONFIG_USB_W90X900_EHCI) += ehci-w90x900.o
obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o
obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
@@ -82,11 +79,11 @@
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
-obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
obj-$(CONFIG_USB_FSL_USB2) += fsl-mph-dr-of.o
obj-$(CONFIG_USB_EHCI_FSL) += fsl-mph-dr-of.o
obj-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
+obj-$(CONFIG_USB_EHCI_MV) += ehci-mv.o
obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o
obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o
obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 3ba140c..e893467 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -100,9 +100,6 @@
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
- dev_err(&pdev->dev,
- "Found HC with no IRQ. Check %s setup!\n",
- dev_name(&pdev->dev));
retval = -ENODEV;
goto fail_create_hcd;
}
diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c
index 8e3bab1..01debfd 100644
--- a/drivers/usb/host/ehci-exynos.c
+++ b/drivers/usb/host/ehci-exynos.c
@@ -39,7 +39,9 @@
struct exynos_ehci_hcd {
struct clk *clk;
+ struct device_node *of_node;
struct phy *phy[PHY_NUMBER];
+ bool legacy_phy;
};
#define to_exynos_ehci(hcd) (struct exynos_ehci_hcd *)(hcd_to_ehci(hcd)->priv)
@@ -49,10 +51,22 @@
{
struct device_node *child;
struct phy *phy;
- int phy_number;
+ int phy_number, num_phys;
int ret;
/* Get PHYs for the controller */
+ num_phys = of_count_phandle_with_args(dev->of_node, "phys",
+ "#phy-cells");
+ for (phy_number = 0; phy_number < num_phys; phy_number++) {
+ phy = devm_of_phy_get_by_index(dev, dev->of_node, phy_number);
+ if (IS_ERR(phy))
+ return PTR_ERR(phy);
+ exynos_ehci->phy[phy_number] = phy;
+ }
+ if (num_phys > 0)
+ return 0;
+
+ /* Get PHYs using legacy bindings */
for_each_available_child_of_node(dev->of_node, child) {
ret = of_property_read_u32(child, "reg", &phy_number);
if (ret) {
@@ -83,6 +97,7 @@
}
}
+ exynos_ehci->legacy_phy = true;
return 0;
}
@@ -203,6 +218,14 @@
ehci = hcd_to_ehci(hcd);
ehci->caps = hcd->regs;
+ /*
+ * Workaround: reset of_node pointer to avoid conflict between legacy
+ * Exynos EHCI port subnodes and generic USB device bindings
+ */
+ exynos_ehci->of_node = pdev->dev.of_node;
+ if (exynos_ehci->legacy_phy)
+ pdev->dev.of_node = NULL;
+
/* DMA burst Enable */
writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
@@ -219,6 +242,7 @@
fail_add_hcd:
exynos_ehci_phy_disable(&pdev->dev);
+ pdev->dev.of_node = exynos_ehci->of_node;
fail_io:
clk_disable_unprepare(exynos_ehci->clk);
fail_clk:
@@ -231,6 +255,8 @@
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd);
+ pdev->dev.of_node = exynos_ehci->of_node;
+
usb_remove_hcd(hcd);
exynos_ehci_phy_disable(&pdev->dev);
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 0a9fd20..9e9c232 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -23,6 +23,7 @@
#include <linux/platform_device.h>
#include <linux/fsl_devices.h>
#include <linux/of_platform.h>
+#include <linux/io.h>
#include "ehci.h"
#include "ehci-fsl.h"
@@ -50,6 +51,7 @@
struct resource *res;
int irq;
int retval;
+ u32 tmp;
pr_debug("initializing FSL-SOC USB Controller\n");
@@ -114,17 +116,28 @@
}
/* Enable USB controller, 83xx or 8536 */
- if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6)
- clrsetbits_be32(hcd->regs + FSL_SOC_USB_CTRL,
- CONTROL_REGISTER_W1C_MASK, 0x4);
+ if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6) {
+ tmp = ioread32be(hcd->regs + FSL_SOC_USB_CTRL);
+ tmp &= ~CONTROL_REGISTER_W1C_MASK;
+ tmp |= 0x4;
+ iowrite32be(tmp, hcd->regs + FSL_SOC_USB_CTRL);
+ }
+
+ /* Set USB_EN bit to select ULPI phy for USB controller version 2.5 */
+ if (pdata->controller_ver == FSL_USB_VER_2_5 &&
+ pdata->phy_mode == FSL_USB2_PHY_ULPI)
+ iowrite32be(USB_CTRL_USB_EN, hcd->regs + FSL_SOC_USB_CTRL);
/*
* Enable UTMI phy and program PTS field in UTMI mode before asserting
* controller reset for USB Controller version 2.5
*/
if (pdata->has_fsl_erratum_a007792) {
- clrsetbits_be32(hcd->regs + FSL_SOC_USB_CTRL,
- CONTROL_REGISTER_W1C_MASK, CTRL_UTMI_PHY_EN);
+ tmp = ioread32be(hcd->regs + FSL_SOC_USB_CTRL);
+ tmp &= ~CONTROL_REGISTER_W1C_MASK;
+ tmp |= CTRL_UTMI_PHY_EN;
+ iowrite32be(tmp, hcd->regs + FSL_SOC_USB_CTRL);
+
writel(PORT_PTS_UTMI, hcd->regs + FSL_SOC_USB_PORTSC1);
}
@@ -170,11 +183,22 @@
return retval;
}
+static bool usb_phy_clk_valid(struct usb_hcd *hcd)
+{
+ void __iomem *non_ehci = hcd->regs;
+ bool ret = true;
+
+ if (!(ioread32be(non_ehci + FSL_SOC_USB_CTRL) & PHY_CLK_VALID))
+ ret = false;
+
+ return ret;
+}
+
static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
enum fsl_usb2_phy_modes phy_mode,
unsigned int port_offset)
{
- u32 portsc;
+ u32 portsc, tmp;
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
void __iomem *non_ehci = hcd->regs;
struct device *dev = hcd->self.controller;
@@ -192,11 +216,16 @@
case FSL_USB2_PHY_ULPI:
if (pdata->have_sysif_regs && pdata->controller_ver) {
/* controller version 1.6 or above */
- clrbits32(non_ehci + FSL_SOC_USB_CTRL,
- CONTROL_REGISTER_W1C_MASK | UTMI_PHY_EN);
- clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL,
- CONTROL_REGISTER_W1C_MASK,
- ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN);
+ /* turn off UTMI PHY first */
+ tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL);
+ tmp &= ~(CONTROL_REGISTER_W1C_MASK | UTMI_PHY_EN);
+ iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL);
+
+ /* then turn on ULPI and enable USB controller */
+ tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL);
+ tmp &= ~CONTROL_REGISTER_W1C_MASK;
+ tmp |= ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN;
+ iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL);
}
portsc |= PORT_PTS_ULPI;
break;
@@ -207,43 +236,64 @@
portsc |= PORT_PTS_PTW;
/* fall through */
case FSL_USB2_PHY_UTMI:
+ /* Presence of this node "has_fsl_erratum_a006918"
+ * in device-tree is used to stop USB controller
+ * initialization in Linux
+ */
+ if (pdata->has_fsl_erratum_a006918) {
+ dev_warn(dev, "USB PHY clock invalid\n");
+ return -EINVAL;
+ }
+ /* fall through */
case FSL_USB2_PHY_UTMI_DUAL:
+ /* PHY_CLK_VALID bit is de-featured from all controller
+ * versions below 2.4 and is to be checked only for
+ * internal UTMI phy
+ */
+ if (pdata->controller_ver > FSL_USB_VER_2_4 &&
+ pdata->have_sysif_regs && !usb_phy_clk_valid(hcd)) {
+ dev_err(dev, "USB PHY clock invalid\n");
+ return -EINVAL;
+ }
+
if (pdata->have_sysif_regs && pdata->controller_ver) {
/* controller version 1.6 or above */
- clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL,
- CONTROL_REGISTER_W1C_MASK, UTMI_PHY_EN);
+ tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL);
+ tmp &= ~CONTROL_REGISTER_W1C_MASK;
+ tmp |= UTMI_PHY_EN;
+ iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL);
+
mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to
become stable - 10ms*/
}
/* enable UTMI PHY */
- if (pdata->have_sysif_regs)
- clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL,
- CONTROL_REGISTER_W1C_MASK,
- CTRL_UTMI_PHY_EN);
+ if (pdata->have_sysif_regs) {
+ tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL);
+ tmp &= ~CONTROL_REGISTER_W1C_MASK;
+ tmp |= CTRL_UTMI_PHY_EN;
+ iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL);
+ }
portsc |= PORT_PTS_UTMI;
break;
case FSL_USB2_PHY_NONE:
break;
}
- /*
- * check PHY_CLK_VALID to determine phy clock presence before writing
- * to portsc
- */
- if (pdata->check_phy_clk_valid) {
- if (!(ioread32be(non_ehci + FSL_SOC_USB_CTRL) &
- PHY_CLK_VALID)) {
- dev_warn(hcd->self.controller,
- "USB PHY clock invalid\n");
- return -EINVAL;
- }
+ if (pdata->have_sysif_regs &&
+ pdata->controller_ver > FSL_USB_VER_1_6 &&
+ !usb_phy_clk_valid(hcd)) {
+ dev_warn(hcd->self.controller, "USB PHY clock invalid\n");
+ return -EINVAL;
}
ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
- if (phy_mode != FSL_USB2_PHY_ULPI && pdata->have_sysif_regs)
- clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL,
- CONTROL_REGISTER_W1C_MASK, USB_CTRL_USB_EN);
+ if (phy_mode != FSL_USB2_PHY_ULPI && pdata->have_sysif_regs) {
+ tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL);
+ tmp &= ~CONTROL_REGISTER_W1C_MASK;
+ tmp |= USB_CTRL_USB_EN;
+ iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL);
+ }
return 0;
}
@@ -284,14 +334,9 @@
return -EINVAL;
if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
- unsigned int chip, rev, svr;
-
- svr = mfspr(SPRN_SVR);
- chip = svr >> 16;
- rev = (svr >> 4) & 0xf;
/* Deal with USB Erratum #14 on MPC834x Rev 1.0 & 1.1 chips */
- if ((rev == 1) && (chip >= 0x8050) && (chip <= 0x8055))
+ if (pdata->has_fsl_erratum_14 == 1)
ehci->has_fsl_port_bug = 1;
if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h
index cbc4220..9d18c6e 100644
--- a/drivers/usb/host/ehci-fsl.h
+++ b/drivers/usb/host/ehci-fsl.h
@@ -50,4 +50,7 @@
#define UTMI_PHY_EN (1<<9)
#define ULPI_PHY_CLK_SEL (1<<10)
#define PHY_CLK_VALID (1<<17)
+
+/* Retry count for checking UTMI PHY CLK validity */
+#define UTMI_PHY_CLK_VALID_CHK_RETRY 5
#endif /* _EHCI_FSL_H */
diff --git a/drivers/usb/host/ehci-grlib.c b/drivers/usb/host/ehci-grlib.c
index 656b8c0..a2c3b4e 100644
--- a/drivers/usb/host/ehci-grlib.c
+++ b/drivers/usb/host/ehci-grlib.c
@@ -30,7 +30,7 @@
* generic hardware linkage
*/
.irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
+ .flags = HCD_MEMORY | HCD_DMA | HCD_USB2 | HCD_BH,
/*
* basic lifecycle operations
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 8608ac5..cf2b7ae 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -559,7 +559,7 @@
ehci->command = temp;
/* Accept arbitrarily long scatter-gather lists */
- if (!(hcd->driver->flags & HCD_LOCAL_MEM))
+ if (!hcd->localmem_pool)
hcd->self.sg_tablesize = ~0;
/* Prepare for unlinking active QHs */
@@ -730,9 +730,9 @@
/* normal [4.15.1.2] or error [4.15.1.1] completion */
if (likely ((status & (STS_INT|STS_ERR)) != 0)) {
if (likely ((status & STS_ERR) == 0))
- COUNT (ehci->stats.normal);
+ INCR(ehci->stats.normal);
else
- COUNT (ehci->stats.error);
+ INCR(ehci->stats.error);
bh = 1;
}
@@ -756,7 +756,7 @@
if (cmd & CMD_IAAD)
ehci_dbg(ehci, "IAA with IAAD still set?\n");
if (ehci->iaa_in_progress)
- COUNT(ehci->stats.iaa);
+ INCR(ehci->stats.iaa);
end_iaa_cycle(ehci);
}
@@ -1193,7 +1193,7 @@
* generic hardware linkage
*/
.irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
+ .flags = HCD_MEMORY | HCD_DMA | HCD_USB2 | HCD_BH,
/*
* basic lifecycle operations
@@ -1286,11 +1286,6 @@
#define PLATFORM_DRIVER ehci_grlib_driver
#endif
-#ifdef CONFIG_USB_EHCI_MV
-#include "ehci-mv.c"
-#define PLATFORM_DRIVER ehci_mv_driver
-#endif
-
static int __init ehci_hcd_init(void)
{
int retval = 0;
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c
index de76445..66ec1fd 100644
--- a/drivers/usb/host/ehci-mv.c
+++ b/drivers/usb/host/ehci-mv.c
@@ -12,24 +12,33 @@
#include <linux/err.h>
#include <linux/usb/otg.h>
#include <linux/platform_data/mv_usb.h>
+#include <linux/io.h>
+
+#include <linux/usb/hcd.h>
+
+#include "ehci.h"
+
+/* registers */
+#define U2x_CAPREGS_OFFSET 0x100
#define CAPLENGTH_MASK (0xff)
-struct ehci_hcd_mv {
- struct usb_hcd *hcd;
+#define hcd_to_ehci_hcd_mv(h) ((struct ehci_hcd_mv *)hcd_to_ehci(h)->priv)
+struct ehci_hcd_mv {
/* Which mode does this ehci running OTG/Host ? */
int mode;
- void __iomem *phy_regs;
+ void __iomem *base;
void __iomem *cap_regs;
void __iomem *op_regs;
struct usb_phy *otg;
-
- struct mv_usb_platform_data *pdata;
-
struct clk *clk;
+
+ struct phy *phy;
+
+ int (*set_vbus)(unsigned int vbus);
};
static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv)
@@ -44,29 +53,20 @@
static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv)
{
- int retval;
-
ehci_clock_enable(ehci_mv);
- if (ehci_mv->pdata->phy_init) {
- retval = ehci_mv->pdata->phy_init(ehci_mv->phy_regs);
- if (retval)
- return retval;
- }
-
- return 0;
+ return phy_init(ehci_mv->phy);
}
static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv)
{
- if (ehci_mv->pdata->phy_deinit)
- ehci_mv->pdata->phy_deinit(ehci_mv->phy_regs);
+ phy_exit(ehci_mv->phy);
ehci_clock_disable(ehci_mv);
}
static int mv_ehci_reset(struct usb_hcd *hcd)
{
struct device *dev = hcd->self.controller;
- struct ehci_hcd_mv *ehci_mv = dev_get_drvdata(dev);
+ struct ehci_hcd_mv *ehci_mv = hcd_to_ehci_hcd_mv(hcd);
int retval;
if (ehci_mv == NULL) {
@@ -83,46 +83,11 @@
return retval;
}
-static const struct hc_driver mv_ehci_hc_driver = {
- .description = hcd_name,
- .product_desc = "Marvell EHCI",
- .hcd_priv_size = sizeof(struct ehci_hcd),
+static struct hc_driver __read_mostly ehci_platform_hc_driver;
- /*
- * generic hardware linkage
- */
- .irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
-
- /*
- * basic lifecycle operations
- */
- .reset = mv_ehci_reset,
- .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,
- .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
-
- /*
- * scheduling support
- */
- .get_frame_number = ehci_get_frame,
-
- /*
- * root hub support
- */
- .hub_status_data = ehci_hub_status_data,
- .hub_control = ehci_hub_control,
- .bus_suspend = ehci_bus_suspend,
- .bus_resume = ehci_bus_resume,
+static const struct ehci_driver_overrides platform_overrides __initconst = {
+ .reset = mv_ehci_reset,
+ .extra_priv_size = sizeof(struct ehci_hcd_mv),
};
static int mv_ehci_probe(struct platform_device *pdev)
@@ -135,27 +100,29 @@
int retval = -ENODEV;
u32 offset;
- if (!pdata) {
- dev_err(&pdev->dev, "missing platform_data\n");
- return -ENODEV;
- }
-
if (usb_disabled())
return -ENODEV;
- hcd = usb_create_hcd(&mv_ehci_hc_driver, &pdev->dev, "mv ehci");
+ hcd = usb_create_hcd(&ehci_platform_hc_driver, &pdev->dev, "mv ehci");
if (!hcd)
return -ENOMEM;
- ehci_mv = devm_kzalloc(&pdev->dev, sizeof(*ehci_mv), GFP_KERNEL);
- if (ehci_mv == NULL) {
- retval = -ENOMEM;
- goto err_put_hcd;
+ platform_set_drvdata(pdev, hcd);
+ ehci_mv = hcd_to_ehci_hcd_mv(hcd);
+
+ ehci_mv->mode = MV_USB_MODE_HOST;
+ if (pdata) {
+ ehci_mv->mode = pdata->mode;
+ ehci_mv->set_vbus = pdata->set_vbus;
}
- platform_set_drvdata(pdev, ehci_mv);
- ehci_mv->pdata = pdata;
- ehci_mv->hcd = hcd;
+ ehci_mv->phy = devm_phy_get(&pdev->dev, "usb");
+ if (IS_ERR(ehci_mv->phy)) {
+ retval = PTR_ERR(ehci_mv->phy);
+ if (retval != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get phy.\n");
+ goto err_put_hcd;
+ }
ehci_mv->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(ehci_mv->clk)) {
@@ -164,17 +131,12 @@
goto err_put_hcd;
}
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs");
- ehci_mv->phy_regs = devm_ioremap_resource(&pdev->dev, r);
- if (IS_ERR(ehci_mv->phy_regs)) {
- retval = PTR_ERR(ehci_mv->phy_regs);
- goto err_put_hcd;
- }
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs");
- ehci_mv->cap_regs = devm_ioremap_resource(&pdev->dev, r);
- if (IS_ERR(ehci_mv->cap_regs)) {
- retval = PTR_ERR(ehci_mv->cap_regs);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ehci_mv->base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(ehci_mv->base)) {
+ retval = PTR_ERR(ehci_mv->base);
goto err_put_hcd;
}
@@ -184,6 +146,8 @@
goto err_put_hcd;
}
+ ehci_mv->cap_regs =
+ (void __iomem *) ((unsigned long) ehci_mv->base + U2x_CAPREGS_OFFSET);
offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK;
ehci_mv->op_regs =
(void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset);
@@ -202,7 +166,6 @@
ehci = hcd_to_ehci(hcd);
ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs;
- ehci_mv->mode = pdata->mode;
if (ehci_mv->mode == MV_USB_MODE_OTG) {
ehci_mv->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
if (IS_ERR(ehci_mv->otg)) {
@@ -227,8 +190,8 @@
/* otg will enable clock before use as host */
mv_ehci_disable(ehci_mv);
} else {
- if (pdata->set_vbus)
- pdata->set_vbus(1);
+ if (ehci_mv->set_vbus)
+ ehci_mv->set_vbus(1);
retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
if (retval) {
@@ -239,9 +202,6 @@
device_wakeup_enable(hcd->self.controller);
}
- if (pdata->private_init)
- pdata->private_init(ehci_mv->op_regs, ehci_mv->phy_regs);
-
dev_info(&pdev->dev,
"successful find EHCI device with regs 0x%p irq %d"
" working in %s mode\n", hcd->regs, hcd->irq,
@@ -250,8 +210,8 @@
return 0;
err_set_vbus:
- if (pdata->set_vbus)
- pdata->set_vbus(0);
+ if (ehci_mv->set_vbus)
+ ehci_mv->set_vbus(0);
err_disable_clk:
mv_ehci_disable(ehci_mv);
err_put_hcd:
@@ -262,8 +222,8 @@
static int mv_ehci_remove(struct platform_device *pdev)
{
- struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev);
- struct usb_hcd *hcd = ehci_mv->hcd;
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct ehci_hcd_mv *ehci_mv = hcd_to_ehci_hcd_mv(hcd);
if (hcd->rh_registered)
usb_remove_hcd(hcd);
@@ -272,8 +232,8 @@
otg_set_host(ehci_mv->otg->otg, NULL);
if (ehci_mv->mode == MV_USB_MODE_HOST) {
- if (ehci_mv->pdata->set_vbus)
- ehci_mv->pdata->set_vbus(0);
+ if (ehci_mv->set_vbus)
+ ehci_mv->set_vbus(0);
mv_ehci_disable(ehci_mv);
}
@@ -295,8 +255,7 @@
static void mv_ehci_shutdown(struct platform_device *pdev)
{
- struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev);
- struct usb_hcd *hcd = ehci_mv->hcd;
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
if (!hcd->rh_registered)
return;
@@ -305,13 +264,42 @@
hcd->driver->shutdown(hcd);
}
+static const struct of_device_id ehci_mv_dt_ids[] = {
+ { .compatible = "marvell,pxau2o-ehci", },
+ {},
+};
+
static struct platform_driver ehci_mv_driver = {
.probe = mv_ehci_probe,
.remove = mv_ehci_remove,
.shutdown = mv_ehci_shutdown,
.driver = {
- .name = "mv-ehci",
- .bus = &platform_bus_type,
- },
+ .name = "mv-ehci",
+ .bus = &platform_bus_type,
+ .of_match_table = ehci_mv_dt_ids,
+ },
.id_table = ehci_id_table,
};
+
+static int __init ehci_platform_init(void)
+{
+ if (usb_disabled())
+ return -ENODEV;
+
+ ehci_init_driver(&ehci_platform_hc_driver, &platform_overrides);
+ return platform_driver_register(&ehci_mv_driver);
+}
+module_init(ehci_platform_init);
+
+static void __exit ehci_platform_cleanup(void)
+{
+ platform_driver_unregister(&ehci_mv_driver);
+}
+module_exit(ehci_platform_cleanup);
+
+MODULE_DESCRIPTION("Marvell EHCI driver");
+MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>");
+MODULE_AUTHOR("Neil Zhang <zhangwm@marvell.com>");
+MODULE_ALIAS("mv-ehci");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, ehci_mv_dt_ids);
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 7e4c133..fc125b3 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -115,10 +115,8 @@
}
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(dev, "EHCI irq failed: %d\n", irq);
+ if (irq < 0)
return irq;
- }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(dev, res);
@@ -159,11 +157,12 @@
/* get the PHY device */
phy = devm_usb_get_phy_by_phandle(dev, "phys", i);
if (IS_ERR(phy)) {
- /* Don't bail out if PHY is not absolutely necessary */
- if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY)
- continue;
-
ret = PTR_ERR(phy);
+ if (ret == -ENODEV) { /* no PHY */
+ phy = NULL;
+ continue;
+ }
+
if (ret != -EPROBE_DEFER)
dev_err(dev, "Can't get PHY for port %d: %d\n",
i, ret);
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
index 1ad7264..a319b1d 100644
--- a/drivers/usb/host/ehci-orion.c
+++ b/drivers/usb/host/ehci-orion.c
@@ -182,6 +182,23 @@
return ret;
}
+static int __maybe_unused ehci_orion_drv_suspend(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+ return ehci_suspend(hcd, device_may_wakeup(dev));
+}
+
+static int __maybe_unused ehci_orion_drv_resume(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+ return ehci_resume(hcd, false);
+}
+
+static SIMPLE_DEV_PM_OPS(ehci_orion_pm_ops, ehci_orion_drv_suspend,
+ ehci_orion_drv_resume);
+
static const struct ehci_driver_overrides orion_overrides __initconst = {
.extra_priv_size = sizeof(struct orion_ehci_hcd),
.reset = ehci_orion_drv_reset,
@@ -206,9 +223,6 @@
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
- dev_err(&pdev->dev,
- "Found HC with no IRQ. Check %s setup!\n",
- dev_name(&pdev->dev));
err = -ENODEV;
goto err;
}
@@ -257,15 +271,7 @@
if (IS_ERR(priv->phy)) {
err = PTR_ERR(priv->phy);
if (err != -ENOSYS)
- goto err_phy_get;
- } else {
- err = phy_init(priv->phy);
- if (err)
- goto err_phy_init;
-
- err = phy_power_on(priv->phy);
- if (err)
- goto err_phy_power_on;
+ goto err_dis_clk;
}
/*
@@ -297,19 +303,12 @@
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err)
- goto err_add_hcd;
+ goto err_dis_clk;
device_wakeup_enable(hcd->self.controller);
return 0;
-err_add_hcd:
- if (!IS_ERR(priv->phy))
- phy_power_off(priv->phy);
-err_phy_power_on:
- if (!IS_ERR(priv->phy))
- phy_exit(priv->phy);
-err_phy_init:
-err_phy_get:
+err_dis_clk:
if (!IS_ERR(priv->clk))
clk_disable_unprepare(priv->clk);
usb_put_hcd(hcd);
@@ -327,11 +326,6 @@
usb_remove_hcd(hcd);
- if (!IS_ERR(priv->phy)) {
- phy_power_off(priv->phy);
- phy_exit(priv->phy);
- }
-
if (!IS_ERR(priv->clk))
clk_disable_unprepare(priv->clk);
@@ -354,6 +348,7 @@
.driver = {
.name = "orion-ehci",
.of_match_table = ehci_orion_dt_ids,
+ .pm = &ehci_orion_pm_ops,
},
};
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index fe9422d..b0882c1 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -149,7 +149,7 @@
break;
case PCI_VENDOR_ID_AMD:
/* AMD PLL quirk */
- if (usb_amd_find_chipset_info())
+ if (usb_amd_quirk_pll_check())
ehci->amd_pll_fix = 1;
/* AMD8111 EHCI doesn't work, according to AMD errata */
if (pdev->device == 0x7463) {
@@ -186,7 +186,7 @@
break;
case PCI_VENDOR_ID_ATI:
/* AMD PLL quirk */
- if (usb_amd_find_chipset_info())
+ if (usb_amd_quirk_pll_check())
ehci->amd_pll_fix = 1;
/*
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index 4c306fb..769749c 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -145,10 +145,8 @@
}
irq = platform_get_irq(dev, 0);
- if (irq < 0) {
- dev_err(&dev->dev, "no irq provided");
+ if (irq < 0)
return irq;
- }
hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
dev_name(&dev->dev));
diff --git a/drivers/usb/host/ehci-pmcmsp.c b/drivers/usb/host/ehci-pmcmsp.c
index 46e1603..a2b610d 100644
--- a/drivers/usb/host/ehci-pmcmsp.c
+++ b/drivers/usb/host/ehci-pmcmsp.c
@@ -250,7 +250,7 @@
* generic hardware linkage
*/
.irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
+ .flags = HCD_MEMORY | HCD_DMA | HCD_USB2 | HCD_BH,
/*
* basic lifecycle operations
diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
index 576f7d7..6bbaee7 100644
--- a/drivers/usb/host/ehci-ppc-of.c
+++ b/drivers/usb/host/ehci-ppc-of.c
@@ -31,7 +31,7 @@
* generic hardware linkage
*/
.irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
+ .flags = HCD_MEMORY | HCD_DMA | HCD_USB2 | HCD_BH,
/*
* basic lifecycle operations
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index 454d8c6..fb52133 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -59,7 +59,7 @@
.product_desc = "PS3 EHCI Host Controller",
.hcd_priv_size = sizeof(struct ehci_hcd),
.irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
+ .flags = HCD_MEMORY | HCD_DMA | HCD_USB2 | HCD_BH,
.reset = ps3_ehci_hc_reset,
.start = ehci_run,
.stop = ehci_stop,
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 3276304..aa2f77f 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -245,12 +245,12 @@
}
if (unlikely(urb->unlinked)) {
- COUNT(ehci->stats.unlink);
+ INCR(ehci->stats.unlink);
} else {
/* report non-error and short read status as zero */
if (status == -EINPROGRESS || status == -EREMOTEIO)
status = 0;
- COUNT(ehci->stats.complete);
+ INCR(ehci->stats.complete);
}
#ifdef EHCI_URB_TRACE
diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c
index a9ee767..2afde14 100644
--- a/drivers/usb/host/ehci-sh.c
+++ b/drivers/usb/host/ehci-sh.c
@@ -33,7 +33,7 @@
* generic hardware linkage
*/
.irq = ehci_irq,
- .flags = HCD_USB2 | HCD_MEMORY | HCD_BH,
+ .flags = HCD_USB2 | HCD_DMA | HCD_MEMORY | HCD_BH,
/*
* basic lifecycle operations
@@ -85,9 +85,6 @@
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
- dev_err(&pdev->dev,
- "Found HC with no IRQ. Check %s setup!\n",
- dev_name(&pdev->dev));
ret = -ENODEV;
goto fail_create_hcd;
}
diff --git a/drivers/usb/host/ehci-st.c b/drivers/usb/host/ehci-st.c
index dc42981..f74433a 100644
--- a/drivers/usb/host/ehci-st.c
+++ b/drivers/usb/host/ehci-st.c
@@ -152,17 +152,14 @@
struct resource *res_mem;
struct usb_ehci_pdata *pdata = &ehci_platform_defaults;
struct st_ehci_platform_priv *priv;
- struct ehci_hcd *ehci;
int err, irq, clk = 0;
if (usb_disabled())
return -ENODEV;
irq = platform_get_irq(dev, 0);
- if (irq < 0) {
- dev_err(&dev->dev, "no irq provided");
+ if (irq < 0)
return irq;
- }
res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!res_mem) {
dev_err(&dev->dev, "no memory resource provided");
@@ -177,7 +174,6 @@
platform_set_drvdata(dev, hcd);
dev->dev.platform_data = pdata;
priv = hcd_to_ehci_priv(hcd);
- ehci = hcd_to_ehci(hcd);
priv->phy = devm_phy_get(&dev->dev, "usb");
if (IS_ERR(priv->phy)) {
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c
index 4fcebda..a79c8ac 100644
--- a/drivers/usb/host/ehci-timer.c
+++ b/drivers/usb/host/ehci-timer.c
@@ -347,7 +347,7 @@
*/
status = ehci_readl(ehci, &ehci->regs->status);
if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
- COUNT(ehci->stats.lost_iaa);
+ INCR(ehci->stats.lost_iaa);
ehci_writel(ehci, STS_IAA, &ehci->regs->status);
}
diff --git a/drivers/usb/host/ehci-w90x900.c b/drivers/usb/host/ehci-w90x900.c
deleted file mode 100644
index 6d77ace..0000000
--- a/drivers/usb/host/ehci-w90x900.c
+++ /dev/null
@@ -1,130 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * linux/driver/usb/host/ehci-w90x900.c
- *
- * Copyright (c) 2008 Nuvoton technology corporation.
- *
- * Wan ZongShun <mcuos.com@gmail.com>
- */
-
-#include <linux/dma-mapping.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/usb.h>
-#include <linux/usb/hcd.h>
-
-#include "ehci.h"
-
-/* enable phy0 and phy1 for w90p910 */
-#define ENPHY (0x01<<8)
-#define PHY0_CTR (0xA4)
-#define PHY1_CTR (0xA8)
-
-#define DRIVER_DESC "EHCI w90x900 driver"
-
-static const char hcd_name[] = "ehci-w90x900 ";
-
-static struct hc_driver __read_mostly ehci_w90x900_hc_driver;
-
-static int ehci_w90x900_probe(struct platform_device *pdev)
-{
- struct usb_hcd *hcd;
- struct ehci_hcd *ehci;
- struct resource *res;
- int retval = 0, irq;
- unsigned long val;
-
- hcd = usb_create_hcd(&ehci_w90x900_hc_driver,
- &pdev->dev, "w90x900 EHCI");
- if (!hcd) {
- retval = -ENOMEM;
- goto err1;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hcd->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(hcd->regs)) {
- retval = PTR_ERR(hcd->regs);
- goto err2;
- }
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
-
- ehci = hcd_to_ehci(hcd);
- ehci->caps = hcd->regs;
- ehci->regs = hcd->regs +
- 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
- * w90p910 IC relative to ehci->regs.
- */
- val = __raw_readl(ehci->regs+PHY0_CTR);
- val |= ENPHY;
- __raw_writel(val, ehci->regs+PHY0_CTR);
-
- val = __raw_readl(ehci->regs+PHY1_CTR);
- val |= ENPHY;
- __raw_writel(val, ehci->regs+PHY1_CTR);
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- retval = irq;
- goto err2;
- }
-
- retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
- if (retval != 0)
- goto err2;
-
- device_wakeup_enable(hcd->self.controller);
- return retval;
-err2:
- usb_put_hcd(hcd);
-err1:
- return retval;
-}
-
-static int ehci_w90x900_remove(struct platform_device *pdev)
-{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
- usb_remove_hcd(hcd);
- usb_put_hcd(hcd);
-
- return 0;
-}
-
-static struct platform_driver ehci_hcd_w90x900_driver = {
- .probe = ehci_w90x900_probe,
- .remove = ehci_w90x900_remove,
- .driver = {
- .name = "w90x900-ehci",
- },
-};
-
-static int __init ehci_w90X900_init(void)
-{
- if (usb_disabled())
- return -ENODEV;
-
- pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-
- ehci_init_driver(&ehci_w90x900_hc_driver, NULL);
- return platform_driver_register(&ehci_hcd_w90x900_driver);
-}
-module_init(ehci_w90X900_init);
-
-static void __exit ehci_w90X900_cleanup(void)
-{
- platform_driver_unregister(&ehci_hcd_w90x900_driver);
-}
-module_exit(ehci_w90X900_cleanup);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
-MODULE_ALIAS("platform:w90p910-ehci");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c
index d2a2757..67a6ee8 100644
--- a/drivers/usb/host/ehci-xilinx-of.c
+++ b/drivers/usb/host/ehci-xilinx-of.c
@@ -66,7 +66,7 @@
* generic hardware linkage
*/
.irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
+ .flags = HCD_MEMORY | HCD_DMA | HCD_USB2 | HCD_BH,
/*
* basic lifecycle operations
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index c8e9a48..ac5e967 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -235,9 +235,9 @@
/* irq statistics */
#ifdef EHCI_STATS
struct ehci_stats stats;
-# define COUNT(x) ((x)++)
+# define INCR(x) ((x)++)
#else
-# define COUNT(x)
+# define INCR(x) do {} while (0)
#endif
/* debug files */
diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c
index 48fe9e6..0473387 100644
--- a/drivers/usb/host/fhci-hcd.c
+++ b/drivers/usb/host/fhci-hcd.c
@@ -538,7 +538,7 @@
/* generic hardware linkage */
.irq = fhci_irq,
- .flags = HCD_USB11 | HCD_MEMORY,
+ .flags = HCD_DMA | HCD_USB11 | HCD_MEMORY,
/* basic lifecycle operation */
.start = fhci_start,
diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c
index 3d12cdd..3235d53 100644
--- a/drivers/usb/host/fhci-sched.c
+++ b/drivers/usb/host/fhci-sched.c
@@ -727,8 +727,7 @@
}
ed->speed = (urb->dev->speed == USB_SPEED_LOW) ?
FHCI_LOW_SPEED : FHCI_FULL_SPEED;
- ed->max_pkt_size = usb_maxpacket(urb->dev,
- urb->pipe, usb_pipeout(urb->pipe));
+ ed->max_pkt_size = usb_endpoint_maxp(&urb->ep->desc);
urb->ep->hcpriv = ed;
fhci_dbg(fhci, "new ep speed=%d max_pkt_size=%d\n",
ed->speed, ed->max_pkt_size);
@@ -768,8 +767,7 @@
if (urb->transfer_flags & URB_ZERO_PACKET &&
urb->transfer_buffer_length > 0 &&
((urb->transfer_buffer_length %
- usb_maxpacket(urb->dev, urb->pipe,
- usb_pipeout(urb->pipe))) == 0))
+ usb_endpoint_maxp(&urb->ep->desc)) == 0))
urb_state = US_BULK0;
while (data_len > 4096) {
td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt,
@@ -807,8 +805,8 @@
break;
case FHCI_TF_CTRL:
ed->dev_addr = usb_pipedevice(urb->pipe);
- ed->max_pkt_size = usb_maxpacket(urb->dev, urb->pipe,
- usb_pipeout(urb->pipe));
+ ed->max_pkt_size = usb_endpoint_maxp(&urb->ep->desc);
+
/* setup stage */
td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, FHCI_TA_SETUP,
USB_TD_TOGGLE_DATA0, urb->setup_packet, 8, 0, 0, true);
diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c
index e64eb47..9e0c98d 100644
--- a/drivers/usb/host/fotg210-hcd.c
+++ b/drivers/usb/host/fotg210-hcd.c
@@ -10,6 +10,7 @@
* Most of code borrowed from the Linux-3.7 EHCI driver
*/
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/device.h>
#include <linux/dmapool.h>
#include <linux/kernel.h>
@@ -31,6 +32,7 @@
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/clk.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
@@ -1285,7 +1287,7 @@
*/
status = fotg210_readl(fotg210, &fotg210->regs->status);
if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
- COUNT(fotg210->stats.lost_iaa);
+ INCR(fotg210->stats.lost_iaa);
fotg210_writel(fotg210, STS_IAA,
&fotg210->regs->status);
}
@@ -1627,6 +1629,10 @@
/* see what we found out */
temp = check_reset_complete(fotg210, wIndex, status_reg,
fotg210_readl(fotg210, status_reg));
+
+ /* restart schedule */
+ fotg210->command |= CMD_RUN;
+ fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
}
if (!(temp & (PORT_RESUME|PORT_RESET))) {
@@ -2204,12 +2210,12 @@
}
if (unlikely(urb->unlinked)) {
- COUNT(fotg210->stats.unlink);
+ INCR(fotg210->stats.unlink);
} else {
/* report non-error and short read status as zero */
if (status == -EINPROGRESS || status == -EREMOTEIO)
status = 0;
- COUNT(fotg210->stats.complete);
+ INCR(fotg210->stats.complete);
}
#ifdef FOTG210_URB_TRACE
@@ -4994,7 +5000,7 @@
fotg210->command = temp;
/* Accept arbitrarily long scatter-gather lists */
- if (!(hcd->driver->flags & HCD_LOCAL_MEM))
+ if (!hcd->localmem_pool)
hcd->self.sg_tablesize = ~0;
return 0;
}
@@ -5153,9 +5159,9 @@
/* normal [4.15.1.2] or error [4.15.1.1] completion */
if (likely((status & (STS_INT|STS_ERR)) != 0)) {
if (likely((status & STS_ERR) == 0))
- COUNT(fotg210->stats.normal);
+ INCR(fotg210->stats.normal);
else
- COUNT(fotg210->stats.error);
+ INCR(fotg210->stats.error);
bh = 1;
}
@@ -5180,7 +5186,7 @@
if (cmd & CMD_IAAD)
fotg210_dbg(fotg210, "IAA with IAAD still set?\n");
if (fotg210->async_iaa) {
- COUNT(fotg210->stats.iaa);
+ INCR(fotg210->stats.iaa);
end_unlink_async(fotg210);
} else
fotg210_dbg(fotg210, "IAA with nothing unlinked?\n");
@@ -5502,7 +5508,7 @@
* generic hardware linkage
*/
.irq = fotg210_irq,
- .flags = HCD_MEMORY | HCD_USB2,
+ .flags = HCD_MEMORY | HCD_DMA | HCD_USB2,
/*
* basic lifecycle operations
@@ -5596,7 +5602,7 @@
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
retval = PTR_ERR(hcd->regs);
- goto failed;
+ goto failed_put_hcd;
}
hcd->rsrc_start = res->start;
@@ -5606,22 +5612,43 @@
fotg210->caps = hcd->regs;
+ /* It's OK not to supply this clock */
+ fotg210->pclk = clk_get(dev, "PCLK");
+ if (!IS_ERR(fotg210->pclk)) {
+ retval = clk_prepare_enable(fotg210->pclk);
+ if (retval) {
+ dev_err(dev, "failed to enable PCLK\n");
+ goto failed_put_hcd;
+ }
+ } else if (PTR_ERR(fotg210->pclk) == -EPROBE_DEFER) {
+ /*
+ * Percolate deferrals, for anything else,
+ * just live without the clocking.
+ */
+ retval = PTR_ERR(fotg210->pclk);
+ goto failed_dis_clk;
+ }
+
retval = fotg210_setup(hcd);
if (retval)
- goto failed;
+ goto failed_dis_clk;
fotg210_init(fotg210);
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval) {
dev_err(dev, "failed to add hcd with err %d\n", retval);
- goto failed;
+ goto failed_dis_clk;
}
device_wakeup_enable(hcd->self.controller);
+ platform_set_drvdata(pdev, hcd);
return retval;
-failed:
+failed_dis_clk:
+ if (!IS_ERR(fotg210->pclk))
+ clk_disable_unprepare(fotg210->pclk);
+failed_put_hcd:
usb_put_hcd(hcd);
fail_create_hcd:
dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval);
@@ -5635,11 +5662,11 @@
*/
static int fotg210_hcd_remove(struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
- struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- if (!hcd)
- return 0;
+ if (!IS_ERR(fotg210->pclk))
+ clk_disable_unprepare(fotg210->pclk);
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
@@ -5647,9 +5674,18 @@
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id fotg210_of_match[] = {
+ { .compatible = "faraday,fotg210" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, fotg210_of_match);
+#endif
+
static struct platform_driver fotg210_hcd_driver = {
.driver = {
.name = "fotg210-hcd",
+ .of_match_table = of_match_ptr(fotg210_of_match),
},
.probe = fotg210_hcd_probe,
.remove = fotg210_hcd_remove,
diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h
index 7fcd785..1b4db95 100644
--- a/drivers/usb/host/fotg210.h
+++ b/drivers/usb/host/fotg210.h
@@ -177,11 +177,14 @@
/* irq statistics */
#ifdef FOTG210_STATS
struct fotg210_stats stats;
-# define COUNT(x) ((x)++)
+# define INCR(x) ((x)++)
#else
-# define COUNT(x)
+# define INCR(x) do {} while (0)
#endif
+ /* silicon clock */
+ struct clk *pclk;
+
/* debug files */
struct dentry *debug_dir;
};
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index 677f9d5..ae8f60f 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -224,6 +224,10 @@
of_property_read_bool(np, "fsl,usb-erratum-a005275");
pdata->has_fsl_erratum_a005697 =
of_property_read_bool(np, "fsl,usb_erratum-a005697");
+ pdata->has_fsl_erratum_a006918 =
+ of_property_read_bool(np, "fsl,usb_erratum-a006918");
+ pdata->has_fsl_erratum_14 =
+ of_property_read_bool(np, "fsl,usb_erratum-14");
/*
* Determine whether phy_clk_valid needs to be checked
diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c
deleted file mode 100644
index 09a8ebd..0000000
--- a/drivers/usb/host/hwa-hc.c
+++ /dev/null
@@ -1,875 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Host Wire Adapter:
- * Driver glue, HWA-specific functions, bridges to WAHC and WUSBHC
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * The HWA driver is a simple layer that forwards requests to the WAHC
- * (Wire Adater Host Controller) or WUSBHC (Wireless USB Host
- * Controller) layers.
- *
- * Host Wire Adapter is the 'WUSB 1.0 standard' name for Wireless-USB
- * Host Controller that is connected to your system via USB (a USB
- * dongle that implements a USB host...). There is also a Device Wired
- * Adaptor, DWA (Wireless USB hub) that uses the same mechanism for
- * transferring data (it is after all a USB host connected via
- * Wireless USB), we have a common layer called Wire Adapter Host
- * Controller that does all the hard work. The WUSBHC (Wireless USB
- * Host Controller) is the part common to WUSB Host Controllers, the
- * HWA and the PCI-based one, that is implemented following the WHCI
- * spec. All these layers are implemented in ../wusbcore.
- *
- * The main functions are hwahc_op_urb_{en,de}queue(), that pass the
- * job of converting a URB to a Wire Adapter
- *
- * Entry points:
- *
- * hwahc_driver_*() Driver initialization, registration and
- * teardown.
- *
- * hwahc_probe() New device came up, create an instance for
- * it [from device enumeration].
- *
- * hwahc_disconnect() Remove device instance [from device
- * enumeration].
- *
- * [__]hwahc_op_*() Host-Wire-Adaptor specific functions for
- * starting/stopping/etc (some might be made also
- * DWA).
- */
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/workqueue.h>
-#include <linux/wait.h>
-#include <linux/completion.h>
-#include "../wusbcore/wa-hc.h"
-#include "../wusbcore/wusbhc.h"
-
-struct hwahc {
- struct wusbhc wusbhc; /* has to be 1st */
- struct wahc wa;
-};
-
-/*
- * FIXME should be wusbhc
- *
- * NOTE: we need to cache the Cluster ID because later...there is no
- * way to get it :)
- */
-static int __hwahc_set_cluster_id(struct hwahc *hwahc, u8 cluster_id)
-{
- int result;
- struct wusbhc *wusbhc = &hwahc->wusbhc;
- struct wahc *wa = &hwahc->wa;
- struct device *dev = &wa->usb_iface->dev;
-
- result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
- WUSB_REQ_SET_CLUSTER_ID,
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- cluster_id,
- wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
- NULL, 0, USB_CTRL_SET_TIMEOUT);
- if (result < 0)
- dev_err(dev, "Cannot set WUSB Cluster ID to 0x%02x: %d\n",
- cluster_id, result);
- else
- wusbhc->cluster_id = cluster_id;
- dev_info(dev, "Wireless USB Cluster ID set to 0x%02x\n", cluster_id);
- return result;
-}
-
-static int __hwahc_op_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots)
-{
- struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
- struct wahc *wa = &hwahc->wa;
-
- return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
- WUSB_REQ_SET_NUM_DNTS,
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- interval << 8 | slots,
- wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
- NULL, 0, USB_CTRL_SET_TIMEOUT);
-}
-
-/*
- * Reset a WUSB host controller and wait for it to complete doing it.
- *
- * @usb_hcd: Pointer to WUSB Host Controller instance.
- *
- */
-static int hwahc_op_reset(struct usb_hcd *usb_hcd)
-{
- int result;
- struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
- struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
- struct device *dev = &hwahc->wa.usb_iface->dev;
-
- mutex_lock(&wusbhc->mutex);
- wa_nep_disarm(&hwahc->wa);
- result = __wa_set_feature(&hwahc->wa, WA_RESET);
- if (result < 0) {
- dev_err(dev, "error commanding HC to reset: %d\n", result);
- goto error_unlock;
- }
- result = __wa_wait_status(&hwahc->wa, WA_STATUS_RESETTING, 0);
- if (result < 0) {
- dev_err(dev, "error waiting for HC to reset: %d\n", result);
- goto error_unlock;
- }
-error_unlock:
- mutex_unlock(&wusbhc->mutex);
- return result;
-}
-
-/*
- * FIXME: break this function up
- */
-static int hwahc_op_start(struct usb_hcd *usb_hcd)
-{
- u8 addr;
- int result;
- struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
- struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-
- result = -ENOSPC;
- mutex_lock(&wusbhc->mutex);
- addr = wusb_cluster_id_get();
- if (addr == 0)
- goto error_cluster_id_get;
- result = __hwahc_set_cluster_id(hwahc, addr);
- if (result < 0)
- goto error_set_cluster_id;
-
- usb_hcd->uses_new_polling = 1;
- set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags);
- usb_hcd->state = HC_STATE_RUNNING;
-
- /*
- * prevent USB core from suspending the root hub since
- * bus_suspend and bus_resume are not yet supported.
- */
- pm_runtime_get_noresume(&usb_hcd->self.root_hub->dev);
-
- result = 0;
-out:
- mutex_unlock(&wusbhc->mutex);
- return result;
-
-error_set_cluster_id:
- wusb_cluster_id_put(wusbhc->cluster_id);
-error_cluster_id_get:
- goto out;
-
-}
-
-/*
- * No need to abort pipes, as when this is called, all the children
- * has been disconnected and that has done it [through
- * usb_disable_interface() -> usb_disable_endpoint() ->
- * hwahc_op_ep_disable() - >rpipe_ep_disable()].
- */
-static void hwahc_op_stop(struct usb_hcd *usb_hcd)
-{
- struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-
- mutex_lock(&wusbhc->mutex);
- wusb_cluster_id_put(wusbhc->cluster_id);
- mutex_unlock(&wusbhc->mutex);
-}
-
-static int hwahc_op_get_frame_number(struct usb_hcd *usb_hcd)
-{
- struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
- struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
- struct wahc *wa = &hwahc->wa;
-
- /*
- * We cannot query the HWA for the WUSB time since that requires sending
- * a synchronous URB and this function can be called in_interrupt.
- * Instead, query the USB frame number for our parent and use that.
- */
- return usb_get_current_frame_number(wa->usb_dev);
-}
-
-static int hwahc_op_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb,
- gfp_t gfp)
-{
- struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
- struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-
- return wa_urb_enqueue(&hwahc->wa, urb->ep, urb, gfp);
-}
-
-static int hwahc_op_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb,
- int status)
-{
- struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
- struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-
- return wa_urb_dequeue(&hwahc->wa, urb, status);
-}
-
-/*
- * Release resources allocated for an endpoint
- *
- * If there is an associated rpipe to this endpoint, go ahead and put it.
- */
-static void hwahc_op_endpoint_disable(struct usb_hcd *usb_hcd,
- struct usb_host_endpoint *ep)
-{
- struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
- struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-
- rpipe_ep_disable(&hwahc->wa, ep);
-}
-
-static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc)
-{
- int result;
- struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
- struct device *dev = &hwahc->wa.usb_iface->dev;
-
- result = __wa_set_feature(&hwahc->wa, WA_ENABLE);
- if (result < 0) {
- dev_err(dev, "error commanding HC to start: %d\n", result);
- goto error_stop;
- }
- result = __wa_wait_status(&hwahc->wa, WA_ENABLE, WA_ENABLE);
- if (result < 0) {
- dev_err(dev, "error waiting for HC to start: %d\n", result);
- goto error_stop;
- }
- result = wa_nep_arm(&hwahc->wa, GFP_KERNEL);
- if (result < 0) {
- dev_err(dev, "cannot listen to notifications: %d\n", result);
- goto error_stop;
- }
- /*
- * If WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS is set,
- * disable transfer notifications.
- */
- if (hwahc->wa.quirks &
- WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS) {
- struct usb_host_interface *cur_altsetting =
- hwahc->wa.usb_iface->cur_altsetting;
-
- result = usb_control_msg(hwahc->wa.usb_dev,
- usb_sndctrlpipe(hwahc->wa.usb_dev, 0),
- WA_REQ_ALEREON_DISABLE_XFER_NOTIFICATIONS,
- USB_DIR_OUT | USB_TYPE_VENDOR |
- USB_RECIP_INTERFACE,
- WA_REQ_ALEREON_FEATURE_SET,
- cur_altsetting->desc.bInterfaceNumber,
- NULL, 0,
- USB_CTRL_SET_TIMEOUT);
- /*
- * If we successfully sent the control message, start DTI here
- * because no transfer notifications will be received which is
- * where DTI is normally started.
- */
- if (result == 0)
- result = wa_dti_start(&hwahc->wa);
- else
- result = 0; /* OK. Continue normally. */
-
- if (result < 0) {
- dev_err(dev, "cannot start DTI: %d\n", result);
- goto error_dti_start;
- }
- }
-
- return result;
-
-error_dti_start:
- wa_nep_disarm(&hwahc->wa);
-error_stop:
- __wa_clear_feature(&hwahc->wa, WA_ENABLE);
- return result;
-}
-
-static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc, int delay)
-{
- struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
- struct wahc *wa = &hwahc->wa;
- u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
- int ret;
-
- ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
- WUSB_REQ_CHAN_STOP,
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- delay * 1000,
- iface_no,
- NULL, 0, USB_CTRL_SET_TIMEOUT);
- if (ret == 0)
- msleep(delay);
-
- wa_nep_disarm(&hwahc->wa);
- __wa_stop(&hwahc->wa);
-}
-
-/*
- * Set the UWB MAS allocation for the WUSB cluster
- *
- * @stream_index: stream to use (-1 for cancelling the allocation)
- * @mas: mas bitmap to use
- */
-static int __hwahc_op_bwa_set(struct wusbhc *wusbhc, s8 stream_index,
- const struct uwb_mas_bm *mas)
-{
- int result;
- struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
- struct wahc *wa = &hwahc->wa;
- struct device *dev = &wa->usb_iface->dev;
- u8 mas_le[UWB_NUM_MAS/8];
-
- /* Set the stream index */
- result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
- WUSB_REQ_SET_STREAM_IDX,
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- stream_index,
- wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
- NULL, 0, USB_CTRL_SET_TIMEOUT);
- if (result < 0) {
- dev_err(dev, "Cannot set WUSB stream index: %d\n", result);
- goto out;
- }
- uwb_mas_bm_copy_le(mas_le, mas);
- /* Set the MAS allocation */
- result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
- WUSB_REQ_SET_WUSB_MAS,
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
- mas_le, 32, USB_CTRL_SET_TIMEOUT);
- if (result < 0)
- dev_err(dev, "Cannot set WUSB MAS allocation: %d\n", result);
-out:
- return result;
-}
-
-/*
- * Add an IE to the host's MMC
- *
- * @interval: See WUSB1.0[8.5.3.1]
- * @repeat_cnt: See WUSB1.0[8.5.3.1]
- * @handle: See WUSB1.0[8.5.3.1]
- * @wuie: Pointer to the header of the WUSB IE data to add.
- * MUST BE allocated in a kmalloc buffer (no stack or
- * vmalloc).
- *
- * NOTE: the format of the WUSB IEs for MMCs are different to the
- * normal MBOA MAC IEs (IE Id + Length in MBOA MAC vs. Length +
- * Id in WUSB IEs). Standards...you gotta love'em.
- */
-static int __hwahc_op_mmcie_add(struct wusbhc *wusbhc, u8 interval,
- u8 repeat_cnt, u8 handle,
- struct wuie_hdr *wuie)
-{
- struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
- struct wahc *wa = &hwahc->wa;
- u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
-
- return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
- WUSB_REQ_ADD_MMC_IE,
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- interval << 8 | repeat_cnt,
- handle << 8 | iface_no,
- wuie, wuie->bLength, USB_CTRL_SET_TIMEOUT);
-}
-
-/*
- * Remove an IE to the host's MMC
- *
- * @handle: See WUSB1.0[8.5.3.1]
- */
-static int __hwahc_op_mmcie_rm(struct wusbhc *wusbhc, u8 handle)
-{
- struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
- struct wahc *wa = &hwahc->wa;
- u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
- return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
- WUSB_REQ_REMOVE_MMC_IE,
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, handle << 8 | iface_no,
- NULL, 0, USB_CTRL_SET_TIMEOUT);
-}
-
-/*
- * Update device information for a given fake port
- *
- * @port_idx: Fake port to which device is connected (wusbhc index, not
- * USB port number).
- */
-static int __hwahc_op_dev_info_set(struct wusbhc *wusbhc,
- struct wusb_dev *wusb_dev)
-{
- struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
- struct wahc *wa = &hwahc->wa;
- u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
- struct hwa_dev_info *dev_info;
- int ret;
-
- /* fill out the Device Info buffer and send it */
- dev_info = kzalloc(sizeof(struct hwa_dev_info), GFP_KERNEL);
- if (!dev_info)
- return -ENOMEM;
- uwb_mas_bm_copy_le(dev_info->bmDeviceAvailability,
- &wusb_dev->availability);
- dev_info->bDeviceAddress = wusb_dev->addr;
-
- /*
- * If the descriptors haven't been read yet, use a default PHY
- * rate of 53.3 Mbit/s only. The correct value will be used
- * when this will be called again as part of the
- * authentication process (which occurs after the descriptors
- * have been read).
- */
- if (wusb_dev->wusb_cap_descr)
- dev_info->wPHYRates = wusb_dev->wusb_cap_descr->wPHYRates;
- else
- dev_info->wPHYRates = cpu_to_le16(USB_WIRELESS_PHY_53);
-
- ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
- WUSB_REQ_SET_DEV_INFO,
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, wusb_dev->port_idx << 8 | iface_no,
- dev_info, sizeof(struct hwa_dev_info),
- USB_CTRL_SET_TIMEOUT);
- kfree(dev_info);
- return ret;
-}
-
-/*
- * Set host's idea of which encryption (and key) method to use when
- * talking to ad evice on a given port.
- *
- * If key is NULL, it means disable encryption for that "virtual port"
- * (used when we disconnect).
- */
-static int __hwahc_dev_set_key(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
- const void *key, size_t key_size,
- u8 key_idx)
-{
- int result = -ENOMEM;
- struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
- struct wahc *wa = &hwahc->wa;
- u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
- struct usb_key_descriptor *keyd;
- size_t keyd_len;
-
- keyd_len = sizeof(*keyd) + key_size;
- keyd = kzalloc(keyd_len, GFP_KERNEL);
- if (keyd == NULL)
- return -ENOMEM;
-
- keyd->bLength = keyd_len;
- keyd->bDescriptorType = USB_DT_KEY;
- keyd->tTKID[0] = (tkid >> 0) & 0xff;
- keyd->tTKID[1] = (tkid >> 8) & 0xff;
- keyd->tTKID[2] = (tkid >> 16) & 0xff;
- memcpy(keyd->bKeyData, key, key_size);
-
- result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
- USB_REQ_SET_DESCRIPTOR,
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- USB_DT_KEY << 8 | key_idx,
- port_idx << 8 | iface_no,
- keyd, keyd_len, USB_CTRL_SET_TIMEOUT);
-
- kzfree(keyd); /* clear keys etc. */
- return result;
-}
-
-/*
- * Set host's idea of which encryption (and key) method to use when
- * talking to ad evice on a given port.
- *
- * If key is NULL, it means disable encryption for that "virtual port"
- * (used when we disconnect).
- */
-static int __hwahc_op_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
- const void *key, size_t key_size)
-{
- int result = -ENOMEM;
- struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
- struct wahc *wa = &hwahc->wa;
- u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
- u8 encryption_value;
-
- /* Tell the host which key to use to talk to the device */
- if (key) {
- u8 key_idx = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_PTK,
- WUSB_KEY_INDEX_ORIGINATOR_HOST);
-
- result = __hwahc_dev_set_key(wusbhc, port_idx, tkid,
- key, key_size, key_idx);
- if (result < 0)
- goto error_set_key;
- encryption_value = wusbhc->ccm1_etd->bEncryptionValue;
- } else {
- /* FIXME: this should come from wusbhc->etd[UNSECURE].value */
- encryption_value = 0;
- }
-
- /* Set the encryption type for communicating with the device */
- result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
- USB_REQ_SET_ENCRYPTION,
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- encryption_value, port_idx << 8 | iface_no,
- NULL, 0, USB_CTRL_SET_TIMEOUT);
- if (result < 0)
- dev_err(wusbhc->dev, "Can't set host's WUSB encryption for "
- "port index %u to %s (value %d): %d\n", port_idx,
- wusb_et_name(wusbhc->ccm1_etd->bEncryptionType),
- wusbhc->ccm1_etd->bEncryptionValue, result);
-error_set_key:
- return result;
-}
-
-/*
- * Set host's GTK key
- */
-static int __hwahc_op_set_gtk(struct wusbhc *wusbhc, u32 tkid,
- const void *key, size_t key_size)
-{
- u8 key_idx = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_GTK,
- WUSB_KEY_INDEX_ORIGINATOR_HOST);
-
- return __hwahc_dev_set_key(wusbhc, 0, tkid, key, key_size, key_idx);
-}
-
-/*
- * Get the Wire Adapter class-specific descriptor
- *
- * NOTE: this descriptor comes with the big bundled configuration
- * descriptor that includes the interfaces' and endpoints', so
- * we just look for it in the cached copy kept by the USB stack.
- *
- * NOTE2: We convert LE fields to CPU order.
- */
-static int wa_fill_descr(struct wahc *wa)
-{
- int result;
- struct device *dev = &wa->usb_iface->dev;
- char *itr;
- struct usb_device *usb_dev = wa->usb_dev;
- struct usb_descriptor_header *hdr;
- struct usb_wa_descriptor *wa_descr;
- size_t itr_size, actconfig_idx;
-
- actconfig_idx = (usb_dev->actconfig - usb_dev->config) /
- sizeof(usb_dev->config[0]);
- itr = usb_dev->rawdescriptors[actconfig_idx];
- itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength);
- while (itr_size >= sizeof(*hdr)) {
- hdr = (struct usb_descriptor_header *) itr;
- dev_dbg(dev, "Extra device descriptor: "
- "type %02x/%u bytes @ %zu (%zu left)\n",
- hdr->bDescriptorType, hdr->bLength,
- (itr - usb_dev->rawdescriptors[actconfig_idx]),
- itr_size);
- if (hdr->bDescriptorType == USB_DT_WIRE_ADAPTER)
- goto found;
- itr += hdr->bLength;
- itr_size -= hdr->bLength;
- }
- dev_err(dev, "cannot find Wire Adapter Class descriptor\n");
- return -ENODEV;
-
-found:
- result = -EINVAL;
- if (hdr->bLength > itr_size) { /* is it available? */
- dev_err(dev, "incomplete Wire Adapter Class descriptor "
- "(%zu bytes left, %u needed)\n",
- itr_size, hdr->bLength);
- goto error;
- }
- if (hdr->bLength < sizeof(*wa->wa_descr)) {
- dev_err(dev, "short Wire Adapter Class descriptor\n");
- goto error;
- }
- wa->wa_descr = wa_descr = (struct usb_wa_descriptor *) hdr;
- if (le16_to_cpu(wa_descr->bcdWAVersion) > 0x0100)
- dev_warn(dev, "Wire Adapter v%d.%d newer than groked v1.0\n",
- (le16_to_cpu(wa_descr->bcdWAVersion) & 0xff00) >> 8,
- le16_to_cpu(wa_descr->bcdWAVersion) & 0x00ff);
- result = 0;
-error:
- return result;
-}
-
-static const struct hc_driver hwahc_hc_driver = {
- .description = "hwa-hcd",
- .product_desc = "Wireless USB HWA host controller",
- .hcd_priv_size = sizeof(struct hwahc) - sizeof(struct usb_hcd),
- .irq = NULL, /* FIXME */
- .flags = HCD_USB25,
- .reset = hwahc_op_reset,
- .start = hwahc_op_start,
- .stop = hwahc_op_stop,
- .get_frame_number = hwahc_op_get_frame_number,
- .urb_enqueue = hwahc_op_urb_enqueue,
- .urb_dequeue = hwahc_op_urb_dequeue,
- .endpoint_disable = hwahc_op_endpoint_disable,
-
- .hub_status_data = wusbhc_rh_status_data,
- .hub_control = wusbhc_rh_control,
- .start_port_reset = wusbhc_rh_start_port_reset,
-};
-
-static int hwahc_security_create(struct hwahc *hwahc)
-{
- int result;
- struct wusbhc *wusbhc = &hwahc->wusbhc;
- struct usb_device *usb_dev = hwahc->wa.usb_dev;
- struct device *dev = &usb_dev->dev;
- struct usb_security_descriptor *secd;
- struct usb_encryption_descriptor *etd;
- void *itr, *top;
- size_t itr_size, needed, bytes;
- u8 index;
- char buf[64];
-
- /* Find the host's security descriptors in the config descr bundle */
- index = (usb_dev->actconfig - usb_dev->config) /
- sizeof(usb_dev->config[0]);
- itr = usb_dev->rawdescriptors[index];
- itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength);
- top = itr + itr_size;
- result = __usb_get_extra_descriptor(usb_dev->rawdescriptors[index],
- le16_to_cpu(usb_dev->actconfig->desc.wTotalLength),
- USB_DT_SECURITY, (void **) &secd, sizeof(*secd));
- if (result == -1) {
- dev_warn(dev, "BUG? WUSB host has no security descriptors\n");
- return 0;
- }
- needed = sizeof(*secd);
- if (top - (void *)secd < needed) {
- dev_err(dev, "BUG? Not enough data to process security "
- "descriptor header (%zu bytes left vs %zu needed)\n",
- top - (void *) secd, needed);
- return 0;
- }
- needed = le16_to_cpu(secd->wTotalLength);
- if (top - (void *)secd < needed) {
- dev_err(dev, "BUG? Not enough data to process security "
- "descriptors (%zu bytes left vs %zu needed)\n",
- top - (void *) secd, needed);
- return 0;
- }
- /* Walk over the sec descriptors and store CCM1's on wusbhc */
- itr = (void *) secd + sizeof(*secd);
- top = (void *) secd + le16_to_cpu(secd->wTotalLength);
- index = 0;
- bytes = 0;
- while (itr < top) {
- etd = itr;
- if (top - itr < sizeof(*etd)) {
- dev_err(dev, "BUG: bad host security descriptor; "
- "not enough data (%zu vs %zu left)\n",
- top - itr, sizeof(*etd));
- break;
- }
- if (etd->bLength < sizeof(*etd)) {
- dev_err(dev, "BUG: bad host encryption descriptor; "
- "descriptor is too short "
- "(%zu vs %zu needed)\n",
- (size_t)etd->bLength, sizeof(*etd));
- break;
- }
- itr += etd->bLength;
- bytes += snprintf(buf + bytes, sizeof(buf) - bytes,
- "%s (0x%02x) ",
- wusb_et_name(etd->bEncryptionType),
- etd->bEncryptionValue);
- wusbhc->ccm1_etd = etd;
- }
- dev_info(dev, "supported encryption types: %s\n", buf);
- if (wusbhc->ccm1_etd == NULL) {
- dev_err(dev, "E: host doesn't support CCM-1 crypto\n");
- return 0;
- }
- /* Pretty print what we support */
- return 0;
-}
-
-static void hwahc_security_release(struct hwahc *hwahc)
-{
- /* nothing to do here so far... */
-}
-
-static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface,
- kernel_ulong_t quirks)
-{
- int result;
- struct device *dev = &iface->dev;
- struct wusbhc *wusbhc = &hwahc->wusbhc;
- struct wahc *wa = &hwahc->wa;
- struct usb_device *usb_dev = interface_to_usbdev(iface);
-
- wa->usb_dev = usb_get_dev(usb_dev); /* bind the USB device */
- wa->usb_iface = usb_get_intf(iface);
- wusbhc->dev = dev;
- /* defer getting the uwb_rc handle until it is needed since it
- * may not have been registered by the hwa_rc driver yet. */
- wusbhc->uwb_rc = NULL;
- result = wa_fill_descr(wa); /* Get the device descriptor */
- if (result < 0)
- goto error_fill_descriptor;
- if (wa->wa_descr->bNumPorts > USB_MAXCHILDREN) {
- dev_err(dev, "FIXME: USB_MAXCHILDREN too low for WUSB "
- "adapter (%u ports)\n", wa->wa_descr->bNumPorts);
- wusbhc->ports_max = USB_MAXCHILDREN;
- } else {
- wusbhc->ports_max = wa->wa_descr->bNumPorts;
- }
- wusbhc->mmcies_max = wa->wa_descr->bNumMMCIEs;
- wusbhc->start = __hwahc_op_wusbhc_start;
- wusbhc->stop = __hwahc_op_wusbhc_stop;
- wusbhc->mmcie_add = __hwahc_op_mmcie_add;
- wusbhc->mmcie_rm = __hwahc_op_mmcie_rm;
- wusbhc->dev_info_set = __hwahc_op_dev_info_set;
- wusbhc->bwa_set = __hwahc_op_bwa_set;
- wusbhc->set_num_dnts = __hwahc_op_set_num_dnts;
- wusbhc->set_ptk = __hwahc_op_set_ptk;
- wusbhc->set_gtk = __hwahc_op_set_gtk;
- result = hwahc_security_create(hwahc);
- if (result < 0) {
- dev_err(dev, "Can't initialize security: %d\n", result);
- goto error_security_create;
- }
- wa->wusb = wusbhc; /* FIXME: ugly, need to fix */
- result = wusbhc_create(&hwahc->wusbhc);
- if (result < 0) {
- dev_err(dev, "Can't create WUSB HC structures: %d\n", result);
- goto error_wusbhc_create;
- }
- result = wa_create(&hwahc->wa, iface, quirks);
- if (result < 0)
- goto error_wa_create;
- return 0;
-
-error_wa_create:
- wusbhc_destroy(&hwahc->wusbhc);
-error_wusbhc_create:
- /* WA Descr fill allocs no resources */
-error_security_create:
-error_fill_descriptor:
- usb_put_intf(iface);
- usb_put_dev(usb_dev);
- return result;
-}
-
-static void hwahc_destroy(struct hwahc *hwahc)
-{
- struct wusbhc *wusbhc = &hwahc->wusbhc;
-
- mutex_lock(&wusbhc->mutex);
- __wa_destroy(&hwahc->wa);
- wusbhc_destroy(&hwahc->wusbhc);
- hwahc_security_release(hwahc);
- hwahc->wusbhc.dev = NULL;
- uwb_rc_put(wusbhc->uwb_rc);
- usb_put_intf(hwahc->wa.usb_iface);
- usb_put_dev(hwahc->wa.usb_dev);
- mutex_unlock(&wusbhc->mutex);
-}
-
-static void hwahc_init(struct hwahc *hwahc)
-{
- wa_init(&hwahc->wa);
-}
-
-static int hwahc_probe(struct usb_interface *usb_iface,
- const struct usb_device_id *id)
-{
- int result;
- struct usb_hcd *usb_hcd;
- struct wusbhc *wusbhc;
- struct hwahc *hwahc;
- struct device *dev = &usb_iface->dev;
-
- result = -ENOMEM;
- usb_hcd = usb_create_hcd(&hwahc_hc_driver, &usb_iface->dev, "wusb-hwa");
- if (usb_hcd == NULL) {
- dev_err(dev, "unable to allocate instance\n");
- goto error_alloc;
- }
- usb_hcd->wireless = 1;
- usb_hcd->self.sg_tablesize = ~0;
- wusbhc = usb_hcd_to_wusbhc(usb_hcd);
- hwahc = container_of(wusbhc, struct hwahc, wusbhc);
- hwahc_init(hwahc);
- result = hwahc_create(hwahc, usb_iface, id->driver_info);
- if (result < 0) {
- dev_err(dev, "Cannot initialize internals: %d\n", result);
- goto error_hwahc_create;
- }
- result = usb_add_hcd(usb_hcd, 0, 0);
- if (result < 0) {
- dev_err(dev, "Cannot add HCD: %d\n", result);
- goto error_add_hcd;
- }
- device_wakeup_enable(usb_hcd->self.controller);
- result = wusbhc_b_create(&hwahc->wusbhc);
- if (result < 0) {
- dev_err(dev, "Cannot setup phase B of WUSBHC: %d\n", result);
- goto error_wusbhc_b_create;
- }
- return 0;
-
-error_wusbhc_b_create:
- usb_remove_hcd(usb_hcd);
-error_add_hcd:
- hwahc_destroy(hwahc);
-error_hwahc_create:
- usb_put_hcd(usb_hcd);
-error_alloc:
- return result;
-}
-
-static void hwahc_disconnect(struct usb_interface *usb_iface)
-{
- struct usb_hcd *usb_hcd;
- struct wusbhc *wusbhc;
- struct hwahc *hwahc;
-
- usb_hcd = usb_get_intfdata(usb_iface);
- wusbhc = usb_hcd_to_wusbhc(usb_hcd);
- hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-
- wusbhc_b_destroy(&hwahc->wusbhc);
- usb_remove_hcd(usb_hcd);
- hwahc_destroy(hwahc);
- usb_put_hcd(usb_hcd);
-}
-
-static const struct usb_device_id hwahc_id_table[] = {
- /* Alereon 5310 */
- { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5310, 0xe0, 0x02, 0x01),
- .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC |
- WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS },
- /* Alereon 5611 */
- { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5611, 0xe0, 0x02, 0x01),
- .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC |
- WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS },
- /* FIXME: use class labels for this */
- { USB_INTERFACE_INFO(0xe0, 0x02, 0x01), },
- {},
-};
-MODULE_DEVICE_TABLE(usb, hwahc_id_table);
-
-static struct usb_driver hwahc_driver = {
- .name = "hwa-hc",
- .probe = hwahc_probe,
- .disconnect = hwahc_disconnect,
- .id_table = hwahc_id_table,
-};
-
-module_usb_driver(hwahc_driver);
-
-MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
-MODULE_DESCRIPTION("Host Wired Adapter USB Host Control Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c
index 6e3dad1..5835f99 100644
--- a/drivers/usb/host/imx21-hcd.c
+++ b/drivers/usb/host/imx21-hcd.c
@@ -1771,7 +1771,7 @@
.product_desc = "IMX21 USB Host Controller",
.hcd_priv_size = sizeof(struct imx21),
- .flags = HCD_USB11,
+ .flags = HCD_DMA | HCD_USB11,
.irq = imx21_irq,
.reset = imx21_hc_reset,
@@ -1836,10 +1836,8 @@
if (!res)
return -ENODEV;
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq);
+ if (irq < 0)
return irq;
- }
hcd = usb_create_hcd(&imx21_hc_driver,
&pdev->dev, dev_name(&pdev->dev));
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 74da136..a87c0b2 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -1581,12 +1581,6 @@
irq = ires->start;
irqflags = ires->flags & IRQF_TRIGGER_MASK;
- if (pdev->dev.dma_mask) {
- DBG("DMA not supported\n");
- ret = -EINVAL;
- goto err1;
- }
-
if (!request_mem_region(addr->start, 2, hcd_name)) {
ret = -EBUSY;
goto err1;
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index b21c386..96f8daa 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -2159,25 +2159,15 @@
return 0;
}
-
-static int isp1362_open(struct inode *inode, struct file *file)
-{
- return single_open(file, isp1362_show, inode);
-}
-
-static const struct file_operations debug_ops = {
- .open = isp1362_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(isp1362);
/* expect just one isp1362_hcd per system */
static void create_debug_file(struct isp1362_hcd *isp1362_hcd)
{
isp1362_hcd->debug_file = debugfs_create_file("isp1362", S_IRUGO,
usb_debug_root,
- isp1362_hcd, &debug_ops);
+ isp1362_hcd,
+ &isp1362_fops);
}
static void remove_debug_file(struct isp1362_hcd *isp1362_hcd)
@@ -2655,11 +2645,6 @@
if (pdev->num_resources < 3)
return -ENODEV;
- if (pdev->dev.dma_mask) {
- DBG(1, "won't do DMA");
- return -ENODEV;
- }
-
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq_res)
return -ENODEV;
diff --git a/drivers/usb/host/isp1362.h b/drivers/usb/host/isp1362.h
index 6502408..4c49688 100644
--- a/drivers/usb/host/isp1362.h
+++ b/drivers/usb/host/isp1362.h
@@ -11,7 +11,7 @@
#define USE_32BIT 0
-/* These options are mutually eclusive */
+/* These options are mutually exclusive */
#define USE_PLATFORM_DELAY 0
#define USE_NDELAY 0
diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c
index afa321a..8819f50 100644
--- a/drivers/usb/host/max3421-hcd.c
+++ b/drivers/usb/host/max3421-hcd.c
@@ -1800,21 +1800,6 @@
return -1;
}
-/*
- * The SPI driver already takes care of DMA-mapping/unmapping, so no
- * reason to do it twice.
- */
-static int
-max3421_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
-{
- return 0;
-}
-
-static void
-max3421_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
-{
-}
-
static const struct hc_driver max3421_hcd_desc = {
.description = "max3421",
.product_desc = DRIVER_DESC,
@@ -1826,8 +1811,6 @@
.get_frame_number = max3421_get_frame_number,
.urb_enqueue = max3421_urb_enqueue,
.urb_dequeue = max3421_urb_dequeue,
- .map_urb_for_dma = max3421_map_urb_for_dma,
- .unmap_urb_for_dma = max3421_unmap_urb_for_dma,
.endpoint_disable = max3421_endpoint_disable,
.hub_status_data = max3421_hub_status_data,
.hub_control = max3421_hub_control,
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index ec6739e..fc35a79 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -141,8 +141,11 @@
struct regmap *regmap;
regmap = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr");
- if (IS_ERR(regmap))
- regmap = NULL;
+ if (IS_ERR(regmap)) {
+ regmap = syscon_regmap_lookup_by_compatible("microchip,sam9x60-sfr");
+ if (IS_ERR(regmap))
+ regmap = NULL;
+ }
return regmap;
}
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index a55cbba..38183ac 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -9,6 +9,7 @@
*/
#include <linux/clk.h>
+#include <linux/gpio/consumer.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
@@ -39,7 +40,7 @@
struct phy *usb11_phy;
struct regulator *vbus_reg;
struct notifier_block nb;
- unsigned int reg_enabled;
+ struct gpio_desc *oc_gpio;
};
#define to_da8xx_ohci(hcd) (struct da8xx_ohci_hcd *)(hcd_to_ohci(hcd)->priv)
@@ -86,31 +87,24 @@
static int ohci_da8xx_set_power(struct usb_hcd *hcd, int on)
{
struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
- struct device *dev = hcd->self.controller;
- struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
+ struct device *dev = hcd->self.controller;
int ret;
- if (hub && hub->set_power)
- return hub->set_power(1, on);
-
if (!da8xx_ohci->vbus_reg)
return 0;
- if (on && !da8xx_ohci->reg_enabled) {
+ if (on) {
ret = regulator_enable(da8xx_ohci->vbus_reg);
if (ret) {
dev_err(dev, "Failed to enable regulator: %d\n", ret);
return ret;
}
- da8xx_ohci->reg_enabled = 1;
-
- } else if (!on && da8xx_ohci->reg_enabled) {
+ } else {
ret = regulator_disable(da8xx_ohci->vbus_reg);
if (ret) {
dev_err(dev, "Failed to disable regulator: %d\n", ret);
return ret;
}
- da8xx_ohci->reg_enabled = 0;
}
return 0;
@@ -119,11 +113,6 @@
static int ohci_da8xx_get_power(struct usb_hcd *hcd)
{
struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
- struct device *dev = hcd->self.controller;
- struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
-
- if (hub && hub->get_power)
- return hub->get_power(1);
if (da8xx_ohci->vbus_reg)
return regulator_is_enabled(da8xx_ohci->vbus_reg);
@@ -134,13 +123,11 @@
static int ohci_da8xx_get_oci(struct usb_hcd *hcd)
{
struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
- struct device *dev = hcd->self.controller;
- struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
unsigned int flags;
int ret;
- if (hub && hub->get_oci)
- return hub->get_oci(1);
+ if (da8xx_ohci->oc_gpio)
+ return gpiod_get_value_cansleep(da8xx_ohci->oc_gpio);
if (!da8xx_ohci->vbus_reg)
return 0;
@@ -158,11 +145,6 @@
static int ohci_da8xx_has_set_power(struct usb_hcd *hcd)
{
struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
- struct device *dev = hcd->self.controller;
- struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
-
- if (hub && hub->set_power)
- return 1;
if (da8xx_ohci->vbus_reg)
return 1;
@@ -173,10 +155,8 @@
static int ohci_da8xx_has_oci(struct usb_hcd *hcd)
{
struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
- struct device *dev = hcd->self.controller;
- struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
- if (hub && hub->get_oci)
+ if (da8xx_ohci->oc_gpio)
return 1;
if (da8xx_ohci->vbus_reg)
@@ -196,19 +176,6 @@
return 0;
}
-/*
- * Handle the port over-current indicator change.
- */
-static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub,
- unsigned port)
-{
- ocic_mask |= 1 << port;
-
- /* Once over-current is detected, the port needs to be powered down */
- if (hub->get_oci(port) > 0)
- hub->set_power(port, 0);
-}
-
static int ohci_da8xx_regulator_event(struct notifier_block *nb,
unsigned long event, void *data)
{
@@ -223,16 +190,29 @@
return 0;
}
+static irqreturn_t ohci_da8xx_oc_thread(int irq, void *data)
+{
+ struct da8xx_ohci_hcd *da8xx_ohci = data;
+ struct device *dev = da8xx_ohci->hcd->self.controller;
+ int ret;
+
+ if (gpiod_get_value_cansleep(da8xx_ohci->oc_gpio) &&
+ da8xx_ohci->vbus_reg) {
+ ret = regulator_disable(da8xx_ohci->vbus_reg);
+ if (ret)
+ dev_err(dev, "Failed to disable regulator: %d\n", ret);
+ }
+
+ return IRQ_HANDLED;
+}
+
static int ohci_da8xx_register_notify(struct usb_hcd *hcd)
{
struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
struct device *dev = hcd->self.controller;
- struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
int ret = 0;
- if (hub && hub->ocic_notify) {
- ret = hub->ocic_notify(ohci_da8xx_ocic_handler);
- } else if (da8xx_ohci->vbus_reg) {
+ if (!da8xx_ohci->oc_gpio && da8xx_ohci->vbus_reg) {
da8xx_ohci->nb.notifier_call = ohci_da8xx_regulator_event;
ret = devm_regulator_register_notifier(da8xx_ohci->vbus_reg,
&da8xx_ohci->nb);
@@ -244,15 +224,6 @@
return ret;
}
-static void ohci_da8xx_unregister_notify(struct usb_hcd *hcd)
-{
- struct device *dev = hcd->self.controller;
- struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
-
- if (hub && hub->ocic_notify)
- hub->ocic_notify(NULL);
-}
-
static int ohci_da8xx_reset(struct usb_hcd *hcd)
{
struct device *dev = hcd->self.controller;
@@ -402,34 +373,35 @@
static int ohci_da8xx_probe(struct platform_device *pdev)
{
struct da8xx_ohci_hcd *da8xx_ohci;
+ struct device *dev = &pdev->dev;
+ int error, hcd_irq, oc_irq;
struct usb_hcd *hcd;
struct resource *mem;
- int error, irq;
- hcd = usb_create_hcd(&ohci_da8xx_hc_driver, &pdev->dev,
- dev_name(&pdev->dev));
+
+ hcd = usb_create_hcd(&ohci_da8xx_hc_driver, dev, dev_name(dev));
if (!hcd)
return -ENOMEM;
da8xx_ohci = to_da8xx_ohci(hcd);
da8xx_ohci->hcd = hcd;
- da8xx_ohci->usb11_clk = devm_clk_get(&pdev->dev, NULL);
+ da8xx_ohci->usb11_clk = devm_clk_get(dev, NULL);
if (IS_ERR(da8xx_ohci->usb11_clk)) {
error = PTR_ERR(da8xx_ohci->usb11_clk);
if (error != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Failed to get clock.\n");
+ dev_err(dev, "Failed to get clock.\n");
goto err;
}
- da8xx_ohci->usb11_phy = devm_phy_get(&pdev->dev, "usb-phy");
+ da8xx_ohci->usb11_phy = devm_phy_get(dev, "usb-phy");
if (IS_ERR(da8xx_ohci->usb11_phy)) {
error = PTR_ERR(da8xx_ohci->usb11_phy);
if (error != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Failed to get phy.\n");
+ dev_err(dev, "Failed to get phy.\n");
goto err;
}
- da8xx_ohci->vbus_reg = devm_regulator_get_optional(&pdev->dev, "vbus");
+ da8xx_ohci->vbus_reg = devm_regulator_get_optional(dev, "vbus");
if (IS_ERR(da8xx_ohci->vbus_reg)) {
error = PTR_ERR(da8xx_ohci->vbus_reg);
if (error == -ENODEV) {
@@ -437,13 +409,30 @@
} else if (error == -EPROBE_DEFER) {
goto err;
} else {
- dev_err(&pdev->dev, "Failed to get regulator\n");
+ dev_err(dev, "Failed to get regulator\n");
goto err;
}
}
+ da8xx_ohci->oc_gpio = devm_gpiod_get_optional(dev, "oc", GPIOD_IN);
+ if (IS_ERR(da8xx_ohci->oc_gpio))
+ goto err;
+
+ if (da8xx_ohci->oc_gpio) {
+ oc_irq = gpiod_to_irq(da8xx_ohci->oc_gpio);
+ if (oc_irq < 0)
+ goto err;
+
+ error = devm_request_threaded_irq(dev, oc_irq, NULL,
+ ohci_da8xx_oc_thread, IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "OHCI over-current indicator", da8xx_ohci);
+ if (error)
+ goto err;
+ }
+
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hcd->regs = devm_ioremap_resource(&pdev->dev, mem);
+ hcd->regs = devm_ioremap_resource(dev, mem);
if (IS_ERR(hcd->regs)) {
error = PTR_ERR(hcd->regs);
goto err;
@@ -451,13 +440,13 @@
hcd->rsrc_start = mem->start;
hcd->rsrc_len = resource_size(mem);
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
+ hcd_irq = platform_get_irq(pdev, 0);
+ if (hcd_irq < 0) {
error = -ENODEV;
goto err;
}
- error = usb_add_hcd(hcd, irq, 0);
+ error = usb_add_hcd(hcd, hcd_irq, 0);
if (error)
goto err;
@@ -480,7 +469,6 @@
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
- ohci_da8xx_unregister_notify(hcd);
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index c0c4dcc..d5ce98e 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -30,7 +30,9 @@
struct exynos_ohci_hcd {
struct clk *clk;
+ struct device_node *of_node;
struct phy *phy[PHY_NUMBER];
+ bool legacy_phy;
};
static int exynos_ohci_get_phy(struct device *dev,
@@ -38,10 +40,22 @@
{
struct device_node *child;
struct phy *phy;
- int phy_number;
+ int phy_number, num_phys;
int ret;
/* Get PHYs for the controller */
+ num_phys = of_count_phandle_with_args(dev->of_node, "phys",
+ "#phy-cells");
+ for (phy_number = 0; phy_number < num_phys; phy_number++) {
+ phy = devm_of_phy_get_by_index(dev, dev->of_node, phy_number);
+ if (IS_ERR(phy))
+ return PTR_ERR(phy);
+ exynos_ohci->phy[phy_number] = phy;
+ }
+ if (num_phys > 0)
+ return 0;
+
+ /* Get PHYs using legacy bindings */
for_each_available_child_of_node(dev->of_node, child) {
ret = of_property_read_u32(child, "reg", &phy_number);
if (ret) {
@@ -72,6 +86,7 @@
}
}
+ exynos_ohci->legacy_phy = true;
return 0;
}
@@ -170,6 +185,14 @@
goto fail_io;
}
+ /*
+ * Workaround: reset of_node pointer to avoid conflict between legacy
+ * Exynos OHCI port subnodes and generic USB device bindings
+ */
+ exynos_ohci->of_node = pdev->dev.of_node;
+ if (exynos_ohci->legacy_phy)
+ pdev->dev.of_node = NULL;
+
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err) {
dev_err(&pdev->dev, "Failed to add USB HCD\n");
@@ -180,6 +203,7 @@
fail_add_hcd:
exynos_ohci_phy_disable(&pdev->dev);
+ pdev->dev.of_node = exynos_ohci->of_node;
fail_io:
clk_disable_unprepare(exynos_ohci->clk);
fail_clk:
@@ -192,6 +216,8 @@
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd);
+ pdev->dev.of_node = exynos_ohci->of_node;
+
usb_remove_hcd(hcd);
exynos_ohci_phy_disable(&pdev->dev);
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 210181f..4de9165 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -40,6 +40,7 @@
#include <linux/dmapool.h>
#include <linux/workqueue.h>
#include <linux/debugfs.h>
+#include <linux/genalloc.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -418,8 +419,7 @@
* other cases where the next software may expect clean state from the
* "firmware". this is bus-neutral, unlike shutdown() methods.
*/
-static void
-ohci_shutdown (struct usb_hcd *hcd)
+static void _ohci_shutdown(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci;
@@ -435,6 +435,16 @@
ohci->rh_state = OHCI_RH_HALTED;
}
+static void ohci_shutdown(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ohci->lock, flags);
+ _ohci_shutdown(hcd);
+ spin_unlock_irqrestore(&ohci->lock, flags);
+}
+
/*-------------------------------------------------------------------------*
* HC functions
*-------------------------------------------------------------------------*/
@@ -447,7 +457,7 @@
struct usb_hcd *hcd = ohci_to_hcd(ohci);
/* Accept arbitrarily long scatter-gather lists */
- if (!(hcd->driver->flags & HCD_LOCAL_MEM))
+ if (!hcd->localmem_pool)
hcd->self.sg_tablesize = ~0;
if (distrust_firmware)
@@ -505,8 +515,15 @@
timer_setup(&ohci->io_watchdog, io_watchdog_func, 0);
ohci->prev_frame_no = IO_WATCHDOG_OFF;
- ohci->hcca = dma_alloc_coherent (hcd->self.controller,
- sizeof(*ohci->hcca), &ohci->hcca_dma, GFP_KERNEL);
+ if (hcd->localmem_pool)
+ ohci->hcca = gen_pool_dma_alloc_align(hcd->localmem_pool,
+ sizeof(*ohci->hcca),
+ &ohci->hcca_dma, 256);
+ else
+ ohci->hcca = dma_alloc_coherent(hcd->self.controller,
+ sizeof(*ohci->hcca),
+ &ohci->hcca_dma,
+ GFP_KERNEL);
if (!ohci->hcca)
return -ENOMEM;
@@ -752,7 +769,7 @@
died:
usb_hc_died(ohci_to_hcd(ohci));
ohci_dump(ohci);
- ohci_shutdown(ohci_to_hcd(ohci));
+ _ohci_shutdown(ohci_to_hcd(ohci));
goto done;
} else {
/* No write back because the done queue was empty */
@@ -990,9 +1007,14 @@
remove_debug_files (ohci);
ohci_mem_cleanup (ohci);
if (ohci->hcca) {
- dma_free_coherent (hcd->self.controller,
- sizeof *ohci->hcca,
- ohci->hcca, ohci->hcca_dma);
+ if (hcd->localmem_pool)
+ gen_pool_free(hcd->localmem_pool,
+ (unsigned long)ohci->hcca,
+ sizeof(*ohci->hcca));
+ else
+ dma_free_coherent(hcd->self.controller,
+ sizeof(*ohci->hcca),
+ ohci->hcca, ohci->hcca_dma);
ohci->hcca = NULL;
ohci->hcca_dma = 0;
}
@@ -1165,7 +1187,7 @@
* generic hardware linkage
*/
.irq = ohci_irq,
- .flags = HCD_MEMORY | HCD_USB11,
+ .flags = HCD_MEMORY | HCD_DMA | HCD_USB11,
/*
* basic lifecycle operations
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
index b3da3f1..1425335 100644
--- a/drivers/usb/host/ohci-mem.c
+++ b/drivers/usb/host/ohci-mem.c
@@ -36,6 +36,13 @@
static int ohci_mem_init (struct ohci_hcd *ohci)
{
+ /*
+ * HCs with local memory allocate from localmem_pool so there's
+ * no need to create the below dma pools.
+ */
+ if (ohci_to_hcd(ohci)->localmem_pool)
+ return 0;
+
ohci->td_cache = dma_pool_create ("ohci_td",
ohci_to_hcd(ohci)->self.controller,
sizeof (struct td),
@@ -57,14 +64,10 @@
static void ohci_mem_cleanup (struct ohci_hcd *ohci)
{
- if (ohci->td_cache) {
- dma_pool_destroy (ohci->td_cache);
- ohci->td_cache = NULL;
- }
- if (ohci->ed_cache) {
- dma_pool_destroy (ohci->ed_cache);
- ohci->ed_cache = NULL;
- }
+ dma_pool_destroy(ohci->td_cache);
+ ohci->td_cache = NULL;
+ dma_pool_destroy(ohci->ed_cache);
+ ohci->ed_cache = NULL;
}
/*-------------------------------------------------------------------------*/
@@ -88,8 +91,13 @@
{
dma_addr_t dma;
struct td *td;
+ struct usb_hcd *hcd = ohci_to_hcd(hc);
- td = dma_pool_zalloc (hc->td_cache, mem_flags, &dma);
+ if (hcd->localmem_pool)
+ td = gen_pool_dma_zalloc_align(hcd->localmem_pool,
+ sizeof(*td), &dma, 32);
+ else
+ td = dma_pool_zalloc(hc->td_cache, mem_flags, &dma);
if (td) {
/* in case hc fetches it, make it look dead */
td->hwNextTD = cpu_to_hc32 (hc, dma);
@@ -103,6 +111,7 @@
td_free (struct ohci_hcd *hc, struct td *td)
{
struct td **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)];
+ struct usb_hcd *hcd = ohci_to_hcd(hc);
while (*prev && *prev != td)
prev = &(*prev)->td_hash;
@@ -110,7 +119,12 @@
*prev = td->td_hash;
else if ((td->hwINFO & cpu_to_hc32(hc, TD_DONE)) != 0)
ohci_dbg (hc, "no hash for td %p\n", td);
- dma_pool_free (hc->td_cache, td, td->td_dma);
+
+ if (hcd->localmem_pool)
+ gen_pool_free(hcd->localmem_pool, (unsigned long)td,
+ sizeof(*td));
+ else
+ dma_pool_free(hc->td_cache, td, td->td_dma);
}
/*-------------------------------------------------------------------------*/
@@ -121,8 +135,13 @@
{
dma_addr_t dma;
struct ed *ed;
+ struct usb_hcd *hcd = ohci_to_hcd(hc);
- ed = dma_pool_zalloc (hc->ed_cache, mem_flags, &dma);
+ if (hcd->localmem_pool)
+ ed = gen_pool_dma_zalloc_align(hcd->localmem_pool,
+ sizeof(*ed), &dma, 16);
+ else
+ ed = dma_pool_zalloc(hc->ed_cache, mem_flags, &dma);
if (ed) {
INIT_LIST_HEAD (&ed->td_list);
ed->dma = dma;
@@ -133,6 +152,12 @@
static void
ed_free (struct ohci_hcd *hc, struct ed *ed)
{
- dma_pool_free (hc->ed_cache, ed, ed->dma);
+ struct usb_hcd *hcd = ohci_to_hcd(hc);
+
+ if (hcd->localmem_pool)
+ gen_pool_free(hcd->localmem_pool, (unsigned long)ed,
+ sizeof(*ed));
+ else
+ dma_pool_free(hc->ed_cache, ed, ed->dma);
}
diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c
index f5f5326..c561881 100644
--- a/drivers/usb/host/ohci-nxp.c
+++ b/drivers/usb/host/ohci-nxp.c
@@ -29,10 +29,7 @@
#include "ohci.h"
-#include <mach/hardware.h>
-
#define USB_CONFIG_BASE 0x31020000
-#define USB_OTG_STAT_CONTROL IO_ADDRESS(USB_CONFIG_BASE + 0x110)
/* USB_OTG_STAT_CONTROL bit defines */
#define TRANSPARENT_I2C_EN (1 << 7)
@@ -122,19 +119,33 @@
static void ohci_nxp_start_hc(void)
{
- unsigned long tmp = __raw_readl(USB_OTG_STAT_CONTROL) | HOST_EN;
+ void __iomem *usb_otg_stat_control = ioremap(USB_CONFIG_BASE + 0x110, 4);
+ unsigned long tmp;
- __raw_writel(tmp, USB_OTG_STAT_CONTROL);
+ if (WARN_ON(!usb_otg_stat_control))
+ return;
+
+ tmp = __raw_readl(usb_otg_stat_control) | HOST_EN;
+
+ __raw_writel(tmp, usb_otg_stat_control);
isp1301_vbus_on();
+
+ iounmap(usb_otg_stat_control);
}
static void ohci_nxp_stop_hc(void)
{
+ void __iomem *usb_otg_stat_control = ioremap(USB_CONFIG_BASE + 0x110, 4);
unsigned long tmp;
+ if (WARN_ON(!usb_otg_stat_control))
+ return;
+
isp1301_vbus_off();
- tmp = __raw_readl(USB_OTG_STAT_CONTROL) & ~HOST_EN;
- __raw_writel(tmp, USB_OTG_STAT_CONTROL);
+ tmp = __raw_readl(usb_otg_stat_control) & ~HOST_EN;
+ __raw_writel(tmp, usb_otg_stat_control);
+
+ iounmap(usb_otg_stat_control);
}
static int ohci_hcd_nxp_probe(struct platform_device *pdev)
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index fbcd349..f4e13a3 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -152,7 +152,7 @@
{
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
- if (usb_amd_find_chipset_info())
+ if (usb_amd_quirk_pll_check())
ohci->flags |= OHCI_QUIRK_AMD_PLL;
/* SB800 needs pre-fetch fix */
@@ -274,7 +274,7 @@
.reset = ohci_pci_reset,
};
-static const struct pci_device_id pci_ids [] = { {
+static const struct pci_device_id pci_ids[] = { {
/* handle any USB OHCI controller */
PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_OHCI, ~0),
.driver_data = (unsigned long) &ohci_pci_hc_driver,
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index 65a1c3f..7addfc2 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -111,10 +111,8 @@
return err;
irq = platform_get_irq(dev, 0);
- if (irq < 0) {
- dev_err(&dev->dev, "no irq provided");
+ if (irq < 0)
return irq;
- }
hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
dev_name(&dev->dev));
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index 76a9b40..45f7cce 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -50,7 +50,7 @@
* generic hardware linkage
*/
.irq = ohci_irq,
- .flags = HCD_USB11 | HCD_MEMORY,
+ .flags = HCD_USB11 | HCD_DMA | HCD_MEMORY,
/*
* basic lifecycle operations
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
index 395f9d3..f77cd6a 100644
--- a/drivers/usb/host/ohci-ps3.c
+++ b/drivers/usb/host/ohci-ps3.c
@@ -46,7 +46,7 @@
.product_desc = "PS3 OHCI Host Controller",
.hcd_priv_size = sizeof(struct ohci_hcd),
.irq = ohci_irq,
- .flags = HCD_MEMORY | HCD_USB11,
+ .flags = HCD_MEMORY | HCD_DMA | HCD_USB11,
.reset = ps3_ohci_hc_reset,
.start = ps3_ohci_hc_start,
.stop = ohci_stop,
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 3e24749..7679fb5 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -148,7 +148,7 @@
uhcrhda |= RH_A_NPS;
break;
case PMM_GLOBAL_MODE:
- uhcrhda &= ~(RH_A_NPS & RH_A_PSM);
+ uhcrhda &= ~(RH_A_NPS | RH_A_PSM);
break;
case PMM_PERPORT_MODE:
uhcrhda &= ~(RH_A_NPS);
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index 4511e27..d961097 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -293,7 +293,6 @@
static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc)
{
struct s3c2410_hcd_port *port;
- struct usb_hcd *hcd;
unsigned long flags;
int portno;
@@ -301,7 +300,6 @@
return;
port = &info->port[0];
- hcd = info->hcd;
local_irq_save(flags);
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index ebec9a7..8e19a5e 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -84,7 +84,7 @@
* generic hardware linkage
*/
.irq = ohci_irq,
- .flags = HCD_USB11 | HCD_MEMORY,
+ .flags = HCD_USB11 | HCD_DMA | HCD_MEMORY,
/*
* basic lifecycle operations
diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c
index c9233cd..c158cda 100644
--- a/drivers/usb/host/ohci-sm501.c
+++ b/drivers/usb/host/ohci-sm501.c
@@ -49,7 +49,7 @@
* generic hardware linkage
*/
.irq = ohci_irq,
- .flags = HCD_USB11 | HCD_MEMORY | HCD_LOCAL_MEM,
+ .flags = HCD_USB11 | HCD_MEMORY,
/*
* basic lifecycle operations
@@ -110,41 +110,18 @@
goto err0;
}
- /* The sm501 chip is equipped with local memory that may be used
- * by on-chip devices such as the video controller and the usb host.
- * This driver uses dma_declare_coherent_memory() to make sure
- * usb allocations with dma_alloc_coherent() allocate from
- * this local memory. The dma_handle returned by dma_alloc_coherent()
- * will be an offset starting from 0 for the first local memory byte.
- *
- * So as long as data is allocated using dma_alloc_coherent() all is
- * fine. This is however not always the case - buffers may be allocated
- * using kmalloc() - so the usb core needs to be told that it must copy
- * data into our local memory if the buffers happen to be placed in
- * regular memory. The HCD_LOCAL_MEM flag does just that.
- */
-
- retval = dma_declare_coherent_memory(dev, mem->start,
- mem->start - mem->parent->start,
- resource_size(mem),
- DMA_MEMORY_EXCLUSIVE);
- if (retval) {
- dev_err(dev, "cannot declare coherent memory\n");
- goto err1;
- }
-
/* allocate, reserve and remap resources for registers */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
dev_err(dev, "no resource definition for registers\n");
retval = -ENOENT;
- goto err2;
+ goto err1;
}
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) {
retval = -ENOMEM;
- goto err2;
+ goto err1;
}
hcd->rsrc_start = res->start;
@@ -165,6 +142,25 @@
ohci_hcd_init(hcd_to_ohci(hcd));
+ /* The sm501 chip is equipped with local memory that may be used
+ * by on-chip devices such as the video controller and the usb host.
+ * This driver uses genalloc so that usb allocations with
+ * gen_pool_dma_alloc() allocate from this local memory. The dma_handle
+ * returned by gen_pool_dma_alloc() will be an offset starting from 0
+ * for the first local memory byte.
+ *
+ * So as long as data is allocated using gen_pool_dma_alloc() all is
+ * fine. This is however not always the case - buffers may be allocated
+ * using kmalloc() - so the usb core needs to be told that it must copy
+ * data into our local memory if the buffers happen to be placed in
+ * regular memory. A non-null hcd->localmem_pool initialized by the
+ * the call to usb_hcd_setup_local_mem() below does just that.
+ */
+
+ if (usb_hcd_setup_local_mem(hcd, mem->start,
+ mem->start - mem->parent->start,
+ resource_size(mem)) < 0)
+ goto err5;
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval)
goto err5;
@@ -182,8 +178,6 @@
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err3:
usb_put_hcd(hcd);
-err2:
- dma_release_declared_memory(dev);
err1:
release_mem_region(mem->start, resource_size(mem));
err0:
@@ -198,7 +192,6 @@
usb_remove_hcd(hcd);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
- dma_release_declared_memory(&pdev->dev);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (mem)
release_mem_region(mem->start, resource_size(mem));
diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c
index 69fa046..5cc0544 100644
--- a/drivers/usb/host/ohci-spear.c
+++ b/drivers/usb/host/ohci-spear.c
@@ -35,7 +35,6 @@
static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)
{
const struct hc_driver *driver = &ohci_spear_hc_driver;
- struct ohci_hcd *ohci;
struct usb_hcd *hcd = NULL;
struct clk *usbh_clk;
struct spear_ohci *sohci_p;
@@ -85,8 +84,6 @@
clk_prepare_enable(sohci_p->clk);
- ohci = hcd_to_ohci(hcd);
-
retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), 0);
if (retval == 0) {
device_wakeup_enable(hcd->self.controller);
diff --git a/drivers/usb/host/ohci-st.c b/drivers/usb/host/ohci-st.c
index 992807c..ac796cc 100644
--- a/drivers/usb/host/ohci-st.c
+++ b/drivers/usb/host/ohci-st.c
@@ -132,17 +132,14 @@
struct resource *res_mem;
struct usb_ohci_pdata *pdata = &ohci_platform_defaults;
struct st_ohci_platform_priv *priv;
- struct ohci_hcd *ohci;
int err, irq, clk = 0;
if (usb_disabled())
return -ENODEV;
irq = platform_get_irq(dev, 0);
- if (irq < 0) {
- dev_err(&dev->dev, "no irq provided");
+ if (irq < 0)
return irq;
- }
res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!res_mem) {
@@ -158,7 +155,6 @@
platform_set_drvdata(dev, hcd);
dev->dev.platform_data = pdata;
priv = hcd_to_ohci_priv(hcd);
- ohci = hcd_to_ohci(hcd);
priv->phy = devm_phy_get(&dev->dev, "usb");
if (IS_ERR(priv->phy)) {
diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c
index a631dbb..fb6f5e9 100644
--- a/drivers/usb/host/ohci-tmio.c
+++ b/drivers/usb/host/ohci-tmio.c
@@ -97,10 +97,13 @@
switch (ohci->num_ports) {
default:
dev_err(&dev->dev, "Unsupported amount of ports: %d\n", ohci->num_ports);
+ /* fall through */
case 3:
pm |= CCR_PM_USBPW3;
+ /* fall through */
case 2:
pm |= CCR_PM_USBPW2;
+ /* fall through */
case 1:
pm |= CCR_PM_USBPW1;
}
@@ -153,7 +156,7 @@
/* generic hardware linkage */
.irq = ohci_irq,
- .flags = HCD_USB11 | HCD_MEMORY | HCD_LOCAL_MEM,
+ .flags = HCD_USB11 | HCD_MEMORY,
/* basic lifecycle operations */
.start = ohci_tmio_start,
@@ -224,11 +227,6 @@
goto err_ioremap_regs;
}
- ret = dma_declare_coherent_memory(&dev->dev, sram->start, sram->start,
- resource_size(sram), DMA_MEMORY_EXCLUSIVE);
- if (ret)
- goto err_dma_declare;
-
if (cell->enable) {
ret = cell->enable(dev);
if (ret)
@@ -239,6 +237,11 @@
ohci = hcd_to_ohci(hcd);
ohci_hcd_init(ohci);
+ ret = usb_hcd_setup_local_mem(hcd, sram->start, sram->start,
+ resource_size(sram));
+ if (ret < 0)
+ goto err_enable;
+
ret = usb_add_hcd(hcd, irq, 0);
if (ret)
goto err_add_hcd;
@@ -254,8 +257,6 @@
if (cell->disable)
cell->disable(dev);
err_enable:
- dma_release_declared_memory(&dev->dev);
-err_dma_declare:
iounmap(hcd->regs);
err_ioremap_regs:
iounmap(tmio->ccr);
@@ -276,7 +277,6 @@
tmio_stop_hc(dev);
if (cell->disable)
cell->disable(dev);
- dma_release_declared_memory(&dev->dev);
iounmap(hcd->regs);
iounmap(tmio->ccr);
usb_put_hcd(hcd);
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index ef4813b..b015b00 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -385,6 +385,8 @@
/*
* memory management for queue data structures
+ *
+ * @td_cache and @ed_cache are %NULL if &usb_hcd.localmem_pool is used.
*/
struct dma_pool *td_cache;
struct dma_pool *ed_cache;
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index c5e6e8d..e67242e 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -31,10 +31,449 @@
#include <linux/irq.h>
#include <linux/platform_device.h>
-#include "oxu210hp.h"
-
#define DRIVER_VERSION "0.0.50"
+#define OXU_DEVICEID 0x00
+ #define OXU_REV_MASK 0xffff0000
+ #define OXU_REV_SHIFT 16
+ #define OXU_REV_2100 0x2100
+ #define OXU_BO_SHIFT 8
+ #define OXU_BO_MASK (0x3 << OXU_BO_SHIFT)
+ #define OXU_MAJ_REV_SHIFT 4
+ #define OXU_MAJ_REV_MASK (0xf << OXU_MAJ_REV_SHIFT)
+ #define OXU_MIN_REV_SHIFT 0
+ #define OXU_MIN_REV_MASK (0xf << OXU_MIN_REV_SHIFT)
+#define OXU_HOSTIFCONFIG 0x04
+#define OXU_SOFTRESET 0x08
+ #define OXU_SRESET (1 << 0)
+
+#define OXU_PIOBURSTREADCTRL 0x0C
+
+#define OXU_CHIPIRQSTATUS 0x10
+#define OXU_CHIPIRQEN_SET 0x14
+#define OXU_CHIPIRQEN_CLR 0x18
+ #define OXU_USBSPHLPWUI 0x00000080
+ #define OXU_USBOTGLPWUI 0x00000040
+ #define OXU_USBSPHI 0x00000002
+ #define OXU_USBOTGI 0x00000001
+
+#define OXU_CLKCTRL_SET 0x1C
+ #define OXU_SYSCLKEN 0x00000008
+ #define OXU_USBSPHCLKEN 0x00000002
+ #define OXU_USBOTGCLKEN 0x00000001
+
+#define OXU_ASO 0x68
+ #define OXU_SPHPOEN 0x00000100
+ #define OXU_OVRCCURPUPDEN 0x00000800
+ #define OXU_ASO_OP (1 << 10)
+ #define OXU_COMPARATOR 0x000004000
+
+#define OXU_USBMODE 0x1A8
+ #define OXU_VBPS 0x00000020
+ #define OXU_ES_LITTLE 0x00000000
+ #define OXU_CM_HOST_ONLY 0x00000003
+
+/*
+ * Proper EHCI structs & defines
+ */
+
+/* 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 */
+
+struct oxu_hcd;
+
+/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
+
+/* Section 2.2 Host Controller Capability Registers */
+struct ehci_caps {
+ /* these fields are specified as 8 and 16 bit registers,
+ * but some hosts can't perform 8 or 16 bit PCI accesses.
+ */
+ u32 hc_capbase;
+#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */
+#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */
+ u32 hcs_params; /* HCSPARAMS - offset 0x4 */
+#define HCS_DEBUG_PORT(p) (((p)>>20)&0xf) /* bits 23:20, debug port? */
+#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
+#define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
+#define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */
+#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */
+#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
+#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
+
+ u32 hcc_params; /* HCCPARAMS - offset 0x8 */
+#define HCC_EXT_CAPS(p) (((p)>>8)&0xff) /* for pci extended caps */
+#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */
+#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */
+#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */
+#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/
+#define HCC_64BIT_ADDR(p) ((p)&(1)) /* true: can use 64-bit addr */
+ u8 portroute[8]; /* nibbles for routing - offset 0xC */
+} __packed;
+
+
+/* Section 2.3 Host Controller Operational Registers */
+struct ehci_regs {
+ /* USBCMD: offset 0x00 */
+ u32 command;
+/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
+#define CMD_PARK (1<<11) /* enable "park" on async qh */
+#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */
+#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
+#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */
+#define CMD_ASE (1<<5) /* async schedule enable */
+#define CMD_PSE (1<<4) /* periodic schedule enable */
+/* 3:2 is periodic frame list size */
+#define CMD_RESET (1<<1) /* reset HC not bus */
+#define CMD_RUN (1<<0) /* start/stop HC */
+
+ /* USBSTS: offset 0x04 */
+ u32 status;
+#define STS_ASS (1<<15) /* Async Schedule Status */
+#define STS_PSS (1<<14) /* Periodic Schedule Status */
+#define STS_RECL (1<<13) /* Reclamation */
+#define STS_HALT (1<<12) /* Not running (any reason) */
+/* some bits reserved */
+ /* these STS_* flags are also intr_enable bits (USBINTR) */
+#define STS_IAA (1<<5) /* Interrupted on async advance */
+#define STS_FATAL (1<<4) /* such as some PCI access errors */
+#define STS_FLR (1<<3) /* frame list rolled over */
+#define STS_PCD (1<<2) /* port change detect */
+#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */
+#define STS_INT (1<<0) /* "normal" completion (short, ...) */
+
+#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
+
+ /* USBINTR: offset 0x08 */
+ u32 intr_enable;
+
+ /* FRINDEX: offset 0x0C */
+ u32 frame_index; /* current microframe number */
+ /* CTRLDSSEGMENT: offset 0x10 */
+ u32 segment; /* address bits 63:32 if needed */
+ /* PERIODICLISTBASE: offset 0x14 */
+ u32 frame_list; /* points to periodic list */
+ /* ASYNCLISTADDR: offset 0x18 */
+ u32 async_next; /* address of next async queue head */
+
+ u32 reserved[9];
+
+ /* CONFIGFLAG: offset 0x40 */
+ u32 configured_flag;
+#define FLAG_CF (1<<0) /* true: we'll support "high speed" */
+
+ /* PORTSC: offset 0x44 */
+ u32 port_status[0]; /* up to N_PORTS */
+/* 31:23 reserved */
+#define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */
+#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */
+#define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */
+/* 19:16 for port testing */
+#define PORT_LED_OFF (0<<14)
+#define PORT_LED_AMBER (1<<14)
+#define PORT_LED_GREEN (2<<14)
+#define PORT_LED_MASK (3<<14)
+#define PORT_OWNER (1<<13) /* true: companion hc owns this port */
+#define PORT_POWER (1<<12) /* true: has power (see PPC) */
+#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10)) /* USB 1.1 device */
+/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
+/* 9 reserved */
+#define PORT_RESET (1<<8) /* reset port */
+#define PORT_SUSPEND (1<<7) /* suspend port */
+#define PORT_RESUME (1<<6) /* resume it */
+#define PORT_OCC (1<<5) /* over current change */
+#define PORT_OC (1<<4) /* over current active */
+#define PORT_PEC (1<<3) /* port enable change */
+#define PORT_PE (1<<2) /* port enable */
+#define PORT_CSC (1<<1) /* connect status change */
+#define PORT_CONNECT (1<<0) /* device connected */
+#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
+} __packed;
+
+/* Appendix C, Debug port ... intended for use with special "debug devices"
+ * that can help if there's no serial console. (nonstandard enumeration.)
+ */
+struct ehci_dbg_port {
+ u32 control;
+#define DBGP_OWNER (1<<30)
+#define DBGP_ENABLED (1<<28)
+#define DBGP_DONE (1<<16)
+#define DBGP_INUSE (1<<10)
+#define DBGP_ERRCODE(x) (((x)>>7)&0x07)
+# define DBGP_ERR_BAD 1
+# define DBGP_ERR_SIGNAL 2
+#define DBGP_ERROR (1<<6)
+#define DBGP_GO (1<<5)
+#define DBGP_OUT (1<<4)
+#define DBGP_LEN(x) (((x)>>0)&0x0f)
+ u32 pids;
+#define DBGP_PID_GET(x) (((x)>>16)&0xff)
+#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok))
+ u32 data03;
+ u32 data47;
+ u32 address;
+#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep))
+} __packed;
+
+#define QTD_NEXT(dma) cpu_to_le32((u32)dma)
+
+/*
+ * EHCI Specification 0.95 Section 3.5
+ * QTD: describe data transfer components (buffer, direction, ...)
+ * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
+ *
+ * These are associated only with "QH" (Queue Head) structures,
+ * used with control, bulk, and interrupt transfers.
+ */
+struct ehci_qtd {
+ /* first part defined by EHCI spec */
+ __le32 hw_next; /* see EHCI 3.5.1 */
+ __le32 hw_alt_next; /* see EHCI 3.5.2 */
+ __le32 hw_token; /* see EHCI 3.5.3 */
+#define QTD_TOGGLE (1 << 31) /* data toggle */
+#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
+#define QTD_IOC (1 << 15) /* interrupt on complete */
+#define QTD_CERR(tok) (((tok)>>10) & 0x3)
+#define QTD_PID(tok) (((tok)>>8) & 0x3)
+#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */
+#define QTD_STS_HALT (1 << 6) /* halted on error */
+#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */
+#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */
+#define QTD_STS_XACT (1 << 3) /* device gave illegal response */
+#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */
+#define QTD_STS_STS (1 << 1) /* split transaction state */
+#define QTD_STS_PING (1 << 0) /* issue PING? */
+ __le32 hw_buf[5]; /* see EHCI 3.5.4 */
+ __le32 hw_buf_hi[5]; /* Appendix B */
+
+ /* the rest is HCD-private */
+ dma_addr_t qtd_dma; /* qtd address */
+ struct list_head qtd_list; /* sw qtd list */
+ struct urb *urb; /* qtd's urb */
+ size_t length; /* length of buffer */
+
+ u32 qtd_buffer_len;
+ void *buffer;
+ dma_addr_t buffer_dma;
+ void *transfer_buffer;
+ void *transfer_dma;
+} __aligned(32);
+
+/* mask NakCnt+T in qh->hw_alt_next */
+#define QTD_MASK cpu_to_le32 (~0x1f)
+
+#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1)
+
+/* Type tag from {qh, itd, sitd, fstn}->hw_next */
+#define Q_NEXT_TYPE(dma) ((dma) & cpu_to_le32 (3 << 1))
+
+/* values for that type tag */
+#define Q_TYPE_QH cpu_to_le32 (1 << 1)
+
+/* next async queue entry, or pointer to interrupt/periodic QH */
+#define QH_NEXT(dma) (cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH)
+
+/* for periodic/async schedules and qtd lists, mark end of list */
+#define EHCI_LIST_END cpu_to_le32(1) /* "null pointer" to hw */
+
+/*
+ * Entries in periodic shadow table are pointers to one of four kinds
+ * of data structure. That's dictated by the hardware; a type tag is
+ * encoded in the low bits of the hardware's periodic schedule. Use
+ * Q_NEXT_TYPE to get the tag.
+ *
+ * For entries in the async schedule, the type tag always says "qh".
+ */
+union ehci_shadow {
+ struct ehci_qh *qh; /* Q_TYPE_QH */
+ __le32 *hw_next; /* (all types) */
+ void *ptr;
+};
+
+/*
+ * EHCI Specification 0.95 Section 3.6
+ * QH: describes control/bulk/interrupt endpoints
+ * See Fig 3-7 "Queue Head Structure Layout".
+ *
+ * These appear in both the async and (for interrupt) periodic schedules.
+ */
+
+struct ehci_qh {
+ /* first part defined by EHCI spec */
+ __le32 hw_next; /* see EHCI 3.6.1 */
+ __le32 hw_info1; /* see EHCI 3.6.2 */
+#define QH_HEAD 0x00008000
+ __le32 hw_info2; /* see EHCI 3.6.2 */
+#define QH_SMASK 0x000000ff
+#define QH_CMASK 0x0000ff00
+#define QH_HUBADDR 0x007f0000
+#define QH_HUBPORT 0x3f800000
+#define QH_MULT 0xc0000000
+ __le32 hw_current; /* qtd list - see EHCI 3.6.4 */
+
+ /* qtd overlay (hardware parts of a struct ehci_qtd) */
+ __le32 hw_qtd_next;
+ __le32 hw_alt_next;
+ __le32 hw_token;
+ __le32 hw_buf[5];
+ __le32 hw_buf_hi[5];
+
+ /* the rest is HCD-private */
+ dma_addr_t qh_dma; /* address of qh */
+ union ehci_shadow qh_next; /* ptr to qh; or periodic */
+ struct list_head qtd_list; /* sw qtd list */
+ struct ehci_qtd *dummy;
+ struct ehci_qh *reclaim; /* next to reclaim */
+
+ struct oxu_hcd *oxu;
+ struct kref kref;
+ unsigned int stamp;
+
+ u8 qh_state;
+#define QH_STATE_LINKED 1 /* HC sees this */
+#define QH_STATE_UNLINK 2 /* HC may still see this */
+#define QH_STATE_IDLE 3 /* HC doesn't see this */
+#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on reclaim q */
+#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */
+
+ /* periodic schedule info */
+ u8 usecs; /* intr bandwidth */
+ u8 gap_uf; /* uframes split/csplit gap */
+ u8 c_usecs; /* ... split completion bw */
+ u16 tt_usecs; /* tt downstream bandwidth */
+ unsigned short period; /* polling interval */
+ unsigned short start; /* where polling starts */
+#define NO_FRAME ((unsigned short)~0) /* pick new start */
+ struct usb_device *dev; /* access to TT */
+} __aligned(32);
+
+/*
+ * Proper OXU210HP structs
+ */
+
+#define OXU_OTG_CORE_OFFSET 0x00400
+#define OXU_OTG_CAP_OFFSET (OXU_OTG_CORE_OFFSET + 0x100)
+#define OXU_SPH_CORE_OFFSET 0x00800
+#define OXU_SPH_CAP_OFFSET (OXU_SPH_CORE_OFFSET + 0x100)
+
+#define OXU_OTG_MEM 0xE000
+#define OXU_SPH_MEM 0x16000
+
+/* Only how many elements & element structure are specifies here. */
+/* 2 host controllers are enabled - total size <= 28 kbytes */
+#define DEFAULT_I_TDPS 1024
+#define QHEAD_NUM 16
+#define QTD_NUM 32
+#define SITD_NUM 8
+#define MURB_NUM 8
+
+#define BUFFER_NUM 8
+#define BUFFER_SIZE 512
+
+struct oxu_info {
+ struct usb_hcd *hcd[2];
+};
+
+struct oxu_buf {
+ u8 buffer[BUFFER_SIZE];
+} __aligned(BUFFER_SIZE);
+
+struct oxu_onchip_mem {
+ struct oxu_buf db_pool[BUFFER_NUM];
+
+ u32 frame_list[DEFAULT_I_TDPS];
+ struct ehci_qh qh_pool[QHEAD_NUM];
+ struct ehci_qtd qtd_pool[QTD_NUM];
+} __aligned(4 << 10);
+
+#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */
+
+struct oxu_murb {
+ struct urb urb;
+ struct urb *main;
+ u8 last;
+};
+
+struct oxu_hcd { /* one per controller */
+ unsigned int is_otg:1;
+
+ u8 qh_used[QHEAD_NUM];
+ u8 qtd_used[QTD_NUM];
+ u8 db_used[BUFFER_NUM];
+ u8 murb_used[MURB_NUM];
+
+ struct oxu_onchip_mem __iomem *mem;
+ spinlock_t mem_lock;
+
+ struct timer_list urb_timer;
+
+ struct ehci_caps __iomem *caps;
+ struct ehci_regs __iomem *regs;
+
+ u32 hcs_params; /* cached register copy */
+ spinlock_t lock;
+
+ /* async schedule support */
+ struct ehci_qh *async;
+ struct ehci_qh *reclaim;
+ unsigned int reclaim_ready:1;
+ unsigned int scanning:1;
+
+ /* periodic schedule support */
+ unsigned int periodic_size;
+ __le32 *periodic; /* hw periodic table */
+ dma_addr_t periodic_dma;
+ unsigned int i_thresh; /* uframes HC might cache */
+
+ union ehci_shadow *pshadow; /* mirror hw periodic table */
+ int next_uframe; /* scan periodic, start here */
+ unsigned int periodic_sched; /* periodic activity count */
+
+ /* per root hub port */
+ unsigned long reset_done[EHCI_MAX_ROOT_PORTS];
+ /* bit vectors (one bit per port) */
+ unsigned long bus_suspended; /* which ports were
+ * already suspended at the
+ * start of a bus suspend
+ */
+ unsigned long companion_ports;/* which ports are dedicated
+ * to the companion controller
+ */
+
+ struct timer_list watchdog;
+ unsigned long actions;
+ unsigned int stamp;
+ unsigned long next_statechange;
+ u32 command;
+
+ /* SILICON QUIRKS */
+ struct list_head urb_list; /* this is the head to urb
+ * queue that didn't get enough
+ * resources
+ */
+ struct oxu_murb *murb_pool; /* murb per split big urb */
+ unsigned int urb_len;
+
+ u8 sbrn; /* packed release number */
+};
+
+#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */
+#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
+#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
+#define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */
+
+enum ehci_timer_action {
+ TIMER_IO_WATCHDOG,
+ TIMER_IAA_WATCHDOG,
+ TIMER_ASYNC_SHRINK,
+ TIMER_ASYNC_OFF,
+};
+
/*
* Main defines
*/
@@ -1323,7 +1762,7 @@
}
/* by default, enable interrupt on urb completion */
- qtd->hw_token |= cpu_to_le32(QTD_IOC);
+ qtd->hw_token |= cpu_to_le32(QTD_IOC);
return head;
cleanup:
@@ -2253,16 +2692,12 @@
for (;;) {
union ehci_shadow q, *q_p;
__le32 type, *hw_p;
- unsigned uframes;
/* don't scan past the live uframe */
frame = now_uframe >> 3;
- if (frame == (clock >> 3))
- uframes = now_uframe & 0x07;
- else {
+ if (frame != (clock >> 3)) {
/* safe to scan the whole frame at once */
now_uframe |= 0x07;
- uframes = 8;
}
restart:
@@ -2653,9 +3088,6 @@
INIT_LIST_HEAD(&oxu->urb_list);
oxu->urb_len = 0;
- /* FIMXE */
- hcd->self.controller->dma_mask = NULL;
-
if (oxu->is_otg) {
oxu->caps = hcd->regs + OXU_OTG_CAP_OFFSET;
oxu->regs = hcd->regs + OXU_OTG_CAP_OFFSET + \
@@ -2832,7 +3264,6 @@
{
struct oxu_hcd *oxu = hcd_to_oxu(hcd);
int num, rem;
- int transfer_buffer_length;
void *transfer_buffer;
struct urb *murb;
int i, ret;
@@ -2843,7 +3274,6 @@
/* Otherwise we should verify the USB transfer buffer size! */
transfer_buffer = urb->transfer_buffer;
- transfer_buffer_length = urb->transfer_buffer_length;
num = urb->transfer_buffer_length / 4096;
rem = urb->transfer_buffer_length % 4096;
diff --git a/drivers/usb/host/oxu210hp.h b/drivers/usb/host/oxu210hp.h
deleted file mode 100644
index 4370441..0000000
--- a/drivers/usb/host/oxu210hp.h
+++ /dev/null
@@ -1,448 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Host interface registers
- */
-
-#define OXU_DEVICEID 0x00
- #define OXU_REV_MASK 0xffff0000
- #define OXU_REV_SHIFT 16
- #define OXU_REV_2100 0x2100
- #define OXU_BO_SHIFT 8
- #define OXU_BO_MASK (0x3 << OXU_BO_SHIFT)
- #define OXU_MAJ_REV_SHIFT 4
- #define OXU_MAJ_REV_MASK (0xf << OXU_MAJ_REV_SHIFT)
- #define OXU_MIN_REV_SHIFT 0
- #define OXU_MIN_REV_MASK (0xf << OXU_MIN_REV_SHIFT)
-#define OXU_HOSTIFCONFIG 0x04
-#define OXU_SOFTRESET 0x08
- #define OXU_SRESET (1 << 0)
-
-#define OXU_PIOBURSTREADCTRL 0x0C
-
-#define OXU_CHIPIRQSTATUS 0x10
-#define OXU_CHIPIRQEN_SET 0x14
-#define OXU_CHIPIRQEN_CLR 0x18
- #define OXU_USBSPHLPWUI 0x00000080
- #define OXU_USBOTGLPWUI 0x00000040
- #define OXU_USBSPHI 0x00000002
- #define OXU_USBOTGI 0x00000001
-
-#define OXU_CLKCTRL_SET 0x1C
- #define OXU_SYSCLKEN 0x00000008
- #define OXU_USBSPHCLKEN 0x00000002
- #define OXU_USBOTGCLKEN 0x00000001
-
-#define OXU_ASO 0x68
- #define OXU_SPHPOEN 0x00000100
- #define OXU_OVRCCURPUPDEN 0x00000800
- #define OXU_ASO_OP (1 << 10)
- #define OXU_COMPARATOR 0x000004000
-
-#define OXU_USBMODE 0x1A8
- #define OXU_VBPS 0x00000020
- #define OXU_ES_LITTLE 0x00000000
- #define OXU_CM_HOST_ONLY 0x00000003
-
-/*
- * Proper EHCI structs & defines
- */
-
-/* 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 */
-
-struct oxu_hcd;
-
-/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
-
-/* Section 2.2 Host Controller Capability Registers */
-struct ehci_caps {
- /* these fields are specified as 8 and 16 bit registers,
- * but some hosts can't perform 8 or 16 bit PCI accesses.
- */
- u32 hc_capbase;
-#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */
-#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */
- u32 hcs_params; /* HCSPARAMS - offset 0x4 */
-#define HCS_DEBUG_PORT(p) (((p)>>20)&0xf) /* bits 23:20, debug port? */
-#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
-#define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
-#define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */
-#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */
-#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
-#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
-
- u32 hcc_params; /* HCCPARAMS - offset 0x8 */
-#define HCC_EXT_CAPS(p) (((p)>>8)&0xff) /* for pci extended caps */
-#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */
-#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */
-#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */
-#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/
-#define HCC_64BIT_ADDR(p) ((p)&(1)) /* true: can use 64-bit addr */
- u8 portroute[8]; /* nibbles for routing - offset 0xC */
-} __attribute__ ((packed));
-
-
-/* Section 2.3 Host Controller Operational Registers */
-struct ehci_regs {
- /* USBCMD: offset 0x00 */
- u32 command;
-/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
-#define CMD_PARK (1<<11) /* enable "park" on async qh */
-#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */
-#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
-#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */
-#define CMD_ASE (1<<5) /* async schedule enable */
-#define CMD_PSE (1<<4) /* periodic schedule enable */
-/* 3:2 is periodic frame list size */
-#define CMD_RESET (1<<1) /* reset HC not bus */
-#define CMD_RUN (1<<0) /* start/stop HC */
-
- /* USBSTS: offset 0x04 */
- u32 status;
-#define STS_ASS (1<<15) /* Async Schedule Status */
-#define STS_PSS (1<<14) /* Periodic Schedule Status */
-#define STS_RECL (1<<13) /* Reclamation */
-#define STS_HALT (1<<12) /* Not running (any reason) */
-/* some bits reserved */
- /* these STS_* flags are also intr_enable bits (USBINTR) */
-#define STS_IAA (1<<5) /* Interrupted on async advance */
-#define STS_FATAL (1<<4) /* such as some PCI access errors */
-#define STS_FLR (1<<3) /* frame list rolled over */
-#define STS_PCD (1<<2) /* port change detect */
-#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */
-#define STS_INT (1<<0) /* "normal" completion (short, ...) */
-
-#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
-
- /* USBINTR: offset 0x08 */
- u32 intr_enable;
-
- /* FRINDEX: offset 0x0C */
- u32 frame_index; /* current microframe number */
- /* CTRLDSSEGMENT: offset 0x10 */
- u32 segment; /* address bits 63:32 if needed */
- /* PERIODICLISTBASE: offset 0x14 */
- u32 frame_list; /* points to periodic list */
- /* ASYNCLISTADDR: offset 0x18 */
- u32 async_next; /* address of next async queue head */
-
- u32 reserved[9];
-
- /* CONFIGFLAG: offset 0x40 */
- u32 configured_flag;
-#define FLAG_CF (1<<0) /* true: we'll support "high speed" */
-
- /* PORTSC: offset 0x44 */
- u32 port_status[0]; /* up to N_PORTS */
-/* 31:23 reserved */
-#define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */
-#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */
-#define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */
-/* 19:16 for port testing */
-#define PORT_LED_OFF (0<<14)
-#define PORT_LED_AMBER (1<<14)
-#define PORT_LED_GREEN (2<<14)
-#define PORT_LED_MASK (3<<14)
-#define PORT_OWNER (1<<13) /* true: companion hc owns this port */
-#define PORT_POWER (1<<12) /* true: has power (see PPC) */
-#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10)) /* USB 1.1 device */
-/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
-/* 9 reserved */
-#define PORT_RESET (1<<8) /* reset port */
-#define PORT_SUSPEND (1<<7) /* suspend port */
-#define PORT_RESUME (1<<6) /* resume it */
-#define PORT_OCC (1<<5) /* over current change */
-#define PORT_OC (1<<4) /* over current active */
-#define PORT_PEC (1<<3) /* port enable change */
-#define PORT_PE (1<<2) /* port enable */
-#define PORT_CSC (1<<1) /* connect status change */
-#define PORT_CONNECT (1<<0) /* device connected */
-#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
-} __attribute__ ((packed));
-
-/* Appendix C, Debug port ... intended for use with special "debug devices"
- * that can help if there's no serial console. (nonstandard enumeration.)
- */
-struct ehci_dbg_port {
- u32 control;
-#define DBGP_OWNER (1<<30)
-#define DBGP_ENABLED (1<<28)
-#define DBGP_DONE (1<<16)
-#define DBGP_INUSE (1<<10)
-#define DBGP_ERRCODE(x) (((x)>>7)&0x07)
-# define DBGP_ERR_BAD 1
-# define DBGP_ERR_SIGNAL 2
-#define DBGP_ERROR (1<<6)
-#define DBGP_GO (1<<5)
-#define DBGP_OUT (1<<4)
-#define DBGP_LEN(x) (((x)>>0)&0x0f)
- u32 pids;
-#define DBGP_PID_GET(x) (((x)>>16)&0xff)
-#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok))
- u32 data03;
- u32 data47;
- u32 address;
-#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep))
-} __attribute__ ((packed));
-
-
-#define QTD_NEXT(dma) cpu_to_le32((u32)dma)
-
-/*
- * EHCI Specification 0.95 Section 3.5
- * QTD: describe data transfer components (buffer, direction, ...)
- * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
- *
- * These are associated only with "QH" (Queue Head) structures,
- * used with control, bulk, and interrupt transfers.
- */
-struct ehci_qtd {
- /* first part defined by EHCI spec */
- __le32 hw_next; /* see EHCI 3.5.1 */
- __le32 hw_alt_next; /* see EHCI 3.5.2 */
- __le32 hw_token; /* see EHCI 3.5.3 */
-#define QTD_TOGGLE (1 << 31) /* data toggle */
-#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
-#define QTD_IOC (1 << 15) /* interrupt on complete */
-#define QTD_CERR(tok) (((tok)>>10) & 0x3)
-#define QTD_PID(tok) (((tok)>>8) & 0x3)
-#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */
-#define QTD_STS_HALT (1 << 6) /* halted on error */
-#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */
-#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */
-#define QTD_STS_XACT (1 << 3) /* device gave illegal response */
-#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */
-#define QTD_STS_STS (1 << 1) /* split transaction state */
-#define QTD_STS_PING (1 << 0) /* issue PING? */
- __le32 hw_buf[5]; /* see EHCI 3.5.4 */
- __le32 hw_buf_hi[5]; /* Appendix B */
-
- /* the rest is HCD-private */
- dma_addr_t qtd_dma; /* qtd address */
- struct list_head qtd_list; /* sw qtd list */
- struct urb *urb; /* qtd's urb */
- size_t length; /* length of buffer */
-
- u32 qtd_buffer_len;
- void *buffer;
- dma_addr_t buffer_dma;
- void *transfer_buffer;
- void *transfer_dma;
-} __attribute__ ((aligned(32)));
-
-/* mask NakCnt+T in qh->hw_alt_next */
-#define QTD_MASK cpu_to_le32 (~0x1f)
-
-#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1)
-
-/* Type tag from {qh, itd, sitd, fstn}->hw_next */
-#define Q_NEXT_TYPE(dma) ((dma) & cpu_to_le32 (3 << 1))
-
-/* values for that type tag */
-#define Q_TYPE_QH cpu_to_le32 (1 << 1)
-
-/* next async queue entry, or pointer to interrupt/periodic QH */
-#define QH_NEXT(dma) (cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH)
-
-/* for periodic/async schedules and qtd lists, mark end of list */
-#define EHCI_LIST_END cpu_to_le32(1) /* "null pointer" to hw */
-
-/*
- * Entries in periodic shadow table are pointers to one of four kinds
- * of data structure. That's dictated by the hardware; a type tag is
- * encoded in the low bits of the hardware's periodic schedule. Use
- * Q_NEXT_TYPE to get the tag.
- *
- * For entries in the async schedule, the type tag always says "qh".
- */
-union ehci_shadow {
- struct ehci_qh *qh; /* Q_TYPE_QH */
- __le32 *hw_next; /* (all types) */
- void *ptr;
-};
-
-/*
- * EHCI Specification 0.95 Section 3.6
- * QH: describes control/bulk/interrupt endpoints
- * See Fig 3-7 "Queue Head Structure Layout".
- *
- * These appear in both the async and (for interrupt) periodic schedules.
- */
-
-struct ehci_qh {
- /* first part defined by EHCI spec */
- __le32 hw_next; /* see EHCI 3.6.1 */
- __le32 hw_info1; /* see EHCI 3.6.2 */
-#define QH_HEAD 0x00008000
- __le32 hw_info2; /* see EHCI 3.6.2 */
-#define QH_SMASK 0x000000ff
-#define QH_CMASK 0x0000ff00
-#define QH_HUBADDR 0x007f0000
-#define QH_HUBPORT 0x3f800000
-#define QH_MULT 0xc0000000
- __le32 hw_current; /* qtd list - see EHCI 3.6.4 */
-
- /* qtd overlay (hardware parts of a struct ehci_qtd) */
- __le32 hw_qtd_next;
- __le32 hw_alt_next;
- __le32 hw_token;
- __le32 hw_buf[5];
- __le32 hw_buf_hi[5];
-
- /* the rest is HCD-private */
- dma_addr_t qh_dma; /* address of qh */
- union ehci_shadow qh_next; /* ptr to qh; or periodic */
- struct list_head qtd_list; /* sw qtd list */
- struct ehci_qtd *dummy;
- struct ehci_qh *reclaim; /* next to reclaim */
-
- struct oxu_hcd *oxu;
- struct kref kref;
- unsigned stamp;
-
- u8 qh_state;
-#define QH_STATE_LINKED 1 /* HC sees this */
-#define QH_STATE_UNLINK 2 /* HC may still see this */
-#define QH_STATE_IDLE 3 /* HC doesn't see this */
-#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on reclaim q */
-#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */
-
- /* periodic schedule info */
- u8 usecs; /* intr bandwidth */
- u8 gap_uf; /* uframes split/csplit gap */
- u8 c_usecs; /* ... split completion bw */
- u16 tt_usecs; /* tt downstream bandwidth */
- unsigned short period; /* polling interval */
- unsigned short start; /* where polling starts */
-#define NO_FRAME ((unsigned short)~0) /* pick new start */
- struct usb_device *dev; /* access to TT */
-} __attribute__ ((aligned(32)));
-
-/*
- * Proper OXU210HP structs
- */
-
-#define OXU_OTG_CORE_OFFSET 0x00400
-#define OXU_OTG_CAP_OFFSET (OXU_OTG_CORE_OFFSET + 0x100)
-#define OXU_SPH_CORE_OFFSET 0x00800
-#define OXU_SPH_CAP_OFFSET (OXU_SPH_CORE_OFFSET + 0x100)
-
-#define OXU_OTG_MEM 0xE000
-#define OXU_SPH_MEM 0x16000
-
-/* Only how many elements & element structure are specifies here. */
-/* 2 host controllers are enabled - total size <= 28 kbytes */
-#define DEFAULT_I_TDPS 1024
-#define QHEAD_NUM 16
-#define QTD_NUM 32
-#define SITD_NUM 8
-#define MURB_NUM 8
-
-#define BUFFER_NUM 8
-#define BUFFER_SIZE 512
-
-struct oxu_info {
- struct usb_hcd *hcd[2];
-};
-
-struct oxu_buf {
- u8 buffer[BUFFER_SIZE];
-} __attribute__ ((aligned(BUFFER_SIZE)));
-
-struct oxu_onchip_mem {
- struct oxu_buf db_pool[BUFFER_NUM];
-
- u32 frame_list[DEFAULT_I_TDPS];
- struct ehci_qh qh_pool[QHEAD_NUM];
- struct ehci_qtd qtd_pool[QTD_NUM];
-} __attribute__ ((aligned(4 << 10)));
-
-#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */
-
-struct oxu_murb {
- struct urb urb;
- struct urb *main;
- u8 last;
-};
-
-struct oxu_hcd { /* one per controller */
- unsigned int is_otg:1;
-
- u8 qh_used[QHEAD_NUM];
- u8 qtd_used[QTD_NUM];
- u8 db_used[BUFFER_NUM];
- u8 murb_used[MURB_NUM];
-
- struct oxu_onchip_mem __iomem *mem;
- spinlock_t mem_lock;
-
- struct timer_list urb_timer;
-
- struct ehci_caps __iomem *caps;
- struct ehci_regs __iomem *regs;
-
- __u32 hcs_params; /* cached register copy */
- spinlock_t lock;
-
- /* async schedule support */
- struct ehci_qh *async;
- struct ehci_qh *reclaim;
- unsigned reclaim_ready:1;
- unsigned scanning:1;
-
- /* periodic schedule support */
- unsigned periodic_size;
- __le32 *periodic; /* hw periodic table */
- dma_addr_t periodic_dma;
- unsigned i_thresh; /* uframes HC might cache */
-
- union ehci_shadow *pshadow; /* mirror hw periodic table */
- int next_uframe; /* scan periodic, start here */
- unsigned periodic_sched; /* periodic activity count */
-
- /* per root hub port */
- unsigned long reset_done[EHCI_MAX_ROOT_PORTS];
- /* bit vectors (one bit per port) */
- unsigned long bus_suspended; /* which ports were
- * already suspended at the
- * start of a bus suspend
- */
- unsigned long companion_ports;/* which ports are dedicated
- * to the companion controller
- */
-
- struct timer_list watchdog;
- unsigned long actions;
- unsigned stamp;
- unsigned long next_statechange;
- u32 command;
-
- /* SILICON QUIRKS */
- struct list_head urb_list; /* this is the head to urb
- * queue that didn't get enough
- * resources
- */
- struct oxu_murb *murb_pool; /* murb per split big urb */
- unsigned urb_len;
-
- u8 sbrn; /* packed release number */
-};
-
-#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */
-#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
-#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
-#define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */
-
-enum ehci_timer_action {
- TIMER_IO_WATCHDOG,
- TIMER_IAA_WATCHDOG,
- TIMER_ASYNC_SHRINK,
- TIMER_ASYNC_OFF,
-};
-
-#include <linux/oxu210hp.h>
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 3625a5c..f6d0449 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -132,7 +132,7 @@
struct amd_chipset_type sb_type;
int isoc_reqs;
int probe_count;
- int probe_result;
+ bool need_pll_quirk;
} amd_chipset;
static DEFINE_SPINLOCK(amd_lock);
@@ -201,11 +201,11 @@
}
EXPORT_SYMBOL_GPL(sb800_prefetch);
-int usb_amd_find_chipset_info(void)
+static void usb_amd_find_chipset_info(void)
{
unsigned long flags;
struct amd_chipset_info info;
- int ret;
+ info.need_pll_quirk = 0;
spin_lock_irqsave(&amd_lock, flags);
@@ -213,27 +213,34 @@
if (amd_chipset.probe_count > 0) {
amd_chipset.probe_count++;
spin_unlock_irqrestore(&amd_lock, flags);
- return amd_chipset.probe_result;
+ return;
}
memset(&info, 0, sizeof(info));
spin_unlock_irqrestore(&amd_lock, flags);
if (!amd_chipset_sb_type_init(&info)) {
- ret = 0;
goto commit;
}
- /* Below chipset generations needn't enable AMD PLL quirk */
- if (info.sb_type.gen == AMD_CHIPSET_UNKNOWN ||
- info.sb_type.gen == AMD_CHIPSET_SB600 ||
- info.sb_type.gen == AMD_CHIPSET_YANGTZE ||
- (info.sb_type.gen == AMD_CHIPSET_SB700 &&
- info.sb_type.rev > 0x3b)) {
+ switch (info.sb_type.gen) {
+ case AMD_CHIPSET_SB700:
+ info.need_pll_quirk = info.sb_type.rev <= 0x3B;
+ break;
+ case AMD_CHIPSET_SB800:
+ case AMD_CHIPSET_HUDSON2:
+ case AMD_CHIPSET_BOLTON:
+ info.need_pll_quirk = 1;
+ break;
+ default:
+ info.need_pll_quirk = 0;
+ break;
+ }
+
+ if (!info.need_pll_quirk) {
if (info.smbus_dev) {
pci_dev_put(info.smbus_dev);
info.smbus_dev = NULL;
}
- ret = 0;
goto commit;
}
@@ -252,7 +259,6 @@
}
}
- ret = info.probe_result = 1;
printk(KERN_DEBUG "QUIRK: Enable AMD PLL fix\n");
commit:
@@ -263,7 +269,6 @@
/* Mark that we where here */
amd_chipset.probe_count++;
- ret = amd_chipset.probe_result;
spin_unlock_irqrestore(&amd_lock, flags);
@@ -276,10 +281,7 @@
amd_chipset = info;
spin_unlock_irqrestore(&amd_lock, flags);
}
-
- return ret;
}
-EXPORT_SYMBOL_GPL(usb_amd_find_chipset_info);
int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev)
{
@@ -315,6 +317,13 @@
}
EXPORT_SYMBOL_GPL(usb_amd_prefetch_quirk);
+bool usb_amd_quirk_pll_check(void)
+{
+ usb_amd_find_chipset_info();
+ return amd_chipset.need_pll_quirk;
+}
+EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_check);
+
/*
* The hardware normally enables the A-link power management feature, which
* lets the system lower the power consumption in idle states.
@@ -520,7 +529,7 @@
amd_chipset.nb_type = 0;
memset(&amd_chipset.sb_type, 0, sizeof(amd_chipset.sb_type));
amd_chipset.isoc_reqs = 0;
- amd_chipset.probe_result = 0;
+ amd_chipset.need_pll_quirk = 0;
spin_unlock_irqrestore(&amd_lock, flags);
@@ -783,15 +792,9 @@
/* disable interrupts */
writel((u32) ~0, base + OHCI_INTRDISABLE);
- /* Reset the USB bus, if the controller isn't already in RESET */
- if (control & OHCI_HCFS) {
- /* Go into RESET, preserving RWC (and possibly IR) */
- writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
- readl(base + OHCI_CONTROL);
-
- /* drive bus reset for at least 50 ms (7.1.7.5) */
- msleep(50);
- }
+ /* Go into the USB_RESET state, preserving RWC (and possibly IR) */
+ writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
+ readl(base + OHCI_CONTROL);
/* software reset of the controller, preserving HcFmInterval */
if (!no_fminterval)
diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h
index 63c6330..e729de2 100644
--- a/drivers/usb/host/pci-quirks.h
+++ b/drivers/usb/host/pci-quirks.h
@@ -5,11 +5,11 @@
#ifdef CONFIG_USB_PCI
void uhci_reset_hc(struct pci_dev *pdev, unsigned long base);
int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base);
-int usb_amd_find_chipset_info(void);
int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev);
bool usb_amd_hang_symptom_quirk(void);
bool usb_amd_prefetch_quirk(void);
void usb_amd_dev_put(void);
+bool usb_amd_quirk_pll_check(void);
void usb_amd_quirk_pll_disable(void);
void usb_amd_quirk_pll_enable(void);
void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev);
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 984892d..0c03ac6 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -1979,6 +1979,8 @@
static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
struct usb_host_endpoint *hep)
+__acquires(r8a66597->lock)
+__releases(r8a66597->lock)
{
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
struct r8a66597_pipe *pipe = (struct r8a66597_pipe *)hep->hcpriv;
@@ -1991,13 +1993,14 @@
return;
pipenum = pipe->info.pipenum;
+ spin_lock_irqsave(&r8a66597->lock, flags);
if (pipenum == 0) {
kfree(hep->hcpriv);
hep->hcpriv = NULL;
+ spin_unlock_irqrestore(&r8a66597->lock, flags);
return;
}
- spin_lock_irqsave(&r8a66597->lock, flags);
pipe_stop(r8a66597, pipe);
pipe_irq_disable(r8a66597, pipenum);
disable_irq_empty(r8a66597, pipenum);
@@ -2408,12 +2411,6 @@
if (usb_disabled())
return -ENODEV;
- if (pdev->dev.dma_mask) {
- ret = -EINVAL;
- dev_err(&pdev->dev, "dma not supported\n");
- goto clean_up;
- }
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENODEV;
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 5b061e5..72a34a1 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1632,12 +1632,6 @@
irq = ires->start;
irqflags = ires->flags & IRQF_TRIGGER_MASK;
- /* refuse to confuse usbcore */
- if (dev->dev.dma_mask) {
- dev_dbg(&dev->dev, "no we won't dma\n");
- return -EINVAL;
- }
-
/* the chip may be wired for either kind of addressing */
addr = platform_get_resource(dev, IORESOURCE_MEM, 0);
data = platform_get_resource(dev, IORESOURCE_MEM, 1);
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 5b8a3d95..4efee34 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -2477,7 +2477,8 @@
spin_unlock_irqrestore(&endp->queue_lock.slock,
irqs);
kfree(urbq);
- } urb->error_count = 0;
+ }
+ urb->error_count = 0;
usb_hcd_giveback_urb(hcd, urb, status);
return 0;
} else if (list_empty(&endp->urb_more)) {
@@ -2553,10 +2554,9 @@
dev_err(&u132->platform_dev->dev, "device is being removed\n");
return -ESHUTDOWN;
} else {
- int frame = 0;
dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n");
mdelay(100);
- return frame;
+ return 0;
}
}
@@ -2982,7 +2982,8 @@
while (rings-- > 0) {
struct u132_ring *ring = &u132->ring[rings];
u132_ring_cancel_work(u132, ring);
- } while (endps-- > 0) {
+ }
+ while (endps-- > 0) {
struct u132_endp *endp = u132->endp[endps];
if (endp)
u132_endp_cancel_work(u132, endp);
@@ -3076,8 +3077,6 @@
retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a);
if (retval)
return retval;
- if (pdev->dev.dma_mask)
- return -EINVAL;
hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) {
@@ -3201,7 +3200,12 @@
return -ENODEV;
printk(KERN_INFO "driver %s\n", hcd_name);
workqueue = create_singlethread_workqueue("u132");
+ if (!workqueue)
+ return -ENOMEM;
retval = platform_driver_register(&u132_platform_driver);
+ if (retval)
+ destroy_workqueue(workqueue);
+
return retval;
}
diff --git a/drivers/usb/host/uhci-grlib.c b/drivers/usb/host/uhci-grlib.c
index 2103b1e..0a201a7 100644
--- a/drivers/usb/host/uhci-grlib.c
+++ b/drivers/usb/host/uhci-grlib.c
@@ -63,7 +63,7 @@
/* Generic hardware linkage */
.irq = uhci_irq,
- .flags = HCD_MEMORY | HCD_USB11,
+ .flags = HCD_MEMORY | HCD_DMA | HCD_USB11,
/* Basic lifecycle operations */
.reset = uhci_grlib_init,
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 6218bfe..03bc597 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -581,7 +581,7 @@
hcd->uses_new_polling = 1;
/* Accept arbitrarily long scatter-gather lists */
- if (!(hcd->driver->flags & HCD_LOCAL_MEM))
+ if (!hcd->localmem_pool)
hcd->self.sg_tablesize = ~0;
spin_lock_init(&uhci->lock);
@@ -596,9 +596,9 @@
&uhci_debug_operations);
#endif
- uhci->frame = dma_zalloc_coherent(uhci_dev(uhci),
- UHCI_NUMFRAMES * sizeof(*uhci->frame),
- &uhci->frame_dma_handle, GFP_KERNEL);
+ uhci->frame = dma_alloc_coherent(uhci_dev(uhci),
+ UHCI_NUMFRAMES * sizeof(*uhci->frame),
+ &uhci->frame_dma_handle, GFP_KERNEL);
if (!uhci->frame) {
dev_err(uhci_dev(uhci),
"unable to allocate consistent memory for frame list\n");
diff --git a/drivers/usb/host/uhci-pci.c b/drivers/usb/host/uhci-pci.c
index 0dd9442..0fa3d72 100644
--- a/drivers/usb/host/uhci-pci.c
+++ b/drivers/usb/host/uhci-pci.c
@@ -261,7 +261,7 @@
/* Generic hardware linkage */
.irq = uhci_irq,
- .flags = HCD_USB11,
+ .flags = HCD_DMA | HCD_USB11,
/* Basic lifecycle operations */
.reset = uhci_pci_init,
diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c
index 89700e2..70dbd95 100644
--- a/drivers/usb/host/uhci-platform.c
+++ b/drivers/usb/host/uhci-platform.c
@@ -41,7 +41,7 @@
/* Generic hardware linkage */
.irq = uhci_irq,
- .flags = HCD_MEMORY | HCD_USB11,
+ .flags = HCD_MEMORY | HCD_DMA | HCD_USB11,
/* Basic lifecycle operations */
.reset = uhci_platform_init,
diff --git a/drivers/usb/host/whci/Kbuild b/drivers/usb/host/whci/Kbuild
deleted file mode 100644
index 26df013..0000000
--- a/drivers/usb/host/whci/Kbuild
+++ /dev/null
@@ -1,12 +0,0 @@
-obj-$(CONFIG_USB_WHCI_HCD) += whci-hcd.o
-
-whci-hcd-y := \
- asl.o \
- debug.o \
- hcd.o \
- hw.o \
- init.o \
- int.o \
- pzl.o \
- qset.o \
- wusb.o
diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c
deleted file mode 100644
index 276fb34..0000000
--- a/drivers/usb/host/whci/asl.c
+++ /dev/null
@@ -1,376 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) asynchronous schedule management.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/dma-mapping.h>
-#include <linux/uwb/umc.h>
-#include <linux/usb.h>
-
-#include "../../wusbcore/wusbhc.h"
-
-#include "whcd.h"
-
-static void qset_get_next_prev(struct whc *whc, struct whc_qset *qset,
- struct whc_qset **next, struct whc_qset **prev)
-{
- struct list_head *n, *p;
-
- BUG_ON(list_empty(&whc->async_list));
-
- n = qset->list_node.next;
- if (n == &whc->async_list)
- n = n->next;
- p = qset->list_node.prev;
- if (p == &whc->async_list)
- p = p->prev;
-
- *next = container_of(n, struct whc_qset, list_node);
- *prev = container_of(p, struct whc_qset, list_node);
-
-}
-
-static void asl_qset_insert_begin(struct whc *whc, struct whc_qset *qset)
-{
- list_move(&qset->list_node, &whc->async_list);
- qset->in_sw_list = true;
-}
-
-static void asl_qset_insert(struct whc *whc, struct whc_qset *qset)
-{
- struct whc_qset *next, *prev;
-
- qset_clear(whc, qset);
-
- /* Link into ASL. */
- qset_get_next_prev(whc, qset, &next, &prev);
- whc_qset_set_link_ptr(&qset->qh.link, next->qset_dma);
- whc_qset_set_link_ptr(&prev->qh.link, qset->qset_dma);
- qset->in_hw_list = true;
-}
-
-static void asl_qset_remove(struct whc *whc, struct whc_qset *qset)
-{
- struct whc_qset *prev, *next;
-
- qset_get_next_prev(whc, qset, &next, &prev);
-
- list_move(&qset->list_node, &whc->async_removed_list);
- qset->in_sw_list = false;
-
- /*
- * No more qsets in the ASL? The caller must stop the ASL as
- * it's no longer valid.
- */
- if (list_empty(&whc->async_list))
- return;
-
- /* Remove from ASL. */
- whc_qset_set_link_ptr(&prev->qh.link, next->qset_dma);
- qset->in_hw_list = false;
-}
-
-/**
- * process_qset - process any recently inactivated or halted qTDs in a
- * qset.
- *
- * After inactive qTDs are removed, new qTDs can be added if the
- * urb queue still contains URBs.
- *
- * Returns any additional WUSBCMD bits for the ASL sync command (i.e.,
- * WUSBCMD_ASYNC_QSET_RM if a halted qset was removed).
- */
-static uint32_t process_qset(struct whc *whc, struct whc_qset *qset)
-{
- enum whc_update update = 0;
- uint32_t status = 0;
-
- while (qset->ntds) {
- struct whc_qtd *td;
-
- td = &qset->qtd[qset->td_start];
- status = le32_to_cpu(td->status);
-
- /*
- * Nothing to do with a still active qTD.
- */
- if (status & QTD_STS_ACTIVE)
- break;
-
- if (status & QTD_STS_HALTED) {
- /* Ug, an error. */
- process_halted_qtd(whc, qset, td);
- /* A halted qTD always triggers an update
- because the qset was either removed or
- reactivated. */
- update |= WHC_UPDATE_UPDATED;
- goto done;
- }
-
- /* Mmm, a completed qTD. */
- process_inactive_qtd(whc, qset, td);
- }
-
- if (!qset->remove)
- update |= qset_add_qtds(whc, qset);
-
-done:
- /*
- * Remove this qset from the ASL if requested, but only if has
- * no qTDs.
- */
- if (qset->remove && qset->ntds == 0) {
- asl_qset_remove(whc, qset);
- update |= WHC_UPDATE_REMOVED;
- }
- return update;
-}
-
-void asl_start(struct whc *whc)
-{
- struct whc_qset *qset;
-
- qset = list_first_entry(&whc->async_list, struct whc_qset, list_node);
-
- le_writeq(qset->qset_dma | QH_LINK_NTDS(8), whc->base + WUSBASYNCLISTADDR);
-
- whc_write_wusbcmd(whc, WUSBCMD_ASYNC_EN, WUSBCMD_ASYNC_EN);
- whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
- WUSBSTS_ASYNC_SCHED, WUSBSTS_ASYNC_SCHED,
- 1000, "start ASL");
-}
-
-void asl_stop(struct whc *whc)
-{
- whc_write_wusbcmd(whc, WUSBCMD_ASYNC_EN, 0);
- whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
- WUSBSTS_ASYNC_SCHED, 0,
- 1000, "stop ASL");
-}
-
-/**
- * asl_update - request an ASL update and wait for the hardware to be synced
- * @whc: the WHCI HC
- * @wusbcmd: WUSBCMD value to start the update.
- *
- * If the WUSB HC is inactive (i.e., the ASL is stopped) then the
- * update must be skipped as the hardware may not respond to update
- * requests.
- */
-void asl_update(struct whc *whc, uint32_t wusbcmd)
-{
- struct wusbhc *wusbhc = &whc->wusbhc;
- long t;
-
- mutex_lock(&wusbhc->mutex);
- if (wusbhc->active) {
- whc_write_wusbcmd(whc, wusbcmd, wusbcmd);
- t = wait_event_timeout(
- whc->async_list_wq,
- (le_readl(whc->base + WUSBCMD) & WUSBCMD_ASYNC_UPDATED) == 0,
- msecs_to_jiffies(1000));
- if (t == 0)
- whc_hw_error(whc, "ASL update timeout");
- }
- mutex_unlock(&wusbhc->mutex);
-}
-
-/**
- * scan_async_work - scan the ASL for qsets to process.
- *
- * Process each qset in the ASL in turn and then signal the WHC that
- * the ASL has been updated.
- *
- * Then start, stop or update the asynchronous schedule as required.
- */
-void scan_async_work(struct work_struct *work)
-{
- struct whc *whc = container_of(work, struct whc, async_work);
- struct whc_qset *qset, *t;
- enum whc_update update = 0;
-
- spin_lock_irq(&whc->lock);
-
- /*
- * Transerve the software list backwards so new qsets can be
- * safely inserted into the ASL without making it non-circular.
- */
- list_for_each_entry_safe_reverse(qset, t, &whc->async_list, list_node) {
- if (!qset->in_hw_list) {
- asl_qset_insert(whc, qset);
- update |= WHC_UPDATE_ADDED;
- }
-
- update |= process_qset(whc, qset);
- }
-
- spin_unlock_irq(&whc->lock);
-
- if (update) {
- uint32_t wusbcmd = WUSBCMD_ASYNC_UPDATED | WUSBCMD_ASYNC_SYNCED_DB;
- if (update & WHC_UPDATE_REMOVED)
- wusbcmd |= WUSBCMD_ASYNC_QSET_RM;
- asl_update(whc, wusbcmd);
- }
-
- /*
- * Now that the ASL is updated, complete the removal of any
- * removed qsets.
- *
- * If the qset was to be reset, do so and reinsert it into the
- * ASL if it has pending transfers.
- */
- spin_lock_irq(&whc->lock);
-
- list_for_each_entry_safe(qset, t, &whc->async_removed_list, list_node) {
- qset_remove_complete(whc, qset);
- if (qset->reset) {
- qset_reset(whc, qset);
- if (!list_empty(&qset->stds)) {
- asl_qset_insert_begin(whc, qset);
- queue_work(whc->workqueue, &whc->async_work);
- }
- }
- }
-
- spin_unlock_irq(&whc->lock);
-}
-
-/**
- * asl_urb_enqueue - queue an URB onto the asynchronous list (ASL).
- * @whc: the WHCI host controller
- * @urb: the URB to enqueue
- * @mem_flags: flags for any memory allocations
- *
- * The qset for the endpoint is obtained and the urb queued on to it.
- *
- * Work is scheduled to update the hardware's view of the ASL.
- */
-int asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags)
-{
- struct whc_qset *qset;
- int err;
- unsigned long flags;
-
- spin_lock_irqsave(&whc->lock, flags);
-
- err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb);
- if (err < 0) {
- spin_unlock_irqrestore(&whc->lock, flags);
- return err;
- }
-
- qset = get_qset(whc, urb, GFP_ATOMIC);
- if (qset == NULL)
- err = -ENOMEM;
- else
- err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
- if (!err) {
- if (!qset->in_sw_list && !qset->remove)
- asl_qset_insert_begin(whc, qset);
- } else
- usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb);
-
- spin_unlock_irqrestore(&whc->lock, flags);
-
- if (!err)
- queue_work(whc->workqueue, &whc->async_work);
-
- return err;
-}
-
-/**
- * asl_urb_dequeue - remove an URB (qset) from the async list.
- * @whc: the WHCI host controller
- * @urb: the URB to dequeue
- * @status: the current status of the URB
- *
- * URBs that do yet have qTDs can simply be removed from the software
- * queue, otherwise the qset must be removed from the ASL so the qTDs
- * can be removed.
- */
-int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
-{
- struct whc_urb *wurb = urb->hcpriv;
- struct whc_qset *qset = wurb->qset;
- struct whc_std *std, *t;
- bool has_qtd = false;
- int ret;
- unsigned long flags;
-
- spin_lock_irqsave(&whc->lock, flags);
-
- ret = usb_hcd_check_unlink_urb(&whc->wusbhc.usb_hcd, urb, status);
- if (ret < 0)
- goto out;
-
- list_for_each_entry_safe(std, t, &qset->stds, list_node) {
- if (std->urb == urb) {
- if (std->qtd)
- has_qtd = true;
- qset_free_std(whc, std);
- } else
- std->qtd = NULL; /* so this std is re-added when the qset is */
- }
-
- if (has_qtd) {
- asl_qset_remove(whc, qset);
- wurb->status = status;
- wurb->is_async = true;
- queue_work(whc->workqueue, &wurb->dequeue_work);
- } else
- qset_remove_urb(whc, qset, urb, status);
-out:
- spin_unlock_irqrestore(&whc->lock, flags);
-
- return ret;
-}
-
-/**
- * asl_qset_delete - delete a qset from the ASL
- */
-void asl_qset_delete(struct whc *whc, struct whc_qset *qset)
-{
- qset->remove = 1;
- queue_work(whc->workqueue, &whc->async_work);
- qset_delete(whc, qset);
-}
-
-/**
- * asl_init - initialize the asynchronous schedule list
- *
- * A dummy qset with no qTDs is added to the ASL to simplify removing
- * qsets (no need to stop the ASL when the last qset is removed).
- */
-int asl_init(struct whc *whc)
-{
- struct whc_qset *qset;
-
- qset = qset_alloc(whc, GFP_KERNEL);
- if (qset == NULL)
- return -ENOMEM;
-
- asl_qset_insert_begin(whc, qset);
- asl_qset_insert(whc, qset);
-
- return 0;
-}
-
-/**
- * asl_clean_up - free ASL resources
- *
- * The ASL is stopped and empty except for the dummy qset.
- */
-void asl_clean_up(struct whc *whc)
-{
- struct whc_qset *qset;
-
- if (!list_empty(&whc->async_list)) {
- qset = list_first_entry(&whc->async_list, struct whc_qset, list_node);
- list_del(&qset->list_node);
- qset_free(whc, qset);
- }
-}
diff --git a/drivers/usb/host/whci/debug.c b/drivers/usb/host/whci/debug.c
deleted file mode 100644
index 8ddfe3f..0000000
--- a/drivers/usb/host/whci/debug.c
+++ /dev/null
@@ -1,153 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) debug.
- *
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- */
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/export.h>
-
-#include "../../wusbcore/wusbhc.h"
-
-#include "whcd.h"
-
-struct whc_dbg {
- struct dentry *di_f;
- struct dentry *asl_f;
- struct dentry *pzl_f;
-};
-
-static void qset_print(struct seq_file *s, struct whc_qset *qset)
-{
- static const char *qh_type[] = {
- "ctrl", "isoc", "bulk", "intr", "rsvd", "rsvd", "rsvd", "lpintr", };
- struct whc_std *std;
- struct urb *urb = NULL;
- int i;
-
- seq_printf(s, "qset %08x", (u32)qset->qset_dma);
- if (&qset->list_node == qset->whc->async_list.prev) {
- seq_printf(s, " (dummy)\n");
- } else {
- seq_printf(s, " ep%d%s-%s maxpkt: %d\n",
- qset->qh.info1 & 0x0f,
- (qset->qh.info1 >> 4) & 0x1 ? "in" : "out",
- qh_type[(qset->qh.info1 >> 5) & 0x7],
- (qset->qh.info1 >> 16) & 0xffff);
- }
- seq_printf(s, " -> %08x\n", (u32)qset->qh.link);
- seq_printf(s, " info: %08x %08x %08x\n",
- qset->qh.info1, qset->qh.info2, qset->qh.info3);
- seq_printf(s, " sts: %04x errs: %d curwin: %08x\n",
- qset->qh.status, qset->qh.err_count, qset->qh.cur_window);
- seq_printf(s, " TD: sts: %08x opts: %08x\n",
- qset->qh.overlay.qtd.status, qset->qh.overlay.qtd.options);
-
- for (i = 0; i < WHCI_QSET_TD_MAX; i++) {
- seq_printf(s, " %c%c TD[%d]: sts: %08x opts: %08x ptr: %08x\n",
- i == qset->td_start ? 'S' : ' ',
- i == qset->td_end ? 'E' : ' ',
- i, qset->qtd[i].status, qset->qtd[i].options,
- (u32)qset->qtd[i].page_list_ptr);
- }
- seq_printf(s, " ntds: %d\n", qset->ntds);
- list_for_each_entry(std, &qset->stds, list_node) {
- if (urb != std->urb) {
- urb = std->urb;
- seq_printf(s, " urb %p transferred: %d bytes\n", urb,
- urb->actual_length);
- }
- if (std->qtd)
- seq_printf(s, " sTD[%td]: %zu bytes @ %08x\n",
- std->qtd - &qset->qtd[0],
- std->len, std->num_pointers ?
- (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr);
- else
- seq_printf(s, " sTD[-]: %zd bytes @ %08x\n",
- std->len, std->num_pointers ?
- (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr);
- }
-}
-
-static int di_show(struct seq_file *s, void *p)
-{
- struct whc *whc = s->private;
- int d;
-
- for (d = 0; d < whc->n_devices; d++) {
- struct di_buf_entry *di = &whc->di_buf[d];
-
- seq_printf(s, "DI[%d]\n", d);
- seq_printf(s, " availability: %*pb\n",
- UWB_NUM_MAS, (unsigned long *)di->availability_info);
- seq_printf(s, " %c%c key idx: %d dev addr: %d\n",
- (di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ',
- (di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ',
- (di->addr_sec_info & WHC_DI_KEY_IDX_MASK) >> 8,
- (di->addr_sec_info & WHC_DI_DEV_ADDR_MASK));
- }
- return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(di);
-
-static int asl_show(struct seq_file *s, void *p)
-{
- struct whc *whc = s->private;
- struct whc_qset *qset;
-
- list_for_each_entry(qset, &whc->async_list, list_node) {
- qset_print(s, qset);
- }
-
- return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(asl);
-
-static int pzl_show(struct seq_file *s, void *p)
-{
- struct whc *whc = s->private;
- struct whc_qset *qset;
- int period;
-
- for (period = 0; period < 5; period++) {
- seq_printf(s, "Period %d\n", period);
- list_for_each_entry(qset, &whc->periodic_list[period], list_node) {
- qset_print(s, qset);
- }
- }
- return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(pzl);
-
-void whc_dbg_init(struct whc *whc)
-{
- if (whc->wusbhc.pal.debugfs_dir == NULL)
- return;
-
- whc->dbg = kzalloc(sizeof(struct whc_dbg), GFP_KERNEL);
- if (whc->dbg == NULL)
- return;
-
- whc->dbg->di_f = debugfs_create_file("di", 0444,
- whc->wusbhc.pal.debugfs_dir, whc,
- &di_fops);
- whc->dbg->asl_f = debugfs_create_file("asl", 0444,
- whc->wusbhc.pal.debugfs_dir, whc,
- &asl_fops);
- whc->dbg->pzl_f = debugfs_create_file("pzl", 0444,
- whc->wusbhc.pal.debugfs_dir, whc,
- &pzl_fops);
-}
-
-void whc_dbg_clean_up(struct whc *whc)
-{
- if (whc->dbg) {
- debugfs_remove(whc->dbg->pzl_f);
- debugfs_remove(whc->dbg->asl_f);
- debugfs_remove(whc->dbg->di_f);
- kfree(whc->dbg);
- }
-}
diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c
deleted file mode 100644
index 8af9dcf..0000000
--- a/drivers/usb/host/whci/hcd.c
+++ /dev/null
@@ -1,356 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) driver.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/uwb/umc.h>
-
-#include "../../wusbcore/wusbhc.h"
-
-#include "whcd.h"
-
-/*
- * One time initialization.
- *
- * Nothing to do here.
- */
-static int whc_reset(struct usb_hcd *usb_hcd)
-{
- return 0;
-}
-
-/*
- * Start the wireless host controller.
- *
- * Start device notification.
- *
- * Put hc into run state, set DNTS parameters.
- */
-static int whc_start(struct usb_hcd *usb_hcd)
-{
- struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
- struct whc *whc = wusbhc_to_whc(wusbhc);
- u8 bcid;
- int ret;
-
- mutex_lock(&wusbhc->mutex);
-
- le_writel(WUSBINTR_GEN_CMD_DONE
- | WUSBINTR_HOST_ERR
- | WUSBINTR_ASYNC_SCHED_SYNCED
- | WUSBINTR_DNTS_INT
- | WUSBINTR_ERR_INT
- | WUSBINTR_INT,
- whc->base + WUSBINTR);
-
- /* set cluster ID */
- bcid = wusb_cluster_id_get();
- ret = whc_set_cluster_id(whc, bcid);
- if (ret < 0)
- goto out;
- wusbhc->cluster_id = bcid;
-
- /* start HC */
- whc_write_wusbcmd(whc, WUSBCMD_RUN, WUSBCMD_RUN);
-
- usb_hcd->uses_new_polling = 1;
- set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags);
- usb_hcd->state = HC_STATE_RUNNING;
-
-out:
- mutex_unlock(&wusbhc->mutex);
- return ret;
-}
-
-
-/*
- * Stop the wireless host controller.
- *
- * Stop device notification.
- *
- * Wait for pending transfer to stop? Put hc into stop state?
- */
-static void whc_stop(struct usb_hcd *usb_hcd)
-{
- struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
- struct whc *whc = wusbhc_to_whc(wusbhc);
-
- mutex_lock(&wusbhc->mutex);
-
- /* stop HC */
- le_writel(0, whc->base + WUSBINTR);
- whc_write_wusbcmd(whc, WUSBCMD_RUN, 0);
- whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
- WUSBSTS_HCHALTED, WUSBSTS_HCHALTED,
- 100, "HC to halt");
-
- wusb_cluster_id_put(wusbhc->cluster_id);
-
- mutex_unlock(&wusbhc->mutex);
-}
-
-static int whc_get_frame_number(struct usb_hcd *usb_hcd)
-{
- /* Frame numbers are not applicable to WUSB. */
- return -ENOSYS;
-}
-
-
-/*
- * Queue an URB to the ASL or PZL
- */
-static int whc_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb,
- gfp_t mem_flags)
-{
- struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
- struct whc *whc = wusbhc_to_whc(wusbhc);
- int ret;
-
- switch (usb_pipetype(urb->pipe)) {
- case PIPE_INTERRUPT:
- ret = pzl_urb_enqueue(whc, urb, mem_flags);
- break;
- case PIPE_ISOCHRONOUS:
- dev_err(&whc->umc->dev, "isochronous transfers unsupported\n");
- ret = -ENOTSUPP;
- break;
- case PIPE_CONTROL:
- case PIPE_BULK:
- default:
- ret = asl_urb_enqueue(whc, urb, mem_flags);
- break;
- }
-
- return ret;
-}
-
-/*
- * Remove a queued URB from the ASL or PZL.
- */
-static int whc_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb, int status)
-{
- struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
- struct whc *whc = wusbhc_to_whc(wusbhc);
- int ret;
-
- switch (usb_pipetype(urb->pipe)) {
- case PIPE_INTERRUPT:
- ret = pzl_urb_dequeue(whc, urb, status);
- break;
- case PIPE_ISOCHRONOUS:
- ret = -ENOTSUPP;
- break;
- case PIPE_CONTROL:
- case PIPE_BULK:
- default:
- ret = asl_urb_dequeue(whc, urb, status);
- break;
- }
-
- return ret;
-}
-
-/*
- * Wait for all URBs to the endpoint to be completed, then delete the
- * qset.
- */
-static void whc_endpoint_disable(struct usb_hcd *usb_hcd,
- struct usb_host_endpoint *ep)
-{
- struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
- struct whc *whc = wusbhc_to_whc(wusbhc);
- struct whc_qset *qset;
-
- qset = ep->hcpriv;
- if (qset) {
- ep->hcpriv = NULL;
- if (usb_endpoint_xfer_bulk(&ep->desc)
- || usb_endpoint_xfer_control(&ep->desc))
- asl_qset_delete(whc, qset);
- else
- pzl_qset_delete(whc, qset);
- }
-}
-
-static void whc_endpoint_reset(struct usb_hcd *usb_hcd,
- struct usb_host_endpoint *ep)
-{
- struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
- struct whc *whc = wusbhc_to_whc(wusbhc);
- struct whc_qset *qset;
- unsigned long flags;
-
- spin_lock_irqsave(&whc->lock, flags);
-
- qset = ep->hcpriv;
- if (qset) {
- qset->remove = 1;
- qset->reset = 1;
-
- if (usb_endpoint_xfer_bulk(&ep->desc)
- || usb_endpoint_xfer_control(&ep->desc))
- queue_work(whc->workqueue, &whc->async_work);
- else
- queue_work(whc->workqueue, &whc->periodic_work);
- }
-
- spin_unlock_irqrestore(&whc->lock, flags);
-}
-
-
-static const struct hc_driver whc_hc_driver = {
- .description = "whci-hcd",
- .product_desc = "Wireless host controller",
- .hcd_priv_size = sizeof(struct whc) - sizeof(struct usb_hcd),
- .irq = whc_int_handler,
- .flags = HCD_USB2,
-
- .reset = whc_reset,
- .start = whc_start,
- .stop = whc_stop,
- .get_frame_number = whc_get_frame_number,
- .urb_enqueue = whc_urb_enqueue,
- .urb_dequeue = whc_urb_dequeue,
- .endpoint_disable = whc_endpoint_disable,
- .endpoint_reset = whc_endpoint_reset,
-
- .hub_status_data = wusbhc_rh_status_data,
- .hub_control = wusbhc_rh_control,
- .start_port_reset = wusbhc_rh_start_port_reset,
-};
-
-static int whc_probe(struct umc_dev *umc)
-{
- int ret;
- struct usb_hcd *usb_hcd;
- struct wusbhc *wusbhc;
- struct whc *whc;
- struct device *dev = &umc->dev;
-
- usb_hcd = usb_create_hcd(&whc_hc_driver, dev, "whci");
- if (usb_hcd == NULL) {
- dev_err(dev, "unable to create hcd\n");
- return -ENOMEM;
- }
-
- usb_hcd->wireless = 1;
- usb_hcd->self.sg_tablesize = 2048; /* somewhat arbitrary */
-
- wusbhc = usb_hcd_to_wusbhc(usb_hcd);
- whc = wusbhc_to_whc(wusbhc);
- whc->umc = umc;
-
- ret = whc_init(whc);
- if (ret)
- goto error_whc_init;
-
- wusbhc->dev = dev;
- wusbhc->uwb_rc = uwb_rc_get_by_grandpa(umc->dev.parent);
- if (!wusbhc->uwb_rc) {
- ret = -ENODEV;
- dev_err(dev, "cannot get radio controller\n");
- goto error_uwb_rc;
- }
-
- if (whc->n_devices > USB_MAXCHILDREN) {
- dev_warn(dev, "USB_MAXCHILDREN too low for WUSB adapter (%u ports)\n",
- whc->n_devices);
- wusbhc->ports_max = USB_MAXCHILDREN;
- } else
- wusbhc->ports_max = whc->n_devices;
- wusbhc->mmcies_max = whc->n_mmc_ies;
- wusbhc->start = whc_wusbhc_start;
- wusbhc->stop = whc_wusbhc_stop;
- wusbhc->mmcie_add = whc_mmcie_add;
- wusbhc->mmcie_rm = whc_mmcie_rm;
- wusbhc->dev_info_set = whc_dev_info_set;
- wusbhc->bwa_set = whc_bwa_set;
- wusbhc->set_num_dnts = whc_set_num_dnts;
- wusbhc->set_ptk = whc_set_ptk;
- wusbhc->set_gtk = whc_set_gtk;
-
- ret = wusbhc_create(wusbhc);
- if (ret)
- goto error_wusbhc_create;
-
- ret = usb_add_hcd(usb_hcd, whc->umc->irq, IRQF_SHARED);
- if (ret) {
- dev_err(dev, "cannot add HCD: %d\n", ret);
- goto error_usb_add_hcd;
- }
- device_wakeup_enable(usb_hcd->self.controller);
-
- ret = wusbhc_b_create(wusbhc);
- if (ret) {
- dev_err(dev, "WUSBHC phase B setup failed: %d\n", ret);
- goto error_wusbhc_b_create;
- }
-
- whc_dbg_init(whc);
-
- return 0;
-
-error_wusbhc_b_create:
- usb_remove_hcd(usb_hcd);
-error_usb_add_hcd:
- wusbhc_destroy(wusbhc);
-error_wusbhc_create:
- uwb_rc_put(wusbhc->uwb_rc);
-error_uwb_rc:
- whc_clean_up(whc);
-error_whc_init:
- usb_put_hcd(usb_hcd);
- return ret;
-}
-
-
-static void whc_remove(struct umc_dev *umc)
-{
- struct usb_hcd *usb_hcd = dev_get_drvdata(&umc->dev);
- struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
- struct whc *whc = wusbhc_to_whc(wusbhc);
-
- if (usb_hcd) {
- whc_dbg_clean_up(whc);
- wusbhc_b_destroy(wusbhc);
- usb_remove_hcd(usb_hcd);
- wusbhc_destroy(wusbhc);
- uwb_rc_put(wusbhc->uwb_rc);
- whc_clean_up(whc);
- usb_put_hcd(usb_hcd);
- }
-}
-
-static struct umc_driver whci_hc_driver = {
- .name = "whci-hcd",
- .cap_id = UMC_CAP_ID_WHCI_WUSB_HC,
- .probe = whc_probe,
- .remove = whc_remove,
-};
-
-static int __init whci_hc_driver_init(void)
-{
- return umc_driver_register(&whci_hc_driver);
-}
-module_init(whci_hc_driver_init);
-
-static void __exit whci_hc_driver_exit(void)
-{
- umc_driver_unregister(&whci_hc_driver);
-}
-module_exit(whci_hc_driver_exit);
-
-/* PCI device ID's that we handle (so it gets loaded) */
-static struct pci_device_id __used whci_hcd_id_table[] = {
- { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
- { /* empty last entry */ }
-};
-MODULE_DEVICE_TABLE(pci, whci_hcd_id_table);
-
-MODULE_DESCRIPTION("WHCI Wireless USB host controller driver");
-MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/whci/hw.c b/drivers/usb/host/whci/hw.c
deleted file mode 100644
index 22b3b7f..0000000
--- a/drivers/usb/host/whci/hw.c
+++ /dev/null
@@ -1,93 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) hardware access helpers.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/dma-mapping.h>
-#include <linux/uwb/umc.h>
-
-#include "../../wusbcore/wusbhc.h"
-
-#include "whcd.h"
-
-void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val)
-{
- unsigned long flags;
- u32 cmd;
-
- spin_lock_irqsave(&whc->lock, flags);
-
- cmd = le_readl(whc->base + WUSBCMD);
- cmd = (cmd & ~mask) | val;
- le_writel(cmd, whc->base + WUSBCMD);
-
- spin_unlock_irqrestore(&whc->lock, flags);
-}
-
-/**
- * whc_do_gencmd - start a generic command via the WUSBGENCMDSTS register
- * @whc: the WHCI HC
- * @cmd: command to start.
- * @params: parameters for the command (the WUSBGENCMDPARAMS register value).
- * @addr: pointer to any data for the command (may be NULL).
- * @len: length of the data (if any).
- */
-int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len)
-{
- unsigned long flags;
- dma_addr_t dma_addr;
- int t;
- int ret = 0;
-
- mutex_lock(&whc->mutex);
-
- /* Wait for previous command to complete. */
- t = wait_event_timeout(whc->cmd_wq,
- (le_readl(whc->base + WUSBGENCMDSTS) & WUSBGENCMDSTS_ACTIVE) == 0,
- WHC_GENCMD_TIMEOUT_MS);
- if (t == 0) {
- dev_err(&whc->umc->dev, "generic command timeout (%04x/%04x)\n",
- le_readl(whc->base + WUSBGENCMDSTS),
- le_readl(whc->base + WUSBGENCMDPARAMS));
- ret = -ETIMEDOUT;
- goto out;
- }
-
- if (addr) {
- memcpy(whc->gen_cmd_buf, addr, len);
- dma_addr = whc->gen_cmd_buf_dma;
- } else
- dma_addr = 0;
-
- /* Poke registers to start cmd. */
- spin_lock_irqsave(&whc->lock, flags);
-
- le_writel(params, whc->base + WUSBGENCMDPARAMS);
- le_writeq(dma_addr, whc->base + WUSBGENADDR);
-
- le_writel(WUSBGENCMDSTS_ACTIVE | WUSBGENCMDSTS_IOC | cmd,
- whc->base + WUSBGENCMDSTS);
-
- spin_unlock_irqrestore(&whc->lock, flags);
-out:
- mutex_unlock(&whc->mutex);
-
- return ret;
-}
-
-/**
- * whc_hw_error - recover from a hardware error
- * @whc: the WHCI HC that broke.
- * @reason: a description of the failure.
- *
- * Recover from broken hardware with a full reset.
- */
-void whc_hw_error(struct whc *whc, const char *reason)
-{
- struct wusbhc *wusbhc = &whc->wusbhc;
-
- dev_err(&whc->umc->dev, "hardware error: %s\n", reason);
- wusbhc_reset_all(wusbhc);
-}
diff --git a/drivers/usb/host/whci/init.c b/drivers/usb/host/whci/init.c
deleted file mode 100644
index 8241697..0000000
--- a/drivers/usb/host/whci/init.c
+++ /dev/null
@@ -1,177 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) initialization.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/dma-mapping.h>
-#include <linux/uwb/umc.h>
-
-#include "../../wusbcore/wusbhc.h"
-
-#include "whcd.h"
-
-/*
- * Reset the host controller.
- */
-static void whc_hw_reset(struct whc *whc)
-{
- le_writel(WUSBCMD_WHCRESET, whc->base + WUSBCMD);
- whci_wait_for(&whc->umc->dev, whc->base + WUSBCMD, WUSBCMD_WHCRESET, 0,
- 100, "reset");
-}
-
-static void whc_hw_init_di_buf(struct whc *whc)
-{
- int d;
-
- /* Disable all entries in the Device Information buffer. */
- for (d = 0; d < whc->n_devices; d++)
- whc->di_buf[d].addr_sec_info = WHC_DI_DISABLE;
-
- le_writeq(whc->di_buf_dma, whc->base + WUSBDEVICEINFOADDR);
-}
-
-static void whc_hw_init_dn_buf(struct whc *whc)
-{
- /* Clear the Device Notification buffer to ensure the V (valid)
- * bits are clear. */
- memset(whc->dn_buf, 0, 4096);
-
- le_writeq(whc->dn_buf_dma, whc->base + WUSBDNTSBUFADDR);
-}
-
-int whc_init(struct whc *whc)
-{
- u32 whcsparams;
- int ret, i;
- resource_size_t start, len;
-
- spin_lock_init(&whc->lock);
- mutex_init(&whc->mutex);
- init_waitqueue_head(&whc->cmd_wq);
- init_waitqueue_head(&whc->async_list_wq);
- init_waitqueue_head(&whc->periodic_list_wq);
- whc->workqueue = alloc_ordered_workqueue(dev_name(&whc->umc->dev), 0);
- if (whc->workqueue == NULL) {
- ret = -ENOMEM;
- goto error;
- }
- INIT_WORK(&whc->dn_work, whc_dn_work);
-
- INIT_WORK(&whc->async_work, scan_async_work);
- INIT_LIST_HEAD(&whc->async_list);
- INIT_LIST_HEAD(&whc->async_removed_list);
-
- INIT_WORK(&whc->periodic_work, scan_periodic_work);
- for (i = 0; i < 5; i++)
- INIT_LIST_HEAD(&whc->periodic_list[i]);
- INIT_LIST_HEAD(&whc->periodic_removed_list);
-
- /* Map HC registers. */
- start = whc->umc->resource.start;
- len = whc->umc->resource.end - start + 1;
- if (!request_mem_region(start, len, "whci-hc")) {
- dev_err(&whc->umc->dev, "can't request HC region\n");
- ret = -EBUSY;
- goto error;
- }
- whc->base_phys = start;
- whc->base = ioremap(start, len);
- if (!whc->base) {
- dev_err(&whc->umc->dev, "ioremap\n");
- ret = -ENOMEM;
- goto error;
- }
-
- whc_hw_reset(whc);
-
- /* Read maximum number of devices, keys and MMC IEs. */
- whcsparams = le_readl(whc->base + WHCSPARAMS);
- whc->n_devices = WHCSPARAMS_TO_N_DEVICES(whcsparams);
- whc->n_keys = WHCSPARAMS_TO_N_KEYS(whcsparams);
- whc->n_mmc_ies = WHCSPARAMS_TO_N_MMC_IES(whcsparams);
-
- dev_dbg(&whc->umc->dev, "N_DEVICES = %d, N_KEYS = %d, N_MMC_IES = %d\n",
- whc->n_devices, whc->n_keys, whc->n_mmc_ies);
-
- whc->qset_pool = dma_pool_create("qset", &whc->umc->dev,
- sizeof(struct whc_qset), 64, 0);
- if (whc->qset_pool == NULL) {
- ret = -ENOMEM;
- goto error;
- }
-
- ret = asl_init(whc);
- if (ret < 0)
- goto error;
- ret = pzl_init(whc);
- if (ret < 0)
- goto error;
-
- /* Allocate and initialize a buffer for generic commands, the
- Device Information buffer, and the Device Notification
- buffer. */
-
- whc->gen_cmd_buf = dma_alloc_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN,
- &whc->gen_cmd_buf_dma, GFP_KERNEL);
- if (whc->gen_cmd_buf == NULL) {
- ret = -ENOMEM;
- goto error;
- }
-
- whc->dn_buf = dma_alloc_coherent(&whc->umc->dev,
- sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES,
- &whc->dn_buf_dma, GFP_KERNEL);
- if (!whc->dn_buf) {
- ret = -ENOMEM;
- goto error;
- }
- whc_hw_init_dn_buf(whc);
-
- whc->di_buf = dma_alloc_coherent(&whc->umc->dev,
- sizeof(struct di_buf_entry) * whc->n_devices,
- &whc->di_buf_dma, GFP_KERNEL);
- if (!whc->di_buf) {
- ret = -ENOMEM;
- goto error;
- }
- whc_hw_init_di_buf(whc);
-
- return 0;
-
-error:
- whc_clean_up(whc);
- return ret;
-}
-
-void whc_clean_up(struct whc *whc)
-{
- resource_size_t len;
-
- if (whc->di_buf)
- dma_free_coherent(&whc->umc->dev, sizeof(struct di_buf_entry) * whc->n_devices,
- whc->di_buf, whc->di_buf_dma);
- if (whc->dn_buf)
- dma_free_coherent(&whc->umc->dev, sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES,
- whc->dn_buf, whc->dn_buf_dma);
- if (whc->gen_cmd_buf)
- dma_free_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN,
- whc->gen_cmd_buf, whc->gen_cmd_buf_dma);
-
- pzl_clean_up(whc);
- asl_clean_up(whc);
-
- dma_pool_destroy(whc->qset_pool);
-
- len = resource_size(&whc->umc->resource);
- if (whc->base)
- iounmap(whc->base);
- if (whc->base_phys)
- release_mem_region(whc->base_phys, len);
-
- if (whc->workqueue)
- destroy_workqueue(whc->workqueue);
-}
diff --git a/drivers/usb/host/whci/int.c b/drivers/usb/host/whci/int.c
deleted file mode 100644
index 7e4ad1b..0000000
--- a/drivers/usb/host/whci/int.c
+++ /dev/null
@@ -1,82 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) interrupt handling.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/uwb/umc.h>
-
-#include "../../wusbcore/wusbhc.h"
-
-#include "whcd.h"
-
-static void transfer_done(struct whc *whc)
-{
- queue_work(whc->workqueue, &whc->async_work);
- queue_work(whc->workqueue, &whc->periodic_work);
-}
-
-irqreturn_t whc_int_handler(struct usb_hcd *hcd)
-{
- struct wusbhc *wusbhc = usb_hcd_to_wusbhc(hcd);
- struct whc *whc = wusbhc_to_whc(wusbhc);
- u32 sts;
-
- sts = le_readl(whc->base + WUSBSTS);
- if (!(sts & WUSBSTS_INT_MASK))
- return IRQ_NONE;
- le_writel(sts & WUSBSTS_INT_MASK, whc->base + WUSBSTS);
-
- if (sts & WUSBSTS_GEN_CMD_DONE)
- wake_up(&whc->cmd_wq);
-
- if (sts & WUSBSTS_HOST_ERR)
- dev_err(&whc->umc->dev, "FIXME: host system error\n");
-
- if (sts & WUSBSTS_ASYNC_SCHED_SYNCED)
- wake_up(&whc->async_list_wq);
-
- if (sts & WUSBSTS_PERIODIC_SCHED_SYNCED)
- wake_up(&whc->periodic_list_wq);
-
- if (sts & WUSBSTS_DNTS_INT)
- queue_work(whc->workqueue, &whc->dn_work);
-
- /*
- * A transfer completed (see [WHCI] section 4.7.1.2 for when
- * this occurs).
- */
- if (sts & (WUSBSTS_INT | WUSBSTS_ERR_INT))
- transfer_done(whc);
-
- return IRQ_HANDLED;
-}
-
-static int process_dn_buf(struct whc *whc)
-{
- struct wusbhc *wusbhc = &whc->wusbhc;
- struct dn_buf_entry *dn;
- int processed = 0;
-
- for (dn = whc->dn_buf; dn < whc->dn_buf + WHC_N_DN_ENTRIES; dn++) {
- if (dn->status & WHC_DN_STATUS_VALID) {
- wusbhc_handle_dn(wusbhc, dn->src_addr,
- (struct wusb_dn_hdr *)dn->dn_data,
- dn->msg_size);
- dn->status &= ~WHC_DN_STATUS_VALID;
- processed++;
- }
- }
- return processed;
-}
-
-void whc_dn_work(struct work_struct *work)
-{
- struct whc *whc = container_of(work, struct whc, dn_work);
- int processed;
-
- do {
- processed = process_dn_buf(whc);
- } while (processed);
-}
diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c
deleted file mode 100644
index ef52aeb..0000000
--- a/drivers/usb/host/whci/pzl.c
+++ /dev/null
@@ -1,404 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) periodic schedule management.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/dma-mapping.h>
-#include <linux/uwb/umc.h>
-#include <linux/usb.h>
-
-#include "../../wusbcore/wusbhc.h"
-
-#include "whcd.h"
-
-static void update_pzl_pointers(struct whc *whc, int period, u64 addr)
-{
- switch (period) {
- case 0:
- whc_qset_set_link_ptr(&whc->pz_list[0], addr);
- whc_qset_set_link_ptr(&whc->pz_list[2], addr);
- whc_qset_set_link_ptr(&whc->pz_list[4], addr);
- whc_qset_set_link_ptr(&whc->pz_list[6], addr);
- whc_qset_set_link_ptr(&whc->pz_list[8], addr);
- whc_qset_set_link_ptr(&whc->pz_list[10], addr);
- whc_qset_set_link_ptr(&whc->pz_list[12], addr);
- whc_qset_set_link_ptr(&whc->pz_list[14], addr);
- break;
- case 1:
- whc_qset_set_link_ptr(&whc->pz_list[1], addr);
- whc_qset_set_link_ptr(&whc->pz_list[5], addr);
- whc_qset_set_link_ptr(&whc->pz_list[9], addr);
- whc_qset_set_link_ptr(&whc->pz_list[13], addr);
- break;
- case 2:
- whc_qset_set_link_ptr(&whc->pz_list[3], addr);
- whc_qset_set_link_ptr(&whc->pz_list[11], addr);
- break;
- case 3:
- whc_qset_set_link_ptr(&whc->pz_list[7], addr);
- break;
- case 4:
- whc_qset_set_link_ptr(&whc->pz_list[15], addr);
- break;
- }
-}
-
-/*
- * Return the 'period' to use for this qset. The minimum interval for
- * the endpoint is used so whatever urbs are submitted the device is
- * polled often enough.
- */
-static int qset_get_period(struct whc *whc, struct whc_qset *qset)
-{
- uint8_t bInterval = qset->ep->desc.bInterval;
-
- if (bInterval < 6)
- bInterval = 6;
- if (bInterval > 10)
- bInterval = 10;
- return bInterval - 6;
-}
-
-static void qset_insert_in_sw_list(struct whc *whc, struct whc_qset *qset)
-{
- int period;
-
- period = qset_get_period(whc, qset);
-
- qset_clear(whc, qset);
- list_move(&qset->list_node, &whc->periodic_list[period]);
- qset->in_sw_list = true;
-}
-
-static void pzl_qset_remove(struct whc *whc, struct whc_qset *qset)
-{
- list_move(&qset->list_node, &whc->periodic_removed_list);
- qset->in_hw_list = false;
- qset->in_sw_list = false;
-}
-
-/**
- * pzl_process_qset - process any recently inactivated or halted qTDs
- * in a qset.
- *
- * After inactive qTDs are removed, new qTDs can be added if the
- * urb queue still contains URBs.
- *
- * Returns the schedule updates required.
- */
-static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset)
-{
- enum whc_update update = 0;
- uint32_t status = 0;
-
- while (qset->ntds) {
- struct whc_qtd *td;
-
- td = &qset->qtd[qset->td_start];
- status = le32_to_cpu(td->status);
-
- /*
- * Nothing to do with a still active qTD.
- */
- if (status & QTD_STS_ACTIVE)
- break;
-
- if (status & QTD_STS_HALTED) {
- /* Ug, an error. */
- process_halted_qtd(whc, qset, td);
- /* A halted qTD always triggers an update
- because the qset was either removed or
- reactivated. */
- update |= WHC_UPDATE_UPDATED;
- goto done;
- }
-
- /* Mmm, a completed qTD. */
- process_inactive_qtd(whc, qset, td);
- }
-
- if (!qset->remove)
- update |= qset_add_qtds(whc, qset);
-
-done:
- /*
- * If there are no qTDs in this qset, remove it from the PZL.
- */
- if (qset->remove && qset->ntds == 0) {
- pzl_qset_remove(whc, qset);
- update |= WHC_UPDATE_REMOVED;
- }
-
- return update;
-}
-
-/**
- * pzl_start - start the periodic schedule
- * @whc: the WHCI host controller
- *
- * The PZL must be valid (e.g., all entries in the list should have
- * the T bit set).
- */
-void pzl_start(struct whc *whc)
-{
- le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE);
-
- whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, WUSBCMD_PERIODIC_EN);
- whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
- WUSBSTS_PERIODIC_SCHED, WUSBSTS_PERIODIC_SCHED,
- 1000, "start PZL");
-}
-
-/**
- * pzl_stop - stop the periodic schedule
- * @whc: the WHCI host controller
- */
-void pzl_stop(struct whc *whc)
-{
- whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, 0);
- whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
- WUSBSTS_PERIODIC_SCHED, 0,
- 1000, "stop PZL");
-}
-
-/**
- * pzl_update - request a PZL update and wait for the hardware to be synced
- * @whc: the WHCI HC
- * @wusbcmd: WUSBCMD value to start the update.
- *
- * If the WUSB HC is inactive (i.e., the PZL is stopped) then the
- * update must be skipped as the hardware may not respond to update
- * requests.
- */
-void pzl_update(struct whc *whc, uint32_t wusbcmd)
-{
- struct wusbhc *wusbhc = &whc->wusbhc;
- long t;
-
- mutex_lock(&wusbhc->mutex);
- if (wusbhc->active) {
- whc_write_wusbcmd(whc, wusbcmd, wusbcmd);
- t = wait_event_timeout(
- whc->periodic_list_wq,
- (le_readl(whc->base + WUSBCMD) & WUSBCMD_PERIODIC_UPDATED) == 0,
- msecs_to_jiffies(1000));
- if (t == 0)
- whc_hw_error(whc, "PZL update timeout");
- }
- mutex_unlock(&wusbhc->mutex);
-}
-
-static void update_pzl_hw_view(struct whc *whc)
-{
- struct whc_qset *qset, *t;
- int period;
- u64 tmp_qh = 0;
-
- for (period = 0; period < 5; period++) {
- list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) {
- whc_qset_set_link_ptr(&qset->qh.link, tmp_qh);
- tmp_qh = qset->qset_dma;
- qset->in_hw_list = true;
- }
- update_pzl_pointers(whc, period, tmp_qh);
- }
-}
-
-/**
- * scan_periodic_work - scan the PZL for qsets to process.
- *
- * Process each qset in the PZL in turn and then signal the WHC that
- * the PZL has been updated.
- *
- * Then start, stop or update the periodic schedule as required.
- */
-void scan_periodic_work(struct work_struct *work)
-{
- struct whc *whc = container_of(work, struct whc, periodic_work);
- struct whc_qset *qset, *t;
- enum whc_update update = 0;
- int period;
-
- spin_lock_irq(&whc->lock);
-
- for (period = 4; period >= 0; period--) {
- list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) {
- if (!qset->in_hw_list)
- update |= WHC_UPDATE_ADDED;
- update |= pzl_process_qset(whc, qset);
- }
- }
-
- if (update & (WHC_UPDATE_ADDED | WHC_UPDATE_REMOVED))
- update_pzl_hw_view(whc);
-
- spin_unlock_irq(&whc->lock);
-
- if (update) {
- uint32_t wusbcmd = WUSBCMD_PERIODIC_UPDATED | WUSBCMD_PERIODIC_SYNCED_DB;
- if (update & WHC_UPDATE_REMOVED)
- wusbcmd |= WUSBCMD_PERIODIC_QSET_RM;
- pzl_update(whc, wusbcmd);
- }
-
- /*
- * Now that the PZL is updated, complete the removal of any
- * removed qsets.
- *
- * If the qset was to be reset, do so and reinsert it into the
- * PZL if it has pending transfers.
- */
- spin_lock_irq(&whc->lock);
-
- list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) {
- qset_remove_complete(whc, qset);
- if (qset->reset) {
- qset_reset(whc, qset);
- if (!list_empty(&qset->stds)) {
- qset_insert_in_sw_list(whc, qset);
- queue_work(whc->workqueue, &whc->periodic_work);
- }
- }
- }
-
- spin_unlock_irq(&whc->lock);
-}
-
-/**
- * pzl_urb_enqueue - queue an URB onto the periodic list (PZL)
- * @whc: the WHCI host controller
- * @urb: the URB to enqueue
- * @mem_flags: flags for any memory allocations
- *
- * The qset for the endpoint is obtained and the urb queued on to it.
- *
- * Work is scheduled to update the hardware's view of the PZL.
- */
-int pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags)
-{
- struct whc_qset *qset;
- int err;
- unsigned long flags;
-
- spin_lock_irqsave(&whc->lock, flags);
-
- err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb);
- if (err < 0) {
- spin_unlock_irqrestore(&whc->lock, flags);
- return err;
- }
-
- qset = get_qset(whc, urb, GFP_ATOMIC);
- if (qset == NULL)
- err = -ENOMEM;
- else
- err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
- if (!err) {
- if (!qset->in_sw_list && !qset->remove)
- qset_insert_in_sw_list(whc, qset);
- } else
- usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb);
-
- spin_unlock_irqrestore(&whc->lock, flags);
-
- if (!err)
- queue_work(whc->workqueue, &whc->periodic_work);
-
- return err;
-}
-
-/**
- * pzl_urb_dequeue - remove an URB (qset) from the periodic list
- * @whc: the WHCI host controller
- * @urb: the URB to dequeue
- * @status: the current status of the URB
- *
- * URBs that do yet have qTDs can simply be removed from the software
- * queue, otherwise the qset must be removed so the qTDs can be safely
- * removed.
- */
-int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
-{
- struct whc_urb *wurb = urb->hcpriv;
- struct whc_qset *qset = wurb->qset;
- struct whc_std *std, *t;
- bool has_qtd = false;
- int ret;
- unsigned long flags;
-
- spin_lock_irqsave(&whc->lock, flags);
-
- ret = usb_hcd_check_unlink_urb(&whc->wusbhc.usb_hcd, urb, status);
- if (ret < 0)
- goto out;
-
- list_for_each_entry_safe(std, t, &qset->stds, list_node) {
- if (std->urb == urb) {
- if (std->qtd)
- has_qtd = true;
- qset_free_std(whc, std);
- } else
- std->qtd = NULL; /* so this std is re-added when the qset is */
- }
-
- if (has_qtd) {
- pzl_qset_remove(whc, qset);
- update_pzl_hw_view(whc);
- wurb->status = status;
- wurb->is_async = false;
- queue_work(whc->workqueue, &wurb->dequeue_work);
- } else
- qset_remove_urb(whc, qset, urb, status);
-out:
- spin_unlock_irqrestore(&whc->lock, flags);
-
- return ret;
-}
-
-/**
- * pzl_qset_delete - delete a qset from the PZL
- */
-void pzl_qset_delete(struct whc *whc, struct whc_qset *qset)
-{
- qset->remove = 1;
- queue_work(whc->workqueue, &whc->periodic_work);
- qset_delete(whc, qset);
-}
-
-/**
- * pzl_init - initialize the periodic zone list
- * @whc: the WHCI host controller
- */
-int pzl_init(struct whc *whc)
-{
- int i;
-
- whc->pz_list = dma_alloc_coherent(&whc->umc->dev, sizeof(u64) * 16,
- &whc->pz_list_dma, GFP_KERNEL);
- if (whc->pz_list == NULL)
- return -ENOMEM;
-
- /* Set T bit on all elements in PZL. */
- for (i = 0; i < 16; i++)
- whc->pz_list[i] = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T);
-
- le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE);
-
- return 0;
-}
-
-/**
- * pzl_clean_up - free PZL resources
- * @whc: the WHCI host controller
- *
- * The PZL is stopped and empty.
- */
-void pzl_clean_up(struct whc *whc)
-{
- if (whc->pz_list)
- dma_free_coherent(&whc->umc->dev, sizeof(u64) * 16, whc->pz_list,
- whc->pz_list_dma);
-}
diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c
deleted file mode 100644
index 925166a..0000000
--- a/drivers/usb/host/whci/qset.c
+++ /dev/null
@@ -1,831 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) qset management.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <linux/uwb/umc.h>
-#include <linux/usb.h>
-
-#include "../../wusbcore/wusbhc.h"
-
-#include "whcd.h"
-
-struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags)
-{
- struct whc_qset *qset;
- dma_addr_t dma;
-
- qset = dma_pool_zalloc(whc->qset_pool, mem_flags, &dma);
- if (qset == NULL)
- return NULL;
-
- qset->qset_dma = dma;
- qset->whc = whc;
-
- INIT_LIST_HEAD(&qset->list_node);
- INIT_LIST_HEAD(&qset->stds);
-
- return qset;
-}
-
-/**
- * qset_fill_qh - fill the static endpoint state in a qset's QHead
- * @qset: the qset whose QH needs initializing with static endpoint
- * state
- * @urb: an urb for a transfer to this endpoint
- */
-static void qset_fill_qh(struct whc *whc, struct whc_qset *qset, struct urb *urb)
-{
- struct usb_device *usb_dev = urb->dev;
- struct wusb_dev *wusb_dev = usb_dev->wusb_dev;
- struct usb_wireless_ep_comp_descriptor *epcd;
- bool is_out;
- uint8_t phy_rate;
-
- is_out = usb_pipeout(urb->pipe);
-
- qset->max_packet = le16_to_cpu(urb->ep->desc.wMaxPacketSize);
-
- epcd = (struct usb_wireless_ep_comp_descriptor *)qset->ep->extra;
- if (epcd) {
- qset->max_seq = epcd->bMaxSequence;
- qset->max_burst = epcd->bMaxBurst;
- } else {
- qset->max_seq = 2;
- qset->max_burst = 1;
- }
-
- /*
- * Initial PHY rate is 53.3 Mbit/s for control endpoints or
- * the maximum supported by the device for other endpoints
- * (unless limited by the user).
- */
- if (usb_pipecontrol(urb->pipe))
- phy_rate = UWB_PHY_RATE_53;
- else {
- uint16_t phy_rates;
-
- phy_rates = le16_to_cpu(wusb_dev->wusb_cap_descr->wPHYRates);
- phy_rate = fls(phy_rates) - 1;
- if (phy_rate > whc->wusbhc.phy_rate)
- phy_rate = whc->wusbhc.phy_rate;
- }
-
- qset->qh.info1 = cpu_to_le32(
- QH_INFO1_EP(usb_pipeendpoint(urb->pipe))
- | (is_out ? QH_INFO1_DIR_OUT : QH_INFO1_DIR_IN)
- | usb_pipe_to_qh_type(urb->pipe)
- | QH_INFO1_DEV_INFO_IDX(wusb_port_no_to_idx(usb_dev->portnum))
- | QH_INFO1_MAX_PKT_LEN(qset->max_packet)
- );
- qset->qh.info2 = cpu_to_le32(
- QH_INFO2_BURST(qset->max_burst)
- | QH_INFO2_DBP(0)
- | QH_INFO2_MAX_COUNT(3)
- | QH_INFO2_MAX_RETRY(3)
- | QH_INFO2_MAX_SEQ(qset->max_seq - 1)
- );
- /* FIXME: where can we obtain these Tx parameters from? Why
- * doesn't the chip know what Tx power to use? It knows the Rx
- * strength and can presumably guess the Tx power required
- * from that? */
- qset->qh.info3 = cpu_to_le32(
- QH_INFO3_TX_RATE(phy_rate)
- | QH_INFO3_TX_PWR(0) /* 0 == max power */
- );
-
- qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1);
-}
-
-/**
- * qset_clear - clear fields in a qset so it may be reinserted into a
- * schedule.
- *
- * The sequence number and current window are not cleared (see
- * qset_reset()).
- */
-void qset_clear(struct whc *whc, struct whc_qset *qset)
-{
- qset->td_start = qset->td_end = qset->ntds = 0;
-
- qset->qh.link = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T);
- qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK;
- qset->qh.err_count = 0;
- qset->qh.scratch[0] = 0;
- qset->qh.scratch[1] = 0;
- qset->qh.scratch[2] = 0;
-
- memset(&qset->qh.overlay, 0, sizeof(qset->qh.overlay));
-
- init_completion(&qset->remove_complete);
-}
-
-/**
- * qset_reset - reset endpoint state in a qset.
- *
- * Clears the sequence number and current window. This qset must not
- * be in the ASL or PZL.
- */
-void qset_reset(struct whc *whc, struct whc_qset *qset)
-{
- qset->reset = 0;
-
- qset->qh.status &= ~QH_STATUS_SEQ_MASK;
- qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1);
-}
-
-/**
- * get_qset - get the qset for an async endpoint
- *
- * A new qset is created if one does not already exist.
- */
-struct whc_qset *get_qset(struct whc *whc, struct urb *urb,
- gfp_t mem_flags)
-{
- struct whc_qset *qset;
-
- qset = urb->ep->hcpriv;
- if (qset == NULL) {
- qset = qset_alloc(whc, mem_flags);
- if (qset == NULL)
- return NULL;
-
- qset->ep = urb->ep;
- urb->ep->hcpriv = qset;
- qset_fill_qh(whc, qset, urb);
- }
- return qset;
-}
-
-void qset_remove_complete(struct whc *whc, struct whc_qset *qset)
-{
- qset->remove = 0;
- list_del_init(&qset->list_node);
- complete(&qset->remove_complete);
-}
-
-/**
- * qset_add_qtds - add qTDs for an URB to a qset
- *
- * Returns true if the list (ASL/PZL) must be updated because (for a
- * WHCI 0.95 controller) an activated qTD was pointed to be iCur.
- */
-enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset)
-{
- struct whc_std *std;
- enum whc_update update = 0;
-
- list_for_each_entry(std, &qset->stds, list_node) {
- struct whc_qtd *qtd;
- uint32_t status;
-
- if (qset->ntds >= WHCI_QSET_TD_MAX
- || (qset->pause_after_urb && std->urb != qset->pause_after_urb))
- break;
-
- if (std->qtd)
- continue; /* already has a qTD */
-
- qtd = std->qtd = &qset->qtd[qset->td_end];
-
- /* Fill in setup bytes for control transfers. */
- if (usb_pipecontrol(std->urb->pipe))
- memcpy(qtd->setup, std->urb->setup_packet, 8);
-
- status = QTD_STS_ACTIVE | QTD_STS_LEN(std->len);
-
- if (whc_std_last(std) && usb_pipeout(std->urb->pipe))
- status |= QTD_STS_LAST_PKT;
-
- /*
- * For an IN transfer the iAlt field should be set so
- * the h/w will automatically advance to the next
- * transfer. However, if there are 8 or more TDs
- * remaining in this transfer then iAlt cannot be set
- * as it could point to somewhere in this transfer.
- */
- if (std->ntds_remaining < WHCI_QSET_TD_MAX) {
- int ialt;
- ialt = (qset->td_end + std->ntds_remaining) % WHCI_QSET_TD_MAX;
- status |= QTD_STS_IALT(ialt);
- } else if (usb_pipein(std->urb->pipe))
- qset->pause_after_urb = std->urb;
-
- if (std->num_pointers)
- qtd->options = cpu_to_le32(QTD_OPT_IOC);
- else
- qtd->options = cpu_to_le32(QTD_OPT_IOC | QTD_OPT_SMALL);
- qtd->page_list_ptr = cpu_to_le64(std->dma_addr);
-
- qtd->status = cpu_to_le32(status);
-
- if (QH_STATUS_TO_ICUR(qset->qh.status) == qset->td_end)
- update = WHC_UPDATE_UPDATED;
-
- if (++qset->td_end >= WHCI_QSET_TD_MAX)
- qset->td_end = 0;
- qset->ntds++;
- }
-
- return update;
-}
-
-/**
- * qset_remove_qtd - remove the first qTD from a qset.
- *
- * The qTD might be still active (if it's part of a IN URB that
- * resulted in a short read) so ensure it's deactivated.
- */
-static void qset_remove_qtd(struct whc *whc, struct whc_qset *qset)
-{
- qset->qtd[qset->td_start].status = 0;
-
- if (++qset->td_start >= WHCI_QSET_TD_MAX)
- qset->td_start = 0;
- qset->ntds--;
-}
-
-static void qset_copy_bounce_to_sg(struct whc *whc, struct whc_std *std)
-{
- struct scatterlist *sg;
- void *bounce;
- size_t remaining, offset;
-
- bounce = std->bounce_buf;
- remaining = std->len;
-
- sg = std->bounce_sg;
- offset = std->bounce_offset;
-
- while (remaining) {
- size_t len;
-
- len = min(sg->length - offset, remaining);
- memcpy(sg_virt(sg) + offset, bounce, len);
-
- bounce += len;
- remaining -= len;
-
- offset += len;
- if (offset >= sg->length) {
- sg = sg_next(sg);
- offset = 0;
- }
- }
-
-}
-
-/**
- * qset_free_std - remove an sTD and free it.
- * @whc: the WHCI host controller
- * @std: the sTD to remove and free.
- */
-void qset_free_std(struct whc *whc, struct whc_std *std)
-{
- list_del(&std->list_node);
- if (std->bounce_buf) {
- bool is_out = usb_pipeout(std->urb->pipe);
- dma_addr_t dma_addr;
-
- if (std->num_pointers)
- dma_addr = le64_to_cpu(std->pl_virt[0].buf_ptr);
- else
- dma_addr = std->dma_addr;
-
- dma_unmap_single(whc->wusbhc.dev, dma_addr,
- std->len, is_out ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- if (!is_out)
- qset_copy_bounce_to_sg(whc, std);
- kfree(std->bounce_buf);
- }
- if (std->pl_virt) {
- if (!dma_mapping_error(whc->wusbhc.dev, std->dma_addr))
- dma_unmap_single(whc->wusbhc.dev, std->dma_addr,
- std->num_pointers * sizeof(struct whc_page_list_entry),
- DMA_TO_DEVICE);
- kfree(std->pl_virt);
- std->pl_virt = NULL;
- }
- kfree(std);
-}
-
-/**
- * qset_remove_qtds - remove an URB's qTDs (and sTDs).
- */
-static void qset_remove_qtds(struct whc *whc, struct whc_qset *qset,
- struct urb *urb)
-{
- struct whc_std *std, *t;
-
- list_for_each_entry_safe(std, t, &qset->stds, list_node) {
- if (std->urb != urb)
- break;
- if (std->qtd != NULL)
- qset_remove_qtd(whc, qset);
- qset_free_std(whc, std);
- }
-}
-
-/**
- * qset_free_stds - free any remaining sTDs for an URB.
- */
-static void qset_free_stds(struct whc_qset *qset, struct urb *urb)
-{
- struct whc_std *std, *t;
-
- list_for_each_entry_safe(std, t, &qset->stds, list_node) {
- if (std->urb == urb)
- qset_free_std(qset->whc, std);
- }
-}
-
-static int qset_fill_page_list(struct whc *whc, struct whc_std *std, gfp_t mem_flags)
-{
- dma_addr_t dma_addr = std->dma_addr;
- dma_addr_t sp, ep;
- size_t pl_len;
- int p;
-
- /* Short buffers don't need a page list. */
- if (std->len <= WHCI_PAGE_SIZE) {
- std->num_pointers = 0;
- return 0;
- }
-
- sp = dma_addr & ~(WHCI_PAGE_SIZE-1);
- ep = dma_addr + std->len;
- std->num_pointers = DIV_ROUND_UP(ep - sp, WHCI_PAGE_SIZE);
-
- pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
- std->pl_virt = kmalloc(pl_len, mem_flags);
- if (std->pl_virt == NULL)
- return -ENOMEM;
- std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt, pl_len, DMA_TO_DEVICE);
- if (dma_mapping_error(whc->wusbhc.dev, std->dma_addr)) {
- kfree(std->pl_virt);
- return -EFAULT;
- }
-
- for (p = 0; p < std->num_pointers; p++) {
- std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr);
- dma_addr = (dma_addr + WHCI_PAGE_SIZE) & ~(WHCI_PAGE_SIZE-1);
- }
-
- return 0;
-}
-
-/**
- * urb_dequeue_work - executes asl/pzl update and gives back the urb to the system.
- */
-static void urb_dequeue_work(struct work_struct *work)
-{
- struct whc_urb *wurb = container_of(work, struct whc_urb, dequeue_work);
- struct whc_qset *qset = wurb->qset;
- struct whc *whc = qset->whc;
- unsigned long flags;
-
- if (wurb->is_async)
- asl_update(whc, WUSBCMD_ASYNC_UPDATED
- | WUSBCMD_ASYNC_SYNCED_DB
- | WUSBCMD_ASYNC_QSET_RM);
- else
- pzl_update(whc, WUSBCMD_PERIODIC_UPDATED
- | WUSBCMD_PERIODIC_SYNCED_DB
- | WUSBCMD_PERIODIC_QSET_RM);
-
- spin_lock_irqsave(&whc->lock, flags);
- qset_remove_urb(whc, qset, wurb->urb, wurb->status);
- spin_unlock_irqrestore(&whc->lock, flags);
-}
-
-static struct whc_std *qset_new_std(struct whc *whc, struct whc_qset *qset,
- struct urb *urb, gfp_t mem_flags)
-{
- struct whc_std *std;
-
- std = kzalloc(sizeof(struct whc_std), mem_flags);
- if (std == NULL)
- return NULL;
-
- std->urb = urb;
- std->qtd = NULL;
-
- INIT_LIST_HEAD(&std->list_node);
- list_add_tail(&std->list_node, &qset->stds);
-
- return std;
-}
-
-static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *urb,
- gfp_t mem_flags)
-{
- size_t remaining;
- struct scatterlist *sg;
- int i;
- int ntds = 0;
- struct whc_std *std = NULL;
- struct whc_page_list_entry *new_pl_virt;
- dma_addr_t prev_end = 0;
- size_t pl_len;
- int p = 0;
-
- remaining = urb->transfer_buffer_length;
-
- for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
- dma_addr_t dma_addr;
- size_t dma_remaining;
- dma_addr_t sp, ep;
- int num_pointers;
-
- if (remaining == 0) {
- break;
- }
-
- dma_addr = sg_dma_address(sg);
- dma_remaining = min_t(size_t, sg_dma_len(sg), remaining);
-
- while (dma_remaining) {
- size_t dma_len;
-
- /*
- * We can use the previous std (if it exists) provided that:
- * - the previous one ended on a page boundary.
- * - the current one begins on a page boundary.
- * - the previous one isn't full.
- *
- * If a new std is needed but the previous one
- * was not a whole number of packets then this
- * sg list cannot be mapped onto multiple
- * qTDs. Return an error and let the caller
- * sort it out.
- */
- if (!std
- || (prev_end & (WHCI_PAGE_SIZE-1))
- || (dma_addr & (WHCI_PAGE_SIZE-1))
- || std->len + WHCI_PAGE_SIZE > QTD_MAX_XFER_SIZE) {
- if (std && std->len % qset->max_packet != 0)
- return -EINVAL;
- std = qset_new_std(whc, qset, urb, mem_flags);
- if (std == NULL) {
- return -ENOMEM;
- }
- ntds++;
- p = 0;
- }
-
- dma_len = dma_remaining;
-
- /*
- * If the remainder of this element doesn't
- * fit in a single qTD, limit the qTD to a
- * whole number of packets. This allows the
- * remainder to go into the next qTD.
- */
- if (std->len + dma_len > QTD_MAX_XFER_SIZE) {
- dma_len = (QTD_MAX_XFER_SIZE / qset->max_packet)
- * qset->max_packet - std->len;
- }
-
- std->len += dma_len;
- std->ntds_remaining = -1; /* filled in later */
-
- sp = dma_addr & ~(WHCI_PAGE_SIZE-1);
- ep = dma_addr + dma_len;
- num_pointers = DIV_ROUND_UP(ep - sp, WHCI_PAGE_SIZE);
- std->num_pointers += num_pointers;
-
- pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
-
- new_pl_virt = krealloc(std->pl_virt, pl_len, mem_flags);
- if (new_pl_virt == NULL) {
- kfree(std->pl_virt);
- std->pl_virt = NULL;
- return -ENOMEM;
- }
- std->pl_virt = new_pl_virt;
-
- for (;p < std->num_pointers; p++) {
- std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr);
- dma_addr = (dma_addr + WHCI_PAGE_SIZE) & ~(WHCI_PAGE_SIZE-1);
- }
-
- prev_end = dma_addr = ep;
- dma_remaining -= dma_len;
- remaining -= dma_len;
- }
- }
-
- /* Now the number of stds is know, go back and fill in
- std->ntds_remaining. */
- list_for_each_entry(std, &qset->stds, list_node) {
- if (std->ntds_remaining == -1) {
- pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
- std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt,
- pl_len, DMA_TO_DEVICE);
- if (dma_mapping_error(whc->wusbhc.dev, std->dma_addr))
- return -EFAULT;
- std->ntds_remaining = ntds--;
- }
- }
- return 0;
-}
-
-/**
- * qset_add_urb_sg_linearize - add an urb with sg list, copying the data
- *
- * If the URB contains an sg list whose elements cannot be directly
- * mapped to qTDs then the data must be transferred via bounce
- * buffers.
- */
-static int qset_add_urb_sg_linearize(struct whc *whc, struct whc_qset *qset,
- struct urb *urb, gfp_t mem_flags)
-{
- bool is_out = usb_pipeout(urb->pipe);
- size_t max_std_len;
- size_t remaining;
- int ntds = 0;
- struct whc_std *std = NULL;
- void *bounce = NULL;
- struct scatterlist *sg;
- int i;
-
- /* limit maximum bounce buffer to 16 * 3.5 KiB ~= 28 k */
- max_std_len = qset->max_burst * qset->max_packet;
-
- remaining = urb->transfer_buffer_length;
-
- for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
- size_t len;
- size_t sg_remaining;
- void *orig;
-
- if (remaining == 0) {
- break;
- }
-
- sg_remaining = min_t(size_t, remaining, sg->length);
- orig = sg_virt(sg);
-
- while (sg_remaining) {
- if (!std || std->len == max_std_len) {
- std = qset_new_std(whc, qset, urb, mem_flags);
- if (std == NULL)
- return -ENOMEM;
- std->bounce_buf = kmalloc(max_std_len, mem_flags);
- if (std->bounce_buf == NULL)
- return -ENOMEM;
- std->bounce_sg = sg;
- std->bounce_offset = orig - sg_virt(sg);
- bounce = std->bounce_buf;
- ntds++;
- }
-
- len = min(sg_remaining, max_std_len - std->len);
-
- if (is_out)
- memcpy(bounce, orig, len);
-
- std->len += len;
- std->ntds_remaining = -1; /* filled in later */
-
- bounce += len;
- orig += len;
- sg_remaining -= len;
- remaining -= len;
- }
- }
-
- /*
- * For each of the new sTDs, map the bounce buffers, create
- * page lists (if necessary), and fill in std->ntds_remaining.
- */
- list_for_each_entry(std, &qset->stds, list_node) {
- if (std->ntds_remaining != -1)
- continue;
-
- std->dma_addr = dma_map_single(&whc->umc->dev, std->bounce_buf, std->len,
- is_out ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- if (dma_mapping_error(&whc->umc->dev, std->dma_addr))
- return -EFAULT;
-
- if (qset_fill_page_list(whc, std, mem_flags) < 0)
- return -ENOMEM;
-
- std->ntds_remaining = ntds--;
- }
-
- return 0;
-}
-
-/**
- * qset_add_urb - add an urb to the qset's queue.
- *
- * The URB is chopped into sTDs, one for each qTD that will required.
- * At least one qTD (and sTD) is required even if the transfer has no
- * data (e.g., for some control transfers).
- */
-int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb,
- gfp_t mem_flags)
-{
- struct whc_urb *wurb;
- int remaining = urb->transfer_buffer_length;
- u64 transfer_dma = urb->transfer_dma;
- int ntds_remaining;
- int ret;
-
- wurb = kzalloc(sizeof(struct whc_urb), mem_flags);
- if (wurb == NULL)
- goto err_no_mem;
- urb->hcpriv = wurb;
- wurb->qset = qset;
- wurb->urb = urb;
- INIT_WORK(&wurb->dequeue_work, urb_dequeue_work);
-
- if (urb->num_sgs) {
- ret = qset_add_urb_sg(whc, qset, urb, mem_flags);
- if (ret == -EINVAL) {
- qset_free_stds(qset, urb);
- ret = qset_add_urb_sg_linearize(whc, qset, urb, mem_flags);
- }
- if (ret < 0)
- goto err_no_mem;
- return 0;
- }
-
- ntds_remaining = DIV_ROUND_UP(remaining, QTD_MAX_XFER_SIZE);
- if (ntds_remaining == 0)
- ntds_remaining = 1;
-
- while (ntds_remaining) {
- struct whc_std *std;
- size_t std_len;
-
- std_len = remaining;
- if (std_len > QTD_MAX_XFER_SIZE)
- std_len = QTD_MAX_XFER_SIZE;
-
- std = qset_new_std(whc, qset, urb, mem_flags);
- if (std == NULL)
- goto err_no_mem;
-
- std->dma_addr = transfer_dma;
- std->len = std_len;
- std->ntds_remaining = ntds_remaining;
-
- if (qset_fill_page_list(whc, std, mem_flags) < 0)
- goto err_no_mem;
-
- ntds_remaining--;
- remaining -= std_len;
- transfer_dma += std_len;
- }
-
- return 0;
-
-err_no_mem:
- qset_free_stds(qset, urb);
- return -ENOMEM;
-}
-
-/**
- * qset_remove_urb - remove an URB from the urb queue.
- *
- * The URB is returned to the USB subsystem.
- */
-void qset_remove_urb(struct whc *whc, struct whc_qset *qset,
- struct urb *urb, int status)
-{
- struct wusbhc *wusbhc = &whc->wusbhc;
- struct whc_urb *wurb = urb->hcpriv;
-
- usb_hcd_unlink_urb_from_ep(&wusbhc->usb_hcd, urb);
- /* Drop the lock as urb->complete() may enqueue another urb. */
- spin_unlock(&whc->lock);
- wusbhc_giveback_urb(wusbhc, urb, status);
- spin_lock(&whc->lock);
-
- kfree(wurb);
-}
-
-/**
- * get_urb_status_from_qtd - get the completed urb status from qTD status
- * @urb: completed urb
- * @status: qTD status
- */
-static int get_urb_status_from_qtd(struct urb *urb, u32 status)
-{
- if (status & QTD_STS_HALTED) {
- if (status & QTD_STS_DBE)
- return usb_pipein(urb->pipe) ? -ENOSR : -ECOMM;
- else if (status & QTD_STS_BABBLE)
- return -EOVERFLOW;
- else if (status & QTD_STS_RCE)
- return -ETIME;
- return -EPIPE;
- }
- if (usb_pipein(urb->pipe)
- && (urb->transfer_flags & URB_SHORT_NOT_OK)
- && urb->actual_length < urb->transfer_buffer_length)
- return -EREMOTEIO;
- return 0;
-}
-
-/**
- * process_inactive_qtd - process an inactive (but not halted) qTD.
- *
- * Update the urb with the transfer bytes from the qTD, if the urb is
- * completely transferred or (in the case of an IN only) the LPF is
- * set, then the transfer is complete and the urb should be returned
- * to the system.
- */
-void process_inactive_qtd(struct whc *whc, struct whc_qset *qset,
- struct whc_qtd *qtd)
-{
- struct whc_std *std = list_first_entry(&qset->stds, struct whc_std, list_node);
- struct urb *urb = std->urb;
- uint32_t status;
- bool complete;
-
- status = le32_to_cpu(qtd->status);
-
- urb->actual_length += std->len - QTD_STS_TO_LEN(status);
-
- if (usb_pipein(urb->pipe) && (status & QTD_STS_LAST_PKT))
- complete = true;
- else
- complete = whc_std_last(std);
-
- qset_remove_qtd(whc, qset);
- qset_free_std(whc, std);
-
- /*
- * Transfers for this URB are complete? Then return it to the
- * USB subsystem.
- */
- if (complete) {
- qset_remove_qtds(whc, qset, urb);
- qset_remove_urb(whc, qset, urb, get_urb_status_from_qtd(urb, status));
-
- /*
- * If iAlt isn't valid then the hardware didn't
- * advance iCur. Adjust the start and end pointers to
- * match iCur.
- */
- if (!(status & QTD_STS_IALT_VALID))
- qset->td_start = qset->td_end
- = QH_STATUS_TO_ICUR(le16_to_cpu(qset->qh.status));
- qset->pause_after_urb = NULL;
- }
-}
-
-/**
- * process_halted_qtd - process a qset with a halted qtd
- *
- * Remove all the qTDs for the failed URB and return the failed URB to
- * the USB subsystem. Then remove all other qTDs so the qset can be
- * removed.
- *
- * FIXME: this is the point where rate adaptation can be done. If a
- * transfer failed because it exceeded the maximum number of retries
- * then it could be reactivated with a slower rate without having to
- * remove the qset.
- */
-void process_halted_qtd(struct whc *whc, struct whc_qset *qset,
- struct whc_qtd *qtd)
-{
- struct whc_std *std = list_first_entry(&qset->stds, struct whc_std, list_node);
- struct urb *urb = std->urb;
- int urb_status;
-
- urb_status = get_urb_status_from_qtd(urb, le32_to_cpu(qtd->status));
-
- qset_remove_qtds(whc, qset, urb);
- qset_remove_urb(whc, qset, urb, urb_status);
-
- list_for_each_entry(std, &qset->stds, list_node) {
- if (qset->ntds == 0)
- break;
- qset_remove_qtd(whc, qset);
- std->qtd = NULL;
- }
-
- qset->remove = 1;
-}
-
-void qset_free(struct whc *whc, struct whc_qset *qset)
-{
- dma_pool_free(whc->qset_pool, qset, qset->qset_dma);
-}
-
-/**
- * qset_delete - wait for a qset to be unused, then free it.
- */
-void qset_delete(struct whc *whc, struct whc_qset *qset)
-{
- wait_for_completion(&qset->remove_complete);
- qset_free(whc, qset);
-}
diff --git a/drivers/usb/host/whci/whcd.h b/drivers/usb/host/whci/whcd.h
deleted file mode 100644
index 1394769..0000000
--- a/drivers/usb/host/whci/whcd.h
+++ /dev/null
@@ -1,202 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) private header.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#ifndef __WHCD_H
-#define __WHCD_H
-
-#include <linux/uwb/whci.h>
-#include <linux/uwb/umc.h>
-#include <linux/workqueue.h>
-
-#include "whci-hc.h"
-
-/* Generic command timeout. */
-#define WHC_GENCMD_TIMEOUT_MS 100
-
-struct whc_dbg;
-
-struct whc {
- struct wusbhc wusbhc;
- struct umc_dev *umc;
-
- resource_size_t base_phys;
- void __iomem *base;
- int irq;
-
- u8 n_devices;
- u8 n_keys;
- u8 n_mmc_ies;
-
- u64 *pz_list;
- struct dn_buf_entry *dn_buf;
- struct di_buf_entry *di_buf;
- dma_addr_t pz_list_dma;
- dma_addr_t dn_buf_dma;
- dma_addr_t di_buf_dma;
-
- spinlock_t lock;
- struct mutex mutex;
-
- void * gen_cmd_buf;
- dma_addr_t gen_cmd_buf_dma;
- wait_queue_head_t cmd_wq;
-
- struct workqueue_struct *workqueue;
- struct work_struct dn_work;
-
- struct dma_pool *qset_pool;
-
- struct list_head async_list;
- struct list_head async_removed_list;
- wait_queue_head_t async_list_wq;
- struct work_struct async_work;
-
- struct list_head periodic_list[5];
- struct list_head periodic_removed_list;
- wait_queue_head_t periodic_list_wq;
- struct work_struct periodic_work;
-
- struct whc_dbg *dbg;
-};
-
-#define wusbhc_to_whc(w) (container_of((w), struct whc, wusbhc))
-
-/**
- * struct whc_std - a software TD.
- * @urb: the URB this sTD is for.
- * @offset: start of the URB's data for this TD.
- * @len: the length of data in the associated TD.
- * @ntds_remaining: number of TDs (starting from this one) in this transfer.
- *
- * @bounce_buf: a bounce buffer if the std was from an urb with a sg
- * list that could not be mapped to qTDs directly.
- * @bounce_sg: the first scatterlist element bounce_buf is for.
- * @bounce_offset: the offset into bounce_sg for the start of bounce_buf.
- *
- * Queued URBs may require more TDs than are available in a qset so we
- * use a list of these "software TDs" (sTDs) to hold per-TD data.
- */
-struct whc_std {
- struct urb *urb;
- size_t len;
- int ntds_remaining;
- struct whc_qtd *qtd;
-
- struct list_head list_node;
- int num_pointers;
- dma_addr_t dma_addr;
- struct whc_page_list_entry *pl_virt;
-
- void *bounce_buf;
- struct scatterlist *bounce_sg;
- unsigned bounce_offset;
-};
-
-/**
- * struct whc_urb - per URB host controller structure.
- * @urb: the URB this struct is for.
- * @qset: the qset associated to the URB.
- * @dequeue_work: the work to remove the URB when dequeued.
- * @is_async: the URB belongs to async sheduler or not.
- * @status: the status to be returned when calling wusbhc_giveback_urb.
- */
-struct whc_urb {
- struct urb *urb;
- struct whc_qset *qset;
- struct work_struct dequeue_work;
- bool is_async;
- int status;
-};
-
-/**
- * whc_std_last - is this sTD the URB's last?
- * @std: the sTD to check.
- */
-static inline bool whc_std_last(struct whc_std *std)
-{
- return std->ntds_remaining <= 1;
-}
-
-enum whc_update {
- WHC_UPDATE_ADDED = 0x01,
- WHC_UPDATE_REMOVED = 0x02,
- WHC_UPDATE_UPDATED = 0x04,
-};
-
-/* init.c */
-int whc_init(struct whc *whc);
-void whc_clean_up(struct whc *whc);
-
-/* hw.c */
-void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val);
-int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len);
-void whc_hw_error(struct whc *whc, const char *reason);
-
-/* wusb.c */
-int whc_wusbhc_start(struct wusbhc *wusbhc);
-void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay);
-int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
- u8 handle, struct wuie_hdr *wuie);
-int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle);
-int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm);
-int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev);
-int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots);
-int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
- const void *ptk, size_t key_size);
-int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid,
- const void *gtk, size_t key_size);
-int whc_set_cluster_id(struct whc *whc, u8 bcid);
-
-/* int.c */
-irqreturn_t whc_int_handler(struct usb_hcd *hcd);
-void whc_dn_work(struct work_struct *work);
-
-/* asl.c */
-void asl_start(struct whc *whc);
-void asl_stop(struct whc *whc);
-int asl_init(struct whc *whc);
-void asl_clean_up(struct whc *whc);
-int asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags);
-int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status);
-void asl_qset_delete(struct whc *whc, struct whc_qset *qset);
-void scan_async_work(struct work_struct *work);
-
-/* pzl.c */
-int pzl_init(struct whc *whc);
-void pzl_clean_up(struct whc *whc);
-void pzl_start(struct whc *whc);
-void pzl_stop(struct whc *whc);
-int pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags);
-int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status);
-void pzl_qset_delete(struct whc *whc, struct whc_qset *qset);
-void scan_periodic_work(struct work_struct *work);
-
-/* qset.c */
-struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags);
-void qset_free(struct whc *whc, struct whc_qset *qset);
-struct whc_qset *get_qset(struct whc *whc, struct urb *urb, gfp_t mem_flags);
-void qset_delete(struct whc *whc, struct whc_qset *qset);
-void qset_clear(struct whc *whc, struct whc_qset *qset);
-void qset_reset(struct whc *whc, struct whc_qset *qset);
-int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb,
- gfp_t mem_flags);
-void qset_free_std(struct whc *whc, struct whc_std *std);
-void qset_remove_urb(struct whc *whc, struct whc_qset *qset,
- struct urb *urb, int status);
-void process_halted_qtd(struct whc *whc, struct whc_qset *qset,
- struct whc_qtd *qtd);
-void process_inactive_qtd(struct whc *whc, struct whc_qset *qset,
- struct whc_qtd *qtd);
-enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset);
-void qset_remove_complete(struct whc *whc, struct whc_qset *qset);
-void pzl_update(struct whc *whc, uint32_t wusbcmd);
-void asl_update(struct whc *whc, uint32_t wusbcmd);
-
-/* debug.c */
-void whc_dbg_init(struct whc *whc);
-void whc_dbg_clean_up(struct whc *whc);
-
-#endif /* #ifndef __WHCD_H */
diff --git a/drivers/usb/host/whci/whci-hc.h b/drivers/usb/host/whci/whci-hc.h
deleted file mode 100644
index 5a86a57..0000000
--- a/drivers/usb/host/whci/whci-hc.h
+++ /dev/null
@@ -1,401 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) data structures.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#ifndef _WHCI_WHCI_HC_H
-#define _WHCI_WHCI_HC_H
-
-#include <linux/list.h>
-
-/**
- * WHCI_PAGE_SIZE - page size use by WHCI
- *
- * WHCI assumes that host system uses pages of 4096 octets.
- */
-#define WHCI_PAGE_SIZE 4096
-
-
-/**
- * QTD_MAX_TXFER_SIZE - max number of bytes to transfer with a single
- * qtd.
- *
- * This is 2^20 - 1.
- */
-#define QTD_MAX_XFER_SIZE 1048575
-
-
-/**
- * struct whc_qtd - Queue Element Transfer Descriptors (qTD)
- *
- * This describes the data for a bulk, control or interrupt transfer.
- *
- * [WHCI] section 3.2.4
- */
-struct whc_qtd {
- __le32 status; /*< remaining transfer len and transfer status */
- __le32 options;
- __le64 page_list_ptr; /*< physical pointer to data buffer page list*/
- __u8 setup[8]; /*< setup data for control transfers */
-} __attribute__((packed));
-
-#define QTD_STS_ACTIVE (1 << 31) /* enable execution of transaction */
-#define QTD_STS_HALTED (1 << 30) /* transfer halted */
-#define QTD_STS_DBE (1 << 29) /* data buffer error */
-#define QTD_STS_BABBLE (1 << 28) /* babble detected */
-#define QTD_STS_RCE (1 << 27) /* retry count exceeded */
-#define QTD_STS_LAST_PKT (1 << 26) /* set Last Packet Flag in WUSB header */
-#define QTD_STS_INACTIVE (1 << 25) /* queue set is marked inactive */
-#define QTD_STS_IALT_VALID (1 << 23) /* iAlt field is valid */
-#define QTD_STS_IALT(i) (QTD_STS_IALT_VALID | ((i) << 20)) /* iAlt field */
-#define QTD_STS_LEN(l) ((l) << 0) /* transfer length */
-#define QTD_STS_TO_LEN(s) ((s) & 0x000fffff)
-
-#define QTD_OPT_IOC (1 << 1) /* page_list_ptr points to buffer directly */
-#define QTD_OPT_SMALL (1 << 0) /* interrupt on complete */
-
-/**
- * struct whc_itd - Isochronous Queue Element Transfer Descriptors (iTD)
- *
- * This describes the data and other parameters for an isochronous
- * transfer.
- *
- * [WHCI] section 3.2.5
- */
-struct whc_itd {
- __le16 presentation_time; /*< presentation time for OUT transfers */
- __u8 num_segments; /*< number of data segments in segment list */
- __u8 status; /*< command execution status */
- __le32 options; /*< misc transfer options */
- __le64 page_list_ptr; /*< physical pointer to data buffer page list */
- __le64 seg_list_ptr; /*< physical pointer to segment list */
-} __attribute__((packed));
-
-#define ITD_STS_ACTIVE (1 << 7) /* enable execution of transaction */
-#define ITD_STS_DBE (1 << 5) /* data buffer error */
-#define ITD_STS_BABBLE (1 << 4) /* babble detected */
-#define ITD_STS_INACTIVE (1 << 1) /* queue set is marked inactive */
-
-#define ITD_OPT_IOC (1 << 1) /* interrupt on complete */
-#define ITD_OPT_SMALL (1 << 0) /* page_list_ptr points to buffer directly */
-
-/**
- * Page list entry.
- *
- * A TD's page list must contain sufficient page list entries for the
- * total data length in the TD.
- *
- * [WHCI] section 3.2.4.3
- */
-struct whc_page_list_entry {
- __le64 buf_ptr; /*< physical pointer to buffer */
-} __attribute__((packed));
-
-/**
- * struct whc_seg_list_entry - Segment list entry.
- *
- * Describes a portion of the data buffer described in the containing
- * qTD's page list.
- *
- * seg_ptr = qtd->page_list_ptr[qtd->seg_list_ptr[seg].idx].buf_ptr
- * + qtd->seg_list_ptr[seg].offset;
- *
- * Segments can't cross page boundries.
- *
- * [WHCI] section 3.2.5.5
- */
-struct whc_seg_list_entry {
- __le16 len; /*< segment length */
- __u8 idx; /*< index into page list */
- __u8 status; /*< segment status */
- __le16 offset; /*< 12 bit offset into page */
-} __attribute__((packed));
-
-/**
- * struct whc_qhead - endpoint and status information for a qset.
- *
- * [WHCI] section 3.2.6
- */
-struct whc_qhead {
- __le64 link; /*< next qset in list */
- __le32 info1;
- __le32 info2;
- __le32 info3;
- __le16 status;
- __le16 err_count; /*< transaction error count */
- __le32 cur_window;
- __le32 scratch[3]; /*< h/w scratch area */
- union {
- struct whc_qtd qtd;
- struct whc_itd itd;
- } overlay;
-} __attribute__((packed));
-
-#define QH_LINK_PTR_MASK (~0x03Full)
-#define QH_LINK_PTR(ptr) ((ptr) & QH_LINK_PTR_MASK)
-#define QH_LINK_IQS (1 << 4) /* isochronous queue set */
-#define QH_LINK_NTDS(n) (((n) - 1) << 1) /* number of TDs in queue set */
-#define QH_LINK_T (1 << 0) /* last queue set in periodic schedule list */
-
-#define QH_INFO1_EP(e) ((e) << 0) /* endpoint number */
-#define QH_INFO1_DIR_IN (1 << 4) /* IN transfer */
-#define QH_INFO1_DIR_OUT (0 << 4) /* OUT transfer */
-#define QH_INFO1_TR_TYPE_CTRL (0x0 << 5) /* control transfer */
-#define QH_INFO1_TR_TYPE_ISOC (0x1 << 5) /* isochronous transfer */
-#define QH_INFO1_TR_TYPE_BULK (0x2 << 5) /* bulk transfer */
-#define QH_INFO1_TR_TYPE_INT (0x3 << 5) /* interrupt */
-#define QH_INFO1_TR_TYPE_LP_INT (0x7 << 5) /* low power interrupt */
-#define QH_INFO1_DEV_INFO_IDX(i) ((i) << 8) /* index into device info buffer */
-#define QH_INFO1_SET_INACTIVE (1 << 15) /* set inactive after transfer */
-#define QH_INFO1_MAX_PKT_LEN(l) ((l) << 16) /* maximum packet length */
-
-#define QH_INFO2_BURST(b) ((b) << 0) /* maximum burst length */
-#define QH_INFO2_DBP(p) ((p) << 5) /* data burst policy (see [WUSB] table 5-7) */
-#define QH_INFO2_MAX_COUNT(c) ((c) << 8) /* max isoc/int pkts per zone */
-#define QH_INFO2_RQS (1 << 15) /* reactivate queue set */
-#define QH_INFO2_MAX_RETRY(r) ((r) << 16) /* maximum transaction retries */
-#define QH_INFO2_MAX_SEQ(s) ((s) << 20) /* maximum sequence number */
-#define QH_INFO3_MAX_DELAY(d) ((d) << 0) /* maximum stream delay in 125 us units (isoc only) */
-#define QH_INFO3_INTERVAL(i) ((i) << 16) /* segment interval in 125 us units (isoc only) */
-
-#define QH_INFO3_TX_RATE(r) ((r) << 24) /* PHY rate (see [ECMA-368] section 10.3.1.1) */
-#define QH_INFO3_TX_PWR(p) ((p) << 29) /* transmit power (see [WUSB] section 5.2.1.2) */
-
-#define QH_STATUS_FLOW_CTRL (1 << 15)
-#define QH_STATUS_ICUR(i) ((i) << 5)
-#define QH_STATUS_TO_ICUR(s) (((s) >> 5) & 0x7)
-#define QH_STATUS_SEQ_MASK 0x1f
-
-/**
- * usb_pipe_to_qh_type - USB core pipe type to QH transfer type
- *
- * Returns the QH type field for a USB core pipe type.
- */
-static inline unsigned usb_pipe_to_qh_type(unsigned pipe)
-{
- static const unsigned type[] = {
- [PIPE_ISOCHRONOUS] = QH_INFO1_TR_TYPE_ISOC,
- [PIPE_INTERRUPT] = QH_INFO1_TR_TYPE_INT,
- [PIPE_CONTROL] = QH_INFO1_TR_TYPE_CTRL,
- [PIPE_BULK] = QH_INFO1_TR_TYPE_BULK,
- };
- return type[usb_pipetype(pipe)];
-}
-
-/**
- * Maxiumum number of TDs in a qset.
- */
-#define WHCI_QSET_TD_MAX 8
-
-/**
- * struct whc_qset - WUSB data transfers to a specific endpoint
- * @qh: the QHead of this qset
- * @qtd: up to 8 qTDs (for qsets for control, bulk and interrupt
- * transfers)
- * @itd: up to 8 iTDs (for qsets for isochronous transfers)
- * @qset_dma: DMA address for this qset
- * @whc: WHCI HC this qset is for
- * @ep: endpoint
- * @stds: list of sTDs queued to this qset
- * @ntds: number of qTDs queued (not necessarily the same as nTDs
- * field in the QH)
- * @td_start: index of the first qTD in the list
- * @td_end: index of next free qTD in the list (provided
- * ntds < WHCI_QSET_TD_MAX)
- *
- * Queue Sets (qsets) are added to the asynchronous schedule list
- * (ASL) or the periodic zone list (PZL).
- *
- * qsets may contain up to 8 TDs (either qTDs or iTDs as appropriate).
- * Each TD may refer to at most 1 MiB of data. If a single transfer
- * has > 8MiB of data, TDs can be reused as they are completed since
- * the TD list is used as a circular buffer. Similarly, several
- * (smaller) transfers may be queued in a qset.
- *
- * WHCI controllers may cache portions of the qsets in the ASL and
- * PZL, requiring the WHCD to inform the WHC that the lists have been
- * updated (fields changed or qsets inserted or removed). For safe
- * insertion and removal of qsets from the lists the schedule must be
- * stopped to avoid races in updating the QH link pointers.
- *
- * Since the HC is free to execute qsets in any order, all transfers
- * to an endpoint should use the same qset to ensure transfers are
- * executed in the order they're submitted.
- *
- * [WHCI] section 3.2.3
- */
-struct whc_qset {
- struct whc_qhead qh;
- union {
- struct whc_qtd qtd[WHCI_QSET_TD_MAX];
- struct whc_itd itd[WHCI_QSET_TD_MAX];
- };
-
- /* private data for WHCD */
- dma_addr_t qset_dma;
- struct whc *whc;
- struct usb_host_endpoint *ep;
- struct list_head stds;
- int ntds;
- int td_start;
- int td_end;
- struct list_head list_node;
- unsigned in_sw_list:1;
- unsigned in_hw_list:1;
- unsigned remove:1;
- unsigned reset:1;
- struct urb *pause_after_urb;
- struct completion remove_complete;
- uint16_t max_packet;
- uint8_t max_burst;
- uint8_t max_seq;
-};
-
-static inline void whc_qset_set_link_ptr(u64 *ptr, u64 target)
-{
- if (target)
- *ptr = (*ptr & ~(QH_LINK_PTR_MASK | QH_LINK_T)) | QH_LINK_PTR(target);
- else
- *ptr = QH_LINK_T;
-}
-
-/**
- * struct di_buf_entry - Device Information (DI) buffer entry.
- *
- * There's one of these per connected device.
- */
-struct di_buf_entry {
- __le32 availability_info[8]; /*< MAS availability information, one MAS per bit */
- __le32 addr_sec_info; /*< addressing and security info */
- __le32 reserved[7];
-} __attribute__((packed));
-
-#define WHC_DI_SECURE (1 << 31)
-#define WHC_DI_DISABLE (1 << 30)
-#define WHC_DI_KEY_IDX(k) ((k) << 8)
-#define WHC_DI_KEY_IDX_MASK 0x0000ff00
-#define WHC_DI_DEV_ADDR(a) ((a) << 0)
-#define WHC_DI_DEV_ADDR_MASK 0x000000ff
-
-/**
- * struct dn_buf_entry - Device Notification (DN) buffer entry.
- *
- * [WHCI] section 3.2.8
- */
-struct dn_buf_entry {
- __u8 msg_size; /*< number of octets of valid DN data */
- __u8 reserved1;
- __u8 src_addr; /*< source address */
- __u8 status; /*< buffer entry status */
- __le32 tkid; /*< TKID for source device, valid if secure bit is set */
- __u8 dn_data[56]; /*< up to 56 octets of DN data */
-} __attribute__((packed));
-
-#define WHC_DN_STATUS_VALID (1 << 7) /* buffer entry is valid */
-#define WHC_DN_STATUS_SECURE (1 << 6) /* notification received using secure frame */
-
-#define WHC_N_DN_ENTRIES (4096 / sizeof(struct dn_buf_entry))
-
-/* The Add MMC IE WUSB Generic Command may take up to 256 bytes of
- data. [WHCI] section 2.4.7. */
-#define WHC_GEN_CMD_DATA_LEN 256
-
-/*
- * HC registers.
- *
- * [WHCI] section 2.4
- */
-
-#define WHCIVERSION 0x00
-
-#define WHCSPARAMS 0x04
-# define WHCSPARAMS_TO_N_MMC_IES(p) (((p) >> 16) & 0xff)
-# define WHCSPARAMS_TO_N_KEYS(p) (((p) >> 8) & 0xff)
-# define WHCSPARAMS_TO_N_DEVICES(p) (((p) >> 0) & 0x7f)
-
-#define WUSBCMD 0x08
-# define WUSBCMD_BCID(b) ((b) << 16)
-# define WUSBCMD_BCID_MASK (0xff << 16)
-# define WUSBCMD_ASYNC_QSET_RM (1 << 12)
-# define WUSBCMD_PERIODIC_QSET_RM (1 << 11)
-# define WUSBCMD_WUSBSI(s) ((s) << 8)
-# define WUSBCMD_WUSBSI_MASK (0x7 << 8)
-# define WUSBCMD_ASYNC_SYNCED_DB (1 << 7)
-# define WUSBCMD_PERIODIC_SYNCED_DB (1 << 6)
-# define WUSBCMD_ASYNC_UPDATED (1 << 5)
-# define WUSBCMD_PERIODIC_UPDATED (1 << 4)
-# define WUSBCMD_ASYNC_EN (1 << 3)
-# define WUSBCMD_PERIODIC_EN (1 << 2)
-# define WUSBCMD_WHCRESET (1 << 1)
-# define WUSBCMD_RUN (1 << 0)
-
-#define WUSBSTS 0x0c
-# define WUSBSTS_ASYNC_SCHED (1 << 15)
-# define WUSBSTS_PERIODIC_SCHED (1 << 14)
-# define WUSBSTS_DNTS_SCHED (1 << 13)
-# define WUSBSTS_HCHALTED (1 << 12)
-# define WUSBSTS_GEN_CMD_DONE (1 << 9)
-# define WUSBSTS_CHAN_TIME_ROLLOVER (1 << 8)
-# define WUSBSTS_DNTS_OVERFLOW (1 << 7)
-# define WUSBSTS_BPST_ADJUSTMENT_CHANGED (1 << 6)
-# define WUSBSTS_HOST_ERR (1 << 5)
-# define WUSBSTS_ASYNC_SCHED_SYNCED (1 << 4)
-# define WUSBSTS_PERIODIC_SCHED_SYNCED (1 << 3)
-# define WUSBSTS_DNTS_INT (1 << 2)
-# define WUSBSTS_ERR_INT (1 << 1)
-# define WUSBSTS_INT (1 << 0)
-# define WUSBSTS_INT_MASK 0x3ff
-
-#define WUSBINTR 0x10
-# define WUSBINTR_GEN_CMD_DONE (1 << 9)
-# define WUSBINTR_CHAN_TIME_ROLLOVER (1 << 8)
-# define WUSBINTR_DNTS_OVERFLOW (1 << 7)
-# define WUSBINTR_BPST_ADJUSTMENT_CHANGED (1 << 6)
-# define WUSBINTR_HOST_ERR (1 << 5)
-# define WUSBINTR_ASYNC_SCHED_SYNCED (1 << 4)
-# define WUSBINTR_PERIODIC_SCHED_SYNCED (1 << 3)
-# define WUSBINTR_DNTS_INT (1 << 2)
-# define WUSBINTR_ERR_INT (1 << 1)
-# define WUSBINTR_INT (1 << 0)
-# define WUSBINTR_ALL 0x3ff
-
-#define WUSBGENCMDSTS 0x14
-# define WUSBGENCMDSTS_ACTIVE (1 << 31)
-# define WUSBGENCMDSTS_ERROR (1 << 24)
-# define WUSBGENCMDSTS_IOC (1 << 23)
-# define WUSBGENCMDSTS_MMCIE_ADD 0x01
-# define WUSBGENCMDSTS_MMCIE_RM 0x02
-# define WUSBGENCMDSTS_SET_MAS 0x03
-# define WUSBGENCMDSTS_CHAN_STOP 0x04
-# define WUSBGENCMDSTS_RWP_EN 0x05
-
-#define WUSBGENCMDPARAMS 0x18
-#define WUSBGENADDR 0x20
-#define WUSBASYNCLISTADDR 0x28
-#define WUSBDNTSBUFADDR 0x30
-#define WUSBDEVICEINFOADDR 0x38
-
-#define WUSBSETSECKEYCMD 0x40
-# define WUSBSETSECKEYCMD_SET (1 << 31)
-# define WUSBSETSECKEYCMD_ERASE (1 << 30)
-# define WUSBSETSECKEYCMD_GTK (1 << 8)
-# define WUSBSETSECKEYCMD_IDX(i) ((i) << 0)
-
-#define WUSBTKID 0x44
-#define WUSBSECKEY 0x48
-#define WUSBPERIODICLISTBASE 0x58
-#define WUSBMASINDEX 0x60
-
-#define WUSBDNTSCTRL 0x64
-# define WUSBDNTSCTRL_ACTIVE (1 << 31)
-# define WUSBDNTSCTRL_INTERVAL(i) ((i) << 8)
-# define WUSBDNTSCTRL_SLOTS(s) ((s) << 0)
-
-#define WUSBTIME 0x68
-# define WUSBTIME_CHANNEL_TIME_MASK 0x00ffffff
-
-#define WUSBBPST 0x6c
-#define WUSBDIBUPDATED 0x70
-
-#endif /* #ifndef _WHCI_WHCI_HC_H */
diff --git a/drivers/usb/host/whci/wusb.c b/drivers/usb/host/whci/wusb.c
deleted file mode 100644
index 8a4d805..0000000
--- a/drivers/usb/host/whci/wusb.c
+++ /dev/null
@@ -1,210 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) WUSB operations.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/uwb/umc.h>
-
-#include "../../wusbcore/wusbhc.h"
-
-#include "whcd.h"
-
-static int whc_update_di(struct whc *whc, int idx)
-{
- int offset = idx / 32;
- u32 bit = 1 << (idx % 32);
-
- le_writel(bit, whc->base + WUSBDIBUPDATED + offset);
-
- return whci_wait_for(&whc->umc->dev,
- whc->base + WUSBDIBUPDATED + offset, bit, 0,
- 100, "DI update");
-}
-
-/*
- * WHCI starts MMCs based on there being a valid GTK so these need
- * only start/stop the asynchronous and periodic schedules and send a
- * channel stop command.
- */
-
-int whc_wusbhc_start(struct wusbhc *wusbhc)
-{
- struct whc *whc = wusbhc_to_whc(wusbhc);
-
- asl_start(whc);
- pzl_start(whc);
-
- return 0;
-}
-
-void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay)
-{
- struct whc *whc = wusbhc_to_whc(wusbhc);
- u32 stop_time, now_time;
- int ret;
-
- pzl_stop(whc);
- asl_stop(whc);
-
- now_time = le_readl(whc->base + WUSBTIME) & WUSBTIME_CHANNEL_TIME_MASK;
- stop_time = (now_time + ((delay * 8) << 7)) & 0x00ffffff;
- ret = whc_do_gencmd(whc, WUSBGENCMDSTS_CHAN_STOP, stop_time, NULL, 0);
- if (ret == 0)
- msleep(delay);
-}
-
-int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
- u8 handle, struct wuie_hdr *wuie)
-{
- struct whc *whc = wusbhc_to_whc(wusbhc);
- u32 params;
-
- params = (interval << 24)
- | (repeat_cnt << 16)
- | (wuie->bLength << 8)
- | handle;
-
- return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_ADD, params, wuie, wuie->bLength);
-}
-
-int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle)
-{
- struct whc *whc = wusbhc_to_whc(wusbhc);
- u32 params;
-
- params = handle;
-
- return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_RM, params, NULL, 0);
-}
-
-int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm)
-{
- struct whc *whc = wusbhc_to_whc(wusbhc);
-
- if (stream_index >= 0)
- whc_write_wusbcmd(whc, WUSBCMD_WUSBSI_MASK, WUSBCMD_WUSBSI(stream_index));
-
- return whc_do_gencmd(whc, WUSBGENCMDSTS_SET_MAS, 0, (void *)mas_bm, sizeof(*mas_bm));
-}
-
-int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
-{
- struct whc *whc = wusbhc_to_whc(wusbhc);
- int idx = wusb_dev->port_idx;
- struct di_buf_entry *di = &whc->di_buf[idx];
- int ret;
-
- mutex_lock(&whc->mutex);
-
- uwb_mas_bm_copy_le(di->availability_info, &wusb_dev->availability);
- di->addr_sec_info &= ~(WHC_DI_DISABLE | WHC_DI_DEV_ADDR_MASK);
- di->addr_sec_info |= WHC_DI_DEV_ADDR(wusb_dev->addr);
-
- ret = whc_update_di(whc, idx);
-
- mutex_unlock(&whc->mutex);
-
- return ret;
-}
-
-/*
- * Set the number of Device Notification Time Slots (DNTS) and enable
- * device notifications.
- */
-int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots)
-{
- struct whc *whc = wusbhc_to_whc(wusbhc);
- u32 dntsctrl;
-
- dntsctrl = WUSBDNTSCTRL_ACTIVE
- | WUSBDNTSCTRL_INTERVAL(interval)
- | WUSBDNTSCTRL_SLOTS(slots);
-
- le_writel(dntsctrl, whc->base + WUSBDNTSCTRL);
-
- return 0;
-}
-
-static int whc_set_key(struct whc *whc, u8 key_index, uint32_t tkid,
- const void *key, size_t key_size, bool is_gtk)
-{
- uint32_t setkeycmd;
- uint32_t seckey[4];
- int i;
- int ret;
-
- memcpy(seckey, key, key_size);
- setkeycmd = WUSBSETSECKEYCMD_SET | WUSBSETSECKEYCMD_IDX(key_index);
- if (is_gtk)
- setkeycmd |= WUSBSETSECKEYCMD_GTK;
-
- le_writel(tkid, whc->base + WUSBTKID);
- for (i = 0; i < 4; i++)
- le_writel(seckey[i], whc->base + WUSBSECKEY + 4*i);
- le_writel(setkeycmd, whc->base + WUSBSETSECKEYCMD);
-
- ret = whci_wait_for(&whc->umc->dev, whc->base + WUSBSETSECKEYCMD,
- WUSBSETSECKEYCMD_SET, 0, 100, "set key");
-
- return ret;
-}
-
-/**
- * whc_set_ptk - set the PTK to use for a device.
- *
- * The index into the key table for this PTK is the same as the
- * device's port index.
- */
-int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
- const void *ptk, size_t key_size)
-{
- struct whc *whc = wusbhc_to_whc(wusbhc);
- struct di_buf_entry *di = &whc->di_buf[port_idx];
- int ret;
-
- mutex_lock(&whc->mutex);
-
- if (ptk) {
- ret = whc_set_key(whc, port_idx, tkid, ptk, key_size, false);
- if (ret)
- goto out;
-
- di->addr_sec_info &= ~WHC_DI_KEY_IDX_MASK;
- di->addr_sec_info |= WHC_DI_SECURE | WHC_DI_KEY_IDX(port_idx);
- } else
- di->addr_sec_info &= ~WHC_DI_SECURE;
-
- ret = whc_update_di(whc, port_idx);
-out:
- mutex_unlock(&whc->mutex);
- return ret;
-}
-
-/**
- * whc_set_gtk - set the GTK for subsequent broadcast packets
- *
- * The GTK is stored in the last entry in the key table (the previous
- * N_DEVICES entries are for the per-device PTKs).
- */
-int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid,
- const void *gtk, size_t key_size)
-{
- struct whc *whc = wusbhc_to_whc(wusbhc);
- int ret;
-
- mutex_lock(&whc->mutex);
-
- ret = whc_set_key(whc, whc->n_devices, tkid, gtk, key_size, true);
-
- mutex_unlock(&whc->mutex);
-
- return ret;
-}
-
-int whc_set_cluster_id(struct whc *whc, u8 bcid)
-{
- whc_write_wusbcmd(whc, WUSBCMD_BCID_MASK, WUSBCMD_BCID(bcid));
- return 0;
-}
diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c
index 86cff5c..93e2cca 100644
--- a/drivers/usb/host/xhci-dbgcap.c
+++ b/drivers/usb/host/xhci-dbgcap.c
@@ -22,7 +22,6 @@
vaddr = dma_alloc_coherent(xhci_to_hcd(xhci)->self.sysdev,
size, dma_handle, flags);
- memset(vaddr, 0, size);
return vaddr;
}
@@ -181,7 +180,7 @@
xhci_dbc_flush_single_request(req);
}
-static void xhci_dbc_flush_reqests(struct xhci_dbc *dbc)
+static void xhci_dbc_flush_requests(struct xhci_dbc *dbc)
{
xhci_dbc_flush_endpoint_requests(&dbc->eps[BULK_OUT]);
xhci_dbc_flush_endpoint_requests(&dbc->eps[BULK_IN]);
@@ -421,8 +420,6 @@
string_length = xhci_dbc_populate_strings(dbc->string);
xhci_dbc_init_contexts(xhci, string_length);
- mmiowb();
-
xhci_dbc_eps_init(xhci);
dbc->state = DS_INITIALIZED;
@@ -516,7 +513,6 @@
return -1;
writel(0, &dbc->regs->control);
- xhci_dbc_mem_cleanup(xhci);
dbc->state = DS_DISABLED;
return 0;
@@ -562,8 +558,10 @@
ret = xhci_do_dbc_stop(xhci);
spin_unlock_irqrestore(&dbc->lock, flags);
- if (!ret)
+ if (!ret) {
+ xhci_dbc_mem_cleanup(xhci);
pm_runtime_put_sync(xhci_to_hcd(xhci)->self.controller);
+ }
}
static void
@@ -687,7 +685,7 @@
!(portsc & DBC_PORTSC_CONN_STATUS)) {
xhci_info(xhci, "DbC cable unplugged\n");
dbc->state = DS_ENABLED;
- xhci_dbc_flush_reqests(dbc);
+ xhci_dbc_flush_requests(dbc);
return EVT_DISC;
}
@@ -697,7 +695,7 @@
xhci_info(xhci, "DbC port reset\n");
writel(portsc, &dbc->regs->portsc);
dbc->state = DS_ENABLED;
- xhci_dbc_flush_reqests(dbc);
+ xhci_dbc_flush_requests(dbc);
return EVT_DISC;
}
diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c
index aff79ff..be726c7 100644
--- a/drivers/usb/host/xhci-dbgtty.c
+++ b/drivers/usb/host/xhci-dbgtty.c
@@ -139,14 +139,14 @@
struct dbc_request *req;
for (i = 0; i < DBC_QUEUE_SIZE; i++) {
- req = dbc_alloc_request(dep, GFP_ATOMIC);
+ req = dbc_alloc_request(dep, GFP_KERNEL);
if (!req)
break;
req->length = DBC_MAX_PACKET;
req->buf = kmalloc(req->length, GFP_KERNEL);
if (!req->buf) {
- xhci_dbc_free_req(dep, req);
+ dbc_free_request(dep, req);
break;
}
diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
index cadc013..76c3f29 100644
--- a/drivers/usb/host/xhci-debugfs.c
+++ b/drivers/usb/host/xhci-debugfs.c
@@ -202,10 +202,10 @@
trb = &seg->trbs[i];
dma = seg->dma + i * sizeof(*trb);
seq_printf(s, "%pad: %s\n", &dma,
- xhci_decode_trb(trb->generic.field[0],
- trb->generic.field[1],
- trb->generic.field[2],
- trb->generic.field[3]));
+ xhci_decode_trb(le32_to_cpu(trb->generic.field[0]),
+ le32_to_cpu(trb->generic.field[1]),
+ le32_to_cpu(trb->generic.field[2]),
+ le32_to_cpu(trb->generic.field[3])));
}
}
@@ -263,10 +263,10 @@
xhci = hcd_to_xhci(bus_to_hcd(dev->udev->bus));
slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx);
seq_printf(s, "%pad: %s\n", &dev->out_ctx->dma,
- xhci_decode_slot_context(slot_ctx->dev_info,
- slot_ctx->dev_info2,
- slot_ctx->tt_info,
- slot_ctx->dev_state));
+ xhci_decode_slot_context(le32_to_cpu(slot_ctx->dev_info),
+ le32_to_cpu(slot_ctx->dev_info2),
+ le32_to_cpu(slot_ctx->tt_info),
+ le32_to_cpu(slot_ctx->dev_state)));
return 0;
}
@@ -286,10 +286,10 @@
ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, dci);
dma = dev->out_ctx->dma + dci * CTX_SIZE(xhci->hcc_params);
seq_printf(s, "%pad: %s\n", &dma,
- xhci_decode_ep_context(ep_ctx->ep_info,
- ep_ctx->ep_info2,
- ep_ctx->deq,
- ep_ctx->tx_info));
+ xhci_decode_ep_context(le32_to_cpu(ep_ctx->ep_info),
+ le32_to_cpu(ep_ctx->ep_info2),
+ le64_to_cpu(ep_ctx->deq),
+ le32_to_cpu(ep_ctx->tx_info)));
}
return 0;
@@ -440,6 +440,9 @@
struct xhci_ep_priv *epriv;
struct xhci_slot_priv *spriv = dev->debugfs_private;
+ if (!spriv)
+ return;
+
if (spriv->eps[ep_index])
return;
diff --git a/drivers/usb/host/xhci-debugfs.h b/drivers/usb/host/xhci-debugfs.h
index ac5bc40..f7a4e24 100644
--- a/drivers/usb/host/xhci-debugfs.h
+++ b/drivers/usb/host/xhci-debugfs.h
@@ -80,7 +80,6 @@
char name[DEBUGFS_NAMELEN];
struct debugfs_regset32 regset;
size_t nregs;
- struct dentry *parent;
struct list_head list;
};
diff --git a/drivers/usb/host/xhci-ext-caps.c b/drivers/usb/host/xhci-ext-caps.c
index 399113f..3351d07 100644
--- a/drivers/usb/host/xhci-ext-caps.c
+++ b/drivers/usb/host/xhci-ext-caps.c
@@ -6,11 +6,20 @@
*/
#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/pci.h>
#include "xhci.h"
#define USB_SW_DRV_NAME "intel_xhci_usb_sw"
#define USB_SW_RESOURCE_SIZE 0x400
+#define PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI 0x22b5
+
+static const struct property_entry role_switch_props[] = {
+ PROPERTY_ENTRY_BOOL("sw_switch_disable"),
+ {},
+};
+
static void xhci_intel_unregister_pdev(void *arg)
{
platform_device_unregister(arg);
@@ -21,6 +30,7 @@
struct usb_hcd *hcd = xhci_to_hcd(xhci);
struct device *dev = hcd->self.controller;
struct platform_device *pdev;
+ struct pci_dev *pci = to_pci_dev(dev);
struct resource res = { 0, };
int ret;
@@ -43,6 +53,15 @@
return ret;
}
+ if (pci->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) {
+ ret = platform_device_add_properties(pdev, role_switch_props);
+ if (ret) {
+ dev_err(dev, "failed to register device properties\n");
+ platform_device_put(pdev);
+ return ret;
+ }
+ }
+
pdev->dev.parent = dev;
ret = platform_device_add(pdev);
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 01b5818..b7d23c4 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -487,8 +487,8 @@
/* Write 1 to disable the port */
writel(port_status | PORT_PE, addr);
port_status = readl(addr);
- xhci_dbg(xhci, "disable port, actual port %d status = 0x%x\n",
- wIndex, port_status);
+ xhci_dbg(xhci, "disable port %d-%d, portsc: 0x%x\n",
+ hcd->self.busnum, wIndex + 1, port_status);
}
static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
@@ -537,8 +537,9 @@
/* Change bits are all write 1 to clear */
writel(port_status | status, addr);
port_status = readl(addr);
- xhci_dbg(xhci, "clear port %s change, actual port %d status = 0x%x\n",
- port_change_bit, wIndex, port_status);
+
+ xhci_dbg(xhci, "clear port%d %s change, portsc: 0x%x\n",
+ wIndex + 1, port_change_bit, port_status);
}
struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd)
@@ -565,13 +566,16 @@
rhub = xhci_get_rhub(hcd);
port = rhub->ports[index];
temp = readl(port->addr);
+
+ xhci_dbg(xhci, "set port power %d-%d %s, portsc: 0x%x\n",
+ hcd->self.busnum, index + 1, on ? "ON" : "OFF", temp);
+
temp = xhci_port_state_to_neutral(temp);
+
if (on) {
/* Power on */
writel(temp | PORT_POWER, port->addr);
- temp = readl(port->addr);
- xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n",
- index, temp);
+ readl(port->addr);
} else {
/* Power off */
writel(temp & ~PORT_POWER, port->addr);
@@ -666,12 +670,17 @@
u32 link_state)
{
u32 temp;
+ u32 portsc;
- temp = readl(port->addr);
- temp = xhci_port_state_to_neutral(temp);
+ portsc = readl(port->addr);
+ temp = xhci_port_state_to_neutral(portsc);
temp &= ~PORT_PLS_MASK;
temp |= PORT_LINK_STROBE | link_state;
writel(temp, port->addr);
+
+ xhci_dbg(xhci, "Set port %d-%d link state, portsc: 0x%x, write 0x%x",
+ port->rhub->hcd->self.busnum, port->hcd_portnum + 1,
+ portsc, temp);
}
static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
@@ -714,13 +723,6 @@
}
}
-/* Updates Link Status for USB 2.1 port */
-static void xhci_hub_report_usb2_link_state(u32 *status, u32 status_reg)
-{
- if ((status_reg & PORT_PLS_MASK) == XDEV_U2)
- *status |= USB_PORT_STAT_L1;
-}
-
/* Updates Link Status for super Speed port */
static void xhci_hub_report_usb3_link_state(struct xhci_hcd *xhci,
u32 *status, u32 status_reg)
@@ -802,6 +804,101 @@
}
}
+static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
+ u32 *status, u32 portsc,
+ unsigned long flags)
+{
+ struct xhci_bus_state *bus_state;
+ struct xhci_hcd *xhci;
+ struct usb_hcd *hcd;
+ int slot_id;
+ u32 wIndex;
+
+ hcd = port->rhub->hcd;
+ bus_state = &port->rhub->bus_state;
+ xhci = hcd_to_xhci(hcd);
+ wIndex = port->hcd_portnum;
+
+ if ((portsc & PORT_RESET) || !(portsc & PORT_PE)) {
+ *status = 0xffffffff;
+ return -EINVAL;
+ }
+ /* did port event handler already start resume timing? */
+ if (!bus_state->resume_done[wIndex]) {
+ /* If not, maybe we are in a host initated resume? */
+ if (test_bit(wIndex, &bus_state->resuming_ports)) {
+ /* Host initated resume doesn't time the resume
+ * signalling using resume_done[].
+ * It manually sets RESUME state, sleeps 20ms
+ * and sets U0 state. This should probably be
+ * changed, but not right now.
+ */
+ } else {
+ /* port resume was discovered now and here,
+ * start resume timing
+ */
+ unsigned long timeout = jiffies +
+ msecs_to_jiffies(USB_RESUME_TIMEOUT);
+
+ set_bit(wIndex, &bus_state->resuming_ports);
+ bus_state->resume_done[wIndex] = timeout;
+ mod_timer(&hcd->rh_timer, timeout);
+ usb_hcd_start_port_resume(&hcd->self, wIndex);
+ }
+ /* Has resume been signalled for USB_RESUME_TIME yet? */
+ } else if (time_after_eq(jiffies, bus_state->resume_done[wIndex])) {
+ int time_left;
+
+ xhci_dbg(xhci, "resume USB2 port %d-%d\n",
+ hcd->self.busnum, wIndex + 1);
+
+ bus_state->resume_done[wIndex] = 0;
+ clear_bit(wIndex, &bus_state->resuming_ports);
+
+ set_bit(wIndex, &bus_state->rexit_ports);
+
+ xhci_test_and_clear_bit(xhci, port, PORT_PLC);
+ xhci_set_link_state(xhci, port, XDEV_U0);
+
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ time_left = wait_for_completion_timeout(
+ &bus_state->rexit_done[wIndex],
+ msecs_to_jiffies(XHCI_MAX_REXIT_TIMEOUT_MS));
+ spin_lock_irqsave(&xhci->lock, flags);
+
+ if (time_left) {
+ slot_id = xhci_find_slot_id_by_port(hcd, xhci,
+ wIndex + 1);
+ if (!slot_id) {
+ xhci_dbg(xhci, "slot_id is zero\n");
+ *status = 0xffffffff;
+ return -ENODEV;
+ }
+ xhci_ring_device(xhci, slot_id);
+ } else {
+ int port_status = readl(port->addr);
+
+ xhci_warn(xhci, "Port resume timed out, port %d-%d: 0x%x\n",
+ hcd->self.busnum, wIndex + 1, port_status);
+ *status |= USB_PORT_STAT_SUSPEND;
+ clear_bit(wIndex, &bus_state->rexit_ports);
+ }
+
+ usb_hcd_end_port_resume(&hcd->self, wIndex);
+ bus_state->port_c_suspend |= 1 << wIndex;
+ bus_state->suspended_ports &= ~(1 << wIndex);
+ } else {
+ /*
+ * The resume has been signaling for less than
+ * USB_RESUME_TIME. Report the port status as SUSPEND,
+ * let the usbcore check port status again and clear
+ * resume signaling later.
+ */
+ *status |= USB_PORT_STAT_SUSPEND;
+ }
+ return 0;
+}
+
static u32 xhci_get_ext_port_status(u32 raw_port_status, u32 port_li)
{
u32 ext_stat = 0;
@@ -818,6 +915,85 @@
return ext_stat;
}
+static void xhci_get_usb3_port_status(struct xhci_port *port, u32 *status,
+ u32 portsc)
+{
+ struct xhci_bus_state *bus_state;
+ struct xhci_hcd *xhci;
+ u32 link_state;
+ u32 portnum;
+
+ bus_state = &port->rhub->bus_state;
+ xhci = hcd_to_xhci(port->rhub->hcd);
+ link_state = portsc & PORT_PLS_MASK;
+ portnum = port->hcd_portnum;
+
+ /* USB3 specific wPortChange bits
+ *
+ * Port link change with port in resume state should not be
+ * reported to usbcore, as this is an internal state to be
+ * handled by xhci driver. Reporting PLC to usbcore may
+ * cause usbcore clearing PLC first and port change event
+ * irq won't be generated.
+ */
+
+ if (portsc & PORT_PLC && (link_state != XDEV_RESUME))
+ *status |= USB_PORT_STAT_C_LINK_STATE << 16;
+ if (portsc & PORT_WRC)
+ *status |= USB_PORT_STAT_C_BH_RESET << 16;
+ if (portsc & PORT_CEC)
+ *status |= USB_PORT_STAT_C_CONFIG_ERROR << 16;
+
+ /* USB3 specific wPortStatus bits */
+ if (portsc & PORT_POWER) {
+ *status |= USB_SS_PORT_STAT_POWER;
+ /* link state handling */
+ if (link_state == XDEV_U0)
+ bus_state->suspended_ports &= ~(1 << portnum);
+ }
+
+ xhci_hub_report_usb3_link_state(xhci, status, portsc);
+ xhci_del_comp_mod_timer(xhci, portsc, portnum);
+}
+
+static void xhci_get_usb2_port_status(struct xhci_port *port, u32 *status,
+ u32 portsc, unsigned long flags)
+{
+ struct xhci_bus_state *bus_state;
+ u32 link_state;
+ u32 portnum;
+ int ret;
+
+ bus_state = &port->rhub->bus_state;
+ link_state = portsc & PORT_PLS_MASK;
+ portnum = port->hcd_portnum;
+
+ /* USB2 wPortStatus bits */
+ if (portsc & PORT_POWER) {
+ *status |= USB_PORT_STAT_POWER;
+
+ /* link state is only valid if port is powered */
+ if (link_state == XDEV_U3)
+ *status |= USB_PORT_STAT_SUSPEND;
+ if (link_state == XDEV_U2)
+ *status |= USB_PORT_STAT_L1;
+ if (link_state == XDEV_U0) {
+ bus_state->resume_done[portnum] = 0;
+ clear_bit(portnum, &bus_state->resuming_ports);
+ if (bus_state->suspended_ports & (1 << portnum)) {
+ bus_state->suspended_ports &= ~(1 << portnum);
+ bus_state->port_c_suspend |= 1 << portnum;
+ }
+ }
+ if (link_state == XDEV_RESUME) {
+ ret = xhci_handle_usb2_port_link_resume(port, status,
+ portsc, flags);
+ if (ret)
+ return;
+ }
+ }
+}
+
/*
* Converts a raw xHCI port status into the format that external USB 2.0 or USB
* 3.0 hubs use.
@@ -835,16 +1011,14 @@
__releases(&xhci->lock)
__acquires(&xhci->lock)
{
- struct xhci_hcd *xhci = hcd_to_xhci(hcd);
u32 status = 0;
- int slot_id;
struct xhci_hub *rhub;
struct xhci_port *port;
rhub = xhci_get_rhub(hcd);
port = rhub->ports[wIndex];
- /* wPortChange bits */
+ /* common wPortChange bits */
if (raw_port_status & PORT_CSC)
status |= USB_PORT_STAT_C_CONNECTION << 16;
if (raw_port_status & PORT_PEC)
@@ -853,107 +1027,25 @@
status |= USB_PORT_STAT_C_OVERCURRENT << 16;
if ((raw_port_status & PORT_RC))
status |= USB_PORT_STAT_C_RESET << 16;
- /* USB3.0 only */
- if (hcd->speed >= HCD_USB3) {
- /* Port link change with port in resume state should not be
- * reported to usbcore, as this is an internal state to be
- * handled by xhci driver. Reporting PLC to usbcore may
- * cause usbcore clearing PLC first and port change event
- * irq won't be generated.
- */
- if ((raw_port_status & PORT_PLC) &&
- (raw_port_status & PORT_PLS_MASK) != XDEV_RESUME)
- status |= USB_PORT_STAT_C_LINK_STATE << 16;
- if ((raw_port_status & PORT_WRC))
- status |= USB_PORT_STAT_C_BH_RESET << 16;
- if ((raw_port_status & PORT_CEC))
- status |= USB_PORT_STAT_C_CONFIG_ERROR << 16;
+
+ /* common wPortStatus bits */
+ if (raw_port_status & PORT_CONNECT) {
+ status |= USB_PORT_STAT_CONNECTION;
+ status |= xhci_port_speed(raw_port_status);
}
+ if (raw_port_status & PORT_PE)
+ status |= USB_PORT_STAT_ENABLE;
+ if (raw_port_status & PORT_OC)
+ status |= USB_PORT_STAT_OVERCURRENT;
+ if (raw_port_status & PORT_RESET)
+ status |= USB_PORT_STAT_RESET;
- if (hcd->speed < HCD_USB3) {
- if ((raw_port_status & PORT_PLS_MASK) == XDEV_U3
- && (raw_port_status & PORT_POWER))
- status |= USB_PORT_STAT_SUSPEND;
- }
- if ((raw_port_status & PORT_PLS_MASK) == XDEV_RESUME &&
- !DEV_SUPERSPEED_ANY(raw_port_status) && hcd->speed < HCD_USB3) {
- if ((raw_port_status & PORT_RESET) ||
- !(raw_port_status & PORT_PE))
- return 0xffffffff;
- /* did port event handler already start resume timing? */
- if (!bus_state->resume_done[wIndex]) {
- /* If not, maybe we are in a host initated resume? */
- if (test_bit(wIndex, &bus_state->resuming_ports)) {
- /* Host initated resume doesn't time the resume
- * signalling using resume_done[].
- * It manually sets RESUME state, sleeps 20ms
- * and sets U0 state. This should probably be
- * changed, but not right now.
- */
- } else {
- /* port resume was discovered now and here,
- * start resume timing
- */
- unsigned long timeout = jiffies +
- msecs_to_jiffies(USB_RESUME_TIMEOUT);
-
- set_bit(wIndex, &bus_state->resuming_ports);
- bus_state->resume_done[wIndex] = timeout;
- mod_timer(&hcd->rh_timer, timeout);
- usb_hcd_start_port_resume(&hcd->self, wIndex);
- }
- /* Has resume been signalled for USB_RESUME_TIME yet? */
- } else if (time_after_eq(jiffies,
- bus_state->resume_done[wIndex])) {
- int time_left;
-
- xhci_dbg(xhci, "Resume USB2 port %d\n",
- wIndex + 1);
- bus_state->resume_done[wIndex] = 0;
- clear_bit(wIndex, &bus_state->resuming_ports);
-
- set_bit(wIndex, &bus_state->rexit_ports);
-
- xhci_test_and_clear_bit(xhci, port, PORT_PLC);
- xhci_set_link_state(xhci, port, XDEV_U0);
-
- spin_unlock_irqrestore(&xhci->lock, flags);
- time_left = wait_for_completion_timeout(
- &bus_state->rexit_done[wIndex],
- msecs_to_jiffies(
- XHCI_MAX_REXIT_TIMEOUT_MS));
- spin_lock_irqsave(&xhci->lock, flags);
-
- if (time_left) {
- slot_id = xhci_find_slot_id_by_port(hcd,
- xhci, wIndex + 1);
- if (!slot_id) {
- xhci_dbg(xhci, "slot_id is zero\n");
- return 0xffffffff;
- }
- xhci_ring_device(xhci, slot_id);
- } else {
- int port_status = readl(port->addr);
- xhci_warn(xhci, "Port resume took longer than %i msec, port status = 0x%x\n",
- XHCI_MAX_REXIT_TIMEOUT_MS,
- port_status);
- status |= USB_PORT_STAT_SUSPEND;
- clear_bit(wIndex, &bus_state->rexit_ports);
- }
-
- usb_hcd_end_port_resume(&hcd->self, wIndex);
- bus_state->port_c_suspend |= 1 << wIndex;
- bus_state->suspended_ports &= ~(1 << wIndex);
- } else {
- /*
- * The resume has been signaling for less than
- * USB_RESUME_TIME. Report the port status as SUSPEND,
- * let the usbcore check port status again and clear
- * resume signaling later.
- */
- status |= USB_PORT_STAT_SUSPEND;
- }
- }
+ /* USB2 and USB3 specific bits, including Port Link State */
+ if (hcd->speed >= HCD_USB3)
+ xhci_get_usb3_port_status(port, &status, raw_port_status);
+ else
+ xhci_get_usb2_port_status(port, &status, raw_port_status,
+ flags);
/*
* Clear stale usb2 resume signalling variables in case port changed
* state during resume signalling. For example on error
@@ -967,44 +1059,6 @@
usb_hcd_end_port_resume(&hcd->self, wIndex);
}
-
- if ((raw_port_status & PORT_PLS_MASK) == XDEV_U0 &&
- (raw_port_status & PORT_POWER)) {
- if (bus_state->suspended_ports & (1 << wIndex)) {
- bus_state->suspended_ports &= ~(1 << wIndex);
- if (hcd->speed < HCD_USB3)
- bus_state->port_c_suspend |= 1 << wIndex;
- }
- bus_state->resume_done[wIndex] = 0;
- clear_bit(wIndex, &bus_state->resuming_ports);
- }
- if (raw_port_status & PORT_CONNECT) {
- status |= USB_PORT_STAT_CONNECTION;
- status |= xhci_port_speed(raw_port_status);
- }
- if (raw_port_status & PORT_PE)
- status |= USB_PORT_STAT_ENABLE;
- if (raw_port_status & PORT_OC)
- status |= USB_PORT_STAT_OVERCURRENT;
- if (raw_port_status & PORT_RESET)
- status |= USB_PORT_STAT_RESET;
- if (raw_port_status & PORT_POWER) {
- if (hcd->speed >= HCD_USB3)
- status |= USB_SS_PORT_STAT_POWER;
- else
- status |= USB_PORT_STAT_POWER;
- }
- /* Update Port Link State */
- if (hcd->speed >= HCD_USB3) {
- xhci_hub_report_usb3_link_state(xhci, &status, raw_port_status);
- /*
- * Verify if all USB3 Ports Have entered U0 already.
- * Delete Compliance Mode Timer if so.
- */
- xhci_del_comp_mod_timer(xhci, raw_port_status, wIndex);
- } else {
- xhci_hub_report_usb2_link_state(&status, raw_port_status);
- }
if (bus_state->port_c_suspend & (1 << wIndex))
status |= USB_PORT_STAT_C_SUSPEND << 16;
@@ -1031,7 +1085,7 @@
rhub = xhci_get_rhub(hcd);
ports = rhub->ports;
max_ports = rhub->num_ports;
- bus_state = &xhci->bus_state[hcd_index(hcd)];
+ bus_state = &rhub->bus_state;
spin_lock_irqsave(&xhci->lock, flags);
switch (typeReq) {
@@ -1080,9 +1134,8 @@
if (status == 0xffffffff)
goto error;
- xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n",
- wIndex, temp);
- xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
+ xhci_dbg(xhci, "Get port status %d-%d read: 0x%x, return 0x%x",
+ hcd->self.busnum, wIndex + 1, temp, status);
put_unaligned(cpu_to_le32(status), (__le32 *) buf);
/* if USB 3.1 extended port status return additional 4 bytes */
@@ -1096,7 +1149,7 @@
}
port_li = readl(ports[wIndex]->addr + PORTLI);
status = xhci_get_ext_port_status(temp, port_li);
- put_unaligned_le32(cpu_to_le32(status), &buf[4]);
+ put_unaligned_le32(status, &buf[4]);
}
break;
case SetPortFeature:
@@ -1138,7 +1191,8 @@
temp = readl(ports[wIndex]->addr);
if ((temp & PORT_PE) == 0 || (temp & PORT_RESET)
|| (temp & PORT_PLS_MASK) >= XDEV_U3) {
- xhci_warn(xhci, "USB core suspending device not in U0/U1/U2.\n");
+ xhci_warn(xhci, "USB core suspending port %d-%d not in U0/U1/U2\n",
+ hcd->self.busnum, wIndex + 1);
goto error;
}
@@ -1421,7 +1475,7 @@
rhub = xhci_get_rhub(hcd);
ports = rhub->ports;
max_ports = rhub->num_ports;
- bus_state = &xhci->bus_state[hcd_index(hcd)];
+ bus_state = &rhub->bus_state;
/* Initial status is no changes */
retval = (max_ports + 8) / 8;
@@ -1480,7 +1534,7 @@
rhub = xhci_get_rhub(hcd);
ports = rhub->ports;
max_ports = rhub->num_ports;
- bus_state = &xhci->bus_state[hcd_index(hcd)];
+ bus_state = &rhub->bus_state;
wake_enabled = hcd->self.root_hub->do_remote_wakeup;
spin_lock_irqsave(&xhci->lock, flags);
@@ -1501,20 +1555,25 @@
port_index = max_ports;
while (port_index--) {
u32 t1, t2;
-
+ int retries = 10;
+retry:
t1 = readl(ports[port_index]->addr);
t2 = xhci_port_state_to_neutral(t1);
portsc_buf[port_index] = 0;
- /* Bail out if a USB3 port has a new device in link training */
- if ((hcd->speed >= HCD_USB3) &&
+ /*
+ * Give a USB3 port in link training time to finish, but don't
+ * prevent suspend as port might be stuck
+ */
+ if ((hcd->speed >= HCD_USB3) && retries-- &&
(t1 & PORT_PLS_MASK) == XDEV_POLLING) {
- bus_state->bus_suspended = 0;
spin_unlock_irqrestore(&xhci->lock, flags);
- xhci_dbg(xhci, "Bus suspend bailout, port in polling\n");
- return -EBUSY;
+ msleep(XHCI_PORT_POLLING_LFPS_TIME);
+ spin_lock_irqsave(&xhci->lock, flags);
+ xhci_dbg(xhci, "port %d polling in bus suspend, waiting\n",
+ port_index);
+ goto retry;
}
-
/* suspend ports in U0, or bail out for new connect changes */
if ((t1 & PORT_PE) && (t1 & PORT_PLS_MASK) == XDEV_U0) {
if ((t1 & PORT_CSC) && wake_enabled) {
@@ -1623,7 +1682,7 @@
rhub = xhci_get_rhub(hcd);
ports = rhub->ports;
max_ports = rhub->num_ports;
- bus_state = &xhci->bus_state[hcd_index(hcd)];
+ bus_state = &rhub->bus_state;
if (time_before(jiffies, bus_state->next_statechange))
msleep(5);
@@ -1724,13 +1783,10 @@
unsigned long xhci_get_resuming_ports(struct usb_hcd *hcd)
{
- struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- struct xhci_bus_state *bus_state;
-
- bus_state = &xhci->bus_state[hcd_index(hcd)];
+ struct xhci_hub *rhub = xhci_get_rhub(hcd);
/* USB3 port wakeups are reported via usb_wakeup_notification() */
- return bus_state->resuming_ports; /* USB2 ports only */
+ return rhub->bus_state.resuming_ports; /* USB2 ports only */
}
#endif /* CONFIG_PM */
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index b1f27aa..e16eda6 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -933,7 +933,7 @@
* that tt_info, then free the child first. Recursive.
* We can't rely on udev at this point to find child-parent relationships.
*/
-void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_id)
+static void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_id)
{
struct xhci_virt_device *vdev;
struct list_head *tt_list_head;
@@ -1672,8 +1672,8 @@
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 = dma_zalloc_coherent(dev, xhci->page_size, &dma,
- flags);
+ void *buf = dma_alloc_coherent(dev, xhci->page_size, &dma,
+ flags);
if (!buf)
goto fail_sp4;
@@ -1799,8 +1799,8 @@
struct xhci_erst_entry *entry;
size = sizeof(struct xhci_erst_entry) * evt_ring->num_segs;
- erst->entries = dma_zalloc_coherent(xhci_to_hcd(xhci)->self.sysdev,
- size, &erst->erst_dma_addr, flags);
+ erst->entries = dma_alloc_coherent(xhci_to_hcd(xhci)->self.sysdev,
+ size, &erst->erst_dma_addr, flags);
if (!erst->entries)
return -ENOMEM;
@@ -1922,8 +1922,8 @@
xhci->page_size = 0;
xhci->page_shift = 0;
- xhci->bus_state[0].bus_suspended = 0;
- xhci->bus_state[1].bus_suspended = 0;
+ xhci->usb2_rhub.bus_state.bus_suspended = 0;
+ xhci->usb3_rhub.bus_state.bus_suspended = 0;
}
static int xhci_test_trb_in_td(struct xhci_hcd *xhci,
@@ -2181,23 +2181,11 @@
if (major_revision < 0x03 && xhci->num_ext_caps < max_caps)
xhci->ext_caps[xhci->num_ext_caps++] = temp;
- /* Check the host's USB2 LPM capability */
- if ((xhci->hci_version == 0x96) && (major_revision != 0x03) &&
- (temp & XHCI_L1C)) {
+ if ((xhci->hci_version >= 0x100) && (major_revision != 0x03) &&
+ (temp & XHCI_HLC)) {
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "xHCI 0.96: support USB2 software lpm");
- xhci->sw_lpm_support = 1;
- }
-
- if ((xhci->hci_version >= 0x100) && (major_revision != 0x03)) {
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "xHCI 1.0: support USB2 software lpm");
- xhci->sw_lpm_support = 1;
- if (temp & XHCI_HLC) {
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "xHCI 1.0: support USB2 hardware lpm");
- xhci->hw_lpm_support = 1;
- }
+ "xHCI 1.0: support USB2 hardware lpm");
+ xhci->hw_lpm_support = 1;
}
port_offset--;
@@ -2411,7 +2399,6 @@
flags);
if (!xhci->dcbaa)
goto fail;
- memset(xhci->dcbaa, 0, sizeof *(xhci->dcbaa));
xhci->dcbaa->dma = dma;
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"// Device context base array address = 0x%llx (DMA), %p (virt)",
@@ -2536,10 +2523,10 @@
for (i = 0; i < MAX_HC_SLOTS; i++)
xhci->devs[i] = NULL;
for (i = 0; i < USB_MAXCHILDREN; i++) {
- xhci->bus_state[0].resume_done[i] = 0;
- xhci->bus_state[1].resume_done[i] = 0;
+ xhci->usb2_rhub.bus_state.resume_done[i] = 0;
+ xhci->usb3_rhub.bus_state.resume_done[i] = 0;
/* Only the USB 2.0 completions will ever be used. */
- init_completion(&xhci->bus_state[1].rexit_done[i]);
+ init_completion(&xhci->usb2_rhub.bus_state.rexit_done[i]);
}
if (scratchpad_alloc(xhci, flags))
diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index fa33d6e..fea5555 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -13,14 +13,20 @@
#include "xhci.h"
#include "xhci-mtk.h"
+#define SSP_BW_BOUNDARY 130000
#define SS_BW_BOUNDARY 51000
/* table 5-5. High-speed Isoc Transaction Limits in usb_20 spec */
#define HS_BW_BOUNDARY 6144
/* usb2 spec section11.18.1: at most 188 FS bytes per microframe */
#define FS_PAYLOAD_MAX 188
+/*
+ * max number of microframes for split transfer,
+ * for fs isoc in : 1 ss + 1 idle + 7 cs
+ */
+#define TT_MICROFRAMES_MAX 9
/* mtk scheduler bitmasks */
-#define EP_BPKTS(p) ((p) & 0x3f)
+#define EP_BPKTS(p) ((p) & 0x7f)
#define EP_BCSCOUNT(p) (((p) & 0x7) << 8)
#define EP_BBM(p) ((p) << 11)
#define EP_BOFFSET(p) ((p) & 0x3fff)
@@ -51,7 +57,7 @@
virt_dev = xhci->devs[udev->slot_id];
- if (udev->speed == USB_SPEED_SUPER) {
+ if (udev->speed >= USB_SPEED_SUPER) {
if (usb_endpoint_dir_out(&ep->desc))
bw_index = (virt_dev->real_port - 1) * 2;
else
@@ -64,25 +70,167 @@
return bw_index;
}
+static u32 get_esit(struct xhci_ep_ctx *ep_ctx)
+{
+ u32 esit;
+
+ esit = 1 << CTX_TO_EP_INTERVAL(le32_to_cpu(ep_ctx->ep_info));
+ if (esit > XHCI_MTK_MAX_ESIT)
+ esit = XHCI_MTK_MAX_ESIT;
+
+ return esit;
+}
+
+static struct mu3h_sch_tt *find_tt(struct usb_device *udev)
+{
+ struct usb_tt *utt = udev->tt;
+ struct mu3h_sch_tt *tt, **tt_index, **ptt;
+ unsigned int port;
+ bool allocated_index = false;
+
+ if (!utt)
+ return NULL; /* Not below a TT */
+
+ /*
+ * Find/create our data structure.
+ * For hubs with a single TT, we get it directly.
+ * For hubs with multiple TTs, there's an extra level of pointers.
+ */
+ tt_index = NULL;
+ if (utt->multi) {
+ tt_index = utt->hcpriv;
+ if (!tt_index) { /* Create the index array */
+ tt_index = kcalloc(utt->hub->maxchild,
+ sizeof(*tt_index), GFP_KERNEL);
+ if (!tt_index)
+ return ERR_PTR(-ENOMEM);
+ utt->hcpriv = tt_index;
+ allocated_index = true;
+ }
+ port = udev->ttport - 1;
+ ptt = &tt_index[port];
+ } else {
+ port = 0;
+ ptt = (struct mu3h_sch_tt **) &utt->hcpriv;
+ }
+
+ tt = *ptt;
+ if (!tt) { /* Create the mu3h_sch_tt */
+ tt = kzalloc(sizeof(*tt), GFP_KERNEL);
+ if (!tt) {
+ if (allocated_index) {
+ utt->hcpriv = NULL;
+ kfree(tt_index);
+ }
+ return ERR_PTR(-ENOMEM);
+ }
+ INIT_LIST_HEAD(&tt->ep_list);
+ tt->usb_tt = utt;
+ tt->tt_port = port;
+ *ptt = tt;
+ }
+
+ return tt;
+}
+
+/* Release the TT above udev, if it's not in use */
+static void drop_tt(struct usb_device *udev)
+{
+ struct usb_tt *utt = udev->tt;
+ struct mu3h_sch_tt *tt, **tt_index, **ptt;
+ int i, cnt;
+
+ if (!utt || !utt->hcpriv)
+ return; /* Not below a TT, or never allocated */
+
+ cnt = 0;
+ if (utt->multi) {
+ tt_index = utt->hcpriv;
+ ptt = &tt_index[udev->ttport - 1];
+ /* How many entries are left in tt_index? */
+ for (i = 0; i < utt->hub->maxchild; ++i)
+ cnt += !!tt_index[i];
+ } else {
+ tt_index = NULL;
+ ptt = (struct mu3h_sch_tt **)&utt->hcpriv;
+ }
+
+ tt = *ptt;
+ if (!tt || !list_empty(&tt->ep_list))
+ return; /* never allocated , or still in use*/
+
+ *ptt = NULL;
+ kfree(tt);
+
+ if (cnt == 1) {
+ utt->hcpriv = NULL;
+ kfree(tt_index);
+ }
+}
+
+static struct mu3h_sch_ep_info *create_sch_ep(struct usb_device *udev,
+ struct usb_host_endpoint *ep, struct xhci_ep_ctx *ep_ctx)
+{
+ struct mu3h_sch_ep_info *sch_ep;
+ struct mu3h_sch_tt *tt = NULL;
+ u32 len_bw_budget_table;
+ size_t mem_size;
+
+ if (is_fs_or_ls(udev->speed))
+ len_bw_budget_table = TT_MICROFRAMES_MAX;
+ else if ((udev->speed >= USB_SPEED_SUPER)
+ && usb_endpoint_xfer_isoc(&ep->desc))
+ len_bw_budget_table = get_esit(ep_ctx);
+ else
+ len_bw_budget_table = 1;
+
+ mem_size = sizeof(struct mu3h_sch_ep_info) +
+ len_bw_budget_table * sizeof(u32);
+ sch_ep = kzalloc(mem_size, GFP_KERNEL);
+ if (!sch_ep)
+ return ERR_PTR(-ENOMEM);
+
+ if (is_fs_or_ls(udev->speed)) {
+ tt = find_tt(udev);
+ if (IS_ERR(tt)) {
+ kfree(sch_ep);
+ return ERR_PTR(-ENOMEM);
+ }
+ }
+
+ sch_ep->sch_tt = tt;
+ sch_ep->ep = ep;
+
+ return sch_ep;
+}
+
static void setup_sch_info(struct usb_device *udev,
struct xhci_ep_ctx *ep_ctx, struct mu3h_sch_ep_info *sch_ep)
{
u32 ep_type;
- u32 ep_interval;
- u32 max_packet_size;
+ u32 maxpkt;
u32 max_burst;
u32 mult;
u32 esit_pkts;
+ u32 max_esit_payload;
+ u32 *bwb_table = sch_ep->bw_budget_table;
+ int i;
ep_type = CTX_TO_EP_TYPE(le32_to_cpu(ep_ctx->ep_info2));
- ep_interval = CTX_TO_EP_INTERVAL(le32_to_cpu(ep_ctx->ep_info));
- max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2));
+ maxpkt = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2));
max_burst = CTX_TO_MAX_BURST(le32_to_cpu(ep_ctx->ep_info2));
mult = CTX_TO_EP_MULT(le32_to_cpu(ep_ctx->ep_info));
+ max_esit_payload =
+ (CTX_TO_MAX_ESIT_PAYLOAD_HI(
+ le32_to_cpu(ep_ctx->ep_info)) << 16) |
+ CTX_TO_MAX_ESIT_PAYLOAD(le32_to_cpu(ep_ctx->tx_info));
- sch_ep->esit = 1 << ep_interval;
+ sch_ep->esit = get_esit(ep_ctx);
+ sch_ep->ep_type = ep_type;
+ sch_ep->maxpkt = maxpkt;
sch_ep->offset = 0;
sch_ep->burst_mode = 0;
+ sch_ep->repeat = 0;
if (udev->speed == USB_SPEED_HIGH) {
sch_ep->cs_count = 0;
@@ -93,7 +241,6 @@
* in a interval
*/
sch_ep->num_budget_microframes = 1;
- sch_ep->repeat = 0;
/*
* xHCI spec section6.2.3.4
@@ -101,19 +248,33 @@
* opportunities per microframe
*/
sch_ep->pkts = max_burst + 1;
- sch_ep->bw_cost_per_microframe = max_packet_size * sch_ep->pkts;
- } else if (udev->speed == USB_SPEED_SUPER) {
+ sch_ep->bw_cost_per_microframe = maxpkt * sch_ep->pkts;
+ bwb_table[0] = sch_ep->bw_cost_per_microframe;
+ } else if (udev->speed >= USB_SPEED_SUPER) {
/* usb3_r1 spec section4.4.7 & 4.4.8 */
sch_ep->cs_count = 0;
- esit_pkts = (mult + 1) * (max_burst + 1);
+ sch_ep->burst_mode = 1;
+ /*
+ * some device's (d)wBytesPerInterval is set as 0,
+ * then max_esit_payload is 0, so evaluate esit_pkts from
+ * mult and burst
+ */
+ esit_pkts = DIV_ROUND_UP(max_esit_payload, maxpkt);
+ if (esit_pkts == 0)
+ esit_pkts = (mult + 1) * (max_burst + 1);
+
if (ep_type == INT_IN_EP || ep_type == INT_OUT_EP) {
sch_ep->pkts = esit_pkts;
sch_ep->num_budget_microframes = 1;
- sch_ep->repeat = 0;
+ bwb_table[0] = maxpkt * sch_ep->pkts;
}
if (ep_type == ISOC_IN_EP || ep_type == ISOC_OUT_EP) {
- if (esit_pkts <= sch_ep->esit)
+ u32 remainder;
+
+ if (sch_ep->esit == 1)
+ sch_ep->pkts = esit_pkts;
+ else if (esit_pkts <= sch_ep->esit)
sch_ep->pkts = 1;
else
sch_ep->pkts = roundup_pow_of_two(esit_pkts)
@@ -122,43 +283,48 @@
sch_ep->num_budget_microframes =
DIV_ROUND_UP(esit_pkts, sch_ep->pkts);
- if (sch_ep->num_budget_microframes > 1)
- sch_ep->repeat = 1;
- else
- sch_ep->repeat = 0;
+ sch_ep->repeat = !!(sch_ep->num_budget_microframes > 1);
+ sch_ep->bw_cost_per_microframe = maxpkt * sch_ep->pkts;
+
+ remainder = sch_ep->bw_cost_per_microframe;
+ remainder *= sch_ep->num_budget_microframes;
+ remainder -= (maxpkt * esit_pkts);
+ for (i = 0; i < sch_ep->num_budget_microframes - 1; i++)
+ bwb_table[i] = sch_ep->bw_cost_per_microframe;
+
+ /* last one <= bw_cost_per_microframe */
+ bwb_table[i] = remainder;
}
- sch_ep->bw_cost_per_microframe = max_packet_size * sch_ep->pkts;
} else if (is_fs_or_ls(udev->speed)) {
+ sch_ep->pkts = 1; /* at most one packet for each microframe */
/*
- * usb_20 spec section11.18.4
- * assume worst cases
+ * num_budget_microframes and cs_count will be updated when
+ * check TT for INT_OUT_EP, ISOC/INT_IN_EP type
*/
- sch_ep->repeat = 0;
- sch_ep->pkts = 1; /* at most one packet for each microframe */
- if (ep_type == INT_IN_EP || ep_type == INT_OUT_EP) {
- sch_ep->cs_count = 3; /* at most need 3 CS*/
- /* one for SS and one for budgeted transaction */
- sch_ep->num_budget_microframes = sch_ep->cs_count + 2;
- sch_ep->bw_cost_per_microframe = max_packet_size;
- }
- if (ep_type == ISOC_OUT_EP) {
+ sch_ep->cs_count = DIV_ROUND_UP(maxpkt, FS_PAYLOAD_MAX);
+ sch_ep->num_budget_microframes = sch_ep->cs_count;
+ sch_ep->bw_cost_per_microframe =
+ (maxpkt < FS_PAYLOAD_MAX) ? maxpkt : FS_PAYLOAD_MAX;
+ /* init budget table */
+ if (ep_type == ISOC_OUT_EP) {
+ for (i = 0; i < sch_ep->num_budget_microframes; i++)
+ bwb_table[i] = sch_ep->bw_cost_per_microframe;
+ } else if (ep_type == INT_OUT_EP) {
+ /* only first one consumes bandwidth, others as zero */
+ bwb_table[0] = sch_ep->bw_cost_per_microframe;
+ } else { /* INT_IN_EP or ISOC_IN_EP */
+ bwb_table[0] = 0; /* start split */
+ bwb_table[1] = 0; /* idle */
/*
- * the best case FS budget assumes that 188 FS bytes
- * occur in each microframe
+ * due to cs_count will be updated according to cs
+ * position, assign all remainder budget array
+ * elements as @bw_cost_per_microframe, but only first
+ * @num_budget_microframes elements will be used later
*/
- sch_ep->num_budget_microframes = DIV_ROUND_UP(
- max_packet_size, FS_PAYLOAD_MAX);
- sch_ep->bw_cost_per_microframe = FS_PAYLOAD_MAX;
- sch_ep->cs_count = sch_ep->num_budget_microframes;
- }
- if (ep_type == ISOC_IN_EP) {
- /* at most need additional two CS. */
- sch_ep->cs_count = DIV_ROUND_UP(
- max_packet_size, FS_PAYLOAD_MAX) + 2;
- sch_ep->num_budget_microframes = sch_ep->cs_count + 2;
- sch_ep->bw_cost_per_microframe = FS_PAYLOAD_MAX;
+ for (i = 2; i < TT_MICROFRAMES_MAX; i++)
+ bwb_table[i] = sch_ep->bw_cost_per_microframe;
}
}
}
@@ -169,6 +335,7 @@
{
u32 num_esit;
u32 max_bw = 0;
+ u32 bw;
int i;
int j;
@@ -177,15 +344,17 @@
u32 base = offset + i * sch_ep->esit;
for (j = 0; j < sch_ep->num_budget_microframes; j++) {
- if (sch_bw->bus_bw[base + j] > max_bw)
- max_bw = sch_bw->bus_bw[base + j];
+ bw = sch_bw->bus_bw[base + j] +
+ sch_ep->bw_budget_table[j];
+ if (bw > max_bw)
+ max_bw = bw;
}
}
return max_bw;
}
static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw,
- struct mu3h_sch_ep_info *sch_ep, int bw_cost)
+ struct mu3h_sch_ep_info *sch_ep, bool used)
{
u32 num_esit;
u32 base;
@@ -195,27 +364,122 @@
num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit;
for (i = 0; i < num_esit; i++) {
base = sch_ep->offset + i * sch_ep->esit;
- for (j = 0; j < sch_ep->num_budget_microframes; j++)
- sch_bw->bus_bw[base + j] += bw_cost;
+ for (j = 0; j < sch_ep->num_budget_microframes; j++) {
+ if (used)
+ sch_bw->bus_bw[base + j] +=
+ sch_ep->bw_budget_table[j];
+ else
+ sch_bw->bus_bw[base + j] -=
+ sch_ep->bw_budget_table[j];
+ }
}
}
+static int check_sch_tt(struct usb_device *udev,
+ struct mu3h_sch_ep_info *sch_ep, u32 offset)
+{
+ struct mu3h_sch_tt *tt = sch_ep->sch_tt;
+ u32 extra_cs_count;
+ u32 fs_budget_start;
+ u32 start_ss, last_ss;
+ u32 start_cs, last_cs;
+ int i;
+
+ start_ss = offset % 8;
+ fs_budget_start = (start_ss + 1) % 8;
+
+ if (sch_ep->ep_type == ISOC_OUT_EP) {
+ last_ss = start_ss + sch_ep->cs_count - 1;
+
+ /*
+ * usb_20 spec section11.18:
+ * must never schedule Start-Split in Y6
+ */
+ if (!(start_ss == 7 || last_ss < 6))
+ return -ERANGE;
+
+ for (i = 0; i < sch_ep->cs_count; i++)
+ if (test_bit(offset + i, tt->split_bit_map))
+ return -ERANGE;
+
+ } else {
+ u32 cs_count = DIV_ROUND_UP(sch_ep->maxpkt, FS_PAYLOAD_MAX);
+
+ /*
+ * usb_20 spec section11.18:
+ * must never schedule Start-Split in Y6
+ */
+ if (start_ss == 6)
+ return -ERANGE;
+
+ /* one uframe for ss + one uframe for idle */
+ start_cs = (start_ss + 2) % 8;
+ last_cs = start_cs + cs_count - 1;
+
+ if (last_cs > 7)
+ return -ERANGE;
+
+ if (sch_ep->ep_type == ISOC_IN_EP)
+ extra_cs_count = (last_cs == 7) ? 1 : 2;
+ else /* ep_type : INTR IN / INTR OUT */
+ extra_cs_count = (fs_budget_start == 6) ? 1 : 2;
+
+ cs_count += extra_cs_count;
+ if (cs_count > 7)
+ cs_count = 7; /* HW limit */
+
+ for (i = 0; i < cs_count + 2; i++) {
+ if (test_bit(offset + i, tt->split_bit_map))
+ return -ERANGE;
+ }
+
+ sch_ep->cs_count = cs_count;
+ /* one for ss, the other for idle */
+ sch_ep->num_budget_microframes = cs_count + 2;
+
+ /*
+ * if interval=1, maxp >752, num_budge_micoframe is larger
+ * than sch_ep->esit, will overstep boundary
+ */
+ if (sch_ep->num_budget_microframes > sch_ep->esit)
+ sch_ep->num_budget_microframes = sch_ep->esit;
+ }
+
+ return 0;
+}
+
+static void update_sch_tt(struct usb_device *udev,
+ struct mu3h_sch_ep_info *sch_ep)
+{
+ struct mu3h_sch_tt *tt = sch_ep->sch_tt;
+ u32 base, num_esit;
+ int i, j;
+
+ num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit;
+ for (i = 0; i < num_esit; i++) {
+ base = sch_ep->offset + i * sch_ep->esit;
+ for (j = 0; j < sch_ep->num_budget_microframes; j++)
+ set_bit(base + j, tt->split_bit_map);
+ }
+
+ list_add_tail(&sch_ep->tt_endpoint, &tt->ep_list);
+}
+
static int check_sch_bw(struct usb_device *udev,
struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep)
{
u32 offset;
u32 esit;
- u32 num_budget_microframes;
u32 min_bw;
u32 min_index;
u32 worst_bw;
u32 bw_boundary;
-
- if (sch_ep->esit > XHCI_MTK_MAX_ESIT)
- sch_ep->esit = XHCI_MTK_MAX_ESIT;
+ u32 min_num_budget;
+ u32 min_cs_count;
+ bool tt_offset_ok = false;
+ int ret;
esit = sch_ep->esit;
- num_budget_microframes = sch_ep->num_budget_microframes;
/*
* Search through all possible schedule microframes.
@@ -223,36 +487,56 @@
*/
min_bw = ~0;
min_index = 0;
+ min_cs_count = sch_ep->cs_count;
+ min_num_budget = sch_ep->num_budget_microframes;
for (offset = 0; offset < esit; offset++) {
- if ((offset + num_budget_microframes) > sch_ep->esit)
- break;
+ if (is_fs_or_ls(udev->speed)) {
+ ret = check_sch_tt(udev, sch_ep, offset);
+ if (ret)
+ continue;
+ else
+ tt_offset_ok = true;
+ }
- /*
- * usb_20 spec section11.18:
- * must never schedule Start-Split in Y6
- */
- if (is_fs_or_ls(udev->speed) && (offset % 8 == 6))
- continue;
+ if ((offset + sch_ep->num_budget_microframes) > sch_ep->esit)
+ break;
worst_bw = get_max_bw(sch_bw, sch_ep, offset);
if (min_bw > worst_bw) {
min_bw = worst_bw;
min_index = offset;
+ min_cs_count = sch_ep->cs_count;
+ min_num_budget = sch_ep->num_budget_microframes;
}
if (min_bw == 0)
break;
}
- sch_ep->offset = min_index;
- bw_boundary = (udev->speed == USB_SPEED_SUPER)
- ? SS_BW_BOUNDARY : HS_BW_BOUNDARY;
+ if (udev->speed == USB_SPEED_SUPER_PLUS)
+ bw_boundary = SSP_BW_BOUNDARY;
+ else if (udev->speed == USB_SPEED_SUPER)
+ bw_boundary = SS_BW_BOUNDARY;
+ else
+ bw_boundary = HS_BW_BOUNDARY;
/* check bandwidth */
- if (min_bw + sch_ep->bw_cost_per_microframe > bw_boundary)
+ if (min_bw > bw_boundary)
return -ERANGE;
+ sch_ep->offset = min_index;
+ sch_ep->cs_count = min_cs_count;
+ sch_ep->num_budget_microframes = min_num_budget;
+
+ if (is_fs_or_ls(udev->speed)) {
+ /* all offset for tt is not ok*/
+ if (!tt_offset_ok)
+ return -ERANGE;
+
+ update_sch_tt(udev, sch_ep);
+ }
+
/* update bus bandwidth info */
- update_bus_bw(sch_bw, sch_ep, sch_ep->bw_cost_per_microframe);
+ update_bus_bw(sch_bw, sch_ep, 1);
return 0;
}
@@ -347,8 +631,8 @@
bw_index = get_bw_index(xhci, udev, ep);
sch_bw = &sch_array[bw_index];
- sch_ep = kzalloc(sizeof(struct mu3h_sch_ep_info), GFP_NOIO);
- if (!sch_ep)
+ sch_ep = create_sch_ep(udev, ep, ep_ctx);
+ if (IS_ERR_OR_NULL(sch_ep))
return -ENOMEM;
setup_sch_info(udev, ep_ctx, sch_ep);
@@ -356,12 +640,14 @@
ret = check_sch_bw(udev, sch_bw, sch_ep);
if (ret) {
xhci_err(xhci, "Not enough bandwidth!\n");
+ if (is_fs_or_ls(udev->speed))
+ drop_tt(udev);
+
kfree(sch_ep);
return -ENOSPC;
}
list_add_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list);
- sch_ep->ep = ep;
ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts)
| EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode));
@@ -406,9 +692,12 @@
list_for_each_entry(sch_ep, &sch_bw->bw_ep_list, endpoint) {
if (sch_ep->ep == ep) {
- update_bus_bw(sch_bw, sch_ep,
- -sch_ep->bw_cost_per_microframe);
+ update_bus_bw(sch_bw, sch_ep, 0);
list_del(&sch_ep->endpoint);
+ if (is_fs_or_ls(udev->speed)) {
+ list_del(&sch_ep->tt_endpoint);
+ drop_tt(udev);
+ }
kfree(sch_ep);
break;
}
diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
index 60987c7..b18a6ba 100644
--- a/drivers/usb/host/xhci-mtk.c
+++ b/drivers/usb/host/xhci-mtk.c
@@ -206,19 +206,6 @@
return xhci_mtk_host_enable(mtk);
}
-/* ignore the error if the clock does not exist */
-static struct clk *optional_clk_get(struct device *dev, const char *id)
-{
- struct clk *opt_clk;
-
- opt_clk = devm_clk_get(dev, id);
- /* ignore error number except EPROBE_DEFER */
- if (IS_ERR(opt_clk) && (PTR_ERR(opt_clk) != -EPROBE_DEFER))
- opt_clk = NULL;
-
- return opt_clk;
-}
-
static int xhci_mtk_clks_get(struct xhci_hcd_mtk *mtk)
{
struct device *dev = mtk->dev;
@@ -229,15 +216,19 @@
return PTR_ERR(mtk->sys_clk);
}
- mtk->ref_clk = optional_clk_get(dev, "ref_ck");
+ mtk->xhci_clk = devm_clk_get_optional(dev, "xhci_ck");
+ if (IS_ERR(mtk->xhci_clk))
+ return PTR_ERR(mtk->xhci_clk);
+
+ mtk->ref_clk = devm_clk_get_optional(dev, "ref_ck");
if (IS_ERR(mtk->ref_clk))
return PTR_ERR(mtk->ref_clk);
- mtk->mcu_clk = optional_clk_get(dev, "mcu_ck");
+ mtk->mcu_clk = devm_clk_get_optional(dev, "mcu_ck");
if (IS_ERR(mtk->mcu_clk))
return PTR_ERR(mtk->mcu_clk);
- mtk->dma_clk = optional_clk_get(dev, "dma_ck");
+ mtk->dma_clk = devm_clk_get_optional(dev, "dma_ck");
return PTR_ERR_OR_ZERO(mtk->dma_clk);
}
@@ -257,6 +248,12 @@
goto sys_clk_err;
}
+ ret = clk_prepare_enable(mtk->xhci_clk);
+ if (ret) {
+ dev_err(mtk->dev, "failed to enable xhci_clk\n");
+ goto xhci_clk_err;
+ }
+
ret = clk_prepare_enable(mtk->mcu_clk);
if (ret) {
dev_err(mtk->dev, "failed to enable mcu_clk\n");
@@ -274,6 +271,8 @@
dma_clk_err:
clk_disable_unprepare(mtk->mcu_clk);
mcu_clk_err:
+ clk_disable_unprepare(mtk->xhci_clk);
+xhci_clk_err:
clk_disable_unprepare(mtk->sys_clk);
sys_clk_err:
clk_disable_unprepare(mtk->ref_clk);
@@ -285,6 +284,7 @@
{
clk_disable_unprepare(mtk->dma_clk);
clk_disable_unprepare(mtk->mcu_clk);
+ clk_disable_unprepare(mtk->xhci_clk);
clk_disable_unprepare(mtk->sys_clk);
clk_disable_unprepare(mtk->ref_clk);
}
diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h
index cc59d80..5ac458b 100644
--- a/drivers/usb/host/xhci-mtk.h
+++ b/drivers/usb/host/xhci-mtk.h
@@ -20,6 +20,19 @@
#define XHCI_MTK_MAX_ESIT 64
/**
+ * @split_bit_map: used to avoid split microframes overlay
+ * @ep_list: Endpoints using this TT
+ * @usb_tt: usb TT related
+ * @tt_port: TT port number
+ */
+struct mu3h_sch_tt {
+ DECLARE_BITMAP(split_bit_map, XHCI_MTK_MAX_ESIT);
+ struct list_head ep_list;
+ struct usb_tt *usb_tt;
+ int tt_port;
+};
+
+/**
* struct mu3h_sch_bw_info: schedule information for bandwidth domain
*
* @bus_bw: array to keep track of bandwidth already used at each uframes
@@ -41,6 +54,10 @@
* (@repeat==1) scheduled within the interval
* @bw_cost_per_microframe: bandwidth cost per microframe
* @endpoint: linked into bandwidth domain which it belongs to
+ * @tt_endpoint: linked into mu3h_sch_tt's list which it belongs to
+ * @sch_tt: mu3h_sch_tt linked into
+ * @ep_type: endpoint type
+ * @maxpkt: max packet size of endpoint
* @ep: address of usb_host_endpoint struct
* @offset: which uframe of the interval that transfer should be
* scheduled first time within the interval
@@ -57,12 +74,17 @@
* times; 1: distribute the (bMaxBurst+1)*(Mult+1) packets
* according to @pkts and @repeat. normal mode is used by
* default
+ * @bw_budget_table: table to record bandwidth budget per microframe
*/
struct mu3h_sch_ep_info {
u32 esit;
u32 num_budget_microframes;
u32 bw_cost_per_microframe;
struct list_head endpoint;
+ struct list_head tt_endpoint;
+ struct mu3h_sch_tt *sch_tt;
+ u32 ep_type;
+ u32 maxpkt;
void *ep;
/*
* mtk xHCI scheduling information put into reserved DWs
@@ -73,6 +95,7 @@
u32 pkts;
u32 cs_count;
u32 burst_mode;
+ u32 bw_budget_table[0];
};
#define MU3C_U3_PORT_MAX 4
@@ -116,6 +139,7 @@
struct regulator *vusb33;
struct regulator *vbus;
struct clk *sys_clk; /* sys and mac clock */
+ struct clk *xhci_clk;
struct clk *ref_clk;
struct clk *mcu_clk;
struct clk *dma_clk;
diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c
index 32e1585..60651a5 100644
--- a/drivers/usb/host/xhci-mvebu.c
+++ b/drivers/usb/host/xhci-mvebu.c
@@ -13,6 +13,7 @@
#include <linux/usb/hcd.h>
#include "xhci-mvebu.h"
+#include "xhci.h"
#define USB3_MAX_WINDOWS 4
#define USB3_WIN_CTRL(w) (0x0 + ((w) * 8))
@@ -72,3 +73,13 @@
return 0;
}
+
+int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+ /* Without reset on resume, the HC won't work at all */
+ xhci->quirks |= XHCI_RESET_ON_RESUME;
+
+ return 0;
+}
diff --git a/drivers/usb/host/xhci-mvebu.h b/drivers/usb/host/xhci-mvebu.h
index 09791df..ca0a3a5 100644
--- a/drivers/usb/host/xhci-mvebu.h
+++ b/drivers/usb/host/xhci-mvebu.h
@@ -12,10 +12,16 @@
#if IS_ENABLED(CONFIG_USB_XHCI_MVEBU)
int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd);
+int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd);
#else
static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
{
return 0;
}
+
+static inline int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd)
+{
+ return 0;
+}
#endif
#endif /* __LINUX_XHCI_MVEBU_H */
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 09bf6b4..1e0236e 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -41,6 +41,13 @@
#define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI 0x1aa8
#define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8
#define PCI_DEVICE_ID_INTEL_DNV_XHCI 0x19d0
+#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_XHCI 0x15b5
+#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_XHCI 0x15b6
+#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_XHCI 0x15db
+#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_XHCI 0x15d4
+#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_XHCI 0x15e9
+#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_XHCI 0x15ec
+#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI 0x15f0
#define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9
#define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba
@@ -123,7 +130,7 @@
xhci->quirks |= XHCI_AMD_0x96_HOST;
/* AMD PLL quirk */
- if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
+ if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_quirk_pll_check())
xhci->quirks |= XHCI_AMD_PLL_FIX;
if (pdev->vendor == PCI_VENDOR_ID_AMD &&
@@ -187,6 +194,7 @@
xhci->quirks |= XHCI_SSIC_PORT_UNUSED;
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
(pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI))
xhci->quirks |= XHCI_INTEL_USB_ROLE_SW;
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
@@ -197,6 +205,16 @@
pdev->device == PCI_DEVICE_ID_INTEL_DNV_XHCI))
xhci->quirks |= XHCI_MISSING_CAS;
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
+ (pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI))
+ xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
+
if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
pdev->device == PCI_DEVICE_ID_EJ168) {
xhci->quirks |= XHCI_RESET_ON_RESUME;
@@ -345,6 +363,9 @@
/* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */
pm_runtime_put_noidle(&dev->dev);
+ if (xhci->quirks & XHCI_DEFAULT_PM_RUNTIME_ALLOW)
+ pm_runtime_allow(&dev->dev);
+
return 0;
put_usb3_hcd:
@@ -362,6 +383,10 @@
xhci = hcd_to_xhci(pci_get_drvdata(dev));
xhci->xhc_state |= XHCI_STATE_REMOVING;
+
+ if (xhci->quirks & XHCI_DEFAULT_PM_RUNTIME_ALLOW)
+ pm_runtime_forbid(&dev->dev);
+
if (xhci->shared_hcd) {
usb_remove_hcd(xhci->shared_hcd);
usb_put_hcd(xhci->shared_hcd);
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index e5da8ce..d90cd5e 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -18,6 +18,7 @@
#include <linux/usb/phy.h>
#include <linux/slab.h>
#include <linux/acpi.h>
+#include <linux/usb/of.h>
#include "xhci.h"
#include "xhci-plat.h"
@@ -65,12 +66,14 @@
static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
{
+ struct xhci_plat_priv *priv = xhci_to_priv(xhci);
+
/*
* As of now platform drivers don't provide MSI support so we ensure
* here that the generic code does not try to make a pci_dev from our
* dev struct in order to setup MSI
*/
- xhci->quirks |= XHCI_PLAT;
+ xhci->quirks |= XHCI_PLAT | priv->quirks;
}
/* called during probe() after chip reset completes */
@@ -97,18 +100,16 @@
.init_quirk = xhci_mvebu_mbus_init_quirk,
};
+static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = {
+ .init_quirk = xhci_mvebu_a3700_init_quirk,
+};
+
static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = {
- .firmware_name = XHCI_RCAR_FIRMWARE_NAME_V1,
- .init_quirk = xhci_rcar_init_quirk,
- .plat_start = xhci_rcar_start,
- .resume_quirk = xhci_rcar_resume_quirk,
+ SET_XHCI_PLAT_PRIV_FOR_RCAR(XHCI_RCAR_FIRMWARE_NAME_V1)
};
static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = {
- .firmware_name = XHCI_RCAR_FIRMWARE_NAME_V3,
- .init_quirk = xhci_rcar_init_quirk,
- .plat_start = xhci_rcar_start,
- .resume_quirk = xhci_rcar_resume_quirk,
+ SET_XHCI_PLAT_PRIV_FOR_RCAR(XHCI_RCAR_FIRMWARE_NAME_V3)
};
static const struct of_device_id usb_xhci_of_match[] = {
@@ -123,6 +124,9 @@
.compatible = "marvell,armada-380-xhci",
.data = &xhci_plat_marvell_armada,
}, {
+ .compatible = "marvell,armada3700-xhci",
+ .data = &xhci_plat_marvell_armada3700,
+ }, {
.compatible = "renesas,xhci-r8a7790",
.data = &xhci_plat_renesas_rcar_gen2,
}, {
@@ -157,8 +161,6 @@
struct xhci_hcd *xhci;
struct resource *res;
struct usb_hcd *hcd;
- struct clk *clk;
- struct clk *reg_clk;
int ret;
int irq;
@@ -227,31 +229,32 @@
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
+ xhci = hcd_to_xhci(hcd);
+
/*
* Not all platforms have clks so it is not an error if the
* clock do not exist.
*/
- reg_clk = devm_clk_get(&pdev->dev, "reg");
- if (!IS_ERR(reg_clk)) {
- ret = clk_prepare_enable(reg_clk);
- if (ret)
- goto put_hcd;
- } else if (PTR_ERR(reg_clk) == -EPROBE_DEFER) {
- ret = -EPROBE_DEFER;
+ xhci->reg_clk = devm_clk_get_optional(&pdev->dev, "reg");
+ if (IS_ERR(xhci->reg_clk)) {
+ ret = PTR_ERR(xhci->reg_clk);
goto put_hcd;
}
- clk = devm_clk_get(&pdev->dev, NULL);
- if (!IS_ERR(clk)) {
- ret = clk_prepare_enable(clk);
- if (ret)
- goto disable_reg_clk;
- } else if (PTR_ERR(clk) == -EPROBE_DEFER) {
- ret = -EPROBE_DEFER;
+ ret = clk_prepare_enable(xhci->reg_clk);
+ if (ret)
+ goto put_hcd;
+
+ xhci->clk = devm_clk_get_optional(&pdev->dev, NULL);
+ if (IS_ERR(xhci->clk)) {
+ ret = PTR_ERR(xhci->clk);
goto disable_reg_clk;
}
- xhci = hcd_to_xhci(hcd);
+ ret = clk_prepare_enable(xhci->clk);
+ if (ret)
+ goto disable_reg_clk;
+
priv_match = of_device_get_match_data(&pdev->dev);
if (priv_match) {
struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
@@ -263,8 +266,6 @@
device_wakeup_enable(hcd->self.controller);
- xhci->clk = clk;
- xhci->reg_clk = reg_clk;
xhci->main_hcd = hcd;
xhci->shared_hcd = __usb_create_hcd(driver, sysdev, &pdev->dev,
dev_name(&pdev->dev), hcd);
@@ -302,9 +303,10 @@
ret = usb_phy_init(hcd->usb_phy);
if (ret)
goto put_usb3_hcd;
- hcd->skip_phy_initialization = 1;
}
+ hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node);
+ xhci->shared_hcd->tpl_support = hcd->tpl_support;
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret)
goto disable_usb_phy;
@@ -338,10 +340,10 @@
usb_put_hcd(xhci->shared_hcd);
disable_clk:
- clk_disable_unprepare(clk);
+ clk_disable_unprepare(xhci->clk);
disable_reg_clk:
- clk_disable_unprepare(reg_clk);
+ clk_disable_unprepare(xhci->reg_clk);
put_hcd:
usb_put_hcd(hcd);
diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h
index ae29f22..5681723 100644
--- a/drivers/usb/host/xhci-plat.h
+++ b/drivers/usb/host/xhci-plat.h
@@ -12,10 +12,12 @@
struct xhci_plat_priv {
const char *firmware_name;
+ unsigned long long quirks;
void (*plat_start)(struct usb_hcd *);
int (*init_quirk)(struct usb_hcd *);
int (*resume_quirk)(struct usb_hcd *);
};
#define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv)
+#define xhci_to_priv(x) ((struct xhci_plat_priv *)(x)->priv)
#endif /* _XHCI_PLAT_H */
diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c
index a6e4637..c1025d3 100644
--- a/drivers/usb/host/xhci-rcar.c
+++ b/drivers/usb/host/xhci-rcar.c
@@ -104,16 +104,7 @@
return of_device_is_compatible(node, "renesas,xhci-r8a7790") ||
of_device_is_compatible(node, "renesas,xhci-r8a7791") ||
of_device_is_compatible(node, "renesas,xhci-r8a7793") ||
- of_device_is_compatible(node, "renensas,rcar-gen2-xhci");
-}
-
-static int xhci_rcar_is_gen3(struct device *dev)
-{
- struct device_node *node = dev->of_node;
-
- return of_device_is_compatible(node, "renesas,xhci-r8a7795") ||
- of_device_is_compatible(node, "renesas,xhci-r8a7796") ||
- of_device_is_compatible(node, "renesas,rcar-gen3-xhci");
+ of_device_is_compatible(node, "renesas,rcar-gen2-xhci");
}
void xhci_rcar_start(struct usb_hcd *hcd)
@@ -226,23 +217,10 @@
/* This function needs to initialize a "phy" of usb before */
int xhci_rcar_init_quirk(struct usb_hcd *hcd)
{
- struct xhci_hcd *xhci = hcd_to_xhci(hcd);
-
/* If hcd->regs is NULL, we don't just call the following function */
if (!hcd->regs)
return 0;
- /*
- * On R-Car Gen2 and Gen3, the AC64 bit (bit 0) of HCCPARAMS1 is set
- * to 1. However, these SoCs don't support 64-bit address memory
- * pointers. So, this driver clears the AC64 bit of xhci->hcc_params
- * to call dma_set_coherent_mask(dev, DMA_BIT_MASK(32)) in
- * xhci_gen_setup().
- */
- if (xhci_rcar_is_gen2(hcd->self.controller) ||
- xhci_rcar_is_gen3(hcd->self.controller))
- xhci->quirks |= XHCI_NO_64BIT_SUPPORT;
-
if (!xhci_rcar_wait_for_pll_active(hcd))
return -ETIMEDOUT;
diff --git a/drivers/usb/host/xhci-rcar.h b/drivers/usb/host/xhci-rcar.h
index 804b6ab..012744a 100644
--- a/drivers/usb/host/xhci-rcar.h
+++ b/drivers/usb/host/xhci-rcar.h
@@ -31,4 +31,25 @@
return 0;
}
#endif
+
+/*
+ * On R-Car Gen2 and Gen3, the AC64 bit (bit 0) of HCCPARAMS1 is set
+ * to 1. However, these SoCs don't support 64-bit address memory
+ * pointers. So, this driver clears the AC64 bit of xhci->hcc_params
+ * to call dma_set_coherent_mask(dev, DMA_BIT_MASK(32)) in
+ * xhci_gen_setup() by using the XHCI_NO_64BIT_SUPPORT quirk.
+ *
+ * And, since the firmware/internal CPU control the USBSTS.STS_HALT
+ * and the process speed is down when the roothub port enters U3,
+ * long delay for the handshake of STS_HALT is neeed in xhci_suspend()
+ * by using the XHCI_SLOW_SUSPEND quirk.
+ */
+#define SET_XHCI_PLAT_PRIV_FOR_RCAR(firmware) \
+ .firmware_name = firmware, \
+ .quirks = XHCI_NO_64BIT_SUPPORT | XHCI_TRUST_TX_LENGTH | \
+ XHCI_SLOW_SUSPEND, \
+ .init_quirk = xhci_rcar_init_quirk, \
+ .plat_start = xhci_rcar_start, \
+ .resume_quirk = xhci_rcar_resume_quirk,
+
#endif /* _XHCI_RCAR_H */
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 9ae17a6..e7aab31 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -399,7 +399,7 @@
* stream once the endpoint is on the HW schedule.
*/
if ((ep_state & EP_STOP_CMD_PENDING) || (ep_state & SET_DEQ_PENDING) ||
- (ep_state & EP_HALTED))
+ (ep_state & EP_HALTED) || (ep_state & EP_CLEARING_TT))
return;
writel(DB_VALUE(ep_index, stream_id), db_addr);
/* The CPU has better things to do at this point than wait for a
@@ -433,6 +433,13 @@
}
}
+void xhci_ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
+ unsigned int slot_id,
+ unsigned int ep_index)
+{
+ ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
+}
+
/* Get the right ring for the given slot_id, ep_index and stream_id.
* If the endpoint supports streams, boundary check the URB's stream ID.
* If the endpoint doesn't support streams, return the singular endpoint ring.
@@ -656,6 +663,7 @@
struct device *dev = xhci_to_hcd(xhci)->self.controller;
struct xhci_segment *seg = td->bounce_seg;
struct urb *urb = td->urb;
+ size_t len;
if (!ring || !seg || !urb)
return;
@@ -666,11 +674,14 @@
return;
}
- /* for in tranfers we need to copy the data from bounce to sg */
- sg_pcopy_from_buffer(urb->sg, urb->num_mapped_sgs, seg->bounce_buf,
- seg->bounce_len, seg->bounce_offs);
dma_unmap_single(dev, seg->bounce_dma, ring->bounce_buf_len,
DMA_FROM_DEVICE);
+ /* for in tranfers we need to copy the data from bounce to sg */
+ len = sg_pcopy_from_buffer(urb->sg, urb->num_sgs, seg->bounce_buf,
+ seg->bounce_len, seg->bounce_offs);
+ if (len != seg->bounce_len)
+ xhci_warn(xhci, "WARN Wrong bounce buffer read length: %zu != %d\n",
+ len, seg->bounce_len);
seg->bounce_len = 0;
seg->bounce_offs = 0;
}
@@ -1155,6 +1166,10 @@
/* Clear our internal halted state */
xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_HALTED;
}
+
+ /* if this was a soft reset, then restart */
+ if ((le32_to_cpu(trb->generic.field[3])) & TRB_TSP)
+ ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
}
static void xhci_handle_cmd_enable_slot(struct xhci_hcd *xhci, int slot_id,
@@ -1565,18 +1580,19 @@
"WARN: xHC returned failed port status event\n");
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);
+
if ((port_id <= 0) || (port_id > max_ports)) {
- xhci_warn(xhci, "Invalid port id %d\n", port_id);
+ xhci_warn(xhci, "Port change event with invalid port ID %d\n",
+ port_id);
inc_deq(xhci, xhci->event_ring);
return;
}
port = &xhci->hw_ports[port_id - 1];
if (!port || !port->rhub || port->hcd_portnum == DUPLICATE_ENTRY) {
- xhci_warn(xhci, "Event for invalid port %u\n", port_id);
+ xhci_warn(xhci, "Port change event, no port for port ID %u\n",
+ port_id);
bogus_port_status = true;
goto cleanup;
}
@@ -1589,10 +1605,13 @@
}
hcd = port->rhub->hcd;
- bus_state = &xhci->bus_state[hcd_index(hcd)];
+ bus_state = &port->rhub->bus_state;
hcd_portnum = port->hcd_portnum;
portsc = readl(port->addr);
+ xhci_dbg(xhci, "Port change event, %d-%d, id %d, portsc: 0x%x\n",
+ hcd->self.busnum, hcd_portnum + 1, port_id, portsc);
+
trace_xhci_handle_port_status(hcd_portnum, portsc);
if (hcd->state == HC_STATE_SUSPENDED) {
@@ -1600,8 +1619,13 @@
usb_hcd_resume_root_hub(hcd);
}
- if (hcd->speed >= HCD_USB3 && (portsc & PORT_PLS_MASK) == XDEV_INACTIVE)
+ if (hcd->speed >= HCD_USB3 &&
+ (portsc & PORT_PLS_MASK) == XDEV_INACTIVE) {
+ slot_id = xhci_find_slot_id_by_port(hcd, xhci, hcd_portnum + 1);
+ if (slot_id && xhci->devs[slot_id])
+ xhci->devs[slot_id]->flags |= VDEV_PORT_ERROR;
bus_state->port_remote_wakeup &= ~(1 << hcd_portnum);
+ }
if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) {
xhci_dbg(xhci, "port resume event for port %d\n", port_id);
@@ -1643,10 +1667,13 @@
}
}
- if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_U0 &&
- DEV_SUPERSPEED_ANY(portsc)) {
+ if ((portsc & PORT_PLC) &&
+ DEV_SUPERSPEED_ANY(portsc) &&
+ ((portsc & PORT_PLS_MASK) == XDEV_U0 ||
+ (portsc & PORT_PLS_MASK) == XDEV_U1 ||
+ (portsc & PORT_PLS_MASK) == XDEV_U2)) {
xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
- /* We've just brought the device into U0 through either the
+ /* We've just brought the device into U0/1/2 through either the
* Resume state after a device remote wakeup, or through the
* U3Exit state after a host-initiated resume. If it's a device
* initiated remote wake, don't pass up the link state change,
@@ -1779,6 +1806,23 @@
return NULL;
}
+static void xhci_clear_hub_tt_buffer(struct xhci_hcd *xhci, struct xhci_td *td,
+ struct xhci_virt_ep *ep)
+{
+ /*
+ * As part of low/full-speed endpoint-halt processing
+ * we must clear the TT buffer (USB 2.0 specification 11.17.5).
+ */
+ if (td->urb->dev->tt && !usb_pipeint(td->urb->pipe) &&
+ (td->urb->dev->tt->hub != xhci_to_hcd(xhci)->self.root_hub) &&
+ !(ep->ep_state & EP_CLEARING_TT)) {
+ ep->ep_state |= EP_CLEARING_TT;
+ td->urb->ep->hcpriv = td->urb->dev;
+ if (usb_hub_clear_tt_buffer(td->urb))
+ ep->ep_state &= ~EP_CLEARING_TT;
+ }
+}
+
static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
unsigned int stream_id, struct xhci_td *td,
@@ -1786,6 +1830,14 @@
{
struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
struct xhci_command *command;
+
+ /*
+ * Avoid resetting endpoint if link is inactive. Can cause host hang.
+ * Device will be reset soon to recover the link so don't do anything
+ */
+ if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR)
+ return;
+
command = xhci_alloc_command(xhci, false, GFP_ATOMIC);
if (!command)
return;
@@ -1797,6 +1849,7 @@
if (reset_type == EP_HARD_RESET) {
ep->ep_state |= EP_HARD_CLEAR_TOGGLE;
xhci_cleanup_stalled_ring(xhci, ep_index, stream_id, td);
+ xhci_clear_hub_tt_buffer(xhci, td, ep);
}
xhci_ring_cmd_db(xhci);
}
@@ -2173,10 +2226,16 @@
union xhci_trb *ep_trb, struct xhci_transfer_event *event,
struct xhci_virt_ep *ep, int *status)
{
+ struct xhci_slot_ctx *slot_ctx;
struct xhci_ring *ep_ring;
u32 trb_comp_code;
u32 remaining, requested, ep_trb_len;
+ unsigned int slot_id;
+ int ep_index;
+ slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
+ slot_ctx = xhci_get_slot_ctx(xhci, xhci->devs[slot_id]->out_ctx);
+ 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));
trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
@@ -2185,6 +2244,7 @@
switch (trb_comp_code) {
case COMP_SUCCESS:
+ ep_ring->err_count = 0;
/* handle success with untransferred data as short packet */
if (ep_trb != td->last_trb || remaining) {
xhci_warn(xhci, "WARN Successful completion on short TX\n");
@@ -2208,6 +2268,14 @@
ep_trb_len = 0;
remaining = 0;
break;
+ case COMP_USB_TRANSACTION_ERROR:
+ if ((ep_ring->err_count++ > MAX_SOFT_RETRY) ||
+ le32_to_cpu(slot_ctx->tt_info) & TT_SLOT)
+ break;
+ *status = 0;
+ xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index,
+ ep_ring->stream_id, td, EP_SOFT_RESET);
+ return 0;
default:
/* do nothing */
break;
@@ -3101,6 +3169,7 @@
unsigned int unalign;
unsigned int max_pkt;
u32 new_buff_len;
+ size_t len;
max_pkt = usb_endpoint_maxp(&urb->ep->desc);
unalign = (enqd_len + *trb_buff_len) % max_pkt;
@@ -3131,8 +3200,12 @@
/* create a max max_pkt sized bounce buffer pointed to by last trb */
if (usb_urb_dir_out(urb)) {
- sg_pcopy_to_buffer(urb->sg, urb->num_mapped_sgs,
+ len = sg_pcopy_to_buffer(urb->sg, urb->num_sgs,
seg->bounce_buf, new_buff_len, enqd_len);
+ if (len != new_buff_len)
+ xhci_warn(xhci,
+ "WARN Wrong bounce buffer write length: %zu != %d\n",
+ len, new_buff_len);
seg->bounce_dma = dma_map_single(dev, seg->bounce_buf,
max_pkt, DMA_TO_DEVICE);
} else {
@@ -3253,6 +3326,13 @@
field |= TRB_IOC;
more_trbs_coming = false;
td->last_trb = ring->enqueue;
+
+ if (xhci_urb_suitable_for_idt(urb)) {
+ memcpy(&send_addr, urb->transfer_buffer,
+ trb_buff_len);
+ le64_to_cpus(&send_addr);
+ field |= TRB_IDT;
+ }
}
/* Only set interrupt on short packet for IN endpoints */
@@ -3391,6 +3471,16 @@
if (urb->transfer_buffer_length > 0) {
u32 length_field, remainder;
+ u64 addr;
+
+ if (xhci_urb_suitable_for_idt(urb)) {
+ memcpy(&addr, urb->transfer_buffer,
+ urb->transfer_buffer_length);
+ le64_to_cpus(&addr);
+ field |= TRB_IDT;
+ } else {
+ addr = (u64) urb->transfer_dma;
+ }
remainder = xhci_td_remainder(xhci, 0,
urb->transfer_buffer_length,
@@ -3402,8 +3492,8 @@
if (setup->bRequestType & USB_DIR_IN)
field |= TRB_DIR_IN;
queue_trb(xhci, ep_ring, true,
- lower_32_bits(urb->transfer_dma),
- upper_32_bits(urb->transfer_dma),
+ lower_32_bits(addr),
+ upper_32_bits(addr),
length_field,
field | ep_ring->cycle_state);
}
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
index b1cce98..2ff7c91 100644
--- a/drivers/usb/host/xhci-tegra.c
+++ b/drivers/usb/host/xhci-tegra.c
@@ -18,6 +18,7 @@
#include <linux/phy/tegra/xusb.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
+#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
@@ -107,35 +108,35 @@
#define IMEM_BLOCK_SIZE 256
struct tegra_xusb_fw_header {
- u32 boot_loadaddr_in_imem;
- u32 boot_codedfi_offset;
- u32 boot_codetag;
- u32 boot_codesize;
- u32 phys_memaddr;
- u16 reqphys_memsize;
- u16 alloc_phys_memsize;
- u32 rodata_img_offset;
- u32 rodata_section_start;
- u32 rodata_section_end;
- u32 main_fnaddr;
- u32 fwimg_cksum;
- u32 fwimg_created_time;
- u32 imem_resident_start;
- u32 imem_resident_end;
- u32 idirect_start;
- u32 idirect_end;
- u32 l2_imem_start;
- u32 l2_imem_end;
- u32 version_id;
+ __le32 boot_loadaddr_in_imem;
+ __le32 boot_codedfi_offset;
+ __le32 boot_codetag;
+ __le32 boot_codesize;
+ __le32 phys_memaddr;
+ __le16 reqphys_memsize;
+ __le16 alloc_phys_memsize;
+ __le32 rodata_img_offset;
+ __le32 rodata_section_start;
+ __le32 rodata_section_end;
+ __le32 main_fnaddr;
+ __le32 fwimg_cksum;
+ __le32 fwimg_created_time;
+ __le32 imem_resident_start;
+ __le32 imem_resident_end;
+ __le32 idirect_start;
+ __le32 idirect_end;
+ __le32 l2_imem_start;
+ __le32 l2_imem_end;
+ __le32 version_id;
u8 init_ddirect;
u8 reserved[3];
- u32 phys_addr_log_buffer;
- u32 total_log_entries;
- u32 dequeue_ptr;
- u32 dummy_var[2];
- u32 fwimg_len;
+ __le32 phys_addr_log_buffer;
+ __le32 total_log_entries;
+ __le32 dequeue_ptr;
+ __le32 dummy_var[2];
+ __le32 fwimg_len;
u8 magic[8];
- u32 ss_low_power_entry_timeout;
+ __le32 ss_low_power_entry_timeout;
u8 num_hsic_port;
u8 padding[139]; /* Pad to 256 bytes */
};
@@ -160,6 +161,7 @@
} ports;
bool scale_ss_clock;
+ bool has_ipfs;
};
struct tegra_xusb {
@@ -194,6 +196,11 @@
struct reset_control *host_rst;
struct reset_control *ss_rst;
+ struct device *genpd_dev_host;
+ struct device *genpd_dev_ss;
+ struct device_link *genpd_dl_host;
+ struct device_link *genpd_dl_ss;
+
struct phy **phys;
unsigned int num_phys;
@@ -347,29 +354,6 @@
MBOX_CMD_NAK
};
-static const char * const mbox_cmd_name[] = {
- [ 1] = "MSG_ENABLE",
- [ 2] = "INC_FALCON_CLOCK",
- [ 3] = "DEC_FALCON_CLOCK",
- [ 4] = "INC_SSPI_CLOCK",
- [ 5] = "DEC_SSPI_CLOCK",
- [ 6] = "SET_BW",
- [ 7] = "SET_SS_PWR_GATING",
- [ 8] = "SET_SS_PWR_UNGATING",
- [ 9] = "SAVE_DFE_CTLE_CTX",
- [ 10] = "AIRPLANE_MODE_ENABLED",
- [ 11] = "AIRPLANE_MODE_DISABLED",
- [ 12] = "START_HSIC_IDLE",
- [ 13] = "STOP_HSIC_IDLE",
- [ 14] = "DBC_WAKE_STACK",
- [ 15] = "HSIC_PRETEND_CONNECT",
- [ 16] = "RESET_SSPI",
- [ 17] = "DISABLE_SS_LFPS_DETECTION",
- [ 18] = "ENABLE_SS_LFPS_DETECTION",
- [128] = "ACK",
- [129] = "NAK",
-};
-
struct tegra_xusb_mbox_msg {
u32 cmd;
u32 data;
@@ -631,16 +615,18 @@
return IRQ_HANDLED;
}
-static void tegra_xusb_ipfs_config(struct tegra_xusb *tegra,
- struct resource *regs)
+static void tegra_xusb_config(struct tegra_xusb *tegra,
+ struct resource *regs)
{
u32 value;
- value = ipfs_readl(tegra, IPFS_XUSB_HOST_CONFIGURATION_0);
- value |= IPFS_EN_FPCI;
- ipfs_writel(tegra, value, IPFS_XUSB_HOST_CONFIGURATION_0);
+ if (tegra->soc->has_ipfs) {
+ value = ipfs_readl(tegra, IPFS_XUSB_HOST_CONFIGURATION_0);
+ value |= IPFS_EN_FPCI;
+ ipfs_writel(tegra, value, IPFS_XUSB_HOST_CONFIGURATION_0);
- usleep_range(10, 20);
+ usleep_range(10, 20);
+ }
/* Program BAR0 space */
value = fpci_readl(tegra, XUSB_CFG_4);
@@ -655,13 +641,15 @@
value |= XUSB_IO_SPACE_EN | XUSB_MEM_SPACE_EN | XUSB_BUS_MASTER_EN;
fpci_writel(tegra, value, XUSB_CFG_1);
- /* Enable interrupt assertion */
- value = ipfs_readl(tegra, IPFS_XUSB_HOST_INTR_MASK_0);
- value |= IPFS_IP_INT_MASK;
- ipfs_writel(tegra, value, IPFS_XUSB_HOST_INTR_MASK_0);
+ if (tegra->soc->has_ipfs) {
+ /* Enable interrupt assertion */
+ value = ipfs_readl(tegra, IPFS_XUSB_HOST_INTR_MASK_0);
+ value |= IPFS_IP_INT_MASK;
+ ipfs_writel(tegra, value, IPFS_XUSB_HOST_INTR_MASK_0);
- /* Set hysteresis */
- ipfs_writel(tegra, 0x80, IPFS_XUSB_HOST_CLKGATE_HYSTERESIS_0);
+ /* Set hysteresis */
+ ipfs_writel(tegra, 0x80, IPFS_XUSB_HOST_CLKGATE_HYSTERESIS_0);
+ }
}
static int tegra_xusb_clk_enable(struct tegra_xusb *tegra)
@@ -928,6 +916,57 @@
return 0;
}
+static void tegra_xusb_powerdomain_remove(struct device *dev,
+ struct tegra_xusb *tegra)
+{
+ if (tegra->genpd_dl_ss)
+ device_link_del(tegra->genpd_dl_ss);
+ if (tegra->genpd_dl_host)
+ device_link_del(tegra->genpd_dl_host);
+ if (!IS_ERR_OR_NULL(tegra->genpd_dev_ss))
+ dev_pm_domain_detach(tegra->genpd_dev_ss, true);
+ if (!IS_ERR_OR_NULL(tegra->genpd_dev_host))
+ dev_pm_domain_detach(tegra->genpd_dev_host, true);
+}
+
+static int tegra_xusb_powerdomain_init(struct device *dev,
+ struct tegra_xusb *tegra)
+{
+ int err;
+
+ tegra->genpd_dev_host = dev_pm_domain_attach_by_name(dev, "xusb_host");
+ if (IS_ERR(tegra->genpd_dev_host)) {
+ err = PTR_ERR(tegra->genpd_dev_host);
+ dev_err(dev, "failed to get host pm-domain: %d\n", err);
+ return err;
+ }
+
+ tegra->genpd_dev_ss = dev_pm_domain_attach_by_name(dev, "xusb_ss");
+ if (IS_ERR(tegra->genpd_dev_ss)) {
+ err = PTR_ERR(tegra->genpd_dev_ss);
+ dev_err(dev, "failed to get superspeed pm-domain: %d\n", err);
+ return err;
+ }
+
+ tegra->genpd_dl_host = device_link_add(dev, tegra->genpd_dev_host,
+ DL_FLAG_PM_RUNTIME |
+ DL_FLAG_STATELESS);
+ if (!tegra->genpd_dl_host) {
+ dev_err(dev, "adding host device link failed!\n");
+ return -ENODEV;
+ }
+
+ tegra->genpd_dl_ss = device_link_add(dev, tegra->genpd_dev_ss,
+ DL_FLAG_PM_RUNTIME |
+ DL_FLAG_STATELESS);
+ if (!tegra->genpd_dl_ss) {
+ dev_err(dev, "adding superspeed device link failed!\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
static int tegra_xusb_probe(struct platform_device *pdev)
{
struct tegra_xusb_mbox_msg msg;
@@ -958,10 +997,12 @@
if (IS_ERR(tegra->fpci_base))
return PTR_ERR(tegra->fpci_base);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
- tegra->ipfs_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(tegra->ipfs_base))
- return PTR_ERR(tegra->ipfs_base);
+ if (tegra->soc->has_ipfs) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ tegra->ipfs_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(tegra->ipfs_base))
+ return PTR_ERR(tegra->ipfs_base);
+ }
tegra->xhci_irq = platform_get_irq(pdev, 0);
if (tegra->xhci_irq < 0)
@@ -1038,7 +1079,7 @@
goto put_padctl;
}
- if (!pdev->dev.pm_domain) {
+ if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) {
tegra->host_rst = devm_reset_control_get(&pdev->dev,
"xusb_host");
if (IS_ERR(tegra->host_rst)) {
@@ -1069,17 +1110,22 @@
tegra->host_clk,
tegra->host_rst);
if (err) {
+ tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA);
dev_err(&pdev->dev,
"failed to enable XUSBC domain: %d\n", err);
- goto disable_xusba;
+ goto put_padctl;
}
+ } else {
+ err = tegra_xusb_powerdomain_init(&pdev->dev, tegra);
+ if (err)
+ goto put_powerdomains;
}
tegra->supplies = devm_kcalloc(&pdev->dev, tegra->soc->num_supplies,
sizeof(*tegra->supplies), GFP_KERNEL);
if (!tegra->supplies) {
err = -ENOMEM;
- goto disable_xusbc;
+ goto put_powerdomains;
}
for (i = 0; i < tegra->soc->num_supplies; i++)
@@ -1089,7 +1135,7 @@
tegra->supplies);
if (err) {
dev_err(&pdev->dev, "failed to get regulators: %d\n", err);
- goto disable_xusbc;
+ goto put_powerdomains;
}
for (i = 0; i < tegra->soc->num_types; i++)
@@ -1099,7 +1145,7 @@
sizeof(*tegra->phys), GFP_KERNEL);
if (!tegra->phys) {
err = -ENOMEM;
- goto disable_xusbc;
+ goto put_powerdomains;
}
for (i = 0, k = 0; i < tegra->soc->num_types; i++) {
@@ -1115,7 +1161,7 @@
"failed to get PHY %s: %ld\n", prop,
PTR_ERR(phy));
err = PTR_ERR(phy);
- goto disable_xusbc;
+ goto put_powerdomains;
}
tegra->phys[k++] = phy;
@@ -1126,7 +1172,7 @@
dev_name(&pdev->dev));
if (!tegra->hcd) {
err = -ENOMEM;
- goto disable_xusbc;
+ goto put_powerdomains;
}
/*
@@ -1146,7 +1192,17 @@
goto disable_rpm;
}
- tegra_xusb_ipfs_config(tegra, regs);
+ tegra_xusb_config(tegra, regs);
+
+ /*
+ * The XUSB Falcon microcontroller can only address 40 bits, so set
+ * the DMA mask accordingly.
+ */
+ err = dma_set_mask_and_coherent(tegra->dev, DMA_BIT_MASK(40));
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err);
+ goto put_rpm;
+ }
err = tegra_xusb_load_firmware(tegra);
if (err < 0) {
@@ -1222,12 +1278,13 @@
disable_rpm:
pm_runtime_disable(&pdev->dev);
usb_put_hcd(tegra->hcd);
-disable_xusbc:
- if (!pdev->dev.pm_domain)
+put_powerdomains:
+ if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) {
tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC);
-disable_xusba:
- if (!pdev->dev.pm_domain)
tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA);
+ } else {
+ tegra_xusb_powerdomain_remove(&pdev->dev, tegra);
+ }
put_padctl:
tegra_xusb_padctl_put(tegra->padctl);
return err;
@@ -1250,6 +1307,13 @@
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) {
+ tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC);
+ tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA);
+ } else {
+ tegra_xusb_powerdomain_remove(&pdev->dev, tegra);
+ }
+
tegra_xusb_padctl_put(tegra->padctl);
return 0;
@@ -1310,6 +1374,7 @@
.usb3 = { .offset = 0, .count = 2, },
},
.scale_ss_clock = true,
+ .has_ipfs = true,
};
MODULE_FIRMWARE("nvidia/tegra124/xusb.bin");
@@ -1341,12 +1406,38 @@
.usb3 = { .offset = 0, .count = 4, },
},
.scale_ss_clock = false,
+ .has_ipfs = true,
};
MODULE_FIRMWARE("nvidia/tegra210/xusb.bin");
+static const char * const tegra186_supply_names[] = {
+};
+
+static const struct tegra_xusb_phy_type tegra186_phy_types[] = {
+ { .name = "usb3", .num = 3, },
+ { .name = "usb2", .num = 3, },
+ { .name = "hsic", .num = 1, },
+};
+
+static const struct tegra_xusb_soc tegra186_soc = {
+ .firmware = "nvidia/tegra186/xusb.bin",
+ .supply_names = tegra186_supply_names,
+ .num_supplies = ARRAY_SIZE(tegra186_supply_names),
+ .phy_types = tegra186_phy_types,
+ .num_types = ARRAY_SIZE(tegra186_phy_types),
+ .ports = {
+ .usb3 = { .offset = 0, .count = 3, },
+ .usb2 = { .offset = 3, .count = 3, },
+ .hsic = { .offset = 6, .count = 1, },
+ },
+ .scale_ss_clock = false,
+ .has_ipfs = false,
+};
+
static const struct of_device_id tegra_xusb_of_match[] = {
{ .compatible = "nvidia,tegra124-xusb", .data = &tegra124_soc },
{ .compatible = "nvidia,tegra210-xusb", .data = &tegra210_soc },
+ { .compatible = "nvidia,tegra186-xusb", .data = &tegra186_soc },
{ },
};
MODULE_DEVICE_TABLE(of, tegra_xusb_of_match);
diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h
index 88b4274..052a269 100644
--- a/drivers/usb/host/xhci-trace.h
+++ b/drivers/usb/host/xhci-trace.h
@@ -366,6 +366,11 @@
TP_ARGS(ctx)
);
+DEFINE_EVENT(xhci_log_ep_ctx, xhci_add_endpoint,
+ TP_PROTO(struct xhci_ep_ctx *ctx),
+ TP_ARGS(ctx)
+);
+
DECLARE_EVENT_CLASS(xhci_log_slot_ctx,
TP_PROTO(struct xhci_slot_ctx *ctx),
TP_ARGS(ctx),
@@ -432,6 +437,31 @@
TP_ARGS(ctx)
);
+DECLARE_EVENT_CLASS(xhci_log_ctrl_ctx,
+ TP_PROTO(struct xhci_input_control_ctx *ctrl_ctx),
+ TP_ARGS(ctrl_ctx),
+ TP_STRUCT__entry(
+ __field(u32, drop)
+ __field(u32, add)
+ ),
+ TP_fast_assign(
+ __entry->drop = le32_to_cpu(ctrl_ctx->drop_flags);
+ __entry->add = le32_to_cpu(ctrl_ctx->add_flags);
+ ),
+ TP_printk("%s", xhci_decode_ctrl_ctx(__entry->drop, __entry->add)
+ )
+);
+
+DEFINE_EVENT(xhci_log_ctrl_ctx, xhci_address_ctrl_ctx,
+ TP_PROTO(struct xhci_input_control_ctx *ctrl_ctx),
+ TP_ARGS(ctrl_ctx)
+);
+
+DEFINE_EVENT(xhci_log_ctrl_ctx, xhci_configure_endpoint_ctrl_ctx,
+ TP_PROTO(struct xhci_input_control_ctx *ctrl_ctx),
+ TP_ARGS(ctrl_ctx)
+);
+
DECLARE_EVENT_CLASS(xhci_log_ring,
TP_PROTO(struct xhci_ring *ring),
TP_ARGS(ring),
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index dae3be1..6c17e3f 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -9,6 +9,7 @@
*/
#include <linux/pci.h>
+#include <linux/iopoll.h>
#include <linux/irq.h>
#include <linux/log2.h>
#include <linux/module.h>
@@ -52,7 +53,6 @@
return false;
}
-/* TODO: copied from ehci-hcd.c - can this be refactored? */
/*
* xhci_handshake - spin reading hc until handshake completes or fails
* @ptr: address of hc register to be read
@@ -69,18 +69,16 @@
int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec)
{
u32 result;
+ int ret;
- do {
- result = readl(ptr);
- if (result == ~(u32)0) /* card removed */
- return -ENODEV;
- result &= mask;
- if (result == done)
- return 0;
- udelay(1);
- usec--;
- } while (usec > 0);
- return -ETIMEDOUT;
+ ret = readl_poll_timeout_atomic(ptr, result,
+ (result & mask) == done ||
+ result == U32_MAX,
+ 1, usec);
+ if (result == U32_MAX) /* card removed */
+ return -ENODEV;
+
+ return ret;
}
/*
@@ -169,7 +167,7 @@
{
u32 command;
u32 state;
- int ret, i;
+ int ret;
state = readl(&xhci->op_regs->status);
@@ -215,11 +213,12 @@
ret = xhci_handshake(&xhci->op_regs->status,
STS_CNR, 0, 10 * 1000 * 1000);
- for (i = 0; i < 2; i++) {
- xhci->bus_state[i].port_c_suspend = 0;
- xhci->bus_state[i].suspended_ports = 0;
- xhci->bus_state[i].resuming_ports = 0;
- }
+ xhci->usb2_rhub.bus_state.port_c_suspend = 0;
+ xhci->usb2_rhub.bus_state.suspended_ports = 0;
+ xhci->usb2_rhub.bus_state.resuming_ports = 0;
+ xhci->usb3_rhub.bus_state.port_c_suspend = 0;
+ xhci->usb3_rhub.bus_state.suspended_ports = 0;
+ xhci->usb3_rhub.bus_state.resuming_ports = 0;
return ret;
}
@@ -244,7 +243,7 @@
* an iommu. Doing anything when there is no iommu is definitely
* unsafe...
*/
- if (!(xhci->quirks & XHCI_ZERO_64B_REGS) || !dev->iommu_group)
+ if (!(xhci->quirks & XHCI_ZERO_64B_REGS) || !device_iommu_mapped(dev))
return;
xhci_info(xhci, "Zeroing 64bit base registers, expecting fault\n");
@@ -892,7 +891,7 @@
struct xhci_port **ports;
int port_index;
unsigned long flags;
- u32 t1, t2;
+ u32 t1, t2, portsc;
spin_lock_irqsave(&xhci->lock, flags);
@@ -901,10 +900,15 @@
ports = xhci->usb3_rhub.ports;
while (port_index--) {
t1 = readl(ports[port_index]->addr);
+ portsc = t1;
t1 = xhci_port_state_to_neutral(t1);
t2 = t1 & ~PORT_WAKE_BITS;
- if (t1 != t2)
+ if (t1 != t2) {
writel(t2, ports[port_index]->addr);
+ xhci_dbg(xhci, "disable wake bits port %d-%d, portsc: 0x%x, write: 0x%x\n",
+ xhci->usb3_rhub.hcd->self.busnum,
+ port_index + 1, portsc, t2);
+ }
}
/* disable usb2 ports Wake bits */
@@ -912,12 +916,16 @@
ports = xhci->usb2_rhub.ports;
while (port_index--) {
t1 = readl(ports[port_index]->addr);
+ portsc = t1;
t1 = xhci_port_state_to_neutral(t1);
t2 = t1 & ~PORT_WAKE_BITS;
- if (t1 != t2)
+ if (t1 != t2) {
writel(t2, ports[port_index]->addr);
+ xhci_dbg(xhci, "disable wake bits port %d-%d, portsc: 0x%x, write: 0x%x\n",
+ xhci->usb2_rhub.hcd->self.busnum,
+ port_index + 1, portsc, t2);
+ }
}
-
spin_unlock_irqrestore(&xhci->lock, flags);
}
@@ -1024,7 +1032,7 @@
writel(command, &xhci->op_regs->command);
xhci->broken_suspend = 0;
if (xhci_handshake(&xhci->op_regs->status,
- STS_SAVE, 0, 10 * 1000)) {
+ STS_SAVE, 0, 20 * 1000)) {
/*
* AMD SNPS xHC 3.0 occasionally does not clear the
* SSS bit of USBSTS and when driver tries to poll
@@ -1087,9 +1095,9 @@
/* Wait a bit if either of the roothubs need to settle from the
* transition into bus suspend.
*/
- if (time_before(jiffies, xhci->bus_state[0].next_statechange) ||
- time_before(jiffies,
- xhci->bus_state[1].next_statechange))
+
+ if (time_before(jiffies, xhci->usb2_rhub.bus_state.next_statechange) ||
+ time_before(jiffies, xhci->usb3_rhub.bus_state.next_statechange))
msleep(100);
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
@@ -1100,6 +1108,18 @@
hibernated = true;
if (!hibernated) {
+ /*
+ * Some controllers might lose power during suspend, so wait
+ * for controller not ready bit to clear, just as in xHC init.
+ */
+ retval = xhci_handshake(&xhci->op_regs->status,
+ STS_CNR, 0, 10 * 1000 * 1000);
+ if (retval) {
+ xhci_warn(xhci, "Controller not ready at resume %d\n",
+ retval);
+ spin_unlock_irq(&xhci->lock);
+ return retval;
+ }
/* step 1: restore register */
xhci_restore_registers(xhci);
/* step 2: initialize command ring buffer */
@@ -1237,6 +1257,21 @@
/*-------------------------------------------------------------------------*/
+/*
+ * Bypass the DMA mapping if URB is suitable for Immediate Transfer (IDT),
+ * we'll copy the actual data into the TRB address register. This is limited to
+ * transfers up to 8 bytes on output endpoints of any kind with wMaxPacketSize
+ * >= 8 bytes. If suitable for IDT only one Transfer TRB per TD is allowed.
+ */
+static int xhci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ if (xhci_urb_suitable_for_idt(urb))
+ return 0;
+
+ return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
+}
+
/**
* xhci_get_endpoint_index - Used for passing endpoint bitmasks between the core and
* HCDs. Find the index for an endpoint given its descriptor. Use the return
@@ -1443,6 +1478,10 @@
xhci_dbg(xhci, "urb submitted during PCI suspend\n");
return -ESHUTDOWN;
}
+ if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR) {
+ xhci_dbg(xhci, "Can't queue urb, port error, link inactive\n");
+ return -ENODEV;
+ }
if (usb_endpoint_xfer_isoc(&urb->ep->desc))
num_tds = urb->number_of_packets;
@@ -1454,8 +1493,7 @@
else
num_tds = 1;
- urb_priv = kzalloc(sizeof(struct urb_priv) +
- num_tds * sizeof(struct xhci_td), mem_flags);
+ urb_priv = kzalloc(struct_size(urb_priv, td, num_tds), mem_flags);
if (!urb_priv)
return -ENOMEM;
@@ -1783,6 +1821,7 @@
struct xhci_container_ctx *in_ctx;
unsigned int ep_index;
struct xhci_input_control_ctx *ctrl_ctx;
+ struct xhci_ep_ctx *ep_ctx;
u32 added_ctxs;
u32 new_add_flags, new_drop_flags;
struct xhci_virt_device *virt_dev;
@@ -1873,6 +1912,9 @@
/* Store the usb_device pointer for later use */
ep->hcpriv = udev;
+ ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
+ trace_xhci_add_endpoint(ep_ctx);
+
xhci_debugfs_create_endpoint(xhci, virt_dev, ep_index);
xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n",
@@ -2747,6 +2789,8 @@
}
slot_ctx = xhci_get_slot_ctx(xhci, command->in_ctx);
+
+ trace_xhci_configure_endpoint_ctrl_ctx(ctrl_ctx);
trace_xhci_configure_endpoint(slot_ctx);
if (!ctx_change)
@@ -3027,6 +3071,48 @@
}
}
+static void xhci_endpoint_disable(struct usb_hcd *hcd,
+ struct usb_host_endpoint *host_ep)
+{
+ struct xhci_hcd *xhci;
+ struct xhci_virt_device *vdev;
+ struct xhci_virt_ep *ep;
+ struct usb_device *udev;
+ unsigned long flags;
+ unsigned int ep_index;
+
+ xhci = hcd_to_xhci(hcd);
+rescan:
+ spin_lock_irqsave(&xhci->lock, flags);
+
+ udev = (struct usb_device *)host_ep->hcpriv;
+ if (!udev || !udev->slot_id)
+ goto done;
+
+ vdev = xhci->devs[udev->slot_id];
+ if (!vdev)
+ goto done;
+
+ ep_index = xhci_get_endpoint_index(&host_ep->desc);
+ ep = &vdev->eps[ep_index];
+ if (!ep)
+ goto done;
+
+ /* wait for hub_tt_work to finish clearing hub TT */
+ if (ep->ep_state & EP_CLEARING_TT) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ schedule_timeout_uninterruptible(1);
+ goto rescan;
+ }
+
+ if (ep->ep_state)
+ xhci_dbg(xhci, "endpoint disable with ep_state 0x%x\n",
+ ep->ep_state);
+done:
+ host_ep->hcpriv = NULL;
+ spin_unlock_irqrestore(&xhci->lock, flags);
+}
+
/*
* Called after usb core issues a clear halt control message.
* The host side of the halt should already be cleared by a reset endpoint
@@ -3051,14 +3137,25 @@
unsigned int ep_index;
unsigned long flags;
u32 ep_flag;
+ int err;
xhci = hcd_to_xhci(hcd);
if (!host_ep->hcpriv)
return;
udev = (struct usb_device *) host_ep->hcpriv;
vdev = xhci->devs[udev->slot_id];
+
+ /*
+ * vdev may be lost due to xHC restore error and re-initialization
+ * during S3/S4 resume. A new vdev will be allocated later by
+ * xhci_discover_or_reset_device()
+ */
+ if (!udev->slot_id || !vdev)
+ return;
ep_index = xhci_get_endpoint_index(&host_ep->desc);
ep = &vdev->eps[ep_index];
+ if (!ep)
+ return;
/* Bail out if toggle is already being cleared by a endpoint reset */
if (ep->ep_state & EP_HARD_CLEAR_TOGGLE) {
@@ -3100,7 +3197,17 @@
xhci_free_command(xhci, cfg_cmd);
goto cleanup;
}
- xhci_queue_stop_endpoint(xhci, stop_cmd, udev->slot_id, ep_index, 0);
+
+ err = xhci_queue_stop_endpoint(xhci, stop_cmd, udev->slot_id,
+ ep_index, 0);
+ if (err < 0) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ xhci_free_command(xhci, cfg_cmd);
+ xhci_dbg(xhci, "%s: Failed to queue stop ep command, %d ",
+ __func__, err);
+ goto cleanup;
+ }
+
xhci_ring_cmd_db(xhci);
spin_unlock_irqrestore(&xhci->lock, flags);
@@ -3114,8 +3221,16 @@
ctrl_ctx, ep_flag, ep_flag);
xhci_endpoint_copy(xhci, cfg_cmd->in_ctx, vdev->out_ctx, ep_index);
- xhci_queue_configure_endpoint(xhci, cfg_cmd, cfg_cmd->in_ctx->dma,
+ err = xhci_queue_configure_endpoint(xhci, cfg_cmd, cfg_cmd->in_ctx->dma,
udev->slot_id, false);
+ if (err < 0) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ xhci_free_command(xhci, cfg_cmd);
+ xhci_dbg(xhci, "%s: Failed to queue config ep command, %d ",
+ __func__, err);
+ goto cleanup;
+ }
+
xhci_ring_cmd_db(xhci);
spin_unlock_irqrestore(&xhci->lock, flags);
@@ -3726,6 +3841,7 @@
}
/* If necessary, update the number of active TTs on this root port */
xhci_update_tt_active_eps(xhci, virt_dev, old_active_eps);
+ virt_dev->flags = 0;
ret = 0;
command_cleanup:
@@ -3771,7 +3887,6 @@
virt_dev->eps[i].ep_state &= ~EP_STOP_CMD_PENDING;
del_timer_sync(&virt_dev->eps[i].stop_cmd_timer);
}
- xhci_debugfs_remove_slot(xhci, udev->slot_id);
virt_dev->udev = NULL;
ret = xhci_disable_slot(xhci, udev->slot_id);
if (ret)
@@ -3789,6 +3904,8 @@
if (!command)
return -ENOMEM;
+ xhci_debugfs_remove_slot(xhci, slot_id);
+
spin_lock_irqsave(&xhci->lock, flags);
/* Don't disable the slot if the host controller is dead. */
state = readl(&xhci->op_regs->status);
@@ -4012,6 +4129,7 @@
trace_xhci_address_ctx(xhci, virt_dev->in_ctx,
le32_to_cpu(slot_ctx->dev_info) >> 27);
+ trace_xhci_address_ctrl_ctx(ctrl_ctx);
spin_lock_irqsave(&xhci->lock, flags);
trace_xhci_setup_device(virt_dev);
ret = xhci_queue_address_device(xhci, command, virt_dev->in_ctx->dma,
@@ -4096,6 +4214,8 @@
/* Zero the input context control for later use */
ctrl_ctx->add_flags = 0;
ctrl_ctx->drop_flags = 0;
+ slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
+ udev->devaddr = (u8)(le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK);
xhci_dbg_trace(xhci, trace_xhci_dbg_address,
"Internal device address = %d",
@@ -4289,7 +4409,6 @@
pm_addr = ports[port_num]->addr + PORTPMSC;
pm_val = readl(pm_addr);
hlpm_addr = ports[port_num]->addr + PORTHLPMC;
- field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);
xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n",
enable ? "enable" : "disable", port_num + 1);
@@ -4301,6 +4420,7 @@
* default one which works with mixed HIRD and BESL
* systems. See XHCI_DEFAULT_BESL definition in xhci.h
*/
+ field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);
if ((field & USB_BESL_SUPPORT) &&
(field & USB_BESL_BASELINE_VALID))
hird = USB_GET_BESL_BASELINE(field);
@@ -4388,8 +4508,7 @@
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
int portnum = udev->portnum - 1;
- if (hcd->speed >= HCD_USB3 || !xhci->sw_lpm_support ||
- !udev->lpm_capable)
+ if (hcd->speed >= HCD_USB3 || !udev->lpm_capable)
return 0;
/* we only support lpm for non-hub device connected to root hub yet */
@@ -4628,12 +4747,12 @@
alt_timeout = xhci_call_host_update_timeout_for_endpoint(xhci, udev,
desc, state, timeout);
- /* If we found we can't enable hub-initiated LPM, or
+ /* If we found we can't enable hub-initiated LPM, and
* the U1 or U2 exit latency was too high to allow
- * device-initiated LPM as well, just stop searching.
+ * device-initiated LPM as well, then we will disable LPM
+ * for this device, so stop searching any further.
*/
- if (alt_timeout == USB3_LPM_DISABLED ||
- alt_timeout == USB3_LPM_DEVICE_INITIATED) {
+ if (alt_timeout == USB3_LPM_DISABLED) {
*timeout = alt_timeout;
return -E2BIG;
}
@@ -4744,10 +4863,12 @@
if (intf->dev.driver) {
driver = to_usb_driver(intf->dev.driver);
if (driver && driver->disable_hub_initiated_lpm) {
- dev_dbg(&udev->dev, "Hub-initiated %s disabled "
- "at request of driver %s\n",
- state_name, driver->name);
- return xhci_get_timeout_no_hub_lpm(udev, state);
+ dev_dbg(&udev->dev, "Hub-initiated %s disabled at request of driver %s\n",
+ state_name, driver->name);
+ timeout = xhci_get_timeout_no_hub_lpm(udev,
+ state);
+ if (timeout == USB3_LPM_DISABLED)
+ return timeout;
}
}
@@ -5031,17 +5152,34 @@
hcd->has_tt = 1;
} else {
/*
- * Some 3.1 hosts return sbrn 0x30, use xhci supported protocol
- * minor revision instead of sbrn
+ * Early xHCI 1.1 spec did not mention USB 3.1 capable hosts
+ * should return 0x31 for sbrn, or that the minor revision
+ * is a two digit BCD containig minor and sub-minor numbers.
+ * This was later clarified in xHCI 1.2.
+ *
+ * Some USB 3.1 capable hosts therefore have sbrn 0x30, and
+ * minor revision set to 0x1 instead of 0x10.
*/
- minor_rev = xhci->usb3_rhub.min_rev;
- if (minor_rev) {
+ if (xhci->usb3_rhub.min_rev == 0x1)
+ minor_rev = 1;
+ else
+ minor_rev = xhci->usb3_rhub.min_rev / 0x10;
+
+ switch (minor_rev) {
+ case 2:
+ hcd->speed = HCD_USB32;
+ hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS;
+ hcd->self.root_hub->rx_lanes = 2;
+ hcd->self.root_hub->tx_lanes = 2;
+ break;
+ case 1:
hcd->speed = HCD_USB31;
hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS;
+ break;
}
- xhci_info(xhci, "Host supports USB 3.%x %s SuperSpeed\n",
+ xhci_info(xhci, "Host supports USB 3.%x %sSuperSpeed\n",
minor_rev,
- minor_rev ? "Enhanced" : "");
+ minor_rev ? "Enhanced " : "");
xhci->usb3_rhub.hcd = hcd;
/* xHCI private pointer was set in xhci_pci_probe for the second
@@ -5133,6 +5271,27 @@
}
EXPORT_SYMBOL_GPL(xhci_gen_setup);
+static void xhci_clear_tt_buffer_complete(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct xhci_hcd *xhci;
+ struct usb_device *udev;
+ unsigned int slot_id;
+ unsigned int ep_index;
+ unsigned long flags;
+
+ xhci = hcd_to_xhci(hcd);
+
+ spin_lock_irqsave(&xhci->lock, flags);
+ udev = (struct usb_device *)ep->hcpriv;
+ slot_id = udev->slot_id;
+ ep_index = xhci_get_endpoint_index(&ep->desc);
+
+ xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_CLEARING_TT;
+ xhci_ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+}
+
static const struct hc_driver xhci_hc_driver = {
.description = "xhci-hcd",
.product_desc = "xHCI Host Controller",
@@ -5142,7 +5301,7 @@
* generic hardware linkage
*/
.irq = xhci_irq,
- .flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED,
+ .flags = HCD_MEMORY | HCD_DMA | HCD_USB3 | HCD_SHARED,
/*
* basic lifecycle operations
@@ -5155,6 +5314,7 @@
/*
* managing i/o requests and associated device resources
*/
+ .map_urb_for_dma = xhci_map_urb_for_dma,
.urb_enqueue = xhci_urb_enqueue,
.urb_dequeue = xhci_urb_dequeue,
.alloc_dev = xhci_alloc_dev,
@@ -5163,6 +5323,7 @@
.free_streams = xhci_free_streams,
.add_endpoint = xhci_add_endpoint,
.drop_endpoint = xhci_drop_endpoint,
+ .endpoint_disable = xhci_endpoint_disable,
.endpoint_reset = xhci_endpoint_reset,
.check_bandwidth = xhci_check_bandwidth,
.reset_bandwidth = xhci_reset_bandwidth,
@@ -5193,6 +5354,7 @@
.enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout,
.disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout,
.find_raw_port_number = xhci_find_raw_port_number,
+ .clear_tt_buffer_complete = xhci_clear_tt_buffer_complete,
};
void xhci_init_driver(struct hc_driver *drv,
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index e88060e..f9f8862 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -452,6 +452,14 @@
*/
#define XHCI_DEFAULT_BESL 4
+/*
+ * USB3 specification define a 360ms tPollingLFPSTiemout for USB3 ports
+ * to complete link training. usually link trainig completes much faster
+ * so check status 10 times with 36ms sleep in places we need to wait for
+ * polling to complete.
+ */
+#define XHCI_PORT_POLLING_LFPS_TIME 36
+
/**
* struct xhci_intr_reg - Interrupt Register Set
* @irq_pending: IMAN - Interrupt Management Register. Used to enable
@@ -928,6 +936,8 @@
#define EP_GETTING_NO_STREAMS (1 << 5)
#define EP_HARD_CLEAR_TOGGLE (1 << 6)
#define EP_SOFT_CLEAR_TOGGLE (1 << 7)
+/* usb_hub_clear_tt_buffer is in progress */
+#define EP_CLEARING_TT (1 << 8)
/* ---- Related to URB cancellation ---- */
struct list_head cancelled_td_list;
/* Watchdog timer for stop endpoint command to cancel URBs */
@@ -1002,6 +1012,15 @@
u8 real_port;
struct xhci_interval_bw_table *bw_table;
struct xhci_tt_bw_info *tt_info;
+ /*
+ * flags for state tracking based on events and issued commands.
+ * Software can not rely on states from output contexts because of
+ * latency between events and xHC updating output context values.
+ * See xhci 1.1 section 4.8.3 for more details
+ */
+ unsigned long flags;
+#define VDEV_PORT_ERROR BIT(0) /* Port error, link inactive */
+
/* The current max exit latency for the enabled USB3 link states. */
u16 current_mel;
/* Used for the debugfs interfaces. */
@@ -1295,6 +1314,8 @@
#define TRB_IOC (1<<5)
/* The buffer pointer contains immediate data */
#define TRB_IDT (1<<6)
+/* TDs smaller than this might use IDT */
+#define TRB_IDT_MAX_SIZE 8
/* Block Event Interrupt */
#define TRB_BEI (1<<9)
@@ -1496,6 +1517,7 @@
/* How much data is left before the 64KB boundary? */
#define TRB_BUFF_LEN_UP_TO_BOUNDARY(addr) (TRB_MAX_BUFF_SIZE - \
(addr & (TRB_MAX_BUFF_SIZE - 1)))
+#define MAX_SOFT_RETRY 3
struct xhci_segment {
union xhci_trb *trbs;
@@ -1583,6 +1605,7 @@
* if we own the TRB (if we are the consumer). See section 4.9.1.
*/
u32 cycle_state;
+ unsigned int err_count;
unsigned int stream_id;
unsigned int num_segs;
unsigned int num_trbs_free;
@@ -1680,13 +1703,6 @@
*/
#define XHCI_MAX_REXIT_TIMEOUT_MS 20
-static inline unsigned int hcd_index(struct usb_hcd *hcd)
-{
- if (hcd->speed >= HCD_USB3)
- return 0;
- else
- return 1;
-}
struct xhci_port {
__le32 __iomem *addr;
int hw_portnum;
@@ -1698,6 +1714,8 @@
struct xhci_port **ports;
unsigned int num_ports;
struct usb_hcd *hcd;
+ /* keep track of bus suspend info */
+ struct xhci_bus_state bus_state;
/* supported prococol extended capabiliy values */
u8 maj_rev;
u8 min_rev;
@@ -1846,18 +1864,15 @@
#define XHCI_SUSPEND_DELAY BIT_ULL(30)
#define XHCI_INTEL_USB_ROLE_SW BIT_ULL(31)
#define XHCI_ZERO_64B_REGS BIT_ULL(32)
+#define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33)
#define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34)
#define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35)
unsigned int num_active_eps;
unsigned int limit_active_eps;
- /* There are two roothubs to keep track of bus suspend info for */
- struct xhci_bus_state bus_state[2];
struct xhci_port *hw_ports;
struct xhci_hub usb2_rhub;
struct xhci_hub usb3_rhub;
- /* support xHCI 0.96 spec USB2 software LPM */
- unsigned sw_lpm_support:1;
/* support xHCI 1.0 spec USB2 hardware LPM */
unsigned hw_lpm_support:1;
/* Broken Suspend flag for SNPS Suspend resume issue */
@@ -2098,6 +2113,9 @@
void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
unsigned int ep_index, unsigned int stream_id);
+void xhci_ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
+ unsigned int slot_id,
+ unsigned int ep_index);
void xhci_cleanup_command_queue(struct xhci_hcd *xhci);
void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring);
unsigned int count_trbs(u64 addr, u64 len);
@@ -2147,6 +2165,23 @@
urb->stream_id);
}
+/*
+ * TODO: As per spec Isochronous IDT transmissions are supported. We bypass
+ * them anyways as we where unable to find a device that matches the
+ * constraints.
+ */
+static inline bool xhci_urb_suitable_for_idt(struct urb *urb)
+{
+ if (!usb_endpoint_xfer_isoc(&urb->ep->desc) && usb_urb_dir_out(urb) &&
+ usb_endpoint_maxp(&urb->ep->desc) >= TRB_IDT_MAX_SIZE &&
+ urb->transfer_buffer_length <= TRB_IDT_MAX_SIZE &&
+ !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) &&
+ !urb->num_sgs)
+ return true;
+
+ return false;
+}
+
static inline char *xhci_slot_state_string(u32 state)
{
switch (state) {
@@ -2302,12 +2337,13 @@
break;
case TRB_RESET_EP:
sprintf(str,
- "%s: ctx %08x%08x slot %d ep %d flags %c",
+ "%s: ctx %08x%08x slot %d ep %d flags %c:%c",
xhci_trb_type_string(type),
field1, field0,
TRB_TO_SLOT_ID(field3),
/* Macro decrements 1, maybe it shouldn't?!? */
TRB_TO_EP_INDEX(field3) + 1,
+ field3 & TRB_TSP ? 'T' : 't',
field3 & TRB_CYCLE ? 'C' : 'c');
break;
case TRB_STOP_RING:
@@ -2382,6 +2418,35 @@
return str;
}
+static inline const char *xhci_decode_ctrl_ctx(unsigned long drop,
+ unsigned long add)
+{
+ static char str[1024];
+ unsigned int bit;
+ int ret = 0;
+
+ if (drop) {
+ ret = sprintf(str, "Drop:");
+ for_each_set_bit(bit, &drop, 32)
+ ret += sprintf(str + ret, " %d%s",
+ bit / 2,
+ bit % 2 ? "in":"out");
+ ret += sprintf(str + ret, ", ");
+ }
+
+ if (add) {
+ ret += sprintf(str + ret, "Add:%s%s",
+ (add & SLOT_FLAG) ? " slot":"",
+ (add & EP0_FLAG) ? " ep0":"");
+ add &= ~(SLOT_FLAG | EP0_FLAG);
+ for_each_set_bit(bit, &add, 32)
+ ret += sprintf(str + ret, " %d%s",
+ bit / 2,
+ bit % 2 ? "in":"out");
+ }
+ return str;
+}
+
static inline const char *xhci_decode_slot_context(u32 info, u32 info2,
u32 tt_info, u32 state)
{