hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/remoteproc/qcom_sysmon.c
....@@ -6,8 +6,9 @@
66 #include <linux/module.h>
77 #include <linux/notifier.h>
88 #include <linux/slab.h>
9
+#include <linux/interrupt.h>
910 #include <linux/io.h>
10
-#include <linux/notifier.h>
11
+#include <linux/of_irq.h>
1112 #include <linux/of_platform.h>
1213 #include <linux/platform_device.h>
1314 #include <linux/remoteproc/qcom_rproc.h>
....@@ -21,10 +22,14 @@
2122 struct rproc_subdev subdev;
2223 struct rproc *rproc;
2324
25
+ int state;
26
+ struct mutex state_lock;
27
+
2428 struct list_head node;
2529
2630 const char *name;
2731
32
+ int shutdown_irq;
2833 int ssctl_version;
2934 int ssctl_instance;
3035
....@@ -34,6 +39,9 @@
3439
3540 struct rpmsg_endpoint *ept;
3641 struct completion comp;
42
+ struct completion ind_comp;
43
+ struct completion shutdown_comp;
44
+ struct completion ssctl_comp;
3745 struct mutex lock;
3846
3947 bool ssr_ack;
....@@ -42,21 +50,42 @@
4250 struct sockaddr_qrtr ssctl;
4351 };
4452
53
+enum {
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
+
60
+static 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
+
67
+struct sysmon_event {
68
+ const char *subsys_name;
69
+ u32 ssr_event;
70
+};
71
+
4572 static DEFINE_MUTEX(sysmon_lock);
4673 static LIST_HEAD(sysmon_list);
4774
4875 /**
4976 * sysmon_send_event() - send notification of other remote's SSR event
5077 * @sysmon: sysmon context
51
- * @name: other remote's name
78
+ * @event: sysmon event context
5279 */
53
-static void sysmon_send_event(struct qcom_sysmon *sysmon, const char *name)
80
+static void sysmon_send_event(struct qcom_sysmon *sysmon,
81
+ const struct sysmon_event *event)
5482 {
5583 char req[50];
5684 int len;
5785 int ret;
5886
59
- len = snprintf(req, sizeof(req), "ssr:%s:before_shutdown", name);
87
+ len = snprintf(req, sizeof(req), "ssr:%s:%s", event->subsys_name,
88
+ sysmon_state_string[event->ssr_event]);
6089 if (len >= sizeof(req))
6190 return;
6291
....@@ -137,18 +166,12 @@
137166 }
138167
139168 #define SSCTL_SHUTDOWN_REQ 0x21
169
+#define SSCTL_SHUTDOWN_READY_IND 0x21
140170 #define SSCTL_SUBSYS_EVENT_REQ 0x23
141171
142172 #define SSCTL_MAX_MSG_LEN 7
143173
144174 #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
-};
152175
153176 enum {
154177 SSCTL_SSR_EVENT_FORCED,
....@@ -252,6 +275,29 @@
252275 {}
253276 };
254277
278
+static struct qmi_elem_info ssctl_shutdown_ind_ei[] = {
279
+ {}
280
+};
281
+
282
+static 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
+
290
+static 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
+
255301 /**
256302 * ssctl_request_shutdown() - request shutdown via SSCTL QMI service
257303 * @sysmon: sysmon context
....@@ -262,6 +308,8 @@
262308 struct qmi_txn txn;
263309 int ret;
264310
311
+ reinit_completion(&sysmon->ind_comp);
312
+ reinit_completion(&sysmon->shutdown_comp);
265313 ret = qmi_txn_init(&sysmon->qmi, &txn, ssctl_shutdown_resp_ei, &resp);
266314 if (ret < 0) {
267315 dev_err(sysmon->dev, "failed to allocate QMI txn\n");
....@@ -283,14 +331,26 @@
283331 dev_err(sysmon->dev, "shutdown request failed\n");
284332 else
285333 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
+ }
286345 }
287346
288347 /**
289348 * ssctl_send_event() - send notification of other remote's SSR event
290349 * @sysmon: sysmon context
291
- * @name: other remote's name
350
+ * @event: sysmon event context
292351 */
293
-static void ssctl_send_event(struct qcom_sysmon *sysmon, const char *name)
352
+static void ssctl_send_event(struct qcom_sysmon *sysmon,
353
+ const struct sysmon_event *event)
294354 {
295355 struct ssctl_subsys_event_resp resp;
296356 struct ssctl_subsys_event_req req;
....@@ -305,9 +365,9 @@
305365 }
306366
307367 memset(&req, 0, sizeof(req));
308
- strlcpy(req.subsys_name, name, sizeof(req.subsys_name));
368
+ strlcpy(req.subsys_name, event->subsys_name, sizeof(req.subsys_name));
309369 req.subsys_name_len = strlen(req.subsys_name);
310
- req.event = SSCTL_SSR_EVENT_BEFORE_SHUTDOWN;
370
+ req.event = event->ssr_event;
311371 req.evt_driven_valid = true;
312372 req.evt_driven = SSCTL_SSR_EVENT_FORCED;
313373
....@@ -353,7 +413,7 @@
353413 break;
354414 default:
355415 return -EINVAL;
356
- };
416
+ }
357417
358418 sysmon->ssctl_version = svc->version;
359419
....@@ -362,6 +422,8 @@
362422 sysmon->ssctl.sq_port = svc->port;
363423
364424 svc->priv = sysmon;
425
+
426
+ complete(&sysmon->ssctl_comp);
365427
366428 return 0;
367429 }
....@@ -383,25 +445,109 @@
383445 .del_server = ssctl_del_server,
384446 };
385447
448
+static 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
+ */
386474 static int sysmon_start(struct rproc_subdev *subdev)
387475 {
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
+
388507 return 0;
389508 }
390509
391510 static void sysmon_stop(struct rproc_subdev *subdev, bool crashed)
392511 {
393512 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
+ };
394517
395
- blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)sysmon->name);
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);
396522
397523 /* Don't request graceful shutdown if we've crashed */
398524 if (crashed)
399525 return;
400526
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
+
401532 if (sysmon->ssctl_version)
402533 ssctl_request_shutdown(sysmon);
403534 else if (sysmon->ept)
404535 sysmon_request_shutdown(sysmon);
536
+}
537
+
538
+static 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);
405551 }
406552
407553 /**
....@@ -414,22 +560,31 @@
414560 void *data)
415561 {
416562 struct qcom_sysmon *sysmon = container_of(nb, struct qcom_sysmon, nb);
417
- struct rproc *rproc = sysmon->rproc;
418
- const char *ssr_name = data;
563
+ struct sysmon_event *sysmon_event = data;
419564
420565 /* Skip non-running rprocs and the originating instance */
421
- if (rproc->state != RPROC_RUNNING || !strcmp(data, sysmon->name)) {
566
+ if (sysmon->state != SSCTL_SSR_EVENT_AFTER_POWERUP ||
567
+ !strcmp(sysmon_event->subsys_name, sysmon->name)) {
422568 dev_dbg(sysmon->dev, "not notifying %s\n", sysmon->name);
423569 return NOTIFY_DONE;
424570 }
425571
426572 /* Only SSCTL version 2 supports SSR events */
427573 if (sysmon->ssctl_version == 2)
428
- ssctl_send_event(sysmon, ssr_name);
574
+ ssctl_send_event(sysmon, sysmon_event);
429575 else if (sysmon->ept)
430
- sysmon_send_event(sysmon, ssr_name);
576
+ sysmon_send_event(sysmon, sysmon_event);
431577
432578 return NOTIFY_DONE;
579
+}
580
+
581
+static 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;
433588 }
434589
435590 /**
....@@ -449,7 +604,7 @@
449604
450605 sysmon = kzalloc(sizeof(*sysmon), GFP_KERNEL);
451606 if (!sysmon)
452
- return NULL;
607
+ return ERR_PTR(-ENOMEM);
453608
454609 sysmon->dev = rproc->dev.parent;
455610 sysmon->rproc = rproc;
....@@ -458,19 +613,50 @@
458613 sysmon->ssctl_instance = ssctl_instance;
459614
460615 init_completion(&sysmon->comp);
616
+ init_completion(&sysmon->ind_comp);
617
+ init_completion(&sysmon->shutdown_comp);
618
+ init_completion(&sysmon->ssctl_comp);
461619 mutex_init(&sysmon->lock);
620
+ mutex_init(&sysmon->state_lock);
462621
463
- ret = qmi_handle_init(&sysmon->qmi, SSCTL_MAX_MSG_LEN, &ssctl_ops, NULL);
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);
464648 if (ret < 0) {
465649 dev_err(sysmon->dev, "failed to initialize qmi handle\n");
466650 kfree(sysmon);
467
- return NULL;
651
+ return ERR_PTR(ret);
468652 }
469653
470654 qmi_add_lookup(&sysmon->qmi, 43, 0, 0);
471655
656
+ sysmon->subdev.prepare = sysmon_prepare;
472657 sysmon->subdev.start = sysmon_start;
473658 sysmon->subdev.stop = sysmon_stop;
659
+ sysmon->subdev.unprepare = sysmon_unprepare;
474660
475661 rproc_add_subdev(rproc, &sysmon->subdev);
476662