Commit ee222c5d authored by Thierry Reding's avatar Thierry Reding

Merge branch 'reset/acquire' of git://git.pengutronix.de/git/pza/linux into drm/tegra/for-next

parents 9e98c678 22815f18
......@@ -34,6 +34,7 @@ static LIST_HEAD(reset_lookup_list);
* @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
* @triggered_count: Number of times this reset line has been reset. Currently
......@@ -45,6 +46,7 @@ struct reset_control {
struct list_head list;
unsigned int id;
struct kref refcnt;
bool acquired;
bool shared;
bool array;
atomic_t deassert_count;
......@@ -63,6 +65,17 @@ struct reset_control_array {
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
......@@ -232,6 +245,34 @@ static int reset_control_array_deassert(struct reset_control_array *resets)
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 +313,9 @@ int reset_control_reset(struct reset_control *rstc)
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);
......@@ -334,6 +378,12 @@ int reset_control_assert(struct reset_control *rstc)
*/
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);
......@@ -369,6 +419,12 @@ int reset_control_deassert(struct reset_control *rstc)
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 +462,87 @@ int reset_control_status(struct reset_control *rstc)
}
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 +550,14 @@ static struct reset_control *__reset_control_get_internal(
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);
......@@ -434,6 +576,7 @@ static struct reset_control *__reset_control_get_internal(
list_add(&rstc->list, &rcdev->reset_control_head);
rstc->id = index;
kref_init(&rstc->refcnt);
rstc->acquired = acquired;
rstc->shared = shared;
return rstc;
......@@ -461,7 +604,7 @@ static void __reset_control_put_internal(struct reset_control *rstc)
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;
......@@ -514,7 +657,7 @@ struct reset_control *__of_reset_control_get(struct device_node *node,
}
/* 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);
......@@ -544,7 +687,7 @@ __reset_controller_by_name(const char *name)
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;
......@@ -574,7 +717,7 @@ __reset_control_get_from_lookup(struct device *dev, const char *con_id,
rstc = __reset_control_get_internal(rcdev,
lookup->index,
shared);
shared, acquired);
mutex_unlock(&reset_list_mutex);
break;
}
......@@ -589,13 +732,18 @@ __reset_control_get_from_lookup(struct device *dev, const char *con_id,
}
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);
......@@ -636,7 +784,7 @@ static void devm_reset_control_release(struct device *dev, void *res)
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;
......@@ -645,7 +793,7 @@ struct reset_control *__devm_reset_control_get(struct device *dev,
if (!ptr)
return ERR_PTR(-ENOMEM);
rstc = __reset_control_get(dev, id, index, shared, optional);
rstc = __reset_control_get(dev, id, index, shared, optional, acquired);
if (!IS_ERR(rstc)) {
*ptr = rstc;
devres_add(dev, ptr);
......@@ -672,7 +820,7 @@ int __device_reset(struct device *dev, bool optional)
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);
......@@ -716,12 +864,15 @@ static int of_reset_control_get_count(struct device_node *node)
* @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
*/
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;
......@@ -736,7 +887,8 @@ of_reset_control_array_get(struct device_node *np, bool shared, bool optional)
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;
......@@ -783,7 +935,7 @@ devm_reset_control_array_get(struct device *dev, bool shared, bool optional)
if (!devres)
return ERR_PTR(-ENOMEM);
rstc = of_reset_control_array_get(dev->of_node, shared, optional);
rstc = of_reset_control_array_get(dev->of_node, shared, optional, true);
if (IS_ERR(rstc)) {
devres_free(devres);
return rstc;
......
......@@ -107,7 +107,8 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
simple->pulse_resets = true;
}
simple->resets = of_reset_control_array_get(np, shared_resets, true);
simple->resets = of_reset_control_array_get(np, shared_resets, true,
true);
if (IS_ERR(simple->resets)) {
ret = PTR_ERR(simple->resets);
dev_err(dev, "failed to get device resets, err=%d\n", ret);
......
......@@ -14,23 +14,26 @@ int reset_control_reset(struct reset_control *rstc);
int reset_control_assert(struct reset_control *rstc);
int reset_control_deassert(struct reset_control *rstc);
int reset_control_status(struct reset_control *rstc);
int reset_control_acquire(struct reset_control *rstc);
void reset_control_release(struct reset_control *rstc);
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 *__reset_control_get(struct device *dev, const char *id,
int index, bool shared,
bool optional);
bool optional, bool acquired);
void reset_control_put(struct reset_control *rstc);
int __device_reset(struct device *dev, bool optional);
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 *devm_reset_control_array_get(struct device *dev,
bool shared, bool optional);
struct reset_control *of_reset_control_array_get(struct device_node *np,
bool shared, bool optional);
bool shared, bool optional,
bool acquired);
int reset_control_get_count(struct device *dev);
......@@ -56,6 +59,15 @@ static inline int reset_control_status(struct reset_control *rstc)
return 0;
}
static inline int reset_control_acquire(struct reset_control *rstc)
{
return 0;
}
static inline void reset_control_release(struct reset_control *rstc)
{
}
static inline void reset_control_put(struct reset_control *rstc)
{
}
......@@ -68,21 +80,23 @@ static inline int __device_reset(struct device *dev, bool optional)
static inline struct reset_control *__of_reset_control_get(
struct device_node *node,
const char *id, int index, bool shared,
bool optional)
bool optional, bool acquired)
{
return optional ? NULL : ERR_PTR(-ENOTSUPP);
}
static inline 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)
{
return optional ? NULL : ERR_PTR(-ENOTSUPP);
}
static inline struct reset_control *__devm_reset_control_get(
struct device *dev, const char *id,
int index, bool shared, bool optional)
int index, bool shared, bool optional,
bool acquired)
{
return optional ? NULL : ERR_PTR(-ENOTSUPP);
}
......@@ -94,7 +108,8 @@ devm_reset_control_array_get(struct device *dev, bool shared, bool optional)
}
static inline 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)
{
return optional ? NULL : ERR_PTR(-ENOTSUPP);
}
......@@ -134,7 +149,28 @@ static inline int device_reset_optional(struct device *dev)
static inline struct reset_control *
__must_check reset_control_get_exclusive(struct device *dev, const char *id)
{
return __reset_control_get(dev, id, 0, false, false);
return __reset_control_get(dev, id, 0, false, false, true);
}
/**
* reset_control_get_exclusive_released - Lookup and obtain a temoprarily
* exclusive reference to a reset
* controller.
* @dev: device to be reset by the controller
* @id: reset line name
*
* Returns a struct reset_control or IS_ERR() condition containing errno.
* reset-controls returned by this function must be acquired via
* reset_control_acquire() before they can be used and should be released
* via reset_control_release() afterwards.
*
* Use of id names is optional.
*/
static inline struct reset_control *
__must_check reset_control_get_exclusive_released(struct device *dev,
const char *id)
{
return __reset_control_get(dev, id, 0, false, false, false);
}
/**
......@@ -162,19 +198,19 @@ __must_check reset_control_get_exclusive(struct device *dev, const char *id)
static inline struct reset_control *reset_control_get_shared(
struct device *dev, const char *id)
{
return __reset_control_get(dev, id, 0, true, false);
return __reset_control_get(dev, id, 0, true, false, false);
}
static inline struct reset_control *reset_control_get_optional_exclusive(
struct device *dev, const char *id)
{
return __reset_control_get(dev, id, 0, false, true);
return __reset_control_get(dev, id, 0, false, true, true);
}
static inline struct reset_control *reset_control_get_optional_shared(
struct device *dev, const char *id)
{
return __reset_control_get(dev, id, 0, true, true);
return __reset_control_get(dev, id, 0, true, true, false);
}
/**
......@@ -190,7 +226,7 @@ static inline struct reset_control *reset_control_get_optional_shared(
static inline struct reset_control *of_reset_control_get_exclusive(
struct device_node *node, const char *id)
{
return __of_reset_control_get(node, id, 0, false, false);
return __of_reset_control_get(node, id, 0, false, false, true);
}
/**
......@@ -215,7 +251,7 @@ static inline struct reset_control *of_reset_control_get_exclusive(
static inline struct reset_control *of_reset_control_get_shared(
struct device_node *node, const char *id)
{
return __of_reset_control_get(node, id, 0, true, false);
return __of_reset_control_get(node, id, 0, true, false, false);
}
/**
......@@ -232,7 +268,7 @@ static inline struct reset_control *of_reset_control_get_shared(
static inline struct reset_control *of_reset_control_get_exclusive_by_index(
struct device_node *node, int index)
{
return __of_reset_control_get(node, NULL, index, false, false);
return __of_reset_control_get(node, NULL, index, false, false, true);
}
/**
......@@ -260,7 +296,7 @@ static inline struct reset_control *of_reset_control_get_exclusive_by_index(
static inline struct reset_control *of_reset_control_get_shared_by_index(
struct device_node *node, int index)
{
return __of_reset_control_get(node, NULL, index, true, false);
return __of_reset_control_get(node, NULL, index, true, false, false);
}
/**
......@@ -279,7 +315,26 @@ static inline struct reset_control *
__must_check devm_reset_control_get_exclusive(struct device *dev,
const char *id)
{
return __devm_reset_control_get(dev, id, 0, false, false);
return __devm_reset_control_get(dev, id, 0, false, false, true);
}
/**
* devm_reset_control_get_exclusive_released - resource managed
* reset_control_get_exclusive_released()
* @dev: device to be reset by the controller
* @id: reset line name
*
* Managed reset_control_get_exclusive_released(). For reset controllers
* returned from this function, reset_control_put() is called automatically on
* driver detach.
*
* See reset_control_get_exclusive_released() for more information.
*/
static inline struct reset_control *
__must_check devm_reset_control_get_exclusive_released(struct device *dev,
const char *id)
{
return __devm_reset_control_get(dev, id, 0, false, false, false);
}
/**
......@@ -294,19 +349,19 @@ __must_check devm_reset_control_get_exclusive(struct device *dev,
static inline struct reset_control *devm_reset_control_get_shared(
struct device *dev, const char *id)
{
return __devm_reset_control_get(dev, id, 0, true, false);
return __devm_reset_control_get(dev, id, 0, true, false, false);
}
static inline struct reset_control *devm_reset_control_get_optional_exclusive(
struct device *dev, const char *id)
{
return __devm_reset_control_get(dev, id, 0, false, true);
return __devm_reset_control_get(dev, id, 0, false, true, true);
}
static inline struct reset_control *devm_reset_control_get_optional_shared(
struct device *dev, const char *id)
{
return __devm_reset_control_get(dev, id, 0, true, true);
return __devm_reset_control_get(dev, id, 0, true, true, false);
}
/**
......@@ -324,7 +379,7 @@ static inline struct reset_control *devm_reset_control_get_optional_shared(
static inline struct reset_control *
devm_reset_control_get_exclusive_by_index(struct device *dev, int index)
{
return __devm_reset_control_get(dev, NULL, index, false, false);
return __devm_reset_control_get(dev, NULL, index, false, false, true);
}
/**
......@@ -340,7 +395,7 @@ devm_reset_control_get_exclusive_by_index(struct device *dev, int index)
static inline struct reset_control *
devm_reset_control_get_shared_by_index(struct device *dev, int index)
{
return __devm_reset_control_get(dev, NULL, index, true, false);
return __devm_reset_control_get(dev, NULL, index, true, false, false);
}
/*
......@@ -412,24 +467,30 @@ devm_reset_control_array_get_optional_shared(struct device *dev)
static inline struct reset_control *
of_reset_control_array_get_exclusive(struct device_node *node)
{
return of_reset_control_array_get(node, false, false);
return of_reset_control_array_get(node, false, false, true);
}
static inline struct reset_control *
of_reset_control_array_get_exclusive_released(struct device_node *node)
{
return of_reset_control_array_get(node, false, false, false);
}
static inline struct reset_control *
of_reset_control_array_get_shared(struct device_node *node)
{
return of_reset_control_array_get(node, true, false);
return of_reset_control_array_get(node, true, false, true);
}
static inline struct reset_control *
of_reset_control_array_get_optional_exclusive(struct device_node *node)
{
return of_reset_control_array_get(node, false, true);
return of_reset_control_array_get(node, false, true, true);
}
static inline struct reset_control *
of_reset_control_array_get_optional_shared(struct device_node *node)
{
return of_reset_control_array_get(node, true, true);
return of_reset_control_array_get(node, true, true, true);
}
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment