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 {
