All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rayagonda Kokatanur <rayagonda.kokatanur@broadcom.com>
To: u-boot@lists.denx.de
Subject: [PATCH v1 3/3] cmd: bcm: add broadcom error log setup command
Date: Sun, 17 May 2020 14:02:57 +0530	[thread overview]
Message-ID: <20200517083257.22191-4-rayagonda.kokatanur@broadcom.com> (raw)
In-Reply-To: <20200517083257.22191-1-rayagonda.kokatanur@broadcom.com>

From: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>

Add broadcom error log setup command.

Some Broadcom platforms have ability to record event logs by SCP.
- Add a logsetup command which is used to perform initial configuration
  of this log.
  Move this command to bcm/ directory to be used for Broadcom-specific
  U-boot commands.
- Add support for Broadcom-specific commands to Kconfig and to Makefile
  in cmd/.

Signed-off-by: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
Signed-off-by: Rayagonda Kokatanur <rayagonda.kokatanur@broadcom.com>
---
 board/broadcom/bcmns3/Kconfig |   1 +
 cmd/Kconfig                   |   2 +
 cmd/Makefile                  |   2 +
 cmd/bcm/Kconfig               |  12 +
 cmd/bcm/Makefile              |   4 +
 cmd/bcm/elog.h                |  64 +++++
 cmd/bcm/logsetup.c            | 432 ++++++++++++++++++++++++++++++++++
 7 files changed, 517 insertions(+)
 create mode 100644 cmd/bcm/Kconfig
 create mode 100644 cmd/bcm/Makefile
 create mode 100644 cmd/bcm/elog.h
 create mode 100644 cmd/bcm/logsetup.c

diff --git a/board/broadcom/bcmns3/Kconfig b/board/broadcom/bcmns3/Kconfig
index 10547f71de..6a8c7bc7db 100644
--- a/board/broadcom/bcmns3/Kconfig
+++ b/board/broadcom/bcmns3/Kconfig
@@ -15,6 +15,7 @@ config SYS_CONFIG_NAME
 config CMD_BCM_EXT_UTILS
 	bool "Enable Broadcom-specific u-boot commands"
 	default y
+	select CMD_BCM_LOGSETUP
 
 config CHIMP_OPTEE
 	bool "Enable secure ChiMP firmware loading"
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 157a33081f..d7b34828fa 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -2214,4 +2214,6 @@ config CMD_UBIFS
 	help
 	  UBIFS is a file system for flash devices which works on top of UBI.
 
+source cmd/bcm/Kconfig
+
 endmenu
diff --git a/cmd/Makefile b/cmd/Makefile
index 974ad48b0a..f9925e3a34 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -191,6 +191,8 @@ obj-$(CONFIG_$(SPL_)CMD_TLV_EEPROM) += tlv_eeprom.o
 # core command
 obj-y += nvedit.o
 
+obj-$(CONFIG_CMD_BCM_EXT_UTILS) += bcm/
+
 obj-$(CONFIG_TI_COMMON_CMD_OPTIONS) += ti/
 
 filechk_data_gz = (echo "static const char data_gz[] ="; cat $< | scripts/bin2c; echo ";")
