aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorArvid Brodin <arvid.brodin@enea.com>2011-02-26 16:07:35 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-02-28 22:23:38 -0500
commit65f1b5255ce0e657e4d8de92098837d36831320a (patch)
treeccb5d598233a24c53d0a8303faae4bb7a2acf208 /drivers/usb/host
parent6bda21bc0941c11f07cbf436ff6ca85e7e6e47f0 (diff)
usb/isp1760: Replace period calculation for INT packets with something readable
Replace the period calculation for INT packets with something readable. Seems to fix a rare bug with quickly repeated insertion/removal of several USB devices simultaneously (hub control INT packets). Signed-off-by: Arvid Brodin <arvid.brodin@enea.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/isp1760-hcd.c106
1 files changed, 37 insertions, 69 deletions
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
index 0f5b48946739..fd718ff6afab 100644
--- a/drivers/usb/host/isp1760-hcd.c
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -97,9 +97,6 @@ struct isp1760_qh {
97 /* first part defined by EHCI spec */ 97 /* first part defined by EHCI spec */
98 struct list_head qtd_list; 98 struct list_head qtd_list;
99 99
100 /* periodic schedule info */
101 unsigned short period; /* polling interval */
102
103 u32 toggle; 100 u32 toggle;
104 u32 ping; 101 u32 ping;
105}; 102};
@@ -673,60 +670,51 @@ static void transform_into_atl(struct isp1760_qh *qh,
673static void transform_add_int(struct isp1760_qh *qh, 670static void transform_add_int(struct isp1760_qh *qh,
674 struct isp1760_qtd *qtd, struct ptd *ptd) 671 struct isp1760_qtd *qtd, struct ptd *ptd)
675{ 672{
676 u32 maxpacket; 673 u32 usof;
677 u32 multi;
678 u32 numberofusofs;
679 u32 i;
680 u32 usofmask, usof;
681 u32 period; 674 u32 period;
682 675
683 maxpacket = usb_maxpacket(qtd->urb->dev, qtd->urb->pipe, 676 /*
684 usb_pipeout(qtd->urb->pipe)); 677 * Most of this is guessing. ISP1761 datasheet is quite unclear, and
685 multi = 1 + ((maxpacket >> 11) & 0x3); 678 * the algorithm from the original Philips driver code, which was
686 maxpacket &= 0x7ff; 679 * pretty much used in this driver before as well, is quite horrendous
687 /* length of the data per uframe */ 680 * and, i believe, incorrect. The code below follows the datasheet and
688 maxpacket = multi * maxpacket; 681 * USB2.0 spec as far as I can tell, and plug/unplug seems to be much
689 682 * more reliable this way (fingers crossed...).
690 numberofusofs = qtd->urb->transfer_buffer_length / maxpacket; 683 */
691 if (qtd->urb->transfer_buffer_length % maxpacket)
692 numberofusofs += 1;
693
694 usofmask = 1;
695 usof = 0;
696 for (i = 0; i < numberofusofs; i++) {
697 usof |= usofmask;
698 usofmask <<= 1;
699 }
700
701 if (qtd->urb->dev->speed != USB_SPEED_HIGH) {
702 /* split */
703 ptd->dw5 = 0x1c;
704 684
705 if (qh->period >= 32) 685 if (qtd->urb->dev->speed == USB_SPEED_HIGH) {
706 period = qh->period / 2; 686 /* urb->interval is in units of microframes (1/8 ms) */
687 period = qtd->urb->interval >> 3;
688
689 if (qtd->urb->interval > 4)
690 usof = 0x01; /* One bit set =>
691 interval 1 ms * uFrame-match */
692 else if (qtd->urb->interval > 2)
693 usof = 0x22; /* Two bits set => interval 1/2 ms */
694 else if (qtd->urb->interval > 1)
695 usof = 0x55; /* Four bits set => interval 1/4 ms */
707 else 696 else
708 period = qh->period; 697 usof = 0xff; /* All bits set => interval 1/8 ms */
709
710 } else { 698 } else {
699 /* urb->interval is in units of frames (1 ms) */
700 period = qtd->urb->interval;
701 usof = 0x0f; /* Execute Start Split on any of the
702 four first uFrames */
711 703
712 if (qh->period >= 8) 704 /*
713 period = qh->period/8; 705 * First 8 bits in dw5 is uSCS and "specifies which uSOF the
714 else 706 * complete split needs to be sent. Valid only for IN." Also,
715 period = qh->period; 707 * "All bits can be set to one for every transfer." (p 82,
716 708 * ISP1761 data sheet.) 0x1c is from Philips driver. Where did
717 if (period >= 32) 709 * that number come from? 0xff seems to work fine...
718 period = 16; 710 */
719 711 /* ptd->dw5 = 0x1c; */
720 if (qh->period >= 8) { 712 ptd->dw5 = 0xff; /* Execute Complete Split on any uFrame */
721 /* millisecond period */
722 period = (period << 3);
723 } else {
724 /* usof based tranmsfers */
725 /* minimum 4 usofs */
726 usof = 0x11;
727 }
728 } 713 }
729 714
715 period = period >> 1;/* Ensure equal or shorter period than requested */
716 period &= 0xf8; /* Mask off too large values and lowest unused 3 bits */
717
730 ptd->dw2 |= period; 718 ptd->dw2 |= period;
731 ptd->dw4 = usof; 719 ptd->dw4 = usof;
732} 720}
@@ -1328,26 +1316,6 @@ static struct isp1760_qh *qh_make(struct usb_hcd *hcd, struct urb *urb,
1328 is_input = usb_pipein(urb->pipe); 1316 is_input = usb_pipein(urb->pipe);
1329 type = usb_pipetype(urb->pipe); 1317 type = usb_pipetype(urb->pipe);
1330 1318
1331 if (type == PIPE_INTERRUPT) {
1332
1333 if (urb->dev->speed == USB_SPEED_HIGH) {
1334
1335 qh->period = urb->interval >> 3;
1336 if (qh->period == 0 && urb->interval != 1) {
1337 /* NOTE interval 2 or 4 uframes could work.
1338 * But interval 1 scheduling is simpler, and
1339 * includes high bandwidth.
1340 */
1341 dev_err(hcd->self.controller, "intr period %d uframes, NYET!",
1342 urb->interval);
1343 qh_destroy(qh);
1344 return NULL;
1345 }
1346 } else {
1347 qh->period = urb->interval;
1348 }
1349 }
1350
1351 if (!usb_pipecontrol(urb->pipe)) 1319 if (!usb_pipecontrol(urb->pipe))
1352 usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, 1320 usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input,
1353 1); 1321 1);