1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2017, Linaro Ltd. 4 */ 5 #include <linux/firmware.h> 6 #include <linux/module.h> 7 #include <linux/notifier.h> 8 #include <linux/slab.h> 9 #include <linux/io.h> 10 #include <linux/notifier.h> 11 #include <linux/of_platform.h> 12 #include <linux/platform_device.h> 13 #include <linux/remoteproc/qcom_rproc.h> 14 #include <linux/rpmsg.h> 15 16 #include "qcom_common.h" 17 18 static BLOCKING_NOTIFIER_HEAD(sysmon_notifiers); 19 20 struct qcom_sysmon { 21 struct rproc_subdev subdev; 22 struct rproc *rproc; 23 24 struct list_head node; 25 26 const char *name; 27 28 int ssctl_version; 29 int ssctl_instance; 30 31 struct notifier_block nb; 32 33 struct device *dev; 34 35 struct rpmsg_endpoint *ept; 36 struct completion comp; 37 struct mutex lock; 38 39 bool ssr_ack; 40 41 struct qmi_handle qmi; 42 struct sockaddr_qrtr ssctl; 43 }; 44 45 static DEFINE_MUTEX(sysmon_lock); 46 static LIST_HEAD(sysmon_list); 47 48 /** 49 * sysmon_send_event() - send notification of other remote's SSR event 50 * @sysmon: sysmon context 51 * @name: other remote's name 52 */ 53 static void sysmon_send_event(struct qcom_sysmon *sysmon, const char *name) 54 { 55 char req[50]; 56 int len; 57 int ret; 58 59 len = snprintf(req, sizeof(req), "ssr:%s:before_shutdown", name); 60 if (len >= sizeof(req)) 61 return; 62 63 mutex_lock(&sysmon->lock); 64 reinit_completion(&sysmon->comp); 65 sysmon->ssr_ack = false; 66 67 ret = rpmsg_send(sysmon->ept, req, len); 68 if (ret < 0) { 69 dev_err(sysmon->dev, "failed to send sysmon event\n"); 70 goto out_unlock; 71 } 72 73 ret = wait_for_completion_timeout(&sysmon->comp, 74 msecs_to_jiffies(5000)); 75 if (!ret) { 76 dev_err(sysmon->dev, "timeout waiting for sysmon ack\n"); 77 goto out_unlock; 78 } 79 80 if (!sysmon->ssr_ack) 81 dev_err(sysmon->dev, "unexpected response to sysmon event\n"); 82 83 out_unlock: 84 mutex_unlock(&sysmon->lock); 85 } 86 87 /** 88 * sysmon_request_shutdown() - request graceful shutdown of remote 89 * @sysmon: sysmon context 90 */ 91 static void sysmon_request_shutdown(struct qcom_sysmon *sysmon) 92 { 93 char *req = "ssr:shutdown"; 94 int ret; 95 96 mutex_lock(&sysmon->lock); 97 reinit_completion(&sysmon->comp); 98 sysmon->ssr_ack = false; 99 100 ret = rpmsg_send(sysmon->ept, req, strlen(req) + 1); 101 if (ret < 0) { 102 dev_err(sysmon->dev, "send sysmon shutdown request failed\n"); 103 goto out_unlock; 104 } 105 106 ret = wait_for_completion_timeout(&sysmon->comp, 107 msecs_to_jiffies(5000)); 108 if (!ret) { 109 dev_err(sysmon->dev, "timeout waiting for sysmon ack\n"); 110 goto out_unlock; 111 } 112 113 if (!sysmon->ssr_ack) 114 dev_err(sysmon->dev, 115 "unexpected response to sysmon shutdown request\n"); 116 117 out_unlock: 118 mutex_unlock(&sysmon->lock); 119 } 120 121 static int sysmon_callback(struct rpmsg_device *rpdev, void *data, int count, 122 void *priv, u32 addr) 123 { 124 struct qcom_sysmon *sysmon = priv; 125 const char *ssr_ack = "ssr:ack"; 126 const int ssr_ack_len = strlen(ssr_ack) + 1; 127 128 if (!sysmon) 129 return -EINVAL; 130 131 if (count >= ssr_ack_len && !memcmp(data, ssr_ack, ssr_ack_len)) 132 sysmon->ssr_ack = true; 133 134 complete(&sysmon->comp); 135 136 return 0; 137 } 138 139 #define SSCTL_SHUTDOWN_REQ 0x21 140 #define SSCTL_SUBSYS_EVENT_REQ 0x23 141 142 #define SSCTL_MAX_MSG_LEN 7 143 144 #define SSCTL_SUBSYS_NAME_LENGTH 15 145 146 enum { 147 SSCTL_SSR_EVENT_BEFORE_POWERUP, 148 SSCTL_SSR_EVENT_AFTER_POWERUP, 149 SSCTL_SSR_EVENT_BEFORE_SHUTDOWN, 150 SSCTL_SSR_EVENT_AFTER_SHUTDOWN, 151 }; 152 153 enum { 154 SSCTL_SSR_EVENT_FORCED, 155 SSCTL_SSR_EVENT_GRACEFUL, 156 }; 157 158 struct ssctl_shutdown_resp { 159 struct qmi_response_type_v01 resp; 160 }; 161 162 static struct qmi_elem_info ssctl_shutdown_resp_ei[] = { 163 { 164 .data_type = QMI_STRUCT, 165 .elem_len = 1, 166 .elem_size = sizeof(struct qmi_response_type_v01), 167 .array_type = NO_ARRAY, 168 .tlv_type = 0x02, 169 .offset = offsetof(struct ssctl_shutdown_resp, resp), 170 .ei_array = qmi_response_type_v01_ei, 171 }, 172 {} 173 }; 174 175 struct ssctl_subsys_event_req { 176 u8 subsys_name_len; 177 char subsys_name[SSCTL_SUBSYS_NAME_LENGTH]; 178 u32 event; 179 u8 evt_driven_valid; 180 u32 evt_driven; 181 }; 182 183 static struct qmi_elem_info ssctl_subsys_event_req_ei[] = { 184 { 185 .data_type = QMI_DATA_LEN, 186 .elem_len = 1, 187 .elem_size = sizeof(uint8_t), 188 .array_type = NO_ARRAY, 189 .tlv_type = 0x01, 190 .offset = offsetof(struct ssctl_subsys_event_req, 191 subsys_name_len), 192 .ei_array = NULL, 193 }, 194 { 195 .data_type = QMI_UNSIGNED_1_BYTE, 196 .elem_len = SSCTL_SUBSYS_NAME_LENGTH, 197 .elem_size = sizeof(char), 198 .array_type = VAR_LEN_ARRAY, 199 .tlv_type = 0x01, 200 .offset = offsetof(struct ssctl_subsys_event_req, 201 subsys_name), 202 .ei_array = NULL, 203 }, 204 { 205 .data_type = QMI_SIGNED_4_BYTE_ENUM, 206 .elem_len = 1, 207 .elem_size = sizeof(uint32_t), 208 .array_type = NO_ARRAY, 209 .tlv_type = 0x02, 210 .offset = offsetof(struct ssctl_subsys_event_req, 211 event), 212 .ei_array = NULL, 213 }, 214 { 215 .data_type = QMI_OPT_FLAG, 216 .elem_len = 1, 217 .elem_size = sizeof(uint8_t), 218 .array_type = NO_ARRAY, 219 .tlv_type = 0x10, 220 .offset = offsetof(struct ssctl_subsys_event_req, 221 evt_driven_valid), 222 .ei_array = NULL, 223 }, 224 { 225 .data_type = QMI_SIGNED_4_BYTE_ENUM, 226 .elem_len = 1, 227 .elem_size = sizeof(uint32_t), 228 .array_type = NO_ARRAY, 229 .tlv_type = 0x10, 230 .offset = offsetof(struct ssctl_subsys_event_req, 231 evt_driven), 232 .ei_array = NULL, 233 }, 234 {} 235 }; 236 237 struct ssctl_subsys_event_resp { 238 struct qmi_response_type_v01 resp; 239 }; 240 241 static struct qmi_elem_info ssctl_subsys_event_resp_ei[] = { 242 { 243 .data_type = QMI_STRUCT, 244 .elem_len = 1, 245 .elem_size = sizeof(struct qmi_response_type_v01), 246 .array_type = NO_ARRAY, 247 .tlv_type = 0x02, 248 .offset = offsetof(struct ssctl_subsys_event_resp, 249 resp), 250 .ei_array = qmi_response_type_v01_ei, 251 }, 252 {} 253 }; 254 255 /** 256 * ssctl_request_shutdown() - request shutdown via SSCTL QMI service 257 * @sysmon: sysmon context 258 */ 259 static void ssctl_request_shutdown(struct qcom_sysmon *sysmon) 260 { 261 struct ssctl_shutdown_resp resp; 262 struct qmi_txn txn; 263 int ret; 264 265 ret = qmi_txn_init(&sysmon->qmi, &txn, ssctl_shutdown_resp_ei, &resp); 266 if (ret < 0) { 267 dev_err(sysmon->dev, "failed to allocate QMI txn\n"); 268 return; 269 } 270 271 ret = qmi_send_request(&sysmon->qmi, &sysmon->ssctl, &txn, 272 SSCTL_SHUTDOWN_REQ, 0, NULL, NULL); 273 if (ret < 0) { 274 dev_err(sysmon->dev, "failed to send shutdown request\n"); 275 qmi_txn_cancel(&txn); 276 return; 277 } 278 279 ret = qmi_txn_wait(&txn, 5 * HZ); 280 if (ret < 0) 281 dev_err(sysmon->dev, "failed receiving QMI response\n"); 282 else if (resp.resp.result) 283 dev_err(sysmon->dev, "shutdown request failed\n"); 284 else 285 dev_dbg(sysmon->dev, "shutdown request completed\n"); 286 } 287 288 /** 289 * ssctl_send_event() - send notification of other remote's SSR event 290 * @sysmon: sysmon context 291 * @name: other remote's name 292 */ 293 static void ssctl_send_event(struct qcom_sysmon *sysmon, const char *name) 294 { 295 struct ssctl_subsys_event_resp resp; 296 struct ssctl_subsys_event_req req; 297 struct qmi_txn txn; 298 int ret; 299 300 memset(&resp, 0, sizeof(resp)); 301 ret = qmi_txn_init(&sysmon->qmi, &txn, ssctl_subsys_event_resp_ei, &resp); 302 if (ret < 0) { 303 dev_err(sysmon->dev, "failed to allocate QMI txn\n"); 304 return; 305 } 306 307 memset(&req, 0, sizeof(req)); 308 strlcpy(req.subsys_name, name, sizeof(req.subsys_name)); 309 req.subsys_name_len = strlen(req.subsys_name); 310 req.event = SSCTL_SSR_EVENT_BEFORE_SHUTDOWN; 311 req.evt_driven_valid = true; 312 req.evt_driven = SSCTL_SSR_EVENT_FORCED; 313 314 ret = qmi_send_request(&sysmon->qmi, &sysmon->ssctl, &txn, 315 SSCTL_SUBSYS_EVENT_REQ, 40, 316 ssctl_subsys_event_req_ei, &req); 317 if (ret < 0) { 318 dev_err(sysmon->dev, "failed to send shutdown request\n"); 319 qmi_txn_cancel(&txn); 320 return; 321 } 322 323 ret = qmi_txn_wait(&txn, 5 * HZ); 324 if (ret < 0) 325 dev_err(sysmon->dev, "failed receiving QMI response\n"); 326 else if (resp.resp.result) 327 dev_err(sysmon->dev, "ssr event send failed\n"); 328 else 329 dev_dbg(sysmon->dev, "ssr event send completed\n"); 330 } 331 332 /** 333 * ssctl_new_server() - QMI callback indicating a new service 334 * @qmi: QMI handle 335 * @svc: service information 336 * 337 * Return: 0 if we're interested in this service, -EINVAL otherwise. 338 */ 339 static int ssctl_new_server(struct qmi_handle *qmi, struct qmi_service *svc) 340 { 341 struct qcom_sysmon *sysmon = container_of(qmi, struct qcom_sysmon, qmi); 342 343 switch (svc->version) { 344 case 1: 345 if (svc->instance != 0) 346 return -EINVAL; 347 if (strcmp(sysmon->name, "modem")) 348 return -EINVAL; 349 break; 350 case 2: 351 if (svc->instance != sysmon->ssctl_instance) 352 return -EINVAL; 353 break; 354 default: 355 return -EINVAL; 356 }; 357 358 sysmon->ssctl_version = svc->version; 359 360 sysmon->ssctl.sq_family = AF_QIPCRTR; 361 sysmon->ssctl.sq_node = svc->node; 362 sysmon->ssctl.sq_port = svc->port; 363 364 svc->priv = sysmon; 365 366 return 0; 367 } 368 369 /** 370 * ssctl_del_server() - QMI callback indicating that @svc is removed 371 * @qmi: QMI handle 372 * @svc: service information 373 */ 374 static void ssctl_del_server(struct qmi_handle *qmi, struct qmi_service *svc) 375 { 376 struct qcom_sysmon *sysmon = svc->priv; 377 378 sysmon->ssctl_version = 0; 379 } 380 381 static const struct qmi_ops ssctl_ops = { 382 .new_server = ssctl_new_server, 383 .del_server = ssctl_del_server, 384 }; 385 386 static int sysmon_start(struct rproc_subdev *subdev) 387 { 388 return 0; 389 } 390 391 static void sysmon_stop(struct rproc_subdev *subdev, bool crashed) 392 { 393 struct qcom_sysmon *sysmon = container_of(subdev, struct qcom_sysmon, subdev); 394 395 blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)sysmon->name); 396 397 /* Don't request graceful shutdown if we've crashed */ 398 if (crashed) 399 return; 400 401 if (sysmon->ssctl_version) 402 ssctl_request_shutdown(sysmon); 403 else if (sysmon->ept) 404 sysmon_request_shutdown(sysmon); 405 } 406 407 /** 408 * sysmon_notify() - notify sysmon target of another's SSR 409 * @nb: notifier_block associated with sysmon instance 410 * @event: unused 411 * @data: SSR identifier of the remote that is going down 412 */ 413 static int sysmon_notify(struct notifier_block *nb, unsigned long event, 414 void *data) 415 { 416 struct qcom_sysmon *sysmon = container_of(nb, struct qcom_sysmon, nb); 417 struct rproc *rproc = sysmon->rproc; 418 const char *ssr_name = data; 419 420 /* Skip non-running rprocs and the originating instance */ 421 if (rproc->state != RPROC_RUNNING || !strcmp(data, sysmon->name)) { 422 dev_dbg(sysmon->dev, "not notifying %s\n", sysmon->name); 423 return NOTIFY_DONE; 424 } 425 426 /* Only SSCTL version 2 supports SSR events */ 427 if (sysmon->ssctl_version == 2) 428 ssctl_send_event(sysmon, ssr_name); 429 else if (sysmon->ept) 430 sysmon_send_event(sysmon, ssr_name); 431 432 return NOTIFY_DONE; 433 } 434 435 /** 436 * qcom_add_sysmon_subdev() - create a sysmon subdev for the given remoteproc 437 * @rproc: rproc context to associate the subdev with 438 * @name: name of this subdev, to use in SSR 439 * @ssctl_instance: instance id of the ssctl QMI service 440 * 441 * Return: A new qcom_sysmon object, or NULL on failure 442 */ 443 struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc, 444 const char *name, 445 int ssctl_instance) 446 { 447 struct qcom_sysmon *sysmon; 448 int ret; 449 450 sysmon = kzalloc(sizeof(*sysmon), GFP_KERNEL); 451 if (!sysmon) 452 return NULL; 453 454 sysmon->dev = rproc->dev.parent; 455 sysmon->rproc = rproc; 456 457 sysmon->name = name; 458 sysmon->ssctl_instance = ssctl_instance; 459 460 init_completion(&sysmon->comp); 461 mutex_init(&sysmon->lock); 462 463 ret = qmi_handle_init(&sysmon->qmi, SSCTL_MAX_MSG_LEN, &ssctl_ops, NULL); 464 if (ret < 0) { 465 dev_err(sysmon->dev, "failed to initialize qmi handle\n"); 466 kfree(sysmon); 467 return NULL; 468 } 469 470 qmi_add_lookup(&sysmon->qmi, 43, 0, 0); 471 472 sysmon->subdev.start = sysmon_start; 473 sysmon->subdev.stop = sysmon_stop; 474 475 rproc_add_subdev(rproc, &sysmon->subdev); 476 477 sysmon->nb.notifier_call = sysmon_notify; 478 blocking_notifier_chain_register(&sysmon_notifiers, &sysmon->nb); 479 480 mutex_lock(&sysmon_lock); 481 list_add(&sysmon->node, &sysmon_list); 482 mutex_unlock(&sysmon_lock); 483 484 return sysmon; 485 } 486 EXPORT_SYMBOL_GPL(qcom_add_sysmon_subdev); 487 488 /** 489 * qcom_remove_sysmon_subdev() - release a qcom_sysmon 490 * @sysmon: sysmon context, as retrieved by qcom_add_sysmon_subdev() 491 */ 492 void qcom_remove_sysmon_subdev(struct qcom_sysmon *sysmon) 493 { 494 if (!sysmon) 495 return; 496 497 mutex_lock(&sysmon_lock); 498 list_del(&sysmon->node); 499 mutex_unlock(&sysmon_lock); 500 501 blocking_notifier_chain_unregister(&sysmon_notifiers, &sysmon->nb); 502 503 rproc_remove_subdev(sysmon->rproc, &sysmon->subdev); 504 505 qmi_handle_release(&sysmon->qmi); 506 507 kfree(sysmon); 508 } 509 EXPORT_SYMBOL_GPL(qcom_remove_sysmon_subdev); 510 511 /** 512 * sysmon_probe() - probe sys_mon channel 513 * @rpdev: rpmsg device handle 514 * 515 * Find the sysmon context associated with the ancestor remoteproc and assign 516 * this rpmsg device with said sysmon context. 517 * 518 * Return: 0 on success, negative errno on failure. 519 */ 520 static int sysmon_probe(struct rpmsg_device *rpdev) 521 { 522 struct qcom_sysmon *sysmon; 523 struct rproc *rproc; 524 525 rproc = rproc_get_by_child(&rpdev->dev); 526 if (!rproc) { 527 dev_err(&rpdev->dev, "sysmon device not child of rproc\n"); 528 return -EINVAL; 529 } 530 531 mutex_lock(&sysmon_lock); 532 list_for_each_entry(sysmon, &sysmon_list, node) { 533 if (sysmon->rproc == rproc) 534 goto found; 535 } 536 mutex_unlock(&sysmon_lock); 537 538 dev_err(&rpdev->dev, "no sysmon associated with parent rproc\n"); 539 540 return -EINVAL; 541 542 found: 543 mutex_unlock(&sysmon_lock); 544 545 rpdev->ept->priv = sysmon; 546 sysmon->ept = rpdev->ept; 547 548 return 0; 549 } 550 551 /** 552 * sysmon_remove() - sys_mon channel remove handler 553 * @rpdev: rpmsg device handle 554 * 555 * Disassociate the rpmsg device with the sysmon instance. 556 */ 557 static void sysmon_remove(struct rpmsg_device *rpdev) 558 { 559 struct qcom_sysmon *sysmon = rpdev->ept->priv; 560 561 sysmon->ept = NULL; 562 } 563 564 static const struct rpmsg_device_id sysmon_match[] = { 565 { "sys_mon" }, 566 {} 567 }; 568 569 static struct rpmsg_driver sysmon_driver = { 570 .probe = sysmon_probe, 571 .remove = sysmon_remove, 572 .callback = sysmon_callback, 573 .id_table = sysmon_match, 574 .drv = { 575 .name = "qcom_sysmon", 576 }, 577 }; 578 579 module_rpmsg_driver(sysmon_driver); 580 581 MODULE_DESCRIPTION("Qualcomm sysmon driver"); 582 MODULE_LICENSE("GPL v2"); 583