diff options
Diffstat (limited to 'drivers/usb/host/ehci-hcd.c')
| -rw-r--r-- | drivers/usb/host/ehci-hcd.c | 95 |
1 files changed, 58 insertions, 37 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index d63177a8eaea..5ac918591131 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2000-2004 by David Brownell | 2 | * Copyright (c) 2000-2004 by David Brownell |
| 3 | * | 3 | * |
| 4 | * This program is free software; you can redistribute it and/or modify it | 4 | * This program is free software; you can redistribute it and/or modify it |
| 5 | * under the terms of the GNU General Public License as published by the | 5 | * under the terms of the GNU General Public License as published by the |
| 6 | * Free Software Foundation; either version 2 of the License, or (at your | 6 | * Free Software Foundation; either version 2 of the License, or (at your |
| @@ -70,7 +70,7 @@ | |||
| 70 | * 2002-08-06 Handling for bulk and interrupt transfers is mostly shared; | 70 | * 2002-08-06 Handling for bulk and interrupt transfers is mostly shared; |
| 71 | * only scheduling is different, no arbitrary limitations. | 71 | * only scheduling is different, no arbitrary limitations. |
| 72 | * 2002-07-25 Sanity check PCI reads, mostly for better cardbus support, | 72 | * 2002-07-25 Sanity check PCI reads, mostly for better cardbus support, |
| 73 | * clean up HC run state handshaking. | 73 | * clean up HC run state handshaking. |
| 74 | * 2002-05-24 Preliminary FS/LS interrupts, using scheduling shortcuts | 74 | * 2002-05-24 Preliminary FS/LS interrupts, using scheduling shortcuts |
| 75 | * 2002-05-11 Clear TT errors for FS/LS ctrl/bulk. Fill in some other | 75 | * 2002-05-11 Clear TT errors for FS/LS ctrl/bulk. Fill in some other |
| 76 | * missing pieces: enabling 64bit dma, handoff from BIOS/SMM. | 76 | * missing pieces: enabling 64bit dma, handoff from BIOS/SMM. |
| @@ -111,7 +111,7 @@ static const char hcd_name [] = "ehci_hcd"; | |||
| 111 | #define EHCI_TUNE_MULT_TT 1 | 111 | #define EHCI_TUNE_MULT_TT 1 |
| 112 | #define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ | 112 | #define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ |
| 113 | 113 | ||
| 114 | #define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */ | 114 | #define EHCI_IAA_MSECS 10 /* arbitrary */ |
| 115 | #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ | 115 | #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ |
| 116 | #define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */ | 116 | #define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */ |
| 117 | #define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */ | 117 | #define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */ |
| @@ -254,6 +254,7 @@ static void ehci_quiesce (struct ehci_hcd *ehci) | |||
| 254 | 254 | ||
| 255 | /*-------------------------------------------------------------------------*/ | 255 | /*-------------------------------------------------------------------------*/ |
| 256 | 256 | ||
| 257 | static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs); | ||
| 257 | static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs); | 258 | static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs); |
| 258 | 259 | ||
| 259 | #include "ehci-hub.c" | 260 | #include "ehci-hub.c" |
| @@ -263,28 +264,39 @@ static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs); | |||
| 263 | 264 | ||
| 264 | /*-------------------------------------------------------------------------*/ | 265 | /*-------------------------------------------------------------------------*/ |
| 265 | 266 | ||
| 266 | static void ehci_watchdog (unsigned long param) | 267 | static void ehci_iaa_watchdog (unsigned long param) |
| 267 | { | 268 | { |
| 268 | struct ehci_hcd *ehci = (struct ehci_hcd *) param; | 269 | struct ehci_hcd *ehci = (struct ehci_hcd *) param; |
| 269 | unsigned long flags; | 270 | unsigned long flags; |
| 271 | u32 status; | ||
| 270 | 272 | ||
| 271 | spin_lock_irqsave (&ehci->lock, flags); | 273 | spin_lock_irqsave (&ehci->lock, flags); |
| 274 | WARN_ON(!ehci->reclaim); | ||
| 272 | 275 | ||
| 273 | /* lost IAA irqs wedge things badly; seen with a vt8235 */ | 276 | /* lost IAA irqs wedge things badly; seen first with a vt8235 */ |
| 274 | if (ehci->reclaim) { | 277 | if (ehci->reclaim) { |
| 275 | u32 status = readl (&ehci->regs->status); | 278 | status = readl (&ehci->regs->status); |
| 276 | |||
| 277 | if (status & STS_IAA) { | 279 | if (status & STS_IAA) { |
| 278 | ehci_vdbg (ehci, "lost IAA\n"); | 280 | ehci_vdbg (ehci, "lost IAA\n"); |
| 279 | COUNT (ehci->stats.lost_iaa); | 281 | COUNT (ehci->stats.lost_iaa); |
| 280 | writel (STS_IAA, &ehci->regs->status); | 282 | writel (STS_IAA, &ehci->regs->status); |
| 281 | ehci->reclaim_ready = 1; | 283 | end_unlink_async (ehci, NULL); |
| 282 | } | 284 | } |
| 283 | } | 285 | } |
| 284 | 286 | ||
| 285 | /* stop async processing after it's idled a bit */ | 287 | spin_unlock_irqrestore (&ehci->lock, flags); |
| 288 | } | ||
| 289 | |||
| 290 | static void ehci_watchdog (unsigned long param) | ||
| 291 | { | ||
| 292 | struct ehci_hcd *ehci = (struct ehci_hcd *) param; | ||
| 293 | unsigned long flags; | ||
| 294 | |||
| 295 | spin_lock_irqsave (&ehci->lock, flags); | ||
| 296 | |||
| 297 | /* stop async processing after it's idled a bit */ | ||
| 286 | if (test_bit (TIMER_ASYNC_OFF, &ehci->actions)) | 298 | if (test_bit (TIMER_ASYNC_OFF, &ehci->actions)) |
| 287 | start_unlink_async (ehci, ehci->async); | 299 | start_unlink_async (ehci, ehci->async); |
| 288 | 300 | ||
| 289 | /* ehci could run by timer, without IRQs ... */ | 301 | /* ehci could run by timer, without IRQs ... */ |
| 290 | ehci_work (ehci, NULL); | 302 | ehci_work (ehci, NULL); |
| @@ -292,21 +304,20 @@ static void ehci_watchdog (unsigned long param) | |||
| 292 | spin_unlock_irqrestore (&ehci->lock, flags); | 304 | spin_unlock_irqrestore (&ehci->lock, flags); |
| 293 | } | 305 | } |
| 294 | 306 | ||
| 295 | /* Reboot notifiers kick in for silicon on any bus (not just pci, etc). | 307 | /* ehci_shutdown kick in for silicon on any bus (not just pci, etc). |
| 296 | * This forcibly disables dma and IRQs, helping kexec and other cases | 308 | * This forcibly disables dma and IRQs, helping kexec and other cases |
| 297 | * where the next system software may expect clean state. | 309 | * where the next system software may expect clean state. |
| 298 | */ | 310 | */ |
| 299 | static int | 311 | static void |
| 300 | ehci_reboot (struct notifier_block *self, unsigned long code, void *null) | 312 | ehci_shutdown (struct usb_hcd *hcd) |
| 301 | { | 313 | { |
| 302 | struct ehci_hcd *ehci; | 314 | struct ehci_hcd *ehci; |
| 303 | 315 | ||
| 304 | ehci = container_of (self, struct ehci_hcd, reboot_notifier); | 316 | ehci = hcd_to_ehci (hcd); |
| 305 | (void) ehci_halt (ehci); | 317 | (void) ehci_halt (ehci); |
| 306 | 318 | ||
| 307 | /* make BIOS/etc use companion controller during reboot */ | 319 | /* make BIOS/etc use companion controller during reboot */ |
| 308 | writel (0, &ehci->regs->configured_flag); | 320 | writel (0, &ehci->regs->configured_flag); |
| 309 | return 0; | ||
| 310 | } | 321 | } |
| 311 | 322 | ||
| 312 | static void ehci_port_power (struct ehci_hcd *ehci, int is_on) | 323 | static void ehci_port_power (struct ehci_hcd *ehci, int is_on) |
| @@ -334,8 +345,6 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on) | |||
| 334 | static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) | 345 | static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) |
| 335 | { | 346 | { |
| 336 | timer_action_done (ehci, TIMER_IO_WATCHDOG); | 347 | timer_action_done (ehci, TIMER_IO_WATCHDOG); |
| 337 | if (ehci->reclaim_ready) | ||
| 338 | end_unlink_async (ehci, regs); | ||
| 339 | 348 | ||
| 340 | /* another CPU may drop ehci->lock during a schedule scan while | 349 | /* another CPU may drop ehci->lock during a schedule scan while |
| 341 | * it reports urb completions. this flag guards against bogus | 350 | * it reports urb completions. this flag guards against bogus |
| @@ -370,6 +379,7 @@ static void ehci_stop (struct usb_hcd *hcd) | |||
| 370 | 379 | ||
| 371 | /* no more interrupts ... */ | 380 | /* no more interrupts ... */ |
| 372 | del_timer_sync (&ehci->watchdog); | 381 | del_timer_sync (&ehci->watchdog); |
| 382 | del_timer_sync (&ehci->iaa_watchdog); | ||
| 373 | 383 | ||
| 374 | spin_lock_irq(&ehci->lock); | 384 | spin_lock_irq(&ehci->lock); |
| 375 | if (HC_IS_RUNNING (hcd->state)) | 385 | if (HC_IS_RUNNING (hcd->state)) |
| @@ -381,7 +391,6 @@ static void ehci_stop (struct usb_hcd *hcd) | |||
| 381 | 391 | ||
| 382 | /* let companion controllers work when we aren't */ | 392 | /* let companion controllers work when we aren't */ |
| 383 | writel (0, &ehci->regs->configured_flag); | 393 | writel (0, &ehci->regs->configured_flag); |
| 384 | unregister_reboot_notifier (&ehci->reboot_notifier); | ||
| 385 | 394 | ||
| 386 | remove_debug_files (ehci); | 395 | remove_debug_files (ehci); |
| 387 | 396 | ||
| @@ -417,6 +426,10 @@ static int ehci_init(struct usb_hcd *hcd) | |||
| 417 | ehci->watchdog.function = ehci_watchdog; | 426 | ehci->watchdog.function = ehci_watchdog; |
| 418 | ehci->watchdog.data = (unsigned long) ehci; | 427 | ehci->watchdog.data = (unsigned long) ehci; |
| 419 | 428 | ||
| 429 | init_timer(&ehci->iaa_watchdog); | ||
| 430 | ehci->iaa_watchdog.function = ehci_iaa_watchdog; | ||
| 431 | ehci->iaa_watchdog.data = (unsigned long) ehci; | ||
| 432 | |||
| 420 | /* | 433 | /* |
| 421 | * hw default: 1K periodic list heads, one per frame. | 434 | * hw default: 1K periodic list heads, one per frame. |
| 422 | * periodic_size can shrink by USBCMD update if hcc_params allows. | 435 | * periodic_size can shrink by USBCMD update if hcc_params allows. |
| @@ -427,13 +440,12 @@ static int ehci_init(struct usb_hcd *hcd) | |||
| 427 | 440 | ||
| 428 | /* controllers may cache some of the periodic schedule ... */ | 441 | /* controllers may cache some of the periodic schedule ... */ |
| 429 | hcc_params = readl(&ehci->caps->hcc_params); | 442 | hcc_params = readl(&ehci->caps->hcc_params); |
| 430 | if (HCC_ISOC_CACHE(hcc_params)) // full frame cache | 443 | if (HCC_ISOC_CACHE(hcc_params)) // full frame cache |
| 431 | ehci->i_thresh = 8; | 444 | ehci->i_thresh = 8; |
| 432 | else // N microframes cached | 445 | else // N microframes cached |
| 433 | ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); | 446 | ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); |
| 434 | 447 | ||
| 435 | ehci->reclaim = NULL; | 448 | ehci->reclaim = NULL; |
| 436 | ehci->reclaim_ready = 0; | ||
| 437 | ehci->next_uframe = -1; | 449 | ehci->next_uframe = -1; |
| 438 | 450 | ||
| 439 | /* | 451 | /* |
| @@ -483,9 +495,6 @@ static int ehci_init(struct usb_hcd *hcd) | |||
| 483 | } | 495 | } |
| 484 | ehci->command = temp; | 496 | ehci->command = temp; |
| 485 | 497 | ||
| 486 | ehci->reboot_notifier.notifier_call = ehci_reboot; | ||
| 487 | register_reboot_notifier(&ehci->reboot_notifier); | ||
| 488 | |||
| 489 | return 0; | 498 | return 0; |
| 490 | } | 499 | } |
| 491 | 500 | ||
| @@ -499,7 +508,6 @@ static int ehci_run (struct usb_hcd *hcd) | |||
| 499 | 508 | ||
| 500 | /* EHCI spec section 4.1 */ | 509 | /* EHCI spec section 4.1 */ |
| 501 | if ((retval = ehci_reset(ehci)) != 0) { | 510 | if ((retval = ehci_reset(ehci)) != 0) { |
| 502 | unregister_reboot_notifier(&ehci->reboot_notifier); | ||
| 503 | ehci_mem_cleanup(ehci); | 511 | ehci_mem_cleanup(ehci); |
| 504 | return retval; | 512 | return retval; |
| 505 | } | 513 | } |
| @@ -611,7 +619,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs) | |||
| 611 | /* complete the unlinking of some qh [4.15.2.3] */ | 619 | /* complete the unlinking of some qh [4.15.2.3] */ |
| 612 | if (status & STS_IAA) { | 620 | if (status & STS_IAA) { |
| 613 | COUNT (ehci->stats.reclaim); | 621 | COUNT (ehci->stats.reclaim); |
| 614 | ehci->reclaim_ready = 1; | 622 | end_unlink_async (ehci, regs); |
| 615 | bh = 1; | 623 | bh = 1; |
| 616 | } | 624 | } |
| 617 | 625 | ||
| @@ -715,10 +723,14 @@ static int ehci_urb_enqueue ( | |||
| 715 | 723 | ||
| 716 | static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) | 724 | static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) |
| 717 | { | 725 | { |
| 718 | /* if we need to use IAA and it's busy, defer */ | 726 | // BUG_ON(qh->qh_state != QH_STATE_LINKED); |
| 719 | if (qh->qh_state == QH_STATE_LINKED | 727 | |
| 720 | && ehci->reclaim | 728 | /* failfast */ |
| 721 | && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) { | 729 | if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) |
| 730 | end_unlink_async (ehci, NULL); | ||
| 731 | |||
| 732 | /* defer till later if busy */ | ||
| 733 | else if (ehci->reclaim) { | ||
| 722 | struct ehci_qh *last; | 734 | struct ehci_qh *last; |
| 723 | 735 | ||
| 724 | for (last = ehci->reclaim; | 736 | for (last = ehci->reclaim; |
| @@ -728,12 +740,8 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
| 728 | qh->qh_state = QH_STATE_UNLINK_WAIT; | 740 | qh->qh_state = QH_STATE_UNLINK_WAIT; |
| 729 | last->reclaim = qh; | 741 | last->reclaim = qh; |
| 730 | 742 | ||
| 731 | /* bypass IAA if the hc can't care */ | 743 | /* start IAA cycle */ |
| 732 | } else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim) | 744 | } else |
| 733 | end_unlink_async (ehci, NULL); | ||
| 734 | |||
| 735 | /* something else might have unlinked the qh by now */ | ||
| 736 | if (qh->qh_state == QH_STATE_LINKED) | ||
| 737 | start_unlink_async (ehci, qh); | 745 | start_unlink_async (ehci, qh); |
| 738 | } | 746 | } |
| 739 | 747 | ||
| @@ -755,7 +763,19 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) | |||
| 755 | qh = (struct ehci_qh *) urb->hcpriv; | 763 | qh = (struct ehci_qh *) urb->hcpriv; |
| 756 | if (!qh) | 764 | if (!qh) |
| 757 | break; | 765 | break; |
| 758 | unlink_async (ehci, qh); | 766 | switch (qh->qh_state) { |
| 767 | case QH_STATE_LINKED: | ||
| 768 | case QH_STATE_COMPLETING: | ||
| 769 | unlink_async (ehci, qh); | ||
| 770 | break; | ||
| 771 | case QH_STATE_UNLINK: | ||
| 772 | case QH_STATE_UNLINK_WAIT: | ||
| 773 | /* already started */ | ||
| 774 | break; | ||
| 775 | case QH_STATE_IDLE: | ||
| 776 | WARN_ON(1); | ||
| 777 | break; | ||
| 778 | } | ||
| 759 | break; | 779 | break; |
| 760 | 780 | ||
| 761 | case PIPE_INTERRUPT: | 781 | case PIPE_INTERRUPT: |
| @@ -847,6 +867,7 @@ rescan: | |||
| 847 | unlink_async (ehci, qh); | 867 | unlink_async (ehci, qh); |
| 848 | /* FALL THROUGH */ | 868 | /* FALL THROUGH */ |
| 849 | case QH_STATE_UNLINK: /* wait for hw to finish? */ | 869 | case QH_STATE_UNLINK: /* wait for hw to finish? */ |
| 870 | case QH_STATE_UNLINK_WAIT: | ||
| 850 | idle_timeout: | 871 | idle_timeout: |
| 851 | spin_unlock_irqrestore (&ehci->lock, flags); | 872 | spin_unlock_irqrestore (&ehci->lock, flags); |
| 852 | schedule_timeout_uninterruptible(1); | 873 | schedule_timeout_uninterruptible(1); |
