From patchwork Wed Jul 23 23:44:17 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Grant Likely X-Patchwork-Id: 34186 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-qg0-f71.google.com (mail-qg0-f71.google.com [209.85.192.71]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 1EF9E20672 for ; Wed, 23 Jul 2014 23:47:01 +0000 (UTC) Received: by mail-qg0-f71.google.com with SMTP id f51sf4091803qge.2 for ; Wed, 23 Jul 2014 16:47:00 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:sender:precedence:list-id :x-original-sender:x-original-authentication-results:mailing-list :list-post:list-help:list-archive:list-unsubscribe; bh=Wvd2MEwFtSy5WV0HbY37kxLsSDVmOa13Zj2s3MvGhGA=; b=EYvD1pFW+ZOkdzR2kxKb8UPu99COfhPOUzFEX7wF7UCxyVYDGZE0vK/eye5fTeqFTl w4FU9sWzF80nPX0IImH2lvoyJFvWLzC1NGC0IxR3un0+o7SBcyQrnn7NKz+c8DX+Mwa2 l6n0bwLAWWSbjLaYAHCyltnxRr/ys3yO5Wbg7TfmIVDsNPR22QFBoGogrPm6AQ7jaJwp WGga4TH3ZpIZrpEXKv93bfZ0g5lu08QTY2mEdnHKrDLWS8umY/KbfRoc/vG3jo6l/kpU afIa/i3DHWqLhwGTXNgeF5vyyh/NHgvr9BIHA9QFk4EsGAYGCwVVeLyi/XIFXKODp3/d 0j4w== X-Gm-Message-State: ALoCoQlHZrc8Suo5pxUl+tzBIHwT1su3bPTpljFTqMFx+Rf482cnPilvE+oSIWIvC5w7uoGpwx8B X-Received: by 10.236.231.238 with SMTP id l104mr1125295yhq.51.1406159220897; Wed, 23 Jul 2014 16:47:00 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.92.140 with SMTP id b12ls494972qge.88.gmail; Wed, 23 Jul 2014 16:47:00 -0700 (PDT) X-Received: by 10.220.12.78 with SMTP id w14mr7040960vcw.68.1406159220751; Wed, 23 Jul 2014 16:47:00 -0700 (PDT) Received: from mail-vc0-f178.google.com (mail-vc0-f178.google.com [209.85.220.178]) by mx.google.com with ESMTPS id fy20si3815473vec.33.2014.07.23.16.47.00 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 23 Jul 2014 16:47:00 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.178 as permitted sender) client-ip=209.85.220.178; Received: by mail-vc0-f178.google.com with SMTP id la4so3567091vcb.23 for ; Wed, 23 Jul 2014 16:47:00 -0700 (PDT) X-Received: by 10.52.37.81 with SMTP id w17mr5692385vdj.95.1406159220613; Wed, 23 Jul 2014 16:47:00 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.221.37.5 with SMTP id tc5csp321052vcb; Wed, 23 Jul 2014 16:47:00 -0700 (PDT) X-Received: by 10.68.65.9 with SMTP id t9mr5923880pbs.77.1406159219620; Wed, 23 Jul 2014 16:46:59 -0700 (PDT) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id pe9si4082771pac.40.2014.07.23.16.46.58 for ; Wed, 23 Jul 2014 16:46:59 -0700 (PDT) Received-SPF: none (google.com: linux-kernel-owner@vger.kernel.org does not designate permitted sender hosts) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758704AbaGWXqv (ORCPT + 16 others); Wed, 23 Jul 2014 19:46:51 -0400 Received: from mail-pd0-f173.google.com ([209.85.192.173]:53785 "EHLO mail-pd0-f173.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1758542AbaGWXoh (ORCPT ); Wed, 23 Jul 2014 19:44:37 -0400 Received: by mail-pd0-f173.google.com with SMTP id w10so2499718pde.32 for ; Wed, 23 Jul 2014 16:44:36 -0700 (PDT) X-Received: by 10.70.35.207 with SMTP id k15mr6135418pdj.46.1406159076481; Wed, 23 Jul 2014 16:44:36 -0700 (PDT) Received: from trevor.secretlab.ca (S0106602ad082623c.cg.shawcable.net. [68.146.69.61]) by mx.google.com with ESMTPSA id hm4sm3547346pbb.88.2014.07.23.16.44.33 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 23 Jul 2014 16:44:34 -0700 (PDT) Received: by trevor.secretlab.ca (Postfix, from userid 1000) id C8646C439CC; Wed, 23 Jul 2014 17:44:26 -0600 (MDT) From: Grant Likely To: linux-kernel@vger.kernel.org, Nathan Fontenot , Tyrel Datwyler , Pantelis Antoniou , devicetree@vger.kernel.org Cc: Grant Likely , Rob Herring Subject: [PATCH 03/10] of: Move CONFIG_OF_DYNAMIC code into a separate file Date: Wed, 23 Jul 2014 17:44:17 -0600 Message-Id: <1406159064-21366-4-git-send-email-grant.likely@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1406159064-21366-1-git-send-email-grant.likely@linaro.org> References: <1406159064-21366-1-git-send-email-grant.likely@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: grant.likely@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.178 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Split the dynamic device tree code into a separate file to make it really clear what features CONFIF_OF_DYNAMIC add to the kernel. Without CONFIG_OF_DYNAMIC only properties can be changed, and notifiers do not get sent. Enabling it turns on reference counting, notifiers and the ability to add and remove nodes. v2: Moved of_node_release() into dynamic.c Signed-off-by: Grant Likely Signed-off-by: Pantelis Antoniou Cc: Rob Herring --- drivers/of/Makefile | 1 + drivers/of/base.c | 230 +----------------------------------------------- drivers/of/dynamic.c | 216 +++++++++++++++++++++++++++++++++++++++++++++ drivers/of/of_private.h | 18 ++++ 4 files changed, 236 insertions(+), 229 deletions(-) create mode 100644 drivers/of/dynamic.c diff --git a/drivers/of/Makefile b/drivers/of/Makefile index 099b1fb00af4..08e6c0f79806 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -1,4 +1,5 @@ obj-y = base.o device.o platform.o +obj-$(CONFIG_OF_DYNAMIC) += dynamic.o obj-$(CONFIG_OF_FLATTREE) += fdt.o obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o obj-$(CONFIG_OF_PROMTREE) += pdt.o diff --git a/drivers/of/base.c b/drivers/of/base.c index e48a1b90a392..0d8955605738 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -88,79 +88,7 @@ int __weak of_node_to_nid(struct device_node *np) } #endif -#if defined(CONFIG_OF_DYNAMIC) -/** - * of_node_get - Increment refcount of a node - * @node: Node to inc refcount, NULL is supported to - * simplify writing of callers - * - * Returns node. - */ -struct device_node *of_node_get(struct device_node *node) -{ - if (node) - kobject_get(&node->kobj); - return node; -} -EXPORT_SYMBOL(of_node_get); - -static inline struct device_node *kobj_to_device_node(struct kobject *kobj) -{ - return container_of(kobj, struct device_node, kobj); -} - -/** - * of_node_release - release a dynamically allocated node - * @kref: kref element of the node to be released - * - * In of_node_put() this function is passed to kref_put() - * as the destructor. - */ -static void of_node_release(struct kobject *kobj) -{ - struct device_node *node = kobj_to_device_node(kobj); - struct property *prop = node->properties; - - /* We should never be releasing nodes that haven't been detached. */ - if (!of_node_check_flag(node, OF_DETACHED)) { - pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name); - dump_stack(); - return; - } - - if (!of_node_check_flag(node, OF_DYNAMIC)) - return; - - while (prop) { - struct property *next = prop->next; - kfree(prop->name); - kfree(prop->value); - kfree(prop); - prop = next; - - if (!prop) { - prop = node->deadprops; - node->deadprops = NULL; - } - } - kfree(node->full_name); - kfree(node->data); - kfree(node); -} - -/** - * of_node_put - Decrement refcount of a node - * @node: Node to dec refcount, NULL is supported to - * simplify writing of callers - * - */ -void of_node_put(struct device_node *node) -{ - if (node) - kobject_put(&node->kobj); -} -EXPORT_SYMBOL(of_node_put); -#else +#ifndef CONFIG_OF_DYNAMIC static void of_node_release(struct kobject *kobj) { /* Without CONFIG_OF_DYNAMIC, no nodes gets freed */ @@ -264,25 +192,6 @@ int of_node_add(struct device_node *np) return rc; } -#if defined(CONFIG_OF_DYNAMIC) -static void of_node_remove(struct device_node *np) -{ - struct property *pp; - - BUG_ON(!of_node_is_initialized(np)); - - /* only remove properties if on sysfs */ - if (of_node_is_attached(np)) { - for_each_property_of_node(np, pp) - sysfs_remove_bin_file(&np->kobj, &pp->attr); - kobject_del(&np->kobj); - } - - /* finally remove the kobj_init ref */ - of_node_put(np); -} -#endif - static int __init of_init(void) { struct device_node *np; @@ -1747,28 +1656,6 @@ int of_count_phandle_with_args(const struct device_node *np, const char *list_na } EXPORT_SYMBOL(of_count_phandle_with_args); -#if defined(CONFIG_OF_DYNAMIC) -static int of_property_notify(int action, struct device_node *np, - struct property *prop) -{ - struct of_prop_reconfig pr; - - /* only call notifiers if the node is attached */ - if (!of_node_is_attached(np)) - return 0; - - pr.dn = np; - pr.prop = prop; - return of_reconfig_notify(action, &pr); -} -#else -static int of_property_notify(int action, struct device_node *np, - struct property *prop) -{ - return 0; -} -#endif - /** * __of_add_property - Add a property to a node without lock operations */ @@ -1915,121 +1802,6 @@ int of_update_property(struct device_node *np, struct property *newprop) return 0; } -#if defined(CONFIG_OF_DYNAMIC) -/* - * Support for dynamic device trees. - * - * On some platforms, the device tree can be manipulated at runtime. - * The routines in this section support adding, removing and changing - * device tree nodes. - */ - -static BLOCKING_NOTIFIER_HEAD(of_reconfig_chain); - -int of_reconfig_notifier_register(struct notifier_block *nb) -{ - return blocking_notifier_chain_register(&of_reconfig_chain, nb); -} -EXPORT_SYMBOL_GPL(of_reconfig_notifier_register); - -int of_reconfig_notifier_unregister(struct notifier_block *nb) -{ - return blocking_notifier_chain_unregister(&of_reconfig_chain, nb); -} -EXPORT_SYMBOL_GPL(of_reconfig_notifier_unregister); - -int of_reconfig_notify(unsigned long action, void *p) -{ - int rc; - - rc = blocking_notifier_call_chain(&of_reconfig_chain, action, p); - return notifier_to_errno(rc); -} - -/** - * of_attach_node - Plug a device node into the tree and global list. - */ -int of_attach_node(struct device_node *np) -{ - unsigned long flags; - int rc; - - rc = of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, np); - if (rc) - return rc; - - raw_spin_lock_irqsave(&devtree_lock, flags); - np->sibling = np->parent->child; - np->allnext = np->parent->allnext; - np->parent->allnext = np; - np->parent->child = np; - of_node_clear_flag(np, OF_DETACHED); - raw_spin_unlock_irqrestore(&devtree_lock, flags); - - of_node_add(np); - return 0; -} - -/** - * of_detach_node - "Unplug" a node from the device tree. - * - * The caller must hold a reference to the node. The memory associated with - * the node is not freed until its refcount goes to zero. - */ -int of_detach_node(struct device_node *np) -{ - struct device_node *parent; - unsigned long flags; - int rc = 0; - - rc = of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np); - if (rc) - return rc; - - raw_spin_lock_irqsave(&devtree_lock, flags); - - if (of_node_check_flag(np, OF_DETACHED)) { - /* someone already detached it */ - raw_spin_unlock_irqrestore(&devtree_lock, flags); - return rc; - } - - parent = np->parent; - if (!parent) { - raw_spin_unlock_irqrestore(&devtree_lock, flags); - return rc; - } - - if (of_allnodes == np) - of_allnodes = np->allnext; - else { - struct device_node *prev; - for (prev = of_allnodes; - prev->allnext != np; - prev = prev->allnext) - ; - prev->allnext = np->allnext; - } - - if (parent->child == np) - parent->child = np->sibling; - else { - struct device_node *prevsib; - for (prevsib = np->parent->child; - prevsib->sibling != np; - prevsib = prevsib->sibling) - ; - prevsib->sibling = np->sibling; - } - - of_node_set_flag(np, OF_DETACHED); - raw_spin_unlock_irqrestore(&devtree_lock, flags); - - of_node_remove(np); - return rc; -} -#endif /* defined(CONFIG_OF_DYNAMIC) */ - static void of_alias_add(struct alias_prop *ap, struct device_node *np, int id, const char *stem, int stem_len) { diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c new file mode 100644 index 000000000000..125994330437 --- /dev/null +++ b/drivers/of/dynamic.c @@ -0,0 +1,216 @@ +/* + * Support for dynamic device trees. + * + * On some platforms, the device tree can be manipulated at runtime. + * The routines in this section support adding, removing and changing + * device tree nodes. + */ + +#include +#include +#include +#include +#include + +#include "of_private.h" + +/** + * of_node_get() - Increment refcount of a node + * @node: Node to inc refcount, NULL is supported to simplify writing of + * callers + * + * Returns node. + */ +struct device_node *of_node_get(struct device_node *node) +{ + if (node) + kobject_get(&node->kobj); + return node; +} +EXPORT_SYMBOL(of_node_get); + +/** + * of_node_put() - Decrement refcount of a node + * @node: Node to dec refcount, NULL is supported to simplify writing of + * callers + */ +void of_node_put(struct device_node *node) +{ + if (node) + kobject_put(&node->kobj); +} +EXPORT_SYMBOL(of_node_put); + +static void of_node_remove(struct device_node *np) +{ + struct property *pp; + + BUG_ON(!of_node_is_initialized(np)); + + /* only remove properties if on sysfs */ + if (of_node_is_attached(np)) { + for_each_property_of_node(np, pp) + sysfs_remove_bin_file(&np->kobj, &pp->attr); + kobject_del(&np->kobj); + } + + /* finally remove the kobj_init ref */ + of_node_put(np); +} + +static BLOCKING_NOTIFIER_HEAD(of_reconfig_chain); + +int of_reconfig_notifier_register(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&of_reconfig_chain, nb); +} +EXPORT_SYMBOL_GPL(of_reconfig_notifier_register); + +int of_reconfig_notifier_unregister(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&of_reconfig_chain, nb); +} +EXPORT_SYMBOL_GPL(of_reconfig_notifier_unregister); + +int of_reconfig_notify(unsigned long action, void *p) +{ + int rc; + + rc = blocking_notifier_call_chain(&of_reconfig_chain, action, p); + return notifier_to_errno(rc); +} + +int of_property_notify(int action, struct device_node *np, + struct property *prop) +{ + struct of_prop_reconfig pr; + + /* only call notifiers if the node is attached */ + if (!of_node_is_attached(np)) + return 0; + + pr.dn = np; + pr.prop = prop; + return of_reconfig_notify(action, &pr); +} + +/** + * of_attach_node() - Plug a device node into the tree and global list. + */ +int of_attach_node(struct device_node *np) +{ + unsigned long flags; + int rc; + + rc = of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, np); + if (rc) + return rc; + + raw_spin_lock_irqsave(&devtree_lock, flags); + np->sibling = np->parent->child; + np->allnext = np->parent->allnext; + np->parent->allnext = np; + np->parent->child = np; + of_node_clear_flag(np, OF_DETACHED); + raw_spin_unlock_irqrestore(&devtree_lock, flags); + + of_node_add(np); + return 0; +} + +/** + * of_detach_node() - "Unplug" a node from the device tree. + * + * The caller must hold a reference to the node. The memory associated with + * the node is not freed until its refcount goes to zero. + */ +int of_detach_node(struct device_node *np) +{ + struct device_node *parent; + unsigned long flags; + int rc = 0; + + rc = of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np); + if (rc) + return rc; + + raw_spin_lock_irqsave(&devtree_lock, flags); + + if (of_node_check_flag(np, OF_DETACHED)) { + /* someone already detached it */ + raw_spin_unlock_irqrestore(&devtree_lock, flags); + return rc; + } + + parent = np->parent; + if (!parent) { + raw_spin_unlock_irqrestore(&devtree_lock, flags); + return rc; + } + + if (of_allnodes == np) + of_allnodes = np->allnext; + else { + struct device_node *prev; + for (prev = of_allnodes; + prev->allnext != np; + prev = prev->allnext) + ; + prev->allnext = np->allnext; + } + + if (parent->child == np) + parent->child = np->sibling; + else { + struct device_node *prevsib; + for (prevsib = np->parent->child; + prevsib->sibling != np; + prevsib = prevsib->sibling) + ; + prevsib->sibling = np->sibling; + } + + of_node_set_flag(np, OF_DETACHED); + raw_spin_unlock_irqrestore(&devtree_lock, flags); + + of_node_remove(np); + return rc; +} + +/** + * of_node_release() - release a dynamically allocated node + * @kref: kref element of the node to be released + * + * In of_node_put() this function is passed to kref_put() as the destructor. + */ +void of_node_release(struct kobject *kobj) +{ + struct device_node *node = kobj_to_device_node(kobj); + struct property *prop = node->properties; + + /* We should never be releasing nodes that haven't been detached. */ + if (!of_node_check_flag(node, OF_DETACHED)) { + pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name); + dump_stack(); + return; + } + + if (!of_node_check_flag(node, OF_DYNAMIC)) + return; + + while (prop) { + struct property *next = prop->next; + kfree(prop->name); + kfree(prop->value); + kfree(prop); + prop = next; + + if (!prop) { + prop = node->deadprops; + node->deadprops = NULL; + } + } + kfree(node->full_name); + kfree(node->data); + kfree(node); +} diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h index fcc70e74dfe0..c270f2037779 100644 --- a/drivers/of/of_private.h +++ b/drivers/of/of_private.h @@ -33,4 +33,22 @@ struct alias_prop { extern struct mutex of_mutex; extern struct list_head aliases_lookup; + +static inline struct device_node *kobj_to_device_node(struct kobject *kobj) +{ + return container_of(kobj, struct device_node, kobj); +} + +#if defined(CONFIG_OF_DYNAMIC) +extern int of_property_notify(int action, struct device_node *np, + struct property *prop); +extern void of_node_release(struct kobject *kobj); +#else /* CONFIG_OF_DYNAMIC */ +static inline int of_property_notify(int action, struct device_node *np, + struct property *prop) +{ + return 0; +} +#endif /* CONFIG_OF_DYNAMIC */ + #endif /* _LINUX_OF_PRIVATE_H */