From nobody Mon Nov 02 11:20:15 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4jJ8Pw5bjTz6y85g for ; Mon, 02 Nov 2026 11:20:20 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 4jJ8Pw4zR7z4gvx for ; Mon, 02 Nov 2026 11:20:20 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1793618420; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=8295ViNZuvG9s0rFtfbQnAjgNup40CVbL0DtAfJRs8s=; b=lc57wMVOaFJaZuMuk0uOGTmTRPzb6X3eJ8bz4B0vItEX5FCuqsPNPbYd9adXLrReuREXkc pCZ4TrjNOPEv15OXBAX3oIjxGSUdx/Kp+9tGSAu8w2NpLBatGhP2xeXplnE1uNNrRZUi8u BhHLbVTbD51zAgRqCETgrfMF55fG3dzMcaNMab3FsdzEyJKhVlJCmzd8Qp8E9PMIWbS+6o Q/MqgR9E3HHWeBEdl1NjYa5mRgQ+s1YS7rKI4iJTAh/qXzvDhjpMTXd7wm2EHFm9mMzqkb HIVmoyNfqCKdGvZqZVSxuASANDTk/trRZYCyNEefTxaUBZGNyCXId6QjySQ77g== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1793618420; b=vBpp3A30o7sEtnVxzkAHabdNFpF1c/GRnVkSwOcQlu3wPbjWFZexXoKtrmDxxK6g3b0t+2 fxI37vhm6eABy7PQaopHPAUtmDvJB2olLGI0l1Qradj/qbE2jkokhuONZaOPYflIcpr4rO pLcDvTfforcIgHiqwTeRSNRt4v4Z/fSJOWHfl86Y+F9Cpf1dHiAAXln8rPH1x4iltehcqz ieFO4nL5gcYrNcWW6ERXWUEN1dQYDkyWbRRyvxm0xwUcAnPMj83QAf8pSpKuIkprsFCieI yj/shdxDqDrYSKrMj7ptAR5COPsU7se5MK+S5tACo9I3rpgVl7XArq3JdloWnQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1793618420; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=8295ViNZuvG9s0rFtfbQnAjgNup40CVbL0DtAfJRs8s=; b=kllVU0KRFVKMgvQ/cR/NTphwPe9gMY05EvlFH6i+8S1+YksupZ1HcV4Pur2cg1Y+DxLJ1L pf89MIslzHq3FIkWwqoLHGnDNHYiFgGtM4y6L5eYrlZYblkF1NzvHvP01WEh/EBfLwn5Oh 9zo3zpfCdVR4OLU1Z2R5lsBNG/uJZ3scq3cv37fZ2suMmAGd3bU4YyNub4LI1VplC3ZEe8 u6dqiCyaQxen/3lm2C1i8wHkwi7PSPk1pbFn3BdrHCEoWKRgKnKGh8utFV/XeYUh53hC6U SuzL4gBb/12AHphhgPTw0ALp2rAcwaP0MydpvwS6MzLv0c+veZTKUERmJnHkAw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4jJ8Pw4Z3tzkZl for ; Mon, 02 Nov 2026 11:20:20 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 1ec5d by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 02 Nov 2026 11:20:15 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Krzysztof Galazka Subject: git: 7868958f5c79 - main - ix(4): Support Total Port Shutdown on E610 List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: Commit messages for all branches of the src repository List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kgalazka X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 7868958f5c79eb986d067e02ca8239aa7491dfac Auto-Submitted: auto-generated Date: Mon, 02 Nov 2026 11:20:15 +0000 Message-Id: <6ae871ef.1ec5d.4507e67d@gitrepo.freebsd.org> The branch main has been updated by kgalazka: URL: https://cgit.FreeBSD.org/src/commit/?id=7868958f5c79eb986d067e02ca8239aa7491dfac commit 7868958f5c79eb986d067e02ca8239aa7491dfac Author: Krzysztof Galazka AuthorDate: 2026-11-02 11:17:08 +0000 Commit: Krzysztof Galazka CommitDate: 2026-11-02 11:18:31 +0000 ix(4): Support Total Port Shutdown on E610 Firmware controls the physical link state on E610 adapters, similarly to X700 and E800 adapters. As a result, running "ifconfig down" does not disable the physical link unless Total Port Shutdown is enabled. Read the Link Default Override TLV from NVM to detect when Total Port Shutdown was enabled for given port in system setup. In that case, force the link down when the interface is stopped and restore it during link configuration. Leave link state management unchanged when the TLV is unavailable or the feature is not enabled. Co-authored-by: MiƂosz Linkiewicz Co-authored-by: Tomasz Lichwala Signed-off-by: Krzysztof Galazka Tested by: Mateusz Moga MFC after: 1 week Sponsored by: Intel Corporation Differential Revision: https://reviews.freebsd.org/D60643 --- sys/dev/ixgbe/if_ix.c | 83 ++++++++++++++++++++++++++++++++++++++++- sys/dev/ixgbe/ixgbe.h | 2 + sys/dev/ixgbe/ixgbe_e610.c | 79 +++++++++++++++++++++++++++++++++++++++ sys/dev/ixgbe/ixgbe_e610.h | 4 ++ sys/dev/ixgbe/ixgbe_type_e610.h | 17 +++++++++ 5 files changed, 184 insertions(+), 1 deletion(-) diff --git a/sys/dev/ixgbe/if_ix.c b/sys/dev/ixgbe/if_ix.c index 74ccfb7f629f..bbce4012ca53 100644 --- a/sys/dev/ixgbe/if_ix.c +++ b/sys/dev/ixgbe/if_ix.c @@ -307,6 +307,9 @@ static u32 ixgbe_handle_fw_event(void *); static int ixgbe_enable_lse(struct ixgbe_softc *sc); static int ixgbe_disable_lse(struct ixgbe_softc *sc); +static void ixgbe_cache_ldo_policy(struct ixgbe_softc *sc); +static void ixgbe_apply_ldo_link_state(struct ixgbe_softc *sc, bool link_up); + /************************************************************************ * FreeBSD Device Interface Entry Points ************************************************************************/ @@ -361,6 +364,62 @@ ixgbe_device_iov_init(device_t dev, uint16_t num_vfs, } #endif +/************************************************************************ + * ixgbe_cache_ldo_policy + ************************************************************************/ +static void +ixgbe_cache_ldo_policy(struct ixgbe_softc *sc) +{ + struct ixgbe_link_default_override_tlv ldo = {0}; + struct ixgbe_hw *hw = &sc->hw; + s32 error; + + sc->ldo_valid = false; + sc->ldo_port_disabled = false; + + error = ixgbe_get_link_default_override(hw, &ldo); + if (error) { + device_printf(sc->dev, + "Failed to read E610 Link Default Override TLV, error: %d\n", + error); + return; + } + + sc->ldo_valid = true; + sc->ldo_port_disabled = + !!(ldo.link_options & IXGBE_LINK_OVERRIDE_PORT_DIS); +} /* ixgbe_cache_ldo_policy */ + +/************************************************************************ + * ixgbe_apply_ldo_link_state + ************************************************************************/ +static void +ixgbe_apply_ldo_link_state(struct ixgbe_softc *sc, bool link_up) +{ + struct ixgbe_hw *hw = &sc->hw; + s32 error; + + if (!sc->ldo_valid || !sc->ldo_port_disabled) + return; + + error = ixgbe_force_link_state(hw, link_up); + if (!error) + return; + + if (!link_up && error == IXGBE_ERR_ACI_ERROR && + hw->aci.last_status == IXGBE_ACI_RC_EMODE) { + device_printf(sc->dev, + "Firmware vetoed link shutdown, " + "last ACI status: %d\n", hw->aci.last_status); + return; + } + + device_printf(sc->dev, + "Failed to force link %s, error: %d, " + "last aci status: %d\n", link_up ? "up" : "down", error, + hw->aci.last_status); +} /* ixgbe_apply_ldo_link_state */ + static device_method_t ixgbe_if_methods[] = { DEVMETHOD(ifdi_attach_pre, ixgbe_if_attach_pre), DEVMETHOD(ifdi_attach_post, ixgbe_if_attach_post), @@ -1175,6 +1234,7 @@ ixgbe_if_attach_pre(if_ctx_t ctx) hw->phy.smart_speed = ixgbe_smart_speed; ixgbe_init_device_features(sc); + ixgbe_cache_ldo_policy(sc); /* Verify adapter fan is still functional (if applicable) */ if (sc->feat_en & IXGBE_FEATURE_FAN_FAIL) { @@ -2061,9 +2121,14 @@ ixgbe_config_link(if_ctx_t ctx) "error: %d", err); } - if (hw->mac.ops.setup_link) + if (hw->mac.ops.setup_link) { err = hw->mac.ops.setup_link(hw, autoneg, sc->link_up); + if (err) + return; + } + + ixgbe_apply_ldo_link_state(sc, true); } } /* ixgbe_config_link */ @@ -3730,6 +3795,20 @@ ixgbe_add_debug_sysctls(struct ixgbe_softc *sc) if (sc->feat_en & IXGBE_FEATURE_FW_LOGGING) ixgbe_add_fw_logging_tunables(sc, sc->debug_sysctls); + + if (sc->hw.mac.type == ixgbe_mac_E610) { + struct sysctl_oid_list *debug_list; + debug_list = SYSCTL_CHILDREN(sc->debug_sysctls); + + SYSCTL_ADD_BOOL(ctx, debug_list, OID_AUTO, "ldo_valid", + CTLFLAG_RD, &sc->ldo_valid, 0, + "E610 Link Default Override policy valid"); + + SYSCTL_ADD_BOOL(ctx, debug_list, OID_AUTO, + "ldo_port_disabled", CTLFLAG_RD, &sc->ldo_port_disabled, + 0, "E610 Link Default Override PORT_DIS set"); + } + } /* ixgbe_add_debug_sysctls */ /************************************************************************ @@ -5120,6 +5199,8 @@ ixgbe_if_stop(if_ctx_t ctx) iflib_link_state_change(ctx, LINK_STATE_DOWN, 0); sc->link_active = false; } + ixgbe_if_update_admin_status(ctx); + ixgbe_apply_ldo_link_state(sc, false); /* reprogram the RAR[0] in case user changed it. */ ixgbe_set_rar(&sc->hw, 0, sc->hw.mac.addr, 0, IXGBE_RAH_AV); diff --git a/sys/dev/ixgbe/ixgbe.h b/sys/dev/ixgbe/ixgbe.h index 28d9adeeb7a5..41beaeaec7d7 100644 --- a/sys/dev/ixgbe/ixgbe.h +++ b/sys/dev/ixgbe/ixgbe.h @@ -443,6 +443,8 @@ struct ixgbe_softc { int advertise; /* link speeds */ int enable_aim; /* adaptive interrupt moderation */ bool link_active; + bool ldo_valid; + bool ldo_port_disabled; u16 num_segs; u32 link_speed; bool link_up; diff --git a/sys/dev/ixgbe/ixgbe_e610.c b/sys/dev/ixgbe/ixgbe_e610.c index 058c79928cd3..507dc7d16920 100644 --- a/sys/dev/ixgbe/ixgbe_e610.c +++ b/sys/dev/ixgbe/ixgbe_e610.c @@ -1643,6 +1643,38 @@ s32 ixgbe_aci_get_link_info(struct ixgbe_hw *hw, bool ena_lse, return IXGBE_SUCCESS; } +/** + * ixgbe_force_link_state - force phy link to get up/down + * @hw: pointer to hardware structure + * @link_up: if true: force link up, if false: force link down + * + * Send 0x0601 with the IXGBE_ACI_PHY_ENA_LINK bit set/cleared. + * + * Return: the exit code of the operation. + */ +s32 ixgbe_force_link_state(struct ixgbe_hw *hw, bool link_up) +{ + struct ixgbe_aci_cmd_set_phy_cfg_data pcfg = {0}; + struct ixgbe_aci_cmd_get_phy_caps_data pcaps; + s32 err; + + err = ixgbe_aci_get_phy_caps(hw, false, IXGBE_ACI_REPORT_ACTIVE_CFG, + &pcaps); + if (err) { + return err; + } + + ixgbe_copy_phy_caps_to_cfg(&pcaps, &pcfg); + + if (link_up) + pcfg.caps |= IXGBE_ACI_PHY_ENA_LINK; + else + pcfg.caps &= ~IXGBE_ACI_PHY_ENA_LINK; + pcfg.caps |= IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT; + + return ixgbe_aci_set_phy_cfg(hw, &pcfg); +} + /** * ixgbe_aci_set_event_mask - set event mask * @hw: pointer to the HW struct @@ -5973,6 +6005,53 @@ static s32 ixgbe_get_pfa_module_tlv(struct ixgbe_hw *hw, u16 *module_tlv, return IXGBE_ERR_DOES_NOT_EXIST; } +/** + * ixgbe_get_link_default_override - Get link default override from NVM + * @hw: pointer to hardware structure + * @ldo: pointer to link default override struct to populate + * + * Read the Link Default Override TLV (0x134) from the NVM PFA and return + * the full per-port override configuration. The caller must consume only + * IXGBE_LINK_OVERRIDE_PORT_DIS from link_options for force-link policy. + * All port data is read in a single bulk NVM access. + * + * Return: the exit code of the operation. + */ +s32 ixgbe_get_link_default_override(struct ixgbe_hw *hw, + struct ixgbe_link_default_override_tlv *ldo) +{ + u16 min_tlv_len; + u16 tlv, tlv_len, tlv_start; + s32 status; + + DEBUGFUNC("ixgbe_get_link_default_override"); + + if (!ldo) + return IXGBE_ERR_PARAM; + + status = ixgbe_get_pfa_module_tlv(hw, &tlv, &tlv_len, + E610_SR_LINK_DEFAULT_OVERRIDE_PTR); + if (status) + return status; + + /* tlv_len covers value words only, don't add header offset. */ + min_tlv_len = (hw->bus.func + 1) * E610_SR_PFA_LINK_OVERRIDE_WORDS; + if (tlv_len < min_tlv_len) + return IXGBE_ERR_INVAL_SIZE; + + tlv_start = tlv + E610_SR_PFA_LINK_OVERRIDE_OFFSET + + hw->bus.func * E610_SR_PFA_LINK_OVERRIDE_WORDS; + + /* Read all port-specific words in a single NVM access */ + status = ixgbe_read_ee_aci_buffer_E610(hw, tlv_start, + E610_SR_PFA_LINK_OVERRIDE_WORDS, + (u16 *)ldo); + if (status) + return status; + + return IXGBE_SUCCESS; +} + /** * ixgbe_read_pba_string_E610 - Reads part number string from NVM * @hw: pointer to hardware structure diff --git a/sys/dev/ixgbe/ixgbe_e610.h b/sys/dev/ixgbe/ixgbe_e610.h index 7af5506d85e8..a9e496098e52 100644 --- a/sys/dev/ixgbe/ixgbe_e610.h +++ b/sys/dev/ixgbe/ixgbe_e610.h @@ -75,6 +75,7 @@ s32 ixgbe_update_link_info(struct ixgbe_hw *hw); s32 ixgbe_get_link_status(struct ixgbe_hw *hw, bool *link_up); s32 ixgbe_aci_get_link_info(struct ixgbe_hw *hw, bool ena_lse, struct ixgbe_link_status *link); +s32 ixgbe_force_link_state(struct ixgbe_hw *hw, bool link_up); s32 ixgbe_aci_set_event_mask(struct ixgbe_hw *hw, u8 port_num, u16 mask); s32 ixgbe_configure_lse(struct ixgbe_hw *hw, bool activate, u16 mask); @@ -232,6 +233,9 @@ s32 ixgbe_write_ee_aci_buffer_E610(struct ixgbe_hw *hw, u16 offset, s32 ixgbe_calc_eeprom_checksum_E610(struct ixgbe_hw *hw); s32 ixgbe_update_eeprom_checksum_E610(struct ixgbe_hw *hw); s32 ixgbe_validate_eeprom_checksum_E610(struct ixgbe_hw *hw, u16 *checksum_val); +/* Reads LDO TLV 0x134; callers consume only IXGBE_LINK_OVERRIDE_PORT_DIS. */ +s32 ixgbe_get_link_default_override(struct ixgbe_hw *hw, + struct ixgbe_link_default_override_tlv *ldo); s32 ixgbe_read_pba_string_E610(struct ixgbe_hw *hw, u8 *pba_num, u32 pba_num_size); #endif /* _IXGBE_E610_H_ */ diff --git a/sys/dev/ixgbe/ixgbe_type_e610.h b/sys/dev/ixgbe/ixgbe_type_e610.h index da46e503f660..005fec423a20 100644 --- a/sys/dev/ixgbe/ixgbe_type_e610.h +++ b/sys/dev/ixgbe/ixgbe_type_e610.h @@ -140,6 +140,23 @@ #define E610_SR_NVM_CTRL_WORD 0x00 #define E610_SR_PBA_BLOCK_PTR 0x16 +/* Link Default Override TLV in PFA */ +#define E610_SR_LINK_DEFAULT_OVERRIDE_PTR 0x134 +#define E610_SR_PFA_LINK_OVERRIDE_WORDS 10 +#define E610_SR_PFA_LINK_OVERRIDE_PHY_WORDS 8 +#define E610_SR_PFA_LINK_OVERRIDE_OFFSET 2 + +/* Link Options bits */ +#define IXGBE_LINK_OVERRIDE_PORT_DIS BIT(2) + +#pragma pack(1) +struct ixgbe_link_default_override_tlv { + u16 link_options; /* Port Options 0: only PORT_DIS is consumed */ + u16 phy_options; /* Port Options 1 */ + u16 phy_types[E610_SR_PFA_LINK_OVERRIDE_PHY_WORDS]; /* words 2-9 */ +}; +#pragma pack() + /* The Orom version topology */ #define IXGBE_OROM_VER_PATCH_SHIFT 0 #define IXGBE_OROM_VER_PATCH_MASK (0xff << IXGBE_OROM_VER_PATCH_SHIFT)