xref: /rk3399_ARM-atf/services/std_svc/lfa/lfa_holding_pen.c (revision ff7daec6f4bd151a1787c12db546509db49597df)
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