]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
dpll: allow registering FW-identified pin with a different DPLL
authorGrzegorz Nitka <grzegorz.nitka@intel.com>
Sun, 7 Jun 2026 18:30:34 +0000 (20:30 +0200)
committerJakub Kicinski <kuba@kernel.org>
Sat, 13 Jun 2026 20:24:32 +0000 (13:24 -0700)
Relax the (module, clock_id) equality requirement when registering a
pin identified by firmware (pin->fwnode). Some platforms associate a
FW-described pin with a DPLL instance that differs from the pin's
(module, clock_id) tuple. For such pins, permit registration without
requiring the strict match. Non-FW pins still require equality.

Keep netlink pin module reporting/filtering safe for this relaxed
registration model by caching the module name in the pin object at
allocation time and using the cached string in netlink paths.
This avoids dereferencing pin->module after provider module teardown.

Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Grzegorz Nitka <grzegorz.nitka@intel.com>
Link: https://patch.msgid.link/20260607183045.1213735-3-grzegorz.nitka@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/dpll/dpll_core.c
drivers/dpll/dpll_core.h
drivers/dpll/dpll_netlink.c

index 20a54728549cc78de2fdd830da5086a899951a42..6dc7e93ece7501bbe3398bb52e43086f241293a9 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/idr.h>
+#include <linux/module.h>
 #include <linux/property.h>
 #include <linux/slab.h>
 #include <linux/string.h>
@@ -652,6 +653,7 @@ dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module,
        pin->pin_idx = pin_idx;
        pin->clock_id = clock_id;
        pin->module = module;
+       strscpy(pin->module_name, module_name(module));
        if (WARN_ON(prop->type < DPLL_PIN_TYPE_MUX ||
                    prop->type > DPLL_PIN_TYPE_MAX)) {
                ret = -EINVAL;
@@ -884,11 +886,21 @@ dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
                return -EINVAL;
 
        mutex_lock(&dpll_lock);
-       if (WARN_ON(!(dpll->module == pin->module &&
-                     dpll->clock_id == pin->clock_id)))
+
+       /*
+        * For pins identified via firmware (pin->fwnode), allow registration
+        * even if the pin's (module, clock_id) differs from the target DPLL.
+        * For non-fwnode pins, require a strict (module, clock_id) match.
+        */
+       if (!pin->fwnode &&
+           WARN_ON_ONCE(dpll->module != pin->module ||
+                        dpll->clock_id != pin->clock_id)) {
                ret = -EINVAL;
-       else
-               ret = __dpll_pin_register(dpll, pin, ops, priv, NULL);
+               goto out_unlock;
+       }
+
+       ret = __dpll_pin_register(dpll, pin, ops, priv, NULL);
+out_unlock:
        mutex_unlock(&dpll_lock);
 
        return ret;
index 71ac88ef20172a1bd68dec6ea61cc1c611a5e795..26d1537ada8292a23280953320ec5a24f3f39eec 100644 (file)
@@ -45,6 +45,7 @@ struct dpll_device {
  * @pin_idx:           index of a pin given by dev driver
  * @clock_id:          clock_id of creator
  * @module:            module of creator
+ * @module_name:       module name of creator
  * @fwnode:            optional reference to firmware node
  * @dpll_refs:         hold referencees to dplls pin was registered with
  * @parent_refs:       hold references to parent pins pin was registered with
@@ -59,6 +60,7 @@ struct dpll_pin {
        u32 pin_idx;
        u64 clock_id;
        struct module *module;
+       char module_name[MODULE_NAME_LEN];
        struct fwnode_handle *fwnode;
        struct xarray dpll_refs;
        struct xarray parent_refs;
index d62350b181072a5a5e755f939dc3c48ba44a0b21..6a23298244ccc5e86a5570c98efe9251a01937ec 100644 (file)
@@ -703,7 +703,7 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
        if (ret)
                return ret;
        if (nla_put_string(msg, DPLL_A_PIN_MODULE_NAME,
-                          module_name(pin->module)))
+                          pin->module_name))
                return -EMSGSIZE;
        if (nla_put_64bit(msg, DPLL_A_PIN_CLOCK_ID, sizeof(pin->clock_id),
                          &pin->clock_id, DPLL_A_PIN_PAD))
@@ -1650,9 +1650,9 @@ dpll_pin_find(u64 clock_id, struct nlattr *mod_name_attr,
        xa_for_each_marked(&dpll_pin_xa, i, pin, DPLL_REGISTERED) {
                prop = &pin->prop;
                cid_match = clock_id ? pin->clock_id == clock_id : true;
-               mod_match = mod_name_attr && module_name(pin->module) ?
+               mod_match = mod_name_attr && pin->module_name[0] ?
                        !nla_strcmp(mod_name_attr,
-                                   module_name(pin->module)) : true;
+                                   pin->module_name) : true;
                type_match = type ? prop->type == type : true;
                board_match = board_label ? (prop->board_label ?
                        !nla_strcmp(board_label, prop->board_label) : false) :