diff options
author | Arvid Brodin <arvid.brodin@enea.com> | 2011-02-26 16:07:35 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-02-28 22:23:38 -0500 |
commit | 65f1b5255ce0e657e4d8de92098837d36831320a (patch) | |
tree | ccb5d598233a24c53d0a8303faae4bb7a2acf208 /drivers/usb/host | |
parent | 6bda21bc0941c11f07cbf436ff6ca85e7e6e47f0 (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.c | 106 |
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, | |||
673 | static void transform_add_int(struct isp1760_qh *qh, | 670 | static 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); |