1717#define PIPE_DETECT_LANE BIT(17)
1818#define LANE_SELECT GENMASK(3, 0)
1919
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+
2034#define DWC_DEBUGFS_BUF_MAX 128
2135
2236/**
@@ -33,6 +47,74 @@ struct dwc_pcie_rasdes_info {
3347 struct mutex reg_event_lock ;
3448};
3549
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+
36118static ssize_t lane_detect_read (struct file * file , char __user * buf ,
37119 size_t count , loff_t * ppos )
38120{
@@ -96,6 +178,64 @@ static ssize_t rx_valid_write(struct file *file, const char __user *buf,
96178 return lane_detect_write (file , buf , count , ppos );
97179}
98180
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+
99239#define dwc_debugfs_create (name ) \
100240debugfs_create_file(#name, 0644, rasdes_debug, pci, \
101241 &dbg_ ## name ## _fops)
@@ -110,6 +250,11 @@ static const struct file_operations dbg_ ## name ## _fops = { \
110250DWC_DEBUGFS_FOPS (lane_detect );
111251DWC_DEBUGFS_FOPS (rx_valid );
112252
253+ static const struct file_operations dwc_pcie_err_inj_ops = {
254+ .open = simple_open ,
255+ .write = err_inj_write ,
256+ };
257+
113258static void dwc_pcie_rasdes_debugfs_deinit (struct dw_pcie * pci )
114259{
115260 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)
119264
120265static int dwc_pcie_rasdes_debugfs_init (struct dw_pcie * pci , struct dentry * dir )
121266{
122- struct dentry * rasdes_debug ;
267+ struct dentry * rasdes_debug , * rasdes_err_inj ;
123268 struct dwc_pcie_rasdes_info * rasdes_info ;
269+ struct dwc_pcie_rasdes_priv * priv_tmp ;
124270 struct device * dev = pci -> dev ;
125- int ras_cap ;
271+ int ras_cap , i , ret ;
126272
127273 /*
128274 * 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)
141287
142288 /* Create subdirectories for Debug, Error Injection, Statistics. */
143289 rasdes_debug = debugfs_create_dir ("rasdes_debug" , dir );
290+ rasdes_err_inj = debugfs_create_dir ("rasdes_err_inj" , dir );
144291
145292 mutex_init (& rasdes_info -> reg_event_lock );
146293 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)
150297 dwc_debugfs_create (lane_detect );
151298 dwc_debugfs_create (rx_valid );
152299
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+ }
153313 return 0 ;
314+
315+ err_deinit :
316+ dwc_pcie_rasdes_debugfs_deinit (pci );
317+ return ret ;
154318}
155319
156320void dwc_pcie_debugfs_deinit (struct dw_pcie * pci )
0 commit comments