diff mbox series

[RFC,v1,100/256] cl8k: add hw_assert.c

Message ID 20210617160223.160998-101-viktor.barna@celeno.com (mailing list archive)
State RFC
Delegated to: Kalle Valo
Headers show
Series wireless: cl8k driver for Celeno IEEE 802.11ax devices | expand

Commit Message

Viktor Barna June 17, 2021, 3:59 p.m. UTC
From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/hw_assert.c | 129 +++++++++++++++++++
 1 file changed, 129 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/hw_assert.c

--
2.30.0
diff mbox series

Patch

diff --git a/drivers/net/wireless/celeno/cl8k/hw_assert.c b/drivers/net/wireless/celeno/cl8k/hw_assert.c
new file mode 100644
index 000000000000..b632d70bae44
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/hw_assert.c
@@ -0,0 +1,129 @@ 
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "hw_assert.h"
+#include "recovery.h"
+#include "debug.h"
+#include "dbgfile.h"
+#include "bus/pci/ipc.h"
+#include "coredump.h"
+
+#define ASSERT_PATTERN 0xC0DEDEAD
+
+/*
+ * Function will take time stamp for each hw error indication.
+ * when time diff between each error is less than ce_hw_assert_time_max
+ * cl_hw_restart work will be scheduled
+ */
+static bool cl_hw_assert_storm_detect(struct cl_hw *cl_hw)
+{
+       struct cl_hw_asserts_info *assert_info = &cl_hw->assert_info;
+       u8 idx = assert_info->index % CL_MIN_ASSERT_CNT;
+       /* Get the oldest assert timestamp. */
+       u8 prev_idx = (assert_info->index + 1) % CL_MIN_ASSERT_CNT;
+       bool is_hw_restarted = false;
+
+       if (assert_info->restart_sched) {
+               is_hw_restarted = true;
+       } else {
+               /* Take time stamp of the assert */
+               assert_info->timestamp[idx] = jiffies;
+               assert_info->index++;
+               /* In case hw assert time diff is less than CL_HW_ASSERT_TIME_MAX, restart hw. */
+               if (assert_info->index > CL_MIN_ASSERT_CNT) {
+                       unsigned long time_diff_jiffies =
+                               assert_info->timestamp[idx] - assert_info->timestamp[prev_idx];
+                       unsigned int time_diff_msecs = jiffies_to_msecs(time_diff_jiffies);
+
+                       if (time_diff_msecs < cl_hw->conf->ce_hw_assert_time_max) {
+                               assert_info->index = 0;
+
+                               cl_dbg_err(cl_hw, "Assert storm detect (time_diff = %u)\n",
+                                          time_diff_msecs);
+                               cl_recovery_start(cl_hw, RECOVERY_ASSERT_STORM_DETECT);
+
+                               is_hw_restarted = true;
+                       }
+               }
+       }
+
+       return is_hw_restarted;
+}
+
+void cl_hw_assert_info_init(struct cl_hw *cl_hw)
+{
+       memset(&cl_hw->assert_info, 0, sizeof(cl_hw->assert_info));
+}
+
+void cl_hw_assert_print(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+       struct dbg_print_ind *ind = (struct dbg_print_ind *)msg->param;
+       const char *assert_string;
+       u32 assert_pattern;
+       u16 file_id = le16_to_cpu(ind->file_id);
+       u16 line = le16_to_cpu(ind->line);
+       u16 has_param = le16_to_cpu(ind->has_param);
+       u32 param = le32_to_cpu(ind->param);
+
+       /* If ce_hw_assert_time_max is 0, HW assert storm detection is disabled */
+       if (cl_hw->conf->ce_hw_assert_time_max)
+               if (cl_hw_assert_storm_detect(cl_hw))
+                       return;
+
+       /* Print ASSERT message with fileid, line, [parameter] */
+       if (has_param)
+               cl_dbg_err(cl_hw, "ASSERT_TCV%u @ FILE=%hu LINE=%hu param=0x%08X\n",
+                          cl_hw->idx, file_id, line, param);
+       else
+               cl_dbg_err(cl_hw, "ASSERT_TCV%u @ file=%hu line=%hu\n",
+                          cl_hw->idx, file_id, line);
+
+       assert_string = cl_dbgfile_get_msg_txt(&cl_hw->dbg_data, file_id, line);
+
+       if (!assert_string)
+               assert_string = "ASSERT STRING NOT FOUND";
+
+       /* TODO: length of single print may be limited, consider printing long msgs by pieces */
+       cl_dbg_err(cl_hw, "%.500s\n", assert_string);
+
+       assert_pattern = le32_to_cpu(cl_hw->ipc_env->shared->assert_pattern);
+
+       /* Reset ASSERT pattern if needed (in order to prevent assert prints loop) */
+       if (assert_pattern == ASSERT_PATTERN)
+               cl_hw->ipc_env->shared->assert_pattern = 0;
+
+       if (ind->err_no_dump) {
+               bool reason = RECOVERY_UNRECOVERABLE_ASSERT_NO_DUMP;
+               bool restart = cl_coredump_recovery(cl_hw, reason);
+
+               if (restart)
+                       cl_hw->assert_info.restart_needed = true;
+       } else {
+               cl_hw->assert_info.restart_needed = false;
+       }
+}
+
+void cl_hw_assert_check(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_shared_env *shared_env = cl_hw->ipc_env->shared;
+       u32 assert_pattern = le32_to_cpu(shared_env->assert_pattern);
+
+       if (assert_pattern == ASSERT_PATTERN) {
+               u16 line = le16_to_cpu(shared_env->assert_line_num);
+               u16 fileid = le16_to_cpu(shared_env->assert_file_id);
+               u32 param = le32_to_cpu(shared_env->assert_param);
+               const char *assert_string = cl_dbgfile_get_msg_txt(&cl_hw->dbg_data, fileid, line);
+
+               /* Print 1st ASSERT message with fileid, line, [parameter] */
+               cl_dbg_err(cl_hw, "ASSERT_%cmac @ FILE=%hu LINE=%hu param=0x%08X\n",
+                          cl_hw->fw_prefix, fileid, line, param);
+
+               if (!assert_string)
+                       assert_string = "ASSERT STRING NOT FOUND";
+
+               cl_dbg_err(cl_hw, "%.500s\n", assert_string);
+
+               /* Reset ASSERT pattern in order to prevent assert prints loop */
+               shared_env->assert_pattern = 0;
+       }
+}