xref: /rk3399_ARM-atf/lib/pmf/pmf_main.c (revision a31d8983f42153b0448103bdd47e1f4c9c093765)
1*a31d8983SYatharth Kochar /*
2*a31d8983SYatharth Kochar  * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
3*a31d8983SYatharth Kochar  *
4*a31d8983SYatharth Kochar  * Redistribution and use in source and binary forms, with or without
5*a31d8983SYatharth Kochar  * modification, are permitted provided that the following conditions are met:
6*a31d8983SYatharth Kochar  *
7*a31d8983SYatharth Kochar  * Redistributions of source code must retain the above copyright notice, this
8*a31d8983SYatharth Kochar  * list of conditions and the following disclaimer.
9*a31d8983SYatharth Kochar  *
10*a31d8983SYatharth Kochar  * Redistributions in binary form must reproduce the above copyright notice,
11*a31d8983SYatharth Kochar  * this list of conditions and the following disclaimer in the documentation
12*a31d8983SYatharth Kochar  * and/or other materials provided with the distribution.
13*a31d8983SYatharth Kochar  *
14*a31d8983SYatharth Kochar  * Neither the name of ARM nor the names of its contributors may be used
15*a31d8983SYatharth Kochar  * to endorse or promote products derived from this software without specific
16*a31d8983SYatharth Kochar  * prior written permission.
17*a31d8983SYatharth Kochar  *
18*a31d8983SYatharth Kochar  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19*a31d8983SYatharth Kochar  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*a31d8983SYatharth Kochar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*a31d8983SYatharth Kochar  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22*a31d8983SYatharth Kochar  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23*a31d8983SYatharth Kochar  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24*a31d8983SYatharth Kochar  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25*a31d8983SYatharth Kochar  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26*a31d8983SYatharth Kochar  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27*a31d8983SYatharth Kochar  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28*a31d8983SYatharth Kochar  * POSSIBILITY OF SUCH DAMAGE.
29*a31d8983SYatharth Kochar  */
30*a31d8983SYatharth Kochar #include <arch.h>
31*a31d8983SYatharth Kochar #include <arch_helpers.h>
32*a31d8983SYatharth Kochar #include <assert.h>
33*a31d8983SYatharth Kochar #include <debug.h>
34*a31d8983SYatharth Kochar #include <errno.h>
35*a31d8983SYatharth Kochar #include <platform.h>
36*a31d8983SYatharth Kochar #include <pmf.h>
37*a31d8983SYatharth Kochar #include <string.h>
38*a31d8983SYatharth Kochar 
39*a31d8983SYatharth Kochar /*******************************************************************************
40*a31d8983SYatharth Kochar  * The 'pmf_svc_descs' array holds the PMF service descriptors exported by
41*a31d8983SYatharth Kochar  * services by placing them in the 'pmf_svc_descs' linker section.
42*a31d8983SYatharth Kochar  * The 'pmf_svc_descs_indices' array holds the index of a descriptor in the
43*a31d8983SYatharth Kochar  * 'pmf_svc_descs' array. The TIF[15:10] bits in the time-stamp id are used
44*a31d8983SYatharth Kochar  * to get an index into the 'pmf_svc_descs_indices' array. This gives the
45*a31d8983SYatharth Kochar  * index of the descriptor in the 'pmf_svc_descs' array  which contains the
46*a31d8983SYatharth Kochar  * service function pointers.
47*a31d8983SYatharth Kochar  ******************************************************************************/
48*a31d8983SYatharth Kochar extern uintptr_t __PMF_SVC_DESCS_START__;
49*a31d8983SYatharth Kochar extern uintptr_t __PMF_SVC_DESCS_END__;
50*a31d8983SYatharth Kochar #define PMF_SVC_DESCS_START		((uintptr_t)(&__PMF_SVC_DESCS_START__))
51*a31d8983SYatharth Kochar #define PMF_SVC_DESCS_END		((uintptr_t)(&__PMF_SVC_DESCS_END__))
52*a31d8983SYatharth Kochar extern void *__PERCPU_TIMESTAMP_SIZE__;
53*a31d8983SYatharth Kochar #define PMF_PERCPU_TIMESTAMP_SIZE	((uintptr_t)&__PERCPU_TIMESTAMP_SIZE__)
54*a31d8983SYatharth Kochar extern uintptr_t __PMF_TIMESTAMP_START__;
55*a31d8983SYatharth Kochar #define PMF_TIMESTAMP_ARRAY_START	((uintptr_t)&__PMF_TIMESTAMP_START__)
56*a31d8983SYatharth Kochar extern uintptr_t __PMF_TIMESTAMP_END__;
57*a31d8983SYatharth Kochar #define PMF_TIMESTAMP_ARRAY_END		((uintptr_t)&__PMF_TIMESTAMP_END__)
58*a31d8983SYatharth Kochar 
59*a31d8983SYatharth Kochar #define PMF_SVC_DESCS_MAX		10
60*a31d8983SYatharth Kochar 
61*a31d8983SYatharth Kochar /*
62*a31d8983SYatharth Kochar  * This is used to traverse through registered PMF services.
63*a31d8983SYatharth Kochar  */
64*a31d8983SYatharth Kochar static pmf_svc_desc_t *pmf_svc_descs;
65*a31d8983SYatharth Kochar 
66*a31d8983SYatharth Kochar /*
67*a31d8983SYatharth Kochar  * This array is used to store registered PMF services in sorted order.
68*a31d8983SYatharth Kochar  */
69*a31d8983SYatharth Kochar static int pmf_svc_descs_indices[PMF_SVC_DESCS_MAX];
70*a31d8983SYatharth Kochar 
71*a31d8983SYatharth Kochar /*
72*a31d8983SYatharth Kochar  * This is used to track total number of successfully registered PMF services.
73*a31d8983SYatharth Kochar  */
74*a31d8983SYatharth Kochar static int pmf_num_services;
75*a31d8983SYatharth Kochar 
76*a31d8983SYatharth Kochar /*
77*a31d8983SYatharth Kochar  * This is the main PMF function that initialize registered
78*a31d8983SYatharth Kochar  * PMF services and also sort them in ascending order.
79*a31d8983SYatharth Kochar  */
80*a31d8983SYatharth Kochar int pmf_setup(void)
81*a31d8983SYatharth Kochar {
82*a31d8983SYatharth Kochar 	int rc, ii, jj = 0;
83*a31d8983SYatharth Kochar 	int pmf_svc_descs_num, temp_val;
84*a31d8983SYatharth Kochar 
85*a31d8983SYatharth Kochar 	/* If no PMF services are registered then simply bail out */
86*a31d8983SYatharth Kochar 	pmf_svc_descs_num = (PMF_SVC_DESCS_END - PMF_SVC_DESCS_START)/
87*a31d8983SYatharth Kochar 				 sizeof(pmf_svc_desc_t);
88*a31d8983SYatharth Kochar 	if (pmf_svc_descs_num == 0)
89*a31d8983SYatharth Kochar 		return 0;
90*a31d8983SYatharth Kochar 
91*a31d8983SYatharth Kochar 	assert(pmf_svc_descs_num < PMF_SVC_DESCS_MAX);
92*a31d8983SYatharth Kochar 
93*a31d8983SYatharth Kochar 	pmf_svc_descs = (pmf_svc_desc_t *) PMF_SVC_DESCS_START;
94*a31d8983SYatharth Kochar 	for (ii = 0; ii < pmf_svc_descs_num; ii++) {
95*a31d8983SYatharth Kochar 
96*a31d8983SYatharth Kochar 		assert(pmf_svc_descs[ii].get_ts);
97*a31d8983SYatharth Kochar 
98*a31d8983SYatharth Kochar 		/*
99*a31d8983SYatharth Kochar 		 * Call the initialization routine for this
100*a31d8983SYatharth Kochar 		 * PMF service, if it is defined.
101*a31d8983SYatharth Kochar 		 */
102*a31d8983SYatharth Kochar 		if (pmf_svc_descs[ii].init) {
103*a31d8983SYatharth Kochar 			rc = pmf_svc_descs[ii].init();
104*a31d8983SYatharth Kochar 			if (rc) {
105*a31d8983SYatharth Kochar 				WARN("Could not initialize PMF"
106*a31d8983SYatharth Kochar 					"service %s - skipping \n",
107*a31d8983SYatharth Kochar 					pmf_svc_descs[ii].name);
108*a31d8983SYatharth Kochar 				continue;
109*a31d8983SYatharth Kochar 			}
110*a31d8983SYatharth Kochar 		}
111*a31d8983SYatharth Kochar 
112*a31d8983SYatharth Kochar 		/* Update the pmf_svc_descs_indices array */
113*a31d8983SYatharth Kochar 		pmf_svc_descs_indices[jj++] = ii;
114*a31d8983SYatharth Kochar 	}
115*a31d8983SYatharth Kochar 
116*a31d8983SYatharth Kochar 	pmf_num_services = jj;
117*a31d8983SYatharth Kochar 
118*a31d8983SYatharth Kochar 	/*
119*a31d8983SYatharth Kochar 	 * Sort the successfully registered PMF services
120*a31d8983SYatharth Kochar 	 * according to service ID
121*a31d8983SYatharth Kochar 	 */
122*a31d8983SYatharth Kochar 	for (ii = 1; ii < pmf_num_services; ii++) {
123*a31d8983SYatharth Kochar 		for (jj = 0; jj < (pmf_num_services - ii); jj++) {
124*a31d8983SYatharth Kochar 			if ((pmf_svc_descs[jj].svc_config & PMF_SVC_ID_MASK) >
125*a31d8983SYatharth Kochar 				(pmf_svc_descs[jj + 1].svc_config &
126*a31d8983SYatharth Kochar 						PMF_SVC_ID_MASK)) {
127*a31d8983SYatharth Kochar 				temp_val = pmf_svc_descs_indices[jj];
128*a31d8983SYatharth Kochar 				pmf_svc_descs_indices[jj] =
129*a31d8983SYatharth Kochar 						pmf_svc_descs_indices[jj+1];
130*a31d8983SYatharth Kochar 				pmf_svc_descs_indices[jj+1] = temp_val;
131*a31d8983SYatharth Kochar 			}
132*a31d8983SYatharth Kochar 		}
133*a31d8983SYatharth Kochar 	}
134*a31d8983SYatharth Kochar 
135*a31d8983SYatharth Kochar 	return 0;
136*a31d8983SYatharth Kochar }
137*a31d8983SYatharth Kochar 
138*a31d8983SYatharth Kochar /*
139*a31d8983SYatharth Kochar  * This function implements binary search to find registered
140*a31d8983SYatharth Kochar  * PMF service based on Service ID provided in `tid` argument.
141*a31d8983SYatharth Kochar  */
142*a31d8983SYatharth Kochar static pmf_svc_desc_t *get_service(unsigned int tid)
143*a31d8983SYatharth Kochar {
144*a31d8983SYatharth Kochar 	int low = 0;
145*a31d8983SYatharth Kochar 	int mid;
146*a31d8983SYatharth Kochar 	int high = pmf_num_services;
147*a31d8983SYatharth Kochar 	unsigned int svc_id = tid & PMF_SVC_ID_MASK;
148*a31d8983SYatharth Kochar 	int index;
149*a31d8983SYatharth Kochar 	unsigned int desc_svc_id;
150*a31d8983SYatharth Kochar 
151*a31d8983SYatharth Kochar 	if (pmf_num_services == 0)
152*a31d8983SYatharth Kochar 		return NULL;
153*a31d8983SYatharth Kochar 
154*a31d8983SYatharth Kochar 	assert(pmf_svc_descs);
155*a31d8983SYatharth Kochar 
156*a31d8983SYatharth Kochar 	do {
157*a31d8983SYatharth Kochar 		mid = (low + high) / 2;
158*a31d8983SYatharth Kochar 		index = pmf_svc_descs_indices[mid];
159*a31d8983SYatharth Kochar 
160*a31d8983SYatharth Kochar 		desc_svc_id = pmf_svc_descs[index].svc_config & PMF_SVC_ID_MASK;
161*a31d8983SYatharth Kochar 		if (svc_id < desc_svc_id)
162*a31d8983SYatharth Kochar 			high = mid - 1;
163*a31d8983SYatharth Kochar 		if (svc_id > desc_svc_id)
164*a31d8983SYatharth Kochar 			low = mid + 1;
165*a31d8983SYatharth Kochar 	} while ((svc_id != desc_svc_id) && (low <= high));
166*a31d8983SYatharth Kochar 
167*a31d8983SYatharth Kochar 	/*
168*a31d8983SYatharth Kochar 	 * Make sure the Service found supports the tid range.
169*a31d8983SYatharth Kochar 	 */
170*a31d8983SYatharth Kochar 	if ((svc_id == desc_svc_id) && ((tid & PMF_TID_MASK) <
171*a31d8983SYatharth Kochar 		(pmf_svc_descs[index].svc_config & PMF_TID_MASK)))
172*a31d8983SYatharth Kochar 		return (pmf_svc_desc_t *)&pmf_svc_descs[index];
173*a31d8983SYatharth Kochar 
174*a31d8983SYatharth Kochar 	return NULL;
175*a31d8983SYatharth Kochar }
176*a31d8983SYatharth Kochar 
177*a31d8983SYatharth Kochar /*
178*a31d8983SYatharth Kochar  * This function gets the time-stamp value for the PMF services
179*a31d8983SYatharth Kochar  * registered for SMC interface based on `tid` and `mpidr`.
180*a31d8983SYatharth Kochar  */
181*a31d8983SYatharth Kochar int pmf_get_timestamp_smc(unsigned int tid,
182*a31d8983SYatharth Kochar 		u_register_t mpidr,
183*a31d8983SYatharth Kochar 		unsigned int flags,
184*a31d8983SYatharth Kochar 		unsigned long long *ts_value)
185*a31d8983SYatharth Kochar {
186*a31d8983SYatharth Kochar 	pmf_svc_desc_t *svc_desc;
187*a31d8983SYatharth Kochar 	assert(ts_value);
188*a31d8983SYatharth Kochar 
189*a31d8983SYatharth Kochar 	/* Search for registered service. */
190*a31d8983SYatharth Kochar 	svc_desc = get_service(tid);
191*a31d8983SYatharth Kochar 
192*a31d8983SYatharth Kochar 	if ((svc_desc == NULL) || (plat_core_pos_by_mpidr(mpidr) < 0)) {
193*a31d8983SYatharth Kochar 		*ts_value = 0;
194*a31d8983SYatharth Kochar 		return -EINVAL;
195*a31d8983SYatharth Kochar 	} else {
196*a31d8983SYatharth Kochar 		/* Call the service time-stamp handler. */
197*a31d8983SYatharth Kochar 		*ts_value = svc_desc->get_ts(tid, mpidr, flags);
198*a31d8983SYatharth Kochar 		return 0;
199*a31d8983SYatharth Kochar 	}
200*a31d8983SYatharth Kochar }
201*a31d8983SYatharth Kochar 
202*a31d8983SYatharth Kochar /*
203*a31d8983SYatharth Kochar  * This function can be used to dump `ts` value for given `tid`.
204*a31d8983SYatharth Kochar  * Assumption is that the console is already initialized.
205*a31d8983SYatharth Kochar  */
206*a31d8983SYatharth Kochar void __pmf_dump_timestamp(unsigned int tid, unsigned long long ts)
207*a31d8983SYatharth Kochar {
208*a31d8983SYatharth Kochar 	tf_printf("PMF:cpu %u	tid %u	ts %llu\n",
209*a31d8983SYatharth Kochar 		plat_my_core_pos(), tid, ts);
210*a31d8983SYatharth Kochar }
211*a31d8983SYatharth Kochar 
212*a31d8983SYatharth Kochar /*
213*a31d8983SYatharth Kochar  * This function calculate the address identified by
214*a31d8983SYatharth Kochar  * `base_addr`, `tid` and `cpuid`.
215*a31d8983SYatharth Kochar  */
216*a31d8983SYatharth Kochar static inline uintptr_t calc_ts_addr(uintptr_t base_addr,
217*a31d8983SYatharth Kochar 		unsigned int tid,
218*a31d8983SYatharth Kochar 		unsigned int cpuid)
219*a31d8983SYatharth Kochar {
220*a31d8983SYatharth Kochar 	assert(cpuid < PLATFORM_CORE_COUNT);
221*a31d8983SYatharth Kochar 	assert(base_addr >= PMF_TIMESTAMP_ARRAY_START);
222*a31d8983SYatharth Kochar 	assert(base_addr < ((PMF_TIMESTAMP_ARRAY_START +
223*a31d8983SYatharth Kochar 		PMF_PERCPU_TIMESTAMP_SIZE) - ((tid & PMF_TID_MASK) *
224*a31d8983SYatharth Kochar 		sizeof(unsigned long long))));
225*a31d8983SYatharth Kochar 
226*a31d8983SYatharth Kochar 	base_addr += ((cpuid * PMF_PERCPU_TIMESTAMP_SIZE) +
227*a31d8983SYatharth Kochar 		((tid & PMF_TID_MASK) * sizeof(unsigned long long)));
228*a31d8983SYatharth Kochar 
229*a31d8983SYatharth Kochar 	return base_addr;
230*a31d8983SYatharth Kochar }
231*a31d8983SYatharth Kochar 
232*a31d8983SYatharth Kochar /*
233*a31d8983SYatharth Kochar  * This function stores the `ts` value to the storage identified by
234*a31d8983SYatharth Kochar  * `base_addr`, `tid` and current cpu id.
235*a31d8983SYatharth Kochar  * Note: The timestamp addresses are cache line aligned per cpu
236*a31d8983SYatharth Kochar  * and only the owning CPU would ever write into it.
237*a31d8983SYatharth Kochar  */
238*a31d8983SYatharth Kochar void __pmf_store_timestamp(uintptr_t base_addr,
239*a31d8983SYatharth Kochar 			unsigned int tid,
240*a31d8983SYatharth Kochar 			unsigned long long ts)
241*a31d8983SYatharth Kochar {
242*a31d8983SYatharth Kochar 	unsigned long long *ts_addr = (unsigned long long *)calc_ts_addr(base_addr,
243*a31d8983SYatharth Kochar 				 tid, plat_my_core_pos());
244*a31d8983SYatharth Kochar 	*ts_addr = ts;
245*a31d8983SYatharth Kochar }
246*a31d8983SYatharth Kochar 
247*a31d8983SYatharth Kochar /*
248*a31d8983SYatharth Kochar  * This is the cached version of `pmf_store_my_timestamp`
249*a31d8983SYatharth Kochar  * Note: The timestamp addresses are cache line aligned per cpu
250*a31d8983SYatharth Kochar  * and only the owning CPU would ever write into it.
251*a31d8983SYatharth Kochar  */
252*a31d8983SYatharth Kochar void __pmf_store_timestamp_with_cache_maint(uintptr_t base_addr,
253*a31d8983SYatharth Kochar 			unsigned int tid,
254*a31d8983SYatharth Kochar 			unsigned long long ts)
255*a31d8983SYatharth Kochar {
256*a31d8983SYatharth Kochar 	unsigned long long *ts_addr = (unsigned long long *)calc_ts_addr(base_addr,
257*a31d8983SYatharth Kochar 				 tid, plat_my_core_pos());
258*a31d8983SYatharth Kochar 	*ts_addr = ts;
259*a31d8983SYatharth Kochar 	flush_dcache_range((uintptr_t)ts_addr, sizeof(unsigned long long));
260*a31d8983SYatharth Kochar }
261*a31d8983SYatharth Kochar 
262*a31d8983SYatharth Kochar /*
263*a31d8983SYatharth Kochar  * This function retrieves the `ts` value from the storage identified by
264*a31d8983SYatharth Kochar  * `base_addr`, `tid` and `cpuid`.
265*a31d8983SYatharth Kochar  * Note: The timestamp addresses are cache line aligned per cpu.
266*a31d8983SYatharth Kochar  */
267*a31d8983SYatharth Kochar unsigned long long __pmf_get_timestamp(uintptr_t base_addr,
268*a31d8983SYatharth Kochar 			unsigned int tid,
269*a31d8983SYatharth Kochar 			unsigned int cpuid,
270*a31d8983SYatharth Kochar 			unsigned int flags)
271*a31d8983SYatharth Kochar {
272*a31d8983SYatharth Kochar 	assert(cpuid < PLATFORM_CORE_COUNT);
273*a31d8983SYatharth Kochar 	unsigned long long *ts_addr = (unsigned long long *)calc_ts_addr(base_addr,
274*a31d8983SYatharth Kochar 				tid, cpuid);
275*a31d8983SYatharth Kochar 
276*a31d8983SYatharth Kochar 	if (flags & PMF_CACHE_MAINT)
277*a31d8983SYatharth Kochar 		inv_dcache_range((uintptr_t)ts_addr, sizeof(unsigned long long));
278*a31d8983SYatharth Kochar 
279*a31d8983SYatharth Kochar 	return *ts_addr;
280*a31d8983SYatharth Kochar }
281