Commit 93f1a47c authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

USB: add ehci_hcd.ignore_oc parameter

Certain boards seem to like to issue false overcurrent notifications, for
example on ports that don't have anything connected to them.  This looks
like a hardware error, at the level of noise to those ports' overcurrent
input signals (or non-debounced VBUS comparators).  This surfaces to users
as truly massive amounts of syslog spam from khubd (which is appropriate
for real hardware problems, except for the volume from multiple ports).

Using this new "ignore_oc" flag helps such systems work more sanely, by
preventing such indications from getting to khubd (and spam syslog).  The
downside is of course that true overcurrent errors will be masked; they'll
appear as spontaneous disconnects, without the diagnostics that will let
users troubleshoot issues like short circuited cables.

Note that the bulk of these reports seem to be with VIA southbridges, but
I think some were with Intel ones.
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent f0d7f273
...@@ -126,6 +126,11 @@ static unsigned park = 0; ...@@ -126,6 +126,11 @@ static unsigned park = 0;
module_param (park, uint, S_IRUGO); module_param (park, uint, S_IRUGO);
MODULE_PARM_DESC (park, "park setting; 1-3 back-to-back async packets"); MODULE_PARM_DESC (park, "park setting; 1-3 back-to-back async packets");
/* for flakey hardware, ignore overcurrent indicators */
static int ignore_oc = 0;
module_param (ignore_oc, bool, S_IRUGO);
MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");
#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT) #define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -541,9 +546,10 @@ static int ehci_run (struct usb_hcd *hcd) ...@@ -541,9 +546,10 @@ static int ehci_run (struct usb_hcd *hcd)
temp = HC_VERSION(readl (&ehci->caps->hc_capbase)); temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
ehci_info (ehci, ehci_info (ehci,
"USB %x.%x started, EHCI %x.%02x, driver %s\n", "USB %x.%x started, EHCI %x.%02x, driver %s%s\n",
((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
temp >> 8, temp & 0xff, DRIVER_VERSION); temp >> 8, temp & 0xff, DRIVER_VERSION,
ignore_oc ? ", overcurrent ignored" : "");
writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */ writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
......
...@@ -218,6 +218,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) ...@@ -218,6 +218,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
{ {
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 temp, status = 0; u32 temp, status = 0;
u32 mask;
int ports, i, retval = 1; int ports, i, retval = 1;
unsigned long flags; unsigned long flags;
...@@ -233,6 +234,18 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) ...@@ -233,6 +234,18 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
retval++; retval++;
} }
/* Some boards (mostly VIA?) report bogus overcurrent indications,
* causing massive log spam unless we completely ignore them. It
* may be relevant that VIA VT8235 controlers, where PORT_POWER is
* always set, seem to clear PORT_OCC and PORT_CSC when writing to
* PORT_POWER; that's surprising, but maybe within-spec.
*/
if (!ignore_oc)
mask = PORT_CSC | PORT_PEC | PORT_OCC;
else
mask = PORT_CSC | PORT_PEC;
// PORT_RESUME from hardware ~= PORT_STAT_C_SUSPEND
/* no hub change reports (bit 0) for now (power, ...) */ /* no hub change reports (bit 0) for now (power, ...) */
/* port N changes (bit N)? */ /* port N changes (bit N)? */
...@@ -250,8 +263,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) ...@@ -250,8 +263,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
} }
if (!(temp & PORT_CONNECT)) if (!(temp & PORT_CONNECT))
ehci->reset_done [i] = 0; ehci->reset_done [i] = 0;
if ((temp & (PORT_CSC | PORT_PEC | PORT_OCC)) != 0 if ((temp & mask) != 0
// PORT_STAT_C_SUSPEND?
|| ((temp & PORT_RESUME) != 0 || ((temp & PORT_RESUME) != 0
&& time_after (jiffies, && time_after (jiffies,
ehci->reset_done [i]))) { ehci->reset_done [i]))) {
...@@ -418,7 +430,7 @@ static int ehci_hub_control ( ...@@ -418,7 +430,7 @@ static int ehci_hub_control (
status |= 1 << USB_PORT_FEAT_C_CONNECTION; status |= 1 << USB_PORT_FEAT_C_CONNECTION;
if (temp & PORT_PEC) if (temp & PORT_PEC)
status |= 1 << USB_PORT_FEAT_C_ENABLE; status |= 1 << USB_PORT_FEAT_C_ENABLE;
if (temp & PORT_OCC) if ((temp & PORT_OCC) && !ignore_oc)
status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT; status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
/* whoever resumes must GetPortStatus to complete it!! */ /* whoever resumes must GetPortStatus to complete it!! */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment