vserver 2.0 rc7
[linux-2.6.git] / drivers / pci / quirks.c
index 7fffd4d..968033f 100644 (file)
@@ -18,8 +18,8 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-
-#undef DEBUG
+#include <linux/acpi.h>
+#include "pci.h"
 
 /* Deal with broken BIOS'es that neglect to enable passive release,
    which can cause problems in combination with the 82441FX/PPro MTRRs */
@@ -330,6 +330,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801CA_12,
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801DB_0,                quirk_ich4_lpc_acpi );
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801DB_12,       quirk_ich4_lpc_acpi );
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801EB_0,                quirk_ich4_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_ESB_1,            quirk_ich4_lpc_acpi );
 
 /*
  * VIA ACPI: One IO region pointed to by longword at
@@ -429,6 +430,8 @@ static void __init quirk_ioapic_rmw(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,      PCI_ANY_ID,                     quirk_ioapic_rmw );
 
+int pci_msi_quirk;
+
 #define AMD8131_revA0        0x01
 #define AMD8131_revB0        0x11
 #define AMD8131_MISC         0x40
@@ -437,6 +440,9 @@ static void __init quirk_amd_8131_ioapic(struct pci_dev *dev)
 { 
         unsigned char revid, tmp;
         
+       pci_msi_quirk = 1;
+       printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n");
+
         if (nr_ioapics == 0) 
                 return;
 
@@ -450,23 +456,15 @@ static void __init quirk_amd_8131_ioapic(struct pci_dev *dev)
 } 
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_APIC,         quirk_amd_8131_ioapic ); 
 
+static void __init quirk_svw_msi(struct pci_dev *dev)
+{
+       pci_msi_quirk = 1;
+       printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n");
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_svw_msi );
 #endif /* CONFIG_X86_IO_APIC */
 
 
-/*
- * Via 686A/B:  The PCI_INTERRUPT_LINE register for the on-chip
- * devices, USB0/1, AC97, MC97, and ACPI, has an unusual feature:
- * when written, it makes an internal connection to the PIC.
- * For these devices, this register is defined to be 4 bits wide.
- * Normally this is fine.  However for IO-APIC motherboards, or
- * non-x86 architectures (yes Via exists on PPC among other places),
- * we must mask the PCI_INTERRUPT_LINE value versus 0xf to get
- * interrupts delivered properly.
- *
- * TODO: When we have device-specific interrupt routers,
- * quirk_via_irqpic will go away from quirks.
- */
-
 /*
  * FIXME: it is questionable that quirk_via_acpi
  * is needed.  It shows up as an ISA bridge, and does not
@@ -489,6 +487,31 @@ 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 );
 
+/*
+ * Via 686A/B:  The PCI_INTERRUPT_LINE register for the on-chip
+ * devices, USB0/1, AC97, MC97, and ACPI, has an unusual feature:
+ * when written, it makes an internal connection to the PIC.
+ * For these devices, this register is defined to be 4 bits wide.
+ * Normally this is fine.  However for IO-APIC motherboards, or
+ * non-x86 architectures (yes Via exists on PPC among other places),
+ * we must mask the PCI_INTERRUPT_LINE value versus 0xf to get
+ * interrupts delivered properly.
+ */
+static void quirk_via_irq(struct pci_dev *dev)
+{
+       u8 irq, new_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);     /* unknown if delay really needed */
+               pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq);
+       }
+}
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq);
+
 /*
  * PIIX3 USB: We have to disable USB interrupts that are
  * hardwired to PIRQD# and may be shared with an
@@ -536,7 +559,7 @@ static void __devinit quirk_cardbus_legacy(struct pci_dev *dev)
                return;
        pci_write_config_dword(dev, PCI_CB_LEGACY_MODE_BASE, 0);
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID,            PCI_ANY_ID,                     quirk_cardbus_legacy );
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy);
 
 /*
  * Following the PCI ordering rules is optional on the AMD762. I'm not
@@ -654,7 +677,7 @@ static void __devinit quirk_ide_bases(struct pci_dev *dev)
        printk(KERN_INFO "PCI: Ignoring BAR%d-%d of IDE controller %s\n",
               first_bar, last_bar, pci_name(dev));
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID,             PCI_ANY_ID,                     quirk_ide_bases );
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_ide_bases);
 
 /*
  *     Ensure C0 rev restreaming is off. This is normally done by
@@ -678,24 +701,11 @@ static void __init quirk_disable_pxb(struct pci_dev *pdev)
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82454NX,    quirk_disable_pxb );
 
-/*
- *     VIA northbridges care about PCI_INTERRUPT_LINE
- */
-int via_interrupt_line_quirk;
-
-static void __devinit quirk_via_bridge(struct pci_dev *pdev)
-{
-       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 );
 
 /*
  *     Serverworks CSB5 IDE does not fully support native mode
  */
