diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2007-02-19 15:52:45 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-02-23 18:03:45 -0500 |
commit | 17230acdc71137622ca7dfd789b3944c75d39404 (patch) | |
tree | 67eb75c5e8d254b2d5490ea9982efe73952f90d5 /drivers/usb/host/uhci-hcd.c | |
parent | 28b9325e6ae45ffb5e99fedcafe00f25fcaacf06 (diff) |
UHCI: Eliminate asynchronous skeleton Queue Headers
This patch (as856) attempts to improve the performance of uhci-hcd by
removing the asynchronous skeleton Queue Headers. They don't contain
any useful information but the controller has to read through them at
least once every millisecond, incurring a non-zero DMA overhead.
Now all the asynchronous queues are combined, along with the period-1
interrupt queue, into a single list with a single skeleton QH. The
start of the low-speed control, full-speed control, and bulk sublists
is determined by linear search. Since there should rarely be more
than a couple of QHs in the list, the searches should incur a much
smaller total load than keeping the skeleton QHs.
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-hcd.c')
-rw-r--r-- | drivers/usb/host/uhci-hcd.c | 52 |
1 files changed, 21 insertions, 31 deletions
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 1f0833ab294a..44da4334f1d6 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c | |||
@@ -13,7 +13,7 @@ | |||
13 | * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface | 13 | * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface |
14 | * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). | 14 | * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). |
15 | * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) | 15 | * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) |
16 | * (C) Copyright 2004-2006 Alan Stern, stern@rowland.harvard.edu | 16 | * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu |
17 | * | 17 | * |
18 | * Intel documents this fairly well, and as far as I know there | 18 | * Intel documents this fairly well, and as far as I know there |
19 | * are no royalties or anything like that, but even so there are | 19 | * are no royalties or anything like that, but even so there are |
@@ -107,10 +107,10 @@ static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame) | |||
107 | * interrupt QHs, which will help spread out bandwidth utilization. | 107 | * interrupt QHs, which will help spread out bandwidth utilization. |
108 | * | 108 | * |
109 | * ffs (Find First bit Set) does exactly what we need: | 109 | * ffs (Find First bit Set) does exactly what we need: |
110 | * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8], | 110 | * 1,3,5,... => ffs = 0 => use period-2 QH = skelqh[8], |
111 | * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc. | 111 | * 2,6,10,... => ffs = 1 => use period-4 QH = skelqh[7], etc. |
112 | * ffs >= 7 => not on any high-period queue, so use | 112 | * ffs >= 7 => not on any high-period queue, so use |
113 | * skel_int1_qh = skelqh[9]. | 113 | * period-1 QH = skelqh[9]. |
114 | * Add in UHCI_NUMFRAMES to insure at least one bit is set. | 114 | * Add in UHCI_NUMFRAMES to insure at least one bit is set. |
115 | */ | 115 | */ |
116 | skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES); | 116 | skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES); |
@@ -540,16 +540,18 @@ static void uhci_shutdown(struct pci_dev *pdev) | |||
540 | * | 540 | * |
541 | * The hardware doesn't really know any difference | 541 | * The hardware doesn't really know any difference |
542 | * in the queues, but the order does matter for the | 542 | * in the queues, but the order does matter for the |
543 | * protocols higher up. The order is: | 543 | * protocols higher up. The order in which the queues |
544 | * are encountered by the hardware is: | ||
544 | * | 545 | * |
545 | * - any isochronous events handled before any | 546 | * - All isochronous events are handled before any |
546 | * of the queues. We don't do that here, because | 547 | * of the queues. We don't do that here, because |
547 | * we'll create the actual TD entries on demand. | 548 | * we'll create the actual TD entries on demand. |
548 | * - The first queue is the interrupt queue. | 549 | * - The first queue is the high-period interrupt queue. |
549 | * - The second queue is the control queue, split into low- and full-speed | 550 | * - The second queue is the period-1 interrupt and async |
550 | * - The third queue is bulk queue. | 551 | * (low-speed control, full-speed control, then bulk) queue. |
551 | * - The fourth queue is the bandwidth reclamation queue, which loops back | 552 | * - The third queue is the terminating bandwidth reclamation queue, |
552 | * to the full-speed control queue. | 553 | * which contains no members, loops back to itself, and is present |
554 | * only when FSBR is on and there are no full-speed control or bulk QHs. | ||
553 | */ | 555 | */ |
554 | static int uhci_start(struct usb_hcd *hcd) | 556 | static int uhci_start(struct usb_hcd *hcd) |
555 | { | 557 | { |
@@ -626,30 +628,18 @@ static int uhci_start(struct usb_hcd *hcd) | |||
626 | } | 628 | } |
627 | 629 | ||
628 | /* | 630 | /* |
629 | * 8 Interrupt queues; link all higher int queues to int1, | 631 | * 8 Interrupt queues; link all higher int queues to int1 = async |
630 | * then link int1 to control and control to bulk | ||
631 | */ | 632 | */ |
632 | uhci->skel_int128_qh->link = | 633 | for (i = SKEL_ISO + 1; i < SKEL_ASYNC; ++i) |
633 | uhci->skel_int64_qh->link = | 634 | uhci->skelqh[i]->link = LINK_TO_QH(uhci->skel_async_qh); |
634 | uhci->skel_int32_qh->link = | 635 | uhci->skel_async_qh->link = uhci->skel_term_qh->link = UHCI_PTR_TERM; |
635 | uhci->skel_int16_qh->link = | ||
636 | uhci->skel_int8_qh->link = | ||
637 | uhci->skel_int4_qh->link = | ||
638 | uhci->skel_int2_qh->link = LINK_TO_QH( | ||
639 | uhci->skel_int1_qh); | ||
640 | |||
641 | uhci->skel_int1_qh->link = LINK_TO_QH(uhci->skel_ls_control_qh); | ||
642 | uhci->skel_ls_control_qh->link = LINK_TO_QH(uhci->skel_fs_control_qh); | ||
643 | uhci->skel_fs_control_qh->link = LINK_TO_QH(uhci->skel_bulk_qh); | ||
644 | uhci->skel_bulk_qh->link = LINK_TO_QH(uhci->skel_term_qh); | ||
645 | 636 | ||
646 | /* This dummy TD is to work around a bug in Intel PIIX controllers */ | 637 | /* This dummy TD is to work around a bug in Intel PIIX controllers */ |
647 | uhci_fill_td(uhci->term_td, 0, uhci_explen(0) | | 638 | uhci_fill_td(uhci->term_td, 0, uhci_explen(0) | |
648 | (0x7f << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_IN, 0); | 639 | (0x7f << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_IN, 0); |
649 | uhci->term_td->link = LINK_TO_TD(uhci->term_td); | 640 | uhci->term_td->link = UHCI_PTR_TERM; |
650 | 641 | uhci->skel_async_qh->element = uhci->skel_term_qh->element = | |
651 | uhci->skel_term_qh->link = UHCI_PTR_TERM; | 642 | LINK_TO_TD(uhci->term_td); |
652 | uhci->skel_term_qh->element = LINK_TO_TD(uhci->term_td); | ||
653 | 643 | ||
654 | /* | 644 | /* |
655 | * Fill the frame list: make all entries point to the proper | 645 | * Fill the frame list: make all entries point to the proper |