Merge "arm64: defconfig: Enable boot log dump for pineapple"

This commit is contained in:
qctecmdr 2023-02-28 20:57:01 -08:00 committed by Gerrit - the friendly Code Review server
commit 5bdbd9edab
7 changed files with 44 additions and 302 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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");

View File

@ -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

View File

@ -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;
}

View File

@ -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",