aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2005-10-13 17:00:24 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-10-28 19:47:44 -0400
commitb81d34363c0b17c47f4ef63d5888c4f47f315d29 (patch)
treeaf4151e7d296da8f9e9a493ed81c5513f2454618 /drivers
parent0c0382e32d46f606951010b202382be14d180a17 (diff)
[PATCH] UHCI: Improve handling of iso TDs
The uhci-hcd driver is fairly lax about the way it handles isochronous transfers. This patch (as579) improves it in three respects: TDs for a new URB aren't added to the schedule until all of them have been allocated. This way there's no risk of the controller executing some of them when an allocation fails. TDs for an unlinked URB are removed from the schedule as soon as the URB is unlinked, rather than waiting until the URB is given back. This way there's no risk of the controller still executing a TD after the URB completes. The urb->error_count values are now reported correctly. Although since they aren't used in any drivers except for debug messages in the system log, probably nobody cares. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/uhci-q.c39
1 files changed, 26 insertions, 13 deletions
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 51de06bc438..7e46887d9e1 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -108,13 +108,16 @@ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td,
108 } 108 }
109} 109}
110 110
111static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td) 111static inline void uhci_remove_td_frame_list(struct uhci_hcd *uhci,
112 struct uhci_td *td)
112{ 113{
113 /* If it's not inserted, don't remove it */ 114 /* If it's not inserted, don't remove it */
114 if (td->frame == -1 && list_empty(&td->fl_list)) 115 if (td->frame == -1) {
116 WARN_ON(!list_empty(&td->fl_list));
115 return; 117 return;
118 }
116 119
117 if (td->frame != -1 && uhci->frame_cpu[td->frame] == td) { 120 if (uhci->frame_cpu[td->frame] == td) {
118 if (list_empty(&td->fl_list)) { 121 if (list_empty(&td->fl_list)) {
119 uhci->frame[td->frame] = td->link; 122 uhci->frame[td->frame] = td->link;
120 uhci->frame_cpu[td->frame] = NULL; 123 uhci->frame_cpu[td->frame] = NULL;
@@ -132,13 +135,20 @@ static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td)
132 ptd->link = td->link; 135 ptd->link = td->link;
133 } 136 }
134 137
135 wmb();
136 td->link = UHCI_PTR_TERM;
137
138 list_del_init(&td->fl_list); 138 list_del_init(&td->fl_list);
139 td->frame = -1; 139 td->frame = -1;
140} 140}
141 141
142static void unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb)
143{
144 struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
145 struct uhci_td *td;
146
147 list_for_each_entry(td, &urbp->td_list, list)
148 uhci_remove_td_frame_list(uhci, td);
149 wmb();
150}
151
142/* 152/*
143 * Inserts a td list into qh. 153 * Inserts a td list into qh.
144 */ 154 */
@@ -498,7 +508,6 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
498 508
499 list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { 509 list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
500 uhci_remove_td_from_urb(td); 510 uhci_remove_td_from_urb(td);
501 uhci_remove_td(uhci, td);
502 list_add(&td->remove_list, &uhci->td_remove_list); 511 list_add(&td->remove_list, &uhci->td_remove_list);
503 } 512 }
504 513
@@ -1068,6 +1077,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
1068 struct uhci_td *td; 1077 struct uhci_td *td;
1069 int i, ret, frame; 1078 int i, ret, frame;
1070 int status, destination; 1079 int status, destination;
1080 struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
1071 1081
1072 status = TD_CTRL_ACTIVE | TD_CTRL_IOS; 1082 status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
1073 destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); 1083 destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
@@ -1076,11 +1086,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
1076 if (ret) 1086 if (ret)
1077 return ret; 1087 return ret;
1078 1088
1079 frame = urb->start_frame; 1089 for (i = 0; i < urb->number_of_packets; i++) {
1080 for (i = 0; i < urb->number_of_packets; i++, frame += urb->interval) {
1081 if (!urb->iso_frame_desc[i].length)
1082 continue;
1083
1084 td = uhci_alloc_td(uhci); 1090 td = uhci_alloc_td(uhci);
1085 if (!td) 1091 if (!td)
1086 return -ENOMEM; 1092 return -ENOMEM;
@@ -1091,8 +1097,12 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
1091 1097
1092 if (i + 1 >= urb->number_of_packets) 1098 if (i + 1 >= urb->number_of_packets)
1093 td->status |= cpu_to_le32(TD_CTRL_IOC); 1099 td->status |= cpu_to_le32(TD_CTRL_IOC);
1100 }
1094 1101
1102 frame = urb->start_frame;
1103 list_for_each_entry(td, &urbp->td_list, list) {
1095 uhci_insert_td_frame_list(uhci, td, frame); 1104 uhci_insert_td_frame_list(uhci, td, frame);
1105 frame += urb->interval;
1096 } 1106 }
1097 1107
1098 return -EINPROGRESS; 1108 return -EINPROGRESS;
@@ -1105,7 +1115,7 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
1105 int status; 1115 int status;
1106 int i, ret = 0; 1116 int i, ret = 0;
1107 1117
1108 urb->actual_length = 0; 1118 urb->actual_length = urb->error_count = 0;
1109 1119
1110 i = 0; 1120 i = 0;
1111 list_for_each_entry(td, &urbp->td_list, list) { 1121 list_for_each_entry(td, &urbp->td_list, list) {
@@ -1129,6 +1139,7 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
1129 1139
1130 i++; 1140 i++;
1131 } 1141 }
1142 unlink_isochronous_tds(uhci, urb);
1132 1143
1133 return ret; 1144 return ret;
1134} 1145}
@@ -1361,6 +1372,8 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
1361 goto done; 1372 goto done;
1362 list_del_init(&urbp->urb_list); 1373 list_del_init(&urbp->urb_list);
1363 1374
1375 if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
1376 unlink_isochronous_tds(uhci, urb);
1364 uhci_unlink_generic(uhci, urb); 1377 uhci_unlink_generic(uhci, urb);
1365 1378
1366 uhci_get_current_frame_number(uhci); 1379 uhci_get_current_frame_number(uhci);