Commit 283f105b authored by David S. Miller's avatar David S. Miller

Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue

Tony Nguyen says:

====================
add v2 FW logging for ice driver

Paul Stillwell says:

Firmware (FW) log support was added to the ice driver, but that version is
no longer supported. There is a newer version of FW logging (v2) that
adds more control knobs to get the exact data out of the FW
for debugging.

The interface for FW logging is debugfs. This was chosen based on
discussions here:
https://lore.kernel.org/netdev/20230214180712.53fc8ba2@kernel.org/ and
https://lore.kernel.org/netdev/20231012164033.1069fb4b@kernel.org/

We talked about using devlink in a variety of ways, but none of those
options made any sense for the way the FW reports data. We briefly talked
about using ethtool, but that seemed to go by the wayside. Ultimately it
seems like using debugfs is the way to go so re-implement the code to use
that.

FW logging is across all the PFs on the device so restrict the commands to
only PF0.

If the device supports FW logging then a directory named 'fwlog' will be
created under '/sys/kernel/debug/ice/<pci_dev>'. A variety of files will be
created to manage the behavior of logging. The following files will be
created:
- modules/<module>
- nr_messages
- enable
- log_size
- data

where
modules/<module> is used to read/write the log level for a specific module

nr_messages is used to determine how many events should be in each message
sent to the driver

enable is used to start/stop FW logging. This is a boolean value so only 1
or 0 are permissible values

log_size is used to configure the amount of memory the driver uses for log
data

data is used to read/clear the log data

Generally there is a lot of data and dumping that data to syslog will
result in a loss of data. This causes problems when decoding the data and
the user doesn't know that data is missing until later. Instead of dumping
the FW log output to syslog use debugfs. This ensures that all the data the
driver has gets retrieved correctly.

The FW log data is binary data that the FW team decodes to determine what
happened in firmware. The binary blob is sent to Intel for decoding.
---
v6:
- use seq_printf() for outputting module info when reading from 'module' file
- replace code that created argc and argv for handling command line input
- removed checks in all the _read() and _write() functions to see if FW logging
  is supported because the files will not exist if it is not supported
- removed warnings on allocation failures on debugfs file creation failures
- removed a newline between memory allocation and checking if the memory was
  allocated
- fixed cases where we could just return the value from a function call
  instead of saving the value in a variable
- moved the check for PFO in ice_fwlog_init() to an earlier patch
- reworked all of argument scanning in the _write() functions in ice_debugfs.c
  to remove adding characters past the end of the buffer

v5: https://lore.kernel.org/netdev/20231205211251.2122874-1-anthony.l.nguyen@intel.com/
- changed the log level configuration from a single file for all modules to a
  file per module.
- changed 'nr_buffs' to 'log_size' because users understand memory sizes
  better than a number of buffers
- changed 'resolution' to 'nr_messages' to better reflect what it represents
- updated documentation to reflect these changes
- updated documentation to indicate that FW logging must be disabled to
  clear the data. also clarified that any value written to the 'data' file will
  clear the data

v4: https://lore.kernel.org/netdev/20231005170110.3221306-1-anthony.l.nguyen@intel.com/
- removed CONFIG_DEBUG_FS wrapper around code because the debugfs calls handle
  this case already
- moved ice_debugfs_exit() call to remove unreachable code issue
- minor changes to documentation based on feedback

v3: https://lore.kernel.org/netdev/20230815165750.2789609-1-anthony.l.nguyen@intel.com/
- Adjust error path cleanup in ice_module_init() for unreachable code.

v2: https://lore.kernel.org/netdev/20230810170109.1963832-1-anthony.l.nguyen@intel.com/
- Rewrote code to use debugfs instead of devlink

