Ejemplo n.º 1
0
void fdt_fixup_ethernet(void *fdt)
{
	int i, j, prop;
	char *tmp, *end;
	char mac[16];
	const char *path;
	unsigned char mac_addr[ARP_HLEN];
	int offset;

	if (fdt_path_offset(fdt, "/aliases") < 0)
		return;

	/* Cycle through all aliases */
	for (prop = 0; ; prop++) {
		const char *name;

		/* FDT might have been edited, recompute the offset */
		offset = fdt_first_property_offset(fdt,
			fdt_path_offset(fdt, "/aliases"));
		/* Select property number 'prop' */
		for (i = 0; i < prop; i++)
			offset = fdt_next_property_offset(fdt, offset);

		if (offset < 0)
			break;

		path = fdt_getprop_by_offset(fdt, offset, &name, NULL);
		if (!strncmp(name, "ethernet", 8)) {
			/* Treat plain "ethernet" same as "ethernet0". */
			if (!strcmp(name, "ethernet"))
				i = 0;
			else
				i = trailing_strtol(name);

			if (i != -1) {
				if (i == 0)
					strcpy(mac, "ethaddr");
				else
					sprintf(mac, "eth%daddr", i);
			} else {
				continue;
			}
			tmp = env_get(mac);
			if (!tmp)
				continue;

			for (j = 0; j < 6; j++) {
				mac_addr[j] = tmp ?
					      simple_strtoul(tmp, &end, 16) : 0;
				if (tmp)
					tmp = (*end) ? end + 1 : end;
			}

			do_fixup_by_path(fdt, path, "mac-address",
					 &mac_addr, 6, 0);
			do_fixup_by_path(fdt, path, "local-mac-address",
					 &mac_addr, 6, 1);
		}
	}
}
Ejemplo n.º 2
0
/**
 * pinctrl_generic_set_state_one() - set state for a certain pin/group
 * Apply all pin multiplexing and pin configurations specified by @config
 * for a given pin or pin group.
 *
 * @dev: pin controller device
 * @config: pseudo device pointing to config node
 * @is_group: target of operation (true: pin group, false: pin)
 * @selector: pin selector or group selector, depending on @is_group
 * @return: 0 on success, or negative error code on failure
 */
static int pinctrl_generic_set_state_one(struct udevice *dev,
					 struct udevice *config,
					 bool is_group, unsigned selector)
{
	const void *fdt = gd->fdt_blob;
	int node_offset = config->of_offset;
	const char *propname;
	const void *value;
	int prop_offset, len, func_selector, param, ret;
	u32 arg, default_val;

	for (prop_offset = fdt_first_property_offset(fdt, node_offset);
	     prop_offset > 0;
	     prop_offset = fdt_next_property_offset(fdt, prop_offset)) {
		value = fdt_getprop_by_offset(fdt, prop_offset,
					      &propname, &len);
		if (!value)
			return -EINVAL;

		if (!strcmp(propname, "function")) {
			func_selector = pinmux_func_name_to_selector(dev,
								     value);
			if (func_selector < 0)
				return func_selector;
			ret = pinmux_enable_setting(dev, is_group,
						    selector,
						    func_selector);
		} else {
			param = pinconf_prop_name_to_param(dev, propname,
							   &default_val);
			if (param < 0)
				continue; /* just skip unknown properties */

			if (len >= sizeof(fdt32_t))
				arg = fdt32_to_cpu(*(fdt32_t *)value);
			else
				arg = default_val;

			ret = pinconf_enable_setting(dev, is_group,
						     selector, param, arg);
		}

		if (ret)
			return ret;
	}

	return 0;
}
Ejemplo n.º 3
0
static void compare_properties(const void *fdt1, int offset1,
			       const void *fdt2, int offset2)
{
	int offset = offset1;

	/* Check the properties */
	for (offset = fdt_first_property_offset(fdt1, offset1);
	     offset >= 0;
	     offset = fdt_next_property_offset(fdt1, offset)) {
		const char *name;
		int len1, len2;
		const void *data1, *data2;
		int i;

		data1 = fdt_getprop_by_offset(fdt1, offset, &name, &len1);
		if (!data1)
			FAIL("fdt_getprop_by_offset(): %s\n",
			     fdt_strerror(len1));

		verbose_printf("Property '%s'\n", name);

		data2 = fdt_getprop(fdt2, offset2, name, &len2);
		if (!data2) {
			if (len2 == -FDT_ERR_NOTFOUND)
				MISMATCH("Property '%s' missing\n", name);
			else
				FAIL("fdt_get_property(): %s\n",
				     fdt_strerror(len2));
		}

		verbose_printf("len1=%d data1=", len1);
		for (i = 0; i < len1; i++)
			verbose_printf(" %02x", ((const char *)data1)[i]);
		verbose_printf("\nlen2=%d data2=", len2);
		for (i = 0; i < len1; i++)
			verbose_printf(" %02x", ((const char *)data2)[i]);
		verbose_printf("\n");

		if (len1 != len2)
			MISMATCH("Property '%s' mismatched length %d vs. %d\n",
			     name, len1, len2);
		else if (memcmp(data1, data2, len1) != 0)
			MISMATCH("Property '%s' mismatched value\n", name);
	}
}
Ejemplo n.º 4
0
int fdtdec_get_alias_seq(const void *blob, const char *base, int offset,
			 int *seqp)
{
	int base_len = strlen(base);
	const char *find_name;
	int find_namelen;
	int prop_offset;
	int aliases;

	find_name = fdt_get_name(blob, offset, &find_namelen);
	debug("Looking for '%s' at %d, name %s\n", base, offset, find_name);

	aliases = fdt_path_offset(blob, "/aliases");
	for (prop_offset = fdt_first_property_offset(blob, aliases);
	     prop_offset > 0;
	     prop_offset = fdt_next_property_offset(blob, prop_offset)) {
		const char *prop;
		const char *name;
		const char *slash;
		const char *p;
		int len;

		prop = fdt_getprop_by_offset(blob, prop_offset, &name, &len);
		debug("   - %s, %s\n", name, prop);
		if (len < find_namelen || *prop != '/' || prop[len - 1] ||
		    strncmp(name, base, base_len))
			continue;

		slash = strrchr(prop, '/');
		if (strcmp(slash + 1, find_name))
			continue;
		for (p = name + strlen(name) - 1; p > name; p--) {
			if (!isdigit(*p)) {
				*seqp = simple_strtoul(p + 1, NULL, 10);
				debug("Found seq %d\n", *seqp);
				return 0;
			}
		}
	}

	debug("Not found\n");
	return -ENOENT;
}
Ejemplo n.º 5
0
/*
 * Handle __fixups__ node in overlay DTB
 */
static int
fdt_overlay_do_fixups(void *main_fdtp, void *overlay_fdtp)
{
	int main_symbols_o, symbol_o, overlay_fixups_o;
	int fixup_prop_o;
	int len;
	const char *fixups, *name;
	const char *symbol_path;
	uint32_t phandle;

	main_symbols_o = fdt_path_offset(main_fdtp, "/__symbols__");
	overlay_fixups_o = fdt_path_offset(overlay_fdtp, "/__fixups__");

	if (main_symbols_o < 0)
		return (-1);
	if (overlay_fixups_o < 0)
		return (-1);

	for (fixup_prop_o = fdt_first_property_offset(overlay_fdtp, overlay_fixups_o);
	    fixup_prop_o >= 0;
	    fixup_prop_o = fdt_next_property_offset(overlay_fdtp, fixup_prop_o)) {
		fixups = fdt_getprop_by_offset(overlay_fdtp, fixup_prop_o, &name, &len);
		symbol_path = fdt_getprop(main_fdtp, main_symbols_o, name, NULL);
		if (symbol_path == NULL) {
			printf("couldn't find \"%s\" symbol in main dtb\n", name);
			return (-1);
		}
		symbol_o = fdt_path_offset(main_fdtp, symbol_path);
		if (symbol_o < 0) {
			printf("couldn't find \"%s\" path in main dtb\n", symbol_path);
			return (-1);
		}
		phandle = fdt_get_phandle(main_fdtp, symbol_o);
		if (fdt_do_one_fixup(overlay_fdtp, fixups, len, phandle) < 0)
			return (-1);
	}

	return (0);
}
Ejemplo n.º 6
0
/*
 * Overlay one node defined by <overlay_fdtp, overlay_o> over <main_fdtp, target_o>
 */
