wlbt: Implement mxlogger module
authorAlbert Cano <a.canocamps@samsung.com>
Thu, 12 Jul 2018 17:20:05 +0000 (18:20 +0100)
committerhskang <hs1218.kang@samsung.com>
Fri, 17 Aug 2018 00:32:53 +0000 (20:32 -0400)
Implement mxlogger module, responsible of:
- Defining and providing logging buffers in Shared
DRAM
- Providing a communication channel from/to FW to
send receive low level logging commands (START,
STOP, SWITCH, FW_TRIGGER...)
- Creating an interface to register/unregister
local or global observers
- Implementing the control mechanism to instruct the
FW to store logs in Shared DRAM or stream logs to
Host

Keep logs streamed to host by default

Change-Id: Ia831573630a07c63fb3420aa28bcddd932296548
SCSC-Bug-Id: SSB-41855
Signed-off-by: Cristian Marussi <c.marussi@samsung.com>
Signed-off-by: Albert Cano <a.canocamps@samsung.com>
drivers/misc/samsung/scsc/Kconfig
drivers/misc/samsung/scsc/Makefile
drivers/misc/samsung/scsc/mxlogger.c [new file with mode: 0644]
drivers/misc/samsung/scsc/mxlogger.h [new file with mode: 0644]
drivers/misc/samsung/scsc/mxman.c
drivers/misc/samsung/scsc/mxmgmt_transport_format.h
drivers/misc/samsung/scsc/scsc_mx_impl.c
drivers/misc/samsung/scsc/scsc_mx_impl.h
drivers/misc/samsung/scsc/scsc_service.c
include/scsc/scsc_mx.h

index 82317080844e5eda74ea83eb30a7d11996c4b5b0..63f61f7cdd73c6845efc161a88b6b27d87837ae8 100644 (file)
@@ -35,6 +35,13 @@ config SCSC_PCIE
        depends on SCSC_CORE
        depends on PCI
 
+config SCSC_MXLOGGER
+       bool "Samsung SCSC MXLOGGER"
+       depends on SCSC_CORE
+       default y
+       ---help---
+          MXLOGGER provides FW level logging in DRAM
+
 config SCSC_SMAPPER
        bool "Samsung SCSC WLAN Smapper support"
        depends on SCSC_CORE
index d6e9b94f14213aabae6959676a7ce35b4416933d..13ac55555c0f24e6e27e6747fc9252851e0aa4b0 100644 (file)
@@ -84,6 +84,8 @@ scsc_mx-y += \
        mifqos.o \
        mx140_file.o
 
+scsc_mx-$(CONFIG_SCSC_MXLOGGER) += mxlogger.o
+
 scsc_mx-$(CONFIG_SCSC_SMAPPER) += mifsmapper.o
 
 scsc_mx-$(CONFIG_SCSC_WLBTD) += scsc_wlbtd.o
diff --git a/drivers/misc/samsung/scsc/mxlogger.c b/drivers/misc/samsung/scsc/mxlogger.c
new file mode 100644 (file)
index 0000000..360b2a5
--- /dev/null
@@ -0,0 +1,780 @@
+/****************************************************************************
+ *
+ * Copyright (c) 2014 - 2018 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ ****************************************************************************/
+
+/** Implements */
+#include "mxlogger.h"
+
+/** Uses */
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/atomic.h>
+#include <scsc/scsc_logring.h>
+#ifdef CONFIG_SCSC_LOG_COLLECTION
+#include <scsc/scsc_log_collector.h>
+#endif
+
+#include "srvman.h"
+#include "scsc_mif_abs.h"
+#include "miframman.h"
+#include "mifintrbit.h"
+#include "mxmgmt_transport.h"
+
+static bool mxlogger_forced_disabled = true;
+
+static int force_disable_mxlogger_set_param_cb(const char *val,
+                                              const struct kernel_param *kp)
+{
+       bool nval;
+
+       if (!val || strtobool(val, &nval))
+               return -EINVAL;
+
+       if (mxlogger_forced_disabled ^ nval) {
+               mxlogger_forced_disabled = nval;
+
+               SCSC_TAG_INFO(MXMAN, "MXLOGGER will now be %sABLED.\n",
+                             mxlogger_forced_disabled ? "FORCIBLY DIS" : "RE-EN");
+               if (mxlogger_forced_disabled)
+                       mxlogger_register_global_observer("FAKE_OBSERVER");
+               else
+                       mxlogger_unregister_global_observer("FAKE_OBSERVER");
+       }
+
+       return 0;
+}
+
+/**
+ * As described in struct kernel_param+ops the _get method:
+ * -> returns length written or -errno.  Buffer is 4k (ie. be short!)
+ */
+static int force_disable_mxlogger_get_param_cb(char *buffer,
+                                              const struct kernel_param *kp)
+{
+       return sprintf(buffer, "%c", mxlogger_forced_disabled ? 'Y' : 'N');
+}
+
+static struct kernel_param_ops force_disable_mxlogger_ops = {
+       .set = force_disable_mxlogger_set_param_cb,
+       .get = force_disable_mxlogger_get_param_cb,
+};
+module_param_cb(force_disable_mxlogger, &force_disable_mxlogger_ops, NULL, 0644);
+MODULE_PARM_DESC(force_disable_mxlogger, "Force mxlogger to be disabled, using a fake observer.");
+
+/**
+ * Observers of log material could come and go before mxman and mxlogger
+ * are initialized and started...so we keep this stuff here out of mxman,
+ * but all the lifecycle of mxlogger should be reviewed.
+ */
+static u8 active_global_observers;
+static DEFINE_MUTEX(global_lock);
+
+struct mxlogger_node {
+       struct list_head list;
+       struct mxlogger *mxl;
+};
+static struct mxlogger_list { struct list_head list; } mxlogger_list = {
+       .list = LIST_HEAD_INIT(mxlogger_list.list)
+};
+
+#ifdef CONFIG_SCSC_LOG_COLLECTION
+static int mxlogger_collect_init(struct scsc_log_collector_client *collect_client);
+static int mxlogger_collect(struct scsc_log_collector_client *collect_client, size_t size);
+static int mxlogger_collect_end(struct scsc_log_collector_client *collect_client);
+
+/* Collect client registration SYNC buffer */
+/* SYNC - SHOULD BE THE FIRST CHUNK TO BE CALLED - SO USE THE INIT/END ON THIS CLIENT */
+struct scsc_log_collector_client mxlogger_collect_client_sync = {
+       .name = "Sync",
+       .type = SCSC_LOG_CHUNK_SYNC,
+       .collect_init = mxlogger_collect_init,
+       .collect = mxlogger_collect,
+       .collect_end = mxlogger_collect_end,
+       .prv = NULL,
+};
+
+/* Collect client registration IMP buffer */
+struct scsc_log_collector_client mxlogger_collect_client_imp = {
+       .name = "Important",
+       .type = SCSC_LOG_CHUNK_IMP,
+       .collect_init = NULL,
+       .collect = mxlogger_collect,
+       .collect_end = NULL,
+       .prv = NULL,
+};
+
+struct scsc_log_collector_client mxlogger_collect_client_rsv_common = {
+       .name = "Rsv_common",
+       .type = SCSC_LOG_RESERVED_COMMON,
+       .collect_init = NULL,
+       .collect = mxlogger_collect,
+       .collect_end = NULL,
+       .prv = NULL,
+};
+
+struct scsc_log_collector_client mxlogger_collect_client_rsv_bt = {
+       .name = "Rsv_bt",
+       .type = SCSC_LOG_RESERVED_BT,
+       .collect_init = NULL,
+       .collect = mxlogger_collect,
+       .collect_end = NULL,
+       .prv = NULL,
+};
+
+struct scsc_log_collector_client mxlogger_collect_client_rsv_wlan = {
+       .name = "Rsv_wlan",
+       .type = SCSC_LOG_RESERVED_WLAN,
+       .collect_init = NULL,
+       .collect = mxlogger_collect,
+       .collect_end = NULL,
+       .prv = NULL,
+};
+
+struct scsc_log_collector_client mxlogger_collect_client_rsv_radio = {
+       .name = "Rsv_radio",
+       .type = SCSC_LOG_RESERVED_RADIO,
+       .collect_init = NULL,
+       .collect = mxlogger_collect,
+       .collect_end = NULL,
+       .prv = NULL,
+};
+/* Collect client registration MXL buffer */
+struct scsc_log_collector_client mxlogger_collect_client_mxl = {
+       .name = "MXL",
+       .type = SCSC_LOG_CHUNK_MXL,
+       .collect_init = NULL,
+       .collect = mxlogger_collect,
+       .collect_end = NULL,
+       .prv = NULL,
+};
+
+/* Collect client registration MXL buffer */
+struct scsc_log_collector_client mxlogger_collect_client_udi = {
+       .name = "UDI",
+       .type = SCSC_LOG_CHUNK_UDI,
+       .collect_init = NULL,
+       .collect = mxlogger_collect,
+       .collect_end = NULL,
+       .prv = NULL,
+};
+#endif
+
+const char *mxlogger_buf_name[] = { "syn", "imp", "rsv_common", "rsv_bt", "rsv_wlan", "rsv_radio", "mxl", "udi" };
+
+static void mxlogger_message_handler(const void *message, void *data)
+{
+       struct mxlogger         __attribute__((unused)) *mxlogger = (struct mxlogger *)data;
+       const struct log_msg_packet     *msg = message;
+
+       switch (msg->msg) {
+       case MM_MXLOGGER_INITIALIZED_EVT:
+               SCSC_TAG_INFO(MXMAN, "MXLOGGER Initialized.\n");
+               mxlogger->initialized = true;
+               complete(&mxlogger->rings_serialized_ops);
+               break;
+       case MM_MXLOGGER_STARTED_EVT:
+               SCSC_TAG_INFO(MXMAN, "MXLOGGER:: RINGS Enabled.\n");
+               mxlogger->enabled = true;
+               complete(&mxlogger->rings_serialized_ops);
+               break;
+       case MM_MXLOGGER_STOPPED_EVT:
+               SCSC_TAG_INFO(MXMAN, "MXLOGGER:: RINGS Disabled.\n");
+               mxlogger->enabled = false;
+               complete(&mxlogger->rings_serialized_ops);
+               break;
+       case MM_MXLOGGER_COLLECTION_FW_REQ_EVT:
+               SCSC_TAG_INFO(MXMAN, "MXLOGGER:: FW requested collection - Reason:%d\n", msg->arg);
+#ifdef CONFIG_SCSC_LOG_COLLECTION
+               scsc_log_collector_schedule_collection(SCSC_LOG_REASON_FW_TRIGGERED);
+#endif
+               break;
+       default:
+               SCSC_TAG_WARNING(MXMAN,
+                                "Received UNKNOWN msg on MMTRANS_CHAN_ID_MAXWELL_LOGGING -- msg->msg=%d\n",
+                                msg->msg);
+               break;
+       }
+}
+
+static int __mxlogger_generate_sync_record(struct mxlogger *mxlogger, enum mxlogger_sync_event event)
+{
+       struct mxlogger_sync_record sync_r;
+       struct timeval t;
+       struct log_msg_packet msg = {};
+       void *mem;
+
+       msg.msg = MM_MXLOGGER_SYNC_RECORD;
+       msg.arg = MM_MXLOGGER_SYNC_INDEX;
+       memcpy(&msg.payload, &mxlogger->sync_buffer_index, sizeof(mxlogger->sync_buffer_index));
+
+       do_gettimeofday(&t);
+
+       sync_r.tv_sec = (u64)t.tv_sec;
+       sync_r.tv_usec = (u64)t.tv_usec;
+       sync_r.kernel_time = ktime_to_ns(ktime_get());
+       sync_r.sync_event = event;
+
+       /* Get the pointer from the index of the sync array */
+       mem =  mxlogger->mem_sync_buf + mxlogger->sync_buffer_index * sizeof(struct mxlogger_sync_record);
+       memcpy(mem, &sync_r, sizeof(struct mxlogger_sync_record));
+
+       mxlogger->sync_buffer_index++;
+       mxlogger->sync_buffer_index &= SYNC_MASK;
+
+       /* Send the msg as fast as possible */
+       mxmgmt_transport_send(scsc_mx_get_mxmgmt_transport(mxlogger->mx),
+                             MMTRANS_CHAN_ID_MAXWELL_LOGGING,
+                             &msg, sizeof(msg));
+
+       return 0;
+}
+
+int mxlogger_generate_sync_record(struct mxlogger *mxlogger, enum mxlogger_sync_event event)
+{
+       int r;
+
+       mutex_lock(&mxlogger->lock);
+       r = __mxlogger_generate_sync_record(mxlogger, event);
+       mutex_unlock(&mxlogger->lock);
+
+       return r;
+}
+
+static bool mxlogger_wait_for_msg_reply(struct mxlogger *mxlogger)
+{
+       int ret;
+
+       reinit_completion(&mxlogger->rings_serialized_ops);
+
+       ret = wait_for_completion_timeout(&mxlogger->rings_serialized_ops, usecs_to_jiffies(MXLOGGER_RINGS_TMO_US));
+       if (ret) {
+               int i;
+
+               SCSC_TAG_DBG3(MXMAN, "MXLOGGER RINGS -- replied in %lu usecs.\n",
+                             MXLOGGER_RINGS_TMO_US - jiffies_to_usecs(ret));
+
+               for (i = 0; i < MXLOGGER_NUM_BUFFERS; i++)
+                       SCSC_TAG_DBG3(MXMAN, "MXLOGGER:: RING[%d] -- INFO[0x%X]  STATUS[0x%X]\n", i,
+                                     mxlogger->cfg->bfds[i].info, mxlogger->cfg->bfds[i].status);
+       } else {
+               SCSC_TAG_ERR(MXMAN, "MXLOGGER timeout waiting for reply.\n");
+       }
+
+       return ret ? true : false;
+}
+
+static inline void __mxlogger_enable(struct mxlogger *mxlogger, bool enable, uint8_t reason)
+{
+       struct log_msg_packet msg = {};
+
+       msg.msg = MM_MXLOGGER_LOGGER_CMD;
+       msg.arg = (enable) ? MM_MXLOGGER_LOGGER_ENABLE : MM_MXLOGGER_LOGGER_DISABLE;
+       msg.payload[0] = reason;
+
+       mxmgmt_transport_send(scsc_mx_get_mxmgmt_transport(mxlogger->mx),
+                             MMTRANS_CHAN_ID_MAXWELL_LOGGING,
+                             &msg, sizeof(msg));
+
+       SCSC_TAG_DBG4(MXMAN, "MXLOGGER RINGS -- enable:%d  reason:%d\n",
+                     enable, reason);
+
+       mxlogger_wait_for_msg_reply(mxlogger);
+}
+
+static void mxlogger_enable(struct mxlogger *mxlogger, bool enable)
+{
+       return __mxlogger_enable(mxlogger, enable, MM_MXLOGGER_DISABLE_REASON_STOP);
+}
+
+static int mxlogger_send_config(struct mxlogger *mxlogger)
+{
+       struct log_msg_packet msg = {};
+
+       SCSC_TAG_INFO(MXMAN, "MXLOGGER Config mifram_ref: 0x%x  size:%d\n",
+                     mxlogger->mifram_ref, mxlogger->msz);
+
+       msg.msg = MM_MXLOGGER_CONFIG_CMD;
+       msg.arg = MM_MXLOGGER_CONFIG_BASE_ADDR;
+       memcpy(&msg.payload, &mxlogger->mifram_ref, sizeof(mxlogger->mifram_ref));
+       mxmgmt_transport_send(scsc_mx_get_mxmgmt_transport(mxlogger->mx),
+                             MMTRANS_CHAN_ID_MAXWELL_LOGGING,
+                             &msg, sizeof(msg));
+
+       SCSC_TAG_INFO(MXMAN, "MXLOGGER Config SENT\n");
+       if (!mxlogger_wait_for_msg_reply(mxlogger))
+               return -1;
+
+       return 0;
+}
+
+static void mxlogger_to_shared_dram(struct mxlogger *mxlogger)
+{
+       struct log_msg_packet msg = { .msg = MM_MXLOGGER_DIRECTION_CMD,
+                                     .arg = MM_MXLOGGER_DIRECTION_DRAM };
+
+       SCSC_TAG_INFO(MXMAN, "MXLOGGER -- NO active observers detected. Send logs to DRAM\n");
+
+       __mxlogger_generate_sync_record(mxlogger, MXLOGGER_SYN_TORAM);
+
+       mxmgmt_transport_send(scsc_mx_get_mxmgmt_transport(mxlogger->mx),
+                             MMTRANS_CHAN_ID_MAXWELL_LOGGING,
+                             &msg, sizeof(msg));
+}
+
+static void mxlogger_to_host(struct mxlogger *mxlogger)
+{
+       struct log_msg_packet msg = { .msg = MM_MXLOGGER_DIRECTION_CMD,
+                                     .arg = MM_MXLOGGER_DIRECTION_HOST };
+
+       SCSC_TAG_INFO(MXMAN, "MXLOGGER -- active observers detected. Send logs to host\n");
+
+       __mxlogger_generate_sync_record(mxlogger, MXLOGGER_SYN_TOHOST);
+
+       mxmgmt_transport_send(scsc_mx_get_mxmgmt_transport(mxlogger->mx),
+                             MMTRANS_CHAN_ID_MAXWELL_LOGGING,
+                             &msg, sizeof(msg));
+}
+
+#ifdef CONFIG_SCSC_LOG_COLLECTION
+static void mxlogger_disable_for_collection(struct mxlogger *mxlogger)
+{
+       return __mxlogger_enable(mxlogger, false, MM_MXLOGGER_DISABLE_REASON_COLLECTION);
+}
+
+static int mxlogger_collect_init(struct scsc_log_collector_client *collect_client)
+{
+       struct mxlogger *mxlogger = (struct mxlogger *)collect_client->prv;
+
+       if (!mxlogger->initialized)
+               return 0;
+
+       mutex_lock(&mxlogger->lock);
+
+       SCSC_TAG_INFO(MXMAN, "Started log collection\n");
+
+       __mxlogger_generate_sync_record(mxlogger, MXLOGGER_SYN_LOGCOLLECTION);
+
+       mxlogger->re_enable = mxlogger->enabled;
+       /**
+        * If enabled, tell FW we are stopping for collection:
+        * this way FW can dump last minute stuff and flush properly
+        * its cache
+        */
+       if (mxlogger->enabled)
+               mxlogger_disable_for_collection(mxlogger);
+
+       mutex_unlock(&mxlogger->lock);
+
+       return 0;
+}
+
+static int mxlogger_collect(struct scsc_log_collector_client *collect_client, size_t size)
+{
+       struct scsc_mif_abs *mif;
+       struct mxlogger *mxlogger = (struct mxlogger *)collect_client->prv;
+       void *buf;
+       int ret = 0;
+       int i;
+       size_t sz;
+
+       if (mxlogger && mxlogger->mx)
+               mif = scsc_mx_get_mif_abs(mxlogger->mx);
+       else
+               return -EIO;
+
+       mutex_lock(&mxlogger->lock);
+
+       if (collect_client->type == SCSC_LOG_CHUNK_SYNC)
+               i = MXLOGGER_SYNC;
+       else if (collect_client->type == SCSC_LOG_CHUNK_IMP)
+               i = MXLOGGER_IMP;
+       else if (collect_client->type == SCSC_LOG_RESERVED_COMMON)
+               i = MXLOGGER_RESERVED_COMMON;
+       else if (collect_client->type == SCSC_LOG_RESERVED_BT)
+               i = MXLOGGER_RESERVED_BT;
+       else if (collect_client->type == SCSC_LOG_RESERVED_WLAN)
+               i = MXLOGGER_RESERVED_WLAN;
+       else if (collect_client->type == SCSC_LOG_RESERVED_RADIO)
+               i = MXLOGGER_RESERVED_RADIO;
+       else if (collect_client->type == SCSC_LOG_CHUNK_MXL)
+               i = MXLOGGER_MXLOG;
+       else if (collect_client->type == SCSC_LOG_CHUNK_UDI)
+               i = MXLOGGER_UDI;
+       else {
+               SCSC_TAG_ERR(MXMAN, "MXLOGGER Incorrect type. Return 'success' and continue to collect other buffers\n");
+               mutex_unlock(&mxlogger->lock);
+               return 0;
+       }
+
+       sz = mxlogger->cfg->bfds[i].size;
+       buf = mif->get_mifram_ptr(mif, mxlogger->cfg->bfds[i].location);
+       SCSC_TAG_INFO(MXMAN, "Writing buffer %s size: %zu\n", mxlogger_buf_name[i], sz);
+       ret = scsc_log_collector_write(buf, sz, 1);
+       if (ret) {
+               mutex_unlock(&mxlogger->lock);
+               return ret;
+       }
+
+       mutex_unlock(&mxlogger->lock);
+       return ret;
+}
+
+static int mxlogger_collect_end(struct scsc_log_collector_client *collect_client)
+{
+       struct mxlogger *mxlogger = (struct mxlogger *)collect_client->prv;
+
+       if (!mxlogger->initialized)
+               return 0;
+
+       mutex_lock(&mxlogger->lock);
+
+       SCSC_TAG_INFO(MXMAN, "End log collection\n");
+
+       /* Renable again if was previoulsy enabled */
+       if (mxlogger->re_enable)
+               mxlogger_enable(mxlogger, true);
+
+       mutex_unlock(&mxlogger->lock);
+       return 0;
+}
+#endif
+
+void mxlogger_print_mapping(struct mxlogger_config_area *cfg)
+{
+       u8 i;
+
+       SCSC_TAG_INFO(MXMAN, "MXLOGGER  -- Configured Buffers [%d]\n", cfg->config.num_buffers);
+       for (i = 0; i < MXLOGGER_NUM_BUFFERS; i++)
+               SCSC_TAG_INFO(MXMAN, "buffer %s loc: 0x%08x size: %u\n",
+                             mxlogger_buf_name[i], cfg->bfds[i].location, cfg->bfds[i].size);
+
+}
+
+/* Lock should be adquired by caller */
+int mxlogger_init(struct scsc_mx *mx, struct mxlogger *mxlogger, uint32_t mem_sz)
+{
+       struct miframman *miframman;
+       struct scsc_mif_abs *mif = scsc_mx_get_mif_abs(mx);
+       struct mxlogger_config_area *cfg;
+       size_t remaining_mem;
+       size_t udi_mxl_mem_sz;
+       struct mxlogger_node *mn;
+
+       MEM_LAYOUT_CHECK();
+
+       if (!is_power_of_2(mem_sz)) {
+               SCSC_TAG_ERR(MXMAN, "MXLOGGER size should be power of 2\n");
+               return -EIO;
+       }
+
+       //XXX ???
+       if (mem_sz <= (sizeof(struct mxlogger_config_area) + MXLOGGER_IMP_SIZE)) {
+               SCSC_TAG_ERR(MXMAN, "Insufficient memory allocation\n");
+               return -EIO;
+       }
+
+       mxlogger->mx = mx;
+       miframman = scsc_mx_get_ramman(mx);
+       if (!miframman)
+               return -ENOMEM;
+       mxlogger->mem = miframman_alloc(miframman, mem_sz, 32);
+       if (!mxlogger->mem) {
+               SCSC_TAG_ERR(MXMAN, "Error allocating memory for MXLOGGER\n");
+               return -ENOMEM;
+       }
+       mxlogger->msz = mem_sz;
+
+       /* Clear memory to avoid reading old records */
+       memset(mxlogger->mem, 0, mxlogger->msz);
+       mif->get_mifram_ref(mif, mxlogger->mem, &mxlogger->mifram_ref);
+
+       mxmgmt_transport_register_channel_handler(scsc_mx_get_mxmgmt_transport(mxlogger->mx),
+                                                 MMTRANS_CHAN_ID_MAXWELL_LOGGING,
+                                                 &mxlogger_message_handler, mxlogger);
+
+       /* Initialize configuration structure */
+       SCSC_TAG_INFO(MXMAN, "MXLOGGER Configuration: 0x%x\n", (u32)mxlogger->mifram_ref);
+       cfg = (struct mxlogger_config_area *)mxlogger->mem;
+       //memset(cfg, 0, sizeof(struct mxlogger_config_area));
+
+       cfg->config.magic_number = MXLOGGER_MAGIG_NUMBER;
+       cfg->config.config_major = MXLOGGER_MAJOR;
+       cfg->config.config_minor = MXLOGGER_MINOR;
+       cfg->config.num_buffers = MXLOGGER_NUM_BUFFERS;
+
+       /**
+        * Populate information of Fixed size buffers
+        * These are mifram-reletive references
+        */
+       cfg->bfds[MXLOGGER_SYNC].location = mxlogger->mifram_ref +
+               offsetof(struct mxlogger_config_area, buffers_start);
+       cfg->bfds[MXLOGGER_SYNC].size = MXLOGGER_SYNC_SIZE;
+       /* additionally cache the va of sync_buffer */
+       mxlogger->mem_sync_buf = mxlogger->mem +
+               offsetof(struct mxlogger_config_area, buffers_start);
+
+       cfg->bfds[MXLOGGER_IMP].location =
+               cfg->bfds[MXLOGGER_IMP - 1].location +
+               cfg->bfds[MXLOGGER_IMP - 1].size;
+       cfg->bfds[MXLOGGER_IMP].size = MXLOGGER_IMP_SIZE;
+
+       cfg->bfds[MXLOGGER_RESERVED_COMMON].location =
+               cfg->bfds[MXLOGGER_RESERVED_COMMON - 1].location +
+               cfg->bfds[MXLOGGER_RESERVED_COMMON - 1].size;
+       cfg->bfds[MXLOGGER_RESERVED_COMMON].size = MXLOGGER_RSV_COMMON_SZ;
+
+       cfg->bfds[MXLOGGER_RESERVED_BT].location =
+               cfg->bfds[MXLOGGER_RESERVED_BT - 1].location +
+               cfg->bfds[MXLOGGER_RESERVED_BT - 1].size;
+       cfg->bfds[MXLOGGER_RESERVED_BT].size = MXLOGGER_RSV_BT_SZ;
+
+       cfg->bfds[MXLOGGER_RESERVED_WLAN].location =
+               cfg->bfds[MXLOGGER_RESERVED_WLAN - 1].location +
+               cfg->bfds[MXLOGGER_RESERVED_WLAN - 1].size;
+       cfg->bfds[MXLOGGER_RESERVED_WLAN].size = MXLOGGER_RSV_WLAN_SZ;
+
+       cfg->bfds[MXLOGGER_RESERVED_RADIO].location =
+               cfg->bfds[MXLOGGER_RESERVED_RADIO - 1].location +
+               cfg->bfds[MXLOGGER_RESERVED_RADIO - 1].size;
+       cfg->bfds[MXLOGGER_RESERVED_RADIO].size = MXLOGGER_RSV_RADIO_SZ;
+
+       /* Compute buffer locations and size based on the remaining space */
+       remaining_mem = mem_sz - (sizeof(struct mxlogger_config_area) + MXLOGGER_TOTAL_FIX_BUF);
+       udi_mxl_mem_sz = remaining_mem >> 1;
+
+       cfg->bfds[MXLOGGER_MXLOG].location =
+               cfg->bfds[MXLOGGER_MXLOG - 1].location +
+               cfg->bfds[MXLOGGER_MXLOG - 1].size;
+       cfg->bfds[MXLOGGER_MXLOG].size = udi_mxl_mem_sz;
+
+       cfg->bfds[MXLOGGER_UDI].location =
+               cfg->bfds[MXLOGGER_UDI - 1].location +
+               cfg->bfds[MXLOGGER_UDI - 1].size;
+       cfg->bfds[MXLOGGER_UDI].size = udi_mxl_mem_sz;
+
+       /* Save offset to buffers array */
+       mif->get_mifram_ref(mif, cfg->bfds, &cfg->config.bfds_ref);
+
+       mxlogger_print_mapping(cfg);
+
+       mxlogger->cfg = cfg;
+
+       init_completion(&mxlogger->rings_serialized_ops);
+       mxlogger->enabled = false;
+
+       mutex_init(&mxlogger->lock);
+
+       mn = kzalloc(sizeof(*mn), GFP_KERNEL);
+       if (!mn) {
+               miframman_free(miframman, mxlogger->mem);
+               return -ENOMEM;
+       }
+
+       mutex_lock(&global_lock);
+       mxlogger->observers = active_global_observers;
+       if (mxlogger->observers)
+               SCSC_TAG_INFO(MXMAN, "Detected global %d observer[s]\n", active_global_observers);
+       mutex_unlock(&global_lock);
+
+       mxlogger->sync_buffer_index = 0;
+
+       mn->mxl = mxlogger;
+       list_add_tail(&mn->list, &mxlogger_list.list);
+
+#ifdef CONFIG_SCSC_LOG_COLLECTION
+       /**
+        * Register to the collection infrastructure
+        *
+        * All of mxlogger buffers are registered here, NO matter if
+        * MXLOGGER initialization was successfull FW side.
+        *
+        * In such a case MXLOGGER-FW will simply ignore all of our following
+        * requests and we'll end up dumping empty buffers, BUT with a partially
+        * meaningful sync buffer. (since this last is written also Host side)
+        */
+       mxlogger_collect_client_sync.prv = mxlogger;
+       scsc_log_collector_register_client(&mxlogger_collect_client_sync);
+
+       mxlogger_collect_client_imp.prv = mxlogger;
+       scsc_log_collector_register_client(&mxlogger_collect_client_imp);
+
+       mxlogger_collect_client_rsv_common.prv = mxlogger;
+       scsc_log_collector_register_client(&mxlogger_collect_client_rsv_common);
+
+       mxlogger_collect_client_rsv_bt.prv = mxlogger;
+       scsc_log_collector_register_client(&mxlogger_collect_client_rsv_bt);
+
+       mxlogger_collect_client_rsv_wlan.prv = mxlogger;
+       scsc_log_collector_register_client(&mxlogger_collect_client_rsv_wlan);
+
+       mxlogger_collect_client_rsv_radio.prv = mxlogger;
+       scsc_log_collector_register_client(&mxlogger_collect_client_rsv_radio);
+
+       mxlogger_collect_client_udi.prv = mxlogger;
+       scsc_log_collector_register_client(&mxlogger_collect_client_udi);
+
+       mxlogger_collect_client_mxl.prv = mxlogger;
+       scsc_log_collector_register_client(&mxlogger_collect_client_mxl);
+#endif
+
+       SCSC_TAG_INFO(MXMAN, "MXLOGGER Initialized.\n");
+       return 0;
+}
+
+int mxlogger_start(struct mxlogger *mxlogger)
+{
+       SCSC_TAG_INFO(MXMAN, "Starting mxlogger with %d observer[s]\n", mxlogger->observers);
+
+       mutex_lock(&mxlogger->lock);
+       if (mxlogger_send_config(mxlogger)) {
+               mutex_unlock(&mxlogger->lock);
+               return -ENOMEM;
+       }
+
+       /* Enabling before switching direction to avoid msg lost */
+       mxlogger_enable(mxlogger, true);
+
+       if (mxlogger->observers == 0)
+               mxlogger_to_shared_dram(mxlogger);
+       else
+               mxlogger_to_host(mxlogger);
+
+       SCSC_TAG_INFO(MXMAN, "MXLOGGER Configured.\n");
+       mutex_unlock(&mxlogger->lock);
+
+       return 0;
+}
+
+void mxlogger_deinit(struct scsc_mx *mx, struct mxlogger *mxlogger)
+{
+       struct miframman *miframman = NULL;
+       struct mxlogger_node *mn, *next;
+       bool match = false;
+
+       mutex_lock(&mxlogger->lock);
+       mxlogger->initialized = false;
+       mxlogger_to_host(mxlogger);
+       mxlogger_enable(mxlogger, false);
+       mxmgmt_transport_register_channel_handler(scsc_mx_get_mxmgmt_transport(mxlogger->mx),
+                                                 MMTRANS_CHAN_ID_MAXWELL_LOGGING,
+                                                 NULL, NULL);
+       miframman = scsc_mx_get_ramman(mx);
+       if (miframman)
+               miframman_free(miframman, mxlogger->mem);
+
+       list_for_each_entry_safe(mn, next, &mxlogger_list.list, list) {
+               if (mn->mxl == mxlogger) {
+                       match = true;
+                       list_del(&mn->list);
+                       kfree(mn);
+               }
+       }
+
+       if (match == false)
+               SCSC_TAG_ERR(MXMAN, "FATAL, no match for given scsc_mif_abs\n");
+
+#ifdef CONFIG_SCSC_LOG_COLLECTION
+       scsc_log_collector_unregister_client(&mxlogger_collect_client_sync);
+       scsc_log_collector_unregister_client(&mxlogger_collect_client_imp);
+       scsc_log_collector_unregister_client(&mxlogger_collect_client_rsv_common);
+       scsc_log_collector_unregister_client(&mxlogger_collect_client_rsv_bt);
+       scsc_log_collector_unregister_client(&mxlogger_collect_client_rsv_wlan);
+       scsc_log_collector_unregister_client(&mxlogger_collect_client_rsv_radio);
+       scsc_log_collector_unregister_client(&mxlogger_collect_client_mxl);
+       scsc_log_collector_unregister_client(&mxlogger_collect_client_udi);
+#endif
+       mutex_unlock(&mxlogger->lock);
+}
+
+int mxlogger_register_observer(struct mxlogger *mxlogger, char *name)
+{
+       mutex_lock(&mxlogger->lock);
+
+       mxlogger->observers++;
+
+       SCSC_TAG_INFO(MXMAN, "Register observer[%d] -- %s\n",
+                     mxlogger->observers, name);
+
+       /* Switch logs to host */
+       mxlogger_to_host(mxlogger);
+
+       mutex_unlock(&mxlogger->lock);
+
+       return 0;
+}
+
+int mxlogger_unregister_observer(struct mxlogger *mxlogger, char *name)
+{
+       mutex_lock(&mxlogger->lock);
+
+       if (mxlogger->observers == 0) {
+               SCSC_TAG_INFO(MXMAN, "Incorrect number of observers \n");
+               mutex_unlock(&mxlogger->lock);
+               return -EIO;
+       }
+
+       mxlogger->observers--;
+
+       SCSC_TAG_INFO(MXMAN, "UN-register observer[%d] --  %s\n",
+                     mxlogger->observers, name);
+
+       if (mxlogger->observers == 0)
+               mxlogger_to_shared_dram(mxlogger);
+
+       mutex_unlock(&mxlogger->lock);
+
+       return 0;
+}
+
+/* Global observer are not associated to any [mx] mxlogger instance. So it registers as
+ * an observer to all the [mx] mxlogger instances. */
+int mxlogger_register_global_observer(char *name)
+{
+       struct mxlogger_node *mn, *next;
+
+       mutex_lock(&global_lock);
+       active_global_observers++;
+
+       SCSC_TAG_INFO(MXMAN, "Register global observer[%d] -- %s\n",
+                     active_global_observers, name);
+
+       if (list_empty(&mxlogger_list.list)) {
+               SCSC_TAG_INFO(MXMAN, "No instances of mxman\n");
+               mutex_unlock(&global_lock);
+               return -EIO;
+       }
+
+       list_for_each_entry_safe(mn, next, &mxlogger_list.list, list) {
+               /* There is a mxlogger instance */
+               mxlogger_register_observer(mn->mxl, name);
+       }
+
+       mutex_unlock(&global_lock);
+
+       return 0;
+}
+
+int mxlogger_unregister_global_observer(char *name)
+{
+       struct mxlogger_node *mn, *next;
+
+       mutex_lock(&global_lock);
+       if (active_global_observers)
+               active_global_observers--;
+
+       SCSC_TAG_INFO(MXMAN, "UN-register global observer[%d] --  %s\n",
+                     active_global_observers, name);
+
+       list_for_each_entry_safe(mn, next, &mxlogger_list.list, list) {
+               /* There is a mxlogger instance */
+               mxlogger_unregister_observer(mn->mxl, name);
+       }
+
+       mutex_unlock(&global_lock);
+
+       return 0;
+}
+
diff --git a/drivers/misc/samsung/scsc/mxlogger.h b/drivers/misc/samsung/scsc/mxlogger.h
new file mode 100644 (file)
index 0000000..6651155
--- /dev/null
@@ -0,0 +1,215 @@
+/****************************************************************************
+ *
+ * Copyright (c) 2014 - 2016 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ ****************************************************************************/
+
+/**
+ * Maxwell mxlogger (Interface)
+ *
+ * Provides bi-directional communication between the firmware and the
+ * host.
+ *
+ */
+
+#ifndef __MX_LOGGER_H__
+#define __MX_LOGGER_H__
+
+#include <linux/types.h>
+#include <scsc/scsc_mifram.h>
+#include <linux/mutex.h>
+#include <linux/time.h>
+#include <linux/ktime.h>
+#include <linux/completion.h>
+#include <linux/jiffies.h>
+
+#include "mxmgmt_transport_format.h"
+
+/**
+ * ___________________________________________________________________
+ * |    Cmd       |    Arg       |   ...  payload (opt)  ...         |
+ * -------------------------------------------------------------------
+ * <-- uint8_t --><-- uint8_t --><-----  uint8_t[] buffer ----------->
+ *
+ */
+
+#define MXL_POOL_SZ                    (4 * 1024 * 1024)
+
+#define        MXLOGGER_RINGS_TMO_US           200000
+
+/* CMD/EVENTS */
+#define MM_MXLOGGER_LOGGER_CMD                 (0)
+#define MM_MXLOGGER_DIRECTION_CMD              (1)
+#define MM_MXLOGGER_CONFIG_CMD                 (2)
+#define MM_MXLOGGER_INITIALIZED_EVT            (3)
+#define MM_MXLOGGER_SYNC_RECORD                        (4)
+#define        MM_MXLOGGER_STARTED_EVT                 (5)
+#define        MM_MXLOGGER_STOPPED_EVT                 (6)
+#define        MM_MXLOGGER_COLLECTION_FW_REQ_EVT       (7)
+
+/* ARG - LOGGER */
+#define MM_MXLOGGER_LOGGER_ENABLE              (0)
+#define MM_MXLOGGER_LOGGER_DISABLE             (1)
+#define MM_MXLOGGER_DISABLE_REASON_STOP                (0)
+#define MM_MXLOGGER_DISABLE_REASON_COLLECTION  (1)
+
+/* ARG - DIRECTION */
+#define MM_MXLOGGER_DIRECTION_DRAM     (0)
+#define MM_MXLOGGER_DIRECTION_HOST     (1)
+
+/* ARG - CONFIG TABLE */
+#define MM_MXLOGGER_CONFIG_BASE_ADDR   (0)
+
+/* ARG - CONFIG TABLE */
+#define MM_MXLOGGER_SYNC_INDEX         (0)
+
+#define MM_MXLOGGER_PAYLOAD_SZ          (MXMGR_MESSAGE_PAYLOAD_SIZE - 2)
+
+#define MXLOGGER_SYNC_SIZE             (10 * 1024)
+#define MXLOGGER_IMP_SIZE              (102 * 1024)
+#define MXLOGGER_RSV_COMMON_SZ         (4 * 1024)
+#define MXLOGGER_RSV_BT_SZ             (4 * 1024)
+#define MXLOGGER_RSV_WLAN_SZ           (4 * 1024)
+#define MXLOGGER_RSV_RADIO_SZ          (4 * 1024)
+
+#define MXLOGGER_TOTAL_FIX_BUF         (MXLOGGER_SYNC_SIZE + MXLOGGER_IMP_SIZE + \
+                                       MXLOGGER_RSV_COMMON_SZ + MXLOGGER_RSV_BT_SZ + \
+                                       MXLOGGER_RSV_WLAN_SZ + MXLOGGER_RSV_RADIO_SZ)
+/* Add further buffers in pow2 size */
+
+#define MXLOGGER_MAGIG_NUMBER          0xcaba0401
+#define MXLOGGER_MAJOR                 0
+#define MXLOGGER_MINOR                 0
+
+#define NUM_SYNC_RECORDS               256
+#define SYNC_MASK                      (NUM_SYNC_RECORDS - 1)
+
+/* Shared memory Layout
+ *
+ * |-------------------------| CONFIG
+ * |    CONFIG AREA          |
+ * |    ...                  |
+ * |    *bufs               |------|
+ * |    ....                 |      |
+ * |    ....                 |      |
+ * |  --------------------   |<-----|
+ * |                         |
+ * |  loc | sz | state |info |---------------------|
+ * |  loc | sz | state |info |---------------------|
+ * |  loc | sz | state |info |---------------------|
+ * |    ...                  |                     |
+ * |-------------------------| Fixed size buffers  |
+ * |     SYNC  BUFFER        |<--------------------|
+ * |-------------------------|                            |
+ * |     IMPORTANT EVENTS    |<--------------------|
+ * |-------------------------|                     |
+ * |    Reserved COMMON      |<--------------------|
+ * |-------------------------|
+ * |    Reserved BT          |
+ * |-------------------------|
+ * |    Reserved WL          |
+ * |-------------------------|
+ * |    Reserved RADIO       |
+ * |-------------------------| Not fixed size buffers
+ * |         MXLOG           |
+ * |-------------------------|
+ * |         UDI             |
+ * |-------------------------|
+ * |  Future buffers (TBD)   |
+ * |-------------------------|
+ * |  Future buffers (TBD)   |
+ * |-------------------------|
+ */
+
+enum mxlogger_buffers {
+       MXLOGGER_FIRST_FIXED_SZ,
+       MXLOGGER_SYNC = MXLOGGER_FIRST_FIXED_SZ,
+       MXLOGGER_IMP,
+       MXLOGGER_RESERVED_COMMON,
+       MXLOGGER_RESERVED_BT,
+       MXLOGGER_RESERVED_WLAN,
+       MXLOGGER_RESERVED_RADIO,
+       MXLOGGER_LAST_FIXED_SZ = MXLOGGER_RESERVED_RADIO,
+       MXLOGGER_MXLOG,
+       MXLOGGER_UDI,
+       MXLOGGER_NUM_BUFFERS
+};
+
+enum mxlogger_sync_event {
+       MXLOGGER_SYN_SUSPEND,
+       MXLOGGER_SYN_RESUME,
+       MXLOGGER_SYN_TOHOST,
+       MXLOGGER_SYN_TORAM,
+       MXLOGGER_SYN_LOGCOLLECTION,
+};
+
+struct mxlogger_sync_record {
+       u64 tv_sec; /* struct timeval.tv_sec */
+       u64 tv_usec; /* struct timeval.tv_usec */
+       u64 kernel_time; /* ktime_t */
+       u32 sync_event; /* type of sync event*/
+       u32 fw_time;
+       u32 fw_wrap;
+       u8  reserved[4];
+} __packed;
+
+struct buffer_desc {
+       u32 location;                   /* Buffer location */
+       u32 size;                       /* Buffer sz (in bytes) */
+       u32 status;                     /* buffer status */
+       u32 info;                       /* buffer info */
+} __packed;
+
+struct mxlogger_config {
+       u32                     magic_number;   /* 0xcaba0401 */
+       u32                     config_major;   /* Version Major */
+       u32                     config_minor;   /* Version Minor */
+       u32                     num_buffers;    /* configured buffers */
+       scsc_mifram_ref         bfds_ref;
+} __packed;
+
+struct mxlogger_config_area {
+       struct  mxlogger_config  config;
+       struct  buffer_desc      bfds[MXLOGGER_NUM_BUFFERS];
+       uint8_t *buffers_start;
+} __packed;
+
+struct log_msg_packet {
+       uint8_t         msg;            /* cmd or event id */
+       uint8_t         arg;
+       uint8_t         payload[MM_MXLOGGER_PAYLOAD_SZ];
+} __packed;
+
+struct mxlogger {
+       bool                            initialized;
+       bool                            enabled;
+       struct scsc_mx                  *mx;
+       void                            *mem;
+       void                            *mem_sync_buf;
+       uint32_t                        msz;
+       scsc_mifram_ref                 mifram_ref;
+       struct mutex                    lock;
+       struct mxlogger_config_area     *cfg;
+       u8                              observers;
+       u8                              sync_buffer_index;
+       /* collection variables */
+       bool                            re_enable;
+       struct completion               rings_serialized_ops;
+};
+
+int mxlogger_generate_sync_record(struct mxlogger *mxlogger, enum mxlogger_sync_event event);
+int mxlogger_dump_shared_memory_to_file(struct mxlogger *mxlogger);
+int mxlogger_init(struct scsc_mx *mx, struct mxlogger *mxlogger, uint32_t mem_sz);
+void mxlogger_deinit(struct scsc_mx *mx, struct mxlogger *mxlogger);
+int mxlogger_start(struct mxlogger *mxlogger);
+int mxlogger_register_observer(struct mxlogger *mxlogger, char *name);
+int mxlogger_unregister_observer(struct mxlogger *mxlogger, char *name);
+int mxlogger_register_global_observer(char *name);
+int mxlogger_unregister_global_observer(char *name);
+
+#define MEM_LAYOUT_CHECK()     \
+ ({                            \
+       BUILD_BUG_ON((sizeof(struct mxlogger_sync_record) * NUM_SYNC_RECORDS) >  MXLOGGER_SYNC_SIZE); \
+ })
+
+#endif /* __MX_LOGGER_H__ */
index 4e4e74226564cbb71f225e26e65d6f4b4a45a00c..8a25d6b16bc503a7c11f4693e6e1a8ffb2f6eaf9 100755 (executable)
@@ -23,6 +23,7 @@
 #include "fwimage.h"
 #include "fwhdr.h"
 #include "mxlog.h"
