========
 
 - `Enabling the driver and kconfig options`_
+- `Devlink info`_
 - `Devlink health reporters`_
 
 Enabling the driver and kconfig options
 - CONFIG_VXLAN: When chosen, mlx5 vxaln support will be enabled.
 - CONFIG_MLXFW: When chosen, mlx5 firmware flashing support will be enabled (via devlink and ethtool).
 
+Devlink info
+============
+
+The devlink info reports the running and stored firmware versions on device.
+It also prints the device PSID which represents the HCA board type ID.
+
+User command example::
+
+   $ devlink dev info pci/0000:00:06.0
+      pci/0000:00:06.0:
+      driver mlx5_core
+      versions:
+         fixed:
+            fw.psid MT_0000000009
+         running:
+            fw.version 16.26.0100
+         stored:
+            fw.version 16.26.0100
 
 Devlink health reporters
 ========================
 
        return mlx5_firmware_flash(dev, fw, extack);
 }
 
+static u8 mlx5_fw_ver_major(u32 version)
+{
+       return (version >> 24) & 0xff;
+}
+
+static u8 mlx5_fw_ver_minor(u32 version)
+{
+       return (version >> 16) & 0xff;
+}
+
+static u16 mlx5_fw_ver_subminor(u32 version)
+{
+       return version & 0xffff;
+}
+
+#define DEVLINK_FW_STRING_LEN 32
+
+static int
+mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
+                     struct netlink_ext_ack *extack)
+{
+       struct mlx5_core_dev *dev = devlink_priv(devlink);
+       char version_str[DEVLINK_FW_STRING_LEN];
+       u32 running_fw, stored_fw;
+       int err;
+
+       err = devlink_info_driver_name_put(req, DRIVER_NAME);
+       if (err)
+               return err;
+
+       err = devlink_info_version_fixed_put(req, "fw.psid", dev->board_id);
+       if (err)
+               return err;
+
+       err = mlx5_fw_version_query(dev, &running_fw, &stored_fw);
+       if (err)
+               return err;
+
+       snprintf(version_str, sizeof(version_str), "%d.%d.%04d",
+                mlx5_fw_ver_major(running_fw), mlx5_fw_ver_minor(running_fw),
+                mlx5_fw_ver_subminor(running_fw));
+       err = devlink_info_version_running_put(req, "fw.version", version_str);
+       if (err)
+               return err;
+
+       /* no pending version, return running (stored) version */
+       if (stored_fw == 0)
+               stored_fw = running_fw;
+
+       snprintf(version_str, sizeof(version_str), "%d.%d.%04d",
+                mlx5_fw_ver_major(stored_fw), mlx5_fw_ver_minor(stored_fw),
+                mlx5_fw_ver_subminor(stored_fw));
+       err = devlink_info_version_stored_put(req, "fw.version", version_str);
+       if (err)
+               return err;
+
+       return 0;
+}
+
 static const struct devlink_ops mlx5_devlink_ops = {
 #ifdef CONFIG_MLX5_ESWITCH
        .eswitch_mode_set = mlx5_devlink_eswitch_mode_set,
        .eswitch_encap_mode_get = mlx5_devlink_eswitch_encap_mode_get,
 #endif
        .flash_update = mlx5_devlink_flash_update,
+       .info_get = mlx5_devlink_info_get,
 };
 
 struct devlink *mlx5_devlink_alloc(void)