Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/of/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 125 kB image not shown  

Quelle  unittest.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * Self tests for device tree subsystem
 */


#define pr_fmt(fmt) "### dt-test ### " fmt

#include <linux/memblock.h>
#include <linux/clk.h>
#include <linux/dma-direct.h> /* to test phys_to_dma/dma_to_phys */
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/hashtable.h>
#include <linux/libfdt.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_fdt.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/pci.h>
#include <linux/kernel.h>

#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/gpio/driver.h>

#include <linux/bitops.h>

#include "of_private.h"

static struct unittest_results {
 int passed;
 int failed;
} unittest_results;

#define unittest(result, fmt, ...) ({ \
 bool failed = !(result); \
 if (failed) { \
  unittest_results.failed++; \
  pr_err("FAIL %s():%i " fmt, __func__, __LINE__, ##__VA_ARGS__); \
 } else { \
  unittest_results.passed++; \
  pr_info("pass %s():%i\n", __func__, __LINE__); \
 } \
 failed; \
})

#ifdef CONFIG_OF_KOBJ
#define OF_KREF_READ(NODE) kref_read(&(NODE)->kobj.kref)
#else
#define OF_KREF_READ(NODE) 1
#endif

/*
 * Expected message may have a message level other than KERN_INFO.
 * Print the expected message only if the current loglevel will allow
 * the actual message to print.
 *
 * Do not use EXPECT_BEGIN(), EXPECT_END(), EXPECT_NOT_BEGIN(), or
 * EXPECT_NOT_END() to report messages expected to be reported or not
 * reported by pr_debug().
 */

#define EXPECT_BEGIN(level, fmt, ...) \
 printk(level pr_fmt("EXPECT \\ : ") fmt, ##__VA_ARGS__)

#define EXPECT_END(level, fmt, ...) \
 printk(level pr_fmt("EXPECT / : ") fmt, ##__VA_ARGS__)

#define EXPECT_NOT_BEGIN(level, fmt, ...) \
 printk(level pr_fmt("EXPECT_NOT \\ : ") fmt, ##__VA_ARGS__)

#define EXPECT_NOT_END(level, fmt, ...) \
 printk(level pr_fmt("EXPECT_NOT / : ") fmt, ##__VA_ARGS__)

static void __init of_unittest_find_node_by_name(void)
{
 struct device_node *np;
 const char *options, *name;

 np = of_find_node_by_path("/testcase-data");
 name = kasprintf(GFP_KERNEL, "%pOF", np);
 unittest(np && name && !strcmp("/testcase-data", name),
  "find /testcase-data failed\n");
 of_node_put(np);
 kfree(name);

 /* Test if trailing '/' works */
 np = of_find_node_by_path("/testcase-data/");
 unittest(!np, "trailing '/' on /testcase-data/ should fail\n");

 np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
 name = kasprintf(GFP_KERNEL, "%pOF", np);
 unittest(np && name && !strcmp("/testcase-data/phandle-tests/consumer-a", name),
  "find /testcase-data/phandle-tests/consumer-a failed\n");
 of_node_put(np);
 kfree(name);

 np = of_find_node_by_path("testcase-alias");
 name = kasprintf(GFP_KERNEL, "%pOF", np);
 unittest(np && name && !strcmp("/testcase-data", name),
  "find testcase-alias failed\n");
 of_node_put(np);
 kfree(name);

 /* Test if trailing '/' works on aliases */
 np = of_find_node_by_path("testcase-alias/");
 unittest(!np, "trailing '/' on testcase-alias/ should fail\n");

 np = of_find_node_by_path("testcase-alias/phandle-tests/consumer-a");
 name = kasprintf(GFP_KERNEL, "%pOF", np);
 unittest(np && name && !strcmp("/testcase-data/phandle-tests/consumer-a", name),
  "find testcase-alias/phandle-tests/consumer-a failed\n");
 of_node_put(np);
 kfree(name);

 np = of_find_node_by_path("/testcase-data/missing-path");
 unittest(!np, "non-existent path returned node %pOF\n", np);
 of_node_put(np);

 np = of_find_node_by_path("missing-alias");
 unittest(!np, "non-existent alias returned node %pOF\n", np);
 of_node_put(np);

 np = of_find_node_by_path("testcase-alias/missing-path");
 unittest(!np, "non-existent alias with relative path returned node %pOF\n", np);
 of_node_put(np);

 np = of_find_node_opts_by_path("/testcase-data:testoption", &options);
 unittest(np && !strcmp("testoption", options),
   "option path test failed\n");
 of_node_put(np);

 np = of_find_node_opts_by_path("/testcase-data:test/option", &options);
 unittest(np && !strcmp("test/option", options),
   "option path test, subcase #1 failed\n");
 of_node_put(np);

 np = of_find_node_opts_by_path("/testcase-data/testcase-device1:test/option", &options);
 unittest(np && !strcmp("test/option", options),
   "option path test, subcase #2 failed\n");
 of_node_put(np);

 np = of_find_node_opts_by_path("/testcase-data:testoption", NULL);
 unittest(np, "NULL option path test failed\n");
 of_node_put(np);

 np = of_find_node_opts_by_path("testcase-alias:testaliasoption",
           &options);
 unittest(np && !strcmp("testaliasoption", options),
   "option alias path test failed\n");
 of_node_put(np);

 np = of_find_node_opts_by_path("testcase-alias:test/alias/option",
           &options);
 unittest(np && !strcmp("test/alias/option", options),
   "option alias path test, subcase #1 failed\n");
 of_node_put(np);

 np = of_find_node_opts_by_path("testcase-alias/phandle-tests/consumer-a:testaliasoption",
           &options);
 name = kasprintf(GFP_KERNEL, "%pOF", np);
 unittest(np && name && !strcmp("/testcase-data/phandle-tests/consumer-a", name) &&
   !strcmp("testaliasoption", options),
   "option alias path test, subcase #2 failed\n");
 of_node_put(np);
 kfree(name);

 np = of_find_node_opts_by_path("testcase-alias:testaliasoption", NULL);
 unittest(np, "NULL option alias path test failed\n");
 of_node_put(np);

 options = "testoption";
 np = of_find_node_opts_by_path("testcase-alias", &options);
 unittest(np && !options, "option clearing test failed\n");
 of_node_put(np);

 options = "testoption";
 np = of_find_node_opts_by_path("/", &options);
 unittest(np && !options, "option clearing root node test failed\n");
 of_node_put(np);
}

static void __init of_unittest_dynamic(void)
{
 struct device_node *np;
 struct property *prop;

 np = of_find_node_by_path("/testcase-data");
 if (!np) {
  pr_err("missing testcase data\n");
  return;
 }

 /* Array of 4 properties for the purpose of testing */
 prop = kcalloc(4, sizeof(*prop), GFP_KERNEL);
 if (!prop) {
  unittest(0, "kzalloc() failed\n");
  return;
 }

 /* Add a new property - should pass*/
 prop->name = "new-property";
 prop->value = "new-property-data";
 prop->length = strlen(prop->value) + 1;
 unittest(of_add_property(np, prop) == 0, "Adding a new property failed\n");

 /* Try to add an existing property - should fail */
 prop++;
 prop->name = "new-property";
 prop->value = "new-property-data-should-fail";
 prop->length = strlen(prop->value) + 1;
 unittest(of_add_property(np, prop) != 0,
   "Adding an existing property should have failed\n");

 /* Try to modify an existing property - should pass */
 prop->value = "modify-property-data-should-pass";
 prop->length = strlen(prop->value) + 1;
 unittest(of_update_property(np, prop) == 0,
   "Updating an existing property should have passed\n");

 /* Try to modify non-existent property - should pass*/
 prop++;
 prop->name = "modify-property";
 prop->value = "modify-missing-property-data-should-pass";
 prop->length = strlen(prop->value) + 1;
 unittest(of_update_property(np, prop) == 0,
   "Updating a missing property should have passed\n");

 /* Remove property - should pass */
 unittest(of_remove_property(np, prop) == 0,
   "Removing a property should have passed\n");

 /* Adding very large property - should pass */
 prop++;
 prop->name = "large-property-PAGE_SIZEx8";
 prop->length = PAGE_SIZE * 8;
 prop->value = kzalloc(prop->length, GFP_KERNEL);
 unittest(prop->value != NULL, "Unable to allocate large buffer\n");
 if (prop->value)
  unittest(of_add_property(np, prop) == 0,
    "Adding a large property should have passed\n");
}

static int __init of_unittest_check_node_linkage(struct device_node *np)
{
 int count = 0, rc;

 for_each_child_of_node_scoped(np, child) {
  if (child->parent != np) {
   pr_err("Child node %pOFn links to wrong parent %pOFn\n",
     child, np);
   return -EINVAL;
  }

  rc = of_unittest_check_node_linkage(child);
  if (rc < 0)
   return rc;
  count += rc;
 }

 return count + 1;
}

static void __init of_unittest_check_tree_linkage(void)
{
 struct device_node *np;
 int allnode_count = 0, child_count;

 if (!of_root)
  return;

 for_each_of_allnodes(np)
  allnode_count++;
 child_count = of_unittest_check_node_linkage(of_root);

 unittest(child_count > 0, "Device node data structure is corrupted\n");
 unittest(child_count == allnode_count,
   "allnodes list size (%i) doesn't match sibling lists size (%i)\n",
   allnode_count, child_count);
 pr_debug("allnodes list size (%i); sibling lists size (%i)\n", allnode_count, child_count);
}

static void __init of_unittest_printf_one(struct device_node *np, const char *fmt,
       const char *expected)
{
 unsigned char *buf;
 int buf_size;
 int size, i;

 buf_size = strlen(expected) + 10;
 buf = kmalloc(buf_size, GFP_KERNEL);
 if (!buf)
  return;

 /* Baseline; check conversion with a large size limit */
 memset(buf, 0xff, buf_size);
 size = snprintf(buf, buf_size - 2, fmt, np);

 /* use strcmp() instead of strncmp() here to be absolutely sure strings match */
 unittest((strcmp(buf, expected) == 0) && (buf[size+1] == 0xff),
  "sprintf failed; fmt='%s' expected='%s' rslt='%s'\n",
  fmt, expected, buf);

 /* Make sure length limits work */
 size++;
 for (i = 0; i < 2; i++, size--) {
  /* Clear the buffer, and make sure it works correctly still */
  memset(buf, 0xff, buf_size);
  snprintf(buf, size+1, fmt, np);
  unittest(strncmp(buf, expected, size) == 0 && (buf[size+1] == 0xff),
   "snprintf failed; size=%i fmt='%s' expected='%s' rslt='%s'\n",
   size, fmt, expected, buf);
 }
 kfree(buf);
}

static void __init of_unittest_printf(void)
{
 struct device_node *np;
 const char *full_name = "/testcase-data/platform-tests/test-device@1/dev@100";
 char phandle_str[16] = "";

 np = of_find_node_by_path(full_name);
 if (!np) {
  unittest(np, "testcase data missing\n");
  return;
 }

 num_to_str(phandle_str, sizeof(phandle_str), np->phandle, 0);

 of_unittest_printf_one(np, "%pOF",  full_name);
 of_unittest_printf_one(np, "%pOFf", full_name);
 of_unittest_printf_one(np, "%pOFn""dev");
 of_unittest_printf_one(np, "%2pOFn""dev");
 of_unittest_printf_one(np, "%5pOFn"" dev");
 of_unittest_printf_one(np, "%pOFnc""dev:test-sub-device");
 of_unittest_printf_one(np, "%pOFp", phandle_str);
 of_unittest_printf_one(np, "%pOFP""dev@100");
 of_unittest_printf_one(np, "ABC %pOFP ABC""ABC dev@100 ABC");
 of_unittest_printf_one(np, "%10pOFP"" dev@100");
 of_unittest_printf_one(np, "%-10pOFP""dev@100 ");
 of_unittest_printf_one(of_root, "%pOFP""/");
 of_unittest_printf_one(np, "%pOFF""----");
 of_unittest_printf_one(np, "%pOFPF""dev@100:----");
 of_unittest_printf_one(np, "%pOFPFPc""dev@100:----:dev@100:test-sub-device");
 of_unittest_printf_one(np, "%pOFc""test-sub-device");
 of_unittest_printf_one(np, "%pOFC",
   "\"test-sub-device\",\"test-compat2\",\"test-compat3\"");
}

struct node_hash {
 struct hlist_node node;
 struct device_node *np;
};

static DEFINE_HASHTABLE(phandle_ht, 8);
static void __init of_unittest_check_phandles(void)
{
 struct device_node *np;
 struct node_hash *nh;
 struct hlist_node *tmp;
 int i, dup_count = 0, phandle_count = 0;

 for_each_of_allnodes(np) {
  if (!np->phandle)
   continue;

  hash_for_each_possible(phandle_ht, nh, node, np->phandle) {
   if (nh->np->phandle == np->phandle) {
    pr_info("Duplicate phandle! %i used by %pOF and %pOF\n",
     np->phandle, nh->np, np);
    dup_count++;
    break;
   }
  }

  nh = kzalloc(sizeof(*nh), GFP_KERNEL);
  if (!nh)
   return;

  nh->np = np;
  hash_add(phandle_ht, &nh->node, np->phandle);
  phandle_count++;
 }
 unittest(dup_count == 0, "Found %i duplicates in %i phandles\n",
   dup_count, phandle_count);

 /* Clean up */
 hash_for_each_safe(phandle_ht, i, tmp, nh, node) {
  hash_del(&nh->node);
  kfree(nh);
 }
}

static void __init of_unittest_parse_phandle_with_args(void)
{
 struct device_node *np;
 struct of_phandle_args args;
 int i, rc;

 np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
 if (!np) {
  pr_err("missing testcase data\n");
  return;
 }

 rc = of_count_phandle_with_args(np, "phandle-list""#phandle-cells");
 unittest(rc == 7, "of_count_phandle_with_args() returned %i, expected 7\n", rc);

 for (i = 0; i < 8; i++) {
  bool passed = true;

  memset(&args, 0, sizeof(args));
  rc = of_parse_phandle_with_args(np, "phandle-list",
      "#phandle-cells", i, &args);

  /* Test the values from tests-phandle.dtsi */
  switch (i) {
  case 0:
   passed &= !rc;
   passed &= (args.args_count == 1);
   passed &= (args.args[0] == (i + 1));
   break;
  case 1:
   passed &= !rc;
   passed &= (args.args_count == 2);
   passed &= (args.args[0] == (i + 1));
   passed &= (args.args[1] == 0);
   break;
  case 2:
   passed &= (rc == -ENOENT);
   break;
  case 3:
   passed &= !rc;
   passed &= (args.args_count == 3);
   passed &= (args.args[0] == (i + 1));
   passed &= (args.args[1] == 4);
   passed &= (args.args[2] == 3);
   break;
  case 4:
   passed &= !rc;
   passed &= (args.args_count == 2);
   passed &= (args.args[0] == (i + 1));
   passed &= (args.args[1] == 100);
   break;
  case 5:
   passed &= !rc;
   passed &= (args.args_count == 0);
   break;
  case 6:
   passed &= !rc;
   passed &= (args.args_count == 1);
   passed &= (args.args[0] == (i + 1));
   break;
  case 7:
   passed &= (rc == -ENOENT);
   break;
  default:
   passed = false;
  }

  unittest(passed, "index %i - data error on node %pOF rc=%i\n",
    i, args.np, rc);

  if (rc == 0)
   of_node_put(args.np);
 }

 /* Check for missing list property */
 memset(&args, 0, sizeof(args));
 rc = of_parse_phandle_with_args(np, "phandle-list-missing",
     "#phandle-cells", 0, &args);
 unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
 rc = of_count_phandle_with_args(np, "phandle-list-missing",
     "#phandle-cells");
 unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);

 /* Check for missing cells property */
 memset(&args, 0, sizeof(args));

 EXPECT_BEGIN(KERN_INFO,
       "OF: /testcase-data/phandle-tests/consumer-a: could not get #phandle-cells-missing for /testcase-data/phandle-tests/provider1");

 rc = of_parse_phandle_with_args(np, "phandle-list",
     "#phandle-cells-missing", 0, &args);

 EXPECT_END(KERN_INFO,
     "OF: /testcase-data/phandle-tests/consumer-a: could not get #phandle-cells-missing for /testcase-data/phandle-tests/provider1");

 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);

 EXPECT_BEGIN(KERN_INFO,
       "OF: /testcase-data/phandle-tests/consumer-a: could not get #phandle-cells-missing for /testcase-data/phandle-tests/provider1");

 rc = of_count_phandle_with_args(np, "phandle-list",
     "#phandle-cells-missing");

 EXPECT_END(KERN_INFO,
     "OF: /testcase-data/phandle-tests/consumer-a: could not get #phandle-cells-missing for /testcase-data/phandle-tests/provider1");

 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);

 /* Check for bad phandle in list */
 memset(&args, 0, sizeof(args));

 EXPECT_BEGIN(KERN_INFO,
       "OF: /testcase-data/phandle-tests/consumer-a: could not find phandle");

 rc = of_parse_phandle_with_args(np, "phandle-list-bad-phandle",
     "#phandle-cells", 0, &args);

 EXPECT_END(KERN_INFO,
     "OF: /testcase-data/phandle-tests/consumer-a: could not find phandle");

 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);

 EXPECT_BEGIN(KERN_INFO,
       "OF: /testcase-data/phandle-tests/consumer-a: could not find phandle");

 rc = of_count_phandle_with_args(np, "phandle-list-bad-phandle",
     "#phandle-cells");

 EXPECT_END(KERN_INFO,
     "OF: /testcase-data/phandle-tests/consumer-a: could not find phandle");

 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);

 /* Check for incorrectly formed argument list */
 memset(&args, 0, sizeof(args));

 EXPECT_BEGIN(KERN_INFO,
       "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found 1");

 rc = of_parse_phandle_with_args(np, "phandle-list-bad-args",
     "#phandle-cells", 1, &args);

 EXPECT_END(KERN_INFO,
     "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found 1");

 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);

 EXPECT_BEGIN(KERN_INFO,
       "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found 1");

 rc = of_count_phandle_with_args(np, "phandle-list-bad-args",
     "#phandle-cells");

 EXPECT_END(KERN_INFO,
     "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found 1");

 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
}

static void __init of_unittest_parse_phandle_with_args_map(void)
{
 struct device_node *np, *p[6] = {};
 struct of_phandle_args args;
 unsigned int prefs[6];
 int i, rc;

 np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-b");
 if (!np) {
  pr_err("missing testcase data\n");
  return;
 }

 p[0] = of_find_node_by_path("/testcase-data/phandle-tests/provider0");
 p[1] = of_find_node_by_path("/testcase-data/phandle-tests/provider1");
 p[2] = of_find_node_by_path("/testcase-data/phandle-tests/provider2");
 p[3] = of_find_node_by_path("/testcase-data/phandle-tests/provider3");
 p[4] = of_find_node_by_path("/testcase-data/phandle-tests/provider4");
 p[5] = of_find_node_by_path("/testcase-data/phandle-tests/provider5");
 for (i = 0; i < ARRAY_SIZE(p); ++i) {
  if (!p[i]) {
   pr_err("missing testcase data\n");
   return;
  }
  prefs[i] = OF_KREF_READ(p[i]);
 }

 rc = of_count_phandle_with_args(np, "phandle-list""#phandle-cells");
 unittest(rc == 8, "of_count_phandle_with_args() returned %i, expected 8\n", rc);

 for (i = 0; i < 9; i++) {
  bool passed = true;

  memset(&args, 0, sizeof(args));
  rc = of_parse_phandle_with_args_map(np, "phandle-list",
          "phandle", i, &args);

  /* Test the values from tests-phandle.dtsi */
  switch (i) {
  case 0:
   passed &= !rc;
   passed &= (args.np == p[1]);
   passed &= (args.args_count == 1);
   passed &= (args.args[0] == 1);
   break;
  case 1:
   passed &= !rc;
   passed &= (args.np == p[3]);
   passed &= (args.args_count == 3);
   passed &= (args.args[0] == 2);
   passed &= (args.args[1] == 5);
   passed &= (args.args[2] == 3);
   break;
  case 2:
   passed &= (rc == -ENOENT);
   break;
  case 3:
   passed &= !rc;
   passed &= (args.np == p[0]);
   passed &= (args.args_count == 0);
   break;
  case 4:
   passed &= !rc;
   passed &= (args.np == p[1]);
   passed &= (args.args_count == 1);
   passed &= (args.args[0] == 3);
   break;
  case 5:
   passed &= !rc;
   passed &= (args.np == p[0]);
   passed &= (args.args_count == 0);
   break;
  case 6:
   passed &= !rc;
   passed &= (args.np == p[2]);
   passed &= (args.args_count == 2);
   passed &= (args.args[0] == 15);
   passed &= (args.args[1] == 0x20);
   break;
  case 7:
   passed &= !rc;
   passed &= (args.np == p[3]);
   passed &= (args.args_count == 3);
   passed &= (args.args[0] == 2);
   passed &= (args.args[1] == 5);
   passed &= (args.args[2] == 3);
   break;
  case 8:
   passed &= (rc == -ENOENT);
   break;
  default:
   passed = false;
  }

  unittest(passed, "index %i - data error on node %s rc=%i\n",
    i, args.np->full_name, rc);

  if (rc == 0)
   of_node_put(args.np);
 }

 /* Check for missing list property */
 memset(&args, 0, sizeof(args));
 rc = of_parse_phandle_with_args_map(np, "phandle-list-missing",
         "phandle", 0, &args);
 unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);

 /* Check for missing cells,map,mask property */
 memset(&args, 0, sizeof(args));

 EXPECT_BEGIN(KERN_INFO,
       "OF: /testcase-data/phandle-tests/consumer-b: could not get #phandle-missing-cells for /testcase-data/phandle-tests/provider1");

 rc = of_parse_phandle_with_args_map(np, "phandle-list",
         "phandle-missing", 0, &args);
 EXPECT_END(KERN_INFO,
     "OF: /testcase-data/phandle-tests/consumer-b: could not get #phandle-missing-cells for /testcase-data/phandle-tests/provider1");

 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);

 /* Check for bad phandle in list */
 memset(&args, 0, sizeof(args));

 EXPECT_BEGIN(KERN_INFO,
       "OF: /testcase-data/phandle-tests/consumer-b: could not find phandle 12345678");

 rc = of_parse_phandle_with_args_map(np, "phandle-list-bad-phandle",
         "phandle", 0, &args);
 EXPECT_END(KERN_INFO,
     "OF: /testcase-data/phandle-tests/consumer-b: could not find phandle 12345678");

 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);

 /* Check for incorrectly formed argument list */
 memset(&args, 0, sizeof(args));

 EXPECT_BEGIN(KERN_INFO,
       "OF: /testcase-data/phandle-tests/consumer-b: #phandle-cells = 2 found 1");

 rc = of_parse_phandle_with_args_map(np, "phandle-list-bad-args",
         "phandle", 1, &args);
 EXPECT_END(KERN_INFO,
     "OF: /testcase-data/phandle-tests/consumer-b: #phandle-cells = 2 found 1");

 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);

 for (i = 0; i < ARRAY_SIZE(p); ++i) {
  unittest(prefs[i] == OF_KREF_READ(p[i]),
    "provider%d: expected:%d got:%d\n",
    i, prefs[i], OF_KREF_READ(p[i]));
  of_node_put(p[i]);
 }
}

static void __init of_unittest_property_string(void)
{
 const char *strings[4];
 struct device_node *np;
 int rc;

 np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
 if (!np) {
  pr_err("No testcase data in device tree\n");
  return;
 }

 rc = of_property_match_string(np, "phandle-list-names""first");
 unittest(rc == 0, "first expected:0 got:%i\n", rc);
 rc = of_property_match_string(np, "phandle-list-names""second");
 unittest(rc == 1, "second expected:1 got:%i\n", rc);
 rc = of_property_match_string(np, "phandle-list-names""third");
 unittest(rc == 2, "third expected:2 got:%i\n", rc);
 rc = of_property_match_string(np, "phandle-list-names""fourth");
 unittest(rc == -ENODATA, "unmatched string; rc=%i\n", rc);
 rc = of_property_match_string(np, "missing-property""blah");
 unittest(rc == -EINVAL, "missing property; rc=%i\n", rc);
 rc = of_property_match_string(np, "empty-property""blah");
 unittest(rc == -ENODATA, "empty property; rc=%i\n", rc);
 rc = of_property_match_string(np, "unterminated-string""blah");
 unittest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);

 /* of_property_count_strings() tests */
 rc = of_property_count_strings(np, "string-property");
 unittest(rc == 1, "Incorrect string count; rc=%i\n", rc);
 rc = of_property_count_strings(np, "phandle-list-names");
 unittest(rc == 3, "Incorrect string count; rc=%i\n", rc);
 rc = of_property_count_strings(np, "unterminated-string");
 unittest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);
 rc = of_property_count_strings(np, "unterminated-string-list");
 unittest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc);

 /* of_property_read_string_index() tests */
 rc = of_property_read_string_index(np, "string-property", 0, strings);
 unittest(rc == 0 && !strcmp(strings[0], "foobar"), "of_property_read_string_index() failure; rc=%i\n", rc);
 strings[0] = NULL;
 rc = of_property_read_string_index(np, "string-property", 1, strings);
 unittest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
 rc = of_property_read_string_index(np, "phandle-list-names", 0, strings);
 unittest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc);
 rc = of_property_read_string_index(np, "phandle-list-names", 1, strings);
 unittest(rc == 0 && !strcmp(strings[0], "second"), "of_property_read_string_index() failure; rc=%i\n", rc);
 rc = of_property_read_string_index(np, "phandle-list-names", 2, strings);
 unittest(rc == 0 && !strcmp(strings[0], "third"), "of_property_read_string_index() failure; rc=%i\n", rc);
 strings[0] = NULL;
 rc = of_property_read_string_index(np, "phandle-list-names", 3, strings);
 unittest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
 strings[0] = NULL;
 rc = of_property_read_string_index(np, "unterminated-string", 0, strings);
 unittest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
 rc = of_property_read_string_index(np, "unterminated-string-list", 0, strings);
 unittest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc);
 strings[0] = NULL;
 rc = of_property_read_string_index(np, "unterminated-string-list", 2, strings); /* should fail */
 unittest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
 strings[1] = NULL;

 /* of_property_read_string_array() tests */
 rc = of_property_read_string_array(np, "string-property", strings, 4);
 unittest(rc == 1, "Incorrect string count; rc=%i\n", rc);
 rc = of_property_read_string_array(np, "phandle-list-names", strings, 4);
 unittest(rc == 3, "Incorrect string count; rc=%i\n", rc);
 rc = of_property_read_string_array(np, "unterminated-string", strings, 4);
 unittest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);
 /* -- An incorrectly formed string should cause a failure */
 rc = of_property_read_string_array(np, "unterminated-string-list", strings, 4);
 unittest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc);
 /* -- parsing the correctly formed strings should still work: */
 strings[2] = NULL;
 rc = of_property_read_string_array(np, "unterminated-string-list", strings, 2);
 unittest(rc == 2 && strings[2] == NULL, "of_property_read_string_array() failure; rc=%i\n", rc);
 strings[1] = NULL;
 rc = of_property_read_string_array(np, "phandle-list-names", strings, 1);
 unittest(rc == 1 && strings[1] == NULL, "Overwrote end of string array; rc=%i, str='%s'\n", rc, strings[1]);
}

#define propcmp(p1, p2) (((p1)->length == (p2)->length) && \
   (p1)->value && (p2)->value && \
   !memcmp((p1)->value, (p2)->value, (p1)->length) && \
   !strcmp((p1)->name, (p2)->name))
