[PATCH net-next 2/3] dpll: add actual frequency monitoring callback ops

Ivan Vecera posted 3 patches 1 week, 1 day ago
[PATCH net-next 2/3] dpll: add actual frequency monitoring callback ops
Posted by Ivan Vecera 1 week, 1 day ago
Add new callback operations for a dpll device:
- freq_monitor_get(..) - to obtain current state of frequency monitor
  feature from dpll device,
- freq_monitor_set(..) - to allow feature configuration.

Add new callback operation for a dpll pin:
- actual_freq_get(..) - to obtain the actual (measured) frequency in Hz.

Obtain the feature state value using the get callback and provide it to
the user if the device driver implements callbacks. The actual_freq_get
pin callback is only invoked when the frequency monitor is enabled.

Execute the set callback upon user requests.

Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
 drivers/dpll/dpll_netlink.c | 90 +++++++++++++++++++++++++++++++++++++
 include/linux/dpll.h        | 12 +++++
 2 files changed, 102 insertions(+)

diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c
index 83cbd64abf5a4..6fe4ae38cff62 100644
--- a/drivers/dpll/dpll_netlink.c
+++ b/drivers/dpll/dpll_netlink.c
@@ -175,6 +175,26 @@ dpll_msg_add_phase_offset_monitor(struct sk_buff *msg, struct dpll_device *dpll,
 	return 0;
 }
 
+static int
+dpll_msg_add_freq_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->freq_monitor_set && ops->freq_monitor_get) {
+		ret = ops->freq_monitor_get(dpll, dpll_priv(dpll),
+					    &state, extack);
+		if (ret)
+			return ret;
+		if (nla_put_u32(msg, DPLL_A_FREQUENCY_MONITOR, state))
+			return -EMSGSIZE;
+	}
+
+	return 0;
+}
+
 static int
 dpll_msg_add_phase_offset_avg_factor(struct sk_buff *msg,
 				     struct dpll_device *dpll,
@@ -400,6 +420,38 @@ static int dpll_msg_add_ffo(struct sk_buff *msg, struct dpll_pin *pin,
 			    ffo);
 }
 
+static int dpll_msg_add_actual_freq(struct sk_buff *msg, struct dpll_pin *pin,
+				    struct dpll_pin_ref *ref,
+				    struct netlink_ext_ack *extack)
+{
+	const struct dpll_device_ops *dev_ops = dpll_device_ops(ref->dpll);
+	const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
+	struct dpll_device *dpll = ref->dpll;
+	enum dpll_feature_state state;
+	u64 actual_freq;
+	int ret;
+
+	if (!ops->actual_freq_get)
+		return 0;
+	if (dev_ops->freq_monitor_get) {
+		ret = dev_ops->freq_monitor_get(dpll, dpll_priv(dpll),
+						&state, extack);
+		if (ret)
+			return ret;
+		if (state == DPLL_FEATURE_STATE_DISABLE)
+			return 0;
+	}
+	ret = ops->actual_freq_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
+				   dpll, dpll_priv(dpll), &actual_freq, extack);
+	if (ret)
+		return ret;
+	if (nla_put_64bit(msg, DPLL_A_PIN_ACTUAL_FREQUENCY,
+			  sizeof(actual_freq), &actual_freq, DPLL_A_PIN_PAD))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
 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)
@@ -670,6 +722,9 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
 	if (ret)
 		return ret;
 	ret = dpll_msg_add_ffo(msg, pin, ref, extack);
+	if (ret)
+		return ret;
+	ret = dpll_msg_add_actual_freq(msg, pin, ref, extack);
 	if (ret)
 		return ret;
 	ret = dpll_msg_add_pin_esync(msg, pin, ref, extack);
@@ -722,6 +777,9 @@ dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg,
 	if (ret)
 		return ret;
 	ret = dpll_msg_add_phase_offset_avg_factor(msg, dpll, extack);
+	if (ret)
+		return ret;
+	ret = dpll_msg_add_freq_monitor(msg, dpll, extack);
 	if (ret)
 		return ret;
 
@@ -948,6 +1006,32 @@ dpll_phase_offset_avg_factor_set(struct dpll_device *dpll, struct nlattr *a,
 						extack);
 }
 
+static int
+dpll_freq_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->freq_monitor_set && ops->freq_monitor_get)) {
+		NL_SET_ERR_MSG_ATTR(extack, a,
+				    "dpll device not capable of frequency monitor");
+		return -EOPNOTSUPP;
+	}
+	ret = ops->freq_monitor_get(dpll, dpll_priv(dpll), &old_state,
+				    extack);
+	if (ret) {
+		NL_SET_ERR_MSG(extack,
+			       "unable to get current state of frequency monitor");
+		return ret;
+	}
+	if (state == old_state)
+		return 0;
+
+	return ops->freq_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)
@@ -1878,6 +1962,12 @@ dpll_set_from_nlattr(struct dpll_device *dpll, struct genl_info *info)
 			if (ret)
 				return ret;
 			break;
+		case DPLL_A_FREQUENCY_MONITOR:
+			ret = dpll_freq_monitor_set(dpll, a,
+						    info->extack);
+			if (ret)
+				return ret;
+			break;
 		}
 	}
 
diff --git a/include/linux/dpll.h b/include/linux/dpll.h
index 2ce295b46b8cd..d14cdc2a37f62 100644
--- a/include/linux/dpll.h
+++ b/include/linux/dpll.h
@@ -52,6 +52,14 @@ struct dpll_device_ops {
 	int (*phase_offset_avg_factor_get)(const struct dpll_device *dpll,
 					   void *dpll_priv, u32 *factor,
 					   struct netlink_ext_ack *extack);
+	int (*freq_monitor_set)(const struct dpll_device *dpll,
+				void *dpll_priv,
+				enum dpll_feature_state state,
+				struct netlink_ext_ack *extack);
+	int (*freq_monitor_get)(const struct dpll_device *dpll,
+				void *dpll_priv,
+				enum dpll_feature_state *state,
+				struct netlink_ext_ack *extack);
 };
 
 struct dpll_pin_ops {
@@ -110,6 +118,10 @@ struct dpll_pin_ops {
 	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);
+	int (*actual_freq_get)(const struct dpll_pin *pin, void *pin_priv,
+			       const struct dpll_device *dpll, void *dpll_priv,
+			       u64 *actual_freq,
+			       struct netlink_ext_ack *extack);
 	int (*esync_set)(const struct dpll_pin *pin, void *pin_priv,
 			 const struct dpll_device *dpll, void *dpll_priv,
 			 u64 freq, struct netlink_ext_ack *extack);
-- 
2.52.0
Re: [PATCH net-next 2/3] dpll: add actual frequency monitoring callback ops
Posted by Vadim Fedorenko 1 week ago
On 25/03/2026 19:39, Ivan Vecera wrote:

> +static int dpll_msg_add_actual_freq(struct sk_buff *msg, struct dpll_pin *pin,
> +				    struct dpll_pin_ref *ref,
> +				    struct netlink_ext_ack *extack)
> +{
> +	const struct dpll_device_ops *dev_ops = dpll_device_ops(ref->dpll);
> +	const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
> +	struct dpll_device *dpll = ref->dpll;
> +	enum dpll_feature_state state;
> +	u64 actual_freq;
> +	int ret;
> +
> +	if (!ops->actual_freq_get)
> +		return 0;
> +	if (dev_ops->freq_monitor_get) {
> +		ret = dev_ops->freq_monitor_get(dpll, dpll_priv(dpll),
> +						&state, extack);
> +		if (ret)
> +			return ret;
> +		if (state == DPLL_FEATURE_STATE_DISABLE)
> +			return 0;

I think we have to signal back to user that frequency monitoring is
disabled via extack.

> +	}
> +	ret = ops->actual_freq_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
> +				   dpll, dpll_priv(dpll), &actual_freq, extack);
> +	if (ret)
> +		return ret;
> +	if (nla_put_64bit(msg, DPLL_A_PIN_ACTUAL_FREQUENCY,
> +			  sizeof(actual_freq), &actual_freq, DPLL_A_PIN_PAD))
> +		return -EMSGSIZE;
> +
> +	return 0;
Re: [PATCH net-next 2/3] dpll: add actual frequency monitoring callback ops
Posted by Ivan Vecera 1 week ago
On 3/26/26 12:21 PM, Vadim Fedorenko wrote:
> On 25/03/2026 19:39, Ivan Vecera wrote:
> 
>> +static int dpll_msg_add_actual_freq(struct sk_buff *msg, struct 
>> dpll_pin *pin,
>> +                    struct dpll_pin_ref *ref,
>> +                    struct netlink_ext_ack *extack)
>> +{
>> +    const struct dpll_device_ops *dev_ops = dpll_device_ops(ref->dpll);
>> +    const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
>> +    struct dpll_device *dpll = ref->dpll;
>> +    enum dpll_feature_state state;
>> +    u64 actual_freq;
>> +    int ret;
>> +
>> +    if (!ops->actual_freq_get)
>> +        return 0;
>> +    if (dev_ops->freq_monitor_get) {
>> +        ret = dev_ops->freq_monitor_get(dpll, dpll_priv(dpll),
>> +                        &state, extack);
>> +        if (ret)
>> +            return ret;
>> +        if (state == DPLL_FEATURE_STATE_DISABLE)
>> +            return 0;
> 
> I think we have to signal back to user that frequency monitoring is
> disabled via extack.

Hi Vadim,

This would break pin-get operation... Do or dump pin-get operation would
fail with this extack message.

Here we can check if the freq-monitoring is enabled and conditionally
call actual_freq_get() or measured_freq_get()

-or-

Call this callback unconditionally and check for return code and if a
driver returns e.g. -ENODATA then skip nla_put_64bit() but return
success.

WDYT?

Thanks,
Ivan

Re: [PATCH net-next 2/3] dpll: add actual frequency monitoring callback ops
Posted by Ivan Vecera 3 days, 15 hours ago
On 3/26/26 6:48 PM, Ivan Vecera wrote:
> On 3/26/26 12:21 PM, Vadim Fedorenko wrote:
>> On 25/03/2026 19:39, Ivan Vecera wrote:
>>
>>> +static int dpll_msg_add_actual_freq(struct sk_buff *msg, struct 
>>> dpll_pin *pin,
>>> +                    struct dpll_pin_ref *ref,
>>> +                    struct netlink_ext_ack *extack)
>>> +{
>>> +    const struct dpll_device_ops *dev_ops = dpll_device_ops(ref->dpll);
>>> +    const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
>>> +    struct dpll_device *dpll = ref->dpll;
>>> +    enum dpll_feature_state state;
>>> +    u64 actual_freq;
>>> +    int ret;
>>> +
>>> +    if (!ops->actual_freq_get)
>>> +        return 0;
>>> +    if (dev_ops->freq_monitor_get) {
>>> +        ret = dev_ops->freq_monitor_get(dpll, dpll_priv(dpll),
>>> +                        &state, extack);
>>> +        if (ret)
>>> +            return ret;
>>> +        if (state == DPLL_FEATURE_STATE_DISABLE)
>>> +            return 0;
>>
>> I think we have to signal back to user that frequency monitoring is
>> disabled via extack.
> 
> Hi Vadim,
> 
> This would break pin-get operation... Do or dump pin-get operation would
> fail with this extack message.
> 
> Here we can check if the freq-monitoring is enabled and conditionally
> call actual_freq_get() or measured_freq_get()
> 
> -or-
> 
> Call this callback unconditionally and check for return code and if a
> driver returns e.g. -ENODATA then skip nla_put_64bit() but return
> success.
> 
> WDYT?

Vadim?

Re: [PATCH net-next 2/3] dpll: add actual frequency monitoring callback ops
Posted by Vadim Fedorenko 3 days, 13 hours ago
On 30/03/2026 09:52, Ivan Vecera wrote:
> On 3/26/26 6:48 PM, Ivan Vecera wrote:
>> On 3/26/26 12:21 PM, Vadim Fedorenko wrote:
>>> On 25/03/2026 19:39, Ivan Vecera wrote:
>>>
>>>> +static int dpll_msg_add_actual_freq(struct sk_buff *msg, struct 
>>>> dpll_pin *pin,
>>>> +                    struct dpll_pin_ref *ref,
>>>> +                    struct netlink_ext_ack *extack)
>>>> +{
>>>> +    const struct dpll_device_ops *dev_ops = dpll_device_ops(ref- 
>>>> >dpll);
>>>> +    const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
>>>> +    struct dpll_device *dpll = ref->dpll;
>>>> +    enum dpll_feature_state state;
>>>> +    u64 actual_freq;
>>>> +    int ret;
>>>> +
>>>> +    if (!ops->actual_freq_get)
>>>> +        return 0;
>>>> +    if (dev_ops->freq_monitor_get) {
>>>> +        ret = dev_ops->freq_monitor_get(dpll, dpll_priv(dpll),
>>>> +                        &state, extack);
>>>> +        if (ret)
>>>> +            return ret;
>>>> +        if (state == DPLL_FEATURE_STATE_DISABLE)
>>>> +            return 0;
>>>
>>> I think we have to signal back to user that frequency monitoring is
>>> disabled via extack.
>>
>> Hi Vadim,
>>
>> This would break pin-get operation... Do or dump pin-get operation would
>> fail with this extack message.
>>
>> Here we can check if the freq-monitoring is enabled and conditionally
>> call actual_freq_get() or measured_freq_get()

Let's make it this way, we don't want to waste even small amount of
resources for useless call.

>>
>> -or-
>>
>> Call this callback unconditionally and check for return code and if a
>> driver returns e.g. -ENODATA then skip nla_put_64bit() but return
>> success.
>>
>> WDYT?
> 
> Vadim?

Sorry, was AFK this Friday/weekend