1*f1cec17aSPascal Paillet // SPDX-License-Identifier: BSD-3-Clause
2*f1cec17aSPascal Paillet /*
3*f1cec17aSPascal Paillet * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
4*f1cec17aSPascal Paillet * Copyright (c) 2021, Linaro Limited
5*f1cec17aSPascal Paillet * Copyright (c) 2024, STMicroelectronics
6*f1cec17aSPascal Paillet */
7*f1cec17aSPascal Paillet #include <assert.h>
8*f1cec17aSPascal Paillet #include <confine_array_index.h>
9*f1cec17aSPascal Paillet #include <drivers/scmi-msg.h>
10*f1cec17aSPascal Paillet #include <drivers/scmi.h>
11*f1cec17aSPascal Paillet #include <mm/core_memprot.h>
12*f1cec17aSPascal Paillet #include <string.h>
13*f1cec17aSPascal Paillet #include <util.h>
14*f1cec17aSPascal Paillet
15*f1cec17aSPascal Paillet #include "common.h"
16*f1cec17aSPascal Paillet #include "perf_domain.h"
17*f1cec17aSPascal Paillet
18*f1cec17aSPascal Paillet #define VERBOSE_MSG(...) FMSG(__VA_ARGS__)
19*f1cec17aSPascal Paillet
20*f1cec17aSPascal Paillet static bool message_id_is_supported(unsigned int message_id);
21*f1cec17aSPascal Paillet
22*f1cec17aSPascal Paillet /* Weak handlers platform shall override on purpose */
plat_scmi_perf_count(unsigned int channel_id __unused)23*f1cec17aSPascal Paillet size_t __weak plat_scmi_perf_count(unsigned int channel_id __unused)
24*f1cec17aSPascal Paillet {
25*f1cec17aSPascal Paillet return 0;
26*f1cec17aSPascal Paillet }
27*f1cec17aSPascal Paillet
plat_scmi_perf_statistics_buf(unsigned int channel_id __unused,size_t * stats_len)28*f1cec17aSPascal Paillet void __weak *plat_scmi_perf_statistics_buf(unsigned int channel_id __unused,
29*f1cec17aSPascal Paillet size_t *stats_len)
30*f1cec17aSPascal Paillet {
31*f1cec17aSPascal Paillet *stats_len = 0;
32*f1cec17aSPascal Paillet
33*f1cec17aSPascal Paillet return NULL;
34*f1cec17aSPascal Paillet }
35*f1cec17aSPascal Paillet
plat_scmi_perf_domain_name(unsigned int channel_id __unused,unsigned int domain_id __unused)36*f1cec17aSPascal Paillet const char __weak *plat_scmi_perf_domain_name(unsigned int channel_id __unused,
37*f1cec17aSPascal Paillet unsigned int domain_id __unused)
38*f1cec17aSPascal Paillet {
39*f1cec17aSPascal Paillet return NULL;
40*f1cec17aSPascal Paillet }
41*f1cec17aSPascal Paillet
plat_scmi_perf_sustained_freq(unsigned int channel_id __unused,unsigned int domain_id __unused,unsigned int * freq __unused)42*f1cec17aSPascal Paillet int32_t __weak plat_scmi_perf_sustained_freq(unsigned int channel_id __unused,
43*f1cec17aSPascal Paillet unsigned int domain_id __unused,
44*f1cec17aSPascal Paillet unsigned int *freq __unused)
45*f1cec17aSPascal Paillet {
46*f1cec17aSPascal Paillet return SCMI_NOT_SUPPORTED;
47*f1cec17aSPascal Paillet }
48*f1cec17aSPascal Paillet
plat_scmi_perf_levels_array(unsigned int channel_id __unused,unsigned int domain_id __unused,size_t start_index __unused,unsigned int * elt __unused,size_t * nb_elts __unused)49*f1cec17aSPascal Paillet int32_t __weak plat_scmi_perf_levels_array(unsigned int channel_id __unused,
50*f1cec17aSPascal Paillet unsigned int domain_id __unused,
51*f1cec17aSPascal Paillet size_t start_index __unused,
52*f1cec17aSPascal Paillet unsigned int *elt __unused,
53*f1cec17aSPascal Paillet size_t *nb_elts __unused)
54*f1cec17aSPascal Paillet {
55*f1cec17aSPascal Paillet return SCMI_NOT_SUPPORTED;
56*f1cec17aSPascal Paillet }
57*f1cec17aSPascal Paillet
plat_scmi_perf_level_latency(unsigned int channel_id __unused,unsigned int domain_id __unused,unsigned int level __unused,unsigned int * latency)58*f1cec17aSPascal Paillet int32_t __weak plat_scmi_perf_level_latency(unsigned int channel_id __unused,
59*f1cec17aSPascal Paillet unsigned int domain_id __unused,
60*f1cec17aSPascal Paillet unsigned int level __unused,
61*f1cec17aSPascal Paillet unsigned int *latency)
62*f1cec17aSPascal Paillet {
63*f1cec17aSPascal Paillet /* Use 1 microsecond because the Linux kernel treats 0 as eternal */
64*f1cec17aSPascal Paillet *latency = 1;
65*f1cec17aSPascal Paillet
66*f1cec17aSPascal Paillet return SCMI_SUCCESS;
67*f1cec17aSPascal Paillet }
68*f1cec17aSPascal Paillet
plat_scmi_perf_level_power_cost(unsigned int channel_id __unused,unsigned int domain_id __unused,unsigned int level __unused,unsigned int * cost __unused)69*f1cec17aSPascal Paillet int32_t __weak plat_scmi_perf_level_power_cost(unsigned int channel_id __unused,
70*f1cec17aSPascal Paillet unsigned int domain_id __unused,
71*f1cec17aSPascal Paillet unsigned int level __unused,
72*f1cec17aSPascal Paillet unsigned int *cost __unused)
73*f1cec17aSPascal Paillet {
74*f1cec17aSPascal Paillet *cost = 0;
75*f1cec17aSPascal Paillet
76*f1cec17aSPascal Paillet return SCMI_SUCCESS;
77*f1cec17aSPascal Paillet }
78*f1cec17aSPascal Paillet
plat_scmi_perf_level_get(unsigned int channel_id __unused,unsigned int domain_id __unused,unsigned int * level __unused)79*f1cec17aSPascal Paillet int32_t __weak plat_scmi_perf_level_get(unsigned int channel_id __unused,
80*f1cec17aSPascal Paillet unsigned int domain_id __unused,
81*f1cec17aSPascal Paillet unsigned int *level __unused)
82*f1cec17aSPascal Paillet {
83*f1cec17aSPascal Paillet return SCMI_NOT_SUPPORTED;
84*f1cec17aSPascal Paillet }
85*f1cec17aSPascal Paillet
plat_scmi_perf_level_set(unsigned int channel_id __unused,unsigned int domain_id __unused,unsigned int level __unused)86*f1cec17aSPascal Paillet int32_t __weak plat_scmi_perf_level_set(unsigned int channel_id __unused,
87*f1cec17aSPascal Paillet unsigned int domain_id __unused,
88*f1cec17aSPascal Paillet unsigned int level __unused)
89*f1cec17aSPascal Paillet {
90*f1cec17aSPascal Paillet return SCMI_NOT_SUPPORTED;
91*f1cec17aSPascal Paillet }
92*f1cec17aSPascal Paillet
protocol_version(struct scmi_msg * msg)93*f1cec17aSPascal Paillet static void protocol_version(struct scmi_msg *msg)
94*f1cec17aSPascal Paillet {
95*f1cec17aSPascal Paillet struct scmi_protocol_version_p2a return_values = {
96*f1cec17aSPascal Paillet .status = SCMI_SUCCESS,
97*f1cec17aSPascal Paillet .version = SCMI_PROTOCOL_VERSION_PERF_DOMAIN,
98*f1cec17aSPascal Paillet };
99*f1cec17aSPascal Paillet
100*f1cec17aSPascal Paillet VERBOSE_MSG("SCMI perf %#"PRIx32, SCMI_PROTOCOL_VERSION_PERF_DOMAIN);
101*f1cec17aSPascal Paillet
102*f1cec17aSPascal Paillet if (msg->in_size) {
103*f1cec17aSPascal Paillet scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
104*f1cec17aSPascal Paillet return;
105*f1cec17aSPascal Paillet }
106*f1cec17aSPascal Paillet
107*f1cec17aSPascal Paillet scmi_write_response(msg, &return_values, sizeof(return_values));
108*f1cec17aSPascal Paillet }
109*f1cec17aSPascal Paillet
protocol_attributes(struct scmi_msg * msg)110*f1cec17aSPascal Paillet static void protocol_attributes(struct scmi_msg *msg)
111*f1cec17aSPascal Paillet {
112*f1cec17aSPascal Paillet unsigned int channel_id = msg->channel_id;
113*f1cec17aSPascal Paillet size_t count = plat_scmi_perf_count(channel_id);
114*f1cec17aSPascal Paillet uint32_t power_in_mw = 0;
115*f1cec17aSPascal Paillet struct scmi_perf_protocol_attributes_p2a return_values = {
116*f1cec17aSPascal Paillet .status = SCMI_SUCCESS,
117*f1cec17aSPascal Paillet .attributes = SCMI_PERF_PROTOCOL_ATTRIBUTES(power_in_mw, count),
118*f1cec17aSPascal Paillet };
119*f1cec17aSPascal Paillet void *stats_buf = NULL;
120*f1cec17aSPascal Paillet size_t stats_len = 0;
121*f1cec17aSPascal Paillet
122*f1cec17aSPascal Paillet VERBOSE_MSG("channel %u: %zu performance domains", channel_id, count);
123*f1cec17aSPascal Paillet
124*f1cec17aSPascal Paillet if (msg->in_size) {
125*f1cec17aSPascal Paillet scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
126*f1cec17aSPascal Paillet return;
127*f1cec17aSPascal Paillet }
128*f1cec17aSPascal Paillet
129*f1cec17aSPascal Paillet stats_buf = plat_scmi_perf_statistics_buf(channel_id, &stats_len);
130*f1cec17aSPascal Paillet if (stats_len) {
131*f1cec17aSPascal Paillet paddr_t stats_pa = virt_to_phys(stats_buf);
132*f1cec17aSPascal Paillet
133*f1cec17aSPascal Paillet if (stats_pa && tee_vbuf_is_non_sec(stats_buf, stats_len)) {
134*f1cec17aSPascal Paillet return_values.statistics_len = stats_len;
135*f1cec17aSPascal Paillet reg_pair_from_64((uint64_t)stats_pa,
136*f1cec17aSPascal Paillet &return_values.statistics_address_high,
137*f1cec17aSPascal Paillet &return_values.statistics_address_low);
138*f1cec17aSPascal Paillet } else {
139*f1cec17aSPascal Paillet IMSG("Disable SCMI perf statistics: invalid buffer");
140*f1cec17aSPascal Paillet DMSG("Stats buffer va %p, pa %#"PRIxPA", size %zu",
141*f1cec17aSPascal Paillet stats_buf, stats_pa, stats_len);
142*f1cec17aSPascal Paillet }
143*f1cec17aSPascal Paillet }
144*f1cec17aSPascal Paillet
145*f1cec17aSPascal Paillet scmi_write_response(msg, &return_values, sizeof(return_values));
146*f1cec17aSPascal Paillet }
147*f1cec17aSPascal Paillet
protocol_message_attributes(struct scmi_msg * msg)148*f1cec17aSPascal Paillet static void protocol_message_attributes(struct scmi_msg *msg)
149*f1cec17aSPascal Paillet {
150*f1cec17aSPascal Paillet struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in;
151*f1cec17aSPascal Paillet struct scmi_protocol_message_attributes_p2a return_values = {
152*f1cec17aSPascal Paillet .status = SCMI_SUCCESS,
153*f1cec17aSPascal Paillet /* For this protocol, attributes shall be zero */
154*f1cec17aSPascal Paillet .attributes = 0,
155*f1cec17aSPascal Paillet };
156*f1cec17aSPascal Paillet
157*f1cec17aSPascal Paillet if (msg->in_size != sizeof(*in_args)) {
158*f1cec17aSPascal Paillet scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
159*f1cec17aSPascal Paillet return;
160*f1cec17aSPascal Paillet }
161*f1cec17aSPascal Paillet
162*f1cec17aSPascal Paillet if (!message_id_is_supported(in_args->message_id)) {
163*f1cec17aSPascal Paillet scmi_status_response(msg, SCMI_NOT_FOUND);
164*f1cec17aSPascal Paillet return;
165*f1cec17aSPascal Paillet }
166*f1cec17aSPascal Paillet
167*f1cec17aSPascal Paillet scmi_write_response(msg, &return_values, sizeof(return_values));
168*f1cec17aSPascal Paillet }
169*f1cec17aSPascal Paillet
sanitize_message(struct scmi_msg * msg,unsigned int * domain_id,size_t exp_in_size)170*f1cec17aSPascal Paillet static int32_t sanitize_message(struct scmi_msg *msg, unsigned int *domain_id,
171*f1cec17aSPascal Paillet size_t exp_in_size)
172*f1cec17aSPascal Paillet {
173*f1cec17aSPascal Paillet size_t domain_count = plat_scmi_perf_count(msg->channel_id);
174*f1cec17aSPascal Paillet
175*f1cec17aSPascal Paillet *domain_id = confine_array_index(*domain_id, domain_count);
176*f1cec17aSPascal Paillet
177*f1cec17aSPascal Paillet if (msg->in_size != exp_in_size)
178*f1cec17aSPascal Paillet return SCMI_PROTOCOL_ERROR;
179*f1cec17aSPascal Paillet
180*f1cec17aSPascal Paillet if (*domain_id >= domain_count)
181*f1cec17aSPascal Paillet return SCMI_INVALID_PARAMETERS;
182*f1cec17aSPascal Paillet
183*f1cec17aSPascal Paillet return SCMI_SUCCESS;
184*f1cec17aSPascal Paillet }
185*f1cec17aSPascal Paillet
scmi_perf_domain_attributes(struct scmi_msg * msg)186*f1cec17aSPascal Paillet static void scmi_perf_domain_attributes(struct scmi_msg *msg)
187*f1cec17aSPascal Paillet {
188*f1cec17aSPascal Paillet const struct scmi_perf_attributes_a2p *in_args = (void *)msg->in;
189*f1cec17aSPascal Paillet /* It is safe to read in_args->domain_id before sanitize_message() */
190*f1cec17aSPascal Paillet unsigned int domain_id = in_args->domain_id;
191*f1cec17aSPascal Paillet int32_t res = SCMI_GENERIC_ERROR;
192*f1cec17aSPascal Paillet struct scmi_perf_attributes_p2a return_values = {
193*f1cec17aSPascal Paillet .attributes = SCMI_PERF_DOMAIN_ATTRIBUTES_CAN_SET_LEVEL,
194*f1cec17aSPascal Paillet .status = SCMI_SUCCESS,
195*f1cec17aSPascal Paillet };
196*f1cec17aSPascal Paillet const char *name = NULL;
197*f1cec17aSPascal Paillet
198*f1cec17aSPascal Paillet FMSG("channel %u: domain %u", msg->channel_id, domain_id);
199*f1cec17aSPascal Paillet
200*f1cec17aSPascal Paillet res = sanitize_message(msg, &domain_id, sizeof(*in_args));
201*f1cec17aSPascal Paillet if (res) {
202*f1cec17aSPascal Paillet scmi_status_response(msg, res);
203*f1cec17aSPascal Paillet return;
204*f1cec17aSPascal Paillet }
205*f1cec17aSPascal Paillet
206*f1cec17aSPascal Paillet name = plat_scmi_perf_domain_name(msg->channel_id, domain_id);
207*f1cec17aSPascal Paillet if (!name) {
208*f1cec17aSPascal Paillet scmi_status_response(msg, SCMI_NOT_FOUND);
209*f1cec17aSPascal Paillet return;
210*f1cec17aSPascal Paillet }
211*f1cec17aSPascal Paillet
212*f1cec17aSPascal Paillet res = plat_scmi_perf_sustained_freq(msg->channel_id, domain_id,
213*f1cec17aSPascal Paillet &return_values.sustained_freq);
214*f1cec17aSPascal Paillet if (res) {
215*f1cec17aSPascal Paillet scmi_status_response(msg, res);
216*f1cec17aSPascal Paillet return;
217*f1cec17aSPascal Paillet }
218*f1cec17aSPascal Paillet
219*f1cec17aSPascal Paillet COPY_NAME_IDENTIFIER(return_values.name, name);
220*f1cec17aSPascal Paillet
221*f1cec17aSPascal Paillet /*
222*f1cec17aSPascal Paillet * .rate_limit and .sustained_perf_level are
223*f1cec17aSPascal Paillet * implicitly set to 0.
224*f1cec17aSPascal Paillet */
225*f1cec17aSPascal Paillet
226*f1cec17aSPascal Paillet VERBOSE_MSG("channel %u: domain %u: name \"%s\"", msg->channel_id,
227*f1cec17aSPascal Paillet domain_id, name);
228*f1cec17aSPascal Paillet
229*f1cec17aSPascal Paillet scmi_write_response(msg, &return_values, sizeof(return_values));
230*f1cec17aSPascal Paillet }
231*f1cec17aSPascal Paillet
scmi_perf_level_get(struct scmi_msg * msg)232*f1cec17aSPascal Paillet static void scmi_perf_level_get(struct scmi_msg *msg)
233*f1cec17aSPascal Paillet {
234*f1cec17aSPascal Paillet const struct scmi_perf_level_get_a2p *in_args = (void *)msg->in;
235*f1cec17aSPascal Paillet /* It is safe to read in_args->domain_id before sanitize_message() */
236*f1cec17aSPascal Paillet unsigned int domain_id = in_args->domain_id;
237*f1cec17aSPascal Paillet int32_t res = SCMI_GENERIC_ERROR;
238*f1cec17aSPascal Paillet unsigned int level = 0;
239*f1cec17aSPascal Paillet struct scmi_perf_level_get_p2a return_values = {
240*f1cec17aSPascal Paillet .status = SCMI_SUCCESS,
241*f1cec17aSPascal Paillet };
242*f1cec17aSPascal Paillet
243*f1cec17aSPascal Paillet VERBOSE_MSG("channel %u, domain %u", msg->channel_id, domain_id);
244*f1cec17aSPascal Paillet
245*f1cec17aSPascal Paillet res = sanitize_message(msg, &domain_id, sizeof(*in_args));
246*f1cec17aSPascal Paillet if (res) {
247*f1cec17aSPascal Paillet scmi_status_response(msg, res);
248*f1cec17aSPascal Paillet return;
249*f1cec17aSPascal Paillet }
250*f1cec17aSPascal Paillet
251*f1cec17aSPascal Paillet res = plat_scmi_perf_level_get(msg->channel_id, domain_id, &level);
252*f1cec17aSPascal Paillet if (res) {
253*f1cec17aSPascal Paillet scmi_status_response(msg, res);
254*f1cec17aSPascal Paillet return;
255*f1cec17aSPascal Paillet }
256*f1cec17aSPascal Paillet
257*f1cec17aSPascal Paillet assert(level <= UINT32_MAX);
258*f1cec17aSPascal Paillet return_values.performance_level = level;
259*f1cec17aSPascal Paillet
260*f1cec17aSPascal Paillet VERBOSE_MSG("channel %u, domain %u: level %u", msg->channel_id,
261*f1cec17aSPascal Paillet domain_id, level);
262*f1cec17aSPascal Paillet
263*f1cec17aSPascal Paillet scmi_write_response(msg, &return_values, sizeof(return_values));
264*f1cec17aSPascal Paillet }
265*f1cec17aSPascal Paillet
scmi_perf_level_set(struct scmi_msg * msg)266*f1cec17aSPascal Paillet static void scmi_perf_level_set(struct scmi_msg *msg)
267*f1cec17aSPascal Paillet {
268*f1cec17aSPascal Paillet const struct scmi_perf_level_set_a2p *in_args = (void *)msg->in;
269*f1cec17aSPascal Paillet unsigned int channel_id = msg->channel_id;
270*f1cec17aSPascal Paillet /* It is safe to read in in_args before sanitize_message() */
271*f1cec17aSPascal Paillet unsigned int domain_id = in_args->domain_id;
272*f1cec17aSPascal Paillet unsigned int level = in_args->performance_level;
273*f1cec17aSPascal Paillet int32_t res = SCMI_GENERIC_ERROR;
274*f1cec17aSPascal Paillet
275*f1cec17aSPascal Paillet VERBOSE_MSG("channel %u, domain %u: set level %u", channel_id,
276*f1cec17aSPascal Paillet domain_id, level);
277*f1cec17aSPascal Paillet
278*f1cec17aSPascal Paillet res = sanitize_message(msg, &domain_id, sizeof(*in_args));
279*f1cec17aSPascal Paillet if (res == SCMI_SUCCESS)
280*f1cec17aSPascal Paillet res = plat_scmi_perf_level_set(channel_id, domain_id, level);
281*f1cec17aSPascal Paillet
282*f1cec17aSPascal Paillet scmi_status_response(msg, res);
283*f1cec17aSPascal Paillet }
284*f1cec17aSPascal Paillet
285*f1cec17aSPascal Paillet /* List levels array by small chunks fitting in SCMI message max payload size */
286*f1cec17aSPascal Paillet #define LEVELS_ARRAY_SIZE \
287*f1cec17aSPascal Paillet ((SCMI_SEC_PAYLOAD_SIZE - \
288*f1cec17aSPascal Paillet sizeof(struct scmi_perf_describe_levels_a2p)) / \
289*f1cec17aSPascal Paillet sizeof(struct scmi_perf_level))
290*f1cec17aSPascal Paillet
scmi_perf_describe_levels(struct scmi_msg * msg)291*f1cec17aSPascal Paillet static void scmi_perf_describe_levels(struct scmi_msg *msg)
292*f1cec17aSPascal Paillet {
293*f1cec17aSPascal Paillet const struct scmi_perf_describe_levels_a2p *in_args = (void *)msg->in;
294*f1cec17aSPascal Paillet size_t nb_levels = 0;
295*f1cec17aSPascal Paillet /* It is safe to read in_args->domain_id before sanitize_message() */
296*f1cec17aSPascal Paillet unsigned int domain_id = in_args->domain_id;
297*f1cec17aSPascal Paillet int32_t res = SCMI_GENERIC_ERROR;
298*f1cec17aSPascal Paillet /* Use the stack to get the returned a portion of the level array */
299*f1cec17aSPascal Paillet unsigned int plat_levels[LEVELS_ARRAY_SIZE] = { 0 };
300*f1cec17aSPascal Paillet size_t ret_nb = 0;
301*f1cec17aSPascal Paillet size_t rem_nb = 0;
302*f1cec17aSPascal Paillet
303*f1cec17aSPascal Paillet VERBOSE_MSG("channel %u, domain %u", msg->channel_id, domain_id);
304*f1cec17aSPascal Paillet
305*f1cec17aSPascal Paillet res = sanitize_message(msg, &domain_id, sizeof(*in_args));
306*f1cec17aSPascal Paillet if (res)
307*f1cec17aSPascal Paillet goto err;
308*f1cec17aSPascal Paillet
309*f1cec17aSPascal Paillet res = plat_scmi_perf_levels_array(msg->channel_id, domain_id, 0,
310*f1cec17aSPascal Paillet NULL, &nb_levels);
311*f1cec17aSPascal Paillet if (res)
312*f1cec17aSPascal Paillet goto err;
313*f1cec17aSPascal Paillet
314*f1cec17aSPascal Paillet if (in_args->level_index >= nb_levels) {
315*f1cec17aSPascal Paillet res = SCMI_INVALID_PARAMETERS;
316*f1cec17aSPascal Paillet goto err;
317*f1cec17aSPascal Paillet }
318*f1cec17aSPascal Paillet
319*f1cec17aSPascal Paillet ret_nb = MIN(ARRAY_SIZE(plat_levels), nb_levels - in_args->level_index);
320*f1cec17aSPascal Paillet rem_nb = nb_levels - in_args->level_index - ret_nb;
321*f1cec17aSPascal Paillet
322*f1cec17aSPascal Paillet res = plat_scmi_perf_levels_array(msg->channel_id, domain_id,
323*f1cec17aSPascal Paillet in_args->level_index, plat_levels,
324*f1cec17aSPascal Paillet &ret_nb);
325*f1cec17aSPascal Paillet
326*f1cec17aSPascal Paillet if (res == SCMI_SUCCESS) {
327*f1cec17aSPascal Paillet struct scmi_perf_describe_levels_p2a p2a = {
328*f1cec17aSPascal Paillet .status = SCMI_SUCCESS,
329*f1cec17aSPascal Paillet .num_levels = SCMI_PERF_NUM_LEVELS(ret_nb, rem_nb),
330*f1cec17aSPascal Paillet };
331*f1cec17aSPascal Paillet struct scmi_perf_level *levels = NULL;
332*f1cec17aSPascal Paillet size_t n = 0;
333*f1cec17aSPascal Paillet
334*f1cec17aSPascal Paillet memcpy(msg->out, &p2a, sizeof(p2a));
335*f1cec17aSPascal Paillet
336*f1cec17aSPascal Paillet /* By construction these values are 32bit aligned */
337*f1cec17aSPascal Paillet levels = (void *)(uintptr_t)(msg->out + sizeof(p2a));
338*f1cec17aSPascal Paillet
339*f1cec17aSPascal Paillet for (n = 0; n < ret_nb; n++) {
340*f1cec17aSPascal Paillet unsigned int latency = 0;
341*f1cec17aSPascal Paillet unsigned int power_cost = 0;
342*f1cec17aSPascal Paillet
343*f1cec17aSPascal Paillet res = plat_scmi_perf_level_latency(msg->channel_id,
344*f1cec17aSPascal Paillet domain_id,
345*f1cec17aSPascal Paillet plat_levels[n],
346*f1cec17aSPascal Paillet &latency);
347*f1cec17aSPascal Paillet if (res != SCMI_SUCCESS)
348*f1cec17aSPascal Paillet goto err;
349*f1cec17aSPascal Paillet
350*f1cec17aSPascal Paillet assert(latency <= UINT16_MAX);
351*f1cec17aSPascal Paillet latency &= SCMI_PERF_LEVEL_ATTRIBUTES_LATENCY_US_MASK;
352*f1cec17aSPascal Paillet
353*f1cec17aSPascal Paillet res = plat_scmi_perf_level_power_cost(msg->channel_id,
354*f1cec17aSPascal Paillet domain_id,
355*f1cec17aSPascal Paillet plat_levels[n],
356*f1cec17aSPascal Paillet &power_cost);
357*f1cec17aSPascal Paillet if (res != SCMI_SUCCESS)
358*f1cec17aSPascal Paillet goto err;
359*f1cec17aSPascal Paillet
360*f1cec17aSPascal Paillet levels[n] = (struct scmi_perf_level){
361*f1cec17aSPascal Paillet .performance_level = plat_levels[n],
362*f1cec17aSPascal Paillet .power_cost = power_cost,
363*f1cec17aSPascal Paillet .attributes = latency,
364*f1cec17aSPascal Paillet };
365*f1cec17aSPascal Paillet }
366*f1cec17aSPascal Paillet
367*f1cec17aSPascal Paillet msg->out_size_out =
368*f1cec17aSPascal Paillet sizeof(p2a) + ret_nb * sizeof(struct scmi_perf_level);
369*f1cec17aSPascal Paillet
370*f1cec17aSPascal Paillet return;
371*f1cec17aSPascal Paillet }
372*f1cec17aSPascal Paillet
373*f1cec17aSPascal Paillet err:
374*f1cec17aSPascal Paillet assert(res);
375*f1cec17aSPascal Paillet scmi_status_response(msg, res);
376*f1cec17aSPascal Paillet }
377*f1cec17aSPascal Paillet
378*f1cec17aSPascal Paillet static const scmi_msg_handler_t scmi_perf_handler_table[] = {
379*f1cec17aSPascal Paillet [SCMI_PROTOCOL_VERSION] = protocol_version,
380*f1cec17aSPascal Paillet [SCMI_PROTOCOL_ATTRIBUTES] = protocol_attributes,
381*f1cec17aSPascal Paillet [SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = protocol_message_attributes,
382*f1cec17aSPascal Paillet [SCMI_PERF_DOMAIN_ATTRIBUTES] = scmi_perf_domain_attributes,
383*f1cec17aSPascal Paillet [SCMI_PERF_DESCRIBE_LEVELS] = scmi_perf_describe_levels,
384*f1cec17aSPascal Paillet [SCMI_PERF_LEVEL_SET] = scmi_perf_level_set,
385*f1cec17aSPascal Paillet [SCMI_PERF_LEVEL_GET] = scmi_perf_level_get,
386*f1cec17aSPascal Paillet };
387*f1cec17aSPascal Paillet
message_id_is_supported(size_t message_id)388*f1cec17aSPascal Paillet static bool message_id_is_supported(size_t message_id)
389*f1cec17aSPascal Paillet {
390*f1cec17aSPascal Paillet return message_id < ARRAY_SIZE(scmi_perf_handler_table) &&
391*f1cec17aSPascal Paillet scmi_perf_handler_table[message_id];
392*f1cec17aSPascal Paillet }
393*f1cec17aSPascal Paillet
scmi_msg_get_perf_handler(struct scmi_msg * msg)394*f1cec17aSPascal Paillet scmi_msg_handler_t scmi_msg_get_perf_handler(struct scmi_msg *msg)
395*f1cec17aSPascal Paillet {
396*f1cec17aSPascal Paillet const size_t array_size = ARRAY_SIZE(scmi_perf_handler_table);
397*f1cec17aSPascal Paillet unsigned int message_id = 0;
398*f1cec17aSPascal Paillet
399*f1cec17aSPascal Paillet if (msg->message_id >= array_size) {
400*f1cec17aSPascal Paillet DMSG("handle not found %u", msg->message_id);
401*f1cec17aSPascal Paillet return NULL;
402*f1cec17aSPascal Paillet }
403*f1cec17aSPascal Paillet
404*f1cec17aSPascal Paillet message_id = confine_array_index(msg->message_id, array_size);
405*f1cec17aSPascal Paillet
406*f1cec17aSPascal Paillet return scmi_perf_handler_table[message_id];
407*f1cec17aSPascal Paillet }
408