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
139
140
141
142
143
144
145
146
147
|
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/slab.h>
#include <asm/io.h>
#include "../lastpc.h"
struct lastpc_imp {
struct lastpc_plt plt;
void __iomem *toprgu_reg;
};
#define to_lastpc_imp(p) container_of((p), struct lastpc_imp, plt);
//#define LASTPC 0X20
//#define LASTSP 0X24
//#define LASTFP 0X28
//#define MUX_CONTOL_C0_REG (base + 0x140)
//#define MUX_READ_C0_REG (base + 0x144)
//#define MUX_CONTOL_C1_REG (base + 0x21C)
//#define MUX_READ_C1_REG (base + 0x25C)
//static unsigned int LASTPC_MAGIC_NUM[] = {0x3, 0xB, 0x33, 0x43};
static int lastpc_plt_start(struct lastpc_plt *plt)
{
return 0;
}
static int lastpc_plt_dump(struct lastpc_plt *plt, char *buf, int len)
{
void __iomem *mcu_base = plt->common->base + 0x410;
int ret = -1, cnt = num_possible_cpus();
char *ptr = buf;
unsigned long pc_value;
unsigned long fp_value;
unsigned long sp_value;
#ifdef CONFIG_ARM64
unsigned long pc_value_h;
unsigned long fp_value_h;
unsigned long sp_value_h;
#endif
unsigned long size = 0;
unsigned long offset = 0;
char str[KSYM_SYMBOL_LEN];
int i;
int cluster, cpu_in_cluster;
if(cnt < 0)
return ret;
#ifdef CONFIG_ARM64
/* Get PC, FP, SP and save to buf */
for (i = 0; i < cnt; i++) {
cluster = i / 4;
cpu_in_cluster = i % 4;
pc_value_h = readl(IOMEM((mcu_base+0x4) + (cpu_in_cluster << 5) + (0x100 * cluster)));
pc_value = (pc_value_h << 32) | readl(IOMEM((mcu_base+0x0) + (cpu_in_cluster << 5) + (0x100 * cluster)));
fp_value_h = readl(IOMEM((mcu_base+0x14) + (cpu_in_cluster << 5) + (0x100 * cluster)));
fp_value = (fp_value_h <<32) | readl(IOMEM((mcu_base+0x10) + (cpu_in_cluster << 5) + (0x100 * cluster)));
sp_value_h = readl(IOMEM((mcu_base+0x1c) + (cpu_in_cluster << 5) + (0x100 * cluster)));
sp_value = (sp_value_h << 32) | readl(IOMEM((mcu_base+0x18) + (cpu_in_cluster << 5) + (0x100 * cluster)));
kallsyms_lookup(pc_value, &size, &offset, NULL, str);
ptr += sprintf(ptr, "[LAST PC] CORE_%d PC = 0x%lx(%s + 0x%lx), FP = 0x%lx, SP = 0x%lx\n", i, pc_value, str, offset, fp_value, sp_value);
pr_notice("[LAST PC] CORE_%d PC = 0x%lx(%s), FP = 0x%lx, SP = 0x%lx\n", i, pc_value, str, fp_value, sp_value);
}
#else
/* Get PC, FP, SP and save to buf */
for (i = 0; i < cnt; i++) {
cluster = i / 4;
cpu_in_cluster = i % 4;
pc_value = readl(IOMEM((mcu_base+0x0) + (cpu_in_cluster << 5) + (0x100 * cluster)));
fp_value = readl(IOMEM((mcu_base+0x8) + (cpu_in_cluster << 5) + (0x100 * cluster)));
sp_value = readl(IOMEM((mcu_base+0xc) + (cpu_in_cluster << 5) + (0x100 * cluster)));
kallsyms_lookup((unsigned long)pc_value, &size, &offset, NULL, str);
ptr += sprintf(ptr, "[LAST PC] CORE_%d PC = 0x%lx(%s + 0x%lx), FP = 0x%lx, SP = 0x%lx\n", i, pc_value, str, offset, fp_value, sp_value);
pr_notice("[LAST PC] CORE_%d PC = 0x%lx(%s), FP = 0x%lx, SP = 0x%lx\n", i, pc_value, str, fp_value, sp_value);
}
#endif
#if 0
/* Get PC, FP, SP and save to buf */
for (i = 0; i < cnt; i++) {
/* this calculation assumes that we have 4 cores in the first cluster, and 2 clusters in the system */
cluster = i / 4;
cpu_in_cluster = i % 4;
if (cluster == 0) {
writel(LASTPC + i, MUX_CONTOL_C0_REG);
pc_value = readl(MUX_READ_C0_REG);
writel(LASTSP + i, MUX_CONTOL_C0_REG);
sp_value = readl(MUX_READ_C0_REG);
writel(LASTFP + i, MUX_CONTOL_C0_REG);
fp_value = readl(MUX_READ_C0_REG);
kallsyms_lookup((unsigned long)pc_value, &size, &offset, NULL, str);
ptr += sprintf(ptr, "CORE_%d PC = 0x%x(%s + 0x%lx), FP = 0x%x, SP = 0x%x\n", i, pc_value, str, offset, fp_value, sp_value);
} else {
writel(LASTPC_MAGIC_NUM[cpu_in_cluster], MUX_CONTOL_C1_REG);
pc_value = readl(MUX_READ_C1_REG);
writel(LASTPC_MAGIC_NUM[cpu_in_cluster] + 1, MUX_CONTOL_C1_REG);
pc_i1_value = readl(MUX_READ_C1_REG);
ptr += sprintf(ptr, "CORE_%d PC_i0 = 0x%x, PC_i1 = 0x%x\n", i, pc_value, pc_i1_value);
}
}
#endif
return 0;
}
static int reboot_test(struct lastpc_plt *plt)
{
return 0;
}
static struct lastpc_plt_operations lastpc_ops = {
.start = lastpc_plt_start,
.dump = lastpc_plt_dump,
.reboot_test = reboot_test,
};
static int __init lastpc_init(void)
{
struct lastpc_imp *drv = NULL;
int ret = 0;
drv = kzalloc(sizeof(struct lastpc_imp), GFP_KERNEL);
if (!drv) {
pr_err("%s:%d: kzalloc fail.\n", __func__, __LINE__);
return -ENOMEM;
}
drv->plt.ops = &lastpc_ops;
drv->plt.chip_code = 0x6752;
drv->plt.min_buf_len = 2048; //TODO: can calculate the len by how many levels of bt we want
ret = lastpc_register(&drv->plt);
if (ret) {
pr_err("%s:%d: lastpc_register failed\n", __func__, __LINE__);
goto register_lastpc_err;
}
return 0;
register_lastpc_err:
kfree(drv);
return ret;
}
arch_initcall(lastpc_init);
|