+#include "mxlogger.h"
 #include "fw_panic_record.h"
 #include "panicmon.h"
 #include "mxproc.h"
@@ -35,6 +36,9 @@
 #include <scsc/scsc_release.h>
 #include "scsc_mx.h"
 #include <linux/fs.h>
+#ifdef CONFIG_SCSC_LOG_COLLECTION
+#include <scsc/scsc_log_collector.h>
+#endif
 
 #include <scsc/scsc_logring.h>
 #ifdef CONFIG_SCSC_WLBTD
@@ -873,6 +877,9 @@ static int mxman_start(struct mxman *mxman)
                                                  &mxman_message_handler, mxman);
 
        mxlog_init(scsc_mx_get_mxlog(mxman->mx), mxman->mx, mxman->fw_build_id);
+#ifdef CONFIG_SCSC_MXLOGGER
+       mxlogger_init(mxman->mx, scsc_mx_get_mxlogger(mxman->mx), MXL_POOL_SZ);
+#endif
 #ifdef CONFIG_SCSC_SMAPPER
        /* Initialize SMAPPER */
        mifsmapper_init(scsc_mx_get_smapper(mxman->mx), mif);
@@ -933,6 +940,9 @@ static int mxman_start(struct mxman *mxman)
                        mxman_stop(mxman);
                        return r;
                }
