Commit c8155cc5d839838f8425dbea568fc537337176a7

Authored by Alan Stern
Committed by Greg Kroah-Hartman
1 parent caf3827a65

[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>

Showing 3 changed files with 90 additions and 37 deletions Side-by-side Diff

drivers/usb/host/uhci-debug.c
... ... @@ -127,7 +127,8 @@
127 127  
128 128 i = nactive = ninactive = 0;
129 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 132 out += sprintf(out, "%*s%d: ", space + 2, "", i);
132 133 out += uhci_show_td(td, out, len - (out - buf), 0);
133 134 } else {
... ... @@ -168,8 +169,9 @@
168 169 space, "", qh, qtype,
169 170 le32_to_cpu(qh->link), le32_to_cpu(element));
170 171 if (qh->type == USB_ENDPOINT_XFER_ISOC)
171   - out += sprintf(out, "%*s period %d\n",
172   - space, "", qh->period);
  172 + out += sprintf(out, "%*s period %d frame %x desc [%p]\n",
  173 + space, "", qh->period, qh->iso_frame,
  174 + qh->iso_packet_desc);
173 175  
174 176 if (element & UHCI_PTR_QH)
175 177 out += sprintf(out, "%*s Element points to QH (bug?)\n", space, "");
... ... @@ -331,8 +333,10 @@
331 333 out += sprintf(out, " sof = %02x\n", sof);
332 334 out += uhci_show_sc(1, portsc1, out, len - (out - buf));
333 335 out += uhci_show_sc(2, portsc2, out, len - (out - buf));
334   - out += sprintf(out, "Most recent frame: %x\n",
335   - uhci->frame_number);
  336 + out += sprintf(out, "Most recent frame: %x (%d) "
  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 341 return out - buf;
338 342 }
drivers/usb/host/uhci-hcd.h
... ... @@ -128,8 +128,6 @@
128 128 __le32 element; /* Queue element (TD) pointer */
129 129  
130 130 /* Software fields */
131   - dma_addr_t dma_handle;
132   -
133 131 struct list_head node; /* Node in the list of QHs */
134 132 struct usb_host_endpoint *hep; /* Endpoint information */
135 133 struct usb_device *udev;
136 134  
137 135  
... ... @@ -138,13 +136,19 @@
138 136 struct uhci_td *dummy_td; /* Dummy TD to end the queue */
139 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 141 unsigned long advance_jiffies; /* Time of last queue advance */
142 142 unsigned int unlink_frame; /* When the QH was unlinked */
143 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 147 int state; /* QH_STATE_xxx; see above */
146 148 int type; /* Queue type (control, bulk, etc) */
147 149  
  150 + dma_addr_t dma_handle;
  151 +
148 152 unsigned int initial_toggle:1; /* Endpoint's current toggle value */
149 153 unsigned int needs_fixup:1; /* Must fix the TD toggle values */
150 154 unsigned int is_stopped:1; /* Queue was stopped by error/unlink */
... ... @@ -386,6 +390,8 @@
386 390 unsigned int frame_number; /* As of last check */
387 391 unsigned int is_stopped;
388 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 396 unsigned int scan_in_progress:1; /* Schedule scan is running */
391 397 unsigned int need_rescan:1; /* Redo the schedule scan */
drivers/usb/host/uhci-q.c
... ... @@ -184,6 +184,24 @@
184 184 td->frame = -1;
185 185 }
186 186  
  187 +static 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 206 * Remove all the TDs for an Isochronous URB from the frame list
189 207 */
... ... @@ -523,7 +541,6 @@
523 541 return -ENOSR;
524 542 if (status & TD_CTRL_STALLED) /* Stalled */
525 543 return -EPIPE;
526   - WARN_ON(status & TD_CTRL_ACTIVE); /* Active */
527 544 return 0;
528 545 }
529 546  
530 547  
531 548  
... ... @@ -960,12 +977,12 @@
960 977 return -EFBIG;
961 978  
962 979 /* Check the period and figure out the starting frame number */
963   - uhci_get_current_frame_number(uhci);
964 980 if (qh->period == 0) {
965 981 if (urb->transfer_flags & URB_ISO_ASAP) {
  982 + uhci_get_current_frame_number(uhci);
966 983 urb->start_frame = uhci->frame_number + 10;
967 984 } else {
968   - i = urb->start_frame - uhci->frame_number;
  985 + i = urb->start_frame - uhci->last_iso_frame;
969 986 if (i <= 0 || i >= UHCI_NUMFRAMES)
970 987 return -EINVAL;
971 988 }
... ... @@ -974,7 +991,7 @@
974 991  
975 992 } else { /* Pick up where the last URB leaves off */
976 993 if (list_empty(&qh->queue)) {
977   - frame = uhci->frame_number + 10;
  994 + frame = qh->iso_frame;
978 995 } else {
979 996 struct urb *lurb;
980 997  
981 998  
... ... @@ -986,11 +1003,12 @@
986 1003 }
987 1004 if (urb->transfer_flags & URB_ISO_ASAP)
988 1005 urb->start_frame = frame;
989   - /* FIXME: Sanity check */
  1006 + else if (urb->start_frame != frame)
  1007 + return -EINVAL;
990 1008 }
991 1009  
992 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 1012 urb->start_frame + urb->number_of_packets *
995 1013 urb->interval))
996 1014 return -EFBIG;
997 1015  
998 1016  
999 1017  
1000 1018  
1001 1019  
1002 1020  
1003 1021  
1004 1022  
1005 1023  
1006 1024  
... ... @@ -1020,45 +1038,58 @@
1020 1038 frame = urb->start_frame;
1021 1039 list_for_each_entry(td, &urbp->td_list, list) {
1022 1040 uhci_insert_td_in_frame_list(uhci, td, frame);
1023   - frame += urb->interval;
  1041 + frame += qh->period;
1024 1042 }
1025 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;
  1048 + }
  1049 +
