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
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
subset-of: pin
@ -460,6 +470,7 @@ operations:
- phase-adjust-min
- phase-adjust-max
- phase-adjust
- fractional-frequency-offset
dump:
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;
}
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
dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin,
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))
return -EMSGSIZE;
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)
return ret;
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;
}
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
mlx5_dpll_synce_status_get(struct mlx5_core_dev *mdev,
enum mlx5_msees_admin_status *admin_status,
enum mlx5_msees_oper_status *oper_status,
bool *ho_acq)
struct mlx5_dpll_synce_status *synce_status)
{
u32 out[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);
if (err)
return err;
if (admin_status)
*admin_status = MLX5_GET(msees_reg, out, admin_status);
*oper_status = MLX5_GET(msees_reg, out, oper_status);
if (ho_acq)
*ho_acq = MLX5_GET(msees_reg, out, ho_acq);
synce_status->admin_status = MLX5_GET(msees_reg, out, admin_status);
synce_status->oper_status = MLX5_GET(msees_reg, out, oper_status);
synce_status->ho_acq = MLX5_GET(msees_reg, out, ho_acq);
synce_status->oper_freq_measure = MLX5_GET(msees_reg, out, oper_freq_measure);
synce_status->frequency_diff = MLX5_GET(msees_reg, out, frequency_diff);
return 0;
}
@ -67,21 +73,23 @@ mlx5_dpll_synce_status_set(struct mlx5_core_dev *mdev,
MLX5_SET(msees_reg, in, field_select,
MLX5_MSEES_FIELD_SELECT_ENABLE |
MLX5_MSEES_FIELD_SELECT_ADMIN_FREQ_MEASURE |
MLX5_MSEES_FIELD_SELECT_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),
MLX5_REG_MSEES, 0, 1);
}
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:
fallthrough;
case MLX5_MSEES_OPER_STATUS_OTHER_TRACK:
return ho_acq ? DPLL_LOCK_STATUS_LOCKED_HO_ACQ :
DPLL_LOCK_STATUS_LOCKED;
return synce_status->ho_acq ? DPLL_LOCK_STATUS_LOCKED_HO_ACQ :
DPLL_LOCK_STATUS_LOCKED;
case MLX5_MSEES_OPER_STATUS_HOLDOVER:
fallthrough;
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
mlx5_dpll_pin_state_get(enum mlx5_msees_admin_status admin_status,
enum mlx5_msees_oper_status oper_status)
mlx5_dpll_pin_state_get(struct mlx5_dpll_synce_status *synce_status)
{
return (admin_status == MLX5_MSEES_ADMIN_STATUS_TRACK &&
(oper_status == MLX5_MSEES_OPER_STATUS_SELF_TRACK ||
oper_status == MLX5_MSEES_OPER_STATUS_OTHER_TRACK)) ?
return (synce_status->admin_status == MLX5_MSEES_ADMIN_STATUS_TRACK &&
(synce_status->oper_status == MLX5_MSEES_OPER_STATUS_SELF_TRACK ||
synce_status->oper_status == MLX5_MSEES_OPER_STATUS_OTHER_TRACK)) ?
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,
void *priv,
enum dpll_lock_status *status,
struct netlink_ext_ack *extack)
{
enum mlx5_msees_oper_status oper_status;
struct mlx5_dpll_synce_status synce_status;
struct mlx5_dpll *mdpll = priv;
bool ho_acq;
int err;
err = mlx5_dpll_synce_status_get(mdpll->mdev, NULL,
&oper_status, &ho_acq);
err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status);
if (err)
return err;
*status = mlx5_dpll_lock_status_get(oper_status, ho_acq);
*status = mlx5_dpll_lock_status_get(&synce_status);
return 0;
}
@ -151,16 +165,14 @@ static int mlx5_dpll_state_on_dpll_get(const struct dpll_pin *pin,
enum dpll_pin_state *state,
struct netlink_ext_ack *extack)
{
enum mlx5_msees_admin_status admin_status;
enum mlx5_msees_oper_status oper_status;
struct mlx5_dpll_synce_status synce_status;
struct mlx5_dpll *mdpll = pin_priv;
int err;
err = mlx5_dpll_synce_status_get(mdpll->mdev, &admin_status,
&oper_status, NULL);
err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status);
if (err)
return err;
*state = mlx5_dpll_pin_state_get(admin_status, oper_status);
*state = mlx5_dpll_pin_state_get(&synce_status);
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);
}
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 = {
.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,
.ffo_get = mlx5_dpll_ffo_get,
};
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,
work.work);
enum mlx5_msees_admin_status admin_status;
enum mlx5_msees_oper_status oper_status;
struct mlx5_dpll_synce_status synce_status;
enum dpll_lock_status lock_status;
enum dpll_pin_state pin_state;
bool ho_acq;
int err;
err = mlx5_dpll_synce_status_get(mdpll->mdev, &admin_status,
&oper_status, &ho_acq);
err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status);
if (err)
goto err_out;
lock_status = mlx5_dpll_lock_status_get(oper_status, ho_acq);
pin_state = mlx5_dpll_pin_state_get(admin_status, oper_status);
lock_status = mlx5_dpll_lock_status_get(&synce_status);
pin_state = mlx5_dpll_pin_state_get(&synce_status);
if (!mdpll->last.valid)
goto invalid_out;

View File

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

View File

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