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 18 enum 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 30 struct scmi_msg_resp_base_attributes { 31 u8 num_protocols; 32 u8 num_agents; 33 __le16 reserved; 34 }; 35 36 struct scmi_msg_base_error_notify { 37 __le32 event_control; 38 #define BASE_TP_NOTIFY_ALL BIT(0) 39 }; 40 41 struct 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 */ 57 static 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 */ 89 static int 90 scmi_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 */ 130 static int 131 scmi_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 */ 163 static 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 (tot_num_ret + loop_num_ret > MAX_PROTOCOLS_IMP) { 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 */ 221 static 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 244 static 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 265 static 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 277 static 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 307 static 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 316 static 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 321 int 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