aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2013-03-22 13:31:45 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-03-25 16:35:05 -0400
commit6e018751a35f6ef7ad04eb8006b5886b6a7c47f5 (patch)
treee1dde22b7aa1ac3566ebbbd29b78df611e05c572 /drivers
parent7655e3160c78a18c2ecf7bf4dee0bbfe58575c7f (diff)
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/ehci-dbg.c15
-rw-r--r--drivers/usb/host/ehci-hcd.c5
-rw-r--r--drivers/usb/host/ehci-q.c41
-rw-r--r--drivers/usb/host/ehci-sched.c8
-rw-r--r--drivers/usb/host/ehci-timer.c11
-rw-r--r--drivers/usb/host/ehci.h10
6 files changed, 43 insertions, 47 deletions
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 70b496dc18a0..5429d2645bbc 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -510,14 +510,16 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf)
510 spin_lock_irqsave (&ehci->lock, flags); 510 spin_lock_irqsave (&ehci->lock, flags);
511 for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh) 511 for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh)
512 qh_lines (ehci, qh, &next, &size); 512 qh_lines (ehci, qh, &next, &size);
513 if (ehci->async_unlink && size > 0) { 513 if (!list_empty(&ehci->async_unlink) && size > 0) {
514 temp = scnprintf(next, size, "\nunlink =\n"); 514 temp = scnprintf(next, size, "\nunlink =\n");
515 size -= temp; 515 size -= temp;
516 next += temp; 516 next += temp;
517 517
518 for (qh = ehci->async_unlink; size > 0 && qh; 518 list_for_each_entry(qh, &ehci->async_unlink, unlink_node) {
519 qh = qh->unlink_next) 519 if (size <= 0)
520 qh_lines (ehci, qh, &next, &size); 520 break;
521 qh_lines(ehci, qh, &next, &size);
522 }
521 } 523 }
522 spin_unlock_irqrestore (&ehci->lock, flags); 524 spin_unlock_irqrestore (&ehci->lock, flags);
523 525
@@ -814,9 +816,10 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
814 } 816 }
815 } 817 }
816 818
817 if (ehci->async_unlink) { 819 if (!list_empty(&ehci->async_unlink)) {
818 temp = scnprintf(next, size, "async unlink qh %p\n", 820 temp = scnprintf(next, size, "async unlink qh %p\n",
819 ehci->async_unlink); 821 list_first_entry(&ehci->async_unlink,
822 struct ehci_qh, unlink_node));
820 size -= temp; 823 size -= temp;
821 next += temp; 824 next += temp;
822 } 825 }
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 87fe3daaa092..b32323ca07d3 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -482,6 +482,9 @@ static int ehci_init(struct usb_hcd *hcd)
482 * periodic_size can shrink by USBCMD update if hcc_params allows. 482 * periodic_size can shrink by USBCMD update if hcc_params allows.
483 */ 483 */
484 ehci->periodic_size = DEFAULT_I_TDPS; 484 ehci->periodic_size = DEFAULT_I_TDPS;
485 INIT_LIST_HEAD(&ehci->async_unlink);
486 INIT_LIST_HEAD(&ehci->async_iaa);
487 INIT_LIST_HEAD(&ehci->intr_unlink);
485 INIT_LIST_HEAD(&ehci->intr_qh_list); 488 INIT_LIST_HEAD(&ehci->intr_qh_list);
486 INIT_LIST_HEAD(&ehci->cached_itd_list); 489 INIT_LIST_HEAD(&ehci->cached_itd_list);
487 INIT_LIST_HEAD(&ehci->cached_sitd_list); 490 INIT_LIST_HEAD(&ehci->cached_sitd_list);
@@ -749,7 +752,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
749 /* guard against (alleged) silicon errata */ 752 /* guard against (alleged) silicon errata */
750 if (cmd & CMD_IAAD) 753 if (cmd & CMD_IAAD)
751 ehci_dbg(ehci, "IAA with IAAD still set?\n"); 754 ehci_dbg(ehci, "IAA with IAAD still set?\n");
752 if (ehci->async_iaa) 755 if (!list_empty(&ehci->async_iaa))
753 COUNT(ehci->stats.iaa); 756 COUNT(ehci->stats.iaa);
754 end_unlink_async(ehci); 757 end_unlink_async(ehci);
755 } 758 }
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index fca741dbf9df..4a01367bb2a0 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -958,8 +958,9 @@ static void disable_async(struct ehci_hcd *ehci)
958 if (--ehci->async_count) 958 if (--ehci->async_count)
959 return; 959 return;
960 960
961 /* The async schedule and async_unlink list are supposed to be empty */ 961 /* The async schedule and unlink lists are supposed to be empty */
962 WARN_ON(ehci->async->qh_next.qh || ehci->async_unlink); 962 WARN_ON(ehci->async->qh_next.qh || !list_empty(&ehci->async_unlink) ||
963 !list_empty(&ehci->async_iaa));
963 964
964 /* Don't turn off the schedule until ASS is 1 */ 965 /* Don't turn off the schedule until ASS is 1 */
965 ehci_poll_ASS(ehci); 966 ehci_poll_ASS(ehci);
@@ -1150,11 +1151,7 @@ static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
1150 1151
1151 /* Add to the end of the list of QHs waiting for the next IAAD */ 1152 /* Add to the end of the list of QHs waiting for the next IAAD */
1152 qh->qh_state = QH_STATE_UNLINK_WAIT; 1153 qh->qh_state = QH_STATE_UNLINK_WAIT;
1153 if (ehci->async_unlink) 1154 list_add_tail(&qh->unlink_node, &ehci->async_unlink);
1154 ehci->async_unlink_last->unlink_next = qh;
1155 else
1156 ehci->async_unlink = qh;
1157 ehci->async_unlink_last = qh;
1158 1155
1159 /* Unlink it from the schedule */ 1156 /* Unlink it from the schedule */
1160 prev = ehci->async; 1157 prev = ehci->async;
@@ -1173,15 +1170,14 @@ static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested)
1173 * Do nothing if an IAA cycle is already running or 1170 * Do nothing if an IAA cycle is already running or
1174 * if one will be started shortly. 1171 * if one will be started shortly.
1175 */ 1172 */
1176 if (ehci->async_iaa || ehci->async_unlinking) 1173 if (!list_empty(&ehci->async_iaa) || ehci->async_unlinking)
1177 return; 1174 return;
1178 1175
1179 /* If the controller isn't running, we don't have to wait for it */ 1176 /* If the controller isn't running, we don't have to wait for it */
1180 if (unlikely(ehci->rh_state < EHCI_RH_RUNNING)) { 1177 if (unlikely(ehci->rh_state < EHCI_RH_RUNNING)) {
1181 1178
1182 /* Do all the waiting QHs */ 1179 /* Do all the waiting QHs */
1183 ehci->async_iaa = ehci->async_unlink; 1180 list_splice_tail_init(&ehci->async_unlink, &ehci->async_iaa);
1184 ehci->async_unlink = NULL;
1185 1181
1186 if (!nested) /* Avoid recursion */ 1182 if (!nested) /* Avoid recursion */
1187 end_unlink_async(ehci); 1183 end_unlink_async(ehci);
@@ -1191,20 +1187,18 @@ static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested)
1191 struct ehci_qh *qh; 1187 struct ehci_qh *qh;
1192 1188
1193 /* Do only the first waiting QH (nVidia bug?) */ 1189 /* Do only the first waiting QH (nVidia bug?) */
1194 qh = ehci->async_unlink; 1190 qh = list_first_entry(&ehci->async_unlink, struct ehci_qh,
1191 unlink_node);
1195 1192
1196 /* 1193 /*
1197 * Intel (?) bug: The HC can write back the overlay region 1194 * Intel (?) bug: The HC can write back the overlay region
1198 * even after the IAA interrupt occurs. In self-defense, 1195 * even after the IAA interrupt occurs. In self-defense,
1199 * always go through two IAA cycles for each QH. 1196 * always go through two IAA cycles for each QH.
1200 */ 1197 */
1201 if (qh->qh_state == QH_STATE_UNLINK_WAIT) { 1198 if (qh->qh_state == QH_STATE_UNLINK_WAIT)
1202 qh->qh_state = QH_STATE_UNLINK; 1199 qh->qh_state = QH_STATE_UNLINK;
1203 } else { 1200 else
1204 ehci->async_iaa = qh; 1201 list_move_tail(&qh->unlink_node, &ehci->async_iaa);
1205 ehci->async_unlink = qh->unlink_next;
1206 qh->unlink_next = NULL;
1207 }
1208 1202
1209 /* Make sure the unlinks are all visible to the hardware */ 1203 /* Make sure the unlinks are all visible to the hardware */
1210 wmb(); 1204 wmb();
@@ -1229,10 +1223,10 @@ static void end_unlink_async(struct ehci_hcd *ehci)
1229 /* Process the idle QHs */ 1223 /* Process the idle QHs */
1230 restart: 1224 restart:
1231 ehci->async_unlinking = true; 1225 ehci->async_unlinking = true;
1232 while (ehci->async_iaa) { 1226 while (!list_empty(&ehci->async_iaa)) {
1233 qh = ehci->async_iaa; 1227 qh = list_first_entry(&ehci->async_iaa, struct ehci_qh,
1234 ehci->async_iaa = qh->unlink_next; 1228 unlink_node);
1235 qh->unlink_next = NULL; 1229 list_del(&qh->unlink_node);
1236 1230
1237 qh->qh_state = QH_STATE_IDLE; 1231 qh->qh_state = QH_STATE_IDLE;
1238 qh->qh_next.qh = NULL; 1232 qh->qh_next.qh = NULL;
@@ -1247,7 +1241,7 @@ static void end_unlink_async(struct ehci_hcd *ehci)
1247 ehci->async_unlinking = false; 1241 ehci->async_unlinking = false;
1248 1242
1249 /* Start a new IAA cycle if any QHs are waiting for it */ 1243 /* Start a new IAA cycle if any QHs are waiting for it */
1250 if (ehci->async_unlink) { 1244 if (!list_empty(&ehci->async_unlink)) {
1251 start_iaa_cycle(ehci, true); 1245 start_iaa_cycle(ehci, true);
1252 if (unlikely(ehci->rh_state < EHCI_RH_RUNNING)) 1246 if (unlikely(ehci->rh_state < EHCI_RH_RUNNING))
1253 goto restart; 1247 goto restart;
@@ -1276,7 +1270,8 @@ static void unlink_empty_async(struct ehci_hcd *ehci)
1276 } 1270 }
1277 1271
1278 /* If nothing else is being unlinked, unlink the last empty QH */ 1272 /* If nothing else is being unlinked, unlink the last empty QH */
1279 if (!ehci->async_iaa && !ehci->async_unlink && qh_to_unlink) { 1273 if (list_empty(&ehci->async_iaa) && list_empty(&ehci->async_unlink) &&
1274 qh_to_unlink) {
1280 start_unlink_async(ehci, qh_to_unlink); 1275 start_unlink_async(ehci, qh_to_unlink);
1281 --count; 1276 --count;
1282 } 1277 }
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index e7a2dbd27b1e..c833febf8df0 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -620,17 +620,13 @@ static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
620 qh->unlink_cycle = ehci->intr_unlink_cycle; 620 qh->unlink_cycle = ehci->intr_unlink_cycle;
621 621
622 /* New entries go at the end of the intr_unlink list */ 622 /* New entries go at the end of the intr_unlink list */
623 if (ehci->intr_unlink) 623 list_add_tail(&qh->unlink_node, &ehci->intr_unlink);
624 ehci->intr_unlink_last->unlink_next = qh;
625 else
626 ehci->intr_unlink = qh;
627 ehci->intr_unlink_last = qh;
628 624
629 if (ehci->intr_unlinking) 625 if (ehci->intr_unlinking)
630 ; /* Avoid recursive calls */ 626 ; /* Avoid recursive calls */
631 else if (ehci->rh_state < EHCI_RH_RUNNING) 627 else if (ehci->rh_state < EHCI_RH_RUNNING)
632 ehci_handle_intr_unlinks(ehci); 628 ehci_handle_intr_unlinks(ehci);
633 else if (ehci->intr_unlink == qh) { 629 else if (ehci->intr_unlink.next == &qh->unlink_node) {
634 ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true); 630 ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true);
635 ++ehci->intr_unlink_cycle; 631 ++ehci->intr_unlink_cycle;
636 } 632 }
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c
index e7363332887e..f63a98353efd 100644
--- a/drivers/usb/host/ehci-timer.c
+++ b/drivers/usb/host/ehci-timer.c
@@ -229,18 +229,19 @@ static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci)
229 * process all the QHs on the list. 229 * process all the QHs on the list.
230 */ 230 */
231 ehci->intr_unlinking = true; 231 ehci->intr_unlinking = true;
232 while (ehci->intr_unlink) { 232 while (!list_empty(&ehci->intr_unlink)) {
233 struct ehci_qh *qh = ehci->intr_unlink; 233 struct ehci_qh *qh;
234 234
235 qh = list_first_entry(&ehci->intr_unlink, struct ehci_qh,
236 unlink_node);
235 if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle) 237 if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle)
236 break; 238 break;
237 ehci->intr_unlink = qh->unlink_next; 239 list_del(&qh->unlink_node);
238 qh->unlink_next = NULL;
239 end_unlink_intr(ehci, qh); 240 end_unlink_intr(ehci, qh);
240 } 241 }
241 242
242 /* Handle remaining entries later */ 243 /* Handle remaining entries later */
243 if (ehci->intr_unlink) { 244 if (!list_empty(&ehci->intr_unlink)) {
244 ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true); 245 ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true);
245 ++ehci->intr_unlink_cycle; 246 ++ehci->intr_unlink_cycle;
246 } 247 }
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 6815209511aa..13f67041502e 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -128,9 +128,8 @@ struct ehci_hcd { /* one per controller */
128 /* async schedule support */ 128 /* async schedule support */
129 struct ehci_qh *async; 129 struct ehci_qh *async;
130 struct ehci_qh *dummy; /* For AMD quirk use */ 130 struct ehci_qh *dummy; /* For AMD quirk use */
131 struct ehci_qh *async_unlink; 131 struct list_head async_unlink;
132 struct ehci_qh *async_unlink_last; 132 struct list_head async_iaa;
133 struct ehci_qh *async_iaa;
134 unsigned async_unlink_cycle; 133 unsigned async_unlink_cycle;
135 unsigned async_count; /* async activity count */ 134 unsigned async_count; /* async activity count */
136 135
@@ -143,8 +142,7 @@ struct ehci_hcd { /* one per controller */
143 unsigned i_thresh; /* uframes HC might cache */ 142 unsigned i_thresh; /* uframes HC might cache */
144 143
145 union ehci_shadow *pshadow; /* mirror hw periodic table */ 144 union ehci_shadow *pshadow; /* mirror hw periodic table */
146 struct ehci_qh *intr_unlink; 145 struct list_head intr_unlink;
147 struct ehci_qh *intr_unlink_last;
148 unsigned intr_unlink_cycle; 146 unsigned intr_unlink_cycle;
149 unsigned now_frame; /* frame from HC hardware */ 147 unsigned now_frame; /* frame from HC hardware */
150 unsigned last_iso_frame; /* last frame scanned for iso */ 148 unsigned last_iso_frame; /* last frame scanned for iso */
@@ -380,7 +378,7 @@ struct ehci_qh {
380 struct list_head qtd_list; /* sw qtd list */ 378 struct list_head qtd_list; /* sw qtd list */
381 struct list_head intr_node; /* list of intr QHs */ 379 struct list_head intr_node; /* list of intr QHs */
382 struct ehci_qtd *dummy; 380 struct ehci_qtd *dummy;
383 struct ehci_qh *unlink_next; /* next on unlink list */ 381 struct list_head unlink_node;
384 382
385 unsigned unlink_cycle; 383 unsigned unlink_cycle;
386 384