net/mlx5: Add support for fw live patch event
authorMoshe Shemesh <moshe@mellanox.com>
Wed, 7 Oct 2020 06:00:55 +0000 (09:00 +0300)
committerJakub Kicinski <kuba@kernel.org>
Fri, 9 Oct 2020 19:06:53 +0000 (12:06 -0700)
Firmware live patch event notifies the driver that the firmware was just
updated using live patch. In such case the driver should not reload or
re-initiate entities, part to updating the firmware version and
re-initiate the firmware tracer which can be updated by live patch with
new strings database to help debugging an issue.

Signed-off-by: Moshe Shemesh <moshe@mellanox.com>
Reviewed-by: Saeed Mahameed <saeedm@nvidia.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.h
drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
include/linux/mlx5/device.h

index ede4640..2eb022a 100644 (file)
@@ -1066,6 +1066,58 @@ void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer)
        kvfree(tracer);
 }
 
+static int mlx5_fw_tracer_recreate_strings_db(struct mlx5_fw_tracer *tracer)
+{
+       struct mlx5_core_dev *dev;
+       int err;
+
+       cancel_work_sync(&tracer->read_fw_strings_work);
+       mlx5_fw_tracer_clean_ready_list(tracer);
+       mlx5_fw_tracer_clean_print_hash(tracer);
+       mlx5_fw_tracer_clean_saved_traces_array(tracer);
+       mlx5_fw_tracer_free_strings_db(tracer);
+
+       dev = tracer->dev;
+       err = mlx5_query_mtrc_caps(tracer);
+       if (err) {
+               mlx5_core_dbg(dev, "FWTracer: Failed to query capabilities %d\n", err);
+               return err;
+       }
+
+       err = mlx5_fw_tracer_allocate_strings_db(tracer);
+       if (err) {
+               mlx5_core_warn(dev, "FWTracer: Allocate strings DB failed %d\n", err);
+               return err;
+       }
+       mlx5_fw_tracer_init_saved_traces_array(tracer);
+
+       return 0;
+}
+
+int mlx5_fw_tracer_reload(struct mlx5_fw_tracer *tracer)
+{
+       struct mlx5_core_dev *dev;
+       int err;
+
+       if (IS_ERR_OR_NULL(tracer))
+               return -EINVAL;
+
+       dev = tracer->dev;
+       mlx5_fw_tracer_cleanup(tracer);
+       err = mlx5_fw_tracer_recreate_strings_db(tracer);
+       if (err) {
+               mlx5_core_warn(dev, "Failed to recreate FW tracer strings DB\n");
+               return err;
+       }
+       err = mlx5_fw_tracer_init(tracer);
+       if (err) {
+               mlx5_core_warn(dev, "Failed to re-initialize FW tracer\n");
+               return err;
+       }
+
+       return 0;
+}
+
 static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data)
 {
        struct mlx5_fw_tracer *tracer = mlx5_nb_cof(nb, struct mlx5_fw_tracer, nb);
index 40601fb..97252a8 100644 (file)
@@ -191,5 +191,6 @@ void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer);
 int mlx5_fw_tracer_trigger_core_dump_general(struct mlx5_core_dev *dev);
 int mlx5_fw_tracer_get_saved_traces_objects(struct mlx5_fw_tracer *tracer,
                                            struct devlink_fmsg *fmsg);
+int mlx5_fw_tracer_reload(struct mlx5_fw_tracer *tracer);
 
 #endif
index b2aaff8..f9042e1 100644 (file)
@@ -2,6 +2,7 @@
 /* Copyright (c) 2020, Mellanox Technologies inc.  All rights reserved. */
 
 #include "fw_reset.h"
+#include "diag/fw_tracer.h"
 
 enum {
        MLX5_FW_RESET_FLAGS_RESET_REQUESTED,
@@ -13,6 +14,7 @@ struct mlx5_fw_reset {
        struct mlx5_core_dev *dev;
        struct mlx5_nb nb;
        struct workqueue_struct *wq;
+       struct work_struct fw_live_patch_work;
        struct work_struct reset_request_work;
        struct work_struct reset_reload_work;
        struct work_struct reset_now_work;
@@ -192,6 +194,24 @@ static void mlx5_sync_reset_set_reset_requested(struct mlx5_core_dev *dev)
        mlx5_start_sync_reset_poll(dev);
 }
 
+static void mlx5_fw_live_patch_event(struct work_struct *work)
+{
+       struct mlx5_fw_reset *fw_reset = container_of(work, struct mlx5_fw_reset,
+                                                     fw_live_patch_work);
+       struct mlx5_core_dev *dev = fw_reset->dev;
+       struct mlx5_fw_tracer *tracer;
+
+       mlx5_core_info(dev, "Live patch updated firmware version: %d.%d.%d\n", fw_rev_maj(dev),
+                      fw_rev_min(dev), fw_rev_sub(dev));
+
+       tracer = dev->tracer;
+       if (IS_ERR_OR_NULL(tracer))
+               return;
+
+       if (mlx5_fw_tracer_reload(tracer))
+               mlx5_core_err(dev, "Failed to reload FW tracer\n");
+}
+
 static void mlx5_sync_reset_request_event(struct work_struct *work)
 {
        struct mlx5_fw_reset *fw_reset = container_of(work, struct mlx5_fw_reset,
@@ -364,6 +384,9 @@ static int fw_reset_event_notifier(struct notifier_block *nb, unsigned long acti
        struct mlx5_eqe *eqe = data;
 
        switch (eqe->sub_type) {
+       case MLX5_GENERAL_SUBTYPE_FW_LIVE_PATCH_EVENT:
+                       queue_work(fw_reset->wq, &fw_reset->fw_live_patch_work);
+               break;
        case MLX5_GENERAL_SUBTYPE_PCI_SYNC_FOR_FW_UPDATE_EVENT:
                mlx5_sync_reset_events_handle(fw_reset, eqe);
                break;
@@ -421,6 +444,7 @@ int mlx5_fw_reset_init(struct mlx5_core_dev *dev)
        fw_reset->dev = dev;
        dev->priv.fw_reset = fw_reset;
 
+       INIT_WORK(&fw_reset->fw_live_patch_work, mlx5_fw_live_patch_event);
        INIT_WORK(&fw_reset->reset_request_work, mlx5_sync_reset_request_event);
        INIT_WORK(&fw_reset->reset_reload_work, mlx5_sync_reset_reload_work);
        INIT_WORK(&fw_reset->reset_now_work, mlx5_sync_reset_now_event);
index 81ca598..cf82436 100644 (file)
@@ -366,6 +366,7 @@ enum {
 enum {
        MLX5_GENERAL_SUBTYPE_DELAY_DROP_TIMEOUT = 0x1,
        MLX5_GENERAL_SUBTYPE_PCI_POWER_CHANGE_EVENT = 0x5,
+       MLX5_GENERAL_SUBTYPE_FW_LIVE_PATCH_EVENT = 0x7,
        MLX5_GENERAL_SUBTYPE_PCI_SYNC_FOR_FW_UPDATE_EVENT = 0x8,
 };