Netdev List
 help / color / mirror / Atom feed
* [iwl-next] ixgbe: implement Total Port Shutdown for E610
@ 2026-08-10  7:56 Tomasz Lichwala
  0 siblings, 0 replies; only message in thread
From: Tomasz Lichwala @ 2026-08-10  7:56 UTC (permalink / raw)
  To: intel-wired-lan; +Cc: netdev, Tomasz Lichwala

Implement Total Port Shutdown (TPS) for E610. When TPS is provisioned
in the NVM (by the platform firmware), the port's PHY is powered down
whenever the interface is administratively down.

When the PORT_DIS bit is set in the Link Default Override TLV in
the NVM PFA area, enable Total Port Shutdown (TPS). This forces the
link-down-on-close private flag and prevents the user from changing
it via ethtool, ensuring the PHY is powered down when the interface
is brought down as provisioned in the NVM.

The Link Default Override TLV (0x134) is read from the NVM PFA during
driver init. Each port has its own 10-word configuration block within
the TLV. If the PORT_DIS bit is set in the port's link_options field,
the driver sets both TOTAL_PORT_SHUTDOWN_ENA and LINK_DOWN_ON_CLOSE
flags.

Signed-off-by: Tomasz Lichwala <tomasz.lichwala@linux.intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe.h      |  1 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 38 +++++++++++++++++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h |  2 +
 .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c  | 13 +++++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 14 ++++++-
 .../ethernet/intel/ixgbe/ixgbe_type_e610.h    | 13 +++++++
 6 files changed, 80 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 02e7d6f0d852..41f43294465b 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -684,6 +684,7 @@ struct ixgbe_adapter {
 #define IXGBE_FLAG2_API_MISMATCH		BIT(23)
 #define IXGBE_FLAG2_FW_ROLLBACK			BIT(24)
 #define IXGBE_FLAG2_LINK_DOWN_ON_CLOSE		BIT(25)
+#define IXGBE_FLAG2_TOTAL_PORT_SHUTDOWN_ENA	BIT(26)
 
 	/* Tx fast path data */
 	int num_tx_queues;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
index c92a586ee9b6..46a7c3ef7396 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
@@ -4051,6 +4051,44 @@ static int ixgbe_get_pfa_module_tlv(struct ixgbe_hw *hw, u16 *module_tlv,
 	return -ENODATA;
 }
 
+/**
+ * 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 from the NVM PFA and return
+ * the per-port override configuration.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int ixgbe_get_link_default_override(struct ixgbe_hw *hw,
+				    struct ixgbe_link_default_override_tlv *ldo)
+{
+	struct ixgbe_adapter *adapter = hw->back;
+	u16 tlv, tlv_len;
+	u32 tlv_start;
+	u8 pf_func;
+	int err;
+
+	err = ixgbe_get_pfa_module_tlv(hw, &tlv, &tlv_len,
+				       IXGBE_E610_SR_LINK_DEFAULT_OVERRIDE_PTR);
+	if (err)
+		return err;
+
+	pf_func = PCI_FUNC(adapter->pdev->devfn);
+
+	tlv_start = tlv + IXGBE_E610_SR_PFA_TLV_HDR_SIZE +
+		    pf_func * IXGBE_E610_SR_PFA_LINK_OVERRIDE_WORDS;
+
+	if (tlv_start + IXGBE_E610_SR_PFA_LINK_OVERRIDE_WORDS >
+	    tlv + IXGBE_E610_SR_PFA_TLV_HDR_SIZE + tlv_len)
+		return -ERANGE;
+
+	return ixgbe_read_ee_aci_buffer_e610(hw, tlv_start,
+					     IXGBE_E610_SR_PFA_LINK_OVERRIDE_WORDS,
+					     (u16 *)ldo);
+}
+
 /**
  * ixgbe_read_pba_string_e610 - Read PBA string from NVM
  * @hw: pointer to hardware structure
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
index 1f4c8b022698..fc96d67e018e 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
@@ -82,6 +82,8 @@ int ixgbe_read_ee_aci_e610(struct ixgbe_hw *hw, u16 offset, u16 *data);
 int ixgbe_read_ee_aci_buffer_e610(struct ixgbe_hw *hw, u16 offset,
 				  u16 words, u16 *data);
 int ixgbe_validate_eeprom_checksum_e610(struct ixgbe_hw *hw, u16 *checksum_val);
+int ixgbe_get_link_default_override(struct ixgbe_hw *hw,
+				    struct ixgbe_link_default_override_tlv *ldo);
 int ixgbe_reset_hw_e610(struct ixgbe_hw *hw);
 int ixgbe_get_flash_data(struct ixgbe_hw *hw);
 int ixgbe_aci_nvm_update_empr(struct ixgbe_hw *hw);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index 6a35630f8421..1e1db8435506 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -3852,6 +3852,19 @@ static int ixgbe_set_priv_flags(struct net_device *netdev, u32 priv_flags)
 		}
 	}
 
+	/* Do not allow any change to link-down-on-close when Total Port
+	 * Shutdown is enabled - the flag is managed by TPS exclusively.
+	 */
+	if (adapter->flags2 & IXGBE_FLAG2_TOTAL_PORT_SHUTDOWN_ENA) {
+		bool cur = !!(adapter->flags2 & IXGBE_FLAG2_LINK_DOWN_ON_CLOSE);
+		bool req = !!(priv_flags & IXGBE_PRIV_LINK_DOWN_ON_CLOSE);
+
+		if (req != cur) {
+			e_warn(probe, "Setting link-down-on-close not supported on this port\n");
+			return -EOPNOTSUPP;
+		}
+	}
+
 	flags2 &= ~IXGBE_FLAG2_LINK_DOWN_ON_CLOSE;
 	if (priv_flags & IXGBE_PRIV_LINK_DOWN_ON_CLOSE) {
 		if (adapter->hw.mac.type == ixgbe_mac_e610) {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 79d5d652d3cf..5f8f9884cbea 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -7001,9 +7001,21 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter,
 	if (hw->mac.ops.init_swfw_sync)
 		hw->mac.ops.init_swfw_sync(hw);
 
-	if (hw->mac.type == ixgbe_mac_e610)
+	if (hw->mac.type == ixgbe_mac_e610) {
+		struct ixgbe_link_default_override_tlv ldo = {};
+		int err;
+
 		mutex_init(&hw->aci.lock);
 
+		err = ixgbe_get_link_default_override(hw, &ldo);
+		if (!err && (ldo.link_options & IXGBE_LINK_OVERRIDE_PORT_DIS)) {
+			adapter->flags2 |=
+				IXGBE_FLAG2_TOTAL_PORT_SHUTDOWN_ENA |
+				IXGBE_FLAG2_LINK_DOWN_ON_CLOSE;
+			e_dev_info("Total Port Shutdown enabled\n");
+		}
+	}
+
 #ifdef IXGBE_FCOE
 	/* FCoE support exists, always init the FCoE lock */
 	spin_lock_init(&adapter->fcoe.lock);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
index 959cacecae49..43e2d3e1cd59 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
@@ -29,6 +29,19 @@
 #define IXGBE_E610_SR_NETLIST_BANK_PTR		0x46
 #define IXGBE_E610_SR_NETLIST_BANK_SIZE		0x47
 
+/* Link Default Override TLV in PFA */
+#define IXGBE_E610_SR_LINK_DEFAULT_OVERRIDE_PTR	0x134
+#define IXGBE_E610_SR_PFA_LINK_OVERRIDE_WORDS	10
+#define IXGBE_E610_SR_PFA_TLV_HDR_SIZE		2
+
+#define IXGBE_LINK_OVERRIDE_PORT_DIS		BIT(2)
+
+struct ixgbe_link_default_override_tlv {
+	u16 link_options;
+	u16 phy_options;
+	u16 phy_types[8];
+};
+
 /* The OROM version topology */
 #define IXGBE_OROM_VER_PATCH_MASK		GENMASK_ULL(7, 0)
 #define IXGBE_OROM_VER_BUILD_MASK		GENMASK_ULL(23, 8)
-- 
2.54.0


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-08-10  7:57 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-10  7:56 [iwl-next] ixgbe: implement Total Port Shutdown for E610 Tomasz Lichwala

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox