[PATCH v2 0/3] driver core: remove software node from platform devices on device release

0 views
Skip to first unread message

Bartosz Golaszewski

unread,
Apr 23, 2026, 8:12:22 AM (8 days ago) Apr 23
to Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, br...@kernel.org, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, Bartosz Golaszewski
This fixes an issue in platform device code where, if we specify a
software node for a platform device using struct platform_device_info,
it will not be removed on device .release().

The second patch adds a new kunit helper which is used in patch 3/3 that
adds a test-case that can be used to reproduce the problem and prove that
the fix works as well as another making sure a corner case of using a
software node as the primary firmware node works too.

First patch should go into v7.1 while patches 2/3 and 3/3 can be queued
for v7.2.

Signed-off-by: Bartosz Golaszewski <bartosz.g...@oss.qualcomm.com>
---
Changes in v2:
- Change the order between removing the software node and dropping the
reference to the device's OF node
- Address a situation where a software node is used as the primary
firmware node
- Add a patch adding a new kunit helper
- Add another test case
- Link to v1: https://patch.msgid.link/20260410-swnode-remove-on-...@oss.qualcomm.com

---
Bartosz Golaszewski (3):
driver core: platform: remove software node on release()
kunit: provide kunit_software_node_register()
driver core: platform: tests: add test cases for correct swnode removal

drivers/base/platform.c | 11 ++++
drivers/base/test/platform-device-test.c | 106 +++++++++++++++++++++++++++++++
include/kunit/fwnode.h | 19 ++++++
lib/kunit/Makefile | 3 +-
lib/kunit/fwnode.c | 52 +++++++++++++++
5 files changed, 190 insertions(+), 1 deletion(-)
---
base-commit: 70c8a7ec6715b5fb14e501731b5b9210a16684f7
change-id: 20260410-swnode-remove-on-dev-unreg-42bfc4b23ba8

Best regards,
--
Bartosz Golaszewski <bartosz.g...@oss.qualcomm.com>

Bartosz Golaszewski

unread,
Apr 23, 2026, 8:12:23 AM (8 days ago) Apr 23
to Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, br...@kernel.org, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, Bartosz Golaszewski
If we pass a software node to a newly created device using struct
platform_device_info, it will not be removed when the device is
released. This may happen when a module creating the device is removed
or on failure in platform_device_add().

When we try to reuse that software node in a subsequent call to
platform_device_register_full(), it will fails with -EBUSY. Add the
missing call to device_remove_software_node() in release path.

Make sure that we still function correctly if a software node is used as
the primary firmware node.

Fixes: 0fc434bc2c45 ("driver core: platform: allow attaching software nodes when creating devices")
Signed-off-by: Bartosz Golaszewski <bartosz.g...@oss.qualcomm.com>
---
drivers/base/platform.c | 11 +++++++++++
1 file changed, 11 insertions(+)

diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 75b4698d0e582e67adafa78c312d75c72fd654cf..43ea7dcd338dd3ddae57e6d0677e5cb2673f6ed5 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -599,6 +599,7 @@ static void platform_device_release(struct device *dev)
struct platform_object *pa = container_of(dev, struct platform_object,
pdev.dev);

+ device_remove_software_node(dev);
of_node_put(pa->pdev.dev.of_node);
kfree(pa->pdev.dev.platform_data);
kfree(pa->pdev.mfd_cell);
@@ -885,6 +886,16 @@ struct platform_device *platform_device_register_full(const struct platform_devi
goto err;
}

