blob: a91818fd2fdd9e1e3ff935d317360ca7b1f41318 [file] [log] [blame]
#include <linux/proc_fs.h>
#include <linux/atomic.h>
#include <linux/printk.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/history_record.h>
static struct saved_history_record all_history_record[SAVED_HISTORY_MAX];
static atomic_t saved_history_current = ATOMIC_INIT(-1);
/* mapping entry name according type */
static char *entry_name[] = {
" ",
"sgx-1",
"sgx-2",
"pipe",
"msvdx_stat",
"vdc_stat",
};
static void history_record_init(struct saved_history_record *record)
{
int cpu;
cpu = raw_smp_processor_id();
record->ts = cpu_clock(cpu);
record->record_value.value = 0;
}
struct saved_history_record *get_new_history_record(void)
{
struct saved_history_record *precord = NULL;
int ret = atomic_add_return(1, &saved_history_current);
/* in case overflow */
if (ret < 0) {
atomic_set(&saved_history_current, 0);
ret = 0;
}
precord = &all_history_record[ret%SAVED_HISTORY_MAX];
history_record_init(precord);
return precord;
}
EXPORT_SYMBOL(get_new_history_record);
static void print_saved_history_record(struct saved_history_record *record)
{
unsigned long long ts = record->ts;
unsigned long nanosec_rem = do_div(ts, 1000000000);
printk(KERN_INFO "----\n");
switch (record->type) {
case 1:
case 2:
printk(KERN_INFO "name:[%s] ts[%5lu.%06lu] HostIrqCountSample[%u] InterruptCount[%u]\n",
entry_name[record->type],
(unsigned long)ts,
nanosec_rem / 1000,
record->record_value.sgx.HostIrqCountSample,
record->record_value.sgx.InterruptCount);
break;
case 3:
printk(KERN_INFO "name:[%s] ts[%5lu.%06lu] pipe[%u] pipe_stat_val[%#x]\n",
entry_name[record->type],
(unsigned long)ts,
nanosec_rem / 1000,
record->record_value.pipe.pipe_nu,
record->record_value.pipe.pipe_stat_val);
break;
case 4:
printk(KERN_INFO "name:[%s] ts[%5lu.%06lu] msvdx_stat[%#lx]\n",
entry_name[record->type],
(unsigned long)ts,
nanosec_rem / 1000,
record->record_value.msvdx_stat);
break;
case 5:
printk(KERN_INFO "name:[%s] ts[%5lu.%06lu] vdc_stat[%#lx]\n",
entry_name[record->type],
(unsigned long)ts,
nanosec_rem / 1000,
record->record_value.vdc_stat);
break;
default:
break;
}
}
void interrupt_dump_history(void)
{
int i, start;
unsigned int total = atomic_read(&saved_history_current);
start = total % SAVED_HISTORY_MAX;
printk(KERN_INFO "<----current timestamp\n");
printk(KERN_INFO "start[%d] saved[%d]\n",
start, total);
for (i = start; i >= 0; i--) {
if (i % 10 == 0)
schedule();
print_saved_history_record(&all_history_record[i]);
}
for (i = SAVED_HISTORY_MAX - 1; i > start; i--) {
if (i % 10 == 0)
schedule();
print_saved_history_record(&all_history_record[i]);
}
}
EXPORT_SYMBOL(interrupt_dump_history);
static ssize_t debug_read_history_record(struct file *f,
char __user *buf, size_t size, loff_t *off)
{
interrupt_dump_history();
return 0;
}
static const struct file_operations debug_history_proc_fops = {
.owner = THIS_MODULE,
.read = debug_read_history_record,
};
static int __init debug_read_history_record_entry(void)
{
struct proc_dir_entry *res = NULL;
res = proc_create_data("debug_read_sgx_history", S_IRUGO | S_IWUSR,
NULL, &debug_history_proc_fops, NULL);
return 0;
}
device_initcall(debug_read_history_record_entry);