PCI quirks: add quirk to disable boot interrupt generation on broadcom HT1000
[deliverable/linux.git] / drivers / pci / quirks.c
index e887aa45c9cdd4ad41863f199f9f26f4551659a4..d1f0281279c3e939b7070ff6243477edb3a4fb3b 100644 (file)
@@ -1363,6 +1363,94 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,     0x2609, quirk_intel_pcie_pm);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   0x260a, quirk_intel_pcie_pm);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   0x260b, quirk_intel_pcie_pm);
 
+#ifdef CONFIG_X86_IO_APIC
+/*
+ * Boot interrupts on some chipsets cannot be turned off. For these chipsets,
+ * remap the original interrupt in the linux kernel to the boot interrupt, so
+ * that a PCI device's interrupt handler is installed on the boot interrupt
+ * line instead.
+ */
+static void quirk_reroute_to_boot_interrupts_intel(struct pci_dev *dev)
+{
+       if (noioapicquirk)
+               return;
+
+       dev->irq_reroute_variant = INTEL_IRQ_REROUTE_VARIANT;
+
+       printk(KERN_INFO "PCI quirk: reroute interrupts for 0x%04x:0x%04x\n",
+                       dev->vendor, dev->device);
+       return;
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_80333_0,    quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_80333_1,    quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_ESB2_0,     quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_PXH_0,      quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_PXH_1,      quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_PXHV,       quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_80332_0,    quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_80332_1,    quirk_reroute_to_boot_interrupts_intel);
+
+/*
+ * On some chipsets we can disable the generation of legacy INTx boot
+ * interrupts.
+ */
+
+/*
+ * IO-APIC1 on 6300ESB generates boot interrupts, see intel order no
+ * 300641-004US, section 5.7.3.
+ */
+#define INTEL_6300_IOAPIC_ABAR         0x40
+#define INTEL_6300_DISABLE_BOOT_IRQ    (1<<14)
+
+static void quirk_disable_intel_boot_interrupt(struct pci_dev *dev)
+{
+       u16 pci_config_word;
+
+       if (noioapicquirk)
+               return;
+
+       pci_read_config_word(dev, INTEL_6300_IOAPIC_ABAR, &pci_config_word);
+       pci_config_word |= INTEL_6300_DISABLE_BOOT_IRQ;
+       pci_write_config_word(dev, INTEL_6300_IOAPIC_ABAR, pci_config_word);
+
+       printk(KERN_INFO "disabled boot interrupt on device 0x%04x:0x%04x\n",
+               dev->vendor, dev->device);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_ESB_10,     quirk_disable_intel_boot_interrupt);
+
+/*
+ * disable boot interrupts on HT-1000
+ */
+#define BC_HT1000_FEATURE_REG          0x64
+#define BC_HT1000_PIC_REGS_ENABLE      (1<<0)
+#define BC_HT1000_MAP_IDX              0xC00
+#define BC_HT1000_MAP_DATA             0xC01
+
+static void quirk_disable_broadcom_boot_interrupt(struct pci_dev *dev)
+{
+       u32 pci_config_dword;
+       u8 irq;
+
+       if (noioapicquirk)
+               return;
+
+       pci_read_config_dword(dev, BC_HT1000_FEATURE_REG, &pci_config_dword);
+       pci_write_config_dword(dev, BC_HT1000_FEATURE_REG, pci_config_dword |
+                       BC_HT1000_PIC_REGS_ENABLE);
+
+       for (irq = 0x10; irq < 0x10 + 32; irq++) {
+               outb(irq, BC_HT1000_MAP_IDX);
+               outb(0x00, BC_HT1000_MAP_DATA);
+       }
+
+       pci_write_config_dword(dev, BC_HT1000_FEATURE_REG, pci_config_dword);
+
+       printk(KERN_INFO "disabled boot interrupts on PCI device"
+                       "0x%04x:0x%04x\n", dev->vendor, dev->device);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS,   PCI_DEVICE_ID_SERVERWORKS_HT1000SB,       quirk_disable_broadcom_boot_interrupt);
+#endif /* CONFIG_X86_IO_APIC */
+
 /*
  * Toshiba TC86C001 IDE controller reports the standard 8-byte BAR0 size
  * but the PIO transfers won't work if BAR0 falls at the odd 8 bytes.
@@ -1502,9 +1590,8 @@ static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_f
                if ((f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) &&
                    (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) {
 #ifdef DEBUG
-                       dev_dbg(&dev->dev, "calling quirk 0x%p", f->hook);
-                       print_fn_descriptor_symbol(": %s()\n",
-                               (unsigned long) f->hook);
+                       dev_dbg(&dev->dev, "calling ");
+                       print_fn_descriptor_symbol("%s\n", f->hook);
 #endif
                        f->hook(dev);
                }
@@ -1648,18 +1735,71 @@ static void __devinit quirk_via_cx700_pci_parking_caching(struct pci_dev *dev)
                        /* Turn off PCI Bus Parking */
                        pci_write_config_byte(dev, 0x76, b ^ 0x40);
 
