PSCI v0.2 support and DT bindings
Subsystems (3)
v10 cover PSCI v0.2 support and DT bindings
This patchset introduces some functions as defined in the PSCI v0.2 spec and a corresponding DT binding to differentiate it from previous PSCI versions. Since PSCIv0.2 has standard function IDs, it is possible to statically assign them rather than depend on values from DT.
This patchset depends on the PSCI header (/uapi/linux/psci.h) introduced by
http://www.spinics.net/lists/arm-kernel/msg319712.html which is now merged in the ARM KVM tree next branch.
Changes in v10:
- Documented explicit use of case dual PSCI bindings for hypervisors.
- Corrected POWER_STATE macros as per new definitions.
- Added arm64 cpu_kill cpu-op and tied it to psci affinity info.
- Misc cleanups in prints.
Changes in v9:
- Rebased on top of KVM "next" - https://git.kernel.org/cgit/linux/kernel/git/kvmarm/kvmarm.git/log/?h=next
Changes in v8:
- Replace msleep(100) with 10 x msleep(10)
Changes in v7:
- Add two new functions: SYSTEM_OFF and SYSTEM_RESET as defined in PSCIv0.2.
- Added a delay before calling cpu_kill to avoid race with cpu_die.
Changes in v6:
- rebase on top of uapi/linux/psci.h introduced by Anups patch
http://www.spinics.net/lists/arm-kernel/msg319712.html
- rebase on top of Catalins tree tip.
Changes in v5:
- Add uapi/linux/psci.h to kbuild
- ret with err if PSCI_ID_VERSION is not implemented.
Changes in v4:
- Correct copyright banner format.
- Check if PSCI Version ID is supported.
- Add all PSCI RET codes in uapi header.
- Explicitely ret 1 from psci_cpu_kill()Changes in v3:
- Roll up common functionality for getting conduit method.
- Remove #defines for ARM32 and ARM64 in uapi/linux/psci.h
- Remove functions not supported by PSCI v0.1
- Misc cleanups.
- Add PSCI_AFFINITY_INFO return types in uapi header.
- Changed function names for PSCI v0.1 and PSCI v0.2
- Added copyright info to uapi header.
- Fixed args to affinity_info call.
- Fix typo in psci_init definition when PSCI is not defined.Changes in v2:
- Add AFFINITY_INFO and MIGRATE_INFO_TYPE functions.
- Add binding Documentation.
- Add function to get PSCI version.
- Add common #defines in uapi/linux/psci.h
- Implement cpu_kill and check if CPU is dead via AFFINITY_INFO.
- Misc cleanups.Changes in v1:
- Add new binding "arm, psci-0.2"
- Separate conduit and PSCI function assignment methods.
Ashwin Chaugule (3):
PSCI: Add initial support for PSCIv0.2 functions
Documentation: devicetree: Add new binding for PSCIv0.2
ARM: Check if a CPU has gone offline
Documentation/devicetree/bindings/arm/psci.txt | 37 +++- arch/arm/include/asm/psci.h | 7 +- arch/arm/kernel/psci.c | 196 +++++++++++++++++---- arch/arm/kernel/psci_smp.c | 33 ++++ arch/arm64/include/asm/cpu_ops.h | 2 + arch/arm64/include/asm/psci.h | 2 +- arch/arm64/kernel/psci.c | 231 +++++++++++++++++++++---- arch/arm64/kernel/smp.c | 22 +++ 8 files changed, 452 insertions(+), 78 deletions(-)
Signature · 1 line
1.8.3.2
PATCH v10 1/3 PSCI: Add initial support for PSCIv0.2 functions
The PSCIv0.2 spec defines standard values of function IDs and introduces a few new functions. Detect version of PSCI and appropriately select the right PSCI functions.
--- arch/arm/include/asm/psci.h | 7 +- arch/arm/kernel/psci.c | 196 +++++++++++++++++++++++++++++++++-------- arch/arm64/include/asm/psci.h | 2 +- arch/arm64/kernel/psci.c | 200 ++++++++++++++++++++++++++++++++++-------- 4 files changed, 328 insertions(+), 77 deletions(-)
arch/arm/include/asm/psci.h +5 -2
@@ -29,16 +29,19 @@ struct psci_operations {int (*cpu_off)(struct psci_power_state state);int (*cpu_on)(unsigned long cpuid,unsigned long entry_point);int (*migrate)(unsigned long cpuid); +int (*affinity_info)(unsigned long target_affinity, +unsigned long lowest_affinity_level); +int (*migrate_info_type)(void ); };extern struct psci_operations psci_ops;extern struct smp_operations psci_smp_ops;#ifdef CONFIG_ARM_PSCI -void psci_init (void ); +int psci_init (void );bool psci_smp_available (void );#else -static inline void psci_init (void ) { } +static inline int psci_init (void ) { }static inline bool psci_smp_available (void ) {return false; }#endif
arch/arm/kernel/psci.c +159 -37
269 lines not on this page · raw message
arch/arm64/include/asm/psci.h +1 -1
@@ -14,6 +14,6 @@#ifndef __ASM_PSCI_H#define __ASM_PSCI_H -void psci_init (void ); +int psci_init (void );#endif /* __ASM_PSCI_H */
arch/arm64/kernel/psci.c +163 -37
282 lines not on this page · raw message
Signature · 1 line
1.8.3.2
Catalin Marinas
maintainerPATCH v10 1/3 PSCI: Add initial support for PSCIv0.2 functions
Quoted 6 lines · Ashwin Chaugule
The PSCIv0.2 spec defines standard values of function IDs and introduces a few new functions. Detect version of PSCI and appropriately select the right PSCI functions.
Signed-off-by Ashwin Chaugule <[email protected]>Reviewed-by Rob Herring <[email protected]>
PATCH v10 2/3 Documentation: devicetree: Add new binding for PSCIv0.2
In reply to Ashwin ChauguleThe PSCI v0.2+ spec defines standard values for PSCI function IDs. Add a new binding entry so that pre v0.2 implementations can use DT entries for function IDs and v0.2+ implementations use standard entries as defined by the PSCIv0.2 specification.
--- Documentation/devicetree/bindings/arm/psci.txt | 37 +++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/arm/psci.txt +36 -1
@@ -21,7 +21,15 @@ to #0. Main node required properties: - - compatible : Must be "arm,psci" + - compatible : should contain at least one of: + + * "arm,psci" : for implementations complying to PSCI versions prior to + 0.2. For these cases function IDs must be provided. + + * "arm,psci-0.2" : for implementations complying to PSCI 0.2. Function + IDs are not required and should be ignored by an OS with PSCI 0.2 + support, but are permitted to be present for compatibility with + existing software when "arm,psci" is later in the compatible list. - method : The method of calling the PSCI firmware. Permitted values are:
@@ -45,6 +53,8 @@ Main node optional properties: Example: +Case 1: PSCI v0.1 only. + psci { compatible = "arm,psci"; method = "smc";
@@ -53,3 +63,28 @@ Example: cpu_on = <0x95c10002>; migrate = <0x95c10003>; }; + + +Case 2: PSCI v0.2 only + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + +Case 3: PSCI v0.2 and PSCI v0.1. + + A DTB may provide IDs for use by kernels without PSCI 0.2 support, + enabling firmware and hypervisors to support existing and new kernels. + These IDs will be ignored by kernels with PSCI 0.2 support, which will + use the standard PSCI 0.2 IDs exclusively. + + psci { + compatible = "arm,psci-0.2", "arm,psci"; + method = "hvc"; + + cpu_on = < arbitrary value >; + cpu_off = < arbitrary value >; + + ... + };
Signature · 1 line
1.8.3.2
Catalin Marinas
maintainerPATCH v10 2/3 Documentation: devicetree: Add new binding for PSCIv0.2
Quoted 8 lines · Ashwin Chaugule
The PSCI v0.2+ spec defines standard values for PSCI function IDs. Add a new binding entry so that pre v0.2 implementations can use DT entries for function IDs and v0.2+ implementations use standard entries as defined by the PSCIv0.2 specification.
Signed-off-by Ashwin Chaugule <[email protected]>Reviewed-by Mark Rutland <[email protected]>Acked-by Rob Herring <[email protected]>
PATCH v10 3/3 ARM: Check if a CPU has gone offline
In reply to Ashwin ChaugulePSCIv0.2 adds a new function called AFFINITY_INFO, which can be used to query if a specified CPU has actually gone offline. Calling this function via cpu_kill ensures that a CPU has quiesced after a call to cpu_die. This helps prevent the CPU from doing arbitrary bad things when data or instructions are clobbered (as happens with kexec) in the window between a CPU announcing that it is dead and said CPU leaving the kernel.
--- arch/arm/kernel/psci_smp.c | 33 +++++++++++++++++++++++++++++++++ arch/arm64/include/asm/cpu_ops.h | 2 ++ arch/arm64/kernel/psci.c | 31 +++++++++++++++++++++++++++++++ arch/arm64/kernel/smp.c | 22 ++++++++++++++++++++++ 4 files changed, 88 insertions(+)
arch/arm/kernel/psci_smp.c +33 -0
@@ -16,6 +16,8 @@#include <linux/init.h> #include <linux/smp.h> #include <linux/of.h> +#include <linux/delay.h> +#include <uapi/linux/psci.h> #include <asm/psci.h> #include <asm/smp_plat.h>
@@ -66,6 +68,36 @@ void __ref psci_cpu_die(unsigned int cpu)/* We should never return */ panic("psci: cpu %d failed to shutdown\n", cpu); } + +int __ref psci_cpu_kill (unsigned int cpu) +{ +int err, i; + +if (!psci_ops.affinity_info) +return 1 ; +/* +* cpu_kill could race with cpu_die and we can +* potentially end up declaring this cpu undead +* while it is dying. So, try again a few times. +*/ + +for (i =0 ; i <10 ; i++) { + err = psci_ops.affinity_info (cpu_logical_map (cpu),0 ); +if (err ==PSCI_0_2_AFFINITY_LEVEL_OFF ) { +pr_info ("CPU%d killed.\n" , cpu); +return 1 ; + } + +msleep (10 ); +pr_info ("Retrying again to check for CPU kill\n" ); + } + +pr_warn ("CPU%d may not have shut down cleanly (AFFINITY_INFO reports %d)\n" , + cpu, err); +/* Make platform_cpu_kill() fail. */ +return 0 ; +} +#endif bool __init psci_smp_available (void )
@@ -78,5 +110,6 @@ struct smp_operations __initdata psci_smp_ops = { .smp_boot_secondary = psci_boot_secondary, #ifdef CONFIG_HOTPLUG_CPU .cpu_die = psci_cpu_die, + .cpu_kill = psci_cpu_kill,#endif };
arch/arm64/include/asm/cpu_ops.h +2 -0
@@ -39,6 +39,7 @@ struct device_node;* from the cpu to be killed. * @cpu_die: Makes a cpu leave the kernel. Must not fail. Called from the * cpu being killed. +* @cpu_kill: Ensures a cpu has left the kernel. Called from another cpu. * @cpu_suspend: Suspends a cpu and saves the required context. May fail owing * to wrong parameters or error conditions. Called from the * CPU being suspended. Must be called with IRQs disabled.
@@ -52,6 +53,7 @@ struct cpu_operations {#ifdef CONFIG_HOTPLUG_CPU int (*cpu_disable)(unsigned int cpu);void (*cpu_die)(unsigned int cpu); +int (*cpu_kill)(unsigned int cpu);#endif #ifdef CONFIG_ARM64_CPU_SUSPEND int (*cpu_suspend)(unsigned long );
arch/arm64/kernel/psci.c +31 -0
@@ -20,6 +20,7 @@#include <linux/smp.h> #include <linux/reboot.h> #include <linux/pm.h> +#include <linux/delay.h> #include <uapi/linux/psci.h> #include <asm/compiler.h>
@@ -403,6 +404,35 @@ static void cpu_psci_cpu_die(unsigned int cpu)pr_crit ("unable to power off CPU%u (%d)\n" , cpu, ret); } + +static int cpu_psci_cpu_kill (unsigned int cpu) +{ +int err, i; + +if (!psci_ops.affinity_info) +return 1 ; +/* +* cpu_kill could race with cpu_die and we can +* potentially end up declaring this cpu undead +* while it is dying. So, try again a few times. +*/ + +for (i =0 ; i <10 ; i++) { + err = psci_ops.affinity_info (cpu_logical_map (cpu),0 ); +if (err ==PSCI_0_2_AFFINITY_LEVEL_OFF ) { +pr_info ("CPU%d killed.\n" , cpu); +return 1 ; + } + +msleep (10 ); +pr_info ("Retrying again to check for CPU kill\n" ); + } + +pr_warn ("CPU%d may not have shut down cleanly (AFFINITY_INFO reports %d)\n" , + cpu, err); +/* Make op_cpu_kill() fail. */ +return 0 ; +}#endif const struct cpu_operations cpu_psci_ops = {
@@ -413,6 +443,7 @@ const struct cpu_operations cpu_psci_ops = {#ifdef CONFIG_HOTPLUG_CPU .cpu_disable = cpu_psci_cpu_disable, .cpu_die = cpu_psci_cpu_die, + .cpu_kill = cpu_psci_cpu_kill,#endif };
arch/arm64/kernel/smp.c +22 -0
@@ -228,6 +228,19 @@ int __cpu_disable(void)return 0 ; } +static int op_cpu_kill (unsigned int cpu) +{ +/* +* If we have no means of synchronising with the dying CPU, then assume +* that it is really dead. We can only wait for an arbitrary length of +* time and hope that it's dead, so let's skip the wait and just hope. +*/ +if (!cpu_ops[cpu]->cpu_kill) +return 1 ; + +return cpu_ops[cpu]->cpu_kill (cpu); +} +static DECLARE_COMPLETION (cpu_died);/*
@@ -241,6 +254,15 @@ void __cpu_die(unsigned int cpu)return ; }pr_notice ("CPU%u: shutdown\n" , cpu); + +/* +* Now that the dying CPU is beyond the point of no return w.r.t. +* in-kernel synchronisation, try to get the firwmare to help us to +* verify that it has really left the kernel before we consider +* clobbering anything it might still be using. +*/ +if (!op_cpu_kill (cpu)) +pr_warn ("CPU%d may not have shut down cleanly\n" , cpu); }/*
Signature · 1 line
1.8.3.2
Catalin Marinas
maintainerPATCH v10 3/3 ARM: Check if a CPU has gone offline
Quoted 9 lines · Ashwin Chaugule
PSCIv0.2 adds a new function called
AFFINITY_INFO, which can be used to query if a specified CPU has actually gone offline. Calling this function viacpu_killensures that a CPU has quiesced after a call tocpu_die. This helps prevent the CPU from doing arbitrary bad things when data or instructions are clobbered (as happens with kexec) in the window between a CPU announcing that it is dead and said CPU leaving the kernel.
Quoted 3 lines
Signed-off-by Ashwin Chaugule <[email protected]>Signed-off-by Mark Rutland <[email protected]>Reviewed-by Rob Herring <[email protected]>