1// SPDX-License-Identifier: GPL-2.0 2// Copyright 2023 Maxime Ripard <mripard@kernel.org> 3 4#include <kunit/resource.h> 5 6#include <linux/device.h> 7 8#define DEVICE_NAME "test" 9 10struct test_priv { 11 bool probe_done; 12 bool release_done; 13 wait_queue_head_t release_wq; 14 struct device *dev; 15}; 16 17static int root_device_devm_init(struct kunit *test) 18{ 19 struct test_priv *priv; 20 21 priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); 22 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv); 23 init_waitqueue_head(&priv->release_wq); 24 25 test->priv = priv; 26 27 return 0; 28} 29 30static void devm_device_action(void *ptr) 31{ 32 struct test_priv *priv = ptr; 33 34 priv->release_done = true; 35 wake_up_interruptible(&priv->release_wq); 36} 37 38#define RELEASE_TIMEOUT_MS 100 39 40/* 41 * Tests that a bus-less, non-probed device will run its device-managed 42 * actions when unregistered. 43 */ 44static void root_device_devm_register_unregister_test(struct kunit *test) 45{ 46 struct test_priv *priv = test->priv; 47 int ret; 48 49 priv->dev = root_device_register(DEVICE_NAME); 50 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev); 51 52 ret = devm_add_action_or_reset(priv->dev, devm_device_action, priv); 53 KUNIT_ASSERT_EQ(test, ret, 0); 54 55 root_device_unregister(priv->dev); 56 57 ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done, 58 msecs_to_jiffies(RELEASE_TIMEOUT_MS)); 59 KUNIT_EXPECT_GT(test, ret, 0); 60} 61 62static void devm_put_device_action(void *ptr) 63{ 64 struct test_priv *priv = ptr; 65 66 put_device(priv->dev); 67 priv->release_done = true; 68 wake_up_interruptible(&priv->release_wq); 69} 70 71/* 72 * Tests that a bus-less, non-probed device will run its device-managed 73 * actions when unregistered, even if someone still holds a reference to 74 * it. 75 */ 76static void root_device_devm_register_get_unregister_with_devm_test(struct kunit *test) 77{ 78 struct test_priv *priv = test->priv; 79 int ret; 80 81 priv->dev = root_device_register(DEVICE_NAME); 82 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev); 83 84 get_device(priv->dev); 85 86 ret = devm_add_action_or_reset(priv->dev, devm_put_device_action, priv); 87 KUNIT_ASSERT_EQ(test, ret, 0); 88 89 root_device_unregister(priv->dev); 90 91 ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done, 92 msecs_to_jiffies(RELEASE_TIMEOUT_MS)); 93 KUNIT_EXPECT_GT(test, ret, 0); 94} 95 96static struct kunit_case root_device_devm_tests[] = { 97 KUNIT_CASE(root_device_devm_register_unregister_test), 98 KUNIT_CASE(root_device_devm_register_get_unregister_with_devm_test), 99 {} 100}; 101 102static struct kunit_suite root_device_devm_test_suite = { 103 .name = "root-device-devm", 104 .init = root_device_devm_init, 105 .test_cases = root_device_devm_tests, 106}; 107 108kunit_test_suite(root_device_devm_test_suite); 109 110MODULE_DESCRIPTION("Test module for root devices"); 111MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>"); 112MODULE_LICENSE("GPL"); 113