diff options
Diffstat (limited to 'kernel/smp.c')
-rw-r--r-- | kernel/smp.c | 79 |
1 files changed, 32 insertions, 47 deletions
diff --git a/kernel/smp.c b/kernel/smp.c index 36552beed397..3aa642d39c03 100644 --- a/kernel/smp.c +++ b/kernel/smp.c | |||
@@ -33,69 +33,54 @@ static DEFINE_PER_CPU_SHARED_ALIGNED(struct llist_head, call_single_queue); | |||
33 | 33 | ||
34 | static void flush_smp_call_function_queue(bool warn_cpu_offline); | 34 | static void flush_smp_call_function_queue(bool warn_cpu_offline); |
35 | 35 | ||
36 | static int | 36 | int smpcfd_prepare_cpu(unsigned int cpu) |
37 | hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu) | ||
38 | { | 37 | { |
39 | long cpu = (long)hcpu; | ||
40 | struct call_function_data *cfd = &per_cpu(cfd_data, cpu); | 38 | struct call_function_data *cfd = &per_cpu(cfd_data, cpu); |
41 | 39 | ||
42 | switch (action) { | 40 | if (!zalloc_cpumask_var_node(&cfd->cpumask, GFP_KERNEL, |
43 | case CPU_UP_PREPARE: | 41 | cpu_to_node(cpu))) |
44 | case CPU_UP_PREPARE_FROZEN: | 42 | return -ENOMEM; |
45 | if (!zalloc_cpumask_var_node(&cfd->cpumask, GFP_KERNEL, | 43 | cfd->csd = alloc_percpu(struct call_single_data); |
46 | cpu_to_node(cpu))) | 44 | if (!cfd->csd) { |
47 | return notifier_from_errno(-ENOMEM); | ||
48 | cfd->csd = alloc_percpu(struct call_single_data); | ||
49 | if (!cfd->csd) { | ||
50 | free_cpumask_var(cfd->cpumask); | ||
51 | return notifier_from_errno(-ENOMEM); | ||
52 | } | ||
53 | break; | ||
54 | |||
55 | #ifdef CONFIG_HOTPLUG_CPU | ||
56 | case CPU_UP_CANCELED: | ||
57 | case CPU_UP_CANCELED_FROZEN: | ||
58 | /* Fall-through to the CPU_DEAD[_FROZEN] case. */ | ||
59 | |||
60 | case CPU_DEAD: | ||
61 | case CPU_DEAD_FROZEN: | ||
62 | free_cpumask_var(cfd->cpumask); | 45 | free_cpumask_var(cfd->cpumask); |
63 | free_percpu(cfd->csd); | 46 | return -ENOMEM; |
64 | break; | 47 | } |
65 | 48 | ||
66 | case CPU_DYING: | 49 | return 0; |
67 | case CPU_DYING_FROZEN: | 50 | } |
68 | /* | 51 | |
69 | * The IPIs for the smp-call-function callbacks queued by other | 52 | int smpcfd_dead_cpu(unsigned int cpu) |
70 | * CPUs might arrive late, either due to hardware latencies or | 53 | { |
71 | * because this CPU disabled interrupts (inside stop-machine) | 54 | struct call_function_data *cfd = &per_cpu(cfd_data, cpu); |
72 | * before the IPIs were sent. So flush out any pending callbacks | ||
73 | * explicitly (without waiting for the IPIs to arrive), to | ||
74 | * ensure that the outgoing CPU doesn't go offline with work | ||
75 | * still pending. | ||
76 | */ | ||
77 | flush_smp_call_function_queue(false); | ||
78 | break; | ||
79 | #endif | ||
80 | }; | ||
81 | 55 | ||
82 | return NOTIFY_OK; | 56 | free_cpumask_var(cfd->cpumask); |
57 | free_percpu(cfd->csd); | ||
58 | return 0; | ||
83 | } | 59 | } |
84 | 60 | ||
85 | static struct notifier_block hotplug_cfd_notifier = { | 61 | int smpcfd_dying_cpu(unsigned int cpu) |
86 | .notifier_call = hotplug_cfd, | 62 | { |
87 | }; | 63 | /* |
64 | * The IPIs for the smp-call-function callbacks queued by other | ||
65 | * CPUs might arrive late, either due to hardware latencies or | ||
66 | * because this CPU disabled interrupts (inside stop-machine) | ||
67 | * before the IPIs were sent. So flush out any pending callbacks | ||
68 | * explicitly (without waiting for the IPIs to arrive), to | ||
69 | * ensure that the outgoing CPU doesn't go offline with work | ||
70 | * still pending. | ||
71 | */ | ||
72 | flush_smp_call_function_queue(false); | ||
73 | return 0; | ||
74 | } | ||
88 | 75 | ||
89 | void __init call_function_init(void) | 76 | void __init call_function_init(void) |
90 | { | 77 | { |
91 | void *cpu = (void *)(long)smp_processor_id(); | ||
92 | int i; | 78 | int i; |
93 | 79 | ||
94 | for_each_possible_cpu(i) | 80 | for_each_possible_cpu(i) |
95 | init_llist_head(&per_cpu(call_single_queue, i)); | 81 | init_llist_head(&per_cpu(call_single_queue, i)); |
96 | 82 | ||
97 | hotplug_cfd(&hotplug_cfd_notifier, CPU_UP_PREPARE, cpu); | 83 | smpcfd_prepare_cpu(smp_processor_id()); |
98 | register_cpu_notifier(&hotplug_cfd_notifier); | ||
99 | } | 84 | } |
100 | 85 | ||
101 | /* | 86 | /* |