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); } } }
void dump_fdt(const void *fdt) { int err; dprintf("FDT @ %p:\n", fdt); if (!fdt) return; err = fdt_check_header(fdt); if (err) { dprintf("fdt error: %s\n", fdt_strerror(err)); return; } dprintf("fdt_totalsize: %d\n", fdt_totalsize(fdt)); dprintf("fdt_off_dt_struct: %d\n", fdt_off_dt_struct(fdt)); dprintf("fdt_off_dt_strings: %d\n", fdt_off_dt_strings(fdt)); dprintf("fdt_off_mem_rsvmap: %d\n", fdt_off_mem_rsvmap(fdt)); dprintf("fdt_version: %d\n", fdt_version(fdt)); dprintf("fdt_last_comp_version: %d\n", fdt_last_comp_version(fdt)); dprintf("fdt_boot_cpuid_phys: %d\n", fdt_boot_cpuid_phys(fdt)); dprintf("fdt_size_dt_strings: %d\n", fdt_size_dt_strings(fdt)); dprintf("fdt_size_dt_struct: %d\n", fdt_size_dt_struct(fdt)); #ifdef FDT_DUMP_NODES dprintf("fdt tree:\n"); int node = -1; int depth = 0; while ((node = fdt_next_node(fdt, node, &depth)) >= 0) { dprintf(DS"node at %d: '%s'\n", DA, node, fdt_get_name(fdt, node, NULL)); #ifdef FDT_DUMP_PROPS int prop, len; const struct fdt_property *property; prop = fdt_first_property_offset(fdt, node); while (prop >= 0) { property = fdt_get_property_by_offset(fdt, prop, &len); if (property == NULL) { dprintf("getting prop at %d: %s\n", prop, fdt_strerror(len)); break; } dprintf(DS" prop at %d: '%s', len %d\n", DA, prop, fdt_string(fdt, fdt32_to_cpu(property->nameoff)), fdt32_to_cpu(property->len)); #ifdef FDT_DUMP_PROP_VALUES dump_hex(property->data, fdt32_to_cpu(property->len), depth); #endif prop = fdt_next_property_offset(fdt, prop); } #endif } #endif }
/** * h_include() - Include handler function for fdt_find_regions() * * This function decides whether to include or exclude a node, property or * compatible string. The function is defined by fdt_find_regions(). * * The algorithm is documented in the code - disp->invert is 0 for normal * operation, and 1 to invert the sense of all matches. * * See */ static int h_include(void *priv, const void *fdt, int offset, int type, const char *data, int size) { struct display_info *disp = priv; int inc, len; inc = check_type_include(priv, type, data, size); if (disp->include_root && type == FDT_IS_PROP && offset == 0 && inc) return 1; /* * If the node name does not tell us anything, check the * compatible string */ if (inc == -1 && type == FDT_IS_NODE) { debug(" - checking compatible2\n"); data = fdt_getprop(fdt, offset, "compatible", &len); inc = check_type_include(priv, FDT_IS_COMPAT, data, len); } /* If we still have no idea, check for properties in the node */ if (inc != 1 && type == FDT_IS_NODE && (disp->types_inc & FDT_NODE_HAS_PROP)) { debug(" - checking node '%s'\n", fdt_get_name(fdt, offset, NULL)); for (offset = fdt_first_property_offset(fdt, offset); offset > 0 && inc != 1; offset = fdt_next_property_offset(fdt, offset)) { const struct fdt_property *prop; const char *str; prop = fdt_get_property_by_offset(fdt, offset, NULL); if (!prop) continue; str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); inc = check_type_include(priv, FDT_NODE_HAS_PROP, str, strlen(str)); } if (inc == -1) inc = 0; } switch (inc) { case 1: inc = !disp->invert; break; case 0: inc = disp->invert; break; } debug(" - returning %d\n", inc); return inc; }
/** * 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; }
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); } }
static int list_properties(const void *blob, int node) { const struct fdt_property *data; const char *name; int prop; prop = fdt_first_property_offset(blob, node); do { /* */ if (prop < 0) return prop == -FDT_ERR_NOTFOUND ? 0 : prop; data = fdt_get_property_by_offset(blob, prop, NULL); name = fdt_string(blob, fdt32_to_cpu(data->nameoff)); if (name) puts(name); prop = fdt_next_property_offset(blob, prop); } while (1); }
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; }
/* * Get the next property of a package. Return values: * -1: package or previous property does not exist * 0: no more properties * 1: success */ static int ofw_fdt_nextprop(ofw_t ofw, phandle_t package, const char *previous, char *buf, size_t size) { const struct fdt_property *prop; const char *name; int offset; offset = fdt_phandle_offset(package); if (offset < 0) return (-1); /* Find the first prop in the node */ offset = fdt_first_property_offset(fdtp, offset); if (offset < 0) return (0); /* No properties */ if (previous != NULL) { while (offset >= 0) { prop = fdt_get_property_by_offset(fdtp, offset, NULL); if (prop == NULL) return (-1); /* Internal error */ offset = fdt_next_property_offset(fdtp, offset); if (offset < 0) return (0); /* No more properties */ /* Check if the last one was the one we wanted */ name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff)); if (strcmp(name, previous) == 0) break; } } prop = fdt_get_property_by_offset(fdtp, offset, &offset); if (prop == NULL) return (-1); /* Internal error */ strncpy(buf, fdt_string(fdtp, fdt32_to_cpu(prop->nameoff)), size); return (1); }
/* * chosen { * bootargs="console=ttyS0,115200 ubi.mtd=4 root=ubi0:rootfs rootfstype=ubifs"; * }; * offset: node "/chosen"의 offset * name: property "bootargs" * namelen: property "bootargs" 길이 * lenp: property 내용의 길이 */ const struct fdt_property *fdt_get_property_namelen(const void *fdt, int offset, const char *name, int namelen, int *lenp) { /* * node안의 property들을 순회하면서 찾고자 하는 name의 property 리턴 * 참고로 아래 for문에서 offset을 계속 받아오면서 값을 체크하고 있음 * 즉, 순회하면서 찾는 property가 없거나 탐색시 에러가 나면 탐색 중단 */ for (offset = fdt_first_property_offset(fdt, offset); (offset >= 0); (offset = fdt_next_property_offset(fdt, offset))) { const struct fdt_property *prop; /* * offset만큼 위치한 property에 접근해서 * lenp에 property의 value의 길이를 저장 * 하지만 에러가 나는 경우엔 for문을 빠져나감 */ if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) { offset = -FDT_ERR_INTERNAL; break; } /* * 찾고자 하는 property가 맞는지 확인하고 * 맞다면 가져온 property 구조체를 리턴 */ if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), name, namelen)) return prop; } /* * 찾는 property가 없는경우 or property 접근하다 에러가 난 경우 * lenp에 에러값 저장 */ if (lenp) *lenp = offset; return NULL; }
/* * 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); }
const struct fdt_property *fdt_get_property_namelen(const void *fdt, int offset, const char *name, int namelen, int *lenp) { for (offset = fdt_first_property_offset(fdt, offset); (offset >= 0); (offset = fdt_next_property_offset(fdt, offset))) { const struct fdt_property *prop; if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) { offset = -FDT_ERR_INTERNAL; break; } if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), name, namelen)) return prop; } if (lenp) *lenp = offset; return NULL; }
static dt_node_t add_device_fdt(dt_node_t parent, void *fdt, int fdt_node, int depth) { const char *name = fdt_get_name(fdt, fdt_node, NULL); printf("%*cEnumerating \"%s\"\n", depth, ' ', name); dt_node_t n = dt_node_alloc(parent, name); if (!n) panic("Out of memory enumerating node \"%s\"\n", name); for (int propoff = fdt_first_property_offset(fdt, fdt_node); propoff >= 0; propoff = fdt_next_property_offset(fdt, propoff)) { int len; const struct fdt_property *fdt_prop = fdt_get_property_by_offset(fdt, propoff, &len); if (!fdt_prop) { panic("Error getting property of \"%s\": %s\n", name, fdt_strerror(len)); } const char *prop_name = fdt_string(fdt, fdt32_to_cpu(fdt_prop->nameoff)); printf("%*c \"%s\" = \"", depth, ' ', prop_name); print_dtval(fdt_prop->data, len); printf("\"\n"); if (!dt_node_set_property(n, prop_name, fdt_prop->data, len)) panic("Out of memory allocating \"%s\":\"%s\"", name, prop_name); } for (int suboff = fdt_first_subnode(fdt, fdt_node); suboff != -FDT_ERR_NOTFOUND; suboff = fdt_next_subnode(fdt, suboff)) { add_device_fdt(n, fdt, suboff, depth + 2); } return n; }
/* * 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); } }
/** * 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; }
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; }
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; }
/* TODO: Can we tighten this code up a little? */ int fdtdec_add_aliases_for_id(const void *blob, const char *name, enum fdt_compat_id id, int *node_list, int maxcount) { int name_len = strlen(name); int nodes[maxcount]; int num_found = 0; int offset, node; int alias_node; int count; int i, j; /* find the alias node if present */ alias_node = fdt_path_offset(blob, "/aliases"); /* * start with nothing, and we can assume that the root node can't * match */ memset(nodes, '\0', sizeof(nodes)); /* First find all the compatible nodes */ for (node = count = 0; node >= 0 && count < maxcount;) { node = fdtdec_next_compatible(blob, node, id); if (node >= 0) nodes[count++] = node; } if (node >= 0) debug("%s: warning: maxcount exceeded with alias '%s'\n", __func__, name); /* Now find all the aliases */ for (offset = fdt_first_property_offset(blob, alias_node); offset > 0; offset = fdt_next_property_offset(blob, offset)) { const struct fdt_property *prop; const char *path; int number; int found; node = 0; prop = fdt_get_property_by_offset(blob, offset, NULL); path = fdt_string(blob, fdt32_to_cpu(prop->nameoff)); if (prop->len && 0 == strncmp(path, name, name_len)) node = fdt_path_offset(blob, prop->data); if (node <= 0) continue; /* Get the alias number */ number = simple_strtoul(path + name_len, NULL, 10); if (number < 0 || number >= maxcount) { debug("%s: warning: alias '%s' is out of range\n", __func__, path); continue; } /* Make sure the node we found is actually in our list! */ found = -1; for (j = 0; j < count; j++) if (nodes[j] == node) { found = j; break; } if (found == -1) { debug("%s: warning: alias '%s' points to a node " "'%s' that is missing or is not compatible " " with '%s'\n", __func__, path, fdt_get_name(blob, node, NULL), compat_names[id]); continue; } /* * Add this node to our list in the right place, and mark * it as done. */ if (fdtdec_get_is_enabled(blob, node)) { if (node_list[number]) { debug("%s: warning: alias '%s' requires that " "a node be placed in the list in a " "position which is already filled by " "node '%s'\n", __func__, path, fdt_get_name(blob, node, NULL)); continue; } node_list[number] = node; if (number >= num_found) num_found = number + 1; } nodes[found] = 0; } /* Add any nodes not mentioned by an alias */ for (i = j = 0; i < maxcount; i++) { if (!node_list[i]) { for (; j < maxcount; j++) if (nodes[j] && fdtdec_get_is_enabled(blob, nodes[j])) break; /* Have we run out of nodes to add? */ if (j == maxcount) break; assert(!node_list[i]); node_list[i] = nodes[j++]; if (i >= num_found) num_found = i + 1; } } return num_found; }
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); } } }