1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Test managed platform driver 4 */ 5 6 #include <linux/completion.h> 7 #include <linux/device/bus.h> 8 #include <linux/device/driver.h> 9 #include <linux/platform_device.h> 10 11 #include <kunit/platform_device.h> 12 #include <kunit/resource.h> 13 14 struct kunit_platform_device_alloc_params { 15 const char *name; 16 int id; 17 }; 18 19 static int kunit_platform_device_alloc_init(struct kunit_resource *res, void *context) 20 { 21 struct kunit_platform_device_alloc_params *params = context; 22 struct platform_device *pdev; 23 24 pdev = platform_device_alloc(params->name, params->id); 25 if (!pdev) 26 return -ENOMEM; 27 28 res->data = pdev; 29 30 return 0; 31 } 32 33 static void kunit_platform_device_alloc_exit(struct kunit_resource *res) 34 { 35 struct platform_device *pdev = res->data; 36 37 platform_device_put(pdev); 38 } 39 40 /** 41 * kunit_platform_device_alloc() - Allocate a KUnit test managed platform device 42 * @test: test context 43 * @name: device name of platform device to alloc 44 * @id: identifier of platform device to alloc. 45 * 46 * Allocate a test managed platform device. The device is put when the test completes. 47 * 48 * Return: Allocated platform device on success, NULL on failure. 49 */ 50 struct platform_device * 51 kunit_platform_device_alloc(struct kunit *test, const char *name, int id) 52 { 53 struct kunit_platform_device_alloc_params params = { 54 .name = name, 55 .id = id, 56 }; 57 58 return kunit_alloc_resource(test, 59 kunit_platform_device_alloc_init, 60 kunit_platform_device_alloc_exit, 61 GFP_KERNEL, ¶ms); 62 } 63 EXPORT_SYMBOL_GPL(kunit_platform_device_alloc); 64 65 static void kunit_platform_device_add_exit(struct kunit_resource *res) 66 { 67 struct platform_device *pdev = res->data; 68 69 platform_device_unregister(pdev); 70 } 71 72 static bool 73 kunit_platform_device_alloc_match(struct kunit *test, 74 struct kunit_resource *res, void *match_data) 75 { 76 struct platform_device *pdev = match_data; 77 78 return res->data == pdev && res->free == kunit_platform_device_alloc_exit; 79 } 80 81 KUNIT_DEFINE_ACTION_WRAPPER(platform_device_unregister_wrapper, 82 platform_device_unregister, struct platform_device *); 83 /** 84 * kunit_platform_device_add() - Register a KUnit test managed platform device 85 * @test: test context 86 * @pdev: platform device to add 87 * 88 * Register a test managed platform device. The device is unregistered when the 89 * test completes. 90 * 91 * Return: 0 on success, negative errno on failure. 92 */ 93 int kunit_platform_device_add(struct kunit *test, struct platform_device *pdev) 94 { 95 struct kunit_resource *res; 96 int ret; 97 98 ret = platform_device_add(pdev); 99 if (ret) 100 return ret; 101 102 res = kunit_find_resource(test, kunit_platform_device_alloc_match, pdev); 103 if (res) { 104 /* 105 * Transfer the reference count of the platform device if it 106 * was allocated with kunit_platform_device_alloc(). In this 107 * case, calling platform_device_put() when the test exits from 108 * kunit_platform_device_alloc_exit() would lead to reference 109 * count underflow because platform_device_unregister_wrapper() 110 * calls platform_device_unregister() which also calls 111 * platform_device_put(). 112 * 113 * Usually callers transfer the refcount initialized in 114 * platform_device_alloc() to platform_device_add() by calling 115 * platform_device_unregister() when platform_device_add() 116 * succeeds or platform_device_put() when it fails. KUnit has to 117 * keep this straight by redirecting the free routine for the 118 * resource to the right function. Luckily this only has to 119 * account for the success scenario. 120 */ 121 res->free = kunit_platform_device_add_exit; 122 kunit_put_resource(res); 123 } else { 124 ret = kunit_add_action_or_reset(test, platform_device_unregister_wrapper, pdev); 125 if (ret) 126 return ret; 127 } 128 129 return 0; 130 } 131 EXPORT_SYMBOL_GPL(kunit_platform_device_add); 132 133 struct kunit_platform_device_probe_nb { 134 struct completion *x; 135 struct device *dev; 136 struct notifier_block nb; 137 }; 138 139 static int kunit_platform_device_probe_notify(struct notifier_block *nb, 140 unsigned long event, void *data) 141 { 142 struct kunit_platform_device_probe_nb *knb; 143 struct device *dev = data; 144 145 knb = container_of(nb, struct kunit_platform_device_probe_nb, nb); 146 if (event != BUS_NOTIFY_BOUND_DRIVER || knb->dev != dev) 147 return NOTIFY_DONE; 148 149 complete(knb->x); 150 151 return NOTIFY_OK; 152 } 153 154 static void kunit_platform_device_probe_nb_remove(void *nb) 155 { 156 bus_unregister_notifier(&platform_bus_type, nb); 157 } 158 159 /** 160 * kunit_platform_device_prepare_wait_for_probe() - Prepare a completion 161 * variable to wait for a platform device to probe 162 * @test: test context 163 * @pdev: platform device to prepare to wait for probe of 164 * @x: completion variable completed when @dev has probed 165 * 166 * Prepare a completion variable @x to wait for @pdev to probe. Waiting on the 167 * completion forces a preemption, allowing the platform driver to probe. 168 * 169 * Example 170 * 171 * .. code-block:: c 172 * 173 * static int kunit_platform_driver_probe(struct platform_device *pdev) 174 * { 175 * return 0; 176 * } 177 * 178 * static void kunit_platform_driver_test(struct kunit *test) 179 * { 180 * struct platform_device *pdev; 181 * struct platform_driver *pdrv; 182 * DECLARE_COMPLETION_ONSTACK(comp); 183 * 184 * pdev = kunit_platform_device_alloc(test, "kunit-platform", -1); 185 * KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); 186 * KUNIT_ASSERT_EQ(test, 0, kunit_platform_device_add(test, pdev)); 187 * 188 * pdrv = kunit_kzalloc(test, sizeof(*pdrv), GFP_KERNEL); 189 * KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdrv); 190 * 191 * pdrv->probe = kunit_platform_driver_probe; 192 * pdrv->driver.name = "kunit-platform"; 193 * pdrv->driver.owner = THIS_MODULE; 194 * 195 * KUNIT_ASSERT_EQ(test, 0, kunit_platform_device_prepare_wait_for_probe(test, pdev, &comp)); 196 * KUNIT_ASSERT_EQ(test, 0, kunit_platform_driver_register(test, pdrv)); 197 * 198 * KUNIT_EXPECT_NE(test, 0, wait_for_completion_timeout(&comp, 3 * HZ)); 199 * } 200 * 201 * Return: 0 on success, negative errno on failure. 202 */ 203 int kunit_platform_device_prepare_wait_for_probe(struct kunit *test, 204 struct platform_device *pdev, 205 struct completion *x) 206 { 207 struct device *dev = &pdev->dev; 208 struct kunit_platform_device_probe_nb *knb; 209 bool bound; 210 211 knb = kunit_kzalloc(test, sizeof(*knb), GFP_KERNEL); 212 if (!knb) 213 return -ENOMEM; 214 215 knb->nb.notifier_call = kunit_platform_device_probe_notify; 216 knb->dev = dev; 217 knb->x = x; 218 219 device_lock(dev); 220 bound = device_is_bound(dev); 221 if (bound) { 222 device_unlock(dev); 223 complete(x); 224 kunit_kfree(test, knb); 225 return 0; 226 } 227 228 bus_register_notifier(&platform_bus_type, &knb->nb); 229 device_unlock(&pdev->dev); 230 231 return kunit_add_action_or_reset(test, kunit_platform_device_probe_nb_remove, &knb->nb); 232 } 233 EXPORT_SYMBOL_GPL(kunit_platform_device_prepare_wait_for_probe); 234 235 KUNIT_DEFINE_ACTION_WRAPPER(platform_driver_unregister_wrapper, 236 platform_driver_unregister, struct platform_driver *); 237 /** 238 * kunit_platform_driver_register() - Register a KUnit test managed platform driver 239 * @test: test context 240 * @drv: platform driver to register 241 * 242 * Register a test managed platform driver. This allows callers to embed the 243 * @drv in a container structure and use container_of() in the probe function 244 * to pass information to KUnit tests. 245 * 246 * Example 247 * 248 * .. code-block:: c 249 * 250 * struct kunit_test_context { 251 * struct platform_driver pdrv; 252 * const char *data; 253 * }; 254 * 255 * static inline struct kunit_test_context * 256 * to_test_context(struct platform_device *pdev) 257 * { 258 * return container_of(to_platform_driver(pdev->dev.driver), 259 * struct kunit_test_context, 260 * pdrv); 261 * } 262 * 263 * static int kunit_platform_driver_probe(struct platform_device *pdev) 264 * { 265 * struct kunit_test_context *ctx; 266 * 267 * ctx = to_test_context(pdev); 268 * ctx->data = "test data"; 269 * 270 * return 0; 271 * } 272 * 273 * static void kunit_platform_driver_test(struct kunit *test) 274 * { 275 * struct kunit_test_context *ctx; 276 * 277 * ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); 278 * KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); 279 * 280 * ctx->pdrv.probe = kunit_platform_driver_probe; 281 * ctx->pdrv.driver.name = "kunit-platform"; 282 * ctx->pdrv.driver.owner = THIS_MODULE; 283 * 284 * KUNIT_EXPECT_EQ(test, 0, kunit_platform_driver_register(test, &ctx->pdrv)); 285 * <... wait for driver to probe ...> 286 * KUNIT_EXPECT_STREQ(test, ctx->data, "test data"); 287 * } 288 * 289 * Return: 0 on success, negative errno on failure. 290 */ 291 int kunit_platform_driver_register(struct kunit *test, 292 struct platform_driver *drv) 293 { 294 int ret; 295 296 ret = platform_driver_register(drv); 297 if (ret) 298 return ret; 299 300 return kunit_add_action_or_reset(test, platform_driver_unregister_wrapper, drv); 301 } 302 EXPORT_SYMBOL_GPL(kunit_platform_driver_register); 303
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.