18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Self tests for device tree subsystem 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "### dt-test ### " fmt 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/memblock.h> 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/dma-direct.h> /* to test phys_to_dma/dma_to_phys */ 118c2ecf20Sopenharmony_ci#include <linux/err.h> 128c2ecf20Sopenharmony_ci#include <linux/errno.h> 138c2ecf20Sopenharmony_ci#include <linux/hashtable.h> 148c2ecf20Sopenharmony_ci#include <linux/libfdt.h> 158c2ecf20Sopenharmony_ci#include <linux/of.h> 168c2ecf20Sopenharmony_ci#include <linux/of_address.h> 178c2ecf20Sopenharmony_ci#include <linux/of_fdt.h> 188c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 198c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 208c2ecf20Sopenharmony_ci#include <linux/list.h> 218c2ecf20Sopenharmony_ci#include <linux/mutex.h> 228c2ecf20Sopenharmony_ci#include <linux/slab.h> 238c2ecf20Sopenharmony_ci#include <linux/device.h> 248c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <linux/i2c.h> 278c2ecf20Sopenharmony_ci#include <linux/i2c-mux.h> 288c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <linux/bitops.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "of_private.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic struct unittest_results { 358c2ecf20Sopenharmony_ci int passed; 368c2ecf20Sopenharmony_ci int failed; 378c2ecf20Sopenharmony_ci} unittest_results; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define unittest(result, fmt, ...) ({ \ 408c2ecf20Sopenharmony_ci bool failed = !(result); \ 418c2ecf20Sopenharmony_ci if (failed) { \ 428c2ecf20Sopenharmony_ci unittest_results.failed++; \ 438c2ecf20Sopenharmony_ci pr_err("FAIL %s():%i " fmt, __func__, __LINE__, ##__VA_ARGS__); \ 448c2ecf20Sopenharmony_ci } else { \ 458c2ecf20Sopenharmony_ci unittest_results.passed++; \ 468c2ecf20Sopenharmony_ci pr_debug("pass %s():%i\n", __func__, __LINE__); \ 478c2ecf20Sopenharmony_ci } \ 488c2ecf20Sopenharmony_ci failed; \ 498c2ecf20Sopenharmony_ci}) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#ifdef CONFIG_OF_KOBJ 528c2ecf20Sopenharmony_ci#define OF_KREF_READ(NODE) kref_read(&(NODE)->kobj.kref) 538c2ecf20Sopenharmony_ci#else 548c2ecf20Sopenharmony_ci#define OF_KREF_READ(NODE) 1 558c2ecf20Sopenharmony_ci#endif 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* 588c2ecf20Sopenharmony_ci * Expected message may have a message level other than KERN_INFO. 598c2ecf20Sopenharmony_ci * Print the expected message only if the current loglevel will allow 608c2ecf20Sopenharmony_ci * the actual message to print. 618c2ecf20Sopenharmony_ci * 628c2ecf20Sopenharmony_ci * Do not use EXPECT_BEGIN() or EXPECT_END() for messages generated by 638c2ecf20Sopenharmony_ci * pr_debug(). 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_ci#define EXPECT_BEGIN(level, fmt, ...) \ 668c2ecf20Sopenharmony_ci printk(level pr_fmt("EXPECT \\ : ") fmt, ##__VA_ARGS__) 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define EXPECT_END(level, fmt, ...) \ 698c2ecf20Sopenharmony_ci printk(level pr_fmt("EXPECT / : ") fmt, ##__VA_ARGS__) 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic void __init of_unittest_find_node_by_name(void) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct device_node *np; 748c2ecf20Sopenharmony_ci const char *options, *name; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci np = of_find_node_by_path("/testcase-data"); 778c2ecf20Sopenharmony_ci name = kasprintf(GFP_KERNEL, "%pOF", np); 788c2ecf20Sopenharmony_ci unittest(np && name && !strcmp("/testcase-data", name), 798c2ecf20Sopenharmony_ci "find /testcase-data failed\n"); 808c2ecf20Sopenharmony_ci of_node_put(np); 818c2ecf20Sopenharmony_ci kfree(name); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* Test if trailing '/' works */ 848c2ecf20Sopenharmony_ci np = of_find_node_by_path("/testcase-data/"); 858c2ecf20Sopenharmony_ci unittest(!np, "trailing '/' on /testcase-data/ should fail\n"); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a"); 888c2ecf20Sopenharmony_ci name = kasprintf(GFP_KERNEL, "%pOF", np); 898c2ecf20Sopenharmony_ci unittest(np && name && !strcmp("/testcase-data/phandle-tests/consumer-a", name), 908c2ecf20Sopenharmony_ci "find /testcase-data/phandle-tests/consumer-a failed\n"); 918c2ecf20Sopenharmony_ci of_node_put(np); 928c2ecf20Sopenharmony_ci kfree(name); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci np = of_find_node_by_path("testcase-alias"); 958c2ecf20Sopenharmony_ci name = kasprintf(GFP_KERNEL, "%pOF", np); 968c2ecf20Sopenharmony_ci unittest(np && name && !strcmp("/testcase-data", name), 978c2ecf20Sopenharmony_ci "find testcase-alias failed\n"); 988c2ecf20Sopenharmony_ci of_node_put(np); 998c2ecf20Sopenharmony_ci kfree(name); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* Test if trailing '/' works on aliases */ 1028c2ecf20Sopenharmony_ci np = of_find_node_by_path("testcase-alias/"); 1038c2ecf20Sopenharmony_ci unittest(!np, "trailing '/' on testcase-alias/ should fail\n"); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci np = of_find_node_by_path("testcase-alias/phandle-tests/consumer-a"); 1068c2ecf20Sopenharmony_ci name = kasprintf(GFP_KERNEL, "%pOF", np); 1078c2ecf20Sopenharmony_ci unittest(np && name && !strcmp("/testcase-data/phandle-tests/consumer-a", name), 1088c2ecf20Sopenharmony_ci "find testcase-alias/phandle-tests/consumer-a failed\n"); 1098c2ecf20Sopenharmony_ci of_node_put(np); 1108c2ecf20Sopenharmony_ci kfree(name); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci np = of_find_node_by_path("/testcase-data/missing-path"); 1138c2ecf20Sopenharmony_ci unittest(!np, "non-existent path returned node %pOF\n", np); 1148c2ecf20Sopenharmony_ci of_node_put(np); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci np = of_find_node_by_path("missing-alias"); 1178c2ecf20Sopenharmony_ci unittest(!np, "non-existent alias returned node %pOF\n", np); 1188c2ecf20Sopenharmony_ci of_node_put(np); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci np = of_find_node_by_path("testcase-alias/missing-path"); 1218c2ecf20Sopenharmony_ci unittest(!np, "non-existent alias with relative path returned node %pOF\n", np); 1228c2ecf20Sopenharmony_ci of_node_put(np); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci np = of_find_node_opts_by_path("/testcase-data:testoption", &options); 1258c2ecf20Sopenharmony_ci unittest(np && !strcmp("testoption", options), 1268c2ecf20Sopenharmony_ci "option path test failed\n"); 1278c2ecf20Sopenharmony_ci of_node_put(np); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci np = of_find_node_opts_by_path("/testcase-data:test/option", &options); 1308c2ecf20Sopenharmony_ci unittest(np && !strcmp("test/option", options), 1318c2ecf20Sopenharmony_ci "option path test, subcase #1 failed\n"); 1328c2ecf20Sopenharmony_ci of_node_put(np); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci np = of_find_node_opts_by_path("/testcase-data/testcase-device1:test/option", &options); 1358c2ecf20Sopenharmony_ci unittest(np && !strcmp("test/option", options), 1368c2ecf20Sopenharmony_ci "option path test, subcase #2 failed\n"); 1378c2ecf20Sopenharmony_ci of_node_put(np); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci np = of_find_node_opts_by_path("/testcase-data:testoption", NULL); 1408c2ecf20Sopenharmony_ci unittest(np, "NULL option path test failed\n"); 1418c2ecf20Sopenharmony_ci of_node_put(np); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci np = of_find_node_opts_by_path("testcase-alias:testaliasoption", 1448c2ecf20Sopenharmony_ci &options); 1458c2ecf20Sopenharmony_ci unittest(np && !strcmp("testaliasoption", options), 1468c2ecf20Sopenharmony_ci "option alias path test failed\n"); 1478c2ecf20Sopenharmony_ci of_node_put(np); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci np = of_find_node_opts_by_path("testcase-alias:test/alias/option", 1508c2ecf20Sopenharmony_ci &options); 1518c2ecf20Sopenharmony_ci unittest(np && !strcmp("test/alias/option", options), 1528c2ecf20Sopenharmony_ci "option alias path test, subcase #1 failed\n"); 1538c2ecf20Sopenharmony_ci of_node_put(np); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci np = of_find_node_opts_by_path("testcase-alias:testaliasoption", NULL); 1568c2ecf20Sopenharmony_ci unittest(np, "NULL option alias path test failed\n"); 1578c2ecf20Sopenharmony_ci of_node_put(np); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci options = "testoption"; 1608c2ecf20Sopenharmony_ci np = of_find_node_opts_by_path("testcase-alias", &options); 1618c2ecf20Sopenharmony_ci unittest(np && !options, "option clearing test failed\n"); 1628c2ecf20Sopenharmony_ci of_node_put(np); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci options = "testoption"; 1658c2ecf20Sopenharmony_ci np = of_find_node_opts_by_path("/", &options); 1668c2ecf20Sopenharmony_ci unittest(np && !options, "option clearing root node test failed\n"); 1678c2ecf20Sopenharmony_ci of_node_put(np); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic void __init of_unittest_dynamic(void) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct device_node *np; 1738c2ecf20Sopenharmony_ci struct property *prop; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci np = of_find_node_by_path("/testcase-data"); 1768c2ecf20Sopenharmony_ci if (!np) { 1778c2ecf20Sopenharmony_ci pr_err("missing testcase data\n"); 1788c2ecf20Sopenharmony_ci return; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci /* Array of 4 properties for the purpose of testing */ 1828c2ecf20Sopenharmony_ci prop = kcalloc(4, sizeof(*prop), GFP_KERNEL); 1838c2ecf20Sopenharmony_ci if (!prop) { 1848c2ecf20Sopenharmony_ci unittest(0, "kzalloc() failed\n"); 1858c2ecf20Sopenharmony_ci return; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* Add a new property - should pass*/ 1898c2ecf20Sopenharmony_ci prop->name = "new-property"; 1908c2ecf20Sopenharmony_ci prop->value = "new-property-data"; 1918c2ecf20Sopenharmony_ci prop->length = strlen(prop->value) + 1; 1928c2ecf20Sopenharmony_ci unittest(of_add_property(np, prop) == 0, "Adding a new property failed\n"); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* Try to add an existing property - should fail */ 1958c2ecf20Sopenharmony_ci prop++; 1968c2ecf20Sopenharmony_ci prop->name = "new-property"; 1978c2ecf20Sopenharmony_ci prop->value = "new-property-data-should-fail"; 1988c2ecf20Sopenharmony_ci prop->length = strlen(prop->value) + 1; 1998c2ecf20Sopenharmony_ci unittest(of_add_property(np, prop) != 0, 2008c2ecf20Sopenharmony_ci "Adding an existing property should have failed\n"); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* Try to modify an existing property - should pass */ 2038c2ecf20Sopenharmony_ci prop->value = "modify-property-data-should-pass"; 2048c2ecf20Sopenharmony_ci prop->length = strlen(prop->value) + 1; 2058c2ecf20Sopenharmony_ci unittest(of_update_property(np, prop) == 0, 2068c2ecf20Sopenharmony_ci "Updating an existing property should have passed\n"); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* Try to modify non-existent property - should pass*/ 2098c2ecf20Sopenharmony_ci prop++; 2108c2ecf20Sopenharmony_ci prop->name = "modify-property"; 2118c2ecf20Sopenharmony_ci prop->value = "modify-missing-property-data-should-pass"; 2128c2ecf20Sopenharmony_ci prop->length = strlen(prop->value) + 1; 2138c2ecf20Sopenharmony_ci unittest(of_update_property(np, prop) == 0, 2148c2ecf20Sopenharmony_ci "Updating a missing property should have passed\n"); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* Remove property - should pass */ 2178c2ecf20Sopenharmony_ci unittest(of_remove_property(np, prop) == 0, 2188c2ecf20Sopenharmony_ci "Removing a property should have passed\n"); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* Adding very large property - should pass */ 2218c2ecf20Sopenharmony_ci prop++; 2228c2ecf20Sopenharmony_ci prop->name = "large-property-PAGE_SIZEx8"; 2238c2ecf20Sopenharmony_ci prop->length = PAGE_SIZE * 8; 2248c2ecf20Sopenharmony_ci prop->value = kzalloc(prop->length, GFP_KERNEL); 2258c2ecf20Sopenharmony_ci unittest(prop->value != NULL, "Unable to allocate large buffer\n"); 2268c2ecf20Sopenharmony_ci if (prop->value) 2278c2ecf20Sopenharmony_ci unittest(of_add_property(np, prop) == 0, 2288c2ecf20Sopenharmony_ci "Adding a large property should have passed\n"); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int __init of_unittest_check_node_linkage(struct device_node *np) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct device_node *child; 2348c2ecf20Sopenharmony_ci int count = 0, rc; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci for_each_child_of_node(np, child) { 2378c2ecf20Sopenharmony_ci if (child->parent != np) { 2388c2ecf20Sopenharmony_ci pr_err("Child node %pOFn links to wrong parent %pOFn\n", 2398c2ecf20Sopenharmony_ci child, np); 2408c2ecf20Sopenharmony_ci rc = -EINVAL; 2418c2ecf20Sopenharmony_ci goto put_child; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci rc = of_unittest_check_node_linkage(child); 2458c2ecf20Sopenharmony_ci if (rc < 0) 2468c2ecf20Sopenharmony_ci goto put_child; 2478c2ecf20Sopenharmony_ci count += rc; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci return count + 1; 2518c2ecf20Sopenharmony_ciput_child: 2528c2ecf20Sopenharmony_ci of_node_put(child); 2538c2ecf20Sopenharmony_ci return rc; 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic void __init of_unittest_check_tree_linkage(void) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci struct device_node *np; 2598c2ecf20Sopenharmony_ci int allnode_count = 0, child_count; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (!of_root) 2628c2ecf20Sopenharmony_ci return; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci for_each_of_allnodes(np) 2658c2ecf20Sopenharmony_ci allnode_count++; 2668c2ecf20Sopenharmony_ci child_count = of_unittest_check_node_linkage(of_root); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci unittest(child_count > 0, "Device node data structure is corrupted\n"); 2698c2ecf20Sopenharmony_ci unittest(child_count == allnode_count, 2708c2ecf20Sopenharmony_ci "allnodes list size (%i) doesn't match sibling lists size (%i)\n", 2718c2ecf20Sopenharmony_ci allnode_count, child_count); 2728c2ecf20Sopenharmony_ci pr_debug("allnodes list size (%i); sibling lists size (%i)\n", allnode_count, child_count); 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic void __init of_unittest_printf_one(struct device_node *np, const char *fmt, 2768c2ecf20Sopenharmony_ci const char *expected) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci unsigned char *buf; 2798c2ecf20Sopenharmony_ci int buf_size; 2808c2ecf20Sopenharmony_ci int size, i; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci buf_size = strlen(expected) + 10; 2838c2ecf20Sopenharmony_ci buf = kmalloc(buf_size, GFP_KERNEL); 2848c2ecf20Sopenharmony_ci if (!buf) 2858c2ecf20Sopenharmony_ci return; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* Baseline; check conversion with a large size limit */ 2888c2ecf20Sopenharmony_ci memset(buf, 0xff, buf_size); 2898c2ecf20Sopenharmony_ci size = snprintf(buf, buf_size - 2, fmt, np); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* use strcmp() instead of strncmp() here to be absolutely sure strings match */ 2928c2ecf20Sopenharmony_ci unittest((strcmp(buf, expected) == 0) && (buf[size+1] == 0xff), 2938c2ecf20Sopenharmony_ci "sprintf failed; fmt='%s' expected='%s' rslt='%s'\n", 2948c2ecf20Sopenharmony_ci fmt, expected, buf); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* Make sure length limits work */ 2978c2ecf20Sopenharmony_ci size++; 2988c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++, size--) { 2998c2ecf20Sopenharmony_ci /* Clear the buffer, and make sure it works correctly still */ 3008c2ecf20Sopenharmony_ci memset(buf, 0xff, buf_size); 3018c2ecf20Sopenharmony_ci snprintf(buf, size+1, fmt, np); 3028c2ecf20Sopenharmony_ci unittest(strncmp(buf, expected, size) == 0 && (buf[size+1] == 0xff), 3038c2ecf20Sopenharmony_ci "snprintf failed; size=%i fmt='%s' expected='%s' rslt='%s'\n", 3048c2ecf20Sopenharmony_ci size, fmt, expected, buf); 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci kfree(buf); 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic void __init of_unittest_printf(void) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct device_node *np; 3128c2ecf20Sopenharmony_ci const char *full_name = "/testcase-data/platform-tests/test-device@1/dev@100"; 3138c2ecf20Sopenharmony_ci char phandle_str[16] = ""; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci np = of_find_node_by_path(full_name); 3168c2ecf20Sopenharmony_ci if (!np) { 3178c2ecf20Sopenharmony_ci unittest(np, "testcase data missing\n"); 3188c2ecf20Sopenharmony_ci return; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci num_to_str(phandle_str, sizeof(phandle_str), np->phandle, 0); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci of_unittest_printf_one(np, "%pOF", full_name); 3248c2ecf20Sopenharmony_ci of_unittest_printf_one(np, "%pOFf", full_name); 3258c2ecf20Sopenharmony_ci of_unittest_printf_one(np, "%pOFn", "dev"); 3268c2ecf20Sopenharmony_ci of_unittest_printf_one(np, "%2pOFn", "dev"); 3278c2ecf20Sopenharmony_ci of_unittest_printf_one(np, "%5pOFn", " dev"); 3288c2ecf20Sopenharmony_ci of_unittest_printf_one(np, "%pOFnc", "dev:test-sub-device"); 3298c2ecf20Sopenharmony_ci of_unittest_printf_one(np, "%pOFp", phandle_str); 3308c2ecf20Sopenharmony_ci of_unittest_printf_one(np, "%pOFP", "dev@100"); 3318c2ecf20Sopenharmony_ci of_unittest_printf_one(np, "ABC %pOFP ABC", "ABC dev@100 ABC"); 3328c2ecf20Sopenharmony_ci of_unittest_printf_one(np, "%10pOFP", " dev@100"); 3338c2ecf20Sopenharmony_ci of_unittest_printf_one(np, "%-10pOFP", "dev@100 "); 3348c2ecf20Sopenharmony_ci of_unittest_printf_one(of_root, "%pOFP", "/"); 3358c2ecf20Sopenharmony_ci of_unittest_printf_one(np, "%pOFF", "----"); 3368c2ecf20Sopenharmony_ci of_unittest_printf_one(np, "%pOFPF", "dev@100:----"); 3378c2ecf20Sopenharmony_ci of_unittest_printf_one(np, "%pOFPFPc", "dev@100:----:dev@100:test-sub-device"); 3388c2ecf20Sopenharmony_ci of_unittest_printf_one(np, "%pOFc", "test-sub-device"); 3398c2ecf20Sopenharmony_ci of_unittest_printf_one(np, "%pOFC", 3408c2ecf20Sopenharmony_ci "\"test-sub-device\",\"test-compat2\",\"test-compat3\""); 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistruct node_hash { 3448c2ecf20Sopenharmony_ci struct hlist_node node; 3458c2ecf20Sopenharmony_ci struct device_node *np; 3468c2ecf20Sopenharmony_ci}; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic DEFINE_HASHTABLE(phandle_ht, 8); 3498c2ecf20Sopenharmony_cistatic void __init of_unittest_check_phandles(void) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct device_node *np; 3528c2ecf20Sopenharmony_ci struct node_hash *nh; 3538c2ecf20Sopenharmony_ci struct hlist_node *tmp; 3548c2ecf20Sopenharmony_ci int i, dup_count = 0, phandle_count = 0; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci for_each_of_allnodes(np) { 3578c2ecf20Sopenharmony_ci if (!np->phandle) 3588c2ecf20Sopenharmony_ci continue; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci hash_for_each_possible(phandle_ht, nh, node, np->phandle) { 3618c2ecf20Sopenharmony_ci if (nh->np->phandle == np->phandle) { 3628c2ecf20Sopenharmony_ci pr_info("Duplicate phandle! %i used by %pOF and %pOF\n", 3638c2ecf20Sopenharmony_ci np->phandle, nh->np, np); 3648c2ecf20Sopenharmony_ci dup_count++; 3658c2ecf20Sopenharmony_ci break; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci nh = kzalloc(sizeof(*nh), GFP_KERNEL); 3708c2ecf20Sopenharmony_ci if (!nh) 3718c2ecf20Sopenharmony_ci return; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci nh->np = np; 3748c2ecf20Sopenharmony_ci hash_add(phandle_ht, &nh->node, np->phandle); 3758c2ecf20Sopenharmony_ci phandle_count++; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci unittest(dup_count == 0, "Found %i duplicates in %i phandles\n", 3788c2ecf20Sopenharmony_ci dup_count, phandle_count); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* Clean up */ 3818c2ecf20Sopenharmony_ci hash_for_each_safe(phandle_ht, i, tmp, nh, node) { 3828c2ecf20Sopenharmony_ci hash_del(&nh->node); 3838c2ecf20Sopenharmony_ci kfree(nh); 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic void __init of_unittest_parse_phandle_with_args(void) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci struct device_node *np; 3908c2ecf20Sopenharmony_ci struct of_phandle_args args; 3918c2ecf20Sopenharmony_ci int i, rc; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a"); 3948c2ecf20Sopenharmony_ci if (!np) { 3958c2ecf20Sopenharmony_ci pr_err("missing testcase data\n"); 3968c2ecf20Sopenharmony_ci return; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci rc = of_count_phandle_with_args(np, "phandle-list", "#phandle-cells"); 4008c2ecf20Sopenharmony_ci unittest(rc == 7, "of_count_phandle_with_args() returned %i, expected 7\n", rc); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 4038c2ecf20Sopenharmony_ci bool passed = true; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 4068c2ecf20Sopenharmony_ci rc = of_parse_phandle_with_args(np, "phandle-list", 4078c2ecf20Sopenharmony_ci "#phandle-cells", i, &args); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci /* Test the values from tests-phandle.dtsi */ 4108c2ecf20Sopenharmony_ci switch (i) { 4118c2ecf20Sopenharmony_ci case 0: 4128c2ecf20Sopenharmony_ci passed &= !rc; 4138c2ecf20Sopenharmony_ci passed &= (args.args_count == 1); 4148c2ecf20Sopenharmony_ci passed &= (args.args[0] == (i + 1)); 4158c2ecf20Sopenharmony_ci break; 4168c2ecf20Sopenharmony_ci case 1: 4178c2ecf20Sopenharmony_ci passed &= !rc; 4188c2ecf20Sopenharmony_ci passed &= (args.args_count == 2); 4198c2ecf20Sopenharmony_ci passed &= (args.args[0] == (i + 1)); 4208c2ecf20Sopenharmony_ci passed &= (args.args[1] == 0); 4218c2ecf20Sopenharmony_ci break; 4228c2ecf20Sopenharmony_ci case 2: 4238c2ecf20Sopenharmony_ci passed &= (rc == -ENOENT); 4248c2ecf20Sopenharmony_ci break; 4258c2ecf20Sopenharmony_ci case 3: 4268c2ecf20Sopenharmony_ci passed &= !rc; 4278c2ecf20Sopenharmony_ci passed &= (args.args_count == 3); 4288c2ecf20Sopenharmony_ci passed &= (args.args[0] == (i + 1)); 4298c2ecf20Sopenharmony_ci passed &= (args.args[1] == 4); 4308c2ecf20Sopenharmony_ci passed &= (args.args[2] == 3); 4318c2ecf20Sopenharmony_ci break; 4328c2ecf20Sopenharmony_ci case 4: 4338c2ecf20Sopenharmony_ci passed &= !rc; 4348c2ecf20Sopenharmony_ci passed &= (args.args_count == 2); 4358c2ecf20Sopenharmony_ci passed &= (args.args[0] == (i + 1)); 4368c2ecf20Sopenharmony_ci passed &= (args.args[1] == 100); 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci case 5: 4398c2ecf20Sopenharmony_ci passed &= !rc; 4408c2ecf20Sopenharmony_ci passed &= (args.args_count == 0); 4418c2ecf20Sopenharmony_ci break; 4428c2ecf20Sopenharmony_ci case 6: 4438c2ecf20Sopenharmony_ci passed &= !rc; 4448c2ecf20Sopenharmony_ci passed &= (args.args_count == 1); 4458c2ecf20Sopenharmony_ci passed &= (args.args[0] == (i + 1)); 4468c2ecf20Sopenharmony_ci break; 4478c2ecf20Sopenharmony_ci case 7: 4488c2ecf20Sopenharmony_ci passed &= (rc == -ENOENT); 4498c2ecf20Sopenharmony_ci break; 4508c2ecf20Sopenharmony_ci default: 4518c2ecf20Sopenharmony_ci passed = false; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci unittest(passed, "index %i - data error on node %pOF rc=%i\n", 4558c2ecf20Sopenharmony_ci i, args.np, rc); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (rc == 0) 4588c2ecf20Sopenharmony_ci of_node_put(args.np); 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* Check for missing list property */ 4628c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 4638c2ecf20Sopenharmony_ci rc = of_parse_phandle_with_args(np, "phandle-list-missing", 4648c2ecf20Sopenharmony_ci "#phandle-cells", 0, &args); 4658c2ecf20Sopenharmony_ci unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc); 4668c2ecf20Sopenharmony_ci rc = of_count_phandle_with_args(np, "phandle-list-missing", 4678c2ecf20Sopenharmony_ci "#phandle-cells"); 4688c2ecf20Sopenharmony_ci unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* Check for missing cells property */ 4718c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 4748c2ecf20Sopenharmony_ci "OF: /testcase-data/phandle-tests/consumer-a: could not get #phandle-cells-missing for /testcase-data/phandle-tests/provider1"); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci rc = of_parse_phandle_with_args(np, "phandle-list", 4778c2ecf20Sopenharmony_ci "#phandle-cells-missing", 0, &args); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 4808c2ecf20Sopenharmony_ci "OF: /testcase-data/phandle-tests/consumer-a: could not get #phandle-cells-missing for /testcase-data/phandle-tests/provider1"); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 4858c2ecf20Sopenharmony_ci "OF: /testcase-data/phandle-tests/consumer-a: could not get #phandle-cells-missing for /testcase-data/phandle-tests/provider1"); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci rc = of_count_phandle_with_args(np, "phandle-list", 4888c2ecf20Sopenharmony_ci "#phandle-cells-missing"); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 4918c2ecf20Sopenharmony_ci "OF: /testcase-data/phandle-tests/consumer-a: could not get #phandle-cells-missing for /testcase-data/phandle-tests/provider1"); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci /* Check for bad phandle in list */ 4968c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 4998c2ecf20Sopenharmony_ci "OF: /testcase-data/phandle-tests/consumer-a: could not find phandle"); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci rc = of_parse_phandle_with_args(np, "phandle-list-bad-phandle", 5028c2ecf20Sopenharmony_ci "#phandle-cells", 0, &args); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 5058c2ecf20Sopenharmony_ci "OF: /testcase-data/phandle-tests/consumer-a: could not find phandle"); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 5108c2ecf20Sopenharmony_ci "OF: /testcase-data/phandle-tests/consumer-a: could not find phandle"); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci rc = of_count_phandle_with_args(np, "phandle-list-bad-phandle", 5138c2ecf20Sopenharmony_ci "#phandle-cells"); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 5168c2ecf20Sopenharmony_ci "OF: /testcase-data/phandle-tests/consumer-a: could not find phandle"); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci /* Check for incorrectly formed argument list */ 5218c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 5248c2ecf20Sopenharmony_ci "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found -1"); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci rc = of_parse_phandle_with_args(np, "phandle-list-bad-args", 5278c2ecf20Sopenharmony_ci "#phandle-cells", 1, &args); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 5308c2ecf20Sopenharmony_ci "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found -1"); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 5358c2ecf20Sopenharmony_ci "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found -1"); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci rc = of_count_phandle_with_args(np, "phandle-list-bad-args", 5388c2ecf20Sopenharmony_ci "#phandle-cells"); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 5418c2ecf20Sopenharmony_ci "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found -1"); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic void __init of_unittest_parse_phandle_with_args_map(void) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct device_node *np, *p[6] = {}; 5498c2ecf20Sopenharmony_ci struct of_phandle_args args; 5508c2ecf20Sopenharmony_ci unsigned int prefs[6]; 5518c2ecf20Sopenharmony_ci int i, rc; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-b"); 5548c2ecf20Sopenharmony_ci if (!np) { 5558c2ecf20Sopenharmony_ci pr_err("missing testcase data\n"); 5568c2ecf20Sopenharmony_ci return; 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci p[0] = of_find_node_by_path("/testcase-data/phandle-tests/provider0"); 5608c2ecf20Sopenharmony_ci p[1] = of_find_node_by_path("/testcase-data/phandle-tests/provider1"); 5618c2ecf20Sopenharmony_ci p[2] = of_find_node_by_path("/testcase-data/phandle-tests/provider2"); 5628c2ecf20Sopenharmony_ci p[3] = of_find_node_by_path("/testcase-data/phandle-tests/provider3"); 5638c2ecf20Sopenharmony_ci p[4] = of_find_node_by_path("/testcase-data/phandle-tests/provider4"); 5648c2ecf20Sopenharmony_ci p[5] = of_find_node_by_path("/testcase-data/phandle-tests/provider5"); 5658c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(p); ++i) { 5668c2ecf20Sopenharmony_ci if (!p[i]) { 5678c2ecf20Sopenharmony_ci pr_err("missing testcase data\n"); 5688c2ecf20Sopenharmony_ci return; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci prefs[i] = OF_KREF_READ(p[i]); 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci rc = of_count_phandle_with_args(np, "phandle-list", "#phandle-cells"); 5748c2ecf20Sopenharmony_ci unittest(rc == 8, "of_count_phandle_with_args() returned %i, expected 8\n", rc); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci for (i = 0; i < 9; i++) { 5778c2ecf20Sopenharmony_ci bool passed = true; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 5808c2ecf20Sopenharmony_ci rc = of_parse_phandle_with_args_map(np, "phandle-list", 5818c2ecf20Sopenharmony_ci "phandle", i, &args); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci /* Test the values from tests-phandle.dtsi */ 5848c2ecf20Sopenharmony_ci switch (i) { 5858c2ecf20Sopenharmony_ci case 0: 5868c2ecf20Sopenharmony_ci passed &= !rc; 5878c2ecf20Sopenharmony_ci passed &= (args.np == p[1]); 5888c2ecf20Sopenharmony_ci passed &= (args.args_count == 1); 5898c2ecf20Sopenharmony_ci passed &= (args.args[0] == 1); 5908c2ecf20Sopenharmony_ci break; 5918c2ecf20Sopenharmony_ci case 1: 5928c2ecf20Sopenharmony_ci passed &= !rc; 5938c2ecf20Sopenharmony_ci passed &= (args.np == p[3]); 5948c2ecf20Sopenharmony_ci passed &= (args.args_count == 3); 5958c2ecf20Sopenharmony_ci passed &= (args.args[0] == 2); 5968c2ecf20Sopenharmony_ci passed &= (args.args[1] == 5); 5978c2ecf20Sopenharmony_ci passed &= (args.args[2] == 3); 5988c2ecf20Sopenharmony_ci break; 5998c2ecf20Sopenharmony_ci case 2: 6008c2ecf20Sopenharmony_ci passed &= (rc == -ENOENT); 6018c2ecf20Sopenharmony_ci break; 6028c2ecf20Sopenharmony_ci case 3: 6038c2ecf20Sopenharmony_ci passed &= !rc; 6048c2ecf20Sopenharmony_ci passed &= (args.np == p[0]); 6058c2ecf20Sopenharmony_ci passed &= (args.args_count == 0); 6068c2ecf20Sopenharmony_ci break; 6078c2ecf20Sopenharmony_ci case 4: 6088c2ecf20Sopenharmony_ci passed &= !rc; 6098c2ecf20Sopenharmony_ci passed &= (args.np == p[1]); 6108c2ecf20Sopenharmony_ci passed &= (args.args_count == 1); 6118c2ecf20Sopenharmony_ci passed &= (args.args[0] == 3); 6128c2ecf20Sopenharmony_ci break; 6138c2ecf20Sopenharmony_ci case 5: 6148c2ecf20Sopenharmony_ci passed &= !rc; 6158c2ecf20Sopenharmony_ci passed &= (args.np == p[0]); 6168c2ecf20Sopenharmony_ci passed &= (args.args_count == 0); 6178c2ecf20Sopenharmony_ci break; 6188c2ecf20Sopenharmony_ci case 6: 6198c2ecf20Sopenharmony_ci passed &= !rc; 6208c2ecf20Sopenharmony_ci passed &= (args.np == p[2]); 6218c2ecf20Sopenharmony_ci passed &= (args.args_count == 2); 6228c2ecf20Sopenharmony_ci passed &= (args.args[0] == 15); 6238c2ecf20Sopenharmony_ci passed &= (args.args[1] == 0x20); 6248c2ecf20Sopenharmony_ci break; 6258c2ecf20Sopenharmony_ci case 7: 6268c2ecf20Sopenharmony_ci passed &= !rc; 6278c2ecf20Sopenharmony_ci passed &= (args.np == p[3]); 6288c2ecf20Sopenharmony_ci passed &= (args.args_count == 3); 6298c2ecf20Sopenharmony_ci passed &= (args.args[0] == 2); 6308c2ecf20Sopenharmony_ci passed &= (args.args[1] == 5); 6318c2ecf20Sopenharmony_ci passed &= (args.args[2] == 3); 6328c2ecf20Sopenharmony_ci break; 6338c2ecf20Sopenharmony_ci case 8: 6348c2ecf20Sopenharmony_ci passed &= (rc == -ENOENT); 6358c2ecf20Sopenharmony_ci break; 6368c2ecf20Sopenharmony_ci default: 6378c2ecf20Sopenharmony_ci passed = false; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci unittest(passed, "index %i - data error on node %s rc=%i\n", 6418c2ecf20Sopenharmony_ci i, args.np->full_name, rc); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if (rc == 0) 6448c2ecf20Sopenharmony_ci of_node_put(args.np); 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* Check for missing list property */ 6488c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 6498c2ecf20Sopenharmony_ci rc = of_parse_phandle_with_args_map(np, "phandle-list-missing", 6508c2ecf20Sopenharmony_ci "phandle", 0, &args); 6518c2ecf20Sopenharmony_ci unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci /* Check for missing cells,map,mask property */ 6548c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 6578c2ecf20Sopenharmony_ci "OF: /testcase-data/phandle-tests/consumer-b: could not get #phandle-missing-cells for /testcase-data/phandle-tests/provider1"); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci rc = of_parse_phandle_with_args_map(np, "phandle-list", 6608c2ecf20Sopenharmony_ci "phandle-missing", 0, &args); 6618c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 6628c2ecf20Sopenharmony_ci "OF: /testcase-data/phandle-tests/consumer-b: could not get #phandle-missing-cells for /testcase-data/phandle-tests/provider1"); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci /* Check for bad phandle in list */ 6678c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 6708c2ecf20Sopenharmony_ci "OF: /testcase-data/phandle-tests/consumer-b: could not find phandle"); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci rc = of_parse_phandle_with_args_map(np, "phandle-list-bad-phandle", 6738c2ecf20Sopenharmony_ci "phandle", 0, &args); 6748c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 6758c2ecf20Sopenharmony_ci "OF: /testcase-data/phandle-tests/consumer-b: could not find phandle"); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci /* Check for incorrectly formed argument list */ 6808c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 6838c2ecf20Sopenharmony_ci "OF: /testcase-data/phandle-tests/consumer-b: #phandle-cells = 2 found -1"); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci rc = of_parse_phandle_with_args_map(np, "phandle-list-bad-args", 6868c2ecf20Sopenharmony_ci "phandle", 1, &args); 6878c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 6888c2ecf20Sopenharmony_ci "OF: /testcase-data/phandle-tests/consumer-b: #phandle-cells = 2 found -1"); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(p); ++i) { 6938c2ecf20Sopenharmony_ci unittest(prefs[i] == OF_KREF_READ(p[i]), 6948c2ecf20Sopenharmony_ci "provider%d: expected:%d got:%d\n", 6958c2ecf20Sopenharmony_ci i, prefs[i], OF_KREF_READ(p[i])); 6968c2ecf20Sopenharmony_ci of_node_put(p[i]); 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cistatic void __init of_unittest_property_string(void) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci const char *strings[4]; 7038c2ecf20Sopenharmony_ci struct device_node *np; 7048c2ecf20Sopenharmony_ci int rc; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a"); 7078c2ecf20Sopenharmony_ci if (!np) { 7088c2ecf20Sopenharmony_ci pr_err("No testcase data in device tree\n"); 7098c2ecf20Sopenharmony_ci return; 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci rc = of_property_match_string(np, "phandle-list-names", "first"); 7138c2ecf20Sopenharmony_ci unittest(rc == 0, "first expected:0 got:%i\n", rc); 7148c2ecf20Sopenharmony_ci rc = of_property_match_string(np, "phandle-list-names", "second"); 7158c2ecf20Sopenharmony_ci unittest(rc == 1, "second expected:1 got:%i\n", rc); 7168c2ecf20Sopenharmony_ci rc = of_property_match_string(np, "phandle-list-names", "third"); 7178c2ecf20Sopenharmony_ci unittest(rc == 2, "third expected:2 got:%i\n", rc); 7188c2ecf20Sopenharmony_ci rc = of_property_match_string(np, "phandle-list-names", "fourth"); 7198c2ecf20Sopenharmony_ci unittest(rc == -ENODATA, "unmatched string; rc=%i\n", rc); 7208c2ecf20Sopenharmony_ci rc = of_property_match_string(np, "missing-property", "blah"); 7218c2ecf20Sopenharmony_ci unittest(rc == -EINVAL, "missing property; rc=%i\n", rc); 7228c2ecf20Sopenharmony_ci rc = of_property_match_string(np, "empty-property", "blah"); 7238c2ecf20Sopenharmony_ci unittest(rc == -ENODATA, "empty property; rc=%i\n", rc); 7248c2ecf20Sopenharmony_ci rc = of_property_match_string(np, "unterminated-string", "blah"); 7258c2ecf20Sopenharmony_ci unittest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* of_property_count_strings() tests */ 7288c2ecf20Sopenharmony_ci rc = of_property_count_strings(np, "string-property"); 7298c2ecf20Sopenharmony_ci unittest(rc == 1, "Incorrect string count; rc=%i\n", rc); 7308c2ecf20Sopenharmony_ci rc = of_property_count_strings(np, "phandle-list-names"); 7318c2ecf20Sopenharmony_ci unittest(rc == 3, "Incorrect string count; rc=%i\n", rc); 7328c2ecf20Sopenharmony_ci rc = of_property_count_strings(np, "unterminated-string"); 7338c2ecf20Sopenharmony_ci unittest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc); 7348c2ecf20Sopenharmony_ci rc = of_property_count_strings(np, "unterminated-string-list"); 7358c2ecf20Sopenharmony_ci unittest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci /* of_property_read_string_index() tests */ 7388c2ecf20Sopenharmony_ci rc = of_property_read_string_index(np, "string-property", 0, strings); 7398c2ecf20Sopenharmony_ci unittest(rc == 0 && !strcmp(strings[0], "foobar"), "of_property_read_string_index() failure; rc=%i\n", rc); 7408c2ecf20Sopenharmony_ci strings[0] = NULL; 7418c2ecf20Sopenharmony_ci rc = of_property_read_string_index(np, "string-property", 1, strings); 7428c2ecf20Sopenharmony_ci unittest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); 7438c2ecf20Sopenharmony_ci rc = of_property_read_string_index(np, "phandle-list-names", 0, strings); 7448c2ecf20Sopenharmony_ci unittest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc); 7458c2ecf20Sopenharmony_ci rc = of_property_read_string_index(np, "phandle-list-names", 1, strings); 7468c2ecf20Sopenharmony_ci unittest(rc == 0 && !strcmp(strings[0], "second"), "of_property_read_string_index() failure; rc=%i\n", rc); 7478c2ecf20Sopenharmony_ci rc = of_property_read_string_index(np, "phandle-list-names", 2, strings); 7488c2ecf20Sopenharmony_ci unittest(rc == 0 && !strcmp(strings[0], "third"), "of_property_read_string_index() failure; rc=%i\n", rc); 7498c2ecf20Sopenharmony_ci strings[0] = NULL; 7508c2ecf20Sopenharmony_ci rc = of_property_read_string_index(np, "phandle-list-names", 3, strings); 7518c2ecf20Sopenharmony_ci unittest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); 7528c2ecf20Sopenharmony_ci strings[0] = NULL; 7538c2ecf20Sopenharmony_ci rc = of_property_read_string_index(np, "unterminated-string", 0, strings); 7548c2ecf20Sopenharmony_ci unittest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); 7558c2ecf20Sopenharmony_ci rc = of_property_read_string_index(np, "unterminated-string-list", 0, strings); 7568c2ecf20Sopenharmony_ci unittest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc); 7578c2ecf20Sopenharmony_ci strings[0] = NULL; 7588c2ecf20Sopenharmony_ci rc = of_property_read_string_index(np, "unterminated-string-list", 2, strings); /* should fail */ 7598c2ecf20Sopenharmony_ci unittest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); 7608c2ecf20Sopenharmony_ci strings[1] = NULL; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci /* of_property_read_string_array() tests */ 7638c2ecf20Sopenharmony_ci rc = of_property_read_string_array(np, "string-property", strings, 4); 7648c2ecf20Sopenharmony_ci unittest(rc == 1, "Incorrect string count; rc=%i\n", rc); 7658c2ecf20Sopenharmony_ci rc = of_property_read_string_array(np, "phandle-list-names", strings, 4); 7668c2ecf20Sopenharmony_ci unittest(rc == 3, "Incorrect string count; rc=%i\n", rc); 7678c2ecf20Sopenharmony_ci rc = of_property_read_string_array(np, "unterminated-string", strings, 4); 7688c2ecf20Sopenharmony_ci unittest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc); 7698c2ecf20Sopenharmony_ci /* -- An incorrectly formed string should cause a failure */ 7708c2ecf20Sopenharmony_ci rc = of_property_read_string_array(np, "unterminated-string-list", strings, 4); 7718c2ecf20Sopenharmony_ci unittest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc); 7728c2ecf20Sopenharmony_ci /* -- parsing the correctly formed strings should still work: */ 7738c2ecf20Sopenharmony_ci strings[2] = NULL; 7748c2ecf20Sopenharmony_ci rc = of_property_read_string_array(np, "unterminated-string-list", strings, 2); 7758c2ecf20Sopenharmony_ci unittest(rc == 2 && strings[2] == NULL, "of_property_read_string_array() failure; rc=%i\n", rc); 7768c2ecf20Sopenharmony_ci strings[1] = NULL; 7778c2ecf20Sopenharmony_ci rc = of_property_read_string_array(np, "phandle-list-names", strings, 1); 7788c2ecf20Sopenharmony_ci unittest(rc == 1 && strings[1] == NULL, "Overwrote end of string array; rc=%i, str='%s'\n", rc, strings[1]); 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci#define propcmp(p1, p2) (((p1)->length == (p2)->length) && \ 7828c2ecf20Sopenharmony_ci (p1)->value && (p2)->value && \ 7838c2ecf20Sopenharmony_ci !memcmp((p1)->value, (p2)->value, (p1)->length) && \ 7848c2ecf20Sopenharmony_ci !strcmp((p1)->name, (p2)->name)) 7858c2ecf20Sopenharmony_cistatic void __init of_unittest_property_copy(void) 7868c2ecf20Sopenharmony_ci{ 7878c2ecf20Sopenharmony_ci#ifdef CONFIG_OF_DYNAMIC 7888c2ecf20Sopenharmony_ci struct property p1 = { .name = "p1", .length = 0, .value = "" }; 7898c2ecf20Sopenharmony_ci struct property p2 = { .name = "p2", .length = 5, .value = "abcd" }; 7908c2ecf20Sopenharmony_ci struct property *new; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci new = __of_prop_dup(&p1, GFP_KERNEL); 7938c2ecf20Sopenharmony_ci unittest(new && propcmp(&p1, new), "empty property didn't copy correctly\n"); 7948c2ecf20Sopenharmony_ci kfree(new->value); 7958c2ecf20Sopenharmony_ci kfree(new->name); 7968c2ecf20Sopenharmony_ci kfree(new); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci new = __of_prop_dup(&p2, GFP_KERNEL); 7998c2ecf20Sopenharmony_ci unittest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n"); 8008c2ecf20Sopenharmony_ci kfree(new->value); 8018c2ecf20Sopenharmony_ci kfree(new->name); 8028c2ecf20Sopenharmony_ci kfree(new); 8038c2ecf20Sopenharmony_ci#endif 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_cistatic void __init of_unittest_changeset(void) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci#ifdef CONFIG_OF_DYNAMIC 8098c2ecf20Sopenharmony_ci struct property *ppadd, padd = { .name = "prop-add", .length = 1, .value = "" }; 8108c2ecf20Sopenharmony_ci struct property *ppname_n1, pname_n1 = { .name = "name", .length = 3, .value = "n1" }; 8118c2ecf20Sopenharmony_ci struct property *ppname_n2, pname_n2 = { .name = "name", .length = 3, .value = "n2" }; 8128c2ecf20Sopenharmony_ci struct property *ppname_n21, pname_n21 = { .name = "name", .length = 3, .value = "n21" }; 8138c2ecf20Sopenharmony_ci struct property *ppupdate, pupdate = { .name = "prop-update", .length = 5, .value = "abcd" }; 8148c2ecf20Sopenharmony_ci struct property *ppremove; 8158c2ecf20Sopenharmony_ci struct device_node *n1, *n2, *n21, *nchangeset, *nremove, *parent, *np; 8168c2ecf20Sopenharmony_ci struct of_changeset chgset; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci n1 = __of_node_dup(NULL, "n1"); 8198c2ecf20Sopenharmony_ci unittest(n1, "testcase setup failure\n"); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci n2 = __of_node_dup(NULL, "n2"); 8228c2ecf20Sopenharmony_ci unittest(n2, "testcase setup failure\n"); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci n21 = __of_node_dup(NULL, "n21"); 8258c2ecf20Sopenharmony_ci unittest(n21, "testcase setup failure %p\n", n21); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci nchangeset = of_find_node_by_path("/testcase-data/changeset"); 8288c2ecf20Sopenharmony_ci nremove = of_get_child_by_name(nchangeset, "node-remove"); 8298c2ecf20Sopenharmony_ci unittest(nremove, "testcase setup failure\n"); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci ppadd = __of_prop_dup(&padd, GFP_KERNEL); 8328c2ecf20Sopenharmony_ci unittest(ppadd, "testcase setup failure\n"); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci ppname_n1 = __of_prop_dup(&pname_n1, GFP_KERNEL); 8358c2ecf20Sopenharmony_ci unittest(ppname_n1, "testcase setup failure\n"); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci ppname_n2 = __of_prop_dup(&pname_n2, GFP_KERNEL); 8388c2ecf20Sopenharmony_ci unittest(ppname_n2, "testcase setup failure\n"); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci ppname_n21 = __of_prop_dup(&pname_n21, GFP_KERNEL); 8418c2ecf20Sopenharmony_ci unittest(ppname_n21, "testcase setup failure\n"); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci ppupdate = __of_prop_dup(&pupdate, GFP_KERNEL); 8448c2ecf20Sopenharmony_ci unittest(ppupdate, "testcase setup failure\n"); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci parent = nchangeset; 8478c2ecf20Sopenharmony_ci n1->parent = parent; 8488c2ecf20Sopenharmony_ci n2->parent = parent; 8498c2ecf20Sopenharmony_ci n21->parent = n2; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci ppremove = of_find_property(parent, "prop-remove", NULL); 8528c2ecf20Sopenharmony_ci unittest(ppremove, "failed to find removal prop"); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci of_changeset_init(&chgset); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci unittest(!of_changeset_attach_node(&chgset, n1), "fail attach n1\n"); 8578c2ecf20Sopenharmony_ci unittest(!of_changeset_add_property(&chgset, n1, ppname_n1), "fail add prop name\n"); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci unittest(!of_changeset_attach_node(&chgset, n2), "fail attach n2\n"); 8608c2ecf20Sopenharmony_ci unittest(!of_changeset_add_property(&chgset, n2, ppname_n2), "fail add prop name\n"); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci unittest(!of_changeset_detach_node(&chgset, nremove), "fail remove node\n"); 8638c2ecf20Sopenharmony_ci unittest(!of_changeset_add_property(&chgset, n21, ppname_n21), "fail add prop name\n"); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci unittest(!of_changeset_attach_node(&chgset, n21), "fail attach n21\n"); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci unittest(!of_changeset_add_property(&chgset, parent, ppadd), "fail add prop prop-add\n"); 8688c2ecf20Sopenharmony_ci unittest(!of_changeset_update_property(&chgset, parent, ppupdate), "fail update prop\n"); 8698c2ecf20Sopenharmony_ci unittest(!of_changeset_remove_property(&chgset, parent, ppremove), "fail remove prop\n"); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci unittest(!of_changeset_apply(&chgset), "apply failed\n"); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci of_node_put(nchangeset); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci /* Make sure node names are constructed correctly */ 8768c2ecf20Sopenharmony_ci unittest((np = of_find_node_by_path("/testcase-data/changeset/n2/n21")), 8778c2ecf20Sopenharmony_ci "'%pOF' not added\n", n21); 8788c2ecf20Sopenharmony_ci of_node_put(np); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci unittest(!of_changeset_revert(&chgset), "revert failed\n"); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci of_changeset_destroy(&chgset); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci of_node_put(n1); 8858c2ecf20Sopenharmony_ci of_node_put(n2); 8868c2ecf20Sopenharmony_ci of_node_put(n21); 8878c2ecf20Sopenharmony_ci#endif 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cistatic void __init of_unittest_dma_get_max_cpu_address(void) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci struct device_node *np; 8938c2ecf20Sopenharmony_ci phys_addr_t cpu_addr; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_OF_ADDRESS)) 8968c2ecf20Sopenharmony_ci return; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci np = of_find_node_by_path("/testcase-data/address-tests"); 8998c2ecf20Sopenharmony_ci if (!np) { 9008c2ecf20Sopenharmony_ci pr_err("missing testcase data\n"); 9018c2ecf20Sopenharmony_ci return; 9028c2ecf20Sopenharmony_ci } 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci cpu_addr = of_dma_get_max_cpu_address(np); 9058c2ecf20Sopenharmony_ci unittest(cpu_addr == 0x4fffffff, 9068c2ecf20Sopenharmony_ci "of_dma_get_max_cpu_address: wrong CPU addr %pad (expecting %x)\n", 9078c2ecf20Sopenharmony_ci &cpu_addr, 0x4fffffff); 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_cistatic void __init of_unittest_dma_ranges_one(const char *path, 9118c2ecf20Sopenharmony_ci u64 expect_dma_addr, u64 expect_paddr) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci#ifdef CONFIG_HAS_DMA 9148c2ecf20Sopenharmony_ci struct device_node *np; 9158c2ecf20Sopenharmony_ci const struct bus_dma_region *map = NULL; 9168c2ecf20Sopenharmony_ci int rc; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci np = of_find_node_by_path(path); 9198c2ecf20Sopenharmony_ci if (!np) { 9208c2ecf20Sopenharmony_ci pr_err("missing testcase data\n"); 9218c2ecf20Sopenharmony_ci return; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci rc = of_dma_get_range(np, &map); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci unittest(!rc, "of_dma_get_range failed on node %pOF rc=%i\n", np, rc); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (!rc) { 9298c2ecf20Sopenharmony_ci phys_addr_t paddr; 9308c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 9318c2ecf20Sopenharmony_ci struct device *dev_bogus; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci dev_bogus = kzalloc(sizeof(struct device), GFP_KERNEL); 9348c2ecf20Sopenharmony_ci if (!dev_bogus) { 9358c2ecf20Sopenharmony_ci unittest(0, "kzalloc() failed\n"); 9368c2ecf20Sopenharmony_ci kfree(map); 9378c2ecf20Sopenharmony_ci return; 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci dev_bogus->dma_range_map = map; 9418c2ecf20Sopenharmony_ci paddr = dma_to_phys(dev_bogus, expect_dma_addr); 9428c2ecf20Sopenharmony_ci dma_addr = phys_to_dma(dev_bogus, expect_paddr); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci unittest(paddr == expect_paddr, 9458c2ecf20Sopenharmony_ci "of_dma_get_range: wrong phys addr %pap (expecting %llx) on node %pOF\n", 9468c2ecf20Sopenharmony_ci &paddr, expect_paddr, np); 9478c2ecf20Sopenharmony_ci unittest(dma_addr == expect_dma_addr, 9488c2ecf20Sopenharmony_ci "of_dma_get_range: wrong DMA addr %pad (expecting %llx) on node %pOF\n", 9498c2ecf20Sopenharmony_ci &dma_addr, expect_dma_addr, np); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci kfree(map); 9528c2ecf20Sopenharmony_ci kfree(dev_bogus); 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ci of_node_put(np); 9558c2ecf20Sopenharmony_ci#endif 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_cistatic void __init of_unittest_parse_dma_ranges(void) 9598c2ecf20Sopenharmony_ci{ 9608c2ecf20Sopenharmony_ci of_unittest_dma_ranges_one("/testcase-data/address-tests/device@70000000", 9618c2ecf20Sopenharmony_ci 0x0, 0x20000000); 9628c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT)) 9638c2ecf20Sopenharmony_ci of_unittest_dma_ranges_one("/testcase-data/address-tests/bus@80000000/device@1000", 9648c2ecf20Sopenharmony_ci 0x100000000, 0x20000000); 9658c2ecf20Sopenharmony_ci of_unittest_dma_ranges_one("/testcase-data/address-tests/pci@90000000", 9668c2ecf20Sopenharmony_ci 0x80000000, 0x20000000); 9678c2ecf20Sopenharmony_ci} 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_cistatic void __init of_unittest_pci_dma_ranges(void) 9708c2ecf20Sopenharmony_ci{ 9718c2ecf20Sopenharmony_ci struct device_node *np; 9728c2ecf20Sopenharmony_ci struct of_pci_range range; 9738c2ecf20Sopenharmony_ci struct of_pci_range_parser parser; 9748c2ecf20Sopenharmony_ci int i = 0; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_PCI)) 9778c2ecf20Sopenharmony_ci return; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci np = of_find_node_by_path("/testcase-data/address-tests/pci@90000000"); 9808c2ecf20Sopenharmony_ci if (!np) { 9818c2ecf20Sopenharmony_ci pr_err("missing testcase data\n"); 9828c2ecf20Sopenharmony_ci return; 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci if (of_pci_dma_range_parser_init(&parser, np)) { 9868c2ecf20Sopenharmony_ci pr_err("missing dma-ranges property\n"); 9878c2ecf20Sopenharmony_ci return; 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci /* 9918c2ecf20Sopenharmony_ci * Get the dma-ranges from the device tree 9928c2ecf20Sopenharmony_ci */ 9938c2ecf20Sopenharmony_ci for_each_of_pci_range(&parser, &range) { 9948c2ecf20Sopenharmony_ci if (!i) { 9958c2ecf20Sopenharmony_ci unittest(range.size == 0x10000000, 9968c2ecf20Sopenharmony_ci "for_each_of_pci_range wrong size on node %pOF size=%llx\n", 9978c2ecf20Sopenharmony_ci np, range.size); 9988c2ecf20Sopenharmony_ci unittest(range.cpu_addr == 0x20000000, 9998c2ecf20Sopenharmony_ci "for_each_of_pci_range wrong CPU addr (%llx) on node %pOF", 10008c2ecf20Sopenharmony_ci range.cpu_addr, np); 10018c2ecf20Sopenharmony_ci unittest(range.pci_addr == 0x80000000, 10028c2ecf20Sopenharmony_ci "for_each_of_pci_range wrong DMA addr (%llx) on node %pOF", 10038c2ecf20Sopenharmony_ci range.pci_addr, np); 10048c2ecf20Sopenharmony_ci } else { 10058c2ecf20Sopenharmony_ci unittest(range.size == 0x10000000, 10068c2ecf20Sopenharmony_ci "for_each_of_pci_range wrong size on node %pOF size=%llx\n", 10078c2ecf20Sopenharmony_ci np, range.size); 10088c2ecf20Sopenharmony_ci unittest(range.cpu_addr == 0x40000000, 10098c2ecf20Sopenharmony_ci "for_each_of_pci_range wrong CPU addr (%llx) on node %pOF", 10108c2ecf20Sopenharmony_ci range.cpu_addr, np); 10118c2ecf20Sopenharmony_ci unittest(range.pci_addr == 0xc0000000, 10128c2ecf20Sopenharmony_ci "for_each_of_pci_range wrong DMA addr (%llx) on node %pOF", 10138c2ecf20Sopenharmony_ci range.pci_addr, np); 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci i++; 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci of_node_put(np); 10198c2ecf20Sopenharmony_ci} 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_cistatic void __init of_unittest_parse_interrupts(void) 10228c2ecf20Sopenharmony_ci{ 10238c2ecf20Sopenharmony_ci struct device_node *np; 10248c2ecf20Sopenharmony_ci struct of_phandle_args args; 10258c2ecf20Sopenharmony_ci int i, rc; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC) 10288c2ecf20Sopenharmony_ci return; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci np = of_find_node_by_path("/testcase-data/interrupts/interrupts0"); 10318c2ecf20Sopenharmony_ci if (!np) { 10328c2ecf20Sopenharmony_ci pr_err("missing testcase data\n"); 10338c2ecf20Sopenharmony_ci return; 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 10378c2ecf20Sopenharmony_ci bool passed = true; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 10408c2ecf20Sopenharmony_ci rc = of_irq_parse_one(np, i, &args); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci passed &= !rc; 10438c2ecf20Sopenharmony_ci passed &= (args.args_count == 1); 10448c2ecf20Sopenharmony_ci passed &= (args.args[0] == (i + 1)); 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci unittest(passed, "index %i - data error on node %pOF rc=%i\n", 10478c2ecf20Sopenharmony_ci i, args.np, rc); 10488c2ecf20Sopenharmony_ci } 10498c2ecf20Sopenharmony_ci of_node_put(np); 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci np = of_find_node_by_path("/testcase-data/interrupts/interrupts1"); 10528c2ecf20Sopenharmony_ci if (!np) { 10538c2ecf20Sopenharmony_ci pr_err("missing testcase data\n"); 10548c2ecf20Sopenharmony_ci return; 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 10588c2ecf20Sopenharmony_ci bool passed = true; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 10618c2ecf20Sopenharmony_ci rc = of_irq_parse_one(np, i, &args); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci /* Test the values from tests-phandle.dtsi */ 10648c2ecf20Sopenharmony_ci switch (i) { 10658c2ecf20Sopenharmony_ci case 0: 10668c2ecf20Sopenharmony_ci passed &= !rc; 10678c2ecf20Sopenharmony_ci passed &= (args.args_count == 1); 10688c2ecf20Sopenharmony_ci passed &= (args.args[0] == 9); 10698c2ecf20Sopenharmony_ci break; 10708c2ecf20Sopenharmony_ci case 1: 10718c2ecf20Sopenharmony_ci passed &= !rc; 10728c2ecf20Sopenharmony_ci passed &= (args.args_count == 3); 10738c2ecf20Sopenharmony_ci passed &= (args.args[0] == 10); 10748c2ecf20Sopenharmony_ci passed &= (args.args[1] == 11); 10758c2ecf20Sopenharmony_ci passed &= (args.args[2] == 12); 10768c2ecf20Sopenharmony_ci break; 10778c2ecf20Sopenharmony_ci case 2: 10788c2ecf20Sopenharmony_ci passed &= !rc; 10798c2ecf20Sopenharmony_ci passed &= (args.args_count == 2); 10808c2ecf20Sopenharmony_ci passed &= (args.args[0] == 13); 10818c2ecf20Sopenharmony_ci passed &= (args.args[1] == 14); 10828c2ecf20Sopenharmony_ci break; 10838c2ecf20Sopenharmony_ci case 3: 10848c2ecf20Sopenharmony_ci passed &= !rc; 10858c2ecf20Sopenharmony_ci passed &= (args.args_count == 2); 10868c2ecf20Sopenharmony_ci passed &= (args.args[0] == 15); 10878c2ecf20Sopenharmony_ci passed &= (args.args[1] == 16); 10888c2ecf20Sopenharmony_ci break; 10898c2ecf20Sopenharmony_ci default: 10908c2ecf20Sopenharmony_ci passed = false; 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci unittest(passed, "index %i - data error on node %pOF rc=%i\n", 10938c2ecf20Sopenharmony_ci i, args.np, rc); 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci of_node_put(np); 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_cistatic void __init of_unittest_parse_interrupts_extended(void) 10998c2ecf20Sopenharmony_ci{ 11008c2ecf20Sopenharmony_ci struct device_node *np; 11018c2ecf20Sopenharmony_ci struct of_phandle_args args; 11028c2ecf20Sopenharmony_ci int i, rc; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC) 11058c2ecf20Sopenharmony_ci return; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci np = of_find_node_by_path("/testcase-data/interrupts/interrupts-extended0"); 11088c2ecf20Sopenharmony_ci if (!np) { 11098c2ecf20Sopenharmony_ci pr_err("missing testcase data\n"); 11108c2ecf20Sopenharmony_ci return; 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci for (i = 0; i < 7; i++) { 11148c2ecf20Sopenharmony_ci bool passed = true; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 11178c2ecf20Sopenharmony_ci rc = of_irq_parse_one(np, i, &args); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci /* Test the values from tests-phandle.dtsi */ 11208c2ecf20Sopenharmony_ci switch (i) { 11218c2ecf20Sopenharmony_ci case 0: 11228c2ecf20Sopenharmony_ci passed &= !rc; 11238c2ecf20Sopenharmony_ci passed &= (args.args_count == 1); 11248c2ecf20Sopenharmony_ci passed &= (args.args[0] == 1); 11258c2ecf20Sopenharmony_ci break; 11268c2ecf20Sopenharmony_ci case 1: 11278c2ecf20Sopenharmony_ci passed &= !rc; 11288c2ecf20Sopenharmony_ci passed &= (args.args_count == 3); 11298c2ecf20Sopenharmony_ci passed &= (args.args[0] == 2); 11308c2ecf20Sopenharmony_ci passed &= (args.args[1] == 3); 11318c2ecf20Sopenharmony_ci passed &= (args.args[2] == 4); 11328c2ecf20Sopenharmony_ci break; 11338c2ecf20Sopenharmony_ci case 2: 11348c2ecf20Sopenharmony_ci passed &= !rc; 11358c2ecf20Sopenharmony_ci passed &= (args.args_count == 2); 11368c2ecf20Sopenharmony_ci passed &= (args.args[0] == 5); 11378c2ecf20Sopenharmony_ci passed &= (args.args[1] == 6); 11388c2ecf20Sopenharmony_ci break; 11398c2ecf20Sopenharmony_ci case 3: 11408c2ecf20Sopenharmony_ci passed &= !rc; 11418c2ecf20Sopenharmony_ci passed &= (args.args_count == 1); 11428c2ecf20Sopenharmony_ci passed &= (args.args[0] == 9); 11438c2ecf20Sopenharmony_ci break; 11448c2ecf20Sopenharmony_ci case 4: 11458c2ecf20Sopenharmony_ci passed &= !rc; 11468c2ecf20Sopenharmony_ci passed &= (args.args_count == 3); 11478c2ecf20Sopenharmony_ci passed &= (args.args[0] == 10); 11488c2ecf20Sopenharmony_ci passed &= (args.args[1] == 11); 11498c2ecf20Sopenharmony_ci passed &= (args.args[2] == 12); 11508c2ecf20Sopenharmony_ci break; 11518c2ecf20Sopenharmony_ci case 5: 11528c2ecf20Sopenharmony_ci passed &= !rc; 11538c2ecf20Sopenharmony_ci passed &= (args.args_count == 2); 11548c2ecf20Sopenharmony_ci passed &= (args.args[0] == 13); 11558c2ecf20Sopenharmony_ci passed &= (args.args[1] == 14); 11568c2ecf20Sopenharmony_ci break; 11578c2ecf20Sopenharmony_ci case 6: 11588c2ecf20Sopenharmony_ci passed &= !rc; 11598c2ecf20Sopenharmony_ci passed &= (args.args_count == 1); 11608c2ecf20Sopenharmony_ci passed &= (args.args[0] == 15); 11618c2ecf20Sopenharmony_ci break; 11628c2ecf20Sopenharmony_ci default: 11638c2ecf20Sopenharmony_ci passed = false; 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci unittest(passed, "index %i - data error on node %pOF rc=%i\n", 11678c2ecf20Sopenharmony_ci i, args.np, rc); 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci of_node_put(np); 11708c2ecf20Sopenharmony_ci} 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_cistatic const struct of_device_id match_node_table[] = { 11738c2ecf20Sopenharmony_ci { .data = "A", .name = "name0", }, /* Name alone is lowest priority */ 11748c2ecf20Sopenharmony_ci { .data = "B", .type = "type1", }, /* followed by type alone */ 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci { .data = "Ca", .name = "name2", .type = "type1", }, /* followed by both together */ 11778c2ecf20Sopenharmony_ci { .data = "Cb", .name = "name2", }, /* Only match when type doesn't match */ 11788c2ecf20Sopenharmony_ci { .data = "Cc", .name = "name2", .type = "type2", }, 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci { .data = "E", .compatible = "compat3" }, 11818c2ecf20Sopenharmony_ci { .data = "G", .compatible = "compat2", }, 11828c2ecf20Sopenharmony_ci { .data = "H", .compatible = "compat2", .name = "name5", }, 11838c2ecf20Sopenharmony_ci { .data = "I", .compatible = "compat2", .type = "type1", }, 11848c2ecf20Sopenharmony_ci { .data = "J", .compatible = "compat2", .type = "type1", .name = "name8", }, 11858c2ecf20Sopenharmony_ci { .data = "K", .compatible = "compat2", .name = "name9", }, 11868c2ecf20Sopenharmony_ci {} 11878c2ecf20Sopenharmony_ci}; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_cistatic struct { 11908c2ecf20Sopenharmony_ci const char *path; 11918c2ecf20Sopenharmony_ci const char *data; 11928c2ecf20Sopenharmony_ci} match_node_tests[] = { 11938c2ecf20Sopenharmony_ci { .path = "/testcase-data/match-node/name0", .data = "A", }, 11948c2ecf20Sopenharmony_ci { .path = "/testcase-data/match-node/name1", .data = "B", }, 11958c2ecf20Sopenharmony_ci { .path = "/testcase-data/match-node/a/name2", .data = "Ca", }, 11968c2ecf20Sopenharmony_ci { .path = "/testcase-data/match-node/b/name2", .data = "Cb", }, 11978c2ecf20Sopenharmony_ci { .path = "/testcase-data/match-node/c/name2", .data = "Cc", }, 11988c2ecf20Sopenharmony_ci { .path = "/testcase-data/match-node/name3", .data = "E", }, 11998c2ecf20Sopenharmony_ci { .path = "/testcase-data/match-node/name4", .data = "G", }, 12008c2ecf20Sopenharmony_ci { .path = "/testcase-data/match-node/name5", .data = "H", }, 12018c2ecf20Sopenharmony_ci { .path = "/testcase-data/match-node/name6", .data = "G", }, 12028c2ecf20Sopenharmony_ci { .path = "/testcase-data/match-node/name7", .data = "I", }, 12038c2ecf20Sopenharmony_ci { .path = "/testcase-data/match-node/name8", .data = "J", }, 12048c2ecf20Sopenharmony_ci { .path = "/testcase-data/match-node/name9", .data = "K", }, 12058c2ecf20Sopenharmony_ci}; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_cistatic void __init of_unittest_match_node(void) 12088c2ecf20Sopenharmony_ci{ 12098c2ecf20Sopenharmony_ci struct device_node *np; 12108c2ecf20Sopenharmony_ci const struct of_device_id *match; 12118c2ecf20Sopenharmony_ci int i; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(match_node_tests); i++) { 12148c2ecf20Sopenharmony_ci np = of_find_node_by_path(match_node_tests[i].path); 12158c2ecf20Sopenharmony_ci if (!np) { 12168c2ecf20Sopenharmony_ci unittest(0, "missing testcase node %s\n", 12178c2ecf20Sopenharmony_ci match_node_tests[i].path); 12188c2ecf20Sopenharmony_ci continue; 12198c2ecf20Sopenharmony_ci } 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci match = of_match_node(match_node_table, np); 12228c2ecf20Sopenharmony_ci if (!match) { 12238c2ecf20Sopenharmony_ci unittest(0, "%s didn't match anything\n", 12248c2ecf20Sopenharmony_ci match_node_tests[i].path); 12258c2ecf20Sopenharmony_ci continue; 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci if (strcmp(match->data, match_node_tests[i].data) != 0) { 12298c2ecf20Sopenharmony_ci unittest(0, "%s got wrong match. expected %s, got %s\n", 12308c2ecf20Sopenharmony_ci match_node_tests[i].path, match_node_tests[i].data, 12318c2ecf20Sopenharmony_ci (const char *)match->data); 12328c2ecf20Sopenharmony_ci continue; 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ci unittest(1, "passed"); 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci} 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_cistatic struct resource test_bus_res = { 12398c2ecf20Sopenharmony_ci .start = 0xfffffff8, 12408c2ecf20Sopenharmony_ci .end = 0xfffffff9, 12418c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 12428c2ecf20Sopenharmony_ci}; 12438c2ecf20Sopenharmony_cistatic const struct platform_device_info test_bus_info = { 12448c2ecf20Sopenharmony_ci .name = "unittest-bus", 12458c2ecf20Sopenharmony_ci}; 12468c2ecf20Sopenharmony_cistatic void __init of_unittest_platform_populate(void) 12478c2ecf20Sopenharmony_ci{ 12488c2ecf20Sopenharmony_ci int irq, rc; 12498c2ecf20Sopenharmony_ci struct device_node *np, *child, *grandchild; 12508c2ecf20Sopenharmony_ci struct platform_device *pdev, *test_bus; 12518c2ecf20Sopenharmony_ci const struct of_device_id match[] = { 12528c2ecf20Sopenharmony_ci { .compatible = "test-device", }, 12538c2ecf20Sopenharmony_ci {} 12548c2ecf20Sopenharmony_ci }; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci np = of_find_node_by_path("/testcase-data"); 12578c2ecf20Sopenharmony_ci of_platform_default_populate(np, NULL, NULL); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci /* Test that a missing irq domain returns -EPROBE_DEFER */ 12608c2ecf20Sopenharmony_ci np = of_find_node_by_path("/testcase-data/testcase-device1"); 12618c2ecf20Sopenharmony_ci pdev = of_find_device_by_node(np); 12628c2ecf20Sopenharmony_ci unittest(pdev, "device 1 creation failed\n"); 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci if (!(of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)) { 12658c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 12668c2ecf20Sopenharmony_ci unittest(irq == -EPROBE_DEFER, 12678c2ecf20Sopenharmony_ci "device deferred probe failed - %d\n", irq); 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci /* Test that a parsing failure does not return -EPROBE_DEFER */ 12708c2ecf20Sopenharmony_ci np = of_find_node_by_path("/testcase-data/testcase-device2"); 12718c2ecf20Sopenharmony_ci pdev = of_find_device_by_node(np); 12728c2ecf20Sopenharmony_ci unittest(pdev, "device 2 creation failed\n"); 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 12758c2ecf20Sopenharmony_ci "platform testcase-data:testcase-device2: IRQ index 0 not found"); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 12808c2ecf20Sopenharmony_ci "platform testcase-data:testcase-device2: IRQ index 0 not found"); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci unittest(irq < 0 && irq != -EPROBE_DEFER, 12838c2ecf20Sopenharmony_ci "device parsing error failed - %d\n", irq); 12848c2ecf20Sopenharmony_ci } 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci np = of_find_node_by_path("/testcase-data/platform-tests"); 12878c2ecf20Sopenharmony_ci unittest(np, "No testcase data in device tree\n"); 12888c2ecf20Sopenharmony_ci if (!np) 12898c2ecf20Sopenharmony_ci return; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci test_bus = platform_device_register_full(&test_bus_info); 12928c2ecf20Sopenharmony_ci rc = PTR_ERR_OR_ZERO(test_bus); 12938c2ecf20Sopenharmony_ci unittest(!rc, "testbus registration failed; rc=%i\n", rc); 12948c2ecf20Sopenharmony_ci if (rc) { 12958c2ecf20Sopenharmony_ci of_node_put(np); 12968c2ecf20Sopenharmony_ci return; 12978c2ecf20Sopenharmony_ci } 12988c2ecf20Sopenharmony_ci test_bus->dev.of_node = np; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci /* 13018c2ecf20Sopenharmony_ci * Add a dummy resource to the test bus node after it is 13028c2ecf20Sopenharmony_ci * registered to catch problems with un-inserted resources. The 13038c2ecf20Sopenharmony_ci * DT code doesn't insert the resources, and it has caused the 13048c2ecf20Sopenharmony_ci * kernel to oops in the past. This makes sure the same bug 13058c2ecf20Sopenharmony_ci * doesn't crop up again. 13068c2ecf20Sopenharmony_ci */ 13078c2ecf20Sopenharmony_ci platform_device_add_resources(test_bus, &test_bus_res, 1); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci of_platform_populate(np, match, NULL, &test_bus->dev); 13108c2ecf20Sopenharmony_ci for_each_child_of_node(np, child) { 13118c2ecf20Sopenharmony_ci for_each_child_of_node(child, grandchild) { 13128c2ecf20Sopenharmony_ci pdev = of_find_device_by_node(grandchild); 13138c2ecf20Sopenharmony_ci unittest(pdev, 13148c2ecf20Sopenharmony_ci "Could not create device for node '%pOFn'\n", 13158c2ecf20Sopenharmony_ci grandchild); 13168c2ecf20Sopenharmony_ci of_dev_put(pdev); 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci } 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci of_platform_depopulate(&test_bus->dev); 13218c2ecf20Sopenharmony_ci for_each_child_of_node(np, child) { 13228c2ecf20Sopenharmony_ci for_each_child_of_node(child, grandchild) 13238c2ecf20Sopenharmony_ci unittest(!of_find_device_by_node(grandchild), 13248c2ecf20Sopenharmony_ci "device didn't get destroyed '%pOFn'\n", 13258c2ecf20Sopenharmony_ci grandchild); 13268c2ecf20Sopenharmony_ci } 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci platform_device_unregister(test_bus); 13298c2ecf20Sopenharmony_ci of_node_put(np); 13308c2ecf20Sopenharmony_ci} 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci/** 13338c2ecf20Sopenharmony_ci * update_node_properties - adds the properties 13348c2ecf20Sopenharmony_ci * of np into dup node (present in live tree) and 13358c2ecf20Sopenharmony_ci * updates parent of children of np to dup. 13368c2ecf20Sopenharmony_ci * 13378c2ecf20Sopenharmony_ci * @np: node whose properties are being added to the live tree 13388c2ecf20Sopenharmony_ci * @dup: node present in live tree to be updated 13398c2ecf20Sopenharmony_ci */ 13408c2ecf20Sopenharmony_cistatic void update_node_properties(struct device_node *np, 13418c2ecf20Sopenharmony_ci struct device_node *dup) 13428c2ecf20Sopenharmony_ci{ 13438c2ecf20Sopenharmony_ci struct property *prop; 13448c2ecf20Sopenharmony_ci struct property *save_next; 13458c2ecf20Sopenharmony_ci struct device_node *child; 13468c2ecf20Sopenharmony_ci int ret; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci for_each_child_of_node(np, child) 13498c2ecf20Sopenharmony_ci child->parent = dup; 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci /* 13528c2ecf20Sopenharmony_ci * "unittest internal error: unable to add testdata property" 13538c2ecf20Sopenharmony_ci * 13548c2ecf20Sopenharmony_ci * If this message reports a property in node '/__symbols__' then 13558c2ecf20Sopenharmony_ci * the respective unittest overlay contains a label that has the 13568c2ecf20Sopenharmony_ci * same name as a label in the live devicetree. The label will 13578c2ecf20Sopenharmony_ci * be in the live devicetree only if the devicetree source was 13588c2ecf20Sopenharmony_ci * compiled with the '-@' option. If you encounter this error, 13598c2ecf20Sopenharmony_ci * please consider renaming __all__ of the labels in the unittest 13608c2ecf20Sopenharmony_ci * overlay dts files with an odd prefix that is unlikely to be 13618c2ecf20Sopenharmony_ci * used in a real devicetree. 13628c2ecf20Sopenharmony_ci */ 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci /* 13658c2ecf20Sopenharmony_ci * open code for_each_property_of_node() because of_add_property() 13668c2ecf20Sopenharmony_ci * sets prop->next to NULL 13678c2ecf20Sopenharmony_ci */ 13688c2ecf20Sopenharmony_ci for (prop = np->properties; prop != NULL; prop = save_next) { 13698c2ecf20Sopenharmony_ci save_next = prop->next; 13708c2ecf20Sopenharmony_ci ret = of_add_property(dup, prop); 13718c2ecf20Sopenharmony_ci if (ret) { 13728c2ecf20Sopenharmony_ci if (ret == -EEXIST && !strcmp(prop->name, "name")) 13738c2ecf20Sopenharmony_ci continue; 13748c2ecf20Sopenharmony_ci pr_err("unittest internal error: unable to add testdata property %pOF/%s", 13758c2ecf20Sopenharmony_ci np, prop->name); 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci} 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci/** 13818c2ecf20Sopenharmony_ci * attach_node_and_children - attaches nodes 13828c2ecf20Sopenharmony_ci * and its children to live tree. 13838c2ecf20Sopenharmony_ci * CAUTION: misleading function name - if node @np already exists in 13848c2ecf20Sopenharmony_ci * the live tree then children of @np are *not* attached to the live 13858c2ecf20Sopenharmony_ci * tree. This works for the current test devicetree nodes because such 13868c2ecf20Sopenharmony_ci * nodes do not have child nodes. 13878c2ecf20Sopenharmony_ci * 13888c2ecf20Sopenharmony_ci * @np: Node to attach to live tree 13898c2ecf20Sopenharmony_ci */ 13908c2ecf20Sopenharmony_cistatic void attach_node_and_children(struct device_node *np) 13918c2ecf20Sopenharmony_ci{ 13928c2ecf20Sopenharmony_ci struct device_node *next, *dup, *child; 13938c2ecf20Sopenharmony_ci unsigned long flags; 13948c2ecf20Sopenharmony_ci const char *full_name; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci full_name = kasprintf(GFP_KERNEL, "%pOF", np); 13978c2ecf20Sopenharmony_ci if (!full_name) 13988c2ecf20Sopenharmony_ci return; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci if (!strcmp(full_name, "/__local_fixups__") || 14018c2ecf20Sopenharmony_ci !strcmp(full_name, "/__fixups__")) { 14028c2ecf20Sopenharmony_ci kfree(full_name); 14038c2ecf20Sopenharmony_ci return; 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci dup = of_find_node_by_path(full_name); 14078c2ecf20Sopenharmony_ci kfree(full_name); 14088c2ecf20Sopenharmony_ci if (dup) { 14098c2ecf20Sopenharmony_ci update_node_properties(np, dup); 14108c2ecf20Sopenharmony_ci return; 14118c2ecf20Sopenharmony_ci } 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci child = np->child; 14148c2ecf20Sopenharmony_ci np->child = NULL; 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci mutex_lock(&of_mutex); 14178c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&devtree_lock, flags); 14188c2ecf20Sopenharmony_ci np->sibling = np->parent->child; 14198c2ecf20Sopenharmony_ci np->parent->child = np; 14208c2ecf20Sopenharmony_ci of_node_clear_flag(np, OF_DETACHED); 14218c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&devtree_lock, flags); 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci __of_attach_node_sysfs(np); 14248c2ecf20Sopenharmony_ci mutex_unlock(&of_mutex); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci while (child) { 14278c2ecf20Sopenharmony_ci next = child->sibling; 14288c2ecf20Sopenharmony_ci attach_node_and_children(child); 14298c2ecf20Sopenharmony_ci child = next; 14308c2ecf20Sopenharmony_ci } 14318c2ecf20Sopenharmony_ci} 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci/** 14348c2ecf20Sopenharmony_ci * unittest_data_add - Reads, copies data from 14358c2ecf20Sopenharmony_ci * linked tree and attaches it to the live tree 14368c2ecf20Sopenharmony_ci */ 14378c2ecf20Sopenharmony_cistatic int __init unittest_data_add(void) 14388c2ecf20Sopenharmony_ci{ 14398c2ecf20Sopenharmony_ci void *unittest_data; 14408c2ecf20Sopenharmony_ci struct device_node *unittest_data_node, *np; 14418c2ecf20Sopenharmony_ci /* 14428c2ecf20Sopenharmony_ci * __dtb_testcases_begin[] and __dtb_testcases_end[] are magically 14438c2ecf20Sopenharmony_ci * created by cmd_dt_S_dtb in scripts/Makefile.lib 14448c2ecf20Sopenharmony_ci */ 14458c2ecf20Sopenharmony_ci extern uint8_t __dtb_testcases_begin[]; 14468c2ecf20Sopenharmony_ci extern uint8_t __dtb_testcases_end[]; 14478c2ecf20Sopenharmony_ci const int size = __dtb_testcases_end - __dtb_testcases_begin; 14488c2ecf20Sopenharmony_ci int rc; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci if (!size) { 14518c2ecf20Sopenharmony_ci pr_warn("%s: No testcase data to attach; not running tests\n", 14528c2ecf20Sopenharmony_ci __func__); 14538c2ecf20Sopenharmony_ci return -ENODATA; 14548c2ecf20Sopenharmony_ci } 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci /* creating copy */ 14578c2ecf20Sopenharmony_ci unittest_data = kmemdup(__dtb_testcases_begin, size, GFP_KERNEL); 14588c2ecf20Sopenharmony_ci if (!unittest_data) 14598c2ecf20Sopenharmony_ci return -ENOMEM; 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci of_fdt_unflatten_tree(unittest_data, NULL, &unittest_data_node); 14628c2ecf20Sopenharmony_ci if (!unittest_data_node) { 14638c2ecf20Sopenharmony_ci pr_warn("%s: No tree to attach; not running tests\n", __func__); 14648c2ecf20Sopenharmony_ci kfree(unittest_data); 14658c2ecf20Sopenharmony_ci return -ENODATA; 14668c2ecf20Sopenharmony_ci } 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci /* 14698c2ecf20Sopenharmony_ci * This lock normally encloses of_resolve_phandles() 14708c2ecf20Sopenharmony_ci */ 14718c2ecf20Sopenharmony_ci of_overlay_mutex_lock(); 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci rc = of_resolve_phandles(unittest_data_node); 14748c2ecf20Sopenharmony_ci if (rc) { 14758c2ecf20Sopenharmony_ci pr_err("%s: Failed to resolve phandles (rc=%i)\n", __func__, rc); 14768c2ecf20Sopenharmony_ci of_overlay_mutex_unlock(); 14778c2ecf20Sopenharmony_ci return -EINVAL; 14788c2ecf20Sopenharmony_ci } 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci if (!of_root) { 14818c2ecf20Sopenharmony_ci of_root = unittest_data_node; 14828c2ecf20Sopenharmony_ci for_each_of_allnodes(np) 14838c2ecf20Sopenharmony_ci __of_attach_node_sysfs(np); 14848c2ecf20Sopenharmony_ci of_aliases = of_find_node_by_path("/aliases"); 14858c2ecf20Sopenharmony_ci of_chosen = of_find_node_by_path("/chosen"); 14868c2ecf20Sopenharmony_ci of_overlay_mutex_unlock(); 14878c2ecf20Sopenharmony_ci return 0; 14888c2ecf20Sopenharmony_ci } 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 14918c2ecf20Sopenharmony_ci "Duplicate name in testcase-data, renamed to \"duplicate-name#1\""); 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci /* attach the sub-tree to live tree */ 14948c2ecf20Sopenharmony_ci np = unittest_data_node->child; 14958c2ecf20Sopenharmony_ci while (np) { 14968c2ecf20Sopenharmony_ci struct device_node *next = np->sibling; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci np->parent = of_root; 14998c2ecf20Sopenharmony_ci attach_node_and_children(np); 15008c2ecf20Sopenharmony_ci np = next; 15018c2ecf20Sopenharmony_ci } 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 15048c2ecf20Sopenharmony_ci "Duplicate name in testcase-data, renamed to \"duplicate-name#1\""); 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci of_overlay_mutex_unlock(); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci return 0; 15098c2ecf20Sopenharmony_ci} 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci#ifdef CONFIG_OF_OVERLAY 15128c2ecf20Sopenharmony_cistatic int __init overlay_data_apply(const char *overlay_name, int *overlay_id); 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_cistatic int unittest_probe(struct platform_device *pdev) 15158c2ecf20Sopenharmony_ci{ 15168c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 15178c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci if (np == NULL) { 15208c2ecf20Sopenharmony_ci dev_err(dev, "No OF data for device\n"); 15218c2ecf20Sopenharmony_ci return -EINVAL; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci } 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci dev_dbg(dev, "%s for node @%pOF\n", __func__, np); 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci of_platform_populate(np, NULL, NULL, &pdev->dev); 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci return 0; 15308c2ecf20Sopenharmony_ci} 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_cistatic int unittest_remove(struct platform_device *pdev) 15338c2ecf20Sopenharmony_ci{ 15348c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 15358c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci dev_dbg(dev, "%s for node @%pOF\n", __func__, np); 15388c2ecf20Sopenharmony_ci return 0; 15398c2ecf20Sopenharmony_ci} 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_cistatic const struct of_device_id unittest_match[] = { 15428c2ecf20Sopenharmony_ci { .compatible = "unittest", }, 15438c2ecf20Sopenharmony_ci {}, 15448c2ecf20Sopenharmony_ci}; 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_cistatic struct platform_driver unittest_driver = { 15478c2ecf20Sopenharmony_ci .probe = unittest_probe, 15488c2ecf20Sopenharmony_ci .remove = unittest_remove, 15498c2ecf20Sopenharmony_ci .driver = { 15508c2ecf20Sopenharmony_ci .name = "unittest", 15518c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(unittest_match), 15528c2ecf20Sopenharmony_ci }, 15538c2ecf20Sopenharmony_ci}; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci/* get the platform device instantiated at the path */ 15568c2ecf20Sopenharmony_cistatic struct platform_device *of_path_to_platform_device(const char *path) 15578c2ecf20Sopenharmony_ci{ 15588c2ecf20Sopenharmony_ci struct device_node *np; 15598c2ecf20Sopenharmony_ci struct platform_device *pdev; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci np = of_find_node_by_path(path); 15628c2ecf20Sopenharmony_ci if (np == NULL) 15638c2ecf20Sopenharmony_ci return NULL; 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci pdev = of_find_device_by_node(np); 15668c2ecf20Sopenharmony_ci of_node_put(np); 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci return pdev; 15698c2ecf20Sopenharmony_ci} 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci/* find out if a platform device exists at that path */ 15728c2ecf20Sopenharmony_cistatic int of_path_platform_device_exists(const char *path) 15738c2ecf20Sopenharmony_ci{ 15748c2ecf20Sopenharmony_ci struct platform_device *pdev; 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci pdev = of_path_to_platform_device(path); 15778c2ecf20Sopenharmony_ci platform_device_put(pdev); 15788c2ecf20Sopenharmony_ci return pdev != NULL; 15798c2ecf20Sopenharmony_ci} 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci#ifdef CONFIG_OF_GPIO 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_cistruct unittest_gpio_dev { 15848c2ecf20Sopenharmony_ci struct gpio_chip chip; 15858c2ecf20Sopenharmony_ci}; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_cistatic int unittest_gpio_chip_request_count; 15888c2ecf20Sopenharmony_cistatic int unittest_gpio_probe_count; 15898c2ecf20Sopenharmony_cistatic int unittest_gpio_probe_pass_count; 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_cistatic int unittest_gpio_chip_request(struct gpio_chip *chip, unsigned int offset) 15928c2ecf20Sopenharmony_ci{ 15938c2ecf20Sopenharmony_ci unittest_gpio_chip_request_count++; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci pr_debug("%s(): %s %d %d\n", __func__, chip->label, offset, 15968c2ecf20Sopenharmony_ci unittest_gpio_chip_request_count); 15978c2ecf20Sopenharmony_ci return 0; 15988c2ecf20Sopenharmony_ci} 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_cistatic int unittest_gpio_probe(struct platform_device *pdev) 16018c2ecf20Sopenharmony_ci{ 16028c2ecf20Sopenharmony_ci struct unittest_gpio_dev *devptr; 16038c2ecf20Sopenharmony_ci int ret; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci unittest_gpio_probe_count++; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci devptr = kzalloc(sizeof(*devptr), GFP_KERNEL); 16088c2ecf20Sopenharmony_ci if (!devptr) 16098c2ecf20Sopenharmony_ci return -ENOMEM; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, devptr); 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci devptr->chip.of_node = pdev->dev.of_node; 16148c2ecf20Sopenharmony_ci devptr->chip.label = "of-unittest-gpio"; 16158c2ecf20Sopenharmony_ci devptr->chip.base = -1; /* dynamic allocation */ 16168c2ecf20Sopenharmony_ci devptr->chip.ngpio = 5; 16178c2ecf20Sopenharmony_ci devptr->chip.request = unittest_gpio_chip_request; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci ret = gpiochip_add_data(&devptr->chip, NULL); 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci unittest(!ret, 16228c2ecf20Sopenharmony_ci "gpiochip_add_data() for node @%pOF failed, ret = %d\n", devptr->chip.of_node, ret); 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci if (!ret) 16258c2ecf20Sopenharmony_ci unittest_gpio_probe_pass_count++; 16268c2ecf20Sopenharmony_ci return ret; 16278c2ecf20Sopenharmony_ci} 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_cistatic int unittest_gpio_remove(struct platform_device *pdev) 16308c2ecf20Sopenharmony_ci{ 16318c2ecf20Sopenharmony_ci struct unittest_gpio_dev *gdev = platform_get_drvdata(pdev); 16328c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 16338c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci dev_dbg(dev, "%s for node @%pOF\n", __func__, np); 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci if (!gdev) 16388c2ecf20Sopenharmony_ci return -EINVAL; 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci if (gdev->chip.base != -1) 16418c2ecf20Sopenharmony_ci gpiochip_remove(&gdev->chip); 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, NULL); 16448c2ecf20Sopenharmony_ci kfree(gdev); 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci return 0; 16478c2ecf20Sopenharmony_ci} 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_cistatic const struct of_device_id unittest_gpio_id[] = { 16508c2ecf20Sopenharmony_ci { .compatible = "unittest-gpio", }, 16518c2ecf20Sopenharmony_ci {} 16528c2ecf20Sopenharmony_ci}; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_cistatic struct platform_driver unittest_gpio_driver = { 16558c2ecf20Sopenharmony_ci .probe = unittest_gpio_probe, 16568c2ecf20Sopenharmony_ci .remove = unittest_gpio_remove, 16578c2ecf20Sopenharmony_ci .driver = { 16588c2ecf20Sopenharmony_ci .name = "unittest-gpio", 16598c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(unittest_gpio_id), 16608c2ecf20Sopenharmony_ci }, 16618c2ecf20Sopenharmony_ci}; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_gpio(void) 16648c2ecf20Sopenharmony_ci{ 16658c2ecf20Sopenharmony_ci int chip_request_count; 16668c2ecf20Sopenharmony_ci int probe_pass_count; 16678c2ecf20Sopenharmony_ci int ret; 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci /* 16708c2ecf20Sopenharmony_ci * tests: apply overlays before registering driver 16718c2ecf20Sopenharmony_ci * Similar to installing a driver as a module, the 16728c2ecf20Sopenharmony_ci * driver is registered after applying the overlays. 16738c2ecf20Sopenharmony_ci * 16748c2ecf20Sopenharmony_ci * The overlays are applied by overlay_data_apply() 16758c2ecf20Sopenharmony_ci * instead of of_unittest_apply_overlay() so that they 16768c2ecf20Sopenharmony_ci * will not be tracked. Thus they will not be removed 16778c2ecf20Sopenharmony_ci * by of_unittest_destroy_tracked_overlays(). 16788c2ecf20Sopenharmony_ci * 16798c2ecf20Sopenharmony_ci * - apply overlay_gpio_01 16808c2ecf20Sopenharmony_ci * - apply overlay_gpio_02a 16818c2ecf20Sopenharmony_ci * - apply overlay_gpio_02b 16828c2ecf20Sopenharmony_ci * - register driver 16838c2ecf20Sopenharmony_ci * 16848c2ecf20Sopenharmony_ci * register driver will result in 16858c2ecf20Sopenharmony_ci * - probe and processing gpio hog for overlay_gpio_01 16868c2ecf20Sopenharmony_ci * - probe for overlay_gpio_02a 16878c2ecf20Sopenharmony_ci * - processing gpio for overlay_gpio_02b 16888c2ecf20Sopenharmony_ci */ 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci probe_pass_count = unittest_gpio_probe_pass_count; 16918c2ecf20Sopenharmony_ci chip_request_count = unittest_gpio_chip_request_count; 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci /* 16948c2ecf20Sopenharmony_ci * overlay_gpio_01 contains gpio node and child gpio hog node 16958c2ecf20Sopenharmony_ci * overlay_gpio_02a contains gpio node 16968c2ecf20Sopenharmony_ci * overlay_gpio_02b contains child gpio hog node 16978c2ecf20Sopenharmony_ci */ 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci unittest(overlay_data_apply("overlay_gpio_01", NULL), 17008c2ecf20Sopenharmony_ci "Adding overlay 'overlay_gpio_01' failed\n"); 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci unittest(overlay_data_apply("overlay_gpio_02a", NULL), 17038c2ecf20Sopenharmony_ci "Adding overlay 'overlay_gpio_02a' failed\n"); 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci unittest(overlay_data_apply("overlay_gpio_02b", NULL), 17068c2ecf20Sopenharmony_ci "Adding overlay 'overlay_gpio_02b' failed\n"); 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci /* 17098c2ecf20Sopenharmony_ci * messages are the result of the probes, after the 17108c2ecf20Sopenharmony_ci * driver is registered 17118c2ecf20Sopenharmony_ci */ 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 17148c2ecf20Sopenharmony_ci "gpio-<<int>> (line-B-input): hogged as input\n"); 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 17178c2ecf20Sopenharmony_ci "gpio-<<int>> (line-A-input): hogged as input\n"); 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci ret = platform_driver_register(&unittest_gpio_driver); 17208c2ecf20Sopenharmony_ci if (unittest(ret == 0, "could not register unittest gpio driver\n")) 17218c2ecf20Sopenharmony_ci return; 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 17248c2ecf20Sopenharmony_ci "gpio-<<int>> (line-A-input): hogged as input\n"); 17258c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 17268c2ecf20Sopenharmony_ci "gpio-<<int>> (line-B-input): hogged as input\n"); 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci unittest(probe_pass_count + 2 == unittest_gpio_probe_pass_count, 17298c2ecf20Sopenharmony_ci "unittest_gpio_probe() failed or not called\n"); 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci unittest(chip_request_count + 2 == unittest_gpio_chip_request_count, 17328c2ecf20Sopenharmony_ci "unittest_gpio_chip_request() called %d times (expected 1 time)\n", 17338c2ecf20Sopenharmony_ci unittest_gpio_chip_request_count - chip_request_count); 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci /* 17368c2ecf20Sopenharmony_ci * tests: apply overlays after registering driver 17378c2ecf20Sopenharmony_ci * 17388c2ecf20Sopenharmony_ci * Similar to a driver built-in to the kernel, the 17398c2ecf20Sopenharmony_ci * driver is registered before applying the overlays. 17408c2ecf20Sopenharmony_ci * 17418c2ecf20Sopenharmony_ci * overlay_gpio_03 contains gpio node and child gpio hog node 17428c2ecf20Sopenharmony_ci * 17438c2ecf20Sopenharmony_ci * - apply overlay_gpio_03 17448c2ecf20Sopenharmony_ci * 17458c2ecf20Sopenharmony_ci * apply overlay will result in 17468c2ecf20Sopenharmony_ci * - probe and processing gpio hog. 17478c2ecf20Sopenharmony_ci */ 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci probe_pass_count = unittest_gpio_probe_pass_count; 17508c2ecf20Sopenharmony_ci chip_request_count = unittest_gpio_chip_request_count; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 17538c2ecf20Sopenharmony_ci "gpio-<<int>> (line-D-input): hogged as input\n"); 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci /* overlay_gpio_03 contains gpio node and child gpio hog node */ 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci unittest(overlay_data_apply("overlay_gpio_03", NULL), 17588c2ecf20Sopenharmony_ci "Adding overlay 'overlay_gpio_03' failed\n"); 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 17618c2ecf20Sopenharmony_ci "gpio-<<int>> (line-D-input): hogged as input\n"); 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci unittest(probe_pass_count + 1 == unittest_gpio_probe_pass_count, 17648c2ecf20Sopenharmony_ci "unittest_gpio_probe() failed or not called\n"); 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci unittest(chip_request_count + 1 == unittest_gpio_chip_request_count, 17678c2ecf20Sopenharmony_ci "unittest_gpio_chip_request() called %d times (expected 1 time)\n", 17688c2ecf20Sopenharmony_ci unittest_gpio_chip_request_count - chip_request_count); 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci /* 17718c2ecf20Sopenharmony_ci * overlay_gpio_04a contains gpio node 17728c2ecf20Sopenharmony_ci * 17738c2ecf20Sopenharmony_ci * - apply overlay_gpio_04a 17748c2ecf20Sopenharmony_ci * 17758c2ecf20Sopenharmony_ci * apply the overlay will result in 17768c2ecf20Sopenharmony_ci * - probe for overlay_gpio_04a 17778c2ecf20Sopenharmony_ci */ 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci probe_pass_count = unittest_gpio_probe_pass_count; 17808c2ecf20Sopenharmony_ci chip_request_count = unittest_gpio_chip_request_count; 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci /* overlay_gpio_04a contains gpio node */ 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci unittest(overlay_data_apply("overlay_gpio_04a", NULL), 17858c2ecf20Sopenharmony_ci "Adding overlay 'overlay_gpio_04a' failed\n"); 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci unittest(probe_pass_count + 1 == unittest_gpio_probe_pass_count, 17888c2ecf20Sopenharmony_ci "unittest_gpio_probe() failed or not called\n"); 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci /* 17918c2ecf20Sopenharmony_ci * overlay_gpio_04b contains child gpio hog node 17928c2ecf20Sopenharmony_ci * 17938c2ecf20Sopenharmony_ci * - apply overlay_gpio_04b 17948c2ecf20Sopenharmony_ci * 17958c2ecf20Sopenharmony_ci * apply the overlay will result in 17968c2ecf20Sopenharmony_ci * - processing gpio for overlay_gpio_04b 17978c2ecf20Sopenharmony_ci */ 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 18008c2ecf20Sopenharmony_ci "gpio-<<int>> (line-C-input): hogged as input\n"); 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci /* overlay_gpio_04b contains child gpio hog node */ 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci unittest(overlay_data_apply("overlay_gpio_04b", NULL), 18058c2ecf20Sopenharmony_ci "Adding overlay 'overlay_gpio_04b' failed\n"); 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 18088c2ecf20Sopenharmony_ci "gpio-<<int>> (line-C-input): hogged as input\n"); 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci unittest(chip_request_count + 1 == unittest_gpio_chip_request_count, 18118c2ecf20Sopenharmony_ci "unittest_gpio_chip_request() called %d times (expected 1 time)\n", 18128c2ecf20Sopenharmony_ci unittest_gpio_chip_request_count - chip_request_count); 18138c2ecf20Sopenharmony_ci} 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci#else 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_gpio(void) 18188c2ecf20Sopenharmony_ci{ 18198c2ecf20Sopenharmony_ci /* skip tests */ 18208c2ecf20Sopenharmony_ci} 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci#endif 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci#if IS_BUILTIN(CONFIG_I2C) 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci/* get the i2c client device instantiated at the path */ 18278c2ecf20Sopenharmony_cistatic struct i2c_client *of_path_to_i2c_client(const char *path) 18288c2ecf20Sopenharmony_ci{ 18298c2ecf20Sopenharmony_ci struct device_node *np; 18308c2ecf20Sopenharmony_ci struct i2c_client *client; 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci np = of_find_node_by_path(path); 18338c2ecf20Sopenharmony_ci if (np == NULL) 18348c2ecf20Sopenharmony_ci return NULL; 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci client = of_find_i2c_device_by_node(np); 18378c2ecf20Sopenharmony_ci of_node_put(np); 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci return client; 18408c2ecf20Sopenharmony_ci} 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci/* find out if a i2c client device exists at that path */ 18438c2ecf20Sopenharmony_cistatic int of_path_i2c_client_exists(const char *path) 18448c2ecf20Sopenharmony_ci{ 18458c2ecf20Sopenharmony_ci struct i2c_client *client; 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci client = of_path_to_i2c_client(path); 18488c2ecf20Sopenharmony_ci if (client) 18498c2ecf20Sopenharmony_ci put_device(&client->dev); 18508c2ecf20Sopenharmony_ci return client != NULL; 18518c2ecf20Sopenharmony_ci} 18528c2ecf20Sopenharmony_ci#else 18538c2ecf20Sopenharmony_cistatic int of_path_i2c_client_exists(const char *path) 18548c2ecf20Sopenharmony_ci{ 18558c2ecf20Sopenharmony_ci return 0; 18568c2ecf20Sopenharmony_ci} 18578c2ecf20Sopenharmony_ci#endif 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_cienum overlay_type { 18608c2ecf20Sopenharmony_ci PDEV_OVERLAY, 18618c2ecf20Sopenharmony_ci I2C_OVERLAY 18628c2ecf20Sopenharmony_ci}; 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_cistatic int of_path_device_type_exists(const char *path, 18658c2ecf20Sopenharmony_ci enum overlay_type ovtype) 18668c2ecf20Sopenharmony_ci{ 18678c2ecf20Sopenharmony_ci switch (ovtype) { 18688c2ecf20Sopenharmony_ci case PDEV_OVERLAY: 18698c2ecf20Sopenharmony_ci return of_path_platform_device_exists(path); 18708c2ecf20Sopenharmony_ci case I2C_OVERLAY: 18718c2ecf20Sopenharmony_ci return of_path_i2c_client_exists(path); 18728c2ecf20Sopenharmony_ci } 18738c2ecf20Sopenharmony_ci return 0; 18748c2ecf20Sopenharmony_ci} 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_cistatic const char *unittest_path(int nr, enum overlay_type ovtype) 18778c2ecf20Sopenharmony_ci{ 18788c2ecf20Sopenharmony_ci const char *base; 18798c2ecf20Sopenharmony_ci static char buf[256]; 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci switch (ovtype) { 18828c2ecf20Sopenharmony_ci case PDEV_OVERLAY: 18838c2ecf20Sopenharmony_ci base = "/testcase-data/overlay-node/test-bus"; 18848c2ecf20Sopenharmony_ci break; 18858c2ecf20Sopenharmony_ci case I2C_OVERLAY: 18868c2ecf20Sopenharmony_ci base = "/testcase-data/overlay-node/test-bus/i2c-test-bus"; 18878c2ecf20Sopenharmony_ci break; 18888c2ecf20Sopenharmony_ci default: 18898c2ecf20Sopenharmony_ci buf[0] = '\0'; 18908c2ecf20Sopenharmony_ci return buf; 18918c2ecf20Sopenharmony_ci } 18928c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf) - 1, "%s/test-unittest%d", base, nr); 18938c2ecf20Sopenharmony_ci buf[sizeof(buf) - 1] = '\0'; 18948c2ecf20Sopenharmony_ci return buf; 18958c2ecf20Sopenharmony_ci} 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_cistatic int of_unittest_device_exists(int unittest_nr, enum overlay_type ovtype) 18988c2ecf20Sopenharmony_ci{ 18998c2ecf20Sopenharmony_ci const char *path; 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci path = unittest_path(unittest_nr, ovtype); 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci switch (ovtype) { 19048c2ecf20Sopenharmony_ci case PDEV_OVERLAY: 19058c2ecf20Sopenharmony_ci return of_path_platform_device_exists(path); 19068c2ecf20Sopenharmony_ci case I2C_OVERLAY: 19078c2ecf20Sopenharmony_ci return of_path_i2c_client_exists(path); 19088c2ecf20Sopenharmony_ci } 19098c2ecf20Sopenharmony_ci return 0; 19108c2ecf20Sopenharmony_ci} 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_cistatic const char *overlay_name_from_nr(int nr) 19138c2ecf20Sopenharmony_ci{ 19148c2ecf20Sopenharmony_ci static char buf[256]; 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf) - 1, 19178c2ecf20Sopenharmony_ci "overlay_%d", nr); 19188c2ecf20Sopenharmony_ci buf[sizeof(buf) - 1] = '\0'; 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci return buf; 19218c2ecf20Sopenharmony_ci} 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_cistatic const char *bus_path = "/testcase-data/overlay-node/test-bus"; 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci/* FIXME: it is NOT guaranteed that overlay ids are assigned in sequence */ 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci#define MAX_UNITTEST_OVERLAYS 256 19288c2ecf20Sopenharmony_cistatic unsigned long overlay_id_bits[BITS_TO_LONGS(MAX_UNITTEST_OVERLAYS)]; 19298c2ecf20Sopenharmony_cistatic int overlay_first_id = -1; 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_cistatic long of_unittest_overlay_tracked(int id) 19328c2ecf20Sopenharmony_ci{ 19338c2ecf20Sopenharmony_ci if (WARN_ON(id >= MAX_UNITTEST_OVERLAYS)) 19348c2ecf20Sopenharmony_ci return 0; 19358c2ecf20Sopenharmony_ci return overlay_id_bits[BIT_WORD(id)] & BIT_MASK(id); 19368c2ecf20Sopenharmony_ci} 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_cistatic void of_unittest_track_overlay(int id) 19398c2ecf20Sopenharmony_ci{ 19408c2ecf20Sopenharmony_ci if (overlay_first_id < 0) 19418c2ecf20Sopenharmony_ci overlay_first_id = id; 19428c2ecf20Sopenharmony_ci id -= overlay_first_id; 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci if (WARN_ON(id >= MAX_UNITTEST_OVERLAYS)) 19458c2ecf20Sopenharmony_ci return; 19468c2ecf20Sopenharmony_ci overlay_id_bits[BIT_WORD(id)] |= BIT_MASK(id); 19478c2ecf20Sopenharmony_ci} 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_cistatic void of_unittest_untrack_overlay(int id) 19508c2ecf20Sopenharmony_ci{ 19518c2ecf20Sopenharmony_ci if (overlay_first_id < 0) 19528c2ecf20Sopenharmony_ci return; 19538c2ecf20Sopenharmony_ci id -= overlay_first_id; 19548c2ecf20Sopenharmony_ci if (WARN_ON(id >= MAX_UNITTEST_OVERLAYS)) 19558c2ecf20Sopenharmony_ci return; 19568c2ecf20Sopenharmony_ci overlay_id_bits[BIT_WORD(id)] &= ~BIT_MASK(id); 19578c2ecf20Sopenharmony_ci} 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_cistatic void of_unittest_destroy_tracked_overlays(void) 19608c2ecf20Sopenharmony_ci{ 19618c2ecf20Sopenharmony_ci int id, ret, defers, ovcs_id; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci if (overlay_first_id < 0) 19648c2ecf20Sopenharmony_ci return; 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci /* try until no defers */ 19678c2ecf20Sopenharmony_ci do { 19688c2ecf20Sopenharmony_ci defers = 0; 19698c2ecf20Sopenharmony_ci /* remove in reverse order */ 19708c2ecf20Sopenharmony_ci for (id = MAX_UNITTEST_OVERLAYS - 1; id >= 0; id--) { 19718c2ecf20Sopenharmony_ci if (!of_unittest_overlay_tracked(id)) 19728c2ecf20Sopenharmony_ci continue; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci ovcs_id = id + overlay_first_id; 19758c2ecf20Sopenharmony_ci ret = of_overlay_remove(&ovcs_id); 19768c2ecf20Sopenharmony_ci if (ret == -ENODEV) { 19778c2ecf20Sopenharmony_ci pr_warn("%s: no overlay to destroy for #%d\n", 19788c2ecf20Sopenharmony_ci __func__, id + overlay_first_id); 19798c2ecf20Sopenharmony_ci continue; 19808c2ecf20Sopenharmony_ci } 19818c2ecf20Sopenharmony_ci if (ret != 0) { 19828c2ecf20Sopenharmony_ci defers++; 19838c2ecf20Sopenharmony_ci pr_warn("%s: overlay destroy failed for #%d\n", 19848c2ecf20Sopenharmony_ci __func__, id + overlay_first_id); 19858c2ecf20Sopenharmony_ci continue; 19868c2ecf20Sopenharmony_ci } 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci of_unittest_untrack_overlay(id); 19898c2ecf20Sopenharmony_ci } 19908c2ecf20Sopenharmony_ci } while (defers > 0); 19918c2ecf20Sopenharmony_ci} 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_cistatic int __init of_unittest_apply_overlay(int overlay_nr, int *overlay_id) 19948c2ecf20Sopenharmony_ci{ 19958c2ecf20Sopenharmony_ci const char *overlay_name; 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci overlay_name = overlay_name_from_nr(overlay_nr); 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci if (!overlay_data_apply(overlay_name, overlay_id)) { 20008c2ecf20Sopenharmony_ci unittest(0, "could not apply overlay \"%s\"\n", 20018c2ecf20Sopenharmony_ci overlay_name); 20028c2ecf20Sopenharmony_ci return -EFAULT; 20038c2ecf20Sopenharmony_ci } 20048c2ecf20Sopenharmony_ci of_unittest_track_overlay(*overlay_id); 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci return 0; 20078c2ecf20Sopenharmony_ci} 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci/* apply an overlay while checking before and after states */ 20108c2ecf20Sopenharmony_cistatic int __init of_unittest_apply_overlay_check(int overlay_nr, 20118c2ecf20Sopenharmony_ci int unittest_nr, int before, int after, 20128c2ecf20Sopenharmony_ci enum overlay_type ovtype) 20138c2ecf20Sopenharmony_ci{ 20148c2ecf20Sopenharmony_ci int ret, ovcs_id; 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci /* unittest device must not be in before state */ 20178c2ecf20Sopenharmony_ci if (of_unittest_device_exists(unittest_nr, ovtype) != before) { 20188c2ecf20Sopenharmony_ci unittest(0, "%s with device @\"%s\" %s\n", 20198c2ecf20Sopenharmony_ci overlay_name_from_nr(overlay_nr), 20208c2ecf20Sopenharmony_ci unittest_path(unittest_nr, ovtype), 20218c2ecf20Sopenharmony_ci !before ? "enabled" : "disabled"); 20228c2ecf20Sopenharmony_ci return -EINVAL; 20238c2ecf20Sopenharmony_ci } 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci ovcs_id = 0; 20268c2ecf20Sopenharmony_ci ret = of_unittest_apply_overlay(overlay_nr, &ovcs_id); 20278c2ecf20Sopenharmony_ci if (ret != 0) { 20288c2ecf20Sopenharmony_ci /* of_unittest_apply_overlay already called unittest() */ 20298c2ecf20Sopenharmony_ci return ret; 20308c2ecf20Sopenharmony_ci } 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci /* unittest device must be to set to after state */ 20338c2ecf20Sopenharmony_ci if (of_unittest_device_exists(unittest_nr, ovtype) != after) { 20348c2ecf20Sopenharmony_ci unittest(0, "%s failed to create @\"%s\" %s\n", 20358c2ecf20Sopenharmony_ci overlay_name_from_nr(overlay_nr), 20368c2ecf20Sopenharmony_ci unittest_path(unittest_nr, ovtype), 20378c2ecf20Sopenharmony_ci !after ? "enabled" : "disabled"); 20388c2ecf20Sopenharmony_ci return -EINVAL; 20398c2ecf20Sopenharmony_ci } 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci return 0; 20428c2ecf20Sopenharmony_ci} 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci/* apply an overlay and then revert it while checking before, after states */ 20458c2ecf20Sopenharmony_cistatic int __init of_unittest_apply_revert_overlay_check(int overlay_nr, 20468c2ecf20Sopenharmony_ci int unittest_nr, int before, int after, 20478c2ecf20Sopenharmony_ci enum overlay_type ovtype) 20488c2ecf20Sopenharmony_ci{ 20498c2ecf20Sopenharmony_ci int ret, ovcs_id, save_id; 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci /* unittest device must be in before state */ 20528c2ecf20Sopenharmony_ci if (of_unittest_device_exists(unittest_nr, ovtype) != before) { 20538c2ecf20Sopenharmony_ci unittest(0, "%s with device @\"%s\" %s\n", 20548c2ecf20Sopenharmony_ci overlay_name_from_nr(overlay_nr), 20558c2ecf20Sopenharmony_ci unittest_path(unittest_nr, ovtype), 20568c2ecf20Sopenharmony_ci !before ? "enabled" : "disabled"); 20578c2ecf20Sopenharmony_ci return -EINVAL; 20588c2ecf20Sopenharmony_ci } 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci /* apply the overlay */ 20618c2ecf20Sopenharmony_ci ovcs_id = 0; 20628c2ecf20Sopenharmony_ci ret = of_unittest_apply_overlay(overlay_nr, &ovcs_id); 20638c2ecf20Sopenharmony_ci if (ret != 0) { 20648c2ecf20Sopenharmony_ci /* of_unittest_apply_overlay already called unittest() */ 20658c2ecf20Sopenharmony_ci return ret; 20668c2ecf20Sopenharmony_ci } 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci /* unittest device must be in after state */ 20698c2ecf20Sopenharmony_ci if (of_unittest_device_exists(unittest_nr, ovtype) != after) { 20708c2ecf20Sopenharmony_ci unittest(0, "%s failed to create @\"%s\" %s\n", 20718c2ecf20Sopenharmony_ci overlay_name_from_nr(overlay_nr), 20728c2ecf20Sopenharmony_ci unittest_path(unittest_nr, ovtype), 20738c2ecf20Sopenharmony_ci !after ? "enabled" : "disabled"); 20748c2ecf20Sopenharmony_ci return -EINVAL; 20758c2ecf20Sopenharmony_ci } 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci save_id = ovcs_id; 20788c2ecf20Sopenharmony_ci ret = of_overlay_remove(&ovcs_id); 20798c2ecf20Sopenharmony_ci if (ret != 0) { 20808c2ecf20Sopenharmony_ci unittest(0, "%s failed to be destroyed @\"%s\"\n", 20818c2ecf20Sopenharmony_ci overlay_name_from_nr(overlay_nr), 20828c2ecf20Sopenharmony_ci unittest_path(unittest_nr, ovtype)); 20838c2ecf20Sopenharmony_ci return ret; 20848c2ecf20Sopenharmony_ci } 20858c2ecf20Sopenharmony_ci of_unittest_untrack_overlay(save_id); 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci /* unittest device must be again in before state */ 20888c2ecf20Sopenharmony_ci if (of_unittest_device_exists(unittest_nr, ovtype) != before) { 20898c2ecf20Sopenharmony_ci unittest(0, "%s with device @\"%s\" %s\n", 20908c2ecf20Sopenharmony_ci overlay_name_from_nr(overlay_nr), 20918c2ecf20Sopenharmony_ci unittest_path(unittest_nr, ovtype), 20928c2ecf20Sopenharmony_ci !before ? "enabled" : "disabled"); 20938c2ecf20Sopenharmony_ci return -EINVAL; 20948c2ecf20Sopenharmony_ci } 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci return 0; 20978c2ecf20Sopenharmony_ci} 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci/* test activation of device */ 21008c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_0(void) 21018c2ecf20Sopenharmony_ci{ 21028c2ecf20Sopenharmony_ci int ret; 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 21058c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest0/status"); 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci /* device should enable */ 21088c2ecf20Sopenharmony_ci ret = of_unittest_apply_overlay_check(0, 0, 0, 1, PDEV_OVERLAY); 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 21118c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest0/status"); 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci if (ret) 21148c2ecf20Sopenharmony_ci return; 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci unittest(1, "overlay test %d passed\n", 0); 21178c2ecf20Sopenharmony_ci} 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci/* test deactivation of device */ 21208c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_1(void) 21218c2ecf20Sopenharmony_ci{ 21228c2ecf20Sopenharmony_ci int ret; 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 21258c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest1/status"); 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci /* device should disable */ 21288c2ecf20Sopenharmony_ci ret = of_unittest_apply_overlay_check(1, 1, 1, 0, PDEV_OVERLAY); 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 21318c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest1/status"); 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci if (ret) 21348c2ecf20Sopenharmony_ci return; 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_ci unittest(1, "overlay test %d passed\n", 1); 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci} 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci/* test activation of device */ 21418c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_2(void) 21428c2ecf20Sopenharmony_ci{ 21438c2ecf20Sopenharmony_ci int ret; 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 21468c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest2/status"); 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci /* device should enable */ 21498c2ecf20Sopenharmony_ci ret = of_unittest_apply_overlay_check(2, 2, 0, 1, PDEV_OVERLAY); 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 21528c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest2/status"); 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci if (ret) 21558c2ecf20Sopenharmony_ci return; 21568c2ecf20Sopenharmony_ci unittest(1, "overlay test %d passed\n", 2); 21578c2ecf20Sopenharmony_ci} 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci/* test deactivation of device */ 21608c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_3(void) 21618c2ecf20Sopenharmony_ci{ 21628c2ecf20Sopenharmony_ci int ret; 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 21658c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest3/status"); 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci /* device should disable */ 21688c2ecf20Sopenharmony_ci ret = of_unittest_apply_overlay_check(3, 3, 1, 0, PDEV_OVERLAY); 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 21718c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest3/status"); 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci if (ret) 21748c2ecf20Sopenharmony_ci return; 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci unittest(1, "overlay test %d passed\n", 3); 21778c2ecf20Sopenharmony_ci} 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci/* test activation of a full device node */ 21808c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_4(void) 21818c2ecf20Sopenharmony_ci{ 21828c2ecf20Sopenharmony_ci /* device should disable */ 21838c2ecf20Sopenharmony_ci if (of_unittest_apply_overlay_check(4, 4, 0, 1, PDEV_OVERLAY)) 21848c2ecf20Sopenharmony_ci return; 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci unittest(1, "overlay test %d passed\n", 4); 21878c2ecf20Sopenharmony_ci} 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci/* test overlay apply/revert sequence */ 21908c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_5(void) 21918c2ecf20Sopenharmony_ci{ 21928c2ecf20Sopenharmony_ci int ret; 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 21958c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest5/status"); 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci /* device should disable */ 21988c2ecf20Sopenharmony_ci ret = of_unittest_apply_revert_overlay_check(5, 5, 0, 1, PDEV_OVERLAY); 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 22018c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest5/status"); 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci if (ret) 22048c2ecf20Sopenharmony_ci return; 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci unittest(1, "overlay test %d passed\n", 5); 22078c2ecf20Sopenharmony_ci} 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci/* test overlay application in sequence */ 22108c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_6(void) 22118c2ecf20Sopenharmony_ci{ 22128c2ecf20Sopenharmony_ci int i, ov_id[2], ovcs_id; 22138c2ecf20Sopenharmony_ci int overlay_nr = 6, unittest_nr = 6; 22148c2ecf20Sopenharmony_ci int before = 0, after = 1; 22158c2ecf20Sopenharmony_ci const char *overlay_name; 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci int ret; 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci /* unittest device must be in before state */ 22208c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 22218c2ecf20Sopenharmony_ci if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY) 22228c2ecf20Sopenharmony_ci != before) { 22238c2ecf20Sopenharmony_ci unittest(0, "%s with device @\"%s\" %s\n", 22248c2ecf20Sopenharmony_ci overlay_name_from_nr(overlay_nr + i), 22258c2ecf20Sopenharmony_ci unittest_path(unittest_nr + i, 22268c2ecf20Sopenharmony_ci PDEV_OVERLAY), 22278c2ecf20Sopenharmony_ci !before ? "enabled" : "disabled"); 22288c2ecf20Sopenharmony_ci return; 22298c2ecf20Sopenharmony_ci } 22308c2ecf20Sopenharmony_ci } 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci /* apply the overlays */ 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 22358c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest6/status"); 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci overlay_name = overlay_name_from_nr(overlay_nr + 0); 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci ret = overlay_data_apply(overlay_name, &ovcs_id); 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci if (!ret) { 22428c2ecf20Sopenharmony_ci unittest(0, "could not apply overlay \"%s\"\n", overlay_name); 22438c2ecf20Sopenharmony_ci return; 22448c2ecf20Sopenharmony_ci } 22458c2ecf20Sopenharmony_ci ov_id[0] = ovcs_id; 22468c2ecf20Sopenharmony_ci of_unittest_track_overlay(ov_id[0]); 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 22498c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest6/status"); 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 22528c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest7/status"); 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci overlay_name = overlay_name_from_nr(overlay_nr + 1); 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_ci ret = overlay_data_apply(overlay_name, &ovcs_id); 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci if (!ret) { 22598c2ecf20Sopenharmony_ci unittest(0, "could not apply overlay \"%s\"\n", overlay_name); 22608c2ecf20Sopenharmony_ci return; 22618c2ecf20Sopenharmony_ci } 22628c2ecf20Sopenharmony_ci ov_id[1] = ovcs_id; 22638c2ecf20Sopenharmony_ci of_unittest_track_overlay(ov_id[1]); 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 22668c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest7/status"); 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 22708c2ecf20Sopenharmony_ci /* unittest device must be in after state */ 22718c2ecf20Sopenharmony_ci if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY) 22728c2ecf20Sopenharmony_ci != after) { 22738c2ecf20Sopenharmony_ci unittest(0, "overlay @\"%s\" failed @\"%s\" %s\n", 22748c2ecf20Sopenharmony_ci overlay_name_from_nr(overlay_nr + i), 22758c2ecf20Sopenharmony_ci unittest_path(unittest_nr + i, 22768c2ecf20Sopenharmony_ci PDEV_OVERLAY), 22778c2ecf20Sopenharmony_ci !after ? "enabled" : "disabled"); 22788c2ecf20Sopenharmony_ci return; 22798c2ecf20Sopenharmony_ci } 22808c2ecf20Sopenharmony_ci } 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci for (i = 1; i >= 0; i--) { 22838c2ecf20Sopenharmony_ci ovcs_id = ov_id[i]; 22848c2ecf20Sopenharmony_ci if (of_overlay_remove(&ovcs_id)) { 22858c2ecf20Sopenharmony_ci unittest(0, "%s failed destroy @\"%s\"\n", 22868c2ecf20Sopenharmony_ci overlay_name_from_nr(overlay_nr + i), 22878c2ecf20Sopenharmony_ci unittest_path(unittest_nr + i, 22888c2ecf20Sopenharmony_ci PDEV_OVERLAY)); 22898c2ecf20Sopenharmony_ci return; 22908c2ecf20Sopenharmony_ci } 22918c2ecf20Sopenharmony_ci of_unittest_untrack_overlay(ov_id[i]); 22928c2ecf20Sopenharmony_ci } 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 22958c2ecf20Sopenharmony_ci /* unittest device must be again in before state */ 22968c2ecf20Sopenharmony_ci if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY) 22978c2ecf20Sopenharmony_ci != before) { 22988c2ecf20Sopenharmony_ci unittest(0, "%s with device @\"%s\" %s\n", 22998c2ecf20Sopenharmony_ci overlay_name_from_nr(overlay_nr + i), 23008c2ecf20Sopenharmony_ci unittest_path(unittest_nr + i, 23018c2ecf20Sopenharmony_ci PDEV_OVERLAY), 23028c2ecf20Sopenharmony_ci !before ? "enabled" : "disabled"); 23038c2ecf20Sopenharmony_ci return; 23048c2ecf20Sopenharmony_ci } 23058c2ecf20Sopenharmony_ci } 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci unittest(1, "overlay test %d passed\n", 6); 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci} 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_ci/* test overlay application in sequence */ 23128c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_8(void) 23138c2ecf20Sopenharmony_ci{ 23148c2ecf20Sopenharmony_ci int i, ov_id[2], ovcs_id; 23158c2ecf20Sopenharmony_ci int overlay_nr = 8, unittest_nr = 8; 23168c2ecf20Sopenharmony_ci const char *overlay_name; 23178c2ecf20Sopenharmony_ci int ret; 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci /* we don't care about device state in this test */ 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 23228c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest8/status"); 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci overlay_name = overlay_name_from_nr(overlay_nr + 0); 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci ret = overlay_data_apply(overlay_name, &ovcs_id); 23278c2ecf20Sopenharmony_ci if (!ret) 23288c2ecf20Sopenharmony_ci unittest(0, "could not apply overlay \"%s\"\n", overlay_name); 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 23318c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest8/status"); 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci if (!ret) 23348c2ecf20Sopenharmony_ci return; 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci ov_id[0] = ovcs_id; 23378c2ecf20Sopenharmony_ci of_unittest_track_overlay(ov_id[0]); 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci overlay_name = overlay_name_from_nr(overlay_nr + 1); 23408c2ecf20Sopenharmony_ci 23418c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 23428c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest8/property-foo"); 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci /* apply the overlays */ 23458c2ecf20Sopenharmony_ci ret = overlay_data_apply(overlay_name, &ovcs_id); 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 23488c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest8/property-foo"); 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci if (!ret) { 23518c2ecf20Sopenharmony_ci unittest(0, "could not apply overlay \"%s\"\n", overlay_name); 23528c2ecf20Sopenharmony_ci return; 23538c2ecf20Sopenharmony_ci } 23548c2ecf20Sopenharmony_ci 23558c2ecf20Sopenharmony_ci ov_id[1] = ovcs_id; 23568c2ecf20Sopenharmony_ci of_unittest_track_overlay(ov_id[1]); 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci /* now try to remove first overlay (it should fail) */ 23598c2ecf20Sopenharmony_ci ovcs_id = ov_id[0]; 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 23628c2ecf20Sopenharmony_ci "OF: overlay: node_overlaps_later_cs: #6 overlaps with #7 @/testcase-data/overlay-node/test-bus/test-unittest8"); 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 23658c2ecf20Sopenharmony_ci "OF: overlay: overlay #6 is not topmost"); 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci ret = of_overlay_remove(&ovcs_id); 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 23708c2ecf20Sopenharmony_ci "OF: overlay: overlay #6 is not topmost"); 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 23738c2ecf20Sopenharmony_ci "OF: overlay: node_overlaps_later_cs: #6 overlaps with #7 @/testcase-data/overlay-node/test-bus/test-unittest8"); 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci if (!ret) { 23768c2ecf20Sopenharmony_ci unittest(0, "%s was destroyed @\"%s\"\n", 23778c2ecf20Sopenharmony_ci overlay_name_from_nr(overlay_nr + 0), 23788c2ecf20Sopenharmony_ci unittest_path(unittest_nr, 23798c2ecf20Sopenharmony_ci PDEV_OVERLAY)); 23808c2ecf20Sopenharmony_ci return; 23818c2ecf20Sopenharmony_ci } 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci /* removing them in order should work */ 23848c2ecf20Sopenharmony_ci for (i = 1; i >= 0; i--) { 23858c2ecf20Sopenharmony_ci ovcs_id = ov_id[i]; 23868c2ecf20Sopenharmony_ci if (of_overlay_remove(&ovcs_id)) { 23878c2ecf20Sopenharmony_ci unittest(0, "%s not destroyed @\"%s\"\n", 23888c2ecf20Sopenharmony_ci overlay_name_from_nr(overlay_nr + i), 23898c2ecf20Sopenharmony_ci unittest_path(unittest_nr, 23908c2ecf20Sopenharmony_ci PDEV_OVERLAY)); 23918c2ecf20Sopenharmony_ci return; 23928c2ecf20Sopenharmony_ci } 23938c2ecf20Sopenharmony_ci of_unittest_untrack_overlay(ov_id[i]); 23948c2ecf20Sopenharmony_ci } 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci unittest(1, "overlay test %d passed\n", 8); 23978c2ecf20Sopenharmony_ci} 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci/* test insertion of a bus with parent devices */ 24008c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_10(void) 24018c2ecf20Sopenharmony_ci{ 24028c2ecf20Sopenharmony_ci int ret; 24038c2ecf20Sopenharmony_ci char *child_path; 24048c2ecf20Sopenharmony_ci 24058c2ecf20Sopenharmony_ci /* device should disable */ 24068c2ecf20Sopenharmony_ci ret = of_unittest_apply_overlay_check(10, 10, 0, 1, PDEV_OVERLAY); 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci if (unittest(ret == 0, 24098c2ecf20Sopenharmony_ci "overlay test %d failed; overlay application\n", 10)) 24108c2ecf20Sopenharmony_ci return; 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci child_path = kasprintf(GFP_KERNEL, "%s/test-unittest101", 24138c2ecf20Sopenharmony_ci unittest_path(10, PDEV_OVERLAY)); 24148c2ecf20Sopenharmony_ci if (unittest(child_path, "overlay test %d failed; kasprintf\n", 10)) 24158c2ecf20Sopenharmony_ci return; 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci ret = of_path_device_type_exists(child_path, PDEV_OVERLAY); 24188c2ecf20Sopenharmony_ci kfree(child_path); 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci unittest(ret, "overlay test %d failed; no child device\n", 10); 24218c2ecf20Sopenharmony_ci} 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_ci/* test insertion of a bus with parent devices (and revert) */ 24248c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_11(void) 24258c2ecf20Sopenharmony_ci{ 24268c2ecf20Sopenharmony_ci int ret; 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci /* device should disable */ 24298c2ecf20Sopenharmony_ci ret = of_unittest_apply_revert_overlay_check(11, 11, 0, 1, 24308c2ecf20Sopenharmony_ci PDEV_OVERLAY); 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci unittest(ret == 0, "overlay test %d failed; overlay apply\n", 11); 24338c2ecf20Sopenharmony_ci} 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci#if IS_BUILTIN(CONFIG_I2C) && IS_ENABLED(CONFIG_OF_OVERLAY) 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_cistruct unittest_i2c_bus_data { 24388c2ecf20Sopenharmony_ci struct platform_device *pdev; 24398c2ecf20Sopenharmony_ci struct i2c_adapter adap; 24408c2ecf20Sopenharmony_ci}; 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_cistatic int unittest_i2c_master_xfer(struct i2c_adapter *adap, 24438c2ecf20Sopenharmony_ci struct i2c_msg *msgs, int num) 24448c2ecf20Sopenharmony_ci{ 24458c2ecf20Sopenharmony_ci struct unittest_i2c_bus_data *std = i2c_get_adapdata(adap); 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci (void)std; 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_ci return num; 24508c2ecf20Sopenharmony_ci} 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_cistatic u32 unittest_i2c_functionality(struct i2c_adapter *adap) 24538c2ecf20Sopenharmony_ci{ 24548c2ecf20Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 24558c2ecf20Sopenharmony_ci} 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_cistatic const struct i2c_algorithm unittest_i2c_algo = { 24588c2ecf20Sopenharmony_ci .master_xfer = unittest_i2c_master_xfer, 24598c2ecf20Sopenharmony_ci .functionality = unittest_i2c_functionality, 24608c2ecf20Sopenharmony_ci}; 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_cistatic int unittest_i2c_bus_probe(struct platform_device *pdev) 24638c2ecf20Sopenharmony_ci{ 24648c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 24658c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 24668c2ecf20Sopenharmony_ci struct unittest_i2c_bus_data *std; 24678c2ecf20Sopenharmony_ci struct i2c_adapter *adap; 24688c2ecf20Sopenharmony_ci int ret; 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci if (np == NULL) { 24718c2ecf20Sopenharmony_ci dev_err(dev, "No OF data for device\n"); 24728c2ecf20Sopenharmony_ci return -EINVAL; 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_ci } 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_ci dev_dbg(dev, "%s for node @%pOF\n", __func__, np); 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci std = devm_kzalloc(dev, sizeof(*std), GFP_KERNEL); 24798c2ecf20Sopenharmony_ci if (!std) 24808c2ecf20Sopenharmony_ci return -ENOMEM; 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci /* link them together */ 24838c2ecf20Sopenharmony_ci std->pdev = pdev; 24848c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, std); 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci adap = &std->adap; 24878c2ecf20Sopenharmony_ci i2c_set_adapdata(adap, std); 24888c2ecf20Sopenharmony_ci adap->nr = -1; 24898c2ecf20Sopenharmony_ci strlcpy(adap->name, pdev->name, sizeof(adap->name)); 24908c2ecf20Sopenharmony_ci adap->class = I2C_CLASS_DEPRECATED; 24918c2ecf20Sopenharmony_ci adap->algo = &unittest_i2c_algo; 24928c2ecf20Sopenharmony_ci adap->dev.parent = dev; 24938c2ecf20Sopenharmony_ci adap->dev.of_node = dev->of_node; 24948c2ecf20Sopenharmony_ci adap->timeout = 5 * HZ; 24958c2ecf20Sopenharmony_ci adap->retries = 3; 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci ret = i2c_add_numbered_adapter(adap); 24988c2ecf20Sopenharmony_ci if (ret != 0) { 24998c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add I2C adapter\n"); 25008c2ecf20Sopenharmony_ci return ret; 25018c2ecf20Sopenharmony_ci } 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci return 0; 25048c2ecf20Sopenharmony_ci} 25058c2ecf20Sopenharmony_ci 25068c2ecf20Sopenharmony_cistatic int unittest_i2c_bus_remove(struct platform_device *pdev) 25078c2ecf20Sopenharmony_ci{ 25088c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 25098c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 25108c2ecf20Sopenharmony_ci struct unittest_i2c_bus_data *std = platform_get_drvdata(pdev); 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci dev_dbg(dev, "%s for node @%pOF\n", __func__, np); 25138c2ecf20Sopenharmony_ci i2c_del_adapter(&std->adap); 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci return 0; 25168c2ecf20Sopenharmony_ci} 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_cistatic const struct of_device_id unittest_i2c_bus_match[] = { 25198c2ecf20Sopenharmony_ci { .compatible = "unittest-i2c-bus", }, 25208c2ecf20Sopenharmony_ci {}, 25218c2ecf20Sopenharmony_ci}; 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_cistatic struct platform_driver unittest_i2c_bus_driver = { 25248c2ecf20Sopenharmony_ci .probe = unittest_i2c_bus_probe, 25258c2ecf20Sopenharmony_ci .remove = unittest_i2c_bus_remove, 25268c2ecf20Sopenharmony_ci .driver = { 25278c2ecf20Sopenharmony_ci .name = "unittest-i2c-bus", 25288c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(unittest_i2c_bus_match), 25298c2ecf20Sopenharmony_ci }, 25308c2ecf20Sopenharmony_ci}; 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_cistatic int unittest_i2c_dev_probe(struct i2c_client *client, 25338c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 25348c2ecf20Sopenharmony_ci{ 25358c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 25368c2ecf20Sopenharmony_ci struct device_node *np = client->dev.of_node; 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ci if (!np) { 25398c2ecf20Sopenharmony_ci dev_err(dev, "No OF node\n"); 25408c2ecf20Sopenharmony_ci return -EINVAL; 25418c2ecf20Sopenharmony_ci } 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci dev_dbg(dev, "%s for node @%pOF\n", __func__, np); 25448c2ecf20Sopenharmony_ci 25458c2ecf20Sopenharmony_ci return 0; 25468c2ecf20Sopenharmony_ci}; 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_cistatic int unittest_i2c_dev_remove(struct i2c_client *client) 25498c2ecf20Sopenharmony_ci{ 25508c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 25518c2ecf20Sopenharmony_ci struct device_node *np = client->dev.of_node; 25528c2ecf20Sopenharmony_ci 25538c2ecf20Sopenharmony_ci dev_dbg(dev, "%s for node @%pOF\n", __func__, np); 25548c2ecf20Sopenharmony_ci return 0; 25558c2ecf20Sopenharmony_ci} 25568c2ecf20Sopenharmony_ci 25578c2ecf20Sopenharmony_cistatic const struct i2c_device_id unittest_i2c_dev_id[] = { 25588c2ecf20Sopenharmony_ci { .name = "unittest-i2c-dev" }, 25598c2ecf20Sopenharmony_ci { } 25608c2ecf20Sopenharmony_ci}; 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_cistatic struct i2c_driver unittest_i2c_dev_driver = { 25638c2ecf20Sopenharmony_ci .driver = { 25648c2ecf20Sopenharmony_ci .name = "unittest-i2c-dev", 25658c2ecf20Sopenharmony_ci }, 25668c2ecf20Sopenharmony_ci .probe = unittest_i2c_dev_probe, 25678c2ecf20Sopenharmony_ci .remove = unittest_i2c_dev_remove, 25688c2ecf20Sopenharmony_ci .id_table = unittest_i2c_dev_id, 25698c2ecf20Sopenharmony_ci}; 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci#if IS_BUILTIN(CONFIG_I2C_MUX) 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_cistatic int unittest_i2c_mux_select_chan(struct i2c_mux_core *muxc, u32 chan) 25748c2ecf20Sopenharmony_ci{ 25758c2ecf20Sopenharmony_ci return 0; 25768c2ecf20Sopenharmony_ci} 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_cistatic int unittest_i2c_mux_probe(struct i2c_client *client, 25798c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 25808c2ecf20Sopenharmony_ci{ 25818c2ecf20Sopenharmony_ci int i, nchans; 25828c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 25838c2ecf20Sopenharmony_ci struct i2c_adapter *adap = client->adapter; 25848c2ecf20Sopenharmony_ci struct device_node *np = client->dev.of_node, *child; 25858c2ecf20Sopenharmony_ci struct i2c_mux_core *muxc; 25868c2ecf20Sopenharmony_ci u32 reg, max_reg; 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci dev_dbg(dev, "%s for node @%pOF\n", __func__, np); 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci if (!np) { 25918c2ecf20Sopenharmony_ci dev_err(dev, "No OF node\n"); 25928c2ecf20Sopenharmony_ci return -EINVAL; 25938c2ecf20Sopenharmony_ci } 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci max_reg = (u32)-1; 25968c2ecf20Sopenharmony_ci for_each_child_of_node(np, child) { 25978c2ecf20Sopenharmony_ci if (of_property_read_u32(child, "reg", ®)) 25988c2ecf20Sopenharmony_ci continue; 25998c2ecf20Sopenharmony_ci if (max_reg == (u32)-1 || reg > max_reg) 26008c2ecf20Sopenharmony_ci max_reg = reg; 26018c2ecf20Sopenharmony_ci } 26028c2ecf20Sopenharmony_ci nchans = max_reg == (u32)-1 ? 0 : max_reg + 1; 26038c2ecf20Sopenharmony_ci if (nchans == 0) { 26048c2ecf20Sopenharmony_ci dev_err(dev, "No channels\n"); 26058c2ecf20Sopenharmony_ci return -EINVAL; 26068c2ecf20Sopenharmony_ci } 26078c2ecf20Sopenharmony_ci 26088c2ecf20Sopenharmony_ci muxc = i2c_mux_alloc(adap, dev, nchans, 0, 0, 26098c2ecf20Sopenharmony_ci unittest_i2c_mux_select_chan, NULL); 26108c2ecf20Sopenharmony_ci if (!muxc) 26118c2ecf20Sopenharmony_ci return -ENOMEM; 26128c2ecf20Sopenharmony_ci for (i = 0; i < nchans; i++) { 26138c2ecf20Sopenharmony_ci if (i2c_mux_add_adapter(muxc, 0, i, 0)) { 26148c2ecf20Sopenharmony_ci dev_err(dev, "Failed to register mux #%d\n", i); 26158c2ecf20Sopenharmony_ci i2c_mux_del_adapters(muxc); 26168c2ecf20Sopenharmony_ci return -ENODEV; 26178c2ecf20Sopenharmony_ci } 26188c2ecf20Sopenharmony_ci } 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci i2c_set_clientdata(client, muxc); 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_ci return 0; 26238c2ecf20Sopenharmony_ci}; 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_cistatic int unittest_i2c_mux_remove(struct i2c_client *client) 26268c2ecf20Sopenharmony_ci{ 26278c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 26288c2ecf20Sopenharmony_ci struct device_node *np = client->dev.of_node; 26298c2ecf20Sopenharmony_ci struct i2c_mux_core *muxc = i2c_get_clientdata(client); 26308c2ecf20Sopenharmony_ci 26318c2ecf20Sopenharmony_ci dev_dbg(dev, "%s for node @%pOF\n", __func__, np); 26328c2ecf20Sopenharmony_ci i2c_mux_del_adapters(muxc); 26338c2ecf20Sopenharmony_ci return 0; 26348c2ecf20Sopenharmony_ci} 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_cistatic const struct i2c_device_id unittest_i2c_mux_id[] = { 26378c2ecf20Sopenharmony_ci { .name = "unittest-i2c-mux" }, 26388c2ecf20Sopenharmony_ci { } 26398c2ecf20Sopenharmony_ci}; 26408c2ecf20Sopenharmony_ci 26418c2ecf20Sopenharmony_cistatic struct i2c_driver unittest_i2c_mux_driver = { 26428c2ecf20Sopenharmony_ci .driver = { 26438c2ecf20Sopenharmony_ci .name = "unittest-i2c-mux", 26448c2ecf20Sopenharmony_ci }, 26458c2ecf20Sopenharmony_ci .probe = unittest_i2c_mux_probe, 26468c2ecf20Sopenharmony_ci .remove = unittest_i2c_mux_remove, 26478c2ecf20Sopenharmony_ci .id_table = unittest_i2c_mux_id, 26488c2ecf20Sopenharmony_ci}; 26498c2ecf20Sopenharmony_ci 26508c2ecf20Sopenharmony_ci#endif 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_cistatic int of_unittest_overlay_i2c_init(void) 26538c2ecf20Sopenharmony_ci{ 26548c2ecf20Sopenharmony_ci int ret; 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_ci ret = i2c_add_driver(&unittest_i2c_dev_driver); 26578c2ecf20Sopenharmony_ci if (unittest(ret == 0, 26588c2ecf20Sopenharmony_ci "could not register unittest i2c device driver\n")) 26598c2ecf20Sopenharmony_ci return ret; 26608c2ecf20Sopenharmony_ci 26618c2ecf20Sopenharmony_ci ret = platform_driver_register(&unittest_i2c_bus_driver); 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_ci if (unittest(ret == 0, 26648c2ecf20Sopenharmony_ci "could not register unittest i2c bus driver\n")) 26658c2ecf20Sopenharmony_ci return ret; 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci#if IS_BUILTIN(CONFIG_I2C_MUX) 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 26708c2ecf20Sopenharmony_ci "i2c i2c-1: Added multiplexed i2c bus 2"); 26718c2ecf20Sopenharmony_ci 26728c2ecf20Sopenharmony_ci ret = i2c_add_driver(&unittest_i2c_mux_driver); 26738c2ecf20Sopenharmony_ci 26748c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 26758c2ecf20Sopenharmony_ci "i2c i2c-1: Added multiplexed i2c bus 2"); 26768c2ecf20Sopenharmony_ci 26778c2ecf20Sopenharmony_ci if (unittest(ret == 0, 26788c2ecf20Sopenharmony_ci "could not register unittest i2c mux driver\n")) 26798c2ecf20Sopenharmony_ci return ret; 26808c2ecf20Sopenharmony_ci#endif 26818c2ecf20Sopenharmony_ci 26828c2ecf20Sopenharmony_ci return 0; 26838c2ecf20Sopenharmony_ci} 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_cistatic void of_unittest_overlay_i2c_cleanup(void) 26868c2ecf20Sopenharmony_ci{ 26878c2ecf20Sopenharmony_ci#if IS_BUILTIN(CONFIG_I2C_MUX) 26888c2ecf20Sopenharmony_ci i2c_del_driver(&unittest_i2c_mux_driver); 26898c2ecf20Sopenharmony_ci#endif 26908c2ecf20Sopenharmony_ci platform_driver_unregister(&unittest_i2c_bus_driver); 26918c2ecf20Sopenharmony_ci i2c_del_driver(&unittest_i2c_dev_driver); 26928c2ecf20Sopenharmony_ci} 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_i2c_12(void) 26958c2ecf20Sopenharmony_ci{ 26968c2ecf20Sopenharmony_ci int ret; 26978c2ecf20Sopenharmony_ci 26988c2ecf20Sopenharmony_ci /* device should enable */ 26998c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 27008c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest12/status"); 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ci ret = of_unittest_apply_overlay_check(12, 12, 0, 1, I2C_OVERLAY); 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 27058c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest12/status"); 27068c2ecf20Sopenharmony_ci 27078c2ecf20Sopenharmony_ci if (ret) 27088c2ecf20Sopenharmony_ci return; 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ci unittest(1, "overlay test %d passed\n", 12); 27118c2ecf20Sopenharmony_ci} 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci/* test deactivation of device */ 27148c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_i2c_13(void) 27158c2ecf20Sopenharmony_ci{ 27168c2ecf20Sopenharmony_ci int ret; 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 27198c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest13/status"); 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_ci /* device should disable */ 27228c2ecf20Sopenharmony_ci ret = of_unittest_apply_overlay_check(13, 13, 1, 0, I2C_OVERLAY); 27238c2ecf20Sopenharmony_ci 27248c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 27258c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest13/status"); 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci if (ret) 27288c2ecf20Sopenharmony_ci return; 27298c2ecf20Sopenharmony_ci 27308c2ecf20Sopenharmony_ci unittest(1, "overlay test %d passed\n", 13); 27318c2ecf20Sopenharmony_ci} 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci/* just check for i2c mux existence */ 27348c2ecf20Sopenharmony_cistatic void of_unittest_overlay_i2c_14(void) 27358c2ecf20Sopenharmony_ci{ 27368c2ecf20Sopenharmony_ci} 27378c2ecf20Sopenharmony_ci 27388c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_i2c_15(void) 27398c2ecf20Sopenharmony_ci{ 27408c2ecf20Sopenharmony_ci int ret; 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_ci /* device should enable */ 27438c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_INFO, 27448c2ecf20Sopenharmony_ci "i2c i2c-1: Added multiplexed i2c bus 3"); 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_ci ret = of_unittest_apply_overlay_check(15, 15, 0, 1, I2C_OVERLAY); 27478c2ecf20Sopenharmony_ci 27488c2ecf20Sopenharmony_ci EXPECT_END(KERN_INFO, 27498c2ecf20Sopenharmony_ci "i2c i2c-1: Added multiplexed i2c bus 3"); 27508c2ecf20Sopenharmony_ci 27518c2ecf20Sopenharmony_ci if (ret) 27528c2ecf20Sopenharmony_ci return; 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_ci unittest(1, "overlay test %d passed\n", 15); 27558c2ecf20Sopenharmony_ci} 27568c2ecf20Sopenharmony_ci 27578c2ecf20Sopenharmony_ci#else 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_cistatic inline void of_unittest_overlay_i2c_14(void) { } 27608c2ecf20Sopenharmony_cistatic inline void of_unittest_overlay_i2c_15(void) { } 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci#endif 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay(void) 27658c2ecf20Sopenharmony_ci{ 27668c2ecf20Sopenharmony_ci struct device_node *bus_np = NULL; 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_ci if (platform_driver_register(&unittest_driver)) { 27698c2ecf20Sopenharmony_ci unittest(0, "could not register unittest driver\n"); 27708c2ecf20Sopenharmony_ci goto out; 27718c2ecf20Sopenharmony_ci } 27728c2ecf20Sopenharmony_ci 27738c2ecf20Sopenharmony_ci bus_np = of_find_node_by_path(bus_path); 27748c2ecf20Sopenharmony_ci if (bus_np == NULL) { 27758c2ecf20Sopenharmony_ci unittest(0, "could not find bus_path \"%s\"\n", bus_path); 27768c2ecf20Sopenharmony_ci goto out; 27778c2ecf20Sopenharmony_ci } 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci if (of_platform_default_populate(bus_np, NULL, NULL)) { 27808c2ecf20Sopenharmony_ci unittest(0, "could not populate bus @ \"%s\"\n", bus_path); 27818c2ecf20Sopenharmony_ci goto out; 27828c2ecf20Sopenharmony_ci } 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci if (!of_unittest_device_exists(100, PDEV_OVERLAY)) { 27858c2ecf20Sopenharmony_ci unittest(0, "could not find unittest0 @ \"%s\"\n", 27868c2ecf20Sopenharmony_ci unittest_path(100, PDEV_OVERLAY)); 27878c2ecf20Sopenharmony_ci goto out; 27888c2ecf20Sopenharmony_ci } 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_ci if (of_unittest_device_exists(101, PDEV_OVERLAY)) { 27918c2ecf20Sopenharmony_ci unittest(0, "unittest1 @ \"%s\" should not exist\n", 27928c2ecf20Sopenharmony_ci unittest_path(101, PDEV_OVERLAY)); 27938c2ecf20Sopenharmony_ci goto out; 27948c2ecf20Sopenharmony_ci } 27958c2ecf20Sopenharmony_ci 27968c2ecf20Sopenharmony_ci unittest(1, "basic infrastructure of overlays passed"); 27978c2ecf20Sopenharmony_ci 27988c2ecf20Sopenharmony_ci /* tests in sequence */ 27998c2ecf20Sopenharmony_ci of_unittest_overlay_0(); 28008c2ecf20Sopenharmony_ci of_unittest_overlay_1(); 28018c2ecf20Sopenharmony_ci of_unittest_overlay_2(); 28028c2ecf20Sopenharmony_ci of_unittest_overlay_3(); 28038c2ecf20Sopenharmony_ci of_unittest_overlay_4(); 28048c2ecf20Sopenharmony_ci of_unittest_overlay_5(); 28058c2ecf20Sopenharmony_ci of_unittest_overlay_6(); 28068c2ecf20Sopenharmony_ci of_unittest_overlay_8(); 28078c2ecf20Sopenharmony_ci 28088c2ecf20Sopenharmony_ci of_unittest_overlay_10(); 28098c2ecf20Sopenharmony_ci of_unittest_overlay_11(); 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci#if IS_BUILTIN(CONFIG_I2C) 28128c2ecf20Sopenharmony_ci if (unittest(of_unittest_overlay_i2c_init() == 0, "i2c init failed\n")) 28138c2ecf20Sopenharmony_ci goto out; 28148c2ecf20Sopenharmony_ci 28158c2ecf20Sopenharmony_ci of_unittest_overlay_i2c_12(); 28168c2ecf20Sopenharmony_ci of_unittest_overlay_i2c_13(); 28178c2ecf20Sopenharmony_ci of_unittest_overlay_i2c_14(); 28188c2ecf20Sopenharmony_ci of_unittest_overlay_i2c_15(); 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_ci of_unittest_overlay_i2c_cleanup(); 28218c2ecf20Sopenharmony_ci#endif 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_ci of_unittest_overlay_gpio(); 28248c2ecf20Sopenharmony_ci 28258c2ecf20Sopenharmony_ci of_unittest_destroy_tracked_overlays(); 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ciout: 28288c2ecf20Sopenharmony_ci of_node_put(bus_np); 28298c2ecf20Sopenharmony_ci} 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci#else 28328c2ecf20Sopenharmony_cistatic inline void __init of_unittest_overlay(void) { } 28338c2ecf20Sopenharmony_ci#endif 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_ci#ifdef CONFIG_OF_OVERLAY 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_ci/* 28388c2ecf20Sopenharmony_ci * __dtb_ot_begin[] and __dtb_ot_end[] are created by cmd_dt_S_dtb 28398c2ecf20Sopenharmony_ci * in scripts/Makefile.lib 28408c2ecf20Sopenharmony_ci */ 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_ci#define OVERLAY_INFO_EXTERN(name) \ 28438c2ecf20Sopenharmony_ci extern uint8_t __dtb_##name##_begin[]; \ 28448c2ecf20Sopenharmony_ci extern uint8_t __dtb_##name##_end[] 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci#define OVERLAY_INFO(overlay_name, expected) \ 28478c2ecf20Sopenharmony_ci{ .dtb_begin = __dtb_##overlay_name##_begin, \ 28488c2ecf20Sopenharmony_ci .dtb_end = __dtb_##overlay_name##_end, \ 28498c2ecf20Sopenharmony_ci .expected_result = expected, \ 28508c2ecf20Sopenharmony_ci .name = #overlay_name, \ 28518c2ecf20Sopenharmony_ci} 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_cistruct overlay_info { 28548c2ecf20Sopenharmony_ci uint8_t *dtb_begin; 28558c2ecf20Sopenharmony_ci uint8_t *dtb_end; 28568c2ecf20Sopenharmony_ci int expected_result; 28578c2ecf20Sopenharmony_ci int overlay_id; 28588c2ecf20Sopenharmony_ci char *name; 28598c2ecf20Sopenharmony_ci}; 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_base); 28628c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay); 28638c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_0); 28648c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_1); 28658c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_2); 28668c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_3); 28678c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_4); 28688c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_5); 28698c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_6); 28708c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_7); 28718c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_8); 28728c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_9); 28738c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_10); 28748c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_11); 28758c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_12); 28768c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_13); 28778c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_15); 28788c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_gpio_01); 28798c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_gpio_02a); 28808c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_gpio_02b); 28818c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_gpio_03); 28828c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_gpio_04a); 28838c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_gpio_04b); 28848c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_bad_add_dup_node); 28858c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_bad_add_dup_prop); 28868c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_bad_phandle); 28878c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_bad_symbol); 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_ci/* entries found by name */ 28908c2ecf20Sopenharmony_cistatic struct overlay_info overlays[] = { 28918c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_base, -9999), 28928c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay, 0), 28938c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_0, 0), 28948c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_1, 0), 28958c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_2, 0), 28968c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_3, 0), 28978c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_4, 0), 28988c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_5, 0), 28998c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_6, 0), 29008c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_7, 0), 29018c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_8, 0), 29028c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_9, 0), 29038c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_10, 0), 29048c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_11, 0), 29058c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_12, 0), 29068c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_13, 0), 29078c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_15, 0), 29088c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_gpio_01, 0), 29098c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_gpio_02a, 0), 29108c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_gpio_02b, 0), 29118c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_gpio_03, 0), 29128c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_gpio_04a, 0), 29138c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_gpio_04b, 0), 29148c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_bad_add_dup_node, -EINVAL), 29158c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_bad_add_dup_prop, -EINVAL), 29168c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_bad_phandle, -EINVAL), 29178c2ecf20Sopenharmony_ci OVERLAY_INFO(overlay_bad_symbol, -EINVAL), 29188c2ecf20Sopenharmony_ci /* end marker */ 29198c2ecf20Sopenharmony_ci {.dtb_begin = NULL, .dtb_end = NULL, .expected_result = 0, .name = NULL} 29208c2ecf20Sopenharmony_ci}; 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_cistatic struct device_node *overlay_base_root; 29238c2ecf20Sopenharmony_ci 29248c2ecf20Sopenharmony_cistatic void * __init dt_alloc_memory(u64 size, u64 align) 29258c2ecf20Sopenharmony_ci{ 29268c2ecf20Sopenharmony_ci void *ptr = memblock_alloc(size, align); 29278c2ecf20Sopenharmony_ci 29288c2ecf20Sopenharmony_ci if (!ptr) 29298c2ecf20Sopenharmony_ci panic("%s: Failed to allocate %llu bytes align=0x%llx\n", 29308c2ecf20Sopenharmony_ci __func__, size, align); 29318c2ecf20Sopenharmony_ci 29328c2ecf20Sopenharmony_ci return ptr; 29338c2ecf20Sopenharmony_ci} 29348c2ecf20Sopenharmony_ci 29358c2ecf20Sopenharmony_ci/* 29368c2ecf20Sopenharmony_ci * Create base device tree for the overlay unittest. 29378c2ecf20Sopenharmony_ci * 29388c2ecf20Sopenharmony_ci * This is called from very early boot code. 29398c2ecf20Sopenharmony_ci * 29408c2ecf20Sopenharmony_ci * Do as much as possible the same way as done in __unflatten_device_tree 29418c2ecf20Sopenharmony_ci * and other early boot steps for the normal FDT so that the overlay base 29428c2ecf20Sopenharmony_ci * unflattened tree will have the same characteristics as the real tree 29438c2ecf20Sopenharmony_ci * (such as having memory allocated by the early allocator). The goal 29448c2ecf20Sopenharmony_ci * is to test "the real thing" as much as possible, and test "test setup 29458c2ecf20Sopenharmony_ci * code" as little as possible. 29468c2ecf20Sopenharmony_ci * 29478c2ecf20Sopenharmony_ci * Have to stop before resolving phandles, because that uses kmalloc. 29488c2ecf20Sopenharmony_ci */ 29498c2ecf20Sopenharmony_civoid __init unittest_unflatten_overlay_base(void) 29508c2ecf20Sopenharmony_ci{ 29518c2ecf20Sopenharmony_ci struct overlay_info *info; 29528c2ecf20Sopenharmony_ci u32 data_size; 29538c2ecf20Sopenharmony_ci void *new_fdt; 29548c2ecf20Sopenharmony_ci u32 size; 29558c2ecf20Sopenharmony_ci int found = 0; 29568c2ecf20Sopenharmony_ci const char *overlay_name = "overlay_base"; 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci for (info = overlays; info && info->name; info++) { 29598c2ecf20Sopenharmony_ci if (!strcmp(overlay_name, info->name)) { 29608c2ecf20Sopenharmony_ci found = 1; 29618c2ecf20Sopenharmony_ci break; 29628c2ecf20Sopenharmony_ci } 29638c2ecf20Sopenharmony_ci } 29648c2ecf20Sopenharmony_ci if (!found) { 29658c2ecf20Sopenharmony_ci pr_err("no overlay data for %s\n", overlay_name); 29668c2ecf20Sopenharmony_ci return; 29678c2ecf20Sopenharmony_ci } 29688c2ecf20Sopenharmony_ci 29698c2ecf20Sopenharmony_ci info = &overlays[0]; 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_ci if (info->expected_result != -9999) { 29728c2ecf20Sopenharmony_ci pr_err("No dtb 'overlay_base' to attach\n"); 29738c2ecf20Sopenharmony_ci return; 29748c2ecf20Sopenharmony_ci } 29758c2ecf20Sopenharmony_ci 29768c2ecf20Sopenharmony_ci data_size = info->dtb_end - info->dtb_begin; 29778c2ecf20Sopenharmony_ci if (!data_size) { 29788c2ecf20Sopenharmony_ci pr_err("No dtb 'overlay_base' to attach\n"); 29798c2ecf20Sopenharmony_ci return; 29808c2ecf20Sopenharmony_ci } 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ci size = fdt_totalsize(info->dtb_begin); 29838c2ecf20Sopenharmony_ci if (size != data_size) { 29848c2ecf20Sopenharmony_ci pr_err("dtb 'overlay_base' header totalsize != actual size"); 29858c2ecf20Sopenharmony_ci return; 29868c2ecf20Sopenharmony_ci } 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_ci new_fdt = dt_alloc_memory(size, roundup_pow_of_two(FDT_V17_SIZE)); 29898c2ecf20Sopenharmony_ci if (!new_fdt) { 29908c2ecf20Sopenharmony_ci pr_err("alloc for dtb 'overlay_base' failed"); 29918c2ecf20Sopenharmony_ci return; 29928c2ecf20Sopenharmony_ci } 29938c2ecf20Sopenharmony_ci 29948c2ecf20Sopenharmony_ci memcpy(new_fdt, info->dtb_begin, size); 29958c2ecf20Sopenharmony_ci 29968c2ecf20Sopenharmony_ci __unflatten_device_tree(new_fdt, NULL, &overlay_base_root, 29978c2ecf20Sopenharmony_ci dt_alloc_memory, true); 29988c2ecf20Sopenharmony_ci} 29998c2ecf20Sopenharmony_ci 30008c2ecf20Sopenharmony_ci/* 30018c2ecf20Sopenharmony_ci * The purpose of of_unittest_overlay_data_add is to add an 30028c2ecf20Sopenharmony_ci * overlay in the normal fashion. This is a test of the whole 30038c2ecf20Sopenharmony_ci * picture, instead of testing individual elements. 30048c2ecf20Sopenharmony_ci * 30058c2ecf20Sopenharmony_ci * A secondary purpose is to be able to verify that the contents of 30068c2ecf20Sopenharmony_ci * /proc/device-tree/ contains the updated structure and values from 30078c2ecf20Sopenharmony_ci * the overlay. That must be verified separately in user space. 30088c2ecf20Sopenharmony_ci * 30098c2ecf20Sopenharmony_ci * Return 0 on unexpected error. 30108c2ecf20Sopenharmony_ci */ 30118c2ecf20Sopenharmony_cistatic int __init overlay_data_apply(const char *overlay_name, int *overlay_id) 30128c2ecf20Sopenharmony_ci{ 30138c2ecf20Sopenharmony_ci struct overlay_info *info; 30148c2ecf20Sopenharmony_ci int found = 0; 30158c2ecf20Sopenharmony_ci int ret; 30168c2ecf20Sopenharmony_ci u32 size; 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_ci for (info = overlays; info && info->name; info++) { 30198c2ecf20Sopenharmony_ci if (!strcmp(overlay_name, info->name)) { 30208c2ecf20Sopenharmony_ci found = 1; 30218c2ecf20Sopenharmony_ci break; 30228c2ecf20Sopenharmony_ci } 30238c2ecf20Sopenharmony_ci } 30248c2ecf20Sopenharmony_ci if (!found) { 30258c2ecf20Sopenharmony_ci pr_err("no overlay data for %s\n", overlay_name); 30268c2ecf20Sopenharmony_ci return 0; 30278c2ecf20Sopenharmony_ci } 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci size = info->dtb_end - info->dtb_begin; 30308c2ecf20Sopenharmony_ci if (!size) 30318c2ecf20Sopenharmony_ci pr_err("no overlay data for %s\n", overlay_name); 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_ci ret = of_overlay_fdt_apply(info->dtb_begin, size, &info->overlay_id); 30348c2ecf20Sopenharmony_ci if (overlay_id) 30358c2ecf20Sopenharmony_ci *overlay_id = info->overlay_id; 30368c2ecf20Sopenharmony_ci if (ret < 0) 30378c2ecf20Sopenharmony_ci goto out; 30388c2ecf20Sopenharmony_ci 30398c2ecf20Sopenharmony_ci pr_debug("%s applied\n", overlay_name); 30408c2ecf20Sopenharmony_ci 30418c2ecf20Sopenharmony_ciout: 30428c2ecf20Sopenharmony_ci if (ret != info->expected_result) 30438c2ecf20Sopenharmony_ci pr_err("of_overlay_fdt_apply() expected %d, ret=%d, %s\n", 30448c2ecf20Sopenharmony_ci info->expected_result, ret, overlay_name); 30458c2ecf20Sopenharmony_ci 30468c2ecf20Sopenharmony_ci return (ret == info->expected_result); 30478c2ecf20Sopenharmony_ci} 30488c2ecf20Sopenharmony_ci 30498c2ecf20Sopenharmony_ci/* 30508c2ecf20Sopenharmony_ci * The purpose of of_unittest_overlay_high_level is to add an overlay 30518c2ecf20Sopenharmony_ci * in the normal fashion. This is a test of the whole picture, 30528c2ecf20Sopenharmony_ci * instead of individual elements. 30538c2ecf20Sopenharmony_ci * 30548c2ecf20Sopenharmony_ci * The first part of the function is _not_ normal overlay usage; it is 30558c2ecf20Sopenharmony_ci * finishing splicing the base overlay device tree into the live tree. 30568c2ecf20Sopenharmony_ci */ 30578c2ecf20Sopenharmony_cistatic __init void of_unittest_overlay_high_level(void) 30588c2ecf20Sopenharmony_ci{ 30598c2ecf20Sopenharmony_ci struct device_node *last_sibling; 30608c2ecf20Sopenharmony_ci struct device_node *np; 30618c2ecf20Sopenharmony_ci struct device_node *of_symbols; 30628c2ecf20Sopenharmony_ci struct device_node *overlay_base_symbols; 30638c2ecf20Sopenharmony_ci struct device_node **pprev; 30648c2ecf20Sopenharmony_ci struct property *prop; 30658c2ecf20Sopenharmony_ci int ret; 30668c2ecf20Sopenharmony_ci 30678c2ecf20Sopenharmony_ci if (!overlay_base_root) { 30688c2ecf20Sopenharmony_ci unittest(0, "overlay_base_root not initialized\n"); 30698c2ecf20Sopenharmony_ci return; 30708c2ecf20Sopenharmony_ci } 30718c2ecf20Sopenharmony_ci 30728c2ecf20Sopenharmony_ci /* 30738c2ecf20Sopenharmony_ci * Could not fixup phandles in unittest_unflatten_overlay_base() 30748c2ecf20Sopenharmony_ci * because kmalloc() was not yet available. 30758c2ecf20Sopenharmony_ci */ 30768c2ecf20Sopenharmony_ci of_overlay_mutex_lock(); 30778c2ecf20Sopenharmony_ci of_resolve_phandles(overlay_base_root); 30788c2ecf20Sopenharmony_ci of_overlay_mutex_unlock(); 30798c2ecf20Sopenharmony_ci 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_ci /* 30828c2ecf20Sopenharmony_ci * do not allow overlay_base to duplicate any node already in 30838c2ecf20Sopenharmony_ci * tree, this greatly simplifies the code 30848c2ecf20Sopenharmony_ci */ 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_ci /* 30878c2ecf20Sopenharmony_ci * remove overlay_base_root node "__local_fixups", after 30888c2ecf20Sopenharmony_ci * being used by of_resolve_phandles() 30898c2ecf20Sopenharmony_ci */ 30908c2ecf20Sopenharmony_ci pprev = &overlay_base_root->child; 30918c2ecf20Sopenharmony_ci for (np = overlay_base_root->child; np; np = np->sibling) { 30928c2ecf20Sopenharmony_ci if (of_node_name_eq(np, "__local_fixups__")) { 30938c2ecf20Sopenharmony_ci *pprev = np->sibling; 30948c2ecf20Sopenharmony_ci break; 30958c2ecf20Sopenharmony_ci } 30968c2ecf20Sopenharmony_ci pprev = &np->sibling; 30978c2ecf20Sopenharmony_ci } 30988c2ecf20Sopenharmony_ci 30998c2ecf20Sopenharmony_ci /* remove overlay_base_root node "__symbols__" if in live tree */ 31008c2ecf20Sopenharmony_ci of_symbols = of_get_child_by_name(of_root, "__symbols__"); 31018c2ecf20Sopenharmony_ci if (of_symbols) { 31028c2ecf20Sopenharmony_ci /* will have to graft properties from node into live tree */ 31038c2ecf20Sopenharmony_ci pprev = &overlay_base_root->child; 31048c2ecf20Sopenharmony_ci for (np = overlay_base_root->child; np; np = np->sibling) { 31058c2ecf20Sopenharmony_ci if (of_node_name_eq(np, "__symbols__")) { 31068c2ecf20Sopenharmony_ci overlay_base_symbols = np; 31078c2ecf20Sopenharmony_ci *pprev = np->sibling; 31088c2ecf20Sopenharmony_ci break; 31098c2ecf20Sopenharmony_ci } 31108c2ecf20Sopenharmony_ci pprev = &np->sibling; 31118c2ecf20Sopenharmony_ci } 31128c2ecf20Sopenharmony_ci } 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_ci for_each_child_of_node(overlay_base_root, np) { 31158c2ecf20Sopenharmony_ci struct device_node *base_child; 31168c2ecf20Sopenharmony_ci for_each_child_of_node(of_root, base_child) { 31178c2ecf20Sopenharmony_ci if (!strcmp(np->full_name, base_child->full_name)) { 31188c2ecf20Sopenharmony_ci unittest(0, "illegal node name in overlay_base %pOFn", 31198c2ecf20Sopenharmony_ci np); 31208c2ecf20Sopenharmony_ci return; 31218c2ecf20Sopenharmony_ci } 31228c2ecf20Sopenharmony_ci } 31238c2ecf20Sopenharmony_ci } 31248c2ecf20Sopenharmony_ci 31258c2ecf20Sopenharmony_ci /* 31268c2ecf20Sopenharmony_ci * overlay 'overlay_base' is not allowed to have root 31278c2ecf20Sopenharmony_ci * properties, so only need to splice nodes into main device tree. 31288c2ecf20Sopenharmony_ci * 31298c2ecf20Sopenharmony_ci * root node of *overlay_base_root will not be freed, it is lost 31308c2ecf20Sopenharmony_ci * memory. 31318c2ecf20Sopenharmony_ci */ 31328c2ecf20Sopenharmony_ci 31338c2ecf20Sopenharmony_ci for (np = overlay_base_root->child; np; np = np->sibling) 31348c2ecf20Sopenharmony_ci np->parent = of_root; 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_ci mutex_lock(&of_mutex); 31378c2ecf20Sopenharmony_ci 31388c2ecf20Sopenharmony_ci for (last_sibling = np = of_root->child; np; np = np->sibling) 31398c2ecf20Sopenharmony_ci last_sibling = np; 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_ci if (last_sibling) 31428c2ecf20Sopenharmony_ci last_sibling->sibling = overlay_base_root->child; 31438c2ecf20Sopenharmony_ci else 31448c2ecf20Sopenharmony_ci of_root->child = overlay_base_root->child; 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_ci for_each_of_allnodes_from(overlay_base_root, np) 31478c2ecf20Sopenharmony_ci __of_attach_node_sysfs(np); 31488c2ecf20Sopenharmony_ci 31498c2ecf20Sopenharmony_ci if (of_symbols) { 31508c2ecf20Sopenharmony_ci struct property *new_prop; 31518c2ecf20Sopenharmony_ci for_each_property_of_node(overlay_base_symbols, prop) { 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_ci new_prop = __of_prop_dup(prop, GFP_KERNEL); 31548c2ecf20Sopenharmony_ci if (!new_prop) { 31558c2ecf20Sopenharmony_ci unittest(0, "__of_prop_dup() of '%s' from overlay_base node __symbols__", 31568c2ecf20Sopenharmony_ci prop->name); 31578c2ecf20Sopenharmony_ci goto err_unlock; 31588c2ecf20Sopenharmony_ci } 31598c2ecf20Sopenharmony_ci if (__of_add_property(of_symbols, new_prop)) { 31608c2ecf20Sopenharmony_ci kfree(new_prop->name); 31618c2ecf20Sopenharmony_ci kfree(new_prop->value); 31628c2ecf20Sopenharmony_ci kfree(new_prop); 31638c2ecf20Sopenharmony_ci /* "name" auto-generated by unflatten */ 31648c2ecf20Sopenharmony_ci if (!strcmp(prop->name, "name")) 31658c2ecf20Sopenharmony_ci continue; 31668c2ecf20Sopenharmony_ci unittest(0, "duplicate property '%s' in overlay_base node __symbols__", 31678c2ecf20Sopenharmony_ci prop->name); 31688c2ecf20Sopenharmony_ci goto err_unlock; 31698c2ecf20Sopenharmony_ci } 31708c2ecf20Sopenharmony_ci if (__of_add_property_sysfs(of_symbols, new_prop)) { 31718c2ecf20Sopenharmony_ci unittest(0, "unable to add property '%s' in overlay_base node __symbols__ to sysfs", 31728c2ecf20Sopenharmony_ci prop->name); 31738c2ecf20Sopenharmony_ci goto err_unlock; 31748c2ecf20Sopenharmony_ci } 31758c2ecf20Sopenharmony_ci } 31768c2ecf20Sopenharmony_ci } 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_ci mutex_unlock(&of_mutex); 31798c2ecf20Sopenharmony_ci 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_ci /* now do the normal overlay usage test */ 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_ERR, 31848c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/substation@100/status"); 31858c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_ERR, 31868c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/fairway-1/status"); 31878c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_ERR, 31888c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/fairway-1/ride@100/track@30/incline-up"); 31898c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_ERR, 31908c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/fairway-1/ride@100/track@40/incline-up"); 31918c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_ERR, 31928c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/lights@40000/status"); 31938c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_ERR, 31948c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/lights@40000/color"); 31958c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_ERR, 31968c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/lights@40000/rate"); 31978c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_ERR, 31988c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /__symbols__/hvac_2"); 31998c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_ERR, 32008c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /__symbols__/ride_200"); 32018c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_ERR, 32028c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /__symbols__/ride_200_left"); 32038c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_ERR, 32048c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /__symbols__/ride_200_right"); 32058c2ecf20Sopenharmony_ci 32068c2ecf20Sopenharmony_ci ret = overlay_data_apply("overlay", NULL); 32078c2ecf20Sopenharmony_ci 32088c2ecf20Sopenharmony_ci EXPECT_END(KERN_ERR, 32098c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /__symbols__/ride_200_right"); 32108c2ecf20Sopenharmony_ci EXPECT_END(KERN_ERR, 32118c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /__symbols__/ride_200_left"); 32128c2ecf20Sopenharmony_ci EXPECT_END(KERN_ERR, 32138c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /__symbols__/ride_200"); 32148c2ecf20Sopenharmony_ci EXPECT_END(KERN_ERR, 32158c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /__symbols__/hvac_2"); 32168c2ecf20Sopenharmony_ci EXPECT_END(KERN_ERR, 32178c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/lights@40000/rate"); 32188c2ecf20Sopenharmony_ci EXPECT_END(KERN_ERR, 32198c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/lights@40000/color"); 32208c2ecf20Sopenharmony_ci EXPECT_END(KERN_ERR, 32218c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/lights@40000/status"); 32228c2ecf20Sopenharmony_ci EXPECT_END(KERN_ERR, 32238c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/fairway-1/ride@100/track@40/incline-up"); 32248c2ecf20Sopenharmony_ci EXPECT_END(KERN_ERR, 32258c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/fairway-1/ride@100/track@30/incline-up"); 32268c2ecf20Sopenharmony_ci EXPECT_END(KERN_ERR, 32278c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/fairway-1/status"); 32288c2ecf20Sopenharmony_ci EXPECT_END(KERN_ERR, 32298c2ecf20Sopenharmony_ci "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/substation@100/status"); 32308c2ecf20Sopenharmony_ci 32318c2ecf20Sopenharmony_ci unittest(ret, "Adding overlay 'overlay' failed\n"); 32328c2ecf20Sopenharmony_ci 32338c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_ERR, 32348c2ecf20Sopenharmony_ci "OF: overlay: ERROR: multiple fragments add and/or delete node /testcase-data-2/substation@100/motor-1/controller"); 32358c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_ERR, 32368c2ecf20Sopenharmony_ci "OF: overlay: ERROR: multiple fragments add, update, and/or delete property /testcase-data-2/substation@100/motor-1/controller/name"); 32378c2ecf20Sopenharmony_ci 32388c2ecf20Sopenharmony_ci unittest(overlay_data_apply("overlay_bad_add_dup_node", NULL), 32398c2ecf20Sopenharmony_ci "Adding overlay 'overlay_bad_add_dup_node' failed\n"); 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci EXPECT_END(KERN_ERR, 32428c2ecf20Sopenharmony_ci "OF: overlay: ERROR: multiple fragments add, update, and/or delete property /testcase-data-2/substation@100/motor-1/controller/name"); 32438c2ecf20Sopenharmony_ci EXPECT_END(KERN_ERR, 32448c2ecf20Sopenharmony_ci "OF: overlay: ERROR: multiple fragments add and/or delete node /testcase-data-2/substation@100/motor-1/controller"); 32458c2ecf20Sopenharmony_ci 32468c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_ERR, 32478c2ecf20Sopenharmony_ci "OF: overlay: ERROR: multiple fragments add and/or delete node /testcase-data-2/substation@100/motor-1/electric"); 32488c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_ERR, 32498c2ecf20Sopenharmony_ci "OF: overlay: ERROR: multiple fragments add, update, and/or delete property /testcase-data-2/substation@100/motor-1/electric/rpm_avail"); 32508c2ecf20Sopenharmony_ci EXPECT_BEGIN(KERN_ERR, 32518c2ecf20Sopenharmony_ci "OF: overlay: ERROR: multiple fragments add, update, and/or delete property /testcase-data-2/substation@100/motor-1/electric/name"); 32528c2ecf20Sopenharmony_ci 32538c2ecf20Sopenharmony_ci unittest(overlay_data_apply("overlay_bad_add_dup_prop", NULL), 32548c2ecf20Sopenharmony_ci "Adding overlay 'overlay_bad_add_dup_prop' failed\n"); 32558c2ecf20Sopenharmony_ci 32568c2ecf20Sopenharmony_ci EXPECT_END(KERN_ERR, 32578c2ecf20Sopenharmony_ci "OF: overlay: ERROR: multiple fragments add, update, and/or delete property /testcase-data-2/substation@100/motor-1/electric/name"); 32588c2ecf20Sopenharmony_ci EXPECT_END(KERN_ERR, 32598c2ecf20Sopenharmony_ci "OF: overlay: ERROR: multiple fragments add, update, and/or delete property /testcase-data-2/substation@100/motor-1/electric/rpm_avail"); 32608c2ecf20Sopenharmony_ci EXPECT_END(KERN_ERR, 32618c2ecf20Sopenharmony_ci "OF: overlay: ERROR: multiple fragments add and/or delete node /testcase-data-2/substation@100/motor-1/electric"); 32628c2ecf20Sopenharmony_ci 32638c2ecf20Sopenharmony_ci unittest(overlay_data_apply("overlay_bad_phandle", NULL), 32648c2ecf20Sopenharmony_ci "Adding overlay 'overlay_bad_phandle' failed\n"); 32658c2ecf20Sopenharmony_ci 32668c2ecf20Sopenharmony_ci unittest(overlay_data_apply("overlay_bad_symbol", NULL), 32678c2ecf20Sopenharmony_ci "Adding overlay 'overlay_bad_symbol' failed\n"); 32688c2ecf20Sopenharmony_ci 32698c2ecf20Sopenharmony_ci return; 32708c2ecf20Sopenharmony_ci 32718c2ecf20Sopenharmony_cierr_unlock: 32728c2ecf20Sopenharmony_ci mutex_unlock(&of_mutex); 32738c2ecf20Sopenharmony_ci} 32748c2ecf20Sopenharmony_ci 32758c2ecf20Sopenharmony_ci#else 32768c2ecf20Sopenharmony_ci 32778c2ecf20Sopenharmony_cistatic inline __init void of_unittest_overlay_high_level(void) {} 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_ci#endif 32808c2ecf20Sopenharmony_ci 32818c2ecf20Sopenharmony_cistatic int __init of_unittest(void) 32828c2ecf20Sopenharmony_ci{ 32838c2ecf20Sopenharmony_ci struct device_node *np; 32848c2ecf20Sopenharmony_ci int res; 32858c2ecf20Sopenharmony_ci 32868c2ecf20Sopenharmony_ci pr_info("start of unittest - you will see error messages\n"); 32878c2ecf20Sopenharmony_ci 32888c2ecf20Sopenharmony_ci /* adding data for unittest */ 32898c2ecf20Sopenharmony_ci 32908c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_UML)) 32918c2ecf20Sopenharmony_ci unittest_unflatten_overlay_base(); 32928c2ecf20Sopenharmony_ci 32938c2ecf20Sopenharmony_ci res = unittest_data_add(); 32948c2ecf20Sopenharmony_ci if (res) 32958c2ecf20Sopenharmony_ci return res; 32968c2ecf20Sopenharmony_ci if (!of_aliases) 32978c2ecf20Sopenharmony_ci of_aliases = of_find_node_by_path("/aliases"); 32988c2ecf20Sopenharmony_ci 32998c2ecf20Sopenharmony_ci np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a"); 33008c2ecf20Sopenharmony_ci if (!np) { 33018c2ecf20Sopenharmony_ci pr_info("No testcase data in device tree; not running tests\n"); 33028c2ecf20Sopenharmony_ci return 0; 33038c2ecf20Sopenharmony_ci } 33048c2ecf20Sopenharmony_ci of_node_put(np); 33058c2ecf20Sopenharmony_ci 33068c2ecf20Sopenharmony_ci of_unittest_check_tree_linkage(); 33078c2ecf20Sopenharmony_ci of_unittest_check_phandles(); 33088c2ecf20Sopenharmony_ci of_unittest_find_node_by_name(); 33098c2ecf20Sopenharmony_ci of_unittest_dynamic(); 33108c2ecf20Sopenharmony_ci of_unittest_parse_phandle_with_args(); 33118c2ecf20Sopenharmony_ci of_unittest_parse_phandle_with_args_map(); 33128c2ecf20Sopenharmony_ci of_unittest_printf(); 33138c2ecf20Sopenharmony_ci of_unittest_property_string(); 33148c2ecf20Sopenharmony_ci of_unittest_property_copy(); 33158c2ecf20Sopenharmony_ci of_unittest_changeset(); 33168c2ecf20Sopenharmony_ci of_unittest_parse_interrupts(); 33178c2ecf20Sopenharmony_ci of_unittest_parse_interrupts_extended(); 33188c2ecf20Sopenharmony_ci of_unittest_dma_get_max_cpu_address(); 33198c2ecf20Sopenharmony_ci of_unittest_parse_dma_ranges(); 33208c2ecf20Sopenharmony_ci of_unittest_pci_dma_ranges(); 33218c2ecf20Sopenharmony_ci of_unittest_match_node(); 33228c2ecf20Sopenharmony_ci of_unittest_platform_populate(); 33238c2ecf20Sopenharmony_ci of_unittest_overlay(); 33248c2ecf20Sopenharmony_ci 33258c2ecf20Sopenharmony_ci /* Double check linkage after removing testcase data */ 33268c2ecf20Sopenharmony_ci of_unittest_check_tree_linkage(); 33278c2ecf20Sopenharmony_ci 33288c2ecf20Sopenharmony_ci of_unittest_overlay_high_level(); 33298c2ecf20Sopenharmony_ci 33308c2ecf20Sopenharmony_ci pr_info("end of unittest - %i passed, %i failed\n", 33318c2ecf20Sopenharmony_ci unittest_results.passed, unittest_results.failed); 33328c2ecf20Sopenharmony_ci 33338c2ecf20Sopenharmony_ci return 0; 33348c2ecf20Sopenharmony_ci} 33358c2ecf20Sopenharmony_cilate_initcall(of_unittest); 3336