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