public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/4] Untie the host lock entanglement - part 2
@ 2024-11-24  7:08 Avri Altman
  2024-11-24  7:08 ` [PATCH v5 1/4] scsi: ufs: core: Introduce ufshcd_has_pending_tasks Avri Altman
                   ` (5 more replies)
  0 siblings, 6 replies; 13+ messages in thread
From: Avri Altman @ 2024-11-24  7:08 UTC (permalink / raw)
  To: Martin K . Petersen
  Cc: linux-scsi, linux-kernel, Bart Van Assche, Bean Huo, Avri Altman

Here is the 2nd part in the sequel, watering down the scsi host lock
usage in the ufs driver. This work is motivated by a comment made by
Bart [1], of the abuse of the scsi host lock in the ufs driver.  Its
Precursor [2] removed the host lock around some of the host register
accesses.

This part replaces the scsi host lock by dedicated locks serializing
access to the clock gating and clock scaling members.

Changes compared to v4:
 - split patch 1 into 2 parts (Bart)
 - use scoped_guard() for the host_lock as well (Bart)
 - remove irrelevant comment and use lockdep_assert_held instead (Bart)
 - improve @lock documentation (Bart)

Changes compared to v3:
 - Keep the host lock when checking ufshcd_state (Bean)

Changes compared to v2:
 - Use clang-format to fix formating (Bart)
 - Use guard() in ufshcd_clkgate_enable_store (Bart)
 - Elaborate commit log (Bart)

Changes compared to v1:
 - use the guard() & scoped_guard() macros (Bart)
 - re-order struct ufs_clk_scaling and struct ufs_clk_gating (Bart)

[1] https://lore.kernel.org/linux-scsi/0b031b8f-c07c-42ef-af93-7336439d3c37@acm.org/
[2] https://lore.kernel.org/linux-scsi/20241024075033.562562-1-avri.altman@wdc.com/

Avri Altman (4):
  scsi: ufs: core: Introduce ufshcd_has_pending_tasks
  scsi: ufs: core: Prepare to introduce a new clock_gating lock
  scsi: ufs: core: Introduce a new clock_gating lock
  scsi: ufs: core: Introduce a new clock_scaling lock

 drivers/ufs/core/ufshcd.c | 253 ++++++++++++++++++--------------------
 include/ufs/ufshcd.h      |  25 ++--
 2 files changed, 140 insertions(+), 138 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v5 1/4] scsi: ufs: core: Introduce ufshcd_has_pending_tasks
  2024-11-24  7:08 [PATCH v5 0/4] Untie the host lock entanglement - part 2 Avri Altman
@ 2024-11-24  7:08 ` Avri Altman
  2024-11-25 21:28   ` Bart Van Assche
  2024-11-24  7:08 ` [PATCH v5 2/4] scsi: ufs: core: Prepare to introduce a new clock_gating lock Avri Altman
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: Avri Altman @ 2024-11-24  7:08 UTC (permalink / raw)
  To: Martin K . Petersen
  Cc: linux-scsi, linux-kernel, Bart Van Assche, Bean Huo, Avri Altman

Prepare to removed hba->clk_gating.active_reqs check from
ufshcd_is_ufs_dev_busy.

Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 drivers/ufs/core/ufshcd.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index acc3607bbd9c..e0a7ef1cb052 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -258,10 +258,16 @@ ufs_get_desired_pm_lvl_for_dev_link_state(enum ufs_dev_pwr_mode dev_state,
 	return UFS_PM_LVL_0;
 }
 
+static bool ufshcd_has_pending_tasks(struct ufs_hba *hba)
+{
+	return hba->outstanding_tasks || hba->active_uic_cmd ||
+	       hba->uic_async_done;
+}
+
 static bool ufshcd_is_ufs_dev_busy(struct ufs_hba *hba)
 {
-	return (hba->clk_gating.active_reqs || hba->outstanding_reqs || hba->outstanding_tasks ||
-		hba->active_uic_cmd || hba->uic_async_done);
+	return hba->clk_gating.active_reqs || hba->outstanding_reqs ||
+	       ufshcd_has_pending_tasks(hba);
 }
 
 static const struct ufs_dev_quirk ufs_fixups[] = {
@@ -1999,8 +2005,7 @@ static void __ufshcd_release(struct ufs_hba *hba)
 
 	if (hba->clk_gating.active_reqs || hba->clk_gating.is_suspended ||
 	    hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL ||
-	    hba->outstanding_tasks || !hba->clk_gating.is_initialized ||
-	    hba->active_uic_cmd || hba->uic_async_done ||
+	    ufshcd_has_pending_tasks(hba) || !hba->clk_gating.is_initialized ||
 	    hba->clk_gating.state == CLKS_OFF)
 		return;
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v5 2/4] scsi: ufs: core: Prepare to introduce a new clock_gating lock
  2024-11-24  7:08 [PATCH v5 0/4] Untie the host lock entanglement - part 2 Avri Altman
  2024-11-24  7:08 ` [PATCH v5 1/4] scsi: ufs: core: Introduce ufshcd_has_pending_tasks Avri Altman
@ 2024-11-24  7:08 ` Avri Altman
  2024-11-25 21:30   ` Bart Van Assche
  2024-11-24  7:08 ` [PATCH v5 3/4] scsi: ufs: core: Introduce " Avri Altman
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: Avri Altman @ 2024-11-24  7:08 UTC (permalink / raw)
  To: Martin K . Petersen
  Cc: linux-scsi, linux-kernel, Bart Van Assche, Bean Huo, Avri Altman

Removed hba->clk_gating.active_reqs check from ufshcd_is_ufs_dev_busy
function to separate clock gating logic from general device busy checks.

Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 drivers/ufs/core/ufshcd.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index e0a7ef1cb052..838bbab97438 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -266,8 +266,7 @@ static bool ufshcd_has_pending_tasks(struct ufs_hba *hba)
 
 static bool ufshcd_is_ufs_dev_busy(struct ufs_hba *hba)
 {
-	return hba->clk_gating.active_reqs || hba->outstanding_reqs ||
-	       ufshcd_has_pending_tasks(hba);
+	return hba->outstanding_reqs || ufshcd_has_pending_tasks(hba);
 }
 
 static const struct ufs_dev_quirk ufs_fixups[] = {
@@ -1949,7 +1948,9 @@ static void ufshcd_gate_work(struct work_struct *work)
 		goto rel_lock;
 	}
 
-	if (ufshcd_is_ufs_dev_busy(hba) || hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)
+	if (ufshcd_is_ufs_dev_busy(hba) ||
+	    hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL ||
+	    hba->clk_gating.active_reqs)
 		goto rel_lock;
 
 	spin_unlock_irqrestore(hba->host->host_lock, flags);
@@ -8262,7 +8263,9 @@ static void ufshcd_rtc_work(struct work_struct *work)
 	hba = container_of(to_delayed_work(work), struct ufs_hba, ufs_rtc_update_work);
 
 	 /* Update RTC only when there are no requests in progress and UFSHCI is operational */
-	if (!ufshcd_is_ufs_dev_busy(hba) && hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL)
+	if (!ufshcd_is_ufs_dev_busy(hba) &&
+	    hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL &&
+	    !hba->clk_gating.active_reqs)
 		ufshcd_update_rtc(hba);
 
 	if (ufshcd_is_ufs_dev_active(hba) && hba->dev_info.rtc_update_period)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v5 3/4] scsi: ufs: core: Introduce a new clock_gating lock
  2024-11-24  7:08 [PATCH v5 0/4] Untie the host lock entanglement - part 2 Avri Altman
  2024-11-24  7:08 ` [PATCH v5 1/4] scsi: ufs: core: Introduce ufshcd_has_pending_tasks Avri Altman
  2024-11-24  7:08 ` [PATCH v5 2/4] scsi: ufs: core: Prepare to introduce a new clock_gating lock Avri Altman
@ 2024-11-24  7:08 ` Avri Altman
  2024-11-25 21:35   ` Bart Van Assche
  2025-01-21 12:42   ` Manivannan Sadhasivam
  2024-11-24  7:08 ` [PATCH v5 4/4] scsi: ufs: core: Introduce a new clock_scaling lock Avri Altman
                   ` (2 subsequent siblings)
  5 siblings, 2 replies; 13+ messages in thread
