Commit af08571d authored by Haim Dreyfuss's avatar Haim Dreyfuss Committed by Luca Coelho

iwlwifi: pcie: support Bz suspend/resume trigger

Instead of using two bits in the doorbell interrupt, the new Bz
devices have a new CSR_IPC_SLEEP_CONTROL register to let drivers
indicate the desired transition before triggering the doorbell
interrupt.
Signed-off-by: default avatarHaim Dreyfuss <haim.dreyfuss@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20211204083238.63f3d150689a.Iaeb6f9b007e81b1a5a02144b0281935e4613cb78@changeidSigned-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent 87209b7f
...@@ -105,6 +105,10 @@ ...@@ -105,6 +105,10 @@
/* GIO Chicken Bits (PCI Express bus link power management) */ /* GIO Chicken Bits (PCI Express bus link power management) */
#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100)
#define CSR_IPC_SLEEP_CONTROL (CSR_BASE + 0x114)
#define CSR_IPC_SLEEP_CONTROL_SUSPEND 0x3
#define CSR_IPC_SLEEP_CONTROL_RESUME 0
/* Doorbell NMI (since Bz) */ /* Doorbell NMI (since Bz) */
#define CSR_DOORBELL_VECTOR (CSR_BASE + 0x130) #define CSR_DOORBELL_VECTOR (CSR_BASE + 0x130)
#define CSR_DOORBELL_VECTOR_NMI BIT(1) #define CSR_DOORBELL_VECTOR_NMI BIT(1)
......
...@@ -455,6 +455,13 @@ enum { ...@@ -455,6 +455,13 @@ enum {
#define UREG_DOORBELL_TO_ISR6_RESUME BIT(19) #define UREG_DOORBELL_TO_ISR6_RESUME BIT(19)
#define UREG_DOORBELL_TO_ISR6_PNVM BIT(20) #define UREG_DOORBELL_TO_ISR6_PNVM BIT(20)
/*
* From BZ family driver triggers this bit for suspend and resume
* The driver should update CSR_IPC_SLEEP_CONTROL before triggering
* this interrupt with suspend/resume value
*/
#define UREG_DOORBELL_TO_ISR6_SLEEP_CTRL BIT(31)
#define CNVI_MBOX_C 0xA3400C #define CNVI_MBOX_C 0xA3400C
#define FSEQ_ERROR_CODE 0xA340C8 #define FSEQ_ERROR_CODE 0xA340C8
......
...@@ -1499,33 +1499,54 @@ void iwl_pcie_d3_complete_suspend(struct iwl_trans *trans, ...@@ -1499,33 +1499,54 @@ void iwl_pcie_d3_complete_suspend(struct iwl_trans *trans,
iwl_pcie_set_pwr(trans, true); iwl_pcie_set_pwr(trans, true);
} }
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->trans_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->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) {
iwl_write32(trans, CSR_IPC_SLEEP_CONTROL,
suspend ? CSR_IPC_SLEEP_CONTROL_SUSPEND :
CSR_IPC_SLEEP_CONTROL_RESUME);
iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6,
UREG_DOORBELL_TO_ISR6_SLEEP_CTRL);
} 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;
if (!ret) {
IWL_ERR(trans, "Timeout %s D3\n",
suspend ? "entering" : "exiting");
return -ETIMEDOUT;
}
return 0;
}
static int iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test, static int iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test,
bool reset) bool reset)
{ {
int ret; int ret;
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
if (!reset) if (!reset)
/* Enable persistence mode to avoid reset */ /* Enable persistence mode to avoid reset */
iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_PERSIST_MODE); CSR_HW_IF_CONFIG_REG_PERSIST_MODE);
if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { ret = iwl_pcie_d3_handshake(trans, true);
iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, if (ret)
UREG_DOORBELL_TO_ISR6_SUSPEND); return ret;
ret = wait_event_timeout(trans_pcie->sx_waitq,
trans_pcie->sx_complete, 2 * HZ);
/*
* Invalidate it toward resume.
*/
trans_pcie->sx_complete = false;
if (!ret) {
IWL_ERR(trans, "Timeout entering D3\n");
return -ETIMEDOUT;
}
}
iwl_pcie_d3_complete_suspend(trans, test, reset); iwl_pcie_d3_complete_suspend(trans, test, reset);
return 0; return 0;
...@@ -1542,6 +1563,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, ...@@ -1542,6 +1563,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
if (test) { if (test) {
iwl_enable_interrupts(trans); iwl_enable_interrupts(trans);
*status = IWL_D3_STATUS_ALIVE; *status = IWL_D3_STATUS_ALIVE;
ret = 0;
goto out; goto out;
} }
...@@ -1590,25 +1612,10 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, ...@@ -1590,25 +1612,10 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
*status = IWL_D3_STATUS_ALIVE; *status = IWL_D3_STATUS_ALIVE;
out: out:
if (*status == IWL_D3_STATUS_ALIVE && if (*status == IWL_D3_STATUS_ALIVE)
trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { ret = iwl_pcie_d3_handshake(trans, false);
trans_pcie->sx_complete = false;
iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6,
UREG_DOORBELL_TO_ISR6_RESUME);
ret = wait_event_timeout(trans_pcie->sx_waitq, return ret;
trans_pcie->sx_complete, 2 * HZ);
/*
* Invalidate it toward next suspend.
*/
trans_pcie->sx_complete = false;
if (!ret) {
IWL_ERR(trans, "Timeout exiting D3\n");
return -ETIMEDOUT;
}
}
return 0;
} }
static void static void
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment