Re: [PATCH] Documentation: Update CPU hotplug and move it to core-api

From: Jani Nikula
Date: Fri Dec 23 2016 - 03:04:12 EST


On Thu, 22 Dec 2016, Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> wrote:
> The current CPU hotplug is outdated. During the update to what we
> currently have I rewrote it partly and moved to sphinx format.
>
> Cc: Jonathan Corbet <corbet@xxxxxxx>
> Cc: Mauro Carvalho Chehab <mchehab@xxxxxxxxxx>
> Cc: Rusty Russell <rusty@xxxxxxxxxxxxxxx>
> Cc: Srivatsa Vaddagiri <vatsa@xxxxxxxxxx>
> Cc: Ashok Raj <ashok.raj@xxxxxxxxx>
> Cc: Joel Schopp <jschopp@xxxxxxxxxxxxxx>
> Cc: linux-doc@xxxxxxxxxxxxxxx
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx>
> ---
> Documentation/core-api/cpu_hotplug.rst | 372 +++++++++++++++++++++++++++
> Documentation/core-api/index.rst | 1 +
> Documentation/cpu-hotplug.txt | 452 ---------------------------------
> 3 files changed, 373 insertions(+), 452 deletions(-)
> create mode 100644 Documentation/core-api/cpu_hotplug.rst
> delete mode 100644 Documentation/cpu-hotplug.txt
>
> diff --git a/Documentation/core-api/cpu_hotplug.rst b/Documentation/core-api/cpu_hotplug.rst
> new file mode 100644
> index 000000000000..4a50ab7817f7
> --- /dev/null
> +++ b/Documentation/core-api/cpu_hotplug.rst
> @@ -0,0 +1,372 @@
> +=========================
> +CPU hotplug in the Kernel
> +=========================
> +
> +:Date: December, 2016
> +:Author: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx>,
> + Rusty Russell <rusty@xxxxxxxxxxxxxxx>,
> + Srivatsa Vaddagiri <vatsa@xxxxxxxxxx>,
> + Ashok Raj <ashok.raj@xxxxxxxxx>,
> + Joel Schopp <jschopp@xxxxxxxxxxxxxx>

Just a drive-by comment, does that do what you want? You might want to
see if adding one :Author: line per author produces better results.

That said, I think git will do a better job of maintaining both the date
and the authorship.


BR,
Jani.


