1*ff7daec6SManish V Badarkhe /* 2*ff7daec6SManish V Badarkhe * Copyright (c) 2025, Arm Limited. All rights reserved. 3*ff7daec6SManish V Badarkhe * 4*ff7daec6SManish V Badarkhe * SPDX-License-Identifier: BSD-3-Clause 5*ff7daec6SManish V Badarkhe */ 6*ff7daec6SManish V Badarkhe 7*ff7daec6SManish V Badarkhe #include <string.h> 8*ff7daec6SManish V Badarkhe 9*ff7daec6SManish V Badarkhe #include <common/debug.h> 10*ff7daec6SManish V Badarkhe #include <lib/psci/psci_lib.h> 11*ff7daec6SManish V Badarkhe #include <lib/spinlock.h> 12*ff7daec6SManish V Badarkhe #include <lib/utils_def.h> 13*ff7daec6SManish V Badarkhe #include <plat/common/platform.h> 14*ff7daec6SManish V Badarkhe #include <services/lfa_holding_pen.h> 15*ff7daec6SManish V Badarkhe 16*ff7daec6SManish V Badarkhe #include <platform_def.h> 17*ff7daec6SManish V Badarkhe 18*ff7daec6SManish V Badarkhe static spinlock_t holding_lock; 19*ff7daec6SManish V Badarkhe static spinlock_t activation_lock; 20*ff7daec6SManish V Badarkhe static uint32_t activation_count; 21*ff7daec6SManish V Badarkhe static enum lfa_retc activation_status; 22*ff7daec6SManish V Badarkhe 23*ff7daec6SManish V Badarkhe /** 24*ff7daec6SManish V Badarkhe * lfa_holding_start - Called by each active CPU to coordinate live activation. 25*ff7daec6SManish V Badarkhe * 26*ff7daec6SManish V Badarkhe * Note that only CPUs that are active at the time of activation will 27*ff7daec6SManish V Badarkhe * participate in CPU rendezvous. 28*ff7daec6SManish V Badarkhe * 29*ff7daec6SManish V Badarkhe * This function is invoked by each CPU participating in the LFA Activate 30*ff7daec6SManish V Badarkhe * process. It increments the shared activation count under `activation_lock` 31*ff7daec6SManish V Badarkhe * to track how many CPUs have entered the activation phase. 32*ff7daec6SManish V Badarkhe * 33*ff7daec6SManish V Badarkhe * The first CPU to enter acquires the `holding_lock`, which ensures 34*ff7daec6SManish V Badarkhe * serialization during the wait and activation phases. This lock is 35*ff7daec6SManish V Badarkhe * released only after the last CPU completes the activation. 36*ff7daec6SManish V Badarkhe * 37*ff7daec6SManish V Badarkhe * The function returns `true` only for the last CPU to enter, allowing it 38*ff7daec6SManish V Badarkhe * to proceed with performing the live firmware activation. All other CPUs 39*ff7daec6SManish V Badarkhe * receive `false` and will wait in `lfa_holding_wait()` until activation 40*ff7daec6SManish V Badarkhe * is complete. 41*ff7daec6SManish V Badarkhe * 42*ff7daec6SManish V Badarkhe * @return `true` for the last CPU, `false` for all others. 43*ff7daec6SManish V Badarkhe */ 44*ff7daec6SManish V Badarkhe bool lfa_holding_start(void) 45*ff7daec6SManish V Badarkhe { 46*ff7daec6SManish V Badarkhe bool status; 47*ff7daec6SManish V Badarkhe unsigned int no_of_cpus; 48*ff7daec6SManish V Badarkhe 49*ff7daec6SManish V Badarkhe spin_lock(&activation_lock); 50*ff7daec6SManish V Badarkhe 51*ff7daec6SManish V Badarkhe if (activation_count == 0U) { 52*ff7daec6SManish V Badarkhe /* First CPU locks holding lock */ 53*ff7daec6SManish V Badarkhe spin_lock(&holding_lock); 54*ff7daec6SManish V Badarkhe } 55*ff7daec6SManish V Badarkhe 56*ff7daec6SManish V Badarkhe activation_count += 1U; 57*ff7daec6SManish V Badarkhe 58*ff7daec6SManish V Badarkhe no_of_cpus = psci_num_cpus_running_on_safe(plat_my_core_pos()); 59*ff7daec6SManish V Badarkhe status = (activation_count == no_of_cpus); 60*ff7daec6SManish V Badarkhe if (!status) { 61*ff7daec6SManish V Badarkhe VERBOSE("Hold, %d CPU left\n", 62*ff7daec6SManish V Badarkhe PLATFORM_CORE_COUNT - activation_count); 63*ff7daec6SManish V Badarkhe } 64*ff7daec6SManish V Badarkhe 65*ff7daec6SManish V Badarkhe spin_unlock(&activation_lock); 66*ff7daec6SManish V Badarkhe 67*ff7daec6SManish V Badarkhe return status; 68*ff7daec6SManish V Badarkhe } 69*ff7daec6SManish V Badarkhe 70*ff7daec6SManish V Badarkhe /** 71*ff7daec6SManish V Badarkhe * lfa_holding_wait - CPUs wait until activation is completed by the last CPU. 72*ff7daec6SManish V Badarkhe * 73*ff7daec6SManish V Badarkhe * All CPUs are serialized using `holding_lock`, which is initially acquired 74*ff7daec6SManish V Badarkhe * by the first CPU in `lfa_holding_start()` and only released by the last 75*ff7daec6SManish V Badarkhe * CPU through `lfa_holding_release()`. This ensures that no two CPUs enter 76*ff7daec6SManish V Badarkhe * the critical section at the same time during the wait phase. Once the 77*ff7daec6SManish V Badarkhe * last CPU completes activation, each CPU decrements the activation count 78*ff7daec6SManish V Badarkhe * and returns the final activation status, which was set by the last CPU 79*ff7daec6SManish V Badarkhe * to complete the activation process. 80*ff7daec6SManish V Badarkhe * 81*ff7daec6SManish V Badarkhe * @return Activation status set by the last CPU. 82*ff7daec6SManish V Badarkhe */ 83*ff7daec6SManish V Badarkhe enum lfa_retc lfa_holding_wait(void) 84*ff7daec6SManish V Badarkhe { 85*ff7daec6SManish V Badarkhe spin_lock(&holding_lock); 86*ff7daec6SManish V Badarkhe activation_count -= 1U; 87*ff7daec6SManish V Badarkhe spin_unlock(&holding_lock); 88*ff7daec6SManish V Badarkhe return activation_status; 89*ff7daec6SManish V Badarkhe } 90*ff7daec6SManish V Badarkhe 91*ff7daec6SManish V Badarkhe /** 92*ff7daec6SManish V Badarkhe * lfa_holding_release - Called by the last CPU to complete activation. 93*ff7daec6SManish V Badarkhe * 94*ff7daec6SManish V Badarkhe * This function is used by the last participating CPU after it completes 95*ff7daec6SManish V Badarkhe * live firmware activation. It updates the shared activation status and 96*ff7daec6SManish V Badarkhe * resets the activation count. Finally, it releases the `holding_lock` to 97*ff7daec6SManish V Badarkhe * allow other CPUs that were waiting in `lfa_holding_wait()` to proceed. 98*ff7daec6SManish V Badarkhe * 99*ff7daec6SManish V Badarkhe * @param status Activation status to be shared with other CPUs. 100*ff7daec6SManish V Badarkhe */ 101*ff7daec6SManish V Badarkhe void lfa_holding_release(enum lfa_retc status) 102*ff7daec6SManish V Badarkhe { 103*ff7daec6SManish V Badarkhe activation_count = 0U; 104*ff7daec6SManish V Badarkhe activation_status = status; 105*ff7daec6SManish V Badarkhe spin_unlock(&holding_lock); 106*ff7daec6SManish V Badarkhe } 107