Commit d4d4126f authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'dpll-add-all-inputs-phase-offset-monitor'

Arkadiusz Kubalewski says:

====================
dpll: add all inputs phase offset monitor

Add dpll device level feature: phase offset monitor.

Phase offset measurement is typically performed against the current active
source. However, some DPLL (Digital Phase-Locked Loop) devices may offer
the capability to monitor phase offsets across all available inputs.
The attribute and current feature state shall be included in the response
message of the ``DPLL_CMD_DEVICE_GET`` command for supported DPLL devices.
In such cases, users can also control the feature using the
``DPLL_CMD_DEVICE_SET`` command by setting the ``enum dpll_feature_state``
values for the attribute.
Once enabled the phase offset measurements for the input shall be returned
in the ``DPLL_A_PIN_PHASE_OFFSET`` attribute.

Implement feature support in ice driver for dpll-enabled devices.

Verify capability:
$ ./tools/net/ynl/pyynl/cli.py \
 --spec Documentation/netlink/specs/dpll.yaml \
 --dump device-get
[{'clock-id': 4658613174691613800,
  'id': 0,
  'lock-status': 'locked-ho-acq',
  'mode': 'automatic',
  'mode-supported': ['automatic'],
  'module-name': 'ice',
  'type': 'eec'},
 {'clock-id': 4658613174691613800,
  'id': 1,
  'lock-status': 'locked-ho-acq',
  'mode': 'automatic',
  'mode-supported': ['automatic'],
  'module-name': 'ice',
  'phase-offset-monitor': 'disable',
  'type': 'pps'}]

Enable the feature:
$ ./tools/net/ynl/pyynl/cli.py \
 --spec Documentation/netlink/specs/dpll.yaml \
 --do device-set --json '{"id":1, "phase-offset-monitor":"enable"}'

Verify feature is enabled:
$ ./tools/net/ynl/pyynl/cli.py \
 --spec Documentation/netlink/specs/dpll.yaml \
 --dump device-get
[
 [...]
 {'capabilities': {'all-inputs-phase-offset-monitor'},
  'clock-id': 4658613174691613800,
  'id': 1,
 [...]
  'phase-offset-monitor': 'enable',
 [...]]

v6:
- rebase.
====================

Link: https://patch.msgid.link/20250612152835.1703397-1-arkadiusz.kubalewski@intel.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents bd1d76a6 863c7e50
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -214,6 +214,24 @@ offset values are fractional with 3-digit decimal places and shell be
divided with ``DPLL_PIN_PHASE_OFFSET_DIVIDER`` to get integer part and
modulo divided to get fractional part.

Phase offset monitor
====================

Phase offset measurement is typically performed against the current active
source. However, some DPLL (Digital Phase-Locked Loop) devices may offer
the capability to monitor phase offsets across all available inputs.
The attribute and current feature state shall be included in the response
message of the ``DPLL_CMD_DEVICE_GET`` command for supported DPLL devices.
In such cases, users can also control the feature using the
``DPLL_CMD_DEVICE_SET`` command by setting the ``enum dpll_feature_state``
values for the attribute.
Once enabled the phase offset measurements for the input shall be returned
in the ``DPLL_A_PIN_PHASE_OFFSET`` attribute.

  =============================== ========================
  ``DPLL_A_PHASE_OFFSET_MONITOR`` attr state of a feature
  =============================== ========================

Embedded SYNC
=============

+24 −0
Original line number Diff line number Diff line
@@ -240,6 +240,20 @@ definitions:
      integer part of a measured phase offset value.
      Value of (DPLL_A_PHASE_OFFSET % DPLL_PHASE_OFFSET_DIVIDER) is a
      fractional part of a measured phase offset value.
  -
    type: enum
    name: feature-state
    doc: |
      Allow control (enable/disable) and status checking over features.
    entries:
      -
        name: disable
        doc: |
          feature shall be disabled
      -
        name: enable
        doc: |
          feature shall be enabled

attribute-sets:
  -
@@ -293,6 +307,14 @@ attribute-sets:
          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: phase-offset-monitor
        type: u32
        enum: feature-state
        doc: Receive or request state of phase offset monitor feature.
          If enabled, dpll device shall monitor and notify all currently
          available inputs for changes of their phase offset against the
          dpll device.
  -
    name: pin
    enum-name: dpll_a_pin
@@ -483,6 +505,7 @@ operations:
            - temp
            - clock-id
            - type
            - phase-offset-monitor

      dump:
        reply: *dev-attrs
@@ -499,6 +522,7 @@ operations:
        request:
          attributes:
            - id
            - phase-offset-monitor
    -
      name: device-create-ntf
      doc: Notification about device appearing
+67 −2
Original line number Diff line number Diff line
@@ -126,6 +126,26 @@ dpll_msg_add_mode_supported(struct sk_buff *msg, struct dpll_device *dpll,
	return 0;
}

static int
dpll_msg_add_phase_offset_monitor(struct sk_buff *msg, struct dpll_device *dpll,
				  struct netlink_ext_ack *extack)
{
	const struct dpll_device_ops *ops = dpll_device_ops(dpll);
	enum dpll_feature_state state;
	int ret;

	if (ops->phase_offset_monitor_set && ops->phase_offset_monitor_get) {
		ret = ops->phase_offset_monitor_get(dpll, dpll_priv(dpll),
						    &state, extack);
		if (ret)
			return ret;
		if (nla_put_u32(msg, DPLL_A_PHASE_OFFSET_MONITOR, state))
			return -EMSGSIZE;
	}

	return 0;
}

static int
dpll_msg_add_lock_status(struct sk_buff *msg, struct dpll_device *dpll,
			 struct netlink_ext_ack *extack)
@@ -591,6 +611,9 @@ dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg,
		return ret;
	if (nla_put_u32(msg, DPLL_A_TYPE, dpll->type))
		return -EMSGSIZE;
	ret = dpll_msg_add_phase_offset_monitor(msg, dpll, extack);
	if (ret)
		return ret;

	return 0;
}
@@ -746,6 +769,31 @@ int dpll_pin_change_ntf(struct dpll_pin *pin)
}
EXPORT_SYMBOL_GPL(dpll_pin_change_ntf);

static int
dpll_phase_offset_monitor_set(struct dpll_device *dpll, struct nlattr *a,
			      struct netlink_ext_ack *extack)
{
	const struct dpll_device_ops *ops = dpll_device_ops(dpll);
	enum dpll_feature_state state = nla_get_u32(a), old_state;
	int ret;

	if (!(ops->phase_offset_monitor_set && ops->phase_offset_monitor_get)) {
		NL_SET_ERR_MSG_ATTR(extack, a, "dpll device not capable of phase offset monitor");
		return -EOPNOTSUPP;
	}
	ret = ops->phase_offset_monitor_get(dpll, dpll_priv(dpll), &old_state,
					    extack);
	if (ret) {
		NL_SET_ERR_MSG(extack, "unable to get current state of phase offset monitor");
		return ret;
	}
	if (state == old_state)
		return 0;

	return ops->phase_offset_monitor_set(dpll, dpll_priv(dpll), state,
					     extack);
}

static int
dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
		  struct netlink_ext_ack *extack)
@@ -1533,12 +1581,29 @@ int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info)
	return genlmsg_reply(msg, info);
}

int dpll_nl_device_set_doit(struct sk_buff *skb, struct genl_info *info)
static int
dpll_set_from_nlattr(struct dpll_device *dpll, struct genl_info *info)
{
	/* placeholder for set command */
	int ret;

	if (info->attrs[DPLL_A_PHASE_OFFSET_MONITOR]) {
		struct nlattr *a = info->attrs[DPLL_A_PHASE_OFFSET_MONITOR];

		ret = dpll_phase_offset_monitor_set(dpll, a, info->extack);
		if (ret)
			return ret;
	}

	return 0;
}

int dpll_nl_device_set_doit(struct sk_buff *skb, struct genl_info *info)
{
	struct dpll_device *dpll = info->user_ptr[0];

	return dpll_set_from_nlattr(dpll, info);
}

int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
{
	struct dpll_dump_ctx *ctx = dpll_dump_context(cb);
+3 −2
Original line number Diff line number Diff line
@@ -37,8 +37,9 @@ static const struct nla_policy dpll_device_get_nl_policy[DPLL_A_ID + 1] = {
};

/* DPLL_CMD_DEVICE_SET - do */
static const struct nla_policy dpll_device_set_nl_policy[DPLL_A_ID + 1] = {
static const struct nla_policy dpll_device_set_nl_policy[DPLL_A_PHASE_OFFSET_MONITOR + 1] = {
	[DPLL_A_ID] = { .type = NLA_U32, },
	[DPLL_A_PHASE_OFFSET_MONITOR] = NLA_POLICY_MAX(NLA_U32, 1),
};

/* DPLL_CMD_PIN_ID_GET - do */
@@ -105,7 +106,7 @@ static const struct genl_split_ops dpll_nl_ops[] = {
		.doit		= dpll_nl_device_set_doit,
		.post_doit	= dpll_post_doit,
		.policy		= dpll_device_set_nl_policy,
		.maxattr	= DPLL_A_ID,
		.maxattr	= DPLL_A_PHASE_OFFSET_MONITOR,
		.flags		= GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
	},
	{
+20 −0
Original line number Diff line number Diff line
@@ -2272,6 +2272,22 @@ struct ice_aqc_get_pkg_info_resp {
	struct ice_aqc_get_pkg_info pkg_info[];
};

#define ICE_CGU_INPUT_PHASE_OFFSET_BYTES	6

struct ice_cgu_input_measure {
	u8 phase_offset[ICE_CGU_INPUT_PHASE_OFFSET_BYTES];
	__le32 freq;
} __packed __aligned(sizeof(__le16));

#define ICE_AQC_GET_CGU_IN_MEAS_DPLL_IDX_M	ICE_M(0xf, 0)

/* Get CGU input measure command response data structure (indirect 0x0C59) */
struct ice_aqc_get_cgu_input_measure {
	u8 dpll_idx_opt;
	u8 length;
	u8 rsvd[6];
};

#define ICE_AQC_GET_CGU_MAX_PHASE_ADJ	GENMASK(30, 0)

/* Get CGU abilities command response data structure (indirect 0x0C61) */
@@ -2721,6 +2737,7 @@ struct ice_aq_desc {
		struct ice_aqc_add_get_update_free_vsi vsi_cmd;
		struct ice_aqc_add_update_free_vsi_resp add_update_free_vsi_res;
		struct ice_aqc_download_pkg download_pkg;
		struct ice_aqc_get_cgu_input_measure get_cgu_input_measure;
		struct ice_aqc_set_cgu_input_config set_cgu_input_config;
		struct ice_aqc_get_cgu_input_config get_cgu_input_config;
		struct ice_aqc_set_cgu_output_config set_cgu_output_config;
@@ -2772,6 +2789,8 @@ enum ice_aq_err {
	ICE_AQ_RC_OK		= 0,  /* Success */
	ICE_AQ_RC_EPERM		= 1,  /* Operation not permitted */
	ICE_AQ_RC_ENOENT	= 2,  /* No such element */
	ICE_AQ_RC_ESRCH		= 3,  /* Bad opcode */
	ICE_AQ_RC_EAGAIN	= 8,  /* Try again */
	ICE_AQ_RC_ENOMEM	= 9,  /* Out of memory */
	ICE_AQ_RC_EBUSY		= 12, /* Device or resource busy */
	ICE_AQ_RC_EEXIST	= 13, /* Object already exists */
@@ -2927,6 +2946,7 @@ enum ice_adminq_opc {
	ice_aqc_opc_get_pkg_info_list			= 0x0C43,

	/* 1588/SyncE commands/events */
	ice_aqc_opc_get_cgu_input_measure		= 0x0C59,
	ice_aqc_opc_get_cgu_abilities			= 0x0C61,
	ice_aqc_opc_set_cgu_input_config		= 0x0C62,
	ice_aqc_opc_get_cgu_input_config		= 0x0C63,
Loading