Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 6cf4cf6b authored by derfelot's avatar derfelot
Browse files

soc: qcom: Add Sony error logging and subsystem restart

Taken from Sony 47.2.A.10.107 stock kernel
parent 8627e118
Loading
Loading
Loading
Loading
+154 −0
Original line number Diff line number Diff line
@@ -10,6 +10,11 @@
 * GNU General Public License for more details.
 *
 */
/*
 * NOTE: This file has been modified by Sony Mobile Communications Inc.
 * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc,
 * and licensed under the license of the file.
 */
#include <linux/debugfs.h>
#include <linux/errno.h>
#include <linux/delay.h>
@@ -26,6 +31,11 @@

#include <soc/qcom/scm.h>
#include <soc/qcom/qseecomi.h>
#include <soc/qcom/security_status.h>

#ifdef CONFIG_LAST_LOGS
#include <soc/qcom/last_logs_tz.h>
#endif

/* QSEE_LOG_BUF_SIZE = 32K */
#define QSEE_LOG_BUF_SIZE 0x8000
@@ -1165,6 +1175,150 @@ err:
	return -ENXIO;
}

#ifdef CONFIG_LAST_LOGS
#define TZBSP_DIAG_MAGIC 0x747a6461
#define MAX_BANNER_LEN 1024
#define TZDBG_STATS_COUNT (TZDBG_LOG + 1)
static int (*disp_stat[TZDBG_STATS_MAX])(void);
static char *merge_buf;
static uint32_t merge_buf_len;

static int _tz_log_stats(void)
{
	static struct tzdbg_log_pos_t log_start = {0};
	struct tzdbg_log_t *log_ptr;

	log_ptr = (struct tzdbg_log_t *)((unsigned char *)tzdbg.diag_buf +
			tzdbg.diag_buf->ring_off -
			offsetof(struct tzdbg_log_t, log_buf));

	/* No data in ring buffer, so no need to hang around */
	if (log_ptr && log_ptr->log_pos.offset == 0 && log_ptr->log_pos.wrap == 0)
		return 0;

	return _disp_log_stats(log_ptr, &log_start,
			tzdbg.diag_buf->ring_len, debug_rw_buf_size, TZDBG_LOG);
}

static void merge_buffers(void)
{
	int data_len = 0, len = 0, i, status = SECURITY_ON;

	if (get_security_status(&status) < 0)
		pr_warn("Unable to get security status.\n");

	for (i = 0; i < TZDBG_STATS_COUNT; i++) {
		if ((status == SECURITY_ON) && (i == TZDBG_LOG))
			continue;

		if ((len + MAX_BANNER_LEN + debug_rw_buf_size) <
				merge_buf_len) {
			len += snprintf(merge_buf + len,
				MAX_BANNER_LEN, "\n\n--------%s--------\n\n",
				tzdbg.stat[i].name);
			data_len = disp_stat[i]();
			memcpy(merge_buf + len, tzdbg.stat[i].data, data_len);
			len += data_len;
			memset(tzdbg.disp_buf, 0x0, debug_rw_buf_size);
		}
	}

	merge_buf_len = len;
	pr_info("Length of merged buffers %d\n", len);
}

