vserver 1.9.5.x5
[linux-2.6.git] / drivers / pci / quirks.c
index 164f738..7fffd4d 100644 (file)
@@ -30,7 +30,7 @@ static void __devinit quirk_passive_release(struct pci_dev *dev)
 
        /* We have to make sure a particular bit is set in the PIIX3
           ISA bridge, so we have to go out and find it. */
-       while ((d = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, d))) {
+       while ((d = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, d))) {
                pci_read_config_byte(d, 0x82, &dlc);
                if (!(dlc & 1<<1)) {
                        printk(KERN_ERR "PCI: PIIX3: Enabling Passive Release on %s\n", pci_name(d));
@@ -116,21 +116,21 @@ static void __devinit quirk_vialatency(struct pci_dev *dev)
        /* Ok we have a potential problem chipset here. Now see if we have
           a buggy southbridge */
           
-       p = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL);
+       p = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL);
        if (p!=NULL) {
                pci_read_config_byte(p, PCI_CLASS_REVISION, &rev);
                /* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */
                /* Check for buggy part revisions */
-               if (rev < 0x40 || rev > 0x42) 
-                       return;
+               if (rev < 0x40 || rev > 0x42)
+                       goto exit;
        } else {
-               p = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, NULL);
+               p = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, NULL);
                if (p==NULL)    /* No problem parts */
-                       return;
+                       goto exit;
                pci_read_config_byte(p, PCI_CLASS_REVISION, &rev);
                /* Check for buggy part revisions */
                if (rev < 0x10 || rev > 0x12) 
-                       return;
+                       goto exit;
        }
        
        /*
@@ -153,6 +153,8 @@ static void __devinit quirk_vialatency(struct pci_dev *dev)
        busarb |= (1<<4);
        pci_write_config_byte(dev, 0x76, busarb);
        printk(KERN_INFO "Applying VIA southbridge workaround.\n");
+exit:
+       pci_dev_put(p);
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_8363_0,       quirk_vialatency );
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_8371_1,       quirk_vialatency );
@@ -213,6 +215,16 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,       PCI_DEVICE_ID_INTEL_82443BX_0,  qu
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82443BX_1,  quirk_natoma ); 
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82443BX_2,  quirk_natoma );
 
+/*
+ *  This chip can cause PCI parity errors if config register 0xA0 is read
+ *  while DMAs are occurring.
+ */
+static void __devinit quirk_citrine(struct pci_dev *dev)
+{
+       dev->cfg_size = 0xA0;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM,    PCI_DEVICE_ID_IBM_CITRINE,      quirk_citrine );
+
 /*
  *  S3 868 and 968 chips report region size equal to 32M, but they decode 64M.
  *  If it's needed, re-allocate the region.
@@ -477,25 +489,6 @@ static void __devinit quirk_via_acpi(struct pci_dev *d)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C586_3,     quirk_via_acpi );
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C686_4,     quirk_via_acpi );
 
-static void __devinit quirk_via_irqpic(struct pci_dev *dev)
-{
-       u8 irq, new_irq = dev->irq & 0xf;
-
-       pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
-
-       if (new_irq != irq) {
-               printk(KERN_INFO "PCI: Via IRQ fixup for %s, from %d to %d\n",
-                      pci_name(dev), irq, new_irq);
-
-               udelay(15);
-               pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq);
-       }
-}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C586_2,     quirk_via_irqpic );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C686_5,     quirk_via_irqpic );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C686_6,     quirk_via_irqpic );
-
-
 /*
  * PIIX3 USB: We have to disable USB interrupts that are
  * hardwired to PIRQD# and may be shared with an
@@ -688,12 +681,14 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,      PCI_DEVICE_ID_INTEL_82454NX,    quirk_
 /*
  *     VIA northbridges care about PCI_INTERRUPT_LINE
  */
-int interrupt_line_quirk;
+int via_interrupt_line_quirk;
 
 static void __devinit quirk_via_bridge(struct pci_dev *pdev)
 {
-       if(pdev->devfn == 0)
-               interrupt_line_quirk = 1;
+       if(pdev->devfn == 0) {
+               printk(KERN_INFO "PCI: Via IRQ fixup\n");
+               via_interrupt_line_quirk = 1;
+       }
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,    PCI_ANY_ID,                     quirk_via_bridge );
 
@@ -714,6 +709,26 @@ static void __init quirk_svwks_csb5ide(struct pci_dev *pdev)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, quirk_svwks_csb5ide );
 
