[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen master] xen/arm: Add helpers to use the device tree
commit dbd1243248298014f47f88ad43f592133f4fc82f Author: Julien Grall <julien.grall@xxxxxxxxxx> AuthorDate: Fri Apr 26 17:09:25 2013 +0100 Commit: Ian Campbell <ian.campbell@xxxxxxxxxx> CommitDate: Mon May 13 11:59:57 2013 +0100 xen/arm: Add helpers to use the device tree Signed-off-by: Julien Grall <julien.grall@xxxxxxxxxx> Acked-by: Ian Campbell <ian.campbell@xxxxxxxxxx> --- xen/common/device_tree.c | 162 ++++++++++++++++++++++++++++++++++++----- xen/include/xen/device_tree.h | 155 +++++++++++++++++++++++++++++++++++---- 2 files changed, 283 insertions(+), 34 deletions(-) diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index 215feb1..92f2ac5 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -72,7 +72,8 @@ static LIST_HEAD(aliases_lookup); # define dt_dprintk(fmt, args...) do {} while ( 0 ) #endif -bool_t device_tree_node_matches(const void *fdt, int node, const char *match) +bool_t __init device_tree_node_matches(const void *fdt, int node, + const char *match) { const char *name; size_t match_len; @@ -86,7 +87,8 @@ bool_t device_tree_node_matches(const void *fdt, int node, const char *match) && (name[match_len] == '@' || name[match_len] == '\0'); } -bool_t device_tree_type_matches(const void *fdt, int node, const char *match) +bool_t __init device_tree_type_matches(const void *fdt, int node, + const char *match) { const void *prop; @@ -94,20 +96,24 @@ bool_t device_tree_type_matches(const void *fdt, int node, const char *match) if ( prop == NULL ) return 0; - return !strcmp(prop, match); + return !dt_node_cmp(prop, match); } -bool_t device_tree_node_compatible(const void *fdt, int node, const char *match) +bool_t __init device_tree_node_compatible(const void *fdt, int node, + const char *match) { int len, l; + int mlen; const void *prop; + mlen = strlen(match); + prop = fdt_getprop(fdt, node, "compatible", &len); if ( prop == NULL ) return 0; while ( len > 0 ) { - if ( !strcmp(prop, match) ) + if ( !dt_compat_cmp(prop, match, mlen) ) return 1; l = strlen(prop) + 1; prop += l; @@ -117,7 +123,7 @@ bool_t device_tree_node_compatible(const void *fdt, int node, const char *match) return 0; } -static int device_tree_nr_reg_ranges(const struct fdt_property *prop, +static __init int device_tree_nr_reg_ranges(const struct fdt_property *prop, u32 address_cells, u32 size_cells) { u32 reg_cells = address_cells + size_cells; @@ -138,14 +144,14 @@ static void __init get_val(const u32 **cell, u32 cells, u64 *val) } } -void device_tree_get_reg(const u32 **cell, u32 address_cells, u32 size_cells, - u64 *start, u64 *size) +void __init device_tree_get_reg(const u32 **cell, u32 address_cells, + u32 size_cells, u64 *start, u64 *size) { get_val(cell, address_cells, start); get_val(cell, size_cells, size); } -static void set_val(u32 **cell, u32 cells, u64 val) +static void __init set_val(u32 **cell, u32 cells, u64 val) { u32 c = cells; @@ -157,15 +163,15 @@ static void set_val(u32 **cell, u32 cells, u64 val) (*cell) += cells; } -void device_tree_set_reg(u32 **cell, u32 address_cells, u32 size_cells, - u64 start, u64 size) +void __init device_tree_set_reg(u32 **cell, u32 address_cells, u32 size_cells, + u64 start, u64 size) { set_val(cell, address_cells, start); set_val(cell, size_cells, size); } -u32 device_tree_get_u32(const void *fdt, int node, const char *prop_name, - u32 dflt) +u32 __init device_tree_get_u32(const void *fdt, int node, const char *prop_name, + u32 dflt) { const struct fdt_property *prop; @@ -187,8 +193,8 @@ u32 device_tree_get_u32(const void *fdt, int node, const char *prop_name, * Returns 0 if all nodes were iterated over successfully. If @func * returns a value different from 0, that value is returned immediately. */ -int device_tree_for_each_node(const void *fdt, - device_tree_node_func func, void *data) +int __init device_tree_for_each_node(const void *fdt, + device_tree_node_func func, void *data) { int node; int depth; @@ -254,8 +260,8 @@ static int _find_compatible_node(const void *fdt, return 0; } -int find_compatible_node(const char *compatible, int *node, int *depth, - u32 *address_cells, u32 *size_cells) +int __init find_compatible_node(const char *compatible, int *node, int *depth, + u32 *address_cells, u32 *size_cells) { int ret; struct find_compat c; @@ -327,7 +333,7 @@ static int dump_node(const void *fdt, int node, const char *name, int depth, * device_tree_dump - print a text representation of a device tree * @fdt: flat device tree to print */ -void device_tree_dump(const void *fdt) +void __init device_tree_dump(const void *fdt) { device_tree_for_each_node(fdt, dump_node, NULL); } @@ -579,6 +585,54 @@ const void *dt_get_property(const struct dt_device_node *np, return pp ? pp->value : NULL; } +bool_t dt_device_is_compatible(const struct dt_device_node *device, + const char *compat) +{ + const char* cp; + u32 cplen, l; + + cp = dt_get_property(device, "compatible", &cplen); + if ( cp == NULL ) + return 0; + while ( cplen > 0 ) + { + if ( dt_compat_cmp(cp, compat, strlen(compat)) == 0 ) + return 1; + l = strlen(cp) + 1; + cp += l; + cplen -= l; + } + + return 0; +} + +bool_t dt_machine_is_compatible(const char *compat) +{ + const struct dt_device_node *root; + bool_t rc = 0; + + root = dt_find_node_by_path("/"); + if ( root ) + { + rc = dt_device_is_compatible(root, compat); + } + return rc; +} + +struct dt_device_node *dt_find_node_by_name(struct dt_device_node *from, + const char *name) +{ + struct dt_device_node *np; + struct dt_device_node *dt; + + dt = from ? from->allnext : dt_host; + for_each_device_node(dt, np) + if ( np->name && (dt_node_cmp(np->name, name) == 0) ) + break; + + return np; +} + struct dt_device_node *dt_find_node_by_path(const char *path) { struct dt_device_node *np; @@ -590,6 +644,78 @@ struct dt_device_node *dt_find_node_by_path(const char *path) return np; } +struct dt_device_node *dt_find_node_by_alias(const char *alias) +{ + const struct dt_alias_prop *app; + + list_for_each_entry( app, &aliases_lookup, link ) + { + if ( !strcmp(app->alias, alias) ) + return app->np; + } + + return NULL; +} + +const struct dt_device_node *dt_get_parent(const struct dt_device_node *node) +{ + if ( !node ) + return NULL; + + return node->parent; +} + +struct dt_device_node * +dt_find_compatible_node(struct dt_device_node *from, + const char *type, + const char *compatible) +{ + struct dt_device_node *np; + struct dt_device_node *dt; + + dt = from ? from->allnext : dt_host; + for_each_device_node(dt, np) + { + if ( type + && !(np->type && (dt_node_cmp(np->type, type) == 0)) ) + continue; + if ( dt_device_is_compatible(np, compatible) ) + break; + } + + return np; +} + +int dt_n_addr_cells(const struct dt_device_node *np) +{ + const __be32 *ip; + + do { + if ( np->parent ) + np = np->parent; + ip = dt_get_property(np, "#address-cells", NULL); + if ( ip ) + return be32_to_cpup(ip); + } while ( np->parent ); + /* No #address-cells property for the root node */ + return DT_ROOT_NODE_ADDR_CELLS_DEFAULT; +} + +int dt_n_size_cells(const struct dt_device_node *np) +{ + const __be32 *ip; + + do { + if ( np->parent ) + np = np->parent; + ip = dt_get_property(np, "#size-cells", NULL); + if ( ip ) + return be32_to_cpup(ip); + } while ( np->parent ); + /* No #address-cells property for the root node */ + return DT_ROOT_NODE_SIZE_CELLS_DEFAULT; +} + /** * unflatten_dt_node - Alloc and populate a device_node from the flat tree * @fdt: The parent device tree blob diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h index 015b808..7a6adc7 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -107,22 +107,25 @@ typedef int (*device_tree_node_func)(const void *fdt, extern struct dt_early_info early_info; extern void *device_tree_flattened; -size_t device_tree_early_init(const void *fdt); - -void device_tree_get_reg(const u32 **cell, u32 address_cells, u32 size_cells, - u64 *start, u64 *size); -void device_tree_set_reg(u32 **cell, u32 address_cells, u32 size_cells, - u64 start, u64 size); -u32 device_tree_get_u32(const void *fdt, int node, const char *prop_name, - u32 dflt); -bool_t device_tree_node_matches(const void *fdt, int node, const char *match); -bool_t device_tree_node_compatible(const void *fdt, int node, const char *match); -int find_compatible_node(const char *compatible, int *node, int *depth, - u32 *address_cells, u32 *size_cells); -int device_tree_for_each_node(const void *fdt, - device_tree_node_func func, void *data); -const char *device_tree_bootargs(const void *fdt); -void device_tree_dump(const void *fdt); +size_t __init device_tree_early_init(const void *fdt); + +void __init device_tree_get_reg(const u32 **cell, u32 address_cells, + u32 size_cells, + u64 *start, u64 *size); +void __init device_tree_set_reg(u32 **cell, u32 address_cells, u32 size_cells, + u64 start, u64 size); +u32 __init device_tree_get_u32(const void *fdt, int node, + const char *prop_name, u32 dflt); +bool_t __init device_tree_node_matches(const void *fdt, int node, + const char *match); +bool_t __init device_tree_node_compatible(const void *fdt, int node, + const char *match); +int __init find_compatible_node(const char *compatible, int *node, int *depth, + u32 *address_cells, u32 *size_cells); +int __init device_tree_for_each_node(const void *fdt, + device_tree_node_func func, void *data); +const char __init *device_tree_bootargs(const void *fdt); +void __init device_tree_dump(const void *fdt); /** * dt_unflatten_host_device_tree - Unflatten the host device tree @@ -141,17 +144,72 @@ extern struct dt_device_node *dt_host; #define dt_node_cmp(s1, s2) strcmp((s1), (s2)) #define dt_compat_cmp(s1, s2, l) strnicmp((s1), (s2), l) +/* Default #address and #size cells */ +#define DT_ROOT_NODE_ADDR_CELLS_DEFAULT 1 +#define DT_ROOT_NODE_SIZE_CELLS_DEFAULT 1 + #define for_each_property_of_node(dn, pp) \ for ( pp = dn->properties; pp != NULL; pp = pp->next ) #define for_each_device_node(dt, dn) \ for ( dn = dt; dn != NULL; dn = dn->allnext ) +/* Helper to read a big number; size is in cells (not bytes) */ +static inline u64 dt_read_number(const __be32 *cell, int size) +{ + u64 r = 0; + + while ( size-- ) + r = (r << 32) | be32_to_cpu(*(cell++)); + return r; +} + static inline const char *dt_node_full_name(const struct dt_device_node *np) { return (np && np->full_name) ? np->full_name : "<no-node>"; } +static inline const char *dt_node_name(const struct dt_device_node *np) +{ + return (np && np->name) ? np->name : "<no-node>"; +} + +static inline bool_t +dt_device_type_is_equal(const struct dt_device_node *device, + const char *type) +{ + return !dt_node_cmp(device->type, type); +} + +static inline void dt_device_set_used_by(struct dt_device_node *device, + domid_t used_by) +{ + /* TODO: children must inherit to the used_by thing */ + device->used_by = used_by; +} + +static inline domid_t dt_device_used_by(const struct dt_device_node *device) +{ + return device->used_by; +} + +/** + * dt_find_compatible_node - Find a node based on type and one of the + * tokens in its "compatible" property + * @from: The node to start searching from or NULL, the node + * you pass will not be searched, only the next one + * will; typically, you pass what the previous call + * returned. + * @type: The type string to match "device_type" or NULL to ignore + * @compatible: The string to match to one of the tokens in the device + * "compatible" list. + * + * Returns a node pointer. + */ +struct dt_device_node *dt_find_compatible_node(struct dt_device_node *from, + const char *type, + const char *compatible); + /** * Find a property with a given name for a given node * and return the value. @@ -160,10 +218,75 @@ const void *dt_get_property(const struct dt_device_node *np, const char *name, u32 *lenp); /** + * Checks if the given "compat" string matches one of the strings in + * the device's "compatible" property + */ +bool_t dt_device_is_compatible(const struct dt_device_node *device, + const char *compat); + +/** + * dt_machine_is_compatible - Test root of device tree for a given compatible value + * @compat: compatible string to look for in root node's compatible property. + * + * Returns true if the root node has the given value in its + * compatible property. + */ +bool_t dt_machine_is_compatible(const char *compat); + +/** + * dt_find_node_by_name - Find a node by its "name" property + * @from: The node to start searching from or NULL, the node + * you pass will not be searched, only the next one + * will; typically, you pass what the previous call + * returned. of_node_put() will be called on it + * @name: The name string to match against + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct dt_device_node *dt_find_node_by_name(struct dt_device_node *node, + const char *name); + +/** + * df_find_node_by_alias - Find a node matching an alias + * @alias: The alias to match + * + * Returns a node pointer. + */ +struct dt_device_node *dt_find_node_by_alias(const char *alias); + +/** * dt_find_node_by_path - Find a node matching a full DT path * @path: The full path to match * * Returns a node pointer. */ struct dt_device_node *dt_find_node_by_path(const char *path); + +/** + * dt_get_parent - Get a node's parent if any + * @node: Node to get parent + * + * Returns a node pointer. + */ +const struct dt_device_node *dt_get_parent(const struct dt_device_node *node); + +/** + * dt_n_size_cells - Helper to retrieve the number of cell for the size + * @np: node to get the value + * + * This function retrieves for a give device-tree node the number of + * cell for the size field. + */ +int dt_n_size_cells(const struct dt_device_node *np); + +/** + * dt_n_addr_cells - Helper to retrieve the number of cell for the address + * @np: node to get the value + * + * This function retrieves for a give device-tree node the number of + * cell for the address field. + */ +int dt_n_addr_cells(const struct dt_device_node *np); + #endif -- generated by git-patchbot for /home/xen/git/xen.git#master _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |