Merge branch 'dpll-expose-fractional-frequency-offset-value-to-user'

Jiri Pirko says:

====================
dpll: expose fractional frequency offset value to user

Allow to expose pin fractional frequency offset value over new DPLL
generic netlink attribute. Add an op to get the value from the driver.
Implement this new op in mlx5 driver.
====================

Link: https://lore.kernel.org/r/20240103132838.1501801-1-jiri@resnulli.us
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2024-01-05 07:58:21 -08:00
commit aa537fee61
5 changed files with 98 additions and 35 deletions

View file

@ -296,6 +296,16 @@ attribute-sets:
- -
name: phase-offset name: phase-offset
type: s64 type: s64
-
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
Value is in PPM (parts per million).
This may be implemented for example for pin of type
PIN_TYPE_SYNCE_ETH_PORT.
- -
name: pin-parent-device name: pin-parent-device
subset-of: pin subset-of: pin
@ -460,6 +470,7 @@ operations:
- phase-adjust-min - phase-adjust-min
- phase-adjust-max - phase-adjust-max
- phase-adjust - phase-adjust
- fractional-frequency-offset
dump: dump:
pre: dpll-lock-dumpit pre: dpll-lock-dumpit

View file

@ -263,6 +263,27 @@ dpll_msg_add_phase_offset(struct sk_buff *msg, struct dpll_pin *pin,
return 0; return 0;
} }
static int dpll_msg_add_ffo(struct sk_buff *msg, struct dpll_pin *pin,
struct dpll_pin_ref *ref,
struct netlink_ext_ack *extack)
{
const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
struct dpll_device *dpll = ref->dpll;
s64 ffo;
int ret;
if (!ops->ffo_get)
return 0;
ret = ops->ffo_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
dpll, dpll_priv(dpll), &ffo, extack);
if (ret) {
if (ret == -ENODATA)
return 0;
return ret;
}
return nla_put_sint(msg, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET, ffo);
}
static int static int
dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin, dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin,
struct dpll_pin_ref *ref, struct netlink_ext_ack *extack) struct dpll_pin_ref *ref, struct netlink_ext_ack *extack)
@ -440,6 +461,9 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
prop->phase_range.max)) prop->phase_range.max))
return -EMSGSIZE; return -EMSGSIZE;
ret = dpll_msg_add_pin_phase_adjust(msg, pin, ref, extack); ret = dpll_msg_add_pin_phase_adjust(msg, pin, ref, extack);
if (ret)
return ret;
ret = dpll_msg_add_ffo(msg, pin, ref, extack);
if (ret) if (ret)
return ret; return ret;
if (xa_empty(&pin->parent_refs)) if (xa_empty(&pin->parent_refs))

View file

