diff options
author | Yinghai Lu <yinghai@kernel.org> | 2009-03-20 22:29:41 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2009-03-26 19:09:14 -0400 |
commit | de7453065d5d5243686467998f1fcc58d20e0a7c (patch) | |
tree | a010aa2eb04f824a6fac08be2e60b99ac4bcb303 /drivers/pci/quirks.c | |
parent | e42d1fe804408c57506a5326252b4db29958a7fb (diff) |
PCI: don't enable too much HT MSI mapping
Impact: fix bug
Prakash reported that his c51-mcp51 system ondie sound card doesn't work
MSI but if he hack out the HT-MSI on mcp51, the MSI will work well with
sound card.
This patch reworks nv_msi_ht_cap_quirk() and will only avoid enabling
ht_msi on devices following that root device.
Reported-by: Prakash Punnoor <prakash@punnoor.de>
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/quirks.c')
-rw-r--r-- | drivers/pci/quirks.c | 118 |
1 files changed, 82 insertions, 36 deletions
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 7ddcfc65e790..faf02dd00015 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
@@ -2147,6 +2147,65 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, | |||
2147 | PCI_DEVICE_ID_NVIDIA_NVENET_15, | 2147 | PCI_DEVICE_ID_NVIDIA_NVENET_15, |
2148 | nvenet_msi_disable); | 2148 | nvenet_msi_disable); |
2149 | 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 | |||
2150 | static void __devinit nv_ht_enable_msi_mapping(struct pci_dev *dev) | 2209 | static void __devinit nv_ht_enable_msi_mapping(struct pci_dev *dev) |
2151 | { | 2210 | { |
2152 | struct pci_dev *host_bridge; | 2211 | struct pci_dev *host_bridge; |
@@ -2171,6 +2230,10 @@ static void __devinit nv_ht_enable_msi_mapping(struct pci_dev *dev) | |||
2171 | if (!found) | 2230 | if (!found) |
2172 | return; | 2231 | return; |
2173 | 2232 | ||
2233 | /* don't enable host_bridge with leaf directly here */ | ||
2234 | if (host_bridge == dev && host_bridge_with_leaf(host_bridge)) | ||
2235 | goto out; | ||
2236 | |||
2174 | /* root did that ! */ | 2237 | /* root did that ! */ |
2175 | if (msi_ht_cap_enabled(host_bridge)) | 2238 | if (msi_ht_cap_enabled(host_bridge)) |
2176 | goto out; | 2239 | goto out; |
@@ -2201,44 +2264,12 @@ static void __devinit ht_disable_msi_mapping(struct pci_dev *dev) | |||
2201 | } | 2264 | } |
2202 | } | 2265 | } |
2203 | 2266 | ||
2204 | static int __devinit ht_check_msi_mapping(struct pci_dev *dev) | 2267 | static void __devinit __nv_msi_ht_cap_quirk(struct pci_dev *dev, int all) |
2205 | { | ||
2206 | int pos, ttl = 48; | ||
2207 | int found = 0; | ||
2208 | |||
2209 | /* check if there is HT MSI cap or enabled on this device */ | ||
2210 | pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING); | ||
2211 | while (pos && ttl--) { | ||
2212 | u8 flags; | ||
2213 | |||
2214 | if (found < 1) | ||
2215 | found = 1; | ||
2216 | if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, | ||
2217 | &flags) == 0) { | ||
2218 | if (flags & HT_MSI_FLAGS_ENABLE) { | ||
2219 | if (found < 2) { | ||
2220 | found = 2; | ||
2221 | break; | ||
2222 | } | ||
2223 | } | ||
2224 | } | ||
2225 | pos = pci_find_next_ht_capability(dev, pos, | ||
2226 | HT_CAPTYPE_MSI_MAPPING); | ||
2227 | } | ||
2228 | |||
2229 | return found; | ||
2230 | } | ||
2231 | |||
2232 | static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev) | ||
2233 | { | 2268 | { |
2234 | struct pci_dev *host_bridge; | 2269 | struct pci_dev *host_bridge; |
2235 | int pos; | 2270 | int pos; |
2236 | int found; | 2271 | int found; |
2237 | 2272 | ||
2238 | /* Enabling HT MSI mapping on this device breaks MCP51 */ | ||
2239 | if (dev->device == 0x270) | ||
2240 | return; | ||
2241 | |||
2242 | /* check if there is HT MSI cap or enabled on this device */ | 2273 | /* check if there is HT MSI cap or enabled on this device */ |
2243 | found = ht_check_msi_mapping(dev); | 2274 | found = ht_check_msi_mapping(dev); |
2244 | 2275 | ||
@@ -2262,7 +2293,10 @@ static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev) | |||
2262 | /* Host bridge is to HT */ | 2293 | /* Host bridge is to HT */ |
2263 | if (found == 1) { | 2294 | if (found == 1) { |
2264 | /* it is not enabled, try to enable it */ | 2295 | /* it is not enabled, try to enable it */ |
2265 | nv_ht_enable_msi_mapping(dev); | 2296 | if (all) |
2297 | ht_enable_msi_mapping(dev); | ||
2298 | else | ||
2299 | nv_ht_enable_msi_mapping(dev); | ||
2266 | } | 2300 | } |
2267 | return; | 2301 | return; |
2268 | } | 2302 | } |
@@ -2274,8 +2308,20 @@ static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev) | |||
2274 | /* Host bridge is not to HT, disable HT MSI mapping on this device */ | 2308 | /* Host bridge is not to HT, disable HT MSI mapping on this device */ |
2275 | ht_disable_msi_mapping(dev); | 2309 | ht_disable_msi_mapping(dev); |
2276 | } | 2310 | } |
2277 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk); | 2311 | |
2278 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk); | 2312 | static void __devinit nv_msi_ht_cap_quirk_all(struct pci_dev *dev) |
2313 | { | ||
2314 | return __nv_msi_ht_cap_quirk(dev, 1); | ||
2315 | } | ||
2316 | |||
2317 | static void __devinit nv_msi_ht_cap_quirk_leaf(struct pci_dev *dev) | ||
2318 | { | ||
2319 | return __nv_msi_ht_cap_quirk(dev, 0); | ||
2320 | } | ||
2321 | |||
2322 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk_leaf); | ||
2323 | |||
2324 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk_all); | ||
2279 | 2325 | ||
2280 | static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev) | 2326 | static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev) |
2281 | { | 2327 | { |