From nobody Thu Apr 2 20:21:31 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8AF2B33F370; Thu, 26 Mar 2026 16:32:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.19 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774542747; cv=none; b=MW1VnOnMzKLOGsc5PVH+a2cApKp6uTUyF1UqLCYJdzfdGHZcZSDvjZgMG8v1bqedeje/OWHuWwTk/TIylF3Keoc6tm4L/gy+hkSa3G+msJ3YKMkEiXiXwKVdev5c2O4bZHNsbtNPxo0KGtA5JWKBmW8xG+httInuRts0XrpJM5Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774542747; c=relaxed/simple; bh=h6SdAt8V/8U61Dau5TYRbsrbBcUy7opyRgE4IDMhs3o=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=r8gV7ECvlOuxFvMoyYqNi2sg3/KQ8KWu0Fj7Ssnc+SFMh6DFDTTB1bLfRJzo681QXYujVWlRbMHl9hsUEy15uJciZT/VbCj3iMUoxs+OBEVCvzNH7nE8+a/zbXDsj67pwyAw4w3KMyssBTdFDgmpzOZV7YKbjhNfBHD98ZYxlxc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=d1/c57mx; arc=none smtp.client-ip=192.198.163.19 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="d1/c57mx" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1774542745; x=1806078745; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=h6SdAt8V/8U61Dau5TYRbsrbBcUy7opyRgE4IDMhs3o=; b=d1/c57mxfXE6bURXtrNj9UtoNAvmGpPCyDNbzdOz79PiprjmxQyxlygF ffRlqpQnInT7WHr+b4T0yE24Uk8qBXlHxeOGTCSorLw7e3HGAEtm/e4Vo tI71hWlT3HvCZBLw0i8AjjFOQb3+6IWpaxe16O7RNPmWyGjxOCgHCGGO+ Xs9Z71ADnSb7rxkka432YJwCpHddo2WneAQccTHND1/lp7b3qi+fS5JIP 2WSoopYfaVTHgg69AeONzUsZuYC1LtbYWvxP4Kh43Rxw4dgD2E6Wpk2gY J47CtR4qi0KpeIetrniXLhzYsJHjp+cL3dHEtxFCi2wP/mobeqQnNswup A==; X-CSE-ConnectionGUID: k9uRZ6PQReW5MYvwkSH1RQ== X-CSE-MsgGUID: leQsqrcfQK+mwYFVLpgM4w== X-IronPort-AV: E=McAfee;i="6800,10657,11741"; a="74636560" X-IronPort-AV: E=Sophos;i="6.23,142,1770624000"; d="scan'208";a="74636560" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by fmvoesa113.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 Mar 2026 09:32:24 -0700 X-CSE-ConnectionGUID: dfd35oV+TCaHZ6HM57vDPw== X-CSE-MsgGUID: nmJNRV5ESau2FtC0lmev0A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,142,1770624000"; d="scan'208";a="225310865" Received: from gklab-003-001.igk.intel.com ([10.91.173.48]) by orviesa007.jf.intel.com with ESMTP; 26 Mar 2026 09:32:20 -0700 From: Grzegorz Nitka To: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org, intel-wired-lan@lists.osuosl.org, poros@redhat.com, richardcochran@gmail.com, andrew+netdev@lunn.ch, przemyslaw.kitszel@intel.com, anthony.l.nguyen@intel.com, Prathosh.Satish@microchip.com, ivecera@redhat.com, jiri@resnulli.us, arkadiusz.kubalewski@intel.com, vadim.fedorenko@linux.dev, donald.hunter@gmail.com, horms@kernel.org, pabeni@redhat.com, kuba@kernel.org, davem@davemloft.net, edumazet@google.com, Grzegorz Nitka , Jiri Pirko , Aleksandr Loktionov Subject: [PATCH v4 net-next 1/8] dpll: add new DPLL type for transmit clock (TXC) usage Date: Thu, 26 Mar 2026 17:28:25 +0100 Message-Id: <20260326162832.3135857-2-grzegorz.nitka@intel.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20260326162832.3135857-1-grzegorz.nitka@intel.com> References: <20260326162832.3135857-1-grzegorz.nitka@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 Reviewed-by: Arkadiusz Kubalewski Reviewed-by: Aleksandr Loktionov Signed-off-by: Grzegorz Nitka --- 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[DPL= L_A_PIN_STATE + 1] =3D { static const struct nla_policy dpll_device_id_get_nl_policy[DPLL_A_TYPE + = 1] =3D { [DPLL_A_MODULE_NAME] =3D { .type =3D NLA_NUL_STRING, }, [DPLL_A_CLOCK_ID] =3D { .type =3D NLA_U64, }, - [DPLL_A_TYPE] =3D NLA_POLICY_RANGE(NLA_U32, 1, 2), + [DPLL_A_TYPE] =3D NLA_POLICY_RANGE(NLA_U32, 1, 3), }; =20 /* 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 =3D 1, DPLL_TYPE_EEC, + DPLL_TYPE_TXC, =20 /* private: */ __DPLL_TYPE_MAX, --=20 2.39.3 From nobody Thu Apr 2 20:21:31 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2A167402443; Thu, 26 Mar 2026 16:32:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.19 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774542759; cv=none; b=nOtwWF5hp1X2P3wB3/ICV/M49JW6AuM6bzlzTdv/meH/MpkwdZeRnFTXXApYfG7/qBGSuUg/YB0xo82qd4VFtUw5N/FeiuSfNQOO07nOOE9OzyON1eqJ0wOF/JaMKVg6mB/vxaKvMmg8haub9Xjhj79sjRTmJm3tQWdVKbIB6oo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774542759; c=relaxed/simple; bh=mGVGmB9xUUY2QySpvbbDhKQd8FqE0QgLo4M6A/it0eo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=haWtTpgaOZ/9Xle05/cryNHIc8KBQXx184r1Rokc7UXmWwlF5yExva8nQYsKoREgHdoLd4iuZYJ62TA7qC/SgdCjoTCTGVGAFceskK/5j78qk0ejzf5qqkgfWzzEAUynaVzoSgLzfkhfuc/mmI0D5KifZo8mVO4H+91ze7PskJA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=BHyC0L0b; arc=none smtp.client-ip=192.198.163.19 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="BHyC0L0b" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1774542757; x=1806078757; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=mGVGmB9xUUY2QySpvbbDhKQd8FqE0QgLo4M6A/it0eo=; b=BHyC0L0brzRuoZDOd2+ICUkst4Lj0oGSkY94nrl5Fow6l11908APtb4t 12LwxqGmBFS3E8RRQhKYmRU1xvVy3d9fjfFsxgL+e/V26+6XL5s/vg3eP FJg3VMyebVM/SWiaeryPiXecxffP3m13tK4lRaQQLid3rZfHzchQQgRod DpvZzZgGV9Hup2HQnJ8JTnYlKAoFfdXPKzXzmWjoiRjOglTAQP5MYt6tu Kct0SvsUORk/Z3OSvI8gINRSaoxeAK0nLtsz1FZaD/Xec/buX97KVQtSL 7cXszxKMvHHrULj9zOmmxno/PQA36RM+9QnyDc9VGjFbwJ2/1iecMb33U Q==; X-CSE-ConnectionGUID: DogPyaHUTvSK62ip/Gs0fw== X-CSE-MsgGUID: Loh8GY6sQ8qlgXMweDCROg== X-IronPort-AV: E=McAfee;i="6800,10657,11741"; a="74636613" X-IronPort-AV: E=Sophos;i="6.23,142,1770624000"; d="scan'208";a="74636613" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by fmvoesa113.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 Mar 2026 09:32:35 -0700 X-CSE-ConnectionGUID: foKnV65nRIu3ObJ2/MVYhQ== X-CSE-MsgGUID: WidJjEn2TjqhHZjQQX+ElA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,142,1770624000"; d="scan'208";a="225310908" Received: from gklab-003-001.igk.intel.com ([10.91.173.48]) by orviesa007.jf.intel.com with ESMTP; 26 Mar 2026 09:32:30 -0700 From: Grzegorz Nitka To: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org, intel-wired-lan@lists.osuosl.org, poros@redhat.com, richardcochran@gmail.com, andrew+netdev@lunn.ch, przemyslaw.kitszel@intel.com, anthony.l.nguyen@intel.com, Prathosh.Satish@microchip.com, ivecera@redhat.com, jiri@resnulli.us, arkadiusz.kubalewski@intel.com, vadim.fedorenko@linux.dev, donald.hunter@gmail.com, horms@kernel.org, pabeni@redhat.com, kuba@kernel.org, davem@davemloft.net, edumazet@google.com, Grzegorz Nitka , Jiri Pirko , Aleksandr Loktionov Subject: [PATCH v4 net-next 2/8] dpll: allow registering FW-identified pin with a different DPLL Date: Thu, 26 Mar 2026 17:28:26 +0100 Message-Id: <20260326162832.3135857-3-grzegorz.nitka@intel.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20260326162832.3135857-1-grzegorz.nitka@intel.com> References: <20260326162832.3135857-1-grzegorz.nitka@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 Reviewed-by: Arkadiusz Kubalewski Reviewed-by: Aleksandr Loktionov Signed-off-by: Grzegorz Nitka --- 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 dp= ll_pin *pin, return -EINVAL; =20 mutex_lock(&dpll_lock); - if (WARN_ON(!(dpll->module =3D=3D pin->module && - dpll->clock_id =3D=3D 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 !=3D pin->module || + dpll->clock_id !=3D pin->clock_id)) { ret =3D -EINVAL; - else - ret =3D __dpll_pin_register(dpll, pin, ops, priv, NULL); + goto out_unlock; + } + + ret =3D __dpll_pin_register(dpll, pin, ops, priv, NULL); +out_unlock: mutex_unlock(&dpll_lock); =20 return ret; --=20 2.39.3 From nobody Thu Apr 2 20:21:31 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5523C2DA755; Thu, 26 Mar 2026 16:32:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.19 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774542771; cv=none; b=C39yWuGY24HHIjF/XqfsEalTuzz95SgUazpFsutwyKsUtVFZw2liZUSCOf9gUlVITB/xI8B89NJe2B11Lcj3Sn7vvlbYpmqRY/AFWCFb1fkmILJ67gRNAuRiE/7VxX7Uwwm+sVUDpwDKkwtmzWh68AxKMdHshOwFNtXs8BEkuhE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774542771; c=relaxed/simple; bh=2Etx+rXvLgn5f8FbpTl8o586ChunxqUzp8NBTbrLv7U=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=htrC5FKdP2/kTDYtYBzHXi05YoTd6bqhUDd23PgsdWRID9Wv+3zXGqh8jhQqhQTBQ6E1Wn0Nj/RRCs6s7rMMtGRhViE8vP061P4QoRoKIF/2sUecIYjqdnObPrtHYKWzk526eFS2mtrFxzw8onGreb3MUp+lBIaUedeYsxngpsE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=TrIwaliC; arc=none smtp.client-ip=192.198.163.19 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="TrIwaliC" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1774542769; x=1806078769; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=2Etx+rXvLgn5f8FbpTl8o586ChunxqUzp8NBTbrLv7U=; b=TrIwaliCzXXcfwdeXJx4ITyaMqJf2A3MXQWJ3VTw9zjYFs584Ca5W40x q/oHpvr0MSOlRKzT9a9l33D7ZePy2C/eWp3rE0Zoeu7mhJZwk/7rXwh/f ecctb0OXGhCWxl1/F3AMXXmAl2jfkWHT1Su21snaBvCYRdnxQiFkbmLE4 OdD73nLkZBGJBSWJQe96BxmcictMAZxUExnEiYAMwUlzMki9HQJxejQ+B YPDBuCUn+gjoT7HAvHNXKLU3kM/vdcKJHNrBXjHschPQfKAr/Z8Juw15+ rozj8kNpfL0jGNKgGe+Rl1PpKl24pnkG50ohshD6VSZZpXV0jga5k7yaK A==; X-CSE-ConnectionGUID: Mq3TMWYISY6Quzeg3/zPEA== X-CSE-MsgGUID: 4WFpi8i2Sh6/ORrfor/9EQ== X-IronPort-AV: E=McAfee;i="6800,10657,11741"; a="74636647" X-IronPort-AV: E=Sophos;i="6.23,142,1770624000"; d="scan'208";a="74636647" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by fmvoesa113.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 Mar 2026 09:32:48 -0700 X-CSE-ConnectionGUID: P5wfBzOnRNqjHANLEEwfEA== X-CSE-MsgGUID: OJIESRsLStekGtbRsc35ng== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,142,1770624000"; d="scan'208";a="225310978" Received: from gklab-003-001.igk.intel.com ([10.91.173.48]) by orviesa007.jf.intel.com with ESMTP; 26 Mar 2026 09:32:44 -0700 From: Grzegorz Nitka To: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org, intel-wired-lan@lists.osuosl.org, poros@redhat.com, richardcochran@gmail.com, andrew+netdev@lunn.ch, przemyslaw.kitszel@intel.com, anthony.l.nguyen@intel.com, Prathosh.Satish@microchip.com, ivecera@redhat.com, jiri@resnulli.us, arkadiusz.kubalewski@intel.com, vadim.fedorenko@linux.dev, donald.hunter@gmail.com, horms@kernel.org, pabeni@redhat.com, kuba@kernel.org, davem@davemloft.net, edumazet@google.com, Grzegorz Nitka , Aleksandr Loktionov Subject: [PATCH v4 net-next 3/8] dpll: extend pin notifier and netlink events with notification source ID Date: Thu, 26 Mar 2026 17:28:27 +0100 Message-Id: <20260326162832.3135857-4-grzegorz.nitka@intel.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20260326162832.3135857-1-grzegorz.nitka@intel.com> References: <20260326162832.3135857-1-grzegorz.nitka@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 Reviewed-by: Aleksandr Loktionov Signed-off-by: Grzegorz Nitka --- 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, unsigne= d long action) call_dpll_notifiers(action, &info); } =20 -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 =3D { .pin =3D pin, @@ -80,6 +81,7 @@ void dpll_pin_notify(struct dpll_pin *pin, unsigned long = action) .clock_id =3D pin->clock_id, .fwnode =3D pin->fwnode, .prop =3D &pin->prop, + .src_id =3D ntfy_src, }; =20 call_dpll_notifiers(action, &info); @@ -847,7 +849,7 @@ __dpll_pin_register(struct dpll_device *dpll, struct dp= ll_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); =20 return ret; =20 @@ -946,7 +948,7 @@ void dpll_pin_unregister(struct dpll_device *dpll, stru= ct dpll_pin *pin, return; =20 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, s= truct dpll_pin *pin, stop =3D i; goto dpll_unregister; } - dpll_pin_create_ntf(pin); + dpll_pin_create_ntf(pin, parent->clock_id); } mutex_unlock(&dpll_lock); =20 @@ -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 *pare= nt, struct dpll_pin *pin, unsigned long i; =20 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; =20 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 act= ion); =20 #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; } =20 -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); } =20 -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); } =20 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); } =20 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); =20 int dpll_device_delete_ntf(struct dpll_device *dpll); =20 -int dpll_pin_create_ntf(struct dpll_pin *pin); +int dpll_pin_create_ntf(struct dpll_pin *pin, u64 ntfy_src); =20 -int dpll_pin_delete_ntf(struct dpll_pin *pin); +int dpll_pin_delete_ntf(struct dpll_pin *pin, u64 ntfy_src); =20 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; }; =20 #if IS_ENABLED(CONFIG_DPLL) --=20 2.39.3 From nobody Thu Apr 2 20:21:31 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 432A62DA755; Thu, 26 Mar 2026 16:32:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.19 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774542776; cv=none; b=RhiCfRf43uuDR6bflcmtHKBEEFoCaYi6OVW1q7W3xcZoKjwBVEGeRTHSMeEnFuYjIq3PtAdd5OS59nDxM4ADDY4lfP1rhkWBKENGHhDYGLC6LKN+zqs3B8SiC4TOe6Zr5BeQqTEc3RuyBnURKJuDD2UuB+QZtCJryNOXd+NXxUI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774542776; c=relaxed/simple; bh=Izbqb6M5jnyKGkCx6C0FAG3R4OV2Dm01nNdm0f5hBzY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Fw6f1eX/9zCM6UcoIvnYp0JnMfTNeqgcSGa/6X/VuAP9J6jnuP940Dreid7M/hzb6GgB0CIyOYq6be5XovlTspow9g+aeuJDX+qPFsPSFjZD0V3xtvf0i2zSPpIBE0I/iZn0YCBb4/ofrahLfSxWec761A1cdyQAcvBDcu6l7xc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=eP3og8sk; arc=none smtp.client-ip=192.198.163.19 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="eP3og8sk" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1774542775; x=1806078775; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Izbqb6M5jnyKGkCx6C0FAG3R4OV2Dm01nNdm0f5hBzY=; b=eP3og8skrtshbDP1KtRnKd9kLPX1E7LQhMJQZXLugXC/W65+mMTAr2EX 95KNeHlOYawtl7xwo9YpKSfOGbNJj5uWdesmSS3cKgFouw8HsrBtxjrVv UgYuJ/H+13Rf9P04M1M1h6ZXzZHmBpVrjsSBttN3ONhHDxDlF4pNsJfvt gcOqxv2mrk2MDXpQ0t8CKVTf7w1giV7EsgRusTs/uXv1bUF70K4rOSYx5 ODyYnDJ1d2fDGMnU2Jb72NDlLzY3UQAbTbtEPjo/z3ExCVLkMJpiDVDSZ aDPakwjZP7avXXJi2iVT6lXghXRIIauGm3pojRo345wUu2EYPtRTTGVp0 A==; X-CSE-ConnectionGUID: 8MbKZN6OTG+C5qaim8dL1g== X-CSE-MsgGUID: 4MINUEK0Soi448MFsePclQ== X-IronPort-AV: E=McAfee;i="6800,10657,11741"; a="74636657" X-IronPort-AV: E=Sophos;i="6.23,142,1770624000"; d="scan'208";a="74636657" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by fmvoesa113.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 Mar 2026 09:32:55 -0700 X-CSE-ConnectionGUID: 4ypneq9KQxuydLG5tMkNjw== X-CSE-MsgGUID: B7XIhe7VT9u1M3sKGU9d+Q== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,142,1770624000"; d="scan'208";a="225311062" Received: from gklab-003-001.igk.intel.com ([10.91.173.48]) by orviesa007.jf.intel.com with ESMTP; 26 Mar 2026 09:32:51 -0700 From: Grzegorz Nitka To: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org, intel-wired-lan@lists.osuosl.org, poros@redhat.com, richardcochran@gmail.com, andrew+netdev@lunn.ch, przemyslaw.kitszel@intel.com, anthony.l.nguyen@intel.com, Prathosh.Satish@microchip.com, ivecera@redhat.com, jiri@resnulli.us, arkadiusz.kubalewski@intel.com, vadim.fedorenko@linux.dev, donald.hunter@gmail.com, horms@kernel.org, pabeni@redhat.com, kuba@kernel.org, davem@davemloft.net, edumazet@google.com, Grzegorz Nitka , Aleksandr Loktionov Subject: [PATCH v4 net-next 4/8] dpll: zl3073x: allow SyncE_Ref pin state change Date: Thu, 26 Mar 2026 17:28:28 +0100 Message-Id: <20260326162832.3135857-5-grzegorz.nitka@intel.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20260326162832.3135857-1-grzegorz.nitka@intel.com> References: <20260326162832.3135857-1-grzegorz.nitka@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 Reviewed-by: Aleksandr Loktionov Signed-off-by: Grzegorz Nitka --- 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, =20 props->dpll_props.type =3D DPLL_PIN_TYPE_GNSS; =20 + /* + * 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 |=3D + DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE; + /* The output pin phase adjustment granularity equals half of * the synth frequency count. */ --=20 2.39.3 From nobody Thu Apr 2 20:21:31 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2E626411608; Thu, 26 Mar 2026 16:33:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.19 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774542784; cv=none; b=LaV2xklgKhSzpK9WENZXsRFTje50UxKpNIs3aS/m7wWVFrbDvW0TqI7WQNlhc+9XaxTUmmkD9ISj6DtbKp/jqknMstW4OEgdx+Q4L7qxoPfaX3V8PXz0/8vV0uHrcB6PnePV3zvA34ErBdCH7njEkHCfQFG8qjF00EaNc+MyC3k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774542784; c=relaxed/simple; bh=8ceLVs2JsObasP3Lu+oXmghvt3ALk1HbwW5kHqK/T4Q=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=uQYK6lrCfP7D+n4foSzmHWfKhJfgGZC9VLGPQEoxntNzt9qWgEBa5X/onpC3/4HUtoVnO8T8VXyCY9I96uSrTzfmCiBQF8cii/6DFwtwUN0BK2y+vmhezojNJ2vptauJDwYKmjTnlipII6sno9G2QRcY5FE4zja/O+LES608h1g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=IBClPsnw; arc=none smtp.client-ip=192.198.163.19 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="IBClPsnw" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1774542782; x=1806078782; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=8ceLVs2JsObasP3Lu+oXmghvt3ALk1HbwW5kHqK/T4Q=; b=IBClPsnwa98bsL/QsQwVTRDOTtd8G7CnYeJ1C4/rX8DT3mgvPcYmHaWQ SFCxdVYwmdaW1AjSFal2f84rHFuTtFcAJe0W4BQWpB40pjcEn66VC1b1m gsk9JPiYO1o9vBglZSZbpvjTWoDd+EF/v8VYFRr+bLM/zOD4MZlOSreM9 mW8wwweKWIMz6YEFvEbRq7rY54e05d4gIkMzsZW4mVBOCA9htCbFtKW6m NyfnJSkl5bSSSCOiQWHpOaXfVQF4Tz8eZUOIMZkVZSZwH1RHubPklID9z DBWcRuP6rLSybuyAiI/AEoF4BaIylOnReEdyNNF6lkoGPWSCjZ1cuVeqH A==; X-CSE-ConnectionGUID: JVih9PwfSCm+wyT/oddjBQ== X-CSE-MsgGUID: pg2R3EwcSb2C149vY80klg== X-IronPort-AV: E=McAfee;i="6800,10657,11741"; a="74636688" X-IronPort-AV: E=Sophos;i="6.23,142,1770624000"; d="scan'208";a="74636688" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by fmvoesa113.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 Mar 2026 09:33:01 -0700 X-CSE-ConnectionGUID: UEH2dNSlS32v7jmotODE2w== X-CSE-MsgGUID: 2nDTOYt9Ql6QRFNCuuUcFA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,142,1770624000"; d="scan'208";a="225311144" Received: from gklab-003-001.igk.intel.com ([10.91.173.48]) by orviesa007.jf.intel.com with ESMTP; 26 Mar 2026 09:32:57 -0700 From: Grzegorz Nitka To: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org, intel-wired-lan@lists.osuosl.org, poros@redhat.com, richardcochran@gmail.com, andrew+netdev@lunn.ch, przemyslaw.kitszel@intel.com, anthony.l.nguyen@intel.com, Prathosh.Satish@microchip.com, ivecera@redhat.com, jiri@resnulli.us, arkadiusz.kubalewski@intel.com, vadim.fedorenko@linux.dev, donald.hunter@gmail.com, horms@kernel.org, pabeni@redhat.com, kuba@kernel.org, davem@davemloft.net, edumazet@google.com, Grzegorz Nitka Subject: [PATCH v4 net-next 5/8] ice: add TX clock (TXC) DPLL interface for E825 devices Date: Thu, 26 Mar 2026 17:28:29 +0100 Message-Id: <20260326162832.3135857-6-grzegorz.nitka@intel.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20260326162832.3135857-1-grzegorz.nitka@intel.com> References: <20260326162832.3135857-1-grzegorz.nitka@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 Signed-off-by: Grzegorz Nitka --- 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/ethern= et/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 =20 +#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)) =20 @@ -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, }; =20 static const char * const pin_type_name[] =3D { @@ -71,10 +78,13 @@ static const char * const pin_type_name[] =3D { [ICE_DPLL_PIN_TYPE_OUTPUT] =3D "output", [ICE_DPLL_PIN_TYPE_RCLK_INPUT] =3D "rclk-input", [ICE_DPLL_PIN_TYPE_SOFTWARE] =3D "software", + [ICE_DPLL_PIN_TYPE_TXCLK] =3D "txclk-input", }; =20 static const char * const ice_dpll_sw_pin_sma[] =3D { "SMA1", "SMA2" }; static const char * const ice_dpll_sw_pin_ufl[] =3D { "U.FL1", "U.FL2" }; +static const char * const ice_dpll_ext_eref_pin =3D "EXT_EREF0"; +static const char * const ice_dpll_fwnode_ext_synce =3D "clk_ref_synce"; =20 static const struct dpll_pin_frequency ice_esync_range[] =3D { DPLL_PIN_FREQUENCY_RANGE(0, DPLL_PIN_FREQUENCY_1_HZ), @@ -2517,12 +2527,75 @@ ice_dpll_rclk_state_on_pin_get(const struct dpll_pi= n *pin, void *pin_priv, return ret; } =20 +/** + * 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_pri= v, + 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_pri= v, + 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 =3D DPLL_PIN_STATE_DISCONNECTED; + + return 0; +} + static const struct dpll_pin_ops ice_dpll_rclk_ops =3D { .state_on_pin_set =3D ice_dpll_rclk_state_on_pin_set, .state_on_pin_get =3D ice_dpll_rclk_state_on_pin_get, .direction_get =3D ice_dpll_input_direction, }; =20 +static const struct dpll_pin_ops ice_dpll_txclk_ops =3D { + .state_on_dpll_set =3D ice_dpll_txclk_state_on_dpll_set, + .state_on_dpll_get =3D ice_dpll_txclk_state_on_dpll_get, + .direction_get =3D ice_dpll_input_direction, +}; + static const struct dpll_pin_ops ice_dpll_pin_sma_ops =3D { .state_on_dpll_set =3D ice_dpll_sma_pin_state_set, .state_on_dpll_get =3D ice_dpll_sw_pin_state_get, @@ -3023,9 +3096,13 @@ ice_dpll_unregister_pins(struct dpll_device *dpll, s= truct ice_dpll_pin *pins, { int i; =20 - for (i =3D 0; i < count; i++) - if (!pins[i].hidden) - dpll_pin_unregister(dpll, pins[i].pin, ops, &pins[i]); + for (i =3D 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]); + } } =20 /** @@ -3199,19 +3276,40 @@ static bool ice_dpll_is_fwnode_pin(struct ice_dpll_= pin *pin) return !IS_ERR_OR_NULL(pin->fwnode); } =20 +static bool ice_dpll_fwnode_eq(const struct fwnode_handle *a, + const struct fwnode_handle *b) +{ + return a && b && a =3D=3D b; +} + static void ice_dpll_pin_notify_work(struct work_struct *work) { struct ice_dpll_pin_work *w =3D container_of(work, struct ice_dpll_pin_work, work); struct ice_dpll_pin *pin, *parent =3D w->pin; + bool is_tx_synce_parent =3D false; struct ice_pf *pf =3D parent->pf; + bool is_rclk_parent =3D false; int ret; =20 wait_for_completion(&pf->dplls.dpll_init); if (!test_bit(ICE_FLAG_DPLL, pf->flags)) goto out; /* DPLL initialization failed */ =20 + /* Decide which parent we are handling, defensively checking FWNs */ + is_rclk_parent =3D + 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 =3D + 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_st= ruct *work) goto out; } =20 - /* Register rclk pin */ - pin =3D &pf->dplls.rclk; - ret =3D 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 =3D NULL; - goto out; + if (is_rclk_parent) { + /* Register rclk pin via on-pin relationship */ + pin =3D &pf->dplls.rclk; + ret =3D 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 =3D &pf->dplls.txclks[E825_EXT_SYNCE_PIN_IDX]; + ret =3D 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_st= ruct *work) goto out; } =20 - /* Unregister rclk pin */ - pin =3D &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 =3D &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 =3D &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 =3D NULL; @@ -3276,6 +3393,12 @@ static int ice_dpll_pin_notify(struct notifier_block= *nb, unsigned long action, if (pin->fwnode !=3D info->fwnode) return NOTIFY_DONE; /* Not this pin */ =20 + /* Ignore notification which are the outcome of internal pin + * registration/unregistration calls - synce pin case. + */ + if (info->src_id =3D=3D pin->pf->dplls.clock_id) + return NOTIFY_DONE; + work =3D kzalloc_obj(*work); if (!work) return NOTIFY_DONE; @@ -3401,6 +3524,19 @@ ice_dpll_deinit_fwnode_pins(struct ice_pf *pf, struc= t ice_dpll_pin *pins, destroy_workqueue(pf->dplls.wq); } =20 +static int ice_dpll_deinit_txclk_pins(struct ice_pf *pf) +{ + struct ice_dpll_pin *synce_pin =3D &pf->dplls.txclks[E825_EXT_SYNCE_PIN_I= DX]; + struct ice_dpll *dt =3D &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 =3D &d->pps; =20 ice_dpll_deinit_rclk_pin(pf); - if (pf->hw.mac_type =3D=3D ICE_MAC_GENERIC_3K_E825) + if (pf->hw.mac_type =3D=3D 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; } =20 +static int ice_dpll_init_txclk_pins(struct ice_pf *pf, int start_idx) +{ + struct ice_dpll_pin *ref_pin =3D pf->dplls.txclks; + struct ice_dpll *txc =3D &pf->dplls.txc; + int ret; + + /* Configure EXT_EREF0 pin */ + ret =3D ice_dpll_get_pins(pf, ref_pin, start_idx, 1, pf->dplls.clock_id); + if (ret) + return ret; + ret =3D 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 =3D 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 =3D 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) =20 ret =3D ice_dpll_init_rclk_pin(pf, DPLL_PIN_IDX_UNSPEC, &ice_dpll_rclk_ops); + + if (ret) + goto unregister_pins; + + ret =3D 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 =3D=3D 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_dp= ll *d, bool cgu, return ret; } d->pf =3D pf; - if (cgu) { + if (cgu || pf->hw.mac_type =3D=3D ICE_MAC_GENERIC_3K_E825) { const struct dpll_device_ops *ops =3D &ice_dpll_ops; =20 if (type =3D=3D DPLL_TYPE_PPS && ice_dpll_is_pps_phase_monitor(pf)) ops =3D &ice_dpll_pom_ops; - ice_dpll_update_state(pf, d, true); + if (cgu) + ice_dpll_update_state(pf, d, true); ret =3D 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; } =20 +/** + * ice_dpll_init_info_txclk_pins_e825c - initializes tx-clk pins informati= on + * @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 =3D 0; i < ICE_DPLL_TXCLK_NUM_MAX; i++) { + tx_pin =3D &pf->dplls.txclks[i]; + tx_pin->prop.type =3D DPLL_PIN_TYPE_EXT; + tx_pin->prop.capabilities |=3D + DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE; + tx_pin->pf =3D pf; + if (i =3D=3D E825_EXT_EREF_PIN_IDX) { + tx_pin->prop.board_label =3D ice_dpll_ext_eref_pin; + tx_pin->tx_ref_src =3D ICE_REF_CLK_EREF0; + } else if (i =3D=3D E825_EXT_SYNCE_PIN_IDX) { + tx_pin->tx_ref_src =3D 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_d= pll_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 =3D &pf->dplls; + struct ice_dpll *dt =3D &d->txc; int ret =3D 0; int i; =20 d->clock_id =3D ice_generate_clock_id(pf); d->num_inputs =3D ICE_SYNCE_CLK_NUM; + dt->dpll_state =3D DPLL_LOCK_STATUS_LOCKED; + dt->mode =3D DPLL_MODE_MANUAL; + dt->dpll_idx =3D pf->ptp.port.port_num; =20 d->inputs =3D kzalloc_objs(*d->inputs, d->num_inputs); if (!d->inputs) @@ -4160,6 +4397,11 @@ static int ice_dpll_init_info_e825c(struct ice_pf *p= f) ret =3D ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_RCLK_INPUT); if (ret) goto deinit_info; + + ret =3D 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 =3D ice_dpll_init_info_e825c(pf); if (err) goto err_exit; - err =3D ice_dpll_init_pins_e825(pf); + err =3D ice_dpll_init_dpll(pf, &pf->dplls.txc, false, DPLL_TYPE_TXC); if (err) goto deinit_info; + err =3D ice_dpll_init_pins_e825(pf); + if (err) + goto deinit_txclk; set_bit(ICE_FLAG_DPLL, pf->flags); complete_all(&d->dpll_init); =20 return; =20 +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/ethern= et/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" =20 #define ICE_DPLL_RCLK_NUM_MAX 4 +#define ICE_DPLL_TXCLK_NUM_MAX 2 =20 /** * 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; }; =20 /** 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/ethe= rnet/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; }; =20 +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 =20 --=20 2.39.3 From nobody Thu Apr 2 20:21:31 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A74F2413229; Thu, 26 Mar 2026 16:33:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.19 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774542792; cv=none; b=JdpkoDZgdubqh3UpSon80CajpspOTFW14Xd8KMlG1U8mx4gRmh3/DM6wgKNEv9R2LwRLbTm2OOrr/0fCzdOqX7G/dfWr1L3IdCHgntFqJV/LWhFAiug6jiZWuvyt9p2XZyPfGWvdMYpEeW5ZMjtMBgVjKbkvx+NxvuF3KVkXJaA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774542792; c=relaxed/simple; bh=RXeLAwQd/WhX+HnMNBfpNgz9UNtamMV0lERMiFBdSsM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=qAODhYGQGqYBMmQADe1+P+uFtFZ5AclWlixynBHPKVHWEqizVzjAhsWV4dJ5joOxkWEwX0VvsdglTQ9LHSsb+OX32hU18hOILtH14wrt+OSHyQQ1pt9fLM3UlFk1eMM2ArhSwE6UCHT/Agriluct+95Ihnv2cSOlwIx6Q1bw7a8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=hAIyITwK; arc=none smtp.client-ip=192.198.163.19 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="hAIyITwK" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1774542790; x=1806078790; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=RXeLAwQd/WhX+HnMNBfpNgz9UNtamMV0lERMiFBdSsM=; b=hAIyITwKp4ACYN/cRXj0w8pn1RS8FflpkBKWQar+eFgrs87SMtkUaQEC EyToFWtf4cZyuZ/St+lpcLaujydD74poUYbaSdTY9N6f7ENLqfvt1c3NN 7waW2XCNusa49cdt6KcxrGD5D/3nCXP32TnY5xMyep6StoWvkF8MkW1eT aWzEaKWdQR6W0kqg/LYI00TJdUjylAqwvfmiNmMmLBNMkXoEPprN5Eqym KDG1RLSSU7hR3ESu8XCEvqL5gg08lXa2mPMbqgxLYJdR4UKleljRZj7Im W2B087m/qEE/S85/pxVcGVWAdID9q/H63KqvExNpvtp66W48eJHGx+Nub w==; X-CSE-ConnectionGUID: THtOdPxFSrSXywdvANJm0w== X-CSE-MsgGUID: FDuJWYPaRo+nuJEGslCTFQ== X-IronPort-AV: E=McAfee;i="6800,10657,11741"; a="74636714" X-IronPort-AV: E=Sophos;i="6.23,142,1770624000"; d="scan'208";a="74636714" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by fmvoesa113.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 Mar 2026 09:33:10 -0700 X-CSE-ConnectionGUID: 06dnr0SJRoGxAQ1iFRumMg== X-CSE-MsgGUID: y/jfD1TFR0eN4K+pN3EBqQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,142,1770624000"; d="scan'208";a="225311228" Received: from gklab-003-001.igk.intel.com ([10.91.173.48]) by orviesa007.jf.intel.com with ESMTP; 26 Mar 2026 09:33:05 -0700 From: Grzegorz Nitka To: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org, intel-wired-lan@lists.osuosl.org, poros@redhat.com, richardcochran@gmail.com, andrew+netdev@lunn.ch, przemyslaw.kitszel@intel.com, anthony.l.nguyen@intel.com, Prathosh.Satish@microchip.com, ivecera@redhat.com, jiri@resnulli.us, arkadiusz.kubalewski@intel.com, vadim.fedorenko@linux.dev, donald.hunter@gmail.com, horms@kernel.org, pabeni@redhat.com, kuba@kernel.org, davem@davemloft.net, edumazet@google.com, Grzegorz Nitka Subject: [PATCH v4 net-next 6/8] ice: implement CPI support for E825C Date: Thu, 26 Mar 2026 17:28:30 +0100 Message-Id: <20260326162832.3135857-7-grzegorz.nitka@intel.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20260326162832.3135857-1-grzegorz.nitka@intel.com> References: <20260326162832.3135857-1-grzegorz.nitka@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 Signed-off-by: Grzegorz Nitka --- 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) +=3D \ ice_vf_mbx.o \ ice_vf_vsi_vlan_ops.o \ ice_vf_lib.o -ice-$(CONFIG_PTP_1588_CLOCK) +=3D ice_ptp.o ice_ptp_hw.o ice_dpll.o ice_ts= pll.o +ice-$(CONFIG_PTP_1588_CLOCK) +=3D ice_ptp.o ice_ptp_hw.o ice_dpll.o ice_ts= pll.o ice_cpi.o ice-$(CONFIG_DCB) +=3D ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o ice-$(CONFIG_RFS_ACCEL) +=3D ice_arfs.o ice-$(CONFIG_XDP_SOCKETS) +=3D ice_xsk.o diff --git a/drivers/net/ethernet/intel/ice/ice_cpi.c b/drivers/net/etherne= t/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 =3D 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 !=3D 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 =3D { + .dest_dev =3D ice_cpi_get_dest_dev(hw, phy), + .opcode =3D ice_sbq_msg_wr_np, + .msg_addr_low =3D lower_16_bits(addr), + .msg_addr_high =3D upper_16_bits(addr), + .data =3D val + }; + int err; + + err =3D 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 =3D { + .dest_dev =3D ice_cpi_get_dest_dev(hw, phy), + .opcode =3D ice_sbq_msg_rd, + .msg_addr_low =3D lower_16_bits(addr), + .msg_addr_high =3D upper_16_bits(addr) + }; + int err; + + err =3D 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 =3D 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 =3D 0; i < CPI_RETRIES_COUNT; i++) { + int err; + + /* check if another CPI Client is also accessing CPI */ + err =3D 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 =3D 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 com= mand + * 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 =3D 0; i < CPI_RETRIES_COUNT; i++) { + int err; + + err =3D 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 =3D 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 =3D (union cpi_reg_lm_cmd_data *)&data; + lm_regs->field.cpi_req =3D 0; + + err =3D 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 =3D 0; + + if (!cmd || !resp) + return -EINVAL; + + memset(&lm_cmd_data, 0, sizeof(lm_cmd_data)); + + lm_cmd_data.field.cpi_req =3D CPI_LM_CMD_REQ; + lm_cmd_data.field.get_set =3D cmd->set; + lm_cmd_data.field.opcode =3D cmd->opcode; + lm_cmd_data.field.portlane =3D cmd->port; + lm_cmd_data.field.data =3D cmd->data; + + /* 1. Try to acquire the bus, PHY ACK should be low before we begin */ + err =3D ice_cpi_wait_req0_ack0(hw, phy); + if (err) + goto cpi_exec_exit; + + /* 2. We start the CPI request */ + err =3D 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 =3D 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 !=3D phy_cmd_data.field.opcode) { + err =3D -EFAULT; + goto cpi_deassert; + } + + resp->opcode =3D phy_cmd_data.field.opcode; + resp->data =3D phy_cmd_data.field.data; + resp->port =3D phy_cmd_data.field.portlane; + +cpi_deassert: + /* 4. We deassert REQ */ + err1 =3D ice_cpi_req0(hw, phy, lm_cmd_data.val); + if (err1) + goto cpi_exec_exit; + + /* 5. PHY ACK should be deasserted in response */ + err1 =3D ice_cpi_wait_ack0(hw, phy); + +cpi_exec_exit: + if (!err) + err =3D 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 =3D {0}; + struct ice_cpi_cmd cpi_cmd =3D { + .opcode =3D opcode, + .set =3D true, + .port =3D port_lane, + .data =3D 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 =3D 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/etherne= t/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/eth= ernet/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 { }; =20 enum ice_sbq_msg_opcode { - ice_sbq_msg_rd =3D 0x00, - ice_sbq_msg_wr =3D 0x01 + ice_sbq_msg_rd =3D 0x00, + ice_sbq_msg_wr =3D 0x01, + ice_sbq_msg_wr_np =3D 0x02 }; =20 #define ICE_SBQ_MSG_FLAGS 0x40 --=20 2.39.3 From nobody Thu Apr 2 20:21:31 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 17C31413258; Thu, 26 Mar 2026 16:33:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.19 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774542798; cv=none; b=m5Izgzt/oRnQTMu4mD0wbmLFdP7hh5MNkCOPWBdocVDtlyM7yMi2up/sFtA1o1GvFhNx3O4c94zJAKNSnN1AybMiaLCtHLjYIFOsTNupgBMiu2K+0zMsrYoeuLQc8SfMODI4b3HcQyfp9nHpotaKU9oDcZ368TNEyaWm0n4QCB4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774542798; c=relaxed/simple; bh=2MZHnP/9cS14JCDWx6lZ3RRAkM3yTL2R5Dnn1mrIUqo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=j5aywP/dPZse1LSNzbRs6+g3sZrv0d0nSY0KR3CypKhrGUIQx1JXUThWfjJ/LtJBYEdEcY0L8f4rcpstQ+bLXAX0JV7173wNUXSoAfDj6bi2mZPoekRhJBZtWYtAjO82M7arOu43flx6vez6NeB6iEHrjS8zMw6OPI4D+sZt6W8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=W8W1+pSZ; arc=none smtp.client-ip=192.198.163.19 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="W8W1+pSZ" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1774542796; x=1806078796; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=2MZHnP/9cS14JCDWx6lZ3RRAkM3yTL2R5Dnn1mrIUqo=; b=W8W1+pSZ655/vCDWRIkMO1xs5Z5GDl/Q3ZTjY+uViIVkZS2qZejQAHUD o5eOELANF620YBk5jM1Y7HCK0umNxdsZFoH/SI5PSF5Qe/Q9Zi0WGEKyK nFA4aeX4IAMaguY9tFtY9R8/TGQy5FzUdjcFlU0PWq7wPKRHeCFCx9YFq XH7tUgv7CUf9vYebTASGp9j4r+m4cccAy7KgLC4qj6fHz6R/GeWDBdCx3 Nn/OcTm9aHJkkwqYiY/ZQgJtAIzksnzSB6LuwnQuTrL3eddrV7gUGXZrT Ti5EBpE1o1NwedlI2Vylxsj1FecBB9PfvKs/Y/F3yWZNHd4ZEHRtLgdeI Q==; X-CSE-ConnectionGUID: EANywaBZSM6dZHtrX4fclQ== X-CSE-MsgGUID: 8K8WORsOSsWDhdQTiwO8vg== X-IronPort-AV: E=McAfee;i="6800,10657,11741"; a="74636742" X-IronPort-AV: E=Sophos;i="6.23,142,1770624000"; d="scan'208";a="74636742" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by fmvoesa113.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 Mar 2026 09:33:16 -0700 X-CSE-ConnectionGUID: eX5HKoH3SbyKGTplUSVCIg== X-CSE-MsgGUID: nr2VscN5RQO67pCuqqFE5Q== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,142,1770624000"; d="scan'208";a="225311294" Received: from gklab-003-001.igk.intel.com ([10.91.173.48]) by orviesa007.jf.intel.com with ESMTP; 26 Mar 2026 09:33:12 -0700 From: Grzegorz Nitka To: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org, intel-wired-lan@lists.osuosl.org, poros@redhat.com, richardcochran@gmail.com, andrew+netdev@lunn.ch, przemyslaw.kitszel@intel.com, anthony.l.nguyen@intel.com, Prathosh.Satish@microchip.com, ivecera@redhat.com, jiri@resnulli.us, arkadiusz.kubalewski@intel.com, vadim.fedorenko@linux.dev, donald.hunter@gmail.com, horms@kernel.org, pabeni@redhat.com, kuba@kernel.org, davem@davemloft.net, edumazet@google.com, Grzegorz Nitka Subject: [PATCH v4 net-next 7/8] ice: add Tx reference clock index handling to AN restart command Date: Thu, 26 Mar 2026 17:28:31 +0100 Message-Id: <20260326162832.3135857-8-grzegorz.nitka@intel.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20260326162832.3135857-1-grzegorz.nitka@intel.com> References: <20260326162832.3135857-1-grzegorz.nitka@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 Signed-off-by: Grzegorz Nitka Reviewed-by: Aleksandr Loktionov --- 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]; }; =20 diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethe= rnet/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, b= ool *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 &=3D ~ICE_AQC_RESTART_AN_LINK_ENABLE; =20 + cmd->cmd_flags |=3D FIELD_PREP(ICE_AQC_RESTART_AN_REFCLK_M, refclk); + return ice_aq_send_cmd(pi->hw, &desc, NULL, 0, cd); } =20 diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethe= rnet/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_aq= c_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/etherne= t/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 !=3D ICE_VSI_PF) return -EINVAL; =20 - status =3D ice_aq_set_link_restart_an(pi, ena, NULL); + status =3D ice_aq_set_link_restart_an(pi, ena, NULL, + ICE_AQC_RESTART_AN_REFCLK_NOCHANGE); =20 /* 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 --=20 2.39.3 From nobody Thu Apr 2 20:21:31 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A5CAA3F0AB9; Thu, 26 Mar 2026 16:33:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.19 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774542809; cv=none; b=VKZ50+83JLEbDDe7ves3wbY8xaoHUkwK0eIa52Xsyn8jcbB3s9CIXATRK/IqqycWLGxdOMjdiLKCF1N44KhIOLSWMuEGWDWPEavRNDJtKT4pvu5iQHXYhEXIsTYQyfjmeAMipxexFnsj1hj9pyhVE+tOpWC2S/90gDwdmDV5pjs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774542809; c=relaxed/simple; bh=YvFe7Mrp0/nooPRVRV/8VS/UW7rTm2ND8U7tebxBNaU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=bX5lABvO67NzEWo65g+ZiXIkZhklVV199jENdlVr64ck6Mds0kiTOxSumvRFB5yCmu/M/lLKbL4xjCVof01eQl4uRPouu8VjeGXtCZULI/63x20hWeT8mXwvPgvDLvmwG0SEGHKH/FgIByhqXSWU3dH+E0pf4fge4DtNLW/4VsM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=LtaI87uf; arc=none smtp.client-ip=192.198.163.19 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="LtaI87uf" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1774542807; x=1806078807; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=YvFe7Mrp0/nooPRVRV/8VS/UW7rTm2ND8U7tebxBNaU=; b=LtaI87ufk8q9PFN7SkZtSlp+uJff7lfJK5z3lYh9j/K8POeeuI5Y/klE kdSg0s7lBZGE5M3A0qPWHu5fY4eJONGCIHossFm/G0eH3cppV31Rf3LWq of0QtiX9N9OzUlT7BUaBn90o6d3AvRPYgk8W57O0TasHEZxzsuN49RxQU 84ISVl2ofYwH/i5TWYxcBDbG4tYy35Y01gVTeGfd5xay3uRXvQVb0dDfP EpxvVjH6j7/VlQ1f9xrMQfBkQkaYm1Evkz8g6WGRV036oYG1XT+Kn/7RD L3X15MjI4dD7PDDQvtBhCS2B+CheHFzVbx2awKocZstOhJLKOvRt33ylr w==; X-CSE-ConnectionGUID: RnceLxo3RceYEHxvjtVPoQ== X-CSE-MsgGUID: q6qISCppTS+CXIjPSqyiPA== X-IronPort-AV: E=McAfee;i="6800,10657,11741"; a="74636783" X-IronPort-AV: E=Sophos;i="6.23,142,1770624000"; d="scan'208";a="74636783" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by fmvoesa113.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 Mar 2026 09:33:25 -0700 X-CSE-ConnectionGUID: CtUyLLrVTx61STSSPn75cA== X-CSE-MsgGUID: koG7bDrXSyWxLH3L+XrkuA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,142,1770624000"; d="scan'208";a="225311414" Received: from gklab-003-001.igk.intel.com ([10.91.173.48]) by orviesa007.jf.intel.com with ESMTP; 26 Mar 2026 09:33:21 -0700 From: Grzegorz Nitka To: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org, intel-wired-lan@lists.osuosl.org, poros@redhat.com, richardcochran@gmail.com, andrew+netdev@lunn.ch, przemyslaw.kitszel@intel.com, anthony.l.nguyen@intel.com, Prathosh.Satish@microchip.com, ivecera@redhat.com, jiri@resnulli.us, arkadiusz.kubalewski@intel.com, vadim.fedorenko@linux.dev, donald.hunter@gmail.com, horms@kernel.org, pabeni@redhat.com, kuba@kernel.org, davem@davemloft.net, edumazet@google.com, Grzegorz Nitka Subject: [PATCH v4 net-next 8/8] ice: add TX reference clock (tx_clk) control for E825 devices Date: Thu, 26 Mar 2026 17:28:32 +0100 Message-Id: <20260326162832.3135857-9-grzegorz.nitka@intel.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20260326162832.3135857-1-grzegorz.nitka@intel.com> References: <20260326162832.3135857-1-grzegorz.nitka@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Add full support for selecting and controlling the TX SERDES reference clock on E825C hardware. E825C devicede supports selecting among multiple SERDES transmit reference clock sources (ENET, SyncE, EREF0), but imposes several routing constraints: on some paths a reference must be enabled on both PHY complexes, and ports sharing a PHY must coordinate usage so that a reference is not disabled while still in active use. Until now the driver did not expose this domain through the DPLL API, nor did it provide a coherent control layer for enabling, switching, or tracking TX reference clocks. This patch implements full TX reference clock management for E825 devices. Compared to previous iterations, the logic is now separated into a dedicated module (ice_txclk.c) which encapsulates all clock-selection rules, cross=E2=80=91PHY dependencies, and the bookkeeping needed to ensure safe transitions. This allows the DPLL layer and the PTP code to remain focused on their respective roles. Key additions: * A new txclk control module (`ice_txclk.c`) implementing: - software usage tracking for each reference clock per PHY, - peer=E2=80=91PHY enable rules (SyncE required on both PHYs when use= d on PHY0, EREF0 required on both when used on PHY1), - safe disabling of unused reference clocks after switching, - a single, driver=E2=80=91internal entry point for clock changes. * Integration with the DPLL pin ops: - pin=E2=80=91set now calls into `ice_txclk_set_clk()` to request a hardware switch, - pin=E2=80=91get reports the current SERDES reference by reading bac= k the active selector (`ice_get_serdes_ref_sel_e825c()`). * Wiring the requested reference clock into Auto=E2=80=91Negotiation rest= art through the already=E2=80=91extended `ice_aq_set_link_restart_an()`. * After each link-up the driver verifies the effective hardware state (`ice_txclk_verify()`) and updates its per=E2=80=91PHY usage bitmaps, correcting the requested/active state if the FW or AN flow applied a different reference. * PTP PF initialization now seeds the ENET reference clock as enabled by default for its port. All reference clock transitions are serialized through the DPLL lock, and usage information is shared across all PFs belonging to the same E825C controller PF. This ensures that concurrent changes are coordinated and that shared PHYs never see an unexpected disable. With this patch, E825 devices gain full userspace=E2=80=91driven TXC refere= nce clock selection via the DPLL subsystem, enabling complete SyncE support, precise multi=E2=80=91clock setups, and predictable clock routing behavior. Reviewed-by: Arkadiusz Kubalewski Signed-off-by: Grzegorz Nitka --- drivers/net/ethernet/intel/ice/Makefile | 2 +- drivers/net/ethernet/intel/ice/ice.h | 12 + drivers/net/ethernet/intel/ice/ice_dpll.c | 53 +++- 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 | 27 +++ drivers/net/ethernet/intel/ice/ice_txclk.c | 256 ++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_txclk.h | 41 ++++ 9 files changed, 445 insertions(+), 17 deletions(-) create mode 100644 drivers/net/ethernet/intel/ice/ice_txclk.c create mode 100644 drivers/net/ethernet/intel/ice/ice_txclk.h diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet= /intel/ice/Makefile index 38db476ab2ec..95fd0c49800f 100644 --- a/drivers/net/ethernet/intel/ice/Makefile +++ b/drivers/net/ethernet/intel/ice/Makefile @@ -54,7 +54,7 @@ ice-$(CONFIG_PCI_IOV) +=3D \ ice_vf_mbx.o \ ice_vf_vsi_vlan_ops.o \ ice_vf_lib.o -ice-$(CONFIG_PTP_1588_CLOCK) +=3D ice_ptp.o ice_ptp_hw.o ice_dpll.o ice_ts= pll.o ice_cpi.o +ice-$(CONFIG_PTP_1588_CLOCK) +=3D ice_ptp.o ice_ptp_hw.o ice_dpll.o ice_ts= pll.o ice_cpi.o ice_txclk.o ice-$(CONFIG_DCB) +=3D ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o ice-$(CONFIG_RFS_ACCEL) +=3D ice_arfs.o ice-$(CONFIG_XDP_SOCKETS) +=3D ice_xsk.o diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/in= tel/ice/ice.h index 2b2b22af42be..b42df789295f 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -1133,4 +1133,16 @@ static inline struct ice_hw *ice_get_primary_hw(stru= ct ice_pf *pf) else return &pf->adapter->ctrl_pf->hw; } + +/** + * ice_get_ctrl_pf - Get pointer to Control PF of the adapter + * @pf: pointer to the current PF structure + * + * Return: A pointer to ice_pf structure which is Control PF, + * NULL if it's not initialized yet. + */ +static inline struct ice_pf *ice_get_ctrl_pf(struct ice_pf *pf) +{ + return !pf->adapter ? NULL : pf->adapter->ctrl_pf; +} #endif /* _ICE_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethern= et/intel/ice/ice_dpll.c index 72518fd1398d..ac0bfc2f0f0e 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -4,6 +4,7 @@ #include "ice.h" #include "ice_lib.h" #include "ice_trace.h" +#include "ice_txclk.h" #include #include =20 @@ -2538,7 +2539,9 @@ ice_dpll_rclk_state_on_pin_get(const struct dpll_pin = *pin, void *pin_priv, * * Dpll subsystem callback, set a state of a Tx reference clock pin * + * Context: Acquires and releases pf->dplls.lock * Return: + * * 0 - success * * negative - failure */ static int @@ -2547,11 +2550,24 @@ ice_dpll_txclk_state_on_dpll_set(const struct dpll_= pin *pin, void *pin_priv, 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; + struct ice_dpll_pin *p =3D pin_priv; + struct ice_pf *pf =3D p->pf; + enum ice_e825c_ref_clk new_clk; + int ret =3D 0; + + if (ice_dpll_is_reset(pf, extack)) + return -EBUSY; + + mutex_lock(&pf->dplls.lock); + new_clk =3D (state =3D=3D DPLL_PIN_STATE_DISCONNECTED) ? ICE_REF_CLK_ENET= : + p->tx_ref_src; + if (new_clk =3D=3D pf->ptp.port.tx_clk) + goto unlock; + + ret =3D ice_txclk_set_clk(pf, new_clk); +unlock: + mutex_unlock(&pf->dplls.lock); + return ret; } =20 /** @@ -2565,8 +2581,10 @@ ice_dpll_txclk_state_on_dpll_set(const struct dpll_p= in *pin, void *pin_priv, * * dpll subsystem callback, get a state of a TX clock reference pin. * + * Context: Acquires and releases pf->dplls.lock * Return: * * 0 - success + * * negative - failure */ static int ice_dpll_txclk_state_on_dpll_get(const struct dpll_pin *pin, void *pin_pri= v, @@ -2575,13 +2593,26 @@ ice_dpll_txclk_state_on_dpll_get(const struct dpll_= pin *pin, void *pin_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 =3D DPLL_PIN_STATE_DISCONNECTED; + struct ice_dpll_pin *p =3D pin_priv; + enum ice_e825c_ref_clk clk; + struct ice_pf *pf =3D p->pf; + int ret; =20 - return 0; + if (ice_dpll_is_reset(pf, extack)) + return -EBUSY; + + mutex_lock(&pf->dplls.lock); + ret =3D ice_get_serdes_ref_sel_e825c(&pf->hw, pf->ptp.port.port_num, + &clk); + if (ret) + goto unlock; + + *state =3D (clk =3D=3D p->tx_ref_src) ? DPLL_PIN_STATE_CONNECTED : + DPLL_PIN_STATE_DISCONNECTED; +unlock: + mutex_unlock(&pf->dplls.lock); + + return ret; } =20 static const struct dpll_pin_ops ice_dpll_rclk_ops =3D { diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/etherne= t/intel/ice/ice_ptp.c index 094e96219f45..a75a1380097b 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -4,6 +4,7 @@ #include "ice.h" #include "ice_lib.h" #include "ice_trace.h" +#include "ice_txclk.h" =20 static const char ice_pin_names[][64] =3D { "SDP0", @@ -54,11 +55,6 @@ static const struct ice_ptp_pin_desc ice_pin_desc_dpll[]= =3D { { SDP3, { 3, -1 }, { 0, 0 }}, }; =20 -static struct ice_pf *ice_get_ctrl_pf(struct ice_pf *pf) -{ - return !pf->adapter ? NULL : pf->adapter->ctrl_pf; -} - static struct ice_ptp *ice_get_ctrl_ptp(struct ice_pf *pf) { struct ice_pf *ctrl_pf =3D ice_get_ctrl_pf(pf); @@ -1325,6 +1321,10 @@ void ice_ptp_link_change(struct ice_pf *pf, bool lin= kup) return; } } + + if (linkup) + ice_txclk_verify(pf); + mutex_unlock(&pf->dplls.lock); } =20 @@ -3079,6 +3079,7 @@ static int ice_ptp_setup_pf(struct ice_pf *pf) { struct ice_ptp *ctrl_ptp =3D ice_get_ctrl_ptp(pf); struct ice_ptp *ptp =3D &pf->ptp; + u8 port_num, phy; =20 if (WARN_ON(!ctrl_ptp) || pf->hw.mac_type =3D=3D ICE_MAC_UNKNOWN) return -ENODEV; @@ -3090,6 +3091,10 @@ static int ice_ptp_setup_pf(struct ice_pf *pf) &pf->adapter->ports.ports); mutex_unlock(&pf->adapter->ports.lock); =20 + port_num =3D ptp->port.port_num; + phy =3D port_num / pf->hw.ptp.ports_per_phy; + set_bit(port_num, &ctrl_ptp->tx_refclks[phy][pf->ptp.port.tx_clk]); + return 0; } =20 @@ -3290,6 +3295,7 @@ static void ice_ptp_init_tx_interrupt_mode(struct ice= _pf *pf) */ void ice_ptp_init(struct ice_pf *pf) { + enum ice_e825c_ref_clk tx_ref_clk; struct ice_ptp *ptp =3D &pf->ptp; struct ice_hw *hw =3D &pf->hw; int err; @@ -3318,6 +3324,17 @@ void ice_ptp_init(struct ice_pf *pf) goto err_exit; } =20 + ptp->port.tx_clk =3D ICE_REF_CLK_ENET; + ptp->port.tx_clk_req =3D ICE_REF_CLK_ENET; + if (hw->mac_type =3D=3D ICE_MAC_GENERIC_3K_E825) { + err =3D ice_get_serdes_ref_sel_e825c(hw, ptp->port.port_num, + &tx_ref_clk); + if (!err) { + ptp->port.tx_clk =3D tx_ref_clk; + ptp->port.tx_clk_req =3D tx_ref_clk; + } + } + err =3D ice_ptp_setup_pf(pf); if (err) goto err_exit; diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/etherne= t/intel/ice/ice_ptp.h index 8c44bd758a4f..8b385271ab36 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp.h @@ -144,6 +144,8 @@ struct ice_ptp_tx { * @link_up: indicates whether the link is up * @tx_fifo_busy_cnt: number of times the Tx FIFO was busy * @port_num: the port number this structure represents + * @tx_clk: currently active Tx reference clock source + * @tx_clk_req: requested Tx reference clock source (new target) */ struct ice_ptp_port { struct list_head list_node; @@ -153,6 +155,8 @@ struct ice_ptp_port { bool link_up; u8 tx_fifo_busy_cnt; u8 port_num; + enum ice_e825c_ref_clk tx_clk; + enum ice_e825c_ref_clk tx_clk_req; }; =20 enum ice_ptp_tx_interrupt { @@ -236,6 +240,7 @@ struct ice_ptp_pin_desc { * @info: structure defining PTP hardware capabilities * @clock: pointer to registered PTP clock device * @tstamp_config: hardware timestamping configuration + * @tx_refclks: bitmaps table to store the information about TX reference = clocks * @reset_time: kernel time after clock stop on reset * @tx_hwtstamp_good: number of completed Tx timestamp requests * @tx_hwtstamp_skipped: number of Tx time stamp requests skipped @@ -261,6 +266,8 @@ struct ice_ptp { struct ptp_clock_info info; struct ptp_clock *clock; struct kernel_hwtstamp_config tstamp_config; +#define ICE_E825_MAX_PHYS 2 + unsigned long tx_refclks[ICE_E825_MAX_PHYS][ICE_REF_CLK_MAX]; u64 reset_time; u64 tx_hwtstamp_good; u32 tx_hwtstamp_skipped; diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethe= rnet/intel/ice/ice_ptp_hw.c index 61c0a0d93ea8..c0720525ac49 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c @@ -461,6 +461,43 @@ static int ice_read_phy_eth56g(struct ice_hw *hw, u8 p= ort, u32 addr, u32 *val) return err; } =20 +/** + * ice_get_serdes_ref_sel_e825c - Read current Tx ref clock source + * @hw: pointer to the HW struct + * @port: port number for which Tx reference clock is read + * @clk: Tx reference clock value (output) + * + * Return: 0 on success, other error codes when failed to read from PHY + */ +int ice_get_serdes_ref_sel_e825c(struct ice_hw *hw, u8 port, + enum ice_e825c_ref_clk *clk) +{ + u8 lane =3D port % hw->ptp.ports_per_phy; + u32 serdes_rx_nt, serdes_tx_nt; + u32 val; + int ret; + + ret =3D ice_read_phy_eth56g(hw, port, + SERDES_IP_IF_LN_FLXM_GENERAL(lane, 0), + &val); + if (ret) + return ret; + + serdes_rx_nt =3D FIELD_GET(CFG_ICTL_PCS_REF_SEL_RX_NT, val); + serdes_tx_nt =3D FIELD_GET(CFG_ICTL_PCS_REF_SEL_TX_NT, val); + + if (serdes_tx_nt =3D=3D REF_SEL_NT_SYNCE && + serdes_rx_nt =3D=3D REF_SEL_NT_SYNCE) + *clk =3D ICE_REF_CLK_SYNCE; + else if (serdes_tx_nt =3D=3D REF_SEL_NT_EREF0 && + serdes_rx_nt =3D=3D REF_SEL_NT_EREF0) + *clk =3D ICE_REF_CLK_EREF0; + else + *clk =3D ICE_REF_CLK_ENET; + + return 0; +} + /** * ice_phy_res_address_eth56g - Calculate a PHY port register address * @hw: pointer to the HW struct diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethe= rnet/intel/ice/ice_ptp_hw.h index cbc9693179a1..820ba953ea01 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h @@ -381,6 +381,8 @@ int ice_stop_phy_timer_eth56g(struct ice_hw *hw, u8 por= t, bool soft_reset); int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port); int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 thres= hold); int ice_phy_cfg_ptp_1step_eth56g(struct ice_hw *hw, u8 port); +int ice_get_serdes_ref_sel_e825c(struct ice_hw *hw, u8 port, + enum ice_e825c_ref_clk *clk); =20 #define ICE_ETH56G_NOMINAL_INCVAL 0x140000000ULL #define ICE_ETH56G_NOMINAL_PCS_REF_TUS 0x100000000ULL @@ -790,4 +792,29 @@ static inline u64 ice_get_base_incval(struct ice_hw *h= w) #define PHY_PTP_1STEP_PD_DELAY_M GENMASK(30, 1) #define PHY_PTP_1STEP_PD_DLY_V_M BIT(31) =20 +#define SERDES_IP_IF_LN_FLXM_GENERAL(n, m) \ + (0x32B800 + (m) * 0x100000 + (n) * 0x8000) +#define CFG_RESERVED0_1 GENMASK(1, 0) +#define CFG_ICTL_PCS_MODE_NT BIT(2) +#define CFG_ICTL_PCS_RCOMP_SLAVE_EN_NT BIT(3) +#define CFG_ICTL_PCS_CMN_FORCE_PUP_A BIT(4) +#define CFG_ICTL_PCS_RCOMP_SLAVE_VALID_A BIT(5) +#define CFG_ICTL_PCS_REF_SEL_RX_NT GENMASK(9, 6) +#define REF_SEL_NT_ENET 0 +#define REF_SEL_NT_EREF0 1 +#define REF_SEL_NT_SYNCE 2 +#define CFG_IDAT_DFX_OBS_DIG_ GENMASK(11, 10) +#define CFG_IRST_APB_MEM_B BIT(12) +#define CFG_ICTL_PCS_DISCONNECT_NT BIT(13) +#define CFG_ICTL_PCS_ISOLATE_NT BIT(14) +#define CFG_RESERVED15_15 BIT(15) +#define CFG_IRST_PCS_TSTBUS_B_A BIT(16) +#define CFG_ICTL_PCS_REF_TERM_HIZ_EN_NT BIT(17) +#define CFG_RESERVED18_19 GENMASK(19, 18) +#define CFG_ICTL_PCS_SYNTHLCSLOW_FORCE_PUP_A BIT(20) +#define CFG_ICTL_PCS_SYNTHLCFAST_FORCE_PUP_A BIT(21) +#define CFG_RESERVED22_24 GENMASK(24, 22) +#define CFG_ICTL_PCS_REF_SEL_TX_NT GENMASK(28, 25) +#define CFG_RESERVED29_31 GENMASK(31, 29) + #endif /* _ICE_PTP_HW_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_txclk.c b/drivers/net/ether= net/intel/ice/ice_txclk.c new file mode 100644 index 000000000000..ccb8411dca94 --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_txclk.c @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2026 Intel Corporation */ + +#include "ice.h" +#include "ice_cpi.h" +#include "ice_txclk.h" + +#define ICE_PHY0 0 +#define ICE_PHY1 1 + +/** + * ice_txclk_enable_peer - Enable required TX reference clock on peer PHY + * @pf: pointer to the PF structure + * @clk: TX reference clock that must be enabled + * + * Some TX reference clocks on E825-class devices (SyncE and EREF0) must + * be enabled on both PHY complexes to allow proper routing: + * + * - SyncE must be enabled on both PHYs when used by PHY0 + * - EREF0 must be enabled on both PHYs when used by PHY1 + * + * If the requested clock is not yet enabled on the peer PHY, enable it. + * ENET does not require duplication and is ignored. + * + * Return: 0 on success or negative error code on failure. + */ +static int ice_txclk_enable_peer(struct ice_pf *pf, enum ice_e825c_ref_clk= clk) +{ + struct ice_pf *ctrl_pf =3D ice_get_ctrl_pf(pf); + u8 port_num, phy; + int err; + + if (clk =3D=3D ICE_REF_CLK_ENET) + return 0; + + if (IS_ERR_OR_NULL(ctrl_pf)) { + dev_err(ice_pf_to_dev(pf), + "Can't enable tx-clk on peer: no controlling PF\n"); + return -EINVAL; + } + + port_num =3D pf->ptp.port.port_num; + phy =3D port_num / pf->hw.ptp.ports_per_phy; + + if ((clk =3D=3D ICE_REF_CLK_SYNCE && phy =3D=3D ICE_PHY0 && + !ice_txclk_any_port_uses(ctrl_pf, ICE_PHY1, clk)) || + (clk =3D=3D ICE_REF_CLK_EREF0 && phy =3D=3D ICE_PHY1 && + !ice_txclk_any_port_uses(ctrl_pf, ICE_PHY0, clk))) { + u8 peer_phy =3D phy ? ICE_PHY0 : ICE_PHY1; + + err =3D ice_cpi_ena_dis_clk_ref(&pf->hw, peer_phy, clk, true); + if (err) { + dev_err(ice_hw_to_dev(&pf->hw), + "Failed to enable the %u TX clock for the %u PHY\n", + clk, peer_phy); + return err; + } + } + + return 0; +} + +/** + * ice_txclk_disable_unused - Disable TX reference clock no longer in use + * @pf: pointer to the PF structure + * @ref_clk: TX reference clock source to evaluate for disabling + * + * Disable (from power-saving reasons) a TX reference clock after a clock + * switch, provided that: + * - no port on the local PHY uses this clock, and + * - for SyncE: no port on PHY0 or PHY1 requires the clock, depending on + * where it must remain enabled for routing. + * - for EREF0: same logic as above but inverted PHY roles. + * + * Some reference clocks must be enabled on both PHY complexes when used + * (SyncE for PHY0, EREF0 for PHY1). The function therefore also attempts + * to implicitly disable the peer PHY copy when no port requires it. + * + * Return: 0 on success or negative error code if disabling fails. + */ +static int +ice_txclk_disable_unused(struct ice_pf *pf, enum ice_e825c_ref_clk ref_clk) +{ + struct ice_pf *ctrl_pf =3D ice_get_ctrl_pf(pf); + struct ice_hw *hw =3D &pf->hw; + int err =3D 0; + u8 cur_phy; + + if (IS_ERR_OR_NULL(ctrl_pf)) { + dev_err(ice_pf_to_dev(pf), + "Can't disable unused tx-clk: no controlling PF\n"); + return -EINVAL; + } + + cur_phy =3D pf->ptp.port.port_num / hw->ptp.ports_per_phy; + + if (ref_clk =3D=3D ICE_REF_CLK_SYNCE) { + /* Don't disable SyncE clock if it's still in use on PHY 0 */ + if (ice_txclk_any_port_uses(ctrl_pf, ICE_PHY0, ref_clk)) + return 0; + if (cur_phy =3D=3D ICE_PHY0 && + !ice_txclk_any_port_uses(ctrl_pf, ICE_PHY1, ref_clk)) { + err =3D ice_cpi_ena_dis_clk_ref(hw, ICE_PHY1, ref_clk, + false); + if (err) { + cur_phy =3D ICE_PHY1; + goto err; + } + } + } else if (ref_clk =3D=3D ICE_REF_CLK_EREF0) { + /* Don't disable EREF0 clock if it's still in use on PHY 1 */ + if (ice_txclk_any_port_uses(ctrl_pf, ICE_PHY1, ref_clk)) + return 0; + if (cur_phy =3D=3D ICE_PHY1 && + !ice_txclk_any_port_uses(ctrl_pf, ICE_PHY0, ref_clk)) { + err =3D ice_cpi_ena_dis_clk_ref(hw, ICE_PHY0, ref_clk, + false); + if (err) { + cur_phy =3D ICE_PHY0; + goto err; + } + } + } + + if (!ice_txclk_any_port_uses(ctrl_pf, cur_phy, ref_clk)) + err =3D ice_cpi_ena_dis_clk_ref(hw, cur_phy, ref_clk, false); +err: + if (err) + dev_warn(ice_pf_to_dev(pf), "Failed to disable the %u TX clock for the %= u PHY\n", + ref_clk, cur_phy); + + return err; +} + +#define ICE_REFCLK_USER_TO_AQ_IDX(x) ((x) + 1) + +/** + * ice_txclk_set_clk - Set Tx reference clock + * @pf: pointer to pf structure + * @clk: new Tx clock + * + * Return: 0 on success, negative value otherwise. + */ +int ice_txclk_set_clk(struct ice_pf *pf, enum ice_e825c_ref_clk clk) +{ + struct ice_pf *ctrl_pf =3D ice_get_ctrl_pf(pf); + struct ice_port_info *port_info; + u8 port_num, phy; + int err; + + if (pf->ptp.port.tx_clk =3D=3D clk) + return 0; + + if (IS_ERR_OR_NULL(ctrl_pf)) { + dev_err(ice_pf_to_dev(pf), + "Can't set tx-clk: no controlling PF\n"); + return -EINVAL; + } + + port_num =3D pf->ptp.port.port_num; + phy =3D port_num / pf->hw.ptp.ports_per_phy; + port_info =3D pf->hw.port_info; + + /* Check if the TX clk is enabled for this PHY, if not - enable it */ + if (!ice_txclk_any_port_uses(ctrl_pf, phy, clk)) { + err =3D ice_cpi_ena_dis_clk_ref(&pf->hw, phy, clk, true); + if (err) { + dev_err(ice_hw_to_dev(&pf->hw), "Failed to enable the %u TX clock for t= he %u PHY\n", + clk, phy); + return err; + } + err =3D ice_txclk_enable_peer(pf, clk); + if (err) + return err; + } + + pf->ptp.port.tx_clk_req =3D clk; + + /* We are ready to switch to the new TX clk. */ + err =3D ice_aq_set_link_restart_an(port_info, true, NULL, + ICE_REFCLK_USER_TO_AQ_IDX(clk)); + if (err) + dev_err(ice_hw_to_dev(&pf->hw), "Failed to switch to %u TX clock for the= %u PHY\n", + clk, phy); + + return err; +} + +/** + * ice_txclk_verify - Validate TX reference clock switch and update usage = state + * @pf: pointer to PF structure + * + * After a link-up event, verify whether the previously requested TX refer= ence + * clock transition actually succeeded. The SERDES reference selector refl= ects + * the effective hardware choice, which may differ from the requested clock + * when Auto-Negotiation or firmware applies additional policy. + * + * If the hardware-selected clock differs from the requested one, update t= he + * software state accordingly and stop further processing. + * + * When the switch is successful, update the per=E2=80=91PHY usage bitmaps= so that the + * driver knows which reference clock is currently in use by this port. Us= ing + * these bitmaps, disable any reference clocks that are no longer required= by + * any port on the local PHY or, when applicable, on the peer PHY (accordi= ng + * to E825 clock=E2=80=91routing rules). + * + * This function does not initiate a clock switch; it only validates the r= esult + * of a previously triggered transition and performs cleanup of unused clo= cks. + */ +void ice_txclk_verify(struct ice_pf *pf) +{ + struct ice_ptp_port *ptp_port =3D &pf->ptp.port; + struct ice_pf *ctrl_pf =3D ice_get_ctrl_pf(pf); + struct ice_hw *hw =3D &pf->hw; + enum ice_e825c_ref_clk clk; + int err; + u8 phy; + + phy =3D ptp_port->port_num / hw->ptp.ports_per_phy; + + /* verify current Tx reference settings */ + err =3D ice_get_serdes_ref_sel_e825c(hw, + ptp_port->port_num, + &clk); + if (err) + return; + + if (clk !=3D pf->ptp.port.tx_clk_req) { + dev_warn(ice_pf_to_dev(pf), + "Failed to switch tx-clk for phy %d and clk %u (current: %u)\n", + phy, pf->ptp.port.tx_clk_req, clk); + pf->ptp.port.tx_clk =3D clk; + pf->ptp.port.tx_clk_req =3D clk; + return; + } + + if (IS_ERR_OR_NULL(ctrl_pf)) { + dev_err(ice_pf_to_dev(pf), + "Can't set tx-clk: no controlling PF\n"); + return; + } + + /* update Tx reference clock usage map */ + for (int i =3D 0; i < ICE_REF_CLK_MAX; i++) + (clk =3D=3D i) ? + set_bit(ptp_port->port_num, + &ctrl_pf->ptp.tx_refclks[phy][i]) : + clear_bit(ptp_port->port_num, + &ctrl_pf->ptp.tx_refclks[phy][i]); + + ice_txclk_disable_unused(pf, pf->ptp.port.tx_clk); + + pf->ptp.port.tx_clk =3D clk; + pf->ptp.port.tx_clk_req =3D clk; +} + diff --git a/drivers/net/ethernet/intel/ice/ice_txclk.h b/drivers/net/ether= net/intel/ice/ice_txclk.h new file mode 100644 index 000000000000..6423b448841e --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_txclk.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2026 Intel Corporation */ + +#ifndef _ICE_TXCLK_H_ +#define _ICE_TXCLK_H_ + +/** + * ice_txclk_any_port_uses - check if any port on a PHY uses this TX refclk + * @ctrl_pf: control PF (owner of the shared tx_refclks map) + * @phy: PHY index + * @clk: TX reference clock + * + * Return: true if any bit (port) is set for this clock on this PHY + */ +static inline bool +ice_txclk_any_port_uses(const struct ice_pf *ctrl_pf, u8 phy, + enum ice_e825c_ref_clk clk) +{ + return find_first_bit(&ctrl_pf->ptp.tx_refclks[phy][clk], + BITS_PER_LONG) < BITS_PER_LONG; +} + +/** + * ice_txclk_port_uses - check if a specific port uses this TX refclk + * @ctrl_pf: control PF + * @phy: PHY index + * @clk: TX reference clock + * @port: port number to test + * + * Return: true if this port uses the given clock + */ +static inline bool +ice_txclk_port_uses(const struct ice_pf *ctrl_pf, u8 phy, + enum ice_e825c_ref_clk clk, u8 port) +{ + return test_bit(port, &ctrl_pf->ptp.tx_refclks[phy][clk]); +} + +int ice_txclk_set_clk(struct ice_pf *pf, enum ice_e825c_ref_clk clk); +void ice_txclk_verify(struct ice_pf *pf); +#endif /* _ICE_TXCLK_H_ */ --=20 2.39.3