Skip to content

Commit

Permalink
USB: EHCI support for big-endian descriptors
Browse files Browse the repository at this point in the history
This patch implements supports for EHCI controllers whose in-memory
data structures are represented in big-endian format. This is needed
(unfortunately) for the AMCC PPC440EPx SoC EHCI controller; the EHCI
spec doesn't specify little-endian format, although that's what most
other implementations use.

The guts of the patch are to introduce the hc32 type and change all
references from le32 to hc32.  All access routines are converted from
cpu_to_le32(...) to cpu_to_hc32(ehci, ...) and similar for the other
"direction".  (This is the same approach used with OHCI.)

David fixed:
	Whitespace fixes; refresh against ehci cpufreq patch; move glue
	for that PPC driver to the patch adding it; fix free symbol
	capture bugs in modified "constant" macros; and make "hc32" etc
	be "le32" unless we really need the BE options, so "sparse" can
	do some real good.

Signed-off-by: Stefan Roese <sr@denx.de>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Stefan Roese authored and Greg Kroah-Hartman committed Jul 12, 2007
1 parent 196705c commit 6dbd682
Show file tree
Hide file tree
Showing 7 changed files with 432 additions and 302 deletions.
5 changes: 5 additions & 0 deletions drivers/usb/host/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ config USB_EHCI_BIG_ENDIAN_MMIO
depends on USB_EHCI_HCD
default n

config USB_EHCI_BIG_ENDIAN_DESC
bool
depends on USB_EHCI_HCD
default n

config USB_ISP116X_HCD
tristate "ISP116X HCD support"
depends on USB
Expand Down
161 changes: 85 additions & 76 deletions drivers/usb/host/ehci-dbg.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
HCS_INDICATOR (params) ? " ind" : "",
HCS_N_CC (params),
HCS_N_PCC (params),
HCS_PORTROUTED (params) ? "" : " ordered",
HCS_PORTROUTED (params) ? "" : " ordered",
HCS_PPC (params) ? "" : " !ppc",
HCS_N_PORTS (params)
);
Expand Down Expand Up @@ -91,20 +91,20 @@ static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)

if (HCC_ISOC_CACHE (params)) {
ehci_dbg (ehci,
"%s hcc_params %04x caching frame %s%s%s\n",
label, params,
HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
HCC_CANPARK (params) ? " park" : "",
HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
"%s hcc_params %04x caching frame %s%s%s\n",
label, params,
HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
HCC_CANPARK(params) ? " park" : "",
HCC_64BIT_ADDR(params) ? " 64 bit addr" : "");
} else {
ehci_dbg (ehci,
"%s hcc_params %04x thresh %d uframes %s%s%s\n",
label,
params,
HCC_ISOC_THRES (params),
HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
HCC_CANPARK (params) ? " park" : "",
HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
"%s hcc_params %04x thresh %d uframes %s%s%s\n",
label,
params,
HCC_ISOC_THRES(params),
HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
HCC_CANPARK(params) ? " park" : "",
HCC_64BIT_ADDR(params) ? " 64 bit addr" : "");
}
}
#else
Expand All @@ -118,17 +118,17 @@ static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {}
static void __attribute__((__unused__))
dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
{
ehci_dbg (ehci, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
le32_to_cpup (&qtd->hw_next),
le32_to_cpup (&qtd->hw_alt_next),
le32_to_cpup (&qtd->hw_token),
le32_to_cpup (&qtd->hw_buf [0]));
ehci_dbg(ehci, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
hc32_to_cpup(ehci, &qtd->hw_next),
hc32_to_cpup(ehci, &qtd->hw_alt_next),
hc32_to_cpup(ehci, &qtd->hw_token),
hc32_to_cpup(ehci, &qtd->hw_buf [0]));
if (qtd->hw_buf [1])
ehci_dbg (ehci, " p1=%08x p2=%08x p3=%08x p4=%08x\n",
le32_to_cpup (&qtd->hw_buf [1]),
le32_to_cpup (&qtd->hw_buf [2]),
le32_to_cpup (&qtd->hw_buf [3]),
le32_to_cpup (&qtd->hw_buf [4]));
ehci_dbg(ehci, " p1=%08x p2=%08x p3=%08x p4=%08x\n",
hc32_to_cpup(ehci, &qtd->hw_buf[1]),
hc32_to_cpup(ehci, &qtd->hw_buf[2]),
hc32_to_cpup(ehci, &qtd->hw_buf[3]),
hc32_to_cpup(ehci, &qtd->hw_buf[4]));
}

