Skip to content

Commit 78ebbff

Browse files
Bartosz GolaszewskipH5
authored andcommitted
reset: handle removing supplier before consumers
Except for the reset-gpio, all reset drivers use device tree - and as such - benefit from the device links set up by driver core. This means, that no reset supplier will be unbound before all its consumers have been. For this reason, nobody bothered making the reset core resiliant to the object life-time issues that are plagueing the kernel. In this case: reset control handles referencing the reset provider device with no serialization or NULL-pointer checking. We now want to make the reset core fwnode-agnostic but before we do, we must make sure it can survive unbinding of suppliers with consumers still holding reset control handles. To that end: use SRCU to protect the rcdev pointer inside struct reset_control. We protect all sections using the pointer with SRCU read-only critical sections and synchronize SRCU after every modification of the pointer. This is in line with what the GPIO subsystem does and what the proposed revocable API tries to generalize. When and if the latter makes its way into the kernel, reset core could potentially also be generalized to use it. 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 1f10008 commit 78ebbff

1 file changed

Lines changed: 91 additions & 17 deletions

File tree

drivers/reset/core.c

Lines changed: 91 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <linux/reset.h>
2424
#include <linux/reset-controller.h>
2525
#include <linux/slab.h>
26+
#include <linux/srcu.h>
2627

2728
static DEFINE_MUTEX(reset_list_mutex);
2829
static LIST_HEAD(reset_controller_list);
@@ -36,6 +37,7 @@ static DEFINE_IDA(reset_gpio_ida);
3637
* struct reset_control - a reset control
3738
* @rcdev: a pointer to the reset controller device
3839
* this reset control belongs to
40+
* @srcu: protects the rcdev pointer from removal during consumer access
3941
* @list: list entry for the rcdev's reset controller list
4042
* @id: ID of the reset controller in the reset
4143
* controller device
@@ -49,7 +51,8 @@ static DEFINE_IDA(reset_gpio_ida);
4951
* will be either 0 or 1.
5052
*/
5153
struct reset_control {
52-
struct reset_controller_dev *rcdev;
54+
struct reset_controller_dev __rcu *rcdev;
55+
struct srcu_struct srcu;
5356
struct list_head list;
5457
unsigned int id;
5558
struct kref refcnt;
@@ -137,15 +140,35 @@ int reset_controller_register(struct reset_controller_dev *rcdev)
137140
}
138141
EXPORT_SYMBOL_GPL(reset_controller_register);
139142

143+
static void reset_controller_remove(struct reset_controller_dev *rcdev,
144+
struct reset_control *rstc)
145+
{
146+
list_del(&rstc->list);
147+
module_put(rcdev->owner);
148+
put_device(rcdev->dev);
149+
}
150+
140151
/**
141152
* reset_controller_unregister - unregister a reset controller device
142153
* @rcdev: a pointer to the reset controller device
143154
*/
144155
void reset_controller_unregister(struct reset_controller_dev *rcdev)
145156
{
157+
struct reset_control *rstc, *pos;
158+
146159
guard(mutex)(&reset_list_mutex);
147160

148161
list_del(&rcdev->list);
162+
163+
/*
164+
* Numb but don't free the remaining reset control handles that are
165+
* still held by consumers.
166+
*/
167+
list_for_each_entry_safe(rstc, pos, &rcdev->reset_control_head, list) {
168+
rcu_assign_pointer(rstc->rcdev, NULL);
169+
synchronize_srcu(&rstc->srcu);
170+
reset_controller_remove(rcdev, rstc);
171+
}
149172
}
150173
EXPORT_SYMBOL_GPL(reset_controller_unregister);
151174

@@ -322,6 +345,7 @@ static inline bool reset_control_is_array(struct reset_control *rstc)
322345
*/
323346
int reset_control_reset(struct reset_control *rstc)
324347
{
348+
struct reset_controller_dev *rcdev;
325349
int ret;
326350

327351
if (!rstc)
@@ -333,7 +357,13 @@ int reset_control_reset(struct reset_control *rstc)
333357
if (reset_control_is_array(rstc))
334358
return reset_control_array_reset(rstc_to_array(rstc));
335359

336-
if (!rstc->rcdev->ops->reset)
360+
guard(srcu)(&rstc->srcu);
361+
362+
rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu);
363+
if (!rcdev)
364+
return -ENODEV;
365+
366+
if (!rcdev->ops->reset)
337367
return -ENOTSUPP;
338368

