summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2026-05-13 04:48:10 +0300
committerJakub Kicinski <kuba@kernel.org>2026-05-13 04:48:10 +0300
commit8ebd24a7822cbae25beeafba49b2159d6a68a5f2 (patch)
tree5ddede51bd7aeffd51f82b03aa5b8cbd56d9508d
parent28702a215c96917d85558ad6309a57ab224808c0 (diff)
parent54e65df8cf18a741745645aed7ae91514d437b43 (diff)
downloadlinux-8ebd24a7822cbae25beeafba49b2159d6a68a5f2.tar.xz
Merge branch 'dpll-rework-fractional-frequency-offset-reporting'
Ivan Vecera says: ==================== dpll: rework fractional frequency offset reporting Rework how the fractional frequency offset (FFO) is reported in the DPLL subsystem. Both fractional-frequency-offset (PPM) and fractional-frequency-offset-ppt (PPT) attributes are now present at the top level of a pin and inside each pin-parent-device nest. They 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 at the top level, and DPLL_FFO_PIN_DEVICE for the pin vs parent DPLL offset in the nest. Drivers declare which types they support via the supported_ffo bitmask in dpll_pin_ops; the core only calls ffo_get for opted-in types. Patch 1 adds the type-safe FFO API, updates the YAML spec, netlink handling, and documentation, and converts mlx5 and zl3073x drivers. Patch 2 implements the nested FFO for zl3073x using the dpll_df_offset_x register with ref_ofst=1, providing 2^-48 resolution. The old per-reference frequency measurement is removed as it was redundant with measured-frequency. ==================== Link: https://patch.msgid.link/20260511155816.99936-1-ivecera@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--Documentation/driver-api/dpll.rst20
-rw-r--r--Documentation/netlink/specs/dpll.yaml28
-rw-r--r--drivers/dpll/dpll_core.c3
-rw-r--r--drivers/dpll/dpll_netlink.c30
-rw-r--r--drivers/dpll/dpll_nl.c2
-rw-r--r--drivers/dpll/zl3073x/chan.c31
-rw-r--r--drivers/dpll/zl3073x/chan.h14
-rw-r--r--drivers/dpll/zl3073x/core.c45
-rw-r--r--drivers/dpll/zl3073x/dpll.c40
-rw-r--r--drivers/dpll/zl3073x/ref.h14
-rw-r--r--drivers/dpll/zl3073x/regs.h15
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/dpll.c6
-rw-r--r--include/linux/dpll.h16
13 files changed, 154 insertions, 110 deletions
diff --git a/Documentation/driver-api/dpll.rst b/Documentation/driver-api/dpll.rst
index 37eaef785e30..bae14766d4f7 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 c45de70a47ce..91a172617b3a 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 cbb635db4321..20a54728549c 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 ea6360263786..53ca24d0f191 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,
@@ -688,6 +685,10 @@ dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin,
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 58235845fa3d..b1d9182c7802 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/chan.c b/drivers/dpll/zl3073x/chan.c
index 2f48ca239149..2fe3c3da84bb 100644
--- a/drivers/dpll/zl3073x/chan.c
+++ b/drivers/dpll/zl3073x/chan.c
@@ -18,6 +18,7 @@
int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index)
{
struct zl3073x_chan *chan = &zldev->chan[index];
+ u64 val;
int rc;
rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MON_STATUS(index),
@@ -25,8 +26,34 @@ int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index)
if (rc)
return rc;
- return zl3073x_read_u8(zldev, ZL_REG_DPLL_REFSEL_STATUS(index),
- &chan->refsel_status);
+ rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_REFSEL_STATUS(index),
+ &chan->refsel_status);
+ if (rc)
+ return rc;
+
+ /* Read df_offset vs tracked reference */
+ rc = zl3073x_poll_zero_u8(zldev, ZL_REG_DPLL_DF_READ(index),
+ ZL_DPLL_DF_READ_SEM);
+ if (rc)
+ return rc;
+
+ rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_DF_READ(index),
+ ZL_DPLL_DF_READ_SEM | ZL_DPLL_DF_READ_REF_OFST);
+ if (rc)
+ return rc;
+
+ rc = zl3073x_poll_zero_u8(zldev, ZL_REG_DPLL_DF_READ(index),
+ ZL_DPLL_DF_READ_SEM);
+ if (rc)
+ return rc;
+
+ rc = zl3073x_read_u48(zldev, ZL_REG_DPLL_DF_OFFSET(index), &val);
+ if (rc)
+ return rc;
+
+ chan->df_offset = sign_extend64(val, 47);
+
+ return 0;
}
/**
diff --git a/drivers/dpll/zl3073x/chan.h b/drivers/dpll/zl3073x/chan.h
index 481da2133202..4353809c6912 100644
--- a/drivers/dpll/zl3073x/chan.h
+++ b/drivers/dpll/zl3073x/chan.h
@@ -17,6 +17,7 @@ struct zl3073x_dev;
* @ref_prio: reference priority registers (4 bits per ref, P/N packed)
* @mon_status: monitor status register value
* @refsel_status: reference selection status register value
+ * @df_offset: frequency offset vs tracked reference in 2^-48 steps
*/
struct zl3073x_chan {
struct_group(cfg,
@@ -26,6 +27,7 @@ struct zl3073x_chan {
struct_group(stat,
u8 mon_status;
u8 refsel_status;
+ s64 df_offset;
);
};
@@ -38,6 +40,18 @@ int zl3073x_chan_state_set(struct zl3073x_dev *zldev, u8 index,
int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index);
/**
+ * zl3073x_chan_df_offset_get - get cached df_offset vs tracked reference
+ * @chan: pointer to channel state
+ *
+ * Return: frequency offset in 2^-48 steps
+ */
+static inline s64
+zl3073x_chan_df_offset_get(const struct zl3073x_chan *chan)
+{
+ return chan->df_offset;
+}
+
+/**
* zl3073x_chan_mode_get - get DPLL channel operating mode
* @chan: pointer to channel state
*
diff --git a/drivers/dpll/zl3073x/core.c b/drivers/dpll/zl3073x/core.c
index 5f1e70f3e40a..b3345060490d 100644
--- a/drivers/dpll/zl3073x/core.c
+++ b/drivers/dpll/zl3073x/core.c
@@ -704,44 +704,6 @@ zl3073x_ref_freq_meas_update(struct zl3073x_dev *zldev)
return 0;
}
-/**
- * zl3073x_ref_ffo_update - update reference fractional frequency offsets
- * @zldev: pointer to zl3073x_dev structure
- *
- * The function asks device to latch the latest measured fractional
- * frequency offset values, reads and stores them into the ref state.
- *
- * Return: 0 on success, <0 on error
- */
-static int
-zl3073x_ref_ffo_update(struct zl3073x_dev *zldev)
-{
- int i, rc;
-
- rc = zl3073x_ref_freq_meas_latch(zldev,
- ZL_REF_FREQ_MEAS_CTRL_REF_FREQ_OFF);
- if (rc)
- return rc;
-
- /* Read DPLL-to-REFx frequency offset measurements */
- for (i = 0; i < ZL3073X_NUM_REFS; i++) {
- s32 value;
-
- /* Read value stored in units of 2^-32 signed */
- rc = zl3073x_read_u32(zldev, ZL_REG_REF_FREQ(i), &value);
- if (rc)
- return rc;
-
- /* Convert to ppt
- * ffo = (10^12 * value) / 2^32
- * ffo = ( 5^12 * value) / 2^20
- */
- zldev->ref[i].ffo = mul_s64_u64_shr(value, 244140625, 20);
- }
-
- return 0;
-}
-
static void
zl3073x_dev_periodic_work(struct kthread_work *work)
{
@@ -776,13 +738,6 @@ zl3073x_dev_periodic_work(struct kthread_work *work)
}
}
- /* Update references' fractional frequency offsets */
- rc = zl3073x_ref_ffo_update(zldev);
- if (rc)
- dev_warn(zldev->dev,
- "Failed to update fractional frequency offsets: %pe\n",
- ERR_PTR(rc));
-
list_for_each_entry(zldpll, &zldev->dplls, list)
zl3073x_dpll_changes_check(zldpll);
diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
index 6fd718696de0..cff85cdb9d0e 100644
--- a/drivers/dpll/zl3073x/dpll.c
+++ b/drivers/dpll/zl3073x/dpll.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/atomic.h>
#include <linux/bits.h>
#include <linux/bitfield.h>
#include <linux/bug.h>
@@ -57,7 +58,7 @@ struct zl3073x_dpll_pin {
s32 phase_gran;
enum dpll_pin_operstate operstate;
s64 phase_offset;
- s64 freq_offset;
+ atomic64_t freq_offset;
u32 measured_freq;
};
@@ -295,11 +296,15 @@ 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;
+ if (pin->operstate != DPLL_PIN_OPERSTATE_ACTIVE)
+ return -ENODATA;
+
+ ffo->ffo = atomic64_read(&pin->freq_offset);
return 0;
}
@@ -1274,6 +1279,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_PIN_DEVICE),
.direction_get = zl3073x_dpll_pin_direction_get,
.esync_get = zl3073x_dpll_input_pin_esync_get,
.esync_set = zl3073x_dpll_input_pin_esync_set,
@@ -1729,37 +1735,29 @@ zl3073x_dpll_pin_phase_offset_check(struct zl3073x_dpll_pin *pin)
}
/**
- * zl3073x_dpll_pin_ffo_check - check for pin fractional frequency offset change
+ * zl3073x_dpll_pin_ffo_check - check for FFO change on active pin
* @pin: pin to check
*
- * Check for the given pin's fractional frequency change.
- *
- * Return: true on fractional frequency offset change, false otherwise
+ * Return: true on change, false otherwise
*/
static bool
zl3073x_dpll_pin_ffo_check(struct zl3073x_dpll_pin *pin)
{
struct zl3073x_dpll *zldpll = pin->dpll;
struct zl3073x_dev *zldev = zldpll->dev;
- const struct zl3073x_ref *ref;
- u8 ref_id;
+ const struct zl3073x_chan *chan;
s64 ffo;
- /* Get reference monitor status */
- ref_id = zl3073x_input_pin_ref_get(pin->id);
- ref = zl3073x_ref_state_get(zldev, ref_id);
-
- /* Do not report ffo changes if the reference monitor report errors */
- if (!zl3073x_ref_is_status_ok(ref))
+ if (pin->operstate != DPLL_PIN_OPERSTATE_ACTIVE)
return false;
- /* Compare with previous value */
- ffo = zl3073x_ref_ffo_get(ref);
- if (pin->freq_offset != ffo) {
- dev_dbg(zldev->dev, "%s freq offset changed: %lld -> %lld\n",
- pin->label, pin->freq_offset, ffo);
- pin->freq_offset = ffo;
+ chan = zl3073x_chan_state_get(zldpll->dev, zldpll->id);
+ ffo = mul_s64_u64_shr(zl3073x_chan_df_offset_get(chan),
+ 244140625, 36);
+ if (atomic64_xchg(&pin->freq_offset, ffo) != ffo) {
+ dev_dbg(zldev->dev, "%s freq offset changed to: %lld\n",
+ pin->label, ffo);
return true;
}
diff --git a/drivers/dpll/zl3073x/ref.h b/drivers/dpll/zl3073x/ref.h
index 55e80e4f0873..e140ca3ea17d 100644
--- a/drivers/dpll/zl3073x/ref.h
+++ b/drivers/dpll/zl3073x/ref.h
@@ -22,7 +22,6 @@ struct zl3073x_dev;
* @freq_ratio_n: FEC mode divisor
* @sync_ctrl: reference sync control
* @config: reference config
- * @ffo: current fractional frequency offset
* @meas_freq: measured input frequency in Hz
* @mon_status: reference monitor status
*/
@@ -40,7 +39,6 @@ struct zl3073x_ref {
u8 config;
);
struct_group(stat, /* Status */
- s64 ffo;
u32 meas_freq;
u8 mon_status;
);
@@ -59,18 +57,6 @@ int zl3073x_ref_state_update(struct zl3073x_dev *zldev, u8 index);
int zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult);
/**
- * zl3073x_ref_ffo_get - get current fractional frequency offset
- * @ref: pointer to ref state
- *
- * Return: the latest measured fractional frequency offset
- */
-static inline s64
-zl3073x_ref_ffo_get(const struct zl3073x_ref *ref)
-{
- return ref->ffo;
-}
-
-/**
* zl3073x_ref_meas_freq_get - get measured input frequency
* @ref: pointer to ref state
*
diff --git a/drivers/dpll/zl3073x/regs.h b/drivers/dpll/zl3073x/regs.h
index 8015808bdf54..9578f0009528 100644
--- a/drivers/dpll/zl3073x/regs.h
+++ b/drivers/dpll/zl3073x/regs.h
@@ -164,6 +164,11 @@
#define ZL_DPLL_MODE_REFSEL_MODE_NCO 4
#define ZL_DPLL_MODE_REFSEL_REF GENMASK(7, 4)
+#define ZL_REG_DPLL_DF_READ(_idx) \
+ ZL_REG_IDX(_idx, 5, 0x28, 1, ZL3073X_MAX_CHANNELS, 1)
+#define ZL_DPLL_DF_READ_SEM BIT(4)
+#define ZL_DPLL_DF_READ_REF_OFST BIT(3)
+
#define ZL_REG_DPLL_MEAS_CTRL ZL_REG(5, 0x50, 1)
#define ZL_DPLL_MEAS_CTRL_EN BIT(0)
#define ZL_DPLL_MEAS_CTRL_AVG_FACTOR GENMASK(7, 4)
@@ -176,6 +181,16 @@
#define ZL_REG_DPLL_PHASE_ERR_DATA(_idx) \
ZL_REG_IDX(_idx, 5, 0x55, 6, ZL3073X_MAX_CHANNELS, 6)
+/*******************************
+ * Register Pages 6-7, DPLL Data
+ *******************************/
+
+#define ZL_REG_DPLL_DF_OFFSET_03(_idx) \
+ ZL_REG_IDX(_idx, 6, 0x00, 6, 4, 0x20)
+#define ZL_REG_DPLL_DF_OFFSET_4 ZL_REG(7, 0x00, 6)
+#define ZL_REG_DPLL_DF_OFFSET(_idx) \
+ ((_idx) < 4 ? ZL_REG_DPLL_DF_OFFSET_03(_idx) : ZL_REG_DPLL_DF_OFFSET_4)
+
/***********************************
* Register Page 9, Synth and Output
***********************************/
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c
index bce72e8d1bc3..7c69d9029bfa 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 193abfb6ce66..82dfadd9f593 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,