aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/linux/linux-efika-2.6.20/0006-Rework-the-OHCI-quirk-mecanism-as-suggested-by-David.txt
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/linux/linux-efika-2.6.20/0006-Rework-the-OHCI-quirk-mecanism-as-suggested-by-David.txt')
-rw-r--r--recipes/linux/linux-efika-2.6.20/0006-Rework-the-OHCI-quirk-mecanism-as-suggested-by-David.txt236
1 files changed, 236 insertions, 0 deletions
diff --git a/recipes/linux/linux-efika-2.6.20/0006-Rework-the-OHCI-quirk-mecanism-as-suggested-by-David.txt b/recipes/linux/linux-efika-2.6.20/0006-Rework-the-OHCI-quirk-mecanism-as-suggested-by-David.txt
new file mode 100644
index 0000000000..39f6fef607
--- /dev/null
+++ b/recipes/linux/linux-efika-2.6.20/0006-Rework-the-OHCI-quirk-mecanism-as-suggested-by-David.txt
@@ -0,0 +1,236 @@
+From 9282a04f14cef512736ac4a895fb48456e6a8989 Mon Sep 17 00:00:00 2001
+From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+Date: Thu, 14 Dec 2006 14:13:26 +1100
+Subject: [PATCH] [PATCH] Rework the OHCI quirk mecanism as suggested by David
+
+This patch applies David Brownell's suggestion for reworking the
+OHCI quirk mechanism via a table of PCI IDs. It adapts the existing
+quirks to use that mechanism.
+
+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 <benh@kernel.crashing.org>
+Acked-by: David Brownell <dbrownell@users.sourceforge.net>
+
+ drivers/usb/host/ohci-pci.c | 173 +++++++++++++++++++++++++++-----------------
+ 1 file changed, 110 insertions(+), 63 deletions(-)
+---
+ drivers/usb/host/ohci-pci.c | 173 +++++++++++++++++++++++++++----------------
+ 1 files changed, 110 insertions(+), 63 deletions(-)
+
+diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
+index 596e0b4..82fbec3 100644
+--- a/drivers/usb/host/ohci-pci.c
++++ b/drivers/usb/host/ohci-pci.c
+@@ -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.
+ */
++ {},
++};
++
++static int ohci_pci_reset (struct usb_hcd *hcd)
++{
++ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
++ int ret = 0;
++
+ if (hcd->self.controller) {
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
++ const struct pci_device_id *quirk_id;
+
+- /* 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);
++ quirk_id = pci_match_id(ohci_pci_quirks, pdev);
++ if (quirk_id != NULL) {
++ int (*quirk)(struct usb_hcd *ohci);
++ quirk = (void *)quirk_id->driver_data;
++ ret = quirk(hcd);
+ }
++ }
++ if (ret == 0) {
++ ohci_hcd_init (ohci);
++ return ohci_init (ohci);
++ }
++ return ret;
++}
+
+- /* FIXME for some of the early AMD 760 southbridges, OHCI
+- * won't work at all. blacklist them.
+- */
+-
+- /* 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");
+- }
+
+- /* 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 @@ ohci_pci_start (struct usb_hcd *hcd)
+ 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
+--
+1.4.4.2
+