static void __init of_unittest_property_copy(void)
{
#ifdef CONFIG_OF_DYNAMIC
 struct property p1 = { .name = "p1", .length = 0, .value = "" };
 struct property p2 = { .name = "p2", .length = 5, .value = "abcd" };
 struct property *new;

 new = __of_prop_dup(&p1, GFP_KERNEL);
 unittest(new && propcmp(&p1, new), "empty property didn't copy correctly\n");
 __of_prop_free(new);

 new = __of_prop_dup(&p2, GFP_KERNEL);
 unittest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n");
 __of_prop_free(new);
#endif
}

static void __init of_unittest_changeset(void)
{
#ifdef CONFIG_OF_DYNAMIC
 int ret;
 struct property *ppadd, padd = { .name = "prop-add", .length = 1, .value = "" };
 struct property *ppname_n1,  pname_n1  = { .name = "name", .length = 3, .value = "n1"  };
 struct property *ppname_n2,  pname_n2  = { .name = "name", .length = 3, .value = "n2"  };
 struct property *ppname_n21, pname_n21 = { .name = "name", .length = 3, .value = "n21" };
 struct property *ppupdate, pupdate = { .name = "prop-update", .length = 5, .value = "abcd" };
 struct property *ppremove;
 struct device_node *n1, *n2, *n21, *n22, *nchangeset, *nremove, *parent, *np;
 static const char * const str_array[] = { "str1""str2""str3" };
 const u32 u32_array[] = { 1, 2, 3 };
 struct of_changeset chgset;
 const char *propstr = NULL;

 n1 = __of_node_dup(NULL, "n1");
 unittest(n1, "testcase setup failure\n");

 n2 = __of_node_dup(NULL, "n2");
 unittest(n2, "testcase setup failure\n");

 n21 = __of_node_dup(NULL, "n21");
 unittest(n21, "testcase setup failure %p\n", n21);

 nchangeset = of_find_node_by_path("/testcase-data/changeset");
 nremove = of_get_child_by_name(nchangeset, "node-remove");
 unittest(nremove, "testcase setup failure\n");

 ppadd = __of_prop_dup(&padd, GFP_KERNEL);
 unittest(ppadd, "testcase setup failure\n");

 ppname_n1  = __of_prop_dup(&pname_n1, GFP_KERNEL);
 unittest(ppname_n1, "testcase setup failure\n");

 ppname_n2  = __of_prop_dup(&pname_n2, GFP_KERNEL);
 unittest(ppname_n2, "testcase setup failure\n");

 ppname_n21 = __of_prop_dup(&pname_n21, GFP_KERNEL);
 unittest(ppname_n21, "testcase setup failure\n");

 ppupdate = __of_prop_dup(&pupdate, GFP_KERNEL);
 unittest(ppupdate, "testcase setup failure\n");

 parent = nchangeset;
 n1->parent = parent;
 n2->parent = parent;
 n21->parent = n2;

 ppremove = of_find_property(parent, "prop-remove", NULL);
 unittest(ppremove, "failed to find removal prop");

 of_changeset_init(&chgset);

 unittest(!of_changeset_attach_node(&chgset, n1), "fail attach n1\n");
 unittest(!of_changeset_add_property(&chgset, n1, ppname_n1), "fail add prop name\n");

 unittest(!of_changeset_attach_node(&chgset, n2), "fail attach n2\n");
 unittest(!of_changeset_add_property(&chgset, n2, ppname_n2), "fail add prop name\n");

 unittest(!of_changeset_detach_node(&chgset, nremove), "fail remove node\n");
 unittest(!of_changeset_add_property(&chgset, n21, ppname_n21), "fail add prop name\n");

 unittest(!of_changeset_attach_node(&chgset, n21), "fail attach n21\n");

 unittest(!of_changeset_add_property(&chgset, parent, ppadd), "fail add prop prop-add\n");
 unittest(!of_changeset_update_property(&chgset, parent, ppupdate), "fail update prop\n");
 unittest(!of_changeset_remove_property(&chgset, parent, ppremove), "fail remove prop\n");
 n22 = of_changeset_create_node(&chgset, n2, "n22");
 unittest(n22, "fail create n22\n");
 unittest(!of_changeset_add_prop_string(&chgset, n22, "prop-str""abcd"),
   "fail add prop prop-str");
 unittest(!of_changeset_add_prop_string_array(&chgset, n22, "prop-str-array",
           (const char **)str_array,
           ARRAY_SIZE(str_array)),
   "fail add prop prop-str-array");
 unittest(!of_changeset_add_prop_u32_array(&chgset, n22, "prop-u32-array",
        u32_array, ARRAY_SIZE(u32_array)),
   "fail add prop prop-u32-array");

 unittest(!of_changeset_apply(&chgset), "apply failed\n");

 of_node_put(nchangeset);

 /* Make sure node names are constructed correctly */
 unittest((np = of_find_node_by_path("/testcase-data/changeset/n2/n21")),
   "'%pOF' not added\n", n21);
 of_node_put(np);
 unittest((np = of_find_node_by_path("/testcase-data/changeset/n2/n22")),
   "'%pOF' not added\n", n22);
 of_node_put(np);

 unittest(!of_changeset_revert(&chgset), "revert failed\n");

 unittest(!of_find_node_by_path("/testcase-data/changeset/n2/n21"),
   "'%pOF' still present after revert\n", n21);

 unittest(of_property_present(parent, "prop-remove"),
   "failed to find removed prop after revert\n");

 ret = of_property_read_string(parent, "prop-update", &propstr);
 unittest(!ret, "failed to find updated prop after revert\n");
 if (!ret)
  unittest(strcmp(propstr, "hello") == 0, "original value not in updated property after revert");

 of_changeset_destroy(&chgset);

 of_node_put(n1);
 of_node_put(n2);
 of_node_put(n21);
 of_node_put(n22);
#endif
}

static void __init __maybe_unused changeset_check_string(struct device_node *np,
        const char *prop_name,
        const char *expected_str)
{
 const char *str;
 int ret;

 ret = of_property_read_string(np, prop_name, &str);
 if (unittest(ret == 0, "failed to read %s\n", prop_name))
  return;

 unittest(strcmp(str, expected_str) == 0,
   "%s value mismatch (read '%s', exp '%s')\n",
   prop_name, str, expected_str);
}

static void __init __maybe_unused changeset_check_string_array(struct device_node *np,
              const char *prop_name,
              const char * const *expected_array,
              unsigned int count)
{
 const char *str;
 unsigned int i;
 int ret;
 int cnt;

 cnt = of_property_count_strings(np, prop_name);
 if (unittest(cnt >= 0, "failed to get %s count\n", prop_name))
  return;

 if (unittest(cnt == count,
       "%s count mismatch (read %d, exp %u)\n",
       prop_name, cnt, count))
  return;

 for (i = 0; i < count; i++) {
  ret = of_property_read_string_index(np, prop_name, i, &str);
  if (unittest(ret == 0, "failed to read %s[%d]\n", prop_name, i))
   continue;

  unittest(strcmp(str, expected_array[i]) == 0,
    "%s[%d] value mismatch (read '%s', exp '%s')\n",
    prop_name, i, str, expected_array[i]);
 }
}

static void __init __maybe_unused changeset_check_u32(struct device_node *np,
            const char *prop_name,
            u32 expected_u32)
{
 u32 val32;
 int ret;

 ret = of_property_read_u32(np, prop_name, &val32);
 if (unittest(ret == 0, "failed to read %s\n", prop_name))
  return;

 unittest(val32 == expected_u32,
   "%s value mismatch (read '%u', exp '%u')\n",
   prop_name, val32, expected_u32);
}

static void __init __maybe_unused changeset_check_u32_array(struct device_node *np,
           const char *prop_name,
           const u32 *expected_array,
           unsigned int count)
{
 unsigned int i;
 u32 val32;
 int ret;
 int cnt;

 cnt = of_property_count_u32_elems(np, prop_name);
 if (unittest(cnt >= 0, "failed to get %s count\n", prop_name))
  return;

 if (unittest(cnt == count,
       "%s count mismatch (read %d, exp %u)\n",
       prop_name, cnt, count))
  return;

 for (i = 0; i < count; i++) {
  ret = of_property_read_u32_index(np, prop_name, i, &val32);
  if (unittest(ret == 0, "failed to read %s[%d]\n", prop_name, i))
   continue;

  unittest(val32 == expected_array[i],
    "%s[%d] value mismatch (read '%u', exp '%u')\n",
    prop_name, i, val32, expected_array[i]);
 }
}

static void __init __maybe_unused changeset_check_bool(struct device_node *np,
             const char *prop_name)
{
 unittest(of_property_read_bool(np, prop_name),
   "%s value mismatch (read 'false', exp 'true')\n", prop_name);
}

