mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-03 19:55:31 +00:00
Merge branch 'dpll-expose-clock-quality-level'
Jiri Pirko says: ==================== dpll: expose clock quality level Some device driver might know the quality of the clock it is running. In order to expose the information to the user, introduce new netlink attribute and dpll device op. Implement the op in mlx5 driver. Example: $ ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/dpll.yaml --dump device-get [{'clock-id': 13316852727532664826, 'clock-quality-level': ['itu-opt1-eeec'], <<<<<<<<<<<<<<<<< 'id': 0, 'lock-status': 'unlocked', 'lock-status-error': 'none', 'mode': 'manual', 'mode-supported': ['manual'], 'module-name': 'mlx5_dpll', 'type': 'eec'}] ==================== Link: https://patch.msgid.link/20241030081157.966604-1-jiri@resnulli.us Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
f07a6e6ceb
@ -85,6 +85,36 @@ definitions:
|
||||
This may happen for example if dpll device was previously
|
||||
locked on an input pin of type PIN_TYPE_SYNCE_ETH_PORT.
|
||||
render-max: true
|
||||
-
|
||||
type: enum
|
||||
name: clock-quality-level
|
||||
doc: |
|
||||
level of quality of a clock device. This mainly applies when
|
||||
the dpll lock-status is DPLL_LOCK_STATUS_HOLDOVER.
|
||||
The current list is defined according to the table 11-7 contained
|
||||
in ITU-T G.8264/Y.1364 document. One may extend this list freely
|
||||
by other ITU-T defined clock qualities, or different ones defined
|
||||
by another standardization body (for those, please use
|
||||
different prefix).
|
||||
entries:
|
||||
-
|
||||
name: itu-opt1-prc
|
||||
value: 1
|
||||
-
|
||||
name: itu-opt1-ssu-a
|
||||
-
|
||||
name: itu-opt1-ssu-b
|
||||
-
|
||||
name: itu-opt1-eec1
|
||||
-
|
||||
name: itu-opt1-prtc
|
||||
-
|
||||
name: itu-opt1-eprtc
|
||||
-
|
||||
name: itu-opt1-eeec
|
||||
-
|
||||
name: itu-opt1-eprc
|
||||
render-max: true
|
||||
-
|
||||
type: const
|
||||
name: temp-divider
|
||||
@ -252,6 +282,17 @@ attribute-sets:
|
||||
name: lock-status-error
|
||||
type: u32
|
||||
enum: lock-status-error
|
||||
-
|
||||
name: clock-quality-level
|
||||
type: u32
|
||||
enum: clock-quality-level
|
||||
multi-attr: true
|
||||
doc: |
|
||||
Level of quality of a clock device. This mainly applies when
|
||||
the dpll lock-status is DPLL_LOCK_STATUS_HOLDOVER. This could
|
||||
be put to message multiple times to indicate possible parallel
|
||||
quality levels (e.g. one specified by ITU option 1 and another
|
||||
one specified by option 2).
|
||||
-
|
||||
name: pin
|
||||
enum-name: dpll_a_pin
|
||||
|
@ -169,6 +169,27 @@ dpll_msg_add_temp(struct sk_buff *msg, struct dpll_device *dpll,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dpll_msg_add_clock_quality_level(struct sk_buff *msg, struct dpll_device *dpll,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
const struct dpll_device_ops *ops = dpll_device_ops(dpll);
|
||||
DECLARE_BITMAP(qls, DPLL_CLOCK_QUALITY_LEVEL_MAX) = { 0 };
|
||||
enum dpll_clock_quality_level ql;
|
||||
int ret;
|
||||
|
||||
if (!ops->clock_quality_level_get)
|
||||
return 0;
|
||||
ret = ops->clock_quality_level_get(dpll, dpll_priv(dpll), qls, extack);
|
||||
if (ret)
|
||||
return ret;
|
||||
for_each_set_bit(ql, qls, DPLL_CLOCK_QUALITY_LEVEL_MAX)
|
||||
if (nla_put_u32(msg, DPLL_A_CLOCK_QUALITY_LEVEL, ql))
|
||||
return -EMSGSIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dpll_msg_add_pin_prio(struct sk_buff *msg, struct dpll_pin *pin,
|
||||
struct dpll_pin_ref *ref,
|
||||
@ -557,6 +578,9 @@ dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg,
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = dpll_msg_add_lock_status(msg, dpll, extack);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = dpll_msg_add_clock_quality_level(msg, dpll, extack);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = dpll_msg_add_mode(msg, dpll, extack);
|
||||
|
@ -166,9 +166,90 @@ static int mlx5_dpll_device_mode_get(const struct dpll_device *dpll,
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum {
|
||||
MLX5_DPLL_SSM_CODE_PRC = 0b0010,
|
||||
MLX5_DPLL_SSM_CODE_SSU_A = 0b0100,
|
||||
MLX5_DPLL_SSM_CODE_SSU_B = 0b1000,
|
||||
MLX5_DPLL_SSM_CODE_EEC1 = 0b1011,
|
||||
MLX5_DPLL_SSM_CODE_PRTC = 0b0010,
|
||||
MLX5_DPLL_SSM_CODE_EPRTC = 0b0010,
|
||||
MLX5_DPLL_SSM_CODE_EEEC = 0b1011,
|
||||
MLX5_DPLL_SSM_CODE_EPRC = 0b0010,
|
||||
};
|
||||
|
||||
enum {
|
||||
MLX5_DPLL_ENHANCED_SSM_CODE_PRC = 0xff,
|
||||
MLX5_DPLL_ENHANCED_SSM_CODE_SSU_A = 0xff,
|
||||
MLX5_DPLL_ENHANCED_SSM_CODE_SSU_B = 0xff,
|
||||
MLX5_DPLL_ENHANCED_SSM_CODE_EEC1 = 0xff,
|
||||
MLX5_DPLL_ENHANCED_SSM_CODE_PRTC = 0x20,
|
||||
MLX5_DPLL_ENHANCED_SSM_CODE_EPRTC = 0x21,
|
||||
MLX5_DPLL_ENHANCED_SSM_CODE_EEEC = 0x22,
|
||||
MLX5_DPLL_ENHANCED_SSM_CODE_EPRC = 0x23,
|
||||
};
|
||||
|
||||
#define __MLX5_DPLL_SSM_COMBINED_CODE(ssm_code, enhanced_ssm_code) \
|
||||
((ssm_code) | ((enhanced_ssm_code) << 8))
|
||||
|
||||
#define MLX5_DPLL_SSM_COMBINED_CODE(type) \
|
||||
__MLX5_DPLL_SSM_COMBINED_CODE(MLX5_DPLL_SSM_CODE_##type, \
|
||||
MLX5_DPLL_ENHANCED_SSM_CODE_##type)
|
||||
|
||||
static int mlx5_dpll_clock_quality_level_get(const struct dpll_device *dpll,
|
||||
void *priv, unsigned long *qls,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
u8 network_option, ssm_code, enhanced_ssm_code;
|
||||
u32 out[MLX5_ST_SZ_DW(msecq_reg)] = {};
|
||||
u32 in[MLX5_ST_SZ_DW(msecq_reg)] = {};
|
||||
struct mlx5_dpll *mdpll = priv;
|
||||
int err;
|
||||
|
||||
err = mlx5_core_access_reg(mdpll->mdev, in, sizeof(in),
|
||||
out, sizeof(out), MLX5_REG_MSECQ, 0, 0);
|
||||
if (err)
|
||||
return err;
|
||||
network_option = MLX5_GET(msecq_reg, out, network_option);
|
||||
if (network_option != 1)
|
||||
goto errout;
|
||||
ssm_code = MLX5_GET(msecq_reg, out, local_ssm_code);
|
||||
enhanced_ssm_code = MLX5_GET(msecq_reg, out, local_enhanced_ssm_code);
|
||||
|
||||
switch (__MLX5_DPLL_SSM_COMBINED_CODE(ssm_code, enhanced_ssm_code)) {
|
||||
case MLX5_DPLL_SSM_COMBINED_CODE(PRC):
|
||||
__set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_PRC, qls);
|
||||
return 0;
|
||||
case MLX5_DPLL_SSM_COMBINED_CODE(SSU_A):
|
||||
__set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_SSU_A, qls);
|
||||
return 0;
|
||||
case MLX5_DPLL_SSM_COMBINED_CODE(SSU_B):
|
||||
__set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_SSU_B, qls);
|
||||
return 0;
|
||||
case MLX5_DPLL_SSM_COMBINED_CODE(EEC1):
|
||||
__set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EEC1, qls);
|
||||
return 0;
|
||||
case MLX5_DPLL_SSM_COMBINED_CODE(PRTC):
|
||||
__set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_PRTC, qls);
|
||||
return 0;
|
||||
case MLX5_DPLL_SSM_COMBINED_CODE(EPRTC):
|
||||
__set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EPRTC, qls);
|
||||
return 0;
|
||||
case MLX5_DPLL_SSM_COMBINED_CODE(EEEC):
|
||||
__set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EEEC, qls);
|
||||
return 0;
|
||||
case MLX5_DPLL_SSM_COMBINED_CODE(EPRC):
|
||||
__set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EPRC, qls);
|
||||
return 0;
|
||||
}
|
||||
errout:
|
||||
NL_SET_ERR_MSG_MOD(extack, "Invalid clock quality level obtained from firmware\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct dpll_device_ops mlx5_dpll_device_ops = {
|
||||
.lock_status_get = mlx5_dpll_device_lock_status_get,
|
||||
.mode_get = mlx5_dpll_device_mode_get,
|
||||
.clock_quality_level_get = mlx5_dpll_clock_quality_level_get,
|
||||
};
|
||||
|
||||
static int mlx5_dpll_pin_direction_get(const struct dpll_pin *pin,
|
||||
|
@ -26,6 +26,10 @@ struct dpll_device_ops {
|
||||
struct netlink_ext_ack *extack);
|
||||
int (*temp_get)(const struct dpll_device *dpll, void *dpll_priv,
|
||||
s32 *temp, struct netlink_ext_ack *extack);
|
||||
int (*clock_quality_level_get)(const struct dpll_device *dpll,
|
||||
void *dpll_priv,
|
||||
unsigned long *qls,
|
||||
struct netlink_ext_ack *extack);
|
||||
};
|
||||
|
||||
struct dpll_pin_ops {
|
||||
|
@ -79,6 +79,29 @@ enum dpll_lock_status_error {
|
||||
DPLL_LOCK_STATUS_ERROR_MAX = (__DPLL_LOCK_STATUS_ERROR_MAX - 1)
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dpll_clock_quality_level - level of quality of a clock device. This
|
||||
* mainly applies when the dpll lock-status is DPLL_LOCK_STATUS_HOLDOVER. The
|
||||
* current list is defined according to the table 11-7 contained in ITU-T
|
||||
* G.8264/Y.1364 document. One may extend this list freely by other ITU-T
|
||||
* defined clock qualities, or different ones defined by another
|
||||
* standardization body (for those, please use different prefix).
|
||||
*/
|
||||
enum dpll_clock_quality_level {
|
||||
DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_PRC = 1,
|
||||
DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_SSU_A,
|
||||
DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_SSU_B,
|
||||
DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EEC1,
|
||||
DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_PRTC,
|
||||
DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EPRTC,
|
||||
DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EEEC,
|
||||
DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EPRC,
|
||||
|
||||
/* private: */
|
||||
__DPLL_CLOCK_QUALITY_LEVEL_MAX,
|
||||
DPLL_CLOCK_QUALITY_LEVEL_MAX = (__DPLL_CLOCK_QUALITY_LEVEL_MAX - 1)
|
||||
};
|
||||
|
||||
#define DPLL_TEMP_DIVIDER 1000
|
||||
|
||||
/**
|
||||
@ -180,6 +203,7 @@ enum dpll_a {
|
||||
DPLL_A_TEMP,
|
||||
DPLL_A_TYPE,
|
||||
DPLL_A_LOCK_STATUS_ERROR,
|
||||
DPLL_A_CLOCK_QUALITY_LEVEL,
|
||||
|
||||
__DPLL_A_MAX,
|
||||
DPLL_A_MAX = (__DPLL_A_MAX - 1)
|
||||
|
Loading…
Reference in New Issue
Block a user