Skip to contentSkip to conversation

PSCI v0.2 support and DT bindings

PATCH New Ashwin Chaugule 2 participants 7 messages May 15, 2014

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

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
#1 lore raw

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
index c4ae171..b93e34a 100644
@@ -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
index d15ab8b4..e5312ea 100644
@@ -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
#3 lore raw

PATCH v10 2/3 Documentation: devicetree: Add new binding for PSCIv0.2

In reply to 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.

---
 Documentation/devicetree/bindings/arm/psci.txt | 37 +++++++++++++++++++++++++-
 1 file changed, 36 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/arm/psci.txt +36 -1
index 433afe9..b4a58f3 100644
@@ -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
maintainer
#4 lore raw

PATCH 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.

#5 lore raw

PATCH v10 3/3 ARM: Check if a CPU has gone offline

In reply to 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 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
index 570a48c..28a1db4 100644
@@ -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
index 1524130..d7b4b38 100644
@@ -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
index 90df6e6..9e9798f 100644
@@ -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
index f0a141d..c3cb160 100644
@@ -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
maintainer
#6 lore raw

PATCH 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 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.

Quoted 3 lines