static void __init of_unittest_changeset_prop(void)
{
#ifdef CONFIG_OF_DYNAMIC
 static const char * const str_array[] = { "abc""defg""hij" };
 static const u32 u32_array[] = { 123, 4567, 89, 10, 11 };
 struct device_node *nchangeset, *np;
 struct of_changeset chgset;
 int ret;

 nchangeset = of_find_node_by_path("/testcase-data/changeset");
 if (!nchangeset) {
  pr_err("missing testcase data\n");
  return;
 }

 of_changeset_init(&chgset);

 np = of_changeset_create_node(&chgset, nchangeset, "test-prop");
 if (unittest(np, "failed to create test-prop node\n"))
  goto end_changeset_destroy;

 ret = of_changeset_add_prop_string(&chgset, np, "prop-string""abcde");
 unittest(ret == 0, "failed to add prop-string\n");

 ret = of_changeset_add_prop_string_array(&chgset, np, "prop-string-array",
       str_array, ARRAY_SIZE(str_array));
 unittest(ret == 0, "failed to add prop-string-array\n");

 ret = of_changeset_add_prop_u32(&chgset, np, "prop-u32", 1234);
 unittest(ret == 0, "failed to add prop-u32\n");

 ret = of_changeset_add_prop_u32_array(&chgset, np, "prop-u32-array",
           u32_array, ARRAY_SIZE(u32_array));
 unittest(ret == 0, "failed to add prop-u32-array\n");

 ret = of_changeset_add_prop_bool(&chgset, np, "prop-bool");
 unittest(ret == 0, "failed to add prop-bool\n");

 of_node_put(np);

 ret = of_changeset_apply(&chgset);
 if (unittest(ret == 0, "failed to apply changeset\n"))
  goto end_changeset_destroy;

 np = of_find_node_by_path("/testcase-data/changeset/test-prop");
 if (unittest(np, "failed to find test-prop node\n"))
  goto end_revert_changeset;

 changeset_check_string(np, "prop-string""abcde");
 changeset_check_string_array(np, "prop-string-array", str_array, ARRAY_SIZE(str_array));
 changeset_check_u32(np, "prop-u32", 1234);
 changeset_check_u32_array(np, "prop-u32-array", u32_array, ARRAY_SIZE(u32_array));
 changeset_check_bool(np, "prop-bool");

 of_node_put(np);

end_revert_changeset:
 ret = of_changeset_revert(&chgset);
 unittest(ret == 0, "failed to revert changeset\n");

end_changeset_destroy:
 of_changeset_destroy(&chgset);
 of_node_put(nchangeset);
#endif
}

static void __init of_unittest_dma_get_max_cpu_address(void)
{
 struct device_node *np;
 phys_addr_t cpu_addr;

 if (!IS_ENABLED(CONFIG_OF_ADDRESS))
  return;

 np = of_find_node_by_path("/testcase-data/address-tests");
 if (!np) {
  pr_err("missing testcase data\n");
  return;
 }

 cpu_addr = of_dma_get_max_cpu_address(np);
 unittest(cpu_addr == 0x4fffffff,
   "of_dma_get_max_cpu_address: wrong CPU addr %pad (expecting %x)\n",
   &cpu_addr, 0x4fffffff);
}

static void __init of_unittest_dma_ranges_one(const char *path,
  u64 expect_dma_addr, u64 expect_paddr)
{
#ifdef CONFIG_HAS_DMA
 struct device_node *np;
 const struct bus_dma_region *map = NULL;
 int rc;

 np = of_find_node_by_path(path);
 if (!np) {
  pr_err("missing testcase data\n");
  return;
 }

 rc = of_dma_get_range(np, &map);

 unittest(!rc, "of_dma_get_range failed on node %pOF rc=%i\n", np, rc);

 if (!rc) {
  phys_addr_t paddr;
  dma_addr_t dma_addr;
  struct device *dev_bogus;

  dev_bogus = kzalloc(sizeof(struct device), GFP_KERNEL);
  if (!dev_bogus) {
   unittest(0, "kzalloc() failed\n");
   kfree(map);
   return;
  }

  dev_bogus->dma_range_map = map;
  paddr = dma_to_phys(dev_bogus, expect_dma_addr);
  dma_addr = phys_to_dma(dev_bogus, expect_paddr);

  unittest(paddr == expect_paddr,
    "of_dma_get_range: wrong phys addr %pap (expecting %llx) on node %pOF\n",
    &paddr, expect_paddr, np);
  unittest(dma_addr == expect_dma_addr,
    "of_dma_get_range: wrong DMA addr %pad (expecting %llx) on node %pOF\n",
    &dma_addr, expect_dma_addr, np);

  kfree(map);
  kfree(dev_bogus);
 }
 of_node_put(np);
#endif
}

static void __init of_unittest_parse_dma_ranges(void)
{
 of_unittest_dma_ranges_one("/testcase-data/address-tests/device@70000000",
  0x0, 0x20000000);
 if (IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT))
  of_unittest_dma_ranges_one("/testcase-data/address-tests/bus@80000000/device@1000",
   0x100000000, 0x20000000);
 of_unittest_dma_ranges_one("/testcase-data/address-tests/pci@90000000",
  0x80000000, 0x20000000);
}

static void __init of_unittest_pci_dma_ranges(void)
{
 struct device_node *np;
 struct of_pci_range range;
 struct of_pci_range_parser parser;
 int i = 0;

 if (!IS_ENABLED(CONFIG_PCI))
  return;

 np = of_find_node_by_path("/testcase-data/address-tests/pci@90000000");
 if (!np) {
  pr_err("missing testcase data\n");
  return;
 }

 if (of_pci_dma_range_parser_init(&parser, np)) {
  pr_err("missing dma-ranges property\n");
  return;
 }

 /*
 * Get the dma-ranges from the device tree
 */

 for_each_of_pci_range(&parser, &range) {
  if (!i) {
   unittest(range.size == 0x10000000,
     "for_each_of_pci_range wrong size on node %pOF size=%llx\n",
     np, range.size);
   unittest(range.cpu_addr == 0x20000000,
     "for_each_of_pci_range wrong CPU addr (%llx) on node %pOF",
     range.cpu_addr, np);
   unittest(range.pci_addr == 0x80000000,
     "for_each_of_pci_range wrong DMA addr (%llx) on node %pOF",
     range.pci_addr, np);
  } else {
   unittest(range.size == 0x10000000,
     "for_each_of_pci_range wrong size on node %pOF size=%llx\n",
     np, range.size);
   unittest(range.cpu_addr == 0x40000000,
     "for_each_of_pci_range wrong CPU addr (%llx) on node %pOF",
     range.cpu_addr, np);
   unittest(range.pci_addr == 0xc0000000,
     "for_each_of_pci_range wrong DMA addr (%llx) on node %pOF",
     range.pci_addr, np);
  }
  i++;
 }

 of_node_put(np);
}

static void __init of_unittest_pci_empty_dma_ranges(void)
{
 struct device_node *np;
 struct of_pci_range range;
 struct of_pci_range_parser parser;

 if (!IS_ENABLED(CONFIG_PCI))
  return;

 np = of_find_node_by_path("/testcase-data/address-tests2/pcie@d1070000/pci@0,0/dev@0,0/local-bus@0");
 if (!np) {
  pr_err("missing testcase data\n");
  return;
 }

 if (of_pci_dma_range_parser_init(&parser, np)) {
  pr_err("missing dma-ranges property\n");
  return;
 }

 /*
 * Get the dma-ranges from the device tree
 */

 for_each_of_pci_range(&parser, &range) {
  unittest(range.size == 0x10000000,
    "for_each_of_pci_range wrong size on node %pOF size=%llx\n",
    np, range.size);
  unittest(range.cpu_addr == 0x00000000,
    "for_each_of_pci_range wrong CPU addr (%llx) on node %pOF",
    range.cpu_addr, np);
  unittest(range.pci_addr == 0xc0000000,
    "for_each_of_pci_range wrong DMA addr (%llx) on node %pOF",
    range.pci_addr, np);
 }

 of_node_put(np);
}

static void __init of_unittest_bus_ranges(void)
{
 struct device_node *np;
 struct of_range range;
 struct of_range_parser parser;
 struct resource res;
 int ret, count, i = 0;

 np = of_find_node_by_path("/testcase-data/address-tests");
 if (!np) {
  pr_err("missing testcase data\n");
  return;
 }

 if (of_range_parser_init(&parser, np)) {
  pr_err("missing ranges property\n");
  return;
 }

 ret = of_range_to_resource(np, 1, &res);
 unittest(!ret, "of_range_to_resource returned error (%d) node %pOF\n",
  ret, np);
 unittest(resource_type(&res) == IORESOURCE_MEM,
  "of_range_to_resource wrong resource type on node %pOF res=%pR\n",
  np, &res);
 unittest(res.start == 0xd0000000,
  "of_range_to_resource wrong resource start address on node %pOF res=%pR\n",
  np, &res);
 unittest(resource_size(&res) == 0x20000000,
  "of_range_to_resource wrong resource start address on node %pOF res=%pR\n",
  np, &res);

 count = of_range_count(&parser);
 unittest(count == 2,
  "of_range_count wrong size on node %pOF count=%d\n",
  np, count);

 /*
 * Get the "ranges" from the device tree
 */

 for_each_of_range(&parser, &range) {
  unittest(range.flags == IORESOURCE_MEM,
   "for_each_of_range wrong flags on node %pOF flags=%x (expected %x)\n",
   np, range.flags, IORESOURCE_MEM);
  if (!i) {
   unittest(range.size == 0x50000000,
     "for_each_of_range wrong size on node %pOF size=%llx\n",
     np, range.size);
   unittest(range.cpu_addr == 0x70000000,
     "for_each_of_range wrong CPU addr (%llx) on node %pOF",
     range.cpu_addr, np);
   unittest(range.bus_addr == 0x70000000,
     "for_each_of_range wrong bus addr (%llx) on node %pOF",
     range.pci_addr, np);
  } else {
   unittest(range.size == 0x20000000,
     "for_each_of_range wrong size on node %pOF size=%llx\n",
     np, range.size);
   unittest(range.cpu_addr == 0xd0000000,
     "for_each_of_range wrong CPU addr (%llx) on node %pOF",
     range.cpu_addr, np);
   unittest(range.bus_addr == 0x00000000,
     "for_each_of_range wrong bus addr (%llx) on node %pOF",
     range.pci_addr, np);
  }
  i++;
 }

 of_node_put(np);
}

