mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
dpll: add fractional frequency offset to pin-parent-device
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> Link: https://patch.msgid.link/20260511155816.99936-2-ivecera@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
28702a215c
commit
9c11fcb2e9
|
|
@ -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
|
||||
=================
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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] = {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user