Here is a patch to 2.6.0-test9 that addresses mips bit-endian bus accesses breaking
endianness in EHCI and OHCI. It also fixes a problem with ohci_dbg() not endian
swapping the frame number field in a debug print.
Untested on x86, but the changes are trivial so it should work there as well. I assume
the sanity test will catch any coarse errors there rather quickly.
diff -Naur linux-2.6.0-test9/drivers/usb/host/ehci-dbg.c
linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ehci-dbg.c
--- linux-2.6.0-test9/drivers/usb/host/ehci-dbg.c 2003-10-25 11:44:31.000000000
-0700
+++ linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ehci-dbg.c 2003-10-28
09:41:05.000000000 -0800
@@ -591,7 +591,7 @@
spin_lock_irqsave (&ehci->lock, flags);
/* Capability Registers */
- i = readw (&ehci->caps->hci_version);
+ i = HC_VERSION(readl (&ehci->caps->hc_capbase));
temp = snprintf (next, size,
"PCI device %s\nEHCI %x.%02x, hcd state %d (driver " DRIVER_VERSION
")\n",
pci_name(hcd->pdev),
diff -Naur linux-2.6.0-test9/drivers/usb/host/ehci.h
linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ehci.h
--- linux-2.6.0-test9/drivers/usb/host/ehci.h 2003-10-25 11:44:35.000000000 -0700
+++ linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ehci.h 2003-10-28
09:42:11.000000000 -0800
@@ -153,9 +153,9 @@
/* Section 2.2 Host Controller Capability Registers */
struct ehci_caps {
- u8 length; /* CAPLENGTH - size of this struct */
- u8 reserved; /* offset 0x1 */
- u16 hci_version; /* HCIVERSION - offset 0x2 */
+ u32 hc_capbase; /* HCCAPBASE - must be a u32 to be endian-neutral */
+#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */
+#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */
u32 hcs_params; /* HCSPARAMS - offset 0x4 */
#define HCS_DEBUG_PORT(p) (((p)>>20)&0xf) /* bits 23:20, debug port? */
#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
diff -Naur linux-2.6.0-test9/drivers/usb/host/ehci-hcd.c
linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ehci-hcd.c
--- linux-2.6.0-test9/drivers/usb/host/ehci-hcd.c 2003-10-25 11:44:01.000000000
-0700
+++ linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ehci-hcd.c 2003-10-28
09:41:38.000000000 -0800
@@ -324,8 +324,8 @@
spin_lock_init (&ehci->lock);
ehci->caps = (struct ehci_caps *) hcd->regs;
- ehci->regs = (struct ehci_regs *) (hcd->regs +
- readb (&ehci->caps->length));
+ ehci->regs = (struct ehci_regs *) (hcd->regs +
+ HC_LENGTH(ehci->caps->hc_capbase));
dbg_hcs_params (ehci, "reset");
dbg_hcc_params (ehci, "reset");
@@ -486,7 +486,7 @@
/* PCI Serial Bus Release Number is at 0x60 offset */
pci_read_config_byte (hcd->pdev, 0x60, &tempbyte);
- temp = readw (&ehci->caps->hci_version);
+ temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
ehci_info (ehci,
"USB %x.%x enabled, EHCI %x.%02x, driver %s\n",
((tempbyte & 0xf0)>>4), (tempbyte & 0x0f),
diff -Naur linux-2.6.0-test9/drivers/usb/host/ohci-dbg.c
linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ohci-dbg.c
--- linux-2.6.0-test9/drivers/usb/host/ohci-dbg.c 2003-10-25 11:44:36.000000000
-0700
+++ linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ohci-dbg.c 2003-10-28
09:35:45.000000000 -0800
@@ -269,7 +269,7 @@
ohci_dump_status (controller, NULL, 0);
if (controller->hcca)
ohci_dbg (controller,
- "hcca frame #%04x\n", controller->hcca->frame_no);
+ "hcca frame #%04x\n", OHCI_FRAME_NO(controller->hcca));
ohci_dump_roothub (controller, 1, NULL, 0);
}
@@ -617,7 +617,7 @@
/* hcca */
if (ohci->hcca)
ohci_dbg_sw (ohci, &next, &size,
- "hcca frame 0x%04x\n", ohci->hcca->frame_no);
+ "hcca frame 0x%04x\n", OHCI_FRAME_NO(ohci->hcca));
/* other registers mostly affect frame timings */
rdata = readl (®s->fminterval);
diff -Naur linux-2.6.0-test9/drivers/usb/host/ohci.h
linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ohci.h
--- linux-2.6.0-test9/drivers/usb/host/ohci.h 2003-10-25 11:44:57.000000000 -0700
+++ linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ohci.h 2003-10-28
09:43:51.000000000 -0800
@@ -172,8 +172,18 @@
struct ohci_hcca {
#define NUM_INTS 32
__u32 int_table [NUM_INTS]; /* periodic schedule */
- __u16 frame_no; /* current frame number */
- __u16 pad1; /* set to 0 on each frame_no change */
+
+ /*
+ * Note that the specification defines u16 frame_no, followed by u16 pad,
+ * which breaks endianness on big endian processors that do 32-bit bus
+ * accesses. The solution is to use a u32 to represent the frame number on
+ * all architectures. The pad is handled automatically as the zeroed
+ * upper word of the frame number. In the LE case, the frame_no (ls byte)
+ * goes out first, with no swapping. In the BE case, the frame_no (ls byte)
+ * also goes out first, after the 32-bit endian swap.
+ */
+ __u32 frame_no; /* current frame number */
+#define OHCI_FRAME_NO(hccap) (u16)((le32_to_cpu(hccap->frame_no) & 0xffff))
__u32 done_head; /* info returned for an interrupt */
u8 reserved_for_hc [116];
u8 what [4]; /* spec only identifies 252 bytes :) */
diff -Naur linux-2.6.0-test9/drivers/usb/host/ohci-hcd.c
linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ohci-hcd.c
--- linux-2.6.0-test9/drivers/usb/host/ohci-hcd.c 2003-10-25 11:42:54.000000000
-0700
+++ linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ohci-hcd.c 2003-10-27
17:01:33.000000000 -0800
@@ -226,7 +226,7 @@
if (retval < 0)
goto fail;
if (ed->type == PIPE_ISOCHRONOUS) {
- u16 frame = le16_to_cpu (ohci->hcca->frame_no);
+ u16 frame = OHCI_FRAME_NO(ohci->hcca);
/* delay a few frames before the first TD */
frame += max_t (u16, 8, ed->interval);
@@ -363,7 +363,7 @@
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
- return le16_to_cpu (ohci->hcca->frame_no);
+ return OHCI_FRAME_NO(ohci->hcca);
}
/*-------------------------------------------------------------------------*
@@ -591,7 +591,7 @@
*/
spin_lock (&ohci->lock);
if (ohci->ed_rm_list)
- finish_unlinks (ohci, le16_to_cpu (ohci->hcca->frame_no),
+ finish_unlinks (ohci, OHCI_FRAME_NO(ohci->hcca),
ptregs);
if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
&& HCD_IS_RUNNING(ohci->hcd.state))
diff -Naur linux-2.6.0-test9/drivers/usb/host/ohci-q.c
linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ohci-q.c
--- linux-2.6.0-test9/drivers/usb/host/ohci-q.c 2003-10-25 11:44:44.000000000 -0700
+++ linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ohci-q.c 2003-10-27
17:02:56.000000000 -0800
@@ -441,7 +441,7 @@
* behave. frame_no wraps every 2^16 msec, and changes right before
* SF is triggered.
*/
- ed->tick = le16_to_cpu (ohci->hcca->frame_no) + 1;
+ ed->tick = OHCI_FRAME_NO(ohci->hcca) + 1;
/* rm_list is just singly linked, for simplicity */
ed->ed_next = ohci->ed_rm_list;
-------------------------------------------------------
This SF.net email is sponsored by: SF.net Giveback Program.
Does SourceForge.net help you be more productive? Does it
help you create better code? SHARE THE LOVE, and help us help
YOU! Click Here: http://sourceforge.net/donate/
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel