aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/uhci-q.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2006-05-12 11:29:04 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-06-21 18:04:11 -0400
commit04538a255ac8b404c20cbf15867c9829254c470f (patch)
tree8b8a9bf63e9b1b804e2bf732e32db2827f422867 /drivers/usb/host/uhci-q.c
parenta0b458b64b2a3a4cb806dd5cd889bbf6c7e9d686 (diff)
[PATCH] UHCI: Eliminate the TD-removal list
This patch (as682) gets rid of the TD-removal list in uhci-hcd. It is no longer needed because now TDs are not freed until we know the hardware isn't using them. It also simplifies the code for adding and removing TDs to/from URBs. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/uhci-q.c')
-rw-r--r--drivers/usb/host/uhci-q.c92
1 files changed, 27 insertions, 65 deletions
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 64b6c74789fd..12af6fb05a30 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -16,7 +16,6 @@
16 * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu 16 * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu
17 */ 17 */
18 18
19static void uhci_free_pending_tds(struct uhci_hcd *uhci);
20 19
21/* 20/*
22 * Technically, updating td->status here is a race, but it's not really a 21 * Technically, updating td->status here is a race, but it's not really a
@@ -51,7 +50,6 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci)
51 td->frame = -1; 50 td->frame = -1;
52 51
53 INIT_LIST_HEAD(&td->list); 52 INIT_LIST_HEAD(&td->list);
54 INIT_LIST_HEAD(&td->remove_list);
55 INIT_LIST_HEAD(&td->fl_list); 53 INIT_LIST_HEAD(&td->fl_list);
56 54
57 return td; 55 return td;
@@ -61,8 +59,6 @@ static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
61{ 59{
62 if (!list_empty(&td->list)) 60 if (!list_empty(&td->list))
63 dev_warn(uhci_dev(uhci), "td %p still in list!\n", td); 61 dev_warn(uhci_dev(uhci), "td %p still in list!\n", td);
64 if (!list_empty(&td->remove_list))
65 dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td);
66 if (!list_empty(&td->fl_list)) 62 if (!list_empty(&td->fl_list))
67 dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td); 63 dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
68 64
@@ -77,6 +73,16 @@ static inline void uhci_fill_td(struct uhci_td *td, u32 status,
77 td->buffer = cpu_to_le32(buffer); 73 td->buffer = cpu_to_le32(buffer);
78} 74}
79 75
76static void uhci_add_td_to_urbp(struct uhci_td *td, struct urb_priv *urbp)
77{
78 list_add_tail(&td->list, &urbp->td_list);
79}
80
81static void uhci_remove_td_from_urbp(struct uhci_td *td)
82{
83 list_del_init(&td->list);
84}
85
80/* 86/*
81 * We insert Isochronous URBs directly into the frame list at the beginning 87 * We insert Isochronous URBs directly into the frame list at the beginning
82 */ 88 */
@@ -421,21 +427,6 @@ static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci,
421 return urbp; 427 return urbp;
422} 428}
423 429
424static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td)
425{
426 struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
427
428 list_add_tail(&td->list, &urbp->td_list);
429}
430
431static void uhci_remove_td_from_urb(struct uhci_td *td)
432{
433 if (list_empty(&td->list))
434 return;
435
436 list_del_init(&td->list);
437}
438
439static void uhci_free_urb_priv(struct uhci_hcd *uhci, 430static void uhci_free_urb_priv(struct uhci_hcd *uhci,
440 struct urb_priv *urbp) 431 struct urb_priv *urbp)
441{ 432{
@@ -445,20 +436,9 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci,
445 dev_warn(uhci_dev(uhci), "urb %p still on QH's list!\n", 436 dev_warn(uhci_dev(uhci), "urb %p still on QH's list!\n",
446 urbp->urb); 437 urbp->urb);
447 438
448 uhci_get_current_frame_number(uhci);
449 if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age) {
450 uhci_free_pending_tds(uhci);
451 uhci->td_remove_age = uhci->frame_number;
452 }
453
454 /* Check to see if the remove list is empty. Set the IOC bit */
455 /* to force an interrupt so we can remove the TDs. */
456 if (list_empty(&uhci->td_remove_list))
457 uhci_set_next_interrupt(uhci);
458
459 list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { 439 list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
460 uhci_remove_td_from_urb(td); 440 uhci_remove_td_from_urbp(td);
461 list_add(&td->remove_list, &uhci->td_remove_list); 441 uhci_free_td(uhci, td);
462 } 442 }
463 443
464 urbp->urb->hcpriv = NULL; 444 urbp->urb->hcpriv = NULL;
@@ -529,6 +509,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
529 int len = urb->transfer_buffer_length; 509 int len = urb->transfer_buffer_length;
530 dma_addr_t data = urb->transfer_dma; 510 dma_addr_t data = urb->transfer_dma;
531 __le32 *plink; 511 __le32 *plink;
512 struct urb_priv *urbp = urb->hcpriv;
532 513
533 /* The "pipe" thing contains the destination in bits 8--18 */ 514 /* The "pipe" thing contains the destination in bits 8--18 */
534 destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; 515 destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
@@ -542,7 +523,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
542 * Build the TD for the control request setup packet 523 * Build the TD for the control request setup packet
543 */ 524 */
544 td = qh->dummy_td; 525 td = qh->dummy_td;
545 uhci_add_td_to_urb(urb, td); 526 uhci_add_td_to_urbp(td, urbp);
546 uhci_fill_td(td, status, destination | uhci_explen(8), 527 uhci_fill_td(td, status, destination | uhci_explen(8),
547 urb->setup_dma); 528 urb->setup_dma);
548 plink = &td->link; 529 plink = &td->link;
@@ -574,7 +555,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
574 /* Alternate Data0/1 (start with Data1) */ 555 /* Alternate Data0/1 (start with Data1) */
575 destination ^= TD_TOKEN_TOGGLE; 556 destination ^= TD_TOKEN_TOGGLE;
576 557
577 uhci_add_td_to_urb(urb, td); 558 uhci_add_td_to_urbp(td, urbp);
578 uhci_fill_td(td, status, destination | uhci_explen(pktsze), 559 uhci_fill_td(td, status, destination | uhci_explen(pktsze),
579 data); 560 data);
580 plink = &td->link; 561 plink = &td->link;
@@ -605,7 +586,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
605 586
606 status &= ~TD_CTRL_SPD; 587 status &= ~TD_CTRL_SPD;
607 588
608 uhci_add_td_to_urb(urb, td); 589 uhci_add_td_to_urbp(td, urbp);
609 uhci_fill_td(td, status | TD_CTRL_IOC, 590 uhci_fill_td(td, status | TD_CTRL_IOC,
610 destination | uhci_explen(0), 0); 591 destination | uhci_explen(0), 0);
611 plink = &td->link; 592 plink = &td->link;
@@ -640,7 +621,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
640 621
641nomem: 622nomem:
642 /* Remove the dummy TD from the td_list so it doesn't get freed */ 623 /* Remove the dummy TD from the td_list so it doesn't get freed */
643 uhci_remove_td_from_urb(qh->dummy_td); 624 uhci_remove_td_from_urbp(qh->dummy_td);
644 return -ENOMEM; 625 return -ENOMEM;
645} 626}
646 627
@@ -656,6 +637,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
656 int len = urb->transfer_buffer_length; 637 int len = urb->transfer_buffer_length;
657 dma_addr_t data = urb->transfer_dma; 638 dma_addr_t data = urb->transfer_dma;
658 __le32 *plink; 639 __le32 *plink;
640 struct urb_priv *urbp = urb->hcpriv;
659 unsigned int toggle; 641 unsigned int toggle;
660 642
661 if (len < 0) 643 if (len < 0)
@@ -693,7 +675,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
693 goto nomem; 675 goto nomem;
694 *plink = cpu_to_le32(td->dma_handle); 676 *plink = cpu_to_le32(td->dma_handle);
695 } 677 }
696 uhci_add_td_to_urb(urb, td); 678 uhci_add_td_to_urbp(td, urbp);
697 uhci_fill_td(td, status, 679 uhci_fill_td(td, status,
698 destination | uhci_explen(pktsze) | 680 destination | uhci_explen(pktsze) |
699 (toggle << TD_TOKEN_TOGGLE_SHIFT), 681 (toggle << TD_TOKEN_TOGGLE_SHIFT),
@@ -721,7 +703,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
721 goto nomem; 703 goto nomem;
722 *plink = cpu_to_le32(td->dma_handle); 704 *plink = cpu_to_le32(td->dma_handle);
723 705
724 uhci_add_td_to_urb(urb, td); 706 uhci_add_td_to_urbp(td, urbp);
725 uhci_fill_td(td, status, 707 uhci_fill_td(td, status,
726 destination | uhci_explen(0) | 708 destination | uhci_explen(0) |
727 (toggle << TD_TOKEN_TOGGLE_SHIFT), 709 (toggle << TD_TOKEN_TOGGLE_SHIFT),
@@ -758,7 +740,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
758 740
759nomem: 741nomem:
760 /* Remove the dummy TD from the td_list so it doesn't get freed */ 742 /* Remove the dummy TD from the td_list so it doesn't get freed */
761 uhci_remove_td_from_urb(qh->dummy_td); 743 uhci_remove_td_from_urbp(qh->dummy_td);
762 return -ENOMEM; 744 return -ENOMEM;
763} 745}
764 746
@@ -830,8 +812,8 @@ static int uhci_fixup_short_transfer(struct uhci_hcd *uhci,
830 td = list_entry(tmp, struct uhci_td, list); 812 td = list_entry(tmp, struct uhci_td, list);
831 tmp = tmp->prev; 813 tmp = tmp->prev;
832 814
833 uhci_remove_td_from_urb(td); 815 uhci_remove_td_from_urbp(td);
834 list_add(&td->remove_list, &uhci->td_remove_list); 816 uhci_free_td(uhci, td);
835 } 817 }
836 return ret; 818 return ret;
837} 819}
@@ -885,10 +867,9 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
885 ret = 1; 867 ret = 1;
886 } 868 }
887 869
888 uhci_remove_td_from_urb(td); 870 uhci_remove_td_from_urbp(td);
889 if (qh->post_td) 871 if (qh->post_td)
890 list_add(&qh->post_td->remove_list, 872 uhci_free_td(uhci, qh->post_td);
891 &uhci->td_remove_list);
892 qh->post_td = td; 873 qh->post_td = td;
893 874
894 if (ret != 0) 875 if (ret != 0)
@@ -957,7 +938,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
957 if (!td) 938 if (!td)
958 return -ENOMEM; 939 return -ENOMEM;
959 940
960 uhci_add_td_to_urb(urb, td); 941 uhci_add_td_to_urbp(td, urbp);
961 uhci_fill_td(td, status, destination | 942 uhci_fill_td(td, status, destination |
962 uhci_explen(urb->iso_frame_desc[i].length), 943 uhci_explen(urb->iso_frame_desc[i].length),
963 urb->transfer_dma + 944 urb->transfer_dma +
@@ -1267,17 +1248,6 @@ restart:
1267 uhci_make_qh_idle(uhci, qh); 1248 uhci_make_qh_idle(uhci, qh);
1268} 1249}
1269 1250
1270static void uhci_free_pending_tds(struct uhci_hcd *uhci)
1271{
1272 struct uhci_td *td, *tmp;
1273
1274 list_for_each_entry_safe(td, tmp, &uhci->td_remove_list, remove_list) {
1275 list_del_init(&td->remove_list);
1276
1277 uhci_free_td(uhci, td);
1278 }
1279}
1280
1281/* 1251/*
1282 * Process events in the schedule, but only in one thread at a time 1252 * Process events in the schedule, but only in one thread at a time
1283 */ 1253 */
@@ -1298,9 +1268,6 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
1298 uhci_clear_next_interrupt(uhci); 1268 uhci_clear_next_interrupt(uhci);
1299 uhci_get_current_frame_number(uhci); 1269 uhci_get_current_frame_number(uhci);
1300 1270
1301 if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age)
1302 uhci_free_pending_tds(uhci);
1303
1304 /* Go through all the QH queues and process the URBs in each one */ 1271 /* Go through all the QH queues and process the URBs in each one */
1305 for (i = 0; i < UHCI_NUM_SKELQH - 1; ++i) { 1272 for (i = 0; i < UHCI_NUM_SKELQH - 1; ++i) {
1306 uhci->next_qh = list_entry(uhci->skelqh[i]->node.next, 1273 uhci->next_qh = list_entry(uhci->skelqh[i]->node.next,
@@ -1316,12 +1283,7 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
1316 goto rescan; 1283 goto rescan;
1317 uhci->scan_in_progress = 0; 1284 uhci->scan_in_progress = 0;
1318 1285
1319 /* If the controller is stopped, we can finish these off right now */ 1286 if (list_empty(&uhci->skel_unlink_qh->node))
1320 if (uhci->is_stopped)
1321 uhci_free_pending_tds(uhci);
1322
1323 if (list_empty(&uhci->td_remove_list) &&
1324 list_empty(&uhci->skel_unlink_qh->node))
1325 uhci_clear_next_interrupt(uhci); 1287 uhci_clear_next_interrupt(uhci);
1326 else 1288 else
1327 uhci_set_next_interrupt(uhci); 1289 uhci_set_next_interrupt(uhci);