123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611 |
- /*
- * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
- *
- * 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
- * OpenIB.org 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.
- *
- * 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/module.h>
- #include <linux/debugfs.h>
- #include <linux/mlx5/qp.h>
- #include <linux/mlx5/cq.h>
- #include <linux/mlx5/driver.h>
- #include "mlx5_core.h"
- enum {
- QP_PID,
- QP_STATE,
- QP_XPORT,
- QP_MTU,
- QP_N_RECV,
- QP_RECV_SZ,
- QP_N_SEND,
- QP_LOG_PG_SZ,
- QP_RQPN,
- };
- static char *qp_fields[] = {
- [QP_PID] = "pid",
- [QP_STATE] = "state",
- [QP_XPORT] = "transport",
- [QP_MTU] = "mtu",
- [QP_N_RECV] = "num_recv",
- [QP_RECV_SZ] = "rcv_wqe_sz",
- [QP_N_SEND] = "num_send",
- [QP_LOG_PG_SZ] = "log2_page_sz",
- [QP_RQPN] = "remote_qpn",
- };
- enum {
- EQ_NUM_EQES,
- EQ_INTR,
- EQ_LOG_PG_SZ,
- };
- static char *eq_fields[] = {
- [EQ_NUM_EQES] = "num_eqes",
- [EQ_INTR] = "intr",
- [EQ_LOG_PG_SZ] = "log_page_size",
- };
- enum {
- CQ_PID,
- CQ_NUM_CQES,
- CQ_LOG_PG_SZ,
- };
- static char *cq_fields[] = {
- [CQ_PID] = "pid",
- [CQ_NUM_CQES] = "num_cqes",
- [CQ_LOG_PG_SZ] = "log_page_size",
- };
- struct dentry *mlx5_debugfs_root;
- EXPORT_SYMBOL(mlx5_debugfs_root);
- void mlx5_register_debugfs(void)
- {
- mlx5_debugfs_root = debugfs_create_dir("mlx5", NULL);
- if (IS_ERR_OR_NULL(mlx5_debugfs_root))
- mlx5_debugfs_root = NULL;
- }
- void mlx5_unregister_debugfs(void)
- {
- debugfs_remove(mlx5_debugfs_root);
- }
- int mlx5_qp_debugfs_init(struct mlx5_core_dev *dev)
- {
- if (!mlx5_debugfs_root)
- return 0;
- atomic_set(&dev->num_qps, 0);
- dev->priv.qp_debugfs = debugfs_create_dir("QPs", dev->priv.dbg_root);
- if (!dev->priv.qp_debugfs)
- return -ENOMEM;
- return 0;
- }
- void mlx5_qp_debugfs_cleanup(struct mlx5_core_dev *dev)
- {
- if (!mlx5_debugfs_root)
- return;
- debugfs_remove_recursive(dev->priv.qp_debugfs);
- }
- int mlx5_eq_debugfs_init(struct mlx5_core_dev *dev)
- {
- if (!mlx5_debugfs_root)
- return 0;
- dev->priv.eq_debugfs = debugfs_create_dir("EQs", dev->priv.dbg_root);
- if (!dev->priv.eq_debugfs)
- return -ENOMEM;
- return 0;
- }
- void mlx5_eq_debugfs_cleanup(struct mlx5_core_dev *dev)
- {
- if (!mlx5_debugfs_root)
- return;
- debugfs_remove_recursive(dev->priv.eq_debugfs);
- }
- static ssize_t average_read(struct file *filp, char __user *buf, size_t count,
- loff_t *pos)
- {
- struct mlx5_cmd_stats *stats;
- u64 field = 0;
- int ret;
- char tbuf[22];
- if (*pos)
- return 0;
- stats = filp->private_data;
- spin_lock_irq(&stats->lock);
- if (stats->n)
- field = div64_u64(stats->sum, stats->n);
- spin_unlock_irq(&stats->lock);
- ret = snprintf(tbuf, sizeof(tbuf), "%llu\n", field);
- if (ret > 0) {
- if (copy_to_user(buf, tbuf, ret))
- return -EFAULT;
- }
- *pos += ret;
- return ret;
- }
- static ssize_t average_write(struct file *filp, const char __user *buf,
- size_t count, loff_t *pos)
- {
- struct mlx5_cmd_stats *stats;
- stats = filp->private_data;
- spin_lock_irq(&stats->lock);
- stats->sum = 0;
- stats->n = 0;
- spin_unlock_irq(&stats->lock);
- *pos += count;
- return count;
- }
- static const struct file_operations stats_fops = {
- .owner = THIS_MODULE,
- .open = simple_open,
- .read = average_read,
- .write = average_write,
- };
- int mlx5_cmdif_debugfs_init(struct mlx5_core_dev *dev)
- {
- struct mlx5_cmd_stats *stats;
- struct dentry **cmd;
- const char *namep;
- int err;
- int i;
- if (!mlx5_debugfs_root)
- return 0;
- cmd = &dev->priv.cmdif_debugfs;
- *cmd = debugfs_create_dir("commands", dev->priv.dbg_root);
- if (!*cmd)
- return -ENOMEM;
- for (i = 0; i < ARRAY_SIZE(dev->cmd.stats); i++) {
- stats = &dev->cmd.stats[i];
- namep = mlx5_command_str(i);
- if (strcmp(namep, "unknown command opcode")) {
- stats->root = debugfs_create_dir(namep, *cmd);
- if (!stats->root) {
- mlx5_core_warn(dev, "failed adding command %d\n",
- i);
- err = -ENOMEM;
- goto out;
- }
- stats->avg = debugfs_create_file("average", 0400,
- stats->root, stats,
- &stats_fops);
- if (!stats->avg) {
- mlx5_core_warn(dev, "failed creating debugfs file\n");
- err = -ENOMEM;
- goto out;
- }
- stats->count = debugfs_create_u64("n", 0400,
- stats->root,
- &stats->n);
- if (!stats->count) {
- mlx5_core_warn(dev, "failed creating debugfs file\n");
- err = -ENOMEM;
- goto out;
- }
- }
- }
- return 0;
- out:
- debugfs_remove_recursive(dev->priv.cmdif_debugfs);
- return err;
- }
- void mlx5_cmdif_debugfs_cleanup(struct mlx5_core_dev *dev)
- {
- if (!mlx5_debugfs_root)
- return;
- debugfs_remove_recursive(dev->priv.cmdif_debugfs);
- }
- int mlx5_cq_debugfs_init(struct mlx5_core_dev *dev)
- {
- if (!mlx5_debugfs_root)
- return 0;
- dev->priv.cq_debugfs = debugfs_create_dir("CQs", dev->priv.dbg_root);
- if (!dev->priv.cq_debugfs)
- return -ENOMEM;
- return 0;
- }
- void mlx5_cq_debugfs_cleanup(struct mlx5_core_dev *dev)
- {
- if (!mlx5_debugfs_root)
- return;
- debugfs_remove_recursive(dev->priv.cq_debugfs);
- }
- static u64 qp_read_field(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp,
- int index, int *is_str)
- {
- struct mlx5_query_qp_mbox_out *out;
- struct mlx5_qp_context *ctx;
- u64 param = 0;
- int err;
- int no_sq;
- out = kzalloc(sizeof(*out), GFP_KERNEL);
- if (!out)
- return param;
- err = mlx5_core_qp_query(dev, qp, out, sizeof(*out));
- if (err) {
- mlx5_core_warn(dev, "failed to query qp\n");
- goto out;
- }
- *is_str = 0;
- ctx = &out->ctx;
- switch (index) {
- case QP_PID:
- param = qp->pid;
- break;
- case QP_STATE:
- param = (unsigned long)mlx5_qp_state_str(be32_to_cpu(ctx->flags) >> 28);
- *is_str = 1;
- break;
- case QP_XPORT:
- param = (unsigned long)mlx5_qp_type_str((be32_to_cpu(ctx->flags) >> 16) & 0xff);
- *is_str = 1;
- break;
- case QP_MTU:
- switch (ctx->mtu_msgmax >> 5) {
- case IB_MTU_256:
- param = 256;
- break;
- case IB_MTU_512:
- param = 512;
- break;
- case IB_MTU_1024:
- param = 1024;
- break;
- case IB_MTU_2048:
- param = 2048;
- break;
- case IB_MTU_4096:
- param = 4096;
- break;
- default:
- param = 0;
- }
- break;
- case QP_N_RECV:
- param = 1 << ((ctx->rq_size_stride >> 3) & 0xf);
- break;
- case QP_RECV_SZ:
- param = 1 << ((ctx->rq_size_stride & 7) + 4);
- break;
- case QP_N_SEND:
- no_sq = be16_to_cpu(ctx->sq_crq_size) >> 15;
- if (!no_sq)
- param = 1 << (be16_to_cpu(ctx->sq_crq_size) >> 11);
- else
- param = 0;
- break;
- case QP_LOG_PG_SZ:
- param = (be32_to_cpu(ctx->log_pg_sz_remote_qpn) >> 24) & 0x1f;
- param += 12;
- break;
- case QP_RQPN:
- param = be32_to_cpu(ctx->log_pg_sz_remote_qpn) & 0xffffff;
- break;
- }
- out:
- kfree(out);
- return param;
- }
- static u64 eq_read_field(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
- int index)
- {
- struct mlx5_query_eq_mbox_out *out;
- struct mlx5_eq_context *ctx;
- u64 param = 0;
- int err;
- out = kzalloc(sizeof(*out), GFP_KERNEL);
- if (!out)
- return param;
- ctx = &out->ctx;
- err = mlx5_core_eq_query(dev, eq, out, sizeof(*out));
- if (err) {
- mlx5_core_warn(dev, "failed to query eq\n");
- goto out;
- }
- switch (index) {
- case EQ_NUM_EQES:
- param = 1 << ((be32_to_cpu(ctx->log_sz_usr_page) >> 24) & 0x1f);
- break;
- case EQ_INTR:
- param = ctx->intr;
- break;
- case EQ_LOG_PG_SZ:
- param = (ctx->log_page_size & 0x1f) + 12;
- break;
- }
- out:
- kfree(out);
- return param;
- }
- static u64 cq_read_field(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
- int index)
- {
- struct mlx5_query_cq_mbox_out *out;
- struct mlx5_cq_context *ctx;
- u64 param = 0;
- int err;
- out = kzalloc(sizeof(*out), GFP_KERNEL);
- if (!out)
- return param;
- ctx = &out->ctx;
- err = mlx5_core_query_cq(dev, cq, out);
- if (err) {
- mlx5_core_warn(dev, "failed to query cq\n");
- goto out;
- }
- switch (index) {
- case CQ_PID:
- param = cq->pid;
- break;
- case CQ_NUM_CQES:
- param = 1 << ((be32_to_cpu(ctx->log_sz_usr_page) >> 24) & 0x1f);
- break;
- case CQ_LOG_PG_SZ:
- param = (ctx->log_pg_sz & 0x1f) + 12;
- break;
- }
- out:
- kfree(out);
- return param;
- }
- static ssize_t dbg_read(struct file *filp, char __user *buf, size_t count,
- loff_t *pos)
- {
- struct mlx5_field_desc *desc;
- struct mlx5_rsc_debug *d;
- char tbuf[18];
- int is_str = 0;
- u64 field;
- int ret;
- if (*pos)
- return 0;
- desc = filp->private_data;
- d = (void *)(desc - desc->i) - sizeof(*d);
- switch (d->type) {
- case MLX5_DBG_RSC_QP:
- field = qp_read_field(d->dev, d->object, desc->i, &is_str);
- break;
- case MLX5_DBG_RSC_EQ:
- field = eq_read_field(d->dev, d->object, desc->i);
- break;
- case MLX5_DBG_RSC_CQ:
- field = cq_read_field(d->dev, d->object, desc->i);
- break;
- default:
- mlx5_core_warn(d->dev, "invalid resource type %d\n", d->type);
- return -EINVAL;
- }
- if (is_str)
- ret = snprintf(tbuf, sizeof(tbuf), "%s\n", (const char *)(unsigned long)field);
- else
- ret = snprintf(tbuf, sizeof(tbuf), "0x%llx\n", field);
- if (ret > 0) {
- if (copy_to_user(buf, tbuf, ret))
- return -EFAULT;
- }
- *pos += ret;
- return ret;
- }
- static const struct file_operations fops = {
- .owner = THIS_MODULE,
- .open = simple_open,
- .read = dbg_read,
- };
- static int add_res_tree(struct mlx5_core_dev *dev, enum dbg_rsc_type type,
- struct dentry *root, struct mlx5_rsc_debug **dbg,
- int rsn, char **field, int nfile, void *data)
- {
- struct mlx5_rsc_debug *d;
- char resn[32];
- int err;
- int i;
- d = kzalloc(sizeof(*d) + nfile * sizeof(d->fields[0]), GFP_KERNEL);
- if (!d)
- return -ENOMEM;
- d->dev = dev;
- d->object = data;
- d->type = type;
- sprintf(resn, "0x%x", rsn);
- d->root = debugfs_create_dir(resn, root);
- if (!d->root) {
- err = -ENOMEM;
- goto out_free;
- }
- for (i = 0; i < nfile; i++) {
- d->fields[i].i = i;
- d->fields[i].dent = debugfs_create_file(field[i], 0400,
- d->root, &d->fields[i],
- &fops);
- if (!d->fields[i].dent) {
- err = -ENOMEM;
- goto out_rem;
- }
- }
- *dbg = d;
- return 0;
- out_rem:
- debugfs_remove_recursive(d->root);
- out_free:
- kfree(d);
- return err;
- }
- static void rem_res_tree(struct mlx5_rsc_debug *d)
- {
- debugfs_remove_recursive(d->root);
- kfree(d);
- }
- int mlx5_debug_qp_add(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp)
- {
- int err;
- if (!mlx5_debugfs_root)
- return 0;
- err = add_res_tree(dev, MLX5_DBG_RSC_QP, dev->priv.qp_debugfs,
- &qp->dbg, qp->qpn, qp_fields,
- ARRAY_SIZE(qp_fields), qp);
- if (err)
- qp->dbg = NULL;
- return err;
- }
- void mlx5_debug_qp_remove(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp)
- {
- if (!mlx5_debugfs_root)
- return;
- if (qp->dbg)
- rem_res_tree(qp->dbg);
- }
- int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
- {
- int err;
- if (!mlx5_debugfs_root)
- return 0;
- err = add_res_tree(dev, MLX5_DBG_RSC_EQ, dev->priv.eq_debugfs,
- &eq->dbg, eq->eqn, eq_fields,
- ARRAY_SIZE(eq_fields), eq);
- if (err)
- eq->dbg = NULL;
- return err;
- }
- void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
- {
- if (!mlx5_debugfs_root)
- return;
- if (eq->dbg)
- rem_res_tree(eq->dbg);
- }
- int mlx5_debug_cq_add(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
- {
- int err;
- if (!mlx5_debugfs_root)
- return 0;
- err = add_res_tree(dev, MLX5_DBG_RSC_CQ, dev->priv.cq_debugfs,
- &cq->dbg, cq->cqn, cq_fields,
- ARRAY_SIZE(cq_fields), cq);
- if (err)
- cq->dbg = NULL;
- return err;
- }
- void mlx5_debug_cq_remove(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
- {
- if (!mlx5_debugfs_root)
- return;
- if (cq->dbg)
- rem_res_tree(cq->dbg);
- }
|