// SPDX-License-Identifier: GPL-2.0+ /* * sys log sys for light c906 and e902 * Copyright (C) 2021 Alibaba Group Holding Limited. */ #include #include #include #include #include #include #include #include #include #include #include #include #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"); }