From: Maher Sanalla <msanalla@nvidia.com>
Subject: [PATCH] BACKPORT: drivers/net/ethernet/mellanox/mlx5/core/health.c

Change-Id: I976861181f418bda545924b33660ea876544d5d4
---
 .../net/ethernet/mellanox/mlx5/core/health.c  | 168 ++++++++++++++++--
 1 file changed, 157 insertions(+), 11 deletions(-)

--- a/drivers/net/ethernet/mellanox/mlx5/core/health.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c
@@ -80,6 +80,31 @@ enum {
 	MLX5_SEVERITY_VALID_MASK	= 0x8,
 };
 
+/* BACKPORT for RHEL 7.4 PPC - can't be inline with unknown num of args */
+static void mlx5_printk(struct mlx5_core_dev *dev, int level, const char *format, ...)
+{
+	struct device *device = dev->device;
+	struct va_format vaf;
+	va_list args;
+
+	if (WARN_ONCE(level < LOGLEVEL_EMERG || level > LOGLEVEL_DEBUG,
+		      "Level %d is out of range, set to default level\n", level))
+		level = LOGLEVEL_DEFAULT;
+
+	va_start(args, format);
+	vaf.fmt = format;
+	vaf.va = &args;
+
+	dev_printk_emit(level, device, "%s %s: %pV", dev_driver_string(device), dev_name(device),
+			&vaf);
+	va_end(args);
+}
+
+#define mlx5_log(__dev, level, format, ...)			\
+	mlx5_printk(__dev, level, "%s:%d:(pid %d): " format,	\
+		    __func__, __LINE__, current->pid,		\
+		    ##__VA_ARGS__)
+
 u8 mlx5_get_nic_state(struct mlx5_core_dev *dev)
 {
 	return (ioread32be(&dev->iseg->cmdq_addr_l_sz) >> 8) & 7;
@@ -368,6 +393,23 @@ err_eio:
 	return -EIO;
 }
 
+#ifndef HAVE_DEVLINK_HEALTH_REPORT_SUPPORT
+static void health_recover_work(struct work_struct *work)
+{
+	struct mlx5_core_health *health;
+	struct mlx5_core_dev *dev;
+	struct mlx5_priv *priv;
+
+	health = container_of(work, struct mlx5_core_health, fatal_report_work);
+	priv = container_of(health, struct mlx5_priv, health);
+	dev = container_of(priv, struct mlx5_core_dev, priv);
+
+	enter_error_state(dev, false);
+	if (mlx5_health_try_recover(dev))
+		mlx5_core_err(dev, "Health recovery failed\n");
+}
+#endif /* HAVE_DEVLINK_HEALTH_REPORT_SUPPORT */
+
 static const char *hsynd_str(u8 synd)
 {
 	switch (synd) {
@@ -468,10 +510,14 @@ static void print_health_info(struct mlx
 	mlx5_log(dev, severity, "raw fw_ver 0x%08x\n", ioread32be(&h->fw_ver));
 }
 
+#ifdef HAVE_DEVLINK_HEALTH_REPORT_SUPPORT
 static int
 mlx5_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
-			  struct devlink_fmsg *fmsg,
-			  struct netlink_ext_ack *extack)
+			  struct devlink_fmsg *fmsg
+#ifdef HAVE_HEALTH_REPORTER_RECOVER_HAS_EXTACK
+		          , struct netlink_ext_ack *extack
+#endif
+			 )
 {
 	struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
 	struct mlx5_core_health *health = &dev->priv.health;
@@ -583,8 +629,11 @@ mlx5_fw_reporter_heath_buffer_data_put(s
 
 static int
 mlx5_fw_reporter_dump(struct devlink_health_reporter *reporter,
-		      struct devlink_fmsg *fmsg, void *priv_ctx,
-		      struct netlink_ext_ack *extack)
+		      struct devlink_fmsg *fmsg, void *priv_ctx
+#ifdef HAVE_HEALTH_REPORTER_RECOVER_HAS_EXTACK
+		      , struct netlink_ext_ack *extack
+#endif
+		     )
 {
 	struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
 	int err;
@@ -638,22 +687,36 @@ static const struct devlink_health_repor
 
 static int
 mlx5_fw_fatal_reporter_recover(struct devlink_health_reporter *reporter,
-			       void *priv_ctx,
-			       struct netlink_ext_ack *extack)
+			       void *priv_ctx
+#ifdef HAVE_HEALTH_REPORTER_RECOVER_HAS_EXTACK
+			       , struct netlink_ext_ack *extack
+#endif
+			       )
 {
 	struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
 
 	return mlx5_health_try_recover(dev);
 }
 
+#ifndef HAVE_DEVLINK_FMSG_BINARY_PAIR_PUT_ARG_U32
+#define MLX5_CR_DUMP_CHUNK_SIZE 256
+#endif
+
 static int
 mlx5_fw_fatal_reporter_dump(struct devlink_health_reporter *reporter,
-			    struct devlink_fmsg *fmsg, void *priv_ctx,
-			    struct netlink_ext_ack *extack)
+			    struct devlink_fmsg *fmsg, void *priv_ctx
+#ifdef HAVE_HEALTH_REPORTER_RECOVER_HAS_EXTACK
+			    , struct netlink_ext_ack *extack
+#endif
+			   )
 {
 	struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
 	u32 crdump_size = dev->priv.health.crdump_size;
 	u32 *cr_data;
+#ifndef HAVE_DEVLINK_FMSG_BINARY_PAIR_PUT_ARG_U32
+	u32 data_size;
+	u32 offset;
+#endif
 	int err;
 
 	if (!mlx5_core_is_pf(dev))
@@ -677,7 +740,24 @@ mlx5_fw_fatal_reporter_dump(struct devli
 			goto free_data;
 	}
 
+#ifdef HAVE_DEVLINK_FMSG_BINARY_PAIR_PUT_ARG_U32
 	err = devlink_fmsg_binary_pair_put(fmsg, "crdump_data", cr_data, crdump_size);
+#else
+	err = devlink_fmsg_arr_pair_nest_start(fmsg, "crdump_data");
+	if (err)
+		goto free_data;
+	for (offset = 0; offset < crdump_size; offset += data_size) {
+		if (crdump_size - offset < MLX5_CR_DUMP_CHUNK_SIZE)
+			data_size = crdump_size - offset;
+		else
+			data_size = MLX5_CR_DUMP_CHUNK_SIZE;
+		err = devlink_fmsg_binary_put(fmsg, (char *)cr_data + offset,
+					      data_size);
+		if (err)
+			goto free_data;
+	}
+	err = devlink_fmsg_arr_pair_nest_end(fmsg);
+#endif /* HAVE_DEVLINK_FMSG_BINARY_PAIR_PUT_ARG_U32 */
 
 free_data:
 	kvfree(cr_data);
@@ -690,12 +770,18 @@ static void mlx5_fw_fatal_reporter_err_w
 	struct mlx5_fw_reporter_ctx fw_reporter_ctx;
 	struct mlx5_core_health *health;
 	struct mlx5_core_dev *dev;
+#ifdef HAVE_DEVL_TRAP_GROUPS_REGISTER //forward port
+	struct devlink *devlink;
+#endif
 	struct mlx5_priv *priv;
 
 	health = container_of(work, struct mlx5_core_health, fatal_report_work);
 	priv = container_of(health, struct mlx5_priv, health);
 	dev = container_of(priv, struct mlx5_core_dev, priv);
 
+#ifdef HAVE_DEVL_TRAP_GROUPS_REGISTER //forward port
+	devlink = priv_to_devlink(dev);
+#endif
 	mutex_lock(&dev->intf_state_mutex);
 	if (test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags)) {
 		mlx5_core_err(dev, "health works are not permitted at this stage\n");
@@ -705,16 +791,25 @@ static void mlx5_fw_fatal_reporter_err_w
 	mutex_unlock(&dev->intf_state_mutex);
 	enter_error_state(dev, false);
 	if (IS_ERR_OR_NULL(health->fw_fatal_reporter)) {
+#ifdef HAVE_DEVL_TRAP_GROUPS_REGISTER //forward port
+	devl_lock(devlink);
+#endif
 		if (mlx5_health_try_recover(dev))
 			mlx5_core_err(dev, "health recovery failed\n");
+#ifdef HAVE_DEVL_TRAP_GROUPS_REGISTER //forward port
+	devl_unlock(devlink);
+#endif
 		return;
 	}
 	fw_reporter_ctx.err_synd = health->synd;
 	fw_reporter_ctx.miss_counter = health->miss_counter;
+#ifdef HAVE_DEVLINK_HEALTH_REPORTER_STATE_UPDATE
 	if (health->failed_in_seq &&
 	    health->failed_in_seq < MLX5_MAX_FAILED_RECOVERIES_IN_SEQUENCE)
 		devlink_health_reporter_state_update(health->fw_fatal_reporter,
 						     DEVLINK_HEALTH_REPORTER_STATE_HEALTHY);
+#endif
+
 	if (devlink_health_report(health->fw_fatal_reporter,
 				  "FW fatal error reported", &fw_reporter_ctx) == -ECANCELED) {
 		/* If recovery wasn't performed, due to grace period,
@@ -755,7 +850,11 @@ static void mlx5_fw_reporters_create(str
 
 	health->fw_reporter =
 		devlink_health_reporter_create(devlink, &mlx5_fw_reporter_ops,
-					       0, dev);
+#ifndef HAVE_DEVLINK_HEALTH_REPORTER_CREATE_5_ARGS
+				0, dev);
+#else
+				0, false, dev);
+#endif
 	if (IS_ERR(health->fw_reporter))
 		mlx5_core_warn(dev, "Failed to create fw reporter, err = %ld\n",
 			       PTR_ERR(health->fw_reporter));
@@ -763,7 +862,11 @@ static void mlx5_fw_reporters_create(str
 	health->fw_fatal_reporter =
 		devlink_health_reporter_create(devlink,
 					       &mlx5_fw_fatal_reporter_ops,
+#ifndef HAVE_DEVLINK_HEALTH_REPORTER_CREATE_5_ARGS
 					       grace_period, dev);
+#else
+					       grace_period, true,  dev);
+#endif
 	if (IS_ERR(health->fw_fatal_reporter))
 		mlx5_core_warn(dev, "Failed to create fw fatal reporter, err = %ld\n",
 			       PTR_ERR(health->fw_fatal_reporter));
@@ -774,11 +877,20 @@ static void mlx5_fw_reporters_destroy(st
 	struct mlx5_core_health *health = &dev->priv.health;
 
 	if (!IS_ERR_OR_NULL(health->fw_reporter))
-		devlink_health_reporter_destroy(health->fw_reporter);
+#ifdef HAVE_DEVL_PARAM_DRIVERINIT_VALUE_GET
+		devl_health_reporter_destroy(health->fw_reporter);
+#else
+	devlink_health_reporter_destroy(health->fw_reporter);
+#endif
 
 	if (!IS_ERR_OR_NULL(health->fw_fatal_reporter))
-		devlink_health_reporter_destroy(health->fw_fatal_reporter);
+#ifdef HAVE_DEVL_PARAM_DRIVERINIT_VALUE_GET
+		devl_health_reporter_destroy(health->fw_fatal_reporter);
+#else
+	devlink_health_reporter_destroy(health->fw_fatal_reporter);
+#endif
 }
+#endif /* HAVE_DEVLINK_HEALTH_REPORT_SUPPORT */
 
 static unsigned long get_next_poll_jiffies(struct mlx5_core_dev *dev)
 {
@@ -829,13 +941,25 @@ static void mlx5_health_log_ts_update(st
 			   msecs_to_jiffies(MLX5_MSEC_PER_HOUR));
 }
 
+#ifdef HAVE_TIMER_SETUP
 static void poll_health(struct timer_list *t)
+#else
+static void poll_health(unsigned long data)
+#endif
 {
+#ifdef HAVE_TIMER_SETUP
 	struct mlx5_core_dev *dev = from_timer(dev, t, priv.health.timer);
+#else
+	struct mlx5_core_dev *dev = (struct mlx5_core_dev *)data;
+#endif
 	struct mlx5_core_health *health = &dev->priv.health;
+#ifdef HAVE_DEVLINK_HEALTH_REPORT_SUPPORT
 	struct health_buffer __iomem *h = health->health;
+#endif /* HAVE_DEVLINK_HEALTH_REPORT_SUPPORT */
 	u32 fatal_error;
+#ifdef HAVE_DEVLINK_HEALTH_REPORT_SUPPORT
 	u8 prev_synd;
+#endif /* HAVE_DEVLINK_HEALTH_REPORT_SUPPORT */
 	u32 count;
 
 	if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
@@ -862,13 +986,17 @@ static void poll_health(struct timer_lis
 	if (health->miss_counter == MAX_MISSES) {
 		mlx5_core_err(dev, "device's health compromised - reached miss count\n");
 		print_health_info(dev);
+#ifdef HAVE_DEVLINK_HEALTH_REPORT_SUPPORT
 		queue_work(health->wq, &health->report_work);
+#endif /* HAVE_DEVLINK_HEALTH_REPORT_SUPPORT */
 	}
 
+#ifdef HAVE_DEVLINK_HEALTH_REPORT_SUPPORT
 	prev_synd = health->synd;
 	health->synd = ioread8(&h->synd);
 	if (health->synd && health->synd != prev_synd)
 		queue_work(health->wq, &health->report_work);
+#endif /* HAVE_DEVLINK_HEALTH_REPORT_SUPPORT */
 
 out:
 	mod_timer(&health->timer, get_next_poll_jiffies(dev));
@@ -879,7 +1007,13 @@ void mlx5_start_health_poll(struct mlx5_
 	u64 poll_interval_ms =  mlx5_tout_ms(dev, HEALTH_POLL_INTERVAL);
 	struct mlx5_core_health *health = &dev->priv.health;
 
+#ifdef HAVE_TIMER_SETUP
 	timer_setup(&health->timer, poll_health, 0);
+#else
+	init_timer(&health->timer);
+	health->timer.data = (unsigned long)dev;
+	health->timer.function = poll_health;
+#endif
 	health->fatal_error = MLX5_SENSOR_NO_ERR;
 	clear_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
 	health->health = &dev->iseg->health;
@@ -920,7 +1054,9 @@ void mlx5_drain_health_wq(struct mlx5_co
 	set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
 	spin_unlock_irqrestore(&health->wq_lock, flags);
 	cancel_delayed_work_sync(&health->update_fw_log_ts_work);
+#ifdef HAVE_DEVLINK_HEALTH_REPORT_SUPPORT
 	cancel_work_sync(&health->report_work);
+#endif /* HAVE_DEVLINK_HEALTH_REPORT_SUPPORT */
 	cancel_work_sync(&health->fatal_report_work);
 }
 
@@ -937,7 +1073,9 @@ void mlx5_health_cleanup(struct mlx5_cor
 
 	cancel_delayed_work_sync(&health->update_fw_log_ts_work);
 	destroy_workqueue(health->wq);
+#ifdef HAVE_DEVLINK_HEALTH_REPORT_SUPPORT
 	mlx5_fw_reporters_destroy(dev);
+#endif /* HAVE_DEVLINK_HEALTH_REPORT_SUPPORT */
 }
 
 int mlx5_health_init(struct mlx5_core_dev *dev)
@@ -945,7 +1083,9 @@ int mlx5_health_init(struct mlx5_core_de
 	struct mlx5_core_health *health;
 	char *name;
 
+#ifdef HAVE_DEVLINK_HEALTH_REPORT_SUPPORT
 	mlx5_fw_reporters_create(dev);
+#endif /* HAVE_DEVLINK_HEALTH_REPORT_SUPPORT */
 
 	health = &dev->priv.health;
 	name = kmalloc(64, GFP_KERNEL);
@@ -959,13 +1099,19 @@ int mlx5_health_init(struct mlx5_core_de
 	if (!health->wq)
 		goto out_err;
 	spin_lock_init(&health->wq_lock);
+#ifdef HAVE_DEVLINK_HEALTH_REPORT_SUPPORT
 	INIT_WORK(&health->fatal_report_work, mlx5_fw_fatal_reporter_err_work);
 	INIT_WORK(&health->report_work, mlx5_fw_reporter_err_work);
+#else
+	INIT_WORK(&health->fatal_report_work, health_recover_work);
+#endif
 	INIT_DELAYED_WORK(&health->update_fw_log_ts_work, mlx5_health_log_ts_update);
 
 	return 0;
 
 out_err:
+#ifdef HAVE_DEVLINK_HEALTH_REPORT_SUPPORT
 	mlx5_fw_reporters_destroy(dev);
+#endif
 	return -ENOMEM;
 }
