xref: /freebsd/sys/dev/ice/ice_fwlog.c (revision f2635e844dd138ac9dfba676f27d41750049af26)
156429daeSEric Joyner /* SPDX-License-Identifier: BSD-3-Clause */
2015f8cc5SEric Joyner /*  Copyright (c) 2024, Intel Corporation
356429daeSEric Joyner  *  All rights reserved.
456429daeSEric Joyner  *
556429daeSEric Joyner  *  Redistribution and use in source and binary forms, with or without
656429daeSEric Joyner  *  modification, are permitted provided that the following conditions are met:
756429daeSEric Joyner  *
856429daeSEric Joyner  *   1. Redistributions of source code must retain the above copyright notice,
956429daeSEric Joyner  *      this list of conditions and the following disclaimer.
1056429daeSEric Joyner  *
1156429daeSEric Joyner  *   2. Redistributions in binary form must reproduce the above copyright
1256429daeSEric Joyner  *      notice, this list of conditions and the following disclaimer in the
1356429daeSEric Joyner  *      documentation and/or other materials provided with the distribution.
1456429daeSEric Joyner  *
1556429daeSEric Joyner  *   3. Neither the name of the Intel Corporation nor the names of its
1656429daeSEric Joyner  *      contributors may be used to endorse or promote products derived from
1756429daeSEric Joyner  *      this software without specific prior written permission.
1856429daeSEric Joyner  *
1956429daeSEric Joyner  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2056429daeSEric Joyner  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2156429daeSEric Joyner  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2256429daeSEric Joyner  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2356429daeSEric Joyner  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2456429daeSEric Joyner  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2556429daeSEric Joyner  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2656429daeSEric Joyner  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2756429daeSEric Joyner  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2856429daeSEric Joyner  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2956429daeSEric Joyner  *  POSSIBILITY OF SUCH DAMAGE.
3056429daeSEric Joyner  */
3156429daeSEric Joyner 
32*f2635e84SEric Joyner #include "ice_osdep.h"
3356429daeSEric Joyner #include "ice_common.h"
3456429daeSEric Joyner #include "ice_fwlog.h"
3556429daeSEric Joyner 
3656429daeSEric Joyner /**
3756429daeSEric Joyner  * cache_cfg - Cache FW logging config
3856429daeSEric Joyner  * @hw: pointer to the HW structure
3956429daeSEric Joyner  * @cfg: config to cache
4056429daeSEric Joyner  */
4156429daeSEric Joyner static void cache_cfg(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
4256429daeSEric Joyner {
4356429daeSEric Joyner 	hw->fwlog_cfg = *cfg;
4456429daeSEric Joyner }
4556429daeSEric Joyner 
4656429daeSEric Joyner /**
4756429daeSEric Joyner  * valid_module_entries - validate all the module entry IDs and log levels
4856429daeSEric Joyner  * @hw: pointer to the HW structure
4956429daeSEric Joyner  * @entries: entries to validate
5056429daeSEric Joyner  * @num_entries: number of entries to validate
5156429daeSEric Joyner  */
5256429daeSEric Joyner static bool
5356429daeSEric Joyner valid_module_entries(struct ice_hw *hw, struct ice_fwlog_module_entry *entries,
5456429daeSEric Joyner 		     u16 num_entries)
5556429daeSEric Joyner {
5656429daeSEric Joyner 	u16 i;
5756429daeSEric Joyner 
5856429daeSEric Joyner 	if (!entries) {
5956429daeSEric Joyner 		ice_debug(hw, ICE_DBG_FW_LOG, "Null ice_fwlog_module_entry array\n");
6056429daeSEric Joyner 		return false;
6156429daeSEric Joyner 	}
6256429daeSEric Joyner 
6356429daeSEric Joyner 	if (!num_entries) {
6456429daeSEric Joyner 		ice_debug(hw, ICE_DBG_FW_LOG, "num_entries must be non-zero\n");
6556429daeSEric Joyner 		return false;
6656429daeSEric Joyner 	}
6756429daeSEric Joyner 
6856429daeSEric Joyner 	for (i = 0; i < num_entries; i++) {
6956429daeSEric Joyner 		struct ice_fwlog_module_entry *entry = &entries[i];
7056429daeSEric Joyner 
7156429daeSEric Joyner 		if (entry->module_id >= ICE_AQC_FW_LOG_ID_MAX) {
7256429daeSEric Joyner 			ice_debug(hw, ICE_DBG_FW_LOG, "Invalid module_id %u, max valid module_id is %u\n",
7356429daeSEric Joyner 				  entry->module_id, ICE_AQC_FW_LOG_ID_MAX - 1);
7456429daeSEric Joyner 			return false;
7556429daeSEric Joyner 		}
7656429daeSEric Joyner 
7756429daeSEric Joyner 		if (entry->log_level >= ICE_FWLOG_LEVEL_INVALID) {
7856429daeSEric Joyner 			ice_debug(hw, ICE_DBG_FW_LOG, "Invalid log_level %u, max valid log_level is %u\n",
7956429daeSEric Joyner 				  entry->log_level,
8056429daeSEric Joyner 				  ICE_AQC_FW_LOG_ID_MAX - 1);
8156429daeSEric Joyner 			return false;
8256429daeSEric Joyner 		}
8356429daeSEric Joyner 	}
8456429daeSEric Joyner 
8556429daeSEric Joyner 	return true;
8656429daeSEric Joyner }
8756429daeSEric Joyner 
8856429daeSEric Joyner /**
8956429daeSEric Joyner  * valid_cfg - validate entire configuration
9056429daeSEric Joyner  * @hw: pointer to the HW structure
9156429daeSEric Joyner  * @cfg: config to validate
9256429daeSEric Joyner  */
9356429daeSEric Joyner static bool valid_cfg(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
9456429daeSEric Joyner {
9556429daeSEric Joyner 	if (!cfg) {
9656429daeSEric Joyner 		ice_debug(hw, ICE_DBG_FW_LOG, "Null ice_fwlog_cfg\n");
9756429daeSEric Joyner 		return false;
9856429daeSEric Joyner 	}
9956429daeSEric Joyner 
10056429daeSEric Joyner 	if (cfg->log_resolution < ICE_AQC_FW_LOG_MIN_RESOLUTION ||
10156429daeSEric Joyner 	    cfg->log_resolution > ICE_AQC_FW_LOG_MAX_RESOLUTION) {
10256429daeSEric Joyner 		ice_debug(hw, ICE_DBG_FW_LOG, "Unsupported log_resolution %u, must be between %u and %u\n",
10356429daeSEric Joyner 			  cfg->log_resolution, ICE_AQC_FW_LOG_MIN_RESOLUTION,
10456429daeSEric Joyner 			  ICE_AQC_FW_LOG_MAX_RESOLUTION);
10556429daeSEric Joyner 		return false;
10656429daeSEric Joyner 	}
10756429daeSEric Joyner 
10856429daeSEric Joyner 	if (!valid_module_entries(hw, cfg->module_entries,
10956429daeSEric Joyner 				  ICE_AQC_FW_LOG_ID_MAX))
11056429daeSEric Joyner 		return false;
11156429daeSEric Joyner 
11256429daeSEric Joyner 	return true;
11356429daeSEric Joyner }
11456429daeSEric Joyner 
11556429daeSEric Joyner /**
11656429daeSEric Joyner  * ice_fwlog_init - Initialize cached structures for tracking FW logging
11756429daeSEric Joyner  * @hw: pointer to the HW structure
11856429daeSEric Joyner  * @cfg: config used to initialize the cached structures
11956429daeSEric Joyner  *
12056429daeSEric Joyner  * This function should be called on driver initialization and before calling
12156429daeSEric Joyner  * ice_init_hw(). Firmware logging will be configured based on these settings
12256429daeSEric Joyner  * and also the PF will be registered on init.
12356429daeSEric Joyner  */
124*f2635e84SEric Joyner int
12556429daeSEric Joyner ice_fwlog_init(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
12656429daeSEric Joyner {
12756429daeSEric Joyner 	if (!valid_cfg(hw, cfg))
12856429daeSEric Joyner 		return ICE_ERR_PARAM;
12956429daeSEric Joyner 
13056429daeSEric Joyner 	cache_cfg(hw, cfg);
13156429daeSEric Joyner 
132*f2635e84SEric Joyner 	return 0;
13356429daeSEric Joyner }
13456429daeSEric Joyner 
13556429daeSEric Joyner /**
13656429daeSEric Joyner  * ice_aq_fwlog_set - Set FW logging configuration AQ command (0xFF30)
13756429daeSEric Joyner  * @hw: pointer to the HW structure
13856429daeSEric Joyner  * @entries: entries to configure
13956429daeSEric Joyner  * @num_entries: number of @entries
14056429daeSEric Joyner  * @options: options from ice_fwlog_cfg->options structure
14156429daeSEric Joyner  * @log_resolution: logging resolution
14256429daeSEric Joyner  */
143*f2635e84SEric Joyner static int
14456429daeSEric Joyner ice_aq_fwlog_set(struct ice_hw *hw, struct ice_fwlog_module_entry *entries,
14556429daeSEric Joyner 		 u16 num_entries, u16 options, u16 log_resolution)
14656429daeSEric Joyner {
14756429daeSEric Joyner 	struct ice_aqc_fw_log_cfg_resp *fw_modules;
14856429daeSEric Joyner 	struct ice_aqc_fw_log *cmd;
14956429daeSEric Joyner 	struct ice_aq_desc desc;
150*f2635e84SEric Joyner 	int status;
15156429daeSEric Joyner 	u16 i;
15256429daeSEric Joyner 
15356429daeSEric Joyner 	fw_modules = (struct ice_aqc_fw_log_cfg_resp *)
15456429daeSEric Joyner 		ice_calloc(hw, num_entries, sizeof(*fw_modules));
15556429daeSEric Joyner 	if (!fw_modules)
15656429daeSEric Joyner 		return ICE_ERR_NO_MEMORY;
15756429daeSEric Joyner 
15856429daeSEric Joyner 	for (i = 0; i < num_entries; i++) {
15956429daeSEric Joyner 		fw_modules[i].module_identifier =
16056429daeSEric Joyner 			CPU_TO_LE16(entries[i].module_id);
16156429daeSEric Joyner 		fw_modules[i].log_level = entries[i].log_level;
16256429daeSEric Joyner 	}
16356429daeSEric Joyner 
16456429daeSEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logs_config);
16556429daeSEric Joyner 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
16656429daeSEric Joyner 
16756429daeSEric Joyner 	cmd = &desc.params.fw_log;
16856429daeSEric Joyner 
16956429daeSEric Joyner 	cmd->cmd_flags = ICE_AQC_FW_LOG_CONF_SET_VALID;
17056429daeSEric Joyner 	cmd->ops.cfg.log_resolution = CPU_TO_LE16(log_resolution);
17156429daeSEric Joyner 	cmd->ops.cfg.mdl_cnt = CPU_TO_LE16(num_entries);
17256429daeSEric Joyner 
17356429daeSEric Joyner 	if (options & ICE_FWLOG_OPTION_ARQ_ENA)
17456429daeSEric Joyner 		cmd->cmd_flags |= ICE_AQC_FW_LOG_CONF_AQ_EN;
17556429daeSEric Joyner 	if (options & ICE_FWLOG_OPTION_UART_ENA)
17656429daeSEric Joyner 		cmd->cmd_flags |= ICE_AQC_FW_LOG_CONF_UART_EN;
17756429daeSEric Joyner 
17856429daeSEric Joyner 	status = ice_aq_send_cmd(hw, &desc, fw_modules,
17956429daeSEric Joyner 				 sizeof(*fw_modules) * num_entries,
18056429daeSEric Joyner 				 NULL);
18156429daeSEric Joyner 
18256429daeSEric Joyner 	ice_free(hw, fw_modules);
18356429daeSEric Joyner 
18456429daeSEric Joyner 	return status;
18556429daeSEric Joyner }
18656429daeSEric Joyner 
18756429daeSEric Joyner /**
18856429daeSEric Joyner  * ice_fwlog_supported - Cached for whether FW supports FW logging or not
18956429daeSEric Joyner  * @hw: pointer to the HW structure
19056429daeSEric Joyner  *
19156429daeSEric Joyner  * This will always return false if called before ice_init_hw(), so it must be
19256429daeSEric Joyner  * called after ice_init_hw().
19356429daeSEric Joyner  */
19456429daeSEric Joyner bool ice_fwlog_supported(struct ice_hw *hw)
19556429daeSEric Joyner {
19656429daeSEric Joyner 	return hw->fwlog_support_ena;
19756429daeSEric Joyner }
19856429daeSEric Joyner 
19956429daeSEric Joyner /**
20056429daeSEric Joyner  * ice_fwlog_set - Set the firmware logging settings
20156429daeSEric Joyner  * @hw: pointer to the HW structure
20256429daeSEric Joyner  * @cfg: config used to set firmware logging
20356429daeSEric Joyner  *
20456429daeSEric Joyner  * This function should be called whenever the driver needs to set the firmware
20556429daeSEric Joyner  * logging configuration. It can be called on initialization, reset, or during
20656429daeSEric Joyner  * runtime.
20756429daeSEric Joyner  *
20856429daeSEric Joyner  * If the PF wishes to receive FW logging then it must register via
20956429daeSEric Joyner  * ice_fwlog_register. Note, that ice_fwlog_register does not need to be called
21056429daeSEric Joyner  * for init.
21156429daeSEric Joyner  */
212*f2635e84SEric Joyner int
21356429daeSEric Joyner ice_fwlog_set(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
21456429daeSEric Joyner {
215*f2635e84SEric Joyner 	int status;
21656429daeSEric Joyner 
21756429daeSEric Joyner 	if (!ice_fwlog_supported(hw))
21856429daeSEric Joyner 		return ICE_ERR_NOT_SUPPORTED;
21956429daeSEric Joyner 
22056429daeSEric Joyner 	if (!valid_cfg(hw, cfg))
22156429daeSEric Joyner 		return ICE_ERR_PARAM;
22256429daeSEric Joyner 
22356429daeSEric Joyner 	status = ice_aq_fwlog_set(hw, cfg->module_entries,
22456429daeSEric Joyner 				  ICE_AQC_FW_LOG_ID_MAX, cfg->options,
22556429daeSEric Joyner 				  cfg->log_resolution);
22656429daeSEric Joyner 	if (!status)
22756429daeSEric Joyner 		cache_cfg(hw, cfg);
22856429daeSEric Joyner 
22956429daeSEric Joyner 	return status;
23056429daeSEric Joyner }
23156429daeSEric Joyner 
23256429daeSEric Joyner /**
23356429daeSEric Joyner  * update_cached_entries - Update module entries in cached FW logging config
23456429daeSEric Joyner  * @hw: pointer to the HW structure
23556429daeSEric Joyner  * @entries: entries to cache
23656429daeSEric Joyner  * @num_entries: number of @entries
23756429daeSEric Joyner  */
23856429daeSEric Joyner static void
23956429daeSEric Joyner update_cached_entries(struct ice_hw *hw, struct ice_fwlog_module_entry *entries,
24056429daeSEric Joyner 		      u16 num_entries)
24156429daeSEric Joyner {
24256429daeSEric Joyner 	u16 i;
24356429daeSEric Joyner 
24456429daeSEric Joyner 	for (i = 0; i < num_entries; i++) {
24556429daeSEric Joyner 		struct ice_fwlog_module_entry *updated = &entries[i];
24656429daeSEric Joyner 		u16 j;
24756429daeSEric Joyner 
24856429daeSEric Joyner 		for (j = 0; j < ICE_AQC_FW_LOG_ID_MAX; j++) {
24956429daeSEric Joyner 			struct ice_fwlog_module_entry *cached =
25056429daeSEric Joyner 				&hw->fwlog_cfg.module_entries[j];
25156429daeSEric Joyner 
25256429daeSEric Joyner 			if (cached->module_id == updated->module_id) {
25356429daeSEric Joyner 				cached->log_level = updated->log_level;
25456429daeSEric Joyner 				break;
25556429daeSEric Joyner 			}
25656429daeSEric Joyner 		}
25756429daeSEric Joyner 	}
25856429daeSEric Joyner }
25956429daeSEric Joyner 
26056429daeSEric Joyner /**
26156429daeSEric Joyner  * ice_fwlog_update_modules - Update the log level 1 or more FW logging modules
26256429daeSEric Joyner  * @hw: pointer to the HW structure
26356429daeSEric Joyner  * @entries: array of ice_fwlog_module_entry(s)
26456429daeSEric Joyner  * @num_entries: number of entries
26556429daeSEric Joyner  *
26656429daeSEric Joyner  * This function should be called to update the log level of 1 or more FW
26756429daeSEric Joyner  * logging modules via module ID.
26856429daeSEric Joyner  *
26956429daeSEric Joyner  * Only the entries passed in will be affected. All other firmware logging
27056429daeSEric Joyner  * settings will be unaffected.
27156429daeSEric Joyner  */
272*f2635e84SEric Joyner int
27356429daeSEric Joyner ice_fwlog_update_modules(struct ice_hw *hw,
27456429daeSEric Joyner 			 struct ice_fwlog_module_entry *entries,
27556429daeSEric Joyner 			 u16 num_entries)
27656429daeSEric Joyner {
27756429daeSEric Joyner 	struct ice_fwlog_cfg *cfg;
278*f2635e84SEric Joyner 	int status;
27956429daeSEric Joyner 
28056429daeSEric Joyner 	if (!ice_fwlog_supported(hw))
28156429daeSEric Joyner 		return ICE_ERR_NOT_SUPPORTED;
28256429daeSEric Joyner 
28356429daeSEric Joyner 	if (!valid_module_entries(hw, entries, num_entries))
28456429daeSEric Joyner 		return ICE_ERR_PARAM;
28556429daeSEric Joyner 
28656429daeSEric Joyner 	cfg = (struct ice_fwlog_cfg *)ice_calloc(hw, 1, sizeof(*cfg));
28756429daeSEric Joyner 	if (!cfg)
28856429daeSEric Joyner 		return ICE_ERR_NO_MEMORY;
28956429daeSEric Joyner 
29056429daeSEric Joyner 	status = ice_fwlog_get(hw, cfg);
29156429daeSEric Joyner 	if (status)
29256429daeSEric Joyner 		goto status_out;
29356429daeSEric Joyner 
29456429daeSEric Joyner 	status = ice_aq_fwlog_set(hw, entries, num_entries, cfg->options,
29556429daeSEric Joyner 				  cfg->log_resolution);
29656429daeSEric Joyner 	if (!status)
29756429daeSEric Joyner 		update_cached_entries(hw, entries, num_entries);
29856429daeSEric Joyner 
29956429daeSEric Joyner status_out:
30056429daeSEric Joyner 	ice_free(hw, cfg);
30156429daeSEric Joyner 	return status;
30256429daeSEric Joyner }
30356429daeSEric Joyner 
30456429daeSEric Joyner /**
30556429daeSEric Joyner  * ice_aq_fwlog_register - Register PF for firmware logging events (0xFF31)
30656429daeSEric Joyner  * @hw: pointer to the HW structure
30756429daeSEric Joyner  * @reg: true to register and false to unregister
30856429daeSEric Joyner  */
309*f2635e84SEric Joyner static int ice_aq_fwlog_register(struct ice_hw *hw, bool reg)
31056429daeSEric Joyner {
31156429daeSEric Joyner 	struct ice_aq_desc desc;
31256429daeSEric Joyner 
31356429daeSEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logs_register);
31456429daeSEric Joyner 
31556429daeSEric Joyner 	if (reg)
31656429daeSEric Joyner 		desc.params.fw_log.cmd_flags = ICE_AQC_FW_LOG_AQ_REGISTER;
31756429daeSEric Joyner 
31856429daeSEric Joyner 	return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
31956429daeSEric Joyner }
32056429daeSEric Joyner 
32156429daeSEric Joyner /**
32256429daeSEric Joyner  * ice_fwlog_register - Register the PF for firmware logging
32356429daeSEric Joyner  * @hw: pointer to the HW structure
32456429daeSEric Joyner  *
32556429daeSEric Joyner  * After this call the PF will start to receive firmware logging based on the
32656429daeSEric Joyner  * configuration set in ice_fwlog_set.
32756429daeSEric Joyner  */
328*f2635e84SEric Joyner int ice_fwlog_register(struct ice_hw *hw)
32956429daeSEric Joyner {
330*f2635e84SEric Joyner 	int status;
33156429daeSEric Joyner 
33256429daeSEric Joyner 	if (!ice_fwlog_supported(hw))
33356429daeSEric Joyner 		return ICE_ERR_NOT_SUPPORTED;
33456429daeSEric Joyner 
33556429daeSEric Joyner 	status = ice_aq_fwlog_register(hw, true);
33656429daeSEric Joyner 	if (status)
33756429daeSEric Joyner 		ice_debug(hw, ICE_DBG_FW_LOG, "Failed to register for firmware logging events over ARQ\n");
33856429daeSEric Joyner 	else
33956429daeSEric Joyner 		hw->fwlog_cfg.options |= ICE_FWLOG_OPTION_IS_REGISTERED;
34056429daeSEric Joyner 
34156429daeSEric Joyner 	return status;
34256429daeSEric Joyner }
34356429daeSEric Joyner 
34456429daeSEric Joyner /**
34556429daeSEric Joyner  * ice_fwlog_unregister - Unregister the PF from firmware logging
34656429daeSEric Joyner  * @hw: pointer to the HW structure
34756429daeSEric Joyner  */
348*f2635e84SEric Joyner int ice_fwlog_unregister(struct ice_hw *hw)
34956429daeSEric Joyner {
350*f2635e84SEric Joyner 	int status;
35156429daeSEric Joyner 
35256429daeSEric Joyner 	if (!ice_fwlog_supported(hw))
35356429daeSEric Joyner 		return ICE_ERR_NOT_SUPPORTED;
35456429daeSEric Joyner 
35556429daeSEric Joyner 	status = ice_aq_fwlog_register(hw, false);
35656429daeSEric Joyner 	if (status)
35756429daeSEric Joyner 		ice_debug(hw, ICE_DBG_FW_LOG, "Failed to unregister from firmware logging events over ARQ\n");
35856429daeSEric Joyner 	else
35956429daeSEric Joyner 		hw->fwlog_cfg.options &= ~ICE_FWLOG_OPTION_IS_REGISTERED;
36056429daeSEric Joyner 
36156429daeSEric Joyner 	return status;
36256429daeSEric Joyner }
36356429daeSEric Joyner 
36456429daeSEric Joyner /**
36556429daeSEric Joyner  * ice_aq_fwlog_get - Get the current firmware logging configuration (0xFF32)
36656429daeSEric Joyner  * @hw: pointer to the HW structure
36756429daeSEric Joyner  * @cfg: firmware logging configuration to populate
36856429daeSEric Joyner  */
369*f2635e84SEric Joyner static int
37056429daeSEric Joyner ice_aq_fwlog_get(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
37156429daeSEric Joyner {
37256429daeSEric Joyner 	struct ice_aqc_fw_log_cfg_resp *fw_modules;
37356429daeSEric Joyner 	struct ice_aqc_fw_log *cmd;
37456429daeSEric Joyner 	struct ice_aq_desc desc;
37556429daeSEric Joyner 	u16 i, module_id_cnt;
376*f2635e84SEric Joyner 	int status;
37756429daeSEric Joyner 	void *buf;
37856429daeSEric Joyner 
37956429daeSEric Joyner 	ice_memset(cfg, 0, sizeof(*cfg), ICE_NONDMA_MEM);
38056429daeSEric Joyner 
38156429daeSEric Joyner 	buf = ice_calloc(hw, 1, ICE_AQ_MAX_BUF_LEN);
38256429daeSEric Joyner 	if (!buf)
38356429daeSEric Joyner 		return ICE_ERR_NO_MEMORY;
38456429daeSEric Joyner 
38556429daeSEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logs_query);
38656429daeSEric Joyner 	cmd = &desc.params.fw_log;
38756429daeSEric Joyner 
38856429daeSEric Joyner 	cmd->cmd_flags = ICE_AQC_FW_LOG_AQ_QUERY;
38956429daeSEric Joyner 
39056429daeSEric Joyner 	status = ice_aq_send_cmd(hw, &desc, buf, ICE_AQ_MAX_BUF_LEN, NULL);
39156429daeSEric Joyner 	if (status) {
39256429daeSEric Joyner 		ice_debug(hw, ICE_DBG_FW_LOG, "Failed to get FW log configuration\n");
39356429daeSEric Joyner 		goto status_out;
39456429daeSEric Joyner 	}
39556429daeSEric Joyner 
39656429daeSEric Joyner 	module_id_cnt = LE16_TO_CPU(cmd->ops.cfg.mdl_cnt);
39756429daeSEric Joyner 	if (module_id_cnt < ICE_AQC_FW_LOG_ID_MAX) {
39856429daeSEric Joyner 		ice_debug(hw, ICE_DBG_FW_LOG, "FW returned less than the expected number of FW log module IDs\n");
39956429daeSEric Joyner 	} else {
40056429daeSEric Joyner 		if (module_id_cnt > ICE_AQC_FW_LOG_ID_MAX)
40156429daeSEric Joyner 			ice_debug(hw, ICE_DBG_FW_LOG, "FW returned more than expected number of FW log module IDs, setting module_id_cnt to software expected max %u\n",
40256429daeSEric Joyner 				  ICE_AQC_FW_LOG_ID_MAX);
40356429daeSEric Joyner 		module_id_cnt = ICE_AQC_FW_LOG_ID_MAX;
40456429daeSEric Joyner 	}
40556429daeSEric Joyner 
40656429daeSEric Joyner 	cfg->log_resolution = LE16_TO_CPU(cmd->ops.cfg.log_resolution);
40756429daeSEric Joyner 	if (cmd->cmd_flags & ICE_AQC_FW_LOG_CONF_AQ_EN)
40856429daeSEric Joyner 		cfg->options |= ICE_FWLOG_OPTION_ARQ_ENA;
40956429daeSEric Joyner 	if (cmd->cmd_flags & ICE_AQC_FW_LOG_CONF_UART_EN)
41056429daeSEric Joyner 		cfg->options |= ICE_FWLOG_OPTION_UART_ENA;
41156429daeSEric Joyner 	if (cmd->cmd_flags & ICE_AQC_FW_LOG_QUERY_REGISTERED)
41256429daeSEric Joyner 		cfg->options |= ICE_FWLOG_OPTION_IS_REGISTERED;
41356429daeSEric Joyner 
41456429daeSEric Joyner 	fw_modules = (struct ice_aqc_fw_log_cfg_resp *)buf;
41556429daeSEric Joyner 
41656429daeSEric Joyner 	for (i = 0; i < module_id_cnt; i++) {
41756429daeSEric Joyner 		struct ice_aqc_fw_log_cfg_resp *fw_module = &fw_modules[i];
41856429daeSEric Joyner 
41956429daeSEric Joyner 		cfg->module_entries[i].module_id =
42056429daeSEric Joyner 			LE16_TO_CPU(fw_module->module_identifier);
42156429daeSEric Joyner 		cfg->module_entries[i].log_level = fw_module->log_level;
42256429daeSEric Joyner 	}
42356429daeSEric Joyner 
42456429daeSEric Joyner status_out:
42556429daeSEric Joyner 	ice_free(hw, buf);
42656429daeSEric Joyner 	return status;
42756429daeSEric Joyner }
42856429daeSEric Joyner 
42956429daeSEric Joyner /**
43056429daeSEric Joyner  * ice_fwlog_set_support_ena - Set if FW logging is supported by FW
43156429daeSEric Joyner  * @hw: pointer to the HW struct
43256429daeSEric Joyner  *
43356429daeSEric Joyner  * If FW returns success to the ice_aq_fwlog_get call then it supports FW
43456429daeSEric Joyner  * logging, else it doesn't. Set the fwlog_support_ena flag accordingly.
43556429daeSEric Joyner  *
43656429daeSEric Joyner  * This function is only meant to be called during driver init to determine if
43756429daeSEric Joyner  * the FW support FW logging.
43856429daeSEric Joyner  */
43956429daeSEric Joyner void ice_fwlog_set_support_ena(struct ice_hw *hw)
44056429daeSEric Joyner {
44156429daeSEric Joyner 	struct ice_fwlog_cfg *cfg;
442*f2635e84SEric Joyner 	int status;
44356429daeSEric Joyner 
44456429daeSEric Joyner 	hw->fwlog_support_ena = false;
44556429daeSEric Joyner 
44656429daeSEric Joyner 	cfg = (struct ice_fwlog_cfg *)ice_calloc(hw, 1, sizeof(*cfg));
44756429daeSEric Joyner 	if (!cfg)
44856429daeSEric Joyner 		return;
44956429daeSEric Joyner 
45056429daeSEric Joyner 	/* don't call ice_fwlog_get() because that would overwrite the cached
45156429daeSEric Joyner 	 * configuration from the call to ice_fwlog_init(), which is expected to
45256429daeSEric Joyner 	 * be called prior to this function
45356429daeSEric Joyner 	 */
45456429daeSEric Joyner 	status = ice_aq_fwlog_get(hw, cfg);
45556429daeSEric Joyner 	if (status)
45656429daeSEric Joyner 		ice_debug(hw, ICE_DBG_FW_LOG, "ice_fwlog_get failed, FW logging is not supported on this version of FW, status %d\n",
45756429daeSEric Joyner 			  status);
45856429daeSEric Joyner 	else
45956429daeSEric Joyner 		hw->fwlog_support_ena = true;
46056429daeSEric Joyner 
46156429daeSEric Joyner 	ice_free(hw, cfg);
46256429daeSEric Joyner }
46356429daeSEric Joyner 
46456429daeSEric Joyner /**
46556429daeSEric Joyner  * ice_fwlog_get - Get the firmware logging settings
46656429daeSEric Joyner  * @hw: pointer to the HW structure
46756429daeSEric Joyner  * @cfg: config to populate based on current firmware logging settings
46856429daeSEric Joyner  */
469*f2635e84SEric Joyner int
47056429daeSEric Joyner ice_fwlog_get(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
47156429daeSEric Joyner {
472*f2635e84SEric Joyner 	int status;
47356429daeSEric Joyner 
47456429daeSEric Joyner 	if (!ice_fwlog_supported(hw))
47556429daeSEric Joyner 		return ICE_ERR_NOT_SUPPORTED;
47656429daeSEric Joyner 
47756429daeSEric Joyner 	if (!cfg)
47856429daeSEric Joyner 		return ICE_ERR_PARAM;
47956429daeSEric Joyner 
48056429daeSEric Joyner 	status = ice_aq_fwlog_get(hw, cfg);
48156429daeSEric Joyner 	if (status)
48256429daeSEric Joyner 		return status;
48356429daeSEric Joyner 
48456429daeSEric Joyner 	cache_cfg(hw, cfg);
48556429daeSEric Joyner 
486*f2635e84SEric Joyner 	return 0;
48756429daeSEric Joyner }
48856429daeSEric Joyner 
48956429daeSEric Joyner /**
49056429daeSEric Joyner  * ice_fwlog_event_dump - Dump the event received over the Admin Receive Queue
49156429daeSEric Joyner  * @hw: pointer to the HW structure
49256429daeSEric Joyner  * @desc: Admin Receive Queue descriptor
49356429daeSEric Joyner  * @buf: buffer that contains the FW log event data
49456429daeSEric Joyner  *
49556429daeSEric Joyner  * If the driver receives the ice_aqc_opc_fw_logs_event on the Admin Receive
49656429daeSEric Joyner  * Queue, then it should call this function to dump the FW log data.
49756429daeSEric Joyner  */
49856429daeSEric Joyner void
49956429daeSEric Joyner ice_fwlog_event_dump(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf)
50056429daeSEric Joyner {
50156429daeSEric Joyner 	if (!ice_fwlog_supported(hw))
50256429daeSEric Joyner 		return;
50356429daeSEric Joyner 
50456429daeSEric Joyner 	ice_info_fwlog(hw, 32, 1, (u8 *)buf, LE16_TO_CPU(desc->datalen));
50556429daeSEric Joyner }
5069c30461dSEric Joyner 
507