mirror of
https://github.com/torvalds/linux.git
synced 2026-06-03 12:03:54 +02:00
wifi: iwlwifi: pcie: abort D3 handshake on error
The D3 handshake can be interrupted by an error, especially on resume where we no longer want to check explicitly for errors. Expand the sx_complete to sx_state and handle any errors occurring during the handshake. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Link: https://patch.msgid.link/20250611222325.157dca92c573.I6dd3b9d2f435c2c363224aa84e373931e56a545f@changeid
This commit is contained in:
parent
eda36f5195
commit
8689bc3fc0
|
|
@ -382,7 +382,7 @@ struct iwl_pcie_txqs {
|
|||
* @irq_lock: lock to synchronize IRQ handling
|
||||
* @txq_memory: TXQ allocation array
|
||||
* @sx_waitq: waitqueue for Sx transitions
|
||||
* @sx_complete: completion for Sx transitions
|
||||
* @sx_state: state tracking Sx transitions
|
||||
* @pcie_dbg_dumped_once: indicates PCIe regs were dumped already
|
||||
* @opmode_down: indicates opmode went away
|
||||
* @num_rx_bufs: number of RX buffers to allocate/use
|
||||
|
|
@ -448,7 +448,12 @@ struct iwl_trans_pcie {
|
|||
u8 __iomem *hw_base;
|
||||
|
||||
bool ucode_write_complete;
|
||||
bool sx_complete;
|
||||
enum {
|
||||
IWL_SX_INVALID = 0,
|
||||
IWL_SX_WAITING,
|
||||
IWL_SX_ERROR,
|
||||
IWL_SX_COMPLETE,
|
||||
} sx_state;
|
||||
wait_queue_head_t ucode_write_waitq;
|
||||
wait_queue_head_t sx_waitq;
|
||||
|
||||
|
|
|
|||
|
|
@ -2394,6 +2394,11 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)
|
|||
} else {
|
||||
iwl_pcie_irq_handle_error(trans);
|
||||
}
|
||||
|
||||
if (trans_pcie->sx_state == IWL_SX_WAITING) {
|
||||
trans_pcie->sx_state = IWL_SX_ERROR;
|
||||
wake_up(&trans_pcie->sx_waitq);
|
||||
}
|
||||
}
|
||||
|
||||
/* After checking FH register check HW register */
|
||||
|
|
@ -2428,13 +2433,20 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)
|
|||
if (inta_hw & MSIX_HW_INT_CAUSES_REG_WAKEUP && trans_pcie->prph_info) {
|
||||
u32 sleep_notif =
|
||||
le32_to_cpu(trans_pcie->prph_info->sleep_notif);
|
||||
|
||||
if (sleep_notif == IWL_D3_SLEEP_STATUS_SUSPEND ||
|
||||
sleep_notif == IWL_D3_SLEEP_STATUS_RESUME) {
|
||||
IWL_DEBUG_ISR(trans,
|
||||
"Sx interrupt: sleep notification = 0x%x\n",
|
||||
sleep_notif);
|
||||
trans_pcie->sx_complete = true;
|
||||
wake_up(&trans_pcie->sx_waitq);
|
||||
if (trans_pcie->sx_state == IWL_SX_WAITING) {
|
||||
trans_pcie->sx_state = IWL_SX_COMPLETE;
|
||||
wake_up(&trans_pcie->sx_waitq);
|
||||
} else {
|
||||
IWL_ERR(trans,
|
||||
"unexpected Sx interrupt (0x%x)\n",
|
||||
sleep_notif);
|
||||
}
|
||||
} else {
|
||||
/* uCode wakes up after power-down sleep */
|
||||
IWL_DEBUG_ISR(trans, "Wakeup interrupt\n");
|
||||
|
|
|
|||
|
|
@ -1536,30 +1536,41 @@ static int iwl_pcie_d3_handshake(struct iwl_trans *trans, bool suspend)
|
|||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
int ret;
|
||||
|
||||
if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
|
||||
return 0;
|
||||
|
||||
trans_pcie->sx_state = IWL_SX_WAITING;
|
||||
|
||||
if (trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_AX210)
|
||||
iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6,
|
||||
suspend ? UREG_DOORBELL_TO_ISR6_SUSPEND :
|
||||
UREG_DOORBELL_TO_ISR6_RESUME);
|
||||
else if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ)
|
||||
else
|
||||
iwl_write32(trans, CSR_IPC_SLEEP_CONTROL,
|
||||
suspend ? CSR_IPC_SLEEP_CONTROL_SUSPEND :
|
||||
CSR_IPC_SLEEP_CONTROL_RESUME);
|
||||
else
|
||||
return 0;
|
||||
|
||||
ret = wait_event_timeout(trans_pcie->sx_waitq,
|
||||
trans_pcie->sx_complete, 2 * HZ);
|
||||
|
||||
/* Invalidate it toward next suspend or resume */
|
||||
trans_pcie->sx_complete = false;
|
||||
|
||||
trans_pcie->sx_state != IWL_SX_WAITING,
|
||||
2 * HZ);
|
||||
if (!ret) {
|
||||
IWL_ERR(trans, "Timeout %s D3\n",
|
||||
suspend ? "entering" : "exiting");
|
||||
return -ETIMEDOUT;
|
||||
ret = -ETIMEDOUT;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (trans_pcie->sx_state == IWL_SX_ERROR) {
|
||||
IWL_ERR(trans, "FW error while %s D3\n",
|
||||
suspend ? "entering" : "exiting");
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
/* Invalidate it toward next suspend or resume */
|
||||
trans_pcie->sx_state = IWL_SX_INVALID;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test, bool reset)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user