ice: enable FW logging
authorPaul M Stillwell Jr <paul.m.stillwell.jr@intel.com>
Wed, 13 Dec 2023 05:07:13 +0000 (21:07 -0800)
committerTony Nguyen <anthony.l.nguyen@intel.com>
Thu, 14 Dec 2023 17:50:53 +0000 (09:50 -0800)
Once users have configured the FW logging then allow them to enable it
by writing to the 'fwlog/enable' file. The file accepts a boolean value
(0 or 1) where 1 means enable FW logging and 0 means disable FW logging.

  # echo <value> > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/enable

Where <value> is 0 or 1.

The user can read the 'fwlog/enable' file to see whether logging is
enabled or not. Reading the actual data is a separate patch. To see the
current value then:

  # cat /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/enable

Signed-off-by: Paul M Stillwell Jr <paul.m.stillwell.jr@intel.com>
Tested-by: Pucha Himasekhar Reddy <himasekharx.reddy.pucha@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
drivers/net/ethernet/intel/ice/ice_debugfs.c
drivers/net/ethernet/intel/ice/ice_fwlog.c
drivers/net/ethernet/intel/ice/ice_fwlog.h

index 612c8d2708382068fe822167ae053db72d1beff4..9ddd50ba07b2e34b617f72e7ce1dae1723cd63eb 100644 (file)
@@ -2393,6 +2393,7 @@ enum ice_aqc_fw_logging_mod {
 };
 
 /* Set FW Logging configuration (indirect 0xFF30)
+ * Register for FW Logging (indirect 0xFF31)
  * Query FW Logging (indirect 0xFF32)
  */
 struct ice_aqc_fw_log {
@@ -2401,6 +2402,7 @@ struct ice_aqc_fw_log {
 #define ICE_AQC_FW_LOG_CONF_AQ_EN      BIT(1)
 #define ICE_AQC_FW_LOG_QUERY_REGISTERED        BIT(2)
 #define ICE_AQC_FW_LOG_CONF_SET_VALID  BIT(3)
+#define ICE_AQC_FW_LOG_AQ_REGISTER     BIT(0)
 #define ICE_AQC_FW_LOG_AQ_QUERY                BIT(2)
 
        u8 rsp_flag;
@@ -2722,6 +2724,7 @@ enum ice_adminq_opc {
 
        /* FW Logging Commands */
        ice_aqc_opc_fw_logs_config                      = 0xFF30,
+       ice_aqc_opc_fw_logs_register                    = 0xFF31,
        ice_aqc_opc_fw_logs_query                       = 0xFF32,
 };
 
index 3b0d9b214fd1f120794337e9e945396a75d06202..3dde999691320b5de352498b677c8fbaf02fe8d3 100644 (file)
@@ -281,6 +281,101 @@ static const struct file_operations ice_debugfs_nr_messages_fops = {
        .write = ice_debugfs_nr_messages_write,
 };
 
+/**
+ * ice_debugfs_enable_read - read from 'enable' file
+ * @filp: the opened file
+ * @buffer: where to write the data for the user to read
+ * @count: the size of the user's buffer
+ * @ppos: file position offset
+ */
+static ssize_t ice_debugfs_enable_read(struct file *filp,
+                                      char __user *buffer, size_t count,
+                                      loff_t *ppos)
+{
+       struct ice_pf *pf = filp->private_data;
+       struct ice_hw *hw = &pf->hw;
+       char buff[32] = {};
+
+       snprintf(buff, sizeof(buff), "%u\n",
+                (u16)(hw->fwlog_cfg.options &
+                ICE_FWLOG_OPTION_IS_REGISTERED) >> 3);
+
+       return simple_read_from_buffer(buffer, count, ppos, buff, strlen(buff));
+}
+
+/**
+ * ice_debugfs_enable_write - write into 'enable' file
+ * @filp: the opened file
+ * @buf: where to find the user's data
+ * @count: the length of the user's data
+ * @ppos: file position offset
+ */
+static ssize_t
+ice_debugfs_enable_write(struct file *filp, const char __user *buf,
+                        size_t count, loff_t *ppos)
+{
+       struct ice_pf *pf = filp->private_data;
+       struct ice_hw *hw = &pf->hw;
+       char user_val[8], *cmd_buf;
+       bool enable;
+       ssize_t ret;
+
+       /* don't allow partial writes or invalid input */
+       if (*ppos != 0 || count > 2)
+               return -EINVAL;
+
+       cmd_buf = memdup_user(buf, count);
+       if (IS_ERR(cmd_buf))
+               return PTR_ERR(cmd_buf);
+
+       ret = sscanf(cmd_buf, "%s", user_val);
+       if (ret != 1)
+               return -EINVAL;
+
+       ret = kstrtobool(user_val, &enable);
+       if (ret)
+               goto enable_write_error;
+
+       if (enable)
+               hw->fwlog_cfg.options |= ICE_FWLOG_OPTION_ARQ_ENA;
+       else
+               hw->fwlog_cfg.options &= ~ICE_FWLOG_OPTION_ARQ_ENA;
+
+       ret = ice_fwlog_set(hw, &hw->fwlog_cfg);
+       if (ret)
+               goto enable_write_error;
+
+       if (enable)
+               ret = ice_fwlog_register(hw);
+       else
+               ret = ice_fwlog_unregister(hw);
+
+       if (ret)
+               goto enable_write_error;
+
+       /* if we get here, nothing went wrong; return count since we didn't
+        * really write anything
+        */
+       ret = (ssize_t)count;
+
+enable_write_error:
+       /* This function always consumes all of the written input, or produces
+        * an error. Check and enforce this. Otherwise, the write operation
+        * won't complete properly.
+        */
+       if (WARN_ON(ret != (ssize_t)count && ret >= 0))
+               ret = -EIO;
+
+       return ret;
+}
+
+static const struct file_operations ice_debugfs_enable_fops = {
+       .owner = THIS_MODULE,
+       .open  = simple_open,
+       .read = ice_debugfs_enable_read,
+       .write = ice_debugfs_enable_write,
+};
+
 /**
  * ice_debugfs_fwlog_init - setup the debugfs directory
  * @pf: the ice that is starting up
@@ -332,6 +427,9 @@ void ice_debugfs_fwlog_init(struct ice_pf *pf)
 
        pf->ice_debugfs_pf_fwlog_modules = fw_modules;
 
+       debugfs_create_file("enable", 0600, pf->ice_debugfs_pf_fwlog,
+                           pf, &ice_debugfs_enable_fops);
+
        return;
 
 err_create_module_files:
index 307e0d04f3fe534a8e4b2b3e68aa4998e97a50fe..25a17cbc1d34c712848d057ef12fa7b008a3350a 100644 (file)
@@ -63,6 +63,11 @@ void ice_fwlog_deinit(struct ice_hw *hw)
        kfree(pf->ice_debugfs_pf_fwlog_modules);
 
        pf->ice_debugfs_pf_fwlog_modules = NULL;
+
+       status = ice_fwlog_unregister(hw);
+       if (status)
+               dev_warn(ice_hw_to_dev(hw), "Unable to unregister FW logging, status: %d\n",
+                        status);
 }
 
 /**
@@ -197,6 +202,8 @@ static int ice_aq_fwlog_get(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
                cfg->options |= ICE_FWLOG_OPTION_ARQ_ENA;
        if (cmd->cmd_flags & ICE_AQC_FW_LOG_CONF_UART_EN)
                cfg->options |= ICE_FWLOG_OPTION_UART_ENA;
+       if (cmd->cmd_flags & ICE_AQC_FW_LOG_QUERY_REGISTERED)
+               cfg->options |= ICE_FWLOG_OPTION_IS_REGISTERED;
 
        fw_modules = (struct ice_aqc_fw_log_cfg_resp *)buf;
 
@@ -226,6 +233,66 @@ int ice_fwlog_get(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
        return ice_aq_fwlog_get(hw, cfg);
 }
 
+/**
+ * ice_aq_fwlog_register - Register PF for firmware logging events (0xFF31)
+ * @hw: pointer to the HW structure
+ * @reg: true to register and false to unregister
+ */
+static int ice_aq_fwlog_register(struct ice_hw *hw, bool reg)
+{
+       struct ice_aq_desc desc;
+
+       ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logs_register);
+
+       if (reg)
+               desc.params.fw_log.cmd_flags = ICE_AQC_FW_LOG_AQ_REGISTER;
+
+       return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
+}
+
+/**
+ * ice_fwlog_register - Register the PF for firmware logging
+ * @hw: pointer to the HW structure
+ *
+ * After this call the PF will start to receive firmware logging based on the
+ * configuration set in ice_fwlog_set.
+ */
+int ice_fwlog_register(struct ice_hw *hw)
+{
+       int status;
+
+       if (!ice_fwlog_supported(hw))
+               return -EOPNOTSUPP;
+
+       status = ice_aq_fwlog_register(hw, true);
+       if (status)
+               ice_debug(hw, ICE_DBG_FW_LOG, "Failed to register for firmware logging events over ARQ\n");
+       else
+               hw->fwlog_cfg.options |= ICE_FWLOG_OPTION_IS_REGISTERED;
+
+       return status;
+}
+
+/**
+ * ice_fwlog_unregister - Unregister the PF from firmware logging
+ * @hw: pointer to the HW structure
+ */
+int ice_fwlog_unregister(struct ice_hw *hw)
+{
+       int status;
+
+       if (!ice_fwlog_supported(hw))
+               return -EOPNOTSUPP;
+
+       status = ice_aq_fwlog_register(hw, false);
+       if (status)
+               ice_debug(hw, ICE_DBG_FW_LOG, "Failed to unregister from firmware logging events over ARQ\n");
+       else
+               hw->fwlog_cfg.options &= ~ICE_FWLOG_OPTION_IS_REGISTERED;
+
+       return status;
+}
+
 /**
  * ice_fwlog_set_supported - Set if FW logging is supported by FW
  * @hw: pointer to the HW struct
index 8e68ee02713b30676bfd4fdf92a102e190dacc53..45865558425d81553664444429fd0151aea3b9e3 100644 (file)
@@ -53,4 +53,6 @@ int ice_fwlog_init(struct ice_hw *hw);
 void ice_fwlog_deinit(struct ice_hw *hw);
 int ice_fwlog_set(struct ice_hw *hw, struct ice_fwlog_cfg *cfg);
 int ice_fwlog_get(struct ice_hw *hw, struct ice_fwlog_cfg *cfg);
+int ice_fwlog_register(struct ice_hw *hw);
+int ice_fwlog_unregister(struct ice_hw *hw);
 #endif /* _ICE_FWLOG_H_ */