diff options
author | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2012-03-31 11:28:38 -0400 |
---|---|---|
committer | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2012-04-23 17:19:47 -0400 |
commit | 218733cf7d01fb6225e37a16818870d20c1d8771 (patch) | |
tree | f5b2afb03ced78868a9cad0599a1fb6b0aa4f8bd /drivers/net | |
parent | d23f78e61f6b37159df6bfce7023500d731f61f3 (diff) |
iwlwifi: provide proper API to disable all interrupts
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>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-mac80211.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | 37 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans.h | 10 |
4 files changed, 35 insertions, 17 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 07df4326cde..3024d8cc7aa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -1633,7 +1633,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, | |||
1633 | goto out_free_traffic_mem; | 1633 | goto out_free_traffic_mem; |
1634 | } | 1634 | } |
1635 | /* Reset chip to save power until we load uCode during "up". */ | 1635 | /* Reset chip to save power until we load uCode during "up". */ |
1636 | iwl_trans_stop_hw(priv->trans); | 1636 | iwl_trans_stop_hw(priv->trans, false); |
1637 | 1637 | ||
1638 | if (iwl_eeprom_check_version(priv)) | 1638 | if (iwl_eeprom_check_version(priv)) |
1639 | goto out_free_eeprom; | 1639 | goto out_free_eeprom; |
@@ -1786,6 +1786,7 @@ void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode) | |||
1786 | 1786 | ||
1787 | dev_kfree_skb(priv->beacon_skb); | 1787 | dev_kfree_skb(priv->beacon_skb); |
1788 | 1788 | ||
1789 | iwl_trans_stop_hw(priv->trans, true); | ||
1789 | ieee80211_free_hw(priv->hw); | 1790 | ieee80211_free_hw(priv->hw); |
1790 | } | 1791 | } |
1791 | 1792 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c index 2d7453de5c7..b309ede4f07 100644 --- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c +++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c | |||
@@ -355,7 +355,7 @@ void iwlagn_mac_stop(struct ieee80211_hw *hw) | |||
355 | * even if interface is down, trans->down will leave the RF | 355 | * even if interface is down, trans->down will leave the RF |
356 | * kill interrupt enabled | 356 | * kill interrupt enabled |
357 | */ | 357 | */ |
358 | iwl_trans_stop_hw(priv->trans); | 358 | iwl_trans_stop_hw(priv->trans, false); |
359 | 359 | ||
360 | IWL_DEBUG_MAC80211(priv, "leave\n"); | 360 | IWL_DEBUG_MAC80211(priv, "leave\n"); |
361 | } | 361 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index 8e1cf97dfad..2a9fb984526 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | |||
@@ -1210,6 +1210,8 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) | |||
1210 | iwl_disable_interrupts(trans); | 1210 | iwl_disable_interrupts(trans); |
1211 | spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); | 1211 | spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); |
1212 | 1212 | ||
1213 | iwl_enable_rfkill_int(trans); | ||
1214 | |||
1213 | /* wait to make sure we flush pending tasklet*/ | 1215 | /* wait to make sure we flush pending tasklet*/ |
1214 | synchronize_irq(trans_pcie->irq); | 1216 | synchronize_irq(trans_pcie->irq); |
1215 | tasklet_kill(&trans_pcie->irq_tasklet); | 1217 | tasklet_kill(&trans_pcie->irq_tasklet); |
@@ -1436,24 +1438,37 @@ error: | |||
1436 | return err; | 1438 | return err; |
1437 | } | 1439 | } |
1438 | 1440 | ||
1439 | static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans) | 1441 | static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans, |
1442 | bool op_mode_leaving) | ||
1440 | { | 1443 | { |
1441 | bool hw_rfkill; | 1444 | bool hw_rfkill; |
1445 | unsigned long flags; | ||
1446 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | ||
1442 | 1447 | ||
1443 | iwl_apm_stop(trans); | 1448 | iwl_apm_stop(trans); |
1444 | 1449 | ||
1445 | iwl_write32(trans, CSR_INT, 0xFFFFFFFF); | 1450 | spin_lock_irqsave(&trans_pcie->irq_lock, flags); |
1451 | iwl_disable_interrupts(trans); | ||
1452 | spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); | ||
1446 | 1453 | ||
1447 | /* Even if we stop the HW, we still want the RF kill interrupt */ | 1454 | iwl_write32(trans, CSR_INT, 0xFFFFFFFF); |
1448 | iwl_enable_rfkill_int(trans); | ||
1449 | 1455 | ||
1450 | /* | 1456 | if (!op_mode_leaving) { |
1451 | * Check again since the RF kill state may have changed while all the | 1457 | /* |
1452 | * interrupts were disabled, in this case we couldn't receive the | 1458 | * Even if we stop the HW, we still want the RF kill |
1453 | * RF kill interrupt and update the state in the op_mode. | 1459 | * interrupt |
1454 | */ | 1460 | */ |
1455 | hw_rfkill = iwl_is_rfkill_set(trans); | 1461 | iwl_enable_rfkill_int(trans); |
1456 | iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); | 1462 | |
1463 | /* | ||
1464 | * Check again since the RF kill state may have changed while | ||
1465 | * all the interrupts were disabled, in this case we couldn't | ||
1466 | * receive the RF kill interrupt and update the state in the | ||
1467 | * op_mode. | ||
1468 | */ | ||
1469 | hw_rfkill = iwl_is_rfkill_set(trans); | ||
1470 | iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); | ||
1471 | } | ||
1457 | } | 1472 | } |
1458 | 1473 | ||
1459 | static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, | 1474 | static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 885c03659f2..d7c30325ce3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -335,7 +335,8 @@ struct iwl_trans; | |||
335 | * @start_hw: starts the HW- from that point on, the HW can send interrupts | 335 | * @start_hw: starts the HW- from that point on, the HW can send interrupts |
336 | * May sleep | 336 | * May sleep |
337 | * @stop_hw: stops the HW- from that point on, the HW will be in low power but | 337 | * @stop_hw: stops the HW- from that point on, the HW will be in low power but |
338 | * will still issue interrupt if the HW RF kill is triggered. | 338 | * will still issue interrupt if the HW RF kill is triggered unless |
339 | * op_mode_leaving is true. | ||
339 | * May sleep | 340 | * May sleep |
340 | * @start_fw: allocates and inits all the resources for the transport | 341 | * @start_fw: allocates and inits all the resources for the transport |
341 | * layer. Also kick a fw image. | 342 | * layer. Also kick a fw image. |
@@ -379,7 +380,7 @@ struct iwl_trans; | |||
379 | struct iwl_trans_ops { | 380 | struct iwl_trans_ops { |
380 | 381 | ||
381 | int (*start_hw)(struct iwl_trans *iwl_trans); | 382 | int (*start_hw)(struct iwl_trans *iwl_trans); |
382 | void (*stop_hw)(struct iwl_trans *iwl_trans); | 383 | void (*stop_hw)(struct iwl_trans *iwl_trans, bool op_mode_leaving); |
383 | int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw); | 384 | int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw); |
384 | void (*fw_alive)(struct iwl_trans *trans); | 385 | void (*fw_alive)(struct iwl_trans *trans); |
385 | void (*stop_device)(struct iwl_trans *trans); | 386 | void (*stop_device)(struct iwl_trans *trans); |
@@ -478,11 +479,12 @@ static inline int iwl_trans_start_hw(struct iwl_trans *trans) | |||
478 | return trans->ops->start_hw(trans); | 479 | return trans->ops->start_hw(trans); |
479 | } | 480 | } |
480 | 481 | ||
481 | static inline void iwl_trans_stop_hw(struct iwl_trans *trans) | 482 | static inline void iwl_trans_stop_hw(struct iwl_trans *trans, |
483 | bool op_mode_leaving) | ||
482 | { | 484 | { |
483 | might_sleep(); | 485 | might_sleep(); |
484 | 486 | ||
485 | trans->ops->stop_hw(trans); | 487 | trans->ops->stop_hw(trans, op_mode_leaving); |
486 | 488 | ||
487 | trans->state = IWL_TRANS_NO_FW; | 489 | trans->state = IWL_TRANS_NO_FW; |
488 | } | 490 | } |