USB: EHCI: convert singly-linked lists to list_heads

This patch (as1664) converts ehci-hcd's async_unlink, async_iaa, and
intr_unlink from singly-linked lists to standard doubly-linked
list_heads.  Originally it didn't seem necessary to use list_heads,
because items are always added to and removed from these lists in FIFO
order.  But now with more list processing going on, it's easier to use
the standard routines than continue with a roll-your-own approach.

I don't know if the code ends up being notably shorter, but the
patterns will be more familiar to any kernel hacker.

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-q.c b/drivers/usb/host/ehci-q.c
index fca741d..4a01367 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -958,8 +958,9 @@
 	if (--ehci->async_count)
 		return;
 
-	/* The async schedule and async_unlink list are supposed to be empty */
-	WARN_ON(ehci->async->qh_next.qh || ehci->async_unlink);
+	/* The async schedule and unlink lists are supposed to be empty */
+	WARN_ON(ehci->async->qh_next.qh || !list_empty(&ehci->async_unlink) ||
+			!list_empty(&ehci->async_iaa));
 
 	/* Don't turn off the schedule until ASS is 1 */
 	ehci_poll_ASS(ehci);
@@ -1150,11 +1151,7 @@
 
 	/* Add to the end of the list of QHs waiting for the next IAAD */
 	qh->qh_state = QH_STATE_UNLINK_WAIT;
-	if (ehci->async_unlink)
-		ehci->async_unlink_last->unlink_next = qh;
-	else
-		ehci->async_unlink = qh;
-	ehci->async_unlink_last = qh;
+	list_add_tail(&qh->unlink_node, &ehci->async_unlink);
 
 	/* Unlink it from the schedule */
 	prev = ehci->async;
@@ -1173,15 +1170,14 @@
 	 * Do nothing if an IAA cycle is already running or
 	 * if one will be started shortly.
 	 */
-	if (ehci->async_iaa || ehci->async_unlinking)
+	if (!list_empty(&ehci->async_iaa) || ehci->async_unlinking)
 		return;
 
 	/* If the controller isn't running, we don't have to wait for it */
 	if (unlikely(ehci->rh_state < EHCI_RH_RUNNING)) {
 
 		/* Do all the waiting QHs */
-		ehci->async_iaa = ehci->async_unlink;
-		ehci->async_unlink = NULL;
+		list_splice_tail_init(&ehci->async_unlink, &ehci->async_iaa);
 
 		if (!nested)		/* Avoid recursion */
 			end_unlink_async(ehci);
@@ -1191,20 +1187,18 @@
 		struct ehci_qh		*qh;
 
 		/* Do only the first waiting QH (nVidia bug?) */
-		qh = ehci->async_unlink;
+		qh = list_first_entry(&ehci->async_unlink, struct ehci_qh,
+				unlink_node);
 
 		/*
 		 * Intel (?) bug: The HC can write back the overlay region
 		 * even after the IAA interrupt occurs.  In self-defense,
 		 * always go through two IAA cycles for each QH.
 		 */
-		if (qh->qh_state == QH_STATE_UNLINK_WAIT) {
+		if (qh->qh_state == QH_STATE_UNLINK_WAIT)
 			qh->qh_state = QH_STATE_UNLINK;
-		} else {
-			ehci->async_iaa = qh;
-			ehci->async_unlink = qh->unlink_next;
-			qh->unlink_next = NULL;
-		}
+		else
+			list_move_tail(&qh->unlink_node, &ehci->async_iaa);
 
 		/* Make sure the unlinks are all visible to the hardware */
 		wmb();
@@ -1229,10 +1223,10 @@
 	/* Process the idle QHs */
  restart:
 	ehci->async_unlinking = true;
-	while (ehci->async_iaa) {
-		qh = ehci->async_iaa;
-		ehci->async_iaa = qh->unlink_next;
-		qh->unlink_next = NULL;
+	while (!list_empty(&ehci->async_iaa)) {
+		qh = list_first_entry(&ehci->async_iaa, struct ehci_qh,
+				unlink_node);
+		list_del(&qh->unlink_node);
 
 		qh->qh_state = QH_STATE_IDLE;
 		qh->qh_next.qh = NULL;
@@ -1247,7 +1241,7 @@
 	ehci->async_unlinking = false;
 
 	/* Start a new IAA cycle if any QHs are waiting for it */
-	if (ehci->async_unlink) {
+	if (!list_empty(&ehci->async_unlink)) {
 		start_iaa_cycle(ehci, true);
 		if (unlikely(ehci->rh_state < EHCI_RH_RUNNING))
 			goto restart;
@@ -1276,7 +1270,8 @@
 	}
 
 	/* If nothing else is being unlinked, unlink the last empty QH */
-	if (!ehci->async_iaa && !ehci->async_unlink && qh_to_unlink) {
+	if (list_empty(&ehci->async_iaa) && list_empty(&ehci->async_unlink) &&
+			qh_to_unlink) {
 		start_unlink_async(ehci, qh_to_unlink);
 		--count;
 	}