get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/2219418/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2219418,
    "url": "http://patchwork.ozlabs.org/api/patches/2219418/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20260402230626.3826719-9-grzegorz.nitka@intel.com/",
    "project": {
        "id": 46,
        "url": "http://patchwork.ozlabs.org/api/projects/46/?format=api",
        "name": "Intel Wired Ethernet development",
        "link_name": "intel-wired-lan",
        "list_id": "intel-wired-lan.osuosl.org",
        "list_email": "intel-wired-lan@osuosl.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20260402230626.3826719-9-grzegorz.nitka@intel.com>",
    "list_archive_url": null,
    "date": "2026-04-02T23:06:26",
    "name": "[v5,net-next,8/8] ice: implement E825 TX ref clock control and TXC hardware sync status",
    "commit_ref": null,
    "pull_url": null,
    "state": "handled-elsewhere",
    "archived": false,
    "hash": "fec0a165cf233e8cf4bbfa145af69296067aba0a",
    "submitter": {
        "id": 82711,
        "url": "http://patchwork.ozlabs.org/api/people/82711/?format=api",
        "name": "Grzegorz Nitka",
        "email": "grzegorz.nitka@intel.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20260402230626.3826719-9-grzegorz.nitka@intel.com/mbox/",
    "series": [
        {
            "id": 498564,
            "url": "http://patchwork.ozlabs.org/api/series/498564/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/list/?series=498564",
            "date": "2026-04-02T23:06:18",
            "name": "dpll/ice: Add TXC DPLL type and full TX reference clock control for E825",
            "version": 5,
            "mbox": "http://patchwork.ozlabs.org/series/498564/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2219418/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2219418/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<intel-wired-lan-bounces@osuosl.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "intel-wired-lan@lists.osuosl.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@legolas.ozlabs.org",
            "intel-wired-lan@lists.osuosl.org"
        ],
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=osuosl.org header.i=@osuosl.org header.a=rsa-sha256\n header.s=default header.b=u+kC49cj;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=osuosl.org\n (client-ip=140.211.166.137; helo=smtp4.osuosl.org;\n envelope-from=intel-wired-lan-bounces@osuosl.org;\n receiver=patchwork.ozlabs.org)"
        ],
        "Received": [
            "from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fmyJw3kDYz1yCs\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 03 Apr 2026 10:11:12 +1100 (AEDT)",
            "from localhost (localhost [127.0.0.1])\n\tby smtp4.osuosl.org (Postfix) with ESMTP id 9EFDA403EB;\n\tThu,  2 Apr 2026 23:11:10 +0000 (UTC)",
            "from smtp4.osuosl.org ([127.0.0.1])\n by localhost (smtp4.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id tp4H6xW0ibo3; Thu,  2 Apr 2026 23:11:09 +0000 (UTC)",
            "from lists1.osuosl.org (lists1.osuosl.org [140.211.166.142])\n\tby smtp4.osuosl.org (Postfix) with ESMTP id 35129406A7;\n\tThu,  2 Apr 2026 23:11:09 +0000 (UTC)",
            "from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138])\n by lists1.osuosl.org (Postfix) with ESMTP id 8B8FC2CC\n for <intel-wired-lan@lists.osuosl.org>; Thu,  2 Apr 2026 23:11:07 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n by smtp1.osuosl.org (Postfix) with ESMTP id 7119D812DB\n for <intel-wired-lan@lists.osuosl.org>; Thu,  2 Apr 2026 23:11:07 +0000 (UTC)",
            "from smtp1.osuosl.org ([127.0.0.1])\n by localhost (smtp1.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id JwwPofldfOxy for <intel-wired-lan@lists.osuosl.org>;\n Thu,  2 Apr 2026 23:11:06 +0000 (UTC)",
            "from mgamail.intel.com (mgamail.intel.com [198.175.65.19])\n by smtp1.osuosl.org (Postfix) with ESMTPS id D2C12812C7\n for <intel-wired-lan@lists.osuosl.org>; Thu,  2 Apr 2026 23:11:05 +0000 (UTC)",
            "from orviesa008.jf.intel.com ([10.64.159.148])\n by orvoesa111.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 02 Apr 2026 16:11:05 -0700",
            "from gklab-003-001.igk.intel.com ([10.91.173.48])\n by orviesa008.jf.intel.com with ESMTP; 02 Apr 2026 16:11:01 -0700"
        ],
        "X-Virus-Scanned": [
            "amavis at osuosl.org",
            "amavis at osuosl.org"
        ],
        "X-Comment": "SPF check N/A for local connections - client-ip=140.211.166.142;\n helo=lists1.osuosl.org; envelope-from=intel-wired-lan-bounces@osuosl.org;\n receiver=<UNKNOWN> ",
        "DKIM-Filter": [
            "OpenDKIM Filter v2.11.0 smtp4.osuosl.org 35129406A7",
            "OpenDKIM Filter v2.11.0 smtp1.osuosl.org D2C12812C7"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=osuosl.org;\n\ts=default; t=1775171469;\n\tbh=YXhvr+Wj/T32z6XAJ9LY4Pw8enaozjr2o5DQgt3yWnA=;\n\th=From:To:Date:In-Reply-To:References:Subject:List-Id:\n\t List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe:\n\t Cc:From;\n\tb=u+kC49cjLZbZJOQVN1u6onXDZwB185teN32Xe11+9Al9TMYLXQQR4cxJ0JTTuP+ws\n\t GSM/fD6fPmrTsHkSRovTsFp1don+CSuLqQzkoJuZpW17JBab4zvCSVoNDWPebMIUQl\n\t aR06jqkN3KuovzYjlXYYKb47dwLUqUzKhsuQ2xa6i/WUORV16FZ9FZq8WgDm+KwBnt\n\t MAqan6rWGYbdwgsaNnaaGkfdIN10ADyMqexUeN5XpNZtH0I7QgDMUZMlrtjwMeIWBW\n\t LJYNofOSAZDpwEmT3k06NmIlG3JbYHcAiXYvT2NXzXbyzqrzl0/0mnJ13mT+GPHGl/\n\t 9Hy1oLZ+c8vKQ==",
        "Received-SPF": "Pass (mailfrom) identity=mailfrom; client-ip=198.175.65.19;\n helo=mgamail.intel.com; envelope-from=grzegorz.nitka@intel.com;\n receiver=<UNKNOWN>",
        "DMARC-Filter": "OpenDMARC Filter v1.4.2 smtp1.osuosl.org D2C12812C7",
        "X-CSE-ConnectionGUID": [
            "KERiILtvTIKdis8aGXUC2w==",
            "jzg9aZgoQMCdszq0K4VvJQ=="
        ],
        "X-CSE-MsgGUID": [
            "58keA0KHSFKzLsI56gnyJw==",
            "+eLAz76ASJ62DhDKQy/biw=="
        ],
        "X-IronPort-AV": [
            "E=McAfee;i=\"6800,10657,11747\"; a=\"76123154\"",
            "E=Sophos;i=\"6.23,156,1770624000\"; d=\"scan'208\";a=\"76123154\"",
            "E=Sophos;i=\"6.23,156,1770624000\"; d=\"scan'208\";a=\"227044489\""
        ],
        "X-ExtLoop1": "1",
        "From": "Grzegorz Nitka <grzegorz.nitka@intel.com>",
        "To": "netdev@vger.kernel.org",
        "Date": "Fri,  3 Apr 2026 01:06:26 +0200",
        "Message-Id": "<20260402230626.3826719-9-grzegorz.nitka@intel.com>",
        "X-Mailer": "git-send-email 2.39.3",
        "In-Reply-To": "<20260402230626.3826719-1-grzegorz.nitka@intel.com>",
        "References": "<20260402230626.3826719-1-grzegorz.nitka@intel.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=UTF-8",
        "Content-Transfer-Encoding": "8bit",
        "X-Mailman-Original-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple;\n d=intel.com; i=@intel.com; q=dns/txt; s=Intel;\n t=1775171466; x=1806707466;\n h=from:to:cc:subject:date:message-id:in-reply-to:\n references:mime-version:content-transfer-encoding;\n bh=eJKt+MDJnq/FIC45XW0Oqu/uaqkmngm7foO+FbPFcfY=;\n b=YfaJaaGrWdbedMOJRCFgSeELwGMJt08+LmSa8Tgh7zYXmFLpAjWhZ+TH\n ursLD5XRrdL2HQNjY4Z+Vs4YNS1O5tYMiG61eBILtxjZSfp4qmBk34DQs\n e0yoBQJ665T45iuXNV2l8P7ElG8F0C5simiNUFdJ6HCzuZWIcDfJ2wiPw\n pJhj54KkS4E4qtweRkACJQzjY+JfyB4wVf5pDl4JczjxqwVwJQMD/QTyf\n zOw//Q9SveIupUrsbLmFJYBJiM04sybsgO2exb7WfYs2clJcIQM8Qiz41\n wCi6cSWNkC52gC6+AXJA9Y7ej0T1Wy8R62ZIvxcCTUwVjVGVhIVR1CEtJ\n Q==;",
        "X-Mailman-Original-Authentication-Results": [
            "smtp1.osuosl.org;\n dmarc=pass (p=none dis=none)\n header.from=intel.com",
            "smtp1.osuosl.org;\n dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com\n header.a=rsa-sha256 header.s=Intel header.b=YfaJaaGr"
        ],
        "Subject": "[Intel-wired-lan] [PATCH v5 net-next 8/8] ice: implement E825 TX\n ref clock control and TXC hardware sync status",
        "X-BeenThere": "intel-wired-lan@osuosl.org",
        "X-Mailman-Version": "2.1.30",
        "Precedence": "list",
        "List-Id": "Intel Wired Ethernet Linux Kernel Driver Development\n <intel-wired-lan.osuosl.org>",
        "List-Unsubscribe": "<https://lists.osuosl.org/mailman/options/intel-wired-lan>,\n <mailto:intel-wired-lan-request@osuosl.org?subject=unsubscribe>",
        "List-Archive": "<http://lists.osuosl.org/pipermail/intel-wired-lan/>",
        "List-Post": "<mailto:intel-wired-lan@osuosl.org>",
        "List-Help": "<mailto:intel-wired-lan-request@osuosl.org?subject=help>",
        "List-Subscribe": "<https://lists.osuosl.org/mailman/listinfo/intel-wired-lan>,\n <mailto:intel-wired-lan-request@osuosl.org?subject=subscribe>",
        "Cc": "ivecera@redhat.com, vadim.fedorenko@linux.dev, kuba@kernel.org,\n jiri@resnulli.us, edumazet@google.com, przemyslaw.kitszel@intel.com,\n richardcochran@gmail.com, donald.hunter@gmail.com,\n linux-kernel@vger.kernel.org, arkadiusz.kubalewski@intel.com,\n andrew+netdev@lunn.ch, intel-wired-lan@lists.osuosl.org, horms@kernel.org,\n Prathosh.Satish@microchip.com, anthony.l.nguyen@intel.com, pabeni@redhat.com,\n davem@davemloft.net",
        "Errors-To": "intel-wired-lan-bounces@osuosl.org",
        "Sender": "\"Intel-wired-lan\" <intel-wired-lan-bounces@osuosl.org>"
    },
    "content": "Build on the previously introduced TXC DPLL framework and implement\nfull TX reference clock control and hardware-backed synchronization\nstatus reporting for E825 devices.\n\nE825 firmware may accept or override TX reference clock requests based\non device-wide routing constraints and link conditions. For this\nreason, TX reference selection and synchronization status must be\nobserved from hardware rather than inferred from user intent.\n\nThis change implements TX reference switching using a deferred worker,\ntriggered by DPLL TXCLK pin operations. Pin set callbacks express\nselection intent and schedule the operation asynchronously; firmware\ncommands and autonegotiation restarts are executed outside of DPLL\ncontext.\n\nAfter link-up, the effective TX reference clock is read back from\nhardware and software state is reconciled accordingly. TXCLK pin state\nreflects only the selected reference clock topology:\n- External references (SYNCE, EREF0) are represented as TXCLK pins\n- The internal ENET/TXCO clock has no pin representation; when selected,\n  all TXCLK pins are reported DISCONNECTED\n\nActual hardware synchronization result is reported exclusively via the\nTXC DPLL lock status:\n- LOCKED when an external TX reference is in use\n- UNLOCKED when falling back to ENET/TXCO\n\nThis separation allows userspace to distinguish between TX reference\nselection and successful synchronization, matching the DPLL subsystem\nmodel where pin state describes topology and device lock status\ndescribes signal quality.\n\nThe implementation also tracks TX reference usage per PHY across all\nPFs to ensure shared TX clock resources are not disabled while still in\nuse by peer ports.\n\nWith this change, TX reference clocks on E825 devices can be reliably\nselected, verified against hardware state, and monitored for effective\nsynchronization via standard DPLL interfaces.\n\nReviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>\nSigned-off-by: Grzegorz Nitka <grzegorz.nitka@intel.com>\n---\n drivers/net/ethernet/intel/ice/Makefile     |   2 +-\n drivers/net/ethernet/intel/ice/ice.h        |  12 +\n drivers/net/ethernet/intel/ice/ice_dpll.c   | 110 +++++++--\n drivers/net/ethernet/intel/ice/ice_dpll.h   |   4 +\n drivers/net/ethernet/intel/ice/ice_ptp.c    |  26 ++-\n drivers/net/ethernet/intel/ice/ice_ptp.h    |   7 +\n drivers/net/ethernet/intel/ice/ice_ptp_hw.c |  37 +++\n drivers/net/ethernet/intel/ice/ice_ptp_hw.h |  27 +++\n drivers/net/ethernet/intel/ice/ice_txclk.c  | 241 ++++++++++++++++++++\n drivers/net/ethernet/intel/ice/ice_txclk.h  |  38 +++\n 10 files changed, 485 insertions(+), 19 deletions(-)\n create mode 100644 drivers/net/ethernet/intel/ice/ice_txclk.c\n create mode 100644 drivers/net/ethernet/intel/ice/ice_txclk.h",
    "diff": "diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile\nindex 38db476ab2ec..95fd0c49800f 100644\n--- a/drivers/net/ethernet/intel/ice/Makefile\n+++ b/drivers/net/ethernet/intel/ice/Makefile\n@@ -54,7 +54,7 @@ ice-$(CONFIG_PCI_IOV) +=\t\\\n \tice_vf_mbx.o\t\t\\\n \tice_vf_vsi_vlan_ops.o\t\\\n \tice_vf_lib.o\n-ice-$(CONFIG_PTP_1588_CLOCK) += ice_ptp.o ice_ptp_hw.o ice_dpll.o ice_tspll.o ice_cpi.o\n+ice-$(CONFIG_PTP_1588_CLOCK) += ice_ptp.o ice_ptp_hw.o ice_dpll.o ice_tspll.o ice_cpi.o ice_txclk.o\n ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o\n ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o\n ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o\ndiff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h\nindex eb3a48330cc1..6edafce4624a 100644\n--- a/drivers/net/ethernet/intel/ice/ice.h\n+++ b/drivers/net/ethernet/intel/ice/ice.h\n@@ -1155,4 +1155,16 @@ static inline struct ice_hw *ice_get_primary_hw(struct ice_pf *pf)\n \telse\n \t\treturn &pf->adapter->ctrl_pf->hw;\n }\n+\n+/**\n+ * ice_get_ctrl_pf - Get pointer to Control PF of the adapter\n+ * @pf: pointer to the current PF structure\n+ *\n+ * Return: A pointer to ice_pf structure which is Control PF,\n+ * NULL if it's not initialized yet.\n+ */\n+static inline struct ice_pf *ice_get_ctrl_pf(struct ice_pf *pf)\n+{\n+\treturn !pf->adapter ? NULL : pf->adapter->ctrl_pf;\n+}\n #endif /* _ICE_H_ */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c\nindex ab62aac77399..201181ccd2ed 100644\n--- a/drivers/net/ethernet/intel/ice/ice_dpll.c\n+++ b/drivers/net/ethernet/intel/ice/ice_dpll.c\n@@ -4,6 +4,7 @@\n #include \"ice.h\"\n #include \"ice_lib.h\"\n #include \"ice_trace.h\"\n+#include \"ice_txclk.h\"\n #include <linux/dpll.h>\n #include <linux/property.h>\n \n@@ -19,8 +20,6 @@\n #define ICE_DPLL_SW_PIN_INPUT_BASE_QSFP\t\t6\n #define ICE_DPLL_SW_PIN_OUTPUT_BASE\t\t0\n \n-#define E825_EXT_EREF_PIN_IDX\t\t\t0\n-#define E825_EXT_SYNCE_PIN_IDX\t\t\t1\n #define E825_RCLK_PARENT_0_PIN_IDX\t\t0\n #define E825_RCLK_PARENT_1_PIN_IDX\t\t1\n \n@@ -2527,6 +2526,44 @@ ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, void *pin_priv,\n \treturn ret;\n }\n \n+/**\n+ * ice_dpll_txclk_work - apply a pending TX reference clock change\n+ * @work: work_struct embedded in struct ice_dplls\n+ *\n+ * This worker executes an outstanding TX reference clock switch request\n+ * that was previously queued via the DPLL TXCLK pin set callback.\n+ *\n+ * The worker performs only the operational part of the switch, issuing\n+ * the necessary firmware commands to request a new TX reference clock\n+ * selection (e.g. triggering an AN restart). It does not verify whether\n+ * the requested clock was ultimately accepted by the hardware.\n+ *\n+ * Hardware verification, software state reconciliation, pin state\n+ * notification, and TXC DPLL lock-status updates are performed later,\n+ * after link-up, by ice_txclk_update_and_notify().\n+ *\n+ * Context:\n+ *   - Runs in process context on pf->dplls.wq and may sleep.\n+ *   - Serializes access to shared TXCLK state using pf->dplls.lock.\n+ */\n+static void ice_dpll_txclk_work(struct work_struct *work)\n+{\n+\tstruct ice_dplls *dplls =\n+\t\tcontainer_of(work, struct ice_dplls, txclk_work);\n+\tstruct ice_pf *pf = container_of(dplls, struct ice_pf, dplls);\n+\tenum ice_e825c_ref_clk clk;\n+\tbool do_switch;\n+\n+\tmutex_lock(&pf->dplls.lock);\n+\tdo_switch  = pf->dplls.txclk_switch_requested;\n+\tclk = pf->ptp.port.tx_clk_req;\n+\tpf->dplls.txclk_switch_requested  = false;\n+\tmutex_unlock(&pf->dplls.lock);\n+\n+\tif (do_switch)\n+\t\tice_txclk_set_clk(pf, clk);\n+}\n+\n /**\n  * ice_dpll_txclk_state_on_dpll_set - set a state on TX clk pin\n  * @pin: pointer to a pin\n@@ -2538,7 +2575,9 @@ ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, void *pin_priv,\n  *\n  * Dpll subsystem callback, set a state of a Tx reference clock pin\n  *\n+ * Context: Acquires and releases pf->dplls.lock\n  * Return:\n+ * * 0 - success\n  * * negative - failure\n  */\n static int\n@@ -2547,11 +2586,29 @@ ice_dpll_txclk_state_on_dpll_set(const struct dpll_pin *pin, void *pin_priv,\n \t\t\t\t void *dpll_priv, enum dpll_pin_state state,\n \t\t\t\t struct netlink_ext_ack *extack)\n {\n-\t/*\n-\t * TODO: set HW accordingly to selected TX reference clock.\n-\t * To be added in the follow up patches.\n-\t */\n-\treturn -EOPNOTSUPP;\n+\tstruct ice_dpll_pin *p = pin_priv;\n+\tstruct ice_pf *pf = p->pf;\n+\tenum ice_e825c_ref_clk new_clk;\n+\n+\tif (ice_dpll_is_reset(pf, extack))\n+\t\treturn -EBUSY;\n+\n+\tmutex_lock(&pf->dplls.lock);\n+\tnew_clk = (state == DPLL_PIN_STATE_DISCONNECTED) ? ICE_REF_CLK_ENET :\n+\t\t\tp->tx_ref_src;\n+\tif (new_clk == pf->ptp.port.tx_clk) {\n+\t\tNL_SET_ERR_MSG_FMT(extack,\n+\t\t\t\t   \"pin:%u state:%u on parent device already set\",\n+\t\t\t\t   p->idx, state);\n+\t\tgoto unlock;\n+\t}\n+\n+\tpf->ptp.port.tx_clk_req = new_clk;\n+\tpf->dplls.txclk_switch_requested = true;\n+\tqueue_work(pf->dplls.wq, &pf->dplls.txclk_work);\n+unlock:\n+\tmutex_unlock(&pf->dplls.lock);\n+\treturn 0;\n }\n \n /**\n@@ -2563,10 +2620,21 @@ ice_dpll_txclk_state_on_dpll_set(const struct dpll_pin *pin, void *pin_priv,\n  * @state: on success holds pin state on parent pin\n  * @extack: error reporting\n  *\n- * dpll subsystem callback, get a state of a TX clock reference pin.\n+ * TXCLK DPLL pin state is derived and not stored explicitly.\n+ *\n+ * Only external TX reference clocks (SYNCE, EREF0) are modeled\n+ * as DPLL pins. The internal ENET (TXCO) clock has no pin and,\n+ * when selected, all TXCLK pins are reported DISCONNECTED.\n+ *\n+ * During a pending TXCLK switch, the requested pin may be\n+ * reported as CONNECTED before hardware verification.\n+ * Hardware acceptance and synchronization are reported\n+ * exclusively via TXC DPLL lock-status.\n  *\n+ * Context: Acquires and releases pf->dplls.lock\n  * Return:\n  * * 0 - success\n+ * * negative - failure\n  */\n static int\n ice_dpll_txclk_state_on_dpll_get(const struct dpll_pin *pin, void *pin_priv,\n@@ -2575,11 +2643,21 @@ ice_dpll_txclk_state_on_dpll_get(const struct dpll_pin *pin, void *pin_priv,\n \t\t\t\t enum dpll_pin_state *state,\n \t\t\t\t struct netlink_ext_ack *extack)\n {\n-\t/*\n-\t * TODO: query HW status to determine if the TX reference is selected.\n-\t * To be added in the follow up patches.\n-\t */\n-\t*state = DPLL_PIN_STATE_DISCONNECTED;\n+\tstruct ice_dpll_pin *p = pin_priv;\n+\tstruct ice_pf *pf = p->pf;\n+\n+\tif (ice_dpll_is_reset(pf, extack))\n+\t\treturn -EBUSY;\n+\n+\tmutex_lock(&pf->dplls.lock);\n+\tif (pf->ptp.port.tx_clk_req == p->tx_ref_src)\n+\t\t*state = DPLL_PIN_STATE_CONNECTED;\n+\telse if (pf->ptp.port.tx_clk == p->tx_ref_src &&\n+\t\t pf->ptp.port.tx_clk_req == pf->ptp.port.tx_clk)\n+\t\t*state = DPLL_PIN_STATE_CONNECTED;\n+\telse\n+\t\t*state = DPLL_PIN_STATE_DISCONNECTED;\n+\tmutex_unlock(&pf->dplls.lock);\n \n \treturn 0;\n }\n@@ -4402,6 +4480,8 @@ static int ice_dpll_init_info_e825c(struct ice_pf *pf)\n \tif (ret)\n \t\tgoto deinit_info;\n \n+\tINIT_WORK(&pf->dplls.txclk_work, ice_dpll_txclk_work);\n+\n \tdev_dbg(ice_pf_to_dev(pf),\n \t\t\"%s - success, inputs: %u, outputs: %u, rclk-parents: %u\\n\",\n \t\t __func__, d->num_inputs, d->num_outputs, d->rclk.num_parents);\n@@ -4538,6 +4618,10 @@ void ice_dpll_deinit(struct ice_pf *pf)\n \t\tice_dpll_deinit_dpll(pf, &pf->dplls.txc, false);\n \n \tice_dpll_deinit_info(pf);\n+\n+\tif (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825)\n+\t\tflush_work(&pf->dplls.txclk_work);\n+\n \tmutex_destroy(&pf->dplls.lock);\n }\n \ndiff --git a/drivers/net/ethernet/intel/ice/ice_dpll.h b/drivers/net/ethernet/intel/ice/ice_dpll.h\nindex 23f9d4da73c5..9a96b905141d 100644\n--- a/drivers/net/ethernet/intel/ice/ice_dpll.h\n+++ b/drivers/net/ethernet/intel/ice/ice_dpll.h\n@@ -8,6 +8,8 @@\n \n #define ICE_DPLL_RCLK_NUM_MAX\t4\n #define ICE_DPLL_TXCLK_NUM_MAX\t2\n+#define E825_EXT_EREF_PIN_IDX\t0\n+#define E825_EXT_SYNCE_PIN_IDX\t1\n \n /**\n  * enum ice_dpll_pin_sw - enumerate ice software pin indices:\n@@ -152,6 +154,8 @@ struct ice_dplls {\n \ts32 output_phase_adj_max;\n \tu32 periodic_counter;\n \tbool generic;\n+\tstruct work_struct txclk_work;\n+\tbool txclk_switch_requested;\n };\n \n #if IS_ENABLED(CONFIG_PTP_1588_CLOCK)\ndiff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c\nindex 094e96219f45..14c805ed2f09 100644\n--- a/drivers/net/ethernet/intel/ice/ice_ptp.c\n+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c\n@@ -4,6 +4,7 @@\n #include \"ice.h\"\n #include \"ice_lib.h\"\n #include \"ice_trace.h\"\n+#include \"ice_txclk.h\"\n \n static const char ice_pin_names[][64] = {\n \t\"SDP0\",\n@@ -54,11 +55,6 @@ static const struct ice_ptp_pin_desc ice_pin_desc_dpll[] = {\n \t{  SDP3, {  3, -1 }, { 0, 0 }},\n };\n \n-static struct ice_pf *ice_get_ctrl_pf(struct ice_pf *pf)\n-{\n-\treturn !pf->adapter ? NULL : pf->adapter->ctrl_pf;\n-}\n-\n static struct ice_ptp *ice_get_ctrl_ptp(struct ice_pf *pf)\n {\n \tstruct ice_pf *ctrl_pf = ice_get_ctrl_pf(pf);\n@@ -1326,6 +1322,9 @@ void ice_ptp_link_change(struct ice_pf *pf, bool linkup)\n \t\t\t}\n \t\t}\n \t\tmutex_unlock(&pf->dplls.lock);\n+\n+\t\tif (linkup)\n+\t\t\tice_txclk_update_and_notify(pf);\n \t}\n \n \tswitch (hw->mac_type) {\n@@ -3079,6 +3078,7 @@ static int ice_ptp_setup_pf(struct ice_pf *pf)\n {\n \tstruct ice_ptp *ctrl_ptp = ice_get_ctrl_ptp(pf);\n \tstruct ice_ptp *ptp = &pf->ptp;\n+\tu8 port_num, phy;\n \n \tif (WARN_ON(!ctrl_ptp) || pf->hw.mac_type == ICE_MAC_UNKNOWN)\n \t\treturn -ENODEV;\n@@ -3090,6 +3090,10 @@ static int ice_ptp_setup_pf(struct ice_pf *pf)\n \t\t &pf->adapter->ports.ports);\n \tmutex_unlock(&pf->adapter->ports.lock);\n \n+\tport_num = ptp->port.port_num;\n+\tphy = port_num / pf->hw.ptp.ports_per_phy;\n+\tset_bit(port_num, &ctrl_ptp->tx_refclks[phy][pf->ptp.port.tx_clk]);\n+\n \treturn 0;\n }\n \n@@ -3290,6 +3294,7 @@ static void ice_ptp_init_tx_interrupt_mode(struct ice_pf *pf)\n  */\n void ice_ptp_init(struct ice_pf *pf)\n {\n+\tenum ice_e825c_ref_clk tx_ref_clk;\n \tstruct ice_ptp *ptp = &pf->ptp;\n \tstruct ice_hw *hw = &pf->hw;\n \tint err;\n@@ -3318,6 +3323,17 @@ void ice_ptp_init(struct ice_pf *pf)\n \t\t\tgoto err_exit;\n \t}\n \n+\tptp->port.tx_clk = ICE_REF_CLK_ENET;\n+\tptp->port.tx_clk_req = ICE_REF_CLK_ENET;\n+\tif (hw->mac_type == ICE_MAC_GENERIC_3K_E825) {\n+\t\terr = ice_get_serdes_ref_sel_e825c(hw, ptp->port.port_num,\n+\t\t\t\t\t\t   &tx_ref_clk);\n+\t\tif (!err) {\n+\t\t\tptp->port.tx_clk = tx_ref_clk;\n+\t\t\tptp->port.tx_clk_req = tx_ref_clk;\n+\t\t}\n+\t}\n+\n \terr = ice_ptp_setup_pf(pf);\n \tif (err)\n \t\tgoto err_exit;\ndiff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h\nindex 8c44bd758a4f..8b385271ab36 100644\n--- a/drivers/net/ethernet/intel/ice/ice_ptp.h\n+++ b/drivers/net/ethernet/intel/ice/ice_ptp.h\n@@ -144,6 +144,8 @@ struct ice_ptp_tx {\n  * @link_up: indicates whether the link is up\n  * @tx_fifo_busy_cnt: number of times the Tx FIFO was busy\n  * @port_num: the port number this structure represents\n+ * @tx_clk: currently active Tx reference clock source\n+ * @tx_clk_req: requested Tx reference clock source (new target)\n  */\n struct ice_ptp_port {\n \tstruct list_head list_node;\n@@ -153,6 +155,8 @@ struct ice_ptp_port {\n \tbool link_up;\n \tu8 tx_fifo_busy_cnt;\n \tu8 port_num;\n+\tenum ice_e825c_ref_clk tx_clk;\n+\tenum ice_e825c_ref_clk tx_clk_req;\n };\n \n enum ice_ptp_tx_interrupt {\n@@ -236,6 +240,7 @@ struct ice_ptp_pin_desc {\n  * @info: structure defining PTP hardware capabilities\n  * @clock: pointer to registered PTP clock device\n  * @tstamp_config: hardware timestamping configuration\n+ * @tx_refclks: bitmaps table to store the information about TX reference clocks\n  * @reset_time: kernel time after clock stop on reset\n  * @tx_hwtstamp_good: number of completed Tx timestamp requests\n  * @tx_hwtstamp_skipped: number of Tx time stamp requests skipped\n@@ -261,6 +266,8 @@ struct ice_ptp {\n \tstruct ptp_clock_info info;\n \tstruct ptp_clock *clock;\n \tstruct kernel_hwtstamp_config tstamp_config;\n+#define ICE_E825_MAX_PHYS 2\n+\tunsigned long tx_refclks[ICE_E825_MAX_PHYS][ICE_REF_CLK_MAX];\n \tu64 reset_time;\n \tu64 tx_hwtstamp_good;\n \tu32 tx_hwtstamp_skipped;\ndiff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c\nindex 61c0a0d93ea8..c0720525ac49 100644\n--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c\n+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c\n@@ -461,6 +461,43 @@ static int ice_read_phy_eth56g(struct ice_hw *hw, u8 port, u32 addr, u32 *val)\n \treturn err;\n }\n \n+/**\n+ * ice_get_serdes_ref_sel_e825c - Read current Tx ref clock source\n+ * @hw: pointer to the HW struct\n+ * @port: port number for which Tx reference clock is read\n+ * @clk: Tx reference clock value (output)\n+ *\n+ * Return: 0 on success, other error codes when failed to read from PHY\n+ */\n+int ice_get_serdes_ref_sel_e825c(struct ice_hw *hw, u8 port,\n+\t\t\t\t enum ice_e825c_ref_clk *clk)\n+{\n+\tu8 lane = port % hw->ptp.ports_per_phy;\n+\tu32 serdes_rx_nt, serdes_tx_nt;\n+\tu32 val;\n+\tint ret;\n+\n+\tret = ice_read_phy_eth56g(hw, port,\n+\t\t\t\t  SERDES_IP_IF_LN_FLXM_GENERAL(lane, 0),\n+\t\t\t\t  &val);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tserdes_rx_nt = FIELD_GET(CFG_ICTL_PCS_REF_SEL_RX_NT, val);\n+\tserdes_tx_nt = FIELD_GET(CFG_ICTL_PCS_REF_SEL_TX_NT, val);\n+\n+\tif (serdes_tx_nt == REF_SEL_NT_SYNCE &&\n+\t    serdes_rx_nt == REF_SEL_NT_SYNCE)\n+\t\t*clk = ICE_REF_CLK_SYNCE;\n+\telse if (serdes_tx_nt == REF_SEL_NT_EREF0 &&\n+\t\t serdes_rx_nt == REF_SEL_NT_EREF0)\n+\t\t*clk = ICE_REF_CLK_EREF0;\n+\telse\n+\t\t*clk = ICE_REF_CLK_ENET;\n+\n+\treturn 0;\n+}\n+\n /**\n  * ice_phy_res_address_eth56g - Calculate a PHY port register address\n  * @hw: pointer to the HW struct\ndiff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h\nindex cbc9693179a1..820ba953ea01 100644\n--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h\n+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h\n@@ -381,6 +381,8 @@ int ice_stop_phy_timer_eth56g(struct ice_hw *hw, u8 port, bool soft_reset);\n int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port);\n int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold);\n int ice_phy_cfg_ptp_1step_eth56g(struct ice_hw *hw, u8 port);\n+int ice_get_serdes_ref_sel_e825c(struct ice_hw *hw, u8 port,\n+\t\t\t\t enum ice_e825c_ref_clk *clk);\n \n #define ICE_ETH56G_NOMINAL_INCVAL\t0x140000000ULL\n #define ICE_ETH56G_NOMINAL_PCS_REF_TUS\t0x100000000ULL\n@@ -790,4 +792,29 @@ static inline u64 ice_get_base_incval(struct ice_hw *hw)\n #define PHY_PTP_1STEP_PD_DELAY_M\tGENMASK(30, 1)\n #define PHY_PTP_1STEP_PD_DLY_V_M\tBIT(31)\n \n+#define SERDES_IP_IF_LN_FLXM_GENERAL(n, m) \\\n+\t(0x32B800 + (m) * 0x100000 + (n) * 0x8000)\n+#define CFG_RESERVED0_1                         GENMASK(1, 0)\n+#define CFG_ICTL_PCS_MODE_NT                    BIT(2)\n+#define CFG_ICTL_PCS_RCOMP_SLAVE_EN_NT          BIT(3)\n+#define CFG_ICTL_PCS_CMN_FORCE_PUP_A            BIT(4)\n+#define CFG_ICTL_PCS_RCOMP_SLAVE_VALID_A        BIT(5)\n+#define CFG_ICTL_PCS_REF_SEL_RX_NT              GENMASK(9, 6)\n+#define REF_SEL_NT_ENET                         0\n+#define REF_SEL_NT_EREF0                        1\n+#define REF_SEL_NT_SYNCE                        2\n+#define CFG_IDAT_DFX_OBS_DIG_                   GENMASK(11, 10)\n+#define CFG_IRST_APB_MEM_B                      BIT(12)\n+#define CFG_ICTL_PCS_DISCONNECT_NT              BIT(13)\n+#define CFG_ICTL_PCS_ISOLATE_NT                 BIT(14)\n+#define CFG_RESERVED15_15                       BIT(15)\n+#define CFG_IRST_PCS_TSTBUS_B_A                 BIT(16)\n+#define CFG_ICTL_PCS_REF_TERM_HIZ_EN_NT         BIT(17)\n+#define CFG_RESERVED18_19                       GENMASK(19, 18)\n+#define CFG_ICTL_PCS_SYNTHLCSLOW_FORCE_PUP_A    BIT(20)\n+#define CFG_ICTL_PCS_SYNTHLCFAST_FORCE_PUP_A    BIT(21)\n+#define CFG_RESERVED22_24                       GENMASK(24, 22)\n+#define CFG_ICTL_PCS_REF_SEL_TX_NT              GENMASK(28, 25)\n+#define CFG_RESERVED29_31                       GENMASK(31, 29)\n+\n #endif /* _ICE_PTP_HW_H_ */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_txclk.c b/drivers/net/ethernet/intel/ice/ice_txclk.c\nnew file mode 100644\nindex 000000000000..3a79e770f796\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ice/ice_txclk.c\n@@ -0,0 +1,241 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/* Copyright (C) 2026 Intel Corporation */\n+\n+#include \"ice.h\"\n+#include \"ice_cpi.h\"\n+#include \"ice_txclk.h\"\n+\n+#define ICE_PHY0\t0\n+#define ICE_PHY1\t1\n+\n+/**\n+ * ice_txclk_get_pin - map TX reference clock to its DPLL pin\n+ * @pf: pointer to the PF structure\n+ * @ref_clk: TX reference clock selection\n+ *\n+ * Return the DPLL pin corresponding to a given external TX reference\n+ * clock. Only external TX reference clocks (SYNCE and EREF0) are\n+ * represented as DPLL pins. The internal ENET (TXCO) clock has no\n+ * associated DPLL pin and therefore yields %NULL.\n+ *\n+ * This helper is used when emitting DPLL pin change notifications\n+ * after TX reference clock transitions have been verified.\n+ *\n+ * Return: Pointer to the corresponding struct dpll_pin, or %NULL if\n+ *         the TX reference clock has no DPLL pin representation.\n+ */\n+static struct dpll_pin *\n+ice_txclk_get_pin(struct ice_pf *pf, enum ice_e825c_ref_clk ref_clk)\n+{\n+\tswitch (ref_clk) {\n+\tcase ICE_REF_CLK_SYNCE:\n+\t\treturn pf->dplls.txclks[E825_EXT_SYNCE_PIN_IDX].pin;\n+\tcase ICE_REF_CLK_EREF0:\n+\t\treturn pf->dplls.txclks[E825_EXT_EREF_PIN_IDX].pin;\n+\tcase ICE_REF_CLK_ENET:\n+\tdefault:\n+\t\treturn NULL;\n+\t}\n+}\n+\n+/**\n+ * ice_txclk_enable_peer - Enable required TX reference clock on peer PHY\n+ * @pf: pointer to the PF structure\n+ * @clk: TX reference clock that must be enabled\n+ *\n+ * Some TX reference clocks on E825-class devices (SyncE and EREF0) must\n+ * be enabled on both PHY complexes to allow proper routing:\n+ *\n+ *   - SyncE must be enabled on both PHYs when used by PHY0\n+ *   - EREF0 must be enabled on both PHYs when used by PHY1\n+ *\n+ * If the requested clock is not yet enabled on the peer PHY, enable it.\n+ * ENET does not require duplication and is ignored.\n+ *\n+ * Return: 0 on success or negative error code on failure.\n+ */\n+static int ice_txclk_enable_peer(struct ice_pf *pf, enum ice_e825c_ref_clk clk)\n+{\n+\tstruct ice_pf *ctrl_pf = ice_get_ctrl_pf(pf);\n+\tu8 port_num, phy;\n+\tint err;\n+\n+\tif (clk == ICE_REF_CLK_ENET)\n+\t\treturn 0;\n+\n+\tif (IS_ERR_OR_NULL(ctrl_pf)) {\n+\t\tdev_err(ice_pf_to_dev(pf),\n+\t\t\t\"Can't enable tx-clk on peer: no controlling PF\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tport_num = pf->ptp.port.port_num;\n+\tphy = port_num / pf->hw.ptp.ports_per_phy;\n+\n+\tif ((clk == ICE_REF_CLK_SYNCE && phy == ICE_PHY0 &&\n+\t     !ice_txclk_any_port_uses(ctrl_pf, ICE_PHY1, clk)) ||\n+\t    (clk == ICE_REF_CLK_EREF0 && phy == ICE_PHY1 &&\n+\t     !ice_txclk_any_port_uses(ctrl_pf, ICE_PHY0, clk))) {\n+\t\tu8 peer_phy = phy ? ICE_PHY0 : ICE_PHY1;\n+\n+\t\terr = ice_cpi_ena_dis_clk_ref(&pf->hw, peer_phy, clk, true);\n+\t\tif (err) {\n+\t\t\tdev_err(ice_hw_to_dev(&pf->hw),\n+\t\t\t\t\"Failed to enable the %u TX clock for the %u PHY\\n\",\n+\t\t\t\tclk, peer_phy);\n+\t\t\treturn err;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+#define ICE_REFCLK_USER_TO_AQ_IDX(x) ((x) + 1)\n+\n+/**\n+ * ice_txclk_set_clk - Set Tx reference clock\n+ * @pf: pointer to pf structure\n+ * @clk: new Tx clock\n+ *\n+ * Return: 0 on success, negative value otherwise.\n+ */\n+int ice_txclk_set_clk(struct ice_pf *pf, enum ice_e825c_ref_clk clk)\n+{\n+\tstruct ice_pf *ctrl_pf = ice_get_ctrl_pf(pf);\n+\tstruct ice_port_info *port_info;\n+\tu8 port_num, phy;\n+\tint err;\n+\n+\tif (pf->ptp.port.tx_clk == clk)\n+\t\treturn 0;\n+\n+\tif (IS_ERR_OR_NULL(ctrl_pf)) {\n+\t\tdev_err(ice_pf_to_dev(pf),\n+\t\t\t\"Can't set tx-clk: no controlling PF\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tport_num = pf->ptp.port.port_num;\n+\tphy = port_num / pf->hw.ptp.ports_per_phy;\n+\tport_info = pf->hw.port_info;\n+\n+\t/* Check if the TX clk is enabled for this PHY, if not - enable it */\n+\tif (!ice_txclk_any_port_uses(ctrl_pf, phy, clk)) {\n+\t\terr = ice_cpi_ena_dis_clk_ref(&pf->hw, phy, clk, true);\n+\t\tif (err) {\n+\t\t\tdev_err(ice_pf_to_dev(pf), \"Failed to enable the %u TX clock for the %u PHY\\n\",\n+\t\t\t\tclk, phy);\n+\t\t\treturn err;\n+\t\t}\n+\t\terr = ice_txclk_enable_peer(pf, clk);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t}\n+\n+\t/* We are ready to switch to the new TX clk. */\n+\terr = ice_aq_set_link_restart_an(port_info, true, NULL,\n+\t\t\t\t\t ICE_REFCLK_USER_TO_AQ_IDX(clk));\n+\tif (err)\n+\t\tdev_err(ice_pf_to_dev(pf),\n+\t\t\t\"AN restart AQ command failed with err %d\\n\",\n+\t\t\terr);\n+\n+\treturn err;\n+}\n+\n+/**\n+ * ice_txclk_update_and_notify - Validate TX reference clock switching\n+ * @pf: pointer to PF structure\n+ *\n+ * After a link-up event, verify whether the previously requested TX reference\n+ * clock transition actually succeeded. The SERDES reference selector reflects\n+ * the effective hardware choice, which may differ from the requested clock\n+ * when Auto-Negotiation or firmware applies additional policy.\n+ *\n+ * If the hardware-selected clock differs from the requested one, update the\n+ * software state accordingly and stop further processing.\n+ *\n+ * When the switch is successful, update the per‑PHY usage bitmaps so that the\n+ * driver knows which reference clock is currently in use by this port.\n+ *\n+ * This function does not initiate a clock switch; it only validates the result\n+ * of a previously triggered transition and performs cleanup of unused clocks.\n+ */\n+void ice_txclk_update_and_notify(struct ice_pf *pf)\n+{\n+\tstruct ice_ptp_port *ptp_port = &pf->ptp.port;\n+\tstruct ice_pf *ctrl_pf = ice_get_ctrl_pf(pf);\n+\tstruct dpll_pin *old_pin = NULL;\n+\tstruct dpll_pin *new_pin = NULL;\n+\tstruct ice_hw *hw = &pf->hw;\n+\tenum ice_e825c_ref_clk clk;\n+\tint err;\n+\tu8 phy;\n+\n+\tphy = ptp_port->port_num / hw->ptp.ports_per_phy;\n+\n+\tmutex_lock(&pf->dplls.lock);\n+\t/* no TX clock change requested */\n+\tif (pf->ptp.port.tx_clk == pf->ptp.port.tx_clk_req) {\n+\t\tmutex_unlock(&pf->dplls.lock);\n+\t\treturn;\n+\t}\n+\t/* verify current Tx reference settings */\n+\terr = ice_get_serdes_ref_sel_e825c(hw,\n+\t\t\t\t\t   ptp_port->port_num,\n+\t\t\t\t\t   &clk);\n+\tif (err) {\n+\t\tmutex_unlock(&pf->dplls.lock);\n+\t\treturn;\n+\t}\n+\n+\tif (clk != pf->ptp.port.tx_clk_req) {\n+\t\tdev_warn(ice_pf_to_dev(pf),\n+\t\t\t \"Failed to switch tx-clk for phy %d and clk %u (current: %u)\\n\",\n+\t\t\t phy, pf->ptp.port.tx_clk_req, clk);\n+\t\told_pin = ice_txclk_get_pin(pf, pf->ptp.port.tx_clk_req);\n+\t\tnew_pin = ice_txclk_get_pin(pf, clk);\n+\t\tpf->ptp.port.tx_clk = clk;\n+\t\tpf->ptp.port.tx_clk_req = clk;\n+\t\tgoto err_notify;\n+\t}\n+\n+\told_pin = ice_txclk_get_pin(pf, pf->ptp.port.tx_clk);\n+\tpf->ptp.port.tx_clk = clk;\n+\tpf->ptp.port.tx_clk_req = clk;\n+\n+\tif (IS_ERR_OR_NULL(ctrl_pf)) {\n+\t\tdev_err(ice_pf_to_dev(pf),\n+\t\t\t\"Can't set tx-clk: no controlling PF\\n\");\n+\t\tgoto err_notify;\n+\t}\n+\n+\t/* update Tx reference clock usage map */\n+\tfor (int i = 0; i < ICE_REF_CLK_MAX; i++)\n+\t\t(clk == i) ?\n+\t\t set_bit(ptp_port->port_num,\n+\t\t\t &ctrl_pf->ptp.tx_refclks[phy][i]) :\n+\t\t clear_bit(ptp_port->port_num,\n+\t\t\t   &ctrl_pf->ptp.tx_refclks[phy][i]);\n+\n+err_notify:\n+\tmutex_unlock(&pf->dplls.lock);\n+\n+\t/* Notify TX clk pins state transition */\n+\tif (old_pin)\n+\t\tdpll_pin_change_ntf(old_pin);\n+\tif (new_pin)\n+\t\tdpll_pin_change_ntf(new_pin);\n+\n+\t/* Update TXC DPLL lock status based on effective TX clk */\n+\tif (!IS_ERR_OR_NULL(pf->dplls.txc.dpll)) {\n+\t\tenum dpll_lock_status new_lock;\n+\n+\t\tnew_lock = ice_txclk_lock_status(clk);\n+\n+\t\tif (pf->dplls.txc.dpll_state != new_lock) {\n+\t\t\tpf->dplls.txc.dpll_state = new_lock;\n+\t\t\tdpll_device_change_ntf(pf->dplls.txc.dpll);\n+\t\t}\n+\t}\n+}\ndiff --git a/drivers/net/ethernet/intel/ice/ice_txclk.h b/drivers/net/ethernet/intel/ice/ice_txclk.h\nnew file mode 100644\nindex 000000000000..bdf591ea8f14\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ice/ice_txclk.h\n@@ -0,0 +1,38 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+/* Copyright (C) 2026 Intel Corporation */\n+\n+#ifndef _ICE_TXCLK_H_\n+#define _ICE_TXCLK_H_\n+\n+/**\n+ * ice_txclk_any_port_uses - check if any port on a PHY uses this TX refclk\n+ * @ctrl_pf: control PF (owner of the shared tx_refclks map)\n+ * @phy: PHY index\n+ * @clk: TX reference clock\n+ *\n+ * Return: true if any bit (port) is set for this clock on this PHY\n+ */\n+static inline bool\n+ice_txclk_any_port_uses(const struct ice_pf *ctrl_pf, u8 phy,\n+\t\t\tenum ice_e825c_ref_clk clk)\n+{\n+\treturn find_first_bit(&ctrl_pf->ptp.tx_refclks[phy][clk],\n+\t\t\tBITS_PER_LONG) < BITS_PER_LONG;\n+}\n+\n+static inline enum dpll_lock_status\n+ice_txclk_lock_status(enum ice_e825c_ref_clk clk)\n+{\n+\tswitch (clk) {\n+\tcase ICE_REF_CLK_SYNCE:\n+\tcase ICE_REF_CLK_EREF0:\n+\t\treturn DPLL_LOCK_STATUS_LOCKED;\n+\tcase ICE_REF_CLK_ENET:\n+\tdefault:\n+\t\treturn DPLL_LOCK_STATUS_UNLOCKED;\n+\t}\n+}\n+\n+int ice_txclk_set_clk(struct ice_pf *pf, enum ice_e825c_ref_clk clk);\n+void ice_txclk_update_and_notify(struct ice_pf *pf);\n+#endif /* _ICE_TXCLK_H_ */\n",
    "prefixes": [
        "v5",
        "net-next",
        "8/8"
    ]
}