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: Alek Du <alek.du@intel.com> Cc: David Brownell <dbrownell@users.sourceforge.net> CC: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
403dbd3673
commit
3807e26d69
@ -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 (
|
|||||||
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 (
|
|||||||
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)
|
|||||||
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)
|
|||||||
/* 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)
|
|||||||
} 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)
|
|||||||
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)
|
|||||||
* 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 @@ rescan:
|
|||||||
/* 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)
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
/* 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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
/* 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)
|
|||||||
* 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 @@ halt:
|
|||||||
* 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 @@ halt:
|
|||||||
* 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 (
|
|||||||
* (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 (
|
|||||||
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 @@ done:
|
|||||||
|
|
||||||
/* 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)
|
|||||||
|
|
||||||
/* 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 (
|
|||||||
|
|
||||||
/* 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)
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
|||||||
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)
|
|||||||
*/
|
*/
|
||||||
*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)
|
|||||||
__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 (
|
|||||||
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 (
|
|||||||
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 (
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
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)
|
|||||||
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 @@ restart:
|
|||||||
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 {
|
|||||||
* 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 {
|
|||||||
__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 {
|
|||||||
|
|
||||||
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)));
|
};
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user