mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-04 08:04:24 -04:00
Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue
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: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,270 @@
|
||||
// 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) \
|
||||
static const struct devlink_health_reporter_ops ice_ ## _name ## _reporter_ops = { \
|
||||
.name = #_name, \
|
||||
.dump = ice_ ## _name ## _reporter_dump, \
|
||||
}
|
||||
#define ICE_HEALTH_REPORTER_OPS_FIELD(_name, _field) \
|
||||
._field = ice_##_name##_reporter_##_field,
|
||||
|
||||
ICE_DEFINE_HEALTH_REPORTER_OPS(mdd);
|
||||
ICE_DEFINE_HEALTH_REPORTER_OPS(tx_hang);
|
||||
#define ICE_DEFINE_HEALTH_REPORTER_OPS_1(_name, _field1) \
|
||||
static const struct devlink_health_reporter_ops ice_##_name##_reporter_ops = { \
|
||||
.name = #_name, \
|
||||
ICE_HEALTH_REPORTER_OPS_FIELD(_name, _field1) \
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -112,7 +112,6 @@ int
|
||||
ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode,
|
||||
struct ice_aqc_get_phy_caps_data *caps,
|
||||
struct ice_sq_cd *cd);
|
||||
bool ice_is_pf_c827(struct ice_hw *hw);
|
||||
bool ice_is_phy_rclk_in_netlist(struct ice_hw *hw);
|
||||
bool ice_is_clock_mux_in_netlist(struct ice_hw *hw);
|
||||
bool ice_is_cgu_in_netlist(struct ice_hw *hw);
|
||||
@@ -142,6 +141,8 @@ int
|
||||
ice_get_link_default_override(struct ice_link_default_override_tlv *ldo,
|
||||
struct ice_port_info *pi);
|
||||
bool ice_is_phy_caps_an_enabled(struct ice_aqc_get_phy_caps_data *caps);
|
||||
bool ice_is_fw_health_report_supported(struct ice_hw *hw);
|
||||
int ice_aq_set_health_status_cfg(struct ice_hw *hw, u8 event_source);
|
||||
int ice_aq_get_phy_equalization(struct ice_hw *hw, u16 data_in, u16 op_code,
|
||||
u8 serdes_num, int *output);
|
||||
int
|
||||
|
||||
@@ -1567,6 +1567,9 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type)
|
||||
case ice_aqc_opc_lldp_set_mib_change:
|
||||
ice_dcb_process_lldp_set_mib_change(pf, &event);
|
||||
break;
|
||||
case ice_aqc_opc_get_health_status:
|
||||
ice_process_health_status_event(pf, &event);
|
||||
break;
|
||||
default:
|
||||
dev_dbg(dev, "%s Receive Queue unknown event 0x%04x ignored\n",
|
||||
qtype, opcode);
|
||||
@@ -4749,55 +4752,12 @@ static void ice_decfg_netdev(struct ice_vsi *vsi)
|
||||
vsi->netdev = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_wait_for_fw - wait for full FW readiness
|
||||
* @hw: pointer to the hardware structure
|
||||
* @timeout: milliseconds that can elapse before timing out
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
int ice_init_dev(struct ice_pf *pf)
|
||||
{
|
||||
struct device *dev = ice_pf_to_dev(pf);
|
||||
struct ice_hw *hw = &pf->hw;
|
||||
int err;
|
||||
|
||||
err = ice_init_hw(hw);
|
||||
if (err) {
|
||||
dev_err(dev, "ice_init_hw failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* 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)) {
|
||||
err = ice_wait_for_fw(hw, 30000);
|
||||
if (err) {
|
||||
dev_err(dev, "ice_wait_for_fw timed out");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
ice_init_feature_support(pf);
|
||||
|
||||
err = ice_init_ddp_config(hw, pf);
|
||||
@@ -4818,7 +4778,7 @@ int ice_init_dev(struct ice_pf *pf)
|
||||
err = ice_init_pf(pf);
|
||||
if (err) {
|
||||
dev_err(dev, "ice_init_pf failed: %d\n", err);
|
||||
goto err_init_pf;
|
||||
return err;
|
||||
}
|
||||
|
||||
pf->hw.udp_tunnel_nic.set_port = ice_udp_tunnel_set_port;
|
||||
@@ -4842,7 +4802,7 @@ int ice_init_dev(struct ice_pf *pf)
|
||||
if (err) {
|
||||
dev_err(dev, "ice_init_interrupt_scheme failed: %d\n", err);
|
||||
err = -EIO;
|
||||
goto err_init_interrupt_scheme;
|
||||
goto unroll_pf_init;
|
||||
}
|
||||
|
||||
/* In case of MSIX we are going to setup the misc vector right here
|
||||
@@ -4853,17 +4813,15 @@ int ice_init_dev(struct ice_pf *pf)
|
||||
err = ice_req_irq_msix_misc(pf);
|
||||
if (err) {
|
||||
dev_err(dev, "setup of misc vector failed: %d\n", err);
|
||||
goto err_req_irq_msix_misc;
|
||||
goto unroll_irq_scheme_init;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_req_irq_msix_misc:
|
||||
unroll_irq_scheme_init:
|
||||
ice_clear_interrupt_scheme(pf);
|
||||
err_init_interrupt_scheme:
|
||||
unroll_pf_init:
|
||||
ice_deinit_pf(pf);
|
||||
err_init_pf:
|
||||
ice_deinit_hw(hw);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -5322,13 +5280,7 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
|
||||
}
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
adapter = ice_adapter_get(pdev);
|
||||
if (IS_ERR(adapter))
|
||||
return PTR_ERR(adapter);
|
||||
|
||||
pf->pdev = pdev;
|
||||
pf->adapter = adapter;
|
||||
pci_set_drvdata(pdev, pf);
|
||||
set_bit(ICE_DOWN, pf->state);
|
||||
/* Disable service task until DOWN bit is cleared */
|
||||
@@ -5356,29 +5308,44 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
|
||||
hw->debug_mask = debug;
|
||||
#endif
|
||||
|
||||
err = ice_init_hw(hw);
|
||||
if (err) {
|
||||
dev_err(dev, "ice_init_hw failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
adapter = ice_adapter_get(pdev);
|
||||
if (IS_ERR(adapter)) {
|
||||
err = PTR_ERR(adapter);
|
||||
goto unroll_hw_init;
|
||||
}
|
||||
pf->adapter = adapter;
|
||||
|
||||
err = ice_init(pf);
|
||||
if (err)
|
||||
goto err_init;
|
||||
goto unroll_adapter;
|
||||
|
||||
devl_lock(priv_to_devlink(pf));
|
||||
err = ice_load(pf);
|
||||
if (err)
|
||||
goto err_load;
|
||||
goto unroll_init;
|
||||
|
||||
err = ice_init_devlink(pf);
|
||||
if (err)
|
||||
goto err_init_devlink;
|
||||
goto unroll_load;
|
||||
devl_unlock(priv_to_devlink(pf));
|
||||
|
||||
return 0;
|
||||
|
||||
err_init_devlink:
|
||||
unroll_load:
|
||||
ice_unload(pf);
|
||||
err_load:
|
||||
unroll_init:
|
||||
devl_unlock(priv_to_devlink(pf));
|
||||
ice_deinit(pf);
|
||||
err_init:
|
||||
unroll_adapter:
|
||||
ice_adapter_put(pdev);
|
||||
unroll_hw_init:
|
||||
ice_deinit_hw(hw);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,28 +16,28 @@ static const char ice_pin_names[][64] = {
|
||||
};
|
||||
|
||||
static const struct ice_ptp_pin_desc ice_pin_desc_e82x[] = {
|
||||
/* name, gpio */
|
||||
{ TIME_SYNC, { 4, -1 }},
|
||||
{ ONE_PPS, { -1, 5 }},
|
||||
/* name, gpio, delay */
|
||||
{ TIME_SYNC, { 4, -1 }, { 0, 0 }},
|
||||
{ ONE_PPS, { -1, 5 }, { 0, 11 }},
|
||||
};
|
||||
|
||||
static const struct ice_ptp_pin_desc ice_pin_desc_e825c[] = {
|
||||
/* name, gpio */
|
||||
{ SDP0, { 0, 0 }},
|
||||
{ SDP1, { 1, 1 }},
|
||||
{ SDP2, { 2, 2 }},
|
||||
{ SDP3, { 3, 3 }},
|
||||
{ TIME_SYNC, { 4, -1 }},
|
||||
{ ONE_PPS, { -1, 5 }},
|
||||
/* name, gpio, delay */
|
||||
{ SDP0, { 0, 0 }, { 15, 14 }},
|
||||
{ SDP1, { 1, 1 }, { 15, 14 }},
|
||||
{ SDP2, { 2, 2 }, { 15, 14 }},
|
||||
{ SDP3, { 3, 3 }, { 15, 14 }},
|
||||
{ TIME_SYNC, { 4, -1 }, { 11, 0 }},
|
||||
{ ONE_PPS, { -1, 5 }, { 0, 9 }},
|
||||
};
|
||||
|
||||
static const struct ice_ptp_pin_desc ice_pin_desc_e810[] = {
|
||||
/* name, gpio */
|
||||
{ SDP0, { 0, 0 }},
|
||||
{ SDP1, { 1, 1 }},
|
||||
{ SDP2, { 2, 2 }},
|
||||
{ SDP3, { 3, 3 }},
|
||||
{ ONE_PPS, { -1, 5 }},
|
||||
/* name, gpio, delay */
|
||||
{ SDP0, { 0, 0 }, { 0, 1 }},
|
||||
{ SDP1, { 1, 1 }, { 0, 1 }},
|
||||
{ SDP2, { 2, 2 }, { 0, 1 }},
|
||||
{ SDP3, { 3, 3 }, { 0, 1 }},
|
||||
{ ONE_PPS, { -1, 5 }, { 0, 1 }},
|
||||
};
|
||||
|
||||
static const char ice_pin_names_nvm[][64] = {
|
||||
@@ -49,12 +49,12 @@ static const char ice_pin_names_nvm[][64] = {
|
||||
};
|
||||
|
||||
static const struct ice_ptp_pin_desc ice_pin_desc_e810_sma[] = {
|
||||
/* name, gpio */
|
||||
{ GNSS, { 1, -1 }},
|
||||
{ SMA1, { 1, 0 }},
|
||||
{ UFL1, { -1, 0 }},
|
||||
{ SMA2, { 3, 2 }},
|
||||
{ UFL2, { 3, -1 }},
|
||||
/* name, gpio, delay */
|
||||
{ GNSS, { 1, -1 }, { 0, 0 }},
|
||||
{ SMA1, { 1, 0 }, { 0, 1 }},
|
||||
{ UFL1, { -1, 0 }, { 0, 1 }},
|
||||
{ SMA2, { 3, 2 }, { 0, 1 }},
|
||||
{ UFL2, { 3, -1 }, { 0, 0 }},
|
||||
};
|
||||
|
||||
static struct ice_pf *ice_get_ctrl_pf(struct ice_pf *pf)
|
||||
@@ -464,7 +464,9 @@ ice_ptp_is_tx_tracker_up(struct ice_ptp_tx *tx)
|
||||
*/
|
||||
void ice_ptp_req_tx_single_tstamp(struct ice_ptp_tx *tx, u8 idx)
|
||||
{
|
||||
struct ice_e810_params *params;
|
||||
struct ice_ptp_port *ptp_port;
|
||||
unsigned long flags;
|
||||
struct sk_buff *skb;
|
||||
struct ice_pf *pf;
|
||||
|
||||
@@ -473,6 +475,7 @@ void ice_ptp_req_tx_single_tstamp(struct ice_ptp_tx *tx, u8 idx)
|
||||
|
||||
ptp_port = container_of(tx, struct ice_ptp_port, tx);
|
||||
pf = ptp_port_to_pf(ptp_port);
|
||||
params = &pf->hw.ptp.phy.e810;
|
||||
|
||||
/* Drop packets which have waited for more than 2 seconds */
|
||||
if (time_is_before_jiffies(tx->tstamps[idx].start + 2 * HZ)) {
|
||||
@@ -489,11 +492,17 @@ void ice_ptp_req_tx_single_tstamp(struct ice_ptp_tx *tx, u8 idx)
|
||||
|
||||
ice_trace(tx_tstamp_fw_req, tx->tstamps[idx].skb, idx);
|
||||
|
||||
spin_lock_irqsave(¶ms->atqbal_wq.lock, flags);
|
||||
|
||||
params->atqbal_flags |= ATQBAL_FLAGS_INTR_IN_PROGRESS;
|
||||
|
||||
/* Write TS index to read to the PF register so the FW can read it */
|
||||
wr32(&pf->hw, PF_SB_ATQBAL,
|
||||
TS_LL_READ_TS_INTR | FIELD_PREP(TS_LL_READ_TS_IDX, idx) |
|
||||
TS_LL_READ_TS);
|
||||
wr32(&pf->hw, REG_LL_PROXY_H,
|
||||
REG_LL_PROXY_H_TS_INTR_ENA | FIELD_PREP(REG_LL_PROXY_H_TS_IDX, idx) |
|
||||
REG_LL_PROXY_H_EXEC);
|
||||
tx->last_ll_ts_idx_read = idx;
|
||||
|
||||
spin_unlock_irqrestore(¶ms->atqbal_wq.lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -504,35 +513,52 @@ void ice_ptp_complete_tx_single_tstamp(struct ice_ptp_tx *tx)
|
||||
{
|
||||
struct skb_shared_hwtstamps shhwtstamps = {};
|
||||
u8 idx = tx->last_ll_ts_idx_read;
|
||||
struct ice_e810_params *params;
|
||||
struct ice_ptp_port *ptp_port;
|
||||
u64 raw_tstamp, tstamp;
|
||||
bool drop_ts = false;
|
||||
struct sk_buff *skb;
|
||||
unsigned long flags;
|
||||
struct device *dev;
|
||||
struct ice_pf *pf;
|
||||
u32 val;
|
||||
u32 reg_ll_high;
|
||||
|
||||
if (!tx->init || tx->last_ll_ts_idx_read < 0)
|
||||
return;
|
||||
|
||||
ptp_port = container_of(tx, struct ice_ptp_port, tx);
|
||||
pf = ptp_port_to_pf(ptp_port);
|
||||
dev = ice_pf_to_dev(pf);
|
||||
params = &pf->hw.ptp.phy.e810;
|
||||
|
||||
ice_trace(tx_tstamp_fw_done, tx->tstamps[idx].skb, idx);
|
||||
|
||||
val = rd32(&pf->hw, PF_SB_ATQBAL);
|
||||
spin_lock_irqsave(¶ms->atqbal_wq.lock, flags);
|
||||
|
||||
if (!(params->atqbal_flags & ATQBAL_FLAGS_INTR_IN_PROGRESS))
|
||||
dev_dbg(dev, "%s: low latency interrupt request not in progress?\n",
|
||||
__func__);
|
||||
|
||||
/* Read the low 32 bit value */
|
||||
raw_tstamp = rd32(&pf->hw, REG_LL_PROXY_L);
|
||||
/* Read the status together with high TS part */
|
||||
reg_ll_high = rd32(&pf->hw, REG_LL_PROXY_H);
|
||||
|
||||
/* Wake up threads waiting on low latency interface */
|
||||
params->atqbal_flags &= ~ATQBAL_FLAGS_INTR_IN_PROGRESS;
|
||||
|
||||
wake_up_locked(¶ms->atqbal_wq);
|
||||
|
||||
spin_unlock_irqrestore(¶ms->atqbal_wq.lock, flags);
|
||||
|
||||
/* When the bit is cleared, the TS is ready in the register */
|
||||
if (val & TS_LL_READ_TS) {
|
||||
if (reg_ll_high & REG_LL_PROXY_H_EXEC) {
|
||||
dev_err(ice_pf_to_dev(pf), "Failed to get the Tx tstamp - FW not ready");
|
||||
return;
|
||||
}
|
||||
|
||||
/* High 8 bit value of the TS is on the bits 16:23 */
|
||||
raw_tstamp = FIELD_GET(TS_LL_READ_TS_HIGH, val);
|
||||
raw_tstamp <<= 32;
|
||||
|
||||
/* Read the low 32 bit value */
|
||||
raw_tstamp |= (u64)rd32(&pf->hw, PF_SB_ATQBAH);
|
||||
raw_tstamp |= ((u64)FIELD_GET(REG_LL_PROXY_H_TS_HIGH, reg_ll_high)) << 32;
|
||||
|
||||
/* Devices using this interface always verify the timestamp differs
|
||||
* relative to the last cached timestamp value.
|
||||
@@ -1566,18 +1592,29 @@ void ice_ptp_extts_event(struct ice_pf *pf)
|
||||
* Event is defined in GLTSYN_EVNT_0 register
|
||||
*/
|
||||
for (chan = 0; chan < GLTSYN_EVNT_H_IDX_MAX; chan++) {
|
||||
/* Check if channel is enabled */
|
||||
if (pf->ptp.ext_ts_irq & (1 << chan)) {
|
||||
lo = rd32(hw, GLTSYN_EVNT_L(chan, tmr_idx));
|
||||
hi = rd32(hw, GLTSYN_EVNT_H(chan, tmr_idx));
|
||||
event.timestamp = (((u64)hi) << 32) | lo;
|
||||
event.type = PTP_CLOCK_EXTTS;
|
||||
event.index = chan;
|
||||
int pin_desc_idx;
|
||||
|
||||
/* Fire event */
|
||||
ptp_clock_event(pf->ptp.clock, &event);
|
||||
pf->ptp.ext_ts_irq &= ~(1 << chan);
|
||||
/* Check if channel is enabled */
|
||||
if (!(pf->ptp.ext_ts_irq & (1 << chan)))
|
||||
continue;
|
||||
|
||||
lo = rd32(hw, GLTSYN_EVNT_L(chan, tmr_idx));
|
||||
hi = rd32(hw, GLTSYN_EVNT_H(chan, tmr_idx));
|
||||
event.timestamp = (u64)hi << 32 | lo;
|
||||
|
||||
/* Add delay compensation */
|
||||
pin_desc_idx = ice_ptp_find_pin_idx(pf, PTP_PF_EXTTS, chan);
|
||||
if (pin_desc_idx >= 0) {
|
||||
const struct ice_ptp_pin_desc *desc;
|
||||
|
||||
desc = &pf->ptp.ice_pin_desc[pin_desc_idx];
|
||||
event.timestamp -= desc->delay[0];
|
||||
}
|
||||
|
||||
event.type = PTP_CLOCK_EXTTS;
|
||||
event.index = chan;
|
||||
pf->ptp.ext_ts_irq &= ~(1 << chan);
|
||||
ptp_clock_event(pf->ptp.clock, &event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1772,9 +1809,9 @@ static int ice_ptp_write_perout(struct ice_hw *hw, unsigned int chan,
|
||||
static int ice_ptp_cfg_perout(struct ice_pf *pf, struct ptp_perout_request *rq,
|
||||
int on)
|
||||
{
|
||||
unsigned int gpio_pin, prop_delay_ns;
|
||||
u64 clk, period, start, phase;
|
||||
struct ice_hw *hw = &pf->hw;
|
||||
unsigned int gpio_pin;
|
||||
int pin_desc_idx;
|
||||
|
||||
if (rq->flags & ~PTP_PEROUT_PHASE)
|
||||
@@ -1785,6 +1822,7 @@ static int ice_ptp_cfg_perout(struct ice_pf *pf, struct ptp_perout_request *rq,
|
||||
return -EIO;
|
||||
|
||||
gpio_pin = pf->ptp.ice_pin_desc[pin_desc_idx].gpio[1];
|
||||
prop_delay_ns = pf->ptp.ice_pin_desc[pin_desc_idx].delay[1];
|
||||
period = rq->period.sec * NSEC_PER_SEC + rq->period.nsec;
|
||||
|
||||
/* If we're disabling the output or period is 0, clear out CLKO and TGT
|
||||
@@ -1816,11 +1854,11 @@ static int ice_ptp_cfg_perout(struct ice_pf *pf, struct ptp_perout_request *rq,
|
||||
* at the next multiple of period, maintaining phase.
|
||||
*/
|
||||
clk = ice_ptp_read_src_clk_reg(pf, NULL);
|
||||
if (rq->flags & PTP_PEROUT_PHASE || start <= clk - ice_prop_delay(hw))
|
||||
if (rq->flags & PTP_PEROUT_PHASE || start <= clk - prop_delay_ns)
|
||||
start = div64_u64(clk + period - 1, period) * period + phase;
|
||||
|
||||
/* Compensate for propagation delay from the generator to the pin. */
|
||||
start -= ice_prop_delay(hw);
|
||||
start -= prop_delay_ns;
|
||||
|
||||
return ice_ptp_write_perout(hw, rq->index, gpio_pin, start, period);
|
||||
}
|
||||
|
||||
@@ -211,6 +211,7 @@ enum ice_ptp_pin_nvm {
|
||||
* struct ice_ptp_pin_desc - hardware pin description data
|
||||
* @name_idx: index of the name of pin in ice_pin_names
|
||||
* @gpio: the associated GPIO input and output pins
|
||||
* @delay: input and output signal delays in nanoseconds
|
||||
*
|
||||
* Structure describing a PTP-capable GPIO pin that extends ptp_pin_desc array
|
||||
* for the device. Device families have separate sets of available pins with
|
||||
@@ -219,6 +220,7 @@ enum ice_ptp_pin_nvm {
|
||||
struct ice_ptp_pin_desc {
|
||||
int name_idx;
|
||||
int gpio[2];
|
||||
unsigned int delay[2];
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -341,8 +341,6 @@ const struct ice_time_ref_info_e82x e82x_time_ref[NUM_ICE_TIME_REF_FREQ] = {
|
||||
823437500, /* 823.4375 MHz PLL */
|
||||
/* nominal_incval */
|
||||
0x136e44fabULL,
|
||||
/* pps_delay */
|
||||
11,
|
||||
},
|
||||
|
||||
/* ICE_TIME_REF_FREQ_122_880 -> 122.88 MHz */
|
||||
@@ -351,8 +349,6 @@ const struct ice_time_ref_info_e82x e82x_time_ref[NUM_ICE_TIME_REF_FREQ] = {
|
||||
783360000, /* 783.36 MHz */
|
||||
/* nominal_incval */
|
||||
0x146cc2177ULL,
|
||||
/* pps_delay */
|
||||
12,
|
||||
},
|
||||
|
||||
/* ICE_TIME_REF_FREQ_125_000 -> 125 MHz */
|
||||
@@ -361,8 +357,6 @@ const struct ice_time_ref_info_e82x e82x_time_ref[NUM_ICE_TIME_REF_FREQ] = {
|
||||
796875000, /* 796.875 MHz */
|
||||
/* nominal_incval */
|
||||
0x141414141ULL,
|
||||
/* pps_delay */
|
||||
12,
|
||||
},
|
||||
|
||||
/* ICE_TIME_REF_FREQ_153_600 -> 153.6 MHz */
|
||||
@@ -371,8 +365,6 @@ const struct ice_time_ref_info_e82x e82x_time_ref[NUM_ICE_TIME_REF_FREQ] = {
|
||||
816000000, /* 816 MHz */
|
||||
/* nominal_incval */
|
||||
0x139b9b9baULL,
|
||||
/* pps_delay */
|
||||
12,
|
||||
},
|
||||
|
||||
/* ICE_TIME_REF_FREQ_156_250 -> 156.25 MHz */
|
||||
@@ -381,8 +373,6 @@ const struct ice_time_ref_info_e82x e82x_time_ref[NUM_ICE_TIME_REF_FREQ] = {
|
||||
830078125, /* 830.78125 MHz */
|
||||
/* nominal_incval */
|
||||
0x134679aceULL,
|
||||
/* pps_delay */
|
||||
11,
|
||||
},
|
||||
|
||||
/* ICE_TIME_REF_FREQ_245_760 -> 245.76 MHz */
|
||||
@@ -391,8 +381,6 @@ const struct ice_time_ref_info_e82x e82x_time_ref[NUM_ICE_TIME_REF_FREQ] = {
|
||||
783360000, /* 783.36 MHz */
|
||||
/* nominal_incval */
|
||||
0x146cc2177ULL,
|
||||
/* pps_delay */
|
||||
12,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -391,7 +391,7 @@ static int ice_cfg_cgu_pll_e82x(struct ice_hw *hw,
|
||||
|
||||
/* Log the current clock configuration */
|
||||
ice_debug(hw, ICE_DBG_PTP, "Current CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n",
|
||||
dw24.ts_pll_enable ? "enabled" : "disabled",
|
||||
str_enabled_disabled(dw24.ts_pll_enable),
|
||||
ice_clk_src_str(dw24.time_ref_sel),
|
||||
ice_clk_freq_str(dw9.time_ref_freq_sel),
|
||||
bwm_lf.plllock_true_lock_cri ? "locked" : "unlocked");
|
||||
@@ -469,7 +469,7 @@ static int ice_cfg_cgu_pll_e82x(struct ice_hw *hw,
|
||||
|
||||
/* Log the current clock configuration */
|
||||
ice_debug(hw, ICE_DBG_PTP, "New CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n",
|
||||
dw24.ts_pll_enable ? "enabled" : "disabled",
|
||||
str_enabled_disabled(dw24.ts_pll_enable),
|
||||
ice_clk_src_str(dw24.time_ref_sel),
|
||||
ice_clk_freq_str(dw9.time_ref_freq_sel),
|
||||
bwm_lf.plllock_true_lock_cri ? "locked" : "unlocked");
|
||||
@@ -546,7 +546,7 @@ static int ice_cfg_cgu_pll_e825c(struct ice_hw *hw,
|
||||
|
||||
/* Log the current clock configuration */
|
||||
ice_debug(hw, ICE_DBG_PTP, "Current CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n",
|
||||
dw24.ts_pll_enable ? "enabled" : "disabled",
|
||||
str_enabled_disabled(dw24.ts_pll_enable),
|
||||
ice_clk_src_str(dw23.time_ref_sel),
|
||||
ice_clk_freq_str(dw9.time_ref_freq_sel),
|
||||
ro_lock.plllock_true_lock_cri ? "locked" : "unlocked");
|
||||
@@ -651,7 +651,7 @@ static int ice_cfg_cgu_pll_e825c(struct ice_hw *hw,
|
||||
|
||||
/* Log the current clock configuration */
|
||||
ice_debug(hw, ICE_DBG_PTP, "New CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n",
|
||||
dw24.ts_pll_enable ? "enabled" : "disabled",
|
||||
str_enabled_disabled(dw24.ts_pll_enable),
|
||||
ice_clk_src_str(dw23.time_ref_sel),
|
||||
ice_clk_freq_str(dw9.time_ref_freq_sel),
|
||||
ro_lock.plllock_true_lock_cri ? "locked" : "unlocked");
|
||||
@@ -4857,33 +4857,46 @@ static int ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val)
|
||||
static int
|
||||
ice_read_phy_tstamp_ll_e810(struct ice_hw *hw, u8 idx, u8 *hi, u32 *lo)
|
||||
{
|
||||
struct ice_e810_params *params = &hw->ptp.phy.e810;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
u8 i;
|
||||
int err;
|
||||
|
||||
/* Write TS index to read to the PF register so the FW can read it */
|
||||
val = FIELD_PREP(TS_LL_READ_TS_IDX, idx) | TS_LL_READ_TS;
|
||||
wr32(hw, PF_SB_ATQBAL, val);
|
||||
spin_lock_irqsave(¶ms->atqbal_wq.lock, flags);
|
||||
|
||||
/* Read the register repeatedly until the FW provides us the TS */
|
||||
for (i = TS_LL_READ_RETRIES; i > 0; i--) {
|
||||
val = rd32(hw, PF_SB_ATQBAL);
|
||||
|
||||
/* When the bit is cleared, the TS is ready in the register */
|
||||
if (!(FIELD_GET(TS_LL_READ_TS, val))) {
|
||||
/* High 8 bit value of the TS is on the bits 16:23 */
|
||||
*hi = FIELD_GET(TS_LL_READ_TS_HIGH, val);
|
||||
|
||||
/* Read the low 32 bit value and set the TS valid bit */
|
||||
*lo = rd32(hw, PF_SB_ATQBAH) | TS_VALID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
udelay(10);
|
||||
/* Wait for any pending in-progress low latency interrupt */
|
||||
err = wait_event_interruptible_locked_irq(params->atqbal_wq,
|
||||
!(params->atqbal_flags &
|
||||
ATQBAL_FLAGS_INTR_IN_PROGRESS));
|
||||
if (err) {
|
||||
spin_unlock_irqrestore(¶ms->atqbal_wq.lock, flags);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* FW failed to provide the TS in time */
|
||||
ice_debug(hw, ICE_DBG_PTP, "Failed to read PTP timestamp using low latency read\n");
|
||||
return -EINVAL;
|
||||
/* Write TS index to read to the PF register so the FW can read it */
|
||||
val = FIELD_PREP(REG_LL_PROXY_H_TS_IDX, idx) | REG_LL_PROXY_H_EXEC;
|
||||
wr32(hw, REG_LL_PROXY_H, val);
|
||||
|
||||
/* Read the register repeatedly until the FW provides us the TS */
|
||||
err = read_poll_timeout_atomic(rd32, val,
|
||||
!FIELD_GET(REG_LL_PROXY_H_EXEC, val), 10,
|
||||
REG_LL_PROXY_H_TIMEOUT_US, false, hw,
|
||||
REG_LL_PROXY_H);
|
||||
if (err) {
|
||||
ice_debug(hw, ICE_DBG_PTP, "Failed to read PTP timestamp using low latency read\n");
|
||||
spin_unlock_irqrestore(¶ms->atqbal_wq.lock, flags);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* High 8 bit value of the TS is on the bits 16:23 */
|
||||
*hi = FIELD_GET(REG_LL_PROXY_H_TS_HIGH, val);
|
||||
|
||||
/* Read the low 32 bit value and set the TS valid bit */
|
||||
*lo = rd32(hw, REG_LL_PROXY_L) | TS_VALID;
|
||||
|
||||
spin_unlock_irqrestore(¶ms->atqbal_wq.lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5065,6 +5078,55 @@ static int ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_ptp_prep_phy_adj_ll_e810 - Prep PHY ports for a time adjustment
|
||||
* @hw: pointer to HW struct
|
||||
* @adj: adjustment value to program
|
||||
*
|
||||
* Use the low latency firmware interface to program PHY time adjustment to
|
||||
* all PHY ports.
|
||||
*
|
||||
* Return: 0 on success, -EBUSY on timeout
|
||||
*/
|
||||
static int ice_ptp_prep_phy_adj_ll_e810(struct ice_hw *hw, s32 adj)
|
||||
{
|
||||
const u8 tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
|
||||
struct ice_e810_params *params = &hw->ptp.phy.e810;
|
||||
u32 val;
|
||||
int err;
|
||||
|
||||
spin_lock_irq(¶ms->atqbal_wq.lock);
|
||||
|
||||
/* Wait for any pending in-progress low latency interrupt */
|
||||
err = wait_event_interruptible_locked_irq(params->atqbal_wq,
|
||||
!(params->atqbal_flags &
|
||||
ATQBAL_FLAGS_INTR_IN_PROGRESS));
|
||||
if (err) {
|
||||
spin_unlock_irq(¶ms->atqbal_wq.lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
wr32(hw, REG_LL_PROXY_L, adj);
|
||||
val = FIELD_PREP(REG_LL_PROXY_H_PHY_TMR_CMD_M, REG_LL_PROXY_H_PHY_TMR_CMD_ADJ) |
|
||||
FIELD_PREP(REG_LL_PROXY_H_PHY_TMR_IDX_M, tmr_idx) | REG_LL_PROXY_H_EXEC;
|
||||
wr32(hw, REG_LL_PROXY_H, val);
|
||||
|
||||
/* Read the register repeatedly until the FW indicates completion */
|
||||
err = read_poll_timeout_atomic(rd32, val,
|
||||
!FIELD_GET(REG_LL_PROXY_H_EXEC, val),
|
||||
10, REG_LL_PROXY_H_TIMEOUT_US, false, hw,
|
||||
REG_LL_PROXY_H);
|
||||
if (err) {
|
||||
ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY timer adjustment using low latency interface\n");
|
||||
spin_unlock_irq(¶ms->atqbal_wq.lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
spin_unlock_irq(¶ms->atqbal_wq.lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_ptp_prep_phy_adj_e810 - Prep PHY port for a time adjustment
|
||||
* @hw: pointer to HW struct
|
||||
@@ -5083,6 +5145,9 @@ static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj)
|
||||
u8 tmr_idx;
|
||||
int err;
|
||||
|
||||
if (hw->dev_caps.ts_dev_info.ll_phy_tmr_update)
|
||||
return ice_ptp_prep_phy_adj_ll_e810(hw, adj);
|
||||
|
||||
tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
|
||||
|
||||
/* Adjustments are represented as signed 2's complement values in
|
||||
@@ -5105,6 +5170,56 @@ static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_ptp_prep_phy_incval_ll_e810 - Prep PHY ports increment value change
|
||||
* @hw: pointer to HW struct
|
||||
* @incval: The new 40bit increment value to prepare
|
||||
*
|
||||
* Use the low latency firmware interface to program PHY time increment value
|
||||
* for all PHY ports.
|
||||
*
|
||||
* Return: 0 on success, -EBUSY on timeout
|
||||
*/
|
||||
static int ice_ptp_prep_phy_incval_ll_e810(struct ice_hw *hw, u64 incval)
|
||||
{
|
||||
const u8 tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
|
||||
struct ice_e810_params *params = &hw->ptp.phy.e810;
|
||||
u32 val;
|
||||
int err;
|
||||
|
||||
spin_lock_irq(¶ms->atqbal_wq.lock);
|
||||
|
||||
/* Wait for any pending in-progress low latency interrupt */
|
||||
err = wait_event_interruptible_locked_irq(params->atqbal_wq,
|
||||
!(params->atqbal_flags &
|
||||
ATQBAL_FLAGS_INTR_IN_PROGRESS));
|
||||
if (err) {
|
||||
spin_unlock_irq(¶ms->atqbal_wq.lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
wr32(hw, REG_LL_PROXY_L, lower_32_bits(incval));
|
||||
val = FIELD_PREP(REG_LL_PROXY_H_PHY_TMR_CMD_M, REG_LL_PROXY_H_PHY_TMR_CMD_FREQ) |
|
||||
FIELD_PREP(REG_LL_PROXY_H_TS_HIGH, (u8)upper_32_bits(incval)) |
|
||||
FIELD_PREP(REG_LL_PROXY_H_PHY_TMR_IDX_M, tmr_idx) | REG_LL_PROXY_H_EXEC;
|
||||
wr32(hw, REG_LL_PROXY_H, val);
|
||||
|
||||
/* Read the register repeatedly until the FW indicates completion */
|
||||
err = read_poll_timeout_atomic(rd32, val,
|
||||
!FIELD_GET(REG_LL_PROXY_H_EXEC, val),
|
||||
10, REG_LL_PROXY_H_TIMEOUT_US, false, hw,
|
||||
REG_LL_PROXY_H);
|
||||
if (err) {
|
||||
ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY timer increment using low latency interface\n");
|
||||
spin_unlock_irq(¶ms->atqbal_wq.lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
spin_unlock_irq(¶ms->atqbal_wq.lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_ptp_prep_phy_incval_e810 - Prep PHY port increment value change
|
||||
* @hw: pointer to HW struct
|
||||
@@ -5120,6 +5235,9 @@ static int ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval)
|
||||
u8 tmr_idx;
|
||||
int err;
|
||||
|
||||
if (hw->dev_caps.ts_dev_info.ll_phy_tmr_update)
|
||||
return ice_ptp_prep_phy_incval_ll_e810(hw, incval);
|
||||
|
||||
tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
|
||||
low = lower_32_bits(incval);
|
||||
high = upper_32_bits(incval);
|
||||
@@ -5404,6 +5522,8 @@ static void ice_ptp_init_phy_e810(struct ice_ptp_hw *ptp)
|
||||
ptp->phy_model = ICE_PHY_E810;
|
||||
ptp->num_lports = 8;
|
||||
ptp->ports_per_phy = 4;
|
||||
|
||||
init_waitqueue_head(&ptp->phy.e810.atqbal_wq);
|
||||
}
|
||||
|
||||
/* Device agnostic functions
|
||||
|
||||
@@ -80,7 +80,6 @@ struct ice_phy_reg_info_eth56g {
|
||||
* struct ice_time_ref_info_e82x
|
||||
* @pll_freq: Frequency of PLL that drives timer ticks in Hz
|
||||
* @nominal_incval: increment to generate nanoseconds in GLTSYN_TIME_L
|
||||
* @pps_delay: propagation delay of the PPS output signal
|
||||
*
|
||||
* Characteristic information for the various TIME_REF sources possible in the
|
||||
* E822 devices
|
||||
@@ -88,7 +87,6 @@ struct ice_phy_reg_info_eth56g {
|
||||
struct ice_time_ref_info_e82x {
|
||||
u64 pll_freq;
|
||||
u64 nominal_incval;
|
||||
u8 pps_delay;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -326,8 +324,6 @@ extern const struct ice_vernier_info_e82x e822_vernier[NUM_ICE_PTP_LNK_SPD];
|
||||
*/
|
||||
#define ICE_E810_PLL_FREQ 812500000
|
||||
#define ICE_PTP_NOMINAL_INCVAL_E810 0x13b13b13bULL
|
||||
#define ICE_E810_OUT_PROP_DELAY_NS 1
|
||||
#define ICE_E825C_OUT_PROP_DELAY_NS 11
|
||||
|
||||
/* Device agnostic functions */
|
||||
u8 ice_get_ptp_src_clock_index(struct ice_hw *hw);
|
||||
@@ -389,11 +385,6 @@ static inline u64 ice_e82x_nominal_incval(enum ice_time_ref_freq time_ref)
|
||||
return e82x_time_ref[time_ref].nominal_incval;
|
||||
}
|
||||
|
||||
static inline u64 ice_e82x_pps_delay(enum ice_time_ref_freq time_ref)
|
||||
{
|
||||
return e82x_time_ref[time_ref].pps_delay;
|
||||
}
|
||||
|
||||
/* E822 Vernier calibration functions */
|
||||
int ice_stop_phy_timer_e82x(struct ice_hw *hw, u8 port, bool soft_reset);
|
||||
int ice_start_phy_timer_e82x(struct ice_hw *hw, u8 port);
|
||||
@@ -432,20 +423,6 @@ int ice_phy_cfg_ptp_1step_eth56g(struct ice_hw *hw, u8 port);
|
||||
#define ICE_ETH56G_NOMINAL_THRESH4 0x7777
|
||||
#define ICE_ETH56G_NOMINAL_TX_THRESH 0x6
|
||||
|
||||
static inline u64 ice_prop_delay(const struct ice_hw *hw)
|
||||
{
|
||||
switch (hw->ptp.phy_model) {
|
||||
case ICE_PHY_ETH56G:
|
||||
return ICE_E825C_OUT_PROP_DELAY_NS;
|
||||
case ICE_PHY_E810:
|
||||
return ICE_E810_OUT_PROP_DELAY_NS;
|
||||
case ICE_PHY_E82X:
|
||||
return ice_e82x_pps_delay(ice_e82x_time_ref(hw));
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_get_base_incval - Get base clock increment value
|
||||
* @hw: pointer to the HW struct
|
||||
@@ -689,11 +666,18 @@ static inline bool ice_is_dual(struct ice_hw *hw)
|
||||
#define BYTES_PER_IDX_ADDR_L 4
|
||||
|
||||
/* Tx timestamp low latency read definitions */
|
||||
#define TS_LL_READ_RETRIES 200
|
||||
#define TS_LL_READ_TS_HIGH GENMASK(23, 16)
|
||||
#define TS_LL_READ_TS_IDX GENMASK(29, 24)
|
||||
#define TS_LL_READ_TS_INTR BIT(30)
|
||||
#define TS_LL_READ_TS BIT(31)
|
||||
#define REG_LL_PROXY_H_TIMEOUT_US 2000
|
||||
#define REG_LL_PROXY_H_PHY_TMR_CMD_M GENMASK(7, 6)
|
||||
#define REG_LL_PROXY_H_PHY_TMR_CMD_ADJ 0x1
|
||||
#define REG_LL_PROXY_H_PHY_TMR_CMD_FREQ 0x2
|
||||
#define REG_LL_PROXY_H_TS_HIGH GENMASK(23, 16)
|
||||
#define REG_LL_PROXY_H_PHY_TMR_IDX_M BIT(24)
|
||||
#define REG_LL_PROXY_H_TS_IDX GENMASK(29, 24)
|
||||
#define REG_LL_PROXY_H_TS_INTR_ENA BIT(30)
|
||||
#define REG_LL_PROXY_H_EXEC BIT(31)
|
||||
|
||||
#define REG_LL_PROXY_L PF_SB_ATQBAH
|
||||
#define REG_LL_PROXY_H PF_SB_ATQBAL
|
||||
|
||||
/* Internal PHY timestamp address */
|
||||
#define TS_L(a, idx) ((a) + ((idx) * BYTES_PER_IDX_ADDR_L_U))
|
||||
|
||||
@@ -4784,7 +4784,8 @@ ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts,
|
||||
*/
|
||||
if (found && recp[i].tun_type == rinfo->tun_type &&
|
||||
recp[i].need_pass_l2 == rinfo->need_pass_l2 &&
|
||||
recp[i].allow_pass_l2 == rinfo->allow_pass_l2)
|
||||
recp[i].allow_pass_l2 == rinfo->allow_pass_l2 &&
|
||||
recp[i].priority == rinfo->priority)
|
||||
return i; /* Return the recipe ID */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "ice_sbq_cmd.h"
|
||||
#include "ice_vlan_mode.h"
|
||||
#include "ice_fwlog.h"
|
||||
#include <linux/wait.h>
|
||||
|
||||
static inline bool ice_is_tc_ena(unsigned long bitmap, u8 tc)
|
||||
{
|
||||
@@ -368,6 +369,7 @@ struct ice_ts_func_info {
|
||||
#define ICE_TS_TMR1_ENA_M BIT(26)
|
||||
#define ICE_TS_LL_TX_TS_READ_M BIT(28)
|
||||
#define ICE_TS_LL_TX_TS_INT_READ_M BIT(29)
|
||||
#define ICE_TS_LL_PHY_TMR_UPDATE_M BIT(30)
|
||||
|
||||
struct ice_ts_dev_info {
|
||||
/* Device specific info */
|
||||
@@ -382,6 +384,7 @@ struct ice_ts_dev_info {
|
||||
u8 tmr1_ena;
|
||||
u8 ts_ll_read;
|
||||
u8 ts_ll_int_read;
|
||||
u8 ll_phy_tmr_update;
|
||||
};
|
||||
|
||||
#define ICE_NAC_TOPO_PRIMARY_M BIT(0)
|
||||
@@ -848,6 +851,14 @@ struct ice_mbx_data {
|
||||
#define ICE_PORTS_PER_QUAD 4
|
||||
#define ICE_GET_QUAD_NUM(port) ((port) / ICE_PORTS_PER_QUAD)
|
||||
|
||||
#define ATQBAL_FLAGS_INTR_IN_PROGRESS BIT(0)
|
||||
|
||||
struct ice_e810_params {
|
||||
/* The wait queue lock also protects the low latency interface */
|
||||
wait_queue_head_t atqbal_wq;
|
||||
unsigned int atqbal_flags;
|
||||
};
|
||||
|
||||
struct ice_eth56g_params {
|
||||
u8 num_phys;
|
||||
u8 phy_addr[2];
|
||||
@@ -857,6 +868,7 @@ struct ice_eth56g_params {
|
||||
};
|
||||
|
||||
union ice_phy_params {
|
||||
struct ice_e810_params e810;
|
||||
struct ice_eth56g_params eth56g;
|
||||
};
|
||||
|
||||
@@ -1216,4 +1228,9 @@ struct ice_aq_get_set_rss_lut_params {
|
||||
#define ICE_FW_API_REPORT_DFLT_CFG_MIN 7
|
||||
#define ICE_FW_API_REPORT_DFLT_CFG_PATCH 3
|
||||
|
||||
/* AQ API version for Health Status support */
|
||||
#define ICE_FW_API_HEALTH_REPORT_MAJ 1
|
||||
#define ICE_FW_API_HEALTH_REPORT_MIN 7
|
||||
#define ICE_FW_API_HEALTH_REPORT_PATCH 6
|
||||
|
||||
#endif /* _ICE_TYPE_H_ */
|
||||
|
||||
Reference in New Issue
Block a user