Merge tag 'pwm/for-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry...
[linux-2.6-microblaze.git] / Documentation / translations / zh_CN / core-api / cpu_hotplug.rst
1 .. include:: ../disclaimer-zh_CN.rst
2
3 :Original: Documentation/core-api/cpu_hotplug.rst
4 :翻译:
5
6  司延腾 Yanteng Si <siyanteng@loongson.cn>
7
8 :校译:
9
10  吴想成 Wu XiangCheng <bobwxc@email.cn>
11
12 .. _cn_core_api_cpu_hotplug:
13
14 =================
15 内核中的CPU热拔插
16 =================
17
18 :时间: 2016年12月
19 :作者: Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
20           Rusty Russell <rusty@rustcorp.com.au>,
21           Srivatsa Vaddagiri <vatsa@in.ibm.com>,
22           Ashok Raj <ashok.raj@intel.com>,
23           Joel Schopp <jschopp@austin.ibm.com>
24
25 简介
26 ====
27
28 现代系统架构的演进已经在处理器中引入了先进的错误报告和纠正能力。有一些OEM也支
29 持可热拔插的NUMA(Non Uniform Memory Access,非统一内存访问)硬件,其中物理
30 节点的插入和移除需要支持CPU热插拔。
31
32 这样的进步要求内核可用的CPU被移除,要么是出于配置的原因,要么是出于RAS的目的,
33 以保持一个不需要的CPU不在系统执行路径。因此需要在Linux内核中支持CPU热拔插。
34
35 CPU热拔插支持的一个更新颖的用途是它在SMP的暂停恢复支持中的应用。双核和超线程支
36 持使得即使是笔记本电脑也能运行不支持这些方法的SMP内核。
37
38
39 命令行开关
40 ==========
41
42 ``maxcpus=n``
43   限制启动时的CPU为 *n* 个。例如,如果你有四个CPU,使用 ``maxcpus=2`` 将只能启
44   动两个。你可以选择稍后让其他CPU上线。
45
46 ``nr_cpus=n``
47   限制内核将支持的CPU总量。如果这里提供的数量低于实际可用的CPU数量,那么其他CPU
48   以后就不能上线了。
49
50 ``additional_cpus=n``
51   使用它来限制可热插拔的CPU。该选项设置
52   ``cpu_possible_mask = cpu_present_mask + additional_cpus``
53
54   这个选项只限于IA64架构。
55
56 ``possible_cpus=n``
57   这个选项设置 ``cpu_possible_mask`` 中的 ``possible_cpus`` 位。
58
59   这个选项只限于X86和S390架构。
60
61 ``cpu0_hotplug``
62   允许关闭CPU0。
63
64   这个选项只限于X86架构。
65
66 CPU位图
67 =======
68
69 ``cpu_possible_mask``
70   系统中可能可用CPU的位图。这是用来为per_cpu变量分配一些启动时的内存,这些变量
71   不会随着CPU的可用或移除而增加/减少。一旦在启动时的发现阶段被设置,该映射就是静态
72   的,也就是说,任何时候都不会增加或删除任何位。根据你的系统需求提前准确地调整它
73   可以节省一些启动时的内存。
74
75 ``cpu_online_mask``
76   当前在线的所有CPU的位图。在一个CPU可用于内核调度并准备接收设备的中断后,它被
77   设置在 ``__cpu_up()`` 中。当使用 ``__cpu_disable()`` 关闭一个CPU时,它被清
78   空,在此之前,所有的操作系统服务包括中断都被迁移到另一个目标CPU。
79
80 ``cpu_present_mask``
81   系统中当前存在的CPU的位图。它们并非全部在线。当物理热拔插被相关的子系统
82   (如ACPI)处理时,可以改变和添加新的位或从位图中删除,这取决于事件是
83   hot-add/hot-remove。目前还没有定死规定。典型的用法是在启动时启动拓扑结构,这时
84   热插拔被禁用。
85
86 你真的不需要操作任何系统的CPU映射。在大多数情况下,它们应该是只读的。当设置每个
87 CPU资源时,几乎总是使用 ``cpu_possible_mask`` 或 ``for_each_possible_cpu()``
88 来进行迭代。宏 ``for_each_cpu()`` 可以用来迭代一个自定义的CPU掩码。
89
90 不要使用 ``cpumask_t`` 以外的任何东西来表示CPU的位图。
91
92
93 使用CPU热拔插
94 =============
95
96 内核选项 *CONFIG_HOTPLUG_CPU* 需要被启用。它目前可用于多种架构,包括ARM、MIPS、
97 PowerPC和X86。配置是通过sysfs接口完成的::
98
99  $ ls -lh /sys/devices/system/cpu
100  total 0
101  drwxr-xr-x  9 root root    0 Dec 21 16:33 cpu0
102  drwxr-xr-x  9 root root    0 Dec 21 16:33 cpu1
103  drwxr-xr-x  9 root root    0 Dec 21 16:33 cpu2
104  drwxr-xr-x  9 root root    0 Dec 21 16:33 cpu3
105  drwxr-xr-x  9 root root    0 Dec 21 16:33 cpu4
106  drwxr-xr-x  9 root root    0 Dec 21 16:33 cpu5
107  drwxr-xr-x  9 root root    0 Dec 21 16:33 cpu6
108  drwxr-xr-x  9 root root    0 Dec 21 16:33 cpu7
109  drwxr-xr-x  2 root root    0 Dec 21 16:33 hotplug
110  -r--r--r--  1 root root 4.0K Dec 21 16:33 offline
111  -r--r--r--  1 root root 4.0K Dec 21 16:33 online
112  -r--r--r--  1 root root 4.0K Dec 21 16:33 possible
113  -r--r--r--  1 root root 4.0K Dec 21 16:33 present
114
115 文件 *offline* 、 *online* 、*possible* 、*present* 代表CPU掩码。每个CPU文件
116 夹包含一个 *online* 文件,控制逻辑上的开(1)和关(0)状态。要在逻辑上关闭CPU4::
117
118  $ echo 0 > /sys/devices/system/cpu/cpu4/online
119   smpboot: CPU 4 is now offline
120
121 一旦CPU被关闭,它将从 */proc/interrupts* 、*/proc/cpuinfo* 中被删除,也不应该
122 被 *top* 命令显示出来。要让CPU4重新上线::
123
124  $ echo 1 > /sys/devices/system/cpu/cpu4/online
125  smpboot: Booting Node 0 Processor 4 APIC 0x1
126
127 CPU又可以使用了。这应该对所有的CPU都有效。CPU0通常比较特殊,被排除在CPU热拔插之外。
128 在X86上,内核选项 *CONFIG_BOOTPARAM_HOTPLUG_CPU0* 必须被启用,以便能够关闭CPU0。
129 或者,可以使用内核命令选项 *cpu0_hotplug* 。CPU0的一些已知的依赖性:
130
131 * 从休眠/暂停中恢复。如果CPU0处于离线状态,休眠/暂停将失败。
132 * PIC中断。如果检测到PIC中断,CPU0就不能被移除。
133
134 如果你发现CPU0上有任何依赖性,请告知Fenghua Yu <fenghua.yu@intel.com>。
135
136 CPU的热拔插协作
137 ===============
138
139 下线情况
140 --------
141
142 一旦CPU被逻辑关闭,注册的热插拔状态的清除回调将被调用,从 ``CPUHP_ONLINE`` 开始,在
143 ``CPUHP_OFFLINE`` 状态结束。这包括:
144
145 * 如果任务因暂停操作而被冻结,那么 *cpuhp_tasks_frozen* 将被设置为true。
146
147 * 所有进程都会从这个将要离线的CPU迁移到新的CPU上。新的CPU是从每个进程的当前cpuset中
148   选择的,它可能是所有在线CPU的一个子集。
149
150 * 所有针对这个CPU的中断都被迁移到新的CPU上。
151
152 * 计时器也会被迁移到新的CPU上。
153
154 * 一旦所有的服务被迁移,内核会调用一个特定的例程 ``__cpu_disable()`` 来进行特定的清
155   理。
156
157 使用热插拔API
158 -------------
159
160 一旦一个CPU下线或上线,就有可能收到通知。这对某些需要根据可用CPU数量执行某种设置或清
161 理功能的驱动程序来说可能很重要::
162
163   #include <linux/cpuhotplug.h>
164
165   ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "X/Y:online",
166                           Y_online, Y_prepare_down);
167
168 *X* 是子系统, *Y* 是特定的驱动程序。 *Y_online* 回调将在所有在线CPU的注册过程中被调用。
169 如果在线回调期间发生错误, *Y_prepare_down*  回调将在所有之前调用过在线回调的CPU上调
170 用。注册完成后,一旦有CPU上线, *Y_online* 回调将被调用,当CPU关闭时, *Y_prepare_down*
171 将被调用。所有之前在 *Y_online* 中分配的资源都应该在 *Y_prepare_down* 中释放。如果在
172 注册过程中发生错误,返回值 *ret* 为负值。否则会返回一个正值,其中包含动态分配状态
173 ( *CPUHP_AP_ONLINE_DYN* )的分配热拔插。对于预定义的状态,它将返回0。
174
175 该回调可以通过调用 ``cpuhp_remove_state()`` 来删除。如果是动态分配的状态
176 ( *CPUHP_AP_ONLINE_DYN* ),则使用返回的状态。在移除热插拔状态的过程中,将调用拆解回调。
177
178 多个实例
179 ~~~~~~~~
180
181 如果一个驱动程序有多个实例,并且每个实例都需要独立执行回调,那么很可能应该使用
182 ``multi-state`` 。首先需要注册一个多状态的状态::
183
184   ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "X/Y:online,
185                                 Y_online, Y_prepare_down);
186   Y_hp_online = ret;
187
188 ``cpuhp_setup_state_multi()`` 的行为与 ``cpuhp_setup_state()`` 类似,只是它
189 为多状态准备了回调,但不调用回调。这是一个一次性的设置。
190 一旦分配了一个新的实例,你需要注册这个新实例::
191
192   ret = cpuhp_state_add_instance(Y_hp_online, &d->node);
193
194 这个函数将把这个实例添加到你先前分配的 ``Y_hp_online`` 状态,并在所有在线的
195 CPU上调用先前注册的回调( ``Y_online`` )。 *node* 元素是你的每个实例数据结构
196 中的一个 ``struct hlist_node`` 成员。
197
198 在移除该实例时::
199
200   cpuhp_state_remove_instance(Y_hp_online, &d->node)
201
202 应该被调用,这将在所有在线CPU上调用拆分回调。
203
204 手动设置
205 ~~~~~~~~
206
207 通常情况下,在注册或移除状态时调用setup和teamdown回调是很方便的,因为通常在CPU上线
208 (下线)和驱动的初始设置(关闭)时需要执行该操作。然而,每个注册和删除功能也有一个
209 _nocalls的后缀,如果不希望调用回调,则不调用所提供的回调。在手动设置(或关闭)期间,
210 应该使用 ``get_online_cpus()`` 和 ``put_online_cpus()`` 函数来抑制CPU热插拔操作。
211
212
213 事件的顺序
214 ----------
215
216 热插拔状态被定义在 ``include/linux/cpuhotplug.h``:
217
218 * ``CPUHP_OFFLINE`` ... ``CPUHP_AP_OFFLINE`` 状态是在CPU启动前调用的。
219
220 * ``CPUHP_AP_OFFLINE`` ... ``CPUHP_AP_ONLINE`` 状态是在CPU被启动后被调用的。
221   中断是关闭的,调度程序还没有在这个CPU上活动。从 ``CPUHP_AP_OFFLINE`` 开始,
222   回调被调用到目标CPU上。
223
224 * ``CPUHP_AP_ONLINE_DYN`` 和 ``CPUHP_AP_ONLINE_DYN_END`` 之间的状态被保留
225   给动态分配。
226
227 * 这些状态在CPU关闭时以相反的顺序调用,从 ``CPUHP_ONLINE`` 开始,在 ``CPUHP_OFFLINE``
228   停止。这里的回调是在将被关闭的CPU上调用的,直到 ``CPUHP_AP_OFFLINE`` 。
229
230 通过 ``CPUHP_AP_ONLINE_DYN`` 动态分配的状态通常已经足够了。然而,如果在启动或关闭
231 期间需要更早的调用,那么应该获得一个显式状态。如果热拔插事件需要相对于另一个热拔插事
232 件的特定排序,也可能需要一个显式状态。
233
234 测试热拔插状态
235 ==============
236
237 验证自定义状态是否按预期工作的一个方法是关闭一个CPU,然后再把它上线。也可以把CPU放到某
238 些状态(例如 ``CPUHP_AP_ONLINE`` ),然后再回到 ``CPUHP_ONLINE`` 。这将模拟在
239 ``CPUHP_AP_ONLINE`` 之后的一个状态出现错误,从而导致回滚到在线状态。
240
241 所有注册的状态都被列举在 ``/sys/devices/system/cpu/hotplug/states`` ::
242
243  $ tail /sys/devices/system/cpu/hotplug/states
244  138: mm/vmscan:online
245  139: mm/vmstat:online
246  140: lib/percpu_cnt:online
247  141: acpi/cpu-drv:online
248  142: base/cacheinfo:online
249  143: virtio/net:online
250  144: x86/mce:online
251  145: printk:online
252  168: sched:active
253  169: online
254
255 要将CPU4回滚到 ``lib/percpu_cnt:online`` ,再回到在线状态,只需发出::
256
257   $ cat /sys/devices/system/cpu/cpu4/hotplug/state
258   169
259   $ echo 140 > /sys/devices/system/cpu/cpu4/hotplug/target
260   $ cat /sys/devices/system/cpu/cpu4/hotplug/state
261   140
262
263 需要注意的是,状态140的清除回调已经被调用。现在重新上线::
264
265   $ echo 169 > /sys/devices/system/cpu/cpu4/hotplug/target
266   $ cat /sys/devices/system/cpu/cpu4/hotplug/state
267   169
268
269 启用追踪事件后,单个步骤也是可见的::
270
271   #  TASK-PID   CPU#    TIMESTAMP  FUNCTION
272   #     | |       |        |         |
273       bash-394  [001]  22.976: cpuhp_enter: cpu: 0004 target: 140 step: 169 (cpuhp_kick_ap_work)
274    cpuhp/4-31   [004]  22.977: cpuhp_enter: cpu: 0004 target: 140 step: 168 (sched_cpu_deactivate)
275    cpuhp/4-31   [004]  22.990: cpuhp_exit:  cpu: 0004  state: 168 step: 168 ret: 0
276    cpuhp/4-31   [004]  22.991: cpuhp_enter: cpu: 0004 target: 140 step: 144 (mce_cpu_pre_down)
277    cpuhp/4-31   [004]  22.992: cpuhp_exit:  cpu: 0004  state: 144 step: 144 ret: 0
278    cpuhp/4-31   [004]  22.993: cpuhp_multi_enter: cpu: 0004 target: 140 step: 143 (virtnet_cpu_down_prep)
279    cpuhp/4-31   [004]  22.994: cpuhp_exit:  cpu: 0004  state: 143 step: 143 ret: 0
280    cpuhp/4-31   [004]  22.995: cpuhp_enter: cpu: 0004 target: 140 step: 142 (cacheinfo_cpu_pre_down)
281    cpuhp/4-31   [004]  22.996: cpuhp_exit:  cpu: 0004  state: 142 step: 142 ret: 0
282       bash-394  [001]  22.997: cpuhp_exit:  cpu: 0004  state: 140 step: 169 ret: 0
283       bash-394  [005]  95.540: cpuhp_enter: cpu: 0004 target: 169 step: 140 (cpuhp_kick_ap_work)
284    cpuhp/4-31   [004]  95.541: cpuhp_enter: cpu: 0004 target: 169 step: 141 (acpi_soft_cpu_online)
285    cpuhp/4-31   [004]  95.542: cpuhp_exit:  cpu: 0004  state: 141 step: 141 ret: 0
286    cpuhp/4-31   [004]  95.543: cpuhp_enter: cpu: 0004 target: 169 step: 142 (cacheinfo_cpu_online)
287    cpuhp/4-31   [004]  95.544: cpuhp_exit:  cpu: 0004  state: 142 step: 142 ret: 0
288    cpuhp/4-31   [004]  95.545: cpuhp_multi_enter: cpu: 0004 target: 169 step: 143 (virtnet_cpu_online)
289    cpuhp/4-31   [004]  95.546: cpuhp_exit:  cpu: 0004  state: 143 step: 143 ret: 0
290    cpuhp/4-31   [004]  95.547: cpuhp_enter: cpu: 0004 target: 169 step: 144 (mce_cpu_online)
291    cpuhp/4-31   [004]  95.548: cpuhp_exit:  cpu: 0004  state: 144 step: 144 ret: 0
292    cpuhp/4-31   [004]  95.549: cpuhp_enter: cpu: 0004 target: 169 step: 145 (console_cpu_notify)
293    cpuhp/4-31   [004]  95.550: cpuhp_exit:  cpu: 0004  state: 145 step: 145 ret: 0
294    cpuhp/4-31   [004]  95.551: cpuhp_enter: cpu: 0004 target: 169 step: 168 (sched_cpu_activate)
295    cpuhp/4-31   [004]  95.552: cpuhp_exit:  cpu: 0004  state: 168 step: 168 ret: 0
296       bash-394  [005]  95.553: cpuhp_exit:  cpu: 0004  state: 169 step: 140 ret: 0
297
298 可以看到,CPU4一直下降到时间戳22.996,然后又上升到95.552。所有被调用的回调,
299 包括它们的返回代码都可以在跟踪中看到。
300
301 架构的要求
302 ==========
303
304 需要具备以下功能和配置:
305
306 ``CONFIG_HOTPLUG_CPU``
307   这个配置项需要在Kconfig中启用
308
309 ``__cpu_up()``
310   调出一个cpu的架构接口
311
312 ``__cpu_disable()``
313   关闭CPU的架构接口,在此程序返回后,内核不能再处理任何中断。这包括定时器的关闭。
314
315 ``__cpu_die()``
316   这实际上是为了确保CPU的死亡。实际上,看看其他架构中实现CPU热拔插的一些示例代
317   码。对于那个特定的架构,处理器被从 ``idle()`` 循环中拿下来。 ``__cpu_die()``
318   通常会等待一些per_cpu状态的设置,以确保处理器的死亡例程被调用来保持活跃。
319
320 用户空间通知
321 ============
322
323 在CPU成功上线或下线后,udev事件被发送。一个udev规则,比如::
324
325   SUBSYSTEM=="cpu", DRIVERS=="processor", DEVPATH=="/devices/system/cpu/*", RUN+="the_hotplug_receiver.sh"
326
327 将接收所有事件。一个像这样的脚本::
328
329   #!/bin/sh
330
331   if [ "${ACTION}" = "offline" ]
332   then
333       echo "CPU ${DEVPATH##*/} offline"
334
335   elif [ "${ACTION}" = "online" ]
336   then
337       echo "CPU ${DEVPATH##*/} online"
338
339   fi
340
341 可以进一步处理该事件。
342
343 内核内联文档参考
344 ================
345
346 该API在以下内核代码中:
347
348 include/linux/cpuhotplug.h