aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/amd_nb.c44
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())