aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2005-04-09 12:00:29 -0400
committerGreg KH <gregkh@suse.de>2005-05-04 02:31:49 -0400
commit56c1e26d75008d39f1067f453719857a81109d9f (patch)
treef75ba4203962410bb9ec1ea159c4055a4ee09710
parente2e66446e08a7a365a59e25bbc8dd320ab3da0a6 (diff)
[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>
-rw-r--r--drivers/usb/host/ehci-hcd.c65
-rw-r--r--drivers/usb/host/ehci-hub.c2
-rw-r--r--drivers/usb/host/ehci.h19
3 files changed, 56 insertions, 30 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 84d2b93aca37..bc69bd7acebe 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -346,6 +346,22 @@ ehci_reboot (struct notifier_block *self, unsigned long code, void *null)
346 return 0; 346 return 0;
347} 347}
348 348
349static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
350{
351 unsigned port;
352
353 if (!HCS_PPC (ehci->hcs_params))
354 return;
355
356 ehci_dbg (ehci, "...power%s ports...\n", is_on ? "up" : "down");
357 for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; )
358 (void) ehci_hub_control(ehci_to_hcd(ehci),
359 is_on ? SetPortFeature : ClearPortFeature,
360 USB_PORT_FEAT_POWER,
361 port--, NULL, 0);
362 msleep(20);
363}
364
349 365
350/* called by khubd or root hub init threads */ 366/* called by khubd or root hub init threads */
351 367
@@ -362,8 +378,10 @@ static int ehci_hc_reset (struct usb_hcd *hcd)
362 dbg_hcs_params (ehci, "reset"); 378 dbg_hcs_params (ehci, "reset");
363 dbg_hcc_params (ehci, "reset"); 379 dbg_hcc_params (ehci, "reset");
364 380
381 /* cache this readonly data; minimize chip reads */
382 ehci->hcs_params = readl (&ehci->caps->hcs_params);
383
365#ifdef CONFIG_PCI 384#ifdef CONFIG_PCI
366 /* EHCI 0.96 and later may have "extended capabilities" */
367 if (hcd->self.controller->bus == &pci_bus_type) { 385 if (hcd->self.controller->bus == &pci_bus_type) {
368 struct pci_dev *pdev = to_pci_dev(hcd->self.controller); 386 struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
369 387
@@ -383,9 +401,30 @@ static int ehci_hc_reset (struct usb_hcd *hcd)
383 break; 401 break;
384 } 402 }
385 403
404 /* optional debug port, normally in the first BAR */
405 temp = pci_find_capability (pdev, 0x0a);
406 if (temp) {
407 pci_read_config_dword(pdev, temp, &temp);
408 temp >>= 16;
409 if ((temp & (3 << 13)) == (1 << 13)) {
410 temp &= 0x1fff;
411 ehci->debug = hcd->regs + temp;
412 temp = readl (&ehci->debug->control);
413 ehci_info (ehci, "debug port %d%s\n",
414 HCS_DEBUG_PORT(ehci->hcs_params),
415 (temp & DBGP_ENABLED)
416 ? " IN USE"
417 : "");
418 if (!(temp & DBGP_ENABLED))
419 ehci->debug = NULL;
420 }
421 }
422
386 temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params)); 423 temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
387 } else 424 } else
388 temp = 0; 425 temp = 0;
426
427 /* EHCI 0.96 and later may have "extended capabilities" */
389 while (temp && count--) { 428 while (temp && count--) {
390 u32 cap; 429 u32 cap;
391 430
@@ -414,8 +453,7 @@ static int ehci_hc_reset (struct usb_hcd *hcd)
414 ehci_reset (ehci); 453 ehci_reset (ehci);
415#endif 454#endif
416 455
417 /* cache this readonly data; minimize PCI reads */ 456 ehci_port_power (ehci, 0);
418 ehci->hcs_params = readl (&ehci->caps->hcs_params);
419 457
420 /* at least the Genesys GL880S needs fixup here */ 458 /* at least the Genesys GL880S needs fixup here */
421 temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params); 459 temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
@@ -657,16 +695,11 @@ done2:
657static void ehci_stop (struct usb_hcd *hcd) 695static void ehci_stop (struct usb_hcd *hcd)
658{ 696{
659 struct ehci_hcd *ehci = hcd_to_ehci (hcd); 697 struct ehci_hcd *ehci = hcd_to_ehci (hcd);
660 u8 rh_ports, port;
661 698
662 ehci_dbg (ehci, "stop\n"); 699 ehci_dbg (ehci, "stop\n");
663 700
664 /* Turn off port power on all root hub ports. */ 701 /* Turn off port power on all root hub ports. */
665 rh_ports = HCS_N_PORTS (ehci->hcs_params); 702 ehci_port_power (ehci, 0);
666 for (port = 1; port <= rh_ports; port++)
667 (void) ehci_hub_control(hcd,
668 ClearPortFeature, USB_PORT_FEAT_POWER,
669 port, NULL, 0);
670 703
671 /* no more interrupts ... */ 704 /* no more interrupts ... */
672 del_timer_sync (&ehci->watchdog); 705 del_timer_sync (&ehci->watchdog);
@@ -748,7 +781,6 @@ static int ehci_resume (struct usb_hcd *hcd)
748 unsigned port; 781 unsigned port;
749 struct usb_device *root = hcd->self.root_hub; 782 struct usb_device *root = hcd->self.root_hub;
750 int retval = -EINVAL; 783 int retval = -EINVAL;
751 int powerup = 0;
752 784
753 // maybe restore (PCI) FLADJ 785 // maybe restore (PCI) FLADJ
754 786
@@ -766,8 +798,6 @@ static int ehci_resume (struct usb_hcd *hcd)
766 up (&hcd->self.root_hub->serialize); 798 up (&hcd->self.root_hub->serialize);
767 break; 799 break;
768 } 800 }
769 if ((status & PORT_POWER) == 0)
770 powerup = 1;
771 if (!root->children [port]) 801 if (!root->children [port])
772 continue; 802 continue;
773 dbg_port (ehci, __FUNCTION__, port + 1, status); 803 dbg_port (ehci, __FUNCTION__, port + 1, status);
@@ -794,16 +824,9 @@ static int ehci_resume (struct usb_hcd *hcd)
794 retval = ehci_start (hcd); 824 retval = ehci_start (hcd);
795 825
796 /* here we "know" root ports should always stay powered; 826 /* here we "know" root ports should always stay powered;
797 * but some controllers may lost all power. 827 * but some controllers may lose all power.
798 */ 828 */
799 if (powerup) { 829 ehci_port_power (ehci, 1);
800 ehci_dbg (ehci, "...powerup ports...\n");
801 for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; )
802 (void) ehci_hub_control(hcd,
803 SetPortFeature, USB_PORT_FEAT_POWER,
804 port--, NULL, 0);
805 msleep(20);
806 }
807 } 830 }
808 831
809 return retval; 832 return retval;
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 2373537fabed..02fefab3501e 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -281,6 +281,8 @@ ehci_hub_descriptor (
281 temp = 0x0008; /* per-port overcurrent reporting */ 281 temp = 0x0008; /* per-port overcurrent reporting */
282 if (HCS_PPC (ehci->hcs_params)) 282 if (HCS_PPC (ehci->hcs_params))
283 temp |= 0x0001; /* per-port power control */ 283 temp |= 0x0001; /* per-port power control */
284 else
285 temp |= 0x0002; /* no power switching */
284#if 0 286#if 0
285// re-enable when we support USB_PORT_FEAT_INDICATOR below. 287// re-enable when we support USB_PORT_FEAT_INDICATOR below.
286 if (HCS_INDICATOR (ehci->hcs_params)) 288 if (HCS_INDICATOR (ehci->hcs_params))
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index e763a8399a75..4df498231752 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -47,6 +47,12 @@ struct ehci_stats {
47#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */ 47#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */
48 48
49struct ehci_hcd { /* one per controller */ 49struct ehci_hcd { /* one per controller */
50 /* glue to PCI and HCD framework */
51 struct ehci_caps __iomem *caps;
52 struct ehci_regs __iomem *regs;
53 struct ehci_dbg_port __iomem *debug;
54
55 __u32 hcs_params; /* cached register copy */
50 spinlock_t lock; 56 spinlock_t lock;
51 57
52 /* async schedule support */ 58 /* async schedule support */
@@ -84,11 +90,6 @@ struct ehci_hcd { /* one per controller */
84 90
85 unsigned is_tdi_rh_tt:1; /* TDI roothub with TT */ 91 unsigned is_tdi_rh_tt:1; /* TDI roothub with TT */
86 92
87 /* glue to PCI and HCD framework */
88 struct ehci_caps __iomem *caps;
89 struct ehci_regs __iomem *regs;
90 __u32 hcs_params; /* cached register copy */
91
92 /* irq statistics */ 93 /* irq statistics */
93#ifdef EHCI_STATS 94#ifdef EHCI_STATS
94 struct ehci_stats stats; 95 struct ehci_stats stats;
@@ -165,7 +166,7 @@ struct ehci_caps {
165 /* these fields are specified as 8 and 16 bit registers, 166 /* these fields are specified as 8 and 16 bit registers,
166 * but some hosts can't perform 8 or 16 bit PCI accesses. 167 * but some hosts can't perform 8 or 16 bit PCI accesses.
167 */ 168 */
168 u32 hc_capbase; 169 u32 hc_capbase;
169#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */ 170#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */
170#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */ 171#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */
171 u32 hcs_params; /* HCSPARAMS - offset 0x4 */ 172 u32 hcs_params; /* HCSPARAMS - offset 0x4 */
@@ -273,7 +274,7 @@ struct ehci_dbg_port {
273#define DBGP_ENABLED (1<<28) 274#define DBGP_ENABLED (1<<28)
274#define DBGP_DONE (1<<16) 275#define DBGP_DONE (1<<16)
275#define DBGP_INUSE (1<<10) 276#define DBGP_INUSE (1<<10)
276#define DBGP_ERRCODE(x) (((x)>>7)&0x0f) 277#define DBGP_ERRCODE(x) (((x)>>7)&0x07)
277# define DBGP_ERR_BAD 1 278# define DBGP_ERR_BAD 1
278# define DBGP_ERR_SIGNAL 2 279# define DBGP_ERR_SIGNAL 2
279#define DBGP_ERROR (1<<6) 280#define DBGP_ERROR (1<<6)
@@ -282,11 +283,11 @@ struct ehci_dbg_port {
282#define DBGP_LEN(x) (((x)>>0)&0x0f) 283#define DBGP_LEN(x) (((x)>>0)&0x0f)
283 u32 pids; 284 u32 pids;
284#define DBGP_PID_GET(x) (((x)>>16)&0xff) 285#define DBGP_PID_GET(x) (((x)>>16)&0xff)
285#define DBGP_PID_SET(data,tok) (((data)<<8)|(tok)); 286#define DBGP_PID_SET(data,tok) (((data)<<8)|(tok))
286 u32 data03; 287 u32 data03;
287 u32 data47; 288 u32 data47;
288 u32 address; 289 u32 address;
289#define DBGP_EPADDR(dev,ep) (((dev)<<8)|(ep)); 290#define DBGP_EPADDR(dev,ep) (((dev)<<8)|(ep))
290} __attribute__ ((packed)); 291} __attribute__ ((packed));
291 292
292/*-------------------------------------------------------------------------*/ 293/*-------------------------------------------------------------------------*/