IB/mlx5: Add delay drop configuration and statistics
authorMaor Gottlieb <maorg@mellanox.com>
Tue, 30 May 2017 07:29:14 +0000 (10:29 +0300)
committerDoug Ledford <dledford@redhat.com>
Mon, 24 Jul 2017 14:40:22 +0000 (10:40 -0400)
Add debugfs interface for monitor the number of delay drop timeout
events and the number of existing dropless RQs in the system.

In addition add debugfs interface for configuring the global timeout value
which is used in the SET_DELAY_DROP command.

Signed-off-by: Maor Gottlieb <maorg@mellanox.com>
Reviewed-by: Yishai Hadas <yishaih@mellanox.com>
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/mlx5_ib.h
drivers/infiniband/hw/mlx5/qp.c

index ad4b12decc23f4baef07c354c0247eb01e78cd30..7455f95bf67908f8d1330d444d48ab8a099706d1 100644 (file)
@@ -30,6 +30,7 @@
  * SOFTWARE.
  */
 
+#include <linux/debugfs.h>
 #include <linux/highmem.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -2763,6 +2764,8 @@ static void delay_drop_handler(struct work_struct *work)
                container_of(work, struct mlx5_ib_delay_drop,
                             delay_drop_work);
 
+       atomic_inc(&delay_drop->events_cnt);
+
        mutex_lock(&delay_drop->lock);
        err = mlx5_core_set_delay_drop(delay_drop->dev->mdev,
                                       delay_drop->timeout);
@@ -3651,12 +3654,107 @@ mlx5_ib_alloc_rdma_netdev(struct ib_device *hca,
        return netdev;
 }
 
+static void delay_drop_debugfs_cleanup(struct mlx5_ib_dev *dev)
+{
+       if (!dev->delay_drop.dbg)
+               return;
+       debugfs_remove_recursive(dev->delay_drop.dbg->dir_debugfs);
+       kfree(dev->delay_drop.dbg);
+       dev->delay_drop.dbg = NULL;
+}
+
 static void cancel_delay_drop(struct mlx5_ib_dev *dev)
 {
        if (!(dev->ib_dev.attrs.raw_packet_caps & IB_RAW_PACKET_CAP_DELAY_DROP))
                return;
 
        cancel_work_sync(&dev->delay_drop.delay_drop_work);
+       delay_drop_debugfs_cleanup(dev);
+}
+
+static ssize_t delay_drop_timeout_read(struct file *filp, char __user *buf,
+                                      size_t count, loff_t *pos)
+{
+       struct mlx5_ib_delay_drop *delay_drop = filp->private_data;
+       char lbuf[20];
+       int len;
+
+       len = snprintf(lbuf, sizeof(lbuf), "%u\n", delay_drop->timeout);
+       return simple_read_from_buffer(buf, count, pos, lbuf, len);
+}
+
+static ssize_t delay_drop_timeout_write(struct file *filp, const char __user *buf,
+                                       size_t count, loff_t *pos)
+{
+       struct mlx5_ib_delay_drop *delay_drop = filp->private_data;
+       u32 timeout;
+       u32 var;
+
+       if (kstrtouint_from_user(buf, count, 0, &var))
+               return -EFAULT;
+
+       timeout = min_t(u32, roundup(var, 100), MLX5_MAX_DELAY_DROP_TIMEOUT_MS *
+                       1000);
+       if (timeout != var)
+               mlx5_ib_dbg(delay_drop->dev, "Round delay drop timeout to %u usec\n",
+                           timeout);
+
+       delay_drop->timeout = timeout;
+
+       return count;
+}
+
+static const struct file_operations fops_delay_drop_timeout = {
+       .owner  = THIS_MODULE,
+       .open   = simple_open,
+       .write  = delay_drop_timeout_write,
+       .read   = delay_drop_timeout_read,
+};
+
+static int delay_drop_debugfs_init(struct mlx5_ib_dev *dev)
+{
+       struct mlx5_ib_dbg_delay_drop *dbg;
+
+       if (!mlx5_debugfs_root)
+               return 0;
+
+       dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
+       if (!dbg)
+               return -ENOMEM;
+
+       dbg->dir_debugfs =
+               debugfs_create_dir("delay_drop",
+                                  dev->mdev->priv.dbg_root);
+       if (!dbg->dir_debugfs)
+               return -ENOMEM;
+
+       dbg->events_cnt_debugfs =
+               debugfs_create_atomic_t("num_timeout_events", 0400,
+                                       dbg->dir_debugfs,
+                                       &dev->delay_drop.events_cnt);
+       if (!dbg->events_cnt_debugfs)
+               goto out_debugfs;
+
+       dbg->rqs_cnt_debugfs =
+               debugfs_create_atomic_t("num_rqs", 0400,
+                                       dbg->dir_debugfs,
+                                       &dev->delay_drop.rqs_cnt);
+       if (!dbg->rqs_cnt_debugfs)
+               goto out_debugfs;
+
+       dbg->timeout_debugfs =
+               debugfs_create_file("timeout", 0600,
+                                   dbg->dir_debugfs,
+                                   &dev->delay_drop,
+                                   &fops_delay_drop_timeout);
+       if (!dbg->timeout_debugfs)
+               goto out_debugfs;
+
+       return 0;
+
+out_debugfs:
+       delay_drop_debugfs_cleanup(dev);
+       return -ENOMEM;
 }
 
 static void init_delay_drop(struct mlx5_ib_dev *dev)
