xref: /rk3399_ARM-atf/lib/pmf/pmf_main.c (revision 9f85f9e3796f1c351bbc4c8436dc66d83c140b71)
1a31d8983SYatharth Kochar /*
2*9f85f9e3SJoel Hutton  * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
3a31d8983SYatharth Kochar  *
482cb2c1aSdp-arm  * SPDX-License-Identifier: BSD-3-Clause
5a31d8983SYatharth Kochar  */
6a31d8983SYatharth Kochar #include <arch.h>
7a31d8983SYatharth Kochar #include <arch_helpers.h>
8a31d8983SYatharth Kochar #include <assert.h>
9a31d8983SYatharth Kochar #include <debug.h>
10a31d8983SYatharth Kochar #include <errno.h>
11a31d8983SYatharth Kochar #include <platform.h>
12a31d8983SYatharth Kochar #include <pmf.h>
13a31d8983SYatharth Kochar #include <string.h>
14*9f85f9e3SJoel Hutton #include <utils_def.h>
15a31d8983SYatharth Kochar 
16a31d8983SYatharth Kochar /*******************************************************************************
17a31d8983SYatharth Kochar  * The 'pmf_svc_descs' array holds the PMF service descriptors exported by
18a31d8983SYatharth Kochar  * services by placing them in the 'pmf_svc_descs' linker section.
19a31d8983SYatharth Kochar  * The 'pmf_svc_descs_indices' array holds the index of a descriptor in the
20a31d8983SYatharth Kochar  * 'pmf_svc_descs' array. The TIF[15:10] bits in the time-stamp id are used
21a31d8983SYatharth Kochar  * to get an index into the 'pmf_svc_descs_indices' array. This gives the
22a31d8983SYatharth Kochar  * index of the descriptor in the 'pmf_svc_descs' array  which contains the
23a31d8983SYatharth Kochar  * service function pointers.
24a31d8983SYatharth Kochar  ******************************************************************************/
25*9f85f9e3SJoel Hutton 
26*9f85f9e3SJoel Hutton IMPORT_SYM(uintptr_t, __PMF_SVC_DESCS_START__,		PMF_SVC_DESCS_START);
27*9f85f9e3SJoel Hutton IMPORT_SYM(uintptr_t, __PMF_SVC_DESCS_END__,		PMF_SVC_DESCS_END);
28*9f85f9e3SJoel Hutton IMPORT_SYM(uintptr_t, __PERCPU_TIMESTAMP_SIZE__,	PMF_PERCPU_TIMESTAMP_SIZE);
29*9f85f9e3SJoel Hutton IMPORT_SYM(intptr_t,  __PMF_TIMESTAMP_START__,		PMF_TIMESTAMP_ARRAY_START);
30*9f85f9e3SJoel Hutton IMPORT_SYM(uintptr_t, __PMF_TIMESTAMP_END__,		PMF_TIMESTAMP_ARRAY_END);
31a31d8983SYatharth Kochar 
32a31d8983SYatharth Kochar #define PMF_SVC_DESCS_MAX		10
33a31d8983SYatharth Kochar 
34a31d8983SYatharth Kochar /*
35a31d8983SYatharth Kochar  * This is used to traverse through registered PMF services.
36a31d8983SYatharth Kochar  */
37a31d8983SYatharth Kochar static pmf_svc_desc_t *pmf_svc_descs;
38a31d8983SYatharth Kochar 
39a31d8983SYatharth Kochar /*
40a31d8983SYatharth Kochar  * This array is used to store registered PMF services in sorted order.
41a31d8983SYatharth Kochar  */
42a31d8983SYatharth Kochar static int pmf_svc_descs_indices[PMF_SVC_DESCS_MAX];
43a31d8983SYatharth Kochar 
44a31d8983SYatharth Kochar /*
45a31d8983SYatharth Kochar  * This is used to track total number of successfully registered PMF services.
46a31d8983SYatharth Kochar  */
47a31d8983SYatharth Kochar static int pmf_num_services;
48a31d8983SYatharth Kochar 
49a31d8983SYatharth Kochar /*
50a31d8983SYatharth Kochar  * This is the main PMF function that initialize registered
51a31d8983SYatharth Kochar  * PMF services and also sort them in ascending order.
52a31d8983SYatharth Kochar  */
53a31d8983SYatharth Kochar int pmf_setup(void)
54a31d8983SYatharth Kochar {
55a31d8983SYatharth Kochar 	int rc, ii, jj = 0;
56a31d8983SYatharth Kochar 	int pmf_svc_descs_num, temp_val;
57a31d8983SYatharth Kochar 
58a31d8983SYatharth Kochar 	/* If no PMF services are registered then simply bail out */
59a31d8983SYatharth Kochar 	pmf_svc_descs_num = (PMF_SVC_DESCS_END - PMF_SVC_DESCS_START)/
60a31d8983SYatharth Kochar 				 sizeof(pmf_svc_desc_t);
61a31d8983SYatharth Kochar 	if (pmf_svc_descs_num == 0)
62a31d8983SYatharth Kochar 		return 0;
63a31d8983SYatharth Kochar 
64a31d8983SYatharth Kochar 	assert(pmf_svc_descs_num < PMF_SVC_DESCS_MAX);
65a31d8983SYatharth Kochar 
66a31d8983SYatharth Kochar 	pmf_svc_descs = (pmf_svc_desc_t *) PMF_SVC_DESCS_START;
67a31d8983SYatharth Kochar 	for (ii = 0; ii < pmf_svc_descs_num; ii++) {
68a31d8983SYatharth Kochar 
69a31d8983SYatharth Kochar 		assert(pmf_svc_descs[ii].get_ts);
70a31d8983SYatharth Kochar 
71a31d8983SYatharth Kochar 		/*
72a31d8983SYatharth Kochar 		 * Call the initialization routine for this
73a31d8983SYatharth Kochar 		 * PMF service, if it is defined.
74a31d8983SYatharth Kochar 		 */
75a31d8983SYatharth Kochar 		if (pmf_svc_descs[ii].init) {
76a31d8983SYatharth Kochar 			rc = pmf_svc_descs[ii].init();
77a31d8983SYatharth Kochar 			if (rc) {
78a31d8983SYatharth Kochar 				WARN("Could not initialize PMF"
79a31d8983SYatharth Kochar 					"service %s - skipping \n",
80a31d8983SYatharth Kochar 					pmf_svc_descs[ii].name);
81a31d8983SYatharth Kochar 				continue;
82a31d8983SYatharth Kochar 			}
83a31d8983SYatharth Kochar 		}
84a31d8983SYatharth Kochar 
85a31d8983SYatharth Kochar 		/* Update the pmf_svc_descs_indices array */
86a31d8983SYatharth Kochar 		pmf_svc_descs_indices[jj++] = ii;
87a31d8983SYatharth Kochar 	}
88a31d8983SYatharth Kochar 
89a31d8983SYatharth Kochar 	pmf_num_services = jj;
90a31d8983SYatharth Kochar 
91a31d8983SYatharth Kochar 	/*
92a31d8983SYatharth Kochar 	 * Sort the successfully registered PMF services
93a31d8983SYatharth Kochar 	 * according to service ID
94a31d8983SYatharth Kochar 	 */
95a31d8983SYatharth Kochar 	for (ii = 1; ii < pmf_num_services; ii++) {
96a31d8983SYatharth Kochar 		for (jj = 0; jj < (pmf_num_services - ii); jj++) {
97a31d8983SYatharth Kochar 			if ((pmf_svc_descs[jj].svc_config & PMF_SVC_ID_MASK) >
98a31d8983SYatharth Kochar 				(pmf_svc_descs[jj + 1].svc_config &
99a31d8983SYatharth Kochar 						PMF_SVC_ID_MASK)) {
100a31d8983SYatharth Kochar 				temp_val = pmf_svc_descs_indices[jj];
101a31d8983SYatharth Kochar 				pmf_svc_descs_indices[jj] =
102a31d8983SYatharth Kochar 						pmf_svc_descs_indices[jj+1];
103a31d8983SYatharth Kochar 				pmf_svc_descs_indices[jj+1] = temp_val;
104a31d8983SYatharth Kochar 			}
105a31d8983SYatharth Kochar 		}
106a31d8983SYatharth Kochar 	}
107a31d8983SYatharth Kochar 
108a31d8983SYatharth Kochar 	return 0;
109a31d8983SYatharth Kochar }
110a31d8983SYatharth Kochar 
111a31d8983SYatharth Kochar /*
112a31d8983SYatharth Kochar  * This function implements binary search to find registered
113a31d8983SYatharth Kochar  * PMF service based on Service ID provided in `tid` argument.
114a31d8983SYatharth Kochar  */
115a31d8983SYatharth Kochar static pmf_svc_desc_t *get_service(unsigned int tid)
116a31d8983SYatharth Kochar {
117a31d8983SYatharth Kochar 	int low = 0;
118a31d8983SYatharth Kochar 	int mid;
119a31d8983SYatharth Kochar 	int high = pmf_num_services;
120a31d8983SYatharth Kochar 	unsigned int svc_id = tid & PMF_SVC_ID_MASK;
121a31d8983SYatharth Kochar 	int index;
122a31d8983SYatharth Kochar 	unsigned int desc_svc_id;
123a31d8983SYatharth Kochar 
124a31d8983SYatharth Kochar 	if (pmf_num_services == 0)
125a31d8983SYatharth Kochar 		return NULL;
126a31d8983SYatharth Kochar 
127a31d8983SYatharth Kochar 	assert(pmf_svc_descs);
128a31d8983SYatharth Kochar 
129a31d8983SYatharth Kochar 	do {
130a31d8983SYatharth Kochar 		mid = (low + high) / 2;
131a31d8983SYatharth Kochar 		index = pmf_svc_descs_indices[mid];
132a31d8983SYatharth Kochar 
133a31d8983SYatharth Kochar 		desc_svc_id = pmf_svc_descs[index].svc_config & PMF_SVC_ID_MASK;
134a31d8983SYatharth Kochar 		if (svc_id < desc_svc_id)
135a31d8983SYatharth Kochar 			high = mid - 1;
136a31d8983SYatharth Kochar 		if (svc_id > desc_svc_id)
137a31d8983SYatharth Kochar 			low = mid + 1;
138a31d8983SYatharth Kochar 	} while ((svc_id != desc_svc_id) && (low <= high));
139a31d8983SYatharth Kochar 
140a31d8983SYatharth Kochar 	/*
141a31d8983SYatharth Kochar 	 * Make sure the Service found supports the tid range.
142a31d8983SYatharth Kochar 	 */
143a31d8983SYatharth Kochar 	if ((svc_id == desc_svc_id) && ((tid & PMF_TID_MASK) <
144a31d8983SYatharth Kochar 		(pmf_svc_descs[index].svc_config & PMF_TID_MASK)))
145a31d8983SYatharth Kochar 		return (pmf_svc_desc_t *)&pmf_svc_descs[index];
146a31d8983SYatharth Kochar 
147a31d8983SYatharth Kochar 	return NULL;
148a31d8983SYatharth Kochar }
149a31d8983SYatharth Kochar 
150a31d8983SYatharth Kochar /*
151a31d8983SYatharth Kochar  * This function gets the time-stamp value for the PMF services
152a31d8983SYatharth Kochar  * registered for SMC interface based on `tid` and `mpidr`.
153a31d8983SYatharth Kochar  */
154a31d8983SYatharth Kochar int pmf_get_timestamp_smc(unsigned int tid,
155a31d8983SYatharth Kochar 		u_register_t mpidr,
156a31d8983SYatharth Kochar 		unsigned int flags,
157a31d8983SYatharth Kochar 		unsigned long long *ts_value)
158a31d8983SYatharth Kochar {
159a31d8983SYatharth Kochar 	pmf_svc_desc_t *svc_desc;
160a31d8983SYatharth Kochar 	assert(ts_value);
161a31d8983SYatharth Kochar 
162a31d8983SYatharth Kochar 	/* Search for registered service. */
163a31d8983SYatharth Kochar 	svc_desc = get_service(tid);
164a31d8983SYatharth Kochar 
165a31d8983SYatharth Kochar 	if ((svc_desc == NULL) || (plat_core_pos_by_mpidr(mpidr) < 0)) {
166a31d8983SYatharth Kochar 		*ts_value = 0;
167a31d8983SYatharth Kochar 		return -EINVAL;
168a31d8983SYatharth Kochar 	} else {
169a31d8983SYatharth Kochar 		/* Call the service time-stamp handler. */
170a31d8983SYatharth Kochar 		*ts_value = svc_desc->get_ts(tid, mpidr, flags);
171a31d8983SYatharth Kochar 		return 0;
172a31d8983SYatharth Kochar 	}
173a31d8983SYatharth Kochar }
174a31d8983SYatharth Kochar 
175a31d8983SYatharth Kochar /*
176a31d8983SYatharth Kochar  * This function can be used to dump `ts` value for given `tid`.
177a31d8983SYatharth Kochar  * Assumption is that the console is already initialized.
178a31d8983SYatharth Kochar  */
179a31d8983SYatharth Kochar void __pmf_dump_timestamp(unsigned int tid, unsigned long long ts)
180a31d8983SYatharth Kochar {
181a31d8983SYatharth Kochar 	tf_printf("PMF:cpu %u	tid %u	ts %llu\n",
182a31d8983SYatharth Kochar 		plat_my_core_pos(), tid, ts);
183a31d8983SYatharth Kochar }
184a31d8983SYatharth Kochar 
185a31d8983SYatharth Kochar /*
186a31d8983SYatharth Kochar  * This function calculate the address identified by
187a31d8983SYatharth Kochar  * `base_addr`, `tid` and `cpuid`.
188a31d8983SYatharth Kochar  */
189a31d8983SYatharth Kochar static inline uintptr_t calc_ts_addr(uintptr_t base_addr,
190a31d8983SYatharth Kochar 		unsigned int tid,
191a31d8983SYatharth Kochar 		unsigned int cpuid)
192a31d8983SYatharth Kochar {
193a31d8983SYatharth Kochar 	assert(cpuid < PLATFORM_CORE_COUNT);
194a31d8983SYatharth Kochar 	assert(base_addr >= PMF_TIMESTAMP_ARRAY_START);
195a31d8983SYatharth Kochar 	assert(base_addr < ((PMF_TIMESTAMP_ARRAY_START +
196a31d8983SYatharth Kochar 		PMF_PERCPU_TIMESTAMP_SIZE) - ((tid & PMF_TID_MASK) *
197a31d8983SYatharth Kochar 		sizeof(unsigned long long))));
198a31d8983SYatharth Kochar 
199a31d8983SYatharth Kochar 	base_addr += ((cpuid * PMF_PERCPU_TIMESTAMP_SIZE) +
200a31d8983SYatharth Kochar 		((tid & PMF_TID_MASK) * sizeof(unsigned long long)));
201a31d8983SYatharth Kochar 
202a31d8983SYatharth Kochar 	return base_addr;
203a31d8983SYatharth Kochar }
204a31d8983SYatharth Kochar 
205a31d8983SYatharth Kochar /*
206a31d8983SYatharth Kochar  * This function stores the `ts` value to the storage identified by
207a31d8983SYatharth Kochar  * `base_addr`, `tid` and current cpu id.
208a31d8983SYatharth Kochar  * Note: The timestamp addresses are cache line aligned per cpu
209a31d8983SYatharth Kochar  * and only the owning CPU would ever write into it.
210a31d8983SYatharth Kochar  */
211a31d8983SYatharth Kochar void __pmf_store_timestamp(uintptr_t base_addr,
212a31d8983SYatharth Kochar 			unsigned int tid,
213a31d8983SYatharth Kochar 			unsigned long long ts)
214a31d8983SYatharth Kochar {
215a31d8983SYatharth Kochar 	unsigned long long *ts_addr = (unsigned long long *)calc_ts_addr(base_addr,
216a31d8983SYatharth Kochar 				 tid, plat_my_core_pos());
217a31d8983SYatharth Kochar 	*ts_addr = ts;
218a31d8983SYatharth Kochar }
219a31d8983SYatharth Kochar 
220a31d8983SYatharth Kochar /*
221a31d8983SYatharth Kochar  * This is the cached version of `pmf_store_my_timestamp`
222a31d8983SYatharth Kochar  * Note: The timestamp addresses are cache line aligned per cpu
223a31d8983SYatharth Kochar  * and only the owning CPU would ever write into it.
224a31d8983SYatharth Kochar  */
225a31d8983SYatharth Kochar void __pmf_store_timestamp_with_cache_maint(uintptr_t base_addr,
226a31d8983SYatharth Kochar 			unsigned int tid,
227a31d8983SYatharth Kochar 			unsigned long long ts)
228a31d8983SYatharth Kochar {
229a31d8983SYatharth Kochar 	unsigned long long *ts_addr = (unsigned long long *)calc_ts_addr(base_addr,
230a31d8983SYatharth Kochar 				 tid, plat_my_core_pos());
231a31d8983SYatharth Kochar 	*ts_addr = ts;
232a31d8983SYatharth Kochar 	flush_dcache_range((uintptr_t)ts_addr, sizeof(unsigned long long));
233a31d8983SYatharth Kochar }
234a31d8983SYatharth Kochar 
235a31d8983SYatharth Kochar /*
236a31d8983SYatharth Kochar  * This function retrieves the `ts` value from the storage identified by
237a31d8983SYatharth Kochar  * `base_addr`, `tid` and `cpuid`.
238a31d8983SYatharth Kochar  * Note: The timestamp addresses are cache line aligned per cpu.
239a31d8983SYatharth Kochar  */
240a31d8983SYatharth Kochar unsigned long long __pmf_get_timestamp(uintptr_t base_addr,
241a31d8983SYatharth Kochar 			unsigned int tid,
242a31d8983SYatharth Kochar 			unsigned int cpuid,
243a31d8983SYatharth Kochar 			unsigned int flags)
244a31d8983SYatharth Kochar {
245a31d8983SYatharth Kochar 	assert(cpuid < PLATFORM_CORE_COUNT);
246a31d8983SYatharth Kochar 	unsigned long long *ts_addr = (unsigned long long *)calc_ts_addr(base_addr,
247a31d8983SYatharth Kochar 				tid, cpuid);
248a31d8983SYatharth Kochar 
249a31d8983SYatharth Kochar 	if (flags & PMF_CACHE_MAINT)
250a31d8983SYatharth Kochar 		inv_dcache_range((uintptr_t)ts_addr, sizeof(unsigned long long));
251a31d8983SYatharth Kochar 
252a31d8983SYatharth Kochar 	return *ts_addr;
253a31d8983SYatharth Kochar }
254