root/drivers/remoteproc/qcom_sysmon.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sysmon_send_event
  2. sysmon_request_shutdown
  3. sysmon_callback
  4. sysmon_ind_cb
  5. ssctl_request_shutdown
  6. ssctl_send_event
  7. ssctl_new_server
  8. ssctl_del_server
  9. sysmon_start
  10. sysmon_stop
  11. sysmon_notify
  12. sysmon_shutdown_interrupt
  13. qcom_add_sysmon_subdev
  14. qcom_remove_sysmon_subdev
  15. sysmon_probe
  16. sysmon_remove

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

/* [<][>][^][v][top][bottom][index][help] */