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