* [PATCH v4 net-next 7/8] ice: add Tx reference clock index handling to AN restart command
From: Grzegorz Nitka @ 2026-03-26 16:28 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, intel-wired-lan, poros, richardcochran,
andrew+netdev, przemyslaw.kitszel, anthony.l.nguyen,
Prathosh.Satish, ivecera, jiri, arkadiusz.kubalewski,
vadim.fedorenko, donald.hunter, horms, pabeni, kuba, davem,
edumazet, Grzegorz Nitka
In-Reply-To: <20260326162832.3135857-1-grzegorz.nitka@intel.com>
Extend the Restart Auto-Negotiation (AN) AdminQ command with a new
parameter allowing software to specify the Tx reference clock index to
be used during link restart.
This patch:
- adds REFCLK field definitions to ice_aqc_restart_an
- updates ice_aq_set_link_restart_an() to take a new refclk parameter
and properly encode it into the command
- keeps legacy behavior by passing REFCLK_NOCHANGE where appropriate
This prepares the driver for configurations requiring dynamic selection
of the Tx reference clock as part of the AN flow.
Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Signed-off-by: Grzegorz Nitka <grzegorz.nitka@intel.com>
---
drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 2 ++
drivers/net/ethernet/intel/ice/ice_common.c | 5 ++++-
drivers/net/ethernet/intel/ice/ice_common.h | 2 +-
drivers/net/ethernet/intel/ice/ice_lib.c | 3 ++-
4 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
index 859e9c66f3e7..a24a0613d887 100644
--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
@@ -1169,6 +1169,8 @@ struct ice_aqc_restart_an {
u8 cmd_flags;
#define ICE_AQC_RESTART_AN_LINK_RESTART BIT(1)
#define ICE_AQC_RESTART_AN_LINK_ENABLE BIT(2)
+#define ICE_AQC_RESTART_AN_REFCLK_M GENMASK(4, 3)
+#define ICE_AQC_RESTART_AN_REFCLK_NOCHANGE 0
u8 reserved2[13];
};
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index ce11fea122d0..de88aec9137c 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -4126,12 +4126,13 @@ int ice_get_link_status(struct ice_port_info *pi, bool *link_up)
* @pi: pointer to the port information structure
* @ena_link: if true: enable link, if false: disable link
* @cd: pointer to command details structure or NULL
+ * @refclk: the new TX reference clock, 0 if no change
*
* Sets up the link and restarts the Auto-Negotiation over the link.
*/
int
ice_aq_set_link_restart_an(struct ice_port_info *pi, bool ena_link,
- struct ice_sq_cd *cd)
+ struct ice_sq_cd *cd, u8 refclk)
{
struct ice_aqc_restart_an *cmd;
struct libie_aq_desc desc;
@@ -4147,6 +4148,8 @@ ice_aq_set_link_restart_an(struct ice_port_info *pi, bool ena_link,
else
cmd->cmd_flags &= ~ICE_AQC_RESTART_AN_LINK_ENABLE;
+ cmd->cmd_flags |= FIELD_PREP(ICE_AQC_RESTART_AN_REFCLK_M, refclk);
+
return ice_aq_send_cmd(pi->hw, &desc, NULL, 0, cd);
}
diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h
index e700ac0dc347..9f5344212195 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.h
+++ b/drivers/net/ethernet/intel/ice/ice_common.h
@@ -215,7 +215,7 @@ ice_cfg_phy_fec(struct ice_port_info *pi, struct ice_aqc_set_phy_cfg_data *cfg,
enum ice_fec_mode fec);
int
ice_aq_set_link_restart_an(struct ice_port_info *pi, bool ena_link,
- struct ice_sq_cd *cd);
+ struct ice_sq_cd *cd, u8 refclk);
int
ice_aq_set_mac_cfg(struct ice_hw *hw, u16 max_frame_size, struct ice_sq_cd *cd);
int
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 689c6025ea82..c2c7f186bcc7 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -3769,7 +3769,8 @@ int ice_set_link(struct ice_vsi *vsi, bool ena)
if (vsi->type != ICE_VSI_PF)
return -EINVAL;
- status = ice_aq_set_link_restart_an(pi, ena, NULL);
+ status = ice_aq_set_link_restart_an(pi, ena, NULL,
+ ICE_AQC_RESTART_AN_REFCLK_NOCHANGE);
/* if link is owned by manageability, FW will return LIBIE_AQ_RC_EMODE.
* this is not a fatal error, so print a warning message and return
--
2.39.3
^ permalink raw reply related
* [PATCH v4 net-next 6/8] ice: implement CPI support for E825C
From: Grzegorz Nitka @ 2026-03-26 16:28 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, intel-wired-lan, poros, richardcochran,
andrew+netdev, przemyslaw.kitszel, anthony.l.nguyen,
Prathosh.Satish, ivecera, jiri, arkadiusz.kubalewski,
vadim.fedorenko, donald.hunter, horms, pabeni, kuba, davem,
edumazet, Grzegorz Nitka
In-Reply-To: <20260326162832.3135857-1-grzegorz.nitka@intel.com>
Add full CPI (Converged PHY Interface) command handling required for
E825C devices. The CPI interface allows the driver to interact with
PHY-side control logic through the LM/PHY command registers, including
enabling/disabling/selection of PHY reference clock.
This patch introduces:
- a new CPI subsystem (ice_cpi.c / ice_cpi.h) implementing the CPI
request/acknowledge state machine, including REQ/ACK protocol,
command execution, and response handling
- helper functions for reading/writing PHY registers over Sideband
Queue
- CPI command execution API (ice_cpi_exec) and a helper for enabling or
disabling Tx reference clocks (CPI 0xF1 opcode 'Config PHY clocking')
- addition of the non-posted write opcode (wr_np) to SBQ
- Makefile integration to build CPI support together with the PTP stack
This provides the infrastructure necessary to support PHY-side
configuration flows on E825C and is required for advanced link control
and Tx reference clock management.
Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Signed-off-by: Grzegorz Nitka <grzegorz.nitka@intel.com>
---
drivers/net/ethernet/intel/ice/Makefile | 2 +-
drivers/net/ethernet/intel/ice/ice_cpi.c | 347 +++++++++++++++++++
drivers/net/ethernet/intel/ice/ice_cpi.h | 69 ++++
drivers/net/ethernet/intel/ice/ice_sbq_cmd.h | 5 +-
4 files changed, 420 insertions(+), 3 deletions(-)
create mode 100644 drivers/net/ethernet/intel/ice/ice_cpi.c
create mode 100644 drivers/net/ethernet/intel/ice/ice_cpi.h
diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile
index 5b2c666496e7..38db476ab2ec 100644
--- a/drivers/net/ethernet/intel/ice/Makefile
+++ b/drivers/net/ethernet/intel/ice/Makefile
@@ -54,7 +54,7 @@ ice-$(CONFIG_PCI_IOV) += \
ice_vf_mbx.o \
ice_vf_vsi_vlan_ops.o \
ice_vf_lib.o
-ice-$(CONFIG_PTP_1588_CLOCK) += ice_ptp.o ice_ptp_hw.o ice_dpll.o ice_tspll.o
+ice-$(CONFIG_PTP_1588_CLOCK) += ice_ptp.o ice_ptp_hw.o ice_dpll.o ice_tspll.o ice_cpi.o
ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
diff --git a/drivers/net/ethernet/intel/ice/ice_cpi.c b/drivers/net/ethernet/intel/ice/ice_cpi.c
new file mode 100644
index 000000000000..97fe2ebb99f3
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_cpi.c
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2018-2026 Intel Corporation */
+
+#include "ice_type.h"
+#include "ice_common.h"
+#include "ice_ptp_hw.h"
+#include "ice_cpi.h"
+
+/**
+ * ice_cpi_get_dest_dev - get destination PHY for given phy index
+ * @hw: pointer to the HW struct
+ * @phy: phy index of port the CPI action is taken on
+ *
+ * Return: sideband queue destination PHY device.
+ */
+static enum ice_sbq_dev_id ice_cpi_get_dest_dev(struct ice_hw *hw, u8 phy)
+{
+ u8 curr_phy = hw->lane_num / hw->ptp.ports_per_phy;
+
+ /* In the driver, lanes 4..7 are in fact 0..3 on a second PHY.
+ * On a single complex E825C, PHY 0 is always destination device phy_0
+ * and PHY 1 is phy_0_peer.
+ * On dual complex E825C, device phy_0 points to PHY on a current
+ * complex and phy_0_peer to PHY on a different complex.
+ */
+ if ((!ice_is_dual(hw) && phy) ||
+ (ice_is_dual(hw) && phy != curr_phy))
+ return ice_sbq_dev_phy_0_peer;
+ else
+ return ice_sbq_dev_phy_0;
+}
+
+/**
+ * ice_cpi_write_phy - Write a CPI port register
+ * @hw: pointer to the HW struct
+ * @phy: phy index of port the CPI action is taken on
+ * @addr: PHY register address
+ * @val: Value to write
+ *
+ * Return:
+ * * 0 on success
+ * * other error codes when failed to write to PHY
+ */
+static int ice_cpi_write_phy(struct ice_hw *hw, u8 phy, u32 addr, u32 val)
+{
+ struct ice_sbq_msg_input msg = {
+ .dest_dev = ice_cpi_get_dest_dev(hw, phy),
+ .opcode = ice_sbq_msg_wr_np,
+ .msg_addr_low = lower_16_bits(addr),
+ .msg_addr_high = upper_16_bits(addr),
+ .data = val
+ };
+ int err;
+
+ err = ice_sbq_rw_reg(hw, &msg, LIBIE_AQ_FLAG_RD);
+ if (err)
+ ice_debug(hw, ICE_DBG_PTP,
+ "Failed to write CPI msg to phy %d, err: %d\n",
+ phy, err);
+
+ return err;
+}
+
+/**
+ * ice_cpi_read_phy - Read a CPI port register
+ * @hw: pointer to the HW struct
+ * @phy: phy index of port the CPI action is taken on
+ * @addr: PHY register address
+ * @val: storage for register value
+ *
+ * Return:
+ * * 0 on success
+ * * other error codes when failed to read from PHY
+ */
+static int ice_cpi_read_phy(struct ice_hw *hw, u8 phy, u32 addr, u32 *val)
+{
+ struct ice_sbq_msg_input msg = {
+ .dest_dev = ice_cpi_get_dest_dev(hw, phy),
+ .opcode = ice_sbq_msg_rd,
+ .msg_addr_low = lower_16_bits(addr),
+ .msg_addr_high = upper_16_bits(addr)
+ };
+ int err;
+
+ err = ice_sbq_rw_reg(hw, &msg, LIBIE_AQ_FLAG_RD);
+ if (err) {
+ ice_debug(hw, ICE_DBG_PTP,
+ "Failed to read CPI msg from phy %d, err: %d\n",
+ phy, err);
+ return err;
+ }
+
+ *val = msg.data;
+
+ return 0;
+}
+
+/**
+ * ice_cpi_wait_req0_ack0 - waits for CPI interface to be available
+ * @hw: pointer to the HW struct
+ * @phy: phy index of port the CPI action is taken on
+ *
+ * This function checks if CPI interface is ready to use by CPI client.
+ * It's done by assuring LM.CMD.REQ and PHY.CMD.ACK bit in CPI
+ * interface registers to be 0.
+ *
+ * Return: 0 on success, negative on error
+ */
+static int ice_cpi_wait_req0_ack0(struct ice_hw *hw, int phy)
+{
+ union cpi_reg_phy_cmd_data phy_regs;
+ union cpi_reg_lm_cmd_data lm_regs;
+
+ for (int i = 0; i < CPI_RETRIES_COUNT; i++) {
+ int err;
+
+ /* check if another CPI Client is also accessing CPI */
+ err = ice_cpi_read_phy(hw, phy, CPI0_LM1_CMD_DATA,
+ &lm_regs.val);
+ if (err)
+ return err;
+ if (lm_regs.field.cpi_req)
+ return -EBUSY;
+
+ /* check if PHY.ACK is deasserted */
+ err = ice_cpi_read_phy(hw, phy, CPI0_PHY1_CMD_DATA,
+ &phy_regs.val);
+ if (err)
+ return err;
+ if (phy_regs.field.error)
+ return -EFAULT;
+ if (!phy_regs.field.ack)
+ /* req0 and ack0 at this point - ready to go */
+ return 0;
+
+ msleep(CPI_RETRIES_CADENCE_MS);
+ }
+
+ return -ETIMEDOUT;
+}
+
+/**
+ * ice_cpi_wait_ack - Waits for the PHY.ACK bit to be asserted/deasserted
+ * @hw: pointer to the HW struct
+ * @phy: phy index of port the CPI action is taken on
+ * @asserted: desired state of PHY.ACK bit
+ * @data: pointer to the user data where PHY.data is stored
+ *
+ * This function checks if PHY.ACK bit is asserted or deasserted, depending
+ * on the phase of CPI handshake. If 'asserted' state is required, PHY command
+ * data is stored in the 'data' storage.
+ *
+ * Return: 0 on success, negative on error
+ */
+static int ice_cpi_wait_ack(struct ice_hw *hw, u8 phy, bool asserted,
+ u32 *data)
+{
+ union cpi_reg_phy_cmd_data phy_regs;
+
+ for (int i = 0; i < CPI_RETRIES_COUNT; i++) {
+ int err;
+
+ err = ice_cpi_read_phy(hw, phy, CPI0_PHY1_CMD_DATA,
+ &phy_regs.val);
+ if (err)
+ return err;
+ if (phy_regs.field.error)
+ return -EFAULT;
+ if (asserted && phy_regs.field.ack) {
+ if (data)
+ *data = phy_regs.val;
+ return 0;
+ }
+ if (!asserted && !phy_regs.field.ack)
+ return 0;
+
+ msleep(CPI_RETRIES_CADENCE_MS);
+ }
+
+ return -ETIMEDOUT;
+}
+
+#define ice_cpi_wait_ack0(hw, port) \
+ ice_cpi_wait_ack(hw, port, false, NULL)
+
+#define ice_cpi_wait_ack1(hw, port, data) \
+ ice_cpi_wait_ack(hw, port, true, data)
+
+/**
+ * ice_cpi_req0 - deasserts LM.REQ bit
+ * @hw: pointer to the HW struct
+ * @phy: phy index of port the CPI action is taken on
+ * @data: the command data
+ *
+ * Return: 0 on success, negative on CPI write error
+ */
+static int ice_cpi_req0(struct ice_hw *hw, u8 phy, u32 data)
+{
+ union cpi_reg_lm_cmd_data *lm_regs;
+ int err;
+
+ lm_regs = (union cpi_reg_lm_cmd_data *)&data;
+ lm_regs->field.cpi_req = 0;
+
+ err = ice_cpi_write_phy(hw, phy, CPI0_LM1_CMD_DATA, lm_regs->val);
+
+ return err;
+}
+
+/**
+ * ice_cpi_exec_cmd - writes command data to CPI interface
+ * @hw: pointer to the HW struct
+ * @phy: phy index of port the CPI action is taken on
+ * @data: the command data
+ *
+ * Return: 0 on success, otherwise negative on error
+ */
+static int ice_cpi_exec_cmd(struct ice_hw *hw, int phy, u32 data)
+{
+ return ice_cpi_write_phy(hw, phy, CPI0_LM1_CMD_DATA, data);
+}
+
+/**
+ * ice_cpi_exec - executes CPI command
+ * @hw: pointer to the HW struct
+ * @phy: phy index of port the CPI action is taken on
+ * @cmd: pointer to the command struct to execute
+ * @resp: pointer to user allocated CPI response struct
+ *
+ * This function executes CPI request with respect to CPI handshake
+ * mechanism.
+ *
+ * Return: 0 on success, otherwise negative on error
+ */
+int ice_cpi_exec(struct ice_hw *hw, u8 phy,
+ const struct ice_cpi_cmd *cmd,
+ struct ice_cpi_resp *resp)
+{
+ union cpi_reg_phy_cmd_data phy_cmd_data;
+ union cpi_reg_lm_cmd_data lm_cmd_data;
+ int err, err1 = 0;
+
+ if (!cmd || !resp)
+ return -EINVAL;
+
+ memset(&lm_cmd_data, 0, sizeof(lm_cmd_data));
+
+ lm_cmd_data.field.cpi_req = CPI_LM_CMD_REQ;
+ lm_cmd_data.field.get_set = cmd->set;
+ lm_cmd_data.field.opcode = cmd->opcode;
+ lm_cmd_data.field.portlane = cmd->port;
+ lm_cmd_data.field.data = cmd->data;
+
+ /* 1. Try to acquire the bus, PHY ACK should be low before we begin */
+ err = ice_cpi_wait_req0_ack0(hw, phy);
+ if (err)
+ goto cpi_exec_exit;
+
+ /* 2. We start the CPI request */
+ err = ice_cpi_exec_cmd(hw, phy, lm_cmd_data.val);
+ if (err)
+ goto cpi_exec_exit;
+
+ /*
+ * 3. Wait for CPI confirmation, PHY ACK should be asserted and opcode
+ * echoed in the response
+ */
+ err = ice_cpi_wait_ack1(hw, phy, &phy_cmd_data.val);
+ if (err)
+ goto cpi_deassert;
+
+ if (phy_cmd_data.field.ack &&
+ lm_cmd_data.field.opcode != phy_cmd_data.field.opcode) {
+ err = -EFAULT;
+ goto cpi_deassert;
+ }
+
+ resp->opcode = phy_cmd_data.field.opcode;
+ resp->data = phy_cmd_data.field.data;
+ resp->port = phy_cmd_data.field.portlane;
+
+cpi_deassert:
+ /* 4. We deassert REQ */
+ err1 = ice_cpi_req0(hw, phy, lm_cmd_data.val);
+ if (err1)
+ goto cpi_exec_exit;
+
+ /* 5. PHY ACK should be deasserted in response */
+ err1 = ice_cpi_wait_ack0(hw, phy);
+
+cpi_exec_exit:
+ if (!err)
+ err = err1;
+
+ return err;
+}
+
+/**
+ * ice_cpi_set_cmd - execute CPI SET command
+ * @hw: pointer to the HW struct
+ * @opcode: CPI command opcode
+ * @phy: phy index CPI command is applied for
+ * @port_lane: ephy index CPI command is applied for
+ * @data: CPI opcode context specific data
+ *
+ * Return: 0 on success.
+ */
+static int ice_cpi_set_cmd(struct ice_hw *hw, u16 opcode, u8 phy, u8 port_lane,
+ u16 data)
+{
+ struct ice_cpi_resp cpi_resp = {0};
+ struct ice_cpi_cmd cpi_cmd = {
+ .opcode = opcode,
+ .set = true,
+ .port = port_lane,
+ .data = data,
+ };
+
+ return ice_cpi_exec(hw, phy, &cpi_cmd, &cpi_resp);
+}
+
+/**
+ * ice_cpi_ena_dis_clk_ref - enables/disables Tx reference clock on port
+ * @hw: pointer to the HW struct
+ * @phy: phy index of port for which Tx reference clock is enabled/disabled
+ * @clk: Tx reference clock to enable or disable
+ * @enable: bool value to enable or disable Tx reference clock
+ *
+ * This function executes CPI request to enable or disable specific
+ * Tx reference clock on given PHY.
+ *
+ * Return: 0 on success.
+ */
+int ice_cpi_ena_dis_clk_ref(struct ice_hw *hw, u8 phy,
+ enum ice_e825c_ref_clk clk, bool enable)
+{
+ u16 val;
+
+ val = FIELD_PREP(CPI_OPCODE_PHY_CLK_PHY_SEL_M, phy) |
+ FIELD_PREP(CPI_OPCODE_PHY_CLK_REF_CTRL_M,
+ enable ? CPI_OPCODE_PHY_CLK_ENABLE :
+ CPI_OPCODE_PHY_CLK_DISABLE) |
+ FIELD_PREP(CPI_OPCODE_PHY_CLK_REF_SEL_M, clk);
+
+ return ice_cpi_set_cmd(hw, CPI_OPCODE_PHY_CLK, phy, 0, val);
+}
+
diff --git a/drivers/net/ethernet/intel/ice/ice_cpi.h b/drivers/net/ethernet/intel/ice/ice_cpi.h
new file mode 100644
index 000000000000..767107fc18e5
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_cpi.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2018-2025 Intel Corporation */
+
+#ifndef _ICE_CPI_H_
+#define _ICE_CPI_H_
+
+#define CPI0_PHY1_CMD_DATA 0x7FD028
+#define CPI0_LM1_CMD_DATA 0x7FD024
+#define CPI_RETRIES_COUNT 10
+#define CPI_RETRIES_CADENCE_MS 100
+
+#define CPI_OPCODE_PHY_CLK 0xF1
+#define CPI_OPCODE_PHY_CLK_PHY_SEL_M GENMASK(9, 6)
+#define CPI_OPCODE_PHY_CLK_REF_CTRL_M GENMASK(5, 4)
+#define CPI_OPCODE_PHY_CLK_PORT_SEL 0
+#define CPI_OPCODE_PHY_CLK_DISABLE 1
+#define CPI_OPCODE_PHY_CLK_ENABLE 2
+#define CPI_OPCODE_PHY_CLK_REF_SEL_M GENMASK(3, 0)
+
+#define CPI_OPCODE_PHY_PCS_RESET 0xF0
+#define CPI_OPCODE_PHY_PCS_ONPI_RESET_VAL 0x3F
+
+#define CPI_LM_CMD_REQ 1
+#define CPI_LM_CMD_SET 1
+
+union cpi_reg_phy_cmd_data {
+ struct {
+ u16 data;
+ u16 opcode : 8;
+ u16 portlane : 3;
+ u16 reserved_13_11: 3;
+ u16 error : 1;
+ u16 ack : 1;
+ } __packed field;
+ u32 val;
+};
+
+union cpi_reg_lm_cmd_data {
+ struct {
+ u16 data;
+ u16 opcode : 8;
+ u16 portlane : 3;
+ u16 reserved_12_11: 2;
+ u16 get_set : 1;
+ u16 cpi_reset : 1;
+ u16 cpi_req : 1;
+ } __packed field;
+ u32 val;
+};
+
+struct ice_cpi_cmd {
+ u8 port;
+ u8 opcode;
+ u16 data;
+ bool set;
+};
+
+struct ice_cpi_resp {
+ u8 port;
+ u8 opcode;
+ u16 data;
+};
+
+int ice_cpi_exec(struct ice_hw *hw, u8 phy,
+ const struct ice_cpi_cmd *cmd,
+ struct ice_cpi_resp *resp);
+int ice_cpi_ena_dis_clk_ref(struct ice_hw *hw, u8 port,
+ enum ice_e825c_ref_clk clk, bool enable);
+#endif /* _ICE_CPI_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_sbq_cmd.h b/drivers/net/ethernet/intel/ice/ice_sbq_cmd.h
index 21bb861febbf..226243d32968 100644
--- a/drivers/net/ethernet/intel/ice/ice_sbq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_sbq_cmd.h
@@ -54,8 +54,9 @@ enum ice_sbq_dev_id {
};
enum ice_sbq_msg_opcode {
- ice_sbq_msg_rd = 0x00,
- ice_sbq_msg_wr = 0x01
+ ice_sbq_msg_rd = 0x00,
+ ice_sbq_msg_wr = 0x01,
+ ice_sbq_msg_wr_np = 0x02
};
#define ICE_SBQ_MSG_FLAGS 0x40
--
2.39.3
^ permalink raw reply related
* Re: [RFC PATCH net-next 0/3] seg6: SRv6 L2 VPN with End.DT2U and srl2 device
From: Nicolas Dichtel @ 2026-03-26 16:32 UTC (permalink / raw)
To: Andrea Mayer, netdev
Cc: David S . Miller, David Ahern, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Stefano Salsano, Paolo Lungaroni,
Ahmed Abdelsalam, Justin Iurman, linux-kernel
In-Reply-To: <20260322000557.12559-1-andrea.mayer@uniroma2.it>
Le 22/03/2026 à 01:05, Andrea Mayer a écrit :
> Hi all,
Hi,
first, thank you for posting this RFC.
>
> this RFC series adds support for the SRv6 End.DT2U behavior and
> introduces the srl2 Ethernet pseudowire device, together with
> corresponding selftests.
>
> Motivation
> ==========
>
> The main goal is to enable L2 service delivery through an internal
> SRv6 L2 endpoint, in a way similar to how VXLAN provides L2 services
> through a VXLAN netdevice.
>
> Today, Linux supports SRv6 L2 decapsulation only through an
> End.DX2-style model, where the exposed Ethernet frame is forwarded
> to a configured egress interface. The current implementation does
> not provide a native netdevice representing the SRv6 L2 service
> endpoint. This is a significant limitation compared to VXLAN, where
> the tunnel endpoint is represented by a netdevice that can be
> attached to a bridge and integrated naturally into the local L2
> data plane.
>
> On the encapsulation side, the existing H.L2.Encaps mode is
> implemented as a route-based lwtunnel, which only intercepts packets
> entering the IP routing path. Non-IP protocols such as ARP are
> never routed and therefore cannot be encapsulated, making it
> unsuitable for full L2 service delivery.
>
> Design
> ======
>
> This series addresses that limitation by introducing srl2, a native
> SRv6 L2 endpoint interface. The intent is to make SRv6 L2 delivery
> usable in the same deployment model already familiar from VXLAN: an
> internal interface that represents the L2 service endpoint and can
> participate naturally in local L2 forwarding.
The current design, with vxlan, uses two interfaces: one bridge and one vxlan.
I presume this design was chosen because the vxlan protocol is implemented in
the vxlan driver.
I wonder if using the same design for SRv6 is the best choice. Why not use only
a bridge interface? Instead of pointing to a port, the FDB entries could point
to a nexthop id. This enables to associate a srv6 encap directly to a MAC
address. Something like:
$ ip nexthop list id 1234
id 1234 encap seg6 mode encap segs ...
$ bridge fdb show dev br0
02:03:04:05:06:07 dev br0 nhid 1234 ...
What is the gain of having two interfaces?
In term of scalability, it is interesting to have only one interface.
Regards,
Nicolas
>
> On top of that, the series adds support for End.DT2U so that Ethernet
> payloads carried over SRv6 can be decapsulated and delivered into an
> L2 domain through either a bridge port or an srl2 interface.
>
> Relation to RFC 8986
> ====================
>
> RFC 8986 describes End.DT2U in terms of an abstract L2 table
> associated with the SID. That abstraction specifies the externally
> observable forwarding behavior of the node, but it does not mandate a
> specific internal implementation. What matters is functional
> equivalence.
>
> This series enforces that property by restricting valid End.DT2U
> decapsulation targets to endpoints that provide the required L2
> forwarding semantics by construction.
>
> When the target device is a bridge port, the Linux bridge provides
> the expected behavior directly: source MAC learning, destination MAC
> lookup, and unknown-unicast flooding within the corresponding L2
> domain.
>
> When the target device is an srl2 interface, the same model is
> realized in a degenerate but valid form, corresponding to a minimal
> two-port L2 domain in which one endpoint is srl2. In that case,
> forwarding is trivial: frames are delivered to srl2 only when
> addressed to its MAC address, or when they are broadcast or multicast.
> No general FDB is required in this case because there are no
> additional L2 destinations to learn.
>
> Any other type of decapsulation target is rejected at configuration
> time, since it would not guarantee the forwarding behavior required by
> End.DT2U.
>
> The srl2 device is the minimal baseline implementation providing
> point-to-point L2 encapsulation with a single segment list.
> Additional features can be added incrementally based on community
> feedback and use cases.
>
> Usage
> =====
>
> ip link add srl2-0 type srl2 segs fc00::a,fc00::b
> ip link set srl2-0 master br0
>
> ip -6 route add fc00::100/128 encap seg6local action End.DT2U \
> l2dev srl2-0 dev dum0
>
> # encapsulating traffic from veth-hs into srl2-0
> ip link set veth-hs master br0
>
> Selftest topology
> =================
>
> cafe::1 cafe::2
> 10.0.0.1 10.0.0.2
> +--------+ +--------+
> | hs-1 | | hs-2 |
> +---+----+ +----+---+
> | |
> +-----+------+ +------+-----+
> | veth-hs | | veth-hs |
> | | | fcf0:0:1:2::/64 | | |
> | br0 +-------------------------+ br0 |
> | | | | | |
> | srl2-0 | | srl2-0 |
> | rt-1 | | rt-2 |
> +------------+ +------------+
>
> The test verifies IPv4/IPv6 host-to-host and host-to-gateway
> connectivity over the SRv6 L2 VPN, including ARP resolution
> through the tunnel.
>
> A companion iproute2 series provides userspace support:
>
> [RFC PATCH iproute2-next 0/4] seg6: add SRv6 End.DT2U and srl2 support
>
>
> This is an RFC posting to collect feedback on both the overall design
> and the userspace API before moving forward with a formal submission.
>
> Comments are very welcome, especially on:
> - the introduction of srl2 as an internal SRv6 L2 endpoint
> - the choice of constraining End.DT2U targets to bridge ports
> and srl2 devices
> - the netlink/uAPI exposure
> - the selftest coverage and topology
>
> Thanks,
> Andrea and Stefano
>
>
> Andrea Mayer (3):
> seg6: add support for the SRv6 End.DT2U behavior
> seg6: add SRv6 L2 tunnel device (srl2)
> selftests: seg6: add SRv6 srl2 + End.DT2U L2 VPN test
>
> include/linux/srl2.h | 7 +
> include/uapi/linux/seg6_local.h | 3 +
> include/uapi/linux/srl2.h | 20 +
> net/ipv6/Kconfig | 16 +
> net/ipv6/Makefile | 1 +
> net/ipv6/seg6.c | 1 +
> net/ipv6/seg6_local.c | 160 ++++-
> net/ipv6/srl2.c | 269 ++++++++
> tools/testing/selftests/net/Makefile | 1 +
> tools/testing/selftests/net/config | 1 +
> .../selftests/net/srv6_srl2_l2vpn_test.sh | 621 ++++++++++++++++++
> 11 files changed, 1094 insertions(+), 6 deletions(-)
> create mode 100644 include/linux/srl2.h
> create mode 100644 include/uapi/linux/srl2.h
> create mode 100644 net/ipv6/srl2.c
> create mode 100755 tools/testing/selftests/net/srv6_srl2_l2vpn_test.sh
>
^ permalink raw reply
* [PATCH v4 net-next 5/8] ice: add TX clock (TXC) DPLL interface for E825 devices
From: Grzegorz Nitka @ 2026-03-26 16:28 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, intel-wired-lan, poros, richardcochran,
andrew+netdev, przemyslaw.kitszel, anthony.l.nguyen,
Prathosh.Satish, ivecera, jiri, arkadiusz.kubalewski,
vadim.fedorenko, donald.hunter, horms, pabeni, kuba, davem,
edumazet, Grzegorz Nitka
In-Reply-To: <20260326162832.3135857-1-grzegorz.nitka@intel.com>
Introduce a TX clock DPLL instance and pins for E825-based devices.
The TXC domain exposes two reference pins:
- EXT_EREF0 (board external electrical reference)
- SYNCE (port-derived reference, described via fwnode)
A new pin type (ICE_DPLL_PIN_TYPE_TXCLK) and pin ops are added. The
SYNCE pin is registered when its fwnode becomes available, while
EXT_EREF0 is registered directly. The notifier worker is updated to
register/unregister TXC pins and to ignore notifications that are a
side effect of internal registration by checking the src_id.
A new per-pin attribute tracks the TX reference source
(enum ice_e825c_ref_clk). The TXC DPLL device is created and torn
down alongside existing PPS/EEC devices on E825, with specific init
and deinit flows for the TXC pins.
Current TXC pin state getters return DISCONNECTED as a placeholder;
hardware-backed state reporting will be implemented in a follow-up.
Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Signed-off-by: Grzegorz Nitka <grzegorz.nitka@intel.com>
---
drivers/net/ethernet/intel/ice/ice_dpll.c | 296 ++++++++++++++++++--
drivers/net/ethernet/intel/ice/ice_dpll.h | 6 +
drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 7 +
3 files changed, 286 insertions(+), 23 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c
index 62f75701d652..72518fd1398d 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.c
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.c
@@ -19,6 +19,11 @@
#define ICE_DPLL_SW_PIN_INPUT_BASE_QSFP 6
#define ICE_DPLL_SW_PIN_OUTPUT_BASE 0
+#define E825_EXT_EREF_PIN_IDX 0
+#define E825_EXT_SYNCE_PIN_IDX 1
+#define E825_RCLK_PARENT_0_PIN_IDX 0
+#define E825_RCLK_PARENT_1_PIN_IDX 1
+
#define ICE_DPLL_PIN_SW_INPUT_ABS(in_idx) \
(ICE_DPLL_SW_PIN_INPUT_BASE_SFP + (in_idx))
@@ -57,6 +62,7 @@
* @ICE_DPLL_PIN_TYPE_OUTPUT: output pin
* @ICE_DPLL_PIN_TYPE_RCLK_INPUT: recovery clock input pin
* @ICE_DPLL_PIN_TYPE_SOFTWARE: software controlled SMA/U.FL pins
+ * @ICE_DPLL_PIN_TYPE_TXCLK: transmit clock reference input pin
*/
enum ice_dpll_pin_type {
ICE_DPLL_PIN_INVALID,
@@ -64,6 +70,7 @@ enum ice_dpll_pin_type {
ICE_DPLL_PIN_TYPE_OUTPUT,
ICE_DPLL_PIN_TYPE_RCLK_INPUT,
ICE_DPLL_PIN_TYPE_SOFTWARE,
+ ICE_DPLL_PIN_TYPE_TXCLK,
};
static const char * const pin_type_name[] = {
@@ -71,10 +78,13 @@ static const char * const pin_type_name[] = {
[ICE_DPLL_PIN_TYPE_OUTPUT] = "output",
[ICE_DPLL_PIN_TYPE_RCLK_INPUT] = "rclk-input",
[ICE_DPLL_PIN_TYPE_SOFTWARE] = "software",
+ [ICE_DPLL_PIN_TYPE_TXCLK] = "txclk-input",
};
static const char * const ice_dpll_sw_pin_sma[] = { "SMA1", "SMA2" };
static const char * const ice_dpll_sw_pin_ufl[] = { "U.FL1", "U.FL2" };
+static const char * const ice_dpll_ext_eref_pin = "EXT_EREF0";
+static const char * const ice_dpll_fwnode_ext_synce = "clk_ref_synce";
static const struct dpll_pin_frequency ice_esync_range[] = {
DPLL_PIN_FREQUENCY_RANGE(0, DPLL_PIN_FREQUENCY_1_HZ),
@@ -2517,12 +2527,75 @@ ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, void *pin_priv,
return ret;
}
+/**
+ * ice_dpll_txclk_state_on_dpll_set - set a state on TX clk pin
+ * @pin: pointer to a pin
+ * @pin_priv: private data pointer passed on pin registration
+ * @dpll: registered dpll pointer
+ * @dpll_priv: private data pointer passed on dpll registration
+ * @state: state to be set on pin
+ * @extack: error reporting
+ *
+ * Dpll subsystem callback, set a state of a Tx reference clock pin
+ *
+ * Return:
+ * * negative - failure
+ */
+static int
+ice_dpll_txclk_state_on_dpll_set(const struct dpll_pin *pin, void *pin_priv,
+ const struct dpll_device *dpll,
+ void *dpll_priv, enum dpll_pin_state state,
+ struct netlink_ext_ack *extack)
+{
+ /*
+ * TODO: set HW accordingly to selected TX reference clock.
+ * To be added in the follow up patches.
+ */
+ return -EOPNOTSUPP;
+}
+
+/**
+ * ice_dpll_txclk_state_on_dpll_get - get a state of Tx clk reference pin
+ * @pin: pointer to a pin
+ * @pin_priv: private data pointer passed on pin registration
+ * @dpll: registered dpll pointer
+ * @dpll_priv: private data pointer passed on dpll registration
+ * @state: on success holds pin state on parent pin
+ * @extack: error reporting
+ *
+ * dpll subsystem callback, get a state of a TX clock reference pin.
+ *
+ * Return:
+ * * 0 - success
+ */
+static int
+ice_dpll_txclk_state_on_dpll_get(const struct dpll_pin *pin, void *pin_priv,
+ const struct dpll_device *dpll,
+ void *dpll_priv,
+ enum dpll_pin_state *state,
+ struct netlink_ext_ack *extack)
+{
+ /*
+ * TODO: query HW status to determine if the TX reference is selected.
+ * To be added in the follow up patches.
+ */
+ *state = DPLL_PIN_STATE_DISCONNECTED;
+
+ return 0;
+}
+
static const struct dpll_pin_ops ice_dpll_rclk_ops = {
.state_on_pin_set = ice_dpll_rclk_state_on_pin_set,
.state_on_pin_get = ice_dpll_rclk_state_on_pin_get,
.direction_get = ice_dpll_input_direction,
};
+static const struct dpll_pin_ops ice_dpll_txclk_ops = {
+ .state_on_dpll_set = ice_dpll_txclk_state_on_dpll_set,
+ .state_on_dpll_get = ice_dpll_txclk_state_on_dpll_get,
+ .direction_get = ice_dpll_input_direction,
+};
+
static const struct dpll_pin_ops ice_dpll_pin_sma_ops = {
.state_on_dpll_set = ice_dpll_sma_pin_state_set,
.state_on_dpll_get = ice_dpll_sw_pin_state_get,
@@ -3023,9 +3096,13 @@ ice_dpll_unregister_pins(struct dpll_device *dpll, struct ice_dpll_pin *pins,
{
int i;
- for (i = 0; i < count; i++)
- if (!pins[i].hidden)
- dpll_pin_unregister(dpll, pins[i].pin, ops, &pins[i]);
+ for (i = 0; i < count; i++) {
+ if (pins[i].hidden)
+ continue;
+ if (IS_ERR_OR_NULL(pins[i].pin))
+ continue;
+ dpll_pin_unregister(dpll, pins[i].pin, ops, &pins[i]);
+ }
}
/**
@@ -3199,19 +3276,40 @@ static bool ice_dpll_is_fwnode_pin(struct ice_dpll_pin *pin)
return !IS_ERR_OR_NULL(pin->fwnode);
}
+static bool ice_dpll_fwnode_eq(const struct fwnode_handle *a,
+ const struct fwnode_handle *b)
+{
+ return a && b && a == b;
+}
+
static void ice_dpll_pin_notify_work(struct work_struct *work)
{
struct ice_dpll_pin_work *w = container_of(work,
struct ice_dpll_pin_work,
work);
struct ice_dpll_pin *pin, *parent = w->pin;
+ bool is_tx_synce_parent = false;
struct ice_pf *pf = parent->pf;
+ bool is_rclk_parent = false;
int ret;
wait_for_completion(&pf->dplls.dpll_init);
if (!test_bit(ICE_FLAG_DPLL, pf->flags))
goto out; /* DPLL initialization failed */
+ /* Decide which parent we are handling, defensively checking FWNs */
+ is_rclk_parent =
+ ice_dpll_fwnode_eq(parent->fwnode,
+ pf->dplls.inputs[E825_RCLK_PARENT_0_PIN_IDX].fwnode) ||
+ ice_dpll_fwnode_eq(parent->fwnode,
+ pf->dplls.inputs[E825_RCLK_PARENT_1_PIN_IDX].fwnode);
+
+ is_tx_synce_parent =
+ ice_dpll_fwnode_eq(parent->fwnode,
+ pf->dplls.txclks[E825_EXT_SYNCE_PIN_IDX].fwnode);
+ if (!is_rclk_parent && !is_tx_synce_parent)
+ goto out;
+
switch (w->action) {
case DPLL_PIN_CREATED:
if (!IS_ERR_OR_NULL(parent->pin)) {
@@ -3228,16 +3326,28 @@ static void ice_dpll_pin_notify_work(struct work_struct *work)
goto out;
}
- /* Register rclk pin */
- pin = &pf->dplls.rclk;
- ret = dpll_pin_on_pin_register(parent->pin, pin->pin,
- &ice_dpll_rclk_ops, pin);
- if (ret) {
- dev_err(ice_pf_to_dev(pf),
- "Failed to register pin: %pe\n", ERR_PTR(ret));
- dpll_pin_put(parent->pin, &parent->tracker);
- parent->pin = NULL;
- goto out;
+ if (is_rclk_parent) {
+ /* Register rclk pin via on-pin relationship */
+ pin = &pf->dplls.rclk;
+ ret = dpll_pin_on_pin_register(parent->pin, pin->pin,
+ &ice_dpll_rclk_ops, pin);
+ if (ret) {
+ dev_err(ice_pf_to_dev(pf),
+ "RCLK pin register failed: %pe\n",
+ ERR_PTR(ret));
+ goto drop_parent_ref;
+ }
+ } else if (is_tx_synce_parent) {
+ /* Register TX-CLK SYNCE pin directly to TXC DPLL */
+ pin = &pf->dplls.txclks[E825_EXT_SYNCE_PIN_IDX];
+ ret = dpll_pin_register(pf->dplls.txc.dpll, pin->pin,
+ &ice_dpll_txclk_ops, pin);
+ if (ret) {
+ dev_err(ice_pf_to_dev(pf),
+ "TX SYNCE pin register failed: %pe\n",
+ ERR_PTR(ret));
+ goto drop_parent_ref;
+ }
}
break;
case DPLL_PIN_DELETED:
@@ -3246,11 +3356,18 @@ static void ice_dpll_pin_notify_work(struct work_struct *work)
goto out;
}
- /* Unregister rclk pin */
- pin = &pf->dplls.rclk;
- dpll_pin_on_pin_unregister(parent->pin, pin->pin,
- &ice_dpll_rclk_ops, pin);
-
+ if (is_rclk_parent) {
+ /* Unregister rclk pin */
+ pin = &pf->dplls.rclk;
+ dpll_pin_on_pin_unregister(parent->pin, pin->pin,
+ &ice_dpll_rclk_ops, pin);
+ } else if (is_tx_synce_parent) {
+ /* Unregister TX-CLK SYNCE pin from TXC DPLL */
+ pin = &pf->dplls.txclks[E825_EXT_SYNCE_PIN_IDX];
+ dpll_pin_unregister(pf->dplls.txc.dpll, pin->pin,
+ &ice_dpll_txclk_ops, pin);
+ }
+drop_parent_ref:
/* Drop fwnode pin reference */
dpll_pin_put(parent->pin, &parent->tracker);
parent->pin = NULL;
@@ -3276,6 +3393,12 @@ static int ice_dpll_pin_notify(struct notifier_block *nb, unsigned long action,
if (pin->fwnode != info->fwnode)
return NOTIFY_DONE; /* Not this pin */
+ /* Ignore notification which are the outcome of internal pin
+ * registration/unregistration calls - synce pin case.
+ */
+ if (info->src_id == pin->pf->dplls.clock_id)
+ return NOTIFY_DONE;
+
work = kzalloc_obj(*work);
if (!work)
return NOTIFY_DONE;
@@ -3401,6 +3524,19 @@ ice_dpll_deinit_fwnode_pins(struct ice_pf *pf, struct ice_dpll_pin *pins,
destroy_workqueue(pf->dplls.wq);
}
+static int ice_dpll_deinit_txclk_pins(struct ice_pf *pf)
+{
+ struct ice_dpll_pin *synce_pin = &pf->dplls.txclks[E825_EXT_SYNCE_PIN_IDX];
+ struct ice_dpll *dt = &pf->dplls.txc;
+
+ ice_dpll_unregister_pins(dt->dpll, pf->dplls.txclks,
+ &ice_dpll_txclk_ops,
+ ARRAY_SIZE(pf->dplls.txclks));
+ ice_dpll_release_pins(&pf->dplls.txclks[E825_EXT_EREF_PIN_IDX], 1);
+ ice_dpll_deinit_fwnode_pin(synce_pin);
+ return 0;
+}
+
/**
* ice_dpll_deinit_pins - deinitialize direct pins
* @pf: board private structure
@@ -3420,8 +3556,10 @@ static void ice_dpll_deinit_pins(struct ice_pf *pf, bool cgu)
struct ice_dpll *dp = &d->pps;
ice_dpll_deinit_rclk_pin(pf);
- if (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825)
+ if (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825) {
+ ice_dpll_deinit_txclk_pins(pf);
ice_dpll_deinit_fwnode_pins(pf, pf->dplls.inputs, 0);
+ }
if (cgu) {
ice_dpll_unregister_pins(dp->dpll, inputs, &ice_dpll_input_ops,
num_inputs);
@@ -3552,6 +3690,58 @@ ice_dpll_init_fwnode_pins(struct ice_pf *pf, struct ice_dpll_pin *pins,
return ret;
}
+static int ice_dpll_init_txclk_pins(struct ice_pf *pf, int start_idx)
+{
+ struct ice_dpll_pin *ref_pin = pf->dplls.txclks;
+ struct ice_dpll *txc = &pf->dplls.txc;
+ int ret;
+
+ /* Configure EXT_EREF0 pin */
+ ret = ice_dpll_get_pins(pf, ref_pin, start_idx, 1, pf->dplls.clock_id);
+ if (ret)
+ return ret;
+ ret = dpll_pin_register(txc->dpll, ref_pin->pin, &ice_dpll_txclk_ops,
+ ref_pin);
+ if (ret)
+ goto err_release_ext_eref;
+
+ /*
+ * Configure EXT_SYNCE pin (fwnode-backed).
+ * The pin may not yet be available; in that case registration
+ * will be deferred via the notifier path.
+ */
+ ref_pin++;
+ ret = ice_dpll_init_fwnode_pin(ref_pin, ice_dpll_fwnode_ext_synce);
+ if (ret)
+ goto err_unregister_ext_eref;
+
+ if (IS_ERR_OR_NULL(ref_pin->pin)) {
+ dev_dbg(ice_pf_to_dev(pf),
+ "Tx-clk SYNCE pin not registered yet\n");
+ return 0;
+ }
+
+ ret = dpll_pin_register(txc->dpll, ref_pin->pin, &ice_dpll_txclk_ops,
+ ref_pin);
+ if (ret)
+ goto err_deinit_synce;
+
+ return 0;
+
+err_deinit_synce:
+ ice_dpll_deinit_fwnode_pin(ref_pin);
+err_unregister_ext_eref:
+ dpll_pin_unregister(txc->dpll,
+ pf->dplls.txclks[E825_EXT_EREF_PIN_IDX].pin,
+ &ice_dpll_txclk_ops,
+ &pf->dplls.txclks[E825_EXT_EREF_PIN_IDX]);
+
+err_release_ext_eref:
+ ice_dpll_release_pins(&pf->dplls.txclks[E825_EXT_EREF_PIN_IDX], 1);
+
+ return ret;
+}
+
/**
* ice_dpll_init_pins_e825 - init pins and register pins with a dplls
* @pf: board private structure
@@ -3574,6 +3764,15 @@ static int ice_dpll_init_pins_e825(struct ice_pf *pf)
ret = ice_dpll_init_rclk_pin(pf, DPLL_PIN_IDX_UNSPEC,
&ice_dpll_rclk_ops);
+
+ if (ret)
+ goto unregister_pins;
+
+ ret = ice_dpll_init_txclk_pins(pf, 0);
+ if (ret)
+ ice_dpll_deinit_rclk_pin(pf);
+
+unregister_pins:
if (ret) {
/* Inform DPLL notifier works that DPLL init was finished
* unsuccessfully (ICE_DPLL_FLAG not set).
@@ -3692,7 +3891,7 @@ static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu)
static void
ice_dpll_deinit_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu)
{
- if (cgu)
+ if (cgu || pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825)
dpll_device_unregister(d->dpll, d->ops, d);
dpll_device_put(d->dpll, &d->tracker);
}
@@ -3727,12 +3926,13 @@ ice_dpll_init_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu,
return ret;
}
d->pf = pf;
- if (cgu) {
+ if (cgu || pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825) {
const struct dpll_device_ops *ops = &ice_dpll_ops;
if (type == DPLL_TYPE_PPS && ice_dpll_is_pps_phase_monitor(pf))
ops = &ice_dpll_pom_ops;
- ice_dpll_update_state(pf, d, true);
+ if (cgu)
+ ice_dpll_update_state(pf, d, true);
ret = dpll_device_register(d->dpll, type, ops, d);
if (ret) {
dpll_device_put(d->dpll, &d->tracker);
@@ -4081,6 +4281,36 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf)
return 0;
}
+/**
+ * ice_dpll_init_info_txclk_pins_e825c - initializes tx-clk pins information
+ * @pf: board private structure
+ *
+ * Init information for tx-clks pin, cache them in pf->dplls.txclks
+ *
+ * Return:
+ * * 0 - success
+ */
+static int ice_dpll_init_info_txclk_pins_e825c(struct ice_pf *pf)
+{
+ struct ice_dpll_pin *tx_pin;
+
+ for (int i = 0; i < ICE_DPLL_TXCLK_NUM_MAX; i++) {
+ tx_pin = &pf->dplls.txclks[i];
+ tx_pin->prop.type = DPLL_PIN_TYPE_EXT;
+ tx_pin->prop.capabilities |=
+ DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE;
+ tx_pin->pf = pf;
+ if (i == E825_EXT_EREF_PIN_IDX) {
+ tx_pin->prop.board_label = ice_dpll_ext_eref_pin;
+ tx_pin->tx_ref_src = ICE_REF_CLK_EREF0;
+ } else if (i == E825_EXT_SYNCE_PIN_IDX) {
+ tx_pin->tx_ref_src = ICE_REF_CLK_SYNCE;
+ }
+ }
+
+ return 0;
+}
+
/**
* ice_dpll_init_pins_info - init pins info wrapper
* @pf: board private structure
@@ -4106,6 +4336,9 @@ ice_dpll_init_pins_info(struct ice_pf *pf, enum ice_dpll_pin_type pin_type)
return ice_dpll_init_info_rclk_pin(pf);
case ICE_DPLL_PIN_TYPE_SOFTWARE:
return ice_dpll_init_info_sw_pins(pf);
+
+ case ICE_DPLL_PIN_TYPE_TXCLK:
+ return ice_dpll_init_info_txclk_pins_e825c(pf);
default:
return -EINVAL;
}
@@ -4139,11 +4372,15 @@ static void ice_dpll_deinit_info(struct ice_pf *pf)
static int ice_dpll_init_info_e825c(struct ice_pf *pf)
{
struct ice_dplls *d = &pf->dplls;
+ struct ice_dpll *dt = &d->txc;
int ret = 0;
int i;
d->clock_id = ice_generate_clock_id(pf);
d->num_inputs = ICE_SYNCE_CLK_NUM;
+ dt->dpll_state = DPLL_LOCK_STATUS_LOCKED;
+ dt->mode = DPLL_MODE_MANUAL;
+ dt->dpll_idx = pf->ptp.port.port_num;
d->inputs = kzalloc_objs(*d->inputs, d->num_inputs);
if (!d->inputs)
@@ -4160,6 +4397,11 @@ static int ice_dpll_init_info_e825c(struct ice_pf *pf)
ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_RCLK_INPUT);
if (ret)
goto deinit_info;
+
+ ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_TXCLK);
+ if (ret)
+ goto deinit_info;
+
dev_dbg(ice_pf_to_dev(pf),
"%s - success, inputs: %u, outputs: %u, rclk-parents: %u\n",
__func__, d->num_inputs, d->num_outputs, d->rclk.num_parents);
@@ -4292,6 +4534,9 @@ void ice_dpll_deinit(struct ice_pf *pf)
ice_dpll_deinit_dpll(pf, &pf->dplls.pps, cgu);
if (!IS_ERR_OR_NULL(pf->dplls.eec.dpll))
ice_dpll_deinit_dpll(pf, &pf->dplls.eec, cgu);
+ if (!IS_ERR_OR_NULL(pf->dplls.txc.dpll))
+ ice_dpll_deinit_dpll(pf, &pf->dplls.txc, false);
+
ice_dpll_deinit_info(pf);
mutex_destroy(&pf->dplls.lock);
}
@@ -4317,14 +4562,19 @@ static void ice_dpll_init_e825(struct ice_pf *pf)
err = ice_dpll_init_info_e825c(pf);
if (err)
goto err_exit;
- err = ice_dpll_init_pins_e825(pf);
+ err = ice_dpll_init_dpll(pf, &pf->dplls.txc, false, DPLL_TYPE_TXC);
if (err)
goto deinit_info;
+ err = ice_dpll_init_pins_e825(pf);
+ if (err)
+ goto deinit_txclk;
set_bit(ICE_FLAG_DPLL, pf->flags);
complete_all(&d->dpll_init);
return;
+deinit_txclk:
+ ice_dpll_deinit_dpll(pf, &pf->dplls.txc, false);
deinit_info:
ice_dpll_deinit_info(pf);
err_exit:
diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.h b/drivers/net/ethernet/intel/ice/ice_dpll.h
index ae42cdea0ee1..23f9d4da73c5 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.h
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.h
@@ -7,6 +7,7 @@
#include "ice.h"
#define ICE_DPLL_RCLK_NUM_MAX 4
+#define ICE_DPLL_TXCLK_NUM_MAX 2
/**
* enum ice_dpll_pin_sw - enumerate ice software pin indices:
@@ -63,6 +64,7 @@ struct ice_dpll_pin {
u8 ref_sync;
bool active;
bool hidden;
+ enum ice_e825c_ref_clk tx_ref_src;
};
/** ice_dpll - store info required for DPLL control
@@ -111,9 +113,11 @@ struct ice_dpll {
* @lock: locks access to configuration of a dpll
* @eec: pointer to EEC dpll dev
* @pps: pointer to PPS dpll dev
+ * @txc: pointer to TXC dpll dev
* @inputs: input pins pointer
* @outputs: output pins pointer
* @rclk: recovered pins pointer
+ * @txclks: TX clock reference pins pointer
* @num_inputs: number of input pins available on dpll
* @num_outputs: number of output pins available on dpll
* @cgu_state_acq_err_num: number of errors returned during periodic work
@@ -131,11 +135,13 @@ struct ice_dplls {
struct completion dpll_init;
struct ice_dpll eec;
struct ice_dpll pps;
+ struct ice_dpll txc;
struct ice_dpll_pin *inputs;
struct ice_dpll_pin *outputs;
struct ice_dpll_pin sma[ICE_DPLL_PIN_SW_NUM];
struct ice_dpll_pin ufl[ICE_DPLL_PIN_SW_NUM];
struct ice_dpll_pin rclk;
+ struct ice_dpll_pin txclks[ICE_DPLL_TXCLK_NUM_MAX];
u8 num_inputs;
u8 num_outputs;
u8 sma_data;
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
index 9bfd3e79c580..cbc9693179a1 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
@@ -265,6 +265,13 @@ struct ice_cgu_pin_desc {
struct dpll_pin_frequency *freq_supp;
};
+enum ice_e825c_ref_clk {
+ ICE_REF_CLK_ENET,
+ ICE_REF_CLK_SYNCE,
+ ICE_REF_CLK_EREF0,
+ ICE_REF_CLK_MAX,
+};
+
#define E810C_QSFP_C827_0_HANDLE 2
#define E810C_QSFP_C827_1_HANDLE 3
--
2.39.3
^ permalink raw reply related
* [PATCH v4 net-next 4/8] dpll: zl3073x: allow SyncE_Ref pin state change
From: Grzegorz Nitka @ 2026-03-26 16:28 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, intel-wired-lan, poros, richardcochran,
andrew+netdev, przemyslaw.kitszel, anthony.l.nguyen,
Prathosh.Satish, ivecera, jiri, arkadiusz.kubalewski,
vadim.fedorenko, donald.hunter, horms, pabeni, kuba, davem,
edumazet, Grzegorz Nitka, Aleksandr Loktionov
In-Reply-To: <20260326162832.3135857-1-grzegorz.nitka@intel.com>
The SyncE_Ref pin may operate as either an active or inactive reference
depending on board design and system configuration. Some platforms need
to disable the SyncE reference dynamically (e.g., when selecting a
different recovered clock input). The hardware supports toggling this
pin, therefore advertise the STATE_CAN_CHANGE capability.
Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Grzegorz Nitka <grzegorz.nitka@intel.com>
---
drivers/dpll/zl3073x/prop.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/dpll/zl3073x/prop.c b/drivers/dpll/zl3073x/prop.c
index ac9d41d0f978..acd7061a741a 100644
--- a/drivers/dpll/zl3073x/prop.c
+++ b/drivers/dpll/zl3073x/prop.c
@@ -215,6 +215,15 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
props->dpll_props.type = DPLL_PIN_TYPE_GNSS;
+ /*
+ * The SyncE_Ref pin supports enabling/disabling dynamically.
+ * Some platforms may choose to expose this through firmware
+ * configuration later. For now, advertise this capability
+ * universally since the hardware allows state toggling.
+ */
+ props->dpll_props.capabilities |=
+ DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE;
+
/* The output pin phase adjustment granularity equals half of
* the synth frequency count.
*/
--
2.39.3
^ permalink raw reply related
* [PATCH v4 net-next 3/8] dpll: extend pin notifier and netlink events with notification source ID
From: Grzegorz Nitka @ 2026-03-26 16:28 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, intel-wired-lan, poros, richardcochran,
andrew+netdev, przemyslaw.kitszel, anthony.l.nguyen,
Prathosh.Satish, ivecera, jiri, arkadiusz.kubalewski,
vadim.fedorenko, donald.hunter, horms, pabeni, kuba, davem,
edumazet, Grzegorz Nitka, Aleksandr Loktionov
In-Reply-To: <20260326162832.3135857-1-grzegorz.nitka@intel.com>
Extend the DPLL pin notification API to include a source identifier
indicating where the notification originates. This allows notifier
consumers and netlink listeners to distinguish between notifications
coming from an associated DPLL instance, a parent pin, or the pin
itself.
A new field, src_id, is added to struct dpll_pin_notifier_info and is
passed through all pin-related notification paths. Callers of
dpll_pin_notify() are updated to provide a meaningful source identifier
based on their context:
- pin registration/unregistration uses the DPLL's clock_id,
- pin-on-pin operations use the parent pin's clock_id,
- pin changes use the pin's own clock_id.
As introduced in the commit ("dpll: allow registering FW-identified pin
with a different DPLL"), it is possible to share the same physical pin
via firmware description (fwnode) with DPLL objects from different
kernel modules. This means that a given pin can be registered multiple
times.
Driver such as ICE (E825 devices) rely on this mechanism when listening
for the event where a shared-fwnode pin appears, while avoiding reacting
to events triggered by their own registration logic.
This change only extends the notification metadata and does not alter
existing semantics for drivers that do not use the new field.
Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Grzegorz Nitka <grzegorz.nitka@intel.com>
---
drivers/dpll/dpll_core.c | 14 ++++++++------
drivers/dpll/dpll_core.h | 2 +-
drivers/dpll/dpll_netlink.c | 10 +++++-----
drivers/dpll/dpll_netlink.h | 4 ++--
include/linux/dpll.h | 1 +
5 files changed, 17 insertions(+), 14 deletions(-)
diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c
index 55ad03977d6d..c7fcae76c3f5 100644
--- a/drivers/dpll/dpll_core.c
+++ b/drivers/dpll/dpll_core.c
@@ -71,7 +71,8 @@ void dpll_device_notify(struct dpll_device *dpll, unsigned long action)
call_dpll_notifiers(action, &info);
}
-void dpll_pin_notify(struct dpll_pin *pin, unsigned long action)
+void dpll_pin_notify(struct dpll_pin *pin, u64 ntfy_src,
+ unsigned long action)
{
struct dpll_pin_notifier_info info = {
.pin = pin,
@@ -80,6 +81,7 @@ void dpll_pin_notify(struct dpll_pin *pin, unsigned long action)
.clock_id = pin->clock_id,
.fwnode = pin->fwnode,
.prop = &pin->prop,
+ .src_id = ntfy_src,
};
call_dpll_notifiers(action, &info);
@@ -847,7 +849,7 @@ __dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
if (ret)
goto ref_pin_del;
xa_set_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED);
- dpll_pin_create_ntf(pin);
+ dpll_pin_create_ntf(pin, dpll->clock_id);
return ret;
@@ -946,7 +948,7 @@ void dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin,
return;
mutex_lock(&dpll_lock);
- dpll_pin_delete_ntf(pin);
+ dpll_pin_delete_ntf(pin, dpll->clock_id);
__dpll_pin_unregister(dpll, pin, ops, priv, NULL);
mutex_unlock(&dpll_lock);
}
@@ -992,7 +994,7 @@ int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin,
stop = i;
goto dpll_unregister;
}
- dpll_pin_create_ntf(pin);
+ dpll_pin_create_ntf(pin, parent->clock_id);
}
mutex_unlock(&dpll_lock);
@@ -1003,7 +1005,7 @@ int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin,
if (i < stop) {
__dpll_pin_unregister(ref->dpll, pin, ops, priv,
parent);
- dpll_pin_delete_ntf(pin);
+ dpll_pin_delete_ntf(pin, parent->clock_id);
}
dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv, pin);
unlock:
@@ -1029,7 +1031,7 @@ void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin,
unsigned long i;
mutex_lock(&dpll_lock);
- dpll_pin_delete_ntf(pin);
+ dpll_pin_delete_ntf(pin, parent->clock_id);
dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv, pin);
xa_for_each(&pin->dpll_refs, i, ref)
__dpll_pin_unregister(ref->dpll, pin, ops, priv, parent);
diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h
index 71ac88ef2017..f684d9d4c4da 100644
--- a/drivers/dpll/dpll_core.h
+++ b/drivers/dpll/dpll_core.h
@@ -98,6 +98,6 @@ extern struct xarray dpll_pin_xa;
extern struct mutex dpll_lock;
void dpll_device_notify(struct dpll_device *dpll, unsigned long action);
-void dpll_pin_notify(struct dpll_pin *pin, unsigned long action);
+void dpll_pin_notify(struct dpll_pin *pin, u64 ntfy_src, unsigned long action);
#endif
diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c
index 83cbd64abf5a..afb778420b93 100644
--- a/drivers/dpll/dpll_netlink.c
+++ b/drivers/dpll/dpll_netlink.c
@@ -830,21 +830,21 @@ dpll_pin_event_send(enum dpll_cmd event, struct dpll_pin *pin)
return ret;
}
-int dpll_pin_create_ntf(struct dpll_pin *pin)
+int dpll_pin_create_ntf(struct dpll_pin *pin, u64 ntfy_src)
{
- dpll_pin_notify(pin, DPLL_PIN_CREATED);
+ dpll_pin_notify(pin, ntfy_src, DPLL_PIN_CREATED);
return dpll_pin_event_send(DPLL_CMD_PIN_CREATE_NTF, pin);
}
-int dpll_pin_delete_ntf(struct dpll_pin *pin)
+int dpll_pin_delete_ntf(struct dpll_pin *pin, u64 ntfy_src)
{
- dpll_pin_notify(pin, DPLL_PIN_DELETED);
+ dpll_pin_notify(pin, ntfy_src, DPLL_PIN_DELETED);
return dpll_pin_event_send(DPLL_CMD_PIN_DELETE_NTF, pin);
}
int __dpll_pin_change_ntf(struct dpll_pin *pin)
{
- dpll_pin_notify(pin, DPLL_PIN_CHANGED);
+ dpll_pin_notify(pin, pin->clock_id, DPLL_PIN_CHANGED);
return dpll_pin_event_send(DPLL_CMD_PIN_CHANGE_NTF, pin);
}
diff --git a/drivers/dpll/dpll_netlink.h b/drivers/dpll/dpll_netlink.h
index dd28b56d27c5..082c2aea6d1a 100644
--- a/drivers/dpll/dpll_netlink.h
+++ b/drivers/dpll/dpll_netlink.h
@@ -8,8 +8,8 @@ int dpll_device_create_ntf(struct dpll_device *dpll);
int dpll_device_delete_ntf(struct dpll_device *dpll);
-int dpll_pin_create_ntf(struct dpll_pin *pin);
+int dpll_pin_create_ntf(struct dpll_pin *pin, u64 ntfy_src);
-int dpll_pin_delete_ntf(struct dpll_pin *pin);
+int dpll_pin_delete_ntf(struct dpll_pin *pin, u64 ntfy_src);
int __dpll_pin_change_ntf(struct dpll_pin *pin);
diff --git a/include/linux/dpll.h b/include/linux/dpll.h
index 2ce295b46b8c..ae4b146d7243 100644
--- a/include/linux/dpll.h
+++ b/include/linux/dpll.h
@@ -202,6 +202,7 @@ struct dpll_pin_notifier_info {
u64 clock_id;
const struct fwnode_handle *fwnode;
const struct dpll_pin_properties *prop;
+ u64 src_id;
};
#if IS_ENABLED(CONFIG_DPLL)
--
2.39.3
^ permalink raw reply related
* [PATCH v4 net-next 2/8] dpll: allow registering FW-identified pin with a different DPLL
From: Grzegorz Nitka @ 2026-03-26 16:28 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, intel-wired-lan, poros, richardcochran,
andrew+netdev, przemyslaw.kitszel, anthony.l.nguyen,
Prathosh.Satish, ivecera, jiri, arkadiusz.kubalewski,
vadim.fedorenko, donald.hunter, horms, pabeni, kuba, davem,
edumazet, Grzegorz Nitka, Jiri Pirko, Aleksandr Loktionov
In-Reply-To: <20260326162832.3135857-1-grzegorz.nitka@intel.com>
Relax the (module, clock_id) equality requirement when registering a
pin identified by firmware (pin->fwnode). Some platforms associate a
FW-described pin with a DPLL instance that differs from the pin's
(module, clock_id) tuple. For such pins, permit registration without
requiring the strict match. Non-FW pins still require equality.
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Grzegorz Nitka <grzegorz.nitka@intel.com>
---
drivers/dpll/dpll_core.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c
index 3f54754cdec4..55ad03977d6d 100644
--- a/drivers/dpll/dpll_core.c
+++ b/drivers/dpll/dpll_core.c
@@ -880,11 +880,21 @@ dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
return -EINVAL;
mutex_lock(&dpll_lock);
- if (WARN_ON(!(dpll->module == pin->module &&
- dpll->clock_id == pin->clock_id)))
+
+ /*
+ * For pins identified via firmware (pin->fwnode), allow registration
+ * even if the pin's (module, clock_id) differs from the target DPLL.
+ * For non-fwnode pins, require a strict (module, clock_id) match.
+ */
+ if (!pin->fwnode &&
+ WARN_ON_ONCE(dpll->module != pin->module ||
+ dpll->clock_id != pin->clock_id)) {
ret = -EINVAL;
- else
- ret = __dpll_pin_register(dpll, pin, ops, priv, NULL);
+ goto out_unlock;
+ }
+
+ ret = __dpll_pin_register(dpll, pin, ops, priv, NULL);
+out_unlock:
mutex_unlock(&dpll_lock);
return ret;
--
2.39.3
^ permalink raw reply related
* [PATCH v4 net-next 1/8] dpll: add new DPLL type for transmit clock (TXC) usage
From: Grzegorz Nitka @ 2026-03-26 16:28 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, intel-wired-lan, poros, richardcochran,
andrew+netdev, przemyslaw.kitszel, anthony.l.nguyen,
Prathosh.Satish, ivecera, jiri, arkadiusz.kubalewski,
vadim.fedorenko, donald.hunter, horms, pabeni, kuba, davem,
edumazet, Grzegorz Nitka, Jiri Pirko, Aleksandr Loktionov
In-Reply-To: <20260326162832.3135857-1-grzegorz.nitka@intel.com>
Extend the DPLL subsystem with a new DPLL type, DPLL_TYPE_TXC,
representing devices that drive a transmit reference clock. Certain
PHYs, MACs and SerDes blocks use a dedicated TX reference clock for
link operation, and this clock domain is distinct from PPS- and
EEC-driven synchronization sources. Defining a dedicated type allows
user space and drivers to correctly classify and configure DPLLs
intended for TX clock generation.
The corresponding netlink specification is updated to expose "txc".
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Grzegorz Nitka <grzegorz.nitka@intel.com>
---
Documentation/netlink/specs/dpll.yaml | 3 +++
drivers/dpll/dpll_nl.c | 2 +-
include/uapi/linux/dpll.h | 2 ++
3 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml
index 3dd48a32f783..2a2ee37a1fc0 100644
--- a/Documentation/netlink/specs/dpll.yaml
+++ b/Documentation/netlink/specs/dpll.yaml
@@ -138,6 +138,9 @@ definitions:
-
name: eec
doc: dpll drives the Ethernet Equipment Clock
+ -
+ name: txc
+ doc: dpll drives Tx reference clock
render-max: true
-
type: enum
diff --git a/drivers/dpll/dpll_nl.c b/drivers/dpll/dpll_nl.c
index a2b22d492114..4182bdbb6dbb 100644
--- a/drivers/dpll/dpll_nl.c
+++ b/drivers/dpll/dpll_nl.c
@@ -34,7 +34,7 @@ const struct nla_policy dpll_reference_sync_nl_policy[DPLL_A_PIN_STATE + 1] = {
static const struct nla_policy dpll_device_id_get_nl_policy[DPLL_A_TYPE + 1] = {
[DPLL_A_MODULE_NAME] = { .type = NLA_NUL_STRING, },
[DPLL_A_CLOCK_ID] = { .type = NLA_U64, },
- [DPLL_A_TYPE] = NLA_POLICY_RANGE(NLA_U32, 1, 2),
+ [DPLL_A_TYPE] = NLA_POLICY_RANGE(NLA_U32, 1, 3),
};
/* DPLL_CMD_DEVICE_GET - do */
diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h
index de0005f28e5c..8f6db5d5bf0c 100644
--- a/include/uapi/linux/dpll.h
+++ b/include/uapi/linux/dpll.h
@@ -109,10 +109,12 @@ enum dpll_clock_quality_level {
* enum dpll_type - type of dpll, valid values for DPLL_A_TYPE attribute
* @DPLL_TYPE_PPS: dpll produces Pulse-Per-Second signal
* @DPLL_TYPE_EEC: dpll drives the Ethernet Equipment Clock
+ * @DPLL_TYPE_TXC: dpll drives Tx reference clock
*/
enum dpll_type {
DPLL_TYPE_PPS = 1,
DPLL_TYPE_EEC,
+ DPLL_TYPE_TXC,
/* private: */
__DPLL_TYPE_MAX,
--
2.39.3
^ permalink raw reply related
* [PATCH v4 net-next 0/8] dpll/ice: Add TXC DPLL type and full TX reference clock control for E825
From: Grzegorz Nitka @ 2026-03-26 16:28 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, intel-wired-lan, poros, richardcochran,
andrew+netdev, przemyslaw.kitszel, anthony.l.nguyen,
Prathosh.Satish, ivecera, jiri, arkadiusz.kubalewski,
vadim.fedorenko, donald.hunter, horms, pabeni, kuba, davem,
edumazet, Grzegorz Nitka
NOTE: This series is intentionally submitted on net-next (not
intel-wired-lan) as early feedback of DPLL subsystem changes is
welcomed. In the past possible approaches were discussed in [1].
This series extends the DPLL subsystem and the ICE driver to fully
support transmit‑clock (TXC) reference selection on Intel E825‑class
hardware. These devices expose a dedicated TX reference clock domain
separate from PPS and SyncE/EEC, and they allow switching between
multiple PHY‑sourced references (TXC0, EREF0, SyncE). Until now
the kernel lacked a DPLL type to represent TXC‑class devices, and
the ICE driver had no way to control or report the active TX reference.
The series introduces:
Subsystem‑wide improvements:
- A new DPLL type (DPLL_TYPE_TXC) to represent devices that generate a TX
SERDES reference clock.
- Improvements to pin registration for fwnode‑identified pins.
- Addition of a notification source identifier (src_id) for more accurate
pin event routing in both netlink and internal notifiers.
Hardware/driver support:
- ZL3073x: allow control of the SyncE_Ref pin state.
- ICE/E825: full TXC DPLL instance with dedicated pins (EXT_EREF0 and
SyncE) and proper integration into the notifier/mux logic.
-A new CPI (Converged PHY Interface) subsystem implementing the low‑level
command protocol required by E825 PHY clocking control.
- Extension of the Restart AN AQ command with a TX reference clock
selector.
- Complete support for selecting, enabling, disabling, and tracking the
active TX reference clock for E825 devices, including peer‑PHY routing
and safe clean‑up of unused clock sources.
This enables proper userspace‑driven clock control via the DPLL API and
is a prerequisite for advanced SyncE deployments, link recovery modes, and
multi‑clock orchestration on E825 NICs.
Patch summary:
dpll: add new DPLL type for transmit clock (TXC) usage
Introduces DPLL_TYPE_TXC and publishes it through netlink.
dpll: allow registering FW‑identified pin with a different DPLL
Relax the (module, clock_id) matching rules when fwnode pins are
involved.
dpll: extend pin notifier and netlink events with notification source ID
Adds src_id to pin notification paths and updates all callers.
dpll: zl3073x: allow SyncE_Ref pin state change
Advertise hardware support for state toggling.
ice: add TX clock (TXC) DPLL interface for E825 devices
Introduces the ICE TXC DPLL, its pins, and relations to existing PHY
fwnode pins.
ice: implement CPI support for E825C
Adds the CPI command engine used for PHY‑side clock control.
ice: add Tx reference clock index handling to AN restart command
Wires the refclk field into the AQ Restart AN command.
ice: add TX reference clock (tx_clk) control for E825 devices
Implements full clock‑selection logic, state tracking, cleanup, and
DPLL pin ops integration.
Testing was performed on E825C hardware in multi‑port configurations,
verifying TXC pin exposure, SyncE/EREF0 switching via DPLL netlink, and
link recovery across all combinations.
[1] https://lore.kernel.org/netdev/20250905160333.715c34ac@kernel.org/
Changes in v4:
- rebased
- edited, shortened the commit message in 3/8 patch
- moved ice_get_ctrl_pf to the header file (patch 8/8) and
removed duplicated static definitions from ice_ptp and ice_txlck
modules
- add NULL/invalid pointer checker for returned pointer from
ice_get_ctrl_pf (patch 8/8)
- edited error message in case AN restart failure (patch 8/8)
Changes in v3:
- improved commit message (patch 1/8, AI review comment)
- improved deinitialization path in ice_dpll_deinit_txclk_pins to
avoid potential NULL dereference. NULL checking moved to
ice_dpll_unregister_pins (patch 5/8, found by AI review)
- removed redundant semicolon (patch 6/8)
Changes in v2:
- rebased
- added autogenerated DPLL files (patch 1/8)
- fixed checkpatch 'parenthesis alignment' warning (patch 2/8)
- fixed error path in ice_dpll_init_txclk_pins (AI warning, patch 5/8)
- fixed kdoc warnings (patch 6/8, patch 8/8)
Grzegorz Nitka (8):
dpll: add new DPLL type for transmit clock (TXC) usage
dpll: allow registering FW-identified pin with a different DPLL
dpll: extend pin notifier and netlink events with notification source
ID
dpll: zl3073x: allow SyncE_Ref pin state change
ice: add TX clock (TXC) DPLL interface for E825 devices
ice: implement CPI support for E825C
ice: add Tx reference clock index handling to AN restart command
ice: add TX reference clock (tx_clk) control for E825 devices
Documentation/netlink/specs/dpll.yaml | 3 +
drivers/dpll/dpll_core.c | 32 +-
drivers/dpll/dpll_core.h | 2 +-
drivers/dpll/dpll_netlink.c | 10 +-
drivers/dpll/dpll_netlink.h | 4 +-
drivers/dpll/dpll_nl.c | 2 +-
drivers/dpll/zl3073x/prop.c | 9 +
drivers/net/ethernet/intel/ice/Makefile | 2 +-
drivers/net/ethernet/intel/ice/ice.h | 12 +
.../net/ethernet/intel/ice/ice_adminq_cmd.h | 2 +
drivers/net/ethernet/intel/ice/ice_common.c | 5 +-
drivers/net/ethernet/intel/ice/ice_common.h | 2 +-
drivers/net/ethernet/intel/ice/ice_cpi.c | 347 ++++++++++++++++++
drivers/net/ethernet/intel/ice/ice_cpi.h | 69 ++++
drivers/net/ethernet/intel/ice/ice_dpll.c | 327 +++++++++++++++--
drivers/net/ethernet/intel/ice/ice_dpll.h | 6 +
drivers/net/ethernet/intel/ice/ice_lib.c | 3 +-
drivers/net/ethernet/intel/ice/ice_ptp.c | 27 +-
drivers/net/ethernet/intel/ice/ice_ptp.h | 7 +
drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 37 ++
drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 34 ++
drivers/net/ethernet/intel/ice/ice_sbq_cmd.h | 5 +-
drivers/net/ethernet/intel/ice/ice_txclk.c | 256 +++++++++++++
drivers/net/ethernet/intel/ice/ice_txclk.h | 41 +++
include/linux/dpll.h | 1 +
include/uapi/linux/dpll.h | 2 +
26 files changed, 1194 insertions(+), 53 deletions(-)
create mode 100644 drivers/net/ethernet/intel/ice/ice_cpi.c
create mode 100644 drivers/net/ethernet/intel/ice/ice_cpi.h
create mode 100644 drivers/net/ethernet/intel/ice/ice_txclk.c
create mode 100644 drivers/net/ethernet/intel/ice/ice_txclk.h
base-commit: d1e59a46973719e458bec78d00dd767d7a7ba71f
--
2.39.3
^ permalink raw reply
* [GIT PULL] Networking for v7.0-rc6
From: Paolo Abeni @ 2026-03-26 16:30 UTC (permalink / raw)
To: torvalds; +Cc: kuba, davem, netdev, linux-kernel
Hi Linus!
The following changes since commit a1d9d8e833781c44ab688708804ce35f20f3cbbd:
Merge tag 'net-7.0-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net (2026-03-19 11:25:40 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git net-7.0-rc6
for you to fetch changes up to db472c34a74770f39318ddb1efa986c0a8d5d86a:
Merge tag 'nf-26-03-26' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf (2026-03-26 15:38:14 +0100)
----------------------------------------------------------------
Including fixes from Bluetooth, CAN, IPsec and Netfilter.
Notably, this includes the fix for the Bluetooth regression that you
were notified about. I'm not aware of any other pending regressions.
Current release - regressions:
- bluetooth:
- fix stack-out-of-bounds read in l2cap_ecred_conn_req
- fix regressions caused by reusing ident
- netfilter: revisit array resize logic
- eth: ice: set max queues in alloc_etherdev_mqs()
Previous releases - regressions:
- core: correctly handle tunneled traffic on IPV6_CSUM GSO fallback
- bluetooth:
- fix dangling pointer on mgmt_add_adv_patterns_monitor_complete
- fix deadlock in l2cap_conn_del()
- sched: codel: fix stale state for empty flows in fq_codel
- ipv6: remove permanent routes from tb6_gc_hlist when all exceptions expire.
- xfrm: fix skb_put() panic on non-linear skb during reassembly
- openvswitch:
- avoid releasing netdev before teardown completes
- validate MPLS set/set_masked payload length
- eth: iavf: fix out-of-bounds writes in iavf_get_ethtool_stats()
Previous releases - always broken:
- bluetooth: fix null-ptr-deref on l2cap_sock_ready_cb
- udp: fix wildcard bind conflict check when using hash2
- netfilter: fix use of uninitialized rtp_addr in process_sdp
- tls: Purge async_hold in tls_decrypt_async_wait()
- xfrm:
- prevent policy_hthresh.work from racing with netns teardown
- fix skb leak with espintcp and async crypto
- smc: fix double-free of smc_spd_priv when tee() duplicates splice pipe buffer
- can:
- add missing error handling to call can_ctrlmode_changelink()
- fix OOB heap access in cgw_csum_crc8_rel()
- eth: mana: fix use-after-free in add_adev() error path
- eth: virtio-net: fix for VIRTIO_NET_F_GUEST_HDRLEN
- eth: bcmasp: fix double free of WoL irq
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
----------------------------------------------------------------
Ali Norouzi (1):
can: gw: fix OOB heap access in cgw_csum_crc8_rel()
Anas Iqbal (1):
Bluetooth: hci_ll: Fix firmware leak on error path
Arnd Bergmann (1):
net: b44: always select CONFIG_FIXED_PHY
Cen Zhang (2):
Bluetooth: hci_sync: annotate data-races around hdev->req_status
Bluetooth: btintel: serialize btintel_hw_error() with hci_req_sync_lock
Chuck Lever (1):
tls: Purge async_hold in tls_decrypt_async_wait()
David Carlier (2):
net: ti: icssg-prueth: fix use-after-free of CPPI descriptor in RX path
netfilter: ctnetlink: use netlink policy range checks
Eric Dumazet (1):
af_key: validate families in pfkey_send_migrate()
Fernando Fernandez Mancera (1):
xfrm: iptfs: fix skb_put() panic on non-linear skb during reassembly
Florian Westphal (2):
netfilter: nft_set_pipapo_avx2: don't return non-matching entry on expiry
selftests: netfilter: nft_concat_range.sh: add check for flush+reload bug
Guangshuo Li (1):
net: mana: fix use-after-free in add_adev() error path
Helen Koike (1):
Bluetooth: L2CAP: Fix null-ptr-deref on l2cap_sock_ready_cb
Hyunwoo Kim (5):
xfrm: Fix work re-schedule after cancel in xfrm_nat_keepalive_net_fini()
Bluetooth: L2CAP: Validate PDU length before reading SDU length in l2cap_ecred_data_rcv()
Bluetooth: SCO: Fix use-after-free in sco_recv_frame() due to missing sock_hold
Bluetooth: L2CAP: Fix deadlock in l2cap_conn_del()
Bluetooth: L2CAP: Fix ERTM re-init and zero pdu_len infinite loop
Jakub Kicinski (6):
Merge tag 'for-net-2026-03-19' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth
nfc: nci: fix circular locking dependency in nci_close_device
Merge branch 'net-macb-fix-two-lock-warnings-when-wol-is-used'
Merge branch 'rtnetlink-add-missing-attributes-in-if_nlmsg_size'
Merge branch 'net-bcmasp-fix-issues-during-driver-unbind'
Merge branch 'ipv6-fix-two-gc-issues-with-permanent-routes'
Jiayuan Chen (2):
team: fix header_ops type confusion with non-Ethernet ports
selftests: team: add non-Ethernet header_ops reproducer
Jonas Köppeler (1):
net_sched: codel: fix stale state for empty flows in fq_codel
Joshua Hay (2):
idpf: clear stale cdev_info ptr
idpf: only assign num refillqs if allocation was successful
Justin Chen (2):
net: bcmasp: fix double free of WoL irq
net: bcmasp: fix double disable of clk
Kevin Hao (3):
net: macb: Move devm_{free,request}_irq() out of spin lock area
net: macb: Protect access to net_device::ip_ptr with RCU lock
net: macb: Use dev_consume_skb_any() to free TX SKBs
Kohei Enju (1):
iavf: fix out-of-bounds writes in iavf_get_ethtool_stats()
Kuniyuki Iwashima (3):
ipv6: Remove permanent routes from tb6_gc_hlist when all exceptions expire.
ipv6: Don't remove permanent routes with exceptions from tb6_gc_hlist.
selftest: net: Add GC test for temporary routes with exceptions.
Luiz Augusto von Dentz (2):
Bluetooth: MGMT: Fix dangling pointer on mgmt_add_adv_patterns_monitor_complete
Bluetooth: L2CAP: Fix regressions caused by reusing ident
Marc Kleine-Budde (2):
can: netlink: can_changelink(): add missing error handling to call can_ctrlmode_changelink()
Merge patch series "can: fix can-gw Out-of-Bounds Heap R/W and isotp UAF"
Martin KaFai Lau (1):
udp: Fix wildcard bind conflict check when using hash2
Michal Swiatkowski (1):
ice: set max queues in alloc_etherdev_mqs()
Minseo Park (1):
Bluetooth: L2CAP: Fix stack-out-of-bounds read in l2cap_ecred_conn_req
Minwoo Ra (1):
xfrm: prevent policy_hthresh.work from racing with netns teardown
Mohammad Heib (1):
ionic: fix persistent MAC address override on PF
Oliver Hartkopp (2):
can: statistics: add missing atomic access in hot path
can: isotp: fix tx.buf use-after-free in isotp_sendmsg()
Pablo Neira Ayuso (6):
netfilter: nft_set_rbtree: revisit array resize logic
netfilter: nf_conntrack_expect: honor expectation helper field
netfilter: nf_conntrack_expect: use expect->helper
netfilter: ctnetlink: ensure safe access to master conntrack
netfilter: nf_conntrack_expect: store netns and zone in expectation
netfilter: nf_conntrack_expect: skip expectations in other netns via proc
Paolo Abeni (7):
Merge branch 'virtio-net-fix-for-virtio_net_f_guest_hdrlen'
Merge branch 'team-fix-header_ops-type-confusion-and-add-selftest'
Merge tag 'linux-can-fixes-for-7.0-20260323' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can
Merge tag 'ipsec-2026-03-23' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
Merge tag 'for-net-2026-03-25' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth
Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue
Merge tag 'nf-26-03-26' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
Paolo Valerio (1):
net: macb: use the current queue number for stats
Paul Moses (1):
xfrm: iptfs: only publish mode_data after clone setup
Pengpeng Hou (1):
Bluetooth: btusb: clamp SCO altsetting table indices
Petr Oros (2):
ice: fix inverted ready check for VF representors
ice: use ice_update_eth_stats() for representor stats
Qi Tang (1):
net/smc: fix double-free of smc_spd_priv when tee() duplicates splice pipe buffer
Qingfang Deng (1):
net: airoha: add RCU lock around dev_fill_forward_path
Ren Wei (1):
netfilter: ip6t_rt: reject oversized addrnr in rt_mt6_check()
Roshan Kumar (1):
xfrm: iptfs: validate inner IPv4 header length in IPTFS payload
Sabrina Dubroca (17):
xfrm: add missing extack for XFRMA_SA_PCPU in add_acquire and allocspi
xfrm: fix the condition on x->pcpu_num in xfrm_sa_len
xfrm: call xdo_dev_state_delete during state update
esp: fix skb leak with espintcp and async crypto
xfrm: state: fix sparse warnings on xfrm_state_hold_rcu
xfrm: state: fix sparse warnings in xfrm_state_init
xfrm: state: fix sparse warnings around XFRM_STATE_INSERT
xfrm: state: add xfrm_state_deref_prot to state_by* walk under lock
xfrm: remove rcu/state_hold from xfrm_state_lookup_spi_proto
xfrm: state: silence sparse warnings during netns exit
xfrm: policy: fix sparse warnings in xfrm_policy_{init,fini}
xfrm: policy: silence sparse warning in xfrm_policy_unregister_afinfo
xfrm: add rcu_access_pointer to silence sparse warning for xfrm_input_afinfo
xfrm: avoid RCU warnings around the per-netns netlink socket
rtnetlink: count IFLA_PARENT_DEV_{NAME,BUS_NAME} in if_nlmsg_size
rtnetlink: count IFLA_INFO_SLAVE_KIND in if_nlmsg_size
rtnetlink: fix leak of SRCU struct in rtnl_link_register
Steffen Klassert (1):
Merge branch 'xfrm-fix-most-sparse-warnings'
Thangaraj Samynathan (1):
net: lan743x: fix duplex configuration in mac_link_up
Toke Høiland-Jørgensen (1):
net: openvswitch: Avoid releasing netdev before teardown completes
Wei Fang (1):
net: enetc: fix the output issue of 'ethtool --show-ring'
Weiming Shi (2):
netfilter: nfnetlink_log: fix uninitialized padding leak in NFULA_PAYLOAD
netfilter: nf_conntrack_sip: fix use of uninitialized rtp_addr in process_sdp
Wenyuan Li (1):
can: mcp251x: add error handling for power enable in open and resume
Willem de Bruijn (1):
net: correctly handle tunneled traffic on IPV6_CSUM GSO fallback
Xuan Zhuo (2):
virtio-net: correct hdr_len handling for VIRTIO_NET_F_GUEST_HDRLEN
virtio-net: correct hdr_len handling for tunnel gso
Yang Yang (2):
openvswitch: defer tunnel netdev_put to RCU release
openvswitch: validate MPLS set/set_masked payload length
Yochai Eisenrich (1):
net: fix fanout UAF in packet_release() via NETDEV_UP race
Zhang Chen (1):
Bluetooth: L2CAP: Fix send LE flow credits in ACL link
xietangxin (1):
virtio_net: Fix UAF on dst_ops when IFF_XMIT_DST_RELEASE is cleared and napi_tx is false
drivers/bluetooth/btintel.c | 11 +-
drivers/bluetooth/btusb.c | 5 +-
drivers/bluetooth/hci_ll.c | 2 +
drivers/net/can/dev/netlink.c | 4 +-
drivers/net/can/spi/mcp251x.c | 29 +++++-
drivers/net/ethernet/airoha/airoha_ppe.c | 2 +
drivers/net/ethernet/broadcom/Kconfig | 2 +-
drivers/net/ethernet/broadcom/asp2/bcmasp.c | 41 ++++----
drivers/net/ethernet/cadence/macb_main.c | 41 +++++---
.../net/ethernet/freescale/enetc/enetc_ethtool.c | 2 +
drivers/net/ethernet/intel/iavf/iavf_ethtool.c | 31 +++---
drivers/net/ethernet/intel/ice/ice.h | 22 ++++
drivers/net/ethernet/intel/ice/ice_ethtool.c | 32 ++----
drivers/net/ethernet/intel/ice/ice_main.c | 4 +-
drivers/net/ethernet/intel/ice/ice_repr.c | 5 +-
drivers/net/ethernet/intel/idpf/idpf.h | 2 +-
drivers/net/ethernet/intel/idpf/idpf_idc.c | 6 +-
drivers/net/ethernet/intel/idpf/idpf_txrx.c | 2 +-
drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 2 +-
drivers/net/ethernet/microchip/lan743x_main.c | 5 +
drivers/net/ethernet/microsoft/mana/mana_en.c | 6 +-
drivers/net/ethernet/pensando/ionic/ionic_lif.c | 17 +--
drivers/net/ethernet/ti/icssg/icssg_common.c | 4 +-
drivers/net/team/team_core.c | 65 +++++++++++-
drivers/net/tun_vnet.h | 2 +-
drivers/net/virtio_net.c | 7 +-
include/linux/virtio_net.h | 53 +++++++++-
include/net/bluetooth/l2cap.h | 1 +
include/net/codel_impl.h | 1 +
include/net/inet_hashtables.h | 14 +++
include/net/ip6_fib.h | 21 +++-
include/net/netfilter/nf_conntrack_core.h | 5 +
include/net/netfilter/nf_conntrack_expect.h | 20 +++-
include/net/netns/xfrm.h | 2 +-
include/uapi/linux/netfilter/nf_conntrack_common.h | 4 +
net/bluetooth/hci_conn.c | 2 +-
net/bluetooth/hci_core.c | 2 +-
net/bluetooth/hci_sync.c | 20 ++--
net/bluetooth/l2cap_core.c | 71 +++++++++----
net/bluetooth/l2cap_sock.c | 3 +
net/bluetooth/mgmt.c | 2 +-
net/bluetooth/sco.c | 10 +-
net/can/af_can.c | 4 +-
net/can/af_can.h | 2 +-
net/can/gw.c | 6 +-
net/can/isotp.c | 24 +++--
net/can/proc.c | 3 +-
net/core/dev.c | 22 +++-
net/core/rtnetlink.c | 28 ++++-
net/ipv4/esp4.c | 9 +-
net/ipv4/inet_connection_sock.c | 20 +---
net/ipv4/udp.c | 2 +-
net/ipv6/addrconf.c | 4 +-
net/ipv6/esp6.c | 9 +-
net/ipv6/ip6_fib.c | 15 ++-
net/ipv6/netfilter/ip6t_rt.c | 4 +
net/ipv6/route.c | 2 +-
net/key/af_key.c | 19 ++--
net/netfilter/nf_conntrack_broadcast.c | 8 +-
net/netfilter/nf_conntrack_ecache.c | 2 +
net/netfilter/nf_conntrack_expect.c | 39 ++++++-
net/netfilter/nf_conntrack_h323_main.c | 12 +--
net/netfilter/nf_conntrack_helper.c | 11 +-
net/netfilter/nf_conntrack_netlink.c | 75 ++++++-------
net/netfilter/nf_conntrack_proto_tcp.c | 10 +-
net/netfilter/nf_conntrack_sip.c | 18 ++--
net/netfilter/nfnetlink_log.c | 8 +-
net/netfilter/nft_set_pipapo_avx2.c | 20 ++--
net/netfilter/nft_set_rbtree.c | 92 +++++++++++++---
net/nfc/nci/core.c | 10 +-
net/openvswitch/flow_netlink.c | 2 +
net/openvswitch/vport-netdev.c | 11 +-
net/packet/af_packet.c | 1 +
net/smc/smc_rx.c | 9 +-
net/tls/tls_sw.c | 2 +-
net/xfrm/xfrm_input.c | 5 +-
net/xfrm/xfrm_iptfs.c | 17 ++-
net/xfrm/xfrm_nat_keepalive.c | 2 +-
net/xfrm/xfrm_policy.c | 12 ++-
net/xfrm/xfrm_state.c | 116 ++++++++++++---------
net/xfrm/xfrm_user.c | 32 ++++--
tools/testing/selftests/drivers/net/team/Makefile | 1 +
tools/testing/selftests/drivers/net/team/config | 2 +
.../drivers/net/team/non_ether_header_ops.sh | 41 ++++++++
tools/testing/selftests/net/fib_tests.sh | 61 ++++++++++-
.../selftests/net/netfilter/nft_concat_range.sh | 70 ++++++++++++-
86 files changed, 1057 insertions(+), 387 deletions(-)
create mode 100755 tools/testing/selftests/drivers/net/team/non_ether_header_ops.sh
^ permalink raw reply
* Re: [PATCH net 3/3] vxlan: validate ND option lengths in vxlan_na_create
From: Ido Schimmel @ 2026-03-26 16:30 UTC (permalink / raw)
To: Yang Yang
Cc: davem, edumazet, kuba, pabeni, razor, andrew+netdev, horms,
florian.fainelli, roopa, dlstevens, nb, netdev, bridge,
linux-kernel, yifanwucs, tomapufckgml, tanyuan98, bird
In-Reply-To: <20260326034441.2037420-4-n05ec@lzu.edu.cn>
On Thu, Mar 26, 2026 at 03:44:41AM +0000, Yang Yang wrote:
> vxlan_na_create() walks ND options according to option-provided
> lengths. A malformed option can make the parser advance beyond the
> computed option span or use a too-short source LLADDR option payload.
>
> Validate option lengths against the remaining NS option area before
> advancing, and only read source LLADDR when the option is large enough
> for an Ethernet address.
>
> Fixes: 4b29dba9c085 ("vxlan: fix nonfunctional neigh_reduce()")
> Cc: stable@vger.kernel.org
> Reported-by: Yifan Wu <yifanwucs@gmail.com>
> Reported-by: Juefei Pu <tomapufckgml@gmail.com>
> Tested-by: Ao Zhou <n05ec@lzu.edu.cn>
> Co-developed-by: Yuan Tan <tanyuan98@outlook.com>
> Signed-off-by: Yuan Tan <tanyuan98@outlook.com>
> Suggested-by: Xin Liu <bird@lzu.edu.cn>
> Signed-off-by: Yang Yang <n05ec@lzu.edu.cn>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
^ permalink raw reply
* Re: [RFC PATCH net-next 0/3] seg6: SRv6 L2 VPN with End.DT2U and srl2 device
From: Nicolas Dichtel @ 2026-03-26 16:30 UTC (permalink / raw)
To: Stefano Salsano, Justin Iurman, Andrea Mayer
Cc: netdev, David S . Miller, David Ahern, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Paolo Lungaroni,
Ahmed Abdelsalam, linux-kernel
In-Reply-To: <6fef33af-b351-4bf6-a210-ae2283ec9f69@uniroma2.it>
Le 25/03/2026 à 08:10, Stefano Salsano a écrit :
> Il 24/03/2026 17:00, Justin Iurman ha scritto:
>> On Sun, Mar 22, 2026 at 12:06 AM Andrea Mayer <andrea.mayer@uniroma2.it> wrote:
>>>
>>> Hi all,
>>>
>>> this RFC series adds support for the SRv6 End.DT2U behavior and
>>> introduces the srl2 Ethernet pseudowire device, together with
>>> corresponding selftests.
>>
>> Hi Andrea,
>>
>> Thanks for the work you (and Stefano) put into this series! As
>> discussed offline, there is interest in such a solution.
>
> Hi Justin,
>
> thx for your interest!
>
>> A general comment: I'm not sure about the name "srl2", as we're
>> talking about SRv6 specifically here.
>
> fair point
>
>> I would personally love to have
>> "l2srv6", although I suspect we may end up with "l2seg6" to remain
>> consistent.
>
> I'd like to keep it as short as possible, our initial idea was seg6l2, very
> close to your last suggestion, then we opted for srl2 losing the "6" concept
>
> now it comes to my mind that l2 is somehow redudant in an interface type name,
> as an interface is an l2 concept per se, so my preferred option becomes:
>
> sr6
Note that the interface name is defined to kind + a number when the IFLA_IFNAME
attribute is not specified:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/core/rtnetlink.c?h=v7.0-rc5#n3823
Here, the default name will be 'sr60' :)
'vti6' is already in this case, so it's probably ok. I vote for 'sr6' too ;-)
My two cents,
Nicolas
^ permalink raw reply
* Re: [PATCH net 2/3] bridge: br_nd_send: validate ND option lengths
From: Ido Schimmel @ 2026-03-26 16:30 UTC (permalink / raw)
To: Yang Yang
Cc: davem, edumazet, kuba, pabeni, razor, andrew+netdev, horms,
florian.fainelli, roopa, dlstevens, nb, netdev, bridge,
linux-kernel, yifanwucs, tomapufckgml, tanyuan98, bird
In-Reply-To: <20260326034441.2037420-3-n05ec@lzu.edu.cn>
On Thu, Mar 26, 2026 at 03:44:40AM +0000, Yang Yang wrote:
> br_nd_send() walks ND options according to option-provided lengths.
> A malformed option can make the parser advance beyond the computed
> option span or use a too-short source LLADDR option payload.
>
> Validate option lengths against the remaining NS option area before
> advancing, and only read source LLADDR when the option is large enough
> for an Ethernet address.
>
> Fixes: ed842faeb2bd ("bridge: suppress nd pkts on BR_NEIGH_SUPPRESS ports")
> Cc: stable@vger.kernel.org
> Reported-by: Yifan Wu <yifanwucs@gmail.com>
> Reported-by: Juefei Pu <tomapufckgml@gmail.com>
> Tested-by: Ao Zhou <n05ec@lzu.edu.cn>
> Co-developed-by: Yuan Tan <tanyuan98@outlook.com>
> Signed-off-by: Yuan Tan <tanyuan98@outlook.com>
> Suggested-by: Xin Liu <bird@lzu.edu.cn>
> Signed-off-by: Yang Yang <n05ec@lzu.edu.cn>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
The AI review [1] is correct that the length check for the
ND_OPT_SOURCE_LL_ADDR option is not strictly necessary, but it makes it
clear that the access is valid and it's harmless.
The other comment is about another existing issue in the code, but it's
less severe and shouldn't delay this patch.
[1] https://sashiko.dev/#/patchset/20260326034441.2037420-1-n05ec%40lzu.edu.cn
^ permalink raw reply
* Re: [PATCH net 1/3] bridge: br_nd_send: linearize skb before parsing ND options
From: Ido Schimmel @ 2026-03-26 16:29 UTC (permalink / raw)
To: Yang Yang
Cc: davem, edumazet, kuba, pabeni, razor, andrew+netdev, horms,
florian.fainelli, roopa, dlstevens, nb, netdev, bridge,
linux-kernel, yifanwucs, tomapufckgml, tanyuan98, bird
In-Reply-To: <20260326034441.2037420-2-n05ec@lzu.edu.cn>
On Thu, Mar 26, 2026 at 03:44:39AM +0000, Yang Yang wrote:
> br_nd_send() parses neighbour discovery options from ns->opt[] and
> assumes that these options are in the linear part of request.
>
> Its callers only guarantee that the ICMPv6 header and target address
> are available, so the option area can still be non-linear. Parsing
> ns->opt[] in that case can access data past the linear buffer.
>
> Linearize request before option parsing and derive ns from the linear
> network header.
>
> Fixes: ed842faeb2bd ("bridge: suppress nd pkts on BR_NEIGH_SUPPRESS ports")
> Reported-by: Yifan Wu <yifanwucs@gmail.com>
> Reported-by: Juefei Pu <tomapufckgml@gmail.com>
> Tested-by: Ao Zhou <n05ec@lzu.edu.cn>
> Co-developed-by: Yuan Tan <tanyuan98@outlook.com>
> Signed-off-by: Yuan Tan <tanyuan98@outlook.com>
> Suggested-by: Xin Liu <bird@lzu.edu.cn>
> Signed-off-by: Yang Yang <n05ec@lzu.edu.cn>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
^ permalink raw reply
* Re: [RFC PATCH net-next v6 2/2] selftests: net: test PPPoE packets in gro.sh
From: Willem de Bruijn @ 2026-03-26 16:29 UTC (permalink / raw)
To: Qingfang Deng, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Shuah Khan, Simon Horman,
Willem de Bruijn, Petr Machata, Richard Gobert, Anubhav Singh,
Chia-Yu Chang, netdev, linux-kselftest, linux-kernel
Cc: linux-ppp
In-Reply-To: <20260326081127.61229-2-dqfext@gmail.com>
Qingfang Deng wrote:
> Add PPPoE test-cases to the GRO selftest.
>
> Signed-off-by: Qingfang Deng <dqfext@gmail.com>
> ---
> v6: new patch
>
> I'm not sure if I should include all the existing IPv4/v6 tests for
> PPPoE. There are tests that hardcode ETH_HLEN as the NH offset, which
> are meant to test the L3 protocol, not the underlying protocol, and
> changing all of them seems too invasive.
Overall this change looks good to me. But indeed all the churn of
(pppoe ? PPPOE_SES_HLEN : 0)
is a bit annoying. Left a few representative snippets below.
I think that could be avoided similar to MAX_HDR_LEN by having a
global definition and using that everywhere. Still a lot of churn, but
at least no repeated open-coded logic.
Also consider whether running all these tests again in PPPoE adds
value, if not, then indeed trim the tests to those that truly add
code coverage.
> @@ -745,7 +777,7 @@ static void add_ipv4_ts_option(void *buf, void *optpkt)
> memcpy(optpkt + tcp_offset + optlen, buf + tcp_offset,
> sizeof(struct tcphdr) + PAYLOAD_LEN);
>
> - iph = (struct iphdr *)(optpkt + ETH_HLEN);
> + iph = (struct iphdr *)(optpkt + ETH_HLEN + (pppoe ? PPPOE_SES_HLEN : 0));
> iph->ihl = 5 + (optlen / 4);
> iph->tot_len = htons(ntohs(iph->tot_len) + optlen);
> iph->check = 0;
> @@ -755,7 +787,7 @@ static void add_ipv4_ts_option(void *buf, void *optpkt)
> static void add_ipv6_exthdr(void *buf, void *optpkt, __u8 exthdr_type, char *ext_payload)
> {
> struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr *)(optpkt + tcp_offset);
> - struct ipv6hdr *iph = (struct ipv6hdr *)(optpkt + ETH_HLEN);
> + struct ipv6hdr *iph = (struct ipv6hdr *)(optpkt + ETH_HLEN + (pppoe ? PPPOE_SES_HLEN : 0));
> char *exthdr_payload_start = (char *)(exthdr + 1);
>
> exthdr->hdrlen = 0;
^ permalink raw reply
* Re: [PATCH 09/11 net-next v5] bpf: remove ipv6_bpf_stub completely and use direct function calls
From: David Ahern @ 2026-03-26 16:27 UTC (permalink / raw)
To: Fernando Fernandez Mancera, Martin KaFai Lau
Cc: Ricardo B. Marlière, Daniel Borkmann, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Alexei Starovoitov, Andrii Nakryiko, Eduard Zingerman, Song Liu,
Yonghong Song, John Fastabend, KP Singh, Stanislav Fomichev,
Hao Luo, Jiri Olsa, Ido Schimmel, Guillaume Nault, linux-kernel,
bpf, netdev
In-Reply-To: <77792d0f-925f-4600-913c-b9dcdf8e9ea9@suse.de>
On 3/25/26 5:41 PM, Fernando Fernandez Mancera wrote:
> Hi David, I did the following testing:
>
> 1. ipv6.disabled=1 since booting - the IPv6 nexthop cannot be added to
> the IPv4 route at all.
>
> 2. ipv6.disabled=1 after booting but before configuring the IPv4 route -
> same result as above.
>
> 3. ipv6.disabled=1 after booting and after the IPv4 is configured - the
> neighbor lookup is fine as the nd_tbl is initialized. It didn't crash.
>
> I did tracing to make sure that code path was hit. I tested the
> forwarding with 3 namespaces 1<-->2<-->3 loading the BPF program on the
> second one performing the bpf_fib_lookup() instruction.
>
> I could do more testing regarding this if needed, let me know.
>
that looks good. Thank you
^ permalink raw reply
* Re: [PATCH net-next v1 7/7] net: hsr: use BIT() macro for bit shift constant
From: Felix Maurer @ 2026-03-26 16:26 UTC (permalink / raw)
To: luka.gejak
Cc: davem, edumazet, kuba, pabeni, netdev, horms, liuhangbin,
linux-kernel
In-Reply-To: <20260324144630.189094-8-luka.gejak@linux.dev>
On Tue, Mar 24, 2026 at 03:46:30PM +0100, luka.gejak@linux.dev wrote:
> From: Luka Gejak <luka.gejak@linux.dev>
>
> Replace the explicit bit shift (1 << HSR_SEQ_BLOCK_SHIFT) with the
> standardized BIT() macro for defining HSR_SEQ_BLOCK_SIZE. This improves
> readability and aligns with kernel coding conventions.
I know that checkpatch suggests this, but I don't agree with it:
HSR_SEQ_BLOCK_SHIFT is not a bitmap but a number, so in my opinion the
BIT() macro makes this particular define harder to read/understand.
> Signed-off-by: Luka Gejak <luka.gejak@linux.dev>
> ---
> net/hsr/hsr_framereg.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/hsr/hsr_framereg.h b/net/hsr/hsr_framereg.h
> index c65ecb925734..cb731ee0ce5c 100644
> --- a/net/hsr/hsr_framereg.h
> +++ b/net/hsr/hsr_framereg.h
> @@ -79,7 +79,7 @@ struct hsr_seq_block *hsr_get_seq_block(struct hsr_node *node, u16 block_idx);
> #endif
>
> #define HSR_SEQ_BLOCK_SHIFT 7 /* 128 bits */
> -#define HSR_SEQ_BLOCK_SIZE (1 << HSR_SEQ_BLOCK_SHIFT)
> +#define HSR_SEQ_BLOCK_SIZE BIT(HSR_SEQ_BLOCK_SHIFT)
> #define HSR_SEQ_BLOCK_MASK (HSR_SEQ_BLOCK_SIZE - 1)
> #define HSR_MAX_SEQ_BLOCKS 64
>
> --
> 2.53.0
>
^ permalink raw reply
* Re: [PATCH net-next v1 2/7] net: hsr: replace fallthrough comments with fallthrough macro
From: Felix Maurer @ 2026-03-26 16:25 UTC (permalink / raw)
To: luka.gejak
Cc: davem, edumazet, kuba, pabeni, netdev, horms, liuhangbin,
linux-kernel
In-Reply-To: <20260324144630.189094-3-luka.gejak@linux.dev>
On Tue, Mar 24, 2026 at 03:46:25PM +0100, luka.gejak@linux.dev wrote:
> From: Luka Gejak <luka.gejak@linux.dev>
>
> Replace two instances of the legacy '/* Fall through */' comment with the
> standardized 'fallthrough;' macro in hsr_get_node_status() and
> hsr_get_node_list(). The kernel has standardized on the fallthrough macro
> since the migration from comment-based annotations, which provides
> compiler-level verification of intentional case fall-throughs.
As the test robot message suggests: the fallthrough macro is only for
case statement blocks.
> Signed-off-by: Luka Gejak <luka.gejak@linux.dev>
> ---
> net/hsr/hsr_netlink.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c
> index db0b0af7a692..32c1b77cf84b 100644
> --- a/net/hsr/hsr_netlink.c
> +++ b/net/hsr/hsr_netlink.c
> @@ -433,7 +433,7 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info)
>
> nla_put_failure:
> kfree_skb(skb_out);
> - /* Fall through */
> + fallthrough;
>
> fail:
> rcu_read_unlock();
> @@ -524,7 +524,7 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info)
>
> nla_put_failure:
> nlmsg_free(skb_out);
> - /* Fall through */
> + fallthrough;
>
> fail:
> rcu_read_unlock();
> --
> 2.53.0
>
^ permalink raw reply
* Re: [PATCH net-next v1 0/7] net: hsr: subsystem cleanups and modernization
From: Felix Maurer @ 2026-03-26 16:25 UTC (permalink / raw)
To: luka.gejak
Cc: davem, edumazet, kuba, pabeni, netdev, horms, liuhangbin,
linux-kernel
In-Reply-To: <20260324144630.189094-1-luka.gejak@linux.dev>
On Tue, Mar 24, 2026 at 03:46:23PM +0100, luka.gejak@linux.dev wrote:
> From: Luka Gejak <luka.gejak@linux.dev>
>
> This patch series performs a general cleanup and modernization of the
> HSR(High-availability Seamless Redundancy) protocol driver. Since the
> HSR subsystem is currently orphaned, these changes aim to bring the
> code up to modern kernel standards and improve overall maintainability.
I appreciate that you are working on hsr and want to improve its code
quality. I agree that there is quite some room for improvement here.
However, I have a few general remarks before commenting on the
individual patches:
- Please consider the netdev policy for simple clean-up patches outside
the context of larger work [1] (esp. patches 5, 6).
- Please attribute the use of AI coding assistants [2].
Thanks,
Felix
[1]: https://docs.kernel.org/process/maintainer-netdev.html#clean-up-patches
[2]: https://docs.kernel.org/process/coding-assistants.html
> Luka Gejak (7):
> net: hsr: constify hsr_ops and prp_ops protocol operation structures
> net: hsr: replace fallthrough comments with fallthrough macro
> net: hsr: remove unnecessary void function return statement
> net: hsr: use __func__ instead of hardcoded function name
> net: hsr: remove unnecessary braces for single statement block
> net: hsr: add missing blank lines after function declarations
> net: hsr: use BIT() macro for bit shift constant
^ permalink raw reply
* Re: [PATCH net v6] net: use skb_header_pointer() for TCPv4 GSO frag_off
From: Willem de Bruijn @ 2026-03-26 16:25 UTC (permalink / raw)
To: Guoyu Su, edumazet, davem, kuba, pabeni
Cc: willemdebruijn.kernel, netdev, horms, linux-kernel,
syzkaller-bugs, syzbot+1543a7d954d9c6d00407, Guoyu Su
In-Reply-To: <20260326121813.457049-1-yss2813483011xxl@gmail.com>
Guoyu Su wrote:
> Syzbot reported a KMSAN uninit-value warning in gso_features_check()
> called from netif_skb_features() [1].
>
> gso_features_check() reads iph->frag_off to decide whether to clear
> mangleid_features. Accessing the IPv4 header via ip_hdr()/inner_ip_hdr()
> can rely on skb header offsets that are not always safe for direct
> dereference on packets injected from PF_PACKET paths.
>
> Use skb_header_pointer() for the TCPv4 frag_off check so the header read
> is robust whether data is already linear or needs copying.
>
> This also removes the SKB_GSO_DODGY special casing: skb_header_pointer()
> already fast-paths linear data, so a separate direct-access path is not
> needed.
Does not belong in the commit message. It's a diff vs the previous
version.
> [1] https://syzkaller.appspot.com/bug?extid=1543a7d954d9c6d00407
>
> Link: https://lore.kernel.org/netdev/willemdebruijn.kernel.1a9f35039caab@gmail.com/
> Fixes: cbc53e08a793 ("GSO: Add GSO type for fixed IPv4 ID")
> Reported-by: syzbot+1543a7d954d9c6d00407@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=1543a7d954d9c6d00407
> Tested-by: syzbot+1543a7d954d9c6d00407@syzkaller.appspotmail.com
> Signed-off-by: Guoyu Su <yss2813483011xxl@gmail.com>
> ---
> v6:
> - Use skb_header_pointer() for both DODGY and non-DODGY TCPv4 GSO
> packets in gso_features_check().
> - Drop the SKB_GSO_DODGY special-casing for IPv4 header access.
>
> v5: https://lore.kernel.org/netdev/20260320141459.9691-1-yss2813483011xxl@gmail.com/
> v4: https://lore.kernel.org/netdev/20260319005421.14908-1-yss2813483011xxl@gmail.com/
> v3: https://lore.kernel.org/netdev/20260312104351.185370-1-yss2813483011xxl@gmail.com/
> v2: https://lore.kernel.org/netdev/20260308083319.1255118-1-yss2813483011xxl@gmail.com/
> v1: https://lore.kernel.org/netdev/20260307162905.3697050-1-yss2813483011xxl@gmail.com/
>
> net/core/dev.c | 12 +++++++++---
> 1 file changed, 9 insertions(+), 3 deletions(-)
>
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 14a83f2035b9..8a15ca67cfed 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -3805,10 +3805,16 @@ static netdev_features_t gso_features_check(const struct sk_buff *skb,
> * segmentation-offloads.rst).
> */
> if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) {
> - struct iphdr *iph = skb->encapsulation ?
> - inner_ip_hdr(skb) : ip_hdr(skb);
> + const struct iphdr *iph;
> + struct iphdr _iph;
>
> - if (!(iph->frag_off & htons(IP_DF)))
minor: no whitespace in the middle of the variable definition block.
> + int nhoff = skb->encapsulation ?
> + skb_inner_network_offset(skb) :
> + skb_network_offset(skb);
> +
> + iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
> +
> + if (!iph || !(iph->frag_off & htons(IP_DF)))
> features &= ~dev->mangleid_features;
> }
>
> --
> 2.34.1
>
^ permalink raw reply
* Re: [PATCH net-next] net: add sysctl to toggle napi_consume_skb() alien skb defer
From: Jason Xing @ 2026-03-26 16:21 UTC (permalink / raw)
To: Eric Dumazet; +Cc: davem, kuba, pabeni, horms, netdev
In-Reply-To: <CANn89iL6FyoHBrfpwYSd5wPzFh3Y_1T8C6bVFuRRf7PP5p=WRw@mail.gmail.com>
On Thu, Mar 26, 2026 at 10:55 PM Eric Dumazet <edumazet@google.com> wrote:
>
> On Thu, Mar 26, 2026 at 7:43 AM Jason Xing <kerneljasonxing@gmail.com> wrote:
> >
> > Commit e20dfbad8aab ("net: fix napi_consume_skb() with alien skbs")
> > defers freeing of alien SKBs (alloc_cpu != current cpu) via
> > skb_attempt_defer_free() on the TX completion path to reduce cross-NUMA
> > SLUB spinlock contention to improve multi-queue UDP workloads.
> >
> > However, this unconditionally impacts the napi_skb_cache fast recycle
> > path for single-flow / few-flow workloads (e.g. AF_XDP benchmarks[1]):
> > when the TX completion NAPI CPU differs from the SKB allocation CPU,
> > SKBs are deferred instead of being returned to the local napi_skb_cache,
> > forcing RX allocations back to the slow slab path.
> >
> > The existing net.core.skb_defer_max=0 could disable this, but it is a
> > global switch that also disables the defer mechanism in TCP/UDP/MPTCP
> > recvmsg paths, losing its positive SLUB locality benefits there. AF_XDP
> > can co-exist with other protocols. That's the reason why I gave up
> > reusing skb_defer_disable_key. Besides, if the defer path is disabled,
> > that means TCP/UDP/MPTCP in process path will trigger directly freeing
> > skb with enabling/disabling bottom half(in kfree_skb_napi_cache())
> > which could affect others. So my thinking is not to touch this path.
> >
> > Add a dedicated sysctl net.core.napi_consume_skb_defer backed by a
> > static key to selectively control the alien skb defer feature. Let
> > users decide which is the best fit for their own requirements.
> >
> > This patch also avoids touching local_bh* pair(in
> > kfree_skb_napi_cache())
> > to minimize the overhead.
> >
> > [1]: taskset -c 0 ./xdpsock -i enp2s0f1 -q 1 -t -S -s 64
> > 1) sysctl -w net.core.napi_consume_skb_defer=1 (as default)
> > sock0@enp2s0f1:1 txonly xdp-skb
> > pps pkts 1.00
> > rx 0 0
> > tx 1,851,950 20,397,952
> >
> > 2)sysctl -w net.core.napi_consume_skb_defer=0
> > sock0@enp2s0f1:1 txonly xdp-skb
> > pps pkts 1.00
> > rx 0 0
> > tx 1,985,067 25,530,432
> >
> > For AF_XDP scenario, it turns out to be around 6.6% improvement.
> >
> > Signed-off-by: Jason Xing <kerneljasonxing@gmail.com>
> > ---
> > net/core/net-sysfs.h | 1 +
> > net/core/skbuff.c | 5 ++++-
> > net/core/sysctl_net_core.c | 35 +++++++++++++++++++++++++++++++++++
> > 3 files changed, 40 insertions(+), 1 deletion(-)
> >
> > diff --git a/net/core/net-sysfs.h b/net/core/net-sysfs.h
> > index 38e2e3ffd0bd..a026f757867e 100644
> > --- a/net/core/net-sysfs.h
> > +++ b/net/core/net-sysfs.h
> > @@ -14,4 +14,5 @@ int netdev_change_owner(struct net_device *, const struct net *net_old,
> > extern struct mutex rps_default_mask_mutex;
> >
> > DECLARE_STATIC_KEY_FALSE(skb_defer_disable_key);
> > +DECLARE_STATIC_KEY_TRUE(napi_consume_skb_defer_key);
> > #endif
> > diff --git a/net/core/skbuff.c b/net/core/skbuff.c
> > index 3d6978dd0aa8..3db90a9aa61d 100644
> > --- a/net/core/skbuff.c
> > +++ b/net/core/skbuff.c
> > @@ -94,6 +94,7 @@
> >
> > #include "dev.h"
> > #include "devmem.h"
> > +#include "net-sysfs.h"
> > #include "netmem_priv.h"
> > #include "sock_destructor.h"
> >
> > @@ -1519,7 +1520,8 @@ void napi_consume_skb(struct sk_buff *skb, int budget)
> >
> > DEBUG_NET_WARN_ON_ONCE(!in_softirq());
> >
> > - if (skb->alloc_cpu != smp_processor_id() && !skb_shared(skb)) {
> > + if (static_branch_likely(&napi_consume_skb_defer_key) &&
> > + skb->alloc_cpu != smp_processor_id() && !skb_shared(skb)) {
> > skb_release_head_state(skb);
> > return skb_attempt_defer_free(skb);
> > }
> > @@ -7257,6 +7259,7 @@ static void kfree_skb_napi_cache(struct sk_buff *skb)
> > }
> >
> > DEFINE_STATIC_KEY_FALSE(skb_defer_disable_key);
> > +DEFINE_STATIC_KEY_TRUE(napi_consume_skb_defer_key);
> >
> > /**
> > * skb_attempt_defer_free - queue skb for remote freeing
> > diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
> > index b508618bfc12..33e8217ee1ce 100644
> > --- a/net/core/sysctl_net_core.c
> > +++ b/net/core/sysctl_net_core.c
> > @@ -372,6 +372,35 @@ static int proc_do_skb_defer_max(const struct ctl_table *table, int write,
> > return ret;
> > }
> >
> > +static int proc_do_napi_consume_skb_defer(const struct ctl_table *table,
> > + int write, void *buffer,
> > + size_t *lenp, loff_t *ppos)
> > +{
> > + static DEFINE_MUTEX(napi_consume_skb_defer_mutex);
> > + int val, ret;
> > +
> > + mutex_lock(&napi_consume_skb_defer_mutex);
> > +
> > + val = static_key_enabled(&napi_consume_skb_defer_key);
> > + struct ctl_table tmp = {
> > + .data = &val,
> > + .maxlen = sizeof(val),
> > + .extra1 = SYSCTL_ZERO,
> > + .extra2 = SYSCTL_ONE,
> > + };
> > +
> > + ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
> > + if (!ret && write) {
> > + if (val)
> > + static_branch_enable(&napi_consume_skb_defer_key);
> > + else
> > + static_branch_disable(&napi_consume_skb_defer_key);
> > + }
> > +
> > + mutex_unlock(&napi_consume_skb_defer_mutex);
> > + return ret;
> > +}
> > +
>
> Seems a copy/paste of proc_do_static_key() ?
Thanks, Eric. Much simpler right now:
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index b508618bfc12..a6a1b2c3f8e1 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -676,6 +676,16 @@ static struct ctl_table net_core_table[] = {
.proc_handler = proc_do_skb_defer_max,
.extra1 = SYSCTL_ZERO,
},
+ {
+ .procname = "napi_consume_skb_defer",
+ .data = &napi_consume_skb_defer_key.key,
+ .maxlen = sizeof(napi_consume_skb_defer_key),
+ .mode = 0644,
+ .proc_handler = proc_do_static_key,
+ },
};
I will post it then after more tests tomorrow morning :)
Thanks,
Jason
^ permalink raw reply related
* Re: [PATCH net-next v4 1/2] net: stmmac: provide flag to disable EEE
From: Laurent Pinchart @ 2026-03-26 15:53 UTC (permalink / raw)
To: netdev, imx
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Fabio Estevam,
Francesco Dolcini, Frank Li, Jakub Kicinski, Joy Zou,
Kieran Bingham, Marco Felsch, Paolo Abeni,
Pengutronix Kernel Team, Russell King (Oracle), Stefan Klug,
linux-arm-kernel
In-Reply-To: <20260325210003.2752013-2-laurent.pinchart@ideasonboard.com>
On Wed, Mar 25, 2026 at 11:00:02PM +0200, Laurent Pinchart wrote:
> From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
>
> Some platforms have problems when EEE is enabled, and thus need a way
> to disable stmmac EEE support. Add a flag before the other LPI related
> flags which tells stmmac to avoid populating the phylink LPI
> capabilities, which causes phylink to call phy_disable_eee() for any
> PHY that is attached to the affected phylink instance.
>
> iMX8MP is an example - the lpi_intr_o signal is wired to an OR gate
> along with the main dwmac interrupts. Since lpi_intr_o is synchronous
> to the receive clock domain, and takes four clock cycles to clear, this
> leads to interrupt storms as the interrupt remains asserted for some
> time after the LPI control and status register is read.
>
> This problem becomes worse when the receive clock from the PHY stops
> when the receive path enters LPI state - which means that lpi_intr_o
> can not deassert until the clock restarts. Since the LPI state of the
> receive path depends on the link partner, this is out of our control.
> We could disable RX clock stop at the PHY, but that doesn't get around
> the slow-to-deassert lpi_intr_o mentioned in the above paragraph.
>
> Previously, iMX8MP worked around this by disabling gigabit EEE, but
> this is insufficient - the problem is also visible at 100M speeds,
> where the receive clock is slower.
>
> There is extensive discussion and investigation in the thread linked
> below, the result of which is summarised in this commit message.
>
> Reported-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Closes: https://lore.kernel.org/r/20251026122905.29028-1-laurent.pinchart@ideasonboard.com
> Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
> Tested-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>
And I just realized I haven't sent an R-b tag, despite having reviewed
the patch.
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
> drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 7 ++++++-
> include/linux/stmmac.h | 13 +++++++------
> 2 files changed, 13 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 9b6b49331639..ce51b9c22129 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -1438,7 +1438,12 @@ static int stmmac_phylink_setup(struct stmmac_priv *priv)
> config->supported_interfaces,
> pcs->supported_interfaces);
>
> - if (priv->dma_cap.eee) {
> + /* Some platforms, e.g. iMX8MP, wire lpi_intr_o to the same interrupt
> + * used for stmmac's main interrupts, which leads to interrupt storms.
> + * STMMAC_FLAG_EEE_DISABLE allows EEE to be disabled on such platforms.
> + */
> + if (priv->dma_cap.eee &&
> + !(priv->plat->flags & STMMAC_FLAG_EEE_DISABLE)) {
> /* The GMAC 3.74a databook states that EEE is only supported
> * in MII, GMII, and RGMII interfaces.
> */
> diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
> index 5b2bece81448..e62d21afd56d 100644
> --- a/include/linux/stmmac.h
> +++ b/include/linux/stmmac.h
> @@ -207,12 +207,13 @@ enum dwmac_core_type {
> #define STMMAC_FLAG_MULTI_MSI_EN BIT(7)
> #define STMMAC_FLAG_EXT_SNAPSHOT_EN BIT(8)
> #define STMMAC_FLAG_INT_SNAPSHOT_EN BIT(9)
> -#define STMMAC_FLAG_RX_CLK_RUNS_IN_LPI BIT(10)
> -#define STMMAC_FLAG_EN_TX_LPI_CLOCKGATING BIT(11)
> -#define STMMAC_FLAG_EN_TX_LPI_CLK_PHY_CAP BIT(12)
> -#define STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY BIT(13)
> -#define STMMAC_FLAG_KEEP_PREAMBLE_BEFORE_SFD BIT(14)
> -#define STMMAC_FLAG_SERDES_SUPPORTS_2500M BIT(15)
> +#define STMMAC_FLAG_EEE_DISABLE BIT(10)
> +#define STMMAC_FLAG_RX_CLK_RUNS_IN_LPI BIT(11)
> +#define STMMAC_FLAG_EN_TX_LPI_CLOCKGATING BIT(12)
> +#define STMMAC_FLAG_EN_TX_LPI_CLK_PHY_CAP BIT(13)
> +#define STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY BIT(14)
> +#define STMMAC_FLAG_KEEP_PREAMBLE_BEFORE_SFD BIT(15)
> +#define STMMAC_FLAG_SERDES_SUPPORTS_2500M BIT(16)
>
> struct mac_device_info;
>
--
Regards,
Laurent Pinchart
^ permalink raw reply
* [PATCH v2 net] ip6_tunnel: clear skb2->cb[] in ip4ip6_err()
From: Eric Dumazet @ 2026-03-26 15:51 UTC (permalink / raw)
To: David S . Miller, Jakub Kicinski, Paolo Abeni
Cc: Simon Horman, David Ahern, netdev, eric.dumazet, Eric Dumazet,
Oskar Kjos, Ido Schimmel
Oskar Kjos reported the following problem.
ip4ip6_err() calls icmp_send() on a cloned skb whose cb[] was written
by the IPv6 receive path as struct inet6_skb_parm. icmp_send() passes
IPCB(skb2) to __ip_options_echo(), which interprets that cb[] region
as struct inet_skb_parm (IPv4). The layouts differ: inet6_skb_parm.nhoff
at offset 14 overlaps inet_skb_parm.opt.rr, producing a non-zero rr
value. __ip_options_echo() then reads optlen from attacker-controlled
packet data at sptr[rr+1] and copies that many bytes into dopt->__data,
a fixed 40-byte stack buffer (IP_OPTIONS_DATA_FIXED_SIZE).
To fix this we clear skb2->cb[], as suggested by Oskar Kjos.
Also add minimal IPv4 header validation (version == 4, ihl >= 5).
Fixes: c4d3efafcc93 ("[IPV6] IP6TUNNEL: Add support to IPv4 over IPv6 tunnel.")
Reported-by: Oskar Kjos <oskar.kjos@hotmail.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Ido Schimmel <idosch@nvidia.com>
---
v2: dot not even try to take care of IP options.
net/ipv6/ip6_tunnel.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 4c29aa94e86eb9439458e4b23426bfda8b3b8922..0b53488a922900270903cc55840014436bd946f9 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -601,11 +601,16 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if (!skb2)
return 0;
+ /* Remove debris left by IPv6 stack. */
+ memset(IPCB(skb2), 0, sizeof(*IPCB(skb2)));
+
skb_dst_drop(skb2);
skb_pull(skb2, offset);
skb_reset_network_header(skb2);
eiph = ip_hdr(skb2);
+ if (eiph->version != 4 || eiph->ihl < 5)
+ goto out;
/* Try to guess incoming interface */
rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL, eiph->saddr,
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply related
* Re: [PATCH net-next 00/10] net: lan966x: add support for PCIe FDMA
From: Daniel Machon @ 2026-03-26 15:48 UTC (permalink / raw)
To: Herve Codina
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Horatiu Vultur, Steen Hegelund, UNGLinuxDriver,
Alexei Starovoitov, Daniel Borkmann, Jesper Dangaard Brouer,
John Fastabend, Stanislav Fomichev, Arnd Bergmann,
Greg Kroah-Hartman, netdev, linux-kernel, bpf
In-Reply-To: <20260324090752.0799acb1@bootlin.com>
Hi Hervé,
> Hi Daniel,
>
> On Mon, 23 Mar 2026 20:40:59 +0100
> Daniel Machon <daniel.machon@microchip.com> wrote:
>
> > Hi Hervé,
> >
> > > Hi Daniel,
> > >
> > > On Mon, 23 Mar 2026 15:52:04 +0100
> > > Herve Codina <herve.codina@bootlin.com> wrote:
> > >
> > > > Hi Daniel,
> > > >
> > > > On Fri, 20 Mar 2026 16:00:56 +0100
> > > > Daniel Machon <daniel.machon@microchip.com> wrote:
> > > >
> > > > > When lan966x operates as a PCIe endpoint, the driver currently uses
> > > > > register-based I/O for frame injection and extraction. This approach is
> > > > > functional but slow, topping out at around 33 Mbps on an Intel x86 host
> > > > > with a lan966x PCIe card.
> > > > >
> > > > > This series adds FDMA (Frame DMA) support for the PCIe path. When
> > > > > operating as a PCIe endpoint, the internal FDMA engine on lan966x cannot
> > > > > directly access host memory, so DMA buffers are allocated as contiguous
> > > > > coherent memory and mapped through the PCIe Address Translation Unit
> > > > > (ATU). The ATU provides outbound windows that translate internal FDMA
> > > > > addresses to PCIe bus addresses, allowing the FDMA engine to read and
> > > > > write host memory. Because the ATU requires contiguous address regions,
> > > > > page_pool and normal per-page DMA mappings cannot be used. Instead,
> > > > > frames are transferred using memcpy between the ATU-mapped buffers and
> > > > > the network stack. With this, throughput increases from ~33 Mbps to ~620
> > > > > Mbps for default MTU.
> > > > >
> > > > > Patches 1-2 prepare the shared FDMA library: patch 1 renames the
> > > > > contiguous dataptr helpers for clarity, and patch 2 adds PCIe ATU region
> > > > > management and coherent DMA allocation with ATU mapping.
> > > > >
> > > > > Patches 3-5 refactor the lan966x FDMA code to support both platform and
> > > > > PCIe paths: extracting the LLP register write into a helper, exporting
> > > > > shared functions, and introducing an ops dispatch table selected at
> > > > > probe time.
> > > > >
> > > > > Patch 6 adds the core PCIe FDMA implementation with RX/TX using
> > > > > contiguous ATU-mapped buffers. Patches 7 and 8 extend it with MTU
> > > > > change and XDP support respectively.
> > > > >
> > > > > Patches 9-10 update the lan966x PCI device tree overlay to extend the
> > > > > cpu register mapping to cover the ATU register space and add the FDMA
> > > > > interrupt.
> > > > >
> > > >
> > > > Thanks a lot for the series taking care of DMA and ATU in PCIe variants.
> > > >
> > > > I have tested the whole series on both my ARM and x86 systems.
> > > >
> > > > Doing a simple wget on my x86 system, I moved from 3.8MB/s to 11.2MB/s and
> > > > so the improvement is obvious.
> > > >
> > > > Tested-by: Herve Codina <herve.codina@bootlin.com>
> > > >
> > >
> > > Hum, I think I found an issue.
> > >
> > > If I remove the lan966x_pci module (modprobe -r lan966x_pci), and reload
> > > it (modprobe lan966x_pci), the board is not working.
> > >
> > > The system performs DHCP requests. Those requests are served by my PC (observed
> > > with Wireshark) but the system doesn't see those answers. Indeed, he continues
> > > to perform DHCP requests.
> > >
> > > Looks like the lan966x_pci module removal leaves the board in a bad state.
> > >
> > > Without the series applied, DHCP request answers from my PC are seen by the
> > > system after any module unloading / reloading.
> > >
> > > Do you have any ideas of what could be wrong?
> > >
> > > Best regards,
> > > Hervé
> >
> > Thanks for testing this!
> >
> > As part of my testing I did unload/load the lan966x_switch module to ensure the
> > ATU was properly reset and reconfigured, and that seemed to work fine. I must
> > admit, I did not try with the lan966x_pci module.
> >
> > From what I hear, when you are in the bad state, TX is still working, so it's an
> > RX issue. Could be the interrupt is not firing, so the napi poll is not
> > scheduled.
>
> Yes, confirmed that the issue is on Rx path. Tx data were received by my PC.
>
> >
> > Anyway, I will have a look at it during the week. Will let you know.
> >
>
> Some more interesting information.
>
> I tested lan966x_pci module unloading and re-loading on my ARM system.
>
> On this system the following traces are present when I reload the lan966x_pci
> module. Those traces were not present on my x86 system.
>
> [ 104.715031] ------------[ cut here ]------------
> [ 104.719746] Unexpected error: 64, error_type: 1073741824
> [ 104.725217] WARNING: drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c:558 at lan966x_fdma_irq_handler+0xe0/0x12c [lan966x_switch], CPU#0: swapper/0/0
> [ 104.739119] Modules linked in: lan966x_pci irq_lan966x_oic reset_microchip_sparx5 pinctrl_ocelot lan966x_serdes mdio_mscc_miim lan966x_switch rtc_ds1307 marvell [last unloaded: lan966x_pci]
> [ 104.756250] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 7.0.0-rc1-00010-gfa357f2a6a00 #565 PREEMPT
> [ 104.765743] Hardware name: Marvell Armada 3720 Development Board DB-88F3720-DDR3 (DT)
> [ 104.773579] pstate: 600000c5 (nZCv daIF -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
> [ 104.780551] pc : lan966x_fdma_irq_handler+0xe0/0x12c [lan966x_switch]
> [ 104.787046] lr : lan966x_fdma_irq_handler+0xe0/0x12c [lan966x_switch]
> [ 104.793538] sp : ffff800082a7bc00
> [ 104.796860] x29: ffff800082a7bc00 x28: ffff8000819abd00 x27: ffff800081a57757
> [ 104.804033] x26: ffff8000819a5d88 x25: 0000000000012400 x24: ffff800081a57758
> [ 104.811205] x23: 0000000000000038 x22: ffff00000f70ec00 x21: 0000000040000000
> [ 104.818376] x20: ffff00000f7a8080 x19: 0000000000000040 x18: 00000000ffffffff
> [ 104.825548] x17: ffff7fff9e7d6000 x16: ffff800082a78000 x15: ffff800102a7b837
> [ 104.832719] x14: 0000000000000000 x13: 0000000000000000 x12: 3031203a65707974
> [ 104.839891] x11: ffff8000819ca758 x10: 0000000000000018 x9 : ffff8000819ca758
> [ 104.847062] x8 : 00000000ffffefff x7 : ffff800081a22758 x6 : 00000000fffff000
> [ 104.854233] x5 : ffff00001fea1588 x4 : 0000000000000000 x3 : 0000000000000027
> [ 104.861404] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff8000819abd00
> [ 104.868576] Call trace:
> [ 104.871034] lan966x_fdma_irq_handler+0xe0/0x12c [lan966x_switch] (P)
> [ 104.877531] __handle_irq_event_percpu+0xa0/0x4c4
> [ 104.882261] handle_irq_event+0x4c/0xf8
> [ 104.886117] handle_level_irq+0xec/0x17c
> [ 104.890064] handle_irq_desc+0x40/0x58
> [ 104.893831] generic_handle_domain_irq+0x18/0x24
> [ 104.898467] lan966x_oic_irq_handler_domain+0x64/0xb0 [irq_lan966x_oic]
> [ 104.905105] lan966x_oic_irq_handler+0x34/0xb4 [irq_lan966x_oic]
> [ 104.911131] handle_irq_desc+0x40/0x58
> [ 104.914900] generic_handle_domain_irq+0x18/0x24
> [ 104.919536] pci_dev_irq_handler+0x1c/0x30 [lan966x_pci]
> [ 104.924871] __handle_irq_event_percpu+0xa0/0x4c4
> [ 104.929594] handle_irq_event+0x4c/0xf8
> [ 104.933449] handle_level_irq+0xec/0x17c
> [ 104.937394] handle_irq_desc+0x40/0x58
> [ 104.941162] generic_handle_domain_irq+0x18/0x24
> [ 104.945797] advk_pcie_irq_handler+0x160/0x390
> [ 104.950260] __handle_irq_event_percpu+0xa0/0x4c4
> [ 104.954983] handle_irq_event+0x4c/0xf8
> [ 104.958839] handle_fasteoi_irq+0x108/0x20c
> [ 104.963043] handle_irq_desc+0x40/0x58
> [ 104.966811] generic_handle_domain_irq+0x18/0x24
> [ 104.971447] gic_handle_irq+0x4c/0x110
> [ 104.975214] call_on_irq_stack+0x30/0x48
> [ 104.979156] do_interrupt_handler+0x80/0x84
> [ 104.983360] el1_interrupt+0x3c/0x60
> [ 104.986959] el1h_64_irq_handler+0x18/0x24
> [ 104.991076] el1h_64_irq+0x6c/0x70
> [ 104.994495] default_idle_call+0x80/0x138 (P)
> [ 104.998870] do_idle+0x220/0x290
> [ 105.002121] cpu_startup_entry+0x34/0x3c
> [ 105.006064] rest_init+0xf8/0x188
> [ 105.009398] start_kernel+0x818/0x8ec
> [ 105.013085] __primary_switched+0x88/0x90
> [ 105.017119] irq event stamp: 60740
> [ 105.020529] hardirqs last enabled at (60739): [<ffff800080fb37bc>] default_idle_call+0x7c/0x138
> [ 105.029328] hardirqs last disabled at (60740): [<ffff800080fab5c4>] enter_from_kernel_mode+0x10/0x3c
> [ 105.038477] softirqs last enabled at (60728): [<ffff8000800cb774>] handle_softirqs+0x624/0x63c
> [ 105.047193] softirqs last disabled at (60711): [<ffff8000800102d8>] __do_softirq+0x14/0x20
> [ 105.055471] ---[ end trace 0000000000000000 ]---
> [ 105.060274] ------------[ cut here ]------------
> [ 105.064963] Unexpected error: 64, error_type: 1073741824
> [ 105.070440] WARNING: drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c:558 at lan966x_fdma_irq_handler+0xe0/0x12c [lan966x_switch], CPU#0: swapper/0/0
> ...
> [ 105.443891] ------------[ cut here ]------------
> [ 105.448536] Unexpected error: 64, error_type: 0
> [ 105.453235] WARNING: drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c:558 at lan966x_fdma_irq_handler+0xe0/0x12c [lan966x_switch], CPU#0: swapper/0/0
> ...
>
> And after them my ARM system don't see the answer of a ping command
> replied by my PC (I don't use DHCP with my ARM system).
>
> I don't know why those traces are not present on my x86 (config, race
> condition, other reason) but anyway, they can help to find some clues
> about what's going on.
>
> Of course, feel free to ask me some more tests or anything else I can do
> to help on this topic.
>
> Best regards,
> Hervé
As I remembered, doing rmmod on the lan966x_switch followed by modprobe
lan966x_switch works fine. This is because neither the switch core, nor the FDMA
engine is reset, so they remain in sync.
When the lan966x_pci module is removed and reloaded (what you did), the DT
overlay is re-applied, which causes the reset controller
(reset-microchip-sparx5) to re-probe. During probe, it performs a GCB soft reset
that resets the switch core, but protects the CPU domain from the reset. The
FDMA engine is part of the CPU domain, so it is not reset.
This leaves the switch core in a reset state while the FDMA
retains state from the previous driver instance. When the switch driver
subsequently probes and activates the FDMA channels, the two are out of
sync, and the FDMA immediately reports extraction errors.
Theres actually an FDMA register called NRESET that resets the FDMA controller
state. Calling this in the FDMA init path causes traffic to work correctly on
lan966x_pci reload, but it does not get rid of the FDMA splats you posted above.
They get queued up between the switch core reset, in the reset controller, and
the FDMA enabling. I tried different approaches to drain or flush queues, but
they wont go away entirely.
The only thing that seems to work consistently is to *not* do the soft reset in
the reset controller for the PCI path. The soft reset is actually the problem:
it only resets the switch core while protecting the CPU domain (including FDMA),
causing a desync.
A simple fix could be (in reset-microchip-sparx5.c):
+static bool mchp_reset_is_pci(struct device *dev)
+{
+ for (dev = dev->parent; dev; dev = dev->parent) {
+ if (dev_is_pci(dev))
+ return true;
+ }
+ return false;
+}
- /* Issue the reset very early, our actual reset callback is a noop. */
- err = sparx5_switch_reset(ctx);
- if (err)
- return err;
+ /* Issue the reset very early, our actual reset callback is a noop.
+ *
+ * On the PCI path, skip the reset. The endpoint is already in
+ * power-on reset state on the first probe. On subsequent probes
+ * (after driver reload), resetting the switch core while the FDMA
+ * retains state (CPU domain is protected from the soft reset)
+ * causes the two to go out of sync, leading to FDMA extraction
+ * errors.
+ */
+ if (!mchp_reset_is_pci(&pdev->dev)) {
+ err = sparx5_switch_reset(ctx);
+ if (err)
+ return err;
+ }
Could you test it and see if it helps the problem on your side.
/Daniel
^ permalink raw reply
* [PATCH net-next v2 4/4] net: hsr: reject unresolved interlink ifindex
From: luka.gejak @ 2026-03-26 15:47 UTC (permalink / raw)
To: davem, edumazet, kuba, pabeni, netdev
Cc: horms, fmaurer, liuhangbin, linux-kernel, luka.gejak
In-Reply-To: <20260326154715.38405-1-luka.gejak@linux.dev>
From: Luka Gejak <luka.gejak@linux.dev>
In hsr_newlink(), a provided but invalid IFLA_HSR_INTERLINK attribute
was silently ignored if __dev_get_by_index() returned NULL. This leads
to incorrect RedBox topology creation without notifying the user.
Fix this by returning -EINVAL and an extack message when the
interlink attribute is present but cannot be resolved.
Reviewed-by: Felix Maurer <fmaurer@redhat.com>
Signed-off-by: Luka Gejak <luka.gejak@linux.dev>
---
net/hsr/hsr_netlink.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c
index db0b0af7a692..f0ca23da3ab9 100644
--- a/net/hsr/hsr_netlink.c
+++ b/net/hsr/hsr_netlink.c
@@ -76,9 +76,14 @@ static int hsr_newlink(struct net_device *dev,
return -EINVAL;
}
- if (data[IFLA_HSR_INTERLINK])
+ if (data[IFLA_HSR_INTERLINK]) {
interlink = __dev_get_by_index(link_net,
nla_get_u32(data[IFLA_HSR_INTERLINK]));
+ if (!interlink) {
+ NL_SET_ERR_MSG_MOD(extack, "Interlink does not exist");
+ return -EINVAL;
+ }
+ }
if (interlink && interlink == link[0]) {
NL_SET_ERR_MSG_MOD(extack, "Interlink and Slave1 are the same");
--
2.53.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox