On Wed, 27 Aug 2008, Vitaly Bordug wrote:

> A published errata for ppc440epx states, that 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, and functions normally
> if OHCI module is not loaded. 
> 
> Quote from original descriprion:
> 
> The 440EPx USB 2.0 Host controller is an EHCI compliant controller.  In USB
> 2.0 Host controllers, each EHCI controller has one or more companion
> controllers, which may be OHCI or UHCI.  An USB 2.0 Host controller will
> contain one or more ports.  For each port, only one of the controllers is
> connected at any one time. In the 440EPx, there is only one OHCI companion 
> controller, 
> and only one USB 2.0 Host port.
> All ports on an USB 2.0 controller default to the companion controller.  If
> you load only an ohci driver, it will have control of the ports and any
> deviceplugged in will operate, although high speed devices will be forced to
> operate at full speed.  When an ehci driver is loaded, it explicitly takes 
> control
> of the ports.  If there is a device connected, and / or every time there is a
> new device connected, the ehci driver determines if the device is high speed 
> or
> not.  If it is high speed, the driver retains control of the port.  If it
> is not, the driver explicitly gives the companion controller control of the
> port.

This doesn't explain why the fatal error occurs.

> The is a software workaround that uses 
> Initial version of the software workaround was posted to linux-usb-devel:
> 
> http://www.mail-archive.com/[EMAIL PROTECTED]/msg54019.html
> 
> and later available from amcc.com:
> http://www.amcc.com/Embedded/Downloads/download.html?cat=1&family=15&ins=2
> 
> The patch below is generally based on the latter, but reworked to
> powerpc/of_device USB drivers, and uses a few devicetree inquiries to get
> rid of all the hardcoded defines and CONFIG_* stuff, in favor to
> defining specific quirk. The latter required to add more accurate
> description into compatible field of USB node for 'sequioia' board. 

I have some doubts about parts of this patch.

> --- a/drivers/usb/host/ehci-ppc-of.c
> +++ b/drivers/usb/host/ehci-ppc-of.c
> @@ -107,16 +107,17 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const 
> struct of_device_id *match)
>  {
>       struct device_node *dn = op->node;
>       struct usb_hcd *hcd;
> -     struct ehci_hcd *ehci;
> +     struct ehci_hcd *ehci = NULL;
>       struct resource res;
>       int irq;
>       int rv;
>  
> +     struct device_node *np;
> +
>       if (usb_disabled())
>               return -ENODEV;
>  
>       dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
> -
>       rv = of_address_to_resource(dn, 0, &res);
>       if (rv)
>               return rv;
> @@ -125,6 +126,7 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const struct 
> of_device_id *match)
>       if (!hcd)
>               return -ENOMEM;
>  
> +

Is there any reason for these apparently gratuitous whitespace changes?

>       hcd->rsrc_start = res.start;
>       hcd->rsrc_len = res.end - res.start + 1;
>  
> @@ -172,6 +174,21 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const struct 
> of_device_id *match)
>                               rv ? "NOT ": "");
>       }
>  
> +     np = of_find_compatible_node(NULL, NULL, "ibm,usb-ohci-440epx");
> +     if (np != NULL) {
> +     /* claim we really affected by usb23 erratum */
> +             ehci->has_amcc_usb23 = 1;
> +             if (!of_address_to_resource(np, 0, &res))
> +                     ehci->ohci_hcctrl_reg = ioremap(res.start +
> +                                     OHCI_HCCTRL_OFFSET, OHCI_HCCTRL_LEN);
> +             else
> +                     pr_debug(__FILE__ ": no ohci offset in fdt\n");
> +             if (!ehci->ohci_hcctrl_reg) {
> +                     pr_debug(__FILE__ ": ioremap for ohci hcctrl failed\n");
> +                     return -ENOMEM;

This is a memory leak.

> --- a/drivers/usb/host/ehci.h
> +++ b/drivers/usb/host/ehci.h
> @@ -809,6 +819,20 @@ static inline u32 hc32_to_cpup (const struct ehci_hcd 
> *ehci, const __hc32 *x)
>               le32_to_cpup((__force __le32 *)x);
>  }
>  
> +static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational)
> +{
> +     u32 hc_control;
> +
> +     hc_control = (readl_be(ehci->ohci_hcctrl_reg) & ~OHCI_CTRL_HCFS);
> +     if (operational)
> +             hc_control |= OHCI_USB_OPER;
> +     else
> +             hc_control |= OHCI_USB_SUSPEND;
> +
> +     writel_be(hc_control, ehci->ohci_hcctrl_reg);
> +     (void) readl_be(ehci->ohci_hcctrl_reg);
> +}
> +

This should be protected by a preprocessor test so that the code 
doesn't get compiled on architectures that don't need it.

> --- a/drivers/usb/host/ohci-ppc-of.c
> +++ b/drivers/usb/host/ohci-ppc-of.c
> @@ -148,6 +148,31 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct 
> of_device_id *match)
>       if (rv == 0)
>               return 0;
>  
> +     /* by now, 440epx is known to show usb_23 erratum */
> +     np = of_find_compatible_node(NULL, NULL, "ibm,usb-ehci-440epx");
> +
> +     /* Work around - At this point ohci_run has executed, the
> +     * controller is running, everything, the root ports, etc., is
> +     * set up.  If the ehci driver is loaded, put the ohci 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.  If the ehci driver is not
> +     * loaded, do nothing. request_mem_region is used to test if
> +     * the ehci driver is loaded.
> +     */
> +     if (np !=  NULL) {
> +             ohci->flags |= OHCI_QUIRK_AMCC_USB23;
> +             if (!of_address_to_resource(np, 0, &res))
> +                     if (!request_mem_region(res.start, 0x4, hcd_name)) {
> +                             writel_be((readl_be(&ohci->regs->control) |
> +                                 OHCI_USB_SUSPEND), &ohci->regs->control);
> +                                 (void) readl_be(&ohci->regs->control);

Wrong indentation level.

> +                     } else  {
> +                             release_mem_region(res.start, 0x4);
> +                     }
> +             else
> +                 pr_debug(__FILE__ ": cannot get ehci offset from fdt\n");

Wrong indentation amount.

> +     }
>       iounmap(hcd->regs);
>  err_ioremap:
>       irq_dispose_mapping(irq);

I doubt this will interact properly with usbcore and the rest of
ohci-hcd.  They do not expect the root hub to be suspended unless they
know about it.

Alan Stern

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Reply via email to