mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 13:49:24 -04:00
soc: qcom: Add driver to print xbl log on console from fs
Add driver to capture xbl log from reserved memory region and print on console when user requests. Use cat /sys/module/xbl_log/xbl_log to see xbl log. Change-Id: I5d34a4be63244f354ce70cfac8df2724b6a0537b Signed-off-by: Vinay Sudra <vsudra@codeaurora.org>
This commit is contained in:
parent
4dff56a429
commit
2530ebc788
3 changed files with 148 additions and 0 deletions
|
|
@ -1282,5 +1282,14 @@ config QCOM_AOP_SET_DDR
|
|||
into an exposed sysfs node to send to AOP. The driver expects the Cap
|
||||
frequency of DDR based on SKU.
|
||||
|
||||
config DUMP_XBL_LOG
|
||||
bool "print xbl log on console from fs"
|
||||
help
|
||||
This driver is used to capture xbl log from reserved memory region
|
||||
defined separately in each device tree and print on console when user
|
||||
requests. User can perform below command to print xbl log stored in
|
||||
reserved memory region:
|
||||
cat /sys/module/xbl_log/xbl_log
|
||||
|
||||
source "drivers/soc/qcom/icnss2/Kconfig"
|
||||
endmenu
|
||||
|
|
|
|||
|
|
@ -116,3 +116,4 @@ obj-$(CONFIG_MSM_SLATECOM) += slatecom_spi.o
|
|||
obj-$(CONFIG_MSM_SLATECOM_INTERFACE) += slatecom_interface.o
|
||||
obj-$(CONFIG_QCOM_AOP_SET_DDR) += aop-set-ddr.o
|
||||
obj-$(CONFIG_CPU_V7) += idle-v7.o
|
||||
obj-$(CONFIG_DUMP_XBL_LOG) += dump_boot_log.o
|
||||
|
|
|
|||
138
drivers/soc/qcom/dump_boot_log.c
Normal file
138
drivers/soc/qcom/dump_boot_log.c
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
static char *xbl_log_buf;
|
||||
size_t xbl_log_size;
|
||||
|
||||
static ssize_t xbl_log_show(struct file *fp,
|
||||
struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t offset, size_t count)
|
||||
{
|
||||
if (offset < xbl_log_size)
|
||||
return scnprintf(buf, count, "%s", xbl_log_buf + offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bin_attribute attribute =
|
||||
__BIN_ATTR(xbl_log, 0444, xbl_log_show, NULL, 0);
|
||||
|
||||
static void free_xbl_log_buf(phys_addr_t paddr, size_t size)
|
||||
{
|
||||
unsigned long pfn_start = 0, pfn_end = 0, pfn_idx = 0;
|
||||
|
||||
memblock_free(paddr, size);
|
||||
pfn_start = paddr >> PAGE_SHIFT;
|
||||
pfn_end = (paddr + size) >> PAGE_SHIFT;
|
||||
for (pfn_idx = pfn_start; pfn_idx < pfn_end; pfn_idx++)
|
||||
free_reserved_page(pfn_to_page(pfn_idx));
|
||||
}
|
||||
|
||||
static int xbl_log_kthread(void *arg)
|
||||
{
|
||||
int err = 1;
|
||||
struct module_kobject *mkobj;
|
||||
struct device_node *parent = NULL, *node = NULL;
|
||||
struct resource res_log = {0,};
|
||||
phys_addr_t xbl_log_paddr = 0;
|
||||
void *addr = NULL;
|
||||
|
||||
mkobj = kcalloc(1, sizeof(*mkobj), GFP_KERNEL);
|
||||
if (!mkobj)
|
||||
return 1;
|
||||
|
||||
mkobj->mod = THIS_MODULE;
|
||||
mkobj->kobj.kset = module_kset;
|
||||
|
||||
err = kobject_init_and_add(&mkobj->kobj, &module_ktype, NULL, "xbl_log");
|
||||
if (err) {
|
||||
pr_err("xbl_log: cannot create kobject\n");
|
||||
goto kobj_fail;
|
||||
}
|
||||
|
||||
kobject_get(&mkobj->kobj);
|
||||
if (IS_ERR_OR_NULL(&mkobj->kobj)) {
|
||||
err = PTR_ERR(&mkobj->kobj);
|
||||
goto kobj_fail;
|
||||
}
|
||||
|
||||
err = sysfs_create_bin_file(&mkobj->kobj, &attribute);
|
||||
if (err) {
|
||||
pr_err("xbl_log: sysfs entry creation failed\n");
|
||||
goto kobj_fail;
|
||||
}
|
||||
|
||||
parent = of_find_node_by_path("/reserved-memory");
|
||||
if (!parent) {
|
||||
pr_err("xbl_log: reserved-memory node missing\n");
|
||||
goto kobj_fail;
|
||||
}
|
||||
|
||||
node = of_find_node_by_name(parent, "uefi_log");
|
||||
if (!node) {
|
||||
pr_err("xbl_log: uefi_log node missing\n");
|
||||
goto node_fail;
|
||||
}
|
||||
|
||||
if (of_address_to_resource(node, 0, &res_log))
|
||||
goto node_fail;
|
||||
|
||||
xbl_log_paddr = res_log.start;
|
||||
xbl_log_size = resource_size(&res_log) - 1;
|
||||
pr_debug("xbl_log_addr = %x, size=%d\n", xbl_log_paddr, xbl_log_size);
|
||||
|
||||
addr = memremap(xbl_log_paddr, xbl_log_size, MEMREMAP_WB);
|
||||
if (!addr) {
|
||||
pr_err("xbl_log: memremap failed\n");
|
||||
goto remap_fail;
|
||||
}
|
||||
|
||||
xbl_log_buf = kzalloc(xbl_log_size, GFP_KERNEL);
|
||||
if (xbl_log_buf) {
|
||||
memcpy(xbl_log_buf, addr, xbl_log_size);
|
||||
xbl_log_buf[xbl_log_size-1] = '\0';
|
||||
memunmap(addr);
|
||||
if (xbl_log_size)
|
||||
free_xbl_log_buf(xbl_log_paddr, xbl_log_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
kfree(xbl_log_buf);
|
||||
remap_fail:
|
||||
if (node)
|
||||
of_node_put(node);
|
||||
node_fail:
|
||||
if (parent)
|
||||
of_node_put(parent);
|
||||
kobj_fail:
|
||||
kobject_del(&mkobj->kobj);
|
||||
kfree(mkobj);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __init dump_boot_log_init(void)
|
||||
{
|
||||
struct task_struct *xbl_log_task =
|
||||
kthread_run(xbl_log_kthread, NULL, "xbl_log");
|
||||
|
||||
if (PTR_ERR_OR_ZERO(xbl_log_task))
|
||||
return PTR_ERR(xbl_log_task);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
subsys_initcall(dump_boot_log_init);
|
||||
MODULE_DESCRIPTION("dump xbl log");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
Loading…
Reference in a new issue