+ /*
+ * If the primary firmware node is a software node and there's no
+ * secondary firmware node, the primary will be affected by the call
+ * to device_remove_software_node() in platform_device_release() and
+ * its reference count will be dropped by one. Take another reference
+ * here to make it have no effect.
+ */
+ if (is_software_node(pdevinfo->fwnode) && !pdevinfo->swnode)
+ fwnode_handle_get(pdevinfo->fwnode);
+
ret = platform_device_add(pdev);
if (ret) {
err:

--
2.47.3

Bartosz Golaszewski

unread,
Apr 23, 2026, 8:12:27 AM (8 days ago) Apr 23
to Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, br...@kernel.org, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, Bartosz Golaszewski
Extend the kunit module for platform devices with test cases verifying
that the same software node can be added to platform devices repeatedly.

Signed-off-by: Bartosz Golaszewski <bartosz.g...@oss.qualcomm.com>
---
drivers/base/test/platform-device-test.c | 106 +++++++++++++++++++++++++++++++
1 file changed, 106 insertions(+)

diff --git a/drivers/base/test/platform-device-test.c b/drivers/base/test/platform-device-test.c
index 6355a2231b741791b54eb78af42e13f31f745184..4b23f0d7f88548c62c49801fcee0919915e6e153 100644
--- a/drivers/base/test/platform-device-test.c
+++ b/drivers/base/test/platform-device-test.c
@@ -1,12 +1,15 @@
// SPDX-License-Identifier: GPL-2.0

+#include <kunit/fwnode.h>
#include <kunit/platform_device.h>
#include <kunit/resource.h>

#include <linux/device.h>
#include <linux/device/bus.h>
+#include <linux/fwnode.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/property.h>

#define DEVICE_NAME "test"

@@ -253,9 +256,112 @@ static struct kunit_suite platform_device_match_test_suite = {
.test_cases = platform_device_match_tests,
};

+static int platform_device_swnode_test_probe(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver platform_swnode_test_driver = {
+ .probe = platform_device_swnode_test_probe,
+ .driver = {
+ .name = DEVICE_NAME,
+ },
+};
+
+static const struct software_node platform_device_test_swnode = { };
+
+/*
+ * Check that reusing a software node works correctly. If the call to
+ * platform_device_register_full() fails after adding the secondary firmware
+ * node, the software node must be unregistered in the device's release()
+ * callback or the subsequent call to platform_device_register_full() will fail
+ * with -EBUSY due to the software node aleady having been registered.
+ */
+static void platform_device_swnode_add_twice(struct kunit *test)
+{
+ struct platform_device_info pdevinfo;
+ struct platform_device *pdev;
+ struct fwnode_handle fwnode;
+ int ret;
+
+ ret = kunit_platform_driver_register(test, &platform_swnode_test_driver);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ fwnode_init(&fwnode, NULL);
+ pdevinfo = (struct platform_device_info){
+ .name = DEVICE_NAME,
+ .id = PLATFORM_DEVID_NONE,
+ .fwnode = &fwnode,
+ .swnode = &platform_device_test_swnode,
+ };
+
+ pdev = platform_device_register_full(&pdevinfo);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
+
+ wait_for_device_probe();
+ KUNIT_ASSERT_TRUE(test, device_is_bound(&pdev->dev));
+
+ platform_device_unregister(pdev);
+
+ pdev = platform_device_register_full(&pdevinfo);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
+
+ wait_for_device_probe();
+ KUNIT_ASSERT_TRUE(test, device_is_bound(&pdev->dev));
+
+ platform_device_unregister(pdev);
+}
+
+/*
+ * Check that passing a software node as the primary firmware node of the
+ * platform device does not result in it being unregistered by the call to
+ * device_remove_software_node() in its release path.
+ */
+static void platform_device_swnode_as_primary(struct kunit *test)
+{
+ struct platform_device_info pdevinfo;
+ struct platform_device *pdev;
+ struct fwnode_handle *fwnode;
+ int ret;
+
+ ret = kunit_platform_driver_register(test, &platform_swnode_test_driver);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ fwnode = kunit_software_node_register(test, &platform_device_test_swnode);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fwnode);
+
+ pdevinfo = (struct platform_device_info){
+ .name = DEVICE_NAME,
+ .id = PLATFORM_DEVID_NONE,
+ .fwnode = fwnode,
+ };
+
+ pdev = platform_device_register_full(&pdevinfo);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
+
+ wait_for_device_probe();
+ KUNIT_ASSERT_TRUE(test, device_is_bound(&pdev->dev));
+
+ platform_device_unregister(pdev);
+
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, software_node_fwnode(&platform_device_test_swnode));
+}
+
+static struct kunit_case platform_device_swnode_tests[] = {
+ KUNIT_CASE(platform_device_swnode_add_twice),
+ KUNIT_CASE(platform_device_swnode_as_primary),
+ {}
+};
+
+static struct kunit_suite platform_device_swnode_test_suite = {
+ .name = "platform-device-swnode",
+ .test_cases = platform_device_swnode_tests,
+};
+
kunit_test_suites(
&platform_device_devm_test_suite,
&platform_device_match_test_suite,
+ &platform_device_swnode_test_suite,
);

MODULE_DESCRIPTION("Test module for platform devices");

--
2.47.3

Bartosz Golaszewski

unread,
Apr 23, 2026, 8:12:27 AM (8 days ago) Apr 23
to Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, br...@kernel.org, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, Bartosz Golaszewski
Implement a helper for registering kunit test-managed software nodes.

Signed-off-by: Bartosz Golaszewski <bartosz.g...@oss.qualcomm.com>
---
include/kunit/fwnode.h | 19 ++++++++++++++++++
lib/kunit/Makefile | 3 ++-
lib/kunit/fwnode.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 73 insertions(+), 1 deletion(-)

diff --git a/include/kunit/fwnode.h b/include/kunit/fwnode.h
new file mode 100644
index 0000000000000000000000000000000000000000..e1554ace64b8a5899aff9f4b4247e5157826a49b
--- /dev/null
+++ b/include/kunit/fwnode.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * KUnit resource management helpers firmware nodes.
+ *
+ * Copyright (C) Qualcomm Technologies, Inc. and/or its subsidiaries
+ */
+
+#ifndef _KUNIT_FWNODE_H
+#define _KUNIT_FWNODE_H
+
+struct kunit;
+struct fwnode_handle;
+struct software_node;
+
+struct fwnode_handle *
+kunit_software_node_register(struct kunit *test,
+ const struct software_node *node);
+
+#endif /* _KUNIT_FWNODE_H */
diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index 656f1fa35abcc635e67d5b4cb1bc586b48415ac5..7549a701791b5b7eaa8e0637b6818cdfd0b655a8 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -10,7 +10,8 @@ kunit-objs += test.o \
executor.o \
attributes.o \
device.o \
- platform.o
+ platform.o \
+ fwnode.o

