]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
dpll: add frequency monitoring support
authorIvan Vecera <ivecera@redhat.com>
Mon, 4 May 2026 16:30:14 +0000 (18:30 +0200)
committerDavid Ahern <dsahern@kernel.org>
Thu, 7 May 2026 15:20:23 +0000 (09:20 -0600)
Add support for the new frequency monitoring feature from the kernel
patch series "dpll: add actual frequency monitoring feature". This
includes:

- DPLL_A_FREQUENCY_MONITOR device attribute (enable/disable)
- DPLL_A_PIN_MEASURED_FREQUENCY pin attribute displayed as fractional Hz
  using DPLL_PR_MEASURED_FREQUENCY macro (kernel reports in mHz)
- device set: frequency-monitor { enable | disable }
- Refactor phase-offset-monitor to use new dpll_parse_attr_feature_state
  helper shared with frequency-monitor
- Update man page and bash-completion

Reviewed-by: Petr Oros <poros@redhat.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
bash-completion/dpll
dpll/dpll.c
man/man8/dpll.8

index 542b99c2fce264cfa3411332372dfeb2c9bb3091..7ddcf529d429db0434645479ecea6efd3f11e4af 100644 (file)
@@ -100,7 +100,7 @@ _dpll_device()
                     COMPREPLY=( $( compgen -W "automatic manual" -- "$cur" ) )
                     return 0
                     ;;
-                phase-offset-monitor)
+                phase-offset-monitor|frequency-monitor)
                     COMPREPLY=( $( compgen -W "enable disable true false 0 1" -- "$cur" ) )
                     return 0
                     ;;
@@ -110,7 +110,7 @@ _dpll_device()
                     ;;
                 *)
                     COMPREPLY=( $( compgen -W "id mode phase-offset-monitor \
-                        phase-offset-avg-factor" -- "$cur" ) )
+                        phase-offset-avg-factor frequency-monitor" -- "$cur" ) )
                     return 0
                     ;;
             esac
index 1c5d2b1b7f28d4f35fb0ef81a5d98ae3e2f5cc51..febf2a5d1fbdf4cb34a97eea763422ca72f8f921 100644 (file)
@@ -313,6 +313,26 @@ static int dpll_parse_attr_str(struct dpll *dpll, struct nlmsghdr *nlh,
        return 0;
 }
 
+static int dpll_parse_attr_feature_state(struct dpll *dpll,
+                                       struct nlmsghdr *nlh,
+                                       const char *arg_name, int attr_id)
+{
+       const char *str = dpll_argv_next(dpll);
+       bool val;
+
+       if (!str) {
+               pr_err("%s requires an argument\n", arg_name);
+               return -EINVAL;
+       }
+       if (str_to_bool(str, &val)) {
+               pr_err("invalid %s value: %s (use enable/disable)\n",
+                      arg_name, str);
+               return -EINVAL;
+       }
+       mnl_attr_put_u32(nlh, attr_id, val ? 1 : 0);
+       return 0;
+}
+
 static int dpll_parse_attr_enum(struct dpll *dpll, struct nlmsghdr *nlh,
                                const char *arg_name, int attr_id,
                                int (*parse_func)(struct dpll *, __u32 *))
@@ -473,6 +493,22 @@ static void dpll_pr_phase_offset(struct nlattr *attr)
        print_s64(PRINT_FP, NULL, "%03lld ps", d.rem);
 }
 
+/* Measured frequency - JSON prints raw mHz value, FP prints fractional Hz */
+static void dpll_pr_measured_frequency(struct nlattr *attr)
+{
+       __u64 val;
+       lldiv_t d;
+
+       if (!attr)
+               return;
+
+       val = mnl_attr_get_u64(attr);
+       d = lldiv(val, DPLL_PIN_MEASURED_FREQUENCY_DIVIDER);
+       print_lluint(PRINT_JSON, "measured-frequency", NULL, val);
+       print_s64(PRINT_FP, NULL, "  measured-frequency: %lld.", d.quot);
+       print_s64(PRINT_FP, NULL, "%03lld Hz\n", d.rem);
+}
+
 /* Print frequency range (or single value if min==max) */
 static void dpll_pr_freq_range(__u64 freq_min, __u64 freq_max)
 {
@@ -660,6 +696,7 @@ static void cmd_device_help(void)
        pr_err("       dpll device set id DEVICE_ID [ mode { automatic | manual } ]\n");
        pr_err("                                    [ phase-offset-monitor { enable | disable } ]\n");
        pr_err("                                    [ phase-offset-avg-factor NUM ]\n");
+       pr_err("                                    [ frequency-monitor { enable | disable } ]\n");
        pr_err("       dpll device id-get [ module-name NAME ] [ clock-id ID ] [ type TYPE ]\n");
 }
 
@@ -1061,6 +1098,10 @@ static void dpll_device_print_attrs(const struct nlmsghdr *nlh,
                             str_enable_disable);
        DPLL_PR_UINT(tb, DPLL_A_PHASE_OFFSET_AVG_FACTOR,
                     "phase-offset-avg-factor");
+       DPLL_PR_ENUM_STR_FMT(tb, DPLL_A_FREQUENCY_MONITOR,
+                            "frequency-monitor",
+                            "  frequency-monitor: %s\n",
+                            str_enable_disable);
 }
 
 /* Netlink callback - device get (single device) */
@@ -1222,25 +1263,20 @@ static int cmd_device_set(struct dpll *dpll)
                                                 dpll_parse_mode))
                                return -EINVAL;
                } else if (dpll_argv_match(dpll, "phase-offset-monitor")) {
-                       const char *str = dpll_argv_next(dpll);
-                       bool val;
-
-                       if (!str) {
-                               pr_err("phase-offset-monitor requires an argument\n");
+                       if (dpll_parse_attr_feature_state(dpll, nlh,
+                                                         "phase-offset-monitor",
+                                                         DPLL_A_PHASE_OFFSET_MONITOR))
                                return -EINVAL;
-                       }
-                       if (str_to_bool(str, &val)) {
-                               pr_err("invalid phase-offset-monitor value: %s (use enable/disable)\n",
-                                      str);
-                               return -EINVAL;
-                       }
-                       mnl_attr_put_u32(nlh, DPLL_A_PHASE_OFFSET_MONITOR,
-                                        val ? 1 : 0);
                } else if (dpll_argv_match(dpll, "phase-offset-avg-factor")) {
                        if (dpll_parse_attr_u32(dpll, nlh,
                                                "phase-offset-avg-factor",
                                                DPLL_A_PHASE_OFFSET_AVG_FACTOR))
                                return -EINVAL;
+               } else if (dpll_argv_match(dpll, "frequency-monitor")) {
+                       if (dpll_parse_attr_feature_state(dpll, nlh,
+                                                         "frequency-monitor",
+                                                         DPLL_A_FREQUENCY_MONITOR))
+                               return -EINVAL;
                } else {
                        pr_err("unknown option: %s\n", dpll_argv(dpll));
                        return -EINVAL;
@@ -1604,6 +1640,7 @@ static void dpll_pin_print_attrs(struct nlattr **tb)
        DPLL_PR_ENUM_STR(tb, DPLL_A_PIN_TYPE, "type", dpll_pin_type_name);
        DPLL_PR_U64_FMT(tb, DPLL_A_PIN_FREQUENCY, "frequency",
                        "  frequency: %" PRIu64 " Hz\n");
+       dpll_pr_measured_frequency(tb[DPLL_A_PIN_MEASURED_FREQUENCY]);
 
        dpll_pin_print_freq_supported(tb[DPLL_A_PIN_FREQUENCY_SUPPORTED]);
 
index 89f17af749233cd7bf82aebb755f8eed66207358..c0d4b9caef2a6cc670f5e28ff875e42aad591413 100644 (file)
@@ -109,9 +109,11 @@ Lock status (locked-ho-ack, locked, unlocked, holdover)
 Temperature (if supported)
 .IP \[bu]
 Type (PPS or EEC)
+.IP \[bu]
+Frequency monitor status (enable/disable)
 .RE
 
-.SS dpll device set id ID [ mode { automatic | manual } ] [ phase-offset-monitor { enable | disable } ] [ phase-offset-avg-factor FACTOR ]
+.SS dpll device set id ID [ PARAMETER VALUE ] ...
 
 Configure DPLL device parameters.
 
@@ -140,6 +142,14 @@ When enabled, the kernel continuously measures and reports phase differences.
 Set the averaging factor (1-255) applied to phase offset calculations.
 Higher values provide smoother but slower-responding measurements.
 
+.TP
+.BI frequency-monitor " { enable | disable }"
+Enable or disable frequency monitoring on the device. When enabled, the
+kernel continuously measures and reports actual pin frequencies, which can
+be read via the
+.B measured-frequency
+field in pin show output.
+
 .SS dpll device id-get [ module-name NAME ] [ clock-id ID ] [ type TYPE ]
 
 Retrieve the device ID based on identifying attributes. Useful for scripting
@@ -233,7 +243,9 @@ Board label (hardware label from device tree or ACPI)
 .IP \[bu]
 Pin type (mux, ext, synce-eth-port, int-oscillator, gnss)
 .IP \[bu]
-Frequency and supported frequency ranges
+Configured frequency and supported frequency ranges
+.IP \[bu]
+Measured frequency in Hz (when frequency monitoring is enabled)
 .IP \[bu]
 Capabilities (state-can-change, priority-can-change, direction-can-change)
 .IP \[bu]
@@ -372,6 +384,11 @@ Press Ctrl+C to stop monitoring.
 .B dpll device set id 0 phase-offset-monitor enable
 .fi
 
+.SS Enable frequency monitoring on device 0
+.nf
+.B dpll device set id 0 frequency-monitor enable
+.fi
+
 .SS Show all EEC devices
 .nf
 .B dpll device show type eec