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