17
17
#define PIPE_DETECT_LANE BIT(17)
18
18
#define LANE_SELECT GENMASK(3, 0)
19
19
20
+ #define ERR_INJ0_OFF 0x34
21
+ #define EINJ_VAL_DIFF GENMASK(28, 16)
22
+ #define EINJ_VC_NUM GENMASK(14, 12)
23
+ #define EINJ_TYPE_SHIFT 8
24
+ #define EINJ0_TYPE GENMASK(11, 8)
25
+ #define EINJ1_TYPE BIT(8)
26
+ #define EINJ2_TYPE GENMASK(9, 8)
27
+ #define EINJ3_TYPE GENMASK(10, 8)
28
+ #define EINJ4_TYPE GENMASK(10, 8)
29
+ #define EINJ5_TYPE BIT(8)
30
+ #define EINJ_COUNT GENMASK(7, 0)
31
+
32
+ #define ERR_INJ_ENABLE_REG 0x30
33
+
20
34
#define DWC_DEBUGFS_BUF_MAX 128
21
35
22
36
/**
@@ -33,6 +47,74 @@ struct dwc_pcie_rasdes_info {
33
47
struct mutex reg_event_lock ;
34
48
};
35
49
50
+ /**
51
+ * struct dwc_pcie_rasdes_priv - Stores file specific private data information
52
+ * @pci: Reference to the dw_pcie structure
53
+ * @idx: Index of specific file related information in array of structs
54
+ *
55
+ * All debugfs files will have this struct as its private data.
56
+ */
57
+ struct dwc_pcie_rasdes_priv {
58
+ struct dw_pcie * pci ;
59
+ int idx ;
60
+ };
61
+
62
+ /**
63
+ * struct dwc_pcie_err_inj - Store details about each error injection
64
+ * supported by DWC RAS DES
65
+ * @name: Name of the error that can be injected
66
+ * @err_inj_group: Group number to which the error belongs. The value
67
+ * can range from 0 to 5
68
+ * @err_inj_type: Each group can have multiple types of error
69
+ */
70
+ struct dwc_pcie_err_inj {
71
+ const char * name ;
72
+ u32 err_inj_group ;
73
+ u32 err_inj_type ;
74
+ };
75
+
76
+ static const struct dwc_pcie_err_inj err_inj_list [] = {
77
+ {"tx_lcrc" , 0x0 , 0x0 },
78
+ {"b16_crc_dllp" , 0x0 , 0x1 },
79
+ {"b16_crc_upd_fc" , 0x0 , 0x2 },
80
+ {"tx_ecrc" , 0x0 , 0x3 },
81
+ {"fcrc_tlp" , 0x0 , 0x4 },
82
+ {"parity_tsos" , 0x0 , 0x5 },
83
+ {"parity_skpos" , 0x0 , 0x6 },
84
+ {"rx_lcrc" , 0x0 , 0x8 },
85
+ {"rx_ecrc" , 0x0 , 0xb },
86
+ {"tlp_err_seq" , 0x1 , 0x0 },
87
+ {"ack_nak_dllp_seq" , 0x1 , 0x1 },
88
+ {"ack_nak_dllp" , 0x2 , 0x0 },
89
+ {"upd_fc_dllp" , 0x2 , 0x1 },
90
+ {"nak_dllp" , 0x2 , 0x2 },
91
+ {"inv_sync_hdr_sym" , 0x3 , 0x0 },
92
+ {"com_pad_ts1" , 0x3 , 0x1 },
93
+ {"com_pad_ts2" , 0x3 , 0x2 },
94
+ {"com_fts" , 0x3 , 0x3 },
95
+ {"com_idl" , 0x3 , 0x4 },
96
+ {"end_edb" , 0x3 , 0x5 },
97
+ {"stp_sdp" , 0x3 , 0x6 },
98
+ {"com_skp" , 0x3 , 0x7 },
99
+ {"posted_tlp_hdr" , 0x4 , 0x0 },
100
+ {"non_post_tlp_hdr" , 0x4 , 0x1 },
101
+ {"cmpl_tlp_hdr" , 0x4 , 0x2 },
102
+ {"posted_tlp_data" , 0x4 , 0x4 },
103
+ {"non_post_tlp_data" , 0x4 , 0x5 },
104
+ {"cmpl_tlp_data" , 0x4 , 0x6 },
105
+ {"duplicate_tlp" , 0x5 , 0x0 },
106
+ {"nullified_tlp" , 0x5 , 0x1 },
107
+ };
108
+
109
+ static const u32 err_inj_type_mask [] = {
110
+ EINJ0_TYPE ,
111
+ EINJ1_TYPE ,
112
+ EINJ2_TYPE ,
113
+ EINJ3_TYPE ,
114
+ EINJ4_TYPE ,
115
+ EINJ5_TYPE ,
116
+ };
117
+
36
118
static ssize_t lane_detect_read (struct file * file , char __user * buf ,
37
119
size_t count , loff_t * ppos )
38
120
{
@@ -96,6 +178,64 @@ static ssize_t rx_valid_write(struct file *file, const char __user *buf,
96
178
return lane_detect_write (file , buf , count , ppos );
97
179
}
98
180
181
+ static ssize_t err_inj_write (struct file * file , const char __user * buf ,
182
+ size_t count , loff_t * ppos )
183
+ {
184
+ struct dwc_pcie_rasdes_priv * pdata = file -> private_data ;
185
+ struct dw_pcie * pci = pdata -> pci ;
186
+ struct dwc_pcie_rasdes_info * rinfo = pci -> debugfs -> rasdes_info ;
187
+ u32 val , counter , vc_num , err_group , type_mask ;
188
+ int val_diff = 0 ;
189
+ char * kern_buf ;
190
+
191
+ err_group = err_inj_list [pdata -> idx ].err_inj_group ;
192
+ type_mask = err_inj_type_mask [err_group ];
193
+
194
+ kern_buf = memdup_user_nul (buf , count );
195
+ if (IS_ERR (kern_buf ))
196
+ return PTR_ERR (kern_buf );
197
+
198
+ if (err_group == 4 ) {
199
+ val = sscanf (kern_buf , "%u %d %u" , & counter , & val_diff , & vc_num );
200
+ if ((val != 3 ) || (val_diff < -4095 || val_diff > 4095 )) {
201
+ kfree (kern_buf );
202
+ return - EINVAL ;
203
+ }
204
+ } else if (err_group == 1 ) {
205
+ val = sscanf (kern_buf , "%u %d" , & counter , & val_diff );
206
+ if ((val != 2 ) || (val_diff < -4095 || val_diff > 4095 )) {
207
+ kfree (kern_buf );
208
+ return - EINVAL ;
209
+ }
210
+ } else {
211
+ val = kstrtou32 (kern_buf , 0 , & counter );
212
+ if (val ) {
213
+ kfree (kern_buf );
214
+ return val ;
215
+ }
216
+ }
217
+
218
+ val = dw_pcie_readl_dbi (pci , rinfo -> ras_cap_offset + ERR_INJ0_OFF + (0x4 * err_group ));
219
+ val &= ~(type_mask | EINJ_COUNT );
220
+ val |= ((err_inj_list [pdata -> idx ].err_inj_type << EINJ_TYPE_SHIFT ) & type_mask );
221
+ val |= FIELD_PREP (EINJ_COUNT , counter );
222
+
223
+ if (err_group == 1 || err_group == 4 ) {
224
+ val &= ~(EINJ_VAL_DIFF );
225
+ val |= FIELD_PREP (EINJ_VAL_DIFF , val_diff );
226
+ }
227
+ if (err_group == 4 ) {
228
+ val &= ~(EINJ_VC_NUM );
229
+ val |= FIELD_PREP (EINJ_VC_NUM , vc_num );
230
+ }
231
+
232
+ dw_pcie_writel_dbi (pci , rinfo -> ras_cap_offset + ERR_INJ0_OFF + (0x4 * err_group ), val );
233
+ dw_pcie_writel_dbi (pci , rinfo -> ras_cap_offset + ERR_INJ_ENABLE_REG , (0x1 << err_group ));
234
+
235
+ kfree (kern_buf );
236
+ return count ;
237
+ }
238
+
99
239
#define dwc_debugfs_create (name ) \
100
240
debugfs_create_file(#name, 0644, rasdes_debug, pci, \
101
241
&dbg_ ## name ## _fops)
@@ -110,6 +250,11 @@ static const struct file_operations dbg_ ## name ## _fops = { \
110
250
DWC_DEBUGFS_FOPS (lane_detect );
111
251
DWC_DEBUGFS_FOPS (rx_valid );
112
252
253
+ static const struct file_operations dwc_pcie_err_inj_ops = {
254
+ .open = simple_open ,
255
+ .write = err_inj_write ,
256
+ };
257
+
113
258
static void dwc_pcie_rasdes_debugfs_deinit (struct dw_pcie * pci )
114
259
{
115
260
struct dwc_pcie_rasdes_info * rinfo = pci -> debugfs -> rasdes_info ;
@@ -119,10 +264,11 @@ static void dwc_pcie_rasdes_debugfs_deinit(struct dw_pcie *pci)
119
264
120
265
static int dwc_pcie_rasdes_debugfs_init (struct dw_pcie * pci , struct dentry * dir )
121
266
{
122
- struct dentry * rasdes_debug ;
267
+ struct dentry * rasdes_debug , * rasdes_err_inj ;
123
268
struct dwc_pcie_rasdes_info * rasdes_info ;
269
+ struct dwc_pcie_rasdes_priv * priv_tmp ;
124
270
struct device * dev = pci -> dev ;
125
- int ras_cap ;
271
+ int ras_cap , i , ret ;
126
272
127
273
/*
128
274
* If a given SoC has no RAS DES capability, the following call is
@@ -141,6 +287,7 @@ static int dwc_pcie_rasdes_debugfs_init(struct dw_pcie *pci, struct dentry *dir)
141
287
142
288
/* Create subdirectories for Debug, Error Injection, Statistics. */
143
289
rasdes_debug = debugfs_create_dir ("rasdes_debug" , dir );
290
+ rasdes_err_inj = debugfs_create_dir ("rasdes_err_inj" , dir );
144
291
145
292
mutex_init (& rasdes_info -> reg_event_lock );
146
293
rasdes_info -> ras_cap_offset = ras_cap ;
@@ -150,7 +297,24 @@ static int dwc_pcie_rasdes_debugfs_init(struct dw_pcie *pci, struct dentry *dir)
150
297
dwc_debugfs_create (lane_detect );
151
298
dwc_debugfs_create (rx_valid );
152
299
300
+ /* Create debugfs files for Error Injection subdirectory. */
301
+ for (i = 0 ; i < ARRAY_SIZE (err_inj_list ); i ++ ) {
302
+ priv_tmp = devm_kzalloc (dev , sizeof (* priv_tmp ), GFP_KERNEL );
303
+ if (!priv_tmp ) {
304
+ ret = - ENOMEM ;
305
+ goto err_deinit ;
306
+ }
307
+
308
+ priv_tmp -> idx = i ;
309
+ priv_tmp -> pci = pci ;
310
+ debugfs_create_file (err_inj_list [i ].name , 0200 , rasdes_err_inj , priv_tmp ,
311
+ & dwc_pcie_err_inj_ops );
312
+ }
153
313
return 0 ;
314
+
315
+ err_deinit :
316
+ dwc_pcie_rasdes_debugfs_deinit (pci );
317
+ return ret ;
154
318
}
155
319
156
320
void dwc_pcie_debugfs_deinit (struct dw_pcie * pci )
0 commit comments