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-20 22:33:52 +0000
commitba2f531f816a6bc1ef5f2cba4a329ff7bdbec0f3 (patch)
tree0bf5de46539aac5286478e74b6e717388f1979d7
parent1d9722de6f90c3edf286b077938bfa696e728d6c (diff)
downloadsrc-ba2f531f816a6bc1ef5f2cba4a329ff7bdbec0f3.tar.gz
src-ba2f531f816a6bc1ef5f2cba4a329ff7bdbec0f3.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@ MFC after: 2 days Sponsored by: Intel Corporation Differential Revision: https://reviews.freebsd.org/D40899
-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 7ebbed1f81c8..6e1a3e3e2229 100644
--- a/sys/dev/ixl/if_ixl.c
+++ b/sys/dev/ixl/if_ixl.c
@@ -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);
diff --git a/sys/dev/ixl/ixl.h b/sys/dev/ixl/ixl.h
index 30e8ce40126b..03a1fa46fa65 100644
--- a/sys/dev/ixl/ixl.h
+++ b/sys/dev/ixl/ixl.h
@@ -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, ...) \
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 80b35fcb6696..9a786845be13 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 e0452c7dc01e..a0b450dc038b 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 1ba59c0592a7..13ba4c5f5d17 100644
--- a/sys/dev/ixl/ixl_pf_main.c
+++ b/sys/dev/ixl/ixl_pf_main.c
@@ -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)