Commit 1da742e3 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files
Tony Nguyen says:

====================
Intel Wired LAN Driver Updates 2025-01-08 (ice)

This series contains updates to ice driver only.

Przemek reworks implementation so that ice_init_hw() is called before
ice_adapter initialization. The motivation is to have ability to act
on the number of PFs in ice_adapter initialization. This is not done
here but the code is also a bit cleaner.

Michal adds priority to be considered when matching recipes for proper
differentiation.

Konrad adds devlink health reporting for firmware generated events.

R Sundar utilizes string helpers over open coded versions.

Jake adds implementation to utilize a lower latency interface to program
PHY timer when supported.

Additional information can be found on the original cover letter:

  https://lore.kernel.org/intel-wired-lan/20241216145453.333745-1-anton.nadezhdin@intel.com/

Karol adds and allows for different PTP delay values to be used per pin.

* '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue:
  ice: Add in/out PTP pin delays
  ice: implement low latency PHY timer updates
  ice: check low latency PHY timer update firmware capability
  ice: add lock to protect low latency interface
  ice: rename TS_LL_READ* macros to REG_LL_PROXY_H_*
  ice: use read_poll_timeout_atomic in ice_read_phy_tstamp_ll_e810
  ice: use string choice helpers
  ice: add fw and port health reporters
  ice: add recipe priority check in search
  ice: ice_probe: init ice_adapter after HW init
  ice: minor: rename goto labels from err to unroll
  ice: split ice_init_hw() out from ice_init_dev()
  ice: c827: move wait for FW to ice_init_hw()
====================

Link: https://patch.msgid.link/20250115000844.714530-1-anthony.l.nguyen@intel.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 3440fa34 91463946
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -1207,9 +1207,15 @@ static int ice_devlink_reinit_up(struct ice_pf *pf)
	struct ice_vsi *vsi = ice_get_main_vsi(pf);
	int err;

	err = ice_init_hw(&pf->hw);
	if (err) {
		dev_err(ice_pf_to_dev(pf), "ice_init_hw failed: %d\n", err);
		return err;
	}

	err = ice_init_dev(pf);
	if (err)
		return err;
		goto unroll_hw_init;

	vsi->flags = ICE_VSI_FLAG_INIT;

@@ -1232,6 +1238,8 @@ static int ice_devlink_reinit_up(struct ice_pf *pf)
	rtnl_unlock();
err_vsi_cfg:
	ice_deinit_dev(pf);
unroll_hw_init:
	ice_deinit_hw(&pf->hw);
	return err;
}

+288 −7
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2024, Intel Corporation. */

#include "health.h"
#include "ice.h"
#include "ice_adminq_cmd.h" /* for enum ice_aqc_health_status_elem */
#include "health.h"

#define ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, obj, name) \
	devlink_fmsg_put(fmsg, #name, (obj)->name)

#define ICE_HEALTH_STATUS_DATA_SIZE 2

struct ice_health_status {
	enum ice_aqc_health_status code;
	const char *description;
	const char *solution;
	const char *data_label[ICE_HEALTH_STATUS_DATA_SIZE];
};

/*
 * In addition to the health status codes provided below, the firmware might
 * generate Health Status Codes that are not pertinent to the end-user.
 * For instance, Health Code 0x1002 is triggered when the command fails.
 * Such codes should be disregarded by the end-user.
 * The below lookup requires to be sorted by code.
 */

static const char *const ice_common_port_solutions =
	"Check your cable connection. Change or replace the module or cable. Manually set speed and duplex.";
static const char *const ice_port_number_label = "Port Number";
static const char *const ice_update_nvm_solution = "Update to the latest NVM image.";

static const struct ice_health_status ice_health_status_lookup[] = {
	{ICE_AQC_HEALTH_STATUS_ERR_UNKNOWN_MOD_STRICT, "An unsupported module was detected.",
		ice_common_port_solutions, {ice_port_number_label}},
	{ICE_AQC_HEALTH_STATUS_ERR_MOD_TYPE, "Module type is not supported.",
		"Change or replace the module or cable.", {ice_port_number_label}},
	{ICE_AQC_HEALTH_STATUS_ERR_MOD_QUAL, "Module is not qualified.",
		ice_common_port_solutions, {ice_port_number_label}},
	{ICE_AQC_HEALTH_STATUS_ERR_MOD_COMM,
		"Device cannot communicate with the module.",
		"Check your cable connection. Change or replace the module or cable. Manually set speed and duplex.",
		{ice_port_number_label}},
	{ICE_AQC_HEALTH_STATUS_ERR_MOD_CONFLICT, "Unresolved module conflict.",
		"Manually set speed/duplex or change the port option. If the problem persists, use a cable/module that is found in the supported modules and cables list for this device.",
		{ice_port_number_label}},
	{ICE_AQC_HEALTH_STATUS_ERR_MOD_NOT_PRESENT, "Module is not present.",
		"Check that the module is inserted correctly. If the problem persists, use a cable/module that is found in the supported modules and cables list for this device.",
		{ice_port_number_label}},
	{ICE_AQC_HEALTH_STATUS_INFO_MOD_UNDERUTILIZED, "Underutilized module.",
		"Change or replace the module or cable. Change the port option.",
		{ice_port_number_label}},
	{ICE_AQC_HEALTH_STATUS_ERR_UNKNOWN_MOD_LENIENT, "An unsupported module was detected.",
		ice_common_port_solutions, {ice_port_number_label}},
	{ICE_AQC_HEALTH_STATUS_ERR_INVALID_LINK_CFG, "Invalid link configuration.",
		NULL, {ice_port_number_label}},
	{ICE_AQC_HEALTH_STATUS_ERR_PORT_ACCESS, "Port hardware access error.",
		ice_update_nvm_solution, {ice_port_number_label}},
	{ICE_AQC_HEALTH_STATUS_ERR_PORT_UNREACHABLE, "A port is unreachable.",
		"Change the port option. Update to the latest NVM image."},
	{ICE_AQC_HEALTH_STATUS_INFO_PORT_SPEED_MOD_LIMITED, "Port speed is limited due to module.",
		"Change the module or configure the port option to match the current module speed. Change the port option.",
		{ice_port_number_label}},
	{ICE_AQC_HEALTH_STATUS_ERR_PARALLEL_FAULT,
		"All configured link modes were attempted but failed to establish link. The device will restart the process to establish link.",
		"Check link partner connection and configuration.",
		{ice_port_number_label}},
	{ICE_AQC_HEALTH_STATUS_INFO_PORT_SPEED_PHY_LIMITED,
		"Port speed is limited by PHY capabilities.",
		"Change the module to align to port option.", {ice_port_number_label}},
	{ICE_AQC_HEALTH_STATUS_ERR_NETLIST_TOPO, "LOM topology netlist is corrupted.",
		ice_update_nvm_solution, {ice_port_number_label}},
	{ICE_AQC_HEALTH_STATUS_ERR_NETLIST, "Unrecoverable netlist error.",
		ice_update_nvm_solution, {ice_port_number_label}},
	{ICE_AQC_HEALTH_STATUS_ERR_TOPO_CONFLICT, "Port topology conflict.",
		"Change the port option. Update to the latest NVM image."},
	{ICE_AQC_HEALTH_STATUS_ERR_LINK_HW_ACCESS, "Unrecoverable hardware access error.",
		ice_update_nvm_solution, {ice_port_number_label}},
	{ICE_AQC_HEALTH_STATUS_ERR_LINK_RUNTIME, "Unrecoverable runtime error.",
		ice_update_nvm_solution, {ice_port_number_label}},
	{ICE_AQC_HEALTH_STATUS_ERR_DNL_INIT, "Link management engine failed to initialize.",
		ice_update_nvm_solution, {ice_port_number_label}},
	{ICE_AQC_HEALTH_STATUS_ERR_PHY_FW_LOAD,
		"Failed to load the firmware image in the external PHY.",
		ice_update_nvm_solution, {ice_port_number_label}},
	{ICE_AQC_HEALTH_STATUS_INFO_RECOVERY, "The device is in firmware recovery mode.",
		ice_update_nvm_solution, {"Extended Error"}},
	{ICE_AQC_HEALTH_STATUS_ERR_FLASH_ACCESS, "The flash chip cannot be accessed.",
		"If issue persists, call customer support.", {"Access Type"}},
	{ICE_AQC_HEALTH_STATUS_ERR_NVM_AUTH, "NVM authentication failed.",
		ice_update_nvm_solution},
	{ICE_AQC_HEALTH_STATUS_ERR_OROM_AUTH, "Option ROM authentication failed.",
		ice_update_nvm_solution},
	{ICE_AQC_HEALTH_STATUS_ERR_DDP_AUTH, "DDP package authentication failed.",
		"Update to latest base driver and DDP package."},
	{ICE_AQC_HEALTH_STATUS_ERR_NVM_COMPAT, "NVM image is incompatible.",
		ice_update_nvm_solution},
	{ICE_AQC_HEALTH_STATUS_ERR_OROM_COMPAT, "Option ROM is incompatible.",
		ice_update_nvm_solution, {"Expected PCI Device ID", "Expected Module ID"}},
	{ICE_AQC_HEALTH_STATUS_ERR_DCB_MIB,
		"Supplied MIB file is invalid. DCB reverted to default configuration.",
		"Disable FW-LLDP and check DCBx system configuration.",
		{ice_port_number_label, "MIB ID"}},
};

static int ice_health_status_lookup_compare(const void *a, const void *b)
{
	return ((struct ice_health_status *)a)->code - ((struct ice_health_status *)b)->code;
}

static const struct ice_health_status *ice_get_health_status(u16 code)
{
	struct ice_health_status key = { .code = code };

	return bsearch(&key, ice_health_status_lookup, ARRAY_SIZE(ice_health_status_lookup),
		       sizeof(struct ice_health_status), ice_health_status_lookup_compare);
}

static void ice_describe_status_code(struct devlink_fmsg *fmsg,
				     struct ice_aqc_health_status_elem *hse)
{
	static const char *const aux_label[] = { "Aux Data 1", "Aux Data 2" };
	const struct ice_health_status *health_code;
	u32 internal_data[2];
	u16 status_code;

	status_code = le16_to_cpu(hse->health_status_code);

	devlink_fmsg_put(fmsg, "Syndrome", status_code);
	if (status_code) {
		internal_data[0] = le32_to_cpu(hse->internal_data1);
		internal_data[1] = le32_to_cpu(hse->internal_data2);

		health_code = ice_get_health_status(status_code);
		if (!health_code)
			return;

		devlink_fmsg_string_pair_put(fmsg, "Description", health_code->description);
		if (health_code->solution)
			devlink_fmsg_string_pair_put(fmsg, "Possible Solution",
						     health_code->solution);

		for (size_t i = 0; i < ICE_HEALTH_STATUS_DATA_SIZE; i++) {
			if (internal_data[i] != ICE_AQC_HEALTH_STATUS_UNDEFINED_DATA)
				devlink_fmsg_u32_pair_put(fmsg,
							  health_code->data_label[i] ?
							  health_code->data_label[i] :
							  aux_label[i],
							  internal_data[i]);
		}
	}
}

static int
ice_port_reporter_diagnose(struct devlink_health_reporter *reporter, struct devlink_fmsg *fmsg,
			   struct netlink_ext_ack *extack)
{
	struct ice_pf *pf = devlink_health_reporter_priv(reporter);

	ice_describe_status_code(fmsg, &pf->health_reporters.port_status);
	return 0;
}

static int
ice_port_reporter_dump(struct devlink_health_reporter *reporter, struct devlink_fmsg *fmsg,
		       void *priv_ctx, struct netlink_ext_ack __always_unused *extack)
{
	struct ice_pf *pf = devlink_health_reporter_priv(reporter);

	ice_describe_status_code(fmsg, &pf->health_reporters.port_status);
	return 0;
}

static int
ice_fw_reporter_diagnose(struct devlink_health_reporter *reporter, struct devlink_fmsg *fmsg,
			 struct netlink_ext_ack *extack)
{
	struct ice_pf *pf = devlink_health_reporter_priv(reporter);

	ice_describe_status_code(fmsg, &pf->health_reporters.fw_status);
	return 0;
}

static int
ice_fw_reporter_dump(struct devlink_health_reporter *reporter, struct devlink_fmsg *fmsg,
		     void *priv_ctx, struct netlink_ext_ack *extack)
{
	struct ice_pf *pf = devlink_health_reporter_priv(reporter);

	ice_describe_status_code(fmsg, &pf->health_reporters.fw_status);
	return 0;
}

static void ice_config_health_events(struct ice_pf *pf, bool enable)
{
	u8 enable_bits = 0;
	int ret;

	if (enable)
		enable_bits = ICE_AQC_HEALTH_STATUS_SET_PF_SPECIFIC_MASK |
			      ICE_AQC_HEALTH_STATUS_SET_GLOBAL_MASK;

	ret = ice_aq_set_health_status_cfg(&pf->hw, enable_bits);
	if (ret)
		dev_err(ice_pf_to_dev(pf), "Failed to %s firmware health events, err %d aq_err %s\n",
			str_enable_disable(enable), ret,
			ice_aq_str(pf->hw.adminq.sq_last_status));
}

/**
 * ice_process_health_status_event - Process the health status event from FW
 * @pf: pointer to the PF structure
 * @event: event structure containing the Health Status Event opcode
 *
 * Decode the Health Status Events and print the associated messages
 */
void ice_process_health_status_event(struct ice_pf *pf, struct ice_rq_event_info *event)
{
	const struct ice_aqc_health_status_elem *health_info;
	u16 count;

	health_info = (struct ice_aqc_health_status_elem *)event->msg_buf;
	count = le16_to_cpu(event->desc.params.get_health_status.health_status_count);

	if (count > (event->buf_len / sizeof(*health_info))) {
		dev_err(ice_pf_to_dev(pf), "Received a health status event with invalid element count\n");
		return;
	}

	for (size_t i = 0; i < count; i++) {
		const struct ice_health_status *health_code;
		u16 status_code;

		status_code = le16_to_cpu(health_info->health_status_code);
		health_code = ice_get_health_status(status_code);

		if (health_code) {
			switch (le16_to_cpu(health_info->event_source)) {
			case ICE_AQC_HEALTH_STATUS_GLOBAL:
				pf->health_reporters.fw_status = *health_info;
				devlink_health_report(pf->health_reporters.fw,
						      "FW syndrome reported", NULL);
				break;
			case ICE_AQC_HEALTH_STATUS_PF:
			case ICE_AQC_HEALTH_STATUS_PORT:
				pf->health_reporters.port_status = *health_info;
				devlink_health_report(pf->health_reporters.port,
						      "Port syndrome reported", NULL);
				break;
			default:
				dev_err(ice_pf_to_dev(pf), "Health code with unknown source\n");
			}
		} else {
			u32 data1, data2;
			u16 source;

			source = le16_to_cpu(health_info->event_source);
			data1 = le32_to_cpu(health_info->internal_data1);
			data2 = le32_to_cpu(health_info->internal_data2);
			dev_dbg(ice_pf_to_dev(pf),
				"Received internal health status code 0x%08x, source: 0x%08x, data1: 0x%08x, data2: 0x%08x",
				status_code, source, data1, data2);
		}
		health_info++;
	}
}

/**
 * ice_devlink_health_report - boilerplate to call given @reporter
 *
@@ -203,14 +461,26 @@ ice_init_devlink_rep(struct ice_pf *pf,
	return rep;
}

#define ICE_DEFINE_HEALTH_REPORTER_OPS(_name) \
#define ICE_HEALTH_REPORTER_OPS_FIELD(_name, _field) \
	._field = ice_##_name##_reporter_##_field,

#define ICE_DEFINE_HEALTH_REPORTER_OPS_1(_name, _field1) \
	static const struct devlink_health_reporter_ops ice_##_name##_reporter_ops = { \
	.name = #_name, \
	.dump = ice_ ## _name ## _reporter_dump, \
	ICE_HEALTH_REPORTER_OPS_FIELD(_name, _field1) \
	}

ICE_DEFINE_HEALTH_REPORTER_OPS(mdd);
ICE_DEFINE_HEALTH_REPORTER_OPS(tx_hang);
#define ICE_DEFINE_HEALTH_REPORTER_OPS_2(_name, _field1, _field2) \
	static const struct devlink_health_reporter_ops ice_##_name##_reporter_ops = { \
	.name = #_name, \
	ICE_HEALTH_REPORTER_OPS_FIELD(_name, _field1) \
	ICE_HEALTH_REPORTER_OPS_FIELD(_name, _field2) \
	}

ICE_DEFINE_HEALTH_REPORTER_OPS_1(mdd, dump);
ICE_DEFINE_HEALTH_REPORTER_OPS_1(tx_hang, dump);
ICE_DEFINE_HEALTH_REPORTER_OPS_2(fw, dump, diagnose);
ICE_DEFINE_HEALTH_REPORTER_OPS_2(port, dump, diagnose);

/**
 * ice_health_init - allocate and init all ice devlink health reporters and
@@ -224,6 +494,12 @@ void ice_health_init(struct ice_pf *pf)

	reps->mdd = ice_init_devlink_rep(pf, &ice_mdd_reporter_ops);
	reps->tx_hang = ice_init_devlink_rep(pf, &ice_tx_hang_reporter_ops);

	if (ice_is_fw_health_report_supported(&pf->hw)) {
		reps->fw = ice_init_devlink_rep(pf, &ice_fw_reporter_ops);
		reps->port = ice_init_devlink_rep(pf, &ice_port_reporter_ops);
		ice_config_health_events(pf, true);
	}
}

/**
@@ -246,6 +522,11 @@ void ice_health_deinit(struct ice_pf *pf)
{
	ice_deinit_devl_reporter(pf->health_reporters.mdd);
	ice_deinit_devl_reporter(pf->health_reporters.tx_hang);
	if (ice_is_fw_health_report_supported(&pf->hw)) {
		ice_deinit_devl_reporter(pf->health_reporters.fw);
		ice_deinit_devl_reporter(pf->health_reporters.port);
		ice_config_health_events(pf, false);
	}
}

static
+14 −1
Original line number Diff line number Diff line
@@ -13,8 +13,10 @@
 * devlink health mechanism for ice driver.
 */

struct ice_aqc_health_status_elem;
struct ice_pf;
struct ice_tx_ring;
struct ice_rq_event_info;

enum ice_mdd_src {
	ICE_MDD_SRC_TX_PQM,
@@ -25,17 +27,23 @@ enum ice_mdd_src {

/**
 * struct ice_health - stores ice devlink health reporters and accompanied data
 * @tx_hang: devlink health reporter for tx_hang event
 * @fw: devlink health reporter for FW Health Status events
 * @mdd: devlink health reporter for MDD detection event
 * @port: devlink health reporter for Port Health Status events
 * @tx_hang: devlink health reporter for tx_hang event
 * @tx_hang_buf: pre-allocated place to put info for Tx hang reporter from
 *               non-sleeping context
 * @tx_ring: ring that the hang occurred on
 * @head: descriptor head
 * @intr: interrupt register value
 * @vsi_num: VSI owning the queue that the hang occurred on
 * @fw_status: buffer for last received FW Status event
 * @port_status: buffer for last received Port Status event
 */
struct ice_health {
	struct devlink_health_reporter *fw;
	struct devlink_health_reporter *mdd;
	struct devlink_health_reporter *port;
	struct devlink_health_reporter *tx_hang;
	struct_group_tagged(ice_health_tx_hang_buf, tx_hang_buf,
		struct ice_tx_ring *tx_ring;
@@ -43,8 +51,13 @@ struct ice_health {
		u32 intr;
		u16 vsi_num;
	);
	struct ice_aqc_health_status_elem fw_status;
	struct ice_aqc_health_status_elem port_status;
};

void ice_process_health_status_event(struct ice_pf *pf,
				     struct ice_rq_event_info *event);

void ice_health_init(struct ice_pf *pf);
void ice_health_deinit(struct ice_pf *pf);
void ice_health_clear(struct ice_pf *pf);
+87 −0
Original line number Diff line number Diff line
@@ -2517,6 +2517,87 @@ enum ice_aqc_fw_logging_mod {
	ICE_AQC_FW_LOG_ID_MAX,
};

enum ice_aqc_health_status_mask {
	ICE_AQC_HEALTH_STATUS_SET_PF_SPECIFIC_MASK = BIT(0),
	ICE_AQC_HEALTH_STATUS_SET_ALL_PF_MASK      = BIT(1),
	ICE_AQC_HEALTH_STATUS_SET_GLOBAL_MASK      = BIT(2),
};

/* Set Health Status (direct 0xFF20) */
struct ice_aqc_set_health_status_cfg {
	u8 event_source;
	u8 reserved[15];
};

enum ice_aqc_health_status {
	ICE_AQC_HEALTH_STATUS_ERR_UNKNOWN_MOD_STRICT		= 0x101,
	ICE_AQC_HEALTH_STATUS_ERR_MOD_TYPE			= 0x102,
	ICE_AQC_HEALTH_STATUS_ERR_MOD_QUAL			= 0x103,
	ICE_AQC_HEALTH_STATUS_ERR_MOD_COMM			= 0x104,
	ICE_AQC_HEALTH_STATUS_ERR_MOD_CONFLICT			= 0x105,
	ICE_AQC_HEALTH_STATUS_ERR_MOD_NOT_PRESENT		= 0x106,
	ICE_AQC_HEALTH_STATUS_INFO_MOD_UNDERUTILIZED		= 0x107,
	ICE_AQC_HEALTH_STATUS_ERR_UNKNOWN_MOD_LENIENT		= 0x108,
	ICE_AQC_HEALTH_STATUS_ERR_MOD_DIAGNOSTIC_FEATURE	= 0x109,
	ICE_AQC_HEALTH_STATUS_ERR_INVALID_LINK_CFG		= 0x10B,
	ICE_AQC_HEALTH_STATUS_ERR_PORT_ACCESS			= 0x10C,
	ICE_AQC_HEALTH_STATUS_ERR_PORT_UNREACHABLE		= 0x10D,
	ICE_AQC_HEALTH_STATUS_INFO_PORT_SPEED_MOD_LIMITED	= 0x10F,
	ICE_AQC_HEALTH_STATUS_ERR_PARALLEL_FAULT		= 0x110,
	ICE_AQC_HEALTH_STATUS_INFO_PORT_SPEED_PHY_LIMITED	= 0x111,
	ICE_AQC_HEALTH_STATUS_ERR_NETLIST_TOPO			= 0x112,
	ICE_AQC_HEALTH_STATUS_ERR_NETLIST			= 0x113,
	ICE_AQC_HEALTH_STATUS_ERR_TOPO_CONFLICT			= 0x114,
	ICE_AQC_HEALTH_STATUS_ERR_LINK_HW_ACCESS		= 0x115,
	ICE_AQC_HEALTH_STATUS_ERR_LINK_RUNTIME			= 0x116,
	ICE_AQC_HEALTH_STATUS_ERR_DNL_INIT			= 0x117,
	ICE_AQC_HEALTH_STATUS_ERR_PHY_NVM_PROG			= 0x120,
	ICE_AQC_HEALTH_STATUS_ERR_PHY_FW_LOAD			= 0x121,
	ICE_AQC_HEALTH_STATUS_INFO_RECOVERY			= 0x500,
	ICE_AQC_HEALTH_STATUS_ERR_FLASH_ACCESS			= 0x501,
	ICE_AQC_HEALTH_STATUS_ERR_NVM_AUTH			= 0x502,
	ICE_AQC_HEALTH_STATUS_ERR_OROM_AUTH			= 0x503,
	ICE_AQC_HEALTH_STATUS_ERR_DDP_AUTH			= 0x504,
	ICE_AQC_HEALTH_STATUS_ERR_NVM_COMPAT			= 0x505,
	ICE_AQC_HEALTH_STATUS_ERR_OROM_COMPAT			= 0x506,
	ICE_AQC_HEALTH_STATUS_ERR_NVM_SEC_VIOLATION		= 0x507,
	ICE_AQC_HEALTH_STATUS_ERR_OROM_SEC_VIOLATION		= 0x508,
	ICE_AQC_HEALTH_STATUS_ERR_DCB_MIB			= 0x509,
	ICE_AQC_HEALTH_STATUS_ERR_MNG_TIMEOUT			= 0x50A,
	ICE_AQC_HEALTH_STATUS_ERR_BMC_RESET			= 0x50B,
	ICE_AQC_HEALTH_STATUS_ERR_LAST_MNG_FAIL			= 0x50C,
	ICE_AQC_HEALTH_STATUS_ERR_RESOURCE_ALLOC_FAIL		= 0x50D,
	ICE_AQC_HEALTH_STATUS_ERR_FW_LOOP			= 0x1000,
	ICE_AQC_HEALTH_STATUS_ERR_FW_PFR_FAIL			= 0x1001,
	ICE_AQC_HEALTH_STATUS_ERR_LAST_FAIL_AQ			= 0x1002,
};

/* Get Health Status (indirect 0xFF22) */
struct ice_aqc_get_health_status {
	__le16 health_status_count;
	u8 reserved[6];
	__le32 addr_high;
	__le32 addr_low;
};

enum ice_aqc_health_status_scope {
	ICE_AQC_HEALTH_STATUS_PF	= 0x1,
	ICE_AQC_HEALTH_STATUS_PORT	= 0x2,
	ICE_AQC_HEALTH_STATUS_GLOBAL	= 0x3,
};

#define ICE_AQC_HEALTH_STATUS_UNDEFINED_DATA	0xDEADBEEF

/* Get Health Status event buffer entry (0xFF22),
 * repeated per reported health status.
 */
struct ice_aqc_health_status_elem {
	__le16 health_status_code;
	__le16 event_source;
	__le32 internal_data1;
	__le32 internal_data2;
};

/* Set FW Logging configuration (indirect 0xFF30)
 * Register for FW Logging (indirect 0xFF31)
 * Query FW Logging (indirect 0xFF32)
@@ -2657,6 +2738,8 @@ struct ice_aq_desc {
		struct ice_aqc_get_link_status get_link_status;
		struct ice_aqc_event_lan_overflow lan_overflow;
		struct ice_aqc_get_link_topo get_link_topo;
		struct ice_aqc_set_health_status_cfg set_health_status_cfg;
		struct ice_aqc_get_health_status get_health_status;
		struct ice_aqc_dnl_call_command dnl_call;
		struct ice_aqc_i2c read_write_i2c;
		struct ice_aqc_read_i2c_resp read_i2c_resp;
@@ -2859,6 +2942,10 @@ enum ice_adminq_opc {
	/* Standalone Commands/Events */
	ice_aqc_opc_event_lan_overflow			= 0x1001,

	/* System Diagnostic commands */
	ice_aqc_opc_set_health_status_cfg		= 0xFF20,
	ice_aqc_opc_get_health_status			= 0xFF22,

	/* FW Logging Commands */
	ice_aqc_opc_fw_logs_config			= 0xFF30,
	ice_aqc_opc_fw_logs_register			= 0xFF31,
+116 −35
Original line number Diff line number Diff line
@@ -308,6 +308,42 @@ bool ice_is_e825c(struct ice_hw *hw)
	}
}

/**
 * ice_is_pf_c827 - check if pf contains c827 phy
 * @hw: pointer to the hw struct
 *
 * Return: true if the device has c827 phy.
 */
static bool ice_is_pf_c827(struct ice_hw *hw)
{
	struct ice_aqc_get_link_topo cmd = {};
	u8 node_part_number;
	u16 node_handle;
	int status;

	if (hw->mac_type != ICE_MAC_E810)
		return false;

	if (hw->device_id != ICE_DEV_ID_E810C_QSFP)
		return true;

	cmd.addr.topo_params.node_type_ctx =
		FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_TYPE_M, ICE_AQC_LINK_TOPO_NODE_TYPE_PHY) |
		FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M, ICE_AQC_LINK_TOPO_NODE_CTX_PORT);
	cmd.addr.topo_params.index = 0;

	status = ice_aq_get_netlist_node(hw, &cmd, &node_part_number,
					 &node_handle);

	if (status || node_part_number != ICE_AQC_GET_LINK_TOPO_NODE_NR_C827)
		return false;

	if (node_handle == E810C_QSFP_C827_0_HANDLE || node_handle == E810C_QSFP_C827_1_HANDLE)
		return true;

	return false;
}

/**
 * ice_clear_pf_cfg - Clear PF configuration
 * @hw: pointer to the hardware structure
@@ -1025,6 +1061,33 @@ static void ice_get_itr_intrl_gran(struct ice_hw *hw)
	}
}

/**
 * ice_wait_for_fw - wait for full FW readiness
 * @hw: pointer to the hardware structure
 * @timeout: milliseconds that can elapse before timing out
 *
 * Return: 0 on success, -ETIMEDOUT on timeout.
 */
static int ice_wait_for_fw(struct ice_hw *hw, u32 timeout)
{
	int fw_loading;
	u32 elapsed = 0;

	while (elapsed <= timeout) {
		fw_loading = rd32(hw, GL_MNG_FWSM) & GL_MNG_FWSM_FW_LOADING_M;

		/* firmware was not yet loaded, we have to wait more */
		if (fw_loading) {
			elapsed += 100;
			msleep(100);
			continue;
		}
		return 0;
	}

	return -ETIMEDOUT;
}

/**
 * ice_init_hw - main hardware initialization routine
 * @hw: pointer to the hardware structure
@@ -1174,8 +1237,19 @@ int ice_init_hw(struct ice_hw *hw)
	mutex_init(&hw->tnl_lock);
	ice_init_chk_recipe_reuse_support(hw);

	return 0;
	/* Some cards require longer initialization times
	 * due to necessity of loading FW from an external source.
	 * This can take even half a minute.
	 */
	if (ice_is_pf_c827(hw)) {
		status = ice_wait_for_fw(hw, 30000);
		if (status) {
			dev_err(ice_hw_to_dev(hw), "ice_wait_for_fw timed out");
			goto err_unroll_fltr_mgmt_struct;
		}
	}

	return 0;
