ixl(4): Add link state polling

In some cases driver may ask FW about link state before FW finishes
configuration of a (Q)SFP+ transceiver. If first attempt of using Get Link
Status AQC after loading driver or handling a reset fails, then re-try
periodically for 5 seconds.

Signed-off-by: Krzysztof Galazka <krzysztof.galazka@intel.com>
Signed-off-by: Eric Joyner <erj@FreeBSD.org>

Tested by:	jeffrey.e.pieper@intel.com
Approved by:	erj@
MFC after:	2 days
Sponsored by:	Intel Corporation
Differential Revision:	https://reviews.freebsd.org/D40899
This commit is contained in:
Krzysztof Galazka 2023-07-20 15:33:52 -07:00 committed by Eric Joyner
parent 1d9722de6f
commit ba2f531f81
No known key found for this signature in database
GPG key ID: 96F0C6FD61E05DE3
7 changed files with 75 additions and 19 deletions

View file

@ -44,7 +44,7 @@
#define I40E_FW_API_VERSION_MAJOR 0x0001
#define I40E_FW_API_VERSION_MINOR_X722 0x000C
#define I40E_FW_API_VERSION_MINOR_X710 0x000E
#define I40E_FW_API_VERSION_MINOR_X710 0x000F
#define I40E_FW_MINOR_VERSION(_h) ((_h)->mac.type == I40E_MAC_XL710 ? \
I40E_FW_API_VERSION_MINOR_X710 : \

View file

