>From 63538a7c3f002895ee4427f4e78d5e5a348fcbb4 Mon Sep 17 00:00:00 2001 From: Alek Du <alek.du@xxxxxxxxx> Date: Fri, 26 Jun 2009 16:05:24 +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-q.c | 39 +++++++++++++------------ drivers/usb/host/ehci-sched.c | 63 ++++++++++++++++++++++++++--------------- 2 files changed, 60 insertions(+), 42 deletions(-) diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 3192f68..b50e008 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; } @@ -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; + 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. @@ -1106,7 +1107,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) while (prev->qh_next.qh != qh) prev = prev->qh_next.qh; - prev->hw_next = qh->hw_next; + HW(prev)->hw_next = HW(qh)->hw_next; prev->qh_next = qh->qh_next; wmb (); diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 9d1babc..d968c4e 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -60,6 +60,20 @@ periodic_next_shadow(struct ehci_hcd *ehci, union ehci_shadow *periodic, } } +static __hc32 * +shadow_next_periodic(struct ehci_hcd *ehci, union ehci_shadow *periodic, + __hc32 tag) +{ + switch (hc32_to_cpu(ehci, tag)) { + /* our ehci_shadow.qh is actually software part */ + case Q_TYPE_QH: + return &HW(periodic->qh)->hw_next; + /* others are hw parts */ + default: + return periodic->hw_next; + } +} + /* caller must hold ehci->lock */ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) { @@ -71,7 +85,8 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) while (here.ptr && here.ptr != ptr) { prev_p = periodic_next_shadow(ehci, prev_p, Q_NEXT_TYPE(ehci, *hw_p)); - hw_p = here.hw_next; + hw_p = shadow_next_periodic(ehci, &here, + Q_NEXT_TYPE(ehci, *hw_p)); here = *prev_p; } /* an interrupt entry (at list end) could have been shared */ @@ -83,7 +98,7 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) */ *prev_p = *periodic_next_shadow(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p)); - *hw_p = *here.hw_next; + *hw_p = *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p)); } /* how many of the uframe's 125 usecs are allocated? */ @@ -98,13 +113,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)) + if (HW(q->qh)->hw_info2 & cpu_to_hc32(ehci, + 1 << uframe)) usecs += q->qh->usecs; /* ... or C-mask? */ - if (q->qh->hw_info2 & cpu_to_hc32(ehci, + if (HW(q->qh)->hw_info2 & cpu_to_hc32(ehci, 1 << (8 + uframe))) usecs += q->qh->c_usecs; - hw_p = &q->qh->hw_next; + hw_p = &HW(q->qh)->hw_next; q = &q->qh->qh_next; break; // case Q_TYPE_FSTN: @@ -237,10 +253,10 @@ periodic_tt_usecs ( continue; case Q_TYPE_QH: if (same_tt(dev, q->qh->dev)) { - uf = tt_start_uframe(ehci, q->qh->hw_info2); + uf = tt_start_uframe(ehci, HW(q->qh)->hw_info2); tt_usecs[uf] += q->qh->tt_usecs; } - hw_p = &q->qh->hw_next; + hw_p = &HW(q->qh)->hw_next; q = &q->qh->qh_next; continue; case Q_TYPE_SITD: @@ -389,13 +405,13 @@ static int tt_no_collision ( u32 mask; mask = hc32_to_cpu(ehci, - here.qh->hw_info2); + HW(here.qh)->hw_info2); /* "knows" no gap is needed */ mask |= mask >> 8; if (mask & uf_mask) break; } - type = Q_NEXT_TYPE(ehci, here.qh->hw_next); + type = Q_NEXT_TYPE(ehci, HW(here.qh)->hw_next); here = here.qh->qh_next; continue; case Q_TYPE_SITD: @@ -498,7 +514,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,7 +534,7 @@ 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 = shadow_next_periodic(ehci, &here, type); here = *prev; } @@ -528,14 +545,14 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) if (qh->period > here.qh->period) break; prev = &here.qh->qh_next; - hw_p = &here.qh->hw_next; + hw_p = &HW(here.qh)->hw_next; here = *prev; } /* link in this qh, unless some earlier pass did that */ if (qh != here.qh) { qh->qh_next = here; if (here.qh) - qh->hw_next = *hw_p; + HW(qh)->hw_next = *hw_p; wmb (); prev->qh = qh; *hw_p = QH_NEXT (ehci, qh->qh_dma); @@ -570,7 +587,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, qh); /* update per-qh bandwidth for usbfs */ ehci_to_hcd(ehci)->self.bandwidth_allocated -= qh->period @@ -580,7 +597,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 +622,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 +757,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 +800,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); @@ -2183,7 +2200,7 @@ restart: case Q_TYPE_QH: /* handle any completions */ temp.qh = qh_get (q.qh); - type = Q_NEXT_TYPE(ehci, q.qh->hw_next); + type = Q_NEXT_TYPE(ehci, HW(q.qh)->hw_next); q = q.qh->qh_next; modified = qh_completions (ehci, temp.qh); if (unlikely (list_empty (&temp.qh->qtd_list))) -- 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