mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git
synced 2026-05-02 18:17:50 -04:00
Merge tag 'driver-core-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core
Pull driver core updates from Greg KH: "Here is a small set of driver core updates and additions for 6.6-rc1. Included in here are: - stable kernel documentation updates - class structure const work from Ivan on various subsystems - kernfs tweaks - driver core tests! - kobject sanity cleanups - kobject structure reordering to save space - driver core error code handling fixups - other minor driver core cleanups All of these have been in linux-next for a while with no reported problems" * tag 'driver-core-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (32 commits) driver core: Call in reversed order in device_platform_notify_remove() driver core: Return proper error code when dev_set_name() fails kobject: Remove redundant checks for whether ktype is NULL kobject: Add sanity check for kset->kobj.ktype in kset_register() drivers: base: test: Add missing MODULE_* macros to root device tests drivers: base: test: Add missing MODULE_* macros for platform devices tests drivers: base: Free devm resources when unregistering a device drivers: base: Add basic devm tests for platform devices drivers: base: Add basic devm tests for root devices kernfs: fix missing kernfs_iattr_rwsem locking docs: stable-kernel-rules: mention that regressions must be prevented docs: stable-kernel-rules: fine-tune various details docs: stable-kernel-rules: make the examples for option 1 a proper list docs: stable-kernel-rules: move text around to improve flow docs: stable-kernel-rules: improve structure by changing headlines base/node: Remove duplicated include kernfs: attach uuid for every kernfs and report it in fsid kernfs: add stub helper for kernfs_generic_poll() x86/resctrl: make pseudo_lock_class a static const structure x86/MSR: make msr_class a static const structure ...
This commit is contained in:
@@ -2306,12 +2306,12 @@ static void device_platform_notify(struct device *dev)
|
||||
|
||||
static void device_platform_notify_remove(struct device *dev)
|
||||
{
|
||||
acpi_device_notify_remove(dev);
|
||||
if (platform_notify_remove)
|
||||
platform_notify_remove(dev);
|
||||
|
||||
software_node_notify_remove(dev);
|
||||
|
||||
if (platform_notify_remove)
|
||||
platform_notify_remove(dev);
|
||||
acpi_device_notify_remove(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3528,18 +3528,17 @@ int device_add(struct device *dev)
|
||||
* the name, and force the use of dev_name()
|
||||
*/
|
||||
if (dev->init_name) {
|
||||
dev_set_name(dev, "%s", dev->init_name);
|
||||
error = dev_set_name(dev, "%s", dev->init_name);
|
||||
dev->init_name = NULL;
|
||||
}
|
||||
|
||||
if (dev_name(dev))
|
||||
error = 0;
|
||||
/* subsystems can specify simple device enumeration */
|
||||
if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
|
||||
dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
|
||||
|
||||
if (!dev_name(dev)) {
|
||||
error = -EINVAL;
|
||||
else if (dev->bus && dev->bus->dev_name)
|
||||
error = dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
|
||||
if (error)
|
||||
goto name_error;
|
||||
}
|
||||
|
||||
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
|
||||
|
||||
@@ -3815,6 +3814,17 @@ void device_del(struct device *dev)
|
||||
device_platform_notify_remove(dev);
|
||||
device_links_purge(dev);
|
||||
|
||||
/*
|
||||
* If a device does not have a driver attached, we need to clean
|
||||
* up any managed resources. We do this in device_release(), but
|
||||
* it's never called (and we leak the device) if a managed
|
||||
* resource holds a reference to the device. So release all
|
||||
* managed resources here, like we do in driver_detach(). We
|
||||
* still need to do so again in device_release() in case someone
|
||||
* adds a new resource after this point, though.
|
||||
*/
|
||||
devres_release_all(dev);
|
||||
|
||||
bus_notify(dev, BUS_NOTIFY_REMOVED_DEVICE);
|
||||
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
|
||||
glue_dir = get_glue_dir(dev);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <linux/cpufeature.h>
|
||||
#include <linux/tick.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sched/isolation.h>
|
||||
|
||||
#include "base.h"
|
||||
@@ -50,12 +51,30 @@ static int cpu_subsys_online(struct device *dev)
|
||||
int cpuid = dev->id;
|
||||
int from_nid, to_nid;
|
||||
int ret;
|
||||
int retries = 0;
|
||||
|
||||
from_nid = cpu_to_node(cpuid);
|
||||
if (from_nid == NUMA_NO_NODE)
|
||||
return -ENODEV;
|
||||
|
||||
retry:
|
||||
ret = cpu_device_up(dev);
|
||||
|
||||
/*
|
||||
* If -EBUSY is returned, it is likely that hotplug is temporarily
|
||||
* disabled when cpu_hotplug_disable() was called. This condition is
|
||||
* transient. So we retry after waiting for an exponentially
|
||||
* increasing delay up to a total of at least 620ms as some PCI
|
||||
* device initialization can take quite a while.
|
||||
*/
|
||||
if (ret == -EBUSY) {
|
||||
retries++;
|
||||
if (retries > 5)
|
||||
return ret;
|
||||
msleep(10 * (1 << retries));
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/*
|
||||
* When hot adding memory to memoryless node and enabling a cpu
|
||||
* on the node, node number of the cpu may internally change.
|
||||
|
||||
@@ -693,6 +693,8 @@ re_probe:
|
||||
|
||||
device_remove(dev);
|
||||
driver_sysfs_remove(dev);
|
||||
if (dev->bus && dev->bus->dma_cleanup)
|
||||
dev->bus->dma_cleanup(dev);
|
||||
device_unbind_cleanup(dev);
|
||||
|
||||
goto re_probe;
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/swap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/hugetlb.h>
|
||||
|
||||
static struct bus_type node_subsys = {
|
||||
.name = "node",
|
||||
|
||||
2
drivers/base/test/.kunitconfig
Normal file
2
drivers/base/test/.kunitconfig
Normal file
@@ -0,0 +1,2 @@
|
||||
CONFIG_KUNIT=y
|
||||
CONFIG_DM_KUNIT_TEST=y
|
||||
@@ -9,6 +9,10 @@ config TEST_ASYNC_DRIVER_PROBE
|
||||
|
||||
If unsure say N.
|
||||
|
||||
config DM_KUNIT_TEST
|
||||
tristate "KUnit Tests for the device model" if !KUNIT_ALL_TESTS
|
||||
depends on KUNIT
|
||||
|
||||
config DRIVER_PE_KUNIT_TEST
|
||||
bool "KUnit Tests for property entry API" if !KUNIT_ALL_TESTS
|
||||
depends on KUNIT=y
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_TEST_ASYNC_DRIVER_PROBE) += test_async_driver_probe.o
|
||||
|
||||
obj-$(CONFIG_DM_KUNIT_TEST) += root-device-test.o
|
||||
obj-$(CONFIG_DM_KUNIT_TEST) += platform-device-test.o
|
||||
|
||||
obj-$(CONFIG_DRIVER_PE_KUNIT_TEST) += property-entry-test.o
|
||||
CFLAGS_property-entry-test.o += $(DISABLE_STRUCTLEAK_PLUGIN)
|
||||
|
||||
224
drivers/base/test/platform-device-test.c
Normal file
224
drivers/base/test/platform-device-test.c
Normal file
@@ -0,0 +1,224 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <kunit/resource.h>
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define DEVICE_NAME "test"
|
||||
|
||||
struct test_priv {
|
||||
bool probe_done;
|
||||
bool release_done;
|
||||
wait_queue_head_t probe_wq;
|
||||
wait_queue_head_t release_wq;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static int platform_device_devm_init(struct kunit *test)
|
||||
{
|
||||
struct test_priv *priv;
|
||||
|
||||
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
|
||||
init_waitqueue_head(&priv->probe_wq);
|
||||
init_waitqueue_head(&priv->release_wq);
|
||||
|
||||
test->priv = priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void devm_device_action(void *ptr)
|
||||
{
|
||||
struct test_priv *priv = ptr;
|
||||
|
||||
priv->release_done = true;
|
||||
wake_up_interruptible(&priv->release_wq);
|
||||
}
|
||||
|
||||
static void devm_put_device_action(void *ptr)
|
||||
{
|
||||
struct test_priv *priv = ptr;
|
||||
|
||||
put_device(priv->dev);
|
||||
priv->release_done = true;
|
||||
wake_up_interruptible(&priv->release_wq);
|
||||
}
|
||||
|
||||
#define RELEASE_TIMEOUT_MS 100
|
||||
|
||||
/*
|
||||
* Tests that a platform bus, non-probed device will run its
|
||||
* device-managed actions when unregistered.
|
||||
*/
|
||||
static void platform_device_devm_register_unregister_test(struct kunit *test)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct test_priv *priv = test->priv;
|
||||
int ret;
|
||||
|
||||
pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
|
||||
|
||||
ret = platform_device_add(pdev);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
priv->dev = &pdev->dev;
|
||||
|
||||
ret = devm_add_action_or_reset(priv->dev, devm_device_action, priv);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
|
||||
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
|
||||
KUNIT_EXPECT_GT(test, ret, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests that a platform bus, non-probed device will run its
|
||||
* device-managed actions when unregistered, even if someone still holds
|
||||
* a reference to it.
|
||||
*/
|
||||
static void platform_device_devm_register_get_unregister_with_devm_test(struct kunit *test)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct test_priv *priv = test->priv;
|
||||
int ret;
|
||||
|
||||
pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
|
||||
|
||||
ret = platform_device_add(pdev);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
priv->dev = &pdev->dev;
|
||||
|
||||
get_device(priv->dev);
|
||||
|
||||
ret = devm_add_action_or_reset(priv->dev, devm_put_device_action, priv);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
|
||||
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
|
||||
KUNIT_EXPECT_GT(test, ret, 0);
|
||||
}
|
||||
|
||||
static int fake_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct test_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
priv->probe_done = true;
|
||||
wake_up_interruptible(&priv->probe_wq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver fake_driver = {
|
||||
.probe = fake_probe,
|
||||
.driver = {
|
||||
.name = DEVICE_NAME,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Tests that a platform bus, probed device will run its device-managed
|
||||
* actions when unregistered.
|
||||
*/
|
||||
static void probed_platform_device_devm_register_unregister_test(struct kunit *test)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct test_priv *priv = test->priv;
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&fake_driver);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
|
||||
|
||||
priv->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
ret = platform_device_add(pdev);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->probe_wq, priv->probe_done,
|
||||
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
|
||||
KUNIT_ASSERT_GT(test, ret, 0);
|
||||
|
||||
ret = devm_add_action_or_reset(priv->dev, devm_device_action, priv);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
|
||||
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
|
||||
KUNIT_EXPECT_GT(test, ret, 0);
|
||||
|
||||
platform_driver_unregister(&fake_driver);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests that a platform bus, probed device will run its device-managed
|
||||
* actions when unregistered, even if someone still holds a reference to
|
||||
* it.
|
||||
*/
|
||||
static void probed_platform_device_devm_register_get_unregister_with_devm_test(struct kunit *test)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct test_priv *priv = test->priv;
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&fake_driver);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
|
||||
|
||||
priv->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
ret = platform_device_add(pdev);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->probe_wq, priv->probe_done,
|
||||
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
|
||||
KUNIT_ASSERT_GT(test, ret, 0);
|
||||
|
||||
get_device(priv->dev);
|
||||
|
||||
ret = devm_add_action_or_reset(priv->dev, devm_put_device_action, priv);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
|
||||
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
|
||||
KUNIT_EXPECT_GT(test, ret, 0);
|
||||
|
||||
platform_driver_unregister(&fake_driver);
|
||||
}
|
||||
|
||||
static struct kunit_case platform_device_devm_tests[] = {
|
||||
KUNIT_CASE(platform_device_devm_register_unregister_test),
|
||||
KUNIT_CASE(platform_device_devm_register_get_unregister_with_devm_test),
|
||||
KUNIT_CASE(probed_platform_device_devm_register_unregister_test),
|
||||
KUNIT_CASE(probed_platform_device_devm_register_get_unregister_with_devm_test),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite platform_device_devm_test_suite = {
|
||||
.name = "platform-device-devm",
|
||||
.init = platform_device_devm_init,
|
||||
.test_cases = platform_device_devm_tests,
|
||||
};
|
||||
|
||||
kunit_test_suite(platform_device_devm_test_suite);
|
||||
|
||||
MODULE_DESCRIPTION("Test module for platform devices");
|
||||
MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
112
drivers/base/test/root-device-test.c
Normal file
112
drivers/base/test/root-device-test.c
Normal file
@@ -0,0 +1,112 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright 2023 Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
#include <kunit/resource.h>
|
||||
|
||||
#include <linux/device.h>
|
||||
|
||||
#define DEVICE_NAME "test"
|
||||
|
||||
struct test_priv {
|
||||
bool probe_done;
|
||||
bool release_done;
|
||||
wait_queue_head_t release_wq;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static int root_device_devm_init(struct kunit *test)
|
||||
{
|
||||
struct test_priv *priv;
|
||||
|
||||
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
|
||||
init_waitqueue_head(&priv->release_wq);
|
||||
|
||||
test->priv = priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void devm_device_action(void *ptr)
|
||||
{
|
||||
struct test_priv *priv = ptr;
|
||||
|
||||
priv->release_done = true;
|
||||
wake_up_interruptible(&priv->release_wq);
|
||||
}
|
||||
|
||||
#define RELEASE_TIMEOUT_MS 100
|
||||
|
||||
/*
|
||||
* Tests that a bus-less, non-probed device will run its device-managed
|
||||
* actions when unregistered.
|
||||
*/
|
||||
static void root_device_devm_register_unregister_test(struct kunit *test)
|
||||
{
|
||||
struct test_priv *priv = test->priv;
|
||||
int ret;
|
||||
|
||||
priv->dev = root_device_register(DEVICE_NAME);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
|
||||
|
||||
ret = devm_add_action_or_reset(priv->dev, devm_device_action, priv);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
root_device_unregister(priv->dev);
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
|
||||
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
|
||||
KUNIT_EXPECT_GT(test, ret, 0);
|
||||
}
|
||||
|
||||
static void devm_put_device_action(void *ptr)
|
||||
{
|
||||
struct test_priv *priv = ptr;
|
||||
|
||||
put_device(priv->dev);
|
||||
priv->release_done = true;
|
||||
wake_up_interruptible(&priv->release_wq);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests that a bus-less, non-probed device will run its device-managed
|
||||
* actions when unregistered, even if someone still holds a reference to
|
||||
* it.
|
||||
*/
|
||||
static void root_device_devm_register_get_unregister_with_devm_test(struct kunit *test)
|
||||
{
|
||||
struct test_priv *priv = test->priv;
|
||||
int ret;
|
||||
|
||||
priv->dev = root_device_register(DEVICE_NAME);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
|
||||
|
||||
get_device(priv->dev);
|
||||
|
||||
ret = devm_add_action_or_reset(priv->dev, devm_put_device_action, priv);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
root_device_unregister(priv->dev);
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
|
||||
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
|
||||
KUNIT_EXPECT_GT(test, ret, 0);
|
||||
}
|
||||
|
||||
static struct kunit_case root_device_devm_tests[] = {
|
||||
KUNIT_CASE(root_device_devm_register_unregister_test),
|
||||
KUNIT_CASE(root_device_devm_register_get_unregister_with_devm_test),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite root_device_devm_test_suite = {
|
||||
.name = "root-device-devm",
|
||||
.init = root_device_devm_init,
|
||||
.test_cases = root_device_devm_tests,
|
||||
};
|
||||
|
||||
kunit_test_suite(root_device_devm_test_suite);
|
||||
|
||||
MODULE_DESCRIPTION("Test module for root devices");
|
||||
MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -84,7 +84,7 @@ test_platform_device_register_node(char *name, int id, int nid)
|
||||
|
||||
pdev = platform_device_alloc(name, id);
|
||||
if (!pdev)
|
||||
return NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (nid != NUMA_NO_NODE)
|
||||
set_dev_node(&pdev->dev, nid);
|
||||
|
||||
Reference in New Issue
Block a user