aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2006-05-12 11:35:45 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-06-21 18:04:11 -0400
commit84afddd7ac58adad00cb0e50d0af25fcf825668b (patch)
treeb528f0169ae61309ea4a0020bd53504f8faa827e
parent04538a255ac8b404c20cbf15867c9829254c470f (diff)
[PATCH] UHCI: Reimplement FSBR
This patch (as683) re-implements Full-Speed Bandwidth Reclamation (FSBR) properly. It keeps track of which endpoint queues have advanced, and when none have advanced for a sufficiently long time, FSBR is turned off. The next TD on each of the non-moving queues is modified to generate an interrupt on completion, so that FSBR can be re-enabled as soon as the hardware starts to make some progress. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/host/uhci-debug.c3
-rw-r--r--drivers/usb/host/uhci-hcd.c13
-rw-r--r--drivers/usb/host/uhci-hcd.h15
-rw-r--r--drivers/usb/host/uhci-hub.c1
-rw-r--r--drivers/usb/host/uhci-q.c168
5 files changed, 143 insertions, 57 deletions
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 6bbd33db9358..081c592fe8b1 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -274,7 +274,8 @@ static int uhci_show_root_hub_state(struct uhci_hcd *uhci, char *buf, int len)
274 default: 274 default:
275 rh_state = "?"; break; 275 rh_state = "?"; break;
276 } 276 }
277 out += sprintf(out, "Root-hub state: %s\n", rh_state); 277 out += sprintf(out, "Root-hub state: %s FSBR: %d\n",
278 rh_state, uhci->fsbr_is_on);
278 return out - buf; 279 return out - buf;
279} 280}
280 281
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index fb4c1a8cadf4..395402eec5ef 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -88,15 +88,6 @@ static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state);
88static void wakeup_rh(struct uhci_hcd *uhci); 88static void wakeup_rh(struct uhci_hcd *uhci);
89static void uhci_get_current_frame_number(struct uhci_hcd *uhci); 89static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
90 90
91/* If a transfer is still active after this much time, turn off FSBR */
92#define IDLE_TIMEOUT msecs_to_jiffies(50)
93#define FSBR_DELAY msecs_to_jiffies(50)
94
95/* When we timeout an idle transfer for FSBR, we'll switch it over to */
96/* depth first traversal. We'll do it in groups of this number of TDs */
97/* to make sure it doesn't hog all of the bandwidth */
98#define DEPTH_INTERVAL 5
99
100#include "uhci-debug.c" 91#include "uhci-debug.c"
101#include "uhci-q.c" 92#include "uhci-q.c"
102#include "uhci-hub.c" 93#include "uhci-hub.c"
@@ -255,6 +246,7 @@ __acquires(uhci->lock)
255 uhci_to_hcd(uhci)->poll_rh = !int_enable; 246 uhci_to_hcd(uhci)->poll_rh = !int_enable;
256 247
257 uhci_scan_schedule(uhci, NULL); 248 uhci_scan_schedule(uhci, NULL);
249 uhci_fsbr_off(uhci);
258} 250}
259 251
260static void start_rh(struct uhci_hcd *uhci) 252static void start_rh(struct uhci_hcd *uhci)
@@ -487,9 +479,6 @@ static int uhci_start(struct usb_hcd *hcd)
487 479
488 hcd->uses_new_polling = 1; 480 hcd->uses_new_polling = 1;
489 481
490 uhci->fsbr = 0;
491 uhci->fsbrtimeout = 0;
492
493 spin_lock_init(&uhci->lock); 482 spin_lock_init(&uhci->lock);
494 483
495 INIT_LIST_HEAD(&uhci->idle_qh_list); 484 INIT_LIST_HEAD(&uhci->idle_qh_list);
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 90ef7fbbf2fb..04938e64799f 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -84,6 +84,13 @@
84#define CAN_SCHEDULE_FRAMES 1000 /* how far in the future frames 84#define CAN_SCHEDULE_FRAMES 1000 /* how far in the future frames
85 * can be scheduled */ 85 * can be scheduled */
86 86
87/* When no queues need Full-Speed Bandwidth Reclamation,
88 * delay this long before turning FSBR off */
89#define FSBR_OFF_DELAY msecs_to_jiffies(400)
90
91/* If a queue hasn't advanced after this much time, assume it is stuck */
92#define QH_WAIT_TIMEOUT msecs_to_jiffies(200)
93
87 94
88/* 95/*
89 * Queue Headers 96 * Queue Headers
@@ -131,6 +138,7 @@ struct uhci_qh {
131 struct uhci_td *dummy_td; /* Dummy TD to end the queue */ 138 struct uhci_td *dummy_td; /* Dummy TD to end the queue */
132 struct uhci_td *post_td; /* Last TD completed */ 139 struct uhci_td *post_td; /* Last TD completed */
133 140
141 unsigned long advance_jiffies; /* Time of last queue advance */
134 unsigned int unlink_frame; /* When the QH was unlinked */ 142 unsigned int unlink_frame; /* When the QH was unlinked */
135 int state; /* QH_STATE_xxx; see above */ 143 int state; /* QH_STATE_xxx; see above */
136 int type; /* Queue type (control, bulk, etc) */ 144 int type; /* Queue type (control, bulk, etc) */
@@ -138,6 +146,7 @@ struct uhci_qh {
138 unsigned int initial_toggle:1; /* Endpoint's current toggle value */ 146 unsigned int initial_toggle:1; /* Endpoint's current toggle value */
139 unsigned int needs_fixup:1; /* Must fix the TD toggle values */ 147 unsigned int needs_fixup:1; /* Must fix the TD toggle values */
140 unsigned int is_stopped:1; /* Queue was stopped by error/unlink */ 148 unsigned int is_stopped:1; /* Queue was stopped by error/unlink */
149 unsigned int wait_expired:1; /* QH_WAIT_TIMEOUT has expired */
141} __attribute__((aligned(16))); 150} __attribute__((aligned(16)));
142 151
143/* 152/*
@@ -397,8 +406,7 @@ struct uhci_hcd {
397 __le32 *frame; 406 __le32 *frame;
398 void **frame_cpu; /* CPU's frame list */ 407 void **frame_cpu; /* CPU's frame list */
399 408
400 int fsbr; /* Full-speed bandwidth reclamation */ 409 unsigned long fsbr_jiffies; /* Time when FSBR was last wanted */
401 unsigned long fsbrtimeout; /* FSBR delay */
402 410
403 enum uhci_rh_state rh_state; 411 enum uhci_rh_state rh_state;
404 unsigned long auto_stop_time; /* When to AUTO_STOP */ 412 unsigned long auto_stop_time; /* When to AUTO_STOP */
@@ -413,6 +421,7 @@ struct uhci_hcd {
413 unsigned int working_RD:1; /* Suspended root hub doesn't 421 unsigned int working_RD:1; /* Suspended root hub doesn't
414 need to be polled */ 422 need to be polled */
415 unsigned int is_initialized:1; /* Data structure is usable */ 423 unsigned int is_initialized:1; /* Data structure is usable */
424 unsigned int fsbr_is_on:1; /* FSBR is turned on */
416 425
417 /* Support for port suspend/resume/reset */ 426 /* Support for port suspend/resume/reset */
418 unsigned long port_c_suspend; /* Bit-arrays of ports */ 427 unsigned long port_c_suspend; /* Bit-arrays of ports */
@@ -451,7 +460,7 @@ struct urb_priv {
451 struct uhci_qh *qh; /* QH for this URB */ 460 struct uhci_qh *qh; /* QH for this URB */
452 struct list_head td_list; 461 struct list_head td_list;
453 462
454 unsigned fsbr : 1; /* URB turned on FSBR */ 463 unsigned fsbr:1; /* URB wants FSBR */
455}; 464};
456 465
457 466
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
index c8451d9578f1..f53c116e0dfd 100644
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -173,7 +173,6 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
173 uhci_scan_schedule(uhci, NULL); 173 uhci_scan_schedule(uhci, NULL);
174 if (uhci->hc_inaccessible) 174 if (uhci->hc_inaccessible)
175 goto done; 175 goto done;
176 check_fsbr(uhci);
177 uhci_check_ports(uhci); 176 uhci_check_ports(uhci);
178 177
179 status = get_hub_status_data(uhci, buf); 178 status = get_hub_status_data(uhci, buf);
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 12af6fb05a30..2be84b3b40fe 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -37,6 +37,46 @@ static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
37 uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC); 37 uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC);
38} 38}
39 39
40
41/*
42 * Full-Speed Bandwidth Reclamation (FSBR).
43 * We turn on FSBR whenever a queue that wants it is advancing,
44 * and leave it on for a short time thereafter.
45 */
46static void uhci_fsbr_on(struct uhci_hcd *uhci)
47{
48 uhci->fsbr_is_on = 1;
49 uhci->skel_term_qh->link = cpu_to_le32(
50 uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;
51}
52
53static void uhci_fsbr_off(struct uhci_hcd *uhci)
54{
55 uhci->fsbr_is_on = 0;
56 uhci->skel_term_qh->link = UHCI_PTR_TERM;
57}
58
59static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb)
60{
61 struct urb_priv *urbp = urb->hcpriv;
62
63 if (!(urb->transfer_flags & URB_NO_FSBR))
64 urbp->fsbr = 1;
65}
66
67static void uhci_qh_wants_fsbr(struct uhci_hcd *uhci, struct uhci_qh *qh)
68{
69 struct urb_priv *urbp =
70 list_entry(qh->queue.next, struct urb_priv, node);
71
72 if (urbp->fsbr) {
73 uhci->fsbr_jiffies = jiffies;
74 if (!uhci->fsbr_is_on)
75 uhci_fsbr_on(uhci);
76 }
77}
78
79
40static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci) 80static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci)
41{ 81{
42 dma_addr_t dma_handle; 82 dma_addr_t dma_handle;
@@ -331,6 +371,10 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
331 qh->element = cpu_to_le32(td->dma_handle); 371 qh->element = cpu_to_le32(td->dma_handle);
332 } 372 }
333 373
374 /* Treat the queue as if it has just advanced */
375 qh->wait_expired = 0;
376 qh->advance_jiffies = jiffies;
377
334 if (qh->state == QH_STATE_ACTIVE) 378 if (qh->state == QH_STATE_ACTIVE)
335 return; 379 return;
336 qh->state = QH_STATE_ACTIVE; 380 qh->state = QH_STATE_ACTIVE;
@@ -445,28 +489,6 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci,
445 kmem_cache_free(uhci_up_cachep, urbp); 489 kmem_cache_free(uhci_up_cachep, urbp);
446} 490}
447 491
448static void uhci_inc_fsbr(struct uhci_hcd *uhci, struct urb *urb)
449{
450 struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
451
452 if ((!(urb->transfer_flags & URB_NO_FSBR)) && !urbp->fsbr) {
453 urbp->fsbr = 1;
454 if (!uhci->fsbr++ && !uhci->fsbrtimeout)
455 uhci->skel_term_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;
456 }
457}
458
459static void uhci_dec_fsbr(struct uhci_hcd *uhci, struct urb *urb)
460{
461 struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
462
463 if ((!(urb->transfer_flags & URB_NO_FSBR)) && urbp->fsbr) {
464 urbp->fsbr = 0;
465 if (!--uhci->fsbr)
466 uhci->fsbrtimeout = jiffies + FSBR_DELAY;
467 }
468}
469
470/* 492/*
471 * Map status to standard result codes 493 * Map status to standard result codes
472 * 494 *
@@ -613,7 +635,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
613 qh->skel = uhci->skel_ls_control_qh; 635 qh->skel = uhci->skel_ls_control_qh;
614 else { 636 else {
615 qh->skel = uhci->skel_fs_control_qh; 637 qh->skel = uhci->skel_fs_control_qh;
616 uhci_inc_fsbr(uhci, urb); 638 uhci_add_fsbr(uhci, urb);
617 } 639 }
618 640
619 urb->actual_length = -8; /* Account for the SETUP packet */ 641 urb->actual_length = -8; /* Account for the SETUP packet */
@@ -756,7 +778,7 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
756 qh->skel = uhci->skel_bulk_qh; 778 qh->skel = uhci->skel_bulk_qh;
757 ret = uhci_submit_common(uhci, urb, qh); 779 ret = uhci_submit_common(uhci, urb, qh);
758 if (ret == 0) 780 if (ret == 0)
759 uhci_inc_fsbr(uhci, urb); 781 uhci_add_fsbr(uhci, urb);
760 return ret; 782 return ret;
761} 783}
762 784
@@ -1075,8 +1097,10 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
1075 * the QH is new and idle or else it's unlinked and waiting to 1097 * the QH is new and idle or else it's unlinked and waiting to
1076 * become idle, so we can activate it right away. But only if the 1098 * become idle, so we can activate it right away. But only if the
1077 * queue isn't stopped. */ 1099 * queue isn't stopped. */
1078 if (qh->queue.next == &urbp->node && !qh->is_stopped) 1100 if (qh->queue.next == &urbp->node && !qh->is_stopped) {
1079 uhci_activate_qh(uhci, qh); 1101 uhci_activate_qh(uhci, qh);
1102 uhci_qh_wants_fsbr(uhci, qh);
1103 }
1080 goto done; 1104 goto done;
1081 1105
1082err_submit_failed: 1106err_submit_failed:
@@ -1135,7 +1159,6 @@ __acquires(uhci->lock)
1135 qh->needs_fixup = 0; 1159 qh->needs_fixup = 0;
1136 } 1160 }
1137 1161
1138 uhci_dec_fsbr(uhci, urb); /* Safe since it checks */
1139 uhci_free_urb_priv(uhci, urbp); 1162 uhci_free_urb_priv(uhci, urbp);
1140 1163
1141 switch (qh->type) { 1164 switch (qh->type) {
@@ -1239,6 +1262,18 @@ restart:
1239 if (!list_empty(&qh->queue)) { 1262 if (!list_empty(&qh->queue)) {
1240 if (qh->needs_fixup) 1263 if (qh->needs_fixup)
1241 uhci_fixup_toggles(qh, 0); 1264 uhci_fixup_toggles(qh, 0);
1265
1266 /* If the first URB on the queue wants FSBR but its time
1267 * limit has expired, set the next TD to interrupt on
1268 * completion before reactivating the QH. */
1269 urbp = list_entry(qh->queue.next, struct urb_priv, node);
1270 if (urbp->fsbr && qh->wait_expired) {
1271 struct uhci_td *td = list_entry(urbp->td_list.next,
1272 struct uhci_td, list);
1273
1274 td->status |= __cpu_to_le32(TD_CTRL_IOC);
1275 }
1276
1242 uhci_activate_qh(uhci, qh); 1277 uhci_activate_qh(uhci, qh);
1243 } 1278 }
1244 1279
@@ -1249,6 +1284,62 @@ restart:
1249} 1284}
1250 1285
1251/* 1286/*
1287 * Check for queues that have made some forward progress.
1288 * Returns 0 if the queue is not Isochronous, is ACTIVE, and
1289 * has not advanced since last examined; 1 otherwise.
1290 */
1291static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh)
1292{
1293 struct urb_priv *urbp = NULL;
1294 struct uhci_td *td;
1295 int ret = 1;
1296 unsigned status;
1297
1298 if (qh->type == USB_ENDPOINT_XFER_ISOC)
1299 return ret;
1300
1301 /* Treat an UNLINKING queue as though it hasn't advanced.
1302 * This is okay because reactivation will treat it as though
1303 * it has advanced, and if it is going to become IDLE then
1304 * this doesn't matter anyway. Furthermore it's possible
1305 * for an UNLINKING queue not to have any URBs at all, or
1306 * for its first URB not to have any TDs (if it was dequeued
1307 * just as it completed). So it's not easy in any case to
1308 * test whether such queues have advanced. */
1309 if (qh->state != QH_STATE_ACTIVE) {
1310 urbp = NULL;
1311 status = 0;
1312
1313 } else {
1314 urbp = list_entry(qh->queue.next, struct urb_priv, node);
1315 td = list_entry(urbp->td_list.next, struct uhci_td, list);
1316 status = td_status(td);
1317 if (!(status & TD_CTRL_ACTIVE)) {
1318
1319 /* We're okay, the queue has advanced */
1320 qh->wait_expired = 0;
1321 qh->advance_jiffies = jiffies;
1322 return ret;
1323 }
1324 ret = 0;
1325 }
1326
1327 /* The queue hasn't advanced; check for timeout */
1328 if (!qh->wait_expired && time_after(jiffies,
1329 qh->advance_jiffies + QH_WAIT_TIMEOUT)) {
1330 qh->wait_expired = 1;
1331
1332 /* If the current URB wants FSBR, unlink it temporarily
1333 * so that we can safely set the next TD to interrupt on
1334 * completion. That way we'll know as soon as the queue
1335 * starts moving again. */
1336 if (urbp && urbp->fsbr && !(status & TD_CTRL_IOC))
1337 uhci_unlink_qh(uhci, qh);
1338 }
1339 return ret;
1340}
1341
1342/*
1252 * Process events in the schedule, but only in one thread at a time 1343 * Process events in the schedule, but only in one thread at a time
1253 */ 1344 */
1254static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) 1345static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
@@ -1262,7 +1353,7 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
1262 return; 1353 return;
1263 } 1354 }
1264 uhci->scan_in_progress = 1; 1355 uhci->scan_in_progress = 1;
1265 rescan: 1356rescan:
1266 uhci->need_rescan = 0; 1357 uhci->need_rescan = 0;
1267 1358
1268 uhci_clear_next_interrupt(uhci); 1359 uhci_clear_next_interrupt(uhci);
@@ -1275,7 +1366,12 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
1275 while ((qh = uhci->next_qh) != uhci->skelqh[i]) { 1366 while ((qh = uhci->next_qh) != uhci->skelqh[i]) {
1276 uhci->next_qh = list_entry(qh->node.next, 1367 uhci->next_qh = list_entry(qh->node.next,
1277 struct uhci_qh, node); 1368 struct uhci_qh, node);
1278 uhci_scan_qh(uhci, qh, regs); 1369
1370 if (uhci_advance_check(uhci, qh)) {
1371 uhci_scan_qh(uhci, qh, regs);
1372 if (qh->state == QH_STATE_ACTIVE)
1373 uhci_qh_wants_fsbr(uhci, qh);
1374 }
1279 } 1375 }
1280 } 1376 }
1281 1377
@@ -1283,20 +1379,12 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
1283 goto rescan; 1379 goto rescan;
1284 uhci->scan_in_progress = 0; 1380 uhci->scan_in_progress = 0;
1285 1381
1382 if (uhci->fsbr_is_on && time_after(jiffies,
1383 uhci->fsbr_jiffies + FSBR_OFF_DELAY))
1384 uhci_fsbr_off(uhci);
1385
1286 if (list_empty(&uhci->skel_unlink_qh->node)) 1386 if (list_empty(&uhci->skel_unlink_qh->node))
1287 uhci_clear_next_interrupt(uhci); 1387 uhci_clear_next_interrupt(uhci);
1288 else 1388 else
1289 uhci_set_next_interrupt(uhci); 1389 uhci_set_next_interrupt(uhci);
1290} 1390}
1291
1292static void check_fsbr(struct uhci_hcd *uhci)
1293{
1294 /* For now, don't scan URBs for FSBR timeouts.
1295 * Add it back in later... */
1296
1297 /* Really disable FSBR */
1298 if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {
1299 uhci->fsbrtimeout = 0;
1300 uhci->skel_term_qh->link = UHCI_PTR_TERM;
1301 }
1302}