1 /****************************************************************************
3 * Copyright (c) 2014 - 2018 Samsung Electronics Co., Ltd. All rights reserved
5 ****************************************************************************/
7 #include <linux/slab.h>
8 #include <linux/module.h>
9 #include <linux/version.h>
10 #include <linux/firmware.h>
12 #include <linux/wakelock.h>
14 #include <scsc/scsc_mx.h>
15 #include <scsc/scsc_logring.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"
25 #ifdef CONFIG_SCSC_QOS
30 #include "servman_messages.h"
31 #include "mxmgmt_transport.h"
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");
37 #define SCSC_MIFRAM_INVALID_REF -1
38 #define SCSC_MX_SERVICE_RECOVERY_TIMEOUT 20000 /* 20 seconds */
40 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
41 #define reinit_completion(completion) INIT_COMPLETION(*(completion))
45 struct list_head list
;
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
;
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))))
58 void srvman_init(struct srvman
*srvman
, struct scsc_mx
*mx
)
60 SCSC_TAG_INFO(MXMAN
, "\n");
62 INIT_LIST_HEAD(&srvman
->service_list
);
63 mutex_init(&srvman
->service_list_mutex
);
64 mutex_init(&srvman
->api_access_mutex
);
67 wake_lock_init(&srvman
->sm_wake_lock
, WAKE_LOCK_SUSPEND
, "srvman_wakelock");
71 void srvman_deinit(struct srvman
*srvman
)
73 struct scsc_service
*service
, *next
;
75 SCSC_TAG_INFO(MXMAN
, "\n");
76 list_for_each_entry_safe(service
, next
, &srvman
->service_list
, list
) {
77 list_del(&service
->list
);
80 mutex_destroy(&srvman
->api_access_mutex
);
81 mutex_destroy(&srvman
->service_list_mutex
);
84 wake_lock_destroy(&srvman
->sm_wake_lock
);
88 void srvman_set_error(struct srvman
*srvman
)
90 struct scsc_service
*service
;
92 SCSC_TAG_INFO(MXMAN
, "\n");
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
);
99 mutex_unlock(&srvman
->service_list_mutex
);
102 void srvman_clear_error(struct srvman
*srvman
)
104 SCSC_TAG_INFO(MXMAN
, "\n");
105 srvman
->error
= false;
108 static int wait_for_sm_msg_start_cfm(struct scsc_service
*service
)
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
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);
121 SCSC_TAG_ERR(MXMAN
, "timed out\n");
127 r
= wait_for_completion_timeout(&service
->sm_msg_start_completion
, msecs_to_jiffies(sm_completion_timeout_ms
));
129 SCSC_TAG_ERR(MXMAN
, "timeout\n");
135 static int wait_for_sm_msg_stop_cfm(struct scsc_service
*service
)
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
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);
148 SCSC_TAG_ERR(MXMAN
, "timed out\n");
154 r
= wait_for_completion_timeout(&service
->sm_msg_stop_completion
, msecs_to_jiffies(sm_completion_timeout_ms
));
156 SCSC_TAG_ERR(MXMAN
, "timeout\n");
162 static int send_sm_msg_start_blocking(struct scsc_service
*service
, scsc_mifram_ref ref
)
164 struct scsc_mx
*mx
= service
->mx
;
165 struct mxmgmt_transport
*mxmgmt_transport
= scsc_mx_get_mxmgmt_transport(mx
);
167 struct sm_msg_packet message
= { .service_id
= service
->id
,
168 .msg
= SM_MSG_START_REQ
,
169 .optional_data
= ref
};
171 reinit_completion(&service
->sm_msg_start_completion
);
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
);
177 SCSC_TAG_ERR(MXMAN
, "wait_for_sm_msg_start_cfm() failed: r=%d\n", r
);
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");
186 static int send_sm_msg_stop_blocking(struct scsc_service
*service
)
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
);
192 struct sm_msg_packet message
= { .service_id
= service
->id
,
193 .msg
= SM_MSG_STOP_REQ
,
194 .optional_data
= 0 };
196 if (mxman
->mxman_state
== MXMAN_STATE_FAILED
)
199 reinit_completion(&service
->sm_msg_stop_completion
);
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
);
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
);
210 * Receive handler for messages from the FW along the maxwell management transport
212 static void srv_message_handler(const void *message
, void *data
)
214 struct srvman
*srvman
= (struct srvman
*)data
;
215 struct scsc_service
*service
;
216 const struct sm_msg_packet
*msg
= message
;
219 mutex_lock(&srvman
->service_list_mutex
);
220 list_for_each_entry(service
, &srvman
->service_list
, list
) {
221 if (service
->id
== msg
->service_id
) {
227 SCSC_TAG_ERR(MXMAN
, "No service for msg->service_id=%d", msg
->service_id
);
228 mutex_unlock(&srvman
->service_list_mutex
);
231 /* Forward the message to the applicable service to deal with */
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
);
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
);
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
);
249 mutex_unlock(&srvman
->service_list_mutex
);
252 int scsc_mx_service_start(struct scsc_service
*service
, scsc_mifram_ref ref
)
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
);
258 struct timeval tval
= {};
260 SCSC_TAG_INFO(MXMAN
, "%d\n", service
->id
);
261 #ifdef CONFIG_SCSC_CHV_SUPPORT
265 mutex_lock(&srvman
->api_access_mutex
);
266 #ifdef CONFIG_ANDROID
267 wake_lock(&srvman
->sm_wake_lock
);
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
);
274 /* Print the last panic record to help track ancient failures */
275 mxman_show_last_panic(mxman
);
277 #ifdef CONFIG_ANDROID
278 wake_unlock(&srvman
->sm_wake_lock
);
280 mutex_unlock(&srvman
->api_access_mutex
);
284 r
= send_sm_msg_start_blocking(service
, ref
);
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
);
290 mutex_unlock(&srvman
->api_access_mutex
);
294 #ifdef CONFIG_ANDROID
295 wake_unlock(&srvman
->sm_wake_lock
);
297 mutex_unlock(&srvman
->api_access_mutex
);
300 EXPORT_SYMBOL(scsc_mx_service_start
);
302 int scsc_mx_list_services(struct mxman
*mxman_p
, char *buf
, const size_t bufsz
)
304 struct scsc_service
*service
, *next
;
306 struct srvman
*srvman_p
= scsc_mx_get_srvman(mxman_p
->mx
);
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");
313 case SCSC_SERVICE_ID_WLAN
:
314 pos
+= scnprintf(buf
+ pos
, bufsz
- pos
, "%s\n", "wlan");
316 case SCSC_SERVICE_ID_BT
:
317 pos
+= scnprintf(buf
+ pos
, bufsz
- pos
, "%s\n", "bt");
319 case SCSC_SERVICE_ID_ANT
:
320 pos
+= scnprintf(buf
+ pos
, bufsz
- pos
, "%s\n", "ant");
322 case SCSC_SERVICE_ID_R4DBG
:
323 pos
+= scnprintf(buf
+ pos
, bufsz
- pos
, "%s\n", "r4dbg");
325 case SCSC_SERVICE_ID_ECHO
:
326 pos
+= scnprintf(buf
+ pos
, bufsz
- pos
, "%s\n", "echo");
328 case SCSC_SERVICE_ID_DBG_SAMPLER
:
329 pos
+= scnprintf(buf
+ pos
, bufsz
- pos
, "%s\n", "dbg sampler");
331 case SCSC_SERVICE_ID_CLK20MHZ
:
332 pos
+= scnprintf(buf
+ pos
, bufsz
- pos
, "%s\n", "clk20mhz");
334 case SCSC_SERVICE_ID_FM
:
335 pos
+= scnprintf(buf
+ pos
, bufsz
- pos
, "%s\n", "fm");
337 case SCSC_SERVICE_ID_INVALID
:
338 pos
+= scnprintf(buf
+ pos
, bufsz
- pos
, "%s\n", "invalid");
344 EXPORT_SYMBOL(scsc_mx_list_services
);
346 int scsc_mx_service_stop(struct scsc_service
*service
)
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
);
352 struct timeval tval
= {};
354 SCSC_TAG_INFO(MXMAN
, "%d\n", service
->id
);
355 #ifdef CONFIG_SCSC_CHV_SUPPORT
359 mutex_lock(&srvman
->api_access_mutex
);
360 #ifdef CONFIG_ANDROID
361 wake_lock(&srvman
->sm_wake_lock
);
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
);
368 /* Print the last panic record to help track ancient failures */
369 mxman_show_last_panic(mxman
);
371 #ifdef CONFIG_ANDROID
372 wake_unlock(&srvman
->sm_wake_lock
);
374 mutex_unlock(&srvman
->api_access_mutex
);
376 /* Return a special status to allow caller recovery logic to know
377 * that there will never be a recovery
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 */
383 return -EILSEQ
; /* operation rejected due to prior failure */
387 r
= send_sm_msg_stop_blocking(service
);
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
);
393 mutex_unlock(&srvman
->api_access_mutex
);
394 return -EIO
; /* operation failed */
397 #ifdef CONFIG_ANDROID
398 wake_unlock(&srvman
->sm_wake_lock
);
400 mutex_unlock(&srvman
->api_access_mutex
);
403 EXPORT_SYMBOL(scsc_mx_service_stop
);
406 /* Returns 0 if Suspend succeeded, otherwise return error */
407 int srvman_suspend_services(struct srvman
*srvman
)
410 struct scsc_service
*service
;
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 */
419 list_for_each_entry(service
, &srvman
->service_list
, list
) {
420 if (service
->client
->resume
)
421 service
->client
->resume(service
->client
);
423 SCSC_TAG_INFO(MXMAN
, "Service client suspend failure ret: %d\n", ret
);
424 mutex_unlock(&srvman
->service_list_mutex
);
430 mutex_unlock(&srvman
->service_list_mutex
);
431 SCSC_TAG_INFO(MXMAN
, "OK\n");
435 /* Returns always 0. Extend API and return value if required */
436 int srvman_resume_services(struct srvman
*srvman
)
438 struct scsc_service
*service
;
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
);
447 mutex_unlock(&srvman
->service_list_mutex
);
448 SCSC_TAG_INFO(MXMAN
, "OK\n");
453 void srvman_freeze_services(struct srvman
*srvman
, struct mx_syserr_decode
*syserr
)
455 struct scsc_service
*service
;
456 struct mxman
*mxman
= scsc_mx_get_mxman(srvman
->mx
);
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;
470 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
471 reinit_completion(&mxman
->recovery_completion
);
473 INIT_COMPLETION(mxman
->recovery_completion
);
475 mutex_unlock(&srvman
->service_list_mutex
);
476 SCSC_TAG_INFO(MXMAN
, "OK\n");
479 void srvman_freeze_sub_system(struct srvman
*srvman
, struct mx_syserr_decode
*syserr
)
481 struct scsc_service
*service
;
482 struct mxman
*mxman
= scsc_mx_get_mxman(srvman
->mx
);
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;
492 mutex_unlock(&srvman
->service_list_mutex
);
493 SCSC_TAG_INFO(MXMAN
, "OK\n");
496 void srvman_unfreeze_services(struct srvman
*srvman
, u16 scsc_panic_code
)
498 struct scsc_service
*service
;
499 struct mxman
*mxman
= scsc_mx_get_mxman(srvman
->mx
);
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
);
510 mutex_unlock(&srvman
->service_list_mutex
);
511 SCSC_TAG_INFO(MXMAN
, "OK\n");
514 void srvman_unfreeze_sub_system(struct srvman
*srvman
, struct mx_syserr_decode
*syserr
)
516 struct scsc_service
*service
;
517 struct mxman
*mxman
= scsc_mx_get_mxman(srvman
->mx
);
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
);
526 mutex_unlock(&srvman
->service_list_mutex
);
527 SCSC_TAG_INFO(MXMAN
, "OK\n");
530 u8
srvman_notify_sub_system(struct srvman
*srvman
, struct mx_syserr_decode
*syserr
)
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;
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
))
544 else if (SERVICE_IN_SUBSYSTEM(service
->id
, SYSERR_SUBSYS_BT
))
546 if ((SERVICE_IN_SUBSYSTEM(service
->id
, syserr
->subsys
) && (service
->client
->failure_notification
))) {
547 u8 level
= service
->client
->failure_notification(service
->client
, syserr
);
549 affected_service_found
= true;
550 if (level
> final_level
)
554 mutex_unlock(&srvman
->service_list_mutex
);
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
);
563 SCSC_TAG_INFO(MXMAN
, "OK\n");
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
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
;
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.
581 void scsc_mx_service_service_failed(struct scsc_service
*service
, const char *reason
)
583 struct scsc_mx
*mx
= service
->mx
;
584 struct srvman
*srvman
= scsc_mx_get_srvman(mx
);
587 host_panic_code
= (SCSC_PANIC_CODE_HOST
<< 15) | (service
->id
<< SCSC_SYSERR_HOST_SERVICE_SHIFT
);
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
: ""));
594 case SCSC_SERVICE_ID_BT
:
595 SCSC_TAG_INFO(MXMAN
, "BT: %s\n", ((reason
!= NULL
) ? reason
: ""));
598 SCSC_TAG_INFO(MXMAN
, "service id %d failed\n", service
->id
);
603 SCSC_TAG_INFO(MXMAN
, "Reporting host hang code 0x%02x\n", host_panic_code
);
605 mxman_fail(scsc_mx_get_mxman(mx
), host_panic_code
, reason
);
607 EXPORT_SYMBOL(scsc_mx_service_service_failed
);
610 int scsc_mx_service_close(struct scsc_service
*service
)
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
);
616 struct timeval tval
= {};
618 SCSC_TAG_INFO(MXMAN
, "%d\n", service
->id
);
620 mutex_lock(&srvman
->api_access_mutex
);
621 #ifdef CONFIG_ANDROID
622 wake_lock(&srvman
->sm_wake_lock
);
625 /* TODO - Race conditions here unless we protect better
626 * code assumes srvman->error and mxman->state can't change, but they can
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
);
633 /* Print the last panic record to help track ancient failures */
634 mxman_show_last_panic(mxman
);
636 mutex_unlock(&srvman
->api_access_mutex
);
637 #ifdef CONFIG_ANDROID
638 wake_unlock(&srvman
->sm_wake_lock
);
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.
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 */
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
);
659 /* unregister channel handler */
660 mxmgmt_transport_register_channel_handler(scsc_mx_get_mxmgmt_transport(mx
), MMTRANS_CHAN_ID_SERVICE_MANAGEMENT
,
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!
669 struct scsc_service
*serv
;
670 bool all_cleared
= true;
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
))
677 mutex_unlock(&srvman
->service_list_mutex
);
680 mxman
->syserr_recovery_in_progress
= false;
686 #ifdef CONFIG_ANDROID
687 wake_unlock(&srvman
->sm_wake_lock
);
689 mutex_unlock(&srvman
->api_access_mutex
);
692 EXPORT_SYMBOL(scsc_mx_service_close
);
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
)
698 struct scsc_service
*service
;
699 struct srvman
*srvman
= scsc_mx_get_srvman(mx
);
700 struct mxman
*mxman
= scsc_mx_get_mxman(mx
);
702 struct timeval tval
= {};
704 SCSC_TAG_INFO(MXMAN
, "%d\n", id
);
706 mutex_lock(&srvman
->api_access_mutex
);
707 #ifdef CONFIG_ANDROID
708 wake_lock(&srvman
->sm_wake_lock
);
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
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
);
723 mutex_unlock(&srvman
->api_access_mutex
);
728 if (mxman
->mxman_state
== MXMAN_STATE_FAILED
) {
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
));
735 SCSC_TAG_ERR(MXMAN
, "Recovery timeout\n");
736 #ifdef CONFIG_ANDROID
737 wake_unlock(&srvman
->sm_wake_lock
);
743 mutex_lock(&srvman
->api_access_mutex
);
746 service
= kmalloc(sizeof(struct scsc_service
), GFP_KERNEL
);
748 /* MaxwellManager Should allocate Mem and download FW */
749 ret
= mxman_open(mxman
);
752 #ifdef CONFIG_ANDROID
753 wake_unlock(&srvman
->sm_wake_lock
);
755 mutex_unlock(&srvman
->api_access_mutex
);
759 /* Initialise service struct here */
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
);
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
);
777 #ifdef CONFIG_ANDROID
778 wake_unlock(&srvman
->sm_wake_lock
);
780 mutex_unlock(&srvman
->api_access_mutex
);
784 EXPORT_SYMBOL(scsc_mx_service_open
);
786 struct scsc_bt_audio_abox
*scsc_mx_service_get_bt_audio_abox(struct scsc_service
*service
)
788 struct scsc_mx
*mx
= service
->mx
;
791 ptr
= scsc_mx_get_aboxram(mx
);
796 struct mifabox
*scsc_mx_service_get_aboxram(struct scsc_service
*service
)
798 struct scsc_mx
*mx
= service
->mx
;
801 ptr
= scsc_mx_get_aboxram(mx
);
807 * Allocate a contiguous block of SDRAM accessible to Client Driver
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().
813 int scsc_mx_service_mifram_alloc_extended(struct scsc_service
*service
, size_t nbytes
, scsc_mifram_ref
*ref
, u32 align
, uint32_t flags
)
815 struct scsc_mx
*mx
= service
->mx
;
818 struct miframman
*ramman
;
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
);
825 SCSC_TAG_ERR(MXMAN
, "Unsupported flags value: %d", flags
);
826 *ref
= SCSC_MIFRAM_INVALID_REF
;
830 mem
= miframman_alloc(ramman
, nbytes
, align
, service
->id
);
832 SCSC_TAG_ERR(MXMAN
, "miframman_alloc() failed\n");
833 *ref
= SCSC_MIFRAM_INVALID_REF
;
837 SCSC_TAG_DEBUG(MXMAN
, "Allocated mem %p\n", mem
);
839 /* Transform native pointer and get mifram_ref type */
840 ret
= scsc_mx_service_mif_ptr_to_addr(service
, mem
, ref
);
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
;
846 SCSC_TAG_DEBUG(MXMAN
, "mem %p ref %d\n", mem
, *ref
);
850 EXPORT_SYMBOL(scsc_mx_service_mifram_alloc_extended
);
852 int scsc_mx_service_mifram_alloc(struct scsc_service
*service
, size_t nbytes
, scsc_mifram_ref
*ref
, u32 align
)
854 return scsc_mx_service_mifram_alloc_extended(service
, nbytes
, ref
, align
, MIFRAMMAN_MEM_POOL_GENERIC
);
856 EXPORT_SYMBOL(scsc_mx_service_mifram_alloc
);
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
)
861 struct scsc_mx
*mx
= service
->mx
;
863 struct miframman
*ramman
;
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
);
870 SCSC_TAG_ERR(MXMAN
, "Unsupported flags value: %d", flags
);
874 mem
= scsc_mx_service_mif_addr_to_ptr(service
, ref
);
876 SCSC_TAG_DEBUG(MXMAN
, "**** Freeing %p\n", mem
);
878 miframman_free(ramman
, mem
);
880 EXPORT_SYMBOL(scsc_mx_service_mifram_free_extended
);
882 void scsc_mx_service_mifram_free(struct scsc_service
*service
, scsc_mifram_ref ref
)
884 scsc_mx_service_mifram_free_extended(service
, ref
, MIFRAMMAN_MEM_POOL_GENERIC
);
886 EXPORT_SYMBOL(scsc_mx_service_mifram_free
);
888 /* MIF ALLOCATIONS */
889 bool scsc_mx_service_alloc_mboxes(struct scsc_service
*service
, int n
, int *first_mbox_index
)
891 struct scsc_mx
*mx
= service
->mx
;
893 return mifmboxman_alloc_mboxes(scsc_mx_get_mboxman(mx
), n
, first_mbox_index
);
895 EXPORT_SYMBOL(scsc_mx_service_alloc_mboxes
);
897 void scsc_service_free_mboxes(struct scsc_service
*service
, int n
, int first_mbox_index
)
899 struct scsc_mx
*mx
= service
->mx
;
901 return mifmboxman_free_mboxes(scsc_mx_get_mboxman(mx
), first_mbox_index
, n
);
903 EXPORT_SYMBOL(scsc_service_free_mboxes
);
905 u32
*scsc_mx_service_get_mbox_ptr(struct scsc_service
*service
, int mbox_index
)
907 struct scsc_mx
*mx
= service
->mx
;
908 struct scsc_mif_abs
*mif_abs
;
910 mif_abs
= scsc_mx_get_mif_abs(mx
);
912 return mifmboxman_get_mbox_ptr(scsc_mx_get_mboxman(mx
), mif_abs
, mbox_index
);
914 EXPORT_SYMBOL(scsc_mx_service_get_mbox_ptr
);
916 int scsc_service_mifintrbit_bit_mask_status_get(struct scsc_service
*service
)
918 struct scsc_mx
*mx
= service
->mx
;
919 struct scsc_mif_abs
*mif_abs
;
921 mif_abs
= scsc_mx_get_mif_abs(mx
);
923 return mif_abs
->irq_bit_mask_status_get(mif_abs
);
925 EXPORT_SYMBOL(scsc_service_mifintrbit_bit_mask_status_get
);
927 int scsc_service_mifintrbit_get(struct scsc_service
*service
)
929 struct scsc_mx
*mx
= service
->mx
;
930 struct scsc_mif_abs
*mif_abs
;
932 mif_abs
= scsc_mx_get_mif_abs(mx
);
934 return mif_abs
->irq_get(mif_abs
);
936 EXPORT_SYMBOL(scsc_service_mifintrbit_get
);
938 void scsc_service_mifintrbit_bit_set(struct scsc_service
*service
, int which_bit
, enum scsc_mifintr_target dir
)
940 struct scsc_mx
*mx
= service
->mx
;
941 struct scsc_mif_abs
*mif_abs
;
943 mif_abs
= scsc_mx_get_mif_abs(mx
);
945 return mif_abs
->irq_bit_set(mif_abs
, which_bit
, (enum scsc_mif_abs_target
)dir
);
947 EXPORT_SYMBOL(scsc_service_mifintrbit_bit_set
);
949 void scsc_service_mifintrbit_bit_clear(struct scsc_service
*service
, int which_bit
)
951 struct scsc_mx
*mx
= service
->mx
;
952 struct scsc_mif_abs
*mif_abs
;
954 mif_abs
= scsc_mx_get_mif_abs(mx
);
956 return mif_abs
->irq_bit_clear(mif_abs
, which_bit
);
958 EXPORT_SYMBOL(scsc_service_mifintrbit_bit_clear
);
960 void scsc_service_mifintrbit_bit_mask(struct scsc_service
*service
, int which_bit
)
962 struct scsc_mx
*mx
= service
->mx
;
963 struct scsc_mif_abs
*mif_abs
;
965 mif_abs
= scsc_mx_get_mif_abs(mx
);
967 return mif_abs
->irq_bit_mask(mif_abs
, which_bit
);
969 EXPORT_SYMBOL(scsc_service_mifintrbit_bit_mask
);
971 void scsc_service_mifintrbit_bit_unmask(struct scsc_service
*service
, int which_bit
)
973 struct scsc_mx
*mx
= service
->mx
;
974 struct scsc_mif_abs
*mif_abs
;
976 mif_abs
= scsc_mx_get_mif_abs(mx
);
978 return mif_abs
->irq_bit_unmask(mif_abs
, which_bit
);
980 EXPORT_SYMBOL(scsc_service_mifintrbit_bit_unmask
);
982 int scsc_service_mifintrbit_alloc_fromhost(struct scsc_service
*service
, enum scsc_mifintr_target dir
)
984 struct scsc_mx
*mx
= service
->mx
;
986 return mifintrbit_alloc_fromhost(scsc_mx_get_intrbit(mx
), (enum scsc_mif_abs_target
)dir
);
988 EXPORT_SYMBOL(scsc_service_mifintrbit_alloc_fromhost
);
990 int scsc_service_mifintrbit_free_fromhost(struct scsc_service
*service
, int which_bit
, enum scsc_mifintr_target dir
)
992 struct scsc_mx
*mx
= service
->mx
;
994 return mifintrbit_free_fromhost(scsc_mx_get_intrbit(mx
), which_bit
, (enum scsc_mif_abs_target
)dir
);
996 EXPORT_SYMBOL(scsc_service_mifintrbit_free_fromhost
);
998 int scsc_service_mifintrbit_register_tohost(struct scsc_service
*service
, void (*handler
)(int irq
, void *data
), void *data
)
1000 struct scsc_mx
*mx
= service
->mx
;
1002 SCSC_TAG_DEBUG(MXMAN
, "Registering %pS\n", handler
);
1004 return mifintrbit_alloc_tohost(scsc_mx_get_intrbit(mx
), handler
, data
);
1006 EXPORT_SYMBOL(scsc_service_mifintrbit_register_tohost
);
1008 int scsc_service_mifintrbit_unregister_tohost(struct scsc_service
*service
, int which_bit
)
1010 struct scsc_mx
*mx
= service
->mx
;
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
);
1015 EXPORT_SYMBOL(scsc_service_mifintrbit_unregister_tohost
);
1017 void *scsc_mx_service_mif_addr_to_ptr(struct scsc_service
*service
, scsc_mifram_ref ref
)
1019 struct scsc_mx
*mx
= service
->mx
;
1021 struct scsc_mif_abs
*mif_abs
;
1023 mif_abs
= scsc_mx_get_mif_abs(mx
);
1025 return mif_abs
->get_mifram_ptr(mif_abs
, ref
);
1027 EXPORT_SYMBOL(scsc_mx_service_mif_addr_to_ptr
);
1029 void *scsc_mx_service_mif_addr_to_phys(struct scsc_service
*service
, scsc_mifram_ref ref
)
1031 struct scsc_mx
*mx
= service
->mx
;
1033 struct scsc_mif_abs
*mif_abs
;
1035 mif_abs
= scsc_mx_get_mif_abs(mx
);
1037 if (mif_abs
->get_mifram_phy_ptr
)
1038 return mif_abs
->get_mifram_phy_ptr(mif_abs
, ref
);
1042 EXPORT_SYMBOL(scsc_mx_service_mif_addr_to_phys
);
1044 int scsc_mx_service_mif_ptr_to_addr(struct scsc_service
*service
, void *mem_ptr
, scsc_mifram_ref
*ref
)
1046 struct scsc_mx
*mx
= service
->mx
;
1047 struct scsc_mif_abs
*mif_abs
;
1049 mif_abs
= scsc_mx_get_mif_abs(mx
);
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");
1059 EXPORT_SYMBOL(scsc_mx_service_mif_ptr_to_addr
);
1061 int scsc_mx_service_mif_dump_registers(struct scsc_service
*service
)
1063 struct scsc_mx
*mx
= service
->mx
;
1064 struct scsc_mif_abs
*mif_abs
;
1066 mif_abs
= scsc_mx_get_mif_abs(mx
);
1068 /* Dump registers */
1069 mif_abs
->mif_dump_registers(mif_abs
);
1073 EXPORT_SYMBOL(scsc_mx_service_mif_dump_registers
);
1075 struct device
*scsc_service_get_device(struct scsc_service
*service
)
1077 return scsc_mx_get_device(service
->mx
);
1079 EXPORT_SYMBOL(scsc_service_get_device
);
1081 struct device
*scsc_service_get_device_by_mx(struct scsc_mx
*mx
)
1083 return scsc_mx_get_device(mx
);
1085 EXPORT_SYMBOL(scsc_service_get_device_by_mx
);
1087 /* Force a FW panic for test purposes only */
1088 int scsc_service_force_panic(struct scsc_service
*service
)
1090 struct mxman
*mxman
= scsc_mx_get_mxman(service
->mx
);
1092 SCSC_TAG_INFO(MXMAN
, "%d\n", service
->id
);
1094 return mxman_force_panic(mxman
);
1096 EXPORT_SYMBOL(scsc_service_force_panic
);
1098 #ifdef CONFIG_SCSC_SMAPPER
1099 u16
scsc_service_get_alignment(struct scsc_service
*service
)
1101 struct scsc_mx
*mx
= service
->mx
;
1103 return mifsmapper_get_alignment(scsc_mx_get_smapper(mx
));
1106 int scsc_service_mifsmapper_alloc_bank(struct scsc_service
*service
, bool large_bank
, u32 entry_size
, u16
*entries
)
1108 struct scsc_mx
*mx
= service
->mx
;
1110 return mifsmapper_alloc_bank(scsc_mx_get_smapper(mx
), large_bank
, entry_size
, entries
);
1112 EXPORT_SYMBOL(scsc_service_mifsmapper_alloc_bank
);
1114 void scsc_service_mifsmapper_configure(struct scsc_service
*service
, u32 granularity
)
1116 struct scsc_mx
*mx
= service
->mx
;
1118 mifsmapper_configure(scsc_mx_get_smapper(mx
), granularity
);
1120 EXPORT_SYMBOL(scsc_service_mifsmapper_configure
);
1122 int scsc_service_mifsmapper_write_sram(struct scsc_service
*service
, u8 bank
, u8 num_entries
, u8 first_entry
, dma_addr_t
*addr
)
1124 struct scsc_mx
*mx
= service
->mx
;
1126 return mifsmapper_write_sram(scsc_mx_get_smapper(mx
), bank
, num_entries
, first_entry
, addr
);
1128 EXPORT_SYMBOL(scsc_service_mifsmapper_write_sram
);
1130 int scsc_service_mifsmapper_get_entries(struct scsc_service
*service
, u8 bank
, u8 num_entries
, u8
*entries
)
1132 struct scsc_mx
*mx
= service
->mx
;
1134 return mifsmapper_get_entries(scsc_mx_get_smapper(mx
), bank
, num_entries
, entries
);
1136 EXPORT_SYMBOL(scsc_service_mifsmapper_get_entries
);
1138 int scsc_service_mifsmapper_free_entries(struct scsc_service
*service
, u8 bank
, u8 num_entries
, u8
*entries
)
1140 struct scsc_mx
*mx
= service
->mx
;
1142 return mifsmapper_free_entries(scsc_mx_get_smapper(mx
), bank
, num_entries
, entries
);
1144 EXPORT_SYMBOL(scsc_service_mifsmapper_free_entries
);
1146 int scsc_service_mifsmapper_free_bank(struct scsc_service
*service
, u8 bank
)
1148 struct scsc_mx
*mx
= service
->mx
;
1150 return mifsmapper_free_bank(scsc_mx_get_smapper(mx
), bank
);
1152 EXPORT_SYMBOL(scsc_service_mifsmapper_free_bank
);
1154 u32
scsc_service_mifsmapper_get_bank_base_address(struct scsc_service
*service
, u8 bank
)
1156 struct scsc_mx
*mx
= service
->mx
;
1158 return mifsmapper_get_bank_base_address(scsc_mx_get_smapper(mx
), bank
);
1160 EXPORT_SYMBOL(scsc_service_mifsmapper_get_bank_base_address
);
1163 #ifdef CONFIG_SCSC_QOS
1164 int scsc_service_pm_qos_add_request(struct scsc_service
*service
, enum scsc_qos_config config
)
1166 struct scsc_mx
*mx
= service
->mx
;
1168 mifqos_add_request(scsc_mx_get_qos(mx
), service
->id
, config
);
1172 EXPORT_SYMBOL(scsc_service_pm_qos_add_request
);
1174 int scsc_service_pm_qos_update_request(struct scsc_service
*service
, enum scsc_qos_config config
)
1176 struct scsc_mx
*mx
= service
->mx
;
1178 mifqos_update_request(scsc_mx_get_qos(mx
), service
->id
, config
);
1182 EXPORT_SYMBOL(scsc_service_pm_qos_update_request
);
1184 int scsc_service_pm_qos_remove_request(struct scsc_service
*service
)
1186 struct scsc_mx
*mx
= service
->mx
;
1191 mifqos_remove_request(scsc_mx_get_qos(mx
), service
->id
);
1195 EXPORT_SYMBOL(scsc_service_pm_qos_remove_request
);
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
)
1206 return mxlogger_register_global_observer(name
);
1213 return mxlogger_register_observer(scsc_mx_get_mxlogger(mx
), name
);
1215 EXPORT_SYMBOL(scsc_service_register_observer
);
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
)
1223 return mxlogger_unregister_global_observer(name
);
1230 return mxlogger_unregister_observer(scsc_mx_get_mxlogger(mx
), name
);
1232 EXPORT_SYMBOL(scsc_service_unregister_observer
);