* [RESEND PATCH v1 0/2] Add UFS LINERESET handling
@ 2020-08-25 2:07 Can Guo
2020-08-25 2:07 ` [PATCH v1 1/2] scsi: ufs: Abort tasks before clear them from doorbell Can Guo
` (2 more replies)
0 siblings, 3 replies; 11+ messages in thread
From: Can Guo @ 2020-08-25 2:07 UTC (permalink / raw)
To: asutoshd, nguyenb, hongwus, rnayak, linux-scsi, kernel-team,
saravanak, salyzyn, cang
PA Layer issues a LINERESET to the PHY at the recovery step in the Power
Mode change operation. If it happens during auto or mannual hibern8 enter,
even if hibern8 enter succeeds, UFS power mode shall be set to PWM-G1 mode
and kept in that mode after exit from hibern8, leading to bad performance.
Handle the LINERESET in the eh_work by restoring power mode to HS mode
after all pending reqs and tasks are cleared from doorbell.
Can Guo (2):
scsi: ufs: Abort tasks before clear them from doorbell
scsi: ufs: Handle LINERESET indication in err handler
drivers/scsi/ufs/ufshcd.c | 254 ++++++++++++++++++++++++++++++++--------------
drivers/scsi/ufs/ufshcd.h | 2 +
drivers/scsi/ufs/ufshci.h | 1 +
drivers/scsi/ufs/unipro.h | 3 +
4 files changed, 184 insertions(+), 76 deletions(-)
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH v1 1/2] scsi: ufs: Abort tasks before clear them from doorbell 2020-08-25 2:07 [RESEND PATCH v1 0/2] Add UFS LINERESET handling Can Guo @ 2020-08-25 2:07 ` Can Guo 2020-08-27 8:37 ` Stanley Chu 2020-08-30 18:11 ` Bean Huo 2020-08-25 2:07 ` [PATCH v1 2/2] scsi: ufs: Handle LINERESET indication in err handler Can Guo 2020-09-09 2:09 ` [RESEND PATCH v1 0/2] Add UFS LINERESET handling Martin K. Petersen 2 siblings, 2 replies; 11+ messages in thread From: Can Guo @ 2020-08-25 2:07 UTC (permalink / raw) To: asutoshd, nguyenb, hongwus, rnayak, linux-scsi, kernel-team, saravanak, salyzyn, cang Cc: Alim Akhtar, Avri Altman, James E.J. Bottomley, Martin K. Petersen, Stanley Chu, Bean Huo, Bart Van Assche, open list To recovery non-fatal errors, no full reset is required, err_handler only clears those pending TRs/TMRs so that scsi layer can re-issue them. In current err_handler, TRs are directly cleared from UFS host's doorbell but not aborted from device side. However, according to the UFSHCI JEDEC spec, the host software shall use UTP Transfer Request List CLear Register to clear a task from UFS host's doorbell only when a UTP Transfer Request is expected to not be completed, e.g. when the host software receives a “FUNCTION COMPLETE” Task Management response which means a Transfer Request was aborted. To follow the UFSHCI JEDEC spec, in err_handler, aborts one TR before clearing it from doorbell. Signed-off-by: Can Guo <cang@codeaurora.org> --- drivers/scsi/ufs/ufshcd.c | 143 ++++++++++++++++++++++++++-------------------- 1 file changed, 81 insertions(+), 62 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index b8441ad..000895f 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -235,6 +235,7 @@ static int ufshcd_setup_hba_vreg(struct ufs_hba *hba, bool on); static int ufshcd_setup_vreg(struct ufs_hba *hba, bool on); static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba, struct ufs_vreg *vreg); +static int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag); static int ufshcd_wb_buf_flush_enable(struct ufs_hba *hba); static int ufshcd_wb_buf_flush_disable(struct ufs_hba *hba); static int ufshcd_wb_ctrl(struct ufs_hba *hba, bool enable); @@ -5657,8 +5658,8 @@ static void ufshcd_err_handler(struct work_struct *work) { struct ufs_hba *hba; unsigned long flags; - u32 err_xfer = 0; - u32 err_tm = 0; + bool err_xfer = false; + bool err_tm = false; int err = 0; int tag; bool needs_reset = false; @@ -5734,7 +5735,7 @@ static void ufshcd_err_handler(struct work_struct *work) spin_unlock_irqrestore(hba->host->host_lock, flags); /* Clear pending transfer requests */ for_each_set_bit(tag, &hba->outstanding_reqs, hba->nutrs) { - if (ufshcd_clear_cmd(hba, tag)) { + if (ufshcd_try_to_abort_task(hba, tag)) { err_xfer = true; goto lock_skip_pending_xfer_clear; } @@ -6486,7 +6487,7 @@ static void ufshcd_set_req_abort_skip(struct ufs_hba *hba, unsigned long bitmap) } /** - * ufshcd_abort - abort a specific command + * ufshcd_try_to_abort_task - abort a specific task * @cmd: SCSI command pointer * * Abort the pending command in device by sending UFS_ABORT_TASK task management @@ -6495,6 +6496,80 @@ static void ufshcd_set_req_abort_skip(struct ufs_hba *hba, unsigned long bitmap) * issued. To avoid that, first issue UFS_QUERY_TASK to check if the command is * really issued and then try to abort it. * + * Returns zero on success, non-zero on failure + */ +static int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag) +{ + struct ufshcd_lrb *lrbp = &hba->lrb[tag]; + int err = 0; + int poll_cnt; + u8 resp = 0xF; + u32 reg; + + for (poll_cnt = 100; poll_cnt; poll_cnt--) { + err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag, + UFS_QUERY_TASK, &resp); + if (!err && resp == UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED) { + /* cmd pending in the device */ + dev_err(hba->dev, "%s: cmd pending in the device. tag = %d\n", + __func__, tag); + break; + } else if (!err && resp == UPIU_TASK_MANAGEMENT_FUNC_COMPL) { + /* + * cmd not pending in the device, check if it is + * in transition. + */ + dev_err(hba->dev, "%s: cmd at tag %d not pending in the device.\n", + __func__, tag); + reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); + if (reg & (1 << tag)) { + /* sleep for max. 200us to stabilize */ + usleep_range(100, 200); + continue; + } + /* command completed already */ + dev_err(hba->dev, "%s: cmd at tag %d successfully cleared from DB.\n", + __func__, tag); + goto out; + } else { + dev_err(hba->dev, + "%s: no response from device. tag = %d, err %d\n", + __func__, tag, err); + if (!err) + err = resp; /* service response error */ + goto out; + } + } + + if (!poll_cnt) { + err = -EBUSY; + goto out; + } + + err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag, + UFS_ABORT_TASK, &resp); + if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) { + if (!err) { + err = resp; /* service response error */ + dev_err(hba->dev, "%s: issued. tag = %d, err %d\n", + __func__, tag, err); + } + goto out; + } + + err = ufshcd_clear_cmd(hba, tag); + if (err) + dev_err(hba->dev, "%s: Failed clearing cmd at tag %d, err %d\n", + __func__, tag, err); + +out: + return err; +} + +/** + * ufshcd_abort - scsi host template eh_abort_handler callback + * @cmd: SCSI command pointer + * * Returns SUCCESS/FAILED */ static int ufshcd_abort(struct scsi_cmnd *cmd) @@ -6504,8 +6579,6 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) unsigned long flags; unsigned int tag; int err = 0; - int poll_cnt; - u8 resp = 0xF; struct ufshcd_lrb *lrbp; u32 reg; @@ -6574,63 +6647,9 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) goto out; } - for (poll_cnt = 100; poll_cnt; poll_cnt--) { - err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag, - UFS_QUERY_TASK, &resp); - if (!err && resp == UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED) { - /* cmd pending in the device */ - dev_err(hba->dev, "%s: cmd pending in the device. tag = %d\n", - __func__, tag); - break; - } else if (!err && resp == UPIU_TASK_MANAGEMENT_FUNC_COMPL) { - /* - * cmd not pending in the device, check if it is - * in transition. - */ - dev_err(hba->dev, "%s: cmd at tag %d not pending in the device.\n", - __func__, tag); - reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); - if (reg & (1 << tag)) { - /* sleep for max. 200us to stabilize */ - usleep_range(100, 200); - continue; - } - /* command completed already */ - dev_err(hba->dev, "%s: cmd at tag %d successfully cleared from DB.\n", - __func__, tag); - goto out; - } else { - dev_err(hba->dev, - "%s: no response from device. tag = %d, err %d\n", - __func__, tag, err); - if (!err) - err = resp; /* service response error */ - goto out; - } - } - - if (!poll_cnt) { - err = -EBUSY; - goto out; - } - - err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag, - UFS_ABORT_TASK, &resp); - if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) { - if (!err) { - err = resp; /* service response error */ - dev_err(hba->dev, "%s: issued. tag = %d, err %d\n", - __func__, tag, err); - } - goto out; - } - - err = ufshcd_clear_cmd(hba, tag); - if (err) { - dev_err(hba->dev, "%s: Failed clearing cmd at tag %d, err %d\n", - __func__, tag, err); + err = ufshcd_try_to_abort_task(hba, tag); + if (err) goto out; - } spin_lock_irqsave(host->host_lock, flags); __ufshcd_transfer_req_compl(hba, (1UL << tag)); -- Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project. ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v1 1/2] scsi: ufs: Abort tasks before clear them from doorbell 2020-08-25 2:07 ` [PATCH v1 1/2] scsi: ufs: Abort tasks before clear them from doorbell Can Guo @ 2020-08-27 8:37 ` Stanley Chu 2020-08-30 18:11 ` Bean Huo 1 sibling, 0 replies; 11+ messages in thread From: Stanley Chu @ 2020-08-27 8:37 UTC (permalink / raw) To: Can Guo Cc: asutoshd, nguyenb, hongwus, rnayak, linux-scsi, kernel-team, saravanak, salyzyn, Alim Akhtar, Avri Altman, James E.J. Bottomley, Martin K. Petersen, Bean Huo, Bart Van Assche, open list On Mon, 2020-08-24 at 19:07 -0700, Can Guo wrote: > To recovery non-fatal errors, no full reset is required, err_handler only > clears those pending TRs/TMRs so that scsi layer can re-issue them. In > current err_handler, TRs are directly cleared from UFS host's doorbell but > not aborted from device side. However, according to the UFSHCI JEDEC spec, > the host software shall use UTP Transfer Request List CLear Register to > clear a task from UFS host's doorbell only when a UTP Transfer Request is > expected to not be completed, e.g. when the host software receives a > “FUNCTION COMPLETE” Task Management response which means a Transfer Request > was aborted. To follow the UFSHCI JEDEC spec, in err_handler, aborts one TR > before clearing it from doorbell. > > Signed-off-by: Can Guo <cang@codeaurora.org> Acked-by: Stanley Chu <stanley.chu@mediatek.com> ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v1 1/2] scsi: ufs: Abort tasks before clear them from doorbell 2020-08-25 2:07 ` [PATCH v1 1/2] scsi: ufs: Abort tasks before clear them from doorbell Can Guo 2020-08-27 8:37 ` Stanley Chu @ 2020-08-30 18:11 ` Bean Huo 2020-08-31 1:20 ` Can Guo 1 sibling, 1 reply; 11+ messages in thread From: Bean Huo @ 2020-08-30 18:11 UTC (permalink / raw) To: Can Guo, asutoshd, nguyenb, hongwus, rnayak, linux-scsi, kernel-team, saravanak, salyzyn Cc: Alim Akhtar, Avri Altman, James E.J. Bottomley, Martin K. Petersen, Stanley Chu, Bean Huo, Bart Van Assche, open list Hi Can This patch conflicts and be not in line with this series patches : h ttps://patchwork.kernel.org/cover/11709279/, which has been applied into 5.9/scsi-fixes. But they are not apppiled in the 5.9/scsi-queue. Maybe you should rebase your patch from scsi-fixes branch. or do you have another better option? Thanks, Bean On Mon, 2020-08-24 at 19:07 -0700, Can Guo wrote: > To recovery non-fatal errors, no full reset is required, err_handler > only > clears those pending TRs/TMRs so that scsi layer can re-issue them. > In > current err_handler, TRs are directly cleared from UFS host's > doorbell but > not aborted from device side. However, according to the UFSHCI JEDEC > spec, > the host software shall use UTP Transfer Request List CLear Register > to > clear a task from UFS host's doorbell only when a UTP Transfer > Request is > expected to not be completed, e.g. when the host software receives a > “FUNCTION COMPLETE” Task Management response which means a Transfer > Request > was aborted. To follow the UFSHCI JEDEC spec, in err_handler, aborts > one TR > before clearing it from doorbell. > > Signed-off-by: Can Guo <cang@codeaurora.org> > --- > drivers/scsi/ufs/ufshcd.c | 143 ++++++++++++++++++++++++++-------- > ------------ > 1 file changed, 81 insertions(+), 62 deletions(-) > > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c > index b8441ad..000895f 100644 > --- a/drivers/scsi/ufs/ufshcd.c > +++ b/drivers/scsi/ufs/ufshcd.c > @@ -235,6 +235,7 @@ static int ufshcd_setup_hba_vreg(struct ufs_hba > *hba, bool on); > static int ufshcd_setup_vreg(struct ufs_hba *hba, bool on); > static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba, > struct ufs_vreg *vreg); > +static int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag); > static int ufshcd_wb_buf_flush_enable(struct ufs_hba *hba); > static int ufshcd_wb_buf_flush_disable(struct ufs_hba *hba); > static int ufshcd_wb_ctrl(struct ufs_hba *hba, bool enable); > @@ -5657,8 +5658,8 @@ static void ufshcd_err_handler(struct > work_struct *work) > { > struct ufs_hba *hba; > unsigned long flags; > - u32 err_xfer = 0; > - u32 err_tm = 0; > + bool err_xfer = false; > + bool err_tm = false; > int err = 0; > int tag; > bool needs_reset = false; > @@ -5734,7 +5735,7 @@ static void ufshcd_err_handler(struct > work_struct *work) > spin_unlock_irqrestore(hba->host->host_lock, flags); > /* Clear pending transfer requests */ > for_each_set_bit(tag, &hba->outstanding_reqs, hba->nutrs) { > - if (ufshcd_clear_cmd(hba, tag)) { > + if (ufshcd_try_to_abort_task(hba, tag)) { > err_xfer = true; > goto lock_skip_pending_xfer_clear; > } > @@ -6486,7 +6487,7 @@ static void ufshcd_set_req_abort_skip(struct > ufs_hba *hba, unsigned long bitmap) > } > > /** > - * ufshcd_abort - abort a specific command > + * ufshcd_try_to_abort_task - abort a specific task > * @cmd: SCSI command pointer > * > * Abort the pending command in device by sending UFS_ABORT_TASK > task management > @@ -6495,6 +6496,80 @@ static void ufshcd_set_req_abort_skip(struct > ufs_hba *hba, unsigned long bitmap) > * issued. To avoid that, first issue UFS_QUERY_TASK to check if the > command is > * really issued and then try to abort it. > * > + * Returns zero on success, non-zero on failure > + */ > +static int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag) > +{ > + struct ufshcd_lrb *lrbp = &hba->lrb[tag]; > + int err = 0; > + int poll_cnt; > + u8 resp = 0xF; > + u32 reg; > + > + for (poll_cnt = 100; poll_cnt; poll_cnt--) { > + err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp- > >task_tag, > + UFS_QUERY_TASK, &resp); > + if (!err && resp == > UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED) { > + /* cmd pending in the device */ > + dev_err(hba->dev, "%s: cmd pending in the > device. tag = %d\n", > + __func__, tag); > + break; > + } else if (!err && resp == > UPIU_TASK_MANAGEMENT_FUNC_COMPL) { > + /* > + * cmd not pending in the device, check if it > is > + * in transition. > + */ > + dev_err(hba->dev, "%s: cmd at tag %d not > pending in the device.\n", > + __func__, tag); > + reg = ufshcd_readl(hba, > REG_UTP_TRANSFER_REQ_DOOR_BELL); > + if (reg & (1 << tag)) { > + /* sleep for max. 200us to stabilize */ > + usleep_range(100, 200); > + continue; > + } > + /* command completed already */ > + dev_err(hba->dev, "%s: cmd at tag %d > successfully cleared from DB.\n", > + __func__, tag); > + goto out; > + } else { > + dev_err(hba->dev, > + "%s: no response from device. tag = %d, > err %d\n", > + __func__, tag, err); > + if (!err) > + err = resp; /* service response error > */ > + goto out; > + } > + } > + > + if (!poll_cnt) { > + err = -EBUSY; > + goto out; > + } > + > + err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag, > + UFS_ABORT_TASK, &resp); > + if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) { > + if (!err) { > + err = resp; /* service response error */ > + dev_err(hba->dev, "%s: issued. tag = %d, err > %d\n", > + __func__, tag, err); > + } > + goto out; > + } > + > + err = ufshcd_clear_cmd(hba, tag); > + if (err) > + dev_err(hba->dev, "%s: Failed clearing cmd at tag %d, > err %d\n", > + __func__, tag, err); > + > +out: > + return err; > +} > + > +/** > + * ufshcd_abort - scsi host template eh_abort_handler callback > + * @cmd: SCSI command pointer > + * > * Returns SUCCESS/FAILED > */ > static int ufshcd_abort(struct scsi_cmnd *cmd) > @@ -6504,8 +6579,6 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) > unsigned long flags; > unsigned int tag; > int err = 0; > - int poll_cnt; > - u8 resp = 0xF; > struct ufshcd_lrb *lrbp; > u32 reg; > > @@ -6574,63 +6647,9 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) > goto out; > } > > - for (poll_cnt = 100; poll_cnt; poll_cnt--) { > - err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp- > >task_tag, > - UFS_QUERY_TASK, &resp); > - if (!err && resp == > UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED) { > - /* cmd pending in the device */ > - dev_err(hba->dev, "%s: cmd pending in the > device. tag = %d\n", > - __func__, tag); > - break; > - } else if (!err && resp == > UPIU_TASK_MANAGEMENT_FUNC_COMPL) { > - /* > - * cmd not pending in the device, check if it > is > - * in transition. > - */ > - dev_err(hba->dev, "%s: cmd at tag %d not > pending in the device.\n", > - __func__, tag); > - reg = ufshcd_readl(hba, > REG_UTP_TRANSFER_REQ_DOOR_BELL); > - if (reg & (1 << tag)) { > - /* sleep for max. 200us to stabilize */ > - usleep_range(100, 200); > - continue; > - } > - /* command completed already */ > - dev_err(hba->dev, "%s: cmd at tag %d > successfully cleared from DB.\n", > - __func__, tag); > - goto out; > - } else { > - dev_err(hba->dev, > - "%s: no response from device. tag = %d, > err %d\n", > - __func__, tag, err); > - if (!err) > - err = resp; /* service response error > */ > - goto out; > - } > - } > - > - if (!poll_cnt) { > - err = -EBUSY; > - goto out; > - } > - > - err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag, > - UFS_ABORT_TASK, &resp); > - if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) { > - if (!err) { > - err = resp; /* service response error */ > - dev_err(hba->dev, "%s: issued. tag = %d, err > %d\n", > - __func__, tag, err); > - } > - goto out; > - } > - > - err = ufshcd_clear_cmd(hba, tag); > - if (err) { > - dev_err(hba->dev, "%s: Failed clearing cmd at tag %d, > err %d\n", > - __func__, tag, err); > + err = ufshcd_try_to_abort_task(hba, tag); > + if (err) > goto out; > - } > > spin_lock_irqsave(host->host_lock, flags); > __ufshcd_transfer_req_compl(hba, (1UL << tag)); ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v1 1/2] scsi: ufs: Abort tasks before clear them from doorbell 2020-08-30 18:11 ` Bean Huo @ 2020-08-31 1:20 ` Can Guo 2020-08-31 19:38 ` Bean Huo 0 siblings, 1 reply; 11+ messages in thread From: Can Guo @ 2020-08-31 1:20 UTC (permalink / raw) To: Bean Huo Cc: asutoshd, nguyenb, hongwus, rnayak, linux-scsi, kernel-team, saravanak, salyzyn, Alim Akhtar, Avri Altman, James E.J. Bottomley, Martin K. Petersen, Stanley Chu, Bean Huo, Bart Van Assche, open list Hi Bean, On 2020-08-31 02:11, Bean Huo wrote: > Hi Can > This patch conflicts and be not in line with this series patches : h > ttps://patchwork.kernel.org/cover/11709279/, which has been applied > into 5.9/scsi-fixes. But they are not apppiled in the 5.9/scsi-queue. > > Maybe you should rebase your patch from scsi-fixes branch. or do you > have another better option? > > Thanks, > Bean > I am pushing this change due to LINERSET handling needs it and LINERESET handling is added based on my previous changes to err_handler, which are picked by 5.10/scsi-queue. So the two are applied for 5.10/scsi-queue only. Any conflicts you see on 5.10/scsi-queue? Thanks, Can Guo. > On Mon, 2020-08-24 at 19:07 -0700, Can Guo wrote: >> To recovery non-fatal errors, no full reset is required, err_handler >> only >> clears those pending TRs/TMRs so that scsi layer can re-issue them. >> In >> current err_handler, TRs are directly cleared from UFS host's >> doorbell but >> not aborted from device side. However, according to the UFSHCI JEDEC >> spec, >> the host software shall use UTP Transfer Request List CLear Register >> to >> clear a task from UFS host's doorbell only when a UTP Transfer >> Request is >> expected to not be completed, e.g. when the host software receives a >> “FUNCTION COMPLETE” Task Management response which means a Transfer >> Request >> was aborted. To follow the UFSHCI JEDEC spec, in err_handler, aborts >> one TR >> before clearing it from doorbell. >> >> Signed-off-by: Can Guo <cang@codeaurora.org> >> --- >> drivers/scsi/ufs/ufshcd.c | 143 ++++++++++++++++++++++++++-------- >> ------------ >> 1 file changed, 81 insertions(+), 62 deletions(-) >> >> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c >> index b8441ad..000895f 100644 >> --- a/drivers/scsi/ufs/ufshcd.c >> +++ b/drivers/scsi/ufs/ufshcd.c >> @@ -235,6 +235,7 @@ static int ufshcd_setup_hba_vreg(struct ufs_hba >> *hba, bool on); >> static int ufshcd_setup_vreg(struct ufs_hba *hba, bool on); >> static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba, >> struct ufs_vreg *vreg); >> +static int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag); >> static int ufshcd_wb_buf_flush_enable(struct ufs_hba *hba); >> static int ufshcd_wb_buf_flush_disable(struct ufs_hba *hba); >> static int ufshcd_wb_ctrl(struct ufs_hba *hba, bool enable); >> @@ -5657,8 +5658,8 @@ static void ufshcd_err_handler(struct >> work_struct *work) >> { >> struct ufs_hba *hba; >> unsigned long flags; >> - u32 err_xfer = 0; >> - u32 err_tm = 0; >> + bool err_xfer = false; >> + bool err_tm = false; >> int err = 0; >> int tag; >> bool needs_reset = false; >> @@ -5734,7 +5735,7 @@ static void ufshcd_err_handler(struct >> work_struct *work) >> spin_unlock_irqrestore(hba->host->host_lock, flags); >> /* Clear pending transfer requests */ >> for_each_set_bit(tag, &hba->outstanding_reqs, hba->nutrs) { >> - if (ufshcd_clear_cmd(hba, tag)) { >> + if (ufshcd_try_to_abort_task(hba, tag)) { >> err_xfer = true; >> goto lock_skip_pending_xfer_clear; >> } >> @@ -6486,7 +6487,7 @@ static void ufshcd_set_req_abort_skip(struct >> ufs_hba *hba, unsigned long bitmap) >> } >> >> /** >> - * ufshcd_abort - abort a specific command >> + * ufshcd_try_to_abort_task - abort a specific task >> * @cmd: SCSI command pointer >> * >> * Abort the pending command in device by sending UFS_ABORT_TASK >> task management >> @@ -6495,6 +6496,80 @@ static void ufshcd_set_req_abort_skip(struct >> ufs_hba *hba, unsigned long bitmap) >> * issued. To avoid that, first issue UFS_QUERY_TASK to check if the >> command is >> * really issued and then try to abort it. >> * >> + * Returns zero on success, non-zero on failure >> + */ >> +static int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag) >> +{ >> + struct ufshcd_lrb *lrbp = &hba->lrb[tag]; >> + int err = 0; >> + int poll_cnt; >> + u8 resp = 0xF; >> + u32 reg; >> + >> + for (poll_cnt = 100; poll_cnt; poll_cnt--) { >> + err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp- >> >task_tag, >> + UFS_QUERY_TASK, &resp); >> + if (!err && resp == >> UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED) { >> + /* cmd pending in the device */ >> + dev_err(hba->dev, "%s: cmd pending in the >> device. tag = %d\n", >> + __func__, tag); >> + break; >> + } else if (!err && resp == >> UPIU_TASK_MANAGEMENT_FUNC_COMPL) { >> + /* >> + * cmd not pending in the device, check if it >> is >> + * in transition. >> + */ >> + dev_err(hba->dev, "%s: cmd at tag %d not >> pending in the device.\n", >> + __func__, tag); >> + reg = ufshcd_readl(hba, >> REG_UTP_TRANSFER_REQ_DOOR_BELL); >> + if (reg & (1 << tag)) { >> + /* sleep for max. 200us to stabilize */ >> + usleep_range(100, 200); >> + continue; >> + } >> + /* command completed already */ >> + dev_err(hba->dev, "%s: cmd at tag %d >> successfully cleared from DB.\n", >> + __func__, tag); >> + goto out; >> + } else { >> + dev_err(hba->dev, >> + "%s: no response from device. tag = %d, >> err %d\n", >> + __func__, tag, err); >> + if (!err) >> + err = resp; /* service response error >> */ >> + goto out; >> + } >> + } >> + >> + if (!poll_cnt) { >> + err = -EBUSY; >> + goto out; >> + } >> + >> + err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag, >> + UFS_ABORT_TASK, &resp); >> + if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) { >> + if (!err) { >> + err = resp; /* service response error */ >> + dev_err(hba->dev, "%s: issued. tag = %d, err >> %d\n", >> + __func__, tag, err); >> + } >> + goto out; >> + } >> + >> + err = ufshcd_clear_cmd(hba, tag); >> + if (err) >> + dev_err(hba->dev, "%s: Failed clearing cmd at tag %d, >> err %d\n", >> + __func__, tag, err); >> + >> +out: >> + return err; >> +} >> + >> +/** >> + * ufshcd_abort - scsi host template eh_abort_handler callback >> + * @cmd: SCSI command pointer >> + * >> * Returns SUCCESS/FAILED >> */ >> static int ufshcd_abort(struct scsi_cmnd *cmd) >> @@ -6504,8 +6579,6 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) >> unsigned long flags; >> unsigned int tag; >> int err = 0; >> - int poll_cnt; >> - u8 resp = 0xF; >> struct ufshcd_lrb *lrbp; >> u32 reg; >> >> @@ -6574,63 +6647,9 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) >> goto out; >> } >> >> - for (poll_cnt = 100; poll_cnt; poll_cnt--) { >> - err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp- >> >task_tag, >> - UFS_QUERY_TASK, &resp); >> - if (!err && resp == >> UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED) { >> - /* cmd pending in the device */ >> - dev_err(hba->dev, "%s: cmd pending in the >> device. tag = %d\n", >> - __func__, tag); >> - break; >> - } else if (!err && resp == >> UPIU_TASK_MANAGEMENT_FUNC_COMPL) { >> - /* >> - * cmd not pending in the device, check if it >> is >> - * in transition. >> - */ >> - dev_err(hba->dev, "%s: cmd at tag %d not >> pending in the device.\n", >> - __func__, tag); >> - reg = ufshcd_readl(hba, >> REG_UTP_TRANSFER_REQ_DOOR_BELL); >> - if (reg & (1 << tag)) { >> - /* sleep for max. 200us to stabilize */ >> - usleep_range(100, 200); >> - continue; >> - } >> - /* command completed already */ >> - dev_err(hba->dev, "%s: cmd at tag %d >> successfully cleared from DB.\n", >> - __func__, tag); >> - goto out; >> - } else { >> - dev_err(hba->dev, >> - "%s: no response from device. tag = %d, >> err %d\n", >> - __func__, tag, err); >> - if (!err) >> - err = resp; /* service response error >> */ >> - goto out; >> - } >> - } >> - >> - if (!poll_cnt) { >> - err = -EBUSY; >> - goto out; >> - } >> - >> - err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag, >> - UFS_ABORT_TASK, &resp); >> - if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) { >> - if (!err) { >> - err = resp; /* service response error */ >> - dev_err(hba->dev, "%s: issued. tag = %d, err >> %d\n", >> - __func__, tag, err); >> - } >> - goto out; >> - } >> - >> - err = ufshcd_clear_cmd(hba, tag); >> - if (err) { >> - dev_err(hba->dev, "%s: Failed clearing cmd at tag %d, >> err %d\n", >> - __func__, tag, err); >> + err = ufshcd_try_to_abort_task(hba, tag); >> + if (err) >> goto out; >> - } >> >> spin_lock_irqsave(host->host_lock, flags); >> __ufshcd_transfer_req_compl(hba, (1UL << tag)); ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v1 1/2] scsi: ufs: Abort tasks before clear them from doorbell 2020-08-31 1:20 ` Can Guo @ 2020-08-31 19:38 ` Bean Huo 0 siblings, 0 replies; 11+ messages in thread From: Bean Huo @ 2020-08-31 19:38 UTC (permalink / raw) To: Can Guo Cc: asutoshd, nguyenb, hongwus, rnayak, linux-scsi, kernel-team, saravanak, salyzyn, Alim Akhtar, Avri Altman, James E.J. Bottomley, Martin K. Petersen, Stanley Chu, Bean Huo, Bart Van Assche, open list On Mon, 2020-08-31 at 09:20 +0800, Can Guo wrote: > On 2020-08-31 02:11, Bean Huo wrote: > > Hi Can > > This patch conflicts and be not in line with this series patches : > > h > > ttps://patchwork.kernel.org/cover/11709279/, which has been applied > > into 5.9/scsi-fixes. But they are not apppiled in the 5.9/scsi- > > queue. > > > > Maybe you should rebase your patch from scsi-fixes branch. or do > > you > > have another better option? > > > > Thanks, > > Bean > > > > I am pushing this change due to LINERSET handling needs it and > LINERESET > handling is added based on my previous changes to err_handler, which > are > picked by 5.10/scsi-queue. So the two are applied for 5.10/scsi- > queue > only. > Any conflicts you see on 5.10/scsi-queue? Hi Can I meant scsi-fixes branch. no conflict with scsi-queue branch. If the the changes in the scsi-fixes branch will never be merged to scsi- queue branch.It is fine. Thanks, Bean > > Thanks, > > Can Guo. ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v1 2/2] scsi: ufs: Handle LINERESET indication in err handler 2020-08-25 2:07 [RESEND PATCH v1 0/2] Add UFS LINERESET handling Can Guo 2020-08-25 2:07 ` [PATCH v1 1/2] scsi: ufs: Abort tasks before clear them from doorbell Can Guo @ 2020-08-25 2:07 ` Can Guo 2020-09-09 2:09 ` [RESEND PATCH v1 0/2] Add UFS LINERESET handling Martin K. Petersen 2 siblings, 0 replies; 11+ messages in thread From: Can Guo @ 2020-08-25 2:07 UTC (permalink / raw) To: asutoshd, nguyenb, hongwus, rnayak, linux-scsi, kernel-team, saravanak, salyzyn, cang Cc: Alim Akhtar, Avri Altman, James E.J. Bottomley, Martin K. Petersen, Stanley Chu, Bean Huo, Bart Van Assche, Satya Tangirala, Venkat Gopalakrishnan, Kiwoong Kim, open list PA Layer issues a LINERESET to the PHY at the recovery step in the Power Mode change operation. If it happens during auto or mannual hibern8 enter, even if hibern8 enter succeeds, UFS power mode shall be set to PWM-G1 mode and kept in that mode after exit from hibern8, leading to bad performance. Handle the LINERESET in the eh_work by restoring power mode to HS mode after all pending reqs and tasks are cleared from doorbell. Signed-off-by: Can Guo <cang@codeaurora.org> --- drivers/scsi/ufs/ufshcd.c | 111 ++++++++++++++++++++++++++++++++++++++++------ drivers/scsi/ufs/ufshcd.h | 2 + drivers/scsi/ufs/ufshci.h | 1 + drivers/scsi/ufs/unipro.h | 3 ++ 4 files changed, 103 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 000895f..8cc127d 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -143,6 +143,7 @@ enum { UFSHCD_UIC_NL_ERROR = (1 << 3), /* Network layer error */ UFSHCD_UIC_TL_ERROR = (1 << 4), /* Transport Layer error */ UFSHCD_UIC_DME_ERROR = (1 << 5), /* DME error */ + UFSHCD_UIC_PA_GENERIC_ERROR = (1 << 6), /* Generic PA error */ }; #define ufshcd_set_eh_in_progress(h) \ @@ -4066,7 +4067,8 @@ static int ufshcd_change_power_mode(struct ufs_hba *hba, int ret; /* if already configured to the requested pwr_mode */ - if (pwr_mode->gear_rx == hba->pwr_info.gear_rx && + if (!hba->force_pmc && + pwr_mode->gear_rx == hba->pwr_info.gear_rx && pwr_mode->gear_tx == hba->pwr_info.gear_tx && pwr_mode->lane_rx == hba->pwr_info.lane_rx && pwr_mode->lane_tx == hba->pwr_info.lane_tx && @@ -4494,6 +4496,8 @@ static int ufshcd_link_startup(struct ufs_hba *hba) if (ret) goto out; + /* Clear UECPA once due to LINERESET has happened during LINK_STARTUP */ + ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER); ret = ufshcd_make_hba_operational(hba); out: if (ret) { @@ -5650,6 +5654,22 @@ static inline void ufshcd_recover_pm_error(struct ufs_hba *hba) } #endif +static bool ufshcd_is_pwr_mode_restore_needed(struct ufs_hba *hba) +{ + struct ufs_pa_layer_attr *pwr_info = &hba->pwr_info; + u32 mode; + + ufshcd_dme_get(hba, UIC_ARG_MIB(PA_PWRMODE), &mode); + + if (pwr_info->pwr_rx != ((mode >> PWRMODE_RX_OFFSET) & PWRMODE_MASK)) + return true; + + if (pwr_info->pwr_tx != (mode & PWRMODE_MASK)) + return true; + + return false; +} + /** * ufshcd_err_handler - handle UFS errors that require s/w attention * @work: pointer to work structure @@ -5660,9 +5680,9 @@ static void ufshcd_err_handler(struct work_struct *work) unsigned long flags; bool err_xfer = false; bool err_tm = false; - int err = 0; + int err = 0, pmc_err; int tag; - bool needs_reset = false; + bool needs_reset = false, needs_restore = false; hba = container_of(work, struct ufs_hba, eh_work); @@ -5710,8 +5730,9 @@ static void ufshcd_err_handler(struct work_struct *work) UFSHCD_UIC_DL_TCx_REPLAY_ERROR)))) needs_reset = true; - if (hba->saved_err & (INT_FATAL_ERRORS | UIC_ERROR | - UFSHCD_UIC_HIBERN8_MASK)) { + if ((hba->saved_err & (INT_FATAL_ERRORS | UFSHCD_UIC_HIBERN8_MASK)) || + (hba->saved_uic_err && + (hba->saved_uic_err != UFSHCD_UIC_PA_GENERIC_ERROR))) { bool pr_prdt = !!(hba->saved_err & SYSTEM_BUS_FATAL_ERROR); spin_unlock_irqrestore(hba->host->host_lock, flags); @@ -5729,8 +5750,25 @@ static void ufshcd_err_handler(struct work_struct *work) * host reset and restore */ if (needs_reset) - goto skip_pending_xfer_clear; + goto do_reset; + /* + * If LINERESET was caught, UFS might have been put to PWM mode, + * check if power mode restore is needed. + */ + if (hba->saved_uic_err & UFSHCD_UIC_PA_GENERIC_ERROR) { + hba->saved_uic_err &= ~UFSHCD_UIC_PA_GENERIC_ERROR; + if (!hba->saved_uic_err) + hba->saved_err &= ~UIC_ERROR; + spin_unlock_irqrestore(hba->host->host_lock, flags); + if (ufshcd_is_pwr_mode_restore_needed(hba)) + needs_restore = true; + spin_lock_irqsave(hba->host->host_lock, flags); + if (!hba->saved_err && !needs_restore) + goto skip_err_handling; + } + + hba->silence_err_logs = true; /* release lock as clear command might sleep */ spin_unlock_irqrestore(hba->host->host_lock, flags); /* Clear pending transfer requests */ @@ -5754,11 +5792,38 @@ static void ufshcd_err_handler(struct work_struct *work) /* Complete the requests that are cleared by s/w */ ufshcd_complete_requests(hba); + hba->silence_err_logs = false; - if (err_xfer || err_tm) + if (err_xfer || err_tm) { needs_reset = true; + goto do_reset; + } -skip_pending_xfer_clear: + /* + * After all reqs and tasks are cleared from doorbell, + * now it is safe to retore power mode. + */ + if (needs_restore) { + spin_unlock_irqrestore(hba->host->host_lock, flags); + /* + * Hold the scaling lock just in case dev cmds + * are sent via bsg and/or sysfs. + */ + down_write(&hba->clk_scaling_lock); + hba->force_pmc = true; + pmc_err = ufshcd_config_pwr_mode(hba, &(hba->pwr_info)); + if (pmc_err) { + needs_reset = true; + dev_err(hba->dev, "%s: Failed to restore power mode, err = %d\n", + __func__, pmc_err); + } + hba->force_pmc = false; + ufshcd_print_pwr_info(hba); + up_write(&hba->clk_scaling_lock); + spin_lock_irqsave(hba->host->host_lock, flags); + } + +do_reset: /* Fatal errors need reset */ if (needs_reset) { unsigned long max_doorbells = (1UL << hba->nutrs) - 1; @@ -5814,17 +5879,33 @@ static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba) u32 reg; irqreturn_t retval = IRQ_NONE; - /* PHY layer lane error */ + /* PHY layer error */ reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER); - /* Ignore LINERESET indication, as this is not an error */ if ((reg & UIC_PHY_ADAPTER_LAYER_ERROR) && - (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK)) { + (reg & UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK)) { + ufshcd_update_reg_hist(&hba->ufs_stats.pa_err, reg); /* * To know whether this error is fatal or not, DB timeout * must be checked but this error is handled separately. */ - dev_dbg(hba->dev, "%s: UIC Lane error reported\n", __func__); - ufshcd_update_reg_hist(&hba->ufs_stats.pa_err, reg); + if (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK) + dev_dbg(hba->dev, "%s: UIC Lane error reported\n", + __func__); + + /* Got a LINERESET indication. */ + if (reg & UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR) { + struct uic_command *cmd = NULL; + + hba->uic_error |= UFSHCD_UIC_PA_GENERIC_ERROR; + if (hba->uic_async_done && hba->active_uic_cmd) + cmd = hba->active_uic_cmd; + /* + * Ignore the LINERESET during power mode change + * operation via DME_SET command. + */ + if (cmd && (cmd->command == UIC_CMD_DME_SET)) + hba->uic_error &= ~UFSHCD_UIC_PA_GENERIC_ERROR; + } retval |= IRQ_HANDLED; } @@ -5941,7 +6022,9 @@ static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba) hba->saved_uic_err |= hba->uic_error; /* dump controller state before resetting */ - if (hba->saved_err & (INT_FATAL_ERRORS | UIC_ERROR)) { + if ((hba->saved_err & (INT_FATAL_ERRORS)) || + (hba->saved_uic_err && + (hba->saved_uic_err != UFSHCD_UIC_PA_GENERIC_ERROR))) { dev_err(hba->dev, "%s: saved_err 0x%x saved_uic_err 0x%x\n", __func__, hba->saved_err, hba->saved_uic_err); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 618b253..8817103 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -629,6 +629,7 @@ struct ufs_hba_variant_params { * @saved_err: sticky error mask * @saved_uic_err: sticky UIC error mask * @force_reset: flag to force eh_work perform a full reset + * @force_pmc: flag to force a power mode change * @silence_err_logs: flag to silence error logs * @dev_cmd: ufs device management command information * @last_dme_cmd_tstamp: time stamp of the last completed DME command @@ -728,6 +729,7 @@ struct ufs_hba { u32 saved_uic_err; struct ufs_stats ufs_stats; bool force_reset; + bool force_pmc; bool silence_err_logs; /* Device management request data */ diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index ba31b09..6795e1f 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h @@ -171,6 +171,7 @@ enum { #define UIC_PHY_ADAPTER_LAYER_ERROR 0x80000000 #define UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK 0x1F #define UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK 0xF +#define UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR 0x10 /* UECDL - Host UIC Error Code Data Link Layer 3Ch */ #define UIC_DATA_LINK_LAYER_ERROR 0x80000000 diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h index 4ee6478..f6b52ce 100644 --- a/drivers/scsi/ufs/unipro.h +++ b/drivers/scsi/ufs/unipro.h @@ -205,6 +205,9 @@ enum { UNCHANGED = 7, }; +#define PWRMODE_MASK 0xF +#define PWRMODE_RX_OFFSET 4 + /* PA TX/RX Frequency Series */ enum { PA_HS_MODE_A = 1, -- Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project. ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [RESEND PATCH v1 0/2] Add UFS LINERESET handling 2020-08-25 2:07 [RESEND PATCH v1 0/2] Add UFS LINERESET handling Can Guo 2020-08-25 2:07 ` [PATCH v1 1/2] scsi: ufs: Abort tasks before clear them from doorbell Can Guo 2020-08-25 2:07 ` [PATCH v1 2/2] scsi: ufs: Handle LINERESET indication in err handler Can Guo @ 2020-09-09 2:09 ` Martin K. Petersen 2 siblings, 0 replies; 11+ messages in thread From: Martin K. Petersen @ 2020-09-09 2:09 UTC (permalink / raw) To: kernel-team, asutoshd, hongwus, Can Guo, rnayak, salyzyn, saravanak, linux-scsi, nguyenb Cc: Martin K . Petersen On Mon, 24 Aug 2020 19:07:04 -0700, Can Guo wrote: > PA Layer issues a LINERESET to the PHY at the recovery step in the Power > Mode change operation. If it happens during auto or mannual hibern8 enter, > even if hibern8 enter succeeds, UFS power mode shall be set to PWM-G1 mode > and kept in that mode after exit from hibern8, leading to bad performance. > Handle the LINERESET in the eh_work by restoring power mode to HS mode > after all pending reqs and tasks are cleared from doorbell. > > [...] Applied to 5.10/scsi-queue, thanks! [1/2] scsi: ufs: Abort tasks before clearing them from doorbell https://git.kernel.org/mkp/scsi/c/307348f6ab14 [2/2] scsi: ufs: Handle LINERESET indication in err handler https://git.kernel.org/mkp/scsi/c/2355b66ed20c -- Martin K. Petersen Oracle Linux Engineering ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v1 0/2] Add UFS LINERESET handling @ 2020-08-24 9:39 Can Guo 2020-08-24 9:39 ` [PATCH v1 2/2] scsi: ufs: Handle LINERESET indication in err handler Can Guo 0 siblings, 1 reply; 11+ messages in thread From: Can Guo @ 2020-08-24 9:39 UTC (permalink / raw) To: asutoshd, nguyenb, hongwus, rnayak, linux-scsi, kernel-team, saravanak, salyzyn, cang PA Layer issues a LINERESET to the PHY at the recovery step in the Power Mode change operation. If it happens during auto or mannual hibern8 enter, even if hibern8 enter succeeds, UFS power mode shall be set to PWM-G1 mode and kept in that mode after exit from hibern8, leading to bad performance. Handle the LINERESET in the eh_work by restoring power mode to HS mode after all pending reqs and tasks are cleared from doorbell. Can Guo (2): scsi: ufs: Abort tasks before clear them from doorbell scsi: ufs: Handle LINERESET indication in err handler drivers/scsi/ufs/ufshcd.c | 254 ++++++++++++++++++++++++++++++++-------------- drivers/scsi/ufs/ufshcd.h | 2 + drivers/scsi/ufs/unipro.h | 3 + 3 files changed, 183 insertions(+), 76 deletions(-) -- Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project. ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v1 2/2] scsi: ufs: Handle LINERESET indication in err handler 2020-08-24 9:39 [PATCH " Can Guo @ 2020-08-24 9:39 ` Can Guo 2020-08-24 14:56 ` kernel test robot 2020-08-24 15:12 ` kernel test robot 0 siblings, 2 replies; 11+ messages in thread From: Can Guo @ 2020-08-24 9:39 UTC (permalink / raw) To: asutoshd, nguyenb, hongwus, rnayak, linux-scsi, kernel-team, saravanak, salyzyn, cang Cc: Alim Akhtar, Avri Altman, James E.J. Bottomley, Martin K. Petersen, Stanley Chu, Bean Huo, Bart Van Assche, Satya Tangirala, open list PA Layer issues a LINERESET to the PHY at the recovery step in the Power Mode change operation. If it happens during auto or mannual hibern8 enter, even if hibern8 enter succeeds, UFS power mode shall be set to PWM-G1 mode and kept in that mode after exit from hibern8, leading to bad performance. Handle the LINERESET in the eh_work by restoring power mode to HS mode after all pending reqs and tasks are cleared from doorbell. Signed-off-by: Can Guo <cang@codeaurora.org> --- drivers/scsi/ufs/ufshcd.c | 111 ++++++++++++++++++++++++++++++++++++++++------ drivers/scsi/ufs/ufshcd.h | 2 + drivers/scsi/ufs/unipro.h | 3 ++ 3 files changed, 102 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 000895f..8cc127d 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -143,6 +143,7 @@ enum { UFSHCD_UIC_NL_ERROR = (1 << 3), /* Network layer error */ UFSHCD_UIC_TL_ERROR = (1 << 4), /* Transport Layer error */ UFSHCD_UIC_DME_ERROR = (1 << 5), /* DME error */ + UFSHCD_UIC_PA_GENERIC_ERROR = (1 << 6), /* Generic PA error */ }; #define ufshcd_set_eh_in_progress(h) \ @@ -4066,7 +4067,8 @@ static int ufshcd_change_power_mode(struct ufs_hba *hba, int ret; /* if already configured to the requested pwr_mode */ - if (pwr_mode->gear_rx == hba->pwr_info.gear_rx && + if (!hba->force_pmc && + pwr_mode->gear_rx == hba->pwr_info.gear_rx && pwr_mode->gear_tx == hba->pwr_info.gear_tx && pwr_mode->lane_rx == hba->pwr_info.lane_rx && pwr_mode->lane_tx == hba->pwr_info.lane_tx && @@ -4494,6 +4496,8 @@ static int ufshcd_link_startup(struct ufs_hba *hba) if (ret) goto out; + /* Clear UECPA once due to LINERESET has happened during LINK_STARTUP */ + ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER); ret = ufshcd_make_hba_operational(hba); out: if (ret) { @@ -5650,6 +5654,22 @@ static inline void ufshcd_recover_pm_error(struct ufs_hba *hba) } #endif +static bool ufshcd_is_pwr_mode_restore_needed(struct ufs_hba *hba) +{ + struct ufs_pa_layer_attr *pwr_info = &hba->pwr_info; + u32 mode; + + ufshcd_dme_get(hba, UIC_ARG_MIB(PA_PWRMODE), &mode); + + if (pwr_info->pwr_rx != ((mode >> PWRMODE_RX_OFFSET) & PWRMODE_MASK)) + return true; + + if (pwr_info->pwr_tx != (mode & PWRMODE_MASK)) + return true; + + return false; +} + /** * ufshcd_err_handler - handle UFS errors that require s/w attention * @work: pointer to work structure @@ -5660,9 +5680,9 @@ static void ufshcd_err_handler(struct work_struct *work) unsigned long flags; bool err_xfer = false; bool err_tm = false; - int err = 0; + int err = 0, pmc_err; int tag; - bool needs_reset = false; + bool needs_reset = false, needs_restore = false; hba = container_of(work, struct ufs_hba, eh_work); @@ -5710,8 +5730,9 @@ static void ufshcd_err_handler(struct work_struct *work) UFSHCD_UIC_DL_TCx_REPLAY_ERROR)))) needs_reset = true; - if (hba->saved_err & (INT_FATAL_ERRORS | UIC_ERROR | - UFSHCD_UIC_HIBERN8_MASK)) { + if ((hba->saved_err & (INT_FATAL_ERRORS | UFSHCD_UIC_HIBERN8_MASK)) || + (hba->saved_uic_err && + (hba->saved_uic_err != UFSHCD_UIC_PA_GENERIC_ERROR))) { bool pr_prdt = !!(hba->saved_err & SYSTEM_BUS_FATAL_ERROR); spin_unlock_irqrestore(hba->host->host_lock, flags); @@ -5729,8 +5750,25 @@ static void ufshcd_err_handler(struct work_struct *work) * host reset and restore */ if (needs_reset) - goto skip_pending_xfer_clear; + goto do_reset; + /* + * If LINERESET was caught, UFS might have been put to PWM mode, + * check if power mode restore is needed. + */ + if (hba->saved_uic_err & UFSHCD_UIC_PA_GENERIC_ERROR) { + hba->saved_uic_err &= ~UFSHCD_UIC_PA_GENERIC_ERROR; + if (!hba->saved_uic_err) + hba->saved_err &= ~UIC_ERROR; + spin_unlock_irqrestore(hba->host->host_lock, flags); + if (ufshcd_is_pwr_mode_restore_needed(hba)) + needs_restore = true; + spin_lock_irqsave(hba->host->host_lock, flags); + if (!hba->saved_err && !needs_restore) + goto skip_err_handling; + } + + hba->silence_err_logs = true; /* release lock as clear command might sleep */ spin_unlock_irqrestore(hba->host->host_lock, flags); /* Clear pending transfer requests */ @@ -5754,11 +5792,38 @@ static void ufshcd_err_handler(struct work_struct *work) /* Complete the requests that are cleared by s/w */ ufshcd_complete_requests(hba); + hba->silence_err_logs = false; - if (err_xfer || err_tm) + if (err_xfer || err_tm) { needs_reset = true; + goto do_reset; + } -skip_pending_xfer_clear: + /* + * After all reqs and tasks are cleared from doorbell, + * now it is safe to retore power mode. + */ + if (needs_restore) { + spin_unlock_irqrestore(hba->host->host_lock, flags); + /* + * Hold the scaling lock just in case dev cmds + * are sent via bsg and/or sysfs. + */ + down_write(&hba->clk_scaling_lock); + hba->force_pmc = true; + pmc_err = ufshcd_config_pwr_mode(hba, &(hba->pwr_info)); + if (pmc_err) { + needs_reset = true; + dev_err(hba->dev, "%s: Failed to restore power mode, err = %d\n", + __func__, pmc_err); + } + hba->force_pmc = false; + ufshcd_print_pwr_info(hba); + up_write(&hba->clk_scaling_lock); + spin_lock_irqsave(hba->host->host_lock, flags); + } + +do_reset: /* Fatal errors need reset */ if (needs_reset) { unsigned long max_doorbells = (1UL << hba->nutrs) - 1; @@ -5814,17 +5879,33 @@ static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba) u32 reg; irqreturn_t retval = IRQ_NONE; - /* PHY layer lane error */ + /* PHY layer error */ reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER); - /* Ignore LINERESET indication, as this is not an error */ if ((reg & UIC_PHY_ADAPTER_LAYER_ERROR) && - (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK)) { + (reg & UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK)) { + ufshcd_update_reg_hist(&hba->ufs_stats.pa_err, reg); /* * To know whether this error is fatal or not, DB timeout * must be checked but this error is handled separately. */ - dev_dbg(hba->dev, "%s: UIC Lane error reported\n", __func__); - ufshcd_update_reg_hist(&hba->ufs_stats.pa_err, reg); + if (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK) + dev_dbg(hba->dev, "%s: UIC Lane error reported\n", + __func__); + + /* Got a LINERESET indication. */ + if (reg & UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR) { + struct uic_command *cmd = NULL; + + hba->uic_error |= UFSHCD_UIC_PA_GENERIC_ERROR; + if (hba->uic_async_done && hba->active_uic_cmd) + cmd = hba->active_uic_cmd; + /* + * Ignore the LINERESET during power mode change + * operation via DME_SET command. + */ + if (cmd && (cmd->command == UIC_CMD_DME_SET)) + hba->uic_error &= ~UFSHCD_UIC_PA_GENERIC_ERROR; + } retval |= IRQ_HANDLED; } @@ -5941,7 +6022,9 @@ static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba) hba->saved_uic_err |= hba->uic_error; /* dump controller state before resetting */ - if (hba->saved_err & (INT_FATAL_ERRORS | UIC_ERROR)) { + if ((hba->saved_err & (INT_FATAL_ERRORS)) || + (hba->saved_uic_err && + (hba->saved_uic_err != UFSHCD_UIC_PA_GENERIC_ERROR))) { dev_err(hba->dev, "%s: saved_err 0x%x saved_uic_err 0x%x\n", __func__, hba->saved_err, hba->saved_uic_err); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 618b253..8817103 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -629,6 +629,7 @@ struct ufs_hba_variant_params { * @saved_err: sticky error mask * @saved_uic_err: sticky UIC error mask * @force_reset: flag to force eh_work perform a full reset + * @force_pmc: flag to force a power mode change * @silence_err_logs: flag to silence error logs * @dev_cmd: ufs device management command information * @last_dme_cmd_tstamp: time stamp of the last completed DME command @@ -728,6 +729,7 @@ struct ufs_hba { u32 saved_uic_err; struct ufs_stats ufs_stats; bool force_reset; + bool force_pmc; bool silence_err_logs; /* Device management request data */ diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h index 4ee6478..f6b52ce 100644 --- a/drivers/scsi/ufs/unipro.h +++ b/drivers/scsi/ufs/unipro.h @@ -205,6 +205,9 @@ enum { UNCHANGED = 7, }; +#define PWRMODE_MASK 0xF +#define PWRMODE_RX_OFFSET 4 + /* PA TX/RX Frequency Series */ enum { PA_HS_MODE_A = 1, -- Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project. ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v1 2/2] scsi: ufs: Handle LINERESET indication in err handler 2020-08-24 9:39 ` [PATCH v1 2/2] scsi: ufs: Handle LINERESET indication in err handler Can Guo @ 2020-08-24 14:56 ` kernel test robot 2020-08-24 15:12 ` kernel test robot 1 sibling, 0 replies; 11+ messages in thread From: kernel test robot @ 2020-08-24 14:56 UTC (permalink / raw) To: Can Guo, asutoshd, nguyenb, hongwus, rnayak, linux-scsi, kernel-team, saravanak, salyzyn Cc: kbuild-all, Alim Akhtar [-- Attachment #1: Type: text/plain, Size: 5658 bytes --] Hi Can, Thank you for the patch! Yet something to improve: [auto build test ERROR on mkp-scsi/for-next] [cannot apply to scsi/for-next v5.9-rc2 next-20200824] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Can-Guo/Add-UFS-LINERESET-handling/20200824-174334 base: https://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git for-next config: openrisc-randconfig-r034-20200824 (attached as .config) compiler: or1k-linux-gcc (GCC) 9.3.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=openrisc If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All errors (new ones prefixed by >>): drivers/scsi/ufs/ufshcd.c: In function 'ufshcd_update_uic_error': >> drivers/scsi/ufs/ufshcd.c:5897:13: error: 'UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR' undeclared (first use in this function); did you mean 'UIC_PHY_ADAPTER_LAYER_ERROR'? 5897 | if (reg & UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR) { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | UIC_PHY_ADAPTER_LAYER_ERROR drivers/scsi/ufs/ufshcd.c:5897:13: note: each undeclared identifier is reported only once for each function it appears in # https://github.com/0day-ci/linux/commit/ec9dcd8fd02bf2ecd2d75d2bd272d06d10818198 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Can-Guo/Add-UFS-LINERESET-handling/20200824-174334 git checkout ec9dcd8fd02bf2ecd2d75d2bd272d06d10818198 vim +5897 drivers/scsi/ufs/ufshcd.c 5869 5870 /** 5871 * ufshcd_update_uic_error - check and set fatal UIC error flags. 5872 * @hba: per-adapter instance 5873 * 5874 * Returns 5875 * IRQ_HANDLED - If interrupt is valid 5876 * IRQ_NONE - If invalid interrupt 5877 */ 5878 static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba) 5879 { 5880 u32 reg; 5881 irqreturn_t retval = IRQ_NONE; 5882 5883 /* PHY layer error */ 5884 reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER); 5885 if ((reg & UIC_PHY_ADAPTER_LAYER_ERROR) && 5886 (reg & UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK)) { 5887 ufshcd_update_reg_hist(&hba->ufs_stats.pa_err, reg); 5888 /* 5889 * To know whether this error is fatal or not, DB timeout 5890 * must be checked but this error is handled separately. 5891 */ 5892 if (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK) 5893 dev_dbg(hba->dev, "%s: UIC Lane error reported\n", 5894 __func__); 5895 5896 /* Got a LINERESET indication. */ > 5897 if (reg & UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR) { 5898 struct uic_command *cmd = NULL; 5899 5900 hba->uic_error |= UFSHCD_UIC_PA_GENERIC_ERROR; 5901 if (hba->uic_async_done && hba->active_uic_cmd) 5902 cmd = hba->active_uic_cmd; 5903 /* 5904 * Ignore the LINERESET during power mode change 5905 * operation via DME_SET command. 5906 */ 5907 if (cmd && (cmd->command == UIC_CMD_DME_SET)) 5908 hba->uic_error &= ~UFSHCD_UIC_PA_GENERIC_ERROR; 5909 } 5910 retval |= IRQ_HANDLED; 5911 } 5912 5913 /* PA_INIT_ERROR is fatal and needs UIC reset */ 5914 reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER); 5915 if ((reg & UIC_DATA_LINK_LAYER_ERROR) && 5916 (reg & UIC_DATA_LINK_LAYER_ERROR_CODE_MASK)) { 5917 ufshcd_update_reg_hist(&hba->ufs_stats.dl_err, reg); 5918 5919 if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT) 5920 hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR; 5921 else if (hba->dev_quirks & 5922 UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS) { 5923 if (reg & UIC_DATA_LINK_LAYER_ERROR_NAC_RECEIVED) 5924 hba->uic_error |= 5925 UFSHCD_UIC_DL_NAC_RECEIVED_ERROR; 5926 else if (reg & UIC_DATA_LINK_LAYER_ERROR_TCx_REPLAY_TIMEOUT) 5927 hba->uic_error |= UFSHCD_UIC_DL_TCx_REPLAY_ERROR; 5928 } 5929 retval |= IRQ_HANDLED; 5930 } 5931 5932 /* UIC NL/TL/DME errors needs software retry */ 5933 reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_NETWORK_LAYER); 5934 if ((reg & UIC_NETWORK_LAYER_ERROR) && 5935 (reg & UIC_NETWORK_LAYER_ERROR_CODE_MASK)) { 5936 ufshcd_update_reg_hist(&hba->ufs_stats.nl_err, reg); 5937 hba->uic_error |= UFSHCD_UIC_NL_ERROR; 5938 retval |= IRQ_HANDLED; 5939 } 5940 5941 reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_TRANSPORT_LAYER); 5942 if ((reg & UIC_TRANSPORT_LAYER_ERROR) && 5943 (reg & UIC_TRANSPORT_LAYER_ERROR_CODE_MASK)) { 5944 ufshcd_update_reg_hist(&hba->ufs_stats.tl_err, reg); 5945 hba->uic_error |= UFSHCD_UIC_TL_ERROR; 5946 retval |= IRQ_HANDLED; 5947 } 5948 5949 reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DME); 5950 if ((reg & UIC_DME_ERROR) && 5951 (reg & UIC_DME_ERROR_CODE_MASK)) { 5952 ufshcd_update_reg_hist(&hba->ufs_stats.dme_err, reg); 5953 hba->uic_error |= UFSHCD_UIC_DME_ERROR; 5954 retval |= IRQ_HANDLED; 5955 } 5956 5957 dev_dbg(hba->dev, "%s: UIC error flags = 0x%08x\n", 5958 __func__, hba->uic_error); 5959 return retval; 5960 } 5961 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org [-- Attachment #2: .config.gz --] [-- Type: application/gzip, Size: 23858 bytes --] ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v1 2/2] scsi: ufs: Handle LINERESET indication in err handler 2020-08-24 9:39 ` [PATCH v1 2/2] scsi: ufs: Handle LINERESET indication in err handler Can Guo 2020-08-24 14:56 ` kernel test robot @ 2020-08-24 15:12 ` kernel test robot 1 sibling, 0 replies; 11+ messages in thread From: kernel test robot @ 2020-08-24 15:12 UTC (permalink / raw) To: Can Guo, asutoshd, nguyenb, hongwus, rnayak, linux-scsi, kernel-team, saravanak, salyzyn Cc: kbuild-all, clang-built-linux, Alim Akhtar [-- Attachment #1: Type: text/plain, Size: 6053 bytes --] Hi Can, Thank you for the patch! Yet something to improve: [auto build test ERROR on mkp-scsi/for-next] [cannot apply to scsi/for-next v5.9-rc2 next-20200824] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Can-Guo/Add-UFS-LINERESET-handling/20200824-174334 base: https://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git for-next config: riscv-randconfig-r035-20200824 (attached as .config) compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project b587ca93be114d07ec3bf654add97d7872325281) reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # install riscv cross compiling tool for clang build # apt-get install binutils-riscv64-linux-gnu # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=riscv If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All errors (new ones prefixed by >>): >> drivers/scsi/ufs/ufshcd.c:5897:13: error: use of undeclared identifier 'UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR' if (reg & UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR) { ^ drivers/scsi/ufs/ufshcd.c:8928:44: warning: shift count >= width of type [-Wshift-count-overflow] if (!dma_set_mask_and_coherent(hba->dev, DMA_BIT_MASK(64))) ^~~~~~~~~~~~~~~~ include/linux/dma-mapping.h:139:54: note: expanded from macro 'DMA_BIT_MASK' #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) ^ ~~~ 1 warning and 1 error generated. # https://github.com/0day-ci/linux/commit/ec9dcd8fd02bf2ecd2d75d2bd272d06d10818198 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Can-Guo/Add-UFS-LINERESET-handling/20200824-174334 git checkout ec9dcd8fd02bf2ecd2d75d2bd272d06d10818198 vim +/UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR +5897 drivers/scsi/ufs/ufshcd.c 5869 5870 /** 5871 * ufshcd_update_uic_error - check and set fatal UIC error flags. 5872 * @hba: per-adapter instance 5873 * 5874 * Returns 5875 * IRQ_HANDLED - If interrupt is valid 5876 * IRQ_NONE - If invalid interrupt 5877 */ 5878 static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba) 5879 { 5880 u32 reg; 5881 irqreturn_t retval = IRQ_NONE; 5882 5883 /* PHY layer error */ 5884 reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER); 5885 if ((reg & UIC_PHY_ADAPTER_LAYER_ERROR) && 5886 (reg & UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK)) { 5887 ufshcd_update_reg_hist(&hba->ufs_stats.pa_err, reg); 5888 /* 5889 * To know whether this error is fatal or not, DB timeout 5890 * must be checked but this error is handled separately. 5891 */ 5892 if (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK) 5893 dev_dbg(hba->dev, "%s: UIC Lane error reported\n", 5894 __func__); 5895 5896 /* Got a LINERESET indication. */ > 5897 if (reg & UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR) { 5898 struct uic_command *cmd = NULL; 5899 5900 hba->uic_error |= UFSHCD_UIC_PA_GENERIC_ERROR; 5901 if (hba->uic_async_done && hba->active_uic_cmd) 5902 cmd = hba->active_uic_cmd; 5903 /* 5904 * Ignore the LINERESET during power mode change 5905 * operation via DME_SET command. 5906 */ 5907 if (cmd && (cmd->command == UIC_CMD_DME_SET)) 5908 hba->uic_error &= ~UFSHCD_UIC_PA_GENERIC_ERROR; 5909 } 5910 retval |= IRQ_HANDLED; 5911 } 5912 5913 /* PA_INIT_ERROR is fatal and needs UIC reset */ 5914 reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER); 5915 if ((reg & UIC_DATA_LINK_LAYER_ERROR) && 5916 (reg & UIC_DATA_LINK_LAYER_ERROR_CODE_MASK)) { 5917 ufshcd_update_reg_hist(&hba->ufs_stats.dl_err, reg); 5918 5919 if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT) 5920 hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR; 5921 else if (hba->dev_quirks & 5922 UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS) { 5923 if (reg & UIC_DATA_LINK_LAYER_ERROR_NAC_RECEIVED) 5924 hba->uic_error |= 5925 UFSHCD_UIC_DL_NAC_RECEIVED_ERROR; 5926 else if (reg & UIC_DATA_LINK_LAYER_ERROR_TCx_REPLAY_TIMEOUT) 5927 hba->uic_error |= UFSHCD_UIC_DL_TCx_REPLAY_ERROR; 5928 } 5929 retval |= IRQ_HANDLED; 5930 } 5931 5932 /* UIC NL/TL/DME errors needs software retry */ 5933 reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_NETWORK_LAYER); 5934 if ((reg & UIC_NETWORK_LAYER_ERROR) && 5935 (reg & UIC_NETWORK_LAYER_ERROR_CODE_MASK)) { 5936 ufshcd_update_reg_hist(&hba->ufs_stats.nl_err, reg); 5937 hba->uic_error |= UFSHCD_UIC_NL_ERROR; 5938 retval |= IRQ_HANDLED; 5939 } 5940 5941 reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_TRANSPORT_LAYER); 5942 if ((reg & UIC_TRANSPORT_LAYER_ERROR) && 5943 (reg & UIC_TRANSPORT_LAYER_ERROR_CODE_MASK)) { 5944 ufshcd_update_reg_hist(&hba->ufs_stats.tl_err, reg); 5945 hba->uic_error |= UFSHCD_UIC_TL_ERROR; 5946 retval |= IRQ_HANDLED; 5947 } 5948 5949 reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DME); 5950 if ((reg & UIC_DME_ERROR) && 5951 (reg & UIC_DME_ERROR_CODE_MASK)) { 5952 ufshcd_update_reg_hist(&hba->ufs_stats.dme_err, reg); 5953 hba->uic_error |= UFSHCD_UIC_DME_ERROR; 5954 retval |= IRQ_HANDLED; 5955 } 5956 5957 dev_dbg(hba->dev, "%s: UIC error flags = 0x%08x\n", 5958 __func__, hba->uic_error); 5959 return retval; 5960 } 5961 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org [-- Attachment #2: .config.gz --] [-- Type: application/gzip, Size: 27749 bytes --] ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2020-09-09 2:09 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2020-08-25 2:07 [RESEND PATCH v1 0/2] Add UFS LINERESET handling Can Guo 2020-08-25 2:07 ` [PATCH v1 1/2] scsi: ufs: Abort tasks before clear them from doorbell Can Guo 2020-08-27 8:37 ` Stanley Chu 2020-08-30 18:11 ` Bean Huo 2020-08-31 1:20 ` Can Guo 2020-08-31 19:38 ` Bean Huo 2020-08-25 2:07 ` [PATCH v1 2/2] scsi: ufs: Handle LINERESET indication in err handler Can Guo 2020-09-09 2:09 ` [RESEND PATCH v1 0/2] Add UFS LINERESET handling Martin K. Petersen -- strict thread matches above, loose matches on Subject: below -- 2020-08-24 9:39 [PATCH " Can Guo 2020-08-24 9:39 ` [PATCH v1 2/2] scsi: ufs: Handle LINERESET indication in err handler Can Guo 2020-08-24 14:56 ` kernel test robot 2020-08-24 15:12 ` kernel test robot
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox