iwlwifi: pcie: allow the op_mode to call stop_device whenever it wants
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Thu, 19 Dec 2013 20:19:17 +0000 (22:19 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Tue, 31 Dec 2013 17:03:45 +0000 (19:03 +0200)
Calling stop_device when start_fw wasn't called would issue:
Stopping tx queues that aren't allocated...

Also allow the op_mode to call stop_device and then to
disable the Tx queues - in that case just silently ignore
the disabling on the Tx queues, since the PRPH registers
aren't reachable any more.

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

index 0c36478..04e1826 100644 (file)
@@ -622,6 +622,10 @@ static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
 {
        int ret;
 
+       if (unlikely(!(cmd->flags & CMD_SEND_IN_RFKILL) &&
+                    test_bit(STATUS_RFKILL, &trans->status)))
+               return -ERFKILL;
+
        if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
                return -EIO;
 
@@ -684,9 +688,6 @@ static inline void iwl_trans_reclaim(struct iwl_trans *trans, int queue,
 
 static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue)
 {
-       if (unlikely(trans->state != IWL_TRANS_FW_ALIVE))
-               IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
-
        trans->ops->txq_disable(trans, queue);
 }
 
index 2417af9..aec9d9f 100644 (file)
@@ -758,11 +758,17 @@ int iwl_pcie_tx_stop(struct iwl_trans *trans)
        }
        spin_unlock(&trans_pcie->irq_lock);
 
-       if (!trans_pcie->txq) {
-               IWL_WARN(trans,
-                        "Stopping tx queues that aren't allocated...\n");
+       /*
+        * This function can be called before the op_mode disabled the
+        * queues. This happens when we have an rfkill interrupt.
+        * Since we stop Tx altogether - mark the queues as stopped.
+        */
+       memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped));
+       memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used));
+
+       /* This can happen: start_hw, stop_device */
+       if (!trans_pcie->txq)
                return 0;
-       }
 
        /* Unmap DMA from host system and free skb's */
        for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
@@ -1150,8 +1156,15 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
                        SCD_TX_STTS_QUEUE_OFFSET(txq_id);
        static const u32 zero_val[4] = {};
 
+       /*
+        * Upon HW Rfkill - we stop the device, and then stop the queues
+        * in the op_mode. Just for the sake of the simplicity of the op_mode,
+        * allow the op_mode to call txq_disable after it already called
+        * stop_device.
+        */
        if (!test_and_clear_bit(txq_id, trans_pcie->queue_used)) {
-               WARN_ONCE(1, "queue %d not used", txq_id);
+               WARN_ONCE(test_bit(STATUS_DEVICE_ENABLED, &trans->status),
+                         "queue %d not used", txq_id);
                return;
        }