static void
fdt_overlay_node(void *main_fdtp, int target_o, void *overlay_fdtp, int overlay_o)
{
	int len, o, depth;
	const char *name;
	const void *val;
	int target_subnode_o;

	/* Overlay properties */
	for (o = fdt_first_property_offset(overlay_fdtp, overlay_o);
	    o >= 0; o = fdt_next_property_offset(overlay_fdtp, o)) {
		val = fdt_getprop_by_offset(overlay_fdtp, o, &name, &len);
		if (val)
			fdt_setprop(main_fdtp, target_o, name, val, len);
	}

	/* Now overlay nodes */
	o = overlay_o;
        for (depth = 0; (o >= 0) && (depth >= 0);
	    o = fdt_next_node(overlay_fdtp, o, &depth)) {
		if (depth != 1)
			continue;
		/* Check if there is node with the same name */
		name = fdt_get_name(overlay_fdtp, o, NULL);
		target_subnode_o = fdt_subnode_offset(main_fdtp, target_o, name);
		if (target_subnode_o < 0) {
			/* create new subnode and run merge recursively */
			target_subnode_o = fdt_add_subnode(main_fdtp, target_o, name);
			if (target_subnode_o < 0) {
				printf("failed to create subnode \"%s\": %d\n",
				    name, target_subnode_o);
				return;
			}
		}

		fdt_overlay_node(main_fdtp, target_subnode_o,
		    overlay_fdtp, o);
	}
}
Ejemplo n.º 7
0
Archivo: fdt.c Proyecto: SonicFrog/OS
/**
 * unflatten_dt_node - Alloc and populate a device_node from the flat tree
 * @blob: The parent device tree blob
 * @mem: Memory chunk to use for allocating device nodes and properties
 * @p: pointer to node in flat tree
 * @dad: Parent struct device_node
 * @allnextpp: pointer to ->allnext from last allocated device_node
 * @fpsize: Size of the node path up at the current depth.
 */
