From: hdegoede@redhat.com (Hans de Goede)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v4 2/3] reset: Share struct reset_control between reset_control_get calls
Date: Tue, 23 Feb 2016 18:46:25 +0100 [thread overview]
Message-ID: <1456249586-12101-3-git-send-email-hdegoede@redhat.com> (raw)
In-Reply-To: <1456249586-12101-1-git-send-email-hdegoede@redhat.com>
Now that struct reset_control no longer stores the device pointer for
the device calling reset_control_get we can share a single struct
reset_control when multiple calls to reset_control_get are made for
the same reset line (same id / index).
This is a preparation patch for adding support for shared reset lines.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/reset/core.c | 82 ++++++++++++++++++++++++++++++----------
include/linux/reset-controller.h | 2 +
2 files changed, 64 insertions(+), 20 deletions(-)
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index f695429..e439ae2 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -18,19 +18,23 @@
#include <linux/reset-controller.h>
#include <linux/slab.h>
-static DEFINE_MUTEX(reset_controller_list_mutex);
+static DEFINE_MUTEX(reset_list_mutex);
static LIST_HEAD(reset_controller_list);
/**
* struct reset_control - a reset control
* @rcdev: a pointer to the reset controller device
* this reset control belongs to
+ * @list: list entry for the rcdev's reset controller list
* @id: ID of the reset controller in the reset
* controller device
+ * @refcnt: Number of gets of this reset_control
*/
struct reset_control {
struct reset_controller_dev *rcdev;
+ struct list_head list;
unsigned int id;
+ unsigned int refcnt;
};
/**
@@ -65,9 +69,11 @@ int reset_controller_register(struct reset_controller_dev *rcdev)
rcdev->of_xlate = of_reset_simple_xlate;
}
- mutex_lock(&reset_controller_list_mutex);
+ INIT_LIST_HEAD(&rcdev->reset_control_head);
+
+ mutex_lock(&reset_list_mutex);
list_add(&rcdev->list, &reset_controller_list);
- mutex_unlock(&reset_controller_list_mutex);
+ mutex_unlock(&reset_list_mutex);
return 0;
}
@@ -79,9 +85,9 @@ EXPORT_SYMBOL_GPL(reset_controller_register);
*/
void reset_controller_unregister(struct reset_controller_dev *rcdev)
{
- mutex_lock(&reset_controller_list_mutex);
+ mutex_lock(&reset_list_mutex);
list_del(&rcdev->list);
- mutex_unlock(&reset_controller_list_mutex);
+ mutex_unlock(&reset_list_mutex);
}
EXPORT_SYMBOL_GPL(reset_controller_unregister);
@@ -139,6 +145,48 @@ int reset_control_status(struct reset_control *rstc)
}
EXPORT_SYMBOL_GPL(reset_control_status);
+static struct reset_control *__reset_control_get(
+ struct reset_controller_dev *rcdev,
+ unsigned int index)
+{
+ struct reset_control *rstc;
+
+ lockdep_assert_held(&reset_list_mutex);
+
+ list_for_each_entry(rstc, &rcdev->reset_control_head, list) {
+ if (rstc->id == index) {
+ rstc->refcnt++;
+ return rstc;
+ }
+ }
+
+ rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
+ if (!rstc)
+ return ERR_PTR(-ENOMEM);
+
+ try_module_get(rcdev->owner);
+
+ rstc->rcdev = rcdev;
+ list_add(&rstc->list, &rcdev->reset_control_head);
+ rstc->id = index;
+ rstc->refcnt = 1;
+
+ return rstc;
+}
+
+static void __reset_control_put(struct reset_control *rstc)
+{
+ lockdep_assert_held(&reset_list_mutex);
+
+ if (--rstc->refcnt)
+ return;
+
+ module_put(rstc->rcdev->owner);
+
+ list_del(&rstc->list);
+ kfree(rstc);
+}
+
struct reset_control *__of_reset_control_get(struct device_node *node,
const char *id, int index)
{
@@ -163,7 +211,7 @@ struct reset_control *__of_reset_control_get(struct device_node *node,
if (ret)
return ERR_PTR(ret);
- mutex_lock(&reset_controller_list_mutex);
+ mutex_lock(&reset_list_mutex);
rcdev = NULL;
list_for_each_entry(r, &reset_controller_list, list) {
if (args.np == r->of_node) {
@@ -174,27 +222,20 @@ struct reset_control *__of_reset_control_get(struct device_node *node,
of_node_put(args.np);
if (!rcdev) {
- mutex_unlock(&reset_controller_list_mutex);
+ mutex_unlock(&reset_list_mutex);
return ERR_PTR(-EPROBE_DEFER);
}
rstc_id = rcdev->of_xlate(rcdev, &args);
if (rstc_id < 0) {
- mutex_unlock(&reset_controller_list_mutex);
+ mutex_unlock(&reset_list_mutex);
return ERR_PTR(rstc_id);
}
- try_module_get(rcdev->owner);
- mutex_unlock(&reset_controller_list_mutex);
-
- rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
- if (!rstc) {
- module_put(rcdev->owner);
- return ERR_PTR(-ENOMEM);
- }
+ /* reset_list_mutex also protects the rcdev's reset_control list */
+ rstc = __reset_control_get(rcdev, rstc_id);
- rstc->rcdev = rcdev;
- rstc->id = rstc_id;
+ mutex_unlock(&reset_list_mutex);
return rstc;
}
@@ -210,8 +251,9 @@ void reset_control_put(struct reset_control *rstc)
if (IS_ERR(rstc))
return;
- module_put(rstc->rcdev->owner);
- kfree(rstc);
+ mutex_lock(&reset_list_mutex);
+ __reset_control_put(rstc);
+ mutex_unlock(&reset_list_mutex);
}
EXPORT_SYMBOL_GPL(reset_control_put);
diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
index ce6b962..2decc20 100644
--- a/include/linux/reset-controller.h
+++ b/include/linux/reset-controller.h
@@ -31,6 +31,7 @@ struct of_phandle_args;
* @ops: a pointer to device specific struct reset_control_ops
* @owner: kernel module of the reset controller driver
* @list: internal list of reset controller devices
+ * @reset_control_head: head of internal list of requested reset controls
* @of_node: corresponding device tree node as phandle target
* @of_reset_n_cells: number of cells in reset line specifiers
* @of_xlate: translation function to translate from specifier as found in the
@@ -41,6 +42,7 @@ struct reset_controller_dev {
struct reset_control_ops *ops;
struct module *owner;
struct list_head list;
+ struct list_head reset_control_head;
struct device_node *of_node;
int of_reset_n_cells;
int (*of_xlate)(struct reset_controller_dev *rcdev,
--
2.7.1
next prev parent reply other threads:[~2016-02-23 17:46 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-02-23 17:46 [PATCH v4 0/3] reset: Add support for shared reset controls Hans de Goede
2016-02-23 17:46 ` [PATCH v4 1/3] reset: Make [of_]reset_control_get[_foo] functions wrappers Hans de Goede
2016-02-23 17:46 ` Hans de Goede [this message]
2016-02-23 17:46 ` [PATCH v4 3/3] reset: Add support for shared reset controls Hans de Goede
2016-02-24 10:42 ` [PATCH v4 0/3] " Philipp Zabel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1456249586-12101-3-git-send-email-hdegoede@redhat.com \
--to=hdegoede@redhat.com \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).