base.c (10477B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * System Control and Management Interface (SCMI) Base Protocol 4 * 5 * Copyright (C) 2018-2021 ARM Ltd. 6 */ 7 8#define pr_fmt(fmt) "SCMI Notifications BASE - " fmt 9 10#include <linux/module.h> 11#include <linux/scmi_protocol.h> 12 13#include "common.h" 14#include "notify.h" 15 16#define SCMI_BASE_NUM_SOURCES 1 17#define SCMI_BASE_MAX_CMD_ERR_COUNT 1024 18 19enum scmi_base_protocol_cmd { 20 BASE_DISCOVER_VENDOR = 0x3, 21 BASE_DISCOVER_SUB_VENDOR = 0x4, 22 BASE_DISCOVER_IMPLEMENT_VERSION = 0x5, 23 BASE_DISCOVER_LIST_PROTOCOLS = 0x6, 24 BASE_DISCOVER_AGENT = 0x7, 25 BASE_NOTIFY_ERRORS = 0x8, 26 BASE_SET_DEVICE_PERMISSIONS = 0x9, 27 BASE_SET_PROTOCOL_PERMISSIONS = 0xa, 28 BASE_RESET_AGENT_CONFIGURATION = 0xb, 29}; 30 31struct scmi_msg_resp_base_attributes { 32 u8 num_protocols; 33 u8 num_agents; 34 __le16 reserved; 35}; 36 37struct scmi_msg_resp_base_discover_agent { 38 __le32 agent_id; 39 u8 name[SCMI_SHORT_NAME_MAX_SIZE]; 40}; 41 42 43struct scmi_msg_base_error_notify { 44 __le32 event_control; 45#define BASE_TP_NOTIFY_ALL BIT(0) 46}; 47 48struct scmi_base_error_notify_payld { 49 __le32 agent_id; 50 __le32 error_status; 51#define IS_FATAL_ERROR(x) ((x) & BIT(31)) 52#define ERROR_CMD_COUNT(x) FIELD_GET(GENMASK(9, 0), (x)) 53 __le64 msg_reports[SCMI_BASE_MAX_CMD_ERR_COUNT]; 54}; 55 56/** 57 * scmi_base_attributes_get() - gets the implementation details 58 * that are associated with the base protocol. 59 * 60 * @ph: SCMI protocol handle 61 * 62 * Return: 0 on success, else appropriate SCMI error. 63 */ 64static int scmi_base_attributes_get(const struct scmi_protocol_handle *ph) 65{ 66 int ret; 67 struct scmi_xfer *t; 68 struct scmi_msg_resp_base_attributes *attr_info; 69 struct scmi_revision_info *rev = ph->get_priv(ph); 70 71 ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 72 0, sizeof(*attr_info), &t); 73 if (ret) 74 return ret; 75 76 ret = ph->xops->do_xfer(ph, t); 77 if (!ret) { 78 attr_info = t->rx.buf; 79 rev->num_protocols = attr_info->num_protocols; 80 rev->num_agents = attr_info->num_agents; 81 } 82 83 ph->xops->xfer_put(ph, t); 84 85 return ret; 86} 87 88/** 89 * scmi_base_vendor_id_get() - gets vendor/subvendor identifier ASCII string. 90 * 91 * @ph: SCMI protocol handle 92 * @sub_vendor: specify true if sub-vendor ID is needed 93 * 94 * Return: 0 on success, else appropriate SCMI error. 95 */ 96static int 97scmi_base_vendor_id_get(const struct scmi_protocol_handle *ph, bool sub_vendor) 98{ 99 u8 cmd; 100 int ret, size; 101 char *vendor_id; 102 struct scmi_xfer *t; 103 struct scmi_revision_info *rev = ph->get_priv(ph); 104 105 106 if (sub_vendor) { 107 cmd = BASE_DISCOVER_SUB_VENDOR; 108 vendor_id = rev->sub_vendor_id; 109 size = ARRAY_SIZE(rev->sub_vendor_id); 110 } else { 111 cmd = BASE_DISCOVER_VENDOR; 112 vendor_id = rev->vendor_id; 113 size = ARRAY_SIZE(rev->vendor_id); 114 } 115 116 ret = ph->xops->xfer_get_init(ph, cmd, 0, size, &t); 117 if (ret) 118 return ret; 119 120 ret = ph->xops->do_xfer(ph, t); 121 if (!ret) 122 strscpy(vendor_id, t->rx.buf, size); 123 124 ph->xops->xfer_put(ph, t); 125 126 return ret; 127} 128 129/** 130 * scmi_base_implementation_version_get() - gets a vendor-specific 131 * implementation 32-bit version. The format of the version number is 132 * vendor-specific 133 * 134 * @ph: SCMI protocol handle 135 * 136 * Return: 0 on success, else appropriate SCMI error. 137 */ 138static int 139scmi_base_implementation_version_get(const struct scmi_protocol_handle *ph) 140{ 141 int ret; 142 __le32 *impl_ver; 143 struct scmi_xfer *t; 144 struct scmi_revision_info *rev = ph->get_priv(ph); 145 146 ret = ph->xops->xfer_get_init(ph, BASE_DISCOVER_IMPLEMENT_VERSION, 147 0, sizeof(*impl_ver), &t); 148 if (ret) 149 return ret; 150 151 ret = ph->xops->do_xfer(ph, t); 152 if (!ret) { 153 impl_ver = t->rx.buf; 154 rev->impl_ver = le32_to_cpu(*impl_ver); 155 } 156 157 ph->xops->xfer_put(ph, t); 158 159 return ret; 160} 161 162/** 163 * scmi_base_implementation_list_get() - gets the list of protocols it is 164 * OSPM is allowed to access 165 * 166 * @ph: SCMI protocol handle 167 * @protocols_imp: pointer to hold the list of protocol identifiers 168 * 169 * Return: 0 on success, else appropriate SCMI error. 170 */ 171static int 172scmi_base_implementation_list_get(const struct scmi_protocol_handle *ph, 173 u8 *protocols_imp) 174{ 175 u8 *list; 176 int ret, loop; 177 struct scmi_xfer *t; 178 __le32 *num_skip, *num_ret; 179 u32 tot_num_ret = 0, loop_num_ret; 180 struct device *dev = ph->dev; 181 struct scmi_revision_info *rev = ph->get_priv(ph); 182 183 ret = ph->xops->xfer_get_init(ph, BASE_DISCOVER_LIST_PROTOCOLS, 184 sizeof(*num_skip), 0, &t); 185 if (ret) 186 return ret; 187 188 num_skip = t->tx.buf; 189 num_ret = t->rx.buf; 190 list = t->rx.buf + sizeof(*num_ret); 191 192 do { 193 size_t real_list_sz; 194 u32 calc_list_sz; 195 196 /* Set the number of protocols to be skipped/already read */ 197 *num_skip = cpu_to_le32(tot_num_ret); 198 199 ret = ph->xops->do_xfer(ph, t); 200 if (ret) 201 break; 202 203 loop_num_ret = le32_to_cpu(*num_ret); 204 if (!loop_num_ret) 205 break; 206 207 if (loop_num_ret > rev->num_protocols - tot_num_ret) { 208 dev_err(dev, 209 "No. Returned protocols > Total protocols.\n"); 210 break; 211 } 212 213 if (t->rx.len < (sizeof(u32) * 2)) { 214 dev_err(dev, "Truncated reply - rx.len:%zd\n", 215 t->rx.len); 216 ret = -EPROTO; 217 break; 218 } 219 220 real_list_sz = t->rx.len - sizeof(u32); 221 calc_list_sz = (1 + (loop_num_ret - 1) / sizeof(u32)) * 222 sizeof(u32); 223 if (calc_list_sz != real_list_sz) { 224 dev_warn(dev, 225 "Malformed reply - real_sz:%zd calc_sz:%u (loop_num_ret:%d)\n", 226 real_list_sz, calc_list_sz, loop_num_ret); 227 /* 228 * Bail out if the expected list size is bigger than the 229 * total payload size of the received reply. 230 */ 231 if (calc_list_sz > real_list_sz) { 232 ret = -EPROTO; 233 break; 234 } 235 } 236 237 for (loop = 0; loop < loop_num_ret; loop++) 238 protocols_imp[tot_num_ret + loop] = *(list + loop); 239 240 tot_num_ret += loop_num_ret; 241 242 ph->xops->reset_rx_to_maxsz(ph, t); 243 } while (tot_num_ret < rev->num_protocols); 244 245 ph->xops->xfer_put(ph, t); 246 247 return ret; 248} 249 250/** 251 * scmi_base_discover_agent_get() - discover the name of an agent 252 * 253 * @ph: SCMI protocol handle 254 * @id: Agent identifier 255 * @name: Agent identifier ASCII string 256 * 257 * An agent id of 0 is reserved to identify the platform itself. 258 * Generally operating system is represented as "OSPM" 259 * 260 * Return: 0 on success, else appropriate SCMI error. 261 */ 262static int scmi_base_discover_agent_get(const struct scmi_protocol_handle *ph, 263 int id, char *name) 264{ 265 int ret; 266 struct scmi_msg_resp_base_discover_agent *agent_info; 267 struct scmi_xfer *t; 268 269 ret = ph->xops->xfer_get_init(ph, BASE_DISCOVER_AGENT, 270 sizeof(__le32), sizeof(*agent_info), &t); 271 if (ret) 272 return ret; 273 274 put_unaligned_le32(id, t->tx.buf); 275 276 ret = ph->xops->do_xfer(ph, t); 277 if (!ret) { 278 agent_info = t->rx.buf; 279 strscpy(name, agent_info->name, SCMI_SHORT_NAME_MAX_SIZE); 280 } 281 282 ph->xops->xfer_put(ph, t); 283 284 return ret; 285} 286 287static int scmi_base_error_notify(const struct scmi_protocol_handle *ph, 288 bool enable) 289{ 290 int ret; 291 u32 evt_cntl = enable ? BASE_TP_NOTIFY_ALL : 0; 292 struct scmi_xfer *t; 293 struct scmi_msg_base_error_notify *cfg; 294 295 ret = ph->xops->xfer_get_init(ph, BASE_NOTIFY_ERRORS, 296 sizeof(*cfg), 0, &t); 297 if (ret) 298 return ret; 299 300 cfg = t->tx.buf; 301 cfg->event_control = cpu_to_le32(evt_cntl); 302 303 ret = ph->xops->do_xfer(ph, t); 304 305 ph->xops->xfer_put(ph, t); 306 return ret; 307} 308 309static int scmi_base_set_notify_enabled(const struct scmi_protocol_handle *ph, 310 u8 evt_id, u32 src_id, bool enable) 311{ 312 int ret; 313 314 ret = scmi_base_error_notify(ph, enable); 315 if (ret) 316 pr_debug("FAIL_ENABLED - evt[%X] ret:%d\n", evt_id, ret); 317 318 return ret; 319} 320 321static void *scmi_base_fill_custom_report(const struct scmi_protocol_handle *ph, 322 u8 evt_id, ktime_t timestamp, 323 const void *payld, size_t payld_sz, 324 void *report, u32 *src_id) 325{ 326 int i; 327 const struct scmi_base_error_notify_payld *p = payld; 328 struct scmi_base_error_report *r = report; 329 330 /* 331 * BaseError notification payload is variable in size but 332 * up to a maximum length determined by the struct ponted by p. 333 * Instead payld_sz is the effective length of this notification 334 * payload so cannot be greater of the maximum allowed size as 335 * pointed by p. 336 */ 337 if (evt_id != SCMI_EVENT_BASE_ERROR_EVENT || sizeof(*p) < payld_sz) 338 return NULL; 339 340 r->timestamp = timestamp; 341 r->agent_id = le32_to_cpu(p->agent_id); 342 r->fatal = IS_FATAL_ERROR(le32_to_cpu(p->error_status)); 343 r->cmd_count = ERROR_CMD_COUNT(le32_to_cpu(p->error_status)); 344 for (i = 0; i < r->cmd_count; i++) 345 r->reports[i] = le64_to_cpu(p->msg_reports[i]); 346 *src_id = 0; 347 348 return r; 349} 350 351static const struct scmi_event base_events[] = { 352 { 353 .id = SCMI_EVENT_BASE_ERROR_EVENT, 354 .max_payld_sz = sizeof(struct scmi_base_error_notify_payld), 355 .max_report_sz = sizeof(struct scmi_base_error_report) + 356 SCMI_BASE_MAX_CMD_ERR_COUNT * sizeof(u64), 357 }, 358}; 359 360static const struct scmi_event_ops base_event_ops = { 361 .set_notify_enabled = scmi_base_set_notify_enabled, 362 .fill_custom_report = scmi_base_fill_custom_report, 363}; 364 365static const struct scmi_protocol_events base_protocol_events = { 366 .queue_sz = 4 * SCMI_PROTO_QUEUE_SZ, 367 .ops = &base_event_ops, 368 .evts = base_events, 369 .num_events = ARRAY_SIZE(base_events), 370 .num_sources = SCMI_BASE_NUM_SOURCES, 371}; 372 373static int scmi_base_protocol_init(const struct scmi_protocol_handle *ph) 374{ 375 int id, ret; 376 u8 *prot_imp; 377 u32 version; 378 char name[SCMI_SHORT_NAME_MAX_SIZE]; 379 struct device *dev = ph->dev; 380 struct scmi_revision_info *rev = scmi_revision_area_get(ph); 381 382 ret = ph->xops->version_get(ph, &version); 383 if (ret) 384 return ret; 385 386 rev->major_ver = PROTOCOL_REV_MAJOR(version), 387 rev->minor_ver = PROTOCOL_REV_MINOR(version); 388 ph->set_priv(ph, rev); 389 390 ret = scmi_base_attributes_get(ph); 391 if (ret) 392 return ret; 393 394 prot_imp = devm_kcalloc(dev, rev->num_protocols, sizeof(u8), 395 GFP_KERNEL); 396 if (!prot_imp) 397 return -ENOMEM; 398 399 scmi_base_vendor_id_get(ph, false); 400 scmi_base_vendor_id_get(ph, true); 401 scmi_base_implementation_version_get(ph); 402 scmi_base_implementation_list_get(ph, prot_imp); 403 404 scmi_setup_protocol_implemented(ph, prot_imp); 405 406 dev_info(dev, "SCMI Protocol v%d.%d '%s:%s' Firmware version 0x%x\n", 407 rev->major_ver, rev->minor_ver, rev->vendor_id, 408 rev->sub_vendor_id, rev->impl_ver); 409 dev_dbg(dev, "Found %d protocol(s) %d agent(s)\n", rev->num_protocols, 410 rev->num_agents); 411 412 for (id = 0; id < rev->num_agents; id++) { 413 scmi_base_discover_agent_get(ph, id, name); 414 dev_dbg(dev, "Agent %d: %s\n", id, name); 415 } 416 417 return 0; 418} 419 420static const struct scmi_protocol scmi_base = { 421 .id = SCMI_PROTOCOL_BASE, 422 .owner = NULL, 423 .instance_init = &scmi_base_protocol_init, 424 .ops = NULL, 425 .events = &base_protocol_events, 426}; 427 428DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(base, scmi_base)