Commit 8689bc3f authored by Johannes Berg's avatar Johannes Berg Committed by Miri Korenblit
Browse files

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: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarMiri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20250611222325.157dca92c573.I6dd3b9d2f435c2c363224aa84e373931e56a545f@changeid
parent eda36f51
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -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;

+14 −2
Original line number Diff line number Diff line
@@ -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;
			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");
+21 −10
Original line number Diff line number Diff line
@@ -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)