From nobody Mon Jun 8 05:24:51 2026 Received: from mail-106111.protonmail.ch (mail-106111.protonmail.ch [79.135.106.111]) (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 E80C4358D37 for ; Fri, 5 Jun 2026 17:19:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=79.135.106.111 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780679997; cv=none; b=Iq9s9spxaMbC3P7DRkA2x8WEauM9jqYsBLIclhu4O8ocHEIyvATVEfLNODG/TZuNhkWqsq5FksD/RwWnvkywPH49ZYT94ZO714svkCo3U4uR8Vh6mmsyPW1xzte3uEbM9B7RtEiBqX2fxOaxLnELR+MsQit3x2w6HCFLXPLG/AQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780679997; c=relaxed/simple; bh=okmxrgBCvufTcX32FIBoSLwcDGUzqtcDdCzFnkaOA7U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BylaHcZ6I8KGb54aozBn8yFMCrQ6OxdT/qO/Qe6u+yGPLG4sY/6q9A9TBb7zF/asXs9ZW5PJFQFVAy2qgUC0QH5ULyMtN/iFI4oPEkiEjgrsmP9KXtEYaTwxHGeLv9earRHA5D35f+vzR5QpFmW6U1hJzPZKo1Miyp86mof75cc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=theesfeld.net; spf=fail smtp.mailfrom=theesfeld.net; dkim=fail (0-bit key) header.d=theesfeld.net header.i=@theesfeld.net header.b=ui4XRlhA reason="key not found in DNS"; arc=none smtp.client-ip=79.135.106.111 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=theesfeld.net Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=theesfeld.net Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=theesfeld.net header.i=@theesfeld.net header.b="ui4XRlhA" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=theesfeld.net; s=protonmail2; t=1780679989; x=1780939189; bh=s2Tq9L+mxJV1LF+CSfNq0nEeRrlDQozObfED+HQhBNU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:From:To: Cc:Date:Subject:Reply-To:Feedback-ID:Message-ID:BIMI-Selector; b=ui4XRlhALxtb0GLmeJsQCT8vh2XKH7OwDJNvDI1E4KW0+vKaRzOyTA/Q9C16c+k+R gj0WoSZ1eEbO2qx0fvzDyTtGCJQaSP4PMoLX0GsJnhNO8gnCsaIJBhq9cpHA117L0B +6DGhSB/D1nEhomHNur2z0174icqn1IurMeV26RMRmv2/udjXt0yY29Qjj3wpBnk+b YvoB45pI43v/tWcteMKyF1SU497D8u+CgMW6B/WHgjWjBwpvIOC1DPNdDg4hWDP80r Ng/wh5daqb2nzFdnwgpAYonRAFAoX80+V8TEufA6hBGYfHaaof4QKAP3bPr95NUGNT mx1HRWjgZMRBA== X-Pm-Submission-Id: 4gX7Tt4DgYz1DDXm From: William Theesfeld To: Xingyu Wu Cc: Ziv Xu , Wim Van Sebroeck , Guenter Roeck , linux-watchdog@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3 1/6] watchdog: starfive: balance PM refcount when start operation fails Date: Fri, 5 Jun 2026 13:19:37 -0400 Message-ID: <3a2ba59a0ed3e5ee121a49e04c5bed0c452af238.1780666366.git.william@theesfeld.net> X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" After pm_runtime_resume_and_get() succeeds in starfive_wdt_pm_start(), the runtime PM usage counter is incremented. If starfive_wdt_start() subsequently fails, the function returns the error without releasing that reference, leaking the usage counter. Call pm_runtime_put_sync() on the start failure path so the counter is balanced. This also folds in the v1 conversion of pm_runtime_get_sync() to pm_runtime_resume_and_get(), which was the original purpose of this patch; both fixes together close the refcount-leak window in this function as flagged by the maintainer on the v1 thread. Signed-off-by: William Theesfeld --- drivers/watchdog/starfive-wdt.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wd= t.c index af55adc4a..ed8c5711a 100644 --- a/drivers/watchdog/starfive-wdt.c +++ b/drivers/watchdog/starfive-wdt.c @@ -371,12 +371,16 @@ static void starfive_wdt_stop(struct starfive_wdt *wd= t) static int starfive_wdt_pm_start(struct watchdog_device *wdd) { struct starfive_wdt *wdt =3D watchdog_get_drvdata(wdd); - int ret =3D pm_runtime_get_sync(wdd->parent); + int ret =3D pm_runtime_resume_and_get(wdd->parent); =20 if (ret < 0) return ret; =20 - return starfive_wdt_start(wdt); + ret =3D starfive_wdt_start(wdt); + if (ret) + pm_runtime_put_sync(wdd->parent); + + return ret; } =20 static int starfive_wdt_pm_stop(struct watchdog_device *wdd) --=20 2.54.0 From nobody Mon Jun 8 05:24:51 2026 Received: from mail-244106.protonmail.ch (mail-244106.protonmail.ch [109.224.244.106]) (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 61C93390233; Fri, 5 Jun 2026 17:20:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=109.224.244.106 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780680010; cv=none; b=j3m/aPYmLrtCWK77WC1LOO41DUsBiGk+KRely0tqm6uQjkLu6//ZCLzzgJ9cnnngGuBwhoUrOSUczLGyc5I0CFCuehzdu38h8PRG+lc3tUlhzzdTxLg3ccddz/Gvhl05jNChXRlJOQBkByQeiGBs4rT1BekA3NSS/jAfSFBLD2g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780680010; c=relaxed/simple; bh=TFR2ZDOLwSO8KpMOXTu/BFfjmT3o4oODxCQYDa4Xidk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=X+W8UnzOJApaJ6IczICQ1XDXwniYS08578rZXLP/LF9y4U6eMsOfgpNIyvQt2OCpGS5ZKz0t7CA4rtvDTfI1CEbLvpu1UC04Mkxy91vg5fEu5+M/ypflucgDJ4+aqKl7a7BDyxcoKTrYlmNbRsby95EbVn00jOg2qoH4bmEYdwk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=theesfeld.net; spf=fail smtp.mailfrom=theesfeld.net; dkim=fail (0-bit key) header.d=theesfeld.net header.i=@theesfeld.net header.b=c52++xfr reason="key not found in DNS"; arc=none smtp.client-ip=109.224.244.106 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=theesfeld.net Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=theesfeld.net Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=theesfeld.net header.i=@theesfeld.net header.b="c52++xfr" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=theesfeld.net; s=protonmail2; t=1780679992; x=1780939192; bh=j9kCO9GTcIPjil62JnvoovkenD2UMj5ouvi3yiRJ8x4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:From:To: Cc:Date:Subject:Reply-To:Feedback-ID:Message-ID:BIMI-Selector; b=c52++xfrChGEpiB99Z8fZsUYnH1+kRZTkRNx39NMnWvxSN3438p3n5cWFPPlXTjcD fYUFSjvtypIJaTfvCSIkuXfyiCjrsLdZXLqBbM+WUISTs67abueGCF+SXQ2aJGM6hk +7wA54Tv+2On4DVlMXpZc1Nwx4x0oWcOmdgt+t6qdDeRuz0uaYxKc7uZUlnXLot3gY 5gHQ5xJydlUd79JhyKD0416BEjvvzrhvM+uKRQBnnDXjMMozjZRMAUarrsgPhdp03C lnT0+F/Yy9kPeQgmz2ru9J3rEq4xhpxUus5DaNTrfMQR8DA/gTdsY5d56yBmNFGiO2 7Ca80gULPNvLg== X-Pm-Submission-Id: 4gX7Tw6GTVz1DDXp From: William Theesfeld To: Xingyu Wu Cc: Ziv Xu , Wim Van Sebroeck , Guenter Roeck , linux-watchdog@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3 2/6] watchdog: starfive: treat pm_runtime_put_sync() positive return as success Date: Fri, 5 Jun 2026 13:19:38 -0400 Message-ID: X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" pm_runtime_put_sync() can return a positive value to signal a non-error condition (for example, the device was already in the requested state); only negative return values are real errors. Both starfive_wdt_pm_stop() and starfive_wdt_probe() currently treat any non-zero return as failure: pm_stop returns the value verbatim, which the watchdog framework propagates as an error, and probe takes the err_unregister_wdt path even on a successful but non-zero return. Mask off the positive return value in pm_stop and tighten the probe check to "< 0" so the legitimate positive return is no longer mishandled. Signed-off-by: William Theesfeld --- drivers/watchdog/starfive-wdt.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wd= t.c index ed8c5711a..e047f52b0 100644 --- a/drivers/watchdog/starfive-wdt.c +++ b/drivers/watchdog/starfive-wdt.c @@ -386,9 +386,17 @@ static int starfive_wdt_pm_start(struct watchdog_devic= e *wdd) static int starfive_wdt_pm_stop(struct watchdog_device *wdd) { struct starfive_wdt *wdt =3D watchdog_get_drvdata(wdd); + int ret; =20 starfive_wdt_stop(wdt); - return pm_runtime_put_sync(wdd->parent); + ret =3D pm_runtime_put_sync(wdd->parent); + /* + * pm_runtime_put_sync() can return a positive value to signal a + * non-error condition (for example, the device was already in the + * requested state and no suspend callback was needed). Only + * propagate negative return values as failures. + */ + return ret < 0 ? ret : 0; } =20 static int starfive_wdt_set_timeout(struct watchdog_device *wdd, @@ -503,7 +511,7 @@ static int starfive_wdt_probe(struct platform_device *p= dev) if (!early_enable) { if (pm_runtime_enabled(&pdev->dev)) { ret =3D pm_runtime_put_sync(&pdev->dev); - if (ret) + if (ret < 0) goto err_unregister_wdt; } } --=20 2.54.0 From nobody Mon Jun 8 05:24:51 2026 Received: from mail-106111.protonmail.ch (mail-106111.protonmail.ch [79.135.106.111]) (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 3243B274B5F for ; Fri, 5 Jun 2026 17:19:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=79.135.106.111 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780680001; cv=none; b=qEuhKpeMbG8A7J0FE8kQjNumh+I3p/TS4GkOeTMZEBsqRmKTFUorbSsnKCJlMJkRL7V2HHjEuVU+/z4jbv8l0nkKgtqfiTN+6mw+/o1+g3p7cu1k/K2fpfivwAIKJHg7ZtLFYeKWQQbTM5AyRD26JcAScpPG9pIZcSUigjkfquU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780680001; c=relaxed/simple; bh=E448ctvAsbyMRKRPnlBix0CmIiz8mOPi5UFpTBEIm28=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DRd4YXUgRSUIR7cdAs4kFCAgy3ABRi1JNZ1cRr1SSvq93g2t1pI1KTZQt6pev/8pSRLQNXxSXeXBeN8hnnsZ2DEl8PVxCpF/izVYOMfhyCsXZrAX44RJh5H619qREMDaDNGKXSBEAgxrLQ9EfoexqeKONb2xeBm4k3I6Tu/IzeA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=theesfeld.net; spf=fail smtp.mailfrom=theesfeld.net; dkim=fail (0-bit key) header.d=theesfeld.net header.i=@theesfeld.net header.b=GnLVCkB9 reason="key not found in DNS"; arc=none smtp.client-ip=79.135.106.111 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=theesfeld.net Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=theesfeld.net Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=theesfeld.net header.i=@theesfeld.net header.b="GnLVCkB9" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=theesfeld.net; s=protonmail2; t=1780679992; x=1780939192; bh=yIrWc8wNoc75cAvtPZoI/WTAVLJ3Rtu/+7VIbF4n9Rc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:From:To: Cc:Date:Subject:Reply-To:Feedback-ID:Message-ID:BIMI-Selector; b=GnLVCkB9fHMl8AhPNRNCEIE+RRKy9ceyTlDm0CLhsb8Ni7VLshCeOoggswoCEh60f ragcXLAWZb5t5pBWz1ypEfjujYVXe/49JbP3PYx7zGTvM2ylIVm77ppq/Opf0o/nDm /6TeyR1/GIMvIp1jpxdhO4Gz1eKWsFa6fJL4kJ9s0BQNT+ESH6nkT7aAT6OAeClsoJ XdF7pRSRJ9fPSTmBxwzJWgdMFmhg+yDHlGhxNIdb55E8GFzgOI0Y/xUbCUjZh2WEwh YG/ayxBv+eT6EkmDSwl2zZafOPHvsWSlBqGiuMKg2hOzMN8pFN1LXqXtvYMFfTiMU0 uQLUMuMqsI1SQ== X-Pm-Submission-Id: 4gX7Tz1Dq7z1DDXY From: William Theesfeld To: Xingyu Wu Cc: Ziv Xu , Wim Van Sebroeck , Guenter Roeck , linux-watchdog@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3 3/6] watchdog: starfive: balance PM refcount and disable in probe error paths Date: Fri, 5 Jun 2026 13:19:39 -0400 Message-ID: X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The probe path takes a runtime PM reference via pm_runtime_resume_and_get() (or enables the clocks directly when runtime PM is unavailable), but several error paths after that point do not release that reference before returning, and the two earliest error paths return without calling pm_runtime_disable() at all even though pm_runtime_enable() has already run. Restructure the error handling into three labels so every failure path balances exactly the resources it has acquired: err_pm_disable: pm_runtime_enable() ran but no clock/refcount was taken yet (resume_and_get / enable_clock failed). err_put_pm: clock or PM refcount is held; release it, then fall through to disable runtime PM. err_unregister_wdt: watchdog_register_device() succeeded and the success-path pm_runtime_put_sync() returned an error. The put has already decremented the counter, so this path jumps directly to err_pm_disable rather than falling through to err_put_pm; otherwise the counter would be decremented a second time and underflow. Update the in-function goto targets to use these labels and remove the early "return ret;" paths so pm_runtime_disable() is always run once pm_runtime_enable() has been called. Signed-off-by: William Theesfeld --- drivers/watchdog/starfive-wdt.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wd= t.c index e047f52b0..856e55f04 100644 --- a/drivers/watchdog/starfive-wdt.c +++ b/drivers/watchdog/starfive-wdt.c @@ -460,17 +460,17 @@ static int starfive_wdt_probe(struct platform_device = *pdev) if (pm_runtime_enabled(&pdev->dev)) { ret =3D pm_runtime_resume_and_get(&pdev->dev); if (ret < 0) - return ret; + goto err_pm_disable; } else { /* runtime PM is disabled but clocks need to be enabled */ ret =3D starfive_wdt_enable_clock(wdt); if (ret) - return ret; + goto err_pm_disable; } =20 ret =3D starfive_wdt_reset_init(&pdev->dev); if (ret) - goto err_exit; + goto err_put_pm; =20 watchdog_set_drvdata(&wdt->wdd, wdt); wdt->wdd.info =3D &starfive_wdt_info; @@ -482,7 +482,7 @@ static int starfive_wdt_probe(struct platform_device *p= dev) if (!wdt->freq) { dev_err(&pdev->dev, "get clock rate failed.\n"); ret =3D -EINVAL; - goto err_exit; + goto err_put_pm; } =20 wdt->wdd.min_timeout =3D 1; @@ -498,7 +498,7 @@ static int starfive_wdt_probe(struct platform_device *p= dev) if (early_enable) { ret =3D starfive_wdt_start(wdt); if (ret) - goto err_exit; + goto err_put_pm; set_bit(WDOG_HW_RUNNING, &wdt->wdd.status); } else { starfive_wdt_stop(wdt); @@ -506,7 +506,7 @@ static int starfive_wdt_probe(struct platform_device *p= dev) =20 ret =3D watchdog_register_device(&wdt->wdd); if (ret) - goto err_exit; + goto err_put_pm; =20 if (!early_enable) { if (pm_runtime_enabled(&pdev->dev)) { @@ -520,8 +520,20 @@ static int starfive_wdt_probe(struct platform_device *= pdev) =20 err_unregister_wdt: watchdog_unregister_device(&wdt->wdd); -err_exit: - starfive_wdt_disable_clock(wdt); + /* + * The only path into err_unregister_wdt is the post-register + * pm_runtime_put_sync() that returned an error. That call already + * decremented the runtime PM usage counter, so falling through to + * err_put_pm would put again and underflow the counter. Jump + * straight to err_pm_disable. + */ + goto err_pm_disable; +err_put_pm: + if (pm_runtime_enabled(&pdev->dev)) + pm_runtime_put_sync(&pdev->dev); + else + starfive_wdt_disable_clock(wdt); +err_pm_disable: pm_runtime_disable(&pdev->dev); =20 return ret; --=20 2.54.0 From nobody Mon Jun 8 05:24:51 2026 Received: from mail-244106.protonmail.ch (mail-244106.protonmail.ch [109.224.244.106]) (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 6879836D9F8 for ; Fri, 5 Jun 2026 17:20:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=109.224.244.106 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780680007; cv=none; b=iX62xiXb+cLljV+GMcvy2hel0R0gp2G87NxTkNh0bHj9u+2MuwjTd+l0VPLJoP06Ej5DmUOwsJ64qpddInkqwgMceN9imR0NSlYKbL1gRywjwxiuK4FzKnOCf32pS+b2raoVUI1datu4jCs4923vwPr/2KKTdLlX85vpZk63wtk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780680007; c=relaxed/simple; bh=/v+yP0ivLjzr+EfkSnCQP+66rJZUsfB/jdnnERhaeKA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kRdddfD/vufYvLZqQDQUxzfCzG+dMUku4JbeBuizBL4pq4v1JLT9wQqxr5txPfzPjrxzTTuvuzCC7r792KOQQZaYLU4Ms5wZGZmTWeY126l+tckp8w/Ei9J57Z/GNsIoqTou8bvqBu6wJH4/vetzsvT1F2se3KDEQAhckq6Rrmk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=theesfeld.net; spf=fail smtp.mailfrom=theesfeld.net; dkim=fail (0-bit key) header.d=theesfeld.net header.i=@theesfeld.net header.b=10q2aav7 reason="key not found in DNS"; arc=none smtp.client-ip=109.224.244.106 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=theesfeld.net Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=theesfeld.net Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=theesfeld.net header.i=@theesfeld.net header.b="10q2aav7" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=theesfeld.net; s=protonmail2; t=1780679994; x=1780939194; bh=y+AkXVLiX4yk/y/C0+/Mp3RGJYbGlRAkuJKjAOT4gWg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:From:To: Cc:Date:Subject:Reply-To:Feedback-ID:Message-ID:BIMI-Selector; b=10q2aav76oa1bw2VsSQ/rBV42AsFkrzcLKJlJXUIpTovSrYQKirylKzprWqGiAp5v yvar/xSI2dGb1DE11ULvd3bI5rqY1Ff4mdrcIBlkXCzQy7QRKowdnfl38Br9HtSsNj 79PXkM3utYCHUteChJWZBJTpxOHB5rBD0PKXKVI+Q5f7MIOXL1Y0lvnXgLoFXDCR6p Tr9nug+LrVxqu1FIUlRP6J69hfcaK8t2etvKhAOMcki9tm5pbmMeBbVZxEfOB8TIRj LO5TMMGmA5v/T3uDacwFjA7fGBhCedgomcSwbDPmAD7VyGR+GqF91vfFpJWBJsI7AE Djg57cr3eRLNw== X-Pm-Submission-Id: 4gX7V10BkQz1DDXg From: William Theesfeld To: Xingyu Wu Cc: Ziv Xu , Wim Van Sebroeck , Guenter Roeck , linux-watchdog@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3 4/6] watchdog: starfive: guard system suspend/resume hardware access Date: Fri, 5 Jun 2026 13:19:40 -0400 Message-ID: <790637054268689cf06f47cac161118864edab8f.1780666366.git.william@theesfeld.net> X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" starfive_wdt_suspend() reads from STARFIVE_WDT_VALUE and writes to WDOGCONTROL via starfive_wdt_get_count() and starfive_wdt_stop() before calling pm_runtime_force_suspend(). If the device was already runtime-suspended when system suspend began, the apb and core clocks are gated and those register accesses produce a synchronous external abort. starfive_wdt_resume() has the mirror problem: it unconditionally restores the WDOGLOAD value after pm_runtime_force_resume() returns, but pm_runtime_force_resume() leaves the device in whichever runtime PM state it was in pre-suspend. If the device stays suspended, the restore writes race with gated clocks. Gate both halves with pm_runtime_status_suspended() so the hardware is only touched when it is actually active. When the watchdog was suspended at runtime PM level there is no state to save or restore. Additionally, restart the hardware on resume for the early_enable case (WDOG_HW_RUNNING set without WDOG_ACTIVE). Without this, a system suspend stops the early-enabled hardware via the suspend callback above, but the resume callback only restarts when watchdog_active() is true, leaving the watchdog permanently stopped after the suspend/resume cycle. Signed-off-by: William Theesfeld --- drivers/watchdog/starfive-wdt.c | 34 ++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wd= t.c index 856e55f04..e3a47c0c3 100644 --- a/drivers/watchdog/starfive-wdt.c +++ b/drivers/watchdog/starfive-wdt.c @@ -564,11 +564,16 @@ static int starfive_wdt_suspend(struct device *dev) { struct starfive_wdt *wdt =3D dev_get_drvdata(dev); =20 - /* Save watchdog state, and turn it off. */ - wdt->reload =3D starfive_wdt_get_count(wdt); - - /* Note that WTCNT doesn't need to be saved. */ - starfive_wdt_stop(wdt); + /* + * Only access the hardware while the device is runtime-resumed; if + * runtime PM has already suspended the device, its clocks are gated + * and a register read/write would trigger a synchronous external + * abort. WTCNT does not need to be saved. + */ + if (!pm_runtime_status_suspended(dev)) { + wdt->reload =3D starfive_wdt_get_count(wdt); + starfive_wdt_stop(wdt); + } =20 return pm_runtime_force_suspend(dev); } @@ -582,12 +587,27 @@ static int starfive_wdt_resume(struct device *dev) if (ret) return ret; =20 + /* + * pm_runtime_force_resume() leaves the device in whichever runtime + * PM state it was in before system suspend. Only restore hardware + * state when the device is actually resumed; otherwise the register + * writes below would race with gated clocks. + */ + if (pm_runtime_status_suspended(dev)) + return 0; + starfive_wdt_unlock(wdt); - /* Restore watchdog state. */ starfive_wdt_set_reload_count(wdt, wdt->reload); starfive_wdt_lock(wdt); =20 - if (watchdog_active(&wdt->wdd)) + /* + * Restart the hardware on resume for both userspace-opened + * watchdogs (WDOG_ACTIVE) and watchdogs started via early_enable + * (WDOG_HW_RUNNING). Checking only WDOG_ACTIVE leaves the + * early_enable case stopped after a suspend/resume cycle even + * though the framework still considers the hardware running. + */ + if (watchdog_active(&wdt->wdd) || watchdog_hw_running(&wdt->wdd)) return starfive_wdt_start(wdt); =20 return 0; --=20 2.54.0 From nobody Mon Jun 8 05:24:51 2026 Received: from mail-244107.protonmail.ch (mail-244107.protonmail.ch [109.224.244.107]) (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 9AC6E34CFA1 for ; Fri, 5 Jun 2026 17:20:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=109.224.244.107 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780680003; cv=none; b=oArhg2MsNkmCUWBZG4FF4mYpaG8lHgwQdDviCK7nPix785ndsn41ERrOsCozCMLcps7j8cIpxYTNyPmsYSo/96Rp92sv7T8X5LTx1tlY8aURmubNzSQWoj0abNbkiGp4nQB2GT4/jjnuZd4bx7jQU+jSyY4C78gY6q7Vd/EAgKk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780680003; c=relaxed/simple; bh=uX2OO8VIAJ98ooonTDAk3VBWuXWuFIjpzdpbBmNEyEs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QPmgotWmURyUZwb/+wVUuPTomztayRPKD6yOaZwroIGbtvAZFeNSYrCbYBbdOiY6QrweAD5JoK2u4lLnyvJreKMJsQxXarDrve00sRYff4tbjDSubo2I6to55q8QG3lws6vTZAE9rJ63qfsdj7PUzXotPg4B6DdesSW/ZwvFqA8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=theesfeld.net; spf=fail smtp.mailfrom=theesfeld.net; dkim=fail (0-bit key) header.d=theesfeld.net header.i=@theesfeld.net header.b=E/Q8XoPu reason="key not found in DNS"; arc=none smtp.client-ip=109.224.244.107 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=theesfeld.net Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=theesfeld.net Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=theesfeld.net header.i=@theesfeld.net header.b="E/Q8XoPu" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=theesfeld.net; s=protonmail2; t=1780679998; x=1780939198; bh=LGOXpfMPxFoQZg423hlG08nWuFFWTpOwynBjJFDYYww=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:From:To: Cc:Date:Subject:Reply-To:Feedback-ID:Message-ID:BIMI-Selector; b=E/Q8XoPuaQXUrpNupbT8YcSJzN+wW+7SGf8jPXx2NVWLVYHlcHpIyiv1zZFFeB57p SsKWC6ankURqaFWErXLYndtnR1dc5b5f1z9FuV0NXk9FylNKAIZl7aYFyV0wByhXox xIPvFAGFNGJsz/ObS4FVNDE4mJCPoqoZTp+EeFOE7nsA8XnVRPcJnwy7z2LI1sUFvf Q89ZfdAhieZ0TEvfLcmcbuYjO9u7lcqOZ3i1dLWd+BqFWBUGAgxNT2nvlQ/tngG3sa 3roY6p0HFlaCnca90Ikv6wI5fssDl/dh5Fid+N9tqHWRGmNaP9fXVMW8OrJ5cgUQMM Ksew4un1mpnyg== X-Pm-Submission-Id: 4gX7V25lvLz1DDXj From: William Theesfeld To: Xingyu Wu Cc: Ziv Xu , Wim Van Sebroeck , Guenter Roeck , linux-watchdog@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3 5/6] watchdog: starfive: avoid PM refcount underflow in shutdown Date: Fri, 5 Jun 2026 13:19:41 -0400 Message-ID: <294a324adc8007768829613b03d0415a44b2af35.1780666366.git.william@theesfeld.net> X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" starfive_wdt_shutdown() unconditionally calls starfive_wdt_pm_stop(), which drops a runtime PM reference via pm_runtime_put_sync(). If the device was never opened (so there was no matching pm_start()), and early_enable is also off (so probe already balanced its own get/put), the counter is at zero and put_sync() drives it negative. Only call pm_stop() when WDOG_ACTIVE is set (meaning a paired pm_start() happened on open). For the early_enable-and-never-opened case, the framework state is WDOG_HW_RUNNING without WDOG_ACTIVE; in that case stop just the hardware so the watchdog does not keep ticking through shutdown, while leaving the PM refcount for the remove path to release. Signed-off-by: William Theesfeld --- drivers/watchdog/starfive-wdt.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wd= t.c index e3a47c0c3..6137e98f1 100644 --- a/drivers/watchdog/starfive-wdt.c +++ b/drivers/watchdog/starfive-wdt.c @@ -557,7 +557,19 @@ static void starfive_wdt_shutdown(struct platform_devi= ce *pdev) { struct starfive_wdt *wdt =3D platform_get_drvdata(pdev); =20 - starfive_wdt_pm_stop(&wdt->wdd); + /* + * Only drop a runtime PM reference when we actually hold one. The + * watchdog framework increments it via pm_start() on open; when + * early_enable started the hardware without an open, the reference + * was taken at probe time and the framework state reads as + * WDOG_HW_RUNNING without WDOG_ACTIVE. In the inactive-and-not- + * running case there is nothing for us to do and dropping the + * counter unconditionally would underflow it. + */ + if (watchdog_active(&wdt->wdd)) + starfive_wdt_pm_stop(&wdt->wdd); + else if (test_bit(WDOG_HW_RUNNING, &wdt->wdd.status)) + starfive_wdt_stop(wdt); } =20 static int starfive_wdt_suspend(struct device *dev) --=20 2.54.0 From nobody Mon Jun 8 05:24:51 2026 Received: from mail-43172.protonmail.ch (mail-43172.protonmail.ch [185.70.43.172]) (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 3DB08383339 for ; Fri, 5 Jun 2026 17:20:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.70.43.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780680007; cv=none; b=oXgQBQlK10eaoRMa9XV23meLaqNaaOGciOs4K26rfWuFzG4NIECrzqdlZyPrXnZM6g4UOHO1cmuoQzVCm3B7Og6nDTNk0hEtV2u8KnUK44NESX/HWO7OdrJ3CNe64umBCmYbxjIOG3i7glZxzXFW/3KEonssOXMljZ80LZIahqQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780680007; c=relaxed/simple; bh=PqgK0cYWrHnGTwh5lFEXBxUzY1qNaTyQRbMI+o9rCX0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Ip0YXDjsSaDQmgMv9A7ALvsgMTamv6XdV/jVDHZ+XaerpAHCSgPotUyZVuOryGWvw51qsypsR4QTpXLTnpFYOY5KtPzx6lx6t1ptMfEyAVSoqNhk/whHT6e6Wz11oxGX1sXnKoUtPbtmyrcU7faCV/gZ0ID4smX8fiutb810olk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=theesfeld.net; spf=fail smtp.mailfrom=theesfeld.net; dkim=fail (0-bit key) header.d=theesfeld.net header.i=@theesfeld.net header.b=V8gO0Xl4 reason="key not found in DNS"; arc=none smtp.client-ip=185.70.43.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=theesfeld.net Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=theesfeld.net Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=theesfeld.net header.i=@theesfeld.net header.b="V8gO0Xl4" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=theesfeld.net; s=protonmail2; t=1780680000; x=1780939200; bh=XTUAzXgAtMCDdvg+7OgksKUkAdhwoiglQ/p5dcwkckc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:From:To: Cc:Date:Subject:Reply-To:Feedback-ID:Message-ID:BIMI-Selector; b=V8gO0Xl41/AKYrVm2GPbrPu9NxCg0WOU6/xCmwe+LczVNJnjPNnDJHNJFeyuNcHA3 0CIR650rOmYBrYjz3LM9qK6BQdVxqqLbPyTVJoaIgfIkvY+mxvl0NAQww50g3jeDla yfU7hPLTFCGxOY1o+X11pgi+/6Nw8XcRZ6xLmDQTacSB8d+1BaSihWQs17CD6Q6RNw jJD/3+3uxIhR+DsuGx63KRahKXt+cvtXv50B9jlsYR5E/RV5MSc6RKXXqe3o+zjqxa NhNdAQvKrIhA2yIlVKCUX3udqk5d9AWtUdBReN6GtrKbwCPJ1tZ/a17/3dr/s5DWaj dcIjv8t48+fsQ== X-Pm-Submission-Id: 4gX7V573skz1DDXY From: William Theesfeld To: Xingyu Wu Cc: Ziv Xu , Wim Van Sebroeck , Guenter Roeck , linux-watchdog@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3 6/6] watchdog: starfive: release early_enable PM refcount on remove Date: Fri, 5 Jun 2026 13:19:42 -0400 Message-ID: <5e900cfc2e6441207930b3bda3ec0bc818c2087c.1780666366.git.william@theesfeld.net> X-Mailer: git-send-email 2.54.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" When early_enable starts the hardware at probe time, the runtime PM reference taken by pm_runtime_resume_and_get() is intentionally kept to hold the device runtime-resumed. In the normal (userspace-opened) case the watchdog framework unwinds that reference via pm_stop() on close, and again via stop_on_unregister() during watchdog_unregister_device(). But watchdog_unregister_device() only runs the stop path when WDOG_ACTIVE is set (see drivers/watchdog/watchdog_dev.c). If early_enable started the hardware and userspace never opened it, WDOG_HW_RUNNING is set without WDOG_ACTIVE: unregister returns without touching pm_stop, and the probe-time PM reference is leaked. Drop that reference in starfive_wdt_remove() before pm_runtime_disable() runs, when WDOG_HW_RUNNING is still asserted. Signed-off-by: William Theesfeld --- drivers/watchdog/starfive-wdt.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wd= t.c index 6137e98f1..ad5bb67d4 100644 --- a/drivers/watchdog/starfive-wdt.c +++ b/drivers/watchdog/starfive-wdt.c @@ -546,6 +546,19 @@ static void starfive_wdt_remove(struct platform_device= *pdev) starfive_wdt_stop(wdt); watchdog_unregister_device(&wdt->wdd); =20 + /* + * watchdog_unregister_device() only calls our pm_stop op when + * WDOG_ACTIVE is set. When early_enable started the hardware at + * probe time and userspace never opened the watchdog, the framework + * state is WDOG_HW_RUNNING without WDOG_ACTIVE: the unregister path + * leaves the runtime PM reference taken at probe outstanding. Drop + * it here before disabling runtime PM so the usage counter does not + * leak. + */ + if (test_bit(WDOG_HW_RUNNING, &wdt->wdd.status) && + pm_runtime_enabled(&pdev->dev)) + pm_runtime_put_sync(&pdev->dev); + if (pm_runtime_enabled(&pdev->dev)) pm_runtime_disable(&pdev->dev); else --=20 2.54.0