Linux Audio

Check our new training course

Linux kernel drivers training

Mar 31-Apr 9, 2025, special US time zones
Register
Loading...
Note: File does not exist in v5.9.
  1/*
  2 * Self tests for device tree subsystem
  3 */
  4
  5#define pr_fmt(fmt) "### dt-test ### " fmt
  6
  7#include <linux/clk.h>
  8#include <linux/err.h>
  9#include <linux/errno.h>
 10#include <linux/module.h>
 11#include <linux/of.h>
 12#include <linux/of_irq.h>
 13#include <linux/of_platform.h>
 14#include <linux/list.h>
 15#include <linux/mutex.h>
 16#include <linux/slab.h>
 17#include <linux/device.h>
 18
 19static struct selftest_results {
 20	int passed;
 21	int failed;
 22} selftest_results;
 23
 24#define selftest(result, fmt, ...) { \
 25	if (!(result)) { \
 26		selftest_results.failed++; \
 27		pr_err("FAIL %s():%i " fmt, __func__, __LINE__, ##__VA_ARGS__); \
 28	} else { \
 29		selftest_results.passed++; \
 30		pr_debug("pass %s():%i\n", __func__, __LINE__); \
 31	} \
 32}
 33
 34static void __init of_selftest_dynamic(void)
 35{
 36	struct device_node *np;
 37	struct property *prop;
 38
 39	np = of_find_node_by_path("/testcase-data");
 40	if (!np) {
 41		pr_err("missing testcase data\n");
 42		return;
 43	}
 44
 45	/* Array of 4 properties for the purpose of testing */
 46	prop = kzalloc(sizeof(*prop) * 4, GFP_KERNEL);
 47	if (!prop) {
 48		selftest(0, "kzalloc() failed\n");
 49		return;
 50	}
 51
 52	/* Add a new property - should pass*/
 53	prop->name = "new-property";
 54	prop->value = "new-property-data";
 55	prop->length = strlen(prop->value);
 56	selftest(of_add_property(np, prop) == 0, "Adding a new property failed\n");
 57
 58	/* Try to add an existing property - should fail */
 59	prop++;
 60	prop->name = "new-property";
 61	prop->value = "new-property-data-should-fail";
 62	prop->length = strlen(prop->value);
 63	selftest(of_add_property(np, prop) != 0,
 64		 "Adding an existing property should have failed\n");
 65
 66	/* Try to modify an existing property - should pass */
 67	prop->value = "modify-property-data-should-pass";
 68	prop->length = strlen(prop->value);
 69	selftest(of_update_property(np, prop) == 0,
 70		 "Updating an existing property should have passed\n");
 71
 72	/* Try to modify non-existent property - should pass*/
 73	prop++;
 74	prop->name = "modify-property";
 75	prop->value = "modify-missing-property-data-should-pass";
 76	prop->length = strlen(prop->value);
 77	selftest(of_update_property(np, prop) == 0,
 78		 "Updating a missing property should have passed\n");
 79
 80	/* Remove property - should pass */
 81	selftest(of_remove_property(np, prop) == 0,
 82		 "Removing a property should have passed\n");
 83
 84	/* Adding very large property - should pass */
 85	prop++;
 86	prop->name = "large-property-PAGE_SIZEx8";
 87	prop->length = PAGE_SIZE * 8;
 88	prop->value = kzalloc(prop->length, GFP_KERNEL);
 89	selftest(prop->value != NULL, "Unable to allocate large buffer\n");
 90	if (prop->value)
 91		selftest(of_add_property(np, prop) == 0,
 92			 "Adding a large property should have passed\n");
 93}
 94
 95static void __init of_selftest_parse_phandle_with_args(void)
 96{
 97	struct device_node *np;
 98	struct of_phandle_args args;
 99	int i, rc;
100
101	np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
102	if (!np) {
103		pr_err("missing testcase data\n");
104		return;
105	}
106
107	rc = of_count_phandle_with_args(np, "phandle-list", "#phandle-cells");
108	selftest(rc == 7, "of_count_phandle_with_args() returned %i, expected 7\n", rc);
109
110	for (i = 0; i < 8; i++) {
111		bool passed = true;
112		rc = of_parse_phandle_with_args(np, "phandle-list",
113						"#phandle-cells", i, &args);
114
115		/* Test the values from tests-phandle.dtsi */
116		switch (i) {
117		case 0:
118			passed &= !rc;
119			passed &= (args.args_count == 1);
120			passed &= (args.args[0] == (i + 1));
121			break;
122		case 1:
123			passed &= !rc;
124			passed &= (args.args_count == 2);
125			passed &= (args.args[0] == (i + 1));
126			passed &= (args.args[1] == 0);
127			break;
128		case 2:
129			passed &= (rc == -ENOENT);
130			break;
131		case 3:
132			passed &= !rc;
133			passed &= (args.args_count == 3);
134			passed &= (args.args[0] == (i + 1));
135			passed &= (args.args[1] == 4);
136			passed &= (args.args[2] == 3);
137			break;
138		case 4:
139			passed &= !rc;
140			passed &= (args.args_count == 2);
141			passed &= (args.args[0] == (i + 1));
142			passed &= (args.args[1] == 100);
143			break;
144		case 5:
145			passed &= !rc;
146			passed &= (args.args_count == 0);
147			break;
148		case 6:
149			passed &= !rc;
150			passed &= (args.args_count == 1);
151			passed &= (args.args[0] == (i + 1));
152			break;
153		case 7:
154			passed &= (rc == -ENOENT);
155			break;
156		default:
157			passed = false;
158		}
159
160		selftest(passed, "index %i - data error on node %s rc=%i\n",
161			 i, args.np->full_name, rc);
162	}
163
164	/* Check for missing list property */
165	rc = of_parse_phandle_with_args(np, "phandle-list-missing",
166					"#phandle-cells", 0, &args);
167	selftest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
168	rc = of_count_phandle_with_args(np, "phandle-list-missing",
169					"#phandle-cells");
170	selftest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
171
172	/* Check for missing cells property */
173	rc = of_parse_phandle_with_args(np, "phandle-list",
174					"#phandle-cells-missing", 0, &args);
175	selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
176	rc = of_count_phandle_with_args(np, "phandle-list",
177					"#phandle-cells-missing");
178	selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
179
180	/* Check for bad phandle in list */
181	rc = of_parse_phandle_with_args(np, "phandle-list-bad-phandle",
182					"#phandle-cells", 0, &args);
183	selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
184	rc = of_count_phandle_with_args(np, "phandle-list-bad-phandle",
185					"#phandle-cells");
186	selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
187
188	/* Check for incorrectly formed argument list */
189	rc = of_parse_phandle_with_args(np, "phandle-list-bad-args",
190					"#phandle-cells", 1, &args);
191	selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
192	rc = of_count_phandle_with_args(np, "phandle-list-bad-args",
193					"#phandle-cells");
194	selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
195}
196
197static void __init of_selftest_property_match_string(void)
198{
199	struct device_node *np;
200	int rc;
201
202	np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
203	if (!np) {
204		pr_err("No testcase data in device tree\n");
205		return;
206	}
207
208	rc = of_property_match_string(np, "phandle-list-names", "first");
209	selftest(rc == 0, "first expected:0 got:%i\n", rc);
210	rc = of_property_match_string(np, "phandle-list-names", "second");
211	selftest(rc == 1, "second expected:0 got:%i\n", rc);
212	rc = of_property_match_string(np, "phandle-list-names", "third");
213	selftest(rc == 2, "third expected:0 got:%i\n", rc);
214	rc = of_property_match_string(np, "phandle-list-names", "fourth");
215	selftest(rc == -ENODATA, "unmatched string; rc=%i", rc);
216	rc = of_property_match_string(np, "missing-property", "blah");
217	selftest(rc == -EINVAL, "missing property; rc=%i", rc);
218	rc = of_property_match_string(np, "empty-property", "blah");
219	selftest(rc == -ENODATA, "empty property; rc=%i", rc);
220	rc = of_property_match_string(np, "unterminated-string", "blah");
221	selftest(rc == -EILSEQ, "unterminated string; rc=%i", rc);
222}
223
224static void __init of_selftest_parse_interrupts(void)
225{
226	struct device_node *np;
227	struct of_phandle_args args;
228	int i, rc;
229
230	np = of_find_node_by_path("/testcase-data/interrupts/interrupts0");
231	if (!np) {
232		pr_err("missing testcase data\n");
233		return;
234	}
235
236	for (i = 0; i < 4; i++) {
237		bool passed = true;
238		args.args_count = 0;
239		rc = of_irq_parse_one(np, i, &args);
240
241		passed &= !rc;
242		passed &= (args.args_count == 1);
243		passed &= (args.args[0] == (i + 1));
244
245		selftest(passed, "index %i - data error on node %s rc=%i\n",
246			 i, args.np->full_name, rc);
247	}
248	of_node_put(np);
249
250	np = of_find_node_by_path("/testcase-data/interrupts/interrupts1");
251	if (!np) {
252		pr_err("missing testcase data\n");
253		return;
254	}
255
256	for (i = 0; i < 4; i++) {
257		bool passed = true;
258		args.args_count = 0;
259		rc = of_irq_parse_one(np, i, &args);
260
261		/* Test the values from tests-phandle.dtsi */
262		switch (i) {
263		case 0:
264			passed &= !rc;
265			passed &= (args.args_count == 1);
266			passed &= (args.args[0] == 9);
267			break;
268		case 1:
269			passed &= !rc;
270			passed &= (args.args_count == 3);
271			passed &= (args.args[0] == 10);
272			passed &= (args.args[1] == 11);
273			passed &= (args.args[2] == 12);
274			break;
275		case 2:
276			passed &= !rc;
277			passed &= (args.args_count == 2);
278			passed &= (args.args[0] == 13);
279			passed &= (args.args[1] == 14);
280			break;
281		case 3:
282			passed &= !rc;
283			passed &= (args.args_count == 2);
284			passed &= (args.args[0] == 15);
285			passed &= (args.args[1] == 16);
286			break;
287		default:
288			passed = false;
289		}
290		selftest(passed, "index %i - data error on node %s rc=%i\n",
291			 i, args.np->full_name, rc);
292	}
293	of_node_put(np);
294}
295
296static void __init of_selftest_parse_interrupts_extended(void)
297{
298	struct device_node *np;
299	struct of_phandle_args args;
300	int i, rc;
301
302	np = of_find_node_by_path("/testcase-data/interrupts/interrupts-extended0");
303	if (!np) {
304		pr_err("missing testcase data\n");
305		return;
306	}
307
308	for (i = 0; i < 7; i++) {
309		bool passed = true;
310		rc = of_irq_parse_one(np, i, &args);
311
312		/* Test the values from tests-phandle.dtsi */
313		switch (i) {
314		case 0:
315			passed &= !rc;
316			passed &= (args.args_count == 1);
317			passed &= (args.args[0] == 1);
318			break;
319		case 1:
320			passed &= !rc;
321			passed &= (args.args_count == 3);
322			passed &= (args.args[0] == 2);
323			passed &= (args.args[1] == 3);
324			passed &= (args.args[2] == 4);
325			break;
326		case 2:
327			passed &= !rc;
328			passed &= (args.args_count == 2);
329			passed &= (args.args[0] == 5);
330			passed &= (args.args[1] == 6);
331			break;
332		case 3:
333			passed &= !rc;
334			passed &= (args.args_count == 1);
335			passed &= (args.args[0] == 9);
336			break;
337		case 4:
338			passed &= !rc;
339			passed &= (args.args_count == 3);
340			passed &= (args.args[0] == 10);
341			passed &= (args.args[1] == 11);
342			passed &= (args.args[2] == 12);
343			break;
344		case 5:
345			passed &= !rc;
346			passed &= (args.args_count == 2);
347			passed &= (args.args[0] == 13);
348			passed &= (args.args[1] == 14);
349			break;
350		case 6:
351			passed &= !rc;
352			passed &= (args.args_count == 1);
353			passed &= (args.args[0] == 15);
354			break;
355		default:
356			passed = false;
357		}
358
359		selftest(passed, "index %i - data error on node %s rc=%i\n",
360			 i, args.np->full_name, rc);
361	}
362	of_node_put(np);
363}
364
365static struct of_device_id match_node_table[] = {
366	{ .data = "A", .name = "name0", }, /* Name alone is lowest priority */
367	{ .data = "B", .type = "type1", }, /* followed by type alone */
368
369	{ .data = "Ca", .name = "name2", .type = "type1", }, /* followed by both together */
370	{ .data = "Cb", .name = "name2", }, /* Only match when type doesn't match */
371	{ .data = "Cc", .name = "name2", .type = "type2", },
372
373	{ .data = "E", .compatible = "compat3" },
374	{ .data = "G", .compatible = "compat2", },
375	{ .data = "H", .compatible = "compat2", .name = "name5", },
376	{ .data = "I", .compatible = "compat2", .type = "type1", },
377	{ .data = "J", .compatible = "compat2", .type = "type1", .name = "name8", },
378	{ .data = "K", .compatible = "compat2", .name = "name9", },
379	{}
380};
381
382static struct {
383	const char *path;
384	const char *data;
385} match_node_tests[] = {
386	{ .path = "/testcase-data/match-node/name0", .data = "A", },
387	{ .path = "/testcase-data/match-node/name1", .data = "B", },
388	{ .path = "/testcase-data/match-node/a/name2", .data = "Ca", },
389	{ .path = "/testcase-data/match-node/b/name2", .data = "Cb", },
390	{ .path = "/testcase-data/match-node/c/name2", .data = "Cc", },
391	{ .path = "/testcase-data/match-node/name3", .data = "E", },
392	{ .path = "/testcase-data/match-node/name4", .data = "G", },
393	{ .path = "/testcase-data/match-node/name5", .data = "H", },
394	{ .path = "/testcase-data/match-node/name6", .data = "G", },
395	{ .path = "/testcase-data/match-node/name7", .data = "I", },
396	{ .path = "/testcase-data/match-node/name8", .data = "J", },
397	{ .path = "/testcase-data/match-node/name9", .data = "K", },
398};
399
400static void __init of_selftest_match_node(void)
401{
402	struct device_node *np;
403	const struct of_device_id *match;
404	int i;
405
406	for (i = 0; i < ARRAY_SIZE(match_node_tests); i++) {
407		np = of_find_node_by_path(match_node_tests[i].path);
408		if (!np) {
409			selftest(0, "missing testcase node %s\n",
410				match_node_tests[i].path);
411			continue;
412		}
413
414		match = of_match_node(match_node_table, np);
415		if (!match) {
416			selftest(0, "%s didn't match anything\n",
417				match_node_tests[i].path);
418			continue;
419		}
420
421		if (strcmp(match->data, match_node_tests[i].data) != 0) {
422			selftest(0, "%s got wrong match. expected %s, got %s\n",
423				match_node_tests[i].path, match_node_tests[i].data,
424				(const char *)match->data);
425			continue;
426		}
427		selftest(1, "passed");
428	}
429}
430
431static void __init of_selftest_platform_populate(void)
432{
433	int irq;
434	struct device_node *np;
435	struct platform_device *pdev;
436
437	np = of_find_node_by_path("/testcase-data");
438	of_platform_populate(np, of_default_bus_match_table, NULL, NULL);
439
440	/* Test that a missing irq domain returns -EPROBE_DEFER */
441	np = of_find_node_by_path("/testcase-data/testcase-device1");
442	pdev = of_find_device_by_node(np);
443	if (!pdev)
444		selftest(0, "device 1 creation failed\n");
445	irq = platform_get_irq(pdev, 0);
446	if (irq != -EPROBE_DEFER)
447		selftest(0, "device deferred probe failed - %d\n", irq);
448
449	/* Test that a parsing failure does not return -EPROBE_DEFER */
450	np = of_find_node_by_path("/testcase-data/testcase-device2");
451	pdev = of_find_device_by_node(np);
452	if (!pdev)
453		selftest(0, "device 2 creation failed\n");
454	irq = platform_get_irq(pdev, 0);
455	if (irq >= 0 || irq == -EPROBE_DEFER)
456		selftest(0, "device parsing error failed - %d\n", irq);
457
458	selftest(1, "passed");
459}
460
461static int __init of_selftest(void)
462{
463	struct device_node *np;
464
465	np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
466	if (!np) {
467		pr_info("No testcase data in device tree; not running tests\n");
468		return 0;
469	}
470	of_node_put(np);
471
472	pr_info("start of selftest - you will see error messages\n");
473	of_selftest_dynamic();
474	of_selftest_parse_phandle_with_args();
475	of_selftest_property_match_string();
476	of_selftest_parse_interrupts();
477	of_selftest_parse_interrupts_extended();
478	of_selftest_match_node();
479	of_selftest_platform_populate();
480	pr_info("end of selftest - %i passed, %i failed\n",
481		selftest_results.passed, selftest_results.failed);
482	return 0;
483}
484late_initcall(of_selftest);