Merge "arm64: defconfig: Enable boot log dump for pineapple"
This commit is contained in:
commit
5bdbd9edab
@ -135,7 +135,7 @@ CONFIG_QCOM_LAZY_MAPPING=m
|
||||
CONFIG_QCOM_LLCC=m
|
||||
CONFIG_QCOM_LLCC_PERFMON=m
|
||||
CONFIG_QCOM_LLCC_PMU=m
|
||||
# CONFIG_QCOM_LOGBUF_BOOTLOG is not set
|
||||
CONFIG_QCOM_LOGBUF_BOOTLOG=m
|
||||
CONFIG_QCOM_LOGBUF_VENDOR_HOOKS=m
|
||||
CONFIG_QCOM_MDT_LOADER=m
|
||||
CONFIG_QCOM_MEMLAT=m
|
||||
|
@ -516,9 +516,8 @@ config QCOM_LOGBUF_VENDOR_HOOKS
|
||||
device running.
|
||||
|
||||
config QCOM_LOGBUF_BOOTLOG
|
||||
bool "QTI Boot Log Support"
|
||||
depends on QCOM_LOGBUF_VENDOR_HOOKS
|
||||
default y
|
||||
tristate "QTI Boot Log Support"
|
||||
depends on ARCH_QCOM
|
||||
help
|
||||
This enables to keep copy of initial log_buf
|
||||
of minimum 512KB from bootup. It can help in
|
||||
|
@ -65,9 +65,8 @@ obj-$(CONFIG_QCOM_MINIDUMP) += minidump.o
|
||||
minidump-y += msm_minidump.o minidump_log.o
|
||||
minidump-$(CONFIG_QCOM_MINIDUMP_PANIC_MEMORY_INFO) += minidump_memory.o
|
||||
obj-$(CONFIG_QCOM_VA_MINIDUMP) += qcom_va_minidump.o
|
||||
obj-$(CONFIG_QCOM_LOGBUF_VENDOR_HOOKS) += qcom_logbuf_vh.o
|
||||
qcom_logbuf_vh-y := qcom_logbuf_vendor_hooks.o
|
||||
qcom_logbuf_vh-$(CONFIG_QCOM_LOGBUF_BOOTLOG) += qcom_logbuf_boot_log.o
|
||||
obj-$(CONFIG_QCOM_LOGBUF_VENDOR_HOOKS) += qcom_logbuf_vendor_hooks.o
|
||||
obj-$(CONFIG_QCOM_LOGBUF_BOOTLOG) += qcom_logbuf_boot_log.o
|
||||
obj-$(CONFIG_QCOM_HUNG_TASK_ENH) += hung_task_enh.o
|
||||
obj-$(CONFIG_QCOM_MEM_OFFLINE) += mem-offline.o
|
||||
obj-$(CONFIG_GH_TLMM_VM_MEM_ACCESS) += gh_tlmm_vm_mem_access.o
|
||||
|
@ -1,257 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "logbuf_vh: " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kmsg_dump.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <soc/qcom/minidump.h>
|
||||
#include <trace/hooks/logbuf.h>
|
||||
|
||||
#include "qcom_logbuf_boot_log.h"
|
||||
|
||||
#define BOOT_LOG_SIZE SZ_512K
|
||||
#define LOG_NEWLINE 2
|
||||
|
||||
static char *boot_log_buf;
|
||||
static unsigned int boot_log_buf_size;
|
||||
static bool copy_early_boot_log = true;
|
||||
static unsigned int off;
|
||||
static struct kmsg_dump_iter iter;
|
||||
static struct task_struct *dump_thread;
|
||||
|
||||
static size_t print_time(u64 ts, char *buf, size_t buf_sz)
|
||||
int dump_thread_func(void *arg)
|
||||
{
|
||||
unsigned long rem_nsec = do_div(ts, 1000000000);
|
||||
size_t text_len;
|
||||
|
||||
return scnprintf(buf, buf_sz, "[%5lu.%06lu]",
|
||||
(unsigned long)ts, rem_nsec / 1000);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PRINTK_CALLER
|
||||
#define PREFIX_MAX 48
|
||||
static size_t print_caller(u32 id, char *buf, size_t buf_sz)
|
||||
{
|
||||
char caller[12];
|
||||
|
||||
snprintf(caller, sizeof(caller), "%c%u",
|
||||
id & 0x80000000 ? 'C' : 'T', id & ~0x80000000);
|
||||
return scnprintf(buf, buf_sz, "[%6s]", caller);
|
||||
}
|
||||
#else
|
||||
#define PREFIX_MAX 32
|
||||
#define print_caller(id, buf) 0
|
||||
#endif
|
||||
|
||||
static size_t info_print_prefix(const struct printk_info *info, char *buf,
|
||||
size_t buf_sz)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
len = print_time(info->ts_nsec, buf + len, buf_sz);
|
||||
len += print_caller(info->caller_id, buf + len, buf_sz - len);
|
||||
buf[len++] = ' ';
|
||||
buf[len] = '\0';
|
||||
return len;
|
||||
}
|
||||
|
||||
static size_t record_print_text(struct printk_info *pinfo, char *r_text, size_t buf_size)
|
||||
{
|
||||
size_t text_len = pinfo->text_len;
|
||||
char prefix[PREFIX_MAX];
|
||||
size_t prefix_len;
|
||||
char *text = r_text;
|
||||
size_t line_len;
|
||||
size_t len = 0;
|
||||
char *next;
|
||||
|
||||
prefix_len = info_print_prefix(pinfo, prefix, PREFIX_MAX);
|
||||
|
||||
/*
|
||||
* @text_len: bytes of unprocessed text
|
||||
* @line_len: bytes of current line _without_ newline
|
||||
* @text: pointer to beginning of current line
|
||||
* @len: number of bytes prepared in r->text_buf
|
||||
*/
|
||||
for (;;) {
|
||||
next = memchr(text, '\n', text_len);
|
||||
if (next)
|
||||
line_len = next - text;
|
||||
else
|
||||
line_len = text_len;
|
||||
|
||||
/*
|
||||
* Truncate the text if there is not enough space to add the
|
||||
* prefix and a trailing newline and a terminator.
|
||||
*/
|
||||
if ((len + prefix_len + text_len + 1 + 1) > buf_size)
|
||||
break;
|
||||
|
||||
memmove(text + prefix_len, text, text_len);
|
||||
memcpy(text, prefix, prefix_len);
|
||||
|
||||
/*
|
||||
* Increment the prepared length to include the text and
|
||||
* prefix that were just moved+copied. Also increment for the
|
||||
* newline at the end of this line. If this is the last line,
|
||||
* there is no newline, but it will be added immediately below.
|
||||
*/
|
||||
len += prefix_len + line_len + 1;
|
||||
if (text_len == line_len) {
|
||||
/*
|
||||
* This is the last line. Add the trailing newline
|
||||
* removed in vprintk_store().
|
||||
*/
|
||||
text[prefix_len + line_len] = '\n';
|
||||
break;
|
||||
while (!kthread_should_stop()) {
|
||||
while (kmsg_dump_get_line(&iter, true, boot_log_buf,
|
||||
boot_log_buf_size, &text_len)) {
|
||||
boot_log_buf += text_len;
|
||||
boot_log_buf_size -= text_len;
|
||||
if (text_len == 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Advance beyond the added prefix and the related line with
|
||||
* its newline.
|
||||
*/
|
||||
|
||||
text += prefix_len + line_len + 1;
|
||||
|
||||
/*
|
||||
* The remaining text has only decreased by the line with its
|
||||
* newline.
|
||||
*
|
||||
* Note that @text_len can become zero. It happens when @text
|
||||
* ended with a newline (either due to truncation or the
|
||||
* original string ending with "\n\n"). The loop is correctly
|
||||
* repeated and (if not truncated) an empty line with a prefix
|
||||
* will be prepared.
|
||||
*/
|
||||
|
||||
text_len -= line_len + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a buffer was provided, it will be terminated. Space for the
|
||||
* string terminator is guaranteed to be available. The terminator is
|
||||
* not counted in the return value.
|
||||
*/
|
||||
|
||||
if (buf_size > 0)
|
||||
r_text[len] = 0;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static void copy_boot_log_pr_cont(void *unused, struct printk_record *r, size_t text_len)
|
||||
{
|
||||
if (copy_early_boot_log)
|
||||
return;
|
||||
|
||||
if (!r->info->text_len || !off ||
|
||||
((off + r->info->text_len + 1 + 1) > boot_log_buf_size))
|
||||
return;
|
||||
|
||||
if (boot_log_buf[off - 1] == '\n')
|
||||
off = off - 1;
|
||||
|
||||
memcpy(&boot_log_buf[off], &r->text_buf[r->info->text_len - text_len], text_len);
|
||||
off += text_len;
|
||||
if (r->info->flags & LOG_NEWLINE) {
|
||||
boot_log_buf[off] = '\n';
|
||||
boot_log_buf[off + 1] = 0;
|
||||
off += 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void copy_boot_log(void *unused, struct printk_ringbuffer *prb,
|
||||
struct printk_record *r)
|
||||
{
|
||||
struct prb_desc_ring descring = prb->desc_ring;
|
||||
struct prb_data_ring textdata_ring = prb->text_data_ring;
|
||||
struct prb_desc *descaddr = descring.descs;
|
||||
struct printk_info *p_infos = descring.infos;
|
||||
atomic_long_t headid, tailid;
|
||||
unsigned long did, ind, sv;
|
||||
unsigned int textdata_size = _DATA_SIZE(textdata_ring.size_bits);
|
||||
unsigned long begin, end;
|
||||
enum desc_state state;
|
||||
size_t rem_buf_sz;
|
||||
|
||||
tailid = descring.tail_id;
|
||||
headid = descring.head_id;
|
||||
|
||||
if (!copy_early_boot_log) {
|
||||
if (!r->info->text_len)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Check whether remaining buffer has enough space
|
||||
* for record prefix size + newline + terminator
|
||||
* if not, let's reject the record.
|
||||
*/
|
||||
if ((off + r->info->text_len + PREFIX_MAX + 1 + 1) > boot_log_buf_size)
|
||||
return;
|
||||
|
||||
rem_buf_sz = boot_log_buf_size - off;
|
||||
if (!rem_buf_sz)
|
||||
return;
|
||||
|
||||
memcpy(&boot_log_buf[off], &r->text_buf[0], r->info->text_len);
|
||||
off += record_print_text(r->info, &boot_log_buf[off], rem_buf_sz);
|
||||
return;
|
||||
}
|
||||
|
||||
copy_early_boot_log = false;
|
||||
register_log_minidump(prb);
|
||||
did = atomic_long_read(&tailid);
|
||||
while (true) {
|
||||
ind = did % _DESCS_COUNT(descring.count_bits);
|
||||
sv = atomic_long_read(&descaddr[ind].state_var);
|
||||
state = DESC_STATE(sv);
|
||||
/* skip non-committed record */
|
||||
if ((state != desc_committed) && (state != desc_finalized)) {
|
||||
if (did == atomic_long_read(&headid))
|
||||
break;
|
||||
|
||||
did = DESC_ID(did + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
begin = (descaddr[ind].text_blk_lpos.begin) % textdata_size;
|
||||
end = (descaddr[ind].text_blk_lpos.next) % textdata_size;
|
||||
if ((begin & 1) != 1) {
|
||||
unsigned long text_start;
|
||||
u16 textlen;
|
||||
|
||||
if (begin > end)
|
||||
begin = 0;
|
||||
|
||||
text_start = begin + sizeof(unsigned long);
|
||||
textlen = p_infos[ind].text_len;
|
||||
if (end - text_start < textlen)
|
||||
textlen = end - text_start;
|
||||
|
||||
/*
|
||||
* Check whether remaining buffer has enough space
|
||||
* for record prefix size + newline + terminator
|
||||
* if not, let's reject the record.
|
||||
*/
|
||||
if ((off + textlen + PREFIX_MAX + 1 + 1) > boot_log_buf_size)
|
||||
break;
|
||||
|
||||
rem_buf_sz = boot_log_buf_size - off;
|
||||
|
||||
memcpy(&boot_log_buf[off], &textdata_ring.data[text_start],
|
||||
textlen);
|
||||
off += record_print_text(&p_infos[ind],
|
||||
&boot_log_buf[off], rem_buf_sz);
|
||||
}
|
||||
|
||||
if (did == atomic_long_read(&headid))
|
||||
break;
|
||||
|
||||
did = DESC_ID(did + 1);
|
||||
schedule_timeout_interruptible(HZ);
|
||||
}
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int boot_log_init(void)
|
||||
@ -291,42 +72,33 @@ static int boot_log_init(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void release_boot_log_buf(void)
|
||||
{
|
||||
if (!boot_log_buf)
|
||||
return;
|
||||
|
||||
kfree(boot_log_buf);
|
||||
}
|
||||
|
||||
int boot_log_register(struct device *dev)
|
||||
static int __init boot_log_dump_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
u64 dumped_line;
|
||||
size_t text_len;
|
||||
|
||||
ret = boot_log_init();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = register_trace_android_vh_logbuf(copy_boot_log, NULL);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register android_vh_logbuf hook\n");
|
||||
kfree(boot_log_buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = register_trace_android_vh_logbuf_pr_cont(copy_boot_log_pr_cont, NULL);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register android_vh_logbuf_pr_cont hook\n");
|
||||
unregister_trace_android_vh_logbuf(copy_boot_log, NULL);
|
||||
kfree(boot_log_buf);
|
||||
}
|
||||
kmsg_dump_rewind(&iter);
|
||||
dumped_line = iter.next_seq;
|
||||
kmsg_dump_get_buffer(&iter, true, boot_log_buf, boot_log_buf_size, &text_len);
|
||||
boot_log_buf += text_len;
|
||||
boot_log_buf_size -= text_len;
|
||||
iter.cur_seq = dumped_line;
|
||||
dump_thread = kthread_run(dump_thread_func, NULL, "dump_thread");
|
||||
|
||||
return ret;
|
||||
}
|
||||
late_initcall(boot_log_dump_init);
|
||||
|
||||
void boot_log_unregister(void)
|
||||
void boot_log_dump_remove(void)
|
||||
{
|
||||
unregister_trace_android_vh_logbuf_pr_cont(copy_boot_log_pr_cont, NULL);
|
||||
unregister_trace_android_vh_logbuf(copy_boot_log, NULL);
|
||||
release_boot_log_buf();
|
||||
if (dump_thread)
|
||||
kthread_stop(dump_thread);
|
||||
kfree(boot_log_buf);
|
||||
}
|
||||
module_exit(boot_log_dump_remove);
|
||||
|
||||
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Boot Log Dump Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -1,26 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __QCOM_LOGBUF_BOOT_LOG_H
|
||||
#define __QCOM_LOGBUF_BOOT_LOG_H
|
||||
|
||||
#include "../../../kernel/printk/printk_ringbuffer.h"
|
||||
|
||||
void register_log_minidump(struct printk_ringbuffer *prb);
|
||||
|
||||
#if IS_ENABLED(CONFIG_QCOM_LOGBUF_BOOTLOG)
|
||||
int boot_log_register(struct device *dev);
|
||||
void boot_log_unregister(void);
|
||||
#else
|
||||
static inline int boot_log_register(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void boot_log_unregister(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
@ -2,7 +2,7 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "logbuf_vh: " fmt
|
||||
@ -19,7 +19,6 @@
|
||||
|
||||
#include "../../../kernel/printk/printk_ringbuffer.h"
|
||||
#include "debug_symbol.h"
|
||||
#include "qcom_logbuf_boot_log.h"
|
||||
|
||||
void register_log_minidump(struct printk_ringbuffer *prb)
|
||||
{
|
||||
@ -75,14 +74,12 @@ static int logbuf_vh_driver_probe(struct platform_device *pdev)
|
||||
|
||||
prb = *(struct printk_ringbuffer **)DEBUG_SYMBOL_LOOKUP(prb);
|
||||
register_log_minidump(prb);
|
||||
ret = boot_log_register(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int logbuf_vh_driver_remove(struct platform_device *pdev)
|
||||
{
|
||||
boot_log_unregister();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -168,7 +168,8 @@ def define_pineapple():
|
||||
"drivers/soc/qcom/qcom_cpu_vendor_hooks.ko",
|
||||
"drivers/soc/qcom/qcom_cpucp.ko",
|
||||
"drivers/soc/qcom/qcom_cpuss_sleep_stats.ko",
|
||||
"drivers/soc/qcom/qcom_logbuf_vh.ko",
|
||||
"drivers/soc/qcom/qcom_logbuf_boot_log.ko",
|
||||
"drivers/soc/qcom/qcom_logbuf_vendor_hooks.ko",
|
||||
"drivers/soc/qcom/qcom_ramdump.ko",
|
||||
"drivers/soc/qcom/qcom_rpmh.ko",
|
||||
"drivers/soc/qcom/qcom_stats.ko",
|
||||
|
Loading…
Reference in New Issue
Block a user