diff options
author | Mike Travis <travis@sgi.com> | 2009-12-28 16:28:25 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-12-29 00:47:39 -0500 |
commit | 39d30770992895d55789de64bad2349510af68d0 (patch) | |
tree | 06d4304faa228353e10607237f00eb02339df6b9 /arch/x86 | |
parent | c0ca9da442df82b67095f230f24762042f9f3b7d (diff) |
x86: SGI UV: Fix writes to led registers on remote uv hubs
The wrong address was being used to write the SCIR led regs on
remote hubs. Also, there was an inconsistency between how BIOS
and the kernel indexed these regs. Standardize on using the
lower 6 bits of the APIC ID as the index.
This patch fixes the problem of writing to an errant address to
a cpu # >= 64.
Signed-off-by: Mike Travis <travis@sgi.com>
Reviewed-by: Jack Steiner <steiner@sgi.com>
Cc: Robin Holt <holt@sgi.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: stable@kernel.org
LKML-Reference: <4B3922F9.3060905@sgi.com>
[ v2: fix a number of annoying checkpatch artifacts and whitespace noise ]
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/include/asm/uv/uv_hub.h | 86 | ||||
-rw-r--r-- | arch/x86/kernel/apic/x2apic_uv_x.c | 12 |
2 files changed, 54 insertions, 44 deletions
diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h index 811bfabc80b7..bc54fa965af3 100644 --- a/arch/x86/include/asm/uv/uv_hub.h +++ b/arch/x86/include/asm/uv/uv_hub.h | |||
@@ -31,20 +31,20 @@ | |||
31 | * contiguous (although various IO spaces may punch holes in | 31 | * contiguous (although various IO spaces may punch holes in |
32 | * it).. | 32 | * it).. |
33 | * | 33 | * |
34 | * N - Number of bits in the node portion of a socket physical | 34 | * N - Number of bits in the node portion of a socket physical |
35 | * address. | 35 | * address. |
36 | * | 36 | * |
37 | * NASID - network ID of a router, Mbrick or Cbrick. Nasid values of | 37 | * NASID - network ID of a router, Mbrick or Cbrick. Nasid values of |
38 | * routers always have low bit of 1, C/MBricks have low bit | 38 | * routers always have low bit of 1, C/MBricks have low bit |
39 | * equal to 0. Most addressing macros that target UV hub chips | 39 | * equal to 0. Most addressing macros that target UV hub chips |
40 | * right shift the NASID by 1 to exclude the always-zero bit. | 40 | * right shift the NASID by 1 to exclude the always-zero bit. |
41 | * NASIDs contain up to 15 bits. | 41 | * NASIDs contain up to 15 bits. |
42 | * | 42 | * |
43 | * GNODE - NASID right shifted by 1 bit. Most mmrs contain gnodes instead | 43 | * GNODE - NASID right shifted by 1 bit. Most mmrs contain gnodes instead |
44 | * of nasids. | 44 | * of nasids. |
45 | * | 45 | * |
46 | * PNODE - the low N bits of the GNODE. The PNODE is the most useful variant | 46 | * PNODE - the low N bits of the GNODE. The PNODE is the most useful variant |
47 | * of the nasid for socket usage. | 47 | * of the nasid for socket usage. |
48 | * | 48 | * |
49 | * | 49 | * |
50 | * NumaLink Global Physical Address Format: | 50 | * NumaLink Global Physical Address Format: |
@@ -71,12 +71,12 @@ | |||
71 | * | 71 | * |
72 | * | 72 | * |
73 | * APICID format | 73 | * APICID format |
74 | * NOTE!!!!!! This is the current format of the APICID. However, code | 74 | * NOTE!!!!!! This is the current format of the APICID. However, code |
75 | * should assume that this will change in the future. Use functions | 75 | * should assume that this will change in the future. Use functions |
76 | * in this file for all APICID bit manipulations and conversion. | 76 | * in this file for all APICID bit manipulations and conversion. |
77 | * | 77 | * |
78 | * 1111110000000000 | 78 | * 1111110000000000 |
79 | * 5432109876543210 | 79 | * 5432109876543210 |
80 | * pppppppppplc0cch | 80 | * pppppppppplc0cch |
81 | * sssssssssss | 81 | * sssssssssss |
82 | * | 82 | * |
@@ -89,9 +89,9 @@ | |||
89 | * Note: Processor only supports 12 bits in the APICID register. The ACPI | 89 | * Note: Processor only supports 12 bits in the APICID register. The ACPI |
90 | * tables hold all 16 bits. Software needs to be aware of this. | 90 | * tables hold all 16 bits. Software needs to be aware of this. |
91 | * | 91 | * |
92 | * Unless otherwise specified, all references to APICID refer to | 92 | * Unless otherwise specified, all references to APICID refer to |
93 | * the FULL value contained in ACPI tables, not the subset in the | 93 | * the FULL value contained in ACPI tables, not the subset in the |
94 | * processor APICID register. | 94 | * processor APICID register. |
95 | */ | 95 | */ |
96 | 96 | ||
97 | 97 | ||
@@ -151,16 +151,16 @@ struct uv_hub_info_s { | |||
151 | }; | 151 | }; |
152 | 152 | ||
153 | DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); | 153 | DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); |
154 | #define uv_hub_info (&__get_cpu_var(__uv_hub_info)) | 154 | #define uv_hub_info (&__get_cpu_var(__uv_hub_info)) |
155 | #define uv_cpu_hub_info(cpu) (&per_cpu(__uv_hub_info, cpu)) | 155 | #define uv_cpu_hub_info(cpu) (&per_cpu(__uv_hub_info, cpu)) |
156 | 156 | ||
157 | /* | 157 | /* |
158 | * Local & Global MMR space macros. | 158 | * Local & Global MMR space macros. |
159 | * Note: macros are intended to be used ONLY by inline functions | 159 | * Note: macros are intended to be used ONLY by inline functions |
160 | * in this file - not by other kernel code. | 160 | * in this file - not by other kernel code. |
161 | * n - NASID (full 15-bit global nasid) | 161 | * n - NASID (full 15-bit global nasid) |
162 | * g - GNODE (full 15-bit global nasid, right shifted 1) | 162 | * g - GNODE (full 15-bit global nasid, right shifted 1) |
163 | * p - PNODE (local part of nsids, right shifted 1) | 163 | * p - PNODE (local part of nsids, right shifted 1) |
164 | */ | 164 | */ |
165 | #define UV_NASID_TO_PNODE(n) (((n) >> 1) & uv_hub_info->pnode_mask) | 165 | #define UV_NASID_TO_PNODE(n) (((n) >> 1) & uv_hub_info->pnode_mask) |
166 | #define UV_PNODE_TO_GNODE(p) ((p) |uv_hub_info->gnode_extra) | 166 | #define UV_PNODE_TO_GNODE(p) ((p) |uv_hub_info->gnode_extra) |
@@ -215,8 +215,8 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); | |||
215 | /* | 215 | /* |
216 | * Macros for converting between kernel virtual addresses, socket local physical | 216 | * Macros for converting between kernel virtual addresses, socket local physical |
217 | * addresses, and UV global physical addresses. | 217 | * addresses, and UV global physical addresses. |
218 | * Note: use the standard __pa() & __va() macros for converting | 218 | * Note: use the standard __pa() & __va() macros for converting |
219 | * between socket virtual and socket physical addresses. | 219 | * between socket virtual and socket physical addresses. |
220 | */ | 220 | */ |
221 | 221 | ||
222 | /* socket phys RAM --> UV global physical address */ | 222 | /* socket phys RAM --> UV global physical address */ |
@@ -287,21 +287,18 @@ static inline int uv_apicid_to_pnode(int apicid) | |||
287 | * Access global MMRs using the low memory MMR32 space. This region supports | 287 | * Access global MMRs using the low memory MMR32 space. This region supports |
288 | * faster MMR access but not all MMRs are accessible in this space. | 288 | * faster MMR access but not all MMRs are accessible in this space. |
289 | */ | 289 | */ |
290 | static inline unsigned long *uv_global_mmr32_address(int pnode, | 290 | static inline unsigned long *uv_global_mmr32_address(int pnode, unsigned long offset) |
291 | unsigned long offset) | ||
292 | { | 291 | { |
293 | return __va(UV_GLOBAL_MMR32_BASE | | 292 | return __va(UV_GLOBAL_MMR32_BASE | |
294 | UV_GLOBAL_MMR32_PNODE_BITS(pnode) | offset); | 293 | UV_GLOBAL_MMR32_PNODE_BITS(pnode) | offset); |
295 | } | 294 | } |
296 | 295 | ||
297 | static inline void uv_write_global_mmr32(int pnode, unsigned long offset, | 296 | static inline void uv_write_global_mmr32(int pnode, unsigned long offset, unsigned long val) |
298 | unsigned long val) | ||
299 | { | 297 | { |
300 | writeq(val, uv_global_mmr32_address(pnode, offset)); | 298 | writeq(val, uv_global_mmr32_address(pnode, offset)); |
301 | } | 299 | } |
302 | 300 | ||
303 | static inline unsigned long uv_read_global_mmr32(int pnode, | 301 | static inline unsigned long uv_read_global_mmr32(int pnode, unsigned long offset) |
304 | unsigned long offset) | ||
305 | { | 302 | { |
306 | return readq(uv_global_mmr32_address(pnode, offset)); | 303 | return readq(uv_global_mmr32_address(pnode, offset)); |
307 | } | 304 | } |
@@ -310,21 +307,18 @@ static inline unsigned long uv_read_global_mmr32(int pnode, | |||
310 | * Access Global MMR space using the MMR space located at the top of physical | 307 | * Access Global MMR space using the MMR space located at the top of physical |
311 | * memory. | 308 | * memory. |
312 | */ | 309 | */ |
313 | static inline unsigned long *uv_global_mmr64_address(int pnode, | 310 | static inline unsigned long *uv_global_mmr64_address(int pnode, unsigned long offset) |
314 | unsigned long offset) | ||
315 | { | 311 | { |
316 | return __va(UV_GLOBAL_MMR64_BASE | | 312 | return __va(UV_GLOBAL_MMR64_BASE | |
317 | UV_GLOBAL_MMR64_PNODE_BITS(pnode) | offset); | 313 | UV_GLOBAL_MMR64_PNODE_BITS(pnode) | offset); |
318 | } | 314 | } |
319 | 315 | ||
320 | static inline void uv_write_global_mmr64(int pnode, unsigned long offset, | 316 | static inline void uv_write_global_mmr64(int pnode, unsigned long offset, unsigned long val) |
321 | unsigned long val) | ||
322 | { | 317 | { |
323 | writeq(val, uv_global_mmr64_address(pnode, offset)); | 318 | writeq(val, uv_global_mmr64_address(pnode, offset)); |
324 | } | 319 | } |
325 | 320 | ||
326 | static inline unsigned long uv_read_global_mmr64(int pnode, | 321 | static inline unsigned long uv_read_global_mmr64(int pnode, unsigned long offset) |
327 | unsigned long offset) | ||
328 | { | 322 | { |
329 | return readq(uv_global_mmr64_address(pnode, offset)); | 323 | return readq(uv_global_mmr64_address(pnode, offset)); |
330 | } | 324 | } |
@@ -338,6 +332,16 @@ static inline unsigned long uv_global_gru_mmr_address(int pnode, unsigned long o | |||
338 | return UV_GLOBAL_GRU_MMR_BASE | offset | (pnode << uv_hub_info->m_val); | 332 | return UV_GLOBAL_GRU_MMR_BASE | offset | (pnode << uv_hub_info->m_val); |
339 | } | 333 | } |
340 | 334 | ||
335 | static inline void uv_write_global_mmr8(int pnode, unsigned long offset, unsigned char val) | ||
336 | { | ||
337 | writeb(val, uv_global_mmr64_address(pnode, offset)); | ||
338 | } | ||
339 | |||
340 | static inline unsigned char uv_read_global_mmr8(int pnode, unsigned long offset) | ||
341 | { | ||
342 | return readb(uv_global_mmr64_address(pnode, offset)); | ||
343 | } | ||
344 | |||
341 | /* | 345 | /* |
342 | * Access hub local MMRs. Faster than using global space but only local MMRs | 346 | * Access hub local MMRs. Faster than using global space but only local MMRs |
343 | * are accessible. | 347 | * are accessible. |
@@ -457,11 +461,17 @@ static inline void uv_set_scir_bits(unsigned char value) | |||
457 | } | 461 | } |
458 | } | 462 | } |
459 | 463 | ||
464 | static inline unsigned long uv_scir_offset(int apicid) | ||
465 | { | ||
466 | return SCIR_LOCAL_MMR_BASE | (apicid & 0x3f); | ||
467 | } | ||
468 | |||
460 | static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value) | 469 | static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value) |
461 | { | 470 | { |
462 | if (uv_cpu_hub_info(cpu)->scir.state != value) { | 471 | if (uv_cpu_hub_info(cpu)->scir.state != value) { |
472 | uv_write_global_mmr8(uv_cpu_to_pnode(cpu), | ||
473 | uv_cpu_hub_info(cpu)->scir.offset, value); | ||
463 | uv_cpu_hub_info(cpu)->scir.state = value; | 474 | uv_cpu_hub_info(cpu)->scir.state = value; |
464 | uv_write_local_mmr8(uv_cpu_hub_info(cpu)->scir.offset, value); | ||
465 | } | 475 | } |
466 | } | 476 | } |
467 | 477 | ||
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index d56b0efb2057..5f92494dab61 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c | |||
@@ -629,8 +629,10 @@ void __init uv_system_init(void) | |||
629 | uv_rtc_init(); | 629 | uv_rtc_init(); |
630 | 630 | ||
631 | for_each_present_cpu(cpu) { | 631 | for_each_present_cpu(cpu) { |
632 | int apicid = per_cpu(x86_cpu_to_apicid, cpu); | ||
633 | |||
632 | nid = cpu_to_node(cpu); | 634 | nid = cpu_to_node(cpu); |
633 | pnode = uv_apicid_to_pnode(per_cpu(x86_cpu_to_apicid, cpu)); | 635 | pnode = uv_apicid_to_pnode(apicid); |
634 | blade = boot_pnode_to_blade(pnode); | 636 | blade = boot_pnode_to_blade(pnode); |
635 | lcpu = uv_blade_info[blade].nr_possible_cpus; | 637 | lcpu = uv_blade_info[blade].nr_possible_cpus; |
636 | uv_blade_info[blade].nr_possible_cpus++; | 638 | uv_blade_info[blade].nr_possible_cpus++; |
@@ -651,15 +653,13 @@ void __init uv_system_init(void) | |||
651 | uv_cpu_hub_info(cpu)->gnode_extra = gnode_extra; | 653 | uv_cpu_hub_info(cpu)->gnode_extra = gnode_extra; |
652 | uv_cpu_hub_info(cpu)->global_mmr_base = mmr_base; | 654 | uv_cpu_hub_info(cpu)->global_mmr_base = mmr_base; |
653 | uv_cpu_hub_info(cpu)->coherency_domain_number = sn_coherency_id; | 655 | uv_cpu_hub_info(cpu)->coherency_domain_number = sn_coherency_id; |
654 | uv_cpu_hub_info(cpu)->scir.offset = SCIR_LOCAL_MMR_BASE + lcpu; | 656 | uv_cpu_hub_info(cpu)->scir.offset = uv_scir_offset(apicid); |
655 | uv_node_to_blade[nid] = blade; | 657 | uv_node_to_blade[nid] = blade; |
656 | uv_cpu_to_blade[cpu] = blade; | 658 | uv_cpu_to_blade[cpu] = blade; |
657 | max_pnode = max(pnode, max_pnode); | 659 | max_pnode = max(pnode, max_pnode); |
658 | 660 | ||
659 | printk(KERN_DEBUG "UV: cpu %d, apicid 0x%x, pnode %d, nid %d, " | 661 | printk(KERN_DEBUG "UV: cpu %d, apicid 0x%x, pnode %d, nid %d, lcpu %d, blade %d\n", |
660 | "lcpu %d, blade %d\n", | 662 | cpu, apicid, pnode, nid, lcpu, blade); |
661 | cpu, per_cpu(x86_cpu_to_apicid, cpu), pnode, nid, | ||
662 | lcpu, blade); | ||
663 | } | 663 | } |
664 | 664 | ||
665 | /* Add blade/pnode info for nodes without cpus */ | 665 | /* Add blade/pnode info for nodes without cpus */ |