mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 04:10:18 +09:00
debug: improve ftrace_ramoops for io trace [2/2]
PD#SWPL-6028 Problem: improve ftrace_ramoops to debug bus hang Solution: 1. in uboot setenv initargs $initargs ramoops_io_en=1 loglevel=3;save;reset 2. in linux command line: cat /sys/module/kernel/parameters/ramoops_io_en to check if success. 3. after watchdog reboot, get trace data with: cat /sys/fs/pstore/ftrace-ramoops-0 Verify: TL1 x301 Change-Id: If1a2582b40a3ded31eedef5355eb0b8a5bf495c3 Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
This commit is contained in:
@@ -14530,6 +14530,7 @@ AMLOGIC DEBUG
|
||||
M: Jianxin Pan <jianxin.pan@amlogic.com>
|
||||
M: Tao Guo <tao.guo@amlogic.com>
|
||||
F: drivers/amlogic/debug/*
|
||||
F: include/linux/amlogic/debug*.h
|
||||
|
||||
AMLOGIC G12A spdif channel status
|
||||
M: xing wang<xing.wang@amlogic.com>
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
#include <asm-generic/pci_iomap.h>
|
||||
#include <xen/xen.h>
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_MODIFY
|
||||
#include <linux/amlogic/debug_ftrace_ramoops.h>
|
||||
#endif
|
||||
/*
|
||||
* ISA I/O bus memory addresses are 1:1 with the physical address.
|
||||
*/
|
||||
@@ -73,17 +76,29 @@ void __raw_readsl(const volatile void __iomem *addr, void *data, int longlen);
|
||||
#define __raw_writew __raw_writew
|
||||
static inline void __raw_writew(u16 val, volatile void __iomem *addr)
|
||||
{
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr((unsigned long)addr, (unsigned long)val);
|
||||
#endif
|
||||
asm volatile("strh %1, %0"
|
||||
: : "Q" (*(volatile u16 __force *)addr), "r" (val));
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr_end((unsigned long)addr, (unsigned long)val);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define __raw_readw __raw_readw
|
||||
static inline u16 __raw_readw(const volatile void __iomem *addr)
|
||||
{
|
||||
u16 val;
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_rd((unsigned long)addr);
|
||||
#endif
|
||||
asm volatile("ldrh %0, %1"
|
||||
: "=r" (val)
|
||||
: "Q" (*(volatile u16 __force *)addr));
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_rd_end((unsigned long)addr);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
#endif
|
||||
@@ -91,24 +106,42 @@ static inline u16 __raw_readw(const volatile void __iomem *addr)
|
||||
#define __raw_writeb __raw_writeb
|
||||
static inline void __raw_writeb(u8 val, volatile void __iomem *addr)
|
||||
{
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr((unsigned long)addr, (unsigned long)val);
|
||||
#endif
|
||||
asm volatile("strb %1, %0"
|
||||
: : "Qo" (*(volatile u8 __force *)addr), "r" (val));
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr_end((unsigned long)addr, (unsigned long)val);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define __raw_writel __raw_writel
|
||||
static inline void __raw_writel(u32 val, volatile void __iomem *addr)
|
||||
{
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr((unsigned long)addr, (unsigned long)val);
|
||||
#endif
|
||||
asm volatile("str %1, %0"
|
||||
: : "Qo" (*(volatile u32 __force *)addr), "r" (val));
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr_end((unsigned long)addr, (unsigned long)val);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define __raw_readb __raw_readb
|
||||
static inline u8 __raw_readb(const volatile void __iomem *addr)
|
||||
{
|
||||
u8 val;
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_rd((unsigned long)addr);
|
||||
#endif
|
||||
asm volatile("ldrb %0, %1"
|
||||
: "=r" (val)
|
||||
: "Qo" (*(volatile u8 __force *)addr));
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_rd_end((unsigned long)addr);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -116,9 +149,15 @@ static inline u8 __raw_readb(const volatile void __iomem *addr)
|
||||
static inline u32 __raw_readl(const volatile void __iomem *addr)
|
||||
{
|
||||
u32 val;
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_rd((unsigned long)addr);
|
||||
#endif
|
||||
asm volatile("ldr %0, %1"
|
||||
: "=r" (val)
|
||||
: "Qo" (*(volatile u32 __force *)addr));
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_rd_end((unsigned long)addr);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -317,7 +356,13 @@ static inline void memset_io(volatile void __iomem *dst, unsigned c,
|
||||
size_t count)
|
||||
{
|
||||
extern void mmioset(void *, unsigned int, size_t);
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr((unsigned long)dst, (unsigned long)count);
|
||||
#endif
|
||||
mmioset((void __force *)dst, c, count);
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr_end((unsigned long)dst, (unsigned long)count);
|
||||
#endif
|
||||
}
|
||||
#define memset_io(dst,c,count) memset_io(dst,c,count)
|
||||
|
||||
@@ -325,7 +370,13 @@ static inline void memcpy_fromio(void *to, const volatile void __iomem *from,
|
||||
size_t count)
|
||||
{
|
||||
extern void mmiocpy(void *, const void *, size_t);
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr((unsigned long)to, (unsigned long)count);
|
||||
#endif
|
||||
mmiocpy(to, (const void __force *)from, count);
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr_end((unsigned long)to, (unsigned long)count);
|
||||
#endif
|
||||
}
|
||||
#define memcpy_fromio(to,from,count) memcpy_fromio(to,from,count)
|
||||
|
||||
@@ -333,7 +384,13 @@ static inline void memcpy_toio(volatile void __iomem *to, const void *from,
|
||||
size_t count)
|
||||
{
|
||||
extern void mmiocpy(void *, const void *, size_t);
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr((unsigned long)to, (unsigned long)count);
|
||||
#endif
|
||||
mmiocpy((void __force *)to, from, count);
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr_end((unsigned long)to, (unsigned long)count);
|
||||
#endif
|
||||
}
|
||||
#define memcpy_toio(to,from,count) memcpy_toio(to,from,count)
|
||||
|
||||
|
||||
@@ -33,42 +33,74 @@
|
||||
#include <asm/cpufeature.h>
|
||||
|
||||
#include <xen/xen.h>
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
#include <linux/amlogic/debug_ftrace_ramoops.h>
|
||||
#endif
|
||||
/*
|
||||
* Generic IO read/write. These perform native-endian accesses.
|
||||
*/
|
||||
#define __raw_writeb __raw_writeb
|
||||
static inline void __raw_writeb(u8 val, volatile void __iomem *addr)
|
||||
{
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr((unsigned long)addr, (unsigned long)val);
|
||||
#endif
|
||||
asm volatile("strb %w0, [%1]" : : "rZ" (val), "r" (addr));
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr_end((unsigned long)addr, (unsigned long)val);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define __raw_writew __raw_writew
|
||||
static inline void __raw_writew(u16 val, volatile void __iomem *addr)
|
||||
{
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr((unsigned long)addr, (unsigned long)val);
|
||||
#endif
|
||||
asm volatile("strh %w0, [%1]" : : "rZ" (val), "r" (addr));
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr_end((unsigned long)addr, (unsigned long)val);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define __raw_writel __raw_writel
|
||||
static inline void __raw_writel(u32 val, volatile void __iomem *addr)
|
||||
{
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr((unsigned long)addr, (unsigned long)val);
|
||||
#endif
|
||||
asm volatile("str %w0, [%1]" : : "rZ" (val), "r" (addr));
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr_end((unsigned long)addr, (unsigned long)val);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define __raw_writeq __raw_writeq
|
||||
static inline void __raw_writeq(u64 val, volatile void __iomem *addr)
|
||||
{
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr((unsigned long)addr, (unsigned long)val);
|
||||
#endif
|
||||
asm volatile("str %x0, [%1]" : : "rZ" (val), "r" (addr));
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr_end((unsigned long)addr, (unsigned long)val);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define __raw_readb __raw_readb
|
||||
static inline u8 __raw_readb(const volatile void __iomem *addr)
|
||||
{
|
||||
u8 val;
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_rd((unsigned long)addr);
|
||||
#endif
|
||||
asm volatile(ALTERNATIVE("ldrb %w0, [%1]",
|
||||
"ldarb %w0, [%1]",
|
||||
ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE)
|
||||
: "=r" (val) : "r" (addr));
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_rd_end((unsigned long)addr);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -77,10 +109,16 @@ static inline u16 __raw_readw(const volatile void __iomem *addr)
|
||||
{
|
||||
u16 val;
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_rd((unsigned long)addr);
|
||||
#endif
|
||||
asm volatile(ALTERNATIVE("ldrh %w0, [%1]",
|
||||
"ldarh %w0, [%1]",
|
||||
ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE)
|
||||
: "=r" (val) : "r" (addr));
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_rd_end((unsigned long)addr);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -88,10 +126,16 @@ static inline u16 __raw_readw(const volatile void __iomem *addr)
|
||||
static inline u32 __raw_readl(const volatile void __iomem *addr)
|
||||
{
|
||||
u32 val;
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_rd((unsigned long)addr);
|
||||
#endif
|
||||
asm volatile(ALTERNATIVE("ldr %w0, [%1]",
|
||||
"ldar %w0, [%1]",
|
||||
ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE)
|
||||
: "=r" (val) : "r" (addr));
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_rd_end((unsigned long)addr);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -99,10 +143,16 @@ static inline u32 __raw_readl(const volatile void __iomem *addr)
|
||||
static inline u64 __raw_readq(const volatile void __iomem *addr)
|
||||
{
|
||||
u64 val;
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_rd((unsigned long)addr);
|
||||
#endif
|
||||
asm volatile(ALTERNATIVE("ldr %0, [%1]",
|
||||
"ldar %0, [%1]",
|
||||
ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE)
|
||||
: "=r" (val) : "r" (addr));
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_rd_end((unsigned long)addr);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,13 +18,21 @@
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/types.h>
|
||||
#define SKIP_IO_TRACE
|
||||
#include <linux/io.h>
|
||||
#undef SKIP_IO_TRACE
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
#include <linux/amlogic/debug_ftrace_ramoops.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Copy data from IO memory space to "real" memory space.
|
||||
*/
|
||||
void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
|
||||
{
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_rd((unsigned long)addr);
|
||||
#endif
|
||||
while (count && !IS_ALIGNED((unsigned long)from, 8)) {
|
||||
*(u8 *)to = __raw_readb(from);
|
||||
from++;
|
||||
@@ -45,6 +53,9 @@ void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
|
||||
to++;
|
||||
count--;
|
||||
}
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_rd_end((unsigned long)addr);
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(__memcpy_fromio);
|
||||
|
||||
@@ -53,6 +64,9 @@ EXPORT_SYMBOL(__memcpy_fromio);
|
||||
*/
|
||||
void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
|
||||
{
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr((unsigned long)addr, 0x1234);
|
||||
#endif
|
||||
while (count && !IS_ALIGNED((unsigned long)to, 8)) {
|
||||
__raw_writeb(*(u8 *)from, to);
|
||||
from++;
|
||||
@@ -73,6 +87,9 @@ void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
|
||||
to++;
|
||||
count--;
|
||||
}
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr_end((unsigned long)addr, 0x1234);
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(__memcpy_toio);
|
||||
|
||||
@@ -83,6 +100,9 @@ void __memset_io(volatile void __iomem *dst, int c, size_t count)
|
||||
{
|
||||
u64 qc = (u8)c;
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr((unsigned long)addr, 0xabcd);
|
||||
#endif
|
||||
qc |= qc << 8;
|
||||
qc |= qc << 16;
|
||||
qc |= qc << 32;
|
||||
@@ -104,5 +124,8 @@ void __memset_io(volatile void __iomem *dst, int c, size_t count)
|
||||
dst++;
|
||||
count--;
|
||||
}
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_io_wr_end((unsigned long)addr, 0xabcd);
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(__memset_io);
|
||||
|
||||
@@ -19,3 +19,15 @@ config AMLOGIC_DEBUG_ATRACE
|
||||
default y
|
||||
help
|
||||
Add android atrace compatible function
|
||||
|
||||
config AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
bool "Amlogic ftrace pstore debug"
|
||||
depends on AMLOGIC_DEBUG
|
||||
depends on PSTORE_FTRACE
|
||||
default y
|
||||
help
|
||||
Dump function call and register access to ramoops after watchdog
|
||||
reboot.
|
||||
Enable if doubt.
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
obj-$(CONFIG_AMLOGIC_DEBUG_LOCKUP) += debug_lockup.o
|
||||
obj-$(CONFIG_AMLOGIC_DEBUG_ATRACE) += meson_atrace.o
|
||||
obj-$(CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE)+= debug_ftrace_ramoops.o
|
||||
|
||||
149
drivers/amlogic/debug/debug_ftrace_ramoops.c
Normal file
149
drivers/amlogic/debug/debug_ftrace_ramoops.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* drivers/amlogic/debug/debug_ftrace_ramoops.c
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/irqflags.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/amlogic/debug_ftrace_ramoops.h>
|
||||
#include <../../../fs/pstore/internal.h>
|
||||
#include <linux/trace_clock.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/moduleparam.h>
|
||||
|
||||
static DEFINE_PER_CPU(int, en);
|
||||
static DEFINE_PER_CPU(unsigned long, irq_flag);
|
||||
|
||||
#define IRQ_D 1
|
||||
|
||||
unsigned int dump_iomap;
|
||||
core_param(dump_iomap, dump_iomap, uint, 0664);
|
||||
|
||||
unsigned int ramoops_ftrace_en;
|
||||
EXPORT_SYMBOL(ramoops_ftrace_en);
|
||||
|
||||
int ramoops_io_en;
|
||||
EXPORT_SYMBOL(ramoops_io_en);
|
||||
core_param(ramoops_io_en, ramoops_io_en, int, 0664);
|
||||
|
||||
const char *record_name[PSTORE_FLAG_IO_MAX] = {
|
||||
"NULL",
|
||||
"FUNC",
|
||||
"IO-R",
|
||||
"IO-W",
|
||||
"IO-R-E",
|
||||
"IO-W-E",
|
||||
};
|
||||
|
||||
void notrace pstore_ftrace_save(struct pstore_ftrace_record *rec)
|
||||
{
|
||||
int cpu = raw_smp_processor_id();
|
||||
|
||||
if (unlikely(oops_in_progress) || unlikely(per_cpu(en, cpu)))
|
||||
return;
|
||||
per_cpu(en, cpu) = 1;
|
||||
pstore_ftrace_encode_cpu(rec, cpu);
|
||||
strlcpy(rec->comm, current->comm, sizeof(rec->comm) - 1);
|
||||
rec->pid = current->pid;
|
||||
rec->time = trace_clock_local();
|
||||
psinfo->write_buf(PSTORE_TYPE_FTRACE, 0, NULL, 0, (void *)rec,
|
||||
0, sizeof(*rec), psinfo);
|
||||
per_cpu(en, cpu) = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(pstore_ftrace_save);
|
||||
|
||||
static void notrace pstore_function_dump(struct pstore_ftrace_record *rec,
|
||||
struct seq_file *s)
|
||||
{
|
||||
unsigned long sec = 0, ms = 0;
|
||||
unsigned long long time = rec->time;
|
||||
|
||||
do_div(time, 1000000);
|
||||
sec = (unsigned long)time / 1000;
|
||||
ms = (unsigned long)time % 1000;
|
||||
seq_printf(s, "[%04ld.%03ld@%d] <%5d-%s> <%pf <- %pF>\n",
|
||||
sec, ms, pstore_ftrace_decode_cpu(rec), rec->pid, rec->comm,
|
||||
(void *)rec->ip, (void *)rec->parent_ip);
|
||||
}
|
||||
|
||||
void notrace pstore_io_rw_dump(struct pstore_ftrace_record *rec,
|
||||
struct seq_file *s)
|
||||
{
|
||||
unsigned long sec = 0, ms = 0;
|
||||
unsigned long long time = rec->time;
|
||||
unsigned int cpu = pstore_ftrace_decode_cpu(rec);
|
||||
|
||||
do_div(time, 1000000);
|
||||
sec = (unsigned long)time / 1000;
|
||||
ms = (unsigned long)time % 1000;
|
||||
seq_printf(s, "[%04ld.%03ld@%d] <%5d-%6s> <%6s %08lx-%8lx> <%pf <- %pF>\n",
|
||||
sec, ms, cpu, rec->pid, rec->comm, record_name[rec->flag],
|
||||
rec->val1, (rec->flag == PSTORE_FLAG_IO_W) ? rec->val2 : 0,
|
||||
(void *)rec->ip, (void *)rec->parent_ip);
|
||||
}
|
||||
|
||||
void notrace pstore_ftrace_dump(struct pstore_ftrace_record *rec,
|
||||
struct seq_file *s)
|
||||
{
|
||||
switch (rec->flag & PSTORE_FLAG_MASK) {
|
||||
case PSTORE_FLAG_FUNC:
|
||||
pstore_function_dump(rec, s);
|
||||
break;
|
||||
case PSTORE_FLAG_IO_R:
|
||||
case PSTORE_FLAG_IO_W:
|
||||
case PSTORE_FLAG_IO_W_END:
|
||||
case PSTORE_FLAG_IO_R_END:
|
||||
pstore_io_rw_dump(rec, s);
|
||||
break;
|
||||
default:
|
||||
seq_printf(s, "Unknown Msg:%x\n", rec->flag);
|
||||
}
|
||||
}
|
||||
|
||||
void notrace pstore_io_save(unsigned long reg, unsigned long val,
|
||||
unsigned long parant, unsigned int flag)
|
||||
{
|
||||
struct pstore_ftrace_record rec;
|
||||
int cpu = get_cpu();
|
||||
|
||||
put_cpu();
|
||||
if (!ramoops_ftrace_en || !ramoops_io_en)
|
||||
return;
|
||||
|
||||
if ((flag == PSTORE_FLAG_IO_R || flag == PSTORE_FLAG_IO_W) && IRQ_D)
|
||||
local_irq_save(per_cpu(irq_flag, cpu));
|
||||
|
||||
rec.ip = CALLER_ADDR0;
|
||||
rec.parent_ip = parant;
|
||||
rec.flag = flag;
|
||||
rec.val1 = reg;
|
||||
rec.val2 = val;
|
||||
pstore_ftrace_save(&rec);
|
||||
|
||||
if ((flag == PSTORE_FLAG_IO_R_END || flag == PSTORE_FLAG_IO_W_END)
|
||||
&& IRQ_D)
|
||||
local_irq_restore(per_cpu(irq_flag, cpu));
|
||||
}
|
||||
EXPORT_SYMBOL(pstore_io_save);
|
||||
|
||||
@@ -40,7 +40,7 @@ static const struct of_device_id iomap_dt_match[] = {
|
||||
static void __iomem *meson_reg_map[IO_BUS_MAX] = { NULL };
|
||||
static uint meson_reg_max[IO_BUS_MAX] = { 0 };
|
||||
|
||||
int aml_reg_read(u32 bus_type, unsigned int reg, unsigned int *val)
|
||||
inline int aml_reg_read(u32 bus_type, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
if (
|
||||
bus_type < IO_BUS_MAX &&
|
||||
@@ -53,7 +53,7 @@ int aml_reg_read(u32 bus_type, unsigned int reg, unsigned int *val)
|
||||
}
|
||||
EXPORT_SYMBOL(aml_reg_read);
|
||||
|
||||
int aml_reg_write(u32 bus_type, unsigned int reg, unsigned int val)
|
||||
inline int aml_reg_write(u32 bus_type, unsigned int reg, unsigned int val)
|
||||
{
|
||||
if (
|
||||
bus_type < IO_BUS_MAX &&
|
||||
|
||||
@@ -52,7 +52,7 @@ enum {
|
||||
static void __iomem *codecio_reg_map[CODECIO_BUS_MAX];
|
||||
static u32 codecio_reg_max[CODECIO_BUS_MAX];
|
||||
|
||||
static int codecio_reg_read(u32 bus_type, unsigned int reg, unsigned int *val)
|
||||
static inline int codecio_reg_read(u32 bus_type, u32 reg, u32 *val)
|
||||
{
|
||||
if (bus_type < CODECIO_BUS_MAX) {
|
||||
if (
|
||||
@@ -71,7 +71,7 @@ static int codecio_reg_read(u32 bus_type, unsigned int reg, unsigned int *val)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int codecio_reg_write(u32 bus_type, unsigned int reg, unsigned int val)
|
||||
static inline int codecio_reg_write(u32 bus_type, u32 reg, u32 val)
|
||||
{
|
||||
if (bus_type < CODECIO_BUS_MAX) {
|
||||
if (
|
||||
|
||||
@@ -49,20 +49,6 @@
|
||||
MESON_CPU_MAJOR_ID_SM1, \
|
||||
MESON_CPU_MAJOR_ID_TM2, \
|
||||
0}
|
||||
int codec_apb_read(unsigned int reg)
|
||||
{
|
||||
unsigned int val = 0;
|
||||
|
||||
aml_reg_read(IO_APB_BUS_BASE, reg << 2, &val);
|
||||
return val;
|
||||
}
|
||||
EXPORT_SYMBOL(codec_apb_read);
|
||||
|
||||
void codec_apb_write(unsigned int reg, unsigned int val)
|
||||
{
|
||||
aml_reg_write(IO_APB_BUS_BASE, reg << 2, val);
|
||||
}
|
||||
EXPORT_SYMBOL(codec_apb_write);
|
||||
|
||||
static struct chip_register_ops m8_ops[] __initdata = {
|
||||
{IO_DOS_BUS, 0, codecio_read_dosbus, codecio_write_dosbus},
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define SKIP_IO_TRACE
|
||||
#include <linux/clk.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
* As such, the enable set/clear, pending set/clear and active bit
|
||||
* registers are banked per-cpu for these sources.
|
||||
*/
|
||||
#define SKIP_IO_TRACE
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
#include <asm/barrier.h>
|
||||
#include "internal.h"
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
#include <linux/amlogic/debug_ftrace_ramoops.h>
|
||||
#endif
|
||||
|
||||
static void notrace pstore_ftrace_call(unsigned long ip,
|
||||
unsigned long parent_ip,
|
||||
struct ftrace_ops *op,
|
||||
@@ -39,13 +43,16 @@ static void notrace pstore_ftrace_call(unsigned long ip,
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
rec.ip = ip;
|
||||
rec.parent_ip = parent_ip;
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
rec.flag = PSTORE_FLAG_FUNC;
|
||||
pstore_ftrace_save(&rec);
|
||||
#else
|
||||
pstore_ftrace_encode_cpu(&rec, raw_smp_processor_id());
|
||||
psinfo->write_buf(PSTORE_TYPE_FTRACE, 0, NULL, 0, (void *)&rec,
|
||||
0, sizeof(rec), psinfo);
|
||||
|
||||
#endif
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/syslog.h>
|
||||
#include <linux/amlogic/debug_ftrace_ramoops.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -107,10 +108,13 @@ static int pstore_ftrace_seq_show(struct seq_file *s, void *v)
|
||||
struct pstore_ftrace_seq_data *data = v;
|
||||
struct pstore_ftrace_record *rec = (void *)(ps->data + data->off);
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
pstore_ftrace_dump(rec, s);
|
||||
#else
|
||||
seq_printf(s, "%d %08lx %08lx %pf <- %pF\n",
|
||||
pstore_ftrace_decode_cpu(rec), rec->ip, rec->parent_ip,
|
||||
(void *)rec->ip, (void *)rec->parent_ip);
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,22 @@ struct pstore_ftrace_record {
|
||||
#ifndef PSTORE_CPU_IN_IP
|
||||
unsigned int cpu;
|
||||
#endif
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
int pid;
|
||||
unsigned long val1;
|
||||
unsigned long val2;
|
||||
unsigned long long time;
|
||||
unsigned char comm[8];
|
||||
unsigned int flag;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
void notrace pstore_ftrace_save(struct pstore_ftrace_record *rec);
|
||||
void notrace pstore_ftrace_dump(struct pstore_ftrace_record *rec,
|
||||
struct seq_file *s);
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
pstore_ftrace_encode_cpu(struct pstore_ftrace_record *rec, unsigned int cpu)
|
||||
{
|
||||
|
||||
@@ -602,6 +602,9 @@ static int ramoops_probe(struct platform_device *pdev)
|
||||
cxt->size = pdata->mem_size;
|
||||
cxt->phys_addr = pdata->mem_address;
|
||||
cxt->memtype = pdata->mem_type;
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
cxt->memtype |= (!!ramoops_io_en);
|
||||
#endif
|
||||
cxt->record_size = pdata->record_size;
|
||||
cxt->console_size = pdata->console_size;
|
||||
cxt->ftrace_size = pdata->ftrace_size;
|
||||
@@ -621,7 +624,6 @@ static int ramoops_probe(struct platform_device *pdev)
|
||||
cxt->console_size, 0);
|
||||
if (err)
|
||||
goto fail_init_cprz;
|
||||
|
||||
err = ramoops_init_prz(dev, cxt, &cxt->fprz, &paddr, cxt->ftrace_size,
|
||||
LINUX_VERSION_CODE);
|
||||
if (err)
|
||||
@@ -679,6 +681,17 @@ static int ramoops_probe(struct platform_device *pdev)
|
||||
cxt->size, (unsigned long long)cxt->phys_addr,
|
||||
cxt->ecc_info.ecc_size, cxt->ecc_info.block_size);
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
if (ramoops_ftrace_size) {
|
||||
cxt->fprz->flags |= (PRZ_FLAG_NO_LOCK | PRZ_FLAG_BIG_LOCK);
|
||||
ramoops_ftrace_en = !persistent_ram_old_size(cxt->fprz);
|
||||
}
|
||||
pr_info("ramoops_io_en:%d %d old:0x%lx ftrace_size:0x%lx",
|
||||
ramoops_io_en, ramoops_ftrace_en,
|
||||
(unsigned long)persistent_ram_old_size(cxt->fprz),
|
||||
ramoops_ftrace_size);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
fail_buf:
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define SKIP_IO_TRACE
|
||||
#define pr_fmt(fmt) "persistent_ram: " fmt
|
||||
|
||||
#include <linux/device.h>
|
||||
@@ -49,7 +50,8 @@ static inline size_t buffer_start(struct persistent_ram_zone *prz)
|
||||
}
|
||||
|
||||
/* increase and wrap the start pointer, returning the old value */
|
||||
static size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
|
||||
static size_t notrace buffer_start_add(struct persistent_ram_zone *prz,
|
||||
size_t a)
|
||||
{
|
||||
int old;
|
||||
int new;
|
||||
@@ -71,7 +73,7 @@ static size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
|
||||
}
|
||||
|
||||
/* increase the size counter until it hits the max size */
|
||||
static void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
|
||||
static void notrace buffer_size_add(struct persistent_ram_zone *prz, size_t a)
|
||||
{
|
||||
size_t old;
|
||||
size_t new;
|
||||
@@ -310,6 +312,12 @@ int notrace persistent_ram_write(struct persistent_ram_zone *prz,
|
||||
int c = count;
|
||||
size_t start;
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
unsigned long flags = 0;
|
||||
|
||||
if (prz->flags & PRZ_FLAG_BIG_LOCK)
|
||||
raw_spin_lock_irqsave(&prz->buffer_lock, flags);
|
||||
#endif
|
||||
if (unlikely(c > prz->buffer_size)) {
|
||||
s += c - prz->buffer_size;
|
||||
c = prz->buffer_size;
|
||||
@@ -330,6 +338,10 @@ int notrace persistent_ram_write(struct persistent_ram_zone *prz,
|
||||
|
||||
persistent_ram_update_header_ecc(prz);
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
if (prz->flags & PRZ_FLAG_BIG_LOCK)
|
||||
raw_spin_unlock_irqrestore(&prz->buffer_lock, flags);
|
||||
#endif
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
62
include/linux/amlogic/debug_ftrace_ramoops.h
Normal file
62
include/linux/amlogic/debug_ftrace_ramoops.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* include/linux/amlogic/debug_ftrace_ramoops.h
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DEBUG_FTRACE_RAMOOPS_H__
|
||||
#define __DEBUG_FTRACE_RAMOOPS_H__
|
||||
#define __DEBUG_FTRACE_RAMOOPS_H__
|
||||
#include <linux/ftrace.h>
|
||||
|
||||
extern unsigned int ramoops_ftrace_en;
|
||||
extern int ramoops_io_en;
|
||||
extern unsigned int dump_iomap;
|
||||
|
||||
#define PSTORE_FLAG_FUNC 0x1
|
||||
#define PSTORE_FLAG_IO_R 0x2
|
||||
#define PSTORE_FLAG_IO_W 0x3
|
||||
#define PSTORE_FLAG_IO_R_END 0x4
|
||||
#define PSTORE_FLAG_IO_W_END 0x5
|
||||
#define PSTORE_FLAG_IO_MAX 0x6
|
||||
#define PSTORE_FLAG_MASK 0xF
|
||||
|
||||
void notrace pstore_io_save(unsigned long reg, unsigned long val,
|
||||
unsigned long parant, unsigned int flag);
|
||||
|
||||
//#define SKIP_IO_TRACE
|
||||
#if (defined CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE) && (!defined SKIP_IO_TRACE)
|
||||
#define pstore_ftrace_io_wr(reg, val) \
|
||||
pstore_io_save(reg, val, CALLER_ADDR0, PSTORE_FLAG_IO_W)
|
||||
|
||||
#define pstore_ftrace_io_wr_end(reg, val) \
|
||||
pstore_io_save(reg, 0, CALLER_ADDR0, PSTORE_FLAG_IO_W_END)
|
||||
|
||||
#define pstore_ftrace_io_rd(reg) \
|
||||
pstore_io_save(reg, 0, CALLER_ADDR0, PSTORE_FLAG_IO_R)
|
||||
#define pstore_ftrace_io_rd_end(reg) \
|
||||
pstore_io_save(reg, 0, CALLER_ADDR0, PSTORE_FLAG_IO_R_END)
|
||||
|
||||
#define need_dump_iomap() (ramoops_io_en | dump_iomap)
|
||||
|
||||
#else
|
||||
#define pstore_ftrace_io_wr(reg, val) do { } while (0)
|
||||
#define pstore_ftrace_io_rd(reg) do { } while (0)
|
||||
#define need_dump_iomap() 0
|
||||
#define pstore_ftrace_io_wr_end(reg, val) do { } while (0)
|
||||
#define pstore_ftrace_io_rd_end(reg) do { } while (0)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -26,8 +26,9 @@ enum{
|
||||
IO_HIUBUS_BASE,
|
||||
IO_BUS_MAX,
|
||||
};
|
||||
extern int aml_reg_read(u32 bus_type, unsigned int reg, unsigned int *val);
|
||||
extern int aml_reg_write(u32 bus_type, unsigned int reg, unsigned int val);
|
||||
|
||||
extern inline int aml_reg_read(u32 bus_type, u32 reg, u32 *val);
|
||||
extern inline int aml_reg_write(u32 bus_type, u32 reg, u32 val);
|
||||
extern int aml_regmap_update_bits(u32 bus_type,
|
||||
unsigned int reg, unsigned int mask,
|
||||
unsigned int val);
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
* PRZ_FLAG_NO_LOCK is used. For all other cases, locking is required.
|
||||
*/
|
||||
#define PRZ_FLAG_NO_LOCK BIT(0)
|
||||
#define PRZ_FLAG_BIG_LOCK BIT(7)
|
||||
|
||||
struct persistent_ram_buffer;
|
||||
struct rs_control;
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
#include <linux/export.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/pgtable.h>
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/amlogic/debug_ftrace_ramoops.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HAVE_ARCH_HUGE_VMAP
|
||||
static int __read_mostly ioremap_pud_capable;
|
||||
@@ -122,6 +126,19 @@ static inline int ioremap_pud_range(pgd_t *pgd, unsigned long addr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
bool is_normal_memory(pgprot_t p)
|
||||
{
|
||||
#if defined(CONFIG_ARM)
|
||||
return ((pgprot_val(p) & L_PTE_MT_MASK) == L_PTE_MT_WRITEALLOC);
|
||||
#elif defined(CONFIG_ARM64)
|
||||
return (pgprot_val(p) & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL);
|
||||
#else
|
||||
#error "Unuspported architecture"
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int ioremap_page_range(unsigned long addr,
|
||||
unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
|
||||
{
|
||||
@@ -143,7 +160,12 @@ int ioremap_page_range(unsigned long addr,
|
||||
} while (pgd++, addr = next, addr != end);
|
||||
|
||||
flush_cache_vmap(start, end);
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_DEBUG_FTRACE_PSTORE
|
||||
if (need_dump_iomap() && !is_normal_memory(prot))
|
||||
pr_err("io__map <va:0x%08lx-0x%08lx> pa:0x%lx,port:0x%lx\n",
|
||||
start, end, (unsigned long)phys_addr,
|
||||
(unsigned long)pgprot_val(prot));
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ioremap_page_range);
|
||||
|
||||
Reference in New Issue
Block a user