xen/arm: Implement CPU_OFF PSCI call (physical interface)
authorMirela Simonovic <mirela.simonovic@aggios.com>
Fri, 1 Jun 2018 13:17:43 +0000 (15:17 +0200)
committerJulien Grall <julien.grall@arm.com>
Tue, 5 Jun 2018 18:07:24 +0000 (19:07 +0100)
During the system suspend to RAM non-boot CPUs will be hotplugged.
This will be triggered via disable_nonboot_cpus() call. When
hotplugged the CPU will end up in an infinite wfi loop in stop_cpu().
This patch adds PSCI CPU_OFF call to the EL3 with the aim to get powered
down the calling CPU during the suspend. The CPU_OFF call will be made
only if the PSCI version is higher than v0.1 (Note that the CPU_OFF
function is mandatory since PSCI v0.2).
If PSCI CPU_OFF call to the EL3 succeeds it will not return. Otherwise,
when the PSCI CPU_OFF call returns we'll raise panic, because the
calling CPU couldn't be enabled afterwards (stays in WFI loop forever).
Note that if the PSCI version is higher than v0.1 the CPU_OFF will be
called regardless of the system state. This is done because scenarios
other than suspend may benefit from powering off the CPU.

Signed-off-by: Mirela Simonovic <mirela.simonovic@aggios.com>
Acked-by: Julien Grall <julien.grall@arm.com>
xen/arch/arm/psci.c
xen/arch/arm/smpboot.c
xen/include/asm-arm/psci.h

index 94b616df9bf6f52d2bd907edee43943a337f0a06..3cf5ecf0f3e0dcfacd65e1b37fa9165cd649fc91 100644 (file)
@@ -46,6 +46,19 @@ int call_psci_cpu_on(int cpu)
     return call_smc(psci_cpu_on_nr, cpu_logical_map(cpu), __pa(init_secondary), 0);
 }
 
+void call_psci_cpu_off(void)
+{
+    if ( psci_ver > PSCI_VERSION(0, 1) )
+    {
+        int errno;
+
+        /* If successfull the PSCI cpu_off call doesn't return */
+        errno = call_smc(PSCI_0_2_FN32_CPU_OFF, 0, 0, 0);
+        panic("PSCI cpu off failed for CPU%d err=%d\n", smp_processor_id(),
+              errno);
+    }
+}
+
 void call_psci_system_off(void)
 {
     if ( psci_ver > PSCI_VERSION(0, 1) )
index b2116f0d2d71561c84122e2c57c9d99362c24cf4..8b1e274bf3f562b3baa159838272e0dfbe6fa277 100644 (file)
@@ -395,6 +395,8 @@ void stop_cpu(void)
     /* Make sure the write happens before we sleep forever */
     dsb(sy);
     isb();
+    call_psci_cpu_off();
+
     while ( 1 )
         wfi();
 }
index 9ac820e94adf8d5b18d425d71ee5a53d83e23105..832f77afff3ab39b4a74a4eb43c0181cfdc0ff54 100644 (file)
@@ -20,6 +20,7 @@ extern uint32_t psci_ver;
 
 int psci_init(void);
 int call_psci_cpu_on(int cpu);
+void call_psci_cpu_off(void);
 void call_psci_system_off(void);
 void call_psci_system_reset(void);