aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/remoteproc/qcom_sysmon.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/remoteproc/qcom_sysmon.c')
-rw-r--r--drivers/remoteproc/qcom_sysmon.c82
1 files changed, 78 insertions, 4 deletions
diff --git a/drivers/remoteproc/qcom_sysmon.c b/drivers/remoteproc/qcom_sysmon.c
index e976a602b015..c231314eab66 100644
--- a/drivers/remoteproc/qcom_sysmon.c
+++ b/drivers/remoteproc/qcom_sysmon.c
@@ -6,8 +6,9 @@
6#include <linux/module.h> 6#include <linux/module.h>
7#include <linux/notifier.h> 7#include <linux/notifier.h>
8#include <linux/slab.h> 8#include <linux/slab.h>
9#include <linux/interrupt.h>
9#include <linux/io.h> 10#include <linux/io.h>
10#include <linux/notifier.h> 11#include <linux/of_irq.h>
11#include <linux/of_platform.h> 12#include <linux/of_platform.h>
12#include <linux/platform_device.h> 13#include <linux/platform_device.h>
13#include <linux/remoteproc/qcom_rproc.h> 14#include <linux/remoteproc/qcom_rproc.h>
@@ -25,6 +26,7 @@ struct qcom_sysmon {
25 26
26 const char *name; 27 const char *name;
27 28
29 int shutdown_irq;
28 int ssctl_version; 30 int ssctl_version;
29 int ssctl_instance; 31 int ssctl_instance;
30 32
@@ -34,6 +36,8 @@ struct qcom_sysmon {
34 36
35 struct rpmsg_endpoint *ept; 37 struct rpmsg_endpoint *ept;
36 struct completion comp; 38 struct completion comp;
39 struct completion ind_comp;
40 struct completion shutdown_comp;
37 struct mutex lock; 41 struct mutex lock;
38 42
39 bool ssr_ack; 43 bool ssr_ack;
@@ -137,6 +141,7 @@ static int sysmon_callback(struct rpmsg_device *rpdev, void *data, int count,
137} 141}
138 142
139#define SSCTL_SHUTDOWN_REQ 0x21 143#define SSCTL_SHUTDOWN_REQ 0x21
144#define SSCTL_SHUTDOWN_READY_IND 0x21
140#define SSCTL_SUBSYS_EVENT_REQ 0x23 145#define SSCTL_SUBSYS_EVENT_REQ 0x23
141 146
142#define SSCTL_MAX_MSG_LEN 7 147#define SSCTL_MAX_MSG_LEN 7
@@ -252,6 +257,29 @@ static struct qmi_elem_info ssctl_subsys_event_resp_ei[] = {
252 {} 257 {}
253}; 258};
254 259
260static struct qmi_elem_info ssctl_shutdown_ind_ei[] = {
261 {}
262};
263
264static 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
272static 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
255/** 283/**
256 * ssctl_request_shutdown() - request shutdown via SSCTL QMI service 284 * ssctl_request_shutdown() - request shutdown via SSCTL QMI service
257 * @sysmon: sysmon context 285 * @sysmon: sysmon context
@@ -262,6 +290,8 @@ static void ssctl_request_shutdown(struct qcom_sysmon *sysmon)
262 struct qmi_txn txn; 290 struct qmi_txn txn;
263 int ret; 291 int ret;
264 292
293 reinit_completion(&sysmon->ind_comp);
294 reinit_completion(&sysmon->shutdown_comp);
265 ret = qmi_txn_init(&sysmon->qmi, &txn, ssctl_shutdown_resp_ei, &resp); 295 ret = qmi_txn_init(&sysmon->qmi, &txn, ssctl_shutdown_resp_ei, &resp);
266 if (ret < 0) { 296 if (ret < 0) {
267 dev_err(sysmon->dev, "failed to allocate QMI txn\n"); 297 dev_err(sysmon->dev, "failed to allocate QMI txn\n");
@@ -283,6 +313,17 @@ static void ssctl_request_shutdown(struct qcom_sysmon *sysmon)
283 dev_err(sysmon->dev, "shutdown request failed\n"); 313 dev_err(sysmon->dev, "shutdown request failed\n");
284 else 314 else
285 dev_dbg(sysmon->dev, "shutdown request completed\n"); 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 }
286} 327}
287 328
288/** 329/**
@@ -432,6 +473,15 @@ static int sysmon_notify(struct notifier_block *nb, unsigned long event,
432 return NOTIFY_DONE; 473 return NOTIFY_DONE;
433} 474}
434 475
476static 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
435/** 485/**
436 * qcom_add_sysmon_subdev() - create a sysmon subdev for the given remoteproc 486 * qcom_add_sysmon_subdev() - create a sysmon subdev for the given remoteproc
437 * @rproc: rproc context to associate the subdev with 487 * @rproc: rproc context to associate the subdev with
@@ -449,7 +499,7 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
449 499
450 sysmon = kzalloc(sizeof(*sysmon), GFP_KERNEL); 500 sysmon = kzalloc(sizeof(*sysmon), GFP_KERNEL);
451 if (!sysmon) 501 if (!sysmon)
452 return NULL; 502 return ERR_PTR(-ENOMEM);
453 503
454 sysmon->dev = rproc->dev.parent; 504 sysmon->dev = rproc->dev.parent;
455 sysmon->rproc = rproc; 505 sysmon->rproc = rproc;
@@ -458,13 +508,37 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
458 sysmon->ssctl_instance = ssctl_instance; 508 sysmon->ssctl_instance = ssctl_instance;
459 509
460 init_completion(&sysmon->comp); 510 init_completion(&sysmon->comp);
511 init_completion(&sysmon->ind_comp);
512 init_completion(&sysmon->shutdown_comp);
461 mutex_init(&sysmon->lock); 513 mutex_init(&sysmon->lock);
462 514
463 ret = qmi_handle_init(&sysmon->qmi, SSCTL_MAX_MSG_LEN, &ssctl_ops, NULL); 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);
464 if (ret < 0) { 538 if (ret < 0) {
465 dev_err(sysmon->dev, "failed to initialize qmi handle\n"); 539 dev_err(sysmon->dev, "failed to initialize qmi handle\n");
466 kfree(sysmon); 540 kfree(sysmon);
467 return NULL; 541 return ERR_PTR(ret);
468 } 542 }
469 543
470 qmi_add_lookup(&sysmon->qmi, 43, 0, 0); 544 qmi_add_lookup(&sysmon->qmi, 43, 0, 0);