diff options
Diffstat (limited to 'drivers/pci/quirks.c')
-rw-r--r-- | drivers/pci/quirks.c | 221 |
1 files changed, 182 insertions, 39 deletions
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 92b9efe9bcaf..9b2f0d96900d 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/kallsyms.h> | 24 | #include <linux/kallsyms.h> |
25 | #include <linux/dmi.h> | 25 | #include <linux/dmi.h> |
26 | #include <linux/pci-aspm.h> | 26 | #include <linux/pci-aspm.h> |
27 | #include <linux/ioport.h> | ||
27 | #include "pci.h" | 28 | #include "pci.h" |
28 | 29 | ||
29 | int isa_dma_bridge_buggy; | 30 | int isa_dma_bridge_buggy; |
@@ -34,6 +35,65 @@ int pcie_mch_quirk; | |||
34 | EXPORT_SYMBOL(pcie_mch_quirk); | 35 | EXPORT_SYMBOL(pcie_mch_quirk); |
35 | 36 | ||
36 | #ifdef CONFIG_PCI_QUIRKS | 37 | #ifdef CONFIG_PCI_QUIRKS |
38 | /* | ||
39 | * This quirk function disables the device and releases resources | ||
40 | * which is specified by kernel's boot parameter 'pci=resource_alignment='. | ||
41 | * It also rounds up size to specified alignment. | ||
42 | * Later on, the kernel will assign page-aligned memory resource back | ||
43 | * to that device. | ||
44 | */ | ||
45 | static void __devinit quirk_resource_alignment(struct pci_dev *dev) | ||
46 | { | ||
47 | int i; | ||
48 | struct resource *r; | ||
49 | resource_size_t align, size; | ||
50 | |||
51 | if (!pci_is_reassigndev(dev)) | ||
52 | return; | ||
53 | |||
54 | if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL && | ||
55 | (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) { | ||
56 | dev_warn(&dev->dev, | ||
57 | "Can't reassign resources to host bridge.\n"); | ||
58 | return; | ||
59 | } | ||
60 | |||
61 | dev_info(&dev->dev, "Disabling device and release resources.\n"); | ||
62 | pci_disable_device(dev); | ||
63 | |||
64 | align = pci_specified_resource_alignment(dev); | ||
65 | for (i=0; i < PCI_BRIDGE_RESOURCES; i++) { | ||
66 | r = &dev->resource[i]; | ||
67 | if (!(r->flags & IORESOURCE_MEM)) | ||
68 | continue; | ||
69 | size = resource_size(r); | ||
70 | if (size < align) { | ||
71 | size = align; | ||
72 | dev_info(&dev->dev, | ||
73 | "Rounding up size of resource #%d to %#llx.\n", | ||
74 | i, (unsigned long long)size); | ||
75 | } | ||
76 | r->end = size - 1; | ||
77 | r->start = 0; | ||
78 | } | ||
79 | /* Need to disable bridge's resource window, | ||
80 | * to enable the kernel to reassign new resource | ||
81 | * window later on. | ||
82 | */ | ||
83 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && | ||
84 | (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { | ||
85 | for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) { | ||
86 | r = &dev->resource[i]; | ||
87 | if (!(r->flags & IORESOURCE_MEM)) | ||
88 | continue; | ||
89 | r->end = resource_size(r) - 1; | ||
90 | r->start = 0; | ||
91 | } | ||
92 | pci_disable_bridge_window(dev); | ||
93 | } | ||
94 | } | ||
95 | DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_resource_alignment); | ||
96 | |||
37 | /* The Mellanox Tavor device gives false positive parity errors | 97 | /* The Mellanox Tavor device gives false positive parity errors |
38 | * Mark this device with a broken_parity_status, to allow | 98 | * Mark this device with a broken_parity_status, to allow |
39 | * PCI scanning code to "skip" this now blacklisted device. | 99 | * PCI scanning code to "skip" this now blacklisted device. |
@@ -1126,10 +1186,15 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) | |||
1126 | * its on-board VGA controller */ | 1186 | * its on-board VGA controller */ |
1127 | asus_hides_smbus = 1; | 1187 | asus_hides_smbus = 1; |
1128 | } | 1188 | } |
1129 | else if (dev->device == PCI_DEVICE_ID_INTEL_82845G_IG) | 1189 | else if (dev->device == PCI_DEVICE_ID_INTEL_82801DB_2) |
1130 | switch(dev->subsystem_device) { | 1190 | switch(dev->subsystem_device) { |
1131 | case 0x00b8: /* Compaq Evo D510 CMT */ | 1191 | case 0x00b8: /* Compaq Evo D510 CMT */ |
1132 | case 0x00b9: /* Compaq Evo D510 SFF */ | 1192 | case 0x00b9: /* Compaq Evo D510 SFF */ |
1193 | /* Motherboard doesn't have Host bridge | ||
1194 | * subvendor/subdevice IDs and on-board VGA | ||
1195 | * controller is disabled if an AGP card is | ||
1196 | * inserted, therefore checking USB UHCI | ||
1197 | * Controller #1 */ | ||
1133 | asus_hides_smbus = 1; | 1198 | asus_hides_smbus = 1; |
1134 | } | 1199 | } |
1135 | else if (dev->device == PCI_DEVICE_ID_INTEL_82815_CGC) | 1200 | else if (dev->device == PCI_DEVICE_ID_INTEL_82815_CGC) |
@@ -1154,7 +1219,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, as | |||
1154 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge); | 1219 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge); |
1155 | 1220 | ||
1156 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3, asus_hides_smbus_hostbridge); | 1221 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3, asus_hides_smbus_hostbridge); |
1157 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_IG, asus_hides_smbus_hostbridge); | 1222 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_2, asus_hides_smbus_hostbridge); |
1158 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_CGC, asus_hides_smbus_hostbridge); | 1223 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_CGC, asus_hides_smbus_hostbridge); |
1159 | 1224 | ||
1160 | static void asus_hides_smbus_lpc(struct pci_dev *dev) | 1225 | static void asus_hides_smbus_lpc(struct pci_dev *dev) |
@@ -1664,9 +1729,13 @@ static void __devinit quirk_netmos(struct pci_dev *dev) | |||
1664 | * of parallel ports and <S> is the number of serial ports. | 1729 | * of parallel ports and <S> is the number of serial ports. |
1665 | */ | 1730 | */ |
1666 | switch (dev->device) { | 1731 | switch (dev->device) { |
1732 | case PCI_DEVICE_ID_NETMOS_9835: | ||
1733 | /* Well, this rule doesn't hold for the following 9835 device */ | ||
1734 | if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM && | ||
1735 | dev->subsystem_device == 0x0299) | ||
1736 | return; | ||
1667 | case PCI_DEVICE_ID_NETMOS_9735: | 1737 | case PCI_DEVICE_ID_NETMOS_9735: |
1668 | case PCI_DEVICE_ID_NETMOS_9745: | 1738 | case PCI_DEVICE_ID_NETMOS_9745: |
1669 | case PCI_DEVICE_ID_NETMOS_9835: | ||
1670 | case PCI_DEVICE_ID_NETMOS_9845: | 1739 | case PCI_DEVICE_ID_NETMOS_9845: |
1671 | case PCI_DEVICE_ID_NETMOS_9855: | 1740 | case PCI_DEVICE_ID_NETMOS_9855: |
1672 | if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_SERIAL && | 1741 | if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_SERIAL && |
@@ -2078,6 +2147,92 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, | |||
2078 | PCI_DEVICE_ID_NVIDIA_NVENET_15, | 2147 | PCI_DEVICE_ID_NVIDIA_NVENET_15, |
2079 | nvenet_msi_disable); | 2148 | nvenet_msi_disable); |
2080 | 2149 | ||
2150 | static int __devinit ht_check_msi_mapping(struct pci_dev *dev) | ||
2151 | { | ||
2152 | int pos, ttl = 48; | ||
2153 | int found = 0; | ||
2154 | |||
2155 | /* check if there is HT MSI cap or enabled on this device */ | ||
2156 | pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING); | ||
2157 | while (pos && ttl--) { | ||
2158 | u8 flags; | ||
2159 | |||
2160 | if (found < 1) | ||
2161 | found = 1; | ||
2162 | if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, | ||
2163 | &flags) == 0) { | ||
2164 | if (flags & HT_MSI_FLAGS_ENABLE) { | ||
2165 | if (found < 2) { | ||
2166 | found = 2; | ||
2167 | break; | ||
2168 | } | ||
2169 | } | ||
2170 | } | ||
2171 | pos = pci_find_next_ht_capability(dev, pos, | ||
2172 | HT_CAPTYPE_MSI_MAPPING); | ||
2173 | } | ||
2174 | |||
2175 | return found; | ||
2176 | } | ||
2177 | |||
2178 | static int __devinit host_bridge_with_leaf(struct pci_dev *host_bridge) | ||
2179 | { | ||
2180 | struct pci_dev *dev; | ||
2181 | int pos; | ||
2182 | int i, dev_no; | ||
2183 | int found = 0; | ||
2184 | |||
2185 | dev_no = host_bridge->devfn >> 3; | ||
2186 | for (i = dev_no + 1; i < 0x20; i++) { | ||
2187 | dev = pci_get_slot(host_bridge->bus, PCI_DEVFN(i, 0)); | ||
2188 | if (!dev) | ||
2189 | continue; | ||
2190 | |||
2191 | /* found next host bridge ?*/ | ||
2192 | pos = pci_find_ht_capability(dev, HT_CAPTYPE_SLAVE); | ||
2193 | if (pos != 0) { | ||
2194 | pci_dev_put(dev); | ||
2195 | break; | ||
2196 | } | ||
2197 | |||
2198 | if (ht_check_msi_mapping(dev)) { | ||
2199 | found = 1; | ||
2200 | pci_dev_put(dev); | ||
2201 | break; | ||
2202 | } | ||
2203 | pci_dev_put(dev); | ||
2204 | } | ||
2205 | |||
2206 | return found; | ||
2207 | } | ||
2208 | |||
2209 | #define PCI_HT_CAP_SLAVE_CTRL0 4 /* link control */ | ||
2210 | #define PCI_HT_CAP_SLAVE_CTRL1 8 /* link control to */ | ||
2211 | |||
2212 | static int __devinit is_end_of_ht_chain(struct pci_dev *dev) | ||
2213 | { | ||
2214 | int pos, ctrl_off; | ||
2215 | int end = 0; | ||
2216 | u16 flags, ctrl; | ||
2217 | |||
2218 | pos = pci_find_ht_capability(dev, HT_CAPTYPE_SLAVE); | ||
2219 | |||
2220 | if (!pos) | ||
2221 | goto out; | ||
2222 | |||
2223 | pci_read_config_word(dev, pos + PCI_CAP_FLAGS, &flags); | ||
2224 | |||
2225 | ctrl_off = ((flags >> 10) & 1) ? | ||
2226 | PCI_HT_CAP_SLAVE_CTRL0 : PCI_HT_CAP_SLAVE_CTRL1; | ||
2227 | pci_read_config_word(dev, pos + ctrl_off, &ctrl); | ||
2228 | |||
2229 | if (ctrl & (1 << 6)) | ||
2230 | end = 1; | ||
2231 | |||
2232 | out: | ||
2233 | return end; | ||
2234 | } | ||
2235 | |||
2081 | static void __devinit nv_ht_enable_msi_mapping(struct pci_dev *dev) | 2236 | static void __devinit nv_ht_enable_msi_mapping(struct pci_dev *dev) |
2082 | { | 2237 | { |
2083 | struct pci_dev *host_bridge; | 2238 | struct pci_dev *host_bridge; |
@@ -2102,6 +2257,11 @@ static void __devinit nv_ht_enable_msi_mapping(struct pci_dev *dev) | |||
2102 | if (!found) | 2257 | if (!found) |
2103 | return; | 2258 | return; |
2104 | 2259 | ||
2260 | /* don't enable end_device/host_bridge with leaf directly here */ | ||
2261 | if (host_bridge == dev && is_end_of_ht_chain(host_bridge) && | ||
2262 | host_bridge_with_leaf(host_bridge)) | ||
2263 | goto out; | ||
2264 | |||
2105 | /* root did that ! */ | 2265 | /* root did that ! */ |
2106 | if (msi_ht_cap_enabled(host_bridge)) | 2266 | if (msi_ht_cap_enabled(host_bridge)) |
2107 | goto out; | 2267 | goto out; |
@@ -2132,44 +2292,12 @@ static void __devinit ht_disable_msi_mapping(struct pci_dev *dev) | |||
2132 | } | 2292 | } |
2133 | } | 2293 | } |
2134 | 2294 | ||
2135 | static int __devinit ht_check_msi_mapping(struct pci_dev *dev) | 2295 | static void __devinit __nv_msi_ht_cap_quirk(struct pci_dev *dev, int all) |
2136 | { | ||
2137 | int pos, ttl = 48; | ||
2138 | int found = 0; | ||
2139 | |||
2140 | /* check if there is HT MSI cap or enabled on this device */ | ||
2141 | pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING); | ||
2142 | while (pos && ttl--) { | ||
2143 | u8 flags; | ||
2144 | |||
2145 | if (found < 1) | ||
2146 | found = 1; | ||
2147 | if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, | ||
2148 | &flags) == 0) { | ||
2149 | if (flags & HT_MSI_FLAGS_ENABLE) { | ||
2150 | if (found < 2) { | ||
2151 | found = 2; | ||
2152 | break; | ||
2153 | } | ||
2154 | } | ||
2155 | } | ||
2156 | pos = pci_find_next_ht_capability(dev, pos, | ||
2157 | HT_CAPTYPE_MSI_MAPPING); | ||
2158 | } | ||
2159 | |||
2160 | return found; | ||
2161 | } | ||
2162 | |||
2163 | static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev) | ||
2164 | { | 2296 | { |
2165 | struct pci_dev *host_bridge; | 2297 | struct pci_dev *host_bridge; |
2166 | int pos; | 2298 | int pos; |
2167 | int found; | 2299 | int found; |
2168 | 2300 | ||
2169 | /* Enabling HT MSI mapping on this device breaks MCP51 */ | ||
2170 | if (dev->device == 0x270) | ||
2171 | return; | ||
2172 | |||
2173 | /* check if there is HT MSI cap or enabled on this device */ | 2301 | /* check if there is HT MSI cap or enabled on this device */ |
2174 | found = ht_check_msi_mapping(dev); | 2302 | found = ht_check_msi_mapping(dev); |
2175 | 2303 | ||
@@ -2193,7 +2321,10 @@ static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev) | |||
2193 | /* Host bridge is to HT */ | 2321 | /* Host bridge is to HT */ |
2194 | if (found == 1) { | 2322 | if (found == 1) { |
2195 | /* it is not enabled, try to enable it */ | 2323 | /* it is not enabled, try to enable it */ |
2196 | nv_ht_enable_msi_mapping(dev); | 2324 | if (all) |
2325 | ht_enable_msi_mapping(dev); | ||
2326 | else | ||
2327 | nv_ht_enable_msi_mapping(dev); | ||
2197 | } | 2328 | } |
2198 | return; | 2329 | return; |
2199 | } | 2330 | } |
@@ -2205,8 +2336,20 @@ static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev) | |||
2205 | /* Host bridge is not to HT, disable HT MSI mapping on this device */ | 2336 | /* Host bridge is not to HT, disable HT MSI mapping on this device */ |
2206 | ht_disable_msi_mapping(dev); | 2337 | ht_disable_msi_mapping(dev); |
2207 | } | 2338 | } |
2208 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk); | 2339 | |
2209 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk); | 2340 | static void __devinit nv_msi_ht_cap_quirk_all(struct pci_dev *dev) |
2341 | { | ||
2342 | return __nv_msi_ht_cap_quirk(dev, 1); | ||
2343 | } | ||
2344 | |||
2345 | static void __devinit nv_msi_ht_cap_quirk_leaf(struct pci_dev *dev) | ||
2346 | { | ||
2347 | return __nv_msi_ht_cap_quirk(dev, 0); | ||
2348 | } | ||
2349 | |||
2350 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk_leaf); | ||
2351 | |||
2352 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk_all); | ||
2210 | 2353 | ||
2211 | static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev) | 2354 | static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev) |
2212 | { | 2355 | { |