+/*
+ *     Intel 82801CAM ICH3-M datasheet says IDE modes must be the same
+ */
+static void __init quirk_ide_samemode(struct pci_dev *pdev)
+{
+       u8 prog;
+
+       pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
+
+       if (((prog & 1) && !(prog & 4)) || ((prog & 4) && !(prog & 1))) {
+               printk(KERN_INFO "PCI: IDE mode mismatch; forcing legacy mode\n");
+               prog &= ~5;
+               pdev->class &= ~5;
+               pci_write_config_byte(pdev, PCI_CLASS_PROG, prog);
+               /* need to re-assign BARs for compat mode */
+               quirk_ide_bases(pdev);
+       }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, quirk_ide_samemode);
+
 /* This was originally an Alpha specific thing, but it really fits here.
  * The i82375 PCI/EISA bridge appears as non-classified. Fix that.
  */
@@ -769,6 +784,11 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
                        case 0x1751: /* M2N notebook */
                                asus_hides_smbus = 1;
                        }
+               if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
+                       switch (dev->subsystem_device) {
+                       case 0x186a: /* M6Ne notebook */
+                               asus_hides_smbus = 1;
+                       }
        } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_HP)) {
                if (dev->device ==  PCI_DEVICE_ID_INTEL_82855PM_HB)
                        switch(dev->subsystem_device) {
@@ -826,6 +846,234 @@ static void __init quirk_sis_96x_smbus(struct pci_dev *dev)
        pci_read_config_byte(dev, 0x77, &val);
 }
 
+
+#define UHCI_USBLEGSUP         0xc0            /* legacy support */
+#define UHCI_USBCMD            0               /* command register */
+#define UHCI_USBSTS            2               /* status register */
+#define UHCI_USBINTR           4               /* interrupt register */
+#define UHCI_USBLEGSUP_DEFAULT 0x2000          /* only PIRQ enable set */
+#define UHCI_USBCMD_RUN                (1 << 0)        /* RUN/STOP bit */
+#define UHCI_USBCMD_GRESET     (1 << 2)        /* Global reset */
+#define UHCI_USBCMD_CONFIGURE  (1 << 6)        /* config semaphore */
+#define UHCI_USBSTS_HALTED     (1 << 5)        /* HCHalted bit */
+
+#define OHCI_CONTROL           0x04
+#define OHCI_CMDSTATUS         0x08
+#define OHCI_INTRSTATUS                0x0c
+#define OHCI_INTRENABLE                0x10
+#define OHCI_INTRDISABLE       0x14
+#define OHCI_OCR               (1 << 3)        /* ownership change request */
+#define OHCI_CTRL_IR           (1 << 8)        /* interrupt routing */
+#define OHCI_INTR_OC           (1 << 30)       /* ownership change */
+
+#define EHCI_HCC_PARAMS                0x08            /* extended capabilities */
+#define EHCI_USBCMD            0               /* command register */
+#define EHCI_USBCMD_RUN                (1 << 0)        /* RUN/STOP bit */
+#define EHCI_USBSTS            4               /* status register */
+#define EHCI_USBSTS_HALTED     (1 << 12)       /* HCHalted bit */
+#define EHCI_USBINTR           8               /* interrupt register */
+#define EHCI_USBLEGSUP         0               /* legacy support register */
+#define EHCI_USBLEGSUP_BIOS    (1 << 16)       /* BIOS semaphore */
+#define EHCI_USBLEGSUP_OS      (1 << 24)       /* OS semaphore */
+#define EHCI_USBLEGCTLSTS      4               /* legacy control/status */
+#define EHCI_USBLEGCTLSTS_SOOE (1 << 13)       /* SMI on ownership change */
+
+int usb_early_handoff __devinitdata = 0;
+static int __init usb_handoff_early(char *str)
+{
+       usb_early_handoff = 1;
+       return 0;
+}
+__setup("usb-handoff", usb_handoff_early);
+
+static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev)
+{
+       unsigned long base = 0;
+       int wait_time, delta;
+       u16 val, sts;
+       int i;
+
+       for (i = 0; i < PCI_ROM_RESOURCE; i++)
+               if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
+                       base = pci_resource_start(pdev, i);
+                       break;
+               }
+
+       if (!base)
+               return;
+
+       /*
+        * stop controller
+        */
+       sts = inw(base + UHCI_USBSTS);
+       val = inw(base + UHCI_USBCMD);
+       val &= ~(u16)(UHCI_USBCMD_RUN | UHCI_USBCMD_CONFIGURE);
+       outw(val, base + UHCI_USBCMD);
+
+       /*
+        * wait while it stops if it was running
+        */
+       if ((sts & UHCI_USBSTS_HALTED) == 0)
+       {
+               wait_time = 1000;
+               delta = 100;
+
+               do {
+                       outw(0x1f, base + UHCI_USBSTS);
+                       udelay(delta);
+                       wait_time -= delta;
+                       val = inw(base + UHCI_USBSTS);
+                       if (val & UHCI_USBSTS_HALTED)
+                               break;
+               } while (wait_time > 0);
+       }
+
+       /*
+        * disable interrupts & legacy support
+        */
+       outw(0, base + UHCI_USBINTR);
+       outw(0x1f, base + UHCI_USBSTS);
+       pci_read_config_word(pdev, UHCI_USBLEGSUP, &val);
+       if (val & 0xbf) 
+               pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT);
+               
+}
+
+static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
+{
+       void __iomem *base;
+       int wait_time;
+
+       base = ioremap_nocache(pci_resource_start(pdev, 0),
+                                    pci_resource_len(pdev, 0));
+       if (base == NULL) return;
+
+       if (readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
+               wait_time = 500; /* 0.5 seconds */
+               writel(OHCI_INTR_OC, base + OHCI_INTRENABLE);
+               writel(OHCI_OCR, base + OHCI_CMDSTATUS);
+               while (wait_time > 0 && 
+                               readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
+                       wait_time -= 10;
+                       msleep(10);
+               }
+       }
+
+       /*
+        * disable interrupts
+        */
+       writel(~(u32)0, base + OHCI_INTRDISABLE);
+       writel(~(u32)0, base + OHCI_INTRSTATUS);
+
+       iounmap(base);
+}
+
+static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
+{
+       int wait_time, delta;
+       void __iomem *base, *op_reg_base;
+       u32 hcc_params, val, temp;
+       u8 cap_length;
+
+       base = ioremap_nocache(pci_resource_start(pdev, 0),
+                               pci_resource_len(pdev, 0));
+       if (base == NULL) return;
+
+       cap_length = readb(base);
+       op_reg_base = base + cap_length;
+       hcc_params = readl(base + EHCI_HCC_PARAMS);
+       hcc_params = (hcc_params >> 8) & 0xff;
+       if (hcc_params) {
+               pci_read_config_dword(pdev, 
+                                       hcc_params + EHCI_USBLEGSUP,
+                                       &val);
+               if (((val & 0xff) == 1) && (val & EHCI_USBLEGSUP_BIOS)) {
+                       /*
+                        * Ok, BIOS is in smm mode, try to hand off...
+                        */
+                       pci_read_config_dword(pdev,
+                                               hcc_params + EHCI_USBLEGCTLSTS,
+                                               &temp);
+                       pci_write_config_dword(pdev,
+                                               hcc_params + EHCI_USBLEGCTLSTS,
+                                               temp | EHCI_USBLEGCTLSTS_SOOE);
+                       val |= EHCI_USBLEGSUP_OS;
+                       pci_write_config_dword(pdev, 
+                                               hcc_params + EHCI_USBLEGSUP, 
+                                               val);
+
+                       wait_time = 500;
+                       do {
+                               msleep(10);
+                               wait_time -= 10;
+                               pci_read_config_dword(pdev,
+                                               hcc_params + EHCI_USBLEGSUP,
+                                               &val);
+                       } while (wait_time && (val & EHCI_USBLEGSUP_BIOS));
+                       if (!wait_time) {
+                               /*
+                                * well, possibly buggy BIOS...
+                                */
+                               printk(KERN_WARNING "EHCI early BIOS handoff "
+                                               "failed (BIOS bug ?)\n");
+                               pci_write_config_dword(pdev,
+                                               hcc_params + EHCI_USBLEGSUP,
+                                               EHCI_USBLEGSUP_OS);
+                               pci_write_config_dword(pdev,
+                                               hcc_params + EHCI_USBLEGCTLSTS,
+                                               0);
+                       }
+               }
+       }
+
+       /*
+        * halt EHCI & disable its interrupts in any case
+        */
+       val = readl(op_reg_base + EHCI_USBSTS);
+       if ((val & EHCI_USBSTS_HALTED) == 0) {
+               val = readl(op_reg_base + EHCI_USBCMD);
+               val &= ~EHCI_USBCMD_RUN;
+               writel(val, op_reg_base + EHCI_USBCMD);
+
+               wait_time = 2000;
+               delta = 100;
+               do {
+                       writel(0x3f, op_reg_base + EHCI_USBSTS);
+                       udelay(delta);
+                       wait_time -= delta;
+                       val = readl(op_reg_base + EHCI_USBSTS);
+                       if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) {
+                               break;
+                       }
+               } while (wait_time > 0);
+       }
+       writel(0, op_reg_base + EHCI_USBINTR);
+       writel(0x3f, op_reg_base + EHCI_USBSTS);
+
+       iounmap(base);
+
+       return;
+}
+
+
+
+static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
+{
+       if (!usb_early_handoff)
+               return;
+
+       if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x00)) { /* UHCI */
+               quirk_usb_handoff_uhci(pdev);
+       } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) { /* OHCI */
+               quirk_usb_handoff_ohci(pdev);
+       } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x20)) { /* EHCI */
+               quirk_usb_disable_ehci(pdev);
+       }
+
+       return;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
+
 /*
  * ... This is further complicated by the fact that some SiS96x south
  * bridges pretend to be 85C503/5513 instead.  In that case see if we
@@ -905,7 +1153,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,      PCI_DEVICE_ID_INTEL_EESSC,      quirk_a
 #endif
 
 #ifdef CONFIG_SCSI_SATA
-static void __init quirk_intel_ide_combined(struct pci_dev *pdev)
+static void __devinit quirk_intel_ide_combined(struct pci_dev *pdev)
 {
        u8 prog, comb, tmp;
        int ich = 0;
@@ -926,6 +1174,10 @@ static void __init quirk_intel_ide_combined(struct pci_dev *pdev)
        case 0x2653:
                ich = 6;
                break;
+       case 0x27c0:
+       case 0x27c4:
+               ich = 7;
+               break;
        default:
                /* we do not handle this PCI device */
                return;