339369
if (rstc->shared) {
@@ -347,7 +377,7 @@ int reset_control_reset(struct reset_control *rstc)
347377
return -EPERM;
348378
}
349379

350-
ret = rstc->rcdev->ops->reset(rstc->rcdev, rstc->id);
380+
ret = rcdev->ops->reset(rcdev, rstc->id);
351381
if (rstc->shared && ret)
352382
atomic_dec(&rstc->triggered_count);
353383

@@ -437,6 +467,8 @@ EXPORT_SYMBOL_GPL(reset_control_rearm);
437467
*/
438468
int reset_control_assert(struct reset_control *rstc)
439469
{
470+
struct reset_controller_dev *rcdev;
471+
440472
if (!rstc)
441473
return 0;
442474

@@ -446,6 +478,12 @@ int reset_control_assert(struct reset_control *rstc)
446478
if (reset_control_is_array(rstc))
447479
return reset_control_array_assert(rstc_to_array(rstc));
448480

481+
guard(srcu)(&rstc->srcu);
482+
483+
rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu);
484+
if (!rcdev)
485+
return -ENODEV;
486+
449487
if (rstc->shared) {
450488
if (WARN_ON(atomic_read(&rstc->triggered_count) != 0))
451489
return -EINVAL;
@@ -460,25 +498,25 @@ int reset_control_assert(struct reset_control *rstc)
460498
* Shared reset controls allow the reset line to be in any state
461499
* after this call, so doing nothing is a valid option.
462500
*/
463-
if (!rstc->rcdev->ops->assert)
501+
if (!rcdev->ops->assert)
464502
return 0;
465503
} else {
466504
/*
467505
* If the reset controller does not implement .assert(), there
468506
* is no way to guarantee that the reset line is asserted after
469507
* this call.
470508
*/
471-
if (!rstc->rcdev->ops->assert)
509+
if (!rcdev->ops->assert)
472510
return -ENOTSUPP;
473511

474512
if (!rstc->acquired) {
475513
WARN(1, "reset %s (ID: %u) is not acquired\n",
476-
rcdev_name(rstc->rcdev), rstc->id);
514+
rcdev_name(rcdev), rstc->id);
477515
return -EPERM;
478516
}
479517
}
480518

481-
return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);
519+
return rcdev->ops->assert(rcdev, rstc->id);
482520
}
483521
EXPORT_SYMBOL_GPL(reset_control_assert);
484522

@@ -525,6 +563,8 @@ EXPORT_SYMBOL_GPL(reset_control_bulk_assert);
525563
*/
526564
int reset_control_deassert(struct reset_control *rstc)
527565
{
566+
struct reset_controller_dev *rcdev;
567+
528568
if (!rstc)
529569
return 0;
530570

@@ -534,6 +574,12 @@ int reset_control_deassert(struct reset_control *rstc)
534574
if (reset_control_is_array(rstc))
535575
return reset_control_array_deassert(rstc_to_array(rstc));
536576

577+
guard(srcu)(&rstc->srcu);
578+
579+
rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu);
580+
if (!rcdev)
581+
return -ENODEV;
582+
537583
if (rstc->shared) {
538584
if (WARN_ON(atomic_read(&rstc->triggered_count) != 0))
539585
return -EINVAL;
@@ -543,7 +589,7 @@ int reset_control_deassert(struct reset_control *rstc)
543589
} else {
544590
if (!rstc->acquired) {
545591
WARN(1, "reset %s (ID: %u) is not acquired\n",
546-
rcdev_name(rstc->rcdev), rstc->id);
592+
rcdev_name(rcdev), rstc->id);
547593
return -EPERM;
548594
}
549595
}
@@ -555,10 +601,10 @@ int reset_control_deassert(struct reset_control *rstc)
555601
* case, the reset controller driver should implement .deassert() and
556602
* return -ENOTSUPP.
557603
*/
558-
if (!rstc->rcdev->ops->deassert)
604+
if (!rcdev->ops->deassert)
559605
return 0;
560606

