diff options
| author | Meizu OpenSource <patchwork@meizu.com> | 2016-08-15 10:19:42 +0800 |
|---|---|---|
| committer | Meizu OpenSource <patchwork@meizu.com> | 2016-08-15 10:19:42 +0800 |
| commit | d2e1446d81725c351dc73a03b397ce043fb18452 (patch) | |
| tree | 4dbc616b7f92aea39cd697a9084205ddb805e344 /drivers/misc/mediatek/ram_console | |
first commit
Diffstat (limited to 'drivers/misc/mediatek/ram_console')
| -rw-r--r-- | drivers/misc/mediatek/ram_console/Makefile | 1 | ||||
| -rw-r--r-- | drivers/misc/mediatek/ram_console/mtk_ram_console.c | 1247 |
2 files changed, 1248 insertions, 0 deletions
diff --git a/drivers/misc/mediatek/ram_console/Makefile b/drivers/misc/mediatek/ram_console/Makefile new file mode 100644 index 000000000..7993ac90d --- /dev/null +++ b/drivers/misc/mediatek/ram_console/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_MTK_RAM_CONSOLE) += mtk_ram_console.o diff --git a/drivers/misc/mediatek/ram_console/mtk_ram_console.c b/drivers/misc/mediatek/ram_console/mtk_ram_console.c new file mode 100644 index 000000000..6507a3245 --- /dev/null +++ b/drivers/misc/mediatek/ram_console/mtk_ram_console.c @@ -0,0 +1,1247 @@ +#include <linux/slab.h> +#include <linux/aee.h> +#include <linux/atomic.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/proc_fs.h> +#include <linux/string.h> +#include <linux/seq_file.h> +#include <linux/uaccess.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/kthread.h> +#include <linux/of.h> +#include <linux/of_fdt.h> +#include <linux/of_reserved_mem.h> +#include <asm/io.h> +#include <mach/mt_reg_dump.h> +#include <mach/wd_api.h> + +#define RAM_CONSOLE_HEADER_STR_LEN 1024 + +static int mtk_cpu_num; + +/* + This group of API call by sub-driver module to report reboot reasons + aee_rr_* stand for previous reboot reason + */ +struct last_reboot_reason { + uint32_t fiq_step; + uint32_t exp_type; /* 0xaeedeadX: X=1 (HWT), X=2 (KE), X=3 (nested panic) */ + uint32_t reboot_mode; + + uint32_t last_irq_enter[NR_CPUS]; + uint64_t jiffies_last_irq_enter[NR_CPUS]; + + uint32_t last_irq_exit[NR_CPUS]; + uint64_t jiffies_last_irq_exit[NR_CPUS]; + + uint64_t jiffies_last_sched[NR_CPUS]; + char last_sched_comm[NR_CPUS][TASK_COMM_LEN]; + + uint8_t hotplug_data1[NR_CPUS]; + uint8_t hotplug_data2; + uint64_t hotplug_data3; + + uint32_t mcdi_wfi; + uint32_t mcdi_r15; + uint32_t deepidle_data; + uint32_t sodi_data; + uint32_t spm_suspend_data; + uint64_t cpu_dormant[NR_CPUS]; + uint32_t clk_data[8]; + uint32_t suspend_debug_flag; + + uint8_t cpu_dvfs_vproc_big; + uint8_t cpu_dvfs_vproc_little; + uint8_t cpu_dvfs_oppidx; + uint8_t cpu_dvfs_status; + + uint8_t gpu_dvfs_vgpu; + uint8_t gpu_dvfs_oppidx; + uint8_t gpu_dvfs_status; + + uint64_t ptp_cpu_big_volt; + uint64_t ptp_cpu_little_volt; + uint64_t ptp_gpu_volt; + uint64_t ptp_temp; + uint8_t ptp_status; + + + uint8_t thermal_temp1; + uint8_t thermal_temp2; + uint8_t thermal_temp3; + uint8_t thermal_temp4; + uint8_t thermal_temp5; + uint8_t thermal_status; + + + void *kparams; +}; + +struct reboot_reason_pl { + u32 wdt_status; + u32 data[0]; +}; + +struct reboot_reason_lk { + u32 data[0]; +}; + +struct ram_console_buffer { + uint32_t sig; + /* for size comptible */ + uint32_t off_pl; + uint32_t off_lpl; /* last preloader: struct reboot_reason_pl*/ + uint32_t sz_pl; + uint32_t off_lk; + uint32_t off_llk; /* last lk: struct reboot_reason_lk */ + uint32_t sz_lk; + uint32_t padding[3]; + uint32_t sz_buffer; + uint32_t off_linux; /* struct last_reboot_reason */ + uint32_t off_console; + + /* console buffer*/ + uint32_t log_start; + uint32_t log_size; + uint32_t sz_console; +}; + +#define REBOOT_REASON_SIG (0x43474244) /* DBRR */ +static int FIQ_log_size = sizeof(struct ram_console_buffer); + +static struct ram_console_buffer *ram_console_buffer; +static struct ram_console_buffer *ram_console_old ; +static struct ram_console_buffer *ram_console_buffer_pa; + +static DEFINE_SPINLOCK(ram_console_lock); + +static atomic_t rc_in_fiq = ATOMIC_INIT(0); + +#ifdef __aarch64__ +static void *_memcpy(void *dest, const void *src, size_t count) +{ + char *tmp = dest; + const char *s = src; + + while (count--) + *tmp++ = *s++; + return dest; +} + +#define memcpy _memcpy +#endif + +#define LAST_RR_SEC_VAL(header, sect, type, item) \ + header->off_##sect ? ((type*)((void*)header + header->off_##sect))->item : 0 +#define LAST_RRR_BUF_VAL(buf, rr_item) LAST_RR_SEC_VAL(buf, linux, struct last_reboot_reason, rr_item) +#define LAST_RRPL_BUF_VAL(buf, rr_item) LAST_RR_SEC_VAL(buf, pl, struct reboot_reason_pl, rr_item) +#define LAST_RRR_VAL(rr_item) LAST_RR_SEC_VAL(ram_console_old, linux, struct last_reboot_reason, rr_item) +#define LAST_RRPL_VAL(rr_item) LAST_RR_SEC_VAL(ram_console_old, pl, struct reboot_reason_pl, rr_item) + +unsigned int ram_console_size(void) +{ + return ram_console_buffer->sz_console; +} + +#ifdef CONFIG_MTK_EMMC_SUPPORT +#ifdef CONFIG_MTK_AEE_IPANIC +#include <linux/mmc/sd_misc.h> +extern int card_dump_func_write(unsigned char *buf, unsigned int len, unsigned long long offset, + int dev); + +#define EMMC_ADDR 0X700000 +static char *ram_console2_log; +extern int boot_finish; +extern struct file *expdb_open(void); +void last_kmsg_store_to_emmc(void) +{ + int buff_size; + struct wd_api*wd_api = NULL; + get_wd_api(&wd_api); + +// if(num_online_cpus() > 1){ + if(wd_api->wd_get_check_bit() > 1){ + printk(KERN_ERR"ram_console: online cpu %d!\n",wd_api->wd_get_check_bit()); + if(boot_finish == 0) + return; + } + + /* save log to emmc */ + buff_size = ram_console_buffer->sz_buffer; + card_dump_func_write((unsigned char *)ram_console_buffer, buff_size, EMMC_ADDR, + DUMP_INTO_BOOT_CARD_IPANIC); + + pr_err("ram_console: save kernel log (0x%x) to emmc!\n", buff_size); +} + +static int ram_console_lastk_show(struct ram_console_buffer *buffer, struct seq_file *m, void *v); +static int ram_console2_show(struct seq_file *m, void *v) +{ + struct ram_console_buffer *bufp = NULL; + bufp = (struct ram_console_buffer *)ram_console2_log; + seq_printf(m, "show last_kmsg2 sig %d, size %d", bufp->sig, bufp->log_size); + ram_console_lastk_show(bufp, m, v); + return 0; +} + + +static int ram_console2_file_open(struct inode *inode, struct file *file) +{ + return single_open(file, ram_console2_show, inode->i_private); +} + +static const struct file_operations ram_console2_file_ops = { + .owner = THIS_MODULE, + .open = ram_console2_file_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int emmc_read_last_kmsg(void *data) +{ + int ret; + struct file *filp; + + struct proc_dir_entry *entry; + struct ram_console_buffer *bufp = NULL; + int timeout = 0; + + ram_console2_log = kzalloc(ram_console_buffer->sz_buffer, GFP_KERNEL); + if (ram_console2_log == NULL) { + pr_err("ram_console: malloc size 2 error!\n"); + return 1; + } + + do { + filp = expdb_open(); + if (timeout++ > 60) { + pr_err("ram_console: open expdb partition error [%ld]!\n", PTR_ERR(filp)); + return 1; + } + msleep(500); + } while (IS_ERR(filp)); + ret = kernel_read(filp, EMMC_ADDR, ram_console2_log, ram_console_buffer->sz_buffer); + fput(filp); + if (IS_ERR(ERR_PTR(ret))) { + kfree(ram_console2_log); + ram_console2_log = NULL; + pr_err("ram_console: read emmc data 2 error!\n"); + return 1; + } + + bufp = (struct ram_console_buffer *)ram_console2_log; + if (bufp->sig != REBOOT_REASON_SIG) { + kfree(ram_console2_log); + ram_console2_log = NULL; + pr_err("ram_console: emmc read data sig is not match!\n"); + return 1; + } + + entry = proc_create("last_kmsg2", 0444, NULL, &ram_console2_file_ops); + if (!entry) { + pr_err("ram_console: failed to create proc entry\n"); + kfree(ram_console2_log); + ram_console2_log = NULL; + return 1; + } + pr_err("ram_console: create last_kmsg2 ok.\n"); + return 0; + +} +#else +void last_kmsg_store_to_emmc(void) +{ +} +#endif +#endif + +//#ifdef CONFIG_PSTORE +#if 0 +extern void pstore_bconsole_write(struct console *con, const char *s, unsigned c); +void sram_log_save(const char *msg, int count) +{ + pstore_bconsole_write(NULL, msg, count); +} +#else +void sram_log_save(const char *msg, int count) +{ + struct ram_console_buffer *buffer; + char *rc_console; + int rem; + unsigned int ram_console_buffer_size = ram_console_size(); + + if (ram_console_buffer == NULL) { + pr_err("ram console buffer is NULL!\n"); + return; + } + + buffer = ram_console_buffer; + rc_console = (char*)ram_console_buffer + ram_console_buffer->off_console; + + /* count >= buffer_size, full the buffer */ + if (count >= ram_console_buffer_size) { + memcpy(rc_console, msg + (count - ram_console_buffer_size), + ram_console_buffer_size); + buffer->log_start = 0; + buffer->log_size = ram_console_buffer_size; + } else if (count > (ram_console_buffer_size - buffer->log_start)) /* count > last buffer, full them and fill the head buffer */ + { + rem = ram_console_buffer_size - buffer->log_start; + memcpy(rc_console + buffer->log_start, msg, rem); + memcpy(rc_console, msg + rem, count - rem); + buffer->log_start = count - rem; + buffer->log_size = ram_console_buffer_size; + } else /* count <= last buffer, fill in free buffer */ + { + memcpy(rc_console + buffer->log_start, msg, count); /* count <= last buffer, fill them */ + buffer->log_start += count; + buffer->log_size += count; + if (buffer->log_start >= ram_console_buffer_size) { + buffer->log_start = 0; + } + if (buffer->log_size > ram_console_buffer_size) { + buffer->log_size = ram_console_buffer_size; + } + } + +} +#endif + +#ifdef __aarch64__ +#define FORMAT_LONG "%016lx " +#else +#define FORMAT_LONG "%08lx " +#endif +void aee_sram_fiq_save_bin(const char *msg, size_t len) +{ + int i; + char buf[20]; + for (i = 0; i < len;) { + snprintf(buf, sizeof(long)*2 + 2, FORMAT_LONG, *(long*)(msg + i)); + sram_log_save(buf, sizeof(long)*2 + 1); + i += sizeof(long); + if (i % 32 == 0) + sram_log_save("\n", 1); + } +} + +void aee_disable_ram_console_write(void) +{ + atomic_set(&rc_in_fiq, 1); + return; +} + +void aee_sram_fiq_log(const char *msg) +{ + unsigned int count = strlen(msg); + int delay = 100; + unsigned int ram_console_buffer_size = ram_console_size(); + + if (FIQ_log_size + count > ram_console_buffer_size) { + return; + } + + atomic_set(&rc_in_fiq, 1); + + while ((delay > 0) && (spin_is_locked(&ram_console_lock))) { + udelay(1); + delay--; + } + + sram_log_save(msg, count); + FIQ_log_size += count; +} + +void ram_console_write(struct console *console, const char *s, unsigned int count) +{ + unsigned long flags; + + if (atomic_read(&rc_in_fiq)) + return; + + spin_lock_irqsave(&ram_console_lock, flags); + + sram_log_save(s, count); + + spin_unlock_irqrestore(&ram_console_lock, flags); +} + +static struct console ram_console = { + .name = "ram", + .write = ram_console_write, + .flags = CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME, + .index = -1, +}; + +void ram_console_enable_console(int enabled) +{ + if (enabled) + ram_console.flags |= CON_ENABLED; + else + ram_console.flags &= ~CON_ENABLED; +} + +static int ram_console_check_header(struct ram_console_buffer *buffer) +{ + int i; + if (!buffer || (buffer->sz_buffer != ram_console_buffer->sz_buffer) || buffer->off_pl > buffer->sz_buffer + || buffer->off_lk > buffer->sz_buffer || buffer->off_linux > buffer->sz_buffer || buffer->off_console > buffer->sz_buffer) { + pr_err("ram_console: ilegal header."); + for (i = 0; i < 16; i++) + pr_debug("0x%x ", ((int*)buffer)[i]); + pr_debug("\n"); + return -1; + } else + return 0; +} + +static int ram_console_lastk_show(struct ram_console_buffer *buffer, struct seq_file *m, void *v) +{ + unsigned int wdt_status; + if (ram_console_check_header(buffer) && buffer->sz_buffer != 0) { + pr_err("ram_console: buffer %p, size %x(%x)\n", buffer, buffer->sz_buffer, ram_console_buffer->sz_buffer); + if (buffer) + seq_write(m, buffer, ram_console_buffer->sz_buffer); + else + seq_printf(m, "NO VALID DATA.\n"); + return 0; + } + if (buffer->off_pl == 0 || buffer->off_pl + ALIGN(buffer->sz_pl, 64) != buffer->off_lpl) { + /* workaround for compatiblity to old preloader & lk (OTA) */ + wdt_status = *((unsigned char*)buffer + 12); + } else + wdt_status = LAST_RRPL_BUF_VAL(buffer, wdt_status); + + seq_printf(m, "ram console header, hw_status: %u, fiq step %u.\n", + wdt_status, LAST_RRR_BUF_VAL(buffer, fiq_step)); + + if (buffer->off_console != 0 && buffer->off_linux + ALIGN(sizeof(struct last_reboot_reason), 64) == buffer->off_console + && buffer->sz_console == buffer->sz_buffer - buffer->off_console && buffer->log_size <= buffer->sz_console && + buffer->log_start <= buffer->sz_console) { + seq_write(m, (void*)buffer + buffer->off_console + buffer->log_start, buffer->log_size - buffer->log_start); + seq_write(m, (void*)buffer + buffer->off_console, buffer->log_start); + } else { + seq_printf(m, "header may be corrupted, dump the raw buffer for reference only\n"); + seq_write(m, buffer, ram_console_buffer->sz_buffer); + } + return 0; +} + +static int __init ram_console_save_old(struct ram_console_buffer *buffer, size_t buffer_size) +{ + ram_console_old = kmalloc(buffer_size, GFP_KERNEL); + if (ram_console_old == NULL) { + pr_err("ram_console: failed to allocate old buffer\n"); + return -1; + } + memcpy(ram_console_old, buffer, buffer_size); + return 0; +} + +static int __init ram_console_init(struct ram_console_buffer *buffer, size_t buffer_size) +{ + ram_console_buffer = buffer; + + if (buffer->sig != REBOOT_REASON_SIG) { + memset((void*)buffer, 0, buffer_size); + buffer->sig = REBOOT_REASON_SIG; + } + ram_console_save_old(buffer, buffer_size); + if (buffer->sz_lk != 0 && buffer->off_lk + ALIGN(buffer->sz_lk, 64) == buffer->off_llk) + buffer->off_linux = buffer->off_llk + ALIGN(buffer->sz_lk, 64); + else + buffer->off_linux = 512; /* OTA:leave enough space for pl/lk */ + buffer->sz_buffer = buffer_size; + buffer->off_console = buffer->off_linux + ALIGN(sizeof(struct last_reboot_reason), 64); + buffer->sz_console = buffer->sz_buffer - buffer->off_console; + memset((void*)buffer + buffer->off_linux, 0, buffer_size - buffer->off_linux); +//#ifndef CONFIG_PSTORE +#if 1 + register_console(&ram_console); +#endif + return 0; +} + +#if defined(CONFIG_MTK_RAM_CONSOLE_USING_DRAM) +static void *remap_lowmem(phys_addr_t start, phys_addr_t size) +{ + struct page **pages; + phys_addr_t page_start; + unsigned int page_count; + pgprot_t prot; + unsigned int i; + void *vaddr; + + page_start = start - offset_in_page(start); + page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE); + + prot = pgprot_noncached(PAGE_KERNEL); + + pages = kmalloc(sizeof(struct page *) * page_count, GFP_KERNEL); + if (!pages) { + pr_err("%s: Failed to allocate array for %u pages\n", __func__, page_count); + return NULL; + } + + for (i = 0; i < page_count; i++) { + phys_addr_t addr = page_start + i * PAGE_SIZE; + pages[i] = pfn_to_page(addr >> PAGE_SHIFT); + } + vaddr = vmap(pages, page_count, VM_MAP, prot); + kfree(pages); + if (!vaddr) { + pr_err("%s: Failed to map %u pages\n", __func__, page_count); + return NULL; + } + + return vaddr + offset_in_page(start); +} +#endif + +typedef struct { + unsigned int start; + unsigned int size; +} mem_desc_t; + +#if defined(CONFIG_MTK_RAM_CONSOLE_USING_SRAM) +#ifdef CONFIG_OF +static int __init dt_get_ram_console(unsigned long node, const char *uname, int depth, void *data) +{ + mem_desc_t *sram; + if (depth != 1 ||(strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) + return 0; + + sram = (mem_desc_t *) of_get_flat_dt_prop(node, "non_secure_sram", NULL); + if(sram){ + pr_notice("ram_console:[DT] 0x%x@0x%x\n", sram->size, sram->start); + *(mem_desc_t*)data = *sram; + } + + return 1; +} +#endif +#endif + +static int __init ram_console_early_init(void) +{ + struct ram_console_buffer *bufp = NULL; + size_t buffer_size = 0; +#if defined(CONFIG_MTK_RAM_CONSOLE_USING_SRAM) +#ifdef CONFIG_OF + mem_desc_t sram = {0}; + if (of_scan_flat_dt(dt_get_ram_console, &sram)) { + if (sram.start == 0) { + sram.start = CONFIG_MTK_RAM_CONSOLE_ADDR; + sram.size = CONFIG_MTK_RAM_CONSOLE_SIZE; + } + bufp = ioremap(sram.start, sram.size); + ram_console_buffer_pa = sram.start; + if (bufp) + buffer_size = sram.size; + else { + pr_err("ram_console: ioremap failed, [0x%x, 0x%x]\n", sram.start, sram.size); + return 0; + } + } else { + return 0; + } +#else + bufp = (struct ram_console_buffer *)CONFIG_MTK_RAM_CONSOLE_ADDR; + buffer_size = CONFIG_MTK_RAM_CONSOLE_SIZE; +#endif +#elif defined(CONFIG_MTK_RAM_CONSOLE_USING_DRAM) + bufp = remap_lowmem(CONFIG_MTK_RAM_CONSOLE_DRAM_ADDR, CONFIG_MTK_RAM_CONSOLE_DRAM_SIZE); + ram_console_buffer_pa = CONFIG_MTK_RAM_CONSOLE_DRAM_ADDR; + if (bufp == NULL) { + pr_err("ram_console: ioremap failed\n"); + return 0; + } + buffer_size = CONFIG_MTK_RAM_CONSOLE_DRAM_SIZE; +#else + return 0; +#endif + + pr_err("ram_console: buffer start: 0x%p, size: 0x%zx\n", bufp, buffer_size); + mtk_cpu_num = num_present_cpus(); + return ram_console_init(bufp, buffer_size); +} + +static int ram_console_show(struct seq_file *m, void *v) +{ + ram_console_lastk_show(ram_console_old, m, v); + return 0; +} + +static int ram_console_file_open(struct inode *inode, struct file *file) +{ + return single_open(file, ram_console_show, inode->i_private); +} + +static const struct file_operations ram_console_file_ops = { + .owner = THIS_MODULE, + .open = ram_console_file_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init ram_console_late_init(void) +{ + struct proc_dir_entry *entry; + +#ifdef CONFIG_MTK_EMMC_SUPPORT +#ifdef CONFIG_MTK_AEE_IPANIC + int err; + static struct task_struct *thread; + thread = kthread_run(emmc_read_last_kmsg, 0, "read_poweroff_log"); + if (IS_ERR(thread)) { + err = PTR_ERR(thread); + pr_err("ram_console: failed to create kernel thread: %d\n", err); + } +#endif +#endif + entry = proc_create("last_kmsg", 0444, NULL, &ram_console_file_ops); + if (!entry) { + pr_err("ram_console: failed to create proc entry\n"); + kfree(ram_console_old); + ram_console_old = NULL; + return 0; + } + return 0; +} +console_initcall(ram_console_early_init); +late_initcall(ram_console_late_init); + +int ram_console_pstore_reserve_memory(struct reserved_mem *rmem, unsigned long node, const char *uname) +{ + pr_alert("[memblock]%s: 0x%llx - 0x%llx (0x%llx)\n", uname, (unsigned long long)rmem->base, + (unsigned long long)rmem->base + (unsigned long long)rmem->size, (unsigned long long)rmem->size); + return 0; +} +RESERVEDMEM_OF_DECLARE(reserve_memory_pstore, "pstore-reserve-memory", ram_console_pstore_reserve_memory); + +/* aee sram flags save */ +#define RR_BASE(stage) ((void*)ram_console_buffer + ram_console_buffer->off_##stage) +#define RR_LINUX ((struct last_reboot_reason*)RR_BASE(linux)) +#define RR_BASE_PA(stage) ((void*)ram_console_buffer_pa + ram_console_buffer->off_##stage) +#define RR_LINUX_PA ((struct last_reboot_reason*)RR_BASE_PA(linux)) + +#define LAST_RR_SET(rr_item, value) \ + if (ram_console_buffer) { \ + RR_LINUX->rr_item = value; \ + } + +#define LAST_RR_SET_WITH_ID(rr_item, id, value) \ + if (ram_console_buffer) { \ + RR_LINUX->rr_item[id] = value; \ + } + +#define LAST_RR_VAL(rr_item) \ + (ram_console_buffer ? RR_LINUX->rr_item : 0) + +#define LAST_RR_GET(rr_item) \ + return LAST_RR_VAL(rr_item) + +#define LAST_RR_MEMCPY(rr_item, str, len) \ + if (ram_console_buffer) { \ + strlcpy(RR_LINUX->rr_item, str, len); \ + } + +#define LAST_RR_MEMCPY_WITH_ID(rr_item, id, str, len) \ + if (ram_console_buffer) { \ + strlcpy(RR_LINUX->rr_item[id], str, len); \ + } + +void aee_rr_rec_reboot_mode(u8 mode) +{ + LAST_RR_SET(reboot_mode, mode); +} + +void aee_rr_rec_kdump_params(void *params) +{ + LAST_RR_SET(kparams, params); +} + +void aee_rr_rec_fiq_step(u8 step) +{ + LAST_RR_SET(fiq_step, step); +} + +int aee_rr_curr_fiq_step(void) +{ + LAST_RR_GET(fiq_step); +} + +void aee_rr_rec_exp_type(unsigned int type) +{ + if (LAST_RR_VAL(exp_type) == 0 && type < 16) + LAST_RR_SET(exp_type, 0xaeedead0 | type); +} + +unsigned int aee_rr_curr_exp_type(void) +{ + unsigned int exp_type = LAST_RR_VAL(exp_type); + return (exp_type ^ 0xaeedead0) < 16 ? exp_type ^ 0xaeedead0 : exp_type; +} + +/* composite api */ +void aee_rr_rec_last_irq_enter(int cpu, int irq, u64 jiffies) +{ + if (cpu >= 0 && cpu < NR_CPUS) { + LAST_RR_SET_WITH_ID(last_irq_enter, cpu, irq); + LAST_RR_SET_WITH_ID(jiffies_last_irq_enter, cpu, jiffies); + } + mb(); +} + +void aee_rr_rec_last_irq_exit(int cpu, int irq, u64 jiffies) +{ + if (cpu >=0 && cpu < NR_CPUS) { + LAST_RR_SET_WITH_ID(last_irq_exit, cpu, irq); + LAST_RR_SET_WITH_ID(jiffies_last_irq_exit, cpu, jiffies); + } + mb(); +} + +void aee_rr_rec_last_sched_jiffies(int cpu, u64 jiffies, const char *comm) +{ + if (cpu >=0 && cpu < NR_CPUS) { + LAST_RR_SET_WITH_ID(jiffies_last_sched, cpu, jiffies); + LAST_RR_MEMCPY_WITH_ID(last_sched_comm, cpu, comm, TASK_COMM_LEN); + } + mb(); +} + +void aee_rr_rec_hoplug(int cpu, u8 data1, u8 data2) +{ + if (cpu >=0 && cpu < NR_CPUS) { + LAST_RR_SET_WITH_ID(hotplug_data1, cpu, data1); + if (cpu == 0) + LAST_RR_SET(hotplug_data2, data2); + } +} + +void aee_rr_rec_hotplug(int cpu, u8 data1, u8 data2, unsigned long data3) +{ + if (cpu >=0 && cpu < NR_CPUS) { + LAST_RR_SET_WITH_ID(hotplug_data1, cpu, data1); + if (cpu == 0) { + LAST_RR_SET(hotplug_data2, data2); + LAST_RR_SET(hotplug_data3, (uint64_t)data3); + } + } +} + +void aee_rr_rec_clk(int id, u32 val) +{ + LAST_RR_SET_WITH_ID(clk_data, id, val); +} + +void aee_rr_rec_deepidle_val(u32 val) +{ + LAST_RR_SET(deepidle_data, val); +} + +u32 aee_rr_curr_deepidle_val(void) +{ + LAST_RR_GET(deepidle_data); +} + +void aee_rr_rec_mcdi_wfi_val(u32 val) +{ + LAST_RR_SET(mcdi_wfi, val); +} + +u32 aee_rr_curr_mcdi_wfi_val(void) +{ + LAST_RR_GET(mcdi_wfi); +} + +void aee_rr_rec_mcdi_r15_val(u32 val) +{ + LAST_RR_SET(mcdi_r15, val); +} + +void aee_rr_rec_sodi_val(u32 val) +{ + LAST_RR_SET(sodi_data, val); +} + +u32 aee_rr_curr_sodi_val(void) +{ + LAST_RR_GET(sodi_data); +} + +void aee_rr_rec_spm_suspend_val(u32 val) +{ + LAST_RR_SET(spm_suspend_data, val); +} + +u32 aee_rr_curr_spm_suspend_val(void) +{ + LAST_RR_GET(spm_suspend_data); +} + +/* special case without MMU, return addr directly, strongly suggest not to use */ +unsigned int *aee_rr_rec_mcdi_wfi(void) +{ +#if 0 + if (ram_console_buffer) + return &RR_LINUX->mcdi_wfi; + else +#endif + return NULL; +} + +unsigned long *aee_rr_rec_cpu_dormant(void) +{ + if (ram_console_buffer) + return (unsigned long*)&RR_LINUX->cpu_dormant; + else + return NULL; +} + +unsigned long *aee_rr_rec_cpu_dormant_pa(void) +{ + if (ram_console_buffer_pa) + return (unsigned long*)&RR_LINUX_PA->cpu_dormant; + else + return NULL; +} + +void aee_rr_rec_cpu_dvfs_vproc_big(u8 val) +{ + LAST_RR_SET(cpu_dvfs_vproc_big, val); +} + +void aee_rr_rec_cpu_dvfs_vproc_little(u8 val) +{ + LAST_RR_SET(cpu_dvfs_vproc_little, val); +} + +void aee_rr_rec_cpu_dvfs_oppidx(u8 val) +{ + LAST_RR_SET(cpu_dvfs_oppidx, val); +} + +u8 aee_rr_curr_cpu_dvfs_oppidx(void) +{ + LAST_RR_GET(cpu_dvfs_oppidx); +} + +void aee_rr_rec_cpu_dvfs_status(u8 val) +{ + LAST_RR_SET(cpu_dvfs_status, val); +} + +u8 aee_rr_curr_cpu_dvfs_status(void) +{ + LAST_RR_GET(cpu_dvfs_status); +} + +void aee_rr_rec_gpu_dvfs_vgpu(u8 val) +{ + LAST_RR_SET(gpu_dvfs_vgpu, val); +} + +void aee_rr_rec_gpu_dvfs_oppidx(u8 val) +{ + LAST_RR_SET(gpu_dvfs_oppidx, val); +} + +void aee_rr_rec_gpu_dvfs_status(u8 val) +{ + LAST_RR_SET(gpu_dvfs_status, val); +} + +u8 aee_rr_curr_gpu_dvfs_status(void) +{ + LAST_RR_GET(gpu_dvfs_status); +} + +void aee_rr_rec_ptp_cpu_big_volt(u64 val) +{ + LAST_RR_SET(ptp_cpu_big_volt, val); +} + +void aee_rr_rec_ptp_cpu_little_volt(u64 val) +{ + LAST_RR_SET(ptp_cpu_little_volt, val); +} + +void aee_rr_rec_ptp_gpu_volt(u64 val) +{ + LAST_RR_SET(ptp_gpu_volt, val); +} + +void aee_rr_rec_ptp_temp(u64 val) +{ + LAST_RR_SET(ptp_temp, val); +} + +void aee_rr_rec_ptp_status(u8 val) +{ + LAST_RR_SET(ptp_status, val); +} + +void aee_rr_rec_thermal_temp1(u8 val) +{ + LAST_RR_SET(thermal_temp1, val); +} +void aee_rr_rec_thermal_temp2(u8 val) +{ + LAST_RR_SET(thermal_temp2, val); +} +void aee_rr_rec_thermal_temp3(u8 val) +{ + LAST_RR_SET(thermal_temp3, val); +} +void aee_rr_rec_thermal_temp4(u8 val) +{ + LAST_RR_SET(thermal_temp4, val); +} +void aee_rr_rec_thermal_temp5(u8 val) +{ + LAST_RR_SET(thermal_temp5, val); +} + +void aee_rr_rec_thermal_status(u8 val) +{ + LAST_RR_SET(thermal_status, val); +} + + +u64 aee_rr_curr_ptp_cpu_big_volt(void) +{ + LAST_RR_GET(ptp_cpu_big_volt); +} + +u64 aee_rr_curr_ptp_cpu_little_volt(void) +{ + LAST_RR_GET(ptp_cpu_little_volt); +} + +u64 aee_rr_curr_ptp_gpu_volt(void) +{ + LAST_RR_GET(ptp_gpu_volt); +} + +u64 aee_rr_curr_ptp_temp(void) +{ + LAST_RR_GET(ptp_temp); +} + +u8 aee_rr_curr_ptp_status(void) +{ + LAST_RR_GET(ptp_status); +} + +u8 aee_rr_curr_thermal_temp1(void) +{ + LAST_RR_GET(thermal_temp1); +} +u8 aee_rr_curr_thermal_temp2(void) +{ + LAST_RR_GET(thermal_temp2); +} +u8 aee_rr_curr_thermal_temp3(void) +{ + LAST_RR_GET(thermal_temp3); +} +u8 aee_rr_curr_thermal_temp4(void) +{ + LAST_RR_GET(thermal_temp4); +} +u8 aee_rr_curr_thermal_temp5(void) +{ + LAST_RR_GET(thermal_temp5); +} + +u8 aee_rr_curr_thermal_status(void) +{ + LAST_RR_GET(thermal_status); +} + +void aee_rr_rec_suspend_debug_flag(u32 val) +{ + LAST_RR_SET(suspend_debug_flag, val); +} + +/* aee sram flags print */ +int aee_rr_last_fiq_step(void) +{ + return LAST_RRR_VAL(fiq_step); +} + +typedef void (*last_rr_show_t)(struct seq_file *m); +typedef void (*last_rr_show_cpu_t)(struct seq_file *m, int cpu); + +void aee_rr_show_wdt_status(struct seq_file *m) +{ + unsigned int wdt_status; + struct ram_console_buffer *buffer = ram_console_old; + if (buffer->off_pl == 0 || buffer->off_pl + ALIGN(buffer->sz_pl, 64) != buffer->off_lpl) { + /* workaround for compatiblity to old preloader & lk (OTA) */ + wdt_status = *((unsigned char*)buffer + 12); + } else + wdt_status = LAST_RRPL_VAL(wdt_status); + seq_printf(m, "WDT status: %d", wdt_status); +} + +void aee_rr_show_fiq_step(struct seq_file *m) +{ + seq_printf(m, " fiq step: %u ", LAST_RRR_VAL(fiq_step)); +} + +void aee_rr_show_exp_type(struct seq_file *m) +{ + unsigned int exp_type = LAST_RRR_VAL(exp_type); + seq_printf(m, " exception type: %u\n", (exp_type ^ 0xaeedead0) < 16 ? exp_type ^ 0xaeedead0 : exp_type); +} + +void aee_rr_show_last_irq_enter(struct seq_file *m, int cpu) +{ + seq_printf(m, " irq: enter(%d, ", LAST_RRR_VAL(last_irq_enter[cpu])); +} + +void aee_rr_show_jiffies_last_irq_enter(struct seq_file *m, int cpu) +{ + seq_printf(m, "%llu) ", LAST_RRR_VAL(jiffies_last_irq_enter[cpu])); +} + +void aee_rr_show_last_irq_exit(struct seq_file *m, int cpu) +{ + seq_printf(m, "quit(%d, ", LAST_RRR_VAL(last_irq_exit[cpu])); +} + +void aee_rr_show_jiffies_last_irq_exit(struct seq_file *m, int cpu) +{ + seq_printf(m, "%llu)\n", LAST_RRR_VAL(jiffies_last_irq_exit[cpu])); +} + +void aee_rr_show_hotplug_data1(struct seq_file *m, int cpu) +{ + seq_printf(m, " hotplug: %d, ", LAST_RRR_VAL(hotplug_data1[cpu])); +} + +void aee_rr_show_hotplug_data2(struct seq_file *m, int cpu) +{ + if (cpu == 0) + seq_printf(m, "%d, ", LAST_RRR_VAL(hotplug_data2)); +} +void aee_rr_show_hotplug_data3(struct seq_file *m, int cpu) +{ + if (cpu == 0) + seq_printf(m, "0x%llx", LAST_RRR_VAL(hotplug_data3)); + seq_printf(m, "\n"); +} + +void aee_rr_show_mcdi(struct seq_file *m) +{ + seq_printf(m, "mcdi_wfi: 0x%x\n", LAST_RRR_VAL(mcdi_wfi)); +} + +void aee_rr_show_mcdi_r15(struct seq_file *m) +{ + seq_printf(m, "mcdi_r15: 0x%x\n", LAST_RRR_VAL(mcdi_r15)); +} + +void aee_rr_show_deepidle(struct seq_file *m) +{ + seq_printf(m, "deepidle: 0x%x\n", LAST_RRR_VAL(deepidle_data)); +} + +void aee_rr_show_sodi(struct seq_file *m) +{ + seq_printf(m, "sodi: 0x%x\n", LAST_RRR_VAL(sodi_data)); +} + +void aee_rr_show_spm_suspend(struct seq_file *m) +{ + seq_printf(m, "spm_suspend: 0x%x\n", LAST_RRR_VAL(spm_suspend_data)); +} + +void aee_rr_show_cpu_dormant(struct seq_file *m, int cpu) +{ + seq_printf(m, " cpu_dormant: 0x%llx\n", LAST_RRR_VAL(cpu_dormant[cpu])); +} + +void aee_rr_show_clk(struct seq_file *m) +{ + int i=0; + for(i=0; i<8; i++) + seq_printf(m, "clk_data: 0x%x\n", LAST_RRR_VAL(clk_data[i])); +} + +void aee_rr_show_cpu_dvfs_vproc_big(struct seq_file *m) +{ + seq_printf(m, "cpu_dvfs_vproc_big: 0x%x\n", LAST_RRR_VAL(cpu_dvfs_vproc_big)); +} + +void aee_rr_show_cpu_dvfs_vproc_little(struct seq_file *m) +{ + seq_printf(m, "cpu_dvfs_vproc_little: 0x%x\n", LAST_RRR_VAL(cpu_dvfs_vproc_little)); +} + +void aee_rr_show_cpu_dvfs_oppidx(struct seq_file *m) +{ + seq_printf(m, "cpu_dvfs_oppidx: little = 0x%x\n", LAST_RRR_VAL(cpu_dvfs_oppidx) & 0xF); + seq_printf(m, "cpu_dvfs_oppidx: big = 0x%x\n", (LAST_RRR_VAL(cpu_dvfs_oppidx) >> 4) & 0xF); +} + +void aee_rr_show_cpu_dvfs_status(struct seq_file *m) +{ + seq_printf(m, "cpu_dvfs_status: 0x%x\n", LAST_RRR_VAL(cpu_dvfs_status)); +} + +void aee_rr_show_gpu_dvfs_vgpu(struct seq_file *m) +{ + seq_printf(m, "gpu_dvfs_vgpu: 0x%x\n", LAST_RRR_VAL(gpu_dvfs_vgpu)); +} + +void aee_rr_show_gpu_dvfs_oppidx(struct seq_file *m) +{ + seq_printf(m, "gpu_dvfs_oppidx: 0x%x\n", LAST_RRR_VAL(gpu_dvfs_oppidx)); +} + +void aee_rr_show_gpu_dvfs_status(struct seq_file *m) +{ + seq_printf(m, "gpu_dvfs_status: 0x%x\n", LAST_RRR_VAL(gpu_dvfs_status)); +} + +void aee_rr_show_ptp_cpu_big_volt(struct seq_file *m) +{ + int i; + for (i = 0; i < 8; i++) + seq_printf(m, "ptp_cpu_big_volt[%d] = %llx\n", i, (LAST_RRR_VAL(ptp_cpu_big_volt) >> (i*8)) & 0xFF); +} + +void aee_rr_show_ptp_cpu_little_volt(struct seq_file *m) +{ + int i; + for (i = 0; i < 8; i++) + seq_printf(m, "ptp_cpu_little_volt[%d] = %llx\n", i, (LAST_RRR_VAL(ptp_cpu_little_volt) >> (i*8)) & 0xFF); +} + +void aee_rr_show_ptp_gpu_volt(struct seq_file *m) +{ + int i; + for (i = 0; i < 8; i++) + seq_printf(m, "ptp_gpu_volt[%d] = %llx\n", i, (LAST_RRR_VAL(ptp_gpu_volt) >> (i*8)) & 0xFF); +} + +void aee_rr_show_ptp_temp(struct seq_file *m) +{ + seq_printf(m, "ptp_temp: little = %llx\n", LAST_RRR_VAL(ptp_temp) & 0xFF); + seq_printf(m, "ptp_temp: big = %llx\n", (LAST_RRR_VAL(ptp_temp) >> 8) & 0xFF); + seq_printf(m, "ptp_temp: GPU = %llx\n", (LAST_RRR_VAL(ptp_temp) >> 16) & 0xFF); +} + +void aee_rr_show_thermal_temp(struct seq_file *m) +{ + seq_printf(m, "thermal_temp1 = %d\n", LAST_RRR_VAL(thermal_temp1)); + seq_printf(m, "thermal_temp2 = %d\n", LAST_RRR_VAL(thermal_temp2)); + seq_printf(m, "thermal_temp3 = %d\n", LAST_RRR_VAL(thermal_temp3)); + seq_printf(m, "thermal_temp4 = %d\n", LAST_RRR_VAL(thermal_temp4)); + seq_printf(m, "thermal_temp5 = %d\n", LAST_RRR_VAL(thermal_temp5)); +} + +void aee_rr_show_ptp_status(struct seq_file *m) +{ + seq_printf(m, "ptp_status: 0x%x\n", LAST_RRR_VAL(ptp_status)); +} + +void aee_rr_show_thermal_status(struct seq_file *m) +{ + seq_printf(m, "thermal_status: %d\n", LAST_RRR_VAL(thermal_status)); +} + +__weak uint32_t get_suspend_debug_flag(void) +{ + LAST_RR_GET(suspend_debug_flag); +} +void aee_rr_show_suspend_debug_flag(struct seq_file *m) +{ + uint32_t flag = get_suspend_debug_flag(); + seq_printf(m, "SPM Suspend debug = 0x%x\n", flag ); +} + +int __weak mt_reg_dump(char *buf) +{ + return 1; +} + +void aee_rr_show_last_pc(struct seq_file *m) +{ + char *reg_buf = kmalloc(4096, GFP_KERNEL); + if (reg_buf && mt_reg_dump(reg_buf) == 0) { + seq_printf(m, "%s\n", reg_buf); + kfree(reg_buf); + } +} + +last_rr_show_t aee_rr_show[] = { + aee_rr_show_wdt_status, + aee_rr_show_fiq_step, + aee_rr_show_exp_type, + aee_rr_show_last_pc, + aee_rr_show_mcdi, + aee_rr_show_mcdi_r15, + aee_rr_show_suspend_debug_flag, + aee_rr_show_deepidle, + aee_rr_show_sodi, + aee_rr_show_spm_suspend, + aee_rr_show_clk, + aee_rr_show_cpu_dvfs_vproc_big, + aee_rr_show_cpu_dvfs_vproc_little, + aee_rr_show_cpu_dvfs_oppidx, + aee_rr_show_cpu_dvfs_status, + aee_rr_show_gpu_dvfs_vgpu, + aee_rr_show_gpu_dvfs_oppidx, + aee_rr_show_gpu_dvfs_status, + aee_rr_show_ptp_cpu_big_volt, + aee_rr_show_ptp_cpu_little_volt, + aee_rr_show_ptp_gpu_volt, + aee_rr_show_ptp_temp, + aee_rr_show_ptp_status, + aee_rr_show_thermal_temp, + aee_rr_show_thermal_status +}; + +last_rr_show_cpu_t aee_rr_show_cpu[] = { + aee_rr_show_last_irq_enter, + aee_rr_show_jiffies_last_irq_enter, + aee_rr_show_last_irq_exit, + aee_rr_show_jiffies_last_irq_exit, + aee_rr_show_hotplug_data1, + aee_rr_show_hotplug_data2, + aee_rr_show_hotplug_data3, + aee_rr_show_cpu_dormant, +}; + +#define array_size(x) (sizeof(x) / sizeof((x)[0])) +int aee_rr_reboot_reason_show(struct seq_file *m, void *v) +{ + int i, cpu; + if (ram_console_check_header(ram_console_old)) { + seq_printf(m, "NO VALID DATA.\n"); + return 0; + } + for (i = 0; i < array_size(aee_rr_show); i++) + aee_rr_show[i](m); + + for (cpu = 0; cpu < NR_CPUS; cpu++) { + seq_printf(m, "CPU %d\n", cpu); + for (i = 0; i < array_size(aee_rr_show_cpu); i++) + aee_rr_show_cpu[i](m, cpu); + } + return 0; +} |
