Skip to content

Commit 590ff36

Browse files
committed
dpll: add reference sync get/set
JIRA: https://issues.redhat.com/browse/RHEL-126529 Conflicts: - adjusted a context conflict caused by RH_KABI_RESERVE macros in struct dpll_pin_ops. Upstream commit(s): commit 58256a2 Author: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com> Date: Thu Jun 26 15:52:18 2025 +0200 dpll: add reference sync get/set Define function for reference sync pin registration and callback ops to set/get current feature state. Implement netlink handler to fill netlink messages with reference sync pin configuration of capable pins (pin-get). Implement netlink handler to call proper ops and configure reference sync pin state (pin-set). Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com> Reviewed-by: Milena Olech <milena.olech@intel.com> Reviewed-by: Jiri Pirko <jiri@nvidia.com> Signed-off-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com> Link: https://patch.msgid.link/20250626135219.1769350-3-arkadiusz.kubalewski@intel.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Petr Oros <poros@redhat.com>
1 parent abbfd03 commit 590ff36

File tree

5 files changed

+233
-19
lines changed

5 files changed

+233
-19
lines changed

drivers/dpll/dpll_core.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module,
506506
refcount_set(&pin->refcount, 1);
507507
xa_init_flags(&pin->dpll_refs, XA_FLAGS_ALLOC);
508508
xa_init_flags(&pin->parent_refs, XA_FLAGS_ALLOC);
509+
xa_init_flags(&pin->ref_sync_pins, XA_FLAGS_ALLOC);
509510
ret = xa_alloc_cyclic(&dpll_pin_xa, &pin->id, pin, xa_limit_32b,
510511
&dpll_pin_xa_id, GFP_KERNEL);
511512
if (ret < 0)
@@ -514,6 +515,7 @@ dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module,
514515
err_xa_alloc:
515516
xa_destroy(&pin->dpll_refs);
516517
xa_destroy(&pin->parent_refs);
518+
xa_destroy(&pin->ref_sync_pins);
517519
dpll_pin_prop_free(&pin->prop);
518520
err_pin_prop:
519521
kfree(pin);
@@ -595,6 +597,7 @@ void dpll_pin_put(struct dpll_pin *pin)
595597
xa_erase(&dpll_pin_xa, pin->id);
596598
xa_destroy(&pin->dpll_refs);
597599
xa_destroy(&pin->parent_refs);
600+
xa_destroy(&pin->ref_sync_pins);
598601
dpll_pin_prop_free(&pin->prop);
599602
kfree_rcu(pin, rcu);
600603
}
@@ -659,11 +662,26 @@ dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
659662
}
660663
EXPORT_SYMBOL_GPL(dpll_pin_register);
661664

665+
static void dpll_pin_ref_sync_pair_del(u32 ref_sync_pin_id)
666+
{
667+
struct dpll_pin *pin, *ref_sync_pin;
668+
unsigned long i;
669+
670+
xa_for_each(&dpll_pin_xa, i, pin) {
671+
ref_sync_pin = xa_load(&pin->ref_sync_pins, ref_sync_pin_id);
672+
if (ref_sync_pin) {
673+
xa_erase(&pin->ref_sync_pins, ref_sync_pin_id);
674+
__dpll_pin_change_ntf(pin);
675+
}
676+
}
677+
}
678+
662679
static void
663680
__dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin,
664681
const struct dpll_pin_ops *ops, void *priv, void *cookie)
665682
{
666683
ASSERT_DPLL_PIN_REGISTERED(pin);
684+
dpll_pin_ref_sync_pair_del(pin->id);
667685
dpll_xa_ref_pin_del(&dpll->pin_refs, pin, ops, priv, cookie);
668686
dpll_xa_ref_dpll_del(&pin->dpll_refs, dpll, ops, priv, cookie);
669687
if (xa_empty(&pin->dpll_refs))
@@ -783,6 +801,33 @@ void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin,
783801
}
784802
EXPORT_SYMBOL_GPL(dpll_pin_on_pin_unregister);
785803