From: Avri Altman @ 2024-11-24  7:08 UTC (permalink / raw)
  To: Martin K . Petersen
  Cc: linux-scsi, linux-kernel, Bart Van Assche, Bean Huo, Avri Altman

Introduce a new clock gating lock to serialize access to some of the
clock gating members instead of the host_lock.

While at it, simplify the code with the guard() macro and co for
automatic cleanup of the new lock. There are some explicit
spin_lock_irqsave/spin_unlock_irqrestore snaking instances I left behind
because I couldn't make heads or tails of it.

Additionally, move the trace_ufshcd_clk_gating() call from inside the
region protected by the lock as it doesn't needs protection.

Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 drivers/ufs/core/ufshcd.c | 109 ++++++++++++++++++--------------------
 include/ufs/ufshcd.h      |   9 +++-
 2 files changed, 59 insertions(+), 59 deletions(-)

diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 838bbab97438..b4c8f528c18f 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -1816,19 +1816,16 @@ static void ufshcd_exit_clk_scaling(struct ufs_hba *hba)
 static void ufshcd_ungate_work(struct work_struct *work)
 {
 	int ret;
-	unsigned long flags;
 	struct ufs_hba *hba = container_of(work, struct ufs_hba,
 			clk_gating.ungate_work);
 
 	cancel_delayed_work_sync(&hba->clk_gating.gate_work);
 
-	spin_lock_irqsave(hba->host->host_lock, flags);
-	if (hba->clk_gating.state == CLKS_ON) {
-		spin_unlock_irqrestore(hba->host->host_lock, flags);
-		return;
+	scoped_guard(spinlock_irqsave, &hba->clk_gating.lock) {
+		if (hba->clk_gating.state == CLKS_ON)
+			return;
 	}
 
-	spin_unlock_irqrestore(hba->host->host_lock, flags);
 	ufshcd_hba_vreg_set_hpm(hba);
 	ufshcd_setup_clocks(hba, true);
 
@@ -1863,7 +1860,7 @@ void ufshcd_hold(struct ufs_hba *hba)
 	if (!ufshcd_is_clkgating_allowed(hba) ||
 	    !hba->clk_gating.is_initialized)
 		return;
-	spin_lock_irqsave(hba->host->host_lock, flags);
+	spin_lock_irqsave(&hba->clk_gating.lock, flags);
 	hba->clk_gating.active_reqs++;
 
 start:
@@ -1879,11 +1876,11 @@ void ufshcd_hold(struct ufs_hba *hba)
 		 */
 		if (ufshcd_can_hibern8_during_gating(hba) &&
 		    ufshcd_is_link_hibern8(hba)) {
-			spin_unlock_irqrestore(hba->host->host_lock, flags);
+			spin_unlock_irqrestore(&hba->clk_gating.lock, flags);
 			flush_result = flush_work(&hba->clk_gating.ungate_work);
 			if (hba->clk_gating.is_suspended && !flush_result)
 				return;
-			spin_lock_irqsave(hba->host->host_lock, flags);
+			spin_lock_irqsave(&hba->clk_gating.lock, flags);
 			goto start;
 		}
 		break;
@@ -1912,17 +1909,17 @@ void ufshcd_hold(struct ufs_hba *hba)
 		 */
 		fallthrough;
 	case REQ_CLKS_ON:
-		spin_unlock_irqrestore(hba->host->host_lock, flags);
+		spin_unlock_irqrestore(&hba->clk_gating.lock, flags);
 		flush_work(&hba->clk_gating.ungate_work);
 		/* Make sure state is CLKS_ON before returning */
-		spin_lock_irqsave(hba->host->host_lock, flags);
+		spin_lock_irqsave(&hba->clk_gating.lock, flags);
 		goto start;
 	default:
 		dev_err(hba->dev, "%s: clk gating is in invalid state %d\n",
 				__func__, hba->clk_gating.state);
 		break;
 	}
-	spin_unlock_irqrestore(hba->host->host_lock, flags);
+	spin_unlock_irqrestore(&hba->clk_gating.lock, flags);
 }
 EXPORT_SYMBOL_GPL(ufshcd_hold);
 
@@ -1930,30 +1927,32 @@ static void ufshcd_gate_work(struct work_struct *work)
 {
 	struct ufs_hba *hba = container_of(work, struct ufs_hba,
 			clk_gating.gate_work.work);
-	unsigned long flags;
 	int ret;
 
-	spin_lock_irqsave(hba->host->host_lock, flags);
-	/*
-	 * In case you are here to cancel this work the gating state
-	 * would be marked as REQ_CLKS_ON. In this case save time by
-	 * skipping the gating work and exit after changing the clock
-	 * state to CLKS_ON.
-	 */
-	if (hba->clk_gating.is_suspended ||
-		(hba->clk_gating.state != REQ_CLKS_OFF)) {
-		hba->clk_gating.state = CLKS_ON;
-		trace_ufshcd_clk_gating(dev_name(hba->dev),
-					hba->clk_gating.state);
-		goto rel_lock;
-	}
+	scoped_guard(spinlock_irqsave, &hba->clk_gating.lock) {
+		/*
+		 * In case you are here to cancel this work the gating state
+		 * would be marked as REQ_CLKS_ON. In this case save time by
+		 * skipping the gating work and exit after changing the clock
+		 * state to CLKS_ON.
+		 */
+		if (hba->clk_gating.is_suspended ||
+		    hba->clk_gating.state != REQ_CLKS_OFF) {
+			hba->clk_gating.state = CLKS_ON;
+			trace_ufshcd_clk_gating(dev_name(hba->dev),
+						hba->clk_gating.state);
+			return;
+		}
 
-	if (ufshcd_is_ufs_dev_busy(hba) ||
-	    hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL ||
-	    hba->clk_gating.active_reqs)
-		goto rel_lock;
+		if (hba->clk_gating.active_reqs)
+			return;
+	}
 
-	spin_unlock_irqrestore(hba->host->host_lock, flags);
+	scoped_guard(spinlock_irqsave, hba->host->host_lock) {
+		if (ufshcd_is_ufs_dev_busy(hba) ||
+		    hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)
+			return;
+	}
 
 	/* put the link into hibern8 mode before turning off clocks */
 	if (ufshcd_can_hibern8_during_gating(hba)) {
@@ -1964,7 +1963,7 @@ static void ufshcd_gate_work(struct work_struct *work)
 					__func__, ret);
 			trace_ufshcd_clk_gating(dev_name(hba->dev),
 						hba->clk_gating.state);
-			goto out;
+			return;
 		}
 		ufshcd_set_link_hibern8(hba);
 	}
