mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
f71b144e3e
Commitb4cc44301b
("drivers: base: Add basic devm tests for platform devices") introduced a new set of tests for platform devices that could be compiled as a module, but didn't have the usual module macros. Make sure they're there. Fixes:b4cc44301b
("drivers: base: Add basic devm tests for platform devices") Reported-by: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Maxime Ripard <mripard@kernel.org> Link: https://lore.kernel.org/r/20230816073019.1446155-1-mripard@kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
225 lines
5.8 KiB
C
225 lines
5.8 KiB
C
// 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");
|