diff mbox series

[v1,2/2] scsi: ufs: Handle LINERESET indication in err handler

Message ID 1598261952-29209-3-git-send-email-cang@codeaurora.org (mailing list archive)
State Superseded
Headers show
Series Add UFS LINERESET handling | expand

Commit Message

Can Guo Aug. 24, 2020, 9:39 a.m. UTC
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(-)

Comments

kernel test robot Aug. 24, 2020, 2:56 p.m. UTC | #1
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
kernel test robot Aug. 24, 2020, 3:12 p.m. UTC | #2
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
diff mbox series

Patch

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,