]> Git Repo - linux.git/blob - drivers/infiniband/hw/hfi1/fault.c
Linux 6.14-rc3
[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 };
207
208 void hfi1_fault_exit_debugfs(struct hfi1_ibdev *ibd)
209 {
210         if (ibd->fault)
211                 debugfs_remove_recursive(ibd->fault->dir);
212         kfree(ibd->fault);
213         ibd->fault = NULL;
214 }
215
216 int hfi1_fault_init_debugfs(struct hfi1_ibdev *ibd)
217 {
218         struct dentry *parent = ibd->hfi1_ibdev_dbg;
219         struct dentry *fault_dir;
220
221         ibd->fault = kzalloc(sizeof(*ibd->fault), GFP_KERNEL);
222         if (!ibd->fault)
223                 return -ENOMEM;
224
225         ibd->fault->attr.interval = 1;
226         ibd->fault->attr.require_end = ULONG_MAX;
227         ibd->fault->attr.stacktrace_depth = 32;
228         ibd->fault->attr.dname = NULL;
229         ibd->fault->attr.verbose = 0;
230         ibd->fault->enable = false;
231         ibd->fault->opcode = false;
232         ibd->fault->fault_skip = 0;
233         ibd->fault->skip = 0;
234         ibd->fault->direction = HFI1_FAULT_DIR_TXRX;
235         ibd->fault->suppress_err = false;
236         bitmap_zero(ibd->fault->opcodes,
237                     sizeof(ibd->fault->opcodes) * BITS_PER_BYTE);
238
239         fault_dir =
240                 fault_create_debugfs_attr("fault", parent, &ibd->fault->attr);
241         if (IS_ERR(fault_dir)) {
242                 kfree(ibd->fault);
243                 ibd->fault = NULL;
244                 return -ENOENT;
245         }
246         ibd->fault->dir = fault_dir;
247
248         debugfs_create_file("fault_stats", 0444, fault_dir, ibd,
249                             &_fault_stats_file_ops);
250         debugfs_create_bool("enable", 0600, fault_dir, &ibd->fault->enable);
251         debugfs_create_bool("suppress_err", 0600, fault_dir,
252                             &ibd->fault->suppress_err);
253         debugfs_create_bool("opcode_mode", 0600, fault_dir,
254                             &ibd->fault->opcode);
255         debugfs_create_file("opcodes", 0600, fault_dir, ibd->fault,
256                             &__fault_opcodes_fops);
257         debugfs_create_u64("skip_pkts", 0600, fault_dir,
258                            &ibd->fault->fault_skip);
259         debugfs_create_u64("skip_usec", 0600, fault_dir,
260                            &ibd->fault->fault_skip_usec);
261         debugfs_create_u8("direction", 0600, fault_dir, &ibd->fault->direction);
262
263         return 0;
264 }
265
266 bool hfi1_dbg_fault_suppress_err(struct hfi1_ibdev *ibd)
267 {
268         if (ibd->fault)
269                 return ibd->fault->suppress_err;
270         return false;
271 }
272
273 static bool __hfi1_should_fault(struct hfi1_ibdev *ibd, u32 opcode,
274                                 u8 direction)
275 {
276         bool ret = false;
277
278         if (!ibd->fault || !ibd->fault->enable)
279                 return false;
280         if (!(ibd->fault->direction & direction))
281                 return false;
282         if (ibd->fault->opcode) {
283                 if (bitmap_empty(ibd->fault->opcodes,
284                                  (sizeof(ibd->fault->opcodes) *
285                                   BITS_PER_BYTE)))
286                         return false;
287                 if (!(test_bit(opcode, ibd->fault->opcodes)))
288                         return false;
289         }
290         if (ibd->fault->fault_skip_usec &&
291             time_before(jiffies, ibd->fault->skip_usec))
292                 return false;
293         if (ibd->fault->fault_skip && ibd->fault->skip) {
294                 ibd->fault->skip--;
295                 return false;
296         }
297         ret = should_fail(&ibd->fault->attr, 1);
298         if (ret) {
299                 ibd->fault->skip = ibd->fault->fault_skip;
300                 ibd->fault->skip_usec = jiffies +
301                         usecs_to_jiffies(ibd->fault->fault_skip_usec);
302         }
303         return ret;
304 }
305
306 bool hfi1_dbg_should_fault_tx(struct rvt_qp *qp, u32 opcode)
307 {
308         struct hfi1_ibdev *ibd = to_idev(qp->ibqp.device);
309
310         if (__hfi1_should_fault(ibd, opcode, HFI1_FAULT_DIR_TX)) {
311                 trace_hfi1_fault_opcode(qp, opcode);
312                 ibd->fault->n_txfaults[opcode]++;
313                 return true;
314         }
315         return false;
316 }
317
318 bool hfi1_dbg_should_fault_rx(struct hfi1_packet *packet)
319 {
320         struct hfi1_ibdev *ibd = &packet->rcd->dd->verbs_dev;
321
322         if (__hfi1_should_fault(ibd, packet->opcode, HFI1_FAULT_DIR_RX)) {
323                 trace_hfi1_fault_packet(packet);
324                 ibd->fault->n_rxfaults[packet->opcode]++;
325                 return true;
326         }
327         return false;
328 }
This page took 0.050935 seconds and 4 git commands to generate.