| @@ -21,6 +21,7 @@ · 20 unmodified lines |
| 21 | 21 | #include <linux/suspend.h> |
| 22 | 22 | #include <linux/lockdep.h> |
| 23 | 23 | #include <linux/tick.h> |
| 24 | +#include <linux/irq.h> |
| 24 | 25 | #include <trace/events/power.h> |
| 25 | 26 | |
| 26 | 27 | #include "smpboot.h" |
| @@ -392,13 +393,19 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen) · 365 unmodified lines |
| 392 | 393 | smpboot_park_threads(cpu); |
| 393 | 394 | |
| 394 | 395 | /* |
| 395 | | − * So now all preempt/rcu users must observe !cpu_active(). |
| 396 | + * Prevent irq alloc/free while the dying cpu reorganizes the |
| 397 | + * interrupt affinities. |
| 396 | 398 | */ |
| 399 | + irq_lock_sparse(); |
| 397 | 400 | |
| 401 | + /* |
| 402 | + * So now all preempt/rcu users must observe !cpu_active(). |
| 403 | + */ |
| 398 | 404 | err = __stop_machine(take_cpu_down, &tcd_param, cpumask_of(cpu)); |
| 399 | 405 | if (err) { |
| 400 | 406 | /* CPU didn't die: tell everyone. Can't complain. */ |
| 401 | 407 | cpu_notify_nofail(CPU_DOWN_FAILED | mod, hcpu); |
| 408 | + irq_unlock_sparse(); |
| 402 | 409 | goto out_release; |
| 403 | 410 | } |
| 404 | 411 | BUG_ON(cpu_online(cpu)); |
| @@ -415,6 +422,9 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen) · 10 unmodified lines |
| 415 | 422 | smp_mb(); /* Read from cpu_dead_idle before __cpu_die(). */ |
| 416 | 423 | per_cpu(cpu_dead_idle, cpu) = false; |
| 417 | 424 | |
| 425 | + /* Interrupts are moved away from the dying cpu, reenable alloc/free */ |
| 426 | + irq_unlock_sparse(); |
| 427 | + |
| 418 | 428 | hotplug_cpu__broadcast_tick_pull(cpu); |
| 419 | 429 | /* This actually kills the CPU. */ |
| 420 | 430 | __cpu_die(cpu); |
| @@ -517,8 +527,18 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen) · 96 unmodified lines |
| 517 | 527 | goto out_notify; |
| 518 | 528 | } |
| 519 | 529 | |
| 530 | + /* |
| 531 | + * Some architectures have to walk the irq descriptors to |
| 532 | + * setup the vector space for the cpu which comes online. |
| 533 | + * Prevent irq alloc/free across the bringup. |
| 534 | + */ |
| 535 | + irq_lock_sparse(); |
| 536 | + |
| 520 | 537 | /* Arch-specific enabling code. */ |
| 521 | 538 | ret = __cpu_up(cpu, idle); |
| 539 | + |
| 540 | + irq_unlock_sparse(); |
| 541 | + |
| 522 | 542 | if (ret != 0) |
| 523 | 543 | goto out_notify; |
| 524 | 544 | BUG_ON(!cpu_online(cpu)); |