]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
dpll: Add notifier chain for dpll events
authorPetr Oros <poros@redhat.com>
Tue, 3 Feb 2026 17:39:56 +0000 (18:39 +0100)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 5 Feb 2026 14:57:46 +0000 (15:57 +0100)
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 <vadim.fedorenko@linux.dev>
Co-developed-by: Ivan Vecera <ivecera@redhat.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
Signed-off-by: Petr Oros <poros@redhat.com>
Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Link: https://patch.msgid.link/20260203174002.705176-4-ivecera@redhat.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/dpll/dpll_core.c
drivers/dpll/dpll_core.h
drivers/dpll/dpll_netlink.c
include/linux/dpll.h

index f04ed7195cadd6c011805aa47f99a9ea58099419..b05fe2ba46d910af87e171b697dba8da2a6c4113 100644 (file)
@@ -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
index d3e17ff0ecef0492fd9128364babe1a29dc16d75..b7b4bb251f739a9374f8c4e321934a2fca9a628d 100644 (file)
@@ -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
index 904199ddd17815585d064c2faa3cccfc1a8f69e3..83cbd64abf5a47357412a630bb2aae727d3539d1 100644 (file)
@@ -761,17 +761,20 @@ err_free_msg:
 
 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 @@ err_free_msg:
 
 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);
 }
 
index f2e8660e90cdfd6ecc569d402017f0d72ef2ffda..8ed90dfc65f058c9d6c41b5410478ddb7ca4b052 100644 (file)
@@ -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