Skip to content

Commit b544fc2

Browse files
houlz0507robherring
authored andcommitted
of: dynamic: Add interfaces for creating device node dynamically
of_changeset_create_node() creates device node dynamically and attaches the newly created node to a changeset. Expand of_changeset APIs to handle specific types of properties. of_changeset_add_prop_string() of_changeset_add_prop_string_array() of_changeset_add_prop_u32_array() Signed-off-by: Clément Léger <[email protected]> Signed-off-by: Lizhi Hou <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Rob Herring <[email protected]>
1 parent ef04d28 commit b544fc2

File tree

3 files changed

+205
-1
lines changed

3 files changed

+205
-1
lines changed

drivers/of/dynamic.c

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,38 @@ struct device_node *__of_node_dup(const struct device_node *np,
483483
return NULL;
484484
}
485485

486+
/**
487+
* of_changeset_create_node - Dynamically create a device node and attach to
488+
* a given changeset.
489+
*
490+
* @ocs: Pointer to changeset
491+
* @parent: Pointer to parent device node
492+
* @full_name: Node full name
493+
*
494+
* Return: Pointer to the created device node or NULL in case of an error.
495+
*/
496+
struct device_node *of_changeset_create_node(struct of_changeset *ocs,
497+
struct device_node *parent,
498+
const char *full_name)
499+
{
500+
struct device_node *np;
501+
int ret;
502+
503+
np = __of_node_dup(NULL, full_name);
504+
if (!np)
505+
return NULL;
506+
np->parent = parent;
507+
508+
ret = of_changeset_attach_node(ocs, np);
509+
if (ret) {
510+
of_node_put(np);
511+
return NULL;
512+
}
513+
514+
return np;
515+
}
516+
EXPORT_SYMBOL(of_changeset_create_node);
517+
486518
static void __of_changeset_entry_destroy(struct of_changeset_entry *ce)
487519
{
488520
if (ce->action == OF_RECONFIG_ATTACH_NODE &&
@@ -875,3 +907,135 @@ int of_changeset_action(struct of_changeset *ocs, unsigned long action,
875907
return 0;
876908
}
877909
EXPORT_SYMBOL_GPL(of_changeset_action);
910+
911+
static int of_changeset_add_prop_helper(struct of_changeset *ocs,
912+
struct device_node *np,
913+
const struct property *pp)
914+
{
915+
struct property *new_pp;
916+
int ret;
917+
918+
new_pp = __of_prop_dup(pp, GFP_KERNEL);
919+
if (!new_pp)
920+
return -ENOMEM;
921+
922+
ret = of_changeset_add_property(ocs, np, new_pp);
923+
if (ret) {
924+
kfree(new_pp->name);
925+
kfree(new_pp->value);
926+
kfree(new_pp);
927+
}
928+
929+
return ret;
930+
}
931+
932+
/**
933+
* of_changeset_add_prop_string - Add a string property to a changeset
934+
*
935+
* @ocs: changeset pointer
936+
* @np: device node pointer
937+
* @prop_name: name of the property to be added
938+
* @str: pointer to null terminated string
939+
*
940+
* Create a string property and add it to a changeset.
941+
*
942+
* Return: 0 on success, a negative error value in case of an error.
943+
*/
944+
int of_changeset_add_prop_string(struct of_changeset *ocs,
945+
struct device_node *np,
946+
const char *prop_name, const char *str)
947+
{
948+
struct property prop;
949+
950+
prop.name = (char *)prop_name;
951+
prop.length = strlen(str) + 1;
952+
prop.value = (void *)str;
953+
954+
return of_changeset_add_prop_helper(ocs, np, &prop);
955+
}
956+
EXPORT_SYMBOL_GPL(of_changeset_add_prop_string);
957+
958+
/**
959+
* of_changeset_add_prop_string_array - Add a string list property to
960+
* a changeset
961+
*
962+
* @ocs: changeset pointer
963+
* @np: device node pointer
964+
* @prop_name: name of the property to be added
965+
* @str_array: pointer to an array of null terminated strings
966+
* @sz: number of string array elements
967+
*
968+
* Create a string list property and add it to a changeset.
969+
*
970+
* Return: 0 on success, a negative error value in case of an error.
971+
*/
972+
int of_changeset_add_prop_string_array(struct of_changeset *ocs,
973+
struct device_node *np,
974+
const char *prop_name,
975+
const char **str_array, size_t sz)
976+
{
977+
struct property prop;
978+
int i, ret;
979+
char *vp;
980+
981+
prop.name = (char *)prop_name;
982+
983+
prop.length = 0;
984+
for (i = 0; i < sz; i++)
985+
prop.length += strlen(str_array[i]) + 1;
986+
987+
prop.value = kmalloc(prop.length, GFP_KERNEL);
988+
if (!prop.value)
989+
return -ENOMEM;
990+
991+
vp = prop.value;
992+
for (i = 0; i < sz; i++) {
993+
vp += snprintf(vp, (char *)prop.value + prop.length - vp, "%s",
994+
str_array[i]) + 1;
995+
}
996+
ret = of_changeset_add_prop_helper(ocs, np, &prop);
997+
kfree(prop.value);
998+
999+
return ret;
1000+
}
1001+
EXPORT_SYMBOL_GPL(of_changeset_add_prop_string_array);
1002+
1003+
/**
1004+
* of_changeset_add_prop_u32_array - Add a property of 32 bit integers
1005+
* property to a changeset
1006+
*
1007+
* @ocs: changeset pointer
1008+
* @np: device node pointer
1009+
* @prop_name: name of the property to be added
1010+
* @array: pointer to an array of 32 bit integers
1011+
* @sz: number of array elements
1012+
*
1013+
* Create a property of 32 bit integers and add it to a changeset.
1014+
*
1015+
* Return: 0 on success, a negative error value in case of an error.
1016+
*/
1017+
int of_changeset_add_prop_u32_array(struct of_changeset *ocs,
1018+
struct device_node *np,
1019+
const char *prop_name,
1020+
const u32 *array, size_t sz)
1021+
{
1022+
struct property prop;
1023+
__be32 *val;
1024+
int i, ret;
1025+
1026+
val = kcalloc(sz, sizeof(__be32), GFP_KERNEL);
1027+
if (!val)
1028+
return -ENOMEM;
1029+
1030+
for (i = 0; i < sz; i++)
1031+
val[i] = cpu_to_be32(array[i]);
1032+
prop.name = (char *)prop_name;
1033+
prop.length = sizeof(u32) * sz;
1034+
prop.value = (void *)val;
1035+
1036+
ret = of_changeset_add_prop_helper(ocs, np, &prop);
1037+
kfree(val);
1038+
1039+
return ret;
1040+
}
1041+
EXPORT_SYMBOL_GPL(of_changeset_add_prop_u32_array);

drivers/of/unittest.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -802,7 +802,9 @@ static void __init of_unittest_changeset(void)
802802
struct property *ppname_n21, pname_n21 = { .name = "name", .length = 3, .value = "n21" };
803803
struct property *ppupdate, pupdate = { .name = "prop-update", .length = 5, .value = "abcd" };
804804
struct property *ppremove;
805-
struct device_node *n1, *n2, *n21, *nchangeset, *nremove, *parent, *np;
805+
struct device_node *n1, *n2, *n21, *n22, *nchangeset, *nremove, *parent, *np;
806+
static const char * const str_array[] = { "str1", "str2", "str3" };
807+
const u32 u32_array[] = { 1, 2, 3 };
806808
struct of_changeset chgset;
807809

808810
n1 = __of_node_dup(NULL, "n1");
@@ -857,6 +859,17 @@ static void __init of_unittest_changeset(void)
857859
unittest(!of_changeset_add_property(&chgset, parent, ppadd), "fail add prop prop-add\n");
858860
unittest(!of_changeset_update_property(&chgset, parent, ppupdate), "fail update prop\n");
859861
unittest(!of_changeset_remove_property(&chgset, parent, ppremove), "fail remove prop\n");
862+
n22 = of_changeset_create_node(&chgset, n2, "n22");
863+
unittest(n22, "fail create n22\n");
864+
unittest(!of_changeset_add_prop_string(&chgset, n22, "prop-str", "abcd"),
865+
"fail add prop prop-str");
866+
unittest(!of_changeset_add_prop_string_array(&chgset, n22, "prop-str-array",
867+
(const char **)str_array,
868+
ARRAY_SIZE(str_array)),
869+
"fail add prop prop-str-array");
870+
unittest(!of_changeset_add_prop_u32_array(&chgset, n22, "prop-u32-array",
871+
u32_array, ARRAY_SIZE(u32_array)),
872+
"fail add prop prop-u32-array");
860873

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

@@ -866,6 +879,9 @@ static void __init of_unittest_changeset(void)
866879
unittest((np = of_find_node_by_path("/testcase-data/changeset/n2/n21")),
867880
"'%pOF' not added\n", n21);
868881
of_node_put(np);
882+
unittest((np = of_find_node_by_path("/testcase-data/changeset/n2/n22")),
883+
"'%pOF' not added\n", n22);
884+
of_node_put(np);
869885

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

@@ -874,6 +890,7 @@ static void __init of_unittest_changeset(void)
874890
of_node_put(n1);
875891
of_node_put(n2);
876892
of_node_put(n21);
893+
of_node_put(n22);
877894
#endif
878895
}
879896

include/linux/of.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1579,6 +1579,29 @@ static inline int of_changeset_update_property(struct of_changeset *ocs,
15791579
{
15801580
return of_changeset_action(ocs, OF_RECONFIG_UPDATE_PROPERTY, np, prop);
15811581
}
1582+
1583+
struct device_node *of_changeset_create_node(struct of_changeset *ocs,
1584+
struct device_node *parent,
1585+
const char *full_name);
1586+
int of_changeset_add_prop_string(struct of_changeset *ocs,
1587+
struct device_node *np,
1588+
const char *prop_name, const char *str);
1589+
int of_changeset_add_prop_string_array(struct of_changeset *ocs,
1590+
struct device_node *np,
1591+
const char *prop_name,
1592+
const char **str_array, size_t sz);
1593+
int of_changeset_add_prop_u32_array(struct of_changeset *ocs,
1594+
struct device_node *np,
1595+
const char *prop_name,
1596+
const u32 *array, size_t sz);
1597+
static inline int of_changeset_add_prop_u32(struct of_changeset *ocs,
1598+
struct device_node *np,
1599+
const char *prop_name,
1600+
const u32 val)
1601+
{
1602+
return of_changeset_add_prop_u32_array(ocs, np, prop_name, &val, 1);
1603+
}
1604+
15821605
#else /* CONFIG_OF_DYNAMIC */
15831606
static inline int of_reconfig_notifier_register(struct notifier_block *nb)
15841607
{

0 commit comments

Comments
 (0)