/* we can safely call call_wlbtd as we are
* in workqueue context
*/
+#ifdef CONFIG_SCSC_LOG_COLLECTION
+ /* Collect mxlogger logs */
+ r = scsc_log_collector_collect(SCSC_LOG_REASON_FW_PANIC);
+ if (r != 0)
+ SCSC_TAG_INFO(MXMAN, "sable creation failed.");
+ /* call old method to generate moredump anyway */
+ r = call_wlbtd(SCSC_SCRIPT_MOREDUMP);
+#else
r = call_wlbtd(SCSC_SCRIPT_MOREDUMP);
+#endif
#else
r = coredump_helper();
#endif
if (mif->mif_cleanup && mxman_recovery_disabled())
mif->mif_cleanup(mif);
}
-#ifdef CONFIG_SCSC_LOG_COLLECTION
- /* Collect mxlogger logs */
- scsc_log_collector_collect(SCSC_LOG_REASON_FW_PANIC);
-#endif
if (!mxman_recovery_disabled())
srvman_clear_error(srvman);
static void wlbtd_work_func(struct work_struct *work)
{
/* require sleep-able workqueue to run successfully */
+#ifdef CONFIG_SCSC_LOG_COLLECTION
+ /* Collect mxlogger logs */
+ scsc_log_collector_collect(SCSC_LOG_REASON_WLAN_DISCONNECT);
+#else
call_wlbtd(SCSC_SCRIPT_LOGGER_DUMP);
+#endif
}
static void wlbtd_wq_init(struct mxman *mx)
#include <scsc/scsc_log_collector.h>
#include "scsc_log_collector_proc.h"
#include <scsc/scsc_mx.h>
+#ifdef CONFIG_SCSC_WLBTD
+#include "scsc_wlbtd.h"
+#endif
#define SCSC_NUM_CHUNKS_SUPPORTED 12
module_param(collect_to_ram, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(collect_to_ram, "Collect buffer in ram");
-static char collection_dir_buf[256] = "/data/exynos/log/wifi/";
+static char collection_dir_buf[256] = "/data/exynos/log/wifi";
module_param_string(collection_target_directory, collection_dir_buf, sizeof(collection_dir_buf), S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(collection_target_directory, "Specify collection target directory");
#define align_chunk(ppos) (((ppos) + (SCSC_LOG_CHUNK_ALIGN - 1)) & \
~(SCSC_LOG_CHUNK_ALIGN - 1))
-const char *scsc_loc_reason_str[] = { "unknown", "fw_panic", "host_trig",
- "fw_trig", "dumpstate", "wlan_disc", "bt_trig" /* Add others */};
+const char *scsc_loc_reason_str[] = { "unknown", "scsc_log_fw_panic",
+ "scsc_log_host_trig",
+ "scsc_log_fw_trig", "scsc_log_dumpstate",
+ "scsc_log_wlan_trig", "scsc_log_bt_trig",
+ "scsc_log_common_trig"/* Add others */};
static inline int __scsc_log_collector_collect_to_file(enum scsc_log_reason reason)
{
do_gettimeofday(&t);
time_to_tm(t.tv_sec, 0, &tm_n);
- snprintf(memdump_path, sizeof(memdump_path), "%s%s_%s.sbl",
- collection_dir_buf, "scsc_log", scsc_loc_reason_str[reason]);
+ snprintf(memdump_path, sizeof(memdump_path), "%s/%s.sbl",
+ collection_dir_buf, scsc_loc_reason_str[reason]);
/* change to KERNEL_DS address limit */
old_fs = get_fs();
pr_info("File %s collection end. Took: %lld\n", memdump_path, ktime_to_ns(ktime_sub(ktime_get(), start)));
+#ifdef CONFIG_SCSC_WLBTD
+ call_wlbtd_sable(scsc_loc_reason_str[reason]);
+#endif
mutex_unlock(&log_mutex);
+
return ret;
}
int status;
if (info->attrs[1])
- SCSC_TAG_INFO(WLBTD, "wlbtd returned data : %s\n",
+ SCSC_TAG_INFO(WLBTD, "returned data : %s\n",
(char *)nla_data(info->attrs[1]));
if (info->attrs[2]) {
status = *((__u32 *)nla_data(info->attrs[2]));
if (!status)
- SCSC_TAG_INFO(WLBTD,
- "wlbtd returned status : %u\n", status);
+ SCSC_TAG_INFO(WLBTD, "returned status : %u\n", status);
else
- SCSC_TAG_ERR(WLBTD,
- "wlbtd returned error : %u\n", status);
+ SCSC_TAG_ERR(WLBTD, "returned error : %u\n", status);
+ }
+
+ complete(&script_done);
+ return 0;
+}
+
+static int msg_from_wlbtd_sable_cb(struct sk_buff *skb, struct genl_info *info)
+{
+ int status;
+
+ if (info->attrs[1])
+ SCSC_TAG_INFO(WLBTD, "returned data : %s\n",
+ (char *)nla_data(info->attrs[1]));
+
+ if (info->attrs[2]) {
+ status = nla_get_u16(info->attrs[2]);
+ if (!status)
+ SCSC_TAG_INFO(WLBTD, "returned status : %u\n", status);
+ else
+ SCSC_TAG_ERR(WLBTD, "returned error : %u\n", status);
}
complete(&script_done);
[ATTR_INT] = { .type = NLA_U32, },
};
+static struct nla_policy policy_sable[] = {
+ [ATTR_STR] = { .type = NLA_STRING, },
+ [ATTR_INT] = { .type = NLA_U16, },
+};
+
static struct nla_policy policies_build_type[] = {
[ATTR_STR] = { .type = NLA_STRING, },
};
.doit = msg_from_wlbtd_build_type_cb,
.dumpit = NULL,
},
+ {
+ .cmd = EVENT_SABLE,
+ .flags = 0,
+ .policy = policy_sable,
+ .doit = msg_from_wlbtd_sable_cb,
+ .dumpit = NULL,
+ },
};
/* The netlink family */
return -1;
}
+int call_wlbtd_sable(const char *trigger)
+{
+ struct sk_buff *skb;
+ void *msg;
+ int rc = 0;
+ unsigned long completion_jiffies = 0;
+ unsigned long max_timeout_jiffies = msecs_to_jiffies(MAX_TIMEOUT);
+
+ SCSC_TAG_INFO(WLBTD, "start:trigger - %s\n", trigger);
+
+ skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!skb) {
+ SCSC_TAG_ERR(WLBTD, "Failed to construct message\n");
+ goto error;
+ }
+
+ SCSC_TAG_DEBUG(WLBTD, "create message\n");
+ msg = genlmsg_put(skb,
+ 0, // PID is whatever
+ 0, // Sequence number (don't care)
+ &scsc_nlfamily, // Pointer to family struct
+ 0, // Flags
+ EVENT_SABLE // Generic netlink command
+ );
+ if (!msg) {
+ SCSC_TAG_ERR(WLBTD, "Failed to create message\n");
+ goto error;
+ }
+ /* TODO: change when we get passed proper code as well */
+ SCSC_TAG_DEBUG(WLBTD, "add values to msg\n");
+ rc = nla_put_u16(skb, ATTR_INT, 0xffff);
+ if (rc) {
+ SCSC_TAG_ERR(WLBTD, "nla_put_u16 failed. rc = %d\n", rc);
+ genlmsg_cancel(skb, msg);
+ goto error;
+ }
+
+ rc = nla_put_string(skb, ATTR_STR, trigger);
+ if (rc) {
+ SCSC_TAG_ERR(WLBTD, "nla_put_string failed. rc = %d\n", rc);
+ genlmsg_cancel(skb, msg);
+ goto error;
+ }
+
+ genlmsg_end(skb, msg);
+
+ SCSC_TAG_DEBUG(WLBTD, "finalize & send msg\n");
+ /* genlmsg_multicast_allns() frees skb */
+ rc = genlmsg_multicast_allns(&scsc_nlfamily, skb, 0, 0, GFP_KERNEL);
+
+ if (rc) {
+ if (rc == -ESRCH) {
+ /* If no one registered to scsc_mcgrp (e.g. in case
+ * wlbtd is not running) genlmsg_multicast_allns
+ * returns -ESRCH. Ignore and return.
+ */
+ SCSC_TAG_WARNING(WLBTD, "WLBTD not running ?\n");
+ return rc;
+ }
+ SCSC_TAG_ERR(WLBTD, "Failed to send message. rc = %d\n", rc);
+ return rc;
+ }
+
+ SCSC_TAG_INFO(WLBTD, "waiting for completion\n");
+
+ /* wait for script to finish */
+ completion_jiffies = wait_for_completion_timeout(&script_done,
+ max_timeout_jiffies);
+
+ if (completion_jiffies != max_timeout_jiffies) {
+
+ completion_jiffies = max_timeout_jiffies - completion_jiffies;
+ SCSC_TAG_INFO(WLBTD, "log collection done in %dms\n",
+ (int)jiffies_to_msecs(completion_jiffies));
+ } else
+ SCSC_TAG_ERR(WLBTD, "wait for completion timed out !\n");
+
+ /* reinit so completion can be re-used */
+ reinit_completion(&script_done);
+
+ SCSC_TAG_INFO(WLBTD, " end:trigger - %s\n", trigger);
+
+ return rc;
+
+error:
+ /* free skb */
+ nlmsg_free(skb);
+
+ return -1;
+}
+EXPORT_SYMBOL(call_wlbtd_sable);
+
int call_wlbtd(const char *script_path)
{
struct sk_buff *skb;