Message ID | 1665598440-47410-2-git-send-email-lizhi.hou@amd.com (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Bjorn Helgaas |
Headers | show |
Series | Generate device tree node for pci devices | expand |
Le 12/10/2022 à 20:13, Lizhi Hou a écrit : > of_create_node() creates device node and apply to base tree dynamically. > The parent device node and full name are required for creating the node. > And the caller can also provide a property array for the node. > > Inside this function, it creates a changeset. Then the new device node > and properties are added to the changeset and applied to base tree. The > pointer of this changeset is saved in device node private data. > > of_destroy_node() removes the node created by of_create_node() from the > base tree and free it. It gets the changeset pointer from device node > private data and call of_changeset_destroy() to free everything. > > Signed-off-by: Lizhi Hou <lizhi.hou@amd.com> > Signed-off-by: Sonal Santan <sonal.santan@amd.com> > Signed-off-by: Max Zhen <max.zhen@amd.com> > Signed-off-by: Brian Xu <brian.xu@amd.com> > --- > drivers/of/dynamic.c | 80 ++++++++++++++++++++++++++++++++++++++++++++ > include/linux/of.h | 4 +++ > 2 files changed, 84 insertions(+) > > diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c > index cd3821a6444f..eca28b723706 100644 > --- a/drivers/of/dynamic.c > +++ b/drivers/of/dynamic.c > @@ -934,3 +934,83 @@ int of_changeset_action(struct of_changeset *ocs, unsigned long action, > return 0; > } > EXPORT_SYMBOL_GPL(of_changeset_action); > + > +/** > + * of_create_node - Dynamically create a device node and apply it to base tree > + * > + * @parent: Pointer to parent device node > + * @full_name: Full name of device node > + * @props: Pointer to property array > + * > + * Return: Pointer to the created device node or NULL in case of an error. > + */ > +struct device_node *of_create_node(struct device_node *parent, > + const char *full_name, > + struct property *props) > +{ > + struct of_changeset *cset; > + struct property *new_pp; > + struct device_node *np; > + int ret, i; > + > + cset = kzalloc(sizeof(*cset), GFP_KERNEL); Hi, kmalloc() would be enough. of_changeset_init() below already calls memset(). > + if (!cset) > + return NULL; > + > + of_changeset_init(cset); > + > + np = __of_node_dup(NULL, full_name); > + if (!np) > + goto failed; 'cset' seems to be leaking if __of_node_dup() fails. > + np->parent = parent; > + > + ret = of_changeset_attach_node(cset, np); > + if (ret) > + goto failed; > + > + if (props) { > + for (i = 0; props[i].name; i++) { > + new_pp = __of_prop_dup(&props[i], GFP_KERNEL); > + if (!new_pp) > + goto failed; > + ret = of_changeset_add_property(cset, np, new_pp); > + if (ret) { > + kfree(new_pp->name); > + kfree(new_pp->value); > + kfree(new_pp); > + goto failed; > + } > + } > + } > + > + ret = of_changeset_apply(cset); > + if (ret) > + goto failed; > + > + np->data = cset; > + > + return np; > + > +failed: > + of_changeset_destroy(cset); > + if (np) > + of_node_put(np); > + > + return NULL; > +} > + > +/** > + * of_destroy_node - Destroy a dynamically created device node > + * > + * @np: Pointer to dynamically created device node > + * > + */ > +void of_destroy_node(struct device_node *np) > +{ > + struct of_changeset *cset; > + > + cset = (struct of_changeset *)np->data; > + of_changeset_destroy(cset); > + of_node_put(np); > + kfree(cset); > +} > diff --git a/include/linux/of.h b/include/linux/of.h > index 766d002bddb9..493ef957c1a8 100644 > --- a/include/linux/of.h > +++ b/include/linux/of.h > @@ -1475,6 +1475,10 @@ extern int of_changeset_revert(struct of_changeset *ocs); > extern int of_changeset_action(struct of_changeset *ocs, > unsigned long action, struct device_node *np, > struct property *prop); > +struct device_node *of_create_node(struct device_node *parent, > + const char *full_name, > + struct property *props); > +void of_destroy_node(struct device_node *np); > > static inline int of_changeset_attach_node(struct of_changeset *ocs, > struct device_node *np)
On 11/1/22 00:47, Christophe JAILLET wrote: > Le 12/10/2022 à 20:13, Lizhi Hou a écrit : >> of_create_node() creates device node and apply to base tree dynamically. >> The parent device node and full name are required for creating the node. >> And the caller can also provide a property array for the node. >> >> Inside this function, it creates a changeset. Then the new device node >> and properties are added to the changeset and applied to base tree. The >> pointer of this changeset is saved in device node private data. >> >> of_destroy_node() removes the node created by of_create_node() from the >> base tree and free it. It gets the changeset pointer from device node >> private data and call of_changeset_destroy() to free everything. >> >> Signed-off-by: Lizhi Hou <lizhi.hou@amd.com> >> Signed-off-by: Sonal Santan <sonal.santan@amd.com> >> Signed-off-by: Max Zhen <max.zhen@amd.com> >> Signed-off-by: Brian Xu <brian.xu@amd.com> >> --- >> drivers/of/dynamic.c | 80 ++++++++++++++++++++++++++++++++++++++++++++ >> include/linux/of.h | 4 +++ >> 2 files changed, 84 insertions(+) >> >> diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c >> index cd3821a6444f..eca28b723706 100644 >> --- a/drivers/of/dynamic.c >> +++ b/drivers/of/dynamic.c >> @@ -934,3 +934,83 @@ int of_changeset_action(struct of_changeset >> *ocs, unsigned long action, >> return 0; >> } >> EXPORT_SYMBOL_GPL(of_changeset_action); >> + >> +/** >> + * of_create_node - Dynamically create a device node and apply it to >> base tree >> + * >> + * @parent: Pointer to parent device node >> + * @full_name: Full name of device node >> + * @props: Pointer to property array >> + * >> + * Return: Pointer to the created device node or NULL in case of an >> error. >> + */ >> +struct device_node *of_create_node(struct device_node *parent, >> + const char *full_name, >> + struct property *props) >> +{ >> + struct of_changeset *cset; >> + struct property *new_pp; >> + struct device_node *np; >> + int ret, i; >> + >> + cset = kzalloc(sizeof(*cset), GFP_KERNEL); > > Hi, > > kmalloc() would be enough. of_changeset_init() below already calls > memset(). Ok. > >> + if (!cset) >> + return NULL; >> + >> + of_changeset_init(cset); >> + >> + np = __of_node_dup(NULL, full_name); >> + if (!np) >> + goto failed; > > 'cset' seems to be leaking if __of_node_dup() fails. Will fix this. Thanks. Lizhi > >> + np->parent = parent; >> + >> + ret = of_changeset_attach_node(cset, np); >> + if (ret) >> + goto failed; >> + >> + if (props) { >> + for (i = 0; props[i].name; i++) { >> + new_pp = __of_prop_dup(&props[i], GFP_KERNEL); >> + if (!new_pp) >> + goto failed; >> + ret = of_changeset_add_property(cset, np, new_pp); >> + if (ret) { >> + kfree(new_pp->name); >> + kfree(new_pp->value); >> + kfree(new_pp); >> + goto failed; >> + } >> + } >> + } >> + >> + ret = of_changeset_apply(cset); >> + if (ret) >> + goto failed; >> + >> + np->data = cset; >> + >> + return np; >> + >> +failed: >> + of_changeset_destroy(cset); >> + if (np) >> + of_node_put(np); >> + >> + return NULL; >> +} >> + >> +/** >> + * of_destroy_node - Destroy a dynamically created device node >> + * >> + * @np: Pointer to dynamically created device node >> + * >> + */ >> +void of_destroy_node(struct device_node *np) >> +{ >> + struct of_changeset *cset; >> + >> + cset = (struct of_changeset *)np->data; >> + of_changeset_destroy(cset); >> + of_node_put(np); >> + kfree(cset); >> +} >> diff --git a/include/linux/of.h b/include/linux/of.h >> index 766d002bddb9..493ef957c1a8 100644 >> --- a/include/linux/of.h >> +++ b/include/linux/of.h >> @@ -1475,6 +1475,10 @@ extern int of_changeset_revert(struct >> of_changeset *ocs); >> extern int of_changeset_action(struct of_changeset *ocs, >> unsigned long action, struct device_node *np, >> struct property *prop); >> +struct device_node *of_create_node(struct device_node *parent, >> + const char *full_name, >> + struct property *props); >> +void of_destroy_node(struct device_node *np); >> static inline int of_changeset_attach_node(struct of_changeset *ocs, >> struct device_node *np) >
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index cd3821a6444f..eca28b723706 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c @@ -934,3 +934,83 @@ int of_changeset_action(struct of_changeset *ocs, unsigned long action, return 0; } EXPORT_SYMBOL_GPL(of_changeset_action); + +/** + * of_create_node - Dynamically create a device node and apply it to base tree + * + * @parent: Pointer to parent device node + * @full_name: Full name of device node + * @props: Pointer to property array + * + * Return: Pointer to the created device node or NULL in case of an error. + */ +struct device_node *of_create_node(struct device_node *parent, + const char *full_name, + struct property *props) +{ + struct of_changeset *cset; + struct property *new_pp; + struct device_node *np; + int ret, i; + + cset = kzalloc(sizeof(*cset), GFP_KERNEL); + if (!cset) + return NULL; + + of_changeset_init(cset); + + np = __of_node_dup(NULL, full_name); + if (!np) + goto failed; + np->parent = parent; + + ret = of_changeset_attach_node(cset, np); + if (ret) + goto failed; + + if (props) { + for (i = 0; props[i].name; i++) { + new_pp = __of_prop_dup(&props[i], GFP_KERNEL); + if (!new_pp) + goto failed; + ret = of_changeset_add_property(cset, np, new_pp); + if (ret) { + kfree(new_pp->name); + kfree(new_pp->value); + kfree(new_pp); + goto failed; + } + } + } + + ret = of_changeset_apply(cset); + if (ret) + goto failed; + + np->data = cset; + + return np; + +failed: + of_changeset_destroy(cset); + if (np) + of_node_put(np); + + return NULL; +} + +/** + * of_destroy_node - Destroy a dynamically created device node + * + * @np: Pointer to dynamically created device node + * + */ +void of_destroy_node(struct device_node *np) +{ + struct of_changeset *cset; + + cset = (struct of_changeset *)np->data; + of_changeset_destroy(cset); + of_node_put(np); + kfree(cset); +} diff --git a/include/linux/of.h b/include/linux/of.h index 766d002bddb9..493ef957c1a8 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -1475,6 +1475,10 @@ extern int of_changeset_revert(struct of_changeset *ocs); extern int of_changeset_action(struct of_changeset *ocs, unsigned long action, struct device_node *np, struct property *prop); +struct device_node *of_create_node(struct device_node *parent, + const char *full_name, + struct property *props); +void of_destroy_node(struct device_node *np); static inline int of_changeset_attach_node(struct of_changeset *ocs, struct device_node *np)