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.org Reviewed-by: Stanley Chu <stanley.chu@mediatek.com> Reviewed-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Bart Van Assche <bvanassche@acm.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
da8badd7d3
commit
d1a7644648
|
@ -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
|
||||
* @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)
|
||||
ufshcd_writel(hba, (1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR);
|
||||
else
|
||||
ufshcd_writel(hba, ~(1 << pos),
|
||||
REG_UTP_TRANSFER_REQ_LIST_CLEAR);
|
||||
mask = ~mask;
|
||||
/*
|
||||
* From the UFSHCI specification: "UTP Transfer Request 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,
|
|||
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;
|
||||
u32 mask = 1 << tag;
|
||||
|
||||
/* clear outstanding transaction before retry */
|
||||
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);
|
||||
|
||||
/*
|
||||
|
@ -2959,7 +2973,7 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba,
|
|||
err = -ETIMEDOUT;
|
||||
dev_dbg(hba->dev, "%s: dev_cmd request timedout, tag %d\n",
|
||||
__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 */
|
||||
err = -EAGAIN;
|
||||
/*
|
||||
|
@ -6982,7 +6996,7 @@ static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd)
|
|||
/* clear the commands that were pending for corresponding LUN */
|
||||
for_each_set_bit(pos, &hba->outstanding_reqs, hba->nutrs) {
|
||||
if (hba->lrb[pos].lun == lun) {
|
||||
err = ufshcd_clear_cmd(hba, pos);
|
||||
err = ufshcd_clear_cmds(hba, 1U << pos);
|
||||
if (err)
|
||||
break;
|
||||
__ufshcd_transfer_req_compl(hba, 1U << pos);
|
||||
|
@ -7084,7 +7098,7 @@ static int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag)
|
|||
goto out;
|
||||
}
|
||||
|
||||
err = ufshcd_clear_cmd(hba, tag);
|
||||
err = ufshcd_clear_cmds(hba, 1U << tag);
|
||||
if (err)
|
||||
dev_err(hba->dev, "%s: Failed clearing cmd at tag %d, err %d\n",
|
||||
__func__, tag, err);
|
||||
|
|
Loading…
Reference in New Issue