2 * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
4 * SPDX-License-Identifier: BSD-3-Clause
12 #include <arch_helpers.h>
13 #include <common/debug.h>
14 #include <lib/pmf/pmf.h>
15 #include <lib/utils_def.h>
16 #include <plat/common/platform.h>
18 /*******************************************************************************
19 * The 'pmf_svc_descs' array holds the PMF service descriptors exported by
20 * services by placing them in the 'pmf_svc_descs' linker section.
21 * The 'pmf_svc_descs_indices' array holds the index of a descriptor in the
22 * 'pmf_svc_descs' array. The TIF[15:10] bits in the time-stamp id are used
23 * to get an index into the 'pmf_svc_descs_indices' array. This gives the
24 * index of the descriptor in the 'pmf_svc_descs' array which contains the
25 * service function pointers.
26 ******************************************************************************/
28 IMPORT_SYM(uintptr_t, __PMF_SVC_DESCS_START__
, PMF_SVC_DESCS_START
);
29 IMPORT_SYM(uintptr_t, __PMF_SVC_DESCS_END__
, PMF_SVC_DESCS_END
);
30 IMPORT_SYM(uintptr_t, __PMF_PERCPU_TIMESTAMP_END__
, PMF_PERCPU_TIMESTAMP_END
);
31 IMPORT_SYM(uintptr_t, __PMF_TIMESTAMP_START__
, PMF_TIMESTAMP_ARRAY_START
);
33 #define PMF_PERCPU_TIMESTAMP_SIZE (PMF_PERCPU_TIMESTAMP_END - PMF_TIMESTAMP_ARRAY_START)
35 #define PMF_SVC_DESCS_MAX 10
38 * This is used to traverse through registered PMF services.
40 static pmf_svc_desc_t
*pmf_svc_descs
;
43 * This array is used to store registered PMF services in sorted order.
45 static int pmf_svc_descs_indices
[PMF_SVC_DESCS_MAX
];
48 * This is used to track total number of successfully registered PMF services.
50 static int pmf_num_services
;
53 * This is the main PMF function that initialize registered
54 * PMF services and also sort them in ascending order.
59 int pmf_svc_descs_num
, temp_val
;
61 /* If no PMF services are registered then simply bail out */
62 pmf_svc_descs_num
= (PMF_SVC_DESCS_END
- PMF_SVC_DESCS_START
)/
63 sizeof(pmf_svc_desc_t
);
64 if (pmf_svc_descs_num
== 0)
67 assert(pmf_svc_descs_num
< PMF_SVC_DESCS_MAX
);
69 pmf_svc_descs
= (pmf_svc_desc_t
*) PMF_SVC_DESCS_START
;
70 for (ii
= 0; ii
< pmf_svc_descs_num
; ii
++) {
72 assert(pmf_svc_descs
[ii
].get_ts
!= NULL
);
75 * Call the initialization routine for this
76 * PMF service, if it is defined.
78 if (pmf_svc_descs
[ii
].init
!= NULL
) {
79 rc
= pmf_svc_descs
[ii
].init();
81 WARN("Could not initialize PMF"
82 "service %s - skipping \n",
83 pmf_svc_descs
[ii
].name
);
88 /* Update the pmf_svc_descs_indices array */
89 pmf_svc_descs_indices
[jj
++] = ii
;
92 pmf_num_services
= jj
;
95 * Sort the successfully registered PMF services
96 * according to service ID
98 for (ii
= 1; ii
< pmf_num_services
; ii
++) {
99 for (jj
= 0; jj
< (pmf_num_services
- ii
); jj
++) {
100 if ((pmf_svc_descs
[jj
].svc_config
& PMF_SVC_ID_MASK
) >
101 (pmf_svc_descs
[jj
+ 1].svc_config
&
103 temp_val
= pmf_svc_descs_indices
[jj
];
104 pmf_svc_descs_indices
[jj
] =
105 pmf_svc_descs_indices
[jj
+1];
106 pmf_svc_descs_indices
[jj
+1] = temp_val
;
115 * This function implements binary search to find registered
116 * PMF service based on Service ID provided in `tid` argument.
118 static pmf_svc_desc_t
*get_service(unsigned int tid
)
122 int high
= pmf_num_services
;
123 unsigned int svc_id
= tid
& PMF_SVC_ID_MASK
;
125 unsigned int desc_svc_id
;
127 if (pmf_num_services
== 0)
130 assert(pmf_svc_descs
!= NULL
);
133 mid
= (low
+ high
) / 2;
134 index
= pmf_svc_descs_indices
[mid
];
136 desc_svc_id
= pmf_svc_descs
[index
].svc_config
& PMF_SVC_ID_MASK
;
137 if (svc_id
< desc_svc_id
)
139 if (svc_id
> desc_svc_id
)
141 } while ((svc_id
!= desc_svc_id
) && (low
<= high
));
144 * Make sure the Service found supports the tid range.
146 if ((svc_id
== desc_svc_id
) && ((tid
& PMF_TID_MASK
) <
147 (pmf_svc_descs
[index
].svc_config
& PMF_TID_MASK
)))
148 return (pmf_svc_desc_t
*)&pmf_svc_descs
[index
];
154 * This function gets the time-stamp value for the PMF services
155 * registered for SMC interface based on `tid` and `mpidr`.
157 int pmf_get_timestamp_smc(unsigned int tid
,
160 unsigned long long *ts_value
)
162 pmf_svc_desc_t
*svc_desc
;
163 assert(ts_value
!= NULL
);
165 /* Search for registered service. */
166 svc_desc
= get_service(tid
);
168 if ((svc_desc
== NULL
) || (plat_core_pos_by_mpidr(mpidr
) < 0)) {
172 /* Call the service time-stamp handler. */
173 *ts_value
= svc_desc
->get_ts(tid
, mpidr
, flags
);
179 * This function can be used to dump `ts` value for given `tid`.
180 * Assumption is that the console is already initialized.
182 void __pmf_dump_timestamp(unsigned int tid
, unsigned long long ts
)
184 printf("PMF:cpu %u tid %u ts %llu\n",
185 plat_my_core_pos(), tid
, ts
);
189 * This function calculate the address identified by
190 * `base_addr`, `tid` and `cpuid`.
192 static inline uintptr_t calc_ts_addr(uintptr_t base_addr
,
196 assert(cpuid
< PLATFORM_CORE_COUNT
);
197 assert(base_addr
>= PMF_TIMESTAMP_ARRAY_START
);
198 assert(base_addr
< ((PMF_TIMESTAMP_ARRAY_START
+
199 PMF_PERCPU_TIMESTAMP_SIZE
) - ((tid
& PMF_TID_MASK
) *
200 sizeof(unsigned long long))));
202 base_addr
+= ((cpuid
* PMF_PERCPU_TIMESTAMP_SIZE
) +
203 ((tid
& PMF_TID_MASK
) * sizeof(unsigned long long)));
209 * This function stores the `ts` value to the storage identified by
210 * `base_addr`, `tid` and current cpu id.
211 * Note: The timestamp addresses are cache line aligned per cpu
212 * and only the owning CPU would ever write into it.
214 void __pmf_store_timestamp(uintptr_t base_addr
,
216 unsigned long long ts
)
218 unsigned long long *ts_addr
= (unsigned long long *)calc_ts_addr(base_addr
,
219 tid
, plat_my_core_pos());
224 * This is the cached version of `pmf_store_my_timestamp`
225 * Note: The timestamp addresses are cache line aligned per cpu
226 * and only the owning CPU would ever write into it.
228 void __pmf_store_timestamp_with_cache_maint(uintptr_t base_addr
,
230 unsigned long long ts
)
232 unsigned long long *ts_addr
= (unsigned long long *)calc_ts_addr(base_addr
,
233 tid
, plat_my_core_pos());
235 flush_dcache_range((uintptr_t)ts_addr
, sizeof(unsigned long long));
239 * This function retrieves the `ts` value from the storage identified by
240 * `base_addr`, `tid` and `cpuid`.
241 * Note: The timestamp addresses are cache line aligned per cpu.
243 unsigned long long __pmf_get_timestamp(uintptr_t base_addr
,
248 assert(cpuid
< PLATFORM_CORE_COUNT
);
249 unsigned long long *ts_addr
= (unsigned long long *)calc_ts_addr(base_addr
,
252 if ((flags
& PMF_CACHE_MAINT
) != 0U)
253 inv_dcache_range((uintptr_t)ts_addr
, sizeof(unsigned long long));