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 
13 struct 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 
platform_device_devm_init(struct kunit * test)21 static 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 
devm_device_action(void * ptr)35 static 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 
devm_put_device_action(void * ptr)43 static 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  */
platform_device_devm_register_unregister_test(struct kunit * test)58 static 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  */
platform_device_devm_register_get_unregister_with_devm_test(struct kunit * test)87 static 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 
fake_probe(struct platform_device * pdev)113 static 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 
123 static 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  */
probed_platform_device_devm_register_unregister_test(struct kunit * test)134 static 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  */
probed_platform_device_devm_register_get_unregister_with_devm_test(struct kunit * test)173 static 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 
209 static 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 
217 static 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 
platform_device_find_by_null_test(struct kunit * test)223 static 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 
246 static struct kunit_case platform_device_match_tests[] = {
247 	KUNIT_CASE(platform_device_find_by_null_test),
248 	{}
249 };
250 
251 static struct kunit_suite platform_device_match_test_suite = {
252 	.name = "platform-device-match",
253 	.test_cases = platform_device_match_tests,
254 };
255 
256 kunit_test_suites(
257 	&platform_device_devm_test_suite,
258 	&platform_device_match_test_suite,
259 );
260 
261 MODULE_DESCRIPTION("Test module for platform devices");
262 MODULE_AUTHOR("Maxime Ripard <[email protected]>");
263 MODULE_LICENSE("GPL");
264