err_unroll_fltr_mgmt_struct:
	ice_cleanup_fltr_mgmt_struct(hw);
err_unroll_sched:
@@ -2567,6 +2641,7 @@ ice_parse_1588_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,

	info->ts_ll_read = ((number & ICE_TS_LL_TX_TS_READ_M) != 0);
	info->ts_ll_int_read = ((number & ICE_TS_LL_TX_TS_INT_READ_M) != 0);
	info->ll_phy_tmr_update = ((number & ICE_TS_LL_PHY_TMR_UPDATE_M) != 0);

	info->ena_ports = logical_id;
	info->tmr_own_map = phys_id;
@@ -2589,6 +2664,8 @@ ice_parse_1588_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
		  info->ts_ll_read);
	ice_debug(hw, ICE_DBG_INIT, "dev caps: ts_ll_int_read = %u\n",
		  info->ts_ll_int_read);
	ice_debug(hw, ICE_DBG_INIT, "dev caps: ll_phy_tmr_update = %u\n",
		  info->ll_phy_tmr_update);
	ice_debug(hw, ICE_DBG_INIT, "dev caps: ieee_1588 ena_ports = %u\n",
		  info->ena_ports);
	ice_debug(hw, ICE_DBG_INIT, "dev caps: tmr_own_map = %u\n",
@@ -2728,40 +2805,6 @@ ice_parse_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
	ice_recalc_port_limited_caps(hw, &dev_p->common_cap);
}

