|
|
@@ -989,6 +989,65 @@ out:
|
|
|
spin_unlock_bh(&txq->lock);
|
|
|
}
|
|
|
|
|
|
+static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans)
|
|
|
+{
|
|
|
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ lockdep_assert_held(&trans_pcie->reg_lock);
|
|
|
+
|
|
|
+ if (trans_pcie->cmd_in_flight)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ trans_pcie->cmd_in_flight = true;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * wake up the NIC to make sure that the firmware will see the host
|
|
|
+ * command - we will let the NIC sleep once all the host commands
|
|
|
+ * returned. This needs to be done only on NICs that have
|
|
|
+ * apmg_wake_up_wa set.
|
|
|
+ */
|
|
|
+ if (trans->cfg->base_params->apmg_wake_up_wa) {
|
|
|
+ __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
|
|
|
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
|
|
+ if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
|
|
|
+ udelay(2);
|
|
|
+
|
|
|
+ ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
|
|
|
+ CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
|
|
|
+ (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
|
|
|
+ CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP),
|
|
|
+ 15000);
|
|
|
+ if (ret < 0) {
|
|
|
+ __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
|
|
|
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
|
|
+ trans_pcie->cmd_in_flight = false;
|
|
|
+ IWL_ERR(trans, "Failed to wake NIC for hcmd\n");
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans)
|
|
|
+{
|
|
|
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
|
|
+
|
|
|
+ lockdep_assert_held(&trans_pcie->reg_lock);
|
|
|
+
|
|
|
+ if (WARN_ON(!trans_pcie->cmd_in_flight))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ trans_pcie->cmd_in_flight = false;
|
|
|
+
|
|
|
+ if (trans->cfg->base_params->apmg_wake_up_wa)
|
|
|
+ __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
|
|
|
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* iwl_pcie_cmdq_reclaim - Reclaim TX command queue entries already Tx'd
|
|
|
*
|
|
|
@@ -1024,14 +1083,9 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (trans->cfg->base_params->apmg_wake_up_wa &&
|
|
|
- q->read_ptr == q->write_ptr) {
|
|
|
+ if (q->read_ptr == q->write_ptr) {
|
|
|
spin_lock_irqsave(&trans_pcie->reg_lock, flags);
|
|
|
- WARN_ON(!trans_pcie->cmd_in_flight);
|
|
|
- trans_pcie->cmd_in_flight = false;
|
|
|
- __iwl_trans_pcie_clear_bit(trans,
|
|
|
- CSR_GP_CNTRL,
|
|
|
- CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
|
|
+ iwl_pcie_clear_cmd_in_flight(trans);
|
|
|
spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
|
|
|
}
|
|
|
|
|
|
@@ -1419,35 +1473,11 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
|
|
|
mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
|
|
|
|
|
|
spin_lock_irqsave(&trans_pcie->reg_lock, flags);
|
|
|
-
|
|
|
- /*
|
|
|
- * wake up the NIC to make sure that the firmware will see the host
|
|
|
- * command - we will let the NIC sleep once all the host commands
|
|
|
- * returned. This needs to be done only on NICs that have
|
|
|
- * apmg_wake_up_wa set.
|
|
|
- */
|
|
|
- if (trans->cfg->base_params->apmg_wake_up_wa &&
|
|
|
- !trans_pcie->cmd_in_flight) {
|
|
|
- trans_pcie->cmd_in_flight = true;
|
|
|
- __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
|
|
|
- CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
|
|
- if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
|
|
|
- udelay(2);
|
|
|
-
|
|
|
- ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
|
|
|
- CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
|
|
|
- (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
|
|
|
- CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP),
|
|
|
- 15000);
|
|
|
- if (ret < 0) {
|
|
|
- __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
|
|
|
- CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
|
|
- spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
|
|
|
- trans_pcie->cmd_in_flight = false;
|
|
|
- IWL_ERR(trans, "Failed to wake NIC for hcmd\n");
|
|
|
- idx = -EIO;
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ ret = iwl_pcie_set_cmd_in_flight(trans);
|
|
|
+ if (ret < 0) {
|
|
|
+ idx = ret;
|
|
|
+ spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
/* Increment and update queue's write index */
|