Skip to content

Commit 8c91302

Browse files
Bartosz GolaszewskipH5
authored andcommitted
reset: protect struct reset_control with its own mutex
Currently we use a single, global mutex - misleadingly names reset_list_mutex - to protect the global list of reset devices, per-controller list of reset control handles and also internal fields of struct reset_control. Locking can be made a lot more fine-grained if we use a separate mutex for serializing operations on the list AND accessing the reset control handle. Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com> Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
1 parent 44a0acb commit 8c91302

1 file changed

Lines changed: 36 additions & 32 deletions

File tree

drivers/reset/core.c

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ static DEFINE_IDA(reset_gpio_ida);
4949
* @triggered_count: Number of times this reset line has been reset. Currently
5050
* only used for shared resets, which means that the value
5151
* will be either 0 or 1.
52+
* @lock: serializes the internals of reset_control_acquire()
5253
*/
5354
struct reset_control {
5455
struct reset_controller_dev __rcu *rcdev;
@@ -61,6 +62,7 @@ struct reset_control {
6162
bool array;
6263
atomic_t deassert_count;
6364
atomic_t triggered_count;
65+
struct mutex lock;
6466
};
6567

6668
/**
@@ -707,7 +709,7 @@ int reset_control_acquire(struct reset_control *rstc)
707709
if (reset_control_is_array(rstc))
708710
return reset_control_array_acquire(rstc_to_array(rstc));
709711

710-
guard(mutex)(&reset_list_mutex);
712+
guard(mutex)(&rstc->lock);
711713

712714
if (rstc->acquired)
713715
return 0;
@@ -859,6 +861,7 @@ __reset_control_get_internal(struct reset_controller_dev *rcdev,
859861
list_add(&rstc->list, &rcdev->reset_control_head);
860862
rstc->id = index;
861863
kref_init(&rstc->refcnt);
864+
mutex_init(&rstc->lock);
862865
rstc->acquired = acquired;
863866
rstc->shared = shared;
864867
get_device(rcdev->dev);
@@ -872,29 +875,40 @@ static void __reset_control_release(struct kref *kref)
872875
refcnt);
873876
struct reset_controller_dev *rcdev;
874877

875-
lockdep_assert_held(&reset_list_mutex);
878+
lockdep_assert_held(&rstc->srcu);
876879

877-
scoped_guard(srcu, &rstc->srcu) {
878-
rcdev = rcu_replace_pointer(rstc->rcdev, NULL, true);
879-
if (rcdev) {
880-
guard(mutex)(&rcdev->lock);
881-
reset_controller_remove(rcdev, rstc);
882-
}
880+
rcdev = rcu_replace_pointer(rstc->rcdev, NULL, true);
881+
if (rcdev) {
882+
lockdep_assert_held(&rcdev->lock);
883+
reset_controller_remove(rcdev, rstc);
883884
}
884885

885-
synchronize_srcu(&rstc->srcu);
886-
cleanup_srcu_struct(&rstc->srcu);
887-
kfree(rstc);
886+
mutex_destroy(&rstc->lock);
888887
}
889888

890-
static void __reset_control_put_internal(struct reset_control *rstc)
889+
static void reset_control_put_internal(struct reset_control *rstc)
891890
{
892-
lockdep_assert_held(&reset_list_mutex);
891+
struct reset_controller_dev *rcdev;
892+
int ret = 0;
893893

894894
if (IS_ERR_OR_NULL(rstc))
895895
return;
896896

897-
kref_put(&rstc->refcnt, __reset_control_release);
897+
scoped_guard(srcu, &rstc->srcu) {
898+
rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu);
899+
if (!rcdev)
900+
/* Already released. */
901+
return;
902+
903+
guard(mutex)(&rcdev->lock);
904+
ret = kref_put(&rstc->refcnt, __reset_control_release);
905+
}
906+
907+
if (ret) {
908+
synchronize_srcu(&rstc->srcu);
909+
cleanup_srcu_struct(&rstc->srcu);
910+
kfree(rstc);
911+
}
898912
}
899913

900914
static void reset_gpio_aux_device_release(struct device *dev)
@@ -1104,7 +1118,7 @@ __of_reset_control_get(struct device_node *node, const char *id, int index,
11041118
{
11051119
bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
11061120
bool gpio_fallback = false;
1107-
struct reset_control *rstc;
1121+
struct reset_control *rstc = ERR_PTR(-EINVAL);
11081122
struct reset_controller_dev *rcdev;
11091123
struct of_phandle_args args;
11101124
int rstc_id;
@@ -1169,8 +1183,8 @@ __of_reset_control_get(struct device_node *node, const char *id, int index,
11691183

11701184
flags &= ~RESET_CONTROL_FLAGS_BIT_OPTIONAL;
11711185

1172-
/* reset_list_mutex also protects the rcdev's reset_control list */
1173-
rstc = __reset_control_get_internal(rcdev, rstc_id, flags);
1186+
scoped_guard(mutex, &rcdev->lock)
1187+
rstc = __reset_control_get_internal(rcdev, rstc_id, flags);
11741188

11751189
out_put:
11761190
of_node_put(args.np);
@@ -1213,10 +1227,8 @@ int __reset_control_bulk_get(struct device *dev, int num_rstcs,
12131227
return 0;
12141228

12151229
err:
1216-
guard(mutex)(&reset_list_mutex);
1217-
12181230
while (i--)
1219-
__reset_control_put_internal(rstcs[i].rstc);
1231+
reset_control_put_internal(rstcs[i].rstc);
12201232

12211233
return ret;
12221234
}
@@ -1226,10 +1238,8 @@ static void reset_control_array_put(struct reset_control_array *resets)
12261238
{
12271239
int i;
12281240

1229-
guard(mutex)(&reset_list_mutex);
1230-
12311241
for (i = 0; i < resets->num_rstcs; i++)
1232-
__reset_control_put_internal(resets->rstc[i]);
1242+
reset_control_put_internal(resets->rstc[i]);
12331243
kfree(resets);
12341244
}
12351245

@@ -1247,9 +1257,7 @@ void reset_control_put(struct reset_control *rstc)
12471257
return;
12481258
}
12491259

1250-
guard(mutex)(&reset_list_mutex);
1251-
1252-
__reset_control_put_internal(rstc);
1260+
reset_control_put_internal(rstc);
12531261
}
12541262
EXPORT_SYMBOL_GPL(reset_control_put);
12551263

@@ -1260,10 +1268,8 @@ EXPORT_SYMBOL_GPL(reset_control_put);
12601268
*/
12611269
void reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs)
12621270
{
1263-
guard(mutex)(&reset_list_mutex);
1264-
12651271
while (num_rstcs--)
1266-
__reset_control_put_internal(rstcs[num_rstcs].rstc);
1272+
reset_control_put_internal(rstcs[num_rstcs].rstc);
12671273
}
12681274
EXPORT_SYMBOL_GPL(reset_control_bulk_put);
12691275

@@ -1482,10 +1488,8 @@ of_reset_control_array_get(struct device_node *np, enum reset_control_flags flag
14821488
return &resets->base;
14831489

14841490
err_rst:
1485-
guard(mutex)(&reset_list_mutex);
1486-
14871491
while (--i >= 0)
1488-
__reset_control_put_internal(resets->rstc[i]);
1492+
reset_control_put_internal(resets->rstc[i]);
14891493

14901494
kfree(resets);
14911495

0 commit comments

Comments
 (0)