From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BE13A361673 for ; Mon, 23 Feb 2026 10:06:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771841209; cv=none; b=U04yZKDPiqa/MTxNIiXYOpwxADuS0XknJmwDmc87VMsAAijKtIOs3kIng5wPXEJn268JEm2vUKoxyfGVo4ug26A88GtWYRuREXSm793I0PWohp0wnwSqNP90EzCpbLaPsbFE1Op8v0tv/MBY0+V/WjmGetPIfQWWE3ba6hUOVzM= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771841209; c=relaxed/simple; bh=sL1q9wwhxHZZrZlh7F46CRESH8uPDctEF3AFiujRX4A=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=JFlU/X5+sJwtamm6e6w3ZJRzNER7hTodeD3H28vod62qFB6wHSajyJKH+Euo5+LL6Gzoe2srVUwrm8IKMRbeuSBEKLQ590l7InbLgtYmcCpyIbeQhnvkis4J662yawC0n9awjUXzIk7o78RlgSBUfVO+ao/qvtgQLa3XJa3OwGE= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=Hl2PJO8R; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=gEmBasKs; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="Hl2PJO8R"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="gEmBasKs" Received: from pps.filterd (m0279870.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 61N0ka5d3271586 for ; Mon, 23 Feb 2026 10:06:47 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= fazAAiBrJ7rgJoOI1TWI0OtZrQogm6Eto7WktTDuRyg=; b=Hl2PJO8R9rWsQhpn ustIOEqAX79kepy7bCT+lNDkn2o1MbOgygdEegjqyxqbW+9k/cLr1psUeYqtytEe IKrr5R1nMOFjRin9oRNKvCcRIj0gnTurV48/g79kWZqH5AZKf+ARN80a2oebsoYi 3T+VPyYmKQbUzQIt3oOf2sKZNRC9JVrOK5uH5haUdau9qVAqy+yQFh3rfDFm1PcX SXkiIW8L4Z5zDVoF4kNFoiKNDsSKhZR52mYIqm867vNWrXNcpCscfwa5F97uLITw MdBSV0mVkW8ZR0DdlAOFe4gOt3Gy1mQk3qLUIsNHO8ateCVyb6RbldGZinJZSO8U g9AoQA== Received: from mail-qk1-f200.google.com (mail-qk1-f200.google.com [209.85.222.200]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4cf5vj47np-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Mon, 23 Feb 2026 10:06:46 +0000 (GMT) Received: by mail-qk1-f200.google.com with SMTP id af79cd13be357-8ca3ef536ddso5137105085a.0 for ; Mon, 23 Feb 2026 02:06:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1771841206; x=1772446006; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=fazAAiBrJ7rgJoOI1TWI0OtZrQogm6Eto7WktTDuRyg=; b=gEmBasKsnPn+6VukHwJVGaJOX5rOYnUH8rG9nnMcR/oEFdTPVgcejPfKQlrBaWpadU xfB6Bm9Vo0sxBaHaFEj6ogYrNLqPivbtdT/AwcdqqefQQCxB3DdPIThqjkeJ0mEK2M7i 2inexGzxLO08YqnPsT22Q4HpP51rt7cDrqpqRfbdidDRiQ7A0EEX/ol29VqNzbVva3Rv ORrIWtMxVm7YlrK0KXZ/RZHJ6ABtLZKhn8/jgDLSmAAV/EoUDJyZfH3UxD6tyFWl5ylC tg5mXGi6dNIA0aiPLO4t8+JC5FFnXOco71hJMtzOuUkuwhPVEQtYhzzHkGWb9NITR7g5 rZjA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771841206; x=1772446006; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=fazAAiBrJ7rgJoOI1TWI0OtZrQogm6Eto7WktTDuRyg=; b=Oz6NAghh69LFUhJfcUNzDq3HmxZBUaRgR1y62JmJ5JgEdu8+i9GSRdcZvvCMfVi+FF 5rPF90Jv+0S3pO+BkFh4gUKsBToHrR5TfoeWAELiwIzOr2nt0QJ4WMFfHnX8Bl1+sMqQ TqWcpQz2Qs6f8ZmWwIlykKBdeRC6AMTIa2nJLeZ0fBlbGEilRqk7MT0Ax7mSqlnNXKMF GdTgN24jzVx72Z2pRvktRZeKeLp0w6KO3OxHZDPNbv1ZzdzWfU45EwREssUg8qVHTAIb c1FOieHE9pZy/1TiD1gLKfzV6/s1dhZs62MFYW01w67z9kk3Fn/nHD715dfO+L3dDQO4 Dl0A== X-Gm-Message-State: AOJu0YwKZZyRK6hgIzeZQGqij0+ijsEfI6YyQlybRQrxn/VLlT16XMxJ EOpMAyaW5Lkf2hG0OL8rg3VqGV1VGkIgKuKMk7enQsbVleR5IBpUrIOmYLPgEgAM1dKdO10kxQS U0URq4YfthjpW+vjKFoCvhofK1+TlLUsqBCyf0SWDD3LJ4oDarORN+BG8A2sgf2wmic8= X-Gm-Gg: AZuq6aK8/LnmUv5M2qX5KYM+39fZVYwPrahfKVhJSb+qW8bm/irXGEJ82Oo5NpXYGSj Zky5qAdqBqH/EwVLPD0aQ6QsGiTiML+wYskWttZfN7ArghfqGU7W7eaiQFDV4WJwJq/9Ea7In1u jTxvtoaEZstUYo9XcS9R+ODOYD14sTYPsm+g0RXG68iYbw816ifs0weRQaUNYHXHFP1PxXBVPlg fecOa4hzFjKvew6nF5L18OCNVFl4IGkr1mw5T+d9FMVvMzNT51WvTy71LbmItmZsHw9+swvutg+ q51Lz98aR4N+KfHnKfe+wMYtWlymlxoRvIMB6dq194JNhiEpC4jxAD5E+WZinIcYr6FCduq0J5y 3sdtsIx3wI+hy0dzVI5IZspmQ97CkISnWEQZebLv01IE56WE6WWBH X-Received: by 2002:a05:620a:28c3:b0:8b2:f2c5:e7f6 with SMTP id af79cd13be357-8cb8ca65f56mr941515985a.37.1771841206174; Mon, 23 Feb 2026 02:06:46 -0800 (PST) X-Received: by 2002:a05:620a:28c3:b0:8b2:f2c5:e7f6 with SMTP id af79cd13be357-8cb8ca65f56mr941513285a.37.1771841205652; Mon, 23 Feb 2026 02:06:45 -0800 (PST) Received: from brgl-qcom.local ([2a01:cb1d:dc:7e00:bd71:422c:5e83:8b37]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43970d54760sm18288885f8f.35.2026.02.23.02.06.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Feb 2026 02:06:45 -0800 (PST) From: Bartosz Golaszewski Date: Mon, 23 Feb 2026 11:06:21 +0100 Subject: [PATCH v2 08/14] reset: handle removing supplier before consumers Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260223-reset-core-refactor-v2-8-5e5a7289190c@oss.qualcomm.com> References: <20260223-reset-core-refactor-v2-0-5e5a7289190c@oss.qualcomm.com> In-Reply-To: <20260223-reset-core-refactor-v2-0-5e5a7289190c@oss.qualcomm.com> To: Krzysztof Kozlowski , Philipp Zabel Cc: linux-kernel@vger.kernel.org, Bartosz Golaszewski X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=10031; i=bartosz.golaszewski@oss.qualcomm.com; h=from:subject:message-id; bh=sL1q9wwhxHZZrZlh7F46CRESH8uPDctEF3AFiujRX4A=; b=owEBbQKS/ZANAwAKAQWdLsv/NoTDAcsmYgBpnCantW9jF1Qf4GiKFMRfo7cmpDuFo+/otKKhl SWkitJGeAuJAjMEAAEKAB0WIQSR5RMt5bVGHXuiZfwFnS7L/zaEwwUCaZwmpwAKCRAFnS7L/zaE w/c1D/0TcGdkNiV3LY34U3o+ivXFRX6SlB2YnAJoBh9UGnFBrEB6ELX7b5AMQA7+7Gsxw/nrekX iA2U/BbcZBS164KERKHAk2DGO5djPxXIg1EhLPvJPC/Ri185Ej5wSXhBj5p/i3EWfx0r/b6Ht/3 YcLncT5r0qFmQBJGkbvEcyGzbKYEv7NaARAEdE4gJ/Nm4SmbxQWJB1D7ft2ym+0q5ntSGJTorHp 7hBQZOW8RxsVakJz5opua97D5UZgn6TCuf+5pu+Od2X0yoq26AF9AXlWszVt1JfLM4Tig8Oy5jk 0+KiCZ/b7EEgcN2sKlDfKcip9IymZmvomm1uCFdnG5RGXVbu9fhl1BbpBQNaZZvvpFUhxKWVwj1 RYLUR4CNqRy2SO18ftuDdXb1ihCLZkeEgEExGIROmY7N/v0lmzMOeqmXZNjeRu2t+szAiN0JrOV SEHIvC8UhCVChZsrWLw/k1fv0VZc3q/G6TGsR5/Is84/onFxNaLi8FCOb7KX2ZbQ5slNRh8qYF/ GbRhLuUK+IH5k8avCMfY1ZJbCchIR3rZDxGdH2WBQNgQ92IzMKycD/0zIkPzRiSLtA4dv5nkiDe aGYj96I4WlQlde1piLjaXInZxhajsbRBd7Ibjn0LQkssXN4D6FzTm0J3A8nES1V7dOUx0BK3oi2 PdXfMHy2t74hpKQ== X-Developer-Key: i=bartosz.golaszewski@oss.qualcomm.com; a=openpgp; fpr=169DEB6C0BC3C46013D2C79F11A72EA01471D772 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjIzMDA4NiBTYWx0ZWRfX11PrKfOj7z4y P5eqzcStJjeN0TKACUIskvt56k2UuTqIK4+HV3oDC/IDOW58XDoKbqZAP0Iitj4o6mEJFzcC9Ca 7ZTM6JM79EUdBPSJ3NijgvfOdyYvpKLlYwmotB0mPRGqYV0PXSmaUdIGePxzw1f4pNszceEYGS2 YK0YCpe3+wXjr6CJxnKHl61FuHkyFg5n6QZrwN3ZZ88F1GLywzVHtWLymEYBG+9L9fhk2hQ8cCP 1FVwKnLMh3xJAyc3E+tLxoNPvRi77F3D+Fw8H5zUA5Tv0WItJXcavMmYPQjXDa15mtc9kfS2lJV IV0Zsijntb4+ZftTgDFl41txJl0DtulWM0RoWb6Zhwr/j8UHCozxzUU5uzp6gMZH+34+GXvR4QL g1upfh3wi3CHSwxmGiOYFJ1+E5DH7tqjHBQZvKGvT6jaczT60cg1lSxd+PFG2thtVqkmEcj1zPJ d57NCO+8fRqSNWRLnww== X-Authority-Analysis: v=2.4 cv=T5KBjvKQ c=1 sm=1 tr=0 ts=699c26b6 cx=c_pps a=hnmNkyzTK/kJ09Xio7VxxA==:117 a=xqWC_Br6kY4A:10 a=IkcTkHD0fZMA:10 a=HzLeVaNsDn8A:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=gowsoOTTUOVcmtlkKump:22 a=EUspDBNiAAAA:8 a=GiwafSNXLQ0EgbbDNmMA:9 a=QEXdDO2ut3YA:10 a=PEH46H7Ffwr30OY-TuGO:22 X-Proofpoint-GUID: 9mLKEHjtKP9XPs9qldPn_HmDGvu30lDw X-Proofpoint-ORIG-GUID: 9mLKEHjtKP9XPs9qldPn_HmDGvu30lDw X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-02-23_02,2026-02-20_04,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 spamscore=0 malwarescore=0 priorityscore=1501 clxscore=1015 phishscore=0 lowpriorityscore=0 adultscore=0 impostorscore=0 bulkscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2602130000 definitions=main-2602230086 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 --- drivers/reset/core.c | 108 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 91 insertions(+), 17 deletions(-) diff --git a/drivers/reset/core.c b/drivers/reset/core.c index 9fef9f972e93fb7388f27ac3bbdf68c884b72ff5..96199e7b0dd7c89c5a11e2e2c3e5eb7fd5d49355 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -23,6 +23,7 @@ #include #include #include +#include static DEFINE_MUTEX(reset_list_mutex); static LIST_HEAD(reset_controller_list); @@ -36,6 +37,7 @@ static DEFINE_IDA(reset_gpio_ida); * struct reset_control - a reset control * @rcdev: a pointer to the reset controller device * this reset control belongs to + * @srcu: protects the rcdev pointer from removal during consumer access * @list: list entry for the rcdev's reset controller list * @id: ID of the reset controller in the reset * controller device @@ -49,7 +51,8 @@ static DEFINE_IDA(reset_gpio_ida); * will be either 0 or 1. */ struct reset_control { - struct reset_controller_dev *rcdev; + struct reset_controller_dev __rcu *rcdev; + struct srcu_struct srcu; struct list_head list; unsigned int id; struct kref refcnt; @@ -137,15 +140,35 @@ int reset_controller_register(struct reset_controller_dev *rcdev) } EXPORT_SYMBOL_GPL(reset_controller_register); +static void reset_controller_remove(struct reset_controller_dev *rcdev, + struct reset_control *rstc) +{ + list_del(&rstc->list); + module_put(rcdev->owner); + put_device(rcdev->dev); +} + /** * reset_controller_unregister - unregister a reset controller device * @rcdev: a pointer to the reset controller device */ void reset_controller_unregister(struct reset_controller_dev *rcdev) { + struct reset_control *rstc, *pos; + guard(mutex)(&reset_list_mutex); list_del(&rcdev->list); + + /* + * Numb but don't free the remaining reset control handles that are + * still held by consumers. + */ + list_for_each_entry_safe(rstc, pos, &rcdev->reset_control_head, list) { + rcu_assign_pointer(rstc->rcdev, NULL); + synchronize_srcu(&rstc->srcu); + reset_controller_remove(rcdev, rstc); + } } EXPORT_SYMBOL_GPL(reset_controller_unregister); @@ -322,6 +345,7 @@ static inline bool reset_control_is_array(struct reset_control *rstc) */ int reset_control_reset(struct reset_control *rstc) { + struct reset_controller_dev *rcdev; int ret; if (!rstc) @@ -333,7 +357,13 @@ int reset_control_reset(struct reset_control *rstc) if (reset_control_is_array(rstc)) return reset_control_array_reset(rstc_to_array(rstc)); - if (!rstc->rcdev->ops->reset) + guard(srcu)(&rstc->srcu); + + rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu); + if (!rcdev) + return -ENODEV; + + if (!rcdev->ops->reset) return -ENOTSUPP; if (rstc->shared) { @@ -347,7 +377,7 @@ int reset_control_reset(struct reset_control *rstc) return -EPERM; } - ret = rstc->rcdev->ops->reset(rstc->rcdev, rstc->id); + ret = rcdev->ops->reset(rcdev, rstc->id); if (rstc->shared && ret) atomic_dec(&rstc->triggered_count); @@ -437,6 +467,8 @@ EXPORT_SYMBOL_GPL(reset_control_rearm); */ int reset_control_assert(struct reset_control *rstc) { + struct reset_controller_dev *rcdev; + if (!rstc) return 0; @@ -446,6 +478,12 @@ int reset_control_assert(struct reset_control *rstc) if (reset_control_is_array(rstc)) return reset_control_array_assert(rstc_to_array(rstc)); + guard(srcu)(&rstc->srcu); + + rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu); + if (!rcdev) + return -ENODEV; + if (rstc->shared) { if (WARN_ON(atomic_read(&rstc->triggered_count) != 0)) return -EINVAL; @@ -460,7 +498,7 @@ int reset_control_assert(struct reset_control *rstc) * Shared reset controls allow the reset line to be in any state * after this call, so doing nothing is a valid option. */ - if (!rstc->rcdev->ops->assert) + if (!rcdev->ops->assert) return 0; } else { /* @@ -468,17 +506,17 @@ int reset_control_assert(struct reset_control *rstc) * is no way to guarantee that the reset line is asserted after * this call. */ - if (!rstc->rcdev->ops->assert) + if (!rcdev->ops->assert) return -ENOTSUPP; if (!rstc->acquired) { WARN(1, "reset %s (ID: %u) is not acquired\n", - rcdev_name(rstc->rcdev), rstc->id); + rcdev_name(rcdev), rstc->id); return -EPERM; } } - return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id); + return rcdev->ops->assert(rcdev, rstc->id); } EXPORT_SYMBOL_GPL(reset_control_assert); @@ -525,6 +563,8 @@ EXPORT_SYMBOL_GPL(reset_control_bulk_assert); */ int reset_control_deassert(struct reset_control *rstc) { + struct reset_controller_dev *rcdev; + if (!rstc) return 0; @@ -534,6 +574,12 @@ int reset_control_deassert(struct reset_control *rstc) if (reset_control_is_array(rstc)) return reset_control_array_deassert(rstc_to_array(rstc)); + guard(srcu)(&rstc->srcu); + + rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu); + if (!rcdev) + return -ENODEV; + if (rstc->shared) { if (WARN_ON(atomic_read(&rstc->triggered_count) != 0)) return -EINVAL; @@ -543,7 +589,7 @@ int reset_control_deassert(struct reset_control *rstc) } else { if (!rstc->acquired) { WARN(1, "reset %s (ID: %u) is not acquired\n", - rcdev_name(rstc->rcdev), rstc->id); + rcdev_name(rcdev), rstc->id); return -EPERM; } } @@ -555,10 +601,10 @@ int reset_control_deassert(struct reset_control *rstc) * case, the reset controller driver should implement .deassert() and * return -ENOTSUPP. */ - if (!rstc->rcdev->ops->deassert) + if (!rcdev->ops->deassert) return 0; - return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id); + return rcdev->ops->deassert(rcdev, rstc->id); } EXPORT_SYMBOL_GPL(reset_control_deassert); @@ -600,14 +646,22 @@ EXPORT_SYMBOL_GPL(reset_control_bulk_deassert); */ int reset_control_status(struct reset_control *rstc) { + struct reset_controller_dev *rcdev; + if (!rstc) return 0; if (WARN_ON(IS_ERR(rstc)) || reset_control_is_array(rstc)) return -EINVAL; - if (rstc->rcdev->ops->status) - return rstc->rcdev->ops->status(rstc->rcdev, rstc->id); + guard(srcu)(&rstc->srcu); + + rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu); + if (!rcdev) + return -ENODEV; + + if (rcdev->ops->status) + return rcdev->ops->status(rcdev, rstc->id); return -ENOTSUPP; } @@ -635,6 +689,7 @@ EXPORT_SYMBOL_GPL(reset_control_status); */ int reset_control_acquire(struct reset_control *rstc) { + struct reset_controller_dev *rcdev; struct reset_control *rc; if (!rstc) @@ -651,7 +706,13 @@ int reset_control_acquire(struct reset_control *rstc) if (rstc->acquired) return 0; - list_for_each_entry(rc, &rstc->rcdev->reset_control_head, list) { + guard(srcu)(&rstc->srcu); + + rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu); + if (!rcdev) + return -ENODEV; + + list_for_each_entry(rc, &rcdev->reset_control_head, list) { if (rstc != rc && rstc->id == rc->id) { if (rc->acquired) return -EBUSY; @@ -743,6 +804,7 @@ __reset_control_get_internal(struct reset_controller_dev *rcdev, bool shared = flags & RESET_CONTROL_FLAGS_BIT_SHARED; bool acquired = flags & RESET_CONTROL_FLAGS_BIT_ACQUIRED; struct reset_control *rstc; + int ret; lockdep_assert_held(&reset_list_mutex); @@ -773,12 +835,19 @@ __reset_control_get_internal(struct reset_controller_dev *rcdev, if (!rstc) return ERR_PTR(-ENOMEM); + ret = init_srcu_struct(&rstc->srcu); + if (ret) { + kfree(rstc); + return ERR_PTR(ret); + } + if (!try_module_get(rcdev->owner)) { + cleanup_srcu_struct(&rstc->srcu); kfree(rstc); return ERR_PTR(-ENODEV); } - rstc->rcdev = rcdev; + rcu_assign_pointer(rstc->rcdev, rcdev); list_add(&rstc->list, &rcdev->reset_control_head); rstc->id = index; kref_init(&rstc->refcnt); @@ -793,13 +862,18 @@ static void __reset_control_release(struct kref *kref) { struct reset_control *rstc = container_of(kref, struct reset_control, refcnt); + struct reset_controller_dev *rcdev; lockdep_assert_held(&reset_list_mutex); - module_put(rstc->rcdev->owner); + scoped_guard(srcu, &rstc->srcu) { + rcdev = rcu_replace_pointer(rstc->rcdev, NULL, true); + if (rcdev) + reset_controller_remove(rcdev, rstc); + } - list_del(&rstc->list); - put_device(rstc->rcdev->dev); + synchronize_srcu(&rstc->srcu); + cleanup_srcu_struct(&rstc->srcu); kfree(rstc); } -- 2.47.3