static void __init of_unittest_bus_3cell_ranges(void)
{
 struct device_node *np;
 struct of_range range;
 struct of_range_parser parser;
 int i = 0;

 np = of_find_node_by_path("/testcase-data/address-tests/bus@a0000000");
 if (!np) {
  pr_err("missing testcase data\n");
  return;
 }

 if (of_range_parser_init(&parser, np)) {
  pr_err("missing ranges property\n");
  return;
 }

 /*
 * Get the "ranges" from the device tree
 */

 for_each_of_range(&parser, &range) {
  if (!i) {
   unittest(range.flags == 0xf00baa,
     "for_each_of_range wrong flags on node %pOF flags=%x\n",
     np, range.flags);
   unittest(range.size == 0x100000,
     "for_each_of_range wrong size on node %pOF size=%llx\n",
     np, range.size);
   unittest(range.cpu_addr == 0xa0000000,
     "for_each_of_range wrong CPU addr (%llx) on node %pOF",
     range.cpu_addr, np);
   unittest(range.bus_addr == 0x0,
     "for_each_of_range wrong bus addr (%llx) on node %pOF",
     range.pci_addr, np);
  } else {
   unittest(range.flags == 0xf00bee,
     "for_each_of_range wrong flags on node %pOF flags=%x\n",
     np, range.flags);
   unittest(range.size == 0x200000,
     "for_each_of_range wrong size on node %pOF size=%llx\n",
     np, range.size);
   unittest(range.cpu_addr == 0xb0000000,
     "for_each_of_range wrong CPU addr (%llx) on node %pOF",
     range.cpu_addr, np);
   unittest(range.bus_addr == 0x100000000,
     "for_each_of_range wrong bus addr (%llx) on node %pOF",
     range.pci_addr, np);
  }
  i++;
 }

 of_node_put(np);
}

static void __init of_unittest_reg(void)
{
 struct device_node *np;
 struct resource res;
 int ret;
 u64 addr, size;

 np = of_find_node_by_path("/testcase-data/address-tests/bus@80000000/device@1000");
 if (!np) {
  pr_err("missing testcase data\n");
  return;
 }

 ret = of_property_read_reg(np, 0, &addr, &size);
 unittest(!ret, "of_property_read_reg(%pOF) returned error %d\n",
  np, ret);
 unittest(addr == 0x1000, "of_property_read_reg(%pOF) untranslated address (%llx) incorrect\n",
  np, addr);

 of_node_put(np);

 np = of_find_node_by_path("/testcase-data/platform-tests-2/node/test-device@100");
 if (!np) {
  pr_err("missing testcase data\n");
  return;
 }

 ret = of_address_to_resource(np, 0, &res);
 unittest(ret == -EINVAL, "of_address_to_resource(%pOF) expected error on untranslatable address\n",
   np);

 of_node_put(np);

}

struct of_unittest_expected_res {
 int index;
 struct resource res;
};

static void __init of_unittest_check_addr(const char *node_path,
       const struct of_unittest_expected_res *tab_exp,
       unsigned int tab_exp_count)
{
 const struct of_unittest_expected_res *expected;
 struct device_node *np;
 struct resource res;
 unsigned int count;
 int ret;

 if (!IS_ENABLED(CONFIG_OF_ADDRESS))
  return;

 np = of_find_node_by_path(node_path);
 if (!np) {
  pr_err("missing testcase data (%s)\n", node_path);
  return;
 }

 expected = tab_exp;
 count = tab_exp_count;
 while (count--) {
  ret = of_address_to_resource(np, expected->index, &res);
  unittest(!ret, "of_address_to_resource(%pOF, %d) returned error %d\n",
    np, expected->index, ret);
  unittest(resource_type(&res) == resource_type(&expected->res) &&
    res.start == expected->res.start &&
    resource_size(&res) == resource_size(&expected->res),
   "of_address_to_resource(%pOF, %d) wrong resource %pR, expected %pR\n",
   np, expected->index, &res, &expected->res);
  expected++;
 }

 of_node_put(np);
}

static const struct of_unittest_expected_res of_unittest_reg_2cell_expected_res[] = {
 {.index = 0, .res = DEFINE_RES_MEM(0xa0a01000, 0x100) },
 {.index = 1, .res = DEFINE_RES_MEM(0xa0a02000, 0x100) },
 {.index = 2, .res = DEFINE_RES_MEM(0xc0c01000, 0x100) },
 {.index = 3, .res = DEFINE_RES_MEM(0xd0d01000, 0x100) },
};

static const struct of_unittest_expected_res of_unittest_reg_3cell_expected_res[] = {
 {.index = 0, .res = DEFINE_RES_MEM(0xa0a01000, 0x100) },
 {.index = 1, .res = DEFINE_RES_MEM(0xa0b02000, 0x100) },
 {.index = 2, .res = DEFINE_RES_MEM(0xc0c01000, 0x100) },
 {.index = 3, .res = DEFINE_RES_MEM(0xc0c09000, 0x100) },
 {.index = 4, .res = DEFINE_RES_MEM(0xd0d01000, 0x100) },
};

static const struct of_unittest_expected_res of_unittest_reg_pci_expected_res[] = {
 {.index = 0, .res = DEFINE_RES_MEM(0xe8001000, 0x1000) },
 {.index = 1, .res = DEFINE_RES_MEM(0xea002000, 0x2000) },
};

static void __init of_unittest_translate_addr(void)
{
 of_unittest_check_addr("/testcase-data/address-tests2/bus-2cell@10000000/device@100000",
          of_unittest_reg_2cell_expected_res,
          ARRAY_SIZE(of_unittest_reg_2cell_expected_res));

 of_unittest_check_addr("/testcase-data/address-tests2/bus-3cell@20000000/local-bus@100000/device@f1001000",
          of_unittest_reg_3cell_expected_res,
          ARRAY_SIZE(of_unittest_reg_3cell_expected_res));

 of_unittest_check_addr("/testcase-data/address-tests2/pcie@d1070000/pci@0,0/dev@0,0/local-bus@0/dev@e0000000",
          of_unittest_reg_pci_expected_res,
          ARRAY_SIZE(of_unittest_reg_pci_expected_res));
}

static void __init of_unittest_parse_interrupts(void)
{
 struct device_node *np;
 struct of_phandle_args args;
 int i, rc;

 if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
  return;

 np = of_find_node_by_path("/testcase-data/interrupts/interrupts0");
 if (!np) {
  pr_err("missing testcase data\n");
  return;
 }

 for (i = 0; i < 4; i++) {
  bool passed = true;

  memset(&args, 0, sizeof(args));
  rc = of_irq_parse_one(np, i, &args);

  passed &= !rc;
  passed &= (args.args_count == 1);
  passed &= (args.args[0] == (i + 1));

  unittest(passed, "index %i - data error on node %pOF rc=%i\n",
    i, args.np, rc);
 }
 of_node_put(np);

 np = of_find_node_by_path("/testcase-data/interrupts/interrupts1");
 if (!np) {
  pr_err("missing testcase data\n");
  return;
 }

 for (i = 0; i < 4; i++) {
  bool passed = true;

  memset(&args, 0, sizeof(args));
  rc = of_irq_parse_one(np, i, &args);

  /* Test the values from tests-phandle.dtsi */
  switch (i) {
  case 0:
   passed &= !rc;
   passed &= (args.args_count == 1);
   passed &= (args.args[0] == 9);
   break;
  case 1:
   passed &= !rc;
   passed &= (args.args_count == 3);
   passed &= (args.args[0] == 10);
   passed &= (args.args[1] == 11);
   passed &= (args.args[2] == 12);
   break;
  case 2:
   passed &= !rc;
   passed &= (args.args_count == 2);
   passed &= (args.args[0] == 13);
   passed &= (args.args[1] == 14);
   break;
  case 3:
   passed &= !rc;
   passed &= (args.args_count == 2);
   passed &= (args.args[0] == 15);
   passed &= (args.args[1] == 16);
   break;
  default:
   passed = false;
  }
  unittest(passed, "index %i - data error on node %pOF rc=%i\n",
    i, args.np, rc);
 }
 of_node_put(np);
}

