Fixes for some vintage bugs in handling cache node addition and removal, a
miscellaneous BUG->WARN conversion, and removal of the fragile "by count"
CPU DLPAR code that probably has no users.
Changes since v1:
* Remove set but unused local variable (0day)
* Additional comment cleanup patch
Nathan Lynch (4):
powerpc/pseries/cpuhp: cache node corrections
powerpc/cpuhp: BUG -> WARN conversion in offline path
powerpc/pseries/cpuhp: delete add/remove_by_count code
powerpc/pseries/cpuhp: remove obsolete comment from pseries_cpu_die
arch/powerpc/kernel/sysfs.c | 3 +-
arch/powerpc/platforms/pseries/hotplug-cpu.c | 298 +++++--------------
2 files changed, 75 insertions(+), 226 deletions(-)
--
2.31.1
On pseries, cache nodes in the device tree can be added and removed by the
CPU DLPAR code as well as the partition migration (mobility) code. PowerVM
partitions in dedicated processor mode typically have L2 and L3 cache
nodes.
The CPU DLPAR code has the following shortcomings:
* Cache nodes returned as siblings of a new CPU node by
ibm,configure-connector are silently discarded; only the CPU node is
added to the device tree.
* Cache nodes which become unreferenced in the processor removal path are
not removed from the device tree. This can lead to duplicate nodes when
the post-migration device tree update code replaces cache nodes.
This is long-standing behavior. Presumably it has gone mostly unnoticed
because the two bugs have the property of obscuring each other in common
simple scenarios (e.g. remove a CPU and add it back). Likely you'd notice
only if you cared to inspect the device tree or the sysfs cacheinfo
information.
Booted with two processors:
$ pwd
/sys/firmware/devicetree/base/cpus
$ ls -1d */
l2-cache@2010/
l2-cache@2011/
l3-cache@3110/
l3-cache@3111/
PowerPC,POWER9@0/
PowerPC,POWER9@8/
$ lsprop */l2-cache
l2-cache@2010/l2-cache
00003110 (12560)
l2-cache@2011/l2-cache
00003111 (12561)
PowerPC,POWER9@0/l2-cache
00002010 (8208)
PowerPC,POWER9@8/l2-cache
00002011 (8209)
$ ls /sys/devices/system/cpu/cpu0/cache/
index0 index1 index2 index3
After DLPAR-adding PowerPC,POWER9@10, we see that its associated cache
nodes are absent, its threads' L2+L3 cacheinfo is unpopulated, and it is
missing a cache level in its sched domain hierarchy:
$ ls -1d */
l2-cache@2010/
l2-cache@2011/
l3-cache@3110/
l3-cache@3111/
PowerPC,POWER9@0/
PowerPC,POWER9@10/
PowerPC,POWER9@8/
$ lsprop PowerPC\,POWER9@10/l2-cache
PowerPC,POWER9@10/l2-cache
00002012 (8210)
$ ls /sys/devices/system/cpu/cpu16/cache/
index0 index1
$ grep . /sys/kernel/debug/sched/domains/cpu{0,8,16}/domain*/name
/sys/kernel/debug/sched/domains/cpu0/domain0/name:SMT
/sys/kernel/debug/sched/domains/cpu0/domain1/name:CACHE
/sys/kernel/debug/sched/domains/cpu0/domain2/name:DIE
/sys/kernel/debug/sched/domains/cpu8/domain0/name:SMT
/sys/kernel/debug/sched/domains/cpu8/domain1/name:CACHE
/sys/kernel/debug/sched/domains/cpu8/domain2/name:DIE
/sys/kernel/debug/sched/domains/cpu16/domain0/name:SMT
/sys/kernel/debug/sched/domains/cpu16/domain1/name:DIE
When removing PowerPC,POWER9@8, we see that its cache nodes are left
behind:
$ ls -1d */
l2-cache@2010/
l2-cache@2011/
l3-cache@3110/
l3-cache@3111/
PowerPC,POWER9@0/
When DLPAR is combined with VM migration, we can get duplicate nodes. E.g.
removing one processor, then migrating, adding a processor, and then
migrating again can result in warnings from the OF core during
post-migration device tree updates:
Duplicate name in cpus, renamed to "l2-cache@2011#1"
Duplicate name in cpus, renamed to "l3-cache@3111#1"
and nodes with duplicated phandles in the tree, making lookup behavior
unpredictable:
$ lsprop l[23]-cache@*/ibm,phandle
l2-cache@2010/ibm,phandle
00002010 (8208)
l2-cache@2011#1/ibm,phandle
00002011 (8209)
l2-cache@2011/ibm,phandle
00002011 (8209)
l3-cache@3110/ibm,phandle
00003110 (12560)
l3-cache@3111#1/ibm,phandle
00003111 (12561)
l3-cache@3111/ibm,phandle
00003111 (12561)
Address these issues by:
* Correctly processing siblings of the node returned from
dlpar_configure_connector().
* Removing cache nodes in the CPU remove path when it can be determined
that they are not associated with other CPUs or caches.
Use the of_changeset API in both cases, which allows us to keep the error
handling in this code from becoming more complex while ensuring that the
device tree cannot become inconsistent.
Signed-off-by: Nathan Lynch <redacted>
Fixes: ac71380 ("powerpc/pseries: Add CPU dlpar remove functionality")
Fixes: 90edf18 ("powerpc/pseries: Add CPU dlpar add functionality")
Reviewed-by: Daniel Henrique Barboza <redacted>
Tested-by: Daniel Henrique Barboza <redacted>
---
arch/powerpc/platforms/pseries/hotplug-cpu.c | 75 ++++++++++++++++++--
1 file changed, 71 insertions(+), 4 deletions(-)
@@ -563,7 +584,7 @@ static ssize_t dlpar_cpu_add(u32 drc_index)return-EINVAL;}-rc=dlpar_attach_node(dn,parent);+rc=pseries_cpuhp_attach_nodes(dn);/* Regardless we are done with parent now */of_node_put(parent);
The core DLPAR code supports two actions (add and remove) and three
subtypes of action:
* By DRC index: the action is attempted on a single specified resource.
This is the usual case for processors.
* By indexed count: the action is attempted on a range of resources
beginning at the specified index. This is implemented only by the memory
DLPAR code.
* By count: the lower layer (CPU or memory) is responsible for locating the
specified number of resources to which the action can be applied.
I cannot find any evidence of the "by count" subtype being used by drmgr or
qemu for processors. And when I try to exercise this code, the add case
does not work:
$ ppc64_cpu --smt ; nproc
SMT=8
24
$ printf "cpu remove count 2" > /sys/kernel/dlpar
$ nproc
8
$ printf "cpu add count 2" > /sys/kernel/dlpar
-bash: printf: write error: Invalid argument
$ dmesg | tail -2
pseries-hotplug-cpu: Failed to find enough CPUs (1 of 2) to add
dlpar: Could not handle DLPAR request "cpu add count 2"
$ nproc
8
$ drmgr -c cpu -a -q 2 # this uses the by-index method
Validating CPU DLPAR capability...yes.
CPU 1
CPU 17
$ nproc
24
This is because find_drc_info_cpus_to_add() does not increment drc_index
appropriately during its search.
This is not hard to fix. But the _by_count() functions also have the
property that they attempt to roll back all prior operations if the entire
request cannot be satisfied, even though the rollback itself can encounter
errors. It's not possible to provide transaction-like behavior at this
level, and it's undesirable to have code that can only pretend to do that.
Any users of these functions cannot know what the state of the system is in
the error case. And the error paths are, to my knowledge, impossible to
test without adding custom error injection code.
Summary:
* This code has not worked reliably since its introduction.
* There is no evidence that it is used.
* It contains questionable rollback behaviors in error paths which are
difficult to test.
So let's remove it.
Signed-off-by: Nathan Lynch <redacted>
Fixes: ac71380071d1 ("powerpc/pseries: Add CPU dlpar remove functionality")
Fixes: 90edf184b9b7 ("powerpc/pseries: Add CPU dlpar add functionality")
Fixes: b015f6bc9547 ("powerpc/pseries: Add cpu DLPAR support for drc-info property")
Reviewed-by: Daniel Henrique Barboza <redacted>
Tested-by: Daniel Henrique Barboza <redacted>
---
arch/powerpc/platforms/pseries/hotplug-cpu.c | 218 +------------------
1 file changed, 2 insertions(+), 216 deletions(-)
@@ -741,216 +741,6 @@ static int dlpar_cpu_remove_by_index(u32 drc_index)returnrc;}-staticintfind_dlpar_cpus_to_remove(u32*cpu_drcs,intcpus_to_remove)-{-structdevice_node*dn;-intcpus_found=0;-intrc;--/* We want to find cpus_to_remove + 1 CPUs to ensure we do not-*removethelastCPU.-*/-for_each_node_by_type(dn,"cpu"){-cpus_found++;--if(cpus_found>cpus_to_remove){-of_node_put(dn);-break;-}--/* Note that cpus_found is always 1 ahead of the index-*intothecpu_drcsarray,soweusecpus_found-1-*/-rc=of_property_read_u32(dn,"ibm,my-drc-index",-&cpu_drcs[cpus_found-1]);-if(rc){-pr_warn("Error occurred getting drc-index for %pOFn\n",-dn);-of_node_put(dn);-return-1;-}-}--if(cpus_found<cpus_to_remove){-pr_warn("Failed to find enough CPUs (%d of %d) to remove\n",-cpus_found,cpus_to_remove);-}elseif(cpus_found==cpus_to_remove){-pr_warn("Cannot remove all CPUs\n");-}--returncpus_found;-}--staticintdlpar_cpu_remove_by_count(u32cpus_to_remove)-{-u32*cpu_drcs;-intcpus_found;-intcpus_removed=0;-inti,rc;--pr_debug("Attempting to hot-remove %d CPUs\n",cpus_to_remove);--cpu_drcs=kcalloc(cpus_to_remove,sizeof(*cpu_drcs),GFP_KERNEL);-if(!cpu_drcs)-return-EINVAL;--cpus_found=find_dlpar_cpus_to_remove(cpu_drcs,cpus_to_remove);-if(cpus_found<=cpus_to_remove){-kfree(cpu_drcs);-return-EINVAL;-}--for(i=0;i<cpus_to_remove;i++){-rc=dlpar_cpu_remove_by_index(cpu_drcs[i]);-if(rc)-break;--cpus_removed++;-}--if(cpus_removed!=cpus_to_remove){-pr_warn("CPU hot-remove failed, adding back removed CPUs\n");--for(i=0;i<cpus_removed;i++)-dlpar_cpu_add(cpu_drcs[i]);--rc=-EINVAL;-}else{-rc=0;-}--kfree(cpu_drcs);-returnrc;-}--staticintfind_drc_info_cpus_to_add(structdevice_node*cpus,-structproperty*info,-u32*cpu_drcs,u32cpus_to_add)-{-structof_drc_infodrc;-const__be32*value;-u32count,drc_index;-intcpus_found=0;-inti,j;--if(!info)-return-1;--value=of_prop_next_u32(info,NULL,&count);-if(value)-value++;--for(i=0;i<count;i++){-of_read_drc_info_cell(&info,&value,&drc);-if(strncmp(drc.drc_type,"CPU",3))-break;--drc_index=drc.drc_index_start;-for(j=0;j<drc.num_sequential_elems;j++){-if(dlpar_cpu_exists(cpus,drc_index))-continue;--cpu_drcs[cpus_found++]=drc_index;--if(cpus_found==cpus_to_add)-returncpus_found;--drc_index+=drc.sequential_inc;-}-}--returncpus_found;-}--staticintfind_drc_index_cpus_to_add(structdevice_node*cpus,-u32*cpu_drcs,u32cpus_to_add)-{-intcpus_found=0;-intindex,rc;-u32drc_index;--/* Search the ibm,drc-indexes array for possible CPU drcs to-*add.Notethattheformatoftheibm,drc-indexesarrayis-*thenumberofentriesinthearrayfollowedbythearray-*ofdrcvaluessowestartlookingatindex=1.-*/-index=1;-while(cpus_found<cpus_to_add){-rc=of_property_read_u32_index(cpus,"ibm,drc-indexes",-index++,&drc_index);--if(rc)-break;--if(dlpar_cpu_exists(cpus,drc_index))-continue;--cpu_drcs[cpus_found++]=drc_index;-}--returncpus_found;-}--staticintdlpar_cpu_add_by_count(u32cpus_to_add)-{-structdevice_node*parent;-structproperty*info;-u32*cpu_drcs;-intcpus_added=0;-intcpus_found;-inti,rc;--pr_debug("Attempting to hot-add %d CPUs\n",cpus_to_add);--cpu_drcs=kcalloc(cpus_to_add,sizeof(*cpu_drcs),GFP_KERNEL);-if(!cpu_drcs)-return-EINVAL;--parent=of_find_node_by_path("/cpus");-if(!parent){-pr_warn("Could not find CPU root node in device tree\n");-kfree(cpu_drcs);-return-1;-}--info=of_find_property(parent,"ibm,drc-info",NULL);-if(info)-cpus_found=find_drc_info_cpus_to_add(parent,info,cpu_drcs,cpus_to_add);-else-cpus_found=find_drc_index_cpus_to_add(parent,cpu_drcs,cpus_to_add);--of_node_put(parent);--if(cpus_found<cpus_to_add){-pr_warn("Failed to find enough CPUs (%d of %d) to add\n",-cpus_found,cpus_to_add);-kfree(cpu_drcs);-return-EINVAL;-}--for(i=0;i<cpus_to_add;i++){-rc=dlpar_cpu_add(cpu_drcs[i]);-if(rc)-break;--cpus_added++;-}--if(cpus_added<cpus_to_add){-pr_warn("CPU hot-add failed, removing any added CPUs\n");--for(i=0;i<cpus_added;i++)-dlpar_cpu_remove_by_index(cpu_drcs[i]);--rc=-EINVAL;-}else{-rc=0;-}--kfree(cpu_drcs);-returnrc;-}-intdlpar_cpu(structpseries_hp_errorlog*hp_elog){u32drc_index;
@@ -962,9 +752,7 @@ int dlpar_cpu(struct pseries_hp_errorlog *hp_elog)switch(hp_elog->action){casePSERIES_HP_ELOG_ACTION_REMOVE:-if(hp_elog->id_type==PSERIES_HP_ELOG_ID_DRC_COUNT)-rc=dlpar_cpu_remove_by_count(count);-elseif(hp_elog->id_type==PSERIES_HP_ELOG_ID_DRC_INDEX){+if(hp_elog->id_type==PSERIES_HP_ELOG_ID_DRC_INDEX){rc=dlpar_cpu_remove_by_index(drc_index);/**SettingtheisolationstateofanUNISOLATED/CONFIGURED
@@ -978,9 +766,7 @@ int dlpar_cpu(struct pseries_hp_errorlog *hp_elog)rc=-EINVAL;break;casePSERIES_HP_ELOG_ACTION_ADD:-if(hp_elog->id_type==PSERIES_HP_ELOG_ID_DRC_COUNT)-rc=dlpar_cpu_add_by_count(count);-elseif(hp_elog->id_type==PSERIES_HP_ELOG_ID_DRC_INDEX)+if(hp_elog->id_type==PSERIES_HP_ELOG_ID_DRC_INDEX)rc=dlpar_cpu_add(drc_index);elserc=-EINVAL;
This comment likely refers to the obsolete DLPAR workflow where some
resource state transitions were driven more directly from user space
utilities, but it also seems to contradict itself: "Change isolate state to
Isolate [...]" is at odds with the preceding sentences, and it does not
relate at all to the code that follows.
Remove it to prevent confusion.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/platforms/pseries/hotplug-cpu.c | 5 -----
1 file changed, 5 deletions(-)
If, due to bugs elsewhere, we get into unregister_cpu_online() with a CPU
that isn't marked hotpluggable, we can emit a warning and return an
appropriate error instead of crashing.
Signed-off-by: Nathan Lynch <redacted>
Reviewed-by: Daniel Henrique Barboza <redacted>
---
arch/powerpc/kernel/sysfs.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
@@ -928,7 +928,8 @@ static int unregister_cpu_online(unsigned int cpu)structdevice_attribute*attrs,*pmc_attrs;inti,nattrs;-BUG_ON(!c->hotpluggable);+if(WARN_RATELIMIT(!c->hotpluggable,"cpu %d can't be offlined\n",cpu))+return-EBUSY;#ifdef CONFIG_PPC64if(cpu_has_feature(CPU_FTR_SMT))
From: Daniel Henrique Barboza <hidden> Date: 2021-09-29 00:15:40
On 9/27/21 17:19, Nathan Lynch wrote:
This comment likely refers to the obsolete DLPAR workflow where some
resource state transitions were driven more directly from user space
utilities, but it also seems to contradict itself: "Change isolate state to
Isolate [...]" is at odds with the preceding sentences, and it does not
relate at all to the code that follows.
This comment was added by commit 413f7c405a34, a 2006 commit where Mike
Ellerman moved code from platform/pseries/smp.c into hotplug-cpu.c.
I checked the original code back in smp.c and this comment was added there
by commit 1da177e4c3f41, which is Linus's initial git commit, where he mentions
that he didn't bothered with full history (although it is available somewhere,
allegedly).
This is enough to say that we can't easily see the history behind this comment.
I also believe that we're better of without it since it doesn't make sense
with the current codebase.
Reviewed-by: Daniel Henrique Barboza <redacted>
quoted hunk
Remove it to prevent confusion.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/platforms/pseries/hotplug-cpu.c | 5 -----
1 file changed, 5 deletions(-)
From: Michael Ellerman <mpe@ellerman.id.au> Date: 2021-09-29 05:46:33
Daniel Henrique Barboza [off-list ref] writes:
On 9/27/21 17:19, Nathan Lynch wrote:
quoted
This comment likely refers to the obsolete DLPAR workflow where some
resource state transitions were driven more directly from user space
utilities, but it also seems to contradict itself: "Change isolate state to
Isolate [...]" is at odds with the preceding sentences, and it does not
relate at all to the code that follows.
This comment was added by commit 413f7c405a34, a 2006 commit where Mike
Ellerman moved code from platform/pseries/smp.c into hotplug-cpu.c.
I checked the original code back in smp.c and this comment was added there
by commit 1da177e4c3f41, which is Linus's initial git commit, where he mentions
that he didn't bothered with full history (although it is available somewhere,
allegedly).
This is enough to say that we can't easily see the history behind this comment.
I also believe that we're better of without it since it doesn't make sense
with the current codebase.
It was added by the original CPU hotplug commit for ppc64::
https://github.com/mpe/linux-fullhistory/commit/0e9fd9441cd2113b67b14e739267c9e69761489b
The code was fairly similar:
void __cpu_die(unsigned int cpu)
{
int tries;
int cpu_status;
unsigned int pcpu = get_hard_smp_processor_id(cpu);
for (tries = 0; tries < 5; tries++) {
cpu_status = query_cpu_stopped(pcpu);
if (cpu_status == 0)
break;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ);
}
if (cpu_status != 0) {
printk("Querying DEAD? cpu %i (%i) shows %i\n",
cpu, pcpu, cpu_status);
}
/* Isolation and deallocation are definatly done by
* drslot_chrp_cpu. If they were not they would be
* done here. Change isolate state to Isolate and
* change allocation-state to Unusable.
*/
paca[cpu].xProcStart = 0;
/* So we can recognize if it fails to come up next time. */
cpu_callin_map[cpu] = 0;
}
drslot_chrp_cpu() still exists in drmgr:
https://github.com/ibm-power-utilities/powerpc-utils/blob/e798c4a09fbf0fa0f421e624cfa366a6c405c9fe/src/drmgr/drslot_chrp_cpu.c#L406
I agree the comment is no longer meaningful and can be removed.
It might be good to then add a comment explaining why we need to set
cpu_start = 0.
It's not immediately clear why we need to. When we bring a CPU back
online in smp_pSeries_kick_cpu() we ask RTAS to start it and then
immediately set cpu_start = 1, ie. there isn't a separate step that sets
cpu_start = 1 for hotplugged CPUs.
cheers
This is enough to say that we can't easily see the history behind this comment.
I also believe that we're better of without it since it doesn't make sense
with the current codebase.
It was added by the original CPU hotplug commit for ppc64::
https://github.com/mpe/linux-fullhistory/commit/0e9fd9441cd2113b67b14e739267c9e69761489b
The code was fairly similar:
void __cpu_die(unsigned int cpu)
{
int tries;
int cpu_status;
unsigned int pcpu = get_hard_smp_processor_id(cpu);
for (tries = 0; tries < 5; tries++) {
cpu_status = query_cpu_stopped(pcpu);
if (cpu_status == 0)
break;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ);
}
if (cpu_status != 0) {
printk("Querying DEAD? cpu %i (%i) shows %i\n",
cpu, pcpu, cpu_status);
}
/* Isolation and deallocation are definatly done by
* drslot_chrp_cpu. If they were not they would be
* done here. Change isolate state to Isolate and
* change allocation-state to Unusable.
*/
paca[cpu].xProcStart = 0;
/* So we can recognize if it fails to come up next time. */
cpu_callin_map[cpu] = 0;
}
drslot_chrp_cpu() still exists in drmgr:
https://github.com/ibm-power-utilities/powerpc-utils/blob/e798c4a09fbf0fa0f421e624cfa366a6c405c9fe/src/drmgr/drslot_chrp_cpu.c#L406
I agree the comment is no longer meaningful and can be removed.
Thanks for providing this background.
It might be good to then add a comment explaining why we need to set
cpu_start = 0.
Sure, I can take that as a follow-up. Or perhaps it should be moved to
the online path.
It's not immediately clear why we need to. When we bring a CPU back
online in smp_pSeries_kick_cpu() we ask RTAS to start it and then
immediately set cpu_start = 1, ie. there isn't a separate step that sets
cpu_start = 1 for hotplugged CPUs.
Hmm I'm not following the distinction you seem to be drawing between
bringing a CPU back online and a hotplugged CPU. kick_cpu is used in all
cases AFAIK.
From: Michael Ellerman <hidden> Date: 2021-10-11 12:11:47
On Mon, 27 Sep 2021 15:19:29 -0500, Nathan Lynch wrote:
Fixes for some vintage bugs in handling cache node addition and removal, a
miscellaneous BUG->WARN conversion, and removal of the fragile "by count"
CPU DLPAR code that probably has no users.
Changes since v1:
* Remove set but unused local variable (0day)
* Additional comment cleanup patch
[...]
From: Michael Ellerman <mpe@ellerman.id.au> Date: 2021-10-11 12:35:09
Nathan Lynch [off-list ref] writes:
Michael Ellerman [off-list ref] writes:
quoted
Daniel Henrique Barboza [off-list ref] writes:
quoted
This is enough to say that we can't easily see the history behind this comment.
I also believe that we're better of without it since it doesn't make sense
with the current codebase.
It was added by the original CPU hotplug commit for ppc64::
https://github.com/mpe/linux-fullhistory/commit/0e9fd9441cd2113b67b14e739267c9e69761489b
The code was fairly similar:
void __cpu_die(unsigned int cpu)
{
int tries;
int cpu_status;
unsigned int pcpu = get_hard_smp_processor_id(cpu);
for (tries = 0; tries < 5; tries++) {
cpu_status = query_cpu_stopped(pcpu);
if (cpu_status == 0)
break;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ);
}
if (cpu_status != 0) {
printk("Querying DEAD? cpu %i (%i) shows %i\n",
cpu, pcpu, cpu_status);
}
/* Isolation and deallocation are definatly done by
* drslot_chrp_cpu. If they were not they would be
* done here. Change isolate state to Isolate and
* change allocation-state to Unusable.
*/
paca[cpu].xProcStart = 0;
/* So we can recognize if it fails to come up next time. */
cpu_callin_map[cpu] = 0;
}
drslot_chrp_cpu() still exists in drmgr:
https://github.com/ibm-power-utilities/powerpc-utils/blob/e798c4a09fbf0fa0f421e624cfa366a6c405c9fe/src/drmgr/drslot_chrp_cpu.c#L406
I agree the comment is no longer meaningful and can be removed.
Thanks for providing this background.
quoted
It might be good to then add a comment explaining why we need to set
cpu_start = 0.
Sure, I can take that as a follow-up. Or perhaps it should be moved to
the online path.
Yeah possibly.
quoted
It's not immediately clear why we need to. When we bring a CPU back
online in smp_pSeries_kick_cpu() we ask RTAS to start it and then
immediately set cpu_start = 1, ie. there isn't a separate step that sets
cpu_start = 1 for hotplugged CPUs.
Hmm I'm not following the distinction you seem to be drawing between
bringing a CPU back online and a hotplugged CPU. kick_cpu is used in all
cases AFAIK.
Yeah that wasn't very clear, reading it back I have half confused myself.
At boot we need the paca->cpu_start flag because some CPUs can be
spinning in generic_secondary_common_init, in head_64.S.
ie. they're not in RTAS, they're spinning in kernel code, and the only
thing that stops them coming "online" in the Linux sense is
paca->cpu_start.
You can see that in pseries/smp.c:
static inline int smp_startup_cpu(unsigned int lcpu)
{
...
if (cpumask_test_cpu(lcpu, of_spin_mask))
/* Already started by OF and sitting in spin loop */
return 1;
We also hit that case when kexec'ing, where all the secondaries come in
that way.
On the other hand when we offline a CPU, we set paca->cpu_start = 0, in
pseries_cpu_die(), and then we return the CPU to RTAS.
The only way it *should* come back online is via smp_pSeries_kick_cpu(),
which calls smp_startup_cpu() to bring the CPU out of RTAS, and then
smp_pSeries_kick_cpu() immediately sets cpu_start = 1.
So the sequence is:
CPU goes offline from Linux POV
paca->cpu_start = 0;
CPU offline in RTAS
...
CPU brought out of RTAS
paca->cpu_start = 1;
CPU comes back online from Linux POV
But I guess I kind of answered my own question above, where I said
*should*. Clearing paca->cpu_start when we offline the CPU gives us a
little bit of backup if the CPU comes out of RTAS unexpectedly. ie. it
would then spin on paca->cpu_start, rather than spontaneously coming
back into Linux when we weren't expecting it.
cheers