diff mbox series

[RFC,v1,3/4] ufs: mcq: Add support for clean up mcq resources

Message ID 392b790072c2307d366ac80b7552d5f09ae25dfc.1678247309.git.quic_nguyenb@quicinc.com (mailing list archive)
State Superseded
Headers show
Series ufs: core: mcq: Add ufshcd_abort() support in MCQ mode | expand

Commit Message

Bao D. Nguyen March 8, 2023, 4:01 a.m. UTC
Update ufshcd_clear_cmds() 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 <quic_nguyenb@quicinc.com>
---
 drivers/ufs/core/ufshcd.c | 40 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 37 insertions(+), 3 deletions(-)

Comments

Bart Van Assche March 8, 2023, 6:53 p.m. UTC | #1
On 3/7/23 20:01, Bao D. Nguyen wrote:
>   static int ufshcd_clear_cmds(struct ufs_hba *hba, u32 mask)
>   {
>   	unsigned long flags;
> +	int err, result, tag;
>   
> +	if (is_mcq_enabled(hba)) {
> +		/*
> +		 * MCQ mode. Clean up the MCQ resources similar to
> +		 * what the ufshcd_utrl_clear() does for SDB mode.
> +		 */
> +		flags = (unsigned long)mask;
> +		for_each_set_bit(tag, &flags, hba->nutrs) {
> +			err = ufshcd_mcq_sq_cleanup(hba, tag, &result);
> +			if (err || result) {
> +				dev_err(hba->dev, "%s: failed tag=%d. err=%d, result=%d\n",
> +					__func__, tag, err, result);
> +				return FAILED;
> +			}
> +		}
> +		return 0;
> +	}

Please change the type of the 'mask' argument from u32 into unsigned 
long such that the assignment of 'mask' to 'flags' can be removed.

Thanks,

Bart.
Bao D. Nguyen March 8, 2023, 10:27 p.m. UTC | #2
On 3/8/2023 10:53 AM, Bart Van Assche wrote:
> On 3/7/23 20:01, Bao D. Nguyen wrote:
>>   static int ufshcd_clear_cmds(struct ufs_hba *hba, u32 mask)
>>   {
>>       unsigned long flags;
>> +    int err, result, tag;
>>   +    if (is_mcq_enabled(hba)) {
>> +        /*
>> +         * MCQ mode. Clean up the MCQ resources similar to
>> +         * what the ufshcd_utrl_clear() does for SDB mode.
>> +         */
>> +        flags = (unsigned long)mask;
>> +        for_each_set_bit(tag, &flags, hba->nutrs) {
>> +            err = ufshcd_mcq_sq_cleanup(hba, tag, &result);
>> +            if (err || result) {
>> +                dev_err(hba->dev, "%s: failed tag=%d. err=%d, 
>> result=%d\n",
>> +                    __func__, tag, err, result);
>> +                return FAILED;
>> +            }
>> +        }
>> +        return 0;
>> +    }
>
> Please change the type of the 'mask' argument from u32 into unsigned 
> long such that the assignment of 'mask' to 'flags' can be removed.
>
I will make the change in the next rev. Thank you.

> Thanks,
>
> Bart.
diff mbox series

Patch

diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 7e52af6..408c16c 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -2988,7 +2988,26 @@  static int ufshcd_compose_dev_cmd(struct ufs_hba *hba,
 static int ufshcd_clear_cmds(struct ufs_hba *hba, u32 mask)
 {
 	unsigned long flags;
+	int err, result, tag;
 
+	if (is_mcq_enabled(hba)) {
+		/*
+		 * MCQ mode. Clean up the MCQ resources similar to
+		 * what the ufshcd_utrl_clear() does for SDB mode.
+		 */
+		flags = (unsigned long)mask;
+		for_each_set_bit(tag, &flags, hba->nutrs) {
+			err = ufshcd_mcq_sq_cleanup(hba, tag, &result);
+			if (err || result) {
+				dev_err(hba->dev, "%s: failed tag=%d. err=%d, result=%d\n",
+					__func__, tag, err, result);
+				return FAILED;
+			}
+		}
+		return 0;
+	}
+
+	/* Single Doorbell Mode */
 	/* clear outstanding transaction before retry */
 	spin_lock_irqsave(hba->host->host_lock, flags);
 	ufshcd_utrl_clear(hba, mask);
@@ -7344,6 +7363,20 @@  static int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag)
 			 */
 			dev_err(hba->dev, "%s: cmd at tag %d not pending in the device.\n",
 				__func__, tag);
+			if (is_mcq_enabled(hba)) {
+				/* mcq mode */
+				if (!lrbp->cmd) {
+					/* command completed already */
+					dev_err(hba->dev, "%s: cmd at tag=%d is cleared.\n",
+						__func__, tag);
+					goto out;
+				}
+				/* sleep for max. 200us to stabilize */
+				usleep_range(100, 200);
+				continue;
+			}
+
+			/* single door bell mode */
 			reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
 			if (reg & (1 << tag)) {
 				/* sleep for max. 200us to stabilize */
@@ -7410,8 +7443,8 @@  static int ufshcd_abort(struct scsi_cmnd *cmd)
 
 	ufshcd_hold(hba, false);
 	reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
-	/* If command is already aborted/completed, return FAILED. */
-	if (!(test_bit(tag, &hba->outstanding_reqs))) {
+	if (!is_mcq_enabled(hba) && !(test_bit(tag, &hba->outstanding_reqs))) {
+		/* If command is already aborted/completed, return FAILED. */
 		dev_err(hba->dev,
 			"%s: cmd at tag %d already completed, outstanding=0x%lx, doorbell=0x%x\n",
 			__func__, tag, hba->outstanding_reqs, reg);
@@ -7440,7 +7473,8 @@  static int ufshcd_abort(struct scsi_cmnd *cmd)
 	}
 	hba->req_abort_count++;
 
-	if (!(reg & (1 << tag))) {
+	if (!is_mcq_enabled(hba) && !(reg & (1 << tag))) {
+		/* only execute this code in single doorbell mode */
 		dev_err(hba->dev,
 		"%s: cmd was completed, but without a notifying intr, tag = %d",
 		__func__, tag);