@@ -945,7 +1197,7 @@ static void __init quirk_intel_ide_combined(struct pci_dev *pdev)
                else
                        return;                 /* not in combined mode */
        } else {
-               WARN_ON(ich != 6);
+               WARN_ON((ich != 6) && (ich != 7));
                tmp &= 0x3;  /* interesting bits 1:0 */
                if (tmp & (1 << 0))
                        comb = (1 << 2);        /* PATA port 0, SATA port 1 */
@@ -978,37 +1230,49 @@ static void __init quirk_intel_ide_combined(struct pci_dev *pdev)
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,    PCI_ANY_ID,      quirk_intel_ide_combined );
 #endif /* CONFIG_SCSI_SATA */
 
-int pciehp_msi_quirk;
 
-static void __devinit quirk_pciehp_msi(struct pci_dev *pdev)
+int pcie_mch_quirk;
+
+static void __devinit quirk_pcie_mch(struct pci_dev *pdev)
 {
-       pciehp_msi_quirk = 1;
+       pcie_mch_quirk = 1;
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_SMCH,      quirk_pciehp_msi );
-
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7520_MCH,  quirk_pcie_mch );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7320_MCH,  quirk_pcie_mch );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7525_MCH,  quirk_pcie_mch );
 
 static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end)
 {
        while (f < end) {
                if ((f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) &&
                    (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) {
-                       pr_debug(KERN_INFO "PCI: Calling quirk %p for %s\n", f->hook, pci_name(dev));
+                       pr_debug("PCI: Calling quirk %p for %s\n", f->hook, pci_name(dev));
                        f->hook(dev);
                }
                f++;
        }
 }
 
+extern struct pci_fixup __start_pci_fixups_early[];
+extern struct pci_fixup __end_pci_fixups_early[];
 extern struct pci_fixup __start_pci_fixups_header[];
 extern struct pci_fixup __end_pci_fixups_header[];
 extern struct pci_fixup __start_pci_fixups_final[];
 extern struct pci_fixup __end_pci_fixups_final[];
+extern struct pci_fixup __start_pci_fixups_enable[];
+extern struct pci_fixup __end_pci_fixups_enable[];
+
 
 void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
 {
        struct pci_fixup *start, *end;
 
        switch(pass) {
+       case pci_fixup_early:
+               start = __start_pci_fixups_early;
+               end = __end_pci_fixups_early;
+               break;
+
        case pci_fixup_header:
                start = __start_pci_fixups_header;
                end = __end_pci_fixups_header;
@@ -1018,6 +1282,12 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
                start = __start_pci_fixups_final;
                end = __end_pci_fixups_final;
                break;
+
+       case pci_fixup_enable:
+               start = __start_pci_fixups_enable;
+               end = __end_pci_fixups_enable;
+               break;
+
        default:
                /* stupid compiler warning, you would think with an enum... */
                return;
@@ -1025,4 +1295,7 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
        pci_do_fixups(dev, start, end);
 }
 
-EXPORT_SYMBOL(pciehp_msi_quirk);
+EXPORT_SYMBOL(pcie_mch_quirk);
+#ifdef CONFIG_HOTPLUG
+EXPORT_SYMBOL(pci_fixup_device);
+#endif