@@ -1984,32 +1983,34 @@ static void ufshcd_gate_work(struct work_struct *work)
 	 * prevent from doing cancel work multiple times when there are
 	 * new requests arriving before the current cancel work is done.
 	 */
-	spin_lock_irqsave(hba->host->host_lock, flags);
+	guard(spinlock_irqsave)(&hba->clk_gating.lock);
 	if (hba->clk_gating.state == REQ_CLKS_OFF) {
 		hba->clk_gating.state = CLKS_OFF;
 		trace_ufshcd_clk_gating(dev_name(hba->dev),
 					hba->clk_gating.state);
 	}
-rel_lock:
-	spin_unlock_irqrestore(hba->host->host_lock, flags);
-out:
-	return;
 }
 
-/* host lock must be held before calling this variant */
 static void __ufshcd_release(struct ufs_hba *hba)
 {
+	lockdep_assert_held(&hba->clk_gating.lock);
+
 	if (!ufshcd_is_clkgating_allowed(hba))
 		return;
 
 	hba->clk_gating.active_reqs--;
 
 	if (hba->clk_gating.active_reqs || hba->clk_gating.is_suspended ||
-	    hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL ||
-	    ufshcd_has_pending_tasks(hba) || !hba->clk_gating.is_initialized ||
+	    !hba->clk_gating.is_initialized ||
 	    hba->clk_gating.state == CLKS_OFF)
 		return;
 
+	scoped_guard(spinlock_irqsave, hba->host->host_lock) {
+		if (ufshcd_has_pending_tasks(hba) ||
+		    hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)
+			return;
+	}
+
 	hba->clk_gating.state = REQ_CLKS_OFF;
 	trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state);
 	queue_delayed_work(hba->clk_gating.clk_gating_workq,
@@ -2019,11 +2020,8 @@ static void __ufshcd_release(struct ufs_hba *hba)
 
 void ufshcd_release(struct ufs_hba *hba)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(hba->host->host_lock, flags);
+	guard(spinlock_irqsave)(&hba->clk_gating.lock);
 	__ufshcd_release(hba);
-	spin_unlock_irqrestore(hba->host->host_lock, flags);
 }
 EXPORT_SYMBOL_GPL(ufshcd_release);
 
@@ -2038,11 +2036,9 @@ static ssize_t ufshcd_clkgate_delay_show(struct device *dev,
 void ufshcd_clkgate_delay_set(struct device *dev, unsigned long value)
 {
 	struct ufs_hba *hba = dev_get_drvdata(dev);
-	unsigned long flags;
 
-	spin_lock_irqsave(hba->host->host_lock, flags);
+	guard(spinlock_irqsave)(&hba->clk_gating.lock);
 	hba->clk_gating.delay_ms = value;
-	spin_unlock_irqrestore(hba->host->host_lock, flags);
 }
 EXPORT_SYMBOL_GPL(ufshcd_clkgate_delay_set);
 
@@ -2070,7 +2066,6 @@ static ssize_t ufshcd_clkgate_enable_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct ufs_hba *hba = dev_get_drvdata(dev);
-	unsigned long flags;
 	u32 value;
 
 	if (kstrtou32(buf, 0, &value))
@@ -2078,9 +2073,10 @@ static ssize_t ufshcd_clkgate_enable_store(struct device *dev,
 
 	value = !!value;
 
-	spin_lock_irqsave(hba->host->host_lock, flags);
+	guard(spinlock_irqsave)(&hba->clk_gating.lock);
+
 	if (value == hba->clk_gating.is_enabled)
-		goto out;
+		return count;
 
 	if (value)
 		__ufshcd_release(hba);
@@ -2088,8 +2084,7 @@ static ssize_t ufshcd_clkgate_enable_store(struct device *dev,
 		hba->clk_gating.active_reqs++;
 
 	hba->clk_gating.is_enabled = value;
-out:
-	spin_unlock_irqrestore(hba->host->host_lock, flags);
+
 	return count;
 }
 
@@ -2131,6 +2126,8 @@ static void ufshcd_init_clk_gating(struct ufs_hba *hba)
 	INIT_DELAYED_WORK(&hba->clk_gating.gate_work, ufshcd_gate_work);
 	INIT_WORK(&hba->clk_gating.ungate_work, ufshcd_ungate_work);
 
+	spin_lock_init(&hba->clk_gating.lock);
+
 	hba->clk_gating.clk_gating_workq = alloc_ordered_workqueue(
 		"ufs_clk_gating_%d", WQ_MEM_RECLAIM | WQ_HIGHPRI,
 		hba->host->host_no);
@@ -9162,7 +9159,6 @@ static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
 	int ret = 0;
 	struct ufs_clk_info *clki;
 	struct list_head *head = &hba->clk_list_head;
-	unsigned long flags;
 	ktime_t start = ktime_get();
 	bool clk_state_changed = false;
 
@@ -9213,11 +9209,10 @@ static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
 				clk_disable_unprepare(clki->clk);
 		}
 	} else if (!ret && on) {
-		spin_lock_irqsave(hba->host->host_lock, flags);
-		hba->clk_gating.state = CLKS_ON;
+		scoped_guard(spinlock_irqsave, &hba->clk_gating.lock)
+			hba->clk_gating.state = CLKS_ON;
 		trace_ufshcd_clk_gating(dev_name(hba->dev),
 					hba->clk_gating.state);
-		spin_unlock_irqrestore(hba->host->host_lock, flags);
 	}
 
 	if (clk_state_changed)
diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
index d7aca9e61684..b6311069d901 100644
--- a/include/ufs/ufshcd.h
+++ b/include/ufs/ufshcd.h
@@ -403,6 +403,9 @@ enum clk_gating_state {
  * delay_ms
  * @ungate_work: worker to turn on clocks that will be used in case of
  * interrupt context
+ * @clk_gating_workq: workqueue for clock gating work.
+ * @lock: serialize access to some struct ufs_clk_gating members. An outer lock
+ * relative to the host lock
  * @state: the current clocks state
  * @delay_ms: gating delay in ms
  * @is_suspended: clk gating is suspended when set to 1 which can be used
@@ -413,11 +416,14 @@ enum clk_gating_state {
  * @is_initialized: Indicates whether clock gating is initialized or not
  * @active_reqs: number of requests that are pending and should be waited for
  * completion before gating clocks.
- * @clk_gating_workq: workqueue for clock gating work.
  */
 struct ufs_clk_gating {
 	struct delayed_work gate_work;
 	struct work_struct ungate_work;
+	struct workqueue_struct *clk_gating_workq;
+
+	spinlock_t lock;
+
 	enum clk_gating_state state;
 	unsigned long delay_ms;
 	bool is_suspended;
@@ -426,7 +432,6 @@ struct ufs_clk_gating {
 	bool is_enabled;
 	bool is_initialized;
 	int active_reqs;
-	struct workqueue_struct *clk_gating_workq;
 };
 
 /**
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v5 4/4] scsi: ufs: core: Introduce a new clock_scaling lock
  2024-11-24  7:08 [PATCH v5 0/4] Untie the host lock entanglement - part 2 Avri Altman
                   ` (2 preceding siblings ...)
  2024-11-24  7:08 ` [PATCH v5 3/4] scsi: ufs: core: Introduce " Avri Altman
@ 2024-11-24  7:08 ` Avri Altman
  2024-12-04 18:13 ` [PATCH v5 0/4] Untie the host lock entanglement - part 2 Martin K. Petersen
  2024-12-10  2:35 ` Martin K. Petersen
  5 siblings, 0 replies; 13+ messages in thread
From: Avri Altman @ 2024-11-24  7:08 UTC (permalink / raw)
  To: Martin K . Petersen
  Cc: linux-scsi, linux-kernel, Bart Van Assche, Bean Huo, Avri Altman

Introduce a new clock scaling lock to serialize access to some of the
clock scaling members instead of the host_lock. here also, simplify the
code with the guard() macro and co.

Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 drivers/ufs/core/ufshcd.c | 132 ++++++++++++++++++--------------------
 include/ufs/ufshcd.h      |  16 +++--
 2 files changed, 71 insertions(+), 77 deletions(-)

diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index b4c8f528c18f..42ce4dff8dd2 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -1452,16 +1452,16 @@ static void ufshcd_clk_scaling_suspend_work(struct work_struct *work)
 {
 	struct ufs_hba *hba = container_of(work, struct ufs_hba,
 					   clk_scaling.suspend_work);
-	unsigned long irq_flags;
 
-	spin_lock_irqsave(hba->host->host_lock, irq_flags);
-	if (hba->clk_scaling.active_reqs || hba->clk_scaling.is_suspended) {
-		spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
-		return;
+	scoped_guard(spinlock_irqsave, &hba->clk_scaling.lock)
+	{
+		if (hba->clk_scaling.active_reqs ||
+		    hba->clk_scaling.is_suspended)
+			return;
+
+		hba->clk_scaling.is_suspended = true;
+		hba->clk_scaling.window_start_t = 0;
 	}
-	hba->clk_scaling.is_suspended = true;
-	hba->clk_scaling.window_start_t = 0;
-	spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
 
 	devfreq_suspend_device(hba->devfreq);
 }
@@ -1470,15 +1470,13 @@ static void ufshcd_clk_scaling_resume_work(struct work_struct *work)
 {
 	struct ufs_hba *hba = container_of(work, struct ufs_hba,
 					   clk_scaling.resume_work);
-	unsigned long irq_flags;
 
-	spin_lock_irqsave(hba->host->host_lock, irq_flags);
-	if (!hba->clk_scaling.is_suspended) {
-		spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
-		return;
+	scoped_guard(spinlock_irqsave, &hba->clk_scaling.lock)
+	{
+		if (!hba->clk_scaling.is_suspended)
+			return;
+		hba->clk_scaling.is_suspended = false;
 	}
-	hba->clk_scaling.is_suspended = false;
-	spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
 
 	devfreq_resume_device(hba->devfreq);
 }
@@ -1492,7 +1490,6 @@ static int ufshcd_devfreq_target(struct device *dev,
 	bool scale_up = false, sched_clk_scaling_suspend_work = false;
 	struct list_head *clk_list = &hba->clk_list_head;
 	struct ufs_clk_info *clki;
-	unsigned long irq_flags;
 
 	if (!ufshcd_is_clkscaling_supported(hba))
 		return -EINVAL;
@@ -1513,43 +1510,38 @@ static int ufshcd_devfreq_target(struct device *dev,
 		*freq =	(unsigned long) clk_round_rate(clki->clk, *freq);
 	}
 
-	spin_lock_irqsave(hba->host->host_lock, irq_flags);
-	if (ufshcd_eh_in_progress(hba)) {
-		spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
-		return 0;
-	}
+	scoped_guard(spinlock_irqsave, &hba->clk_scaling.lock)
+	{
+		if (ufshcd_eh_in_progress(hba))
+			return 0;
 
-	/* Skip scaling clock when clock scaling is suspended */
-	if (hba->clk_scaling.is_suspended) {
-		spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
-		dev_warn(hba->dev, "clock scaling is suspended, skip");
-		return 0;
-	}
+		/* Skip scaling clock when clock scaling is suspended */
+		if (hba->clk_scaling.is_suspended) {
+			dev_warn(hba->dev, "clock scaling is suspended, skip");
+			return 0;
+		}
 
-	if (!hba->clk_scaling.active_reqs)
-		sched_clk_scaling_suspend_work = true;
+		if (!hba->clk_scaling.active_reqs)
+			sched_clk_scaling_suspend_work = true;
 
-	if (list_empty(clk_list)) {
-		spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
-		goto out;
-	}
+		if (list_empty(clk_list))
+			goto out;
 
-	/* Decide based on the target or rounded-off frequency and update */
-	if (hba->use_pm_opp)
-		scale_up = *freq > hba->clk_scaling.target_freq;
-	else
-		scale_up = *freq == clki->max_freq;
+		/* Decide based on the target or rounded-off frequency and update */
+		if (hba->use_pm_opp)
+			scale_up = *freq > hba->clk_scaling.target_freq;
+		else
+			scale_up = *freq == clki->max_freq;
 
-	if (!hba->use_pm_opp && !scale_up)
-		*freq = clki->min_freq;
+		if (!hba->use_pm_opp && !scale_up)
+			*freq = clki->min_freq;
 
-	/* Update the frequency */
-	if (!ufshcd_is_devfreq_scaling_required(hba, *freq, scale_up)) {
-		spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
-		ret = 0;
-		goto out; /* no state change required */
+		/* Update the frequency */
+		if (!ufshcd_is_devfreq_scaling_required(hba, *freq, scale_up)) {
+			ret = 0;
+			goto out; /* no state change required */
+		}
 	}
-	spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
 
 	start = ktime_get();
 	ret = ufshcd_devfreq_scale(hba, *freq, scale_up);
@@ -1574,7 +1566,6 @@ static int ufshcd_devfreq_get_dev_status(struct device *dev,
 {
 	struct ufs_hba *hba = dev_get_drvdata(dev);
 	struct ufs_clk_scaling *scaling = &hba->clk_scaling;
-	unsigned long flags;
 	ktime_t curr_t;
 
 	if (!ufshcd_is_clkscaling_supported(hba))
@@ -1582,7 +1573,8 @@ static int ufshcd_devfreq_get_dev_status(struct device *dev,
 
 	memset(stat, 0, sizeof(*stat));
 
-	spin_lock_irqsave(hba->host->host_lock, flags);
+	guard(spinlock_irqsave)(&hba->clk_scaling.lock);
+
 	curr_t = ktime_get();
 	if (!scaling->window_start_t)
 		goto start_window;
@@ -1618,7 +1610,7 @@ static int ufshcd_devfreq_get_dev_status(struct device *dev,
 		scaling->busy_start_t = 0;
 		scaling->is_busy_started = false;
 	}
-	spin_unlock_irqrestore(hba->host->host_lock, flags);
+
 	return 0;
 }
 
@@ -1682,19 +1674,19 @@ static void ufshcd_devfreq_remove(struct ufs_hba *hba)
 
 static void ufshcd_suspend_clkscaling(struct ufs_hba *hba)
 {
-	unsigned long flags;
 	bool suspend = false;
 
 	cancel_work_sync(&hba->clk_scaling.suspend_work);
 	cancel_work_sync(&hba->clk_scaling.resume_work);
 
-	spin_lock_irqsave(hba->host->host_lock, flags);
-	if (!hba->clk_scaling.is_suspended) {
-		suspend = true;
-		hba->clk_scaling.is_suspended = true;
-		hba->clk_scaling.window_start_t = 0;
+	scoped_guard(spinlock_irqsave, &hba->clk_scaling.lock)
+	{
+		if (!hba->clk_scaling.is_suspended) {
+			suspend = true;
+			hba->clk_scaling.is_suspended = true;
+			hba->clk_scaling.window_start_t = 0;
+		}
 	}
-	spin_unlock_irqrestore(hba->host->host_lock, flags);
 
 	if (suspend)
 		devfreq_suspend_device(hba->devfreq);
@@ -1702,15 +1694,15 @@ static void ufshcd_suspend_clkscaling(struct ufs_hba *hba)
 
 static void ufshcd_resume_clkscaling(struct ufs_hba *hba)
 {
-	unsigned long flags;
 	bool resume = false;
 
-	spin_lock_irqsave(hba->host->host_lock, flags);
-	if (hba->clk_scaling.is_suspended) {
-		resume = true;
-		hba->clk_scaling.is_suspended = false;
+	scoped_guard(spinlock_irqsave, &hba->clk_scaling.lock)
+	{
+		if (hba->clk_scaling.is_suspended) {
+			resume = true;
+			hba->clk_scaling.is_suspended = false;
+		}
 	}
-	spin_unlock_irqrestore(hba->host->host_lock, flags);
 
 	if (resume)
 		devfreq_resume_device(hba->devfreq);
@@ -1796,6 +1788,8 @@ static void ufshcd_init_clk_scaling(struct ufs_hba *hba)
 	INIT_WORK(&hba->clk_scaling.resume_work,
 		  ufshcd_clk_scaling_resume_work);
 
+	spin_lock_init(&hba->clk_scaling.lock);
+
 	hba->clk_scaling.workq = alloc_ordered_workqueue(
 		"ufs_clkscaling_%d", WQ_MEM_RECLAIM, hba->host->host_no);
 
@@ -2157,19 +2151,17 @@ static void ufshcd_clk_scaling_start_busy(struct ufs_hba *hba)
 {
 	bool queue_resume_work = false;
 	ktime_t curr_t = ktime_get();
-	unsigned long flags;
 
 	if (!ufshcd_is_clkscaling_supported(hba))
 		return;
 
-	spin_lock_irqsave(hba->host->host_lock, flags);
+	guard(spinlock_irqsave)(&hba->clk_scaling.lock);
+
 	if (!hba->clk_scaling.active_reqs++)
 		queue_resume_work = true;
 
-	if (!hba->clk_scaling.is_enabled || hba->pm_op_in_progress) {
-		spin_unlock_irqrestore(hba->host->host_lock, flags);
+	if (!hba->clk_scaling.is_enabled || hba->pm_op_in_progress)
 		return;
-	}
 
 	if (queue_resume_work)
 		queue_work(hba->clk_scaling.workq,
@@ -2185,18 +2177,17 @@ static void ufshcd_clk_scaling_start_busy(struct ufs_hba *hba)
 		hba->clk_scaling.busy_start_t = curr_t;
 		hba->clk_scaling.is_busy_started = true;
 	}
-	spin_unlock_irqrestore(hba->host->host_lock, flags);
 }
 
 static void ufshcd_clk_scaling_update_busy(struct ufs_hba *hba)
 {
 	struct ufs_clk_scaling *scaling = &hba->clk_scaling;
-	unsigned long flags;
 
 	if (!ufshcd_is_clkscaling_supported(hba))
 		return;
 
-	spin_lock_irqsave(hba->host->host_lock, flags);
+	guard(spinlock_irqsave)(&hba->clk_scaling.lock);
+
 	hba->clk_scaling.active_reqs--;
 	if (!scaling->active_reqs && scaling->is_busy_started) {
 		scaling->tot_busy_t += ktime_to_us(ktime_sub(ktime_get(),
@@ -2204,7 +2195,6 @@ static void ufshcd_clk_scaling_update_busy(struct ufs_hba *hba)
 		scaling->busy_start_t = 0;
 		scaling->is_busy_started = false;
 	}
-	spin_unlock_irqrestore(hba->host->host_lock, flags);
 }
 
 static inline int ufshcd_monitor_opcode2dir(u8 opcode)
diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
index b6311069d901..ce7667b020e2 100644
--- a/include/ufs/ufshcd.h
+++ b/include/ufs/ufshcd.h
@@ -436,6 +436,10 @@ struct ufs_clk_gating {
 
 /**
  * struct ufs_clk_scaling - UFS clock scaling related data
+ * @workq: workqueue to schedule devfreq suspend/resume work
+ * @suspend_work: worker to suspend devfreq
+ * @resume_work: worker to resume devfreq
+ * @lock: serialize access to some struct ufs_clk_scaling members
  * @active_reqs: number of requests that are pending. If this is zero when
  * devfreq ->target() function is called then schedule "suspend_work" to
  * suspend devfreq.
@@ -445,9 +449,6 @@ struct ufs_clk_gating {
  * @enable_attr: sysfs attribute to enable/disable clock scaling
  * @saved_pwr_info: UFS power mode may also be changed during scaling and this
  * one keeps track of previous power mode.
- * @workq: workqueue to schedule devfreq suspend/resume work
- * @suspend_work: worker to suspend devfreq
- * @resume_work: worker to resume devfreq
  * @target_freq: frequency requested by devfreq framework
  * @min_gear: lowest HS gear to scale down to
  * @is_enabled: tracks if scaling is currently enabled or not, controlled by
@@ -459,15 +460,18 @@ struct ufs_clk_gating {
  * @is_suspended: tracks if devfreq is suspended or not
  */
 struct ufs_clk_scaling {
+	struct workqueue_struct *workq;
+	struct work_struct suspend_work;
+	struct work_struct resume_work;
+
+	spinlock_t lock;
+
 	int active_reqs;
 	unsigned long tot_busy_t;
 	ktime_t window_start_t;
 	ktime_t busy_start_t;
 	struct device_attribute enable_attr;
 	struct ufs_pa_layer_attr saved_pwr_info;
-	struct workqueue_struct *workq;
-	struct work_struct suspend_work;
-	struct work_struct resume_work;
 	unsigned long target_freq;
 	u32 min_gear;
 	bool is_enabled;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v5 1/4] scsi: ufs: core: Introduce ufshcd_has_pending_tasks
  2024-11-24  7:08 ` [PATCH v5 1/4] scsi: ufs: core: Introduce ufshcd_has_pending_tasks Avri Altman
@ 2024-11-25 21:28   ` Bart Van Assche
  0 siblings, 0 replies; 13+ messages in thread
From: Bart Van Assche @ 2024-11-25 21:28 UTC (permalink / raw)
  To: Avri Altman, Martin K . Petersen; +Cc: linux-scsi, linux-kernel, Bean Huo

On 11/23/24 11:08 PM, Avri Altman wrote:
> Prepare to removed hba->clk_gating.active_reqs check from
> ufshcd_is_ufs_dev_busy.

Patch descriptions should use the imperative mood. If this series
is reposted, please change "removed" into "remove". Since otherwise
this patch looks good to me:

Reviewed-by: Bart Van Assche <bvanassche@acm.org>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v5 2/4] scsi: ufs: core: Prepare to introduce a new clock_gating lock
  2024-11-24  7:08 ` [PATCH v5 2/4] scsi: ufs: core: Prepare to introduce a new clock_gating lock Avri Altman
@ 2024-11-25 21:30   ` Bart Van Assche
  0 siblings, 0 replies; 13+ messages in thread
From: Bart Van Assche @ 2024-11-25 21:30 UTC (permalink / raw)
  To: Avri Altman, Martin K . Petersen; +Cc: linux-scsi, linux-kernel, Bean Huo

On 11/23/24 11:08 PM, Avri Altman wrote:
> Removed hba->clk_gating.active_reqs check from ufshcd_is_ufs_dev_busy
> function to separate clock gating logic from general device busy checks.

Patch descriptions should use the imperative mood. If this series
is reposted, please change "removed" into "remove". Since otherwise
this patch looks good to me:

Reviewed-by: Bart Van Assche <bvanassche@acm.org>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v5 3/4] scsi: ufs: core: Introduce a new clock_gating lock
  2024-11-24  7:08 ` [PATCH v5 3/4] scsi: ufs: core: Introduce " Avri Altman
@ 2024-11-25 21:35   ` Bart Van Assche
  2025-01-21 12:42   ` Manivannan Sadhasivam
  1 sibling, 0 replies; 13+ messages in thread
From: Bart Van Assche @ 2024-11-25 21:35 UTC (permalink / raw)
  To: Avri Altman, Martin K . Petersen; +Cc: linux-scsi, linux-kernel, Bean Huo

On 11/23/24 11:08 PM, Avri Altman wrote:
> Introduce a new clock gating lock to serialize access to some of the
> clock gating members instead of the host_lock.
> 
> While at it, simplify the code with the guard() macro and co for
> automatic cleanup of the new lock. There are some explicit
> spin_lock_irqsave/spin_unlock_irqrestore snaking instances I left behind
> because I couldn't make heads or tails of it.
> 
> Additionally, move the trace_ufshcd_clk_gating() call from inside the
> region protected by the lock as it doesn't needs protection.

Reviewed-by: Bart Van Assche <bvanassche@acm.org>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v5 0/4] Untie the host lock entanglement - part 2
  2024-11-24  7:08 [PATCH v5 0/4] Untie the host lock entanglement - part 2 Avri Altman
                   ` (3 preceding siblings ...)
  2024-11-24  7:08 ` [PATCH v5 4/4] scsi: ufs: core: Introduce a new clock_scaling lock Avri Altman
@ 2024-12-04 18:13 ` Martin K. Petersen
  2024-12-10  2:35 ` Martin K. Petersen
  5 siblings, 0 replies; 13+ messages in thread
From: Martin K. Petersen @ 2024-12-04 18:13 UTC (permalink / raw)
  To: Avri Altman
  Cc: Martin K . Petersen, linux-scsi, linux-kernel, Bart Van Assche,
	Bean Huo


Avri,

> Here is the 2nd part in the sequel, watering down the scsi host lock
> usage in the ufs driver. This work is motivated by a comment made by
> Bart [1], of the abuse of the scsi host lock in the ufs driver. Its
> Precursor [2] removed the host lock around some of the host register
> accesses.
>
> This part replaces the scsi host lock by dedicated locks serializing
> access to the clock gating and clock scaling members.

Applied to 6.14/scsi-staging, thanks!

-- 
Martin K. Petersen	Oracle Linux Engineering

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v5 0/4] Untie the host lock entanglement - part 2
  2024-11-24  7:08 [PATCH v5 0/4] Untie the host lock entanglement - part 2 Avri Altman
                   ` (4 preceding siblings ...)
  2024-12-04 18:13 ` [PATCH v5 0/4] Untie the host lock entanglement - part 2 Martin K. Petersen
@ 2024-12-10  2:35 ` Martin K. Petersen
  5 siblings, 0 replies; 13+ messages in thread
From: Martin K. Petersen @ 2024-12-10  2:35 UTC (permalink / raw)
  To: Avri Altman
  Cc: Martin K . Petersen, linux-scsi, linux-kernel, Bart Van Assche,
	Bean Huo

On Sun, 24 Nov 2024 09:08:04 +0200, Avri Altman wrote:

> Here is the 2nd part in the sequel, watering down the scsi host lock
> usage in the ufs driver. This work is motivated by a comment made by
> Bart [1], of the abuse of the scsi host lock in the ufs driver.  Its
> Precursor [2] removed the host lock around some of the host register
> accesses.
> 
> This part replaces the scsi host lock by dedicated locks serializing
> access to the clock gating and clock scaling members.
> 
> [...]

Applied to 6.14/scsi-queue, thanks!

[1/4] scsi: ufs: core: Introduce ufshcd_has_pending_tasks
      https://git.kernel.org/mkp/scsi/c/e738ba458e75
[2/4] scsi: ufs: core: Prepare to introduce a new clock_gating lock
      https://git.kernel.org/mkp/scsi/c/7869c6521f57
[3/4] scsi: ufs: core: Introduce a new clock_gating lock
      https://git.kernel.org/mkp/scsi/c/209f4e43b806
[4/4] scsi: ufs: core: Introduce a new clock_scaling lock
      https://git.kernel.org/mkp/scsi/c/be769e5cf53b

-- 
Martin K. Petersen	Oracle Linux Engineering

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v5 3/4] scsi: ufs: core: Introduce a new clock_gating lock
  2024-11-24  7:08 ` [PATCH v5 3/4] scsi: ufs: core: Introduce " Avri Altman
  2024-11-25 21:35   ` Bart Van Assche
@ 2025-01-21 12:42   ` Manivannan Sadhasivam
  2025-01-21 12:46     ` Manivannan Sadhasivam
  1 sibling, 1 reply; 13+ messages in thread
From: Manivannan Sadhasivam @ 2025-01-21 12:42 UTC (permalink / raw)
  To: Avri Altman
  Cc: Martin K . Petersen, linux-scsi, linux-kernel, Bart Van Assche,
	Bean Huo

+ Dmitry

On Sun, Nov 24, 2024 at 09:08:07AM +0200, Avri Altman wrote:

[...]

> @@ -9162,7 +9159,6 @@ static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
>  	int ret = 0;
>  	struct ufs_clk_info *clki;
>  	struct list_head *head = &hba->clk_list_head;
> -	unsigned long flags;
>  	ktime_t start = ktime_get();
>  	bool clk_state_changed = false;
>  
> @@ -9213,11 +9209,10 @@ static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
>  				clk_disable_unprepare(clki->clk);
>  		}
>  	} else if (!ret && on) {
> -		spin_lock_irqsave(hba->host->host_lock, flags);
> -		hba->clk_gating.state = CLKS_ON;
> +		scoped_guard(spinlock_irqsave, &hba->clk_gating.lock)

This triggers the following lockdep warning on Qualcomm boards as reported by
Dmitry offline:

[    4.388838] INFO: trying to register non-static key.
[    4.395673] The code is fine but needs lockdep annotation, or maybe
[    4.402118] you didn't initialize this object before use?
[    4.407673] turning off the locking correctness validator.
[    4.413334] CPU: 5 UID: 0 PID: 58 Comm: kworker/u32:1 Not tainted 6.12-rc1 #185
[    4.413343] Hardware name: Qualcomm Technologies, Inc. Robotics RB5 (DT)
[    4.413362] Call trace:
[    4.413364]  show_stack+0x18/0x24 (C)
[    4.413374]  dump_stack_lvl+0x90/0xd0
[    4.413384]  dump_stack+0x18/0x24
[    4.413392]  register_lock_class+0x498/0x4a8
[    4.413400]  __lock_acquire+0xb4/0x1b90
[    4.413406]  lock_acquire+0x114/0x310
[    4.413413]  _raw_spin_lock_irqsave+0x60/0x88
[    4.413423]  ufshcd_setup_clocks+0x2c0/0x490
[    4.413433]  ufshcd_init+0x198/0x10ec
[    4.413437]  ufshcd_pltfrm_init+0x600/0x7c0
[    4.413444]  ufs_qcom_probe+0x20/0x58
[    4.413449]  platform_probe+0x68/0xd8
[    4.413459]  really_probe+0xbc/0x268
[    4.413466]  __driver_probe_device+0x78/0x12c
[    4.413473]  driver_probe_device+0x40/0x11c
[    4.413481]  __device_attach_driver+0xb8/0xf8
[    4.413489]  bus_for_each_drv+0x84/0xe4
[    4.413495]  __device_attach+0xfc/0x18c
[    4.413502]  device_initial_probe+0x14/0x20
[    4.413510]  bus_probe_device+0xb0/0xb4
[    4.413517]  deferred_probe_work_func+0x8c/0xc8
[    4.413524]  process_scheduled_works+0x250/0x658
[    4.413534]  worker_thread+0x15c/0x2c8
[    4.413542]  kthread+0x134/0x200
[    4.413550]  ret_from_fork+0x10/0x20

As lockdep found, clk_gating.lock is uninitialized when ufshcd_setup_clocks() is
called for the first time. I looked into fixing it for a moment, but the overall
locking for 'clk_gating.state' looks fragile i.e., there are instances where the
code is not locked at all. So I'm just reporting to you here hoping that you'd
have some idea to fix it.

While submitting the fix, please add the following reported by tag:

Reported-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>

- Mani

-- 
மணிவண்ணன் சதாசிவம்

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v5 3/4] scsi: ufs: core: Introduce a new clock_gating lock
  2025-01-21 12:42   ` Manivannan Sadhasivam
@ 2025-01-21 12:46     ` Manivannan Sadhasivam
  2025-01-21 13:24       ` Avri Altman
  0 siblings, 1 reply; 13+ messages in thread
From: Manivannan Sadhasivam @ 2025-01-21 12:46 UTC (permalink / raw)
  To: Avri Altman
  Cc: Martin K . Petersen, linux-scsi, linux-kernel, Bart Van Assche,
	Bean Huo, dmitry.baryshkov

On Tue, Jan 21, 2025 at 06:12:23PM +0530, Manivannan Sadhasivam wrote:
> + Dmitry
> 

Oops. Missed CCing Dmitry. Added now.

- Mani

> On Sun, Nov 24, 2024 at 09:08:07AM +0200, Avri Altman wrote:
> 
> [...]
> 
> > @@ -9162,7 +9159,6 @@ static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
> >  	int ret = 0;
> >  	struct ufs_clk_info *clki;
> >  	struct list_head *head = &hba->clk_list_head;
> > -	unsigned long flags;
> >  	ktime_t start = ktime_get();
> >  	bool clk_state_changed = false;
> >  
> > @@ -9213,11 +9209,10 @@ static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
> >  				clk_disable_unprepare(clki->clk);
> >  		}
> >  	} else if (!ret && on) {
> > -		spin_lock_irqsave(hba->host->host_lock, flags);
> > -		hba->clk_gating.state = CLKS_ON;
> > +		scoped_guard(spinlock_irqsave, &hba->clk_gating.lock)
> 
> This triggers the following lockdep warning on Qualcomm boards as reported by
> Dmitry offline:
> 
> [    4.388838] INFO: trying to register non-static key.
> [    4.395673] The code is fine but needs lockdep annotation, or maybe
> [    4.402118] you didn't initialize this object before use?
> [    4.407673] turning off the locking correctness validator.
> [    4.413334] CPU: 5 UID: 0 PID: 58 Comm: kworker/u32:1 Not tainted 6.12-rc1 #185
> [    4.413343] Hardware name: Qualcomm Technologies, Inc. Robotics RB5 (DT)
> [    4.413362] Call trace:
> [    4.413364]  show_stack+0x18/0x24 (C)
> [    4.413374]  dump_stack_lvl+0x90/0xd0
> [    4.413384]  dump_stack+0x18/0x24
> [    4.413392]  register_lock_class+0x498/0x4a8
> [    4.413400]  __lock_acquire+0xb4/0x1b90
> [    4.413406]  lock_acquire+0x114/0x310
> [    4.413413]  _raw_spin_lock_irqsave+0x60/0x88
> [    4.413423]  ufshcd_setup_clocks+0x2c0/0x490
> [    4.413433]  ufshcd_init+0x198/0x10ec
> [    4.413437]  ufshcd_pltfrm_init+0x600/0x7c0
> [    4.413444]  ufs_qcom_probe+0x20/0x58
> [    4.413449]  platform_probe+0x68/0xd8
> [    4.413459]  really_probe+0xbc/0x268
> [    4.413466]  __driver_probe_device+0x78/0x12c
> [    4.413473]  driver_probe_device+0x40/0x11c
> [    4.413481]  __device_attach_driver+0xb8/0xf8
> [    4.413489]  bus_for_each_drv+0x84/0xe4
> [    4.413495]  __device_attach+0xfc/0x18c
> [    4.413502]  device_initial_probe+0x14/0x20
> [    4.413510]  bus_probe_device+0xb0/0xb4
> [    4.413517]  deferred_probe_work_func+0x8c/0xc8
> [    4.413524]  process_scheduled_works+0x250/0x658
> [    4.413534]  worker_thread+0x15c/0x2c8
> [    4.413542]  kthread+0x134/0x200
> [    4.413550]  ret_from_fork+0x10/0x20
> 
> As lockdep found, clk_gating.lock is uninitialized when ufshcd_setup_clocks() is
> called for the first time. I looked into fixing it for a moment, but the overall
> locking for 'clk_gating.state' looks fragile i.e., there are instances where the
> code is not locked at all. So I'm just reporting to you here hoping that you'd
> have some idea to fix it.
> 
> While submitting the fix, please add the following reported by tag:
> 
> Reported-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> 
> - Mani
> 
> -- 
> மணிவண்ணன் சதாசிவம்

-- 
மணிவண்ணன் சதாசிவம்

^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [PATCH v5 3/4] scsi: ufs: core: Introduce a new clock_gating lock
  2025-01-21 12:46     ` Manivannan Sadhasivam
@ 2025-01-21 13:24       ` Avri Altman
  0 siblings, 0 replies; 13+ messages in thread
From: Avri Altman @ 2025-01-21 13:24 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Martin K . Petersen, linux-scsi@vger.kernel.org,
	linux-kernel@vger.kernel.org, Bart Van Assche, Bean Huo,
	dmitry.baryshkov@linaro.org

> > > @@ -9162,7 +9159,6 @@ static int ufshcd_setup_clocks(struct ufs_hba
> *hba, bool on)
> > >     int ret = 0;
> > >     struct ufs_clk_info *clki;
> > >     struct list_head *head = &hba->clk_list_head;
> > > -   unsigned long flags;
> > >     ktime_t start = ktime_get();
> > >     bool clk_state_changed = false;
> > >
> > > @@ -9213,11 +9209,10 @@ static int ufshcd_setup_clocks(struct ufs_hba
> *hba, bool on)
> > >                             clk_disable_unprepare(clki->clk);
> > >             }
> > >     } else if (!ret && on) {
> > > -           spin_lock_irqsave(hba->host->host_lock, flags);
> > > -           hba->clk_gating.state = CLKS_ON;
> > > +           scoped_guard(spinlock_irqsave, &hba->clk_gating.lock)
> >
> > This triggers the following lockdep warning on Qualcomm boards as
> > reported by Dmitry offline:
> >
> > [    4.388838] INFO: trying to register non-static key.
> > [    4.395673] The code is fine but needs lockdep annotation, or maybe
> > [    4.402118] you didn't initialize this object before use?
> > [    4.407673] turning off the locking correctness validator.
> > [    4.413334] CPU: 5 UID: 0 PID: 58 Comm: kworker/u32:1 Not tainted 6.12-
> rc1 #185
> > [    4.413343] Hardware name: Qualcomm Technologies, Inc. Robotics RB5
> (DT)
> > [    4.413362] Call trace:
> > [    4.413364]  show_stack+0x18/0x24 (C)
> > [    4.413374]  dump_stack_lvl+0x90/0xd0
> > [    4.413384]  dump_stack+0x18/0x24
> > [    4.413392]  register_lock_class+0x498/0x4a8
> > [    4.413400]  __lock_acquire+0xb4/0x1b90
> > [    4.413406]  lock_acquire+0x114/0x310
> > [    4.413413]  _raw_spin_lock_irqsave+0x60/0x88
> > [    4.413423]  ufshcd_setup_clocks+0x2c0/0x490
> > [    4.413433]  ufshcd_init+0x198/0x10ec
> > [    4.413437]  ufshcd_pltfrm_init+0x600/0x7c0
> > [    4.413444]  ufs_qcom_probe+0x20/0x58
> > [    4.413449]  platform_probe+0x68/0xd8
> > [    4.413459]  really_probe+0xbc/0x268
> > [    4.413466]  __driver_probe_device+0x78/0x12c
> > [    4.413473]  driver_probe_device+0x40/0x11c
> > [    4.413481]  __device_attach_driver+0xb8/0xf8
> > [    4.413489]  bus_for_each_drv+0x84/0xe4
> > [    4.413495]  __device_attach+0xfc/0x18c
> > [    4.413502]  device_initial_probe+0x14/0x20
> > [    4.413510]  bus_probe_device+0xb0/0xb4
> > [    4.413517]  deferred_probe_work_func+0x8c/0xc8
> > [    4.413524]  process_scheduled_works+0x250/0x658
> > [    4.413534]  worker_thread+0x15c/0x2c8
> > [    4.413542]  kthread+0x134/0x200
> > [    4.413550]  ret_from_fork+0x10/0x20
> >
> > As lockdep found, clk_gating.lock is uninitialized when
> > ufshcd_setup_clocks() is called for the first time. I looked into
> > fixing it for a moment, but the overall locking for 'clk_gating.state'
> > looks fragile i.e., there are instances where the code is not locked
> > at all. So I'm just reporting to you here hoping that you'd have some idea
> to fix it.
Thanks for reporting this.
How about just:
+++ b/drivers/ufs/core/ufshcd.c
@@ -9166,7 +9166,7 @@ static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
                        if (!IS_ERR_OR_NULL(clki->clk) && clki->enabled)
                                clk_disable_unprepare(clki->clk);
                }
-       } else if (!ret && on) {
+       } else if (!ret && on && hba->clk_gating.is_initialized) {
                scoped_guard(spinlock_irqsave, &hba->clk_gating.lock)
                        hba->clk_gating.state = CLKS_ON;
                trace_ufshcd_clk_gating(dev_name(hba->dev),

What do you think?

Thanks,
Avri

> >
> > While submitting the fix, please add the following reported by tag:
> >
> > Reported-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> >
> > - Mani
> >
> > --
> > மணிவண்ணன் சதாசிவம்
> 
> --
> மணிவண்ணன் சதாசிவம்

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2025-01-21 13:24 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-24  7:08 [PATCH v5 0/4] Untie the host lock entanglement - part 2 Avri Altman
2024-11-24  7:08 ` [PATCH v5 1/4] scsi: ufs: core: Introduce ufshcd_has_pending_tasks Avri Altman
2024-11-25 21:28   ` Bart Van Assche
2024-11-24  7:08 ` [PATCH v5 2/4] scsi: ufs: core: Prepare to introduce a new clock_gating lock Avri Altman
2024-11-25 21:30   ` Bart Van Assche
2024-11-24  7:08 ` [PATCH v5 3/4] scsi: ufs: core: Introduce " Avri Altman
2024-11-25 21:35   ` Bart Van Assche
2025-01-21 12:42   ` Manivannan Sadhasivam
2025-01-21 12:46     ` Manivannan Sadhasivam
2025-01-21 13:24       ` Avri Altman
2024-11-24  7:08 ` [PATCH v5 4/4] scsi: ufs: core: Introduce a new clock_scaling lock Avri Altman
2024-12-04 18:13 ` [PATCH v5 0/4] Untie the host lock entanglement - part 2 Martin K. Petersen
2024-12-10  2:35 ` Martin K. Petersen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox