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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
|
/*
* MC error interrupt handling header file. Various defines and declarations
* across tegra chips.
*
* Copyright (c) 2010-2021, NVIDIA Corporation. 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.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MCERR_H
#define __MCERR_H
#include <linux/kernel.h>
#include <linux/debugfs.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/platform/tegra/mc.h>
#define MAX_PRINTS 5
/* defines that are common across SOC's. */
#define MC_INTMASK 0x4
#define MC_ERR_STATUS_WRITE (1 << 16)
#define MC_ERR_STATUS_SECURE (1 << 17)
#define MC_ERR_STATUS_ADR_HI (3 << 20)
#define MC_INT_DECERR_EMEM (1<<6)
#define MC_INT_SECURITY_VIOLATION (1<<8)
#define MC_INT_ARBITRATION_EMEM (1<<9)
#define MC_INT_DECERR_VPR (1<<12)
#define MC_INT_SECERR_SEC (1<<13)
#define MC_INT_DECERR_GENERALIZED_CARVEOUT (1<<17)
#define MC_ERR_DECERR_EMEM (2)
#define MC_ERR_SECURITY_TRUSTZONE (3)
#define MC_ERR_SECURITY_CARVEOUT (4)
#define MC_ERR_INVALID_SMMU_PAGE (6)
struct platform_device;
int tegra_mcerr_init(struct dentry *mc_paren, struct platform_device *pdev);
void tegra_mcerr_resume(void);
irqreturn_t tegra_mc_handle_general_fault(int src_chan, int intstatus);
/*
* This describes errors that can be generated by the MC. One is defined for
* each possibility.
*
* @sig Interrupt signiture for the error.
* @msg Error description.
* @flags Relevant flags for the error.
* @stat_reg Register offset that holds the status of the error.
* @addr_reg Register offset that holds the faulting address.
*/
struct mc_error {
const char *msg;
u32 sig;
int flags;
u32 stat_reg;
u32 addr_reg;
u32 addr_hi_reg;
};
#define E_SMMU (1<<0)
#define E_NO_STATUS (1<<1) /* No status/addr */
#define E_TWO_STATUS (1<<2) /* Two status registers, no addr */
#define E_VPR (1<<3) /* VPR violation */
#define E_ADR_HI_REG (1<<4) /* Hi Addr bits in hi reg */
#define E_GSC (1<<5) /* GSC violation */
extern u32 mc_int_mask;
extern u32 mcerr_silenced;
struct mcerr_ops {
/*
* Show the statistics for each client. This is called from a debugfs
* context - that means you can sleep and do general kernel stuff here.
*/
int (*mcerr_debugfs_show)(struct seq_file *s, void *v);
/* Disable MC Error interrupt.
*
* Called in hard irq context to disable interrupt till
* soft irq handler logs the MC Error.
*/
void (*disable_interrupt)(unsigned int irq);
/* Enable MC Error interrupt.
*
* Called from soft irq context after MC Error is logged.
*/
void (*enable_interrupt)(unsigned int irq);
/* Clear MC Error interrupt.
*
* Called from soft irq context during MC Error print throttle.
*/
void (*clear_interrupt)(unsigned int irq);
/* Log MC Error fault and clear interrupt source
*
* Called in soft irq context.
* As soon as interrupt status is cleared MC would be ready to
* hold next MC Error info.
*/
void (*log_mcerr_fault)(unsigned int irq);
/* Numeric fields that must be set by the different chips. */
unsigned int nr_clients;
/*
* This array lists a string description of each valid interrupt bit.
* It must be at least 32 entries long. Entries that are not valid
* interrupts should be left as NULL. Each entry should be at most 12
* characters long.
*/
const char **intr_descriptions;
struct mc_client *mc_clients;
};
#define client(_swgroup, _name, _swgid) \
{ .swgroup = _swgroup, .name = _name, .swgid = TEGRA_SWGROUP_##_swgid, }
#define dummy_client client("dummy", "dummy", INVALID)
#define MC_ERR(_sig, _msg, _flags, _stat_reg, _addr_reg) \
{ .sig = _sig, .msg = _msg, .flags = _flags, \
.stat_reg = _stat_reg, .addr_reg = _addr_reg }
#define MC_ERR_HI(_sig, _msg, _flags, _stat_reg, _addr_reg, _addr_hi_reg) \
{ .sig = _sig, .msg = _msg, .flags = (_flags | E_ADR_HI_REG), \
.stat_reg = _stat_reg, .addr_reg = _addr_reg, \
.addr_hi_reg = _addr_hi_reg}
#define MC_ERR_GSC(_sig, _msg, _flags, _stat_reg, _addr_reg, _addr_hi_reg) \
{ .sig = _sig, .msg = _msg, .flags = (_flags | E_GSC), \
.stat_reg = _stat_reg, .addr_reg = _addr_reg, \
.addr_hi_reg = _addr_hi_reg}
#define mcerr_pr(fmt, ...) \
do { \
if (!mcerr_silenced) { \
pr_err(fmt, ##__VA_ARGS__); \
} \
} while (0)
/*
* Error MMA tracking.
*/
#define MMA_HISTORY_SAMPLES 20
struct arb_emem_intr_info {
int arb_intr_mma;
u64 time;
spinlock_t lock;
};
typedef struct mcerr_ops *(*of_mcerr_init_fn)(struct device_node *);
#define MCERR_OF_DECLARE(name, compat, fn) \
_OF_DECLARE(mcerr, name, compat, fn, of_mcerr_init_fn)
#endif /* __MCERR_H */
|