+#ifdef CONFIG_SCSC_MXLOGGER
+               mxlogger_start(scsc_mx_get_mxlogger(mxman->mx));
+#endif
        } else {
                msleep(WAIT_FOR_FW_TO_START_DELAY_MS);
        }
@@ -1320,6 +1330,11 @@ static void mxman_failure_work(struct work_struct *work)
                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);
        mutex_unlock(&mxman->mxman_mutex);
@@ -1468,7 +1483,6 @@ static int __mxman_open(struct mxman *mxman)
                mxman->users++;
                mxman->mxman_state = MXMAN_STATE_STARTED;
                mutex_unlock(&mxman->mxman_mutex);
-
                /* Start mxlogger */
                if (!disable_logger) {
                        static char mxlbin[128];
@@ -1608,6 +1622,12 @@ void mxman_close(struct mxman *mxman)
                        mutex_unlock(&mxman->mxman_mutex);
                        return;
                }
+#ifdef CONFIG_SCSC_MXLOGGER
+               /**
+                * Deinit mxlogger on last service stop...BUT before asking for HALT
+                */
+               mxlogger_deinit(mxman->mx, scsc_mx_get_mxlogger(mxman->mx));
+#endif
                /*
                 * Ask the subsystem to stop (MM_STOP_REQ), and wait
                 * for response (MM_STOP_RSP).
@@ -1755,6 +1775,9 @@ int mxman_suspend(struct mxman *mxman)
 
        if (mxman->mxman_state == MXMAN_STATE_STARTED) {
                SCSC_TAG_INFO(MXMAN, "MM_HOST_SUSPEND\n");
+#ifdef CONFIG_SCSC_MXLOGGER
+               mxlogger_generate_sync_record(scsc_mx_get_mxlogger(mxman->mx), MXLOGGER_SYN_SUSPEND);
+#endif
                mxmgmt_transport_send(scsc_mx_get_mxmgmt_transport(mxman->mx), MMTRANS_CHAN_ID_MAXWELL_MANAGEMENT, &message, sizeof(message));
                mxman->suspended = 1;
                atomic_inc(&mxman->suspend_count);
@@ -1793,6 +1816,9 @@ void mxman_resume(struct mxman *mxman)
 
        if (mxman->mxman_state == MXMAN_STATE_STARTED) {
                SCSC_TAG_INFO(MXMAN, "MM_HOST_RESUME\n");
+#ifdef CONFIG_SCSC_MXLOGGER
+               mxlogger_generate_sync_record(scsc_mx_get_mxlogger(mxman->mx), MXLOGGER_SYN_RESUME);
+#endif
                mxmgmt_transport_send(scsc_mx_get_mxmgmt_transport(mxman->mx), MMTRANS_CHAN_ID_MAXWELL_MANAGEMENT, &message, sizeof(message));
                mxman->suspended = 0;
        }
@@ -1968,7 +1994,9 @@ EXPORT_SYMBOL(mxman_get_fw_version);
 
 void mxman_get_driver_version(char *version, size_t ver_sz)
 {
-       snprintf(version, ver_sz - 1, "drv_ver: %d.%d.%d.%d",
+       /* IMPORTANT - Do not change the formatting as User space tooling is parsing the string
+       * to read SAP fapi versions. */
+       snprintf(version, ver_sz - 1, "drv_ver: %u.%u.%u.%u",
                 SCSC_RELEASE_PRODUCT, SCSC_RELEASE_ITERATION, SCSC_RELEASE_CANDIDATE, SCSC_RELEASE_POINT);
 #ifdef CONFIG_SCSC_WLBTD
        scsc_wlbtd_get_and_print_build_type();