@ -36,11 +36,17 @@ static int mlx5_dpll_clock_id_get(struct mlx5_core_dev *mdev, u64 *clock_id)
return 0; return 0;
} }
struct mlx5_dpll_synce_status {
enum mlx5_msees_admin_status admin_status;
enum mlx5_msees_oper_status oper_status;
bool ho_acq;
bool oper_freq_measure;
s32 frequency_diff;
};
static int static int
mlx5_dpll_synce_status_get(struct mlx5_core_dev *mdev, mlx5_dpll_synce_status_get(struct mlx5_core_dev *mdev,
enum mlx5_msees_admin_status *admin_status, struct mlx5_dpll_synce_status *synce_status)
enum mlx5_msees_oper_status *oper_status,
bool *ho_acq)
{ {
u32 out[MLX5_ST_SZ_DW(msees_reg)] = {}; u32 out[MLX5_ST_SZ_DW(msees_reg)] = {};
u32 in[MLX5_ST_SZ_DW(msees_reg)] = {}; u32 in[MLX5_ST_SZ_DW(msees_reg)] = {};
@ -50,11 +56,11 @@ mlx5_dpll_synce_status_get(struct mlx5_core_dev *mdev,
MLX5_REG_MSEES, 0, 0); MLX5_REG_MSEES, 0, 0);
if (err) if (err)
return err; return err;
if (admin_status) synce_status->admin_status = MLX5_GET(msees_reg, out, admin_status);
*admin_status = MLX5_GET(msees_reg, out, admin_status); synce_status->oper_status = MLX5_GET(msees_reg, out, oper_status);
*oper_status = MLX5_GET(msees_reg, out, oper_status); synce_status->ho_acq = MLX5_GET(msees_reg, out, ho_acq);
if (ho_acq) synce_status->oper_freq_measure = MLX5_GET(msees_reg, out, oper_freq_measure);
*ho_acq = MLX5_GET(msees_reg, out, ho_acq); synce_status->frequency_diff = MLX5_GET(msees_reg, out, frequency_diff);
return 0; return 0;
} }
@ -67,21 +73,23 @@ mlx5_dpll_synce_status_set(struct mlx5_core_dev *mdev,
MLX5_SET(msees_reg, in, field_select, MLX5_SET(msees_reg, in, field_select,
MLX5_MSEES_FIELD_SELECT_ENABLE | MLX5_MSEES_FIELD_SELECT_ENABLE |
MLX5_MSEES_FIELD_SELECT_ADMIN_FREQ_MEASURE |
MLX5_MSEES_FIELD_SELECT_ADMIN_STATUS); MLX5_MSEES_FIELD_SELECT_ADMIN_STATUS);
MLX5_SET(msees_reg, in, admin_status, admin_status); MLX5_SET(msees_reg, in, admin_status, admin_status);
MLX5_SET(msees_reg, in, admin_freq_measure, true);
return mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out), return mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out),
MLX5_REG_MSEES, 0, 1); MLX5_REG_MSEES, 0, 1);
} }
static enum dpll_lock_status static enum dpll_lock_status
mlx5_dpll_lock_status_get(enum mlx5_msees_oper_status oper_status, bool ho_acq) mlx5_dpll_lock_status_get(struct mlx5_dpll_synce_status *synce_status)
{ {
switch (oper_status) { switch (synce_status->oper_status) {
case MLX5_MSEES_OPER_STATUS_SELF_TRACK: case MLX5_MSEES_OPER_STATUS_SELF_TRACK:
fallthrough; fallthrough;
case MLX5_MSEES_OPER_STATUS_OTHER_TRACK: case MLX5_MSEES_OPER_STATUS_OTHER_TRACK:
return ho_acq ? DPLL_LOCK_STATUS_LOCKED_HO_ACQ : return synce_status->ho_acq ? DPLL_LOCK_STATUS_LOCKED_HO_ACQ :
DPLL_LOCK_STATUS_LOCKED; DPLL_LOCK_STATUS_LOCKED;
case MLX5_MSEES_OPER_STATUS_HOLDOVER: case MLX5_MSEES_OPER_STATUS_HOLDOVER:
fallthrough; fallthrough;
case MLX5_MSEES_OPER_STATUS_FAIL_HOLDOVER: case MLX5_MSEES_OPER_STATUS_FAIL_HOLDOVER:
@ -92,31 +100,37 @@ mlx5_dpll_lock_status_get(enum mlx5_msees_oper_status oper_status, bool ho_acq)
} }
static enum dpll_pin_state static enum dpll_pin_state
mlx5_dpll_pin_state_get(enum mlx5_msees_admin_status admin_status, mlx5_dpll_pin_state_get(struct mlx5_dpll_synce_status *synce_status)
enum mlx5_msees_oper_status oper_status)
{ {
return (admin_status == MLX5_MSEES_ADMIN_STATUS_TRACK && return (synce_status->admin_status == MLX5_MSEES_ADMIN_STATUS_TRACK &&
(oper_status == MLX5_MSEES_OPER_STATUS_SELF_TRACK || (synce_status->oper_status == MLX5_MSEES_OPER_STATUS_SELF_TRACK ||
oper_status == MLX5_MSEES_OPER_STATUS_OTHER_TRACK)) ? synce_status->oper_status == MLX5_MSEES_OPER_STATUS_OTHER_TRACK)) ?
DPLL_PIN_STATE_CONNECTED : DPLL_PIN_STATE_DISCONNECTED; DPLL_PIN_STATE_CONNECTED : DPLL_PIN_STATE_DISCONNECTED;
} }
static int
mlx5_dpll_pin_ffo_get(struct mlx5_dpll_synce_status *synce_status,
s64 *ffo)
{
if (!synce_status->oper_freq_measure)
return -ENODATA;
*ffo = synce_status->frequency_diff;
return 0;
}
static int mlx5_dpll_device_lock_status_get(const struct dpll_device *dpll, static int mlx5_dpll_device_lock_status_get(const struct dpll_device *dpll,
void *priv, void *priv,
enum dpll_lock_status *status, enum dpll_lock_status *status,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
enum mlx5_msees_oper_status oper_status; struct mlx5_dpll_synce_status synce_status;
struct mlx5_dpll *mdpll = priv; struct mlx5_dpll *mdpll = priv;
bool ho_acq;
int err; int err;
err = mlx5_dpll_synce_status_get(mdpll->mdev, NULL, err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status);
&oper_status, &ho_acq);
if (err) if (err)
return err; return err;
*status = mlx5_dpll_lock_status_get(&synce_status);
*status = mlx5_dpll_lock_status_get(oper_status, ho_acq);
return 0; return 0;
} }
@ -151,16 +165,14 @@ static int mlx5_dpll_state_on_dpll_get(const struct dpll_pin *pin,
enum dpll_pin_state *state, enum dpll_pin_state *state,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
enum mlx5_msees_admin_status admin_status; struct mlx5_dpll_synce_status synce_status;
enum mlx5_msees_oper_status oper_status;
struct mlx5_dpll *mdpll = pin_priv; struct mlx5_dpll *mdpll = pin_priv;
int err; int err;
err = mlx5_dpll_synce_status_get(mdpll->mdev, &admin_status, err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status);
&oper_status, NULL);
if (err) if (err)
return err; return err;
*state = mlx5_dpll_pin_state_get(admin_status, oper_status); *state = mlx5_dpll_pin_state_get(&synce_status);
return 0; return 0;
} }
@ -179,10 +191,25 @@ static int mlx5_dpll_state_on_dpll_set(const struct dpll_pin *pin,
MLX5_MSEES_ADMIN_STATUS_FREE_RUNNING); MLX5_MSEES_ADMIN_STATUS_FREE_RUNNING);
} }
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 mlx5_dpll_synce_status synce_status;
struct mlx5_dpll *mdpll = pin_priv;
int err;
err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status);
if (err)
return err;
return mlx5_dpll_pin_ffo_get(&synce_status, ffo);
}
static const struct dpll_pin_ops mlx5_dpll_pins_ops = { static const struct dpll_pin_ops mlx5_dpll_pins_ops = {
.direction_get = mlx5_dpll_pin_direction_get, .direction_get = mlx5_dpll_pin_direction_get,
.state_on_dpll_get = mlx5_dpll_state_on_dpll_get, .state_on_dpll_get = mlx5_dpll_state_on_dpll_get,
.state_on_dpll_set = mlx5_dpll_state_on_dpll_set, .state_on_dpll_set = mlx5_dpll_state_on_dpll_set,
.ffo_get = mlx5_dpll_ffo_get,
}; };
static const struct dpll_pin_properties mlx5_dpll_pin_properties = { static const struct dpll_pin_properties mlx5_dpll_pin_properties = {
@ -202,19 +229,16 @@ static void mlx5_dpll_periodic_work(struct work_struct *work)
{ {
struct mlx5_dpll *mdpll = container_of(work, struct mlx5_dpll, struct mlx5_dpll *mdpll = container_of(work, struct mlx5_dpll,
work.work); work.work);
enum mlx5_msees_admin_status admin_status; struct mlx5_dpll_synce_status synce_status;
enum mlx5_msees_oper_status oper_status;
enum dpll_lock_status lock_status; enum dpll_lock_status lock_status;
enum dpll_pin_state pin_state; enum dpll_pin_state pin_state;
bool ho_acq;
int err; int err;
err = mlx5_dpll_synce_status_get(mdpll->mdev, &admin_status, err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status);
&oper_status, &ho_acq);
if (err) if (err)
goto err_out; goto err_out;
lock_status = mlx5_dpll_lock_status_get(oper_status, ho_acq); lock_status = mlx5_dpll_lock_status_get(&synce_status);
pin_state = mlx5_dpll_pin_state_get(admin_status, oper_status); pin_state = mlx5_dpll_pin_state_get(&synce_status);
if (!mdpll->last.valid) if (!mdpll->last.valid)
goto invalid_out; goto invalid_out;

View file

@ -77,6 +77,9 @@ struct dpll_pin_ops {
const struct dpll_device *dpll, void *dpll_priv, const struct dpll_device *dpll, void *dpll_priv,
const s32 phase_adjust, const s32 phase_adjust,
struct netlink_ext_ack *extack); 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_pin_frequency { struct dpll_pin_frequency {

View file

@ -179,6 +179,7 @@ enum dpll_a_pin {
DPLL_A_PIN_PHASE_ADJUST_MAX, DPLL_A_PIN_PHASE_ADJUST_MAX,
DPLL_A_PIN_PHASE_ADJUST, DPLL_A_PIN_PHASE_ADJUST,
DPLL_A_PIN_PHASE_OFFSET, DPLL_A_PIN_PHASE_OFFSET,
DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET,
__DPLL_A_PIN_MAX, __DPLL_A_PIN_MAX,
DPLL_A_PIN_MAX = (__DPLL_A_PIN_MAX - 1) DPLL_A_PIN_MAX = (__DPLL_A_PIN_MAX - 1)