summaryrefslogtreecommitdiff
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/ehci-hcd.c8
-rw-r--r--drivers/usb/host/ehci-hub.c10
-rw-r--r--drivers/usb/host/ehci-sched.c3
-rw-r--r--drivers/usb/host/ehci.h9
-rw-r--r--drivers/usb/host/xhci-plat.c11
-rw-r--r--drivers/usb/host/xhci-plat.h1
-rw-r--r--drivers/usb/host/xhci.c12
-rw-r--r--drivers/usb/host/xhci.h17
8 files changed, 55 insertions, 16 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index a1930db0da1c..68674b19f15d 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -755,10 +755,14 @@ restart:
/* 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))
+ if (likely ((status & STS_ERR) == 0)) {
INCR(ehci->stats.normal);
- else
+ } else {
+ /* Force to check port status */
+ if (ehci->has_fsl_port_bug)
+ status |= STS_PCD;
INCR(ehci->stats.error);
+ }
bh = 1;
}
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index efe30e3be22f..1aee392e8492 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -674,7 +674,8 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
if ((temp & mask) != 0 || test_bit(i, &ehci->port_c_suspend)
|| (ehci->reset_done[i] && time_after_eq(
- jiffies, ehci->reset_done[i]))) {
+ jiffies, ehci->reset_done[i]))
+ || ehci_has_ci_pec_bug(ehci, temp)) {
if (i < 7)
buf [0] |= 1 << (i + 1);
else
@@ -875,6 +876,13 @@ int ehci_hub_control(
if (temp & PORT_PEC)
status |= USB_PORT_STAT_C_ENABLE << 16;
+ if (ehci_has_ci_pec_bug(ehci, temp)) {
+ status |= USB_PORT_STAT_C_ENABLE << 16;
+ ehci_info(ehci,
+ "PE is cleared by HW port:%d PORTSC:%08x\n",
+ wIndex + 1, temp);
+ }
+
if ((temp & PORT_OCC) && (!ignore_oc && !ehci->spurious_oc)){
status |= USB_PORT_STAT_C_OVERCURRENT << 16;
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index bd542b6fc46b..7e834587e7de 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -490,13 +490,14 @@ static int tt_no_collision(
static void enable_periodic(struct ehci_hcd *ehci)
{
if (ehci->periodic_count++)
- return;
+ goto out;
/* Stop waiting to turn off the periodic schedule */
ehci->enabled_hrtimer_events &= ~BIT(EHCI_HRTIMER_DISABLE_PERIODIC);
/* Don't start the schedule until PSS is 0 */
ehci_poll_PSS(ehci);
+out:
turn_on_io_watchdog(ehci);
}
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index ad3f13a3eaf1..4ee0d34323cf 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -708,6 +708,15 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
#define ehci_has_fsl_susp_errata(e) ((e)->has_fsl_susp_errata)
/*
+ * Some Freescale/NXP processors using ChipIdea IP have a bug in which
+ * disabling the port (PE is cleared) does not cause PEC to be asserted
+ * when frame babble is detected.
+ */
+#define ehci_has_ci_pec_bug(e, portsc) \
+ ((e)->has_fsl_port_bug && ((e)->command & CMD_PSE) \
+ && !(portsc & PORT_PEC) && !(portsc & PORT_PE))
+
+/*
* While most USB host controllers implement their registers in
* little-endian format, a minority (celleb companion chip) implement
* them in big endian format.
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 2ef716fc3212..3829e1be0383 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -188,11 +188,10 @@ EXPORT_SYMBOL_GPL(xhci_plat_register_vendor_ops);
static int xhci_vendor_init(struct xhci_hcd *xhci)
{
- struct xhci_vendor_ops *ops = xhci_vendor_get_ops(xhci);
- struct xhci_plat_priv *priv = xhci_to_priv(xhci);
+ struct xhci_vendor_ops *ops = NULL;
if (xhci_plat_vendor_overwrite.vendor_ops)
- ops = priv->vendor_ops = xhci_plat_vendor_overwrite.vendor_ops;
+ ops = xhci->vendor_ops = xhci_plat_vendor_overwrite.vendor_ops;
if (ops && ops->vendor_init)
return ops->vendor_init(xhci);
@@ -202,12 +201,11 @@ static int xhci_vendor_init(struct xhci_hcd *xhci)
static void xhci_vendor_cleanup(struct xhci_hcd *xhci)
{
struct xhci_vendor_ops *ops = xhci_vendor_get_ops(xhci);
- struct xhci_plat_priv *priv = xhci_to_priv(xhci);
if (ops && ops->vendor_cleanup)
ops->vendor_cleanup(xhci);
- priv->vendor_ops = NULL;
+ xhci->vendor_ops = NULL;
}
static int xhci_plat_probe(struct platform_device *pdev)
@@ -436,8 +434,8 @@ static int xhci_plat_remove(struct platform_device *dev)
struct clk *reg_clk = xhci->reg_clk;
struct usb_hcd *shared_hcd = xhci->shared_hcd;
- pm_runtime_get_sync(&dev->dev);
xhci->xhc_state |= XHCI_STATE_REMOVING;
+ pm_runtime_get_sync(&dev->dev);
if (shared_hcd) {
usb_remove_hcd(shared_hcd);
@@ -453,7 +451,6 @@ static int xhci_plat_remove(struct platform_device *dev)
xhci_vendor_cleanup(xhci);
- usb_put_hcd(shared_hcd);
clk_disable_unprepare(clk);
clk_disable_unprepare(reg_clk);
usb_put_hcd(hcd);
diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h
index 5b096f72636f..e726a572321d 100644
--- a/drivers/usb/host/xhci-plat.h
+++ b/drivers/usb/host/xhci-plat.h
@@ -13,7 +13,6 @@
struct xhci_plat_priv {
const char *firmware_name;
unsigned long long quirks;
- struct xhci_vendor_ops *vendor_ops;
struct xhci_vendor_data *vendor_data;
int (*plat_setup)(struct usb_hcd *);
void (*plat_start)(struct usb_hcd *);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 4f33afa418b0..be041bd65b19 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -25,7 +25,6 @@
#include "xhci-trace.h"
#include "xhci-debugfs.h"
#include "xhci-dbgcap.h"
-#include "xhci-plat.h"
#define DRIVER_AUTHOR "Sarah Sharp"
#define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
@@ -1194,7 +1193,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
temp = readl(&xhci->op_regs->status);
/* re-initialize the HC on Restore Error, or Host Controller Error */
- if (temp & (STS_SRE | STS_HCE)) {
+ if ((temp & (STS_SRE | STS_HCE)) &&
+ !(xhci->xhc_state & XHCI_STATE_REMOVING)) {
reinit_xhc = true;
if (!xhci->broken_suspend)
xhci_warn(xhci, "xHC error in resume, USBSTS 0x%x, Reinit\n", temp);
@@ -4516,7 +4516,7 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci,
struct xhci_vendor_ops *xhci_vendor_get_ops(struct xhci_hcd *xhci)
{
- return xhci_to_priv(xhci)->vendor_ops;
+ return xhci->vendor_ops;
}
EXPORT_SYMBOL_GPL(xhci_vendor_get_ops);
@@ -5619,6 +5619,12 @@ void xhci_init_driver(struct hc_driver *drv,
drv->reset_bandwidth = over->reset_bandwidth;
if (over->update_hub_device)
drv->update_hub_device = over->update_hub_device;
+ if (over->address_device)
+ drv->address_device = over->address_device;
+ if (over->bus_suspend)
+ drv->bus_suspend = over->bus_suspend;
+ if (over->bus_resume)
+ drv->bus_resume = over->bus_resume;
}
}
EXPORT_SYMBOL_GPL(xhci_init_driver);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index eb2e66a68693..dd634668f5d4 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1941,7 +1941,9 @@ struct xhci_hcd {
void *dbc;
- ANDROID_KABI_RESERVE(1);
+ /* Used for bug 194461020 */
+ ANDROID_KABI_USE(1, struct xhci_vendor_ops *vendor_ops);
+
ANDROID_KABI_RESERVE(2);
ANDROID_KABI_RESERVE(3);
ANDROID_KABI_RESERVE(4);
@@ -1963,6 +1965,14 @@ struct xhci_driver_overrides {
void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
int (*update_hub_device)(struct usb_hcd *hcd, struct usb_device *hdev,
struct usb_tt *tt, gfp_t mem_flags);
+ int (*address_device)(struct usb_hcd *hcd, struct usb_device *udev);
+ int (*bus_suspend)(struct usb_hcd *hcd);
+ int (*bus_resume)(struct usb_hcd *hcd);
+
+ ANDROID_KABI_RESERVE(1);
+ ANDROID_KABI_RESERVE(2);
+ ANDROID_KABI_RESERVE(3);
+ ANDROID_KABI_RESERVE(4);
};
#define XHCI_CFC_DELAY 10
@@ -2288,6 +2298,11 @@ struct xhci_vendor_ops {
void (*alloc_container_ctx)(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx,
int type, gfp_t flags);
void (*free_container_ctx)(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx);
+
+ ANDROID_KABI_RESERVE(1);
+ ANDROID_KABI_RESERVE(2);
+ ANDROID_KABI_RESERVE(3);
+ ANDROID_KABI_RESERVE(4);
};
struct xhci_vendor_ops *xhci_vendor_get_ops(struct xhci_hcd *xhci);