561-
return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
607+
return rcdev->ops->deassert(rcdev, rstc->id);
562608
}
563609
EXPORT_SYMBOL_GPL(reset_control_deassert);
564610

@@ -600,14 +646,22 @@ EXPORT_SYMBOL_GPL(reset_control_bulk_deassert);
600646
*/
601647
int reset_control_status(struct reset_control *rstc)
602648
{
649+
struct reset_controller_dev *rcdev;
650+
603651
if (!rstc)
604652
return 0;
605653

606654
if (WARN_ON(IS_ERR(rstc)) || reset_control_is_array(rstc))
607655
return -EINVAL;
608656

609-
if (rstc->rcdev->ops->status)
610-
return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
657+
guard(srcu)(&rstc->srcu);
658+
659+
rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu);
660+
if (!rcdev)
661+
return -ENODEV;
662+
663+
if (rcdev->ops->status)
664+
return rcdev->ops->status(rcdev, rstc->id);
611665

612666
return -ENOTSUPP;
613667
}
@@ -635,6 +689,7 @@ EXPORT_SYMBOL_GPL(reset_control_status);
635689
*/
636690
int reset_control_acquire(struct reset_control *rstc)
637691
{
692+
struct reset_controller_dev *rcdev;
638693
struct reset_control *rc;
639694

640695
if (!rstc)
@@ -651,7 +706,13 @@ int reset_control_acquire(struct reset_control *rstc)
651706
if (rstc->acquired)
652707
return 0;
653708

654-
list_for_each_entry(rc, &rstc->rcdev->reset_control_head, list) {
709+
guard(srcu)(&rstc->srcu);
710+
711+
rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu);
712+
if (!rcdev)
713+
return -ENODEV;
714+
715+
list_for_each_entry(rc, &rcdev->reset_control_head, list) {
655716
if (rstc != rc && rstc->id == rc->id) {
656717
if (rc->acquired)
657718
return -EBUSY;
@@ -743,6 +804,7 @@ __reset_control_get_internal(struct reset_controller_dev *rcdev,
743804
bool shared = flags & RESET_CONTROL_FLAGS_BIT_SHARED;
744805
bool acquired = flags & RESET_CONTROL_FLAGS_BIT_ACQUIRED;
745806
struct reset_control *rstc;
807+
int ret;
746808

747809
lockdep_assert_held(&reset_list_mutex);
748810

@@ -773,12 +835,19 @@ __reset_control_get_internal(struct reset_controller_dev *rcdev,
773835
if (!rstc)
774836
return ERR_PTR(-ENOMEM);
775837

838+
ret = init_srcu_struct(&rstc->srcu);
839+
if (ret) {
840+
kfree(rstc);
841+
return ERR_PTR(ret);
842+
}
843+
776844
if (!try_module_get(rcdev->owner)) {
845+
cleanup_srcu_struct(&rstc->srcu);
777846
kfree(rstc);
778847
return ERR_PTR(-ENODEV);
779848
}
780849

781-
rstc->rcdev = rcdev;
850+
rcu_assign_pointer(rstc->rcdev, rcdev);
782851
list_add(&rstc->list, &rcdev->reset_control_head);
783852
rstc->id = index;
784853
kref_init(&rstc->refcnt);
@@ -793,13 +862,18 @@ static void __reset_control_release(struct kref *kref)
793862
{
794863
struct reset_control *rstc = container_of(kref, struct reset_control,
795864
refcnt);
865+
struct reset_controller_dev *rcdev;
796866

797867
lockdep_assert_held(&reset_list_mutex);
798868

799-
module_put(rstc->rcdev->owner);
869+
scoped_guard(srcu, &rstc->srcu) {
870+
rcdev = rcu_replace_pointer(rstc->rcdev, NULL, true);
871+
if (rcdev)
872+
reset_controller_remove(rcdev, rstc);
873+
}
800874

801-
list_del(&rstc->list);
802-
put_device(rstc->rcdev->dev);
875+
synchronize_srcu(&rstc->srcu);
876+
cleanup_srcu_struct(&rstc->srcu);
803877
kfree(rstc);
804878
}
805879

0 commit comments

Comments
 (0)