static void __attribute__((__unused__))
Expand All @@ -144,26 +144,27 @@ static void __attribute__((__unused__))
dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
{
ehci_dbg (ehci, "%s [%d] itd %p, next %08x, urb %p\n",
label, itd->frame, itd, le32_to_cpu(itd->hw_next), itd->urb);
label, itd->frame, itd, hc32_to_cpu(ehci, itd->hw_next),
itd->urb);
ehci_dbg (ehci,
" trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
le32_to_cpu(itd->hw_transaction[0]),
le32_to_cpu(itd->hw_transaction[1]),
le32_to_cpu(itd->hw_transaction[2]),
le32_to_cpu(itd->hw_transaction[3]),
le32_to_cpu(itd->hw_transaction[4]),
le32_to_cpu(itd->hw_transaction[5]),
le32_to_cpu(itd->hw_transaction[6]),
le32_to_cpu(itd->hw_transaction[7]));
hc32_to_cpu(ehci, itd->hw_transaction[0]),
hc32_to_cpu(ehci, itd->hw_transaction[1]),
hc32_to_cpu(ehci, itd->hw_transaction[2]),
hc32_to_cpu(ehci, itd->hw_transaction[3]),
hc32_to_cpu(ehci, itd->hw_transaction[4]),
hc32_to_cpu(ehci, itd->hw_transaction[5]),
hc32_to_cpu(ehci, itd->hw_transaction[6]),
hc32_to_cpu(ehci, itd->hw_transaction[7]));
ehci_dbg (ehci,
" buf: %08x %08x %08x %08x %08x %08x %08x\n",
le32_to_cpu(itd->hw_bufp[0]),
le32_to_cpu(itd->hw_bufp[1]),
le32_to_cpu(itd->hw_bufp[2]),
le32_to_cpu(itd->hw_bufp[3]),
le32_to_cpu(itd->hw_bufp[4]),
le32_to_cpu(itd->hw_bufp[5]),
le32_to_cpu(itd->hw_bufp[6]));
hc32_to_cpu(ehci, itd->hw_bufp[0]),
hc32_to_cpu(ehci, itd->hw_bufp[1]),
hc32_to_cpu(ehci, itd->hw_bufp[2]),
hc32_to_cpu(ehci, itd->hw_bufp[3]),
hc32_to_cpu(ehci, itd->hw_bufp[4]),
hc32_to_cpu(ehci, itd->hw_bufp[5]),
hc32_to_cpu(ehci, itd->hw_bufp[6]));
ehci_dbg (ehci, " index: %d %d %d %d %d %d %d %d\n",
itd->index[0], itd->index[1], itd->index[2],
itd->index[3], itd->index[4], itd->index[5],
Expand All @@ -174,14 +175,15 @@ static void __attribute__((__unused__))
dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd)
{
ehci_dbg (ehci, "%s [%d] sitd %p, next %08x, urb %p\n",
label, sitd->frame, sitd, le32_to_cpu(sitd->hw_next), sitd->urb);
label, sitd->frame, sitd, hc32_to_cpu(ehci, sitd->hw_next),
sitd->urb);
ehci_dbg (ehci,
" addr %08x sched %04x result %08x buf %08x %08x\n",
le32_to_cpu(sitd->hw_fullspeed_ep),
le32_to_cpu(sitd->hw_uframe),
le32_to_cpu(sitd->hw_results),
le32_to_cpu(sitd->hw_buf [0]),
le32_to_cpu(sitd->hw_buf [1]));
hc32_to_cpu(ehci, sitd->hw_fullspeed_ep),
hc32_to_cpu(ehci, sitd->hw_uframe),
hc32_to_cpu(ehci, sitd->hw_results),
hc32_to_cpu(ehci, sitd->hw_buf[0]),
hc32_to_cpu(ehci, sitd->hw_buf[1]));
}

static int __attribute__((__unused__))
Expand Down Expand Up @@ -267,8 +269,7 @@ dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
(status & PORT_PEC) ? " PEC" : "",
(status & PORT_PE) ? " PE" : "",
(status & PORT_CSC) ? " CSC" : "",
(status & PORT_CONNECT) ? " CONNECT" : ""
);
(status & PORT_CONNECT) ? " CONNECT" : "");
}

#else
Expand Down Expand Up @@ -332,9 +333,10 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { }
default: tmp = '?'; break; \
}; tmp; })

static inline char token_mark (__le32 token)
static inline char token_mark(struct ehci_hcd *ehci, __hc32 token)
{
__u32 v = le32_to_cpu (token);
__u32 v = hc32_to_cpu(ehci, token);

if (v & QTD_STS_ACTIVE)
return '*';
if (v & QTD_STS_HALT)
Expand All @@ -360,46 +362,48 @@ static void qh_lines (
unsigned size = *sizep;
char *next = *nextp;
char mark;
u32 list_end = EHCI_LIST_END(ehci);

if (qh->hw_qtd_next == EHCI_LIST_END) /* NEC does this */
if (qh->hw_qtd_next == list_end) /* NEC does this */
mark = '@';
else
mark = token_mark (qh->hw_token);
mark = token_mark(ehci, qh->hw_token);
if (mark == '/') { /* qh_alt_next controls qh advance? */
if ((qh->hw_alt_next & QTD_MASK) == ehci->async->hw_alt_next)
if ((qh->hw_alt_next & QTD_MASK(ehci))
== ehci->async->hw_alt_next)
mark = '#'; /* blocked */
else if (qh->hw_alt_next == EHCI_LIST_END)
else if (qh->hw_alt_next == 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 = hc32_to_cpup(ehci, &qh->hw_info1);
hw_curr = (mark == '*') ? hc32_to_cpup(ehci, &qh->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, hc32_to_cpup(ehci, &qh->hw_info2),
hc32_to_cpup(ehci, &qh->hw_token), mark,
(cpu_to_hc32(ehci, QTD_TOGGLE) & qh->hw_token)
? "data1" : "data0",
(le32_to_cpup (&qh->hw_alt_next) >> 1) & 0x0f);
(hc32_to_cpup(ehci, &qh->hw_alt_next) >> 1) & 0x0f);
size -= temp;
next += temp;

/* hc may be modifying the list as we read it ... */
list_for_each (entry, &qh->qtd_list) {
td = list_entry (entry, struct ehci_qtd, qtd_list);
scratch = le32_to_cpup (&td->hw_token);
scratch = hc32_to_cpup(ehci, &td->hw_token);
mark = ' ';
if (hw_curr == td->qtd_dma)
mark = '*';
else if (qh->hw_qtd_next == cpu_to_le32(td->qtd_dma))
else if (qh->hw_qtd_next == cpu_to_hc32(ehci, td->qtd_dma))
mark = '+';
else if (QTD_LENGTH (scratch)) {
if (td->hw_alt_next == ehci->async->hw_alt_next)
mark = '#';
else if (td->hw_alt_next != EHCI_LIST_END)
else if (td->hw_alt_next != list_end)
mark = '/';
}
temp = snprintf (next, size,
Expand Down Expand Up @@ -490,7 +494,7 @@ show_periodic (struct class_device *class_dev, char *buf)
unsigned temp, size, seen_count;
char *next;
unsigned i;
__le32 tag;
__hc32 tag;

if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC)))
return 0;
Expand All @@ -514,18 +518,19 @@ show_periodic (struct class_device *class_dev, char *buf)
p = ehci->pshadow [i];
if (likely (!p.ptr))
continue;
tag = Q_NEXT_TYPE (ehci->periodic [i]);
tag = Q_NEXT_TYPE(ehci, ehci->periodic [i]);

temp = scnprintf (next, size, "%4d: ", i);
size -= temp;
next += temp;

do {
switch (tag) {
switch (hc32_to_cpu(ehci, tag)) {
case Q_TYPE_QH:
temp = scnprintf (next, size, " qh%d-%04x/%p",
p.qh->period,
le32_to_cpup (&p.qh->hw_info2)
hc32_to_cpup(ehci,
&p.qh->hw_info2)
/* uframe masks */
& (QH_CMASK | QH_SMASK),
p.qh);
Expand All @@ -543,7 +548,7 @@ show_periodic (struct class_device *class_dev, char *buf)
}
/* show more info the first time around */
if (temp == seen_count && p.ptr) {
u32 scratch = le32_to_cpup (
u32 scratch = hc32_to_cpup(ehci,
&p.qh->hw_info1);
struct ehci_qtd *qtd;
char *type = "";
Expand All @@ -554,7 +559,8 @@ show_periodic (struct class_device *class_dev, char *buf)
&p.qh->qtd_list,
qtd_list) {
temp++;
switch (0x03 & (le32_to_cpu (
switch (0x03 & (hc32_to_cpu(
ehci,
qtd->hw_token) >> 8)) {
case 0: type = "out"; continue;
case 1: type = "in"; continue;
Expand All @@ -576,31 +582,31 @@ show_periodic (struct class_device *class_dev, char *buf)
} else
temp = 0;
if (p.qh) {
tag = Q_NEXT_TYPE (p.qh->hw_next);
tag = Q_NEXT_TYPE(ehci, p.qh->hw_next);
p = p.qh->qh_next;
}
break;
case Q_TYPE_FSTN:
temp = scnprintf (next, size,
" fstn-%8x/%p", p.fstn->hw_prev,
p.fstn);
tag = Q_NEXT_TYPE (p.fstn->hw_next);
tag = Q_NEXT_TYPE(ehci, p.fstn->hw_next);
p = p.fstn->fstn_next;
break;
case Q_TYPE_ITD:
temp = scnprintf (next, size,
" itd/%p", p.itd);
tag = Q_NEXT_TYPE (p.itd->hw_next);
tag = Q_NEXT_TYPE(ehci, p.itd->hw_next);
p = p.itd->itd_next;
break;
case Q_TYPE_SITD:
temp = scnprintf (next, size,
" sitd%d-%04x/%p",
p.sitd->stream->interval,
le32_to_cpup (&p.sitd->hw_uframe)
hc32_to_cpup(ehci, &p.sitd->hw_uframe)
& 0x0000ffff,
p.sitd);
tag = Q_NEXT_TYPE (p.sitd->hw_next);
tag = Q_NEXT_TYPE(ehci, p.sitd->hw_next);
p = p.sitd->sitd_next;
break;
}
Expand Down Expand Up @@ -673,7 +679,8 @@ show_registers (struct class_device *class_dev, char *buf)
unsigned count = 256/4;

pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
offset = HCC_EXT_CAPS (ehci_readl(ehci, &ehci->caps->hcc_params));
offset = HCC_EXT_CAPS(ehci_readl(ehci,
&ehci->caps->hcc_params));
while (offset && count--) {
pci_read_config_dword (pdev, offset, &cap);
switch (cap & 0xff) {
Expand Down Expand Up @@ -740,14 +747,16 @@ show_registers (struct class_device *class_dev, char *buf)

for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
temp = dbg_port_buf (scratch, sizeof scratch, label, i,
ehci_readl(ehci, &ehci->regs->port_status [i - 1]));
ehci_readl(ehci,
&ehci->regs->port_status[i - 1]));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
temp = scnprintf (next, size,
" debug control %08x\n",
ehci_readl(ehci, &ehci->debug->control));
ehci_readl(ehci,
&ehci->debug->control));
size -= temp;
next += temp;
}
Expand Down
10 changes: 5 additions & 5 deletions drivers/usb/host/ehci-hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -526,12 +526,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->hw_next = QH_NEXT(ehci, ehci->async->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->async->dummy->qtd_dma);
ehci->async->hw_alt_next = QTD_NEXT(ehci, ehci->async->dummy->qtd_dma);

/* clear interrupt enables, set irq latency */
if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
Expand Down
Loading

0 comments on commit 6dbd682

Please sign in to comment.