From: Moshe Shemesh <mo...@mellanox.com>

Create mlx5_devlink_health_reporter for FW reporter. The FW reporter
implements devlink_health_reporter diagnose callback.

Signed-off-by: Moshe Shemesh <mo...@mellanox.com>
---
 .../net/ethernet/mellanox/mlx5/core/devlink.c | 115 ++++++++++++++++++
 .../net/ethernet/mellanox/mlx5/core/devlink.h |   8 ++
 .../net/ethernet/mellanox/mlx5/core/main.c    |   5 +
 include/linux/mlx5/driver.h                   |   1 +
 4 files changed, 129 insertions(+)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c 
b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
index 2daf686bcc98..4ec5d092a332 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
@@ -2,6 +2,121 @@
 /* Copyright (c) 2018, Mellanox Technologies inc. All rights reserved. */
 
 #include <devlink.h>
+#include "mlx5_core.h"
+
+static int
+mlx5_devlink_health_buffer_fill_syndrom(struct devlink_health_buffer 
*dh_buffer,
+                                       u8 syndrom)
+{
+       int err;
+
+       err = devlink_health_buffer_nest_start(dh_buffer,
+                                              
DEVLINK_ATTR_HEALTH_BUFFER_OBJECT);
+       if (err)
+               return err;
+       err = devlink_health_buffer_nest_start(dh_buffer,
+                                              
DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_PAIR);
+       if (err)
+               return err;
+       err = devlink_health_buffer_put_object_name(dh_buffer, "Syndrom");
+       if (err)
+               return err;
+       err = devlink_health_buffer_nest_start(dh_buffer,
+                                              
DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE);
+       if (err)
+               return err;
+       err = devlink_health_buffer_put_value_u8(dh_buffer, syndrom);
+       if (err)
+               return err;
+       devlink_health_buffer_nest_end(dh_buffer);
+       devlink_health_buffer_nest_end(dh_buffer);
+       devlink_health_buffer_nest_end(dh_buffer);
+
+       return 0;
+}
+
+static int
+mlx5_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
+                         struct devlink_health_buffer **buffers_array,
+                         unsigned int buff_size, unsigned int num_buffers)
+{
+       struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
+       char lines_buf[HEALTH_INFO_LINES][HEALTH_INFO_MAX_LINE] = {};
+       struct devlink_health_buffer *buffer;
+       u8 synd;
+       int err;
+       int i;
+
+       if (!buffers_array || buff_size < HEALTH_INFO_MAX_BUFF ||
+           num_buffers < 1 || !buffers_array[0])
+               return -EINVAL;
+
+       buffer = buffers_array[0];
+       mlx5_get_health_info(dev, &synd, lines_buf);
+       mlx5_devlink_health_buffer_fill_syndrom(buffer, synd);
+
+       if (!synd)
+               return 0;
+
+       err = devlink_health_buffer_nest_start(buffer,
+                                              
DEVLINK_ATTR_HEALTH_BUFFER_OBJECT);
+       if (err)
+               return err;
+       err = devlink_health_buffer_nest_start(buffer,
+                                              
DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_PAIR);
+       if (err)
+               return err;
+       err = devlink_health_buffer_put_object_name(buffer, "diagnose data");
+       if (err)
+               return err;
+       err = devlink_health_buffer_nest_start(buffer,
+                                              
DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE);
+       if (err)
+               return err;
+       err = devlink_health_buffer_nest_start(buffer,
+                                              
DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE_ARRAY);
+       if (err)
+               return err;
+
+       for (i = 0; i < HEALTH_INFO_LINES; i++) {
+               err = devlink_health_buffer_nest_start(buffer, 
DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE);
+               if (err)
+                       return err;
+               err = devlink_health_buffer_put_value_string(buffer, 
lines_buf[i]);
+               if (err)
+                       return err;
+               devlink_health_buffer_nest_end(buffer);
+       }
+       devlink_health_buffer_nest_end(buffer); /* 
DEVLINK_HEALTH_BUFFER_OBJECT_VALUE_ARRAY */
+       devlink_health_buffer_nest_end(buffer); /* 
DEVLINK_HEALTH_BUFFER_OBJECT_VALUE */
+       devlink_health_buffer_nest_end(buffer); /* 
DEVLINK_HEALTH_BUFFER_OBJECT_PAIR */
+       devlink_health_buffer_nest_end(buffer); /* DEVLINK_HEALTH_BUFFER_OBJECT 
*/
+
+       return 0;
+}
+
+static const struct devlink_health_reporter_ops mlx5_fw_reporter_ops = {
+               .name = "FW",
+               .diagnose_size = HEALTH_INFO_MAX_BUFF,
+               .diagnose = mlx5_fw_reporter_diagnose,
+};
+
+int mlx5_fw_reporter_create(struct mlx5_core_dev *dev)
+{
+       struct devlink *devlink = priv_to_devlink(dev);
+
+       dev->fw_reporter = devlink_health_reporter_create(devlink, 
&mlx5_fw_reporter_ops,
+                                                         0, false, dev);
+       return PTR_ERR_OR_ZERO(dev->fw_reporter);
+}
+
+void mlx5_fw_reporter_destroy(struct mlx5_core_dev *dev)
+{
+       if (!dev->fw_reporter)
+               return;
+
+       devlink_health_reporter_destroy(dev->fw_reporter);
+}
 
 int mlx5_devlink_register(struct devlink *devlink, struct device *dev)
 {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.h 
b/drivers/net/ethernet/mellanox/mlx5/core/devlink.h
index 455bfa4e89c0..34f6bfed1cfb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.h
@@ -5,8 +5,16 @@
 #define __MLX5_DEVLINK_H__
 
 #include <net/devlink.h>
+#include "mlx5_core.h"
+
+struct mlx5_fw_reporter_ctx {
+       u8 err_synd;
+       int miss_counter;
+};
 
 int mlx5_devlink_register(struct devlink *devlink, struct device *dev);
 void mlx5_devlink_unregister(struct devlink *devlink);
+int mlx5_fw_reporter_create(struct mlx5_core_dev *dev);
+void mlx5_fw_reporter_destroy(struct mlx5_core_dev *dev);
 
 #endif /* __MLX5_DEVLINK_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c 
b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index bd50d4adc6bf..ca5f4c661f6d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -981,6 +981,10 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct 
mlx5_priv *priv,
                goto err_fw_tracer;
        }
 
+       err = mlx5_fw_reporter_create(dev);
+       if (err)
+               dev_warn(&pdev->dev, "Failed to create FW reporter\n");
+
        err = mlx5_fpga_device_start(dev);
        if (err) {
                dev_err(&pdev->dev, "fpga device start failed %d\n", err);
@@ -1113,6 +1117,7 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, 
struct mlx5_priv *priv,
        mlx5_accel_ipsec_cleanup(dev);
        mlx5_accel_tls_cleanup(dev);
        mlx5_fpga_device_stop(dev);
+       mlx5_fw_reporter_destroy(dev);
        mlx5_fw_tracer_cleanup(dev->tracer);
        mlx5_eq_table_destroy(dev);
        mlx5_pagealloc_stop(dev);
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index 4d16ba04790e..98c17e74fd4d 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -677,6 +677,7 @@ struct mlx5_core_dev {
        struct mlx5_ib_clock_info  *clock_info;
        struct page             *clock_info_page;
        struct mlx5_fw_tracer   *tracer;
+       struct devlink_health_reporter *fw_reporter;
 };
 
 struct mlx5_db {
-- 
2.17.1

Reply via email to