From patchwork Wed May 8 02:33:28 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julien Grall X-Patchwork-Id: 16743 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-qa0-f69.google.com (mail-qa0-f69.google.com [209.85.216.69]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 2FF86238FD for ; Wed, 8 May 2013 02:35:04 +0000 (UTC) Received: by mail-qa0-f69.google.com with SMTP id hu16sf1905683qab.0 for ; Tue, 07 May 2013 19:34:44 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:mime-version:x-beenthere:x-received:received-spf :x-received:x-forwarded-to:x-forwarded-for:delivered-to:x-received :received-spf:x-received:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references:x-gm-message-state:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :x-google-group-id:list-post:list-help:list-archive:list-unsubscribe; bh=cIftovfH/8580dlfSnJIt4jFfNje6aM1aafCqrHfZFY=; b=JS7frfALsyH1ybpYWiUP1R4qoC4ndi0gy11L/p16Hq1ESXfcTTBGQzTFTGTE4m9cbQ /elUVzDXBcEv9XXEUjz+cywsAwVLQFnc6emxPr/XeBxB2FjshOGwmXoeu8H6ezAbL7gE M5B4JCqJxeQZjE798FOdwr9MoMsmeUT065sNFtikOVT9clSbRgvaBbKiRJRF9HZGlDzL IjE9RzCZdEtTOyzNGS/xbEserbBv8CSZfwt8kboW3qw06+aNL4M6mRs3tZZEzjz6R7tl EXC1PDuqftzO9h/2J2wilx+xibWWM4N6s8hnhx+DiHqi9A5FaCSsqeAqL8kCF/p3jlcU kb2w== X-Received: by 10.224.200.202 with SMTP id ex10mr6489089qab.8.1367980483921; Tue, 07 May 2013 19:34:43 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.34.211 with SMTP id b19ls651827qej.88.gmail; Tue, 07 May 2013 19:34:43 -0700 (PDT) X-Received: by 10.52.69.40 with SMTP id b8mr2630525vdu.130.1367980483608; Tue, 07 May 2013 19:34:43 -0700 (PDT) Received: from mail-vc0-f172.google.com (mail-vc0-f172.google.com [209.85.220.172]) by mx.google.com with ESMTPS id bb6si240419vcb.84.2013.05.07.19.34.43 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 07 May 2013 19:34:43 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.220.172 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.220.172; Received: by mail-vc0-f172.google.com with SMTP id m17so1233104vca.17 for ; Tue, 07 May 2013 19:34:43 -0700 (PDT) X-Received: by 10.58.173.36 with SMTP id bh4mr3214525vec.9.1367980483480; Tue, 07 May 2013 19:34:43 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.58.127.98 with SMTP id nf2csp131000veb; Tue, 7 May 2013 19:34:42 -0700 (PDT) X-Received: by 10.194.179.169 with SMTP id dh9mr809045wjc.15.1367980481584; Tue, 07 May 2013 19:34:41 -0700 (PDT) Received: from mail-wg0-x230.google.com (mail-wg0-x230.google.com [2a00:1450:400c:c00::230]) by mx.google.com with ESMTPS id v3si1337001wix.16.2013.05.07.19.34.41 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 07 May 2013 19:34:41 -0700 (PDT) Received-SPF: neutral (google.com: 2a00:1450:400c:c00::230 is neither permitted nor denied by best guess record for domain of julien.grall@linaro.org) client-ip=2a00:1450:400c:c00::230; Received: by mail-wg0-f48.google.com with SMTP id f11so1312279wgh.3 for ; Tue, 07 May 2013 19:34:41 -0700 (PDT) X-Received: by 10.180.86.230 with SMTP id s6mr6987632wiz.6.1367980481190; Tue, 07 May 2013 19:34:41 -0700 (PDT) Received: from belegaer.uk.xensource.com. (firewall.ctxuk.citrix.com. [46.33.159.2]) by mx.google.com with ESMTPSA id v6sm6823630wiy.11.2013.05.07.19.34.39 for (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 07 May 2013 19:34:40 -0700 (PDT) From: Julien Grall To: xen-devel@lists.xen.org Cc: Stefano.Stabellini@eu.citrix.com, patches@linaro.org, ian.campbell@citrix.com, Julien Grall Subject: [PATCH V2 08/33] xen/arm: Add helpers to use the device tree Date: Wed, 8 May 2013 03:33:28 +0100 Message-Id: <81cae3ed3ae6da555f2f37d9aab1ba59d7e274c3.1367979526.git.julien.grall@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: References: X-Gm-Message-State: ALoCoQnd77G3H23FK8BMd0OGfSjfhkC1DbqkmQ7FL90a5384EtUHva9JKQNovPdNRAQQBUC361jX X-Original-Sender: julien.grall@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.220.172 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Signed-off-by: Julien Grall Changes in v2: - use dt_node_cmp and dt_compat_cmp in early device tree code --- xen/common/device_tree.c | 127 ++++++++++++++++++++++++++++++++++++++++- xen/include/xen/device_tree.h | 120 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 245 insertions(+), 2 deletions(-) diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index bdf8871..449c332 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -88,20 +88,23 @@ 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) { 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; @@ -573,6 +576,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; @@ -584,6 +635,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 8f526d1..879b75d 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -150,17 +150,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 : ""; } +static inline const char *dt_node_name(const struct dt_device_node *np) +{ + return (np && np->name) ? np->name : ""; +} + +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. @@ -169,10 +224,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