Merge: CNB97: dpll: add phase-offset-monitor feature

MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/7158

JIRA: https://issues.redhat.com/browse/RHEL-105066

This adds phase-offset-monitor feature into DPLL subsystem.

Signed-off-by: Ivan Vecera <ivecera@redhat.com>

Approved-by: Petr Oros <poros@redhat.com>
Approved-by: Murphy Zhou <xzhou@redhat.com>
Approved-by: mheib <mheib@redhat.com>
Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com>

Merged-by: Augusto Caringi <acaringi@redhat.com>
This commit is contained in:
Augusto Caringi 2025-08-06 18:26:13 -03:00
commit a6f311b6c8
6 changed files with 132 additions and 4 deletions

View File

@ -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
=============

View File

@ -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

View File

@ -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,10 +1581,27 @@ int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info)
return genlmsg_reply(msg, info);
}
static int
dpll_set_from_nlattr(struct dpll_device *dpll, struct genl_info *info)
{
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)
{
/* placeholder for set command */
return 0;
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)

View File

@ -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,
},
{

View File

@ -30,6 +30,14 @@ struct dpll_device_ops {
void *dpll_priv,
unsigned long *qls,
struct netlink_ext_ack *extack);
int (*phase_offset_monitor_set)(const struct dpll_device *dpll,
void *dpll_priv,
enum dpll_feature_state state,
struct netlink_ext_ack *extack);
int (*phase_offset_monitor_get)(const struct dpll_device *dpll,
void *dpll_priv,
enum dpll_feature_state *state,
struct netlink_ext_ack *extack);
};
struct dpll_pin_ops {

View File

@ -192,6 +192,17 @@ enum dpll_pin_capabilities {
#define DPLL_PHASE_OFFSET_DIVIDER 1000
/**
* enum dpll_feature_state - Allow control (enable/disable) and status checking
* over features.
* @DPLL_FEATURE_STATE_DISABLE: feature shall be disabled
* @DPLL_FEATURE_STATE_ENABLE: feature shall be enabled
*/
enum dpll_feature_state {
DPLL_FEATURE_STATE_DISABLE,
DPLL_FEATURE_STATE_ENABLE,
};
enum dpll_a {
DPLL_A_ID = 1,
DPLL_A_MODULE_NAME,
@ -204,6 +215,7 @@ enum dpll_a {
DPLL_A_TYPE,
DPLL_A_LOCK_STATUS_ERROR,
DPLL_A_CLOCK_QUALITY_LEVEL,
DPLL_A_PHASE_OFFSET_MONITOR,
__DPLL_A_MAX,
DPLL_A_MAX = (__DPLL_A_MAX - 1)