aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKrzysztof Galazka <krzysztof.galazka@intel.com>2023-07-20 22:33:52 +0000
committerEric Joyner <erj@FreeBSD.org>2023-07-27 21:49:13 +0000
commit1f188b9af0755ee1aeb7e1211f274b96952a10f1 (patch)
tree806282c08c6e070776041bcecb26ac625b69e285
parente30d990e1a6fbbed11bfbfa9b130d7a41f28ee8c (diff)
downloadsrc-1f188b9af0755ee1aeb7e1211f274b96952a10f1.tar.gz
src-1f188b9af0755ee1aeb7e1211f274b96952a10f1.zip
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@ Sponsored by: Intel Corporation Differential Revision: https://reviews.freebsd.org/D40899 (cherry picked from commit ba2f531f816a6bc1ef5f2cba4a329ff7bdbec0f3)
-rw-r--r--sys/dev/ixl/i40e_adminq_cmd.h2
-rw-r--r--sys/dev/ixl/if_ixl.c50
-rw-r--r--sys/dev/ixl/ixl.h2
-rw-r--r--sys/dev/ixl/ixl_debug.h2
-rw-r--r--sys/dev/ixl/ixl_pf.h4
-rw-r--r--sys/dev/ixl/ixl_pf_iflib.c4
-rw-r--r--sys/dev/ixl/ixl_pf_main.c30
7 files changed, 75 insertions, 19 deletions
diff --git a/sys/dev/ixl/i40e_adminq_cmd.h b/sys/dev/ixl/i40e_adminq_cmd.h
index 564a076761d0..679e191412cd 100644
--- a/sys/dev/ixl/i40e_adminq_cmd.h
+++ b/sys/dev/ixl/i40e_adminq_cmd.h
@@ -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 : \
diff --git a/sys/dev/ixl/if_ixl.c b/sys/dev/ixl/if_ixl.c
index 65f6a400569c..a18dd4361bac 100644
--- a/sys/dev/ixl/if_ixl.c
+++ b/sys/dev/ixl/if_ixl.c
@@ -449,6 +449,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);
@@ -711,12 +734,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",
@@ -745,6 +762,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);
@@ -780,8 +802,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);
diff --git a/sys/dev/ixl/ixl.h b/sys/dev/ixl/ixl.h
index 9b49520a8851..2f6fe6c959d9 100644
--- a/sys/dev/ixl/ixl.h
+++ b/sys/dev/ixl/ixl.h
@@ -301,6 +301,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, ...) \
diff --git a/sys/dev/ixl/ixl_debug.h b/sys/dev/ixl/ixl_debug.h
index 0d8c624d2df9..818ba8a1df83 100644
--- a/sys/dev/ixl/ixl_debug.h
+++ b/sys/dev/ixl/ixl_debug.h
@@ -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
};
diff --git a/sys/dev/ixl/ixl_pf.h b/sys/dev/ixl/ixl_pf.h
index 6a73f5acc838..90236ac144c8 100644
--- a/sys/dev/ixl/ixl_pf.h
+++ b/sys/dev/ixl/ixl_pf.h
@@ -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);
diff --git a/sys/dev/ixl/ixl_pf_iflib.c b/sys/dev/ixl/ixl_pf_iflib.c
index b70388bd6f6e..326c10ca8bfe 100644
--- a/sys/dev/ixl/ixl_pf_iflib.c
+++ b/sys/dev/ixl/ixl_pf_iflib.c
@@ -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);
diff --git a/sys/dev/ixl/ixl_pf_main.c b/sys/dev/ixl/ixl_pf_main.c
index 5cf686c5b7cf..23da241315e7 100644
--- a/sys/dev/ixl/ixl_pf_main.c
+++ b/sys/dev/ixl/ixl_pf_main.c
@@ -4656,22 +4656,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)