diff options
Diffstat (limited to 'arch/x86/kernel/microcode_core.c')
-rw-r--r-- | arch/x86/kernel/microcode_core.c | 67 |
1 files changed, 34 insertions, 33 deletions
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c index 9e5bcf1e2376..3a04b224d0c0 100644 --- a/arch/x86/kernel/microcode_core.c +++ b/arch/x86/kernel/microcode_core.c | |||
@@ -279,19 +279,18 @@ static struct platform_device *microcode_pdev; | |||
279 | static int reload_for_cpu(int cpu) | 279 | static int reload_for_cpu(int cpu) |
280 | { | 280 | { |
281 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 281 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
282 | enum ucode_state ustate; | ||
282 | int err = 0; | 283 | int err = 0; |
283 | 284 | ||
284 | if (uci->valid) { | 285 | if (!uci->valid) |
285 | enum ucode_state ustate; | 286 | return err; |
286 | |||
287 | ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev); | ||
288 | if (ustate == UCODE_OK) | ||
289 | apply_microcode_on_target(cpu); | ||
290 | else | ||
291 | if (ustate == UCODE_ERROR) | ||
292 | err = -EINVAL; | ||
293 | } | ||
294 | 287 | ||
288 | ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev, true); | ||
289 | if (ustate == UCODE_OK) | ||
290 | apply_microcode_on_target(cpu); | ||
291 | else | ||
292 | if (ustate == UCODE_ERROR) | ||
293 | err = -EINVAL; | ||
295 | return err; | 294 | return err; |
296 | } | 295 | } |
297 | 296 | ||
@@ -373,18 +372,15 @@ static void microcode_fini_cpu(int cpu) | |||
373 | 372 | ||
374 | static enum ucode_state microcode_resume_cpu(int cpu) | 373 | static enum ucode_state microcode_resume_cpu(int cpu) |
375 | { | 374 | { |
376 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
377 | |||
378 | if (!uci->mc) | ||
379 | return UCODE_NFOUND; | ||
380 | |||
381 | pr_debug("CPU%d updated upon resume\n", cpu); | 375 | pr_debug("CPU%d updated upon resume\n", cpu); |
382 | apply_microcode_on_target(cpu); | 376 | |
377 | if (apply_microcode_on_target(cpu)) | ||
378 | return UCODE_ERROR; | ||
383 | 379 | ||
384 | return UCODE_OK; | 380 | return UCODE_OK; |
385 | } | 381 | } |
386 | 382 | ||
387 | static enum ucode_state microcode_init_cpu(int cpu) | 383 | static enum ucode_state microcode_init_cpu(int cpu, bool refresh_fw) |
388 | { | 384 | { |
389 | enum ucode_state ustate; | 385 | enum ucode_state ustate; |
390 | 386 | ||
@@ -395,7 +391,8 @@ static enum ucode_state microcode_init_cpu(int cpu) | |||
395 | if (system_state != SYSTEM_RUNNING) | 391 | if (system_state != SYSTEM_RUNNING) |
396 | return UCODE_NFOUND; | 392 | return UCODE_NFOUND; |
397 | 393 | ||
398 | ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev); | 394 | ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev, |
395 | refresh_fw); | ||
399 | 396 | ||
400 | if (ustate == UCODE_OK) { | 397 | if (ustate == UCODE_OK) { |
401 | pr_debug("CPU%d updated upon init\n", cpu); | 398 | pr_debug("CPU%d updated upon init\n", cpu); |
@@ -408,14 +405,11 @@ static enum ucode_state microcode_init_cpu(int cpu) | |||
408 | static enum ucode_state microcode_update_cpu(int cpu) | 405 | static enum ucode_state microcode_update_cpu(int cpu) |
409 | { | 406 | { |
410 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 407 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
411 | enum ucode_state ustate; | ||
412 | 408 | ||
413 | if (uci->valid) | 409 | if (uci->valid) |
414 | ustate = microcode_resume_cpu(cpu); | 410 | return microcode_resume_cpu(cpu); |
415 | else | ||
416 | ustate = microcode_init_cpu(cpu); | ||
417 | 411 | ||
418 | return ustate; | 412 | return microcode_init_cpu(cpu, false); |
419 | } | 413 | } |
420 | 414 | ||
421 | static int mc_device_add(struct device *dev, struct subsys_interface *sif) | 415 | static int mc_device_add(struct device *dev, struct subsys_interface *sif) |
@@ -431,7 +425,7 @@ static int mc_device_add(struct device *dev, struct subsys_interface *sif) | |||
431 | if (err) | 425 | if (err) |
432 | return err; | 426 | return err; |
433 | 427 | ||
434 | if (microcode_init_cpu(cpu) == UCODE_ERROR) | 428 | if (microcode_init_cpu(cpu, true) == UCODE_ERROR) |
435 | return -EINVAL; | 429 | return -EINVAL; |
436 | 430 | ||
437 | return err; | 431 | return err; |
@@ -480,34 +474,41 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) | |||
480 | struct device *dev; | 474 | struct device *dev; |
481 | 475 | ||
482 | dev = get_cpu_device(cpu); | 476 | dev = get_cpu_device(cpu); |
483 | switch (action) { | 477 | |
478 | switch (action & ~CPU_TASKS_FROZEN) { | ||
484 | case CPU_ONLINE: | 479 | case CPU_ONLINE: |
485 | case CPU_ONLINE_FROZEN: | ||
486 | microcode_update_cpu(cpu); | 480 | microcode_update_cpu(cpu); |
487 | case CPU_DOWN_FAILED: | ||
488 | case CPU_DOWN_FAILED_FROZEN: | ||
489 | pr_debug("CPU%d added\n", cpu); | 481 | pr_debug("CPU%d added\n", cpu); |
482 | /* | ||
483 | * "break" is missing on purpose here because we want to fall | ||
484 | * through in order to create the sysfs group. | ||
485 | */ | ||
486 | |||
487 | case CPU_DOWN_FAILED: | ||
490 | if (sysfs_create_group(&dev->kobj, &mc_attr_group)) | 488 | if (sysfs_create_group(&dev->kobj, &mc_attr_group)) |
491 | pr_err("Failed to create group for CPU%d\n", cpu); | 489 | pr_err("Failed to create group for CPU%d\n", cpu); |
492 | break; | 490 | break; |
491 | |||
493 | case CPU_DOWN_PREPARE: | 492 | case CPU_DOWN_PREPARE: |
494 | case CPU_DOWN_PREPARE_FROZEN: | ||
495 | /* Suspend is in progress, only remove the interface */ | 493 | /* Suspend is in progress, only remove the interface */ |
496 | sysfs_remove_group(&dev->kobj, &mc_attr_group); | 494 | sysfs_remove_group(&dev->kobj, &mc_attr_group); |
497 | pr_debug("CPU%d removed\n", cpu); | 495 | pr_debug("CPU%d removed\n", cpu); |
498 | break; | 496 | break; |
499 | 497 | ||
500 | /* | 498 | /* |
499 | * case CPU_DEAD: | ||
500 | * | ||
501 | * When a CPU goes offline, don't free up or invalidate the copy of | 501 | * When a CPU goes offline, don't free up or invalidate the copy of |
502 | * the microcode in kernel memory, so that we can reuse it when the | 502 | * the microcode in kernel memory, so that we can reuse it when the |
503 | * CPU comes back online without unnecessarily requesting the userspace | 503 | * CPU comes back online without unnecessarily requesting the userspace |
504 | * for it again. | 504 | * for it again. |
505 | */ | 505 | */ |
506 | case CPU_UP_CANCELED_FROZEN: | ||
507 | /* The CPU refused to come up during a system resume */ | ||
508 | microcode_fini_cpu(cpu); | ||
509 | break; | ||
510 | } | 506 | } |
507 | |||
508 | /* The CPU refused to come up during a system resume */ | ||
509 | if (action == CPU_UP_CANCELED_FROZEN) | ||
510 | microcode_fini_cpu(cpu); | ||
511 | |||
511 | return NOTIFY_OK; | 512 | return NOTIFY_OK; |
512 | } | 513 | } |
513 | 514 | ||