Have to send v2 version again, fixed a qh_destroy issue. >From bd43fff4f26616f3abe58deffeafac3e05aea4c5 Mon Sep 17 00:00:00 2001 From: Alek Du <alek.du@xxxxxxxxx> Date: Wed, 10 Jun 2009 11:53:59 +0800 Subject: [PATCH] EHCI: split ehci_qh structure into hw and sw parts The ehci_qh structure merged hw and sw together which is not good: 1. If HCD has local SRAM, the sw part will consume it too, and it won't bring any benefit. 2. For non-x86 system, the entire ehci_qh is uncachable, actually we only need the hw part to be uncacheable. Split them will give the sw part cacheable feature. Signed-off-by: Alek Du <alek.du@xxxxxxxxx> --- drivers/usb/host/ehci-dbg.c | 18 +++--- drivers/usb/host/ehci-hcd.c | 46 ++++++++------- drivers/usb/host/ehci-hub.c | 5 +- drivers/usb/host/ehci-mem.c | 50 ++++++++++------ drivers/usb/host/ehci-q.c | 131 +++++++++++++++++++++-------------------- drivers/usb/host/ehci-sched.c | 118 +++++++++++++++++++------------------ drivers/usb/host/ehci.h | 9 +++- 7 files changed, 203 insertions(+), 174 deletions(-) diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 7f4ace7..e54bd3c 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -429,7 +429,7 @@ static void qh_lines ( next += temp; /* hc may be modifying the list as we read it ... */ - list_for_each (entry, &qh->qtd_list) { + list_for_each(entry, &qh->sw->qtd_list) { td = list_entry (entry, struct ehci_qtd, qtd_list); scratch = hc32_to_cpup(ehci, &td->hw_token); mark = ' '; @@ -495,14 +495,15 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf) * one QH per line, and TDs we know about */ spin_lock_irqsave (&ehci->lock, flags); - for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh) + for (qh = ehci->async->sw->qh_next.qh; size > 0 && qh; + qh = qh->sw->qh_next.qh) qh_lines (ehci, qh, &next, &size); if (ehci->reclaim && size > 0) { temp = scnprintf (next, size, "\nreclaim =\n"); size -= temp; next += temp; - for (qh = ehci->reclaim; size > 0 && qh; qh = qh->reclaim) + for (qh = ehci->reclaim; size > 0 && qh; qh = qh->sw->reclaim) qh_lines (ehci, qh, &next, &size); } spin_unlock_irqrestore (&ehci->lock, flags); @@ -553,7 +554,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf) switch (hc32_to_cpu(ehci, tag)) { case Q_TYPE_QH: temp = scnprintf (next, size, " qh%d-%04x/%p", - p.qh->period, + p.qh->sw->period, hc32_to_cpup(ehci, &p.qh->hw_info2) /* uframe masks */ @@ -565,7 +566,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf) for (temp = 0; temp < seen_count; temp++) { if (seen [temp].ptr != p.ptr) continue; - if (p.qh->qh_next.ptr) { + if (p.qh->sw->qh_next.ptr) { temp = scnprintf (next, size, " ..."); size -= temp; @@ -583,7 +584,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf) /* count tds, get ep direction */ temp = 0; list_for_each_entry (qtd, - &p.qh->qtd_list, + &p.qh->sw->qtd_list, qtd_list) { temp++; switch (0x03 & (hc32_to_cpu( @@ -600,7 +601,8 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf) speed_char (scratch), scratch & 0x007f, (scratch >> 8) & 0x000f, type, - p.qh->usecs, p.qh->c_usecs, + p.qh->sw->usecs, + p.qh->sw->c_usecs, temp, 0x7ff & (scratch >> 16)); @@ -610,7 +612,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf) temp = 0; if (p.qh) { tag = Q_NEXT_TYPE(ehci, p.qh->hw_next); - p = p.qh->qh_next; + p = p.qh->sw->qh_next; } break; case Q_TYPE_FSTN: diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 36cedc9..d7ba228 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -452,7 +452,7 @@ static void ehci_work (struct ehci_hcd *ehci) * such lossage has been observed on both VT6202 and VT8235. */ if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && - (ehci->async->qh_next.ptr != NULL || + (ehci->async->sw->qh_next.ptr != NULL || ehci->periodic_sched != 0)) timer_action (ehci, TIMER_IO_WATCHDOG); } @@ -545,13 +545,14 @@ static int ehci_init(struct usb_hcd *hcd) * its dummy is used in hw_alt_next of many tds, to prevent the qh * from automatically advancing to the next td after short reads. */ - ehci->async->qh_next.qh = NULL; - ehci->async->hw_next = QH_NEXT(ehci, ehci->async->qh_dma); + ehci->async->sw->qh_next.qh = NULL; + ehci->async->hw_next = QH_NEXT(ehci, ehci->async->sw->qh_dma); ehci->async->hw_info1 = cpu_to_hc32(ehci, QH_HEAD); ehci->async->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT); ehci->async->hw_qtd_next = EHCI_LIST_END(ehci); - ehci->async->qh_state = QH_STATE_LINKED; - ehci->async->hw_alt_next = QTD_NEXT(ehci, ehci->async->dummy->qtd_dma); + ehci->async->sw->qh_state = QH_STATE_LINKED; + ehci->async->hw_alt_next = + QTD_NEXT(ehci, ehci->async->sw->dummy->qtd_dma); /* clear interrupt enables, set irq latency */ if (log2_irq_thresh < 0 || log2_irq_thresh > 6) @@ -605,7 +606,8 @@ static int ehci_run (struct usb_hcd *hcd) return retval; } ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); - ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next); + ehci_writel(ehci, (u32)ehci->async->sw->qh_dma, + &ehci->regs->async_next); /* * hcc_params controls whether ehci->regs->segment must (!!!) @@ -853,7 +855,7 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) end_unlink_async(ehci); /* if it's not linked then there's nothing to do */ - if (qh->qh_state != QH_STATE_LINKED) + if (qh->sw->qh_state != QH_STATE_LINKED) ; /* defer till later if busy */ @@ -861,11 +863,11 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) struct ehci_qh *last; for (last = ehci->reclaim; - last->reclaim; - last = last->reclaim) + last->sw->reclaim; + last = last->sw->reclaim) continue; - qh->qh_state = QH_STATE_UNLINK_WAIT; - last->reclaim = qh; + qh->sw->qh_state = QH_STATE_UNLINK_WAIT; + last->sw->reclaim = qh; /* start IAA cycle */ } else @@ -895,7 +897,7 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) qh = (struct ehci_qh *) urb->hcpriv; if (!qh) break; - switch (qh->qh_state) { + switch (qh->sw->qh_state) { case QH_STATE_LINKED: case QH_STATE_COMPLETING: unlink_async(ehci, qh); @@ -914,7 +916,7 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) qh = (struct ehci_qh *) urb->hcpriv; if (!qh) break; - switch (qh->qh_state) { + switch (qh->sw->qh_state) { case QH_STATE_LINKED: intr_deschedule (ehci, qh); /* FALL THROUGH */ @@ -923,12 +925,12 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) break; default: ehci_dbg (ehci, "bogus qh %p state %d\n", - qh, qh->qh_state); + qh, qh->sw->qh_state); goto done; } /* reschedule QH iff another request is queued */ - if (!list_empty (&qh->qtd_list) + if (!list_empty(&qh->sw->qtd_list) && HC_IS_RUNNING (hcd->state)) { rc = qh_schedule(ehci, qh); @@ -986,12 +988,12 @@ rescan: } if (!HC_IS_RUNNING (hcd->state)) - qh->qh_state = QH_STATE_IDLE; - switch (qh->qh_state) { + qh->sw->qh_state = QH_STATE_IDLE; + switch (qh->sw->qh_state) { case QH_STATE_LINKED: - for (tmp = ehci->async->qh_next.qh; + for (tmp = ehci->async->sw->qh_next.qh; tmp && tmp != qh; - tmp = tmp->qh_next.qh) + tmp = tmp->sw->qh_next.qh) continue; /* periodic qh self-unlinks on empty */ if (!tmp) @@ -1005,7 +1007,7 @@ idle_timeout: schedule_timeout_uninterruptible(1); goto rescan; case QH_STATE_IDLE: /* fully unlinked */ - if (list_empty (&qh->qtd_list)) { + if (list_empty(&qh->sw->qtd_list)) { qh_put (qh); break; } @@ -1016,8 +1018,8 @@ nogood: * that's not our job. just leak this memory. */ ehci_err (ehci, "qh %p (#%02x) state %d%s\n", - qh, ep->desc.bEndpointAddress, qh->qh_state, - list_empty (&qh->qtd_list) ? "" : "(has tds)"); + qh, ep->desc.bEndpointAddress, qh->sw->qh_state, + list_empty(&qh->sw->qtd_list) ? "" : "(has tds)"); break; } ep->hcpriv = NULL; diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 97a53a4..ce04e05 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -222,7 +222,8 @@ static int ehci_bus_resume (struct usb_hcd *hcd) /* re-init operational registers */ ehci_writel(ehci, 0, &ehci->regs->segment); ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); - ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next); + ehci_writel(ehci, (u32) ehci->async->sw->qh_dma, + &ehci->regs->async_next); /* restore CMD_RUN, framelist size, and irq threshold */ ehci_writel(ehci, ehci->command, &ehci->regs->command); @@ -267,7 +268,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 (ehci->async->sw->qh_next.qh) temp |= CMD_ASE; if (ehci->periodic_sched) temp |= CMD_PSE; diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index 10d5291..9bb222c 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -66,16 +66,19 @@ static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd) static void qh_destroy(struct ehci_qh *qh) { - struct ehci_hcd *ehci = qh->ehci; + struct ehci_hcd *ehci = qh->sw->ehci; + dma_addr_t qh_dma; /* clean qtds first, and know this is not linked */ - if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) { + if (!list_empty(&qh->sw->qtd_list) || qh->sw->qh_next.ptr) { ehci_dbg (ehci, "unused qh not empty!\n"); BUG (); } - if (qh->dummy) - ehci_qtd_free (ehci, qh->dummy); - dma_pool_free (ehci->qh_pool, qh, qh->qh_dma); + if (qh->sw->dummy) + ehci_qtd_free(ehci, qh->sw->dummy); + qh_dma = qh->sw->qh_dma; + kfree(qh->sw); + dma_pool_free(ehci->qh_pool, qh, qh_dma); } static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) @@ -86,36 +89,47 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) qh = (struct ehci_qh *) dma_pool_alloc (ehci->qh_pool, flags, &dma); if (!qh) - return qh; + goto done; memset (qh, 0, sizeof *qh); - qh->refcount = 1; - qh->ehci = ehci; - qh->qh_dma = dma; - // INIT_LIST_HEAD (&qh->qh_list); - INIT_LIST_HEAD (&qh->qtd_list); + qh->sw = (struct ehci_qh_sw *) + kzalloc(sizeof *qh->sw, GFP_ATOMIC); + if (qh->sw == NULL) { + ehci_err(ehci, "can not alloc ehci_qh_sw\n"); + goto failed; + } + qh->sw->refcount = 1; + qh->sw->ehci = ehci; + qh->sw->qh_dma = dma; + /* INIT_LIST_HEAD(&qh->sw->qh_list); */ + INIT_LIST_HEAD(&qh->sw->qtd_list); /* dummy td enables safe urb queuing */ - qh->dummy = ehci_qtd_alloc (ehci, flags); - if (qh->dummy == NULL) { + qh->sw->dummy = ehci_qtd_alloc(ehci, flags); + if (qh->sw->dummy == NULL) { ehci_dbg (ehci, "no dummy td\n"); - dma_pool_free (ehci->qh_pool, qh, qh->qh_dma); - qh = NULL; + goto failed1; } +done: return qh; +failed1: + kfree(qh->sw); +failed: + dma_pool_free(ehci->qh_pool, qh, dma); + return NULL; } /* to share a qh (cpu threads, or hc) */ static inline struct ehci_qh *qh_get (struct ehci_qh *qh) { - WARN_ON(!qh->refcount); - qh->refcount++; + WARN_ON(!qh->sw->refcount); + qh->sw->refcount++; return qh; } static inline void qh_put (struct ehci_qh *qh) { - if (!--qh->refcount) + if (!--qh->sw->refcount) qh_destroy(qh); } diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 1976b1b..bc7d0f6 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -88,7 +88,7 @@ static inline void 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); + BUG_ON(qh->sw->qh_state != QH_STATE_IDLE); qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma); qh->hw_alt_next = EHCI_LIST_END(ehci); @@ -103,9 +103,9 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8)); epnum = (hc32_to_cpup(ehci, &qh->hw_info1) >> 8) & 0x0f; - if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { + if (unlikely(!usb_gettoggle(qh->sw->dev, epnum, is_out))) { qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); - usb_settoggle (qh->dev, epnum, is_out, 1); + usb_settoggle(qh->sw->dev, epnum, is_out, 1); } } @@ -123,10 +123,10 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh) { struct ehci_qtd *qtd; - if (list_empty (&qh->qtd_list)) - qtd = qh->dummy; + if (list_empty(&qh->sw->qtd_list)) + qtd = qh->sw->dummy; else { - qtd = list_entry (qh->qtd_list.next, + qtd = list_entry(qh->sw->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) @@ -279,7 +279,7 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh); static unsigned qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) { - struct ehci_qtd *last = NULL, *end = qh->dummy; + struct ehci_qtd *last = NULL, *end = qh->sw->dummy; struct list_head *entry, *tmp; int last_status = -EINPROGRESS; int stopped; @@ -287,7 +287,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) u8 state; __le32 halt = HALT_BIT(ehci); - if (unlikely (list_empty (&qh->qtd_list))) + if (unlikely(list_empty(&qh->sw->qtd_list))) return count; /* completions (or tasks on other cpus) must never clobber HALT @@ -296,8 +296,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) * * NOTE: unlinking expects to be done in queue order. */ - state = qh->qh_state; - qh->qh_state = QH_STATE_COMPLETING; + state = qh->sw->qh_state; + qh->sw->qh_state = QH_STATE_COMPLETING; stopped = (state == QH_STATE_IDLE); /* remove de-activated QTDs from front of queue. @@ -305,7 +305,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) * then let the queue advance. * if queue is stopped, handles unlinks. */ - list_for_each_safe (entry, tmp, &qh->qtd_list) { + list_for_each_safe(entry, tmp, &qh->sw->qtd_list) { struct ehci_qtd *qtd; struct urb *urb; u32 token = 0; @@ -346,12 +346,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) */ if ((token & QTD_STS_XACT) && QTD_CERR(token) == 0 && - --qh->xacterrs > 0 && + --qh->sw->xacterrs > 0 && !urb->unlinked) { ehci_dbg(ehci, "detected XactErr len %zu/%zu retry %d\n", qtd->length - QTD_LENGTH(token), qtd->length, - QH_XACTERR_MAX - qh->xacterrs); + QH_XACTERR_MAX - qh->sw->xacterrs); /* reset the token in the qtd and the * qh overlay (which still contains @@ -440,7 +440,7 @@ halt: /* if we're removing something not at the queue head, * patch the hardware queue pointer. */ - if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { + if (stopped && qtd->qtd_list.prev != &qh->sw->qtd_list) { last = list_entry (qtd->qtd_list.prev, struct ehci_qtd, qtd_list); last->hw_next = qtd->hw_next; @@ -451,7 +451,7 @@ halt: last = qtd; /* reinit the xacterr counter for the next qtd */ - qh->xacterrs = QH_XACTERR_MAX; + qh->sw->xacterrs = QH_XACTERR_MAX; } /* last urb's completion might still need calling */ @@ -462,7 +462,7 @@ halt: } /* restore original state; caller must unlink or relink */ - qh->qh_state = state; + qh->sw->qh_state = state; /* be sure the hardware's done with the qh before refreshing * it after fault cleanup, or recovering from silicon wrongly @@ -733,17 +733,17 @@ qh_make ( * For control/bulk requests, the HC or TT handles these. */ if (type == PIPE_INTERRUPT) { - qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH, + qh->sw->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH, is_input, 0, hb_mult(maxp) * max_packet(maxp))); - qh->start = NO_FRAME; + qh->sw->start = NO_FRAME; if (urb->dev->speed == USB_SPEED_HIGH) { - qh->c_usecs = 0; - qh->gap_uf = 0; + qh->sw->c_usecs = 0; + qh->sw->gap_uf = 0; - qh->period = urb->interval >> 3; - if (qh->period == 0 && urb->interval != 1) { + qh->sw->period = urb->interval >> 3; + if (qh->sw->period == 0 && urb->interval != 1) { /* NOTE interval 2 or 4 uframes could work. * But interval 1 scheduling is simpler, and * includes high bandwidth. @@ -756,28 +756,28 @@ qh_make ( int think_time; /* gap is f(FS/LS transfer times) */ - qh->gap_uf = 1 + usb_calc_bus_time (urb->dev->speed, + qh->sw->gap_uf = 1 + usb_calc_bus_time(urb->dev->speed, is_input, 0, maxp) / (125 * 1000); /* FIXME this just approximates SPLIT/CSPLIT times */ if (is_input) { // SPLIT, gap, CSPLIT+DATA - qh->c_usecs = qh->usecs + HS_USECS (0); - qh->usecs = HS_USECS (1); + qh->sw->c_usecs = qh->sw->usecs + HS_USECS(0); + qh->sw->usecs = HS_USECS(1); } else { // SPLIT+DATA, gap, CSPLIT - qh->usecs += HS_USECS (1); - qh->c_usecs = HS_USECS (0); + qh->sw->usecs += HS_USECS(1); + qh->sw->c_usecs = HS_USECS(0); } think_time = tt ? tt->think_time : 0; - qh->tt_usecs = NS_TO_US (think_time + + qh->sw->tt_usecs = NS_TO_US(think_time + usb_calc_bus_time (urb->dev->speed, is_input, 0, max_packet (maxp))); - qh->period = urb->interval; + qh->sw->period = urb->interval; } } /* support for tt scheduling, and access to toggles */ - qh->dev = urb->dev; + qh->sw->dev = urb->dev; /* using TT? */ switch (urb->dev->speed) { @@ -847,7 +847,7 @@ done: /* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */ /* init as live, toggle clear, advance to dummy */ - qh->qh_state = QH_STATE_IDLE; + qh->sw->qh_state = QH_STATE_IDLE; qh->hw_info1 = cpu_to_hc32(ehci, info1); qh->hw_info2 = cpu_to_hc32(ehci, info2); usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); @@ -861,13 +861,13 @@ done: static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) { - __hc32 dma = QH_NEXT(ehci, qh->qh_dma); + __hc32 dma = QH_NEXT(ehci, qh->sw->qh_dma); struct ehci_qh *head; /* (re)start the async schedule? */ head = ehci->async; timer_action_done (ehci, TIMER_ASYNC_OFF); - if (!head->qh_next.qh) { + if (!head->sw->qh_next.qh) { u32 cmd = ehci_readl(ehci, &ehci->regs->command); if (!(cmd & CMD_ASE)) { @@ -882,19 +882,19 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) } /* clear halt and/or toggle; and maybe recover from silicon quirk */ - if (qh->qh_state == QH_STATE_IDLE) + if (qh->sw->qh_state == QH_STATE_IDLE) qh_refresh (ehci, qh); /* splice right after start */ - qh->qh_next = head->qh_next; + qh->sw->qh_next = head->sw->qh_next; qh->hw_next = head->hw_next; wmb (); - head->qh_next.qh = qh; + head->sw->qh_next.qh = qh; head->hw_next = dma; - qh->xacterrs = QH_XACTERR_MAX; - qh->qh_state = QH_STATE_LINKED; + qh->sw->xacterrs = QH_XACTERR_MAX; + qh->sw->qh_state = QH_STATE_LINKED; /* qtd completions reported later by interrupt */ } @@ -956,7 +956,7 @@ static struct ehci_qh *qh_append_tds ( token = qtd->hw_token; qtd->hw_token = HALT_BIT(ehci); wmb (); - dummy = qh->dummy; + dummy = qh->sw->dummy; dma = dummy->qtd_dma; *dummy = *qtd; @@ -964,14 +964,14 @@ static struct ehci_qh *qh_append_tds ( list_del (&qtd->qtd_list); list_add (&dummy->qtd_list, qtd_list); - list_splice_tail(qtd_list, &qh->qtd_list); + list_splice_tail(qtd_list, &qh->sw->qtd_list); ehci_qtd_init(ehci, qtd, qtd->qtd_dma); - qh->dummy = qtd; + qh->sw->dummy = qtd; /* hc must see the new dummy at list end */ dma = qtd->qtd_dma; - qtd = list_entry (qh->qtd_list.prev, + qtd = list_entry(qh->sw->qtd_list.prev, struct ehci_qtd, qtd_list); qtd->hw_next = QTD_NEXT(ehci, dma); @@ -1032,7 +1032,7 @@ submit_async ( /* Control/bulk operations through TTs don't need scheduling, * the HC and TT handle it when the TT has a buffer ready. */ - if (likely (qh->qh_state == QH_STATE_IDLE)) + if (likely(qh->sw->qh_state == QH_STATE_IDLE)) qh_link_async (ehci, qh_get (qh)); done: spin_unlock_irqrestore (&ehci->lock, flags); @@ -1052,19 +1052,19 @@ static void end_unlink_async (struct ehci_hcd *ehci) iaa_watchdog_done(ehci); - // qh->hw_next = cpu_to_hc32(qh->qh_dma); - qh->qh_state = QH_STATE_IDLE; - qh->qh_next.qh = NULL; + /* qh->hw_next = cpu_to_hc32(qh->sw->qh_dma); */ + qh->sw->qh_state = QH_STATE_IDLE; + qh->sw->qh_next.qh = NULL; qh_put (qh); // refcount from reclaim /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */ - next = qh->reclaim; + next = qh->sw->reclaim; ehci->reclaim = next; - qh->reclaim = NULL; + qh->sw->reclaim = NULL; qh_completions (ehci, qh); - if (!list_empty (&qh->qtd_list) + if (!list_empty(&qh->sw->qtd_list) && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) qh_link_async (ehci, qh); else { @@ -1074,7 +1074,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) + && ehci->async->sw->qh_next.qh == NULL) timer_action (ehci, TIMER_ASYNC_OFF); } @@ -1095,8 +1095,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) #ifdef DEBUG assert_spin_locked(&ehci->lock); if (ehci->reclaim - || (qh->qh_state != QH_STATE_LINKED - && qh->qh_state != QH_STATE_UNLINK_WAIT) + || (qh->sw->qh_state != QH_STATE_LINKED + && qh->sw->qh_state != QH_STATE_UNLINK_WAIT) ) BUG (); #endif @@ -1116,20 +1116,20 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) return; } - qh->qh_state = QH_STATE_UNLINK; + qh->sw->qh_state = QH_STATE_UNLINK; ehci->reclaim = qh = qh_get (qh); prev = ehci->async; - while (prev->qh_next.qh != qh) - prev = prev->qh_next.qh; + while (prev->sw->qh_next.qh != qh) + prev = prev->sw->qh_next.qh; prev->hw_next = qh->hw_next; - prev->qh_next = qh->qh_next; + prev->sw->qh_next = qh->sw->qh_next; wmb (); /* If the controller isn't running, we don't have to wait for it */ if (unlikely(!HC_IS_RUNNING(ehci_to_hcd(ehci)->state))) { - /* if (unlikely (qh->reclaim != 0)) + /* if (unlikely (qh->sw->reclaim != 0)) * this will recurse, probably not much */ end_unlink_async (ehci); @@ -1152,12 +1152,12 @@ 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 = ehci->async->sw->qh_next.qh; if (likely (qh != NULL)) { do { /* clean any finished work for this qh */ - if (!list_empty (&qh->qtd_list) - && qh->stamp != ehci->stamp) { + if (!list_empty(&qh->sw->qtd_list) + && qh->sw->stamp != ehci->stamp) { int temp; /* unlinks could happen here; completion @@ -1166,7 +1166,7 @@ rescan: * qhs we already finished (no looping). */ qh = qh_get (qh); - qh->stamp = ehci->stamp; + qh->sw->stamp = ehci->stamp; temp = qh_completions (ehci, qh); qh_put (qh); if (temp != 0) { @@ -1180,17 +1180,18 @@ rescan: * doesn't stay idle for long. * (plus, avoids some kind of re-activation race.) */ - if (list_empty(&qh->qtd_list) - && qh->qh_state == QH_STATE_LINKED) { + if (list_empty(&qh->sw->qtd_list) + && qh->sw->qh_state == QH_STATE_LINKED) { if (!ehci->reclaim - && ((ehci->stamp - qh->stamp) & 0x1fff) + && ((ehci->stamp - qh->sw->stamp) + & 0x1fff) >= (EHCI_SHRINK_FRAMES * 8)) start_unlink_async(ehci, qh); else action = TIMER_ASYNC_SHRINK; } - qh = qh->qh_next.qh; + qh = qh->sw->qh_next.qh; } while (qh); } if (action == TIMER_ASYNC_SHRINK) diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 556d0ec..cce6f32 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 &periodic->qh->sw->qh_next; case Q_TYPE_FSTN: return &periodic->fstn->fstn_next; case Q_TYPE_ITD: @@ -99,13 +99,13 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) 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; + usecs += q->qh->sw->usecs; /* ... or C-mask? */ if (q->qh->hw_info2 & cpu_to_hc32(ehci, 1 << (8 + uframe))) - usecs += q->qh->c_usecs; + usecs += q->qh->sw->c_usecs; hw_p = &q->qh->hw_next; - q = &q->qh->qh_next; + q = &q->qh->sw->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)) { + if (same_tt(dev, q->qh->sw->dev)) { uf = tt_start_uframe(ehci, q->qh->hw_info2); - tt_usecs[uf] += q->qh->tt_usecs; + tt_usecs[uf] += q->qh->sw->tt_usecs; } hw_p = &q->qh->hw_next; - q = &q->qh->qh_next; + q = &q->qh->sw->qh_next; continue; case Q_TYPE_SITD: if (same_tt(dev, q->sitd->urb->dev)) { @@ -385,7 +385,7 @@ 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, here.qh->sw->dev)) { u32 mask; mask = hc32_to_cpu(ehci, @@ -396,7 +396,7 @@ static int tt_no_collision ( break; } type = Q_NEXT_TYPE(ehci, here.qh->hw_next); - here = here.qh->qh_next; + here = here.qh->sw->qh_next; continue; case Q_TYPE_SITD: if (same_tt (dev, here.sitd->urb->dev)) { @@ -494,18 +494,18 @@ static int disable_periodic (struct ehci_hcd *ehci) static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) { unsigned i; - unsigned period = qh->period; + unsigned period = qh->sw->period; - dev_dbg (&qh->dev->dev, + dev_dbg(&qh->sw->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), - qh, qh->start, qh->usecs, qh->c_usecs); + qh, qh->sw->start, qh->sw->usecs, qh->sw->c_usecs); /* high bandwidth, or otherwise every microframe */ if (period == 0) period = 1; - for (i = qh->start; i < ehci->periodic_size; i += period) { + for (i = qh->sw->start; i < ehci->periodic_size; i += period) { union ehci_shadow *prev = &ehci->pshadow[i]; __hc32 *hw_p = &ehci->periodic[i]; union ehci_shadow here = *prev; @@ -525,29 +525,29 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) * enables sharing interior tree nodes */ while (here.ptr && qh != here.qh) { - if (qh->period > here.qh->period) + if (qh->sw->period > here.qh->sw->period) break; - prev = &here.qh->qh_next; + prev = &here.qh->sw->qh_next; hw_p = &here.qh->hw_next; here = *prev; } /* link in this qh, unless some earlier pass did that */ if (qh != here.qh) { - qh->qh_next = here; + qh->sw->qh_next = here; if (here.qh) qh->hw_next = *hw_p; wmb (); prev->qh = qh; - *hw_p = QH_NEXT (ehci, qh->qh_dma); + *hw_p = QH_NEXT(ehci, qh->sw->qh_dma); } } - qh->qh_state = QH_STATE_LINKED; + qh->sw->qh_state = QH_STATE_LINKED; qh_get (qh); /* update per-qh bandwidth for usbfs */ - ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->period - ? ((qh->usecs + qh->c_usecs) / qh->period) - : (qh->usecs * 8); + ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->sw->period + ? ((qh->sw->usecs + qh->sw->c_usecs) / qh->sw->period) + : (qh->sw->usecs * 8); /* maybe enable periodic schedule processing */ return enable_periodic(ehci); @@ -566,26 +566,27 @@ static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) // qh->hw_info1 |= cpu_to_hc32(1 << 7 /* "ignore" */); /* high bandwidth, or otherwise part of every microframe */ - if ((period = qh->period) == 0) + period = qh->sw->period; + if (period == 0) period = 1; - for (i = qh->start; i < ehci->periodic_size; i += period) + for (i = qh->sw->start; i < ehci->periodic_size; i += period) periodic_unlink (ehci, i, qh); /* update per-qh bandwidth for usbfs */ - ehci_to_hcd(ehci)->self.bandwidth_allocated -= qh->period - ? ((qh->usecs + qh->c_usecs) / qh->period) - : (qh->usecs * 8); + ehci_to_hcd(ehci)->self.bandwidth_allocated -= qh->sw->period + ? ((qh->sw->usecs + qh->sw->c_usecs) / qh->sw->period) + : (qh->sw->usecs * 8); - dev_dbg (&qh->dev->dev, + dev_dbg(&qh->sw->dev->dev, "unlink qh%d-%04x/%p start %d [%d/%d us]\n", - qh->period, + qh->sw->period, hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK), - qh, qh->start, qh->usecs, qh->c_usecs); + qh, qh->sw->start, qh->sw->usecs, qh->sw->c_usecs); - /* qh->qh_next still "live" to HC */ - qh->qh_state = QH_STATE_UNLINK; - qh->qh_next.ptr = NULL; + /* qh->sw->qh_next still "live" to HC */ + qh->sw->qh_state = QH_STATE_UNLINK; + qh->sw->qh_next.ptr = NULL; qh_put (qh); /* maybe turn off periodic schedule */ @@ -603,7 +604,7 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh) * expect khubd to clean up after any CSPLITs we won't issue. * active high speed queues may need bigger delays... */ - if (list_empty (&qh->qtd_list) + if (list_empty(&qh->sw->qtd_list) || (cpu_to_hc32(ehci, QH_CMASK) & qh->hw_info2) != 0) wait = 2; @@ -611,7 +612,7 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh) wait = 55; /* worst case: 3 * 1024 */ udelay (wait); - qh->qh_state = QH_STATE_IDLE; + qh->sw->qh_state = QH_STATE_IDLE; qh->hw_next = EHCI_LIST_END(ehci); wmb (); } @@ -675,26 +676,26 @@ static int check_intr_schedule ( int retval = -ENOSPC; u8 mask = 0; - if (qh->c_usecs && uframe >= 6) /* FSTN territory? */ + if (qh->sw->c_usecs && uframe >= 6) /* FSTN territory? */ goto done; - if (!check_period (ehci, frame, uframe, qh->period, qh->usecs)) + if (!check_period(ehci, frame, uframe, qh->sw->period, qh->sw->usecs)) goto done; - if (!qh->c_usecs) { + if (!qh->sw->c_usecs) { retval = 0; *c_maskp = 0; goto done; } #ifdef CONFIG_USB_EHCI_TT_NEWSCHED - if (tt_available (ehci, qh->period, qh->dev, frame, uframe, - qh->tt_usecs)) { + if (tt_available(ehci, qh->sw->period, qh->sw->dev, frame, uframe, + qh->sw->tt_usecs)) { unsigned i; /* TODO : this may need FSTN for SSPLIT in uframe 5. */ for (i=uframe+1; i<8 && i<uframe+4; i++) - if (!check_period (ehci, frame, i, - qh->period, qh->c_usecs)) + if (!check_period(ehci, frame, i, + qh->sw->period, qh->sw->c_usecs)) goto done; else mask |= 1 << i; @@ -711,16 +712,16 @@ static int check_intr_schedule ( * NOTE: both SPLIT and CSPLIT could be checked in just * one smart pass... */ - mask = 0x03 << (uframe + qh->gap_uf); + mask = 0x03 << (uframe + qh->sw->gap_uf); *c_maskp = cpu_to_hc32(ehci, mask << 8); mask |= 1 << uframe; - if (tt_no_collision (ehci, qh->period, qh->dev, frame, mask)) { - if (!check_period (ehci, frame, uframe + qh->gap_uf + 1, - qh->period, qh->c_usecs)) + if (tt_no_collision(ehci, qh->sw->period, qh->sw->dev, frame, mask)) { + if (!check_period(ehci, frame, uframe + qh->sw->gap_uf + 1, + qh->sw->period, qh->sw->c_usecs)) goto done; - if (!check_period (ehci, frame, uframe + qh->gap_uf, - qh->period, qh->c_usecs)) + if (!check_period(ehci, frame, uframe + qh->sw->gap_uf, + qh->sw->period, qh->sw->c_usecs)) goto done; retval = 0; } @@ -737,14 +738,14 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh) int status; unsigned uframe; __hc32 c_mask; - unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ + unsigned frame; /* 0..(qh->sw->period - 1), or NO_FRAME */ qh_refresh(ehci, qh); qh->hw_next = EHCI_LIST_END(ehci); - frame = qh->start; + frame = qh->sw->start; /* reuse the previous schedule slots, if we can */ - if (frame < qh->period) { + if (frame < qh->sw->period) { uframe = ffs(hc32_to_cpup(ehci, &qh->hw_info2) & QH_SMASK); status = check_intr_schedule (ehci, frame, --uframe, qh, &c_mask); @@ -759,8 +760,8 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh) */ if (status) { /* "normal" case, uframing flexible except with splits */ - if (qh->period) { - frame = qh->period - 1; + if (qh->sw->period) { + frame = qh->sw->period - 1; do { for (uframe = 0; uframe < 8; uframe++) { status = check_intr_schedule (ehci, @@ -771,18 +772,18 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh) } } while (status && frame--); - /* qh->period == 0 means every uframe */ + /* qh->sw->period == 0 means every uframe */ } else { frame = 0; status = check_intr_schedule (ehci, 0, 0, qh, &c_mask); } if (status) goto done; - qh->start = frame; + qh->sw->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 + qh->hw_info2 |= qh->sw->period ? cpu_to_hc32(ehci, 1 << uframe) : cpu_to_hc32(ehci, QH_SMASK); qh->hw_info2 |= c_mask; @@ -828,7 +829,7 @@ static int intr_submit ( status = -ENOMEM; goto done; } - if (qh->qh_state == QH_STATE_IDLE) { + if (qh->sw->qh_state == QH_STATE_IDLE) { if ((status = qh_schedule (ehci, qh)) != 0) goto done; } @@ -2182,9 +2183,10 @@ restart: /* handle any completions */ temp.qh = qh_get (q.qh); type = Q_NEXT_TYPE(ehci, q.qh->hw_next); - q = q.qh->qh_next; + q = q.qh->sw->qh_next; modified = qh_completions (ehci, temp.qh); - if (unlikely (list_empty (&temp.qh->qtd_list))) + if (unlikely( + list_empty(&temp.qh->sw->qtd_list))) intr_deschedule (ehci, temp.qh); qh_put (temp.qh); break; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index c36d22a..5e4b52c 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -298,6 +298,8 @@ union ehci_shadow { * These appear in both the async and (for interrupt) periodic schedules. */ +struct ehci_qh_sw; + struct ehci_qh { /* first part defined by EHCI spec */ __hc32 hw_next; /* see EHCI 3.6.1 */ @@ -319,6 +321,11 @@ struct ehci_qh { __hc32 hw_buf_hi [5]; /* the rest is HCD-private */ + struct ehci_qh_sw *sw; +} __attribute__ ((aligned(32))); + +/* HCD private (software) part */ +struct ehci_qh_sw { dma_addr_t qh_dma; /* address of qh */ union ehci_shadow qh_next; /* ptr to qh; or periodic */ struct list_head qtd_list; /* sw qtd list */ @@ -355,7 +362,7 @@ struct ehci_qh { unsigned short start; /* where polling starts */ #define NO_FRAME ((unsigned short)~0) /* pick new start */ struct usb_device *dev; /* access to TT */ -} __attribute__ ((aligned (32))); +}; /*-------------------------------------------------------------------------*/ -- 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