]> Git Repo - J-linux.git/blob - drivers/infiniband/hw/hfi1/fault.c
Merge tag 'amd-drm-next-6.5-2023-06-09' of https://gitlab.freedesktop.org/agd5f/linux...
[J-linux.git] / drivers / infiniband / hw / hfi1 / fault.c
1 // SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
2 /*
3  * Copyright(c) 2018 Intel Corporation.
4  */
5
6 #include <linux/debugfs.h>
7 #include <linux/seq_file.h>
8 #include <linux/kernel.h>
9 #include <linux/types.h>
10 #include <linux/bitmap.h>
11
12 #include "debugfs.h"
13 #include "fault.h"
14 #include "trace.h"
15
16 #define HFI1_FAULT_DIR_TX   BIT(0)
17 #define HFI1_FAULT_DIR_RX   BIT(1)
18 #define HFI1_FAULT_DIR_TXRX (HFI1_FAULT_DIR_TX | HFI1_FAULT_DIR_RX)
19
20 static void *_fault_stats_seq_start(struct seq_file *s, loff_t *pos)
21 {
22         struct hfi1_opcode_stats_perctx *opstats;
23
24         if (*pos >= ARRAY_SIZE(opstats->stats))
25                 return NULL;
26         return pos;
27 }
28
29 static void *_fault_stats_seq_next(struct seq_file *s, void *v, loff_t *pos)
30 {
31         struct hfi1_opcode_stats_perctx *opstats;
32
33         ++*pos;
34         if (*pos >= ARRAY_SIZE(opstats->stats))
35                 return NULL;
36         return pos;
37 }
38
39 static void _fault_stats_seq_stop(struct seq_file *s, void *v)
40 {
41 }
42
43 static int _fault_stats_seq_show(struct seq_file *s, void *v)
44 {
45         loff_t *spos = v;
46         loff_t i = *spos, j;
47         u64 n_packets = 0, n_bytes = 0;
48         struct hfi1_ibdev *ibd = (struct hfi1_ibdev *)s->private;
49         struct hfi1_devdata *dd = dd_from_dev(ibd);
50         struct hfi1_ctxtdata *rcd;
51
52         for (j = 0; j < dd->first_dyn_alloc_ctxt; j++) {
53                 rcd = hfi1_rcd_get_by_index(dd, j);
54                 if (rcd) {
55                         n_packets += rcd->opstats->stats[i].n_packets;
56                         n_bytes += rcd->opstats->stats[i].n_bytes;
57                 }
58                 hfi1_rcd_put(rcd);
59         }
60         for_each_possible_cpu(j) {
61                 struct hfi1_opcode_stats_perctx *sp =
62                         per_cpu_ptr(dd->tx_opstats, j);
63
64                 n_packets += sp->stats[i].n_packets;
65                 n_bytes += sp->stats[i].n_bytes;
66         }
67         if (!n_packets && !n_bytes)
68                 return SEQ_SKIP;
69         if (!ibd->fault->n_rxfaults[i] && !ibd->fault->n_txfaults[i])
70                 return SEQ_SKIP;
71         seq_printf(s, "%02llx %llu/%llu (faults rx:%llu faults: tx:%llu)\n", i,
72                    (unsigned long long)n_packets,
73                    (unsigned long long)n_bytes,
74                    (unsigned long long)ibd->fault->n_rxfaults[i],
75                    (unsigned long long)ibd->fault->n_txfaults[i]);
76         return 0;
77 }
78
79 DEBUGFS_SEQ_FILE_OPS(fault_stats);
80 DEBUGFS_SEQ_FILE_OPEN(fault_stats);
81 DEBUGFS_FILE_OPS(fault_stats);
82
83 static int fault_opcodes_open(struct inode *inode, struct file *file)
84 {
85         file->private_data = inode->i_private;
86         return nonseekable_open(inode, file);
87 }
88
89 static ssize_t fault_opcodes_write(struct file *file, const char __user *buf,
90                                    size_t len, loff_t *pos)
91 {
92         ssize_t ret = 0;
93         /* 1280 = 256 opcodes * 4 chars/opcode + 255 commas + NULL */
94         size_t copy, datalen = 1280;
95         char *data, *token, *ptr, *end;
96         struct fault *fault = file->private_data;
97
98         data = kcalloc(datalen, sizeof(*data), GFP_KERNEL);
99         if (!data)
100                 return -ENOMEM;
101         copy = min(len, datalen - 1);
102         if (copy_from_user(data, buf, copy)) {
103                 ret = -EFAULT;
104                 goto free_data;
105         }
106
107         ret = debugfs_file_get(file->f_path.dentry);
108         if (unlikely(ret))
109                 goto free_data;
110         ptr = data;
111         token = ptr;
112         for (ptr = data; *ptr; ptr = end + 1, token = ptr) {
113                 char *dash;
114                 unsigned long range_start, range_end, i;
115                 bool remove = false;
116                 unsigned long bound = 1U << BITS_PER_BYTE;
117
118                 end = strchr(ptr, ',');
119                 if (end)
120                         *end = '\0';
121                 if (token[0] == '-') {
122                         remove = true;
123                         token++;
124                 }
125                 dash = strchr(token, '-');
126                 if (dash)
127                         *dash = '\0';
128                 if (kstrtoul(token, 0, &range_start))
129                         break;
130                 if (dash) {
131                         token = dash + 1;
132                         if (kstrtoul(token, 0, &range_end))
133                                 break;
134                 } else {
135                         range_end = range_start;
136                 }
137                 if (range_start == range_end && range_start == -1UL) {
138                         bitmap_zero(fault->opcodes, sizeof(fault->opcodes) *
139                                     BITS_PER_BYTE);
140                         break;
141                 }
142                 /* Check the inputs */
143                 if (range_start >= bound || range_end >= bound)
144                         break;
145
146                 for (i = range_start; i <= range_end; i++) {
147                         if (remove)
148                                 clear_bit(i, fault->opcodes);
149                         else
150                                 set_bit(i, fault->opcodes);
151                 }
152                 if (!end)
153                         break;
154         }
155         ret = len;
156
157         debugfs_file_put(file->f_path.dentry);
158 free_data:
159         kfree(data);
160         return ret;
161 }
162
163 static ssize_t fault_opcodes_read(struct file *file, char __user *buf,
164                                   size_t len, loff_t *pos)
165 {
166         ssize_t ret = 0;
167         char *data;
168         size_t datalen = 1280, size = 0; /* see fault_opcodes_write() */
169         unsigned long bit = 0, zero = 0;
170         struct fault *fault = file->private_data;
171         size_t bitsize = sizeof(fault->opcodes) * BITS_PER_BYTE;
172
173         data = kcalloc(datalen, sizeof(*data), GFP_KERNEL);
174         if (!data)
175                 return -ENOMEM;
176         ret = debugfs_file_get(file->f_path.dentry);
177         if (unlikely(ret))
178                 goto free_data;
179         bit = find_first_bit(fault->opcodes, bitsize);
180         while (bit < bitsize) {
181                 zero = find_next_zero_bit(fault->opcodes, bitsize, bit);
182                 if (zero - 1 != bit)
183                         size += scnprintf(data + size,
184                                          datalen - size - 1,
185                                          "0x%lx-0x%lx,", bit, zero - 1);
186                 else
187                         size += scnprintf(data + size,
188                                          datalen - size - 1, "0x%lx,",
189                                          bit);
190                 bit = find_next_bit(fault->opcodes, bitsize, zero);
191         }
192         debugfs_file_put(file->f_path.dentry);
193         data[size - 1] = '\n';
194         data[size] = '\0';
195         ret = simple_read_from_buffer(buf, len, pos, data, size);
196 free_data:
197         kfree(data);
198         return ret;
199 }
200
201 static const struct file_operations __fault_opcodes_fops = {
202         .owner = THIS_MODULE,
203         .open = fault_opcodes_open,
204         .read = fault_opcodes_read,
205         .write = fault_opcodes_write,
206         .llseek = no_llseek
207 };
208
209 void hfi1_fault_exit_debugfs(struct hfi1_ibdev *ibd)
210 {
211         if (ibd->fault)
212                 debugfs_remove_recursive(ibd->fault->dir);
213         kfree(ibd->fault);
214         ibd->fault = NULL;
215 }
216
217 int hfi1_fault_init_debugfs(struct hfi1_ibdev *ibd)
218 {
219         struct dentry *parent = ibd->hfi1_ibdev_dbg;
220         struct dentry *fault_dir;
221
222         ibd->fault = kzalloc(sizeof(*ibd->fault), GFP_KERNEL);
223         if (!ibd->fault)
224                 return -ENOMEM;
225
226         ibd->fault->attr.interval = 1;
227         ibd->fault->attr.require_end = ULONG_MAX;
228         ibd->fault->attr.stacktrace_depth = 32;
229         ibd->fault->attr.dname = NULL;
230         ibd->fault->attr.verbose = 0;
231         ibd->fault->enable = false;
232         ibd->fault->opcode = false;
233         ibd->fault->fault_skip = 0;
234         ibd->fault->skip = 0;
235         ibd->fault->direction = HFI1_FAULT_DIR_TXRX;
236         ibd->fault->suppress_err = false;
237         bitmap_zero(ibd->fault->opcodes,
238                     sizeof(ibd->fault->opcodes) * BITS_PER_BYTE);
239
240         fault_dir =
241                 fault_create_debugfs_attr("fault", parent, &ibd->fault->attr);
242         if (IS_ERR(fault_dir)) {
243                 kfree(ibd->fault);
244                 ibd->fault = NULL;
245                 return -ENOENT;
246         }
247         ibd->fault->dir = fault_dir;
248
249         debugfs_create_file("fault_stats", 0444, fault_dir, ibd,
250                             &_fault_stats_file_ops);
251         debugfs_create_bool("enable", 0600, fault_dir, &ibd->fault->enable);
252         debugfs_create_bool("suppress_err", 0600, fault_dir,
253                             &ibd->fault->suppress_err);
254         debugfs_create_bool("opcode_mode", 0600, fault_dir,
255                             &ibd->fault->opcode);
256         debugfs_create_file("opcodes", 0600, fault_dir, ibd->fault,
257                             &__fault_opcodes_fops);
258         debugfs_create_u64("skip_pkts", 0600, fault_dir,
259                            &ibd->fault->fault_skip);
260         debugfs_create_u64("skip_usec", 0600, fault_dir,
261                            &ibd->fault->fault_skip_usec);
262         debugfs_create_u8("direction", 0600, fault_dir, &ibd->fault->direction);
263
264         return 0;
265 }
266
267 bool hfi1_dbg_fault_suppress_err(struct hfi1_ibdev *ibd)
268 {
269         if (ibd->fault)
270                 return ibd->fault->suppress_err;
271         return false;
272 }
273
274 static bool __hfi1_should_fault(struct hfi1_ibdev *ibd, u32 opcode,
275                                 u8 direction)
276 {
277         bool ret = false;
278
279         if (!ibd->fault || !ibd->fault->enable)
280                 return false;
281         if (!(ibd->fault->direction & direction))
282                 return false;
283         if (ibd->fault->opcode) {
284                 if (bitmap_empty(ibd->fault->opcodes,
285                                  (sizeof(ibd->fault->opcodes) *
286                                   BITS_PER_BYTE)))
287                         return false;
288                 if (!(test_bit(opcode, ibd->fault->opcodes)))
289                         return false;
290         }
291         if (ibd->fault->fault_skip_usec &&
292             time_before(jiffies, ibd->fault->skip_usec))
293                 return false;
294         if (ibd->fault->fault_skip && ibd->fault->skip) {
295                 ibd->fault->skip--;
296                 return false;
297         }
298         ret = should_fail(&ibd->fault->attr, 1);
299         if (ret) {
300                 ibd->fault->skip = ibd->fault->fault_skip;
301                 ibd->fault->skip_usec = jiffies +
302                         usecs_to_jiffies(ibd->fault->fault_skip_usec);
303         }
304         return ret;
305 }
306
307 bool hfi1_dbg_should_fault_tx(struct rvt_qp *qp, u32 opcode)
308 {
309         struct hfi1_ibdev *ibd = to_idev(qp->ibqp.device);
310
311         if (__hfi1_should_fault(ibd, opcode, HFI1_FAULT_DIR_TX)) {
312                 trace_hfi1_fault_opcode(qp, opcode);
313                 ibd->fault->n_txfaults[opcode]++;
314                 return true;
315         }
316         return false;
317 }
318
319 bool hfi1_dbg_should_fault_rx(struct hfi1_packet *packet)
320 {
321         struct hfi1_ibdev *ibd = &packet->rcd->dd->verbs_dev;
322
323         if (__hfi1_should_fault(ibd, packet->opcode, HFI1_FAULT_DIR_RX)) {
324                 trace_hfi1_fault_packet(packet);
325                 ibd->fault->n_rxfaults[packet->opcode]++;
326                 return true;
327         }
328         return false;
329 }
This page took 0.049974 seconds and 4 git commands to generate.