+                       dev_info(&dev->dev,
+                               "Disabling VIA CX700 PCI parking\n");
+               }
+       }
+
+       if (pci_read_config_byte(dev, 0x72, &b) == 0) {
+               if (b != 0) {
                        /* Turn off PCI Master read caching */
                        pci_write_config_byte(dev, 0x72, 0x0);
+
+                       /* Set PCI Master Bus time-out to "1x16 PCLK" */
                        pci_write_config_byte(dev, 0x75, 0x1);
+
+                       /* Disable "Read FIFO Timer" */
                        pci_write_config_byte(dev, 0x77, 0x0);
 
                        dev_info(&dev->dev,
-                               "Disabling VIA CX700 PCI parking/caching\n");
+                               "Disabling VIA CX700 PCI caching\n");
                }
        }
 }
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_caching);
 
+/*
+ * For Broadcom 5706, 5708, 5709 rev. A nics, any read beyond the
+ * VPD end tag will hang the device.  This problem was initially
+ * observed when a vpd entry was created in sysfs
+ * ('/sys/bus/pci/devices/<id>/vpd').   A read to this sysfs entry
+ * will dump 32k of data.  Reading a full 32k will cause an access
+ * beyond the VPD end tag causing the device to hang.  Once the device
+ * is hung, the bnx2 driver will not be able to reset the device.
+ * We believe that it is legal to read beyond the end tag and
+ * therefore the solution is to limit the read/write length.
+ */
+static void __devinit quirk_brcm_570x_limit_vpd(struct pci_dev *dev)
+{
+       /*  Only disable the VPD capability for 5706, 5708, and 5709 rev. A */
+       if ((dev->device == PCI_DEVICE_ID_NX2_5706) ||
+           (dev->device == PCI_DEVICE_ID_NX2_5708) ||
+           ((dev->device == PCI_DEVICE_ID_NX2_5709) &&
+            (dev->revision & 0xf0) == 0x0)) {
+               if (dev->vpd)
+                       dev->vpd->len = 0x80;
+       }
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+                        PCI_DEVICE_ID_NX2_5706,
+                        quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+                        PCI_DEVICE_ID_NX2_5706S,
+                        quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+                        PCI_DEVICE_ID_NX2_5708,
+                        quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+                        PCI_DEVICE_ID_NX2_5708S,
+                        quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+                        PCI_DEVICE_ID_NX2_5709,
+                        quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+                        PCI_DEVICE_ID_NX2_5709S,
+                        quirk_brcm_570x_limit_vpd);
+
 #ifdef CONFIG_PCI_MSI
 /* Some chipsets do not support MSI. We cannot easily rely on setting
  * PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually
@@ -1675,6 +1815,7 @@ static void __init quirk_disable_all_msi(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_disable_all_msi);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS400_200, quirk_disable_all_msi);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS480, quirk_disable_all_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3336, quirk_disable_all_msi);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disable_all_msi);
 
 /* Disable MSI on chipsets that are known to not support it */
@@ -1815,6 +1956,7 @@ static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)
        }
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk);
 
 static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev)
 {
This page took 0.026859 seconds and 5 git commands to generate.