Merge branch 'for-linus' of git://neil.brown.name/md
[safe/jmp/linux-2.6] / drivers / pci / quirks.c
index 7ddcfc6..3067673 100644 (file)
@@ -36,17 +36,18 @@ EXPORT_SYMBOL(pcie_mch_quirk);
 
 #ifdef CONFIG_PCI_QUIRKS
 /*
- * This quirk function disables the device and releases resources
- * which is specified by kernel's boot parameter 'pci=resource_alignment='.
+ * This quirk function disables memory decoding and releases memory resources
+ * of the device specified by kernel's boot parameter 'pci=resource_alignment='.
  * It also rounds up size to specified alignment.
  * Later on, the kernel will assign page-aligned memory resource back
- * to that device.
+ * to the device.
  */
 static void __devinit quirk_resource_alignment(struct pci_dev *dev)
 {
        int i;
        struct resource *r;
        resource_size_t align, size;
+       u16 command;
 
        if (!pci_is_reassigndev(dev))
                return;
@@ -58,8 +59,11 @@ static void __devinit quirk_resource_alignment(struct pci_dev *dev)
                return;
        }
 
-       dev_info(&dev->dev, "Disabling device and release resources.\n");
-       pci_disable_device(dev);
+       dev_info(&dev->dev,
+               "Disabling memory decoding and releasing memory resources.\n");
+       pci_read_config_word(dev, PCI_COMMAND, &command);
+       command &= ~PCI_COMMAND_MEMORY;
+       pci_write_config_word(dev, PCI_COMMAND, command);
 
        align = pci_specified_resource_alignment(dev);
        for (i=0; i < PCI_BRIDGE_RESOURCES; i++) {
@@ -2029,6 +2033,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS400_200, quirk_di
 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);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3364, quirk_disable_all_msi);
 
 /* Disable MSI on chipsets that are known to not support it */
 static void __devinit quirk_disable_msi(struct pci_dev *dev)
@@ -2147,6 +2152,92 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA,
                        PCI_DEVICE_ID_NVIDIA_NVENET_15,
                        nvenet_msi_disable);
 
+static int __devinit ht_check_msi_mapping(struct pci_dev *dev)
+{
+       int pos, ttl = 48;
+       int found = 0;
+
+       /* check if there is HT MSI cap or enabled on this device */
+       pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
+       while (pos && ttl--) {
+               u8 flags;
+
+               if (found < 1)
+                       found = 1;
+               if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
+                                        &flags) == 0) {
+                       if (flags & HT_MSI_FLAGS_ENABLE) {
+                               if (found < 2) {
+                                       found = 2;
+                                       break;
+                               }
+                       }
+               }
+               pos = pci_find_next_ht_capability(dev, pos,
+                                                 HT_CAPTYPE_MSI_MAPPING);
+       }
+
+       return found;
+}
+
+static int __devinit host_bridge_with_leaf(struct pci_dev *host_bridge)
+{
+       struct pci_dev *dev;
+       int pos;
+       int i, dev_no;
+       int found = 0;
+
+       dev_no = host_bridge->devfn >> 3;
+       for (i = dev_no + 1; i < 0x20; i++) {
+               dev = pci_get_slot(host_bridge->bus, PCI_DEVFN(i, 0));
+               if (!dev)
+                       continue;
+
+               /* found next host bridge ?*/
+               pos = pci_find_ht_capability(dev, HT_CAPTYPE_SLAVE);
+               if (pos != 0) {
+                       pci_dev_put(dev);
+                       break;
+               }
+
+               if (ht_check_msi_mapping(dev)) {
+                       found = 1;
+                       pci_dev_put(dev);
+                       break;
+               }
+               pci_dev_put(dev);
+       }
+
+       return found;
+}
+
+#define PCI_HT_CAP_SLAVE_CTRL0     4    /* link control */
+#define PCI_HT_CAP_SLAVE_CTRL1     8    /* link control to */
+
+static int __devinit is_end_of_ht_chain(struct pci_dev *dev)
+{
+       int pos, ctrl_off;
+       int end = 0;
+       u16 flags, ctrl;
+
+       pos = pci_find_ht_capability(dev, HT_CAPTYPE_SLAVE);
+
+       if (!pos)
+               goto out;
+
+       pci_read_config_word(dev, pos + PCI_CAP_FLAGS, &flags);
+
+       ctrl_off = ((flags >> 10) & 1) ?
+                       PCI_HT_CAP_SLAVE_CTRL0 : PCI_HT_CAP_SLAVE_CTRL1;
+       pci_read_config_word(dev, pos + ctrl_off, &ctrl);
+
+       if (ctrl & (1 << 6))
+               end = 1;
+
+out:
+       return end;
+}
+
 static void __devinit nv_ht_enable_msi_mapping(struct pci_dev *dev)
 {
        struct pci_dev *host_bridge;
@@ -2171,6 +2262,11 @@ static void __devinit nv_ht_enable_msi_mapping(struct pci_dev *dev)
        if (!found)
                return;
 
+       /* don't enable end_device/host_bridge with leaf directly here */
+       if (host_bridge == dev && is_end_of_ht_chain(host_bridge) &&
+           host_bridge_with_leaf(host_bridge))
+               goto out;
+
        /* root did that ! */
        if (msi_ht_cap_enabled(host_bridge))
                goto out;
@@ -2201,44 +2297,12 @@ static void __devinit ht_disable_msi_mapping(struct pci_dev *dev)
        }
 }
 
