File Index
Files and directories
Sign in
FILE

platform-device-test.c

File preview with syntax highlighting.

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