-static void __init quirk_svwks_csb5ide(struct pci_dev *pdev)
+static void __devinit quirk_svwks_csb5ide(struct pci_dev *pdev)
 {
        u8 prog;
        pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
@@ -782,10 +792,12 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
                if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
                        switch (dev->subsystem_device) {
                        case 0x1751: /* M2N notebook */
+                       case 0x1821: /* M5N notebook */
                                asus_hides_smbus = 1;
                        }
                if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
                        switch (dev->subsystem_device) {
+                       case 0x184b: /* W1N notebook */
                        case 0x186a: /* M6Ne notebook */
                                asus_hides_smbus = 1;
                        }
@@ -801,6 +813,18 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
                        case 0x12bc: /* HP D330L */
                                asus_hides_smbus = 1;
                        }
+       } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_TOSHIBA)) {
+               if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
+                       switch(dev->subsystem_device) {
+                       case 0x0001: /* Toshiba Satellite A40 */
+                               asus_hides_smbus = 1;
+                       }
+       } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG)) {
+               if (dev->device ==  PCI_DEVICE_ID_INTEL_82855PM_HB)
+                       switch(dev->subsystem_device) {
+                       case 0xC00C: /* Samsung P35 notebook */
+                               asus_hides_smbus = 1;
+                       }
        }
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82845_HB,   asus_hides_smbus_hostbridge );
@@ -1172,6 +1196,7 @@ static void __devinit quirk_intel_ide_combined(struct pci_dev *pdev)
        case 0x2651:
        case 0x2652:
        case 0x2653:
+       case 0x2680:    /* ESB2 */
                ich = 6;
                break;
        case 0x27c0:
@@ -1241,6 +1266,40 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,     PCI_DEVICE_ID_INTEL_E7520_MCH,  quir
 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 __devinit quirk_netmos(struct pci_dev *dev)
+{
+       unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4;
+       unsigned int num_serial = dev->subsystem_device & 0xf;
+
+       /*
+        * These Netmos parts are multiport serial devices with optional
+        * parallel ports.  Even when parallel ports are present, they
+        * are identified as class SERIAL, which means the serial driver
+        * will claim them.  To prevent this, mark them as class OTHER.
+        * These combo devices should be claimed by parport_serial.
+        *
+        * The subdevice ID is of the form 0x00PS, where <P> is the number
+        * of parallel ports and <S> is the number of serial ports.
+        */
+       switch (dev->device) {
+       case PCI_DEVICE_ID_NETMOS_9735:
+       case PCI_DEVICE_ID_NETMOS_9745:
+       case PCI_DEVICE_ID_NETMOS_9835:
+       case PCI_DEVICE_ID_NETMOS_9845:
+       case PCI_DEVICE_ID_NETMOS_9855:
+               if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_SERIAL &&
+                   num_parallel) {
+                       printk(KERN_INFO "PCI: Netmos %04x (%u parallel, "
+                               "%u serial); changing class SERIAL to OTHER "
+                               "(use parport_serial)\n",
+                               dev->device, num_parallel, num_serial);
+                       dev->class = (PCI_CLASS_COMMUNICATION_OTHER << 8) |
+                           (dev->class & 0xff);
+               }
+       }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, quirk_netmos);
+
 static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end)
 {
        while (f < end) {