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) \
        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 &&
        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) {
 }
 #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
        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);
 
                                    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);
         * 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 */
 
        /* 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;
        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;
        }
 
                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);