This series aims to improve the pseries-specific partition migration
and hibernation implementation, part of which has been living in
kernel/rtas.c. Most of that code is eliminated or moved to
platforms/pseries, and the following major functional changes are
made:
- Use stop_machine() instead of on_each_cpu() to avoid deadlock in the
join/suspend sequence.
- Retry the join/suspend sequence on errors that are likely to be
transient. This is a mitigation for the fact that drivers currently
have no way to prepare for an impending partition suspension,
sometimes resulting in a virtual adapter being in a state which
causes the platform to fail the suspend call.
- Request cancellation of the migration via H_VASI_SIGNAL if Linux is
going to error out of the suspend attempt. This allows the
management console and other entities to promptly clean up their
operations instead of relying on long timeouts to fail the
migration.
- Little-endian users of ibm,suspend-me, ibm,update-nodes and
ibm,update-properties via sys_rtas are blocked when
CONFIG_PPC_RTAS_FILTERS is enabled.
- Legacy user space code (drmgr) historically has driven the migration
process by using sys_rtas to separately call ibm,suspend-me,
ibm,activate-firmware, and ibm,update-nodes/properties, in that
order. With these changes, when sys_rtas() dispatches
ibm,suspend-me, the kernel performs the device tree update and
firmware activation before returning. This is more reliable, and
drmgr does not seem bothered by it.
- If the H_VASI_STATE hcall is absent, the implementation proceeds
with the suspend instead of erroring out. This allows us to exercise
these code paths in QEMU.
Changes since v1:
- Drop "powerpc/rtas: move rtas_call_reentrant() out of pseries
guards". rtas_call_reentrant() actually is pseries-specific and this
broke builds without CONFIG_PPC_PSERIES set.
- Simplify polling logic in wait_for_vasi_session_suspending().
("powerpc/pseries/mobility: extract VASI session polling logic")
- Use direct return instead of goto in pseries_migrate_partition().
("powerpc/pseries/mobility: use stop_machine for join/suspend")
- Change dispatch of ibm,suspend-me in rtas syscall path to use
conventional config symbol guards instead of a weak function.
("powerpc/rtas: dispatch partition migration requests to pseries")
- Fix refcount imbalance in add_dt_node() error path.
("powerpc/pseries/mobility: refactor node lookup during DT update")
Nathan Lynch (28):
powerpc/rtas: prevent suspend-related sys_rtas use on LE
powerpc/rtas: complete ibm,suspend-me status codes
powerpc/rtas: rtas_ibm_suspend_me -> rtas_ibm_suspend_me_unsafe
powerpc/rtas: add rtas_ibm_suspend_me()
powerpc/rtas: add rtas_activate_firmware()
powerpc/hvcall: add token and codes for H_VASI_SIGNAL
powerpc/pseries/mobility: don't error on absence of ibm,update-nodes
powerpc/pseries/mobility: add missing break to default case
powerpc/pseries/mobility: error message improvements
powerpc/pseries/mobility: use rtas_activate_firmware() on resume
powerpc/pseries/mobility: extract VASI session polling logic
powerpc/pseries/mobility: use stop_machine for join/suspend
powerpc/pseries/mobility: signal suspend cancellation to platform
powerpc/pseries/mobility: retry partition suspend after error
powerpc/rtas: dispatch partition migration requests to pseries
powerpc/rtas: remove rtas_ibm_suspend_me_unsafe()
powerpc/pseries/hibernation: drop pseries_suspend_begin() from suspend
ops
powerpc/pseries/hibernation: pass stream id via function arguments
powerpc/pseries/hibernation: remove pseries_suspend_cpu()
powerpc/machdep: remove suspend_disable_cpu()
powerpc/rtas: remove rtas_suspend_cpu()
powerpc/pseries/hibernation: switch to rtas_ibm_suspend_me()
powerpc/rtas: remove unused rtas_suspend_last_cpu()
powerpc/pseries/hibernation: remove redundant cacheinfo update
powerpc/pseries/hibernation: perform post-suspend fixups later
powerpc/pseries/hibernation: remove prepare_late() callback
powerpc/rtas: remove unused rtas_suspend_me_data
powerpc/pseries/mobility: refactor node lookup during DT update
arch/powerpc/include/asm/hvcall.h | 9 +
arch/powerpc/include/asm/machdep.h | 1 -
arch/powerpc/include/asm/rtas-types.h | 8 -
arch/powerpc/include/asm/rtas.h | 17 +-
arch/powerpc/kernel/rtas.c | 243 ++++++---------
arch/powerpc/platforms/pseries/mobility.c | 358 ++++++++++++++++++----
arch/powerpc/platforms/pseries/suspend.c | 79 +----
7 files changed, 415 insertions(+), 300 deletions(-)
--
2.28.0
While drmgr has had work in some areas to make its RTAS syscall
interactions endian-neutral, its code for performing partition
migration via the syscall has never worked on LE. While it is able to
complete ibm,suspend-me successfully, it crashes when attempting the
subsequent ibm,update-nodes call.
drmgr is the only known (or plausible) user of ibm,suspend-me,
ibm,update-nodes, and ibm,update-properties, so allow them only in
big-endian configurations.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/kernel/rtas.c | 2 ++
1 file changed, 2 insertions(+)
The pseries partition suspend sequence requires that all active CPUs
call H_JOIN, which suspends all but one of them with interrupts
disabled. The "chosen" CPU is then to call ibm,suspend-me to complete
the suspend. Upon returning from ibm,suspend-me, the chosen CPU is to
use H_PROD to wake the joined CPUs.
Using on_each_cpu() for this, as rtas_ibm_suspend_me() does to
implement partition migration, is susceptible to deadlock with other
users of on_each_cpu() and with users of stop_machine APIs. The
callback passed to on_each_cpu() is not allowed to synchronize with
other CPUs in the way it is used here.
Complicating the fix is the fact that rtas_ibm_suspend_me() also
occupies the function name that should be used to provide a more
conventional wrapper for ibm,suspend-me. Rename rtas_ibm_suspend_me()
to rtas_ibm_suspend_me_unsafe() to free up the name and indicate that
it should not gain users.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/include/asm/rtas.h | 2 +-
arch/powerpc/kernel/rtas.c | 6 +++---
arch/powerpc/platforms/pseries/mobility.c | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
@@ -257,7 +257,7 @@ extern int rtas_set_indicator_fast(int indicator, int index, int new_value);externvoidrtas_progress(char*s,unsignedshorthex);externintrtas_suspend_cpu(structrtas_suspend_me_data*data);externintrtas_suspend_last_cpu(structrtas_suspend_me_data*data);-externintrtas_ibm_suspend_me(u64handle);+intrtas_ibm_suspend_me_unsafe(u64handle);structrtc_time;externtime64_trtas_get_boot_time(void);
@@ -949,7 +949,7 @@ int rtas_call_reentrant(int token, int nargs, int nret, int *outputs, ...)}#else /* CONFIG_PPC_PSERIES */-intrtas_ibm_suspend_me(u64handle)+intrtas_ibm_suspend_me_unsafe(u64handle){return-ENOSYS;}
Now that the name is available, provide a simple wrapper for
ibm,suspend-me which returns both a Linux errno and optionally the
actual RTAS status to the caller.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/include/asm/rtas.h | 1 +
arch/powerpc/kernel/rtas.c | 57 +++++++++++++++++++++++++++++++++
2 files changed, 58 insertions(+)
@@ -684,6 +684,63 @@ int rtas_set_indicator_fast(int indicator, int index, int new_value)returnrc;}+/**+*rtas_ibm_suspend_me()-Callibm,suspend-metosuspendtheLPAR.+*+*@fw_status:RTAScallstatuswillbeplacedhereifnotNULL.+*+*rtas_ibm_suspend_me()shouldbecalledonlyonaCPUwhichhas+*receivedH_CONTINUEfromtheH_JOINhcall.AllotheractiveCPUs+*shouldbewaitingtoreturnfromH_JOIN.+*+*rtas_ibm_suspend_me()maysuspendexecutionoftheOS+*indefinitely.Callersshouldtakeappropriatemeasuresuponreturn,suchas+*resettingwatchdogfacilities.+*+*Callersmaychoosetoretrythiscallif@fw_statusis+*%RTAS_THREADS_ACTIVE.+*+*Return:+*0-Thepartitionhasresumedfromsuspend,possiblyafter+*migrationtoadifferenthost.+*-ECANCELED-Theoperationwasaborted.+*-EAGAIN-TherewereotherCPUsnotinH_JOINatthetimeofthecall.+*-EBUSY-Someotherconditionpreventedthesuspendfromsucceeding.+*-EIO-Hardware/platformerror.+*/+intrtas_ibm_suspend_me(int*fw_status)+{+intfwrc;+intret;++fwrc=rtas_call(rtas_token("ibm,suspend-me"),0,1,NULL);++switch(fwrc){+case0:+ret=0;+break;+caseRTAS_SUSPEND_ABORTED:+ret=-ECANCELED;+break;+caseRTAS_THREADS_ACTIVE:+ret=-EAGAIN;+break;+caseRTAS_NOT_SUSPENDABLE:+caseRTAS_OUTSTANDING_COPROC:+ret=-EBUSY;+break;+case-1:+default:+ret=-EIO;+break;+}++if(fw_status)+*fw_status=fwrc;++returnret;+}+void__noreturnrtas_restart(char*cmd){if(rtas_flash_term_hook)
Provide a documented wrapper function for the ibm,activate-firmware
service, which must be called after a partition migration or
hibernation.
If the function is absent or the call fails, the OS will continue to
run normally with the current firmware, so there is no need to perform
any recovery. Just log it and continue.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/include/asm/rtas.h | 1 +
arch/powerpc/kernel/rtas.c | 30 ++++++++++++++++++++++++++++++
2 files changed, 31 insertions(+)
Treat the absence of the ibm,update-nodes function as benign instead
of reporting an error. If the platform does not provide that facility,
it's not a problem for Linux.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/platforms/pseries/mobility.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
H_VASI_SIGNAL can be used by a partition to request cancellation of
its migration. To be used in future changes.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/include/asm/hvcall.h | 9 +++++++++
1 file changed, 9 insertions(+)
@@ -155,6 +155,14 @@#define H_VASI_RESUMED 5#define H_VASI_COMPLETED 6+/* VASI signal codes. Only the Cancel code is valid for H_VASI_SIGNAL. */+#define H_VASI_SIGNAL_CANCEL 1+#define H_VASI_SIGNAL_ABORT 2+#define H_VASI_SIGNAL_SUSPEND 3+#define H_VASI_SIGNAL_COMPLETE 4+#define H_VASI_SIGNAL_ENABLE 5+#define H_VASI_SIGNAL_FAILOVER 6+/* Each control block has to be on a 4K boundary */#define H_CB_ALIGNMENT 4096
update_dt_node() has a switch statement where the default case lacks a
break statement.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/platforms/pseries/mobility.c | 1 +
1 file changed, 1 insertion(+)
It's incorrect to abort post-suspend processing if
ibm,activate-firmware isn't available. Use rtas_activate_firmware(),
which logs this condition appropriately and allows us to proceed.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/platforms/pseries/mobility.c | 15 +--------------
1 file changed, 1 insertion(+), 14 deletions(-)
@@ -312,21 +312,8 @@ int pseries_devicetree_update(s32 scope)voidpost_mobility_fixup(void){intrc;-intactivate_fw_token;-activate_fw_token=rtas_token("ibm,activate-firmware");-if(activate_fw_token==RTAS_UNKNOWN_SERVICE){-printk(KERN_ERR"Could not make post-mobility "-"activate-fw call.\n");-return;-}--do{-rc=rtas_call(activate_fw_token,0,1,NULL);-}while(rtas_busy_delay(rc));--if(rc)-printk(KERN_ERR"Post-mobility activate-fw failed: %d\n",rc);+rtas_activate_firmware();/**Wedon'twantCPUstogoonline/offlinewhilethedevice
The partition suspend sequence as specified in the platform
architecture requires that all active processor threads call
H_JOIN, which:
- suspends the calling thread until it is the target of
an H_PROD; or
- immediately returns H_CONTINUE, if the calling thread is the last to
call H_JOIN. This thread is expected to call ibm,suspend-me to
completely suspend the partition.
Upon returning from ibm,suspend-me the calling thread must wake all
others using H_PROD.
rtas_ibm_suspend_me_unsafe() uses on_each_cpu() to implement this
protocol, but because of its synchronizing nature this is susceptible
to deadlock versus users of stop_machine() or other callers of
on_each_cpu().
Not only is stop_machine() intended for use cases like this, it
handles error propagation and allows us to keep the data shared
between CPUs minimal: a single atomic counter which ensures exactly
one CPU will wake the others from their joined states.
Switch the migration code to use stop_machine() and a less complex
local implementation of the H_JOIN/ibm,suspend-me logic, which
carries additional benefits:
- more informative error reporting, appropriately ratelimited
- resets the lockup detector / watchdog on resume to prevent lockup
warnings when the OS has been suspended for a time exceeding the
threshold.
Fixes: 91dc182ca6e2 ("[PATCH] powerpc: special-case ibm,suspend-me RTAS call")
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/platforms/pseries/mobility.c | 132 ++++++++++++++++++++--
1 file changed, 125 insertions(+), 7 deletions(-)
@@ -405,6 +407,128 @@ static int wait_for_vasi_session_suspending(u64 handle)returnret;}+staticvoidprod_single(unsignedinttarget_cpu)+{+longhvrc;+inthwid;++hwid=get_hard_smp_processor_id(target_cpu);+hvrc=plpar_hcall_norets(H_PROD,hwid);+if(hvrc==H_SUCCESS)+return;+pr_err_ratelimited("H_PROD of CPU %u (hwid %d) error: %ld\n",+target_cpu,hwid,hvrc);+}++staticvoidprod_others(void)+{+unsignedintcpu;++for_each_online_cpu(cpu){+if(cpu!=smp_processor_id())+prod_single(cpu);+}+}++staticu16clamp_slb_size(void)+{+u16prev=mmu_slb_size;++slb_set_size(SLB_MIN_SIZE);++returnprev;+}++staticintdo_suspend(void)+{+u16saved_slb_size;+intstatus;+intret;++pr_info("calling ibm,suspend-me on CPU %i\n",smp_processor_id());++/*+*ThedestinationprocessormodelmayhavefewerSLBentries+*thanthesource.Wereducemmu_slb_sizetoasafeminimum+*beforesuspendinginordertominimizethepossibilityof+*programmingnon-existententriesonthedestination.If+*suspendfails,werestoreitbeforereturning.Onsuccess+*theOFreconfigpathwillupdateitfromthenewdevice+*treeafterresumingonthedestination.+*/+saved_slb_size=clamp_slb_size();++ret=rtas_ibm_suspend_me(&status);+if(ret!=0){+pr_err("ibm,suspend-me error: %d\n",status);+slb_set_size(saved_slb_size);+}++returnret;+}++staticintdo_join(void*arg)+{+atomic_t*counter=arg;+longhvrc;+intret;++/* Must ensure MSR.EE off for H_JOIN. */+hard_irq_disable();+hvrc=plpar_hcall_norets(H_JOIN);++switch(hvrc){+caseH_CONTINUE:+/*+*AllotherCPUsareofflineorinH_JOIN.ThisCPU+*attemptsthesuspend.+*/+ret=do_suspend();+break;+caseH_SUCCESS:+/*+*Thesuspendiscompleteandthiscpuhasreceiveda+*prod.+*/+ret=0;+break;+caseH_BAD_MODE:+caseH_HARDWARE:+default:+ret=-EIO;+pr_err_ratelimited("H_JOIN error %ld on CPU %i\n",+hvrc,smp_processor_id());+break;+}++if(atomic_inc_return(counter)==1){+pr_info("CPU %u waking all threads\n",smp_processor_id());+prod_others();+}+/*+*Executionmayhavebeensuspendedforseveralseconds,so+*resetthewatchdog.+*/+touch_nmi_watchdog();+returnret;+}++staticintpseries_migrate_partition(u64handle)+{+atomic_tcounter=ATOMIC_INIT(0);+intret;++ret=wait_for_vasi_session_suspending(handle);+if(ret)+returnret;++ret=stop_machine(do_join,&counter,cpu_online_mask);+if(ret==0)+post_mobility_fixup();++returnret;+}+staticssize_tmigration_store(structclass*class,structclass_attribute*attr,constchar*buf,size_tcount)
@@ -416,16 +540,10 @@ static ssize_t migration_store(struct class *class,if(rc)returnrc;-rc=wait_for_vasi_session_suspending(streamid);+rc=pseries_migrate_partition(streamid);if(rc)returnrc;-rc=rtas_ibm_suspend_me_unsafe(streamid);-if(rc)-returnrc;--post_mobility_fixup();-returncount;}
- Convert printk(KERN_ERR) to pr_err().
- Include errno in property update failure message.
- Remove reference to "Post-mobility" from device tree update message:
with pr_err() it will have a "mobility:" prefix.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/platforms/pseries/mobility.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
If we're returning an error to user space, use H_VASI_SIGNAL to send a
cancellation request to the platform. This isn't strictly required but
it communicates that Linux will not attempt to complete the suspend,
which allows the various entities involved to promptly end the
operation in progress.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/platforms/pseries/mobility.c | 31 +++++++++++++++++++++++
1 file changed, 31 insertions(+)
This is a mitigation for the relatively rare occurrence where a
virtual IOA can be in a transient state that prevents the
suspend/migration from succeeding, resulting in an error from
ibm,suspend-me.
If the join/suspend sequence returns an error, it is acceptable to
retry as long as the VASI suspend session state is still
"Suspending" (i.e. the platform is still waiting for the OS to
suspend).
Retry a few times on suspend failure while this condition holds,
progressively increasing the delay between attempts. We don't want to
retry indefinitey because firmware emits an error log event on each
unsuccessful attempt.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/platforms/pseries/mobility.c | 59 ++++++++++++++++++++++-
1 file changed, 57 insertions(+), 2 deletions(-)
The behavior of rtas_ibm_suspend_me_unsafe() is to return -EAGAIN to
the caller until the specified VASI suspend session state makes the
transition from H_VASI_ENABLED to H_VASI_SUSPENDING. In the interest
of separating concerns to prepare for a new implementation of the
join/suspend sequence, extract VASI session polling logic into a
couple of local functions. Waiting for the session state to reach
H_VASI_SUSPENDING before calling rtas_ibm_suspend_me_unsafe() ensures
that we will never get an EAGAIN result necessitating a retry. No
user-visible change in behavior is intended.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/platforms/pseries/mobility.c | 69 +++++++++++++++++++++--
1 file changed, 64 insertions(+), 5 deletions(-)
sys_rtas() cannot call ibm,suspend-me directly in the same way it
handles other inputs. Instead it must dispatch the request to code
that can first perform the H_JOIN sequence before any call to
ibm,suspend-me can succeed. Over time kernel/rtas.c has accreted a fair
amount of platform-specific code to implement this.
Since a different, more robust implementation of the suspend sequence
is now in the pseries platform code, we want to dispatch the request
there.
Note that invoking ibm,suspend-me via the RTAS syscall is all but
deprecated; this change preserves ABI compatibility for old programs
while providing to them the benefit of the new partition suspend
implementation. This is a behavior change in that the kernel performs
the device tree update and firmware activation before returning, but
experimentation indicates this is tolerated fine by legacy user space.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/include/asm/rtas.h | 5 +++++
arch/powerpc/kernel/rtas.c | 2 +-
arch/powerpc/platforms/pseries/mobility.c | 5 +++++
3 files changed, 11 insertions(+), 1 deletion(-)
rtas_ibm_suspend_me_unsafe() is now unused; remove it and
rtas_percpu_suspend_me() which becomes unused as a result.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/include/asm/rtas.h | 1 -
arch/powerpc/kernel/rtas.c | 67 +--------------------------------
2 files changed, 1 insertion(+), 67 deletions(-)
@@ -258,7 +258,6 @@ extern int rtas_set_indicator_fast(int indicator, int index, int new_value);externvoidrtas_progress(char*s,unsignedshorthex);externintrtas_suspend_cpu(structrtas_suspend_me_data*data);externintrtas_suspend_last_cpu(structrtas_suspend_me_data*data);-intrtas_ibm_suspend_me_unsafe(u64handle);intrtas_ibm_suspend_me(int*fw_status);structrtc_time;
@@ -925,66 +925,6 @@ int rtas_suspend_cpu(struct rtas_suspend_me_data *data)return__rtas_suspend_cpu(data,0);}-staticvoidrtas_percpu_suspend_me(void*info)-{-__rtas_suspend_cpu((structrtas_suspend_me_data*)info,1);-}--intrtas_ibm_suspend_me_unsafe(u64handle)-{-longstate;-longrc;-unsignedlongretbuf[PLPAR_HCALL_BUFSIZE];-structrtas_suspend_me_datadata;-DECLARE_COMPLETION_ONSTACK(done);--if(!rtas_service_present("ibm,suspend-me"))-return-ENOSYS;--/* Make sure the state is valid */-rc=plpar_hcall(H_VASI_STATE,retbuf,handle);--state=retbuf[0];--if(rc){-printk(KERN_ERR"rtas_ibm_suspend_me: vasi_state returned %ld\n",rc);-returnrc;-}elseif(state==H_VASI_ENABLED){-return-EAGAIN;-}elseif(state!=H_VASI_SUSPENDING){-printk(KERN_ERR"rtas_ibm_suspend_me: vasi_state returned state %ld\n",-state);-return-EIO;-}--atomic_set(&data.working,0);-atomic_set(&data.done,0);-atomic_set(&data.error,0);-data.token=rtas_token("ibm,suspend-me");-data.complete=&done;--lock_device_hotplug();--cpu_hotplug_disable();--/* Call function on all CPUs. One of us will make the-*rtascall-*/-on_each_cpu(rtas_percpu_suspend_me,&data,0);--wait_for_completion(&done);--if(atomic_read(&data.error)!=0)-printk(KERN_ERR"Error doing global join\n");---cpu_hotplug_enable();--unlock_device_hotplug();--returnatomic_read(&data.error);-}-/***rtas_call_reentrant()-Usedforreentrantrtascalls*@token:TokenfordesiredreentrantRTAScall
@@ -1035,12 +975,7 @@ int rtas_call_reentrant(int token, int nargs, int nret, int *outputs, ...)returnret;}-#else /* CONFIG_PPC_PSERIES */-intrtas_ibm_suspend_me_unsafe(u64handle)-{-return-ENOSYS;-}-#endif+#endif /* CONFIG_PPC_PSERIES *//***FindaspecificpserieserrorloginanRTASextendedeventlog.
There is no need for the stream id to be a file-global variable; pass
it from hibernate_store() to pseries_suspend_begin() for the
H_VASI_STATE call.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/platforms/pseries/suspend.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
There are three ways pseries_suspend_begin() can be reached:
1. When "mem" is written to /sys/power/state:
kobj_attr_store()
-> state_store()
-> pm_suspend()
-> suspend_devices_and_enter()
-> pseries_suspend_begin()
This never works because there is no way to supply a valid stream id
using this interface, and H_VASI_STATE is called with a stream id of
zero. So this call path is useless at best.
2. When a stream id is written to /sys/devices/system/power/hibernate.
pseries_suspend_begin() is polled directly from store_hibernate()
until the stream is in the "Suspending" state (i.e. the platform is
ready for the OS to suspend execution):
dev_attr_store()
-> store_hibernate()
-> pseries_suspend_begin()
3. When a stream id is written to /sys/devices/system/power/hibernate
(continued). After #2, pseries_suspend_begin() is called once again
from the pm core:
dev_attr_store()
-> store_hibernate()
-> pm_suspend()
-> suspend_devices_and_enter()
-> pseries_suspend_begin()
This is redundant because the VASI suspend state is already known to
be Suspending.
The begin() callback of platform_suspend_ops is optional, so we can
simply remove that assignment with no loss of function.
Fixes: 32d8ad4e621d ("powerpc/pseries: Partition hibernation support")
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/platforms/pseries/suspend.c | 1 -
1 file changed, 1 deletion(-)
Since commit 48f6e7f6d948 ("powerpc/pseries: remove cede offline state
for CPUs"), ppc_md.suspend_disable_cpu() is no longer used and all
CPUs (save one) are placed into true offline state as opposed to
H_JOIN. So pseries_suspend_cpu() is effectively unused; remove it.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/platforms/pseries/suspend.c | 15 ---------------
1 file changed, 15 deletions(-)
There are no users left of the suspend_disable_cpu() callback, remove
it.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/include/asm/machdep.h | 1 -
1 file changed, 1 deletion(-)
rtas_suspend_cpu() no longer has users; remove it and
__rtas_suspend_cpu() which now becomes unused as well.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/include/asm/rtas.h | 1 -
arch/powerpc/kernel/rtas.c | 52 ---------------------------------
2 files changed, 53 deletions(-)
@@ -873,58 +873,6 @@ int rtas_suspend_last_cpu(struct rtas_suspend_me_data *data)return__rtas_suspend_last_cpu(data,0);}-staticint__rtas_suspend_cpu(structrtas_suspend_me_data*data,intwake_when_done)-{-longrc=H_SUCCESS;-unsignedlongmsr_save;-intcpu;--atomic_inc(&data->working);--/* really need to ensure MSR.EE is off for H_JOIN */-msr_save=mfmsr();-mtmsr(msr_save&~(MSR_EE));--while(rc==H_SUCCESS&&!atomic_read(&data->done)&&!atomic_read(&data->error))-rc=plpar_hcall_norets(H_JOIN);--mtmsr(msr_save);--if(rc==H_SUCCESS){-/* This cpu was prodded and the suspend is complete. */-gotoout;-}elseif(rc==H_CONTINUE){-/* All other cpus are in H_JOIN, this cpu does-*thesuspend.-*/-return__rtas_suspend_last_cpu(data,wake_when_done);-}else{-printk(KERN_ERR"H_JOIN on cpu %i failed with rc = %ld\n",-smp_processor_id(),rc);-atomic_set(&data->error,rc);-}--if(wake_when_done){-atomic_set(&data->done,1);--/* This cpu did the suspend or got an error; in either case,-*weneedtoprodallotherothercpusoutofjoinstate.-*Extraprodsareharmless.-*/-for_each_online_cpu(cpu)-plpar_hcall_norets(H_PROD,get_hard_smp_processor_id(cpu));-}-out:-if(atomic_dec_return(&data->working)==0)-complete(data->complete);-returnrc;-}--intrtas_suspend_cpu(structrtas_suspend_me_data*data)-{-return__rtas_suspend_cpu(data,0);-}-/***rtas_call_reentrant()-Usedforreentrantrtascalls*@token:TokenfordesiredreentrantRTAScall
Partitions with cache nodes in the device tree can encounter the
following warning on resume:
CPU 0 already accounted in PowerPC,POWER9@0(Data)
WARNING: CPU: 0 PID: 3177 at arch/powerpc/kernel/cacheinfo.c:197 cacheinfo_cpu_online+0x640/0x820
These calls to cacheinfo_cpu_offline/online have been redundant since
commit e610a466d16a ("powerpc/pseries/mobility: rebuild cacheinfo
hierarchy post-migration").
Fixes: e610a466d16a ("powerpc/pseries/mobility: rebuild cacheinfo hierarchy post-migration")
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/platforms/pseries/suspend.c | 3 ---
1 file changed, 3 deletions(-)
The pseries hibernate code no longer calls into the original
join/suspend code in kernel/rtas.c, so pseries_prepare_late() and
related code don't accomplish anything now.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/platforms/pseries/suspend.c | 25 ------------------------
1 file changed, 25 deletions(-)
The pseries hibernate code calls post_mobility_fixup() which is sort
of a dumping ground of fixups that need to run after resuming from
suspend regardless of whether suspend was a hibernation or a
migration. Calling post_mobility_fixup() from
pseries_suspend_enable_irqs() runs this code early in resume with
devices suspended and only one CPU up, while the much more commonly
used migration case runs these fixups in a more typical process
context.
Call post_mobility_fixup() after the suspend core returns a success
status to the hibernate sysfs store method and remove
pseries_suspend_enable_irqs().
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/platforms/pseries/suspend.c | 21 ++++-----------------
1 file changed, 4 insertions(+), 17 deletions(-)
All code which used this type has been removed.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/include/asm/rtas-types.h | 8 --------
1 file changed, 8 deletions(-)
@@ -23,14 +23,6 @@ struct rtas_t {structdevice_node*dev;/* virtual address pointer */};-structrtas_suspend_me_data{-atomic_tworking;/* number of cpus accessing this struct */-atomic_tdone;-inttoken;/* ibm,suspend-me */-atomic_terror;-structcompletion*complete;/* wait on this until working == 0 */-};-structrtas_error_log{/* Byte 0 */u8byte0;/* Architectural version */
In pseries_devicetree_update(), with each call to ibm,update-nodes the
partition firmware communicates the node to be deleted or updated by
placing its phandle in the work buffer. Each of delete_dt_node(),
update_dt_node(), and add_dt_node() have duplicate lookups using the
phandle value and corresponding refcount management.
Move the lookup and of_node_put() into pseries_devicetree_update(),
and emit a warning on any failed lookups.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/platforms/pseries/mobility.c | 49 ++++++++---------------
1 file changed, 17 insertions(+), 32 deletions(-)
rtas_suspend_last_cpu() is now unused, remove it and
__rtas_suspend_last_cpu() which also becomes unused.
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/include/asm/rtas.h | 1 -
arch/powerpc/kernel/rtas.c | 43 ---------------------------------
2 files changed, 44 deletions(-)
@@ -830,49 +830,6 @@ void rtas_activate_firmware(void)staticintibm_suspend_me_token=RTAS_UNKNOWN_SERVICE;#ifdef CONFIG_PPC_PSERIES-staticint__rtas_suspend_last_cpu(structrtas_suspend_me_data*data,intwake_when_done)-{-u16slb_size=mmu_slb_size;-intrc=H_MULTI_THREADS_ACTIVE;-intcpu;--slb_set_size(SLB_MIN_SIZE);-printk(KERN_DEBUG"calling ibm,suspend-me on cpu %i\n",smp_processor_id());--while(rc==H_MULTI_THREADS_ACTIVE&&!atomic_read(&data->done)&&-!atomic_read(&data->error))-rc=rtas_call(data->token,0,1,NULL);--if(rc||atomic_read(&data->error)){-printk(KERN_DEBUG"ibm,suspend-me returned %d\n",rc);-slb_set_size(slb_size);-}--if(atomic_read(&data->error))-rc=atomic_read(&data->error);--atomic_set(&data->error,rc);-pSeries_coalesce_init();--if(wake_when_done){-atomic_set(&data->done,1);--for_each_online_cpu(cpu)-plpar_hcall_norets(H_PROD,get_hard_smp_processor_id(cpu));-}--if(atomic_dec_return(&data->working)==0)-complete(data->complete);--returnrc;-}--intrtas_suspend_last_cpu(structrtas_suspend_me_data*data)-{-atomic_inc(&data->working);-return__rtas_suspend_last_cpu(data,0);-}-/***rtas_call_reentrant()-Usedforreentrantrtascalls*@token:TokenfordesiredreentrantRTAScall
rtas_suspend_last_cpu() and related code perform a lot of work that
isn't relevant to the hibernation workflow. All other CPUs are offline
when called so there is no need to place them in H_JOIN or prod them
on resume, nor is there need for retries or operations on shared
state.
Call the rtas_ibm_suspend_me() wrapper function directly from
pseries_suspend_enter() instead of using rtas_suspend_last_cpu().
Signed-off-by: Nathan Lynch <redacted>
---
arch/powerpc/platforms/pseries/suspend.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
From: Michael Ellerman <hidden> Date: 2020-12-15 11:24:44
On Mon, 7 Dec 2020 15:51:32 -0600, Nathan Lynch wrote:
This series aims to improve the pseries-specific partition migration
and hibernation implementation, part of which has been living in
kernel/rtas.c. Most of that code is eliminated or moved to
platforms/pseries, and the following major functional changes are
made:
- Use stop_machine() instead of on_each_cpu() to avoid deadlock in the
join/suspend sequence.
[...]