summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/ehci-hcd.c3
-rw-r--r--drivers/usb/host/ehci-sched.c114
-rw-r--r--drivers/usb/host/ehci.h6
3 files changed, 32 insertions, 91 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 9f26080889f5..340c9c4894bf 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -488,9 +488,6 @@ static int ehci_init(struct usb_hcd *hcd)
else // N microframes cached
ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
- ehci->next_uframe = -1;
- ehci->clock_frame = -1;
-
/*
* dedicate a qh for the async ring head, since we couldn't unlink
* a 'real' qh without stopping the async schedule [4.8]. use it
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 26ce8fef0e5b..7cf3da7babf0 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -497,8 +497,6 @@ static void disable_periodic(struct ehci_hcd *ehci)
if (--ehci->periodic_count)
return;
- ehci->next_uframe = -1; /* the periodic schedule is empty */
-
/* Don't turn off the schedule until PSS is 1 */
ehci_poll_PSS(ehci);
}
@@ -1220,7 +1218,7 @@ itd_urb_transaction (
if (likely(!list_empty(&stream->free_list))) {
itd = list_first_entry(&stream->free_list,
struct ehci_itd, itd_list);
- if (itd->frame == ehci->clock_frame)
+ if (itd->frame == ehci->now_frame)
goto alloc_itd;
list_del (&itd->itd_list);
itd_dma = itd->itd_dma;
@@ -1492,7 +1490,7 @@ iso_stream_schedule (
/* Make sure scan_isoc() sees these */
if (ehci->isoc_count == 0)
- ehci->next_uframe = now;
+ ehci->next_frame = now >> 3;
return 0;
fail:
@@ -1666,11 +1664,8 @@ static void itd_link_urb(
* (b) only this endpoint's completions submit URBs. It seems some silicon
* corrupts things if you reuse completed descriptors very quickly...
*/
-static unsigned
-itd_complete (
- struct ehci_hcd *ehci,
- struct ehci_itd *itd
-) {
+static bool itd_complete(struct ehci_hcd *ehci, struct ehci_itd *itd)
+{
struct urb *urb = itd->urb;
struct usb_iso_packet_descriptor *desc;
u32 t;
@@ -1678,7 +1673,7 @@ itd_complete (
int urb_index = -1;
struct ehci_iso_stream *stream = itd->stream;
struct usb_device *dev;
- unsigned retval = false;
+ bool retval = false;
/* for each uframe with a packet */
for (uframe = 0; uframe < 8; uframe++) {
@@ -1917,7 +1912,7 @@ sitd_urb_transaction (
if (likely(!list_empty(&stream->free_list))) {
sitd = list_first_entry(&stream->free_list,
struct ehci_sitd, sitd_list);
- if (sitd->frame == ehci->clock_frame)
+ if (sitd->frame == ehci->now_frame)
goto alloc_sitd;
list_del (&sitd->sitd_list);
sitd_dma = sitd->sitd_dma;
@@ -2071,18 +2066,15 @@ static void sitd_link_urb(
* (b) only this endpoint's completions submit URBs. It seems some silicon
* corrupts things if you reuse completed descriptors very quickly...
*/
-static unsigned
-sitd_complete (
- struct ehci_hcd *ehci,
- struct ehci_sitd *sitd
-) {
+static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd)
+{
struct urb *urb = sitd->urb;
struct usb_iso_packet_descriptor *desc;
u32 t;
int urb_index = -1;
struct ehci_iso_stream *stream = sitd->stream;
struct usb_device *dev;
- unsigned retval = false;
+ bool retval = false;
urb_index = sitd->index;
desc = &urb->iso_frame_desc [urb_index];
@@ -2214,34 +2206,29 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
static void scan_isoc(struct ehci_hcd *ehci)
{
- unsigned now_uframe, frame, clock, clock_frame, mod;
- unsigned modified;
-
- mod = ehci->periodic_size << 3;
+ unsigned uf, now_frame, frame;
+ unsigned fmask = ehci->periodic_size - 1;
+ bool modified, live;
/*
* When running, scan from last scan point up to "now"
* else clean up by scanning everything that's left.
* Touches as few pages as possible: cache-friendly.
*/
- now_uframe = ehci->next_uframe;
if (ehci->rh_state >= EHCI_RH_RUNNING) {
- clock = ehci_read_frame_index(ehci);
- clock_frame = (clock >> 3) & (ehci->periodic_size - 1);
+ uf = ehci_read_frame_index(ehci);
+ now_frame = (uf >> 3) & fmask;
+ live = true;
} else {
- clock = now_uframe + mod - 1;
- clock_frame = -1;
+ now_frame = (ehci->next_frame - 1) & fmask;
+ live = false;
}
- ehci->clock_frame = clock_frame;
- clock &= mod - 1;
- clock_frame = clock >> 3;
+ ehci->now_frame = now_frame;
+ frame = ehci->next_frame;
for (;;) {
union ehci_shadow q, *q_p;
__hc32 type, *hw_p;
- unsigned incomplete = false;
-
- frame = now_uframe >> 3;
restart:
/* scan each element in frame's queue for completions */
@@ -2249,13 +2236,9 @@ restart:
hw_p = &ehci->periodic [frame];
q.ptr = q_p->ptr;
type = Q_NEXT_TYPE(ehci, *hw_p);
- modified = 0;
+ modified = false;
while (q.ptr != NULL) {
- unsigned uf;
- int live;
-
- live = (ehci->rh_state >= EHCI_RH_RUNNING);
switch (hc32_to_cpu(ehci, type)) {
case Q_TYPE_ITD:
/* If this ITD is still active, leave it for
@@ -2263,7 +2246,7 @@ restart:
* No need to check for activity unless the
* frame is current.
*/
- if (frame == clock_frame && live) {
+ if (frame == now_frame && live) {
rmb();
for (uf = 0; uf < 8; uf++) {
if (q.itd->hw_transaction[uf] &
@@ -2271,7 +2254,6 @@ restart:
break;
}
if (uf < 8) {
- incomplete = true;
q_p = &q.itd->itd_next;
hw_p = &q.itd->hw_next;
type = Q_NEXT_TYPE(ehci,
@@ -2303,14 +2285,12 @@ restart:
* No need to check for activity unless the
* frame is current.
*/
- if (((frame == clock_frame) ||
- (((frame + 1) & (ehci->periodic_size - 1))
- == clock_frame))
+ if (((frame == now_frame) ||
+ (((frame + 1) & fmask) == now_frame))
&& live
&& (q.sitd->hw_results &
SITD_ACTIVE(ehci))) {
- incomplete = true;
q_p = &q.sitd->sitd_next;
hw_p = &q.sitd->hw_next;
type = Q_NEXT_TYPE(ehci,
@@ -2347,50 +2327,14 @@ restart:
}
/* assume completion callbacks modify the queue */
- if (unlikely (modified)) {
- if (likely(ehci->isoc_count > 0))
- goto restart;
- /* short-circuit this scan */
- now_uframe = clock;
- break;
- }
+ if (unlikely(modified && ehci->isoc_count > 0))
+ goto restart;
}
- /* If we can tell we caught up to the hardware, stop now.
- * We can't advance our scan without collecting the ISO
- * transfers that are still pending in this frame.
- */
- if (incomplete && ehci->rh_state >= EHCI_RH_RUNNING) {
- ehci->next_uframe = now_uframe;
+ /* Stop when we have reached the current frame */
+ if (frame == now_frame)
break;
- }
-
- // FIXME: this assumes we won't get lapped when
- // latencies climb; that should be rare, but...
- // detect it, and just go all the way around.
- // FLR might help detect this case, so long as latencies
- // don't exceed periodic_size msec (default 1.024 sec).
-
- // FIXME: likewise assumes HC doesn't halt mid-scan
-
- if (now_uframe == clock) {
- unsigned now;
-
- if (ehci->rh_state < EHCI_RH_RUNNING
- || ehci->isoc_count == 0)
- break;
- ehci->next_uframe = now_uframe;
- now = ehci_read_frame_index(ehci) & (mod - 1);
- if (now_uframe == now)
- break;
-
- /* rescan the rest of this frame, then ... */
- clock = now;
- clock_frame = clock >> 3;
- ehci->clock_frame = clock_frame;
- } else {
- now_uframe++;
- now_uframe &= mod - 1;
- }
+ frame = (frame + 1) & fmask;
}
+ ehci->next_frame = now_frame;
}
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 254f414bd0bd..7de58fe52d51 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -141,19 +141,19 @@ struct ehci_hcd { /* one per controller */
struct ehci_qh *intr_unlink;
struct ehci_qh *intr_unlink_last;
unsigned intr_unlink_cycle;
- int next_uframe; /* scan periodic, start here */
+ unsigned now_frame; /* frame from HC hardware */
+ unsigned next_frame; /* scan periodic, start here */
unsigned intr_count; /* intr activity count */
unsigned isoc_count; /* isoc activity count */
unsigned periodic_count; /* periodic activity count */
unsigned uframe_periodic_max; /* max periodic time per uframe */
- /* list of itds & sitds completed while clock_frame was still active */
+ /* list of itds & sitds completed while now_frame was still active */
struct list_head cached_itd_list;
struct ehci_itd *last_itd_to_free;
struct list_head cached_sitd_list;
struct ehci_sitd *last_sitd_to_free;
- unsigned clock_frame;
/* per root hub port */
unsigned long reset_done [EHCI_MAX_ROOT_PORTS];