USB: EHCI: use hrtimer for async schedule

This patch (as1576) adds hrtimer support for managing ehci-hcd's
async schedule.  Just as with the earlier change to the periodic
schedule management, two new hrtimer events take care of everything.

One event polls at 1-ms intervals to see when the Asynchronous
Schedule Status (ASS) flag matches the Asynchronous Schedule Enable
(ASE) value; the schedule's state must not be changed until it does.
The other event delays for 15 ms after the async schedule becomes
empty before turning it off.

The new events replace a busy-wait poll and a kernel timer usage.
They also replace the rather illogical method currently used for
indicating the async schedule should be turned off: attempting to
unlink the dedicated QH at the head of the async list.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index da2e0ab..bf06bbb 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -79,8 +79,10 @@
  * ehci-timer.c) in parallel with this list.
  */
 enum ehci_hrtimer_event {
+	EHCI_HRTIMER_POLL_ASS,		/* Poll for async schedule off */
 	EHCI_HRTIMER_POLL_PSS,		/* Poll for periodic schedule off */
 	EHCI_HRTIMER_DISABLE_PERIODIC,	/* Wait to disable periodic sched */
+	EHCI_HRTIMER_DISABLE_ASYNC,	/* Wait to disable async sched */
 	EHCI_HRTIMER_NUM_EVENTS		/* Must come last */
 };
 #define EHCI_HRTIMER_NO_EVENT	99
@@ -93,6 +95,7 @@
 	struct hrtimer		hrtimer;
 
 	int			PSS_poll_count;
+	int			ASS_poll_count;
 
 	/* glue to PCI and HCD framework */
 	struct ehci_caps __iomem *caps;
@@ -110,6 +113,7 @@
 	struct ehci_qh		*async_unlink_last;
 	struct ehci_qh		*qh_scan_next;
 	unsigned		scanning : 1;
+	unsigned		async_count;	/* async activity count */
 
 	/* periodic schedule support */
 #define	DEFAULT_I_TDPS		1024		/* some HCs can do less */
@@ -229,7 +233,6 @@
 enum ehci_timer_action {
 	TIMER_IO_WATCHDOG,
 	TIMER_ASYNC_SHRINK,
-	TIMER_ASYNC_OFF,
 };
 
 static inline void