drivers/usb/host/ohci-hcd.c | 65 ++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/host/ohci-q.c | 10 ++++++ 2 files changed, 74 insertions(+), 1 deletion(-) Index: usb-3.10/drivers/usb/host/ohci-hcd.c =================================================================== --- usb-3.10.orig/drivers/usb/host/ohci-hcd.c +++ usb-3.10/drivers/usb/host/ohci-hcd.c @@ -81,6 +81,66 @@ static const char hcd_name [] = "ohci_hc static void ohci_dump (struct ohci_hcd *ohci, int verbose); static void ohci_stop (struct usb_hcd *hcd); +#include + +static struct ohci_hcd *alan_ohci; +static struct ed *alan_ed; +static struct hrtimer alan_hrtimer; +static int alan_irq_cnt, alan_wdh_cnt, alan_iso_cnt; + +static enum hrtimer_restart alan_hrtimer_func(struct hrtimer *t) +{ + ktime_t timeout; + struct ed *ed; + struct td *td; + u16 cf, sf, tdPSW; + + ed = ACCESS_ONCE(alan_ed); + if (!ed) + return HRTIMER_NORESTART; + + if (alan_irq_cnt == 0 || alan_wdh_cnt == 0 || alan_iso_cnt == 0) { + ohci_info(alan_ohci, "Alan debug: irq %d wdh %d iso %d\n", + alan_irq_cnt, alan_wdh_cnt, alan_iso_cnt); + if (!list_empty(&ed->td_list)) { + cf = ohci_frame_no(alan_ohci); + td = list_entry(ed->td_list.next, struct td, + td_list); + sf = hc32_to_cpu(alan_ohci, td->hwINFO); + tdPSW = ohci_hwPSW(alan_ohci, td, 0); + ohci_info(alan_ohci, " td %p cf %04x sf %04x cc %x\n", + td, cf, sf, tdPSW >> 12); + } + } + + alan_irq_cnt = alan_wdh_cnt = alan_iso_cnt = 0; + timeout = ktime_add(ktime_get(), + ktime_set(0, 2 * NSEC_PER_MSEC)); + hrtimer_start_range_ns(&alan_hrtimer, timeout, + NSEC_PER_MSEC, HRTIMER_MODE_ABS); + return HRTIMER_NORESTART; +} + +static void alan_start(struct ohci_hcd *ohci, struct ed *ed, struct urb *urb) +{ + if (urb->interval == 1 && urb->number_of_packets == 1) { + alan_ohci = ohci; + alan_ed = ed; + alan_irq_cnt = alan_wdh_cnt = alan_iso_cnt = 1; + hrtimer_init(&alan_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + alan_hrtimer.function = alan_hrtimer_func; + alan_hrtimer_func(&alan_hrtimer); + } +} + +static void alan_stop(struct ohci_hcd *ohci) +{ + if (ohci == alan_ohci) { + alan_ed = NULL; + hrtimer_try_to_cancel(&alan_hrtimer); + } +} + #include "ohci-hub.c" #include "ohci-dbg.c" #include "ohci-mem.c" @@ -816,6 +876,9 @@ static irqreturn_t ohci_irq (struct usb_ if (ints == 0 || unlikely(ohci->rh_state == OHCI_RH_HALTED)) return IRQ_NOTMINE; + if (ohci == alan_ohci) + ++alan_irq_cnt; + if (ints & OHCI_INTR_UE) { // e.g. due to PCI Master/Target Abort if (quirk_nec(ohci)) { @@ -872,6 +935,8 @@ static irqreturn_t ohci_irq (struct usb_ } if (ints & OHCI_INTR_WDH) { + if (ohci == alan_ohci) + ++alan_wdh_cnt; spin_lock (&ohci->lock); dl_done_list (ohci); spin_unlock (&ohci->lock); Index: usb-3.10/drivers/usb/host/ohci-q.c =================================================================== --- usb-3.10.orig/drivers/usb/host/ohci-q.c +++ usb-3.10/drivers/usb/host/ohci-q.c @@ -1081,16 +1081,24 @@ static void takeback_td(struct ohci_hcd struct ed *ed = td->ed; int status; + if (ed->type == PIPE_ISOCHRONOUS && !alan_ed) + alan_start(ohci, ed, urb); + /* update URB's length and status from TD */ status = td_done(ohci, urb, td); urb_priv->td_cnt++; /* If all this urb's TDs are done, call complete() */ - if (urb_priv->td_cnt == urb_priv->length) + if (urb_priv->td_cnt == urb_priv->length) { + if (ed == alan_ed) + ++alan_iso_cnt; finish_urb(ohci, urb, status); + } /* clean schedule: unlink EDs that are no longer busy */ if (list_empty(&ed->td_list)) { + if (ed == alan_ed) + alan_stop(ohci); if (ed->state == ED_OPER) start_ed_unlink(ohci, ed);