Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751817AbdFJEjF (ORCPT ); Sat, 10 Jun 2017 00:39:05 -0400 Received: from mail-pg0-f66.google.com ([74.125.83.66]:36169 "EHLO mail-pg0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750945AbdFJEjD (ORCPT ); Sat, 10 Jun 2017 00:39:03 -0400 Subject: Re: [PATCH v4 1/4] of: remove *phandle properties from expanded device tree To: Rob Herring References: <1493693164-22826-1-git-send-email-frowand.list@gmail.com> <1493693164-22826-2-git-send-email-frowand.list@gmail.com> <593B5AD7.3010201@gmail.com> Cc: Stephen Boyd , "devicetree@vger.kernel.org" , "linux-kernel@vger.kernel.org" From: Frank Rowand Message-ID: <593B77B8.7000203@gmail.com> Date: Fri, 9 Jun 2017 21:38:16 -0700 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.4.0 MIME-Version: 1.0 In-Reply-To: <593B5AD7.3010201@gmail.com> Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 16976 Lines: 401 On 06/09/17 19:35, Frank Rowand wrote: > On 05/15/17 15:23, Rob Herring wrote: >> On Mon, May 1, 2017 at 9:46 PM, wrote: >>> From: Frank Rowand >>> >>> Remove "phandle", "linux,phandle", and "ibm,phandle" properties from >>> the internal device tree. The phandle will still be in the struct >>> device_node phandle field. >>> >>> This is to resolve the issue found by Stephen Boyd [1] when he changed >>> the type of struct property.value from void * to const void *. As >>> a result of the type change, the overlay code had compile errors >>> where the resolver updates phandle values. >>> >>> [1] http://lkml.iu.edu/hypermail/linux/kernel/1702.1/04160.html >>> >>> - Add sysfs infrastructure to report np->phandle, as if it was a property. >>> - Do not create "phandle" "ibm,phandle", and "linux,phandle" properties >>> in the expanded device tree. >>> - Remove phandle properties in of_attach_node(), for nodes dynamically >>> attached to the live tree. Add the phandle sysfs entry for these nodes. >>> - When creating an overlay changeset, duplicate the node phandle in >>> __of_node_dup(). >>> - Remove no longer needed checks to exclude "phandle" and "linux,phandle" >>> properties in several locations. >>> - A side effect of these changes is that the obsolete "linux,phandle" and >>> "ibm,phandle" properties will no longer appear in /proc/device-tree (they >>> will appear as "phandle"). >>> >>> Signed-off-by: Frank Rowand >>> --- >>> drivers/of/base.c | 48 ++++++++++++++++++++++++++++++++++++++++--- >>> drivers/of/dynamic.c | 54 +++++++++++++++++++++++++++++++++++++------------ >>> drivers/of/fdt.c | 40 +++++++++++++++++++++--------------- >>> drivers/of/of_private.h | 1 + >>> drivers/of/overlay.c | 4 +--- >>> drivers/of/resolver.c | 23 +-------------------- >>> include/linux/of.h | 1 + >>> 7 files changed, 114 insertions(+), 57 deletions(-) >>> >>> diff --git a/drivers/of/base.c b/drivers/of/base.c >>> index d7c4629a3a2d..8a0cf9003cf8 100644 >>> --- a/drivers/of/base.c >>> +++ b/drivers/of/base.c >>> @@ -116,6 +116,19 @@ static ssize_t of_node_property_read(struct file *filp, struct kobject *kobj, >>> return memory_read_from_buffer(buf, count, &offset, pp->value, pp->length); >>> } >>> >>> +static ssize_t of_node_phandle_read(struct file *filp, struct kobject *kobj, >>> + struct bin_attribute *bin_attr, char *buf, >>> + loff_t offset, size_t count) >>> +{ >>> + phandle phandle; >>> + struct device_node *np; >>> + >>> + np = container_of(bin_attr, struct device_node, attr_phandle); >>> + phandle = cpu_to_be32(np->phandle); >>> + return memory_read_from_buffer(buf, count, &offset, &phandle, >>> + sizeof(phandle)); >>> +} >>> + >>> /* always return newly allocated name, caller must free after use */ >>> static const char *safe_name(struct kobject *kobj, const char *orig_name) >>> { >>> @@ -164,6 +177,35 @@ int __of_add_property_sysfs(struct device_node *np, struct property *pp) >>> return rc; >>> } >>> >>> +/* >>> + * In the imported device tree (fdt), phandle is a property. In the >>> + * internal data structure it is instead stored in the struct device_node. >>> + * Make phandle visible in sysfs as if it was a property. >>> + */ >>> +int __of_add_phandle_sysfs(struct device_node *np) >>> +{ >>> + int rc; >>> + >>> + if (!IS_ENABLED(CONFIG_SYSFS)) >>> + return 0; >>> + >>> + if (!of_kset || !of_node_is_attached(np)) >>> + return 0; >>> + >>> + if (!np->phandle || np->phandle == 0xffffffff) >>> + return 0; >>> + >>> + sysfs_bin_attr_init(&np->attr_phandle); >>> + np->attr_phandle.attr.name = "phandle"; >>> + np->attr_phandle.attr.mode = 0444; >>> + np->attr_phandle.size = sizeof(np->phandle); >>> + np->attr_phandle.read = of_node_phandle_read; >>> + >>> + rc = sysfs_create_bin_file(&np->kobj, &np->attr_phandle); >>> + WARN(rc, "error adding attribute phandle to node %s\n", np->full_name); >>> + return rc; >>> +} >>> + >>> int __of_attach_node_sysfs(struct device_node *np) >>> { >>> const char *name; >>> @@ -193,6 +235,8 @@ int __of_attach_node_sysfs(struct device_node *np) >>> if (rc) >>> return rc; >>> >>> + __of_add_phandle_sysfs(np); >>> + >>> for_each_property_of_node(np, pp) >>> __of_add_property_sysfs(np, pp); >>> >>> @@ -2097,9 +2141,7 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)) >>> int id, len; >>> >>> /* Skip those we do not want to proceed */ >>> - if (!strcmp(pp->name, "name") || >>> - !strcmp(pp->name, "phandle") || >>> - !strcmp(pp->name, "linux,phandle")) >>> + if (!strcmp(pp->name, "name")) >>> continue; >>> >>> np = of_find_node_by_path(pp->value); >>> diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c >>> index 888fdbc09992..59545b8fbf46 100644 >>> --- a/drivers/of/dynamic.c >>> +++ b/drivers/of/dynamic.c >>> @@ -218,19 +218,6 @@ int of_property_notify(int action, struct device_node *np, >>> >>> void __of_attach_node(struct device_node *np) >>> { >>> - const __be32 *phandle; >>> - int sz; >>> - >>> - np->name = __of_get_property(np, "name", NULL) ? : ""; >>> - np->type = __of_get_property(np, "device_type", NULL) ? : ""; >>> - >>> - phandle = __of_get_property(np, "phandle", &sz); >>> - if (!phandle) >>> - phandle = __of_get_property(np, "linux,phandle", &sz); >>> - if (IS_ENABLED(CONFIG_PPC_PSERIES) && !phandle) >>> - phandle = __of_get_property(np, "ibm,phandle", &sz); >>> - np->phandle = (phandle && (sz >= 4)) ? be32_to_cpup(phandle) : 0; >>> - >>> np->child = NULL; >>> np->sibling = np->parent->child; >>> np->parent->child = np; >>> @@ -243,11 +230,47 @@ void __of_attach_node(struct device_node *np) >>> int of_attach_node(struct device_node *np) >>> { >>> struct of_reconfig_data rd; >>> + struct property *prev; >>> + struct property *prop; >>> + struct property *save_next; >>> unsigned long flags; >>> + const __be32 *phandle; >>> + int sz; >>> >>> memset(&rd, 0, sizeof(rd)); >>> rd.dn = np; >>> >>> + np->name = __of_get_property(np, "name", NULL) ? : ""; >>> + np->type = __of_get_property(np, "device_type", NULL) ? : ""; >> >> Why can't we just store NULL here? I know you're just moving this >> existing code, but now we have it twice. I assume there was some >> reason, so at least a comment why would be good. (I'm guessing it's >> because strcmp won't take a NULL). > > Comment added. > > (Yes, the users of the string pointer are not expecting NULL.) > > >>> + >>> + phandle = __of_get_property(np, "phandle", &sz); >>> + if (!phandle) >>> + phandle = __of_get_property(np, "linux,phandle", &sz); >>> + if (IS_ENABLED(CONFIG_PPC_PSERIES) && !phandle) >>> + phandle = __of_get_property(np, "ibm,phandle", &sz); >>> + np->phandle = (phandle && (sz >= 4)) ? be32_to_cpup(phandle) : 0; >>> + >>> + /* remove phandle properties from node */ >>> + prev = NULL; >>> + for (prop = np->properties; prop != NULL; ) { >>> + save_next = prop->next; >>> + if (!strcmp(prop->name, "phandle") || >>> + !strcmp(prop->name, "ibm,phandle") || >>> + !strcmp(prop->name, "linux,phandle")) { >>> + if (prev) >>> + prev->next = prop->next; >>> + else >>> + np->properties = prop->next; >>> + prop->next = np->deadprops; >>> + np->deadprops = prop; >>> + } else { >>> + prev = prop; >>> + } >>> + prop = save_next; >>> + } >>> + >>> + __of_add_phandle_sysfs(np); >>> + >>> mutex_lock(&of_mutex); >>> raw_spin_lock_irqsave(&devtree_lock, flags); >>> __of_attach_node(np); >>> @@ -429,6 +452,7 @@ struct device_node *__of_node_dup(const struct device_node *np, const char *fmt, >>> /* Iterate over and duplicate all properties */ >>> if (np) { >>> struct property *pp, *new_pp; >>> + node->phandle = np->phandle; >>> for_each_property_of_node(np, pp) { >>> new_pp = __of_prop_dup(pp, GFP_KERNEL); >>> if (!new_pp) >>> @@ -441,6 +465,10 @@ struct device_node *__of_node_dup(const struct device_node *np, const char *fmt, >>> } >>> } >>> } >>> + >>> + node->name = __of_get_property(node, "name", NULL) ? : ""; >>> + node->type = __of_get_property(node, "device_type", NULL) ? : ""; >>> + >>> return node; >>> >>> err_prop: >>> diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c >>> index e5ce4b59e162..270f31b0c259 100644 >>> --- a/drivers/of/fdt.c >>> +++ b/drivers/of/fdt.c >>> @@ -181,6 +181,8 @@ static void populate_properties(const void *blob, >>> const __be32 *val; >>> const char *pname; >>> u32 sz; >>> + int prop_is_phandle = 0; >>> + int prop_is_ibm_phandle = 0; >> >> Can be bool. > > These two variables eliminated while addressing the next comment. That change resulted in a warning for "make W=2", so prop_is_phandle added back, changed to bool. >>> >>> val = fdt_getprop_by_offset(blob, cur, &pname, &sz); >>> if (!val) { >>> @@ -196,11 +198,6 @@ static void populate_properties(const void *blob, >>> if (!strcmp(pname, "name")) >>> has_name = true; >>> >>> - pp = unflatten_dt_alloc(mem, sizeof(struct property), >>> - __alignof__(struct property)); >>> - if (dryrun) >>> - continue; >>> - >>> /* We accept flattened tree phandles either in >>> * ePAPR-style "phandle" properties, or the >>> * legacy "linux,phandle" properties. If both >>> @@ -208,23 +205,34 @@ static void populate_properties(const void *blob, >>> * will get weird. Don't do that. >>> */ >>> if (!strcmp(pname, "phandle") || >>> - !strcmp(pname, "linux,phandle")) { >>> - if (!np->phandle) >>> - np->phandle = be32_to_cpup(val); >>> - } >>> + !strcmp(pname, "linux,phandle")) >>> + prop_is_phandle = 1; >>> >>> /* And we process the "ibm,phandle" property >>> * used in pSeries dynamic device tree >>> * stuff >>> */ >>> - if (!strcmp(pname, "ibm,phandle")) >>> - np->phandle = be32_to_cpup(val); >>> + if (!strcmp(pname, "ibm,phandle")) { >>> + prop_is_phandle = 1; >>> + prop_is_ibm_phandle = 1; >>> + } >>> + >>> + if (!prop_is_phandle) >>> + pp = unflatten_dt_alloc(mem, sizeof(struct property), >>> + __alignof__(struct property)); >>> >>> - pp->name = (char *)pname; >>> - pp->length = sz; >>> - pp->value = (__be32 *)val; >>> - *pprev = pp; >>> - pprev = &pp->next; >>> + if (dryrun) >>> + continue; >>> + >>> + if (!prop_is_phandle) { >>> + pp->name = (char *)pname; >>> + pp->length = sz; >>> + pp->value = (__be32 *)val; >>> + *pprev = pp; >>> + pprev = &pp->next; >>> + } else if (prop_is_ibm_phandle || !np->phandle) { >> >> This logic is a bit strange. I think it would be a bit better if we >> can keep all the phandle code together and end with a continue, then >> have the property handling code at the end of the loop. > > I will do this. One side effect will be that the value of property > "ibm,phandle" will no longer override the value of properties "phandle" > and "linux,phandle". > > >>> + np->phandle = be32_to_cpup(val); >>> + } >>> } >>> >>> /* With version 0x10 we may not have the name property, >>> diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h >>> index 18bbb4517e25..33f11a5384f3 100644 >>> --- a/drivers/of/of_private.h >>> +++ b/drivers/of/of_private.h >>> @@ -47,6 +47,7 @@ extern int of_property_notify(int action, struct device_node *np, >>> extern void of_node_release(struct kobject *kobj); >>> extern int __of_changeset_apply(struct of_changeset *ocs); >>> extern int __of_changeset_revert(struct of_changeset *ocs); >>> +extern int __of_add_phandle_sysfs(struct device_node *np); >>> #else /* CONFIG_OF_DYNAMIC */ >>> static inline int of_property_notify(int action, struct device_node *np, >>> struct property *prop, struct property *old_prop) >>> diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c >>> index 7827786718d8..ca0b85f5deb1 100644 >>> --- a/drivers/of/overlay.c >>> +++ b/drivers/of/overlay.c >>> @@ -101,9 +101,7 @@ static int of_overlay_apply_single_property(struct of_overlay *ov, >>> tprop = of_find_property(target, prop->name, NULL); >>> >>> /* special properties are not meant to be updated (silent NOP) */ >>> - if (of_prop_cmp(prop->name, "name") == 0 || >>> - of_prop_cmp(prop->name, "phandle") == 0 || >>> - of_prop_cmp(prop->name, "linux,phandle") == 0) >>> + if (!of_prop_cmp(prop->name, "name")) >>> return 0; >>> >>> propn = __of_prop_dup(prop, GFP_KERNEL); >>> diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c >>> index 7ae9863cb0a4..624cbaeae0a4 100644 >>> --- a/drivers/of/resolver.c >>> +++ b/drivers/of/resolver.c >>> @@ -71,30 +71,11 @@ static void adjust_overlay_phandles(struct device_node *overlay, >>> int phandle_delta) >>> { >>> struct device_node *child; >>> - struct property *prop; >>> - phandle phandle; >>> >>> /* adjust node's phandle in node */ >>> if (overlay->phandle != 0 && overlay->phandle != OF_PHANDLE_ILLEGAL) >>> overlay->phandle += phandle_delta; >>> >>> - /* copy adjusted phandle into *phandle properties */ >>> - for_each_property_of_node(overlay, prop) { >>> - >>> - if (of_prop_cmp(prop->name, "phandle") && >>> - of_prop_cmp(prop->name, "linux,phandle")) >>> - continue; >>> - >>> - if (prop->length < 4) >>> - continue; >>> - >>> - phandle = be32_to_cpup(prop->value); >>> - if (phandle == OF_PHANDLE_ILLEGAL) >>> - continue; >>> - >>> - *(uint32_t *)prop->value = cpu_to_be32(overlay->phandle); >>> - } >>> - >>> for_each_child_of_node(overlay, child) >>> adjust_overlay_phandles(child, phandle_delta); >>> } >>> @@ -197,9 +178,7 @@ static int adjust_local_phandle_references(struct device_node *local_fixups, >>> for_each_property_of_node(local_fixups, prop_fix) { >>> >>> /* skip properties added automatically */ >>> - if (!of_prop_cmp(prop_fix->name, "name") || >>> - !of_prop_cmp(prop_fix->name, "phandle") || >>> - !of_prop_cmp(prop_fix->name, "linux,phandle")) >>> + if (!of_prop_cmp(prop_fix->name, "name")) >>> continue; >>> >>> if ((prop_fix->length % 4) != 0 || prop_fix->length == 0) >>> diff --git a/include/linux/of.h b/include/linux/of.h >>> index 21e6323de0f3..4e86e05853f3 100644 >>> --- a/include/linux/of.h >>> +++ b/include/linux/of.h >>> @@ -61,6 +61,7 @@ struct device_node { >>> struct kobject kobj; >>> unsigned long _flags; >>> void *data; >>> + struct bin_attribute attr_phandle; >>> #if defined(CONFIG_SPARC) >>> const char *path_component_name; >>> unsigned int unique_id; >>> -- >>> Frank Rowand > >