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 /drivers/usb | |
| 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>
Diffstat (limited to 'drivers/usb')
| -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); |
