diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-02-28 10:55:16 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-02-28 11:03:04 +0000 |
commit | ea824b97424a46140bdcfc27d78da6c7f4ec24ff (patch) | |
tree | ce4c3d0f96ba462ca3159a57b332fad79414cdd6 /target/arm | |
parent | f9f62e4c376c6e737e162209b197dcda690e9f81 (diff) |
target/arm/arm-powerctl: Add new arm_set_cpu_on_and_reset()
Currently the Arm arm-powerctl.h APIs allow:
* arm_set_cpu_on(), which powers on a CPU and sets its
initial PC and other startup state
* arm_reset_cpu(), which resets a CPU which is already on
(and fails if the CPU is powered off)
but there is no way to say "power on a CPU as if it had
just come out of reset and don't do anything else to it".
Add a new function arm_set_cpu_on_and_reset(), which does this.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20190219125808.25174-5-peter.maydell@linaro.org
Diffstat (limited to 'target/arm')
-rw-r--r-- | target/arm/arm-powerctl.c | 56 | ||||
-rw-r--r-- | target/arm/arm-powerctl.h | 16 |
2 files changed, 72 insertions, 0 deletions
diff --git a/target/arm/arm-powerctl.c b/target/arm/arm-powerctl.c index f9de5164e5..f77a950db6 100644 --- a/target/arm/arm-powerctl.c +++ b/target/arm/arm-powerctl.c @@ -228,6 +228,62 @@ int arm_set_cpu_on(uint64_t cpuid, uint64_t entry, uint64_t context_id, return QEMU_ARM_POWERCTL_RET_SUCCESS; } +static void arm_set_cpu_on_and_reset_async_work(CPUState *target_cpu_state, + run_on_cpu_data data) +{ + ARMCPU *target_cpu = ARM_CPU(target_cpu_state); + + /* Initialize the cpu we are turning on */ + cpu_reset(target_cpu_state); + target_cpu_state->halted = 0; + + /* Finally set the power status */ + assert(qemu_mutex_iothread_locked()); + target_cpu->power_state = PSCI_ON; +} + +int arm_set_cpu_on_and_reset(uint64_t cpuid) +{ + CPUState *target_cpu_state; + ARMCPU *target_cpu; + + assert(qemu_mutex_iothread_locked()); + + /* Retrieve the cpu we are powering up */ + target_cpu_state = arm_get_cpu_by_id(cpuid); + if (!target_cpu_state) { + /* The cpu was not found */ + return QEMU_ARM_POWERCTL_INVALID_PARAM; + } + + target_cpu = ARM_CPU(target_cpu_state); + if (target_cpu->power_state == PSCI_ON) { + qemu_log_mask(LOG_GUEST_ERROR, + "[ARM]%s: CPU %" PRId64 " is already on\n", + __func__, cpuid); + return QEMU_ARM_POWERCTL_ALREADY_ON; + } + + /* + * If another CPU has powered the target on we are in the state + * ON_PENDING and additional attempts to power on the CPU should + * fail (see 6.6 Implementation CPU_ON/CPU_OFF races in the PSCI + * spec) + */ + if (target_cpu->power_state == PSCI_ON_PENDING) { + qemu_log_mask(LOG_GUEST_ERROR, + "[ARM]%s: CPU %" PRId64 " is already powering on\n", + __func__, cpuid); + return QEMU_ARM_POWERCTL_ON_PENDING; + } + + async_run_on_cpu(target_cpu_state, arm_set_cpu_on_and_reset_async_work, + RUN_ON_CPU_NULL); + + /* We are good to go */ + return QEMU_ARM_POWERCTL_RET_SUCCESS; +} + static void arm_set_cpu_off_async_work(CPUState *target_cpu_state, run_on_cpu_data data) { diff --git a/target/arm/arm-powerctl.h b/target/arm/arm-powerctl.h index 04353923c0..37c8a04f0a 100644 --- a/target/arm/arm-powerctl.h +++ b/target/arm/arm-powerctl.h @@ -74,4 +74,20 @@ int arm_set_cpu_off(uint64_t cpuid); */ int arm_reset_cpu(uint64_t cpuid); +/* + * arm_set_cpu_on_and_reset: + * @cpuid: the id of the CPU we want to star + * + * Start the cpu designated by @cpuid and put it through its normal + * CPU reset process. The CPU will start in the way it is architected + * to start after a power-on reset. + * + * Returns: QEMU_ARM_POWERCTL_RET_SUCCESS on success. + * QEMU_ARM_POWERCTL_INVALID_PARAM if there is no CPU with that ID. + * QEMU_ARM_POWERCTL_ALREADY_ON if the CPU is already on. + * QEMU_ARM_POWERCTL_ON_PENDING if the CPU is already partway through + * powering on. + */ +int arm_set_cpu_on_and_reset(uint64_t cpuid); + #endif |