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

Commit b9483eb8 authored by Prateek Sood's avatar Prateek Sood
Browse files

soc: qcom: Add support to dump initial bootup logs



Add support to dump initial dmesg buffer into a
buffer available in minidump and fulldump.

Make logs copying from log_buf at configurable.
This is required to avoid memory sensitive target
from using this.

Change-Id: I7e4d0ddc138ff09c9cbe7679db5e790cdaf1db5c
Signed-off-by: default avatarPrateek Sood <prsood@codeaurora.org>
parent 8569bead
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -831,6 +831,15 @@ config QCOM_IRQ_STAT
	  This provides additional debug information
	  for irq counts on cpu and ipi counts.

config QCOM_INITIAL_LOGBUF
	bool "QCOM save initial log_buf"
	depends on QGKI && QCOM_WDT_CORE
	help
	  This enables to keep copy of initial log_buf
	  of minimum 512KB from bootup. It can help in
	  debugging issues which are manifestation
	  of failure during initial bootup.

config QCOM_FORCE_WDOG_BITE_ON_PANIC
	bool "QCOM force watchdog bite on panic"
	depends on QCOM_WDT_CORE
+68 −0
Original line number Diff line number Diff line
@@ -24,12 +24,20 @@
#include <linux/sort.h>
#include <linux/kernel_stat.h>
#include <linux/irq_cpustat.h>
#include <linux/kallsyms.h>

#define MASK_SIZE        32
#define COMPARE_RET      -1

typedef int (*compare_t) (const void *lhs, const void *rhs);

#ifdef CONFIG_QCOM_INITIAL_LOGBUF
#define BOOT_LOG_SIZE    SZ_512K
char *boot_log_buf;
unsigned int boot_log_buf_size;
bool copy_early_boot_log = true;
#endif

static struct msm_watchdog_data *wdog_data;

static void qcom_wdt_dump_cpu_alive_mask(struct msm_watchdog_data *wdog_dd)
@@ -231,6 +239,63 @@ static void queue_irq_counts_work(struct work_struct *irq_counts_work) { }
static void compute_irq_stat(struct work_struct *work) { }
#endif

#ifdef CONFIG_QCOM_INITIAL_LOGBUF
static void boot_log_init(void)
{
	void *start;
	unsigned int size;
	struct md_region md_entry;
	unsigned int *log_buf_size;

	log_buf_size = (unsigned int *)kallsyms_lookup_name("log_buf_len");
	if (!log_buf_size) {
		dev_err(wdog_data->dev, "log_buf_len symbol not found\n");
		goto out;
	}

	if (*log_buf_size >= BOOT_LOG_SIZE)
		size = *log_buf_size;
	else
		size = BOOT_LOG_SIZE;

	start = kmalloc(size, GFP_KERNEL);
	if (!start)
		goto out;

	strlcpy(md_entry.name, "KBOOT_LOG", sizeof(md_entry.name));
	md_entry.virt_addr = (uintptr_t)start;
	md_entry.phys_addr = virt_to_phys(start);
	md_entry.size = size;
	if (msm_minidump_add_region(&md_entry) < 0) {
		dev_err(wdog_data->dev, "Failed to add boot log entry\n");
		kfree(start);
		goto out;
	}

	boot_log_buf_size = size;
	boot_log_buf = (char *)start;

	/* Ensure boot_log_buf and boot_log_buf initialization
	 * is visible to other CPU's
	 */
	smp_mb();

out:
	return;
}

static void release_boot_log_buf(void)
{
	if (!boot_log_buf)
		return;

	kfree(boot_log_buf);
}
#else
static void boot_log_init(void) { }
static void release_boot_log_buf(void) { }
#endif

#ifdef CONFIG_PM_SLEEP
/**
 *  qcom_wdt_suspend() - Suspends qcom watchdog functionality.
@@ -638,6 +703,7 @@ int qcom_wdt_remove(struct platform_device *pdev)
	wdog_dd->user_pet_complete = true;
	kthread_stop(wdog_dd->watchdog_task);
	flush_work(&wdog_dd->irq_counts_work);
	release_boot_log_buf();
	return 0;
}
EXPORT_SYMBOL(qcom_wdt_remove);
@@ -825,6 +891,8 @@ int qcom_wdt_register(struct platform_device *pdev,
	if (ret)
		goto err;

	boot_log_init();

	/* Add wdog info to minidump table */
	strlcpy(md_entry.name, "KWDOGDATA", sizeof(md_entry.name));
	md_entry.virt_addr = (uintptr_t)wdog_dd;
+6 −0
Original line number Diff line number Diff line
@@ -11,6 +11,12 @@
extern const char linux_banner[];
extern const char linux_proc_banner[];

#ifdef CONFIG_QCOM_INITIAL_LOGBUF
extern char *boot_log_buf;
extern unsigned int boot_log_buf_size;
extern bool copy_early_boot_log;
#endif

#define PRINTK_MAX_SINGLE_HEADER_LEN 2

static inline int printk_get_level(const char *buffer)
+44 −0
Original line number Diff line number Diff line
@@ -612,6 +612,47 @@ static u32 truncate_msg(u16 *text_len, u16 *trunc_msg_len,
	return msg_used_size(*text_len + *trunc_msg_len, 0, pad_len);
}

#ifdef CONFIG_QCOM_INITIAL_LOGBUF
static inline void copy_boot_log(struct printk_log *msg)
{
	unsigned int bytes_to_copy;
	unsigned int avail_buf;
	static unsigned int boot_log_offset;

	if (!boot_log_buf)
		goto out;

	avail_buf = boot_log_buf_size - boot_log_offset;
	if (!avail_buf || (avail_buf < sizeof(*msg)))
		goto out;

	if (copy_early_boot_log) {
		bytes_to_copy = log_next_idx;

		if (avail_buf < bytes_to_copy)
			bytes_to_copy = avail_buf;

		memcpy(boot_log_buf + boot_log_offset, log_buf, bytes_to_copy);
		boot_log_offset += bytes_to_copy;
		copy_early_boot_log = false;
		goto out;
	}

	bytes_to_copy = msg->len;
	if (!bytes_to_copy)
		bytes_to_copy = sizeof(*msg);

	if (avail_buf < bytes_to_copy)
		bytes_to_copy = avail_buf;

	memcpy(boot_log_buf + boot_log_offset, msg, bytes_to_copy);
	boot_log_offset += bytes_to_copy;

out:
	return;
}
#endif

/* insert record into the buffer, discard old ones, update heads */
static int log_store(u32 caller_id, int facility, int level,
		     enum log_flags flags, u64 ts_nsec,
@@ -670,6 +711,9 @@ static int log_store(u32 caller_id, int facility, int level,
	/* insert message */
	log_next_idx += msg->len;
	log_next_seq++;
#ifdef CONFIG_QCOM_INITIAL_LOGBUF
	copy_boot_log(msg);
#endif

	return msg->text_len;
}