>-----Original Message----- >From: Jiri Pirko <jiri@xxxxxxxxxxx> >Sent: Thursday, August 8, 2024 1:54 PM > >Thu, Aug 08, 2024 at 01:20:12PM CEST, arkadiusz.kubalewski@xxxxxxxxx wrote: >>Implement and document new pin attributes for providing Embedded SYNC >>capabilities to the DPLL subsystem users through a netlink pin-get >>do/dump messages. Allow the user to set Embedded SYNC frequency with >>pin-set do netlink message. >> >>Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@xxxxxxxxx> >>Signed-off-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@xxxxxxxxx> >>--- >> Documentation/driver-api/dpll.rst | 21 +++++ >> Documentation/netlink/specs/dpll.yaml | 41 +++++++++ >> drivers/dpll/dpll_netlink.c | 127 ++++++++++++++++++++++++++ >> drivers/dpll/dpll_nl.c | 5 +- >> include/linux/dpll.h | 10 ++ >> include/uapi/linux/dpll.h | 23 +++++ >> 6 files changed, 225 insertions(+), 2 deletions(-) >> >>diff --git a/Documentation/driver-api/dpll.rst b/Documentation/driver- >>api/dpll.rst >>index ea8d16600e16..d7d091d268a1 100644 >>--- a/Documentation/driver-api/dpll.rst >>+++ b/Documentation/driver-api/dpll.rst >>@@ -214,6 +214,27 @@ 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. >> >>+Embedded SYNC >>+============= >>+ >>+Device may provide ability to use Embedded SYNC feature. It allows >>+to embed additional SYNC signal into the base frequency of a pin - a one >>+special pulse of base frequency signal every time SYNC signal pulse >>+happens. The user can configure the frequency of Embedded SYNC. >>+The Embedded SYNC capability is always related to a given base frequency >>+and HW capabilities. The user is provided a range of embedded sync >>+frequencies supported, depending on current base frequency configured for >>+the pin. >>+ >>+ ========================================= >>================================= >>+ ``DPLL_A_PIN_E_SYNC_FREQUENCY`` current embedded SYNC frequency >>+ ``DPLL_A_PIN_E_SYNC_FREQUENCY_SUPPORTED`` nest available embedded SYNC >>+ frequency ranges >>+ ``DPLL_A_PIN_FREQUENCY_MIN`` attr minimum value of frequency >>+ ``DPLL_A_PIN_FREQUENCY_MAX`` attr maximum value of frequency >>+ ``DPLL_A_PIN_E_SYNC_PULSE`` pulse type of embedded SYNC >>+ ========================================= >>================================= >>+ >> Configuration commands group >> ============================ >> >>diff --git a/Documentation/netlink/specs/dpll.yaml >>b/Documentation/netlink/specs/dpll.yaml >>index 94132d30e0e0..0aabf6f1fc2f 100644 >>--- a/Documentation/netlink/specs/dpll.yaml >>+++ b/Documentation/netlink/specs/dpll.yaml >>@@ -210,6 +210,25 @@ 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: pin-e-sync-pulse >>+ doc: | >>+ defines possible pulse length ratio between high and low state when >>+ embedded sync signal occurs on base clock signal frequency >>+ entries: >>+ - >>+ name: none >>+ doc: embedded sync not enabled >>+ - >>+ name: 25-75 >>+ doc: when embedded sync signal occurs 25% of signal's period is in >>+ high state, 75% of signal's period is in low state >>+ - >>+ name: 75-25 > >It is very odd to name enums like this. >Why can't this be: > > name: e-sync-pulse-ratio > type: u32 > doc: Embedded sync signal ratio. Value of 0 to 100. Defines the high > state percentage. > >? > I don't know if the other's are actually used by some vendors, but sure sounds good. > >>+ doc: when embedded sync signal occurs 75% of signal's period is in >>+ high state, 25% of signal's period is in low state >>+ render-max: true >> >> attribute-sets: >> - >>@@ -345,6 +364,24 @@ attribute-sets: >> Value is in PPM (parts per million). >> This may be implemented for example for pin of type >> PIN_TYPE_SYNCE_ETH_PORT. >>+ - >>+ name: e-sync-frequency >>+ type: u64 >>+ doc: | >>+ Embedded Sync frequency. If provided a non-zero value, the pin is > >Why non-zero? Why the attr cannot be omitted instead? > Zero is also a turn-off value for set, but sure for get it can be omitted for a netlink return message. > >>+ configured with an embedded sync signal into its base frequency. >>+ - >>+ name: e-sync-frequency-supported >>+ type: nest >>+ nested-attributes: frequency-range >>+ doc: | >>+ If provided a pin is capable of enabling embedded sync frequency >>+ into it's base frequency signal. >>+ - >>+ name: e-sync-pulse >>+ type: u32 >>+ enum: pin-e-sync-pulse >>+ doc: Embedded sync signal ratio. >> - >> name: pin-parent-device >> subset-of: pin >>@@ -510,6 +547,9 @@ operations: >> - phase-adjust-max >> - phase-adjust >> - fractional-frequency-offset >>+ - e-sync-frequency >>+ - e-sync-frequency-supported >>+ - e-sync-pulse >> >> dump: >> request: >>@@ -536,6 +576,7 @@ operations: >> - parent-device >> - parent-pin >> - phase-adjust >>+ - e-sync-frequency >> - >> name: pin-create-ntf >> doc: Notification about pin appearing >>diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c >>index 98e6ad8528d3..5ae2c0adb98e 100644 >>--- a/drivers/dpll/dpll_netlink.c >>+++ b/drivers/dpll/dpll_netlink.c >>@@ -342,6 +342,50 @@ dpll_msg_add_pin_freq(struct sk_buff *msg, struct >>dpll_pin *pin, >> return 0; >> } >> >>+static int >>+dpll_msg_add_pin_esync(struct sk_buff *msg, struct dpll_pin *pin, > >This is "esync", attributes are "E_SYNC". Why can't they be named >"ESYNC" too? Same comment to another "e_sync" names (vars, ops, etc). > Sure, will change. > >>+ struct dpll_pin_ref *ref, struct netlink_ext_ack *extack) >>+{ >>+ const struct dpll_pin_ops *ops = dpll_pin_ops(ref); >>+ struct dpll_device *dpll = ref->dpll; >>+ enum dpll_pin_e_sync_pulse pulse; >>+ struct dpll_pin_frequency range; >>+ struct nlattr *nest; >>+ u64 esync; >>+ int ret; >>+ >>+ if (!ops->e_sync_get) >>+ return 0; >>+ ret = ops->e_sync_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll, >>+ dpll_priv(dpll), &esync, &range, &pulse, extack); >>+ if (ret == -EOPNOTSUPP) >>+ return 0; >>+ else if (ret) >>+ return ret; >>+ if (nla_put_64bit(msg, DPLL_A_PIN_E_SYNC_FREQUENCY, sizeof(esync), >>+ &esync, DPLL_A_PIN_PAD)) >>+ return -EMSGSIZE; >>+ if (nla_put_u32(msg, DPLL_A_PIN_E_SYNC_PULSE, pulse)) >>+ return -EMSGSIZE; >>+ >>+ nest = nla_nest_start(msg, DPLL_A_PIN_E_SYNC_FREQUENCY_SUPPORTED); >>+ if (!nest) >>+ return -EMSGSIZE; >>+ if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MIN, sizeof(range.min), >>+ &range.min, DPLL_A_PIN_PAD)) { >>+ nla_nest_cancel(msg, nest); >>+ return -EMSGSIZE; >>+ } >>+ if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MAX, sizeof(range.max), >>+ &range.max, DPLL_A_PIN_PAD)) { > >Don't you want to have the MIN-MAX here multiple times. I mean, in >theory, can the device support 2 fixed frequencies for example? >Have it at least for UAPI so this is easily extendable. > Sure, makes sense, will fix. > > >>+ nla_nest_cancel(msg, nest); >>+ return -EMSGSIZE; >>+ } >>+ nla_nest_end(msg, nest); >>+ >>+ return 0; >>+} >>+ >> static bool dpll_pin_is_freq_supported(struct dpll_pin *pin, u32 freq) >> { >> int fs; >>@@ -481,6 +525,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_pin_esync(msg, pin, ref, extack); >> if (ret) >> return ret; >> if (xa_empty(&pin->parent_refs)) >>@@ -738,6 +785,81 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr >>*a, >> return ret; >> } >> >>+static int >>+dpll_pin_e_sync_set(struct dpll_pin *pin, struct nlattr *a, >>+ struct netlink_ext_ack *extack) >>+{ >>+ u64 esync = nla_get_u64(a), old_esync; > >"freq"/"old_freq". That aligns with the existing code. > Ok, will fix. > >>+ struct dpll_pin_ref *ref, *failed; >>+ enum dpll_pin_e_sync_pulse pulse; >>+ struct dpll_pin_frequency range; >>+ const struct dpll_pin_ops *ops; >>+ struct dpll_device *dpll; >>+ unsigned long i; >>+ int ret; >>+ >>+ xa_for_each(&pin->dpll_refs, i, ref) { >>+ ops = dpll_pin_ops(ref); >>+ if (!ops->e_sync_set || > >No need for line break. > Sure, will fix. > >>+ !ops->e_sync_get) { >>+ NL_SET_ERR_MSG(extack, >>+ "embedded sync feature is not supported by >>this device"); >>+ return -EOPNOTSUPP; >>+ } >>+ } >>+ ref = dpll_xa_ref_dpll_first(&pin->dpll_refs); >>+ ops = dpll_pin_ops(ref); >>+ dpll = ref->dpll; >>+ ret = ops->e_sync_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll, >>+ dpll_priv(dpll), &old_esync, &range, &pulse, extack); > >Line over 80cols? Didn't checkpatch warn you? > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=bdc48fa11e46f867ea4d75fa59ee87a7f48be144 But sure, I will use 80. Thank you! Arkadiusz > >>+ if (ret) { >>+ NL_SET_ERR_MSG(extack, "unable to get current embedded sync >>frequency value"); >>+ return ret; >>+ } >>+ if (esync == old_esync) >>+ return 0; >>+ if (esync > range.max || esync < range.min) { >>+ NL_SET_ERR_MSG_ATTR(extack, a, >>+ "requested embedded sync frequency value is not >>supported by this device"); >>+ return -EINVAL; >>+ } >>+ >>+ xa_for_each(&pin->dpll_refs, i, ref) { >>+ void *pin_dpll_priv; >>+ >>+ ops = dpll_pin_ops(ref); >>+ dpll = ref->dpll; >>+ pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin); >>+ ret = ops->e_sync_set(pin, pin_dpll_priv, dpll, dpll_priv(dpll), >>+ esync, extack); >>+ if (ret) { >>+ failed = ref; >>+ NL_SET_ERR_MSG_FMT(extack, >>+ "embedded sync frequency set failed for >>dpll_id:%u", >>+ dpll->id); >>+ goto rollback; >>+ } >>+ } >>+ __dpll_pin_change_ntf(pin); >>+ >>+ return 0; >>+ >>+rollback: >>+ xa_for_each(&pin->dpll_refs, i, ref) { >>+ void *pin_dpll_priv; >>+ >>+ if (ref == failed) >>+ break; >>+ ops = dpll_pin_ops(ref); >>+ dpll = ref->dpll; >>+ pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin); >>+ if (ops->e_sync_set(pin, pin_dpll_priv, dpll, dpll_priv(dpll), >>+ old_esync, extack)) >>+ NL_SET_ERR_MSG(extack, "set embedded sync frequency >>rollback failed"); >>+ } >>+ return ret; >>+} >>+ >> static int >> dpll_pin_on_pin_state_set(struct dpll_pin *pin, u32 parent_idx, >> enum dpll_pin_state state, >>@@ -1039,6 +1161,11 @@ dpll_pin_set_from_nlattr(struct dpll_pin *pin, struct >>genl_info *info) >> if (ret) >> return ret; >> break; >>+ case DPLL_A_PIN_E_SYNC_FREQUENCY: >>+ ret = dpll_pin_e_sync_set(pin, a, info->extack); >>+ if (ret) >>+ return ret; >>+ break; >> } >> } >> >>diff --git a/drivers/dpll/dpll_nl.c b/drivers/dpll/dpll_nl.c >>index 1e95f5397cfc..ba79a47f3a17 100644 >>--- a/drivers/dpll/dpll_nl.c >>+++ b/drivers/dpll/dpll_nl.c >>@@ -62,7 +62,7 @@ static const struct nla_policy >>dpll_pin_get_dump_nl_policy[DPLL_A_PIN_ID + 1] = >> }; >> >> /* DPLL_CMD_PIN_SET - do */ >>-static const struct nla_policy >>dpll_pin_set_nl_policy[DPLL_A_PIN_PHASE_ADJUST + 1] = { >>+static const struct nla_policy >>dpll_pin_set_nl_policy[DPLL_A_PIN_E_SYNC_FREQUENCY + 1] = { >> [DPLL_A_PIN_ID] = { .type = NLA_U32, }, >> [DPLL_A_PIN_FREQUENCY] = { .type = NLA_U64, }, >> [DPLL_A_PIN_DIRECTION] = NLA_POLICY_RANGE(NLA_U32, 1, 2), >>@@ -71,6 +71,7 @@ static const struct nla_policy >>dpll_pin_set_nl_policy[DPLL_A_PIN_PHASE_ADJUST + >> [DPLL_A_PIN_PARENT_DEVICE] = >>NLA_POLICY_NESTED(dpll_pin_parent_device_nl_policy), >> [DPLL_A_PIN_PARENT_PIN] = >>NLA_POLICY_NESTED(dpll_pin_parent_pin_nl_policy), >> [DPLL_A_PIN_PHASE_ADJUST] = { .type = NLA_S32, }, >>+ [DPLL_A_PIN_E_SYNC_FREQUENCY] = { .type = NLA_U64, }, >> }; >> >> /* Ops table for dpll */ >>@@ -138,7 +139,7 @@ static const struct genl_split_ops dpll_nl_ops[] = { >> .doit = dpll_nl_pin_set_doit, >> .post_doit = dpll_pin_post_doit, >> .policy = dpll_pin_set_nl_policy, >>- .maxattr = DPLL_A_PIN_PHASE_ADJUST, >>+ .maxattr = DPLL_A_PIN_E_SYNC_FREQUENCY, >> .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, >> }, >> }; >>diff --git a/include/linux/dpll.h b/include/linux/dpll.h >>index d275736230b3..137ab4bcb60e 100644 >>--- a/include/linux/dpll.h >>+++ b/include/linux/dpll.h >>@@ -15,6 +15,7 @@ >> >> struct dpll_device; >> struct dpll_pin; >>+struct dpll_pin_frequency; >> >> struct dpll_device_ops { >> int (*mode_get)(const struct dpll_device *dpll, void *dpll_priv, >>@@ -83,6 +84,15 @@ 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 (*e_sync_set)(const struct dpll_pin *pin, void *pin_priv, >>+ const struct dpll_device *dpll, void *dpll_priv, >>+ u64 e_sync_freq, struct netlink_ext_ack *extack); >>+ int (*e_sync_get)(const struct dpll_pin *pin, void *pin_priv, >>+ const struct dpll_device *dpll, void *dpll_priv, >>+ u64 *e_sync_freq, >>+ struct dpll_pin_frequency *e_sync_range, >>+ enum dpll_pin_e_sync_pulse *pulse, >>+ struct netlink_ext_ack *extack); >> }; >> >> struct dpll_pin_frequency { >>diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h >>index 0c13d7f1a1bc..2a80a6fb0d1d 100644 >>--- a/include/uapi/linux/dpll.h >>+++ b/include/uapi/linux/dpll.h >>@@ -169,6 +169,26 @@ enum dpll_pin_capabilities { >> >> #define DPLL_PHASE_OFFSET_DIVIDER 1000 >> >>+/** >>+ * enum dpll_pin_e_sync_pulse - defines possible pulse length ratio between >>+ * high and low state when embedded sync signal occurs on base clock >>signal >>+ * frequency >>+ * @DPLL_PIN_E_SYNC_PULSE_NONE: embedded sync not enabled >>+ * @DPLL_PIN_E_SYNC_PULSE_25_75: when embedded sync signal occurs 25% of >>+ * signal's period is in high state, 75% of signal's period is in low >>state >>+ * @DPLL_PIN_E_SYNC_PULSE_75_25: when embedded sync signal occurs 75% of >>+ * signal's period is in high state, 25% of signal's period is in low >>state >>+ */ >>+enum dpll_pin_e_sync_pulse { >>+ DPLL_PIN_E_SYNC_PULSE_NONE, >>+ DPLL_PIN_E_SYNC_PULSE_25_75, >>+ DPLL_PIN_E_SYNC_PULSE_75_25, >>+ >>+ /* private: */ >>+ __DPLL_PIN_E_SYNC_PULSE_MAX, >>+ DPLL_PIN_E_SYNC_PULSE_MAX = (__DPLL_PIN_E_SYNC_PULSE_MAX - 1) >>+}; >>+ >> enum dpll_a { >> DPLL_A_ID = 1, >> DPLL_A_MODULE_NAME, >>@@ -210,6 +230,9 @@ enum dpll_a_pin { >> DPLL_A_PIN_PHASE_ADJUST, >> DPLL_A_PIN_PHASE_OFFSET, >> DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET, >>+ DPLL_A_PIN_E_SYNC_FREQUENCY, >>+ DPLL_A_PIN_E_SYNC_FREQUENCY_SUPPORTED, >>+ DPLL_A_PIN_E_SYNC_PULSE, >> >> __DPLL_A_PIN_MAX, >> DPLL_A_PIN_MAX = (__DPLL_A_PIN_MAX - 1) >>-- >>2.38.1 >>