static void * unflatten_dt_node(void *blob,
				void *mem,
				int *poffset,
				struct device_node *dad,
				struct device_node ***allnextpp,
				unsigned long fpsize)
{
	const __be32 *p;
	struct device_node *np;
	struct property *pp, **prev_pp = NULL;
	const char *pathp;
	unsigned int l, allocl;
	static int depth = 0;
	int old_depth;
	int offset;
	int has_name = 0;
	int new_format = 0;

	pathp = fdt_get_name(blob, *poffset, &l);
	if (!pathp)
		return mem;

	allocl = l++;

	/* version 0x10 has a more compact unit name here instead of the full
	 * path. we accumulate the full path size using "fpsize", we'll rebuild
	 * it later. We detect this because the first character of the name is
	 * not '/'.
	 */
	if ((*pathp) != '/') {
		new_format = 1;
		if (fpsize == 0) {
			/* root node: special case. fpsize accounts for path
			 * plus terminating zero. root node only has '/', so
			 * fpsize should be 2, but we want to avoid the first
			 * level nodes to have two '/' so we use fpsize 1 here
			 */
			fpsize = 1;
			allocl = 2;
			l = 1;
			pathp = "";
		} else {
			/* account for '/' and path size minus terminal 0
			 * already in 'l'
			 */
			fpsize += l;
			allocl = fpsize;
		}
	}

	np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
				__alignof__(struct device_node));
	if (allnextpp) {
		char *fn;
		of_node_init(np);
		np->full_name = fn = ((char *)np) + sizeof(*np);
		if (new_format) {
			/* rebuild full path for new format */
			if (dad && dad->parent) {
				strcpy(fn, dad->full_name);
#ifdef DEBUG
				if ((strlen(fn) + l + 1) != allocl) {
					pr_debug("%s: p: %d, l: %d, a: %d\n",
						pathp, (int)strlen(fn),
						l, allocl);
				}
#endif
				fn += strlen(fn);
			}
			*(fn++) = '/';
		}
		memcpy(fn, pathp, l);

		prev_pp = &np->properties;
		**allnextpp = np;
		*allnextpp = &np->allnext;
		if (dad != NULL) {
			np->parent = dad;
			/* we temporarily use the next field as `last_child'*/
			if (dad->next == NULL)
				dad->child = np;
			else
				dad->next->sibling = np;
			dad->next = np;
		}
	}
	/* process properties */
	for (offset = fdt_first_property_offset(blob, *poffset);
	     (offset >= 0);
	     (offset = fdt_next_property_offset(blob, offset))) {
		const char *pname;
		u32 sz;

		if (!(p = fdt_getprop_by_offset(blob, offset, &pname, &sz))) {
			offset = -FDT_ERR_INTERNAL;
			break;
		}

		if (pname == NULL) {
			pr_info("Can't find property name in list !\n");
			break;
		}
		if (strcmp(pname, "name") == 0)
			has_name = 1;
		pp = unflatten_dt_alloc(&mem, sizeof(struct property),
					__alignof__(struct property));
		if (allnextpp) {
			/* We accept flattened tree phandles either in
			 * ePAPR-style "phandle" properties, or the
			 * legacy "linux,phandle" properties.  If both
			 * appear and have different values, things
			 * will get weird.  Don't do that. */
			if ((strcmp(pname, "phandle") == 0) ||
			    (strcmp(pname, "linux,phandle") == 0)) {
				if (np->phandle == 0)
					np->phandle = be32_to_cpup(p);
			}
			/* And we process the "ibm,phandle" property
			 * used in pSeries dynamic device tree
			 * stuff */
			if (strcmp(pname, "ibm,phandle") == 0)
				np->phandle = be32_to_cpup(p);
			pp->name = (char *)pname;
			pp->length = sz;
			pp->value = (__be32 *)p;
			*prev_pp = pp;
			prev_pp = &pp->next;
		}
	}
	/* with version 0x10 we may not have the name property, recreate
	 * it here from the unit name if absent
	 */
	if (!has_name) {
		const char *p1 = pathp, *ps = pathp, *pa = NULL;
		int sz;

		while (*p1) {
			if ((*p1) == '@')
				pa = p1;
			if ((*p1) == '/')
				ps = p1 + 1;
			p1++;
		}
		if (pa < ps)
			pa = p1;
		sz = (pa - ps) + 1;
		pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
					__alignof__(struct property));
		if (allnextpp) {
			pp->name = "name";
			pp->length = sz;
			pp->value = pp + 1;
			*prev_pp = pp;
			prev_pp = &pp->next;
			memcpy(pp->value, ps, sz - 1);
			((char *)pp->value)[sz - 1] = 0;
			pr_debug("fixed up name for %s -> %s\n", pathp,
				(char *)pp->value);
		}
	}
	if (allnextpp) {
		*prev_pp = NULL;
		np->name = of_get_property(np, "name", NULL);
		np->type = of_get_property(np, "device_type", NULL);

		if (!np->name)
			np->name = "<NULL>";
		if (!np->type)
			np->type = "<NULL>";
	}

	old_depth = depth;
	*poffset = fdt_next_node(blob, *poffset, &depth);
	if (depth < 0)
		depth = 0;
	while (*poffset > 0 && depth > old_depth)
		mem = unflatten_dt_node(blob, mem, poffset, np, allnextpp,
					fpsize);

	if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND)
		pr_err("unflatten: error %d processing FDT\n", *poffset);

	return mem;
}
Ejemplo n.º 8
0
static int fdt_init_qdev(char *node_path, FDTMachineInfo *fdti, char *compat)
{
    int err;
    qemu_irq irq;
    hwaddr base;
    int offset;
    DeviceState *dev;
    char *dev_type = NULL;
    int is_intc;
    int i;

    dev = fdt_create_qdev_from_compat(compat, &dev_type);
    if (!dev) {
        DB_PRINT("no match found for %s\n", compat);
        return 1;
    }
    /* FIXME: attach to the sysbus instead */
    object_property_add_child(container_get(qdev_get_machine(), "/unattached"),
                              qemu_fdt_get_node_name(fdti->fdt, node_path),
                              OBJECT(dev), NULL);

    fdt_init_set_opaque(fdti, node_path, dev);

    /* connect nic if appropriate */
    static int nics;
    if (object_property_find(OBJECT(dev), "mac", NULL)) {
        qdev_set_nic_properties(dev, &nd_table[nics]);
        if (nd_table[nics].instantiated) {
            DB_PRINT("NIC instantiated: %s\n", dev_type);
            nics++;
        }
    }

    offset = fdt_path_offset(fdti->fdt, node_path);
    for (offset = fdt_first_property_offset(fdti->fdt, offset);
            offset != -FDT_ERR_NOTFOUND;
            offset = fdt_next_property_offset(fdti->fdt, offset)) {
        const char *propname;
        int len;
        const void *val = fdt_getprop_by_offset(fdti->fdt, offset,
                                                    &propname, &len);

        propname = trim_vendor(propname);
        ObjectProperty *p = object_property_find(OBJECT(dev), propname, NULL);
        if (p) {
            DB_PRINT("matched property: %s of type %s, len %d\n",
                                            propname, p->type, len);
        }
        if (!p) {
            continue;
        }

        /* FIXME: handle generically using accessors and stuff */
        if (!strcmp(p->type, "uint8") || !strcmp(p->type, "uint16") ||
                !strcmp(p->type, "uint32") || !strcmp(p->type, "uint64")) {
            uint64_t offset = (!strcmp(propname, "reg")) ?
                              fdt_get_parent_base(node_path, fdti) : 0;
            object_property_set_int(OBJECT(dev), get_int_be(val, len) + offset,
                                    propname, &error_abort);
            DB_PRINT("set property %s to %#llx\n", propname,
                                            (long long unsigned int)get_int_be(val, len));
        } else if (!strcmp(p->type, "bool")) {
            object_property_set_bool(OBJECT(dev), !!get_int_be(val, len),
                        propname, &error_abort);
            DB_PRINT("set property %s to %#llx\n", propname,
                                            (long long unsigned int)get_int_be(val, len));
        } else if (!strncmp(p->type, "link", 4)) {
            char target_node_path[DT_PATH_LENGTH];
            DeviceState *linked_dev;

            if (qemu_fdt_get_node_by_phandle(fdti->fdt, target_node_path,
                                                get_int_be(val, len))) {
                abort();
            }
            while (!fdt_init_has_opaque(fdti, target_node_path)) {
                fdt_init_yield(fdti);
            }
            linked_dev = fdt_init_get_opaque(fdti, target_node_path);
            object_property_set_link(OBJECT(dev), OBJECT(linked_dev), propname,
                                        &error_abort);
        } else if (!strcmp(p->type, "string")) {
            object_property_set_str(OBJECT(dev), strndup(val, len), propname, &error_abort);
	}
    }

    qdev_init_nofail(dev);
    /* map slave attachment */
    base = qemu_fdt_getprop_cell(fdti->fdt, node_path, "reg", 0, false, &error_abort);

    base += fdt_get_parent_base(node_path, fdti);
    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);

    {
        int len;
        fdt_get_property(fdti->fdt, fdt_path_offset(fdti->fdt, node_path),
                                "interrupt-controller", &len);
        is_intc = len >= 0;
        DB_PRINT("is interrupt controller: %c\n", is_intc ? 'y' : 'n');
    }
    /* connect irq */
    for (i = 0; ; ++i) {
        char irq_info[1024];
        irq = fdt_get_irq_info(fdti, node_path, i, &err, irq_info);
        /* INTCs inferr their top level, if no IRQ connection specified */
        if (err && is_intc) {
            irq = fdti->irq_base;
            sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
            fprintf(stderr, "FDT: (%s) connected top level irq %s\n", dev_type,
                        irq_info);
            break;
        }
        if (!err) {
            sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
            fprintf(stderr, "FDT: (%s) connected irq %s\n", dev_type, irq_info);
        } else {
            break;
        }
    }

    if (dev_type) {
        g_free(dev_type);
    }

    return 0;
}
Ejemplo n.º 9
0
void fdt_fixup_ethernet(void *fdt)
{
	int i = 0, j, prop;
	char *tmp, *end;
	char mac[16];
	const char *path;
	unsigned char mac_addr[ARP_HLEN];
	int offset;
#ifdef FDT_SEQ_MACADDR_FROM_ENV
	int nodeoff;
	const struct fdt_property *fdt_prop;
#endif

	if (fdt_path_offset(fdt, "/aliases") < 0)
		return;

	/* Cycle through all aliases */
	for (prop = 0; ; prop++) {
		const char *name;

		/* FDT might have been edited, recompute the offset */
		offset = fdt_first_property_offset(fdt,
			fdt_path_offset(fdt, "/aliases"));
		/* Select property number 'prop' */
		for (j = 0; j < prop; j++)
			offset = fdt_next_property_offset(fdt, offset);

		if (offset < 0)
			break;

		path = fdt_getprop_by_offset(fdt, offset, &name, NULL);
		if (!strncmp(name, "ethernet", 8)) {
			/* Treat plain "ethernet" same as "ethernet0". */
			if (!strcmp(name, "ethernet")
#ifdef FDT_SEQ_MACADDR_FROM_ENV
			 || !strcmp(name, "ethernet0")
#endif
			)
				i = 0;
#ifndef FDT_SEQ_MACADDR_FROM_ENV
			else
				i = trailing_strtol(name);
#endif
			if (i != -1) {
				if (i == 0)
					strcpy(mac, "ethaddr");
				else
					sprintf(mac, "eth%daddr", i);
			} else {
				continue;
			}
#ifdef FDT_SEQ_MACADDR_FROM_ENV
			nodeoff = fdt_path_offset(fdt, path);
			fdt_prop = fdt_get_property(fdt, nodeoff, "status",
						    NULL);
			if (fdt_prop && !strcmp(fdt_prop->data, "disabled"))
				continue;
			i++;
#endif
			tmp = env_get(mac);
			if (!tmp)
				continue;

			for (j = 0; j < 6; j++) {
				mac_addr[j] = tmp ?
					      simple_strtoul(tmp, &end, 16) : 0;
				if (tmp)
					tmp = (*end) ? end + 1 : end;
			}

			do_fixup_by_path(fdt, path, "mac-address",
					 &mac_addr, 6, 0);
			do_fixup_by_path(fdt, path, "local-mac-address",
					 &mac_addr, 6, 1);
		}
	}
}
Ejemplo n.º 10
0
Archivo: fdt.c Proyecto: acton393/linux
static void populate_properties(const void *blob,
				int offset,
				void **mem,
				struct device_node *np,
				const char *nodename,
				bool dryrun)
{
	struct property *pp, **pprev = NULL;
	int cur;
	bool has_name = false;

	pprev = &np->properties;
	for (cur = fdt_first_property_offset(blob, offset);
	     cur >= 0;
	     cur = fdt_next_property_offset(blob, cur)) {
		const __be32 *val;
		const char *pname;
		u32 sz;

		val = fdt_getprop_by_offset(blob, cur, &pname, &sz);
		if (!val) {
			pr_warn("Cannot locate property at 0x%x\n", cur);
			continue;
		}

		if (!pname) {
			pr_warn("Cannot find property name at 0x%x\n", cur);
			continue;
		}

		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
		 * appear and have different values, things
		 * will get weird. Don't do that.
		 */
		if (!strcmp(pname, "phandle") ||
		    !strcmp(pname, "linux,phandle")) {
			if (!np->phandle)
				np->phandle = be32_to_cpup(val);
		}

		/* 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);

		pp->name   = (char *)pname;
		pp->length = sz;
		pp->value  = (__be32 *)val;
		*pprev     = pp;
		pprev      = &pp->next;
	}

	/* With version 0x10 we may not have the name property,
	 * recreate it here from the unit name if absent
	 */
	if (!has_name) {
		const char *p = nodename, *ps = p, *pa = NULL;
		int len;

		while (*p) {
			if ((*p) == '@')
				pa = p;
			else if ((*p) == '/')
				ps = p + 1;
			p++;
		}

		if (pa < ps)
			pa = p;
		len = (pa - ps) + 1;
		pp = unflatten_dt_alloc(mem, sizeof(struct property) + len,
					__alignof__(struct property));
		if (!dryrun) {
			pp->name   = "name";
			pp->length = len;
			pp->value  = pp + 1;
			*pprev     = pp;
			pprev      = &pp->next;
			memcpy(pp->value, ps, len - 1);
			((char *)pp->value)[len - 1] = 0;
			pr_debug("fixed up name for %s -> %s\n",
				 nodename, (char *)pp->value);
		}
	}

	if (!dryrun)
		*pprev = NULL;
}