/* * Copyright (c) 2025, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include static spinlock_t holding_lock; static spinlock_t activation_lock; static uint32_t activation_count; static enum lfa_retc activation_status; /** * lfa_holding_start - Called by each active CPU to coordinate live activation. * * Note that only CPUs that are active at the time of activation will * participate in CPU rendezvous. * * This function is invoked by each CPU participating in the LFA Activate * process. It increments the shared activation count under `activation_lock` * to track how many CPUs have entered the activation phase. * * The first CPU to enter acquires the `holding_lock`, which ensures * serialization during the wait and activation phases. This lock is * released only after the last CPU completes the activation. * * The function returns `true` only for the last CPU to enter, allowing it * to proceed with performing the live firmware activation. All other CPUs * receive `false` and will wait in `lfa_holding_wait()` until activation * is complete. * * @return `true` for the last CPU, `false` for all others. */ bool lfa_holding_start(void) { bool status; unsigned int no_of_cpus; spin_lock(&activation_lock); if (activation_count == 0U) { /* First CPU locks holding lock */ spin_lock(&holding_lock); } activation_count += 1U; no_of_cpus = psci_num_cpus_running_on_safe(plat_my_core_pos()); status = (activation_count == no_of_cpus); if (!status) { VERBOSE("Hold, %d CPU left\n", PLATFORM_CORE_COUNT - activation_count); } spin_unlock(&activation_lock); return status; } /** * lfa_holding_wait - CPUs wait until activation is completed by the last CPU. * * All CPUs are serialized using `holding_lock`, which is initially acquired * by the first CPU in `lfa_holding_start()` and only released by the last * CPU through `lfa_holding_release()`. This ensures that no two CPUs enter * the critical section at the same time during the wait phase. Once the * last CPU completes activation, each CPU decrements the activation count * and returns the final activation status, which was set by the last CPU * to complete the activation process. * * @return Activation status set by the last CPU. */ enum lfa_retc lfa_holding_wait(void) { spin_lock(&holding_lock); activation_count -= 1U; spin_unlock(&holding_lock); return activation_status; } /** * lfa_holding_release - Called by the last CPU to complete activation. * * This function is used by the last participating CPU after it completes * live firmware activation. It updates the shared activation status and * resets the activation count. Finally, it releases the `holding_lock` to * allow other CPUs that were waiting in `lfa_holding_wait()` to proceed. * * @param status Activation status to be shared with other CPUs. */ void lfa_holding_release(enum lfa_retc status) { activation_count = 0U; activation_status = status; spin_unlock(&holding_lock); }