* [PATCH] USB suspend when no devices attached
@ 2001-03-17 0:21 Grover, Andrew
2001-03-17 0:31 ` [Acpi] " Johannes Erdfelt
0 siblings, 1 reply; 2+ messages in thread
From: Grover, Andrew @ 2001-03-17 0:21 UTC (permalink / raw)
To: 'linux-usb-devel@lists.sourceforge.net'
Cc: 'linux-kernel@vger.kernel.org', Acpi-linux (E-mail)
[-- Attachment #1: Type: text/plain, Size: 1093 bytes --]
Hi all.
This is a preliminary patch against 2.4.2 to uhci.c that puts the host
controller into global suspend when there are no devices attached. This
conserves power on mobile systems, and because suspending the host
controller ceases UHCI's incessant busmastering activity, it allows the CPU
to enter a deeper idle state.
The main problem with this implementation is that it just looks at the 2
root hub ports and suspends if nothing is connected. Ideally, it would be
smart enough to realize it can also suspend when only hubs are present, or
when all devices on the USB are also suspended. I hope a USB expert can add
these enhancements, as it's beyond me.
You should be able to verify this patch is working in one of two ways:
1) Turn on USB debug messages, and look for suspend_hc and wakeup_hc
messages
2) Download the latest ACPI patch from
http://developer.intel.com/technology/iapc/acpi/downloads.htm and verify
that /proc/acpi/processor/0/status shows mostly 0's for busmastering
activity (as opposed to mostly F's) when no USB devices are connected.
Thanks -- Regards -- Andy
[-- Attachment #2: uhci.diff --]
[-- Type: application/octet-stream, Size: 3138 bytes --]
diff -ruN -X exclude /usr/src/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- /usr/src/linux/drivers/usb/uhci.c Fri Feb 9 11:30:23 2001
+++ linux/drivers/usb/uhci.c Fri Mar 16 16:46:29 2001
@@ -66,6 +66,10 @@
static int uhci_unlink_generic(struct urb *urb);
static int uhci_unlink_urb(struct urb *urb);
+static int ports_active(struct uhci *uhci);
+static void suspend_hc(struct uhci *uhci);
+static void wakeup_hc(struct uhci *uhci);
+
#define min(a,b) (((a)<(b))?(a):(b))
/* If a transfer is still active after this much time, turn off FSBR */
@@ -1767,6 +1771,10 @@
}
nested_unlock(&uhci->urblist_lock, flags);
+ /* enter global suspend if nothing connected */
+ if (!uhci->is_suspended && !ports_active(uhci))
+ suspend_hc(uhci);
+
rh_init_int_timer(urb);
}
@@ -2037,19 +2045,21 @@
return;
outw(status, io_addr + USBSTS);
- if (status & ~(USBSTS_USBINT | USBSTS_ERROR)) {
- if (status & USBSTS_RD)
- printk(KERN_INFO "uhci: resume detected, not implemented\n");
+ if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
if (status & USBSTS_HSE)
printk(KERN_ERR "uhci: host system error, PCI problems?\n");
if (status & USBSTS_HCPE)
printk(KERN_ERR "uhci: host controller process error. something bad happened\n");
- if (status & USBSTS_HCH) {
+ if ((status & USBSTS_HCH) && !uhci->is_suspended) {
printk(KERN_ERR "uhci: host controller halted. very bad\n");
/* FIXME: Reset the controller, fix the offending TD */
}
}
+ if (status & USBSTS_RD) {
+ wakeup_hc(uhci);
+ }
+
uhci_free_pending_qhs(uhci);
spin_lock(&uhci->urb_remove_lock);
@@ -2093,6 +2103,51 @@
wait_ms(50);
outw(0, io_addr + USBCMD);
wait_ms(10);
+}
+
+static void suspend_hc(struct uhci *uhci)
+{
+ unsigned int io_addr = uhci->io_addr;
+
+ dbg("suspend_hc");
+
+ outw(USBCMD_EGSM, io_addr + USBCMD);
+
+ uhci->is_suspended = 1;
+}
+
+static void wakeup_hc(struct uhci *uhci)
+{
+ unsigned int io_addr = uhci->io_addr;
+ unsigned int status;
+
+ dbg("wakeup_hc");
+
+ outw(0, io_addr + USBCMD);
+
+ /* wait for EOP to be sent */
+ status = inw(io_addr + USBCMD);
+ while (status & USBCMD_FGR) {
+ status = inw(io_addr + USBCMD);
+ }
+
+ uhci->is_suspended = 0;
+
+ /* Run and mark it configured with a 64-byte max packet */
+ outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
+}
+
+static int ports_active(struct uhci *uhci)
+{
+ unsigned int io_addr = uhci->io_addr;
+ int connection = 0;
+ int i;
+
+ for (i = 0; i < uhci->rh.numports; i++) {
+ connection |= (inw (io_addr + USBPORTSC1 + i * 2) & 0x1);
+ }
+
+ return (connection);
}
static void start_hc(struct uhci *uhci)
diff -ruN -X exclude /usr/src/linux/drivers/usb/uhci.h linux/drivers/usb/uhci.h
--- /usr/src/linux/drivers/usb/uhci.h Wed Feb 21 16:11:49 2001
+++ linux/drivers/usb/uhci.h Fri Mar 16 16:09:29 2001
@@ -332,6 +332,8 @@
struct list_head urb_list;
struct virt_root_hub rh; /* private data of the virtual root hub */
+
+ unsigned int is_suspended;
};
struct urb_priv {
^ permalink raw reply [flat|nested] 2+ messages in thread* Re: [Acpi] [PATCH] USB suspend when no devices attached
2001-03-17 0:21 [PATCH] USB suspend when no devices attached Grover, Andrew
@ 2001-03-17 0:31 ` Johannes Erdfelt
0 siblings, 0 replies; 2+ messages in thread
From: Johannes Erdfelt @ 2001-03-17 0:31 UTC (permalink / raw)
To: Grover, Andrew
Cc: 'linux-usb-devel@lists.sourceforge.net',
'linux-kernel@vger.kernel.org', Acpi-linux (E-mail)
On Fri, Mar 16, 2001, Grover, Andrew <andrew.grover@intel.com> wrote:
> This is a preliminary patch against 2.4.2 to uhci.c that puts the host
> controller into global suspend when there are no devices attached. This
> conserves power on mobile systems, and because suspending the host
> controller ceases UHCI's incessant busmastering activity, it allows the CPU
> to enter a deeper idle state.
>
> The main problem with this implementation is that it just looks at the 2
> root hub ports and suspends if nothing is connected. Ideally, it would be
> smart enough to realize it can also suspend when only hubs are present, or
> when all devices on the USB are also suspended. I hope a USB expert can add
> these enhancements, as it's beyond me.
If you want it to be seamless, you really can't do that. USB is a polled
bus, so the HC needs to send something to the device so it tells us that
something has changed, like a device being plugged into a hub (not the root
hub).
> You should be able to verify this patch is working in one of two ways:
> 1) Turn on USB debug messages, and look for suspend_hc and wakeup_hc
> messages
> 2) Download the latest ACPI patch from
> http://developer.intel.com/technology/iapc/acpi/downloads.htm and verify
> that /proc/acpi/processor/0/status shows mostly 0's for busmastering
> activity (as opposed to mostly F's) when no USB devices are connected.
Thanks for the patch. I'll integrate into my patch and send it off to Linus
as well after I run it through it's paces.
It looks good on visual inspection atleast.
JE
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2001-03-17 0:32 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2001-03-17 0:21 [PATCH] USB suspend when no devices attached Grover, Andrew
2001-03-17 0:31 ` [Acpi] " Johannes Erdfelt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox