Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+98 -35
+11
Documentation/netlink/specs/dpll.yaml
··· 296 296 - 297 297 name: phase-offset 298 298 type: s64 299 + - 300 + name: fractional-frequency-offset 301 + type: sint 302 + doc: | 303 + The FFO (Fractional Frequency Offset) between the RX and TX 304 + symbol rate on the media associated with the pin: 305 + (rx_frequency-tx_frequency)/rx_frequency 306 + Value is in PPM (parts per million). 307 + This may be implemented for example for pin of type 308 + PIN_TYPE_SYNCE_ETH_PORT. 299 309 - 300 310 name: pin-parent-device 301 311 subset-of: pin ··· 470 460 - phase-adjust-min 471 461 - phase-adjust-max 472 462 - phase-adjust 463 + - fractional-frequency-offset 473 464 474 465 dump: 475 466 pre: dpll-lock-dumpit
+24
drivers/dpll/dpll_netlink.c
··· 263 263 return 0; 264 264 } 265 265 266 + static int dpll_msg_add_ffo(struct sk_buff *msg, struct dpll_pin *pin, 267 + struct dpll_pin_ref *ref, 268 + struct netlink_ext_ack *extack) 269 + { 270 + const struct dpll_pin_ops *ops = dpll_pin_ops(ref); 271 + struct dpll_device *dpll = ref->dpll; 272 + s64 ffo; 273 + int ret; 274 + 275 + if (!ops->ffo_get) 276 + return 0; 277 + ret = ops->ffo_get(pin, dpll_pin_on_dpll_priv(dpll, pin), 278 + dpll, dpll_priv(dpll), &ffo, extack); 279 + if (ret) { 280 + if (ret == -ENODATA) 281 + return 0; 282 + return ret; 283 + } 284 + return nla_put_sint(msg, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET, ffo); 285 + } 286 + 266 287 static int 267 288 dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin, 268 289 struct dpll_pin_ref *ref, struct netlink_ext_ack *extack) ··· 461 440 prop->phase_range.max)) 462 441 return -EMSGSIZE; 463 442 ret = dpll_msg_add_pin_phase_adjust(msg, pin, ref, extack); 443 + if (ret) 444 + return ret; 445 + ret = dpll_msg_add_ffo(msg, pin, ref, extack); 464 446 if (ret) 465 447 return ret; 466 448 if (xa_empty(&pin->parent_refs))
+59 -35
drivers/net/ethernet/mellanox/mlx5/core/dpll.c
··· 36 36 return 0; 37 37 } 38 38 39 + struct mlx5_dpll_synce_status { 40 + enum mlx5_msees_admin_status admin_status; 41 + enum mlx5_msees_oper_status oper_status; 42 + bool ho_acq; 43 + bool oper_freq_measure; 44 + s32 frequency_diff; 45 + }; 46 + 39 47 static int 40 48 mlx5_dpll_synce_status_get(struct mlx5_core_dev *mdev, 41 - enum mlx5_msees_admin_status *admin_status, 42 - enum mlx5_msees_oper_status *oper_status, 43 - bool *ho_acq) 49 + struct mlx5_dpll_synce_status *synce_status) 44 50 { 45 51 u32 out[MLX5_ST_SZ_DW(msees_reg)] = {}; 46 52 u32 in[MLX5_ST_SZ_DW(msees_reg)] = {}; ··· 56 50 MLX5_REG_MSEES, 0, 0); 57 51 if (err) 58 52 return err; 59 - if (admin_status) 60 - *admin_status = MLX5_GET(msees_reg, out, admin_status); 61 - *oper_status = MLX5_GET(msees_reg, out, oper_status); 62 - if (ho_acq) 63 - *ho_acq = MLX5_GET(msees_reg, out, ho_acq); 53 + synce_status->admin_status = MLX5_GET(msees_reg, out, admin_status); 54 + synce_status->oper_status = MLX5_GET(msees_reg, out, oper_status); 55 + synce_status->ho_acq = MLX5_GET(msees_reg, out, ho_acq); 56 + synce_status->oper_freq_measure = MLX5_GET(msees_reg, out, oper_freq_measure); 57 + synce_status->frequency_diff = MLX5_GET(msees_reg, out, frequency_diff); 64 58 return 0; 65 59 } 66 60 ··· 73 67 74 68 MLX5_SET(msees_reg, in, field_select, 75 69 MLX5_MSEES_FIELD_SELECT_ENABLE | 70 + MLX5_MSEES_FIELD_SELECT_ADMIN_FREQ_MEASURE | 76 71 MLX5_MSEES_FIELD_SELECT_ADMIN_STATUS); 77 72 MLX5_SET(msees_reg, in, admin_status, admin_status); 73 + MLX5_SET(msees_reg, in, admin_freq_measure, true); 78 74 return mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out), 79 75 MLX5_REG_MSEES, 0, 1); 80 76 } 81 77 82 78 static enum dpll_lock_status 83 - mlx5_dpll_lock_status_get(enum mlx5_msees_oper_status oper_status, bool ho_acq) 79 + mlx5_dpll_lock_status_get(struct mlx5_dpll_synce_status *synce_status) 84 80 { 85 - switch (oper_status) { 81 + switch (synce_status->oper_status) { 86 82 case MLX5_MSEES_OPER_STATUS_SELF_TRACK: 87 83 fallthrough; 88 84 case MLX5_MSEES_OPER_STATUS_OTHER_TRACK: 89 - return ho_acq ? DPLL_LOCK_STATUS_LOCKED_HO_ACQ : 90 - DPLL_LOCK_STATUS_LOCKED; 85 + return synce_status->ho_acq ? DPLL_LOCK_STATUS_LOCKED_HO_ACQ : 86 + DPLL_LOCK_STATUS_LOCKED; 91 87 case MLX5_MSEES_OPER_STATUS_HOLDOVER: 92 88 fallthrough; 93 89 case MLX5_MSEES_OPER_STATUS_FAIL_HOLDOVER: ··· 100 92 } 101 93 102 94 static enum dpll_pin_state 103 - mlx5_dpll_pin_state_get(enum mlx5_msees_admin_status admin_status, 104 - enum mlx5_msees_oper_status oper_status) 95 + mlx5_dpll_pin_state_get(struct mlx5_dpll_synce_status *synce_status) 105 96 { 106 - return (admin_status == MLX5_MSEES_ADMIN_STATUS_TRACK && 107 - (oper_status == MLX5_MSEES_OPER_STATUS_SELF_TRACK || 108 - oper_status == MLX5_MSEES_OPER_STATUS_OTHER_TRACK)) ? 97 + return (synce_status->admin_status == MLX5_MSEES_ADMIN_STATUS_TRACK && 98 + (synce_status->oper_status == MLX5_MSEES_OPER_STATUS_SELF_TRACK || 99 + synce_status->oper_status == MLX5_MSEES_OPER_STATUS_OTHER_TRACK)) ? 109 100 DPLL_PIN_STATE_CONNECTED : DPLL_PIN_STATE_DISCONNECTED; 101 + } 102 + 103 + static int 104 + mlx5_dpll_pin_ffo_get(struct mlx5_dpll_synce_status *synce_status, 105 + s64 *ffo) 106 + { 107 + if (!synce_status->oper_freq_measure) 108 + return -ENODATA; 109 + *ffo = synce_status->frequency_diff; 110 + return 0; 110 111 } 111 112 112 113 static int mlx5_dpll_device_lock_status_get(const struct dpll_device *dpll, ··· 123 106 enum dpll_lock_status *status, 124 107 struct netlink_ext_ack *extack) 125 108 { 126 - enum mlx5_msees_oper_status oper_status; 109 + struct mlx5_dpll_synce_status synce_status; 127 110 struct mlx5_dpll *mdpll = priv; 128 - bool ho_acq; 129 111 int err; 130 112 131 - err = mlx5_dpll_synce_status_get(mdpll->mdev, NULL, 132 - &oper_status, &ho_acq); 113 + err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status); 133 114 if (err) 134 115 return err; 135 - 136 - *status = mlx5_dpll_lock_status_get(oper_status, ho_acq); 116 + *status = mlx5_dpll_lock_status_get(&synce_status); 137 117 return 0; 138 118 } 139 119 ··· 165 151 enum dpll_pin_state *state, 166 152 struct netlink_ext_ack *extack) 167 153 { 168 - enum mlx5_msees_admin_status admin_status; 169 - enum mlx5_msees_oper_status oper_status; 154 + struct mlx5_dpll_synce_status synce_status; 170 155 struct mlx5_dpll *mdpll = pin_priv; 171 156 int err; 172 157 173 - err = mlx5_dpll_synce_status_get(mdpll->mdev, &admin_status, 174 - &oper_status, NULL); 158 + err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status); 175 159 if (err) 176 160 return err; 177 - *state = mlx5_dpll_pin_state_get(admin_status, oper_status); 161 + *state = mlx5_dpll_pin_state_get(&synce_status); 178 162 return 0; 179 163 } 180 164 ··· 191 179 MLX5_MSEES_ADMIN_STATUS_FREE_RUNNING); 192 180 } 193 181 182 + static int mlx5_dpll_ffo_get(const struct dpll_pin *pin, void *pin_priv, 183 + const struct dpll_device *dpll, void *dpll_priv, 184 + s64 *ffo, struct netlink_ext_ack *extack) 185 + { 186 + struct mlx5_dpll_synce_status synce_status; 187 + struct mlx5_dpll *mdpll = pin_priv; 188 + int err; 189 + 190 + err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status); 191 + if (err) 192 + return err; 193 + return mlx5_dpll_pin_ffo_get(&synce_status, ffo); 194 + } 195 + 194 196 static const struct dpll_pin_ops mlx5_dpll_pins_ops = { 195 197 .direction_get = mlx5_dpll_pin_direction_get, 196 198 .state_on_dpll_get = mlx5_dpll_state_on_dpll_get, 197 199 .state_on_dpll_set = mlx5_dpll_state_on_dpll_set, 200 + .ffo_get = mlx5_dpll_ffo_get, 198 201 }; 199 202 200 203 static const struct dpll_pin_properties mlx5_dpll_pin_properties = { ··· 229 202 { 230 203 struct mlx5_dpll *mdpll = container_of(work, struct mlx5_dpll, 231 204 work.work); 232 - enum mlx5_msees_admin_status admin_status; 233 - enum mlx5_msees_oper_status oper_status; 205 + struct mlx5_dpll_synce_status synce_status; 234 206 enum dpll_lock_status lock_status; 235 207 enum dpll_pin_state pin_state; 236 - bool ho_acq; 237 208 int err; 238 209 239 - err = mlx5_dpll_synce_status_get(mdpll->mdev, &admin_status, 240 - &oper_status, &ho_acq); 210 + err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status); 241 211 if (err) 242 212 goto err_out; 243 - lock_status = mlx5_dpll_lock_status_get(oper_status, ho_acq); 244 - pin_state = mlx5_dpll_pin_state_get(admin_status, oper_status); 213 + lock_status = mlx5_dpll_lock_status_get(&synce_status); 214 + pin_state = mlx5_dpll_pin_state_get(&synce_status); 245 215 246 216 if (!mdpll->last.valid) 247 217 goto invalid_out;
+3
include/linux/dpll.h
··· 77 77 const struct dpll_device *dpll, void *dpll_priv, 78 78 const s32 phase_adjust, 79 79 struct netlink_ext_ack *extack); 80 + int (*ffo_get)(const struct dpll_pin *pin, void *pin_priv, 81 + const struct dpll_device *dpll, void *dpll_priv, 82 + s64 *ffo, struct netlink_ext_ack *extack); 80 83 }; 81 84 82 85 struct dpll_pin_frequency {
+1
include/uapi/linux/dpll.h
··· 179 179 DPLL_A_PIN_PHASE_ADJUST_MAX, 180 180 DPLL_A_PIN_PHASE_ADJUST, 181 181 DPLL_A_PIN_PHASE_OFFSET, 182 + DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET, 182 183 183 184 __DPLL_A_PIN_MAX, 184 185 DPLL_A_PIN_MAX = (__DPLL_A_PIN_MAX - 1)