Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Bartosz Golaszewski and committed by
Philipp Zabel
78ebbff6 1f10008a

+91 -17
+91 -17
drivers/reset/core.c
··· 23 23 #include <linux/reset.h> 24 24 #include <linux/reset-controller.h> 25 25 #include <linux/slab.h> 26 + #include <linux/srcu.h> 26 27 27 28 static DEFINE_MUTEX(reset_list_mutex); 28 29 static LIST_HEAD(reset_controller_list); ··· 37 36 * struct reset_control - a reset control 38 37 * @rcdev: a pointer to the reset controller device 39 38 * this reset control belongs to 39 + * @srcu: protects the rcdev pointer from removal during consumer access 40 40 * @list: list entry for the rcdev's reset controller list 41 41 * @id: ID of the reset controller in the reset 42 42 * controller device ··· 51 49 * will be either 0 or 1. 52 50 */ 53 51 struct reset_control { 54 - struct reset_controller_dev *rcdev; 52 + struct reset_controller_dev __rcu *rcdev; 53 + struct srcu_struct srcu; 55 54 struct list_head list; 56 55 unsigned int id; 57 56 struct kref refcnt; ··· 140 137 } 141 138 EXPORT_SYMBOL_GPL(reset_controller_register); 142 139 140 + static void reset_controller_remove(struct reset_controller_dev *rcdev, 141 + struct reset_control *rstc) 142 + { 143 + list_del(&rstc->list); 144 + module_put(rcdev->owner); 145 + put_device(rcdev->dev); 146 + } 147 + 143 148 /** 144 149 * reset_controller_unregister - unregister a reset controller device 145 150 * @rcdev: a pointer to the reset controller device 146 151 */ 147 152 void reset_controller_unregister(struct reset_controller_dev *rcdev) 148 153 { 154 + struct reset_control *rstc, *pos; 155 + 149 156 guard(mutex)(&reset_list_mutex); 150 157 151 158 list_del(&rcdev->list); 159 + 160 + /* 161 + * Numb but don't free the remaining reset control handles that are 162 + * still held by consumers. 163 + */ 164 + list_for_each_entry_safe(rstc, pos, &rcdev->reset_control_head, list) { 165 + rcu_assign_pointer(rstc->rcdev, NULL); 166 + synchronize_srcu(&rstc->srcu); 167 + reset_controller_remove(rcdev, rstc); 168 + } 152 169 } 153 170 EXPORT_SYMBOL_GPL(reset_controller_unregister); 154 171 ··· 345 322 */ 346 323 int reset_control_reset(struct reset_control *rstc) 347 324 { 325 + struct reset_controller_dev *rcdev; 348 326 int ret; 349 327 350 328 if (!rstc) ··· 357 333 if (reset_control_is_array(rstc)) 358 334 return reset_control_array_reset(rstc_to_array(rstc)); 359 335 360 - if (!rstc->rcdev->ops->reset) 336 + guard(srcu)(&rstc->srcu); 337 + 338 + rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu); 339 + if (!rcdev) 340 + return -ENODEV; 341 + 342 + if (!rcdev->ops->reset) 361 343 return -ENOTSUPP; 362 344 363 345 if (rstc->shared) { ··· 377 347 return -EPERM; 378 348 } 379 349 380 - ret = rstc->rcdev->ops->reset(rstc->rcdev, rstc->id); 350 + ret = rcdev->ops->reset(rcdev, rstc->id); 381 351 if (rstc->shared && ret) 382 352 atomic_dec(&rstc->triggered_count); 383 353 ··· 467 437 */ 468 438 int reset_control_assert(struct reset_control *rstc) 469 439 { 440 + struct reset_controller_dev *rcdev; 441 + 470 442 if (!rstc) 471 443 return 0; 472 444 ··· 477 445 478 446 if (reset_control_is_array(rstc)) 479 447 return reset_control_array_assert(rstc_to_array(rstc)); 448 + 449 + guard(srcu)(&rstc->srcu); 450 + 451 + rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu); 452 + if (!rcdev) 453 + return -ENODEV; 480 454 481 455 if (rstc->shared) { 482 456 if (WARN_ON(atomic_read(&rstc->triggered_count) != 0)) ··· 498 460 * Shared reset controls allow the reset line to be in any state 499 461 * after this call, so doing nothing is a valid option. 500 462 */ 501 - if (!rstc->rcdev->ops->assert) 463 + if (!rcdev->ops->assert) 502 464 return 0; 503 465 } else { 504 466 /* ··· 506 468 * is no way to guarantee that the reset line is asserted after 507 469 * this call. 508 470 */ 509 - if (!rstc->rcdev->ops->assert) 471 + if (!rcdev->ops->assert) 510 472 return -ENOTSUPP; 511 473 512 474 if (!rstc->acquired) { 513 475 WARN(1, "reset %s (ID: %u) is not acquired\n", 514 - rcdev_name(rstc->rcdev), rstc->id); 476 + rcdev_name(rcdev), rstc->id); 515 477 return -EPERM; 516 478 } 517 479 } 518 480 519 - return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id); 481 + return rcdev->ops->assert(rcdev, rstc->id); 520 482 } 521 483 EXPORT_SYMBOL_GPL(reset_control_assert); 522 484 ··· 563 525 */ 564 526 int reset_control_deassert(struct reset_control *rstc) 565 527 { 528 + struct reset_controller_dev *rcdev; 529 + 566 530 if (!rstc) 567 531 return 0; 568 532 ··· 573 533 574 534 if (reset_control_is_array(rstc)) 575 535 return reset_control_array_deassert(rstc_to_array(rstc)); 536 + 537 + guard(srcu)(&rstc->srcu); 538 + 539 + rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu); 540 + if (!rcdev) 541 + return -ENODEV; 576 542 577 543 if (rstc->shared) { 578 544 if (WARN_ON(atomic_read(&rstc->triggered_count) != 0)) ··· 589 543 } else { 590 544 if (!rstc->acquired) { 591 545 WARN(1, "reset %s (ID: %u) is not acquired\n", 592 - rcdev_name(rstc->rcdev), rstc->id); 546 + rcdev_name(rcdev), rstc->id); 593 547 return -EPERM; 594 548 } 595 549 } ··· 601 555 * case, the reset controller driver should implement .deassert() and 602 556 * return -ENOTSUPP. 603 557 */ 604 - if (!rstc->rcdev->ops->deassert) 558 + if (!rcdev->ops->deassert) 605 559 return 0; 606 560 607 - return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id); 561 + return rcdev->ops->deassert(rcdev, rstc->id); 608 562 } 609 563 EXPORT_SYMBOL_GPL(reset_control_deassert); 610 564 ··· 646 600 */ 647 601 int reset_control_status(struct reset_control *rstc) 648 602 { 603 + struct reset_controller_dev *rcdev; 604 + 649 605 if (!rstc) 650 606 return 0; 651 607 652 608 if (WARN_ON(IS_ERR(rstc)) || reset_control_is_array(rstc)) 653 609 return -EINVAL; 654 610 655 - if (rstc->rcdev->ops->status) 656 - return rstc->rcdev->ops->status(rstc->rcdev, rstc->id); 611 + guard(srcu)(&rstc->srcu); 612 + 613 + rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu); 614 + if (!rcdev) 615 + return -ENODEV; 616 + 617 + if (rcdev->ops->status) 618 + return rcdev->ops->status(rcdev, rstc->id); 657 619 658 620 return -ENOTSUPP; 659 621 } ··· 689 635 */ 690 636 int reset_control_acquire(struct reset_control *rstc) 691 637 { 638 + struct reset_controller_dev *rcdev; 692 639 struct reset_control *rc; 693 640 694 641 if (!rstc) ··· 706 651 if (rstc->acquired) 707 652 return 0; 708 653 709 - list_for_each_entry(rc, &rstc->rcdev->reset_control_head, list) { 654 + guard(srcu)(&rstc->srcu); 655 + 656 + rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu); 657 + if (!rcdev) 658 + return -ENODEV; 659 + 660 + list_for_each_entry(rc, &rcdev->reset_control_head, list) { 710 661 if (rstc != rc && rstc->id == rc->id) { 711 662 if (rc->acquired) 712 663 return -EBUSY; ··· 804 743 bool shared = flags & RESET_CONTROL_FLAGS_BIT_SHARED; 805 744 bool acquired = flags & RESET_CONTROL_FLAGS_BIT_ACQUIRED; 806 745 struct reset_control *rstc; 746 + int ret; 807 747 808 748 lockdep_assert_held(&reset_list_mutex); 809 749 ··· 835 773 if (!rstc) 836 774 return ERR_PTR(-ENOMEM); 837 775 776 + ret = init_srcu_struct(&rstc->srcu); 777 + if (ret) { 778 + kfree(rstc); 779 + return ERR_PTR(ret); 780 + } 781 + 838 782 if (!try_module_get(rcdev->owner)) { 783 + cleanup_srcu_struct(&rstc->srcu); 839 784 kfree(rstc); 840 785 return ERR_PTR(-ENODEV); 841 786 } 842 787 843 - rstc->rcdev = rcdev; 788 + rcu_assign_pointer(rstc->rcdev, rcdev); 844 789 list_add(&rstc->list, &rcdev->reset_control_head); 845 790 rstc->id = index; 846 791 kref_init(&rstc->refcnt); ··· 862 793 { 863 794 struct reset_control *rstc = container_of(kref, struct reset_control, 864 795 refcnt); 796 + struct reset_controller_dev *rcdev; 865 797 866 798 lockdep_assert_held(&reset_list_mutex); 867 799 868 - module_put(rstc->rcdev->owner); 800 + scoped_guard(srcu, &rstc->srcu) { 801 + rcdev = rcu_replace_pointer(rstc->rcdev, NULL, true); 802 + if (rcdev) 803 + reset_controller_remove(rcdev, rstc); 804 + } 869 805 870 - list_del(&rstc->list); 871 - put_device(rstc->rcdev->dev); 806 + synchronize_srcu(&rstc->srcu); 807 + cleanup_srcu_struct(&rstc->srcu); 872 808 kfree(rstc); 873 809 } 874 810