[RAMEN9610-20413][9610] wlbt: SCSC Driver version 10.6.1.0
[GitHub/MotorolaMobilityLLC/kernel-slsi.git] / drivers / misc / samsung / scsc / scsc_service.c
1 /****************************************************************************
2 *
3 * Copyright (c) 2014 - 2018 Samsung Electronics Co., Ltd. All rights reserved
4 *
5 ****************************************************************************/
6
7 #include <linux/slab.h>
8 #include <linux/module.h>
9 #include <linux/version.h>
10 #include <linux/firmware.h>
11 #ifdef CONFIG_ANDROID
12 #include <linux/wakelock.h>
13 #endif
14 #include <scsc/scsc_mx.h>
15 #include <scsc/scsc_logring.h>
16
17 #include "mxman.h"
18 #include "scsc_mx_impl.h"
19 #include "mifintrbit.h"
20 #include "miframman.h"
21 #include "mifmboxman.h"
22 #ifdef CONFIG_SCSC_SMAPPER
23 #include "mifsmapper.h"
24 #endif
25 #ifdef CONFIG_SCSC_QOS
26 #include "mifqos.h"
27 #endif
28 #include "mxlogger.h"
29 #include "srvman.h"
30 #include "servman_messages.h"
31 #include "mxmgmt_transport.h"
32
33 static ulong sm_completion_timeout_ms = 1000;
34 module_param(sm_completion_timeout_ms, ulong, S_IRUGO | S_IWUSR);
35 MODULE_PARM_DESC(sm_completion_timeout_ms, "Timeout Service Manager start/stop (ms) - default 1000. 0 = infinite");
36
37 #define SCSC_MIFRAM_INVALID_REF -1
38 #define SCSC_MX_SERVICE_RECOVERY_TIMEOUT 20000 /* 20 seconds */
39
40 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
41 #define reinit_completion(completion) INIT_COMPLETION(*(completion))
42 #endif
43
44 struct scsc_service {
45 struct list_head list;
46 struct scsc_mx *mx;
47 enum scsc_service_id id;
48 struct scsc_service_client *client;
49 struct completion sm_msg_start_completion;
50 struct completion sm_msg_stop_completion;
51 };
52
53 /* true if a service is part of a sub-system that is reported by system error */
54 #define SERVICE_IN_SUBSYSTEM(service, subsys) \
55 (((subsys == SYSERR_SUBSYS_WLAN) && (service == SCSC_SERVICE_ID_WLAN)) || \
56 ((subsys == SYSERR_SUBSYS_BT) && ((service == SCSC_SERVICE_ID_BT) || (service == SCSC_SERVICE_ID_ANT))))
57
58 void srvman_init(struct srvman *srvman, struct scsc_mx *mx)
59 {
60 SCSC_TAG_INFO(MXMAN, "\n");
61 srvman->mx = mx;
62 INIT_LIST_HEAD(&srvman->service_list);
63 mutex_init(&srvman->service_list_mutex);
64 mutex_init(&srvman->api_access_mutex);
65
66 #ifdef CONFIG_ANDROID
67 wake_lock_init(&srvman->sm_wake_lock, WAKE_LOCK_SUSPEND, "srvman_wakelock");
68 #endif
69 }
70
71 void srvman_deinit(struct srvman *srvman)
72 {
73 struct scsc_service *service, *next;
74
75 SCSC_TAG_INFO(MXMAN, "\n");
76 list_for_each_entry_safe(service, next, &srvman->service_list, list) {
77 list_del(&service->list);
78 kfree(service);
79 }
80 mutex_destroy(&srvman->api_access_mutex);
81 mutex_destroy(&srvman->service_list_mutex);
82
83 #ifdef CONFIG_ANDROID
84 wake_lock_destroy(&srvman->sm_wake_lock);
85 #endif
86 }
87
88 void srvman_set_error(struct srvman *srvman)
89 {
90 struct scsc_service *service;
91
92 SCSC_TAG_INFO(MXMAN, "\n");
93 srvman->error = true;
94 mutex_lock(&srvman->service_list_mutex);
95 list_for_each_entry(service, &srvman->service_list, list) {
96 complete(&service->sm_msg_start_completion);
97 complete(&service->sm_msg_stop_completion);
98 }
99 mutex_unlock(&srvman->service_list_mutex);
100 }
101
102 void srvman_clear_error(struct srvman *srvman)
103 {
104 SCSC_TAG_INFO(MXMAN, "\n");
105 srvman->error = false;
106 }
107
108 static int wait_for_sm_msg_start_cfm(struct scsc_service *service)
109 {
110 int r;
111
112 if (0 == sm_completion_timeout_ms) {
113 /* Zero implies infinite wait, for development use only.
114 * r = -ERESTARTSYS if interrupted (e.g. Ctrl-C), 0 if completed
115 */
116 r = wait_for_completion_interruptible(&service->sm_msg_start_completion);
117 if (r == -ERESTARTSYS) {
118 /* Paranoid sink of any pending event skipped by the interrupted wait */
119 r = wait_for_completion_timeout(&service->sm_msg_start_completion, HZ / 2);
120 if (r == 0) {
121 SCSC_TAG_ERR(MXMAN, "timed out\n");
122 return -ETIMEDOUT;
123 }
124 }
125 return r;
126 }
127 r = wait_for_completion_timeout(&service->sm_msg_start_completion, msecs_to_jiffies(sm_completion_timeout_ms));
128 if (r == 0) {
129 SCSC_TAG_ERR(MXMAN, "timeout\n");
130 return -ETIMEDOUT;
131 }
132 return 0;
133 }
134
135 static int wait_for_sm_msg_stop_cfm(struct scsc_service *service)
136 {
137 int r;
138
139 if (0 == sm_completion_timeout_ms) {
140 /* Zero implies infinite wait, for development use only.
141 * r = -ERESTARTSYS if interrupted (e.g. Ctrl-C), 0 if completed
142 */
143 r = wait_for_completion_interruptible(&service->sm_msg_stop_completion);
144 if (r == -ERESTARTSYS) {
145 /* Paranoid sink of any pending event skipped by the interrupted wait */
146 r = wait_for_completion_timeout(&service->sm_msg_stop_completion, HZ / 2);
147 if (r == 0) {
148 SCSC_TAG_ERR(MXMAN, "timed out\n");
149 return -ETIMEDOUT;
150 }
151 }
152 return r;
153 }
154 r = wait_for_completion_timeout(&service->sm_msg_stop_completion, msecs_to_jiffies(sm_completion_timeout_ms));
155 if (r == 0) {
156 SCSC_TAG_ERR(MXMAN, "timeout\n");
157 return -ETIMEDOUT;
158 }
159 return 0;
160 }
161
162 static int send_sm_msg_start_blocking(struct scsc_service *service, scsc_mifram_ref ref)
163 {
164 struct scsc_mx *mx = service->mx;
165 struct mxmgmt_transport *mxmgmt_transport = scsc_mx_get_mxmgmt_transport(mx);
166 int r;
167 struct sm_msg_packet message = { .service_id = service->id,
168 .msg = SM_MSG_START_REQ,
169 .optional_data = ref };
170
171 reinit_completion(&service->sm_msg_start_completion);
172
173 /* Send to FW in MM stream */
174 mxmgmt_transport_send(mxmgmt_transport, MMTRANS_CHAN_ID_SERVICE_MANAGEMENT, &message, sizeof(message));
175 r = wait_for_sm_msg_start_cfm(service);
176 if (r) {
177 SCSC_TAG_ERR(MXMAN, "wait_for_sm_msg_start_cfm() failed: r=%d\n", r);
178
179 /* Report the error in order to get a moredump. Avoid auto-recovering this type of failure */
180 if (mxman_recovery_disabled())
181 scsc_mx_service_service_failed(service, "SM_MSG_START_CFM timeout");
182 }
183 return r;
184 }
185
186 static int send_sm_msg_stop_blocking(struct scsc_service *service)
187 {
188 struct scsc_mx *mx = service->mx;
189 struct mxman *mxman = scsc_mx_get_mxman(mx);
190 struct mxmgmt_transport *mxmgmt_transport = scsc_mx_get_mxmgmt_transport(mx);
191 int r;
192 struct sm_msg_packet message = { .service_id = service->id,
193 .msg = SM_MSG_STOP_REQ,
194 .optional_data = 0 };
195
196 if (mxman->mxman_state == MXMAN_STATE_FAILED)
197 return 0;
198
199 reinit_completion(&service->sm_msg_stop_completion);
200
201 /* Send to FW in MM stream */
202 mxmgmt_transport_send(mxmgmt_transport, MMTRANS_CHAN_ID_SERVICE_MANAGEMENT, &message, sizeof(message));
203 r = wait_for_sm_msg_stop_cfm(service);
204 if (r)
205 SCSC_TAG_ERR(MXMAN, "wait_for_sm_msg_stop_cfm() for service=%p service->id=%d failed: r=%d\n", service, service->id, r);
206 return r;
207 }
208
209 /*
210 * Receive handler for messages from the FW along the maxwell management transport
211 */
212 static void srv_message_handler(const void *message, void *data)
213 {
214 struct srvman *srvman = (struct srvman *)data;
215 struct scsc_service *service;
216 const struct sm_msg_packet *msg = message;
217 bool found = false;
218
219 mutex_lock(&srvman->service_list_mutex);
220 list_for_each_entry(service, &srvman->service_list, list) {
221 if (service->id == msg->service_id) {
222 found = true;
223 break;
224 }
225 }
226 if (!found) {
227 SCSC_TAG_ERR(MXMAN, "No service for msg->service_id=%d", msg->service_id);
228 mutex_unlock(&srvman->service_list_mutex);
229 return;
230 }
231 /* Forward the message to the applicable service to deal with */
232 switch (msg->msg) {
233 case SM_MSG_START_CFM:
234 SCSC_TAG_INFO(MXMAN, "Received SM_MSG_START_CFM message service=%p with service_id=%d from the firmware\n",
235 service, msg->service_id);
236 complete(&service->sm_msg_start_completion);
237 break;
238 case SM_MSG_STOP_CFM:
239 SCSC_TAG_INFO(MXMAN, "Received SM_MSG_STOP_CFM message for service=%p with service_id=%d from the firmware\n",
240 service, msg->service_id);
241 complete(&service->sm_msg_stop_completion);
242 break;
243 default:
244 /* HERE: Unknown message, raise fault */
245 SCSC_TAG_WARNING(MXMAN, "Received unknown message for service=%p with service_id=%d from the firmware: msg->msg=%d\n",
246 service, msg->msg, msg->service_id);
247 break;
248 }
249 mutex_unlock(&srvman->service_list_mutex);
250 }
251
252 int scsc_mx_service_start(struct scsc_service *service, scsc_mifram_ref ref)
253 {
254 struct scsc_mx *mx = service->mx;
255 struct srvman *srvman = scsc_mx_get_srvman(mx);
256 struct mxman *mxman = scsc_mx_get_mxman(service->mx);
257 int r;
258 struct timeval tval = {};
259
260 SCSC_TAG_INFO(MXMAN, "%d\n", service->id);
261 #ifdef CONFIG_SCSC_CHV_SUPPORT
262 if (chv_run)
263 return 0;
264 #endif
265 mutex_lock(&srvman->api_access_mutex);
266 #ifdef CONFIG_ANDROID
267 wake_lock(&srvman->sm_wake_lock);
268 #endif
269 if (srvman->error) {
270 tval = ns_to_timeval(mxman->last_panic_time);
271 SCSC_TAG_ERR(MXMAN, "error: refused due to previous f/w failure scsc_panic_code=0x%x happened at [%6lu.%06ld]\n",
272 mxman->scsc_panic_code, tval.tv_sec, tval.tv_usec);
273
274 /* Print the last panic record to help track ancient failures */
275 mxman_show_last_panic(mxman);
276
277 #ifdef CONFIG_ANDROID
278 wake_unlock(&srvman->sm_wake_lock);
279 #endif
280 mutex_unlock(&srvman->api_access_mutex);
281 return -EILSEQ;
282 }
283
284 r = send_sm_msg_start_blocking(service, ref);
285 if (r) {
286 SCSC_TAG_ERR(MXMAN, "send_sm_msg_start_blocking() failed: r=%d\n", r);
287 #ifdef CONFIG_ANDROID
288 wake_unlock(&srvman->sm_wake_lock);
289 #endif
290 mutex_unlock(&srvman->api_access_mutex);
291 return r;
292 }
293
294 #ifdef CONFIG_ANDROID
295 wake_unlock(&srvman->sm_wake_lock);
296 #endif
297 mutex_unlock(&srvman->api_access_mutex);
298 return 0;
299 }
300 EXPORT_SYMBOL(scsc_mx_service_start);
301
302 int scsc_mx_list_services(struct mxman *mxman_p, char *buf, const size_t bufsz)
303 {
304 struct scsc_service *service, *next;
305 int pos = 0;
306 struct srvman *srvman_p = scsc_mx_get_srvman(mxman_p->mx);
307
308 list_for_each_entry_safe(service, next, &srvman_p->service_list, list) {
309 switch (service->id) {
310 case SCSC_SERVICE_ID_NULL:
311 pos += scnprintf(buf + pos, bufsz - pos, "%s\n", "null");
312 break;
313 case SCSC_SERVICE_ID_WLAN:
314 pos += scnprintf(buf + pos, bufsz - pos, "%s\n", "wlan");
315 break;
316 case SCSC_SERVICE_ID_BT:
317 pos += scnprintf(buf + pos, bufsz - pos, "%s\n", "bt");
318 break;
319 case SCSC_SERVICE_ID_ANT:
320 pos += scnprintf(buf + pos, bufsz - pos, "%s\n", "ant");
321 break;
322 case SCSC_SERVICE_ID_R4DBG:
323 pos += scnprintf(buf + pos, bufsz - pos, "%s\n", "r4dbg");
324 break;
325 case SCSC_SERVICE_ID_ECHO:
326 pos += scnprintf(buf + pos, bufsz - pos, "%s\n", "echo");
327 break;
328 case SCSC_SERVICE_ID_DBG_SAMPLER:
329 pos += scnprintf(buf + pos, bufsz - pos, "%s\n", "dbg sampler");
330 break;
331 case SCSC_SERVICE_ID_CLK20MHZ:
332 pos += scnprintf(buf + pos, bufsz - pos, "%s\n", "clk20mhz");
333 break;
334 case SCSC_SERVICE_ID_FM:
335 pos += scnprintf(buf + pos, bufsz - pos, "%s\n", "fm");
336 break;
337 case SCSC_SERVICE_ID_INVALID:
338 pos += scnprintf(buf + pos, bufsz - pos, "%s\n", "invalid");
339 break;
340 }
341 }
342 return pos;
343 }
344 EXPORT_SYMBOL(scsc_mx_list_services);
345
346 int scsc_mx_service_stop(struct scsc_service *service)
347 {
348 struct scsc_mx *mx = service->mx;
349 struct srvman *srvman = scsc_mx_get_srvman(mx);
350 struct mxman *mxman = scsc_mx_get_mxman(service->mx);
351 int r;
352 struct timeval tval = {};
353
354 SCSC_TAG_INFO(MXMAN, "%d\n", service->id);
355 #ifdef CONFIG_SCSC_CHV_SUPPORT
356 if (chv_run)
357 return 0;
358 #endif
359 mutex_lock(&srvman->api_access_mutex);
360 #ifdef CONFIG_ANDROID
361 wake_lock(&srvman->sm_wake_lock);
362 #endif
363 if (srvman->error) {
364 tval = ns_to_timeval(mxman->last_panic_time);
365 SCSC_TAG_ERR(MXMAN, "error: refused due to previous f/w failure scsc_panic_code=0x%x happened at [%6lu.%06ld]\n",
366 mxman->scsc_panic_code, tval.tv_sec, tval.tv_usec);
367
368 /* Print the last panic record to help track ancient failures */
369 mxman_show_last_panic(mxman);
370
371 #ifdef CONFIG_ANDROID
372 wake_unlock(&srvman->sm_wake_lock);
373 #endif
374 mutex_unlock(&srvman->api_access_mutex);
375
376 /* Return a special status to allow caller recovery logic to know
377 * that there will never be a recovery
378 */
379 if (mxman_recovery_disabled()) {
380 SCSC_TAG_ERR(MXMAN, "recovery disabled, return -EPERM (%d)\n", -EPERM);
381 return -EPERM; /* failed due to prior failure, recovery disabled */
382 } else {
383 return -EILSEQ; /* operation rejected due to prior failure */
384 }
385 }
386
387 r = send_sm_msg_stop_blocking(service);
388 if (r) {
389 SCSC_TAG_ERR(MXMAN, "send_sm_msg_stop_blocking() failed: r=%d\n", r);
390 #ifdef CONFIG_ANDROID
391 wake_unlock(&srvman->sm_wake_lock);
392 #endif
393 mutex_unlock(&srvman->api_access_mutex);
394 return -EIO; /* operation failed */
395 }
396
397 #ifdef CONFIG_ANDROID
398 wake_unlock(&srvman->sm_wake_lock);
399 #endif
400 mutex_unlock(&srvman->api_access_mutex);
401 return 0;
402 }
403 EXPORT_SYMBOL(scsc_mx_service_stop);
404
405
406 /* Returns 0 if Suspend succeeded, otherwise return error */
407 int srvman_suspend_services(struct srvman *srvman)
408 {
409 int ret = 0;
410 struct scsc_service *service;
411
412 SCSC_TAG_INFO(MXMAN, "\n");
413 mutex_lock(&srvman->service_list_mutex);
414 list_for_each_entry(service, &srvman->service_list, list) {
415 if (service->client->suspend) {
416 ret = service->client->suspend(service->client);
417 /* If any service returns error message and call resume callbacks */
418 if (ret) {
419 list_for_each_entry(service, &srvman->service_list, list) {
420 if (service->client->resume)
421 service->client->resume(service->client);
422 }
423 SCSC_TAG_INFO(MXMAN, "Service client suspend failure ret: %d\n", ret);
424 mutex_unlock(&srvman->service_list_mutex);
425 return ret;
426 }
427 }
428 }
429
430 mutex_unlock(&srvman->service_list_mutex);
431 SCSC_TAG_INFO(MXMAN, "OK\n");
432 return 0;
433 }
434
435 /* Returns always 0. Extend API and return value if required */
436 int srvman_resume_services(struct srvman *srvman)
437 {
438 struct scsc_service *service;
439
440 SCSC_TAG_INFO(MXMAN, "\n");
441 mutex_lock(&srvman->service_list_mutex);
442 list_for_each_entry(service, &srvman->service_list, list) {
443 if (service->client->resume)
444 service->client->resume(service->client);
445 }
446
447 mutex_unlock(&srvman->service_list_mutex);
448 SCSC_TAG_INFO(MXMAN, "OK\n");
449
450 return 0;
451 }
452
453 void srvman_freeze_services(struct srvman *srvman, struct mx_syserr_decode *syserr)
454 {
455 struct scsc_service *service;
456 struct mxman *mxman = scsc_mx_get_mxman(srvman->mx);
457
458 SCSC_TAG_INFO(MXMAN, "\n");
459 mxman->notify = false;
460 mutex_lock(&srvman->service_list_mutex);
461 list_for_each_entry(service, &srvman->service_list, list) {
462 if (service->client->stop_on_failure) {
463 service->client->stop_on_failure(service->client);
464 mxman->notify = true;
465 } else if ((service->client->stop_on_failure_v2) &&
466 (service->client->stop_on_failure_v2(service->client, syserr)))
467 mxman->notify = true;
468 }
469
470 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
471 reinit_completion(&mxman->recovery_completion);
472 #else
473 INIT_COMPLETION(mxman->recovery_completion);
474 #endif
475 mutex_unlock(&srvman->service_list_mutex);
476 SCSC_TAG_INFO(MXMAN, "OK\n");
477 }
478
479 void srvman_freeze_sub_system(struct srvman *srvman, struct mx_syserr_decode *syserr)
480 {
481 struct scsc_service *service;
482 struct mxman *mxman = scsc_mx_get_mxman(srvman->mx);
483
484 SCSC_TAG_INFO(MXMAN, "\n");
485 mxman->notify = false;
486 mutex_lock(&srvman->service_list_mutex);
487 list_for_each_entry(service, &srvman->service_list, list) {
488 if ((SERVICE_IN_SUBSYSTEM(service->id, syserr->subsys) && (service->client->stop_on_failure_v2)))
489 if (service->client->stop_on_failure_v2(service->client, syserr))
490 mxman->notify = true;
491 }
492 mutex_unlock(&srvman->service_list_mutex);
493 SCSC_TAG_INFO(MXMAN, "OK\n");
494 }
495
496 void srvman_unfreeze_services(struct srvman *srvman, u16 scsc_panic_code)
497 {
498 struct scsc_service *service;
499 struct mxman *mxman = scsc_mx_get_mxman(srvman->mx);
500
501 SCSC_TAG_INFO(MXMAN, "\n");
502 mutex_lock(&srvman->service_list_mutex);
503 list_for_each_entry(service, &srvman->service_list, list) {
504 if (service->client->failure_reset)
505 service->client->failure_reset(service->client, scsc_panic_code);
506 else if (service->client->failure_reset_v2)
507 service->client->failure_reset_v2(service->client, MX_SYSERR_LEVEL_7,
508 mxman->notify ? scsc_panic_code : MX_NULL_SYSERR);
509 }
510 mutex_unlock(&srvman->service_list_mutex);
511 SCSC_TAG_INFO(MXMAN, "OK\n");
512 }
513
514 void srvman_unfreeze_sub_system(struct srvman *srvman, struct mx_syserr_decode *syserr)
515 {
516 struct scsc_service *service;
517 struct mxman *mxman = scsc_mx_get_mxman(srvman->mx);
518
519 SCSC_TAG_INFO(MXMAN, "\n");
520 mutex_lock(&srvman->service_list_mutex);
521 list_for_each_entry(service, &srvman->service_list, list) {
522 if ((SERVICE_IN_SUBSYSTEM(service->id, syserr->subsys) && (service->client->failure_reset_v2)))
523 service->client->failure_reset_v2(service->client, syserr->level,
524 mxman->notify ? syserr->subcode : MX_NULL_SYSERR);
525 }
526 mutex_unlock(&srvman->service_list_mutex);
527 SCSC_TAG_INFO(MXMAN, "OK\n");
528 }
529
530 u8 srvman_notify_sub_system(struct srvman *srvman, struct mx_syserr_decode *syserr)
531 {
532 struct scsc_service *service;
533 u8 initial_level = syserr->level;
534 u8 final_level = syserr->level;
535 bool wlan_active = false;
536 bool bt_active = false;
537 bool affected_service_found = false;
538
539 SCSC_TAG_INFO(MXMAN, "\n");
540 mutex_lock(&srvman->service_list_mutex);
541 list_for_each_entry(service, &srvman->service_list, list) {
542 if (SERVICE_IN_SUBSYSTEM(service->id, SYSERR_SUBSYS_WLAN))
543 wlan_active = true;
544 else if (SERVICE_IN_SUBSYSTEM(service->id, SYSERR_SUBSYS_BT))
545 bt_active = true;
546 if ((SERVICE_IN_SUBSYSTEM(service->id, syserr->subsys) && (service->client->failure_notification))) {
547 u8 level = service->client->failure_notification(service->client, syserr);
548
549 affected_service_found = true;
550 if (level > final_level)
551 final_level = level;
552 }
553 }
554 mutex_unlock(&srvman->service_list_mutex);
555
556 if (final_level == MX_SYSERR_LEVEL_7)
557 SCSC_TAG_INFO(MXMAN, "System error level %d raised to full reset", initial_level);
558 else if ((!(wlan_active && bt_active)) && (final_level >= MX_SYSERR_LEVEL_5)) {
559 final_level = MX_SYSERR_LEVEL_6; /* Still a sub-system reset even though we will do a full restart */
560 SCSC_TAG_INFO(MXMAN, "System error %d now level %d with 1 service active", initial_level, final_level);
561 }
562
563 SCSC_TAG_INFO(MXMAN, "OK\n");
564
565 /* Handle race condition with affected service being closed by demoting severity to stop any recovery
566 * should not be possible, but best be careful anyway
567 */
568 if ((!affected_service_found) && (final_level >= MX_SYSERR_LEVEL_5)) {
569 SCSC_TAG_INFO(MXMAN, "System error %d demoted to 4 as no services affected", final_level);
570 final_level = MX_SYSERR_LEVEL_4;
571 }
572
573 return final_level;
574 }
575
576
577 /** Signal a failure detected by the Client. This will trigger the systemwide
578 * failure handling procedure: _All_ Clients will be called back via
579 * their stop_on_failure() handler as a side-effect.
580 */
581 void scsc_mx_service_service_failed(struct scsc_service *service, const char *reason)
582 {
583 struct scsc_mx *mx = service->mx;
584 struct srvman *srvman = scsc_mx_get_srvman(mx);
585 u16 host_panic_code;
586
587 host_panic_code = (SCSC_PANIC_CODE_HOST << 15) | (service->id << SCSC_SYSERR_HOST_SERVICE_SHIFT);
588
589 srvman_set_error(srvman);
590 switch (service->id) {
591 case SCSC_SERVICE_ID_WLAN:
592 SCSC_TAG_INFO(MXMAN, "WLAN: %s\n", ((reason != NULL) ? reason : ""));
593 break;
594 case SCSC_SERVICE_ID_BT:
595 SCSC_TAG_INFO(MXMAN, "BT: %s\n", ((reason != NULL) ? reason : ""));
596 break;
597 default:
598 SCSC_TAG_INFO(MXMAN, "service id %d failed\n", service->id);
599 break;
600
601 }
602
603 SCSC_TAG_INFO(MXMAN, "Reporting host hang code 0x%02x\n", host_panic_code);
604
605 mxman_fail(scsc_mx_get_mxman(mx), host_panic_code, reason);
606 }
607 EXPORT_SYMBOL(scsc_mx_service_service_failed);
608
609
610 int scsc_mx_service_close(struct scsc_service *service)
611 {
612 struct mxman *mxman = scsc_mx_get_mxman(service->mx);
613 struct scsc_mx *mx = service->mx;
614 struct srvman *srvman = scsc_mx_get_srvman(mx);
615 bool empty;
616 struct timeval tval = {};
617
618 SCSC_TAG_INFO(MXMAN, "%d\n", service->id);
619
620 mutex_lock(&srvman->api_access_mutex);
621 #ifdef CONFIG_ANDROID
622 wake_lock(&srvman->sm_wake_lock);
623 #endif
624
625 /* TODO - Race conditions here unless we protect better
626 * code assumes srvman->error and mxman->state can't change, but they can
627 */
628 if (srvman->error) {
629 tval = ns_to_timeval(mxman->last_panic_time);
630 SCSC_TAG_ERR(MXMAN, "error: refused due to previous f/w failure scsc_panic_code=0x%x happened at [%6lu.%06ld]\n",
631 mxman->scsc_panic_code, tval.tv_sec, tval.tv_usec);
632
633 /* Print the last panic record to help track ancient failures */
634 mxman_show_last_panic(mxman);
635
636 mutex_unlock(&srvman->api_access_mutex);
637 #ifdef CONFIG_ANDROID
638 wake_unlock(&srvman->sm_wake_lock);
639 #endif
640
641 /* Return a special status when recovery is disabled, to allow
642 * calling recovery logic to be aware that recovery is disabled,
643 * hence not wait for recovery events.
644 */
645 if (mxman_recovery_disabled()) {
646 SCSC_TAG_ERR(MXMAN, "recovery disabled, return -EPERM (%d)\n", -EPERM);
647 return -EPERM; /* rejected due to prior failure, recovery disabled */
648 } else {
649 return -EIO;
650 }
651 }
652
653 /* remove the service from the list and deallocate the service memory */
654 mutex_lock(&srvman->service_list_mutex);
655 list_del(&service->list);
656 empty = list_empty(&srvman->service_list);
657 mutex_unlock(&srvman->service_list_mutex);
658 if (empty) {
659 /* unregister channel handler */
660 mxmgmt_transport_register_channel_handler(scsc_mx_get_mxmgmt_transport(mx), MMTRANS_CHAN_ID_SERVICE_MANAGEMENT,
661 NULL, NULL);
662 /* Clear any system error information */
663 mxman->syserr_recovery_in_progress = false;
664 mxman->last_syserr_recovery_time = 0;
665 } else if (mxman->syserr_recovery_in_progress) {
666 /* If we have syserr_recovery_in_progress and all the services we have asked to close are now closed,
667 * we can clear it now - don't wait for open as it may not come - do it now!
668 */
669 struct scsc_service *serv;
670 bool all_cleared = true;
671
672 mutex_lock(&srvman->service_list_mutex);
673 list_for_each_entry(serv, &srvman->service_list, list) {
674 if (SERVICE_IN_SUBSYSTEM(serv->id, mxman->last_syserr.subsys))
675 all_cleared = false;
676 }
677 mutex_unlock(&srvman->service_list_mutex);
678
679 if (all_cleared)
680 mxman->syserr_recovery_in_progress = false;
681 }
682
683 kfree(service);
684
685 mxman_close(mxman);
686 #ifdef CONFIG_ANDROID
687 wake_unlock(&srvman->sm_wake_lock);
688 #endif
689 mutex_unlock(&srvman->api_access_mutex);
690 return 0;
691 }
692 EXPORT_SYMBOL(scsc_mx_service_close);
693
694 /* Consider move to a public scsc_mx interface */
695 struct scsc_service *scsc_mx_service_open(struct scsc_mx *mx, enum scsc_service_id id, struct scsc_service_client *client, int *status)
696 {
697 int ret;
698 struct scsc_service *service;
699 struct srvman *srvman = scsc_mx_get_srvman(mx);
700 struct mxman *mxman = scsc_mx_get_mxman(mx);
701 bool empty;
702 struct timeval tval = {};
703
704 SCSC_TAG_INFO(MXMAN, "%d\n", id);
705
706 mutex_lock(&srvman->api_access_mutex);
707 #ifdef CONFIG_ANDROID
708 wake_lock(&srvman->sm_wake_lock);
709 #endif
710 /* TODO - need to close potential race conditions - see close */
711 /* Have to check for disabled here as there is a small window where error is asserted
712 * even if we are going to allow recovery later on - in these cases we will want to block
713 */
714 if ((srvman->error) && (mxman_recovery_disabled())) {
715 tval = ns_to_timeval(mxman->last_panic_time);
716 SCSC_TAG_ERR(MXMAN, "error: refused due to previous f/w failure scsc_panic_code=0x%x happened at [%6lu.%06ld]\n",
717 mxman->scsc_panic_code, tval.tv_sec, tval.tv_usec);
718 /* Print the last panic record to help track ancient failures */
719 mxman_show_last_panic(mxman);
720 #ifdef CONFIG_ANDROID
721 wake_unlock(&srvman->sm_wake_lock);
722 #endif
723 mutex_unlock(&srvman->api_access_mutex);
724 *status = -EILSEQ;
725 return NULL;
726 }
727
728 if (mxman->mxman_state == MXMAN_STATE_FAILED) {
729 int r;
730
731 mutex_unlock(&srvman->api_access_mutex);
732 r = wait_for_completion_timeout(&mxman->recovery_completion,
733 msecs_to_jiffies(SCSC_MX_SERVICE_RECOVERY_TIMEOUT));
734 if (r == 0) {
735 SCSC_TAG_ERR(MXMAN, "Recovery timeout\n");
736 #ifdef CONFIG_ANDROID
737 wake_unlock(&srvman->sm_wake_lock);
738 #endif
739 *status = -EIO;
740 return NULL;
741 }
742
743 mutex_lock(&srvman->api_access_mutex);
744 }
745
746 service = kmalloc(sizeof(struct scsc_service), GFP_KERNEL);
747 if (service) {
748 /* MaxwellManager Should allocate Mem and download FW */
749 ret = mxman_open(mxman);
750 if (ret) {
751 kfree(service);
752 #ifdef CONFIG_ANDROID
753 wake_unlock(&srvman->sm_wake_lock);
754 #endif
755 mutex_unlock(&srvman->api_access_mutex);
756 *status = ret;
757 return NULL;
758 }
759 /* Initialise service struct here */
760 service->mx = mx;
761 service->id = id;
762 service->client = client;
763 init_completion(&service->sm_msg_start_completion);
764 init_completion(&service->sm_msg_stop_completion);
765 mutex_lock(&srvman->service_list_mutex);
766 empty = list_empty(&srvman->service_list);
767 mutex_unlock(&srvman->service_list_mutex);
768 if (empty)
769 mxmgmt_transport_register_channel_handler(scsc_mx_get_mxmgmt_transport(mx), MMTRANS_CHAN_ID_SERVICE_MANAGEMENT,
770 &srv_message_handler, srvman);
771 mutex_lock(&srvman->service_list_mutex);
772 list_add_tail(&service->list, &srvman->service_list);
773 mutex_unlock(&srvman->service_list_mutex);
774 } else
775 *status = -ENOMEM;
776
777 #ifdef CONFIG_ANDROID
778 wake_unlock(&srvman->sm_wake_lock);
779 #endif
780 mutex_unlock(&srvman->api_access_mutex);
781
782 return service;
783 }
784 EXPORT_SYMBOL(scsc_mx_service_open);
785
786 struct scsc_bt_audio_abox *scsc_mx_service_get_bt_audio_abox(struct scsc_service *service)
787 {
788 struct scsc_mx *mx = service->mx;
789 struct mifabox *ptr;
790
791 ptr = scsc_mx_get_aboxram(mx);
792
793 return ptr->aboxram;
794 }
795
796 struct mifabox *scsc_mx_service_get_aboxram(struct scsc_service *service)
797 {
798 struct scsc_mx *mx = service->mx;
799 struct mifabox *ptr;
800
801 ptr = scsc_mx_get_aboxram(mx);
802
803 return ptr;
804 }
805
806 /**
807 * Allocate a contiguous block of SDRAM accessible to Client Driver
808 *
809 * When allocation fails, beside returning -ENOMEM, the IN-param 'ref'
810 * is cleared to an INVALID value that can be safely fed to the companion
811 * function scsc_mx_service_mifram_free().
812 */
813 int scsc_mx_service_mifram_alloc_extended(struct scsc_service *service, size_t nbytes, scsc_mifram_ref *ref, u32 align, uint32_t flags)
814 {
815 struct scsc_mx *mx = service->mx;
816 void *mem;
817 int ret;
818 struct miframman *ramman;
819
820 if (flags & MIFRAMMAN_MEM_POOL_GENERIC) {
821 ramman = scsc_mx_get_ramman(mx);
822 } else if (flags & MIFRAMMAN_MEM_POOL_LOGGING) {
823 ramman = scsc_mx_get_ramman2(mx);
824 } else {
825 SCSC_TAG_ERR(MXMAN, "Unsupported flags value: %d", flags);
826 *ref = SCSC_MIFRAM_INVALID_REF;
827 return -ENOMEM;
828 }
829
830 mem = miframman_alloc(ramman, nbytes, align, service->id);
831 if (!mem) {
832 SCSC_TAG_ERR(MXMAN, "miframman_alloc() failed\n");
833 *ref = SCSC_MIFRAM_INVALID_REF;
834 return -ENOMEM;
835 }
836
837 SCSC_TAG_DEBUG(MXMAN, "Allocated mem %p\n", mem);
838
839 /* Transform native pointer and get mifram_ref type */
840 ret = scsc_mx_service_mif_ptr_to_addr(service, mem, ref);
841 if (ret) {
842 SCSC_TAG_ERR(MXMAN, "scsc_mx_service_mif_ptr_to_addr() failed: ret=%d", ret);
843 miframman_free(ramman, mem);
844 *ref = SCSC_MIFRAM_INVALID_REF;
845 } else {
846 SCSC_TAG_DEBUG(MXMAN, "mem %p ref %d\n", mem, *ref);
847 }
848 return ret;
849 }
850 EXPORT_SYMBOL(scsc_mx_service_mifram_alloc_extended);
851
852 int scsc_mx_service_mifram_alloc(struct scsc_service *service, size_t nbytes, scsc_mifram_ref *ref, u32 align)
853 {
854 return scsc_mx_service_mifram_alloc_extended(service, nbytes, ref, align, MIFRAMMAN_MEM_POOL_GENERIC);
855 }
856 EXPORT_SYMBOL(scsc_mx_service_mifram_alloc);
857
858 /** Free a contiguous block of SDRAM */
859 void scsc_mx_service_mifram_free_extended(struct scsc_service *service, scsc_mifram_ref ref, uint32_t flags)
860 {
861 struct scsc_mx *mx = service->mx;
862 void *mem;
863 struct miframman *ramman;
864
865 if (flags & MIFRAMMAN_MEM_POOL_GENERIC) {
866 ramman = scsc_mx_get_ramman(mx);
867 } else if (flags & MIFRAMMAN_MEM_POOL_LOGGING) {
868 ramman = scsc_mx_get_ramman2(mx);
869 } else {
870 SCSC_TAG_ERR(MXMAN, "Unsupported flags value: %d", flags);
871 return;
872 }
873
874 mem = scsc_mx_service_mif_addr_to_ptr(service, ref);
875
876 SCSC_TAG_DEBUG(MXMAN, "**** Freeing %p\n", mem);
877
878 miframman_free(ramman, mem);
879 }
880 EXPORT_SYMBOL(scsc_mx_service_mifram_free_extended);
881
882 void scsc_mx_service_mifram_free(struct scsc_service *service, scsc_mifram_ref ref)
883 {
884 scsc_mx_service_mifram_free_extended(service, ref, MIFRAMMAN_MEM_POOL_GENERIC);
885 }
886 EXPORT_SYMBOL(scsc_mx_service_mifram_free);
887
888 /* MIF ALLOCATIONS */
889 bool scsc_mx_service_alloc_mboxes(struct scsc_service *service, int n, int *first_mbox_index)
890 {
891 struct scsc_mx *mx = service->mx;
892
893 return mifmboxman_alloc_mboxes(scsc_mx_get_mboxman(mx), n, first_mbox_index);
894 }
895 EXPORT_SYMBOL(scsc_mx_service_alloc_mboxes);
896
897 void scsc_service_free_mboxes(struct scsc_service *service, int n, int first_mbox_index)
898 {
899 struct scsc_mx *mx = service->mx;
900
901 return mifmboxman_free_mboxes(scsc_mx_get_mboxman(mx), first_mbox_index, n);
902 }
903 EXPORT_SYMBOL(scsc_service_free_mboxes);
904
905 u32 *scsc_mx_service_get_mbox_ptr(struct scsc_service *service, int mbox_index)
906 {
907 struct scsc_mx *mx = service->mx;
908 struct scsc_mif_abs *mif_abs;
909
910 mif_abs = scsc_mx_get_mif_abs(mx);
911
912 return mifmboxman_get_mbox_ptr(scsc_mx_get_mboxman(mx), mif_abs, mbox_index);
913 }
914 EXPORT_SYMBOL(scsc_mx_service_get_mbox_ptr);
915
916 int scsc_service_mifintrbit_bit_mask_status_get(struct scsc_service *service)
917 {
918 struct scsc_mx *mx = service->mx;
919 struct scsc_mif_abs *mif_abs;
920
921 mif_abs = scsc_mx_get_mif_abs(mx);
922
923 return mif_abs->irq_bit_mask_status_get(mif_abs);
924 }
925 EXPORT_SYMBOL(scsc_service_mifintrbit_bit_mask_status_get);
926
927 int scsc_service_mifintrbit_get(struct scsc_service *service)
928 {
929 struct scsc_mx *mx = service->mx;
930 struct scsc_mif_abs *mif_abs;
931
932 mif_abs = scsc_mx_get_mif_abs(mx);
933
934 return mif_abs->irq_get(mif_abs);
935 }
936 EXPORT_SYMBOL(scsc_service_mifintrbit_get);
937
938 void scsc_service_mifintrbit_bit_set(struct scsc_service *service, int which_bit, enum scsc_mifintr_target dir)
939 {
940 struct scsc_mx *mx = service->mx;
941 struct scsc_mif_abs *mif_abs;
942
943 mif_abs = scsc_mx_get_mif_abs(mx);
944
945 return mif_abs->irq_bit_set(mif_abs, which_bit, (enum scsc_mif_abs_target)dir);
946 }
947 EXPORT_SYMBOL(scsc_service_mifintrbit_bit_set);
948
949 void scsc_service_mifintrbit_bit_clear(struct scsc_service *service, int which_bit)
950 {
951 struct scsc_mx *mx = service->mx;
952 struct scsc_mif_abs *mif_abs;
953
954 mif_abs = scsc_mx_get_mif_abs(mx);
955
956 return mif_abs->irq_bit_clear(mif_abs, which_bit);
957 }
958 EXPORT_SYMBOL(scsc_service_mifintrbit_bit_clear);
959
960 void scsc_service_mifintrbit_bit_mask(struct scsc_service *service, int which_bit)
961 {
962 struct scsc_mx *mx = service->mx;
963 struct scsc_mif_abs *mif_abs;
964
965 mif_abs = scsc_mx_get_mif_abs(mx);
966
967 return mif_abs->irq_bit_mask(mif_abs, which_bit);
968 }
969 EXPORT_SYMBOL(scsc_service_mifintrbit_bit_mask);
970
971 void scsc_service_mifintrbit_bit_unmask(struct scsc_service *service, int which_bit)
972 {
973 struct scsc_mx *mx = service->mx;
974 struct scsc_mif_abs *mif_abs;
975
976 mif_abs = scsc_mx_get_mif_abs(mx);
977
978 return mif_abs->irq_bit_unmask(mif_abs, which_bit);
979 }
980 EXPORT_SYMBOL(scsc_service_mifintrbit_bit_unmask);
981
982 int scsc_service_mifintrbit_alloc_fromhost(struct scsc_service *service, enum scsc_mifintr_target dir)
983 {
984 struct scsc_mx *mx = service->mx;
985
986 return mifintrbit_alloc_fromhost(scsc_mx_get_intrbit(mx), (enum scsc_mif_abs_target)dir);
987 }
988 EXPORT_SYMBOL(scsc_service_mifintrbit_alloc_fromhost);
989
990 int scsc_service_mifintrbit_free_fromhost(struct scsc_service *service, int which_bit, enum scsc_mifintr_target dir)
991 {
992 struct scsc_mx *mx = service->mx;
993
994 return mifintrbit_free_fromhost(scsc_mx_get_intrbit(mx), which_bit, (enum scsc_mif_abs_target)dir);
995 }
996 EXPORT_SYMBOL(scsc_service_mifintrbit_free_fromhost);
997
998 int scsc_service_mifintrbit_register_tohost(struct scsc_service *service, void (*handler)(int irq, void *data), void *data)
999 {
1000 struct scsc_mx *mx = service->mx;
1001
1002 SCSC_TAG_DEBUG(MXMAN, "Registering %pS\n", handler);
1003
1004 return mifintrbit_alloc_tohost(scsc_mx_get_intrbit(mx), handler, data);
1005 }
1006 EXPORT_SYMBOL(scsc_service_mifintrbit_register_tohost);
1007
1008 int scsc_service_mifintrbit_unregister_tohost(struct scsc_service *service, int which_bit)
1009 {
1010 struct scsc_mx *mx = service->mx;
1011
1012 SCSC_TAG_DEBUG(MXMAN, "Deregistering int for bit %d\n", which_bit);
1013 return mifintrbit_free_tohost(scsc_mx_get_intrbit(mx), which_bit);
1014 }
1015 EXPORT_SYMBOL(scsc_service_mifintrbit_unregister_tohost);
1016
1017 void *scsc_mx_service_mif_addr_to_ptr(struct scsc_service *service, scsc_mifram_ref ref)
1018 {
1019 struct scsc_mx *mx = service->mx;
1020
1021 struct scsc_mif_abs *mif_abs;
1022
1023 mif_abs = scsc_mx_get_mif_abs(mx);
1024
1025 return mif_abs->get_mifram_ptr(mif_abs, ref);
1026 }
1027 EXPORT_SYMBOL(scsc_mx_service_mif_addr_to_ptr);
1028
1029 void *scsc_mx_service_mif_addr_to_phys(struct scsc_service *service, scsc_mifram_ref ref)
1030 {
1031 struct scsc_mx *mx = service->mx;
1032
1033 struct scsc_mif_abs *mif_abs;
1034
1035 mif_abs = scsc_mx_get_mif_abs(mx);
1036
1037 if (mif_abs->get_mifram_phy_ptr)
1038 return mif_abs->get_mifram_phy_ptr(mif_abs, ref);
1039 else
1040 return NULL;
1041 }
1042 EXPORT_SYMBOL(scsc_mx_service_mif_addr_to_phys);
1043
1044 int scsc_mx_service_mif_ptr_to_addr(struct scsc_service *service, void *mem_ptr, scsc_mifram_ref *ref)
1045 {
1046 struct scsc_mx *mx = service->mx;
1047 struct scsc_mif_abs *mif_abs;
1048
1049 mif_abs = scsc_mx_get_mif_abs(mx);
1050
1051 /* Transform native pointer and get mifram_ref type */
1052 if (mif_abs->get_mifram_ref(mif_abs, mem_ptr, ref)) {
1053 SCSC_TAG_ERR(MXMAN, "ooops somethig went wrong");
1054 return -ENOMEM;
1055 }
1056
1057 return 0;
1058 }
1059 EXPORT_SYMBOL(scsc_mx_service_mif_ptr_to_addr);
1060
1061 int scsc_mx_service_mif_dump_registers(struct scsc_service *service)
1062 {
1063 struct scsc_mx *mx = service->mx;
1064 struct scsc_mif_abs *mif_abs;
1065
1066 mif_abs = scsc_mx_get_mif_abs(mx);
1067
1068 /* Dump registers */
1069 mif_abs->mif_dump_registers(mif_abs);
1070
1071 return 0;
1072 }
1073 EXPORT_SYMBOL(scsc_mx_service_mif_dump_registers);
1074
1075 struct device *scsc_service_get_device(struct scsc_service *service)
1076 {
1077 return scsc_mx_get_device(service->mx);
1078 }
1079 EXPORT_SYMBOL(scsc_service_get_device);
1080
1081 struct device *scsc_service_get_device_by_mx(struct scsc_mx *mx)
1082 {
1083 return scsc_mx_get_device(mx);
1084 }
1085 EXPORT_SYMBOL(scsc_service_get_device_by_mx);
1086
1087 /* Force a FW panic for test purposes only */
1088 int scsc_service_force_panic(struct scsc_service *service)
1089 {
1090 struct mxman *mxman = scsc_mx_get_mxman(service->mx);
1091
1092 SCSC_TAG_INFO(MXMAN, "%d\n", service->id);
1093
1094 return mxman_force_panic(mxman);
1095 }
1096 EXPORT_SYMBOL(scsc_service_force_panic);
1097
1098 #ifdef CONFIG_SCSC_SMAPPER
1099 u16 scsc_service_get_alignment(struct scsc_service *service)
1100 {
1101 struct scsc_mx *mx = service->mx;
1102
1103 return mifsmapper_get_alignment(scsc_mx_get_smapper(mx));
1104 }
1105
1106 int scsc_service_mifsmapper_alloc_bank(struct scsc_service *service, bool large_bank, u32 entry_size, u16 *entries)
1107 {
1108 struct scsc_mx *mx = service->mx;
1109
1110 return mifsmapper_alloc_bank(scsc_mx_get_smapper(mx), large_bank, entry_size, entries);
1111 }
1112 EXPORT_SYMBOL(scsc_service_mifsmapper_alloc_bank);
1113
1114 void scsc_service_mifsmapper_configure(struct scsc_service *service, u32 granularity)
1115 {
1116 struct scsc_mx *mx = service->mx;
1117
1118 mifsmapper_configure(scsc_mx_get_smapper(mx), granularity);
1119 }
1120 EXPORT_SYMBOL(scsc_service_mifsmapper_configure);
1121
1122 int scsc_service_mifsmapper_write_sram(struct scsc_service *service, u8 bank, u8 num_entries, u8 first_entry, dma_addr_t *addr)
1123 {
1124 struct scsc_mx *mx = service->mx;
1125
1126 return mifsmapper_write_sram(scsc_mx_get_smapper(mx), bank, num_entries, first_entry, addr);
1127 }
1128 EXPORT_SYMBOL(scsc_service_mifsmapper_write_sram);
1129
1130 int scsc_service_mifsmapper_get_entries(struct scsc_service *service, u8 bank, u8 num_entries, u8 *entries)
1131 {
1132 struct scsc_mx *mx = service->mx;
1133
1134 return mifsmapper_get_entries(scsc_mx_get_smapper(mx), bank, num_entries, entries);
1135 }
1136 EXPORT_SYMBOL(scsc_service_mifsmapper_get_entries);
1137
1138 int scsc_service_mifsmapper_free_entries(struct scsc_service *service, u8 bank, u8 num_entries, u8 *entries)
1139 {
1140 struct scsc_mx *mx = service->mx;
1141
1142 return mifsmapper_free_entries(scsc_mx_get_smapper(mx), bank, num_entries, entries);
1143 }
1144 EXPORT_SYMBOL(scsc_service_mifsmapper_free_entries);
1145
1146 int scsc_service_mifsmapper_free_bank(struct scsc_service *service, u8 bank)
1147 {
1148 struct scsc_mx *mx = service->mx;
1149
1150 return mifsmapper_free_bank(scsc_mx_get_smapper(mx), bank);
1151 }
1152 EXPORT_SYMBOL(scsc_service_mifsmapper_free_bank);
1153
1154 u32 scsc_service_mifsmapper_get_bank_base_address(struct scsc_service *service, u8 bank)
1155 {
1156 struct scsc_mx *mx = service->mx;
1157
1158 return mifsmapper_get_bank_base_address(scsc_mx_get_smapper(mx), bank);
1159 }
1160 EXPORT_SYMBOL(scsc_service_mifsmapper_get_bank_base_address);
1161 #endif
1162
1163 #ifdef CONFIG_SCSC_QOS
1164 int scsc_service_pm_qos_add_request(struct scsc_service *service, enum scsc_qos_config config)
1165 {
1166 struct scsc_mx *mx = service->mx;
1167
1168 mifqos_add_request(scsc_mx_get_qos(mx), service->id, config);
1169
1170 return 0;
1171 }
1172 EXPORT_SYMBOL(scsc_service_pm_qos_add_request);
1173
1174 int scsc_service_pm_qos_update_request(struct scsc_service *service, enum scsc_qos_config config)
1175 {
1176 struct scsc_mx *mx = service->mx;
1177
1178 mifqos_update_request(scsc_mx_get_qos(mx), service->id, config);
1179
1180 return 0;
1181 }
1182 EXPORT_SYMBOL(scsc_service_pm_qos_update_request);
1183
1184 int scsc_service_pm_qos_remove_request(struct scsc_service *service)
1185 {
1186 struct scsc_mx *mx = service->mx;
1187
1188 if (!mx)
1189 return -EIO;
1190
1191 mifqos_remove_request(scsc_mx_get_qos(mx), service->id);
1192
1193 return 0;
1194 }
1195 EXPORT_SYMBOL(scsc_service_pm_qos_remove_request);
1196 #endif
1197 #ifdef CONFIG_SCSC_MXLOGGER
1198 /* If there is no service/mxman associated, register the observer as global (will affect all the mx instanes)*/
1199 /* Users of these functions should ensure that the registers/unregister functions are balanced (i.e. if observer is registed as global,
1200 * it _has_ to unregister as global) */
1201 int scsc_service_register_observer(struct scsc_service *service, char *name)
1202 {
1203 struct scsc_mx *mx;
1204
1205 if (!service)
1206 return mxlogger_register_global_observer(name);
1207
1208 mx = service->mx;
1209
1210 if (!mx)
1211 return -EIO;
1212
1213 return mxlogger_register_observer(scsc_mx_get_mxlogger(mx), name);
1214 }
1215 EXPORT_SYMBOL(scsc_service_register_observer);
1216
1217 /* If there is no service/mxman associated, unregister the observer as global (will affect all the mx instanes)*/
1218 int scsc_service_unregister_observer(struct scsc_service *service, char *name)
1219 {
1220 struct scsc_mx *mx;
1221
1222 if (!service)
1223 return mxlogger_unregister_global_observer(name);
1224
1225 mx = service->mx;
1226
1227 if (!mx)
1228 return -EIO;
1229
1230 return mxlogger_unregister_observer(scsc_mx_get_mxlogger(mx), name);
1231 }
1232 EXPORT_SYMBOL(scsc_service_unregister_observer);
1233 #endif