ifeq ($(CONFIG_KUNIT_DEBUGFS),y)
kunit-objs += debugfs.o
diff --git a/lib/kunit/fwnode.c b/lib/kunit/fwnode.c
new file mode 100644
index 0000000000000000000000000000000000000000..bc8bf06762dd71a741a3419c1ca04028d6ad3ec8
--- /dev/null
+++ b/lib/kunit/fwnode.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Qualcomm Technologies, Inc. and/or its subsidiaries
+ */
+
+#include <kunit/fwnode.h>
+#include <kunit/test.h>
+
+#include <linux/fwnode.h>
+#include <linux/property.h>
+
+static void kunit_software_node_unregister(void *data)
+{
+ const struct software_node *swnode = data;
+
+ software_node_unregister(swnode);
+}
+
+/**
+ * kunit_software_node_register() - Register a KUnit-managed software node
+ * @test: test context
+ * @swnode: Software node to register
+ *
+ * Register a test-managed software node and return its firmware node handle.
+ * The software node is unregistered after the test case completes.
+ *
+ * Return: Firmware node handle of the registered software node or IS_ERR()
+ * on failure.
+ */
+struct fwnode_handle *
+kunit_software_node_register(struct kunit *test,
+ const struct software_node *swnode)
+{
+ struct fwnode_handle *fwnode;
+ int ret;
+
+ ret = software_node_register(swnode);
+ if (ret)
+ return ERR_PTR(ret);
+
+ fwnode = software_node_fwnode(swnode);
+ if (WARN_ON(!fwnode))
+ return ERR_PTR(-ENOENT);
+
+ ret = kunit_add_action_or_reset(test, kunit_software_node_unregister,
+ (void *)swnode);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return fwnode;
+}
+EXPORT_SYMBOL_GPL(kunit_software_node_register);

--
2.47.3

Dmitry Torokhov

unread,
Apr 23, 2026, 1:32:28 PM (8 days ago) Apr 23
to Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, br...@kernel.org, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com
It is possible to pass already registered node in pdevinfo->swnode
(because device_add_software_node() can handle this just fine). In this
case we also need to take an extra reference (or figure out whether we
need to drop the reference when removing the device).

Thanks.

--
Dmitry

Andy Shevchenko

unread,
Apr 24, 2026, 5:01:28 AM (8 days ago) Apr 24
to Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, br...@kernel.org, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com
On Thu, Apr 23, 2026 at 02:12:02PM +0200, Bartosz Golaszewski wrote:
> If we pass a software node to a newly created device using struct
> platform_device_info, it will not be removed when the device is
> released. This may happen when a module creating the device is removed
> or on failure in platform_device_add().
>
> When we try to reuse that software node in a subsequent call to
> platform_device_register_full(), it will fails with -EBUSY. Add the
> missing call to device_remove_software_node() in release path.
>
> Make sure that we still function correctly if a software node is used as
> the primary firmware node.

...

> + device_remove_software_node(dev);

> of_node_put(pa->pdev.dev.of_node);

Can we rather replace of_* get/put with the fwnode_* get/put and make a
conditional here?

if (is_software_node(...))
device_remove...
else
fwnode_handle_put().

(or something like this)

And IIRC the above pattern has been already seen somewhere else. But I can't
point to it, just some weak memories of seeing that already.


--
With Best Regards,
Andy Shevchenko


Bartosz Golaszewski

unread,
Apr 24, 2026, 8:26:54 AM (7 days ago) Apr 24
to Dmitry Torokhov, Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com
On Thu, Apr 23, 2026 at 7:32 PM Dmitry Torokhov
<dmitry....@gmail.com> wrote:
>
> >
> > + /*
> > + * If the primary firmware node is a software node and there's no
> > + * secondary firmware node, the primary will be affected by the call
> > + * to device_remove_software_node() in platform_device_release() and
> > + * its reference count will be dropped by one. Take another reference
> > + * here to make it have no effect.
> > + */
> > + if (is_software_node(pdevinfo->fwnode) && !pdevinfo->swnode)
> > + fwnode_handle_get(pdevinfo->fwnode);
>
> It is possible to pass already registered node in pdevinfo->swnode
> (because device_add_software_node() can handle this just fine). In this
> case we also need to take an extra reference (or figure out whether we
> need to drop the reference when removing the device).
>

But device_add_software_node() checks if the software node is
registered and - if so - just bumps the reference so the effect is the
same as when it registers the swnode.

Bart

Bartosz Golaszewski

unread,
Apr 24, 2026, 8:34:44 AM (7 days ago) Apr 24
to Andy Shevchenko, Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com
On Fri, Apr 24, 2026 at 11:01 AM Andy Shevchenko
<andriy.s...@intel.com> wrote:
>
> On Thu, Apr 23, 2026 at 02:12:02PM +0200, Bartosz Golaszewski wrote:
> > If we pass a software node to a newly created device using struct
> > platform_device_info, it will not be removed when the device is
> > released. This may happen when a module creating the device is removed
> > or on failure in platform_device_add().
> >
> > When we try to reuse that software node in a subsequent call to
> > platform_device_register_full(), it will fails with -EBUSY. Add the
> > missing call to device_remove_software_node() in release path.
> >
> > Make sure that we still function correctly if a software node is used as
> > the primary firmware node.
>
> ...
>
> > + device_remove_software_node(dev);
>
> > of_node_put(pa->pdev.dev.of_node);
>
> Can we rather replace of_* get/put with the fwnode_* get/put and make a
> conditional here?
>

I thought about it but I'm not sure why we bump the refcount of OF
nodes but not of the firmware nodes supplied in struct
platform_device_info. Maybe there was a reason for it. That would
simplify things.

> if (is_software_node(...))
> device_remove...
> else
> fwnode_handle_put().
>
> (or something like this)
>
> And IIRC the above pattern has been already seen somewhere else. But I can't
> point to it, just some weak memories of seeing that already.
>

That needs to account for two software nodes, I think it's fine to
call the two in sequence unconditionally (like I do this this patch)
and just dump the refcount on registration as necessary.

Bart

Andy Shevchenko

unread,
Apr 24, 2026, 9:13:53 AM (7 days ago) Apr 24
to Bartosz Golaszewski, Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com
On Fri, Apr 24, 2026 at 02:34:29PM +0200, Bartosz Golaszewski wrote:
> On Fri, Apr 24, 2026 at 11:01 AM Andy Shevchenko
> <andriy.s...@intel.com> wrote:
> > On Thu, Apr 23, 2026 at 02:12:02PM +0200, Bartosz Golaszewski wrote:

...

> > > + device_remove_software_node(dev);
> >
> > > of_node_put(pa->pdev.dev.of_node);
> >
> > Can we rather replace of_* get/put with the fwnode_* get/put and make a
> > conditional here?
>
> I thought about it but I'm not sure why we bump the refcount of OF
> nodes but not of the firmware nodes supplied in struct
> platform_device_info. Maybe there was a reason for it. That would
> simplify things.

I could with 99% assurance state that the reason behind this as simple as
ACPI doesn't need that. It's no-op there and no-one at that time thought
of software nodes. More, I have some (a few years old) patch locally that
does this conversion, but never had time to look into it carefully for
any missed corner cases (as part of that work, the preparation was done
for AMBA devices in the ca5a75df36dd ("amba: bus: balance firmware node
reference counting") which is more than a couple of years in upstream).

> > if (is_software_node(...))
> > device_remove...
> > else
> > fwnode_handle_put().
> >
> > (or something like this)
> >
> > And IIRC the above pattern has been already seen somewhere else. But I can't
> > point to it, just some weak memories of seeing that already.
>
> That needs to account for two software nodes, I think it's fine to
> call the two in sequence unconditionally (like I do this this patch)
> and just dump the refcount on registration as necessary.

Sure.

Dmitry Torokhov

unread,
Apr 26, 2026, 12:24:38 AM (6 days ago) Apr 26
to Bartosz Golaszewski, Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com
Ah, yes, you are right.

Still please check sashiko review - I think some of the concerns about
error unwinding are correct.

Thanks.

--
Dmitry

Bartosz Golaszewski

unread,
Apr 27, 2026, 10:13:51 AM (4 days ago) Apr 27
to Dmitry Torokhov, Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com
On Sun, Apr 26, 2026 at 6:24 AM Dmitry Torokhov
<dmitry....@gmail.com> wrote:
>
> Still please check sashiko review - I think some of the concerns about
> error unwinding are correct.
>

Sigh... I hate the walls of text it generates. Can we set it to
"caveman mode"? :)

The first part of the review - while valid - already has a precedence
with this function. If someone allocates the platform device with
platform_device_alloc() and assigns the address of a static structure
as its platform data, on release() we'll unconditionally call kfree()
on it. The user must not assign platform data directly but use the
dedicated platform_device_add_data() helper. We could consider
providing platform_device_add_software_node() but since there are no
users, let's cross that bridge when we get there?

For the second point: sashiko's right, we need to bump the refcount earlier.

For the third: I need to look into it deeper. I thought my second test
case from patch 3/3 checks that use-case but the review makes sense.

Bart

Bartosz Golaszewski

unread,
Apr 28, 2026, 5:20:43 AM (4 days ago) Apr 28
to Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, br...@kernel.org, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, Bartosz Golaszewski
This fixes an issue in platform device code where, if we specify a
software node for a platform device using struct platform_device_info,
it will not be removed on device .release().

The second patch adds a new kunit helper which is used in patch 3/3 that
adds a test-case that can be used to reproduce the problem and prove that
the fix works as well as another making sure a corner case of using a
software node as the primary firmware node works too.

Merging strategy: patch 1/3 should go into v7.1. Once it's upstream, the
first tag containing it should be pulled into the driver core tree and
the remaining patches applied on top with an ack from the kunit
maintainers.

Signed-off-by: Bartosz Golaszewski <bartosz.g...@oss.qualcomm.com>
---
Changes in v3:
- Make sure the reference of the primary software node we possibly take,
is always released by moving the get() before calls that may fail
- Don't allow passing two software nodes
- Add a test case for that situation
- Link to v2: https://patch.msgid.link/20260423-swnode-remove-on-...@oss.qualcomm.com

Changes in v2:
- Change the order between removing the software node and dropping the
reference to the device's OF node
- Address a situation where a software node is used as the primary
firmware node
- Add a patch adding a new kunit helper
- Add another test case
- Link to v1: https://patch.msgid.link/20260410-swnode-remove-on-...@oss.qualcomm.com

---
Bartosz Golaszewski (3):
driver core: platform: remove software node on release()
kunit: provide kunit_software_node_register()
driver core: platform: tests: add test cases for correct swnode removal

drivers/base/platform.c | 17 +++-
drivers/base/test/platform-device-test.c | 156 +++++++++++++++++++++++++++++++
include/kunit/fwnode.h | 19 ++++
lib/kunit/Makefile | 3 +-
lib/kunit/fwnode.c | 52 +++++++++++
5 files changed, 245 insertions(+), 2 deletions(-)
---
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731

Bartosz Golaszewski

unread,
Apr 28, 2026, 5:20:44 AM (4 days ago) Apr 28
to Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, br...@kernel.org, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, Bartosz Golaszewski
If we pass a software node to a newly created device using struct
platform_device_info, it will not be removed when the device is
released. This may happen when a module creating the device is removed
or on failure in platform_device_add().

When we try to reuse that software node in a subsequent call to
platform_device_register_full(), it will fails with -EBUSY. Add the
missing call to device_remove_software_node() in release path.

In addition to the above change, make sure that we still function
correctly if a software node is used as the primary firmware node as
well as disallow using two software nodes for platform devices as
device_add_software_node() does not handle this case correctly (in fact
a comment inside it states that only one software node per device is
allowed but it will not bail out if two are used so we need to handle it
here).

Fixes: 0fc434bc2c45 ("driver core: platform: allow attaching software nodes when creating devices")
Signed-off-by: Bartosz Golaszewski <bartosz.g...@oss.qualcomm.com>
---
drivers/base/platform.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 75b4698d0e582e67adafa78c312d75c72fd654cf..a6268a72a99e864cbfc333cd99c0d5706b901ff3 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -599,6 +599,7 @@ static void platform_device_release(struct device *dev)
struct platform_object *pa = container_of(dev, struct platform_object,
pdev.dev);

+ device_remove_software_node(dev);
of_node_put(pa->pdev.dev.of_node);
kfree(pa->pdev.dev.platform_data);
kfree(pa->pdev.mfd_cell);
@@ -848,7 +849,11 @@ struct platform_device *platform_device_register_full(const struct platform_devi
int ret;
struct platform_device *pdev;

- if (pdevinfo->swnode && pdevinfo->properties)
+ /*
+ * Only one software node per device is allowed. Make sure we don't
+ * accept or create two.
+ */
+ if (pdevinfo->swnode && (pdevinfo->properties || is_software_node(pdevinfo->fwnode)))
return ERR_PTR(-EINVAL);

pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id);
@@ -866,6 +871,16 @@ struct platform_device *platform_device_register_full(const struct platform_devi
pdev->dev.coherent_dma_mask = pdevinfo->dma_mask;
}

+ /*
+ * If the primary firmware node is a software node and there's no
+ * secondary firmware node, the primary will be affected by the call
+ * to device_remove_software_node() in platform_device_release() and
+ * its reference count will be dropped by one. Take another reference
+ * here to make it have no effect.
+ */
+ if (is_software_node(pdevinfo->fwnode) && !pdevinfo->swnode)
+ fwnode_handle_get(pdevinfo->fwnode);
+
ret = platform_device_add_resources(pdev, pdevinfo->res, pdevinfo->num_res);
if (ret)
goto err;

--
2.47.3

Bartosz Golaszewski

unread,
Apr 28, 2026, 5:20:46 AM (4 days ago) Apr 28
to Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, br...@kernel.org, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, Bartosz Golaszewski
Implement a helper for registering kunit test-managed software nodes.

Signed-off-by: Bartosz Golaszewski <bartosz.g...@oss.qualcomm.com>
---

Bartosz Golaszewski

unread,
Apr 28, 2026, 5:20:49 AM (4 days ago) Apr 28
to Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, br...@kernel.org, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, Bartosz Golaszewski
Extend the kunit module for platform devices with test cases verifying
that the same software node can be added to platform devices repeatedly.

Signed-off-by: Bartosz Golaszewski <bartosz.g...@oss.qualcomm.com>
---
drivers/base/test/platform-device-test.c | 156 +++++++++++++++++++++++++++++++
1 file changed, 156 insertions(+)

diff --git a/drivers/base/test/platform-device-test.c b/drivers/base/test/platform-device-test.c
index 6355a2231b741791b54eb78af42e13f31f745184..19b3b2ea150738877278f7e37be7ef69539147c0 100644
--- a/drivers/base/test/platform-device-test.c
+++ b/drivers/base/test/platform-device-test.c
@@ -1,12 +1,15 @@
// SPDX-License-Identifier: GPL-2.0

+#include <kunit/fwnode.h>
#include <kunit/platform_device.h>
#include <kunit/resource.h>

#include <linux/device.h>
#include <linux/device/bus.h>
+#include <linux/fwnode.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/property.h>

#define DEVICE_NAME "test"

@@ -253,9 +256,162 @@ static struct kunit_suite platform_device_match_test_suite = {
+ int ret;
+
+ struct fwnode_handle *fwnode;
+ int ret;
+
+ ret = kunit_platform_driver_register(test, &platform_swnode_test_driver);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ fwnode = kunit_software_node_register(test, &platform_device_test_swnode);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fwnode);
+
+ pdevinfo = (struct platform_device_info){
+ .name = DEVICE_NAME,
+ .id = PLATFORM_DEVID_NONE,
+ .fwnode = fwnode,
+ };
+
+ pdev = platform_device_register_full(&pdevinfo);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
+
+ wait_for_device_probe();
+ KUNIT_ASSERT_TRUE(test, device_is_bound(&pdev->dev));
+
+ platform_device_unregister(pdev);
+
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, software_node_fwnode(&platform_device_test_swnode));
+}
+
+static const struct software_node platform_device_test_primary_swnode = { };
+
+/*
+ * Check that passing two software nodes to platform_device_register_full()
+ * fails.
+ */
+static void platform_device_two_swnodes(struct kunit *test)
+{
+ static const struct property_entry properties[] = {
+ PROPERTY_ENTRY_U32("foo", 42),
+ { }
+ };
+
+ struct platform_device_info pdevinfo;
+ struct platform_device *pdev;
+ struct fwnode_handle *fwnode;
+ int ret;
+
+ ret = kunit_platform_driver_register(test, &platform_swnode_test_driver);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ fwnode = kunit_software_node_register(test, &platform_device_test_swnode);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fwnode);
+
+ pdevinfo = (struct platform_device_info){
+ .name = DEVICE_NAME,
+ .id = PLATFORM_DEVID_NONE,
+ .fwnode = fwnode,
+ .swnode = &platform_device_test_swnode,
+ };
+
+ pdev = platform_device_register_full(&pdevinfo);
+ KUNIT_ASSERT_TRUE(test, IS_ERR(pdev));
+ KUNIT_ASSERT_EQ_MSG(test, PTR_ERR(pdev), -EINVAL,
+ "Expected errno == -EINVAL, got: %pe", pdev);
+
+ pdevinfo = (struct platform_device_info){
+ .name = DEVICE_NAME,
+ .id = PLATFORM_DEVID_NONE,
+ .swnode = &platform_device_test_swnode,
+ .properties = properties,
+ };
+
+ pdev = platform_device_register_full(&pdevinfo);
+ KUNIT_ASSERT_TRUE(test, IS_ERR(pdev));
+ KUNIT_ASSERT_EQ_MSG(test, PTR_ERR(pdev), -EINVAL,
+ "Expected errno == -EINVAL, got: %pe", pdev);
+}
+
+static struct kunit_case platform_device_swnode_tests[] = {
+ KUNIT_CASE(platform_device_swnode_add_twice),
+ KUNIT_CASE(platform_device_swnode_as_primary),
+ KUNIT_CASE(platform_device_two_swnodes),

Andy Shevchenko

unread,
Apr 28, 2026, 7:10:32 AM (4 days ago) Apr 28
to Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, br...@kernel.org, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com
On Tue, Apr 28, 2026 at 11:20:26AM +0200, Bartosz Golaszewski wrote:
> If we pass a software node to a newly created device using struct
> platform_device_info, it will not be removed when the device is
> released. This may happen when a module creating the device is removed
> or on failure in platform_device_add().
>
> When we try to reuse that software node in a subsequent call to
> platform_device_register_full(), it will fails with -EBUSY. Add the
> missing call to device_remove_software_node() in release path.
>
> In addition to the above change, make sure that we still function
> correctly if a software node is used as the primary firmware node as
> well as disallow using two software nodes for platform devices as
> device_add_software_node() does not handle this case correctly (in fact
> a comment inside it states that only one software node per device is
> allowed but it will not bail out if two are used so we need to handle it
> here).

...

> + device_remove_software_node(dev);
> of_node_put(pa->pdev.dev.of_node);

So, why do we decide not to convert this to fwnode_handle_put() (and respective
_get() elsewhere)?

...

> + /*
> + * Only one software node per device is allowed. Make sure we don't
> + * accept or create two.
> + */
> + if (pdevinfo->swnode && (pdevinfo->properties || is_software_node(pdevinfo->fwnode)))
> return ERR_PTR(-EINVAL);

^^^ left for the context.

...

> + /*
> + * If the primary firmware node is a software node and there's no
> + * secondary firmware node, the primary will be affected by the call
> + * to device_remove_software_node() in platform_device_release() and
> + * its reference count will be dropped by one. Take another reference
> + * here to make it have no effect.
> + */
> + if (is_software_node(pdevinfo->fwnode) && !pdevinfo->swnode)
> + fwnode_handle_get(pdevinfo->fwnode);

IIUC the `is_software_node(pdevinfo->fwnode) && pdevinfo->swnode` may not
happen here due to the above check. If I haven't missed anything, this check
is simply

if (is_software_node(pdevinfo->fwnode))

Bartosz Golaszewski

unread,
Apr 28, 2026, 7:16:47 AM (4 days ago) Apr 28
to Andy Shevchenko, Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com
On Tue, Apr 28, 2026 at 1:10 PM Andy Shevchenko
<andriy.s...@intel.com> wrote:
>
> On Tue, Apr 28, 2026 at 11:20:26AM +0200, Bartosz Golaszewski wrote:
> > If we pass a software node to a newly created device using struct
> > platform_device_info, it will not be removed when the device is
> > released. This may happen when a module creating the device is removed
> > or on failure in platform_device_add().
> >
> > When we try to reuse that software node in a subsequent call to
> > platform_device_register_full(), it will fails with -EBUSY. Add the
> > missing call to device_remove_software_node() in release path.
> >
> > In addition to the above change, make sure that we still function
> > correctly if a software node is used as the primary firmware node as
> > well as disallow using two software nodes for platform devices as
> > device_add_software_node() does not handle this case correctly (in fact
> > a comment inside it states that only one software node per device is
> > allowed but it will not bail out if two are used so we need to handle it
> > here).
>
> ...
>
> > + device_remove_software_node(dev);
> > of_node_put(pa->pdev.dev.of_node);
>
> So, why do we decide not to convert this to fwnode_handle_put() (and respective
> _get() elsewhere)?
>

Yes, I'll do it separately, I don't want to shove too much stuff into
this bugfix.

> ...
>
> > + /*
> > + * Only one software node per device is allowed. Make sure we don't
> > + * accept or create two.
> > + */
> > + if (pdevinfo->swnode && (pdevinfo->properties || is_software_node(pdevinfo->fwnode)))
> > return ERR_PTR(-EINVAL);
>
> ^^^ left for the context.
>
> ...
>
> > + /*
> > + * If the primary firmware node is a software node and there's no
> > + * secondary firmware node, the primary will be affected by the call
> > + * to device_remove_software_node() in platform_device_release() and
> > + * its reference count will be dropped by one. Take another reference
> > + * here to make it have no effect.
> > + */
> > + if (is_software_node(pdevinfo->fwnode) && !pdevinfo->swnode)
> > + fwnode_handle_get(pdevinfo->fwnode);
>
> IIUC the `is_software_node(pdevinfo->fwnode) && pdevinfo->swnode` may not
> happen here due to the above check. If I haven't missed anything, this check
> is simply
>

Right, it can be a simple is_software_node(pdevinfo->fwnode).

Bart

Andy Shevchenko

unread,
Apr 28, 2026, 7:26:56 AM (4 days ago) Apr 28
to Bartosz Golaszewski, Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com
On Tue, Apr 28, 2026 at 01:16:30PM +0200, Bartosz Golaszewski wrote:
> On Tue, Apr 28, 2026 at 1:10 PM Andy Shevchenko
> <andriy.s...@intel.com> wrote:
> > On Tue, Apr 28, 2026 at 11:20:26AM +0200, Bartosz Golaszewski wrote:

...

> > > + device_remove_software_node(dev);
> > > of_node_put(pa->pdev.dev.of_node);
> >
> > So, why do we decide not to convert this to fwnode_handle_put() (and respective
> > _get() elsewhere)?
>
> Yes, I'll do it separately, I don't want to shove too much stuff into
> this bugfix.

Ah, good!

...

> > > + /*
> > > + * If the primary firmware node is a software node and there's no
> > > + * secondary firmware node, the primary will be affected by the call
> > > + * to device_remove_software_node() in platform_device_release() and
> > > + * its reference count will be dropped by one. Take another reference
> > > + * here to make it have no effect.
> > > + */
> > > + if (is_software_node(pdevinfo->fwnode) && !pdevinfo->swnode)
> > > + fwnode_handle_get(pdevinfo->fwnode);
> >
> > IIUC the `is_software_node(pdevinfo->fwnode) && pdevinfo->swnode` may not
> > happen here due to the above check. If I haven't missed anything, this check
> > is simply
>
> Right, it can be a simple is_software_node(pdevinfo->fwnode).

With that being addressed, the rest LGTM,

Reviewed-by: Andy Shevchenko <andriy.s...@intel.com>

(also assuming we will have at some point the above mentioned amendment).

Bartosz Golaszewski

unread,
Apr 30, 2026, 3:46:22 AM (yesterday) Apr 30
to Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, br...@kernel.org, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, Bartosz Golaszewski, Andy Shevchenko
This fixes an issue in platform device code where, if we specify a
software node for a platform device using struct platform_device_info,
it will not be removed on device .release().

The second patch adds a new kunit helper which is used in patch 3/3 that
adds a test-case that can be used to reproduce the problem and prove that
the fix works as well as another making sure a corner case of using a
software node as the primary firmware node works too.

Merging strategy: patch 1/3 should go into v7.1. Once it's upstream, the
first tag containing it should be pulled into the driver core tree and
the remaining patches applied on top with an ack from the kunit
maintainers.

Signed-off-by: Bartosz Golaszewski <bartosz.g...@oss.qualcomm.com>
---
Changes in v4:
- Drop redundant !pdevinfo->swnode check in
platform_device_register_full()
- Handle all three combinations with which two software nodes can be
assigned to a platform device
- Extend the new kunit test to verify all three combinations
- Link to v3: https://patch.msgid.link/20260428-swnode-remove-on-...@oss.qualcomm.com

Changes in v3:
- Make sure the reference of the primary software node we possibly take,
is always released by moving the get() before calls that may fail
- Don't allow passing two software nodes
- Add a test case for that situation
- Link to v2: https://patch.msgid.link/20260423-swnode-remove-on-...@oss.qualcomm.com

Changes in v2:
- Change the order between removing the software node and dropping the
reference to the device's OF node
- Address a situation where a software node is used as the primary
firmware node
- Add a patch adding a new kunit helper
- Add another test case
- Link to v1: https://patch.msgid.link/20260410-swnode-remove-on-...@oss.qualcomm.com

---
Bartosz Golaszewski (3):
driver core: platform: remove software node on release()
kunit: provide kunit_software_node_register()
driver core: platform: tests: add test cases for correct swnode removal

drivers/base/platform.c | 19 +++-
drivers/base/test/platform-device-test.c | 168 +++++++++++++++++++++++++++++++
include/kunit/fwnode.h | 19 ++++
lib/kunit/Makefile | 3 +-
lib/kunit/fwnode.c | 52 ++++++++++
5 files changed, 259 insertions(+), 2 deletions(-)

Bartosz Golaszewski

unread,
Apr 30, 2026, 3:46:24 AM (yesterday) Apr 30
to Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, br...@kernel.org, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, Bartosz Golaszewski, Andy Shevchenko
If we pass a software node to a newly created device using struct
platform_device_info, it will not be removed when the device is
released. This may happen when a module creating the device is removed
or on failure in platform_device_add().

When we try to reuse that software node in a subsequent call to
platform_device_register_full(), it will fails with -EBUSY. Add the
missing call to device_remove_software_node() in release path.

In addition to the above change, make sure that we still function
correctly if a software node is used as the primary firmware node as
well as disallow using two software nodes for platform devices as
device_add_software_node() does not handle this case correctly (in fact
a comment inside it states that only one software node per device is
allowed but it will not bail out if two are used so we need to handle it
here).

Fixes: 0fc434bc2c45 ("driver core: platform: allow attaching software nodes when creating devices")
Reviewed-by: Andy Shevchenko <andriy.s...@intel.com>
Signed-off-by: Bartosz Golaszewski <bartosz.g...@oss.qualcomm.com>
---
drivers/base/platform.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 75b4698d0e582e67adafa78c312d75c72fd654cf..22834be0a3aeabf538f57ec6815ab3cd6851c16b 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -599,6 +599,7 @@ static void platform_device_release(struct device *dev)
struct platform_object *pa = container_of(dev, struct platform_object,
pdev.dev);

+ device_remove_software_node(dev);
of_node_put(pa->pdev.dev.of_node);
kfree(pa->pdev.dev.platform_data);
kfree(pa->pdev.mfd_cell);
@@ -848,7 +849,13 @@ struct platform_device *platform_device_register_full(const struct platform_devi
int ret;
struct platform_device *pdev;

- if (pdevinfo->swnode && pdevinfo->properties)
+ /*
+ * Only one software node per device is allowed. Make sure we don't
+ * accept or create two.
+ */
+ if ((pdevinfo->swnode && pdevinfo->properties) ||
+ (pdevinfo->swnode && is_software_node(pdevinfo->fwnode)) ||
+ (pdevinfo->properties && is_software_node(pdevinfo->fwnode)))
return ERR_PTR(-EINVAL);

pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id);
@@ -866,6 +873,16 @@ struct platform_device *platform_device_register_full(const struct platform_devi
pdev->dev.coherent_dma_mask = pdevinfo->dma_mask;
}

+ /*
+ * If the primary firmware node is a software node and there's no
+ * secondary firmware node, the primary will be affected by the call
+ * to device_remove_software_node() in platform_device_release() and
+ * its reference count will be dropped by one. Take another reference
+ * here to make it have no effect.
+ */
+ if (is_software_node(pdevinfo->fwnode))

Bartosz Golaszewski

unread,
Apr 30, 2026, 3:46:26 AM (yesterday) Apr 30
to Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, br...@kernel.org, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, Bartosz Golaszewski
Implement a helper for registering kunit test-managed software nodes.

Signed-off-by: Bartosz Golaszewski <bartosz.g...@oss.qualcomm.com>
---
+ struct fwnode_handle *fwnode;
+ int ret;
+

Bartosz Golaszewski

unread,
Apr 30, 2026, 3:46:28 AM (yesterday) Apr 30
to Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, br...@kernel.org, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com, Bartosz Golaszewski
Extend the kunit module for platform devices with test cases verifying
that the same software node can be added to platform devices repeatedly.

Signed-off-by: Bartosz Golaszewski <bartosz.g...@oss.qualcomm.com>
---
drivers/base/test/platform-device-test.c | 168 +++++++++++++++++++++++++++++++
1 file changed, 168 insertions(+)

diff --git a/drivers/base/test/platform-device-test.c b/drivers/base/test/platform-device-test.c
index 6355a2231b741791b54eb78af42e13f31f745184..3e42c205fc935ab1dd2066e257d4ecf837c9ad79 100644
--- a/drivers/base/test/platform-device-test.c
+++ b/drivers/base/test/platform-device-test.c
@@ -1,12 +1,15 @@
// SPDX-License-Identifier: GPL-2.0

+#include <kunit/fwnode.h>
#include <kunit/platform_device.h>
#include <kunit/resource.h>

#include <linux/device.h>
#include <linux/device/bus.h>
+#include <linux/fwnode.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/property.h>

#define DEVICE_NAME "test"

@@ -253,9 +256,174 @@ static struct kunit_suite platform_device_match_test_suite = {
+ int ret;
+
+ struct fwnode_handle *fwnode;
+ int ret;
+
+ struct fwnode_handle *fwnode;
+ int ret;
+
+ pdevinfo = (struct platform_device_info){
+ .name = DEVICE_NAME,
+ .id = PLATFORM_DEVID_NONE,
+ .fwnode = fwnode,

Andy Shevchenko

unread,
Apr 30, 2026, 8:02:20 AM (yesterday) Apr 30
to Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, br...@kernel.org, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com
On Thu, Apr 30, 2026 at 09:46:04AM +0200, Bartosz Golaszewski wrote:
> If we pass a software node to a newly created device using struct
> platform_device_info, it will not be removed when the device is
> released. This may happen when a module creating the device is removed
> or on failure in platform_device_add().
>
> When we try to reuse that software node in a subsequent call to
> platform_device_register_full(), it will fails with -EBUSY. Add the
> missing call to device_remove_software_node() in release path.
>
> In addition to the above change, make sure that we still function
> correctly if a software node is used as the primary firmware node as
> well as disallow using two software nodes for platform devices as
> device_add_software_node() does not handle this case correctly (in fact
> a comment inside it states that only one software node per device is
> allowed but it will not bail out if two are used so we need to handle it
> here).

...

> - if (pdevinfo->swnode && pdevinfo->properties)
> + /*
> + * Only one software node per device is allowed. Make sure we don't
> + * accept or create two.
> + */
> + if ((pdevinfo->swnode && pdevinfo->properties) ||
> + (pdevinfo->swnode && is_software_node(pdevinfo->fwnode)) ||
> + (pdevinfo->properties && is_software_node(pdevinfo->fwnode)))
> return ERR_PTR(-EINVAL);

This makes me think of why we have these many ways of doing things...
Perhaps we should kill pdevinfo::properties completely?

Second thought is what about actually refusing this on the level of
device_add_software_node()? And looking at it, we have that check
there, why do we need it here then? Did we miss to check error code from
device_add_software_node() somewhere?

Bartosz Golaszewski

unread,
Apr 30, 2026, 8:38:34 AM (yesterday) Apr 30
to Andy Shevchenko, Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Dmitry Torokhov, Brendan Higgins, David Gow, Rae Moar, Andy Shevchenko, drive...@lists.linux.dev, linux-...@vger.kernel.org, linux-k...@vger.kernel.org, kuni...@googlegroups.com
Good luck with that, I'm pretty sure a lot of users are still out
there. :) It's also relatively convenient and skips one more struct
definition.

> Second thought is what about actually refusing this on the level of
> device_add_software_node()? And looking at it, we have that check
> there, why do we need it here then? Did we miss to check error code from
> device_add_software_node() somewhere?
>

device_create_managed_software_node() doesn't seem to have that check
unlike device_add_software_node() so we'd hit an issue with properties
!= NULL && swnode supplied. I think failing earlier here makes for
more readable code and less error-prone unwinding on failure.

Also: device_add_software_node() return -EBUSY while I think it makes
more sense to return -EINVAL. I prefer to keep this check locally
unless driver core maintainers object.

Bart
Reply all
Reply to author
Forward
0 new messages