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