iwlwifi: pcie: fix tracking of cmd_in_flight
authorIlan Peer <ilan.peer@intel.com>
Wed, 13 May 2015 11:34:07 +0000 (14:34 +0300)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Thu, 28 May 2015 10:27:51 +0000 (13:27 +0300)
The cmd_in_flight tracking was introduced to workaround faulty
power management hardware, by having the driver keep the NIC
awake as long as there are commands in flight. However, some of
the code handling this workaround was unconditionally executed,
which resulted with an inconsistent state where the driver assumed
that the NIC was awake although it wasn't.

Fix this by renaming 'cmd_in_flight' to 'cmd_hold_nic_awake' and
handling the NIC requested awake state only for hardwares for
which the workaround is needed.

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/iwlwifi/pcie/internal.h
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/tx.c

index 01996c9d98a79b1d62e3a665cd0c720df79ad04e..376b84e54ad7e8bbb48d039d354c03748665451c 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2003 - 2015 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -320,7 +320,7 @@ struct iwl_trans_pcie {
 
        /*protect hw register */
        spinlock_t reg_lock;
-       bool cmd_in_flight;
+       bool cmd_hold_nic_awake;
        bool ref_cmd_in_flight;
 
        /* protect ref counter */
index d6f6515fe663707c3127f9c1db97c3143a9c0bd8..dc179094e6a0d440b2aa29909c05adbc07f3f6b5 100644 (file)
@@ -1372,7 +1372,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent,
 
        spin_lock_irqsave(&trans_pcie->reg_lock, *flags);
 
-       if (trans_pcie->cmd_in_flight)
+       if (trans_pcie->cmd_hold_nic_awake)
                goto out;
 
        /* this bit wakes up the NIC */
@@ -1438,7 +1438,7 @@ static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans,
         */
        __acquire(&trans_pcie->reg_lock);
 
-       if (trans_pcie->cmd_in_flight)
+       if (trans_pcie->cmd_hold_nic_awake)
                goto out;
 
        __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
index 06952aadfd7b5d4dccfff9f9689cd804031ab0eb..5ef8044c2ea3ed7317870902168c71be936cd8df 100644 (file)
@@ -1039,18 +1039,14 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
                iwl_trans_pcie_ref(trans);
        }
 
-       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) {
+       if (trans->cfg->base_params->apmg_wake_up_wa &&
+           !trans_pcie->cmd_hold_nic_awake) {
                __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)
@@ -1064,10 +1060,10 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
                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;
                }
+               trans_pcie->cmd_hold_nic_awake = true;
        }
 
        return 0;
@@ -1085,15 +1081,14 @@ static int iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans)
                iwl_trans_pcie_unref(trans);
        }
 
-       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) {
+               if (WARN_ON(!trans_pcie->cmd_hold_nic_awake))
+                       return 0;
 
-       if (trans->cfg->base_params->apmg_wake_up_wa)
+               trans_pcie->cmd_hold_nic_awake = false;
                __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
-                                       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
+                                          CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+       }
        return 0;
 }