diff options
Diffstat (limited to 'drivers/usb/host/ehci-q.c')
-rw-r--r-- | drivers/usb/host/ehci-q.c | 27 |
1 files changed, 9 insertions, 18 deletions
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index fe99895fb098..42abd0f603bf 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c | |||
@@ -315,7 +315,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
315 | int stopped; | 315 | int stopped; |
316 | unsigned count = 0; | 316 | unsigned count = 0; |
317 | u8 state; | 317 | u8 state; |
318 | const __le32 halt = HALT_BIT(ehci); | ||
319 | struct ehci_qh_hw *hw = qh->hw; | 318 | struct ehci_qh_hw *hw = qh->hw; |
320 | 319 | ||
321 | if (unlikely (list_empty (&qh->qtd_list))) | 320 | if (unlikely (list_empty (&qh->qtd_list))) |
@@ -422,7 +421,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
422 | && !(qtd->hw_alt_next | 421 | && !(qtd->hw_alt_next |
423 | & EHCI_LIST_END(ehci))) { | 422 | & EHCI_LIST_END(ehci))) { |
424 | stopped = 1; | 423 | stopped = 1; |
425 | goto halt; | ||
426 | } | 424 | } |
427 | 425 | ||
428 | /* stop scanning when we reach qtds the hc is using */ | 426 | /* stop scanning when we reach qtds the hc is using */ |
@@ -456,16 +454,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
456 | */ | 454 | */ |
457 | ehci_clear_tt_buffer(ehci, qh, urb, token); | 455 | ehci_clear_tt_buffer(ehci, qh, urb, token); |
458 | } | 456 | } |
459 | |||
460 | /* force halt for unlinked or blocked qh, so we'll | ||
461 | * patch the qh later and so that completions can't | ||
462 | * activate it while we "know" it's stopped. | ||
463 | */ | ||
464 | if ((halt & hw->hw_token) == 0) { | ||
465 | halt: | ||
466 | hw->hw_token |= halt; | ||
467 | wmb (); | ||
468 | } | ||
469 | } | 457 | } |
470 | 458 | ||
471 | /* unless we already know the urb's status, collect qtd status | 459 | /* unless we already know the urb's status, collect qtd status |
@@ -1259,24 +1247,27 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
1259 | 1247 | ||
1260 | static void scan_async (struct ehci_hcd *ehci) | 1248 | static void scan_async (struct ehci_hcd *ehci) |
1261 | { | 1249 | { |
1250 | bool stopped; | ||
1262 | struct ehci_qh *qh; | 1251 | struct ehci_qh *qh; |
1263 | enum ehci_timer_action action = TIMER_IO_WATCHDOG; | 1252 | enum ehci_timer_action action = TIMER_IO_WATCHDOG; |
1264 | 1253 | ||
1265 | ehci->stamp = ehci_readl(ehci, &ehci->regs->frame_index); | 1254 | ehci->stamp = ehci_readl(ehci, &ehci->regs->frame_index); |
1266 | timer_action_done (ehci, TIMER_ASYNC_SHRINK); | 1255 | timer_action_done (ehci, TIMER_ASYNC_SHRINK); |
1267 | rescan: | 1256 | rescan: |
1257 | stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state); | ||
1268 | qh = ehci->async->qh_next.qh; | 1258 | qh = ehci->async->qh_next.qh; |
1269 | if (likely (qh != NULL)) { | 1259 | if (likely (qh != NULL)) { |
1270 | do { | 1260 | do { |
1271 | /* clean any finished work for this qh */ | 1261 | /* clean any finished work for this qh */ |
1272 | if (!list_empty (&qh->qtd_list) | 1262 | if (!list_empty(&qh->qtd_list) && (stopped || |
1273 | && qh->stamp != ehci->stamp) { | 1263 | qh->stamp != ehci->stamp)) { |
1274 | int temp; | 1264 | int temp; |
1275 | 1265 | ||
1276 | /* unlinks could happen here; completion | 1266 | /* unlinks could happen here; completion |
1277 | * reporting drops the lock. rescan using | 1267 | * reporting drops the lock. rescan using |
1278 | * the latest schedule, but don't rescan | 1268 | * the latest schedule, but don't rescan |
1279 | * qhs we already finished (no looping). | 1269 | * qhs we already finished (no looping) |
1270 | * unless the controller is stopped. | ||
1280 | */ | 1271 | */ |
1281 | qh = qh_get (qh); | 1272 | qh = qh_get (qh); |
1282 | qh->stamp = ehci->stamp; | 1273 | qh->stamp = ehci->stamp; |
@@ -1297,9 +1288,9 @@ rescan: | |||
1297 | */ | 1288 | */ |
1298 | if (list_empty(&qh->qtd_list) | 1289 | if (list_empty(&qh->qtd_list) |
1299 | && qh->qh_state == QH_STATE_LINKED) { | 1290 | && qh->qh_state == QH_STATE_LINKED) { |
1300 | if (!ehci->reclaim | 1291 | if (!ehci->reclaim && (stopped || |
1301 | && ((ehci->stamp - qh->stamp) & 0x1fff) | 1292 | ((ehci->stamp - qh->stamp) & 0x1fff) |
1302 | >= (EHCI_SHRINK_FRAMES * 8)) | 1293 | >= EHCI_SHRINK_FRAMES * 8)) |
1303 | start_unlink_async(ehci, qh); | 1294 | start_unlink_async(ehci, qh); |
1304 | else | 1295 | else |
1305 | action = TIMER_ASYNC_SHRINK; | 1296 | action = TIMER_ASYNC_SHRINK; |