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