int format_tzbsp_log(void *src, size_t src_sz, void **dst, uint32_t *dst_sz)
{
	char *save_disp_buf_addr = NULL;
	uint32_t save_debug_rw_buf_size = 0;
	struct tzdbg_t *dbg = (struct tzdbg_t *)src;
	int ret = 0;

	if (debug_rw_buf_size != src_sz)
		pr_warn("%s: Diag buffer size does not match - 0x%lx",
			__func__, src_sz);

	if (dbg == NULL || !src_sz || !tzdbg.diag_buf)
		return -EINVAL;

	/* validate tzdiag area w.r.t magic */
	if (dbg->magic_num != TZBSP_DIAG_MAGIC) {
		pr_err("No magic found, magic: 0x%x\n", dbg->magic_num);
		return -ENXIO;
	}

	/* As we use the tzdbg.disp_buf pointer, backup tzdbg.disp_buf and
	   restore it before returns */
	save_disp_buf_addr = tzdbg.disp_buf;
	save_debug_rw_buf_size = debug_rw_buf_size;

	/* Debug buffer size increased to 48k (12K*4) size.
	   Because, formatted output buffer size is more than the
	   unformatted buffer size */
	/* debug_rw_buf_size is modified and will be restored
	   before the function returns*/
	debug_rw_buf_size = src_sz * 4;

	/* Merge buffer increased to 294k size */
	merge_buf_len = (debug_rw_buf_size + MAX_BANNER_LEN) *
				TZDBG_STATS_COUNT;

	merge_buf = kzalloc(merge_buf_len, GFP_KERNEL);
	if (merge_buf == NULL) {
		pr_err("%s: Can't Allocate memory: merged_buf\n",
		__func__);
		ret = -ENOMEM;
		goto exit;
	}

	tzdbg.disp_buf = kzalloc(debug_rw_buf_size, GFP_KERNEL);
	if (tzdbg.disp_buf == NULL) {
		pr_err("%s: Can't Allocate memory: disp_buf\n",
		__func__);
		ret = -ENOMEM;
		goto exit1;
	}

	memcpy(tzdbg.diag_buf, src, src_sz);

	disp_stat[TZDBG_BOOT] = _disp_tz_boot_stats;
	disp_stat[TZDBG_RESET] = _disp_tz_reset_stats;
	disp_stat[TZDBG_INTERRUPT] = _disp_tz_interrupt_stats;
	disp_stat[TZDBG_VMID] = _disp_tz_vmid_stats;
	disp_stat[TZDBG_GENERAL] = _disp_tz_general_stats;
	if (TZBSP_DIAG_MAJOR_VERSION_LEGACY <
			(tzdbg.diag_buf->version >> 16)) {
		disp_stat[TZDBG_LOG] = _tz_log_stats;
	} else {
		disp_stat[TZDBG_LOG] = _disp_tz_log_stats_legacy;
	}

	merge_buffers();
	/* Allocate required buffer to store the formatted logs */
	*dst = kzalloc(merge_buf_len, GFP_KERNEL);
	if (*dst == NULL) {
		pr_err("%s: Can't Allocate memory: buffer\n",
		__func__);
		ret = -ENOMEM;
		goto exit2;
	}

	*dst_sz = merge_buf_len;
	memcpy(*dst, merge_buf, *dst_sz);

exit2:
	memset(tzdbg.diag_buf, 0x0, src_sz);
	kzfree(tzdbg.disp_buf);
exit1:
	kzfree(merge_buf);
exit:
	/* Restore tzdbg.disp_buf pointer and debug_rw_buf_size */
	tzdbg.disp_buf = save_disp_buf_addr;
	debug_rw_buf_size = save_debug_rw_buf_size;
	return ret;
}

#endif

