Thread (32 messages) 32 messages, 6 authors, 2021-12-03

Re: [PATCH v3 16/17] scsi: ufs: Optimize the command queueing code

From: Asutosh Das (asd) <hidden>
Date: 2021-12-03 15:38:12

On 12/2/2021 10:13 AM, Bart Van Assche wrote:
On 12/1/21 3:33 PM, Asutosh Das (asd) wrote:
quoted
Hi Bart,
Say an IO (req1) has crossed the scsi_host_queue_ready() check but 
hasn't yet reached ufshcd_queuecommand() and DBR is 0.
ufshcd_clock_scaling_prepare() is invoked and completes and scaling 
proceeds to change the clocks and gear.
I wonder if the IO (req1) would be issued while scaling is in progress.
If so, do you think a check should be added in ufshcd_queuecommand() 
to see if scaling is in progress or if host is blocked?
How about using the patch below instead of patch 16/17 from this patch
series? The patch below should not trigger the race condition mentioned
above.

Thanks,

Bart.
Hi Bart,
This looks like it'd work.

-asd
quoted hunk ↗ jump to hunk
Subject: [PATCH] scsi: ufs: Optimize the command queueing code

Remove the clock scaling lock from ufshcd_queuecommand() since it is a
performance bottleneck. Instead, wait until all budget_maps have cleared
to wait for ongoing ufshcd_queuecommand() calls.

Cc: Asutosh Das (asd) <redacted>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
  drivers/scsi/ufs/ufshcd.c | 33 +++++++++++++++++++++++----------
  drivers/scsi/ufs/ufshcd.h |  1 +
  2 files changed, 24 insertions(+), 10 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c4cf5c4b4893..be679f2a97da 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1070,13 +1070,31 @@ static bool 
ufshcd_is_devfreq_scaling_required(struct ufs_hba *hba,
      return false;
  }

+/*
+ * Determine the number of pending commands by counting the bits in the 
SCSI
+ * device budget maps. This approach has been selected because a bit is 
set in
+ * the budget map before scsi_host_queue_ready() checks the 
host_self_blocked
+ * flag. The host_self_blocked flag can be modified by calling
+ * scsi_block_requests() or scsi_unblock_requests().
+ */
+static u32 ufshcd_pending_cmds(struct ufs_hba *hba)
+{
+    struct scsi_device *sdev;
+    u32 pending;
+
+    shost_for_each_device(sdev, hba->host)
+        pending += sbitmap_weight(&sdev->budget_map);
+
+    return pending;
+}
+
  static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba,
                      u64 wait_timeout_us)
  {
      unsigned long flags;
      int ret = 0;
      u32 tm_doorbell;
-    u32 tr_doorbell;
+    u32 tr_pending;
      bool timeout = false, do_last_check = false;
      ktime_t start;
@@ -1094,8 +1112,8 @@ static int ufshcd_wait_for_doorbell_clr(struct 
ufs_hba *hba,
          }

          tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
-        tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
-        if (!tm_doorbell && !tr_doorbell) {
+        tr_pending = ufshcd_pending_cmds(hba);
+        if (!tm_doorbell && !tr_pending) {
              timeout = false;
              break;
          } else if (do_last_check) {
@@ -1115,12 +1133,12 @@ static int ufshcd_wait_for_doorbell_clr(struct 
ufs_hba *hba,
              do_last_check = true;
          }
          spin_lock_irqsave(hba->host->host_lock, flags);
-    } while (tm_doorbell || tr_doorbell);
+    } while (tm_doorbell || tr_pending);

      if (timeout) {
          dev_err(hba->dev,
              "%s: timedout waiting for doorbell to clear (tm=0x%x, 
tr=0x%x)\n",
-            __func__, tm_doorbell, tr_doorbell);
+            __func__, tm_doorbell, tr_pending);
          ret = -EBUSY;
      }
  out:
@@ -2681,9 +2699,6 @@ static int ufshcd_queuecommand(struct Scsi_Host 
*host, struct scsi_cmnd *cmd)

      WARN_ONCE(tag < 0, "Invalid tag %d\n", tag);

-    if (!down_read_trylock(&hba->clk_scaling_lock))
-        return SCSI_MLQUEUE_HOST_BUSY;
-
      /*
       * Allows the UFS error handler to wait for prior 
ufshcd_queuecommand()
       * calls.
@@ -2772,8 +2787,6 @@ static int ufshcd_queuecommand(struct Scsi_Host 
*host, struct scsi_cmnd *cmd)
  out:
      rcu_read_unlock();

-    up_read(&hba->clk_scaling_lock);
-
      if (ufs_trigger_eh()) {
          unsigned long flags;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index c3c2792f309f..411c6015bbfe 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -779,6 +779,7 @@ struct ufs_hba_monitor {
   * @clk_list_head: UFS host controller clocks list node head
   * @pwr_info: holds current power mode
   * @max_pwr_info: keeps the device max valid pwm
+ * @clk_scaling_lock: used to serialize device commands and clock scaling
   * @desc_size: descriptor sizes reported by device
   * @urgent_bkops_lvl: keeps track of urgent bkops level for device
   * @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level 
for

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help