v1: https://lore.kernel.org/netdev/20230209190702.3638688-1-anthony.l.nguyen@intel.com/
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b84d66b0 d96f04e0
......@@ -895,6 +895,147 @@ driver writes raw bytes by the GNSS object to the receiver through i2c. Please
refer to the hardware GNSS module documentation for configuration details.
Firmware (FW) logging
---------------------
The driver supports FW logging via the debugfs interface on PF 0 only. The FW
running on the NIC must support FW logging; if the FW doesn't support FW logging
the 'fwlog' file will not get created in the ice debugfs directory.
Module configuration
~~~~~~~~~~~~~~~~~~~~
Firmware logging is configured on a per module basis. Each module can be set to
a value independent of the other modules (unless the module 'all' is specified).
The modules will be instantiated under the 'fwlog/modules' directory.
The user can set the log level for a module by writing to the module file like
this::
# echo <log_level> > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/modules/<module>
where
* log_level is a name as described below. Each level includes the
messages from the previous/lower level
* none
* error
* warning
* normal
* verbose
* module is a name that represents the module to receive events for. The
module names are
* general
* ctrl
* link
* link_topo
* dnl
* i2c
* sdp
* mdio
* adminq
* hdma
* lldp
* dcbx
* dcb
* xlr
* nvm
* auth
* vpd
* iosf
* parser
* sw
* scheduler
* txq
* rsvd
* post
* watchdog
* task_dispatch
* mng
* synce
* health
* tsdrv
* pfreg
* mdlver
* all
The name 'all' is special and allows the user to set all of the modules to the
specified log_level or to read the log_level of all of the modules.
Example usage to configure the modules
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To set a single module to 'verbose'::
# echo verbose > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/modules/link
To set multiple modules then issue the command multiple times::
# echo verbose > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/modules/link
# echo warning > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/modules/ctrl
# echo none > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/modules/dcb
To set all the modules to the same value::
# echo normal > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/modules/all
To read the log_level of a specific module (e.g. module 'general')::
# cat /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/modules/general
To read the log_level of all the modules::
# cat /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/modules/all
Enabling FW log
~~~~~~~~~~~~~~~
Configuring the modules indicates to the FW that the configured modules should
generate events that the driver is interested in, but it **does not** send the
events to the driver until the enable message is sent to the FW. To do this
the user can write a 1 (enable) or 0 (disable) to 'fwlog/enable'. An example
is::
# echo 1 > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/enable
Retrieving FW log data
~~~~~~~~~~~~~~~~~~~~~~
The FW log data can be retrieved by reading from 'fwlog/data'. The user can
write any value to 'fwlog/data' to clear the data. The data can only be cleared
when FW logging is disabled. The FW log data is a binary file that is sent to
Intel and used to help debug user issues.
An example to read the data is::
# cat /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/data > fwlog.bin
An example to clear the data is::
# echo 0 > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/data
Changing how often the log events are sent to the driver
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The driver receives FW log data from the Admin Receive Queue (ARQ). The
frequency that the FW sends the ARQ events can be configured by writing to
'fwlog/nr_messages'. The range is 1-128 (1 means push every log message, 128
means push only when the max AQ command buffer is full). The suggested value is
10. The user can see what the value is configured to by reading
'fwlog/nr_messages'. An example to set the value is::
# echo 50 > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/nr_messages
Configuring the amount of memory used to store FW log data
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The driver stores FW log data within the driver. The default size of the memory
used to store the data is 1MB. Some use cases may require more or less data so
the user can change the amount of memory that is allocated for FW log data.
To change the amount of memory then write to 'fwlog/log_size'. The value must be
one of: 128K, 256K, 512K, 1M, or 2M. FW logging must be disabled to change the
value. An example of changing the value is::
# echo 128K > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/log_size
Performance Optimization
========================
Driver defaults are meant to fit a wide variety of workloads, but if further
......
......@@ -34,7 +34,9 @@ ice-y := ice_main.o \
ice_lag.o \
ice_ethtool.o \
ice_repr.o \
ice_tc_lib.o
ice_tc_lib.o \
ice_fwlog.o \
ice_debugfs.o
ice-$(CONFIG_PCI_IOV) += \
ice_sriov.o \
ice_virtchnl.o \
......
......@@ -571,6 +571,10 @@ struct ice_pf {
struct ice_vsi_stats **vsi_stats;
struct ice_sw *first_sw; /* first switch created by firmware */
u16 eswitch_mode; /* current mode of eswitch */
struct dentry *ice_debugfs_pf;
struct dentry *ice_debugfs_pf_fwlog;
/* keep track of all the dentrys for FW log modules */
struct dentry **ice_debugfs_pf_fwlog_modules;
struct ice_vfs vfs;
DECLARE_BITMAP(features, ICE_F_MAX);
DECLARE_BITMAP(state, ICE_STATE_NBITS);
......@@ -890,6 +894,11 @@ static inline bool ice_is_adq_active(struct ice_pf *pf)
return false;
}
void ice_debugfs_fwlog_init(struct ice_pf *pf);
void ice_debugfs_init(void);
void ice_debugfs_exit(void);
void ice_pf_fwlog_update_module(struct ice_pf *pf, int log_level, int module);
bool netif_is_ice(const struct net_device *dev);
int ice_vsi_setup_tx_rings(struct ice_vsi *vsi);
int ice_vsi_setup_rx_rings(struct ice_vsi *vsi);
......
......@@ -2094,78 +2094,6 @@ struct ice_aqc_add_rdma_qset_data {
struct ice_aqc_add_tx_rdma_qset_entry rdma_qsets[];
};
/* Configure Firmware Logging Command (indirect 0xFF09)
* Logging Information Read Response (indirect 0xFF10)
* Note: The 0xFF10 command has no input parameters.
*/
struct ice_aqc_fw_logging {
u8 log_ctrl;
#define ICE_AQC_FW_LOG_AQ_EN BIT(0)
#define ICE_AQC_FW_LOG_UART_EN BIT(1)
u8 rsvd0;
u8 log_ctrl_valid; /* Not used by 0xFF10 Response */
#define ICE_AQC_FW_LOG_AQ_VALID BIT(0)
#define ICE_AQC_FW_LOG_UART_VALID BIT(1)
u8 rsvd1[5];
__le32 addr_high;
__le32 addr_low;
};
enum ice_aqc_fw_logging_mod {
ICE_AQC_FW_LOG_ID_GENERAL = 0,
ICE_AQC_FW_LOG_ID_CTRL,
ICE_AQC_FW_LOG_ID_LINK,
ICE_AQC_FW_LOG_ID_LINK_TOPO,
ICE_AQC_FW_LOG_ID_DNL,
ICE_AQC_FW_LOG_ID_I2C,
ICE_AQC_FW_LOG_ID_SDP,
ICE_AQC_FW_LOG_ID_MDIO,
ICE_AQC_FW_LOG_ID_ADMINQ,
ICE_AQC_FW_LOG_ID_HDMA,
ICE_AQC_FW_LOG_ID_LLDP,
ICE_AQC_FW_LOG_ID_DCBX,
ICE_AQC_FW_LOG_ID_DCB,
ICE_AQC_FW_LOG_ID_NETPROXY,
ICE_AQC_FW_LOG_ID_NVM,
ICE_AQC_FW_LOG_ID_AUTH,
ICE_AQC_FW_LOG_ID_VPD,
ICE_AQC_FW_LOG_ID_IOSF,
ICE_AQC_FW_LOG_ID_PARSER,
ICE_AQC_FW_LOG_ID_SW,
ICE_AQC_FW_LOG_ID_SCHEDULER,
ICE_AQC_FW_LOG_ID_TXQ,
ICE_AQC_FW_LOG_ID_RSVD,
ICE_AQC_FW_LOG_ID_POST,
ICE_AQC_FW_LOG_ID_WATCHDOG,
ICE_AQC_FW_LOG_ID_TASK_DISPATCH,
ICE_AQC_FW_LOG_ID_MNG,
ICE_AQC_FW_LOG_ID_MAX,
};
/* Defines for both above FW logging command/response buffers */
#define ICE_AQC_FW_LOG_ID_S 0
#define ICE_AQC_FW_LOG_ID_M (0xFFF << ICE_AQC_FW_LOG_ID_S)
#define ICE_AQC_FW_LOG_CONF_SUCCESS 0 /* Used by response */
#define ICE_AQC_FW_LOG_CONF_BAD_INDX BIT(12) /* Used by response */
#define ICE_AQC_FW_LOG_EN_S 12
#define ICE_AQC_FW_LOG_EN_M (0xF << ICE_AQC_FW_LOG_EN_S)
#define ICE_AQC_FW_LOG_INFO_EN BIT(12) /* Used by command */
#define ICE_AQC_FW_LOG_INIT_EN BIT(13) /* Used by command */
#define ICE_AQC_FW_LOG_FLOW_EN BIT(14) /* Used by command */
#define ICE_AQC_FW_LOG_ERR_EN BIT(15) /* Used by command */
/* Get/Clear FW Log (indirect 0xFF11) */
struct ice_aqc_get_clear_fw_log {
u8 flags;
#define ICE_AQC_FW_LOG_CLEAR BIT(0)
#define ICE_AQC_FW_LOG_MORE_DATA_AVAIL BIT(1)
u8 rsvd1[7];
__le32 addr_high;
__le32 addr_low;
};
/* Download Package (indirect 0x0C40) */
/* Also used for Update Package (indirect 0x0C41 and 0x0C42) */
struct ice_aqc_download_pkg {
......@@ -2428,6 +2356,84 @@ struct ice_aqc_event_lan_overflow {
u8 reserved[8];
};
enum ice_aqc_fw_logging_mod {
ICE_AQC_FW_LOG_ID_GENERAL = 0,
ICE_AQC_FW_LOG_ID_CTRL,
ICE_AQC_FW_LOG_ID_LINK,
ICE_AQC_FW_LOG_ID_LINK_TOPO,
ICE_AQC_FW_LOG_ID_DNL,
ICE_AQC_FW_LOG_ID_I2C,
ICE_AQC_FW_LOG_ID_SDP,
ICE_AQC_FW_LOG_ID_MDIO,
ICE_AQC_FW_LOG_ID_ADMINQ,
ICE_AQC_FW_LOG_ID_HDMA,
ICE_AQC_FW_LOG_ID_LLDP,
ICE_AQC_FW_LOG_ID_DCBX,
ICE_AQC_FW_LOG_ID_DCB,
ICE_AQC_FW_LOG_ID_XLR,
ICE_AQC_FW_LOG_ID_NVM,
ICE_AQC_FW_LOG_ID_AUTH,
ICE_AQC_FW_LOG_ID_VPD,
ICE_AQC_FW_LOG_ID_IOSF,
ICE_AQC_FW_LOG_ID_PARSER,
ICE_AQC_FW_LOG_ID_SW,
ICE_AQC_FW_LOG_ID_SCHEDULER,
ICE_AQC_FW_LOG_ID_TXQ,
ICE_AQC_FW_LOG_ID_RSVD,
ICE_AQC_FW_LOG_ID_POST,
ICE_AQC_FW_LOG_ID_WATCHDOG,
ICE_AQC_FW_LOG_ID_TASK_DISPATCH,
ICE_AQC_FW_LOG_ID_MNG,
ICE_AQC_FW_LOG_ID_SYNCE,
ICE_AQC_FW_LOG_ID_HEALTH,
ICE_AQC_FW_LOG_ID_TSDRV,
ICE_AQC_FW_LOG_ID_PFREG,
ICE_AQC_FW_LOG_ID_MDLVER,
ICE_AQC_FW_LOG_ID_MAX,
};
/* Set FW Logging configuration (indirect 0xFF30)
* Register for FW Logging (indirect 0xFF31)
* Query FW Logging (indirect 0xFF32)
* FW Log Event (indirect 0xFF33)
*/
struct ice_aqc_fw_log {
u8 cmd_flags;
#define ICE_AQC_FW_LOG_CONF_UART_EN BIT(0)
#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;
__le16 fw_rt_msb;
union {
struct {
__le32 fw_rt_lsb;
} sync;
struct {
__le16 log_resolution;
#define ICE_AQC_FW_LOG_MIN_RESOLUTION (1)
#define ICE_AQC_FW_LOG_MAX_RESOLUTION (128)
__le16 mdl_cnt;
} cfg;
} ops;
__le32 addr_high;
__le32 addr_low;
};
/* Response Buffer for:
* Set Firmware Logging Configuration (0xFF30)
* Query FW Logging (0xFF32)
*/
struct ice_aqc_fw_log_cfg_resp {
__le16 module_identifier;
u8 log_level;
u8 rsvd0;
};
/**
* struct ice_aq_desc - Admin Queue (AQ) descriptor
* @flags: ICE_AQ_FLAG_* flags
......@@ -2507,8 +2513,6 @@ struct ice_aq_desc {
struct ice_aqc_add_rdma_qset add_rdma_qset;
struct ice_aqc_add_get_update_free_vsi vsi_cmd;
struct ice_aqc_add_update_free_vsi_resp add_update_free_vsi_res;
struct ice_aqc_fw_logging fw_logging;
struct ice_aqc_get_clear_fw_log get_clear_fw_log;
struct ice_aqc_download_pkg download_pkg;
struct ice_aqc_set_cgu_input_config set_cgu_input_config;
struct ice_aqc_get_cgu_input_config get_cgu_input_config;
......@@ -2520,6 +2524,7 @@ struct ice_aq_desc {
struct ice_aqc_get_cgu_ref_prio get_cgu_ref_prio;
struct ice_aqc_get_cgu_info get_cgu_info;
struct ice_aqc_driver_shared_params drv_shared_params;
struct ice_aqc_fw_log fw_log;
struct ice_aqc_set_mac_lb set_mac_lb;
struct ice_aqc_alloc_free_res_cmd sw_res_ctrl;
struct ice_aqc_set_mac_cfg set_mac_cfg;
......@@ -2718,9 +2723,11 @@ enum ice_adminq_opc {
/* Standalone Commands/Events */
ice_aqc_opc_event_lan_overflow = 0x1001,
/* debug commands */
ice_aqc_opc_fw_logging = 0xFF09,
ice_aqc_opc_fw_logging_info = 0xFF10,
/* FW Logging Commands */
ice_aqc_opc_fw_logs_config = 0xFF30,
ice_aqc_opc_fw_logs_register = 0xFF31,
ice_aqc_opc_fw_logs_query = 0xFF32,
ice_aqc_opc_fw_logs_event = 0xFF33,
};
#endif /* _ICE_ADMINQ_CMD_H_ */
......@@ -933,216 +933,6 @@ static void ice_cleanup_fltr_mgmt_struct(struct ice_hw *hw)
devm_kfree(ice_hw_to_dev(hw), sw);
}
/**
* ice_get_fw_log_cfg - get FW logging configuration
* @hw: pointer to the HW struct
*/
static int ice_get_fw_log_cfg(struct ice_hw *hw)
{
struct ice_aq_desc desc;
__le16 *config;
int status;
u16 size;
size = sizeof(*config) * ICE_AQC_FW_LOG_ID_MAX;
config = kzalloc(size, GFP_KERNEL);
if (!config)
return -ENOMEM;
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logging_info);
status = ice_aq_send_cmd(hw, &desc, config, size, NULL);
if (!status) {
u16 i;
/* Save FW logging information into the HW structure */
for (i = 0; i < ICE_AQC_FW_LOG_ID_MAX; i++) {
u16 v, m, flgs;
v = le16_to_cpu(config[i]);
m = (v & ICE_AQC_FW_LOG_ID_M) >> ICE_AQC_FW_LOG_ID_S;
flgs = (v & ICE_AQC_FW_LOG_EN_M) >> ICE_AQC_FW_LOG_EN_S;
if (m < ICE_AQC_FW_LOG_ID_MAX)
hw->fw_log.evnts[m].cur = flgs;
}
}
kfree(config);
return status;
}
/**
* ice_cfg_fw_log - configure FW logging
* @hw: pointer to the HW struct
* @enable: enable certain FW logging events if true, disable all if false
*
* This function enables/disables the FW logging via Rx CQ events and a UART
* port based on predetermined configurations. FW logging via the Rx CQ can be
* enabled/disabled for individual PF's. However, FW logging via the UART can
* only be enabled/disabled for all PFs on the same device.
*
* To enable overall FW logging, the "cq_en" and "uart_en" enable bits in
* hw->fw_log need to be set accordingly, e.g. based on user-provided input,
* before initializing the device.
*
* When re/configuring FW logging, callers need to update the "cfg" elements of
* the hw->fw_log.evnts array with the desired logging event configurations for
* modules of interest. When disabling FW logging completely, the callers can
* just pass false in the "enable" parameter. On completion, the function will
* update the "cur" element of the hw->fw_log.evnts array with the resulting
* logging event configurations of the modules that are being re/configured. FW
* logging modules that are not part of a reconfiguration operation retain their
* previous states.
*
* Before resetting the device, it is recommended that the driver disables FW
* logging before shutting down the control queue. When disabling FW logging
* ("enable" = false), the latest configurations of FW logging events stored in
* hw->fw_log.evnts[] are not overridden to allow them to be reconfigured after
* a device reset.
*
* When enabling FW logging to emit log messages via the Rx CQ during the
* device's initialization phase, a mechanism alternative to interrupt handlers
* needs to be used to extract FW log messages from the Rx CQ periodically and
* to prevent the Rx CQ from being full and stalling other types of control
* messages from FW to SW. Interrupts are typically disabled during the device's
* initialization phase.
*/
static int ice_cfg_fw_log(struct ice_hw *hw, bool enable)
{
struct ice_aqc_fw_logging *cmd;
u16 i, chgs = 0, len = 0;
struct ice_aq_desc desc;
__le16 *data = NULL;
u8 actv_evnts = 0;
void *buf = NULL;
int status = 0;
if (!hw->fw_log.cq_en && !hw->fw_log.uart_en)
return 0;
/* Disable FW logging only when the control queue is still responsive */
if (!enable &&
(!hw->fw_log.actv_evnts || !ice_check_sq_alive(hw, &hw->adminq)))
return 0;
/* Get current FW log settings */
status = ice_get_fw_log_cfg(hw);
if (status)
return status;
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logging);
cmd = &desc.params.fw_logging;
/* Indicate which controls are valid */
if (hw->fw_log.cq_en)
cmd->log_ctrl_valid |= ICE_AQC_FW_LOG_AQ_VALID;
if (hw->fw_log.uart_en)
cmd->log_ctrl_valid |= ICE_AQC_FW_LOG_UART_VALID;
if (enable) {
/* Fill in an array of entries with FW logging modules and
* logging events being reconfigured.
*/
for (i = 0; i < ICE_AQC_FW_LOG_ID_MAX; i++) {
u16 val;
/* Keep track of enabled event types */
actv_evnts |= hw->fw_log.evnts[i].cfg;
if (hw->fw_log.evnts[i].cfg == hw->fw_log.evnts[i].cur)
continue;
if (!data) {
data = devm_kcalloc(ice_hw_to_dev(hw),
ICE_AQC_FW_LOG_ID_MAX,
sizeof(*data),
GFP_KERNEL);
if (!data)
return -ENOMEM;
}
val = i << ICE_AQC_FW_LOG_ID_S;
val |= hw->fw_log.evnts[i].cfg << ICE_AQC_FW_LOG_EN_S;
data[chgs++] = cpu_to_le16(val);
}
/* Only enable FW logging if at least one module is specified.
* If FW logging is currently enabled but all modules are not
* enabled to emit log messages, disable FW logging altogether.
*/
if (actv_evnts) {
/* Leave if there is effectively no change */
if (!chgs)
goto out;
if (hw->fw_log.cq_en)
cmd->log_ctrl |= ICE_AQC_FW_LOG_AQ_EN;
if (hw->fw_log.uart_en)
cmd->log_ctrl |= ICE_AQC_FW_LOG_UART_EN;
buf = data;
len = sizeof(*data) * chgs;
desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
}
}
status = ice_aq_send_cmd(hw, &desc, buf, len, NULL);
if (!status) {
/* Update the current configuration to reflect events enabled.
* hw->fw_log.cq_en and hw->fw_log.uart_en indicate if the FW
* logging mode is enabled for the device. They do not reflect
* actual modules being enabled to emit log messages. So, their
* values remain unchanged even when all modules are disabled.
*/
u16 cnt = enable ? chgs : (u16)ICE_AQC_FW_LOG_ID_MAX;
hw->fw_log.actv_evnts = actv_evnts;
for (i = 0; i < cnt; i++) {
u16 v, m;
if (!enable) {
/* When disabling all FW logging events as part
* of device's de-initialization, the original
* configurations are retained, and can be used
* to reconfigure FW logging later if the device
* is re-initialized.
*/
hw->fw_log.evnts[i].cur = 0;
continue;
}
v = le16_to_cpu(data[i]);
m = (v & ICE_AQC_FW_LOG_ID_M) >> ICE_AQC_FW_LOG_ID_S;
hw->fw_log.evnts[m].cur = hw->fw_log.evnts[m].cfg;
}
}
out:
devm_kfree(ice_hw_to_dev(hw), data);
return status;
}
/**
* ice_output_fw_log
* @hw: pointer to the HW struct
* @desc: pointer to the AQ message descriptor
* @buf: pointer to the buffer accompanying the AQ message
*
* Formats a FW Log message and outputs it via the standard driver logs.
*/
void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf)
{
ice_debug(hw, ICE_DBG_FW_LOG, "[ FW Log Msg Start ]\n");
ice_debug_array(hw, ICE_DBG_FW_LOG, 16, 1, (u8 *)buf,
le16_to_cpu(desc->datalen));
ice_debug(hw, ICE_DBG_FW_LOG, "[ FW Log Msg End ]\n");
}
/**
* ice_get_itr_intrl_gran
* @hw: pointer to the HW struct
......@@ -1200,10 +990,10 @@ int ice_init_hw(struct ice_hw *hw)
if (status)
goto err_unroll_cqinit;
/* Enable FW logging. Not fatal if this fails. */
status = ice_cfg_fw_log(hw, true);
status = ice_fwlog_init(hw);
if (status)
ice_debug(hw, ICE_DBG_INIT, "Failed to enable FW logging.\n");
ice_debug(hw, ICE_DBG_FW_LOG, "Error initializing FW logging: %d\n",
status);
status = ice_clear_pf_cfg(hw);
if (status)
......@@ -1354,8 +1144,7 @@ void ice_deinit_hw(struct ice_hw *hw)
ice_free_hw_tbls(hw);
mutex_destroy(&hw->tnl_lock);
/* Attempt to disable FW logging before shutting down control queues */
ice_cfg_fw_log(hw, false);
ice_fwlog_deinit(hw);
ice_destroy_all_ctrlq(hw);
/* Clear VSI contexts if not already cleared */
......
......@@ -200,7 +200,6 @@ ice_aq_cfg_lan_txq(struct ice_hw *hw, struct ice_aqc_cfg_txqs_buf *buf,
struct ice_sq_cd *cd);
int ice_replay_vsi(struct ice_hw *hw, u16 vsi_handle);
void ice_replay_post(struct ice_hw *hw);
void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf);
struct ice_q_ctx *
ice_get_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 q_handle);
int ice_sbq_rw_reg(struct ice_hw *hw, struct ice_sbq_msg_input *in);
......
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2022, Intel Corporation. */
#ifndef _ICE_FWLOG_H_
#define _ICE_FWLOG_H_
#include "ice_adminq_cmd.h"
struct ice_hw;
/* Only a single log level should be set and all log levels under the set value
* are enabled, e.g. if log level is set to ICE_FW_LOG_LEVEL_VERBOSE, then all
* other log levels are included (except ICE_FW_LOG_LEVEL_NONE)
*/
enum ice_fwlog_level {
ICE_FWLOG_LEVEL_NONE = 0,
ICE_FWLOG_LEVEL_ERROR = 1,
ICE_FWLOG_LEVEL_WARNING = 2,
ICE_FWLOG_LEVEL_NORMAL = 3,
ICE_FWLOG_LEVEL_VERBOSE = 4,
ICE_FWLOG_LEVEL_INVALID, /* all values >= this entry are invalid */
};
struct ice_fwlog_module_entry {
/* module ID for the corresponding firmware logging event */
u16 module_id;
/* verbosity level for the module_id */
u8 log_level;
};
struct ice_fwlog_cfg {
/* list of modules for configuring log level */
struct ice_fwlog_module_entry module_entries[ICE_AQC_FW_LOG_ID_MAX];
/* options used to configure firmware logging */
u16 options;
#define ICE_FWLOG_OPTION_ARQ_ENA BIT(0)
#define ICE_FWLOG_OPTION_UART_ENA BIT(1)
/* set before calling ice_fwlog_init() so the PF registers for firmware
* logging on initialization
*/
#define ICE_FWLOG_OPTION_REGISTER_ON_INIT BIT(2)
/* set in the ice_fwlog_get() response if the PF is registered for FW
* logging events over ARQ
*/
#define ICE_FWLOG_OPTION_IS_REGISTERED BIT(3)
/* minimum number of log events sent per Admin Receive Queue event */
u16 log_resolution;
};
struct ice_fwlog_data {
u16 data_size;
u8 *data;
};
struct ice_fwlog_ring {
struct ice_fwlog_data *rings;
u16 index;
u16 size;
u16 head;
u16 tail;
};
#define ICE_FWLOG_RING_SIZE_INDEX_DFLT 3
#define ICE_FWLOG_RING_SIZE_DFLT 256
#define ICE_FWLOG_RING_SIZE_MAX 512
bool ice_fwlog_ring_full(struct ice_fwlog_ring *rings);
bool ice_fwlog_ring_empty(struct ice_fwlog_ring *rings);
void ice_fwlog_ring_increment(u16 *item, u16 size);
void ice_fwlog_set_supported(struct ice_hw *hw);
bool ice_fwlog_supported(struct ice_hw *hw);
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);
void ice_fwlog_realloc_rings(struct ice_hw *hw, int index);
#endif /* _ICE_FWLOG_H_ */
......@@ -1252,6 +1252,32 @@ ice_handle_link_event(struct ice_pf *pf, struct ice_rq_event_info *event)
return status;
}
/**
* ice_get_fwlog_data - copy the FW log data from ARQ event
* @pf: PF that the FW log event is associated with
* @event: event structure containing FW log data
*/
static void
ice_get_fwlog_data(struct ice_pf *pf, struct ice_rq_event_info *event)
{
struct ice_fwlog_data *fwlog;
struct ice_hw *hw = &pf->hw;
fwlog = &hw->fwlog_ring.rings[hw->fwlog_ring.tail];
memset(fwlog->data, 0, PAGE_SIZE);
fwlog->data_size = le16_to_cpu(event->desc.datalen);
memcpy(fwlog->data, event->msg_buf, fwlog->data_size);
ice_fwlog_ring_increment(&hw->fwlog_ring.tail, hw->fwlog_ring.size);
if (ice_fwlog_ring_full(&hw->fwlog_ring)) {
/* the rings are full so bump the head to create room */
ice_fwlog_ring_increment(&hw->fwlog_ring.head,
hw->fwlog_ring.size);
}
}
/**
* ice_aq_prep_for_event - Prepare to wait for an AdminQ event from firmware
* @pf: pointer to the PF private structure
......@@ -1533,8 +1559,8 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type)
ice_vc_process_vf_msg(pf, &event, &data);
break;
case ice_aqc_opc_fw_logging:
ice_output_fw_log(hw, &event.desc, event.msg_buf);
case ice_aqc_opc_fw_logs_event:
ice_get_fwlog_data(pf, &event);
break;
case ice_aqc_opc_lldp_set_mib_change:
ice_dcb_process_lldp_set_mib_change(pf, &event);
......@@ -4363,6 +4389,19 @@ static void ice_print_wake_reason(struct ice_pf *pf)
dev_info(ice_pf_to_dev(pf), "Wake reason: %s", wake_str);
}
/**
* ice_pf_fwlog_update_module - update 1 module
* @pf: pointer to the PF struct
* @log_level: log_level to use for the @module
* @module: module to update
*/
void ice_pf_fwlog_update_module(struct ice_pf *pf, int log_level, int module)
{
struct ice_hw *hw = &pf->hw;
hw->fwlog_cfg.module_entries[module].log_level = log_level;
}
/**
* ice_register_netdev - register netdev
* @vsi: pointer to the VSI struct
......@@ -5210,6 +5249,8 @@ static void ice_remove(struct pci_dev *pdev)
msleep(100);
}
ice_debugfs_exit();
if (test_bit(ICE_FLAG_SRIOV_ENA, pf->flags)) {
set_bit(ICE_VF_RESETS_DISABLED, pf->state);
ice_free_vfs(pf);
......@@ -5681,6 +5722,8 @@ static int __init ice_module_init(void)
goto err_dest_wq;
}
ice_debugfs_init();
status = pci_register_driver(&ice_driver);
if (status) {
pr_err("failed to register PCI driver, err %d\n", status);
......@@ -5691,6 +5734,7 @@ static int __init ice_module_init(void)
err_dest_lag_wq:
destroy_workqueue(ice_lag_wq);
ice_debugfs_exit();
err_dest_wq:
destroy_workqueue(ice_wq);
return status;
......
......@@ -17,6 +17,7 @@
#include "ice_protocol_type.h"
#include "ice_sbq_cmd.h"
#include "ice_vlan_mode.h"
#include "ice_fwlog.h"
static inline bool ice_is_tc_ena(unsigned long bitmap, u8 tc)
{
......@@ -738,24 +739,6 @@ struct ice_switch_info {
DECLARE_BITMAP(prof_res_bm[ICE_MAX_NUM_PROFILES], ICE_MAX_FV_WORDS);
};
/* FW logging configuration */
struct ice_fw_log_evnt {
u8 cfg : 4; /* New event enables to configure */
u8 cur : 4; /* Current/active event enables */
};
struct ice_fw_log_cfg {
u8 cq_en : 1; /* FW logging is enabled via the control queue */
u8 uart_en : 1; /* FW logging is enabled via UART for all PFs */
u8 actv_evnts; /* Cumulation of currently enabled log events */
#define ICE_FW_LOG_EVNT_INFO (ICE_AQC_FW_LOG_INFO_EN >> ICE_AQC_FW_LOG_EN_S)
#define ICE_FW_LOG_EVNT_INIT (ICE_AQC_FW_LOG_INIT_EN >> ICE_AQC_FW_LOG_EN_S)
#define ICE_FW_LOG_EVNT_FLOW (ICE_AQC_FW_LOG_FLOW_EN >> ICE_AQC_FW_LOG_EN_S)
#define ICE_FW_LOG_EVNT_ERR (ICE_AQC_FW_LOG_ERR_EN >> ICE_AQC_FW_LOG_EN_S)
struct ice_fw_log_evnt evnts[ICE_AQC_FW_LOG_ID_MAX];
};
/* Enum defining the different states of the mailbox snapshot in the
* PF-VF mailbox overflow detection algorithm. The snapshot can be in
* states:
......@@ -897,7 +880,9 @@ struct ice_hw {
u8 fw_patch; /* firmware patch version */
u32 fw_build; /* firmware build number */
struct ice_fw_log_cfg fw_log;
struct ice_fwlog_cfg fwlog_cfg;
bool fwlog_supported; /* does hardware support FW logging? */
struct ice_fwlog_ring fwlog_ring;
/* Device max aggregate bandwidths corresponding to the GL_PWR_MODE_CTL
* register. Used for determining the ITR/INTRL granularity during
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment