blob: 9dc3dabfb643cd1525d4be3dd6a52d4341703c82 [file] [log] [blame]
Channagoud Kadabi4d480b02016-12-20 11:57:51 -08001/*
Satya Durga Srinivasu Prabhala34947112017-01-16 10:37:08 -08002 * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
Channagoud Kadabi4d480b02016-12-20 11:57:51 -08003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 */
14
15#define pr_fmt(fmt) "service-notifier: %s: " fmt, __func__
16
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/string.h>
20#include <linux/completion.h>
21#include <linux/slab.h>
22#include <linux/of.h>
23#include <linux/err.h>
24#include <linux/debugfs.h>
25#include <linux/uaccess.h>
26
27#include <soc/qcom/subsystem_restart.h>
28#include <soc/qcom/subsystem_notif.h>
29#include <soc/qcom/sysmon.h>
30#include <soc/qcom/service-locator.h>
31#include <soc/qcom/service-notifier.h>
32#include "service-notifier-private.h"
33
34#define QMI_RESP_BIT_SHIFT(x) (x << 16)
35#define SERVREG_NOTIF_NAME_LENGTH QMI_SERVREG_NOTIF_NAME_LENGTH_V01
36#define SERVREG_NOTIF_SERVICE_ID SERVREG_NOTIF_SERVICE_ID_V01
37#define SERVREG_NOTIF_SERVICE_VERS SERVREG_NOTIF_SERVICE_VERS_V01
38
39#define SERVREG_NOTIF_SET_ACK_REQ \
40 QMI_SERVREG_NOTIF_STATE_UPDATED_IND_ACK_REQ_V01
41#define SERVREG_NOTIF_SET_ACK_REQ_MSG_LEN \
42 QMI_SERVREG_NOTIF_SET_ACK_REQ_MSG_V01_MAX_MSG_LEN
43#define SERVREG_NOTIF_SET_ACK_RESP \
44 QMI_SERVREG_NOTIF_STATE_UPDATED_IND_ACK_RESP_V01
45#define SERVREG_NOTIF_SET_ACK_RESP_MSG_LEN \
46 QMI_SERVREG_NOTIF_SET_ACK_RESP_MSG_V01_MAX_MSG_LEN
47#define SERVREG_NOTIF_STATE_UPDATED_IND_MSG \
48 QMI_SERVREG_NOTIF_STATE_UPDATED_IND_V01
49#define SERVREG_NOTIF_STATE_UPDATED_IND_MSG_LEN \
50 QMI_SERVREG_NOTIF_STATE_UPDATED_IND_MSG_V01_MAX_MSG_LEN
51
52#define SERVREG_NOTIF_REGISTER_LISTENER_REQ \
53 QMI_SERVREG_NOTIF_REGISTER_LISTENER_REQ_V01
54#define SERVREG_NOTIF_REGISTER_LISTENER_REQ_MSG_LEN \
55 QMI_SERVREG_NOTIF_REGISTER_LISTENER_REQ_MSG_V01_MAX_MSG_LEN
56#define SERVREG_NOTIF_REGISTER_LISTENER_RESP \
57 QMI_SERVREG_NOTIF_REGISTER_LISTENER_RESP_V01
58#define SERVREG_NOTIF_REGISTER_LISTENER_RESP_MSG_LEN \
59 QMI_SERVREG_NOTIF_REGISTER_LISTENER_RESP_MSG_V01_MAX_MSG_LEN
60
61#define QMI_STATE_MIN_VAL QMI_SERVREG_NOTIF_SERVICE_STATE_ENUM_TYPE_MIN_VAL_V01
62#define QMI_STATE_MAX_VAL QMI_SERVREG_NOTIF_SERVICE_STATE_ENUM_TYPE_MAX_VAL_V01
63
64#define SERVER_TIMEOUT 500
65#define MAX_STRING_LEN 100
66
67/*
68 * Per user service data structure
69 * struct service_notif_info - notifier struct for each unique service path
70 * service_path - service provider path/location
71 * instance_id - service instance id specific to a subsystem
72 * service_notif_rcvr_list - list of clients interested in this service
73 * providers notifications
74 * curr_state: Current state of the service
75 */
76struct service_notif_info {
77 char service_path[SERVREG_NOTIF_NAME_LENGTH];
78 int instance_id;
79 struct srcu_notifier_head service_notif_rcvr_list;
80 struct list_head list;
81 int curr_state;
82};
83static LIST_HEAD(service_list);
84static DEFINE_MUTEX(service_list_lock);
85
86struct ind_req_resp {
87 char service_path[SERVREG_NOTIF_NAME_LENGTH];
88 int transaction_id;
89};
90
91/*
92 * Per Root Process Domain (Root service) data structure
93 * struct qmi_client_info - QMI client info for each subsystem/instance id
94 * instance_id - service instance id specific to a subsystem (Root PD)
95 * clnt_handle - unique QMI client handle
96 * service_connected - indicates if QMI service is up on the subsystem
97 * ssr_handle - The SSR handle provided by the SSR driver for the subsystem
98 * on which the remote root PD runs.
99 */
100struct qmi_client_info {
101 int instance_id;
102 struct work_struct svc_arrive;
103 struct work_struct svc_exit;
104 struct work_struct svc_rcv_msg;
105 struct work_struct ind_ack;
106 struct workqueue_struct *svc_event_wq;
107 struct qmi_handle *clnt_handle;
108 struct notifier_block notifier;
109 void *ssr_handle;
110 struct notifier_block ssr_notifier;
111 bool service_connected;
112 struct list_head list;
113 struct ind_req_resp ind_msg;
114};
115static LIST_HEAD(qmi_client_list);
116static DEFINE_MUTEX(qmi_list_lock);
117static DEFINE_MUTEX(qmi_client_release_lock);
118
119static DEFINE_MUTEX(notif_add_lock);
120
121static void root_service_clnt_recv_msg(struct work_struct *work);
122static void root_service_service_arrive(struct work_struct *work);
123static void root_service_exit_work(struct work_struct *work);
124
125static struct service_notif_info *_find_service_info(const char *service_path)
126{
127 struct service_notif_info *service_notif;
128
129 mutex_lock(&service_list_lock);
130 list_for_each_entry(service_notif, &service_list, list)
131 if (!strcmp(service_notif->service_path, service_path)) {
132 mutex_unlock(&service_list_lock);
133 return service_notif;
134 }
135 mutex_unlock(&service_list_lock);
136 return NULL;
137}
138
139static int service_notif_queue_notification(struct service_notif_info
140 *service_notif,
141 enum qmi_servreg_notif_service_state_enum_type_v01 notif_type,
142 void *info)
143{
144 int ret;
145
146 if (service_notif->curr_state == notif_type)
147 return 0;
148
149 ret = srcu_notifier_call_chain(&service_notif->service_notif_rcvr_list,
150 notif_type, info);
151 return ret;
152}
153
154static void root_service_clnt_recv_msg(struct work_struct *work)
155{
156 int ret;
157 struct qmi_client_info *data = container_of(work,
158 struct qmi_client_info, svc_rcv_msg);
159
160 do {
161 pr_debug("Polling for QMI recv msg(instance-id: %d)\n",
162 data->instance_id);
163 } while ((ret = qmi_recv_msg(data->clnt_handle)) == 0);
164
165 pr_debug("Notified about a Receive event (instance-id: %d)\n",
166 data->instance_id);
167}
168
169static void root_service_clnt_notify(struct qmi_handle *handle,
170 enum qmi_event_type event, void *notify_priv)
171{
172 struct qmi_client_info *data = container_of(notify_priv,
173 struct qmi_client_info, svc_arrive);
174
175 switch (event) {
176 case QMI_RECV_MSG:
177 schedule_work(&data->svc_rcv_msg);
178 break;
179 default:
180 break;
181 }
182}
183
184static void send_ind_ack(struct work_struct *work)
185{
186 struct qmi_client_info *data = container_of(work,
187 struct qmi_client_info, ind_ack);
188 struct qmi_servreg_notif_set_ack_req_msg_v01 req;
189 struct msg_desc req_desc, resp_desc;
190 struct qmi_servreg_notif_set_ack_resp_msg_v01 resp = { { 0, 0 } };
191 int rc;
192
193 req.transaction_id = data->ind_msg.transaction_id;
194 snprintf(req.service_name, ARRAY_SIZE(req.service_name), "%s",
195 data->ind_msg.service_path);
196
197 req_desc.msg_id = SERVREG_NOTIF_SET_ACK_REQ;
198 req_desc.max_msg_len = SERVREG_NOTIF_SET_ACK_REQ_MSG_LEN;
199 req_desc.ei_array = qmi_servreg_notif_set_ack_req_msg_v01_ei;
200
201 resp_desc.msg_id = SERVREG_NOTIF_SET_ACK_RESP;
202 resp_desc.max_msg_len = SERVREG_NOTIF_SET_ACK_RESP_MSG_LEN;
203 resp_desc.ei_array = qmi_servreg_notif_set_ack_resp_msg_v01_ei;
204
205 rc = qmi_send_req_wait(data->clnt_handle, &req_desc,
206 &req, sizeof(req), &resp_desc, &resp,
207 sizeof(resp), SERVER_TIMEOUT);
208 if (rc < 0) {
209 pr_err("%s: Sending Ack failed/server timeout, ret - %d\n",
210 data->ind_msg.service_path, rc);
211 return;
212 }
213
214 /* Check the response */
215 if (QMI_RESP_BIT_SHIFT(resp.resp.result) != QMI_RESULT_SUCCESS_V01)
216 pr_err("QMI request failed 0x%x\n",
217 QMI_RESP_BIT_SHIFT(resp.resp.error));
218 pr_debug("Indication ACKed for transid %d, service %s, instance %d!\n",
219 data->ind_msg.transaction_id, data->ind_msg.service_path,
220 data->instance_id);
221}
222
223static void root_service_service_ind_cb(struct qmi_handle *handle,
224 unsigned int msg_id, void *msg,
225 unsigned int msg_len, void *ind_cb_priv)
226{
227 struct qmi_client_info *data = (struct qmi_client_info *)ind_cb_priv;
228 struct service_notif_info *service_notif;
229 struct msg_desc ind_desc;
230 struct qmi_servreg_notif_state_updated_ind_msg_v01 ind_msg = {
231 QMI_STATE_MIN_VAL, "", 0xFFFF };
232 int rc;
233
234 ind_desc.msg_id = SERVREG_NOTIF_STATE_UPDATED_IND_MSG;
235 ind_desc.max_msg_len = SERVREG_NOTIF_STATE_UPDATED_IND_MSG_LEN;
236 ind_desc.ei_array = qmi_servreg_notif_state_updated_ind_msg_v01_ei;
237 rc = qmi_kernel_decode(&ind_desc, &ind_msg, msg, msg_len);
238 if (rc < 0) {
239 pr_err("Failed to decode message rc:%d\n", rc);
240 return;
241 }
242
243 pr_debug("Indication received from %s, state: 0x%x, trans-id: %d\n",
244 ind_msg.service_name, ind_msg.curr_state,
245 ind_msg.transaction_id);
246
247 service_notif = _find_service_info(ind_msg.service_name);
248 if (!service_notif)
249 return;
250
251 if ((int)ind_msg.curr_state < QMI_STATE_MIN_VAL ||
252 (int)ind_msg.curr_state > QMI_STATE_MAX_VAL)
253 pr_err("Unexpected indication notification state %d\n",
254 ind_msg.curr_state);
255 else {
256 mutex_lock(&notif_add_lock);
257 mutex_lock(&service_list_lock);
258 rc = service_notif_queue_notification(service_notif,
259 ind_msg.curr_state, NULL);
260 if (rc & NOTIFY_STOP_MASK)
261 pr_err("Notifier callback aborted for %s with error %d\n",
262 ind_msg.service_name, rc);
263 service_notif->curr_state = ind_msg.curr_state;
264 mutex_unlock(&service_list_lock);
265 mutex_unlock(&notif_add_lock);
266 }
267 data->ind_msg.transaction_id = ind_msg.transaction_id;
268 snprintf(data->ind_msg.service_path,
269 ARRAY_SIZE(data->ind_msg.service_path), "%s",
270 ind_msg.service_name);
271 schedule_work(&data->ind_ack);
272}
273
274static int send_notif_listener_msg_req(struct service_notif_info *service_notif,
275 struct qmi_client_info *data,
276 bool register_notif, int *curr_state)
277{
278 struct qmi_servreg_notif_register_listener_req_msg_v01 req;
279 struct qmi_servreg_notif_register_listener_resp_msg_v01
280 resp = { { 0, 0 } };
281 struct msg_desc req_desc, resp_desc;
282 int rc;
283
284 snprintf(req.service_name, ARRAY_SIZE(req.service_name), "%s",
285 service_notif->service_path);
286 req.enable = register_notif;
287
288 req_desc.msg_id = SERVREG_NOTIF_REGISTER_LISTENER_REQ;
289 req_desc.max_msg_len = SERVREG_NOTIF_REGISTER_LISTENER_REQ_MSG_LEN;
290 req_desc.ei_array = qmi_servreg_notif_register_listener_req_msg_v01_ei;
291
292 resp_desc.msg_id = SERVREG_NOTIF_REGISTER_LISTENER_RESP;
293 resp_desc.max_msg_len = SERVREG_NOTIF_REGISTER_LISTENER_RESP_MSG_LEN;
294 resp_desc.ei_array =
295 qmi_servreg_notif_register_listener_resp_msg_v01_ei;
296
297 rc = qmi_send_req_wait(data->clnt_handle, &req_desc, &req, sizeof(req),
298 &resp_desc, &resp, sizeof(resp),
299 SERVER_TIMEOUT);
300 if (rc < 0) {
301 pr_err("%s: Message sending failed/server timeout, ret - %d\n",
302 service_notif->service_path, rc);
303 return rc;
304 }
305
306 /* Check the response */
307 if (QMI_RESP_BIT_SHIFT(resp.resp.result) != QMI_RESULT_SUCCESS_V01) {
308 pr_err("QMI request failed 0x%x\n",
309 QMI_RESP_BIT_SHIFT(resp.resp.error));
310 return -EREMOTEIO;
311 }
312
313 if ((int) resp.curr_state < QMI_STATE_MIN_VAL ||
314 (int) resp.curr_state > QMI_STATE_MAX_VAL) {
315 pr_err("Invalid indication notification state %d\n",
316 resp.curr_state);
317 rc = -EINVAL;
318 }
319 *curr_state = resp.curr_state;
320 return rc;
321}
322
323static int register_notif_listener(struct service_notif_info *service_notif,
324 struct qmi_client_info *data,
325 int *curr_state)
326{
327 return send_notif_listener_msg_req(service_notif, data, true,
328 curr_state);
329}
330
331static void root_service_service_arrive(struct work_struct *work)
332{
333 struct service_notif_info *service_notif = NULL;
334 struct qmi_client_info *data = container_of(work,
335 struct qmi_client_info, svc_arrive);
336 int rc;
337 int curr_state;
338
Satya Durga Srinivasu Prabhala34947112017-01-16 10:37:08 -0800339 mutex_lock(&qmi_client_release_lock);
Channagoud Kadabi4d480b02016-12-20 11:57:51 -0800340 /* Create a Local client port for QMI communication */
341 data->clnt_handle = qmi_handle_create(root_service_clnt_notify, work);
342 if (!data->clnt_handle) {
343 pr_err("QMI client handle alloc failed (instance-id: %d)\n",
344 data->instance_id);
Satya Durga Srinivasu Prabhala34947112017-01-16 10:37:08 -0800345 mutex_unlock(&qmi_client_release_lock);
Channagoud Kadabi4d480b02016-12-20 11:57:51 -0800346 return;
347 }
348
349 /* Connect to the service on the root PD service */
350 rc = qmi_connect_to_service(data->clnt_handle,
351 SERVREG_NOTIF_SERVICE_ID, SERVREG_NOTIF_SERVICE_VERS,
352 data->instance_id);
353 if (rc < 0) {
354 pr_err("Could not connect to service(instance-id: %d) rc:%d\n",
355 data->instance_id, rc);
356 qmi_handle_destroy(data->clnt_handle);
357 data->clnt_handle = NULL;
Satya Durga Srinivasu Prabhala34947112017-01-16 10:37:08 -0800358 mutex_unlock(&qmi_client_release_lock);
Channagoud Kadabi4d480b02016-12-20 11:57:51 -0800359 return;
360 }
361 data->service_connected = true;
Satya Durga Srinivasu Prabhala34947112017-01-16 10:37:08 -0800362 mutex_unlock(&qmi_client_release_lock);
Channagoud Kadabi4d480b02016-12-20 11:57:51 -0800363 pr_info("Connection established between QMI handle and %d service\n",
364 data->instance_id);
365 /* Register for indication messages about service */
366 rc = qmi_register_ind_cb(data->clnt_handle, root_service_service_ind_cb,
367 (void *)data);
368 if (rc < 0)
369 pr_err("Indication callback register failed(instance-id: %d) rc:%d\n",
370 data->instance_id, rc);
371
372 mutex_lock(&notif_add_lock);
373 mutex_lock(&service_list_lock);
374 list_for_each_entry(service_notif, &service_list, list) {
375 if (service_notif->instance_id == data->instance_id) {
376 rc = register_notif_listener(service_notif, data,
377 &curr_state);
378 if (rc) {
379 pr_err("Notifier registration failed for %s rc:%d\n",
380 service_notif->service_path, rc);
381 } else {
382 rc = service_notif_queue_notification(
383 service_notif, curr_state, NULL);
384 if (rc & NOTIFY_STOP_MASK)
385 pr_err("Notifier callback aborted for %s error:%d\n",
386 service_notif->service_path, rc);
387 service_notif->curr_state = curr_state;
388 }
389 }
390 }
391 mutex_unlock(&service_list_lock);
392 mutex_unlock(&notif_add_lock);
393}
394
395static void root_service_service_exit(struct qmi_client_info *data,
396 enum pd_subsys_state state)
397{
398 struct service_notif_info *service_notif = NULL;
399 int rc;
400
401 /*
402 * Send service down notifications to all clients
403 * of registered for notifications for that service.
404 */
405 mutex_lock(&notif_add_lock);
406 mutex_lock(&service_list_lock);
407 list_for_each_entry(service_notif, &service_list, list) {
408 if (service_notif->instance_id == data->instance_id) {
409 rc = service_notif_queue_notification(service_notif,
410 SERVREG_NOTIF_SERVICE_STATE_DOWN_V01,
411 &state);
412 if (rc & NOTIFY_STOP_MASK)
413 pr_err("Notifier callback aborted for %s with error %d\n",
414 service_notif->service_path, rc);
415 service_notif->curr_state =
416 SERVREG_NOTIF_SERVICE_STATE_DOWN_V01;
417 }
418 }
419 mutex_unlock(&service_list_lock);
420 mutex_unlock(&notif_add_lock);
421
422 /*
423 * Destroy client handle and try connecting when
424 * service comes up again.
425 */
426 mutex_lock(&qmi_client_release_lock);
427 data->service_connected = false;
428 qmi_handle_destroy(data->clnt_handle);
429 data->clnt_handle = NULL;
430 mutex_unlock(&qmi_client_release_lock);
431}
432
433static void root_service_exit_work(struct work_struct *work)
434{
435 struct qmi_client_info *data = container_of(work,
436 struct qmi_client_info, svc_exit);
437 root_service_service_exit(data, UNKNOWN);
438}
439
440static int service_event_notify(struct notifier_block *this,
441 unsigned long code,
442 void *_cmd)
443{
444 struct qmi_client_info *data = container_of(this,
445 struct qmi_client_info, notifier);
446
447 switch (code) {
448 case QMI_SERVER_ARRIVE:
449 pr_debug("Root PD service UP\n");
450 queue_work(data->svc_event_wq, &data->svc_arrive);
451 break;
452 case QMI_SERVER_EXIT:
453 pr_debug("Root PD service DOWN\n");
454 queue_work(data->svc_event_wq, &data->svc_exit);
455 break;
456 default:
457 break;
458 }
459 return 0;
460}
461
462static int ssr_event_notify(struct notifier_block *this,
463 unsigned long code,
464 void *data)
465{
466 struct qmi_client_info *info = container_of(this,
467 struct qmi_client_info, ssr_notifier);
468 struct notif_data *notif = data;
469
470 switch (code) {
471 case SUBSYS_BEFORE_SHUTDOWN:
472 pr_debug("Root PD DOWN(SSR notification), crashed?%d\n",
473 notif->crashed);
474 if (notif->crashed)
475 root_service_service_exit(info, CRASHED);
476 else
477 root_service_service_exit(info, SHUTDOWN);
478 break;
479 default:
480 break;
481 }
482 return NOTIFY_DONE;
483}
484
485static void *add_service_notif(const char *service_path, int instance_id,
486 int *curr_state)
487{
488 struct service_notif_info *service_notif;
489 struct qmi_client_info *tmp, *qmi_data;
490 long int rc;
491 char subsys[SERVREG_NOTIF_NAME_LENGTH];
492
493 rc = find_subsys(service_path, subsys);
494 if (rc < 0) {
495 pr_err("Could not find subsys for %s\n", service_path);
496 return ERR_PTR(rc);
497 }
498
499 service_notif = kzalloc(sizeof(struct service_notif_info), GFP_KERNEL);
500 if (!service_notif)
501 return ERR_PTR(-ENOMEM);
502
503 strlcpy(service_notif->service_path, service_path,
504 ARRAY_SIZE(service_notif->service_path));
505 service_notif->instance_id = instance_id;
506
507 /* If we already have a connection to the root PD on which the remote
508 * service we are interested in notifications about runs, then use
509 * the existing QMI connection.
510 */
511 mutex_lock(&qmi_list_lock);
512 list_for_each_entry(tmp, &qmi_client_list, list) {
513 if (tmp->instance_id == instance_id) {
514 if (tmp->service_connected) {
515 rc = register_notif_listener(service_notif, tmp,
516 curr_state);
517 if (rc) {
518 mutex_unlock(&qmi_list_lock);
519 pr_err("Register notifier failed: %s",
520 service_path);
521 kfree(service_notif);
522 return ERR_PTR(rc);
523 }
524 service_notif->curr_state = *curr_state;
525 }
526 mutex_unlock(&qmi_list_lock);
527 goto add_service_list;
528 }
529 }
530 mutex_unlock(&qmi_list_lock);
531
532 qmi_data = kzalloc(sizeof(struct qmi_client_info), GFP_KERNEL);
533 if (!qmi_data) {
534 kfree(service_notif);
535 return ERR_PTR(-ENOMEM);
536 }
537
538 qmi_data->instance_id = instance_id;
539 qmi_data->clnt_handle = NULL;
540 qmi_data->notifier.notifier_call = service_event_notify;
541
542 qmi_data->svc_event_wq = create_singlethread_workqueue(subsys);
543 if (!qmi_data->svc_event_wq) {
544 rc = -ENOMEM;
545 goto exit;
546 }
547
548 INIT_WORK(&qmi_data->svc_arrive, root_service_service_arrive);
549 INIT_WORK(&qmi_data->svc_exit, root_service_exit_work);
550 INIT_WORK(&qmi_data->svc_rcv_msg, root_service_clnt_recv_msg);
551 INIT_WORK(&qmi_data->ind_ack, send_ind_ack);
552
553 *curr_state = service_notif->curr_state =
554 SERVREG_NOTIF_SERVICE_STATE_UNINIT_V01;
555
556 rc = qmi_svc_event_notifier_register(SERVREG_NOTIF_SERVICE_ID,
557 SERVREG_NOTIF_SERVICE_VERS, qmi_data->instance_id,
558 &qmi_data->notifier);
559 if (rc < 0) {
560 pr_err("Notifier register failed (instance-id: %d)\n",
561 qmi_data->instance_id);
562 goto exit;
563 }
564 qmi_data->ssr_notifier.notifier_call = ssr_event_notify;
565 qmi_data->ssr_handle = subsys_notif_register_notifier(subsys,
566 &qmi_data->ssr_notifier);
567 if (IS_ERR(qmi_data->ssr_handle)) {
568 pr_err("SSR notif register for %s failed(instance-id: %d)\n",
569 subsys, qmi_data->instance_id);
570 rc = PTR_ERR(qmi_data->ssr_handle);
571 goto exit;
572 }
573
574 mutex_lock(&qmi_list_lock);
575 INIT_LIST_HEAD(&qmi_data->list);
576 list_add_tail(&qmi_data->list, &qmi_client_list);
577 mutex_unlock(&qmi_list_lock);
578
579add_service_list:
580 srcu_init_notifier_head(&service_notif->service_notif_rcvr_list);
581
582 mutex_lock(&service_list_lock);
583 INIT_LIST_HEAD(&service_notif->list);
584 list_add_tail(&service_notif->list, &service_list);
585 mutex_unlock(&service_list_lock);
586
587 return service_notif;
588exit:
589 if (qmi_data->svc_event_wq)
590 destroy_workqueue(qmi_data->svc_event_wq);
591 kfree(qmi_data);
592 kfree(service_notif);
593 return ERR_PTR(rc);
594}
595
596static int send_pd_restart_req(const char *service_path,
597 struct qmi_client_info *data)
598{
599 struct qmi_servreg_notif_restart_pd_req_msg_v01 req;
600 struct qmi_servreg_notif_register_listener_resp_msg_v01
601 resp = { { 0, 0 } };
602 struct msg_desc req_desc, resp_desc;
603 int rc;
604
605 snprintf(req.service_name, ARRAY_SIZE(req.service_name), "%s",
606 service_path);
607
608 req_desc.msg_id = QMI_SERVREG_NOTIF_RESTART_PD_REQ_V01;
609 req_desc.max_msg_len =
610 QMI_SERVREG_NOTIF_RESTART_PD_REQ_MSG_V01_MAX_MSG_LEN;
611 req_desc.ei_array = qmi_servreg_notif_restart_pd_req_msg_v01_ei;
612
613 resp_desc.msg_id = QMI_SERVREG_NOTIF_RESTART_PD_RESP_V01;
614 resp_desc.max_msg_len =
615 QMI_SERVREG_NOTIF_RESTART_PD_RESP_MSG_V01_MAX_MSG_LEN;
616 resp_desc.ei_array = qmi_servreg_notif_restart_pd_resp_msg_v01_ei;
617
618 rc = qmi_send_req_wait(data->clnt_handle, &req_desc, &req,
619 sizeof(req), &resp_desc, &resp, sizeof(resp),
620 SERVER_TIMEOUT);
621 if (rc < 0) {
622 pr_err("%s: Message sending failed/server timeout, ret - %d\n",
623 service_path, rc);
624 return rc;
625 }
626
627 /* Check the response */
628 if (QMI_RESP_BIT_SHIFT(resp.resp.result) != QMI_RESULT_SUCCESS_V01) {
629 pr_err("QMI request for PD restart failed 0x%x\n",
630 QMI_RESP_BIT_SHIFT(resp.resp.error));
631 return -EREMOTEIO;
632 }
633
634 return rc;
635
636}
637
638/* service_notif_pd_restart() - Request PD restart
639 * @service_path: Individual service identifier path for which restart is
640 * being requested.
641 * @instance_id: Instance id specific to a subsystem.
642 *
643 * @return: >=0 on success, standard Linux error codes on failure.
644 */
645int service_notif_pd_restart(const char *service_path, int instance_id)
646{
647 struct qmi_client_info *tmp;
648 int rc = 0;
649
650 list_for_each_entry(tmp, &qmi_client_list, list) {
651 if (tmp->instance_id == instance_id) {
652 if (tmp->service_connected) {
653 pr_info("Restarting service %s, instance-id %d\n",
654 service_path, instance_id);
655 rc = send_pd_restart_req(service_path, tmp);
656 } else
657 pr_info("Service %s is not connected\n",
658 service_path);
659 }
660 }
661 return rc;
662}
663EXPORT_SYMBOL(service_notif_pd_restart);
664
665/* service_notif_register_notifier() - Register a notifier for a service
666 * On success, it returns back a handle. It takes the following arguments:
667 * service_path: Individual service identifier path for which a client
668 * registers for notifications.
669 * instance_id: Instance id specific to a subsystem.
670 * current_state: Current state of service returned by the registration
671 * process.
672 * notifier block: notifier callback for service events.
673 */
674void *service_notif_register_notifier(const char *service_path, int instance_id,
675 struct notifier_block *nb, int *curr_state)
676{
677 struct service_notif_info *service_notif;
678 int ret = 0;
679
680 if (!service_path || !instance_id || !nb)
681 return ERR_PTR(-EINVAL);
682
683 mutex_lock(&notif_add_lock);
684 service_notif = _find_service_info(service_path);
685 if (!service_notif) {
686 service_notif = (struct service_notif_info *)add_service_notif(
687 service_path,
688 instance_id,
689 curr_state);
690 if (IS_ERR(service_notif))
691 goto exit;
692 }
693
694 ret = srcu_notifier_chain_register(
695 &service_notif->service_notif_rcvr_list, nb);
696 *curr_state = service_notif->curr_state;
697 if (ret < 0)
698 service_notif = ERR_PTR(ret);
699exit:
700 mutex_unlock(&notif_add_lock);
701 return service_notif;
702}
703EXPORT_SYMBOL(service_notif_register_notifier);
704
705/* service_notif_unregister_notifier() - Unregister a notifier for a service.
706 * service_notif_handle - The notifier handler that was provided by the
707 * service_notif_register_notifier function when the
708 * client registered for notifications.
709 * nb - The notifier block that was previously used during the registration.
710 */
711int service_notif_unregister_notifier(void *service_notif_handle,
712 struct notifier_block *nb)
713{
714 struct service_notif_info *service_notif;
715
716 if (!service_notif_handle || !nb)
717 return -EINVAL;
718
719 service_notif = (struct service_notif_info *)service_notif_handle;
720 if (service_notif < 0)
721 return -EINVAL;
722
723 return srcu_notifier_chain_unregister(
724 &service_notif->service_notif_rcvr_list, nb);
725}
726EXPORT_SYMBOL(service_notif_unregister_notifier);
727
728struct service_notifier_test_data {
729 char service_path[MAX_STRING_LEN];
730 int instance_id;
731 struct notifier_block nb;
732 void *service_notif_handle;
733};
734
735static struct service_notifier_test_data test_data;
736
737static void print_service_provider_state(int notification, char *type)
738{
739 if (notification == SERVREG_NOTIF_SERVICE_STATE_DOWN_V01)
740 pr_info("%s: Service %s down!\n", type, test_data.service_path);
741 else if (notification == SERVREG_NOTIF_SERVICE_STATE_UP_V01)
742 pr_info("%s: Service %s up!\n", type, test_data.service_path);
743 else if (notification == SERVREG_NOTIF_SERVICE_STATE_UNINIT_V01)
744 pr_info("%s: Service %s state uninit!\n", type,
745 test_data.service_path);
746 else
747 pr_info("%s: Service %s state Unknown 0x%x!\n", type,
748 test_data.service_path, notification);
749}
750
751static int nb_callback(struct notifier_block *nb,
752 unsigned long notification,
753 void *data)
754{
755 print_service_provider_state((int)notification, "Notification:");
756 return 0;
757}
758
759static ssize_t show_service_path(struct seq_file *f, void *unused)
760{
761 if (test_data.service_notif_handle)
762 seq_printf(f, "Service Path: %s\n", test_data.service_path);
763 else
764 seq_puts(f, "No existing notifier\n");
765 return 0;
766}
767
768
769static ssize_t set_service_notifier_register(struct file *fp,
770 const char __user *buf,
771 size_t count, loff_t *ppos)
772{
773 int curr_state = INT_MAX, rc;
774
775 if (!buf)
776 return -EIO;
777 if (test_data.service_notif_handle) {
778 service_notif_unregister_notifier(
779 test_data.service_notif_handle,
780 &test_data.nb);
781 test_data.service_notif_handle = NULL;
782 pr_info("Unregistering existing notifier for %s\n",
783 test_data.service_path);
784 }
785 rc = simple_write_to_buffer(test_data.service_path, MAX_STRING_LEN,
786 ppos, buf, count - 1);
787 if (rc != count - 1) {
788 pr_err("Unable to read data into kernel buffer\n");
789 goto err;
790 }
791 test_data.nb.notifier_call = nb_callback;
792 test_data.service_notif_handle = service_notif_register_notifier(
793 test_data.service_path,
794 test_data.instance_id, &test_data.nb,
795 &curr_state);
796 if (!IS_ERR(test_data.service_notif_handle)) {
797 pr_info("Notifier Registered for service %s\n",
798 test_data.service_path);
799 print_service_provider_state(curr_state, "Initial State");
800 return count;
801 }
802err:
803 test_data.service_notif_handle = NULL;
804 pr_err("Unable to register notifier for %s\n", test_data.service_path);
805 return -EIO;
806}
807
808static int open_service_notifier_register(struct inode *inode, struct file *f)
809{
810 return single_open(f, (void *) show_service_path,
811 inode->i_private);
812}
813
814static const struct file_operations service_notifier_register_fops = {
815 .open = open_service_notifier_register,
816 .read = seq_read,
817 .write = set_service_notifier_register,
818 .llseek = seq_lseek,
819 .release = seq_release,
820};
821
822static ssize_t show_service_notifier_id(struct seq_file *f, void *unused)
823{
824 seq_printf(f, "Service instance ID: %d\n", test_data.instance_id);
825 return 0;
826}
827
828static ssize_t set_service_notifier_id(struct file *fp,
829 const char __user *buf,
830 size_t count, loff_t *unused)
831{
832 int val, rc;
833 char kbuf[MAX_STRING_LEN];
834
835 if (count > MAX_STRING_LEN) {
836 rc = -EIO;
837 goto err;
838 }
839 rc = copy_from_user(kbuf, buf, count);
840 if (rc != 0) {
841 rc = -EFAULT;
842 goto err;
843 }
844
845 kbuf[count - 1] = '\0';
846 rc = kstrtoint(kbuf, 0, &val);
847 if (rc < 0)
848 goto err;
849
850 test_data.instance_id = val;
851 return count;
852err:
853 pr_err("Invalid input parameters: rc = %d\n", rc);
854 return rc;
855}
856
857static int open_service_notifier_id(struct inode *inode, struct file *f)
858{
859 return single_open(f, (void *) show_service_notifier_id,
860 inode->i_private);
861}
862
863static const struct file_operations service_notifier_id_fops = {
864 .open = open_service_notifier_id,
865 .read = seq_read,
866 .write = set_service_notifier_id,
867 .llseek = seq_lseek,
868 .release = seq_release,
869};
870
871static struct dentry *service_notifier_dir;
872static struct dentry *service_path_file;
873static struct dentry *service_id_file;
874
875static int __init service_notifier_init(void)
876{
877 service_notifier_dir = debugfs_create_dir("service_notifier", NULL);
878 if (service_notifier_dir) {
879 service_path_file = debugfs_create_file("service_path",
880 0644, service_notifier_dir, NULL,
881 &service_notifier_register_fops);
882 if (!service_path_file)
883 goto err;
884 service_id_file = debugfs_create_file("service_id",
885 0644, service_notifier_dir, NULL,
886 &service_notifier_id_fops);
887 if (!service_id_file)
888 goto err;
889 }
890 return 0;
891err:
892 debugfs_remove_recursive(service_notifier_dir);
893 return 0;
894}
895
896static void __exit service_notifier_exit(void)
897{
898 debugfs_remove_recursive(service_notifier_dir);
899 test_data.nb.notifier_call = nb_callback;
900}
901module_init(service_notifier_init);
902module_exit(service_notifier_exit);