brintos

brintos / linux-shallow public Read only

0
0
Text · 8.3 KiB · 0b518de Raw
303 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Test managed platform driver4 */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 14struct kunit_platform_device_alloc_params {15	const char *name;16	int id;17};18 19static 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 33static 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 device42 * @test: test context43 * @name: device name of platform device to alloc44 * @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 */50struct platform_device *51kunit_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, &params);62}63EXPORT_SYMBOL_GPL(kunit_platform_device_alloc);64 65static 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 72static bool73kunit_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 81KUNIT_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 device85 * @test: test context86 * @pdev: platform device to add87 *88 * Register a test managed platform device. The device is unregistered when the89 * test completes.90 *91 * Return: 0 on success, negative errno on failure.92 */93int 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 it106		 * was allocated with kunit_platform_device_alloc(). In this107		 * case, calling platform_device_put() when the test exits from108		 * kunit_platform_device_alloc_exit() would lead to reference109		 * count underflow because platform_device_unregister_wrapper()110		 * calls platform_device_unregister() which also calls111		 * platform_device_put().112		 *113		 * Usually callers transfer the refcount initialized in114		 * platform_device_alloc() to platform_device_add() by calling115		 * platform_device_unregister() when platform_device_add()116		 * succeeds or platform_device_put() when it fails. KUnit has to117		 * keep this straight by redirecting the free routine for the118		 * resource to the right function. Luckily this only has to119		 * 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}131EXPORT_SYMBOL_GPL(kunit_platform_device_add);132 133struct kunit_platform_device_probe_nb {134	struct completion *x;135	struct device *dev;136	struct notifier_block nb;137};138 139static 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 154static 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 completion161 * variable to wait for a platform device to probe162 * @test: test context163 * @pdev: platform device to prepare to wait for probe of164 * @x: completion variable completed when @dev has probed165 *166 * Prepare a completion variable @x to wait for @pdev to probe. Waiting on the167 * completion forces a preemption, allowing the platform driver to probe.168 *169 * Example170 *171 * .. code-block:: c172 *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 */203int 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}233EXPORT_SYMBOL_GPL(kunit_platform_device_prepare_wait_for_probe);234 235KUNIT_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 driver239 * @test: test context240 * @drv: platform driver to register241 *242 * Register a test managed platform driver. This allows callers to embed the243 * @drv in a container structure and use container_of() in the probe function244 * to pass information to KUnit tests.245 *246 * Example247 *248 * .. code-block:: c249 *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 */291int 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}302EXPORT_SYMBOL_GPL(kunit_platform_driver_register);303