1 /*
2  * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #ifndef PMF_HELPERS_H
8 #define PMF_HELPERS_H
9 
10 #include <assert.h>
11 #include <stddef.h>
12 #include <stdint.h>
13 
14 #include <arch_helpers.h>
15 #include <common/bl_common.h>
16 #include <plat/common/platform.h>
17 
18 /*
19  * Prototype for PMF service functions.
20  */
21 typedef int (*pmf_svc_init_t)(void);
22 typedef unsigned long long (*pmf_svc_get_ts_t)(unsigned int tid,
23 		 u_register_t mpidr,
24 		 unsigned int flags);
25 
26 /*
27  * This is the definition of PMF service desc.
28  */
29 typedef struct pmf_svc_desc {
30 	/* Structure version information */
31 	param_header_t h;
32 
33 	/* Name of the PMF service */
34 	const char *name;
35 
36 	/* PMF service config: Implementer id, Service id and total id*/
37 	unsigned int svc_config;
38 
39 	/* PMF service initialization handler */
40 	pmf_svc_init_t init;
41 
42 	/* PMF service time-stamp retrieval handler */
43 	pmf_svc_get_ts_t get_ts;
44 } pmf_svc_desc_t;
45 
46 #if ENABLE_PMF
47 /*
48  * Convenience macros for capturing time-stamp.
49  */
50 #define PMF_DECLARE_CAPTURE_TIMESTAMP(_name)			\
51 	void pmf_capture_timestamp_with_cache_maint_ ## _name(	\
52 				unsigned int tid,		\
53 				unsigned long long ts);		\
54 	void pmf_capture_timestamp_ ## _name(			\
55 				unsigned int tid,		\
56 				unsigned long long ts);
57 
58 #define PMF_CAPTURE_TIMESTAMP(_name, _tid, _flags)			\
59 	do {								\
60 		unsigned long long ts = read_cntpct_el0();		\
61 		if (((_flags) & PMF_CACHE_MAINT) != 0U)			\
62 			pmf_capture_timestamp_with_cache_maint_ ## _name((_tid), ts);\
63 		else							\
64 			pmf_capture_timestamp_ ## _name((_tid), ts);	\
65 	} while (0)
66 
67 #define PMF_CAPTURE_AND_GET_TIMESTAMP(_name, _tid, _flags, _tsval)	\
68 	do {								\
69 		(_tsval) = read_cntpct_el0();				\
70 		CASSERT(sizeof(_tsval) == sizeof(unsigned long long), invalid_tsval_size);\
71 		if (((_flags) & PMF_CACHE_MAINT) != 0U)			\
72 			pmf_capture_timestamp_with_cache_maint_ ## _name((_tid), (_tsval));\
73 		else							\
74 			pmf_capture_timestamp_ ## _name((_tid), (_tsval));\
75 	} while (0)
76 
77 #define PMF_WRITE_TIMESTAMP(_name, _tid, _flags, _wrval)		\
78 	do {								\
79 		CASSERT(sizeof(_wrval) == sizeof(unsigned long long), invalid_wrval_size);\
80 		if (((_flags) & PMF_CACHE_MAINT) != 0U)			\
81 			pmf_capture_timestamp_with_cache_maint_ ## _name((_tid), (_wrval));\
82 		else							\
83 			pmf_capture_timestamp_ ## _name((_tid), (_wrval));\
84 	} while (0)
85 
86 /*
87  * Convenience macros for retrieving time-stamp.
88  */
89 #define PMF_DECLARE_GET_TIMESTAMP(_name)			\
90 	unsigned long long pmf_get_timestamp_by_index_ ## _name(\
91 		unsigned int tid,				\
92 		unsigned int cpuid,				\
93 		unsigned int flags);				\
94 	unsigned long long pmf_get_timestamp_by_mpidr_ ## _name(\
95 		unsigned int tid,				\
96 		u_register_t mpidr,				\
97 		unsigned int flags);
98 
99 #define PMF_GET_TIMESTAMP_BY_MPIDR(_name, _tid, _mpidr, _flags, _tsval)\
100 	_tsval = pmf_get_timestamp_by_mpidr_ ## _name(_tid, _mpidr, _flags)
101 
102 #define PMF_GET_TIMESTAMP_BY_INDEX(_name, _tid, _cpuid, _flags, _tsval)\
103 	_tsval = pmf_get_timestamp_by_index_ ## _name(_tid, _cpuid, _flags)
104 
105 /* Convenience macros to register a PMF service.*/
106 /*
107  * This macro is used to register a PMF Service. It allocates PMF memory
108  * and defines default service-specific PMF functions.
109  */
110 #define PMF_REGISTER_SERVICE(_name, _svcid, _totalid, _flags)	\
111 	PMF_ALLOCATE_TIMESTAMP_MEMORY(_name, _totalid)		\
112 	PMF_DEFINE_CAPTURE_TIMESTAMP(_name, _flags)		\
113 	PMF_DEFINE_GET_TIMESTAMP(_name)
114 
115 /*
116  * This macro is used to register a PMF service, including an
117  * SMC interface to that service.
118  */
119 #define PMF_REGISTER_SERVICE_SMC(_name, _svcid, _totalid, _flags)\
120 	PMF_REGISTER_SERVICE(_name, _svcid, _totalid, _flags)	\
121 	PMF_DEFINE_SERVICE_DESC(_name, PMF_ARM_TIF_IMPL_ID,	\
122 			_svcid, _totalid, NULL,			\
123 			pmf_get_timestamp_by_mpidr_ ## _name)
124 
125 /*
126  * This macro is used to register a PMF service that has an SMC interface
127  * but provides its own service-specific PMF functions.
128  */
129 #define PMF_REGISTER_SERVICE_SMC_OWN(_name, _implid, _svcid, _totalid,	\
130 		 _init, _getts)						\
131 	PMF_DEFINE_SERVICE_DESC(_name, _implid, _svcid, _totalid,	\
132 		 _init, _getts)
133 
134 #else
135 
136 #define PMF_REGISTER_SERVICE(_name, _svcid, _totalid, _flags)
137 #define PMF_REGISTER_SERVICE_SMC(_name, _svcid, _totalid, _flags)
138 #define PMF_REGISTER_SERVICE_SMC_OWN(_name, _implid, _svcid, _totalid,	\
139 				_init, _getts)
140 #define PMF_DECLARE_CAPTURE_TIMESTAMP(_name)
141 #define PMF_DECLARE_GET_TIMESTAMP(_name)
142 #define PMF_CAPTURE_TIMESTAMP(_name, _tid, _flags)
143 #define PMF_GET_TIMESTAMP_BY_MPIDR(_name, _tid, _mpidr, _flags, _tsval)
144 #define PMF_GET_TIMESTAMP_BY_INDEX(_name, _tid, _cpuid, _flags, _tsval)
145 
146 #endif /* ENABLE_PMF */
147 
148 /*
149  * Convenience macro to allocate memory for a PMF service.
150  *
151  * The extern declaration is there to satisfy MISRA C-2012 rule 8.4.
152  */
153 #define PMF_ALLOCATE_TIMESTAMP_MEMORY(_name, _total_id)		\
154 	extern unsigned long long pmf_ts_mem_ ## _name[_total_id];	\
155 	unsigned long long pmf_ts_mem_ ## _name[_total_id]	\
156 	__aligned(CACHE_WRITEBACK_GRANULE)			\
157 	__section("pmf_timestamp_array")			\
158 	__used;
159 
160 /*
161  * Convenience macro to validate tid index for the given TS array.
162  */
163 #define PMF_VALIDATE_TID(_name, _tid)	\
164 	assert((_tid & PMF_TID_MASK) < (ARRAY_SIZE(pmf_ts_mem_ ## _name)))
165 
166 /*
167  * Convenience macros for capturing time-stamp.
168  *
169  * The extern declaration is there to satisfy MISRA C-2012 rule 8.4.
170  */
171 #define PMF_DEFINE_CAPTURE_TIMESTAMP(_name, _flags)			\
172 	void pmf_capture_timestamp_ ## _name(				\
173 			unsigned int tid,				\
174 			unsigned long long ts)				\
175 	{								\
176 		CASSERT(_flags != 0, select_proper_config);		\
177 		PMF_VALIDATE_TID(_name, (uint64_t)tid);			\
178 		uintptr_t base_addr = (uintptr_t) pmf_ts_mem_ ## _name;	\
179 		if (((_flags) & PMF_STORE_ENABLE) != 0)			\
180 			__pmf_store_timestamp(base_addr,		\
181 				(uint64_t)tid, ts);			\
182 		if (((_flags) & PMF_DUMP_ENABLE) != 0)			\
183 			__pmf_dump_timestamp((uint64_t)tid, ts);	\
184 	}								\
185 	void pmf_capture_timestamp_with_cache_maint_ ## _name(		\
186 			unsigned int tid,				\
187 			unsigned long long ts)				\
188 	{								\
189 		CASSERT(_flags != 0, select_proper_config);		\
190 		PMF_VALIDATE_TID(_name, (uint64_t)tid);			\
191 		uintptr_t base_addr = (uintptr_t) pmf_ts_mem_ ## _name;	\
192 		if (((_flags) & PMF_STORE_ENABLE) != 0)			\
193 			__pmf_store_timestamp_with_cache_maint(		\
194 				base_addr, (uint64_t)tid, ts);		\
195 		if (((_flags) & PMF_DUMP_ENABLE) != 0)			\
196 			__pmf_dump_timestamp((uint64_t)tid, ts);	\
197 	}
198 
199 /*
200  * Convenience macros for retrieving time-stamp.
201  *
202  * The extern declaration is there to satisfy MISRA C-2012 rule 8.4.
203  */
204 #define PMF_DEFINE_GET_TIMESTAMP(_name)					\
205 	unsigned long long pmf_get_timestamp_by_index_ ## _name(	\
206 		unsigned int tid, unsigned int cpuid, unsigned int flags)\
207 	{								\
208 		PMF_VALIDATE_TID(_name, tid);				\
209 		uintptr_t base_addr = (uintptr_t) pmf_ts_mem_ ## _name;	\
210 		return __pmf_get_timestamp(base_addr, tid, cpuid, flags);\
211 	}								\
212 	unsigned long long pmf_get_timestamp_by_mpidr_ ## _name(	\
213 		unsigned int tid, u_register_t mpidr, unsigned int flags)\
214 	{								\
215 		PMF_VALIDATE_TID(_name, tid);				\
216 		uintptr_t base_addr = (uintptr_t) pmf_ts_mem_ ## _name;	\
217 		return __pmf_get_timestamp(base_addr, tid,		\
218 			plat_core_pos_by_mpidr(mpidr), flags);		\
219 	}
220 
221 /*
222  * Convenience macro to register a PMF service.
223  * This is needed for services that require SMC handling.
224  */
225 #define PMF_DEFINE_SERVICE_DESC(_name, _implid, _svcid, _totalid,	\
226 		_init, _getts_by_mpidr) 				\
227 	static const pmf_svc_desc_t __pmf_desc_ ## _name 		\
228 	__section("pmf_svc_descs") __used = {		 		\
229 		.h.type = PARAM_EP, 					\
230 		.h.version = VERSION_1, 				\
231 		.h.size = sizeof(pmf_svc_desc_t),			\
232 		.h.attr = 0,						\
233 		.name = #_name, 					\
234 		.svc_config = ((((_implid) << PMF_IMPL_ID_SHIFT) &	\
235 						PMF_IMPL_ID_MASK) |	\
236 				(((_svcid) << PMF_SVC_ID_SHIFT) &	\
237 						PMF_SVC_ID_MASK) |	\
238 				(((_totalid) << PMF_TID_SHIFT) &	\
239 						PMF_TID_MASK)),		\
240 		.init = _init,						\
241 		.get_ts = _getts_by_mpidr				\
242 	};
243 
244 /* PMF internal functions */
245 void __pmf_dump_timestamp(unsigned int tid, unsigned long long ts);
246 void __pmf_store_timestamp(uintptr_t base_addr,
247 		unsigned int tid,
248 		unsigned long long ts);
249 void __pmf_store_timestamp_with_cache_maint(uintptr_t base_addr,
250 		unsigned int tid,
251 		unsigned long long ts);
252 unsigned long long __pmf_get_timestamp(uintptr_t base_addr,
253 		unsigned int tid,
254 		unsigned int cpuid,
255 		unsigned int flags);
256 #endif /* PMF_HELPERS_H */
257