xref: /optee_os/core/drivers/scmi-msg/reset_domain.c (revision a1d5c81f8834a9d2c6f4372cce2e59e70e709121)
1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3  * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
4  * Copyright (c) 2019, Linaro Limited
5  */
6 #include <assert.h>
7 #include <confine_array_index.h>
8 #include <drivers/scmi-msg.h>
9 #include <drivers/scmi.h>
10 #include <string.h>
11 #include <util.h>
12 
13 #include "common.h"
14 
15 static bool message_id_is_supported(unsigned int message_id);
16 
17 size_t __weak plat_scmi_rd_count(unsigned int agent_id __unused)
18 {
19 	return 0;
20 }
21 
22 const char __weak *plat_scmi_rd_get_name(unsigned int agent_id __unused,
23 					 unsigned int scmi_id __unused)
24 {
25 	return NULL;
26 }
27 
28 int32_t __weak plat_scmi_rd_autonomous(unsigned int agent_id __unused,
29 				       unsigned int scmi_id __unused,
30 				       unsigned int state __unused)
31 {
32 	return SCMI_NOT_SUPPORTED;
33 }
34 
35 int32_t __weak plat_scmi_rd_set_state(unsigned int agent_id __unused,
36 				      unsigned int scmi_id __unused,
37 				      bool assert_not_deassert __unused)
38 {
39 	return SCMI_NOT_SUPPORTED;
40 }
41 
42 static void report_version(struct scmi_msg *msg)
43 {
44 	struct scmi_protocol_version_p2a return_values = {
45 		.status = SCMI_SUCCESS,
46 		.version = SCMI_PROTOCOL_VERSION_RESET_DOMAIN,
47 	};
48 
49 	if (msg->in_size) {
50 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
51 		return;
52 	}
53 
54 	scmi_write_response(msg, &return_values, sizeof(return_values));
55 }
56 
57 static void report_attributes(struct scmi_msg *msg)
58 {
59 	struct scmi_protocol_attributes_p2a return_values = {
60 		.status = SCMI_SUCCESS,
61 		.attributes = plat_scmi_rd_count(msg->agent_id),
62 	};
63 
64 	if (msg->in_size) {
65 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
66 		return;
67 	}
68 
69 	scmi_write_response(msg, &return_values, sizeof(return_values));
70 }
71 
72 static void report_message_attributes(struct scmi_msg *msg)
73 {
74 	struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in;
75 	struct scmi_protocol_message_attributes_p2a return_values = {
76 		.status = SCMI_SUCCESS,
77 		/* For this protocol, attributes shall be zero */
78 		.attributes = 0,
79 	};
80 
81 	if (msg->in_size != sizeof(*in_args)) {
82 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
83 		return;
84 	}
85 
86 	if (!message_id_is_supported(in_args->message_id)) {
87 		scmi_status_response(msg, SCMI_NOT_FOUND);
88 		return;
89 	}
90 
91 	scmi_write_response(msg, &return_values, sizeof(return_values));
92 }
93 
94 static void reset_domain_attributes(struct scmi_msg *msg)
95 {
96 	struct scmi_reset_domain_attributes_a2p *in_args = (void *)msg->in;
97 	struct scmi_reset_domain_attributes_p2a return_values = { };
98 	const char *name = NULL;
99 	unsigned int domain_id = 0;
100 
101 	if (msg->in_size != sizeof(*in_args)) {
102 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
103 		return;
104 	}
105 
106 	if (in_args->domain_id >= plat_scmi_rd_count(msg->agent_id)) {
107 		scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
108 		return;
109 	}
110 
111 	domain_id = confine_array_index(in_args->domain_id,
112 					plat_scmi_rd_count(msg->agent_id));
113 
114 	name = plat_scmi_rd_get_name(msg->agent_id, domain_id);
115 	if (!name) {
116 		scmi_status_response(msg, SCMI_NOT_FOUND);
117 		return;
118 	}
119 
120 	COPY_NAME_IDENTIFIER(return_values.name, name);
121 	return_values.status = SCMI_SUCCESS;
122 	return_values.flags = 0; /* Async and Notif are not supported */
123 	return_values.latency = SCMI_RESET_DOMAIN_ATTR_UNK_LAT;
124 
125 	scmi_write_response(msg, &return_values, sizeof(return_values));
126 }
127 
128 static void reset_request(struct scmi_msg *msg)
129 {
130 	struct scmi_reset_domain_request_a2p *in_args = (void *)msg->in;
131 	struct scmi_reset_domain_request_p2a out_args = {
132 		.status = SCMI_SUCCESS,
133 	};
134 	unsigned int domain_id = 0;
135 
136 	domain_id = confine_array_index(in_args->domain_id,
137 					plat_scmi_rd_count(msg->agent_id));
138 
139 	if (msg->in_size != sizeof(*in_args)) {
140 		scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
141 		return;
142 	}
143 
144 	if (in_args->domain_id >= plat_scmi_rd_count(msg->agent_id)) {
145 		scmi_status_response(msg, SCMI_NOT_FOUND);
146 		return;
147 	}
148 
149 	if (in_args->flags & SCMI_RESET_DOMAIN_AUTO)
150 		out_args.status = plat_scmi_rd_autonomous(msg->agent_id,
151 							  domain_id,
152 							  in_args->reset_state);
153 	else if (in_args->flags & SCMI_RESET_DOMAIN_EXPLICIT)
154 		out_args.status = plat_scmi_rd_set_state(msg->agent_id,
155 							 domain_id, true);
156 	else
157 		out_args.status = plat_scmi_rd_set_state(msg->agent_id,
158 							 domain_id, false);
159 
160 	if (out_args.status)
161 		scmi_status_response(msg, out_args.status);
162 	else
163 		scmi_write_response(msg, &out_args, sizeof(out_args));
164 }
165 
166 static const scmi_msg_handler_t scmi_rd_handler_table[] = {
167 	[SCMI_PROTOCOL_VERSION] = report_version,
168 	[SCMI_PROTOCOL_ATTRIBUTES] = report_attributes,
169 	[SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes,
170 	[SCMI_RESET_DOMAIN_ATTRIBUTES] = reset_domain_attributes,
171 	[SCMI_RESET_DOMAIN_REQUEST] = reset_request,
172 };
173 
174 static bool message_id_is_supported(unsigned int message_id)
175 {
176 	return message_id < ARRAY_SIZE(scmi_rd_handler_table) &&
177 	       scmi_rd_handler_table[message_id];
178 }
179 
180 scmi_msg_handler_t scmi_msg_get_rd_handler(struct scmi_msg *msg)
181 {
182 	const size_t array_size = ARRAY_SIZE(scmi_rd_handler_table);
183 	unsigned int message_id = 0;
184 
185 	if (msg->message_id >= array_size) {
186 		DMSG("Reset domain handle not found %u", msg->message_id);
187 		return NULL;
188 	}
189 
190 	message_id = confine_array_index(msg->message_id, array_size);
191 
192 	return scmi_rd_handler_table[message_id];
193 }
194