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