libfdt: Property iteration
David Gibson
david at gibson.dropbear.id.au
Fri Nov 7 14:39:25 EST 2008
On Fri, Nov 07, 2008 at 01:54:44PM +1100, David Gibson wrote:
> On Mon, Oct 27, 2008 at 05:14:41PM -0500, Scott Wood wrote:
> > A while back when discussing property iterators
> > (http://ozlabs.org/pipermail/linuxppc-dev/2008-January/049891.html), you
> > said that you'd prefer not to expose property offsets, because more
> > common uses would be affected by changing offsets. I'm looking again at
> > this, and was wondering what alternative and would-be-broken use cases
> > you were thinking of?
>
> Hrm, well I didn't have things in mind all that precisely. I was just
> thinking that it's fairly common to grab a node, then manipulate
> various properties within it in a more-or-less random-access sort of
> way.
>
> Whereas when finding nodes, ofetn one tends to work down the tree to a
> particular node, and the only things you're interested in keeping tabs
> on (for a little while at least) are some of the ancestors of this
> node - whose offsets are guaranteed not to be messed with by
> manipulations within the descendant.
>
> > We could operate on property indices or names at an efficiency cost.
> > Most nodes should be small enough that the cost isn't too much, but I'd
> > like to know which use cases really need it. The ones I'd use it for
> > involve reading from one tree and adding to another, so moving offsets
> > aren't an issue.
>
> I don't think indices buy us much over offsets. They can still change
> with node insertions or deletions.
>
> > Even in a use case where one makes in-place changes while iterating over
> > properties, changes to the property currently being iterated over should
> > only move later properties -- the next call to fdt_next_prop would be
> > based on the start of the property that was modified, which did not
> > change.
>
> That's true; unless you delete the property entirely. Inserting an
> unrelated property is also potentially dangerous, though from the
> looks of it we always insert properties at the end in libfdt, so that
> should work ok.
>
> Fwiw, I (somewhat reluctantly) accepted the need for property offsets,
> in the prototype patch for property iteration I had. I was going to
> polish it up and push it out, but got sidetracked by other things.
> I've included it below, maybe you'll get to the polishing before I
> do.
Uh.. here's a version that's been fixed up to at least apply to the
current tree.
Index: dtc/libfdt/fdt.c
===================================================================
--- dtc.orig/libfdt/fdt.c 2008-11-07 14:32:36.000000000 +1100
+++ dtc/libfdt/fdt.c 2008-11-07 14:32:48.000000000 +1100
@@ -90,6 +90,31 @@ const void *fdt_offset_ptr(const void *f
return p;
}
+const struct fdt_property *_fdt_offset_property(const void *fdt, int offset,
+ int *lenp)
+{
+ const struct fdt_property *prop;
+ int len;
+
+ if (lenp)
+ *lenp = -FDT_ERR_BADSTRUCTURE;
+
+ prop = fdt_offset_ptr(fdt, offset, sizeof(*prop));
+ if (!prop)
+ return NULL;
+
+ len = fdt32_to_cpu(prop->len);
+
+ prop = fdt_offset_ptr(fdt, offset, sizeof(*prop)+len);
+ if (!prop)
+ return NULL;
+
+ if (lenp)
+ *lenp = len;
+
+ return prop;
+}
+
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset)
{
const uint32_t *tagp, *lenp;
@@ -177,6 +202,46 @@ int fdt_next_node(const void *fdt, int o
return offset;
}
+int _fdt_next_property(const void *fdt, int offset)
+{
+ uint32_t tag;
+ int nextoffset;
+ int err;
+
+ if ((err = fdt_check_header(fdt)) != 0)
+ return err;
+
+ if (offset % FDT_TAGSIZE)
+ return -FDT_ERR_BADOFFSET;
+
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+ if ((tag != FDT_BEGIN_NODE) && (tag != FDT_PROP))
+ return -FDT_ERR_BADOFFSET;
+
+ do {
+ offset = nextoffset;
+
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+ switch (tag) {
+ case FDT_END:
+ return -FDT_ERR_TRUNCATED;
+
+ case FDT_BEGIN_NODE:
+ case FDT_END_NODE:
+ case FDT_NOP:
+ break;
+
+ case FDT_PROP:
+ return offset;
+
+ default:
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+ } while (tag == FDT_NOP);
+
+ return -FDT_ERR_NOTFOUND;
+}
+
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
{
int len = strlen(s) + 1;
Index: dtc/libfdt/fdt_ro.c
===================================================================
--- dtc.orig/libfdt/fdt_ro.c 2008-11-07 14:32:36.000000000 +1100
+++ dtc/libfdt/fdt_ro.c 2008-11-07 14:38:59.000000000 +1100
@@ -203,62 +203,20 @@ const struct fdt_property *fdt_get_prope
const char *name,
int namelen, int *lenp)
{
- uint32_t tag;
const struct fdt_property *prop;
- int namestroff;
- int offset, nextoffset;
- int err;
-
- if (((err = fdt_check_header(fdt)) != 0)
- || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
- goto fail;
-
- nextoffset = err;
- do {
- offset = nextoffset;
-
- tag = fdt_next_tag(fdt, offset, &nextoffset);
- switch (tag) {
- case FDT_END:
- err = -FDT_ERR_TRUNCATED;
- goto fail;
-
- case FDT_BEGIN_NODE:
- case FDT_END_NODE:
- case FDT_NOP:
- break;
-
- case FDT_PROP:
- err = -FDT_ERR_BADSTRUCTURE;
- prop = fdt_offset_ptr(fdt, offset, sizeof(*prop));
- if (! prop)
- goto fail;
- namestroff = fdt32_to_cpu(prop->nameoff);
- if (_fdt_string_eq(fdt, namestroff, name, namelen)) {
- /* Found it! */
- int len = fdt32_to_cpu(prop->len);
- prop = fdt_offset_ptr(fdt, offset,
- sizeof(*prop)+len);
- if (! prop)
- goto fail;
+ int offset = nodeoffset;
- if (lenp)
- *lenp = len;
-
- return prop;
- }
- break;
-
- default:
- err = -FDT_ERR_BADSTRUCTURE;
- goto fail;
- }
- } while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));
+ while ((offset = _fdt_next_property(fdt, offset)) >= 0) {
+ prop = _fdt_offset_property(fdt, offset, lenp);
+ if (!prop)
+ return NULL;
+ if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), name, namelen))
+ /* Found it! */
+ return prop;
+ }
- err = -FDT_ERR_NOTFOUND;
- fail:
if (lenp)
- *lenp = err;
+ *lenp = offset;
return NULL;
}
Index: dtc/libfdt/libfdt_internal.h
===================================================================
--- dtc.orig/libfdt/libfdt_internal.h 2008-11-07 14:32:36.000000000 +1100
+++ dtc/libfdt/libfdt_internal.h 2008-11-07 14:32:48.000000000 +1100
@@ -63,6 +63,7 @@
}
uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset);
+int _fdt_next_property(const void *fdt, int offset);
int _fdt_check_node_offset(const void *fdt, int offset);
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
int _fdt_node_end_offset(void *fdt, int nodeoffset);
Index: dtc/libfdt/libfdt.h
===================================================================
--- dtc.orig/libfdt/libfdt.h 2008-11-07 14:32:48.000000000 +1100
+++ dtc/libfdt/libfdt.h 2008-11-07 14:32:48.000000000 +1100
@@ -128,6 +128,9 @@ static inline void *fdt_offset_ptr_w(voi
return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
}
+const struct fdt_property *_fdt_offset_property(const void *fdt, int offset,
+ int *lenp);
+
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
/**********************************************************************/
@@ -136,6 +139,11 @@ uint32_t fdt_next_tag(const void *fdt, i
int fdt_next_node(const void *fdt, int offset, int *depth);
+#define for_each_property(fdt, node, prop, len) \
+ for (int _off = fdt_next_property((fdt), (node)); \
+ (_off >= 0) && \
+ (((prop) = fdt_offset_property((fdt), _off, &(len))) >= 0);)
+
/**********************************************************************/
/* General functions */
/**********************************************************************/
@@ -256,6 +264,7 @@ int fdt_num_mem_rsv(const void *fdt);
*/
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
+
/**
* fdt_subnode_offset_namelen - find a subnode based on substring
* @fdt: pointer to the device tree blob
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
More information about the devicetree-discuss
mailing list