static void __init of_unittest_parse_interrupts_extended(void)
{
 struct device_node *np;
 struct of_phandle_args args;
 int i, rc;

 if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
  return;

 np = of_find_node_by_path("/testcase-data/interrupts/interrupts-extended0");
 if (!np) {
  pr_err("missing testcase data\n");
  return;
 }

 for (i = 0; i < 7; i++) {
  bool passed = true;

  memset(&args, 0, sizeof(args));
  rc = of_irq_parse_one(np, i, &args);

  /* Test the values from tests-phandle.dtsi */
  switch (i) {
  case 0:
   passed &= !rc;
   passed &= (args.args_count == 1);
   passed &= (args.args[0] == 1);
   break;
  case 1:
   passed &= !rc;
   passed &= (args.args_count == 3);
   passed &= (args.args[0] == 2);
   passed &= (args.args[1] == 3);
   passed &= (args.args[2] == 4);
   break;
  case 2:
   passed &= !rc;
   passed &= (args.args_count == 2);
   passed &= (args.args[0] == 5);
   passed &= (args.args[1] == 6);
   break;
  case 3:
   passed &= !rc;
   passed &= (args.args_count == 1);
   passed &= (args.args[0] == 9);
   break;
  case 4:
   passed &= !rc;
   passed &= (args.args_count == 3);
   passed &= (args.args[0] == 10);
   passed &= (args.args[1] == 11);
   passed &= (args.args[2] == 12);
   break;
  case 5:
   passed &= !rc;
   passed &= (args.args_count == 2);
   passed &= (args.args[0] == 13);
   passed &= (args.args[1] == 14);
   break;
  case 6:
   /*
 * Tests child node that is missing property
 * #address-cells.  See the comments in
 * drivers/of/unittest-data/tests-interrupts.dtsi
 * nodes intmap1 and interrupts-extended0
 */

   passed &= !rc;
   passed &= (args.args_count == 1);
   passed &= (args.args[0] == 15);
   break;
  default:
   passed = false;
  }

  unittest(passed, "index %i - data error on node %pOF rc=%i\n",
    i, args.np, rc);
 }
 of_node_put(np);
}

#if IS_ENABLED(CONFIG_OF_DYNAMIC)
static void __init of_unittest_irq_refcount(void)
{
 struct of_phandle_args args;
 struct device_node *intc0, *int_ext0;
 struct device_node *int2, *intc_intmap0;
 unsigned int ref_c0, ref_c1, ref_c2;
 int rc;
 bool passed;

 if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
  return;

 intc0 = of_find_node_by_path("/testcase-data/interrupts/intc0");
 int_ext0 = of_find_node_by_path("/testcase-data/interrupts/interrupts-extended0");
 intc_intmap0 = of_find_node_by_path("/testcase-data/interrupts/intc-intmap0");
 int2 = of_find_node_by_path("/testcase-data/interrupts/interrupts2");
 if (!intc0 || !int_ext0 || !intc_intmap0 || !int2) {
  pr_err("missing testcase data\n");
  goto out;
 }

 /* Test refcount for API of_irq_parse_one() */
 passed = true;
 ref_c0 = OF_KREF_READ(intc0);
 ref_c1 = ref_c0 + 1;
 memset(&args, 0, sizeof(args));
 rc = of_irq_parse_one(int_ext0, 0, &args);
 ref_c2 = OF_KREF_READ(intc0);
 of_node_put(args.np);

 passed &= !rc;
 passed &= (args.np == intc0);
 passed &= (args.args_count == 1);
 passed &= (args.args[0] == 1);
 passed &= (ref_c1 == ref_c2);
 unittest(passed, "IRQ refcount case #1 failed, original(%u) expected(%u) got(%u)\n",
   ref_c0, ref_c1, ref_c2);

 /* Test refcount for API of_irq_parse_raw() */
 passed = true;
 ref_c0 = OF_KREF_READ(intc_intmap0);
 ref_c1 = ref_c0 + 1;
 memset(&args, 0, sizeof(args));
 rc = of_irq_parse_one(int2, 0, &args);
 ref_c2 = OF_KREF_READ(intc_intmap0);
 of_node_put(args.np);

 passed &= !rc;
 passed &= (args.np == intc_intmap0);
 passed &= (args.args_count == 1);
 passed &= (args.args[0] == 2);
 passed &= (ref_c1 == ref_c2);
 unittest(passed, "IRQ refcount case #2 failed, original(%u) expected(%u) got(%u)\n",
   ref_c0, ref_c1, ref_c2);

out:
 of_node_put(int2);
 of_node_put(intc_intmap0);
 of_node_put(int_ext0);
 of_node_put(intc0);
}
#else
static inline void __init of_unittest_irq_refcount(void) { }
#endif

static const struct of_device_id match_node_table[] = {
 { .data = "A", .name = "name0", }, /* Name alone is lowest priority */
 { .data = "B", .type = "type1", }, /* followed by type alone */

 { .data = "Ca", .name = "name2", .type = "type1", }, /* followed by both together */
 { .data = "Cb", .name = "name2", }, /* Only match when type doesn't match */
 { .data = "Cc", .name = "name2", .type = "type2", },

 { .data = "E", .compatible = "compat3" },
 { .data = "G", .compatible = "compat2", },
 { .data = "H", .compatible = "compat2", .name = "name5", },
 { .data = "I", .compatible = "compat2", .type = "type1", },
 { .data = "J", .compatible = "compat2", .type = "type1", .name = "name8", },
 { .data = "K", .compatible = "compat2", .name = "name9", },
 {}
};

static struct {
 const char *path;
 const char *data;
} match_node_tests[] = {
 { .path = "/testcase-data/match-node/name0", .data = "A", },
 { .path = "/testcase-data/match-node/name1", .data = "B", },
 { .path = "/testcase-data/match-node/a/name2", .data = "Ca", },
 { .path = "/testcase-data/match-node/b/name2", .data = "Cb", },
 { .path = "/testcase-data/match-node/c/name2", .data = "Cc", },
 { .path = "/testcase-data/match-node/name3", .data = "E", },
 { .path = "/testcase-data/match-node/name4", .data = "G", },
 { .path = "/testcase-data/match-node/name5", .data = "H", },
 { .path = "/testcase-data/match-node/name6", .data = "G", },
 { .path = "/testcase-data/match-node/name7", .data = "I", },
 { .path = "/testcase-data/match-node/name8", .data = "J", },
 { .path = "/testcase-data/match-node/name9", .data = "K", },
};

static void __init of_unittest_match_node(void)
{
 struct device_node *np;
 const struct of_device_id *match;
 int i;

 for (i = 0; i < ARRAY_SIZE(match_node_tests); i++) {
  np = of_find_node_by_path(match_node_tests[i].path);
  if (!np) {
   unittest(0, "missing testcase node %s\n",
    match_node_tests[i].path);
   continue;
  }

  match = of_match_node(match_node_table, np);
  if (!match) {
   unittest(0, "%s didn't match anything\n",
    match_node_tests[i].path);
   continue;
  }

  if (strcmp(match->data, match_node_tests[i].data) != 0) {
   unittest(0, "%s got wrong match. expected %s, got %s\n",
    match_node_tests[i].path, match_node_tests[i].data,
    (const char *)match->data);
   continue;
  }
  unittest(1, "passed");
 }
}

static struct resource test_bus_res = DEFINE_RES_MEM(0xfffffff8, 2);
static const struct platform_device_info test_bus_info = {
 .name = "unittest-bus",
};
static void __init of_unittest_platform_populate(void)
{
 int irq, rc;
 struct device_node *np, *child, *grandchild;
 struct platform_device *pdev, *test_bus;
 const struct of_device_id match[] = {
  { .compatible = "test-device", },
  {}
 };

 np = of_find_node_by_path("/testcase-data");
 of_platform_default_populate(np, NULL, NULL);

 /* Test that a missing irq domain returns -EPROBE_DEFER */
 np = of_find_node_by_path("/testcase-data/testcase-device1");
 pdev = of_find_device_by_node(np);
 unittest(pdev, "device 1 creation failed\n");

 if (!(of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)) {
  irq = platform_get_irq(pdev, 0);
  unittest(irq == -EPROBE_DEFER,
    "device deferred probe failed - %d\n", irq);

  /* Test that a parsing failure does not return -EPROBE_DEFER */
  np = of_find_node_by_path("/testcase-data/testcase-device2");
  pdev = of_find_device_by_node(np);
  unittest(pdev, "device 2 creation failed\n");

  EXPECT_BEGIN(KERN_INFO,
        "platform testcase-data:testcase-device2: error -ENXIO: IRQ index 0 not found");

  irq = platform_get_irq(pdev, 0);

  EXPECT_END(KERN_INFO,
      "platform testcase-data:testcase-device2: error -ENXIO: IRQ index 0 not found");

  unittest(irq < 0 && irq != -EPROBE_DEFER,
    "device parsing error failed - %d\n", irq);
 }

 np = of_find_node_by_path("/testcase-data/platform-tests");
 unittest(np, "No testcase data in device tree\n");
 if (!np)
  return;

 test_bus = platform_device_register_full(&test_bus_info);
 rc = PTR_ERR_OR_ZERO(test_bus);
 unittest(!rc, "testbus registration failed; rc=%i\n", rc);
 if (rc) {
  of_node_put(np);
  return;
 }
 test_bus->dev.of_node = np;

 /*
 * Add a dummy resource to the test bus node after it is
 * registered to catch problems with un-inserted resources. The
 * DT code doesn't insert the resources, and it has caused the
 * kernel to oops in the past. This makes sure the same bug
 * doesn't crop up again.
 */

 platform_device_add_resources(test_bus, &test_bus_res, 1);

 of_platform_populate(np, match, NULL, &test_bus->dev);
 for_each_child_of_node(np, child) {
  for_each_child_of_node(child, grandchild) {
   if (!of_property_present(grandchild, "compatible"))
    continue;
   pdev = of_find_device_by_node(grandchild);
   unittest(pdev,
     "Could not create device for node '%pOFn'\n",
     grandchild);
   platform_device_put(pdev);
  }
 }

 of_platform_depopulate(&test_bus->dev);
 for_each_child_of_node(np, child) {
  for_each_child_of_node(child, grandchild)
   unittest(!of_find_device_by_node(grandchild),
     "device didn't get destroyed '%pOFn'\n",
     grandchild);
 }

 platform_device_unregister(test_bus);
 of_node_put(np);
}

