diff options
Diffstat (limited to 'arch/x86/kernel/cpu/amd.c')
| -rw-r--r-- | arch/x86/kernel/cpu/amd.c | 61 |
1 files changed, 39 insertions, 22 deletions
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 7c7bedb83c5..f771ab6b49e 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c | |||
| @@ -233,18 +233,22 @@ static void __cpuinit init_amd_k7(struct cpuinfo_x86 *c) | |||
| 233 | } | 233 | } |
| 234 | #endif | 234 | #endif |
| 235 | 235 | ||
| 236 | #if defined(CONFIG_NUMA) && defined(CONFIG_X86_64) | 236 | #ifdef CONFIG_NUMA |
| 237 | /* | ||
| 238 | * To workaround broken NUMA config. Read the comment in | ||
| 239 | * srat_detect_node(). | ||
| 240 | */ | ||
| 237 | static int __cpuinit nearby_node(int apicid) | 241 | static int __cpuinit nearby_node(int apicid) |
| 238 | { | 242 | { |
| 239 | int i, node; | 243 | int i, node; |
| 240 | 244 | ||
| 241 | for (i = apicid - 1; i >= 0; i--) { | 245 | for (i = apicid - 1; i >= 0; i--) { |
| 242 | node = apicid_to_node[i]; | 246 | node = __apicid_to_node[i]; |
| 243 | if (node != NUMA_NO_NODE && node_online(node)) | 247 | if (node != NUMA_NO_NODE && node_online(node)) |
| 244 | return node; | 248 | return node; |
| 245 | } | 249 | } |
| 246 | for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) { | 250 | for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) { |
| 247 | node = apicid_to_node[i]; | 251 | node = __apicid_to_node[i]; |
| 248 | if (node != NUMA_NO_NODE && node_online(node)) | 252 | if (node != NUMA_NO_NODE && node_online(node)) |
| 249 | return node; | 253 | return node; |
| 250 | } | 254 | } |
| @@ -261,7 +265,7 @@ static int __cpuinit nearby_node(int apicid) | |||
| 261 | #ifdef CONFIG_X86_HT | 265 | #ifdef CONFIG_X86_HT |
| 262 | static void __cpuinit amd_get_topology(struct cpuinfo_x86 *c) | 266 | static void __cpuinit amd_get_topology(struct cpuinfo_x86 *c) |
| 263 | { | 267 | { |
| 264 | u32 nodes; | 268 | u32 nodes, cores_per_cu = 1; |
| 265 | u8 node_id; | 269 | u8 node_id; |
| 266 | int cpu = smp_processor_id(); | 270 | int cpu = smp_processor_id(); |
| 267 | 271 | ||
| @@ -276,6 +280,7 @@ static void __cpuinit amd_get_topology(struct cpuinfo_x86 *c) | |||
| 276 | /* get compute unit information */ | 280 | /* get compute unit information */ |
| 277 | smp_num_siblings = ((ebx >> 8) & 3) + 1; | 281 | smp_num_siblings = ((ebx >> 8) & 3) + 1; |
| 278 | c->compute_unit_id = ebx & 0xff; | 282 | c->compute_unit_id = ebx & 0xff; |
| 283 | cores_per_cu += ((ebx >> 8) & 3); | ||
| 279 | } else if (cpu_has(c, X86_FEATURE_NODEID_MSR)) { | 284 | } else if (cpu_has(c, X86_FEATURE_NODEID_MSR)) { |
| 280 | u64 value; | 285 | u64 value; |
| 281 | 286 | ||
| @@ -288,15 +293,18 @@ static void __cpuinit amd_get_topology(struct cpuinfo_x86 *c) | |||
| 288 | /* fixup multi-node processor information */ | 293 | /* fixup multi-node processor information */ |
| 289 | if (nodes > 1) { | 294 | if (nodes > 1) { |
| 290 | u32 cores_per_node; | 295 | u32 cores_per_node; |
| 296 | u32 cus_per_node; | ||
| 291 | 297 | ||
| 292 | set_cpu_cap(c, X86_FEATURE_AMD_DCM); | 298 | set_cpu_cap(c, X86_FEATURE_AMD_DCM); |
| 293 | cores_per_node = c->x86_max_cores / nodes; | 299 | cores_per_node = c->x86_max_cores / nodes; |
| 300 | cus_per_node = cores_per_node / cores_per_cu; | ||
| 294 | 301 | ||
| 295 | /* store NodeID, use llc_shared_map to store sibling info */ | 302 | /* store NodeID, use llc_shared_map to store sibling info */ |
| 296 | per_cpu(cpu_llc_id, cpu) = node_id; | 303 | per_cpu(cpu_llc_id, cpu) = node_id; |
| 297 | 304 | ||
| 298 | /* core id to be in range from 0 to (cores_per_node - 1) */ | 305 | /* core id has to be in the [0 .. cores_per_node - 1] range */ |
| 299 | c->cpu_core_id = c->cpu_core_id % cores_per_node; | 306 | c->cpu_core_id %= cores_per_node; |
| 307 | c->compute_unit_id %= cus_per_node; | ||
| 300 | } | 308 | } |
| 301 | } | 309 | } |
| 302 | #endif | 310 | #endif |
| @@ -334,31 +342,40 @@ EXPORT_SYMBOL_GPL(amd_get_nb_id); | |||
| 334 | 342 | ||
| 335 | static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c) | 343 | static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c) |
| 336 | { | 344 | { |
| 337 | #if defined(CONFIG_NUMA) && defined(CONFIG_X86_64) | 345 | #ifdef CONFIG_NUMA |
| 338 | int cpu = smp_processor_id(); | 346 | int cpu = smp_processor_id(); |
| 339 | int node; | 347 | int node; |
| 340 | unsigned apicid = c->apicid; | 348 | unsigned apicid = c->apicid; |
| 341 | 349 | ||
| 342 | node = per_cpu(cpu_llc_id, cpu); | 350 | node = numa_cpu_node(cpu); |
| 351 | if (node == NUMA_NO_NODE) | ||
| 352 | node = per_cpu(cpu_llc_id, cpu); | ||
| 343 | 353 | ||
| 344 | if (apicid_to_node[apicid] != NUMA_NO_NODE) | ||
| 345 | node = apicid_to_node[apicid]; | ||
| 346 | if (!node_online(node)) { | 354 | if (!node_online(node)) { |
| 347 | /* Two possibilities here: | 355 | /* |
| 348 | - The CPU is missing memory and no node was created. | 356 | * Two possibilities here: |
| 349 | In that case try picking one from a nearby CPU | 357 | * |
| 350 | - The APIC IDs differ from the HyperTransport node IDs | 358 | * - The CPU is missing memory and no node was created. In |
| 351 | which the K8 northbridge parsing fills in. | 359 | * that case try picking one from a nearby CPU. |
| 352 | Assume they are all increased by a constant offset, | 360 | * |
| 353 | but in the same order as the HT nodeids. | 361 | * - The APIC IDs differ from the HyperTransport node IDs |
| 354 | If that doesn't result in a usable node fall back to the | 362 | * which the K8 northbridge parsing fills in. Assume |
| 355 | path for the previous case. */ | 363 | * they are all increased by a constant offset, but in |
| 356 | 364 | * the same order as the HT nodeids. If that doesn't | |
| 365 | * result in a usable node fall back to the path for the | ||
| 366 | * previous case. | ||
| 367 | * | ||
| 368 | * This workaround operates directly on the mapping between | ||
| 369 | * APIC ID and NUMA node, assuming certain relationship | ||
| 370 | * between APIC ID, HT node ID and NUMA topology. As going | ||
| 371 | * through CPU mapping may alter the outcome, directly | ||
| 372 | * access __apicid_to_node[]. | ||
| 373 | */ | ||
| 357 | int ht_nodeid = c->initial_apicid; | 374 | int ht_nodeid = c->initial_apicid; |
| 358 | 375 | ||
| 359 | if (ht_nodeid >= 0 && | 376 | if (ht_nodeid >= 0 && |
| 360 | apicid_to_node[ht_nodeid] != NUMA_NO_NODE) | 377 | __apicid_to_node[ht_nodeid] != NUMA_NO_NODE) |
| 361 | node = apicid_to_node[ht_nodeid]; | 378 | node = __apicid_to_node[ht_nodeid]; |
| 362 | /* Pick a nearby node */ | 379 | /* Pick a nearby node */ |
| 363 | if (!node_online(node)) | 380 | if (!node_online(node)) |
| 364 | node = nearby_node(apicid); | 381 | node = nearby_node(apicid); |
