diff options
-rw-r--r-- | drivers/usb/host/uhci-hcd.c | 5 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hcd.h | 8 | ||||
-rw-r--r-- | drivers/usb/host/uhci-q.c | 71 |
3 files changed, 59 insertions, 25 deletions
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 025b969f95e8..7b48567622ef 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c | |||
@@ -497,9 +497,9 @@ static int uhci_start(struct usb_hcd *hcd) | |||
497 | hcd->uses_new_polling = 1; | 497 | hcd->uses_new_polling = 1; |
498 | 498 | ||
499 | spin_lock_init(&uhci->lock); | 499 | spin_lock_init(&uhci->lock); |
500 | 500 | setup_timer(&uhci->fsbr_timer, uhci_fsbr_timeout, | |
501 | (unsigned long) uhci); | ||
501 | INIT_LIST_HEAD(&uhci->idle_qh_list); | 502 | INIT_LIST_HEAD(&uhci->idle_qh_list); |
502 | |||
503 | init_waitqueue_head(&uhci->waitqh); | 503 | init_waitqueue_head(&uhci->waitqh); |
504 | 504 | ||
505 | if (DEBUG_CONFIGURED) { | 505 | if (DEBUG_CONFIGURED) { |
@@ -675,6 +675,7 @@ static void uhci_stop(struct usb_hcd *hcd) | |||
675 | uhci_scan_schedule(uhci, NULL); | 675 | uhci_scan_schedule(uhci, NULL); |
676 | spin_unlock_irq(&uhci->lock); | 676 | spin_unlock_irq(&uhci->lock); |
677 | 677 | ||
678 | del_timer_sync(&uhci->fsbr_timer); | ||
678 | release_uhci(uhci); | 679 | release_uhci(uhci); |
679 | } | 680 | } |
680 | 681 | ||
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 619d704f4e8f..108e3de2dc26 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h | |||
@@ -86,7 +86,7 @@ | |||
86 | 86 | ||
87 | /* When no queues need Full-Speed Bandwidth Reclamation, | 87 | /* When no queues need Full-Speed Bandwidth Reclamation, |
88 | * delay this long before turning FSBR off */ | 88 | * delay this long before turning FSBR off */ |
89 | #define FSBR_OFF_DELAY msecs_to_jiffies(400) | 89 | #define FSBR_OFF_DELAY msecs_to_jiffies(10) |
90 | 90 | ||
91 | /* If a queue hasn't advanced after this much time, assume it is stuck */ | 91 | /* If a queue hasn't advanced after this much time, assume it is stuck */ |
92 | #define QH_WAIT_TIMEOUT msecs_to_jiffies(200) | 92 | #define QH_WAIT_TIMEOUT msecs_to_jiffies(200) |
@@ -382,8 +382,6 @@ struct uhci_hcd { | |||
382 | __le32 *frame; | 382 | __le32 *frame; |
383 | void **frame_cpu; /* CPU's frame list */ | 383 | void **frame_cpu; /* CPU's frame list */ |
384 | 384 | ||
385 | unsigned long fsbr_jiffies; /* Time when FSBR was last wanted */ | ||
386 | |||
387 | enum uhci_rh_state rh_state; | 385 | enum uhci_rh_state rh_state; |
388 | unsigned long auto_stop_time; /* When to AUTO_STOP */ | 386 | unsigned long auto_stop_time; /* When to AUTO_STOP */ |
389 | 387 | ||
@@ -400,6 +398,10 @@ struct uhci_hcd { | |||
400 | need to be polled */ | 398 | need to be polled */ |
401 | unsigned int is_initialized:1; /* Data structure is usable */ | 399 | unsigned int is_initialized:1; /* Data structure is usable */ |
402 | unsigned int fsbr_is_on:1; /* FSBR is turned on */ | 400 | unsigned int fsbr_is_on:1; /* FSBR is turned on */ |
401 | unsigned int fsbr_is_wanted:1; /* Does any URB want FSBR? */ | ||
402 | unsigned int fsbr_expiring:1; /* FSBR is timing out */ | ||
403 | |||
404 | struct timer_list fsbr_timer; /* For turning off FBSR */ | ||
403 | 405 | ||
404 | /* Support for port suspend/resume/reset */ | 406 | /* Support for port suspend/resume/reset */ |
405 | unsigned long port_c_suspend; /* Bit-arrays of ports */ | 407 | unsigned long port_c_suspend; /* Bit-arrays of ports */ |
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index b173d914d748..c9d72ac0a1d7 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c | |||
@@ -64,16 +64,30 @@ static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb) | |||
64 | urbp->fsbr = 1; | 64 | urbp->fsbr = 1; |
65 | } | 65 | } |
66 | 66 | ||
67 | static void uhci_qh_wants_fsbr(struct uhci_hcd *uhci, struct uhci_qh *qh) | 67 | static void uhci_urbp_wants_fsbr(struct uhci_hcd *uhci, struct urb_priv *urbp) |
68 | { | 68 | { |
69 | struct urb_priv *urbp = | ||
70 | list_entry(qh->queue.next, struct urb_priv, node); | ||
71 | |||
72 | if (urbp->fsbr) { | 69 | if (urbp->fsbr) { |
73 | uhci->fsbr_jiffies = jiffies; | 70 | uhci->fsbr_is_wanted = 1; |
74 | if (!uhci->fsbr_is_on) | 71 | if (!uhci->fsbr_is_on) |
75 | uhci_fsbr_on(uhci); | 72 | uhci_fsbr_on(uhci); |
73 | else if (uhci->fsbr_expiring) { | ||
74 | uhci->fsbr_expiring = 0; | ||
75 | del_timer(&uhci->fsbr_timer); | ||
76 | } | ||
77 | } | ||
78 | } | ||
79 | |||
80 | static void uhci_fsbr_timeout(unsigned long _uhci) | ||
81 | { | ||
82 | struct uhci_hcd *uhci = (struct uhci_hcd *) _uhci; | ||
83 | unsigned long flags; | ||
84 | |||
85 | spin_lock_irqsave(&uhci->lock, flags); | ||
86 | if (uhci->fsbr_expiring) { | ||
87 | uhci->fsbr_expiring = 0; | ||
88 | uhci_fsbr_off(uhci); | ||
76 | } | 89 | } |
90 | spin_unlock_irqrestore(&uhci->lock, flags); | ||
77 | } | 91 | } |
78 | 92 | ||
79 | 93 | ||
@@ -287,7 +301,7 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh, | |||
287 | if (qh->type == USB_ENDPOINT_XFER_ISOC) { | 301 | if (qh->type == USB_ENDPOINT_XFER_ISOC) { |
288 | ret = (uhci->frame_number + uhci->is_stopped != | 302 | ret = (uhci->frame_number + uhci->is_stopped != |
289 | qh->unlink_frame); | 303 | qh->unlink_frame); |
290 | return ret; | 304 | goto done; |
291 | } | 305 | } |
292 | 306 | ||
293 | /* If the URB isn't first on its queue, adjust the link pointer | 307 | /* If the URB isn't first on its queue, adjust the link pointer |
@@ -304,24 +318,26 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh, | |||
304 | td = list_entry(urbp->td_list.prev, struct uhci_td, | 318 | td = list_entry(urbp->td_list.prev, struct uhci_td, |
305 | list); | 319 | list); |
306 | ptd->link = td->link; | 320 | ptd->link = td->link; |
307 | return ret; | 321 | goto done; |
308 | } | 322 | } |
309 | 323 | ||
310 | /* If the QH element pointer is UHCI_PTR_TERM then then currently | 324 | /* If the QH element pointer is UHCI_PTR_TERM then then currently |
311 | * executing URB has already been unlinked, so this one isn't it. */ | 325 | * executing URB has already been unlinked, so this one isn't it. */ |
312 | if (qh_element(qh) == UHCI_PTR_TERM) | 326 | if (qh_element(qh) == UHCI_PTR_TERM) |
313 | return ret; | 327 | goto done; |
314 | qh->element = UHCI_PTR_TERM; | 328 | qh->element = UHCI_PTR_TERM; |
315 | 329 | ||
316 | /* Control pipes have to worry about toggles */ | 330 | /* Control pipes have to worry about toggles */ |
317 | if (qh->type == USB_ENDPOINT_XFER_CONTROL) | 331 | if (qh->type == USB_ENDPOINT_XFER_CONTROL) |
318 | return ret; | 332 | goto done; |
319 | 333 | ||
320 | /* Save the next toggle value */ | 334 | /* Save the next toggle value */ |
321 | WARN_ON(list_empty(&urbp->td_list)); | 335 | WARN_ON(list_empty(&urbp->td_list)); |
322 | td = list_entry(urbp->td_list.next, struct uhci_td, list); | 336 | td = list_entry(urbp->td_list.next, struct uhci_td, list); |
323 | qh->needs_fixup = 1; | 337 | qh->needs_fixup = 1; |
324 | qh->initial_toggle = uhci_toggle(td_token(td)); | 338 | qh->initial_toggle = uhci_toggle(td_token(td)); |
339 | |||
340 | done: | ||
325 | return ret; | 341 | return ret; |
326 | } | 342 | } |
327 | 343 | ||
@@ -1175,7 +1191,7 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, | |||
1175 | * queue isn't stopped. */ | 1191 | * queue isn't stopped. */ |
1176 | if (qh->queue.next == &urbp->node && !qh->is_stopped) { | 1192 | if (qh->queue.next == &urbp->node && !qh->is_stopped) { |
1177 | uhci_activate_qh(uhci, qh); | 1193 | uhci_activate_qh(uhci, qh); |
1178 | uhci_qh_wants_fsbr(uhci, qh); | 1194 | uhci_urbp_wants_fsbr(uhci, urbp); |
1179 | } | 1195 | } |
1180 | goto done; | 1196 | goto done; |
1181 | 1197 | ||
@@ -1404,7 +1420,7 @@ static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh) | |||
1404 | unsigned status; | 1420 | unsigned status; |
1405 | 1421 | ||
1406 | if (qh->type == USB_ENDPOINT_XFER_ISOC) | 1422 | if (qh->type == USB_ENDPOINT_XFER_ISOC) |
1407 | return ret; | 1423 | goto done; |
1408 | 1424 | ||
1409 | /* Treat an UNLINKING queue as though it hasn't advanced. | 1425 | /* Treat an UNLINKING queue as though it hasn't advanced. |
1410 | * This is okay because reactivation will treat it as though | 1426 | * This is okay because reactivation will treat it as though |
@@ -1427,21 +1443,24 @@ static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh) | |||
1427 | /* We're okay, the queue has advanced */ | 1443 | /* We're okay, the queue has advanced */ |
1428 | qh->wait_expired = 0; | 1444 | qh->wait_expired = 0; |
1429 | qh->advance_jiffies = jiffies; | 1445 | qh->advance_jiffies = jiffies; |
1430 | return ret; | 1446 | goto done; |
1431 | } | 1447 | } |
1432 | ret = 0; | 1448 | ret = 0; |
1433 | } | 1449 | } |
1434 | 1450 | ||
1435 | /* The queue hasn't advanced; check for timeout */ | 1451 | /* The queue hasn't advanced; check for timeout */ |
1436 | if (!qh->wait_expired && time_after(jiffies, | 1452 | if (qh->wait_expired) |
1437 | qh->advance_jiffies + QH_WAIT_TIMEOUT)) { | 1453 | goto done; |
1454 | |||
1455 | if (time_after(jiffies, qh->advance_jiffies + QH_WAIT_TIMEOUT)) { | ||
1438 | 1456 | ||
1439 | /* Detect the Intel bug and work around it */ | 1457 | /* Detect the Intel bug and work around it */ |
1440 | if (qh->post_td && qh_element(qh) == | 1458 | if (qh->post_td && qh_element(qh) == |
1441 | cpu_to_le32(qh->post_td->dma_handle)) { | 1459 | cpu_to_le32(qh->post_td->dma_handle)) { |
1442 | qh->element = qh->post_td->link; | 1460 | qh->element = qh->post_td->link; |
1443 | qh->advance_jiffies = jiffies; | 1461 | qh->advance_jiffies = jiffies; |
1444 | return 1; | 1462 | ret = 1; |
1463 | goto done; | ||
1445 | } | 1464 | } |
1446 | 1465 | ||
1447 | qh->wait_expired = 1; | 1466 | qh->wait_expired = 1; |
@@ -1452,7 +1471,14 @@ static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh) | |||
1452 | * starts moving again. */ | 1471 | * starts moving again. */ |
1453 | if (urbp && urbp->fsbr && !(status & TD_CTRL_IOC)) | 1472 | if (urbp && urbp->fsbr && !(status & TD_CTRL_IOC)) |
1454 | uhci_unlink_qh(uhci, qh); | 1473 | uhci_unlink_qh(uhci, qh); |
1474 | |||
1475 | } else { | ||
1476 | /* Unmoving but not-yet-expired queues keep FSBR alive */ | ||
1477 | if (urbp) | ||
1478 | uhci_urbp_wants_fsbr(uhci, urbp); | ||
1455 | } | 1479 | } |
1480 | |||
1481 | done: | ||
1456 | return ret; | 1482 | return ret; |
1457 | } | 1483 | } |
1458 | 1484 | ||
@@ -1472,6 +1498,7 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) | |||
1472 | uhci->scan_in_progress = 1; | 1498 | uhci->scan_in_progress = 1; |
1473 | rescan: | 1499 | rescan: |
1474 | uhci->need_rescan = 0; | 1500 | uhci->need_rescan = 0; |
1501 | uhci->fsbr_is_wanted = 0; | ||
1475 | 1502 | ||
1476 | uhci_clear_next_interrupt(uhci); | 1503 | uhci_clear_next_interrupt(uhci); |
1477 | uhci_get_current_frame_number(uhci); | 1504 | uhci_get_current_frame_number(uhci); |
@@ -1487,8 +1514,10 @@ rescan: | |||
1487 | 1514 | ||
1488 | if (uhci_advance_check(uhci, qh)) { | 1515 | if (uhci_advance_check(uhci, qh)) { |
1489 | uhci_scan_qh(uhci, qh, regs); | 1516 | uhci_scan_qh(uhci, qh, regs); |
1490 | if (qh->state == QH_STATE_ACTIVE) | 1517 | if (qh->state == QH_STATE_ACTIVE) { |
1491 | uhci_qh_wants_fsbr(uhci, qh); | 1518 | uhci_urbp_wants_fsbr(uhci, |
1519 | list_entry(qh->queue.next, struct urb_priv, node)); | ||
1520 | } | ||
1492 | } | 1521 | } |
1493 | } | 1522 | } |
1494 | } | 1523 | } |
@@ -1498,9 +1527,11 @@ rescan: | |||
1498 | goto rescan; | 1527 | goto rescan; |
1499 | uhci->scan_in_progress = 0; | 1528 | uhci->scan_in_progress = 0; |
1500 | 1529 | ||
1501 | if (uhci->fsbr_is_on && time_after(jiffies, | 1530 | if (uhci->fsbr_is_on && !uhci->fsbr_is_wanted && |
1502 | uhci->fsbr_jiffies + FSBR_OFF_DELAY)) | 1531 | !uhci->fsbr_expiring) { |
1503 | uhci_fsbr_off(uhci); | 1532 | uhci->fsbr_expiring = 1; |
1533 | mod_timer(&uhci->fsbr_timer, jiffies + FSBR_OFF_DELAY); | ||
1534 | } | ||
1504 | 1535 | ||
1505 | if (list_empty(&uhci->skel_unlink_qh->node)) | 1536 | if (list_empty(&uhci->skel_unlink_qh->node)) |
1506 | uhci_clear_next_interrupt(uhci); | 1537 | uhci_clear_next_interrupt(uhci); |