diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2006-05-12 11:29:04 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-06-21 18:04:11 -0400 |
commit | 04538a255ac8b404c20cbf15867c9829254c470f (patch) | |
tree | 8b8a9bf63e9b1b804e2bf732e32db2827f422867 | |
parent | a0b458b64b2a3a4cb806dd5cd889bbf6c7e9d686 (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>
-rw-r--r-- | drivers/usb/host/uhci-hcd.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hcd.h | 5 | ||||
-rw-r--r-- | drivers/usb/host/uhci-q.c | 92 |
3 files changed, 27 insertions, 71 deletions
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index d225e11f4055..fb4c1a8cadf4 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c | |||
@@ -492,7 +492,6 @@ static int uhci_start(struct usb_hcd *hcd) | |||
492 | 492 | ||
493 | spin_lock_init(&uhci->lock); | 493 | spin_lock_init(&uhci->lock); |
494 | 494 | ||
495 | INIT_LIST_HEAD(&uhci->td_remove_list); | ||
496 | INIT_LIST_HEAD(&uhci->idle_qh_list); | 495 | INIT_LIST_HEAD(&uhci->idle_qh_list); |
497 | 496 | ||
498 | init_waitqueue_head(&uhci->waitqh); | 497 | init_waitqueue_head(&uhci->waitqh); |
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 3093ca250942..90ef7fbbf2fb 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h | |||
@@ -228,7 +228,6 @@ struct uhci_td { | |||
228 | dma_addr_t dma_handle; | 228 | dma_addr_t dma_handle; |
229 | 229 | ||
230 | struct list_head list; | 230 | struct list_head list; |
231 | struct list_head remove_list; | ||
232 | 231 | ||
233 | int frame; /* for iso: what frame? */ | 232 | int frame; /* for iso: what frame? */ |
234 | struct list_head fl_list; | 233 | struct list_head fl_list; |
@@ -420,10 +419,6 @@ struct uhci_hcd { | |||
420 | unsigned long resuming_ports; | 419 | unsigned long resuming_ports; |
421 | unsigned long ports_timeout; /* Time to stop signalling */ | 420 | unsigned long ports_timeout; /* Time to stop signalling */ |
422 | 421 | ||
423 | /* List of TDs that are done, but waiting to be freed (race) */ | ||
424 | struct list_head td_remove_list; | ||
425 | unsigned int td_remove_age; /* Age in frames */ | ||
426 | |||
427 | struct list_head idle_qh_list; /* Where the idle QHs live */ | 422 | struct list_head idle_qh_list; /* Where the idle QHs live */ |
428 | 423 | ||
429 | int rh_numports; /* Number of root-hub ports */ | 424 | int rh_numports; /* Number of root-hub ports */ |
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 | ||
19 | static 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 | ||
76 | static 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 | |||
81 | static 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 | ||
424 | static 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 | |||
431 | static 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 | |||
439 | static void uhci_free_urb_priv(struct uhci_hcd *uhci, | 430 | static 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 | ||
641 | nomem: | 622 | nomem: |
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 | ||
759 | nomem: | 741 | nomem: |
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 | ||
1270 | static 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); |