804+
/**
805+
* dpll_pin_ref_sync_pair_add - create a reference sync signal pin pair
806+
* @pin: pin which produces the base frequency
807+
* @ref_sync_pin: pin which produces the sync signal
808+
*
809+
* Once pins are paired, the user-space configuration of reference sync pair
810+
* is possible.
811+
* Context: Acquires a lock (dpll_lock)
812+
* Return:
813+
* * 0 on success
814+
* * negative - error value
815+
*/
816+
int dpll_pin_ref_sync_pair_add(struct dpll_pin *pin,
817+
struct dpll_pin *ref_sync_pin)
818+
{
819+
int ret;
820+
821+
mutex_lock(&dpll_lock);
822+
ret = xa_insert(&pin->ref_sync_pins, ref_sync_pin->id,
823+
ref_sync_pin, GFP_KERNEL);
824+
__dpll_pin_change_ntf(pin);
825+
mutex_unlock(&dpll_lock);
826+
827+
return ret;
828+
}
829+
EXPORT_SYMBOL_GPL(dpll_pin_ref_sync_pair_add);
830+
786831
static struct dpll_device_registration *
787832
dpll_device_registration_first(struct dpll_device *dpll)
788833
{

drivers/dpll/dpll_core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ struct dpll_device {
4949
* @module: module of creator
5050
* @dpll_refs: hold referencees to dplls pin was registered with
5151
* @parent_refs: hold references to parent pins pin was registered with
52+
* @ref_sync_pins: hold references to pins for Reference SYNC feature
5253
* @prop: pin properties copied from the registerer
5354
* @refcount: refcount
5455
* @rcu: rcu_head for kfree_rcu()
@@ -65,6 +66,7 @@ struct dpll_pin {
6566
struct module *module;
6667
struct xarray dpll_refs;
6768
struct xarray parent_refs;
69+
struct xarray ref_sync_pins;
6870
struct dpll_pin_properties prop;
6971
refcount_t refcount;
7072
struct rcu_head rcu;

drivers/dpll/dpll_netlink.c

Lines changed: 171 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,24 @@ dpll_msg_add_dev_parent_handle(struct sk_buff *msg, u32 id)
4848
return 0;
4949
}
5050

51+
static bool dpll_pin_available(struct dpll_pin *pin)
52+
{
53+
struct dpll_pin_ref *par_ref;
54+
unsigned long i;
55+
56+
if (!xa_get_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED))
57+
return false;
58+
xa_for_each(&pin->parent_refs, i, par_ref)
59+
if (xa_get_mark(&dpll_pin_xa, par_ref->pin->id,
60+
DPLL_REGISTERED))
61+
return true;
62+
xa_for_each(&pin->dpll_refs, i, par_ref)
63+
if (xa_get_mark(&dpll_device_xa, par_ref->dpll->id,
64+
DPLL_REGISTERED))
65+
return true;
66+
return false;
67+
}
68+
5169
/**
5270
* dpll_msg_add_pin_handle - attach pin handle attribute to a given message
5371
* @msg: pointer to sk_buff message to attach a pin handle
@@ -428,6 +446,47 @@ dpll_msg_add_pin_esync(struct sk_buff *msg, struct dpll_pin *pin,
428446
return -EMSGSIZE;
429447
}
430448

449+
static int
450+
dpll_msg_add_pin_ref_sync(struct sk_buff *msg, struct dpll_pin *pin,
451+
struct dpll_pin_ref *ref,
452+
struct netlink_ext_ack *extack)
453+
{
454+
const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
455+
struct dpll_device *dpll = ref->dpll;
456+
void *pin_priv, *ref_sync_pin_priv;
457+
struct dpll_pin *ref_sync_pin;
458+
enum dpll_pin_state state;
459+
struct nlattr *nest;
460+
unsigned long index;
461+
int ret;
462+
463+
pin_priv = dpll_pin_on_dpll_priv(dpll, pin);
464+
xa_for_each(&pin->ref_sync_pins, index, ref_sync_pin) {
465+
if (!dpll_pin_available(ref_sync_pin))
466+
continue;
467+
ref_sync_pin_priv = dpll_pin_on_dpll_priv(dpll, ref_sync_pin);
468+
if (WARN_ON(!ops->ref_sync_get))
469+
return -EOPNOTSUPP;
470+
ret = ops->ref_sync_get(pin, pin_priv, ref_sync_pin,
471+
ref_sync_pin_priv, &state, extack);
472+
if (ret)
473+
return ret;
474+
nest = nla_nest_start(msg, DPLL_A_PIN_REFERENCE_SYNC);
475+
if (!nest)
476+
return -EMSGSIZE;
477+
if (nla_put_s32(msg, DPLL_A_PIN_ID, ref_sync_pin->id))
478+
goto nest_cancel;
479+
if (nla_put_s32(msg, DPLL_A_PIN_STATE, state))
480+
goto nest_cancel;
481+
nla_nest_end(msg, nest);
482+
}
483+
return 0;
484+
485+
nest_cancel:
486+
nla_nest_cancel(msg, nest);
487+
return -EMSGSIZE;
488+
}
489+
431490
static bool dpll_pin_is_freq_supported(struct dpll_pin *pin, u32 freq)
432491
{
433492
int fs;
@@ -570,6 +629,10 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
570629
if (ret)
571630
return ret;
572631
ret = dpll_msg_add_pin_esync(msg, pin, ref, extack);
632+
if (ret)
633+
return ret;
634+
if (!xa_empty(&pin->ref_sync_pins))
635+
ret = dpll_msg_add_pin_ref_sync(msg, pin, ref, extack);
573636
if (ret)
574637
return ret;
575638
if (xa_empty(&pin->parent_refs))
@@ -665,24 +728,6 @@ __dpll_device_change_ntf(struct dpll_device *dpll)
665728
return dpll_device_event_send(DPLL_CMD_DEVICE_CHANGE_NTF, dpll);
666729
}
667730

668-
static bool dpll_pin_available(struct dpll_pin *pin)
669-
{
670-
struct dpll_pin_ref *par_ref;
671-
unsigned long i;
672-
673-
if (!xa_get_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED))
674-
return false;
675-
xa_for_each(&pin->parent_refs, i, par_ref)
676-
if (xa_get_mark(&dpll_pin_xa, par_ref->pin->id,
677-
DPLL_REGISTERED))
678-
return true;
679-
xa_for_each(&pin->dpll_refs, i, par_ref)
680-
if (xa_get_mark(&dpll_device_xa, par_ref->dpll->id,
681-
DPLL_REGISTERED))
682-
return true;
683-
return false;
684-
}
685-
686731
/**
687732
* dpll_device_change_ntf - notify that the dpll device has been changed
688733
* @dpll: registered dpll pointer
@@ -745,7 +790,7 @@ int dpll_pin_delete_ntf(struct dpll_pin *pin)
745790
return dpll_pin_event_send(DPLL_CMD_PIN_DELETE_NTF, pin);
746791
}
747792

748-
static int __dpll_pin_change_ntf(struct dpll_pin *pin)
793+
int __dpll_pin_change_ntf(struct dpll_pin *pin)
749794
{
750795
return dpll_pin_event_send(DPLL_CMD_PIN_CHANGE_NTF, pin);
751796
}
@@ -935,6 +980,108 @@ dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
935980
return ret;
936981
}
937982

983+
static int
984+
dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
985+
unsigned long ref_sync_pin_idx,
986+
const enum dpll_pin_state state,
987+
struct netlink_ext_ack *extack)
988+
989+
{
990+
struct dpll_pin_ref *ref, *failed;
991+
const struct dpll_pin_ops *ops;
992+
enum dpll_pin_state old_state;
993+
struct dpll_pin *ref_sync_pin;
994+
struct dpll_device *dpll;
995+
unsigned long i;
996+
int ret;
997+
998+
ref_sync_pin = xa_find(&pin->ref_sync_pins, &ref_sync_pin_idx,
999+
ULONG_MAX, XA_PRESENT);
1000+
if (!ref_sync_pin) {
1001+
NL_SET_ERR_MSG(extack, "reference sync pin not found");
1002+
return -EINVAL;
1003+
}
1004+
if (!dpll_pin_available(ref_sync_pin)) {
1005+
NL_SET_ERR_MSG(extack, "reference sync pin not available");
1006+
return -EINVAL;
1007+
}
1008+
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
1009+
ASSERT_NOT_NULL(ref);
1010+
ops = dpll_pin_ops(ref);
1011+
if (!ops->ref_sync_set || !ops->ref_sync_get) {
1012+
NL_SET_ERR_MSG(extack, "reference sync not supported by this pin");
1013+
return -EOPNOTSUPP;
1014+
}
1015+
dpll = ref->dpll;
1016+
ret = ops->ref_sync_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
1017+
ref_sync_pin,
1018+
dpll_pin_on_dpll_priv(dpll, ref_sync_pin),
1019+
&old_state, extack);
1020+
if (ret) {
1021+
NL_SET_ERR_MSG(extack, "unable to get old reference sync state");
1022+
return ret;
1023+
}
1024+
if (state == old_state)
1025+
return 0;
1026+
xa_for_each(&pin->dpll_refs, i, ref) {
1027+
ops = dpll_pin_ops(ref);
1028+
dpll = ref->dpll;
1029+
ret = ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
1030+
ref_sync_pin,
1031+
dpll_pin_on_dpll_priv(dpll,
1032+
ref_sync_pin),
1033+
state, extack);
1034+
if (ret) {
1035+
failed = ref;
1036+
NL_SET_ERR_MSG_FMT(extack, "reference sync set failed for dpll_id:%u",
1037+
dpll->id);
1038+
goto rollback;
1039+
}
1040+
}
1041+
__dpll_pin_change_ntf(pin);
1042+
1043+
return 0;
1044+
1045+
rollback:
1046+
xa_for_each(&pin->dpll_refs, i, ref) {
1047+
if (ref == failed)
1048+
break;
1049+
ops = dpll_pin_ops(ref);
1050+
dpll = ref->dpll;
1051+
if (ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
1052+
ref_sync_pin,
1053+
dpll_pin_on_dpll_priv(dpll, ref_sync_pin),
1054+
old_state, extack))
1055+
NL_SET_ERR_MSG(extack, "set reference sync rollback failed");
1056+
}
1057+
return ret;
1058+
}
1059+
1060+
static int
1061+
dpll_pin_ref_sync_set(struct dpll_pin *pin, struct nlattr *nest,
1062+
struct netlink_ext_ack *extack)
1063+
{
1064+
struct nlattr *tb[DPLL_A_PIN_MAX + 1];
1065+
enum dpll_pin_state state;
1066+
u32 sync_pin_id;
1067+
1068+
nla_parse_nested(tb, DPLL_A_PIN_MAX, nest,
1069+
dpll_reference_sync_nl_policy, extack);
1070+
if (!tb[DPLL_A_PIN_ID]) {
1071+
NL_SET_ERR_MSG(extack, "sync pin id expected");
1072+
return -EINVAL;
1073+
}
1074+
sync_pin_id = nla_get_u32(tb[DPLL_A_PIN_ID]);
1075+
1076+
if (!tb[DPLL_A_PIN_STATE]) {
1077+
NL_SET_ERR_MSG(extack, "sync pin state expected");
1078+
return -EINVAL;
1079+
}
1080+
state = nla_get_u32(tb[DPLL_A_PIN_STATE]);
1081+
1082+
return dpll_pin_ref_sync_state_set(pin, sync_pin_id, state, extack);
1083+
}
1084+
9381085
static int
9391086
dpll_pin_on_pin_state_set(struct dpll_pin *pin, u32 parent_idx,
9401087
enum dpll_pin_state state,
@@ -1241,6 +1388,11 @@ dpll_pin_set_from_nlattr(struct dpll_pin *pin, struct genl_info *info)
12411388
if (ret)
12421389
return ret;
12431390
break;
1391+
case DPLL_A_PIN_REFERENCE_SYNC:
1392+
ret = dpll_pin_ref_sync_set(pin, a, info->extack);
1393+
if (ret)
1394+
return ret;
1395+
break;
12441396
}
12451397
}
12461398

drivers/dpll/dpll_netlink.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ int dpll_device_delete_ntf(struct dpll_device *dpll);
1111
int dpll_pin_create_ntf(struct dpll_pin *pin);
1212

1313
int dpll_pin_delete_ntf(struct dpll_pin *pin);
14+
15+
int __dpll_pin_change_ntf(struct dpll_pin *pin);

include/linux/dpll.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,16 @@ struct dpll_pin_ops {
116116
const struct dpll_device *dpll, void *dpll_priv,
117117
struct dpll_pin_esync *esync,
118118
struct netlink_ext_ack *extack);
119+
int (*ref_sync_set)(const struct dpll_pin *pin, void *pin_priv,
120+
const struct dpll_pin *ref_sync_pin,
121+
void *ref_sync_pin_priv,
122+
const enum dpll_pin_state state,
123+
struct netlink_ext_ack *extack);
124+
int (*ref_sync_get)(const struct dpll_pin *pin, void *pin_priv,
125+
const struct dpll_pin *ref_sync_pin,
126+
void *ref_sync_pin_priv,
127+
enum dpll_pin_state *state,
128+
struct netlink_ext_ack *extack);
119129

120130
RH_KABI_RESERVE(1)
121131
RH_KABI_RESERVE(2)
@@ -232,6 +242,9 @@ int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin,
232242
void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin,
233243
const struct dpll_pin_ops *ops, void *priv);
234244

245+
int dpll_pin_ref_sync_pair_add(struct dpll_pin *pin,
246+
struct dpll_pin *ref_sync_pin);
247+
235248
int dpll_device_change_ntf(struct dpll_device *dpll);
236249

237250
int dpll_pin_change_ntf(struct dpll_pin *pin);

0 commit comments

Comments
 (0)