/root/src/xen/xen/common/cpu.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include <xen/cpumask.h> |
2 | | #include <xen/cpu.h> |
3 | | #include <xen/event.h> |
4 | | #include <xen/init.h> |
5 | | #include <xen/sched.h> |
6 | | #include <xen/stop_machine.h> |
7 | | |
8 | | unsigned int __read_mostly nr_cpu_ids = NR_CPUS; |
9 | | #ifndef nr_cpumask_bits |
10 | | unsigned int __read_mostly nr_cpumask_bits |
11 | | = BITS_TO_LONGS(NR_CPUS) * BITS_PER_LONG; |
12 | | #endif |
13 | | |
14 | | /* |
15 | | * cpu_bit_bitmap[] is a special, "compressed" data structure that |
16 | | * represents all NR_CPUS bits binary values of 1<<nr. |
17 | | * |
18 | | * It is used by cpumask_of() to get a constant address to a CPU |
19 | | * mask value that has a single bit set only. |
20 | | */ |
21 | | |
22 | | /* cpu_bit_bitmap[0] is empty - so we can back into it */ |
23 | | #define MASK_DECLARE_1(x) [x+1][0] = 1UL << (x) |
24 | | #define MASK_DECLARE_2(x) MASK_DECLARE_1(x), MASK_DECLARE_1(x+1) |
25 | | #define MASK_DECLARE_4(x) MASK_DECLARE_2(x), MASK_DECLARE_2(x+2) |
26 | | #define MASK_DECLARE_8(x) MASK_DECLARE_4(x), MASK_DECLARE_4(x+4) |
27 | | |
28 | | const unsigned long cpu_bit_bitmap[BITS_PER_LONG+1][BITS_TO_LONGS(NR_CPUS)] = { |
29 | | |
30 | | MASK_DECLARE_8(0), MASK_DECLARE_8(8), |
31 | | MASK_DECLARE_8(16), MASK_DECLARE_8(24), |
32 | | #if BITS_PER_LONG > 32 |
33 | | MASK_DECLARE_8(32), MASK_DECLARE_8(40), |
34 | | MASK_DECLARE_8(48), MASK_DECLARE_8(56), |
35 | | #endif |
36 | | }; |
37 | | |
38 | | static DEFINE_SPINLOCK(cpu_add_remove_lock); |
39 | | |
40 | | bool_t get_cpu_maps(void) |
41 | 11 | { |
42 | 11 | return spin_trylock_recursive(&cpu_add_remove_lock); |
43 | 11 | } |
44 | | |
45 | | void put_cpu_maps(void) |
46 | 11 | { |
47 | 11 | spin_unlock_recursive(&cpu_add_remove_lock); |
48 | 11 | } |
49 | | |
50 | | bool_t cpu_hotplug_begin(void) |
51 | 11 | { |
52 | 11 | return get_cpu_maps(); |
53 | 11 | } |
54 | | |
55 | | void cpu_hotplug_done(void) |
56 | 11 | { |
57 | 11 | put_cpu_maps(); |
58 | 11 | } |
59 | | |
60 | | static NOTIFIER_HEAD(cpu_chain); |
61 | | |
62 | | void __init register_cpu_notifier(struct notifier_block *nb) |
63 | 18 | { |
64 | 18 | if ( !spin_trylock(&cpu_add_remove_lock) ) |
65 | 0 | BUG(); /* Should never fail as we are called only during boot. */ |
66 | 18 | notifier_chain_register(&cpu_chain, nb); |
67 | 18 | spin_unlock(&cpu_add_remove_lock); |
68 | 18 | } |
69 | | |
70 | | static int take_cpu_down(void *unused) |
71 | 0 | { |
72 | 0 | void *hcpu = (void *)(long)smp_processor_id(); |
73 | 0 | int notifier_rc = notifier_call_chain(&cpu_chain, CPU_DYING, hcpu, NULL); |
74 | 0 | BUG_ON(notifier_rc != NOTIFY_DONE); |
75 | 0 | __cpu_disable(); |
76 | 0 | return 0; |
77 | 0 | } |
78 | | |
79 | | int cpu_down(unsigned int cpu) |
80 | 0 | { |
81 | 0 | int err, notifier_rc; |
82 | 0 | void *hcpu = (void *)(long)cpu; |
83 | 0 | struct notifier_block *nb = NULL; |
84 | 0 |
|
85 | 0 | if ( !cpu_hotplug_begin() ) |
86 | 0 | return -EBUSY; |
87 | 0 |
|
88 | 0 | if ( (cpu >= nr_cpu_ids) || (cpu == 0) || !cpu_online(cpu) ) |
89 | 0 | { |
90 | 0 | cpu_hotplug_done(); |
91 | 0 | return -EINVAL; |
92 | 0 | } |
93 | 0 |
|
94 | 0 | notifier_rc = notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, hcpu, &nb); |
95 | 0 | if ( notifier_rc != NOTIFY_DONE ) |
96 | 0 | { |
97 | 0 | err = notifier_to_errno(notifier_rc); |
98 | 0 | goto fail; |
99 | 0 | } |
100 | 0 |
|
101 | 0 | if ( (err = stop_machine_run(take_cpu_down, NULL, cpu)) < 0 ) |
102 | 0 | goto fail; |
103 | 0 |
|
104 | 0 | __cpu_die(cpu); |
105 | 0 | BUG_ON(cpu_online(cpu)); |
106 | 0 |
|
107 | 0 | notifier_rc = notifier_call_chain(&cpu_chain, CPU_DEAD, hcpu, NULL); |
108 | 0 | BUG_ON(notifier_rc != NOTIFY_DONE); |
109 | 0 |
|
110 | 0 | send_global_virq(VIRQ_PCPU_STATE); |
111 | 0 | cpu_hotplug_done(); |
112 | 0 | return 0; |
113 | 0 |
|
114 | 0 | fail: |
115 | 0 | notifier_rc = notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, hcpu, &nb); |
116 | 0 | BUG_ON(notifier_rc != NOTIFY_DONE); |
117 | 0 | cpu_hotplug_done(); |
118 | 0 | return err; |
119 | 0 | } |
120 | | |
121 | | int cpu_up(unsigned int cpu) |
122 | 11 | { |
123 | 11 | int notifier_rc, err = 0; |
124 | 11 | void *hcpu = (void *)(long)cpu; |
125 | 11 | struct notifier_block *nb = NULL; |
126 | 11 | |
127 | 11 | if ( !cpu_hotplug_begin() ) |
128 | 0 | return -EBUSY; |
129 | 11 | |
130 | 11 | if ( (cpu >= nr_cpu_ids) || cpu_online(cpu) || !cpu_present(cpu) ) |
131 | 0 | { |
132 | 0 | cpu_hotplug_done(); |
133 | 0 | return -EINVAL; |
134 | 0 | } |
135 | 11 | |
136 | 11 | notifier_rc = notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu, &nb); |
137 | 11 | if ( notifier_rc != NOTIFY_DONE ) |
138 | 0 | { |
139 | 0 | err = notifier_to_errno(notifier_rc); |
140 | 0 | goto fail; |
141 | 0 | } |
142 | 11 | |
143 | 11 | err = __cpu_up(cpu); |
144 | 11 | if ( err < 0 ) |
145 | 0 | goto fail; |
146 | 11 | |
147 | 11 | notifier_rc = notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu, NULL); |
148 | 11 | BUG_ON(notifier_rc != NOTIFY_DONE); |
149 | 11 | |
150 | 11 | send_global_virq(VIRQ_PCPU_STATE); |
151 | 11 | |
152 | 11 | cpu_hotplug_done(); |
153 | 11 | return 0; |
154 | 11 | |
155 | 0 | fail: |
156 | 0 | notifier_rc = notifier_call_chain(&cpu_chain, CPU_UP_CANCELED, hcpu, &nb); |
157 | 0 | BUG_ON(notifier_rc != NOTIFY_DONE); |
158 | 0 | cpu_hotplug_done(); |
159 | 0 | return err; |
160 | 11 | } |
161 | | |
162 | | void notify_cpu_starting(unsigned int cpu) |
163 | 11 | { |
164 | 11 | void *hcpu = (void *)(long)cpu; |
165 | 11 | int notifier_rc = notifier_call_chain( |
166 | 11 | &cpu_chain, CPU_STARTING, hcpu, NULL); |
167 | 11 | BUG_ON(notifier_rc != NOTIFY_DONE); |
168 | 11 | } |
169 | | |
170 | | static cpumask_t frozen_cpus; |
171 | | |
172 | | int disable_nonboot_cpus(void) |
173 | 0 | { |
174 | 0 | int cpu, error = 0; |
175 | 0 |
|
176 | 0 | BUG_ON(smp_processor_id() != 0); |
177 | 0 |
|
178 | 0 | cpumask_clear(&frozen_cpus); |
179 | 0 |
|
180 | 0 | printk("Disabling non-boot CPUs ...\n"); |
181 | 0 |
|
182 | 0 | for_each_online_cpu ( cpu ) |
183 | 0 | { |
184 | 0 | if ( cpu == 0 ) |
185 | 0 | continue; |
186 | 0 |
|
187 | 0 | if ( (error = cpu_down(cpu)) ) |
188 | 0 | { |
189 | 0 | printk("Error taking CPU%d down: %d\n", cpu, error); |
190 | 0 | BUG_ON(error == -EBUSY); |
191 | 0 | break; |
192 | 0 | } |
193 | 0 |
|
194 | 0 | __cpumask_set_cpu(cpu, &frozen_cpus); |
195 | 0 | } |
196 | 0 |
|
197 | 0 | BUG_ON(!error && (num_online_cpus() != 1)); |
198 | 0 | return error; |
199 | 0 | } |
200 | | |
201 | | void enable_nonboot_cpus(void) |
202 | 0 | { |
203 | 0 | int cpu, error; |
204 | 0 |
|
205 | 0 | printk("Enabling non-boot CPUs ...\n"); |
206 | 0 |
|
207 | 0 | for_each_cpu ( cpu, &frozen_cpus ) |
208 | 0 | { |
209 | 0 | if ( (error = cpu_up(cpu)) ) |
210 | 0 | { |
211 | 0 | printk("Error bringing CPU%d up: %d\n", cpu, error); |
212 | 0 | BUG_ON(error == -EBUSY); |
213 | 0 | } |
214 | 0 | } |
215 | 0 |
|
216 | 0 | cpumask_clear(&frozen_cpus); |
217 | 0 | } |