aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@novell.com>2006-06-23 05:04:19 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-23 10:42:56 -0400
commitba528f2854e8632c8d04ddcd45f06c47bc7188b0 (patch)
tree39caa13f0c1d2634e2e7947317c965792ee92d32 /arch/i386/kernel
parent27b07da7332f03a935cd13b6a6beb780bf19e7a4 (diff)
[PATCH] fix x86 microcode driver handling of multiple matching revisions
When multiple updates matching a given CPU are found in the update file, the action taken by the microcode update driver was inappropriate: - when lower revision microcode was found before matching or higher revision one, the driver would needlessly complain that it would not downgrade the CPU - when microcode matching the currently installed revision was found before newer revision code, no update would actually take place To change this behavior, the driver now concludes about possibly updates and issues messages only when the entire input was parsed. Additionally, this adds back (in different places, and conditionalized upon a new module option) some messages removed by a previous patch. Signed-off-by: Jan Beulich <jbeulich@novell.com> Cc: "Siddha, Suresh B" <suresh.b.siddha@intel.com> Cc: Tigran Aivazian <tigran_aivazian@symantec.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/i386/kernel')
-rw-r--r--arch/i386/kernel/microcode.c73
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");
91MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>"); 91MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
92MODULE_LICENSE("GPL"); 92MODULE_LICENSE("GPL");
93 93
94#define MICROCODE_VERSION "1.14" 94static int verbose;
95module_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
123typedef enum mc_error_code { 126typedef 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
130static struct ucode_cpu_info { 134static 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 */
214out:
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 }
430out: 455out:
431 return error; 456 return error;