Commit 3807e26d authored by Alek Du's avatar Alek Du Committed by Greg Kroah-Hartman

USB: EHCI: split ehci_qh into hw and sw parts

The ehci_qh structure merged hw and sw together which is not good:
1. More and more items are being added into ehci_qh, the ehci_qh software
   part are unnecessary to be allocated in DMA qh_pool.
2. If HCD has local SRAM, the sw part will consume it too, and it won't
   bring any benefit.
3. For non-cache-coherence system, the entire ehci_qh is uncachable, actually
   we only need the hw part to be uncacheable. Spliting them will let the sw
   part to be cacheable.
Signed-off-by: default avatarAlek Du <alek.du@intel.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
CC: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 403dbd36
...@@ -134,10 +134,11 @@ dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd) ...@@ -134,10 +134,11 @@ dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
static void __maybe_unused static void __maybe_unused
dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
{ {
struct ehci_qh_hw *hw = qh->hw;
ehci_dbg (ehci, "%s qh %p n%08x info %x %x qtd %x\n", label, 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->hw_next, hw->hw_info1, hw->hw_info2, hw->hw_current);
qh->hw_current); dbg_qtd("overlay", ehci, (struct ehci_qtd *) &hw->hw_qtd_next);
dbg_qtd ("overlay", ehci, (struct ehci_qtd *) &qh->hw_qtd_next);
} }
static void __maybe_unused static void __maybe_unused
...@@ -400,31 +401,32 @@ static void qh_lines ( ...@@ -400,31 +401,32 @@ static void qh_lines (
char *next = *nextp; char *next = *nextp;
char mark; char mark;
__le32 list_end = EHCI_LIST_END(ehci); __le32 list_end = EHCI_LIST_END(ehci);
struct ehci_qh_hw *hw = qh->hw;
if (qh->hw_qtd_next == list_end) /* NEC does this */ if (hw->hw_qtd_next == list_end) /* NEC does this */
mark = '@'; mark = '@';
else else
mark = token_mark(ehci, qh->hw_token); mark = token_mark(ehci, hw->hw_token);
if (mark == '/') { /* qh_alt_next controls qh advance? */ if (mark == '/') { /* qh_alt_next controls qh advance? */
if ((qh->hw_alt_next & QTD_MASK(ehci)) if ((hw->hw_alt_next & QTD_MASK(ehci))
== ehci->async->hw_alt_next) == ehci->async->hw->hw_alt_next)
mark = '#'; /* blocked */ mark = '#'; /* blocked */
else if (qh->hw_alt_next == list_end) else if (hw->hw_alt_next == list_end)
mark = '.'; /* use hw_qtd_next */ mark = '.'; /* use hw_qtd_next */
/* else alt_next points to some other qtd */ /* else alt_next points to some other qtd */
} }
scratch = hc32_to_cpup(ehci, &qh->hw_info1); scratch = hc32_to_cpup(ehci, &hw->hw_info1);
hw_curr = (mark == '*') ? hc32_to_cpup(ehci, &qh->hw_current) : 0; hw_curr = (mark == '*') ? hc32_to_cpup(ehci, &hw->hw_current) : 0;
temp = scnprintf (next, size, temp = scnprintf (next, size,
"qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)", "qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)",
qh, scratch & 0x007f, qh, scratch & 0x007f,
speed_char (scratch), speed_char (scratch),
(scratch >> 8) & 0x000f, (scratch >> 8) & 0x000f,
scratch, hc32_to_cpup(ehci, &qh->hw_info2), scratch, hc32_to_cpup(ehci, &hw->hw_info2),
hc32_to_cpup(ehci, &qh->hw_token), mark, hc32_to_cpup(ehci, &hw->hw_token), mark,
(cpu_to_hc32(ehci, QTD_TOGGLE) & qh->hw_token) (cpu_to_hc32(ehci, QTD_TOGGLE) & hw->hw_token)
? "data1" : "data0", ? "data1" : "data0",
(hc32_to_cpup(ehci, &qh->hw_alt_next) >> 1) & 0x0f); (hc32_to_cpup(ehci, &hw->hw_alt_next) >> 1) & 0x0f);
size -= temp; size -= temp;
next += temp; next += temp;
...@@ -435,10 +437,10 @@ static void qh_lines ( ...@@ -435,10 +437,10 @@ static void qh_lines (
mark = ' '; mark = ' ';
if (hw_curr == td->qtd_dma) if (hw_curr == td->qtd_dma)
mark = '*'; mark = '*';
else if (qh->hw_qtd_next == cpu_to_hc32(ehci, td->qtd_dma)) else if (hw->hw_qtd_next == cpu_to_hc32(ehci, td->qtd_dma))
mark = '+'; mark = '+';
else if (QTD_LENGTH (scratch)) { else if (QTD_LENGTH (scratch)) {
if (td->hw_alt_next == ehci->async->hw_alt_next) if (td->hw_alt_next == ehci->async->hw->hw_alt_next)
mark = '#'; mark = '#';
else if (td->hw_alt_next != list_end) else if (td->hw_alt_next != list_end)
mark = '/'; mark = '/';
...@@ -550,12 +552,15 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf) ...@@ -550,12 +552,15 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
next += temp; next += temp;
do { do {
struct ehci_qh_hw *hw;
switch (hc32_to_cpu(ehci, tag)) { switch (hc32_to_cpu(ehci, tag)) {
case Q_TYPE_QH: case Q_TYPE_QH:
hw = p.qh->hw;
temp = scnprintf (next, size, " qh%d-%04x/%p", temp = scnprintf (next, size, " qh%d-%04x/%p",
p.qh->period, p.qh->period,
hc32_to_cpup(ehci, hc32_to_cpup(ehci,
&p.qh->hw_info2) &hw->hw_info2)
/* uframe masks */ /* uframe masks */
& (QH_CMASK | QH_SMASK), & (QH_CMASK | QH_SMASK),
p.qh); p.qh);
...@@ -576,7 +581,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf) ...@@ -576,7 +581,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
/* show more info the first time around */ /* show more info the first time around */
if (temp == seen_count) { if (temp == seen_count) {
u32 scratch = hc32_to_cpup(ehci, u32 scratch = hc32_to_cpup(ehci,
&p.qh->hw_info1); &hw->hw_info1);
struct ehci_qtd *qtd; struct ehci_qtd *qtd;
char *type = ""; char *type = "";
...@@ -609,7 +614,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf) ...@@ -609,7 +614,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
} else } else
temp = 0; temp = 0;
if (p.qh) { if (p.qh) {
tag = Q_NEXT_TYPE(ehci, p.qh->hw_next); tag = Q_NEXT_TYPE(ehci, hw->hw_next);
p = p.qh->qh_next; p = p.qh->qh_next;
} }
break; break;
......
...@@ -507,6 +507,7 @@ static int ehci_init(struct usb_hcd *hcd) ...@@ -507,6 +507,7 @@ static int ehci_init(struct usb_hcd *hcd)
u32 temp; u32 temp;
int retval; int retval;
u32 hcc_params; u32 hcc_params;
struct ehci_qh_hw *hw;
spin_lock_init(&ehci->lock); spin_lock_init(&ehci->lock);
...@@ -550,12 +551,13 @@ static int ehci_init(struct usb_hcd *hcd) ...@@ -550,12 +551,13 @@ static int ehci_init(struct usb_hcd *hcd)
* from automatically advancing to the next td after short reads. * from automatically advancing to the next td after short reads.
*/ */
ehci->async->qh_next.qh = NULL; ehci->async->qh_next.qh = NULL;
ehci->async->hw_next = QH_NEXT(ehci, ehci->async->qh_dma); hw = ehci->async->hw;
ehci->async->hw_info1 = cpu_to_hc32(ehci, QH_HEAD); hw->hw_next = QH_NEXT(ehci, ehci->async->qh_dma);
ehci->async->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT); hw->hw_info1 = cpu_to_hc32(ehci, QH_HEAD);
ehci->async->hw_qtd_next = EHCI_LIST_END(ehci); hw->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
hw->hw_qtd_next = EHCI_LIST_END(ehci);
ehci->async->qh_state = QH_STATE_LINKED; ehci->async->qh_state = QH_STATE_LINKED;
ehci->async->hw_alt_next = QTD_NEXT(ehci, ehci->async->dummy->qtd_dma); hw->hw_alt_next = QTD_NEXT(ehci, ehci->async->dummy->qtd_dma);
/* clear interrupt enables, set irq latency */ /* clear interrupt enables, set irq latency */
if (log2_irq_thresh < 0 || log2_irq_thresh > 6) if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
...@@ -985,7 +987,7 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) ...@@ -985,7 +987,7 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep)
/* endpoints can be iso streams. for now, we don't /* endpoints can be iso streams. for now, we don't
* accelerate iso completions ... so spin a while. * accelerate iso completions ... so spin a while.
*/ */
if (qh->hw_info1 == 0) { if (qh->hw->hw_info1 == 0) {
ehci_vdbg (ehci, "iso delay\n"); ehci_vdbg (ehci, "iso delay\n");
goto idle_timeout; goto idle_timeout;
} }
......
...@@ -75,7 +75,8 @@ static void qh_destroy(struct ehci_qh *qh) ...@@ -75,7 +75,8 @@ static void qh_destroy(struct ehci_qh *qh)
} }
if (qh->dummy) if (qh->dummy)
ehci_qtd_free (ehci, 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->hw, qh->qh_dma);
kfree(qh);
} }
static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
...@@ -83,12 +84,14 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) ...@@ -83,12 +84,14 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
struct ehci_qh *qh; struct ehci_qh *qh;
dma_addr_t dma; dma_addr_t dma;
qh = (struct ehci_qh *) qh = kzalloc(sizeof *qh, GFP_ATOMIC);
dma_pool_alloc (ehci->qh_pool, flags, &dma);
if (!qh) if (!qh)
return qh; goto done;
qh->hw = (struct ehci_qh_hw *)
memset (qh, 0, sizeof *qh); dma_pool_alloc(ehci->qh_pool, flags, &dma);
if (!qh->hw)
goto fail;
memset(qh->hw, 0, sizeof *qh->hw);
qh->refcount = 1; qh->refcount = 1;
qh->ehci = ehci; qh->ehci = ehci;
qh->qh_dma = dma; qh->qh_dma = dma;
...@@ -99,10 +102,15 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) ...@@ -99,10 +102,15 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
qh->dummy = ehci_qtd_alloc (ehci, flags); qh->dummy = ehci_qtd_alloc (ehci, flags);
if (qh->dummy == NULL) { if (qh->dummy == NULL) {
ehci_dbg (ehci, "no dummy td\n"); ehci_dbg (ehci, "no dummy td\n");
dma_pool_free (ehci->qh_pool, qh, qh->qh_dma); goto fail1;
qh = NULL;
} }
done:
return qh; return qh;
fail1:
dma_pool_free(ehci->qh_pool, qh->hw, qh->qh_dma);
fail:
kfree(qh);
return NULL;
} }
/* to share a qh (cpu threads, or hc) */ /* to share a qh (cpu threads, or hc) */
...@@ -180,7 +188,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags) ...@@ -180,7 +188,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
/* QHs for control/bulk/intr transfers */ /* QHs for control/bulk/intr transfers */
ehci->qh_pool = dma_pool_create ("ehci_qh", ehci->qh_pool = dma_pool_create ("ehci_qh",
ehci_to_hcd(ehci)->self.controller, ehci_to_hcd(ehci)->self.controller,
sizeof (struct ehci_qh), sizeof(struct ehci_qh_hw),
32 /* byte alignment (for hw parts) */, 32 /* byte alignment (for hw parts) */,
4096 /* can't cross 4K */); 4096 /* can't cross 4K */);
if (!ehci->qh_pool) { if (!ehci->qh_pool) {
......
...@@ -87,31 +87,33 @@ qtd_fill(struct ehci_hcd *ehci, struct ehci_qtd *qtd, dma_addr_t buf, ...@@ -87,31 +87,33 @@ qtd_fill(struct ehci_hcd *ehci, struct ehci_qtd *qtd, dma_addr_t buf,
static inline void static inline void
qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
{ {
struct ehci_qh_hw *hw = qh->hw;
/* writes to an active overlay are unsafe */ /* writes to an active overlay are unsafe */
BUG_ON(qh->qh_state != QH_STATE_IDLE); BUG_ON(qh->qh_state != QH_STATE_IDLE);
qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma); hw->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);
qh->hw_alt_next = EHCI_LIST_END(ehci); hw->hw_alt_next = EHCI_LIST_END(ehci);
/* Except for control endpoints, we make hardware maintain data /* Except for control endpoints, we make hardware maintain data
* toggle (like OHCI) ... here (re)initialize the toggle in the QH, * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
* and set the pseudo-toggle in udev. Only usb_clear_halt() will * and set the pseudo-toggle in udev. Only usb_clear_halt() will
* ever clear it. * ever clear it.
*/ */
if (!(qh->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) { if (!(hw->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
unsigned is_out, epnum; unsigned is_out, epnum;
is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8)); is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8));
epnum = (hc32_to_cpup(ehci, &qh->hw_info1) >> 8) & 0x0f; epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f;
if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
usb_settoggle (qh->dev, epnum, is_out, 1); usb_settoggle (qh->dev, epnum, is_out, 1);
} }
} }
/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */ /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
wmb (); wmb ();
qh->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING); hw->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 /* if it weren't for a common silicon quirk (writing the dummy into the qh
...@@ -129,7 +131,7 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -129,7 +131,7 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
qtd = list_entry (qh->qtd_list.next, qtd = list_entry (qh->qtd_list.next,
struct ehci_qtd, qtd_list); struct ehci_qtd, qtd_list);
/* first qtd may already be partially processed */ /* 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) == qh->hw->hw_current)
qtd = NULL; qtd = NULL;
} }
...@@ -260,7 +262,7 @@ __acquires(ehci->lock) ...@@ -260,7 +262,7 @@ __acquires(ehci->lock)
struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv; struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv;
/* S-mask in a QH means it's an interrupt urb */ /* S-mask in a QH means it's an interrupt urb */
if ((qh->hw_info2 & cpu_to_hc32(ehci, QH_SMASK)) != 0) { if ((qh->hw->hw_info2 & cpu_to_hc32(ehci, QH_SMASK)) != 0) {
/* ... update hc-wide periodic stats (for usbfs) */ /* ... update hc-wide periodic stats (for usbfs) */
ehci_to_hcd(ehci)->self.bandwidth_int_reqs--; ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
...@@ -315,6 +317,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -315,6 +317,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
unsigned count = 0; unsigned count = 0;
u8 state; u8 state;
__le32 halt = HALT_BIT(ehci); __le32 halt = HALT_BIT(ehci);
struct ehci_qh_hw *hw = qh->hw;
if (unlikely (list_empty (&qh->qtd_list))) if (unlikely (list_empty (&qh->qtd_list)))
return count; return count;
...@@ -392,7 +395,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -392,7 +395,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
qtd->hw_token = cpu_to_hc32(ehci, qtd->hw_token = cpu_to_hc32(ehci,
token); token);
wmb(); wmb();
qh->hw_token = cpu_to_hc32(ehci, token); hw->hw_token = cpu_to_hc32(ehci,
token);
goto retry_xacterr; goto retry_xacterr;
} }
stopped = 1; stopped = 1;
...@@ -435,8 +439,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -435,8 +439,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* qh unlinked; token in overlay may be most current */ /* qh unlinked; token in overlay may be most current */
if (state == QH_STATE_IDLE if (state == QH_STATE_IDLE
&& cpu_to_hc32(ehci, qtd->qtd_dma) && cpu_to_hc32(ehci, qtd->qtd_dma)
== qh->hw_current) { == hw->hw_current) {
token = hc32_to_cpu(ehci, qh->hw_token); token = hc32_to_cpu(ehci, hw->hw_token);
/* An unlink may leave an incomplete /* An unlink may leave an incomplete
* async transaction in the TT buffer. * async transaction in the TT buffer.
...@@ -449,9 +453,9 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -449,9 +453,9 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
* patch the qh later and so that completions can't * patch the qh later and so that completions can't
* activate it while we "know" it's stopped. * activate it while we "know" it's stopped.
*/ */
if ((halt & qh->hw_token) == 0) { if ((halt & hw->hw_token) == 0) {
halt: halt:
qh->hw_token |= halt; hw->hw_token |= halt;
wmb (); wmb ();
} }
} }
...@@ -510,7 +514,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -510,7 +514,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
* it after fault cleanup, or recovering from silicon wrongly * it after fault cleanup, or recovering from silicon wrongly
* overlaying the dummy qtd (which reduces DMA chatter). * overlaying the dummy qtd (which reduces DMA chatter).
*/ */
if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END(ehci)) { if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci)) {
switch (state) { switch (state) {
case QH_STATE_IDLE: case QH_STATE_IDLE:
qh_refresh(ehci, qh); qh_refresh(ehci, qh);
...@@ -528,7 +532,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -528,7 +532,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
* except maybe high bandwidth ... * except maybe high bandwidth ...
*/ */
if ((cpu_to_hc32(ehci, QH_SMASK) if ((cpu_to_hc32(ehci, QH_SMASK)
& qh->hw_info2) != 0) { & hw->hw_info2) != 0) {
intr_deschedule (ehci, qh); intr_deschedule (ehci, qh);
(void) qh_schedule (ehci, qh); (void) qh_schedule (ehci, qh);
} else } else
...@@ -649,7 +653,7 @@ qh_urb_transaction ( ...@@ -649,7 +653,7 @@ qh_urb_transaction (
* (this will usually be overridden later.) * (this will usually be overridden later.)
*/ */
if (is_input) if (is_input)
qtd->hw_alt_next = ehci->async->hw_alt_next; qtd->hw_alt_next = ehci->async->hw->hw_alt_next;
/* qh makes control packets use qtd toggle; maybe switch it */ /* qh makes control packets use qtd toggle; maybe switch it */
if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
...@@ -744,6 +748,7 @@ qh_make ( ...@@ -744,6 +748,7 @@ qh_make (
int is_input, type; int is_input, type;
int maxp = 0; int maxp = 0;
struct usb_tt *tt = urb->dev->tt; struct usb_tt *tt = urb->dev->tt;
struct ehci_qh_hw *hw;
if (!qh) if (!qh)
return qh; return qh;
...@@ -890,8 +895,9 @@ qh_make ( ...@@ -890,8 +895,9 @@ qh_make (
/* init as live, toggle clear, advance to dummy */ /* init as live, toggle clear, advance to dummy */
qh->qh_state = QH_STATE_IDLE; qh->qh_state = QH_STATE_IDLE;
qh->hw_info1 = cpu_to_hc32(ehci, info1); hw = qh->hw;
qh->hw_info2 = cpu_to_hc32(ehci, info2); hw->hw_info1 = cpu_to_hc32(ehci, info1);
hw->hw_info2 = cpu_to_hc32(ehci, info2);
usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
qh_refresh (ehci, qh); qh_refresh (ehci, qh);
return qh; return qh;
...@@ -933,11 +939,11 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -933,11 +939,11 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* splice right after start */ /* splice right after start */
qh->qh_next = head->qh_next; qh->qh_next = head->qh_next;
qh->hw_next = head->hw_next; qh->hw->hw_next = head->hw->hw_next;
wmb (); wmb ();
head->qh_next.qh = qh; head->qh_next.qh = qh;
head->hw_next = dma; head->hw->hw_next = dma;
qh_get(qh); qh_get(qh);
qh->xacterrs = 0; qh->xacterrs = 0;
...@@ -984,7 +990,7 @@ static struct ehci_qh *qh_append_tds ( ...@@ -984,7 +990,7 @@ static struct ehci_qh *qh_append_tds (
/* usb_reset_device() briefly reverts to address 0 */ /* usb_reset_device() briefly reverts to address 0 */
if (usb_pipedevice (urb->pipe) == 0) if (usb_pipedevice (urb->pipe) == 0)
qh->hw_info1 &= ~qh_addr_mask; qh->hw->hw_info1 &= ~qh_addr_mask;
} }
/* just one way to queue requests: swap with the dummy qtd. /* just one way to queue requests: swap with the dummy qtd.
...@@ -1169,7 +1175,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -1169,7 +1175,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
while (prev->qh_next.qh != qh) while (prev->qh_next.qh != qh)
prev = prev->qh_next.qh; prev = prev->qh_next.qh;
prev->hw_next = qh->hw_next; prev->hw->hw_next = qh->hw->hw_next;
prev->qh_next = qh->qh_next; prev->qh_next = qh->qh_next;
wmb (); wmb ();
......
...@@ -60,6 +60,20 @@ periodic_next_shadow(struct ehci_hcd *ehci, union ehci_shadow *periodic, ...@@ -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 &periodic->qh->hw->hw_next;
/* others are hw parts */
default:
return periodic->hw_next;
}
}
/* caller must hold ehci->lock */ /* caller must hold ehci->lock */
static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) 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) ...@@ -71,7 +85,8 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
while (here.ptr && here.ptr != ptr) { while (here.ptr && here.ptr != ptr) {
prev_p = periodic_next_shadow(ehci, prev_p, prev_p = periodic_next_shadow(ehci, prev_p,
Q_NEXT_TYPE(ehci, *hw_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; here = *prev_p;
} }
/* an interrupt entry (at list end) could have been shared */ /* 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) ...@@ -83,7 +98,7 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
*/ */
*prev_p = *periodic_next_shadow(ehci, &here, *prev_p = *periodic_next_shadow(ehci, &here,
Q_NEXT_TYPE(ehci, *hw_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));
} }
/* how many of the uframe's 125 usecs are allocated? */ /* how many of the uframe's 125 usecs are allocated? */
...@@ -93,18 +108,20 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) ...@@ -93,18 +108,20 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
__hc32 *hw_p = &ehci->periodic [frame]; __hc32 *hw_p = &ehci->periodic [frame];
union ehci_shadow *q = &ehci->pshadow [frame]; union ehci_shadow *q = &ehci->pshadow [frame];
unsigned usecs = 0; unsigned usecs = 0;
struct ehci_qh_hw *hw;
while (q->ptr) { while (q->ptr) {
switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) { switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) {
case Q_TYPE_QH: case Q_TYPE_QH:
hw = q->qh->hw;
/* is it in the S-mask? */ /* is it in the S-mask? */
if (q->qh->hw_info2 & cpu_to_hc32(ehci, 1 << uframe)) if (hw->hw_info2 & cpu_to_hc32(ehci, 1 << uframe))
usecs += q->qh->usecs; usecs += q->qh->usecs;
/* ... or C-mask? */ /* ... or C-mask? */
if (q->qh->hw_info2 & cpu_to_hc32(ehci, if (hw->hw_info2 & cpu_to_hc32(ehci,
1 << (8 + uframe))) 1 << (8 + uframe)))
usecs += q->qh->c_usecs; usecs += q->qh->c_usecs;
hw_p = &q->qh->hw_next; hw_p = &hw->hw_next;
q = &q->qh->qh_next; q = &q->qh->qh_next;
break; break;
// case Q_TYPE_FSTN: // case Q_TYPE_FSTN:
...@@ -237,10 +254,10 @@ periodic_tt_usecs ( ...@@ -237,10 +254,10 @@ periodic_tt_usecs (
continue; continue;
case Q_TYPE_QH: case Q_TYPE_QH:
if (same_tt(dev, q->qh->dev)) { if (same_tt(dev, q->qh->dev)) {
uf = tt_start_uframe(ehci, q->qh->hw_info2); uf = tt_start_uframe(ehci, q->qh->hw->hw_info2);
tt_usecs[uf] += q->qh->tt_usecs; tt_usecs[uf] += q->qh->tt_usecs;
} }
hw_p = &q->qh->hw_next; hw_p = &q->qh->hw->hw_next;
q = &q->qh->qh_next; q = &q->qh->qh_next;
continue; continue;
case Q_TYPE_SITD: case Q_TYPE_SITD:
...@@ -375,6 +392,7 @@ static int tt_no_collision ( ...@@ -375,6 +392,7 @@ static int tt_no_collision (
for (; frame < ehci->periodic_size; frame += period) { for (; frame < ehci->periodic_size; frame += period) {
union ehci_shadow here; union ehci_shadow here;
__hc32 type; __hc32 type;
struct ehci_qh_hw *hw;
here = ehci->pshadow [frame]; here = ehci->pshadow [frame];
type = Q_NEXT_TYPE(ehci, ehci->periodic [frame]); type = Q_NEXT_TYPE(ehci, ehci->periodic [frame]);
...@@ -385,17 +403,18 @@ static int tt_no_collision ( ...@@ -385,17 +403,18 @@ static int tt_no_collision (
here = here.itd->itd_next; here = here.itd->itd_next;
continue; continue;
case Q_TYPE_QH: case Q_TYPE_QH:
hw = here.qh->hw;
if (same_tt (dev, here.qh->dev)) { if (same_tt (dev, here.qh->dev)) {
u32 mask; u32 mask;
mask = hc32_to_cpu(ehci, mask = hc32_to_cpu(ehci,
here.qh->hw_info2); hw->hw_info2);
/* "knows" no gap is needed */ /* "knows" no gap is needed */
mask |= mask >> 8; mask |= mask >> 8;
if (mask & uf_mask) if (mask & uf_mask)
break; break;
} }
type = Q_NEXT_TYPE(ehci, here.qh->hw_next); type = Q_NEXT_TYPE(ehci, hw->hw_next);
here = here.qh->qh_next; here = here.qh->qh_next;
continue; continue;
case Q_TYPE_SITD: case Q_TYPE_SITD:
...@@ -498,7 +517,8 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -498,7 +517,8 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
dev_dbg (&qh->dev->dev, dev_dbg (&qh->dev->dev,
"link qh%d-%04x/%p start %d [%d/%d us]\n", "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, &qh->hw->hw_info2)
& (QH_CMASK | QH_SMASK),
qh, qh->start, qh->usecs, qh->c_usecs); qh, qh->start, qh->usecs, qh->c_usecs);
/* high bandwidth, or otherwise every microframe */ /* high bandwidth, or otherwise every microframe */
...@@ -517,7 +537,7 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -517,7 +537,7 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (type == cpu_to_hc32(ehci, Q_TYPE_QH)) if (type == cpu_to_hc32(ehci, Q_TYPE_QH))
break; break;
prev = periodic_next_shadow(ehci, prev, type); prev = periodic_next_shadow(ehci, prev, type);
hw_p = &here.qh->hw_next; hw_p = shadow_next_periodic(ehci, &here, type);
here = *prev; here = *prev;
} }
...@@ -528,14 +548,14 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -528,14 +548,14 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (qh->period > here.qh->period) if (qh->period > here.qh->period)
break; break;
prev = &here.qh->qh_next; prev = &here.qh->qh_next;
hw_p = &here.qh->hw_next; hw_p = &here.qh->hw->hw_next;
here = *prev; here = *prev;
} }
/* link in this qh, unless some earlier pass did that */ /* link in this qh, unless some earlier pass did that */
if (qh != here.qh) { if (qh != here.qh) {
qh->qh_next = here; qh->qh_next = here;
if (here.qh) if (here.qh)
qh->hw_next = *hw_p; qh->hw->hw_next = *hw_p;
wmb (); wmb ();
prev->qh = qh; prev->qh = qh;
*hw_p = QH_NEXT (ehci, qh->qh_dma); *hw_p = QH_NEXT (ehci, qh->qh_dma);
...@@ -581,7 +601,7 @@ static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -581,7 +601,7 @@ static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
dev_dbg (&qh->dev->dev, dev_dbg (&qh->dev->dev,
"unlink qh%d-%04x/%p start %d [%d/%d us]\n", "unlink qh%d-%04x/%p start %d [%d/%d us]\n",
qh->period, qh->period,
hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK), hc32_to_cpup(ehci, &qh->hw->hw_info2) & (QH_CMASK | QH_SMASK),
qh, qh->start, qh->usecs, qh->c_usecs); qh, qh->start, qh->usecs, qh->c_usecs);
/* qh->qh_next still "live" to HC */ /* qh->qh_next still "live" to HC */
...@@ -596,6 +616,7 @@ static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -596,6 +616,7 @@ static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh) static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
{ {
unsigned wait; unsigned wait;
struct ehci_qh_hw *hw = qh->hw;
qh_unlink_periodic (ehci, qh); qh_unlink_periodic (ehci, qh);
...@@ -606,14 +627,14 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -606,14 +627,14 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
*/ */
if (list_empty (&qh->qtd_list) if (list_empty (&qh->qtd_list)
|| (cpu_to_hc32(ehci, QH_CMASK) || (cpu_to_hc32(ehci, QH_CMASK)
& qh->hw_info2) != 0) & hw->hw_info2) != 0)
wait = 2; wait = 2;
else else
wait = 55; /* worst case: 3 * 1024 */ wait = 55; /* worst case: 3 * 1024 */
udelay (wait); udelay (wait);
qh->qh_state = QH_STATE_IDLE; qh->qh_state = QH_STATE_IDLE;
qh->hw_next = EHCI_LIST_END(ehci); hw->hw_next = EHCI_LIST_END(ehci);
wmb (); wmb ();
} }
...@@ -739,14 +760,15 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -739,14 +760,15 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
unsigned uframe; unsigned uframe;
__hc32 c_mask; __hc32 c_mask;
unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */
struct ehci_qh_hw *hw = qh->hw;
qh_refresh(ehci, qh); qh_refresh(ehci, qh);
qh->hw_next = EHCI_LIST_END(ehci); hw->hw_next = EHCI_LIST_END(ehci);
frame = qh->start; frame = qh->start;
/* reuse the previous schedule slots, if we can */ /* reuse the previous schedule slots, if we can */
if (frame < qh->period) { if (frame < qh->period) {
uframe = ffs(hc32_to_cpup(ehci, &qh->hw_info2) & QH_SMASK); uframe = ffs(hc32_to_cpup(ehci, &hw->hw_info2) & QH_SMASK);
status = check_intr_schedule (ehci, frame, --uframe, status = check_intr_schedule (ehci, frame, --uframe,
qh, &c_mask); qh, &c_mask);
} else { } else {
...@@ -784,11 +806,11 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -784,11 +806,11 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
qh->start = frame; qh->start = frame;
/* reset S-frame and (maybe) C-frame masks */ /* reset S-frame and (maybe) C-frame masks */
qh->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK)); hw->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK));
qh->hw_info2 |= qh->period hw->hw_info2 |= qh->period
? cpu_to_hc32(ehci, 1 << uframe) ? cpu_to_hc32(ehci, 1 << uframe)
: cpu_to_hc32(ehci, QH_SMASK); : cpu_to_hc32(ehci, QH_SMASK);
qh->hw_info2 |= c_mask; hw->hw_info2 |= c_mask;
} else } else
ehci_dbg (ehci, "reused qh %p schedule\n", qh); ehci_dbg (ehci, "reused qh %p schedule\n", qh);
...@@ -2188,7 +2210,7 @@ scan_periodic (struct ehci_hcd *ehci) ...@@ -2188,7 +2210,7 @@ scan_periodic (struct ehci_hcd *ehci)
case Q_TYPE_QH: case Q_TYPE_QH:
/* handle any completions */ /* handle any completions */
temp.qh = qh_get (q.qh); temp.qh = qh_get (q.qh);
type = Q_NEXT_TYPE(ehci, q.qh->hw_next); type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next);
q = q.qh->qh_next; q = q.qh->qh_next;
modified = qh_completions (ehci, temp.qh); modified = qh_completions (ehci, temp.qh);
if (unlikely (list_empty (&temp.qh->qtd_list))) if (unlikely (list_empty (&temp.qh->qtd_list)))
......
...@@ -299,8 +299,8 @@ union ehci_shadow { ...@@ -299,8 +299,8 @@ union ehci_shadow {
* These appear in both the async and (for interrupt) periodic schedules. * These appear in both the async and (for interrupt) periodic schedules.
*/ */
struct ehci_qh { /* first part defined by EHCI spec */
/* first part defined by EHCI spec */ struct ehci_qh_hw {
__hc32 hw_next; /* see EHCI 3.6.1 */ __hc32 hw_next; /* see EHCI 3.6.1 */
__hc32 hw_info1; /* see EHCI 3.6.2 */ __hc32 hw_info1; /* see EHCI 3.6.2 */
#define QH_HEAD 0x00008000 #define QH_HEAD 0x00008000
...@@ -318,7 +318,10 @@ struct ehci_qh { ...@@ -318,7 +318,10 @@ struct ehci_qh {
__hc32 hw_token; __hc32 hw_token;
__hc32 hw_buf [5]; __hc32 hw_buf [5];
__hc32 hw_buf_hi [5]; __hc32 hw_buf_hi [5];
} __attribute__ ((aligned(32)));
struct ehci_qh {
struct ehci_qh_hw *hw;
/* the rest is HCD-private */ /* the rest is HCD-private */
dma_addr_t qh_dma; /* address of qh */ dma_addr_t qh_dma; /* address of qh */
union ehci_shadow qh_next; /* ptr to qh; or periodic */ union ehci_shadow qh_next; /* ptr to qh; or periodic */
...@@ -358,7 +361,7 @@ struct ehci_qh { ...@@ -358,7 +361,7 @@ struct ehci_qh {
struct usb_device *dev; /* access to TT */ struct usb_device *dev; /* access to TT */
unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
} __attribute__ ((aligned (32))); };
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment