diff options
Diffstat (limited to 'drivers/usb/host/uhci-q.c')
-rw-r--r-- | drivers/usb/host/uhci-q.c | 71 |
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 | ||
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); |