From 072de836f53be56a70cecf70b43ae43b7ce17376 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 11 Dec 2023 10:08:36 +0000
Subject: [PATCH] mk-rootfs.sh
---
kernel/drivers/reset/core.c | 287 +++++++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 237 insertions(+), 50 deletions(-)
diff --git a/kernel/drivers/reset/core.c b/kernel/drivers/reset/core.c
index ccb97f4..f93388b 100644
--- a/kernel/drivers/reset/core.c
+++ b/kernel/drivers/reset/core.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Reset Controller framework
*
* Copyright 2013 Philipp Zabel, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/atomic.h>
#include <linux/device.h>
@@ -34,8 +30,10 @@
* @id: ID of the reset controller in the reset
* controller device
* @refcnt: Number of gets of this reset_control
+ * @acquired: Only one reset_control may be acquired for a given rcdev and id.
* @shared: Is this a shared (1), or an exclusive (0) reset_control?
- * @deassert_cnt: Number of times this reset line has been deasserted
+ * @array: Is this an array of reset controls (1)?
+ * @deassert_count: Number of times this reset line has been deasserted
* @triggered_count: Number of times this reset line has been reset. Currently
* only used for shared resets, which means that the value
* will be either 0 or 1.
@@ -45,6 +43,7 @@
struct list_head list;
unsigned int id;
struct kref refcnt;
+ bool acquired;
bool shared;
bool array;
atomic_t deassert_count;
@@ -63,14 +62,26 @@
struct reset_control *rstc[];
};
+static const char *rcdev_name(struct reset_controller_dev *rcdev)
+{
+ if (rcdev->dev)
+ return dev_name(rcdev->dev);
+
+ if (rcdev->of_node)
+ return rcdev->of_node->full_name;
+
+ return NULL;
+}
+
/**
* of_reset_simple_xlate - translate reset_spec to the reset line number
* @rcdev: a pointer to the reset controller device
* @reset_spec: reset line specifier as found in the device tree
- * @flags: a flags pointer to fill in (optional)
*
- * This simple translation function should be used for reset controllers
- * with 1:1 mapping, where reset lines can be indexed by number without gaps.
+ * This static translation function is used by default if of_xlate in
+ * :c:type:`reset_controller_dev` is not set. It is useful for all reset
+ * controllers with 1:1 mapping, where reset lines can be indexed by number
+ * without gaps.
*/
static int of_reset_simple_xlate(struct reset_controller_dev *rcdev,
const struct of_phandle_args *reset_spec)
@@ -140,12 +151,13 @@
return -ENOMEM;
ret = reset_controller_register(rcdev);
- if (!ret) {
- *rcdevp = rcdev;
- devres_add(dev, rcdevp);
- } else {
+ if (ret) {
devres_free(rcdevp);
+ return ret;
}
+
+ *rcdevp = rcdev;
+ devres_add(dev, rcdevp);
return ret;
}
@@ -232,6 +244,34 @@
return ret;
}
+static int reset_control_array_acquire(struct reset_control_array *resets)
+{
+ unsigned int i;
+ int err;
+
+ for (i = 0; i < resets->num_rstcs; i++) {
+ err = reset_control_acquire(resets->rstc[i]);
+ if (err < 0)
+ goto release;
+ }
+
+ return 0;
+
+release:
+ while (i--)
+ reset_control_release(resets->rstc[i]);
+
+ return err;
+}
+
+static void reset_control_array_release(struct reset_control_array *resets)
+{
+ unsigned int i;
+
+ for (i = 0; i < resets->num_rstcs; i++)
+ reset_control_release(resets->rstc[i]);
+}
+
static inline bool reset_control_is_array(struct reset_control *rstc)
{
return rstc->array;
@@ -272,6 +312,9 @@
if (atomic_inc_return(&rstc->triggered_count) != 1)
return 0;
+ } else {
+ if (!rstc->acquired)
+ return -EPERM;
}
ret = rstc->rcdev->ops->reset(rstc->rcdev, rstc->id);
@@ -294,7 +337,6 @@
* internal state to be reset, but must be prepared for this to happen.
* Consumers must not use reset_control_reset on shared reset lines when
* reset_control_(de)assert has been used.
- * return 0.
*
* If rstc is NULL it is an optional reset and the function will just
* return 0.
@@ -334,6 +376,12 @@
*/
if (!rstc->rcdev->ops->assert)
return -ENOTSUPP;
+
+ if (!rstc->acquired) {
+ WARN(1, "reset %s (ID: %u) is not acquired\n",
+ rcdev_name(rstc->rcdev), rstc->id);
+ return -EPERM;
+ }
}
return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);
@@ -347,7 +395,6 @@
* After calling this function, the reset is guaranteed to be deasserted.
* Consumers must not use reset_control_reset on shared reset lines when
* reset_control_(de)assert has been used.
- * return 0.
*
* If rstc is NULL it is an optional reset and the function will just
* return 0.
@@ -369,6 +416,12 @@
if (atomic_inc_return(&rstc->deassert_count) != 1)
return 0;
+ } else {
+ if (!rstc->acquired) {
+ WARN(1, "reset %s (ID: %u) is not acquired\n",
+ rcdev_name(rstc->rcdev), rstc->id);
+ return -EPERM;
+ }
}
/*
@@ -406,9 +459,87 @@
}
EXPORT_SYMBOL_GPL(reset_control_status);
+/**
+ * reset_control_acquire() - acquires a reset control for exclusive use
+ * @rstc: reset control
+ *
+ * This is used to explicitly acquire a reset control for exclusive use. Note
+ * that exclusive resets are requested as acquired by default. In order for a
+ * second consumer to be able to control the reset, the first consumer has to
+ * release it first. Typically the easiest way to achieve this is to call the
+ * reset_control_get_exclusive_released() to obtain an instance of the reset
+ * control. Such reset controls are not acquired by default.
+ *
+ * Consumers implementing shared access to an exclusive reset need to follow
+ * a specific protocol in order to work together. Before consumers can change
+ * a reset they must acquire exclusive access using reset_control_acquire().
+ * After they are done operating the reset, they must release exclusive access
+ * with a call to reset_control_release(). Consumers are not granted exclusive
+ * access to the reset as long as another consumer hasn't released a reset.
+ *
+ * See also: reset_control_release()
+ */
+int reset_control_acquire(struct reset_control *rstc)
+{
+ struct reset_control *rc;
+
+ if (!rstc)
+ return 0;
+
+ if (WARN_ON(IS_ERR(rstc)))
+ return -EINVAL;
+
+ if (reset_control_is_array(rstc))
+ return reset_control_array_acquire(rstc_to_array(rstc));
+
+ mutex_lock(&reset_list_mutex);
+
+ if (rstc->acquired) {
+ mutex_unlock(&reset_list_mutex);
+ return 0;
+ }
+
+ list_for_each_entry(rc, &rstc->rcdev->reset_control_head, list) {
+ if (rstc != rc && rstc->id == rc->id) {
+ if (rc->acquired) {
+ mutex_unlock(&reset_list_mutex);
+ return -EBUSY;
+ }
+ }
+ }
+
+ rstc->acquired = true;
+
+ mutex_unlock(&reset_list_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(reset_control_acquire);
+
+/**
+ * reset_control_release() - releases exclusive access to a reset control
+ * @rstc: reset control
+ *
+ * Releases exclusive access right to a reset control previously obtained by a
+ * call to reset_control_acquire(). Until a consumer calls this function, no
+ * other consumers will be granted exclusive access.
+ *
+ * See also: reset_control_acquire()
+ */
+void reset_control_release(struct reset_control *rstc)
+{
+ if (!rstc || WARN_ON(IS_ERR(rstc)))
+ return;
+
+ if (reset_control_is_array(rstc))
+ reset_control_array_release(rstc_to_array(rstc));
+ else
+ rstc->acquired = false;
+}
+EXPORT_SYMBOL_GPL(reset_control_release);
+
static struct reset_control *__reset_control_get_internal(
struct reset_controller_dev *rcdev,
- unsigned int index, bool shared)
+ unsigned int index, bool shared, bool acquired)
{
struct reset_control *rstc;
@@ -416,6 +547,14 @@
list_for_each_entry(rstc, &rcdev->reset_control_head, list) {
if (rstc->id == index) {
+ /*
+ * Allow creating a secondary exclusive reset_control
+ * that is initially not acquired for an already
+ * controlled reset line.
+ */
+ if (!rstc->shared && !shared && !acquired)
+ break;
+
if (WARN_ON(!rstc->shared || !shared))
return ERR_PTR(-EBUSY);
@@ -437,6 +576,7 @@
list_add(&rstc->list, &rcdev->reset_control_head);
rstc->id = index;
kref_init(&rstc->refcnt);
+ rstc->acquired = acquired;
rstc->shared = shared;
return rstc;
@@ -464,7 +604,7 @@
struct reset_control *__of_reset_control_get(struct device_node *node,
const char *id, int index, bool shared,
- bool optional)
+ bool optional, bool acquired)
{
struct reset_control *rstc;
struct reset_controller_dev *r, *rcdev;
@@ -517,7 +657,7 @@
}
/* reset_list_mutex also protects the rcdev's reset_control list */
- rstc = __reset_control_get_internal(rcdev, rstc_id, shared);
+ rstc = __reset_control_get_internal(rcdev, rstc_id, shared, acquired);
out:
mutex_unlock(&reset_list_mutex);
@@ -547,15 +687,12 @@
static struct reset_control *
__reset_control_get_from_lookup(struct device *dev, const char *con_id,
- bool shared, bool optional)
+ bool shared, bool optional, bool acquired)
{
const struct reset_control_lookup *lookup;
struct reset_controller_dev *rcdev;
const char *dev_id = dev_name(dev);
struct reset_control *rstc = NULL;
-
- if (!dev)
- return ERR_PTR(-EINVAL);
mutex_lock(&reset_lookup_mutex);
@@ -577,7 +714,7 @@
rstc = __reset_control_get_internal(rcdev,
lookup->index,
- shared);
+ shared, acquired);
mutex_unlock(&reset_list_mutex);
break;
}
@@ -592,13 +729,18 @@
}
struct reset_control *__reset_control_get(struct device *dev, const char *id,
- int index, bool shared, bool optional)
+ int index, bool shared, bool optional,
+ bool acquired)
{
+ if (WARN_ON(shared && acquired))
+ return ERR_PTR(-EINVAL);
+
if (dev->of_node)
return __of_reset_control_get(dev->of_node, id, index, shared,
- optional);
+ optional, acquired);
- return __reset_control_get_from_lookup(dev, id, shared, optional);
+ return __reset_control_get_from_lookup(dev, id, shared, optional,
+ acquired);
}
EXPORT_SYMBOL_GPL(__reset_control_get);
@@ -640,7 +782,7 @@
struct reset_control *__devm_reset_control_get(struct device *dev,
const char *id, int index, bool shared,
- bool optional)
+ bool optional, bool acquired)
{
struct reset_control **ptr, *rstc;
@@ -649,13 +791,14 @@
if (!ptr)
return ERR_PTR(-ENOMEM);
- rstc = __reset_control_get(dev, id, index, shared, optional);
- if (!IS_ERR(rstc)) {
- *ptr = rstc;
- devres_add(dev, ptr);
- } else {
+ rstc = __reset_control_get(dev, id, index, shared, optional, acquired);
+ if (IS_ERR_OR_NULL(rstc)) {
devres_free(ptr);
+ return rstc;
}
+
+ *ptr = rstc;
+ devres_add(dev, ptr);
return rstc;
}
@@ -676,7 +819,7 @@
struct reset_control *rstc;
int ret;
- rstc = __reset_control_get(dev, NULL, 0, 0, optional);
+ rstc = __reset_control_get(dev, NULL, 0, 0, optional, true);
if (IS_ERR(rstc))
return PTR_ERR(rstc);
@@ -688,9 +831,10 @@
}
EXPORT_SYMBOL_GPL(__device_reset);
-/**
+/*
* APIs to manage an array of reset controls.
*/
+
/**
* of_reset_control_get_count - Count number of resets available with a device
*
@@ -720,12 +864,14 @@
* @np: device node for the device that requests the reset controls array
* @shared: whether reset controls are shared or not
* @optional: whether it is optional to get the reset controls
+ * @acquired: only one reset control may be acquired for a given controller
+ * and ID
*
- * Returns pointer to allocated reset_control_array on success or
- * error on failure
+ * Returns pointer to allocated reset_control on success or error on failure
*/
struct reset_control *
-of_reset_control_array_get(struct device_node *np, bool shared, bool optional)
+of_reset_control_array_get(struct device_node *np, bool shared, bool optional,
+ bool acquired)
{
struct reset_control_array *resets;
struct reset_control *rstc;
@@ -740,7 +886,8 @@
return ERR_PTR(-ENOMEM);
for (i = 0; i < num; i++) {
- rstc = __of_reset_control_get(np, NULL, i, shared, optional);
+ rstc = __of_reset_control_get(np, NULL, i, shared, optional,
+ acquired);
if (IS_ERR(rstc))
goto err_rst;
resets->rstc[i] = rstc;
@@ -773,29 +920,69 @@
* that just have to be asserted or deasserted, without any
* requirements on the order.
*
- * Returns pointer to allocated reset_control_array on success or
- * error on failure
+ * Returns pointer to allocated reset_control on success or error on failure
*/
struct reset_control *
devm_reset_control_array_get(struct device *dev, bool shared, bool optional)
{
- struct reset_control **devres;
- struct reset_control *rstc;
+ struct reset_control **ptr, *rstc;
- devres = devres_alloc(devm_reset_control_release, sizeof(*devres),
- GFP_KERNEL);
- if (!devres)
+ ptr = devres_alloc(devm_reset_control_release, sizeof(*ptr),
+ GFP_KERNEL);
+ if (!ptr)
return ERR_PTR(-ENOMEM);
- rstc = of_reset_control_array_get(dev->of_node, shared, optional);
- if (IS_ERR(rstc)) {
- devres_free(devres);
+ rstc = of_reset_control_array_get(dev->of_node, shared, optional, true);
+ if (IS_ERR_OR_NULL(rstc)) {
+ devres_free(ptr);
return rstc;
}
- *devres = rstc;
- devres_add(dev, devres);
+ *ptr = rstc;
+ devres_add(dev, ptr);
return rstc;
}
EXPORT_SYMBOL_GPL(devm_reset_control_array_get);
+
+static int reset_control_get_count_from_lookup(struct device *dev)
+{
+ const struct reset_control_lookup *lookup;
+ const char *dev_id;
+ int count = 0;
+
+ if (!dev)
+ return -EINVAL;
+
+ dev_id = dev_name(dev);
+ mutex_lock(&reset_lookup_mutex);
+
+ list_for_each_entry(lookup, &reset_lookup_list, list) {
+ if (!strcmp(lookup->dev_id, dev_id))
+ count++;
+ }
+
+ mutex_unlock(&reset_lookup_mutex);
+
+ if (count == 0)
+ count = -ENOENT;
+
+ return count;
+}
+
+/**
+ * reset_control_get_count - Count number of resets available with a device
+ *
+ * @dev: device for which to return the number of resets
+ *
+ * Returns positive reset count on success, or error number on failure and
+ * on count being zero.
+ */
+int reset_control_get_count(struct device *dev)
+{
+ if (dev->of_node)
+ return of_reset_control_get_count(dev->of_node);
+
+ return reset_control_get_count_from_lookup(dev);
+}
+EXPORT_SYMBOL_GPL(reset_control_get_count);
--
Gitblit v1.6.2