>From 475e0d8b2865b03a5f62840d0ff0551124f4106b Mon Sep 17 00:00:00 2001 From: Alek Du <alek.du@xxxxxxxxx> Date: Tue, 23 Jun 2009 19:05:31 +0800 Subject: [PATCH] EHCI: Split ehci_qh - core part changes The most significant changes are here ... Signed-off-by: Alek Du <alek.du@xxxxxxxxx> --- drivers/usb/host/ehci-hub.c | 2 +- drivers/usb/host/ehci-q.c | 55 +++++++++++++------------- drivers/usb/host/ehci-sched.c | 86 +++++++++++++++++++++-------------------- 3 files changed, 73 insertions(+), 70 deletions(-) diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index f46ad27..e90b190 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -267,7 +267,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) /* maybe re-activate the schedule(s) */ temp = 0; - if (ehci->async->qh_next.qh) + if (SH_HW(&ehci->async->qh_next)) temp |= CMD_ASE; if (ehci->periodic_sched) temp |= CMD_PSE; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 3192f68..d293784 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -90,12 +90,12 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) /* writes to an active overlay are unsafe */ BUG_ON(qh->qh_state != QH_STATE_IDLE); - qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma); - qh->hw_alt_next = EHCI_LIST_END(ehci); + HW(qh)->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma); + HW(qh)->hw_alt_next = EHCI_LIST_END(ehci); /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */ wmb (); - qh->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING); + HW(qh)->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING); } /* if it weren't for a common silicon quirk (writing the dummy into the qh @@ -113,7 +113,7 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh) qtd = list_entry (qh->qtd_list.next, struct ehci_qtd, qtd_list); /* first qtd may already be partially processed */ - if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw_current) + if (cpu_to_hc32(ehci, qtd->qtd_dma) == HW(qh)->hw_current) qtd = NULL; } @@ -215,7 +215,7 @@ __acquires(ehci->lock) struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv; /* S-mask in a QH means it's an interrupt urb */ - if ((qh->hw_info2 & cpu_to_hc32(ehci, QH_SMASK)) != 0) { + if ((HW(qh)->hw_info2 & cpu_to_hc32(ehci, QH_SMASK)) != 0) { /* ... update hc-wide periodic stats (for usbfs) */ ehci_to_hcd(ehci)->self.bandwidth_int_reqs--; @@ -348,7 +348,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) qtd->hw_token = cpu_to_hc32(ehci, token); wmb(); - qh->hw_token = cpu_to_hc32(ehci, token); + HW(qh)->hw_token = + cpu_to_hc32(ehci, token); goto retry_xacterr; } stopped = 1; @@ -391,16 +392,16 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) /* qh unlinked; token in overlay may be most current */ if (state == QH_STATE_IDLE && cpu_to_hc32(ehci, qtd->qtd_dma) - == qh->hw_current) - token = hc32_to_cpu(ehci, qh->hw_token); + == HW(qh)->hw_current) + token = hc32_to_cpu(ehci, HW(qh)->hw_token); /* force halt for unlinked or blocked qh, so we'll * patch the qh later and so that completions can't * activate it while we "know" it's stopped. */ - if ((halt & qh->hw_token) == 0) { + if ((halt & HW(qh)->hw_token) == 0) { halt: - qh->hw_token |= halt; + HW(qh)->hw_token |= halt; wmb (); } } @@ -452,7 +453,7 @@ halt: * it after fault cleanup, or recovering from silicon wrongly * overlaying the dummy qtd (which reduces DMA chatter). */ - if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END(ehci)) { + if (stopped != 0 || HW(qh)->hw_qtd_next == EHCI_LIST_END(ehci)) { switch (state) { case QH_STATE_IDLE: qh_refresh(ehci, qh); @@ -470,7 +471,7 @@ halt: * except maybe high bandwidth ... */ if ((cpu_to_hc32(ehci, QH_SMASK) - & qh->hw_info2) != 0) { + & HW(qh)->hw_info2) != 0) { intr_deschedule (ehci, qh); (void) qh_schedule (ehci, qh); } else @@ -591,7 +592,7 @@ qh_urb_transaction ( * (this will usually be overridden later.) */ if (is_input) - qtd->hw_alt_next = ehci->async->hw_alt_next; + qtd->hw_alt_next = HW(ehci->async)->hw_alt_next; /* qh makes control packets use qtd toggle; maybe switch it */ if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) @@ -832,8 +833,8 @@ done: /* init as live, toggle clear, advance to dummy */ qh->qh_state = QH_STATE_IDLE; - qh->hw_info1 = cpu_to_hc32(ehci, info1); - qh->hw_info2 = cpu_to_hc32(ehci, info2); + HW(qh)->hw_info1 = cpu_to_hc32(ehci, info1); + HW(qh)->hw_info2 = cpu_to_hc32(ehci, info2); qh_refresh (ehci, qh); return qh; } @@ -850,7 +851,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) /* (re)start the async schedule? */ head = ehci->async; timer_action_done (ehci, TIMER_ASYNC_OFF); - if (!head->qh_next.qh) { + if (!SH_HW(&head->qh_next)) { u32 cmd = ehci_readl(ehci, &ehci->regs->command); if (!(cmd & CMD_ASE)) { @@ -870,11 +871,11 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) /* splice right after start */ qh->qh_next = head->qh_next; - qh->hw_next = head->hw_next; + HW(qh)->hw_next = HW(head)->hw_next; wmb (); - head->qh_next.qh = qh; - head->hw_next = dma; + SH_HW(&head->qh_next) = HW(qh); + HW(head)->hw_next = dma; qh->xacterrs = QH_XACTERR_MAX; qh->qh_state = QH_STATE_LINKED; @@ -920,7 +921,7 @@ static struct ehci_qh *qh_append_tds ( /* usb_reset_device() briefly reverts to address 0 */ if (usb_pipedevice (urb->pipe) == 0) - qh->hw_info1 &= ~qh_addr_mask; + HW(qh)->hw_info1 &= ~qh_addr_mask; } /* just one way to queue requests: swap with the dummy qtd. @@ -1037,7 +1038,7 @@ static void end_unlink_async (struct ehci_hcd *ehci) // qh->hw_next = cpu_to_hc32(qh->qh_dma); qh->qh_state = QH_STATE_IDLE; - qh->qh_next.qh = NULL; + SH_HW(&qh->qh_next) = NULL; qh_put (qh); // refcount from reclaim /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */ @@ -1057,7 +1058,7 @@ static void end_unlink_async (struct ehci_hcd *ehci) * active but idle for a while once it empties. */ if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state) - && ehci->async->qh_next.qh == NULL) + && SH_HW(&ehci->async->qh_next) == NULL) timer_action (ehci, TIMER_ASYNC_OFF); } @@ -1103,10 +1104,10 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ehci->reclaim = qh = qh_get (qh); prev = ehci->async; - while (prev->qh_next.qh != qh) - prev = prev->qh_next.qh; + while (SH_QH(&prev->qh_next) != qh) + prev = SH_QH(&prev->qh_next); - prev->hw_next = qh->hw_next; + HW(prev)->hw_next = HW(qh)->hw_next; prev->qh_next = qh->qh_next; wmb (); @@ -1135,7 +1136,7 @@ static void scan_async (struct ehci_hcd *ehci) ehci->stamp = ehci_readl(ehci, &ehci->regs->frame_index); timer_action_done (ehci, TIMER_ASYNC_SHRINK); rescan: - qh = ehci->async->qh_next.qh; + qh = SH_QH(&ehci->async->qh_next); if (likely (qh != NULL)) { do { /* clean any finished work for this qh */ @@ -1173,7 +1174,7 @@ rescan: action = TIMER_ASYNC_SHRINK; } - qh = qh->qh_next.qh; + qh = SH_QH(&qh->qh_next); } while (qh); } if (action == TIMER_ASYNC_SHRINK) diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 9d1babc..d9d4eca 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -49,7 +49,7 @@ periodic_next_shadow(struct ehci_hcd *ehci, union ehci_shadow *periodic, { switch (hc32_to_cpu(ehci, tag)) { case Q_TYPE_QH: - return &periodic->qh->qh_next; + return &SH_QH(periodic)->qh_next; case Q_TYPE_FSTN: return &periodic->fstn->fstn_next; case Q_TYPE_ITD: @@ -98,14 +98,14 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) { case Q_TYPE_QH: /* is it in the S-mask? */ - if (q->qh->hw_info2 & cpu_to_hc32(ehci, 1 << uframe)) - usecs += q->qh->usecs; + if (SH_HW(q)->hw_info2 & cpu_to_hc32(ehci, 1 << uframe)) + usecs += SH_QH(q)->usecs; /* ... or C-mask? */ - if (q->qh->hw_info2 & cpu_to_hc32(ehci, + if (SH_HW(q)->hw_info2 & cpu_to_hc32(ehci, 1 << (8 + uframe))) - usecs += q->qh->c_usecs; - hw_p = &q->qh->hw_next; - q = &q->qh->qh_next; + usecs += SH_QH(q)->c_usecs; + hw_p = &SH_HW(q)->hw_next; + q = &SH_QH(q)->qh_next; break; // case Q_TYPE_FSTN: default: @@ -236,12 +236,12 @@ periodic_tt_usecs ( q = &q->itd->itd_next; continue; case Q_TYPE_QH: - if (same_tt(dev, q->qh->dev)) { - uf = tt_start_uframe(ehci, q->qh->hw_info2); - tt_usecs[uf] += q->qh->tt_usecs; + if (same_tt(dev, SH_QH(q)->dev)) { + uf = tt_start_uframe(ehci, SH_HW(q)->hw_info2); + tt_usecs[uf] += SH_QH(q)->tt_usecs; } - hw_p = &q->qh->hw_next; - q = &q->qh->qh_next; + hw_p = &SH_HW(q)->hw_next; + q = &SH_QH(q)->qh_next; continue; case Q_TYPE_SITD: if (same_tt(dev, q->sitd->urb->dev)) { @@ -385,18 +385,18 @@ static int tt_no_collision ( here = here.itd->itd_next; continue; case Q_TYPE_QH: - if (same_tt (dev, here.qh->dev)) { + if (same_tt(dev, SH_QH(&here)->dev)) { u32 mask; mask = hc32_to_cpu(ehci, - here.qh->hw_info2); + SH_HW(&here)->hw_info2); /* "knows" no gap is needed */ mask |= mask >> 8; if (mask & uf_mask) break; } - type = Q_NEXT_TYPE(ehci, here.qh->hw_next); - here = here.qh->qh_next; + type = Q_NEXT_TYPE(ehci, SH_HW(&here)->hw_next); + here = SH_QH(&here)->qh_next; continue; case Q_TYPE_SITD: if (same_tt (dev, here.sitd->urb->dev)) { @@ -498,7 +498,8 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) dev_dbg (&qh->dev->dev, "link qh%d-%04x/%p start %d [%d/%d us]\n", - period, hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK), + period, hc32_to_cpup(ehci, &HW(qh)->hw_info2) + & (QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs, qh->c_usecs); /* high bandwidth, or otherwise every microframe */ @@ -517,27 +518,27 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) if (type == cpu_to_hc32(ehci, Q_TYPE_QH)) break; prev = periodic_next_shadow(ehci, prev, type); - hw_p = &here.qh->hw_next; + hw_p = &SH_HW(&here)->hw_next; here = *prev; } /* sorting each branch by period (slow-->fast) * enables sharing interior tree nodes */ - while (here.ptr && qh != here.qh) { - if (qh->period > here.qh->period) + while (here.ptr && HW(qh) != SH_HW(&here)) { + if (qh->period > SH_QH(&here)->period) break; - prev = &here.qh->qh_next; - hw_p = &here.qh->hw_next; + prev = &SH_QH(&here)->qh_next; + hw_p = &SH_HW(&here)->hw_next; here = *prev; } /* link in this qh, unless some earlier pass did that */ - if (qh != here.qh) { + if (HW(qh) != SH_HW(&here)) { qh->qh_next = here; - if (here.qh) - qh->hw_next = *hw_p; + if (SH_HW(&here)) + HW(qh)->hw_next = *hw_p; wmb (); - prev->qh = qh; + SH_HW(prev) = HW(qh); *hw_p = QH_NEXT (ehci, qh->qh_dma); } } @@ -570,7 +571,7 @@ static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) period = 1; for (i = qh->start; i < ehci->periodic_size; i += period) - periodic_unlink (ehci, i, qh); + periodic_unlink(ehci, i, HW(qh)); /* update per-qh bandwidth for usbfs */ ehci_to_hcd(ehci)->self.bandwidth_allocated -= qh->period @@ -580,7 +581,7 @@ static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) dev_dbg (&qh->dev->dev, "unlink qh%d-%04x/%p start %d [%d/%d us]\n", qh->period, - hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK), + hc32_to_cpup(ehci, &HW(qh)->hw_info2) & (QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs, qh->c_usecs); /* qh->qh_next still "live" to HC */ @@ -605,14 +606,14 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh) */ if (list_empty (&qh->qtd_list) || (cpu_to_hc32(ehci, QH_CMASK) - & qh->hw_info2) != 0) + & HW(qh)->hw_info2) != 0) wait = 2; else wait = 55; /* worst case: 3 * 1024 */ udelay (wait); qh->qh_state = QH_STATE_IDLE; - qh->hw_next = EHCI_LIST_END(ehci); + HW(qh)->hw_next = EHCI_LIST_END(ehci); wmb (); } @@ -740,12 +741,12 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh) unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ qh_refresh(ehci, qh); - qh->hw_next = EHCI_LIST_END(ehci); + HW(qh)->hw_next = EHCI_LIST_END(ehci); frame = qh->start; /* reuse the previous schedule slots, if we can */ if (frame < qh->period) { - uframe = ffs(hc32_to_cpup(ehci, &qh->hw_info2) & QH_SMASK); + uframe = ffs(hc32_to_cpup(ehci, &HW(qh)->hw_info2) & QH_SMASK); status = check_intr_schedule (ehci, frame, --uframe, qh, &c_mask); } else { @@ -783,11 +784,11 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh) qh->start = frame; /* reset S-frame and (maybe) C-frame masks */ - qh->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK)); - qh->hw_info2 |= qh->period + HW(qh)->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK)); + HW(qh)->hw_info2 |= qh->period ? cpu_to_hc32(ehci, 1 << uframe) : cpu_to_hc32(ehci, QH_SMASK); - qh->hw_info2 |= c_mask; + HW(qh)->hw_info2 |= c_mask; } else ehci_dbg (ehci, "reused qh %p schedule\n", qh); @@ -2182,13 +2183,14 @@ restart: switch (hc32_to_cpu(ehci, type)) { case Q_TYPE_QH: /* handle any completions */ - temp.qh = qh_get (q.qh); - type = Q_NEXT_TYPE(ehci, q.qh->hw_next); - q = q.qh->qh_next; - modified = qh_completions (ehci, temp.qh); - if (unlikely (list_empty (&temp.qh->qtd_list))) - intr_deschedule (ehci, temp.qh); - qh_put (temp.qh); + SH_HW(&temp) = HW(qh_get(SH_QH(&q))); + type = Q_NEXT_TYPE(ehci, SH_HW(&q)->hw_next); + q = SH_QH(&q)->qh_next; + modified = qh_completions(ehci, SH_QH(&temp)); + if (unlikely(list_empty( + &SH_QH(&temp)->qtd_list))) + intr_deschedule(ehci, SH_QH(&temp)); + qh_put(SH_QH(&temp)); break; case Q_TYPE_FSTN: /* for "save place" FSTNs, look at QH entries -- 1.6.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html