mirror of
https://github.com/revyos/thead-kernel.git
synced 2026-06-21 09:12:26 +02:00
171 lines
4.5 KiB
C
171 lines
4.5 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* sys log sys for light c906 and e902
|
|
* Copyright (C) 2021 Alibaba Group Holding Limited.
|
|
*/
|
|
|
|
|
|
#include <linux/delay.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_address.h>
|
|
#include <linux/of_device.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/io.h>
|
|
#include <asm/cacheflush.h>
|
|
|
|
#define GET_PAGE_NUM(size, offset) \
|
|
((((size) + ((offset) & ~PAGE_MASK)) + PAGE_SIZE - 1) >> PAGE_SHIFT)
|
|
|
|
struct light_log_ring_buffer {
|
|
__u32 read;
|
|
__u32 write;
|
|
__u32 size;
|
|
__u32 reserved[1];
|
|
__u8 data[0];
|
|
};
|
|
|
|
struct light_hw_log {
|
|
__u32 panic;
|
|
__u32 reserved[2];
|
|
struct light_log_ring_buffer rb;
|
|
};
|
|
|
|
struct light_proc_log_ctrl {
|
|
struct light_hw_log __iomem *log;
|
|
struct proc_dir_entry *log_proc_file;
|
|
phys_addr_t log_phy;
|
|
};
|
|
|
|
static void memset_hw(void __iomem *dst, int c, size_t sz)
|
|
{
|
|
int i;
|
|
volatile u32 *d_ptr = dst;
|
|
for (i = 0; i < sz / 4; i++) {
|
|
__raw_writel(c, d_ptr++);
|
|
}
|
|
}
|
|
static void dump_regs(const char *fn, void *hw_arg)
|
|
{
|
|
struct light_proc_log_ctrl *log_ctrl = hw_arg;
|
|
|
|
if (!log_ctrl->log)
|
|
return;
|
|
|
|
pr_debug("%s: panic = 0x%08x\n", fn,
|
|
__raw_readl(&log_ctrl->log->panic));
|
|
pr_debug("%s: read = 0x%08x, write = 0x%08x, size = 0x%08x\n", fn,
|
|
__raw_readl(&log_ctrl->log->rb.read),
|
|
__raw_readl(&log_ctrl->log->rb.write),
|
|
__raw_readl(&log_ctrl->log->rb.size));
|
|
}
|
|
|
|
static int log_proc_show(struct seq_file *file, void *v)
|
|
{
|
|
struct light_proc_log_ctrl *log_ctrl = file->private;
|
|
char *buf;
|
|
size_t i;
|
|
/*dcache clean and invalid*/
|
|
dma_wbinv_range(log_ctrl->log_phy, ((char*)log_ctrl->log_phy + sizeof(struct light_hw_log)));
|
|
|
|
uint32_t write = __raw_readl(&log_ctrl->log->rb.write);
|
|
uint32_t read = __raw_readl(&log_ctrl->log->rb.read);
|
|
uint32_t size = __raw_readl(&log_ctrl->log->rb.size);
|
|
size_t log_size = write >= read ? write - read : size + write - read;
|
|
|
|
seq_printf(file,"****************** device log >>>>>>>>>>>>>>>>>\n");
|
|
dump_regs(__func__, log_ctrl);
|
|
if(!log_size) {
|
|
seq_printf(file,"****************** end device log <<<<<<<<<<<<<<<<<\n");
|
|
return 0;
|
|
}
|
|
|
|
int page_num = GET_PAGE_NUM(log_size, 0);
|
|
|
|
int log_patch_1 = -1, log_patch_2 = -1;
|
|
|
|
buf = kmalloc(PAGE_SIZE * page_num, GFP_KERNEL);
|
|
if (buf) {
|
|
if(read + log_size >= size) {
|
|
log_patch_2 = read + log_size - size + 1;
|
|
log_patch_1 = log_size - log_patch_2;
|
|
|
|
} else {
|
|
log_patch_1 = log_size;
|
|
}
|
|
|
|
memcpy_fromio(buf, &log_ctrl->log->rb.data[read], log_patch_1);
|
|
if(log_patch_2 > 0) {
|
|
memcpy_fromio(buf, &log_ctrl->log->rb.data[0], log_patch_2);
|
|
}
|
|
|
|
uint8_t last_fame_size = log_size % 64;
|
|
|
|
for (i = 0; i < log_size - last_fame_size; i += 64) {
|
|
seq_printf(file, " %*pEp", 64, buf + i);
|
|
}
|
|
if(last_fame_size) {
|
|
seq_printf(file, " %*pEp", last_fame_size, buf + log_size - last_fame_size);
|
|
}
|
|
|
|
__raw_writel(write, &log_ctrl->log->rb.read);
|
|
kfree(buf);
|
|
/*dcahce clean*/
|
|
dma_wb_range(log_ctrl->log_phy, ((char*)log_ctrl->log_phy + sizeof(struct light_hw_log)));
|
|
//seq_printf(file,"\n%d %d %d %d %d\n",log_patch_1, log_patch_2, log_size ,last_fame_size, read);
|
|
seq_printf(file,"\n****************** end device log <<<<<<<<<<<<<<<<<\n");
|
|
return 0;
|
|
} else {
|
|
pr_debug("Fail to alloc buf\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static bool light_panic_init(struct light_hw_log *hw_log, size_t size)
|
|
{
|
|
if (size < sizeof(struct light_hw_log)) {
|
|
return false;
|
|
}
|
|
hw_log->rb.read = 0;
|
|
hw_log->rb.size = size - sizeof(struct light_hw_log);
|
|
return true;
|
|
}
|
|
|
|
void *light_create_panic_log_proc(phys_addr_t log_phy, void *dir, void *log_info_addr, size_t size)
|
|
{
|
|
struct light_proc_log_ctrl *log_ctrl =
|
|
kmalloc(sizeof(struct light_proc_log_ctrl), GFP_KERNEL);
|
|
|
|
if (log_ctrl == NULL)
|
|
return NULL;
|
|
|
|
log_ctrl->log = log_info_addr;
|
|
|
|
light_panic_init(log_ctrl->log, size);
|
|
|
|
log_ctrl->log_proc_file = proc_create_single_data(
|
|
"proc_log", 0644, dir, &log_proc_show, log_ctrl);
|
|
if (log_ctrl->log_proc_file == NULL) {
|
|
pr_debug("Error: Could not initialize %s\n", "dsp_log");
|
|
kfree(log_ctrl);
|
|
log_ctrl = NULL;
|
|
} else {
|
|
pr_debug("%s create Success!\n", "dsp_log");
|
|
}
|
|
log_ctrl->log_phy = log_phy;
|
|
return log_ctrl;
|
|
}
|
|
|
|
void light_remove_panic_log_proc(void *arg)
|
|
{
|
|
struct light_proc_log_ctrl *log_ctrl = (struct light_proc_log_ctrl *)arg;
|
|
|
|
proc_remove(log_ctrl->log_proc_file);
|
|
kfree(log_ctrl);
|
|
pr_debug("light proc log removed\n");
|
|
} |