diff options
author | Mike Travis <travis@sgi.com> | 2016-04-29 17:54:17 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-05-04 02:48:49 -0400 |
commit | 405422d88c686e88b4241c0201fd96b61ab8bd77 (patch) | |
tree | 413a5da0ced27e3008c1a151fd05ea40f741a47a | |
parent | 906f3b20da8c6ec3eeef81753b4af9b6780e2edc (diff) |
x86/platform/UV: Add UV4 addressing discovery function
UV4 requires early system wide addressing values. This involves the use
of the CPUID instruction to obtain these values. The current function
(detect_extended_topology()) in the kernel has been copied and streamlined,
with the limitation that only CPU's used by UV architectures are supported.
Tested-by: John Estabrook <estabrook@sgi.com>
Tested-by: Gary Kroening <gfk@sgi.com>
Tested-by: Nathan Zimmer <nzimmer@sgi.com>
Signed-off-by: Mike Travis <travis@sgi.com>
Reviewed-by: Dimitri Sivanich <sivanich@sgi.com>
Cc: Andrew Banman <abanman@sgi.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Len Brown <len.brown@intel.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Russ Anderson <rja@sgi.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160429215405.155660884@asylum.americas.sgi.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/x86/kernel/apic/x2apic_uv_x.c | 85 |
1 files changed, 72 insertions, 13 deletions
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index afe1b039bd40..470f2dfe2709 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c | |||
@@ -48,6 +48,16 @@ static u64 gru_start_paddr, gru_end_paddr; | |||
48 | static u64 gru_dist_base, gru_first_node_paddr = -1LL, gru_last_node_paddr; | 48 | static u64 gru_dist_base, gru_first_node_paddr = -1LL, gru_last_node_paddr; |
49 | static u64 gru_dist_lmask, gru_dist_umask; | 49 | static u64 gru_dist_lmask, gru_dist_umask; |
50 | static union uvh_apicid uvh_apicid; | 50 | static union uvh_apicid uvh_apicid; |
51 | |||
52 | /* info derived from CPUID */ | ||
53 | static struct { | ||
54 | unsigned int apicid_shift; | ||
55 | unsigned int apicid_mask; | ||
56 | unsigned int socketid_shift; /* aka pnode_shift for UV1/2/3 */ | ||
57 | unsigned int pnode_mask; | ||
58 | unsigned int gpa_shift; | ||
59 | } uv_cpuid; | ||
60 | |||
51 | int uv_min_hub_revision_id; | 61 | int uv_min_hub_revision_id; |
52 | EXPORT_SYMBOL_GPL(uv_min_hub_revision_id); | 62 | EXPORT_SYMBOL_GPL(uv_min_hub_revision_id); |
53 | unsigned int uv_apicid_hibits; | 63 | unsigned int uv_apicid_hibits; |
@@ -127,18 +137,65 @@ static int __init early_get_pnodeid(void) | |||
127 | } | 137 | } |
128 | 138 | ||
129 | uv_hub_info->hub_revision = uv_min_hub_revision_id; | 139 | uv_hub_info->hub_revision = uv_min_hub_revision_id; |
130 | pnode = (node_id.s.node_id >> 1) & ((1 << m_n_config.s.n_skt) - 1); | 140 | uv_cpuid.pnode_mask = (1 << m_n_config.s.n_skt) - 1; |
141 | pnode = (node_id.s.node_id >> 1) & uv_cpuid.pnode_mask; | ||
142 | uv_cpuid.gpa_shift = 46; /* default unless changed */ | ||
143 | |||
144 | pr_info("UV: rev:%d part#:%x nodeid:%04x n_skt:%d pnmsk:%x pn:%x\n", | ||
145 | node_id.s.revision, node_id.s.part_number, node_id.s.node_id, | ||
146 | m_n_config.s.n_skt, uv_cpuid.pnode_mask, pnode); | ||
131 | return pnode; | 147 | return pnode; |
132 | } | 148 | } |
133 | 149 | ||
134 | static void __init early_get_apic_pnode_shift(void) | 150 | /* [copied from arch/x86/kernel/cpu/topology.c:detect_extended_topology()] */ |
151 | #define SMT_LEVEL 0 /* leaf 0xb SMT level */ | ||
152 | #define INVALID_TYPE 0 /* leaf 0xb sub-leaf types */ | ||
153 | #define SMT_TYPE 1 | ||
154 | #define CORE_TYPE 2 | ||
155 | #define LEAFB_SUBTYPE(ecx) (((ecx) >> 8) & 0xff) | ||
156 | #define BITS_SHIFT_NEXT_LEVEL(eax) ((eax) & 0x1f) | ||
157 | |||
158 | static void set_x2apic_bits(void) | ||
159 | { | ||
160 | unsigned int eax, ebx, ecx, edx, sub_index; | ||
161 | unsigned int sid_shift; | ||
162 | |||
163 | cpuid(0, &eax, &ebx, &ecx, &edx); | ||
164 | if (eax < 0xb) { | ||
165 | pr_info("UV: CPU does not have CPUID.11\n"); | ||
166 | return; | ||
167 | } | ||
168 | cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx); | ||
169 | if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE)) { | ||
170 | pr_info("UV: CPUID.11 not implemented\n"); | ||
171 | return; | ||
172 | } | ||
173 | sid_shift = BITS_SHIFT_NEXT_LEVEL(eax); | ||
174 | sub_index = 1; | ||
175 | do { | ||
176 | cpuid_count(0xb, sub_index, &eax, &ebx, &ecx, &edx); | ||
177 | if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) { | ||
178 | sid_shift = BITS_SHIFT_NEXT_LEVEL(eax); | ||
179 | break; | ||
180 | } | ||
181 | sub_index++; | ||
182 | } while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE); | ||
183 | uv_cpuid.apicid_shift = 0; | ||
184 | uv_cpuid.apicid_mask = (~(-1 << sid_shift)); | ||
185 | uv_cpuid.socketid_shift = sid_shift; | ||
186 | } | ||
187 | |||
188 | static void __init early_get_apic_socketid_shift(void) | ||
135 | { | 189 | { |
136 | uvh_apicid.v = uv_early_read_mmr(UVH_APICID); | 190 | if (is_uv2_hub() || is_uv3_hub()) |
137 | if (!uvh_apicid.v) | 191 | uvh_apicid.v = uv_early_read_mmr(UVH_APICID); |
138 | /* | 192 | |
139 | * Old bios, use default value | 193 | set_x2apic_bits(); |
140 | */ | 194 | |
141 | uvh_apicid.s.pnode_shift = UV_APIC_PNODE_SHIFT; | 195 | pr_info("UV: apicid_shift:%d apicid_mask:0x%x\n", |
196 | uv_cpuid.apicid_shift, uv_cpuid.apicid_mask); | ||
197 | pr_info("UV: socketid_shift:%d pnode_mask:0x%x\n", | ||
198 | uv_cpuid.socketid_shift, uv_cpuid.pnode_mask); | ||
142 | } | 199 | } |
143 | 200 | ||
144 | /* | 201 | /* |
@@ -186,7 +243,7 @@ static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id) | |||
186 | goto badbios; | 243 | goto badbios; |
187 | 244 | ||
188 | pnodeid = early_get_pnodeid(); | 245 | pnodeid = early_get_pnodeid(); |
189 | early_get_apic_pnode_shift(); | 246 | early_get_apic_socketid_shift(); |
190 | x86_platform.is_untracked_pat_range = uv_is_untracked_pat_range; | 247 | x86_platform.is_untracked_pat_range = uv_is_untracked_pat_range; |
191 | x86_platform.nmi_init = uv_nmi_init; | 248 | x86_platform.nmi_init = uv_nmi_init; |
192 | 249 | ||
@@ -917,11 +974,13 @@ void __init uv_init_hub_info(struct uv_hub_info_s *hub_info) | |||
917 | hub_info->m_val = mn.m_val; | 974 | hub_info->m_val = mn.m_val; |
918 | hub_info->n_val = mn.n_val; | 975 | hub_info->n_val = mn.n_val; |
919 | hub_info->m_shift = mn.m_shift; | 976 | hub_info->m_shift = mn.m_shift; |
920 | hub_info->n_lshift = mn.n_lshift; | 977 | hub_info->n_lshift = mn.n_lshift ? mn.n_lshift : 0; |
921 | 978 | ||
922 | hub_info->hub_revision = uv_hub_info->hub_revision; | 979 | hub_info->hub_revision = uv_hub_info->hub_revision; |
923 | hub_info->pnode_mask = (1 << mn.n_val) - 1; | 980 | hub_info->pnode_mask = uv_cpuid.pnode_mask; |
924 | hub_info->gpa_mask = (1UL << (mn.m_val + mn.n_val)) - 1; | 981 | hub_info->gpa_mask = mn.m_val ? |
982 | (1UL << (mn.m_val + mn.n_val)) - 1 : | ||
983 | (1UL << uv_cpuid.gpa_shift) - 1; | ||
925 | 984 | ||
926 | node_id.v = uv_read_local_mmr(UVH_NODE_ID); | 985 | node_id.v = uv_read_local_mmr(UVH_NODE_ID); |
927 | hub_info->gnode_extra = | 986 | hub_info->gnode_extra = |
@@ -937,7 +996,7 @@ void __init uv_init_hub_info(struct uv_hub_info_s *hub_info) | |||
937 | get_lowmem_redirect( | 996 | get_lowmem_redirect( |
938 | &hub_info->lowmem_remap_base, &hub_info->lowmem_remap_top); | 997 | &hub_info->lowmem_remap_base, &hub_info->lowmem_remap_top); |
939 | 998 | ||
940 | hub_info->apic_pnode_shift = uvh_apicid.s.pnode_shift; | 999 | hub_info->apic_pnode_shift = uv_cpuid.socketid_shift; |
941 | 1000 | ||
942 | /* show system specific info */ | 1001 | /* show system specific info */ |
943 | pr_info("UV: N:%d M:%d m_shift:%d n_lshift:%d\n", | 1002 | pr_info("UV: N:%d M:%d m_shift:%d n_lshift:%d\n", |