aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2005-12-17 18:00:12 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-03-20 17:49:57 -0500
commitaf0bb5998abe8ed28ee354dd4c71689cacdc91e9 (patch)
tree20172dd9551d0e2497ef4b6dff1a84f010f981ab /drivers/usb
parentdccf4a48d47120a42382ba526f1a0848c13ba2a4 (diff)
[PATCH] UHCI: use dummy TDs
This patch (as624) fixes a hardware race in uhci-hcd by adding a dummy TD to the end of each endpoint's queue. Without the dummy the host controller will effectively turn off the queue when it reaches the end, which happens asynchronously. This leads to a potential problem when new transfer descriptors are added to the end of the queue; they may never get used. With a dummy TD present the controller never turns off the queue; instead it just stops at the dummy and leaves the queue on but inactive. When new TDs are added to the end of the queue, the first new one gets written over the dummy. Thus there's never any question about whether the queue is running or needs to be restarted. 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-debug.c5
-rw-r--r--drivers/usb/host/uhci-hcd.h1
-rw-r--r--drivers/usb/host/uhci-q.c138
3 files changed, 83 insertions, 61 deletions
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 3faccbd68547..6814783adf91 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -189,6 +189,11 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
189 space, "", nurbs); 189 space, "", nurbs);
190 } 190 }
191 191
192 if (qh->udev) {
193 out += sprintf(out, "%*s Dummy TD\n", space, "");
194 out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0);
195 }
196
192 return out - buf; 197 return out - buf;
193} 198}
194 199
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 7a9481c09a05..c057956667b5 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -128,6 +128,7 @@ struct uhci_qh {
128 struct usb_device *udev; 128 struct usb_device *udev;
129 struct list_head queue; /* Queue of urbps for this QH */ 129 struct list_head queue; /* Queue of urbps for this QH */
130 struct uhci_qh *skel; /* Skeleton for this QH */ 130 struct uhci_qh *skel; /* Skeleton for this QH */
131 struct uhci_td *dummy_td; /* Dummy TD to end the queue */
131 132
132 unsigned int unlink_frame; /* When the QH was unlinked */ 133 unsigned int unlink_frame; /* When the QH was unlinked */
133 int state; /* QH_STATE_xxx; see above */ 134 int state; /* QH_STATE_xxx; see above */
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index b1b551a3d14e..c4194182dcc4 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -48,10 +48,6 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci)
48 return NULL; 48 return NULL;
49 49
50 td->dma_handle = dma_handle; 50 td->dma_handle = dma_handle;
51
52 td->link = UHCI_PTR_TERM;
53 td->buffer = 0;
54
55 td->frame = -1; 51 td->frame = -1;
56 52
57 INIT_LIST_HEAD(&td->list); 53 INIT_LIST_HEAD(&td->list);
@@ -221,6 +217,11 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
221 INIT_LIST_HEAD(&qh->node); 217 INIT_LIST_HEAD(&qh->node);
222 218
223 if (udev) { /* Normal QH */ 219 if (udev) { /* Normal QH */
220 qh->dummy_td = uhci_alloc_td(uhci);
221 if (!qh->dummy_td) {
222 dma_pool_free(uhci->qh_pool, qh, dma_handle);
223 return NULL;
224 }
224 qh->state = QH_STATE_IDLE; 225 qh->state = QH_STATE_IDLE;
225 qh->hep = hep; 226 qh->hep = hep;
226 qh->udev = udev; 227 qh->udev = udev;
@@ -244,6 +245,7 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
244 if (qh->udev) { 245 if (qh->udev) {
245 qh->hep->hcpriv = NULL; 246 qh->hep->hcpriv = NULL;
246 usb_put_dev(qh->udev); 247 usb_put_dev(qh->udev);
248 uhci_free_td(uhci, qh->dummy_td);
247 } 249 }
248 dma_pool_free(uhci->qh_pool, qh, qh->dma_handle); 250 dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
249} 251}
@@ -531,22 +533,20 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
531 /* The "pipe" thing contains the destination in bits 8--18 */ 533 /* The "pipe" thing contains the destination in bits 8--18 */
532 destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; 534 destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
533 535
534 /* 3 errors */ 536 /* 3 errors, dummy TD remains inactive */
535 status = TD_CTRL_ACTIVE | uhci_maxerr(3); 537 status = uhci_maxerr(3);
536 if (urb->dev->speed == USB_SPEED_LOW) 538 if (urb->dev->speed == USB_SPEED_LOW)
537 status |= TD_CTRL_LS; 539 status |= TD_CTRL_LS;
538 540
539 /* 541 /*
540 * Build the TD for the control request setup packet 542 * Build the TD for the control request setup packet
541 */ 543 */
542 td = uhci_alloc_td(uhci); 544 td = qh->dummy_td;
543 if (!td)
544 return -ENOMEM;
545
546 uhci_add_td_to_urb(urb, td); 545 uhci_add_td_to_urb(urb, td);
547 uhci_fill_td(td, status, destination | uhci_explen(8), 546 uhci_fill_td(td, status, destination | uhci_explen(8),
548 urb->setup_dma); 547 urb->setup_dma);
549 plink = &td->link; 548 plink = &td->link;
549 status |= TD_CTRL_ACTIVE;
550 550
551 /* 551 /*
552 * If direction is "send", change the packet ID from SETUP (0x2D) 552 * If direction is "send", change the packet ID from SETUP (0x2D)
@@ -568,7 +568,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
568 568
569 td = uhci_alloc_td(uhci); 569 td = uhci_alloc_td(uhci);
570 if (!td) 570 if (!td)
571 return -ENOMEM; 571 goto nomem;
572 *plink = cpu_to_le32(td->dma_handle); 572 *plink = cpu_to_le32(td->dma_handle);
573 573
574 /* Alternate Data0/1 (start with Data1) */ 574 /* Alternate Data0/1 (start with Data1) */
@@ -588,7 +588,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
588 */ 588 */
589 td = uhci_alloc_td(uhci); 589 td = uhci_alloc_td(uhci);
590 if (!td) 590 if (!td)
591 return -ENOMEM; 591 goto nomem;
592 *plink = cpu_to_le32(td->dma_handle); 592 *plink = cpu_to_le32(td->dma_handle);
593 593
594 /* 594 /*
@@ -608,6 +608,20 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
608 uhci_add_td_to_urb(urb, td); 608 uhci_add_td_to_urb(urb, td);
609 uhci_fill_td(td, status | TD_CTRL_IOC, 609 uhci_fill_td(td, status | TD_CTRL_IOC,
610 destination | uhci_explen(0), 0); 610 destination | uhci_explen(0), 0);
611 plink = &td->link;
612
613 /*
614 * Build the new dummy TD and activate the old one
615 */
616 td = uhci_alloc_td(uhci);
617 if (!td)
618 goto nomem;
619 *plink = cpu_to_le32(td->dma_handle);
620
621 uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
622 wmb();
623 qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
624 qh->dummy_td = td;
611 625
612 /* Low-speed transfers get a different queue, and won't hog the bus. 626 /* Low-speed transfers get a different queue, and won't hog the bus.
613 * Also, some devices enumerate better without FSBR; the easiest way 627 * Also, some devices enumerate better without FSBR; the easiest way
@@ -620,8 +634,12 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
620 qh->skel = uhci->skel_fs_control_qh; 634 qh->skel = uhci->skel_fs_control_qh;
621 uhci_inc_fsbr(uhci, urb); 635 uhci_inc_fsbr(uhci, urb);
622 } 636 }
623
624 return 0; 637 return 0;
638
639nomem:
640 /* Remove the dummy TD from the td_list so it doesn't get freed */
641 uhci_remove_td_from_urb(qh->dummy_td);
642 return -ENOMEM;
625} 643}
626 644
627/* 645/*
@@ -761,16 +779,19 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
761 int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize); 779 int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
762 int len = urb->transfer_buffer_length; 780 int len = urb->transfer_buffer_length;
763 dma_addr_t data = urb->transfer_dma; 781 dma_addr_t data = urb->transfer_dma;
764 __le32 *plink, fake_link; 782 __le32 *plink;
783 unsigned int toggle;
765 784
766 if (len < 0) 785 if (len < 0)
767 return -EINVAL; 786 return -EINVAL;
768 787
769 /* The "pipe" thing contains the destination in bits 8--18 */ 788 /* The "pipe" thing contains the destination in bits 8--18 */
770 destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); 789 destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
790 toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
791 usb_pipeout(urb->pipe));
771 792
772 /* 3 errors */ 793 /* 3 errors, dummy TD remains inactive */
773 status = TD_CTRL_ACTIVE | uhci_maxerr(3); 794 status = uhci_maxerr(3);
774 if (urb->dev->speed == USB_SPEED_LOW) 795 if (urb->dev->speed == USB_SPEED_LOW)
775 status |= TD_CTRL_LS; 796 status |= TD_CTRL_LS;
776 if (usb_pipein(urb->pipe)) 797 if (usb_pipein(urb->pipe))
@@ -779,7 +800,8 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
779 /* 800 /*
780 * Build the DATA TDs 801 * Build the DATA TDs
781 */ 802 */
782 plink = &fake_link; 803 plink = NULL;
804 td = qh->dummy_td;
783 do { /* Allow zero length packets */ 805 do { /* Allow zero length packets */
784 int pktsze = maxsze; 806 int pktsze = maxsze;
785 807
@@ -789,24 +811,23 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
789 status &= ~TD_CTRL_SPD; 811 status &= ~TD_CTRL_SPD;
790 } 812 }
791 813
792 td = uhci_alloc_td(uhci); 814 if (plink) {
793 if (!td) 815 td = uhci_alloc_td(uhci);
794 return -ENOMEM; 816 if (!td)
795 *plink = cpu_to_le32(td->dma_handle); 817 goto nomem;
796 818 *plink = cpu_to_le32(td->dma_handle);
819 }
797 uhci_add_td_to_urb(urb, td); 820 uhci_add_td_to_urb(urb, td);
798 uhci_fill_td(td, status, 821 uhci_fill_td(td, status,
799 destination | uhci_explen(pktsze) | 822 destination | uhci_explen(pktsze) |
800 (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), 823 (toggle << TD_TOKEN_TOGGLE_SHIFT),
801 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT), 824 data);
802 data);
803 plink = &td->link; 825 plink = &td->link;
826 status |= TD_CTRL_ACTIVE;
804 827
805 data += pktsze; 828 data += pktsze;
806 len -= maxsze; 829 len -= maxsze;
807 830 toggle ^= 1;
808 usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
809 usb_pipeout(urb->pipe));
810 } while (len > 0); 831 } while (len > 0);
811 832
812 /* 833 /*
@@ -821,17 +842,17 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
821 urb->transfer_buffer_length > 0) { 842 urb->transfer_buffer_length > 0) {
822 td = uhci_alloc_td(uhci); 843 td = uhci_alloc_td(uhci);
823 if (!td) 844 if (!td)
824 return -ENOMEM; 845 goto nomem;
825 *plink = cpu_to_le32(td->dma_handle); 846 *plink = cpu_to_le32(td->dma_handle);
826 847
827 uhci_add_td_to_urb(urb, td); 848 uhci_add_td_to_urb(urb, td);
828 uhci_fill_td(td, status, destination | uhci_explen(0) | 849 uhci_fill_td(td, status,
829 (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), 850 destination | uhci_explen(0) |
830 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT), 851 (toggle << TD_TOKEN_TOGGLE_SHIFT),
831 data); 852 data);
853 plink = &td->link;
832 854
833 usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), 855 toggle ^= 1;
834 usb_pipeout(urb->pipe));
835 } 856 }
836 857
837 /* Set the interrupt-on-completion flag on the last packet. 858 /* Set the interrupt-on-completion flag on the last packet.
@@ -842,7 +863,27 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
842 * flag setting. */ 863 * flag setting. */
843 td->status |= __constant_cpu_to_le32(TD_CTRL_IOC); 864 td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
844 865
866 /*
867 * Build the new dummy TD and activate the old one
868 */
869 td = uhci_alloc_td(uhci);
870 if (!td)
871 goto nomem;
872 *plink = cpu_to_le32(td->dma_handle);
873
874 uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
875 wmb();
876 qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
877 qh->dummy_td = td;
878
879 usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
880 usb_pipeout(urb->pipe), toggle);
845 return 0; 881 return 0;
882
883nomem:
884 /* Remove the dummy TD from the td_list so it doesn't get freed */
885 uhci_remove_td_from_urb(qh->dummy_td);
886 return -ENOMEM;
846} 887}
847 888
848/* 889/*
@@ -1169,31 +1210,6 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
1169 * become idle, so we can activate it right away. */ 1210 * become idle, so we can activate it right away. */
1170 if (qh->queue.next == &urbp->node) 1211 if (qh->queue.next == &urbp->node)
1171 uhci_activate_qh(uhci, qh); 1212 uhci_activate_qh(uhci, qh);
1172
1173 /* If the QH is already active, we have a race with the hardware.
1174 * This won't get fixed until dummy TDs are added. */
1175 else if (qh->state == QH_STATE_ACTIVE) {
1176
1177 /* If the URB isn't first on its queue, adjust the link pointer
1178 * of the last TD in the previous URB. */
1179 if (urbp->node.prev != &urbp->qh->queue) {
1180 struct urb_priv *purbp = list_entry(urbp->node.prev,
1181 struct urb_priv, node);
1182 struct uhci_td *ptd = list_entry(purbp->td_list.prev,
1183 struct uhci_td, list);
1184 struct uhci_td *td = list_entry(urbp->td_list.next,
1185 struct uhci_td, list);
1186
1187 ptd->link = cpu_to_le32(td->dma_handle);
1188
1189 }
1190 if (qh_element(qh) == UHCI_PTR_TERM) {
1191 struct uhci_td *td = list_entry(urbp->td_list.next,
1192 struct uhci_td, list);
1193
1194 qh->element = cpu_to_le32(td->dma_handle);
1195 }
1196 }
1197 goto done; 1213 goto done;
1198 1214
1199err_submit_failed: 1215err_submit_failed: