Commit d1a76446 authored by Bart Van Assche's avatar Bart Van Assche Committed by Martin K. Petersen

scsi: ufs: Support clearing multiple commands at once

Modify ufshcd_clear_cmd() such that it supports clearing multiple commands
at once instead of one command at a time. This change will be used in a
later patch to reduce the time spent in the reset handler.

Link: https://lore.kernel.org/r/20220613214442.212466-3-bvanassche@acm.orgReviewed-by: default avatarStanley Chu <stanley.chu@mediatek.com>
Reviewed-by: default avatarAdrian Hunter <adrian.hunter@intel.com>
Signed-off-by: default avatarBart Van Assche <bvanassche@acm.org>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent da8badd7
...@@ -748,17 +748,28 @@ static enum utp_ocs ufshcd_get_tr_ocs(struct ufshcd_lrb *lrbp) ...@@ -748,17 +748,28 @@ static enum utp_ocs ufshcd_get_tr_ocs(struct ufshcd_lrb *lrbp)
} }
/** /**
* ufshcd_utrl_clear - Clear a bit in UTRLCLR register * ufshcd_utrl_clear() - Clear requests from the controller request list.
* @hba: per adapter instance * @hba: per adapter instance
* @pos: position of the bit to be cleared * @mask: mask with one bit set for each request to be cleared
*/ */
static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos) static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 mask)
{ {
if (hba->quirks & UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR) if (hba->quirks & UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR)
ufshcd_writel(hba, (1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR); mask = ~mask;
else /*
ufshcd_writel(hba, ~(1 << pos), * From the UFSHCI specification: "UTP Transfer Request List CLear
REG_UTP_TRANSFER_REQ_LIST_CLEAR); * Register (UTRLCLR): This field is bit significant. Each bit
* corresponds to a slot in the UTP Transfer Request List, where bit 0
* corresponds to request slot 0. A bit in this field is set to ‘0’
* by host software to indicate to the host controller that a transfer
* request slot is cleared. The host controller
* shall free up any resources associated to the request slot
* immediately, and shall set the associated bit in UTRLDBR to ‘0’. The
* host software indicates no change to request slots by setting the
* associated bits in this field to ‘1’. Bits in this field shall only
* be set ‘1’ or ‘0’ by host software when UTRLRSR is set to ‘1’."
*/
ufshcd_writel(hba, ~mask, REG_UTP_TRANSFER_REQ_LIST_CLEAR);
} }
/** /**
...@@ -2863,15 +2874,18 @@ static int ufshcd_compose_dev_cmd(struct ufs_hba *hba, ...@@ -2863,15 +2874,18 @@ static int ufshcd_compose_dev_cmd(struct ufs_hba *hba,
return ufshcd_compose_devman_upiu(hba, lrbp); return ufshcd_compose_devman_upiu(hba, lrbp);
} }
static int /*
ufshcd_clear_cmd(struct ufs_hba *hba, int tag) * Clear all the requests from the controller for which a bit has been set in
* @mask and wait until the controller confirms that these requests have been
* cleared.
*/
static int ufshcd_clear_cmds(struct ufs_hba *hba, u32 mask)
{ {
unsigned long flags; unsigned long flags;
u32 mask = 1 << tag;
/* clear outstanding transaction before retry */ /* clear outstanding transaction before retry */
spin_lock_irqsave(hba->host->host_lock, flags); spin_lock_irqsave(hba->host->host_lock, flags);
ufshcd_utrl_clear(hba, tag); ufshcd_utrl_clear(hba, mask);
spin_unlock_irqrestore(hba->host->host_lock, flags); spin_unlock_irqrestore(hba->host->host_lock, flags);
/* /*
...@@ -2959,7 +2973,7 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba, ...@@ -2959,7 +2973,7 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba,
err = -ETIMEDOUT; err = -ETIMEDOUT;
dev_dbg(hba->dev, "%s: dev_cmd request timedout, tag %d\n", dev_dbg(hba->dev, "%s: dev_cmd request timedout, tag %d\n",
__func__, lrbp->task_tag); __func__, lrbp->task_tag);
if (!ufshcd_clear_cmd(hba, lrbp->task_tag)) if (!ufshcd_clear_cmds(hba, 1U << lrbp->task_tag))
/* successfully cleared the command, retry if needed */ /* successfully cleared the command, retry if needed */
err = -EAGAIN; err = -EAGAIN;
/* /*
...@@ -6982,7 +6996,7 @@ static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd) ...@@ -6982,7 +6996,7 @@ static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd)
/* clear the commands that were pending for corresponding LUN */ /* clear the commands that were pending for corresponding LUN */
for_each_set_bit(pos, &hba->outstanding_reqs, hba->nutrs) { for_each_set_bit(pos, &hba->outstanding_reqs, hba->nutrs) {
if (hba->lrb[pos].lun == lun) { if (hba->lrb[pos].lun == lun) {
err = ufshcd_clear_cmd(hba, pos); err = ufshcd_clear_cmds(hba, 1U << pos);
if (err) if (err)
break; break;
__ufshcd_transfer_req_compl(hba, 1U << pos); __ufshcd_transfer_req_compl(hba, 1U << pos);
...@@ -7084,7 +7098,7 @@ static int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag) ...@@ -7084,7 +7098,7 @@ static int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag)
goto out; goto out;
} }
err = ufshcd_clear_cmd(hba, tag); err = ufshcd_clear_cmds(hba, 1U << tag);
if (err) if (err)
dev_err(hba->dev, "%s: Failed clearing cmd at tag %d, err %d\n", dev_err(hba->dev, "%s: Failed clearing cmd at tag %d, err %d\n",
__func__, tag, err); __func__, tag, err);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment