mirror of
https://github.com/nxp-imx/linux-imx.git
synced 2025-07-13 04:39:36 +02:00
FROMLIST: scsi: ufs: core: Fix the code for entering hibernation
Accessing a host controller register after the host controller has entered the hibernation state may cause the host controller to exit the hibernation state. Hence rework the hibernation entry code such that it does not modify the interrupt enabled status. This patch relies on the following: * If an UIC command is submitted that should be completed by the UIC command completion interrupt, hba->uic_async_done == NULL. * If an UIC command is submitted that should be completed by the power mode change interrupt or by a hibernation state change interrupt, hba->uic_async_done != NULL. Change-Id: I1ae6ebbb6f0a17607258bb8f64539ba7e2c78314 Signed-off-by: Bart Van Assche <bvanassche@acm.org> Bug: 344761008 Link: https://lore.kernel.org/linux-scsi/20240821182923.145631-2-bvanassche@acm.org/ Signed-off-by: Bart Van Assche <bvanassche@google.com>
This commit is contained in:
parent
4c0eff913d
commit
6dcad5bb22
|
@ -2459,6 +2459,7 @@ int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
|
||||||
ufshcd_hold(hba);
|
ufshcd_hold(hba);
|
||||||
mutex_lock(&hba->uic_cmd_mutex);
|
mutex_lock(&hba->uic_cmd_mutex);
|
||||||
ufshcd_add_delay_before_dme_cmd(hba);
|
ufshcd_add_delay_before_dme_cmd(hba);
|
||||||
|
WARN_ON(hba->uic_async_done);
|
||||||
|
|
||||||
ret = __ufshcd_send_uic_cmd(hba, uic_cmd, true);
|
ret = __ufshcd_send_uic_cmd(hba, uic_cmd, true);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
|
@ -4156,7 +4157,6 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u8 status;
|
u8 status;
|
||||||
int ret;
|
int ret;
|
||||||
bool reenable_intr = false;
|
|
||||||
|
|
||||||
mutex_lock(&hba->uic_cmd_mutex);
|
mutex_lock(&hba->uic_cmd_mutex);
|
||||||
ufshcd_add_delay_before_dme_cmd(hba);
|
ufshcd_add_delay_before_dme_cmd(hba);
|
||||||
|
@ -4167,15 +4167,6 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
hba->uic_async_done = &uic_async_done;
|
hba->uic_async_done = &uic_async_done;
|
||||||
if (ufshcd_readl(hba, REG_INTERRUPT_ENABLE) & UIC_COMMAND_COMPL) {
|
|
||||||
ufshcd_disable_intr(hba, UIC_COMMAND_COMPL);
|
|
||||||
/*
|
|
||||||
* Make sure UIC command completion interrupt is disabled before
|
|
||||||
* issuing UIC command.
|
|
||||||
*/
|
|
||||||
wmb();
|
|
||||||
reenable_intr = true;
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(hba->host->host_lock, flags);
|
spin_unlock_irqrestore(hba->host->host_lock, flags);
|
||||||
ret = __ufshcd_send_uic_cmd(hba, cmd, false);
|
ret = __ufshcd_send_uic_cmd(hba, cmd, false);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -4219,8 +4210,6 @@ out:
|
||||||
spin_lock_irqsave(hba->host->host_lock, flags);
|
spin_lock_irqsave(hba->host->host_lock, flags);
|
||||||
hba->active_uic_cmd = NULL;
|
hba->active_uic_cmd = NULL;
|
||||||
hba->uic_async_done = NULL;
|
hba->uic_async_done = NULL;
|
||||||
if (reenable_intr)
|
|
||||||
ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ufshcd_set_link_broken(hba);
|
ufshcd_set_link_broken(hba);
|
||||||
ufshcd_schedule_eh_work(hba);
|
ufshcd_schedule_eh_work(hba);
|
||||||
|
@ -5387,11 +5376,12 @@ static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
|
||||||
hba->errors |= (UFSHCD_UIC_HIBERN8_MASK & intr_status);
|
hba->errors |= (UFSHCD_UIC_HIBERN8_MASK & intr_status);
|
||||||
|
|
||||||
if (intr_status & UIC_COMMAND_COMPL && cmd) {
|
if (intr_status & UIC_COMMAND_COMPL && cmd) {
|
||||||
cmd->argument2 |= ufshcd_get_uic_cmd_result(hba);
|
if (!hba->uic_async_done) {
|
||||||
cmd->argument3 = ufshcd_get_dme_attr_val(hba);
|
cmd->argument2 |= ufshcd_get_uic_cmd_result(hba);
|
||||||
if (!hba->uic_async_done)
|
cmd->argument3 = ufshcd_get_dme_attr_val(hba);
|
||||||
cmd->cmd_active = 0;
|
cmd->cmd_active = 0;
|
||||||
complete(&cmd->done);
|
complete(&cmd->done);
|
||||||
|
}
|
||||||
retval = IRQ_HANDLED;
|
retval = IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -876,9 +876,10 @@ enum ufshcd_mcq_opr {
|
||||||
* @tmf_tag_set: TMF tag set.
|
* @tmf_tag_set: TMF tag set.
|
||||||
* @tmf_queue: Used to allocate TMF tags.
|
* @tmf_queue: Used to allocate TMF tags.
|
||||||
* @tmf_rqs: array with pointers to TMF requests while these are in progress.
|
* @tmf_rqs: array with pointers to TMF requests while these are in progress.
|
||||||
* @active_uic_cmd: handle of active UIC command
|
* @active_uic_cmd: active UIC command pointer.
|
||||||
* @uic_cmd_mutex: mutex for UIC command
|
* @uic_cmd_mutex: mutex used to serialize UIC command processing.
|
||||||
* @uic_async_done: completion used during UIC processing
|
* @uic_async_done: completion used to wait for power mode or hibernation state
|
||||||
|
* changes.
|
||||||
* @ufshcd_state: UFSHCD state
|
* @ufshcd_state: UFSHCD state
|
||||||
* @eh_flags: Error handling flags
|
* @eh_flags: Error handling flags
|
||||||
* @intr_mask: Interrupt Mask Bits
|
* @intr_mask: Interrupt Mask Bits
|
||||||
|
|
Loading…
Reference in New Issue
Block a user