diff -Naurp -x'*~' linux-source-2.6.18/drivers/usb/host/ehci-dbg.c linux-source-2.6.18-test/drivers/usb/host/ehci-dbg.c --- linux-source-2.6.18/drivers/usb/host/ehci-dbg.c 2006-09-20 05:42:06.000000000 +0200 +++ linux-source-2.6.18-test/drivers/usb/host/ehci-dbg.c 2008-06-04 22:54:51.000000000 +0200 @@ -135,9 +135,9 @@ static void __attribute__((__unused__)) dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) { ehci_dbg (ehci, "%s qh %p n%08x info %x %x qtd %x\n", label, - qh, qh->hw_next, qh->hw_info1, qh->hw_info2, - qh->hw_current); - dbg_qtd ("overlay", ehci, (struct ehci_qtd *) &qh->hw_qtd_next); + qh, qh->qh_hw->hw_next, qh->qh_hw->hw_info1, qh->qh_hw->hw_info2, + qh->qh_hw->hw_current); + dbg_qtd ("overlay", ehci, (struct ehci_qtd *) &qh->qh_hw->hw_qtd_next); } static void __attribute__((__unused__)) @@ -361,29 +361,29 @@ static void qh_lines ( char *next = *nextp; char mark; - if (qh->hw_qtd_next == EHCI_LIST_END) /* NEC does this */ + if (qh->qh_hw->hw_qtd_next == EHCI_LIST_END) /* NEC does this */ mark = '@'; else - mark = token_mark (qh->hw_token); + mark = token_mark (qh->qh_hw->hw_token); if (mark == '/') { /* qh_alt_next controls qh advance? */ - if ((qh->hw_alt_next & QTD_MASK) == ehci->async->hw_alt_next) + if ((qh->qh_hw->hw_alt_next & QTD_MASK) == ehci->async->qh_hw->hw_alt_next) mark = '#'; /* blocked */ - else if (qh->hw_alt_next == EHCI_LIST_END) + else if (qh->qh_hw->hw_alt_next == EHCI_LIST_END) mark = '.'; /* use hw_qtd_next */ /* else alt_next points to some other qtd */ } - scratch = le32_to_cpup (&qh->hw_info1); - hw_curr = (mark == '*') ? le32_to_cpup (&qh->hw_current) : 0; + scratch = le32_to_cpup (&qh->qh_hw->hw_info1); + hw_curr = (mark == '*') ? le32_to_cpup (&qh->qh_hw->hw_current) : 0; temp = scnprintf (next, size, "qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)", qh, scratch & 0x007f, speed_char (scratch), (scratch >> 8) & 0x000f, - scratch, le32_to_cpup (&qh->hw_info2), - le32_to_cpup (&qh->hw_token), mark, - (__constant_cpu_to_le32 (QTD_TOGGLE) & qh->hw_token) + scratch, le32_to_cpup (&qh->qh_hw->hw_info2), + le32_to_cpup (&qh->qh_hw->hw_token), mark, + (__constant_cpu_to_le32 (QTD_TOGGLE) & qh->qh_hw->hw_token) ? "data1" : "data0", - (le32_to_cpup (&qh->hw_alt_next) >> 1) & 0x0f); + (le32_to_cpup (&qh->qh_hw->hw_alt_next) >> 1) & 0x0f); size -= temp; next += temp; @@ -394,10 +394,10 @@ static void qh_lines ( mark = ' '; if (hw_curr == td->qtd_dma) mark = '*'; - else if (qh->hw_qtd_next == cpu_to_le32(td->qtd_dma)) + else if (qh->qh_hw->hw_qtd_next == cpu_to_le32(td->qtd_dma)) mark = '+'; else if (QTD_LENGTH (scratch)) { - if (td->hw_alt_next == ehci->async->hw_alt_next) + if (td->hw_alt_next == ehci->async->qh_hw->hw_alt_next) mark = '#'; else if (td->hw_alt_next != EHCI_LIST_END) mark = '/'; @@ -525,7 +525,7 @@ show_periodic (struct class_device *clas case Q_TYPE_QH: temp = scnprintf (next, size, " qh%d-%04x/%p", p.qh->period, - le32_to_cpup (&p.qh->hw_info2) + le32_to_cpup (&p.qh->qh_hw->hw_info2) /* uframe masks */ & (QH_CMASK | QH_SMASK), p.qh); @@ -544,7 +544,7 @@ show_periodic (struct class_device *clas /* show more info the first time around */ if (temp == seen_count && p.ptr) { u32 scratch = le32_to_cpup ( - &p.qh->hw_info1); + &p.qh->qh_hw->hw_info1); struct ehci_qtd *qtd; char *type = ""; @@ -576,7 +576,7 @@ show_periodic (struct class_device *clas } else temp = 0; if (p.qh) { - tag = Q_NEXT_TYPE (p.qh->hw_next); + tag = Q_NEXT_TYPE (p.qh->qh_hw->hw_next); p = p.qh->qh_next; } break; diff -Naurp -x'*~' linux-source-2.6.18/drivers/usb/host/ehci.h linux-source-2.6.18-test/drivers/usb/host/ehci.h --- linux-source-2.6.18/drivers/usb/host/ehci.h 2006-09-20 05:42:06.000000000 +0200 +++ linux-source-2.6.18-test/drivers/usb/host/ehci.h 2008-06-04 22:54:51.000000000 +0200 @@ -385,7 +385,7 @@ union ehci_shadow { * These appear in both the async and (for interrupt) periodic schedules. */ -struct ehci_qh { +struct ehci_qh_hw { /* first part defined by EHCI spec */ __le32 hw_next; /* see EHCI 3.6.1 */ __le32 hw_info1; /* see EHCI 3.6.2 */ @@ -406,6 +406,10 @@ struct ehci_qh { __le32 hw_buf_hi [5]; /* the rest is HCD-private */ +}; + +struct ehci_qh { + struct ehci_qh_hw *qh_hw; 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 */ diff -Naurp -x'*~' linux-source-2.6.18/drivers/usb/host/ehci-hcd.c linux-source-2.6.18-test/drivers/usb/host/ehci-hcd.c --- linux-source-2.6.18/drivers/usb/host/ehci-hcd.c 2006-09-20 05:42:06.000000000 +0200 +++ linux-source-2.6.18-test/drivers/usb/host/ehci-hcd.c 2008-06-04 22:54:51.000000000 +0200 @@ -444,12 +444,12 @@ static int ehci_init(struct usb_hcd *hcd * from automatically advancing to the next td after short reads. */ ehci->async->qh_next.qh = NULL; - ehci->async->hw_next = QH_NEXT(ehci->async->qh_dma); - ehci->async->hw_info1 = cpu_to_le32(QH_HEAD); - ehci->async->hw_token = cpu_to_le32(QTD_STS_HALT); - ehci->async->hw_qtd_next = EHCI_LIST_END; + ehci->async->qh_hw->hw_next = QH_NEXT(ehci->async->qh_dma); + ehci->async->qh_hw->hw_info1 = cpu_to_le32(QH_HEAD); + ehci->async->qh_hw->hw_token = cpu_to_le32(QTD_STS_HALT); + ehci->async->qh_hw->hw_qtd_next = EHCI_LIST_END; ehci->async->qh_state = QH_STATE_LINKED; - ehci->async->hw_alt_next = QTD_NEXT(ehci->async->dummy->qtd_dma); + ehci->async->qh_hw->hw_alt_next = QTD_NEXT(ehci->async->dummy->qtd_dma); /* clear interrupt enables, set irq latency */ if (log2_irq_thresh < 0 || log2_irq_thresh > 6) @@ -828,7 +828,7 @@ rescan: /* endpoints can be iso streams. for now, we don't * accelerate iso completions ... so spin a while. */ - if (qh->hw_info1 == 0) { + if (qh->qh_hw->hw_info1 == 0) { ehci_vdbg (ehci, "iso delay\n"); goto idle_timeout; } diff -Naurp -x'*~' linux-source-2.6.18/drivers/usb/host/ehci-mem.c linux-source-2.6.18-test/drivers/usb/host/ehci-mem.c --- linux-source-2.6.18/drivers/usb/host/ehci-mem.c 2006-09-20 05:42:06.000000000 +0200 +++ linux-source-2.6.18-test/drivers/usb/host/ehci-mem.c 2008-06-04 22:54:51.000000000 +0200 @@ -75,23 +75,32 @@ static void qh_destroy (struct kref *kre } if (qh->dummy) ehci_qtd_free (ehci, qh->dummy); - dma_pool_free (ehci->qh_pool, qh, qh->qh_dma); + dma_pool_free (ehci->qh_pool, qh->qh_hw, qh->qh_dma); + kfree (qh); } static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) { struct ehci_qh *qh; + struct ehci_qh_hw *qh_hw; dma_addr_t dma; - qh = (struct ehci_qh *) + qh_hw = (struct ehci_qh_hw *) dma_pool_alloc (ehci->qh_pool, flags, &dma); - if (!qh) + if (!qh_hw) + return NULL; + qh = (struct ehci_qh *) + kmalloc (sizeof (struct ehci_qh), GFP_KERNEL); + if (!qh) { + dma_pool_free (ehci->qh_pool, qh_hw, dma); return qh; + } memset (qh, 0, sizeof *qh); kref_init(&qh->kref); qh->ehci = ehci; qh->qh_dma = dma; + qh->qh_hw = qh_hw; // INIT_LIST_HEAD (&qh->qh_list); INIT_LIST_HEAD (&qh->qtd_list); @@ -99,7 +108,8 @@ static struct ehci_qh *ehci_qh_alloc (st qh->dummy = ehci_qtd_alloc (ehci, flags); if (qh->dummy == NULL) { ehci_dbg (ehci, "no dummy td\n"); - dma_pool_free (ehci->qh_pool, qh, qh->qh_dma); + dma_pool_free (ehci->qh_pool, qh_hw, dma); + kfree (qh); qh = NULL; } return qh; @@ -177,7 +187,7 @@ static int ehci_mem_init (struct ehci_hc /* QHs for control/bulk/intr transfers */ ehci->qh_pool = dma_pool_create ("ehci_qh", ehci_to_hcd(ehci)->self.controller, - sizeof (struct ehci_qh), + sizeof (struct ehci_qh_hw), 32 /* byte alignment (for hw parts) */, 4096 /* can't cross 4K */); if (!ehci->qh_pool) { diff -Naurp -x'*~' linux-source-2.6.18/drivers/usb/host/ehci-q.c linux-source-2.6.18-test/drivers/usb/host/ehci-q.c --- linux-source-2.6.18/drivers/usb/host/ehci-q.c 2006-09-20 05:42:06.000000000 +0200 +++ linux-source-2.6.18-test/drivers/usb/host/ehci-q.c 2008-06-04 22:54:51.000000000 +0200 @@ -89,28 +89,28 @@ qh_update (struct ehci_hcd *ehci, struct /* writes to an active overlay are unsafe */ BUG_ON(qh->qh_state != QH_STATE_IDLE); - qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma); - qh->hw_alt_next = EHCI_LIST_END; + qh->qh_hw->hw_qtd_next = QTD_NEXT (qtd->qtd_dma); + qh->qh_hw->hw_alt_next = EHCI_LIST_END; /* Except for control endpoints, we make hardware maintain data * toggle (like OHCI) ... here (re)initialize the toggle in the QH, * and set the pseudo-toggle in udev. Only usb_clear_halt() will * ever clear it. */ - if (!(qh->hw_info1 & cpu_to_le32(1 << 14))) { + if (!(qh->qh_hw->hw_info1 & cpu_to_le32(1 << 14))) { unsigned is_out, epnum; is_out = !(qtd->hw_token & cpu_to_le32(1 << 8)); - epnum = (le32_to_cpup(&qh->hw_info1) >> 8) & 0x0f; + epnum = (le32_to_cpup(&qh->qh_hw->hw_info1) >> 8) & 0x0f; if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { - qh->hw_token &= ~__constant_cpu_to_le32 (QTD_TOGGLE); + qh->qh_hw->hw_token &= ~__constant_cpu_to_le32 (QTD_TOGGLE); usb_settoggle (qh->dev, epnum, is_out, 1); } } /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */ wmb (); - qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING); + qh->qh_hw->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING); } /* if it weren't for a common silicon quirk (writing the dummy into the qh @@ -128,7 +128,7 @@ qh_refresh (struct ehci_hcd *ehci, struc qtd = list_entry (qh->qtd_list.next, struct ehci_qtd, qtd_list); /* first qtd may already be partially processed */ - if (cpu_to_le32 (qtd->qtd_dma) == qh->hw_current) + if (cpu_to_le32 (qtd->qtd_dma) == qh->qh_hw->hw_current) qtd = NULL; } @@ -222,7 +222,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 & __constant_cpu_to_le32 (QH_SMASK)) != 0) { + if ((qh->qh_hw->hw_info2 & __constant_cpu_to_le32 (QH_SMASK)) != 0) { /* ... update hc-wide periodic stats (for usbfs) */ ehci_to_hcd(ehci)->self.bandwidth_int_reqs--; @@ -375,16 +375,16 @@ qh_completions (struct ehci_hcd *ehci, s /* token in overlay may be most current */ if (state == QH_STATE_IDLE && cpu_to_le32 (qtd->qtd_dma) - == qh->hw_current) - token = le32_to_cpu (qh->hw_token); + == qh->qh_hw->hw_current) + token = le32_to_cpu (qh->qh_hw->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_BIT & qh->hw_token) == 0) { + if ((HALT_BIT & qh->qh_hw->hw_token) == 0) { halt: - qh->hw_token |= HALT_BIT; + qh->qh_hw->hw_token |= HALT_BIT; wmb (); } } @@ -419,7 +419,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) { + if (stopped != 0 || qh->qh_hw->hw_qtd_next == EHCI_LIST_END) { switch (state) { case QH_STATE_IDLE: qh_refresh(ehci, qh); @@ -429,7 +429,7 @@ halt: * except maybe high bandwidth ... */ if ((__constant_cpu_to_le32 (QH_SMASK) - & qh->hw_info2) != 0) { + & qh->qh_hw->hw_info2) != 0) { intr_deschedule (ehci, qh); (void) qh_schedule (ehci, qh); } else @@ -543,7 +543,7 @@ qh_urb_transaction ( len -= this_qtd_len; buf += this_qtd_len; if (is_input) - qtd->hw_alt_next = ehci->async->hw_alt_next; + qtd->hw_alt_next = ehci->async->qh_hw->hw_alt_next; /* qh makes control packets use qtd toggle; maybe switch it */ if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) @@ -769,8 +769,8 @@ done: /* init as live, toggle clear, advance to dummy */ qh->qh_state = QH_STATE_IDLE; - qh->hw_info1 = cpu_to_le32 (info1); - qh->hw_info2 = cpu_to_le32 (info2); + qh->qh_hw->hw_info1 = cpu_to_le32 (info1); + qh->qh_hw->hw_info2 = cpu_to_le32 (info2); usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); qh_refresh (ehci, qh); return qh; @@ -807,11 +807,11 @@ static void qh_link_async (struct ehci_h /* splice right after start */ qh->qh_next = head->qh_next; - qh->hw_next = head->hw_next; + qh->qh_hw->hw_next = head->qh_hw->hw_next; wmb (); head->qh_next.qh = qh; - head->hw_next = dma; + head->qh_hw->hw_next = dma; qh->qh_state = QH_STATE_LINKED; /* qtd completions reported later by interrupt */ @@ -857,7 +857,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; + qh->qh_hw->hw_info1 &= ~QH_ADDR_MASK; } /* just one way to queue requests: swap with the dummy qtd. @@ -1040,7 +1040,7 @@ static void start_unlink_async (struct e while (prev->qh_next.qh != qh) prev = prev->qh_next.qh; - prev->hw_next = qh->hw_next; + prev->qh_hw->hw_next = qh->qh_hw->hw_next; prev->qh_next = qh->qh_next; wmb (); diff -Naurp -x'*~' linux-source-2.6.18/drivers/usb/host/ehci-sched.c linux-source-2.6.18-test/drivers/usb/host/ehci-sched.c --- linux-source-2.6.18/drivers/usb/host/ehci-sched.c 2006-09-20 05:42:06.000000000 +0200 +++ linux-source-2.6.18-test/drivers/usb/host/ehci-sched.c 2008-06-04 22:54:51.000000000 +0200 @@ -95,12 +95,12 @@ periodic_usecs (struct ehci_hcd *ehci, u switch (Q_NEXT_TYPE (*hw_p)) { case Q_TYPE_QH: /* is it in the S-mask? */ - if (q->qh->hw_info2 & cpu_to_le32 (1 << uframe)) + if (q->qh->qh_hw->hw_info2 & cpu_to_le32 (1 << uframe)) usecs += q->qh->usecs; /* ... or C-mask? */ - if (q->qh->hw_info2 & cpu_to_le32 (1 << (8 + uframe))) + if (q->qh->qh_hw->hw_info2 & cpu_to_le32 (1 << (8 + uframe))) usecs += q->qh->c_usecs; - hw_p = &q->qh->hw_next; + hw_p = &q->qh->qh_hw->hw_next; q = &q->qh->qh_next; break; // case Q_TYPE_FSTN: @@ -382,13 +382,13 @@ static int tt_no_collision ( if (same_tt (dev, here.qh->dev)) { u32 mask; - mask = le32_to_cpu (here.qh->hw_info2); + mask = le32_to_cpu (here.qh->qh_hw->hw_info2); /* "knows" no gap is needed */ mask |= mask >> 8; if (mask & uf_mask) break; } - type = Q_NEXT_TYPE (here.qh->hw_next); + type = Q_NEXT_TYPE (here.qh->qh_hw->hw_next); here = here.qh->qh_next; continue; case Q_TYPE_SITD: @@ -487,7 +487,7 @@ static int qh_link_periodic (struct ehci dev_dbg (&qh->dev->dev, "link qh%d-%04x/%p start %d [%d/%d us]\n", - period, le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK), + period, le32_to_cpup (&qh->qh_hw->hw_info2) & (QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs, qh->c_usecs); /* high bandwidth, or otherwise every microframe */ @@ -506,7 +506,7 @@ static int qh_link_periodic (struct ehci if (type == Q_TYPE_QH) break; prev = periodic_next_shadow (prev, type); - hw_p = &here.qh->hw_next; + hw_p = &here.qh->qh_hw->hw_next; here = *prev; } @@ -517,14 +517,14 @@ static int qh_link_periodic (struct ehci if (qh->period > here.qh->period) break; prev = &here.qh->qh_next; - hw_p = &here.qh->hw_next; + hw_p = &here.qh->qh_hw->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; + qh->qh_hw->hw_next = *hw_p; wmb (); prev->qh = qh; *hw_p = QH_NEXT (qh->qh_dma); @@ -572,7 +572,7 @@ static void qh_unlink_periodic (struct e dev_dbg (&qh->dev->dev, "unlink qh%d-%04x/%p start %d [%d/%d us]\n", qh->period, - le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK), + le32_to_cpup (&qh->qh_hw->hw_info2) & (QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs, qh->c_usecs); /* qh->qh_next still "live" to HC */ @@ -599,14 +599,14 @@ static void intr_deschedule (struct ehci */ if (list_empty (&qh->qtd_list) || (__constant_cpu_to_le32 (QH_CMASK) - & qh->hw_info2) != 0) + & qh->qh_hw->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; + qh->qh_hw->hw_next = EHCI_LIST_END; wmb (); } @@ -734,12 +734,12 @@ static int qh_schedule (struct ehci_hcd unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ qh_refresh(ehci, qh); - qh->hw_next = EHCI_LIST_END; + qh->qh_hw->hw_next = EHCI_LIST_END; frame = qh->start; /* reuse the previous schedule slots, if we can */ if (frame < qh->period) { - uframe = ffs (le32_to_cpup (&qh->hw_info2) & QH_SMASK); + uframe = ffs (le32_to_cpup (&qh->qh_hw->hw_info2) & QH_SMASK); status = check_intr_schedule (ehci, frame, --uframe, qh, &c_mask); } else { @@ -775,11 +775,11 @@ static int qh_schedule (struct ehci_hcd qh->start = frame; /* reset S-frame and (maybe) C-frame masks */ - qh->hw_info2 &= __constant_cpu_to_le32(~(QH_CMASK | QH_SMASK)); - qh->hw_info2 |= qh->period + qh->qh_hw->hw_info2 &= __constant_cpu_to_le32(~(QH_CMASK | QH_SMASK)); + qh->qh_hw->hw_info2 |= qh->period ? cpu_to_le32 (1 << uframe) : __constant_cpu_to_le32 (QH_SMASK); - qh->hw_info2 |= c_mask; + qh->qh_hw->hw_info2 |= c_mask; } else ehci_dbg (ehci, "reused qh %p schedule\n", qh); @@ -2129,7 +2129,7 @@ restart: case Q_TYPE_QH: /* handle any completions */ temp.qh = qh_get (q.qh); - type = Q_NEXT_TYPE (q.qh->hw_next); + type = Q_NEXT_TYPE (q.qh->qh_hw->hw_next); q = q.qh->qh_next; modified = qh_completions (ehci, temp.qh, regs); if (unlikely (list_empty (&temp.qh->qtd_list)))