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 */
lfa_holding_start(void)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 */
lfa_holding_wait(void)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 */
lfa_holding_release(enum lfa_retc status)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