From: Bernard Metzler <bmt@xxxxxxxxxxxxxx> Signed-off-by: Bernard Metzler <bmt@xxxxxxxxxxxxxx> --- drivers/infiniband/sw/siw/siw_debug.c | 467 ++++++++++++++++++++++++++ drivers/infiniband/sw/siw/siw_debug.h | 87 +++++ 2 files changed, 554 insertions(+) create mode 100644 drivers/infiniband/sw/siw/siw_debug.c create mode 100644 drivers/infiniband/sw/siw/siw_debug.h diff --git a/drivers/infiniband/sw/siw/siw_debug.c b/drivers/infiniband/sw/siw/siw_debug.c new file mode 100644 index 000000000000..285206a6f599 --- /dev/null +++ b/drivers/infiniband/sw/siw/siw_debug.c @@ -0,0 +1,467 @@ +/* + * Software iWARP device driver + * + * Authors: Bernard Metzler <bmt@xxxxxxxxxxxxxx> + * Fredy Neeser + * + * Copyright (c) 2008-2018, IBM Corporation + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of IBM nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/errno.h> +#include <linux/types.h> +#include <net/tcp.h> +#include <linux/list.h> +#include <linux/debugfs.h> + +#include <rdma/iw_cm.h> +#include <rdma/ib_verbs.h> +#include <rdma/ib_smi.h> +#include <rdma/ib_user_verbs.h> + +#include "siw.h" +#include "siw_cm.h" +#include "siw_obj.h" + +#define FDENTRY(f) (f->f_path.dentry) + +static struct dentry *siw_debugfs; + +static ssize_t siw_show_qps(struct file *f, char __user *buf, size_t space, + loff_t *ppos) +{ + struct siw_device *sdev = FDENTRY(f)->d_inode->i_private; + struct list_head *pos, *tmp; + char *kbuf = NULL; + int len = 0, n, num_qp; + + if (*ppos) + goto out; + + kbuf = kmalloc(space, GFP_KERNEL); + if (!kbuf) + goto out; + + num_qp = atomic_read(&sdev->num_qp); + if (!num_qp) + goto out; + + len = snprintf(kbuf, space, "%s: %d QPs\n", sdev->base_dev.name, + num_qp); + if (len > space) { + len = space; + goto out; + } + space -= len; + n = snprintf(kbuf + len, space, + "%-11s%-4s%-4s%-6s%-6s%-5s%-5s%-7s%-7s%-5s%-15s%s\n", + "QP-ID", "cpu", "k/u", "State", "Ref's", "SQ", "RQ", + "IRQ", "ORQ", "s/r", "Sock", "CEP"); + + if (n > space) { + len += space; + goto out; + } + len += n; + space -= n; + + list_for_each_safe(pos, tmp, &sdev->qp_list) { + struct siw_qp *qp = list_entry(pos, struct siw_qp, devq); + + n = snprintf(kbuf + len, space, + "%-11d%-4d%-4s%-6d%-6d%-5d%-5d%d/%-5d%d/%-5d%d/%-3d0x%-13p0x%-18p\n", + QP_ID(qp), + qp->tx_cpu, + qp->kernel_verbs ? "k" : "u", + qp->attrs.state, + refcount_read(&qp->hdr.ref), + qp->attrs.sq_size, + qp->attrs.rq_size, + qp->irq_put - qp->irq_get, + qp->attrs.irq_size, + qp->orq_put - qp->orq_get, + qp->attrs.orq_size, + tx_wqe(qp)->wr_status != SIW_WR_IDLE ? 1 : 0, + rx_wqe(qp)->wr_status != SIW_WR_IDLE ? 1 : 0, + qp->attrs.sk, + qp->cep); + if (n < space) { + len += n; + space -= n; + } else { + len += space; + break; + } + } +out: + if (len) + len = simple_read_from_buffer(buf, len, ppos, kbuf, len); + + kfree(kbuf); + + return len; +}; + +static ssize_t siw_show_mrs(struct file *f, char __user *buf, size_t space, + loff_t *ppos) +{ + struct siw_device *sdev = FDENTRY(f)->d_inode->i_private; + struct list_head *pos, *tmp; + char *kbuf = NULL; + int len = 0, n, num_mr; + + if (*ppos) + goto out; + + kbuf = kmalloc(space, GFP_KERNEL); + if (!kbuf) + goto out; + + num_mr = atomic_read(&sdev->num_mr); + if (!num_mr) + goto out; + + len = snprintf(kbuf, space, "%s: %d MRs\n", sdev->base_dev.name, + num_mr); + if (len > space) { + len = space; + goto out; + } + space -= len; + + n = snprintf(kbuf + len, space, + "%-15s%-18s%-8s%-8s%-22s%-8s%-9s\n", + "MEM-ID", "PD", "STag", "Type", "size", "Ref's", "State"); + + if (n > space) { + len += space; + goto out; + } + len += n; + space -= n; + + list_for_each_safe(pos, tmp, &sdev->mr_list) { + struct siw_mr *mr = list_entry(pos, struct siw_mr, devq); + + n = snprintf(kbuf + len, space, + "%-15d%-18p0x%-8x%-8s0x%-20llx%-8d%-9s\n", + OBJ_ID(&mr->mem), mr->pd, mr->mem.hdr.id, + mr->mem_obj ? mr->mem.is_pbl ? "PBL":"UMEM":"KVA", + mr->mem.len, + refcount_read(&mr->mem.hdr.ref), + mr->mem.stag_valid ? "valid" : "invalid"); + if (n < space) { + len += n; + space -= n; + } else { + len += space; + break; + } + } +out: + if (len) + len = simple_read_from_buffer(buf, len, ppos, kbuf, len); + + kfree(kbuf); + + return len; +} + +static ssize_t siw_show_ceps(struct file *f, char __user *buf, size_t space, + loff_t *ppos) +{ + struct siw_device *sdev = FDENTRY(f)->d_inode->i_private; + struct list_head *pos, *tmp; + char *kbuf = NULL; + int len = 0, n, num_cep; + + if (*ppos) + goto out; + + kbuf = kmalloc(space, GFP_KERNEL); + if (!kbuf) + goto out; + + num_cep = atomic_read(&sdev->num_cep); + if (!num_cep) + goto out; + + len = snprintf(kbuf, space, "%s: %d CEPs\n", sdev->base_dev.name, + num_cep); + if (len > space) { + len = space; + goto out; + } + space -= len; + + n = snprintf(kbuf + len, space, + "%-20s%-6s%-6s%-9s%-5s%-3s%-4s%-21s%-9s\n", + "CEP", "State", "Ref's", "QP-ID", "LQ", "LC", "U", "Sock", + "CM-ID"); + + if (n > space) { + len += space; + goto out; + } + len += n; + space -= n; + + list_for_each_safe(pos, tmp, &sdev->cep_list) { + struct siw_cep *cep = list_entry(pos, struct siw_cep, devq); + + n = snprintf(kbuf + len, space, + "0x%-18p%-6d%-6d%-9d%-5s%-3s%-4d0x%-18p 0x%-16p\n", + cep, cep->state, + refcount_read(&cep->ref), + cep->qp ? QP_ID(cep->qp) : -1, + list_empty(&cep->listenq) ? "n" : "y", + cep->listen_cep ? "y" : "n", + cep->in_use, + cep->llp.sock, + cep->cm_id); + if (n < space) { + len += n; + space -= n; + } else { + len += space; + break; + } + } +out: + if (len) + len = simple_read_from_buffer(buf, len, ppos, kbuf, len); + + kfree(kbuf); + + return len; +} + +static ssize_t siw_show_stats(struct file *f, char __user *buf, size_t space, + loff_t *ppos) +{ + struct siw_device *sdev = FDENTRY(f)->d_inode->i_private; + char *kbuf = NULL; + int len = 0; + + if (*ppos) + goto out; + + kbuf = kmalloc(space, GFP_KERNEL); + if (!kbuf) + goto out; + + len = snprintf(kbuf, space, "Allocated SIW Objects:\n" + "Device %s (%s):\t" + "%s: %d, %s %d, %s: %d, %s: %d, %s: %d, %s: %d, %s: %d\n", + sdev->base_dev.name, + sdev->netdev->flags & IFF_UP ? "IFF_UP" : "IFF_DOWN", + "CXs", atomic_read(&sdev->num_ctx), + "PDs", atomic_read(&sdev->num_pd), + "QPs", atomic_read(&sdev->num_qp), + "CQs", atomic_read(&sdev->num_cq), + "SRQs", atomic_read(&sdev->num_srq), + "MRs", atomic_read(&sdev->num_mr), + "CEPs", atomic_read(&sdev->num_cep)); + if (len > space) + len = space; +out: + if (len) + len = simple_read_from_buffer(buf, len, ppos, kbuf, len); + + kfree(kbuf); + return len; +} + +static const struct file_operations siw_qp_debug_fops = { + .owner = THIS_MODULE, + .read = siw_show_qps +}; + +static const struct file_operations siw_mr_debug_fops = { + .owner = THIS_MODULE, + .read = siw_show_mrs +}; + +static const struct file_operations siw_cep_debug_fops = { + .owner = THIS_MODULE, + .read = siw_show_ceps +}; + +static const struct file_operations siw_stats_debug_fops = { + .owner = THIS_MODULE, + .read = siw_show_stats +}; + +void siw_debugfs_add_device(struct siw_device *sdev) +{ + struct dentry *entry; + + if (!siw_debugfs) + return; + + sdev->debugfs = debugfs_create_dir(sdev->base_dev.name, siw_debugfs); + if (sdev->debugfs) { + entry = debugfs_create_file("qp", 0400, sdev->debugfs, + (void *)sdev, &siw_qp_debug_fops); + if (!entry) + siw_dbg(sdev, "could not create 'qp' entry\n"); + + entry = debugfs_create_file("cep", 0400, sdev->debugfs, + (void *)sdev, &siw_cep_debug_fops); + if (!entry) + siw_dbg(sdev, "could not create 'cep' entry\n"); + + entry = debugfs_create_file("mr", 0400, sdev->debugfs, + (void *)sdev, &siw_mr_debug_fops); + if (!entry) + siw_dbg(sdev, "could not create 'qp' entry\n"); + + entry = debugfs_create_file("stats", 0400, sdev->debugfs, + (void *)sdev, + &siw_stats_debug_fops); + if (!entry) + siw_dbg(sdev, "could not create 'stats' entry\n"); + } +} + +void siw_debugfs_del_device(struct siw_device *sdev) +{ + debugfs_remove_recursive(sdev->debugfs); + sdev->debugfs = NULL; +} + +void siw_debug_init(void) +{ + siw_debugfs = debugfs_create_dir("siw", NULL); + + if (!siw_debugfs || siw_debugfs == ERR_PTR(-ENODEV)) { + pr_warn("SIW: could not init debugfs\n"); + siw_debugfs = NULL; + } +} + +void siw_debugfs_delete(void) +{ + debugfs_remove_recursive(siw_debugfs); + siw_debugfs = NULL; +} + +void siw_print_hdr(union iwarp_hdr *hdr, int qp_id, char *string) +{ + enum rdma_opcode op = __rdmap_opcode(&hdr->ctrl); + u16 mpa_len = be16_to_cpu(hdr->ctrl.mpa_len); + + switch (op) { + + case RDMAP_RDMA_WRITE: + pr_info("siw: [QP %d]: %s(WRITE, DDP len %d): %08x %016llx\n", + qp_id, string, ddp_data_len(op, mpa_len), + hdr->rwrite.sink_stag, hdr->rwrite.sink_to); + break; + + case RDMAP_RDMA_READ_REQ: + pr_info("siw: [QP %d]: %s(RREQ, DDP len %d): %08x %08x %08x %08x %016llx %08x %08x %016llx\n", + qp_id, string, + ddp_data_len(op, mpa_len), + be32_to_cpu(hdr->rreq.ddp_qn), + be32_to_cpu(hdr->rreq.ddp_msn), + be32_to_cpu(hdr->rreq.ddp_mo), + be32_to_cpu(hdr->rreq.sink_stag), + be64_to_cpu(hdr->rreq.sink_to), + be32_to_cpu(hdr->rreq.read_size), + be32_to_cpu(hdr->rreq.source_stag), + be64_to_cpu(hdr->rreq.source_to)); + + break; + + case RDMAP_RDMA_READ_RESP: + pr_info("siw: [QP %d]: %s(RRESP, DDP len %d): %08x %016llx\n", + qp_id, string, ddp_data_len(op, mpa_len), + be32_to_cpu(hdr->rresp.sink_stag), + be64_to_cpu(hdr->rresp.sink_to)); + break; + + case RDMAP_SEND: + pr_info("siw: [QP %d]: %s(SEND, DDP len %d): %08x %08x %08x\n", + qp_id, string, ddp_data_len(op, mpa_len), + be32_to_cpu(hdr->send.ddp_qn), + be32_to_cpu(hdr->send.ddp_msn), + be32_to_cpu(hdr->send.ddp_mo)); + break; + + case RDMAP_SEND_INVAL: + pr_info("siw: [QP %d]: %s(S_INV, DDP len %d): %08x %08x %08x %08x\n", + qp_id, string, ddp_data_len(op, mpa_len), + be32_to_cpu(hdr->send_inv.inval_stag), + be32_to_cpu(hdr->send_inv.ddp_qn), + be32_to_cpu(hdr->send_inv.ddp_msn), + be32_to_cpu(hdr->send_inv.ddp_mo)); + break; + + case RDMAP_SEND_SE: + pr_info("siw: [QP %d]: %s(S_SE, DDP len %d): %08x %08x %08x\n", + qp_id, string, ddp_data_len(op, mpa_len), + be32_to_cpu(hdr->send.ddp_qn), + be32_to_cpu(hdr->send.ddp_msn), + be32_to_cpu(hdr->send.ddp_mo)); + break; + + case RDMAP_SEND_SE_INVAL: + pr_info("siw: [QP %d]: %s(S_SE_INV, DDP len %d): %08x %08x %08x %08x\n", + qp_id, string, ddp_data_len(op, mpa_len), + be32_to_cpu(hdr->send_inv.inval_stag), + be32_to_cpu(hdr->send_inv.ddp_qn), + be32_to_cpu(hdr->send_inv.ddp_msn), + be32_to_cpu(hdr->send_inv.ddp_mo)); + break; + + case RDMAP_TERMINATE: + pr_info("siw: [QP %d]: %s(TERM, DDP len %d):\n", qp_id, string, + ddp_data_len(op, mpa_len)); + break; + + default: + pr_info("siw: [QP %d]: %s (undefined opcode %d)", qp_id, string, + op); + break; + } +} + +char ib_qp_state_to_string[IB_QPS_ERR+1][sizeof "RESET"] = { + [IB_QPS_RESET] = "RESET", + [IB_QPS_INIT] = "INIT", + [IB_QPS_RTR] = "RTR", + [IB_QPS_RTS] = "RTS", + [IB_QPS_SQD] = "SQD", + [IB_QPS_SQE] = "SQE", + [IB_QPS_ERR] = "ERR" +}; diff --git a/drivers/infiniband/sw/siw/siw_debug.h b/drivers/infiniband/sw/siw/siw_debug.h new file mode 100644 index 000000000000..40041b938865 --- /dev/null +++ b/drivers/infiniband/sw/siw/siw_debug.h @@ -0,0 +1,87 @@ +/* + * Software iWARP device driver + * + * Authors: Bernard Metzler <bmt@xxxxxxxxxxxxxx> + * Fredy Neeser + * + * + * Copyright (c) 2008-2018, IBM Corporation + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of IBM nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _SIW_DEBUG_H +#define _SIW_DEBUG_H + +#include <linux/uaccess.h> +#include <linux/hardirq.h> /* in_interrupt() */ + +struct siw_device; +struct siw_iwarp_rx; +union iwarp_hdr; + +extern void siw_debug_init(void); +extern void siw_debugfs_add_device(struct siw_device *dev); +extern void siw_debugfs_del_device(struct siw_device *dev); +extern void siw_debugfs_delete(void); + +extern void siw_print_hdr(union iwarp_hdr *hdr, int id, char *msg); +extern void siw_print_qp_attr_mask(enum ib_qp_attr_mask mask, char *msg); +extern char ib_qp_state_to_string[IB_QPS_ERR+1][sizeof "RESET"]; + +#ifndef refcount_read +#define refcount_read(x) atomic_read(x.refcount.refs) +#endif + +#define siw_dbg(ddev, fmt, ...) \ + dev_dbg(&(ddev)->base_dev.dev, "cpu%2d %s: " fmt, smp_processor_id(),\ + __func__, ##__VA_ARGS__) + +#define siw_dbg_qp(qp, fmt, ...) \ + siw_dbg(qp->hdr.sdev, "[QP %d]: " fmt, QP_ID(qp), ##__VA_ARGS__) + +#define siw_dbg_cep(cep, fmt, ...) \ + siw_dbg(cep->sdev, "[CEP 0x%p]: " fmt, cep, ##__VA_ARGS__) + +#define siw_dbg_obj(obj, fmt, ...) \ + siw_dbg(obj->hdr.sdev, "[OBJ ID %d]: " fmt, obj->hdr.id, ##__VA_ARGS__) + +#ifdef DEBUG_HDR + +#define siw_dprint_hdr(hdr, qpn, msg) siw_print_hdr(hdr, qpn, msg) + +#else + +#define siw_dprint_hdr(hdr, qpn, msg) do { } while (0) + +#endif + +#endif -- 2.17.2