+/* Under some circumstances, AER is not linked with extended capabilities.
+ * Force it to be linked by setting the corresponding control bit in the
+ * config space.
+ */
+static void quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev)
+{
+ uint8_t b;
+ if (pci_read_config_byte(dev, 0xf41, &b) == 0) {
+ if (!(b & 0x20)) {
+ pci_write_config_byte(dev, 0xf41, b | 0x20);
+ printk(KERN_INFO
+ "PCI: Linking AER extended capability on %s\n",
+ pci_name(dev));
+ }
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
+ quirk_nvidia_ck804_pcie_aer_ext_cap);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
+ quirk_nvidia_ck804_pcie_aer_ext_cap);
+
+#ifdef CONFIG_PCI_MSI
+/* To disable MSI globally */
+int pci_msi_quirk;
+
+/* The Serverworks PCI-X chipset does not support MSI. We cannot easily rely
+ * on setting PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually
+ * some other busses controlled by the chipset even if Linux is not aware of it.
+ * Instead of setting the flag on all busses in the machine, simply disable MSI
+ * globally.
+ */
+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);
+
+/* Disable MSI on chipsets that are known to not support it */
+static void __devinit quirk_disable_msi(struct pci_dev *dev)
+{
+ if (dev->subordinate) {
+ printk(KERN_WARNING "PCI: MSI quirk detected. "
+ "PCI_BUS_FLAGS_NO_MSI set for %s subordinate bus.\n",
+ pci_name(dev));
+ dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_msi);
+
+/* Go through the list of Hypertransport capabilities and
+ * return 1 if a HT MSI capability is found and enabled */
+static int __devinit msi_ht_cap_enabled(struct pci_dev *dev)
+{
+ int pos, ttl = 48;
+
+ pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
+ while (pos && ttl--) {
+ u8 flags;
+
+ if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
+ &flags) == 0)
+ {
+ printk(KERN_INFO "PCI: Found %s HT MSI Mapping on %s\n",
+ flags & HT_MSI_FLAGS_ENABLE ?
+ "enabled" : "disabled", pci_name(dev));
+ return (flags & HT_MSI_FLAGS_ENABLE) != 0;
+ }
+
+ pos = pci_find_next_ht_capability(dev, pos,
+ HT_CAPTYPE_MSI_MAPPING);
+ }
+ return 0;
+}
+
+/* Check the hypertransport MSI mapping to know whether MSI is enabled or not */
+static void __devinit quirk_msi_ht_cap(struct pci_dev *dev)
+{
+ if (dev->subordinate && !msi_ht_cap_enabled(dev)) {
+ printk(KERN_WARNING "PCI: MSI quirk detected. "
+ "MSI disabled on chipset %s.\n",
+ pci_name(dev));
+ dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE,
+ quirk_msi_ht_cap);
+
+/* The nVidia CK804 chipset may have 2 HT MSI mappings.
+ * MSI are supported if the MSI capability set in any of these mappings.
+ */
+static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev)
+{
+ struct pci_dev *pdev;
+
+ if (!dev->subordinate)
+ return;
+
+ /* check HT MSI cap on this chipset and the root one.
+ * a single one having MSI is enough to be sure that MSI are supported.
+ */
+ pdev = pci_get_slot(dev->bus, 0);
+ if (!pdev)
+ return;
+ if (!msi_ht_cap_enabled(dev) && !msi_ht_cap_enabled(pdev)) {
+ printk(KERN_WARNING "PCI: MSI quirk detected. "
+ "MSI disabled on chipset %s.\n",
+ pci_name(dev));
+ dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
+ }
+ pci_dev_put(pdev);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
+ quirk_nvidia_ck804_msi_ht_cap);
+#endif /* CONFIG_PCI_MSI */
+