1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <kunit/resource.h> 4 5 #include <linux/device.h> 6 #include <linux/platform_device.h> 7 8 #define DEVICE_NAME "test" 9 10 struct test_priv { 11 bool probe_done; 12 bool release_done; 13 wait_queue_head_t probe_wq; 14 wait_queue_head_t release_wq; 15 struct device *dev; 16 }; 17 18 static int platform_device_devm_init(struct kunit *test) 19 { 20 struct test_priv *priv; 21 22 priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); 23 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv); 24 init_waitqueue_head(&priv->probe_wq); 25 init_waitqueue_head(&priv->release_wq); 26 27 test->priv = priv; 28 29 return 0; 30 } 31 32 static void devm_device_action(void *ptr) 33 { 34 struct test_priv *priv = ptr; 35 36 priv->release_done = true; 37 wake_up_interruptible(&priv->release_wq); 38 } 39 40 static void devm_put_device_action(void *ptr) 41 { 42 struct test_priv *priv = ptr; 43 44 put_device(priv->dev); 45 priv->release_done = true; 46 wake_up_interruptible(&priv->release_wq); 47 } 48 49 #define RELEASE_TIMEOUT_MS 100 50 51 /* 52 * Tests that a platform bus, non-probed device will run its 53 * device-managed actions when unregistered. 54 */ 55 static void platform_device_devm_register_unregister_test(struct kunit *test) 56 { 57 struct platform_device *pdev; 58 struct test_priv *priv = test->priv; 59 int ret; 60 61 pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE); 62 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); 63 64 ret = platform_device_add(pdev); 65 KUNIT_ASSERT_EQ(test, ret, 0); 66 67 priv->dev = &pdev->dev; 68 69 ret = devm_add_action_or_reset(priv->dev, devm_device_action, priv); 70 KUNIT_ASSERT_EQ(test, ret, 0); 71 72 platform_device_unregister(pdev); 73 74 ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done, 75 msecs_to_jiffies(RELEASE_TIMEOUT_MS)); 76 KUNIT_EXPECT_GT(test, ret, 0); 77 } 78 79 /* 80 * Tests that a platform bus, non-probed device will run its 81 * device-managed actions when unregistered, even if someone still holds 82 * a reference to it. 83 */ 84 static void platform_device_devm_register_get_unregister_with_devm_test(struct kunit *test) 85 { 86 struct platform_device *pdev; 87 struct test_priv *priv = test->priv; 88 int ret; 89 90 pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE); 91 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); 92 93 ret = platform_device_add(pdev); 94 KUNIT_ASSERT_EQ(test, ret, 0); 95 96 priv->dev = &pdev->dev; 97 98 get_device(priv->dev); 99 100 ret = devm_add_action_or_reset(priv->dev, devm_put_device_action, priv); 101 KUNIT_ASSERT_EQ(test, ret, 0); 102 103 platform_device_unregister(pdev); 104 105 ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done, 106 msecs_to_jiffies(RELEASE_TIMEOUT_MS)); 107 KUNIT_EXPECT_GT(test, ret, 0); 108 } 109 110 static int fake_probe(struct platform_device *pdev) 111 { 112 struct test_priv *priv = platform_get_drvdata(pdev); 113 114 priv->probe_done = true; 115 wake_up_interruptible(&priv->probe_wq); 116 117 return 0; 118 } 119 120 static struct platform_driver fake_driver = { 121 .probe = fake_probe, 122 .driver = { 123 .name = DEVICE_NAME, 124 }, 125 }; 126 127 /* 128 * Tests that a platform bus, probed device will run its device-managed 129 * actions when unregistered. 130 */ 131 static void probed_platform_device_devm_register_unregister_test(struct kunit *test) 132 { 133 struct platform_device *pdev; 134 struct test_priv *priv = test->priv; 135 int ret; 136 137 ret = platform_driver_register(&fake_driver); 138 KUNIT_ASSERT_EQ(test, ret, 0); 139 140 pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE); 141 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); 142 143 priv->dev = &pdev->dev; 144 platform_set_drvdata(pdev, priv); 145 146 ret = platform_device_add(pdev); 147 KUNIT_ASSERT_EQ(test, ret, 0); 148 149 ret = wait_event_interruptible_timeout(priv->probe_wq, priv->probe_done, 150 msecs_to_jiffies(RELEASE_TIMEOUT_MS)); 151 KUNIT_ASSERT_GT(test, ret, 0); 152 153 ret = devm_add_action_or_reset(priv->dev, devm_device_action, priv); 154 KUNIT_ASSERT_EQ(test, ret, 0); 155 156 platform_device_unregister(pdev); 157 158 ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done, 159 msecs_to_jiffies(RELEASE_TIMEOUT_MS)); 160 KUNIT_EXPECT_GT(test, ret, 0); 161 162 platform_driver_unregister(&fake_driver); 163 } 164 165 /* 166 * Tests that a platform bus, probed device will run its device-managed 167 * actions when unregistered, even if someone still holds a reference to 168 * it. 169 */ 170 static void probed_platform_device_devm_register_get_unregister_with_devm_test(struct kunit *test) 171 { 172 struct platform_device *pdev; 173 struct test_priv *priv = test->priv; 174 int ret; 175 176 ret = platform_driver_register(&fake_driver); 177 KUNIT_ASSERT_EQ(test, ret, 0); 178 179 pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE); 180 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); 181 182 priv->dev = &pdev->dev; 183 platform_set_drvdata(pdev, priv); 184 185 ret = platform_device_add(pdev); 186 KUNIT_ASSERT_EQ(test, ret, 0); 187 188 ret = wait_event_interruptible_timeout(priv->probe_wq, priv->probe_done, 189 msecs_to_jiffies(RELEASE_TIMEOUT_MS)); 190 KUNIT_ASSERT_GT(test, ret, 0); 191 192 get_device(priv->dev); 193 194 ret = devm_add_action_or_reset(priv->dev, devm_put_device_action, priv); 195 KUNIT_ASSERT_EQ(test, ret, 0); 196 197 platform_device_unregister(pdev); 198 199 ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done, 200 msecs_to_jiffies(RELEASE_TIMEOUT_MS)); 201 KUNIT_EXPECT_GT(test, ret, 0); 202 203 platform_driver_unregister(&fake_driver); 204 } 205 206 static struct kunit_case platform_device_devm_tests[] = { 207 KUNIT_CASE(platform_device_devm_register_unregister_test), 208 KUNIT_CASE(platform_device_devm_register_get_unregister_with_devm_test), 209 KUNIT_CASE(probed_platform_device_devm_register_unregister_test), 210 KUNIT_CASE(probed_platform_device_devm_register_get_unregister_with_devm_test), 211 {} 212 }; 213 214 static struct kunit_suite platform_device_devm_test_suite = { 215 .name = "platform-device-devm", 216 .init = platform_device_devm_init, 217 .test_cases = platform_device_devm_tests, 218 }; 219 220 kunit_test_suite(platform_device_devm_test_suite); 221 222 MODULE_DESCRIPTION("Test module for platform devices"); 223 MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>"); 224 MODULE_LICENSE("GPL"); 225