index 8b6b264353a8dd06af108f585660052687462173..32200dfc5f15e99be9b6cbab7fcba6682e2b21ed 100644 (file)
@@ -7,6 +7,8 @@
 #ifndef MXMGR_TRANSPORT_FORMAT_H__
 #define MXMGR_TRANSPORT_FORMAT_H__
 
+#define MXMGR_MESSAGE_PAYLOAD_SIZE 7
+
 /**
  * Layout of messages across the manager transport streams.
  *
@@ -15,7 +17,7 @@
  */
 struct mxmgr_message {
        uint8_t channel_id; /* Channel ID from mxmgr_channels */
-       uint8_t payload[7]; /* Message content to store in the transport stream - user defined format */
+       uint8_t payload[MXMGR_MESSAGE_PAYLOAD_SIZE]; /* Message content to store in the transport stream - user defined format */
 } __packed;
 
 #endif /* MXMGR_TRANSPORT_FORMAT_H__ */
index 297f8e05547474a0d6915e80b5bbd06f5ddc6957..b83877d2617afd1c1222a5ec805b58eb15c52d7c 100644 (file)
@@ -20,6 +20,7 @@
 #include "mxmgmt_transport.h"
 #include "gdb_transport.h"
 #include "mxlog.h"
+#include "mxlogger.h"
 #include "panicmon.h"
 #include "mxlog_transport.h"
 #include "suspendmon.h"
