Skip to content

Commit 8d077ed

Browse files
bvanasschemartinkpetersen
authored andcommitted
scsi: ufs: Optimize the command queueing code
Remove the clock scaling lock from ufshcd_queuecommand() since it is a performance bottleneck. Instead check the SCSI device budget bitmaps in the code that waits for ongoing ufshcd_queuecommand() calls. A bit is set in sdev->budget_map just before scsi_queue_rq() is called and a bit is cleared from that bitmap if scsi_queue_rq() does not submit the request or after the request has finished. See also the blk_mq_{get,put}_dispatch_budget() calls in the block layer. There is no risk for a livelock since the block layer delays queue reruns if queueing a request fails because the SCSI host has been blocked. Link: https://lore.kernel.org/r/[email protected] Cc: Asutosh Das (asd) <[email protected]> Reviewed-by: Asutosh Das <[email protected]> Signed-off-by: Bart Van Assche <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent 5675c38 commit 8d077ed

File tree

2 files changed

+24
-10
lines changed

2 files changed

+24
-10
lines changed

drivers/scsi/ufs/ufshcd.c

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,13 +1070,31 @@ static bool ufshcd_is_devfreq_scaling_required(struct ufs_hba *hba,
10701070
return false;
10711071
}
10721072

1073+
/*
1074+
* Determine the number of pending commands by counting the bits in the SCSI
1075+
* device budget maps. This approach has been selected because a bit is set in
1076+
* the budget map before scsi_host_queue_ready() checks the host_self_blocked
1077+
* flag. The host_self_blocked flag can be modified by calling
1078+
* scsi_block_requests() or scsi_unblock_requests().
1079+
*/
1080+
static u32 ufshcd_pending_cmds(struct ufs_hba *hba)
1081+
{
1082+
struct scsi_device *sdev;
1083+
u32 pending = 0;
1084+
1085+
shost_for_each_device(sdev, hba->host)
1086+
pending += sbitmap_weight(&sdev->budget_map);
1087+
1088+
return pending;
1089+
}
1090+
10731091
static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba,
10741092
u64 wait_timeout_us)
10751093
{
10761094
unsigned long flags;
10771095
int ret = 0;
10781096
u32 tm_doorbell;
1079-
u32 tr_doorbell;
1097+
u32 tr_pending;
10801098
bool timeout = false, do_last_check = false;
10811099
ktime_t start;
10821100

@@ -1094,8 +1112,8 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba,
10941112
}
10951113

10961114
tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
1097-
tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
1098-
if (!tm_doorbell && !tr_doorbell) {
1115+
tr_pending = ufshcd_pending_cmds(hba);
1116+
if (!tm_doorbell && !tr_pending) {
10991117
timeout = false;
11001118
break;
11011119
} else if (do_last_check) {
@@ -1115,12 +1133,12 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba,
11151133
do_last_check = true;
11161134
}
11171135
spin_lock_irqsave(hba->host->host_lock, flags);
1118-
} while (tm_doorbell || tr_doorbell);
1136+
} while (tm_doorbell || tr_pending);
11191137

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

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

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

2775-
up_read(&hba->clk_scaling_lock);
2776-
27772790
if (ufs_trigger_eh()) {
27782791
unsigned long flags;
27792792

drivers/scsi/ufs/ufshcd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,7 @@ struct ufs_hba_monitor {
778778
* @clk_list_head: UFS host controller clocks list node head
779779
* @pwr_info: holds current power mode
780780
* @max_pwr_info: keeps the device max valid pwm
781+
* @clk_scaling_lock: used to serialize device commands and clock scaling
781782
* @desc_size: descriptor sizes reported by device
782783
* @urgent_bkops_lvl: keeps track of urgent bkops level for device
783784
* @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level for

0 commit comments

Comments
 (0)