diff options
| -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 e7c138f66c..0a865889b2 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; |
