From: Ivan Vecera <ivecera@redhat.com>
To: netdev@vger.kernel.org
Cc: Jiri Pirko <jiri@nvidia.com>, Andrew Lunn <andrew+netdev@lunn.ch>,
Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>,
"David S. Miller" <davem@davemloft.net>,
Donald Hunter <donald.hunter@gmail.com>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Jiri Pirko <jiri@resnulli.us>,
Jonathan Corbet <corbet@lwn.net>,
Leon Romanovsky <leon@kernel.org>, Mark Bloch <mbloch@nvidia.com>,
Michal Schmidt <mschmidt@redhat.com>,
Paolo Abeni <pabeni@redhat.com>,
Pasi Vaananen <pvaanane@redhat.com>, Petr Oros <poros@redhat.com>,
Prathosh Satish <Prathosh.Satish@microchip.com>,
Saeed Mahameed <saeedm@nvidia.com>,
Shuah Khan <skhan@linuxfoundation.org>,
Simon Horman <horms@kernel.org>, Tariq Toukan <tariqt@nvidia.com>,
Vadim Fedorenko <vadim.fedorenko@linux.dev>,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-rdma@vger.kernel.org
Subject: [PATCH net-next v4 1/2] dpll: add fractional frequency offset to pin-parent-device
Date: Mon, 11 May 2026 17:58:15 +0200 [thread overview]
Message-ID: <20260511155816.99936-2-ivecera@redhat.com> (raw)
In-Reply-To: <20260511155816.99936-1-ivecera@redhat.com>
Add both fractional-frequency-offset (PPM) and
fractional-frequency-offset-ppt (PPT) attributes to the
pin-parent-device nested attribute set, alongside the existing
top-level pin attributes. Both carry the same measurement at
different precisions.
Introduce enum dpll_ffo_type and struct dpll_ffo_param to
distinguish FFO contexts: DPLL_FFO_PORT_RXTX_RATE for the RX vs
TX symbol rate offset reported at the top level, and
DPLL_FFO_PIN_DEVICE for the pin vs parent DPLL offset reported
in the pin-parent-device nest.
Add a supported_ffo bitmask to struct dpll_pin_ops so drivers
declare which FFO types they support. The core only calls ffo_get
for types the driver has opted into, eliminating the need for
per-driver NULL pointer guards. Validate at pin registration time
that supported_ffo is not set without an ffo_get callback.
Update mlx5 (DPLL_FFO_PORT_RXTX_RATE) and zl3073x
(DPLL_FFO_PORT_RXTX_RATE) drivers to use the new API.
Add documentation for both FFO types to dpll.rst.
Changes v3 -> v4:
- Replace dpll=NULL overloading with enum dpll_ffo_type and
struct dpll_ffo_param (Jakub Kicinski)
- Add supported_ffo opt-in bitmask in dpll_pin_ops for fail-close
driver validation (Jakub Kicinski)
- Add WARN_ON in dpll_pin_register for supported_ffo without
ffo_get callback
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
Documentation/driver-api/dpll.rst | 20 +++++++++++++
Documentation/netlink/specs/dpll.yaml | 28 ++++++++++-------
drivers/dpll/dpll_core.c | 3 +-
drivers/dpll/dpll_netlink.c | 30 ++++++++++---------
drivers/dpll/dpll_nl.c | 2 ++
drivers/dpll/zl3073x/dpll.c | 6 ++--
.../net/ethernet/mellanox/mlx5/core/dpll.c | 6 ++--
include/linux/dpll.h | 16 +++++++++-
8 files changed, 81 insertions(+), 30 deletions(-)
diff --git a/Documentation/driver-api/dpll.rst b/Documentation/driver-api/dpll.rst
index 37eaef785e304..090cd4d017c3a 100644
--- a/Documentation/driver-api/dpll.rst
+++ b/Documentation/driver-api/dpll.rst
@@ -258,6 +258,26 @@ in the ``DPLL_A_PIN_PHASE_OFFSET`` attribute.
``DPLL_A_PHASE_OFFSET_MONITOR`` attr state of a feature
=============================== ========================
+Fractional frequency offset
+===========================
+
+The fractional frequency offset (FFO) is reported through two attributes
+that carry the same measurement at different precisions:
+
+- ``DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET`` in PPM (parts per million)
+- ``DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT`` in PPT (parts per trillion)
+
+Both attributes appear at the top level of a pin and inside each
+``pin-parent-device`` nest. Two FFO types are defined:
+
+- ``DPLL_FFO_PORT_RXTX_RATE`` - RX vs TX symbol rate offset (top-level)
+- ``DPLL_FFO_PIN_DEVICE`` - pin vs parent DPLL offset (per-parent)
+
+The driver declares which types it supports via the ``supported_ffo``
+bitmask in ``struct dpll_pin_ops``. The core only calls the ``ffo_get``
+callback for types the driver has opted into. The requested type is
+passed to the driver in the ``struct dpll_ffo_param``.
+
Frequency monitor
=================
diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml
index c45de70a47ce6..91a172617b3a9 100644
--- a/Documentation/netlink/specs/dpll.yaml
+++ b/Documentation/netlink/specs/dpll.yaml
@@ -448,12 +448,14 @@ attribute-sets:
name: fractional-frequency-offset
type: sint
doc: |
- The FFO (Fractional Frequency Offset) between the RX and TX
- symbol rate on the media associated with the pin:
- (rx_frequency-tx_frequency)/rx_frequency
+ The FFO (Fractional Frequency Offset) of the pin.
+ At top level this represents the RX vs TX symbol rate
+ offset on the media associated with the pin. Inside
+ the pin-parent-device nest it represents the frequency
+ offset between the pin and its parent DPLL device.
Value is in PPM (parts per million).
- This may be implemented for example for pin of type
- PIN_TYPE_SYNCE_ETH_PORT.
+ This is a lower-precision version of
+ fractional-frequency-offset-ppt.
-
name: esync-frequency
type: u64
@@ -492,12 +494,14 @@ attribute-sets:
name: fractional-frequency-offset-ppt
type: sint
doc: |
- The FFO (Fractional Frequency Offset) of the pin with respect to
- the nominal frequency.
- Value = (frequency_measured - frequency_nominal) / frequency_nominal
+ The FFO (Fractional Frequency Offset) of the pin.
+ At top level this represents the RX vs TX symbol rate
+ offset on the media associated with the pin. Inside
+ the pin-parent-device nest it represents the frequency
+ offset between the pin and its parent DPLL device.
Value is in PPT (parts per trillion, 10^-12).
- Note: This attribute provides higher resolution than the standard
- fractional-frequency-offset (which is in PPM).
+ This is a higher-precision version of
+ fractional-frequency-offset.
-
name: measured-frequency
type: u64
@@ -534,6 +538,10 @@ attribute-sets:
name: operstate
-
name: phase-offset
+ -
+ name: fractional-frequency-offset
+ -
+ name: fractional-frequency-offset-ppt
-
name: pin-parent-pin
subset-of: pin
diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c
index cbb635db43210..20a54728549cc 100644
--- a/drivers/dpll/dpll_core.c
+++ b/drivers/dpll/dpll_core.c
@@ -879,7 +879,8 @@ dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
WARN_ON(!ops->direction_get) ||
WARN_ON(ops->measured_freq_get &&
(!dpll_device_ops(dpll)->freq_monitor_get ||
- !dpll_device_ops(dpll)->freq_monitor_set)))
+ !dpll_device_ops(dpll)->freq_monitor_set)) ||
+ WARN_ON(ops->supported_ffo && !ops->ffo_get))
return -EINVAL;
mutex_lock(&dpll_lock);
diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c
index 05cf946b4be5e..00e8696cb267b 100644
--- a/drivers/dpll/dpll_netlink.c
+++ b/drivers/dpll/dpll_netlink.c
@@ -417,31 +417,28 @@ dpll_msg_add_phase_offset(struct sk_buff *msg, struct dpll_pin *pin,
static int dpll_msg_add_ffo(struct sk_buff *msg, struct dpll_pin *pin,
struct dpll_pin_ref *ref,
+ enum dpll_ffo_type type,
struct netlink_ext_ack *extack)
{
const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
- struct dpll_device *dpll = ref->dpll;
- s64 ffo;
+ struct dpll_ffo_param ffo = { .type = type };
int ret;
- if (!ops->ffo_get)
+ if (!ops->ffo_get || !(ops->supported_ffo & BIT(type)))
return 0;
- ret = ops->ffo_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
- dpll, dpll_priv(dpll), &ffo, extack);
+ ret = ops->ffo_get(pin, dpll_pin_on_dpll_priv(ref->dpll, pin),
+ ref->dpll, dpll_priv(ref->dpll), &ffo, extack);
if (ret) {
if (ret == -ENODATA)
return 0;
return ret;
}
- /* Put the FFO value in PPM to preserve compatibility with older
- * programs.
- */
- ret = nla_put_sint(msg, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET,
- div_s64(ffo, 1000000));
- if (ret)
+ if (nla_put_sint(msg, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET,
+ div_s64(ffo.ffo, 1000000)))
return -EMSGSIZE;
- return nla_put_sint(msg, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT,
- ffo);
+ return nla_put_sint(msg,
+ DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT,
+ ffo.ffo);
}
static int dpll_msg_add_measured_freq(struct sk_buff *msg, struct dpll_pin *pin,
@@ -686,6 +683,10 @@ dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin,
if (ret)
goto nest_cancel;
ret = dpll_msg_add_phase_offset(msg, pin, ref, extack);
+ if (ret)
+ goto nest_cancel;
+ ret = dpll_msg_add_ffo(msg, pin, ref,
+ DPLL_FFO_PIN_DEVICE, extack);
if (ret)
goto nest_cancel;
nla_nest_end(msg, attr);
@@ -748,7 +749,8 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
ret = dpll_msg_add_pin_phase_adjust(msg, pin, ref, extack);
if (ret)
return ret;
- ret = dpll_msg_add_ffo(msg, pin, ref, extack);
+ ret = dpll_msg_add_ffo(msg, pin, ref,
+ DPLL_FFO_PORT_RXTX_RATE, extack);
if (ret)
return ret;
ret = dpll_msg_add_measured_freq(msg, pin, ref, extack);
diff --git a/drivers/dpll/dpll_nl.c b/drivers/dpll/dpll_nl.c
index 58235845fa3d5..b1d9182c7802f 100644
--- a/drivers/dpll/dpll_nl.c
+++ b/drivers/dpll/dpll_nl.c
@@ -19,6 +19,8 @@ const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_OPERSTATE +
[DPLL_A_PIN_STATE] = NLA_POLICY_RANGE(NLA_U32, 1, 3),
[DPLL_A_PIN_OPERSTATE] = NLA_POLICY_RANGE(NLA_U32, 1, 4),
[DPLL_A_PIN_PHASE_OFFSET] = { .type = NLA_S64, },
+ [DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET] = { .type = NLA_SINT, },
+ [DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT] = { .type = NLA_SINT, },
};
const struct nla_policy dpll_pin_parent_pin_nl_policy[DPLL_A_PIN_STATE + 1] = {
diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
index 6fd718696de0d..05e63661bf074 100644
--- a/drivers/dpll/zl3073x/dpll.c
+++ b/drivers/dpll/zl3073x/dpll.c
@@ -295,11 +295,12 @@ zl3073x_dpll_input_pin_ref_sync_set(const struct dpll_pin *dpll_pin,
static int
zl3073x_dpll_input_pin_ffo_get(const struct dpll_pin *dpll_pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
- s64 *ffo, struct netlink_ext_ack *extack)
+ struct dpll_ffo_param *ffo,
+ struct netlink_ext_ack *extack)
{
struct zl3073x_dpll_pin *pin = pin_priv;
- *ffo = pin->freq_offset;
+ ffo->ffo = pin->freq_offset;
return 0;
}
@@ -1274,6 +1275,7 @@ zl3073x_dpll_freq_monitor_set(const struct dpll_device *dpll,
}
static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = {
+ .supported_ffo = BIT(DPLL_FFO_PORT_RXTX_RATE),
.direction_get = zl3073x_dpll_pin_direction_get,
.esync_get = zl3073x_dpll_input_pin_esync_get,
.esync_set = zl3073x_dpll_input_pin_esync_set,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c
index bce72e8d1bc31..7c69d9029bfa4 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c
@@ -300,7 +300,8 @@ static int mlx5_dpll_state_on_dpll_set(const struct dpll_pin *pin,
static int mlx5_dpll_ffo_get(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
- s64 *ffo, struct netlink_ext_ack *extack)
+ struct dpll_ffo_param *ffo,
+ struct netlink_ext_ack *extack)
{
struct mlx5_dpll_synce_status synce_status;
struct mlx5_dpll *mdpll = pin_priv;
@@ -309,10 +310,11 @@ static int mlx5_dpll_ffo_get(const struct dpll_pin *pin, void *pin_priv,
err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status);
if (err)
return err;
- return mlx5_dpll_pin_ffo_get(&synce_status, ffo);
+ return mlx5_dpll_pin_ffo_get(&synce_status, &ffo->ffo);
}
static const struct dpll_pin_ops mlx5_dpll_pins_ops = {
+ .supported_ffo = BIT(DPLL_FFO_PORT_RXTX_RATE),
.direction_get = mlx5_dpll_pin_direction_get,
.state_on_dpll_get = mlx5_dpll_state_on_dpll_get,
.state_on_dpll_set = mlx5_dpll_state_on_dpll_set,
diff --git a/include/linux/dpll.h b/include/linux/dpll.h
index b6f16c884b99e..945dfde9dc54d 100644
--- a/include/linux/dpll.h
+++ b/include/linux/dpll.h
@@ -60,7 +60,20 @@ struct dpll_device_ops {
struct netlink_ext_ack *extack);
};
+enum dpll_ffo_type {
+ DPLL_FFO_PORT_RXTX_RATE,
+ DPLL_FFO_PIN_DEVICE,
+
+ __DPLL_FFO_TYPE_MAX,
+};
+
+struct dpll_ffo_param {
+ enum dpll_ffo_type type;
+ s64 ffo;
+};
+
struct dpll_pin_ops {
+ unsigned long supported_ffo;
int (*frequency_set)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
const u64 frequency,
@@ -121,7 +134,8 @@ struct dpll_pin_ops {
struct netlink_ext_ack *extack);
int (*ffo_get)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
- s64 *ffo, struct netlink_ext_ack *extack);
+ struct dpll_ffo_param *ffo,
+ struct netlink_ext_ack *extack);
int (*measured_freq_get)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll,
void *dpll_priv, u64 *measured_freq,
--
2.53.0
next prev parent reply other threads:[~2026-05-11 15:58 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-11 15:58 [PATCH net-next v4 0/2] dpll: rework fractional frequency offset reporting Ivan Vecera
2026-05-11 15:58 ` Ivan Vecera [this message]
2026-05-11 15:58 ` [PATCH net-next v4 2/2] dpll: zl3073x: report FFO as DPLL vs input reference offset Ivan Vecera
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260511155816.99936-2-ivecera@redhat.com \
--to=ivecera@redhat.com \
--cc=Prathosh.Satish@microchip.com \
--cc=andrew+netdev@lunn.ch \
--cc=arkadiusz.kubalewski@intel.com \
--cc=corbet@lwn.net \
--cc=davem@davemloft.net \
--cc=donald.hunter@gmail.com \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=jiri@nvidia.com \
--cc=jiri@resnulli.us \
--cc=kuba@kernel.org \
--cc=leon@kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rdma@vger.kernel.org \
--cc=mbloch@nvidia.com \
--cc=mschmidt@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=poros@redhat.com \
--cc=pvaanane@redhat.com \
--cc=saeedm@nvidia.com \
--cc=skhan@linuxfoundation.org \
--cc=tariqt@nvidia.com \
--cc=vadim.fedorenko@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox