diff options
Diffstat (limited to 'arch/i386')
-rw-r--r-- | arch/i386/kernel/microcode.c | 73 |
1 files changed, 49 insertions, 24 deletions
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c index e7c138f66c5a..0a865889b2a9 100644 --- a/arch/i386/kernel/microcode.c +++ b/arch/i386/kernel/microcode.c | |||
@@ -91,7 +91,10 @@ MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver"); | |||
91 | MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>"); | 91 | MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>"); |
92 | MODULE_LICENSE("GPL"); | 92 | MODULE_LICENSE("GPL"); |
93 | 93 | ||
94 | #define MICROCODE_VERSION "1.14" | 94 | static int verbose; |
95 | module_param(verbose, int, 0644); | ||
96 | |||
97 | #define MICROCODE_VERSION "1.14a" | ||
95 | 98 | ||
96 | #define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */ | 99 | #define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */ |
97 | #define MC_HEADER_SIZE (sizeof (microcode_header_t)) /* 48 bytes */ | 100 | #define MC_HEADER_SIZE (sizeof (microcode_header_t)) /* 48 bytes */ |
@@ -122,14 +125,15 @@ static unsigned int user_buffer_size; /* it's size */ | |||
122 | 125 | ||
123 | typedef enum mc_error_code { | 126 | typedef enum mc_error_code { |
124 | MC_SUCCESS = 0, | 127 | MC_SUCCESS = 0, |
125 | MC_NOTFOUND = 1, | 128 | MC_IGNORED = 1, |
126 | MC_MARKED = 2, | 129 | MC_NOTFOUND = 2, |
127 | MC_ALLOCATED = 3, | 130 | MC_MARKED = 3, |
131 | MC_ALLOCATED = 4, | ||
128 | } mc_error_code_t; | 132 | } mc_error_code_t; |
129 | 133 | ||
130 | static struct ucode_cpu_info { | 134 | static struct ucode_cpu_info { |
131 | unsigned int sig; | 135 | unsigned int sig; |
132 | unsigned int pf; | 136 | unsigned int pf, orig_pf; |
133 | unsigned int rev; | 137 | unsigned int rev; |
134 | unsigned int cksum; | 138 | unsigned int cksum; |
135 | mc_error_code_t err; | 139 | mc_error_code_t err; |
@@ -164,6 +168,7 @@ static void collect_cpu_info (void *unused) | |||
164 | rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); | 168 | rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); |
165 | uci->pf = 1 << ((val[1] >> 18) & 7); | 169 | uci->pf = 1 << ((val[1] >> 18) & 7); |
166 | } | 170 | } |
171 | uci->orig_pf = uci->pf; | ||
167 | } | 172 | } |
168 | 173 | ||
169 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); | 174 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); |
@@ -197,21 +202,34 @@ static inline void mark_microcode_update (int cpu_num, microcode_header_t *mc_he | |||
197 | pr_debug(" Checksum 0x%x\n", cksum); | 202 | pr_debug(" Checksum 0x%x\n", cksum); |
198 | 203 | ||
199 | if (mc_header->rev < uci->rev) { | 204 | if (mc_header->rev < uci->rev) { |
200 | printk(KERN_ERR "microcode: CPU%d not 'upgrading' to earlier revision" | 205 | if (uci->err == MC_NOTFOUND) { |
201 | " 0x%x (current=0x%x)\n", cpu_num, mc_header->rev, uci->rev); | 206 | uci->err = MC_IGNORED; |
202 | goto out; | 207 | uci->cksum = mc_header->rev; |
208 | } else if (uci->err == MC_IGNORED && uci->cksum < mc_header->rev) | ||
209 | uci->cksum = mc_header->rev; | ||
203 | } else if (mc_header->rev == uci->rev) { | 210 | } else if (mc_header->rev == uci->rev) { |
204 | /* notify the caller of success on this cpu */ | 211 | if (uci->err < MC_MARKED) { |
205 | uci->err = MC_SUCCESS; | 212 | /* notify the caller of success on this cpu */ |
206 | goto out; | 213 | uci->err = MC_SUCCESS; |
214 | } | ||
215 | } else if (uci->err != MC_ALLOCATED || mc_header->rev > uci->mc->hdr.rev) { | ||
216 | pr_debug("microcode: CPU%d found a matching microcode update with " | ||
217 | " revision 0x%x (current=0x%x)\n", cpu_num, mc_header->rev, uci->rev); | ||
218 | uci->cksum = cksum; | ||
219 | uci->pf = pf; /* keep the original mc pf for cksum calculation */ | ||
220 | uci->err = MC_MARKED; /* found the match */ | ||
221 | for_each_online_cpu(cpu_num) { | ||
222 | if (ucode_cpu_info + cpu_num != uci | ||
223 | && ucode_cpu_info[cpu_num].mc == uci->mc) { | ||
224 | uci->mc = NULL; | ||
225 | break; | ||
226 | } | ||
227 | } | ||
228 | if (uci->mc != NULL) { | ||
229 | vfree(uci->mc); | ||
230 | uci->mc = NULL; | ||
231 | } | ||
207 | } | 232 | } |
208 | |||
209 | pr_debug("microcode: CPU%d found a matching microcode update with " | ||
210 | " revision 0x%x (current=0x%x)\n", cpu_num, mc_header->rev, uci->rev); | ||
211 | uci->cksum = cksum; | ||
212 | uci->pf = pf; /* keep the original mc pf for cksum calculation */ | ||
213 | uci->err = MC_MARKED; /* found the match */ | ||
214 | out: | ||
215 | return; | 233 | return; |
216 | } | 234 | } |
217 | 235 | ||
@@ -253,10 +271,8 @@ static int find_matching_ucodes (void) | |||
253 | 271 | ||
254 | for_each_online_cpu(cpu_num) { | 272 | for_each_online_cpu(cpu_num) { |
255 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; | 273 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; |
256 | if (uci->err != MC_NOTFOUND) /* already found a match or not an online cpu*/ | ||
257 | continue; | ||
258 | 274 | ||
259 | if (sigmatch(mc_header.sig, uci->sig, mc_header.pf, uci->pf)) | 275 | if (sigmatch(mc_header.sig, uci->sig, mc_header.pf, uci->orig_pf)) |
260 | mark_microcode_update(cpu_num, &mc_header, mc_header.sig, mc_header.pf, mc_header.cksum); | 276 | mark_microcode_update(cpu_num, &mc_header, mc_header.sig, mc_header.pf, mc_header.cksum); |
261 | } | 277 | } |
262 | 278 | ||
@@ -295,9 +311,8 @@ static int find_matching_ucodes (void) | |||
295 | } | 311 | } |
296 | for_each_online_cpu(cpu_num) { | 312 | for_each_online_cpu(cpu_num) { |
297 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; | 313 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; |
298 | if (uci->err != MC_NOTFOUND) /* already found a match or not an online cpu*/ | 314 | |
299 | continue; | 315 | if (sigmatch(ext_sig.sig, uci->sig, ext_sig.pf, uci->orig_pf)) { |
300 | if (sigmatch(ext_sig.sig, uci->sig, ext_sig.pf, uci->pf)) { | ||
301 | mark_microcode_update(cpu_num, &mc_header, ext_sig.sig, ext_sig.pf, ext_sig.cksum); | 316 | mark_microcode_update(cpu_num, &mc_header, ext_sig.sig, ext_sig.pf, ext_sig.cksum); |
302 | } | 317 | } |
303 | } | 318 | } |
@@ -368,6 +383,13 @@ static void do_update_one (void * unused) | |||
368 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; | 383 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; |
369 | 384 | ||
370 | if (uci->mc == NULL) { | 385 | if (uci->mc == NULL) { |
386 | if (verbose) { | ||
387 | if (uci->err == MC_SUCCESS) | ||
388 | printk(KERN_INFO "microcode: CPU%d already at revision 0x%x\n", | ||
389 | cpu_num, uci->rev); | ||
390 | else | ||
391 | printk(KERN_INFO "microcode: No new microcode data for CPU%d\n", cpu_num); | ||
392 | } | ||
371 | return; | 393 | return; |
372 | } | 394 | } |
373 | 395 | ||
@@ -426,6 +448,9 @@ out_free: | |||
426 | ucode_cpu_info[j].mc = NULL; | 448 | ucode_cpu_info[j].mc = NULL; |
427 | } | 449 | } |
428 | } | 450 | } |
451 | if (ucode_cpu_info[i].err == MC_IGNORED && verbose) | ||
452 | printk(KERN_WARNING "microcode: CPU%d not 'upgrading' to earlier revision" | ||
453 | " 0x%x (current=0x%x)\n", i, ucode_cpu_info[i].cksum, ucode_cpu_info[i].rev); | ||
429 | } | 454 | } |
430 | out: | 455 | out: |
431 | return error; | 456 | return error; |