blob: 49733cfb6ba7b02917c246d12d8369908d74801f [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
2 * Copyright (c) 2018, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7/*
8 * This file contains tests that measure the round trip latency of an SMC.
9 * The SMC calls used are simple ones (PSCI_VERSION and the Standard Service
10 * UID) that involve almost no handling on the EL3 firmware's side so that we
11 * come close to measuring the overhead of the SMC itself.
12 */
13
14#include <arch_helpers.h>
15#include <arm_arch_svc.h>
16#include <debug.h>
17#include <psci.h>
18#include <smccc.h>
19#include <std_svc.h>
20#include <string.h>
21#include <tftf_lib.h>
22#include <utils_def.h>
23
24#define ITERATIONS_CNT 1000
25static unsigned long long raw_results[ITERATIONS_CNT];
26
27/* Latency information in nano-seconds */
28struct latency_info {
29 unsigned long long min;
30 unsigned long long max;
31 unsigned long long avg;
32};
33
34static inline unsigned long long cycles_to_ns(unsigned long long cycles)
35{
36 unsigned long long freq = read_cntfrq_el0();
37 return (cycles * 1000000000) / freq;
38}
39
40/*
41 * Send the given SMC 'ITERATIONS_CNT' times, measure the time it takes to
42 * return back from the SMC call each time, and gather some statistics across
43 * the whole series.
44 *
45 * The statistics consist of:
46 * - minimum latency (i.e the shortest duration across the whole series);
47 * - maximum latency (i.e the longest duration across the whole series);
48 * - average latency.
49 *
50 * These statistics are stored in the latency_info structure whose address
51 * is passed as an argument.
52 *
53 * This function also prints some additional, intermediate information, like the
54 * number of cycles for each SMC and the average number of cycles for an SMC
55 * round trip.
56 */
57static void test_measure_smc_latency(const smc_args *smc_args,
58 struct latency_info *latency)
59{
60 unsigned long long cycles;
61 unsigned long long min_cycles;
62 unsigned long long max_cycles;
63 unsigned long long avg_cycles;
64 unsigned long long cycles_sum = 0;
65
66 min_cycles = UINT64_MAX;
67 max_cycles = 0;
68 memset(raw_results, 0, sizeof(raw_results));
69
70 for (unsigned int i = 0; i < ITERATIONS_CNT; ++i) {
71 cycles = read_cntpct_el0();
72 tftf_smc(smc_args);
73 cycles = read_cntpct_el0() - cycles;
74
75 min_cycles = MIN(min_cycles, cycles);
76 max_cycles = MAX(max_cycles, cycles);
77
78 cycles_sum += cycles;
79
80 raw_results[i] = cycles;
81 }
82
83 avg_cycles = cycles_sum / ITERATIONS_CNT;
84 tftf_testcase_printf("Average number of cycles: %llu\n",
85 (unsigned long long) avg_cycles);
86 latency->min = cycles_to_ns(min_cycles);
87 latency->max = cycles_to_ns(max_cycles);
88 latency->avg = cycles_to_ns(avg_cycles);
89
90 NOTICE("Raw results:\n");
91 for (unsigned int i = 0; i < ITERATIONS_CNT; ++i) {
92 NOTICE("%llu cycles\t%llu ns\n",
93 raw_results[i], cycles_to_ns(raw_results[i]));
94 }
95}
96
97/*
98 * Measure the latency of the PSCI_VERSION SMC and print the result.
99 * This test always succeed.
100 */
101test_result_t smc_psci_version_latency(void)
102{
103 struct latency_info latency;
104 smc_args args = { SMC_PSCI_VERSION };
105
106 test_measure_smc_latency(&args, &latency);
107 tftf_testcase_printf(
108 "Average time: %llu ns (ranging from %llu to %llu)\n",
109 (unsigned long long) latency.avg,
110 (unsigned long long) latency.min,
111 (unsigned long long) latency.max);
112
113 return TEST_RESULT_SUCCESS;
114}
115
116/*
117 * Measure the latency of the Standard Service Call UID SMC and print the
118 * result.
119 * This test always succeed.
120 */
121test_result_t smc_std_svc_call_uid_latency(void)
122{
123 struct latency_info latency;
124 smc_args args = { SMC_STD_SVC_UID };
125
126 test_measure_smc_latency(&args, &latency);
127 tftf_testcase_printf(
128 "Average time: %llu ns (ranging from %llu to %llu)\n",
129 (unsigned long long) latency.avg,
130 (unsigned long long) latency.min,
131 (unsigned long long) latency.max);
132
133 return TEST_RESULT_SUCCESS;
134}
135
136test_result_t smc_arch_workaround_1(void)
137{
138 struct latency_info latency;
139 smc_args args;
140 smc_ret_values ret;
141 int32_t expected_ver;
142
143 /* Check if SMCCC version is at least v1.1 */
144 expected_ver = MAKE_SMCCC_VERSION(1, 1);
145 memset(&args, 0, sizeof(args));
Sandrine Bailleux17795062018-12-13 16:02:41 +0100146 args.fid = SMCCC_VERSION;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200147 ret = tftf_smc(&args);
148 if ((int32_t)ret.ret0 < expected_ver) {
149 printf("Unexpected SMCCC version: 0x%x\n",
150 (int)ret.ret0);
151 return TEST_RESULT_SKIPPED;
152 }
153
154 /* Check if SMCCC_ARCH_WORKAROUND_1 is implemented */
155 memset(&args, 0, sizeof(args));
Sandrine Bailleux17795062018-12-13 16:02:41 +0100156 args.fid = SMCCC_ARCH_FEATURES;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200157 args.arg1 = SMCCC_ARCH_WORKAROUND_1;
158 ret = tftf_smc(&args);
159 if ((int)ret.ret0 == -1) {
160 printf("SMCCC_ARCH_WORKAROUND_1 is not implemented\n");
161 return TEST_RESULT_SKIPPED;
162 }
163
164 memset(&args, 0, sizeof(args));
Sandrine Bailleux17795062018-12-13 16:02:41 +0100165 args.fid = SMCCC_ARCH_WORKAROUND_1;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200166
167 test_measure_smc_latency(&args, &latency);
168 tftf_testcase_printf(
169 "Average time: %llu ns (ranging from %llu to %llu)\n",
170 (unsigned long long) latency.avg,
171 (unsigned long long) latency.min,
172 (unsigned long long) latency.max);
173
174 return TEST_RESULT_SUCCESS;
175}