1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
#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);
|