Skip to content

Commit adf4526

Browse files
Bao D. Nguyenmartinkpetersen
authored andcommitted
scsi: ufs: mcq: Add support for cleaning up MCQ resources
Update ufshcd_clear_cmd() to clean up the MCQ resources similar to the function ufshcd_utrl_clear() does for SDB mode. Update ufshcd_try_to_abort_task() to support MCQ mode so that this function can be invoked in either mcq or SDB mode. Signed-off-by: Bao D. Nguyen <[email protected]> Link: https://lore.kernel.org/r/dc6d30b3ee55e2072c162b2c08504ba349b87139.1685396241.git.quic_nguyenb@quicinc.com Reviewed-by: Bart Van Assche <[email protected]> Reviewed-by: Stanley Chu <[email protected]> Tested-by: Stanley Chu <[email protected]> Reviewed-by: Can Guo <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent 8d72903 commit adf4526

File tree

2 files changed

+66
-9
lines changed

2 files changed

+66
-9
lines changed

drivers/ufs/core/ufshcd-priv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ struct ufs_hw_queue *ufshcd_mcq_req_to_hwq(struct ufs_hba *hba,
7878
unsigned long ufshcd_mcq_poll_cqe_lock(struct ufs_hba *hba,
7979
struct ufs_hw_queue *hwq);
8080

81+
bool ufshcd_cmd_inflight(struct scsi_cmnd *cmd);
8182
int ufshcd_mcq_sq_cleanup(struct ufs_hba *hba, int task_tag);
8283

8384
#define UFSHCD_MCQ_IO_QUEUE_OFFSET 1

drivers/ufs/core/ufshcd.c

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2997,6 +2997,26 @@ static int ufshcd_compose_dev_cmd(struct ufs_hba *hba,
29972997
return ufshcd_compose_devman_upiu(hba, lrbp);
29982998
}
29992999

3000+
/*
3001+
* Check with the block layer if the command is inflight
3002+
* @cmd: command to check.
3003+
*
3004+
* Returns true if command is inflight; false if not.
3005+
*/
3006+
bool ufshcd_cmd_inflight(struct scsi_cmnd *cmd)
3007+
{
3008+
struct request *rq;
3009+
3010+
if (!cmd)
3011+
return false;
3012+
3013+
rq = scsi_cmd_to_rq(cmd);
3014+
if (!blk_mq_request_started(rq))
3015+
return false;
3016+
3017+
return true;
3018+
}
3019+
30003020
/*
30013021
* Clear the pending command in the controller and wait until
30023022
* the controller confirms that the command has been cleared.
@@ -3005,8 +3025,23 @@ static int ufshcd_compose_dev_cmd(struct ufs_hba *hba,
30053025
*/
30063026
static int ufshcd_clear_cmd(struct ufs_hba *hba, u32 task_tag)
30073027
{
3008-
unsigned long flags;
30093028
u32 mask = 1U << task_tag;
3029+
unsigned long flags;
3030+
int err;
3031+
3032+
if (is_mcq_enabled(hba)) {
3033+
/*
3034+
* MCQ mode. Clean up the MCQ resources similar to
3035+
* what the ufshcd_utrl_clear() does for SDB mode.
3036+
*/
3037+
err = ufshcd_mcq_sq_cleanup(hba, task_tag);
3038+
if (err) {
3039+
dev_err(hba->dev, "%s: failed tag=%d. err=%d\n",
3040+
__func__, task_tag, err);
3041+
return err;
3042+
}
3043+
return 0;
3044+
}
30103045

30113046
/* clear outstanding transaction before retry */
30123047
spin_lock_irqsave(hba->host->host_lock, flags);
@@ -7377,6 +7412,20 @@ static int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag)
73777412
*/
73787413
dev_err(hba->dev, "%s: cmd at tag %d not pending in the device.\n",
73797414
__func__, tag);
7415+
if (is_mcq_enabled(hba)) {
7416+
/* MCQ mode */
7417+
if (ufshcd_cmd_inflight(lrbp->cmd)) {
7418+
/* sleep for max. 200us same delay as in SDB mode */
7419+
usleep_range(100, 200);
7420+
continue;
7421+
}
7422+
/* command completed already */
7423+
dev_err(hba->dev, "%s: cmd at tag=%d is cleared.\n",
7424+
__func__, tag);
7425+
goto out;
7426+
}
7427+
7428+
/* Single Doorbell Mode */
73807429
reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
73817430
if (reg & (1 << tag)) {
73827431
/* sleep for max. 200us to stabilize */
@@ -7442,13 +7491,16 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
74427491
WARN_ONCE(tag < 0, "Invalid tag %d\n", tag);
74437492

74447493
ufshcd_hold(hba, false);
7445-
reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
7446-
/* If command is already aborted/completed, return FAILED. */
7447-
if (!(test_bit(tag, &hba->outstanding_reqs))) {
7448-
dev_err(hba->dev,
7449-
"%s: cmd at tag %d already completed, outstanding=0x%lx, doorbell=0x%x\n",
7450-
__func__, tag, hba->outstanding_reqs, reg);
7451-
goto release;
7494+
7495+
if (!is_mcq_enabled(hba)) {
7496+
reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
7497+
if (!test_bit(tag, &hba->outstanding_reqs)) {
7498+
/* If command is already aborted/completed, return FAILED. */
7499+
dev_err(hba->dev,
7500+
"%s: cmd at tag %d already completed, outstanding=0x%lx, doorbell=0x%x\n",
7501+
__func__, tag, hba->outstanding_reqs, reg);
7502+
goto release;
7503+
}
74527504
}
74537505

74547506
/* Print Transfer Request of aborted task */
@@ -7473,7 +7525,8 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
74737525
}
74747526
hba->req_abort_count++;
74757527

7476-
if (!(reg & (1 << tag))) {
7528+
if (!is_mcq_enabled(hba) && !(reg & (1 << tag))) {
7529+
/* only execute this code in single doorbell mode */
74777530
dev_err(hba->dev,
74787531
"%s: cmd was completed, but without a notifying intr, tag = %d",
74797532
__func__, tag);
@@ -7499,6 +7552,9 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
74997552
goto release;
75007553
}
75017554

7555+
if (is_mcq_enabled(hba))
7556+
goto release;
7557+
75027558
/* Skip task abort in case previous aborts failed and report failure */
75037559
if (lrbp->req_abort_skip) {
75047560
dev_err(hba->dev, "%s: skipping abort\n", __func__);

0 commit comments

Comments
 (0)