aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2006-05-19 16:52:35 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-06-21 18:04:12 -0400
commitc8155cc5d839838f8425dbea568fc537337176a7 (patch)
treefc50ffe774fa59a1a3d18e8543bb7e04d1e80726 /drivers/usb/host
parentcaf3827a65af476c71eaeb79636869a4ab128d48 (diff)
[PATCH] UHCI: remove ISO TDs as they are used
This patch (as690) does the same thing for ISO TDs as as680 did for non-ISO TDs: free them as they are used rather than all at once when an URB is complete. At the same time it fixes a minor buglet (I'm not aware of it ever affecting anyone): An ISO TD should be retired when its frame is over, regardless of whether or not the hardware has marked it inactive. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/uhci-debug.c14
-rw-r--r--drivers/usb/host/uhci-hcd.h10
-rw-r--r--drivers/usb/host/uhci-q.c103
3 files changed, 90 insertions, 37 deletions
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index ab8ba8220ad1..6637a0e49978 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -127,7 +127,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
127 127
128 i = nactive = ninactive = 0; 128 i = nactive = ninactive = 0;
129 list_for_each_entry(td, &urbp->td_list, list) { 129 list_for_each_entry(td, &urbp->td_list, list) {
130 if (++i <= 10 || debug > 2) { 130 if (urbp->qh->type != USB_ENDPOINT_XFER_ISOC &&
131 (++i <= 10 || debug > 2)) {
131 out += sprintf(out, "%*s%d: ", space + 2, "", i); 132 out += sprintf(out, "%*s%d: ", space + 2, "", i);
132 out += uhci_show_td(td, out, len - (out - buf), 0); 133 out += uhci_show_td(td, out, len - (out - buf), 0);
133 } else { 134 } else {
@@ -168,8 +169,9 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
168 space, "", qh, qtype, 169 space, "", qh, qtype,
169 le32_to_cpu(qh->link), le32_to_cpu(element)); 170 le32_to_cpu(qh->link), le32_to_cpu(element));
170 if (qh->type == USB_ENDPOINT_XFER_ISOC) 171 if (qh->type == USB_ENDPOINT_XFER_ISOC)
171 out += sprintf(out, "%*s period %d\n", 172 out += sprintf(out, "%*s period %d frame %x desc [%p]\n",
172 space, "", qh->period); 173 space, "", qh->period, qh->iso_frame,
174 qh->iso_packet_desc);
173 175
174 if (element & UHCI_PTR_QH) 176 if (element & UHCI_PTR_QH)
175 out += sprintf(out, "%*s Element points to QH (bug?)\n", space, ""); 177 out += sprintf(out, "%*s Element points to QH (bug?)\n", space, "");
@@ -331,8 +333,10 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
331 out += sprintf(out, " sof = %02x\n", sof); 333 out += sprintf(out, " sof = %02x\n", sof);
332 out += uhci_show_sc(1, portsc1, out, len - (out - buf)); 334 out += uhci_show_sc(1, portsc1, out, len - (out - buf));
333 out += uhci_show_sc(2, portsc2, out, len - (out - buf)); 335 out += uhci_show_sc(2, portsc2, out, len - (out - buf));
334 out += sprintf(out, "Most recent frame: %x\n", 336 out += sprintf(out, "Most recent frame: %x (%d) "
335 uhci->frame_number); 337 "Last ISO frame: %x (%d)\n",
338 uhci->frame_number, uhci->frame_number & 1023,
339 uhci->last_iso_frame, uhci->last_iso_frame & 1023);
336 340
337 return out - buf; 341 return out - buf;
338} 342}
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index eaac6ddf03a0..469b4268b850 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -128,8 +128,6 @@ struct uhci_qh {
128 __le32 element; /* Queue element (TD) pointer */ 128 __le32 element; /* Queue element (TD) pointer */
129 129
130 /* Software fields */ 130 /* Software fields */
131 dma_addr_t dma_handle;
132
133 struct list_head node; /* Node in the list of QHs */ 131 struct list_head node; /* Node in the list of QHs */
134 struct usb_host_endpoint *hep; /* Endpoint information */ 132 struct usb_host_endpoint *hep; /* Endpoint information */
135 struct usb_device *udev; 133 struct usb_device *udev;
@@ -138,13 +136,19 @@ struct uhci_qh {
138 struct uhci_td *dummy_td; /* Dummy TD to end the queue */ 136 struct uhci_td *dummy_td; /* Dummy TD to end the queue */
139 struct uhci_td *post_td; /* Last TD completed */ 137 struct uhci_td *post_td; /* Last TD completed */
140 138
139 struct usb_iso_packet_descriptor *iso_packet_desc;
140 /* Next urb->iso_frame_desc entry */
141 unsigned long advance_jiffies; /* Time of last queue advance */ 141 unsigned long advance_jiffies; /* Time of last queue advance */
142 unsigned int unlink_frame; /* When the QH was unlinked */ 142 unsigned int unlink_frame; /* When the QH was unlinked */
143 unsigned int period; /* For Interrupt and Isochronous QHs */ 143 unsigned int period; /* For Interrupt and Isochronous QHs */
144 unsigned int iso_frame; /* Frame # for iso_packet_desc */
145 int iso_status; /* Status for Isochronous URBs */
144 146
145 int state; /* QH_STATE_xxx; see above */ 147 int state; /* QH_STATE_xxx; see above */
146 int type; /* Queue type (control, bulk, etc) */ 148 int type; /* Queue type (control, bulk, etc) */
147 149
150 dma_addr_t dma_handle;
151
148 unsigned int initial_toggle:1; /* Endpoint's current toggle value */ 152 unsigned int initial_toggle:1; /* Endpoint's current toggle value */
149 unsigned int needs_fixup:1; /* Must fix the TD toggle values */ 153 unsigned int needs_fixup:1; /* Must fix the TD toggle values */
150 unsigned int is_stopped:1; /* Queue was stopped by error/unlink */ 154 unsigned int is_stopped:1; /* Queue was stopped by error/unlink */
@@ -386,6 +390,8 @@ struct uhci_hcd {
386 unsigned int frame_number; /* As of last check */ 390 unsigned int frame_number; /* As of last check */
387 unsigned int is_stopped; 391 unsigned int is_stopped;
388#define UHCI_IS_STOPPED 9999 /* Larger than a frame # */ 392#define UHCI_IS_STOPPED 9999 /* Larger than a frame # */
393 unsigned int last_iso_frame; /* Frame of last scan */
394 unsigned int cur_iso_frame; /* Frame for current scan */
389 395
390 unsigned int scan_in_progress:1; /* Schedule scan is running */ 396 unsigned int scan_in_progress:1; /* Schedule scan is running */
391 unsigned int need_rescan:1; /* Redo the schedule scan */ 397 unsigned int need_rescan:1; /* Redo the schedule scan */
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 7acc23473c63..cbbaa4c1740f 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -184,6 +184,24 @@ static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci,
184 td->frame = -1; 184 td->frame = -1;
185} 185}
186 186
187static inline void uhci_remove_tds_from_frame(struct uhci_hcd *uhci,
188 unsigned int framenum)
189{
190 struct uhci_td *ftd, *ltd;
191
192 framenum &= (UHCI_NUMFRAMES - 1);
193
194 ftd = uhci->frame_cpu[framenum];
195 if (ftd) {
196 ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list);
197 uhci->frame[framenum] = ltd->link;
198 uhci->frame_cpu[framenum] = NULL;
199
200 while (!list_empty(&ftd->fl_list))
201 list_del_init(ftd->fl_list.prev);
202 }
203}
204
187/* 205/*
188 * Remove all the TDs for an Isochronous URB from the frame list 206 * Remove all the TDs for an Isochronous URB from the frame list
189 */ 207 */
@@ -523,7 +541,6 @@ static int uhci_map_status(int status, int dir_out)
523 return -ENOSR; 541 return -ENOSR;
524 if (status & TD_CTRL_STALLED) /* Stalled */ 542 if (status & TD_CTRL_STALLED) /* Stalled */
525 return -EPIPE; 543 return -EPIPE;
526 WARN_ON(status & TD_CTRL_ACTIVE); /* Active */
527 return 0; 544 return 0;
528} 545}
529 546
@@ -960,12 +977,12 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
960 return -EFBIG; 977 return -EFBIG;
961 978
962 /* Check the period and figure out the starting frame number */ 979 /* Check the period and figure out the starting frame number */
963 uhci_get_current_frame_number(uhci);
964 if (qh->period == 0) { 980 if (qh->period == 0) {
965 if (urb->transfer_flags & URB_ISO_ASAP) { 981 if (urb->transfer_flags & URB_ISO_ASAP) {
982 uhci_get_current_frame_number(uhci);
966 urb->start_frame = uhci->frame_number + 10; 983 urb->start_frame = uhci->frame_number + 10;
967 } else { 984 } else {
968 i = urb->start_frame - uhci->frame_number; 985 i = urb->start_frame - uhci->last_iso_frame;
969 if (i <= 0 || i >= UHCI_NUMFRAMES) 986 if (i <= 0 || i >= UHCI_NUMFRAMES)
970 return -EINVAL; 987 return -EINVAL;
971 } 988 }
@@ -974,7 +991,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
974 991
975 } else { /* Pick up where the last URB leaves off */ 992 } else { /* Pick up where the last URB leaves off */
976 if (list_empty(&qh->queue)) { 993 if (list_empty(&qh->queue)) {
977 frame = uhci->frame_number + 10; 994 frame = qh->iso_frame;
978 } else { 995 } else {
979 struct urb *lurb; 996 struct urb *lurb;
980 997
@@ -986,11 +1003,12 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
986 } 1003 }
987 if (urb->transfer_flags & URB_ISO_ASAP) 1004 if (urb->transfer_flags & URB_ISO_ASAP)
988 urb->start_frame = frame; 1005 urb->start_frame = frame;
989 /* FIXME: Sanity check */ 1006 else if (urb->start_frame != frame)
1007 return -EINVAL;
990 } 1008 }
991 1009
992 /* Make sure we won't have to go too far into the future */ 1010 /* Make sure we won't have to go too far into the future */
993 if (uhci_frame_before_eq(uhci->frame_number + UHCI_NUMFRAMES, 1011 if (uhci_frame_before_eq(uhci->last_iso_frame + UHCI_NUMFRAMES,
994 urb->start_frame + urb->number_of_packets * 1012 urb->start_frame + urb->number_of_packets *
995 urb->interval)) 1013 urb->interval))
996 return -EFBIG; 1014 return -EFBIG;
@@ -1020,7 +1038,13 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
1020 frame = urb->start_frame; 1038 frame = urb->start_frame;
1021 list_for_each_entry(td, &urbp->td_list, list) { 1039 list_for_each_entry(td, &urbp->td_list, list) {
1022 uhci_insert_td_in_frame_list(uhci, td, frame); 1040 uhci_insert_td_in_frame_list(uhci, td, frame);
1023 frame += urb->interval; 1041 frame += qh->period;
1042 }
1043
1044 if (list_empty(&qh->queue)) {
1045 qh->iso_packet_desc = &urb->iso_frame_desc[0];
1046 qh->iso_frame = urb->start_frame;
1047 qh->iso_status = 0;
1024 } 1048 }
1025 1049
1026 return 0; 1050 return 0;
@@ -1028,37 +1052,44 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
1028 1052
1029static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) 1053static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
1030{ 1054{
1031 struct uhci_td *td; 1055 struct uhci_td *td, *tmp;
1032 struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; 1056 struct urb_priv *urbp = urb->hcpriv;
1033 int status; 1057 struct uhci_qh *qh = urbp->qh;
1034 int i, ret = 0;
1035
1036 urb->actual_length = urb->error_count = 0;
1037 1058
1038 i = 0; 1059 list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
1039 list_for_each_entry(td, &urbp->td_list, list) { 1060 unsigned int ctrlstat;
1061 int status;
1040 int actlength; 1062 int actlength;
1041 unsigned int ctrlstat = td_status(td);
1042 1063
1043 if (ctrlstat & TD_CTRL_ACTIVE) 1064 if (uhci_frame_before_eq(uhci->cur_iso_frame, qh->iso_frame))
1044 return -EINPROGRESS; 1065 return -EINPROGRESS;
1045 1066
1046 actlength = uhci_actual_length(ctrlstat); 1067 uhci_remove_tds_from_frame(uhci, qh->iso_frame);
1047 urb->iso_frame_desc[i].actual_length = actlength; 1068
1048 urb->actual_length += actlength; 1069 ctrlstat = td_status(td);
1070 if (ctrlstat & TD_CTRL_ACTIVE) {
1071 status = -EXDEV; /* TD was added too late? */
1072 } else {
1073 status = uhci_map_status(uhci_status_bits(ctrlstat),
1074 usb_pipeout(urb->pipe));
1075 actlength = uhci_actual_length(ctrlstat);
1076
1077 urb->actual_length += actlength;
1078 qh->iso_packet_desc->actual_length = actlength;
1079 qh->iso_packet_desc->status = status;
1080 }
1049 1081
1050 status = uhci_map_status(uhci_status_bits(ctrlstat),
1051 usb_pipeout(urb->pipe));
1052 urb->iso_frame_desc[i].status = status;
1053 if (status) { 1082 if (status) {
1054 urb->error_count++; 1083 urb->error_count++;
1055 ret = status; 1084 qh->iso_status = status;
1056 } 1085 }
1057 1086
1058 i++; 1087 uhci_remove_td_from_urbp(td);
1088 uhci_free_td(uhci, td);
1089 qh->iso_frame += qh->period;
1090 ++qh->iso_packet_desc;
1059 } 1091 }
1060 1092 return qh->iso_status;
1061 return ret;
1062} 1093}
1063 1094
1064static int uhci_urb_enqueue(struct usb_hcd *hcd, 1095static int uhci_urb_enqueue(struct usb_hcd *hcd,
@@ -1119,6 +1150,7 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
1119 } 1150 }
1120 break; 1151 break;
1121 case USB_ENDPOINT_XFER_ISOC: 1152 case USB_ENDPOINT_XFER_ISOC:
1153 urb->error_count = 0;
1122 bustime = usb_check_bandwidth(urb->dev, urb); 1154 bustime = usb_check_bandwidth(urb->dev, urb);
1123 if (bustime < 0) { 1155 if (bustime < 0) {
1124 ret = bustime; 1156 ret = bustime;
@@ -1200,9 +1232,18 @@ __acquires(uhci->lock)
1200{ 1232{
1201 struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; 1233 struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
1202 1234
1203 /* Isochronous TDs get unlinked directly from the frame list */ 1235 /* When giving back the first URB in an Isochronous queue,
1204 if (qh->type == USB_ENDPOINT_XFER_ISOC) 1236 * reinitialize the QH's iso-related members for the next URB. */
1205 uhci_unlink_isochronous_tds(uhci, urb); 1237 if (qh->type == USB_ENDPOINT_XFER_ISOC &&
1238 urbp->node.prev == &qh->queue &&
1239 urbp->node.next != &qh->queue) {
1240 struct urb *nurb = list_entry(urbp->node.next,
1241 struct urb_priv, node)->urb;
1242
1243 qh->iso_packet_desc = &nurb->iso_frame_desc[0];
1244 qh->iso_frame = nurb->start_frame;
1245 qh->iso_status = 0;
1246 }
1206 1247
1207 /* Take the URB off the QH's queue. If the queue is now empty, 1248 /* Take the URB off the QH's queue. If the queue is now empty,
1208 * this is a perfect time for a toggle fixup. */ 1249 * this is a perfect time for a toggle fixup. */
@@ -1434,6 +1475,7 @@ rescan:
1434 1475
1435 uhci_clear_next_interrupt(uhci); 1476 uhci_clear_next_interrupt(uhci);
1436 uhci_get_current_frame_number(uhci); 1477 uhci_get_current_frame_number(uhci);
1478 uhci->cur_iso_frame = uhci->frame_number;
1437 1479
1438 /* Go through all the QH queues and process the URBs in each one */ 1480 /* Go through all the QH queues and process the URBs in each one */
1439 for (i = 0; i < UHCI_NUM_SKELQH - 1; ++i) { 1481 for (i = 0; i < UHCI_NUM_SKELQH - 1; ++i) {
@@ -1451,6 +1493,7 @@ rescan:
1451 } 1493 }
1452 } 1494 }
1453 1495
1496 uhci->last_iso_frame = uhci->cur_iso_frame;
1454 if (uhci->need_rescan) 1497 if (uhci->need_rescan)
1455 goto rescan; 1498 goto rescan;
1456 uhci->scan_in_progress = 0; 1499 uhci->scan_in_progress = 0;