summaryrefslogtreecommitdiff
path: root/fs/proc/sprd_debug
diff options
context:
space:
mode:
Diffstat (limited to 'fs/proc/sprd_debug')
-rw-r--r--fs/proc/sprd_debug/Kconfig39
-rw-r--r--fs/proc/sprd_debug/Makefile12
-rw-r--r--fs/proc/sprd_debug/proc_cpu_usage.c783
-rw-r--r--fs/proc/sprd_debug/proc_phymem.c190
-rw-r--r--fs/proc/sprd_debug/proc_sprd_debug.c227
-rw-r--r--fs/proc/sprd_debug/proc_sprd_debug_frame.c135
-rw-r--r--fs/proc/sprd_debug/proc_usermeminfo.c174
-rw-r--r--fs/proc/sprd_debug/proc_userstack.c169
-rw-r--r--fs/proc/sprd_debug/sprd_uboot_log_dump.c121
-rw-r--r--fs/proc/sprd_debug/usermeminfo.h4
10 files changed, 1854 insertions, 0 deletions
diff --git a/fs/proc/sprd_debug/Kconfig b/fs/proc/sprd_debug/Kconfig
new file mode 100644
index 00000000..958f0f2c
--- /dev/null
+++ b/fs/proc/sprd_debug/Kconfig
@@ -0,0 +1,39 @@
+config SPRD_DEBUG_FRAME
+ bool "sprd debug proc interface support"
+ depends on DEBUG_FS && SPRD_DEBUG
+ default y
+
+config SPRD_DEBUG_PHYMEM_INFO
+ bool "physical memory show support"
+ depends on SPRD_DEBUG_FRAME
+ default n
+
+config SPRD_DEBUG_USRPROCMEM_INFO
+ bool "user proc's memory show support"
+ depends on SPRD_DEBUG_FRAME
+ default n
+
+config SPRD_DEBUG_USRPROCSTACK_INFO
+ bool "user proc's current stack show support"
+ depends on SPRD_DEBUG_FRAME
+ default n
+
+config SPRD_DEBUG_CPU_RATE
+ bool "open sprd cpu rate compute"
+ depends on SPRD_DEBUG_FRAME
+ default y
+
+config SPRD_DEBUG_MORE_SMAPS_INFO
+ default n
+ depends on PROC_FS && MMU
+ bool "Enable more smaps info" if EXPERT
+ help
+ Add more infos in /proc/pid/smaps
+
+config SPRD_UBOOT_LOG_DUMP
+ bool "Spreadtrum u-boot log dump"
+ depends on SPRD_SYSDUMP && PROC_FS
+ default y
+ help
+ Enable this option to support dumping u-boot log via sysfs from
+ userspace
diff --git a/fs/proc/sprd_debug/Makefile b/fs/proc/sprd_debug/Makefile
new file mode 100644
index 00000000..8425757f
--- /dev/null
+++ b/fs/proc/sprd_debug/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the Linux proc filesystem routines.
+#
+
+obj-$(CONFIG_SPRD_DEBUG) += sprd_debug.o
+obj-$(CONFIG_SPRD_UBOOT_LOG_DUMP) += sprd_uboot_log_dump.o
+sprd_debug-$(CONFIG_SPRD_DEBUG_FRAME) += proc_sprd_debug_frame.o
+sprd_debug-$(CONFIG_SPRD_DEBUG_PHYMEM_INFO) += proc_phymem.o
+sprd_debug-$(CONFIG_SPRD_DEBUG_SCHED_LOG) += proc_sprd_debug.o
+sprd_debug-$(CONFIG_SPRD_DEBUG_USRPROCMEM_INFO) += proc_usermeminfo.o
+sprd_debug-$(CONFIG_SPRD_DEBUG_USRPROCSTACK_INFO) += proc_userstack.o
+sprd_debug-$(CONFIG_SPRD_DEBUG_CPU_RATE) += proc_cpu_usage.o
diff --git a/fs/proc/sprd_debug/proc_cpu_usage.c b/fs/proc/sprd_debug/proc_cpu_usage.c
new file mode 100644
index 00000000..ead5c3d2
--- /dev/null
+++ b/fs/proc/sprd_debug/proc_cpu_usage.c
@@ -0,0 +1,783 @@
+/*
+ * SPRD CPU USAGE TOOL:
+ * 1. cpu usage per real-cpu & total
+ * 2. cpu usage per thread
+ * 3. cpu system info per real-cpu & total:
+ * contextswitch, pagefault, pagemajfault per cpu & total
+ * */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/cpumask.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/hrtimer.h>
+#include <linux/irqnr.h>
+#include <linux/tick.h>
+#include <linux/threads.h>
+#include <linux/spinlock.h>
+#include <linux/rtc.h>
+#include <asm/cputime.h>
+#include <asm/div64.h>
+#include <asm/uaccess.h>
+#include <linux/sysrq.h>
+#ifdef CONFIG_VM_EVENT_COUNTERS
+#include <../../../kernel/sched/sched.h>
+#include <linux/mm.h>
+#include <linux/vmstat.h>
+#endif
+
+/*
+ * Macros Definitions:
+ * ----------------------------------------------
+ * 1. DEBUG_PRINT : debug log control
+ * 2. buffer_size : define ringbuffer size
+ * 3. tick_2_ms : change tick to ms
+ * 4. ns_2_ms : change ns to ms
+ * 5. ns_2_us : change ns to us
+ * 6. bufferid : change index to buffer id
+ * */
+#define DEBUG_PRINT 0
+#define buffer_size 3
+#define tick_2_ms(time) (10 * (time))
+#define ns_2_ms(time) (do_div(time, 1000000))
+#define ns_2_us(time) (do_div(time, 1000))
+#define bufferid(index) ((index) % (buffer_size))
+
+/*
+ * CpuInfo Structure Per Thread:
+ * ----------------------------------------------
+ * 1. Located at each-thread stack area, beside threadinfo struct:
+ * HIGH ADDR ---> Thread Stack End.
+ * |--------------------------
+ * | ...
+ * | stack
+ * | ...
+ * |--------------------------
+ * | thread_cpuinfo
+ * |--------------------------
+ * | thread_info
+ * |--------------------------
+ * LOW ADDR ---> Thread Stack Start.
+ *
+ * 2. Cpu Threadinfo:
+ * index : for update;
+ * start : utime stime start record;
+ * persistance[] : ringbuffer --> size according to buffer_size;
+ * */
+typedef struct thread_cpuinfo {
+ unsigned long index;
+ struct u_s_time {
+ unsigned long utime;
+ unsigned long stime;
+ }start, persistance[buffer_size];
+}thread_cpuinfo;
+
+/*
+ * Cpu Info Structure:
+ * ----------------------------------------------
+ * user : user usage, percentage;
+ * system : system usage, percentage;
+ * nice : nice usage, percentage;
+ * idle : idle usage, percentage;
+ * iowait : iowait usage, percentage;
+ * irq : irq usage, percentage;
+ * softirq : softirq usage, percentage;
+ * steal : steal usage, percentage;
+ * sum : sum usage, percentage;
+ * ------------------------------------
+ * ctxt_switch : context switch count;
+ * pagefault : page fault count;
+ * pagemajfault : page majfault count;
+ * */
+typedef struct cpu_info {
+ unsigned long long user;
+ unsigned long long system;
+ unsigned long long nice;
+ unsigned long long idle;
+ unsigned long long iowait;
+ unsigned long long irq;
+ unsigned long long softirq;
+ unsigned long long steal;
+ unsigned long long sum;
+#ifdef CONFIG_VM_EVENT_COUNTERS
+ unsigned long context_switch;
+ unsigned long pagefault;
+ unsigned long pagemajfault;
+#endif
+}cpu_info;
+
+/*
+ * Time Stamp Structure:
+ * ----------------------------------------------
+ * 1. start : this record start cpu clock
+ * 2. end : this record end cpu clock
+ * 3. ts_start :
+ * 4. ts_end :
+ * 5. tm_start :
+ * 6. tm_end :
+ * */
+typedef struct time_stamp {
+ unsigned long long start;
+ unsigned long long end;
+ struct timespec ts_start;
+ struct timespec ts_end;
+ struct rtc_time tm_start;
+ struct rtc_time tm_end;
+}time_stamp;
+
+/*
+ * Recorder Structure:
+ * ----------------------------------------------
+ * 1. percpu : each cpu cpuinfo
+ * 2. total : total cpu_info
+ * 3. timestamp : timestamp for this record
+ * */
+typedef struct cpu_recorder {
+ struct cpu_info percpu[NR_CPUS];
+ struct cpu_info total;
+ struct time_stamp timestamp;
+}cpu_recorder;
+
+/*
+ * Global Data:
+ * ----------------------------------------------
+ * 1. hrtimer : for update
+ * 2. global_index : for per thread
+ * 3. usage_lock : spinlock for update & print
+ * 4. recorder : for cpu usage
+ * */
+ktime_t kt;
+long hrtimer_se = 3;
+long long hrtimer_ns = 0;
+static struct hrtimer timer;
+static unsigned long global_index = 0;
+static DEFINE_SPINLOCK(usage_lock);
+static struct cpu_recorder recorder[buffer_size];
+static struct cpu_info prev_value[NR_CPUS];
+static struct timespec ts;
+static unsigned long long each_time = 0;
+
+/*
+ * Extern Function:
+ * ----------------------------------------------
+ * 1. simeple_strtol : change string to long
+ * 2. dump_stack : for debug
+ * */
+extern long simple_strtol(const char *cp, char **endp, unsigned int base);
+extern void dump_stack(void);
+
+
+/*
+ * Functions Start
+ * ----------------------------------------------
+ * */
+static void div64_compute_ratio(const unsigned long long dividend, const unsigned long long divider, unsigned long *result)
+{
+ /*check divider*/
+ if(0 == divider) {
+ result[0] = result[1] = 0;
+ return;
+ }
+
+ /*64bit divition*/
+ result[0] = 10000 * dividend;
+ result[1] = do_div(result[0], divider);
+
+ /*save result as xx.xx%*/
+ result[1] = result[0] % 100;
+ result[0] = result[0] / 100;
+
+#if 0
+ /*to avoid cpu rate > 100%*/
+ if(result[0] > 100) {
+ result[0] = 100;
+ result[1] = 0;
+ }
+#endif
+}
+
+#ifdef arch_idle_time
+static cputime64_t get_idle_time(int cpu)
+{
+ cputime64_t idle;
+
+ idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE];
+ if (cpu_online(cpu) && !nr_iowait_cpu(cpu))
+ idle += arch_idle_time(cpu);
+ return idle;
+}
+
+static cputime64_t get_iowait_time(int cpu)
+{
+ cputime64_t iowait;
+
+ iowait = kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT];
+ if (cpu_online(cpu) && nr_iowait_cpu(cpu))
+ iowait += arch_idle_time(cpu);
+ return iowait;
+}
+#else
+static u64 get_idle_time(int cpu)
+{
+ u64 idle, idle_time = -1ULL;
+
+ /* FIXME: the idle time from get_cpu_idle_time_us() is reset while CPU is hot-pluged.
+ * Using cpustat[CPUTIME_IDLE] to get idle. It isn't very accurate, but stable */
+#if 0
+ if (cpu_online(cpu))
+ idle_time = get_cpu_idle_time_us(cpu, NULL);
+#endif
+
+ if (idle_time == -1ULL)
+ idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE];
+ else
+ idle = usecs_to_cputime64(idle_time);
+
+ //FIXME: this idle function has bug on our shark platform:
+ // not monotone increasing
+ if(DEBUG_PRINT) printk("acedebug: get_idle_time: cpu=%d, idle=%llu\n", cpu, idle);
+
+ return idle;
+}
+
+static u64 get_iowait_time(int cpu)
+{
+ u64 iowait, iowait_time = -1ULL;
+
+ /* FIXME: the iowait time from get_cpu_iowait_time_us() is reset while CPU is hot-pluged.
+ * Using cpustat[CPUTIME_IOWAIT] to get iowait. It isn't very accurate, but stable */
+#if 0
+ if (cpu_online(cpu))
+ iowait_time = get_cpu_iowait_time_us(cpu, NULL);
+#endif
+
+ if (iowait_time == -1ULL)
+ iowait = kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT];
+ else
+ iowait = usecs_to_cputime64(iowait_time);
+
+ return iowait;
+}
+#endif
+
+static void get_each_cpu_data(struct cpu_info *new, int cpuid)
+{
+#ifdef CONFIG_VM_EVENT_COUNTERS
+ struct vm_event_state *this = &per_cpu(vm_event_states, cpuid);
+ new->context_switch = cpu_rq(cpuid)->nr_switches;
+ new->pagefault = this->event[PGFAULT];
+ new->pagemajfault = this->event[PGMAJFAULT];
+#endif
+
+ new->sum = new->user = kcpustat_cpu(cpuid).cpustat[CPUTIME_USER];
+ new->sum += new->system = kcpustat_cpu(cpuid).cpustat[CPUTIME_SYSTEM];
+ new->sum += new->nice = kcpustat_cpu(cpuid).cpustat[CPUTIME_NICE];
+ new->sum += new->idle = get_idle_time(cpuid);
+ new->sum += new->iowait = get_iowait_time(cpuid);
+ new->sum += new->irq = kcpustat_cpu(cpuid).cpustat[CPUTIME_IRQ];
+ new->sum += new->softirq = kcpustat_cpu(cpuid).cpustat[CPUTIME_SOFTIRQ];
+ new->sum += new->steal = kcpustat_cpu(cpuid).cpustat[CPUTIME_STEAL];
+}
+
+static void update_cpu_record(struct cpu_recorder *record, struct cpu_info *prev, struct cpu_info *next, int cpuid)
+{
+ record->total.user += record->percpu[cpuid].user = next->user - prev->user;
+ record->total.system += record->percpu[cpuid].system = next->system - prev->system;
+ record->total.nice += record->percpu[cpuid].nice = next->nice - prev->nice;
+ /*
+ * FIXME begin: idle from system maybe wrong!!!
+ * in our multi-core system idle may not monotone increasing!!!
+ * SO: here we walk-around, but need modify in future!!!
+ */
+ if(next->idle < prev->idle) {
+ prev->idle = (next->idle > 200) ? (next->idle - 200) : 0;
+ prev->sum = prev->user + prev->system + prev->nice + prev->idle + prev->iowait + prev->irq + prev->softirq + prev->steal;
+ }
+
+ record->total.idle += record->percpu[cpuid].idle = next->idle - prev->idle;
+ record->total.iowait += record->percpu[cpuid].iowait = next->iowait - prev->iowait;
+ record->total.irq += record->percpu[cpuid].irq = next->irq - prev->irq;
+ record->total.softirq += record->percpu[cpuid].softirq = next->softirq - prev->softirq;
+ record->total.steal += record->percpu[cpuid].steal = next->steal - prev->steal;
+ record->total.sum += record->percpu[cpuid].sum = next->sum - prev->sum;
+
+#ifdef CONFIG_VM_EVENT_COUNTERS
+ /*
+ * FIXME begin: pagefault & pagemajfault maybe wrong!!!
+ * in our multi-core system pagefault & pagemajfault may not monotone increasing!!!
+ * SO: here we walk-around, but need modify in future!!!
+ */
+ if(next->context_switch < prev->context_switch) prev->context_switch = next->context_switch;
+ if(next->pagefault < prev->pagefault) prev->pagefault = next->pagefault;
+ if(next->pagemajfault < prev->pagemajfault) prev->pagemajfault = next->pagemajfault;
+
+ record->total.context_switch += record->percpu[cpuid].context_switch = next->context_switch - prev->context_switch;
+ record->total.pagefault += record->percpu[cpuid].pagefault = next->pagefault - prev->pagefault;
+ record->total.pagemajfault += record->percpu[cpuid].pagemajfault = next->pagemajfault - prev->pagemajfault;
+#endif
+}
+
+static void cpu_threadinfo_clean(struct thread_cpuinfo *buffer)
+{
+ unsigned long i = 0;
+ unsigned long begin = 0;
+ unsigned long end = 0;
+
+ begin = bufferid(buffer->index) + 1;
+ end = bufferid(global_index);
+ if((global_index - buffer->index) >= buffer_size) {
+ begin = 0;
+ end = buffer_size - 1;
+ }
+
+ if(begin < end + 1) {
+ for(i = begin; i < end + 1; i++) {
+ buffer->persistance[i].utime = 0;
+ buffer->persistance[i].stime = 0;
+ }
+ } else {
+ for(i = begin; i < buffer_size; i++) {
+ buffer->persistance[i].utime = 0;
+ buffer->persistance[i].stime = 0;
+ }
+ for(i = 0; i < end + 1; i++) {
+ buffer->persistance[i].utime = 0;
+ buffer->persistance[i].stime = 0;
+ }
+ }
+}
+
+static void update_prev(struct task_struct *prev)
+{
+ struct thread_cpuinfo *buffer = NULL;
+
+ /*ignore pid=0 process*/
+ //if(!strncmp(prev->comm, "swapper/", 8)) return;
+
+ /*thread buffer*/
+ buffer = (struct thread_cpuinfo *)(prev->stack + sizeof(struct thread_info));
+ if(!buffer) return;
+
+ /*update*/
+ if(buffer->index == global_index) {
+ /*update utime stime*/
+ buffer->persistance[bufferid(buffer->index)].utime += prev->utime - buffer->start.utime;
+ buffer->persistance[bufferid(buffer->index)].stime += prev->stime - buffer->start.stime;
+ } else {
+ /*clean buffer*/
+ cpu_threadinfo_clean(buffer);
+
+ /*update index utime stime*/
+ buffer->index = global_index;
+ buffer->persistance[bufferid(buffer->index)].utime = prev->utime - buffer->start.utime;
+ buffer->persistance[bufferid(buffer->index)].stime = prev->stime - buffer->start.stime;
+ }
+}
+
+static void update_next(struct task_struct *next)
+{
+ struct thread_cpuinfo *buffer = NULL;
+
+ /*ignore pid=0 process*/
+ //if(!strncmp(next->comm, "swapper/", 8)) return;
+
+ /*thread buffer*/
+ buffer = (struct thread_cpuinfo *)(next->stack + sizeof(struct thread_info));
+ if(!buffer) return;
+
+ /*update utime stime*/
+ buffer->start.utime = next->utime;
+ buffer->start.stime = next->stime;
+}
+
+
+void update_cpu_usage(struct task_struct *prev, struct task_struct *next)
+{
+ unsigned long flags;
+
+ /*lock*/
+ spin_lock_irqsave(&usage_lock, flags);
+
+ /*prev*/
+ update_prev(prev);
+
+ /*next*/
+ update_next(next);
+
+ /*unlock*/
+ spin_unlock_irqrestore(&usage_lock, flags);
+
+ return;
+}
+
+static void record_cpu_usage(void)
+{
+ int i, pos;
+ struct cpu_info next;
+
+ /*init*/
+ pos = bufferid(global_index);
+ memset(&next, 0, sizeof(struct cpu_info));
+ memset(&recorder[pos], 0, sizeof(struct cpu_recorder));
+
+ /*record start time*/
+ recorder[pos].timestamp.start = each_time;
+ memcpy(&recorder[pos].timestamp.ts_start, &ts, sizeof(struct timespec));
+ rtc_time_to_tm(recorder[pos].timestamp.ts_start.tv_sec, &recorder[pos].timestamp.tm_start);
+
+ /*record end time*/
+ recorder[pos].timestamp.end = each_time = cpu_clock(0);
+ getnstimeofday(&ts);
+ memcpy(&recorder[pos].timestamp.ts_end, &ts, sizeof(struct timespec));
+ rtc_time_to_tm(recorder[pos].timestamp.ts_end.tv_sec, &recorder[pos].timestamp.tm_end);
+
+ /*update recorder[pos] cpu data*/
+ for_each_possible_cpu(i) {
+ /*get next*/
+ get_each_cpu_data(&next, i);
+
+ /*update recorder*/
+ update_cpu_record(&recorder[pos], &prev_value[i], &next, i);
+
+ /*update prev*/
+ memcpy(&prev_value[i], &next, sizeof(struct cpu_info));
+ }
+
+ /*update global index*/
+ global_index++;
+}
+
+static void compute_print_cpu_rate(struct seq_file *p, void *v, struct cpu_recorder *record)
+{
+ unsigned long idle_ratio[2] = {0, 0};
+ unsigned long user_ratio[2] = {0, 0};
+ unsigned long system_ratio[2] = {0, 0};
+ unsigned long nice_ratio[2] = {0, 0};
+ unsigned long iowait_ratio[2] = {0, 0};
+ unsigned long irq_ratio[2] = {0, 0};
+ unsigned long softirq_ratio[2] = {0, 0};
+ unsigned long steal_ratio[2] = {0, 0};
+ unsigned long sum_ratio[2] = {0, 0};
+ int i;
+
+ for_each_possible_cpu(i) {
+ /*compute each cpu*/
+ div64_compute_ratio(record->percpu[i].idle, record->percpu[i].sum, idle_ratio);
+ div64_compute_ratio(record->percpu[i].user, record->percpu[i].sum, user_ratio);
+ div64_compute_ratio(record->percpu[i].system, record->percpu[i].sum, system_ratio);
+ div64_compute_ratio(record->percpu[i].nice, record->percpu[i].sum, nice_ratio);
+ div64_compute_ratio(record->percpu[i].iowait, record->percpu[i].sum, iowait_ratio);
+ div64_compute_ratio(record->percpu[i].irq, record->percpu[i].sum, irq_ratio);
+ div64_compute_ratio(record->percpu[i].softirq, record->percpu[i].sum, softirq_ratio);
+ div64_compute_ratio(record->percpu[i].steal, record->percpu[i].sum, steal_ratio);
+ div64_compute_ratio(record->percpu[i].sum, record->percpu[i].sum, sum_ratio);
+ /*print each cpu*/
+ seq_printf(p, " cpu%d(%d): %4lu.%02lu%% %4lu.%02lu%% %4lu.%02lu%% %4lu.%02lu%% %4lu.%02lu%% %4lu.%02lu%% %4lu.%02lu%% %4lu.%02lu%% %4lu.%02lu%% | %15lu %15lu %15lu\n",
+ i, cpu_online(i), idle_ratio[0],idle_ratio[1], user_ratio[0],user_ratio[1], system_ratio[0],system_ratio[1], \
+ nice_ratio[0],nice_ratio[1], iowait_ratio[0],iowait_ratio[1], irq_ratio[0],irq_ratio[1], \
+ softirq_ratio[0],softirq_ratio[1], steal_ratio[0],steal_ratio[1], sum_ratio[0],sum_ratio[1], \
+ record->percpu[i].context_switch, record->percpu[i].pagefault, record->percpu[i].pagemajfault);
+ }
+
+ if(NR_CPUS > 1) {
+ /*compute total*/
+ div64_compute_ratio(record->total.idle, record->total.sum, idle_ratio);
+ div64_compute_ratio(record->total.user, record->total.sum, user_ratio);
+ div64_compute_ratio(record->total.system, record->total.sum, system_ratio);
+ div64_compute_ratio(record->total.nice, record->total.sum, nice_ratio);
+ div64_compute_ratio(record->total.iowait, record->total.sum, iowait_ratio);
+ div64_compute_ratio(record->total.irq, record->total.sum, irq_ratio);
+ div64_compute_ratio(record->total.softirq, record->total.sum, softirq_ratio);
+ div64_compute_ratio(record->total.steal, record->total.sum, steal_ratio);
+ div64_compute_ratio(record->total.sum, record->total.sum, sum_ratio);
+ /*print total*/
+ seq_printf(p, " ------------------\n");
+ seq_printf(p, " Total: %4lu.%02lu%% %4lu.%02lu%% %4lu.%02lu%% %4lu.%02lu%% %4lu.%02lu%% %4lu.%02lu%% %4lu.%02lu%% %4lu.%02lu%% %4lu.%02lu%% | %15lu %15lu %15lu\n",
+ idle_ratio[0],idle_ratio[1], user_ratio[0],user_ratio[1], system_ratio[0],system_ratio[1], \
+ nice_ratio[0],nice_ratio[1], iowait_ratio[0],iowait_ratio[1], irq_ratio[0],irq_ratio[1], \
+ softirq_ratio[0],softirq_ratio[1], steal_ratio[0],steal_ratio[1], sum_ratio[0],sum_ratio[1], \
+ record->total.context_switch, record->total.pagefault, record->total.pagemajfault);
+ }
+}
+
+static void compute_print_each_thread_rate(struct seq_file *p, void *v, int pid, char *name,
+ unsigned long u_time, unsigned long s_time, unsigned long index)
+{
+ unsigned long utime_ratio[2] = {0, 0};
+ unsigned long stime_ratio[2] = {0, 0};
+ unsigned long ttime_ratio[2] = {0, 0};
+ unsigned long timer_circle_long = 0;
+
+ /*devider*/
+ timer_circle_long = recorder[index].timestamp.end - recorder[index].timestamp.start;
+ ns_2_ms(timer_circle_long);
+
+ /*compute ratio*/
+ div64_compute_ratio(u_time, timer_circle_long, utime_ratio);
+ div64_compute_ratio(s_time, timer_circle_long, stime_ratio);
+ div64_compute_ratio((u_time + s_time), timer_circle_long, ttime_ratio);
+
+ if(NULL != name) {
+ seq_printf(p, " %-6d %4lu.%02lu%% %4lu.%02lu%% %4lu.%02lu%% %-15s\n",
+ pid, utime_ratio[0],utime_ratio[1], stime_ratio[0],stime_ratio[1], ttime_ratio[0],ttime_ratio[1], name);
+ } else {
+ seq_printf(p, " %-6s %4lu.%02lu%% %4lu.%02lu%% %4lu.%02lu%%\n",
+ "Total:", utime_ratio[0],utime_ratio[1], stime_ratio[0],stime_ratio[1], ttime_ratio[0],ttime_ratio[1]);
+ }
+}
+
+static void print_summary(struct seq_file *p, void *v, unsigned long bufid)
+{
+ unsigned long long timelongth;
+ unsigned long long start_time = 0;
+ unsigned long long end_time = 0;
+
+ /*update recorder[bufid].timestamp temporarily*/
+ if(bufid == bufferid(global_index)) {
+ recorder[bufid].timestamp.start = each_time;
+ recorder[bufid].timestamp.end = cpu_clock(0);
+ memcpy(&recorder[bufid].timestamp.ts_start, &ts, sizeof(struct timespec));
+ getnstimeofday(&recorder[bufid].timestamp.ts_end);
+ rtc_time_to_tm(recorder[bufid].timestamp.ts_start.tv_sec, &recorder[bufid].timestamp.tm_start);
+ rtc_time_to_tm(recorder[bufid].timestamp.ts_end.tv_sec, &recorder[bufid].timestamp.tm_end);
+ }
+
+ /*compute how long time*/
+ timelongth = recorder[bufid].timestamp.end - recorder[bufid].timestamp.start;
+
+ /*start_time & end_time*/
+ start_time = recorder[bufid].timestamp.start;
+ end_time = recorder[bufid].timestamp.end;
+
+ /*change ns to ms*/
+ ns_2_ms(start_time);
+ ns_2_ms(end_time);
+ ns_2_ms(timelongth);
+
+ /*print cpu core count*/
+ seq_printf(p, "\n\nCpu Core Count: %-6d\n", NR_CPUS);
+
+ /*from start_time to end_time*/
+ seq_printf(p, "Timer Circle: %-llums.\n",timelongth);
+ seq_printf(p, " From time %llums(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC) to %llums(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC).\n\n",
+ start_time, recorder[bufid].timestamp.tm_start.tm_year + 1900, recorder[bufid].timestamp.tm_start.tm_mon + 1,
+ recorder[bufid].timestamp.tm_start.tm_mday, recorder[bufid].timestamp.tm_start.tm_hour, recorder[bufid].timestamp.tm_start.tm_min,
+ recorder[bufid].timestamp.tm_start.tm_sec, recorder[bufid].timestamp.ts_start.tv_nsec,
+ end_time, recorder[bufid].timestamp.tm_end.tm_year + 1900, recorder[bufid].timestamp.tm_end.tm_mon + 1,
+ recorder[bufid].timestamp.tm_end.tm_mday, recorder[bufid].timestamp.tm_end.tm_hour, recorder[bufid].timestamp.tm_end.tm_min,
+ recorder[bufid].timestamp.tm_end.tm_sec, recorder[bufid].timestamp.ts_end.tv_nsec);
+}
+
+static void print_cpu_usage(struct seq_file *p, void *v, unsigned long bufid)
+{
+ int i;
+ struct cpu_info now;
+
+ /*init*/
+ memset(&now, 0, sizeof(cpu_info));
+
+ /*update current record temporarily*/
+ if(bufid == bufferid(global_index)) {
+ memset(&recorder[bufid].percpu, 0, NR_CPUS * sizeof(struct cpu_info));
+ memset(&recorder[bufid].total, 0, sizeof(struct cpu_info));
+
+ /*data*/
+ for_each_possible_cpu(i) {
+ /*get now*/
+ get_each_cpu_data(&now, i);
+
+ /*update recorder*/
+ update_cpu_record(&recorder[bufid], &prev_value[i], &now, i);
+ }
+ }
+
+ /*print tile*/
+ seq_printf(p, "%-87s %-s\n", " * CPU USAGE:", " | * OTHER COUNTS:");
+ seq_printf(p, " -%lu- %8s %8s %8s %8s %8s %8s %8s %8s %8s | %15s %15s %15s\n",
+ bufid, "IDLE", "USER", "SYSTEM", "NICE", "IOWAIT", "IRQ", "SOFTIRQ", "STEAL", "TOTAL", "CTXT_SWITCH", "FG_FAULT", "FG_MAJ_FAULT");
+
+ /*compute & print*/
+ compute_print_cpu_rate(p, v, &recorder[bufid]);
+}
+
+static void print_each_thread_usage(struct seq_file *p, void *v, unsigned long bufid)
+{
+ unsigned long total_usr = 0;
+ unsigned long total_sys = 0;
+ struct task_struct *gp, *pp;
+ struct thread_cpuinfo *buffer = NULL;
+
+ /*print tile*/
+ seq_printf(p, "\n* USAGE PER THREAD:\n");
+ seq_printf(p, " %-6s %8s %8s %8s %-15s\n", "PID", "USER", "SYSTEM", "TOTAL", "NAME");
+
+ /*for all threads*/
+ do_each_thread(gp, pp) {
+
+ /*get ringbuffer*/
+ buffer = (struct thread_cpuinfo *)(pp->stack + sizeof(struct thread_info));
+ if(!buffer) continue;
+
+ /*clean ringbuffer*/
+ if(global_index != buffer->index) {
+
+ cpu_threadinfo_clean(buffer);
+
+ /*update index*/
+ buffer->index = global_index;
+ }
+
+ /*print each none zero thread*/
+ if(0 != (buffer->persistance[bufid].utime + buffer->persistance[bufid].stime)) {
+
+ unsigned long u_time = tick_2_ms(buffer->persistance[bufid].utime);
+ unsigned long s_time = tick_2_ms(buffer->persistance[bufid].stime);
+
+ /*compute total*/
+ total_usr += buffer->persistance[bufid].utime;
+ total_sys += buffer->persistance[bufid].stime;
+
+ compute_print_each_thread_rate(p, v, pp->pid, pp->comm, u_time, s_time, bufid);
+ }
+ } while_each_thread(gp, pp);
+
+ /*print total*/
+ seq_printf(p, " ------------------\n");
+ compute_print_each_thread_rate(p, v, 0, NULL, (tick_2_ms(total_usr)), (tick_2_ms(total_sys)), bufid);
+}
+
+static void print_usage(struct seq_file *p, void *v)
+{
+ unsigned long flags;
+ unsigned long i;
+ /*trigger sysrq when print usage for extra debug info*/
+ __handle_sysrq('w' , false);
+ /*lock*/
+ spin_lock_irqsave(&usage_lock, flags);
+
+ /*each thread: global_index+1 ---> buffer_end*/
+ for(i = bufferid(global_index) + 1; i < buffer_size; i++) {
+
+ /*print time circle*/
+ print_summary(p, v, i);
+
+ /*print cpu info*/
+ print_cpu_usage(p, v, i);
+
+ /*print thread cpu_info*/
+ print_each_thread_usage(p, v, i);
+ }
+
+ /*each thread: buffer_start ---> global_index */
+ for(i = 0; i < bufferid(global_index) + 1; i++) {
+
+ /*print time circle*/
+ print_summary(p, v, i);
+
+ /*print cpu info*/
+ print_cpu_usage(p, v, i);
+
+ /*print thread cpu_info*/
+ print_each_thread_usage(p, v, i);
+ }
+
+ /*unlock*/
+ spin_unlock_irqrestore(&usage_lock, flags);
+}
+
+static enum hrtimer_restart hrtimer_handler(struct hrtimer *timer)
+{
+ unsigned long flags;
+
+ /*lock*/
+ spin_lock_irqsave(&usage_lock, flags);
+
+ /*update cpu rate*/
+ record_cpu_usage();
+
+ /*update hrtimer*/
+ if((hrtimer_se > 0) || (hrtimer_ns >0)) {
+ kt = ktime_set(hrtimer_se, hrtimer_ns);
+ }
+
+ hrtimer_forward_now(timer, kt);
+
+ /*unlock*/
+ spin_unlock_irqrestore(&usage_lock, flags);
+
+ return HRTIMER_RESTART;
+}
+
+static int show_cpu_usage(struct seq_file *p, void *v)
+{
+ print_usage(p, v);
+
+ return 0;
+}
+
+static int cpu_usage_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos)
+{
+ char flag[len + 1];
+ char **endp = NULL;
+
+ memset(flag, 0 ,sizeof(flag));
+
+ if(copy_from_user(flag, buf, len)) return -EFAULT;
+
+ hrtimer_se = simple_strtol(flag, endp, 10);
+
+ return len;
+}
+
+static int cpu_usage_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, show_cpu_usage, NULL);
+}
+
+struct file_operations proc_cpu_usage_fops = {
+ .open = cpu_usage_open,
+ .read = seq_read,
+ .write = cpu_usage_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init proc_sprd_cpu_usage_init(void)
+{
+#ifdef CONFIG_SPRD_DEBUG_CPU_RATE
+ /*int static*/
+ memset(recorder, 0, sizeof(recorder));
+ memset(prev_value, 0, sizeof(prev_value));
+ memset(&ts, 0, sizeof(struct timespec));
+
+ /*init timer*/
+ kt = ktime_set(hrtimer_se, hrtimer_ns);
+ hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ timer.function = hrtimer_handler;
+ hrtimer_start(&timer, kt, HRTIMER_MODE_REL);
+
+ /*create proc*/
+ //proc_create("sprd_cpu_usage", 0, NULL, &proc_cpu_usage_fops);
+#endif
+
+ return 0;
+}
+
+static void __exit proc_sprd_cpu_usage_exit(void)
+{
+#ifdef CONFIG_SPRD_DEBUG_CPU_RATE
+ hrtimer_cancel(&timer);
+#endif
+ return;
+}
+
+module_init(proc_sprd_cpu_usage_init);
+module_exit(proc_sprd_cpu_usage_exit);
+
diff --git a/fs/proc/sprd_debug/proc_phymem.c b/fs/proc/sprd_debug/proc_phymem.c
new file mode 100644
index 00000000..2984a38e
--- /dev/null
+++ b/fs/proc/sprd_debug/proc_phymem.c
@@ -0,0 +1,190 @@
+#include <linux/module.h>
+#include <linux/swap.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/nmi.h>
+#include <linux/quicklist.h>
+#include <linux/vmalloc.h>
+#include <asm/setup.h>
+#include "../internal.h"
+
+#define K(x) ((x) << (PAGE_SHIFT - 10))
+
+extern struct meminfo meminfo;
+
+static struct proc_dir_entry* phymem;
+
+static int _phymem_map_proc_show(struct seq_file *m, void *v)
+{
+ int node, i, totalsize = 0;
+ struct meminfo *mi = &meminfo;
+
+ for_each_bank (i,mi) {
+ struct membank *bank = &mi->bank[i];
+ unsigned int pfn1, pfn2;
+ totalsize += bank->size;
+ seq_printf(m, "0x%08lx - 0x%08lx %lukB\n",
+ bank->start, bank->start + bank->size, bank->size/1024);
+ }
+ seq_printf(m, "linux total memory: %dkB\n", totalsize/1024);
+ return 0;
+}
+
+static int _phymem_pages_proc_show(struct seq_file *m, void *v)
+{
+ int free = 0, total = 0, reserved = 0;
+ int other = 0, shared = 0, cached = 0, slab = 0, node, i;
+
+ struct meminfo * mi = &meminfo;
+ for_each_bank (i,mi) {
+ struct membank *bank = &mi->bank[i];
+ unsigned int pfn1, pfn2;
+ struct page *page, *end;
+ pfn1 = bank_pfn_start(bank);
+ pfn2 = bank_pfn_end(bank);
+ page = pfn_to_page(pfn1);
+ end = pfn_to_page(pfn2 - 1) + 1;
+ do {
+ total++;
+ if (PageReserved(page))
+ reserved++;
+ else if (PageSwapCache(page))
+ cached++;
+ else if (PageSlab(page))
+ slab++;
+ else if (page_count(page) > 1)
+ shared++;
+ else if (!page_count(page))
+ free++;
+ else
+ other++;
+ page++;
+ }while (page < end);
+ }
+
+ seq_printf(m, "pages of RAM %d\n", total);
+ seq_printf(m, "free pages %d\n", free);
+ seq_printf(m, "reserved pages %d\n", reserved);
+ seq_printf(m, "slab pages %d\n", slab);
+ seq_printf(m, "pages shared %d\n", shared);
+ seq_printf(m, "pages swap cached %d\n", cached);
+ seq_printf(m, "other pages %d\n", other);
+ return 0;
+}
+
+#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
+
+static int _phymem_dist_proc_show(struct seq_file *m, void *v)
+{
+ struct sysinfo sys_info;
+ int node, i, pfn = 0, linux_total_size = 0;
+ struct meminfo *mi = &meminfo;
+ long cached;
+ long kernelmem;
+ struct vmalloc_info vmi;
+ unsigned long pages[NR_LRU_LISTS];
+ int lru;
+
+ for_each_bank (i,mi) {
+ struct membank *bank = &mi->bank[i];
+ unsigned int pfn1, pfn2;
+ linux_total_size += bank->size;
+ pfn = bank_pfn_end(bank);
+ }
+
+ si_meminfo(&sys_info);
+ si_swapinfo(&sys_info);
+
+ cached = global_page_state(NR_FILE_PAGES) -
+ total_swapcache_pages() - sys_info.bufferram;
+ if (cached < 0)
+ cached = 0;
+
+ for (lru = LRU_BASE; lru < NR_LRU_LISTS; lru++)
+ pages[lru] = global_page_state(NR_LRU_BASE + lru);
+
+ kernelmem = K(sys_info.totalram - sys_info.freeram - sys_info.bufferram - pages[LRU_ACTIVE_ANON] \
+ - pages[LRU_INACTIVE_ANON] - cached - total_swapcache_pages());
+ get_vmalloc_info(&vmi);
+
+ seq_printf(m, "mem: %lukB\n", pfn*4);
+ seq_printf(m, " |--mem_other: %lukB\n", pfn*4 - linux_total_size/1024);
+ seq_printf(m, " |--mem_linux: %lukB\n", linux_total_size/1024);
+ seq_printf(m, " |--reserved: %lukB\n", linux_total_size/1024 - K(sys_info.totalram));
+ seq_printf(m, " |--mem_total: %lukB\n", K(sys_info.totalram));
+ seq_printf(m, " |--free: %lukB\n", K(sys_info.freeram));
+ seq_printf(m, " |--buffer: %lukB\n", K(sys_info.bufferram));
+ seq_printf(m, " |--cache: %lukB\n", K(cached));
+ seq_printf(m, " |--swapcache: %lukB\n", K(total_swapcache_pages()));
+ seq_printf(m, " |--user: %lukB\n", K(pages[LRU_ACTIVE_ANON] + pages[LRU_INACTIVE_ANON]));
+ seq_printf(m, " | |--active anon: %lukB\n", K(pages[LRU_ACTIVE_ANON]));
+ seq_printf(m, " | |--inactive anon: %lukB\n", K(pages[LRU_INACTIVE_ANON]));
+ seq_printf(m, " |--kernel: %lukB\n", kernelmem);
+ seq_printf(m, " |--stack: %lukB\n", global_page_state(NR_KERNEL_STACK) * THREAD_SIZE / 1024);
+ seq_printf(m, " |--slab: %lukB\n", K(global_page_state(NR_SLAB_RECLAIMABLE) +global_page_state(NR_SLAB_UNRECLAIMABLE)));
+ seq_printf(m, " |--pagetable: %lukB\n", K(global_page_state(NR_PAGETABLE)));
+ seq_printf(m, " |--vmalloc: %lukB\n",
+ kernelmem - global_page_state(NR_KERNEL_STACK) * THREAD_SIZE / 1024 \
+ - K(global_page_state(NR_SLAB_RECLAIMABLE) - global_page_state(NR_SLAB_UNRECLAIMABLE)) \
+ -K(global_page_state(NR_PAGETABLE)));
+ return 0;
+}
+
+
+static int _phymem_map_proc_open(struct inode* inode, struct file* file)
+{
+ single_open(file, _phymem_map_proc_show, NULL);
+ return 0;
+}
+
+static int _phymem_pages_proc_open(struct inode* inode, struct file* file)
+{
+ single_open(file, _phymem_pages_proc_show, NULL);
+ return 0;
+}
+
+static int _phymem_dist_proc_open(struct inode* inode, struct file* file)
+{
+ single_open(file, _phymem_dist_proc_show, NULL);
+ return 0;
+}
+
+static int _phymem_showmem_proc_show(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
+{
+ /* show_mem(); */
+ return 0;
+}
+
+struct file_operations phymem_map_proc_fops = {
+ .open = _phymem_map_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+struct file_operations phymem_pages_proc_fops = {
+ .open = _phymem_pages_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+struct file_operations phymem_dist_proc_fops = {
+ .open = _phymem_dist_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+struct file_operations phymem_showmem_proc_fops = {
+ .open = NULL,
+ .write = _phymem_showmem_proc_show,
+ .llseek = NULL,
+ .release = NULL,
+};
+
diff --git a/fs/proc/sprd_debug/proc_sprd_debug.c b/fs/proc/sprd_debug/proc_sprd_debug.c
new file mode 100644
index 00000000..802fb252
--- /dev/null
+++ b/fs/proc/sprd_debug/proc_sprd_debug.c
@@ -0,0 +1,227 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <soc/sprd/sprd_debug.h>
+#include <asm/uaccess.h>
+#include <linux/regs_debug.h>
+
+extern struct sched_log (*psprd_debug_log);
+extern int get_task_log_idx(int cpu);
+extern int get_irq_log_idx(int cpu);
+
+
+/* sche debug proc */
+static int scheinfo_num = 50;
+
+static int get_task_log_start_idx(int cpu, int length)
+{
+ if (length >= SCHED_LOG_MAX)
+ return -1;
+
+ return (SCHED_LOG_MAX + get_task_log_idx(cpu) - length + 1) % SCHED_LOG_MAX;
+}
+
+static int _scheinfo_proc_show(struct seq_file *m, void *v)
+{
+ int i;
+ int j;
+ int idx;
+ int start_idx;
+ for (i = 0; i < NR_CPUS; i++) {
+ seq_printf(m, "cpu %d\n", i);
+ seq_printf(m, "%7s%20s %-20s\n", "pid", "time", "taskName");
+ seq_printf(m, "-------------------------------------------\n");
+ start_idx = get_task_log_start_idx(i, scheinfo_num);
+ for (j = 0 ; j < scheinfo_num; j++ ) {
+ idx = (start_idx + j) % SCHED_LOG_MAX;
+ seq_printf(m, "%7d%20llu %-20s\n",
+ psprd_debug_log->task[i][idx].pid,
+ psprd_debug_log->task[i][idx].time,
+ psprd_debug_log->task[i][idx].comm);
+ }
+ seq_printf(m, "\n");
+ }
+
+ return 0;
+}
+
+static int _scheinfo_proc_open(struct inode* inode, struct file* file)
+{
+ single_open(file, _scheinfo_proc_show, NULL);
+ return 0;
+}
+
+struct file_operations scheinfo_proc_fops = {
+ .open = _scheinfo_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+
+static int _scheinfo_num_proc_show(struct seq_file *m, void *v)
+{
+ seq_printf(m, "%d\n", scheinfo_num);
+ return 0;
+}
+
+static int _scheinfo_num_proc_open(struct inode* inode, struct file* file)
+{
+ single_open(file, _scheinfo_num_proc_show, NULL);
+ return 0;
+}
+
+static int _scheinfo_num_proc_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos)
+{
+ char sche_num_buf[10] = {0};
+ int sche_num;
+ int err;
+
+ if (len <= 0 || len >= 10)
+ return -EFAULT;
+
+ if (copy_from_user(&sche_num_buf, buf, len))
+ return -EFAULT;
+
+ err = strict_strtol(strstrip(sche_num_buf), 0, &sche_num);
+
+ if (err)
+ return -EINVAL;
+
+ scheinfo_num = sche_num;
+
+ return strlen(sche_num_buf);
+}
+
+struct file_operations scheinfo_num_proc_fops = {
+ .open = _scheinfo_num_proc_open,
+ .read = seq_read,
+ .write = _scheinfo_num_proc_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+
+/* irq debug proc */
+static int irqinfo_num = 50;
+
+static int get_irq_log_start_idx(int cpu, int length)
+{
+ if (length >= SCHED_LOG_MAX)
+ return -1;
+
+ return (SCHED_LOG_MAX + get_irq_log_idx(cpu) - length + 1) % SCHED_LOG_MAX;
+}
+
+static int _irqinfo_proc_show(struct seq_file *m, void *v)
+{
+ int i;
+ int j;
+ int idx;
+ int start_idx;
+ for (i = 0; i < NR_CPUS; i++) {
+ seq_printf(m, "cpu %d\n", i);
+ seq_printf(m, "%7s%20s%5s%18s\n", "irq", "time", "en", "fn");
+ seq_printf(m, "-------------------------------------------\n");
+ start_idx = get_irq_log_start_idx(i, irqinfo_num);
+ for (j = 0 ; j < irqinfo_num; j++ ) {
+ idx = (start_idx + j) % SCHED_LOG_MAX;
+ seq_printf(m, "%7d%20llu%5d%18p\n",
+ psprd_debug_log->irq[i][idx].irq,
+ psprd_debug_log->irq[i][idx].time,
+ psprd_debug_log->irq[i][idx].en,
+ psprd_debug_log->irq[i][idx].fn);
+ }
+ seq_printf(m, "\n");
+ }
+
+ return 0;
+}
+
+static int _irqinfo_proc_open(struct inode* inode, struct file* file)
+{
+ single_open(file, _irqinfo_proc_show, NULL);
+ return 0;
+}
+
+struct file_operations irqinfo_proc_fops = {
+ .open = _irqinfo_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int _irqinfo_num_proc_show(struct seq_file *m, void *v)
+{
+ seq_printf(m, "%d\n", irqinfo_num);
+ return 0;
+}
+
+static int _irqinfo_num_proc_open(struct inode* inode, struct file* file)
+{
+ single_open(file, _irqinfo_num_proc_show, NULL);
+ return 0;
+}
+
+static int _irqinfo_num_proc_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos)
+{
+ char irq_num_buf[10] = {0};
+ int irq_num;
+ int err;
+
+ if (len <= 0 || len >= 10)
+ return -EFAULT;
+
+ if (copy_from_user(&irq_num_buf, buf, len))
+ return -EFAULT;
+
+ err = strict_strtol(strstrip(irq_num_buf), 0, &irq_num);
+
+ if (err)
+ return -EINVAL;
+
+ irqinfo_num = irq_num;
+
+ return strlen(irq_num_buf);
+}
+
+struct file_operations irqinfo_num_proc_fops = {
+ .open = _irqinfo_num_proc_open,
+ .read = seq_read,
+ .write = _irqinfo_num_proc_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/* last regs info */
+extern struct sprd_debug_regs_access *sprd_debug_last_regs_access;
+static int _last_regs_info_proc_show(struct seq_file *m, void *v)
+{
+ int i;
+ for (i = 0; i < NR_CPUS; i++) {
+ seq_printf(m, "cpu %d\n", i);
+ seq_printf(m, "vaddr:%p value:%p pc:%p time:%p status:%p\n",
+ sprd_debug_last_regs_access[i].vaddr,
+ sprd_debug_last_regs_access[i].value,
+ sprd_debug_last_regs_access[i].pc,
+ sprd_debug_last_regs_access[i].time,
+ sprd_debug_last_regs_access[i].status);
+ }
+}
+
+static int _last_regs_info_proc_open(struct inode* inode, struct file* file)
+{
+ single_open(file, _last_regs_info_proc_show, NULL);
+ return 0;
+}
+
+struct file_operations last_regs_info_proc_fops = {
+ .open = _last_regs_info_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
diff --git a/fs/proc/sprd_debug/proc_sprd_debug_frame.c b/fs/proc/sprd_debug/proc_sprd_debug_frame.c
new file mode 100644
index 00000000..8551a4ac
--- /dev/null
+++ b/fs/proc/sprd_debug/proc_sprd_debug_frame.c
@@ -0,0 +1,135 @@
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/mm.h>
+#include <linux/stat.h>
+
+enum sprd_debug_type{
+ SCHE,
+ MEM,
+ COMM,
+ TIMER,
+ IRQ,
+ IO,
+ CPU,
+ MISC,
+ TYPE_COUNT
+};
+
+struct sprd_debug_dir {
+ char *name;
+ struct dentry *debugfs_entry;
+};
+
+struct sprd_debug_dir sprd_debug_dir_table[TYPE_COUNT] = {
+ {.name = "sche", .debugfs_entry = NULL},
+ {.name = "mem", .debugfs_entry = NULL},
+ {.name = "comm", .debugfs_entry = NULL},
+ {.name = "timer", .debugfs_entry = NULL},
+ {.name = "irq", .debugfs_entry = NULL},
+ {.name = "io", .debugfs_entry = NULL},
+ {.name = "cpu", .debugfs_entry = NULL},
+ {.name = "misc", .debugfs_entry = NULL},
+};
+
+struct sprd_debug_entry {
+ enum sprd_debug_type type;
+ char *name;
+ mode_t mode;
+ struct file_operations *fop;
+};
+
+#define NOD(TYPE, NAME, MODE, FOP) { \
+ .type = TYPE, \
+ .name = NAME, \
+ .mode = MODE, \
+ .fop = FOP}
+
+#ifdef CONFIG_SPRD_DEBUG_PHYMEM_INFO
+extern struct file_operations phymem_dist_proc_fops;
+extern struct file_operations phymem_pages_proc_fops;
+extern struct file_operations phymem_map_proc_fops;
+#endif
+
+#ifdef CONFIG_SPRD_DEBUG_USRPROCMEM_INFO
+extern struct file_operations user_process_meminfo_fops;
+#endif
+
+#ifdef CONFIG_SPRD_DEBUG_SCHED_LOG
+extern struct file_operations scheinfo_proc_fops;
+extern struct file_operations scheinfo_num_proc_fops;
+extern struct file_operations irqinfo_proc_fops;
+extern struct file_operations irqinfo_num_proc_fops;
+extern struct file_operations last_regs_info_proc_fops;
+extern struct file_operations userstack_info_proc_fops;
+#endif
+
+#ifdef CONFIG_SPRD_DEBUG_CPU_RATE
+extern struct file_operations proc_cpu_usage_fops;
+#endif
+
+static struct sprd_debug_entry sprd_debug_array[] = {
+#ifdef CONFIG_SPRD_DEBUG_PHYMEM_INFO
+ NOD(MEM, "phymemdist", 0, &phymem_dist_proc_fops),
+ NOD(MEM, "phymempages", 0, &phymem_pages_proc_fops),
+ NOD(MEM, "phymemmap", 0, &phymem_map_proc_fops),
+#endif
+
+#ifdef CONFIG_SPRD_DEBUG_USRPROCMEM_INFO
+ NOD(MEM, "userprocmem", 0, &user_process_meminfo_fops),
+ NOD(MEM, "userthreadstack", 0, &userstack_info_proc_fops),
+#endif
+
+#ifdef CONFIG_SPRD_DEBUG_SCHED_LOG
+ NOD(SCHE, "schedlog", 0444 , &scheinfo_proc_fops),
+ NOD(SCHE, "schedlog_num", 0, &scheinfo_num_proc_fops),
+ NOD(IRQ, "irqlog", 0, &irqinfo_proc_fops),
+ NOD(IRQ, "irqlog_num", 0, &irqinfo_num_proc_fops),
+ NOD(IO, "last_regs", 0, &last_regs_info_proc_fops),
+#endif
+
+#ifdef CONFIG_SPRD_DEBUG_CPU_RATE
+ NOD(CPU, "cpu_usage", 0444, &proc_cpu_usage_fops),
+#endif
+};
+
+static struct dentry *debugfs_sprd_debug_root;
+
+static void _sprd_entry_create(struct sprd_debug_entry *psprd_debug)
+{
+ if ((psprd_debug->name != NULL) && (psprd_debug->fop != NULL))
+ debugfs_create_file(psprd_debug->name, psprd_debug->mode,
+ sprd_debug_dir_table[psprd_debug->type].debugfs_entry, NULL, psprd_debug->fop);
+}
+
+static void _sprd_debug_init(void)
+{
+ int i;
+ int num = sizeof(sprd_debug_array) / sizeof(struct sprd_debug_entry);
+
+ for (i = 0; i < num; i++)
+ _sprd_entry_create(&sprd_debug_array[i]);
+
+}
+
+static void _sprd_dir_init(void)
+{
+ int i;
+
+ debugfs_sprd_debug_root = debugfs_create_dir("sprd_debug", NULL);
+ for (i = 0; i < TYPE_COUNT; i++)
+ sprd_debug_dir_table[i].debugfs_entry = debugfs_create_dir(sprd_debug_dir_table[i].name, debugfs_sprd_debug_root);
+}
+
+static int _sprd_debug_module_init(void)
+{
+ _sprd_dir_init();
+ _sprd_debug_init();
+ return 0;
+}
+
+module_init(_sprd_debug_module_init);
+
diff --git a/fs/proc/sprd_debug/proc_usermeminfo.c b/fs/proc/sprd_debug/proc_usermeminfo.c
new file mode 100644
index 00000000..434cf4c0
--- /dev/null
+++ b/fs/proc/sprd_debug/proc_usermeminfo.c
@@ -0,0 +1,174 @@
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/pid.h>
+#include <asm/uaccess.h>
+#include <asm/current.h>
+#include <linux/mm.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("userspace process memory info device");
+
+struct user_process_mem_info {
+ unsigned long vss;
+ unsigned long rss;
+ unsigned long rss_mapped;
+ unsigned long pss;
+ unsigned long uss;
+ int task_pid;
+};
+
+static int memoryinfo_flag = 0;
+
+static pte_t check_pte(struct mm_struct *mm, unsigned long address)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ pgd = pgd_offset(mm, address);
+ if (!pgd_present(*pgd))
+ goto check_fail;
+
+ pud = pud_offset(pgd, address);
+ if (!pud_present(*pud))
+ goto check_fail;
+
+ pmd = pmd_offset(pud, address);
+ if (!pmd_present(*pmd))
+ goto check_fail;
+ if (pmd_trans_huge(*pmd))
+ goto check_fail;
+
+ pte = pte_offset_map(pmd, address);
+ if (!pte_present(*pte))
+ goto check_fail;
+
+ return *pte;
+
+check_fail:
+ return 0;
+}
+
+
+static struct page *check_pfn(pte_t pte)
+{
+ if (!pte_pfn(pte))
+ return NULL;
+ else
+ return pfn_to_page(pte_pfn(pte));
+}
+
+int get_userprocess_meminfo(struct task_struct* p, struct user_process_mem_info *upmeminfo)
+{
+ struct vm_area_struct *vma = NULL;
+ if (p->mm == NULL)
+ return -1;
+
+ upmeminfo->task_pid = p->pid;
+ for (vma = p->mm->mmap; vma; vma = vma->vm_next) {
+ unsigned long pagesize = PAGE_SIZE;
+ unsigned long step = vma->vm_start;
+
+ for(; step < vma->vm_end; step += pagesize) {
+ pte_t pte;
+ int mapcount;
+ struct page *page;
+
+ /*!!! VSS in procrank equals rss, and actually wrong !!!*/
+ upmeminfo->vss += pagesize; /*vss*/
+ pte = check_pte(p->mm, step);
+ if(!pte) continue;
+
+ page = check_pfn(pte);
+ if(!page) continue;
+
+ /*!!! RSS in procrank equals rss_mapped, and actually wrong !!!*/
+ upmeminfo->rss += pagesize; /*rss*/
+ mapcount = page_mapcount(page);
+ if(2 <= mapcount) {
+ upmeminfo->rss_mapped += pagesize; /*rss_mapped*/
+ upmeminfo->pss += pagesize / mapcount; /*pss*/
+ } else if (1 == mapcount) {
+ upmeminfo->rss_mapped += pagesize; /*rss_mapped*/
+ upmeminfo->pss += pagesize; /*pss*/
+ upmeminfo->uss += pagesize; /*uss*/
+ } else if (0 == mapcount) {
+ /*this is the difference between rss & rss_mapped.*/
+ }
+ }
+ }
+
+ return 0;
+}
+
+int user_process_meminfo_show(void)
+{
+ struct task_struct *p = NULL;
+ struct user_process_mem_info upmeminfo;
+
+ printk(KERN_INFO "%5s %11s %9s %11s %9s %9s %s\n",
+ "pid", "vss", "rss", "rss_mapped", "pss", "uss", "name");
+
+ printk(KERN_INFO "-----------------------------------------------------------------\n");
+ for_each_process(p) {
+ memset(&upmeminfo, 0, sizeof(upmeminfo));
+ if (get_userprocess_meminfo(p, &upmeminfo))
+ continue;
+
+ printk(KERN_INFO "%5d %10luK %8luK %10luK %8luK %8luK %s\n",
+ upmeminfo.task_pid,
+ upmeminfo.vss >> 10,
+ upmeminfo.rss >> 10,
+ upmeminfo.rss_mapped >> 10,
+ upmeminfo.pss >> 10,
+ upmeminfo.uss >> 10,
+ p->comm);
+ }
+
+ return 0;
+}
+
+static int proc_user_process_meminfo_show(struct seq_file *m, void *v)
+{
+ struct task_struct *p = NULL;
+ struct user_process_mem_info upmeminfo;
+
+ seq_printf(m, "%5s %11s %9s %11s %9s %9s %s\n",
+ "pid", "vss", "rss", "rss_mapped", "pss", "uss", "name");
+
+ seq_printf(m, "-----------------------------------------------------------------\n");
+ for_each_process(p) {
+ memset(&upmeminfo, 0, sizeof(upmeminfo));
+ if (get_userprocess_meminfo(p, &upmeminfo))
+ continue;
+
+ seq_printf(m, "%5d %10luK %8luK %10luK %8luK %8luK %s\n",
+ upmeminfo.task_pid,
+ upmeminfo.vss >> 10,
+ upmeminfo.rss >> 10,
+ upmeminfo.rss_mapped >> 10,
+ upmeminfo.pss >> 10,
+ upmeminfo.uss >> 10,
+ p->comm);
+ }
+
+ return 0;
+}
+
+static int proc_user_process_meminfo_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_user_process_meminfo_show, NULL);
+}
+
+struct file_operations user_process_meminfo_fops = {
+ .open = proc_user_process_meminfo_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
diff --git a/fs/proc/sprd_debug/proc_userstack.c b/fs/proc/sprd_debug/proc_userstack.c
new file mode 100644
index 00000000..ef055bb4
--- /dev/null
+++ b/fs/proc/sprd_debug/proc_userstack.c
@@ -0,0 +1,169 @@
+//#ifdef CONFIG_USERSTACKTRACEG
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/nmi.h>
+#include <linux/quicklist.h>
+#include <asm/setup.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/cacheflush.h>
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+#include <asm/cacheflush.h>
+#include <linux/kallsyms.h>
+#include <linux/ext2_fs.h>
+#include <linux/highmem.h>
+#define K(x) ((x) << (PAGE_SHIFT - 10))
+
+extern struct meminfo meminfo;
+static int show_user_stack(struct seq_file *m, void *v);
+//static struct proc_dir_entry* userstack_info;
+
+static int get_pfn_from_mm(unsigned long address, struct mm_struct *mm)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ int ret = 0;
+
+ pgd = pgd_offset(mm, address);
+ if (!pgd_present(*pgd))
+ return ret;
+
+ pud = pud_offset(pgd, address);
+ if (!pud_present(*pud))
+ return ret;
+
+ pmd = pmd_offset(pud, address);
+ if (!pmd_present(*pmd))
+ return ret;
+
+ pte = pte_offset_map(pmd, address);
+
+ if (!pte_present(*pte))
+ return 0;
+
+ return pte_pfn(*pte);
+}
+
+static struct page *user_addr_to_page(unsigned long uaddr, struct task_struct *task)
+{
+ int pfn;
+ pfn = get_pfn_from_mm(uaddr, task->mm);
+
+ if (!pfn)
+ return NULL;
+
+ return pfn_to_page(pfn);
+}
+
+static int show_userstack_of_task(struct task_struct *task, struct seq_file *m, void *v)
+{
+ unsigned long val;
+ unsigned long p;
+ struct vm_area_struct *vma;
+ unsigned long usersp, kusersp;
+ unsigned long length = 32*10;
+ unsigned long *kaddr = NULL;
+ struct page *page = NULL;
+ pgoff_t pgoff;
+
+ if (!task->mm) {
+ seq_printf(m, "pid:%d, it's a kthread, no userstack!\n",task->pid);
+ return 0;
+ }
+
+ usersp = task_pt_regs(task)->uregs[13];
+
+ seq_printf(m, "userstack pid:%d sp:0x%p\n\n", task->pid, (void *)usersp);
+
+ page = user_addr_to_page(usersp, task);
+ if (!page) {
+ seq_printf(m, "Sorry, can't find the stack's page!\n");
+ return 0;
+ }
+
+ pgoff = usersp & 0x00000fff;
+ kaddr = kmap(page);
+ kusersp = (unsigned long)kaddr + pgoff;
+
+ for (p = kusersp; p < kusersp + length; p += 4) {
+ vma = NULL;
+ val = *(unsigned long *)p;
+ vma = find_vma(task->mm, val);
+ if (vma) {
+ struct file *file = vma->vm_file;
+ struct mm_struct *mm = vma->vm_mm;
+
+ if (val < vma->vm_start) {
+ seq_printf(m, "%4lx: %08lx \n", p, val);
+ continue;
+ }
+
+ if (file) {
+ char buf[50];
+ char *pp = NULL;
+
+ memset(buf, 0, 50);
+ pp = d_path(&file->f_path, buf, 50);
+ if (!IS_ERR(pp))
+ mangle_path(buf, pp, "\n");
+
+ seq_printf(m, "%4lx: %08lx %s 0x%p\n", p, val, buf, (void *)vma->vm_start);
+ } else {
+ const char *name = arch_vma_name(vma);
+ if (!name) {
+ if (vma->vm_start <= mm->start_brk && vma->vm_end >= mm->brk)
+ seq_printf(m, "%4lx: %08lx [heap]\n", p, val);
+ else if (vma->vm_start <= mm->start_stack && vma->vm_end >= mm->start_stack)
+ seq_printf(m, "%4lx: %08lx [stack]\n", p, val);
+ else
+ seq_printf(m, "%4lx: %08lx [vdso]\n", p, val);
+ } else
+ seq_printf(m, "%4lx: %08lx %s\n", p, val, name);
+ }
+ } else
+ seq_printf(m, "%4lx: %08lx \n", p, val);
+ }
+ seq_printf(m, "====================================================\n");
+ kunmap(page);
+ return 0;
+}
+
+static int show_user_stack(struct seq_file *m, void *v)
+{
+ struct task_struct *g, *p;
+ seq_printf(m, "=============enter ====show_user_stack===========\n");
+
+ do_each_thread(g, p) {
+ task_lock(p);
+ if (p->state == TASK_UNINTERRUPTIBLE)
+ show_userstack_of_task(p, m, v);
+ task_unlock(p);
+ }while_each_thread(g, p);
+
+ return 0;
+}
+
+static int userstack_proc_open(struct inode* inode, struct file* file)
+{
+ single_open(file, show_user_stack, NULL);
+ return 0;
+}
+
+
+struct file_operations userstack_info_proc_fops =
+{
+ .open = userstack_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
diff --git a/fs/proc/sprd_debug/sprd_uboot_log_dump.c b/fs/proc/sprd_debug/sprd_uboot_log_dump.c
new file mode 100644
index 00000000..b195bdf7
--- /dev/null
+++ b/fs/proc/sprd_debug/sprd_uboot_log_dump.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/module.h>
+#include <linux/memblock.h>
+#include <linux/io.h>
+#include <linux/proc_fs.h>
+
+#define PROC_DUMP_PARENT "bootloader"
+#define PROC_DUMP "log_buf"
+
+static unsigned int log_start = ~0x1;
+static unsigned int log_size = ~0x1;
+
+static int __init set_ram_range(char *str)
+{
+
+ if (get_option(&str, &log_start) == 2)
+ get_option(&str, &log_size);
+
+ return 1;
+}
+
+__setup("boot_ram_log=", set_ram_range);
+
+static int log_buf_open(struct inode *inode, struct file *filp)
+{
+ void *base;
+
+ /* determine the ram area is valid or not. */
+ if (!valid_phys_addr_range(log_start, log_size)
+ || !memblock_is_region_reserved(log_start, log_size)) {
+ pr_err("%s: check memory range failed!\n", __func__);
+
+ return -EINVAL;
+ }
+
+ base = ioremap(log_start, log_size);
+ filp->private_data = base;
+ if (!base) {
+ pr_err("%s: remap error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int log_buf_release(struct inode *inode, struct file *filp)
+{
+ void *base = filp->private_data;
+
+ if (base)
+ iounmap(base);
+
+ return 0;
+}
+
+
+static ssize_t log_buf_read(struct file *filp, char __user *buffer,
+ size_t len, loff_t *offset)
+{
+ void *base = filp->private_data;
+
+ if (!base)
+ return -ENOMEM;
+
+ return simple_read_from_buffer(buffer, len, offset, base, log_size);
+}
+
+
+static int log_buf_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ return vm_iomap_memory(vma, log_start, log_size);
+}
+
+
+static const struct file_operations log_buf_fops = {
+ .owner = THIS_MODULE,
+ .read = log_buf_read,
+ .open = log_buf_open,
+ .mmap = log_buf_mmap,
+ .release = log_buf_release,
+};
+
+
+static int __init uboot_log_dump(void)
+{
+ int err;
+ struct proc_dir_entry *entry_parent, *entry_dump;
+
+ entry_parent = proc_mkdir("bootloader", NULL);
+ if (!entry_parent) {
+ pr_err("u-boot log dump: create proc file failed\n");
+ return -ENOMEM;
+ }
+
+ /* other user is NOT permitted to dump buffer */
+ entry_dump = proc_create_data(PROC_DUMP, S_IRUSR, entry_parent,
+ &log_buf_fops, NULL);
+
+ err = entry_dump ? 0 : -ENOMEM;
+
+ return err;
+}
+
+module_init(uboot_log_dump);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Spreadtrum U-boot log dump support");
diff --git a/fs/proc/sprd_debug/usermeminfo.h b/fs/proc/sprd_debug/usermeminfo.h
new file mode 100644
index 00000000..b3987978
--- /dev/null
+++ b/fs/proc/sprd_debug/usermeminfo.h
@@ -0,0 +1,4 @@
+#ifndef _USERMEM_INFO_H
+#define _USERMEM_INOF_H
+extern int user_process_meminfo_show(void);
+#endif