diff --git a/cmd/bcm/Kconfig b/cmd/bcm/Kconfig
new file mode 100644
index 0000000000..189a45004e
--- /dev/null
+++ b/cmd/bcm/Kconfig
@@ -0,0 +1,12 @@
+menu "Broadcom Extended Utilities"
+
+config CMD_BCM_LOGSETUP
+	bool "Command to setup logging on Broadcom boards"
+	depends on TARGET_BCMNS3
+	default n
+	help
+	   Support specific log setup on Broadcom SoCs. This command
+	   allows checking if logging support is present, and update
+	   log sections.
+
+endmenu
diff --git a/cmd/bcm/Makefile b/cmd/bcm/Makefile
new file mode 100644
index 0000000000..96dc8f7ad7
--- /dev/null
+++ b/cmd/bcm/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2020 Broadcom
+
+obj-$(CONFIG_CMD_BCM_LOGSETUP) += logsetup.o
diff --git a/cmd/bcm/elog.h b/cmd/bcm/elog.h
new file mode 100644
index 0000000000..cc36d8739a
--- /dev/null
+++ b/cmd/bcm/elog.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2020 Broadcom
+ */
+
+#ifndef __ELOG_H__
+#define __ELOG_H__
+
+#define GLOBAL_META_HDR_SIG	0x45524c47
+#define MAX_REC_COUNT		13
+#define MAX_REC_FORMAT		1
+#define MAX_SRC_TYPE		3
+#define MAX_NVM_TYPE		3
+/* A special type. Use defaults specified in CRMU config */
+#define NVM_DEFAULT		0xff
+
+/* Max. number of cmd parameters per elog spec */
+#define PARAM_COUNT		3
+
+#define REC_DESC_LENGTH		8
+
+enum {
+	LOG_SETUP_CMD_VALIDATE_META,
+	LOG_SETUP_CMD_WRITE_META,
+	LOG_SETUP_CMD_ERASE,
+	LOG_SETUP_CMD_READ,
+	LOG_SETUP_CMD_CHECK
+};
+
+#pragma pack(push, 1)
+
+struct meta_record {
+	u8 record_type;
+	u8 record_format;
+	u8 src_mem_type;
+	u8 alt_src_mem_type;
+	u8 nvm_type;
+	char rec_desc[REC_DESC_LENGTH];
+	u64 src_mem_addr;
+	u64 alt_src_mem_addr;
+	u64 rec_addr;
+	u32 rec_size;
+	u32 sector_size;
+	u8 padding[3];
+};
+
+struct global_header {
+	u32 signature;
+	u32 sector_size;
+	u8 revision;
+	u8 rec_count;
+	u16 padding;
+};
+
+struct log_setup {
+	u32 cmd;
+	u32 params[PARAM_COUNT];
+	u32 result;
+	u32 ret_code;
+};
+
+#pragma pack(pop)
+
+#endif
diff --git a/cmd/bcm/logsetup.c b/cmd/bcm/logsetup.c
new file mode 100644
index 0000000000..271462311d
--- /dev/null
+++ b/cmd/bcm/logsetup.c
@@ -0,0 +1,432 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020 Broadcom
+ */
+
+/*
+ * Create a binary file ready to be flashed
+ * as a global meta for logging, from a source file.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <string.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+
+#include "elog.h"
+
+#define FILE_LINE_BUF_SIZE	1024
+#define GLOBAL_PARAM_COUNT	3
+#define REC_PARAM_COUNT		11
+
+#define GLOBAL_NAME		"GLOBAL"
+#define RECORD_NAME		"RECORD"
+
+#define MCU_IPC_MCU_CMD_ELOG_SETUP 0x84
+/* SPI write operations can be slow */
+#define DEFAULT_TIMEOUT_MS	10000
+
+#define MCU_IPC_CMD_DONE_MASK	0x80000000
+#define MCU_IPC_CMD_REPLY_MASK	0x3fff0000
+#define MCU_IPC_CMD_REPLY_SHIFT	16
+
+#define MIN_ARGS_COUNT		3
+#define MAX_ARGS_COUNT		5
+#define SEP_STR			","
+#define SUPPORTED_CMD		"-s"
+#define CHK_HDR_CMD		"-c"
+
+enum {
+	PARAM_GLOBAL,
+	PARAM_REC
+};
+
+static uintptr_t crmu_mbox0_address;
+
+/*
+ * Send a logging command to MCU patch for execution.
+ *
+ * Parameters:
+ *   cmd:         an IPC command code
+ *   param:       a pointer to parameters structure for IPC
+ *   is_real_cmd: whether command produces a response in the structure.
+ *                Only "support" command does not.
+ */
+static int send_crmu_log_cmd(u32 cmd, u32 param, int is_real_cmd)
+{
+	u32 timeout;
+	u32 val;
+	int ret = CMD_RET_FAILURE;
+	struct log_setup *setup;
+
+	setup = (struct log_setup *)(uintptr_t)param;
+	timeout = DEFAULT_TIMEOUT_MS;
+
+	writel(cmd, crmu_mbox0_address);
+	writel(param, crmu_mbox0_address + sizeof(u32));
+
+	do {
+		mdelay(1);
+		val = readl(is_real_cmd ? (uintptr_t)&setup->ret_code :
+						crmu_mbox0_address);
+		if (val & MCU_IPC_CMD_DONE_MASK) {
+			ret = CMD_RET_SUCCESS;
+			break;
+		}
+
+	} while (timeout--);
+
+	if (ret == CMD_RET_FAILURE) {
+		pr_err("CRMU cmd timeout!\n");
+		return ret;
+	}
+
+	/* Obtain status */
+	val = (val & MCU_IPC_CMD_REPLY_MASK) >> MCU_IPC_CMD_REPLY_SHIFT;
+	if (val)
+		ret = CMD_RET_FAILURE;
+
+	return ret;
+}
+
+static char *get_next_param(char **str, char *delimiter)
+{
+	char *ret = strsep(str, delimiter);
+
+	if (!ret)
+		return NULL;
+
+	return strim(ret);
+}
+
+static int count_chars(char *str, char delimiter)
+{
+	int count = 0;
+
+	if (!str || (!strlen(str)))
+		return 0;
+
+	do {
+		if (*str == delimiter)
+			count++;
+
+		str++;
+	} while (*str);
+
+	/* Need to consider leftovers (if any) after the last delimiter */
+	count++;
+
+	return count;
+}
+
+static int do_setup(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	struct global_header global;
+	struct log_setup setup = {0};
+	u8 *temp;
+	u8 *ptr = NULL;
+	char *buf;
+	u32 line_no = 0;
+	u32 expected_meta_size;
+	u32 data_size;
+	u32 log_offset = 0;
+	u32 num_recs = 0;
+	u32 addr;
+	int global_ready = 0;
+	int ret = CMD_RET_FAILURE;
+	int force = 0;
+
+	if (argc < MIN_ARGS_COUNT || argc > MAX_ARGS_COUNT)
+		return CMD_RET_USAGE;
+
+	/* Usage: addr or (-s/-c) mbox0_addr [data_size] [force] */
+	crmu_mbox0_address = simple_strtoul(argv[2], NULL, 16);
+	if (!crmu_mbox0_address) {
+		pr_err("Invalid CRMU mbox0 address\n");
+		return ret;
+	}
+
+	if (argc == MIN_ARGS_COUNT) {
+		if (strncmp(argv[1], SUPPORTED_CMD, 2) == 0)
+			return send_crmu_log_cmd(MCU_IPC_MCU_CMD_ELOG_SETUP,
+						 LOG_SETUP_CMD_CHECK,
+						 0
+						);
+
+		if (strncmp(argv[1], CHK_HDR_CMD, 2) == 0)
+			return send_crmu_log_cmd(MCU_IPC_MCU_CMD_ELOG_SETUP,
+						 (uintptr_t)&setup,
+						 1
+						);
+	}
+
+	/* Expect 1st parameter as a pointer to metadata */
+	addr = simple_strtoul(argv[1], NULL, 16);
+	if (!addr) {
+		pr_err("Address 0x0 is not allowed\n");
+		return ret;
+	}
+
+	data_size = simple_strtoul(argv[3], NULL, 16);
+	if (!data_size) {
+		pr_err("Invalid source size\n");
+		return ret;
+	}
+
+	if (argc == MAX_ARGS_COUNT)
+		force = simple_strtoul(argv[MAX_ARGS_COUNT - 1], NULL, 10);
+
+	memset(&global, 0, sizeof(struct global_header));
+	expected_meta_size = sizeof(struct global_header) +
+				MAX_REC_COUNT * sizeof(struct meta_record);
+
+	temp = (u8 *)malloc(expected_meta_size);
+	if (!temp)
+		return ret;
+
+	memset(temp, 0, expected_meta_size);
+
+	ptr = temp;
+	buf = (char *)(uintptr_t)addr;
+	/* End of file mark */
+	buf[data_size] = '\0';
+
+	do {
+		char  *type_name;
+		u32 entry_type;
+		char *line;
+		char *value;
+
+		line_no++;
+		line = get_next_param(&buf, "\n");
+		if (!line)
+			break;
+
+		if ((!strlen(line)) || line[0] == '#')
+			continue;
+
+		value = get_next_param(&line, "=");
+
+		if (!value || (!strlen(value))) {
+			pr_err("Invalid format of line %d\n", line_no);
+			goto free_params;
+		}
+
+		type_name = GLOBAL_NAME;
+
+		if (!strncasecmp(value, type_name, strlen(GLOBAL_NAME))) {
+			entry_type = PARAM_GLOBAL;
+		} else {
+			type_name = RECORD_NAME;
+			if (!strncasecmp(value,
+					 type_name,
+					 strlen(RECORD_NAME)
+					)
+			   ) {
+				entry_type = PARAM_REC;
+			} else {
+				pr_err("Unknown type %s, line %d\n",
+				       value,
+				       line_no
+				      );
+				goto free_params;
+			}
+		}
+
+		if (global_ready && entry_type == PARAM_GLOBAL) {
+			/* Multiple globals are not allowed */
+			pr_err("Multiple GLOBAL records, line %d\n", line_no);
+			goto free_params;
+		}
+
+		if (entry_type == PARAM_GLOBAL) {
+			/* Parse Global and create global record in outfile */
+			if (count_chars(line, ',') != GLOBAL_PARAM_COUNT) {
+				pr_err("Invalid GLOBAL format, line %d\n",
+				       line_no
+				      );
+				goto free_params;
+			}
+
+			global.sector_size =
+				simple_strtoul
+					(get_next_param(&line, SEP_STR),
+					 NULL,
+					 0
+					);
+			global.revision =
+				(u8)simple_strtoul
+					(get_next_param(&line, SEP_STR),
+					 NULL,
+					 0
+					);
+			log_offset = simple_strtoul
+					(get_next_param(&line, SEP_STR),
+					 NULL,
+					 0
+					);
+
+			if (!global.sector_size) {
+				pr_err("Invalid GLOBAL, line %d\n", line_no);
+				goto free_params;
+			}
+
+			global.signature = GLOBAL_META_HDR_SIG;
+			global_ready = 1;
+
+			/* Shift to the first RECORD header */
+			log_offset += 2 * global.sector_size;
+			ptr += sizeof(struct global_header);
+		} else {
+			struct meta_record rec = {0};
+			char *desc;
+			char *rec_addr_str;
+			int auto_addr = 0;
+
+			if (count_chars(line, ',') != REC_PARAM_COUNT) {
+				pr_err("Invalid RECORD, line %d\n", line_no);
+				goto free_params;
+			}
+
+			rec.record_type = (u8)simple_strtoul
+					(get_next_param(&line, SEP_STR),
+					 NULL,
+					 0
+					);
+			rec.record_format = (u8)simple_strtoul
+					(get_next_param(&line, SEP_STR),
+					 NULL,
+					 0
+					);
+			rec.src_mem_type = (u8)simple_strtoul
+					(get_next_param(&line, SEP_STR),
+					 NULL,
+					 0
+					);
+			rec.alt_src_mem_type = (u8)simple_strtoul
+					(get_next_param(&line, SEP_STR),
+					 NULL,
+					 0
+					);
+			rec.nvm_type = (u8)simple_strtoul
+					(get_next_param(&line, SEP_STR),
+					 NULL,
+					 0
+					);
+			desc = get_next_param(&line, SEP_STR);
+			if (desc)
+				desc = strim(desc);
+
+			rec.src_mem_addr = (u64)simple_strtoul
+					(get_next_param(&line, SEP_STR),
+					 NULL,
+					 0
+					);
+			rec.alt_src_mem_addr = (u64)simple_strtoul
+					(get_next_param(&line, SEP_STR),
+					 NULL,
+					 0
+					);
+			rec_addr_str = get_next_param(&line, SEP_STR);
+			if (rec_addr_str)
+				rec_addr_str = strim(rec_addr_str);
+
+			if (!strcmp(rec_addr_str, "auto"))
+				auto_addr = 1;
+			else
+				rec.rec_addr = (u64)simple_strtoul
+					(rec_addr_str,
+					 NULL,
+					 0
+					);
+
+			rec.rec_size = simple_strtoul
+					(get_next_param(&line, SEP_STR),
+					 NULL,
+					 0
+					);
+			rec.sector_size = simple_strtoul
+					(get_next_param(&line, SEP_STR),
+					 NULL,
+					 0
+					);
+			if (auto_addr) {
+				rec.rec_addr = (u64)log_offset;
+				log_offset += rec.rec_size;
+			}
+
+			/* Sanity checks */
+			if (rec.record_type > MAX_REC_COUNT ||
+			    rec.record_format > MAX_REC_FORMAT ||
+			    (rec.nvm_type > MAX_NVM_TYPE &&
+			     rec.nvm_type != NVM_DEFAULT) ||
+			    !rec.rec_size ||
+			    !rec.sector_size ||
+			    (!desc || !strlen(desc) ||
+			     (strlen(desc) > sizeof(rec.rec_desc) + 1)
+			    )
+			   ) {
+				pr_err("Invalid RECORD %s, line %d\n",
+				       desc ? desc : " (no desc)", line_no
+				      );
+				goto free_params;
+			}
+
+			memset(rec.rec_desc, ' ', sizeof(rec.rec_desc));
+			memcpy(rec.rec_desc, desc, strlen(desc));
+			memcpy(ptr, &rec, sizeof(struct meta_record));
+			ptr += sizeof(struct meta_record);
+			num_recs++;
+		}
+
+	} while (buf && ((uintptr_t)buf < (addr + data_size)));
+
+	if (!num_recs) {
+		pr_err("No RECORD entry!\n");
+		goto free_params;
+	}
+
+	if (!global_ready) {
+		pr_err("Global entry was not found!\n");
+		goto free_params;
+	}
+
+	if (num_recs > MAX_REC_COUNT) {
+		pr_err("Too many records (max %d)\n", MAX_REC_COUNT);
+		goto free_params;
+	}
+
+	/* Recalculate new expected size */
+	if (num_recs != MAX_REC_COUNT) {
+		expected_meta_size = sizeof(struct global_header) +
+			num_recs * sizeof(struct meta_record);
+	}
+
+	global.rec_count = num_recs;
+	memcpy(temp, &global, sizeof(struct global_header));
+
+	setup.params[0] = (uintptr_t)temp;
+	setup.params[1] = expected_meta_size;
+
+	/* Apply the command via CRMU mailboxes and read the result. */
+	setup.cmd = (force) ? LOG_SETUP_CMD_WRITE_META :
+			LOG_SETUP_CMD_VALIDATE_META;
+
+	/* Finally, request the MCU patch to perform the command */
+	ret = send_crmu_log_cmd(MCU_IPC_MCU_CMD_ELOG_SETUP,
+				(uintptr_t)(&setup),
+				1
+			       );
+
+free_params:
+	free(temp);
+
+	return ret;
+}
+
+U_BOOT_CMD(logsetup, 5, 1, do_setup, "setup Broadcom MCU logging subsystem",
+	   "\taddr mbox0_addr [data_size] [force]\nor\n\t -s(or -c) mbox0_addr"
+	  );
-- 
2.17.1

  parent reply	other threads:[~2020-05-17  8:32 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-17  8:32 [PATCH v1 0/3] add elog support for broadcom NS3 soc Rayagonda Kokatanur
2020-05-17  8:32 ` [PATCH v1 1/3] common: ns3: add error logging support Rayagonda Kokatanur
2020-05-25 17:03   ` Simon Glass
2020-08-14 19:52   ` Tom Rini
2020-08-20 15:12     ` Rayagonda Kokatanur
2020-05-17  8:32 ` [PATCH v1 2/3] board: ns3: kconfig: extend board kconfig with specific commands Rayagonda Kokatanur
2020-05-25 17:03   ` Simon Glass
2020-05-17  8:32 ` Rayagonda Kokatanur [this message]
2020-05-25 17:03   ` [PATCH v1 3/3] cmd: bcm: add broadcom error log setup command Simon Glass

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200517083257.22191-4-rayagonda.kokatanur@broadcom.com \
    --to=rayagonda.kokatanur@broadcom.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.