Commit | Line | Data |
---|---|---|
4d285878 DJ |
1 | #include <linux/init.h> |
2 | #include <linux/mm.h> | |
3 | ||
4 | #include <asm/numa_64.h> | |
5 | #include <asm/mmconfig.h> | |
6 | #include <asm/cacheflush.h> | |
7 | ||
8 | #include <mach_apic.h> | |
9e26d842 | 9 | #include "cpu.h" |
4d285878 DJ |
10 | |
11 | extern int __cpuinit get_model_name(struct cpuinfo_x86 *c); | |
12 | extern void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c); | |
13 | ||
14 | int force_mwait __cpuinitdata; | |
15 | ||
16 | #ifdef CONFIG_NUMA | |
17 | static int __cpuinit nearby_node(int apicid) | |
18 | { | |
19 | int i, node; | |
20 | ||
21 | for (i = apicid - 1; i >= 0; i--) { | |
22 | node = apicid_to_node[i]; | |
23 | if (node != NUMA_NO_NODE && node_online(node)) | |
24 | return node; | |
25 | } | |
26 | for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) { | |
27 | node = apicid_to_node[i]; | |
28 | if (node != NUMA_NO_NODE && node_online(node)) | |
29 | return node; | |
30 | } | |
31 | return first_node(node_online_map); /* Shouldn't happen */ | |
32 | } | |
33 | #endif | |
34 | ||
35 | /* | |
36 | * On a AMD dual core setup the lower bits of the APIC id distingush the cores. | |
37 | * Assumes number of cores is a power of two. | |
38 | */ | |
39 | static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c) | |
40 | { | |
41 | #ifdef CONFIG_SMP | |
42 | unsigned bits; | |
43 | #ifdef CONFIG_NUMA | |
44 | int cpu = smp_processor_id(); | |
45 | int node = 0; | |
46 | unsigned apicid = hard_smp_processor_id(); | |
47 | #endif | |
48 | bits = c->x86_coreid_bits; | |
49 | ||
50 | /* Low order bits define the core id (index of core in socket) */ | |
51 | c->cpu_core_id = c->initial_apicid & ((1 << bits)-1); | |
52 | /* Convert the initial APIC ID into the socket ID */ | |
53 | c->phys_proc_id = c->initial_apicid >> bits; | |
54 | ||
55 | #ifdef CONFIG_NUMA | |
56 | node = c->phys_proc_id; | |
57 | if (apicid_to_node[apicid] != NUMA_NO_NODE) | |
58 | node = apicid_to_node[apicid]; | |
59 | if (!node_online(node)) { | |
60 | /* Two possibilities here: | |
61 | - The CPU is missing memory and no node was created. | |
62 | In that case try picking one from a nearby CPU | |
63 | - The APIC IDs differ from the HyperTransport node IDs | |
64 | which the K8 northbridge parsing fills in. | |
65 | Assume they are all increased by a constant offset, | |
66 | but in the same order as the HT nodeids. | |
67 | If that doesn't result in a usable node fall back to the | |
68 | path for the previous case. */ | |
69 | ||
70 | int ht_nodeid = c->initial_apicid; | |
71 | ||
72 | if (ht_nodeid >= 0 && | |
73 | apicid_to_node[ht_nodeid] != NUMA_NO_NODE) | |
74 | node = apicid_to_node[ht_nodeid]; | |
75 | /* Pick a nearby node */ | |
76 | if (!node_online(node)) | |
77 | node = nearby_node(apicid); | |
78 | } | |
79 | numa_set_node(cpu, node); | |
80 | ||
81 | printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node); | |
82 | #endif | |
83 | #endif | |
84 | } | |
85 | ||
86 | static void __cpuinit early_init_amd_mc(struct cpuinfo_x86 *c) | |
87 | { | |
88 | #ifdef CONFIG_SMP | |
89 | unsigned bits, ecx; | |
90 | ||
91 | /* Multi core CPU? */ | |
92 | if (c->extended_cpuid_level < 0x80000008) | |
93 | return; | |
94 | ||
95 | ecx = cpuid_ecx(0x80000008); | |
96 | ||
97 | c->x86_max_cores = (ecx & 0xff) + 1; | |
98 | ||
99 | /* CPU telling us the core id bits shift? */ | |
100 | bits = (ecx >> 12) & 0xF; | |
101 | ||
102 | /* Otherwise recompute */ | |
103 | if (bits == 0) { | |
104 | while ((1 << bits) < c->x86_max_cores) | |
105 | bits++; | |
106 | } | |
107 | ||
108 | c->x86_coreid_bits = bits; | |
109 | ||
110 | #endif | |
111 | } | |
112 | ||
4d285878 DJ |
113 | #define CPUID_PROCESSOR_SIGNATURE 1 |
114 | #define CPUID_XFAM 0x0ff00000 | |
115 | #define CPUID_XFAM_K8 0x00000000 | |
116 | #define CPUID_XFAM_10H 0x00100000 | |
117 | #define CPUID_XFAM_11H 0x00200000 | |
118 | #define CPUID_XMOD 0x000f0000 | |
119 | #define CPUID_XMOD_REV_F 0x00040000 | |
120 | ||
121 | /* AMD systems with C1E don't have a working lAPIC timer. Check for that. */ | |
122 | static __cpuinit int amd_apic_timer_broken(void) | |
123 | { | |
124 | u32 lo, hi, eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE); | |
125 | ||
126 | switch (eax & CPUID_XFAM) { | |
127 | case CPUID_XFAM_K8: | |
128 | if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F) | |
129 | break; | |
130 | case CPUID_XFAM_10H: | |
131 | case CPUID_XFAM_11H: | |
aa83f3f2 TG |
132 | rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi); |
133 | if (lo & K8_INTP_C1E_ACTIVE_MASK) | |
4d285878 DJ |
134 | return 1; |
135 | break; | |
136 | default: | |
137 | /* err on the side of caution */ | |
138 | return 1; | |
139 | } | |
140 | return 0; | |
141 | } | |
142 | ||
143 | void __cpuinit early_init_amd(struct cpuinfo_x86 *c) | |
144 | { | |
145 | early_init_amd_mc(c); | |
146 | ||
147 | /* c->x86_power is 8000_0007 edx. Bit 8 is constant TSC */ | |
148 | if (c->x86_power & (1<<8)) | |
149 | set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); | |
150 | } | |
151 | ||
152 | void __cpuinit init_amd(struct cpuinfo_x86 *c) | |
153 | { | |
154 | unsigned level; | |
155 | ||
156 | #ifdef CONFIG_SMP | |
157 | unsigned long value; | |
158 | ||
159 | /* | |
160 | * Disable TLB flush filter by setting HWCR.FFDIS on K8 | |
161 | * bit 6 of msr C001_0015 | |
162 | * | |
163 | * Errata 63 for SH-B3 steppings | |
164 | * Errata 122 for all steppings (F+ have it disabled by default) | |
165 | */ | |
166 | if (c->x86 == 15) { | |
167 | rdmsrl(MSR_K8_HWCR, value); | |
168 | value |= 1 << 6; | |
169 | wrmsrl(MSR_K8_HWCR, value); | |
170 | } | |
171 | #endif | |
172 | ||
173 | /* Bit 31 in normal CPUID used for nonstandard 3DNow ID; | |
174 | 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */ | |
175 | clear_cpu_cap(c, 0*32+31); | |
176 | ||
177 | /* On C+ stepping K8 rep microcode works well for copy/memset */ | |
178 | level = cpuid_eax(1); | |
179 | if (c->x86 == 15 && ((level >= 0x0f48 && level < 0x0f50) || | |
180 | level >= 0x0f58)) | |
181 | set_cpu_cap(c, X86_FEATURE_REP_GOOD); | |
182 | if (c->x86 == 0x10 || c->x86 == 0x11) | |
183 | set_cpu_cap(c, X86_FEATURE_REP_GOOD); | |
184 | ||
185 | /* Enable workaround for FXSAVE leak */ | |
186 | if (c->x86 >= 6) | |
187 | set_cpu_cap(c, X86_FEATURE_FXSAVE_LEAK); | |
188 | ||
189 | level = get_model_name(c); | |
190 | if (!level) { | |
191 | switch (c->x86) { | |
192 | case 15: | |
193 | /* Should distinguish Models here, but this is only | |
194 | a fallback anyways. */ | |
195 | strcpy(c->x86_model_id, "Hammer"); | |
196 | break; | |
197 | } | |
198 | } | |
199 | display_cacheinfo(c); | |
200 | ||
201 | /* Multi core CPU? */ | |
202 | if (c->extended_cpuid_level >= 0x80000008) | |
203 | amd_detect_cmp(c); | |
204 | ||
205 | if (c->extended_cpuid_level >= 0x80000006 && | |
206 | (cpuid_edx(0x80000006) & 0xf000)) | |
207 | num_cache_leaves = 4; | |
208 | else | |
209 | num_cache_leaves = 3; | |
210 | ||
211 | if (c->x86 == 0xf || c->x86 == 0x10 || c->x86 == 0x11) | |
212 | set_cpu_cap(c, X86_FEATURE_K8); | |
213 | ||
214 | /* MFENCE stops RDTSC speculation */ | |
215 | set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC); | |
216 | ||
217 | if (c->x86 == 0x10) | |
218 | fam10h_check_enable_mmcfg(); | |
219 | ||
831d9918 RR |
220 | if (c->x86 == 0x10) |
221 | amd_enable_pci_ext_cfg(c); | |
222 | ||
4d285878 DJ |
223 | if (amd_apic_timer_broken()) |
224 | disable_apic_timer = 1; | |
225 | ||
226 | if (c == &boot_cpu_data && c->x86 >= 0xf && c->x86 <= 0x11) { | |
227 | unsigned long long tseg; | |
228 | ||
229 | /* | |
230 | * Split up direct mapping around the TSEG SMM area. | |
231 | * Don't do it for gbpages because there seems very little | |
232 | * benefit in doing so. | |
233 | */ | |
234 | if (!rdmsrl_safe(MSR_K8_TSEG_ADDR, &tseg) && | |
1c47cd63 PA |
235 | (tseg >> PMD_SHIFT) < |
236 | (max_pfn_mapped >> (PMD_SHIFT-PAGE_SHIFT))) | |
4d285878 DJ |
237 | set_memory_4k((unsigned long)__va(tseg), 1); |
238 | } | |
239 | } |