Skip to content

Commit

Permalink
powerpc/pseries: implement freeze|thaw_secondary smp ops
Browse files Browse the repository at this point in the history
This currently is hanging in the suspend path with:

  # cd /sys/power/
  # echo 1 > pm_debug_messages
  # echo core > pm_test
  # echo mem >state
  [   28.597952] PM: suspend entry (deep)
  [   28.604185] Filesystems sync: 0.005 seconds
  [   28.640432] Freezing user space processes
  [   28.644731] Freezing user space processes completed (elapsed 0.003 seconds)
  [   28.645398] OOM killer disabled.
  [   28.645579] Freezing remaining freezable tasks
  [   28.650206] Freezing remaining freezable tasks completed (elapsed 0.004 seconds)
  [   28.825795] PM: suspend devices took 0.170 seconds
  [   28.891106] Disabling non-boot CPUs ...
  [   28.897927] premature return from H_JOIN on CPU 2, retrying
  [   28.897943] premature return from H_JOIN on CPU 4, retrying
  [   28.898060] premature return from H_JOIN on CPU 1, retrying
  [   28.898071] premature return from H_JOIN on CPU 3, retrying
  [   28.898082] premature return from H_JOIN on CPU 5, retrying
  [   28.898096] premature return from H_JOIN on CPU 4, retrying
  [   28.898451] premature return from H_JOIN on CPU 3, retrying
  [   28.898469] premature return from H_JOIN on CPU 4, retrying
  [   28.898532] premature return from H_JOIN on CPU 2, retrying
  [   28.898595] premature return from H_JOIN on CPU 4, retrying
  [   33.897589] do_join: 932331 callbacks suppressed
  • Loading branch information
nathanlynch committed Oct 11, 2023
1 parent 136991c commit 40bdd0d
Showing 1 changed file with 76 additions and 0 deletions.
76 changes: 76 additions & 0 deletions arch/powerpc/platforms/pseries/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,78 @@ static __init void pSeries_smp_probe(void)
smp_ops->cause_ipi = dbell_or_ic_cause_ipi;
}

static void do_join(void *arg)
{
cpumask_t *mask = arg;

cpumask_clear_cpu(smp_processor_id(), mask);

while (1) {
long hvrc;

hard_irq_disable();
hvrc = plpar_hcall_norets(H_JOIN);

switch (hvrc) {
case H_SUCCESS:
/*
* The suspend is complete and this cpu has received a
* prod, or we've received a stray prod from unrelated
* code (e.g. paravirt spinlocks) and we need to join
* again.
*
* This barrier orders the return from H_JOIN above vs
* the load of info->done. It pairs with the barrier
* in the wakeup/prod path below.
*/
smp_mb();
if (!cpumask_test_cpu(smp_processor_id(), mask)) {
pr_info_ratelimited("premature return from H_JOIN on CPU %i, retrying",
smp_processor_id());
continue;
}
break;
case H_CONTINUE:
case H_BAD_MODE:
case H_HARDWARE:
default:
pr_err_ratelimited("Unexpected H_JOIN result %ld on CPU %i\n",
hvrc, smp_processor_id());
break;
}

return;
}
}

static cpumask_var_t prod_mask;

static int pseries_cpu_join(int cpu)
{
cpumask_set_cpu(cpu, prod_mask);
smp_call_function_single(cpu, do_join, &prod_mask, 0);
while (cpumask_test_cpu(cpu, prod_mask))
cpu_relax();
return 0;
}

static int pseries_cpu_prod(int target_cpu)
{
long hvrc;
int hwid;

hwid = get_hard_smp_processor_id(target_cpu);
cpumask_set_cpu(target_cpu, prod_mask);
smp_mb();
hvrc = plpar_hcall_norets(H_PROD, hwid);
if (hvrc == H_SUCCESS)
return 0;
pr_err_ratelimited("H_PROD of CPU %u (hwid %d) error: %ld\n",
target_cpu, hwid, hvrc);

return -EIO;
}

static struct smp_ops_t pseries_smp_ops = {
.message_pass = NULL, /* Use smp_muxed_ipi_message_pass */
.cause_ipi = NULL, /* Filled at runtime by pSeries_smp_probe() */
Expand All @@ -248,6 +320,10 @@ static struct smp_ops_t pseries_smp_ops = {
.kick_cpu = smp_pSeries_kick_cpu,
.setup_cpu = smp_setup_cpu,
.cpu_bootable = smp_generic_cpu_bootable,
#ifdef CONFIG_PM_SLEEP_SMP
.freeze_secondary = pseries_cpu_join,
.thaw_secondary = pseries_cpu_prod,
#endif
};

/* This is called very early */
Expand Down

0 comments on commit 40bdd0d

Please sign in to comment.