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/interrupt.h> 10#include <linux/io.h> 11#include <linux/of_irq.h> 12#include <linux/of_platform.h> 13#include <linux/platform_device.h> 14#include <linux/remoteproc/qcom_rproc.h> 15#include <linux/rpmsg.h> 16 17#include "qcom_common.h" 18 19static BLOCKING_NOTIFIER_HEAD(sysmon_notifiers); 20 21struct qcom_sysmon { 22 struct rproc_subdev subdev; 23 struct rproc *rproc; 24 25 int state; 26 struct mutex state_lock; 27 28 struct list_head node; 29 30 const char *name; 31 32 int shutdown_irq; 33 int ssctl_version; 34 int ssctl_instance; 35 36 struct notifier_block nb; 37 38 struct device *dev; 39 40 struct rpmsg_endpoint *ept; 41 struct completion comp; 42 struct completion ind_comp; 43 struct completion shutdown_comp; 44 struct completion ssctl_comp; 45 struct mutex lock; 46 47 bool ssr_ack; 48 49 struct qmi_handle qmi; 50 struct sockaddr_qrtr ssctl; 51}; 52 53enum { 54 SSCTL_SSR_EVENT_BEFORE_POWERUP, 55 SSCTL_SSR_EVENT_AFTER_POWERUP, 56 SSCTL_SSR_EVENT_BEFORE_SHUTDOWN, 57 SSCTL_SSR_EVENT_AFTER_SHUTDOWN, 58}; 59 60static const char * const sysmon_state_string[] = { 61 [SSCTL_SSR_EVENT_BEFORE_POWERUP] = "before_powerup", 62 [SSCTL_SSR_EVENT_AFTER_POWERUP] = "after_powerup", 63 [SSCTL_SSR_EVENT_BEFORE_SHUTDOWN] = "before_shutdown", 64 [SSCTL_SSR_EVENT_AFTER_SHUTDOWN] = "after_shutdown", 65}; 66 67struct sysmon_event { 68 const char *subsys_name; 69 u32 ssr_event; 70}; 71 72static DEFINE_MUTEX(sysmon_lock); 73static LIST_HEAD(sysmon_list); 74 75/** 76 * sysmon_send_event() - send notification of other remote's SSR event 77 * @sysmon: sysmon context 78 * @event: sysmon event context 79 */ 80static void sysmon_send_event(struct qcom_sysmon *sysmon, 81 const struct sysmon_event *event) 82{ 83 char req[50]; 84 int len; 85 int ret; 86 87 len = snprintf(req, sizeof(req), "ssr:%s:%s", event->subsys_name, 88 sysmon_state_string[event->ssr_event]); 89 if (len >= sizeof(req)) 90 return; 91 92 mutex_lock(&sysmon->lock); 93 reinit_completion(&sysmon->comp); 94 sysmon->ssr_ack = false; 95 96 ret = rpmsg_send(sysmon->ept, req, len); 97 if (ret < 0) { 98 dev_err(sysmon->dev, "failed to send sysmon event\n"); 99 goto out_unlock; 100 } 101 102 ret = wait_for_completion_timeout(&sysmon->comp, 103 msecs_to_jiffies(5000)); 104 if (!ret) { 105 dev_err(sysmon->dev, "timeout waiting for sysmon ack\n"); 106 goto out_unlock; 107 } 108 109 if (!sysmon->ssr_ack) 110 dev_err(sysmon->dev, "unexpected response to sysmon event\n"); 111 112out_unlock: 113 mutex_unlock(&sysmon->lock); 114} 115 116/** 117 * sysmon_request_shutdown() - request graceful shutdown of remote 118 * @sysmon: sysmon context 119 */ 120static void sysmon_request_shutdown(struct qcom_sysmon *sysmon) 121{ 122 char *req = "ssr:shutdown"; 123 int ret; 124 125 mutex_lock(&sysmon->lock); 126 reinit_completion(&sysmon->comp); 127 sysmon->ssr_ack = false; 128 129 ret = rpmsg_send(sysmon->ept, req, strlen(req) + 1); 130 if (ret < 0) { 131 dev_err(sysmon->dev, "send sysmon shutdown request failed\n"); 132 goto out_unlock; 133 } 134 135 ret = wait_for_completion_timeout(&sysmon->comp, 136 msecs_to_jiffies(5000)); 137 if (!ret) { 138 dev_err(sysmon->dev, "timeout waiting for sysmon ack\n"); 139 goto out_unlock; 140 } 141 142 if (!sysmon->ssr_ack) 143 dev_err(sysmon->dev, 144 "unexpected response to sysmon shutdown request\n"); 145 146out_unlock: 147 mutex_unlock(&sysmon->lock); 148} 149 150static int sysmon_callback(struct rpmsg_device *rpdev, void *data, int count, 151 void *priv, u32 addr) 152{ 153 struct qcom_sysmon *sysmon = priv; 154 const char *ssr_ack = "ssr:ack"; 155 const int ssr_ack_len = strlen(ssr_ack) + 1; 156 157 if (!sysmon) 158 return -EINVAL; 159 160 if (count >= ssr_ack_len && !memcmp(data, ssr_ack, ssr_ack_len)) 161 sysmon->ssr_ack = true; 162 163 complete(&sysmon->comp); 164 165 return 0; 166} 167 168#define SSCTL_SHUTDOWN_REQ 0x21 169#define SSCTL_SHUTDOWN_READY_IND 0x21 170#define SSCTL_SUBSYS_EVENT_REQ 0x23 171 172#define SSCTL_MAX_MSG_LEN 7 173 174#define SSCTL_SUBSYS_NAME_LENGTH 15 175 176enum { 177 SSCTL_SSR_EVENT_FORCED, 178 SSCTL_SSR_EVENT_GRACEFUL, 179}; 180 181struct ssctl_shutdown_resp { 182 struct qmi_response_type_v01 resp; 183}; 184 185static struct qmi_elem_info ssctl_shutdown_resp_ei[] = { 186 { 187 .data_type = QMI_STRUCT, 188 .elem_len = 1, 189 .elem_size = sizeof(struct qmi_response_type_v01), 190 .array_type = NO_ARRAY, 191 .tlv_type = 0x02, 192 .offset = offsetof(struct ssctl_shutdown_resp, resp), 193 .ei_array = qmi_response_type_v01_ei, 194 }, 195 {} 196}; 197 198struct ssctl_subsys_event_req { 199 u8 subsys_name_len; 200 char subsys_name[SSCTL_SUBSYS_NAME_LENGTH]; 201 u32 event; 202 u8 evt_driven_valid; 203 u32 evt_driven; 204}; 205 206static struct qmi_elem_info ssctl_subsys_event_req_ei[] = { 207 { 208 .data_type = QMI_DATA_LEN, 209 .elem_len = 1, 210 .elem_size = sizeof(uint8_t), 211 .array_type = NO_ARRAY, 212 .tlv_type = 0x01, 213 .offset = offsetof(struct ssctl_subsys_event_req, 214 subsys_name_len), 215 .ei_array = NULL, 216 }, 217 { 218 .data_type = QMI_UNSIGNED_1_BYTE, 219 .elem_len = SSCTL_SUBSYS_NAME_LENGTH, 220 .elem_size = sizeof(char), 221 .array_type = VAR_LEN_ARRAY, 222 .tlv_type = 0x01, 223 .offset = offsetof(struct ssctl_subsys_event_req, 224 subsys_name), 225 .ei_array = NULL, 226 }, 227 { 228 .data_type = QMI_SIGNED_4_BYTE_ENUM, 229 .elem_len = 1, 230 .elem_size = sizeof(uint32_t), 231 .array_type = NO_ARRAY, 232 .tlv_type = 0x02, 233 .offset = offsetof(struct ssctl_subsys_event_req, 234 event), 235 .ei_array = NULL, 236 }, 237 { 238 .data_type = QMI_OPT_FLAG, 239 .elem_len = 1, 240 .elem_size = sizeof(uint8_t), 241 .array_type = NO_ARRAY, 242 .tlv_type = 0x10, 243 .offset = offsetof(struct ssctl_subsys_event_req, 244 evt_driven_valid), 245 .ei_array = NULL, 246 }, 247 { 248 .data_type = QMI_SIGNED_4_BYTE_ENUM, 249 .elem_len = 1, 250 .elem_size = sizeof(uint32_t), 251 .array_type = NO_ARRAY, 252 .tlv_type = 0x10, 253 .offset = offsetof(struct ssctl_subsys_event_req, 254 evt_driven), 255 .ei_array = NULL, 256 }, 257 {} 258}; 259 260struct ssctl_subsys_event_resp { 261 struct qmi_response_type_v01 resp; 262}; 263 264static struct qmi_elem_info ssctl_subsys_event_resp_ei[] = { 265 { 266 .data_type = QMI_STRUCT, 267 .elem_len = 1, 268 .elem_size = sizeof(struct qmi_response_type_v01), 269 .array_type = NO_ARRAY, 270 .tlv_type = 0x02, 271 .offset = offsetof(struct ssctl_subsys_event_resp, 272 resp), 273 .ei_array = qmi_response_type_v01_ei, 274 }, 275 {} 276}; 277 278static struct qmi_elem_info ssctl_shutdown_ind_ei[] = { 279 {} 280}; 281 282static void sysmon_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, 283 struct qmi_txn *txn, const void *data) 284{ 285 struct qcom_sysmon *sysmon = container_of(qmi, struct qcom_sysmon, qmi); 286 287 complete(&sysmon->ind_comp); 288} 289 290static struct qmi_msg_handler qmi_indication_handler[] = { 291 { 292 .type = QMI_INDICATION, 293 .msg_id = SSCTL_SHUTDOWN_READY_IND, 294 .ei = ssctl_shutdown_ind_ei, 295 .decoded_size = 0, 296 .fn = sysmon_ind_cb 297 }, 298 {} 299}; 300 301/** 302 * ssctl_request_shutdown() - request shutdown via SSCTL QMI service 303 * @sysmon: sysmon context 304 */ 305static void ssctl_request_shutdown(struct qcom_sysmon *sysmon) 306{ 307 struct ssctl_shutdown_resp resp; 308 struct qmi_txn txn; 309 int ret; 310 311 reinit_completion(&sysmon->ind_comp); 312 reinit_completion(&sysmon->shutdown_comp); 313 ret = qmi_txn_init(&sysmon->qmi, &txn, ssctl_shutdown_resp_ei, &resp); 314 if (ret < 0) { 315 dev_err(sysmon->dev, "failed to allocate QMI txn\n"); 316 return; 317 } 318 319 ret = qmi_send_request(&sysmon->qmi, &sysmon->ssctl, &txn, 320 SSCTL_SHUTDOWN_REQ, 0, NULL, NULL); 321 if (ret < 0) { 322 dev_err(sysmon->dev, "failed to send shutdown request\n"); 323 qmi_txn_cancel(&txn); 324 return; 325 } 326 327 ret = qmi_txn_wait(&txn, 5 * HZ); 328 if (ret < 0) 329 dev_err(sysmon->dev, "failed receiving QMI response\n"); 330 else if (resp.resp.result) 331 dev_err(sysmon->dev, "shutdown request failed\n"); 332 else 333 dev_dbg(sysmon->dev, "shutdown request completed\n"); 334 335 if (sysmon->shutdown_irq > 0) { 336 ret = wait_for_completion_timeout(&sysmon->shutdown_comp, 337 10 * HZ); 338 if (!ret) { 339 ret = try_wait_for_completion(&sysmon->ind_comp); 340 if (!ret) 341 dev_err(sysmon->dev, 342 "timeout waiting for shutdown ack\n"); 343 } 344 } 345} 346 347/** 348 * ssctl_send_event() - send notification of other remote's SSR event 349 * @sysmon: sysmon context 350 * @event: sysmon event context 351 */ 352static void ssctl_send_event(struct qcom_sysmon *sysmon, 353 const struct sysmon_event *event) 354{ 355 struct ssctl_subsys_event_resp resp; 356 struct ssctl_subsys_event_req req; 357 struct qmi_txn txn; 358 int ret; 359 360 memset(&resp, 0, sizeof(resp)); 361 ret = qmi_txn_init(&sysmon->qmi, &txn, ssctl_subsys_event_resp_ei, &resp); 362 if (ret < 0) { 363 dev_err(sysmon->dev, "failed to allocate QMI txn\n"); 364 return; 365 } 366 367 memset(&req, 0, sizeof(req)); 368 strlcpy(req.subsys_name, event->subsys_name, sizeof(req.subsys_name)); 369 req.subsys_name_len = strlen(req.subsys_name); 370 req.event = event->ssr_event; 371 req.evt_driven_valid = true; 372 req.evt_driven = SSCTL_SSR_EVENT_FORCED; 373 374 ret = qmi_send_request(&sysmon->qmi, &sysmon->ssctl, &txn, 375 SSCTL_SUBSYS_EVENT_REQ, 40, 376 ssctl_subsys_event_req_ei, &req); 377 if (ret < 0) { 378 dev_err(sysmon->dev, "failed to send shutdown request\n"); 379 qmi_txn_cancel(&txn); 380 return; 381 } 382 383 ret = qmi_txn_wait(&txn, 5 * HZ); 384 if (ret < 0) 385 dev_err(sysmon->dev, "failed receiving QMI response\n"); 386 else if (resp.resp.result) 387 dev_err(sysmon->dev, "ssr event send failed\n"); 388 else 389 dev_dbg(sysmon->dev, "ssr event send completed\n"); 390} 391 392/** 393 * ssctl_new_server() - QMI callback indicating a new service 394 * @qmi: QMI handle 395 * @svc: service information 396 * 397 * Return: 0 if we're interested in this service, -EINVAL otherwise. 398 */ 399static int ssctl_new_server(struct qmi_handle *qmi, struct qmi_service *svc) 400{ 401 struct qcom_sysmon *sysmon = container_of(qmi, struct qcom_sysmon, qmi); 402 403 switch (svc->version) { 404 case 1: 405 if (svc->instance != 0) 406 return -EINVAL; 407 if (strcmp(sysmon->name, "modem")) 408 return -EINVAL; 409 break; 410 case 2: 411 if (svc->instance != sysmon->ssctl_instance) 412 return -EINVAL; 413 break; 414 default: 415 return -EINVAL; 416 } 417 418 sysmon->ssctl_version = svc->version; 419 420 sysmon->ssctl.sq_family = AF_QIPCRTR; 421 sysmon->ssctl.sq_node = svc->node; 422 sysmon->ssctl.sq_port = svc->port; 423 424 svc->priv = sysmon; 425 426 complete(&sysmon->ssctl_comp); 427 428 return 0; 429} 430 431/** 432 * ssctl_del_server() - QMI callback indicating that @svc is removed 433 * @qmi: QMI handle 434 * @svc: service information 435 */ 436static void ssctl_del_server(struct qmi_handle *qmi, struct qmi_service *svc) 437{ 438 struct qcom_sysmon *sysmon = svc->priv; 439 440 sysmon->ssctl_version = 0; 441} 442 443static const struct qmi_ops ssctl_ops = { 444 .new_server = ssctl_new_server, 445 .del_server = ssctl_del_server, 446}; 447 448static int sysmon_prepare(struct rproc_subdev *subdev) 449{ 450 struct qcom_sysmon *sysmon = container_of(subdev, struct qcom_sysmon, 451 subdev); 452 struct sysmon_event event = { 453 .subsys_name = sysmon->name, 454 .ssr_event = SSCTL_SSR_EVENT_BEFORE_POWERUP 455 }; 456 457 mutex_lock(&sysmon->state_lock); 458 sysmon->state = SSCTL_SSR_EVENT_BEFORE_POWERUP; 459 blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)&event); 460 mutex_unlock(&sysmon->state_lock); 461 462 return 0; 463} 464 465/** 466 * sysmon_start() - start callback for the sysmon remoteproc subdevice 467 * @subdev: instance of the sysmon subdevice 468 * 469 * Inform all the listners of sysmon notifications that the rproc associated 470 * to @subdev has booted up. The rproc that booted up also needs to know 471 * which rprocs are already up and running, so send start notifications 472 * on behalf of all the online rprocs. 473 */ 474static int sysmon_start(struct rproc_subdev *subdev) 475{ 476 struct qcom_sysmon *sysmon = container_of(subdev, struct qcom_sysmon, 477 subdev); 478 struct qcom_sysmon *target; 479 struct sysmon_event event = { 480 .subsys_name = sysmon->name, 481 .ssr_event = SSCTL_SSR_EVENT_AFTER_POWERUP 482 }; 483 484 reinit_completion(&sysmon->ssctl_comp); 485 mutex_lock(&sysmon->state_lock); 486 sysmon->state = SSCTL_SSR_EVENT_AFTER_POWERUP; 487 blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)&event); 488 mutex_unlock(&sysmon->state_lock); 489 490 mutex_lock(&sysmon_lock); 491 list_for_each_entry(target, &sysmon_list, node) { 492 if (target == sysmon) 493 continue; 494 495 mutex_lock(&target->state_lock); 496 event.subsys_name = target->name; 497 event.ssr_event = target->state; 498 499 if (sysmon->ssctl_version == 2) 500 ssctl_send_event(sysmon, &event); 501 else if (sysmon->ept) 502 sysmon_send_event(sysmon, &event); 503 mutex_unlock(&target->state_lock); 504 } 505 mutex_unlock(&sysmon_lock); 506 507 return 0; 508} 509 510static void sysmon_stop(struct rproc_subdev *subdev, bool crashed) 511{ 512 struct qcom_sysmon *sysmon = container_of(subdev, struct qcom_sysmon, subdev); 513 struct sysmon_event event = { 514 .subsys_name = sysmon->name, 515 .ssr_event = SSCTL_SSR_EVENT_BEFORE_SHUTDOWN 516 }; 517 518 mutex_lock(&sysmon->state_lock); 519 sysmon->state = SSCTL_SSR_EVENT_BEFORE_SHUTDOWN; 520 blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)&event); 521 mutex_unlock(&sysmon->state_lock); 522 523 /* Don't request graceful shutdown if we've crashed */ 524 if (crashed) 525 return; 526 527 if (sysmon->ssctl_instance) { 528 if (!wait_for_completion_timeout(&sysmon->ssctl_comp, HZ / 2)) 529 dev_err(sysmon->dev, "timeout waiting for ssctl service\n"); 530 } 531 532 if (sysmon->ssctl_version) 533 ssctl_request_shutdown(sysmon); 534 else if (sysmon->ept) 535 sysmon_request_shutdown(sysmon); 536} 537 538static void sysmon_unprepare(struct rproc_subdev *subdev) 539{ 540 struct qcom_sysmon *sysmon = container_of(subdev, struct qcom_sysmon, 541 subdev); 542 struct sysmon_event event = { 543 .subsys_name = sysmon->name, 544 .ssr_event = SSCTL_SSR_EVENT_AFTER_SHUTDOWN 545 }; 546 547 mutex_lock(&sysmon->state_lock); 548 sysmon->state = SSCTL_SSR_EVENT_AFTER_SHUTDOWN; 549 blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)&event); 550 mutex_unlock(&sysmon->state_lock); 551} 552 553/** 554 * sysmon_notify() - notify sysmon target of another's SSR 555 * @nb: notifier_block associated with sysmon instance 556 * @event: unused 557 * @data: SSR identifier of the remote that is going down 558 */ 559static int sysmon_notify(struct notifier_block *nb, unsigned long event, 560 void *data) 561{ 562 struct qcom_sysmon *sysmon = container_of(nb, struct qcom_sysmon, nb); 563 struct sysmon_event *sysmon_event = data; 564 565 /* Skip non-running rprocs and the originating instance */ 566 if (sysmon->state != SSCTL_SSR_EVENT_AFTER_POWERUP || 567 !strcmp(sysmon_event->subsys_name, sysmon->name)) { 568 dev_dbg(sysmon->dev, "not notifying %s\n", sysmon->name); 569 return NOTIFY_DONE; 570 } 571 572 /* Only SSCTL version 2 supports SSR events */ 573 if (sysmon->ssctl_version == 2) 574 ssctl_send_event(sysmon, sysmon_event); 575 else if (sysmon->ept) 576 sysmon_send_event(sysmon, sysmon_event); 577 578 return NOTIFY_DONE; 579} 580 581static irqreturn_t sysmon_shutdown_interrupt(int irq, void *data) 582{ 583 struct qcom_sysmon *sysmon = data; 584 585 complete(&sysmon->shutdown_comp); 586 587 return IRQ_HANDLED; 588} 589 590/** 591 * qcom_add_sysmon_subdev() - create a sysmon subdev for the given remoteproc 592 * @rproc: rproc context to associate the subdev with 593 * @name: name of this subdev, to use in SSR 594 * @ssctl_instance: instance id of the ssctl QMI service 595 * 596 * Return: A new qcom_sysmon object, or NULL on failure 597 */ 598struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc, 599 const char *name, 600 int ssctl_instance) 601{ 602 struct qcom_sysmon *sysmon; 603 int ret; 604 605 sysmon = kzalloc(sizeof(*sysmon), GFP_KERNEL); 606 if (!sysmon) 607 return ERR_PTR(-ENOMEM); 608 609 sysmon->dev = rproc->dev.parent; 610 sysmon->rproc = rproc; 611 612 sysmon->name = name; 613 sysmon->ssctl_instance = ssctl_instance; 614 615 init_completion(&sysmon->comp); 616 init_completion(&sysmon->ind_comp); 617 init_completion(&sysmon->shutdown_comp); 618 init_completion(&sysmon->ssctl_comp); 619 mutex_init(&sysmon->lock); 620 mutex_init(&sysmon->state_lock); 621 622 sysmon->shutdown_irq = of_irq_get_byname(sysmon->dev->of_node, 623 "shutdown-ack"); 624 if (sysmon->shutdown_irq < 0) { 625 if (sysmon->shutdown_irq != -ENODATA) { 626 dev_err(sysmon->dev, 627 "failed to retrieve shutdown-ack IRQ\n"); 628 ret = sysmon->shutdown_irq; 629 kfree(sysmon); 630 return ERR_PTR(ret); 631 } 632 } else { 633 ret = devm_request_threaded_irq(sysmon->dev, 634 sysmon->shutdown_irq, 635 NULL, sysmon_shutdown_interrupt, 636 IRQF_TRIGGER_RISING | IRQF_ONESHOT, 637 "q6v5 shutdown-ack", sysmon); 638 if (ret) { 639 dev_err(sysmon->dev, 640 "failed to acquire shutdown-ack IRQ\n"); 641 kfree(sysmon); 642 return ERR_PTR(ret); 643 } 644 } 645 646 ret = qmi_handle_init(&sysmon->qmi, SSCTL_MAX_MSG_LEN, &ssctl_ops, 647 qmi_indication_handler); 648 if (ret < 0) { 649 dev_err(sysmon->dev, "failed to initialize qmi handle\n"); 650 kfree(sysmon); 651 return ERR_PTR(ret); 652 } 653 654 qmi_add_lookup(&sysmon->qmi, 43, 0, 0); 655 656 sysmon->subdev.prepare = sysmon_prepare; 657 sysmon->subdev.start = sysmon_start; 658 sysmon->subdev.stop = sysmon_stop; 659 sysmon->subdev.unprepare = sysmon_unprepare; 660 661 rproc_add_subdev(rproc, &sysmon->subdev); 662 663 sysmon->nb.notifier_call = sysmon_notify; 664 blocking_notifier_chain_register(&sysmon_notifiers, &sysmon->nb); 665 666 mutex_lock(&sysmon_lock); 667 list_add(&sysmon->node, &sysmon_list); 668 mutex_unlock(&sysmon_lock); 669 670 return sysmon; 671} 672EXPORT_SYMBOL_GPL(qcom_add_sysmon_subdev); 673 674/** 675 * qcom_remove_sysmon_subdev() - release a qcom_sysmon 676 * @sysmon: sysmon context, as retrieved by qcom_add_sysmon_subdev() 677 */ 678void qcom_remove_sysmon_subdev(struct qcom_sysmon *sysmon) 679{ 680 if (!sysmon) 681 return; 682 683 mutex_lock(&sysmon_lock); 684 list_del(&sysmon->node); 685 mutex_unlock(&sysmon_lock); 686 687 blocking_notifier_chain_unregister(&sysmon_notifiers, &sysmon->nb); 688 689 rproc_remove_subdev(sysmon->rproc, &sysmon->subdev); 690 691 qmi_handle_release(&sysmon->qmi); 692 693 kfree(sysmon); 694} 695EXPORT_SYMBOL_GPL(qcom_remove_sysmon_subdev); 696 697/** 698 * sysmon_probe() - probe sys_mon channel 699 * @rpdev: rpmsg device handle 700 * 701 * Find the sysmon context associated with the ancestor remoteproc and assign 702 * this rpmsg device with said sysmon context. 703 * 704 * Return: 0 on success, negative errno on failure. 705 */ 706static int sysmon_probe(struct rpmsg_device *rpdev) 707{ 708 struct qcom_sysmon *sysmon; 709 struct rproc *rproc; 710 711 rproc = rproc_get_by_child(&rpdev->dev); 712 if (!rproc) { 713 dev_err(&rpdev->dev, "sysmon device not child of rproc\n"); 714 return -EINVAL; 715 } 716 717 mutex_lock(&sysmon_lock); 718 list_for_each_entry(sysmon, &sysmon_list, node) { 719 if (sysmon->rproc == rproc) 720 goto found; 721 } 722 mutex_unlock(&sysmon_lock); 723 724 dev_err(&rpdev->dev, "no sysmon associated with parent rproc\n"); 725 726 return -EINVAL; 727 728found: 729 mutex_unlock(&sysmon_lock); 730 731 rpdev->ept->priv = sysmon; 732 sysmon->ept = rpdev->ept; 733 734 return 0; 735} 736 737/** 738 * sysmon_remove() - sys_mon channel remove handler 739 * @rpdev: rpmsg device handle 740 * 741 * Disassociate the rpmsg device with the sysmon instance. 742 */ 743static void sysmon_remove(struct rpmsg_device *rpdev) 744{ 745 struct qcom_sysmon *sysmon = rpdev->ept->priv; 746 747 sysmon->ept = NULL; 748} 749 750static const struct rpmsg_device_id sysmon_match[] = { 751 { "sys_mon" }, 752 {} 753}; 754 755static struct rpmsg_driver sysmon_driver = { 756 .probe = sysmon_probe, 757 .remove = sysmon_remove, 758 .callback = sysmon_callback, 759 .id_table = sysmon_match, 760 .drv = { 761 .name = "qcom_sysmon", 762 }, 763}; 764 765module_rpmsg_driver(sysmon_driver); 766 767MODULE_DESCRIPTION("Qualcomm sysmon driver"); 768MODULE_LICENSE("GPL v2"); 769