@@ -43,6 +44,7 @@ struct scsc_mx {
        struct gdb_transport    gdb_transport_m4;
        int                     users;
        struct mxlog            mxlog;
+       struct mxlogger         mxlogger;
        struct panicmon         panicmon;
        struct mxlog_transport  mxlog_transport;
        struct suspendmon       suspendmon;
@@ -171,6 +173,11 @@ struct mxlog_transport *scsc_mx_get_mxlog_transport(struct scsc_mx *mx)
        return &mx->mxlog_transport;
 }
 
+struct mxlogger *scsc_mx_get_mxlogger(struct scsc_mx *mx)
+{
+       return &mx->mxlogger;
+}
+
 struct suspendmon *scsc_mx_get_suspendmon(struct scsc_mx *mx)
 {
        return &mx->suspendmon;
index 38b2a12cbb874acbbe4114e5f1b8631d3a98f0b3..b35c776a973eb4a8423a6f7e84e58c7efff62c41 100644 (file)
@@ -40,6 +40,7 @@ struct gdb_transport    *scsc_mx_get_gdb_transport_r4(struct scsc_mx *mx);
 struct gdb_transport    *scsc_mx_get_gdb_transport_m4(struct scsc_mx *mx);
 struct mxlog            *scsc_mx_get_mxlog(struct scsc_mx *mx);
 struct mxlog_transport  *scsc_mx_get_mxlog_transport(struct scsc_mx *mx);
+struct mxlogger         *scsc_mx_get_mxlogger(struct scsc_mx *mx);
 struct panicmon         *scsc_mx_get_panicmon(struct scsc_mx *mx);
 struct suspendmon      *scsc_mx_get_suspendmon(struct scsc_mx *mx);
 int mx140_file_download_fw(struct scsc_mx *mx, void *dest, size_t dest_size, u32 *fw_image_size);
index 8dd342dd0428d2e66e41dcb6d03e63fe8c09ec3b..d47014ea7b9cd2254e78243657d31a41abf9ba7a 100755 (executable)
@@ -21,6 +21,7 @@
 #include "mifsmapper.h"
 #endif
 #include "mifqos.h"
+#include "mxlogger.h"
 #include "srvman.h"
 #include "servman_messages.h"
 #include "mxmgmt_transport.h"
@@ -983,3 +984,41 @@ int scsc_service_pm_qos_remove_request(struct scsc_service *service)
        return 0;
 }
 EXPORT_SYMBOL(scsc_service_pm_qos_remove_request);
