(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/ _______________________________________________ linux-usb-devel@lists.sourceforge.net To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel