diff options
| -rw-r--r-- | arch/x86/kernel/amd_nb.c | 44 |
1 files changed, 38 insertions, 6 deletions
diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c index 19d489ee2b1e..cc34266e3c62 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c | |||
| @@ -213,7 +213,10 @@ int amd_cache_northbridges(void) | |||
| 213 | const struct pci_device_id *root_ids = amd_root_ids; | 213 | const struct pci_device_id *root_ids = amd_root_ids; |
| 214 | struct pci_dev *root, *misc, *link; | 214 | struct pci_dev *root, *misc, *link; |
| 215 | struct amd_northbridge *nb; | 215 | struct amd_northbridge *nb; |
| 216 | u16 i = 0; | 216 | u16 roots_per_misc = 0; |
| 217 | u16 misc_count = 0; | ||
| 218 | u16 root_count = 0; | ||
| 219 | u16 i, j; | ||
| 217 | 220 | ||
| 218 | if (amd_northbridges.num) | 221 | if (amd_northbridges.num) |
| 219 | return 0; | 222 | return 0; |
| @@ -226,26 +229,55 @@ int amd_cache_northbridges(void) | |||
| 226 | 229 | ||
| 227 | misc = NULL; | 230 | misc = NULL; |
| 228 | while ((misc = next_northbridge(misc, misc_ids)) != NULL) | 231 | while ((misc = next_northbridge(misc, misc_ids)) != NULL) |
| 229 | i++; | 232 | misc_count++; |
| 230 | 233 | ||
| 231 | if (!i) | 234 | if (!misc_count) |
| 232 | return -ENODEV; | 235 | return -ENODEV; |
| 233 | 236 | ||
| 234 | nb = kcalloc(i, sizeof(struct amd_northbridge), GFP_KERNEL); | 237 | root = NULL; |
| 238 | while ((root = next_northbridge(root, root_ids)) != NULL) | ||
| 239 | root_count++; | ||
| 240 | |||
| 241 | if (root_count) { | ||
| 242 | roots_per_misc = root_count / misc_count; | ||
| 243 | |||
| 244 | /* | ||
| 245 | * There should be _exactly_ N roots for each DF/SMN | ||
| 246 | * interface. | ||
| 247 | */ | ||
| 248 | if (!roots_per_misc || (root_count % roots_per_misc)) { | ||
| 249 | pr_info("Unsupported AMD DF/PCI configuration found\n"); | ||
| 250 | return -ENODEV; | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | nb = kcalloc(misc_count, sizeof(struct amd_northbridge), GFP_KERNEL); | ||
| 235 | if (!nb) | 255 | if (!nb) |
| 236 | return -ENOMEM; | 256 | return -ENOMEM; |
| 237 | 257 | ||
| 238 | amd_northbridges.nb = nb; | 258 | amd_northbridges.nb = nb; |
| 239 | amd_northbridges.num = i; | 259 | amd_northbridges.num = misc_count; |
| 240 | 260 | ||
| 241 | link = misc = root = NULL; | 261 | link = misc = root = NULL; |
| 242 | for (i = 0; i != amd_northbridges.num; i++) { | 262 | for (i = 0; i < amd_northbridges.num; i++) { |
| 243 | node_to_amd_nb(i)->root = root = | 263 | node_to_amd_nb(i)->root = root = |
| 244 | next_northbridge(root, root_ids); | 264 | next_northbridge(root, root_ids); |
| 245 | node_to_amd_nb(i)->misc = misc = | 265 | node_to_amd_nb(i)->misc = misc = |
| 246 | next_northbridge(misc, misc_ids); | 266 | next_northbridge(misc, misc_ids); |
| 247 | node_to_amd_nb(i)->link = link = | 267 | node_to_amd_nb(i)->link = link = |
| 248 | next_northbridge(link, link_ids); | 268 | next_northbridge(link, link_ids); |
| 269 | |||
| 270 | /* | ||
| 271 | * If there are more PCI root devices than data fabric/ | ||
| 272 | * system management network interfaces, then the (N) | ||
| 273 | * PCI roots per DF/SMN interface are functionally the | ||
| 274 | * same (for DF/SMN access) and N-1 are redundant. N-1 | ||
| 275 | * PCI roots should be skipped per DF/SMN interface so | ||
| 276 | * the following DF/SMN interfaces get mapped to | ||
| 277 | * correct PCI roots. | ||
| 278 | */ | ||
| 279 | for (j = 1; j < roots_per_misc; j++) | ||
| 280 | root = next_northbridge(root, root_ids); | ||
| 249 | } | 281 | } |
| 250 | 282 | ||
| 251 | if (amd_gart_present()) | 283 | if (amd_gart_present()) |
