On Saturday 09 December 2006 12:26 am, Benjamin Herrenschmidt wrote:
> This patch applies David Brownell's suggestion for reworking the
> OHCI quirk mecanism via a table of PCI IDs. It adapts the existing
> quirks to use that mecanism.

"mechanism".  :)

Thanks for doing this.


> This also moves the quirks to reset() as suggested by the comment
> in there. This is necessary as we need to have the endian properly
> set before we try to init the controller.
> 
> Signed-off-by: Benjamin Herrenschmidt <[EMAIL PROTECTED]>

Acked-by: David Brownell <[EMAIL PROTECTED]>

> 
>  drivers/usb/host/ohci-pci.c |  173 
> +++++++++++++++++++++++++++-----------------
>  1 file changed, 110 insertions(+), 63 deletions(-)
> 
> Index: linux-work/drivers/usb/host/ohci-pci.c
> ===================================================================
> --- linux-work.orig/drivers/usb/host/ohci-pci.c       2006-12-09 
> 19:14:30.000000000 +1100
> +++ linux-work/drivers/usb/host/ohci-pci.c    2006-12-09 19:23:37.000000000 
> +1100
> @@ -20,79 +20,128 @@
>  
>  /*-------------------------------------------------------------------------*/
>  
> -static int
> -ohci_pci_reset (struct usb_hcd *hcd)
> +/* AMD 756, for most chips (early revs), corrupts register
> + * values on read ... so enable the vendor workaround.
> + */
> +static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd)
>  {
>       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
>  
> -     ohci_hcd_init (ohci);
> -     return ohci_init (ohci);
> +     ohci->flags = OHCI_QUIRK_AMD756;
> +     ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
> +
> +     /* also erratum 10 (suspend/resume issues) */
> +     device_init_wakeup(&hcd->self.root_hub->dev, 0);
> +
> +     return 0;
>  }
>  
> -static int __devinit
> -ohci_pci_start (struct usb_hcd *hcd)
> +/* Apple's OHCI driver has a lot of bizarre workarounds
> + * for this chip.  Evidently control and bulk lists
> + * can get confused.  (B&W G3 models, and ...)
> + */
> +static int __devinit ohci_quirk_opti(struct usb_hcd *hcd)
>  {
>       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
> -     int             ret;
>  
> -     /* REVISIT this whole block should move to reset(), which handles
> -      * all the other one-time init.
> +     ohci_dbg (ohci, "WARNING: OPTi workarounds unavailable\n");
> +
> +     return 0;
> +}
> +
> +/* Check for NSC87560. We have to look at the bridge (fn1) to
> + * identify the USB (fn2). This quirk might apply to more or
> + * even all NSC stuff.
> + */
> +static int __devinit ohci_quirk_ns(struct usb_hcd *hcd)
> +{
> +     struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
> +     struct pci_dev  *b;
> +
> +     b  = pci_get_slot (pdev->bus, PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
> +     if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
> +         && b->vendor == PCI_VENDOR_ID_NS) {
> +             struct ohci_hcd *ohci = hcd_to_ohci (hcd);
> +
> +             ohci->flags |= OHCI_QUIRK_SUPERIO;
> +             ohci_dbg (ohci, "Using NSC SuperIO setup\n");
> +     }
> +     pci_dev_put(b);
> +
> +     return 0;
> +}
> +
> +/* Check for Compaq's ZFMicro chipset, which needs short
> + * delays before control or bulk queues get re-activated
> + * in finish_unlinks()
> + */
> +static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd)
> +{
> +     struct ohci_hcd *ohci = hcd_to_ohci (hcd);
> +
> +     ohci->flags |= OHCI_QUIRK_ZFMICRO;
> +     ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
> +
> +     return 0;
> +}
> +
> +
> +/* List of quirks for OHCI */
> +static const struct pci_device_id ohci_pci_quirks[] = {
> +     {
> +             PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x740c),
> +             .driver_data = (unsigned long)ohci_quirk_amd756,
> +     },
> +     {
> +             PCI_DEVICE(PCI_VENDOR_ID_OPTI, 0xc861),
> +             .driver_data = (unsigned long)ohci_quirk_opti,
> +     },
> +     {
> +             PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_ANY_ID),
> +             .driver_data = (unsigned long)ohci_quirk_ns,
> +     },
> +     {
> +             PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xa0f8),
> +             .driver_data = (unsigned long)ohci_quirk_zfmicro,
> +     },
> +     /* FIXME for some of the early AMD 760 southbridges, OHCI
> +      * won't work at all.  blacklist them.
>        */
> -     if (hcd->self.controller) {
> -             struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
> +     {},
> +};
>  
> -             /* AMD 756, for most chips (early revs), corrupts register
> -              * values on read ... so enable the vendor workaround.
> -              */
> -             if (pdev->vendor == PCI_VENDOR_ID_AMD
> -                             && pdev->device == 0x740c) {
> -                     ohci->flags = OHCI_QUIRK_AMD756;
> -                     ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
> -                     /* also erratum 10 (suspend/resume issues) */
> -                     device_init_wakeup(&hcd->self.root_hub->dev, 0);
> -             }
> +static int ohci_pci_reset (struct usb_hcd *hcd)
> +{
> +     struct ohci_hcd *ohci = hcd_to_ohci (hcd);
> +     int ret = 0;
>  
> -             /* FIXME for some of the early AMD 760 southbridges, OHCI
> -              * won't work at all.  blacklist them.
> -              */
> +     if (hcd->self.controller) {
> +             struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
> +             const struct pci_device_id *quirk_id;
>  
> -             /* Apple's OHCI driver has a lot of bizarre workarounds
> -              * for this chip.  Evidently control and bulk lists
> -              * can get confused.  (B&W G3 models, and ...)
> -              */
> -             else if (pdev->vendor == PCI_VENDOR_ID_OPTI
> -                             && pdev->device == 0xc861) {
> -                     ohci_dbg (ohci,
> -                             "WARNING: OPTi workarounds unavailable\n");
> +             quirk_id = pci_match_id(ohci_pci_quirks, pdev);
> +             if (quirk_id != NULL) {
> +                     int (*quirk)(struct ohci_hcd *ohci);
> +                     quirk = (void *)quirk_id->driver_data;
> +                     ret = quirk(ohci);
>               }
> +     }
> +     if (ret == 0) {
> +             ohci_hcd_init (ohci);
> +             return ohci_init (ohci);
> +     }
> +     return ret;
> +}
>  
> -             /* Check for NSC87560. We have to look at the bridge (fn1) to
> -              * identify the USB (fn2). This quirk might apply to more or
> -              * even all NSC stuff.
> -              */
> -             else if (pdev->vendor == PCI_VENDOR_ID_NS) {
> -                     struct pci_dev  *b;
>  
> -                     b  = pci_get_slot (pdev->bus,
> -                                     PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
> -                     if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
> -                                     && b->vendor == PCI_VENDOR_ID_NS) {
> -                             ohci->flags |= OHCI_QUIRK_SUPERIO;
> -                             ohci_dbg (ohci, "Using NSC SuperIO setup\n");
> -                     }
> -                     pci_dev_put(b);
> -             }
> +static int __devinit ohci_pci_start (struct usb_hcd *hcd)
> +{
> +     struct ohci_hcd *ohci = hcd_to_ohci (hcd);
> +     int             ret;
>  
> -             /* Check for Compaq's ZFMicro chipset, which needs short 
> -              * delays before control or bulk queues get re-activated
> -              * in finish_unlinks()
> -              */
> -             else if (pdev->vendor == PCI_VENDOR_ID_COMPAQ
> -                             && pdev->device  == 0xa0f8) {
> -                     ohci->flags |= OHCI_QUIRK_ZFMICRO;
> -                     ohci_dbg (ohci,
> -                             "enabled Compaq ZFMicro chipset quirk\n");
> -             }
> +#ifdef CONFIG_PM /* avoid warnings about unused pdev */
> +     if (hcd->self.controller) {
> +             struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
>  
>               /* RWC may not be set for add-in PCI cards, since boot
>                * firmware probably ignored them.  This transfers PCI
> @@ -101,16 +150,14 @@
>               if (device_may_wakeup(&pdev->dev))
>                       ohci->hc_control |= OHCI_CTRL_RWC;
>       }
> +#endif /* CONFIG_PM */
>  
> -     /* NOTE: there may have already been a first reset, to
> -      * keep bios/smm irqs from making trouble
> -      */
> -     if ((ret = ohci_run (ohci)) < 0) {
> +     ret = ohci_run (ohci);
> +     if (ret < 0) {
>               ohci_err (ohci, "can't start\n");
>               ohci_stop (hcd);
> -             return ret;
>       }
> -     return 0;
> +     return ret;
>  }
>  
>  #ifdef       CONFIG_PM
> 

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to