1026 1050 return 0;
1027 1051 }
1028 1052  
1029 1053 static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
1030 1054 {
1031   - struct uhci_td *td;
1032   - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
1033   - int status;
1034   - int i, ret = 0;
  1055 + struct uhci_td *td, *tmp;
  1056 + struct urb_priv *urbp = urb->hcpriv;
  1057 + struct uhci_qh *qh = urbp->qh;
1035 1058  
1036   - urb->actual_length = urb->error_count = 0;
1037   -
1038   - i = 0;
1039   - list_for_each_entry(td, &urbp->td_list, list) {
  1059 + list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
  1060 + unsigned int ctrlstat;
  1061 + int status;
1040 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 1065 return -EINPROGRESS;
1045 1066  
1046   - actlength = uhci_actual_length(ctrlstat);
1047   - urb->iso_frame_desc[i].actual_length = actlength;
1048   - urb->actual_length += actlength;
  1067 + uhci_remove_tds_from_frame(uhci, qh->iso_frame);
1049 1068  
1050   - status = uhci_map_status(uhci_status_bits(ctrlstat),
1051   - usb_pipeout(urb->pipe));
1052   - urb->iso_frame_desc[i].status = status;
  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 + }
  1081 +
1053 1082 if (status) {
1054 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   -
1061   - return ret;
  1092 + return qh->iso_status;
1062 1093 }
1063 1094  
1064 1095 static int uhci_urb_enqueue(struct usb_hcd *hcd,
... ... @@ -1119,6 +1150,7 @@
1119 1150 }
1120 1151 break;
1121 1152 case USB_ENDPOINT_XFER_ISOC:
  1153 + urb->error_count = 0;
1122 1154 bustime = usb_check_bandwidth(urb->dev, urb);
1123 1155 if (bustime < 0) {
1124 1156 ret = bustime;
1125 1157  
... ... @@ -1200,10 +1232,19 @@
1200 1232 {
1201 1233 struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
1202 1234  
1203   - /* Isochronous TDs get unlinked directly from the frame list */
1204   - if (qh->type == USB_ENDPOINT_XFER_ISOC)
1205   - uhci_unlink_isochronous_tds(uhci, urb);
  1235 + /* When giving back the first URB in an Isochronous queue,
  1236 + * reinitialize the QH's iso-related members for the next 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;
1206 1242  
  1243 + qh->iso_packet_desc = &nurb->iso_frame_desc[0];
  1244 + qh->iso_frame = nurb->start_frame;
  1245 + qh->iso_status = 0;
  1246 + }
  1247 +
1207 1248 /* Take the URB off the QH's queue. If the queue is now empty,
1208 1249 * this is a perfect time for a toggle fixup. */
1209 1250 list_del_init(&urbp->node);
... ... @@ -1434,6 +1475,7 @@
1434 1475  
1435 1476 uhci_clear_next_interrupt(uhci);
1436 1477 uhci_get_current_frame_number(uhci);
  1478 + uhci->cur_iso_frame = uhci->frame_number;
1437 1479  
1438 1480 /* Go through all the QH queues and process the URBs in each one */
1439 1481 for (i = 0; i < UHCI_NUM_SKELQH - 1; ++i) {
... ... @@ -1451,6 +1493,7 @@
1451 1493 }
1452 1494 }
1453 1495  
  1496 + uhci->last_iso_frame = uhci->cur_iso_frame;
1454 1497 if (uhci->need_rescan)
1455 1498 goto rescan;
1456 1499 uhci->scan_in_progress = 0;