/**
 * ice_is_pf_c827 - check if pf contains c827 phy
 * @hw: pointer to the hw struct
 */
bool ice_is_pf_c827(struct ice_hw *hw)
{
	struct ice_aqc_get_link_topo cmd = {};
	u8 node_part_number;
	u16 node_handle;
	int status;

	if (hw->mac_type != ICE_MAC_E810)
		return false;

	if (hw->device_id != ICE_DEV_ID_E810C_QSFP)
		return true;

	cmd.addr.topo_params.node_type_ctx =
		FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_TYPE_M, ICE_AQC_LINK_TOPO_NODE_TYPE_PHY) |
		FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M, ICE_AQC_LINK_TOPO_NODE_CTX_PORT);
	cmd.addr.topo_params.index = 0;

	status = ice_aq_get_netlist_node(hw, &cmd, &node_part_number,
					 &node_handle);

	if (status || node_part_number != ICE_AQC_GET_LINK_TOPO_NODE_NR_C827)
		return false;

	if (node_handle == E810C_QSFP_C827_0_HANDLE || node_handle == E810C_QSFP_C827_1_HANDLE)
		return true;

	return false;
}

/**
 * ice_is_phy_rclk_in_netlist
 * @hw: pointer to the hw struct
@@ -5852,6 +5895,44 @@ bool ice_is_phy_caps_an_enabled(struct ice_aqc_get_phy_caps_data *caps)
	return false;
}

/**
 * ice_is_fw_health_report_supported - checks if firmware supports health events
 * @hw: pointer to the hardware structure
 *
 * Return: true if firmware supports health status reports,
 * false otherwise
 */
bool ice_is_fw_health_report_supported(struct ice_hw *hw)
{
	return ice_is_fw_api_min_ver(hw, ICE_FW_API_HEALTH_REPORT_MAJ,
				     ICE_FW_API_HEALTH_REPORT_MIN,
				     ICE_FW_API_HEALTH_REPORT_PATCH);
}

/**
 * ice_aq_set_health_status_cfg - Configure FW health events
 * @hw: pointer to the HW struct
 * @event_source: type of diagnostic events to enable
 *
 * Configure the health status event types that the firmware will send to this
 * PF. The supported event types are: PF-specific, all PFs, and global.
 *
 * Return: 0 on success, negative error code otherwise.
 */
int ice_aq_set_health_status_cfg(struct ice_hw *hw, u8 event_source)
{
	struct ice_aqc_set_health_status_cfg *cmd;
	struct ice_aq_desc desc;

	cmd = &desc.params.set_health_status_cfg;

	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_health_status_cfg);

	cmd->event_source = event_source;

	return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
}

/**
 * ice_aq_set_lldp_mib - Set the LLDP MIB
 * @hw: pointer to the HW struct
Loading