iwlwifi: provide proper API to disable all interrupts
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Sat, 31 Mar 2012 15:28:38 +0000 (08:28 -0700)
committerWey-Yi Guy <wey-yi.w.guy@intel.com>
Mon, 23 Apr 2012 21:19:47 +0000 (14:19 -0700)
Since the op_mode may go away, the transport needs to be able to
be told not to update the op_mode at all (even for RF kill).
Provide this API and use it in the proper places.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-mac80211.c
drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
drivers/net/wireless/iwlwifi/iwl-trans.h

index 07df4326cdeca2dda79ac5a688e4c9bd6def6a4a..3024d8cc7aa3b9377edff744c4c4350ae269c24e 100644 (file)
@@ -1633,7 +1633,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
                goto out_free_traffic_mem;
        }
        /* Reset chip to save power until we load uCode during "up". */
-       iwl_trans_stop_hw(priv->trans);
+       iwl_trans_stop_hw(priv->trans, false);
 
        if (iwl_eeprom_check_version(priv))
                goto out_free_eeprom;
@@ -1786,6 +1786,7 @@ void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
 
        dev_kfree_skb(priv->beacon_skb);
 
+       iwl_trans_stop_hw(priv->trans, true);
        ieee80211_free_hw(priv->hw);
 }
 
index 2d7453de5c74ff69ec0e33b85718e56976378c7c..b309ede4f0727cfc56ce849f64779c3d9d6cff0f 100644 (file)
@@ -355,7 +355,7 @@ void iwlagn_mac_stop(struct ieee80211_hw *hw)
         * even if interface is down, trans->down will leave the RF
         * kill interrupt enabled
         */
-       iwl_trans_stop_hw(priv->trans);
+       iwl_trans_stop_hw(priv->trans, false);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
 }
index 8e1cf97dfad2ad18f3c187eaf06d843f4c14008e..2a9fb984526fcfd75863d93f846c835c2a0c4028 100644 (file)
@@ -1210,6 +1210,8 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
        iwl_disable_interrupts(trans);
        spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
+       iwl_enable_rfkill_int(trans);
+
        /* wait to make sure we flush pending tasklet*/
        synchronize_irq(trans_pcie->irq);
        tasklet_kill(&trans_pcie->irq_tasklet);
@@ -1436,24 +1438,37 @@ error:
        return err;
 }
 
-static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans)
+static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
+                                  bool op_mode_leaving)
 {
        bool hw_rfkill;
+       unsigned long flags;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
        iwl_apm_stop(trans);
 
-       iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       iwl_disable_interrupts(trans);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
-       /* Even if we stop the HW, we still want the RF kill interrupt */
-       iwl_enable_rfkill_int(trans);
+       iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
 
-       /*
-        * Check again since the RF kill state may have changed while all the
-        * interrupts were disabled, in this case we couldn't receive the
-        * RF kill interrupt and update the state in the op_mode.
-        */
-       hw_rfkill = iwl_is_rfkill_set(trans);
-       iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+       if (!op_mode_leaving) {
+               /*
+                * Even if we stop the HW, we still want the RF kill
+                * interrupt
+                */
+               iwl_enable_rfkill_int(trans);
+
+               /*
+                * Check again since the RF kill state may have changed while
+                * all the interrupts were disabled, in this case we couldn't
+                * receive the RF kill interrupt and update the state in the
+                * op_mode.
+                */
+               hw_rfkill = iwl_is_rfkill_set(trans);
+               iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+       }
 }
 
 static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
index 885c03659f265b7dd75971881c44bb267246f447..d7c30325ce35b7f26718671cedd3ab2e89a04869 100644 (file)
@@ -335,7 +335,8 @@ struct iwl_trans;
  * @start_hw: starts the HW- from that point on, the HW can send interrupts
  *     May sleep
  * @stop_hw: stops the HW- from that point on, the HW will be in low power but
- *     will still issue interrupt if the HW RF kill is triggered.
+ *     will still issue interrupt if the HW RF kill is triggered unless
+ *     op_mode_leaving is true.
  *     May sleep
  * @start_fw: allocates and inits all the resources for the transport
  *     layer. Also kick a fw image.
@@ -379,7 +380,7 @@ struct iwl_trans;
 struct iwl_trans_ops {
 
        int (*start_hw)(struct iwl_trans *iwl_trans);
-       void (*stop_hw)(struct iwl_trans *iwl_trans);
+       void (*stop_hw)(struct iwl_trans *iwl_trans, bool op_mode_leaving);
        int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw);
        void (*fw_alive)(struct iwl_trans *trans);
        void (*stop_device)(struct iwl_trans *trans);
@@ -478,11 +479,12 @@ static inline int iwl_trans_start_hw(struct iwl_trans *trans)
        return trans->ops->start_hw(trans);
 }
 
-static inline void iwl_trans_stop_hw(struct iwl_trans *trans)
+static inline void iwl_trans_stop_hw(struct iwl_trans *trans,
+                                    bool op_mode_leaving)
 {
        might_sleep();
 
-       trans->ops->stop_hw(trans);
+       trans->ops->stop_hw(trans, op_mode_leaving);
 
        trans->state = IWL_TRANS_NO_FW;
 }