aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/host/ohci-hcd.c36
-rw-r--r--drivers/usb/host/ohci.h1
2 files changed, 35 insertions, 2 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index aba8f19eae4d..46987735a2e3 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -72,7 +72,7 @@
72static const char hcd_name [] = "ohci_hcd"; 72static const char hcd_name [] = "ohci_hcd";
73 73
74#define STATECHANGE_DELAY msecs_to_jiffies(300) 74#define STATECHANGE_DELAY msecs_to_jiffies(300)
75#define IO_WATCHDOG_DELAY msecs_to_jiffies(250) 75#define IO_WATCHDOG_DELAY msecs_to_jiffies(250)
76 76
77#include "ohci.h" 77#include "ohci.h"
78#include "pci-quirks.h" 78#include "pci-quirks.h"
@@ -230,9 +230,11 @@ static int ohci_urb_enqueue (
230 230
231 /* Start up the I/O watchdog timer, if it's not running */ 231 /* Start up the I/O watchdog timer, if it's not running */
232 if (!timer_pending(&ohci->io_watchdog) && 232 if (!timer_pending(&ohci->io_watchdog) &&
233 list_empty(&ohci->eds_in_use)) 233 list_empty(&ohci->eds_in_use)) {
234 ohci->prev_frame_no = ohci_frame_no(ohci);
234 mod_timer(&ohci->io_watchdog, 235 mod_timer(&ohci->io_watchdog,
235 jiffies + IO_WATCHDOG_DELAY); 236 jiffies + IO_WATCHDOG_DELAY);
237 }
236 list_add(&ed->in_use_list, &ohci->eds_in_use); 238 list_add(&ed->in_use_list, &ohci->eds_in_use);
237 239
238 if (ed->type == PIPE_ISOCHRONOUS) { 240 if (ed->type == PIPE_ISOCHRONOUS) {
@@ -727,6 +729,7 @@ static void io_watchdog_func(unsigned long _ohci)
727 u32 head; 729 u32 head;
728 struct ed *ed; 730 struct ed *ed;
729 struct td *td, *td_start, *td_next; 731 struct td *td, *td_start, *td_next;
732 unsigned frame_no;
730 unsigned long flags; 733 unsigned long flags;
731 734
732 spin_lock_irqsave(&ohci->lock, flags); 735 spin_lock_irqsave(&ohci->lock, flags);
@@ -742,6 +745,7 @@ static void io_watchdog_func(unsigned long _ohci)
742 if (!(status & OHCI_INTR_WDH) && ohci->wdh_cnt == ohci->prev_wdh_cnt) { 745 if (!(status & OHCI_INTR_WDH) && ohci->wdh_cnt == ohci->prev_wdh_cnt) {
743 if (ohci->prev_donehead) { 746 if (ohci->prev_donehead) {
744 ohci_err(ohci, "HcDoneHead not written back; disabled\n"); 747 ohci_err(ohci, "HcDoneHead not written back; disabled\n");
748 died:
745 usb_hc_died(ohci_to_hcd(ohci)); 749 usb_hc_died(ohci_to_hcd(ohci));
746 ohci_dump(ohci); 750 ohci_dump(ohci);
747 ohci_shutdown(ohci_to_hcd(ohci)); 751 ohci_shutdown(ohci_to_hcd(ohci));
@@ -802,7 +806,35 @@ static void io_watchdog_func(unsigned long _ohci)
802 ohci_work(ohci); 806 ohci_work(ohci);
803 807
804 if (ohci->rh_state == OHCI_RH_RUNNING) { 808 if (ohci->rh_state == OHCI_RH_RUNNING) {
809
810 /*
811 * Sometimes a controller just stops working. We can tell
812 * by checking that the frame counter has advanced since
813 * the last time we ran.
814 *
815 * But be careful: Some controllers violate the spec by
816 * stopping their frame counter when no ports are active.
817 */
818 frame_no = ohci_frame_no(ohci);
819 if (frame_no == ohci->prev_frame_no) {
820 int active_cnt = 0;
821 int i;
822 unsigned tmp;
823
824 for (i = 0; i < ohci->num_ports; ++i) {
825 tmp = roothub_portstatus(ohci, i);
826 /* Enabled and not suspended? */
827 if ((tmp & RH_PS_PES) && !(tmp & RH_PS_PSS))
828 ++active_cnt;
829 }
830
831 if (active_cnt > 0) {
832 ohci_err(ohci, "frame counter not updating; disabled\n");
833 goto died;
834 }
835 }
805 if (!list_empty(&ohci->eds_in_use)) { 836 if (!list_empty(&ohci->eds_in_use)) {
837 ohci->prev_frame_no = frame_no;
806 ohci->prev_wdh_cnt = ohci->wdh_cnt; 838 ohci->prev_wdh_cnt = ohci->wdh_cnt;
807 ohci->prev_donehead = ohci_readl(ohci, 839 ohci->prev_donehead = ohci_readl(ohci,
808 &ohci->regs->donehead); 840 &ohci->regs->donehead);
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 0548f5ca18e2..59f424567a8d 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -421,6 +421,7 @@ struct ohci_hcd {
421 421
422 // there are also chip quirks/bugs in init logic 422 // there are also chip quirks/bugs in init logic
423 423
424 unsigned prev_frame_no;
424 unsigned wdh_cnt, prev_wdh_cnt; 425 unsigned wdh_cnt, prev_wdh_cnt;
425 u32 prev_donehead; 426 u32 prev_donehead;
426 struct timer_list io_watchdog; 427 struct timer_list io_watchdog;