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