aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/microcode.c
diff options
context:
space:
mode:
authorShaohua Li <shaohua.li@intel.com>2006-09-27 04:50:51 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-27 11:26:18 -0400
commit9a3110bf4bb0466b43b898533bfd4952001bc38f (patch)
treea2a9c94564562fda7fb8ca2bbec9611e094ed1f6 /arch/i386/kernel/microcode.c
parent36b756f2b5762e6d5acba0c18e75cb5c11f11c1b (diff)
[PATCH] x86 microcode: microcode driver cleanup.
Clean up microcode update driver and make it more readable. [akpm@osdl.org: cleanups] Signed-off-by: Shaohua Li <shaohua.li@intel.com> Acked-by: Tigran Aivazian <tigran@veritas.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/i386/kernel/microcode.c')
-rw-r--r--arch/i386/kernel/microcode.c508
1 files changed, 250 insertions, 258 deletions
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
index 40b44cc0d14b..00bdc3dd693e 100644
--- a/arch/i386/kernel/microcode.c
+++ b/arch/i386/kernel/microcode.c
@@ -2,6 +2,7 @@
2 * Intel CPU Microcode Update Driver for Linux 2 * Intel CPU Microcode Update Driver for Linux
3 * 3 *
4 * Copyright (C) 2000-2004 Tigran Aivazian 4 * Copyright (C) 2000-2004 Tigran Aivazian
5 * 2006 Shaohua Li <shaohua.li@intel.com>
5 * 6 *
6 * This driver allows to upgrade microcode on Intel processors 7 * This driver allows to upgrade microcode on Intel processors
7 * belonging to IA-32 family - PentiumPro, Pentium II, 8 * belonging to IA-32 family - PentiumPro, Pentium II,
@@ -91,9 +92,6 @@ MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver");
91MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>"); 92MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
92MODULE_LICENSE("GPL"); 93MODULE_LICENSE("GPL");
93 94
94static int verbose;
95module_param(verbose, int, 0644);
96
97#define MICROCODE_VERSION "1.14a" 95#define MICROCODE_VERSION "1.14a"
98 96
99#define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */ 97#define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */
@@ -120,55 +118,40 @@ static DEFINE_SPINLOCK(microcode_update_lock);
120/* no concurrent ->write()s are allowed on /dev/cpu/microcode */ 118/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
121static DEFINE_MUTEX(microcode_mutex); 119static DEFINE_MUTEX(microcode_mutex);
122 120
123static void __user *user_buffer; /* user area microcode data buffer */
124static unsigned int user_buffer_size; /* it's size */
125
126typedef enum mc_error_code {
127 MC_SUCCESS = 0,
128 MC_IGNORED = 1,
129 MC_NOTFOUND = 2,
130 MC_MARKED = 3,
131 MC_ALLOCATED = 4,
132} mc_error_code_t;
133
134static struct ucode_cpu_info { 121static struct ucode_cpu_info {
122 int valid;
135 unsigned int sig; 123 unsigned int sig;
136 unsigned int pf, orig_pf; 124 unsigned int pf;
137 unsigned int rev; 125 unsigned int rev;
138 unsigned int cksum;
139 mc_error_code_t err;
140 microcode_t *mc; 126 microcode_t *mc;
141} ucode_cpu_info[NR_CPUS]; 127} ucode_cpu_info[NR_CPUS];
142
143static int microcode_open (struct inode *unused1, struct file *unused2)
144{
145 return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
146}
147 128
148static void collect_cpu_info (void *unused) 129static void collect_cpu_info(int cpu_num)
149{ 130{
150 int cpu_num = smp_processor_id();
151 struct cpuinfo_x86 *c = cpu_data + cpu_num; 131 struct cpuinfo_x86 *c = cpu_data + cpu_num;
152 struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; 132 struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
153 unsigned int val[2]; 133 unsigned int val[2];
154 134
155 uci->sig = uci->pf = uci->rev = uci->cksum = 0; 135 /* We should bind the task to the CPU */
156 uci->err = MC_NOTFOUND; 136 BUG_ON(raw_smp_processor_id() != cpu_num);
137 uci->pf = uci->rev = 0;
157 uci->mc = NULL; 138 uci->mc = NULL;
139 uci->valid = 1;
158 140
159 if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 || 141 if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
160 cpu_has(c, X86_FEATURE_IA64)) { 142 cpu_has(c, X86_FEATURE_IA64)) {
161 printk(KERN_ERR "microcode: CPU%d not a capable Intel processor\n", cpu_num); 143 printk(KERN_ERR "microcode: CPU%d not a capable Intel "
144 "processor\n", cpu_num);
145 uci->valid = 0;
162 return; 146 return;
163 } else { 147 }
164 uci->sig = cpuid_eax(0x00000001);
165 148
166 if ((c->x86_model >= 5) || (c->x86 > 6)) { 149 uci->sig = cpuid_eax(0x00000001);
167 /* get processor flags from MSR 0x17 */ 150
168 rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); 151 if ((c->x86_model >= 5) || (c->x86 > 6)) {
169 uci->pf = 1 << ((val[1] >> 18) & 7); 152 /* get processor flags from MSR 0x17 */
170 } 153 rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
171 uci->orig_pf = uci->pf; 154 uci->pf = 1 << ((val[1] >> 18) & 7);
172 } 155 }
173 156
174 wrmsr(MSR_IA32_UCODE_REV, 0, 0); 157 wrmsr(MSR_IA32_UCODE_REV, 0, 0);
@@ -180,218 +163,160 @@ static void collect_cpu_info (void *unused)
180 uci->sig, uci->pf, uci->rev); 163 uci->sig, uci->pf, uci->rev);
181} 164}
182 165
183static inline void mark_microcode_update (int cpu_num, microcode_header_t *mc_header, int sig, int pf, int cksum) 166static inline int microcode_update_match(int cpu_num,
167 microcode_header_t *mc_header, int sig, int pf)
184{ 168{
185 struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; 169 struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
186 170
187 pr_debug("Microcode Found.\n"); 171 if (!sigmatch(sig, uci->sig, pf, uci->pf)
188 pr_debug(" Header Revision 0x%x\n", mc_header->hdrver); 172 || mc_header->rev <= uci->rev)
189 pr_debug(" Loader Revision 0x%x\n", mc_header->ldrver); 173 return 0;
190 pr_debug(" Revision 0x%x \n", mc_header->rev); 174 return 1;
191 pr_debug(" Date %x/%x/%x\n",
192 ((mc_header->date >> 24 ) & 0xff),
193 ((mc_header->date >> 16 ) & 0xff),
194 (mc_header->date & 0xFFFF));
195 pr_debug(" Signature 0x%x\n", sig);
196 pr_debug(" Type 0x%x Family 0x%x Model 0x%x Stepping 0x%x\n",
197 ((sig >> 12) & 0x3),
198 ((sig >> 8) & 0xf),
199 ((sig >> 4) & 0xf),
200 ((sig & 0xf)));
201 pr_debug(" Processor Flags 0x%x\n", pf);
202 pr_debug(" Checksum 0x%x\n", cksum);
203
204 if (mc_header->rev < uci->rev) {
205 if (uci->err == MC_NOTFOUND) {
206 uci->err = MC_IGNORED;
207 uci->cksum = mc_header->rev;
208 } else if (uci->err == MC_IGNORED && uci->cksum < mc_header->rev)
209 uci->cksum = mc_header->rev;
210 } else if (mc_header->rev == uci->rev) {
211 if (uci->err < MC_MARKED) {
212 /* notify the caller of success on this cpu */
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 }
232 }
233 return;
234} 175}
235 176
236static int find_matching_ucodes (void) 177static int microcode_sanity_check(void *mc)
237{ 178{
238 int cursor = 0; 179 microcode_header_t *mc_header = mc;
239 int error = 0; 180 struct extended_sigtable *ext_header = NULL;
240 181 struct extended_signature *ext_sig;
241 while (cursor + MC_HEADER_SIZE < user_buffer_size) { 182 unsigned long total_size, data_size, ext_table_size;
242 microcode_header_t mc_header; 183 int sum, orig_sum, ext_sigcount = 0, i;
243 void *newmc = NULL; 184
244 int i, sum, cpu_num, allocated_flag, total_size, data_size, ext_table_size; 185 total_size = get_totalsize(mc_header);
186 data_size = get_datasize(mc_header);
187 if ((data_size + MC_HEADER_SIZE > total_size)
188 || (data_size < DEFAULT_UCODE_DATASIZE)) {
189 printk(KERN_ERR "microcode: error! "
190 "Bad data size in microcode data file\n");
191 return -EINVAL;
192 }
245 193
246 if (copy_from_user(&mc_header, user_buffer + cursor, MC_HEADER_SIZE)) { 194 if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
247 printk(KERN_ERR "microcode: error! Can not read user data\n"); 195 printk(KERN_ERR "microcode: error! "
248 error = -EFAULT; 196 "Unknown microcode update format\n");
249 goto out; 197 return -EINVAL;
198 }
199 ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
200 if (ext_table_size) {
201 if ((ext_table_size < EXT_HEADER_SIZE)
202 || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
203 printk(KERN_ERR "microcode: error! "
204 "Small exttable size in microcode data file\n");
205 return -EINVAL;
250 } 206 }
251 207 ext_header = mc + MC_HEADER_SIZE + data_size;
252 total_size = get_totalsize(&mc_header); 208 if (ext_table_size != exttable_size(ext_header)) {
253 if ((cursor + total_size > user_buffer_size) || (total_size < DEFAULT_UCODE_TOTALSIZE)) { 209 printk(KERN_ERR "microcode: error! "
254 printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); 210 "Bad exttable size in microcode data file\n");
255 error = -EINVAL; 211 return -EFAULT;
256 goto out;
257 } 212 }
213 ext_sigcount = ext_header->count;
214 }
258 215
259 data_size = get_datasize(&mc_header); 216 /* check extended table checksum */
260 if ((data_size + MC_HEADER_SIZE > total_size) || (data_size < DEFAULT_UCODE_DATASIZE)) { 217 if (ext_table_size) {
261 printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); 218 int ext_table_sum = 0;
262 error = -EINVAL; 219 int * ext_tablep = (int *)ext_header;
263 goto out; 220
221 i = ext_table_size / DWSIZE;
222 while (i--)
223 ext_table_sum += ext_tablep[i];
224 if (ext_table_sum) {
225 printk(KERN_WARNING "microcode: aborting, "
226 "bad extended signature table checksum\n");
227 return -EINVAL;
264 } 228 }
229 }
265 230
266 if (mc_header.ldrver != 1 || mc_header.hdrver != 1) { 231 /* calculate the checksum */
267 printk(KERN_ERR "microcode: error! Unknown microcode update format\n"); 232 orig_sum = 0;
268 error = -EINVAL; 233 i = (MC_HEADER_SIZE + data_size) / DWSIZE;
269 goto out; 234 while (i--)
235 orig_sum += ((int *)mc)[i];
236 if (orig_sum) {
237 printk(KERN_ERR "microcode: aborting, bad checksum\n");
238 return -EINVAL;
239 }
240 if (!ext_table_size)
241 return 0;
242 /* check extended signature checksum */
243 for (i = 0; i < ext_sigcount; i++) {
244 ext_sig = (struct extended_signature *)((void *)ext_header
245 + EXT_HEADER_SIZE + EXT_SIGNATURE_SIZE * i);
246 sum = orig_sum
247 - (mc_header->sig + mc_header->pf + mc_header->cksum)
248 + (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
249 if (sum) {
250 printk(KERN_ERR "microcode: aborting, bad checksum\n");
251 return -EINVAL;
270 } 252 }
253 }
254 return 0;
255}
271 256
272 for_each_online_cpu(cpu_num) { 257/*
273 struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; 258 * return 0 - no update found
274 259 * return 1 - found update
275 if (sigmatch(mc_header.sig, uci->sig, mc_header.pf, uci->orig_pf)) 260 * return < 0 - error
276 mark_microcode_update(cpu_num, &mc_header, mc_header.sig, mc_header.pf, mc_header.cksum); 261 */
277 } 262static int get_maching_microcode(void *mc, int cpu)
263{
264 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
265 microcode_header_t *mc_header = mc;
266 struct extended_sigtable *ext_header;
267 unsigned long total_size = get_totalsize(mc_header);
268 int ext_sigcount, i;
269 struct extended_signature *ext_sig;
270 void *new_mc;
271
272 if (microcode_update_match(cpu, mc_header,
273 mc_header->sig, mc_header->pf))
274 goto find;
275
276 if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
277 return 0;
278
279 ext_header = (struct extended_sigtable *)(mc +
280 get_datasize(mc_header) + MC_HEADER_SIZE);
281 ext_sigcount = ext_header->count;
282 ext_sig = (struct extended_signature *)((void *)ext_header
283 + EXT_HEADER_SIZE);
284 for (i = 0; i < ext_sigcount; i++) {
285 if (microcode_update_match(cpu, mc_header,
286 ext_sig->sig, ext_sig->pf))
287 goto find;
288 ext_sig++;
289 }
290 return 0;
291find:
292 pr_debug("microcode: CPU %d found a matching microcode update with"
293 " version 0x%x (current=0x%x)\n", cpu, mc_header->rev,uci->rev);
294 new_mc = vmalloc(total_size);
295 if (!new_mc) {
296 printk(KERN_ERR "microcode: error! Can not allocate memory\n");
297 return -ENOMEM;
298 }
278 299
279 ext_table_size = total_size - (MC_HEADER_SIZE + data_size); 300 /* free previous update file */
280 if (ext_table_size) { 301 vfree(uci->mc);
281 struct extended_sigtable ext_header;
282 struct extended_signature ext_sig;
283 int ext_sigcount;
284 302
285 if ((ext_table_size < EXT_HEADER_SIZE) 303 memcpy(new_mc, mc, total_size);
286 || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) { 304 uci->mc = new_mc;
287 printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); 305 return 1;
288 error = -EINVAL;
289 goto out;
290 }
291 if (copy_from_user(&ext_header, user_buffer + cursor
292 + MC_HEADER_SIZE + data_size, EXT_HEADER_SIZE)) {
293 printk(KERN_ERR "microcode: error! Can not read user data\n");
294 error = -EFAULT;
295 goto out;
296 }
297 if (ext_table_size != exttable_size(&ext_header)) {
298 printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
299 error = -EFAULT;
300 goto out;
301 }
302
303 ext_sigcount = ext_header.count;
304
305 for (i = 0; i < ext_sigcount; i++) {
306 if (copy_from_user(&ext_sig, user_buffer + cursor + MC_HEADER_SIZE + data_size + EXT_HEADER_SIZE
307 + EXT_SIGNATURE_SIZE * i, EXT_SIGNATURE_SIZE)) {
308 printk(KERN_ERR "microcode: error! Can not read user data\n");
309 error = -EFAULT;
310 goto out;
311 }
312 for_each_online_cpu(cpu_num) {
313 struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
314
315 if (sigmatch(ext_sig.sig, uci->sig, ext_sig.pf, uci->orig_pf)) {
316 mark_microcode_update(cpu_num, &mc_header, ext_sig.sig, ext_sig.pf, ext_sig.cksum);
317 }
318 }
319 }
320 }
321 /* now check if any cpu has matched */
322 allocated_flag = 0;
323 sum = 0;
324 for_each_online_cpu(cpu_num) {
325 if (ucode_cpu_info[cpu_num].err == MC_MARKED) {
326 struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
327 if (!allocated_flag) {
328 allocated_flag = 1;
329 newmc = vmalloc(total_size);
330 if (!newmc) {
331 printk(KERN_ERR "microcode: error! Can not allocate memory\n");
332 error = -ENOMEM;
333 goto out;
334 }
335 if (copy_from_user(newmc + MC_HEADER_SIZE,
336 user_buffer + cursor + MC_HEADER_SIZE,
337 total_size - MC_HEADER_SIZE)) {
338 printk(KERN_ERR "microcode: error! Can not read user data\n");
339 vfree(newmc);
340 error = -EFAULT;
341 goto out;
342 }
343 memcpy(newmc, &mc_header, MC_HEADER_SIZE);
344 /* check extended table checksum */
345 if (ext_table_size) {
346 int ext_table_sum = 0;
347 int * ext_tablep = (((void *) newmc) + MC_HEADER_SIZE + data_size);
348 i = ext_table_size / DWSIZE;
349 while (i--) ext_table_sum += ext_tablep[i];
350 if (ext_table_sum) {
351 printk(KERN_WARNING "microcode: aborting, bad extended signature table checksum\n");
352 vfree(newmc);
353 error = -EINVAL;
354 goto out;
355 }
356 }
357
358 /* calculate the checksum */
359 i = (MC_HEADER_SIZE + data_size) / DWSIZE;
360 while (i--) sum += ((int *)newmc)[i];
361 sum -= (mc_header.sig + mc_header.pf + mc_header.cksum);
362 }
363 ucode_cpu_info[cpu_num].mc = newmc;
364 ucode_cpu_info[cpu_num].err = MC_ALLOCATED; /* mc updated */
365 if (sum + uci->sig + uci->pf + uci->cksum != 0) {
366 printk(KERN_ERR "microcode: CPU%d aborting, bad checksum\n", cpu_num);
367 error = -EINVAL;
368 goto out;
369 }
370 }
371 }
372 cursor += total_size; /* goto the next update patch */
373 } /* end of while */
374out:
375 return error;
376} 306}
377 307
378static void do_update_one (void * unused) 308static void apply_microcode(int cpu)
379{ 309{
380 unsigned long flags; 310 unsigned long flags;
381 unsigned int val[2]; 311 unsigned int val[2];
382 int cpu_num = smp_processor_id(); 312 int cpu_num = raw_smp_processor_id();
383 struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; 313 struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
384 314
385 if (uci->mc == NULL) { 315 /* We should bind the task to the CPU */
386 if (verbose) { 316 BUG_ON(cpu_num != cpu);
387 if (uci->err == MC_SUCCESS) 317
388 printk(KERN_INFO "microcode: CPU%d already at revision 0x%x\n", 318 if (uci->mc == NULL)
389 cpu_num, uci->rev);
390 else
391 printk(KERN_INFO "microcode: No new microcode data for CPU%d\n", cpu_num);
392 }
393 return; 319 return;
394 }
395 320
396 /* serialize access to the physical write to MSR 0x79 */ 321 /* serialize access to the physical write to MSR 0x79 */
397 spin_lock_irqsave(&microcode_update_lock, flags); 322 spin_lock_irqsave(&microcode_update_lock, flags);
@@ -408,54 +333,98 @@ static void do_update_one (void * unused)
408 /* get the current revision from MSR 0x8B */ 333 /* get the current revision from MSR 0x8B */
409 rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); 334 rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
410 335
411 /* notify the caller of success on this cpu */
412 uci->err = MC_SUCCESS;
413 spin_unlock_irqrestore(&microcode_update_lock, flags); 336 spin_unlock_irqrestore(&microcode_update_lock, flags);
414 printk(KERN_INFO "microcode: CPU%d updated from revision " 337 if (val[1] != uci->mc->hdr.rev) {
338 printk(KERN_ERR "microcode: CPU%d updated from revision "
339 "0x%x to 0x%x failed\n", cpu_num, uci->rev, val[1]);
340 return;
341 }
342 pr_debug("microcode: CPU%d updated from revision "
415 "0x%x to 0x%x, date = %08x \n", 343 "0x%x to 0x%x, date = %08x \n",
416 cpu_num, uci->rev, val[1], uci->mc->hdr.date); 344 cpu_num, uci->rev, val[1], uci->mc->hdr.date);
417 return; 345 uci->rev = val[1];
418} 346}
419 347
420static int do_microcode_update (void) 348#ifdef CONFIG_MICROCODE_OLD_INTERFACE
421{ 349static void __user *user_buffer; /* user area microcode data buffer */
422 int i, error; 350static unsigned int user_buffer_size; /* it's size */
423 351
424 if (on_each_cpu(collect_cpu_info, NULL, 1, 1) != 0) { 352static long get_next_ucode(void **mc, long offset)
425 printk(KERN_ERR "microcode: Error! Could not run on all processors\n"); 353{
426 error = -EIO; 354 microcode_header_t mc_header;
427 goto out; 355 unsigned long total_size;
356
357 /* No more data */
358 if (offset >= user_buffer_size)
359 return 0;
360 if (copy_from_user(&mc_header, user_buffer + offset, MC_HEADER_SIZE)) {
361 printk(KERN_ERR "microcode: error! Can not read user data\n");
362 return -EFAULT;
428 } 363 }
429 364 total_size = get_totalsize(&mc_header);
430 if ((error = find_matching_ucodes())) { 365 if ((offset + total_size > user_buffer_size)
431 printk(KERN_ERR "microcode: Error in the microcode data\n"); 366 || (total_size < DEFAULT_UCODE_TOTALSIZE)) {
432 goto out_free; 367 printk(KERN_ERR "microcode: error! Bad total size in microcode "
368 "data file\n");
369 return -EINVAL;
433 } 370 }
434 371 *mc = vmalloc(total_size);
435 if (on_each_cpu(do_update_one, NULL, 1, 1) != 0) { 372 if (!*mc)
436 printk(KERN_ERR "microcode: Error! Could not run on all processors\n"); 373 return -ENOMEM;
437 error = -EIO; 374 if (copy_from_user(*mc, user_buffer + offset, total_size)) {
375 printk(KERN_ERR "microcode: error! Can not read user data\n");
376 vfree(*mc);
377 return -EFAULT;
438 } 378 }
379 return offset + total_size;
380}
439 381
440out_free: 382static int do_microcode_update (void)
441 for_each_online_cpu(i) { 383{
442 if (ucode_cpu_info[i].mc) { 384 long cursor = 0;
443 int j; 385 int error = 0;
444 void *tmp = ucode_cpu_info[i].mc; 386 void * new_mc;
445 vfree(tmp); 387 int cpu;
446 for_each_online_cpu(j) { 388 cpumask_t old;
447 if (ucode_cpu_info[j].mc == tmp) 389
448 ucode_cpu_info[j].mc = NULL; 390 old = current->cpus_allowed;
449 } 391
392 while ((cursor = get_next_ucode(&new_mc, cursor)) > 0) {
393 error = microcode_sanity_check(new_mc);
394 if (error)
395 goto out;
396 /*
397 * It's possible the data file has multiple matching ucode,
398 * lets keep searching till the latest version
399 */
400 for_each_online_cpu(cpu) {
401 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
402
403 if (!uci->valid)
404 continue;
405 set_cpus_allowed(current, cpumask_of_cpu(cpu));
406 error = get_maching_microcode(new_mc, cpu);
407 if (error < 0)
408 goto out;
409 if (error == 1)
410 apply_microcode(cpu);
450 } 411 }
451 if (ucode_cpu_info[i].err == MC_IGNORED && verbose) 412 vfree(new_mc);
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);
454 } 413 }
455out: 414out:
415 if (cursor > 0)
416 vfree(new_mc);
417 if (cursor < 0)
418 error = cursor;
419 set_cpus_allowed(current, old);
456 return error; 420 return error;
457} 421}
458 422
423static int microcode_open (struct inode *unused1, struct file *unused2)
424{
425 return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
426}
427
459static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos) 428static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos)
460{ 429{
461 ssize_t ret; 430 ssize_t ret;
@@ -470,6 +439,7 @@ static ssize_t microcode_write (struct file *file, const char __user *buf, size_
470 return -EINVAL; 439 return -EINVAL;
471 } 440 }
472 441
442 lock_cpu_hotplug();
473 mutex_lock(&microcode_mutex); 443 mutex_lock(&microcode_mutex);
474 444
475 user_buffer = (void __user *) buf; 445 user_buffer = (void __user *) buf;
@@ -480,6 +450,7 @@ static ssize_t microcode_write (struct file *file, const char __user *buf, size_
480 ret = (ssize_t)len; 450 ret = (ssize_t)len;
481 451
482 mutex_unlock(&microcode_mutex); 452 mutex_unlock(&microcode_mutex);
453 unlock_cpu_hotplug();
483 454
484 return ret; 455 return ret;
485} 456}
@@ -496,7 +467,7 @@ static struct miscdevice microcode_dev = {
496 .fops = &microcode_fops, 467 .fops = &microcode_fops,
497}; 468};
498 469
499static int __init microcode_init (void) 470static int __init microcode_dev_init (void)
500{ 471{
501 int error; 472 int error;
502 473
@@ -508,6 +479,28 @@ static int __init microcode_init (void)
508 return error; 479 return error;
509 } 480 }
510 481
482 return 0;
483}
484
485static void __exit microcode_dev_exit (void)
486{
487 misc_deregister(&microcode_dev);
488}
489
490MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
491#else
492#define microcode_dev_init() 0
493#define microcode_dev_exit() do { } while(0)
494#endif
495
496static int __init microcode_init (void)
497{
498 int error;
499
500 error = microcode_dev_init();
501 if (error)
502 return error;
503
511 printk(KERN_INFO 504 printk(KERN_INFO
512 "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@veritas.com>\n"); 505 "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@veritas.com>\n");
513 return 0; 506 return 0;
@@ -515,9 +508,8 @@ static int __init microcode_init (void)
515 508
516static void __exit microcode_exit (void) 509static void __exit microcode_exit (void)
517{ 510{
518 misc_deregister(&microcode_dev); 511 microcode_dev_exit();
519} 512}
520 513
521module_init(microcode_init) 514module_init(microcode_init)
522module_exit(microcode_exit) 515module_exit(microcode_exit)
523MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);