>From: Ivan Vecera <[email protected]> >Sent: Tuesday, February 3, 2026 6:40 PM > >From: Petr Oros <[email protected]> > >Currently, the DPLL subsystem reports events (creation, deletion, changes) >to userspace via Netlink. However, there is no mechanism for other kernel >components to be notified of these events directly. > >Add a raw notifier chain to the DPLL core protected by dpll_lock. This >allows other kernel subsystems or drivers to register callbacks and >receive notifications when DPLL devices or pins are created, deleted, >or modified. > >Define the following: >- Registration helpers: {,un}register_dpll_notifier() >- Event types: DPLL_DEVICE_CREATED, DPLL_PIN_CREATED, etc. >- Context structures: dpll_{device,pin}_notifier_info to pass relevant > data to the listeners. > >The notification chain is invoked alongside the existing Netlink event >generation to ensure in-kernel listeners are kept in sync with the >subsystem state. > >Reviewed-by: Vadim Fedorenko <[email protected]>
LGTM, Reviewed-by: Arkadiusz Kubalewski <[email protected]> >Co-developed-by: Ivan Vecera <[email protected]> >Signed-off-by: Ivan Vecera <[email protected]> >Signed-off-by: Petr Oros <[email protected]> >--- > drivers/dpll/dpll_core.c | 57 +++++++++++++++++++++++++++++++++++++ > drivers/dpll/dpll_core.h | 4 +++ > drivers/dpll/dpll_netlink.c | 6 ++++ > include/linux/dpll.h | 29 +++++++++++++++++++ > 4 files changed, 96 insertions(+) > >diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c >index f04ed7195cadd..b05fe2ba46d91 100644 >--- a/drivers/dpll/dpll_core.c >+++ b/drivers/dpll/dpll_core.c >@@ -23,6 +23,8 @@ DEFINE_MUTEX(dpll_lock); > DEFINE_XARRAY_FLAGS(dpll_device_xa, XA_FLAGS_ALLOC); > DEFINE_XARRAY_FLAGS(dpll_pin_xa, XA_FLAGS_ALLOC); > >+static RAW_NOTIFIER_HEAD(dpll_notifier_chain); >+ > static u32 dpll_device_xa_id; > static u32 dpll_pin_xa_id; > >@@ -46,6 +48,39 @@ struct dpll_pin_registration { > void *cookie; > }; > >+static int call_dpll_notifiers(unsigned long action, void *info) >+{ >+ lockdep_assert_held(&dpll_lock); >+ return raw_notifier_call_chain(&dpll_notifier_chain, action, info); >+} >+ >+void dpll_device_notify(struct dpll_device *dpll, unsigned long action) >+{ >+ struct dpll_device_notifier_info info = { >+ .dpll = dpll, >+ .id = dpll->id, >+ .idx = dpll->device_idx, >+ .clock_id = dpll->clock_id, >+ .type = dpll->type, >+ }; >+ >+ call_dpll_notifiers(action, &info); >+} >+ >+void dpll_pin_notify(struct dpll_pin *pin, unsigned long action) >+{ >+ struct dpll_pin_notifier_info info = { >+ .pin = pin, >+ .id = pin->id, >+ .idx = pin->pin_idx, >+ .clock_id = pin->clock_id, >+ .fwnode = pin->fwnode, >+ .prop = &pin->prop, >+ }; >+ >+ call_dpll_notifiers(action, &info); >+} >+ > struct dpll_device *dpll_device_get_by_id(int id) > { > if (xa_get_mark(&dpll_device_xa, id, DPLL_REGISTERED)) >@@ -539,6 +574,28 @@ void dpll_netdev_pin_clear(struct net_device *dev) > } > EXPORT_SYMBOL(dpll_netdev_pin_clear); > >+int register_dpll_notifier(struct notifier_block *nb) >+{ >+ int ret; >+ >+ mutex_lock(&dpll_lock); >+ ret = raw_notifier_chain_register(&dpll_notifier_chain, nb); >+ mutex_unlock(&dpll_lock); >+ return ret; >+} >+EXPORT_SYMBOL_GPL(register_dpll_notifier); >+ >+int unregister_dpll_notifier(struct notifier_block *nb) >+{ >+ int ret; >+ >+ mutex_lock(&dpll_lock); >+ ret = raw_notifier_chain_unregister(&dpll_notifier_chain, nb); >+ mutex_unlock(&dpll_lock); >+ return ret; >+} >+EXPORT_SYMBOL_GPL(unregister_dpll_notifier); >+ > /** > * dpll_pin_get - find existing or create new dpll pin > * @clock_id: clock_id of creator >diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h >index d3e17ff0ecef0..b7b4bb251f739 100644 >--- a/drivers/dpll/dpll_core.h >+++ b/drivers/dpll/dpll_core.h >@@ -91,4 +91,8 @@ struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct >xarray *xa_refs); > extern struct xarray dpll_device_xa; > extern struct xarray dpll_pin_xa; > extern struct mutex dpll_lock; >+ >+void dpll_device_notify(struct dpll_device *dpll, unsigned long action); >+void dpll_pin_notify(struct dpll_pin *pin, unsigned long action); >+ > #endif >diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c >index 904199ddd1781..83cbd64abf5a4 100644 >--- a/drivers/dpll/dpll_netlink.c >+++ b/drivers/dpll/dpll_netlink.c >@@ -761,17 +761,20 @@ dpll_device_event_send(enum dpll_cmd event, struct >dpll_device *dpll) > > int dpll_device_create_ntf(struct dpll_device *dpll) > { >+ dpll_device_notify(dpll, DPLL_DEVICE_CREATED); > return dpll_device_event_send(DPLL_CMD_DEVICE_CREATE_NTF, dpll); > } > > int dpll_device_delete_ntf(struct dpll_device *dpll) > { >+ dpll_device_notify(dpll, DPLL_DEVICE_DELETED); > return dpll_device_event_send(DPLL_CMD_DEVICE_DELETE_NTF, dpll); > } > > static int > __dpll_device_change_ntf(struct dpll_device *dpll) > { >+ dpll_device_notify(dpll, DPLL_DEVICE_CHANGED); > return dpll_device_event_send(DPLL_CMD_DEVICE_CHANGE_NTF, dpll); > } > >@@ -829,16 +832,19 @@ dpll_pin_event_send(enum dpll_cmd event, struct >dpll_pin *pin) > > int dpll_pin_create_ntf(struct dpll_pin *pin) > { >+ dpll_pin_notify(pin, DPLL_PIN_CREATED); > return dpll_pin_event_send(DPLL_CMD_PIN_CREATE_NTF, pin); > } > > int dpll_pin_delete_ntf(struct dpll_pin *pin) > { >+ dpll_pin_notify(pin, DPLL_PIN_DELETED); > return dpll_pin_event_send(DPLL_CMD_PIN_DELETE_NTF, pin); > } > > int __dpll_pin_change_ntf(struct dpll_pin *pin) > { >+ dpll_pin_notify(pin, DPLL_PIN_CHANGED); > return dpll_pin_event_send(DPLL_CMD_PIN_CHANGE_NTF, pin); > } > >diff --git a/include/linux/dpll.h b/include/linux/dpll.h >index f2e8660e90cdf..8ed90dfc65f05 100644 >--- a/include/linux/dpll.h >+++ b/include/linux/dpll.h >@@ -11,6 +11,7 @@ > #include <linux/device.h> > #include <linux/netlink.h> > #include <linux/netdevice.h> >+#include <linux/notifier.h> > #include <linux/rtnetlink.h> > > struct dpll_device; >@@ -172,6 +173,30 @@ struct dpll_pin_properties { > u32 phase_gran; > }; > >+#define DPLL_DEVICE_CREATED 1 >+#define DPLL_DEVICE_DELETED 2 >+#define DPLL_DEVICE_CHANGED 3 >+#define DPLL_PIN_CREATED 4 >+#define DPLL_PIN_DELETED 5 >+#define DPLL_PIN_CHANGED 6 >+ >+struct dpll_device_notifier_info { >+ struct dpll_device *dpll; >+ u32 id; >+ u32 idx; >+ u64 clock_id; >+ enum dpll_type type; >+}; >+ >+struct dpll_pin_notifier_info { >+ struct dpll_pin *pin; >+ u32 id; >+ u32 idx; >+ u64 clock_id; >+ const struct fwnode_handle *fwnode; >+ const struct dpll_pin_properties *prop; >+}; >+ > #if IS_ENABLED(CONFIG_DPLL) > void dpll_netdev_pin_set(struct net_device *dev, struct dpll_pin >*dpll_pin); > void dpll_netdev_pin_clear(struct net_device *dev); >@@ -242,4 +267,8 @@ int dpll_device_change_ntf(struct dpll_device *dpll); > > int dpll_pin_change_ntf(struct dpll_pin *pin); > >+int register_dpll_notifier(struct notifier_block *nb); >+ >+int unregister_dpll_notifier(struct notifier_block *nb); >+ > #endif >-- >2.52.0
