329 lines · c
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause2/*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 20static 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 29static 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 39static void _fault_stats_seq_stop(struct seq_file *s, void *v)40{41}42 43static 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 79DEBUGFS_SEQ_FILE_OPS(fault_stats);80DEBUGFS_SEQ_FILE_OPEN(fault_stats);81DEBUGFS_FILE_OPS(fault_stats);82 83static 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 89static 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 else150 set_bit(i, fault->opcodes);151 }152 if (!end)153 break;154 }155 ret = len;156 157 debugfs_file_put(file->f_path.dentry);158free_data:159 kfree(data);160 return ret;161}162 163static 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 else187 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);196free_data:197 kfree(data);198 return ret;199}200 201static 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 208void 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 216int 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 266bool 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 273static 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 306bool 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 318bool 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}329