static int tz_log_remove(struct platform_device *pdev)
{
+30 −0
Original line number Diff line number Diff line
@@ -450,6 +450,13 @@ config QCOM_WATCHDOG_V2
	  deadlocks. It does not run during the bootup process, so it will
	  not catch any early lockups.

config MSM_FORCE_PANIC_ON_WDOG_BARK
	bool "Force Panic on watchdog bark"
	depends on QCOM_WATCHDOG_V2
	help
	  Triggers a kernel panic for watchdog bark. This will print more
	  information about the current running tasks on all the cpus.

config QCOM_IRQ_HELPER
	bool "QCOM Irq Helper"
	help
@@ -928,6 +935,29 @@ config MSM_RPM_STATS_LOG
	  the low power modes that RPM enters. The drivers outputs the message
	  via a debugfs node.

config SUBSYS_LAST_ERR_LOG
	bool "support last error log for subsystems"
	help
	  When a fatal error is encountered, few subsystems export the
	  error log into SMEM. This driver supports the mechanism to read
	  these logs and exports them to user via procfs.
	  If unsure, say N

config LAST_LOGS
	bool "support last logs for system"
	depends on DEBUG_FS
	select SECURITY_STATUS
	help
	  When a fatal error is encountered on system, system reboots and
	  saves the logs in last logs memory. This driver supports the mechanism
	  to read these logs and exports them via debugfs.

config SECURITY_STATUS
	bool "Get security_status"
	help
	  Gets security status by checking oemandroidboot.securityflags
	  parameter.

config QSEE_IPC_IRQ_BRIDGE
	tristate "QSEE IPC Interrupt Bridge"
	help
+12 −0
Original line number Diff line number Diff line
@@ -113,3 +113,15 @@ obj-$(CONFIG_MSM_CACHE_M4M_ERP64) += cache_m4m_erp64.o
obj-$(CONFIG_MSM_HAB) += hab/
obj-$(CONFIG_QCOM_QDSS_BRIDGE) += qdss_bridge.o
obj-$(CONFIG_MFSE_QMI) += mfse_qmi_v01.o mfse_qmi.o
obj-$(CONFIG_ARCH_MSM8998) += debug_memory.o
obj-$(CONFIG_RAMDUMP_TAGS) += board-rdtags.o
CFLAGS_board-rdtags.o  := \
       -D"INFO_PRODUCT=\"$(if $(TARGET_PRODUCT),$(TARGET_PRODUCT),unknown)\"" \
       -D"INFO_VARIANT= \
       \"$(if $(TARGET_BUILD_VARIANT),$(TARGET_BUILD_VARIANT),unknown)\"" \
       -D"INFO_BUILDID= \
       \"$(if $(SEMC_SYSTEM_VERSION),$(SEMC_SYSTEM_VERSION),private)\""
obj-$(CONFIG_SUBSYS_LAST_ERR_LOG) += last_subsys_errlog.o
obj-$(CONFIG_ARCH_MSM8998) += console_setup.o
obj-$(CONFIG_LAST_LOGS) += last_logs.o
obj-$(CONFIG_SECURITY_STATUS) += security_status.o
+86 −0
Original line number Diff line number Diff line
/*
 *
 * Author: Nilsson, Stefan 2 <stefan2.nilsson@sonymobile.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2, as
 * published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 */
/*
 * Copyright (C) 2015 Sony Mobile Communications Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2, as
 * published by the Free Software Foundation.
 */

#include <linux/rdtags.h>
#include <linux/string.h>
#include <linux/platform_device.h>
#include <asm/setup.h>
#include <linux/io.h>
#include "board-rdtags.h"
#include <soc/qcom/memory_dump.h>

#define RDTAGS_TAG_MAGIC 0xBADFAD01
#define NBR_OF_ELEMENTS 3

struct rdtags_tag_const {
	const char const key[16];
	const char const value[64];
};

struct rdtags_build_tags {
	const unsigned int magic;
	const unsigned int size;
	const struct rdtags_tag_const tag_array[NBR_OF_ELEMENTS];
};

static const struct rdtags_build_tags rdtags_build_info = {
	RDTAGS_TAG_MAGIC,
	sizeof(rdtags_build_info),
	{
		{
			"build_product",
			INFO_PRODUCT
		},
		{
			"build_variant",
			INFO_VARIANT
		},
		{
			"build_id",
			INFO_BUILDID
		}
	}
};

static int board_rdtags_init(int ramdump_mode)
{
	int nbr_tags = 0;
	int i = 0;

	if (!ramdump_mode) {
		for (i = 0; i < NBR_OF_ELEMENTS; i++) {
			const char *key;
			const unsigned char *value;
			unsigned int size = 0;

			key = rdtags_build_info.tag_array[i].key;
			value = rdtags_build_info.tag_array[i].value;
			size = strnlen(value,
				sizeof(rdtags_build_info.tag_array[i].value));
			if (!rdtags_add_tag(key, value, size))
				nbr_tags++;
		}

		nbr_tags += dump_table_ramdump_setup();
	}

	return nbr_tags;
}

struct rdtags_platform_data rdtags_platdata = {
	.platform_init	= board_rdtags_init,
};
+23 −0
Original line number Diff line number Diff line
/*
 *
 * Author: Nilsson, Stefan 2 <stefan2.nilsson@sonymobile.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2, as
 * published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 */
/*
 * Copyright (C) 2015 Sony Mobile Communications Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2, as
 * published by the Free Software Foundation.
 */

#ifndef __BOARD_RDTAGS_H_
#define __BOARD_RDTAGS_H_

extern struct rdtags_platform_data rdtags_platdata;

#endif
Loading