+
+#ifdef CONFIG_SCSC_MXLOGGER
+/* If there is no service/mxman associated, register the observer as global (will affect all the mx instanes)*/
+/* Users of these functions should ensure that the registers/unregister functions are balanced (i.e. if observer is registed as global,
+ * it _has_ to unregister as global) */
+int scsc_service_register_observer(struct scsc_service *service, char *name)
+{
+       struct scsc_mx      *mx;
+
+       if (!service)
+               return mxlogger_register_global_observer(name);
+
+       mx = service->mx;
+
+       if (!mx)
+               return -EIO;
+
+       return mxlogger_register_observer(scsc_mx_get_mxlogger(mx), name);
+}
+EXPORT_SYMBOL(scsc_service_register_observer);
+
+/* If there is no service/mxman associated, unregister the observer as global (will affect all the mx instanes)*/
+int scsc_service_unregister_observer(struct scsc_service *service, char *name)
+{
+       struct scsc_mx      *mx;
+
+       if (!service)
+               return mxlogger_unregister_global_observer(name);
+
+       mx = service->mx;
+
+       if (!mx)
+               return -EIO;
+
+       return mxlogger_unregister_observer(scsc_mx_get_mxlogger(mx), name);
+}
+EXPORT_SYMBOL(scsc_service_unregister_observer);
+#endif
index 0c17b3fcbee81147221302464c6af9809917a4e8..f18de32079b8fdff6ddde646e2ce801ad6937500 100755 (executable)
@@ -74,6 +74,8 @@ struct scsc_service_client {
        int (*suspend)(struct scsc_service_client *client);
        /* called when AP processor has resumed */
        int (*resume)(struct scsc_service_client *client);
+       /* called when log collection has been triggered */
+       void (*log)(struct scsc_service_client *client, u16 reason);
 };
 
 #ifdef CONFIG_SCSC_FM
@@ -226,6 +228,15 @@ u16 scsc_service_get_alignment(struct scsc_service *service);
 int scsc_service_pm_qos_add_request(struct scsc_service *service, enum scsc_qos_config config);
 int scsc_service_pm_qos_update_request(struct scsc_service *service, enum scsc_qos_config config);
 int scsc_service_pm_qos_remove_request(struct scsc_service *service);
+
+/* MXLOGGER API */
+/* If there is no service/mxman associated, register the observer as global (will affect all the mx instanes)*/
+/* Users of these functions should ensure that the registers/unregister functions are balanced (i.e. if observer is registed as global,
+ * it _has_ to unregister as global) */
+int scsc_service_register_observer(struct scsc_service *service, char *name);
+/* Unregister an observer */
+int scsc_service_unregister_observer(struct scsc_service *service, char *name);
+
 /* Reads a configuration file into memory.
  *
  * Path is relative to the currently selected firmware configuration