aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/uhci-q.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/uhci-q.c')
-rw-r--r--drivers/usb/host/uhci-q.c71
1 files changed, 51 insertions, 20 deletions
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
67static void uhci_qh_wants_fsbr(struct uhci_hcd *uhci, struct uhci_qh *qh) 67static 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
80static 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
340done:
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
1481done:
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;
1473rescan: 1499rescan:
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);