> +
> +Introduction
> +============
> +
> +Modern advances in system architectures have introduced advanced error
> +reporting and correction capabilities in processors. There are couple OEMS that
> +support NUMA hardware which are hot pluggable as well, where physical node
> +insertion and removal require support for CPU hotplug.
> +
> +Such advances require CPUs available to a kernel to be removed either for
> +provisioning reasons, or for RAS purposes to keep an offending CPU off
> +system execution path. Hence the need for CPU hotplug support in the
> +Linux kernel.
> +
> +A more novel use of CPU-hotplug support is its use today in suspend resume
> +support for SMP. Dual-core and HT support makes even a laptop run SMP kernels
> +which didn't support these methods.
> +
> +
> +Command Line Switches
> +=====================
> +``maxcpus=n``
> + Restrict boot time CPUs to *n*. Say if you have fourV CPUs, using
> + ``maxcpus=2`` will only boot two. You can choose to bring the
> + other CPUs later online.
> +
> +``nr_cpus=n``
> + Restrict the total amount CPUs the kernel will support. If the number
> + supplied here is lower than the number of physically available CPUs than
> + those CPUs can not be brought online later.
> +
> +``additional_cpus=n``
> + Use this to limit hotpluggable CPUs. This option sets
> + ``cpu_possible_mask = cpu_present_mask + additional_cpus``
> +
> + This option is limited to the IA64 architecture.
> +
> +``possible_cpus=n``
> + This option sets ``possible_cpus`` bits in ``cpu_possible_mask``.
> +
> + This option is limited to the X86 and S390 architecture.
> +
> +``cede_offline={"off","on"}``
> + Use this option to disable/enable putting offlined processors to an extended
> + ``H_CEDE`` state on supported pseries platforms. If nothing is specified,
> + ``cede_offline`` is set to "on".
> +
> + This option is limited to the PowerPC architecture.
> +
> +``cpu0_hotplug``
> + Allow to shutdown CPU0.
> +
> + This option is limited to the X86 architecture.
> +
> +CPU maps
> +========
> +
> +``cpu_possible_mask``
> + Bitmap of possible CPUs that can ever be available in the
> + system. This is used to allocate some boot time memory for per_cpu variables
> + that aren't designed to grow/shrink as CPUs are made available or removed.
> + Once set during boot time discovery phase, the map is static, i.e no bits
> + are added or removed anytime. Trimming it accurately for your system needs
> + upfront can save some boot time memory.
> +
> +``cpu_online_mask``
> + Bitmap of all CPUs currently online. Its set in ``__cpu_up()``
> + after a CPU is available for kernel scheduling and ready to receive
> + interrupts from devices. Its cleared when a CPU is brought down using
> + ``__cpu_disable()``, before which all OS services including interrupts are
> + migrated to another target CPU.
> +
> +``cpu_present_mask``
> + Bitmap of CPUs currently present in the system. Not all
> + of them may be online. When physical hotplug is processed by the relevant
> + subsystem (e.g ACPI) can change and new bit either be added or removed
> + from the map depending on the event is hot-add/hot-remove. There are currently
> + no locking rules as of now. Typical usage is to init topology during boot,
> + at which time hotplug is disabled.
> +
> +You really don't need to manipulate any of the system CPU maps. They should
> +be read-only for most use. When setting up per-cpu resources almost always use
> +``cpu_possible_mask`` or ``for_each_possible_cpu()`` to iterate. To macro
> +``for_each_cpu()`` can be used to iterate over a custom CPU mask.
> +
> +Never use anything other than ``cpumask_t`` to represent bitmap of CPUs.
> +
> +
> +Using CPU hotplug
> +=================
> +The kernel option *CONFIG_HOTPLUG_CPU* needs to be enabled. It is currently
> +available on multiple architectures including ARM, MIPS, PowerPC and X86. The
> +configuration is done via the sysfs interface: ::
> +
> + $ ls -lh /sys/devices/system/cpu
> + total 0
> + drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu0
> + drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu1
> + drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu2
> + drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu3
> + drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu4
> + drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu5
> + drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu6
> + drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu7
> + drwxr-xr-x 2 root root 0 Dec 21 16:33 hotplug
> + -r--r--r-- 1 root root 4.0K Dec 21 16:33 offline
> + -r--r--r-- 1 root root 4.0K Dec 21 16:33 online
> + -r--r--r-- 1 root root 4.0K Dec 21 16:33 possible
> + -r--r--r-- 1 root root 4.0K Dec 21 16:33 present
> +
> +The files *offline*, *online*, *possible*, *present* represent the CPU masks.
> +Each CPU folder contains an *online* file which controls the logical on (1) and
> +off (0) state. To logically shutdown CPU4: ::
> +
> + $ echo 0 > /sys/devices/system/cpu/cpu4/online
> + smpboot: CPU 4 is now offline
> +
> +Once the CPU is shutdown, it will be removed from */proc/interrupts*,
> +*/proc/cpuinfo* and should also not be shown visible by the *top* command. To
> +bring CPU4 back online: ::
> +
> + $ echo 1 > /sys/devices/system/cpu/cpu4/online
> + smpboot: Booting Node 0 Processor 4 APIC 0x1
> +
> +The CPU is usable again. This should work on all CPUs. CPU0 is often special
> +and excluded from CPU hotplug. On X86 the kernel option
> +*CONFIG_BOOTPARAM_HOTPLUG_CPU0* has to be enabled in order to be able to
> +shutdown CPU0. Alternatively the kernel command option *cpu0_hotplug* can be
> +used. Some known dependencies of CPU0:
> +
> +* Resume from hibernate/suspend. Hibernate/suspend will fail if CPU0 is offline.
> +* PIC interrupts. CPU0 can't be removed if a PIC interrupt is detected.
> +
> +Please let Fenghua Yu <fenghua.yu@xxxxxxxxx> know if you find any dependencies
> +on CPU0.
> +
> +The CPU hotplug coordination
> +============================
> +
> +The offline case
> +----------------
> +Once a CPU has been logically shutdown the teardown callbacks of registered
> +hotplug states will be invoked, starting with ``CPUHP_ONLINE`` and terminating
> +at state ``CPUHP_OFFLINE``. This includes:
> +
> +* If tasks are frozen due to a suspend operation then *cpuhp_tasks_frozen*
> + will be set to true.
> +* All processes are migrated away from this outgoing CPU to new CPUs.
> + The new CPU is chosen from each process' current cpuset, which may be
> + a subset of all online CPUs.
> +* All interrupts targeted to this CPU are migrated to a new CPU
> +* timers are also migrated to a new CPU
> +* Once all services are migrated, kernel calls an arch specific routine
> + ``__cpu_disable()`` to perform arch specific cleanup.
> +
> +Using the hotplug API
> +---------------------
> +It is possible to receive notifications once a CPU is offline or onlined. This
> +might be important to certain drivers which need to perform some kind of setup
> +or clean up functions based on the number of available CPUs: ::
> +
> + #include <linux/cpuhotplug.h>
> +
> + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "X/Y:online",
> + Y_online, Y_prepare_down);
> +
> +*X* is the subsystem and *Y* the particular driver. The *Y_online* callback
> +will be invoked during registration on all online CPUs. If an error
> +occurs during the online callback the *Y_prepare_down* callback will be
> +invoked on all CPUs on which the online callback was previously invoked.
> +After registration completed, the *Y_online* callback will be invoked
> +once a CPU is brought online and *Y_prepare_down* will be invoked when a
> +CPU is shutdown. All resources which were previously allocated in
> +*Y_online* should be released in *Y_prepare_down*.
> +The return value *ret* is negative if an error occurred during the
> +registration process. Otherwise a positive value is returned which
> +contains the allocated hotplug for dynamically allocated states
> +(*CPUHP_AP_ONLINE_DYN*). It will return zero for predefined states.
> +
> +The callback can be remove by invoking ``cpuhp_remove_state()``. In case of a
> +dynamically allocated state (*CPUHP_AP_ONLINE_DYN*) use the returned state.
> +During the removal of a hotplug state the teardown callback will be invoked.
> +
> +Multiple instances
> +~~~~~~~~~~~~~~~~~~
> +If a driver has multiple instances and each instance needs to perform the
> +callback independently then it is likely that a ''multi-state'' should be used.
> +First a multi-state state needs to be registered: ::
> +
> + ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "X/Y:online,
> + Y_online, Y_prepare_down);
> + Y_hp_online = ret;
> +
> +The ``cpuhp_setup_state_multi()`` behaves similar to ``cpuhp_setup_state()``
> +except it prepares the callbacks for a multi state and does not invoke
> +the callbacks. This is a one time setup.
> +Once a new instance is allocated, you need to register this new instance: ::
> +
> + ret = cpuhp_state_add_instance(Y_hp_online, &d->node);
> +
> +This function will add this instance to your previously allocated
> +*Y_hp_online* state and invoke the previously registered callback
> +(*Y_online*) on all online CPUs. The *node* element is a ``struct
> +hlist_node`` member of your per-instance data structure.
> +
> +On removal of the instance: ::
> + cpuhp_state_remove_instance(Y_hp_online, &d->node)
> +
> +should be invoked which will invoke the teardown callback on all online
> +CPUs.
> +
> +Manual setup
> +~~~~~~~~~~~~
> +Usually it is handy to invoke setup and teardown callbacks on registration or
> +removal of a state because usually the operation needs to performed once a CPU
> +goes online (offline) and during initial setup (shutdown) of the driver. However
> +each registration and removal function is also available with a ``_nocalls``
> +suffix which does not invoke the provided callbacks if the invocation of the
> +callbacks is not desired. During the manual setup (or teardown) the functions
> +``get_online_cpus()`` and ``put_online_cpus()`` should be used to inhibit CPU
> +hotplug operations.
> +
> +
> +The ordering of the events
> +--------------------------
> +The hotplug states are defined in ``include/linux/cpuhotplug.h``:
> +
> +* The states *CPUHP_OFFLINE* â *CPUHP_AP_OFFLINE* are invoked before the
> + CPU is up.
> +* The states *CPUHP_AP_OFFLINE* â *CPUHP_AP_ONLINE* are invoked
> + just the after the CPU has been brought up. The interrupts are off and
> + the scheduler is not yet active on this CPU. Starting with *CPUHP_AP_OFFLINE*
> + the callbacks are invoked on the target CPU.
> +* The states between *CPUHP_AP_ONLINE_DYN* and *CPUHP_AP_ONLINE_DYN_END* are
> + reserved for the dynamic allocation.
> +* The states are invoked in the reverse order on CPU shutdown starting with
> + *CPUHP_ONLINE* and stopping at *CPUHP_OFFLINE*. Here the callbacks are
> + invoked on the CPU that will be shutdown until *CPUHP_AP_OFFLINE*.
> +
> +A dynamically allocated state via *CPUHP_AP_ONLINE_DYN* is often enough.
> +However if an earlier invocation during the bring up or shutdown is required
> +then an explicit state should be acquired. An explicit state might also be
> +required if the hotplug event requires specific ordering in respect to
> +another hotplug event.
> +
> +Testing of hotplug states
> +=========================
> +One way to verify whether a custom state is working as expected or not is to
> +shutdown a CPU and then put it online again. It is also possible to put the CPU
> +to certain state (for instance *CPUHP_AP_ONLINE*) and then go back to
> +*CPUHP_ONLINE*. This would simulate an error one state after *CPUHP_AP_ONLINE*
> +which would lead to rollback to the online state.
> +
> +All registered states are enumerated in ``/sys/devices/system/cpu/hotplug/states``: ::
> +
> + $ tail /sys/devices/system/cpu/hotplug/states
> + 138: mm/vmscan:online
> + 139: mm/vmstat:online
> + 140: lib/percpu_cnt:online
> + 141: acpi/cpu-drv:online
> + 142: base/cacheinfo:online
> + 143: virtio/net:online
> + 144: x86/mce:online
> + 145: printk:online
> + 168: sched:active
> + 169: online
> +
> +To rollback CPU4 to ``lib/percpu_cnt:online`` and back online just issue: ::
> +
> + $ cat /sys/devices/system/cpu/cpu4/hotplug/state
> + 169
> + $ echo 140 > /sys/devices/system/cpu/cpu4/hotplug/target
> + $ cat /sys/devices/system/cpu/cpu4/hotplug/state
> + 140
> +
> +It is important to note that the teardown callbac of state 140 have been
> +invoked. And now get back online: ::
> +
> + $ echo 169 > /sys/devices/system/cpu/cpu4/hotplug/target
> + $ cat /sys/devices/system/cpu/cpu4/hotplug/state
> + 169
> +
> +With trace events enabled, the individual steps are visible, too: ::
> +
> + # TASK-PID CPU# TIMESTAMP FUNCTION
> + # | | | | |
> + bash-394 [001] 22.976: cpuhp_enter: cpu: 0004 target: 140 step: 169 (cpuhp_kick_ap_work)
> + cpuhp/4-31 [004] 22.977: cpuhp_enter: cpu: 0004 target: 140 step: 168 (sched_cpu_deactivate)
> + cpuhp/4-31 [004] 22.990: cpuhp_exit: cpu: 0004 state: 168 step: 168 ret: 0
> + cpuhp/4-31 [004] 22.991: cpuhp_enter: cpu: 0004 target: 140 step: 144 (mce_cpu_pre_down)
> + cpuhp/4-31 [004] 22.992: cpuhp_exit: cpu: 0004 state: 144 step: 144 ret: 0
> + cpuhp/4-31 [004] 22.993: cpuhp_multi_enter: cpu: 0004 target: 140 step: 143 (virtnet_cpu_down_prep)
> + cpuhp/4-31 [004] 22.994: cpuhp_exit: cpu: 0004 state: 143 step: 143 ret: 0
> + cpuhp/4-31 [004] 22.995: cpuhp_enter: cpu: 0004 target: 140 step: 142 (cacheinfo_cpu_pre_down)
> + cpuhp/4-31 [004] 22.996: cpuhp_exit: cpu: 0004 state: 142 step: 142 ret: 0
> + bash-394 [001] 22.997: cpuhp_exit: cpu: 0004 state: 140 step: 169 ret: 0
> + bash-394 [005] 95.540: cpuhp_enter: cpu: 0004 target: 169 step: 140 (cpuhp_kick_ap_work)
> + cpuhp/4-31 [004] 95.541: cpuhp_enter: cpu: 0004 target: 169 step: 141 (acpi_soft_cpu_online)
> + cpuhp/4-31 [004] 95.542: cpuhp_exit: cpu: 0004 state: 141 step: 141 ret: 0
> + cpuhp/4-31 [004] 95.543: cpuhp_enter: cpu: 0004 target: 169 step: 142 (cacheinfo_cpu_online)
> + cpuhp/4-31 [004] 95.544: cpuhp_exit: cpu: 0004 state: 142 step: 142 ret: 0
> + cpuhp/4-31 [004] 95.545: cpuhp_multi_enter: cpu: 0004 target: 169 step: 143 (virtnet_cpu_online)
> + cpuhp/4-31 [004] 95.546: cpuhp_exit: cpu: 0004 state: 143 step: 143 ret: 0
> + cpuhp/4-31 [004] 95.547: cpuhp_enter: cpu: 0004 target: 169 step: 144 (mce_cpu_online)
> + cpuhp/4-31 [004] 95.548: cpuhp_exit: cpu: 0004 state: 144 step: 144 ret: 0
> + cpuhp/4-31 [004] 95.549: cpuhp_enter: cpu: 0004 target: 169 step: 145 (console_cpu_notify)
> + cpuhp/4-31 [004] 95.550: cpuhp_exit: cpu: 0004 state: 145 step: 145 ret: 0
> + cpuhp/4-31 [004] 95.551: cpuhp_enter: cpu: 0004 target: 169 step: 168 (sched_cpu_activate)
> + cpuhp/4-31 [004] 95.552: cpuhp_exit: cpu: 0004 state: 168 step: 168 ret: 0
> + bash-394 [005] 95.553: cpuhp_exit: cpu: 0004 state: 169 step: 140 ret: 0
> +
> +As it an be seen, CPU4 went down until timestamp 22.996 and then back up until
> +95.552. All invoked callbacks including their return codes are visible in the
> +trace.
> +
> +Architecture's requirements
> +===========================
> +The following functions and configurations are required:
> +
> +``CONFIG_HOTPLUG_CPU``
> + This entry needs to be enabled in Kconfig
> +
> +``__cpu_up()``
> + Arch interface to bring up a CPU
> +
> +``__cpu_disable()``
> + Arch interface to shutdown a CPU, no more interrupts can be handled by the
> + kernel after the routine returns. This includes the shutdown of the timer.
> +
> +``__cpu_die()``
> + This actually supposed to ensure death of the CPU. Actually look at some
> + example code in other arch that implement CPU hotplug. The processor is taken
> + down from the ``idle()`` loop for that specific architecture. ``__cpu_die()``
> + typically waits for some per_cpu state to be set, to ensure the processor dead
> + routine is called to be sure positively.
> +
> +User Space Notification
> +=======================
> +After CPU successfully onlined or offline udev events are sent. A udev rule like: ::
> +
> + SUBSYSTEM=="cpu", DRIVERS=="processor", DEVPATH=="/devices/system/cpu/*", RUN+="the_hotplug_receiver.sh"
> +
> +will receive all events. A script like: ::
> +
> + #!/bin/sh
> +
> + if [ "${ACTION}" = "offline" ]
> + then
> + echo "CPU ${DEVPATH##*/} offline"
> +
> + elif [ "${ACTION}" = "online" ]
> + then
> + echo "CPU ${DEVPATH##*/} online"
> +
> + fi
> +
> +can process the event further.
> +
> +Kernel Inline Documentations Reference
> +======================================
> +
> +.. kernel-doc:: include/linux/cpuhotplug.h
> diff --git a/Documentation/core-api/index.rst b/Documentation/core-api/index.rst
> index 2872ca1a52f1..0d93d8089136 100644
> --- a/Documentation/core-api/index.rst
> +++ b/Documentation/core-api/index.rst
> @@ -13,6 +13,7 @@ Core utilities
>
> assoc_array
> atomic_ops
> + cpu_hotplug
> local_ops
> workqueue
>
> diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt
> deleted file mode 100644
> index d02e8a451872..000000000000
> --- a/Documentation/cpu-hotplug.txt
> +++ /dev/null
> @@ -1,452 +0,0 @@
> - CPU hotplug Support in Linux(tm) Kernel
> -
> - Maintainers:
> - CPU Hotplug Core:
> - Rusty Russell <rusty@xxxxxxxxxxxxxxx>
> - Srivatsa Vaddagiri <vatsa@xxxxxxxxxx>
> - i386:
> - Zwane Mwaikambo <zwanem@xxxxxxxxx>
> - ppc64:
> - Nathan Lynch <nathanl@xxxxxxxxxxxxxx>
> - Joel Schopp <jschopp@xxxxxxxxxxxxxx>
> - ia64/x86_64:
> - Ashok Raj <ashok.raj@xxxxxxxxx>
> - s390:
> - Heiko Carstens <heiko.carstens@xxxxxxxxxx>
> -
> -Authors: Ashok Raj <ashok.raj@xxxxxxxxx>
> -Lots of feedback: Nathan Lynch <nathanl@xxxxxxxxxxxxxx>,
> - Joel Schopp <jschopp@xxxxxxxxxxxxxx>
> -
> -Introduction
> -
> -Modern advances in system architectures have introduced advanced error
> -reporting and correction capabilities in processors. CPU architectures permit
> -partitioning support, where compute resources of a single CPU could be made
> -available to virtual machine environments. There are couple OEMS that
> -support NUMA hardware which are hot pluggable as well, where physical
> -node insertion and removal require support for CPU hotplug.
> -
> -Such advances require CPUs available to a kernel to be removed either for
> -provisioning reasons, or for RAS purposes to keep an offending CPU off
> -system execution path. Hence the need for CPU hotplug support in the
> -Linux kernel.
> -
> -A more novel use of CPU-hotplug support is its use today in suspend
> -resume support for SMP. Dual-core and HT support makes even
> -a laptop run SMP kernels which didn't support these methods. SMP support
> -for suspend/resume is a work in progress.
> -
> -General Stuff about CPU Hotplug
> ---------------------------------
> -
> -Command Line Switches
> ----------------------
> -maxcpus=n Restrict boot time cpus to n. Say if you have 4 cpus, using
> - maxcpus=2 will only boot 2. You can choose to bring the
> - other cpus later online, read FAQ's for more info.
> -
> -additional_cpus=n (*) Use this to limit hotpluggable cpus. This option sets
> - cpu_possible_mask = cpu_present_mask + additional_cpus
> -
> -cede_offline={"off","on"} Use this option to disable/enable putting offlined
> - processors to an extended H_CEDE state on
> - supported pseries platforms.
> - If nothing is specified,
> - cede_offline is set to "on".
> -
> -(*) Option valid only for following architectures
> -- ia64
> -
> -ia64 uses the number of disabled local apics in ACPI tables MADT to
> -determine the number of potentially hot-pluggable cpus. The implementation
> -should only rely on this to count the # of cpus, but *MUST* not rely
> -on the apicid values in those tables for disabled apics. In the event
> -BIOS doesn't mark such hot-pluggable cpus as disabled entries, one could
> -use this parameter "additional_cpus=x" to represent those cpus in the
> -cpu_possible_mask.
> -
> -possible_cpus=n [s390,x86_64] use this to set hotpluggable cpus.
> - This option sets possible_cpus bits in
> - cpu_possible_mask. Thus keeping the numbers of bits set
> - constant even if the machine gets rebooted.
> -
> -CPU maps and such
> ------------------
> -[More on cpumaps and primitive to manipulate, please check
> -include/linux/cpumask.h that has more descriptive text.]
> -
> -cpu_possible_mask: Bitmap of possible CPUs that can ever be available in the
> -system. This is used to allocate some boot time memory for per_cpu variables
> -that aren't designed to grow/shrink as CPUs are made available or removed.
> -Once set during boot time discovery phase, the map is static, i.e no bits
> -are added or removed anytime. Trimming it accurately for your system needs
> -upfront can save some boot time memory. See below for how we use heuristics
> -in x86_64 case to keep this under check.
> -
> -cpu_online_mask: Bitmap of all CPUs currently online. It's set in __cpu_up()
> -after a CPU is available for kernel scheduling and ready to receive
> -interrupts from devices. It's cleared when a CPU is brought down using
> -__cpu_disable(), before which all OS services including interrupts are
> -migrated to another target CPU.
> -
> -cpu_present_mask: Bitmap of CPUs currently present in the system. Not all
> -of them may be online. When physical hotplug is processed by the relevant
> -subsystem (e.g ACPI) can change and new bit either be added or removed
> -from the map depending on the event is hot-add/hot-remove. There are currently
> -no locking rules as of now. Typical usage is to init topology during boot,
> -at which time hotplug is disabled.
> -
> -You really dont need to manipulate any of the system cpu maps. They should
> -be read-only for most use. When setting up per-cpu resources almost always use
> -cpu_possible_mask/for_each_possible_cpu() to iterate.
> -
> -Never use anything other than cpumask_t to represent bitmap of CPUs.
> -
> - #include <linux/cpumask.h>
> -
> - for_each_possible_cpu - Iterate over cpu_possible_mask
> - for_each_online_cpu - Iterate over cpu_online_mask
> - for_each_present_cpu - Iterate over cpu_present_mask
> - for_each_cpu(x,mask) - Iterate over some random collection of cpu mask.
> -
> - #include <linux/cpu.h>
> - get_online_cpus() and put_online_cpus():
> -
> -The above calls are used to inhibit cpu hotplug operations. While the
> -cpu_hotplug.refcount is non zero, the cpu_online_mask will not change.
> -If you merely need to avoid cpus going away, you could also use
> -preempt_disable() and preempt_enable() for those sections.
> -Just remember the critical section cannot call any
> -function that can sleep or schedule this process away. The preempt_disable()
> -will work as long as stop_machine_run() is used to take a cpu down.
> -
> -CPU Hotplug - Frequently Asked Questions.
> -
> -Q: How to enable my kernel to support CPU hotplug?
> -A: When doing make defconfig, Enable CPU hotplug support
> -
> - "Processor type and Features" -> Support for Hotpluggable CPUs
> -
> -Make sure that you have CONFIG_SMP turned on as well.
> -
> -You would need to enable CONFIG_HOTPLUG_CPU for SMP suspend/resume support
> -as well.
> -
> -Q: What architectures support CPU hotplug?
> -A: As of 2.6.14, the following architectures support CPU hotplug.
> -
> -i386 (Intel), ppc, ppc64, parisc, s390, ia64 and x86_64
> -
> -Q: How to test if hotplug is supported on the newly built kernel?
> -A: You should now notice an entry in sysfs.
> -
> -Check if sysfs is mounted, using the "mount" command. You should notice
> -an entry as shown below in the output.
> -
> - ....
> - none on /sys type sysfs (rw)
> - ....
> -
> -If this is not mounted, do the following.
> -
> - #mkdir /sys
> - #mount -t sysfs sys /sys
> -
> -Now you should see entries for all present cpu, the following is an example
> -in a 8-way system.
> -
> - #pwd
> - #/sys/devices/system/cpu
> - #ls -l
> - total 0
> - drwxr-xr-x 10 root root 0 Sep 19 07:44 .
> - drwxr-xr-x 13 root root 0 Sep 19 07:45 ..
> - drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu0
> - drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu1
> - drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu2
> - drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu3
> - drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu4
> - drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu5
> - drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu6
> - drwxr-xr-x 3 root root 0 Sep 19 07:48 cpu7
> -
> -Under each directory you would find an "online" file which is the control
> -file to logically online/offline a processor.
> -
> -Q: Does hot-add/hot-remove refer to physical add/remove of cpus?
> -A: The usage of hot-add/remove may not be very consistently used in the code.
> -CONFIG_HOTPLUG_CPU enables logical online/offline capability in the kernel.
> -To support physical addition/removal, one would need some BIOS hooks and
> -the platform should have something like an attention button in PCI hotplug.
> -CONFIG_ACPI_HOTPLUG_CPU enables ACPI support for physical add/remove of CPUs.
> -
> -Q: How do I logically offline a CPU?
> -A: Do the following.
> -
> - #echo 0 > /sys/devices/system/cpu/cpuX/online
> -
> -Once the logical offline is successful, check
> -
> - #cat /proc/interrupts
> -
> -You should now not see the CPU that you removed. Also online file will report
> -the state as 0 when a CPU is offline and 1 when it's online.
> -
> - #To display the current cpu state.
> - #cat /sys/devices/system/cpu/cpuX/online
> -
> -Q: Why can't I remove CPU0 on some systems?
> -A: Some architectures may have some special dependency on a certain CPU.
> -
> -For e.g in IA64 platforms we have ability to send platform interrupts to the
> -OS. a.k.a Corrected Platform Error Interrupts (CPEI). In current ACPI
> -specifications, we didn't have a way to change the target CPU. Hence if the
> -current ACPI version doesn't support such re-direction, we disable that CPU
> -by making it not-removable.
> -
> -In such cases you will also notice that the online file is missing under cpu0.
> -
> -Q: Is CPU0 removable on X86?
> -A: Yes. If kernel is compiled with CONFIG_BOOTPARAM_HOTPLUG_CPU0=y, CPU0 is
> -removable by default. Otherwise, CPU0 is also removable by kernel option
> -cpu0_hotplug.
> -
> -But some features depend on CPU0. Two known dependencies are:
> -
> -1. Resume from hibernate/suspend depends on CPU0. Hibernate/suspend will fail if
> -CPU0 is offline and you need to online CPU0 before hibernate/suspend can
> -continue.
> -2. PIC interrupts also depend on CPU0. CPU0 can't be removed if a PIC interrupt
> -is detected.
> -
> -It's said poweroff/reboot may depend on CPU0 on some machines although I haven't
> -seen any poweroff/reboot failure so far after CPU0 is offline on a few tested
> -machines.
> -
> -Please let me know if you know or see any other dependencies of CPU0.
> -
> -If the dependencies are under your control, you can turn on CPU0 hotplug feature
> -either by CONFIG_BOOTPARAM_HOTPLUG_CPU0 or by kernel parameter cpu0_hotplug.
> -
> ---Fenghua Yu <fenghua.yu@xxxxxxxxx>
> -
> -Q: How do I find out if a particular CPU is not removable?
> -A: Depending on the implementation, some architectures may show this by the
> -absence of the "online" file. This is done if it can be determined ahead of
> -time that this CPU cannot be removed.
> -
> -In some situations, this can be a run time check, i.e if you try to remove the
> -last CPU, this will not be permitted. You can find such failures by
> -investigating the return value of the "echo" command.
> -
> -Q: What happens when a CPU is being logically offlined?
> -A: The following happen, listed in no particular order :-)
> -
> -- A notification is sent to in-kernel registered modules by sending an event
> - CPU_DOWN_PREPARE or CPU_DOWN_PREPARE_FROZEN, depending on whether or not the
> - CPU is being offlined while tasks are frozen due to a suspend operation in
> - progress
> -- All processes are migrated away from this outgoing CPU to new CPUs.
> - The new CPU is chosen from each process' current cpuset, which may be
> - a subset of all online CPUs.
> -- All interrupts targeted to this CPU are migrated to a new CPU
> -- timers/bottom half/task lets are also migrated to a new CPU
> -- Once all services are migrated, kernel calls an arch specific routine
> - __cpu_disable() to perform arch specific cleanup.
> -- Once this is successful, an event for successful cleanup is sent by an event
> - CPU_DEAD (or CPU_DEAD_FROZEN if tasks are frozen due to a suspend while the
> - CPU is being offlined).
> -
> - "It is expected that each service cleans up when the CPU_DOWN_PREPARE
> - notifier is called, when CPU_DEAD is called it's expected there is nothing
> - running on behalf of this CPU that was offlined"
> -
> -Q: If I have some kernel code that needs to be aware of CPU arrival and
> - departure, how to i arrange for proper notification?
> -A: This is what you would need in your kernel code to receive notifications.
> -
> - #include <linux/cpu.h>
> - static int foobar_cpu_callback(struct notifier_block *nfb,
> - unsigned long action, void *hcpu)
> - {
> - unsigned int cpu = (unsigned long)hcpu;
> -
> - switch (action) {
> - case CPU_ONLINE:
> - case CPU_ONLINE_FROZEN:
> - foobar_online_action(cpu);
> - break;
> - case CPU_DEAD:
> - case CPU_DEAD_FROZEN:
> - foobar_dead_action(cpu);
> - break;
> - }
> - return NOTIFY_OK;
> - }
> -
> - static struct notifier_block foobar_cpu_notifier =
> - {
> - .notifier_call = foobar_cpu_callback,
> - };
> -
> -You need to call register_cpu_notifier() from your init function.
> -Init functions could be of two types:
> -1. early init (init function called when only the boot processor is online).
> -2. late init (init function called _after_ all the CPUs are online).
> -
> -For the first case, you should add the following to your init function
> -
> - register_cpu_notifier(&foobar_cpu_notifier);
> -
> -For the second case, you should add the following to your init function
> -
> - register_hotcpu_notifier(&foobar_cpu_notifier);
> -
> -You can fail PREPARE notifiers if something doesn't work to prepare resources.
> -This will stop the activity and send a following CANCELED event back.
> -
> -CPU_DEAD should not be failed, its just a goodness indication, but bad
> -things will happen if a notifier in path sent a BAD notify code.
> -
> -Q: I don't see my action being called for all CPUs already up and running?
> -A: Yes, CPU notifiers are called only when new CPUs are on-lined or offlined.
> - If you need to perform some action for each CPU already in the system, then
> - do this:
> -
> - for_each_online_cpu(i) {
> - foobar_cpu_callback(&foobar_cpu_notifier, CPU_UP_PREPARE, i);
> - foobar_cpu_callback(&foobar_cpu_notifier, CPU_ONLINE, i);
> - }
> -
> - However, if you want to register a hotplug callback, as well as perform
> - some initialization for CPUs that are already online, then do this:
> -
> - Version 1: (Correct)
> - ---------
> -
> - cpu_notifier_register_begin();
> -
> - for_each_online_cpu(i) {
> - foobar_cpu_callback(&foobar_cpu_notifier,
> - CPU_UP_PREPARE, i);
> - foobar_cpu_callback(&foobar_cpu_notifier,
> - CPU_ONLINE, i);
> - }
> -
> - /* Note the use of the double underscored version of the API */
> - __register_cpu_notifier(&foobar_cpu_notifier);
> -
> - cpu_notifier_register_done();
> -
> - Note that the following code is *NOT* the right way to achieve this,
> - because it is prone to an ABBA deadlock between the cpu_add_remove_lock
> - and the cpu_hotplug.lock.
> -
> - Version 2: (Wrong!)
> - ---------
> -
> - get_online_cpus();
> -
> - for_each_online_cpu(i) {
> - foobar_cpu_callback(&foobar_cpu_notifier,
> - CPU_UP_PREPARE, i);
> - foobar_cpu_callback(&foobar_cpu_notifier,
> - CPU_ONLINE, i);
> - }
> -
> - register_cpu_notifier(&foobar_cpu_notifier);
> -
> - put_online_cpus();
> -
> - So always use the first version shown above when you want to register
> - callbacks as well as initialize the already online CPUs.
> -
> -
> -Q: If I would like to develop CPU hotplug support for a new architecture,
> - what do I need at a minimum?
> -A: The following are what is required for CPU hotplug infrastructure to work
> - correctly.
> -
> - - Make sure you have an entry in Kconfig to enable CONFIG_HOTPLUG_CPU
> - - __cpu_up() - Arch interface to bring up a CPU
> - - __cpu_disable() - Arch interface to shutdown a CPU, no more interrupts
> - can be handled by the kernel after the routine
> - returns. Including local APIC timers etc are
> - shutdown.
> - - __cpu_die() - This actually supposed to ensure death of the CPU.
> - Actually look at some example code in other arch
> - that implement CPU hotplug. The processor is taken
> - down from the idle() loop for that specific
> - architecture. __cpu_die() typically waits for some
> - per_cpu state to be set, to ensure the processor
> - dead routine is called to be sure positively.
> -
> -Q: I need to ensure that a particular CPU is not removed when there is some
> - work specific to this CPU in progress.
> -A: There are two ways. If your code can be run in interrupt context, use
> - smp_call_function_single(), otherwise use work_on_cpu(). Note that
> - work_on_cpu() is slow, and can fail due to out of memory:
> -
> - int my_func_on_cpu(int cpu)
> - {
> - int err;
> - get_online_cpus();
> - if (!cpu_online(cpu))
> - err = -EINVAL;
> - else
> -#if NEEDS_BLOCKING
> - err = work_on_cpu(cpu, __my_func_on_cpu, NULL);
> -#else
> - smp_call_function_single(cpu, __my_func_on_cpu, &err,
> - true);
> -#endif
> - put_online_cpus();
> - return err;
> - }
> -
> -Q: How do we determine how many CPUs are available for hotplug.
> -A: There is no clear spec defined way from ACPI that can give us that
> - information today. Based on some input from Natalie of Unisys,
> - that the ACPI MADT (Multiple APIC Description Tables) marks those possible
> - CPUs in a system with disabled status.
> -
> - Andi implemented some simple heuristics that count the number of disabled
> - CPUs in MADT as hotpluggable CPUS. In the case there are no disabled CPUS
> - we assume 1/2 the number of CPUs currently present can be hotplugged.
> -
> - Caveat: ACPI MADT can only provide 256 entries in systems with only ACPI 2.0c
> - or earlier ACPI version supported, because the apicid field in MADT is only
> - 8 bits. From ACPI 3.0, this limitation was removed since the apicid field
> - was extended to 32 bits with x2APIC introduced.
> -
> -User Space Notification
> -
> -Hotplug support for devices is common in Linux today. Its being used today to
> -support automatic configuration of network, usb and pci devices. A hotplug
> -event can be used to invoke an agent script to perform the configuration task.
> -
> -You can add /etc/hotplug/cpu.agent to handle hotplug notification user space
> -scripts.
> -
> - #!/bin/bash
> - # $Id: cpu.agent
> - # Kernel hotplug params include:
> - #ACTION=%s [online or offline]
> - #DEVPATH=%s
> - #
> - cd /etc/hotplug
> - . ./hotplug.functions
> -
> - case $ACTION in
> - online)
> - echo `date` ":cpu.agent" add cpu >> /tmp/hotplug.txt
> - ;;
> - offline)
> - echo `date` ":cpu.agent" remove cpu >>/tmp/hotplug.txt
> - ;;
> - *)
> - debug_mesg CPU $ACTION event not supported
> - exit 1
> - ;;
> - esac

--
Jani Nikula, Intel Open Source Technology Center