[9610] wlbt: SCSC Driver version 10.9.1.0
[GitHub/MotorolaMobilityLLC/kernel-slsi.git] / drivers / misc / samsung / scsc / mxman.c
CommitLineData
533a23a1
TK
1/****************************************************************************
2 *
3 * Copyright (c) 2014 - 2019 Samsung Electronics Co., Ltd. All rights reserved
4 *
5 ****************************************************************************/
6
7#include <linux/module.h>
8#include <linux/init.h>
9#include <linux/firmware.h>
10#include <linux/slab.h>
11#include <linux/delay.h>
12#include <linux/version.h>
13#include <linux/kmod.h>
14#include <linux/notifier.h>
15#include "scsc_mx_impl.h"
16#include "miframman.h"
17#include "mifmboxman.h"
18#include "mxman.h"
19#include "srvman.h"
20#include "mxmgmt_transport.h"
21#include "gdb_transport.h"
22#include "mxconf.h"
23#include "fwimage.h"
24#include "fwhdr.h"
25#include "mxlog.h"
26#include "mxlogger.h"
27#include "fw_panic_record.h"
28#include "panicmon.h"
29#include "mxproc.h"
30#include "mxlog_transport.h"
31#include "mxsyserr.h"
32#ifdef CONFIG_SCSC_SMAPPER
33#include "mifsmapper.h"
34#endif
35#ifdef CONFIG_SCSC_QOS
36#include "mifqos.h"
37#endif
38#include "mxfwconfig.h"
39#include <scsc/kic/slsi_kic_lib.h>
40#include <scsc/scsc_release.h>
41#include <scsc/scsc_mx.h>
42#include <linux/fs.h>
43#ifdef CONFIG_SCSC_LOG_COLLECTION
44#include <scsc/scsc_log_collector.h>
45#endif
46
47#include <scsc/scsc_logring.h>
48#ifdef CONFIG_SCSC_WLBTD
49#include "scsc_wlbtd.h"
50#define SCSC_SCRIPT_MOREDUMP "moredump"
51#define SCSC_SCRIPT_LOGGER_DUMP "mx_logger_dump.sh"
52static struct work_struct wlbtd_work;
53#endif
54
55#include "scsc_lerna.h"
56
57#include <asm/page.h>
58#include <scsc/api/bt_audio.h>
59
60#define STRING_BUFFER_MAX_LENGTH 512
61#define NUMBER_OF_STRING_ARGS 5
62#define MX_DRAM_SIZE (4 * 1024 * 1024)
63#define MX_DRAM_SIZE_SECTION_1 (8 * 1024 * 1024)
64#define MX_DRAM_SIZE_SECTION_2 (8 * 1024 * 1024)
65#define MX_FW_RUNTIME_LENGTH (1024 * 1024)
66#define WAIT_FOR_FW_TO_START_DELAY_MS 1000
67#define MBOX2_MAGIC_NUMBER 0xbcdeedcb
68#define MBOX_INDEX_0 0
69#define MBOX_INDEX_1 1
70#define MBOX_INDEX_2 2
71#define MBOX_INDEX_3 3
72#ifdef CONFIG_SOC_EXYNOS7570
73#define MBOX_INDEX_4 4
74#define MBOX_INDEX_5 5
75#define MBOX_INDEX_6 6
76#define MBOX_INDEX_7 7
77#endif
78
79#define SCSC_PANIC_ORIGIN_FW (0x0 << 15)
80#define SCSC_PANIC_ORIGIN_HOST (0x1 << 15)
81
82#define SCSC_PANIC_TECH_WLAN (0x0 << 13)
83#define SCSC_PANIC_TECH_CORE (0x1 << 13)
84#define SCSC_PANIC_TECH_BT (0x2 << 13)
85#define SCSC_PANIC_TECH_UNSP (0x3 << 13)
86
87#define SCSC_PANIC_CODE_MASK 0xFFFF
88#define SCSC_PANIC_ORIGIN_MASK 0x8000
89#define SCSC_PANIC_TECH_MASK 0x6000
90#define SCSC_PANIC_SUBCODE_MASK_LEGACY 0x0FFF
91#define SCSC_PANIC_SUBCODE_MASK 0x7FFF
92
93#define SCSC_R4_V2_MINOR_52 52
94#define SCSC_R4_V2_MINOR_53 53
95
96#define MM_HALT_RSP_TIMEOUT_MS 100
97
98static char panic_record_dump[PANIC_RECORD_DUMP_BUFFER_SZ];
99static BLOCKING_NOTIFIER_HEAD(firmware_chain);
100
101/**
102 * This will be returned as fw version ONLY if Maxwell
103 * was never found or was unloaded.
104 */
105static char saved_fw_build_id[FW_BUILD_ID_SZ] = "Maxwell WLBT unavailable";
106
107static bool allow_unidentified_firmware;
108module_param(allow_unidentified_firmware, bool, S_IRUGO | S_IWUSR);
109MODULE_PARM_DESC(allow_unidentified_firmware, "Allow unidentified firmware");
110
111static bool skip_header;
112module_param(skip_header, bool, S_IRUGO | S_IWUSR);
113MODULE_PARM_DESC(skip_header, "Skip header, assuming unidentified firmware");
114
115static bool crc_check_allow_none = true;
116module_param(crc_check_allow_none, bool, S_IRUGO | S_IWUSR);
117MODULE_PARM_DESC(crc_check_allow_none, "Allow skipping firmware CRC checks if CRC is not present");
118
119static int crc_check_period_ms = 30000;
120module_param(crc_check_period_ms, int, S_IRUGO | S_IWUSR);
121MODULE_PARM_DESC(crc_check_period_ms, "Time period for checking the firmware CRCs");
122
123static ulong mm_completion_timeout_ms = 2000;
124module_param(mm_completion_timeout_ms, ulong, S_IRUGO | S_IWUSR);
125MODULE_PARM_DESC(mm_completion_timeout_ms, "Timeout wait_for_mm_msg_start_ind (ms) - default 1000. 0 = infinite");
126
127static bool skip_mbox0_check;
128module_param(skip_mbox0_check, bool, S_IRUGO | S_IWUSR);
129MODULE_PARM_DESC(skip_mbox0_check, "Allow skipping firmware mbox0 signature check");
130
131static uint firmware_startup_flags;
132module_param(firmware_startup_flags, uint, S_IRUGO | S_IWUSR);
133MODULE_PARM_DESC(firmware_startup_flags, "0 = Proceed as normal (default); Bit 0 = 1 - spin at start of CRT0; Other bits reserved = 0");
134
135#ifdef CONFIG_SCSC_CHV_SUPPORT
136/* First arg controls chv function */
137int chv_run;
138module_param(chv_run, int, S_IRUGO | S_IWUSR);
139MODULE_PARM_DESC(chv_run, "Run chv f/w: 0 = feature disabled, 1 = for continuous checking, 2 = 1 shot, anything else, undefined");
140
141/* Optional array of args for firmware to interpret when chv_run = 1 */
142static unsigned int chv_argv[32];
143static int chv_argc;
144
145module_param_array(chv_argv, uint, &chv_argc, S_IRUGO | S_IWUSR);
146MODULE_PARM_DESC(chv_argv, "Array of up to 32 x u32 args for the CHV firmware when chv_run = 1");
147#endif
148
149static bool disable_auto_coredump;
150module_param(disable_auto_coredump, bool, S_IRUGO | S_IWUSR);
151MODULE_PARM_DESC(disable_auto_coredump, "Disable driver automatic coredump");
152
153static bool disable_error_handling;
154module_param(disable_error_handling, bool, S_IRUGO | S_IWUSR);
155MODULE_PARM_DESC(disable_error_handling, "Disable error handling");
156
157int disable_recovery_handling = 1; /* MEMDUMP_FILE_FOR_RECOVERY : for /sys/wifi/memdump */
158module_param(disable_recovery_handling, int, S_IRUGO | S_IWUSR);
159MODULE_PARM_DESC(disable_recovery_handling, "Disable recovery handling");
160static bool disable_recovery_from_memdump_file = true;
161static int memdump = -1;
162static bool disable_recovery_until_reboot;
163
164static uint panic_record_delay = 1;
165module_param(panic_record_delay, uint, S_IRUGO | S_IWUSR);
166MODULE_PARM_DESC(panic_record_delay, "Delay in ms before accessing the panic record");
167
168static bool disable_logger = true;
169module_param(disable_logger, bool, S_IRUGO | S_IWUSR);
170MODULE_PARM_DESC(disable_logger, "Disable launch of user space logger");
171
172/*
173 * shared between this module and mgt.c as this is the kobject referring to
174 * /sys/wifi directory. Core driver is called 1st we create the directory
175 * here and share the kobject, so in mgt.c wifi driver can create
176 * /sys/wif/mac_addr using sysfs_create_file api using the kobject
177 *
178 * If both modules tried to create the dir we were getting kernel panic
179 * failure due to kobject associated with dir already existed
180 */
181static struct kobject *wifi_kobj_ref;
182static int refcount;
183static ssize_t sysfs_show_memdump(struct kobject *kobj, struct kobj_attribute *attr,
184 char *buf);
185static ssize_t sysfs_store_memdump(struct kobject *kobj, struct kobj_attribute *attr,
186 const char *buf, size_t count);
187static struct kobj_attribute memdump_attr =
188 __ATTR(memdump, 0660, sysfs_show_memdump, sysfs_store_memdump);
189
190
191#ifdef CONFIG_SCSC_LOG_COLLECTION
192static int mxman_minimoredump_collect(struct scsc_log_collector_client *collect_client, size_t size)
193{
194 int ret = 0;
195 struct mxman *mxman = (struct mxman *) collect_client->prv;
196
197 if (!mxman || !mxman->start_dram)
198 return ret;
199
200 SCSC_TAG_INFO(MXMAN, "Collecting Minimoredump runtime_length %d fw_image_size %d\n",
201 mxman->fwhdr.fw_runtime_length, mxman->fw_image_size);
202 /* collect RAM sections of FW */
203 ret = scsc_log_collector_write(mxman->start_dram + mxman->fw_image_size,
204 mxman->fwhdr.fw_runtime_length - mxman->fw_image_size, 1);
205
206 return ret;
207}
208
209struct scsc_log_collector_client mini_moredump_client = {
210 .name = "minimoredump",
211 .type = SCSC_LOG_MINIMOREDUMP,
212 .collect_init = NULL,
213 .collect = mxman_minimoredump_collect,
214 .collect_end = NULL,
215 .prv = NULL,
216};
217#endif
218
219/* Retrieve memdump in sysfs global */
220static ssize_t sysfs_show_memdump(struct kobject *kobj,
221 struct kobj_attribute *attr,
222 char *buf)
223{
224 return sprintf(buf, "%d\n", memdump);
225}
226
227/* Update memdump in sysfs global */
228static ssize_t sysfs_store_memdump(struct kobject *kobj,
229 struct kobj_attribute *attr,
230 const char *buf,
231 size_t count)
232{
233 int r;
234
235 r = kstrtoint(buf, 10, &memdump);
236 if (r < 0)
237 memdump = -1;
238
239 switch (memdump) {
240 case 0:
241 case 2:
242 disable_recovery_from_memdump_file = false;
243 break;
244 case 3:
245 default:
246 disable_recovery_from_memdump_file = true;
247 break;
248 }
249
250 SCSC_TAG_INFO(MXMAN, "memdump: %d\n", memdump);
251
252 return (r == 0) ? count : 0;
253}
254
255struct kobject *mxman_wifi_kobject_ref_get(void)
256{
257 if (refcount++ == 0) {
258 /* Create sysfs directory /sys/wifi */
259 wifi_kobj_ref = kobject_create_and_add("wifi", NULL);
260 kobject_get(wifi_kobj_ref);
261 kobject_uevent(wifi_kobj_ref, KOBJ_ADD);
262 SCSC_TAG_INFO(MXMAN, "wifi_kobj_ref: 0x%p\n", wifi_kobj_ref);
263 WARN_ON(refcount == 0);
264 }
265 return wifi_kobj_ref;
266}
267EXPORT_SYMBOL(mxman_wifi_kobject_ref_get);
268
269void mxman_wifi_kobject_ref_put(void)
270{
271 if (--refcount == 0) {
272 kobject_put(wifi_kobj_ref);
273 kobject_uevent(wifi_kobj_ref, KOBJ_REMOVE);
274 wifi_kobj_ref = NULL;
275 WARN_ON(refcount < 0);
276 }
277}
278EXPORT_SYMBOL(mxman_wifi_kobject_ref_put);
279
280/* Register memdump override */
281void mxman_create_sysfs_memdump(void)
282{
283 int r;
284 struct kobject *kobj_ref = mxman_wifi_kobject_ref_get();
285
286 SCSC_TAG_INFO(MXMAN, "kobj_ref: 0x%p\n", kobj_ref);
287
288 if (kobj_ref) {
289 /* Create sysfs file /sys/wifi/memdump */
290 r = sysfs_create_file(kobj_ref, &memdump_attr.attr);
291 if (r) {
292 /* Failed, so clean up dir */
293 SCSC_TAG_ERR(MXMAN, "Can't create /sys/wifi/memdump\n");
294 mxman_wifi_kobject_ref_put();
295 return;
296 }
297 } else {
298 SCSC_TAG_ERR(MXMAN, "failed to create /sys/wifi directory");
299 }
300}
301
302/* Unregister memdump override */
303void mxman_destroy_sysfs_memdump(void)
304{
305 if (!wifi_kobj_ref)
306 return;
307
308 /* Destroy /sys/wifi/memdump file */
309 sysfs_remove_file(wifi_kobj_ref, &memdump_attr.attr);
310
311 /* Destroy /sys/wifi virtual dir */
312 mxman_wifi_kobject_ref_put();
313}
314
315/* Track when WLBT reset fails to allow debug */
316bool reset_failed;
317static u64 reset_failed_time;
318
319/* Status of FM driver request, which persists beyond the lifecyle
320 * of the scsx_mx driver.
321 */
322#ifdef CONFIG_SCSC_FM
323static u32 is_fm_on;
324#endif
325
326static int firmware_runtime_flags;
327static int syserr_command;
328/**
329 * This mxman reference is initialized/nullified via mxman_init/deinit
330 * called by scsc_mx_create/destroy on module probe/remove.
331 */
332static struct mxman *active_mxman;
333static bool send_fw_config_to_active_mxman(uint32_t fw_runtime_flags);
334static bool send_syserr_cmd_to_active_mxman(u32 syserr_cmd);
335
336static int fw_runtime_flags_setter(const char *val, const struct kernel_param *kp)
337{
338 int ret = -EINVAL;
339 uint32_t fw_runtime_flags = 0;
340
341 if (!val)
342 return ret;
343 ret = kstrtouint(val, 10, &fw_runtime_flags);
344 if (!ret) {
345 if (send_fw_config_to_active_mxman(fw_runtime_flags))
346 firmware_runtime_flags = fw_runtime_flags;
347 else
348 ret = -EINVAL;
349 }
350 return ret;
351}
352
353/**
354 * We don't bother to keep an updated copy of the runtime flags effectively
355 * currently set into FW...we should add a new message answer handling both in
356 * Kenrel and FW side to be sure and this is just to easy debug at the end.
357 */
358static struct kernel_param_ops fw_runtime_kops = {
359 .set = fw_runtime_flags_setter,
360 .get = NULL
361};
362
363module_param_cb(firmware_runtime_flags, &fw_runtime_kops, NULL, 0200);
364MODULE_PARM_DESC(firmware_runtime_flags,
365 "0 = Proceed as normal (default); nnn = Provides FW runtime flags bitmask: unknown bits will be ignored.");
366
367static int syserr_setter(const char *val, const struct kernel_param *kp)
368{
369 int ret = -EINVAL;
370 u32 syserr_cmd = 0;
371
372 if (!val)
373 return ret;
374 ret = kstrtouint(val, 10, &syserr_cmd);
375 if (!ret) {
376 u8 sub_system = (u8)(syserr_cmd / 10);
377 u8 level = (u8)(syserr_cmd % 10);
378
379 if (((sub_system > 2) && (sub_system < 8)) || (sub_system > 8) || (level > 7))
380 ret = -EINVAL;
381 else if (send_syserr_cmd_to_active_mxman(syserr_cmd))
382 syserr_command = syserr_cmd;
383 else
384 ret = -EINVAL;
385 }
386 return ret;
387}
388
389static struct kernel_param_ops syserr_kops = {
390 .set = syserr_setter,
391 .get = NULL
392};
393
394module_param_cb(syserr_command, &syserr_kops, NULL, 0200);
395MODULE_PARM_DESC(syserr_command,
396 "Decimal XY - Trigger Type X(0,1,2,8), Level Y(1-7). Some combinations not supported");
397
398/**
399 * Maxwell Agent Management Messages.
400 *
401 * TODO: common defn with firmware, generated.
402 *
403 * The numbers here *must* match the firmware!
404 */
405enum {
406 MM_START_IND = 0,
407 MM_HALT_REQ = 1,
408 MM_FORCE_PANIC = 2,
409 MM_HOST_SUSPEND = 3,
410 MM_HOST_RESUME = 4,
411 MM_FW_CONFIG = 5,
412 MM_HALT_RSP = 6,
413 MM_FM_RADIO_CONFIG = 7,
414 MM_LERNA_CONFIG = 8,
415 MM_SYSERR_IND = 9,
416 MM_SYSERR_CMD = 10
417} ma_msg;
418
419/**
420 * Format of the Maxwell agent messages
421 * on the Maxwell management transport stream.
422 */
423struct ma_msg_packet {
424
425 uint8_t ma_msg; /* Message from ma_msg enum */
426 uint32_t arg; /* Optional arg set by f/w in some to-host messages */
427} __packed;
428
429/**
430 * Special case Maxwell management, carrying FM radio configuration structure
431 */
432struct ma_msg_packet_fm_radio_config {
433
434 uint8_t ma_msg; /* Message from ma_msg enum */
435 struct wlbt_fm_params fm_params; /* FM Radio parameters */
436} __packed;
437
438static bool send_fw_config_to_active_mxman(uint32_t fw_runtime_flags)
439{
440 bool ret = false;
441 struct srvman *srvman = NULL;
442
443 SCSC_TAG_INFO(MXMAN, "\n");
444 if (!active_mxman) {
445 SCSC_TAG_ERR(MXMAN, "Active MXMAN NOT FOUND...cannot send running FW config.\n");
446 return ret;
447 }
448
449 mutex_lock(&active_mxman->mxman_mutex);
450 srvman = scsc_mx_get_srvman(active_mxman->mx);
451 if (srvman && srvman->error) {
452 mutex_unlock(&active_mxman->mxman_mutex);
453 SCSC_TAG_INFO(MXMAN, "Called during error - ignore\n");
454 return ret;
455 }
456
457 if (active_mxman->mxman_state == MXMAN_STATE_STARTED) {
458 struct ma_msg_packet message = { .ma_msg = MM_FW_CONFIG,
459 .arg = fw_runtime_flags };
460
461 SCSC_TAG_INFO(MXMAN, "MM_FW_CONFIG - firmware_runtime_flags:%d\n", message.arg);
462 mxmgmt_transport_send(scsc_mx_get_mxmgmt_transport(active_mxman->mx),
463 MMTRANS_CHAN_ID_MAXWELL_MANAGEMENT, &message,
464 sizeof(message));
465 ret = true;
466 } else {
467 SCSC_TAG_INFO(MXMAN, "MXMAN is NOT STARTED...cannot send MM_FW_CONFIG msg.\n");
468 }
469 mutex_unlock(&active_mxman->mxman_mutex);
470
471 return ret;
472}
473
474static bool send_syserr_cmd_to_active_mxman(u32 syserr_cmd)
475{
476 bool ret = false;
477 struct srvman *srvman = NULL;
478
479 SCSC_TAG_INFO(MXMAN, "\n");
480 if (!active_mxman) {
481 SCSC_TAG_ERR(MXMAN, "Active MXMAN NOT FOUND...cannot send running FW config.\n");
482 return ret;
483 }
484
485 mutex_lock(&active_mxman->mxman_mutex);
486 srvman = scsc_mx_get_srvman(active_mxman->mx);
487 if (srvman && srvman->error) {
488 mutex_unlock(&active_mxman->mxman_mutex);
489 SCSC_TAG_INFO(MXMAN, "Called during error - ignore\n");
490 return ret;
491 }
492
493 if (active_mxman->mxman_state == MXMAN_STATE_STARTED) {
494 struct ma_msg_packet message = { .ma_msg = MM_SYSERR_CMD,
495 .arg = syserr_cmd};
496
497 SCSC_TAG_INFO(MXMAN, "MM_SYSERR_CMD - Args %02d\n", message.arg);
498 mxmgmt_transport_send(scsc_mx_get_mxmgmt_transport(active_mxman->mx),
499 MMTRANS_CHAN_ID_MAXWELL_MANAGEMENT, &message,
500 sizeof(message));
501 ret = true;
502 } else {
503 SCSC_TAG_INFO(MXMAN, "MXMAN is NOT STARTED...cannot send MM_SYSERR_CMD msg.\n");
504 }
505 mutex_unlock(&active_mxman->mxman_mutex);
506
507 return ret;
508}
509
510#ifdef CONFIG_SCSC_FM
511static bool send_fm_params_to_active_mxman(struct wlbt_fm_params *params)
512{
513 bool ret = false;
514 struct srvman *srvman = NULL;
515
516 SCSC_TAG_INFO(MXMAN, "\n");
517 if (!active_mxman) {
518 SCSC_TAG_ERR(MXMAN, "Active MXMAN NOT FOUND...cannot send FM params\n");
519 return false;
520 }
521
522 mutex_lock(&active_mxman->mxman_mutex);
523 srvman = scsc_mx_get_srvman(active_mxman->mx);
524 if (srvman && srvman->error) {
525 mutex_unlock(&active_mxman->mxman_mutex);
526 SCSC_TAG_INFO(MXMAN, "Called during error - ignore\n");
527 return false;
528 }
529
530 if (active_mxman->mxman_state == MXMAN_STATE_STARTED) {
531 struct ma_msg_packet_fm_radio_config message = { .ma_msg = MM_FM_RADIO_CONFIG,
532 .fm_params = *params };
533
534 SCSC_TAG_INFO(MXMAN, "MM_FM_RADIO_CONFIG\n");
535 mxmgmt_transport_send(scsc_mx_get_mxmgmt_transport(active_mxman->mx),
536 MMTRANS_CHAN_ID_MAXWELL_MANAGEMENT, &message,
537 sizeof(message));
538
539 ret = true; /* Success */
540 } else
541 SCSC_TAG_INFO(MXMAN, "MXMAN is NOT STARTED...cannot send MM_FM_RADIO_CONFIG msg.\n");
542
543 mutex_unlock(&active_mxman->mxman_mutex);
544
545 return ret;
546}
547#endif
548
549static void mxman_stop(struct mxman *mxman);
550static void print_mailboxes(struct mxman *mxman);
551#ifdef CONFIG_SCSC_WLBTD
552static int _mx_exec(char *prog, int wait_exec) __attribute__((unused));
553#else
554static int _mx_exec(char *prog, int wait_exec);
555#endif
556static int wait_for_mm_msg(struct mxman *mxman, struct completion *mm_msg_completion, ulong timeout_ms)
557{
558 int r;
559
560 (void)mxman; /* unused */
561
562 if (timeout_ms == 0) {
563 /* Zero implies infinite wait */
564 r = wait_for_completion_interruptible(mm_msg_completion);
565 /* r = -ERESTARTSYS if interrupted, 0 if completed */
566 return r;
567 }
568 r = wait_for_completion_timeout(mm_msg_completion, msecs_to_jiffies(timeout_ms));
569 if (r == 0) {
570 SCSC_TAG_ERR(MXMAN, "timeout\n");
571 return -ETIMEDOUT;
572 }
573
574 return 0;
575}
576
577static int wait_for_mm_msg_start_ind(struct mxman *mxman)
578{
579 return wait_for_mm_msg(mxman, &mxman->mm_msg_start_ind_completion, mm_completion_timeout_ms);
580}
581
582static int wait_for_mm_msg_halt_rsp(struct mxman *mxman)
583{
584 int r;
585 (void)mxman; /* unused */
586
587 if (MM_HALT_RSP_TIMEOUT_MS == 0) {
588 /* Zero implies infinite wait */
589 r = wait_for_completion_interruptible(&mxman->mm_msg_halt_rsp_completion);
590 /* r = -ERESTARTSYS if interrupted, 0 if completed */
591 return r;
592 }
593
594 r = wait_for_completion_timeout(&mxman->mm_msg_halt_rsp_completion, msecs_to_jiffies(MM_HALT_RSP_TIMEOUT_MS));
595 if (r)
596 SCSC_TAG_INFO(MXMAN, "Received MM_HALT_RSP from firmware");
597
598 return r;
599}
600
601#ifndef CONFIG_SCSC_WLBTD
602static int coredump_helper(void)
603{
604 int r;
605 int i;
606 static char mdbin[128];
607
608 /* Determine path to moredump helper script */
609 r = mx140_exe_path(NULL, mdbin, sizeof(mdbin), "moredump");
610 if (r) {
611 SCSC_TAG_ERR(MXMAN, "moredump path error\n");
612 return r;
613 }
614
615 for (i = 0; i < 20; i++) {
616 r = _mx_exec(mdbin, UMH_WAIT_PROC);
617 if (r != -EBUSY)
618 break;
619 /* If the usermode helper fails with -EBUSY, the userspace is
620 * likely still frozen from suspend. Back off and retry.
621 */
622 SCSC_TAG_INFO(MXMAN, "waiting for userspace to thaw...\n");
623 msleep(1000);
624 }
625
626 /* Application return codes are in the MSB */
627 if (r > 0xffL)
628 SCSC_TAG_INFO(MXMAN, "moredump.bin exit(%ld), check syslog\n", (r & 0xff00L) >> 8);
629
630 return r;
631}
632#endif
633
634static int send_mm_msg_stop_blocking(struct mxman *mxman)
635{
636 int r;
637#ifdef CONFIG_SCSC_FM
638 struct ma_msg_packet message = { .ma_msg = MM_HALT_REQ,
639 .arg = mxman->on_halt_ldos_on };
640#else
641 struct ma_msg_packet message = { .ma_msg = MM_HALT_REQ };
642#endif
643 mxmgmt_transport_send(scsc_mx_get_mxmgmt_transport(mxman->mx), MMTRANS_CHAN_ID_MAXWELL_MANAGEMENT, &message, sizeof(message));
644
645 r = wait_for_mm_msg_halt_rsp(mxman);
646 if (r) {
647 /*
648 * MM_MSG_HALT_RSP is not implemented in all versions of firmware, so don't treat it's non-arrival
649 * as an error
650 */
651 SCSC_TAG_INFO(MXMAN, "wait_for_MM_HALT_RSP completed");
652 }
653
654 return 0;
655}
656
657static char *chip_version(u32 rf_hw_ver)
658{
659 switch (rf_hw_ver & 0x00ff) {
660 default:
661 break;
662 case 0x00b0:
663 if ((rf_hw_ver & 0xff00) > 0x1000)
664 return "S610/S611";
665 else
666 return "S610";
667 case 0x00b1:
668 return "S612";
669 case 0x00b2:
670 return "S620";
671 case 0x0000:
672#ifndef CONFIG_SOC_EXYNOS9610
673 return "Error: check if RF chip is present";
674#else
675 return "Unknown";
676#endif
677 }
678 return "Unknown";
679}
680
681/*
682 * This function is used in this file and in mxproc.c to generate consistent
683 * RF CHIP VERSION string for logging on console and for storing the same
684 * in proc/drivers/mxman_info/rf_chip_version file.
685 */
686int mxman_print_rf_hw_version(struct mxman *mxman, char *buf, const size_t bufsz)
687{
688 int r;
689
690 r = snprintf(buf, bufsz, "RF_CHIP_VERSION: 0x%04x: %s (0x%02x), EVT%x.%x\n",
691 mxman->rf_hw_ver,
692 chip_version(mxman->rf_hw_ver), (mxman->rf_hw_ver & 0x00ff),
693 ((mxman->rf_hw_ver >> 12) & 0xfU), ((mxman->rf_hw_ver >> 8) & 0xfU));
694
695 return r;
696}
697
698static void mxman_print_versions(struct mxman *mxman)
699{
700 char buf[80];
701
702 memset(buf, '\0', sizeof(buf));
703
704 (void)mxman_print_rf_hw_version(mxman, buf, sizeof(buf));
705
706 SCSC_TAG_INFO(MXMAN, "%s", buf);
707 SCSC_TAG_INFO(MXMAN, "WLBT FW: %s\n", mxman->fw_build_id);
708 SCSC_TAG_INFO(MXMAN, "WLBT Driver: %d.%d.%d.%d\n",
709 SCSC_RELEASE_PRODUCT, SCSC_RELEASE_ITERATION, SCSC_RELEASE_CANDIDATE, SCSC_RELEASE_POINT);
710#ifdef CONFIG_SCSC_WLBTD
711 scsc_wlbtd_get_and_print_build_type();
712#endif
713}
714
715/** Receive handler for messages from the FW along the maxwell management transport */
716static void mxman_message_handler(const void *message, void *data)
717{
718 struct mxman *mxman = (struct mxman *)data;
719
720 /* Forward the message to the applicable service to deal with */
721 const struct ma_msg_packet *msg = message;
722
723 switch (msg->ma_msg) {
724 case MM_START_IND:
725 /* The arg can be used to determine the WLBT/S610 hardware revision */
726 SCSC_TAG_INFO(MXMAN, "Received MM_START_IND message from the firmware, arg=0x%04x\n", msg->arg);
727 mxman->rf_hw_ver = msg->arg;
728 mxman_print_versions(mxman);
729 atomic_inc(&mxman->boot_count);
730 complete(&mxman->mm_msg_start_ind_completion);
731 break;
732 case MM_HALT_RSP:
733 complete(&mxman->mm_msg_halt_rsp_completion);
734 SCSC_TAG_INFO(MXMAN, "Received MM_HALT_RSP message from the firmware\n");
735 break;
736 case MM_LERNA_CONFIG:
737 /* Message response to a firmware configuration query. */
738 SCSC_TAG_INFO(MXMAN, "Received MM_LERNA_CONFIG message from firmware\n");
739 scsc_lerna_response(message);
740 break;
741 case MM_SYSERR_IND:
742 /* System Error report from firmware */
743 SCSC_TAG_INFO(MXMAN, "Received MM_SYSERR_IND message from firmware\n");
744 mx_syserr_handler(mxman, message);
745 break;
746 default:
747 /* HERE: Unknown message, raise fault */
748 SCSC_TAG_WARNING(MXMAN, "Received unknown message from the firmware: msg->ma_msg=%d\n", msg->ma_msg);
749 break;
750 }
751}
752
753/*
754 * This function calulates and checks two or three (depending on crc32_over_binary flag)
755 * crc32 values in the firmware header. The function will check crc32 over the firmware binary
756 * (i.e. everything in the file following the header) only if the crc32_over_binary is set to 'true'.
757 * This includes initialised data regions so it can be used to check when loading but will not be
758 * meaningful once execution starts.
759 */
760static int do_fw_crc32_checks(char *fw, u32 fw_image_size, struct fwhdr *fwhdr, bool crc32_over_binary)
761{
762 int r;
763
764 if ((fwhdr->fw_crc32 == 0 || fwhdr->header_crc32 == 0 || fwhdr->const_crc32 == 0) && crc_check_allow_none == 0) {
765 SCSC_TAG_ERR(MXMAN, "error: CRC is missing fw_crc32=%d header_crc32=%d crc_check_allow_none=%d\n",
766 fwhdr->fw_crc32, fwhdr->header_crc32, crc_check_allow_none);
767 return -EINVAL;
768 }
769
770 if (fwhdr->header_crc32 == 0 && crc_check_allow_none == 1) {
771 SCSC_TAG_INFO(MXMAN, "Skipping CRC check header_crc32=%d crc_check_allow_none=%d\n",
772 fwhdr->header_crc32, crc_check_allow_none);
773 } else {
774 /*
775 * CRC-32-IEEE of all preceding header fields (including other CRCs).
776 * Always the last word in the header.
777 */
778 r = fwimage_check_fw_header_crc(fw, fwhdr->hdr_length, fwhdr->header_crc32);
779 if (r) {
780 SCSC_TAG_ERR(MXMAN, "fwimage_check_fw_header_crc() failed\n");
781 return r;
782 }
783 }
784
785 if (fwhdr->const_crc32 == 0 && crc_check_allow_none == 1) {
786 SCSC_TAG_INFO(MXMAN, "Skipping CRC check const_crc32=%d crc_check_allow_none=%d\n",
787 fwhdr->const_crc32, crc_check_allow_none);
788 } else {
789 /*
790 * CRC-32-IEEE over the constant sections grouped together at start of firmware binary.
791 * This CRC should remain valid during execution. It can be used by run-time checker on
792 * host to detect firmware corruption (not all memory masters are subject to MPUs).
793 */
794 r = fwimage_check_fw_const_section_crc(fw, fwhdr->const_crc32, fwhdr->const_fw_length, fwhdr->hdr_length);
795 if (r) {
796 SCSC_TAG_ERR(MXMAN, "fwimage_check_fw_const_section_crc() failed\n");
797 return r;
798 }
799 }
800
801 if (crc32_over_binary) {
802 if (fwhdr->fw_crc32 == 0 && crc_check_allow_none == 1)
803 SCSC_TAG_INFO(MXMAN, "Skipping CRC check fw_crc32=%d crc_check_allow_none=%d\n",
804 fwhdr->fw_crc32, crc_check_allow_none);
805 else {
806 /*
807 * CRC-32-IEEE over the firmware binary (i.e. everything
808 * in the file following this header).
809 * This includes initialised data regions so it can be used to
810 * check when loading but will not be meaningful once execution starts.
811 */
812 r = fwimage_check_fw_crc(fw, fw_image_size, fwhdr->hdr_length, fwhdr->fw_crc32);
813 if (r) {
814 SCSC_TAG_ERR(MXMAN, "fwimage_check_fw_crc() failed\n");
815 return r;
816 }
817 }
818 }
819
820 return 0;
821}
822
823
824static void fw_crc_wq_start(struct mxman *mxman)
825{
826 if (mxman->check_crc && crc_check_period_ms)
827 queue_delayed_work(mxman->fw_crc_wq, &mxman->fw_crc_work, msecs_to_jiffies(crc_check_period_ms));
828}
829
830
831static void fw_crc_work_func(struct work_struct *work)
832{
833 int r;
834 struct mxman *mxman = container_of((struct delayed_work *)work, struct mxman, fw_crc_work);
835
836 r = do_fw_crc32_checks(mxman->fw, mxman->fw_image_size, &mxman->fwhdr, false);
837 if (r) {
838 SCSC_TAG_ERR(MXMAN, "do_fw_crc32_checks() failed r=%d\n", r);
839 mxman_fail(mxman, SCSC_PANIC_CODE_HOST << 15, __func__);
840 return;
841 }
842 fw_crc_wq_start(mxman);
843}
844
845
846static void fw_crc_wq_init(struct mxman *mxman)
847{
848 mxman->fw_crc_wq = create_singlethread_workqueue("fw_crc_wq");
849 INIT_DELAYED_WORK(&mxman->fw_crc_work, fw_crc_work_func);
850}
851
852static void fw_crc_wq_stop(struct mxman *mxman)
853{
854 mxman->check_crc = false;
855 cancel_delayed_work(&mxman->fw_crc_work);
856 flush_workqueue(mxman->fw_crc_wq);
857}
858
859static void fw_crc_wq_deinit(struct mxman *mxman)
860{
861 fw_crc_wq_stop(mxman);
862 destroy_workqueue(mxman->fw_crc_wq);
863}
864
865static int transports_init(struct mxman *mxman)
866{
867 struct mxconf *mxconf;
868 int r;
869 struct scsc_mx *mx = mxman->mx;
870
871 /* Initialise mx management stack */
872 r = mxmgmt_transport_init(scsc_mx_get_mxmgmt_transport(mx), mx);
873 if (r) {
874 SCSC_TAG_ERR(MXMAN, "mxmgmt_transport_init() failed %d\n", r);
875 return r;
876 }
877
878 /* Initialise gdb transport for cortex-R4 */
879 r = gdb_transport_init(scsc_mx_get_gdb_transport_r4(mx), mx, GDB_TRANSPORT_R4);
880 if (r) {
881 SCSC_TAG_ERR(MXMAN, "gdb_transport_init() failed %d\n", r);
882 mxmgmt_transport_release(scsc_mx_get_mxmgmt_transport(mx));
883 return r;
884 }
885
886 /* Initialise gdb transport for cortex-M4 */
887 r = gdb_transport_init(scsc_mx_get_gdb_transport_m4(mx), mx, GDB_TRANSPORT_M4);
888 if (r) {
889 SCSC_TAG_ERR(MXMAN, "gdb_transport_init() failed %d\n", r);
890 gdb_transport_release(scsc_mx_get_gdb_transport_r4(mx));
891 mxmgmt_transport_release(scsc_mx_get_mxmgmt_transport(mx));
892 return r;
893 }
894#ifdef CONFIG_SCSC_MX450_GDB_SUPPORT
895 /* Initialise gdb transport for cortex-M4 */
896 r = gdb_transport_init(scsc_mx_get_gdb_transport_m4_1(mx), mx, GDB_TRANSPORT_M4_1);
897 if (r) {
898 SCSC_TAG_ERR(MXMAN, "gdb_transport_init() failed %d\n", r);
899 gdb_transport_release(scsc_mx_get_gdb_transport_r4(mx));
900 mxmgmt_transport_release(scsc_mx_get_mxmgmt_transport(mx));
901 return r;
902 }
903#endif
904
905 /* Initialise mxlog transport */
906 r = mxlog_transport_init(scsc_mx_get_mxlog_transport(mx), mx);
907 if (r) {
908 SCSC_TAG_ERR(MXMAN, "mxlog_transport_init() failed %d\n", r);
909 gdb_transport_release(scsc_mx_get_gdb_transport_m4(mx));
910#ifdef CONFIG_SCSC_MX450_GDB_SUPPORT
911 gdb_transport_release(scsc_mx_get_gdb_transport_m4_1(mx));
912#endif
913 gdb_transport_release(scsc_mx_get_gdb_transport_r4(mx));
914 mxmgmt_transport_release(scsc_mx_get_mxmgmt_transport(mx));
915 return r;
916 }
917
918 /*
919 * Allocate & Initialise Infrastructre Config Structure
920 * including the mx management stack config information.
921 */
922 mxconf = miframman_alloc(scsc_mx_get_ramman(mx), sizeof(struct mxconf), 4, MIFRAMMAN_OWNER_COMMON);
923 if (!mxconf) {
924 SCSC_TAG_ERR(MXMAN, "miframman_alloc() failed\n");
925 gdb_transport_release(scsc_mx_get_gdb_transport_m4(mx));
926#ifdef CONFIG_SCSC_MX450_GDB_SUPPORT
927 gdb_transport_release(scsc_mx_get_gdb_transport_m4_1(mx));
928#endif
929 gdb_transport_release(scsc_mx_get_gdb_transport_r4(mx));
930 mxmgmt_transport_release(scsc_mx_get_mxmgmt_transport(mx));
931 mxlog_transport_release(scsc_mx_get_mxlog_transport(mx));
932 return -ENOMEM;
933 }
934 mxman->mxconf = mxconf;
935 mxconf->magic = MXCONF_MAGIC;
936 mxconf->version.major = MXCONF_VERSION_MAJOR;
937 mxconf->version.minor = MXCONF_VERSION_MINOR;
938
939 /* Pass pre-existing FM status to FW */
940 mxconf->flags = 0;
941#ifdef CONFIG_SCSC_FM
942 mxconf->flags |= is_fm_on ? MXCONF_FLAGS_FM_ON : 0;
943#endif
944 SCSC_TAG_INFO(MXMAN, "mxconf flags 0x%08x\n", mxconf->flags);
945
946 /* serialise mxmgmt transport */
947 mxmgmt_transport_config_serialise(scsc_mx_get_mxmgmt_transport(mx), &mxconf->mx_trans_conf);
948 /* serialise Cortex-R4 gdb transport */
949 gdb_transport_config_serialise(scsc_mx_get_gdb_transport_r4(mx), &mxconf->mx_trans_conf_gdb_r4);
950 /* serialise Cortex-M4 gdb transport */
951 gdb_transport_config_serialise(scsc_mx_get_gdb_transport_m4(mx), &mxconf->mx_trans_conf_gdb_m4);
952
953 /* Default to Fleximac M4_1 monitor channel not in use.
954 * Allows CONFIG_SCSC_MX450_GDB_SUPPORT to be turned off in Kconfig even though mxconf
955 * struct v5 defines M4_1 channel
956 */
957 mxconf->mx_trans_conf_gdb_m4_1.from_ap_stream_conf.buf_conf.buffer_loc = 0;
958#ifdef CONFIG_SCSC_MX450_GDB_SUPPORT
959 /* serialise Cortex-M4 gdb transport */
960 gdb_transport_config_serialise(scsc_mx_get_gdb_transport_m4_1(mx), &mxconf->mx_trans_conf_gdb_m4_1);
961#endif
962 /* serialise mxlog transport */
963 mxlog_transport_config_serialise(scsc_mx_get_mxlog_transport(mx), &mxconf->mxlogconf);
964 SCSC_TAG_DEBUG(MXMAN, "read_bit_idx=%d write_bit_idx=%d buffer=%p num_packets=%d packet_size=%d read_index=%d write_index=%d\n",
965 scsc_mx_get_mxlog_transport(mx)->mif_stream.read_bit_idx,
966 scsc_mx_get_mxlog_transport(mx)->mif_stream.write_bit_idx,
967 scsc_mx_get_mxlog_transport(mx)->mif_stream.buffer.buffer,
968 scsc_mx_get_mxlog_transport(mx)->mif_stream.buffer.num_packets,
969 scsc_mx_get_mxlog_transport(mx)->mif_stream.buffer.packet_size,
970 *scsc_mx_get_mxlog_transport(mx)->mif_stream.buffer.read_index,
971 *scsc_mx_get_mxlog_transport(mx)->mif_stream.buffer.write_index
972 );
973
974 /* Need to initialise fwconfig or else random data can make firmware data abort. */
975 mxconf->fwconfig.offset = 0;
976 mxconf->fwconfig.size = 0;
977#ifdef CONFIG_SCSC_COMMON_HCF
978 /* Load Common Config HCF */
979 mxfwconfig_load(mxman->mx, &mxconf->fwconfig);
980#endif
981 return 0;
982}
983
984static void transports_release(struct mxman *mxman)
985{
986 mxlog_transport_release(scsc_mx_get_mxlog_transport(mxman->mx));
987 mxmgmt_transport_release(scsc_mx_get_mxmgmt_transport(mxman->mx));
988 gdb_transport_release(scsc_mx_get_gdb_transport_r4(mxman->mx));
989 gdb_transport_release(scsc_mx_get_gdb_transport_m4(mxman->mx));
990#ifdef CONFIG_SCSC_MX450_GDB_SUPPORT
991 gdb_transport_release(scsc_mx_get_gdb_transport_m4_1(mxman->mx));
992#endif
993 miframman_free(scsc_mx_get_ramman(mxman->mx), mxman->mxconf);
994}
995
996static void mbox_init(struct mxman *mxman, u32 firmware_entry_point)
997{
998 u32 *mbox0;
999 u32 *mbox1;
1000 u32 *mbox2;
1001 u32 *mbox3;
1002 scsc_mifram_ref mifram_ref;
1003 struct scsc_mx *mx = mxman->mx;
1004 struct scsc_mif_abs *mif = scsc_mx_get_mif_abs(mxman->mx);
1005
1006 /* Place firmware entry address in MIF MBOX 0 so R4 ROM knows where to jump to! */
1007 mbox0 = mifmboxman_get_mbox_ptr(scsc_mx_get_mboxman(mx), mif, MBOX_INDEX_0);
1008 mbox1 = mifmboxman_get_mbox_ptr(scsc_mx_get_mboxman(mx), mif, MBOX_INDEX_1);
1009
1010 /* Write (and flush) entry point to MailBox 0, config address to MBOX 1 */
1011 *mbox0 = firmware_entry_point;
1012 mif->get_mifram_ref(mif, mxman->mxconf, &mifram_ref);
1013 *mbox1 = mifram_ref; /* must be R4-relative address here */
1014 /* CPU memory barrier */
1015 wmb();
1016 /*
1017 * write the magic number "0xbcdeedcb" to MIF Mailbox #2 &
1018 * copy the firmware_startup_flags to MIF Mailbox #3 before starting (reset = 0) the R4
1019 */
1020 mbox2 = mifmboxman_get_mbox_ptr(scsc_mx_get_mboxman(mx), mif, MBOX_INDEX_2);
1021 *mbox2 = MBOX2_MAGIC_NUMBER;
1022 mbox3 = mifmboxman_get_mbox_ptr(scsc_mx_get_mboxman(mx), mif, MBOX_INDEX_3);
1023 *mbox3 = firmware_startup_flags;
1024}
1025
1026static int fwhdr_init(char *fw, struct fwhdr *fwhdr, bool *fwhdr_parsed_ok, bool *check_crc)
1027{
1028 /*
1029 * Validate the fw image including checking the firmware header, majic #, version, checksum so on
1030 * then do CRC on the entire image
1031 *
1032 * Derive some values from header -
1033 *
1034 * PORT: assumes little endian
1035 */
1036 if (skip_header)
1037 *fwhdr_parsed_ok = false; /* Allows the forced start address to be used */
1038 else
1039 *fwhdr_parsed_ok = fwhdr_parse(fw, fwhdr);
1040 *check_crc = false;
1041 if (*fwhdr_parsed_ok) {
1042 SCSC_TAG_INFO(MXMAN, "FW HEADER version: hdr_major: %d hdr_minor: %d\n", fwhdr->hdr_major, fwhdr->hdr_minor);
1043 switch (fwhdr->hdr_major) {
1044 case 0:
1045 switch (fwhdr->hdr_minor) {
1046 case 2:
1047 *check_crc = true;
1048 break;
1049 default:
1050 SCSC_TAG_ERR(MXMAN, "Unsupported FW HEADER version: hdr_major: %d hdr_minor: %d\n",
1051 fwhdr->hdr_major, fwhdr->hdr_minor);
1052 return -EINVAL;
1053 }
1054 break;
1055 case 1:
1056 *check_crc = true;
1057 break;
1058 default:
1059 SCSC_TAG_ERR(MXMAN, "Unsupported FW HEADER version: hdr_major: %d hdr_minor: %d\n",
1060 fwhdr->hdr_major, fwhdr->hdr_minor);
1061 return -EINVAL;
1062 }
1063 switch (fwhdr->fwapi_major) {
1064 case 0:
1065 switch (fwhdr->fwapi_minor) {
1066 case 2:
1067 SCSC_TAG_INFO(MXMAN, "FWAPI version: fwapi_major: %d fwapi_minor: %d\n",
1068 fwhdr->fwapi_major, fwhdr->fwapi_minor);
1069 break;
1070 default:
1071 SCSC_TAG_ERR(MXMAN, "Unsupported FWAPI version: fwapi_major: %d fwapi_minor: %d\n",
1072 fwhdr->fwapi_major, fwhdr->fwapi_minor);
1073 return -EINVAL;
1074 }
1075 break;
1076 default:
1077 SCSC_TAG_ERR(MXMAN, "Unsupported FWAPI version: fwapi_major: %d fwapi_minor: %d\n",
1078 fwhdr->fwapi_major, fwhdr->fwapi_minor);
1079 return -EINVAL;
1080 }
1081 } else {
1082 /* This is unidetified pre-header firmware - assume it is built to run at 0xb8000000 == 0 for bootrom */
1083 if (allow_unidentified_firmware) {
1084 SCSC_TAG_INFO(MXMAN, "Unidentified firmware override\n");
1085 fwhdr->firmware_entry_point = 0;
1086 fwhdr->fw_runtime_length = MX_FW_RUNTIME_LENGTH;
1087 } else {
1088 SCSC_TAG_ERR(MXMAN, "Unidentified firmware is not allowed\n");
1089 return -EINVAL;
1090 }
1091 }
1092 return 0;
1093}
1094
1095static int fw_init(struct mxman *mxman, void *start_dram, size_t size_dram, bool *fwhdr_parsed_ok)
1096{
1097 int r;
1098 char *build_id;
1099 char *ttid;
1100 u32 fw_image_size;
1101 struct fwhdr *fwhdr = &mxman->fwhdr;
1102 char *fw = start_dram;
1103
1104 r = mx140_file_download_fw(mxman->mx, start_dram, size_dram, &fw_image_size);
1105 if (r) {
1106 SCSC_TAG_ERR(MXMAN, "mx140_file_download_fw() failed (%d)\n", r);
1107 return r;
1108 }
1109
1110 r = fwhdr_init(fw, fwhdr, fwhdr_parsed_ok, &mxman->check_crc);
1111 if (r) {
1112 SCSC_TAG_ERR(MXMAN, "fwhdr_init() failed\n");
1113 return r;
1114 }
1115 mxman->fw = fw;
1116 mxman->fw_image_size = fw_image_size;
1117 if (mxman->check_crc) {
1118 /* do CRC on the entire image */
1119 r = do_fw_crc32_checks(fw, fw_image_size, &mxman->fwhdr, true);
1120 if (r) {
1121 SCSC_TAG_ERR(MXMAN, "do_fw_crc32_checks() failed\n");
1122 return r;
1123 }
1124 fw_crc_wq_start(mxman);
1125 }
1126
1127 if (*fwhdr_parsed_ok) {
1128 build_id = fwhdr_get_build_id(fw, fwhdr);
1129 if (build_id) {
1130 struct slsi_kic_service_info kic_info;
1131
1132 (void)snprintf(mxman->fw_build_id, sizeof(mxman->fw_build_id), "%s", build_id);
1133 SCSC_TAG_INFO(MXMAN, "Firmware BUILD_ID: %s\n", mxman->fw_build_id);
1134 memcpy(saved_fw_build_id, mxman->fw_build_id,
1135 sizeof(saved_fw_build_id));
1136
1137 (void) snprintf(kic_info.ver_str,
1138 min(sizeof(mxman->fw_build_id), sizeof(kic_info.ver_str)),
1139 "%s", mxman->fw_build_id);
1140 kic_info.fw_api_major = fwhdr->fwapi_major;
1141 kic_info.fw_api_minor = fwhdr->fwapi_minor;
1142 kic_info.release_product = SCSC_RELEASE_PRODUCT;
1143 kic_info.host_release_iteration = SCSC_RELEASE_ITERATION;
1144 kic_info.host_release_candidate = SCSC_RELEASE_CANDIDATE;
1145
1146 slsi_kic_service_information(slsi_kic_technology_type_common, &kic_info);
1147 } else
1148 SCSC_TAG_ERR(MXMAN, "Failed to get Firmware BUILD_ID\n");
1149
1150 ttid = fwhdr_get_ttid(fw, fwhdr);
1151 if (ttid) {
1152 (void)snprintf(mxman->fw_ttid, sizeof(mxman->fw_ttid), "%s", ttid);
1153 SCSC_TAG_INFO(MXMAN, "Firmware ttid: %s\n", mxman->fw_ttid);
1154 }
1155 }
1156
1157 SCSC_TAG_DEBUG(MXMAN, "firmware_entry_point=0x%x fw_runtime_length=%d\n", fwhdr->firmware_entry_point, fwhdr->fw_runtime_length);
1158
1159 return 0;
1160
1161}
1162
1163static int mxman_start(struct mxman *mxman)
1164{
1165 void *start_dram;
1166 size_t size_dram = MX_DRAM_SIZE;
1167 struct scsc_mif_abs *mif;
1168 struct fwhdr *fwhdr = &mxman->fwhdr;
1169 bool fwhdr_parsed_ok;
1170 void *start_mifram_heap;
1171 u32 length_mifram_heap;
1172 void *start_mifram_heap2;
1173 u32 length_mifram_heap2;
1174 int r;
1175
1176 if (reset_failed) {
1177 struct timeval tval = ns_to_timeval(reset_failed_time);
1178
1179 SCSC_TAG_ERR(MXMAN, "previous reset failed at [%6lu.%06ld], ignoring\n", tval.tv_sec, tval.tv_usec);
1180 return -EIO;
1181 }
1182
1183 (void)snprintf(mxman->fw_build_id, sizeof(mxman->fw_build_id), "unknown");
1184
1185 /* If the option is set to skip header, we must allow unidentified f/w */
1186 if (skip_header) {
1187 SCSC_TAG_INFO(MXMAN, "Ignoring firmware header block\n");
1188 allow_unidentified_firmware = true;
1189 }
1190
1191 mif = scsc_mx_get_mif_abs(mxman->mx);
1192 start_dram = mif->map(mif, &size_dram);
1193
1194 if (!start_dram) {
1195 SCSC_TAG_ERR(MXMAN, "Error allocating dram\n");
1196 return -ENOMEM;
1197 }
1198
1199 SCSC_TAG_INFO(MXMAN, "Allocated %zu bytes\n", size_dram);
1200
1201#ifdef CONFIG_SCSC_CHV_SUPPORT
1202 if (chv_run)
1203 allow_unidentified_firmware = true;
1204 /* Set up chv arguments. */
1205
1206#endif
1207
1208 mxman->start_dram = start_dram;
1209
1210 r = fw_init(mxman, start_dram, size_dram, &fwhdr_parsed_ok);
1211 if (r) {
1212 SCSC_TAG_ERR(MXMAN, "fw_init() failed\n");
1213 mif->unmap(mif, mxman->start_dram);
1214 return r;
1215 }
1216
1217 /* set up memory protection (read only) from start_dram to start_dram+fw_length
1218 * rounding up the size if required
1219 */
1220 start_mifram_heap = (char *)start_dram + fwhdr->fw_runtime_length;
1221 length_mifram_heap = MX_DRAM_SIZE_SECTION_1 - fwhdr->fw_runtime_length;
1222
1223
1224 start_mifram_heap2 = (char *)start_dram + MX_DRAM_SIZE_SECTION_2;
1225
1226 /* ABox reserved at end so adjust length - round to multiple of PAGE_SIZE */
1227 length_mifram_heap2 = MX_DRAM_SIZE_SECTION_2 -
1228 ((sizeof(struct scsc_bt_audio_abox) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1));
1229
1230 miframman_init(scsc_mx_get_ramman(mxman->mx), start_mifram_heap, length_mifram_heap, start_dram);
1231 miframman_init(scsc_mx_get_ramman2(mxman->mx), start_mifram_heap2, length_mifram_heap2, start_mifram_heap2);
1232 miframabox_init(scsc_mx_get_aboxram(mxman->mx), start_mifram_heap2 + length_mifram_heap2);
1233 mifmboxman_init(scsc_mx_get_mboxman(mxman->mx));
1234 mifintrbit_init(scsc_mx_get_intrbit(mxman->mx), mif);
1235 mxfwconfig_init(mxman->mx);
1236
1237 /* Initialise transports */
1238 r = transports_init(mxman);
1239 if (r) {
1240 SCSC_TAG_ERR(MXMAN, "transports_init() failed\n");
1241 fw_crc_wq_stop(mxman);
1242 mifintrbit_deinit(scsc_mx_get_intrbit(mxman->mx));
1243 miframman_deinit(scsc_mx_get_ramman(mxman->mx));
1244 miframman_deinit(scsc_mx_get_ramman2(mxman->mx));
1245 miframabox_deinit(scsc_mx_get_aboxram(mxman->mx));
1246 mifmboxman_deinit(scsc_mx_get_mboxman(mxman->mx));
1247 /* Release the MIF memory resources */
1248 mif->unmap(mif, mxman->start_dram);
1249 return r;
1250 }
1251 mbox_init(mxman, fwhdr->firmware_entry_point);
1252 init_completion(&mxman->mm_msg_start_ind_completion);
1253 init_completion(&mxman->mm_msg_halt_rsp_completion);
1254 mxmgmt_transport_register_channel_handler(scsc_mx_get_mxmgmt_transport(mxman->mx),
1255 MMTRANS_CHAN_ID_MAXWELL_MANAGEMENT,
1256 &mxman_message_handler, mxman);
1257
1258 mxlog_init(scsc_mx_get_mxlog(mxman->mx), mxman->mx, mxman->fw_build_id);
1259#ifdef CONFIG_SCSC_MXLOGGER
1260 mxlogger_init(mxman->mx, scsc_mx_get_mxlogger(mxman->mx), MXL_POOL_SZ);
1261
1262#ifdef CONFIG_SCSC_LOG_COLLECTION
1263 /* Register minimoredump client */
1264 mini_moredump_client.prv = mxman;
1265 scsc_log_collector_register_client(&mini_moredump_client);
1266#endif
1267#endif
1268#ifdef CONFIG_SCSC_SMAPPER
1269 /* Initialize SMAPPER */
1270 mifsmapper_init(scsc_mx_get_smapper(mxman->mx), mif);
1271#endif
1272#ifdef CONFIG_SCSC_QOS
1273 mifqos_init(scsc_mx_get_qos(mxman->mx), mif);
1274#endif
1275
1276#ifdef CONFIG_SCSC_CHV_SUPPORT
1277 if (chv_run) {
1278 int i;
1279
1280 u32 *p = (u32 *)((u8 *)start_dram + SCSC_CHV_ARGV_ADDR_OFFSET);
1281
1282 if (chv_argc == 0) {
1283 /*
1284 * Setup the chv f/w arguments.
1285 * Argument of 0 means run once (driver never set this).
1286 * Argument of 1 means run forever.
1287 */
1288 SCSC_TAG_INFO(MXMAN, "Setting up CHV arguments: start_dram=%p arg=%p, chv_run=%d\n", start_dram, p, chv_run);
1289 *p++ = 1; /* argc */
1290 *p++ = chv_run == 1 ? 0 : 1; /* arg */
1291 } else {
1292 /* Pass separate args */
1293 *p++ = chv_argc; /* argc */
1294 SCSC_TAG_INFO(MXMAN, "Setting up additional CHV args: chv_argc = %d\n", chv_argc);
1295
1296 for (i = 0; i < chv_argc; i++) {
1297 SCSC_TAG_INFO(MXMAN, "Setting up additional CHV args: chv_argv[%d]: *(%p) = 0x%x\n", i, p, (u32)chv_argv[i]);
1298 *p++ = (u32)chv_argv[i]; /* arg */
1299 }
1300 }
1301 }
1302#endif
1303 mxproc_create_ctrl_proc_dir(&mxman->mxproc, mxman);
1304 panicmon_init(scsc_mx_get_panicmon(mxman->mx), mxman->mx);
1305
1306 /* Change state to STARTING to allow coredump as we come out of reset */
1307 mxman->mxman_state = MXMAN_STATE_STARTING;
1308
1309 /* release Maxwell from reset */
1310 r = mif->reset(mif, 0);
1311 if (r) {
1312 reset_failed = true;
1313 SCSC_TAG_INFO(MXMAN, "HW reset deassertion failed\n");
1314
1315 /* Save log at point of failure */
1316#ifdef CONFIG_SCSC_LOG_COLLECTION
1317 scsc_log_collector_schedule_collection(SCSC_LOG_HOST_COMMON, SCSC_LOG_HOST_COMMON_REASON_START);
1318#else
1319 mx140_log_dump();
1320#endif
1321 }
1322 if (fwhdr_parsed_ok) {
1323 r = wait_for_mm_msg_start_ind(mxman);
1324 if (r) {
1325 SCSC_TAG_ERR(MXMAN, "wait_for_MM_START_IND() failed: r=%d\n", r);
1326 print_mailboxes(mxman);
1327 if (skip_mbox0_check) {
1328 SCSC_TAG_ERR(MXMAN, "timeout ignored in skip_mbox0_check mode\n");
1329 return 0;
1330 }
1331 mxman_stop(mxman);
1332 return r;
1333 }
1334#ifdef CONFIG_SCSC_MXLOGGER
1335 mxlogger_start(scsc_mx_get_mxlogger(mxman->mx));
1336#endif
1337 } else {
1338 msleep(WAIT_FOR_FW_TO_START_DELAY_MS);
1339 }
1340
1341 return 0;
1342}
1343
1344static bool is_bug_on_enabled(struct scsc_mx *mx)
1345{
1346 bool bug_on_enabled;
1347 const struct firmware *firm;
1348 int r;
1349
781f598d 1350 if ((memdump == 3) && (disable_recovery_handling == MEMDUMP_FILE_FOR_RECOVERY))
533a23a1
TK
1351 bug_on_enabled = true;
1352 else
1353 bug_on_enabled = false;
1354#ifdef CONFIG_SCSC_LOG_COLLECTION
1355 (void)firm; /* unused */
1356 (void)r; /* unused */
1357 return bug_on_enabled;
1358#else
1359 /* non SABLE platforms should also follow /sys/wifi/memdump if enabled */
1360 if (disable_recovery_handling == MEMDUMP_FILE_FOR_RECOVERY)
1361 return bug_on_enabled;
1362
1363 /* for legacy platforms (including Andorid P) using .memdump.info */
1364#if defined(ANDROID_VERSION) && (ANDROID_VERSION >= 90000)
1365 #define MX140_MEMDUMP_INFO_FILE "/data/vendor/conn/.memdump.info"
1366#else
1367 #define MX140_MEMDUMP_INFO_FILE "/data/misc/conn/.memdump.info"
1368#endif
1369
1370 SCSC_TAG_INFO(MX_FILE, "Loading %s file\n", MX140_MEMDUMP_INFO_FILE);
1371 r = mx140_request_file(mx, MX140_MEMDUMP_INFO_FILE, &firm);
1372 if (r) {
1373 SCSC_TAG_WARNING(MX_FILE, "Error Loading %s file %d\n", MX140_MEMDUMP_INFO_FILE, r);
1374 return bug_on_enabled;
1375 }
1376 if (firm->size < sizeof(char))
1377 SCSC_TAG_WARNING(MX_FILE, "file is too small\n");
1378 else if (*firm->data == '3')
1379 bug_on_enabled = true;
1380 mx140_release_file(mx, firm);
1381 SCSC_TAG_INFO(MX_FILE, "bug_on_enabled %d\n", bug_on_enabled);
1382 return bug_on_enabled;
1383#endif //CONFIG_SCSC_LOG_COLLECTION
1384}
1385
1386static void print_panic_code_legacy(u16 code)
1387{
1388 u16 tech = code & SCSC_PANIC_TECH_MASK;
1389 u16 origin = code & SCSC_PANIC_ORIGIN_MASK;
1390
1391 SCSC_TAG_INFO(MXMAN, "Decoding panic code=0x%x:\n", code);
1392 switch (origin) {
1393 default:
1394 SCSC_TAG_INFO(MXMAN, "Failed to identify panic origin\n");
1395 break;
1396 case SCSC_PANIC_ORIGIN_FW:
1397 SCSC_TAG_INFO(MXMAN, "SCSC_PANIC_ORIGIN_FW\n");
1398 break;
1399 case SCSC_PANIC_ORIGIN_HOST:
1400 SCSC_TAG_INFO(MXMAN, "SCSC_PANIC_ORIGIN_HOST\n");
1401 break;
1402 }
1403
1404 switch (tech) {
1405 default:
1406 SCSC_TAG_INFO(MXMAN, "Failed to identify panic technology\n");
1407 break;
1408 case SCSC_PANIC_TECH_WLAN:
1409 SCSC_TAG_INFO(MXMAN, "SCSC_PANIC_TECH_WLAN\n");
1410 break;
1411 case SCSC_PANIC_TECH_CORE:
1412 SCSC_TAG_INFO(MXMAN, "SCSC_PANIC_TECH_CORE\n");
1413 break;
1414 case SCSC_PANIC_TECH_BT:
1415 SCSC_TAG_INFO(MXMAN, "SCSC_PANIC_TECH_BT\n");
1416 break;
1417 case SCSC_PANIC_TECH_UNSP:
1418 SCSC_TAG_INFO(MXMAN, "PANIC_TECH_UNSP\n");
1419 break;
1420 }
1421 SCSC_TAG_INFO(MXMAN, "panic subcode=0x%x\n", code & SCSC_PANIC_SUBCODE_MASK_LEGACY);
1422}
1423
1424static void print_panic_code(u16 code)
1425{
1426 u16 origin = code & SCSC_PANIC_ORIGIN_MASK; /* Panic origin (host/fw) */
1427 u16 subcode = code & SCSC_PANIC_SUBCODE_MASK; /* The panic code */
1428
1429 SCSC_TAG_INFO(MXMAN, "Decoding panic code=0x%x:\n", code);
1430 SCSC_TAG_INFO(MXMAN, "panic subcode=0x%x\n", code & SCSC_PANIC_SUBCODE_MASK);
1431
1432 switch (origin) {
1433 default:
1434 SCSC_TAG_INFO(MXMAN, "Failed to identify panic origin\n");
1435 break;
1436 case SCSC_PANIC_ORIGIN_FW:
1437 SCSC_TAG_INFO(MXMAN, "WLBT FW PANIC: 0x%02x\n", subcode);
1438 break;
1439 case SCSC_PANIC_ORIGIN_HOST:
1440 SCSC_TAG_INFO(MXMAN, "WLBT HOST detected FW failure, service:\n");
1441 switch (subcode >> SCSC_SYSERR_HOST_SERVICE_SHIFT) {
1442 case SCSC_SERVICE_ID_WLAN:
1443 SCSC_TAG_INFO(MXMAN, " WLAN\n");
1444 break;
1445 case SCSC_SERVICE_ID_BT:
1446 SCSC_TAG_INFO(MXMAN, " BT\n");
1447 break;
1448 case SCSC_SERVICE_ID_ANT:
1449 SCSC_TAG_INFO(MXMAN, " ANT\n");
1450 break;
1451 case SCSC_SERVICE_ID_CLK20MHZ:
1452 SCSC_TAG_INFO(MXMAN, " CLK20MHZ\n");
1453 break;
1454 default:
1455 SCSC_TAG_INFO(MXMAN, " Service 0x%x\n", subcode);
1456 break;
1457 }
1458 break;
1459 }
1460}
1461
1462/**
1463 * Print the last panic record collected to aid in post mortem.
1464 *
1465 * Helps when all we have is kernel log showing WLBT failed some time ago
1466 *
1467 * Only prints the R4 record
1468 */
1469void mxman_show_last_panic(struct mxman *mxman)
1470{
1471 u32 r4_panic_record_length = 0; /* in u32s */
1472
1473 /* Any valid panic? */
1474 if (mxman->scsc_panic_code == 0)
1475 return;
1476
1477 SCSC_TAG_INFO(MXMAN, "\n\n--- DETAILS OF LAST WLBT FAILURE ---\n\n");
1478
1479 switch (mxman->scsc_panic_code & SCSC_PANIC_ORIGIN_MASK) {
1480 case SCSC_PANIC_ORIGIN_HOST:
1481 SCSC_TAG_INFO(MXMAN, "Last panic was host induced:\n");
1482 break;
1483
1484 case SCSC_PANIC_ORIGIN_FW:
1485 SCSC_TAG_INFO(MXMAN, "Last panic was FW:\n");
1486 fw_parse_r4_panic_record(mxman->last_panic_rec_r, &r4_panic_record_length);
1487 break;
1488
1489 default:
1490 SCSC_TAG_INFO(MXMAN, "Last panic unknown origin %d\n", mxman->scsc_panic_code & SCSC_PANIC_ORIGIN_MASK);
1491 break;
1492 }
1493
1494 print_panic_code(mxman->scsc_panic_code);
1495
1496 SCSC_TAG_INFO(MXMAN, "Reason: '%s'\n", mxman->failure_reason[0] ? mxman->failure_reason : "<null>");
1497 SCSC_TAG_INFO(MXMAN, "Auto-recovery: %s\n", disable_recovery_handling ? "off" : "on");
1498
1499 if (mxman_recovery_disabled()) {
1500 /* Labour the point that a reboot is needed when autorecovery is disabled */
1501 SCSC_TAG_INFO(MXMAN, "\n\n*** HANDSET REBOOT NEEDED TO RESTART WLAN AND BT ***\n\n");
1502 }
1503
1504 SCSC_TAG_INFO(MXMAN, "\n\n--- END DETAILS OF LAST WLBT FAILURE ---\n\n");
1505}
1506
1507static void process_panic_record(struct mxman *mxman)
1508{
1509 u32 *r4_panic_record = NULL;
1510 u32 *m4_panic_record = NULL;
1511#ifdef CONFIG_SCSC_MX450_GDB_SUPPORT
1512 u32 *m4_1_panic_record = NULL;
1513#endif
1514 u32 r4_panic_record_length = 0; /* in u32s */
1515 u32 m4_panic_record_length = 0; /* in u32s */
1516#ifdef CONFIG_SCSC_MX450_GDB_SUPPORT
1517 u32 m4_1_panic_record_length = 0; /* in u32s */
1518#endif
1519 u32 full_panic_code = 0;
1520 bool r4_panic_record_ok = false;
1521 bool m4_panic_record_ok = false;
1522#ifdef CONFIG_SCSC_MX450_GDB_SUPPORT
1523 bool m4_1_panic_record_ok = false;
1524#endif
1525 bool r4_sympathetic_panic_flag = false;
1526 bool m4_sympathetic_panic_flag = false;
1527#ifdef CONFIG_SCSC_MX450_GDB_SUPPORT
1528 bool m4_1_sympathetic_panic_flag = false;
1529#endif
1530
1531 /* some configurable delay before accessing the panic record */
1532 msleep(panic_record_delay);
1533 /*
1534 * Check if the panic was trigered by MX and set the subcode if so.
1535 */
1536 if ((mxman->scsc_panic_code & SCSC_PANIC_ORIGIN_MASK) == SCSC_PANIC_ORIGIN_FW) {
1537 if (mxman->fwhdr.r4_panic_record_offset) {
1538 r4_panic_record = (u32 *)(mxman->fw + mxman->fwhdr.r4_panic_record_offset);
1539 r4_panic_record_ok = fw_parse_r4_panic_record(r4_panic_record, &r4_panic_record_length);
1540 } else {
1541 SCSC_TAG_INFO(MXMAN, "R4 panic record doesn't exist in the firmware header\n");
1542 }
1543 if (mxman->fwhdr.m4_panic_record_offset) {
1544 m4_panic_record = (u32 *)(mxman->fw + mxman->fwhdr.m4_panic_record_offset);
1545 m4_panic_record_ok = fw_parse_m4_panic_record(m4_panic_record, &m4_panic_record_length);
1546#ifdef CONFIG_SCSC_MX450_GDB_SUPPORT
1547 } else if (mxman->fwhdr.m4_1_panic_record_offset) {
1548 m4_1_panic_record = (u32 *)(mxman->fw + mxman->fwhdr.m4_1_panic_record_offset);
31418e88 1549 m4_1_panic_record_ok = fw_parse_m4_panic_record(m4_1_panic_record, &m4_1_panic_record_length);
533a23a1
TK
1550#endif
1551 } else {
1552 SCSC_TAG_INFO(MXMAN, "M4 panic record doesn't exist in the firmware header\n");
1553 }
1554
1555 /* Extract and print the panic code */
1556 switch (r4_panic_record_length) {
1557 default:
1558 SCSC_TAG_WARNING(MXMAN, "Bad panic record length/subversion\n");
1559 break;
1560 case SCSC_R4_V2_MINOR_52:
1561 if (r4_panic_record_ok) {
1562 full_panic_code = r4_panic_record[2];
1563 mxman->scsc_panic_code |= SCSC_PANIC_CODE_MASK & full_panic_code;
1564 } else if (m4_panic_record_ok)
1565 mxman->scsc_panic_code |= SCSC_PANIC_CODE_MASK & m4_panic_record[2];
1566#ifdef CONFIG_SCSC_MX450_GDB_SUPPORT
1567 else if (m4_1_panic_record_ok)
1568 mxman->scsc_panic_code |= SCSC_PANIC_CODE_MASK & m4_1_panic_record[2];
1569#endif
1570 /* Set unspecified technology for now */
1571 mxman->scsc_panic_code |= SCSC_PANIC_TECH_UNSP;
1572 print_panic_code_legacy(mxman->scsc_panic_code);
1573 break;
1574 case SCSC_R4_V2_MINOR_53:
1575 if (r4_panic_record_ok) {
1576 /* Save the last R4 panic record for future display */
1577 BUG_ON(sizeof(mxman->last_panic_rec_r) < SCSC_R4_V2_MINOR_53 * sizeof(u32));
1578 memcpy((u8 *)mxman->last_panic_rec_r, (u8 *)r4_panic_record, SCSC_R4_V2_MINOR_53 * sizeof(u32));
1579 mxman->last_panic_rec_sz = r4_panic_record_length;
1580
1581 r4_sympathetic_panic_flag = fw_parse_get_r4_sympathetic_panic_flag(r4_panic_record);
1582 SCSC_TAG_INFO(MXMAN, "r4_panic_record_ok=%d r4_sympathetic_panic_flag=%d\n",
1583 r4_panic_record_ok,
1584 r4_sympathetic_panic_flag
1585 );
1586 if (r4_sympathetic_panic_flag == false) {
1587 /* process R4 record */
1588 SCSC_TAG_INFO(MXMAN, "process R4 record\n");
1589 full_panic_code = r4_panic_record[3];
1590 mxman->scsc_panic_code |= SCSC_PANIC_CODE_MASK & full_panic_code;
1591 print_panic_code(mxman->scsc_panic_code);
1592 break;
1593 }
1594 }
1595 if (m4_panic_record_ok) {
1596 m4_sympathetic_panic_flag = fw_parse_get_m4_sympathetic_panic_flag(m4_panic_record);
1597 SCSC_TAG_INFO(MXMAN, "m4_panic_record_ok=%d m4_sympathetic_panic_flag=%d\n",
1598 m4_panic_record_ok,
1599 m4_sympathetic_panic_flag
1600 );
1601 if (m4_sympathetic_panic_flag == false) {
1602 /* process M4 record */
1603 SCSC_TAG_INFO(MXMAN, "process M4 record\n");
1604 mxman->scsc_panic_code |= SCSC_PANIC_CODE_MASK & m4_panic_record[3];
1605 } else if (r4_panic_record_ok) {
1606 /* process R4 record */
1607 SCSC_TAG_INFO(MXMAN, "process R4 record\n");
1608 mxman->scsc_panic_code |= SCSC_PANIC_CODE_MASK & r4_panic_record[3];
1609 }
1610 print_panic_code(mxman->scsc_panic_code);
1611 }
1612#ifdef CONFIG_SCSC_MX450_GDB_SUPPORT /* this is wrong but not sure what is "right" */
1613/* "sympathetic panics" are not really a thing on the Neus architecture unless */
1614/* generated by the host */
1615 if (m4_1_panic_record_ok) {
1616 m4_1_sympathetic_panic_flag = fw_parse_get_m4_sympathetic_panic_flag(m4_panic_record);
1617 SCSC_TAG_INFO(MXMAN, "m4_1_panic_record_ok=%d m4_1_sympathetic_panic_flag=%d\n",
1618 m4_1_panic_record_ok,
1619 m4_1_sympathetic_panic_flag
1620 );
1621 if (m4_1_sympathetic_panic_flag == false) {
1622 /* process M4 record */
1623 SCSC_TAG_INFO(MXMAN, "process M4_1 record\n");
1624 mxman->scsc_panic_code |= SCSC_PANIC_SUBCODE_MASK & m4_1_panic_record[3];
1625 } else if (r4_panic_record_ok) {
1626 /* process R4 record */
1627 SCSC_TAG_INFO(MXMAN, "process R4 record\n");
1628 mxman->scsc_panic_code |= SCSC_PANIC_SUBCODE_MASK & r4_panic_record[3];
1629 }
1630 print_panic_code(mxman->scsc_panic_code);
1631 }
1632#endif
1633 break;
1634 }
1635 }
1636 if (r4_panic_record_ok) {
1637 /* Populate syserr info with panic equivalent */
1638 mxman->last_syserr.subsys = (u8) ((full_panic_code >> SYSERR_SUB_SYSTEM_POSN) & SYSERR_SUB_SYSTEM_MASK);
1639 mxman->last_syserr.level = MX_SYSERR_LEVEL_7;
1640 mxman->last_syserr.type = (u8) ((full_panic_code >> SYSERR_TYPE_POSN) & SYSERR_TYPE_MASK);
1641 mxman->last_syserr.subcode = (u16) ((full_panic_code >> SYSERR_SUB_CODE_POSN) & SYSERR_SUB_CODE_MASK);
1642 }
1643}
1644
1645#define MAX_UHELP_TMO_MS 20000
1646/*
1647 * workqueue thread
1648 */
1649static void mxman_failure_work(struct work_struct *work)
1650{
1651 struct mxman *mxman = container_of(work, struct mxman, failure_work);
1652 struct srvman *srvman;
1653 struct scsc_mx *mx = mxman->mx;
1654 struct scsc_mif_abs *mif = scsc_mx_get_mif_abs(mxman->mx);
1655 int used = 0, r = 0;
1656
1657#ifdef CONFIG_ANDROID
1658 wake_lock(&mxman->failure_recovery_wake_lock);
1659#endif
1660 /* Take mutex shared with syserr recovery */
1661 mutex_lock(&mxman->mxman_recovery_mutex);
1662
1663 slsi_kic_system_event(slsi_kic_system_event_category_error,
1664 slsi_kic_system_events_subsystem_crashed, GFP_KERNEL);
1665
1666 blocking_notifier_call_chain(&firmware_chain, SCSC_FW_EVENT_FAILURE, NULL);
1667
1668 SCSC_TAG_INFO(MXMAN, "Complete mm_msg_start_ind_completion\n");
1669 complete(&mxman->mm_msg_start_ind_completion);
1670 mutex_lock(&mxman->mxman_mutex);
1671 srvman = scsc_mx_get_srvman(mxman->mx);
1672
1673 if (mxman->mxman_state != MXMAN_STATE_STARTED && mxman->mxman_state != MXMAN_STATE_STARTING) {
1674 SCSC_TAG_WARNING(MXMAN, "Not in started state: mxman->mxman_state=%d\n", mxman->mxman_state);
1675#ifdef CONFIG_ANDROID
1676 wake_unlock(&mxman->failure_recovery_wake_lock);
1677#endif
1678 mutex_unlock(&mxman->mxman_mutex);
1679 mutex_unlock(&mxman->mxman_recovery_mutex);
1680 return;
1681 }
1682
1683 /**
1684 * Set error on mxlog and unregister mxlog msg-handlers.
1685 * mxlog ISR and kthread will ignore further messages
1686 * but mxlog_thread is NOT stopped here.
1687 */
1688 mxlog_transport_set_error(scsc_mx_get_mxlog_transport(mx));
1689 mxlog_release(scsc_mx_get_mxlog(mx));
1690 /* unregister channel handler */
1691 mxmgmt_transport_register_channel_handler(scsc_mx_get_mxmgmt_transport(mx), MMTRANS_CHAN_ID_MAXWELL_MANAGEMENT,
1692 NULL, NULL);
1693 mxmgmt_transport_set_error(scsc_mx_get_mxmgmt_transport(mx));
1694 srvman_set_error(srvman);
1695 fw_crc_wq_stop(mxman);
1696
1697 mxman->mxman_state = mxman->mxman_next_state;
1698
1699 /* Mark any single service recovery as no longer in progress */
1700 mxman->syserr_recovery_in_progress = false;
1701 mxman->last_syserr_recovery_time = 0;
1702
1703 if (mxman->mxman_state != MXMAN_STATE_FAILED
1704 && mxman->mxman_state != MXMAN_STATE_FROZEN) {
1705 WARN_ON(mxman->mxman_state != MXMAN_STATE_FAILED
1706 && mxman->mxman_state != MXMAN_STATE_FROZEN);
1707 SCSC_TAG_ERR(MXMAN, "Bad state=%d\n", mxman->mxman_state);
1708#ifdef CONFIG_ANDROID
1709 wake_unlock(&mxman->failure_recovery_wake_lock);
1710#endif
1711 mutex_unlock(&mxman->mxman_mutex);
1712 mutex_unlock(&mxman->mxman_recovery_mutex);
1713 return;
1714 }
1715 /* Signal panic to r4 and m4 processors */
1716 SCSC_TAG_INFO(MXMAN, "Setting MIFINTRBIT_RESERVED_PANIC_R4\n");
1717 mif->irq_bit_set(mif, MIFINTRBIT_RESERVED_PANIC_R4, SCSC_MIF_ABS_TARGET_R4); /* SCSC_MIFINTR_TARGET_R4 */
1718#ifdef CONFIG_SCSC_MX450_GDB_SUPPORT
1719 SCSC_TAG_INFO(MXMAN, "Setting MIFINTRBIT_RESERVED_PANIC_M4\n");
1720 mif->irq_bit_set(mif, MIFINTRBIT_RESERVED_PANIC_M4, SCSC_MIF_ABS_TARGET_M4); /* SCSC_MIFINTR_TARGET_M4 */
1721 SCSC_TAG_INFO(MXMAN, "Setting MIFINTRBIT_RESERVED_PANIC_M4_1\n");
1722 mif->irq_bit_set(mif, MIFINTRBIT_RESERVED_PANIC_M4_1, SCSC_MIF_ABS_TARGET_M4_1); /* SCSC_MIFINTR_TARGET_M4 */
1723#else
1724 SCSC_TAG_INFO(MXMAN, "Setting MIFINTRBIT_RESERVED_PANIC_M4\n");
1725 mif->irq_bit_set(mif, MIFINTRBIT_RESERVED_PANIC_M4, SCSC_MIF_ABS_TARGET_M4); /* SCSC_MIFINTR_TARGET_M4 */
1726#endif
1727 srvman_freeze_services(srvman, &mxman->last_syserr);
1728 if (mxman->mxman_state == MXMAN_STATE_FAILED) {
1729 mxman->last_panic_time = local_clock();
1730 process_panic_record(mxman);
1731 SCSC_TAG_INFO(MXMAN, "Trying to schedule coredump\n");
1732 SCSC_TAG_INFO(MXMAN, "scsc_release %d.%d.%d.%d\n",
1733 SCSC_RELEASE_PRODUCT,
1734 SCSC_RELEASE_ITERATION,
1735 SCSC_RELEASE_CANDIDATE,
1736 SCSC_RELEASE_POINT);
1737 SCSC_TAG_INFO(MXMAN, "Auto-recovery: %s\n", mxman_recovery_disabled() ? "off" : "on");
1738#ifdef CONFIG_SCSC_WLBTD
1739 scsc_wlbtd_get_and_print_build_type();
1740#endif
1741
1742 /* schedule coredump and wait for it to finish */
1743 if (disable_auto_coredump) {
1744 SCSC_TAG_INFO(MXMAN, "Driver automatic coredump disabled, not launching coredump helper\n");
1745 } else {
1746 /**
1747 * Releasing mxman_mutex here gives way to any
1748 * eventually running resume process while waiting for
1749 * the usermode helper subsystem to be resurrected,
1750 * since this last will be re-enabled right at the end
1751 * of the resume process itself.
1752 */
1753 mutex_unlock(&mxman->mxman_mutex);
1754 SCSC_TAG_INFO(MXMAN,
1755 "waiting up to %dms for usermode_helper subsystem.\n",
1756 MAX_UHELP_TMO_MS);
1757 /* Waits for the usermode_helper subsytem to be re-enabled. */
1758 if (usermodehelper_read_lock_wait(msecs_to_jiffies(MAX_UHELP_TMO_MS))) {
1759 /**
1760 * Release immediately the rwsem on usermode_helper
1761 * enabled since we anyway already hold a wakelock here
1762 */
1763 usermodehelper_read_unlock();
1764 /**
1765 * We claim back the mxman_mutex immediately to avoid anyone
1766 * shutting down the chip while we are dumping the coredump.
1767 */
1768 mutex_lock(&mxman->mxman_mutex);
1769 SCSC_TAG_INFO(MXMAN, "Invoking coredump helper\n");
1770 slsi_kic_system_event(slsi_kic_system_event_category_recovery,
1771 slsi_kic_system_events_coredump_in_progress,
1772 GFP_KERNEL);
1773#ifdef CONFIG_SCSC_WLBTD
1774 /* we can safely call call_wlbtd as we are
1775 * in workqueue context
1776 */
1777#ifdef CONFIG_SCSC_LOG_COLLECTION
1778 /* Collect mxlogger logs */
1779 scsc_log_collector_schedule_collection(SCSC_LOG_FW_PANIC, mxman->scsc_panic_code);
1780#else
1781 r = call_wlbtd(SCSC_SCRIPT_MOREDUMP);
1782#endif
1783#else
1784 r = coredump_helper();
1785#endif
1786 if (r >= 0) {
1787 slsi_kic_system_event(slsi_kic_system_event_category_recovery,
1788 slsi_kic_system_events_coredump_done, GFP_KERNEL);
1789 }
1790
1791 used = snprintf(panic_record_dump,
1792 PANIC_RECORD_DUMP_BUFFER_SZ,
1793 "RF HW Ver: 0x%X\n", mxman->rf_hw_ver);
1794 used += snprintf(panic_record_dump + used,
1795 PANIC_RECORD_DUMP_BUFFER_SZ - used,
1796 "SCSC Panic Code:: 0x%X\n", mxman->scsc_panic_code);
1797 used += snprintf(panic_record_dump + used,
1798 PANIC_RECORD_DUMP_BUFFER_SZ - used,
1799 "SCSC Last Panic Time:: %lld\n", mxman->last_panic_time);
1800 panic_record_dump_buffer("r4", mxman->last_panic_rec_r,
1801 mxman->last_panic_rec_sz,
1802 panic_record_dump + used,
1803 PANIC_RECORD_DUMP_BUFFER_SZ - used);
1804
1805 /* Print the host code/reason again so it's near the FW panic
1806 * record in the kernel log
1807 */
1808 print_panic_code(mxman->scsc_panic_code);
1809 SCSC_TAG_INFO(MXMAN, "Reason: '%s'\n", mxman->failure_reason[0] ? mxman->failure_reason : "<null>");
1810
1811 blocking_notifier_call_chain(&firmware_chain,
1812 SCSC_FW_EVENT_MOREDUMP_COMPLETE,
1813 &panic_record_dump);
1814 } else {
1815 SCSC_TAG_INFO(MXMAN,
1816 "timed out waiting for usermode_helper. Skipping coredump.\n");
1817 mutex_lock(&mxman->mxman_mutex);
1818 }
1819 }
1820
1821 if (is_bug_on_enabled(mx)) {
1822 SCSC_TAG_ERR(MX_FILE, "Deliberately panic the kernel due to WLBT firmware failure!\n");
1823 SCSC_TAG_ERR(MX_FILE, "calling BUG_ON(1)\n");
1824 BUG_ON(1);
1825 }
1826 /* Clean up the MIF following error handling */
1827 if (mif->mif_cleanup && mxman_recovery_disabled())
1828 mif->mif_cleanup(mif);
1829 } else {
1830 /* Populate syserr info with panic equivalent for host induced panic */
1831 mxman->last_syserr.subsys = SYSERR_SUB_SYSTEM_HOST;
1832 mxman->last_syserr.level = MX_SYSERR_LEVEL_7;
1833 mxman->last_syserr.type = 0;
1834 mxman->last_syserr.subcode = mxman->scsc_panic_code;
1835 }
1836
1837 SCSC_TAG_INFO(MXMAN, "Auto-recovery: %s\n",
1838 mxman_recovery_disabled() ? "off" : "on");
1839
1840 if (!mxman_recovery_disabled())
1841 srvman_clear_error(srvman);
1842 mutex_unlock(&mxman->mxman_mutex);
1843 if (!mxman_recovery_disabled()) {
1844 SCSC_TAG_INFO(MXMAN, "Calling srvman_unfreeze_services\n");
1845 srvman_unfreeze_services(srvman, mxman->scsc_panic_code);
1846 if (scsc_mx_module_reset() < 0)
1847 SCSC_TAG_INFO(MXMAN, "failed to call scsc_mx_module_reset\n");
1848 atomic_inc(&mxman->recovery_count);
1849 }
1850
1851 /**
1852 * If recovery is disabled and an scsc_mx_service_open has been hold up,
1853 * release it, rather than wait for the recovery_completion to timeout.
1854 */
1855 if (mxman_recovery_disabled())
1856 complete(&mxman->recovery_completion);
1857
1858 /* Safe to allow syserr recovery thread to run */
1859 mutex_unlock(&mxman->mxman_recovery_mutex);
1860
1861#ifdef CONFIG_ANDROID
1862 wake_unlock(&mxman->failure_recovery_wake_lock);
1863#endif
1864}
1865
1866static void failure_wq_init(struct mxman *mxman)
1867{
1868 mxman->failure_wq = create_singlethread_workqueue("failure_wq");
1869 INIT_WORK(&mxman->failure_work, mxman_failure_work);
1870}
1871
1872static void failure_wq_stop(struct mxman *mxman)
1873{
1874 cancel_work_sync(&mxman->failure_work);
1875 flush_workqueue(mxman->failure_wq);
1876}
1877
1878static void failure_wq_deinit(struct mxman *mxman)
1879{
1880 failure_wq_stop(mxman);
1881 destroy_workqueue(mxman->failure_wq);
1882}
1883
1884static void failure_wq_start(struct mxman *mxman)
1885{
1886 if (disable_error_handling)
1887 SCSC_TAG_INFO(MXMAN, "error handling disabled\n");
1888 else
1889 queue_work(mxman->failure_wq, &mxman->failure_work);
1890}
1891
1892/*
1893 * workqueue thread
1894 */
1895static void mxman_syserr_recovery_work(struct work_struct *work)
1896{
1897 struct mxman *mxman = container_of(work, struct mxman, syserr_recovery_work);
1898 struct srvman *srvman;
1899
1900#ifdef CONFIG_ANDROID
1901 wake_lock(&mxman->syserr_recovery_wake_lock);
1902#endif
1903 if (!mutex_trylock(&mxman->mxman_recovery_mutex)) {
1904 SCSC_TAG_WARNING(MXMAN, "Syserr during full reset - ignored\n");
1905#ifdef CONFIG_ANDROID
1906 wake_unlock(&mxman->syserr_recovery_wake_lock);
1907#endif
1908 return;
1909 }
1910
1911 mutex_lock(&mxman->mxman_mutex);
1912
1913 if (mxman->mxman_state != MXMAN_STATE_STARTED && mxman->mxman_state != MXMAN_STATE_STARTING) {
1914 SCSC_TAG_WARNING(MXMAN, "Syserr reset ignored: mxman->mxman_state=%d\n", mxman->mxman_state);
1915#ifdef CONFIG_ANDROID
1916 wake_unlock(&mxman->syserr_recovery_wake_lock);
1917#endif
1918 mutex_unlock(&mxman->mxman_mutex);
1919 return;
1920 }
1921
1922 srvman = scsc_mx_get_srvman(mxman->mx);
1923
1924 srvman_freeze_sub_system(srvman, &mxman->last_syserr);
1925
1926#ifdef CONFIG_SCSC_WLBTD
1927#ifdef CONFIG_SCSC_LOG_COLLECTION
1928 /* Wait for log generation if not finished */
1929 SCSC_TAG_INFO(MXMAN, "Wait for syserr sable logging\n");
1930 scsc_wlbtd_wait_for_sable_logging();
1931 SCSC_TAG_INFO(MXMAN, "Syserr sable logging complete\n");
1932#endif
1933#endif
1934
1935 srvman_unfreeze_sub_system(srvman, &mxman->last_syserr);
1936
1937#ifdef CONFIG_ANDROID
1938 wake_unlock(&mxman->syserr_recovery_wake_lock);
1939#endif
1940 mutex_unlock(&mxman->mxman_recovery_mutex);
1941 mutex_unlock(&mxman->mxman_mutex);
1942}
1943
1944static void syserr_recovery_wq_init(struct mxman *mxman)
1945{
1946 mxman->syserr_recovery_wq = create_singlethread_workqueue("syserr_recovery_wq");
1947 INIT_WORK(&mxman->syserr_recovery_work, mxman_syserr_recovery_work);
1948}
1949
1950static void syserr_recovery_wq_stop(struct mxman *mxman)
1951{
1952 cancel_work_sync(&mxman->syserr_recovery_work);
1953 flush_workqueue(mxman->syserr_recovery_wq);
1954}
1955
1956static void syserr_recovery_wq_deinit(struct mxman *mxman)
1957{
1958 syserr_recovery_wq_stop(mxman);
1959 destroy_workqueue(mxman->syserr_recovery_wq);
1960}
1961
1962static void syserr_recovery_wq_start(struct mxman *mxman)
1963{
1964 queue_work(mxman->syserr_recovery_wq, &mxman->syserr_recovery_work);
1965}
1966
1967static void print_mailboxes(struct mxman *mxman)
1968{
1969 struct scsc_mif_abs *mif;
1970 struct mifmboxman *mboxman;
1971 int i;
1972
1973 mif = scsc_mx_get_mif_abs(mxman->mx);
1974 mboxman = scsc_mx_get_mboxman(mxman->mx);
1975
1976 SCSC_TAG_INFO(MXMAN, "Printing mailbox values:\n");
1977 for (i = 0; i < MIFMBOX_NUM; i++)
1978 SCSC_TAG_INFO(MXMAN, "MBOX_%d: 0x%x\n", i, *mifmboxman_get_mbox_ptr(mboxman, mif, i));
1979}
1980#ifdef CONFIG_SCSC_WLBTD
1981static void wlbtd_work_func(struct work_struct *work)
1982{
1983 /* require sleep-able workqueue to run successfully */
1984#ifdef CONFIG_SCSC_LOG_COLLECTION
1985 /* Collect mxlogger logs */
1986 /* Extend to scsc_log_collector_collect() if required */
1987#else
1988 call_wlbtd(SCSC_SCRIPT_LOGGER_DUMP);
1989#endif
1990}
1991
1992static void wlbtd_wq_init(struct mxman *mx)
1993{
1994 INIT_WORK(&wlbtd_work, wlbtd_work_func);
1995}
1996
1997static void wlbtd_wq_deinit(struct mxman *mx)
1998{
1999 /* flush and block until work is complete */
2000 flush_work(&wlbtd_work);
2001}
2002#endif
2003/*
2004 * Check for matching f/w and h/w
2005 *
2006 * Returns 0: f/w and h/w match
2007 * 1: f/w and h/w mismatch, try the next config
2008 * -ve fatal error
2009 */
2010static int mxman_hw_ver_check(struct mxman *mxman)
2011{
2012 if (mx140_file_supported_hw(mxman->mx, mxman->rf_hw_ver))
2013 return 0;
2014 else
2015 return 1;
2016}
2017
2018/*
2019 * Select the f/w version to load next
2020 */
2021static int mxman_select_next_fw(struct mxman *mxman)
2022{
2023 return mx140_file_select_fw(mxman->mx, mxman->rf_hw_ver);
2024}
2025
2026/* Boot MX140 with given f/w */
2027static int __mxman_open(struct mxman *mxman)
2028{
2029 int r;
2030 struct srvman *srvman;
2031
2032 mx140_basedir_file(mxman->mx);
2033
2034 mutex_lock(&mxman->mxman_mutex);
2035 if (mxman->scsc_panic_code) {
2036 SCSC_TAG_INFO(MXMAN, "Previously recorded crash panic code: scsc_panic_code=0x%x\n", mxman->scsc_panic_code);
2037 SCSC_TAG_INFO(MXMAN, "Reason: '%s'\n", mxman->failure_reason[0] ? mxman->failure_reason : "<null>");
2038 print_panic_code(mxman->scsc_panic_code);
2039 }
2040 SCSC_TAG_INFO(MXMAN, "Auto-recovery: %s\n", mxman_recovery_disabled() ? "off" : "on");
2041 srvman = scsc_mx_get_srvman(mxman->mx);
2042 if (srvman && srvman->error) {
2043 mutex_unlock(&mxman->mxman_mutex);
2044 SCSC_TAG_INFO(MXMAN, "Called during error - ignore\n");
2045 return -EINVAL;
2046 }
2047
2048 /* Reset the state after a previous crash during f/w boot */
2049 if (mxman->mxman_state == MXMAN_STATE_STARTING)
2050 mxman->mxman_state = MXMAN_STATE_STOPPED;
2051
2052 if (mxman->mxman_state == MXMAN_STATE_STARTED) {
2053 /* if in the STARTED state there MUST already be some users */
2054 if (WARN_ON(!mxman->users)) {
2055 SCSC_TAG_ERR(MXMAN, "ERROR mxman->mxman_state=%d users=%d\n", mxman->mxman_state, mxman->users);
2056 mutex_unlock(&mxman->mxman_mutex);
2057 return -EINVAL;
2058 }
2059 mxman->users++;
2060 SCSC_TAG_INFO(MXMAN, "Already opened: users=%d\n", mxman->users);
2061 mxman_print_versions(mxman);
2062 mutex_unlock(&mxman->mxman_mutex);
2063 return 0;
2064 } else if (mxman->mxman_state == MXMAN_STATE_STOPPED) {
2065 r = mxman_start(mxman);
2066 if (r) {
2067 SCSC_TAG_ERR(MXMAN, "maxwell_manager_start() failed r=%d users=%d\n", r, mxman->users);
2068 mutex_unlock(&mxman->mxman_mutex);
2069 return r;
2070 }
2071 mxman->users++;
2072 mxman->mxman_state = MXMAN_STATE_STARTED;
2073 mutex_unlock(&mxman->mxman_mutex);
2074 /* Start mxlogger */
2075 if (!disable_logger) {
2076 static char mxlbin[128];
2077
2078 r = mx140_exe_path(NULL, mxlbin, sizeof(mxlbin), "mx_logger.sh");
2079 if (r) {
2080 /* Not found */
2081 SCSC_TAG_ERR(MXMAN, "mx_logger.sh path error\n");
2082 } else {
2083 /* Launch it */
2084 _mx_exec(mxlbin, UMH_WAIT_EXEC);
2085 }
2086 }
2087 return 0;
2088 }
2089 WARN_ON(mxman->mxman_state != MXMAN_STATE_STARTED && mxman->mxman_state != MXMAN_STATE_STOPPED);
2090 SCSC_TAG_ERR(MXMAN, "Bad state: mxman->mxman_state=%d\n", mxman->mxman_state);
2091 mutex_unlock(&mxman->mxman_mutex);
2092 return -EIO;
2093}
2094
2095int mxman_open(struct mxman *mxman)
2096{
2097 int r;
2098 int try = 0;
2099
2100 struct scsc_mif_abs *mif = scsc_mx_get_mif_abs(mxman->mx);
2101
2102 for (try = 0; try < 2; try++) {
2103 /* Boot WLBT. This will determine the h/w version */
2104 r = __mxman_open(mxman);
2105 if (r)
2106 return r;
2107
2108 /* On retries, restore USBPLL owner as WLBT */
2109 if (try > 0 && mif->mif_restart)
2110 mif->mif_restart(mif);
2111
2112 /* Check the h/w and f/w versions are compatible */
2113 r = mxman_hw_ver_check(mxman);
2114 if (r > 0) {
2115 /* Not compatible, so try next f/w */
2116 SCSC_TAG_INFO(MXMAN, "Incompatible h/w 0x%04x vs f/w, close and try next\n", mxman->rf_hw_ver);
2117
2118 /* Temporarily return USBPLL owner to AP to keep USB alive */
2119 if (mif->mif_cleanup)
2120 mif->mif_cleanup(mif);
2121
2122 /* Stop WLBT */
2123 mxman_close(mxman);
2124
2125 /* Select the new f/w for this hw ver */
2126 mxman_select_next_fw(mxman);
2127 } else
2128 break; /* Running or given up */
2129 }
2130
2131#ifdef CONFIG_SCSC_FM
2132 /* If we have stored FM radio parameters, deliver them to FW now */
2133 if (r == 0 && mxman->fm_params_pending) {
2134 SCSC_TAG_INFO(MXMAN, "Send pending FM params\n");
2135 mxman_fm_set_params(&mxman->fm_params);
2136 }
2137#endif
2138
2139 return r;
2140}
2141
2142static void mxman_stop(struct mxman *mxman)
2143{
2144 int r;
2145 struct scsc_mif_abs *mif;
2146
2147 SCSC_TAG_INFO(MXMAN, "\n");
2148
2149 /* If reset is failed, prevent new resets */
2150 if (reset_failed) {
2151 struct timeval tval = ns_to_timeval(reset_failed_time);
2152
2153 SCSC_TAG_ERR(MXMAN, "previous reset failed at [%6lu.%06ld], ignoring\n", tval.tv_sec, tval.tv_usec);
2154 return;
2155 }
2156
2157 (void)snprintf(mxman->fw_build_id, sizeof(mxman->fw_build_id), "unknown");
2158
2159 mxproc_remove_ctrl_proc_dir(&mxman->mxproc);
2160
2161 /* Shutdown the hardware */
2162 mif = scsc_mx_get_mif_abs(mxman->mx);
2163 r = mif->reset(mif, 1);
2164 if (r) {
2165 reset_failed_time = local_clock();
2166 SCSC_TAG_INFO(MXMAN, "HW reset failed\n");
2167 reset_failed = true;
2168
2169 /* Save log at point of failure */
2170#ifdef CONFIG_SCSC_LOG_COLLECTION
2171 scsc_log_collector_schedule_collection(SCSC_LOG_HOST_COMMON, SCSC_LOG_HOST_COMMON_REASON_STOP);
2172#else
2173 mx140_log_dump();
2174#endif
2175 }
2176
2177 panicmon_deinit(scsc_mx_get_panicmon(mxman->mx));
2178 transports_release(mxman);
2179 mxfwconfig_unload(mxman->mx);
2180
2181 mxlog_release(scsc_mx_get_mxlog(mxman->mx));
2182 /* unregister channel handler */
2183 mxmgmt_transport_register_channel_handler(scsc_mx_get_mxmgmt_transport(mxman->mx), MMTRANS_CHAN_ID_MAXWELL_MANAGEMENT,
2184 NULL, NULL);
2185 fw_crc_wq_stop(mxman);
2186
2187 /* Unitialise components (they may perform some checks - e.g. all memory freed) */
2188 mxfwconfig_deinit(mxman->mx);
2189 mifintrbit_deinit(scsc_mx_get_intrbit(mxman->mx));
2190 miframman_deinit(scsc_mx_get_ramman(mxman->mx));
2191 miframman_deinit(scsc_mx_get_ramman2(mxman->mx));
2192 miframabox_deinit(scsc_mx_get_aboxram(mxman->mx));
2193 mifmboxman_deinit(scsc_mx_get_mboxman(mxman->mx));
2194#ifdef CONFIG_SCSC_SMAPPER
2195 mifsmapper_deinit(scsc_mx_get_smapper(mxman->mx));
2196#endif
2197#ifdef CONFIG_SCSC_QOS
2198 mifqos_deinit(scsc_mx_get_qos(mxman->mx));
2199#endif
2200 /* Release the MIF memory resources */
2201 mif->unmap(mif, mxman->start_dram);
2202}
2203
2204void mxman_close(struct mxman *mxman)
2205{
2206 int r;
2207 struct srvman *srvman;
2208
2209 mutex_lock(&mxman->mxman_mutex);
2210 srvman = scsc_mx_get_srvman(mxman->mx);
2211 if (srvman && srvman->error) {
2212 mutex_unlock(&mxman->mxman_mutex);
2213 SCSC_TAG_INFO(MXMAN, "Called during error - ignore\n");
2214 return;
2215 }
2216
2217 SCSC_TAG_INFO(MXMAN, "\n");
2218
2219 if (mxman->mxman_state == MXMAN_STATE_STARTED) {
2220 if (WARN_ON(!mxman->users)) {
2221 SCSC_TAG_ERR(MXMAN, "ERROR users=%d\n", mxman->users);
2222 mutex_unlock(&mxman->mxman_mutex);
2223 return;
2224 }
2225 mxman->users--;
2226 if (mxman->users) {
2227 SCSC_TAG_INFO(MXMAN, "Current number of users=%d\n", mxman->users);
2228 mutex_unlock(&mxman->mxman_mutex);
2229 return;
2230 }
2231#ifdef CONFIG_SCSC_MXLOGGER
2232#ifdef CONFIG_SCSC_LOG_COLLECTION
2233 /* Unregister minimoredump client */
2234 scsc_log_collector_unregister_client(&mini_moredump_client);
2235#endif
2236 /**
2237 * Deinit mxlogger on last service stop...BUT before asking for HALT
2238 */
2239 mxlogger_deinit(mxman->mx, scsc_mx_get_mxlogger(mxman->mx));
2240#endif
2241 /*
2242 * Ask the subsystem to stop (MM_STOP_REQ), and wait
2243 * for response (MM_STOP_RSP).
2244 */
2245 r = send_mm_msg_stop_blocking(mxman);
2246 if (r)
2247 SCSC_TAG_ERR(MXMAN, "send_mm_msg_stop_blocking failed: r=%d\n", r);
2248
2249 mxman_stop(mxman);
2250 mxman->mxman_state = MXMAN_STATE_STOPPED;
2251 mutex_unlock(&mxman->mxman_mutex);
2252 } else if (mxman->mxman_state == MXMAN_STATE_FAILED) {
2253 if (WARN_ON(!mxman->users))
2254 SCSC_TAG_ERR(MXMAN, "ERROR users=%d\n", mxman->users);
2255
2256 mxman->users--;
2257 if (mxman->users) {
2258 SCSC_TAG_INFO(MXMAN, "Current number of users=%d\n", mxman->users);
2259 mutex_unlock(&mxman->mxman_mutex);
2260 return;
2261 }
2262#ifdef CONFIG_SCSC_MXLOGGER
2263#ifdef CONFIG_SCSC_LOG_COLLECTION
2264 /* Unregister minimoredump client */
2265 scsc_log_collector_unregister_client(&mini_moredump_client);
2266#endif
2267 /**
2268 * Deinit mxlogger on last service stop...BUT before asking for HALT
2269 */
2270 mxlogger_deinit(mxman->mx, scsc_mx_get_mxlogger(mxman->mx));
2271#endif
2272
2273 mxman_stop(mxman);
2274 mxman->mxman_state = MXMAN_STATE_STOPPED;
2275 mutex_unlock(&mxman->mxman_mutex);
2276 complete(&mxman->recovery_completion);
2277 } else {
2278 WARN_ON(mxman->mxman_state != MXMAN_STATE_STARTED);
2279 SCSC_TAG_ERR(MXMAN, "Bad state: mxman->mxman_state=%d\n", mxman->mxman_state);
2280 mutex_unlock(&mxman->mxman_mutex);
2281 return;
2282 }
2283}
2284
2285void mxman_syserr(struct mxman *mxman, struct mx_syserr_decode *syserr)
2286{
2287 mxman->syserr_recovery_in_progress = true;
2288
2289 mxman->last_syserr.subsys = syserr->subsys;
2290 mxman->last_syserr.level = syserr->level;
2291 mxman->last_syserr.type = syserr->type;
2292 mxman->last_syserr.subcode = syserr->subcode;
2293
2294 syserr_recovery_wq_start(mxman);
2295}
2296
2297void mxman_fail(struct mxman *mxman, u16 scsc_panic_code, const char *reason)
2298{
2299 SCSC_TAG_WARNING(MXMAN, "WLBT FW failure\n");
2300
2301 /* The STARTING state allows a crash during firmware boot to be handled */
2302 if (mxman->mxman_state == MXMAN_STATE_STARTED || mxman->mxman_state == MXMAN_STATE_STARTING) {
2303 mxman->mxman_next_state = MXMAN_STATE_FAILED;
2304 mxman->scsc_panic_code = scsc_panic_code;
2305 strlcpy(mxman->failure_reason, reason, sizeof(mxman->failure_reason));
2306 /* If recovery is disabled, don't let it be
2307 * re-enabled from now on. Device must reboot
2308 */
2309 if (mxman_recovery_disabled())
2310 disable_recovery_until_reboot = true;
2311
2312 failure_wq_start(mxman);
2313 } else {
2314 SCSC_TAG_WARNING(MXMAN, "Not in MXMAN_STATE_STARTED state, ignore (state %d)\n", mxman->mxman_state);
2315 }
2316
2317 /* Populate syserr info with panic equivalent or best we can */
2318 mxman->last_syserr.subsys = scsc_panic_code >> SYSERR_SUB_SYSTEM_POSN;
2319 mxman->last_syserr.level = MX_SYSERR_LEVEL_7;
2320 mxman->last_syserr.type = scsc_panic_code;
2321 mxman->last_syserr.subcode = scsc_panic_code;
2322}
2323
2324void mxman_freeze(struct mxman *mxman)
2325{
2326 SCSC_TAG_WARNING(MXMAN, "WLBT FW frozen\n");
2327
2328 if (mxman->mxman_state == MXMAN_STATE_STARTED) {
2329 mxman->mxman_next_state = MXMAN_STATE_FROZEN;
2330 failure_wq_start(mxman);
2331 } else {
2332 SCSC_TAG_WARNING(MXMAN, "Not in MXMAN_STATE_STARTED state, ignore (state %d)\n", mxman->mxman_state);
2333 }
2334}
2335
2336void mxman_init(struct mxman *mxman, struct scsc_mx *mx)
2337{
2338 mxman->mx = mx;
2339 mxman->suspended = 0;
2340#ifdef CONFIG_SCSC_FM
2341 mxman->on_halt_ldos_on = 0;
2342 mxman->fm_params_pending = 0;
2343#endif
2344 fw_crc_wq_init(mxman);
2345 failure_wq_init(mxman);
2346 syserr_recovery_wq_init(mxman);
2347#ifdef CONFIG_SCSC_WLBTD
2348 wlbtd_wq_init(mxman);
2349#endif
2350 mutex_init(&mxman->mxman_mutex);
2351 mutex_init(&mxman->mxman_recovery_mutex);
2352 init_completion(&mxman->recovery_completion);
2353#ifdef CONFIG_ANDROID
2354 wake_lock_init(&mxman->failure_recovery_wake_lock, WAKE_LOCK_SUSPEND, "mxman_recovery");
2355 wake_lock_init(&mxman->syserr_recovery_wake_lock, WAKE_LOCK_SUSPEND, "mxman_syserr_recovery");
2356#endif
2357 mxman->syserr_recovery_in_progress = false;
2358 mxman->last_syserr_recovery_time = 0;
2359
2360 /* set the initial state */
2361 mxman->mxman_state = MXMAN_STATE_STOPPED;
2362 (void)snprintf(mxman->fw_build_id, sizeof(mxman->fw_build_id), "unknown");
2363 memcpy(saved_fw_build_id, mxman->fw_build_id,
2364 sizeof(saved_fw_build_id));
2365 (void)snprintf(mxman->fw_ttid, sizeof(mxman->fw_ttid), "unknown");
2366 mxproc_create_info_proc_dir(&mxman->mxproc, mxman);
2367 active_mxman = mxman;
2368
2369#if defined(ANDROID_VERSION) && ANDROID_VERSION >= 90000
2370 mxman_create_sysfs_memdump();
2371#endif
2372 scsc_lerna_init();
2373}
2374
2375void mxman_deinit(struct mxman *mxman)
2376{
2377 scsc_lerna_deinit();
2378#if defined(ANDROID_VERSION) && ANDROID_VERSION >= 90000
2379 mxman_destroy_sysfs_memdump();
2380#endif
2381 active_mxman = NULL;
2382 mxproc_remove_info_proc_dir(&mxman->mxproc);
2383 fw_crc_wq_deinit(mxman);
2384 failure_wq_deinit(mxman);
2385 syserr_recovery_wq_deinit(mxman);
2386#ifdef CONFIG_SCSC_WLBTD
2387 wlbtd_wq_deinit(mxman);
2388#endif
2389#ifdef CONFIG_ANDROID
2390 wake_lock_destroy(&mxman->failure_recovery_wake_lock);
2391 wake_lock_destroy(&mxman->syserr_recovery_wake_lock);
2392#endif
2393 mutex_destroy(&mxman->mxman_recovery_mutex);
2394 mutex_destroy(&mxman->mxman_mutex);
2395}
2396
2397int mxman_force_panic(struct mxman *mxman)
2398{
2399 struct srvman *srvman;
2400 struct ma_msg_packet message = { .ma_msg = MM_FORCE_PANIC };
2401
2402 mutex_lock(&mxman->mxman_mutex);
2403 srvman = scsc_mx_get_srvman(mxman->mx);
2404 if (srvman && srvman->error) {
2405 mutex_unlock(&mxman->mxman_mutex);
2406 SCSC_TAG_INFO(MXMAN, "Called during error - ignore\n");
2407 return -EINVAL;
2408 }
2409
2410 if (mxman->mxman_state == MXMAN_STATE_STARTED) {
2411 mxmgmt_transport_send(scsc_mx_get_mxmgmt_transport(mxman->mx), MMTRANS_CHAN_ID_MAXWELL_MANAGEMENT, &message, sizeof(message));
2412 mutex_unlock(&mxman->mxman_mutex);
2413 return 0;
2414 }
2415 mutex_unlock(&mxman->mxman_mutex);
2416 return -EINVAL;
2417}
2418
2419int mxman_suspend(struct mxman *mxman)
2420{
2421 struct srvman *srvman;
2422 struct ma_msg_packet message = { .ma_msg = MM_HOST_SUSPEND };
2423 int ret;
2424
2425 SCSC_TAG_INFO(MXMAN, "\n");
2426
2427 mutex_lock(&mxman->mxman_mutex);
2428 srvman = scsc_mx_get_srvman(mxman->mx);
2429 if (srvman && srvman->error) {
2430 mutex_unlock(&mxman->mxman_mutex);
2431 SCSC_TAG_INFO(MXMAN, "Called during error - ignore\n");
2432 return 0;
2433 }
2434
2435 /* Call Service suspend callbacks */
2436 ret = srvman_suspend_services(srvman);
2437 if (ret) {
2438 mutex_unlock(&mxman->mxman_mutex);
2439 SCSC_TAG_INFO(MXMAN, "Service Suspend canceled - ignore %d\n", ret);
2440 return ret;
2441 }
2442
2443 if (mxman->mxman_state == MXMAN_STATE_STARTED) {
2444 SCSC_TAG_INFO(MXMAN, "MM_HOST_SUSPEND\n");
2445#ifdef CONFIG_SCSC_MXLOGGER
2446 mxlogger_generate_sync_record(scsc_mx_get_mxlogger(mxman->mx), MXLOGGER_SYN_SUSPEND);
2447#endif
2448 mxmgmt_transport_send(scsc_mx_get_mxmgmt_transport(mxman->mx), MMTRANS_CHAN_ID_MAXWELL_MANAGEMENT, &message, sizeof(message));
2449 mxman->suspended = 1;
2450 atomic_inc(&mxman->suspend_count);
2451 }
2452 mutex_unlock(&mxman->mxman_mutex);
2453 return 0;
2454}
2455
2456#ifdef CONFIG_SCSC_FM
2457void mxman_fm_on_halt_ldos_on(void)
2458{
2459 /* Should always be an active mxman unless module is unloaded */
2460 if (!active_mxman) {
2461 SCSC_TAG_ERR(MXMAN, "No active MXMAN\n");
2462 return;
2463 }
2464
2465 active_mxman->on_halt_ldos_on = 1;
2466
2467 /* FM status to pass into FW at next FW init,
2468 * by which time driver context is lost.
2469 * This is required, because now WLBT gates
2470 * LDOs with TCXO instead of leaving them
2471 * always on, to save power in deep sleep.
2472 * FM, however, needs them always on. So
2473 * we need to know when to leave the LDOs
2474 * alone at WLBT boot.
2475 */
2476 is_fm_on = 1;
2477}
2478
2479void mxman_fm_on_halt_ldos_off(void)
2480{
2481 /* Should always be an active mxman unless module is unloaded */
2482 if (!active_mxman) {
2483 SCSC_TAG_ERR(MXMAN, "No active MXMAN\n");
2484 return;
2485 }
2486
2487 /* Newer FW no longer need set shared LDOs
2488 * always-off at WLBT halt, as TCXO gating
2489 * has the same effect. But pass the "off"
2490 * request for backwards compatibility
2491 * with old FW.
2492 */
2493 active_mxman->on_halt_ldos_on = 0;
2494 is_fm_on = 0;
2495}
2496
2497/* Update parameters passed to WLBT FM */
2498int mxman_fm_set_params(struct wlbt_fm_params *params)
2499{
2500 /* Should always be an active mxman unless module is unloaded */
2501 if (!active_mxman) {
2502 SCSC_TAG_ERR(MXMAN, "No active MXMAN\n");
2503 return -EINVAL;
2504 }
2505
2506 /* Params are no longer valid (FM stopped) */
2507 if (!params) {
2508 active_mxman->fm_params_pending = 0;
2509 SCSC_TAG_INFO(MXMAN, "FM params cleared\n");
2510 return 0;
2511 }
2512
2513 /* Once set the value needs to be remembered for each time WLBT starts */
2514 active_mxman->fm_params = *params;
2515 active_mxman->fm_params_pending = 1;
2516
2517 if (send_fm_params_to_active_mxman(params)) {
2518 SCSC_TAG_INFO(MXMAN, "FM params sent to FW\n");
2519 return 0;
2520 }
2521
2522 /* Stored for next time FW is up */
2523 SCSC_TAG_INFO(MXMAN, "FM params stored\n");
2524
2525 return -EAGAIN;
2526}
2527#endif
2528
2529void mxman_resume(struct mxman *mxman)
2530{
2531 struct srvman *srvman;
2532 struct ma_msg_packet message = { .ma_msg = MM_HOST_RESUME };
2533 int ret;
2534
2535 SCSC_TAG_INFO(MXMAN, "\n");
2536
2537 mutex_lock(&mxman->mxman_mutex);
2538 srvman = scsc_mx_get_srvman(mxman->mx);
2539 if (srvman && srvman->error) {
2540 mutex_unlock(&mxman->mxman_mutex);
2541 SCSC_TAG_INFO(MXMAN, "Called during error - ignore\n");
2542 return;
2543 }
2544
2545 if (mxman->mxman_state == MXMAN_STATE_STARTED) {
2546 SCSC_TAG_INFO(MXMAN, "MM_HOST_RESUME\n");
2547#ifdef CONFIG_SCSC_MXLOGGER
2548 mxlogger_generate_sync_record(scsc_mx_get_mxlogger(mxman->mx), MXLOGGER_SYN_RESUME);
2549#endif
2550 mxmgmt_transport_send(scsc_mx_get_mxmgmt_transport(mxman->mx), MMTRANS_CHAN_ID_MAXWELL_MANAGEMENT, &message, sizeof(message));
2551 mxman->suspended = 0;
2552 }
2553
2554 /* Call Service Resume callbacks */
2555 ret = srvman_resume_services(srvman);
2556 if (ret)
2557 SCSC_TAG_INFO(MXMAN, "Service Resume error %d\n", ret);
2558
2559 mutex_unlock(&mxman->mxman_mutex);
2560}
2561
2562static void _mx_exec_cleanup(struct subprocess_info *sp_info)
2563{
2564 if (!sp_info) {
2565 SCSC_TAG_ERR(MXMAN, "sp_info is null\n");
2566 return;
2567 }
2568 if (!sp_info->argv) {
2569 SCSC_TAG_ERR(MXMAN, "argv is null\n");
2570 return;
2571 }
2572
2573 SCSC_TAG_INFO(MXMAN, "0x%p\n", sp_info->argv);
2574 argv_free(sp_info->argv);
2575}
2576
2577/* prog - full path to programme
2578 * wait_exec - one of UMH_WAIT_EXEC, UMH_WAIT_PROC, UMH_KILLABLE, UMH_NO_WAIT
2579 */
2580static int _mx_exec(char *prog, int wait_exec)
2581{
2582 /**
2583 * ENV vars ANDROID_ROOT and ANDROID_DATA are needed to have
2584 * the UMH spawned process working properly (as an example finding
2585 * Timezones files)
2586 */
2587 static char const *envp[] = { "HOME=/", "PATH=/sbin:/system/sbin:/system/bin:/system/xbin:/vendor/bin:/vendor/xbin",
2588 "ANDROID_ROOT=/system", "ANDROID_DATA=/data", NULL };
2589 char **argv;
2590 char argv_str[STRING_BUFFER_MAX_LENGTH];
2591 int argc, result, len;
2592 struct subprocess_info *sp_info;
2593
2594 len = snprintf(argv_str, STRING_BUFFER_MAX_LENGTH, "%s", prog);
2595 if (len >= STRING_BUFFER_MAX_LENGTH) {
2596 /* snprintf() returns a value of buffer size of greater if it had to truncate the format string. */
2597 SCSC_TAG_ERR(MXMAN,
2598 "exec string buffer insufficient (buffer size=%d, actual string=%d)\n",
2599 STRING_BUFFER_MAX_LENGTH, len);
2600 return -E2BIG;
2601 }
2602
2603 /* Kernel library function argv_split() will allocate memory for argv. */
2604 argc = 0;
2605 argv = argv_split(GFP_KERNEL, argv_str, &argc);
2606 if (!argv) {
2607 SCSC_TAG_ERR(MXMAN, "failed to allocate argv for userspace helper\n");
2608 return -ENOMEM;
2609 }
2610
2611 /* Check the argument count just to avoid future abuse */
2612 if (argc > NUMBER_OF_STRING_ARGS) {
2613 SCSC_TAG_ERR(MXMAN,
2614 "exec string has the wrong number of arguments (has %d, should be %d)\n",
2615 argc, NUMBER_OF_STRING_ARGS);
2616 argv_free(argv);
2617 return -E2BIG;
2618 }
2619
2620 /* Allocate sp_info and initialise pointers to argv and envp. */
2621 sp_info = call_usermodehelper_setup(argv[0], argv, (char **)envp,
2622 GFP_KERNEL, NULL, _mx_exec_cleanup,
2623 NULL);
2624
2625 if (!sp_info) {
2626 SCSC_TAG_ERR(MXMAN, "call_usermodehelper_setup() failed\n");
2627 argv_free(argv);
2628 return -EIO;
2629 }
2630
2631 /* Put sp_info into work queue for processing by khelper. */
2632 SCSC_TAG_INFO(MXMAN, "Launch %s\n", prog);
2633
2634 result = call_usermodehelper_exec(sp_info, wait_exec);
2635
2636 if (result != 0) {
2637 /*
2638 * call_usermodehelper_exec() will free sp_info and call any cleanup function
2639 * whether it succeeds or fails, so do not free argv.
2640 */
2641 if (result == -ENOENT)
2642 SCSC_TAG_ERR(MXMAN, "call_usermodehelper() failed with %d, Executable not found %s'\n",
2643 result, prog);
2644 else
2645 SCSC_TAG_ERR(MXMAN, "call_usermodehelper_exec() failed with %d\n", result);
2646 }
2647 return result;
2648}
2649
2650#if defined(CONFIG_SCSC_PRINTK) && !defined(CONFIG_SCSC_WLBTD)
2651static int __stat(const char *file)
2652{
2653 struct kstat stat;
2654 mm_segment_t fs;
2655 int r;
2656
2657 fs = get_fs();
2658 set_fs(get_ds());
2659 r = vfs_stat(file, &stat);
2660 set_fs(fs);
2661
2662 return r;
2663}
2664#endif
2665
2666int mx140_log_dump(void)
2667{
2668#ifdef CONFIG_SCSC_PRINTK
2669 int r;
2670# ifdef CONFIG_SCSC_WLBTD
2671 r = schedule_work(&wlbtd_work);
2672# else
2673 char mxlbin[128];
2674
2675 r = mx140_exe_path(NULL, mxlbin, sizeof(mxlbin), "mx_logger_dump.sh");
2676 if (r) {
2677 SCSC_TAG_ERR(MXMAN, "mx_logger_dump.sh path error\n");
2678 } else {
2679 /*
2680 * Test presence of script before invoking, to suppress
2681 * unnecessary error message if not installed.
2682 */
2683 r = __stat(mxlbin);
2684 if (r) {
2685 SCSC_TAG_DEBUG(MXMAN, "%s not installed\n", mxlbin);
2686 return r;
2687 }
2688 SCSC_TAG_INFO(MXMAN, "Invoking mx_logger_dump.sh UHM\n");
2689 r = _mx_exec(mxlbin, UMH_WAIT_EXEC);
2690 if (r)
2691 SCSC_TAG_ERR(MXMAN, "mx_logger_dump.sh err:%d\n", r);
2692 }
2693# endif /* CONFIG_SCSC_WLBTD */
2694 return r;
2695#else
2696 return 0;
2697#endif
2698}
2699EXPORT_SYMBOL(mx140_log_dump);
2700
2701bool mxman_recovery_disabled(void)
2702{
2703#ifdef CONFIG_SCSC_WLBT_AUTORECOVERY_PERMANENT_DISABLE
2704 /* Add option to kill autorecovery, ignoring module parameter
2705 * to work around platform that enables it against our wishes
2706 */
2707 SCSC_TAG_ERR(MXMAN, "CONFIG_SCSC_WLBT_AUTORECOVERY_PERMANENT_DISABLE is set\n");
2708 return true;
2709#endif
2710 /* If FW has panicked when recovery was disabled, don't allow it to
2711 * be enabled. The horse has bolted.
2712 */
2713 if (disable_recovery_until_reboot)
2714 return true;
2715
2716 if (disable_recovery_handling == MEMDUMP_FILE_FOR_RECOVERY)
2717 return disable_recovery_from_memdump_file;
2718 else
2719 return disable_recovery_handling ? true : false;
2720}
2721EXPORT_SYMBOL(mxman_recovery_disabled);
2722
2723/**
2724 * This returns the last known loaded FW build_id
2725 * even when the fw is NOT running at the time of the request.
2726 *
2727 * It could be used anytime by Android Enhanced Logging
2728 * to query for fw version.
2729 */
2730void mxman_get_fw_version(char *version, size_t ver_sz)
2731{
2732 /* unavailable only if chip not probed ! */
2733 snprintf(version, ver_sz, "%s", saved_fw_build_id);
2734}
2735EXPORT_SYMBOL(mxman_get_fw_version);
2736
2737void mxman_get_driver_version(char *version, size_t ver_sz)
2738{
2739 /* IMPORTANT - Do not change the formatting as User space tooling is parsing the string
2740 * to read SAP fapi versions. */
2741 snprintf(version, ver_sz, "drv_ver: %u.%u.%u.%u",
2742 SCSC_RELEASE_PRODUCT, SCSC_RELEASE_ITERATION, SCSC_RELEASE_CANDIDATE, SCSC_RELEASE_POINT);
2743#ifdef CONFIG_SCSC_WLBTD
2744 scsc_wlbtd_get_and_print_build_type();
2745#endif
2746}
2747EXPORT_SYMBOL(mxman_get_driver_version);
2748
2749int mxman_register_firmware_notifier(struct notifier_block *nb)
2750{
2751 return blocking_notifier_chain_register(&firmware_chain, nb);
2752}
2753EXPORT_SYMBOL(mxman_register_firmware_notifier);
2754
2755int mxman_unregister_firmware_notifier(struct notifier_block *nb)
2756{
2757 return blocking_notifier_chain_unregister(&firmware_chain, nb);
2758}
2759EXPORT_SYMBOL(mxman_unregister_firmware_notifier);
2760
2761
2762int mxman_lerna_send(struct mxman *mxman, void *message, u32 message_size)
2763{
2764 struct srvman *srvman = NULL;
2765
2766 /* May be called when WLBT is off, so find the context in this case */
2767 if (!mxman)
2768 mxman = active_mxman;
2769
2770 if (!active_mxman) {
2771 SCSC_TAG_ERR(MXMAN, "No active MXMAN\n");
2772 return -EINVAL;
2773 }
2774
2775 if (!message || (message_size == 0)) {
2776 SCSC_TAG_INFO(MXMAN, "No lerna request provided.\n");
2777 return 0;
2778 }
2779
2780 mutex_lock(&active_mxman->mxman_mutex);
2781 srvman = scsc_mx_get_srvman(active_mxman->mx);
2782 if (srvman && srvman->error) {
2783 mutex_unlock(&active_mxman->mxman_mutex);
2784 SCSC_TAG_INFO(MXMAN, "Lerna configuration called during error - ignore\n");
2785 return 0;
2786 }
2787
2788 if (active_mxman->mxman_state == MXMAN_STATE_STARTED) {
2789 SCSC_TAG_INFO(MXMAN, "MM_LERNA_CONFIG\n");
2790 mxmgmt_transport_send(scsc_mx_get_mxmgmt_transport(active_mxman->mx),
2791 MMTRANS_CHAN_ID_MAXWELL_MANAGEMENT, message,
2792 message_size);
2793 mutex_unlock(&active_mxman->mxman_mutex);
2794 return 0;
2795 }
2796
2797 SCSC_TAG_INFO(MXMAN, "MXMAN is NOT STARTED...cannot send MM_LERNA_CONFIG msg.\n");
2798 mutex_unlock(&active_mxman->mxman_mutex);
2799 return -EAGAIN;
2800}