(Sorry for this repost, apparently the mailserver reformats before sending.)
There is a published errata for the PPC440EPX, USBH_23: EHCI and OHCI
Linux module contention. The overview states: When running Linux with
both EHCI and OHCI modules loaded, the EHCI module experiences a fatal
error when a high-speed device is connected to the USB2.0 Host controller.
The EHCI module functions normally when the OHCI module is not loaded.
The patch below is a software work around for the problem. I would like to
discuss the probability of the patch being accepted into the kernel and /
or what could be done to increase the probability. The patch is against
the head of the DENX git repository, linux-2.6-denx.git.
Signed-off-by: Mark Miesfeld <[EMAIL PROTECTED]>
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 012954b..1569c8b 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -67,6 +67,26 @@ config USB_EHCI_TT_NEWSCHED
If unsure, say N.
+config USB_PPC440EPX_USBH_23_ERRATA
+ bool "PPC440EPX USBH_23 ERRATA EHCI and OHCI contention"
+ depends on USB_EHCI_HCD && 440EPX
+ default y
+ select USB_OHCI_HCD
+ select USB_OHCI_HCD_PPC_SOC
+ ---help---
+ Allows the EHCI and OHCI drivers to be loaded together when using
+ the USB Host controller on the 440EPX processor chip. This is
+ necessary when either high speed or full speed devices may be
+ connected to the USB Host port. You must compile and use the OHCI
+ driver when selecting this option.
+
+ The option is not needed if the USB Host port is only used with
+ USB 2.0 high speed devices and the OHCI driver is not compiled or
+ loaded.
+
+ Say N when the OHCI driver for the 440EPX will not be compiled or
+ will not be loaded. If unsure, say Y.
+
config USB_EHCI_BIG_ENDIAN_MMIO
bool
depends on USB_EHCI_HCD
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 1813b7c..03516d4 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -289,6 +289,12 @@ static inline void remove_companion_file
/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_USB_PPC440EPX_USBH_23_ERRATA
+extern void ohci_ppc_set_hcfs(int state);
+#define HCFS_SUSPEND 0
+#define HCFS_OPERATIONAL 1
+#endif
+
static int check_reset_complete (
struct ehci_hcd *ehci,
int index,
@@ -319,8 +325,17 @@ static int check_reset_complete (
port_status &= ~PORT_RWC_BITS;
ehci_writel(ehci, port_status, status_reg);
- } else
+#ifdef CONFIG_USB_PPC440EPX_USBH_23_ERRATA
+ /* ensure 440EPX ohci controller state is operational */
+ ohci_ppc_set_hcfs(HCFS_OPERATIONAL);
+#endif
+ } else {
ehci_dbg (ehci, "port %d high speed\n", index + 1);
+#ifdef CONFIG_USB_PPC440EPX_USBH_23_ERRATA
+ /* ensure 440EPx ohci controller state is suspended */
+ ohci_ppc_set_hcfs(HCFS_SUSPEND);
+#endif
+ }
return port_status;
}
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index 1a2e177..7195311 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -20,6 +20,37 @@ #include <linux/signal.h>
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
+#ifdef CONFIG_USB_PPC440EPX_USBH_23_ERRATA
+struct ohci_hcd *cached_ohci = NULL;
+#define HCFS_SUSPEND 0
+#define HCFS_OPERATIONAL 1
+void ohci_ppc_set_hcfs(int state) {
+ u32 hc_control;
+
+ hc_control = (ohci_readl(cached_ohci, &cached_ohci->regs->control)
+ & ~OHCI_CTRL_HCFS);
+
+ switch ( state ) {
+ case HCFS_SUSPEND:
+ hc_control |= OHCI_USB_SUSPEND;
+ break;
+ case HCFS_OPERATIONAL :
+ hc_control |= OHCI_USB_OPER;
+ break;
+
+ default:
+ /* this is unexpected, shoud never happen */
+ hc_control |= OHCI_USB_SUSPEND;
+ break;
+ }
+
+ /* write the new state and flush the write. */
+ ohci_writel(cached_ohci, hc_control, &cached_ohci->regs->control);
+ (void) ohci_readl(cached_ohci, &cached_ohci->regs->control);
+}
+EXPORT_SYMBOL (ohci_ppc_set_hcfs);
+#endif
+
/**
* usb_hcd_ppc_soc_probe - initialize On-Chip HCDs
* Context: !in_interrupt()
@@ -76,9 +107,27 @@ static int usb_hcd_ppc_soc_probe(const s
ohci_hcd_init(ohci);
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
- if (retval == 0)
+ if (retval == 0) {
+#ifdef CONFIG_USB_PPC440EPX_USBH_23_ERRATA
+ /* At this point ohci_run has executed, the controller is
+ * running, the root ports set up, etc. Now, put the core in
+ * the suspended state. The ehci driver will bring it out of
+ * suspended state when / if a non-high speed USB device is
+ * attached to the USB Host port.
+ */
+ u32 hc_control;
+ cached_ohci = ohci;
+ spin_lock_irq(&ohci->lock);
+
+ hc_control = ohci_readl(ohci, &ohci->regs->control);
+ hc_control |= OHCI_USB_SUSPEND;
+ ohci_writel(ohci, hc_control, &ohci->regs->control);
+ (void) ohci_readl(ohci, &ohci->regs->control);
+
+ spin_unlock_irq(&ohci->lock);
+#endif
return retval;
-
+ }
pr_debug("Removing PPC-SOC USB Controller\n");
iounmap(hcd->regs);
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel