提交 51e2f62f 编写于 作者: J Jan Andersson 提交者: Greg Kroah-Hartman

USB: UHCI: Add support for big endian descriptors

This patch adds support for universal host controllers that use
big endian descriptors. Support for BE descriptors requires a non-PCI
host controller. For kernels with PCI-only UHCI there should be no
change in behaviour.

This patch tries to replicate the technique used to support BE descriptors
in the EHCI HCD. Parts added to uhci-hcd.h are basically copy'n'paste from
ehci.h.
Signed-off-by: NJan Andersson <jan@gaisler.com>
Acked-by: NAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
上级 bab1ff1b
...@@ -420,6 +420,10 @@ config USB_UHCI_BIG_ENDIAN_MMIO ...@@ -420,6 +420,10 @@ config USB_UHCI_BIG_ENDIAN_MMIO
bool bool
depends on USB_UHCI_SUPPORT_NON_PCI_HC depends on USB_UHCI_SUPPORT_NON_PCI_HC
config USB_UHCI_BIG_ENDIAN_DESC
bool
depends on USB_UHCI_SUPPORT_NON_PCI_HC
config USB_FHCI_HCD config USB_FHCI_HCD
tristate "Freescale QE USB Host Controller support" tristate "Freescale QE USB Host Controller support"
depends on USB && OF_GPIO && QE_GPIO && QUICC_ENGINE depends on USB && OF_GPIO && QE_GPIO && QUICC_ENGINE
......
...@@ -37,7 +37,8 @@ static void lprintk(char *buf) ...@@ -37,7 +37,8 @@ static void lprintk(char *buf)
} }
} }
static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space) static int uhci_show_td(struct uhci_hcd *uhci, struct uhci_td *td, char *buf,
int len, int space)
{ {
char *out = buf; char *out = buf;
char *spid; char *spid;
...@@ -47,8 +48,9 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space) ...@@ -47,8 +48,9 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
if (len < 160) if (len < 160)
return 0; return 0;
status = td_status(td); status = td_status(uhci, td);
out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td, le32_to_cpu(td->link)); out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td,
hc32_to_cpu(uhci, td->link));
out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ", out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
((status >> 27) & 3), ((status >> 27) & 3),
(status & TD_CTRL_SPD) ? "SPD " : "", (status & TD_CTRL_SPD) ? "SPD " : "",
...@@ -63,7 +65,7 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space) ...@@ -63,7 +65,7 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
(status & TD_CTRL_BITSTUFF) ? "BitStuff " : "", (status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
status & 0x7ff); status & 0x7ff);
token = td_token(td); token = td_token(uhci, td);
switch (uhci_packetid(token)) { switch (uhci_packetid(token)) {
case USB_PID_SETUP: case USB_PID_SETUP:
spid = "SETUP"; spid = "SETUP";
...@@ -86,12 +88,13 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space) ...@@ -86,12 +88,13 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
(token >> 8) & 127, (token >> 8) & 127,
(token & 0xff), (token & 0xff),
spid); spid);
out += sprintf(out, "(buf=%08x)\n", le32_to_cpu(td->buffer)); out += sprintf(out, "(buf=%08x)\n", hc32_to_cpu(uhci, td->buffer));
return out - buf; return out - buf;
} }
static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space) static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp,
char *buf, int len, int space)
{ {
char *out = buf; char *out = buf;
struct uhci_td *td; struct uhci_td *td;
...@@ -130,9 +133,10 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space) ...@@ -130,9 +133,10 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
if (urbp->qh->type != USB_ENDPOINT_XFER_ISOC && if (urbp->qh->type != USB_ENDPOINT_XFER_ISOC &&
(++i <= 10 || debug > 2)) { (++i <= 10 || debug > 2)) {
out += sprintf(out, "%*s%d: ", space + 2, "", i); out += sprintf(out, "%*s%d: ", space + 2, "", i);
out += uhci_show_td(td, out, len - (out - buf), 0); out += uhci_show_td(uhci, td, out,
len - (out - buf), 0);
} else { } else {
if (td_status(td) & TD_CTRL_ACTIVE) if (td_status(uhci, td) & TD_CTRL_ACTIVE)
++nactive; ++nactive;
else else
++ninactive; ++ninactive;
...@@ -151,7 +155,7 @@ static int uhci_show_qh(struct uhci_hcd *uhci, ...@@ -151,7 +155,7 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
{ {
char *out = buf; char *out = buf;
int i, nurbs; int i, nurbs;
__le32 element = qh_element(qh); __hc32 element = qh_element(qh);
char *qtype; char *qtype;
/* Try to make sure there's enough memory */ /* Try to make sure there's enough memory */
...@@ -168,7 +172,8 @@ static int uhci_show_qh(struct uhci_hcd *uhci, ...@@ -168,7 +172,8 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
out += sprintf(out, "%*s[%p] %s QH link (%08x) element (%08x)\n", out += sprintf(out, "%*s[%p] %s QH link (%08x) element (%08x)\n",
space, "", qh, qtype, space, "", qh, qtype,
le32_to_cpu(qh->link), le32_to_cpu(element)); hc32_to_cpu(uhci, qh->link),
hc32_to_cpu(uhci, element));
if (qh->type == USB_ENDPOINT_XFER_ISOC) if (qh->type == USB_ENDPOINT_XFER_ISOC)
out += sprintf(out, "%*s period %d phase %d load %d us, " out += sprintf(out, "%*s period %d phase %d load %d us, "
"frame %x desc [%p]\n", "frame %x desc [%p]\n",
...@@ -178,22 +183,22 @@ static int uhci_show_qh(struct uhci_hcd *uhci, ...@@ -178,22 +183,22 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
out += sprintf(out, "%*s period %d phase %d load %d us\n", out += sprintf(out, "%*s period %d phase %d load %d us\n",
space, "", qh->period, qh->phase, qh->load); space, "", qh->period, qh->phase, qh->load);
if (element & UHCI_PTR_QH) if (element & UHCI_PTR_QH(uhci))
out += sprintf(out, "%*s Element points to QH (bug?)\n", space, ""); out += sprintf(out, "%*s Element points to QH (bug?)\n", space, "");
if (element & UHCI_PTR_DEPTH) if (element & UHCI_PTR_DEPTH(uhci))
out += sprintf(out, "%*s Depth traverse\n", space, ""); out += sprintf(out, "%*s Depth traverse\n", space, "");
if (element & cpu_to_le32(8)) if (element & cpu_to_hc32(uhci, 8))
out += sprintf(out, "%*s Bit 3 set (bug?)\n", space, ""); out += sprintf(out, "%*s Bit 3 set (bug?)\n", space, "");
if (!(element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH))) if (!(element & ~(UHCI_PTR_QH(uhci) | UHCI_PTR_DEPTH(uhci))))
out += sprintf(out, "%*s Element is NULL (bug?)\n", space, ""); out += sprintf(out, "%*s Element is NULL (bug?)\n", space, "");
if (list_empty(&qh->queue)) { if (list_empty(&qh->queue)) {
out += sprintf(out, "%*s queue is empty\n", space, ""); out += sprintf(out, "%*s queue is empty\n", space, "");
if (qh == uhci->skel_async_qh) if (qh == uhci->skel_async_qh)
out += uhci_show_td(uhci->term_td, out, out += uhci_show_td(uhci, uhci->term_td, out,
len - (out - buf), 0); len - (out - buf), 0);
} else { } else {
struct urb_priv *urbp = list_entry(qh->queue.next, struct urb_priv *urbp = list_entry(qh->queue.next,
...@@ -201,13 +206,13 @@ static int uhci_show_qh(struct uhci_hcd *uhci, ...@@ -201,13 +206,13 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
struct uhci_td *td = list_entry(urbp->td_list.next, struct uhci_td *td = list_entry(urbp->td_list.next,
struct uhci_td, list); struct uhci_td, list);
if (element != LINK_TO_TD(td)) if (element != LINK_TO_TD(uhci, td))
out += sprintf(out, "%*s Element != First TD\n", out += sprintf(out, "%*s Element != First TD\n",
space, ""); space, "");
i = nurbs = 0; i = nurbs = 0;
list_for_each_entry(urbp, &qh->queue, node) { list_for_each_entry(urbp, &qh->queue, node) {
if (++i <= 10) if (++i <= 10)
out += uhci_show_urbp(urbp, out, out += uhci_show_urbp(uhci, urbp, out,
len - (out - buf), space + 2); len - (out - buf), space + 2);
else else
++nurbs; ++nurbs;
...@@ -219,7 +224,8 @@ static int uhci_show_qh(struct uhci_hcd *uhci, ...@@ -219,7 +224,8 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
if (qh->dummy_td) { if (qh->dummy_td) {
out += sprintf(out, "%*s Dummy TD\n", space, ""); out += sprintf(out, "%*s Dummy TD\n", space, "");
out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0); out += uhci_show_td(uhci, qh->dummy_td, out,
len - (out - buf), 0);
} }
return out - buf; return out - buf;
...@@ -346,8 +352,8 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) ...@@ -346,8 +352,8 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
struct uhci_td *td; struct uhci_td *td;
struct list_head *tmp, *head; struct list_head *tmp, *head;
int nframes, nerrs; int nframes, nerrs;
__le32 link; __hc32 link;
__le32 fsbr_link; __hc32 fsbr_link;
static const char * const qh_names[] = { static const char * const qh_names[] = {
"unlink", "iso", "int128", "int64", "int32", "int16", "unlink", "iso", "int128", "int64", "int32", "int16",
...@@ -375,7 +381,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) ...@@ -375,7 +381,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
nframes = 10; nframes = 10;
nerrs = 0; nerrs = 0;
for (i = 0; i < UHCI_NUMFRAMES; ++i) { for (i = 0; i < UHCI_NUMFRAMES; ++i) {
__le32 qh_dma; __hc32 qh_dma;
j = 0; j = 0;
td = uhci->frame_cpu[i]; td = uhci->frame_cpu[i];
...@@ -385,7 +391,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) ...@@ -385,7 +391,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
if (nframes > 0) { if (nframes > 0) {
out += sprintf(out, "- Frame %d -> (%08x)\n", out += sprintf(out, "- Frame %d -> (%08x)\n",
i, le32_to_cpu(link)); i, hc32_to_cpu(uhci, link));
j = 1; j = 1;
} }
...@@ -394,7 +400,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) ...@@ -394,7 +400,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
do { do {
td = list_entry(tmp, struct uhci_td, fl_list); td = list_entry(tmp, struct uhci_td, fl_list);
tmp = tmp->next; tmp = tmp->next;
if (link != LINK_TO_TD(td)) { if (link != LINK_TO_TD(uhci, td)) {
if (nframes > 0) if (nframes > 0)
out += sprintf(out, " link does " out += sprintf(out, " link does "
"not match list entry!\n"); "not match list entry!\n");
...@@ -402,7 +408,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) ...@@ -402,7 +408,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
++nerrs; ++nerrs;
} }
if (nframes > 0) if (nframes > 0)
out += uhci_show_td(td, out, out += uhci_show_td(uhci, td, out,
len - (out - buf), 4); len - (out - buf), 4);
link = td->link; link = td->link;
} while (tmp != head); } while (tmp != head);
...@@ -414,11 +420,12 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) ...@@ -414,11 +420,12 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
if (!j) { if (!j) {
out += sprintf(out, out += sprintf(out,
"- Frame %d -> (%08x)\n", "- Frame %d -> (%08x)\n",
i, le32_to_cpu(link)); i, hc32_to_cpu(uhci, link));
j = 1; j = 1;
} }
out += sprintf(out, " link does not match " out += sprintf(out, " link does not match "
"QH (%08x)!\n", le32_to_cpu(qh_dma)); "QH (%08x)!\n",
hc32_to_cpu(uhci, qh_dma));
} else } else
++nerrs; ++nerrs;
} }
...@@ -439,11 +446,11 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) ...@@ -439,11 +446,11 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
/* Last QH is the Terminating QH, it's different */ /* Last QH is the Terminating QH, it's different */
if (i == SKEL_TERM) { if (i == SKEL_TERM) {
if (qh_element(qh) != LINK_TO_TD(uhci->term_td)) if (qh_element(qh) != LINK_TO_TD(uhci, uhci->term_td))
out += sprintf(out, " skel_term_qh element is not set to term_td!\n"); out += sprintf(out, " skel_term_qh element is not set to term_td!\n");
link = fsbr_link; link = fsbr_link;
if (!link) if (!link)
link = LINK_TO_QH(uhci->skel_term_qh); link = LINK_TO_QH(uhci, uhci->skel_term_qh);
goto check_qh_link; goto check_qh_link;
} }
...@@ -457,20 +464,20 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) ...@@ -457,20 +464,20 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
out += uhci_show_qh(uhci, qh, out, out += uhci_show_qh(uhci, qh, out,
len - (out - buf), 4); len - (out - buf), 4);
if (!fsbr_link && qh->skel >= SKEL_FSBR) if (!fsbr_link && qh->skel >= SKEL_FSBR)
fsbr_link = LINK_TO_QH(qh); fsbr_link = LINK_TO_QH(uhci, qh);
} }
if ((cnt -= 10) > 0) if ((cnt -= 10) > 0)
out += sprintf(out, " Skipped %d QHs\n", cnt); out += sprintf(out, " Skipped %d QHs\n", cnt);
link = UHCI_PTR_TERM; link = UHCI_PTR_TERM(uhci);
if (i <= SKEL_ISO) if (i <= SKEL_ISO)
; ;
else if (i < SKEL_ASYNC) else if (i < SKEL_ASYNC)
link = LINK_TO_QH(uhci->skel_async_qh); link = LINK_TO_QH(uhci, uhci->skel_async_qh);
else if (!uhci->fsbr_is_on) else if (!uhci->fsbr_is_on)
; ;
else else
link = LINK_TO_QH(uhci->skel_term_qh); link = LINK_TO_QH(uhci, uhci->skel_term_qh);
check_qh_link: check_qh_link:
if (qh->link != link) if (qh->link != link)
out += sprintf(out, " last QH not linked to next skeleton!\n"); out += sprintf(out, " last QH not linked to next skeleton!\n");
......
...@@ -92,7 +92,7 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci); ...@@ -92,7 +92,7 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
/* /*
* Calculate the link pointer DMA value for the first Skeleton QH in a frame. * Calculate the link pointer DMA value for the first Skeleton QH in a frame.
*/ */
static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame) static __hc32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
{ {
int skelnum; int skelnum;
...@@ -114,7 +114,7 @@ static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame) ...@@ -114,7 +114,7 @@ static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES); skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES);
if (skelnum <= 1) if (skelnum <= 1)
skelnum = 9; skelnum = 9;
return LINK_TO_QH(uhci->skelqh[skelnum]); return LINK_TO_QH(uhci, uhci->skelqh[skelnum]);
} }
#include "uhci-debug.c" #include "uhci-debug.c"
...@@ -630,16 +630,16 @@ static int uhci_start(struct usb_hcd *hcd) ...@@ -630,16 +630,16 @@ static int uhci_start(struct usb_hcd *hcd)
* 8 Interrupt queues; link all higher int queues to int1 = async * 8 Interrupt queues; link all higher int queues to int1 = async
*/ */
for (i = SKEL_ISO + 1; i < SKEL_ASYNC; ++i) for (i = SKEL_ISO + 1; i < SKEL_ASYNC; ++i)
uhci->skelqh[i]->link = LINK_TO_QH(uhci->skel_async_qh); uhci->skelqh[i]->link = LINK_TO_QH(uhci, uhci->skel_async_qh);
uhci->skel_async_qh->link = UHCI_PTR_TERM; uhci->skel_async_qh->link = UHCI_PTR_TERM(uhci);
uhci->skel_term_qh->link = LINK_TO_QH(uhci->skel_term_qh); uhci->skel_term_qh->link = LINK_TO_QH(uhci, uhci->skel_term_qh);
/* This dummy TD is to work around a bug in Intel PIIX controllers */ /* This dummy TD is to work around a bug in Intel PIIX controllers */
uhci_fill_td(uhci->term_td, 0, uhci_explen(0) | uhci_fill_td(uhci, uhci->term_td, 0, uhci_explen(0) |
(0x7f << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_IN, 0); (0x7f << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_IN, 0);
uhci->term_td->link = UHCI_PTR_TERM; uhci->term_td->link = UHCI_PTR_TERM(uhci);
uhci->skel_async_qh->element = uhci->skel_term_qh->element = uhci->skel_async_qh->element = uhci->skel_term_qh->element =
LINK_TO_TD(uhci->term_td); LINK_TO_TD(uhci, uhci->term_td);
/* /*
* Fill the frame list: make all entries point to the proper * Fill the frame list: make all entries point to the proper
......
...@@ -78,11 +78,11 @@ ...@@ -78,11 +78,11 @@
#define USBPORT1EN 0x01 #define USBPORT1EN 0x01
#define USBPORT2EN 0x02 #define USBPORT2EN 0x02
#define UHCI_PTR_BITS cpu_to_le32(0x000F) #define UHCI_PTR_BITS(uhci) cpu_to_hc32((uhci), 0x000F)
#define UHCI_PTR_TERM cpu_to_le32(0x0001) #define UHCI_PTR_TERM(uhci) cpu_to_hc32((uhci), 0x0001)
#define UHCI_PTR_QH cpu_to_le32(0x0002) #define UHCI_PTR_QH(uhci) cpu_to_hc32((uhci), 0x0002)
#define UHCI_PTR_DEPTH cpu_to_le32(0x0004) #define UHCI_PTR_DEPTH(uhci) cpu_to_hc32((uhci), 0x0004)
#define UHCI_PTR_BREADTH cpu_to_le32(0x0000) #define UHCI_PTR_BREADTH(uhci) cpu_to_hc32((uhci), 0x0000)
#define UHCI_NUMFRAMES 1024 /* in the frame list [array] */ #define UHCI_NUMFRAMES 1024 /* in the frame list [array] */
#define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */ #define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */
...@@ -98,6 +98,22 @@ ...@@ -98,6 +98,22 @@
#define QH_WAIT_TIMEOUT msecs_to_jiffies(200) #define QH_WAIT_TIMEOUT msecs_to_jiffies(200)
/*
* __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
* __leXX (normally) or __beXX (given UHCI_BIG_ENDIAN_DESC), depending on
* the host controller implementation.
*
* To facilitate the strongest possible byte-order checking from "sparse"
* and so on, we use __leXX unless that's not practical.
*/
#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_DESC
typedef __u32 __bitwise __hc32;
typedef __u16 __bitwise __hc16;
#else
#define __hc32 __le32
#define __hc16 __le16
#endif
/* /*
* Queue Headers * Queue Headers
*/ */
...@@ -130,8 +146,8 @@ ...@@ -130,8 +146,8 @@
struct uhci_qh { struct uhci_qh {
/* Hardware fields */ /* Hardware fields */
__le32 link; /* Next QH in the schedule */ __hc32 link; /* Next QH in the schedule */
__le32 element; /* Queue element (TD) pointer */ __hc32 element; /* Queue element (TD) pointer */
/* Software fields */ /* Software fields */
dma_addr_t dma_handle; dma_addr_t dma_handle;
...@@ -170,7 +186,8 @@ struct uhci_qh { ...@@ -170,7 +186,8 @@ struct uhci_qh {
*/ */
#define qh_element(qh) ACCESS_ONCE((qh)->element) #define qh_element(qh) ACCESS_ONCE((qh)->element)
#define LINK_TO_QH(qh) (UHCI_PTR_QH | cpu_to_le32((qh)->dma_handle)) #define LINK_TO_QH(uhci, qh) (UHCI_PTR_QH((uhci)) | \
cpu_to_hc32((uhci), (qh)->dma_handle))
/* /*
...@@ -207,7 +224,7 @@ struct uhci_qh { ...@@ -207,7 +224,7 @@ struct uhci_qh {
/* /*
* for TD <info>: (a.k.a. Token) * for TD <info>: (a.k.a. Token)
*/ */
#define td_token(td) le32_to_cpu((td)->token) #define td_token(uhci, td) hc32_to_cpu((uhci), (td)->token)
#define TD_TOKEN_DEVADDR_SHIFT 8 #define TD_TOKEN_DEVADDR_SHIFT 8
#define TD_TOKEN_TOGGLE_SHIFT 19 #define TD_TOKEN_TOGGLE_SHIFT 19
#define TD_TOKEN_TOGGLE (1 << 19) #define TD_TOKEN_TOGGLE (1 << 19)
...@@ -240,10 +257,10 @@ struct uhci_qh { ...@@ -240,10 +257,10 @@ struct uhci_qh {
*/ */
struct uhci_td { struct uhci_td {
/* Hardware fields */ /* Hardware fields */
__le32 link; __hc32 link;
__le32 status; __hc32 status;
__le32 token; __hc32 token;
__le32 buffer; __hc32 buffer;
/* Software fields */ /* Software fields */
dma_addr_t dma_handle; dma_addr_t dma_handle;
...@@ -258,9 +275,10 @@ struct uhci_td { ...@@ -258,9 +275,10 @@ struct uhci_td {
* We need a special accessor for the control/status word because it is * We need a special accessor for the control/status word because it is
* subject to asynchronous updates by the controller. * subject to asynchronous updates by the controller.
*/ */
#define td_status(td) le32_to_cpu(ACCESS_ONCE((td)->status)) #define td_status(uhci, td) hc32_to_cpu((uhci), \
ACCESS_ONCE((td)->status))
#define LINK_TO_TD(td) (cpu_to_le32((td)->dma_handle)) #define LINK_TO_TD(uhci, td) (cpu_to_hc32((uhci), (td)->dma_handle))
/* /*
...@@ -383,7 +401,7 @@ struct uhci_hcd { ...@@ -383,7 +401,7 @@ struct uhci_hcd {
spinlock_t lock; spinlock_t lock;
dma_addr_t frame_dma_handle; /* Hardware frame list */ dma_addr_t frame_dma_handle; /* Hardware frame list */
__le32 *frame; __hc32 *frame;
void **frame_cpu; /* CPU's frame list */ void **frame_cpu; /* CPU's frame list */
enum uhci_rh_state rh_state; enum uhci_rh_state rh_state;
...@@ -412,6 +430,7 @@ struct uhci_hcd { ...@@ -412,6 +430,7 @@ struct uhci_hcd {
unsigned int oc_low:1; /* OverCurrent bit active low */ unsigned int oc_low:1; /* OverCurrent bit active low */
unsigned int wait_for_hp:1; /* Wait for HP port reset */ unsigned int wait_for_hp:1; /* Wait for HP port reset */
unsigned int big_endian_mmio:1; /* Big endian registers */ unsigned int big_endian_mmio:1; /* Big endian registers */
unsigned int big_endian_desc:1; /* Big endian descriptors */
/* Support for port suspend/resume/reset */ /* Support for port suspend/resume/reset */
unsigned long port_c_suspend; /* Bit-arrays of ports */ unsigned long port_c_suspend; /* Bit-arrays of ports */
...@@ -603,4 +622,43 @@ static inline void uhci_writeb(const struct uhci_hcd *uhci, u8 val, int reg) ...@@ -603,4 +622,43 @@ static inline void uhci_writeb(const struct uhci_hcd *uhci, u8 val, int reg)
} }
#endif /* CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC */ #endif /* CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC */
/*
* The GRLIB GRUSBHC controller can use big endian format for its descriptors.
*
* UHCI controllers accessed through PCI work normally (little-endian
* everywhere), so we don't bother supporting a BE-only mode.
*/
#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_DESC
#define uhci_big_endian_desc(u) ((u)->big_endian_desc)
/* cpu to uhci */
static inline __hc32 cpu_to_hc32(const struct uhci_hcd *uhci, const u32 x)
{
return uhci_big_endian_desc(uhci)
? (__force __hc32)cpu_to_be32(x)
: (__force __hc32)cpu_to_le32(x);
}
/* uhci to cpu */
static inline u32 hc32_to_cpu(const struct uhci_hcd *uhci, const __hc32 x)
{
return uhci_big_endian_desc(uhci)
? be32_to_cpu((__force __be32)x)
: le32_to_cpu((__force __le32)x);
}
#else
/* cpu to uhci */
static inline __hc32 cpu_to_hc32(const struct uhci_hcd *uhci, const u32 x)
{
return cpu_to_le32(x);
}
/* uhci to cpu */
static inline u32 hc32_to_cpu(const struct uhci_hcd *uhci, const __hc32 x)
{
return le32_to_cpu(x);
}
#endif
#endif #endif
...@@ -29,12 +29,12 @@ static void uhci_set_next_interrupt(struct uhci_hcd *uhci) ...@@ -29,12 +29,12 @@ static void uhci_set_next_interrupt(struct uhci_hcd *uhci)
{ {
if (uhci->is_stopped) if (uhci->is_stopped)
mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies); mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC); uhci->term_td->status |= cpu_to_hc32(uhci, TD_CTRL_IOC);
} }
static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci) static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
{ {
uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC); uhci->term_td->status &= ~cpu_to_hc32(uhci, TD_CTRL_IOC);
} }
...@@ -53,7 +53,7 @@ static void uhci_fsbr_on(struct uhci_hcd *uhci) ...@@ -53,7 +53,7 @@ static void uhci_fsbr_on(struct uhci_hcd *uhci)
uhci->fsbr_is_on = 1; uhci->fsbr_is_on = 1;
lqh = list_entry(uhci->skel_async_qh->node.prev, lqh = list_entry(uhci->skel_async_qh->node.prev,
struct uhci_qh, node); struct uhci_qh, node);
lqh->link = LINK_TO_QH(uhci->skel_term_qh); lqh->link = LINK_TO_QH(uhci, uhci->skel_term_qh);
} }
static void uhci_fsbr_off(struct uhci_hcd *uhci) static void uhci_fsbr_off(struct uhci_hcd *uhci)
...@@ -65,7 +65,7 @@ static void uhci_fsbr_off(struct uhci_hcd *uhci) ...@@ -65,7 +65,7 @@ static void uhci_fsbr_off(struct uhci_hcd *uhci)
uhci->fsbr_is_on = 0; uhci->fsbr_is_on = 0;
lqh = list_entry(uhci->skel_async_qh->node.prev, lqh = list_entry(uhci->skel_async_qh->node.prev,
struct uhci_qh, node); struct uhci_qh, node);
lqh->link = UHCI_PTR_TERM; lqh->link = UHCI_PTR_TERM(uhci);
} }
static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb) static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb)
...@@ -131,12 +131,12 @@ static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td) ...@@ -131,12 +131,12 @@ static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
dma_pool_free(uhci->td_pool, td, td->dma_handle); dma_pool_free(uhci->td_pool, td, td->dma_handle);
} }
static inline void uhci_fill_td(struct uhci_td *td, u32 status, static inline void uhci_fill_td(struct uhci_hcd *uhci, struct uhci_td *td,
u32 token, u32 buffer) u32 status, u32 token, u32 buffer)
{ {
td->status = cpu_to_le32(status); td->status = cpu_to_hc32(uhci, status);
td->token = cpu_to_le32(token); td->token = cpu_to_hc32(uhci, token);
td->buffer = cpu_to_le32(buffer); td->buffer = cpu_to_hc32(uhci, buffer);
} }
static void uhci_add_td_to_urbp(struct uhci_td *td, struct urb_priv *urbp) static void uhci_add_td_to_urbp(struct uhci_td *td, struct urb_priv *urbp)
...@@ -170,11 +170,11 @@ static inline void uhci_insert_td_in_frame_list(struct uhci_hcd *uhci, ...@@ -170,11 +170,11 @@ static inline void uhci_insert_td_in_frame_list(struct uhci_hcd *uhci,
td->link = ltd->link; td->link = ltd->link;
wmb(); wmb();
ltd->link = LINK_TO_TD(td); ltd->link = LINK_TO_TD(uhci, td);
} else { } else {
td->link = uhci->frame[framenum]; td->link = uhci->frame[framenum];
wmb(); wmb();
uhci->frame[framenum] = LINK_TO_TD(td); uhci->frame[framenum] = LINK_TO_TD(uhci, td);
uhci->frame_cpu[framenum] = td; uhci->frame_cpu[framenum] = td;
} }
} }
...@@ -198,7 +198,7 @@ static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci, ...@@ -198,7 +198,7 @@ static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci,
ntd = list_entry(td->fl_list.next, ntd = list_entry(td->fl_list.next,
struct uhci_td, struct uhci_td,
fl_list); fl_list);
uhci->frame[td->frame] = LINK_TO_TD(ntd); uhci->frame[td->frame] = LINK_TO_TD(uhci, ntd);
uhci->frame_cpu[td->frame] = ntd; uhci->frame_cpu[td->frame] = ntd;
} }
} else { } else {
...@@ -255,8 +255,8 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, ...@@ -255,8 +255,8 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
memset(qh, 0, sizeof(*qh)); memset(qh, 0, sizeof(*qh));
qh->dma_handle = dma_handle; qh->dma_handle = dma_handle;
qh->element = UHCI_PTR_TERM; qh->element = UHCI_PTR_TERM(uhci);
qh->link = UHCI_PTR_TERM; qh->link = UHCI_PTR_TERM(uhci);
INIT_LIST_HEAD(&qh->queue); INIT_LIST_HEAD(&qh->queue);
INIT_LIST_HEAD(&qh->node); INIT_LIST_HEAD(&qh->node);
...@@ -348,9 +348,9 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh, ...@@ -348,9 +348,9 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh,
/* If the QH element pointer is UHCI_PTR_TERM then then currently /* If the QH element pointer is UHCI_PTR_TERM then then currently
* executing URB has already been unlinked, so this one isn't it. */ * executing URB has already been unlinked, so this one isn't it. */
if (qh_element(qh) == UHCI_PTR_TERM) if (qh_element(qh) == UHCI_PTR_TERM(uhci))
goto done; goto done;
qh->element = UHCI_PTR_TERM; qh->element = UHCI_PTR_TERM(uhci);
/* Control pipes don't have to worry about toggles */ /* Control pipes don't have to worry about toggles */
if (qh->type == USB_ENDPOINT_XFER_CONTROL) if (qh->type == USB_ENDPOINT_XFER_CONTROL)
...@@ -360,7 +360,7 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh, ...@@ -360,7 +360,7 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh,
WARN_ON(list_empty(&urbp->td_list)); WARN_ON(list_empty(&urbp->td_list));
td = list_entry(urbp->td_list.next, struct uhci_td, list); td = list_entry(urbp->td_list.next, struct uhci_td, list);
qh->needs_fixup = 1; qh->needs_fixup = 1;
qh->initial_toggle = uhci_toggle(td_token(td)); qh->initial_toggle = uhci_toggle(td_token(uhci, td));
done: done:
return ret; return ret;
...@@ -370,7 +370,8 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh, ...@@ -370,7 +370,8 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh,
* Fix up the data toggles for URBs in a queue, when one of them * Fix up the data toggles for URBs in a queue, when one of them
* terminates early (short transfer, error, or dequeued). * terminates early (short transfer, error, or dequeued).
*/ */
static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first) static void uhci_fixup_toggles(struct uhci_hcd *uhci, struct uhci_qh *qh,
int skip_first)
{ {
struct urb_priv *urbp = NULL; struct urb_priv *urbp = NULL;
struct uhci_td *td; struct uhci_td *td;
...@@ -384,7 +385,7 @@ static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first) ...@@ -384,7 +385,7 @@ static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first)
/* When starting with the first URB, if the QH element pointer is /* When starting with the first URB, if the QH element pointer is
* still valid then we know the URB's toggles are okay. */ * still valid then we know the URB's toggles are okay. */
else if (qh_element(qh) != UHCI_PTR_TERM) else if (qh_element(qh) != UHCI_PTR_TERM(uhci))
toggle = 2; toggle = 2;
/* Fix up the toggle for the URBs in the queue. Normally this /* Fix up the toggle for the URBs in the queue. Normally this
...@@ -396,15 +397,15 @@ static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first) ...@@ -396,15 +397,15 @@ static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first)
/* If the first TD has the right toggle value, we don't /* If the first TD has the right toggle value, we don't
* need to change any toggles in this URB */ * need to change any toggles in this URB */
td = list_entry(urbp->td_list.next, struct uhci_td, list); td = list_entry(urbp->td_list.next, struct uhci_td, list);
if (toggle > 1 || uhci_toggle(td_token(td)) == toggle) { if (toggle > 1 || uhci_toggle(td_token(uhci, td)) == toggle) {
td = list_entry(urbp->td_list.prev, struct uhci_td, td = list_entry(urbp->td_list.prev, struct uhci_td,
list); list);
toggle = uhci_toggle(td_token(td)) ^ 1; toggle = uhci_toggle(td_token(uhci, td)) ^ 1;
/* Otherwise all the toggles in the URB have to be switched */ /* Otherwise all the toggles in the URB have to be switched */
} else { } else {
list_for_each_entry(td, &urbp->td_list, list) { list_for_each_entry(td, &urbp->td_list, list) {
td->token ^= cpu_to_le32( td->token ^= cpu_to_hc32(uhci,
TD_TOKEN_TOGGLE); TD_TOKEN_TOGGLE);
toggle ^= 1; toggle ^= 1;
} }
...@@ -441,7 +442,7 @@ static void link_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh) ...@@ -441,7 +442,7 @@ static void link_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh)
pqh = list_entry(qh->node.prev, struct uhci_qh, node); pqh = list_entry(qh->node.prev, struct uhci_qh, node);
qh->link = pqh->link; qh->link = pqh->link;
wmb(); wmb();
pqh->link = LINK_TO_QH(qh); pqh->link = LINK_TO_QH(uhci, qh);
} }
/* /*
...@@ -451,7 +452,7 @@ static void link_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh) ...@@ -451,7 +452,7 @@ static void link_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh)
static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh) static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
{ {
struct uhci_qh *pqh; struct uhci_qh *pqh;
__le32 link_to_new_qh; __hc32 link_to_new_qh;
/* Find the predecessor QH for our new one and insert it in the list. /* Find the predecessor QH for our new one and insert it in the list.
* The list of QHs is expected to be short, so linear search won't * The list of QHs is expected to be short, so linear search won't
...@@ -465,7 +466,7 @@ static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh) ...@@ -465,7 +466,7 @@ static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
/* Link it into the schedule */ /* Link it into the schedule */
qh->link = pqh->link; qh->link = pqh->link;
wmb(); wmb();
link_to_new_qh = LINK_TO_QH(qh); link_to_new_qh = LINK_TO_QH(uhci, qh);
pqh->link = link_to_new_qh; pqh->link = link_to_new_qh;
/* If this is now the first FSBR QH, link the terminating skeleton /* If this is now the first FSBR QH, link the terminating skeleton
...@@ -483,13 +484,13 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) ...@@ -483,13 +484,13 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
/* Set the element pointer if it isn't set already. /* Set the element pointer if it isn't set already.
* This isn't needed for Isochronous queues, but it doesn't hurt. */ * This isn't needed for Isochronous queues, but it doesn't hurt. */
if (qh_element(qh) == UHCI_PTR_TERM) { if (qh_element(qh) == UHCI_PTR_TERM(uhci)) {
struct urb_priv *urbp = list_entry(qh->queue.next, struct urb_priv *urbp = list_entry(qh->queue.next,
struct urb_priv, node); struct urb_priv, node);
struct uhci_td *td = list_entry(urbp->td_list.next, struct uhci_td *td = list_entry(urbp->td_list.next,
struct uhci_td, list); struct uhci_td, list);
qh->element = LINK_TO_TD(td); qh->element = LINK_TO_TD(uhci, td);
} }
/* Treat the queue as if it has just advanced */ /* Treat the queue as if it has just advanced */
...@@ -533,7 +534,7 @@ static void unlink_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh) ...@@ -533,7 +534,7 @@ static void unlink_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh)
static void unlink_async(struct uhci_hcd *uhci, struct uhci_qh *qh) static void unlink_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
{ {
struct uhci_qh *pqh; struct uhci_qh *pqh;
__le32 link_to_next_qh = qh->link; __hc32 link_to_next_qh = qh->link;
pqh = list_entry(qh->node.prev, struct uhci_qh, node); pqh = list_entry(qh->node.prev, struct uhci_qh, node);
pqh->link = link_to_next_qh; pqh->link = link_to_next_qh;
...@@ -757,8 +758,8 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci, ...@@ -757,8 +758,8 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci,
/* /*
* Map status to standard result codes * Map status to standard result codes
* *
* <status> is (td_status(td) & 0xF60000), a.k.a. * <status> is (td_status(uhci, td) & 0xF60000), a.k.a.
* uhci_status_bits(td_status(td)). * uhci_status_bits(td_status(uhci, td)).
* Note: <status> does not include the TD_CTRL_NAK bit. * Note: <status> does not include the TD_CTRL_NAK bit.
* <dir_out> is True for output TDs and False for input TDs. * <dir_out> is True for output TDs and False for input TDs.
*/ */
...@@ -794,7 +795,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, ...@@ -794,7 +795,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize); int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
int len = urb->transfer_buffer_length; int len = urb->transfer_buffer_length;
dma_addr_t data = urb->transfer_dma; dma_addr_t data = urb->transfer_dma;
__le32 *plink; __hc32 *plink;
struct urb_priv *urbp = urb->hcpriv; struct urb_priv *urbp = urb->hcpriv;
int skel; int skel;
...@@ -811,7 +812,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, ...@@ -811,7 +812,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
*/ */
td = qh->dummy_td; td = qh->dummy_td;
uhci_add_td_to_urbp(td, urbp); uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status, destination | uhci_explen(8), uhci_fill_td(uhci, td, status, destination | uhci_explen(8),
urb->setup_dma); urb->setup_dma);
plink = &td->link; plink = &td->link;
status |= TD_CTRL_ACTIVE; status |= TD_CTRL_ACTIVE;
...@@ -844,14 +845,14 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, ...@@ -844,14 +845,14 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci); td = uhci_alloc_td(uhci);
if (!td) if (!td)
goto nomem; goto nomem;
*plink = LINK_TO_TD(td); *plink = LINK_TO_TD(uhci, td);
/* Alternate Data0/1 (start with Data1) */ /* Alternate Data0/1 (start with Data1) */
destination ^= TD_TOKEN_TOGGLE; destination ^= TD_TOKEN_TOGGLE;
uhci_add_td_to_urbp(td, urbp); uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status, destination | uhci_explen(pktsze), uhci_fill_td(uhci, td, status,
data); destination | uhci_explen(pktsze), data);
plink = &td->link; plink = &td->link;
data += pktsze; data += pktsze;
...@@ -864,14 +865,14 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, ...@@ -864,14 +865,14 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci); td = uhci_alloc_td(uhci);
if (!td) if (!td)
goto nomem; goto nomem;
*plink = LINK_TO_TD(td); *plink = LINK_TO_TD(uhci, td);
/* Change direction for the status transaction */ /* Change direction for the status transaction */
destination ^= (USB_PID_IN ^ USB_PID_OUT); destination ^= (USB_PID_IN ^ USB_PID_OUT);
destination |= TD_TOKEN_TOGGLE; /* End in Data1 */ destination |= TD_TOKEN_TOGGLE; /* End in Data1 */
uhci_add_td_to_urbp(td, urbp); uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status | TD_CTRL_IOC, uhci_fill_td(uhci, td, status | TD_CTRL_IOC,
destination | uhci_explen(0), 0); destination | uhci_explen(0), 0);
plink = &td->link; plink = &td->link;
...@@ -881,11 +882,11 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, ...@@ -881,11 +882,11 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci); td = uhci_alloc_td(uhci);
if (!td) if (!td)
goto nomem; goto nomem;
*plink = LINK_TO_TD(td); *plink = LINK_TO_TD(uhci, td);
uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0); uhci_fill_td(uhci, td, 0, USB_PID_OUT | uhci_explen(0), 0);
wmb(); wmb();
qh->dummy_td->status |= cpu_to_le32(TD_CTRL_ACTIVE); qh->dummy_td->status |= cpu_to_hc32(uhci, TD_CTRL_ACTIVE);
qh->dummy_td = td; qh->dummy_td = td;
/* Low-speed transfers get a different queue, and won't hog the bus. /* Low-speed transfers get a different queue, and won't hog the bus.
...@@ -921,7 +922,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, ...@@ -921,7 +922,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
int len = urb->transfer_buffer_length; int len = urb->transfer_buffer_length;
int this_sg_len; int this_sg_len;
dma_addr_t data; dma_addr_t data;
__le32 *plink; __hc32 *plink;
struct urb_priv *urbp = urb->hcpriv; struct urb_priv *urbp = urb->hcpriv;
unsigned int toggle; unsigned int toggle;
struct scatterlist *sg; struct scatterlist *sg;
...@@ -974,10 +975,10 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, ...@@ -974,10 +975,10 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci); td = uhci_alloc_td(uhci);
if (!td) if (!td)
goto nomem; goto nomem;
*plink = LINK_TO_TD(td); *plink = LINK_TO_TD(uhci, td);
} }
uhci_add_td_to_urbp(td, urbp); uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status, uhci_fill_td(uhci, td, status,
destination | uhci_explen(pktsze) | destination | uhci_explen(pktsze) |
(toggle << TD_TOKEN_TOGGLE_SHIFT), (toggle << TD_TOKEN_TOGGLE_SHIFT),
data); data);
...@@ -1010,10 +1011,10 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, ...@@ -1010,10 +1011,10 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci); td = uhci_alloc_td(uhci);
if (!td) if (!td)
goto nomem; goto nomem;
*plink = LINK_TO_TD(td); *plink = LINK_TO_TD(uhci, td);
uhci_add_td_to_urbp(td, urbp); uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status, uhci_fill_td(uhci, td, status,
destination | uhci_explen(0) | destination | uhci_explen(0) |
(toggle << TD_TOKEN_TOGGLE_SHIFT), (toggle << TD_TOKEN_TOGGLE_SHIFT),
data); data);
...@@ -1028,7 +1029,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, ...@@ -1028,7 +1029,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
* fast side but not enough to justify delaying an interrupt * fast side but not enough to justify delaying an interrupt
* more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT * more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT
* flag setting. */ * flag setting. */
td->status |= cpu_to_le32(TD_CTRL_IOC); td->status |= cpu_to_hc32(uhci, TD_CTRL_IOC);
/* /*
* Build the new dummy TD and activate the old one * Build the new dummy TD and activate the old one
...@@ -1036,11 +1037,11 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, ...@@ -1036,11 +1037,11 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci); td = uhci_alloc_td(uhci);
if (!td) if (!td)
goto nomem; goto nomem;
*plink = LINK_TO_TD(td); *plink = LINK_TO_TD(uhci, td);
uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0); uhci_fill_td(uhci, td, 0, USB_PID_OUT | uhci_explen(0), 0);
wmb(); wmb();
qh->dummy_td->status |= cpu_to_le32(TD_CTRL_ACTIVE); qh->dummy_td->status |= cpu_to_hc32(uhci, TD_CTRL_ACTIVE);
qh->dummy_td = td; qh->dummy_td = td;
usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
...@@ -1133,7 +1134,7 @@ static int uhci_fixup_short_transfer(struct uhci_hcd *uhci, ...@@ -1133,7 +1134,7 @@ static int uhci_fixup_short_transfer(struct uhci_hcd *uhci,
* the queue at the status stage transaction, which is * the queue at the status stage transaction, which is
* the last TD. */ * the last TD. */
WARN_ON(list_empty(&urbp->td_list)); WARN_ON(list_empty(&urbp->td_list));
qh->element = LINK_TO_TD(td); qh->element = LINK_TO_TD(uhci, td);
tmp = td->list.prev; tmp = td->list.prev;
ret = -EINPROGRESS; ret = -EINPROGRESS;
...@@ -1142,8 +1143,9 @@ static int uhci_fixup_short_transfer(struct uhci_hcd *uhci, ...@@ -1142,8 +1143,9 @@ static int uhci_fixup_short_transfer(struct uhci_hcd *uhci,
/* When a bulk/interrupt transfer is short, we have to /* When a bulk/interrupt transfer is short, we have to
* fix up the toggles of the following URBs on the queue * fix up the toggles of the following URBs on the queue
* before restarting the queue at the next URB. */ * before restarting the queue at the next URB. */
qh->initial_toggle = uhci_toggle(td_token(qh->post_td)) ^ 1; qh->initial_toggle =
uhci_fixup_toggles(qh, 1); uhci_toggle(td_token(uhci, qh->post_td)) ^ 1;
uhci_fixup_toggles(uhci, qh, 1);
if (list_empty(&urbp->td_list)) if (list_empty(&urbp->td_list))
td = qh->post_td; td = qh->post_td;
...@@ -1178,7 +1180,7 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) ...@@ -1178,7 +1180,7 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
unsigned int ctrlstat; unsigned int ctrlstat;
int len; int len;
ctrlstat = td_status(td); ctrlstat = td_status(uhci, td);
status = uhci_status_bits(ctrlstat); status = uhci_status_bits(ctrlstat);
if (status & TD_CTRL_ACTIVE) if (status & TD_CTRL_ACTIVE)
return -EINPROGRESS; return -EINPROGRESS;
...@@ -1188,7 +1190,7 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) ...@@ -1188,7 +1190,7 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
if (status) { if (status) {
ret = uhci_map_status(status, ret = uhci_map_status(status,
uhci_packetout(td_token(td))); uhci_packetout(td_token(uhci, td)));
if ((debug == 1 && ret != -EPIPE) || debug > 1) { if ((debug == 1 && ret != -EPIPE) || debug > 1) {
/* Some debugging code */ /* Some debugging code */
dev_dbg(&urb->dev->dev, dev_dbg(&urb->dev->dev,
...@@ -1204,7 +1206,7 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) ...@@ -1204,7 +1206,7 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
} }
/* Did we receive a short packet? */ /* Did we receive a short packet? */
} else if (len < uhci_expected_length(td_token(td))) { } else if (len < uhci_expected_length(td_token(uhci, td))) {
/* For control transfers, go to the status TD if /* For control transfers, go to the status TD if
* this isn't already the last data TD */ * this isn't already the last data TD */
...@@ -1236,10 +1238,10 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) ...@@ -1236,10 +1238,10 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
if (ret < 0) { if (ret < 0) {
/* Note that the queue has stopped and save /* Note that the queue has stopped and save
* the next toggle value */ * the next toggle value */
qh->element = UHCI_PTR_TERM; qh->element = UHCI_PTR_TERM(uhci);
qh->is_stopped = 1; qh->is_stopped = 1;
qh->needs_fixup = (qh->type != USB_ENDPOINT_XFER_CONTROL); qh->needs_fixup = (qh->type != USB_ENDPOINT_XFER_CONTROL);
qh->initial_toggle = uhci_toggle(td_token(td)) ^ qh->initial_toggle = uhci_toggle(td_token(uhci, td)) ^
(ret == -EREMOTEIO); (ret == -EREMOTEIO);
} else /* Short packet received */ } else /* Short packet received */
...@@ -1335,14 +1337,14 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, ...@@ -1335,14 +1337,14 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
return -ENOMEM; return -ENOMEM;
uhci_add_td_to_urbp(td, urbp); uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status, destination | uhci_fill_td(uhci, td, status, destination |
uhci_explen(urb->iso_frame_desc[i].length), uhci_explen(urb->iso_frame_desc[i].length),
urb->transfer_dma + urb->transfer_dma +
urb->iso_frame_desc[i].offset); urb->iso_frame_desc[i].offset);
} }
/* Set the interrupt-on-completion flag on the last packet. */ /* Set the interrupt-on-completion flag on the last packet. */
td->status |= cpu_to_le32(TD_CTRL_IOC); td->status |= cpu_to_hc32(uhci, TD_CTRL_IOC);
/* Add the TDs to the frame list */ /* Add the TDs to the frame list */
frame = urb->start_frame; frame = urb->start_frame;
...@@ -1378,7 +1380,7 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) ...@@ -1378,7 +1380,7 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
uhci_remove_tds_from_frame(uhci, qh->iso_frame); uhci_remove_tds_from_frame(uhci, qh->iso_frame);
ctrlstat = td_status(td); ctrlstat = td_status(uhci, td);
if (ctrlstat & TD_CTRL_ACTIVE) { if (ctrlstat & TD_CTRL_ACTIVE) {
status = -EXDEV; /* TD was added too late? */ status = -EXDEV; /* TD was added too late? */
} else { } else {
...@@ -1629,7 +1631,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) ...@@ -1629,7 +1631,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
* queue, the QH can now be re-activated. */ * queue, the QH can now be re-activated. */
if (!list_empty(&qh->queue)) { if (!list_empty(&qh->queue)) {
if (qh->needs_fixup) if (qh->needs_fixup)
uhci_fixup_toggles(qh, 0); uhci_fixup_toggles(uhci, qh, 0);
/* If the first URB on the queue wants FSBR but its time /* If the first URB on the queue wants FSBR but its time
* limit has expired, set the next TD to interrupt on * limit has expired, set the next TD to interrupt on
...@@ -1639,7 +1641,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) ...@@ -1639,7 +1641,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
struct uhci_td *td = list_entry(urbp->td_list.next, struct uhci_td *td = list_entry(urbp->td_list.next,
struct uhci_td, list); struct uhci_td, list);
td->status |= __cpu_to_le32(TD_CTRL_IOC); td->status |= cpu_to_hc32(uhci, TD_CTRL_IOC);
} }
uhci_activate_qh(uhci, qh); uhci_activate_qh(uhci, qh);
...@@ -1686,7 +1688,7 @@ static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh) ...@@ -1686,7 +1688,7 @@ static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh)
} else { } else {
urbp = list_entry(qh->queue.next, struct urb_priv, node); urbp = list_entry(qh->queue.next, struct urb_priv, node);
td = list_entry(urbp->td_list.next, struct uhci_td, list); td = list_entry(urbp->td_list.next, struct uhci_td, list);
status = td_status(td); status = td_status(uhci, td);
if (!(status & TD_CTRL_ACTIVE)) { if (!(status & TD_CTRL_ACTIVE)) {
/* We're okay, the queue has advanced */ /* We're okay, the queue has advanced */
...@@ -1704,7 +1706,8 @@ static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh) ...@@ -1704,7 +1706,8 @@ static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh)
if (time_after(jiffies, qh->advance_jiffies + QH_WAIT_TIMEOUT)) { if (time_after(jiffies, qh->advance_jiffies + QH_WAIT_TIMEOUT)) {
/* Detect the Intel bug and work around it */ /* Detect the Intel bug and work around it */
if (qh->post_td && qh_element(qh) == LINK_TO_TD(qh->post_td)) { if (qh->post_td && qh_element(qh) ==
LINK_TO_TD(uhci, qh->post_td)) {
qh->element = qh->post_td->link; qh->element = qh->post_td->link;
qh->advance_jiffies = jiffies; qh->advance_jiffies = jiffies;
ret = 1; ret = 1;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册