[PATCH] USB: ehci power fixes
Miscellaneous updates for EHCI. - Mostly updates the power switching on EHCI controllers. One routine centralizes the "power on/off all ports" logic, and the capability to do that is reported more correctly. - Courtesy Colin Leroy, a patch to always power up ports after resumes which didn't keep a USB device suspended. The reset-everything logic powers down those ports (on some hardware) so something needs to turn them back on. - Minor tweaks/bugfixes for the debug port support. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
@@ -346,6 +346,22 @@ ehci_reboot (struct notifier_block *self, unsigned long code, void *null)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
|
||||
{
|
||||
unsigned port;
|
||||
|
||||
if (!HCS_PPC (ehci->hcs_params))
|
||||
return;
|
||||
|
||||
ehci_dbg (ehci, "...power%s ports...\n", is_on ? "up" : "down");
|
||||
for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; )
|
||||
(void) ehci_hub_control(ehci_to_hcd(ehci),
|
||||
is_on ? SetPortFeature : ClearPortFeature,
|
||||
USB_PORT_FEAT_POWER,
|
||||
port--, NULL, 0);
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
|
||||
/* called by khubd or root hub init threads */
|
||||
|
||||
@@ -362,8 +378,10 @@ static int ehci_hc_reset (struct usb_hcd *hcd)
|
||||
dbg_hcs_params (ehci, "reset");
|
||||
dbg_hcc_params (ehci, "reset");
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = readl (&ehci->caps->hcs_params);
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
/* EHCI 0.96 and later may have "extended capabilities" */
|
||||
if (hcd->self.controller->bus == &pci_bus_type) {
|
||||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||
|
||||
@@ -383,9 +401,30 @@ static int ehci_hc_reset (struct usb_hcd *hcd)
|
||||
break;
|
||||
}
|
||||
|
||||
/* optional debug port, normally in the first BAR */
|
||||
temp = pci_find_capability (pdev, 0x0a);
|
||||
if (temp) {
|
||||
pci_read_config_dword(pdev, temp, &temp);
|
||||
temp >>= 16;
|
||||
if ((temp & (3 << 13)) == (1 << 13)) {
|
||||
temp &= 0x1fff;
|
||||
ehci->debug = hcd->regs + temp;
|
||||
temp = readl (&ehci->debug->control);
|
||||
ehci_info (ehci, "debug port %d%s\n",
|
||||
HCS_DEBUG_PORT(ehci->hcs_params),
|
||||
(temp & DBGP_ENABLED)
|
||||
? " IN USE"
|
||||
: "");
|
||||
if (!(temp & DBGP_ENABLED))
|
||||
ehci->debug = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
|
||||
} else
|
||||
temp = 0;
|
||||
|
||||
/* EHCI 0.96 and later may have "extended capabilities" */
|
||||
while (temp && count--) {
|
||||
u32 cap;
|
||||
|
||||
@@ -414,8 +453,7 @@ static int ehci_hc_reset (struct usb_hcd *hcd)
|
||||
ehci_reset (ehci);
|
||||
#endif
|
||||
|
||||
/* cache this readonly data; minimize PCI reads */
|
||||
ehci->hcs_params = readl (&ehci->caps->hcs_params);
|
||||
ehci_port_power (ehci, 0);
|
||||
|
||||
/* at least the Genesys GL880S needs fixup here */
|
||||
temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
|
||||
@@ -657,16 +695,11 @@ done2:
|
||||
static void ehci_stop (struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
|
||||
u8 rh_ports, port;
|
||||
|
||||
ehci_dbg (ehci, "stop\n");
|
||||
|
||||
/* Turn off port power on all root hub ports. */
|
||||
rh_ports = HCS_N_PORTS (ehci->hcs_params);
|
||||
for (port = 1; port <= rh_ports; port++)
|
||||
(void) ehci_hub_control(hcd,
|
||||
ClearPortFeature, USB_PORT_FEAT_POWER,
|
||||
port, NULL, 0);
|
||||
ehci_port_power (ehci, 0);
|
||||
|
||||
/* no more interrupts ... */
|
||||
del_timer_sync (&ehci->watchdog);
|
||||
@@ -748,7 +781,6 @@ static int ehci_resume (struct usb_hcd *hcd)
|
||||
unsigned port;
|
||||
struct usb_device *root = hcd->self.root_hub;
|
||||
int retval = -EINVAL;
|
||||
int powerup = 0;
|
||||
|
||||
// maybe restore (PCI) FLADJ
|
||||
|
||||
@@ -766,8 +798,6 @@ static int ehci_resume (struct usb_hcd *hcd)
|
||||
up (&hcd->self.root_hub->serialize);
|
||||
break;
|
||||
}
|
||||
if ((status & PORT_POWER) == 0)
|
||||
powerup = 1;
|
||||
if (!root->children [port])
|
||||
continue;
|
||||
dbg_port (ehci, __FUNCTION__, port + 1, status);
|
||||
@@ -794,16 +824,9 @@ static int ehci_resume (struct usb_hcd *hcd)
|
||||
retval = ehci_start (hcd);
|
||||
|
||||
/* here we "know" root ports should always stay powered;
|
||||
* but some controllers may lost all power.
|
||||
* but some controllers may lose all power.
|
||||
*/
|
||||
if (powerup) {
|
||||
ehci_dbg (ehci, "...powerup ports...\n");
|
||||
for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; )
|
||||
(void) ehci_hub_control(hcd,
|
||||
SetPortFeature, USB_PORT_FEAT_POWER,
|
||||
port--, NULL, 0);
|
||||
msleep(20);
|
||||
}
|
||||
ehci_port_power (ehci, 1);
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
Reference in New Issue
Block a user