/**
 * update_node_properties - adds the properties
 * of np into dup node (present in live tree) and
 * updates parent of children of np to dup.
 *
 * @np: node whose properties are being added to the live tree
 * @dup: node present in live tree to be updated
 */

static void update_node_properties(struct device_node *np,
     struct device_node *dup)
{
 struct property *prop;
 struct property *save_next;
 struct device_node *child;
 int ret;

 for_each_child_of_node(np, child)
  child->parent = dup;

 /*
 * "unittest internal error: unable to add testdata property"
 *
 *    If this message reports a property in node '/__symbols__' then
 *    the respective unittest overlay contains a label that has the
 *    same name as a label in the live devicetree.  The label will
 *    be in the live devicetree only if the devicetree source was
 *    compiled with the '-@' option.  If you encounter this error,
 *    please consider renaming __all__ of the labels in the unittest
 *    overlay dts files with an odd prefix that is unlikely to be
 *    used in a real devicetree.
 */


 /*
 * open code for_each_property_of_node() because of_add_property()
 * sets prop->next to NULL
 */

 for (prop = np->properties; prop != NULL; prop = save_next) {
  save_next = prop->next;
  ret = of_add_property(dup, prop);
  if (ret) {
   if (ret == -EEXIST && !strcmp(prop->name, "name"))
    continue;
   pr_err("unittest internal error: unable to add testdata property %pOF/%s",
          np, prop->name);
  }
 }
}

/**
 * attach_node_and_children - attaches nodes
 * and its children to live tree.
 * CAUTION: misleading function name - if node @np already exists in
 * the live tree then children of @np are *not* attached to the live
 * tree.  This works for the current test devicetree nodes because such
 * nodes do not have child nodes.
 *
 * @np: Node to attach to live tree
 */

static void attach_node_and_children(struct device_node *np)
{
 struct device_node *next, *dup, *child;
 unsigned long flags;
 const char *full_name;

 full_name = kasprintf(GFP_KERNEL, "%pOF", np);
 if (!full_name)
  return;

 if (!strcmp(full_name, "/__local_fixups__") ||
     !strcmp(full_name, "/__fixups__")) {
  kfree(full_name);
  return;
 }

 dup = of_find_node_by_path(full_name);
 kfree(full_name);
 if (dup) {
  update_node_properties(np, dup);
  return;
 }

 child = np->child;
 np->child = NULL;

 mutex_lock(&of_mutex);
 raw_spin_lock_irqsave(&devtree_lock, flags);
 np->sibling = np->parent->child;
 np->parent->child = np;
 of_node_clear_flag(np, OF_DETACHED);
 raw_spin_unlock_irqrestore(&devtree_lock, flags);

 __of_attach_node_sysfs(np);
 mutex_unlock(&of_mutex);

 while (child) {
  next = child->sibling;
  attach_node_and_children(child);
  child = next;
 }
}

/**
 * unittest_data_add - Reads, copies data from
 * linked tree and attaches it to the live tree
 */

static int __init unittest_data_add(void)
{
 void *unittest_data;
 void *unittest_data_align;
 struct device_node *unittest_data_node = NULL, *np;
 /*
 * __dtbo_testcases_begin[] and __dtbo_testcases_end[] are magically
 * created by cmd_wrap_S_dtbo in scripts/Makefile.dtbs
 */

 extern uint8_t __dtbo_testcases_begin[];
 extern uint8_t __dtbo_testcases_end[];
 const int size = __dtbo_testcases_end - __dtbo_testcases_begin;
 int rc;
 void *ret;

 if (!size) {
  pr_warn("%s: testcases is empty\n", __func__);
  return -ENODATA;
 }

 /* creating copy */
 unittest_data = kmalloc(size + FDT_ALIGN_SIZE, GFP_KERNEL);
 if (!unittest_data)
  return -ENOMEM;

 unittest_data_align = PTR_ALIGN(unittest_data, FDT_ALIGN_SIZE);
 memcpy(unittest_data_align, __dtbo_testcases_begin, size);

 ret = of_fdt_unflatten_tree(unittest_data_align, NULL, &unittest_data_node);
 if (!ret) {
  pr_warn("%s: unflatten testcases tree failed\n", __func__);
  kfree(unittest_data);
  return -ENODATA;
 }
 if (!unittest_data_node) {
  pr_warn("%s: testcases tree is empty\n", __func__);
  kfree(unittest_data);
  return -ENODATA;
 }

 /*
 * This lock normally encloses of_resolve_phandles()
 */

 of_overlay_mutex_lock();

 rc = of_resolve_phandles(unittest_data_node);
 if (rc) {
  pr_err("%s: Failed to resolve phandles (rc=%i)\n", __func__, rc);
  rc = -EINVAL;
  goto unlock;
 }

 /* attach the sub-tree to live tree */
 if (!of_root) {
  pr_warn("%s: no live tree to attach sub-tree\n", __func__);
  kfree(unittest_data);
  rc = -ENODEV;
  goto unlock;
 }

 EXPECT_BEGIN(KERN_INFO,
       "Duplicate name in testcase-data, renamed to \"duplicate-name#1\"");

 np = unittest_data_node->child;
 while (np) {
  struct device_node *next = np->sibling;

  np->parent = of_root;
  /* this will clear OF_DETACHED in np and children */
  attach_node_and_children(np);
  np = next;
 }

 EXPECT_END(KERN_INFO,
     "Duplicate name in testcase-data, renamed to \"duplicate-name#1\"");

unlock:
 of_overlay_mutex_unlock();

 return rc;
}

#ifdef CONFIG_OF_OVERLAY
static int __init overlay_data_apply(const char *overlay_name, int *ovcs_id);

static int unittest_probe(struct platform_device *pdev)
{
 struct device *dev = &pdev->dev;
 struct device_node *np = dev->of_node;

 if (np == NULL) {
  dev_err(dev, "No OF data for device\n");
  return -EINVAL;

 }

 dev_dbg(dev, "%s for node @%pOF\n", __func__, np);

 of_platform_populate(np, NULL, NULL, &pdev->dev);

 return 0;
}

static void unittest_remove(struct platform_device *pdev)
{
 struct device *dev = &pdev->dev;
 struct device_node *np = dev->of_node;

 dev_dbg(dev, "%s for node @%pOF\n", __func__, np);
}

static const struct of_device_id unittest_match[] = {
 { .compatible = "unittest", },
 {},
};

static struct platform_driver unittest_driver = {
 .probe   = unittest_probe,
 .remove   = unittest_remove,
 .driver = {
  .name  = "unittest",
  .of_match_table = unittest_match,
 },
};

/* get the platform device instantiated at the path */
static struct platform_device *of_path_to_platform_device(const char *path)
{
 struct device_node *np;
 struct platform_device *pdev;

 np = of_find_node_by_path(path);
 if (np == NULL)
  return NULL;

 pdev = of_find_device_by_node(np);
 of_node_put(np);

 return pdev;
}

/* find out if a platform device exists at that path */
static int of_path_platform_device_exists(const char *path)
{
 struct platform_device *pdev;

 pdev = of_path_to_platform_device(path);
 platform_device_put(pdev);
 return pdev != NULL;
}

#ifdef CONFIG_OF_GPIO

struct unittest_gpio_dev {
 struct gpio_chip chip;
};

static int unittest_gpio_chip_request_count;
static int unittest_gpio_probe_count;
static int unittest_gpio_probe_pass_count;

static int unittest_gpio_chip_request(struct gpio_chip *chip, unsigned int offset)
{
 unittest_gpio_chip_request_count++;

 pr_debug("%s(): %s %d %d\n", __func__, chip->label, offset,
   unittest_gpio_chip_request_count);
 return 0;
}

static int unittest_gpio_probe(struct platform_device *pdev)
{
 struct unittest_gpio_dev *devptr;
 int ret;

 unittest_gpio_probe_count++;

 devptr = kzalloc(sizeof(*devptr), GFP_KERNEL);
 if (!devptr)
  return -ENOMEM;

 platform_set_drvdata(pdev, devptr);

 devptr->chip.fwnode = dev_fwnode(&pdev->dev);
 devptr->chip.label = "of-unittest-gpio";
 devptr->chip.base = -1; /* dynamic allocation */
 devptr->chip.ngpio = 5;
 devptr->chip.request = unittest_gpio_chip_request;

 ret = gpiochip_add_data(&devptr->chip, NULL);

 unittest(!ret,
   "gpiochip_add_data() for node @%pfw failed, ret = %d\n", devptr->chip.fwnode, ret);

 if (!ret)
  unittest_gpio_probe_pass_count++;
 return ret;
}

static void unittest_gpio_remove(struct platform_device *pdev)
{
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=98 H=81 G=89

¤ Dauer der Verarbeitung: 0.19 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.