@@ -3669,6 +3767,11 @@ static void init_delay_drop(struct mlx5_ib_dev *dev)
        dev->delay_drop.activate = false;
        dev->delay_drop.timeout = MLX5_MAX_DELAY_DROP_TIMEOUT_MS * 1000;
        INIT_WORK(&dev->delay_drop.delay_drop_work, delay_drop_handler);
+       atomic_set(&dev->delay_drop.rqs_cnt, 0);
+       atomic_set(&dev->delay_drop.events_cnt, 0);
+
+       if (delay_drop_debugfs_init(dev))
+               mlx5_ib_warn(dev, "Failed to init delay drop debugfs\n");
 }
 
 static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
index 097f12dc65a648f410c53879b3ae6c86ecae941f..0316147a39a883e710cd5f2a23af39094367ee7b 100644 (file)
@@ -661,6 +661,13 @@ enum {
        MLX5_MAX_DELAY_DROP_TIMEOUT_MS = 100,
 };
 
+struct mlx5_ib_dbg_delay_drop {
+       struct dentry           *dir_debugfs;
+       struct dentry           *rqs_cnt_debugfs;
+       struct dentry           *events_cnt_debugfs;
+       struct dentry           *timeout_debugfs;
+};
+
 struct mlx5_ib_delay_drop {
        struct mlx5_ib_dev     *dev;
        struct work_struct      delay_drop_work;
@@ -668,6 +675,9 @@ struct mlx5_ib_delay_drop {
        struct mutex            lock;
        u32                     timeout;
        bool                    activate;
+       atomic_t                events_cnt;
+       atomic_t                rqs_cnt;
+       struct mlx5_ib_dbg_delay_drop *dbg;
 };
 
 struct mlx5_ib_dev {
index 939553d5c25f48d933e3329c92b7cbb640746cb1..c5d8ec839e99a2464b18bd2ff1c26cea05f79832 100644 (file)
@@ -675,10 +675,14 @@ err_umem:
        return err;
 }
 
-static void destroy_user_rq(struct ib_pd *pd, struct mlx5_ib_rwq *rwq)
+static void destroy_user_rq(struct mlx5_ib_dev *dev, struct ib_pd *pd,
+                           struct mlx5_ib_rwq *rwq)
 {
        struct mlx5_ib_ucontext *context;
 
+       if (rwq->create_flags & MLX5_IB_WQ_FLAGS_DELAY_DROP)
+               atomic_dec(&dev->delay_drop.rqs_cnt);
+
        context = to_mucontext(pd->uobject->context);
        mlx5_ib_db_unmap_user(context, &rwq->db);
        if (rwq->umem)
@@ -4612,6 +4616,9 @@ static int set_delay_drop(struct mlx5_ib_dev *dev)
        dev->delay_drop.activate = true;
 out:
        mutex_unlock(&dev->delay_drop.lock);
+
+       if (!err)
+               atomic_inc(&dev->delay_drop.rqs_cnt);
        return err;
 }
 
@@ -4824,7 +4831,7 @@ struct ib_wq *mlx5_ib_create_wq(struct ib_pd *pd,
 err_copy:
        mlx5_core_destroy_rq_tracked(dev->mdev, &rwq->core_qp);
 err_user_rq:
-       destroy_user_rq(pd, rwq);
+       destroy_user_rq(dev, pd, rwq);
 err:
        kfree(rwq);
        return ERR_PTR(err);
@@ -4836,7 +4843,7 @@ int mlx5_ib_destroy_wq(struct ib_wq *wq)
        struct mlx5_ib_rwq *rwq = to_mrwq(wq);
 
        mlx5_core_destroy_rq_tracked(dev->mdev, &rwq->core_qp);
-       destroy_user_rq(wq->pd, rwq);
+       destroy_user_rq(dev, wq->pd, rwq);
        kfree(rwq);
 
        return 0;