-static int __devinit ht_check_msi_mapping(struct pci_dev *dev)
-{
-       int pos, ttl = 48;
-       int found = 0;
-
-       /* check if there is HT MSI cap or enabled on this device */
-       pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
-       while (pos && ttl--) {
-               u8 flags;
-
-               if (found < 1)
-                       found = 1;
-               if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
-                                        &flags) == 0) {
-                       if (flags & HT_MSI_FLAGS_ENABLE) {
-                               if (found < 2) {
-                                       found = 2;
-                                       break;
-                               }
-                       }
-               }
-               pos = pci_find_next_ht_capability(dev, pos,
-                                                 HT_CAPTYPE_MSI_MAPPING);
-       }
-
-       return found;
-}
-
-static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)
+static void __devinit __nv_msi_ht_cap_quirk(struct pci_dev *dev, int all)
 {
        struct pci_dev *host_bridge;
        int pos;
        int found;
 
-       /* Enabling HT MSI mapping on this device breaks MCP51 */
-       if (dev->device == 0x270)
-               return;
-
        /* check if there is HT MSI cap or enabled on this device */
        found = ht_check_msi_mapping(dev);
 
@@ -2262,7 +2326,10 @@ static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)
                /* Host bridge is to HT */
                if (found == 1) {
                        /* it is not enabled, try to enable it */
-                       nv_ht_enable_msi_mapping(dev);
+                       if (all)
+                               ht_enable_msi_mapping(dev);
+                       else
+                               nv_ht_enable_msi_mapping(dev);
                }
                return;
        }
@@ -2274,8 +2341,20 @@ static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)
        /* Host bridge is not to HT, disable HT MSI mapping on this device */
        ht_disable_msi_mapping(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 nv_msi_ht_cap_quirk_all(struct pci_dev *dev)
+{
+       return __nv_msi_ht_cap_quirk(dev, 1);
+}
+
+static void __devinit nv_msi_ht_cap_quirk_leaf(struct pci_dev *dev)
+{
+       return __nv_msi_ht_cap_quirk(dev, 0);
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk_leaf);
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk_all);
 
 static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev)
 {
@@ -2337,6 +2416,54 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4375,
 
 #endif /* CONFIG_PCI_MSI */
 
+#ifdef CONFIG_PCI_IOV
+
+/*
+ * For Intel 82576 SR-IOV NIC, if BIOS doesn't allocate resources for the
+ * SR-IOV BARs, zero the Flash BAR and program the SR-IOV BARs to use the
+ * old Flash Memory Space.
+ */
+static void __devinit quirk_i82576_sriov(struct pci_dev *dev)
+{
+       int pos, flags;
+       u32 bar, start, size;
+
+       if (PAGE_SIZE > 0x10000)
+               return;
+
+       flags = pci_resource_flags(dev, 0);
+       if ((flags & PCI_BASE_ADDRESS_SPACE) !=
+                       PCI_BASE_ADDRESS_SPACE_MEMORY ||
+           (flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) !=
+                       PCI_BASE_ADDRESS_MEM_TYPE_32)
+               return;
+
+       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
+       if (!pos)
+               return;
+
+       pci_read_config_dword(dev, pos + PCI_SRIOV_BAR, &bar);
+       if (bar & PCI_BASE_ADDRESS_MEM_MASK)
+               return;
+
+       start = pci_resource_start(dev, 1);
+       size = pci_resource_len(dev, 1);
+       if (!start || size != 0x400000 || start & (size - 1))
+               return;
+
+       pci_resource_flags(dev, 1) = 0;
+       pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0);
+       pci_write_config_dword(dev, pos + PCI_SRIOV_BAR, start);
+       pci_write_config_dword(dev, pos + PCI_SRIOV_BAR + 12, start + size / 2);
+
+       dev_info(&dev->dev, "use Flash Memory Space for SR-IOV BARs\n");
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10c9, quirk_i82576_sriov);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e6, quirk_i82576_sriov);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e7, quirk_i82576_sriov);
+
+#endif /* CONFIG_PCI_IOV */
+
 static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
                          struct pci_fixup *end)
 {