€•ª¨Œsphinx.addnodes”Œdocument”“”)”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)”}”(hhh]”(hŒ pending_xref”“”)”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…””}”(hhŒparent”hubaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”Œ0/translations/zh_CN/power/suspend-and-cpuhotplug”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)”}”(hhh]”hŒChinese (Traditional)”…””}”(hhhh2ubah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ0/translations/zh_TW/power/suspend-and-cpuhotplug”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒItalian”…””}”(hhhhFubah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ0/translations/it_IT/power/suspend-and-cpuhotplug”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒJapanese”…””}”(hhhhZubah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ0/translations/ja_JP/power/suspend-and-cpuhotplug”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒKorean”…””}”(hhhhnubah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ0/translations/ko_KR/power/suspend-and-cpuhotplug”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒSpanish”…””}”(hhhh‚ubah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ0/translations/sp_SP/power/suspend-and-cpuhotplug”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒsection”“”)”}”(hhh]”(hŒtitle”“”)”}”(hŒDInteraction of Suspend code (S3) with the CPU hotplug infrastructure”h]”hŒDInteraction of Suspend code (S3) with the CPU hotplug infrastructure”…””}”(hhªhh¨hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hh£hžhhŸŒJ/var/lib/git/docbuild/linux/Documentation/power/suspend-and-cpuhotplug.rst”h KubhŒenumerated_list”“”)”}”(hhh]”hŒ list_item”“”)”}”(hŒA2011 - 2014 Srivatsa S. Bhat ”h]”hŒ paragraph”“”)”}”(hŒ?2011 - 2014 Srivatsa S. Bhat ”h]”(hŒ2011 - 2014 Srivatsa S. Bhat <”…””}”(hŒ2011 - 2014 Srivatsa S. Bhat <”hhÄhžhhŸNh NubhŒ reference”“”)”}”(hŒ srivatsa.bhat@linux.vnet.ibm.com”h]”hŒ srivatsa.bhat@linux.vnet.ibm.com”…””}”(hhhhÏhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”Œrefuri”Œ'mailto:srivatsa.bhat@linux.vnet.ibm.com”uh1hÍhhÄubhŒ>”…””}”(hŒ>”hhÄhžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h Khh¾ubah}”(h]”h ]”h"]”h$]”h&]”uh1h¼hh¹hžhhŸh¶h Nubah}”(h]”h ]”h"]”h$]”h&]”Œenumtype”Œ upperalpha”Œprefix”Œ(”Œsuffix”Œ)”Œstart”Kuh1h·hh£hžhhŸh¶h Kubh¢)”}”(hhh]”(h§)”}”(hŒ5I. Differences between CPU hotplug and Suspend-to-RAM”h]”hŒ5I. Differences between CPU hotplug and Suspend-to-RAM”…””}”(hjhjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hhýhžhhŸh¶h K ubhÃ)”}”(hŒHow does the regular CPU hotplug code differ from how the Suspend-to-RAM infrastructure uses it internally? And where do they share common code?”h]”hŒHow does the regular CPU hotplug code differ from how the Suspend-to-RAM infrastructure uses it internally? And where do they share common code?”…””}”(hjhjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h K hhýhžhubhÃ)”}”(hŒEWell, a picture is worth a thousand words... So ASCII art follows :-)”h]”hŒEWell, a picture is worth a thousand words... So ASCII art follows :-)”…””}”(hjhjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h KhhýhžhubhÃ)”}”(hXÖ[This depicts the current design in the kernel, and focusses only on the interactions involving the freezer and CPU hotplug and also tries to explain the locking involved. It outlines the notifications involved as well. But please note that here, only the call paths are illustrated, with the aim of describing where they take different paths and where they share code. What happens when regular CPU hotplug and Suspend-to-RAM race with each other is not depicted here.]”h]”hXÖ[This depicts the current design in the kernel, and focusses only on the interactions involving the freezer and CPU hotplug and also tries to explain the locking involved. It outlines the notifications involved as well. But please note that here, only the call paths are illustrated, with the aim of describing where they take different paths and where they share code. What happens when regular CPU hotplug and Suspend-to-RAM race with each other is not depicted here.]”…””}”(hj,hj*hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h KhhýhžhubhÃ)”}”(hŒ:On a high level, the suspend-resume cycle goes like this::”h]”hŒ9On a high level, the suspend-resume cycle goes like this:”…””}”(hŒ9On a high level, the suspend-resume cycle goes like this:”hj8hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h KhhýhžhubhŒ literal_block”“”)”}”(hŒ™|Freeze| -> |Disable nonboot| -> |Do suspend| -> |Enable nonboot| -> |Thaw | |tasks | | cpus | | | | cpus | |tasks|”h]”hŒ™|Freeze| -> |Disable nonboot| -> |Do suspend| -> |Enable nonboot| -> |Thaw | |tasks | | cpus | | | | cpus | |tasks|”…””}”(hhhjIubah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”uh1jGhŸh¶h KhhýhžhubhÃ)”}”(hŒMore details follow::”h]”hŒMore details follow:”…””}”(hŒMore details follow:”hjYhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h KhhýhžhubjH)”}”(hXJ Suspend call path ----------------- Write 'mem' to /sys/power/state sysfs file | v Acquire system_transition_mutex lock | v Send PM_SUSPEND_PREPARE notifications | v Freeze tasks | | v freeze_secondary_cpus() /* start */ | v Acquire cpu_add_remove_lock | v Iterate over CURRENTLY online CPUs | | | ---------- v | L ======> _cpu_down() | | [This takes cpuhotplug.lock | Common | before taking down the CPU | code | and releases it when done] | O | While it is at it, notifications | | are sent when notable events occur, | ======> by running all registered callbacks. | | | O | | | | v | Note down these cpus in | P frozen_cpus mask ---------- | v Disable regular cpu hotplug by increasing cpu_hotplug_disabled | v Release cpu_add_remove_lock | v /* freeze_secondary_cpus() complete */ | v Do suspend”h]”hXJ Suspend call path ----------------- Write 'mem' to /sys/power/state sysfs file | v Acquire system_transition_mutex lock | v Send PM_SUSPEND_PREPARE notifications | v Freeze tasks | | v freeze_secondary_cpus() /* start */ | v Acquire cpu_add_remove_lock | v Iterate over CURRENTLY online CPUs | | | ---------- v | L ======> _cpu_down() | | [This takes cpuhotplug.lock | Common | before taking down the CPU | code | and releases it when done] | O | While it is at it, notifications | | are sent when notable events occur, | ======> by running all registered callbacks. | | | O | | | | v | Note down these cpus in | P frozen_cpus mask ---------- | v Disable regular cpu hotplug by increasing cpu_hotplug_disabled | v Release cpu_add_remove_lock | v /* freeze_secondary_cpus() complete */ | v Do suspend”…””}”(hhhjhubah}”(h]”h ]”h"]”h$]”h&]”jWjXuh1jGhŸh¶h K hhýhžhubhÃ)”}”(hŒaResuming back is likewise, with the counterparts being (in the order of execution during resume):”h]”hŒaResuming back is likewise, with the counterparts being (in the order of execution during resume):”…””}”(hjxhjvhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h K]hhýhžhubhŒ bullet_list”“”)”}”(hhh]”(h½)”}”(hŒþthaw_secondary_cpus() which involves:: | Acquire cpu_add_remove_lock | Decrease cpu_hotplug_disabled, thereby enabling regular cpu hotplug | Call _cpu_up() [for all those cpus in the frozen_cpus mask, in a loop] | Release cpu_add_remove_lock v ”h]”(hÃ)”}”(hŒ&thaw_secondary_cpus() which involves::”h]”hŒ%thaw_secondary_cpus() which involves:”…””}”(hŒ%thaw_secondary_cpus() which involves:”hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h K`hj‰ubjH)”}”(hŒÐ| Acquire cpu_add_remove_lock | Decrease cpu_hotplug_disabled, thereby enabling regular cpu hotplug | Call _cpu_up() [for all those cpus in the frozen_cpus mask, in a loop] | Release cpu_add_remove_lock v”h]”hŒÐ| Acquire cpu_add_remove_lock | Decrease cpu_hotplug_disabled, thereby enabling regular cpu hotplug | Call _cpu_up() [for all those cpus in the frozen_cpus mask, in a loop] | Release cpu_add_remove_lock v”…””}”(hhhjœubah}”(h]”h ]”h"]”h$]”h&]”jWjXuh1jGhŸh¶h Kbhj‰ubeh}”(h]”h ]”h"]”h$]”h&]”uh1h¼hj†hžhhŸh¶h Nubh½)”}”(hŒ thaw tasks”h]”hÃ)”}”(hj²h]”hŒ thaw tasks”…””}”(hj²hj´hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h Khhj°ubah}”(h]”h ]”h"]”h$]”h&]”uh1h¼hj†hžhhŸh¶h Nubh½)”}”(hŒ"send PM_POST_SUSPEND notifications”h]”hÃ)”}”(hjÉh]”hŒ"send PM_POST_SUSPEND notifications”…””}”(hjÉhjËhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h KihjÇubah}”(h]”h ]”h"]”h$]”h&]”uh1h¼hj†hžhhŸh¶h Nubh½)”}”(hŒ'Release system_transition_mutex lock. ”h]”hÃ)”}”(hŒ%Release system_transition_mutex lock.”h]”hŒ%Release system_transition_mutex lock.”…””}”(hjähjâhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h KjhjÞubah}”(h]”h ]”h"]”h$]”h&]”uh1h¼hj†hžhhŸh¶h Nubeh}”(h]”h ]”h"]”h$]”h&]”Œbullet”Œ*”uh1j„hŸh¶h K`hhýhžhubhÃ)”}”(hŒÝIt is to be noted here that the system_transition_mutex lock is acquired at the very beginning, when we are just starting out to suspend, and then released only after the entire cycle is complete (i.e., suspend + resume).”h]”hŒÝIt is to be noted here that the system_transition_mutex lock is acquired at the very beginning, when we are just starting out to suspend, and then released only after the entire cycle is complete (i.e., suspend + resume).”…””}”(hjhjþhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h KmhhýhžhubjH)”}”(hXÝ Regular CPU hotplug call path ----------------------------- Write 0 (or 1) to /sys/devices/system/cpu/cpu*/online sysfs file | | v cpu_down() | v Acquire cpu_add_remove_lock | v If cpu_hotplug_disabled > 0 return gracefully | | v ======> _cpu_down() | [This takes cpuhotplug.lock Common | before taking down the CPU code | and releases it when done] | While it is at it, notifications | are sent when notable events occur, ======> by running all registered callbacks. | | v Release cpu_add_remove_lock [That's it!, for regular CPU hotplug]”h]”hXÝ Regular CPU hotplug call path ----------------------------- Write 0 (or 1) to /sys/devices/system/cpu/cpu*/online sysfs file | | v cpu_down() | v Acquire cpu_add_remove_lock | v If cpu_hotplug_disabled > 0 return gracefully | | v ======> _cpu_down() | [This takes cpuhotplug.lock Common | before taking down the CPU code | and releases it when done] | While it is at it, notifications | are sent when notable events occur, ======> by running all registered callbacks. | | v Release cpu_add_remove_lock [That's it!, for regular CPU hotplug]”…””}”(hhhj ubah}”(h]”h ]”h"]”h$]”h&]”jWjXuh1jGhŸh¶h KuhhýhžhubhÃ)”}”(hX&So, as can be seen from the two diagrams (the parts marked as "Common code"), regular CPU hotplug and the suspend code path converge at the _cpu_down() and _cpu_up() functions. They differ in the arguments passed to these functions, in that during regular CPU hotplug, 0 is passed for the 'tasks_frozen' argument. But during suspend, since the tasks are already frozen by the time the non-boot CPUs are offlined or onlined, the _cpu_*() functions are called with the 'tasks_frozen' argument set to 1. [See below for some known issues regarding this.]”h]”hX2So, as can be seen from the two diagrams (the parts marked as “Common codeâ€), regular CPU hotplug and the suspend code path converge at the _cpu_down() and _cpu_up() functions. They differ in the arguments passed to these functions, in that during regular CPU hotplug, 0 is passed for the ‘tasks_frozen’ argument. But during suspend, since the tasks are already frozen by the time the non-boot CPUs are offlined or onlined, the _cpu_*() functions are called with the ‘tasks_frozen’ argument set to 1. [See below for some known issues regarding this.]”…””}”(hjhjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h K™hhýhžhubh¢)”}”(hhh]”(h§)”}”(hŒ+Important files and functions/entry points:”h]”hŒ+Important files and functions/entry points:”…””}”(hj-hj+hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hj(hžhhŸh¶h K¤ubj…)”}”(hhh]”(h½)”}”(hŒ=kernel/power/process.c : freeze_processes(), thaw_processes()”h]”hÃ)”}”(hj>h]”hŒ=kernel/power/process.c : freeze_processes(), thaw_processes()”…””}”(hj>hj@hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h K¦hj<ubah}”(h]”h ]”h"]”h$]”h&]”uh1h¼hj9hžhhŸh¶h Nubh½)”}”(hŒMkernel/power/suspend.c : suspend_prepare(), suspend_enter(), suspend_finish()”h]”hÃ)”}”(hjUh]”hŒMkernel/power/suspend.c : suspend_prepare(), suspend_enter(), suspend_finish()”…””}”(hjUhjWhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h K§hjSubah}”(h]”h ]”h"]”h$]”h&]”uh1h¼hj9hžhhŸh¶h Nubh½)”}”(hŒSkernel/cpu.c: cpu_[up|down](), _cpu_[up|down](), [disable|enable]_nonboot_cpus() ”h]”hÃ)”}”(hŒPkernel/cpu.c: cpu_[up|down](), _cpu_[up|down](), [disable|enable]_nonboot_cpus()”h]”hŒPkernel/cpu.c: cpu_[up|down](), _cpu_[up|down](), [disable|enable]_nonboot_cpus()”…””}”(hjphjnhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h K¨hjjubah}”(h]”h ]”h"]”h$]”h&]”uh1h¼hj9hžhhŸh¶h Nubeh}”(h]”h ]”h"]”h$]”h&]”jüŒ-”uh1j„hŸh¶h K¦hj(hžhubeh}”(h]”Œ*important-files-and-functions-entry-points”ah ]”h"]”Œ+important files and functions/entry points:”ah$]”h&]”uh1h¡hhýhžhhŸh¶h K¤ubh¢)”}”(hhh]”(h§)”}”(hŒ0II. What are the issues involved in CPU hotplug?”h]”hŒ0II. What are the issues involved in CPU hotplug?”…””}”(hj–hj”hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hj‘hžhhŸh¶h K®ubhÃ)”}”(hŒqThere are some interesting situations involving CPU hotplug and microcode update on the CPUs, as discussed below:”h]”hŒqThere are some interesting situations involving CPU hotplug and microcode update on the CPUs, as discussed below:”…””}”(hj¤hj¢hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h K°hj‘hžhubhÃ)”}”(hŒ¨[Please bear in mind that the kernel requests the microcode images from userspace, using the request_firmware() function defined in drivers/base/firmware_loader/main.c]”h]”hŒ¨[Please bear in mind that the kernel requests the microcode images from userspace, using the request_firmware() function defined in drivers/base/firmware_loader/main.c]”…””}”(hj²hj°hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h K³hj‘hžhubh¸)”}”(hhh]”(h½)”}”(hXùWhen all the CPUs are identical: This is the most common situation and it is quite straightforward: we want to apply the same microcode revision to each of the CPUs. To give an example of x86, the collect_cpu_info() function defined in arch/x86/kernel/microcode_core.c helps in discovering the type of the CPU and thereby in applying the correct microcode revision to it. But note that the kernel does not maintain a common microcode image for the all CPUs, in order to handle case 'b' described below. ”h]”(hÃ)”}”(hŒ When all the CPUs are identical:”h]”hŒ When all the CPUs are identical:”…””}”(hjÇhjÅhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h K¸hjÁubhÃ)”}”(hXÕThis is the most common situation and it is quite straightforward: we want to apply the same microcode revision to each of the CPUs. To give an example of x86, the collect_cpu_info() function defined in arch/x86/kernel/microcode_core.c helps in discovering the type of the CPU and thereby in applying the correct microcode revision to it. But note that the kernel does not maintain a common microcode image for the all CPUs, in order to handle case 'b' described below.”h]”hXÙThis is the most common situation and it is quite straightforward: we want to apply the same microcode revision to each of the CPUs. To give an example of x86, the collect_cpu_info() function defined in arch/x86/kernel/microcode_core.c helps in discovering the type of the CPU and thereby in applying the correct microcode revision to it. But note that the kernel does not maintain a common microcode image for the all CPUs, in order to handle case ‘b’ described below.”…””}”(hjÕhjÓhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h KºhjÁubeh}”(h]”h ]”h"]”h$]”h&]”uh1h¼hj¾hžhhŸh¶h Nubh½)”}”(hX4When some of the CPUs are different than the rest: In this case since we probably need to apply different microcode revisions to different CPUs, the kernel maintains a copy of the correct microcode image for each CPU (after appropriate CPU type/model discovery using functions such as collect_cpu_info()). ”h]”(hÃ)”}”(hŒ2When some of the CPUs are different than the rest:”h]”hŒ2When some of the CPUs are different than the rest:”…””}”(hjíhjëhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h KÃhjçubhÃ)”}”(hŒþIn this case since we probably need to apply different microcode revisions to different CPUs, the kernel maintains a copy of the correct microcode image for each CPU (after appropriate CPU type/model discovery using functions such as collect_cpu_info()).”h]”hŒþIn this case since we probably need to apply different microcode revisions to different CPUs, the kernel maintains a copy of the correct microcode image for each CPU (after appropriate CPU type/model discovery using functions such as collect_cpu_info()).”…””}”(hjûhjùhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h KÅhjçubeh}”(h]”h ]”h"]”h$]”h&]”uh1h¼hj¾hžhhŸh¶h Nubh½)”}”(hX‰When a CPU is physically hot-unplugged and a new (and possibly different type of) CPU is hot-plugged into the system: In the current design of the kernel, whenever a CPU is taken offline during a regular CPU hotplug operation, upon receiving the CPU_DEAD notification (which is sent by the CPU hotplug code), the microcode update driver's callback for that event reacts by freeing the kernel's copy of the microcode image for that CPU. Hence, when a new CPU is brought online, since the kernel finds that it doesn't have the microcode image, it does the CPU type/model discovery afresh and then requests the userspace for the appropriate microcode image for that CPU, which is subsequently applied. For example, in x86, the mc_cpu_callback() function (which is the microcode update driver's callback registered for CPU hotplug events) calls microcode_update_cpu() which would call microcode_init_cpu() in this case, instead of microcode_resume_cpu() when it finds that the kernel doesn't have a valid microcode image. This ensures that the CPU type/model discovery is performed and the right microcode is applied to the CPU after getting it from userspace. ”h]”(hÃ)”}”(hŒuWhen a CPU is physically hot-unplugged and a new (and possibly different type of) CPU is hot-plugged into the system:”h]”hŒuWhen a CPU is physically hot-unplugged and a new (and possibly different type of) CPU is hot-plugged into the system:”…””}”(hjhjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h KËhj ubhÃ)”}”(hX=In the current design of the kernel, whenever a CPU is taken offline during a regular CPU hotplug operation, upon receiving the CPU_DEAD notification (which is sent by the CPU hotplug code), the microcode update driver's callback for that event reacts by freeing the kernel's copy of the microcode image for that CPU.”h]”hXAIn the current design of the kernel, whenever a CPU is taken offline during a regular CPU hotplug operation, upon receiving the CPU_DEAD notification (which is sent by the CPU hotplug code), the microcode update driver’s callback for that event reacts by freeing the kernel’s copy of the microcode image for that CPU.”…””}”(hj!hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h KÎhj ubhÃ)”}”(hXHence, when a new CPU is brought online, since the kernel finds that it doesn't have the microcode image, it does the CPU type/model discovery afresh and then requests the userspace for the appropriate microcode image for that CPU, which is subsequently applied.”h]”hXHence, when a new CPU is brought online, since the kernel finds that it doesn’t have the microcode image, it does the CPU type/model discovery afresh and then requests the userspace for the appropriate microcode image for that CPU, which is subsequently applied.”…””}”(hj/hj-hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h KÔhj ubhÃ)”}”(hXÉFor example, in x86, the mc_cpu_callback() function (which is the microcode update driver's callback registered for CPU hotplug events) calls microcode_update_cpu() which would call microcode_init_cpu() in this case, instead of microcode_resume_cpu() when it finds that the kernel doesn't have a valid microcode image. This ensures that the CPU type/model discovery is performed and the right microcode is applied to the CPU after getting it from userspace.”h]”hXÍFor example, in x86, the mc_cpu_callback() function (which is the microcode update driver’s callback registered for CPU hotplug events) calls microcode_update_cpu() which would call microcode_init_cpu() in this case, instead of microcode_resume_cpu() when it finds that the kernel doesn’t have a valid microcode image. This ensures that the CPU type/model discovery is performed and the right microcode is applied to the CPU after getting it from userspace.”…””}”(hj=hj;hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h KÙhj ubeh}”(h]”h ]”h"]”h$]”h&]”uh1h¼hj¾hžhhŸh¶h Nubh½)”}”(hXHandling microcode update during suspend/hibernate: Strictly speaking, during a CPU hotplug operation which does not involve physically removing or inserting CPUs, the CPUs are not actually powered off during a CPU offline. They are just put to the lowest C-states possible. Hence, in such a case, it is not really necessary to re-apply microcode when the CPUs are brought back online, since they wouldn't have lost the image during the CPU offline operation. This is the usual scenario encountered during a resume after a suspend. However, in the case of hibernation, since all the CPUs are completely powered off, during restore it becomes necessary to apply the microcode images to all the CPUs. [Note that we don't expect someone to physically pull out nodes and insert nodes with a different type of CPUs in-between a suspend-resume or a hibernate/restore cycle.] In the current design of the kernel however, during a CPU offline operation as part of the suspend/hibernate cycle (cpuhp_tasks_frozen is set), the existing copy of microcode image in the kernel is not freed up. And during the CPU online operations (during resume/restore), since the kernel finds that it already has copies of the microcode images for all the CPUs, it just applies them to the CPUs, avoiding any re-discovery of CPU type/model and the need for validating whether the microcode revisions are right for the CPUs or not (due to the above assumption that physical CPU hotplug will not be done in-between suspend/resume or hibernate/restore cycles). ”h]”(hÃ)”}”(hŒ3Handling microcode update during suspend/hibernate:”h]”hŒ3Handling microcode update during suspend/hibernate:”…””}”(hjUhjShžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h KâhjOubhÃ)”}”(hX—Strictly speaking, during a CPU hotplug operation which does not involve physically removing or inserting CPUs, the CPUs are not actually powered off during a CPU offline. They are just put to the lowest C-states possible. Hence, in such a case, it is not really necessary to re-apply microcode when the CPUs are brought back online, since they wouldn't have lost the image during the CPU offline operation.”h]”hX™Strictly speaking, during a CPU hotplug operation which does not involve physically removing or inserting CPUs, the CPUs are not actually powered off during a CPU offline. They are just put to the lowest C-states possible. Hence, in such a case, it is not really necessary to re-apply microcode when the CPUs are brought back online, since they wouldn’t have lost the image during the CPU offline operation.”…””}”(hjchjahžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h KähjOubhÃ)”}”(hŒîThis is the usual scenario encountered during a resume after a suspend. However, in the case of hibernation, since all the CPUs are completely powered off, during restore it becomes necessary to apply the microcode images to all the CPUs.”h]”hŒîThis is the usual scenario encountered during a resume after a suspend. However, in the case of hibernation, since all the CPUs are completely powered off, during restore it becomes necessary to apply the microcode images to all the CPUs.”…””}”(hjqhjohžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h KëhjOubhÃ)”}”(hŒ©[Note that we don't expect someone to physically pull out nodes and insert nodes with a different type of CPUs in-between a suspend-resume or a hibernate/restore cycle.]”h]”hŒ«[Note that we don’t expect someone to physically pull out nodes and insert nodes with a different type of CPUs in-between a suspend-resume or a hibernate/restore cycle.]”…””}”(hjhj}hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h KðhjOubhÃ)”}”(hX•In the current design of the kernel however, during a CPU offline operation as part of the suspend/hibernate cycle (cpuhp_tasks_frozen is set), the existing copy of microcode image in the kernel is not freed up. And during the CPU online operations (during resume/restore), since the kernel finds that it already has copies of the microcode images for all the CPUs, it just applies them to the CPUs, avoiding any re-discovery of CPU type/model and the need for validating whether the microcode revisions are right for the CPUs or not (due to the above assumption that physical CPU hotplug will not be done in-between suspend/resume or hibernate/restore cycles).”h]”hX•In the current design of the kernel however, during a CPU offline operation as part of the suspend/hibernate cycle (cpuhp_tasks_frozen is set), the existing copy of microcode image in the kernel is not freed up. And during the CPU online operations (during resume/restore), since the kernel finds that it already has copies of the microcode images for all the CPUs, it just applies them to the CPUs, avoiding any re-discovery of CPU type/model and the need for validating whether the microcode revisions are right for the CPUs or not (due to the above assumption that physical CPU hotplug will not be done in-between suspend/resume or hibernate/restore cycles).”…””}”(hjhj‹hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h KôhjOubeh}”(h]”h ]”h"]”h$]”h&]”uh1h¼hj¾hžhhŸh¶h Nubeh}”(h]”h ]”h"]”h$]”h&]”höŒ loweralpha”høhhúŒ.”uh1h·hj‘hžhhŸh¶h K¸ubeh}”(h]”Œ.ii-what-are-the-issues-involved-in-cpu-hotplug”ah ]”h"]”Œ0ii. what are the issues involved in cpu hotplug?”ah$]”h&]”uh1h¡hhýhžhhŸh¶h K®ubeh}”(h]”Œ4i-differences-between-cpu-hotplug-and-suspend-to-ram”ah ]”h"]”Œ5i. differences between cpu hotplug and suspend-to-ram”ah$]”h&]”uh1h¡hh£hžhhŸh¶h K ubh¢)”}”(hhh]”(h§)”}”(hŒIII. Known problems”h]”hŒIII. Known problems”…””}”(hj¼hjºhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hj·hžhhŸh¶h MubhÃ)”}”(hŒWAre there any known problems when regular CPU hotplug and suspend race with each other?”h]”hŒWAre there any known problems when regular CPU hotplug and suspend race with each other?”…””}”(hjÊhjÈhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h Mhj·hžhubhÃ)”}”(hŒYes, they are listed below:”h]”hŒYes, they are listed below:”…””}”(hjØhjÖhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h Mhj·hžhubh¸)”}”(hhh]”(h½)”}”(hXÌWhen invoking regular CPU hotplug, the 'tasks_frozen' argument passed to the _cpu_down() and _cpu_up() functions is *always* 0. This might not reflect the true current state of the system, since the tasks could have been frozen by an out-of-band event such as a suspend operation in progress. Hence, the cpuhp_tasks_frozen variable will not reflect the frozen state and the CPU hotplug callbacks which evaluate that variable might execute the wrong code path. ”h]”hÃ)”}”(hXËWhen invoking regular CPU hotplug, the 'tasks_frozen' argument passed to the _cpu_down() and _cpu_up() functions is *always* 0. This might not reflect the true current state of the system, since the tasks could have been frozen by an out-of-band event such as a suspend operation in progress. Hence, the cpuhp_tasks_frozen variable will not reflect the frozen state and the CPU hotplug callbacks which evaluate that variable might execute the wrong code path.”h]”(hŒxWhen invoking regular CPU hotplug, the ‘tasks_frozen’ argument passed to the _cpu_down() and _cpu_up() functions is ”…””}”(hŒtWhen invoking regular CPU hotplug, the 'tasks_frozen' argument passed to the _cpu_down() and _cpu_up() functions is ”hjëhžhhŸNh NubhŒemphasis”“”)”}”(hŒ*always*”h]”hŒalways”…””}”(hhhjöhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jôhjëubhXO 0. This might not reflect the true current state of the system, since the tasks could have been frozen by an out-of-band event such as a suspend operation in progress. Hence, the cpuhp_tasks_frozen variable will not reflect the frozen state and the CPU hotplug callbacks which evaluate that variable might execute the wrong code path.”…””}”(hXO 0. This might not reflect the true current state of the system, since the tasks could have been frozen by an out-of-band event such as a suspend operation in progress. Hence, the cpuhp_tasks_frozen variable will not reflect the frozen state and the CPU hotplug callbacks which evaluate that variable might execute the wrong code path.”hjëhžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h Mhjçubah}”(h]”h ]”h"]”h$]”h&]”uh1h¼hjähžhhŸh¶h Nubh½)”}”(hXTIf a regular CPU hotplug stress test happens to race with the freezer due to a suspend operation in progress at the same time, then we could hit the situation described below: * A regular cpu online operation continues its journey from userspace into the kernel, since the freezing has not yet begun. * Then freezer gets to work and freezes userspace. * If cpu online has not yet completed the microcode update stuff by now, it will now start waiting on the frozen userspace in the TASK_UNINTERRUPTIBLE state, in order to get the microcode image. * Now the freezer continues and tries to freeze the remaining tasks. But due to this wait mentioned above, the freezer won't be able to freeze the cpu online hotplug task and hence freezing of tasks fails. As a result of this task freezing failure, the suspend operation gets aborted.”h]”(hÃ)”}”(hŒ¯If a regular CPU hotplug stress test happens to race with the freezer due to a suspend operation in progress at the same time, then we could hit the situation described below:”h]”hŒ¯If a regular CPU hotplug stress test happens to race with the freezer due to a suspend operation in progress at the same time, then we could hit the situation described below:”…””}”(hjhjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h MhjubhŒ block_quote”“”)”}”(hhh]”j…)”}”(hhh]”(h½)”}”(hŒzA regular cpu online operation continues its journey from userspace into the kernel, since the freezing has not yet begun.”h]”hÃ)”}”(hŒzA regular cpu online operation continues its journey from userspace into the kernel, since the freezing has not yet begun.”h]”hŒzA regular cpu online operation continues its journey from userspace into the kernel, since the freezing has not yet begun.”…””}”(hj5hj3hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h Mhj/ubah}”(h]”h ]”h"]”h$]”h&]”uh1h¼hj,ubh½)”}”(hŒ0Then freezer gets to work and freezes userspace.”h]”hÃ)”}”(hjIh]”hŒ0Then freezer gets to work and freezes userspace.”…””}”(hjIhjKhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h MhjGubah}”(h]”h ]”h"]”h$]”h&]”uh1h¼hj,ubh½)”}”(hŒÀIf cpu online has not yet completed the microcode update stuff by now, it will now start waiting on the frozen userspace in the TASK_UNINTERRUPTIBLE state, in order to get the microcode image.”h]”hÃ)”}”(hŒÀIf cpu online has not yet completed the microcode update stuff by now, it will now start waiting on the frozen userspace in the TASK_UNINTERRUPTIBLE state, in order to get the microcode image.”h]”hŒÀIf cpu online has not yet completed the microcode update stuff by now, it will now start waiting on the frozen userspace in the TASK_UNINTERRUPTIBLE state, in order to get the microcode image.”…””}”(hjdhjbhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h Mhj^ubah}”(h]”h ]”h"]”h$]”h&]”uh1h¼hj,ubh½)”}”(hŒÌNow the freezer continues and tries to freeze the remaining tasks. But due to this wait mentioned above, the freezer won't be able to freeze the cpu online hotplug task and hence freezing of tasks fails. ”h]”hÃ)”}”(hŒËNow the freezer continues and tries to freeze the remaining tasks. But due to this wait mentioned above, the freezer won't be able to freeze the cpu online hotplug task and hence freezing of tasks fails.”h]”hŒÍNow the freezer continues and tries to freeze the remaining tasks. But due to this wait mentioned above, the freezer won’t be able to freeze the cpu online hotplug task and hence freezing of tasks fails.”…””}”(hj|hjzhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h Mhjvubah}”(h]”h ]”h"]”h$]”h&]”uh1h¼hj,ubeh}”(h]”h ]”h"]”h$]”h&]”jüjýuh1j„hŸh¶h Mhj)ubah}”(h]”h ]”h"]”h$]”h&]”uh1j'hjubhÃ)”}”(hŒNAs a result of this task freezing failure, the suspend operation gets aborted.”h]”hŒNAs a result of this task freezing failure, the suspend operation gets aborted.”…””}”(hjœhjšhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhŸh¶h Mhjubeh}”(h]”h ]”h"]”h$]”h&]”uh1h¼hjähžhhŸh¶h Nubeh}”(h]”h ]”h"]”h$]”h&]”höŒarabic”høhhúj¦uh1h·hj·hžhhŸh¶h Mubeh}”(h]”Œiii-known-problems”ah ]”h"]”Œiii. known problems”ah$]”h&]”uh1h¡hh£hžhhŸh¶h Mubeh}”(h]”ŒBinteraction-of-suspend-code-s3-with-the-cpu-hotplug-infrastructure”ah ]”h"]”ŒDinteraction of suspend code (s3) with the cpu hotplug infrastructure”ah$]”h&]”uh1h¡hhhžhhŸh¶h Kubeh}”(h]”h ]”h"]”h$]”h&]”Œsource”h¶uh1hŒcurrent_source”NŒ current_line”NŒsettings”Œdocutils.frontend”ŒValues”“”)”}”(h¦NŒ generator”NŒ datestamp”NŒ source_link”NŒ source_url”NŒ toc_backlinks”Œentry”Œfootnote_backlinks”KŒ sectnum_xform”KŒstrip_comments”NŒstrip_elements_with_classes”NŒ strip_classes”NŒ report_level”KŒ halt_level”KŒexit_status_level”KŒdebug”NŒwarning_stream”NŒ traceback”ˆŒinput_encoding”Œ utf-8-sig”Œinput_encoding_error_handler”Œstrict”Œoutput_encoding”Œutf-8”Œoutput_encoding_error_handler”jèŒerror_encoding”ŒUTF-8”Œerror_encoding_error_handler”Œbackslashreplace”Œ language_code”Œen”Œrecord_dependencies”NŒconfig”NŒ id_prefix”hŒauto_id_prefix”Œid”Œ dump_settings”NŒdump_internals”NŒdump_transforms”NŒdump_pseudo_xml”NŒexpose_internals”NŒstrict_visitor”NŒ_disable_config”NŒ_source”h¶Œ _destination”NŒ _config_files”]”Œ7/var/lib/git/docbuild/linux/Documentation/docutils.conf”aŒpep_references”NŒ pep_base_url”Œhttps://peps.python.org/”Œpep_file_url_template”Œpep-%04d”Œrfc_references”NŒ rfc_base_url”Œ&https://datatracker.ietf.org/doc/html/”Œ tab_width”KŒtrim_footnote_reference_space”‰Œfile_insertion_enabled”ˆŒ raw_enabled”KŒline_length_limit”M'Œsyntax_highlight”Œlong”Œ smart_quotes”ˆŒsmartquotes_locales”]”Œcharacter_level_inline_markup”‰Œdoctitle_xform”‰Œ docinfo_xform”KŒsectsubtitle_xform”‰Œ image_loading”Œlink”Œembed_stylesheet”‰Œcloak_email_addresses”ˆŒsection_self_link”‰Œ embed_images”‰Œenv”NubŒreporter”NŒindirect_targets”]”Œsubstitution_defs”}”Œsubstitution_names”}”Œrefnames”}”Œrefids”}”Œnameids”}”(jÂj¿j´j±jŽj‹j¬j©jºj·uŒ nametypes”}”(jÂNj´NjŽNj¬NjºNuh}”(j¿h£j±hýj‹j(j©j‘j·j·uŒ footnote_refs”}”Œ citation_refs”}”Œ autofootnotes”]”Œautofootnote_refs”]”Œsymbol_footnotes”]”Œsymbol_footnote_refs”]”Œ footnotes”]”Œ citations”]”Œautofootnote_start”KŒsymbol_footnote_start”KŒ id_counter”Œ collections”ŒCounter”“”}”…”R”Œparse_messages”]”hŒsystem_message”“”)”}”(hhh]”hÃ)”}”(hŒ:Enumerated list start value not ordinal-1: "C" (ordinal 3)”h]”hŒ>Enumerated list start value not ordinal-1: “C†(ordinal 3)”…””}”(hhhjPhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÂhjMubah}”(h]”h ]”h"]”h$]”h&]”Œlevel”KŒtype”ŒINFO”Œsource”h¶Œline”Kuh1jKhh£hžhhŸh¶h KubaŒtransform_messages”]”Œ transformer”NŒ include_log”]”Œ decoration”Nhžhub.