@ -444,6 +444,29 @@ ixl_admin_timer(void *arg)
{
struct ixl_pf *pf = (struct ixl_pf *)arg;
if (ixl_test_state(&pf->state, IXL_STATE_LINK_POLLING)) {
struct i40e_hw *hw = &pf->hw;
sbintime_t stime;
enum i40e_status_code status;
hw->phy.get_link_info = TRUE;
status = i40e_get_link_status(hw, &pf->link_up);
if (status == I40E_SUCCESS) {
ixl_clear_state(&pf->state, IXL_STATE_LINK_POLLING);
/* OS link info is updated in the admin task */
} else {
device_printf(pf->dev,
"%s: i40e_get_link_status status %s, aq error %s\n",
__func__, i40e_stat_str(hw, status),
i40e_aq_str(hw, hw->aq.asq_last_status));
stime = getsbinuptime();
if (stime - pf->link_poll_start > IXL_PF_MAX_LINK_POLL) {
device_printf(pf->dev, "Polling link status failed\n");
ixl_clear_state(&pf->state, IXL_STATE_LINK_POLLING);
}
}
}
/* Fire off the admin task */
iflib_admin_intr_deferred(pf->vsi.ctx);
@ -706,12 +729,6 @@ ixl_if_attach_post(if_ctx_t ctx)
return (0);
}
/* Determine link state */
if (ixl_attach_get_link_status(pf)) {
error = EINVAL;
goto err;
}
error = ixl_switch_config(pf);
if (error) {
device_printf(dev, "Initial ixl_switch_config() failed: %d\n",
@ -740,6 +757,11 @@ ixl_if_attach_post(if_ctx_t ctx)
device_printf(dev, "Allocating %d queues for PF LAN VSI; %d queues active\n",
pf->qtag.num_allocated, pf->qtag.num_active);
/* Determine link state */
error = ixl_attach_get_link_status(pf);
if (error == EINVAL)
goto err;
/* Limit PHY interrupts to link, autoneg, and modules failure */
status = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK,
NULL);
@ -775,8 +797,20 @@ ixl_if_attach_post(if_ctx_t ctx)
ixl_set_link(pf, ixl_test_state(&pf->state, IXL_STATE_LINK_ACTIVE_ON_DOWN));
hw->phy.get_link_info = true;
i40e_get_link_status(hw, &pf->link_up);
ixl_update_link_status(pf);
status = i40e_get_link_status(hw, &pf->link_up);
if (status != I40E_SUCCESS) {
device_printf(dev,
"%s get link status, status: %s aq_err=%s\n",
__func__, i40e_stat_str(hw, status),
i40e_aq_str(hw, hw->aq.asq_last_status));
/*
* Most probably FW has not finished configuring PHY.
* Retry periodically in a timer callback.
*/
ixl_set_state(&pf->state, IXL_STATE_LINK_POLLING);
pf->link_poll_start = getsbinuptime();
} else
ixl_update_link_status(pf);
#ifdef PCI_IOV
ixl_initialize_sriov(pf);

View file

@ -286,6 +286,8 @@
/* For stats sysctl naming */
#define IXL_QUEUE_NAME_LEN 32
#define IXL_PF_MAX_LINK_POLL SBT_1S * 5
MALLOC_DECLARE(M_IXL);
#define IXL_DEV_ERR(_dev, _format, ...) \

View file

@ -101,6 +101,8 @@ enum ixl_dbg_mask {
IXL_DBG_SWITCH_INFO = 0x00010000,
IXL_DBG_I2C = 0x00020000,
IXL_DBG_LINK = 0x00100000,
IXL_DBG_ALL = 0xFFFFFFFF
};

View file

@ -89,6 +89,7 @@ enum ixl_state {
IXL_STATE_FW_LLDP_DISABLED = 9,
IXL_STATE_EEE_ENABLED = 10,
IXL_STATE_LINK_ACTIVE_ON_DOWN = 11,
IXL_STATE_LINK_POLLING = 12,
};
#define IXL_PF_IN_RECOVERY_MODE(pf) \
@ -172,6 +173,8 @@ struct ixl_pf {
int num_vfs;
uint16_t veb_seid;
int vc_debug_lvl;
sbintime_t link_poll_start;
};
/*
@ -282,6 +285,7 @@ struct ixl_pf {
#define ixl_dbg_info(pf, s, ...) ixl_debug_core((pf)->dev, (pf)->dbg_mask, IXL_DBG_INFO, s, ##__VA_ARGS__)
#define ixl_dbg_filter(pf, s, ...) ixl_debug_core((pf)->dev, (pf)->dbg_mask, IXL_DBG_FILTER, s, ##__VA_ARGS__)
#define ixl_dbg_iov(pf, s, ...) ixl_debug_core((pf)->dev, (pf)->dbg_mask, IXL_DBG_IOV, s, ##__VA_ARGS__)
#define ixl_dbg_link(pf, s, ...) ixl_debug_core((pf)->dev, (pf)->dbg_mask, IXL_DBG_LINK, s, ##__VA_ARGS__)
/* PF-only function declarations */
void ixl_set_state(volatile u32 *s, enum ixl_state bit);

View file

@ -1028,9 +1028,7 @@ ixl_rebuild_hw_structs_after_reset(struct ixl_pf *pf, bool is_up)
i40e_aq_set_vsi_broadcast(&pf->hw, vsi->seid, TRUE, NULL);
/* Determine link state */
if (ixl_attach_get_link_status(pf)) {
error = EINVAL;
}
ixl_attach_get_link_status(pf);
i40e_aq_set_dcb_parameters(hw, TRUE, NULL);

View file

@ -4705,22 +4705,38 @@ ixl_attach_get_link_status(struct ixl_pf *pf)
{
struct i40e_hw *hw = &pf->hw;
device_t dev = pf->dev;
int error = 0;
enum i40e_status_code status;
if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
(hw->aq.fw_maj_ver < 4)) {
i40e_msec_delay(75);
error = i40e_aq_set_link_restart_an(hw, TRUE, NULL);
if (error) {
device_printf(dev, "link restart failed, aq_err=%d\n",
pf->hw.aq.asq_last_status);
return error;
status = i40e_aq_set_link_restart_an(hw, TRUE, NULL);
if (status != I40E_SUCCESS) {
device_printf(dev,
"%s link restart failed status: %s, aq_err=%s\n",
__func__, i40e_stat_str(hw, status),
i40e_aq_str(hw, hw->aq.asq_last_status));
return (EINVAL);
}
}
/* Determine link state */
hw->phy.get_link_info = TRUE;
i40e_get_link_status(hw, &pf->link_up);
status = i40e_get_link_status(hw, &pf->link_up);
if (status != I40E_SUCCESS) {
device_printf(dev,
"%s get link status, status: %s aq_err=%s\n",
__func__, i40e_stat_str(hw, status),
i40e_aq_str(hw, hw->aq.asq_last_status));
/*
* Most probably FW has not finished configuring PHY.
* Retry periodically in a timer callback.
*/
ixl_set_state(&pf->state, IXL_STATE_LINK_POLLING);
pf->link_poll_start = getsbinuptime();
return (EAGAIN);
}
ixl_dbg_link(pf, "%s link_up: %d\n", __func__, pf->link_up);
/* Flow Control mode not set by user, read current FW settings */
if (pf->fc == -1)